diff --git a/.agents/notes/implemented/architecture/2026-10-14-webworker-preview-profile-parity.i18n.yaml b/.agents/notes/implemented/architecture/2026-10-14-webworker-preview-profile-parity.i18n.yaml index 3ae45a7509..b04f873a24 100644 --- a/.agents/notes/implemented/architecture/2026-10-14-webworker-preview-profile-parity.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-10-14-webworker-preview-profile-parity.i18n.yaml @@ -12,8 +12,8 @@ en: a15c7c13f167e5ac zh: 63bcc2ef60c2f344 /agent-note-boot-the-preview-worker-from-the-shipped-profile-and-fetch-lazy-chunks-on-demand/decision/boot-the-same-profile-as-the-served-web-deployment: - en: caf1ca77192dcb20 - zh: d663e2cbb05fe4fc + en: 9b957e37f290abaf + zh: 06a4599c8fe449ad /agent-note-boot-the-preview-worker-from-the-shipped-profile-and-fetch-lazy-chunks-on-demand/decision/node-internal-module-interfaces-in-the-worker: en: 37d8e809eaa21d25 zh: 8c7c31bd6f45c823 diff --git a/.agents/notes/implemented/architecture/2026-10-14-webworker-preview-profile-parity.md b/.agents/notes/implemented/architecture/2026-10-14-webworker-preview-profile-parity.md index 47b2866402..71509500e5 100644 --- a/.agents/notes/implemented/architecture/2026-10-14-webworker-preview-profile-parity.md +++ b/.agents/notes/implemented/architecture/2026-10-14-webworker-preview-profile-parity.md @@ -23,7 +23,7 @@ Measured: with no bundle enabled, the two compositions differ in only one of 188 The served launch path (apps/cli, app-boot) carries no Preview-specific code; the webworker packages reproduce it: - **packer** - - Package roster = `PROFILE_TEMPLATES[profile].bundles` + `OPTIONAL_BUNDLES` + the rows named in those bundles' patch files; the bundle packages themselves also enter the image (patches, locale, and icon through the publish view). Both tables are read from app-boot, the same source the Plugins page uses. + - Package roster = `PROFILE_TEMPLATES[profile].bundles` + `OPTIONAL_BUNDLES` + the rows named in those bundles' patch files; the bundle packages themselves also enter the image (patches, locale, and icon through the publish view). Both tables are read from `@deepseek-ai/dsh-official-bundles`, the same source the Plugins page uses. - The image carries a manifest-only `node_modules/@deepseek-ai/dsh/package.json` (a verbatim copy of `apps/cli/package.json`) as the installation anchor, and the image manifest names it in `installation`. - The image carries no composed configuration and no `config/cordis.yml`; the image manifest records the `profile` the Worker boots. - The image carries a home patch, `home/cordis.patch.yml`: for each row the runtime's `PLATFORM_ENTRY_CONFIG` names (`session-persistence-jsonl`), the config the template's bundle layers compose with the required fields over it (`compression: none`). A patch replaces a row's whole config, so the composed fields stay; the bundle files read at pack time are the ones in the image. diff --git a/.agents/notes/implemented/architecture/2026-10-14-webworker-preview-profile-parity.zh.md b/.agents/notes/implemented/architecture/2026-10-14-webworker-preview-profile-parity.zh.md index 018992e103..5c9b5bf233 100644 --- a/.agents/notes/implemented/architecture/2026-10-14-webworker-preview-profile-parity.zh.md +++ b/.agents/notes/implemented/architecture/2026-10-14-webworker-preview-profile-parity.zh.md @@ -23,7 +23,7 @@ Status: implemented 正式启动链路(apps/cli、app-boot)不含 Preview 专用代码;由 webworker 包复现这条链路: - **packer** - - 收包清单 = `PROFILE_TEMPLATES[profile].bundles` + `OPTIONAL_BUNDLES` + 这些 bundle 补丁文件里的行;bundle 包本身也打进镜像(补丁、locale、icon 走 publish view)。两张表从 app-boot 读,与插件页同一来源。 + - 收包清单 = `PROFILE_TEMPLATES[profile].bundles` + `OPTIONAL_BUNDLES` + 这些 bundle 补丁文件里的行;bundle 包本身也打进镜像(补丁、locale、icon 走 publish view)。两张表从 `@deepseek-ai/dsh-official-bundles` 读,与插件页同一来源。 - 镜像里放一份只含清单的 `node_modules/@deepseek-ai/dsh/package.json`(原样复制 `apps/cli/package.json`),作为安装锚点,镜像 manifest 在 `installation` 里记录它。 - 镜像不带组合好的配置,也没有 `config/cordis.yml`;镜像 manifest 记录 Worker 要启动的 `profile`。 - 镜像带一份 home patch `home/cordis.patch.yml`:对运行时 `PLATFORM_ENTRY_CONFIG` 列出的每一行(`session-persistence-jsonl`),写入模板各 bundle 层合成出的配置,并在其上设置所需字段(`compression: none`)。补丁会整体替换一行的配置,所以保留合成出的字段;打包时读取的 bundle 文件就是镜像里的那些。 diff --git a/.agents/notes/implemented/architecture/2026-10-19-file-drag-plugin-ownership.i18n.yaml b/.agents/notes/implemented/architecture/2026-10-19-file-drag-plugin-ownership.i18n.yaml new file mode 100644 index 0000000000..3ebb632746 --- /dev/null +++ b/.agents/notes/implemented/architecture/2026-10-19-file-drag-plugin-ownership.i18n.yaml @@ -0,0 +1,19 @@ +# Bilingual-pair consistency record for 2026-10-19-file-drag-plugin-ownership.md (docs/i18n/README.md): per heading +# section, a hash of its English and Chinese blocks outside code blocks and generated regions. +# After editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write .agents/notes/implemented/architecture/2026-10-19-file-drag-plugin-ownership.md +/agent-note-file-drag-ownership-outside-the-application-layout: + en: 951575b08912a949 + zh: f33e8e6bcb9240bd +/agent-note-file-drag-ownership-outside-the-application-layout/problem: + en: 557edc1db9bee8d8 + zh: 20f47c78c8b0078b +/agent-note-file-drag-ownership-outside-the-application-layout/decision: + en: 1dfea60901d6e6ae + zh: e4fc534dbe01b0d5 +/agent-note-file-drag-ownership-outside-the-application-layout/alternatives-considered: + en: 571eabab132ce4c1 + zh: b5f8207015aeb3be +/agent-note-file-drag-ownership-outside-the-application-layout/consequences: + en: 56ebb7c25911fd61 + zh: 88120d2af74785ef diff --git a/.agents/notes/implemented/architecture/2026-10-19-file-drag-plugin-ownership.md b/.agents/notes/implemented/architecture/2026-10-19-file-drag-plugin-ownership.md new file mode 100644 index 0000000000..5d99b5815a --- /dev/null +++ b/.agents/notes/implemented/architecture/2026-10-19-file-drag-plugin-ownership.md @@ -0,0 +1,25 @@ +# Agent Note: File drag ownership outside the application layout + +Status: implemented + +English | [中文](2026-10-19-file-drag-plugin-ownership.zh.md) + +## Problem + +Image dragging spans conversation images, sidebar previews, and composer drop targets. Original files must survive source unmount during a drag, and failures must remain visible after the originating panel closes. An application-root image provider puts feature state in layout and makes independent image entries depend on an undeclared React ancestor. + +## Decision + +The [file-drag plugin](../../../../packages/client/ui-file-drag/README.md) owns generic file preparation, browser transfer tokens, retained original files, desktop bridge selection, and transient failure feedback. Consumers receive preparation and error callbacks through their slot or Factory injection. The plugin registers its feedback through `shell.overlay`; layout declares the generic slot and has no image dependency. The shared image primitive owns gestures and cancellation. Images are the first consumer, while MIME naming and transport accept other files. + +## Alternatives considered + +**Root React provider.** It preserves transfer lifetime but adds image-specific assembly to the layout package and hides dependencies from slot registration. Moving the same wrapper into the renderer would move the feature coupling into another generic owner. + +**State on each image.** It avoids shared assembly but cannot deliver the retained file after the source unmounts or keep a late failure visible after the panel closes. + +**Direct browser File only.** Manual macOS Chrome 154.0.8037.93 drags of PNG and PDF fixtures produced a populated `dataTransfer.files` in trusted `dragstart`, but empty files in trusted same-page and cross-window drops. Finder received filename-only text clippings. These measured failures require the application-local token path; they do not establish behavior in untested browsers or cross-tab delivery. Desktop retains Electron native file dragging. + +## Consequences + +One plugin lifetime governs transfer state, a native source-node end listener, and drop completion. The source listener remains attached after React unmount. Independent render roots can share a transfer without sharing a React ancestor. Custom compositions must load the service and declare the feedback slot; custom image Factory registrations supply the required callbacks. Application-local browser tokens are accepted only over the composer; native Desktop files retain the full-page drop overlay. Plugin disposal removes feedback and clears retained files. Loader-backed browser scenarios cover source removal and delivery, while focused tests cover local resource authorization and cleanup failures. diff --git a/.agents/notes/implemented/architecture/2026-10-19-file-drag-plugin-ownership.zh.md b/.agents/notes/implemented/architecture/2026-10-19-file-drag-plugin-ownership.zh.md new file mode 100644 index 0000000000..0e361717a4 --- /dev/null +++ b/.agents/notes/implemented/architecture/2026-10-19-file-drag-plugin-ownership.zh.md @@ -0,0 +1,25 @@ +# Agent Note: 应用布局之外的文件拖放归属 + +Status: implemented + +[English](2026-10-19-file-drag-plugin-ownership.md) | 中文 + +## Problem + +图片拖放跨越会话图片、侧栏预览和输入框接收区。拖动期间原始文件必须在源组件卸载后继续保留,发起操作的面板关闭后失败提示也必须可见。应用根部的图片 Provider 把功能状态放进布局,并使独立图片入口依赖未声明的 React 祖先组件。 + +## Decision + +[文件拖放插件](../../../../packages/client/ui-file-drag/README.zh.md) 持有通用文件准备、浏览器传递令牌、原始文件、桌面桥接选择和临时失败提示。消费方通过 slot 或 Factory 注入接收准备及错误回调。插件通过 `shell.overlay` 注册提示,布局只声明通用插槽,不依赖图片功能。共享图片原语负责手势与取消。图片是首个调用方,MIME 命名与传输也接受其他文件。 + +## Alternatives considered + +**根部 React Provider。** 它能保留传递生命周期,但会把图片专属组合放进布局包,并对 slot 注册隐藏依赖。把同一个包裹组件移到渲染器,只会把功能耦合转移到另一个通用模块。 + +**每张图片独立持有状态。** 这能避免共享组合,却不能在源组件卸载后交付保留文件,也不能在面板关闭后继续显示延迟到达的失败提示。 + +**仅直接传递浏览器 File。** 在 macOS Chrome 154.0.8037.93 中手动拖放 PNG 与 PDF 时,可信 `dragstart` 中 `dataTransfer.files` 有文件,同页与跨窗口的可信 drop 却收到空文件列表。Finder 收到仅含文件名的文本摘录。这些实测失败要求保留应用内令牌路径,但不能据此判定未测试浏览器或跨标签页交付的行为。Desktop 保留 Electron 原生文件拖放。 + +## Consequences + +一个插件生命周期管理传递状态、源节点上的原生结束监听器与投放完成。React 卸载后,监听器仍绑定源节点。独立渲染根可以共享传递,而不共享 React 祖先组件。自定义组合必须加载服务并声明反馈插槽,自定义图片 Factory 注册提供所需回调。应用内浏览器令牌仅在输入框范围接受;Desktop 原生文件保留全页投放遮罩。插件卸载会移除提示并清除保留文件。通过 Loader 启动的浏览器场景覆盖源图移除与交付,定向测试覆盖本地资源授权和清理失败。 diff --git a/.agents/notes/implemented/architecture/2026-10-21-replaceable-icon-sprite.i18n.yaml b/.agents/notes/implemented/architecture/2026-10-21-replaceable-icon-sprite.i18n.yaml new file mode 100644 index 0000000000..59918ce6a1 --- /dev/null +++ b/.agents/notes/implemented/architecture/2026-10-21-replaceable-icon-sprite.i18n.yaml @@ -0,0 +1,19 @@ +# Bilingual-pair consistency record for 2026-10-21-replaceable-icon-sprite.md (docs/i18n/README.md): per heading +# section, a hash of its English and Chinese blocks outside code blocks and generated regions. +# After editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write .agents/notes/implemented/architecture/2026-10-21-replaceable-icon-sprite.md +/agent-note-replaceable-product-icons-through-an-svg-sprite: + en: 2b527e550e071451 + zh: 7de256912270cae0 +/agent-note-replaceable-product-icons-through-an-svg-sprite/problem: + en: d55557fe41ab87c8 + zh: eea3f7d0c82561bf +/agent-note-replaceable-product-icons-through-an-svg-sprite/decision: + en: 6ddd80eae56693dd + zh: 4d654a76eb64c50a +/agent-note-replaceable-product-icons-through-an-svg-sprite/alternatives-considered: + en: 2e25ece88bccdb22 + zh: bb24a28bef7ea7ce +/agent-note-replaceable-product-icons-through-an-svg-sprite/consequences: + en: 0ad6db37bbb76ddb + zh: 0ca09d55a2167970 diff --git a/.agents/notes/implemented/architecture/2026-10-21-replaceable-icon-sprite.md b/.agents/notes/implemented/architecture/2026-10-21-replaceable-icon-sprite.md new file mode 100644 index 0000000000..f4e228ee02 --- /dev/null +++ b/.agents/notes/implemented/architecture/2026-10-21-replaceable-icon-sprite.md @@ -0,0 +1,29 @@ +# Agent Note: Replaceable product icons through an SVG sprite + +Status: implemented + +English | [中文](2026-10-21-replaceable-icon-sprite.zh.md) + +## Problem + +Long-term skin customization needs themes to replace icons, not only colors. Product icons were React components that drew inline SVG paths, so a theme registered through `ctx.theme` could recolor them through `currentColor` but could not change their artwork. About 150 Client files import these components. + +## Decision + +Each product glyph weight is one sprite symbol, `dsw-icon--`. ui-primitives keeps the default SVG documents as `ICON_SYMBOLS`; an icon component keeps its export name, `size`, and `className`, and renders an `` box with one `` of its symbol. ui-theme keeps one hidden sprite in the document whose `` children come from the active theme's `ThemeDefinition.icons` replacements or the defaults. Artwork reached through `` inherits `currentColor` and CSS custom properties from the use site, so a replacement can be multi-color, can paint with `--dsw-*` color tokens, and follows light and dark palettes without separate values. + +## Alternatives considered + +- **Icons as CSS image tokens painted through `mask-image`.** Rejected after design review: a mask keeps only the image's alpha, so every icon stays one color, and a `url()` image cannot read CSS variables, so multi-color artwork could not follow color tokens. It would have reused the token override layer without a new theme field. +- **A runtime icon registry service with React components as values.** Rejected: components cannot read services or React context, so every icon import site would need a new prop or slot. +- **A slot per icon.** Rejected for the same caller cost; slots carry composition, not artwork. + +## Consequences + +- Icon DOM contains a `` reference instead of paths; tests identify glyphs through `data-icon` and inspect artwork through `ICON_SYMBOLS`. +- Without ui-theme, the sprite is absent and icons render nothing. +- Every symbol shares the document id space, so `register` requires element ids inside a replacement to start with `-`; `` in another document, such as an iframe, cannot reach the sprite. +- Replacement markup is trusted like the registering plugin's code; `register` rejects `agent/inbox/spliced pure deletion Driver-->>SDK: agent/inbox/claimed { message, turn } per message - Driver->>Prompt: system-prompt/assemble waterfall + Driver->>Tools: resolve({ agent, modelSelection, signal }) once per proposed step + Driver->>Prompt: system-prompt/assemble waterfall with the step tool set Driver->>Hooks: agent/pre-step waterfall Hooks-->>Driver: authoritative reject or enter(messages) alt proposed step rejected, first batch empty, or pre-step failed @@ -65,6 +66,7 @@ sequenceDiagram end end Driver->>Session: step/end + Driver->>Tools: dispose the step tool set opt natural stop and next-step inbox empty Driver->>Hooks: agent/turn-stopping serial terminal checkpoint end diff --git a/docs/agent-lifecycle.zh.md b/docs/agent-lifecycle.zh.md index c4b2fa70db..66c5dd90bf 100644 --- a/docs/agent-lifecycle.zh.md +++ b/docs/agent-lifecycle.zh.md @@ -27,7 +27,8 @@ sequenceDiagram Note over Agent,Driver: claim pending next-step input plus one queued prompt Driver-->>SDK: agent/inbox/spliced pure deletion Driver-->>SDK: agent/inbox/claimed { message, turn } per message - Driver->>Prompt: system-prompt/assemble waterfall + Driver->>Tools: resolve({ agent, modelSelection, signal }) once per proposed step + Driver->>Prompt: system-prompt/assemble waterfall with the step tool set Driver->>Hooks: agent/pre-step waterfall Hooks-->>Driver: authoritative reject or enter(messages) alt proposed step rejected, first batch empty, or pre-step failed @@ -67,6 +68,7 @@ sequenceDiagram end end Driver->>Session: step/end + Driver->>Tools: dispose the step tool set opt natural stop and next-step inbox empty Driver->>Hooks: agent/turn-stopping serial terminal checkpoint end diff --git a/docs/architecture.i18n.yaml b/docs/architecture.i18n.yaml index 0be75305a0..eb4a96bc94 100644 --- a/docs/architecture.i18n.yaml +++ b/docs/architecture.i18n.yaml @@ -21,11 +21,11 @@ en: 20ef882e44b06a10 zh: c10c3934ed5570e9 /deepseek-harness-architecture/events: - en: e89802f066e4955d - zh: ea2fb4bef94e086d + en: 693407efb233f961 + zh: 37b9dd0677d4405c /deepseek-harness-architecture/turn-flow: - en: 53db218880e07b3d - zh: 17cffbc6258b57a8 + en: 1a79a70b62c04cdb + zh: c86d765e21430405 /deepseek-harness-architecture/session-log: en: 8a7f19b95d426c99 zh: d5bb0538404e20ea diff --git a/docs/architecture.md b/docs/architecture.md index 01b8aeaa4c..93d431ada3 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -72,7 +72,7 @@ Events are the extension points, and picking the right domain is the first decis - **Agent events** (`agent/*`) carry a live `Agent`: inbox, step, status, request, validation, continuation. Use one to observe or intercept work in flight. - **Capability events** attach policy and adapters to a seam (`fs/*`, `tools/*`, `telemetry/*`) without importing the loop. -AgentLoop awaits serial `agent/created` before queued work and rolls back failed initialization. Unload retains resources through Agent teardown; [agent-loop](../packages/core/agent-loop/README.md#understand-the-implementation) defines ordering. +AgentLoop initializes Agents with rollback and awaits serial `agent/created` before queued work. Unload retains resources through Agent teardown; [agent-loop](../packages/core/agent-loop/README.md#understand-the-implementation) defines ordering. The [event map](event-producer-consumer.md) lists every event's producers and consumers. @@ -83,7 +83,7 @@ A **step** is one model request plus the tools it calls. A **turn** is zero or m ```text turn/start claim next-step input plus one queued message - snapshot Session model selection; assemble prompt sections + tool schemas + snapshot Session model selection; assemble prompt sections + step-admitted tool schemas -> agent/pre-step; project runtime context at fallback reject | enter(messages, startsRequestSeries?) reject, or a first enter rewritten empty -> close the turn with no step @@ -105,9 +105,11 @@ turn/end `turn/*`, `step/*`, `system/message`, `user/message`, `assistant/message`, `assistant/attempt`, and `tool/*` are durable session events; the rest are live extension points across three domains. `agent/assistant-stream` publishes process-local start, transient chunk, and end frames. The loop commits the complete compact stream as one message or log-only attempt before a committed end frame, and the Web Session-follow adapter is the live event's only remote consumer. `agent/pre-step`, `agent/request`, `llm/stream`, and the three `tools/*` events are waterfalls, whose listeners must call `next()` to delegate; `agent/turn-stopping` is serial and has no `next()`. +Factory setup follows SessionStore entry and `session/created`, preceding `agent/created`; closing events commit before removal. + One inbox feeds the driver; injected context waits for a waking message. AgentLoop’s durable `inbox` projection exposes pending input without live Agents. -The loop snapshots Session model selection before assembly and shares it through `AssembleContext.modelSelection` and `agent/pre-step.modelSelection`; retries retain that selection, and omitted reasoning effort uses adapter defaults. `agent/pre-step` decides the accepted input. Listeners may rewrite or reject claimed messages; a rejected or empty first claim closes a durable turn without a step. An enter decision may set `startsRequestSeries`: the loop logs a fresh `request/header` (reason `series`, or `change` with `startsSeries: true` when the envelope also changed). Wrapping listeners preserve that declaration with `{ ...decision, messages }`. After assembly and `step/start`, the deprecated `agent/request` hook adjusts controls without changing the provider, model, or effort selection, and `prepareCall()` binds the adapter before the system prompt and accepted users are committed; cancellation during either async phase commits neither. Prepared call capabilities govern prompt admission, not preceding `request/context`. Each attempt refreshes registered runtime facts, reconciles the bound prompt, admits users once, and restores removed runtime context, logs header/context as needed, and freezes the request before streaming the bound call. Retries do not repeat assembly or `agent/pre-step`. Surface replacements and image-offload decisions after attachment start a new request series, including during the first resumed pre-step; unchanged resume continues the series. The system prompt travels as `system/message` history: empty text clears it, capable routes append updates, and other routes consolidate it at the first system node. [Agent-loop](../packages/core/agent-loop/README.md#understand-the-implementation) owns prompt admission and replacement details. +Before assembly, the loop snapshots Session model selection in `AssembleContext.modelSelection` and `agent/pre-step.modelSelection`; retries retain it; omitted reasoning effort uses adapter defaults. `agent/pre-step` listeners accept, rewrite, or reject claimed messages; a rejected or empty first claim closes a durable turn without a step. An enter decision may set `startsRequestSeries`: the loop logs a fresh `request/header` (reason `series`, or `change` with `startsSeries: true` when the envelope also changed). Wrapping listeners preserve that declaration with `{ ...decision, messages }`. After assembly and `step/start`, the deprecated `agent/request` hook adjusts controls without changing the provider, model, or effort selection, and `prepareCall()` binds the adapter before the system prompt and accepted users are committed; cancellation during either async phase commits neither. Prepared call capabilities govern prompt admission, not preceding `request/context`. Each attempt refreshes registered runtime facts, reconciles the bound prompt, admits users once, and restores removed runtime context, logs header/context as needed, and freezes the request before streaming the bound call. Retries do not repeat assembly or `agent/pre-step`. Surface replacements and image-offload decisions after attachment start a new request series, including during the first resumed pre-step; unchanged resume continues the series. The system prompt travels as `system/message` history: empty text clears it, capable routes append updates, and other routes consolidate it at the first system node. [Agent-loop](../packages/core/agent-loop/README.md#understand-the-implementation) owns prompt admission and replacement details. The loop sends immutable requests with live cancellation and reuses freeze evidence for frozen identities; [agent-loop](../packages/core/agent-loop/README.md) owns construction and cancellation causes. diff --git a/docs/architecture.zh.md b/docs/architecture.zh.md index 389250b965..687bf69911 100644 --- a/docs/architecture.zh.md +++ b/docs/architecture.zh.md @@ -74,7 +74,7 @@ Electron 使用 Electron Node 模式启动私有 Desktop Host。Host 调用共 - **Agent 事件**(`agent/*`)携带活跃 `Agent`:inbox、步骤、状态、请求、验证、续跑。要观察或拦截进行中的工作时,使用它。 - **能力事件**无需导入循环即可向某个 seam(`fs/*`、`tools/*`、`telemetry/*`)附加策略和适配器。 -AgentLoop 在启动已排队工作前等待串行 `agent/created`,初始化失败则回滚。卸载在 Agent teardown 期间保留所需资源;[agent-loop](../packages/core/agent-loop/README.zh.md#understand-the-implementation)定义顺序。 +AgentLoop 初始化 Agent,失败则回滚,并在启动已排队工作前等待串行 `agent/created`。卸载在 Agent teardown 期间保留所需资源;[agent-loop](../packages/core/agent-loop/README.zh.md#understand-the-implementation)定义顺序。 [事件映射](event-producer-consumer.zh.md)列出每个事件的生产方与消费方。 @@ -87,7 +87,7 @@ AgentLoop 在启动已排队工作前等待串行 `agent/created`,初始化失 ```text turn/start claim next-step input plus one queued message - snapshot Session model selection; assemble prompt sections + tool schemas + snapshot Session model selection; assemble prompt sections + step-admitted tool schemas -> agent/pre-step; project runtime context at fallback reject | enter(messages, startsRequestSeries?) reject, or a first enter rewritten empty -> close the turn with no step @@ -109,9 +109,11 @@ turn/end `turn/*`、`step/*`、`system/message`、`user/message`、`assistant/message`、`assistant/attempt` 和 `tool/*` 是持久会话事件;其余是分属三个事件域的实时扩展点。`agent/assistant-stream` 发布进程本地 start、瞬态 chunk 与 end frame。loop 会在 committed end frame 前把完整紧凑 stream 提交为一个 message 或仅日志 attempt;Web Session-follow adapter 是该 live event 唯一的远程消费方。`agent/pre-step`、`agent/request`、`llm/stream` 和三个 `tools/*` 事件是 waterfall(瀑布式事件),其监听器必须调用 `next()` 才能委托下去;`agent/turn-stopping` 是 serial 事件,没有 `next()`。 +工厂 setup 在 Session 进入 SessionStore 并完成 `session/created` 之后、`agent/created` 之前运行;收尾事件在移除之前提交。 + 输入通过同一个 inbox 到达驱动器;注入的上下文等待一条唤醒消息。AgentLoop 的持久 `inbox` 投影使待处理输入在没有活跃 Agent 时仍可读取。 -循环在组装前快照 Session 模型选择,并通过 `AssembleContext.modelSelection` 与 `agent/pre-step.modelSelection` 传递该选择;重试保留该选择,省略推理强度时使用适配器默认值。`agent/pre-step` 决定接纳的输入。监听器可以改写或拒绝已领取消息;首次领取被拒绝或为空时,关闭不含步骤的持久轮次。enter 决策可设置 `startsRequestSeries`:循环记录新的 `request/header`(原因为 `series`,或在封装同时变化时为携带 `startsSeries: true` 的 `change`)。包装监听器通过 `{ ...decision, messages }` 保留该声明。组装与 `step/start` 之后,已弃用的 `agent/request` hook 在不改变提供方、模型或推理强度选择的前提下调整控制参数,`prepareCall()` 绑定适配器,再提交系统提示词与已接纳用户消息;在任一异步阶段取消都不会提交这两者。提示词准入依据已准备调用的能力,而非先前的 `request/context`。每次尝试刷新已注册运行时事实、协调绑定的提示词、仅接纳一次用户消息并恢复被移除的运行时上下文、按需记录 header/context,再冻结请求并通过绑定调用发起流式请求。重试不重复组装或 `agent/pre-step`。附接后的 surface 替换和图片省略决定开启新请求序列,包括恢复后的首次 pre-step 中发生的替换;未变化的恢复延续序列。系统提示词通过 `system/message` 历史传递:空文本清除提示词,具备能力的路由追加更新,其他路由将其归并到首个系统节点。[Agent-loop](../packages/core/agent-loop/README.zh.md#understand-the-implementation) 说明提示词准入与替换的细节。 +循环在组装前将 Session 模型选择快照到 `AssembleContext.modelSelection` 与 `agent/pre-step.modelSelection`;重试保留该选择,省略推理强度时使用适配器默认值。`agent/pre-step` 监听器接纳、改写或拒绝已领取消息;首次领取被拒绝或为空时,关闭不含步骤的持久轮次。enter 决策可设置 `startsRequestSeries`:循环记录新的 `request/header`(原因为 `series`,或在封装同时变化时为携带 `startsSeries: true` 的 `change`)。包装监听器通过 `{ ...decision, messages }` 保留该声明。组装与 `step/start` 之后,已弃用的 `agent/request` hook 在不改变提供方、模型或推理强度选择的前提下调整控制参数,`prepareCall()` 绑定适配器,再提交系统提示词与已接纳用户消息;在任一异步阶段取消都不会提交这两者。提示词准入依据已准备调用的能力,而非先前的 `request/context`。每次尝试刷新已注册运行时事实、协调绑定的提示词、仅接纳一次用户消息并恢复被移除的运行时上下文、按需记录 header/context,再冻结请求并通过绑定调用发起流式请求。重试不重复组装或 `agent/pre-step`。附接后的 surface 替换和图片省略决定开启新请求序列,包括恢复后的首次 pre-step 中发生的替换;未变化的恢复延续序列。系统提示词通过 `system/message` 历史传递:空文本清除提示词,具备能力的路由追加更新,其他路由将其归并到首个系统节点。[Agent-loop](../packages/core/agent-loop/README.zh.md#understand-the-implementation) 说明提示词准入与替换的细节。 循环发送不可变请求,同时保持取消有效,仅对完全冻结的对象复用冻结证据;[agent-loop](../packages/core/agent-loop/README.zh.md) 负责请求构建与取消原因。 diff --git a/docs/config-catalog.md b/docs/config-catalog.md index ea795c0d1d..b940c661dd 100644 --- a/docs/config-catalog.md +++ b/docs/config-catalog.md @@ -356,14 +356,14 @@ export interface Config { ## `@deepseek-ai/dsh-attachment-local` -- `source`: [`packages/attachment/attachment-local/src/index.ts:61`](../packages/attachment/attachment-local/src/index.ts) +- `source`: [`packages/attachment/attachment-local/src/index.ts:65`](../packages/attachment/attachment-local/src/index.ts) ```ts config-catalog /** Local attachment backend configuration. */ export interface Config { /** Explicit harness home; omitted follows `DSH_HOME`, then `~/.dsh`. */ dshHome?: string - /** Maximum encoded bytes accepted for one submitted image. Default: 20 MiB. */ + /** Maximum encoded bytes accepted for one submitted image. Default: 50 MiB. */ maxImageBytes?: number /** Maximum image count accepted in one submitted message. Default: 20. */ maxImagesPerMessage?: number @@ -371,7 +371,7 @@ export interface Config { maxMessageImageBytes?: number /** Maximum intrinsic width multiplied by height accepted for one submitted image. Default: 64,000,000. */ maxImagePixels?: number - /** Maximum intrinsic width and maximum intrinsic height accepted for one submitted image. Default: 8192px. */ + /** Maximum intrinsic width and maximum intrinsic height accepted for one submitted image. Default: 65,535px. */ maxImageDimension?: number /** Total-pixel budget of the stored provider-independent normalized image. */ normalizedImageMaxPixels?: number @@ -1623,7 +1623,7 @@ export interface Config { ## `@deepseek-ai/dsh-host-frontend-static` - `inject`: `webServer` · `connection` -- `source`: [`packages/host/frontend-static/src/index.ts:30`](../packages/host/frontend-static/src/index.ts) +- `source`: [`packages/host/frontend-static/src/index.ts:34`](../packages/host/frontend-static/src/index.ts) ```ts config-catalog /** Plugin config: the dist anchor. */ @@ -1708,7 +1708,7 @@ export interface Config { ## `@deepseek-ai/dsh-host-webserver` -- `source`: [`packages/host/webserver/src/index.ts:79`](../packages/host/webserver/src/index.ts) +- `source`: [`packages/host/webserver/src/index.ts:97`](../packages/host/webserver/src/index.ts) ```ts config-catalog /** Web server listen, TLS, and response-compression config. */ @@ -2396,9 +2396,9 @@ export interface Config { ## `@deepseek-ai/dsh-permission-presets` -- `inject`: `shell` · `approval` · `sessions` · `sessionProjections` +- `inject`: `shell` · `approval` · `sessions` · `agents` · `sessionProjections` - `refs`: [`ApprovalPolicy`](subsystems/approval.md) · [`SandboxMode`](subsystems/sandbox.md) · `Volatile` (`@deepseek-ai/cordis`) -- `source`: [`packages/interaction/permission-presets/src/index.ts:152`](../packages/interaction/permission-presets/src/index.ts) +- `source`: [`packages/interaction/permission-presets/src/index.ts:153`](../packages/interaction/permission-presets/src/index.ts) ```ts config-catalog /** The {@link PermissionPresetService} config: preset table and composition default. */ @@ -2467,7 +2467,7 @@ export interface Config { ## `@deepseek-ai/dsh-plan-mode` - `inject`: `tools` · `systemPrompt` · `sessionProjections` · `agents` -- `source`: [`packages/plan/plan-mode/src/index.ts:69`](../packages/plan/plan-mode/src/index.ts) +- `source`: [`packages/plan/plan-mode/src/index.ts:67`](../packages/plan/plan-mode/src/index.ts) ```ts config-catalog /** Deployment-owned plan guidance. */ @@ -2485,7 +2485,7 @@ export interface PlanModeConfig { - `inject`: `loader` · `profileContext` - `refs`: [`NpmFileSource`](subsystems/boot.md) -- `source`: [`packages/boot/plugin-manager/src/index.ts:50`](../packages/boot/plugin-manager/src/index.ts) +- `source`: [`packages/boot/plugin-manager/src/index.ts:51`](../packages/boot/plugin-manager/src/index.ts) ```ts config-catalog /** The pnpm executable, registries, and limits for diagnostics, lookups and connection checks. */ @@ -3640,7 +3640,7 @@ export interface Config { ## `@deepseek-ai/dsh-system-prompt` -- `source`: [`packages/core/system-prompt/src/index.ts:258`](../packages/core/system-prompt/src/index.ts) +- `source`: [`packages/core/system-prompt/src/index.ts:263`](../packages/core/system-prompt/src/index.ts) ```ts config-catalog /** Plugin config: the deployment-authored fragment of the system prompt (see {@link Config.personaPrefix} for its contract). */ @@ -4709,6 +4709,7 @@ These load from a `cordis.yml` entry with no `config:` block; they declare no co | `@deepseek-ai/dsh-client-ui-directory-picker-browse` | — | [`packages/client/ui-directory-picker-browse/src/index.ts`](../packages/client/ui-directory-picker-browse/src/index.ts) | | `@deepseek-ai/dsh-client-ui-directory-picker-native` | — | [`packages/client/ui-directory-picker-native/src/index.ts`](../packages/client/ui-directory-picker-native/src/index.ts) | | `@deepseek-ai/dsh-client-ui-entry-customization` | — | [`packages/client/ui-entry-customization/src/index.ts`](../packages/client/ui-entry-customization/src/index.ts) | +| `@deepseek-ai/dsh-client-ui-file-drag` | — | [`packages/client/ui-file-drag/src/index.ts`](../packages/client/ui-file-drag/src/index.ts) | | `@deepseek-ai/dsh-client-ui-goal` | — | [`packages/client/ui-goal/src/index.ts`](../packages/client/ui-goal/src/index.ts) | | `@deepseek-ai/dsh-client-ui-input-trigger` | — | [`packages/client/ui-input-trigger/src/index.ts`](../packages/client/ui-input-trigger/src/index.ts) | | `@deepseek-ai/dsh-client-ui-jobs` | — | [`packages/client/ui-jobs/src/index.ts`](../packages/client/ui-jobs/src/index.ts) | @@ -4870,6 +4871,7 @@ Imported as libraries by other packages; a `cordis.yml` cannot load them. | `@deepseek-ai/dsh-llm-mock-server` | — | [`packages/test-support/llm-mock-server/src/index.ts`](../packages/test-support/llm-mock-server/src/index.ts) | | `@deepseek-ai/dsh-loader-smoke` | — | [`packages/test-support/loader-smoke/src/index.ts`](../packages/test-support/loader-smoke/src/index.ts) | | `@deepseek-ai/dsh-native-command` | — | [`packages/util/native-command/src/index.ts`](../packages/util/native-command/src/index.ts) | +| `@deepseek-ai/dsh-official-bundles` | — | [`packages/boot/official-bundles/src/index.ts`](../packages/boot/official-bundles/src/index.ts) | | `@deepseek-ai/dsh-output-retention` | — | [`packages/util/output-retention/src/index.ts`](../packages/util/output-retention/src/index.ts) | | `@deepseek-ai/dsh-package-manifest` | — | [`packages/util/package-manifest/src/index.ts`](../packages/util/package-manifest/src/index.ts) | | `@deepseek-ai/dsh-plugin-detail` | — | [`packages/util/plugin-detail/src/index.ts`](../packages/util/plugin-detail/src/index.ts) | @@ -4897,6 +4899,7 @@ Imported as libraries by other packages; a `cordis.yml` cannot load them. | `@deepseek-ai/dsh-typert-registry` | — | [`packages/typert/registry/src/index.ts`](../packages/typert/registry/src/index.ts) | | `@deepseek-ai/dsh-util-code-language` | — | [`packages/util/code-language/src/index.ts`](../packages/util/code-language/src/index.ts) | | `@deepseek-ai/dsh-util-crypto` | — | [`packages/util/crypto/src/index.ts`](../packages/util/crypto/src/index.ts) | +| `@deepseek-ai/dsh-util-file-drag` | — | [`packages/util/file-drag/src/index.ts`](../packages/util/file-drag/src/index.ts) | | `@deepseek-ai/dsh-util-time` | — | [`packages/util/time/src/index.ts`](../packages/util/time/src/index.ts) | | `@deepseek-ai/dsh-util-values` | — | [`packages/util/values/src/index.ts`](../packages/util/values/src/index.ts) | | `@deepseek-ai/dsh-util-workspace-path` | — | [`packages/util/workspace-path/src/index.ts`](../packages/util/workspace-path/src/index.ts) | diff --git a/docs/config-catalog.zh.md b/docs/config-catalog.zh.md index 72b17ced85..8bae5febee 100644 --- a/docs/config-catalog.zh.md +++ b/docs/config-catalog.zh.md @@ -358,14 +358,14 @@ export interface Config { ## `@deepseek-ai/dsh-attachment-local` -- `source`: [`packages/attachment/attachment-local/src/index.ts:61`](../packages/attachment/attachment-local/src/index.ts) +- `source`: [`packages/attachment/attachment-local/src/index.ts:65`](../packages/attachment/attachment-local/src/index.ts) ```ts config-catalog /** Local attachment backend configuration. */ export interface Config { /** Explicit harness home; omitted follows `DSH_HOME`, then `~/.dsh`. */ dshHome?: string - /** Maximum encoded bytes accepted for one submitted image. Default: 20 MiB. */ + /** Maximum encoded bytes accepted for one submitted image. Default: 50 MiB. */ maxImageBytes?: number /** Maximum image count accepted in one submitted message. Default: 20. */ maxImagesPerMessage?: number @@ -373,7 +373,7 @@ export interface Config { maxMessageImageBytes?: number /** Maximum intrinsic width multiplied by height accepted for one submitted image. Default: 64,000,000. */ maxImagePixels?: number - /** Maximum intrinsic width and maximum intrinsic height accepted for one submitted image. Default: 8192px. */ + /** Maximum intrinsic width and maximum intrinsic height accepted for one submitted image. Default: 65,535px. */ maxImageDimension?: number /** Total-pixel budget of the stored provider-independent normalized image. */ normalizedImageMaxPixels?: number @@ -1625,7 +1625,7 @@ export interface Config { ## `@deepseek-ai/dsh-host-frontend-static` - `inject`: `webServer` · `connection` -- `source`: [`packages/host/frontend-static/src/index.ts:30`](../packages/host/frontend-static/src/index.ts) +- `source`: [`packages/host/frontend-static/src/index.ts:34`](../packages/host/frontend-static/src/index.ts) ```ts config-catalog /** Plugin config: the dist anchor. */ @@ -1710,7 +1710,7 @@ export interface Config { ## `@deepseek-ai/dsh-host-webserver` -- `source`: [`packages/host/webserver/src/index.ts:79`](../packages/host/webserver/src/index.ts) +- `source`: [`packages/host/webserver/src/index.ts:97`](../packages/host/webserver/src/index.ts) ```ts config-catalog /** Web server listen, TLS, and response-compression config. */ @@ -2398,9 +2398,9 @@ export interface Config { ## `@deepseek-ai/dsh-permission-presets` -- `inject`: `shell` · `approval` · `sessions` · `sessionProjections` +- `inject`: `shell` · `approval` · `sessions` · `agents` · `sessionProjections` - `refs`: [`ApprovalPolicy`](subsystems/approval.zh.md) · [`SandboxMode`](subsystems/sandbox.zh.md) · `Volatile` (`@deepseek-ai/cordis`) -- `source`: [`packages/interaction/permission-presets/src/index.ts:152`](../packages/interaction/permission-presets/src/index.ts) +- `source`: [`packages/interaction/permission-presets/src/index.ts:153`](../packages/interaction/permission-presets/src/index.ts) ```ts config-catalog /** The {@link PermissionPresetService} config: preset table and composition default. */ @@ -2469,7 +2469,7 @@ export interface Config { ## `@deepseek-ai/dsh-plan-mode` - `inject`: `tools` · `systemPrompt` · `sessionProjections` · `agents` -- `source`: [`packages/plan/plan-mode/src/index.ts:69`](../packages/plan/plan-mode/src/index.ts) +- `source`: [`packages/plan/plan-mode/src/index.ts:67`](../packages/plan/plan-mode/src/index.ts) ```ts config-catalog /** Deployment-owned plan guidance. */ @@ -2487,7 +2487,7 @@ export interface PlanModeConfig { - `inject`: `loader` · `profileContext` - `refs`: [`NpmFileSource`](subsystems/boot.zh.md) -- `source`: [`packages/boot/plugin-manager/src/index.ts:50`](../packages/boot/plugin-manager/src/index.ts) +- `source`: [`packages/boot/plugin-manager/src/index.ts:51`](../packages/boot/plugin-manager/src/index.ts) ```ts config-catalog /** The pnpm executable, registries, and limits for diagnostics, lookups and connection checks. */ @@ -3642,7 +3642,7 @@ export interface Config { ## `@deepseek-ai/dsh-system-prompt` -- `source`: [`packages/core/system-prompt/src/index.ts:258`](../packages/core/system-prompt/src/index.ts) +- `source`: [`packages/core/system-prompt/src/index.ts:263`](../packages/core/system-prompt/src/index.ts) ```ts config-catalog /** Plugin config: the deployment-authored fragment of the system prompt (see {@link Config.personaPrefix} for its contract). */ @@ -4711,6 +4711,7 @@ export interface Config { | `@deepseek-ai/dsh-client-ui-directory-picker-browse` | — | [`packages/client/ui-directory-picker-browse/src/index.ts`](../packages/client/ui-directory-picker-browse/src/index.ts) | | `@deepseek-ai/dsh-client-ui-directory-picker-native` | — | [`packages/client/ui-directory-picker-native/src/index.ts`](../packages/client/ui-directory-picker-native/src/index.ts) | | `@deepseek-ai/dsh-client-ui-entry-customization` | — | [`packages/client/ui-entry-customization/src/index.ts`](../packages/client/ui-entry-customization/src/index.ts) | +| `@deepseek-ai/dsh-client-ui-file-drag` | — | [`packages/client/ui-file-drag/src/index.ts`](../packages/client/ui-file-drag/src/index.ts) | | `@deepseek-ai/dsh-client-ui-goal` | — | [`packages/client/ui-goal/src/index.ts`](../packages/client/ui-goal/src/index.ts) | | `@deepseek-ai/dsh-client-ui-input-trigger` | — | [`packages/client/ui-input-trigger/src/index.ts`](../packages/client/ui-input-trigger/src/index.ts) | | `@deepseek-ai/dsh-client-ui-jobs` | — | [`packages/client/ui-jobs/src/index.ts`](../packages/client/ui-jobs/src/index.ts) | @@ -4872,6 +4873,7 @@ export interface Config { | `@deepseek-ai/dsh-llm-mock-server` | — | [`packages/test-support/llm-mock-server/src/index.ts`](../packages/test-support/llm-mock-server/src/index.ts) | | `@deepseek-ai/dsh-loader-smoke` | — | [`packages/test-support/loader-smoke/src/index.ts`](../packages/test-support/loader-smoke/src/index.ts) | | `@deepseek-ai/dsh-native-command` | — | [`packages/util/native-command/src/index.ts`](../packages/util/native-command/src/index.ts) | +| `@deepseek-ai/dsh-official-bundles` | — | [`packages/boot/official-bundles/src/index.ts`](../packages/boot/official-bundles/src/index.ts) | | `@deepseek-ai/dsh-output-retention` | — | [`packages/util/output-retention/src/index.ts`](../packages/util/output-retention/src/index.ts) | | `@deepseek-ai/dsh-package-manifest` | — | [`packages/util/package-manifest/src/index.ts`](../packages/util/package-manifest/src/index.ts) | | `@deepseek-ai/dsh-plugin-detail` | — | [`packages/util/plugin-detail/src/index.ts`](../packages/util/plugin-detail/src/index.ts) | @@ -4899,6 +4901,7 @@ export interface Config { | `@deepseek-ai/dsh-typert-registry` | — | [`packages/typert/registry/src/index.ts`](../packages/typert/registry/src/index.ts) | | `@deepseek-ai/dsh-util-code-language` | — | [`packages/util/code-language/src/index.ts`](../packages/util/code-language/src/index.ts) | | `@deepseek-ai/dsh-util-crypto` | — | [`packages/util/crypto/src/index.ts`](../packages/util/crypto/src/index.ts) | +| `@deepseek-ai/dsh-util-file-drag` | — | [`packages/util/file-drag/src/index.ts`](../packages/util/file-drag/src/index.ts) | | `@deepseek-ai/dsh-util-time` | — | [`packages/util/time/src/index.ts`](../packages/util/time/src/index.ts) | | `@deepseek-ai/dsh-util-values` | — | [`packages/util/values/src/index.ts`](../packages/util/values/src/index.ts) | | `@deepseek-ai/dsh-util-workspace-path` | — | [`packages/util/workspace-path/src/index.ts`](../packages/util/workspace-path/src/index.ts) | diff --git a/docs/cordis-api/fiber.i18n.yaml b/docs/cordis-api/fiber.i18n.yaml index acc84e2f3a..042af3ba02 100644 --- a/docs/cordis-api/fiber.i18n.yaml +++ b/docs/cordis-api/fiber.i18n.yaml @@ -24,8 +24,8 @@ en: 1b527d85759324f9 zh: 54aa40db2705b95c /fiber/the-fiber-class/fiber-config: - en: ee804c03c39e7806 - zh: 4353ba7817ec61ec + en: 1efe137a7ef0e599 + zh: bb4b9818fb48f4e9 /fiber/the-fiber-class/fiber-state: en: 999ad29dfc29661b zh: 20245d11c338e3f1 @@ -50,15 +50,24 @@ /fiber/the-fiber-class/fiber-geteffects: en: 4d739a9c186fd9c2 zh: f80fd3b87e79b004 +/fiber/the-fiber-class/fiber-rawconfig: + en: 898aab51825bd8c3 + zh: b9ab6339574002df +/fiber/the-fiber-class/fiber-effectiveconfig: + en: 93ac680251e7023f + zh: 8ea7d7de5db39b8e +/fiber/the-fiber-class/fiber-resolveconfig-config: + en: d7319852e2a1c3a9 + zh: 3300fac049227006 /fiber/the-fiber-class/fiber-await: - en: 1d6258cbea61cd18 - zh: 2f10dda8918dadc5 + en: c9a6544cacdbc28e + zh: 636bf93efad95bc9 /fiber/the-fiber-class/fiber-restart: - en: 62d68dedb20b4fa9 - zh: 5a735ae0ff1266f4 + en: 6ffc1baba98d689f + zh: 7e13bc92225c7e0a /fiber/the-fiber-class/fiber-update-config-nosave: - en: b57ce0f6260c2cb8 - zh: 3bfb6c5bc252a2c2 + en: 5c176a6e67073e92 + zh: ee07edc8dbf7c1f3 /fiber/effect: en: 007d5b214e8a8610 zh: d74c26fbb1b8aeb6 diff --git a/docs/cordis-api/fiber.md b/docs/cordis-api/fiber.md index 3044301eff..e85cc7b3e6 100644 --- a/docs/cordis-api/fiber.md +++ b/docs/cordis-api/fiber.md @@ -80,11 +80,11 @@ The context this fiber's plugin runs in (extends the parent context). ### fiber.config ```ts cordis-catalog -/** The validated plugin config (updated by `update()`). */ +/** The validated plugin config (updated by `update()`); read through {@link effectiveConfig}. */ public config: any ``` -The validated plugin config (updated by `update()`). +The validated plugin config (updated by `update()`); read through effectiveConfig. [Source](../../vendor/cordis/src/fiber.ts#L190) @@ -209,6 +209,53 @@ Return metadata for currently registered effects. [Source](../../vendor/cordis/src/fiber.ts#L568) +### fiber.rawConfig + +```ts cordis-catalog +/** Raw input retained for the next activation, without evaluating expressions or validating it. */ +get rawConfig(): unknown +``` + +Raw input retained for the next activation, without evaluating expressions or validating it. + +[Source](../../vendor/cordis/src/fiber.ts#L642) + +### fiber.effectiveConfig + +```ts cordis-catalog +/** + * The config object published by the existing activation/update lifecycle, without cloning or re-parsing. + * It is undefined before the first resolution and remains readable after unload; callers requiring a live instance check `state`. + */ +get effectiveConfig(): unknown +``` + +The config object published by the existing activation/update lifecycle, without cloning or re-parsing. It is undefined before the first resolution and remains readable after unload; callers requiring a live instance check `state`. + +[Source](../../vendor/cordis/src/fiber.ts#L655) + +### fiber.resolveConfig(config) + +```ts cordis-catalog +/** + * Evaluate and validate a candidate using this fiber's `internal/config` hooks and runtime schema. + * Does not publish the result, replace raw input, or commit running volatile references. + * Required injections must be available when a hook uses them. + * @param config Raw candidate input. + * @returns The candidate's resolved config, retaining the schema's result identity. + * @throws {ValidationError} when the runtime schema rejects the candidate; hook errors propagate. + */ +resolveConfig(config: unknown): unknown +``` + +Evaluate and validate a candidate using this fiber's `internal/config` hooks and runtime schema. Does not publish the result, replace raw input, or commit running volatile references. Required injections must be available when a hook uses them. + +- `config` — Raw candidate input. + +**Returns** The candidate's resolved config, retaining the schema's result identity. + +[Source](../../vendor/cordis/src/fiber.ts#L667) + ### fiber.await() ```ts cordis-catalog @@ -225,7 +272,7 @@ Wait for current lifecycle work and rethrow startup errors. **Returns** this fiber, once it has settled into a stable state. -[Source](../../vendor/cordis/src/fiber.ts#L704) +[Source](../../vendor/cordis/src/fiber.ts#L731) ### fiber.restart() @@ -243,7 +290,7 @@ Dispose and immediately reload this plugin with its current config. **Returns** a promise resolving once the reload settled. -[Source](../../vendor/cordis/src/fiber.ts#L718) +[Source](../../vendor/cordis/src/fiber.ts#L745) ### fiber.update(config, noSave?) @@ -271,7 +318,7 @@ Runs the `internal/update` waterfall first, so update hooks (and HMR) can veto o **Returns** nothing; the restart runs behind the `internal/update` waterfall. -[Source](../../vendor/cordis/src/fiber.ts#L736) +[Source](../../vendor/cordis/src/fiber.ts#L764) ## Effect diff --git a/docs/cordis-api/fiber.zh.md b/docs/cordis-api/fiber.zh.md index bee2f523f1..d529013e73 100644 --- a/docs/cordis-api/fiber.zh.md +++ b/docs/cordis-api/fiber.zh.md @@ -82,11 +82,11 @@ public readonly ctx: Context ### fiber.config ```ts cordis-catalog -/** The validated plugin config (updated by `update()`). */ +/** The validated plugin config (updated by `update()`); read through {@link effectiveConfig}. */ public config: any ``` -经过校验的插件配置(由 `update()` 更新)。 +经过校验的插件配置(由 `update()` 更新);通过 `effectiveConfig` 读取。 [源码](../../vendor/cordis/src/fiber.ts#L190) @@ -211,6 +211,53 @@ getEffects() [源码](../../vendor/cordis/src/fiber.ts#L568) +### fiber.rawConfig + +```ts cordis-catalog +/** Raw input retained for the next activation, without evaluating expressions or validating it. */ +get rawConfig(): unknown +``` + +保留供下次激活使用的原始输入,不执行表达式求值或验证。 + +[源码](../../vendor/cordis/src/fiber.ts#L642) + +### fiber.effectiveConfig + +```ts cordis-catalog +/** + * The config object published by the existing activation/update lifecycle, without cloning or re-parsing. + * It is undefined before the first resolution and remains readable after unload; callers requiring a live instance check `state`. + */ +get effectiveConfig(): unknown +``` + +既有激活/更新生命周期发布的配置对象,不克隆或重新解析。首次解析前为 undefined,卸载后仍可读取;需要运行实例的调用方应检查 `state`。 + +[源码](../../vendor/cordis/src/fiber.ts#L655) + +### fiber.resolveConfig(config) + +```ts cordis-catalog +/** + * Evaluate and validate a candidate using this fiber's `internal/config` hooks and runtime schema. + * Does not publish the result, replace raw input, or commit running volatile references. + * Required injections must be available when a hook uses them. + * @param config Raw candidate input. + * @returns The candidate's resolved config, retaining the schema's result identity. + * @throws {ValidationError} when the runtime schema rejects the candidate; hook errors propagate. + */ +resolveConfig(config: unknown): unknown +``` + +通过此 fiber 的 `internal/config` 钩子和运行时 schema 对候选值求值并验证。此操作不发布结果、不替换原始输入,也不提交运行中的 volatile 引用。钩子访问的注入服务必须已经可用。 + +- `config`:原始候选输入。 + +**返回**候选配置的解析结果,保留 schema 返回对象的身份。 + +[源码](../../vendor/cordis/src/fiber.ts#L667) + ### fiber.await() ```ts cordis-catalog @@ -227,7 +274,7 @@ async await() **返回**:进入稳定状态后的此 fiber。 -[源码](../../vendor/cordis/src/fiber.ts#L704) +[源码](../../vendor/cordis/src/fiber.ts#L731) ### fiber.restart() @@ -245,7 +292,7 @@ dispose 此插件,并立即使用其当前配置重新加载。 **返回**一个在重新加载完成后兑现的 promise。 -[源码](../../vendor/cordis/src/fiber.ts#L718) +[源码](../../vendor/cordis/src/fiber.ts#L745) ### fiber.update(config, noSave?) @@ -273,7 +320,7 @@ update(config: any, noSave = false) **返回**无返回值;重启由 `internal/update` waterfall 执行。 -[源码](../../vendor/cordis/src/fiber.ts#L736) +[源码](../../vendor/cordis/src/fiber.ts#L764) ## Effect diff --git a/docs/development.i18n.yaml b/docs/development.i18n.yaml index f7cd583405..089970df47 100644 --- a/docs/development.i18n.yaml +++ b/docs/development.i18n.yaml @@ -30,8 +30,8 @@ en: 2efb7c4e482413fc zh: 75386476a283111a /development-guide/contributor-reference/ci-gates: - en: 16e515e3d94f1cfc - zh: fe8cf9deec64581a + en: dfa3a24d9070478f + zh: fa889b3536ab58e2 /development-guide/contributor-reference/daily-commands: en: 08aa6ec1cdabfeb7 zh: dcce5ae9d3c829d0 diff --git a/docs/development.md b/docs/development.md index c75f6647fe..8b7c6a8e46 100644 --- a/docs/development.md +++ b/docs/development.md @@ -155,7 +155,7 @@ Outside CI (`CI` other than `true`), default worker counts follow the [local wor ### CI gates -The keyless [CI workflow](../.github/workflows/ci.yml) groups independent gates into broad lanes and runs a smaller compatibility signal across supported Node versions. Artifact consumers wait for one build within their lane. Coverage partitions reuse file timings scoped to their platform and runner pool to balance work within the configured worker limit. Required benchmarks run separately on standard GitHub-hosted Linux; the [benchmark runner reference](../benchmarks/AGENTS.md) owns routing and the job timeout. The separate real-API workflow runs `pnpm run test:e2e` with its configured worker bound. See [scripts/run-gates.ts](../scripts/run-gates.ts) and the workflow files for the current gate and job inventory. +The keyless [CI workflow](../.github/workflows/ci.yml) groups independent gates into broad lanes and runs a smaller compatibility signal across supported Node versions. Artifact consumers wait for one build within their lane. Coverage partitions reuse file timings scoped to their platform and runner pool to balance work within the configured worker limit. Native Windows lanes run in the separate [CI Windows workflow](../.github/workflows/ci-windows.yml) and Python checks in the separate [CI Python workflow](../.github/workflows/ci-python.yml), each of which can be re-run independently. Required benchmarks run separately on standard GitHub-hosted Linux; the [benchmark runner reference](../benchmarks/AGENTS.md) owns routing and the job timeout. The separate real-API workflow runs `pnpm run test:e2e` with its configured worker bound. See [scripts/run-gates.ts](../scripts/run-gates.ts) and the workflow files for the current gate and job inventory. The credential-free dsh dependency-layout and dsh/vendor pack rehearsals use the existing Linux self-hosted pool only when `DSH_CI_FAILOVER_LINUX=selfhosted` and the event is a trusted master push or same-repository, non-fork, non-Dependabot pull request. All other cases, including manual dispatch, use `ubuntu-24.94`; manual publication stays hosted. See the [release rehearsal runner reference](../.agents/notes/implemented/process/2026-07-26-ci-failover-runbook.md) for persistent-store isolation and fallback limits. diff --git a/docs/development.zh.md b/docs/development.zh.md index be63a28fed..fc445f0ab0 100644 --- a/docs/development.zh.md +++ b/docs/development.zh.md @@ -160,7 +160,7 @@ pi-ai 检查会在内存中重新生成预期元数据。数据过期时,检 ### CI 门禁 -keyless [CI 工作流](../.github/workflows/ci.yml) 将独立门禁分组到若干宽粒度 lane,并在受支持的 Node 版本上运行一组较小的兼容性检查。产物消费方在各自 lane 内等待一次 build。覆盖率分区复用按平台和运行器池隔离的文件耗时,在配置的 worker 上限内均衡工作量。必需 benchmark 在标准 GitHub 托管 Linux 上独立运行;[benchmark 运行器说明](../benchmarks/AGENTS.md)拥有路由及 job 超时。单独的真实 API 工作流按其配置的 worker 上限运行 `pnpm run test:e2e`。当前门禁和 job 清单以 [scripts/run-gates.ts](../scripts/run-gates.ts) 和工作流文件为准。 +keyless [CI 工作流](../.github/workflows/ci.yml) 将独立门禁分组到若干宽粒度 lane,并在受支持的 Node 版本上运行一组较小的兼容性检查。产物消费方在各自 lane 内等待一次 build。覆盖率分区复用按平台和运行器池隔离的文件耗时,在配置的 worker 上限内均衡工作量。原生 Windows lane 运行在独立的 [CI Windows 工作流](../.github/workflows/ci-windows.yml)中,Python 检查运行在独立的 [CI Python 工作流](../.github/workflows/ci-python.yml)中,两者都可单独重新运行。必需 benchmark 在标准 GitHub 托管 Linux 上独立运行;[benchmark 运行器说明](../benchmarks/AGENTS.md)拥有路由及 job 超时。单独的真实 API 工作流按其配置的 worker 上限运行 `pnpm run test:e2e`。当前门禁和 job 清单以 [scripts/run-gates.ts](../scripts/run-gates.ts) 和工作流文件为准。 不带凭据的 dsh 依赖布局检查与 dsh/vendor 打包演练仅在 `DSH_CI_FAILOVER_LINUX=selfhosted`,且事件为受信任的 master 推送或同仓库、非 fork、非 Dependabot 拉取请求时使用现有 Linux 自托管池。其余情况(包括手动触发)均使用 `ubuntu-24.94`;手动发布仍使用托管运行器。持久化存储隔离与回退限制见[发布演练运行器说明](../.agents/notes/implemented/process/2026-07-26-ci-failover-runbook.zh.md)。 diff --git a/docs/event-producer-consumer.md b/docs/event-producer-consumer.md index 9ac5a22909..bcf0ecc982 100644 --- a/docs/event-producer-consumer.md +++ b/docs/event-producer-consumer.md @@ -11,7 +11,7 @@ This matrix shows which packages dispatch each harness-owned event and which pac | `agent-loop/config-start-failed` | `emit` | [`packages/core/agent-loop/src/index.ts:199`](../packages/core/agent-loop/src/index.ts) | [`agent-loop`](../packages/core/agent-loop) (`events.dispatch`) | - | | `agent-preset/selected` | `emit` | [`packages/preset/agent-preset-registry/src/types.ts:66`](../packages/preset/agent-preset-registry/src/types.ts) | [`agent-preset-registry`](../packages/preset/agent-preset-registry) (`emit`) | [`cua`](../packages/experimental/cua), `remotes` | | `agent/assistant-stream` | `emit` | [`packages/core/agent/src/runtime-types.ts:399`](../packages/core/agent/src/runtime-types.ts) | [`agent-loop`](../packages/core/agent-loop) (`emit`) | [`headless`](../packages/bundle/headless), `session-controller` | -| `agent/created` | `serial` | [`packages/core/agent/src/runtime-types.ts:290`](../packages/core/agent/src/runtime-types.ts) | [`agent`](../packages/core/agent) (`serial`) | `agent-team`, `browser-use-runtime`, `claude-code-mods`, [`cua`](../packages/experimental/cua), [`file-reference-local`](../packages/context/file-reference-local), [`goal`](../packages/goal/goal), [`goal-round-driver`](../packages/goal/goal-round-driver), [`hooks-claude-code`](../packages/experimental/hooks-claude-code), [`hooks-codex`](../packages/experimental/hooks-codex), [`loader-smoke`](../packages/test-support/loader-smoke), `session-controller`, `tool-agent-team`, [`tool-subagent`](../packages/subagent/tool-subagent) | +| `agent/created` | `serial` | [`packages/core/agent/src/runtime-types.ts:290`](../packages/core/agent/src/runtime-types.ts) | [`agent`](../packages/core/agent) (`serial`) | `agent-team`, `browser-use-runtime`, `claude-code-mods`, [`cua`](../packages/experimental/cua), [`file-reference-local`](../packages/context/file-reference-local), [`goal`](../packages/goal/goal), [`goal-round-driver`](../packages/goal/goal-round-driver), [`hooks-claude-code`](../packages/experimental/hooks-claude-code), [`hooks-codex`](../packages/experimental/hooks-codex), [`loader-smoke`](../packages/test-support/loader-smoke), [`permission-presets`](../packages/interaction/permission-presets), `session-controller`, `tool-agent-team`, [`tool-subagent`](../packages/subagent/tool-subagent) | | `agent/disposed` | `emit` | [`packages/core/agent/src/runtime-types.ts:299`](../packages/core/agent/src/runtime-types.ts) | [`agent`](../packages/core/agent) (`events.dispatch`) | [`agent-loop`](../packages/core/agent-loop), `claude-code-mods`, [`file-reference-local`](../packages/context/file-reference-local), [`goal-round-driver`](../packages/goal/goal-round-driver), `session-controller`, [`subagent`](../packages/subagent/subagent), `tool-agent-team`, [`tool-subagent`](../packages/subagent/tool-subagent) | | `agent/error` | `emit` | [`packages/core/agent/src/runtime-types.ts:429`](../packages/core/agent/src/runtime-types.ts) | [`agent-loop`](../packages/core/agent-loop) (`emit`) | [`acp`](../packages/acp/acp), [`deepseek-account`](../packages/credentials/deepseek-account), [`goal-round-driver`](../packages/goal/goal-round-driver), [`headless`](../packages/bundle/headless), `server`, `session-controller`, [`session-telemetry`](../packages/session/session-telemetry), [`subagent`](../packages/subagent/subagent) | | `agent/inbox/claimed` | `emit` | [`packages/core/agent/src/runtime-types.ts:328`](../packages/core/agent/src/runtime-types.ts) | [`agent-loop`](../packages/core/agent-loop) (`emit`) | [`acp`](../packages/acp/acp), [`goal-round-driver`](../packages/goal/goal-round-driver), [`subagent`](../packages/subagent/subagent), [`tool-jobs`](../packages/jobs/tool-jobs), [`user-questions`](../packages/interaction/user-questions) | @@ -21,12 +21,12 @@ This matrix shows which packages dispatch each harness-owned event and which pac | `agent/request-error` | `waterfall` | [`packages/core/agent/src/runtime-types.ts:389`](../packages/core/agent/src/runtime-types.ts) | [`agent-loop`](../packages/core/agent-loop) (`waterfall`) | [`compaction-basic`](../packages/compaction/compaction-basic), [`compaction-image-offload`](../packages/compaction/compaction-image-offload), [`llm-retry`](../packages/llm/llm-retry) | | `agent/status` | `emit` | [`packages/core/agent/src/runtime-types.ts:309`](../packages/core/agent/src/runtime-types.ts) | [`agent-loop`](../packages/core/agent-loop) (`emit`) | [`acp`](../packages/acp/acp), `agent-team`, [`compaction-basic`](../packages/compaction/compaction-basic), [`goal-round-driver`](../packages/goal/goal-round-driver), `server`, `session-controller` | | `agent/turn-stopping` | `serial` | [`packages/core/agent/src/runtime-types.ts:417`](../packages/core/agent/src/runtime-types.ts) | [`agent-loop`](../packages/core/agent-loop) (`serial`) | [`hooks-claude-code`](../packages/experimental/hooks-claude-code), [`hooks-codex`](../packages/experimental/hooks-codex), [`workspace-changes`](../packages/deliverables/workspace-changes) | -| `api-session/activity` | `emit` | [`packages/api/session-controller/src/types.ts:599`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` | -| `api-session/added` | `emit` | [`packages/api/session-controller/src/types.ts:579`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` | -| `api-session/error` | `emit` | [`packages/api/session-controller/src/types.ts:606`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` | -| `api-session/removed` | `emit` | [`packages/api/session-controller/src/types.ts:585`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` | -| `api-session/status` | `emit` | [`packages/api/session-controller/src/types.ts:592`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` | -| `app-boot/config-reload` | `emit` | [`packages/boot/app-boot/src/index.ts:54`](../packages/boot/app-boot/src/index.ts) | [`app-boot`](../packages/boot/app-boot) (`emit`) | [`settings`](../packages/settings/settings) | +| `api-session/activity` | `emit` | [`packages/api/session-controller/src/types.ts:600`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` | +| `api-session/added` | `emit` | [`packages/api/session-controller/src/types.ts:580`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` | +| `api-session/error` | `emit` | [`packages/api/session-controller/src/types.ts:607`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` | +| `api-session/removed` | `emit` | [`packages/api/session-controller/src/types.ts:586`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` | +| `api-session/status` | `emit` | [`packages/api/session-controller/src/types.ts:593`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` | +| `app-boot/config-reload` | `emit` | [`packages/boot/app-boot/src/index.ts:53`](../packages/boot/app-boot/src/index.ts) | [`app-boot`](../packages/boot/app-boot) (`emit`) | [`settings`](../packages/settings/settings) | | `approval/request` | `waterfall` | [`packages/interaction/user-approval/src/types.ts:87`](../packages/interaction/user-approval/src/types.ts) | [`user-approval`](../packages/interaction/user-approval) (`waterfall`) | [`acp`](../packages/acp/acp), `remotes`, `server` | | `authorization/settled` | `emit` | [`packages/credentials/authorization/src/index.ts:57`](../packages/credentials/authorization/src/index.ts) | [`authorization`](../packages/credentials/authorization) (`events.dispatch`) | - | | `commands/change` | `emit` | [`packages/interaction/commands/src/types.ts:89`](../packages/interaction/commands/src/types.ts) | [`commands`](../packages/interaction/commands) (`events.dispatch`) | `remotes` | @@ -63,10 +63,10 @@ This matrix shows which packages dispatch each harness-owned event and which pac | `schedule/changed` | `emit` | [`packages/schedule/schedule/src/types.ts:478`](../packages/schedule/schedule/src/types.ts) | [`schedule`](../packages/schedule/schedule) (`emit`) | `remotes` | | `schedule/resolve-agent` | `waterfall` | [`packages/schedule/schedule/src/index.ts:74`](../packages/schedule/schedule/src/index.ts) | [`schedule`](../packages/schedule/schedule) (`waterfall`) | `server` | | `session-telemetry/record` | `waterfall` | [`packages/session/session-telemetry/src/index.ts:44`](../packages/session/session-telemetry/src/index.ts) | [`session-telemetry`](../packages/session/session-telemetry) (`waterfall`) | - | -| `session/created` | `emit` | [`packages/core/session/src/index.ts:54`](../packages/core/session/src/index.ts) | [`session`](../packages/core/session) (`events.dispatch`) | [`permission-presets`](../packages/interaction/permission-presets), [`schedule`](../packages/schedule/schedule), `server`, `session-controller`, [`session-projection`](../packages/session/session-projection), [`session-projection-cache`](../packages/session/session-projection-cache), [`session-telemetry`](../packages/session/session-telemetry) | -| `session/disposed` | `emit` | [`packages/core/session/src/index.ts:63`](../packages/core/session/src/index.ts) | [`session`](../packages/core/session) (`events.dispatch`) | [`agent-loop`](../packages/core/agent-loop), `agent-team`, `file-upload`, `session-controller`, [`session-persistence-jsonl`](../packages/session/session-persistence-jsonl), [`session-projection-cache`](../packages/session/session-projection-cache), [`session-telemetry`](../packages/session/session-telemetry), [`session-title`](../packages/session/session-title), [`workspace-changes`](../packages/deliverables/workspace-changes) | -| `session/event` | `emit` | [`packages/core/session/src/index.ts:74`](../packages/core/session/src/index.ts) | [`session`](../packages/core/session) (`events.dispatch`) | [`acp`](../packages/acp/acp), [`agent-instructions`](../packages/context/agent-instructions), [`agent-loop`](../packages/core/agent-loop), [`agent-preset-registry`](../packages/preset/agent-preset-registry), `agent-team`, `claude-code-mods`, [`compaction-basic`](../packages/compaction/compaction-basic), [`file-reference-local`](../packages/context/file-reference-local), `file-upload`, [`goal`](../packages/goal/goal), [`goal-round-driver`](../packages/goal/goal-round-driver), [`headless`](../packages/bundle/headless), [`loader-smoke`](../packages/test-support/loader-smoke), `product-analytics`, [`ptc-runtime-node`](../packages/ptc-runtime/ptc-runtime-node), `server`, `session-controller`, [`session-persistence-jsonl`](../packages/session/session-persistence-jsonl), [`session-projection`](../packages/session/session-projection), [`session-projection-cache`](../packages/session/session-projection-cache), [`session-telemetry`](../packages/session/session-telemetry), [`session-telemetry-otel`](../packages/session/session-telemetry-otel), [`session-title`](../packages/session/session-title), [`subagent`](../packages/subagent/subagent), [`token-meter`](../packages/llm/token-meter), [`tool-executor-ptc`](../packages/core/tool-executor-ptc), [`tool-jobs`](../packages/jobs/tool-jobs), [`user-questions`](../packages/interaction/user-questions), [`workspace-changes`](../packages/deliverables/workspace-changes) | -| `session/flush` | `parallel` | [`packages/core/session/src/index.ts:82`](../packages/core/session/src/index.ts) | [`session`](../packages/core/session) (`events.dispatch`) | [`session-persistence-jsonl`](../packages/session/session-persistence-jsonl), [`session-telemetry`](../packages/session/session-telemetry) | +| `session/created` | `emit` | [`packages/core/session/src/index.ts:56`](../packages/core/session/src/index.ts) | [`session`](../packages/core/session) (`events.dispatch`) | [`schedule`](../packages/schedule/schedule), `server`, `session-controller`, [`session-projection`](../packages/session/session-projection), [`session-projection-cache`](../packages/session/session-projection-cache), [`session-telemetry`](../packages/session/session-telemetry) | +| `session/disposed` | `emit` | [`packages/core/session/src/index.ts:65`](../packages/core/session/src/index.ts) | [`session`](../packages/core/session) (`events.dispatch`) | [`agent-loop`](../packages/core/agent-loop), `agent-team`, `file-upload`, `session-controller`, [`session-persistence-jsonl`](../packages/session/session-persistence-jsonl), [`session-projection-cache`](../packages/session/session-projection-cache), [`session-telemetry`](../packages/session/session-telemetry), [`session-title`](../packages/session/session-title), [`workspace-changes`](../packages/deliverables/workspace-changes) | +| `session/event` | `emit` | [`packages/core/session/src/index.ts:76`](../packages/core/session/src/index.ts) | [`session`](../packages/core/session) (`events.dispatch`) | [`acp`](../packages/acp/acp), [`agent-instructions`](../packages/context/agent-instructions), [`agent-loop`](../packages/core/agent-loop), [`agent-preset-registry`](../packages/preset/agent-preset-registry), `agent-team`, `claude-code-mods`, [`compaction-basic`](../packages/compaction/compaction-basic), [`file-reference-local`](../packages/context/file-reference-local), `file-upload`, [`goal`](../packages/goal/goal), [`goal-round-driver`](../packages/goal/goal-round-driver), [`headless`](../packages/bundle/headless), [`loader-smoke`](../packages/test-support/loader-smoke), `product-analytics`, [`ptc-runtime-node`](../packages/ptc-runtime/ptc-runtime-node), `server`, `session-controller`, [`session-persistence-jsonl`](../packages/session/session-persistence-jsonl), [`session-projection`](../packages/session/session-projection), [`session-projection-cache`](../packages/session/session-projection-cache), [`session-telemetry`](../packages/session/session-telemetry), [`session-telemetry-otel`](../packages/session/session-telemetry-otel), [`session-title`](../packages/session/session-title), [`subagent`](../packages/subagent/subagent), [`token-meter`](../packages/llm/token-meter), [`tool-executor-ptc`](../packages/core/tool-executor-ptc), [`tool-jobs`](../packages/jobs/tool-jobs), [`user-questions`](../packages/interaction/user-questions), [`workspace-changes`](../packages/deliverables/workspace-changes) | +| `session/flush` | `parallel` | [`packages/core/session/src/index.ts:84`](../packages/core/session/src/index.ts) | [`session`](../packages/core/session) (`events.dispatch`) | [`session-persistence-jsonl`](../packages/session/session-persistence-jsonl), [`session-telemetry`](../packages/session/session-telemetry) | | `settings/document-updated` | `emit` | [`packages/settings/settings/src/types.ts:75`](../packages/settings/settings/src/types.ts) | [`settings`](../packages/settings/settings) (`emit`) | `remotes` | | `skills/change` | `emit` | [`packages/skill/skill/src/index.ts:296`](../packages/skill/skill/src/index.ts) | [`skill`](../packages/skill/skill) (`events.dispatch`) | - | | `subagent/end` | `emit` | [`packages/subagent/subagent/src/index.ts:166`](../packages/subagent/subagent/src/index.ts) | [`subagent`](../packages/subagent/subagent) (`events.dispatch`) | [`hooks-claude-code`](../packages/experimental/hooks-claude-code), `server` | @@ -82,7 +82,7 @@ This matrix shows which packages dispatch each harness-owned event and which pac | `tools/ptc-dispatch-log` | `waterfall` | [`packages/core/tool-executor-ptc/src/runtime-types.ts:46`](../packages/core/tool-executor-ptc/src/runtime-types.ts) | [`tool-executor-ptc`](../packages/core/tool-executor-ptc) (`waterfall`) | [`spill-policy`](../packages/spill/spill-policy) | | `tools/result` | `emit` | [`packages/core/tools/src/events.ts:49`](../packages/core/tools/src/events.ts) | [`tools`](../packages/core/tools) (`events.dispatch`) | [`agent-instructions`](../packages/context/agent-instructions), `claude-code-mods`, [`subagent`](../packages/subagent/subagent), [`tool-present`](../packages/deliverables/tool-present) | | `user-questions/request` | `waterfall` | [`packages/interaction/user-questions/src/types.ts:174`](../packages/interaction/user-questions/src/types.ts) | [`user-questions`](../packages/interaction/user-questions) (`waterfall`) | `remotes`, `server` | -| `webserver/index-inject` | `emit` | [`packages/host/webserver/src/index.ts:42`](../packages/host/webserver/src/index.ts) | `webserver` (`emit`) | `connection`, `inspector`, `modules`, `remote-access`, `shortcuts`, `ui-sidebar-documentpreview`, `ui-theme` | +| `webserver/index-inject` | `emit` | [`packages/host/webserver/src/index.ts:44`](../packages/host/webserver/src/index.ts) | `webserver` (`emit`) | `connection`, `inspector`, `modules`, `remote-access`, `shortcuts`, `ui-sidebar-documentpreview`, `ui-theme` | | `workflow/agent-end` | `emit` | [`packages/workflow/workflow/src/index.ts:79`](../packages/workflow/workflow/src/index.ts) | [`workflow`](../packages/workflow/workflow) (`events.dispatch`) | [`tool-workflow`](../packages/workflow/tool-workflow) | | `workflow/agent-start` | `emit` | [`packages/workflow/workflow/src/index.ts:68`](../packages/workflow/workflow/src/index.ts) | [`workflow`](../packages/workflow/workflow) (`events.dispatch`) | [`tool-workflow`](../packages/workflow/tool-workflow) | | `workflow/end` | `emit` | [`packages/workflow/workflow/src/index.ts:89`](../packages/workflow/workflow/src/index.ts) | [`workflow`](../packages/workflow/workflow) (`events.dispatch`) | - | @@ -99,7 +99,7 @@ This matrix shows which packages dispatch each harness-owned event and which pac | Event string | Dispatchers | Listeners | | --- | --- | --- | | `agent/request` | [`agent-loop`](../packages/core/agent-loop) (`waterfall`) | [`compaction-basic`](../packages/compaction/compaction-basic) | -| `internal/config` | [`config-editor`](../packages/boot/config-editor) (`waterfall`) | [`llm-pi-ai`](../packages/llm/llm-pi-ai) | +| `internal/config` | - | [`llm-pi-ai`](../packages/llm/llm-pi-ai) | | `internal/dispatch` | - | [`terminal-bash`](../packages/terminal/terminal-bash) | | `internal/plugin` | - | `computer-use-cua-driver-native`, `inspector`, `loader`, [`lsp-stdio`](../packages/lsp/lsp-stdio), [`mcp-client`](../packages/mcp/mcp-client), `modules` | | `internal/service` | - | `gateway` | diff --git a/docs/event-producer-consumer.zh.md b/docs/event-producer-consumer.zh.md index cd7ab8fd47..c00eba653b 100644 --- a/docs/event-producer-consumer.zh.md +++ b/docs/event-producer-consumer.zh.md @@ -13,7 +13,7 @@ | `agent-loop/config-start-failed` | `emit` | [`packages/core/agent-loop/src/index.ts:199`](../packages/core/agent-loop/src/index.ts) | [`agent-loop`](../packages/core/agent-loop) (`events.dispatch`) | - | | `agent-preset/selected` | `emit` | [`packages/preset/agent-preset-registry/src/types.ts:66`](../packages/preset/agent-preset-registry/src/types.ts) | [`agent-preset-registry`](../packages/preset/agent-preset-registry) (`emit`) | [`cua`](../packages/experimental/cua), `remotes` | | `agent/assistant-stream` | `emit` | [`packages/core/agent/src/runtime-types.ts:399`](../packages/core/agent/src/runtime-types.ts) | [`agent-loop`](../packages/core/agent-loop) (`emit`) | [`headless`](../packages/bundle/headless), `session-controller` | -| `agent/created` | `serial` | [`packages/core/agent/src/runtime-types.ts:290`](../packages/core/agent/src/runtime-types.ts) | [`agent`](../packages/core/agent) (`serial`) | `agent-team`, `browser-use-runtime`, `claude-code-mods`, [`cua`](../packages/experimental/cua), [`file-reference-local`](../packages/context/file-reference-local), [`goal`](../packages/goal/goal), [`goal-round-driver`](../packages/goal/goal-round-driver), [`hooks-claude-code`](../packages/experimental/hooks-claude-code), [`hooks-codex`](../packages/experimental/hooks-codex), [`loader-smoke`](../packages/test-support/loader-smoke), `session-controller`, `tool-agent-team`, [`tool-subagent`](../packages/subagent/tool-subagent) | +| `agent/created` | `serial` | [`packages/core/agent/src/runtime-types.ts:290`](../packages/core/agent/src/runtime-types.ts) | [`agent`](../packages/core/agent) (`serial`) | `agent-team`, `browser-use-runtime`, `claude-code-mods`, [`cua`](../packages/experimental/cua), [`file-reference-local`](../packages/context/file-reference-local), [`goal`](../packages/goal/goal), [`goal-round-driver`](../packages/goal/goal-round-driver), [`hooks-claude-code`](../packages/experimental/hooks-claude-code), [`hooks-codex`](../packages/experimental/hooks-codex), [`loader-smoke`](../packages/test-support/loader-smoke), [`permission-presets`](../packages/interaction/permission-presets), `session-controller`, `tool-agent-team`, [`tool-subagent`](../packages/subagent/tool-subagent) | | `agent/disposed` | `emit` | [`packages/core/agent/src/runtime-types.ts:299`](../packages/core/agent/src/runtime-types.ts) | [`agent`](../packages/core/agent) (`events.dispatch`) | [`agent-loop`](../packages/core/agent-loop), `claude-code-mods`, [`file-reference-local`](../packages/context/file-reference-local), [`goal-round-driver`](../packages/goal/goal-round-driver), `session-controller`, [`subagent`](../packages/subagent/subagent), `tool-agent-team`, [`tool-subagent`](../packages/subagent/tool-subagent) | | `agent/error` | `emit` | [`packages/core/agent/src/runtime-types.ts:429`](../packages/core/agent/src/runtime-types.ts) | [`agent-loop`](../packages/core/agent-loop) (`emit`) | [`acp`](../packages/acp/acp), [`deepseek-account`](../packages/credentials/deepseek-account), [`goal-round-driver`](../packages/goal/goal-round-driver), [`headless`](../packages/bundle/headless), `server`, `session-controller`, [`session-telemetry`](../packages/session/session-telemetry), [`subagent`](../packages/subagent/subagent) | | `agent/inbox/claimed` | `emit` | [`packages/core/agent/src/runtime-types.ts:328`](../packages/core/agent/src/runtime-types.ts) | [`agent-loop`](../packages/core/agent-loop) (`emit`) | [`acp`](../packages/acp/acp), [`goal-round-driver`](../packages/goal/goal-round-driver), [`subagent`](../packages/subagent/subagent), [`tool-jobs`](../packages/jobs/tool-jobs), [`user-questions`](../packages/interaction/user-questions) | @@ -23,12 +23,12 @@ | `agent/request-error` | `waterfall` | [`packages/core/agent/src/runtime-types.ts:389`](../packages/core/agent/src/runtime-types.ts) | [`agent-loop`](../packages/core/agent-loop) (`waterfall`) | [`compaction-basic`](../packages/compaction/compaction-basic), [`compaction-image-offload`](../packages/compaction/compaction-image-offload), [`llm-retry`](../packages/llm/llm-retry) | | `agent/status` | `emit` | [`packages/core/agent/src/runtime-types.ts:309`](../packages/core/agent/src/runtime-types.ts) | [`agent-loop`](../packages/core/agent-loop) (`emit`) | [`acp`](../packages/acp/acp), `agent-team`, [`compaction-basic`](../packages/compaction/compaction-basic), [`goal-round-driver`](../packages/goal/goal-round-driver), `server`, `session-controller` | | `agent/turn-stopping` | `serial` | [`packages/core/agent/src/runtime-types.ts:417`](../packages/core/agent/src/runtime-types.ts) | [`agent-loop`](../packages/core/agent-loop) (`serial`) | [`hooks-claude-code`](../packages/experimental/hooks-claude-code), [`hooks-codex`](../packages/experimental/hooks-codex), [`workspace-changes`](../packages/deliverables/workspace-changes) | -| `api-session/activity` | `emit` | [`packages/api/session-controller/src/types.ts:599`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` | -| `api-session/added` | `emit` | [`packages/api/session-controller/src/types.ts:579`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` | -| `api-session/error` | `emit` | [`packages/api/session-controller/src/types.ts:606`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` | -| `api-session/removed` | `emit` | [`packages/api/session-controller/src/types.ts:585`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` | -| `api-session/status` | `emit` | [`packages/api/session-controller/src/types.ts:592`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` | -| `app-boot/config-reload` | `emit` | [`packages/boot/app-boot/src/index.ts:54`](../packages/boot/app-boot/src/index.ts) | [`app-boot`](../packages/boot/app-boot) (`emit`) | [`settings`](../packages/settings/settings) | +| `api-session/activity` | `emit` | [`packages/api/session-controller/src/types.ts:600`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` | +| `api-session/added` | `emit` | [`packages/api/session-controller/src/types.ts:580`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` | +| `api-session/error` | `emit` | [`packages/api/session-controller/src/types.ts:607`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` | +| `api-session/removed` | `emit` | [`packages/api/session-controller/src/types.ts:586`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` | +| `api-session/status` | `emit` | [`packages/api/session-controller/src/types.ts:593`](../packages/api/session-controller/src/types.ts) | `session-controller` (`emit`) | `remotes` | +| `app-boot/config-reload` | `emit` | [`packages/boot/app-boot/src/index.ts:53`](../packages/boot/app-boot/src/index.ts) | [`app-boot`](../packages/boot/app-boot) (`emit`) | [`settings`](../packages/settings/settings) | | `approval/request` | `waterfall` | [`packages/interaction/user-approval/src/types.ts:87`](../packages/interaction/user-approval/src/types.ts) | [`user-approval`](../packages/interaction/user-approval) (`waterfall`) | [`acp`](../packages/acp/acp), `remotes`, `server` | | `authorization/settled` | `emit` | [`packages/credentials/authorization/src/index.ts:57`](../packages/credentials/authorization/src/index.ts) | [`authorization`](../packages/credentials/authorization) (`events.dispatch`) | - | | `commands/change` | `emit` | [`packages/interaction/commands/src/types.ts:89`](../packages/interaction/commands/src/types.ts) | [`commands`](../packages/interaction/commands) (`events.dispatch`) | `remotes` | @@ -65,10 +65,10 @@ | `schedule/changed` | `emit` | [`packages/schedule/schedule/src/types.ts:478`](../packages/schedule/schedule/src/types.ts) | [`schedule`](../packages/schedule/schedule) (`emit`) | `remotes` | | `schedule/resolve-agent` | `waterfall` | [`packages/schedule/schedule/src/index.ts:74`](../packages/schedule/schedule/src/index.ts) | [`schedule`](../packages/schedule/schedule) (`waterfall`) | `server` | | `session-telemetry/record` | `waterfall` | [`packages/session/session-telemetry/src/index.ts:44`](../packages/session/session-telemetry/src/index.ts) | [`session-telemetry`](../packages/session/session-telemetry) (`waterfall`) | - | -| `session/created` | `emit` | [`packages/core/session/src/index.ts:54`](../packages/core/session/src/index.ts) | [`session`](../packages/core/session) (`events.dispatch`) | [`permission-presets`](../packages/interaction/permission-presets), [`schedule`](../packages/schedule/schedule), `server`, `session-controller`, [`session-projection`](../packages/session/session-projection), [`session-projection-cache`](../packages/session/session-projection-cache), [`session-telemetry`](../packages/session/session-telemetry) | -| `session/disposed` | `emit` | [`packages/core/session/src/index.ts:63`](../packages/core/session/src/index.ts) | [`session`](../packages/core/session) (`events.dispatch`) | [`agent-loop`](../packages/core/agent-loop), `agent-team`, `file-upload`, `session-controller`, [`session-persistence-jsonl`](../packages/session/session-persistence-jsonl), [`session-projection-cache`](../packages/session/session-projection-cache), [`session-telemetry`](../packages/session/session-telemetry), [`session-title`](../packages/session/session-title), [`workspace-changes`](../packages/deliverables/workspace-changes) | -| `session/event` | `emit` | [`packages/core/session/src/index.ts:74`](../packages/core/session/src/index.ts) | [`session`](../packages/core/session) (`events.dispatch`) | [`acp`](../packages/acp/acp), [`agent-instructions`](../packages/context/agent-instructions), [`agent-loop`](../packages/core/agent-loop), [`agent-preset-registry`](../packages/preset/agent-preset-registry), `agent-team`, `claude-code-mods`, [`compaction-basic`](../packages/compaction/compaction-basic), [`file-reference-local`](../packages/context/file-reference-local), `file-upload`, [`goal`](../packages/goal/goal), [`goal-round-driver`](../packages/goal/goal-round-driver), [`headless`](../packages/bundle/headless), [`loader-smoke`](../packages/test-support/loader-smoke), `product-analytics`, [`ptc-runtime-node`](../packages/ptc-runtime/ptc-runtime-node), `server`, `session-controller`, [`session-persistence-jsonl`](../packages/session/session-persistence-jsonl), [`session-projection`](../packages/session/session-projection), [`session-projection-cache`](../packages/session/session-projection-cache), [`session-telemetry`](../packages/session/session-telemetry), [`session-telemetry-otel`](../packages/session/session-telemetry-otel), [`session-title`](../packages/session/session-title), [`subagent`](../packages/subagent/subagent), [`token-meter`](../packages/llm/token-meter), [`tool-executor-ptc`](../packages/core/tool-executor-ptc), [`tool-jobs`](../packages/jobs/tool-jobs), [`user-questions`](../packages/interaction/user-questions), [`workspace-changes`](../packages/deliverables/workspace-changes) | -| `session/flush` | `parallel` | [`packages/core/session/src/index.ts:82`](../packages/core/session/src/index.ts) | [`session`](../packages/core/session) (`events.dispatch`) | [`session-persistence-jsonl`](../packages/session/session-persistence-jsonl), [`session-telemetry`](../packages/session/session-telemetry) | +| `session/created` | `emit` | [`packages/core/session/src/index.ts:56`](../packages/core/session/src/index.ts) | [`session`](../packages/core/session) (`events.dispatch`) | [`schedule`](../packages/schedule/schedule), `server`, `session-controller`, [`session-projection`](../packages/session/session-projection), [`session-projection-cache`](../packages/session/session-projection-cache), [`session-telemetry`](../packages/session/session-telemetry) | +| `session/disposed` | `emit` | [`packages/core/session/src/index.ts:65`](../packages/core/session/src/index.ts) | [`session`](../packages/core/session) (`events.dispatch`) | [`agent-loop`](../packages/core/agent-loop), `agent-team`, `file-upload`, `session-controller`, [`session-persistence-jsonl`](../packages/session/session-persistence-jsonl), [`session-projection-cache`](../packages/session/session-projection-cache), [`session-telemetry`](../packages/session/session-telemetry), [`session-title`](../packages/session/session-title), [`workspace-changes`](../packages/deliverables/workspace-changes) | +| `session/event` | `emit` | [`packages/core/session/src/index.ts:76`](../packages/core/session/src/index.ts) | [`session`](../packages/core/session) (`events.dispatch`) | [`acp`](../packages/acp/acp), [`agent-instructions`](../packages/context/agent-instructions), [`agent-loop`](../packages/core/agent-loop), [`agent-preset-registry`](../packages/preset/agent-preset-registry), `agent-team`, `claude-code-mods`, [`compaction-basic`](../packages/compaction/compaction-basic), [`file-reference-local`](../packages/context/file-reference-local), `file-upload`, [`goal`](../packages/goal/goal), [`goal-round-driver`](../packages/goal/goal-round-driver), [`headless`](../packages/bundle/headless), [`loader-smoke`](../packages/test-support/loader-smoke), `product-analytics`, [`ptc-runtime-node`](../packages/ptc-runtime/ptc-runtime-node), `server`, `session-controller`, [`session-persistence-jsonl`](../packages/session/session-persistence-jsonl), [`session-projection`](../packages/session/session-projection), [`session-projection-cache`](../packages/session/session-projection-cache), [`session-telemetry`](../packages/session/session-telemetry), [`session-telemetry-otel`](../packages/session/session-telemetry-otel), [`session-title`](../packages/session/session-title), [`subagent`](../packages/subagent/subagent), [`token-meter`](../packages/llm/token-meter), [`tool-executor-ptc`](../packages/core/tool-executor-ptc), [`tool-jobs`](../packages/jobs/tool-jobs), [`user-questions`](../packages/interaction/user-questions), [`workspace-changes`](../packages/deliverables/workspace-changes) | +| `session/flush` | `parallel` | [`packages/core/session/src/index.ts:84`](../packages/core/session/src/index.ts) | [`session`](../packages/core/session) (`events.dispatch`) | [`session-persistence-jsonl`](../packages/session/session-persistence-jsonl), [`session-telemetry`](../packages/session/session-telemetry) | | `settings/document-updated` | `emit` | [`packages/settings/settings/src/types.ts:75`](../packages/settings/settings/src/types.ts) | [`settings`](../packages/settings/settings) (`emit`) | `remotes` | | `skills/change` | `emit` | [`packages/skill/skill/src/index.ts:296`](../packages/skill/skill/src/index.ts) | [`skill`](../packages/skill/skill) (`events.dispatch`) | - | | `subagent/end` | `emit` | [`packages/subagent/subagent/src/index.ts:166`](../packages/subagent/subagent/src/index.ts) | [`subagent`](../packages/subagent/subagent) (`events.dispatch`) | [`hooks-claude-code`](../packages/experimental/hooks-claude-code), `server` | @@ -84,7 +84,7 @@ | `tools/ptc-dispatch-log` | `waterfall` | [`packages/core/tool-executor-ptc/src/runtime-types.ts:46`](../packages/core/tool-executor-ptc/src/runtime-types.ts) | [`tool-executor-ptc`](../packages/core/tool-executor-ptc) (`waterfall`) | [`spill-policy`](../packages/spill/spill-policy) | | `tools/result` | `emit` | [`packages/core/tools/src/events.ts:49`](../packages/core/tools/src/events.ts) | [`tools`](../packages/core/tools) (`events.dispatch`) | [`agent-instructions`](../packages/context/agent-instructions), `claude-code-mods`, [`subagent`](../packages/subagent/subagent), [`tool-present`](../packages/deliverables/tool-present) | | `user-questions/request` | `waterfall` | [`packages/interaction/user-questions/src/types.ts:174`](../packages/interaction/user-questions/src/types.ts) | [`user-questions`](../packages/interaction/user-questions) (`waterfall`) | `remotes`, `server` | -| `webserver/index-inject` | `emit` | [`packages/host/webserver/src/index.ts:42`](../packages/host/webserver/src/index.ts) | `webserver` (`emit`) | `connection`, `inspector`, `modules`, `remote-access`, `shortcuts`, `ui-sidebar-documentpreview`, `ui-theme` | +| `webserver/index-inject` | `emit` | [`packages/host/webserver/src/index.ts:44`](../packages/host/webserver/src/index.ts) | `webserver` (`emit`) | `connection`, `inspector`, `modules`, `remote-access`, `shortcuts`, `ui-sidebar-documentpreview`, `ui-theme` | | `workflow/agent-end` | `emit` | [`packages/workflow/workflow/src/index.ts:79`](../packages/workflow/workflow/src/index.ts) | [`workflow`](../packages/workflow/workflow) (`events.dispatch`) | [`tool-workflow`](../packages/workflow/tool-workflow) | | `workflow/agent-start` | `emit` | [`packages/workflow/workflow/src/index.ts:68`](../packages/workflow/workflow/src/index.ts) | [`workflow`](../packages/workflow/workflow) (`events.dispatch`) | [`tool-workflow`](../packages/workflow/tool-workflow) | | `workflow/end` | `emit` | [`packages/workflow/workflow/src/index.ts:89`](../packages/workflow/workflow/src/index.ts) | [`workflow`](../packages/workflow/workflow) (`events.dispatch`) | - | @@ -101,7 +101,7 @@ | Event string | Dispatchers | Listeners | | --- | --- | --- | | `agent/request` | [`agent-loop`](../packages/core/agent-loop) (`waterfall`) | [`compaction-basic`](../packages/compaction/compaction-basic) | -| `internal/config` | [`config-editor`](../packages/boot/config-editor) (`waterfall`) | [`llm-pi-ai`](../packages/llm/llm-pi-ai) | +| `internal/config` | - | [`llm-pi-ai`](../packages/llm/llm-pi-ai) | | `internal/dispatch` | - | [`terminal-bash`](../packages/terminal/terminal-bash) | | `internal/plugin` | - | `computer-use-cua-driver-native`, `inspector`, `loader`, [`lsp-stdio`](../packages/lsp/lsp-stdio), [`mcp-client`](../packages/mcp/mcp-client), `modules` | | `internal/service` | - | `gateway` | diff --git a/docs/module-graph.md b/docs/module-graph.md index 5a7793de98..39342f06ce 100644 --- a/docs/module-graph.md +++ b/docs/module-graph.md @@ -24,6 +24,7 @@ flowchart TD pkg_timeout["timeout"] pkg_util_code_language["util-code-language"] pkg_util_crypto["util-crypto"] + pkg_util_file_drag["util-file-drag"] pkg_util_time["util-time"] pkg_util_values["util-values"] pkg_util_workspace_path["util-workspace-path"] @@ -133,6 +134,7 @@ flowchart TD pkg_cmdline["cmdline"] pkg_config_editor["config-editor"] pkg_hmr["hmr"] + pkg_official_bundles["official-bundles"] pkg_plugin_manager["plugin-manager"] pkg_plugin_market["plugin-market"] end @@ -170,6 +172,7 @@ flowchart TD pkg_client_ui_directory_picker_native["client-ui-directory-picker-native"] pkg_client_ui_dockkit["client-ui-dockkit"] pkg_client_ui_entry_customization["client-ui-entry-customization"] + pkg_client_ui_file_drag["client-ui-file-drag"] pkg_client_ui_goal["client-ui-goal"] pkg_client_ui_input_trigger["client-ui-input-trigger"] pkg_client_ui_jobs["client-ui-jobs"] @@ -781,6 +784,7 @@ flowchart TD pkg_command_feedback --> pkg_commands pkg_command_feedback --> pkg_session pkg_command_feedback --> pkg_typert_protocol + pkg_permission_presets --> pkg_agent pkg_permission_presets --> pkg_commands pkg_permission_presets --> pkg_sandbox pkg_permission_presets --> pkg_sandbox_policy @@ -1470,6 +1474,7 @@ flowchart TD | [`timeout`](../packages/util/timeout) | `util` | — | | [`util-code-language`](../packages/util/code-language) | `util` | — | | [`util-crypto`](../packages/util/crypto) | `util` | — | +| [`util-file-drag`](../packages/util/file-drag) | `util` | — | | [`util-time`](../packages/util/time) | `util` | — | | [`util-values`](../packages/util/values) | `util` | — | | [`util-workspace-path`](../packages/util/workspace-path) | `util` | — | @@ -1481,6 +1486,7 @@ flowchart TD | [`api-remote-access`](../packages/api/remote-access) | `api` | — | | [`api-workspace-files`](../packages/api/workspace-files) | `api` | — | | [`cmdline`](../packages/boot/cmdline) | `boot` | — | +| [`official-bundles`](../packages/boot/official-bundles) | `boot` | — | | [`acp-app`](../packages/bundle/acp-app) | `bundle` | — | | [`base`](../packages/bundle/base) | `bundle` | — | | [`sdk-app`](../packages/bundle/sdk-app) | `bundle` | — | @@ -1506,6 +1512,7 @@ flowchart TD | [`client-ui-directory-picker-native`](../packages/client/ui-directory-picker-native) | `client` | — | | [`client-ui-dockkit`](../packages/client/ui-dockkit) | `client` | — | | [`client-ui-entry-customization`](../packages/client/ui-entry-customization) | `client` | — | +| [`client-ui-file-drag`](../packages/client/ui-file-drag) | `client` | — | | [`client-ui-goal`](../packages/client/ui-goal) | `client` | — | | [`client-ui-input-trigger`](../packages/client/ui-input-trigger) | `client` | — | | [`client-ui-jobs`](../packages/client/ui-jobs) | `client` | — | @@ -1697,7 +1704,7 @@ flowchart TD | [`experimental-ptc-runtime-python`](../packages/experimental/ptc-runtime-python) | `experimental` | [`ptc-runtime`](../packages/ptc-runtime/ptc-runtime), [`sandbox`](../packages/sandbox/sandbox), [`sandbox-policy`](../packages/sandbox/sandbox-policy), [`timeout`](../packages/util/timeout), [`util-values`](../packages/util/values) | | [`experimental-worktree`](../packages/experimental/worktree) | `experimental` | [`agent`](../packages/core/agent), [`fs`](../packages/fs/fs), [`sandbox`](../packages/sandbox/sandbox), [`sandbox-policy`](../packages/sandbox/sandbox-policy), [`subprocess`](../packages/subprocess/subprocess), [`working-directory`](../packages/session/working-directory) | | [`command-feedback`](../packages/feedback/command-feedback) | `feedback` | [`anonymous-user-id`](../packages/identity/anonymous-user-id), [`commands`](../packages/interaction/commands), [`session`](../packages/core/session), [`typert-protocol`](../packages/typert/protocol) | -| [`permission-presets`](../packages/interaction/permission-presets) | `interaction` | [`commands`](../packages/interaction/commands), [`sandbox`](../packages/sandbox/sandbox), [`sandbox-policy`](../packages/sandbox/sandbox-policy), [`session`](../packages/core/session), [`session-projection`](../packages/session/session-projection), [`shell`](../packages/shell/shell), [`typert-protocol`](../packages/typert/protocol), [`user-approval`](../packages/interaction/user-approval) | +| [`permission-presets`](../packages/interaction/permission-presets) | `interaction` | [`agent`](../packages/core/agent), [`commands`](../packages/interaction/commands), [`sandbox`](../packages/sandbox/sandbox), [`sandbox-policy`](../packages/sandbox/sandbox-policy), [`session`](../packages/core/session), [`session-projection`](../packages/session/session-projection), [`shell`](../packages/shell/shell), [`typert-protocol`](../packages/typert/protocol), [`user-approval`](../packages/interaction/user-approval) | | [`jobs-local`](../packages/jobs/jobs-local) | `jobs` | [`agent`](../packages/core/agent), [`jobs`](../packages/jobs/jobs), [`scope`](../packages/core/scope), [`timeout`](../packages/util/timeout) | | [`ptc-runtime-node`](../packages/ptc-runtime/ptc-runtime-node) | `ptc-runtime` | [`fs`](../packages/fs/fs), [`ptc-runtime`](../packages/ptc-runtime/ptc-runtime), [`sandbox`](../packages/sandbox/sandbox), [`sandbox-policy`](../packages/sandbox/sandbox-policy), [`session`](../packages/core/session), [`subprocess`](../packages/subprocess/subprocess), [`timeout`](../packages/util/timeout) | | [`session-title-llm`](../packages/session/session-title-llm) | `session` | [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`session-title`](../packages/session/session-title), [`timeout`](../packages/util/timeout) | diff --git a/docs/module-graph.zh.md b/docs/module-graph.zh.md index 56d63f2613..4c83502b78 100644 --- a/docs/module-graph.zh.md +++ b/docs/module-graph.zh.md @@ -26,6 +26,7 @@ flowchart TD pkg_timeout["timeout"] pkg_util_code_language["util-code-language"] pkg_util_crypto["util-crypto"] + pkg_util_file_drag["util-file-drag"] pkg_util_time["util-time"] pkg_util_values["util-values"] pkg_util_workspace_path["util-workspace-path"] @@ -135,6 +136,7 @@ flowchart TD pkg_cmdline["cmdline"] pkg_config_editor["config-editor"] pkg_hmr["hmr"] + pkg_official_bundles["official-bundles"] pkg_plugin_manager["plugin-manager"] pkg_plugin_market["plugin-market"] end @@ -172,6 +174,7 @@ flowchart TD pkg_client_ui_directory_picker_native["client-ui-directory-picker-native"] pkg_client_ui_dockkit["client-ui-dockkit"] pkg_client_ui_entry_customization["client-ui-entry-customization"] + pkg_client_ui_file_drag["client-ui-file-drag"] pkg_client_ui_goal["client-ui-goal"] pkg_client_ui_input_trigger["client-ui-input-trigger"] pkg_client_ui_jobs["client-ui-jobs"] @@ -783,6 +786,7 @@ flowchart TD pkg_command_feedback --> pkg_commands pkg_command_feedback --> pkg_session pkg_command_feedback --> pkg_typert_protocol + pkg_permission_presets --> pkg_agent pkg_permission_presets --> pkg_commands pkg_permission_presets --> pkg_sandbox pkg_permission_presets --> pkg_sandbox_policy @@ -1472,6 +1476,7 @@ flowchart TD | [`timeout`](../packages/util/timeout) | `util` | — | | [`util-code-language`](../packages/util/code-language) | `util` | — | | [`util-crypto`](../packages/util/crypto) | `util` | — | +| [`util-file-drag`](../packages/util/file-drag) | `util` | — | | [`util-time`](../packages/util/time) | `util` | — | | [`util-values`](../packages/util/values) | `util` | — | | [`util-workspace-path`](../packages/util/workspace-path) | `util` | — | @@ -1483,6 +1488,7 @@ flowchart TD | [`api-remote-access`](../packages/api/remote-access) | `api` | — | | [`api-workspace-files`](../packages/api/workspace-files) | `api` | — | | [`cmdline`](../packages/boot/cmdline) | `boot` | — | +| [`official-bundles`](../packages/boot/official-bundles) | `boot` | — | | [`acp-app`](../packages/bundle/acp-app) | `bundle` | — | | [`base`](../packages/bundle/base) | `bundle` | — | | [`sdk-app`](../packages/bundle/sdk-app) | `bundle` | — | @@ -1508,6 +1514,7 @@ flowchart TD | [`client-ui-directory-picker-native`](../packages/client/ui-directory-picker-native) | `client` | — | | [`client-ui-dockkit`](../packages/client/ui-dockkit) | `client` | — | | [`client-ui-entry-customization`](../packages/client/ui-entry-customization) | `client` | — | +| [`client-ui-file-drag`](../packages/client/ui-file-drag) | `client` | — | | [`client-ui-goal`](../packages/client/ui-goal) | `client` | — | | [`client-ui-input-trigger`](../packages/client/ui-input-trigger) | `client` | — | | [`client-ui-jobs`](../packages/client/ui-jobs) | `client` | — | @@ -1699,7 +1706,7 @@ flowchart TD | [`experimental-ptc-runtime-python`](../packages/experimental/ptc-runtime-python) | `experimental` | [`ptc-runtime`](../packages/ptc-runtime/ptc-runtime), [`sandbox`](../packages/sandbox/sandbox), [`sandbox-policy`](../packages/sandbox/sandbox-policy), [`timeout`](../packages/util/timeout), [`util-values`](../packages/util/values) | | [`experimental-worktree`](../packages/experimental/worktree) | `experimental` | [`agent`](../packages/core/agent), [`fs`](../packages/fs/fs), [`sandbox`](../packages/sandbox/sandbox), [`sandbox-policy`](../packages/sandbox/sandbox-policy), [`subprocess`](../packages/subprocess/subprocess), [`working-directory`](../packages/session/working-directory) | | [`command-feedback`](../packages/feedback/command-feedback) | `feedback` | [`anonymous-user-id`](../packages/identity/anonymous-user-id), [`commands`](../packages/interaction/commands), [`session`](../packages/core/session), [`typert-protocol`](../packages/typert/protocol) | -| [`permission-presets`](../packages/interaction/permission-presets) | `interaction` | [`commands`](../packages/interaction/commands), [`sandbox`](../packages/sandbox/sandbox), [`sandbox-policy`](../packages/sandbox/sandbox-policy), [`session`](../packages/core/session), [`session-projection`](../packages/session/session-projection), [`shell`](../packages/shell/shell), [`typert-protocol`](../packages/typert/protocol), [`user-approval`](../packages/interaction/user-approval) | +| [`permission-presets`](../packages/interaction/permission-presets) | `interaction` | [`agent`](../packages/core/agent), [`commands`](../packages/interaction/commands), [`sandbox`](../packages/sandbox/sandbox), [`sandbox-policy`](../packages/sandbox/sandbox-policy), [`session`](../packages/core/session), [`session-projection`](../packages/session/session-projection), [`shell`](../packages/shell/shell), [`typert-protocol`](../packages/typert/protocol), [`user-approval`](../packages/interaction/user-approval) | | [`jobs-local`](../packages/jobs/jobs-local) | `jobs` | [`agent`](../packages/core/agent), [`jobs`](../packages/jobs/jobs), [`scope`](../packages/core/scope), [`timeout`](../packages/util/timeout) | | [`ptc-runtime-node`](../packages/ptc-runtime/ptc-runtime-node) | `ptc-runtime` | [`fs`](../packages/fs/fs), [`ptc-runtime`](../packages/ptc-runtime/ptc-runtime), [`sandbox`](../packages/sandbox/sandbox), [`sandbox-policy`](../packages/sandbox/sandbox-policy), [`session`](../packages/core/session), [`subprocess`](../packages/subprocess/subprocess), [`timeout`](../packages/util/timeout) | | [`session-title-llm`](../packages/session/session-title-llm) | `session` | [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`session-title`](../packages/session/session-title), [`timeout`](../packages/util/timeout) | diff --git a/docs/persistence-catalog.i18n.yaml b/docs/persistence-catalog.i18n.yaml index 0ff19b9ed8..291a298c66 100644 --- a/docs/persistence-catalog.i18n.yaml +++ b/docs/persistence-catalog.i18n.yaml @@ -12,8 +12,8 @@ en: bcff48893d904af8 zh: f82e75c91c39adb1 /session-persistence-event-catalog/event-envelope: - en: 689f781d95689e20 - zh: 602f6a7f0835d698 + en: 981db6b1928eda50 + zh: d77bc66cf678099d /session-persistence-event-catalog/events: en: f4776ba3d0fd53ce zh: e86769f50a69055a @@ -45,11 +45,11 @@ en: 44426b6cd0dc01cf zh: 44426b6cd0dc01cf /session-persistence-event-catalog/events/assistant/assistant-attempt-log-only: - en: 5b002a8dcefbfc71 - zh: e44f53ed4bf1f929 + en: 4e684124f71bd73b + zh: 445ad50a3a4fb635 /session-persistence-event-catalog/events/assistant/assistant-message-surface: - en: a0f8289f97125e4f - zh: 1ff54770086eb016 + en: 87d9bb62e2aea4b9 + zh: 68ef3b05d4aad7d3 /session-persistence-event-catalog/events/command: en: 2cecb5b0ee955732 zh: 2cecb5b0ee955732 @@ -84,8 +84,8 @@ en: 3344204b1858edb1 zh: 3344204b1858edb1 /session-persistence-event-catalog/events/developer/developer-message-surface: - en: cd036bde54c62690 - zh: 5a21179b33551ed5 + en: 927f25c5dbd69c82 + zh: 9c0331f6e61d7e2b /session-persistence-event-catalog/events/feedback: en: f50dbac6867fa64d zh: f50dbac6867fa64d @@ -147,23 +147,23 @@ en: 19917bc5438e60af zh: 19917bc5438e60af /session-persistence-event-catalog/events/permission/permission-preset-log-only: - en: 54423cb464a0a495 - zh: 8b3a9595255184f0 + en: a1be12f743f72925 + zh: 213ebfa9f39f93e3 /session-persistence-event-catalog/events/plan: en: 4294f78d26ed985b zh: 4294f78d26ed985b /session-persistence-event-catalog/events/plan/plan-mode-log-only: - en: 862175bfe8692ef7 - zh: a8ab123bf674cf77 + en: 9ae5537eeae238de + zh: 6be761c7fd83fdce /session-persistence-event-catalog/events/request: en: a8df82440ebdf5f8 zh: a8df82440ebdf5f8 /session-persistence-event-catalog/events/request/request-context-log-only: - en: 799784e7cd019889 - zh: db6c59d673b4acff + en: 9167d83823675b3e + zh: dfe9095419cf76f4 /session-persistence-event-catalog/events/request/request-header-log-only: - en: fb095eddad22b5f5 - zh: 49f1a3ac0a9ec57c + en: 6d9e26081d1e3aec + zh: 36d30d0bff197d1e /session-persistence-event-catalog/events/sandbox: en: ec841ab8439335b0 zh: ec841ab8439335b0 @@ -180,8 +180,8 @@ en: a1ac8f2660a4f61e zh: a1ac8f2660a4f61e /session-persistence-event-catalog/events/session/session-end-seed-log-only: - en: 70c3c0d6614f2d30 - zh: bb4dd52f5bcf351c + en: f285c670d1bf0e71 + zh: 14ec5689a5943156 /session-persistence-event-catalog/events/session/session-title-log-only: en: 6c6a27578dff5828 zh: 9a5add2bc0df2d0a @@ -198,11 +198,11 @@ en: bd0dcbbc352b771a zh: bd0dcbbc352b771a /session-persistence-event-catalog/events/step/step-end-log-only: - en: 2de61d81867d485c - zh: 21025a396ef7c88f + en: 24bc99ca25809609 + zh: 420384e753feba64 /session-persistence-event-catalog/events/step/step-start-log-only: - en: cb8f05bf3b59adef - zh: 686b33b689c4a841 + en: 269a493d00348184 + zh: 80feab63a0431c60 /session-persistence-event-catalog/events/subagent: en: 9630752e97ddbfbc zh: 9630752e97ddbfbc @@ -219,8 +219,8 @@ en: 8cac41d2fb575975 zh: 8cac41d2fb575975 /session-persistence-event-catalog/events/system/system-message-surface: - en: 92b1f61ac638da71 - zh: 2d60ba9d38abda05 + en: 23aedcadb0c95a51 + zh: f58e5195075ddb21 /session-persistence-event-catalog/events/team: en: a640800a38b3c874 zh: a640800a38b3c874 @@ -246,8 +246,8 @@ en: 28a24430609494b2 zh: 28a24430609494b2 /session-persistence-event-catalog/events/tool/tool-call-log-only: - en: 03f36237cbf9e267 - zh: 83fe2e69bbbfd3c1 + en: b5dfd3b4c54281c3 + zh: 3ac01ceab4a36d06 /session-persistence-event-catalog/events/tool/tool-ptc-dispatch-log-only: en: a62b38c00afed655 zh: 793bef93e856eafa @@ -255,8 +255,8 @@ en: da841b1ed3b22c87 zh: 4c9a4d4bc5bd76b6 /session-persistence-event-catalog/events/tool/tool-result-surface: - en: 283e3cf1fdd57f05 - zh: 0bc3a15ae4f47aaf + en: 722a3bf051b384eb + zh: 01e1258be37a82ce /session-persistence-event-catalog/events/tool-workflow: en: 1eac7deac6af15f3 zh: 1eac7deac6af15f3 @@ -276,17 +276,17 @@ en: d7e8c999a0851a0c zh: d7e8c999a0851a0c /session-persistence-event-catalog/events/turn/turn-end-log-only: - en: ce5ef6916c95ea16 - zh: 9652c8d40b5dfb6d + en: 38d2280f449d3112 + zh: 0f7f05475ea514a3 /session-persistence-event-catalog/events/turn/turn-start-log-only: - en: 999ffb7ad4e600aa - zh: a8720bf8578431ae + en: 853b7f23d092c48a + zh: 53e312793b609198 /session-persistence-event-catalog/events/user: en: d864a88c03e8971c zh: d864a88c03e8971c /session-persistence-event-catalog/events/user/user-message-surface: - en: 55128b5458eae10f - zh: 4198ea89093484f6 + en: ba681b5ec685d6e8 + zh: e4b14b585d2b5804 /session-persistence-event-catalog/events/web: en: d278748103cf1640 zh: d278748103cf1640 @@ -1011,8 +1011,8 @@ en: 997b5db27df00446 zh: 07e5197ddd7bd59b /session-persistence-event-catalog/resolved-persistence-types/epochheader: - en: 3786becd1ca9c697 - zh: ea8e6fd4f6590567 + en: c804cb9e2e31c5ec + zh: 3ed7ac59cd1441b7 /session-persistence-event-catalog/resolved-persistence-types/everyscheduledispatchchange: en: 54c487394ce0db1d zh: 48d7c9affbe841cb @@ -1179,11 +1179,11 @@ en: 488050ba0b6438b4 zh: 2bf607b5ad51e39d /session-persistence-event-catalog/resolved-persistence-types/requestcontext: - en: b1ade5ed2c42b1ad - zh: f1a6126bec25657b + en: 00058b6c2220cdcb + zh: a3426a8c69123e2e /session-persistence-event-catalog/resolved-persistence-types/requestheaderreason: - en: 0db3aa2b122a4454 - zh: 15b6cfd8896935b8 + en: 8e563a11c123255f + zh: ebf891f6a3cb93d3 /session-persistence-event-catalog/resolved-persistence-types/sandboxmode: en: c9fa5343ea99733b zh: d6de41351c57a73f @@ -1236,8 +1236,8 @@ en: d34acab659e74957 zh: 25cabc6c9fb44a7e /session-persistence-event-catalog/resolved-persistence-types/surfaceop: - en: 95f8ef2fb8a7c154 - zh: 04cdad161fb88cc3 + en: a62be7c2cb8a4af7 + zh: 616fd1ac4bd3995a /session-persistence-event-catalog/resolved-persistence-types/systemmessage: en: 94876079d6696df9 zh: d25c7ad9f5054eb7 @@ -1287,8 +1287,8 @@ en: fdac0df45529e14c zh: c5e38de83a0e0a42 /session-persistence-event-catalog/resolved-persistence-types/toolrestriction: - en: 9d64c653e33bf2b6 - zh: 7bb427b48756f30f + en: d70be5d46cb1ef7d + zh: d3d5a05d62e443fe /session-persistence-event-catalog/resolved-persistence-types/toolresultmessage: en: 2258683c3cfa4ce3 zh: 5663aa76c911761b @@ -1314,8 +1314,8 @@ en: 4dc89c072fe5d0d1 zh: 4ed2c9e9e8b4f7e2 /session-persistence-event-catalog/resolved-persistence-types/turnendreason: - en: eec92deb07c000fa - zh: 666682b6f3efcfa3 + en: 344a7207a4199a32 + zh: d500af39e83289cf /session-persistence-event-catalog/resolved-persistence-types/usermessage: en: bd3aedd570ded4d2 zh: f020d0816d3a6c1a @@ -1347,8 +1347,8 @@ en: 2786fef560851bb4 zh: 5d787475356b2606 /session-persistence-event-catalog/resolved-persistence-types/string: - en: 967168de7dce17f6 - zh: c43778dcbfea301e + en: a9d7dc010ada133d + zh: 9bd682adee72d04e /session-persistence-event-catalog/resolved-persistence-types/string~2: en: 0089620bf4638263 zh: 1922bef1713094bb @@ -1398,8 +1398,8 @@ en: a74e3dfa51c987af zh: 6c3c87974d7a7260 /session-persistence-event-catalog/resolved-persistence-types/active~2: - en: a3de6a6fe9672c7a - zh: a357481e27b3b81f + en: c861888d6239b700 + zh: a9b2271d3c6b8737 /session-persistence-event-catalog/resolved-persistence-types/agentpreset: en: 1afbe8196f161601 zh: a320a36a8928817c @@ -1410,8 +1410,8 @@ en: a117573a5d58cb3c zh: d5ad59e17a3a815d /session-persistence-event-catalog/resolved-persistence-types/arguments-callid-name-step: - en: 99e67b046fa9cf40 - zh: 88060ee577d02d20 + en: 036101ee99efbf72 + zh: a324d7f9f671bab0 /session-persistence-event-catalog/resolved-persistence-types/callid-files-turn: en: 5f4d3f66ed86a14d zh: 7c729360fa1279e6 @@ -1443,8 +1443,8 @@ en: a1f188c9058cf621 zh: eb43c0f045fb9afb /session-persistence-event-catalog/resolved-persistence-types/code-name-reason: - en: 39c67256532a22f9 - zh: 59f823e98630c5e2 + en: 17649d71411cb827 + zh: abb3138d38c76459 /session-persistence-event-catalog/resolved-persistence-types/commandid-kind-sourceeventseq-text: en: 87b03e1c73d2a326 zh: d7b9f06863cad891 @@ -1485,14 +1485,14 @@ en: 4b7a8793663d3fef zh: 249459c825d330c3 /session-persistence-event-catalog/resolved-persistence-types/endseq-op-startseq: - en: 318404925fed44c8 - zh: 6cc8b0fcd8d11540 + en: 1a533265eb56a8b8 + zh: 57480f4b53713570 /session-persistence-event-catalog/resolved-persistence-types/error-kind-error: - en: 72572b3d4f2f0c01 - zh: 4c4234325c1713fc + en: 8d0448ef77e0da08 + zh: 25770329c9db129a /session-persistence-event-catalog/resolved-persistence-types/error-message-meta-step: - en: 8cc3e4d05fa25012 - zh: 2c2d1c1936dd99ce + en: 9ffa836bf88fd7b4 + zh: 7ca8bc7ebefeadb8 /session-persistence-event-catalog/resolved-persistence-types/failure-kind-aborted: en: 349cd90f2598fd12 zh: 1eda02d520ad5d76 @@ -1500,11 +1500,11 @@ en: 51af619ed8532a43 zh: a5ad878c63d0e046 /session-persistence-event-catalog/resolved-persistence-types/header-reason-startsseries: - en: fe0f6163c5202da6 - zh: 98feea5f03b725e1 + en: 0b1ca5c765d716d1 + zh: dd939095c250c4eb /session-persistence-event-catalog/resolved-persistence-types/headerseq-message-step-turn: - en: 05903e55f510fd79 - zh: 90a17b10f682abcb + en: 3d16abb7b9581429 + zh: dc959157864261d8 /session-persistence-event-catalog/resolved-persistence-types/height-width: en: a5df50710083ac25 zh: aad3ccf6f6de70e4 @@ -1521,14 +1521,14 @@ en: 41f73c58a77dfa28 zh: af77f4aee3cb4a40 /session-persistence-event-catalog/resolved-persistence-types/inherited: - en: 8a9199b1784c70f5 - zh: 76c98bc74686fda0 + en: 6ce6ddac6d815805 + zh: f7196176e902c965 /session-persistence-event-catalog/resolved-persistence-types/inserted-outcome-removedcount-start: en: 346d884a7a74e48d zh: 646ac1021f9ca920 /session-persistence-event-catalog/resolved-persistence-types/interrupted-message-step-stream: - en: ec10cd8e9c202a81 - zh: e08f859bcb13f0d4 + en: 89fb3f919d181c86 + zh: 4380624236500687 /session-persistence-event-catalog/resolved-persistence-types/kind-aborted-reason: en: 48424cbed3fbc269 zh: 2ce88c04ad002104 @@ -1569,8 +1569,8 @@ en: 78e34e6d0d70339e zh: 072127e40cfb9686 /session-persistence-event-catalog/resolved-persistence-types/kind-forked: - en: dc750041126fe853 - zh: 736505cd1e57db62 + en: e2588043ee1a8d50 + zh: d87a5bff12b9190f /session-persistence-event-catalog/resolved-persistence-types/kind-hook: en: 78278a869370695f zh: 6cdc47f1876f3b23 @@ -1617,14 +1617,14 @@ en: a8a338be3b91008f zh: c7632c42c869c2f6 /session-persistence-event-catalog/resolved-persistence-types/kind-interrupted: - en: b2dea1e08facaa40 - zh: 71c9b8d4e3d1d2b8 + en: 452b4a96d072a9b9 + zh: d63c8ab84bd37dbb /session-persistence-event-catalog/resolved-persistence-types/kind-legacy: en: c6f68741f8631d4f zh: 090b58f2b86c02d0 /session-persistence-event-catalog/resolved-persistence-types/kind-max-tokens: - en: 4746f91df74cc1dd - zh: d0427e9191359299 + en: f85b7a64a6a5f1f7 + zh: 3f4ad5183e1020fd /session-persistence-event-catalog/resolved-persistence-types/kind-model-selection: en: a5165486dca91116 zh: b7051ca8167806ef @@ -1830,11 +1830,11 @@ en: 08be4349548406a9 zh: 8e7cf9966198ef78 /session-persistence-event-catalog/resolved-persistence-types/kind-tool-registry: - en: c59d020828d8211f - zh: 154a30cb69e79489 + en: 5a0bbf4c76266ac5 + zh: 0b20854f90f9d74d /session-persistence-event-catalog/resolved-persistence-types/kind-user: - en: 43f0c6042d410afd - zh: a0b68de4e5d220bd + en: 81620af099525ee9 + zh: 812db2fdf9e5d309 /session-persistence-event-catalog/resolved-persistence-types/kind-user-approval: en: a52d2dfbaf844127 zh: 4c5306ca40f20873 @@ -1872,8 +1872,8 @@ en: 82b0989dad6bbfc0 zh: 0789b63f1d59b2ed /session-persistence-event-catalog/resolved-persistence-types/message-step-turn: - en: dcaa676f106cfdfd - zh: e3941fea97c943fb + en: 762219ab10a2d9b1 + zh: ce31f3b385595b96 /session-persistence-event-catalog/resolved-persistence-types/message-teamid-version: en: f778769acb264dd5 zh: eba9b81d04e9f57b @@ -1887,11 +1887,11 @@ en: 00f1d435f82d2753 zh: c2ab108ad2748a6c /session-persistence-event-catalog/resolved-persistence-types/preset: - en: 26cf71c850765c59 - zh: 7a436be430e04898 + en: 8ebd37343b638773 + zh: bf7ffa9a60ca42a8 /session-persistence-event-catalog/resolved-persistence-types/reason-turn: - en: a4ba4d0ee1396381 - zh: b6f595f8a696d512 + en: 2d45d5c5e3959d12 + zh: df4d0d7fca4e26bc /session-persistence-event-catalog/resolved-persistence-types/role-user: en: 04b34b8ffe7e7764 zh: a792d5371516fd9d @@ -1902,11 +1902,11 @@ en: 7a2ab7b62244f43b zh: 1084e3f8876feebc /session-persistence-event-catalog/resolved-persistence-types/step-stream-turn: - en: 84004f9b9c6bf24c - zh: ce1abe27b0bc43e2 + en: d911fd8591d66386 + zh: cba2966a909b9293 /session-persistence-event-catalog/resolved-persistence-types/step-turn: - en: 989fad01cdd866ba - zh: 4f08dafda68f0c77 + en: 4bbf63488cce88c9 + zh: 46b40433a749c133 /session-persistence-event-catalog/resolved-persistence-types/targets: en: 5360af614fe753e3 zh: 96427c489cc71de6 @@ -1917,8 +1917,8 @@ en: 8ab873d30e062fd5 zh: a138832c6e299ebb /session-persistence-event-catalog/resolved-persistence-types/turn: - en: c58b89cec274f956 - zh: 056a29ed1ada9690 + en: ea32b4165dbfb182 + zh: 57f48af06cfa201c /session-persistence-event-catalog/resolved-persistence-types/type-agent-preset-selected: en: c8c731ee23bed85a zh: f4ffc80f7828701d diff --git a/docs/persistence-catalog.md b/docs/persistence-catalog.md index 40d46b0162..e98ae23f5c 100644 --- a/docs/persistence-catalog.md +++ b/docs/persistence-catalog.md @@ -160,7 +160,7 @@ export type SessionEvent = { }[T] ``` -Sources: [`packages/core/session/src/types.ts:432`](../packages/core/session/src/types.ts) · [`packages/core/session/src/types.ts:440`](../packages/core/session/src/types.ts) · [`packages/core/session/src/types.ts:463`](../packages/core/session/src/types.ts) · [`packages/core/session/src/types.ts:494`](../packages/core/session/src/types.ts) +Sources: [`packages/core/session/src/types.ts:433`](../packages/core/session/src/types.ts) · [`packages/core/session/src/types.ts:441`](../packages/core/session/src/types.ts) · [`packages/core/session/src/types.ts:464`](../packages/core/session/src/types.ts) · [`packages/core/session/src/types.ts:495`](../packages/core/session/src/types.ts) ## Events @@ -290,7 +290,7 @@ Source: [`packages/interaction/user-approval/src/index.ts:40`](../packages/inter 'assistant/attempt': { turn: number; step: number; stream: AssistantStreamRecord[] } ``` -Source: [`packages/core/session/src/types.ts:356`](../packages/core/session/src/types.ts) +Source: [`packages/core/session/src/types.ts:357`](../packages/core/session/src/types.ts) @@ -320,7 +320,7 @@ Source: [`packages/core/session/src/types.ts:356`](../packages/core/session/src/ Types: [TokenUsage](subsystems/llm-streaming.md) -Source: [`packages/core/session/src/types.ts:342`](../packages/core/session/src/types.ts) +Source: [`packages/core/session/src/types.ts:343`](../packages/core/session/src/types.ts) ### `command/*` @@ -508,7 +508,7 @@ Source: [`packages/deliverables/tool-present/src/types.ts:15`](../packages/deliv } ``` -Source: [`packages/core/session/src/types.ts:312`](../packages/core/session/src/types.ts) +Source: [`packages/core/session/src/types.ts:313`](../packages/core/session/src/types.ts) ### `feedback/*` @@ -718,7 +718,7 @@ Source: [`packages/core/agent/src/types.ts:121`](../packages/core/agent/src/type 'permission/preset': { preset: string } ``` -Source: [`packages/interaction/permission-presets/src/index.ts:52`](../packages/interaction/permission-presets/src/index.ts) +Source: [`packages/interaction/permission-presets/src/index.ts:53`](../packages/interaction/permission-presets/src/index.ts) ### `plan/*` @@ -735,7 +735,7 @@ Source: [`packages/interaction/permission-presets/src/index.ts:52`](../packages/ 'plan/mode': { active: boolean } ``` -Source: [`packages/plan/plan-mode/src/index.ts:52`](../packages/plan/plan-mode/src/index.ts) +Source: [`packages/plan/plan-mode/src/index.ts:53`](../packages/plan/plan-mode/src/index.ts) ### `request/*` @@ -753,7 +753,7 @@ Source: [`packages/plan/plan-mode/src/index.ts:52`](../packages/plan/plan-mode/s 'request/context': RequestContext ``` -Source: [`packages/core/session/src/types.ts:403`](../packages/core/session/src/types.ts) +Source: [`packages/core/session/src/types.ts:404`](../packages/core/session/src/types.ts) @@ -772,7 +772,7 @@ Source: [`packages/core/session/src/types.ts:403`](../packages/core/session/src/ } ``` -Source: [`packages/core/session/src/types.ts:391`](../packages/core/session/src/types.ts) +Source: [`packages/core/session/src/types.ts:392`](../packages/core/session/src/types.ts) ### `sandbox/*` @@ -849,7 +849,7 @@ Source: [`packages/schedule/schedule/src/types.ts:365`](../packages/schedule/sch 'session/end-seed': { inherited?: true } ``` -Source: [`packages/core/session/src/types.ts:428`](../packages/core/session/src/types.ts) +Source: [`packages/core/session/src/types.ts:429`](../packages/core/session/src/types.ts) @@ -911,7 +911,7 @@ Source: [`packages/session/session-log-deepseek/src/types.ts:81`](../packages/se 'step/end': { turn: number; step: number } ``` -Source: [`packages/core/session/src/types.ts:302`](../packages/core/session/src/types.ts) +Source: [`packages/core/session/src/types.ts:303`](../packages/core/session/src/types.ts) @@ -922,7 +922,7 @@ Source: [`packages/core/session/src/types.ts:302`](../packages/core/session/src/ 'step/start': { turn: number; step: number } ``` -Source: [`packages/core/session/src/types.ts:300`](../packages/core/session/src/types.ts) +Source: [`packages/core/session/src/types.ts:301`](../packages/core/session/src/types.ts) ### `subagent/*` @@ -998,7 +998,7 @@ Source: [`packages/subagent/tool-subagent/src/model-selection-state.ts:17`](../p 'system/message': { turn: number; step: number; message: SystemMessage } ``` -Source: [`packages/core/session/src/types.ts:331`](../packages/core/session/src/types.ts) +Source: [`packages/core/session/src/types.ts:332`](../packages/core/session/src/types.ts) ### `team/*` @@ -1091,7 +1091,7 @@ Source: [`packages/todo/tool-todo/src/types.ts:33`](../packages/todo/tool-todo/s Types: [ToolCallId](subsystems/core.md) -Source: [`packages/core/session/src/types.ts:362`](../packages/core/session/src/types.ts) +Source: [`packages/core/session/src/types.ts:363`](../packages/core/session/src/types.ts) @@ -1172,7 +1172,7 @@ Source: [`packages/core/tool-executor-ptc/src/types.ts:45`](../packages/core/too } ``` -Source: [`packages/core/session/src/types.ts:376`](../packages/core/session/src/types.ts) +Source: [`packages/core/session/src/types.ts:377`](../packages/core/session/src/types.ts) ### `tool-workflow/*` @@ -1252,7 +1252,7 @@ Source: [`packages/workflow/tool-workflow/src/types.ts:47`](../packages/workflow Types: [TurnEndReason](subsystems/session.md) -Source: [`packages/core/session/src/types.ts:298`](../packages/core/session/src/types.ts) +Source: [`packages/core/session/src/types.ts:299`](../packages/core/session/src/types.ts) @@ -1268,7 +1268,7 @@ Source: [`packages/core/session/src/types.ts:298`](../packages/core/session/src/ 'turn/start': { turn: number } ``` -Source: [`packages/core/session/src/types.ts:289`](../packages/core/session/src/types.ts) +Source: [`packages/core/session/src/types.ts:290`](../packages/core/session/src/types.ts) ### `user/*` @@ -1287,7 +1287,7 @@ Source: [`packages/core/session/src/types.ts:289`](../packages/core/session/src/ 'user/message': UserMessage ``` -Source: [`packages/core/session/src/types.ts:310`](../packages/core/session/src/types.ts) +Source: [`packages/core/session/src/types.ts:311`](../packages/core/session/src/types.ts) ### `web/*` @@ -3398,7 +3398,7 @@ Attribution-only additions: `tmux-context`, `user-question-reply`, `working-dire SHA-256: `9a930283b91d493d6347146f2475bb107294b379415ca02162354f46a64164f7` -Sources: [`packages/core/session/src/types.ts:241`](../packages/core/session/src/types.ts) +Sources: [`packages/core/session/src/types.ts:242`](../packages/core/session/src/types.ts) | Property | Presence | Type | |---|---|---| @@ -4528,7 +4528,7 @@ Sources: [`packages/llm/llm/src/types.ts:448`](../packages/llm/llm/src/types.ts) SHA-256: `b158f3ff6923714807c0d73882f0b05dc87f8fa85c9e90814852d48bbc866081` -Sources: [`packages/core/session/src/types.ts:255`](../packages/core/session/src/types.ts) +Sources: [`packages/core/session/src/types.ts:256`](../packages/core/session/src/types.ts) | Property | Presence | Type | |---|---|---| @@ -4547,7 +4547,7 @@ Sources: [`packages/core/session/src/types.ts:255`](../packages/core/session/src SHA-256: `530da6c0267813bb4511af72883cc518834e624e3b3220a7062955fd57a788a6` -Sources: [`packages/core/session/src/types.ts:274`](../packages/core/session/src/types.ts) +Sources: [`packages/core/session/src/types.ts:275`](../packages/core/session/src/types.ts) One of: @@ -4885,7 +4885,7 @@ Sources: [`packages/subagent/subagent/src/continuation-messages.ts:29`](../packa SHA-256: `335e242de1fcc17b6ca920fc420d71bec2d76e53e37955c00948b65ab77f05c5` -Sources: [`packages/core/session/src/types.ts:463`](../packages/core/session/src/types.ts) +Sources: [`packages/core/session/src/types.ts:464`](../packages/core/session/src/types.ts) One of: @@ -5193,7 +5193,7 @@ Sources: [`packages/llm/llm/src/types.ts:127`](../packages/llm/llm/src/types.ts) SHA-256: `3cfc3a56502da1f8c6153c2c56657bab4b749056968634dd0991d325ec1c919f` -Sources: [`packages/core/tools/src/contracts.ts:326`](../packages/core/tools/src/contracts.ts) +Sources: [`packages/core/tools/src/contracts.ts:376`](../packages/core/tools/src/contracts.ts) | Property | Presence | Type | |---|---|---| @@ -5350,7 +5350,7 @@ Sources: [`packages/core/session/src/types.ts:197`](../packages/core/session/src SHA-256: `f1687f982fa3d41ef29e159feed154ecd13af4dd209acaee16038f223f2e9402` -Sources: [`packages/core/session/src/types.ts:233`](../packages/core/session/src/types.ts) +Sources: [`packages/core/session/src/types.ts:234`](../packages/core/session/src/types.ts) | kind | Form property | Other required fields | Full definition | |---|---|---|---| @@ -5583,7 +5583,7 @@ Array of `number`. SHA-256: `4cd48f3e5108bd6ebedf7301c3638839b8b2b9db8dbd493974177fbdeb91a01b` -Sources: [`packages/api/session-controller/src/types.ts:379`](../packages/api/session-controller/src/types.ts) · [`packages/attachment/attachment/src/brand.ts:6`](../packages/attachment/attachment/src/brand.ts) · [`packages/compaction/compaction/src/brand.ts:4`](../packages/compaction/compaction/src/brand.ts) · [`packages/core/session/src/types.ts:21`](../packages/core/session/src/types.ts) · [`packages/experimental/agent-team/src/types.ts:21`](../packages/experimental/agent-team/src/types.ts) · [`packages/experimental/agent-team/src/types.ts:33`](../packages/experimental/agent-team/src/types.ts) · [`packages/experimental/agent-team/src/types.ts:9`](../packages/experimental/agent-team/src/types.ts) · [`packages/experimental/webhook/src/brand.ts:12`](../packages/experimental/webhook/src/brand.ts) · [`packages/experimental/webhook/src/brand.ts:6`](../packages/experimental/webhook/src/brand.ts) · [`packages/experimental/webhook/src/brand.ts:9`](../packages/experimental/webhook/src/brand.ts) · [`packages/feedback/message-feedback/src/types.ts:14`](../packages/feedback/message-feedback/src/types.ts) · [`packages/goal/goal/src/types.ts:17`](../packages/goal/goal/src/types.ts) · [`packages/interaction/commands/src/brand.ts:31`](../packages/interaction/commands/src/brand.ts) · [`packages/interaction/user-approval/src/types.ts:17`](../packages/interaction/user-approval/src/types.ts) · [`packages/jobs/jobs/src/brand.ts:19`](../packages/jobs/jobs/src/brand.ts) · [`packages/llm/llm-retry/src/brand.ts:4`](../packages/llm/llm-retry/src/brand.ts) · [`packages/llm/llm/src/brand.ts:16`](../packages/llm/llm/src/brand.ts) · [`packages/llm/llm/src/brand.ts:31`](../packages/llm/llm/src/brand.ts) · [`packages/llm/llm/src/brand.ts:43`](../packages/llm/llm/src/brand.ts) · [`packages/llm/llm/src/brand.ts:67`](../packages/llm/llm/src/brand.ts) · [`packages/schedule/schedule/src/types.ts:14`](../packages/schedule/schedule/src/types.ts) · [`packages/session/session-title/src/index.ts:42`](../packages/session/session-title/src/index.ts) · [`packages/session/session-title/src/types.ts:17`](../packages/session/session-title/src/types.ts) · [`packages/workflow/workflow/src/types.ts:13`](../packages/workflow/workflow/src/types.ts) +Sources: [`packages/api/session-controller/src/types.ts:380`](../packages/api/session-controller/src/types.ts) · [`packages/attachment/attachment/src/brand.ts:6`](../packages/attachment/attachment/src/brand.ts) · [`packages/compaction/compaction/src/brand.ts:4`](../packages/compaction/compaction/src/brand.ts) · [`packages/core/session/src/types.ts:21`](../packages/core/session/src/types.ts) · [`packages/experimental/agent-team/src/types.ts:21`](../packages/experimental/agent-team/src/types.ts) · [`packages/experimental/agent-team/src/types.ts:33`](../packages/experimental/agent-team/src/types.ts) · [`packages/experimental/agent-team/src/types.ts:9`](../packages/experimental/agent-team/src/types.ts) · [`packages/experimental/webhook/src/brand.ts:12`](../packages/experimental/webhook/src/brand.ts) · [`packages/experimental/webhook/src/brand.ts:6`](../packages/experimental/webhook/src/brand.ts) · [`packages/experimental/webhook/src/brand.ts:9`](../packages/experimental/webhook/src/brand.ts) · [`packages/feedback/message-feedback/src/types.ts:14`](../packages/feedback/message-feedback/src/types.ts) · [`packages/goal/goal/src/types.ts:17`](../packages/goal/goal/src/types.ts) · [`packages/interaction/commands/src/brand.ts:31`](../packages/interaction/commands/src/brand.ts) · [`packages/interaction/user-approval/src/types.ts:17`](../packages/interaction/user-approval/src/types.ts) · [`packages/jobs/jobs/src/brand.ts:19`](../packages/jobs/jobs/src/brand.ts) · [`packages/llm/llm-retry/src/brand.ts:4`](../packages/llm/llm-retry/src/brand.ts) · [`packages/llm/llm/src/brand.ts:16`](../packages/llm/llm/src/brand.ts) · [`packages/llm/llm/src/brand.ts:31`](../packages/llm/llm/src/brand.ts) · [`packages/llm/llm/src/brand.ts:43`](../packages/llm/llm/src/brand.ts) · [`packages/llm/llm/src/brand.ts:67`](../packages/llm/llm/src/brand.ts) · [`packages/schedule/schedule/src/types.ts:14`](../packages/schedule/schedule/src/types.ts) · [`packages/session/session-title/src/index.ts:42`](../packages/session/session-title/src/index.ts) · [`packages/session/session-title/src/types.ts:17`](../packages/session/session-title/src/types.ts) · [`packages/workflow/workflow/src/types.ts:13`](../packages/workflow/workflow/src/types.ts) `string` @@ -5769,7 +5769,7 @@ Array of `unknown` (opaque). SHA-256: `20a57544bbf204dacd1ae6beb2ab29444365c3c869f2afdf489dcdcbc3d9c8c5` -Sources: [`packages/plan/plan-mode/src/index.ts:52`](../packages/plan/plan-mode/src/index.ts) +Sources: [`packages/plan/plan-mode/src/index.ts:53`](../packages/plan/plan-mode/src/index.ts) | Property | Presence | Type | |---|---|---| @@ -5820,7 +5820,7 @@ Sources: [`packages/interaction/commands/src/types.ts:105`](../packages/interact SHA-256: `e4c18e294232c3ba6c9f1999f168263cc55956147cfe4121720899be8e52edd1` -Sources: [`packages/core/session/src/types.ts:362`](../packages/core/session/src/types.ts) +Sources: [`packages/core/session/src/types.ts:363`](../packages/core/session/src/types.ts) | Property | Presence | Type | |---|---|---| @@ -5979,7 +5979,7 @@ SHA-256: `cbbe8377ee744964537dbafd83607219e58ba79a13f6db0d0645c7ad3d5e8a09` SHA-256: `a81059ca06999da1e712414520c2c65e491d052fcf9640fae20aa38f0a5dc735` -Sources: [`packages/core/session/src/types.ts:384`](../packages/core/session/src/types.ts) · [`packages/core/tool-executor-ptc/src/types.ts:27`](../packages/core/tool-executor-ptc/src/types.ts) +Sources: [`packages/core/session/src/types.ts:385`](../packages/core/session/src/types.ts) · [`packages/core/tool-executor-ptc/src/types.ts:27`](../packages/core/tool-executor-ptc/src/types.ts) | Property | Presence | Type | |---|---|---| @@ -6199,7 +6199,7 @@ Sources: [`packages/compaction/compaction/src/types.ts:38`](../packages/compacti SHA-256: `bcf0caf62d964b2fcf5404bd5c909cfa9a21c3f3c96e6b7e36d9e33565223825` -Sources: [`packages/core/session/src/types.ts:465`](../packages/core/session/src/types.ts) +Sources: [`packages/core/session/src/types.ts:466`](../packages/core/session/src/types.ts) | Property | Presence | Type | |---|---|---| @@ -6213,7 +6213,7 @@ Sources: [`packages/core/session/src/types.ts:465`](../packages/core/session/src SHA-256: `79650cfa10aa3c52440328d85e8a25f0ffadc8d7efd784e3c0819d8bb74a1985` -Sources: [`packages/core/session/src/types.ts:213`](../packages/core/session/src/types.ts) +Sources: [`packages/core/session/src/types.ts:214`](../packages/core/session/src/types.ts) | Property | Presence | Type | |---|---|---| @@ -6226,7 +6226,7 @@ Sources: [`packages/core/session/src/types.ts:213`](../packages/core/session/src SHA-256: `5302e763151277614b97e77f00e3b326694c6c1247b916a20503c344dc970777` -Sources: [`packages/core/session/src/types.ts:376`](../packages/core/session/src/types.ts) +Sources: [`packages/core/session/src/types.ts:377`](../packages/core/session/src/types.ts) | Property | Presence | Type | |---|---|---| @@ -6268,7 +6268,7 @@ Sources: [`packages/llm/llm/src/types.ts:161`](../packages/llm/llm/src/types.ts) SHA-256: `ad0c38a0adb82a94c925456df41586d9b5f9202fca18593eae2213d4445b4585` -Sources: [`packages/core/session/src/types.ts:391`](../packages/core/session/src/types.ts) +Sources: [`packages/core/session/src/types.ts:392`](../packages/core/session/src/types.ts) | Property | Presence | Type | |---|---|---| @@ -6282,7 +6282,7 @@ Sources: [`packages/core/session/src/types.ts:391`](../packages/core/session/src SHA-256: `f4ed4717b4c259e933b550a8dcd90dc93628cda8a3c7affcaa53b9c13c1d53eb` -Sources: [`packages/core/session/src/types.ts:312`](../packages/core/session/src/types.ts) +Sources: [`packages/core/session/src/types.ts:313`](../packages/core/session/src/types.ts) | Property | Presence | Type | |---|---|---| @@ -6365,7 +6365,7 @@ SHA-256: `e3e77b26f0148755a505f5b8ea843a3be117827d4703bb5754d9dc8ddbef521f` SHA-256: `17d1afb770d9941936130996da00dc86782cfef731d8d6526162c301256a4ac3` -Sources: [`packages/core/session/src/types.ts:428`](../packages/core/session/src/types.ts) +Sources: [`packages/core/session/src/types.ts:429`](../packages/core/session/src/types.ts) | Property | Presence | Type | |---|---|---| @@ -6393,7 +6393,7 @@ Sources: [`packages/core/agent/src/types.ts:110`](../packages/core/agent/src/typ SHA-256: `1ccb56061942f5ccb0d30c9e4f2883b9d115ff906560029de637b61d3cde896d` -Sources: [`packages/core/session/src/types.ts:342`](../packages/core/session/src/types.ts) +Sources: [`packages/core/session/src/types.ts:343`](../packages/core/session/src/types.ts) | Property | Presence | Type | |---|---|---| @@ -6561,7 +6561,7 @@ Sources: [`packages/session/session-title/src/types.ts:29`](../packages/session/ SHA-256: `ec8b5ff7c77ca6893ac7ba5a0c5b2aefeb52f12c64450b7359660c2a7e8a53d7` -Sources: [`packages/core/session/src/types.ts:229`](../packages/core/session/src/types.ts) +Sources: [`packages/core/session/src/types.ts:230`](../packages/core/session/src/types.ts) | Property | Presence | Type | |---|---|---| @@ -6742,7 +6742,7 @@ SHA-256: `88841202942c7683b3b7e5ea6a796047ec326b6701ac23e58cc236d85613b9fa` SHA-256: `56b7c047694875a843ba020dfea3c8380d54ae4ff88ab349e72004dc21e07c23` -Sources: [`packages/core/session/src/types.ts:222`](../packages/core/session/src/types.ts) +Sources: [`packages/core/session/src/types.ts:223`](../packages/core/session/src/types.ts) | Property | Presence | Type | |---|---|---| @@ -6766,7 +6766,7 @@ Sources: [`packages/core/session/src/types.ts:197`](../packages/core/session/src SHA-256: `ab7ec5f9eb2c6dfacca5da4c37cf7ba85d04172053ee6b1ebf1709ffcd99c1a7` -Sources: [`packages/core/session/src/types.ts:215`](../packages/core/session/src/types.ts) · [`packages/llm/llm/src/types.ts:159`](../packages/llm/llm/src/types.ts) +Sources: [`packages/core/session/src/types.ts:216`](../packages/core/session/src/types.ts) · [`packages/llm/llm/src/types.ts:159`](../packages/llm/llm/src/types.ts) | Property | Presence | Type | |---|---|---| @@ -7542,7 +7542,7 @@ SHA-256: `c5228b7a55498d84f529591744a0ab26e0b93ade18a70a26db1377a1ecfa6b49` SHA-256: `8fcb0b44a575e998665c053643d1ab04c82f39253ebd190ac0c975b78e40b543` -Sources: [`packages/core/tools/src/index.ts:18`](../packages/core/tools/src/index.ts) +Sources: [`packages/core/tools/src/index.ts:28`](../packages/core/tools/src/index.ts) | Property | Presence | Type | |---|---|---| @@ -7554,7 +7554,7 @@ Sources: [`packages/core/tools/src/index.ts:18`](../packages/core/tools/src/inde SHA-256: `6dacb1584f2bfbe209dc6b6f578d51da6d55595f64d0e63c727c98f359278def` -Sources: [`packages/api/session-controller/src/types.ts:388`](../packages/api/session-controller/src/types.ts) +Sources: [`packages/api/session-controller/src/types.ts:389`](../packages/api/session-controller/src/types.ts) | Property | Presence | Type | |---|---|---| @@ -7721,7 +7721,7 @@ Sources: [`packages/experimental/agent-team/src/types.ts:230`](../packages/exper SHA-256: `6bc8e51124d0874bc89e1d0ceff381a9c3cd0fc240667d69f841ce4f60f65fe5` -Sources: [`packages/core/session/src/types.ts:331`](../packages/core/session/src/types.ts) +Sources: [`packages/core/session/src/types.ts:332`](../packages/core/session/src/types.ts) | Property | Presence | Type | |---|---|---| @@ -7790,7 +7790,7 @@ Sources: [`packages/interaction/user-approval/src/index.ts:40`](../packages/inte SHA-256: `8a9c990773f798eac10ca8878e6bcc531ee080bc589cac956730e462cc6a09ad` -Sources: [`packages/interaction/permission-presets/src/index.ts:52`](../packages/interaction/permission-presets/src/index.ts) +Sources: [`packages/interaction/permission-presets/src/index.ts:53`](../packages/interaction/permission-presets/src/index.ts) | Property | Presence | Type | |---|---|---| @@ -7802,7 +7802,7 @@ Sources: [`packages/interaction/permission-presets/src/index.ts:52`](../packages SHA-256: `e481c46af3813e0010558e93f578b2986acd658404cec2d1679e3ac2a6c48654` -Sources: [`packages/core/session/src/types.ts:298`](../packages/core/session/src/types.ts) +Sources: [`packages/core/session/src/types.ts:299`](../packages/core/session/src/types.ts) | Property | Presence | Type | |---|---|---| @@ -7856,7 +7856,7 @@ Sources: [`packages/compaction/compaction/src/types.ts:82`](../packages/compacti SHA-256: `54f9276a1617d7c12594722c89cfe864bcbe4517e9a6f9c98bab14f199a135e0` -Sources: [`packages/core/session/src/types.ts:356`](../packages/core/session/src/types.ts) +Sources: [`packages/core/session/src/types.ts:357`](../packages/core/session/src/types.ts) | Property | Presence | Type | |---|---|---| @@ -7870,7 +7870,7 @@ Sources: [`packages/core/session/src/types.ts:356`](../packages/core/session/src SHA-256: `ef11a3b7fa2033ae4279545ff8a8a2ee4e301b9b73e5b91654c48e6d08283545` -Sources: [`packages/core/session/src/types.ts:300`](../packages/core/session/src/types.ts) · [`packages/core/session/src/types.ts:302`](../packages/core/session/src/types.ts) +Sources: [`packages/core/session/src/types.ts:301`](../packages/core/session/src/types.ts) · [`packages/core/session/src/types.ts:303`](../packages/core/session/src/types.ts) | Property | Presence | Type | |---|---|---| @@ -7921,7 +7921,7 @@ Sources: [`packages/todo/tool-todo/src/types.ts:33`](../packages/todo/tool-todo/ SHA-256: `f90eb4ab2d3897bc20c521a038e3119d581f791ec974b1a0004f63a8ab9e232d` -Sources: [`packages/core/session/src/types.ts:289`](../packages/core/session/src/types.ts) · [`packages/deliverables/workspace-changes/src/types.ts:106`](../packages/deliverables/workspace-changes/src/types.ts) +Sources: [`packages/core/session/src/types.ts:290`](../packages/core/session/src/types.ts) · [`packages/deliverables/workspace-changes/src/types.ts:106`](../packages/deliverables/workspace-changes/src/types.ts) | Property | Presence | Type | |---|---|---| diff --git a/docs/persistence-catalog.zh.md b/docs/persistence-catalog.zh.md index dadbad32d8..9004bc4b21 100644 --- a/docs/persistence-catalog.zh.md +++ b/docs/persistence-catalog.zh.md @@ -162,7 +162,7 @@ export type SessionEvent = { }[T] ``` -来源:[`packages/core/session/src/types.ts:432`](../packages/core/session/src/types.ts) · [`packages/core/session/src/types.ts:440`](../packages/core/session/src/types.ts) · [`packages/core/session/src/types.ts:463`](../packages/core/session/src/types.ts) · [`packages/core/session/src/types.ts:494`](../packages/core/session/src/types.ts) +来源:[`packages/core/session/src/types.ts:433`](../packages/core/session/src/types.ts) · [`packages/core/session/src/types.ts:441`](../packages/core/session/src/types.ts) · [`packages/core/session/src/types.ts:464`](../packages/core/session/src/types.ts) · [`packages/core/session/src/types.ts:495`](../packages/core/session/src/types.ts) ## 事件 @@ -292,7 +292,7 @@ export type SessionEvent = { 'assistant/attempt': { turn: number; step: number; stream: AssistantStreamRecord[] } ``` -来源:[`packages/core/session/src/types.ts:356`](../packages/core/session/src/types.ts) +来源:[`packages/core/session/src/types.ts:357`](../packages/core/session/src/types.ts) @@ -322,7 +322,7 @@ export type SessionEvent = { 类型:[TokenUsage](subsystems/llm-streaming.zh.md) -来源:[`packages/core/session/src/types.ts:342`](../packages/core/session/src/types.ts) +来源:[`packages/core/session/src/types.ts:343`](../packages/core/session/src/types.ts) ### `command/*` @@ -510,7 +510,7 @@ export type SessionEvent = { } ``` -来源:[`packages/core/session/src/types.ts:312`](../packages/core/session/src/types.ts) +来源:[`packages/core/session/src/types.ts:313`](../packages/core/session/src/types.ts) ### `feedback/*` @@ -720,7 +720,7 @@ export type SessionEvent = { 'permission/preset': { preset: string } ``` -来源:[`packages/interaction/permission-presets/src/index.ts:52`](../packages/interaction/permission-presets/src/index.ts) +来源:[`packages/interaction/permission-presets/src/index.ts:53`](../packages/interaction/permission-presets/src/index.ts) ### `plan/*` @@ -737,7 +737,7 @@ export type SessionEvent = { 'plan/mode': { active: boolean } ``` -来源:[`packages/plan/plan-mode/src/index.ts:52`](../packages/plan/plan-mode/src/index.ts) +来源:[`packages/plan/plan-mode/src/index.ts:53`](../packages/plan/plan-mode/src/index.ts) ### `request/*` @@ -755,7 +755,7 @@ export type SessionEvent = { 'request/context': RequestContext ``` -来源:[`packages/core/session/src/types.ts:403`](../packages/core/session/src/types.ts) +来源:[`packages/core/session/src/types.ts:404`](../packages/core/session/src/types.ts) @@ -774,7 +774,7 @@ export type SessionEvent = { } ``` -来源:[`packages/core/session/src/types.ts:391`](../packages/core/session/src/types.ts) +来源:[`packages/core/session/src/types.ts:392`](../packages/core/session/src/types.ts) ### `sandbox/*` @@ -851,7 +851,7 @@ export type SessionEvent = { 'session/end-seed': { inherited?: true } ``` -来源:[`packages/core/session/src/types.ts:428`](../packages/core/session/src/types.ts) +来源:[`packages/core/session/src/types.ts:429`](../packages/core/session/src/types.ts) @@ -913,7 +913,7 @@ export type SessionEvent = { 'step/end': { turn: number; step: number } ``` -来源:[`packages/core/session/src/types.ts:302`](../packages/core/session/src/types.ts) +来源:[`packages/core/session/src/types.ts:303`](../packages/core/session/src/types.ts) @@ -924,7 +924,7 @@ export type SessionEvent = { 'step/start': { turn: number; step: number } ``` -来源:[`packages/core/session/src/types.ts:300`](../packages/core/session/src/types.ts) +来源:[`packages/core/session/src/types.ts:301`](../packages/core/session/src/types.ts) ### `subagent/*` @@ -1000,7 +1000,7 @@ export type SessionEvent = { 'system/message': { turn: number; step: number; message: SystemMessage } ``` -来源:[`packages/core/session/src/types.ts:331`](../packages/core/session/src/types.ts) +来源:[`packages/core/session/src/types.ts:332`](../packages/core/session/src/types.ts) ### `team/*` @@ -1093,7 +1093,7 @@ export type SessionEvent = { 类型:[ToolCallId](subsystems/core.zh.md) -来源:[`packages/core/session/src/types.ts:362`](../packages/core/session/src/types.ts) +来源:[`packages/core/session/src/types.ts:363`](../packages/core/session/src/types.ts) @@ -1174,7 +1174,7 @@ export type SessionEvent = { } ``` -来源:[`packages/core/session/src/types.ts:376`](../packages/core/session/src/types.ts) +来源:[`packages/core/session/src/types.ts:377`](../packages/core/session/src/types.ts) ### `tool-workflow/*` @@ -1254,7 +1254,7 @@ export type SessionEvent = { 类型:[TurnEndReason](subsystems/session.zh.md) -来源:[`packages/core/session/src/types.ts:298`](../packages/core/session/src/types.ts) +来源:[`packages/core/session/src/types.ts:299`](../packages/core/session/src/types.ts) @@ -1270,7 +1270,7 @@ export type SessionEvent = { 'turn/start': { turn: number } ``` -来源:[`packages/core/session/src/types.ts:289`](../packages/core/session/src/types.ts) +来源:[`packages/core/session/src/types.ts:290`](../packages/core/session/src/types.ts) ### `user/*` @@ -1289,7 +1289,7 @@ export type SessionEvent = { 'user/message': UserMessage ``` -来源:[`packages/core/session/src/types.ts:310`](../packages/core/session/src/types.ts) +来源:[`packages/core/session/src/types.ts:311`](../packages/core/session/src/types.ts) ### `web/*` @@ -3400,7 +3400,7 @@ SHA-256: `0f6265188dae7ba6faa26830a180bb4deb0760561f97ee0c9d399ccf6c9cf1f7` SHA-256: `9a930283b91d493d6347146f2475bb107294b379415ca02162354f46a64164f7` -来源:[`packages/core/session/src/types.ts:241`](../packages/core/session/src/types.ts) +来源:[`packages/core/session/src/types.ts:242`](../packages/core/session/src/types.ts) | 属性 | 存在性 | 类型 | |---|---|---| @@ -4530,7 +4530,7 @@ SHA-256: `0acd94fe8794574c9ae72c7855ee16d29c546096d4af760d16d1225385764555` SHA-256: `b158f3ff6923714807c0d73882f0b05dc87f8fa85c9e90814852d48bbc866081` -来源:[`packages/core/session/src/types.ts:255`](../packages/core/session/src/types.ts) +来源:[`packages/core/session/src/types.ts:256`](../packages/core/session/src/types.ts) | 属性 | 存在性 | 类型 | |---|---|---| @@ -4549,7 +4549,7 @@ SHA-256: `b158f3ff6923714807c0d73882f0b05dc87f8fa85c9e90814852d48bbc866081` SHA-256: `530da6c0267813bb4511af72883cc518834e624e3b3220a7062955fd57a788a6` -来源:[`packages/core/session/src/types.ts:274`](../packages/core/session/src/types.ts) +来源:[`packages/core/session/src/types.ts:275`](../packages/core/session/src/types.ts) 以下类型之一: @@ -4887,7 +4887,7 @@ SHA-256: `4e97c3d85c0fc817ee58873c38c25a2474abaaa0af4839311b50b68db3b8cf1a` SHA-256: `335e242de1fcc17b6ca920fc420d71bec2d76e53e37955c00948b65ab77f05c5` -来源:[`packages/core/session/src/types.ts:463`](../packages/core/session/src/types.ts) +来源:[`packages/core/session/src/types.ts:464`](../packages/core/session/src/types.ts) 以下类型之一: @@ -5195,7 +5195,7 @@ SHA-256: `43e311235aa537df1bacdd92d144df8a952337a76e9ac892cdf670f1a797bad8` SHA-256: `3cfc3a56502da1f8c6153c2c56657bab4b749056968634dd0991d325ec1c919f` -来源:[`packages/core/tools/src/contracts.ts:326`](../packages/core/tools/src/contracts.ts) +来源:[`packages/core/tools/src/contracts.ts:376`](../packages/core/tools/src/contracts.ts) | 属性 | 存在性 | 类型 | |---|---|---| @@ -5352,7 +5352,7 @@ SHA-256: `1f8c126cfab3df812cd115cfc23e3256f0fa2383400f4ce91ecad313577e59b0` SHA-256: `f1687f982fa3d41ef29e159feed154ecd13af4dd209acaee16038f223f2e9402` -来源:[`packages/core/session/src/types.ts:233`](../packages/core/session/src/types.ts) +来源:[`packages/core/session/src/types.ts:234`](../packages/core/session/src/types.ts) | kind | form 属性 | 其他必需字段 | 完整定义 | |---|---|---|---| @@ -5585,7 +5585,7 @@ SHA-256: `5d03ba38734809bcbd2a55221bd938b3b3fc34b49bb686c6113e9e4931e3aa78` SHA-256: `4cd48f3e5108bd6ebedf7301c3638839b8b2b9db8dbd493974177fbdeb91a01b` -来源:[`packages/api/session-controller/src/types.ts:379`](../packages/api/session-controller/src/types.ts) · [`packages/attachment/attachment/src/brand.ts:6`](../packages/attachment/attachment/src/brand.ts) · [`packages/compaction/compaction/src/brand.ts:4`](../packages/compaction/compaction/src/brand.ts) · [`packages/core/session/src/types.ts:21`](../packages/core/session/src/types.ts) · [`packages/experimental/agent-team/src/types.ts:21`](../packages/experimental/agent-team/src/types.ts) · [`packages/experimental/agent-team/src/types.ts:33`](../packages/experimental/agent-team/src/types.ts) · [`packages/experimental/agent-team/src/types.ts:9`](../packages/experimental/agent-team/src/types.ts) · [`packages/experimental/webhook/src/brand.ts:12`](../packages/experimental/webhook/src/brand.ts) · [`packages/experimental/webhook/src/brand.ts:6`](../packages/experimental/webhook/src/brand.ts) · [`packages/experimental/webhook/src/brand.ts:9`](../packages/experimental/webhook/src/brand.ts) · [`packages/feedback/message-feedback/src/types.ts:14`](../packages/feedback/message-feedback/src/types.ts) · [`packages/goal/goal/src/types.ts:17`](../packages/goal/goal/src/types.ts) · [`packages/interaction/commands/src/brand.ts:31`](../packages/interaction/commands/src/brand.ts) · [`packages/interaction/user-approval/src/types.ts:17`](../packages/interaction/user-approval/src/types.ts) · [`packages/jobs/jobs/src/brand.ts:19`](../packages/jobs/jobs/src/brand.ts) · [`packages/llm/llm-retry/src/brand.ts:4`](../packages/llm/llm-retry/src/brand.ts) · [`packages/llm/llm/src/brand.ts:16`](../packages/llm/llm/src/brand.ts) · [`packages/llm/llm/src/brand.ts:31`](../packages/llm/llm/src/brand.ts) · [`packages/llm/llm/src/brand.ts:43`](../packages/llm/llm/src/brand.ts) · [`packages/llm/llm/src/brand.ts:67`](../packages/llm/llm/src/brand.ts) · [`packages/schedule/schedule/src/types.ts:14`](../packages/schedule/schedule/src/types.ts) · [`packages/session/session-title/src/index.ts:42`](../packages/session/session-title/src/index.ts) · [`packages/session/session-title/src/types.ts:17`](../packages/session/session-title/src/types.ts) · [`packages/workflow/workflow/src/types.ts:13`](../packages/workflow/workflow/src/types.ts) +来源:[`packages/api/session-controller/src/types.ts:380`](../packages/api/session-controller/src/types.ts) · [`packages/attachment/attachment/src/brand.ts:6`](../packages/attachment/attachment/src/brand.ts) · [`packages/compaction/compaction/src/brand.ts:4`](../packages/compaction/compaction/src/brand.ts) · [`packages/core/session/src/types.ts:21`](../packages/core/session/src/types.ts) · [`packages/experimental/agent-team/src/types.ts:21`](../packages/experimental/agent-team/src/types.ts) · [`packages/experimental/agent-team/src/types.ts:33`](../packages/experimental/agent-team/src/types.ts) · [`packages/experimental/agent-team/src/types.ts:9`](../packages/experimental/agent-team/src/types.ts) · [`packages/experimental/webhook/src/brand.ts:12`](../packages/experimental/webhook/src/brand.ts) · [`packages/experimental/webhook/src/brand.ts:6`](../packages/experimental/webhook/src/brand.ts) · [`packages/experimental/webhook/src/brand.ts:9`](../packages/experimental/webhook/src/brand.ts) · [`packages/feedback/message-feedback/src/types.ts:14`](../packages/feedback/message-feedback/src/types.ts) · [`packages/goal/goal/src/types.ts:17`](../packages/goal/goal/src/types.ts) · [`packages/interaction/commands/src/brand.ts:31`](../packages/interaction/commands/src/brand.ts) · [`packages/interaction/user-approval/src/types.ts:17`](../packages/interaction/user-approval/src/types.ts) · [`packages/jobs/jobs/src/brand.ts:19`](../packages/jobs/jobs/src/brand.ts) · [`packages/llm/llm-retry/src/brand.ts:4`](../packages/llm/llm-retry/src/brand.ts) · [`packages/llm/llm/src/brand.ts:16`](../packages/llm/llm/src/brand.ts) · [`packages/llm/llm/src/brand.ts:31`](../packages/llm/llm/src/brand.ts) · [`packages/llm/llm/src/brand.ts:43`](../packages/llm/llm/src/brand.ts) · [`packages/llm/llm/src/brand.ts:67`](../packages/llm/llm/src/brand.ts) · [`packages/schedule/schedule/src/types.ts:14`](../packages/schedule/schedule/src/types.ts) · [`packages/session/session-title/src/index.ts:42`](../packages/session/session-title/src/index.ts) · [`packages/session/session-title/src/types.ts:17`](../packages/session/session-title/src/types.ts) · [`packages/workflow/workflow/src/types.ts:13`](../packages/workflow/workflow/src/types.ts) `string` @@ -5771,7 +5771,7 @@ SHA-256: `b1664fa89f8eab49a14e7e3168d8bc4da4aa9fd76332f6c4a053d839e5276ae7` SHA-256: `20a57544bbf204dacd1ae6beb2ab29444365c3c869f2afdf489dcdcbc3d9c8c5` -来源:[`packages/plan/plan-mode/src/index.ts:52`](../packages/plan/plan-mode/src/index.ts) +来源:[`packages/plan/plan-mode/src/index.ts:53`](../packages/plan/plan-mode/src/index.ts) | 属性 | 存在性 | 类型 | |---|---|---| @@ -5822,7 +5822,7 @@ SHA-256: `a853902cfab417b8f08aa51ad6855fea46f34ed4588a74e47403035111d0fb86` SHA-256: `e4c18e294232c3ba6c9f1999f168263cc55956147cfe4121720899be8e52edd1` -来源:[`packages/core/session/src/types.ts:362`](../packages/core/session/src/types.ts) +来源:[`packages/core/session/src/types.ts:363`](../packages/core/session/src/types.ts) | 属性 | 存在性 | 类型 | |---|---|---| @@ -5981,7 +5981,7 @@ SHA-256: `cbbe8377ee744964537dbafd83607219e58ba79a13f6db0d0645c7ad3d5e8a09` SHA-256: `a81059ca06999da1e712414520c2c65e491d052fcf9640fae20aa38f0a5dc735` -来源:[`packages/core/session/src/types.ts:384`](../packages/core/session/src/types.ts) · [`packages/core/tool-executor-ptc/src/types.ts:27`](../packages/core/tool-executor-ptc/src/types.ts) +来源:[`packages/core/session/src/types.ts:385`](../packages/core/session/src/types.ts) · [`packages/core/tool-executor-ptc/src/types.ts:27`](../packages/core/tool-executor-ptc/src/types.ts) | 属性 | 存在性 | 类型 | |---|---|---| @@ -6201,7 +6201,7 @@ SHA-256: `9e41386b3a0c9572b0d63078492ebb3997da7d3a830d44e0259418bd02f4bcb2` SHA-256: `bcf0caf62d964b2fcf5404bd5c909cfa9a21c3f3c96e6b7e36d9e33565223825` -来源:[`packages/core/session/src/types.ts:465`](../packages/core/session/src/types.ts) +来源:[`packages/core/session/src/types.ts:466`](../packages/core/session/src/types.ts) | 属性 | 存在性 | 类型 | |---|---|---| @@ -6215,7 +6215,7 @@ SHA-256: `bcf0caf62d964b2fcf5404bd5c909cfa9a21c3f3c96e6b7e36d9e33565223825` SHA-256: `79650cfa10aa3c52440328d85e8a25f0ffadc8d7efd784e3c0819d8bb74a1985` -来源:[`packages/core/session/src/types.ts:213`](../packages/core/session/src/types.ts) +来源:[`packages/core/session/src/types.ts:214`](../packages/core/session/src/types.ts) | 属性 | 存在性 | 类型 | |---|---|---| @@ -6228,7 +6228,7 @@ SHA-256: `79650cfa10aa3c52440328d85e8a25f0ffadc8d7efd784e3c0819d8bb74a1985` SHA-256: `5302e763151277614b97e77f00e3b326694c6c1247b916a20503c344dc970777` -来源:[`packages/core/session/src/types.ts:376`](../packages/core/session/src/types.ts) +来源:[`packages/core/session/src/types.ts:377`](../packages/core/session/src/types.ts) | 属性 | 存在性 | 类型 | |---|---|---| @@ -6270,7 +6270,7 @@ SHA-256: `693f4952fb5565da96c06bace8924b098ac2fbc915fde0ff8019701183abc057` SHA-256: `ad0c38a0adb82a94c925456df41586d9b5f9202fca18593eae2213d4445b4585` -来源:[`packages/core/session/src/types.ts:391`](../packages/core/session/src/types.ts) +来源:[`packages/core/session/src/types.ts:392`](../packages/core/session/src/types.ts) | 属性 | 存在性 | 类型 | |---|---|---| @@ -6284,7 +6284,7 @@ SHA-256: `ad0c38a0adb82a94c925456df41586d9b5f9202fca18593eae2213d4445b4585` SHA-256: `f4ed4717b4c259e933b550a8dcd90dc93628cda8a3c7affcaa53b9c13c1d53eb` -来源:[`packages/core/session/src/types.ts:312`](../packages/core/session/src/types.ts) +来源:[`packages/core/session/src/types.ts:313`](../packages/core/session/src/types.ts) | 属性 | 存在性 | 类型 | |---|---|---| @@ -6367,7 +6367,7 @@ SHA-256: `e3e77b26f0148755a505f5b8ea843a3be117827d4703bb5754d9dc8ddbef521f` SHA-256: `17d1afb770d9941936130996da00dc86782cfef731d8d6526162c301256a4ac3` -来源:[`packages/core/session/src/types.ts:428`](../packages/core/session/src/types.ts) +来源:[`packages/core/session/src/types.ts:429`](../packages/core/session/src/types.ts) | 属性 | 存在性 | 类型 | |---|---|---| @@ -6395,7 +6395,7 @@ SHA-256: `fa106c5b33b657e8ef16e8cbf39f3b7d44e5cbcdf4f9303d9db6410f28951e42` SHA-256: `1ccb56061942f5ccb0d30c9e4f2883b9d115ff906560029de637b61d3cde896d` -来源:[`packages/core/session/src/types.ts:342`](../packages/core/session/src/types.ts) +来源:[`packages/core/session/src/types.ts:343`](../packages/core/session/src/types.ts) | 属性 | 存在性 | 类型 | |---|---|---| @@ -6563,7 +6563,7 @@ SHA-256: `1b5649238876e28811e80f10ec67a00c197ad3babd4ecc61a22b09064b88c597` SHA-256: `ec8b5ff7c77ca6893ac7ba5a0c5b2aefeb52f12c64450b7359660c2a7e8a53d7` -来源:[`packages/core/session/src/types.ts:229`](../packages/core/session/src/types.ts) +来源:[`packages/core/session/src/types.ts:230`](../packages/core/session/src/types.ts) | 属性 | 存在性 | 类型 | |---|---|---| @@ -6744,7 +6744,7 @@ SHA-256: `88841202942c7683b3b7e5ea6a796047ec326b6701ac23e58cc236d85613b9fa` SHA-256: `56b7c047694875a843ba020dfea3c8380d54ae4ff88ab349e72004dc21e07c23` -来源:[`packages/core/session/src/types.ts:222`](../packages/core/session/src/types.ts) +来源:[`packages/core/session/src/types.ts:223`](../packages/core/session/src/types.ts) | 属性 | 存在性 | 类型 | |---|---|---| @@ -6768,7 +6768,7 @@ SHA-256: `eaa71be0fbf0f702df8ea6c11d0aa2f9782263d45a10d0fb14eda662f4bfe04c` SHA-256: `ab7ec5f9eb2c6dfacca5da4c37cf7ba85d04172053ee6b1ebf1709ffcd99c1a7` -来源:[`packages/core/session/src/types.ts:215`](../packages/core/session/src/types.ts) · [`packages/llm/llm/src/types.ts:159`](../packages/llm/llm/src/types.ts) +来源:[`packages/core/session/src/types.ts:216`](../packages/core/session/src/types.ts) · [`packages/llm/llm/src/types.ts:159`](../packages/llm/llm/src/types.ts) | 属性 | 存在性 | 类型 | |---|---|---| @@ -7544,7 +7544,7 @@ SHA-256: `c5228b7a55498d84f529591744a0ab26e0b93ade18a70a26db1377a1ecfa6b49` SHA-256: `8fcb0b44a575e998665c053643d1ab04c82f39253ebd190ac0c975b78e40b543` -来源:[`packages/core/tools/src/index.ts:18`](../packages/core/tools/src/index.ts) +来源:[`packages/core/tools/src/index.ts:28`](../packages/core/tools/src/index.ts) | 属性 | 存在性 | 类型 | |---|---|---| @@ -7556,7 +7556,7 @@ SHA-256: `8fcb0b44a575e998665c053643d1ab04c82f39253ebd190ac0c975b78e40b543` SHA-256: `6dacb1584f2bfbe209dc6b6f578d51da6d55595f64d0e63c727c98f359278def` -来源:[`packages/api/session-controller/src/types.ts:388`](../packages/api/session-controller/src/types.ts) +来源:[`packages/api/session-controller/src/types.ts:389`](../packages/api/session-controller/src/types.ts) | 属性 | 存在性 | 类型 | |---|---|---| @@ -7723,7 +7723,7 @@ SHA-256: `b1ebd5cda47d90d980bb05bffc3f970c51537b9aff15b3bc3d639811727741b1` SHA-256: `6bc8e51124d0874bc89e1d0ceff381a9c3cd0fc240667d69f841ce4f60f65fe5` -来源:[`packages/core/session/src/types.ts:331`](../packages/core/session/src/types.ts) +来源:[`packages/core/session/src/types.ts:332`](../packages/core/session/src/types.ts) | 属性 | 存在性 | 类型 | |---|---|---| @@ -7792,7 +7792,7 @@ SHA-256: `11f70b595aa76897fc4e25a352bfa718c659f44b799e5aa14e84e5a38fe72912` SHA-256: `8a9c990773f798eac10ca8878e6bcc531ee080bc589cac956730e462cc6a09ad` -来源:[`packages/interaction/permission-presets/src/index.ts:52`](../packages/interaction/permission-presets/src/index.ts) +来源:[`packages/interaction/permission-presets/src/index.ts:53`](../packages/interaction/permission-presets/src/index.ts) | 属性 | 存在性 | 类型 | |---|---|---| @@ -7804,7 +7804,7 @@ SHA-256: `8a9c990773f798eac10ca8878e6bcc531ee080bc589cac956730e462cc6a09ad` SHA-256: `e481c46af3813e0010558e93f578b2986acd658404cec2d1679e3ac2a6c48654` -来源:[`packages/core/session/src/types.ts:298`](../packages/core/session/src/types.ts) +来源:[`packages/core/session/src/types.ts:299`](../packages/core/session/src/types.ts) | 属性 | 存在性 | 类型 | |---|---|---| @@ -7858,7 +7858,7 @@ SHA-256: `5dd766ccd1702a1142ad8b4bd44f2242f8e8a6752669ad3de0a5d224329b1438` SHA-256: `54f9276a1617d7c12594722c89cfe864bcbe4517e9a6f9c98bab14f199a135e0` -来源:[`packages/core/session/src/types.ts:356`](../packages/core/session/src/types.ts) +来源:[`packages/core/session/src/types.ts:357`](../packages/core/session/src/types.ts) | 属性 | 存在性 | 类型 | |---|---|---| @@ -7872,7 +7872,7 @@ SHA-256: `54f9276a1617d7c12594722c89cfe864bcbe4517e9a6f9c98bab14f199a135e0` SHA-256: `ef11a3b7fa2033ae4279545ff8a8a2ee4e301b9b73e5b91654c48e6d08283545` -来源:[`packages/core/session/src/types.ts:300`](../packages/core/session/src/types.ts) · [`packages/core/session/src/types.ts:302`](../packages/core/session/src/types.ts) +来源:[`packages/core/session/src/types.ts:301`](../packages/core/session/src/types.ts) · [`packages/core/session/src/types.ts:303`](../packages/core/session/src/types.ts) | 属性 | 存在性 | 类型 | |---|---|---| @@ -7923,7 +7923,7 @@ SHA-256: `79ddc907312f97cf9553d4841e8b3fc937097bd8d97900a790efad3c05255e99` SHA-256: `f90eb4ab2d3897bc20c521a038e3119d581f791ec974b1a0004f63a8ab9e232d` -来源:[`packages/core/session/src/types.ts:289`](../packages/core/session/src/types.ts) · [`packages/deliverables/workspace-changes/src/types.ts:106`](../packages/deliverables/workspace-changes/src/types.ts) +来源:[`packages/core/session/src/types.ts:290`](../packages/core/session/src/types.ts) · [`packages/deliverables/workspace-changes/src/types.ts:106`](../packages/deliverables/workspace-changes/src/types.ts) | 属性 | 存在性 | 类型 | |---|---|---| diff --git a/docs/persistence-schema.json b/docs/persistence-schema.json index 16b178fd37..c668fb96cf 100644 --- a/docs/persistence-schema.json +++ b/docs/persistence-schema.json @@ -123,7 +123,7 @@ {"digest":"15d5dfdd822aa35e115afd74a8982825a493880457774e6850bc1520b50875e4","names":[],"sources":[]}, {"digest":"16d0507cb94b4cfc84a87446b1ba7652d6ec1d65ee1684789e747e30d542800e","names":[],"sources":[]}, {"digest":"17aae616ef020b8b9f011ec398ec935450fb06d3e2a0722c456f63aeaf5ff728","names":[],"sources":[]}, - {"digest":"17d1afb770d9941936130996da00dc86782cfef731d8d6526162c301256a4ac3","names":[],"sources":["packages/core/session/src/types.ts:428"]}, + {"digest":"17d1afb770d9941936130996da00dc86782cfef731d8d6526162c301256a4ac3","names":[],"sources":["packages/core/session/src/types.ts:429"]}, {"digest":"18dc21f12bbac8ade8377e6fbb54179e20c3d955d73fba3244c57fb6bf001df0","names":["packages/schedule/schedule/src/types.ts#ScheduleDeleteChange"],"sources":["packages/schedule/schedule/src/types.ts:230"]}, {"digest":"18ee62b8900a4c3d046700f05d7a4d49d6cab2a660a020c87481d1603dd8bd4f","names":["packages/session/session-persistence-jsonl/src/format.ts#HeaderLine"],"sources":["packages/session/session-persistence-jsonl/src/format.ts:83"]}, {"digest":"18fcdd273a2f2f9d813a3be5e71df5903a963a5c88e46b90b14de6e2db890da0","names":[],"sources":[]}, @@ -138,7 +138,7 @@ {"digest":"1b912703e2d64f91c99c675b8f805b01076c8325b905c1218ad81ef0b24909d5","names":[],"sources":[]}, {"digest":"1c2686c0682e7bc51d61117b2652bd4a80707e331aa276d6ef915ae32534a330","names":[],"sources":[]}, {"digest":"1c5a58f4599bd4a9711712551ffe2442a5e5fcd0758bafe630cc4ead850bdaa7","names":[],"sources":[]}, - {"digest":"1ccb56061942f5ccb0d30c9e4f2883b9d115ff906560029de637b61d3cde896d","names":[],"sources":["packages/core/session/src/types.ts:342"]}, + {"digest":"1ccb56061942f5ccb0d30c9e4f2883b9d115ff906560029de637b61d3cde896d","names":[],"sources":["packages/core/session/src/types.ts:343"]}, {"digest":"1cde1bedde79c5e8a56aee9c05c8e0a579cf5bc611deb85b93fa331a16ca978f","names":["packages/compaction/compaction-image-offload/src/projection.ts#ImageOffloadTarget"],"sources":["packages/compaction/compaction-image-offload/src/projection.ts:9"]}, {"digest":"1d5f04a03ea75fc8eeece544129eba0f49f0c82046e9c404461920390135c7b2","names":[],"sources":[]}, {"digest":"1d76406cbb2ddadb0dbbb51e9d8bc6cf678fed455cf8eb512f36f7c86d37a62f","names":[],"sources":["packages/llm/llm/src/types.ts:157"]}, @@ -153,7 +153,7 @@ {"digest":"1f1385dbc3e875c021e387c7096d671d606f22daec51b25c80348735b6bbfa10","names":[],"sources":[]}, {"digest":"1f8c126cfab3df812cd115cfc23e3256f0fa2383400f4ce91ecad313577e59b0","names":["packages/core/session/src/types.ts#TurnEndCancelCause"],"sources":["packages/core/session/src/types.ts:197"]}, {"digest":"1fdad624334d354820dfb3a26e28d0bc9fc1b62a33f87bab63f715b3f4391bfd","names":[],"sources":[]}, - {"digest":"20a57544bbf204dacd1ae6beb2ab29444365c3c869f2afdf489dcdcbc3d9c8c5","names":[],"sources":["packages/plan/plan-mode/src/index.ts:52"]}, + {"digest":"20a57544bbf204dacd1ae6beb2ab29444365c3c869f2afdf489dcdcbc3d9c8c5","names":[],"sources":["packages/plan/plan-mode/src/index.ts:53"]}, {"digest":"2142e391b9ccb60d487afcf373ce74db98d952f69e8289eddb352a7e16e996c5","names":[],"sources":[]}, {"digest":"2152caf1a71e588e4df2358a806dea24936c1c47131134f01a12939d12cdc0c0","names":["packages/experimental/agent-team/src/types.ts#TeamMessageSource"],"sources":["packages/experimental/agent-team/src/types.ts:138"]}, {"digest":"21fb6a90d5068f6a0003b7ab316ed2f56342477146a65c00db0f13c4d8df667d","names":[],"sources":[]}, @@ -197,7 +197,7 @@ {"digest":"326a9bfda27dda5882fb3cbe6e715df41dae2298fdae3d66437457268a665693","names":["packages/llm/llm/src/call-config.ts#LlmCallConfigAdapterDefaults"],"sources":["packages/llm/llm/src/call-config.ts:54"]}, {"digest":"3305a4bb6b6c29b482ba91d59c60b47e8f98282d3dacc8c29e4a4c2712209bdd","names":[],"sources":[]}, {"digest":"33341aac09312300de5a178e6cc6f6544a4876f7f710cfea55eda473c8d329ef","names":["packages/llm/llm/src/assistant-stream.ts#AssistantStreamRecord"],"sources":["packages/llm/llm/src/assistant-stream.ts:20"]}, - {"digest":"335e242de1fcc17b6ca920fc420d71bec2d76e53e37955c00948b65ab77f05c5","names":["packages/core/session/src/types.ts#SurfaceOp"],"sources":["packages/core/session/src/types.ts:463"]}, + {"digest":"335e242de1fcc17b6ca920fc420d71bec2d76e53e37955c00948b65ab77f05c5","names":["packages/core/session/src/types.ts#SurfaceOp"],"sources":["packages/core/session/src/types.ts:464"]}, {"digest":"347de3380f2da308d0c74e08821f9e85559f55af4c5010795b110d00f7fc9dbd","names":[],"sources":[]}, {"digest":"34d1ab5c5df378186d6054b1a1beea9a41e41965d6f336f0bc0025c441a82e66","names":[],"sources":[]}, {"digest":"35203ba7ad5ef6f97d556b85df20ae98f04f09c65748cecdf8eefdb8b6405ffc","names":[],"sources":[]}, @@ -220,7 +220,7 @@ {"digest":"3bec87f9e6ab3da03346f49923d3c51621debc0159df68605e543c3b2a026f90","names":[],"sources":["packages/llm/llm/src/types.ts:471"]}, {"digest":"3bfeb47b58606f4661904bc723da612782214c463d01e6d61cd6d6193d7374e1","names":[],"sources":[]}, {"digest":"3c2535ca0a2062f172f15344f8040755002b5ac506cf94fc4ebaa822b15feb8c","names":[],"sources":[]}, - {"digest":"3cfc3a56502da1f8c6153c2c56657bab4b749056968634dd0991d325ec1c919f","names":["packages/core/tools/src/contracts.ts#ToolRestriction"],"sources":["packages/core/tools/src/contracts.ts:326"]}, + {"digest":"3cfc3a56502da1f8c6153c2c56657bab4b749056968634dd0991d325ec1c919f","names":["packages/core/tools/src/contracts.ts#ToolRestriction"],"sources":["packages/core/tools/src/contracts.ts:376"]}, {"digest":"3d7d07060a7be77984feb651ea2bf1925d3e0477911d9d3ed86330d1e8ca6182","names":["packages/feedback/message-feedback/src/types.ts#MessageFeedbackItem"],"sources":["packages/feedback/message-feedback/src/types.ts:20"]}, {"digest":"3e0eff5946255ff05d88a10839c60305135801f97794ea48d409f8503303317e","names":[],"sources":[]}, {"digest":"3e2ece4967cfebe95f450a93f45523dff99d6749f6269f2f60f84dfecfcf3693","names":[],"sources":[]}, @@ -253,7 +253,7 @@ {"digest":"4b259f7f8f0a44ad5e90b70a73553ced1df27012d126921d397ff403b6c86731","names":["packages/llm/llm/src/message.ts#ToolResultMessage"],"sources":["packages/llm/llm/src/message.ts:173"]}, {"digest":"4b7ddaf3710b88ff9b8df66304f5f97bf03688fd19730eedc2e9535203c820ea","names":[],"sources":[]}, {"digest":"4bb451330ff699f36b45539ceb0eb2606ead72084e2c5bb637c36cc80e2252db","names":[],"sources":["packages/core/session/src/types.ts:194"]}, - {"digest":"4cd48f3e5108bd6ebedf7301c3638839b8b2b9db8dbd493974177fbdeb91a01b","names":["packages/api/session-controller/src/types.ts#SessionRequestId","packages/attachment/attachment/src/brand.ts#AttachmentId","packages/compaction/compaction/src/brand.ts#CompactionId","packages/core/session/src/types.ts#SessionId","packages/experimental/agent-team/src/types.ts#TeamId","packages/experimental/agent-team/src/types.ts#TeamMessageId","packages/experimental/agent-team/src/types.ts#TeamTaskId","packages/experimental/webhook/src/brand.ts#WebhookDeliveryId","packages/experimental/webhook/src/brand.ts#WebhookRuleId","packages/experimental/webhook/src/brand.ts#WebhookSourceId","packages/feedback/message-feedback/src/types.ts#MessageFeedbackVersion","packages/goal/goal/src/types.ts#GoalId","packages/interaction/commands/src/brand.ts#CommandId","packages/interaction/user-approval/src/types.ts#ApprovalRequestId","packages/jobs/jobs/src/brand.ts#JobId","packages/llm/llm-retry/src/brand.ts#RetryId","packages/llm/llm/src/brand.ts#MessageId","packages/llm/llm/src/brand.ts#ProviderRequestId","packages/llm/llm/src/brand.ts#ReasoningEffortId","packages/llm/llm/src/brand.ts#ToolCallId","packages/schedule/schedule/src/types.ts#ScheduleId","packages/session/session-title/src/index.ts#SessionTitleProviderId","packages/session/session-title/src/types.ts#SessionTitleProviderId","packages/workflow/workflow/src/types.ts#WorkflowRunId"],"sources":["packages/api/session-controller/src/types.ts:379","packages/attachment/attachment/src/brand.ts:6","packages/compaction/compaction/src/brand.ts:4","packages/core/session/src/types.ts:21","packages/experimental/agent-team/src/types.ts:21","packages/experimental/agent-team/src/types.ts:33","packages/experimental/agent-team/src/types.ts:9","packages/experimental/webhook/src/brand.ts:12","packages/experimental/webhook/src/brand.ts:6","packages/experimental/webhook/src/brand.ts:9","packages/feedback/message-feedback/src/types.ts:14","packages/goal/goal/src/types.ts:17","packages/interaction/commands/src/brand.ts:31","packages/interaction/user-approval/src/types.ts:17","packages/jobs/jobs/src/brand.ts:19","packages/llm/llm-retry/src/brand.ts:4","packages/llm/llm/src/brand.ts:16","packages/llm/llm/src/brand.ts:31","packages/llm/llm/src/brand.ts:43","packages/llm/llm/src/brand.ts:67","packages/schedule/schedule/src/types.ts:14","packages/session/session-title/src/index.ts:42","packages/session/session-title/src/types.ts:17","packages/workflow/workflow/src/types.ts:13"]}, + {"digest":"4cd48f3e5108bd6ebedf7301c3638839b8b2b9db8dbd493974177fbdeb91a01b","names":["packages/api/session-controller/src/types.ts#SessionRequestId","packages/attachment/attachment/src/brand.ts#AttachmentId","packages/compaction/compaction/src/brand.ts#CompactionId","packages/core/session/src/types.ts#SessionId","packages/experimental/agent-team/src/types.ts#TeamId","packages/experimental/agent-team/src/types.ts#TeamMessageId","packages/experimental/agent-team/src/types.ts#TeamTaskId","packages/experimental/webhook/src/brand.ts#WebhookDeliveryId","packages/experimental/webhook/src/brand.ts#WebhookRuleId","packages/experimental/webhook/src/brand.ts#WebhookSourceId","packages/feedback/message-feedback/src/types.ts#MessageFeedbackVersion","packages/goal/goal/src/types.ts#GoalId","packages/interaction/commands/src/brand.ts#CommandId","packages/interaction/user-approval/src/types.ts#ApprovalRequestId","packages/jobs/jobs/src/brand.ts#JobId","packages/llm/llm-retry/src/brand.ts#RetryId","packages/llm/llm/src/brand.ts#MessageId","packages/llm/llm/src/brand.ts#ProviderRequestId","packages/llm/llm/src/brand.ts#ReasoningEffortId","packages/llm/llm/src/brand.ts#ToolCallId","packages/schedule/schedule/src/types.ts#ScheduleId","packages/session/session-title/src/index.ts#SessionTitleProviderId","packages/session/session-title/src/types.ts#SessionTitleProviderId","packages/workflow/workflow/src/types.ts#WorkflowRunId"],"sources":["packages/api/session-controller/src/types.ts:380","packages/attachment/attachment/src/brand.ts:6","packages/compaction/compaction/src/brand.ts:4","packages/core/session/src/types.ts:21","packages/experimental/agent-team/src/types.ts:21","packages/experimental/agent-team/src/types.ts:33","packages/experimental/agent-team/src/types.ts:9","packages/experimental/webhook/src/brand.ts:12","packages/experimental/webhook/src/brand.ts:6","packages/experimental/webhook/src/brand.ts:9","packages/feedback/message-feedback/src/types.ts:14","packages/goal/goal/src/types.ts:17","packages/interaction/commands/src/brand.ts:31","packages/interaction/user-approval/src/types.ts:17","packages/jobs/jobs/src/brand.ts:19","packages/llm/llm-retry/src/brand.ts:4","packages/llm/llm/src/brand.ts:16","packages/llm/llm/src/brand.ts:31","packages/llm/llm/src/brand.ts:43","packages/llm/llm/src/brand.ts:67","packages/schedule/schedule/src/types.ts:14","packages/session/session-title/src/index.ts:42","packages/session/session-title/src/types.ts:17","packages/workflow/workflow/src/types.ts:13"]}, {"digest":"4e011753f8263f436efaabfbb3b4db53a98fc55342c5ded2daf7208b217be159","names":[],"sources":[]}, {"digest":"4e44c9118152f6829634bfd508e47669ab0497caffa380c94b4be91f9390d35d","names":[],"sources":[]}, {"digest":"4e887768586528565381dadbddee6cef555874148089f4579e0b4b1ad096fc9c","names":["packages/llm/llm/src/types.ts#TextBlock"],"sources":["packages/llm/llm/src/types.ts:62","packages/web/web-search-deepseek/src/provider.ts:66"]}, @@ -269,14 +269,14 @@ {"digest":"525254db03b1d1e6b74cf55aced52817568331ac1f96c0818728910b6692e336","names":[],"sources":[]}, {"digest":"529e0ccd0e34079ab4ff21ed87f810cee0388246263bf22e8aba5986b56fae05","names":[],"sources":["packages/util/values/src/index.ts:4"]}, {"digest":"52c6113cb0e53f345324bf84f01928bea5d5df57ee80bc0dd65407b8bc5a3734","names":[],"sources":[]}, - {"digest":"5302e763151277614b97e77f00e3b326694c6c1247b916a20503c344dc970777","names":[],"sources":["packages/core/session/src/types.ts:376"]}, - {"digest":"530da6c0267813bb4511af72883cc518834e624e3b3220a7062955fd57a788a6","names":["packages/core/session/src/types.ts#RequestHeaderReason"],"sources":["packages/core/session/src/types.ts:274"]}, + {"digest":"5302e763151277614b97e77f00e3b326694c6c1247b916a20503c344dc970777","names":[],"sources":["packages/core/session/src/types.ts:377"]}, + {"digest":"530da6c0267813bb4511af72883cc518834e624e3b3220a7062955fd57a788a6","names":["packages/core/session/src/types.ts#RequestHeaderReason"],"sources":["packages/core/session/src/types.ts:275"]}, {"digest":"53750b9abf61efb7992b0aadc3e247ec927449c63266df28230fd1139f5590ac","names":[],"sources":[]}, {"digest":"53cf1704ae0709c7678bcf070c83c619fc48ca1b5c173b74cfa8702f22a8e492","names":[],"sources":[]}, - {"digest":"54f9276a1617d7c12594722c89cfe864bcbe4517e9a6f9c98bab14f199a135e0","names":[],"sources":["packages/core/session/src/types.ts:356"]}, + {"digest":"54f9276a1617d7c12594722c89cfe864bcbe4517e9a6f9c98bab14f199a135e0","names":[],"sources":["packages/core/session/src/types.ts:357"]}, {"digest":"557e148d30b79ee48645850832b30c717d7c3b64641deb5d6133b8b4e91ee0b8","names":[],"sources":[]}, {"digest":"5654685d7557ec747e74887237065e626a5bdfa426ca43f7fbb0b6fee9b0916c","names":[],"sources":[]}, - {"digest":"56b7c047694875a843ba020dfea3c8380d54ae4ff88ab349e72004dc21e07c23","names":[],"sources":["packages/core/session/src/types.ts:222"]}, + {"digest":"56b7c047694875a843ba020dfea3c8380d54ae4ff88ab349e72004dc21e07c23","names":[],"sources":["packages/core/session/src/types.ts:223"]}, {"digest":"570e85022434613394418ad33e77e9f1f7a05699b33d0b62eae0677a638c3833","names":[],"sources":[]}, {"digest":"576a2de8355eb09850963ff5953420b172e274d9283666eb7d889097db120796","names":[],"sources":[]}, {"digest":"5776e5553ff2dfe3f5bc202dbb1e7c9f93e35a531aebb7764c23b2b6153b2ccc","names":[],"sources":[]}, @@ -328,14 +328,14 @@ {"digest":"6ab45ac76839722df912f3ba50f1c6b41f2d614bde11f1aabfae04117ccdc80d","names":[],"sources":[]}, {"digest":"6b23ed9ce1b397e602788dbe033693bf97642a69e23fcab1cc45bf6f13b6d619","names":[],"sources":[]}, {"digest":"6bbe793f6a93dc8d50a4d4d3fbb6f8ed15650bcb7e151d28669628f7b7c3fc25","names":["packages/goal/goal/src/types.ts#GoalSnapshot"],"sources":["packages/goal/goal/src/types.ts:60"]}, - {"digest":"6bc8e51124d0874bc89e1d0ceff381a9c3cd0fc240667d69f841ce4f60f65fe5","names":[],"sources":["packages/core/session/src/types.ts:331"]}, + {"digest":"6bc8e51124d0874bc89e1d0ceff381a9c3cd0fc240667d69f841ce4f60f65fe5","names":[],"sources":["packages/core/session/src/types.ts:332"]}, {"digest":"6c03546143cdf6ae88f1745ac98c5139efa1588d1415249bbc5f3104d32ab800","names":[],"sources":["packages/core/session/src/types.ts:192"]}, {"digest":"6c1cccb433ddc153facb380c7dda956237ba5c31f8a532a69142dc277890cc9b","names":[],"sources":[]}, {"digest":"6c5a37d42ebdb12db4410699259335f1e149e3a0260425684c00b153afc8990d","names":[],"sources":["packages/core/session/src/types.ts:193"]}, {"digest":"6ccb6bc423fb3952458abf9c1b1c3284208b7e660344b612cc55da773d61afe4","names":[],"sources":[]}, {"digest":"6cda0d6d3b4336d83998fe580628426df81c2afbab5d768b8813b56d569120e8","names":[],"sources":[]}, {"digest":"6cf082d0fb6034dea61636787ff0ddf43b6e59aad71e644435a479bc9b83ad65","names":[],"sources":[]}, - {"digest":"6dacb1584f2bfbe209dc6b6f578d51da6d55595f64d0e63c727c98f359278def","names":[],"sources":["packages/api/session-controller/src/types.ts:388"]}, + {"digest":"6dacb1584f2bfbe209dc6b6f578d51da6d55595f64d0e63c727c98f359278def","names":[],"sources":["packages/api/session-controller/src/types.ts:389"]}, {"digest":"6e52dd55a1d48954ed5464ec46fe34d9eb65f709baabc9561e7a279910b0c406","names":[],"sources":["packages/preset/agent-preset-registry/src/session.ts:31"]}, {"digest":"6ea608bdc8a7a63d3d23b84c49721325094db88d136482e43a820945295eee3e","names":[],"sources":[]}, {"digest":"6ebcc2dbec9f2dabca9f668ae6d39e877899b180740570f453409db339221df3","names":[],"sources":[]}, @@ -358,7 +358,7 @@ {"digest":"763c8a20af487263a0080548274f7437ef4a86e0ba8769127d1ced10a72c664d","names":[],"sources":[]}, {"digest":"76632533f67879dcb346fcae640540dbc89b2472b0bce88c59f7e48fc5c0e668","names":[],"sources":[]}, {"digest":"78a9be340090b735a39980e7222ce730c972fbcf1de7c9e0aef2125884b7caee","names":[],"sources":[]}, - {"digest":"79650cfa10aa3c52440328d85e8a25f0ffadc8d7efd784e3c0819d8bb74a1985","names":[],"sources":["packages/core/session/src/types.ts:213"]}, + {"digest":"79650cfa10aa3c52440328d85e8a25f0ffadc8d7efd784e3c0819d8bb74a1985","names":[],"sources":["packages/core/session/src/types.ts:214"]}, {"digest":"79a4c87f8bfb4d6d05cd9952b99210d6a7db3b478c4a01d94b4c50602308c056","names":[],"sources":[]}, {"digest":"79ddc907312f97cf9553d4841e8b3fc937097bd8d97900a790efad3c05255e99","names":[],"sources":["packages/todo/tool-todo/src/types.ts:33"]}, {"digest":"7a651f3b672c52fb615f22c0ce9cb3cc5b22aad92e6bbeefb0808fd7b9233a50","names":[],"sources":[]}, @@ -403,7 +403,7 @@ {"digest":"88a610b831be6d92612a464be5c7d0b88ec24d97bd299837bf74bf7672183c9a","names":[],"sources":["packages/llm/llm/src/types.ts:474"]}, {"digest":"8a046b52331959aa3394680d6acbe09b8a5447c6b61375f263445bfcef19b7f1","names":[],"sources":[]}, {"digest":"8a6e1ec9e8db346b0e02f027db73c07a94f067a26d40c1aef1abd09c47ce7ba0","names":[],"sources":[]}, - {"digest":"8a9c990773f798eac10ca8878e6bcc531ee080bc589cac956730e462cc6a09ad","names":[],"sources":["packages/interaction/permission-presets/src/index.ts:52"]}, + {"digest":"8a9c990773f798eac10ca8878e6bcc531ee080bc589cac956730e462cc6a09ad","names":[],"sources":["packages/interaction/permission-presets/src/index.ts:53"]}, {"digest":"8ad45ad053b4d89f8865c17cc9ff3b8748e86045f3f0fb816269a34af2619141","names":[],"sources":["packages/experimental/hook-protocol/src/types.ts:31"]}, {"digest":"8af841fc9b265ade3441caf9fe40dd24db24226befba48150e6d0eeccc1389c3","names":[],"sources":[]}, {"digest":"8bb8c3751a6ce64b61aba1ec7ae798c00a5803c4d868a0430873216c6569ed52","names":[],"sources":["packages/session/session-log-deepseek/src/types.ts:81"]}, @@ -416,7 +416,7 @@ {"digest":"8e8e91646a5cae3fc78f7532a0013ff2088ae47077642c2edd507a508209b8af","names":["packages/schedule/schedule/src/types.ts#OneShotScheduleDispatchChange"],"sources":["packages/schedule/schedule/src/types.ts:237"]}, {"digest":"8f324cea3916c0517261e88167def8efb3a9994c1135e23d40ed9fd48f8c7bd4","names":[],"sources":[]}, {"digest":"8f6d609794bf5afc01d7ccf3e03811d32f4b8047f58a2c9a98db0154c2ad7cb9","names":[],"sources":[]}, - {"digest":"8fcb0b44a575e998665c053643d1ab04c82f39253ebd190ac0c975b78e40b543","names":[],"sources":["packages/core/tools/src/index.ts:18"]}, + {"digest":"8fcb0b44a575e998665c053643d1ab04c82f39253ebd190ac0c975b78e40b543","names":[],"sources":["packages/core/tools/src/index.ts:28"]}, {"digest":"904bf499d98be4a3a5f836fcac533b6c4899569b018071e6604e1d32657d00fd","names":[],"sources":[]}, {"digest":"930c1cd289def119d443e19dd90008916bf035f0a4d23e07241e7f050f2b89b7","names":["packages/interaction/user-approval/src/types.ts#ApprovalOutcome"],"sources":["packages/interaction/user-approval/src/types.ts:32"]}, {"digest":"935c8d486292b13c87b57ca280eb8c58b5b2f5239be86fcd4334c33fdeb87682","names":[],"sources":[]}, @@ -440,7 +440,7 @@ {"digest":"99f0e98184709ad10f27bfdeaafb4457d9d2b413f402331764798cdb7d3cbe4d","names":[],"sources":[]}, {"digest":"9a2a9029f8d7ede05336980d8342737557f487b913bfd28853d0ab5214600ab5","names":[],"sources":["packages/web/web-search-deepseek/src/provider.ts:64"]}, {"digest":"9a410ddf56792b2b7cd4a224a2e54dc4dee30a8e8e6b1c2b9a1d19992b217adc","names":["packages/workflow/tool-workflow/src/types.ts#ToolWorkflowAgentStartData"],"sources":["packages/workflow/tool-workflow/src/types.ts:20"]}, - {"digest":"9a930283b91d493d6347146f2475bb107294b379415ca02162354f46a64164f7","names":["packages/core/session/src/types.ts#EpochHeader"],"sources":["packages/core/session/src/types.ts:241"]}, + {"digest":"9a930283b91d493d6347146f2475bb107294b379415ca02162354f46a64164f7","names":["packages/core/session/src/types.ts#EpochHeader"],"sources":["packages/core/session/src/types.ts:242"]}, {"digest":"9ac52f0f84fec2eb9f71c2937e497d759db5ca0da4836d93a679d113684141f2","names":[],"sources":[]}, {"digest":"9acbe713f3f641921dd3333b240aa72e176d795327c24e8d9db9b68b16771b49","names":[],"sources":[]}, {"digest":"9b4fd974c124c83743efe030ba4e1250e087505f3f74588716a521fb8d453267","names":[],"sources":[]}, @@ -471,7 +471,7 @@ {"digest":"a6da9ad5d42ae83a6833a8288b076688e8e0801633ea36cbdd8a30a6d9f3160c","names":["packages/workflow/tool-workflow/src/types.ts#ToolWorkflowRunStartData"],"sources":["packages/workflow/tool-workflow/src/types.ts:14"]}, {"digest":"a720757f704a2512e9d2f20da4a093e582472176236a75ab8b8eb7aaff17d85a","names":[],"sources":[]}, {"digest":"a7cf43ce7c2a4c038feed1885cd7a00d5c6ee2d90a7e0d56b46f78a3e1ca327f","names":[],"sources":[]}, - {"digest":"a81059ca06999da1e712414520c2c65e491d052fcf9640fae20aa38f0a5dc735","names":[],"sources":["packages/core/session/src/types.ts:384","packages/core/tool-executor-ptc/src/types.ts:27"]}, + {"digest":"a81059ca06999da1e712414520c2c65e491d052fcf9640fae20aa38f0a5dc735","names":[],"sources":["packages/core/session/src/types.ts:385","packages/core/tool-executor-ptc/src/types.ts:27"]}, {"digest":"a853902cfab417b8f08aa51ad6855fea46f34ed4588a74e47403035111d0fb86","names":[],"sources":["packages/interaction/commands/src/types.ts:105"]}, {"digest":"a8a2b9011fc067862df7ce40748868467e5778283d7ac193c13f77684a914c57","names":[],"sources":[]}, {"digest":"a9059a81430b320792bbb7c2ee1f8f6c77ff71e40ee44c18aec72e157c522694","names":[],"sources":[]}, @@ -485,10 +485,10 @@ {"digest":"aa93010d0e521ad7c42273f58d5c9b8bf1dfc94edf1b805a3971b364a35c1877","names":[],"sources":[]}, {"digest":"aacda84a69739238aa782eea902d3073017d9d74b9808de2bf5a83c9738cbdc6","names":[],"sources":[]}, {"digest":"aae343bc3d663c83f2e8b5e1c7eea5d509dc7a5361bc8bd8b5ac3bb8d3b1ed56","names":[],"sources":[]}, - {"digest":"ab7ec5f9eb2c6dfacca5da4c37cf7ba85d04172053ee6b1ebf1709ffcd99c1a7","names":[],"sources":["packages/core/session/src/types.ts:215","packages/llm/llm/src/types.ts:159"]}, + {"digest":"ab7ec5f9eb2c6dfacca5da4c37cf7ba85d04172053ee6b1ebf1709ffcd99c1a7","names":[],"sources":["packages/core/session/src/types.ts:216","packages/llm/llm/src/types.ts:159"]}, {"digest":"aba175fb20ffc71112c55efe70458ff5d7dbfb83501892b4ba8d077f0ea5d7ba","names":[],"sources":[]}, {"digest":"abd6ca62a5ab166553848324a23fef90eed7f59c8021bd63e7ea5bc6fd666b0c","names":["packages/web/web-search-deepseek/src/provider.ts#DeepSeekSearchLlmRequest"],"sources":["packages/web/web-search-deepseek/src/provider.ts:55"]}, - {"digest":"ad0c38a0adb82a94c925456df41586d9b5f9202fca18593eae2213d4445b4585","names":[],"sources":["packages/core/session/src/types.ts:391"]}, + {"digest":"ad0c38a0adb82a94c925456df41586d9b5f9202fca18593eae2213d4445b4585","names":[],"sources":["packages/core/session/src/types.ts:392"]}, {"digest":"ad22a5ca5bbaab2e1440779cd3648e85ddfc6f73b5207394eda699555cf31430","names":[],"sources":[]}, {"digest":"ad3b56aa2fc1ad4250e7399295d34a8eae592e1907e85852e2291b2e498a30bc","names":[],"sources":[]}, {"digest":"ad92f473a03ae72599ff26c86e897c25e16269519ad2a87340f0bea946517af8","names":[],"sources":[]}, @@ -502,7 +502,7 @@ {"digest":"b0127044ab31a702bddfd785d345f5abd7a70876746e895ce443afa3e60ddf2d","names":[],"sources":[]}, {"digest":"b062078e899958f99ae464514578b8c093924dfe34bd9a835932b420ff2150b1","names":[],"sources":[]}, {"digest":"b0b0eb1b16490f6bee135b2377e8f8c39227974c799ad7d49ff418af23ecbc35","names":["packages/attachment/attachment/src/types.ts#ImageAttachmentRef"],"sources":["packages/attachment/attachment/src/types.ts:11"]}, - {"digest":"b158f3ff6923714807c0d73882f0b05dc87f8fa85c9e90814852d48bbc866081","names":["packages/core/session/src/types.ts#RequestContext"],"sources":["packages/core/session/src/types.ts:255"]}, + {"digest":"b158f3ff6923714807c0d73882f0b05dc87f8fa85c9e90814852d48bbc866081","names":["packages/core/session/src/types.ts#RequestContext"],"sources":["packages/core/session/src/types.ts:256"]}, {"digest":"b1664fa89f8eab49a14e7e3168d8bc4da4aa9fd76332f6c4a053d839e5276ae7","names":[],"sources":[]}, {"digest":"b1ebd5cda47d90d980bb05bffc3f970c51537b9aff15b3bc3d639811727741b1","names":[],"sources":["packages/experimental/agent-team/src/types.ts:230"]}, {"digest":"b1f62380f6746fedd629e71065e3583cef83334875b499ac9665c2eb87acfbf5","names":[],"sources":[]}, @@ -542,7 +542,7 @@ {"digest":"bb1ab3d08f49a9f3b265f844cd78d5c49813062a7b34b54904b426f85d0ff6e3","names":[],"sources":[]}, {"digest":"bb94f3217aa56c8876bbff0b8460d6a73cbead545659abb29e76cd0cf2cb92d6","names":[],"sources":[]}, {"digest":"bbc5696e3f13c758237b316e3cf08cda0b9fd51ffe672539883457769faa185d","names":[],"sources":[]}, - {"digest":"bcf0caf62d964b2fcf5404bd5c909cfa9a21c3f3c96e6b7e36d9e33565223825","names":[],"sources":["packages/core/session/src/types.ts:465"]}, + {"digest":"bcf0caf62d964b2fcf5404bd5c909cfa9a21c3f3c96e6b7e36d9e33565223825","names":[],"sources":["packages/core/session/src/types.ts:466"]}, {"digest":"bd499eac047efe091a4df7382eadd06d25cf0cb31fee3981e8b24d85762841cd","names":[],"sources":[]}, {"digest":"bf16d2e98a7f13894ded2cffe5ce857bf473954a0e3c0ed9bc7739e2e1c7b78a","names":[],"sources":[]}, {"digest":"c0ea97bc89dfc46fa94eab956f5c3ee6af2f964aa7db6327cb18b451f207bef7","names":["packages/workflow/tool-workflow/src/types.ts#ToolWorkflowAgentEndData"],"sources":["packages/workflow/tool-workflow/src/types.ts:29"]}, @@ -613,8 +613,8 @@ {"digest":"e41bdebe246abe17154de7e7a1d81035437eee8d20e7f1edff0d91e2598ad828","names":[],"sources":[]}, {"digest":"e42b0f40b5d0b628c6e1c44a8fb9eda0780037a81959e1b93d2dfb47b46b0e87","names":[],"sources":[]}, {"digest":"e438a9d4fb883b3e4a8d9fc8913aa1550ed50eb384bfbf943100a5605b537498","names":[],"sources":[]}, - {"digest":"e481c46af3813e0010558e93f578b2986acd658404cec2d1679e3ac2a6c48654","names":[],"sources":["packages/core/session/src/types.ts:298"]}, - {"digest":"e4c18e294232c3ba6c9f1999f168263cc55956147cfe4121720899be8e52edd1","names":[],"sources":["packages/core/session/src/types.ts:362"]}, + {"digest":"e481c46af3813e0010558e93f578b2986acd658404cec2d1679e3ac2a6c48654","names":[],"sources":["packages/core/session/src/types.ts:299"]}, + {"digest":"e4c18e294232c3ba6c9f1999f168263cc55956147cfe4121720899be8e52edd1","names":[],"sources":["packages/core/session/src/types.ts:363"]}, {"digest":"e4cac694f8b6e1d52e48c699464f1c4c26111ef87e558f7931040d00fdc8d486","names":[],"sources":[]}, {"digest":"e5d3828df1ec3e2a66879de0659e0f4866d9cfffc00825ee731a66f8a0c03d98","names":[],"sources":[]}, {"digest":"e6063d0451dc02026fd9b54ad3f77c7b1b6392ad3e872a7737ac84e13ca72344","names":["packages/schedule/schedule/src/types.ts#EveryScheduleDispatchChange"],"sources":["packages/schedule/schedule/src/types.ts:244"]}, @@ -630,18 +630,18 @@ {"digest":"eaa71be0fbf0f702df8ea6c11d0aa2f9782263d45a10d0fb14eda662f4bfe04c","names":[],"sources":["packages/core/session/src/types.ts:197"]}, {"digest":"ebb768d85ec87fb68e42fc14fd7d8535b5ac11791b14d04c6770180f0a719bf8","names":[],"sources":[]}, {"digest":"ec38b5949af8eacaf00df002f4acbe344f934f8a061e9cdc65a52a48e5f6dd93","names":[],"sources":[]}, - {"digest":"ec8b5ff7c77ca6893ac7ba5a0c5b2aefeb52f12c64450b7359660c2a7e8a53d7","names":[],"sources":["packages/core/session/src/types.ts:229"]}, + {"digest":"ec8b5ff7c77ca6893ac7ba5a0c5b2aefeb52f12c64450b7359660c2a7e8a53d7","names":[],"sources":["packages/core/session/src/types.ts:230"]}, {"digest":"edbbfff1128099fda7b792c56330d2cb04debc9790988e66d1c3f4026e813e0e","names":[],"sources":[]}, {"digest":"edd37b1e4974af648633014435572089b1e8fb71910468a0767a7e28fdd22abf","names":[],"sources":[]}, {"digest":"ee577a0cc18664c9daee50e9455153321155604f8f1817362f8f4a4b6fb9e1ad","names":[],"sources":[]}, {"digest":"eea687d437880bd5f55fb447a561112800ca34334c0724d9cecb98493059d9e4","names":["packages/schedule/schedule/src/types.ts#ScheduleCreateChange"],"sources":["packages/schedule/schedule/src/types.ts:223"]}, {"digest":"eefbea819caeeea91ccb02dfafc16c68dd7f961cf9c1b2be25a2084509cf5c5a","names":[],"sources":[]}, - {"digest":"ef11a3b7fa2033ae4279545ff8a8a2ee4e301b9b73e5b91654c48e6d08283545","names":[],"sources":["packages/core/session/src/types.ts:300","packages/core/session/src/types.ts:302"]}, + {"digest":"ef11a3b7fa2033ae4279545ff8a8a2ee4e301b9b73e5b91654c48e6d08283545","names":[],"sources":["packages/core/session/src/types.ts:301","packages/core/session/src/types.ts:303"]}, {"digest":"ef226a90ddac6cd8e631a3a337a3a3e27f9494be92befb7c718b404681d75e21","names":[],"sources":[]}, {"digest":"ef4f00923b9edbae15c7ef05320280bf61147ca17146cf59690359bfd5e5da45","names":[],"sources":[]}, {"digest":"f05fb85e715af4ab4de0b6ba111166dd0435bd8bb74a0fa0f32b9d174113fc7c","names":[],"sources":[]}, {"digest":"f09e5e7acf5ff5ccd193ff2eeec015fa2ff7c29d98bc465f8c3302058d47e29b","names":["packages/core/agent/src/types.ts#ModelSelection"],"sources":["packages/core/agent/src/types.ts:79"]}, - {"digest":"f1687f982fa3d41ef29e159feed154ecd13af4dd209acaee16038f223f2e9402","names":["packages/core/session/src/types.ts#TurnEndReason"],"sources":["packages/core/session/src/types.ts:233"]}, + {"digest":"f1687f982fa3d41ef29e159feed154ecd13af4dd209acaee16038f223f2e9402","names":["packages/core/session/src/types.ts#TurnEndReason"],"sources":["packages/core/session/src/types.ts:234"]}, {"digest":"f1996af2602e6f62b5ab179ca5c4af00d8753938b74cc6ef102de09e99e74a7e","names":[],"sources":[]}, {"digest":"f19bee84bf3d20904553cdcd57465232bc1c2a194f54c4d195292ba0487223a6","names":["packages/attachment/attachment/src/types.ts#FileAttachmentRef"],"sources":["packages/attachment/attachment/src/types.ts:39"]}, {"digest":"f1a96afe7503ac1817de769cd0ba13d9b80111c7034c50106b3344ecc14cc515","names":[],"sources":["packages/llm/llm/src/types.ts:476"]}, @@ -650,7 +650,7 @@ {"digest":"f2da0f27c1e6add59982c37b15e4a4912c5b33466859cce3b13d503600e24aef","names":["packages/llm/llm/src/types.ts#FileBlock"],"sources":["packages/llm/llm/src/types.ts:98"]}, {"digest":"f311671e07bc7fa645a0b6597de9966b97147956565296ba76a36543801b66c5","names":["packages/llm/llm/src/types.ts#SystemPromptUpdate"],"sources":["packages/llm/llm/src/types.ts:414"]}, {"digest":"f4a66f654996c093aae700ea4c434ff2ee3569fea9c0e5813ccf6afdccabd163","names":[],"sources":[]}, - {"digest":"f4ed4717b4c259e933b550a8dcd90dc93628cda8a3c7affcaa53b9c13c1d53eb","names":[],"sources":["packages/core/session/src/types.ts:312"]}, + {"digest":"f4ed4717b4c259e933b550a8dcd90dc93628cda8a3c7affcaa53b9c13c1d53eb","names":[],"sources":["packages/core/session/src/types.ts:313"]}, {"digest":"f5520c1d261ca86ea03735799c311a0a9ede8babb588cf0a65422576d2ee0ad1","names":[],"sources":[]}, {"digest":"f56c5b59ca0161310c338d31dd16cf14287ccd602ff4181058df178c1c286d7f","names":["packages/context/session-reference/src/types.ts#SessionReferenceSource"],"sources":["packages/context/session-reference/src/types.ts:13"]}, {"digest":"f6329fb30c7ea8013e8975ca5e78284fb7685cc6bd620e8aa4e9a99bc81d45eb","names":[],"sources":[]}, @@ -663,7 +663,7 @@ {"digest":"f731ffe80810b0289b3e694d8f40af6f01865c02a622ee457be90ca808b66e87","names":["packages/subagent/subagent/src/catalog.ts#SubagentCatalogEvent"],"sources":["packages/subagent/subagent/src/catalog.ts:28"]}, {"digest":"f789af5ab844827eb5a4f357c0afae1eeed108c6c22d8ca1a56e586b349a7c85","names":[],"sources":[]}, {"digest":"f88f1b7b6bb733f685f5fb6a8744a5db9199fa53c90463ea1a33bad51153671d","names":[],"sources":[]}, - {"digest":"f90eb4ab2d3897bc20c521a038e3119d581f791ec974b1a0004f63a8ab9e232d","names":[],"sources":["packages/core/session/src/types.ts:289","packages/deliverables/workspace-changes/src/types.ts:106"]}, + {"digest":"f90eb4ab2d3897bc20c521a038e3119d581f791ec974b1a0004f63a8ab9e232d","names":[],"sources":["packages/core/session/src/types.ts:290","packages/deliverables/workspace-changes/src/types.ts:106"]}, {"digest":"f97f47b0eb87905ed77cc27c5e4ed75ef805cb372c98905253709de1aab9b63c","names":[],"sources":[]}, {"digest":"f9cfc89e8fe085b4fcc9cd32b74b6f103608c54d7d8cd97b47c01de34f252ba3","names":[],"sources":[]}, {"digest":"fa106c5b33b657e8ef16e8cbf39f3b7d44e5cbcdf4f9303d9db6410f28951e42","names":[],"sources":["packages/core/agent/src/types.ts:110"]}, diff --git a/docs/subsystems/attachment.i18n.yaml b/docs/subsystems/attachment.i18n.yaml index b548deda3d..621444176d 100644 --- a/docs/subsystems/attachment.i18n.yaml +++ b/docs/subsystems/attachment.i18n.yaml @@ -6,8 +6,8 @@ en: 564dfcaaca384e23 zh: 5d215635919b5bc4 /durable-attachments/identity-and-verified-metadata: - en: 3ddfd5100061dc6a - zh: 3eedb90c8813d015 + en: 96378c208b220c6f + zh: 7af93f6a79520732 /durable-attachments/commit-and-verified-read-payloads: - en: 01c9eb5d67e3c7c3 - zh: abf32dddcca5fce1 + en: f79753272bb0ec70 + zh: 61830c41021f9274 diff --git a/docs/subsystems/attachment.md b/docs/subsystems/attachment.md index 12ae675e3c..2e330672f7 100644 --- a/docs/subsystems/attachment.md +++ b/docs/subsystems/attachment.md @@ -56,7 +56,7 @@ interface ImageAttachmentLimits { } ``` -The local backend admits at most 20 images and 200 MiB of encoded source data per message. One source may use up to 20 MiB, 64,000,000 pixels, and 8192 pixels on either side. These source limits precede the independent normalization stage, which limits the long edge to 2048 pixels and encoded data to 4 MiB by default. +The local backend admits at most 20 images and 200 MiB of encoded source data per message. One source may use up to 50 MiB, 64,000,000 pixels, and 65,535 pixels on either side. These source limits precede the independent normalization stage, which limits the long edge to 2048 pixels and encoded data to 4 MiB by default. The reference records intrinsic dimensions and encoded length so clients can lay out history without decoding first, while every authoritative read still re-checks digest, media signature, dimensions, and metadata against the object. @@ -80,10 +80,16 @@ type PromptContentPart = ``` ```ts type-equiv -/** Host prompt content whose file receipts are resolved and whose image bytes await admission. */ +/** + * Host prompt content whose upload receipts are resolved. An image part + * carries encoded bytes awaiting admission, or references an image this + * service already stored for an upload the same Session staged, with + * `encodedBytes` holding the byte length of that upload. + */ type AttachmentAdmissionPart = | PromptContentPart | { readonly type: 'file'; readonly attachment: FileAttachmentRef } + | { readonly type: 'image'; readonly attachment: ImageAttachmentRef; readonly encodedBytes: number } ``` ```ts type-equiv @@ -167,7 +173,7 @@ interface RequestImageAttachment { } ``` -`saveImage()` prepares and atomically commits a provider-independent normalized attachment before returning its `ImageAttachmentRef`. `saveImages()` prepares every validated attachment once before publishing the batch, so validation rejection leaves no partial objects and publication does not repeat decoding or quality selection. `admitPromptContent()` accepts the complete ordered Host prompt after file receipt resolution, replaces base64 image uploads with durable references, and passes durable file references unchanged. `admitEncodedImages()` supports other wire entries and delegates count, aggregate-byte, and ordered batch admission to `saveImages()`. `admitEncodedFile()` gives encoded protocol adapters the same service-owned canonical-base64 admission, and `isAttachmentError()` lets those adapters recognize stable attachment failures without importing implementation helpers. `readImage()` verifies a normalized attachment from an authorized session path. `imageHostPath()` exposes only the provider-owned host object location; it does not decide whether the current tool execution world can read it. `readImageRequest()` derives and caches one deterministic request version at an exact route-chosen target size and encoded-byte target. That version contains encoded bytes and metadata but no execution-world path. New entries are fully decoded before publication, while cache hits use a bounded metadata probe. Callers use `Promise.all` over the singular method when they need an ordered batch. The local implementation lazily encodes preferred candidates, singleflights equal request identities, lets each waiter cancel independently, stops shared work when no waiter remains, and bounds all transforms with its instance-level limiter, which defaults to two simultaneous transformations. The service is retention-neutral: resumed and forked sessions may share objects, so reference-aware garbage collection is deferred rather than tied to one session's deletion. +`saveImage()` prepares and atomically commits a provider-independent normalized attachment before returning its `ImageAttachmentRef`. `saveImages()` prepares every validated attachment once before publishing the batch, so validation rejection leaves no partial objects and publication does not repeat decoding or quality selection. `admitPromptContent()` accepts the complete ordered Host prompt after upload receipt resolution, replaces base64 image uploads with durable references, passes durable file references and already stored images unchanged, and counts every image toward the per-message image count and aggregate byte limits, a stored image by the bytes of its upload. `admitEncodedImages()` supports other wire entries and delegates count, aggregate-byte, and ordered batch admission to `saveImages()`. `admitEncodedFile()` gives encoded protocol adapters the same service-owned canonical-base64 admission, and `isAttachmentError()` lets those adapters recognize stable attachment failures without importing implementation helpers. `readImage()` verifies a normalized attachment from an authorized session path. `imageHostPath()` exposes only the provider-owned host object location; it does not decide whether the current tool execution world can read it. `readImageRequest()` derives and caches one deterministic request version at an exact route-chosen target size and encoded-byte target. That version contains encoded bytes and metadata but no execution-world path. New entries are fully decoded before publication, while cache hits use a bounded metadata probe. Callers use `Promise.all` over the singular method when they need an ordered batch. The local implementation lazily encodes preferred candidates, singleflights equal request identities, lets each waiter cancel independently, stops shared work when no waiter remains, and bounds all transforms with its instance-level limiter, which defaults to two simultaneous transformations. The service is retention-neutral: resumed and forked sessions may share objects, so reference-aware garbage collection is deferred rather than tied to one session's deletion. @@ -200,9 +206,12 @@ abstract validateImage(input: SaveImageAttachment): Promise async saveImages(inputs: readonly SaveImageAttachment[]): Promise /** - * Admit one Host prompt and replace each uploaded image with its durable reference. - * Text and durable file references pass through unchanged. A prompt without image parts performs no storage operation. - * @param content - prompt parts in message order after file receipt resolution. + * Admit one Host prompt and replace each encoded image with its durable reference. + * Text, durable file references, and already stored images pass through unchanged. + * Every image part counts toward `maxImagesPerMessage` and `maxMessageImageBytes`; + * a stored image counts the bytes of the upload that stored it. Refused content + * starts no writes. A prompt without encoded images performs no storage operation. + * @param content - prompt parts in message order after upload receipt resolution. * @returns admitted prompt parts in the same order as `content`. * @throws AttachmentError when the image batch is refused. */ @@ -320,7 +329,7 @@ registerAgentResolver(resolve: AgentResolver): () => void * @param signal - caller cancellation before storage begins. * @returns the staged receipt and durable file reference. */ -@Remote('upload') upload(agent: Agent, request: EncodedFileUploadRequest, signal: AbortSignal): Promise +@Remote('upload') async upload(agent: Agent, request: EncodedFileUploadRequest, signal: AbortSignal): Promise /** * Persist raw chunks for one Session without aggregating the upload. @@ -329,13 +338,27 @@ registerAgentResolver(resolve: AgentResolver): () => void */ async uploadStream(request: { readonly sessionId: SessionId readonly data: AsyncIterable readonly signal?: AbortSignal readonly name?: string }): Promise +/** + * Persist one prompt image for a Session: read at most the smaller of the + * deployment's per-image and per-message byte limits, then validate, + * normalize, and store the image the way prompt admission does, so a later + * prompt cites it by receipt. + * Cancellation before storage begins stores nothing; a cancelled upload + * never receives a receipt, although an image whose storage already began + * stays in the content-addressed store. + * @param request - Session identity, ordered bytes, the declared media type that this deployment + * must accept, cancellation, and optional display name. + * @returns the staged receipt and durable normalized image reference. + */ +async uploadImageStream(request: { readonly sessionId: SessionId readonly data: AsyncIterable readonly mediaType: string readonly signal?: AbortSignal readonly name?: string }): Promise + /** * Resolve one staged receipt for the receiving Agent's exact Session. * @param agent - receiving Agent. * @param receiptId - opaque receipt minted for one completed upload. - * @returns durable file reference, or `undefined` for an unknown or foreign receipt. + * @returns the staged file or image, or `undefined` for an unknown or foreign receipt. */ -resolve(agent: Agent, receiptId: FileUploadReceiptId): FileAttachmentRef | undefined +resolve(agent: Agent, receiptId: FileUploadReceiptId): StagedAttachment | undefined /** * Bind receipts while one prompt enters an Agent inbox. diff --git a/docs/subsystems/attachment.zh.md b/docs/subsystems/attachment.zh.md index 06ea726f19..057ed080f4 100644 --- a/docs/subsystems/attachment.zh.md +++ b/docs/subsystems/attachment.zh.md @@ -56,7 +56,7 @@ interface ImageAttachmentLimits { } ``` -本地后端每条消息最多准入 20 张图片,源图编码数据总量不超过 200 MiB。单张源图不得超过 20 MiB、64,000,000 像素和单边 8192 像素。这些源文件限制先于独立的规范化阶段执行;该阶段默认把长边限制为 2048 像素,把编码数据限制为 4 MiB。 +本地后端每条消息最多准入 20 张图片,源图编码数据总量不超过 200 MiB。单张源图不得超过 50 MiB、64,000,000 像素和单边 65,535 像素。这些源文件限制先于独立的规范化阶段执行;该阶段默认把长边限制为 2048 像素,把编码数据限制为 4 MiB。 引用记录固有尺寸和编码长度,使客户端无需先解码即可排布历史记录;每次权威读取仍会根据对象重新校验摘要、媒体签名、尺寸和元数据。 @@ -80,10 +80,16 @@ type PromptContentPart = ``` ```ts type-equiv -/** Host prompt content whose file receipts are resolved and whose image bytes await admission. */ +/** + * Host prompt content whose upload receipts are resolved. An image part + * carries encoded bytes awaiting admission, or references an image this + * service already stored for an upload the same Session staged, with + * `encodedBytes` holding the byte length of that upload. + */ type AttachmentAdmissionPart = | PromptContentPart | { readonly type: 'file'; readonly attachment: FileAttachmentRef } + | { readonly type: 'image'; readonly attachment: ImageAttachmentRef; readonly encodedBytes: number } ``` ```ts type-equiv @@ -167,7 +173,7 @@ interface RequestImageAttachment { } ``` -`saveImage()` 准备并原子提交提供方无关的规范化附件,然后直接返回 `ImageAttachmentRef`。`saveImages()` 在发布批次前为每个成员各准备一次经过验证的附件,因此校验拒绝不会留下部分对象,发布也不会重复解码或选择质量。`admitPromptContent()` 在文件凭证解析后接收完整且有序的 Host prompt,把 base64 图片上传替换为持久引用,并让持久文件引用原样通过。`admitEncodedImages()` 支持其他 wire 入口,把张数、聚合字节和有序批量准入交给 `saveImages()`。`admitEncodedFile()` 让编码协议适配器使用服务拥有的规范 base64 准入,`isAttachmentError()` 让这些适配器无需导入实现辅助函数即可识别稳定的附件错误。`readImage()` 校验来自已授权会话路径的规范化附件。`imageHostPath()` 只公开提供方所持对象的宿主位置,不判断当前工具执行环境能否读取它。`readImageRequest()` 按确切的路由目标尺寸和编码字节目标派生并缓存确定性请求版本。该版本包含编码字节和元数据,不包含执行环境路径。新条目在发布前完整解码,缓存命中只做有界元数据探测。调用方需要有序批次时,对单数方法使用 `Promise.all`。本地实现按需编码首选候选、合并相同请求身份的并发任务、允许每个等待方单独取消、没有等待方时停止共享任务,并通过实例级限流器限制全部变换,默认同时执行两项。该服务不规定保留策略:恢复和 fork 后的会话可能共享对象,因此基于引用的垃圾回收会延期实现,不与单个会话的删除绑定。 +`saveImage()` 准备并原子提交提供方无关的规范化附件,然后直接返回 `ImageAttachmentRef`。`saveImages()` 在发布批次前为每个成员各准备一次经过验证的附件,因此校验拒绝不会留下部分对象,发布也不会重复解码或选择质量。`admitPromptContent()` 在上传凭证解析后接收完整且有序的 Host prompt,把 base64 图片上传替换为持久引用,让持久文件引用和已存储的图片原样通过,并把每张图片计入单条消息的图片数量与总字节上限,已存储的图片按其上传的字节数计入。`admitEncodedImages()` 支持其他 wire 入口,把张数、聚合字节和有序批量准入交给 `saveImages()`。`admitEncodedFile()` 让编码协议适配器使用服务拥有的规范 base64 准入,`isAttachmentError()` 让这些适配器无需导入实现辅助函数即可识别稳定的附件错误。`readImage()` 校验来自已授权会话路径的规范化附件。`imageHostPath()` 只公开提供方所持对象的宿主位置,不判断当前工具执行环境能否读取它。`readImageRequest()` 按确切的路由目标尺寸和编码字节目标派生并缓存确定性请求版本。该版本包含编码字节和元数据,不包含执行环境路径。新条目在发布前完整解码,缓存命中只做有界元数据探测。调用方需要有序批次时,对单数方法使用 `Promise.all`。本地实现按需编码首选候选、合并相同请求身份的并发任务、允许每个等待方单独取消、没有等待方时停止共享任务,并通过实例级限流器限制全部变换,默认同时执行两项。该服务不规定保留策略:恢复和 fork 后的会话可能共享对象,因此基于引用的垃圾回收会延期实现,不与单个会话的删除绑定。 @@ -200,9 +206,12 @@ abstract validateImage(input: SaveImageAttachment): Promise async saveImages(inputs: readonly SaveImageAttachment[]): Promise /** - * Admit one Host prompt and replace each uploaded image with its durable reference. - * Text and durable file references pass through unchanged. A prompt without image parts performs no storage operation. - * @param content - prompt parts in message order after file receipt resolution. + * Admit one Host prompt and replace each encoded image with its durable reference. + * Text, durable file references, and already stored images pass through unchanged. + * Every image part counts toward `maxImagesPerMessage` and `maxMessageImageBytes`; + * a stored image counts the bytes of the upload that stored it. Refused content + * starts no writes. A prompt without encoded images performs no storage operation. + * @param content - prompt parts in message order after upload receipt resolution. * @returns admitted prompt parts in the same order as `content`. * @throws AttachmentError when the image batch is refused. */ @@ -320,7 +329,7 @@ registerAgentResolver(resolve: AgentResolver): () => void * @param signal - caller cancellation before storage begins. * @returns the staged receipt and durable file reference. */ -@Remote('upload') upload(agent: Agent, request: EncodedFileUploadRequest, signal: AbortSignal): Promise +@Remote('upload') async upload(agent: Agent, request: EncodedFileUploadRequest, signal: AbortSignal): Promise /** * Persist raw chunks for one Session without aggregating the upload. @@ -329,13 +338,27 @@ registerAgentResolver(resolve: AgentResolver): () => void */ async uploadStream(request: { readonly sessionId: SessionId readonly data: AsyncIterable readonly signal?: AbortSignal readonly name?: string }): Promise +/** + * Persist one prompt image for a Session: read at most the smaller of the + * deployment's per-image and per-message byte limits, then validate, + * normalize, and store the image the way prompt admission does, so a later + * prompt cites it by receipt. + * Cancellation before storage begins stores nothing; a cancelled upload + * never receives a receipt, although an image whose storage already began + * stays in the content-addressed store. + * @param request - Session identity, ordered bytes, the declared media type that this deployment + * must accept, cancellation, and optional display name. + * @returns the staged receipt and durable normalized image reference. + */ +async uploadImageStream(request: { readonly sessionId: SessionId readonly data: AsyncIterable readonly mediaType: string readonly signal?: AbortSignal readonly name?: string }): Promise + /** * Resolve one staged receipt for the receiving Agent's exact Session. * @param agent - receiving Agent. * @param receiptId - opaque receipt minted for one completed upload. - * @returns durable file reference, or `undefined` for an unknown or foreign receipt. + * @returns the staged file or image, or `undefined` for an unknown or foreign receipt. */ -resolve(agent: Agent, receiptId: FileUploadReceiptId): FileAttachmentRef | undefined +resolve(agent: Agent, receiptId: FileUploadReceiptId): StagedAttachment | undefined /** * Bind receipts while one prompt enters an Agent inbox. diff --git a/docs/subsystems/client-modules.md b/docs/subsystems/client-modules.md index 2ebf2c2f64..c7f175b9e6 100644 --- a/docs/subsystems/client-modules.md +++ b/docs/subsystems/client-modules.md @@ -156,7 +156,9 @@ clientPath(id: string): string | undefined * body. Each bundle body is built once on its first `GET`; script * construction never reads maps. A package asset is read on every request * and answers 304 without a body when `If-None-Match` equals its entity tag; - * its body holds the file open until the caller consumes or cancels it. + * its body holds the file open until the caller consumes or cancels it. A + * bundle, map, or chunk body is the held buffer itself, not a copy, so a + * caller must not modify its bytes. * @param request - shell-carrier request for a `/plugins` resource. * @returns the exact response also exposed by the optional Web route. */ diff --git a/docs/subsystems/client-modules.zh.md b/docs/subsystems/client-modules.zh.md index 1049e859f6..b0a665fe9a 100644 --- a/docs/subsystems/client-modules.zh.md +++ b/docs/subsystems/client-modules.zh.md @@ -156,7 +156,9 @@ clientPath(id: string): string | undefined * body. Each bundle body is built once on its first `GET`; script * construction never reads maps. A package asset is read on every request * and answers 304 without a body when `If-None-Match` equals its entity tag; - * its body holds the file open until the caller consumes or cancels it. + * its body holds the file open until the caller consumes or cancels it. A + * bundle, map, or chunk body is the held buffer itself, not a copy, so a + * caller must not modify its bytes. * @param request - shell-carrier request for a `/plugins` resource. * @returns the exact response also exposed by the optional Web route. */ diff --git a/docs/subsystems/core.i18n.yaml b/docs/subsystems/core.i18n.yaml index d93bf7cccf..02e7a5d4f6 100644 --- a/docs/subsystems/core.i18n.yaml +++ b/docs/subsystems/core.i18n.yaml @@ -9,8 +9,8 @@ en: c90cb23528ddb6c8 zh: 62724b7255b586b6 /core/creation-and-ownership: - en: ab09a38b4e1f0883 - zh: 81e2d14c4036ab6c + en: e516e14228c6bd35 + zh: dba25d7da1d5a44e /core/the-agent-handle: en: 6ee15fec81bc0686 zh: b6f3fcd48823ea75 diff --git a/docs/subsystems/core.md b/docs/subsystems/core.md index 78d01b3d89..86df19aa94 100644 --- a/docs/subsystems/core.md +++ b/docs/subsystems/core.md @@ -46,7 +46,7 @@ interface AgentHandle { } ``` -`CreateAgentOptions` carries the shared identity and everything a fresh agent needs before publication: an optional live `parentAgent`, session metadata (`meta` — validated `cwd`, fork lineage, the `isSeeded` marker, origin classification, delegation depth, and `agentPreset`), the exact fork cut in sibling field `inheritedEventCount`, an optional `seed` replay prefix, per-agent `AgentOptions`, a creation-only cancellation `signal`, and `setup`. `ResumeAgentOptions` is the persisted-identity counterpart: `resumeSessionId`, `parentAgent`, `agentOptions`, `signal`, and `setup`. The `setup` callback (`AgentSetup`) receives `(agentCtx, agent)` while both ids are still unpublished: the context owns scoped registrations, while the explicit Agent supplies the exact child Session without a reverse property on the Context. Everything registered through `agentCtx` exists before `agent/created` and the first prompt assembly. Setup may return a synchronous commit invoked immediately before publication; a setup rejection, commit throw, or owner disposal rolls the transaction back without publishing either id. +`CreateAgentOptions` carries the shared identity and everything a fresh agent needs before publication: an optional live `parentAgent`, session metadata (`meta` — validated `cwd`, fork lineage, the `isSeeded` marker, origin classification, delegation depth, and `agentPreset`), the exact fork cut in sibling field `inheritedEventCount`, an optional `seed` replay prefix, per-agent `AgentOptions`, a creation-only cancellation `signal`, and `setup`. `ResumeAgentOptions` is the persisted-identity counterpart: `resumeSessionId`, `parentAgent`, `agentOptions`, `signal`, and `setup`. The `setup` callback (`AgentSetup`) receives `(agentCtx, agent)` after Session store entry and completed `session/created`, before Agent registration: the context owns scoped registrations, while the explicit Agent supplies the exact child Session without a reverse property on the Context. Everything registered through `agentCtx` exists before `agent/created` and the first prompt assembly. Setup may return a synchronous commit invoked immediately before publication; a setup rejection, commit throw, or owner disposal unwinds the transaction, removes the Session, and preserves restored pending input and already stored events. `AgentFactory` is the creation interface behind the registry: the loop registers its factory via `ctx.agents.setFactory()`, so consumers use `ctx.agents` without depending on the concrete loop package. A runtime child creator sets `options.parentAgent`; the registry passes the options and caller Context to the factory without deriving one from the other. The exact `create`/`resume` signatures and rollback contracts are in the [generated section](#ctxagents--agentregistry) below. diff --git a/docs/subsystems/core.zh.md b/docs/subsystems/core.zh.md index 597cbd848f..db4bb206f5 100644 --- a/docs/subsystems/core.zh.md +++ b/docs/subsystems/core.zh.md @@ -48,7 +48,7 @@ interface AgentHandle { } ``` -`CreateAgentOptions` 携带共享标识以及新 agent 发布前所需的一切:可选的存活 `parentAgent`、会话元数据(`meta`——已校验的 `cwd`、fork 谱系、`isSeeded` 标记、来源分类、委派深度与 `agentPreset`)、同级字段 `inheritedEventCount` 所表示的精确 fork cut、可选的 `seed` 回放前缀、按 agent 的 `AgentOptions`、仅创建期有效的取消 `signal`,以及 `setup`。`ResumeAgentOptions` 是持久标识的对应项:`resumeSessionId`、`parentAgent`、`agentOptions`、`signal` 与 `setup`。`setup` 回调(`AgentSetup`)在两个 id 均未发布时接收 `(agentCtx, agent)`:上下文拥有作用域注册,显式 Agent 提供确切的子 Session,Context 无需反向属性。凡经 `agentCtx` 注册的内容都先于 `agent/created` 与第一次提示词组装存在。Setup 可以返回在发布前一刻调用的同步 commit;setup 拒绝、commit 抛出或所有者 dispose(资源释放)都会回滚事务,两个 id 均不发布。 +`CreateAgentOptions` 携带共享标识以及新 agent 发布前所需的一切:可选的存活 `parentAgent`、会话元数据(`meta`——已校验的 `cwd`、fork 谱系、`isSeeded` 标记、来源分类、委派深度与 `agentPreset`)、同级字段 `inheritedEventCount` 所表示的精确 fork cut、可选的 `seed` 回放前缀、按 agent 的 `AgentOptions`、仅创建期有效的取消 `signal`,以及 `setup`。`ResumeAgentOptions` 是持久标识的对应项:`resumeSessionId`、`parentAgent`、`agentOptions`、`signal` 与 `setup`。`setup` 回调(`AgentSetup`)在 Session 入库且 `session/created` 完成后、Agent 注册前接收 `(agentCtx, agent)`:上下文拥有作用域注册,显式 Agent 提供确切的子 Session,Context 无需反向属性。凡经 `agentCtx` 注册的内容都先于 `agent/created` 与第一次提示词组装存在。Setup 可以返回在发布前一刻调用的同步 commit;setup 拒绝、commit 抛出或所有者 dispose(资源释放)都会撤销事务并移除 Session,同时保留恢复出的待处理输入及已存储事件。 `AgentFactory` 是注册表背后的创建接口:循环经 `ctx.agents.setFactory()` 注册其工厂,因此消费方使用 `ctx.agents` 时无需依赖具体循环包。运行时子 Agent 的创建方设置 `options.parentAgent`;注册表把 options 与调用方 Context 传给工厂,不从其中一项推导另一项。确切的 `create`/`resume` 签名及回滚约定见下方[生成区块](#ctxagents--agentregistry)。 diff --git a/docs/subsystems/plan.i18n.yaml b/docs/subsystems/plan.i18n.yaml index a55599bd51..5e92dac5a5 100644 --- a/docs/subsystems/plan.i18n.yaml +++ b/docs/subsystems/plan.i18n.yaml @@ -15,8 +15,8 @@ en: ee04468005fae8e1 zh: 1347d554102951f2 /plan-mode/the-exit-tool-and-the-plan-command: - en: b5bbc440552d7ade - zh: 17fb1cfed1bc48ef + en: 32ecfb7086dd1578 + zh: 0aaeaa69bb63f255 /plan-mode/the-service: - en: 07c3eec12e0dc75c - zh: 183d73f6672e2c5a + en: f3e6d5a7fe0b67f0 + zh: 774cc97e493991fa diff --git a/docs/subsystems/plan.md b/docs/subsystems/plan.md index 68e982ec34..a37207d868 100644 --- a/docs/subsystems/plan.md +++ b/docs/subsystems/plan.md @@ -30,13 +30,13 @@ A missing, blank, or non-string `section` and any unknown key fail at plugin loa ## The exit tool and the `/plan` command -[`exit_plan_mode`](../tool-catalog.md#deepseek-aidsh-plan-mode) stays registered while plan mode is inactive, so entering or leaving plan mode changes only the prompt section, never the request tool catalog; execution outside plan mode fails. In plan mode it requires a complete markdown plan starting with a `#` heading and presents it for review through the [user-questions seam](user-questions.md). Approval returns `{ approved: true }` and records a silent (non-narrated) pending exit that is appended at the next accepted in-turn pre-step. Plan guidance therefore remains active for the rest of the assistant's current tool batch, and the tool result itself reports the transition. Keep-planning is a failed call carrying the user's feedback, so the model revises and presents again. A dismissed review returns `{ approved: false }` and concludes the turn, so plan mode stays active until the user's next message. A missing interaction channel and a service reload during review also fail the call rather than silently leaving plan mode. +[`exit_plan_mode`](../tool-catalog.md#deepseek-aidsh-plan-mode) is disclosed progressively: it is admitted from the first step whose selected plan state is active and stays admitted for the rest of the Session, so the first plan-mode entry adds it to the request tool declarations and later transitions change only the plan guidance. Native and PTC execution use the same admitted set; a call before the first entry returns `UNKNOWN_TOOL`, and a call while plan mode is not committed fails. In plan mode it requires a complete markdown plan starting with a `#` heading and presents it for review through the [user-questions seam](user-questions.md). Approval returns `{ approved: true }` and records a silent (non-narrated) pending exit that is appended at the next accepted in-turn pre-step. Plan guidance therefore remains active for the rest of the assistant's current tool batch, and the tool result itself reports the transition. Keep-planning is a failed call carrying the user's feedback, so the model revises and presents again. A dismissed review returns `{ approved: false }` and concludes the turn, so plan mode stays active until the user's next message. A missing interaction channel and a service reload during review also fail the call rather than silently leaving plan mode. When [`ctx.commands`](commands.md) is composed, the plugin registers `/plan [off|message]`: bare `/plan` selects plan mode, any other non-empty message selects it and then submits the text through `agent.steer()` so it becomes the next step's ordinary logged user message under plan guidance, and the exact argument `off` selects inactive, which also cancels a pending entry before it is appended and becomes visible to a request. ## The service -`ctx.planMode` owns the logged plan state, applies and narrates selected state at step start, and owns the `plan:policy` section, the `/plan` command, and the stable exit tool; `get`/`set` signatures are in the generated [service catalog](#ctxplanmode--planmodecontroller). +`ctx.planMode` owns the logged plan state, applies and narrates selected state at step start, and owns the `plan:policy` section, the `/plan` command, and the conditional exit tool; `get`/`set` signatures are in the generated [service catalog](#ctxplanmode--planmodecontroller). @@ -50,7 +50,7 @@ Generated from source by `scripts/gen-cordis-catalog.ts` (verified fresh by `pnp ### `ctx.planMode` — `PlanModeController` -`ctx.planMode`: owns logged plan state, applies and narrates selected state at step start, the `plan:policy` section, the `/plan` command, and the stable exit tool. Client carriers expose the projection's cropped `{ active, pending }` view. Agent prompt assembly fails while the projection reader is not ready; callers must await plugin activation before running an agent. +`ctx.planMode`: owns logged plan state, applies and narrates selected state at step start, the `plan:policy` section, the `/plan` command, and the conditional exit tool. Client carriers expose the projection's cropped `{ active, pending }` view. Agent prompt assembly fails while the projection reader is not ready; callers must await plugin activation before running an agent. ```ts cordis-catalog /** diff --git a/docs/subsystems/plan.zh.md b/docs/subsystems/plan.zh.md index 25c31455ad..8f45d70c5b 100644 --- a/docs/subsystems/plan.zh.md +++ b/docs/subsystems/plan.zh.md @@ -30,13 +30,13 @@ interface PlanModeConfig { ## 退出工具与 `/plan` 命令 -[`exit_plan_mode`](../tool-catalog.zh.md#deepseek-aidsh-plan-mode) 在计划模式未激活时仍保持注册,因此进入或离开计划模式只改变提示词段落,绝不改变请求的工具目录;在计划模式之外执行会失败。在计划模式中,它要求一份以 `#` 标题开头的完整 markdown 计划,并通过[用户交互 seam](user-questions.zh.md) 呈交评审。批准返回 `{ approved: true }`,并记录一个静默(不叙述)的待生效退出,由下一个被接受的轮内 pre-step 追加。因此,计划指引在 assistant 当前这批工具调用的剩余部分继续生效,而工具结果本身会报告这次转换。「继续规划」则是一次携带用户反馈的失败调用,模型据此修订并再次呈交。放弃评审返回 `{ approved: false }` 并结束当前轮次,计划模式保持激活,直到用户发出下一条消息。评审期间交互通道缺失或服务重载同样使调用失败,而不是静默离开计划模式。 +[`exit_plan_mode`](../tool-catalog.zh.md#deepseek-aidsh-plan-mode) 采用渐进式披露:从已选计划状态首次为激活的步骤起准入,并在会话剩余部分保持准入,因此首次进入计划模式时它进入请求的工具声明,之后的切换只改变计划指引。原生与 PTC 执行使用同一准入集合;首次进入之前调用返回 `UNKNOWN_TOOL`,计划模式未提交时调用会失败。在计划模式中,它要求一份以 `#` 标题开头的完整 markdown 计划,并通过[用户交互 seam](user-questions.zh.md) 呈交评审。批准返回 `{ approved: true }`,并记录一个静默(不叙述)的待生效退出,由下一个被接受的轮内 pre-step 追加。因此,计划指引在 assistant 当前这批工具调用的剩余部分继续生效,而工具结果本身会报告这次转换。「继续规划」则是一次携带用户反馈的失败调用,模型据此修订并再次呈交。放弃评审返回 `{ approved: false }` 并结束当前轮次,计划模式保持激活,直到用户发出下一条消息。评审期间交互通道缺失或服务重载同样使调用失败,而不是静默离开计划模式。 当 [`ctx.commands`](commands.zh.md) 被组合时,插件注册 `/plan [off|message]`:单独的 `/plan` 选择计划模式;任何其他非空消息先选择计划模式,再通过 `agent.steer()` 提交该文本,使其在计划指引下成为下一步骤的普通已记录用户消息;确切参数 `off` 选择未激活,这还会在待生效条目被追加并对请求可见之前将其取消。 ## 服务 -`ctx.planMode` 拥有已记录的计划状态,在步骤开始时应用并叙述选中的状态,还拥有 `plan:policy` 段落、`/plan` 命令和稳定注册的退出工具;`get`/`set` 签名见生成的[服务目录](#ctxplanmode--planmodecontroller)。 +`ctx.planMode` 拥有已记录的计划状态,在步骤开始时应用并叙述选中的状态,还拥有 `plan:policy` 段落、`/plan` 命令和按条件准入的退出工具;`get`/`set` 签名见生成的[服务目录](#ctxplanmode--planmodecontroller)。 @@ -50,7 +50,7 @@ Generated from source by `scripts/gen-cordis-catalog.ts` (verified fresh by `pnp ### `ctx.planMode` — `PlanModeController` -`ctx.planMode`: owns logged plan state, applies and narrates selected state at step start, the `plan:policy` section, the `/plan` command, and the stable exit tool. Client carriers expose the projection's cropped `{ active, pending }` view. Agent prompt assembly fails while the projection reader is not ready; callers must await plugin activation before running an agent. +`ctx.planMode`: owns logged plan state, applies and narrates selected state at step start, the `plan:policy` section, the `/plan` command, and the conditional exit tool. Client carriers expose the projection's cropped `{ active, pending }` view. Agent prompt assembly fails while the projection reader is not ready; callers must await plugin activation before running an agent. ```ts cordis-catalog /** diff --git a/docs/subsystems/session.md b/docs/subsystems/session.md index 4933734d57..e9369b0702 100644 --- a/docs/subsystems/session.md +++ b/docs/subsystems/session.md @@ -578,6 +578,9 @@ declare class Session { * 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. + * Independent Sessions append without notifying store observers. Once a store + * prepares or enters the instance, writes require a completed creation + * announcement and remain disabled after removal. * * @param type - The event type (key of {@link SessionEventMap}). * @param data - The event payload; must be JSON-serializable. @@ -593,7 +596,9 @@ declare class Session { * @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 + * @throws if a store-owned Session is unentered or its creation announcement + * has not completed, or 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 @@ -703,8 +708,9 @@ interface TurnEndReasonMap { blocked: { kind: 'blocked' } /** * The turn failed. `error` is always a structured failure: the `LlmError` - * facts verbatim, or `{ message: errorChain(error), code: 'UNKNOWN' }` - * flattened from any other error. + * facts verbatim, or `{ message: errorChain(error), code }` flattened from + * any other error, where `code` is `TOOL_ACTIVATION_FAILED` for a failed + * tool condition and `UNKNOWN` otherwise. */ error: { kind: 'error'; error: LlmFailure } /** At least one step reached its output-token ceiling, even if a plugin continued the turn. */ @@ -1050,7 +1056,7 @@ create(id?: SessionId, options?: CreateSessionOptions): Session * `eventState`, every seed event is either independently owned or any * shared value is deeply frozen; {@link Session.fromRestore} validates and * adopts those values without copying or freezing them. - * @returns the constructed session, NOT yet in the store. + * @returns the store-owned session, not yet entered and read-only until announced. * @throws if a session with `id` already exists, metadata is not a plain * lossless-JSON record with valid scalar fields, or `meta.cwd` is a * non-absolute path. @@ -1058,8 +1064,9 @@ create(id?: SessionId, options?: CreateSessionOptions): Session prepare(id?: SessionId, options?: PrepareSessionOptions): Session /** - * Enter a {@link prepare}d session into the store: install the module-private - * append publication hooks and add it to the store. Returns the DETACH + * Enter a session into the store: install the module-private + * append publication hooks and add it to the store. Writes remain disabled + * until {@link announce} completes successfully. Returns the DETACH * disposer (hooks + store removal). Does NOT emit `session/created` — * the caller yields this disposer inside its effect and THEN calls * {@link announce}, so a throwing `session/created` listener rolls the attach @@ -1073,7 +1080,7 @@ prepare(id?: SessionId, options?: PrepareSessionOptions): Session * the two back-to-back so they never trip this, but the public API cannot * assume that. * - * @param session - a {@link prepare}d session not yet in the store. + * @param session - an unentered session; independent instances become store-owned. * @returns the detach disposer (publication hooks + store removal). When called from * a synchronous `session/created` listener, removal and disposal wait until * that creation dispatch unwinds. @@ -1084,7 +1091,9 @@ enter(session: Session): () => void /** Emit `session/created` exactly once for an {@link enter}ed session (with * the carrier {@link enter} captured). Separate from {@link enter} so the * caller can yield the detach disposer first (rollback safety — see - * {@link enter}). + * {@link enter}). The Session remains read-only throughout synchronous + * dispatch; successful completion enables appends. A failed announcement + * leaves it read-only and cannot be retried. * @param session - the entered session to announce to listeners. * @throws if the session is not live or its announcement already began, * including a reentrant call from a creation listener. */ @@ -1250,12 +1259,14 @@ Source: [`packages/api/session-controller/src/types.ts`](../../packages/api/sess #### `session/created` — emit -Creation announcement during session publication. A synchronous throw vetoes and rolls back with a paired disposal; detach requested during dispatch is deferred. A returned-promise rejection is logged but cannot retroactively veto this synchronous boundary. Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only sessions entered through that agent's context. +Read-only creation announcement after store entry. New events reject until every synchronous listener has returned successfully. A synchronous throw vetoes creation and rolls back with a paired disposal; detach requested during dispatch is deferred. A returned-promise rejection is logged but cannot retroactively veto this synchronous boundary. Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only sessions entered through that agent's context. ```ts cordis-catalog /** - * Creation announcement during session publication. A synchronous throw vetoes and rolls - * back with a paired disposal; detach requested during dispatch is deferred. + * Read-only creation announcement after store entry. + * New events reject until every synchronous listener has returned successfully. + * A synchronous throw vetoes creation and rolls back with a paired disposal; + * detach requested during dispatch is deferred. * A returned-promise rejection is logged but cannot retroactively veto this * synchronous boundary. * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners diff --git a/docs/subsystems/session.zh.md b/docs/subsystems/session.zh.md index a3e5446b61..7971f5e7fd 100644 --- a/docs/subsystems/session.zh.md +++ b/docs/subsystems/session.zh.md @@ -580,6 +580,9 @@ declare class Session { * 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. + * Independent Sessions append without notifying store observers. Once a store + * prepares or enters the instance, writes require a completed creation + * announcement and remain disabled after removal. * * @param type - The event type (key of {@link SessionEventMap}). * @param data - The event payload; must be JSON-serializable. @@ -595,7 +598,9 @@ declare class Session { * @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 + * @throws if a store-owned Session is unentered or its creation announcement + * has not completed, or 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 @@ -707,8 +712,9 @@ interface TurnEndReasonMap { blocked: { kind: 'blocked' } /** * The turn failed. `error` is always a structured failure: the `LlmError` - * facts verbatim, or `{ message: errorChain(error), code: 'UNKNOWN' }` - * flattened from any other error. + * facts verbatim, or `{ message: errorChain(error), code }` flattened from + * any other error, where `code` is `TOOL_ACTIVATION_FAILED` for a failed + * tool condition and `UNKNOWN` otherwise. */ error: { kind: 'error'; error: LlmFailure } /** At least one step reached its output-token ceiling, even if a plugin continued the turn. */ @@ -1054,7 +1060,7 @@ create(id?: SessionId, options?: CreateSessionOptions): Session * `eventState`, every seed event is either independently owned or any * shared value is deeply frozen; {@link Session.fromRestore} validates and * adopts those values without copying or freezing them. - * @returns the constructed session, NOT yet in the store. + * @returns the store-owned session, not yet entered and read-only until announced. * @throws if a session with `id` already exists, metadata is not a plain * lossless-JSON record with valid scalar fields, or `meta.cwd` is a * non-absolute path. @@ -1062,8 +1068,9 @@ create(id?: SessionId, options?: CreateSessionOptions): Session prepare(id?: SessionId, options?: PrepareSessionOptions): Session /** - * Enter a {@link prepare}d session into the store: install the module-private - * append publication hooks and add it to the store. Returns the DETACH + * Enter a session into the store: install the module-private + * append publication hooks and add it to the store. Writes remain disabled + * until {@link announce} completes successfully. Returns the DETACH * disposer (hooks + store removal). Does NOT emit `session/created` — * the caller yields this disposer inside its effect and THEN calls * {@link announce}, so a throwing `session/created` listener rolls the attach @@ -1077,7 +1084,7 @@ prepare(id?: SessionId, options?: PrepareSessionOptions): Session * the two back-to-back so they never trip this, but the public API cannot * assume that. * - * @param session - a {@link prepare}d session not yet in the store. + * @param session - an unentered session; independent instances become store-owned. * @returns the detach disposer (publication hooks + store removal). When called from * a synchronous `session/created` listener, removal and disposal wait until * that creation dispatch unwinds. @@ -1088,7 +1095,9 @@ enter(session: Session): () => void /** Emit `session/created` exactly once for an {@link enter}ed session (with * the carrier {@link enter} captured). Separate from {@link enter} so the * caller can yield the detach disposer first (rollback safety — see - * {@link enter}). + * {@link enter}). The Session remains read-only throughout synchronous + * dispatch; successful completion enables appends. A failed announcement + * leaves it read-only and cannot be retried. * @param session - the entered session to announce to listeners. * @throws if the session is not live or its announcement already began, * including a reentrant call from a creation listener. */ @@ -1254,12 +1263,14 @@ Source: [`packages/api/session-controller/src/types.ts`](../../packages/api/sess #### `session/created` — emit -Creation announcement during session publication. A synchronous throw vetoes and rolls back with a paired disposal; detach requested during dispatch is deferred. A returned-promise rejection is logged but cannot retroactively veto this synchronous boundary. Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only sessions entered through that agent's context. +Read-only creation announcement after store entry. New events reject until every synchronous listener has returned successfully. A synchronous throw vetoes creation and rolls back with a paired disposal; detach requested during dispatch is deferred. A returned-promise rejection is logged but cannot retroactively veto this synchronous boundary. Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only sessions entered through that agent's context. ```ts cordis-catalog /** - * Creation announcement during session publication. A synchronous throw vetoes and rolls - * back with a paired disposal; detach requested during dispatch is deferred. + * Read-only creation announcement after store entry. + * New events reject until every synchronous listener has returned successfully. + * A synchronous throw vetoes creation and rolls back with a paired disposal; + * detach requested during dispatch is deferred. * A returned-promise rejection is logged but cannot retroactively veto this * synchronous boundary. * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners diff --git a/docs/subsystems/system-prompt.md b/docs/subsystems/system-prompt.md index c87334dcd2..ee803c1dfc 100644 --- a/docs/subsystems/system-prompt.md +++ b/docs/subsystems/system-prompt.md @@ -193,12 +193,12 @@ refreshContext(assembly: PromptAssembly, context: AssembleContext = {}): PromptA /** * Assemble global and scoped providers, detach tool parameters, apply - * canonical ordering, then run the assembly waterfall. Scoped sections and - * variables shadow globals. The returned waterfall value is authoritative - * except that an effective complete section is restored afterwards as the - * sole prompt section. - * @param context - the optional scope and plugin-defined assembly fields. - * @returns the post-waterfall assembly with any complete prompt enforced. + * canonical ordering, then run the presentation waterfall. Scoped sections + * and variables shadow globals. The waterfall's text is authoritative except + * that an effective complete section is restored afterwards as the sole + * prompt section; tool declarations stay provider-owned. + * @param context - the optional scope, step tool set, and plugin-defined assembly fields. + * @returns the post-waterfall assembly with ordered tool declarations and any complete prompt enforced. */ async assemble(context: AssembleContext = {}): Promise ``` @@ -213,13 +213,13 @@ Source: [`packages/core/system-prompt/src/index.ts`](../../packages/core/system- #### `system-prompt/assemble` — waterfall -Expert waterfall over the assembled sections, contexts, tools, and variables. Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): scoped listeners receive only that scope's assemblies. The returned value is authoritative. A supplied signal controls only this explicit assembly request and must not be retained to control later turns. A registered complete section is restored after this waterfall, so listeners cannot add to or replace that scope's system prompt. +Presentation waterfall over assembled sections, contexts, and variables. Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): scoped listeners receive only that scope's assemblies. The returned text is authoritative; tool declarations remain provider-owned. A supplied signal controls only this explicit assembly request and must not be retained to control later turns. A registered complete section is restored after this waterfall, so listeners cannot add to or replace that scope's system prompt. ```ts cordis-catalog /** - * Expert waterfall over the assembled sections, contexts, tools, and variables. + * Presentation waterfall over assembled sections, contexts, and variables. * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): scoped listeners - * receive only that scope's assemblies. The returned value is authoritative. + * receive only that scope's assemblies. The returned text is authoritative; tool declarations remain provider-owned. * A supplied signal controls only this explicit assembly request and must not * be retained to control later turns. A registered complete section is * restored after this waterfall, so listeners cannot add to or replace @@ -228,7 +228,7 @@ Expert waterfall over the assembled sections, contexts, tools, and variables. Sc * @param context - the caller's per-assembly context. * @mode waterfall */ -'system-prompt/assemble'(this: Scoped, assembly: PromptAssembly, context: AssembleContext, next: () => Promise): Promise +'system-prompt/assemble'(this: Scoped, assembly: PromptPresentation, context: AssembleContext, next: () => Promise): Promise ``` Types: [Scoped](scope.md) diff --git a/docs/subsystems/system-prompt.zh.md b/docs/subsystems/system-prompt.zh.md index 6ca4ca97e8..fad3105e64 100644 --- a/docs/subsystems/system-prompt.zh.md +++ b/docs/subsystems/system-prompt.zh.md @@ -193,12 +193,12 @@ refreshContext(assembly: PromptAssembly, context: AssembleContext = {}): PromptA /** * Assemble global and scoped providers, detach tool parameters, apply - * canonical ordering, then run the assembly waterfall. Scoped sections and - * variables shadow globals. The returned waterfall value is authoritative - * except that an effective complete section is restored afterwards as the - * sole prompt section. - * @param context - the optional scope and plugin-defined assembly fields. - * @returns the post-waterfall assembly with any complete prompt enforced. + * canonical ordering, then run the presentation waterfall. Scoped sections + * and variables shadow globals. The waterfall's text is authoritative except + * that an effective complete section is restored afterwards as the sole + * prompt section; tool declarations stay provider-owned. + * @param context - the optional scope, step tool set, and plugin-defined assembly fields. + * @returns the post-waterfall assembly with ordered tool declarations and any complete prompt enforced. */ async assemble(context: AssembleContext = {}): Promise ``` @@ -213,13 +213,13 @@ Source: [`packages/core/system-prompt/src/index.ts`](../../packages/core/system- #### `system-prompt/assemble` — waterfall -Expert waterfall over the assembled sections, contexts, tools, and variables. Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): scoped listeners receive only that scope's assemblies. The returned value is authoritative. A supplied signal controls only this explicit assembly request and must not be retained to control later turns. A registered complete section is restored after this waterfall, so listeners cannot add to or replace that scope's system prompt. +Presentation waterfall over assembled sections, contexts, and variables. Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): scoped listeners receive only that scope's assemblies. The returned text is authoritative; tool declarations remain provider-owned. A supplied signal controls only this explicit assembly request and must not be retained to control later turns. A registered complete section is restored after this waterfall, so listeners cannot add to or replace that scope's system prompt. ```ts cordis-catalog /** - * Expert waterfall over the assembled sections, contexts, tools, and variables. + * Presentation waterfall over assembled sections, contexts, and variables. * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): scoped listeners - * receive only that scope's assemblies. The returned value is authoritative. + * receive only that scope's assemblies. The returned text is authoritative; tool declarations remain provider-owned. * A supplied signal controls only this explicit assembly request and must not * be retained to control later turns. A registered complete section is * restored after this waterfall, so listeners cannot add to or replace @@ -228,7 +228,7 @@ Expert waterfall over the assembled sections, contexts, tools, and variables. Sc * @param context - the caller's per-assembly context. * @mode waterfall */ -'system-prompt/assemble'(this: Scoped, assembly: PromptAssembly, context: AssembleContext, next: () => Promise): Promise +'system-prompt/assemble'(this: Scoped, assembly: PromptPresentation, context: AssembleContext, next: () => Promise): Promise ``` Types: [Scoped](scope.zh.md) diff --git a/docs/subsystems/tools.i18n.yaml b/docs/subsystems/tools.i18n.yaml index b05b723c74..f35d7ae166 100644 --- a/docs/subsystems/tools.i18n.yaml +++ b/docs/subsystems/tools.i18n.yaml @@ -14,6 +14,9 @@ /tools/toolrestriction-one-scope-s-live-filter-over-what-it-inherits: en: 8c3fc4ca26f7e314 zh: 2e27263cb25243b9 +/tools/conditional-activation-step-owned-admission: + en: 472eefe8fab01e57 + zh: 0b98e74f87a6c9c0 /tools/executors-and-raw-call-batches: en: 14522295539ea2fb zh: 572c462f2c6b70ad diff --git a/docs/subsystems/tools.md b/docs/subsystems/tools.md index bff827d584..e94206a685 100644 --- a/docs/subsystems/tools.md +++ b/docs/subsystems/tools.md @@ -177,6 +177,50 @@ interface ToolRestriction { } ``` +## Conditional activation — step-owned admission + +A registration may carry a `when` condition. AgentLoop calls `ctx.tools.resolve()` once per proposed step with the captured model selection; the returned set decides that step's tool declarations, executor sections, and every call in its batch, including PTC program subcalls. `ctx.tools.executable()` applies the set at execution and, without one, excludes conditional registrations. A same-name replacement or a new restriction stops unstarted calls from using an admitted registration, and the loop disposes the set once the step's batch settles. + +```ts type-equiv +/** Inputs for a tool's step-time activation condition. */ +interface ToolActivationContext { + /** Agent preparing the step. */ + readonly agent: Agent + /** Provider, model, and optional reasoning effort captured for the step. */ + readonly modelSelection: Readonly + /** Cancellation of step preparation; asynchronous conditions must observe it. */ + readonly signal: AbortSignal +} +``` + +```ts type-equiv +/** Lifecycle-owned conditions for a registered tool. */ +interface ToolRegistrationOptions { + /** + * Decide whether the step's requests may call the tool. Omission enables + * it. False excludes it from both declarations and dispatch; rejection fails + * step preparation. Conditions must not mutate registrations or start tool work. + * @param context - preparing agent, captured model selection, and cancellation signal. + * @returns whether the tool participates in this step. + */ + readonly when?: (context: ToolActivationContext) => boolean | Promise +} +``` + +```ts type-equiv +/** One step's admitted registrations, also used by nested PTC calls. */ +interface ResolvedToolSet { + /** Close admission after the step's tool batch settles. */ + dispose(): void + /** + * Read admitted registrations that remain visible in their original scope. + * @param scope - exact requesting agent; another scope is never admitted. + * @returns original definitions excluding removed or restricted registrations. + */ + view(scope: ScopeKey | undefined): ReadonlyMap +} +``` + ## Executors and raw call batches `ctx.tools.execute()` delegates a complete raw model-call batch to the nearest scoped executor. The service selects the current provider when each batch starts; prompt assembly returns only model input. `agent` is absent for standalone service calls; `log` is absent for programmatic calls outside a model step, such as initialization hooks. An Agent without `log` still scopes tool access but produces no root call/result events. Tool-owned events may still use its Session. @@ -202,6 +246,11 @@ interface ToolBatchInput { * Undefined for standalone calls outside an Agent, such as a service invocation. */ readonly agent?: Agent + /** + * Step admission for every call in the batch, including program subcalls. + * Undefined admits only unconditional registrations. + */ + readonly toolSet?: ResolvedToolSet /** * Committed model step receiving root call/result events; requires `agent`. * Undefined when `agent` is absent or for calls outside a model response, such @@ -288,6 +337,8 @@ interface ToolExecutionInput { readonly arguments: unknown /** The agent on whose behalf the call runs (set by the agent loop). */ readonly agent?: Agent + /** Step admission shared by Native and PTC dispatch. Conditional tools require it. */ + readonly toolSet?: ResolvedToolSet /** * Opaque token of the enclosing transport execution, when one exists. PTC * mode sets this on SDK sub-dispatches so commit-style observers can wait for @@ -594,9 +645,10 @@ Concrete tool registry and scoped executor dispatcher. * 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 - tool schema, execution, and optional finalization/presentation callbacks. + * @param options - optional step-time activation condition. * @returns the exact disposer that unregisters the tool. */ -register(definition: ToolDefinition): () => void +register(definition: ToolDefinition, options: ToolRegistrationOptions = {}): () => void /** * Restrict global tools for the calling agent scope. Empty filters, unknown @@ -614,24 +666,46 @@ restrict(filter: ToolRestriction): () => void * actually executed. * @param name - the tool name as registered. * @param scope - the viewing scope (the agent); omitted = the global view. + * @param toolSet - step admission; omit only to inspect registered definitions. * @returns the definition the scope resolves, or undefined when none is visible. */ -get(name: string, scope?: ScopeKey): ToolDefinition | undefined +get(name: string, scope?: ScopeKey, toolSet?: ResolvedToolSet): ToolDefinition | undefined + +/** + * Resolve the definition a call may execute. With a step's admitted set, the + * set decides; without one, conditional registrations are unavailable. + * @param name - the tool name as registered. + * @param scope - the calling agent; omitted = the global view. + * @param toolSet - step admission, or omitted for a call outside a model step. + * @returns the executable definition, or undefined when the call must fail as `UNKNOWN_TOOL`. + */ +executable(name: string, scope?: ScopeKey, toolSet?: ResolvedToolSet): ToolDefinition | undefined + +/** + * Resolve conditions once for this step without changing shared registrations. + * Cancellation or a rejected condition publishes no partial selection. Removed + * registrations cannot be restored by a late condition result. + * @param context - preparing agent, captured model selection, and cancellation. + * @returns the complete selection; the caller disposes it after its tool batch settles. + */ +async resolve(context: ToolActivationContext): Promise /** * Read the visible capability definitions for descriptions and program bindings. * @param scope - viewing Agent or preset; omitted selects the global view. - * @returns definitions after scoped shadowing and restrictions. + * @param toolSet - step admission; omit only to inspect registered definitions. + * @returns definitions after scoped shadowing and restrictions, limited to the step's admission when given. */ -definitions(scope?: ScopeKey): readonly ToolDefinition[] +definitions(scope?: ScopeKey, toolSet?: ResolvedToolSet): readonly ToolDefinition[] /** * Project visible definitions onto the allowlisted model-facing schema fields, * excluding execution and presentation callbacks. * @param scope - the viewing scope (the agent); omitted = the global view. + * @param toolSet - step admission, or omitted for registered-definition inspection. * @returns one deep-cloned schema per visible tool. */ -schemas(scope?: ScopeKey): ToolSchema[] +schemas(scope?: ScopeKey, toolSet?: ResolvedToolSet): ToolSchema[] /** * Provide the executor for the calling scope; an unscoped contribution is the deployment default. diff --git a/docs/subsystems/tools.zh.md b/docs/subsystems/tools.zh.md index 53dbd43fb7..e18dfbbe5d 100644 --- a/docs/subsystems/tools.zh.md +++ b/docs/subsystems/tools.zh.md @@ -177,6 +177,50 @@ interface ToolRestriction { } ``` +## 条件准入 — 步骤拥有的准入集合 + +注册可以携带 `when` 条件。AgentLoop 为每个拟议步骤以捕获的模型选择调用一次 `ctx.tools.resolve()`;返回的集合决定该步骤的工具声明、执行器分区以及批次中的每次调用,包括 PTC 程序的子调用。`ctx.tools.executable()` 在执行时应用集合,没有集合时排除条件注册。同名替换或新的限制会阻止尚未开始的调用使用已准入的注册,步骤的批次结束后循环释放集合。 + +```ts type-equiv +/** Inputs for a tool's step-time activation condition. */ +interface ToolActivationContext { + /** Agent preparing the step. */ + readonly agent: Agent + /** Provider, model, and optional reasoning effort captured for the step. */ + readonly modelSelection: Readonly + /** Cancellation of step preparation; asynchronous conditions must observe it. */ + readonly signal: AbortSignal +} +``` + +```ts type-equiv +/** Lifecycle-owned conditions for a registered tool. */ +interface ToolRegistrationOptions { + /** + * Decide whether the step's requests may call the tool. Omission enables + * it. False excludes it from both declarations and dispatch; rejection fails + * step preparation. Conditions must not mutate registrations or start tool work. + * @param context - preparing agent, captured model selection, and cancellation signal. + * @returns whether the tool participates in this step. + */ + readonly when?: (context: ToolActivationContext) => boolean | Promise +} +``` + +```ts type-equiv +/** One step's admitted registrations, also used by nested PTC calls. */ +interface ResolvedToolSet { + /** Close admission after the step's tool batch settles. */ + dispose(): void + /** + * Read admitted registrations that remain visible in their original scope. + * @param scope - exact requesting agent; another scope is never admitted. + * @returns original definitions excluding removed or restricted registrations. + */ + view(scope: ScopeKey | undefined): ReadonlyMap +} +``` + ## 执行器与原始调用批次 `ctx.tools.execute()` 把完整的原始模型调用批次委托给最近作用域的执行器。服务在每个批次开始时选择当前提供者;提示词组装仅返回模型输入。`agent` 在独立服务调用中不存在;`log` 在模型步骤之外的程序调用(例如初始化钩子)中不存在。有 Agent 而没有 `log` 时,调用仍受该 Agent 的工具作用域约束,但不记录根调用/结果事件。工具自身的事件仍可使用 Agent 的 Session。 @@ -202,6 +246,11 @@ interface ToolBatchInput { * Undefined for standalone calls outside an Agent, such as a service invocation. */ readonly agent?: Agent + /** + * Step admission for every call in the batch, including program subcalls. + * Undefined admits only unconditional registrations. + */ + readonly toolSet?: ResolvedToolSet /** * Committed model step receiving root call/result events; requires `agent`. * Undefined when `agent` is absent or for calls outside a model response, such @@ -288,6 +337,8 @@ interface ToolExecutionInput { readonly arguments: unknown /** The agent on whose behalf the call runs (set by the agent loop). */ readonly agent?: Agent + /** Step admission shared by Native and PTC dispatch. Conditional tools require it. */ + readonly toolSet?: ResolvedToolSet /** * Opaque token of the enclosing transport execution, when one exists. PTC * mode sets this on SDK sub-dispatches so commit-style observers can wait for @@ -594,9 +645,10 @@ Concrete tool registry and scoped executor dispatcher. * 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 - tool schema, execution, and optional finalization/presentation callbacks. + * @param options - optional step-time activation condition. * @returns the exact disposer that unregisters the tool. */ -register(definition: ToolDefinition): () => void +register(definition: ToolDefinition, options: ToolRegistrationOptions = {}): () => void /** * Restrict global tools for the calling agent scope. Empty filters, unknown @@ -614,24 +666,46 @@ restrict(filter: ToolRestriction): () => void * actually executed. * @param name - the tool name as registered. * @param scope - the viewing scope (the agent); omitted = the global view. + * @param toolSet - step admission; omit only to inspect registered definitions. * @returns the definition the scope resolves, or undefined when none is visible. */ -get(name: string, scope?: ScopeKey): ToolDefinition | undefined +get(name: string, scope?: ScopeKey, toolSet?: ResolvedToolSet): ToolDefinition | undefined + +/** + * Resolve the definition a call may execute. With a step's admitted set, the + * set decides; without one, conditional registrations are unavailable. + * @param name - the tool name as registered. + * @param scope - the calling agent; omitted = the global view. + * @param toolSet - step admission, or omitted for a call outside a model step. + * @returns the executable definition, or undefined when the call must fail as `UNKNOWN_TOOL`. + */ +executable(name: string, scope?: ScopeKey, toolSet?: ResolvedToolSet): ToolDefinition | undefined + +/** + * Resolve conditions once for this step without changing shared registrations. + * Cancellation or a rejected condition publishes no partial selection. Removed + * registrations cannot be restored by a late condition result. + * @param context - preparing agent, captured model selection, and cancellation. + * @returns the complete selection; the caller disposes it after its tool batch settles. + */ +async resolve(context: ToolActivationContext): Promise /** * Read the visible capability definitions for descriptions and program bindings. * @param scope - viewing Agent or preset; omitted selects the global view. - * @returns definitions after scoped shadowing and restrictions. + * @param toolSet - step admission; omit only to inspect registered definitions. + * @returns definitions after scoped shadowing and restrictions, limited to the step's admission when given. */ -definitions(scope?: ScopeKey): readonly ToolDefinition[] +definitions(scope?: ScopeKey, toolSet?: ResolvedToolSet): readonly ToolDefinition[] /** * Project visible definitions onto the allowlisted model-facing schema fields, * excluding execution and presentation callbacks. * @param scope - the viewing scope (the agent); omitted = the global view. + * @param toolSet - step admission, or omitted for registered-definition inspection. * @returns one deep-cloned schema per visible tool. */ -schemas(scope?: ScopeKey): ToolSchema[] +schemas(scope?: ScopeKey, toolSet?: ResolvedToolSet): ToolSchema[] /** * Provide the executor for the calling scope; an unscoped contribution is the deployment default. diff --git a/docs/subsystems/web-server.i18n.yaml b/docs/subsystems/web-server.i18n.yaml index bd4c01c442..d34ca1303f 100644 --- a/docs/subsystems/web-server.i18n.yaml +++ b/docs/subsystems/web-server.i18n.yaml @@ -3,14 +3,14 @@ # After editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write docs/subsystems/web-server.md /http-server: - en: 56b268a69964f651 - zh: c8ac8f16bf58a98a + en: a4861c68f3eb0b03 + zh: a3da9f0467fdee02 /http-server/routes: - en: e949c3738a35b58f - zh: 138e3aaeb319ddc4 + en: 57adf92882ff0f77 + zh: d17992cca18cc790 /http-server/config: en: 4b162bd9f280eb06 zh: 3bea98dfee88c582 /http-server/the-service: - en: bbf84a6cd0460dc2 - zh: cc63ce45b0675c6d + en: d1922a5e809e20c3 + zh: 5c1772c81a19784c diff --git a/docs/subsystems/web-server.md b/docs/subsystems/web-server.md index c6c731343a..2420b6713b 100644 --- a/docs/subsystems/web-server.md +++ b/docs/subsystems/web-server.md @@ -2,7 +2,7 @@ English | [中文](web-server.zh.md) -[dsh-host-webserver](../../packages/host/webserver) is the browser HTTP carrier for the GUI host: one `node:http` server — `node:https` when `tls` is configured — providing `ctx.webServer`, a named-route registry, optional gzip response compression, index.html transform callbacks, and one fallback handler that a plugin may claim. It is not part of the agent loop and not a capability seam; its only harness concept is the Peer an index render speaks for, and another plugin registers every feature route, including the `/api` bridge, plugin bundles, and the HMR event stream ([layering reference](../../packages/boot/app-boot/README.md)). It serves browsers only: Electron loads the built files over `file://` and sends fetch requests through an IPC bridge instead of this server. +[dsh-host-webserver](../../packages/host/webserver) is the browser HTTP carrier for the GUI host: one `node:http` server — `node:https` when `tls` is configured — providing `ctx.webServer`, a named-route registry, optional gzip response compression, index.html transform callbacks, and one fallback, a handler or a resource, that a plugin may claim. It is not part of the agent loop and not a capability seam; its only harness concept is the Peer an index render speaks for, and another plugin registers every feature route, including the `/api` bridge, plugin bundles, and the HMR event stream ([layering reference](../../packages/boot/app-boot/README.md)). It serves browsers only: Electron loads the built files over `file://` and sends fetch requests through an IPC bridge instead of this server. Source: [`packages/host/webserver/src/index.ts`](../../packages/host/webserver/src/index.ts) @@ -24,8 +24,30 @@ interface WebRoute { } ``` +```ts type-equiv +/** + * Answers one GET or HEAD request with a Fetch response. An HTTP request + * arrives without a Peer and carries the client's headers; an in-process + * {@link WebServer.readResource} read passes the Peer its caller admitted. + */ +type WebResource = (request: Request, peer?: PeerScope) => Promise +``` + +```ts type-equiv +/** One named route answered by a resource instead of a handler. */ +interface WebResourceRoute { + kind: WebRouteKind + /** Absolute pathname, no trailing slash. */ + path: string + /** Answers HTTP GET and HEAD requests and in-process reads. */ + resource: WebResource +} +``` + Match order is fixed: exact table first, then longest matching prefix, then the registered fallback. Registration order carries no request-facing semantics — named routes are composed to be disjoint, and the fallback seat answers anything no named route claims; one owner only, a second registration throws. The shipped Web composition claims the seat with [`dsh-host-frontend-static`](../../packages/host/frontend-static/src/index.ts), the SPA dist server with locked semantics: Connection authenticates the dist root and configured index before their HTML is read; non-index assets remain public; non-GET/HEAD is 405, traversal outside the dist root is 403, existing files are served directly, absent or non-file targets are empty 404 responses, and unknown extensions ship as octet-stream. +A route or the fallback may give a resource, a function from a Fetch `Request` to a `Response`, instead of a handler. HTTP `GET` and `HEAD` requests reach it without a Peer, and `readResource(request, peer)` reads it in process for the Peer its caller admitted; a read follows the same match order but reaches only resources, so a route that returns owner-private data or performs an action stays a handler even when it answers `GET`. + ## Config @@ -81,7 +103,7 @@ No composition can bind every interface at once: the unspecified address is reje ## The service -`WebServer` (`ctx.webServer`) listens immediately on activation; a listen failure (EADDRINUSE…) rejects initialization, and the boot process reports the failed fiber. The `tls` pair is read once before the listener binds, and an unreadable, empty, or mismatched pair rejects initialization the same way instead of falling back to HTTP. `register(route)` adds one named route and returns its disposer; a duplicate `(kind, path)` throws because route patterns are a composition-level contract and a collision is a misconfiguration. Gzip wraps eligible socket-backed responses inside the server, so route handlers retain direct `ServerResponse` ownership and no response-writing API is added to the service. Existing content encodings, `Cache-Control: no-transform`, ranges, SSE, ZIP, and the packaged `.gz` Worker image remain identity responses. `collectIndexInjections(peer)` gathers structured `IndexInjection` rows over one `webserver/index-inject` emit that passes the Peer the page speaks for, and `renderIndex(html, peer)` renders them into successful root and configured index responses before applying the raw `tapIndex(transform)` escape-hatch transforms in registration order; [dsh-client-modules](../../packages/client/modules) answers the event with the boot manifest rows. `port` reads the listening port, including the port assigned by the OS when `config.port` is 0, and `protocol` reports the scheme the listener serves (`http:` or `https:`). +`WebServer` (`ctx.webServer`) listens immediately on activation; a listen failure (EADDRINUSE…) rejects initialization, and the boot process reports the failed fiber. The `tls` pair is read once before the listener binds, and an unreadable, empty, or mismatched pair rejects initialization the same way instead of falling back to HTTP. `register(route)` adds one named route and returns its disposer; a duplicate `(kind, path)` throws because route patterns are a composition-level contract and a collision is a misconfiguration. Gzip wraps eligible socket-backed responses inside the server, so handlers keep direct `ServerResponse` ownership, and a resource hands the service a `Response` to write back. Existing content encodings, `Cache-Control: no-transform`, ranges, SSE, ZIP, and the packaged `.gz` Worker image remain identity responses. `collectIndexInjections(peer)` gathers structured `IndexInjection` rows over one `webserver/index-inject` emit that passes the Peer the page speaks for, and `renderIndex(html, peer)` renders them into successful root and configured index responses before applying the raw `tapIndex(transform)` escape-hatch transforms in registration order; [dsh-client-modules](../../packages/client/modules) answers the event with the boot manifest rows. `port` reads the listening port, including the port assigned by the OS when `config.port` is 0, and `protocol` reports the scheme the listener serves (`http:` or `https:`). A request whose handling throws (a malformed %-escape hitting `decodeURIComponent`, a client dropping mid-body) is logged as a warning and answered 400 — or the socket destroyed when headers are already out — never a process exit. Disposal pairs `close()` with `closeAllConnections()` because a handler may hold its response open (SSE) and such connections never end on their own; without the force-close, teardown would hang. A TLS socket counts as a connection only after its handshake, so the server tracks raw TLS sockets beside upgraded ones and destroys both at disposal. The package never prints: the URL line belongs to the shell. Per-package operational detail, including the dev-mode bundle watch pipeline, stays in the [README](../../packages/host/webserver/README.md). @@ -180,7 +202,7 @@ Source: [`packages/bundle/web-app/src/index.ts`](../../packages/bundle/web-app/s ### `ctx.webServer` — `WebServer` -The browser HTTP carrier service. Activation loads any configured TLS material, then listens immediately; a material or listen failure rejects initialization, and the boot process reports the failed fiber. Route registration order does not affect requests because configured named routes must be distinct, and the fallback handler answers anything not yet claimed during startup with 404 until its owner registers. +The browser HTTP carrier service. Activation loads any configured TLS material, then listens immediately; a material or listen failure rejects initialization, and the boot process reports the failed fiber. Route registration order does not affect requests because configured named routes must be distinct, and a request no named route matches is answered 404 until the fallback owner registers. ```ts cordis-catalog /** @@ -194,10 +216,10 @@ getOrigin(): string /** * Register a named route. Duplicate (kind, path) throws — route patterns are * a composition-level contract, so a collision is a misconfiguration. - * @param route - kind, path, and the owning handler. + * @param route - kind, path, and the owning handler or resource. * @returns the disposer removing the route. */ -register(route: WebRoute): () => void +register(route: WebRoute | WebResourceRoute): () => void /** * Register an exact-path HTTP upgrade route. Duplicate paths throw because @@ -208,14 +230,32 @@ register(route: WebRoute): () => void registerUpgrade(route: WebUpgradeRoute): () => void /** - * Claim the fallback seat: the handler answering every request no named - * route matches (the SPA dist server in the shipped Web composition). One - * owner only — a second registration throws, because two fallbacks cannot - * compose. - * @param handler - owns the full response lifecycle of unmatched requests. + * Claim the fallback seat: the handler or resource answering every request + * no named route matches (the SPA dist server in the shipped Web + * composition). One owner only — a second registration throws, because two + * fallbacks cannot compose. + * @param fallback - a handler owning the full response lifecycle of + * unmatched requests, or `{ resource }` answering them. * @returns the disposer releasing the seat. */ -registerFallback(handler: WebRoute['handler']): () => void +registerFallback(fallback: WebRoute['handler'] | Pick): () => void + +/** + * Read the response an HTTP request for the same URL would receive, as the + * resource computes it for `peer`, without an HTTP exchange. The request + * path picks the responder by the HTTP match order — exact, longest prefix, + * then the fallback — and only a resource answers. This method checks no + * cookie, Host, or Origin: the caller admits the reader before reading. + * @param request - the read; its URL path selects the responder. + * @param peer - the Peer the read speaks for, passed to the resource. + * @returns the resource's response, without a body for HEAD as over HTTP; + * 405 with `Allow: GET, HEAD` for any other method, checked before matching, + * where over HTTP a handler route or an unmatched path answers such a + * method itself; 404 when the path matches a handler route, or reaches the + * fallback seat while it is unclaimed or holds a handler. A resource that + * throws rejects the read, where an HTTP request would receive 400. + */ +async readResource(request: Request, peer: PeerScope): Promise /** * Register a raw-HTML index transform, the escape hatch for markup no diff --git a/docs/subsystems/web-server.zh.md b/docs/subsystems/web-server.zh.md index 21a97be800..a59344ad75 100644 --- a/docs/subsystems/web-server.zh.md +++ b/docs/subsystems/web-server.zh.md @@ -2,7 +2,7 @@ [English](web-server.md) | 中文 -[dsh-host-webserver](../../packages/host/webserver) 是 GUI Host 的浏览器 HTTP 载体:一个 `node:http` 服务器——配置 `tls` 时改用 `node:https`——提供 `ctx.webServer`、具名路由注册表、可选的 gzip 响应压缩、index.html 转换回调,以及一个可由插件认领的回退处理器。它不属于 agent loop(智能体循环),也不是能力 seam;它唯一涉及的 harness 概念是 index 渲染所代表的 Peer。其他插件负责注册所有功能路由,包括 `/api` 桥接、插件 bundle 和 HMR(热模块替换)事件流([分层说明](../../packages/boot/app-boot/README.zh.md))。该服务器只服务浏览器:Electron 通过 `file://` 加载已构建文件,并经 IPC 桥接发送 fetch 请求,不使用本服务器。 +[dsh-host-webserver](../../packages/host/webserver) 是 GUI Host 的浏览器 HTTP 载体:一个 `node:http` 服务器——配置 `tls` 时改用 `node:https`——提供 `ctx.webServer`、具名路由注册表、可选的 gzip 响应压缩、index.html 转换回调,以及一个可由插件认领的回退(handler 或 resource)。它不属于 agent loop(智能体循环),也不是能力 seam;它唯一涉及的 harness 概念是 index 渲染所代表的 Peer。其他插件负责注册所有功能路由,包括 `/api` 桥接、插件 bundle 和 HMR(热模块替换)事件流([分层说明](../../packages/boot/app-boot/README.zh.md))。该服务器只服务浏览器:Electron 通过 `file://` 加载已构建文件,并经 IPC 桥接发送 fetch 请求,不使用本服务器。 源码:[`packages/host/webserver/src/index.ts`](../../packages/host/webserver/src/index.ts) @@ -24,8 +24,30 @@ interface WebRoute { } ``` +```ts type-equiv +/** + * Answers one GET or HEAD request with a Fetch response. An HTTP request + * arrives without a Peer and carries the client's headers; an in-process + * {@link WebServer.readResource} read passes the Peer its caller admitted. + */ +type WebResource = (request: Request, peer?: PeerScope) => Promise +``` + +```ts type-equiv +/** One named route answered by a resource instead of a handler. */ +interface WebResourceRoute { + kind: WebRouteKind + /** Absolute pathname, no trailing slash. */ + path: string + /** Answers HTTP GET and HEAD requests and in-process reads. */ + resource: WebResource +} +``` + 匹配顺序固定:先查 exact 表,再取最长匹配前缀,最后落到已注册的回退。注册顺序不携带任何面向请求的语义:具名路由在组合上互不相交,任何未被具名路由认领的请求都由回退席位应答;席位只有一个所有者,第二次注册会抛出异常。发布的 Web 组合用 [`dsh-host-frontend-static`](../../packages/host/frontend-static/src/index.ts) 认领席位,即遵循固定语义的 SPA dist 服务器:Connection 在读取 dist 根目录和配置 index 的 HTML 前完成认证;非 index 资产保持公开;非 GET/HEAD 返回 405,越出 dist 根目录的遍历返回 403,现有文件直接提供,缺失或不是文件的目标返回空的 404,未知扩展名按 octet-stream 发送。 +路由或回退可以用 resource——一个把 Fetch `Request` 映射为 `Response` 的函数——代替 handler。HTTP 的 `GET`、`HEAD` 请求不带 Peer 到达它,`readResource(request, peer)` 则在进程内按调用方准入的 Peer 读取它;读取遵循同样的匹配顺序但只到达 resource,因此返回 owner 私有数据或会执行操作的路由即使应答 `GET` 也保持为 handler。 + ## 配置 @@ -81,7 +103,7 @@ interface TlsConfig { ## 服务 -`WebServer`(`ctx.webServer`)在激活时立即监听;监听失败(EADDRINUSE 等)会使初始化被拒绝,启动进程会报告失败的 fiber。`tls` 证书对在监听器绑定前读取一次;文件不可读、为空或二者不匹配时同样会使初始化被拒绝,而不是回退到 HTTP。`register(route)` 添加一条具名路由并返回其 disposer;重复的 `(kind, path)` 抛出异常,因为路由模式是组合层约定,冲突即配置错误。Gzip 在服务器内部包装符合条件且基于 socket 的响应,因此 route handler 继续直接持有 `ServerResponse`,服务也不新增响应写出 API。已有内容编码、`Cache-Control: no-transform`、范围响应、SSE、ZIP 与打包后的 `.gz` Worker 镜像均保持 identity 响应。`collectIndexInjections(peer)` 经一次传入页面所代表 Peer 的 `webserver/index-inject` emit 收集结构化 `IndexInjection` 行,`renderIndex(html, peer)` 把它们渲染进成功的根路径和配置 index 响应,随后再按注册顺序应用原始的 `tapIndex(transform)` 逃生口转换;[dsh-client-modules](../../packages/client/modules) 以启动 manifest(元数据清单)行回应该事件。`port` 读取监听端口,包括 `config.port` 为 0 时操作系统分配的端口,`protocol` 则报告监听器提供的协议(`http:` 或 `https:`)。 +`WebServer`(`ctx.webServer`)在激活时立即监听;监听失败(EADDRINUSE 等)会使初始化被拒绝,启动进程会报告失败的 fiber。`tls` 证书对在监听器绑定前读取一次;文件不可读、为空或二者不匹配时同样会使初始化被拒绝,而不是回退到 HTTP。`register(route)` 添加一条具名路由并返回其 disposer;重复的 `(kind, path)` 抛出异常,因为路由模式是组合层约定,冲突即配置错误。Gzip 在服务器内部包装符合条件且基于 socket 的响应,因此 handler 继续直接持有 `ServerResponse`,resource 则把 `Response` 交给服务写回。已有内容编码、`Cache-Control: no-transform`、范围响应、SSE、ZIP 与打包后的 `.gz` Worker 镜像均保持 identity 响应。`collectIndexInjections(peer)` 经一次传入页面所代表 Peer 的 `webserver/index-inject` emit 收集结构化 `IndexInjection` 行,`renderIndex(html, peer)` 把它们渲染进成功的根路径和配置 index 响应,随后再按注册顺序应用原始的 `tapIndex(transform)` 逃生口转换;[dsh-client-modules](../../packages/client/modules) 以启动 manifest(元数据清单)行回应该事件。`port` 读取监听端口,包括 `config.port` 为 0 时操作系统分配的端口,`protocol` 则报告监听器提供的协议(`http:` 或 `https:`)。 处理过程中抛出异常的请求(畸形的 % 转义撞上 `decodeURIComponent`、客户端在请求体中途断开)会记录为警告并应答 400(响应头已发出时则销毁 socket),绝不导致进程退出。dispose(资源释放)把 `close()` 与 `closeAllConnections()` 配对使用,因为处理器可能像 SSE(Server-Sent Events)那样保持响应打开,而这类连接永远不会自行结束;没有强制关闭,拆卸就会挂起。TLS socket 只有完成握手后才计入连接,因此服务器会把原始 TLS socket 与升级后的 socket 一并跟踪,并在 dispose 时销毁两者。该包从不打印输出:URL 行归 shell 所有。逐包运维细节(含开发模式的 bundle 监视流水线)留在 [README](../../packages/host/webserver/README.zh.md) 中。 @@ -180,7 +202,7 @@ Source: [`packages/bundle/web-app/src/index.ts`](../../packages/bundle/web-app/s ### `ctx.webServer` — `WebServer` -The browser HTTP carrier service. Activation loads any configured TLS material, then listens immediately; a material or listen failure rejects initialization, and the boot process reports the failed fiber. Route registration order does not affect requests because configured named routes must be distinct, and the fallback handler answers anything not yet claimed during startup with 404 until its owner registers. +The browser HTTP carrier service. Activation loads any configured TLS material, then listens immediately; a material or listen failure rejects initialization, and the boot process reports the failed fiber. Route registration order does not affect requests because configured named routes must be distinct, and a request no named route matches is answered 404 until the fallback owner registers. ```ts cordis-catalog /** @@ -194,10 +216,10 @@ getOrigin(): string /** * Register a named route. Duplicate (kind, path) throws — route patterns are * a composition-level contract, so a collision is a misconfiguration. - * @param route - kind, path, and the owning handler. + * @param route - kind, path, and the owning handler or resource. * @returns the disposer removing the route. */ -register(route: WebRoute): () => void +register(route: WebRoute | WebResourceRoute): () => void /** * Register an exact-path HTTP upgrade route. Duplicate paths throw because @@ -208,14 +230,32 @@ register(route: WebRoute): () => void registerUpgrade(route: WebUpgradeRoute): () => void /** - * Claim the fallback seat: the handler answering every request no named - * route matches (the SPA dist server in the shipped Web composition). One - * owner only — a second registration throws, because two fallbacks cannot - * compose. - * @param handler - owns the full response lifecycle of unmatched requests. + * Claim the fallback seat: the handler or resource answering every request + * no named route matches (the SPA dist server in the shipped Web + * composition). One owner only — a second registration throws, because two + * fallbacks cannot compose. + * @param fallback - a handler owning the full response lifecycle of + * unmatched requests, or `{ resource }` answering them. * @returns the disposer releasing the seat. */ -registerFallback(handler: WebRoute['handler']): () => void +registerFallback(fallback: WebRoute['handler'] | Pick): () => void + +/** + * Read the response an HTTP request for the same URL would receive, as the + * resource computes it for `peer`, without an HTTP exchange. The request + * path picks the responder by the HTTP match order — exact, longest prefix, + * then the fallback — and only a resource answers. This method checks no + * cookie, Host, or Origin: the caller admits the reader before reading. + * @param request - the read; its URL path selects the responder. + * @param peer - the Peer the read speaks for, passed to the resource. + * @returns the resource's response, without a body for HEAD as over HTTP; + * 405 with `Allow: GET, HEAD` for any other method, checked before matching, + * where over HTTP a handler route or an unmatched path answers such a + * method itself; 404 when the path matches a handler route, or reaches the + * fallback seat while it is unclaimed or holds a handler. A resource that + * throws rejects the read, where an HTTP request would receive 400. + */ +async readResource(request: Request, peer: PeerScope): Promise /** * Register a raw-HTML index transform, the escape hatch for markup no diff --git a/docs/upgrade-guide/v0.2.1-rc.2/conditional-tools/guide.i18n.yaml b/docs/upgrade-guide/v0.2.1-rc.2/conditional-tools/guide.i18n.yaml new file mode 100644 index 0000000000..3ca37a1f2a --- /dev/null +++ b/docs/upgrade-guide/v0.2.1-rc.2/conditional-tools/guide.i18n.yaml @@ -0,0 +1,16 @@ +# Bilingual-pair consistency record for guide.md (docs/i18n/README.md): per heading +# section, a hash of its English and Chinese blocks outside code blocks and generated regions. +# After editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write docs/upgrade-guide/v0.2.1-rc.2/conditional-tools/guide.md +/: + en: 1dc343c5aa10de02 + zh: 59ac1c2052255919 +/declare-conditional-tools-through-step-admission: + en: 4edb4c80b402de77 + zh: 856160ec69c515ea +/declare-conditional-tools-through-step-admission/change: + en: e140ab052beb78ed + zh: 9603c44ae7731ab8 +/declare-conditional-tools-through-step-admission/migration: + en: 364c2a62343a608b + zh: c00ab4611b1fc4e3 diff --git a/docs/upgrade-guide/v0.2.1-rc.2/conditional-tools/guide.md b/docs/upgrade-guide/v0.2.1-rc.2/conditional-tools/guide.md new file mode 100644 index 0000000000..30d37bca41 --- /dev/null +++ b/docs/upgrade-guide/v0.2.1-rc.2/conditional-tools/guide.md @@ -0,0 +1,25 @@ +--- +kind: upgrade-guide +description: "Tool declarations come only from step-admitted registrations: `system-prompt/assemble` no longer carries tools, conditional tools need a resolved step set, and `exit_plan_mode` is declared only after a Session first enters plan mode." +--- + +# Declare conditional tools through step admission + +English | [中文](guide.zh.md) + +## Change + +`ctx.tools.register(definition, { when })` adds a synchronous or asynchronous condition. AgentLoop resolves conditions once per proposed step with `{ agent, modelSelection, signal }`, before prompt assembly and `agent/pre-step`, and uses the resulting `ResolvedToolSet` for tool declarations, Native dispatch, PTC bindings, and nested calls in that step and its retries. A false condition removes the tool from all of them; a thrown condition ends the turn with `TOOL_ACTIVATION_FAILED`. + +The `system-prompt/assemble` waterfall now receives sections, contexts, and variables (`PromptPresentation`) without a tool array, and a returned `tools` field is ignored. Plugins that removed or added tool declarations in that waterfall are affected; their removals no longer reach the request, and a listener that reads `assembly.tools` receives `undefined` and fails at runtime. + +Model tool calls run only through their step's admitted set. A call to a conditional tool without a resolved set, a call after the set is disposed, and a pending call whose registration was replaced or removed during the step return `UNKNOWN_TOOL` instead of running. Replacement applies to every tool, so a hot reload, MCP reconnect, or skill reload that re-registers a tool mid-step fails that step's unstarted calls of it. Callers that pass no set, such as the experimental `claude-code-mods` `$.tool.call`, cannot call conditional tools. + +`exit_plan_mode` is declared from the first step whose selected plan state is active and stays declared for the rest of the Session, so requests of a Session that never entered plan mode no longer list it. Existing Sessions require no format migration. + +## Migration + +1. Replace tool filtering and reads of `assembly.tools` in `system-prompt/assemble` listeners with a `when` condition on the registration; read the step's provider, model, and reasoning effort from the condition's `modelSelection`. Keep only section, context, and variable changes in the waterfall. +2. Make tool guidance follow the same admission: section callbacks pass `context.toolSet` to `ctx.tools.get()` or `ctx.tools.schemas()`. +3. For programmatic calls of conditional tools, call `ctx.tools.resolve({ agent, modelSelection, signal })`, pass the returned `toolSet` to `assemble()` and the `ctx.tools.execute()` batch, and dispose it after the batch settles. A custom executor that does not use the shared pipeline looks up each call with `ctx.tools.executable(name, agent, toolSet)`. +4. Update expectations that listed `exit_plan_mode` before a Session entered plan mode. Verify that a disabled tool is absent from the request, that calling its name returns `UNKNOWN_TOOL` without reaching the implementation, and that a failing condition ends the turn with `TOOL_ACTIVATION_FAILED`. diff --git a/docs/upgrade-guide/v0.2.1-rc.2/conditional-tools/guide.zh.md b/docs/upgrade-guide/v0.2.1-rc.2/conditional-tools/guide.zh.md new file mode 100644 index 0000000000..ee1644a36e --- /dev/null +++ b/docs/upgrade-guide/v0.2.1-rc.2/conditional-tools/guide.zh.md @@ -0,0 +1,25 @@ +--- +kind: upgrade-guide +description: "工具声明只来自步骤准入的注册:`system-prompt/assemble` 不再携带工具,条件工具需要已解析的步骤集合,`exit_plan_mode` 只在会话首次进入计划模式后声明。" +--- + +# 通过步骤准入声明条件工具 + +[English](guide.md) | 中文 + +## 变更 + +`ctx.tools.register(definition, { when })` 可以附加同步或异步条件。AgentLoop 在提示词组装与 `agent/pre-step` 之前,以 `{ agent, modelSelection, signal }` 为每个拟议步骤计算一次条件,并在该步骤及其重试中用得到的 `ResolvedToolSet` 决定工具声明、原生分发、PTC 绑定和嵌套调用。条件返回 false 时,工具从以上所有位置移除;条件抛错时,轮次以 `TOOL_ACTIVATION_FAILED` 结束。 + +`system-prompt/assemble` waterfall 现在接收不含工具数组的段落、上下文与变量(`PromptPresentation`),返回的 `tools` 字段会被忽略。在这个 waterfall 中删除或添加工具声明的插件会受到影响:它们做的删除不再进入请求;读取 `assembly.tools` 的监听器会拿到 `undefined`,并在运行时出错。 + +模型的工具调用只通过所属步骤的准入集合执行。没有已解析集合的条件工具调用、集合释放之后的调用,以及注册在步骤内被替换或移除时尚未开始的调用,都会返回 `UNKNOWN_TOOL`,不会执行。替换规则适用于所有工具,因此在步骤中途重新注册工具的热重载、MCP 重连或 skill 重载会让该步骤里这个工具尚未开始的调用失败。不传集合的调用方(例如实验性 `claude-code-mods` 的 `$.tool.call`)无法调用条件工具。 + +`exit_plan_mode` 从已选计划状态首次为激活的步骤起声明,并在会话剩余部分保持声明,因此从未进入计划模式的会话,其请求不再列出它。现有 Session 无需格式迁移。 + +## 迁移 + +1. 把 `system-prompt/assemble` 监听器中的工具过滤和对 `assembly.tools` 的读取改为注册时的 `when` 条件;从条件的 `modelSelection` 读取该步骤的提供方、模型与推理强度。waterfall 中只保留段落、上下文与变量的修改。 +2. 让工具指引跟随同一准入:段落回调把 `context.toolSet` 传给 `ctx.tools.get()` 或 `ctx.tools.schemas()`。 +3. 程序化调用条件工具时,调用 `ctx.tools.resolve({ agent, modelSelection, signal })`,把返回的 `toolSet` 传给 `assemble()` 与 `ctx.tools.execute()` 批次,并在批次结束后释放。不使用共享 pipeline 的自定义执行器用 `ctx.tools.executable(name, agent, toolSet)` 查找每次调用。 +4. 更新在会话进入计划模式之前仍列出 `exit_plan_mode` 的期望。验证被禁用的工具不出现在请求中,用其名称调用会返回 `UNKNOWN_TOOL` 且不进入实现,条件失败时轮次以 `TOOL_ACTIVATION_FAILED` 结束。 diff --git a/docs/upgrade-guide/v0.2.1-rc.2/file-drag-callbacks/guide.i18n.yaml b/docs/upgrade-guide/v0.2.1-rc.2/file-drag-callbacks/guide.i18n.yaml new file mode 100644 index 0000000000..8fd9c8bcf7 --- /dev/null +++ b/docs/upgrade-guide/v0.2.1-rc.2/file-drag-callbacks/guide.i18n.yaml @@ -0,0 +1,16 @@ +# Bilingual-pair consistency record for guide.md (docs/i18n/README.md): per heading +# section, a hash of its English and Chinese blocks outside code blocks and generated regions. +# After editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write docs/upgrade-guide/v0.2.1-rc.2/file-drag-callbacks/guide.md +/: + en: 9af755cc45c2291b + zh: 3c4053dd22a8263c +/supply-file-preparation-callbacks-to-image-views: + en: 52816e83f1c07873 + zh: fd96927a64d80a3c +/supply-file-preparation-callbacks-to-image-views/change: + en: f790da179b0f64b4 + zh: 7640190a12fd6796 +/supply-file-preparation-callbacks-to-image-views/migration: + en: 02f27032b22dae7c + zh: 242a3b6779ad4c4b diff --git a/docs/upgrade-guide/v0.2.1-rc.2/file-drag-callbacks/guide.md b/docs/upgrade-guide/v0.2.1-rc.2/file-drag-callbacks/guide.md new file mode 100644 index 0000000000..bfe909aeff --- /dev/null +++ b/docs/upgrade-guide/v0.2.1-rc.2/file-drag-callbacks/guide.md @@ -0,0 +1,19 @@ +--- +kind: upgrade-guide +description: "Custom image factories and Markdown image delegates must supply file preparation callbacks." +--- + +# Supply file preparation callbacks to image views + +English | [中文](guide.zh.md) + +## Change + +The published `conversation.images.content` Factory now requires a `fileDrag` inject member, and `MarkdownDelegate.fileImages` requires the same callbacks. `ChatViewInjected` also gains `fileDrag`. Custom registrations that construct these values must update before compilation succeeds. The shipped Web and Desktop compositions provide `@deepseek-ai/dsh-client-ui-file-drag`; custom compositions must provide the service and its feedback slot. Existing image label fields are unchanged. + +## Migration + +1. Include `@deepseek-ai/dsh-client-ui-file-drag` in the custom client composition, together with locale, the slot renderer, and a shell declaring `shell.overlay`. Declare `fileDrag` in each consumer plugin’s `inject` list. +2. Pass `ctx.fileDrag.actions` as `fileDrag` when registering `conversation.images.content`, assembling `ChatViewInjected`, or constructing `MarkdownDelegate.fileImages`. The callbacks prepare Blob or URL content and report localized failures; components receive them explicitly. Optional `resourceAddress(path)` supplies a Session resource reference for authorized Desktop source reuse. +3. Custom composer implementations can receive `ctx.fileDrag.read` through their own inject interface to accept application-local tokens. The `conversation.input.attachments` slot’s public props remain unchanged; only the shipped attachment implementation requires this callback. Accept internal drops in the composer region and retain ordinary `dataTransfer.files` handling for external files. +4. Rebuild custom packages and verify an image drag into the composer. Confirm the original filename and bytes and that dropping back on the source does not add an attachment. See the [file-drag plugin](../../../../packages/client/ui-file-drag/README.md) for ownership and browser limitations. diff --git a/docs/upgrade-guide/v0.2.1-rc.2/file-drag-callbacks/guide.zh.md b/docs/upgrade-guide/v0.2.1-rc.2/file-drag-callbacks/guide.zh.md new file mode 100644 index 0000000000..cff02143af --- /dev/null +++ b/docs/upgrade-guide/v0.2.1-rc.2/file-drag-callbacks/guide.zh.md @@ -0,0 +1,19 @@ +--- +kind: upgrade-guide +description: "自定义图片 Factory 和 Markdown 图片委托必须提供文件准备回调。" +--- + +# 为图片视图提供文件准备回调 + +[English](guide.md) | 中文 + +## 变更 + +已发布的 `conversation.images.content` Factory 现在要求 `fileDrag` 注入成员,`MarkdownDelegate.fileImages` 也要求相同回调。`ChatViewInjected` 同样新增 `fileDrag`。构造这些值的自定义注册必须更新才能通过编译。内置 Web 和 Desktop 组合提供 `@deepseek-ai/dsh-client-ui-file-drag`;自定义组合必须提供该服务及其反馈插槽。已有图片文案字段不变。 + +## 迁移 + +1. 在自定义客户端组合中加载 `@deepseek-ai/dsh-client-ui-file-drag`,同时提供 locale、插槽渲染器和声明 `shell.overlay` 的外壳。在每个消费插件的 `inject` 列表中声明 `fileDrag`。 +2. 注册 `conversation.images.content`、组装 `ChatViewInjected` 或构造 `MarkdownDelegate.fileImages` 时,将 `ctx.fileDrag.actions` 作为 `fileDrag` 传入。回调负责准备 Blob 或 URL 内容及报告本地化失败;组件显式接收它们。可选的 `resourceAddress(path)` 提供 Session 资源引用,以便 Desktop 经授权后复用源文件。 +3. 自定义输入框实现可通过自己的注入接口接收 `ctx.fileDrag.read`,以接受应用内令牌。`conversation.input.attachments` 插槽的公开 props 不变;只有内置附件实现要求该回调。内部投放仅在输入框范围接受,外部文件保留普通 `dataTransfer.files` 处理。 +4. 重新构建自定义包,验证图片拖入输入框后的原始文件名和字节,并确认拖回源图不会增加附件。所有权和浏览器限制见[文件拖放插件](../../../../packages/client/ui-file-drag/README.zh.md)。 diff --git a/docs/upgrade-guide/v0.2.1-rc.2/official-bundle-lists/guide.i18n.yaml b/docs/upgrade-guide/v0.2.1-rc.2/official-bundle-lists/guide.i18n.yaml new file mode 100644 index 0000000000..5697bed51b --- /dev/null +++ b/docs/upgrade-guide/v0.2.1-rc.2/official-bundle-lists/guide.i18n.yaml @@ -0,0 +1,16 @@ +# Bilingual-pair consistency record for guide.md (docs/i18n/README.md): per heading +# section, a hash of its English and Chinese blocks outside code blocks and generated regions. +# After editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write docs/upgrade-guide/v0.2.1-rc.2/official-bundle-lists/guide.md +/: + en: d6f85fefe3671f5d + zh: 2719b3d5ba1b2120 +/import-bundle-lists-from-deepseek-ai-dsh-official-bundles: + en: 89f87bcf95ee4262 + zh: 00bbb48605743bcc +/import-bundle-lists-from-deepseek-ai-dsh-official-bundles/change: + en: 0d8984d9bead43c6 + zh: 60939a14fcf1ba9a +/import-bundle-lists-from-deepseek-ai-dsh-official-bundles/migration: + en: 6db29a6197a38b9e + zh: f1b445be37526806 diff --git a/docs/upgrade-guide/v0.2.1-rc.2/official-bundle-lists/guide.md b/docs/upgrade-guide/v0.2.1-rc.2/official-bundle-lists/guide.md new file mode 100644 index 0000000000..602fa01af5 --- /dev/null +++ b/docs/upgrade-guide/v0.2.1-rc.2/official-bundle-lists/guide.md @@ -0,0 +1,18 @@ +--- +kind: upgrade-guide +description: "The bundle lists and profile templates move from @deepseek-ai/dsh-app-boot to @deepseek-ai/dsh-official-bundles." +--- + +# Import bundle lists from `@deepseek-ai/dsh-official-bundles` + +English | [中文](guide.zh.md) + +## Change + +`@deepseek-ai/dsh-app-boot` no longer exports `PROFILE_TEMPLATES`, `ProfileTemplate`, `DEFAULT_PROFILE_BUNDLES`, `OPTIONAL_BUNDLES`, `ON_DEMAND_BUNDLES`, `OFFICIAL_ON_DEMAND_CATALOG`, or `OfficialBundleCatalogEntry`. The new published package `@deepseek-ai/dsh-official-bundles` exports them with unchanged values and types. Code that imports any of these names from `@deepseek-ai/dsh-app-boot` fails to compile or load. The `dsh` launcher, profiles, and bundle selection behave as before. + +## Migration + +1. Add `@deepseek-ai/dsh-official-bundles` to the `dependencies` of each package that imports one of these names. +2. Change those imports from `@deepseek-ai/dsh-app-boot` to `@deepseek-ai/dsh-official-bundles`, for example `import { PROFILE_TEMPLATES } from '@deepseek-ai/dsh-official-bundles'`. Keep importing every other name, such as `initProfile` or `loadProfile`, from `@deepseek-ai/dsh-app-boot`. +3. Run your type check or build; it succeeds when no import of a moved name from `@deepseek-ai/dsh-app-boot` remains. See the [package README](../../../../packages/boot/official-bundles/README.md) for each list. diff --git a/docs/upgrade-guide/v0.2.1-rc.2/official-bundle-lists/guide.zh.md b/docs/upgrade-guide/v0.2.1-rc.2/official-bundle-lists/guide.zh.md new file mode 100644 index 0000000000..bff51e358a --- /dev/null +++ b/docs/upgrade-guide/v0.2.1-rc.2/official-bundle-lists/guide.zh.md @@ -0,0 +1,18 @@ +--- +kind: upgrade-guide +description: "组合包列表和 profile 模板从 @deepseek-ai/dsh-app-boot 移至 @deepseek-ai/dsh-official-bundles。" +--- + +# 从 `@deepseek-ai/dsh-official-bundles` 导入组合包列表 + +[English](guide.md) | 中文 + +## 变更 + +`@deepseek-ai/dsh-app-boot` 不再导出 `PROFILE_TEMPLATES`、`ProfileTemplate`、`DEFAULT_PROFILE_BUNDLES`、`OPTIONAL_BUNDLES`、`ON_DEMAND_BUNDLES`、`OFFICIAL_ON_DEMAND_CATALOG` 和 `OfficialBundleCatalogEntry`。新发布的包 `@deepseek-ai/dsh-official-bundles` 导出它们,值和类型不变。从 `@deepseek-ai/dsh-app-boot` 导入这些名称的代码将无法编译或加载。`dsh` 启动器、profile 和组合包选择的行为不变。 + +## 迁移 + +1. 在每个导入这些名称的包的 `dependencies` 中加入 `@deepseek-ai/dsh-official-bundles`。 +2. 把这些导入从 `@deepseek-ai/dsh-app-boot` 改为 `@deepseek-ai/dsh-official-bundles`,例如 `import { PROFILE_TEMPLATES } from '@deepseek-ai/dsh-official-bundles'`。其他名称(如 `initProfile` 或 `loadProfile`)仍从 `@deepseek-ai/dsh-app-boot` 导入。 +3. 运行类型检查或构建;不再有从 `@deepseek-ai/dsh-app-boot` 导入已移动名称的代码时即通过。各列表的说明见[包 README](../../../../packages/boot/official-bundles/README.zh.md)。 diff --git a/docs/upgrade-guide/v0.2.1-rc.2/session-store-writes/guide.i18n.yaml b/docs/upgrade-guide/v0.2.1-rc.2/session-store-writes/guide.i18n.yaml new file mode 100644 index 0000000000..fa72f7b4e8 --- /dev/null +++ b/docs/upgrade-guide/v0.2.1-rc.2/session-store-writes/guide.i18n.yaml @@ -0,0 +1,16 @@ +# Bilingual-pair consistency record for guide.md (docs/i18n/README.md): per heading +# section, a hash of its English and Chinese blocks outside code blocks and generated regions. +# After editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write docs/upgrade-guide/v0.2.1-rc.2/session-store-writes/guide.md +/: + en: 9f4269869ddedadc + zh: 1727a99e307a0748 +/store-owned-session-writes-follow-publication: + en: 084471869eed95ac + zh: f85b7855bab7868e +/store-owned-session-writes-follow-publication/change: + en: be28a83cfa73d844 + zh: 5c380f0e25c3f6ca +/store-owned-session-writes-follow-publication/migration: + en: ebfc3e7cdf09ddda + zh: 8f53f5500fbe1958 diff --git a/docs/upgrade-guide/v0.2.1-rc.2/session-store-writes/guide.md b/docs/upgrade-guide/v0.2.1-rc.2/session-store-writes/guide.md new file mode 100644 index 0000000000..1542ef457c --- /dev/null +++ b/docs/upgrade-guide/v0.2.1-rc.2/session-store-writes/guide.md @@ -0,0 +1,25 @@ +--- +kind: upgrade-guide +description: "Store-owned Sessions reject writes before creation announcement completes and after removal." +--- +# Store-owned Session writes follow publication + +English | [中文](guide.zh.md) + +## Change + +`Session.append()` and `appendPluginRecord()` on store-owned instances reject writes until the instance enters a `SessionStore` and its synchronous `session/created` dispatch completes, and after it leaves. Store ownership starts at `prepare()` or `enter()`. Creation listeners cannot append; a failed announcement leaves writes disabled. Independent `Session.create()` and `Session.fromRestore()` instances remain writable without notifying store observers. Constructor, restore, and fork history still load normally. The Agent factory completes `session/created` before invoking setup; `agent/created` still follows setup. During `session/created`, `ctx.agents.get(session.id)` now returns `undefined`. Listeners registered inside setup miss their own Session’s creation announcement. Setup events now reach live Session subscribers as well as persisted history. + +A failed setup retains constructor history and setup events already written to persistence. A failed seeded creation, including a fork, can therefore leave a stored Session; its identity is no longer available for a new creation. + +Permission defaults are initialized during `agent/created`, so creating a bare Session no longer pins them. `dsh-permission-presets` now requires the `agents` service as well as its existing dependencies. + +## Migration + +1. Use `ctx.sessions.create()` for a writable Session owned by the calling fiber. For explicit lifecycle ownership, call `prepare()`, `enter()`, and `announce()` before appending; retain the returned disposer until all closing events finish. +2. Keep `Session.create()` and `Session.fromRestore()` for independent log construction. Build history before handing the instance to `enter()`, or pass it as the seed to `prepare()`. Removal does not restore independent write access. Cold durable writes use the persistence write handle. +3. Move writes and Agent-dependent work out of `session/created` listeners. Use setup or `agent/created` for writes; use the supplied Agent in setup and the `agent/created` payload instead of looking up an Agent during Session announcement. +4. Replace setup-installed observers of their own `session/created` with `agent/created` listeners. Keep Session creation observers in a scope installed before factory creation starts. +5. After failed creation with persisted history, retry with `ctx.agents.resume({ resumeSessionId })` instead of `create()` on the same id. Retain the stored history for recovery. +6. Custom profiles mounting `dsh-permission-presets` must also mount `dsh-agent`, the provider of `agents`, and await permission plugin activation before creating Agents. +7. Verify that creation observers see the expected registry state, permission initialization completes, failed creation can resume its stored history, and rejected appends leave history unchanged. diff --git a/docs/upgrade-guide/v0.2.1-rc.2/session-store-writes/guide.zh.md b/docs/upgrade-guide/v0.2.1-rc.2/session-store-writes/guide.zh.md new file mode 100644 index 0000000000..d287b9e8dc --- /dev/null +++ b/docs/upgrade-guide/v0.2.1-rc.2/session-store-writes/guide.zh.md @@ -0,0 +1,25 @@ +--- +kind: upgrade-guide +description: "Store 接管的 Session 拒绝创建宣告完成前和移除后的写入。" +--- +# Store 接管的 Session 在发布后开放写入 + +[English](guide.md) | 中文 + +## 变更 + +Store 接管的实例仅在进入 `SessionStore` 且同步 `session/created` 分发完成后,才能通过 `Session.append()` 和 `appendPluginRecord()` 写入,离开 Store 后再次拒绝写入。Store 从 `prepare()` 或 `enter()` 开始接管实例。创建监听器不能追加,宣告失败后仍不能写入。独立的 `Session.create()` 和 `Session.fromRestore()` 实例仍可写入,且不通知 Store 观察者。构造、恢复和 fork 历史仍可正常加载。Agent 工厂在调用 setup 前完成 `session/created`,`agent/created` 仍在 setup 后执行。在 `session/created` 期间,`ctx.agents.get(session.id)` 现在返回 `undefined`。setup 内注册的监听器会错过其所属 Session 的创建宣告。setup 事件现在除了进入持久化历史,也会传递给 Session 的实时订阅方。 + +setup 失败后会保留已经写入持久化存储的构造历史和 setup 事件。因此,带 seed 的创建(包括 fork)失败后可能留下已存储的 Session,其标识不能再用于新建。 + +权限默认值在 `agent/created` 中初始化,因此只创建 Session 不再固定这些默认值。`dsh-permission-presets` 除既有依赖外,现在还要求 `agents` 服务。 + +## 迁移 + +1. 使用 `ctx.sessions.create()` 创建由调用方 fiber 拥有的可写 Session。若显式拥有生命周期,依次调用 `prepare()`、`enter()` 和 `announce()` 后再追加;保留返回的 disposer,直到所有收尾事件完成。 +2. 独立日志构造继续使用 `Session.create()` 和 `Session.fromRestore()`。在把实例交给 `enter()` 前构造历史,或把历史作为 seed 传给 `prepare()`。移除不会恢复独立写入权限。冷日志的持久化写入使用持久化写句柄。 +3. 将写入和依赖 Agent 的工作移出 `session/created` 监听器。在 setup 或 `agent/created` 中写入;使用 setup 提供的 Agent 或 `agent/created` 载荷,不要在 Session 宣告期间查找 Agent。 +4. 将 setup 内监听所属 Session 的 `session/created` 的代码改为监听 `agent/created`。需要观察 Session 创建时,应在工厂创建开始前安装监听作用域。 +5. 创建失败但已持久化历史时,使用 `ctx.agents.resume({ resumeSessionId })` 重试,不要对同一 id 再次调用 `create()`;保留存储历史用于恢复。 +6. 挂载 `dsh-permission-presets` 的自定义 profile 也必须挂载提供 `agents` 的 `dsh-agent`,并等待权限插件激活后再创建 Agent。 +7. 验证创建观察者看到预期的注册表状态、权限完成初始化、创建失败后能恢复存储历史,以及被拒绝的追加不会改变历史。 diff --git a/docs/user/guide/providers.i18n.yaml b/docs/user/guide/providers.i18n.yaml index 6f7e665a4f..93bc2cc11f 100644 --- a/docs/user/guide/providers.i18n.yaml +++ b/docs/user/guide/providers.i18n.yaml @@ -18,8 +18,8 @@ en: ec10ba53a00eddc6 zh: 857373a4e0fefee4 /configure-models/select-a-model: - en: 6a94264c99535caf - zh: f97bb0dc6a40c0d3 + en: 281b2f40645aa5eb + zh: 861bfe9584d9d30f /configure-models/advanced-configuration: en: b882ec69a6899d8a zh: 66a1713aca0e6f1c diff --git a/docs/user/guide/providers.md b/docs/user/guide/providers.md index c1118e469f..144b33d835 100644 --- a/docs/user/guide/providers.md +++ b/docs/user/guide/providers.md @@ -40,6 +40,8 @@ Discovery reads the listing formats common gateways publish, but not every endpo Configured providers appear in the model picker. Selecting a model also makes it the default for new sessions. A session that has already sent a request retains the model recorded in its own log. +To change a provider’s model order, edit it in **Settings → Models**, open **Customized settings**, and drag a model’s three-line handle. You can also focus the handle and press the up or down arrow key. **Apply** keeps the order; **Cancel** discards it. The model picker follows the saved order within that provider. + If a saved default names a provider that was deleted, the composer displays **Select model** and blocks input until another model is selected. ## Advanced configuration diff --git a/docs/user/guide/providers.zh.md b/docs/user/guide/providers.zh.md index ebf6147681..e20d1eb4aa 100644 --- a/docs/user/guide/providers.zh.md +++ b/docs/user/guide/providers.zh.md @@ -40,6 +40,8 @@ Provider ID 是永久的,因为请求、已保存会话、模型默认值和 已配置的提供商会出现在模型选择器中。选择模型也会将其设为新会话的默认值。已发送过请求的会话会保留自身日志中记录的模型。 +在**设置 → 模型**中编辑提供商,打开**自定义设置**,再拖动模型的三横线手柄,即可调整该提供商内的模型顺序。也可以聚焦手柄后按上下方向键。保存会保留顺序;取消会放弃修改。模型选择器会按该提供商保存的顺序列出模型。 + 如果已保存默认值指向已删除的提供商,输入框会显示**选择模型**,并在选择其他模型前阻止输入。 ## 进阶配置 diff --git a/packages/README.i18n.yaml b/packages/README.i18n.yaml index 4412f95938..701a4ae942 100644 --- a/packages/README.i18n.yaml +++ b/packages/README.i18n.yaml @@ -15,8 +15,8 @@ en: ffc55792d6e922e1 zh: 83bd759638857e2d /packages/package-groups: - en: ff0b0b8388457f47 - zh: b9ace22bb3cbad48 + en: d67996086e3b4f28 + zh: cb758b1fcee5ab3e /packages/release-expectations: en: 236081c1659b25ab zh: 809110adf003802e diff --git a/packages/README.md b/packages/README.md index 9485cc1001..b6d04e0f04 100644 --- a/packages/README.md +++ b/packages/README.md @@ -75,7 +75,7 @@ Every package lives in exactly one group; new packages join existing groups, and | [`sdk/`](sdk/README.md) | Out-of-process SDK: JSON-RPC protocol and TypeScript client/server | | [`acp/`](acp/README.md) | Automation-only Agent Client Protocol server | | [`interaction/`](interaction/README.md) | Human-collaboration plane: approval/interaction seams, permission preset, commands, ask-user tool | -| [`boot/`](boot/README.md) | Shared app-bin boot glue | +| [`boot/`](boot/README.md) | Shared app-bin boot glue and installation bundle lists | | [`host/`](host/README.md) | Web GUI host services, directory picking, application launch, plugin inventory, and product telemetry | | [`client/`](client/README.md) | Web-GUI browser half: shell, wire, object services, slots, `ui-*` plugins | | [`test-support/`](test-support/README.md) | Test infrastructure (testkits, replay, Loader smokes) | diff --git a/packages/README.zh.md b/packages/README.zh.md index ec2a9b81f8..f1cb7f8266 100644 --- a/packages/README.zh.md +++ b/packages/README.zh.md @@ -75,7 +75,7 @@ harness 由 `packages/` 下的 npm 包组装而成,按能力系列分组:会 | [`sdk/`](sdk/README.zh.md) | 进程外 SDK:JSON-RPC 协议与 TypeScript 客户端/服务器 | | [`acp/`](acp/README.zh.md) | 仅面向自动化的 ACP(Agent Client Protocol)服务器 | | [`interaction/`](interaction/README.zh.md) | 人机协作平面:批准/交互 seam、权限预设、命令、询问用户的工具 | -| [`boot/`](boot/README.zh.md) | 共享的 app bin 启动粘合层 | +| [`boot/`](boot/README.zh.md) | 共享的 app bin 启动粘合层与安装方组合包列表 | | [`host/`](host/README.zh.md) | Web GUI 宿主服务、目录选择、应用启动、插件清单和产品遥测 | | [`client/`](client/README.zh.md) | web GUI 浏览器半侧:shell、协议层、对象服务、slot、`ui-*` 插件 | | [`test-support/`](test-support/README.zh.md) | 测试基础设施(testkit、回放、Loader 冒烟测试) | diff --git a/packages/api/gateway/tests/gateway.host.spec.ts b/packages/api/gateway/tests/gateway.host.spec.ts index 6ec0e64bbb..4272ee90bb 100644 --- a/packages/api/gateway/tests/gateway.host.spec.ts +++ b/packages/api/gateway/tests/gateway.host.spec.ts @@ -153,7 +153,7 @@ class FakeConnectionService extends Service { function fakeHttpServer(routes: WebRoute[]): Pick { return { - register(route) { + register(route: WebRoute) { if (routes.some(candidate => candidate.kind === route.kind && candidate.path === route.path)) { throw new Error(`duplicate route ${route.path}`) } diff --git a/packages/api/session-controller/README.i18n.yaml b/packages/api/session-controller/README.i18n.yaml index 0bc8aff3f8..6df1300fd1 100644 --- a/packages/api/session-controller/README.i18n.yaml +++ b/packages/api/session-controller/README.i18n.yaml @@ -15,14 +15,14 @@ en: 1fdf707322fb6996 zh: 0204f7e9d4aa3cce /session-controller/use-this-package: - en: 8fcfa14545bd9d1c - zh: c10c2bba792699ef + en: aabd5be911e477f5 + zh: 2f7fdb44bc8777bc /session-controller/client-references: en: 41bdda1ac32df558 zh: aa5d0e325924066b /session-controller/session-media-references: - en: 49a3d0e8e92017d3 - zh: 91302aa3dd6e9378 + en: 25e40cb508265c01 + zh: c8ce39a94997af00 /session-controller/configuration: en: c92590fbaf75e45e zh: fcac67017bb0e3ab diff --git a/packages/api/session-controller/README.md b/packages/api/session-controller/README.md index b935dfe606..abbb52cd63 100644 --- a/packages/api/session-controller/README.md +++ b/packages/api/session-controller/README.md @@ -33,7 +33,7 @@ History pages and follow opening snapshots carry one `{ type: 'event', event: Se The Client journal validates current Session event envelopes before publishing follow snapshots, live entries, or history pages. It reuses the browser-safe Session validators for required surface markers, exact replacement endpoints, earlier unique source seqs, embedded Assistant provider metadata, request-header omissions, and tool-error consistency. Invalid records fail without field stripping or normalization; range membership and source existence remain durable-log checks on the Host. -Each endpoint states its activation policy. List reads only stored headers and projection-cache rows: it never calls per-session stat or opens a cold Session body. A current-format cache identity may supply every list hint; a lifecycle-matching predecessor cache may supply only its version-compatible title as a stale display fact, never as an authoritative fold seed. Search, attachment, history pages, log following, skill discovery, and workspace-path opening can inspect persistence without activating an Agent; `canOpenWorkspacePath()` reports native-opening availability without addressing a Session. Cancellation requires live state; queue mutation, model, rename, prompt, and file-reference operations may resolve or resume an ordinary Session. Prompt rejects content with neither non-whitespace text nor an attachment before resolving the Agent or appending Session events; queue edits accept only non-empty text content. Prompt admission consumes opaque receipts from the injected [`fileUploads`](../../client/file-upload/README.md) Host service and resolves every same-Agent receipt before sending the complete ordered content list through `ctx.attachments`. Prompt retries whose `requestId` is already queued or logged return the original acceptance without inserting another message. Create and fork are the only operations that create a new Agent directly. The service applies one preset-aware resume policy and subagent ownership fence to its own methods and to the Typert Agent and Session lookups used by other Remote namespaces. Queue mutation has one narrow exception: a live child whose current projected identity is continuable and comes from its own non-seed suffix accepts the ordinary Edit, Remove, and QueueDock Steer actions across both inbox destinations. One-shot, missing, unknown, corrupt, seed-only, or cold children remain rejected without resume. The skill catalog uses a live Agent's effective working directory and scoped registry when present. Cold listing uses the projected current directory, falling back to the recorded origin and then the configured directory default. It retains the preset standing scope without activating an Agent. The authenticated delivery routes use `workspaceDesktop()` for the serving Host name and file-manager behavior. `openWorkspacePath({ path, action: "reveal" })` delegates file-manager navigation to the native adapter; omitting `action` opens the file-type association, including HTML and SVG. Both operations require the composed filesystem to map the requested Host path to the same canonical process path; unmapped remote paths are refused before a native command runs. `session.projections` normally reads an exact baseline, including current-format cold logs, and returns `kind: sequenced`. Only a read requiring migration returns `kind: migration-required` hints without `asOfSeq`; missing keys remain absent. It returns null for a missing Session. Fork callers may set `allowMigration: false` to receive `session/migration-required` instead of starting source migration; omission retains automatic migration. The Client exposes shared values and explicit-read state through `projectionsBySession`; domains select their own keys. Session-list summaries carry `agentAvailable`, updated through existing summary and status events independently of durable projections. Sequenced reads and live projection frames use the same sequence ordering; cached reads fill hints without replacing sequenced values. +Each endpoint states its activation policy. List reads only stored headers and projection-cache rows: it never calls per-session stat or opens a cold Session body. A current-format cache identity may supply every list hint; a lifecycle-matching predecessor cache may supply only its version-compatible title as a stale display fact, never as an authoritative fold seed. Search, attachment, history pages, log following, skill discovery, and workspace-path opening can inspect persistence without activating an Agent; `canOpenWorkspacePath()` reports native-opening availability without addressing a Session. Cancellation requires live state; queue mutation, model, rename, prompt, and file-reference operations may resolve or resume an ordinary Session. Prompt rejects content with neither non-whitespace text nor an attachment before resolving the Agent or appending Session events; queue edits accept only non-empty text content. Prompt admission consumes opaque receipts from the injected [`fileUploads`](../../client/file-upload/README.md) Host service and resolves every same-Agent receipt before sending the complete ordered content list through `ctx.attachments`. A receipt names a staged file or a staged image, and an image receipt subjects the prompt to the same image-input check as an encoded image. Prompt retries whose `requestId` is already queued or logged return the original acceptance without inserting another message. Create and fork are the only operations that create a new Agent directly. The service applies one preset-aware resume policy and subagent ownership fence to its own methods and to the Typert Agent and Session lookups used by other Remote namespaces. Queue mutation has one narrow exception: a live child whose current projected identity is continuable and comes from its own non-seed suffix accepts the ordinary Edit, Remove, and QueueDock Steer actions across both inbox destinations. One-shot, missing, unknown, corrupt, seed-only, or cold children remain rejected without resume. The skill catalog uses a live Agent's effective working directory and scoped registry when present. Cold listing uses the projected current directory, falling back to the recorded origin and then the configured directory default. It retains the preset standing scope without activating an Agent. The authenticated delivery routes use `workspaceDesktop()` for the serving Host name and file-manager behavior. `openWorkspacePath({ path, action: "reveal" })` delegates file-manager navigation to the native adapter; omitting `action` opens the file-type association, including HTML and SVG. Both operations require the composed filesystem to map the requested Host path to the same canonical process path; unmapped remote paths are refused before a native command runs. `session.projections` normally reads an exact baseline, including current-format cold logs, and returns `kind: sequenced`. Only a read requiring migration returns `kind: migration-required` hints without `asOfSeq`; missing keys remain absent. It returns null for a missing Session. Fork callers may set `allowMigration: false` to receive `session/migration-required` instead of starting source migration; omission retains automatic migration. The Client exposes shared values and explicit-read state through `projectionsBySession`; domains select their own keys. Session-list summaries carry `agentAvailable`, updated through existing summary and status events independently of durable projections. Sequenced reads and live projection frames use the same sequence ordering; cached reads fill hints without replacing sequenced values. Every Remote endpoint is access-controlled: a Peer whose principal is not the owner reaches an endpoint only when, on every resource the call touches, a binding of that principal kind's policy in [`dsh-api-remote-access`](../remote-access/README.md) grants a role listing the action ([Peer principals Agent Note](../../../.agents/notes/implemented/architecture/2026-10-12-peer-principal-and-remote-access.md)). The controller injects `remoteAccess` and registers the `session` resource kind with the default field `sessionId` through `typert.resources`. `session/page` and `session/follow` declare a `session` reader in `@Remote({ resources })` that reads `request.address.sessionId` for an ordinary Session address and `request.address.childSessionId` for a subagent address; whether access to the parent Session covers its children is the policy's rule. `session/projections` reads the Session resource from `request.sessionId`, so a reconnecting reader reloads only the projections of Sessions it may read. `session/list`, `session/search`, and `session/control` read no resource, so their calls touch the `global` resource and need a `global` role; for a non-owner caller, `session/list` returns only the rows, `session/search` only the hits, and `session/control` only the baseline projections and projection frames, whose Session `ctx.remoteAccess.allows()` admits for the same action, so that action also belongs to a `session` role; owner results are unfiltered. `session/prompt` builds the durable `user-rpc` message source in its Remote method and records `principal` only for a non-owner caller, read through `principalOf(this.ctx.invocation)`; a source without `principal` belongs to the owner. @@ -86,7 +86,7 @@ References keep local Session data, scoped Contexts, and history streams alive, ## Session media references -`SessionMediaReferences` mounts `GET|HEAD /api/file?path=` on the authenticated `connection.fetch` channel when `connection`, `fs`, and `attachments` are composed. It reads ordinary files through `ctx.fs`, including temporary paths outside registered workspaces and files in remote providers. Neither directory containment nor MIME categories restrict access; `mime-types` supplies the response type, with `application/octet-stream` for unknown extensions. GET reuses `readBytes` for preflight and ongoing byte limits; HEAD reads metadata only. All files use `ctx.attachments.imageLimits.maxImageBytes` (normally 20 MiB); exceeding this limit returns 413. Responses contain the complete file, ignore Range, and carry `private, no-store`, `nosniff`, and a sandbox CSP so directly opened HTML/SVG cannot execute with the API origin. The Client rewrite lives in `ui-chat` (`AssistantMarkdown`); audio/video responses are available, while Markdown audio/video player nodes remain separate work. +`SessionMediaReferences` mounts `GET|HEAD /api/file?path=` on the authenticated `connection.fetch` channel when `connection`, `fs`, and `attachments` are composed. It reads ordinary files through `ctx.fs`, including temporary paths outside registered workspaces and files in remote providers. Neither directory containment nor MIME categories restrict access; `mime-types` supplies the response type, with `application/octet-stream` for unknown extensions. GET reuses `readBytes` for preflight and ongoing byte limits; HEAD reads metadata only. All files use `ctx.attachments.imageLimits.maxImageBytes` (normally 50 MiB); exceeding this limit returns 413. Responses contain the complete file, ignore Range, and carry `private, no-store`, `nosniff`, and a sandbox CSP so directly opened HTML/SVG cannot execute with the API origin. The Client rewrite lives in `ui-chat` (`AssistantMarkdown`); audio/video responses are available, while Markdown audio/video player nodes remain separate work. GUI model selection requires the exact provider/model pair in the available catalog; unavailable choices reject with `session/model-unavailable`. Prompt admission retains the saved route without a catalog availability gate, so request execution reports missing credentials or unavailable models. `initializeDefaultModel()` saves the first available account model after login when no other provider has a configured API key; credential checks use configured references independently of model availability. A provider with no available models rejects initialization with `session/provider-models-unavailable`. Availability never substitutes another model or rewrites a Session selection. diff --git a/packages/api/session-controller/README.zh.md b/packages/api/session-controller/README.zh.md index 57262c5267..58bdbbf48b 100644 --- a/packages/api/session-controller/README.zh.md +++ b/packages/api/session-controller/README.zh.md @@ -33,7 +33,7 @@ kind: "package-reference" Client journal 在发布 follow 快照、live entry 或历史页之前验证当前 Session 事件 envelope。它复用浏览器安全的 Session validator,检查必需的 surface marker、精确的 replacement endpoint、更早且唯一的 source seq、内嵌 Assistant 提供方元数据、request header 可选字段的省略规则以及工具错误一致性。无效 record 直接失败,不删除字段或归一化;范围成员与来源存在性仍由 Host 的持久日志检查。 -每个 endpoint 都声明自己的激活策略。列表只读取持久化 header 与 projection cache row,绝不调用逐 Session stat 或打开冷 Session body。当前格式 cache identity 可以提供全部列表 hint;生命周期匹配的 predecessor cache 只能提供版本兼容的 title,作为可能过时的展示事实,绝不能作为权威 fold seed。搜索、附件、历史页、日志跟随、skill 发现和工作区路径打开可以在不激活 Agent 的情况下检查 persistence;`canOpenWorkspacePath()` 无需指定 Session 即可报告原生打开能力。取消要求 live 状态;queue 变更、模型、重命名、prompt 和文件引用操作可以解析或恢复普通 Session。提示词会在解析 Agent 或追加 Session 事件前,拒绝既没有非空白文本也没有附件的 content;queue edit 只接受非空文本 content。prompt 准入从注入的 [`fileUploads`](../../client/file-upload/README.zh.md) Host 服务取得不透明凭证,在把完整有序内容列表交给 `ctx.attachments` 前解析每个属于同一 Agent 的凭证。`requestId` 已进入 queue 或日志时,prompt 重试直接返回原来的接受结果,不会重复插入消息。只有 create 与 fork 会直接创建新 Agent。该服务把同一套感知 preset 的恢复策略和 subagent ownership fence 同时用于自身方法,以及其他 Remote namespace 使用的 Typert Agent 与 Session lookup。Queue 变更只有一个狭窄例外:当前 projection identity 为 continuable 且来自自身非 seed suffix 的在线 child,可以在两个 inbox 目标上使用普通 Edit、Remove 与 QueueDock Steer action。One-shot、缺失、未知、损坏、仅含 seed identity 或冷 child 继续被拒绝,且不会恢复。skill 目录优先使用已有 live Agent 的有效工作目录与限定范围内的注册表。冷态列表使用投影中的当前目录,依次回退到记录的起始目录与配置的默认目录。它保留 preset 常驻 scope,不会激活 Agent。经过鉴权的文件交付路由通过 `workspaceDesktop()` 获取提供服务的 Host 名称和文件管理器行为。`openWorkspacePath({ path, action: "reveal" })` 将文件管理器导航委托给原生适配器;省略 `action` 时按文件类型关联打开,包括 HTML 和 SVG。两种操作都要求当前文件系统将请求的 Host 路径映射到同一个规范进程路径;无法映射的远端路径会在执行原生命令之前被拒绝。 `session.projections` 正常读取准确基线,包括当前格式的冷日志,返回 `kind: sequenced`。只有需要迁移时才返回不带 `asOfSeq` 的 `kind: migration-required` 提示,缺少的键保持缺席。Session 不存在时返回 null。Fork 调用者可设置 `allowMigration: false`,在源历史需要迁移时收到 `session/migration-required`;省略则保持自动迁移。Client 通过 `projectionsBySession` 暴露共享值和显式读取状态,由领域选择自身的 key。Session 列表摘要携带 `agentAvailable`,通过已有摘要与状态事件更新,与持久化 projection 相互独立。有序读取与实时 projection 帧使用相同的序号排序规则;缓存读取只补充提示,不替换有序值。 +每个 endpoint 都声明自己的激活策略。列表只读取持久化 header 与 projection cache row,绝不调用逐 Session stat 或打开冷 Session body。当前格式 cache identity 可以提供全部列表 hint;生命周期匹配的 predecessor cache 只能提供版本兼容的 title,作为可能过时的展示事实,绝不能作为权威 fold seed。搜索、附件、历史页、日志跟随、skill 发现和工作区路径打开可以在不激活 Agent 的情况下检查 persistence;`canOpenWorkspacePath()` 无需指定 Session 即可报告原生打开能力。取消要求 live 状态;queue 变更、模型、重命名、prompt 和文件引用操作可以解析或恢复普通 Session。提示词会在解析 Agent 或追加 Session 事件前,拒绝既没有非空白文本也没有附件的 content;queue edit 只接受非空文本 content。prompt 准入从注入的 [`fileUploads`](../../client/file-upload/README.zh.md) Host 服务取得不透明凭证,在把完整有序内容列表交给 `ctx.attachments` 前解析每个属于同一 Agent 的凭证。凭证指向一个暂存文件或一张暂存图片;图片凭证与编码图片一样要经过图片输入检查。`requestId` 已进入 queue 或日志时,prompt 重试直接返回原来的接受结果,不会重复插入消息。只有 create 与 fork 会直接创建新 Agent。该服务把同一套感知 preset 的恢复策略和 subagent ownership fence 同时用于自身方法,以及其他 Remote namespace 使用的 Typert Agent 与 Session lookup。Queue 变更只有一个狭窄例外:当前 projection identity 为 continuable 且来自自身非 seed suffix 的在线 child,可以在两个 inbox 目标上使用普通 Edit、Remove 与 QueueDock Steer action。One-shot、缺失、未知、损坏、仅含 seed identity 或冷 child 继续被拒绝,且不会恢复。skill 目录优先使用已有 live Agent 的有效工作目录与限定范围内的注册表。冷态列表使用投影中的当前目录,依次回退到记录的起始目录与配置的默认目录。它保留 preset 常驻 scope,不会激活 Agent。经过鉴权的文件交付路由通过 `workspaceDesktop()` 获取提供服务的 Host 名称和文件管理器行为。`openWorkspacePath({ path, action: "reveal" })` 将文件管理器导航委托给原生适配器;省略 `action` 时按文件类型关联打开,包括 HTML 和 SVG。两种操作都要求当前文件系统将请求的 Host 路径映射到同一个规范进程路径;无法映射的远端路径会在执行原生命令之前被拒绝。 `session.projections` 正常读取准确基线,包括当前格式的冷日志,返回 `kind: sequenced`。只有需要迁移时才返回不带 `asOfSeq` 的 `kind: migration-required` 提示,缺少的键保持缺席。Session 不存在时返回 null。Fork 调用者可设置 `allowMigration: false`,在源历史需要迁移时收到 `session/migration-required`;省略则保持自动迁移。Client 通过 `projectionsBySession` 暴露共享值和显式读取状态,由领域选择自身的 key。Session 列表摘要携带 `agentAvailable`,通过已有摘要与状态事件更新,与持久化 projection 相互独立。有序读取与实时 projection 帧使用相同的序号排序规则;缓存读取只补充提示,不替换有序值。 每个 Remote 端点都受访问控制:principal 不是 owner 的 Peer 只有在本次调用访问的每个资源上,该 principal kind 在 [`dsh-api-remote-access`](../remote-access/README.zh.md) 中的 policy 都有某个 binding 授予列出该 action 的 role 时,才能调用该端点([Peer 身份属性 Agent Note](../../../.agents/notes/implemented/architecture/2026-10-12-peer-principal-and-remote-access.zh.md))。控制器注入 `remoteAccess`,并经 `typert.resources` 以默认字段 `sessionId` 登记 `session` 资源种类。`session/page` 与 `session/follow` 在 `@Remote({ resources })` 中声明 `session` 读取函数:对普通 Session 地址读 `request.address.sessionId`,对 subagent 地址读 `request.address.childSessionId`;父会话的访问权是否覆盖其子会话由 policy 决定。`session/projections` 从 `request.sessionId` 读取会话资源,因此重连的读者只会重新读取它可读的会话的 projections。`session/list`、`session/search` 与 `session/control` 不读取资源,其调用访问 `global` 资源,需要 `global` role;对非 owner 调用方,`session/list` 只返回其 Session 被 `ctx.remoteAccess.allows()` 按同一 action 允许的行,`session/search` 只返回这类 Session 的命中,`session/control` 也只返回这类 Session 的 baseline projection 与 projection 帧,因此该 action 也要列在 `session` role 中;owner 的结果不过滤。`session/prompt` 在其 Remote 方法内构造持久的 `user-rpc` 消息 source,且只为非 owner 调用方记录经 `principalOf(this.ctx.invocation)` 读取的 `principal`;不带 `principal` 的 source 属于 owner。 @@ -86,7 +86,7 @@ Client 的首次 `follow`、重连首屏与 `loadOlder()` 至少请求 50 条以 ## 会话媒体引用 -当 `connection`、`fs` 与 `attachments` 均被组合时,`SessionMediaReferences` 在鉴权 `connection.fetch` 通道上挂载 `GET|HEAD /api/file?path=<绝对路径>`。它通过 `ctx.fs` 读取普通文件,包括已注册工作区之外的临时路径与远程提供方中的文件。目录包含关系与 MIME 类别均不限制访问;`mime-types` 提供响应类型,未知扩展名使用 `application/octet-stream`。GET 复用 `readBytes` 执行读取前及读取中的字节限制;HEAD 只读取元数据。所有文件均使用 `ctx.attachments.imageLimits.maxImageBytes`(通常为 20 MiB);超过此上限返回 413。响应包含完整文件,忽略 Range,并携带 `private, no-store`、`nosniff` 与沙箱 CSP,使直接打开的 HTML/SVG 无法以 API 源身份执行脚本。客户端重写位于 `ui-chat`(`AssistantMarkdown`);音视频文件响应已可用,Markdown 音视频播放器节点仍是独立工作。 +当 `connection`、`fs` 与 `attachments` 均被组合时,`SessionMediaReferences` 在鉴权 `connection.fetch` 通道上挂载 `GET|HEAD /api/file?path=<绝对路径>`。它通过 `ctx.fs` 读取普通文件,包括已注册工作区之外的临时路径与远程提供方中的文件。目录包含关系与 MIME 类别均不限制访问;`mime-types` 提供响应类型,未知扩展名使用 `application/octet-stream`。GET 复用 `readBytes` 执行读取前及读取中的字节限制;HEAD 只读取元数据。所有文件均使用 `ctx.attachments.imageLimits.maxImageBytes`(通常为 50 MiB);超过此上限返回 413。响应包含完整文件,忽略 Range,并携带 `private, no-store`、`nosniff` 与沙箱 CSP,使直接打开的 HTML/SVG 无法以 API 源身份执行脚本。客户端重写位于 `ui-chat`(`AssistantMarkdown`);音视频文件响应已可用,Markdown 音视频播放器节点仍是独立工作。 GUI 模型选择要求确切提供方/模型对出现在可用目录中;不可用的选择以 `session/model-unavailable` 拒绝。提示词准入保留已保存的路由,不按目录可用性阻断发送,由请求执行报告凭据缺失或模型不可用。`initializeDefaultModel()` 在账号登录后、其他提供方均未配置 API key 时,将第一个可用账号模型保存为默认模型;凭据检查使用已配置的引用,不依赖模型是否可用。提供方没有可用模型时,初始化以 `session/provider-models-unavailable` 拒绝。可用性变化不会替换模型或改写会话选择。 diff --git a/packages/api/session-controller/src/commands.ts b/packages/api/session-controller/src/commands.ts index 59e32cd431..c91f6e5b02 100644 --- a/packages/api/session-controller/src/commands.ts +++ b/packages/api/session-controller/src/commands.ts @@ -7,9 +7,9 @@ import { brandString } from '@deepseek-ai/dsh-brand' import type { Agent, ModelSelection as AgentModelSelection } from '@deepseek-ai/dsh-agent' import { AttachmentError } from '@deepseek-ai/dsh-attachment' import type { - AttachmentAdmissionPart, FileAttachmentRef, ImageAttachmentRef, + AttachmentAdmissionPart, ImageAttachmentRef, } from '@deepseek-ai/dsh-attachment' -import type { FileUploadReceiptId } from '@deepseek-ai/dsh-client-file-upload/types' +import type { FileUploadReceiptId, StagedAttachment } from '@deepseek-ai/dsh-client-file-upload/types' import type {} from '@deepseek-ai/dsh-client-file-upload' import { ReasoningEffortId, assistantStreamChunks, createUserMessage, freezeMessage, @@ -313,7 +313,12 @@ export class SessionCommandController { async prompt(request: SessionPromptRequest, source: MessageSource): Promise { const agent = await this.resolveAgent(request.sessionId) if (hasPromptRequest(agent, request.requestId)) return { accepted: true } - const hasImage = request.content.some(part => part.type === 'image') + const admission = resolvePromptFileReceipts( + request.content, + receiptId => this.ctx.fileUploads.resolve(agent, receiptId), + ) + // Encoded images and image upload receipts both make an image prompt. + const hasImage = admission.content.some(part => part.type === 'image') const admit = async (): Promise => { try { if (hasImage) { @@ -329,10 +334,6 @@ export class SessionCommandController { } } } - const admission = resolvePromptFileReceipts( - request.content, - receiptId => this.ctx.fileUploads.resolve(agent, receiptId), - ) const content = await this.ctx.attachments.admitPromptContent(admission.content) const message: UserMessage = createUserMessage({ content, source }) if (this.ctx.agents.get(agent.id) !== agent) { @@ -556,14 +557,15 @@ export class SessionCommandController { } } +/** Replace each file part with the file or image its staged receipt names. */ function resolvePromptFileReceipts( content: SessionPromptRequest['content'], - stagedFile: (receiptId: FileUploadReceiptId) => FileAttachmentRef | undefined, + staged: (receiptId: FileUploadReceiptId) => StagedAttachment | undefined, ): { readonly content: AttachmentAdmissionPart[]; readonly receiptIds: readonly FileUploadReceiptId[] } { const receiptIds = new Set() const resolved = content.map((part): AttachmentAdmissionPart => { if (part.type !== 'file') return part - const attachment = stagedFile(part.receiptId) + const attachment = staged(part.receiptId) if (attachment === undefined) { throw new RemoteError( 'session/attachment-invalid', @@ -572,7 +574,7 @@ function resolvePromptFileReceipts( ) } receiptIds.add(part.receiptId) - return { type: 'file', attachment } + return attachment }) return { content: resolved, receiptIds: [...receiptIds] } } diff --git a/packages/api/session-controller/src/types.ts b/packages/api/session-controller/src/types.ts index f25a35d4ae..8c6da77a60 100644 --- a/packages/api/session-controller/src/types.ts +++ b/packages/api/session-controller/src/types.ts @@ -71,7 +71,8 @@ export type SessionProjectionValues = Partial /** * Browser-submitted prompt content; the Host promotes image bytes to durable * references. File parts carry the opaque receipt returned by a preceding - * `uploadFile` call on the same Session. + * upload on the same Session; the receipt of an image upload enters the + * message as that image. */ export type PromptContentPart = | { readonly type: 'text'; readonly text: string } diff --git a/packages/api/session-controller/tests/commands-upload-file.host.spec.ts b/packages/api/session-controller/tests/commands-upload-file.host.spec.ts index 305bace577..0f6aff10f2 100644 --- a/packages/api/session-controller/tests/commands-upload-file.host.spec.ts +++ b/packages/api/session-controller/tests/commands-upload-file.host.spec.ts @@ -6,7 +6,8 @@ import { createInboxStub } from '@deepseek-ai/dsh-agent-loop-testkit' import type { Agent } from '@deepseek-ai/dsh-agent' import AttachmentStore, { AttachmentId } from '@deepseek-ai/dsh-attachment' import type { - FileAttachmentRef, ImageAttachmentRef, SaveFileAttachment, SaveFileStreamAttachment, + FileAttachmentRef, ImageAttachmentLimits, ImageAttachmentRef, SaveFileAttachment, SaveFileStreamAttachment, + SaveImageAttachment, } from '@deepseek-ai/dsh-attachment' import { createUserMessage } from '@deepseek-ai/dsh-llm' import type { MessageSource, UserMessage } from '@deepseek-ai/dsh-llm' @@ -21,8 +22,28 @@ import { SessionCommandController } from '../src/commands.ts' import type { SessionRequestId } from '../src/types.ts' const SESSION = SessionId('upload-session') +const IMAGE_LIMITS: ImageAttachmentLimits = { + maxImageBytes: 4, + maxImagesPerMessage: 2, + maxMessageImageBytes: 8, + maxImagePixels: 64, + maxImageDimension: 8, + mediaTypes: ['image/png'], +} +const STAGED_IMAGE: ImageAttachmentRef = { + attachmentId: AttachmentId(`sha256:${'12'.repeat(32)}`), + mediaType: 'image/png', + bytes: 3, + width: 1, + height: 1, + name: 'shot.png', +} -async function uploadHarness(origin?: 'subagent'): Promise<{ +async function* chunks(...parts: readonly number[][]): AsyncIterable { + for (const part of parts) yield Uint8Array.from(part) +} + +async function uploadHarness(origin?: 'subagent', imageLimits: ImageAttachmentLimits = IMAGE_LIMITS): Promise<{ ctx: Context controller: SessionCommandController uploads: FileUploads @@ -31,6 +52,7 @@ async function uploadHarness(origin?: 'subagent'): Promise<{ saveFile: ReturnType saveFileStream: ReturnType saveImages: ReturnType + resolveModelInfo: ReturnType disposeAgent: () => Promise uploadRoute: (request: Request) => Promise }> { @@ -79,10 +101,10 @@ async function uploadHarness(origin?: 'subagent'): Promise<{ bytes, } }) - const saveImages = vi.fn((): Promise => + const saveImages = vi.fn((_inputs: readonly SaveImageAttachment[]): Promise => Promise.reject(new Error('fixture did not expect image persistence'))) ctx.provide('attachments', Object.setPrototypeOf( - { saveFile, saveFileStream, saveImages }, + { saveFile, saveFileStream, saveImages, imageLimits }, AttachmentStore.prototype, ) as never) let uploadRoute: ((request: Request) => Promise) | undefined @@ -94,10 +116,16 @@ async function uploadHarness(origin?: 'subagent'): Promise<{ }, }, } as never) + const resolveModelInfo = vi.fn((): Promise<{ + readonly provider: string + readonly id: string + readonly name: string + readonly inputModalities?: readonly string[] + }> => Promise.resolve({ provider: 'fixture', id: 'fixture-model', name: 'Fixture' })) ctx.provide('llm', { listModels: async () => [{ id: 'fixture-model', name: 'Model' }], listProviders: () => [{ id: 'fixture', name: 'Fixture' }], - resolveModelInfo: () => Promise.resolve({ provider: 'fixture', id: 'fixture-model', name: 'Fixture' }), + resolveModelInfo, } as never) const agents = new ApiSessionAgentController(ctx) vi.spyOn(agents, 'resolveAgent').mockResolvedValue({ agent }) @@ -112,6 +140,7 @@ async function uploadHarness(origin?: 'subagent'): Promise<{ saveFile, saveFileStream, saveImages, + resolveModelInfo, disposeAgent, uploadRoute, } @@ -142,7 +171,7 @@ describe('Session file uploads', () => { expect(saveFile).toHaveBeenCalledTimes(1) expect(receipt.file.name).toBe('notes.pdf') expect(receipt.file.bytes).toBe(3) - expect(uploads.resolve(agent, receipt.receiptId)).toEqual(receipt.file) + expect(uploads.resolve(agent, receipt.receiptId)).toEqual({ type: 'file', attachment: receipt.file }) expect(uploads.resolve(agent, 'missing' as FileUploadReceiptId)).toBeUndefined() const commandHandler = vi.fn((_invocation: unknown) => ({ kind: 'success' as const })) ctx.commands.register({ @@ -203,6 +232,116 @@ describe('Session file uploads', () => { ]) }) + it('stages an uploaded image and admits its receipt as that image, which commands do not accept', async () => { + const { ctx, controller, uploads, agent, followup, saveImages } = await uploadHarness() + saveImages.mockResolvedValueOnce([STAGED_IMAGE]) + const receipt = await uploads.uploadImageStream({ + sessionId: SESSION, data: chunks([1, 2], [3, 4]), mediaType: 'image/png', name: 'shot.png', + }) + expect(saveImages).toHaveBeenCalledWith([{ data: Uint8Array.of(1, 2, 3, 4), mediaType: 'image/png', name: 'shot.png' }]) + expect(receipt.image).toEqual(STAGED_IMAGE) + expect(uploads.resolve(agent, receipt.receiptId)).toEqual({ type: 'image', attachment: STAGED_IMAGE, encodedBytes: 4 }) + const commandHandler = vi.fn((_invocation: unknown) => ({ kind: 'success' as const })) + ctx.commands.register({ + name: 'files', description: 'Use staged files', input: { hint: '', attachments: true }, + handler: commandHandler, + }) + await ctx.commands.execute( + agent, + '/files inspect', + [{ type: 'file', receiptId: receipt.receiptId }], + new AbortController().signal, + ) + expect(commandHandler).not.toHaveBeenCalled() + await controller.prompt(promptRequest([ + { type: 'file', receiptId: receipt.receiptId }, + { type: 'text', text: 'look' }, + ]), USER_SOURCE) + expect((followup.mock.calls[0]?.[0] as UserMessage).content).toEqual([ + { type: 'image', attachment: STAGED_IMAGE }, + { type: 'text', text: 'look' }, + ]) + expect(saveImages).toHaveBeenCalledTimes(1) + }) + + it('refuses an uploaded image for a model without image input', async () => { + const { controller, uploads, followup, saveImages, resolveModelInfo } = await uploadHarness() + saveImages.mockResolvedValueOnce([STAGED_IMAGE]) + const receipt = await uploads.uploadImageStream({ sessionId: SESSION, data: chunks([1]), mediaType: 'image/png' }) + resolveModelInfo.mockResolvedValue({ provider: 'fixture', id: 'fixture-model', name: 'Fixture', inputModalities: ['text'] }) + await expect(controller.prompt(promptRequest([{ type: 'file', receiptId: receipt.receiptId }]), USER_SOURCE)) + .rejects.toMatchObject({ code: 'session/attachment-invalid', details: { reason: 'MODEL_DOES_NOT_SUPPORT_IMAGES' } }) + expect(followup).not.toHaveBeenCalled() + }) + + it('refuses image receipts whose uploads together exceed the message image-byte limit', async () => { + const { controller, uploads, followup, saveImages } = await uploadHarness(undefined, { + ...IMAGE_LIMITS, maxMessageImageBytes: 5, + }) + saveImages.mockResolvedValue([STAGED_IMAGE]) + const first = await uploads.uploadImageStream({ sessionId: SESSION, data: chunks([1, 2, 3]), mediaType: 'image/png' }) + const second = await uploads.uploadImageStream({ sessionId: SESSION, data: chunks([4, 5, 6]), mediaType: 'image/png' }) + await expect(controller.prompt(promptRequest([ + { type: 'file', receiptId: first.receiptId }, + { type: 'file', receiptId: second.receiptId }, + ]), USER_SOURCE)).rejects.toMatchObject({ code: 'session/attachment-invalid', details: { reason: 'IMAGES_TOO_LARGE' } }) + expect(followup).not.toHaveBeenCalled() + }) + + it('issues no receipt for an image upload cancelled after its last chunk or during storage', async () => { + const { uploads, saveImages } = await uploadHarness() + const afterBody = new AbortController() + await expect(uploads.uploadImageStream({ + sessionId: SESSION, + data: (async function* (): AsyncIterable { + yield Uint8Array.of(1, 2, 3) + afterBody.abort() + })(), + mediaType: 'image/png', + signal: afterBody.signal, + })).rejects.toThrow('failed to store file upload: AbortError') + expect(saveImages).not.toHaveBeenCalled() + const duringStorage = new AbortController() + const stored = Promise.withResolvers() + saveImages.mockReturnValueOnce(stored.promise) + const uploading = uploads.uploadImageStream({ + sessionId: SESSION, data: chunks([1, 2, 3]), mediaType: 'image/png', signal: duringStorage.signal, + }) + await vi.waitFor(() => { expect(saveImages).toHaveBeenCalledOnce() }) + duringStorage.abort() + stored.resolve([STAGED_IMAGE]) + // The image whose storage began stays stored; only its receipt is withheld. + await expect(uploading).rejects.toThrow('failed to store file upload: AbortError') + }) + + it('refuses an image past the per-image byte limit without reading further, and an unaccepted type', async () => { + const { uploads, saveImages } = await uploadHarness() + const overLimit = (async function* (): AsyncIterable { + yield Uint8Array.of(1, 2, 3) + yield Uint8Array.of(4, 5) + throw new Error('read past the limit') + })() + await expect(uploads.uploadImageStream({ sessionId: SESSION, data: overLimit, mediaType: 'image/png' })) + .rejects.toMatchObject({ code: 'session/attachment-invalid', details: { reason: 'IMAGE_TOO_LARGE' } }) + await expect(uploads.uploadImageStream({ sessionId: SESSION, data: chunks([1]), mediaType: 'image/bmp' })) + .rejects.toMatchObject({ code: 'session/attachment-invalid', details: { reason: 'UNSUPPORTED_IMAGE_TYPE' } }) + expect(saveImages).not.toHaveBeenCalled() + }) + + it('stops reading an image at the message byte limit when it is below the per-image limit', async () => { + const { uploads, saveImages } = await uploadHarness(undefined, { + ...IMAGE_LIMITS, maxImageBytes: 8, maxMessageImageBytes: 3, + }) + const overLimit = (async function* (): AsyncIterable { + yield Uint8Array.of(1, 2) + yield Uint8Array.of(3, 4) + throw new Error('read past the limit') + })() + await expect(uploads.uploadImageStream({ sessionId: SESSION, data: overLimit, mediaType: 'image/png' })) + .rejects.toMatchObject({ code: 'session/attachment-invalid', details: { reason: 'IMAGE_TOO_LARGE' } }) + expect(saveImages).not.toHaveBeenCalled() + }) + it('keeps the stream name optional and maps storage failures through the same error vocabulary', async () => { const { uploads, saveFileStream } = await uploadHarness() const stream = (async function* (): AsyncIterable {})() @@ -320,6 +459,9 @@ describe('Session file uploads', () => { details: { reason: 'SUBAGENT_FILE_UNSUPPORTED' }, }) expect(child.saveFile).not.toHaveBeenCalled() + await expect(child.uploads.uploadImageStream({ sessionId: SESSION, data: chunks([1]), mediaType: 'image/png' })) + .rejects.toMatchObject({ code: 'subagent/attachment-invalid', details: { reason: 'SUBAGENT_FILE_UNSUPPORTED' } }) + expect(child.saveImages).not.toHaveBeenCalled() }) it('isolates receipts by Session object even when Session ids match', async () => { @@ -335,7 +477,7 @@ describe('Session file uploads', () => { expect(() => owner.uploads.bindPrompt(other.agent, [receipt.receiptId], 'other-prompt')) .toThrow(expect.objectContaining({ code: 'session/attachment-invalid', details: { reason: 'FILE_NOT_STAGED' } })) owner.uploads.retirePrompt(other.agent, 'owner-prompt') - expect(owner.uploads.resolve(owner.agent, receipt.receiptId)).toEqual(receipt.file) + expect(owner.uploads.resolve(owner.agent, receipt.receiptId)).toEqual({ type: 'file', attachment: receipt.file }) owner.uploads.retirePrompt(owner.agent, 'owner-prompt') expect(owner.uploads.resolve(owner.agent, receipt.receiptId)).toBeUndefined() }) @@ -345,9 +487,9 @@ describe('Session file uploads', () => { uploads.retirePrompt(agent, 'not-staged') const receipt = await uploads.upload(agent, { data: 'AAAA' }, new AbortController().signal) await controller.prompt(promptRequest([{ type: 'file', receiptId: receipt.receiptId }]), USER_SOURCE) - expect(uploads.resolve(agent, receipt.receiptId)).toEqual(receipt.file) + expect(uploads.resolve(agent, receipt.receiptId)).toEqual({ type: 'file', attachment: receipt.file }) uploads.retirePrompt(agent, 'other-request') - expect(uploads.resolve(agent, receipt.receiptId)).toEqual(receipt.file) + expect(uploads.resolve(agent, receipt.receiptId)).toEqual({ type: 'file', attachment: receipt.file }) uploads.retirePrompt(agent, 'req-1') expect(uploads.resolve(agent, receipt.receiptId)).toBeUndefined() }) @@ -364,7 +506,7 @@ describe('Session file uploads', () => { content: [{ type: 'text', text: 'extension event' }], source: { kind: 'user', rpcId: 1 } as never, }), { surfaceOp: 'append' }) - expect(first.uploads.resolve(first.agent, observed.receiptId)).toEqual(observed.file) + expect(first.uploads.resolve(first.agent, observed.receiptId)).toEqual({ type: 'file', attachment: observed.file }) first.agent.session.append('user/message', createUserMessage({ content: [{ type: 'text', text: 'observed' }], source: { kind: 'user', rpcId: 'req-1' as SessionRequestId }, @@ -466,7 +608,7 @@ describe('Session file uploads', () => { { type: 'file', receiptId: receipt.receiptId }, ]), USER_SOURCE)).rejects.toMatchObject({ code: 'session/agent-busy' }) uploads.retirePrompt(agent, 'req-1') - expect(uploads.resolve(agent, receipt.receiptId)).toEqual(receipt.file) + expect(uploads.resolve(agent, receipt.receiptId)).toEqual({ type: 'file', attachment: receipt.file }) }) it('retires a prompt-bound receipt when its queued occurrence is removed', async () => { diff --git a/packages/api/session-controller/tests/session-fork.host.spec.ts b/packages/api/session-controller/tests/session-fork.host.spec.ts index 9d407a1378..5b00f060f1 100644 --- a/packages/api/session-controller/tests/session-fork.host.spec.ts +++ b/packages/api/session-controller/tests/session-fork.host.spec.ts @@ -107,8 +107,11 @@ describe('sessions.fork', () => { const ctx = await composed() try { const source = ctx.sessions.prepare(sid('current-cold'), { meta: { cwd: '/proj' } }) + const detach = ctx.effect(() => ctx.sessions.enter(source)) + ctx.sessions.announce(source) source.append('turn/start', { turn: 1 }) source.append('turn/end', { turn: 1, reason: { kind: 'completed' } }) + await detach() const snapshot: SessionPersistenceSnapshot = { header: source.header, revision: SessionPersistenceRevision('test:cold-source'), diff --git a/packages/api/session-controller/tests/session-presets.host.spec.ts b/packages/api/session-controller/tests/session-presets.host.spec.ts index 2308ef77c0..23fcc49df2 100644 --- a/packages/api/session-controller/tests/session-presets.host.spec.ts +++ b/packages/api/session-controller/tests/session-presets.host.spec.ts @@ -122,20 +122,24 @@ async function harness(options: HarnessOptions = {}) { archivedSessionIds: archived, } as never) - /** Run setup on the unpublished Session, then publish it and its Agent, as the Agent factory does. */ + /** Enter the Session for setup, then announce creation as the Agent factory does. */ const publish = async ( session: Session, setup: Parameters[1]['setup'], ): Promise<{ agent: Agent; dispose: () => Promise }> => { const agent = stubAgent(session) ;(agent as { ctx?: Context }).ctx = ctx - await setup?.(ctx, agent) - ctx.effect(function* () { - yield ctx.sessions.enter(session) + const detach = ctx.effect(() => ctx.sessions.enter(session)) + try { ctx.sessions.announce(session) - }, 'test: published Session') - const unregister = await ctx.agents.register(agent) - return { agent, dispose: async () => { await unregister() } } + const commit = await setup?.(ctx, agent) + commit?.commit() + const unregister = await ctx.agents.register(agent) + return { agent, dispose: async () => { await unregister(); await detach() } } + } catch (error) { + await detach() + throw error + } } const factory: AgentFactory = { async createAgent(_ownerCtx, create) { diff --git a/packages/api/session-controller/tests/transport.host.spec.ts b/packages/api/session-controller/tests/transport.host.spec.ts index 66b697fcef..e48b114c91 100644 --- a/packages/api/session-controller/tests/transport.host.spec.ts +++ b/packages/api/session-controller/tests/transport.host.spec.ts @@ -278,11 +278,6 @@ describe('SessionHistoryController', () => { } const seed = [event('fixture/start', SessionSeq(0))] cold(ctx, header, seed) - agentCtx.on('session/created', (session) => { - if (session.id !== sessionId) return - append(session, 'fixture/setup-one', {}) - append(session, 'fixture/setup-two', {}) - }) const abort = new AbortController() const iterator = transport.follow({ address: { kind: 'session', sessionId } }, abort.signal) [Symbol.asyncIterator]() @@ -292,6 +287,8 @@ describe('SessionHistoryController', () => { const attached = agentCtx.sessions.prepare(sessionId, { meta: header, seed }) agentCtx.sessions.enter(attached) agentCtx.sessions.announce(attached) + append(attached, 'fixture/setup-one', {}) + append(attached, 'fixture/setup-two', {}) await expect(iterator.next()).resolves.toMatchObject({ done: false, value: { type: 'event', event: { type: 'session/end-seed', seq: 1 } }, diff --git a/packages/attachment/attachment-local/README.i18n.yaml b/packages/attachment/attachment-local/README.i18n.yaml index 520e5af483..be08b2fdbd 100644 --- a/packages/attachment/attachment-local/README.i18n.yaml +++ b/packages/attachment/attachment-local/README.i18n.yaml @@ -18,8 +18,8 @@ en: 912a19be4b59ff8a zh: 9c14694cf2ebbaf2 /deepseek-ai-dsh-attachment-local/use-this-package/minimal-configuration: - en: b34e09c3236f81f1 - zh: c541b5dc22c8f307 + en: 9597c3d9779cb93d + zh: 900baa94138cc7de /deepseek-ai-dsh-attachment-local/use-this-package/where-your-images-are-stored-and-how-long-they-last: en: 4ee90b8f74baa38c zh: 9c577709ec55eb82 @@ -36,8 +36,8 @@ en: dcd9857653645420 zh: a27259a09f17465d /deepseek-ai-dsh-attachment-local/understand-the-implementation/write-and-read-paths: - en: 609ccc784a87b770 - zh: bc702582cf2b3316 + en: 62ea104a00a7fdb8 + zh: b08575274ca244b4 /deepseek-ai-dsh-attachment-local/understand-the-implementation/source-map: en: 05af85aa85934d01 zh: 1c89e80d496dc0a3 diff --git a/packages/attachment/attachment-local/README.md b/packages/attachment/attachment-local/README.md index 4303813905..4844be3670 100644 --- a/packages/attachment/attachment-local/README.md +++ b/packages/attachment/attachment-local/README.md @@ -38,11 +38,11 @@ Mount the plugin with no required configuration. The defaults below define what | Field | Default | Meaning | |---|---|---| | `dshHome` | resolved | Explicit harness home; omitted follows `$DSH_HOME`, then `~/.dsh` | -| `maxImageBytes` | `20 MiB` | Maximum encoded source bytes accepted for one image | +| `maxImageBytes` | `50 MiB` | Maximum encoded source bytes accepted for one image | | `maxImagesPerMessage` | `20` | Maximum image count accepted in one submitted message | | `maxMessageImageBytes` | `200 MiB` | Maximum aggregate encoded source bytes in one submitted message | | `maxImagePixels` | `64,000,000` | Maximum source width multiplied by height | -| `maxImageDimension` | `8192` | Maximum source width or height | +| `maxImageDimension` | `65,535` | Maximum source width or height; the default leaves admission to `maxImagePixels`, and normalization downscales long sides | | `normalizedImageMaxPixels` | `2048 × 2048` | Total-pixel budget of the stored normalized image | | `normalizedImageMaxDimension` | `8192` | Maximum long edge after applying the total-pixel budget | | `normalizedImageMaxBytes` | `4 MiB` | Encoded-byte target; the smallest quality-ladder output is kept when none fits | @@ -83,7 +83,7 @@ This section explains the durability and verification design behind the storage, Objects land at `/attachments/v1/objects//`; equal bytes deduplicate to one object and one `sha256:` id. Before the first write, the process syncs every ancestor directory of the home down to the filesystem root once, so a directory another process created but has not yet synced is never mistaken for a safe boundary. Writes then stage bytes in `v1/tmp`, sync the temporary file, publish with an atomic exclusive hard link, and sync the publication directories — on Windows, filesystem metadata journaling owns entry durability. Once the save resolves, the reported reference is durable. -Admission accepts up to 20 images and 200 MiB of source bytes per message; one source may use up to 20 MiB, 64 million pixels, and 8192 pixels per side. It applies orientation, removes metadata and color profiles, and normalizes under a 2048×2048 total-pixel budget, an 8192-pixel long edge, and a 4 MiB encoded-byte target. Extreme aspect ratios therefore retain their short-edge resolution. Clean single-frame 8-bit sRGB/sRGBA PNG, JPEG, or WebP input already within those limits passes through byte-identically; GIF, animation, metadata, orientation, 16-bit PNG, and incompatible color spaces force conversion. +Admission accepts up to 20 images and 200 MiB of source bytes per message; one source may use up to 50 MiB, 64 million pixels, and 65,535 pixels per side. It applies orientation, removes metadata and color profiles, and normalizes under a 2048×2048 total-pixel budget, an 8192-pixel long edge, and a 4 MiB encoded-byte target. Extreme aspect ratios therefore retain their short-edge resolution. Clean single-frame 8-bit sRGB/sRGBA PNG, JPEG, or WebP input already within those limits passes through byte-identically; GIF, animation, metadata, orientation, 16-bit PNG, and incompatible color spaces force conversion. Request versions live below `/cache/attachments/request-images/`, resolved by `dshCachePath`; an explicit `dshHome` setting applies to both cache and durable storage. Clearing this cache between requests preserves durable attachments, and later reads regenerate the variants. `readImageRequest` scales without enlargement to the route-chosen target, resizing by the long edge only so the encoder derives the short edge as the route predicts, then applies a separate encoded-byte target through the same alpha routing and quality ladder. Its cache identity includes the attachment id, transform version, target dimensions, byte target, and fixed encoder settings; cached bytes are header-probed for format, 8-bit sRGB/sRGBA, dimensions, and alpha facts, and a mismatch regenerates the entry. Concurrent callers share one transform and cache write, while cancellation stops shared work only when no waiter remains. `imageHostPath` derives the normalized object's host path, and the mounted filesystem may map that path into its execution world without writing it to durable history. diff --git a/packages/attachment/attachment-local/README.zh.md b/packages/attachment/attachment-local/README.zh.md index 4c52dab3ac..a079785984 100644 --- a/packages/attachment/attachment-local/README.zh.md +++ b/packages/attachment/attachment-local/README.zh.md @@ -38,11 +38,11 @@ kind: "package-reference" | 字段 | 默认值 | 含义 | |---|---|---| | `dshHome` | 自动解析 | 显式 harness home;省略时依次跟随 `$DSH_HOME` 与 `~/.dsh` | -| `maxImageBytes` | `20 MiB` | 单张图片接受的最大编码源字节数 | +| `maxImageBytes` | `50 MiB` | 单张图片接受的最大编码源字节数 | | `maxImagesPerMessage` | `20` | 单条提交消息接受的最大图片数量 | | `maxMessageImageBytes` | `200 MiB` | 单条提交消息接受的最大编码源图字节总数 | | `maxImagePixels` | `64,000,000` | 源图宽度与高度乘积的最大值 | -| `maxImageDimension` | `8192` | 源图接受的最大宽度或高度 | +| `maxImageDimension` | `65,535` | 源图接受的最大宽度或高度;默认值让 `maxImagePixels` 单独把关,长边由规范化缩小 | | `normalizedImageMaxPixels` | `2048 × 2048` | 已存规范化图片的总像素预算 | | `normalizedImageMaxDimension` | `8192` | 应用总像素预算后的最大长边 | | `normalizedImageMaxBytes` | `4 MiB` | 编码字节目标;没有候选满足时保留质量阶梯中的最小输出 | @@ -83,7 +83,7 @@ kind: "package-reference" 对象存放在 `/attachments/v1/objects//`;相同字节会去重为同一个对象和同一个 `sha256:` 标识符。首次写入前,进程会把 home 的每个祖先目录逐级同步到文件系统根目录,因此绝不会把另一个进程已创建但尚未同步的目录误认为安全边界。随后,写入过程把字节暂存到 `v1/tmp`、同步临时文件、以原子且排他的硬链接发布,并同步发布目录——在 Windows 上,文件系统元数据日志负责目录项持久性。保存操作完成后,返回的引用已具备持久性。 -准入允许每条消息最多 20 张图片与 200 MiB 源字节;单个源图最多 20 MiB、6400 万像素与单边 8192 像素。系统应用方向、移除元数据与色彩配置,并把规范化结果限制在 2048×2048 总像素预算、8192 像素长边和 4 MiB 编码字节目标内,因此,即使宽高比极端,图片也会保留短边分辨率。已经满足限制的干净、单帧、8-bit sRGB/sRGBA PNG、JPEG 或 WebP 会逐字节直通;GIF、动画、元数据、方向、16-bit PNG 与不兼容色彩空间会触发转换。 +准入允许每条消息最多 20 张图片与 200 MiB 源字节;单个源图最多 50 MiB、6400 万像素与单边 65,535 像素。系统应用方向、移除元数据与色彩配置,并把规范化结果限制在 2048×2048 总像素预算、8192 像素长边和 4 MiB 编码字节目标内,因此,即使宽高比极端,图片也会保留短边分辨率。已经满足限制的干净、单帧、8-bit sRGB/sRGBA PNG、JPEG 或 WebP 会逐字节直通;GIF、动画、元数据、方向、16-bit PNG 与不兼容色彩空间会触发转换。 请求版本位于由 `dshCachePath` 解析的 `/cache/attachments/request-images/`;显式 `dshHome` 设置同时适用于缓存与持久存储。在两次请求之间清空此缓存会保留持久附件,后续读取会重新生成请求版本。`readImageRequest` 在不放大的前提下缩放到路由选定的目标尺寸,缩放只按长边给定,短边由编码器按路由预测的方式推出,随后通过相同的 alpha 路由与质量阶梯应用独立编码字节目标。缓存身份包含附件 id、变换版本、目标尺寸、字节目标与固定编码参数;缓存字节会先通过文件头探测格式、8-bit sRGB/sRGBA、尺寸与 alpha 信息,不匹配时重新生成。并发调用方共享一次变换与缓存写入,且只在没有等待方时由取消停止共享工作。`imageHostPath` 派生规范化对象的宿主路径,挂载的文件系统可以把该路径映射进执行世界,而不会写入持久历史。 diff --git a/packages/attachment/attachment-local/src/index.ts b/packages/attachment/attachment-local/src/index.ts index 34959d088a..2965fef0cc 100644 --- a/packages/attachment/attachment-local/src/index.ts +++ b/packages/attachment/attachment-local/src/index.ts @@ -31,15 +31,19 @@ export type { PreparedImageFile } from './store.ts' export { readRequestImageFile, requestImageVariantId } from './request-image.ts' /** Default maximum encoded bytes for one submitted image; oversized sources are refused, not shrunk. */ -export const DEFAULT_MAX_IMAGE_BYTES = 20 * 1024 * 1024 +export const DEFAULT_MAX_IMAGE_BYTES = 50 * 1024 * 1024 /** Default maximum images in one prompt. */ export const DEFAULT_MAX_IMAGES_PER_MESSAGE = 20 /** Default maximum aggregate image bytes in one prompt. */ export const DEFAULT_MAX_MESSAGE_IMAGE_BYTES = 200 * 1024 * 1024 /** Default maximum intrinsic pixels for one submitted image. */ export const DEFAULT_MAX_IMAGE_PIXELS = 64_000_000 -/** Default per-side pixel cap for one submitted image. */ -export const DEFAULT_MAX_IMAGE_DIMENSION = 8192 +/** + * Default per-side pixel cap for one submitted image: the largest side a JPEG + * can carry. Normalization downscales a long side, so by default the + * decoded-pixel limit alone bounds admission. + */ +export const DEFAULT_MAX_IMAGE_DIMENSION = 65_535 /** * Default total-pixel budget of the stored normalized image. A larger source * is admitted and downscaled proportionally, so admission bounds what rides @@ -61,7 +65,7 @@ export const MAX_IMAGE_COMPRESSION_CONCURRENCY = 8 export interface Config { /** Explicit harness home; omitted follows `DSH_HOME`, then `~/.dsh`. */ dshHome?: string - /** Maximum encoded bytes accepted for one submitted image. Default: 20 MiB. */ + /** Maximum encoded bytes accepted for one submitted image. Default: 50 MiB. */ maxImageBytes?: number /** Maximum image count accepted in one submitted message. Default: 20. */ maxImagesPerMessage?: number @@ -69,7 +73,7 @@ export interface Config { maxMessageImageBytes?: number /** Maximum intrinsic width multiplied by height accepted for one submitted image. Default: 64,000,000. */ maxImagePixels?: number - /** Maximum intrinsic width and maximum intrinsic height accepted for one submitted image. Default: 8192px. */ + /** Maximum intrinsic width and maximum intrinsic height accepted for one submitted image. Default: 65,535px. */ maxImageDimension?: number /** Total-pixel budget of the stored provider-independent normalized image. */ normalizedImageMaxPixels?: number diff --git a/packages/attachment/attachment-local/tests/index.spec.ts b/packages/attachment/attachment-local/tests/index.spec.ts index 00a427e16e..6482190ebe 100644 --- a/packages/attachment/attachment-local/tests/index.spec.ts +++ b/packages/attachment/attachment-local/tests/index.spec.ts @@ -21,11 +21,11 @@ import LocalAttachmentStore, { describe('local attachment service', () => { it('resolves every omitted admission limit explicitly', () => { const service = new LocalAttachmentStore(new Context(), {}) - expect(DEFAULT_MAX_IMAGE_BYTES).toBe(20 * 1024 * 1024) + expect(DEFAULT_MAX_IMAGE_BYTES).toBe(50 * 1024 * 1024) expect(DEFAULT_MAX_IMAGES_PER_MESSAGE).toBe(20) expect(DEFAULT_MAX_MESSAGE_IMAGE_BYTES).toBe(200 * 1024 * 1024) expect(DEFAULT_MAX_IMAGE_PIXELS).toBe(64_000_000) - expect(DEFAULT_MAX_IMAGE_DIMENSION).toBe(8192) + expect(DEFAULT_MAX_IMAGE_DIMENSION).toBe(65_535) expect(service.imageLimits).toEqual({ maxImageBytes: DEFAULT_MAX_IMAGE_BYTES, maxImagesPerMessage: DEFAULT_MAX_IMAGES_PER_MESSAGE, diff --git a/packages/attachment/attachment/README.i18n.yaml b/packages/attachment/attachment/README.i18n.yaml index 4f941409fe..b2b7ba57ad 100644 --- a/packages/attachment/attachment/README.i18n.yaml +++ b/packages/attachment/attachment/README.i18n.yaml @@ -39,8 +39,8 @@ en: af7deef72fd2fa93 zh: f217d52ce3971135 /deepseek-ai-dsh-attachment/understand-the-implementation/service-operations: - en: 4a35cdba790c3b8b - zh: 08d4a18bbad4b182 + en: b94d13fe133d8ce6 + zh: dd4064d20d510afc /deepseek-ai-dsh-attachment/understand-the-implementation/source-map: en: 4fb4c96184c38169 zh: 015b06e4bfff4fcd diff --git a/packages/attachment/attachment/README.md b/packages/attachment/attachment/README.md index 43eb4d8ae8..2acdc13c42 100644 --- a/packages/attachment/attachment/README.md +++ b/packages/attachment/attachment/README.md @@ -72,7 +72,7 @@ This section explains the design decisions behind the seam and the service opera ### Service operations -The service family runs one admission-and-storage flow: every entry point enforces source batch limits and canonical base64, prepares provider-independent normalized attachments before publishing any member, and commits them durably in input order without partial results. Host prompt consumers pass ordered text, encoded images, and already resolved file references to `ctx.attachments.admitPromptContent()`; the method persists images and passes file references unchanged. Encoded protocol adapters call `ctx.attachments.admitEncodedFile()`, which checks canonical base64 before delegating to `saveFile`; adapters recognize attachment failures through `ctx.attachments.isAttachmentError()`. Generic-file callers choose `saveFile` for existing bytes or `saveFileStream` for a bounded asynchronous byte source; both return the same durable reference, while `readFileStream` verifies its digest and length during a bounded read. `readImageRequest` derives deterministic route-sized variants whose identity includes the attachment id, transform version, target dimensions, byte target, and encoder settings. The pure `requestImageDimensions` and `longEdgeDimensions` exports compute aspect-preserving dimensions from a total-pixel budget or an exact long edge, so routes and request pricing share one geometry. `imageHostPath` exposes an implementation-owned host location only to trusted same-process consumers that need execution-world mapping. Callers compose ordered batches while the implementation owns compression concurrency, caching, and singleflight. Reads, streamed writes, and projections preserve caller cancellation. Failures carry stable machine-readable codes, and the caller-correctable admission subset is recognizable at runtime so each protocol adapter maps its own vocabulary; the exact per-operation contracts live in [`src/index.ts`](src/index.ts) and [`src/error.ts`](src/error.ts). +The service family runs one admission-and-storage flow: every entry point enforces source batch limits and canonical base64, prepares provider-independent normalized attachments before publishing any member, and commits them durably in input order without partial results. Host prompt consumers pass ordered text, encoded images, and already resolved file and image references to `ctx.attachments.admitPromptContent()`; the method persists the encoded images, passes references unchanged, and counts every image toward the per-message image count and aggregate byte limits, a stored image by the bytes of the upload that stored it. Encoded protocol adapters call `ctx.attachments.admitEncodedFile()`, which checks canonical base64 before delegating to `saveFile`; adapters recognize attachment failures through `ctx.attachments.isAttachmentError()`. Generic-file callers choose `saveFile` for existing bytes or `saveFileStream` for a bounded asynchronous byte source; both return the same durable reference, while `readFileStream` verifies its digest and length during a bounded read. `readImageRequest` derives deterministic route-sized variants whose identity includes the attachment id, transform version, target dimensions, byte target, and encoder settings. The pure `requestImageDimensions` and `longEdgeDimensions` exports compute aspect-preserving dimensions from a total-pixel budget or an exact long edge, so routes and request pricing share one geometry. `imageHostPath` exposes an implementation-owned host location only to trusted same-process consumers that need execution-world mapping. Callers compose ordered batches while the implementation owns compression concurrency, caching, and singleflight. Reads, streamed writes, and projections preserve caller cancellation. Failures carry stable machine-readable codes, and the caller-correctable admission subset is recognizable at runtime so each protocol adapter maps its own vocabulary; the exact per-operation contracts live in [`src/index.ts`](src/index.ts) and [`src/error.ts`](src/error.ts). ### Source map diff --git a/packages/attachment/attachment/README.zh.md b/packages/attachment/attachment/README.zh.md index 4fa95d20f3..06cbe5631a 100644 --- a/packages/attachment/attachment/README.zh.md +++ b/packages/attachment/attachment/README.zh.md @@ -72,7 +72,7 @@ kind: "package-reference" ### 服务操作 -服务族运行同一条准入与存储流程:每个入口都强制执行源批次限制与规范 base64,在发布任何成员前准备提供方无关的规范化附件,再按输入顺序持久提交而不产生部分结果。Host 提示词消费方把有序文本、编码图片和已经解析的文件引用交给 `ctx.attachments.admitPromptContent()`;该方法持久化图片,并让文件引用原样通过。编码协议适配器调用 `ctx.attachments.admitEncodedFile()`,由该方法检查规范 base64 后委托给 `saveFile`;适配器通过 `ctx.attachments.isAttachmentError()` 识别附件错误。通用文件调用方可以用 `saveFile` 提交已有字节,或用 `saveFileStream` 提交有界异步字节源;两者返回相同的持久引用,`readFileStream` 则在有界读取过程中校验摘要与长度。`readImageRequest` 派生确定性的路由尺寸变体,其身份包含附件 id、变换版本、目标尺寸、字节目标及编码参数。纯函数导出 `requestImageDimensions` 与 `longEdgeDimensions` 按总像素预算或精确长边计算保持宽高比的尺寸,使路由与请求定价共享同一套几何计算。`imageHostPath` 只向需要把该位置映射到执行环境的受信任同进程消费方暴露实现拥有的宿主位置。调用方组合有序批次,而实现负责管理压缩并发、缓存与 singleflight。读取、流式写入和投影保留调用方的取消语义。失败带有稳定且机器可读的错误码,运行时即可识别可由调用方修正的准入子集,让每个协议适配器映射自己的词汇;各操作的确切约定见 [`src/index.ts`](src/index.ts) 与 [`src/error.ts`](src/error.ts)。 +服务族运行同一条准入与存储流程:每个入口都强制执行源批次限制与规范 base64,在发布任何成员前准备提供方无关的规范化附件,再按输入顺序持久提交而不产生部分结果。Host 提示词消费方把有序文本、编码图片和已经解析的文件与图片引用交给 `ctx.attachments.admitPromptContent()`;该方法持久化编码图片,让引用原样通过,并把每张图片计入单条消息的图片数量与总字节上限,已存储的图片按存储它的那次上传的字节数计入。编码协议适配器调用 `ctx.attachments.admitEncodedFile()`,由该方法检查规范 base64 后委托给 `saveFile`;适配器通过 `ctx.attachments.isAttachmentError()` 识别附件错误。通用文件调用方可以用 `saveFile` 提交已有字节,或用 `saveFileStream` 提交有界异步字节源;两者返回相同的持久引用,`readFileStream` 则在有界读取过程中校验摘要与长度。`readImageRequest` 派生确定性的路由尺寸变体,其身份包含附件 id、变换版本、目标尺寸、字节目标及编码参数。纯函数导出 `requestImageDimensions` 与 `longEdgeDimensions` 按总像素预算或精确长边计算保持宽高比的尺寸,使路由与请求定价共享同一套几何计算。`imageHostPath` 只向需要把该位置映射到执行环境的受信任同进程消费方暴露实现拥有的宿主位置。调用方组合有序批次,而实现负责管理压缩并发、缓存与 singleflight。读取、流式写入和投影保留调用方的取消语义。失败带有稳定且机器可读的错误码,运行时即可识别可由调用方修正的准入子集,让每个协议适配器映射自己的词汇;各操作的确切约定见 [`src/index.ts`](src/index.ts) 与 [`src/error.ts`](src/error.ts)。 ### 源码地图 diff --git a/packages/attachment/attachment/src/index.ts b/packages/attachment/attachment/src/index.ts index d5854336db..ba7f567884 100644 --- a/packages/attachment/attachment/src/index.ts +++ b/packages/attachment/attachment/src/index.ts @@ -1,5 +1,6 @@ /** Durable attachment storage seam (`ctx.attachments`). @module @deepseek-ai/dsh-attachment */ +import { Buffer } from 'node:buffer' import { Context, Service } from '@deepseek-ai/cordis' import { admitEncodedFile as admitFileInput, admitEncodedImages } from './admission.ts' import { AttachmentError, isAttachmentError as matchesAttachmentError } from './error.ts' @@ -11,6 +12,7 @@ import type { ImageAttachmentLimits, ImageAttachmentRef, ImageRequestTarget, + PromptContentPart, RequestImageAttachment, SaveFileAttachment, SaveFileStreamAttachment, @@ -49,6 +51,28 @@ declare module '@deepseek-ai/cordis' { } } +/** Whether one admission part still carries encoded image bytes. */ +function isEncodedImage(part: AttachmentAdmissionPart): part is Extract { + return part.type === 'image' && !('attachment' in part) +} + +/** Whether one admission part references an image an earlier upload stored. */ +function isStoredImage( + part: AttachmentAdmissionPart, +): part is Extract { + return part.type === 'image' && 'attachment' in part +} + +/** Refuse one message whose images exceed the configured count or aggregate byte limit. */ +function assertMessageImages(limits: ImageAttachmentLimits, count: number, bytes: number): void { + if (count > limits.maxImagesPerMessage) { + throw new AttachmentError('Image batch exceeds the configured image-count limit.', 'TOO_MANY_IMAGES') + } + if (bytes > limits.maxMessageImageBytes) { + throw new AttachmentError('Image batch exceeds the configured aggregate image-byte limit.', 'IMAGES_TOO_LARGE') + } +} + /** Immutable binary attachment service. Implementations validate bytes before publishing a reference. */ export abstract class AttachmentStore extends Service { constructor(ctx: Context) { @@ -75,16 +99,10 @@ export abstract class AttachmentStore extends Service { * @returns durable references in the exact input order. */ protected validateImageBatch(inputs: readonly SaveImageAttachment[]): void { - const { maxImagesPerMessage, maxMessageImageBytes, mediaTypes } = this.imageLimits - if (inputs.length > maxImagesPerMessage) { - throw new AttachmentError('Image batch exceeds the configured image-count limit.', 'TOO_MANY_IMAGES') - } - const totalBytes = inputs.reduce((sum, input) => sum + input.data.byteLength, 0) - if (totalBytes > maxMessageImageBytes) { - throw new AttachmentError('Image batch exceeds the configured aggregate image-byte limit.', 'IMAGES_TOO_LARGE') - } + const limits = this.imageLimits + assertMessageImages(limits, inputs.length, inputs.reduce((sum, input) => sum + input.data.byteLength, 0)) for (const input of inputs) { - if (!mediaTypes.includes(input.mediaType)) { + if (!limits.mediaTypes.includes(input.mediaType)) { throw new AttachmentError(`Image type ${input.mediaType} is not accepted by this deployment.`, 'UNSUPPORTED_IMAGE_TYPE') } } @@ -105,25 +123,35 @@ export abstract class AttachmentStore extends Service { } /** - * Admit one Host prompt and replace each uploaded image with its durable reference. - * Text and durable file references pass through unchanged. A prompt without image parts performs no storage operation. - * @param content - prompt parts in message order after file receipt resolution. + * Admit one Host prompt and replace each encoded image with its durable reference. + * Text, durable file references, and already stored images pass through unchanged. + * Every image part counts toward `maxImagesPerMessage` and `maxMessageImageBytes`; + * a stored image counts the bytes of the upload that stored it. Refused content + * starts no writes. A prompt without encoded images performs no storage operation. + * @param content - prompt parts in message order after upload receipt resolution. * @returns admitted prompt parts in the same order as `content`. * @throws AttachmentError when the image batch is refused. */ async admitPromptContent( content: readonly AttachmentAdmissionPart[], ): Promise { - if (content.every(part => part.type !== 'image')) { - return content.map(part => part.type === 'text' - ? { type: 'text', text: part.text } - : { type: 'file', attachment: part.attachment }) + const encoded = content.filter(isEncodedImage) + const stored = content.filter(isStoredImage) + // Each upload passed the limits alone; the encoded batch below checks only itself. + if (stored.length > 0) { + assertMessageImages( + this.imageLimits, + encoded.length + stored.length, + encoded.reduce((sum, part) => sum + Buffer.byteLength(part.data, 'base64'), 0) + + stored.reduce((sum, part) => sum + part.encodedBytes, 0), + ) } - const refs = await admitEncodedImages(this, content.filter(part => part.type === 'image')) + const refs = encoded.length === 0 ? [] : await admitEncodedImages(this, encoded) let next = 0 return content.map((part) => { if (part.type === 'text') return { type: 'text', text: part.text } if (part.type === 'file') return { type: 'file', attachment: part.attachment } + if ('attachment' in part) return { type: 'image', attachment: part.attachment } return { type: 'image', attachment: refs[next++] as ImageAttachmentRef } }) } diff --git a/packages/attachment/attachment/src/types.ts b/packages/attachment/attachment/src/types.ts index 455d6c9de0..bc84ed6654 100644 --- a/packages/attachment/attachment/src/types.ts +++ b/packages/attachment/attachment/src/types.ts @@ -106,10 +106,16 @@ export type PromptContentPart = readonly name?: string } -/** Host prompt content whose file receipts are resolved and whose image bytes await admission. */ +/** + * Host prompt content whose upload receipts are resolved. An image part + * carries encoded bytes awaiting admission, or references an image this + * service already stored for an upload the same Session staged, with + * `encodedBytes` holding the byte length of that upload. + */ export type AttachmentAdmissionPart = | PromptContentPart | { readonly type: 'file'; readonly attachment: FileAttachmentRef } + | { readonly type: 'image'; readonly attachment: ImageAttachmentRef; readonly encodedBytes: number } /** Host-admitted prompt content with every attachment represented by its durable reference. */ export type AdmittedPromptContentPart = diff --git a/packages/attachment/attachment/tests/admission.spec.ts b/packages/attachment/attachment/tests/admission.spec.ts index 71c56c0fed..bc50c6068a 100644 --- a/packages/attachment/attachment/tests/admission.spec.ts +++ b/packages/attachment/attachment/tests/admission.spec.ts @@ -10,6 +10,13 @@ const FILE_REF: FileAttachmentRef = { name: 'notes.md', bytes: 12, } +const STORED_REF: ImageAttachmentRef = { + attachmentId: 'stored-1' as ImageAttachmentRef['attachmentId'], + mediaType: 'image/png', + bytes: 8, + width: 2, + height: 2, +} /** Delegation double: records the exact saveImages batch and answers ordered refs. */ function storeOf() { @@ -138,4 +145,50 @@ describe('AttachmentStore.admitPromptContent', () => { { type: 'image', attachment: { attachmentId: 'att-2', mediaType: 'image/png', bytes: 1, width: 1, height: 1 } }, ]) }) + + it('passes stored images through in part order and stores only the encoded ones', async () => { + const { store, mocks } = storeOf() + // The stored upload's 4 bytes and the encoded byte fill the budget exactly; the normalized 8 bytes do not count. + Object.defineProperty(store, 'imageLimits', { value: { maxImagesPerMessage: 2, maxMessageImageBytes: 5 } }) + await expect(store.admitPromptContent([ + { type: 'image', attachment: STORED_REF, encodedBytes: 4 }, + { type: 'text', text: 'between' }, + { type: 'image', mediaType: 'image/png', data: 'AQ==' }, + ])).resolves.toEqual([ + { type: 'image', attachment: STORED_REF }, + { type: 'text', text: 'between' }, + { type: 'image', attachment: { attachmentId: 'att-1', mediaType: 'image/png', bytes: 1, width: 1, height: 1 } }, + ]) + expect(mocks.saveImages).toHaveBeenCalledTimes(1) + expect((mocks.saveImages.mock.calls[0]?.[0] as readonly SaveImageAttachment[]).length).toBe(1) + }) + + it('counts stored images toward the image-count limit before storing anything', async () => { + const { store, mocks } = storeOf() + Object.defineProperty(store, 'imageLimits', { value: { maxImagesPerMessage: 1, maxMessageImageBytes: 100 } }) + await expect(store.admitPromptContent([ + { type: 'image', attachment: STORED_REF, encodedBytes: 1 }, + { type: 'image', mediaType: 'image/png', data: 'AQ==' }, + ])).rejects.toMatchObject({ code: 'TOO_MANY_IMAGES' }) + await expect(store.admitPromptContent([ + { type: 'image', attachment: STORED_REF, encodedBytes: 1 }, + { type: 'image', attachment: { ...STORED_REF, attachmentId: 'stored-2' as ImageAttachmentRef['attachmentId'] }, encodedBytes: 1 }, + ])).rejects.toMatchObject({ code: 'TOO_MANY_IMAGES' }) + expect(mocks.saveImages).not.toHaveBeenCalled() + }) + + it('counts stored upload bytes with encoded bytes toward the message byte limit before storing anything', async () => { + const { store, mocks } = storeOf() + Object.defineProperty(store, 'imageLimits', { value: { maxImagesPerMessage: 4, maxMessageImageBytes: 5 } }) + // Two 3-byte uploads each fit alone; together they exceed one message. + await expect(store.admitPromptContent([ + { type: 'image', attachment: STORED_REF, encodedBytes: 3 }, + { type: 'image', attachment: { ...STORED_REF, attachmentId: 'stored-2' as ImageAttachmentRef['attachmentId'] }, encodedBytes: 3 }, + ])).rejects.toMatchObject({ code: 'IMAGES_TOO_LARGE' }) + await expect(store.admitPromptContent([ + { type: 'image', attachment: STORED_REF, encodedBytes: 3 }, + { type: 'image', mediaType: 'image/png', data: PNG }, + ])).rejects.toMatchObject({ code: 'IMAGES_TOO_LARGE' }) + expect(mocks.saveImages).not.toHaveBeenCalled() + }) }) diff --git a/packages/boot/README.i18n.yaml b/packages/boot/README.i18n.yaml index cc38560dae..8ecc1fc6e8 100644 --- a/packages/boot/README.i18n.yaml +++ b/packages/boot/README.i18n.yaml @@ -15,8 +15,8 @@ en: 09848f4d056e4fc1 zh: 8df6139cff0288f6 /boot-shared-app-bin-boot-glue/packages: - en: 626cbd4bc04cf9bb - zh: 3c2f6154e58908c2 + en: 71736c39fd71952c + zh: 2033a18debd8a2d8 /boot-shared-app-bin-boot-glue/related-documentation: en: 77af4b40ee7b98a3 zh: e9b4e817823b973d diff --git a/packages/boot/README.md b/packages/boot/README.md index 7d657279b5..d3d6610d1c 100644 --- a/packages/boot/README.md +++ b/packages/boot/README.md @@ -23,6 +23,7 @@ The boot group launches profile applications and manages their installed composi | Package | Role | ctx key | |---|---|---| | [`app-boot`](app-boot/README.md) | Boots a dsh app from a `cordis.yml`: loads `.env`, applies profile and patch layers, and reports startup failures clearly | (library for the bins) | +| [`official-bundles`](official-bundles/README.md) | Lists the bundles the installation ships in profile templates, offers switched off, installs on demand, or retires | (library) | | [`cmdline`](cmdline/README.md) | Lets the app own its flags, `--help`, and exit code; passes everything after the launcher's flags through verbatim | `cmdlineArgs`, `appExit` | | [`hmr`](hmr/README.md) | Coordinates module and configuration reloads with package mutations | `hmr` | | [`config-editor`](config-editor/README.md) | Persists active profile configuration through Loader reconciliation | `configEditor` | diff --git a/packages/boot/README.zh.md b/packages/boot/README.zh.md index a4b30225cf..12c9b32d7d 100644 --- a/packages/boot/README.zh.md +++ b/packages/boot/README.zh.md @@ -23,6 +23,7 @@ boot 组负责启动 profile 应用并管理其已安装组合。`app-boot` 解 | 包 | 职责 | ctx 键 | |---|---|---| | [`app-boot`](app-boot/README.zh.md) | 从 `cordis.yml` 启动 dsh 应用:加载 `.env`、应用 profile 与 patch 层,并清晰报告启动失败 | (供各 bin 使用的库) | +| [`official-bundles`](official-bundles/README.zh.md) | 列出安装随附于 profile 模板、默认关闭提供、按需安装或已退役的组合包 | (库) | | [`cmdline`](cmdline/README.zh.md) | 让应用持有自己的 flag、`--help` 与退出码;启动器自身 flag 之后的一切原样传入 | `cmdlineArgs`、`appExit` | | [`hmr`](hmr/README.zh.md) | 协调模块与配置重载,并与包修改互斥执行 | `hmr` | | [`config-editor`](config-editor/README.zh.md) | 通过 Loader 应用并持久化当前 profile 配置 | `configEditor` | diff --git a/packages/boot/app-boot/README.i18n.yaml b/packages/boot/app-boot/README.i18n.yaml index 82f7210aef..7170485221 100644 --- a/packages/boot/app-boot/README.i18n.yaml +++ b/packages/boot/app-boot/README.i18n.yaml @@ -33,8 +33,8 @@ en: c4a301652b851ce9 zh: 784871e19cd9db0a /deepseek-ai-dsh-app-boot/use-this-package/reading-plugin-display-metadata: - en: a9afb263b03d112c - zh: 31f5e797cd953c15 + en: b737278c1bc065e7 + zh: f42bdbfe267581d1 /deepseek-ai-dsh-app-boot/use-this-package/startup-and-reload-failures: en: dc13dfa1f79292e4 zh: d51682ced7a18ac2 diff --git a/packages/boot/app-boot/README.md b/packages/boot/app-boot/README.md index 39b2684db0..53c72680be 100644 --- a/packages/boot/app-boot/README.md +++ b/packages/boot/app-boot/README.md @@ -86,7 +86,7 @@ The projector preserves native omission behavior by checking literal defaults ag Use `readPluginMeta(specifier, parentURL)` or `ctx.pluginPackages.metaOf(specifier, parentURL)` to read installed package display text without importing or activating the plugin. Lookup uses the complete package specifier and the caller's resolution base, respecting Node exports. File paths and file URLs return no metadata without resolving resources. For a package-root specifier, missing locale fields fall back to the accessible `package.json`; a subpath specifier never reads a `package.json`. Malformed metadata returns an `error` diagnostic. Results retain translations for Client-side language selection. The reader also loads an image data URL, even when locale text is complete: a package root uses its manifest `icon`, or `/icon` when that field is omitted; a subpath uses `/icon`. An icon error preserves valid text alongside the diagnostic. See [Plugin display metadata](../../../docs/cookbook/adding-a-package.md#plugin-display-metadata) for the author format. -`ON_DEMAND_BUNDLES` names the public Official packages installed only on request. `OFFICIAL_ON_DEMAND_CATALOG` embeds their package-owned localized metadata and icons for offline discovery; `pnpm gen-official-bundle-catalog` explicitly updates generated content, and `verify-official-bundle-catalog` checks resource completeness and freshness; builds consume the committed catalog without importing provider code. The catalog contains no install target: [Plugin Manager](../plugin-manager/README.md#use-this-package) derives it from the running version and installation and uses the ordinary bundle installer. The [product-use check](../../../scripts/verify-product-use.ts) composes shipped and on-demand selections against Web without executing providers. +The profile templates, installation-owned profile tuples, and retired bundle list that app-boot applies live in [`@deepseek-ai/dsh-official-bundles`](../official-bundles/README.md), together with the installation's default, optional, and on-demand bundle lists. ### Startup and reload failures diff --git a/packages/boot/app-boot/README.zh.md b/packages/boot/app-boot/README.zh.md index 04d9237ea0..a22b7eabab 100644 --- a/packages/boot/app-boot/README.zh.md +++ b/packages/boot/app-boot/README.zh.md @@ -86,7 +86,7 @@ profile 导入插件前,DSH 会将其声明的 DSH 版本要求与 `getDshRunt 使用 `readPluginMeta(specifier, parentURL)` 或 `ctx.pluginPackages.metaOf(specifier, parentURL)` 读取已安装包的展示文本,无需导入或激活插件。查询使用完整包标识与调用方的解析基准,并遵循 Node exports。文件路径与文件 URL 不解析资源,直接返回无元信息。包根标识缺失的 locale 字段回退到可访问的 `package.json`;子路径标识从不读取 `package.json`。格式错误的元信息返回 `error` 诊断。结果保留翻译,由 Client 选择语言。即使 locale 文本完整,读取器也会加载图片 data URL:包根使用清单 `icon`,省略该字段时使用 `<包名>/icon`;子路径使用 `<标识>/icon`。图标出错时,保留有效文本并附上诊断。作者格式见[插件展示元信息](../../../docs/cookbook/adding-a-package.zh.md#plugin-display-metadata)。 -`ON_DEMAND_BUNDLES` 列出仅按需安装的官方公开包。`OFFICIAL_ON_DEMAND_CATALOG` 内嵌这些包拥有的本地化元信息和图标,支持离线发现;`pnpm gen-official-bundle-catalog` 显式更新生成内容,`verify-official-bundle-catalog` 检查资源完整性与新鲜度;构建只读取已提交的目录,不导入提供者代码。目录不保存安装目标;[插件管理器](../plugin-manager/README.zh.md#use-this-package)根据当前版本和安装位置确定目标,并使用普通组合包安装器。[产品用途检查](../../../scripts/verify-product-use.ts)将随附和按需选择与 Web 组合,但不执行提供者。 +app-boot 应用的 profile 模板、安装方拥有的 profile 组合包元组和已退役组合包列表位于 [`@deepseek-ai/dsh-official-bundles`](../official-bundles/README.zh.md),安装方的默认、可选和按需组合包列表也在该包中。 ### 启动与重载失败 diff --git a/packages/boot/app-boot/package.json b/packages/boot/app-boot/package.json index b1bceec433..1db32358de 100644 --- a/packages/boot/app-boot/package.json +++ b/packages/boot/app-boot/package.json @@ -33,6 +33,7 @@ "license": "MIT", "dependencies": { "@deepseek-ai/dsh-atomic-write": "workspace:*", + "@deepseek-ai/dsh-official-bundles": "workspace:*", "@deepseek-ai/dsh-package-manifest": "workspace:*", "@eslint-community/regexpp": "^4.12.2", "ajv": "^8.20.0", diff --git a/packages/boot/app-boot/src/index.ts b/packages/boot/app-boot/src/index.ts index 67c8618b9d..fb68e4ba08 100644 --- a/packages/boot/app-boot/src/index.ts +++ b/packages/boot/app-boot/src/index.ts @@ -29,7 +29,6 @@ import { ProfileRuntimeResolution, type RuntimeResolution } from './profile.ts' import { ResolutionRestartRequired } from './profile-resolution/resolver.ts' export { prepareProfileEntries, prepareProfilePatches } from './compatibility-preflight.ts' export { readPluginMeta, resolvePluginResource } from './package-meta.ts' -export { ON_DEMAND_BUNDLES, OFFICIAL_ON_DEMAND_CATALOG, type OfficialBundleCatalogEntry } from './official-bundles.ts' export { generateConfigSchema, type ConfigSchemaDump, type NativeConfigSchema } from './config-schema/index.ts' export { createConfigProjector, LOADER_EXPRESSION_SCHEMA, type ConfigProjection } from './config-schema/projector.ts' export { isNativeConfigSchema } from './config-schema/native.ts' @@ -59,8 +58,6 @@ export { composeEntries, createRuntimeResolution, ProfileRuntimeResolution, - DEFAULT_PROFILE_BUNDLES, - OPTIONAL_BUNDLES, bundlePatchFiles, bundlePatchPaths, initProfile, @@ -68,7 +65,6 @@ export { loadProfile, loadProfileDirectory, PROFILE_PATCH_FILENAME, - PROFILE_TEMPLATES, PROFILES_DIR, readProfileManifest, reportSkippedBundles, @@ -83,7 +79,6 @@ export { type RuntimeResolutionOptions, type RuntimeResolutionEntry, type RuntimeResolution, - type ProfileTemplate, } from './profile.ts' export { PluginPackages, diff --git a/packages/boot/app-boot/src/official-bundle-packages.ts b/packages/boot/app-boot/src/official-bundle-packages.ts deleted file mode 100644 index b77f9fcdd9..0000000000 --- a/packages/boot/app-boot/src/official-bundle-packages.ts +++ /dev/null @@ -1,7 +0,0 @@ -/** Package admission shared by offline catalog generation and release ordering. */ - -/** Public DSH release members available through the ordinary on-demand bundle installer. */ -export const ON_DEMAND_BUNDLES: readonly string[] = [ - '@deepseek-ai/dsh-subagent-claude-code', - '@deepseek-ai/dsh-subagent-codex', -] diff --git a/packages/boot/app-boot/src/profile.ts b/packages/boot/app-boot/src/profile.ts index 98ff84a21a..1472e06c64 100644 --- a/packages/boot/app-boot/src/profile.ts +++ b/packages/boot/app-boot/src/profile.ts @@ -28,6 +28,7 @@ import type { EntryOptions } from '@deepseek-ai/cordis-plugin-loader' import { applyEntryPatches, type PatchOptions } from '@deepseek-ai/cordis-plugin-include' import { resolveDshHome } from '@deepseek-ai/dsh-home-paths' import type { DshBundleManifest, DshPackageManifest } from '@deepseek-ai/dsh-package-manifest' +import { INSTALLATION_OWNED_PROFILE_TUPLES, PROFILE_TEMPLATES, RETIRED_BUNDLES } from '@deepseek-ai/dsh-official-bundles' import { evaluatePluginCompatibility, pluginCompatibilityWarning } from './plugin-compatibility.ts' import { readProfileVersionExemptions } from './profile-compatibility.ts' import { loadOverlayPatches } from './index.ts' @@ -39,12 +40,6 @@ export const PROFILES_DIR = 'profiles' /** The user patch layer inside a profile directory (hot-reloaded on long-lived surfaces). */ export const PROFILE_PATCH_FILENAME = 'cordis.patch.yml' -/** Installation-owned defaults used when a shipped profile is first opened. */ -export interface ProfileTemplate { - /** Ordered bundle layer list. */ - bundles: readonly string[] -} - /** Package metadata accepted by the profile reader; local profiles need no published identity. */ export type ProfileManifest = Partial @@ -175,68 +170,6 @@ export function resolveProfileDir(name: string, home: string = resolveDshHome()) return join(home, PROFILES_DIR, name) } -/** The shipped profile templates auto-initialized on first use, by name. */ -export const PROFILE_TEMPLATES: Record = { - acp: { - bundles: ['@deepseek-ai/dsh-base', '@deepseek-ai/dsh-acp-app'], - }, - web: { - bundles: ['@deepseek-ai/dsh-base', '@deepseek-ai/dsh-web-app'], - }, - headless: { - bundles: ['@deepseek-ai/dsh-base', '@deepseek-ai/dsh-headless'], - }, - sdk: { - bundles: ['@deepseek-ai/dsh-base', '@deepseek-ai/dsh-sdk-app'], - }, - 'sdk-minimal': { - bundles: ['@deepseek-ai/dsh-sdk-minimal'], - }, -} - -/** Installation-owned bundle tuples normalized to the shipped template. */ -const INSTALLATION_OWNED_PROFILE_TUPLES: Record = { - headless: ['@deepseek-ai/dsh-base', '@deepseek-ai/dsh-web-app', '@deepseek-ai/dsh-headless'], -} - -/** - * Bundles an earlier release shipped and the installation no longer carries; - * {@link loadProfileDirectory} removes them from the profile's bundle list. - */ -const RETIRED_BUNDLES: ReadonlySet = new Set([ - // The Web composition mounts Schedule itself - // ([upgrade guide](../../../../docs/upgrade-guide/v0.2.0-rc.2/schedule-bundle-retired/guide.md)). - '@deepseek-ai/dsh-experimental-schedule-bundle', -]) - -/** The bundle list a `dsh plugin` init uses for a name with no shipped template. */ -export const DEFAULT_PROFILE_BUNDLES: readonly string[] = ['@deepseek-ai/dsh-base'] - -/** - * The bundles the dsh installation ships for a person to switch on: each a - * runtime dependency of the installation that declares `dsh.bundle.patch`, - * an `icon`, and `./locale/*.json` display metadata, selected by no shipped - * template, and offered switched off by the plugin manager except persistent - * terminals, which have no page switch - * ([rationale](../../../../.agents/notes/implemented/process/2026-09-15-shipped-optional-bundles.md), - * [admission](../../../../.agents/notes/implemented/architecture/2026-09-21-experimental-capabilities-as-optional-bundles.md)). - */ -export const OPTIONAL_BUNDLES: readonly string[] = [ - '@deepseek-ai/dsh-cua-bundle', - '@deepseek-ai/dsh-experimental-session-search', - '@deepseek-ai/dsh-experimental-ralph-bundle', - '@deepseek-ai/dsh-experimental-terminal-bundle', - '@deepseek-ai/dsh-experimental-badge-skill-bundle', - '@deepseek-ai/dsh-experimental-session-titles-bundle', - '@deepseek-ai/dsh-experimental-agent-team-profile', - '@deepseek-ai/dsh-experimental-voice-input-bundle', - '@deepseek-ai/dsh-experimental-cot-translation-bundle', - '@deepseek-ai/dsh-experimental-auto-review', - '@deepseek-ai/dsh-experimental-inspector-profile', - '@deepseek-ai/dsh-experimental-plugin-market-bundle', - '@deepseek-ai/dsh-experimental-tool-worktree', -] - const PROFILE_PATCH_TEMPLATE = `# Your patch layer for this dsh profile, applied after every bundle layer: # a top-level YAML array of loader patch entries (id-targeted config # overrides, disables, and insert lists; \`!!js\` expressions allowed). diff --git a/packages/boot/app-boot/tests/config-reload.spec.ts b/packages/boot/app-boot/tests/config-reload.spec.ts index 4d8dae27e4..f96ddd36c6 100644 --- a/packages/boot/app-boot/tests/config-reload.spec.ts +++ b/packages/boot/app-boot/tests/config-reload.spec.ts @@ -246,13 +246,13 @@ describe('best-effort config failure recovery', () => { await ctx.loader.await() const entry = [...ctx.loader.entries()].find(candidate => candidate.options.id === 'webserver')! expect(entry.options.config).toEqual({ value: 'invalid' }) - expect(entry.fiber?.config).toEqual({ value: 1 }) + expect(entry.fiber?.effectiveConfig).toEqual({ value: 1 }) expect(ctx.get('validatedValue')).toBe(1) writeFileSync(join(dir, 'cordis.yml'), config(2)) await include.refresh() await ctx.loader.await() - expect(entry.fiber?.config).toEqual({ value: 2 }) + expect(entry.fiber?.effectiveConfig).toEqual({ value: 2 }) expect(ctx.get('validatedValue')).toBe(2) } finally { await ctx.fiber.dispose() diff --git a/packages/boot/app-boot/tests/profile-sanitize.spec.ts b/packages/boot/app-boot/tests/profile-sanitize.spec.ts index 6104656be7..f02b1fc001 100644 --- a/packages/boot/app-boot/tests/profile-sanitize.spec.ts +++ b/packages/boot/app-boot/tests/profile-sanitize.spec.ts @@ -4,7 +4,8 @@ import { existsSync, mkdirSync, mkdtempSync, readdirSync, readFileSync, renameSy import { tmpdir } from 'node:os' import { join } from 'node:path' import { afterEach, expect, it, vi } from 'vitest' -import { initProfile, PROFILE_PATCH_FILENAME, PROFILE_TEMPLATES, readProfileManifest, sanitizeProfile } from '../src/index.ts' +import { initProfile, PROFILE_PATCH_FILENAME, readProfileManifest, sanitizeProfile } from '../src/index.ts' +import { PROFILE_TEMPLATES } from '@deepseek-ai/dsh-official-bundles' vi.mock('node:fs', async (importOriginal) => { const actual = await importOriginal() diff --git a/packages/boot/app-boot/tests/profile.spec.ts b/packages/boot/app-boot/tests/profile.spec.ts index fbd47c20bf..390e888050 100644 --- a/packages/boot/app-boot/tests/profile.spec.ts +++ b/packages/boot/app-boot/tests/profile.spec.ts @@ -21,7 +21,6 @@ import { loadProfileDirectory, PROFILE_COMPATIBILITY_FILENAME, PROFILE_PATCH_FILENAME, - PROFILE_TEMPLATES, readProfileManifest, readProfilePatches, removeLinkProjections, @@ -32,6 +31,7 @@ import { type Profile, type RuntimeResolution, } from '../src/index.ts' +import { PROFILE_TEMPLATES } from '@deepseek-ai/dsh-official-bundles' import { installRuntimeInterception } from '../src/profile-resolution/resolver.ts' const tempRoots: string[] = [] @@ -341,16 +341,6 @@ describe('loadProfile', () => { const home = tmp() expect(() => loadProfile('t', 'custom', anchor, home)) .toThrow('profile "custom" does not exist') - expect(PROFILE_TEMPLATES.web?.bundles).toContain('@deepseek-ai/dsh-base') - expect(PROFILE_TEMPLATES.acp).toEqual({ - bundles: ['@deepseek-ai/dsh-base', '@deepseek-ai/dsh-acp-app'], - }) - expect(PROFILE_TEMPLATES.sdk).toEqual({ - bundles: ['@deepseek-ai/dsh-base', '@deepseek-ai/dsh-sdk-app'], - }) - expect(PROFILE_TEMPLATES['sdk-minimal']).toEqual({ - bundles: ['@deepseek-ai/dsh-sdk-minimal'], - }) loadProfile('t', 'web', anchor, home) expect(readProfileManifest('t', resolveProfileDir('web', home)).dsh?.profile?.bundles) .toEqual([...PROFILE_TEMPLATES.web?.bundles ?? []]) diff --git a/packages/boot/app-boot/tests/user-patches.spec.ts b/packages/boot/app-boot/tests/user-patches.spec.ts index 09e5653c56..63e0af5ea6 100644 --- a/packages/boot/app-boot/tests/user-patches.spec.ts +++ b/packages/boot/app-boot/tests/user-patches.spec.ts @@ -451,7 +451,7 @@ describe('boot with user patches', () => { try { const noop = [...ctx.loader.entries()].find(entry => entry.options.id === 'noop') // The mounted plugin received the interpolated environment value. - expect(noop?.fiber?.config).toEqual({ value: 'user-value' }) + expect(noop?.fiber?.effectiveConfig).toEqual({ value: 'user-value' }) expect([...ctx.loader.entries()].some(entry => entry.options.id === 'user-extra')).toBe(true) } finally { await ctx.fiber.dispose() diff --git a/packages/boot/app-boot/tsconfig.json b/packages/boot/app-boot/tsconfig.json index 9c3e57c809..c1dcee4ba2 100644 --- a/packages/boot/app-boot/tsconfig.json +++ b/packages/boot/app-boot/tsconfig.json @@ -26,6 +26,9 @@ { "path": "../../util/home-paths" }, + { + "path": "../official-bundles" + }, { "path": "../../util/package-manifest" }, diff --git a/packages/boot/config-editor/src/index.ts b/packages/boot/config-editor/src/index.ts index ffec879f40..8fe686e478 100644 --- a/packages/boot/config-editor/src/index.ts +++ b/packages/boot/config-editor/src/index.ts @@ -2,7 +2,7 @@ import { readFile } from 'node:fs/promises' import { join } from 'node:path' import { isDeepStrictEqual } from 'node:util' -import { Context, FiberState, Service, resolveConfig } from '@deepseek-ai/cordis' +import { Context, FiberState, Service } from '@deepseek-ai/cordis' import { entryListSchema, type PatchOptions } from '@deepseek-ai/cordis-plugin-include' import yaml from 'js-yaml' import type { Entry, EntryOptions } from '@deepseek-ai/cordis-plugin-loader' @@ -100,8 +100,7 @@ export class ConfigEditor extends Service { const next = change(current, inherited) const fiber = entry.fiber if (fiber.state !== FiberState.ACTIVE) throw new Error('Configuration plugin is no longer active') - const resolved: unknown = fiber.ctx.waterfall(fiber, 'internal/config', next, () => next) - resolveConfig(fiber.runtime as NonNullable, resolved) + fiber.resolveConfig(next) let before: string try { before = await readFile(path, 'utf8') } catch (error) { diff --git a/packages/boot/hmr/src/index.ts b/packages/boot/hmr/src/index.ts index e5c113db7b..709524d741 100644 --- a/packages/boot/hmr/src/index.ts +++ b/packages/boot/hmr/src/index.ts @@ -646,7 +646,7 @@ class Hmr extends Service { ...info, previous, fibers: [...info.runtime?.fibers ?? []].map((fiber) => { const entry = fiber.entry?.fiber?.uid === fiber.uid ? fiber.entry : undefined - const config: unknown = entry === undefined ? fiber._config : entry.options.config + const config: unknown = entry === undefined ? fiber.rawConfig : entry.options.config return { fiber, entry, config, moduleNamespace: entry?.moduleNamespace } }), })) diff --git a/packages/boot/hmr/tests/modules.spec.ts b/packages/boot/hmr/tests/modules.spec.ts index 5cf710ea07..33895a7106 100644 --- a/packages/boot/hmr/tests/modules.spec.ts +++ b/packages/boot/hmr/tests/modules.spec.ts @@ -298,7 +298,7 @@ it('leaves disposed child instances to their replacing parent', async () => { expect(seen).toContain('new:entry') expect(seen).not.toContain('new:child') expect(seen).toContain('new:independent') - expect(entry.fiber?._config).toEqual({ value: 'entry' }) + expect(entry.fiber?.rawConfig).toEqual({ value: 'entry' }) }) it.each(['v1', 'v2'] as const)('invalidates a disabled %s module without activating it', async (version) => { diff --git a/packages/boot/official-bundles/README.i18n.yaml b/packages/boot/official-bundles/README.i18n.yaml new file mode 100644 index 0000000000..de5b0232da --- /dev/null +++ b/packages/boot/official-bundles/README.i18n.yaml @@ -0,0 +1,43 @@ +# Bilingual-pair consistency record for README.md (docs/i18n/README.md): per heading +# section, a hash of its English and Chinese blocks outside code blocks and generated regions. +# After editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write packages/boot/official-bundles/README.md +/: + en: bf83ae511baf1048 + zh: f8966b8dd39c5b9a +/deepseek-ai-dsh-official-bundles: + en: bb5c2cd3ee2ee02b + zh: cf78cfef3b92ab25 +/deepseek-ai-dsh-official-bundles/summary: + en: 3d64166b71a685bc + zh: 424e1f77fc987115 +/deepseek-ai-dsh-official-bundles/table-of-contents: + en: 80b31a934611cb4a + zh: 05f3f7f9cb2fd881 +/deepseek-ai-dsh-official-bundles/use-this-package: + en: 62c8aa1af42d91d7 + zh: 39674a200b42b0d2 +/deepseek-ai-dsh-official-bundles/use-this-package/profile-templates: + en: 60ef21314c76c3ec + zh: f769091957235e12 +/deepseek-ai-dsh-official-bundles/use-this-package/optional-and-retired-bundles: + en: c0940eb304bbacd1 + zh: bbc4f72b7a49c676 +/deepseek-ai-dsh-official-bundles/use-this-package/on-demand-bundles: + en: 10dac368736afde3 + zh: 7684ca22ba4b5a67 +/deepseek-ai-dsh-official-bundles/understand-the-implementation: + en: 2986cf8f3115a483 + zh: 3eb2dade2666bbc6 +/deepseek-ai-dsh-official-bundles/understand-the-implementation/source-map: + en: af30ccf226fbb7d4 + zh: f39ae7a50b2aaa80 +/deepseek-ai-dsh-official-bundles/further-exploration: + en: 16a331e64c81b2a5 + zh: abfe9b1a1294b6b3 +/deepseek-ai-dsh-official-bundles/known-limitations-and-deferred-work: + en: 6631976cc7404166 + zh: edb2094b17bc4009 +/deepseek-ai-dsh-official-bundles/known-limitations-and-deferred-work/dev-note: + en: e67f633dc6fe7773 + zh: 3bb0c20c93f16f98 diff --git a/packages/boot/official-bundles/README.md b/packages/boot/official-bundles/README.md new file mode 100644 index 0000000000..7fb4babfa0 --- /dev/null +++ b/packages/boot/official-bundles/README.md @@ -0,0 +1,86 @@ +--- +description: "Installation-owned lists of official dsh bundles: shipped profile templates, the default bundle list, and the optional, on-demand, and retired bundles." +kind: "package-library" +--- + +# @deepseek-ai/dsh-official-bundles + +English | [中文](README.zh.md) + +## Summary + +`@deepseek-ai/dsh-official-bundles` holds the bundle package names the dsh installation decides on: which bundles each shipped profile starts with, which bundles it ships switched off, which official bundles install on request, and which bundles earlier releases shipped and profiles drop. [`dsh-app-boot`](../app-boot/README.md) applies these lists when it loads a profile; the plugin manager, the CLI, Desktop, the WebWorker image packer, and repository checks read them directly. The package holds data only, so adding or removing a bundle leaves app-boot untouched. Use it as a direct library dependency, not through `cordis.yml`. + +## Table of Contents + +- [Use this package](#use-this-package) +- [Understand the implementation](#understand-the-implementation) +- [Further Exploration](#further-exploration) +- [Known Limitations and Deferred Work](#known-limitations-and-deferred-work) +- [Dev Note](#dev-note) + +----- + + +## Use this package + +Edit this package when the installation's bundle selection changes; read it wherever code must agree with the launcher about that selection. + +### Profile templates + +`PROFILE_TEMPLATES` maps each shipped profile name (`web`, `headless`, `acp`, `sdk`, `sdk-minimal`) to its ordered bundle layer list. App-boot initializes a missing shipped profile from its template, and `dsh --profile --from-default-profile