diff --git a/.agents/notes/implemented/architecture/2026-08-27-adjacent-agent-steer-messaging.i18n.yaml b/.agents/notes/implemented/architecture/2026-08-27-adjacent-agent-steer-messaging.i18n.yaml index 97e7927b58..09305c1c93 100644 --- a/.agents/notes/implemented/architecture/2026-08-27-adjacent-agent-steer-messaging.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-08-27-adjacent-agent-steer-messaging.i18n.yaml @@ -15,11 +15,11 @@ en: 62284bd7dd804188 zh: b3a8dfebffc01bdb /agent-note-adjacent-agents-share-one-steer-send-message-operation/decision/complete-removal-and-reintroduction-condition: - en: 8c6d355d91ec83d2 - zh: fcc74d1e6ef477bf + en: 8cd78e21602f17f0 + zh: 3843fea07e9b93a3 /agent-note-adjacent-agents-share-one-steer-send-message-operation/alternatives-considered: en: 7386e88e7051dce7 zh: dcea5b9e30374be3 /agent-note-adjacent-agents-share-one-steer-send-message-operation/consequences: - en: 9c23dd6ace029ec3 - zh: f08ef3f142534843 + en: 22a3af4c51aee23e + zh: 9d59315313d0f761 diff --git a/.agents/notes/implemented/architecture/2026-08-27-adjacent-agent-steer-messaging.md b/.agents/notes/implemented/architecture/2026-08-27-adjacent-agent-steer-messaging.md index a4cfbc91cb..080f10f19a 100644 --- a/.agents/notes/implemented/architecture/2026-08-27-adjacent-agent-steer-messaging.md +++ b/.agents/notes/implemented/architecture/2026-08-27-adjacent-agent-steer-messaging.md @@ -40,7 +40,7 @@ The globally registered model tool is direction-neutral and has one fixed schema ```ts interface SendMessageInput { - readonly agent_id: string + readonly agent: string readonly message: string } ``` @@ -53,7 +53,7 @@ Human browser prompts are not model-authored Agent messages. The remote prompt p ### Complete removal and reintroduction condition -The standalone `@deepseek-ai/dsh-tool-subagent-report` package, `report` schema, `tool:report` prompt section, `reportDelivery` configuration, report-specific message source, catalog entries, composition rows, and supported-behavior snapshots are absent. The unified tool gives up the recipient-free child shortcut and the old ability for a structural return tool to survive an explicit child allow-list. Those capabilities return only if a concrete use case requires semantics that a tree member’s `agent_id` and fixed Steer cannot express; reintroducing them requires a distinct model operation and prefix-cost evidence, not an alias over `sendMessage()`. +The standalone `@deepseek-ai/dsh-tool-subagent-report` package, `report` schema, `tool:report` prompt section, `reportDelivery` configuration, report-specific message source, catalog entries, composition rows, and supported-behavior snapshots are absent. The unified tool gives up the recipient-free child shortcut and the old ability for a structural return tool to survive an explicit child allow-list. Those capabilities return only if a concrete use case requires semantics that a tree member’s `agent` reference and fixed Steer cannot express; reintroducing them requires a distinct model operation and prefix-cost evidence, not an alias over `sendMessage()`. ## Alternatives considered @@ -71,7 +71,7 @@ The standalone `@deepseek-ai/dsh-tool-subagent-report` package, `report` schema, ## Consequences -- Model consumers expose one `send_message({ agent_id, message })` definition to parents and children, with no model-selected Queue versus Steer parameter. +- Model consumers expose one `send_message({ agent, message })` definition to parents and children, with no model-selected Queue versus Steer parameter. - The continuation manager remains the sole owner of tree authorization, residency, cold resume, waking admission, and teardown races. - Accepted messages may extend a running target's current turn; messages waiting together share next-step FIFO ordering. - Caller cancellation owns work only until inbox acceptance and does not retract an accepted message or dispose the target. diff --git a/.agents/notes/implemented/architecture/2026-08-27-adjacent-agent-steer-messaging.zh.md b/.agents/notes/implemented/architecture/2026-08-27-adjacent-agent-steer-messaging.zh.md index d907eaeac0..2c944b44ea 100644 --- a/.agents/notes/implemented/architecture/2026-08-27-adjacent-agent-steer-messaging.zh.md +++ b/.agents/notes/implemented/architecture/2026-08-27-adjacent-agent-steer-messaging.zh.md @@ -40,7 +40,7 @@ interface AgentMessageSource { ```ts interface SendMessageInput { - readonly agent_id: string + readonly agent: string readonly message: string } ``` @@ -53,7 +53,7 @@ parent 与 child 以相同注册表顺序继承相同定义。标准定义携带 ### 完整移除与重新引入条件 -独立的 `@deepseek-ai/dsh-tool-subagent-report` 包、`report` schema、`tool:report` 提示词 section、`reportDelivery` 配置、report 专属消息来源、目录项、组合行和受支持行为快照均已不存在。统一工具放弃了无需接收方的 child 快捷方式,也放弃了让结构性返回工具绕过显式 child allow-list 的旧能力。只有具体用例需要树成员的 `agent_id` 与固定 Steer 无法表达的语义时,这些能力才会重新出现;重新引入需要独立的模型操作与前缀成本证据,而非 `sendMessage()` 之上的别名。 +独立的 `@deepseek-ai/dsh-tool-subagent-report` 包、`report` schema、`tool:report` 提示词 section、`reportDelivery` 配置、report 专属消息来源、目录项、组合行和受支持行为快照均已不存在。统一工具放弃了无需接收方的 child 快捷方式,也放弃了让结构性返回工具绕过显式 child allow-list 的旧能力。只有具体用例需要树成员的 `agent` 引用与固定 Steer 无法表达的语义时,这些能力才会重新出现;重新引入需要独立的模型操作与前缀成本证据,而非 `sendMessage()` 之上的别名。 ## 考虑过的替代方案 @@ -71,7 +71,7 @@ parent 与 child 以相同注册表顺序继承相同定义。标准定义携带 ## 后果 -- 模型 Consumer 向 parent 与 child 公开一个 `send_message({ agent_id, message })` 定义,不提供模型选择的 Queue 与 Steer 参数。 +- 模型 Consumer 向 parent 与 child 公开一个 `send_message({ agent, message })` 定义,不提供模型选择的 Queue 与 Steer 参数。 - 继续执行管理器仍是整树授权、驻留、冷恢复、唤醒准入与拆卸竞态的唯一所有者。 - 被接受的消息可以延长运行中目标的当前轮次;一起等待的消息共享 next-step FIFO 顺序。 - 调用方取消只在 inbox 接受前掌管工作,不会撤回已接受消息或 dispose(资源释放)目标。 diff --git a/.agents/notes/implemented/architecture/2026-09-01-parent-owned-subagent-catalog.i18n.yaml b/.agents/notes/implemented/architecture/2026-09-01-parent-owned-subagent-catalog.i18n.yaml index 33ebd75e3d..c922f333d8 100644 --- a/.agents/notes/implemented/architecture/2026-09-01-parent-owned-subagent-catalog.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-09-01-parent-owned-subagent-catalog.i18n.yaml @@ -9,8 +9,8 @@ en: 5a991fec31578cea zh: 13b75aa36eb22907 /agent-note-parent-owned-subagent-catalog-events/decision: - en: 4319c502038ab34d - zh: b11825ff9d744822 + en: d2290d8e70d42054 + zh: 64a2d1d0915f6c3e /agent-note-parent-owned-subagent-catalog-events/alternatives-considered: en: 7a3d4b9f69c243d8 zh: 82b03d16ccc94dd2 diff --git a/.agents/notes/implemented/architecture/2026-09-01-parent-owned-subagent-catalog.md b/.agents/notes/implemented/architecture/2026-09-01-parent-owned-subagent-catalog.md index 2fac858789..d5a03d7f9f 100644 --- a/.agents/notes/implemented/architecture/2026-09-01-parent-owned-subagent-catalog.md +++ b/.agents/notes/implemented/architecture/2026-09-01-parent-owned-subagent-catalog.md @@ -14,7 +14,7 @@ The child descriptor remains necessary for recovery and composition, but it cann The shared activation entry point, external execution ownership, and caller-versus-parent result delivery are governed by [Unified subagent activations](../simplification/2026-09-17-unified-subagent-activations.md). This record retains the independent rationale described below. -The parent Session's required `subagent/catalog` events are the persistent authority for direct-child discovery. Every local child enters the catalog independently of its result recipient; external children enter only with parent delivery. Workflow membership records describe execution progress and do not replace local Session discovery. Each event contains `childId`, `childCreatedAt`, mode, and the mode-discriminated label. Local children use `continuable`; external executions use `external` and cannot be opened as local Sessions. Historical `one-shot` and `unknown` entries remain readable. Invalid own facts, including unsupported payload versions, reject projection restoration because silently dropping a required fact would return an incomplete catalog. +The parent Session's required `subagent/catalog` events are the persistent authority for direct-child discovery. Every local child enters the catalog independently of its result recipient; external children enter only with parent delivery. Workflow membership records describe execution progress and do not replace local Session discovery. Each event contains `childId`, `childCreatedAt`, mode, the mode-discriminated label, and, from payload v3, the child's [name](2026-11-02-subagent-catalog-names.md). Local children use `continuable`; external executions use `external` and cannot be opened as local Sessions. Historical `one-shot` and `unknown` entries remain readable. Invalid own facts, including unsupported payload versions, reject projection restoration because silently dropping a required fact would return an incomplete catalog. Creation publishes only successful facts. A local activation admits the initial prompt before appending its catalog event. An external activation appends its event after provider startup and before returning the receipt. Failed admission or publication releases the unpublished execution; there is no compensating catalog event or rollback protocol. @@ -22,7 +22,7 @@ The child header and `subagent/descriptor` remain authoritative for recovery and The registered `subagentCatalog` projection materializes the parent facts. It delegates storage, append, iteration, and checkpoint validation to [`dsh-chunked-list`](../../../../packages/util/chunked-list/README.md), which stores facts in a persistent stack of 64-entry chunks, so an append copies at most the head chunk in bounded O(1) work. Materialization visits chunks from oldest to newest and preserves parent catalog event order in O(D) time for D facts. Concurrent creation is ordered by successful catalog append, independent of child timestamps and ids. A projection checkpoint clones the state once in O(D); projection-cache writes remain asynchronous and use the existing mandatory creation, turn-end, and disposal points. -The utility owns chunk layout and its shared capacity constant; the catalog owns event validation, fork filtering, and row conversion. Catalog projection state version 6 accepts external membership, so the projection registry rebuilds incompatible caches from Session events. Payload v0 and v1 remain unchanged; v2 records external executions. +The utility owns chunk layout and its shared capacity constant; the catalog owns event validation, fork filtering, and row conversion. Catalog projection state version 7 accepts external membership and child names, so the projection registry rebuilds incompatible caches from Session events. Payload v0 and v1 remain unchanged; v2 records external executions; v3 adds names to continuable and external entries. Fork isolation uses the exact `Session.inheritedEventCount` supplied to projection initialization. The fold ignores `subagent/catalog` events below that offset. The state stores the inherited offset but not each event seq because acceptance is decided during folding. diff --git a/.agents/notes/implemented/architecture/2026-09-01-parent-owned-subagent-catalog.zh.md b/.agents/notes/implemented/architecture/2026-09-01-parent-owned-subagent-catalog.zh.md index 10088c52a7..7ebab0cef7 100644 --- a/.agents/notes/implemented/architecture/2026-09-01-parent-owned-subagent-catalog.zh.md +++ b/.agents/notes/implemented/architecture/2026-09-01-parent-owned-subagent-catalog.zh.md @@ -14,7 +14,7 @@ child descriptor 对恢复与 composition 仍然必要,但它不能作为 disc 共享 activation 入口、外部执行所有权,以及调用方与父级之间的结果投递选择由[统一 subagent activation](../simplification/2026-09-17-unified-subagent-activations.zh.md) 决策拥有。本记录保留下述独立理由。 -父级 Session 的必读 `subagent/catalog` 事件是发现直接子级的持久化权威。每个本地子级都会进入目录,与结果接收方无关;外部子级仅在 parent 投递时进入目录。工作流成员记录描述执行进度,不替代本地 Session 发现。每个事件包含 `childId`、`childCreatedAt`、mode 与按 mode 区分的 label。本地子级使用 `continuable`;外部执行使用 `external`,不能作为本地 Session 打开。历史 `one-shot` 与 `unknown` 条目仍可读取。无效的自身事实(包括不支持的载荷版本)会使投影恢复失败,因为静默丢弃必读事实将返回不完整的 catalog。 +父级 Session 的必读 `subagent/catalog` 事件是发现直接子级的持久化权威。每个本地子级都会进入目录,与结果接收方无关;外部子级仅在 parent 投递时进入目录。工作流成员记录描述执行进度,不替代本地 Session 发现。每个事件包含 `childId`、`childCreatedAt`、mode、按 mode 区分的 label,以及从载荷 v3 起的子级[名称](2026-11-02-subagent-catalog-names.zh.md)。本地子级使用 `continuable`;外部执行使用 `external`,不能作为本地 Session 打开。历史 `one-shot` 与 `unknown` 条目仍可读取。无效的自身事实(包括不支持的载荷版本)会使投影恢复失败,因为静默丢弃必读事实将返回不完整的 catalog。 创建只发布成功事实。本地 activation 先接纳初始提示词,再追加 catalog 事件。外部 activation 在提供方启动后、返回回执前追加事件。准入或发布失败会释放未发布的执行;不存在补偿 catalog 事件或回滚协议。 @@ -22,7 +22,7 @@ child header 与 `subagent/descriptor` 继续拥有恢复与 composition 权威 注册的 `subagentCatalog` projection 物化 parent fact。它将存储、追加、迭代和检查点校验交给 [`dsh-chunked-list`](../../../../packages/util/chunked-list/README.zh.md),后者以每块 64 项的持久 stack 保存事实,因此 append 最多复制 head chunk,以有界 O(1) 工作完成。materialization 从旧到新访问 chunk,对 D 条事实以 O(D) 时间保留父目录事件顺序。并发创建按目录成功追加的顺序排列,与 child 时间戳和 id 无关。projection checkpoint 以 O(D) 克隆 state;projection-cache 继续异步写入,并使用既有创建、turn-end 与 disposal 强制点。 -工具库拥有 chunk 布局与共享容量常量;catalog 拥有事件校验、fork 过滤和行转换。catalog 投影状态版本 6 接受外部成员,因此投影注册表会从 Session 事件重建不兼容缓存。载荷 v0 与 v1 保持不变;v2 记录外部执行。 +工具库拥有 chunk 布局与共享容量常量;catalog 拥有事件校验、fork 过滤和行转换。catalog 投影状态版本 7 接受外部成员和子级名称,因此投影注册表会从 Session 事件重建不兼容缓存。载荷 v0 与 v1 保持不变;v2 记录外部执行;v3 为可继续和外部条目增加名称。 fork 隔离使用 projection 初始化时提供的精确 `Session.inheritedEventCount`。fold 忽略该 offset 之前的 `subagent/catalog` 事件。state 保存 inherited offset,但不保存每条 event seq,因为接受判定已在 fold 时完成。 diff --git a/.agents/notes/implemented/architecture/2026-10-13-team-identity-runtime-context.i18n.yaml b/.agents/notes/implemented/architecture/2026-10-13-team-identity-runtime-context.i18n.yaml index f1c602359c..61d408cf40 100644 --- a/.agents/notes/implemented/architecture/2026-10-13-team-identity-runtime-context.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-10-13-team-identity-runtime-context.i18n.yaml @@ -3,8 +3,8 @@ # After editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write .agents/notes/implemented/architecture/2026-10-13-team-identity-runtime-context.md /agent-note-subagent-identity-in-required-runtime-context: - en: ce8f378b6e7b57fa - zh: 26bd0415b4dba94a + en: 3da6e33c5dc2c917 + zh: 9c8d4542cda63fc4 /agent-note-subagent-identity-in-required-runtime-context/problem: en: f944254565541454 zh: 27fa9f67c671dec7 diff --git a/.agents/notes/implemented/architecture/2026-10-13-team-identity-runtime-context.md b/.agents/notes/implemented/architecture/2026-10-13-team-identity-runtime-context.md index fb8e92e811..bb2405a145 100644 --- a/.agents/notes/implemented/architecture/2026-10-13-team-identity-runtime-context.md +++ b/.agents/notes/implemented/architecture/2026-10-13-team-identity-runtime-context.md @@ -4,6 +4,8 @@ Status: implemented English | [中文](2026-10-13-team-identity-runtime-context.zh.md) +[Catalog names](2026-11-02-subagent-catalog-names.md) supersede the Session-id identity text below: agents see their own, direct parent, and root names. The runtime-context retention decision remains active. + ## Problem A teammate identity embedded in its initial task depends on ordinary history retention. Compaction can remove it, and an ordinary fork from that teammate can retain the old role even though the fork is an independent Lead. Identity must reflect the current subagent tree while keeping shared system instructions uniform. diff --git a/.agents/notes/implemented/architecture/2026-10-13-team-identity-runtime-context.zh.md b/.agents/notes/implemented/architecture/2026-10-13-team-identity-runtime-context.zh.md index f3ebb3e6b3..09adf8c130 100644 --- a/.agents/notes/implemented/architecture/2026-10-13-team-identity-runtime-context.zh.md +++ b/.agents/notes/implemented/architecture/2026-10-13-team-identity-runtime-context.zh.md @@ -4,6 +4,8 @@ Status: implemented [English](2026-10-13-team-identity-runtime-context.md) | 中文 +[目录名称](2026-11-02-subagent-catalog-names.zh.md)取代下文以 Session id 表述身份的文本:agent 看到自身、直接父级和根的名称。runtime context 保留决策仍然有效。 + ## Problem 嵌入初始任务的 teammate 身份依赖普通历史保留。压缩可能移除它;从 teammate 创建的普通 fork 即使已成为独立 Lead,也可能保留旧角色。身份必须反映当前 subagent 树,同时保持共享系统指令一致。 diff --git a/.agents/notes/implemented/architecture/2026-10-15-agent-teams-as-subagents.i18n.yaml b/.agents/notes/implemented/architecture/2026-10-15-agent-teams-as-subagents.i18n.yaml index 282acab92a..bdf1744de7 100644 --- a/.agents/notes/implemented/architecture/2026-10-15-agent-teams-as-subagents.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-10-15-agent-teams-as-subagents.i18n.yaml @@ -3,8 +3,8 @@ # After editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write .agents/notes/implemented/architecture/2026-10-15-agent-teams-as-subagents.md /agent-note-agent-teams-teammates-are-subagents: - en: 51e2fc51a6e1622a - zh: 7e09ea6292e5921d + en: f49f9e7ef588e612 + zh: 7da804056221af51 /agent-note-agent-teams-teammates-are-subagents/problem: en: ca2848e3bbc3a009 zh: 0551e32ff6d187d0 diff --git a/.agents/notes/implemented/architecture/2026-10-15-agent-teams-as-subagents.md b/.agents/notes/implemented/architecture/2026-10-15-agent-teams-as-subagents.md index 8cab7023e0..2b11e98b0e 100644 --- a/.agents/notes/implemented/architecture/2026-10-15-agent-teams-as-subagents.md +++ b/.agents/notes/implemented/architecture/2026-10-15-agent-teams-as-subagents.md @@ -4,7 +4,7 @@ Status: implemented English | [中文](2026-10-15-agent-teams-as-subagents.zh.md) -The adjacency and parent-lifetime restrictions are superseded by [tree-wide communication](2026-10-16-tree-wide-agent-communication.md). [Task-board inbox coordination](2026-10-19-team-task-board-inbox.md) supersedes the separate roster and Team-owned wait; the single subagent identity decision remains active. +The adjacency and parent-lifetime restrictions are superseded by [tree-wide communication](2026-10-16-tree-wide-agent-communication.md). [Task-board inbox coordination](2026-10-19-team-task-board-inbox.md) supersedes the separate roster and Team-owned wait; the single subagent identity decision remains active. [Catalog names](2026-11-02-subagent-catalog-names.md) supersede the statement that creation accepts no member name and the rejection of unique names below. ## Problem diff --git a/.agents/notes/implemented/architecture/2026-10-15-agent-teams-as-subagents.zh.md b/.agents/notes/implemented/architecture/2026-10-15-agent-teams-as-subagents.zh.md index 8c113d288a..a7467f1dbb 100644 --- a/.agents/notes/implemented/architecture/2026-10-15-agent-teams-as-subagents.zh.md +++ b/.agents/notes/implemented/architecture/2026-10-15-agent-teams-as-subagents.zh.md @@ -4,7 +4,7 @@ Status: implemented [English](2026-10-15-agent-teams-as-subagents.md) | 中文 -邻接和父级生命周期限制由[整树通信](2026-10-16-tree-wide-agent-communication.zh.md)取代。[任务板收件箱协调](2026-10-19-team-task-board-inbox.zh.md)取代独立名册和 Team 所有的等待;单一 subagent 身份决策仍有效。 +邻接和父级生命周期限制由[整树通信](2026-10-16-tree-wide-agent-communication.zh.md)取代。[任务板收件箱协调](2026-10-19-team-task-board-inbox.zh.md)取代独立名册和 Team 所有的等待;单一 subagent 身份决策仍有效。[目录名称](2026-11-02-subagent-catalog-names.zh.md)取代下文“创建不接收成员名称”的表述及对唯一名称的否决。 ## Problem diff --git a/.agents/notes/implemented/architecture/2026-10-16-tree-wide-agent-communication.i18n.yaml b/.agents/notes/implemented/architecture/2026-10-16-tree-wide-agent-communication.i18n.yaml index ee52c30615..fd6879706d 100644 --- a/.agents/notes/implemented/architecture/2026-10-16-tree-wide-agent-communication.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-10-16-tree-wide-agent-communication.i18n.yaml @@ -9,8 +9,8 @@ en: c583c3cdb894e417 zh: 6edc0354b79f4f26 /agent-note-communication-follows-the-subagent-tree/decision: - en: da35a75e069fa1e4 - zh: 7edf62ad66ab04ec + en: 767b4b4dfd84f72e + zh: 36617ec0dab777ee /agent-note-communication-follows-the-subagent-tree/alternatives-considered: en: 470f9cf8c3e32af9 zh: 73bbe29767c5d02a diff --git a/.agents/notes/implemented/architecture/2026-10-16-tree-wide-agent-communication.md b/.agents/notes/implemented/architecture/2026-10-16-tree-wide-agent-communication.md index 30dee6781a..8b80b0b841 100644 --- a/.agents/notes/implemented/architecture/2026-10-16-tree-wide-agent-communication.md +++ b/.agents/notes/implemented/architecture/2026-10-16-tree-wide-agent-communication.md @@ -10,13 +10,13 @@ A Team shares one task board across the root's entire subagent tree. Restricting ## Decision -`list_agents` starts at the caller's live root and lists that root and all reachable continuable descendants, including the caller. Parent ids and depth remain relative to the root. The existing parent catalogs remain authoritative; no Team directory is stored separately. +`list_agents` starts at the caller's live root and lists that root and all reachable continuable descendants, including the caller. Full names remain relative to the root. The existing parent catalogs remain authoritative; no Team directory is stored separately. `send_message` accepts another root or continuable member of the same tree. The sender must be the exact live root or a resident continuable subagent. Cross-branch delivery verifies the target descriptor and creation catalogs, then restores only the target under the Team root. Final inbox admission rechecks the sender and root. Cancellation or rejection before acceptance releases the new target instance; accepted input follows normal Agent persistence. The existing Agent registry records runtime ownership by the Team root. Creation parent ids and catalogs preserve ancestry for discovery and interrupt authority. A member finishing or being released affects only its own instance; Team-root shutdown joins all startup and cleanup. This removes ancestor restoration, parent retention, and recursive disposal without adding a Team runtime registry. Saved target presets and permission events supply restoration configuration. -This supersedes the adjacency, discovery, and parent-lifetime restrictions in [adjacent messaging](2026-08-27-adjacent-agent-steer-messaging.md) and [subagent teammates](2026-10-15-agent-teams-as-subagents.md). Their shared inbox, scheduling, attribution, and Team reuse decisions remain active. Members use Session ids for addressing; ordinary Session forks lead independent Teams. +This supersedes the adjacency, discovery, and parent-lifetime restrictions in [adjacent messaging](2026-08-27-adjacent-agent-steer-messaging.md) and [subagent teammates](2026-10-15-agent-teams-as-subagents.md). Their shared inbox, scheduling, attribution, and Team reuse decisions remain active. Members address one another by the names that [catalog names](2026-11-02-subagent-catalog-names.md) define, or by Session id; ordinary Session forks lead independent Teams. ## Alternatives considered diff --git a/.agents/notes/implemented/architecture/2026-10-16-tree-wide-agent-communication.zh.md b/.agents/notes/implemented/architecture/2026-10-16-tree-wide-agent-communication.zh.md index 58d075e9a6..b026bda26c 100644 --- a/.agents/notes/implemented/architecture/2026-10-16-tree-wide-agent-communication.zh.md +++ b/.agents/notes/implemented/architecture/2026-10-16-tree-wide-agent-communication.zh.md @@ -10,13 +10,13 @@ Status: implemented ## Decision -`list_agents` 从调用方的在线根开始,列出该根与所有可达的可继续后代,包括调用方。父级 id 和深度始终相对根计算。现有父级目录仍是权威来源;不单独存储 Team 目录。 +`list_agents` 从调用方的在线根开始,列出该根与所有可达的可继续后代,包括调用方。完整名称始终相对根计算。现有父级目录仍是权威来源;不单独存储 Team 目录。 `send_message` 接受同一棵树中的其他根或可继续成员。发送者必须是确切在线根或驻留的可继续子代理。跨分支投递验证目标描述符和创建目录后,仅在 Team 根下恢复目标。最终收件箱准入重新检查发送者与根。接受前的取消或拒绝释放新建目标实例;已接受输入遵循普通 Agent 持久化。 现有 Agent 注册表记录 Team 根对运行时实例的所有权。创建父级 id 和目录保留用于发现及中断授权的祖先关系。成员完成或释放只影响自身实例;关闭 Team 根会等待全部启动和清理。这删除了祖先恢复、父级保留和递归释放,无需增加 Team 运行时注册表。目标保存的 preset 和权限事件提供恢复配置。 -本决策替代[相邻消息](2026-08-27-adjacent-agent-steer-messaging.zh.md)与[子代理队友](2026-10-15-agent-teams-as-subagents.zh.md)中的邻接、发现及父子生命周期限制。它们的共享收件箱、调度、发送者归属和 Team 复用决策仍有效。成员使用 Session id 寻址;普通 Session 分叉领导独立 Team。 +本决策替代[相邻消息](2026-08-27-adjacent-agent-steer-messaging.zh.md)与[子代理队友](2026-10-15-agent-teams-as-subagents.zh.md)中的邻接、发现及父子生命周期限制。它们的共享收件箱、调度、发送者归属和 Team 复用决策仍有效。成员使用[目录名称](2026-11-02-subagent-catalog-names.zh.md)定义的名称或 Session id 互相寻址;普通 Session 分叉领导独立 Team。 ## Alternatives considered diff --git a/.agents/notes/implemented/architecture/2026-10-22-subagent-tool-owned-communication.i18n.yaml b/.agents/notes/implemented/architecture/2026-10-22-subagent-tool-owned-communication.i18n.yaml index 81682a6981..90ff666645 100644 --- a/.agents/notes/implemented/architecture/2026-10-22-subagent-tool-owned-communication.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-10-22-subagent-tool-owned-communication.i18n.yaml @@ -9,8 +9,8 @@ en: ac391b569d2bc7e9 zh: a95f613aa2b330b8 /agent-note-subagent-tools-own-communication-guidance/decision: - en: 52fb33963bedfe07 - zh: 75fe66d80f47323f + en: d83310e85ffcb3cf + zh: eb1f069948399d93 /agent-note-subagent-tools-own-communication-guidance/alternatives-considered: en: c55d44c6414e0c4c zh: 9fa2ab31843e259b diff --git a/.agents/notes/implemented/architecture/2026-10-22-subagent-tool-owned-communication.md b/.agents/notes/implemented/architecture/2026-10-22-subagent-tool-owned-communication.md index 2222cd5dd7..5aa5ddca3d 100644 --- a/.agents/notes/implemented/architecture/2026-10-22-subagent-tool-owned-communication.md +++ b/.agents/notes/implemented/architecture/2026-10-22-subagent-tool-owned-communication.md @@ -10,7 +10,7 @@ The continuation manager inspected a Symbol on the standard messaging tool befor ## Decision -`tool-subagent-control` owns messaging instructions and parent addressing. Its logged runtime context gives delegated children their direct creator’s id from the Session header, explains when to send findings, and states that sending does not finish a turn. The context is emitted only for delegated children when the plugin’s own tool definition is admitted in the current scope and step; roots and ordinary Session forks receive none. Communication guidance follows inherited history without changing the shared system prompt or tool schema. +`tool-subagent-control` owns messaging instructions and parent addressing. Its logged runtime context gives delegated children their direct creator’s name from `ctx.subagents.namesOf()`, explains when to send findings, and states that sending does not finish a turn. The context is emitted only for delegated children when the plugin’s own tool definition is admitted in the current scope and step; roots and ordinary Session forks receive none. Communication guidance follows inherited history without changing the shared system prompt or tool schema. The manager owns result delivery. Local activations with `delivery: 'parent'` receive automatic-result guidance even without messaging tools; caller-owned activations receive no parent-delivery promise. Settlement timing, recipients, output, and suppression of closing text after a final message to the parent remain unchanged. Tool visibility grants no messaging authority. diff --git a/.agents/notes/implemented/architecture/2026-10-22-subagent-tool-owned-communication.zh.md b/.agents/notes/implemented/architecture/2026-10-22-subagent-tool-owned-communication.zh.md index 21242507b7..67f1146819 100644 --- a/.agents/notes/implemented/architecture/2026-10-22-subagent-tool-owned-communication.zh.md +++ b/.agents/notes/implemented/architecture/2026-10-22-subagent-tool-owned-communication.zh.md @@ -10,7 +10,7 @@ Status: implemented ## 决策 -`tool-subagent-control` 拥有通信说明和父级寻址。持久记录的运行时上下文从 Session header 读取委派子级的直接创建者 id,说明何时发送发现,并指出发送不会结束轮次。仅当本插件的工具定义在当前作用域和 step 中可用时,才向委派子级提供上下文;根代理和普通 Session fork 不接收。通信指导位于继承历史之后,不改变共享系统提示词或工具 schema。 +`tool-subagent-control` 拥有通信说明和父级寻址。持久记录的运行时上下文通过 `ctx.subagents.namesOf()` 提供委派子级的直接创建者名称,说明何时发送发现,并指出发送不会结束轮次。仅当本插件的工具定义在当前作用域和 step 中可用时,才向委派子级提供上下文;根代理和普通 Session fork 不接收。通信指导位于继承历史之后,不改变共享系统提示词或工具 schema。 管理器拥有结果交付。采用 `delivery: 'parent'` 的本地 activation 即使没有通信工具,也会收到自动结果交付指导;调用方拥有的 activation 不会收到父级交付承诺。结算时序、接收方、输出,以及最后向父级发送消息后省略结束文本的规则保持不变。工具可见性不授予通信权限。 diff --git a/.agents/notes/implemented/architecture/2026-11-02-subagent-catalog-names.i18n.yaml b/.agents/notes/implemented/architecture/2026-11-02-subagent-catalog-names.i18n.yaml new file mode 100644 index 0000000000..b5550a48c8 --- /dev/null +++ b/.agents/notes/implemented/architecture/2026-11-02-subagent-catalog-names.i18n.yaml @@ -0,0 +1,22 @@ +# Bilingual-pair consistency record for 2026-11-02-subagent-catalog-names.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-11-02-subagent-catalog-names.md +/agent-note-subagent-names-live-in-the-creator-s-catalog: + en: 987d2272bb47fe75 + zh: 54e701ecbaa60457 +/agent-note-subagent-names-live-in-the-creator-s-catalog/problem: + en: d4798e7bbbd5d49d + zh: b388470cf1ff33ac +/agent-note-subagent-names-live-in-the-creator-s-catalog/decision: + en: 8fafb256536d1bc5 + zh: f45f9e6d6f9a2407 +/agent-note-subagent-names-live-in-the-creator-s-catalog/alternatives-considered: + en: 14b564fd848248da + zh: 5f65c05bbe22d581 +/agent-note-subagent-names-live-in-the-creator-s-catalog/consequences: + en: 4baa2557e5415ee1 + zh: 8e8d7819c04f9043 +/agent-note-subagent-names-live-in-the-creator-s-catalog/testing: + en: a7963eadbfe52c21 + zh: 10bfc9fb28f6ae73 diff --git a/.agents/notes/implemented/architecture/2026-11-02-subagent-catalog-names.md b/.agents/notes/implemented/architecture/2026-11-02-subagent-catalog-names.md new file mode 100644 index 0000000000..f4ab4dada3 --- /dev/null +++ b/.agents/notes/implemented/architecture/2026-11-02-subagent-catalog-names.md @@ -0,0 +1,45 @@ +# Agent Note: Subagent names live in the creator's catalog + +Status: implemented + +English | [中文](2026-11-02-subagent-catalog-names.zh.md) + +## Problem + +Models coordinate subagents through `send_message`, `interrupt_agent`, `list_agents`, and Team task owners. Those tools addressed every member by a 36-character Session id. Models copy such ids poorly: they cannot recall which id belongs to which task, they mistype ids, and every listing, receipt, notice, and identity statement spends tokens on them. Descriptions explain responsibilities but repeat and cannot address a member. Models need short, readable references that survive restarts and resolve to exactly one member, without a second execution identity. + +## Decision + +The Session id remains the only execution identity for routing, authorization, persistence, task ownership, and navigation. A name is a model-facing reference to it. + +Each new child has a name that is unique among its creator's children. The name is a field of the `subagent/catalog` entry that the creator already appends when it creates the child, using catalog payload version 3. Local and parent-delivered external creation write it; caller-delivered external runs enter no catalog and take no name. A name is 1–32 lower-case letters, digits, or hyphens starting with a letter, and is never `lead`. A 36-character UUID therefore never parses as a name. Omission selects the first free `agent-N`. An explicit name already held by a sibling fails with `DUPLICATE_AGENT_NAME`, and an invalid name fails with `INVALID_AGENT_NAME`. + +The creator reserves the name synchronously at admission, before startup awaits anything. The reservation lives in process memory beside the creator's committed catalog names and is released when the catalog entry commits or startup fails. Task assignment copies the immutable full name into optional `ownerName` beside `ownerId` in the same task event. Task reads use this saved value and fall back to `ownerId`, so display does not require catalog traversal. + +The root is always `lead`. A descendant's full name is the slash-separated path of names from the root without a `lead/` prefix, such as `reviewer/checker`. Sibling-unique segments make full names unique in the tree. A child whose catalog entry predates names, and every descendant below it, keeps its Session id as its name. + +`ctx.subagents.resolveName()` returns the Session id for `lead` or a full name by reading only the catalogs along the path; any other text is returned unchanged as a Session id. Tools resolve before they call messaging, interruption, or Team assignment, and those operations authorize the resulting Session id. Resolution grants no authority. Runtime-authored text names agents by full name, while durable attribution such as `senderSessionId` and Team `ownerId` keeps Session ids. The [subagent runtime](../../../../packages/subagent/subagent/README.md#agent-names) owns the API contract and the [upgrade guide](../../../../docs/upgrade-guide/v0.2.2-alpha.3/subagent-names/guide.md) owns caller migration. + +This supersedes the rejection of "unique names as sibling-routing opt-in" and the statement that creation accepts no member name in [subagent teammates](2026-10-15-agent-teams-as-subagents.md), and the Session-id identity text in [required runtime-context identity](2026-10-13-team-identity-runtime-context.md). Their single-identity, Team, and runtime-context retention decisions remain active. + +## Alternatives considered + +**Optional naming plugin with a root-Session binding event.** A separate plugin would record a name-to-Session binding in the root Session after the child starts. That adds a second write that can fail independently after startup succeeds, so a started child can lack its binding, and binding after start can report errors for children that are already running. The presentation plugin would then own cancellation of a lifecycle it does not control, would rewrite runtime-authored messages that name agents, and would still change model-visible schemas when it is absent, because the core tools must accept and render either form. Recording the name in the creator's existing catalog fact needs no second write, no rollback protocol, and no optional service. + +**Flat names unique across the tree.** A tree-wide flat namespace needs one registry at the root that every creation must consult and update, including creations by descendants whose root may be cold. Sibling-unique segments joined into paths are unique without a root registry, and each creator checks only its own catalog. + +**Recyclable names.** Releasing a name when its child settles would let a later sibling take it. A model that still remembers the earlier child would then message or interrupt a different agent. A name stays taken for as long as the catalog entry exists. + +**Automatic suffixes on conflict.** Turning a duplicate `reviewer` into `reviewer-2` would let creation succeed, but the model would believe it holds a name that the runtime never assigned. A duplicate fails so that the model chooses a name it knows. + +## Consequences + +Catalog payload version 3 is a same-format addition: `SESSION_FORMAT_VERSION` is unchanged, current readers accept versions 0 through 3, and releases that predate names reject version 3 loudly. The `subagentCatalog` projection state version remains 6 because old checkpoint facts keep their meaning and accept named suffix events; invalidating them would add full catalog folds to cold descendant observations without changing the recovered state. Native admission rejects a repeated sibling name in own catalog facts, so a log that could make name lookup ambiguous fails before any member is resolved. The [persistence acknowledgement](../../../../docs/persistence-changes/2026-11-02-subagent-catalog-names.md) records the type change. + +Tool schemas grow by one optional `name` parameter on each delegation tool, and `send_message` and `interrupt_agent` rename `agent_id` to `agent`. These schema changes invalidate cached request prefixes once after upgrading. Identity runtime context, receipts, settlement notices, agent messages, and listing rows become shorter for shallow trees, while full names lengthen with nesting depth. `list_agents` drops parent ids and depth because a full name encodes both. + +Names cannot be renamed or recycled. Historical children have no names, and no migration assigns them. Name reservations are process-local, as is subagent residency. Tools still accept Session ids, so recorded Session ids and members below unnamed creators remain addressable. + +## Testing + +Runtime tests cover requested and default names, duplicate and invalid names rejected before startup, reservation across concurrent startup and release after failed startup, nested paths and `namesOf`, resolution of names, unknown text, and Session ids without granting authority, cold restoration of a member's path from the catalogs along its creation chain, and Session-id addressing below an unnamed historical creator. Catalog tests restore version-3 names beside unnamed historical entries, and the V4 format reader admits native version-3 catalog facts. Control-tool and Team-tool tests cover name-addressed messaging, listing rows, owner names, and historical owners shown by Session id. Recorded sessions pin the tool schemas, identity runtime context, receipts, listing rows, and Team policy text. diff --git a/.agents/notes/implemented/architecture/2026-11-02-subagent-catalog-names.zh.md b/.agents/notes/implemented/architecture/2026-11-02-subagent-catalog-names.zh.md new file mode 100644 index 0000000000..ec05878efb --- /dev/null +++ b/.agents/notes/implemented/architecture/2026-11-02-subagent-catalog-names.zh.md @@ -0,0 +1,45 @@ +# Agent Note: Subagent 名称记录在创建者目录中 + +Status: implemented + +[English](2026-11-02-subagent-catalog-names.md) | 中文 + +## Problem + +模型通过 `send_message`、`interrupt_agent`、`list_agents` 和 Team 任务所有者协调 subagent(子智能体)。这些工具曾以 36 字符的 Session id 寻址每个成员。模型难以准确复制这类 id:记不清哪个 id 对应哪个任务,会输错 id,而且每次列表、回执、通知和身份声明都要为其消耗 token。描述能说明职责,但可以重复,无法寻址成员。模型需要简短、可读、跨重启有效且只解析到唯一成员的引用,同时不引入第二种执行身份。 + +## Decision + +Session id 仍是路由、授权、持久化、任务归属和导航使用的唯一执行身份。名称是指向它的面向模型的引用。 + +每个新子级都有一个名称,在其创建者的子级之间唯一。名称是创建者在创建子级时本就会追加的 `subagent/catalog` 条目中的一个字段,使用第 3 版目录载荷。本地创建和父级投递的外部创建写入名称;调用方投递的外部执行不进入目录,也没有名称。名称由 1–32 个小写字母、数字或连字符组成,以字母开头,且绝不能是 `lead`。因此 36 字符的 UUID 永远不会被解析为名称。省略时选择第一个空闲的 `agent-N`。显式请求同级已持有的名称会以 `DUPLICATE_AGENT_NAME` 失败,无效名称以 `INVALID_AGENT_NAME` 失败。 + +创建者在准入时、启动等待任何操作之前同步预留名称。预留保存在进程内存中,与创建者已提交的目录名称并列,并在目录条目提交或启动失败时释放。任务分配在同一个任务事件中,将不可变的完整名称复制到 `ownerId` 旁的可选 `ownerName`。任务读取使用此保存值,缺失时回退到 `ownerId`,因此展示无需遍历目录。 + +根的名称始终为 `lead`。后代的完整名称是从根开始、以斜杠分隔的名称路径,不带 `lead/` 前缀,例如 `reviewer/checker`。同级唯一的各段使完整名称在整棵树中唯一。目录条目早于名称机制的子级及其下所有后代继续以 Session id 作为名称。 + +`ctx.subagents.resolveName()` 只读取路径上的目录,为 `lead` 或完整名称返回 Session id;其他文本原样作为 Session id 返回。工具先解析名称,再调用消息、中断或 Team 分配,由这些操作对解析出的 Session id 授权。解析本身不授予权限。运行时撰写的文本以完整名称指称 agent,而 `senderSessionId` 和 Team `ownerId` 等持久归属仍保留 Session id。[subagent 运行时](../../../../packages/subagent/subagent/README.zh.md#agent-names)定义 API 约定,[升级指南](../../../../docs/upgrade-guide/v0.2.2-alpha.3/subagent-names/guide.zh.md)负责调用方迁移。 + +本决策取代 [Agent Teams 队友是子代理](2026-10-15-agent-teams-as-subagents.zh.md)中对“以唯一名称选择性启用同级路由”的否决以及“创建不接收成员名称”的表述,并取代[必需运行时身份](2026-10-13-team-identity-runtime-context.zh.md)中以 Session id 表述身份的文本。它们的单一身份、Team 和运行时上下文保留决策仍然有效。 + +## Alternatives considered + +**带根 Session 绑定事件的可选命名插件。** 独立插件会在子级启动后,在根 Session 中记录名称到 Session 的绑定。这会增加第二次写入,且可能在启动成功后单独失败,导致已启动的子级缺少绑定;启动后再绑定还可能为已在运行的子级报告错误。展示用插件因此要负责取消一个不受它控制的生命周期,要改写指称 agent 的运行时消息;而且即使插件不存在,面向模型的 schema 仍会改变,因为核心工具必须接受并渲染两种形式。把名称记录在创建者已有的目录事实中,不需要第二次写入、回滚协议或可选服务。 + +**全树唯一的扁平名称。** 全树扁平命名空间需要根上的一个注册表,每次创建都要查询并更新它,包括根可能处于冷状态时由后代发起的创建。同级唯一的各段连接成路径后无需根注册表即可唯一,每个创建者只检查自己的目录。 + +**可回收名称。** 子级结算后释放名称会让之后的同级取得该名称。仍记得先前子级的模型会因此向另一个 agent 发消息或发出中断。只要目录条目存在,名称就保持占用。 + +**冲突时自动加后缀。** 把重复的 `reviewer` 改为 `reviewer-2` 能让创建成功,但模型会以为自己持有一个运行时从未分配的名称。重复名称直接失败,模型才会选择一个自己知道的名称。 + +## Consequences + +第 3 版目录载荷是同格式增量:`SESSION_FORMAT_VERSION` 不变,当前读取器接受第 0 至第 3 版,早于名称机制的发布会明确拒绝第 3 版。`subagentCatalog` 投影状态版本保持为 6,因为旧检查点事实的含义不变,且能继续处理具名后缀事件;使其失效会在冷后代观察时增加完整目录折叠,却不改变恢复结果。原生准入会拒绝自身目录事实中重复的同级名称,因此会让名称查找产生歧义的日志在解析任何成员之前就失败。[持久化确认记录](../../../../docs/persistence-changes/2026-11-02-subagent-catalog-names.zh.md)记录了该类型变更。 + +每个委派工具的 schema 增加一个可选 `name` 参数,`send_message` 和 `interrupt_agent` 把 `agent_id` 改名为 `agent`。这些 schema 变更会在升级后使缓存的请求前缀失效一次。对浅层树而言,身份运行时上下文、回执、结算通知、agent 消息和列表行都变短,完整名称则随嵌套深度变长。`list_agents` 不再携带父级 id 和深度,因为完整名称已包含这两项信息。 + +名称不能修改或回收。历史子级没有名称,也没有迁移为其分配名称。名称预留与 subagent 驻留一样仅限进程内。工具仍接受 Session id,因此已记录的 Session id 和无名创建者下的成员仍可寻址。 + +## Testing + +运行时测试覆盖请求名称与默认名称、启动前拒绝重复和无效名称、并发启动期间的预留和启动失败后的释放、嵌套路径与 `namesOf`、在不授予权限的前提下解析名称、未知文本和 Session id、从创建链上的目录冷恢复成员路径,以及无名历史创建者之下以 Session id 寻址。目录测试在无名历史条目旁恢复第 3 版名称,V4 格式读取器接纳原生第 3 版目录事实。控制工具和 Team 工具测试覆盖按名称发消息、列表行、所有者名称,以及以 Session id 显示的历史所有者。录制会话固定工具 schema、身份运行时上下文、回执、列表行和 Team 策略文本。 diff --git a/.agents/notes/implemented/feature/2026-10-26-manual-generation-continuation.i18n.yaml b/.agents/notes/implemented/feature/2026-10-26-manual-generation-continuation.i18n.yaml new file mode 100644 index 0000000000..79b2e5d678 --- /dev/null +++ b/.agents/notes/implemented/feature/2026-10-26-manual-generation-continuation.i18n.yaml @@ -0,0 +1,22 @@ +# Bilingual-pair consistency record for 2026-10-26-manual-generation-continuation.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/feature/2026-10-26-manual-generation-continuation.md +/agent-note-manual-generation-continuation: + en: 327aaa1cdc63b1f5 + zh: 1147b4a23e51772c +/agent-note-manual-generation-continuation/problem: + en: f118844946afdbdc + zh: f1fe37d042f88b24 +/agent-note-manual-generation-continuation/decision: + en: 463db7deb7710e07 + zh: cfacb69cb58349a9 +/agent-note-manual-generation-continuation/alternatives-considered: + en: 58bb948d210d42ea + zh: 5dc920d222d71218 +/agent-note-manual-generation-continuation/consequences: + en: e86aee3a7da7649f + zh: d58e8cc94e5008bf +/agent-note-manual-generation-continuation/verification: + en: e31a5bd5826c689f + zh: 02ac700146246664 diff --git a/.agents/notes/implemented/feature/2026-10-26-manual-generation-continuation.md b/.agents/notes/implemented/feature/2026-10-26-manual-generation-continuation.md new file mode 100644 index 0000000000..dd7a0e24f1 --- /dev/null +++ b/.agents/notes/implemented/feature/2026-10-26-manual-generation-continuation.md @@ -0,0 +1,33 @@ +# Agent Note: Manual generation continuation + +Status: implemented + +English | [中文](2026-10-26-manual-generation-continuation.zh.md) + +## Problem + +Users need another request after a model failure without inserting an artificial instruction. Browser paging can omit the failed turn's start, and streaming must not repeatedly copy history. + +## Decision + +The play action submits `content: []` through the existing Session prompt API. The API assigns `source.kind: 'retry'`; unchanged AgentLoop admission records an empty `user/message` and opens a normally balanced new turn. Chat presents a compact continuation-request receipt while the log retains the empty input. The original failed turn remains closed. + +The Session API owns the fixed-size `conversationContinuation` projection and shares its value with the browser. Admission requires an eligible failure, true idle ownership, and no pending human input. An appended empty retry message admits the new turn, preserving eligibility if its request also fails. + +The six-code manual allowlist stays independent of provider retry policy. Non-waking injected context accompanies the request. The accepted user message retains request-id deduplication after the inbox input is claimed. Reusing ordinary message admission avoids a Loop branch and a separate durable acceptance event. + +## Alternatives considered + +**Localized or hidden continuation text.** Adds model-visible instructions and changes retained history. + +**A separate resume operation.** The existing prompt and inbox already carry identified control input and own wakeup. + +**Keep the failed turn waiting for a click.** Changes failure settlement, idle status, cancellation, and model-selection semantics. + +## Consequences + +Ordinary empty-draft Enter remains inert. The explicit action reuses submission state and error reporting without an echo or generated draft. Pre-step rejection and cleared batches still prevent model calls. + +## Verification + +Unit and assembled scenarios cover repeated failure, request deduplication, injected context, balanced turns, retained tools, one original user message, and zero Client event-window reads. diff --git a/.agents/notes/implemented/feature/2026-10-26-manual-generation-continuation.zh.md b/.agents/notes/implemented/feature/2026-10-26-manual-generation-continuation.zh.md new file mode 100644 index 0000000000..dc23da7759 --- /dev/null +++ b/.agents/notes/implemented/feature/2026-10-26-manual-generation-continuation.zh.md @@ -0,0 +1,33 @@ +# Agent Note: 手动继续生成 + +Status: implemented + +[English](2026-10-26-manual-generation-continuation.md) | 中文 + +## 问题 + +模型请求失败后,用户需要再次请求,但不应插入人为构造的指令。浏览器分页可能缺少失败轮次起点,流式输出也不能反复复制历史。 + +## 决策 + +播放按钮通过现有 Session prompt API 提交 `content: []`。API 指定 `source.kind: 'retry'`;AgentLoop 沿用普通准入,记录空 `user/message` 并开启正常闭合的新轮次。Chat 显示轻量的继续请求记录,日志保留空输入。原失败轮次保持闭合。 + +Session API 拥有固定大小的 `conversationContinuation` 投影,向浏览器发布相同的值。准入要求失败符合条件、持有真正的空闲状态且没有待消费的用户输入。追加的空重试消息使新轮次获得准入,因此请求再次失败后仍保留继续资格。 + +六码手动白名单独立于提供方重试策略。非唤醒的注入上下文随请求进入。inbox 输入被领取后,已接受的用户消息仍支持 request-id 去重。复用普通消息准入避免增加 Loop 分支及独立持久接受事件。 + +## 考虑过的替代方案 + +**本地化或隐藏的继续文本。** 增加模型可见指令并改变保留历史。 + +**单独的 resume 操作。** 现有 prompt 和 inbox 已可承载带身份的控制输入并拥有唤醒流程。 + +**保持失败轮次等待点击。** 改变失败结算、空闲状态、取消和模型选择语义。 + +## 后果 + +普通空草稿回车仍不执行。显式继续沿用提交状态与错误报告,不创建消息回显或生成草稿。pre-step 拒绝和被清空的批次仍阻止模型调用。 + +## 验证 + +单元和组装场景覆盖重复失败、请求去重、注入上下文、轮次闭合、工具结果保留、仅一条原始用户消息,以及客户端不读取完整事件窗口。 diff --git a/.agents/skills/dsh-session-projection/SKILL.md b/.agents/skills/dsh-session-projection/SKILL.md index f2820d7454..1384fdb128 100644 --- a/.agents/skills/dsh-session-projection/SKILL.md +++ b/.agents/skills/dsh-session-projection/SKILL.md @@ -17,7 +17,7 @@ Keep recoverable session facts in Projection and expose them through their ownin 3. State recovery through `init` and `apply` is synchronous and deterministic. Do not perform I/O or trigger Cordis hooks, models, or tools. Runtime hooks own those effects. Replay must not repeat them. Return the same state reference for unrelated events. Keep views synchronous and preserve their references when visible values do not change. -4. Persist JSON state that its schema accepts. Follow the README's state-version and checkpoint-watermark rules. Restoring a checkpoint and replaying its suffix must match full replay. Change the version when state fields or recovery semantics change. +4. Persist JSON state that its schema accepts. Follow the README's state-version and checkpoint-watermark rules. Restoring a checkpoint and replaying its suffix must match full replay. Change the version when state fields or recovery semantics change, except for optional additions that preserve historical meaning when absent and have tested old-checkpoint suffix equivalence with full replay. Schema acceptance alone is insufficient. 5. Prefer fixed-size or sublinear state. Growth is acceptable only when slow enough to remain negligible. Necessary linear state must have a current use and explicit memory, replay, and per-event costs. Do not retain history-sized indexes, including event sequence collections, by habit. Do not discard required data or change behavior to reduce size. Start with a complete implementation; optimize for a concrete need. diff --git a/.github/workflows/macos-intel-package.yml b/.github/workflows/macos-intel-package.yml index 3fdb193807..01308037fe 100644 --- a/.github/workflows/macos-intel-package.yml +++ b/.github/workflows/macos-intel-package.yml @@ -187,6 +187,7 @@ jobs: timeout-minutes: 30 env: DESKTOP_RETAINED_DIRECTORY: ${{ needs.package.outputs.directory }} + DESKTOP_ARCHIVE_NAME: macos-x64-${{ needs.package.outputs.mode }}-${{ needs.package.outputs.version }}-${{ github.run_id }}-${{ needs.package.outputs.attempt }}.zip DESKTOP_PACKAGE_ATTEMPT: ${{ needs.package.outputs.attempt }} DESKTOP_PACKAGE_RUNNER: ${{ needs.package.outputs.runner-name }} steps: @@ -209,17 +210,17 @@ jobs: echo "PNPM_CONFIG_STORE_DIR=$DSH_DESKTOP_PACKAGE_CACHE_DIR/workspace-pnpm-store" >> "$GITHUB_ENV" - run: pnpm install --frozen-lockfile working-directory: artifact-archiver - - name: Verify original retained build before GitHub archival + - name: Archive verified retained build + id: archive working-directory: artifact-archiver run: node --import tsx apps/desktop/scripts/archive-desktop-ci.ts - name: Retain installers for the selected mode if: success() uses: actions/upload-artifact@v7.0.1 with: - name: macos-x64-${{ needs.package.outputs.mode }}-${{ needs.package.outputs.version }}-${{ github.run_id }}-${{ needs.package.outputs.attempt }} - include-hidden-files: true - path: ${{ needs.package.outputs.directory }}/* - compression-level: 0 + name: ${{ env.DESKTOP_ARCHIVE_NAME }} + path: ${{ steps.archive.outputs.path }} + archive: false if-no-files-found: error retention-days: 14 overwrite: true diff --git a/.github/workflows/macos-package.yml b/.github/workflows/macos-package.yml index f6f9f97401..4b8fd840b2 100644 --- a/.github/workflows/macos-package.yml +++ b/.github/workflows/macos-package.yml @@ -184,6 +184,7 @@ jobs: timeout-minutes: 30 env: DESKTOP_RETAINED_DIRECTORY: ${{ needs.package.outputs.directory }} + DESKTOP_ARCHIVE_NAME: macos-arm64-${{ needs.package.outputs.mode }}-${{ needs.package.outputs.version }}-${{ github.run_id }}-${{ needs.package.outputs.attempt }}.zip DESKTOP_PACKAGE_ATTEMPT: ${{ needs.package.outputs.attempt }} DESKTOP_PACKAGE_RUNNER: ${{ needs.package.outputs.runner-name }} steps: @@ -206,17 +207,17 @@ jobs: echo "PNPM_CONFIG_STORE_DIR=$DSH_DESKTOP_PACKAGE_CACHE_DIR/workspace-pnpm-store" >> "$GITHUB_ENV" - run: pnpm install --frozen-lockfile working-directory: artifact-archiver - - name: Verify original retained build before GitHub archival + - name: Archive verified retained build + id: archive working-directory: artifact-archiver run: node --import tsx apps/desktop/scripts/archive-desktop-ci.ts - name: Retain installers for the selected mode if: success() uses: actions/upload-artifact@v7.0.1 with: - name: macos-arm64-${{ needs.package.outputs.mode }}-${{ needs.package.outputs.version }}-${{ github.run_id }}-${{ needs.package.outputs.attempt }} - include-hidden-files: true - path: ${{ needs.package.outputs.directory }}/* - compression-level: 0 + name: ${{ env.DESKTOP_ARCHIVE_NAME }} + path: ${{ steps.archive.outputs.path }} + archive: false if-no-files-found: error retention-days: 14 overwrite: true diff --git a/.github/workflows/windows-package.yml b/.github/workflows/windows-package.yml index 0b137fc3b2..7a6ec241d5 100644 --- a/.github/workflows/windows-package.yml +++ b/.github/workflows/windows-package.yml @@ -220,6 +220,7 @@ jobs: env: PACKAGE_CACHE_NAMESPACE: ${{ inputs.cache_namespace }} DESKTOP_RETAINED_DIRECTORY: ${{ needs.package.outputs.directory }} + DESKTOP_ARCHIVE_NAME: windows-x64-${{ inputs.signing }}-${{ needs.package.outputs.version }}-${{ github.run_id }}-${{ needs.package.outputs.attempt }}.zip DESKTOP_PACKAGE_ATTEMPT: ${{ needs.package.outputs.attempt }} DESKTOP_PACKAGE_RUNNER: ${{ needs.package.outputs.runner-name }} steps: @@ -251,28 +252,17 @@ jobs: "PNPM_CONFIG_STORE_DIR=$storeRoot" >> $env:GITHUB_ENV - run: pnpm install --frozen-lockfile working-directory: artifact-archiver - - name: Verify original retained build before GitHub archival + - name: Archive verified retained build + id: archive working-directory: artifact-archiver run: node --import tsx apps/desktop/scripts/archive-desktop-ci.ts - - name: Retain verified unsigned installer - if: success() && inputs.signing == 'unsigned' + - name: Retain installers for the selected mode + if: success() uses: actions/upload-artifact@v7.0.1 with: - name: windows-x64-unsigned-${{ needs.package.outputs.version }}-${{ github.run_id }}-${{ needs.package.outputs.attempt }} - compression-level: 0 - include-hidden-files: true - path: ${{ needs.package.outputs.directory }}/* - if-no-files-found: error - retention-days: 14 - overwrite: true - - name: Retain verified signed installer - if: success() && inputs.signing == 'signed' - uses: actions/upload-artifact@v7.0.1 - with: - name: windows-x64-signed-${{ needs.package.outputs.version }}-${{ github.run_id }}-${{ needs.package.outputs.attempt }} - compression-level: 0 - include-hidden-files: true - path: ${{ needs.package.outputs.directory }}/* + name: ${{ env.DESKTOP_ARCHIVE_NAME }} + path: ${{ steps.archive.outputs.path }} + archive: false if-no-files-found: error retention-days: 14 overwrite: true diff --git a/apps/cli/tests/agent-team-headless.e2e.ts b/apps/cli/tests/agent-team-headless.e2e.ts index e38a33777d..026a54903c 100644 --- a/apps/cli/tests/agent-team-headless.e2e.ts +++ b/apps/cli/tests/agent-team-headless.e2e.ts @@ -102,11 +102,11 @@ describe('dsh run with Agent Teams enabled', () => { expect(eventTypes).not.toContain('team/member') const catalog = root!.filter(record => record.type === 'subagent/catalog').map(record => record.data) expect(catalog).toEqual(expect.arrayContaining([ - expect.objectContaining({ version: 0, childId: workflowChild![0]?.id }), - expect.objectContaining({ version: 0, label: 'Own deterministic implementation.' }), - expect.objectContaining({ version: 0, label: 'Own deterministic research.' }), + expect.objectContaining({ version: 3, childId: workflowChild![0]?.id, name: 'agent-1' }), + expect.objectContaining({ version: 3, label: 'Own deterministic implementation.', name: 'agent-2' }), + expect.objectContaining({ version: 3, label: 'Own deterministic research.', name: 'agent-3' }), ])) - for (const entry of catalog) expect(entry).not.toHaveProperty('name') + for (const entry of catalog) expect(entry).toHaveProperty('name') expect(eventTypes).not.toContain('subagent-name/bound') expect(eventTypes).not.toContain('team/message/queued') expect(eventTypes).not.toContain('team/message/delivered') diff --git a/apps/cli/tests/profiles/acp/tests/goal-expected/goal-round-driver/session.expected.jsonl b/apps/cli/tests/profiles/acp/tests/goal-expected/goal-round-driver/session.expected.jsonl index 8467970106..59a1c137aa 100644 --- a/apps/cli/tests/profiles/acp/tests/goal-expected/goal-round-driver/session.expected.jsonl +++ b/apps/cli/tests/profiles/acp/tests/goal-expected/goal-round-driver/session.expected.jsonl @@ -8,7 +8,7 @@ {"type":"step/start","data":{"turn":1,"step":1}} {"type":"system/message","data":{"turn":1,"step":1,"message":{"role":"system","content":[{"type":"text","text":"{{system}}"}],"source":{"kind":"system-prompt"},"id":"{{sessionId}}"}},"surfaceOp":"append"} {"type":"user/message","data":{"content":[{"type":"text","text":"Create a durable two-round goal for the ACP snapshot, inspect it, then report readiness."}],"source":{"kind":"user"},"role":"user","id":"{{sessionId}}"},"surfaceOp":"append"} -{"type":"user/message","data":{"content":[{"type":"text","text":"Current runtime context. This snapshot supersedes earlier runtime-context snapshots.\n\nCurrent working directory: \"{{cwd}}\".\n\nCurrent DSH file policy: danger-full-access. The DSH file sandbox does not restrict file modifications by available operations.\n\nApproval prompts are disabled in this session: actions that require approval are rejected automatically — do not request sandbox escalation (do not set `sandbox_permissions`).\n\nYou are the root agent. Your agent id is \"{{sessionId}}\".\n\nTo message other agents, use send_message({ agent_id: \"\", message: \"...\" }).\nUse list_agents({}) to find your collaborator agents and their ids."}],"source":{"kind":"runtime-context","form":"snapshot","sections":[{"name":"working-directory:current","text":"Current working directory: \"{{cwd}}\"."},{"name":"sandbox:policy","text":"Current DSH file policy: danger-full-access. The DSH file sandbox does not restrict file modifications by available operations."},{"name":"approval:policy","text":"Approval prompts are disabled in this session: actions that require approval are rejected automatically — do not request sandbox escalation (do not set `sandbox_permissions`)."},{"name":"subagent:identity","text":"You are the root agent. Your agent id is \"{{sessionId}}\".\n\nTo message other agents, use send_message({ agent_id: \"\", message: \"...\" }).\nUse list_agents({}) to find your collaborator agents and their ids."}]},"role":"user","id":"{{sessionId}}"},"surfaceOp":"append"} +{"type":"user/message","data":{"content":[{"type":"text","text":"Current runtime context. This snapshot supersedes earlier runtime-context snapshots.\n\nCurrent working directory: \"{{cwd}}\".\n\nCurrent DSH file policy: danger-full-access. The DSH file sandbox does not restrict file modifications by available operations.\n\nApproval prompts are disabled in this session: actions that require approval are rejected automatically — do not request sandbox escalation (do not set `sandbox_permissions`).\n\nYou are the root agent. Your name is \"lead\".\n\nTo message other agents, use send_message({ agent: \"\", message: \"...\" }).\nUse list_agents({}) to find your collaborator agents and their names."}],"source":{"kind":"runtime-context","form":"snapshot","sections":[{"name":"working-directory:current","text":"Current working directory: \"{{cwd}}\"."},{"name":"sandbox:policy","text":"Current DSH file policy: danger-full-access. The DSH file sandbox does not restrict file modifications by available operations."},{"name":"approval:policy","text":"Approval prompts are disabled in this session: actions that require approval are rejected automatically — do not request sandbox escalation (do not set `sandbox_permissions`)."},{"name":"subagent:identity","text":"You are the root agent. Your name is \"lead\".\n\nTo message other agents, use send_message({ agent: \"\", message: \"...\" }).\nUse list_agents({}) to find your collaborator agents and their names."}]},"role":"user","id":"{{sessionId}}"},"surfaceOp":"append"} {"type":"request/header","data":{"header":{"config":{"provider":"deepseek-official","model":"deepseek-v4-flash"},"tools":"{{tools}}"},"reason":"initial"}} {"type":"request/context","data":{"provider":"deepseek-official","model":"deepseek-v4-flash"}} {"type":"session/title","data":{"title":"Create a durable two-round goal","messageSeqs":[8],"source":{"kind":"fallback"}}} diff --git a/apps/cli/tests/profiles/acp/tests/goal-expected/goal-wrapup/session.expected.jsonl b/apps/cli/tests/profiles/acp/tests/goal-expected/goal-wrapup/session.expected.jsonl index a4ac54b8c1..acac6db06d 100644 --- a/apps/cli/tests/profiles/acp/tests/goal-expected/goal-wrapup/session.expected.jsonl +++ b/apps/cli/tests/profiles/acp/tests/goal-expected/goal-wrapup/session.expected.jsonl @@ -8,7 +8,7 @@ {"type":"step/start","data":{"turn":1,"step":1}} {"type":"system/message","data":{"turn":1,"step":1,"message":{"role":"system","content":[{"type":"text","text":"{{system}}"}],"source":{"kind":"system-prompt"},"id":"{{sessionId}}"}},"surfaceOp":"append"} {"type":"user/message","data":{"content":[{"type":"text","text":"Create a durable goal for the wrap-up snapshot, then report readiness."}],"source":{"kind":"user"},"role":"user","id":"{{sessionId}}"},"surfaceOp":"append"} -{"type":"user/message","data":{"content":[{"type":"text","text":"Current runtime context. This snapshot supersedes earlier runtime-context snapshots.\n\nCurrent working directory: \"{{cwd}}\".\n\nCurrent DSH file policy: danger-full-access. The DSH file sandbox does not restrict file modifications by available operations.\n\nApproval prompts are disabled in this session: actions that require approval are rejected automatically — do not request sandbox escalation (do not set `sandbox_permissions`).\n\nYou are the root agent. Your agent id is \"{{sessionId}}\".\n\nTo message other agents, use send_message({ agent_id: \"\", message: \"...\" }).\nUse list_agents({}) to find your collaborator agents and their ids."}],"source":{"kind":"runtime-context","form":"snapshot","sections":[{"name":"working-directory:current","text":"Current working directory: \"{{cwd}}\"."},{"name":"sandbox:policy","text":"Current DSH file policy: danger-full-access. The DSH file sandbox does not restrict file modifications by available operations."},{"name":"approval:policy","text":"Approval prompts are disabled in this session: actions that require approval are rejected automatically — do not request sandbox escalation (do not set `sandbox_permissions`)."},{"name":"subagent:identity","text":"You are the root agent. Your agent id is \"{{sessionId}}\".\n\nTo message other agents, use send_message({ agent_id: \"\", message: \"...\" }).\nUse list_agents({}) to find your collaborator agents and their ids."}]},"role":"user","id":"{{sessionId}}"},"surfaceOp":"append"} +{"type":"user/message","data":{"content":[{"type":"text","text":"Current runtime context. This snapshot supersedes earlier runtime-context snapshots.\n\nCurrent working directory: \"{{cwd}}\".\n\nCurrent DSH file policy: danger-full-access. The DSH file sandbox does not restrict file modifications by available operations.\n\nApproval prompts are disabled in this session: actions that require approval are rejected automatically — do not request sandbox escalation (do not set `sandbox_permissions`).\n\nYou are the root agent. Your name is \"lead\".\n\nTo message other agents, use send_message({ agent: \"\", message: \"...\" }).\nUse list_agents({}) to find your collaborator agents and their names."}],"source":{"kind":"runtime-context","form":"snapshot","sections":[{"name":"working-directory:current","text":"Current working directory: \"{{cwd}}\"."},{"name":"sandbox:policy","text":"Current DSH file policy: danger-full-access. The DSH file sandbox does not restrict file modifications by available operations."},{"name":"approval:policy","text":"Approval prompts are disabled in this session: actions that require approval are rejected automatically — do not request sandbox escalation (do not set `sandbox_permissions`)."},{"name":"subagent:identity","text":"You are the root agent. Your name is \"lead\".\n\nTo message other agents, use send_message({ agent: \"\", message: \"...\" }).\nUse list_agents({}) to find your collaborator agents and their names."}]},"role":"user","id":"{{sessionId}}"},"surfaceOp":"append"} {"type":"request/header","data":{"header":{"config":{"provider":"deepseek-official","model":"deepseek-v4-flash"},"tools":"{{tools}}"},"reason":"initial"}} {"type":"request/context","data":{"provider":"deepseek-official","model":"deepseek-v4-flash"}} {"type":"session/title","data":{"title":"Create a durable goal for","messageSeqs":[8],"source":{"kind":"fallback"}}} diff --git a/apps/cli/tests/profiles/acp/tests/image-offload.expected.e2e.ts b/apps/cli/tests/profiles/acp/tests/image-offload.expected.e2e.ts index 63715e4638..2d23d1bfa7 100644 --- a/apps/cli/tests/profiles/acp/tests/image-offload.expected.e2e.ts +++ b/apps/cli/tests/profiles/acp/tests/image-offload.expected.e2e.ts @@ -140,13 +140,13 @@ it('pins Messages Files offload and inline fallback in assembled requests', asyn const fileImage = { type: 'image', source: { type: 'file', file_id: 'file-api-snapshot-1' } } const offloadedImage = `[image omitted to fit request image limits; ${attachmentId}.${normalizedAccess}]` const imageHandle = `Image ${attachmentId}; request preview 1x1px.${normalizedAccess}` - const runtimeContext = (cwd: string, sessionId: string): string => 'Current runtime context. This snapshot supersedes earlier runtime-context snapshots.\n\n' + const runtimeContext = (cwd: string): string => 'Current runtime context. This snapshot supersedes earlier runtime-context snapshots.\n\n' + `Current working directory: ${JSON.stringify(cwd)}.\n\n` + 'Current DSH file policy: danger-full-access. The DSH file sandbox does not restrict file modifications by available operations.\n\n' + 'Approval prompts are disabled in this session: actions that require approval are rejected automatically — do not request sandbox escalation (do not set `sandbox_permissions`).\n\n' - + `You are the root agent. Your agent id is ${JSON.stringify(sessionId)}.\n\n` - + 'To message other agents, use send_message({ agent_id: "", message: "..." }).\n' - + 'Use list_agents({}) to find your collaborator agents and their ids.' + + 'You are the root agent. Your name is "lead".\n\n' + + 'To message other agents, use send_message({ agent: "", message: "..." }).\n' + + 'Use list_agents({}) to find your collaborator agents and their names.' const messages = requests[0]?.messages as { content?: unknown }[] | undefined const offloaded = messages?.find(message => JSON.stringify(message.content).includes('[image omitted')) expect(offloaded?.content).toEqual([ @@ -156,7 +156,7 @@ it('pins Messages Files offload and inline fallback in assembled requests', asyn { type: 'text', text: imageHandle }, fileImage, { type: 'text', text: ', then use read_image on red.png and reply with DONE.' }, - { type: 'text', text: runtimeContext(result.cwd, result.sessionId) }, + { type: 'text', text: runtimeContext(result.cwd) }, ]) const followup = requests[1]?.messages as Array<{ role: string; content: Array> }> @@ -208,7 +208,7 @@ it('pins Messages Files offload and inline fallback in assembled requests', asyn { type: 'text', text: `Image ${attachmentId}; request preview 1x1px.${fallbackAccess}` }, { type: 'image', source: { type: 'base64', media_type: 'image/png', data: image } }, { type: 'text', text: ', then use read_image on red.png and reply with DONE.' }, - { type: 'text', text: runtimeContext(fallback.cwd, fallback.sessionId) }, + { type: 'text', text: runtimeContext(fallback.cwd) }, ]) } finally { await new Promise(resolve => server.close(() => { resolve() })) diff --git a/apps/cli/tests/profiles/headless/tests/expected/goal-tools/stream-json.expected.jsonl b/apps/cli/tests/profiles/headless/tests/expected/goal-tools/stream-json.expected.jsonl index 7779eb2181..7323185cf5 100644 --- a/apps/cli/tests/profiles/headless/tests/expected/goal-tools/stream-json.expected.jsonl +++ b/apps/cli/tests/profiles/headless/tests/expected/goal-tools/stream-json.expected.jsonl @@ -4,7 +4,7 @@ {"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"step/start","seq":6,"time":0,"data":{"turn":1,"step":1}}} {"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"system/message","seq":7,"time":0,"data":{"turn":1,"step":1,"message":{"role":"system","content":[{"type":"text","text":"{{system}}"}],"source":{"kind":"system-prompt"},"id":"{{sessionId}}"}},"surfaceOp":"append"}} {"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"user/message","seq":8,"time":0,"data":{"content":[{"type":"text","text":"Probe strict-schema fillers against missing-goal revision 1, then create a durable goal to finish the snapshot proof and inspect it."}],"source":{"kind":"user"},"role":"user","id":"{{sessionId}}"},"surfaceOp":"append"}} -{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"user/message","seq":9,"time":0,"data":{"content":[{"type":"text","text":"Current runtime context. This snapshot supersedes earlier runtime-context snapshots.\n\nCurrent working directory: \"{{cwd}}\".\n\nCurrent DSH file policy: workspace-write. Any available operation enforced by the DSH file sandbox may modify files under the session workspace: \"{{cwd}}\". Some platform temporary areas may also be writable.\n\nApproval prompts are enabled in this session: operations that require approval may ask through the configured answerers; without an available answerer, the request fails closed.\n\nYou are the root agent. Your agent id is \"{{sessionId}}\".\n\nTo message other agents, use send_message({ agent_id: \"\", message: \"...\" }).\nUse list_agents({}) to find your collaborator agents and their ids."}],"source":{"kind":"runtime-context","form":"snapshot","sections":[{"name":"working-directory:current","text":"Current working directory: \"{{cwd}}\"."},{"name":"sandbox:policy","text":"Current DSH file policy: workspace-write. Any available operation enforced by the DSH file sandbox may modify files under the session workspace: \"{{cwd}}\". Some platform temporary areas may also be writable."},{"name":"approval:policy","text":"Approval prompts are enabled in this session: operations that require approval may ask through the configured answerers; without an available answerer, the request fails closed."},{"name":"subagent:identity","text":"You are the root agent. Your agent id is \"{{sessionId}}\".\n\nTo message other agents, use send_message({ agent_id: \"\", message: \"...\" }).\nUse list_agents({}) to find your collaborator agents and their ids."}]},"role":"user","id":"{{sessionId}}"},"surfaceOp":"append"}} +{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"user/message","seq":9,"time":0,"data":{"content":[{"type":"text","text":"Current runtime context. This snapshot supersedes earlier runtime-context snapshots.\n\nCurrent working directory: \"{{cwd}}\".\n\nCurrent DSH file policy: workspace-write. Any available operation enforced by the DSH file sandbox may modify files under the session workspace: \"{{cwd}}\". Some platform temporary areas may also be writable.\n\nApproval prompts are enabled in this session: operations that require approval may ask through the configured answerers; without an available answerer, the request fails closed.\n\nYou are the root agent. Your name is \"lead\".\n\nTo message other agents, use send_message({ agent: \"\", message: \"...\" }).\nUse list_agents({}) to find your collaborator agents and their names."}],"source":{"kind":"runtime-context","form":"snapshot","sections":[{"name":"working-directory:current","text":"Current working directory: \"{{cwd}}\"."},{"name":"sandbox:policy","text":"Current DSH file policy: workspace-write. Any available operation enforced by the DSH file sandbox may modify files under the session workspace: \"{{cwd}}\". Some platform temporary areas may also be writable."},{"name":"approval:policy","text":"Approval prompts are enabled in this session: operations that require approval may ask through the configured answerers; without an available answerer, the request fails closed."},{"name":"subagent:identity","text":"You are the root agent. Your name is \"lead\".\n\nTo message other agents, use send_message({ agent: \"\", message: \"...\" }).\nUse list_agents({}) to find your collaborator agents and their names."}]},"role":"user","id":"{{sessionId}}"},"surfaceOp":"append"}} {"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"request/header","seq":10,"time":0,"data":{"header":{"config":{"provider":"deepseek-official","model":"deepseek-v4-flash"},"tools":"{{tools}}"},"reason":"initial"}}} {"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"request/context","seq":11,"time":0,"data":{"provider":"deepseek-official","model":"deepseek-v4-flash"}}} {"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"session/title","seq":12,"time":0,"data":{"title":"Probe strict-schema fillers against miss","messageSeqs":[8],"source":{"kind":"fallback"}}}} diff --git a/apps/cli/tests/profiles/headless/tests/expected/headless-profile/session.expected.jsonl b/apps/cli/tests/profiles/headless/tests/expected/headless-profile/session.expected.jsonl index d4385b311d..233b696634 100644 --- a/apps/cli/tests/profiles/headless/tests/expected/headless-profile/session.expected.jsonl +++ b/apps/cli/tests/profiles/headless/tests/expected/headless-profile/session.expected.jsonl @@ -8,7 +8,7 @@ {"type":"step/start","data":{"turn":1,"step":1}} {"type":"system/message","data":{"turn":1,"step":1,"message":{"role":"system","content":[{"type":"text","text":"{{system}}"}],"source":{"kind":"system-prompt"},"id":"{{sessionId}}"}},"surfaceOp":"append"} {"type":"user/message","data":{"content":[{"type":"text","text":"Prove the product headless profile path with one real tool round trip."}],"source":{"kind":"user"},"role":"user","id":"{{sessionId}}"},"surfaceOp":"append"} -{"type":"user/message","data":{"content":[{"type":"text","text":"Current runtime context. This snapshot supersedes earlier runtime-context snapshots.\n\nCurrent working directory: \"{{cwd}}\".\n\nCurrent DSH file policy: danger-full-access. The DSH file sandbox does not restrict file modifications by available operations.\n\nApproval prompts are disabled in this session: actions that require approval are rejected automatically — do not request sandbox escalation (do not set `sandbox_permissions`).\n\nYou are the root agent. Your agent id is \"{{sessionId}}\".\n\nTo message other agents, use send_message({ agent_id: \"\", message: \"...\" }).\nUse list_agents({}) to find your collaborator agents and their ids."}],"source":{"kind":"runtime-context","form":"snapshot","sections":[{"name":"working-directory:current","text":"Current working directory: \"{{cwd}}\"."},{"name":"sandbox:policy","text":"Current DSH file policy: danger-full-access. The DSH file sandbox does not restrict file modifications by available operations."},{"name":"approval:policy","text":"Approval prompts are disabled in this session: actions that require approval are rejected automatically — do not request sandbox escalation (do not set `sandbox_permissions`)."},{"name":"subagent:identity","text":"You are the root agent. Your agent id is \"{{sessionId}}\".\n\nTo message other agents, use send_message({ agent_id: \"\", message: \"...\" }).\nUse list_agents({}) to find your collaborator agents and their ids."}]},"role":"user","id":"{{sessionId}}"},"surfaceOp":"append"} +{"type":"user/message","data":{"content":[{"type":"text","text":"Current runtime context. This snapshot supersedes earlier runtime-context snapshots.\n\nCurrent working directory: \"{{cwd}}\".\n\nCurrent DSH file policy: danger-full-access. The DSH file sandbox does not restrict file modifications by available operations.\n\nApproval prompts are disabled in this session: actions that require approval are rejected automatically — do not request sandbox escalation (do not set `sandbox_permissions`).\n\nYou are the root agent. Your name is \"lead\".\n\nTo message other agents, use send_message({ agent: \"\", message: \"...\" }).\nUse list_agents({}) to find your collaborator agents and their names."}],"source":{"kind":"runtime-context","form":"snapshot","sections":[{"name":"working-directory:current","text":"Current working directory: \"{{cwd}}\"."},{"name":"sandbox:policy","text":"Current DSH file policy: danger-full-access. The DSH file sandbox does not restrict file modifications by available operations."},{"name":"approval:policy","text":"Approval prompts are disabled in this session: actions that require approval are rejected automatically — do not request sandbox escalation (do not set `sandbox_permissions`)."},{"name":"subagent:identity","text":"You are the root agent. Your name is \"lead\".\n\nTo message other agents, use send_message({ agent: \"\", message: \"...\" }).\nUse list_agents({}) to find your collaborator agents and their names."}]},"role":"user","id":"{{sessionId}}"},"surfaceOp":"append"} {"type":"request/header","data":{"header":{"config":{"provider":"cli-mock","model":"cli-mock","reasoningEffort":"high"},"adapterDefaults":{"reasoningEffort":true},"tools":"{{tools}}"},"reason":"initial"}} {"type":"request/context","data":{"provider":"cli-mock","model":"cli-mock"}} {"type":"session/title","data":{"title":"Prove the product headless profile","messageSeqs":[8],"source":{"kind":"fallback"}}} diff --git a/apps/cli/tests/profiles/headless/tests/expected/invalid-credential/stream-json.expected.jsonl b/apps/cli/tests/profiles/headless/tests/expected/invalid-credential/stream-json.expected.jsonl index 6cebc92a87..117f517cb8 100644 --- a/apps/cli/tests/profiles/headless/tests/expected/invalid-credential/stream-json.expected.jsonl +++ b/apps/cli/tests/profiles/headless/tests/expected/invalid-credential/stream-json.expected.jsonl @@ -4,7 +4,7 @@ {"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"step/start","seq":6,"time":0,"data":{"turn":1,"step":1}}} {"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"system/message","seq":7,"time":0,"data":{"turn":1,"step":1,"message":{"role":"system","content":[{"type":"text","text":"{{system}}"}],"source":{"kind":"system-prompt"},"id":"{{sessionId}}"}},"surfaceOp":"append"}} {"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"user/message","seq":8,"time":0,"data":{"content":[{"type":"text","text":"say pong"}],"source":{"kind":"user"},"role":"user","id":"{{sessionId}}"},"surfaceOp":"append"}} -{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"user/message","seq":9,"time":0,"data":{"content":[{"type":"text","text":"Current runtime context. This snapshot supersedes earlier runtime-context snapshots.\n\nCurrent working directory: \"{{cwd}}\".\n\nCurrent DSH file policy: workspace-write. Any available operation enforced by the DSH file sandbox may modify files under the session workspace: \"{{cwd}}\". Some platform temporary areas may also be writable.\n\nApproval prompts are enabled in this session: operations that require approval may ask through the configured answerers; without an available answerer, the request fails closed.\n\nYou are the root agent. Your agent id is \"{{sessionId}}\".\n\nTo message other agents, use send_message({ agent_id: \"\", message: \"...\" }).\nUse list_agents({}) to find your collaborator agents and their ids."}],"source":{"kind":"runtime-context","form":"snapshot","sections":[{"name":"working-directory:current","text":"Current working directory: \"{{cwd}}\"."},{"name":"sandbox:policy","text":"Current DSH file policy: workspace-write. Any available operation enforced by the DSH file sandbox may modify files under the session workspace: \"{{cwd}}\". Some platform temporary areas may also be writable."},{"name":"approval:policy","text":"Approval prompts are enabled in this session: operations that require approval may ask through the configured answerers; without an available answerer, the request fails closed."},{"name":"subagent:identity","text":"You are the root agent. Your agent id is \"{{sessionId}}\".\n\nTo message other agents, use send_message({ agent_id: \"\", message: \"...\" }).\nUse list_agents({}) to find your collaborator agents and their ids."}]},"role":"user","id":"{{sessionId}}"},"surfaceOp":"append"}} +{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"user/message","seq":9,"time":0,"data":{"content":[{"type":"text","text":"Current runtime context. This snapshot supersedes earlier runtime-context snapshots.\n\nCurrent working directory: \"{{cwd}}\".\n\nCurrent DSH file policy: workspace-write. Any available operation enforced by the DSH file sandbox may modify files under the session workspace: \"{{cwd}}\". Some platform temporary areas may also be writable.\n\nApproval prompts are enabled in this session: operations that require approval may ask through the configured answerers; without an available answerer, the request fails closed.\n\nYou are the root agent. Your name is \"lead\".\n\nTo message other agents, use send_message({ agent: \"\", message: \"...\" }).\nUse list_agents({}) to find your collaborator agents and their names."}],"source":{"kind":"runtime-context","form":"snapshot","sections":[{"name":"working-directory:current","text":"Current working directory: \"{{cwd}}\"."},{"name":"sandbox:policy","text":"Current DSH file policy: workspace-write. Any available operation enforced by the DSH file sandbox may modify files under the session workspace: \"{{cwd}}\". Some platform temporary areas may also be writable."},{"name":"approval:policy","text":"Approval prompts are enabled in this session: operations that require approval may ask through the configured answerers; without an available answerer, the request fails closed."},{"name":"subagent:identity","text":"You are the root agent. Your name is \"lead\".\n\nTo message other agents, use send_message({ agent: \"\", message: \"...\" }).\nUse list_agents({}) to find your collaborator agents and their names."}]},"role":"user","id":"{{sessionId}}"},"surfaceOp":"append"}} {"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"request/header","seq":10,"time":0,"data":{"header":{"config":{"provider":"deepseek-official","model":"deepseek-v4-flash","maxTokens":256000,"reasoningEffort":"high"},"adapterDefaults":{"reasoningEffort":true,"maxTokens":true},"tools":"{{tools}}"},"reason":"initial"}}} {"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"request/context","seq":11,"time":0,"data":{"provider":"deepseek-official","model":"deepseek-v4-flash","contextWindow":1000000}}} {"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"session/title","seq":12,"time":0,"data":{"title":"say pong","messageSeqs":[8],"source":{"kind":"fallback"}}}} diff --git a/apps/cli/tests/profiles/headless/tests/expected/missing-credential/stream-json.expected.jsonl b/apps/cli/tests/profiles/headless/tests/expected/missing-credential/stream-json.expected.jsonl index 8cc16706c1..39a2f16c0d 100644 --- a/apps/cli/tests/profiles/headless/tests/expected/missing-credential/stream-json.expected.jsonl +++ b/apps/cli/tests/profiles/headless/tests/expected/missing-credential/stream-json.expected.jsonl @@ -4,7 +4,7 @@ {"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"step/start","seq":6,"time":0,"data":{"turn":1,"step":1}}} {"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"system/message","seq":7,"time":0,"data":{"turn":1,"step":1,"message":{"role":"system","content":[{"type":"text","text":"{{system}}"}],"source":{"kind":"system-prompt"},"id":"{{sessionId}}"}},"surfaceOp":"append"}} {"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"user/message","seq":8,"time":0,"data":{"content":[{"type":"text","text":"say pong"}],"source":{"kind":"user"},"role":"user","id":"{{sessionId}}"},"surfaceOp":"append"}} -{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"user/message","seq":9,"time":0,"data":{"content":[{"type":"text","text":"Current runtime context. This snapshot supersedes earlier runtime-context snapshots.\n\nCurrent working directory: \"{{cwd}}\".\n\nCurrent DSH file policy: workspace-write. Any available operation enforced by the DSH file sandbox may modify files under the session workspace: \"{{cwd}}\". Some platform temporary areas may also be writable.\n\nApproval prompts are enabled in this session: operations that require approval may ask through the configured answerers; without an available answerer, the request fails closed.\n\nYou are the root agent. Your agent id is \"{{sessionId}}\".\n\nTo message other agents, use send_message({ agent_id: \"\", message: \"...\" }).\nUse list_agents({}) to find your collaborator agents and their ids."}],"source":{"kind":"runtime-context","form":"snapshot","sections":[{"name":"working-directory:current","text":"Current working directory: \"{{cwd}}\"."},{"name":"sandbox:policy","text":"Current DSH file policy: workspace-write. Any available operation enforced by the DSH file sandbox may modify files under the session workspace: \"{{cwd}}\". Some platform temporary areas may also be writable."},{"name":"approval:policy","text":"Approval prompts are enabled in this session: operations that require approval may ask through the configured answerers; without an available answerer, the request fails closed."},{"name":"subagent:identity","text":"You are the root agent. Your agent id is \"{{sessionId}}\".\n\nTo message other agents, use send_message({ agent_id: \"\", message: \"...\" }).\nUse list_agents({}) to find your collaborator agents and their ids."}]},"role":"user","id":"{{sessionId}}"},"surfaceOp":"append"}} +{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"user/message","seq":9,"time":0,"data":{"content":[{"type":"text","text":"Current runtime context. This snapshot supersedes earlier runtime-context snapshots.\n\nCurrent working directory: \"{{cwd}}\".\n\nCurrent DSH file policy: workspace-write. Any available operation enforced by the DSH file sandbox may modify files under the session workspace: \"{{cwd}}\". Some platform temporary areas may also be writable.\n\nApproval prompts are enabled in this session: operations that require approval may ask through the configured answerers; without an available answerer, the request fails closed.\n\nYou are the root agent. Your name is \"lead\".\n\nTo message other agents, use send_message({ agent: \"\", message: \"...\" }).\nUse list_agents({}) to find your collaborator agents and their names."}],"source":{"kind":"runtime-context","form":"snapshot","sections":[{"name":"working-directory:current","text":"Current working directory: \"{{cwd}}\"."},{"name":"sandbox:policy","text":"Current DSH file policy: workspace-write. Any available operation enforced by the DSH file sandbox may modify files under the session workspace: \"{{cwd}}\". Some platform temporary areas may also be writable."},{"name":"approval:policy","text":"Approval prompts are enabled in this session: operations that require approval may ask through the configured answerers; without an available answerer, the request fails closed."},{"name":"subagent:identity","text":"You are the root agent. Your name is \"lead\".\n\nTo message other agents, use send_message({ agent: \"\", message: \"...\" }).\nUse list_agents({}) to find your collaborator agents and their names."}]},"role":"user","id":"{{sessionId}}"},"surfaceOp":"append"}} {"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"request/header","seq":10,"time":0,"data":{"header":{"config":{"provider":"deepseek-official","model":"deepseek-v4-flash","maxTokens":256000,"reasoningEffort":"high"},"adapterDefaults":{"reasoningEffort":true,"maxTokens":true},"tools":"{{tools}}"},"reason":"initial"}}} {"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"request/context","seq":11,"time":0,"data":{"provider":"deepseek-official","model":"deepseek-v4-flash","contextWindow":1000000}}} {"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"session/title","seq":12,"time":0,"data":{"title":"say pong","messageSeqs":[8],"source":{"kind":"fallback"}}}} diff --git a/apps/cli/tests/profiles/headless/tests/expected/provider-retry/stream-json.expected.jsonl b/apps/cli/tests/profiles/headless/tests/expected/provider-retry/stream-json.expected.jsonl index 8488837003..e6861c5f68 100644 --- a/apps/cli/tests/profiles/headless/tests/expected/provider-retry/stream-json.expected.jsonl +++ b/apps/cli/tests/profiles/headless/tests/expected/provider-retry/stream-json.expected.jsonl @@ -4,7 +4,7 @@ {"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"step/start","seq":6,"time":0,"data":{"turn":1,"step":1}}} {"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"system/message","seq":7,"time":0,"data":{"turn":1,"step":1,"message":{"role":"system","content":[{"type":"text","text":"{{system}}"}],"source":{"kind":"system-prompt"},"id":"{{sessionId}}"}},"surfaceOp":"append"}} {"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"user/message","seq":8,"time":0,"data":{"content":[{"type":"text","text":"retry the transient provider failure"}],"source":{"kind":"user"},"role":"user","id":"{{sessionId}}"},"surfaceOp":"append"}} -{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"user/message","seq":9,"time":0,"data":{"content":[{"type":"text","text":"Current runtime context. This snapshot supersedes earlier runtime-context snapshots.\n\nCurrent working directory: \"{{cwd}}\".\n\nCurrent DSH file policy: workspace-write. Any available operation enforced by the DSH file sandbox may modify files under the session workspace: \"{{cwd}}\". Some platform temporary areas may also be writable.\n\nApproval prompts are enabled in this session: operations that require approval may ask through the configured answerers; without an available answerer, the request fails closed.\n\nYou are the root agent. Your agent id is \"{{sessionId}}\".\n\nTo message other agents, use send_message({ agent_id: \"\", message: \"...\" }).\nUse list_agents({}) to find your collaborator agents and their ids."}],"source":{"kind":"runtime-context","form":"snapshot","sections":[{"name":"working-directory:current","text":"Current working directory: \"{{cwd}}\"."},{"name":"sandbox:policy","text":"Current DSH file policy: workspace-write. Any available operation enforced by the DSH file sandbox may modify files under the session workspace: \"{{cwd}}\". Some platform temporary areas may also be writable."},{"name":"approval:policy","text":"Approval prompts are enabled in this session: operations that require approval may ask through the configured answerers; without an available answerer, the request fails closed."},{"name":"subagent:identity","text":"You are the root agent. Your agent id is \"{{sessionId}}\".\n\nTo message other agents, use send_message({ agent_id: \"\", message: \"...\" }).\nUse list_agents({}) to find your collaborator agents and their ids."}]},"role":"user","id":"{{sessionId}}"},"surfaceOp":"append"}} +{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"user/message","seq":9,"time":0,"data":{"content":[{"type":"text","text":"Current runtime context. This snapshot supersedes earlier runtime-context snapshots.\n\nCurrent working directory: \"{{cwd}}\".\n\nCurrent DSH file policy: workspace-write. Any available operation enforced by the DSH file sandbox may modify files under the session workspace: \"{{cwd}}\". Some platform temporary areas may also be writable.\n\nApproval prompts are enabled in this session: operations that require approval may ask through the configured answerers; without an available answerer, the request fails closed.\n\nYou are the root agent. Your name is \"lead\".\n\nTo message other agents, use send_message({ agent: \"\", message: \"...\" }).\nUse list_agents({}) to find your collaborator agents and their names."}],"source":{"kind":"runtime-context","form":"snapshot","sections":[{"name":"working-directory:current","text":"Current working directory: \"{{cwd}}\"."},{"name":"sandbox:policy","text":"Current DSH file policy: workspace-write. Any available operation enforced by the DSH file sandbox may modify files under the session workspace: \"{{cwd}}\". Some platform temporary areas may also be writable."},{"name":"approval:policy","text":"Approval prompts are enabled in this session: operations that require approval may ask through the configured answerers; without an available answerer, the request fails closed."},{"name":"subagent:identity","text":"You are the root agent. Your name is \"lead\".\n\nTo message other agents, use send_message({ agent: \"\", message: \"...\" }).\nUse list_agents({}) to find your collaborator agents and their names."}]},"role":"user","id":"{{sessionId}}"},"surfaceOp":"append"}} {"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"request/header","seq":10,"time":0,"data":{"header":{"config":{"provider":"deepseek-official","model":"deepseek-v4-flash"},"tools":"{{tools}}"},"reason":"initial"}}} {"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"request/context","seq":11,"time":0,"data":{"provider":"deepseek-official","model":"deepseek-v4-flash"}}} {"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"session/title","seq":12,"time":0,"data":{"title":"retry the transient provider failure","messageSeqs":[8],"source":{"kind":"fallback"}}}} diff --git a/apps/cli/tests/profiles/headless/tests/expected/semantic-checkpoint/session.expected.jsonl b/apps/cli/tests/profiles/headless/tests/expected/semantic-checkpoint/session.expected.jsonl index c14e345b7f..b8c1abf034 100644 --- a/apps/cli/tests/profiles/headless/tests/expected/semantic-checkpoint/session.expected.jsonl +++ b/apps/cli/tests/profiles/headless/tests/expected/semantic-checkpoint/session.expected.jsonl @@ -18,7 +18,7 @@ {"type":"step/start","data":{"turn":2,"step":1}} {"type":"system/message","data":{"turn":2,"step":1,"message":{"role":"system","content":[{"type":"text","text":"{{system}}"}],"source":{"kind":"system-prompt"},"id":"{{sessionId}}"}},"sourceEventSeqs":[2],"surfaceOp":{"op":"replace","startSeq":2,"endSeq":2}} {"type":"user/message","data":{"content":[{"type":"text","text":"Continue safely from the interrupted operation."}],"source":{"kind":"user"},"role":"user","id":"{{sessionId}}"},"surfaceOp":"append"} -{"type":"user/message","data":{"content":[{"type":"text","text":"Current runtime context. This snapshot supersedes earlier runtime-context snapshots.\n\nCurrent working directory: \"{{cwd}}\".\n\nCurrent DSH file policy: workspace-write. Any available operation enforced by the DSH file sandbox may modify files under the session workspace: \"{{cwd}}\". Some platform temporary areas may also be writable.\n\nApproval prompts are enabled in this session: operations that require approval may ask through the configured answerers; without an available answerer, the request fails closed.\n\nYou are the root agent. Your agent id is \"{{sessionId}}\".\n\nTo message other agents, use send_message({ agent_id: \"\", message: \"...\" }).\nUse list_agents({}) to find your collaborator agents and their ids."}],"source":{"kind":"runtime-context","form":"snapshot","sections":[{"name":"working-directory:current","text":"Current working directory: \"{{cwd}}\"."},{"name":"sandbox:policy","text":"Current DSH file policy: workspace-write. Any available operation enforced by the DSH file sandbox may modify files under the session workspace: \"{{cwd}}\". Some platform temporary areas may also be writable."},{"name":"approval:policy","text":"Approval prompts are enabled in this session: operations that require approval may ask through the configured answerers; without an available answerer, the request fails closed."},{"name":"subagent:identity","text":"You are the root agent. Your agent id is \"{{sessionId}}\".\n\nTo message other agents, use send_message({ agent_id: \"\", message: \"...\" }).\nUse list_agents({}) to find your collaborator agents and their ids."}]},"role":"user","id":"{{sessionId}}"},"surfaceOp":"append"} +{"type":"user/message","data":{"content":[{"type":"text","text":"Current runtime context. This snapshot supersedes earlier runtime-context snapshots.\n\nCurrent working directory: \"{{cwd}}\".\n\nCurrent DSH file policy: workspace-write. Any available operation enforced by the DSH file sandbox may modify files under the session workspace: \"{{cwd}}\". Some platform temporary areas may also be writable.\n\nApproval prompts are enabled in this session: operations that require approval may ask through the configured answerers; without an available answerer, the request fails closed.\n\nYou are the root agent. Your name is \"lead\".\n\nTo message other agents, use send_message({ agent: \"\", message: \"...\" }).\nUse list_agents({}) to find your collaborator agents and their names."}],"source":{"kind":"runtime-context","form":"snapshot","sections":[{"name":"working-directory:current","text":"Current working directory: \"{{cwd}}\"."},{"name":"sandbox:policy","text":"Current DSH file policy: workspace-write. Any available operation enforced by the DSH file sandbox may modify files under the session workspace: \"{{cwd}}\". Some platform temporary areas may also be writable."},{"name":"approval:policy","text":"Approval prompts are enabled in this session: operations that require approval may ask through the configured answerers; without an available answerer, the request fails closed."},{"name":"subagent:identity","text":"You are the root agent. Your name is \"lead\".\n\nTo message other agents, use send_message({ agent: \"\", message: \"...\" }).\nUse list_agents({}) to find your collaborator agents and their names."}]},"role":"user","id":"{{sessionId}}"},"surfaceOp":"append"} {"type":"request/header","data":{"header":{"config":{"provider":"deepseek-official","model":"deepseek-v4-flash"},"tools":"{{tools}}"},"reason":"initial","startsSeries":true}} {"type":"request/context","data":{"provider":"deepseek-official","model":"deepseek-v4-flash"}} {"type":"session/title","data":{"title":"Perform one side-effecting remote mutati","messageSeqs":[3],"source":{"kind":"fallback"}}} diff --git a/apps/cli/tests/profiles/headless/tests/expected/subagent-diagnostic/parent.expected.jsonl b/apps/cli/tests/profiles/headless/tests/expected/subagent-diagnostic/parent.expected.jsonl index 57f93111e7..db32c5f5bc 100644 --- a/apps/cli/tests/profiles/headless/tests/expected/subagent-diagnostic/parent.expected.jsonl +++ b/apps/cli/tests/profiles/headless/tests/expected/subagent-diagnostic/parent.expected.jsonl @@ -16,13 +16,13 @@ {"type":"step/start","data":{"turn":2,"step":1}} {"type":"system/message","data":{"turn":2,"step":1,"message":{"role":"system","content":[{"type":"text","text":"{{system}}"}],"source":{"kind":"system-prompt"},"id":"{{sessionId}}"}},"sourceEventSeqs":[2],"surfaceOp":{"op":"replace","startSeq":2,"endSeq":2}} {"type":"user/message","data":{"content":[{"type":"text","text":"Call list_agents once and report what it shows."}],"source":{"kind":"user"},"role":"user","id":"{{sessionId}}"},"surfaceOp":"append"} -{"type":"user/message","data":{"content":[{"type":"text","text":"Current runtime context. This snapshot supersedes earlier runtime-context snapshots.\n\nCurrent working directory: \"{{cwd}}\".\n\nCurrent DSH file policy: workspace-write. Any available operation enforced by the DSH file sandbox may modify files under the session workspace: \"{{cwd}}\". Some platform temporary areas may also be writable.\n\nApproval prompts are enabled in this session: operations that require approval may ask through the configured answerers; without an available answerer, the request fails closed.\n\nYou are the root agent. Your agent id is \"{{sessionId}}\".\n\nTo message other agents, use send_message({ agent_id: \"\", message: \"...\" }).\nUse list_agents({}) to find your collaborator agents and their ids."}],"source":{"kind":"runtime-context","form":"snapshot","sections":[{"name":"working-directory:current","text":"Current working directory: \"{{cwd}}\"."},{"name":"sandbox:policy","text":"Current DSH file policy: workspace-write. Any available operation enforced by the DSH file sandbox may modify files under the session workspace: \"{{cwd}}\". Some platform temporary areas may also be writable."},{"name":"approval:policy","text":"Approval prompts are enabled in this session: operations that require approval may ask through the configured answerers; without an available answerer, the request fails closed."},{"name":"subagent:identity","text":"You are the root agent. Your agent id is \"{{sessionId}}\".\n\nTo message other agents, use send_message({ agent_id: \"\", message: \"...\" }).\nUse list_agents({}) to find your collaborator agents and their ids."}]},"role":"user","id":"{{sessionId}}"},"surfaceOp":"append"} +{"type":"user/message","data":{"content":[{"type":"text","text":"Current runtime context. This snapshot supersedes earlier runtime-context snapshots.\n\nCurrent working directory: \"{{cwd}}\".\n\nCurrent DSH file policy: workspace-write. Any available operation enforced by the DSH file sandbox may modify files under the session workspace: \"{{cwd}}\". Some platform temporary areas may also be writable.\n\nApproval prompts are enabled in this session: operations that require approval may ask through the configured answerers; without an available answerer, the request fails closed.\n\nYou are the root agent. Your name is \"lead\".\n\nTo message other agents, use send_message({ agent: \"\", message: \"...\" }).\nUse list_agents({}) to find your collaborator agents and their names."}],"source":{"kind":"runtime-context","form":"snapshot","sections":[{"name":"working-directory:current","text":"Current working directory: \"{{cwd}}\"."},{"name":"sandbox:policy","text":"Current DSH file policy: workspace-write. Any available operation enforced by the DSH file sandbox may modify files under the session workspace: \"{{cwd}}\". Some platform temporary areas may also be writable."},{"name":"approval:policy","text":"Approval prompts are enabled in this session: operations that require approval may ask through the configured answerers; without an available answerer, the request fails closed."},{"name":"subagent:identity","text":"You are the root agent. Your name is \"lead\".\n\nTo message other agents, use send_message({ agent: \"\", message: \"...\" }).\nUse list_agents({}) to find your collaborator agents and their names."}]},"role":"user","id":"{{sessionId}}"},"surfaceOp":"append"} {"type":"request/header","data":{"header":{"config":{"provider":"deepseek-official","model":"deepseek-v4-flash"},"tools":"{{tools}}"},"reason":"initial","startsSeries":true}} {"type":"request/context","data":{"provider":"deepseek-official","model":"deepseek-v4-flash"}} {"type":"session/title","data":{"title":"Start a background job.","messageSeqs":[3],"source":{"kind":"fallback"}}} {"type":"assistant/message","data":{"turn":2,"step":1,"message":{"role":"assistant","content":[{"type":"tool-call","id":"list-once","name":"list_agents","arguments":"{}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{sessionId}}"},"usage":{"inputTokens":10,"outputTokens":5},"stream":[{"type":"chunk","time":0,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}},{"type":"tool-call-chunks","time0":0,"index":0,"dt":[],"id":"list-once","name":"list_agents","args":["{}"]},{"type":"chunk","time":0,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"list-once","name":"list_agents","arguments":"{}"}}},{"type":"chunk","time":0,"chunk":{"type":"usage","usage":{"inputTokens":10,"outputTokens":5}}},{"type":"chunk","time":0,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}]},"surfaceOp":"append"} {"type":"tool/call","data":{"turn":2,"step":1,"callId":"list-once","name":"list_agents","arguments":"{}"}} -{"type":"tool/result","data":{"turn":2,"step":1,"message":{"role":"tool","source":{"kind":"tool","callId":"list-once"},"toolCallId":"list-once","content":[{"type":"text","text":"{{sessionId}} [running] — root agent\n{{sessionId}} [inactive] parent={{sessionId}} depth=1 — descriptorless child"}],"isError":false,"id":"{{sessionId}}"}},"sourceEventSeqs":[22],"surfaceOp":"append"} +{"type":"tool/result","data":{"turn":2,"step":1,"message":{"role":"tool","source":{"kind":"tool","callId":"list-once"},"toolCallId":"list-once","content":[{"type":"text","text":"lead [running] — root agent\n{{sessionId}} [inactive] — descriptorless child"}],"isError":false,"id":"{{sessionId}}"}},"sourceEventSeqs":[22],"surfaceOp":"append"} {"type":"step/end","data":{"turn":2,"step":1}} {"type":"step/start","data":{"turn":2,"step":2}} {"type":"assistant/message","data":{"turn":2,"step":2,"message":{"role":"assistant","content":[{"type":"text","text":"The catalogued subagent is ready. PARENT_DONE"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{sessionId}}"},"usage":{"inputTokens":10,"outputTokens":5},"stream":[{"type":"chunk","time":0,"chunk":{"type":"block-start","index":0,"blockType":"text"}},{"type":"text-chunks","time0":0,"index":0,"dt":[],"texts":["The catalogued subagent is ready. PARENT_DONE"]},{"type":"chunk","time":0,"chunk":{"type":"block-end","index":0,"block":{"type":"text","text":"The catalogued subagent is ready. PARENT_DONE"}}},{"type":"chunk","time":0,"chunk":{"type":"usage","usage":{"inputTokens":10,"outputTokens":5}}},{"type":"chunk","time":0,"chunk":{"type":"finish","reason":{"kind":"stop"}}}]},"surfaceOp":"append"} diff --git a/apps/cli/tests/profiles/headless/tests/expected/subagent-inheritance/child.expected.jsonl b/apps/cli/tests/profiles/headless/tests/expected/subagent-inheritance/child.expected.jsonl index 27712bcd00..d71a2334f8 100644 --- a/apps/cli/tests/profiles/headless/tests/expected/subagent-inheritance/child.expected.jsonl +++ b/apps/cli/tests/profiles/headless/tests/expected/subagent-inheritance/child.expected.jsonl @@ -8,7 +8,7 @@ {"type":"step/start","data":{"turn":1,"step":1}} {"type":"system/message","data":{"turn":1,"step":1,"message":{"role":"system","content":[{"type":"text","text":"{{system}}"}],"source":{"kind":"system-prompt"},"id":"{{sessionId}}"}},"surfaceOp":"append"} {"type":"user/message","data":{"content":[{"type":"text","text":"Use the write tool exactly once with file_path set to exactly the relative path inherited.txt and content escaped. If the write is denied, reply with the single word CHILD_DENIED and the denial marker line; do not retry and do not request escalation. If it succeeds, reply CHILD_WROTE."},{"type":"text","text":"Your final answer is delivered automatically if your parent is still online. Include the result and relevant evidence in that answer; the parent does not receive your full transcript, tool output, or reasoning. If your last action is a message to your parent, the completion notice omits your final answer; include the result and relevant evidence in that message."}],"source":{"kind":"user"},"role":"user","id":"{{sessionId}}"},"surfaceOp":"append"} -{"type":"user/message","data":{"content":[{"type":"text","text":"Current runtime context. This snapshot supersedes earlier runtime-context snapshots.\n\nCurrent working directory: \"{{cwd}}\".\n\nCurrent DSH file policy: read-only. Any available operation enforced by the DSH file sandbox cannot modify files in the standing mode. Do not refuse a required modification from this policy alone: try an available tool normally and follow any denial and escalation guidance it returns.\n\nApproval prompts are disabled in this session: actions that require approval are rejected automatically — do not request sandbox escalation (do not set `sandbox_permissions`).\n\nYou are a subagent delegated by agent \"{{sessionId}}\".\nYour agent id is \"{{sessionId}}\".\nThe root agent of your collaboration tree is \"{{sessionId}}\".\n\nTo message other agents, use send_message({ agent_id: \"\", message: \"...\" }).\nUse list_agents({}) to find your collaborator agents and their ids.\n\nDelegation depth for `subagent`: current 1, maximum 1, remaining levels 0. Do not call `subagent` at this depth; carry out the work directly.\n\nDelegation depth for `subagent_fork`: current 1, maximum 1, remaining levels 0. Do not call `subagent_fork` at this depth; carry out the work directly.\n\nYou are a delegated subagent: your permission scope was fixed when you were started and cannot be widened from inside this session — operations that require approval are rejected automatically. When the task needs access beyond that scope, do not retry the denied operation; state the limitation in your reply so the delegating agent can handle it."}],"source":{"kind":"runtime-context","form":"snapshot","sections":[{"name":"working-directory:current","text":"Current working directory: \"{{cwd}}\"."},{"name":"sandbox:policy","text":"Current DSH file policy: read-only. Any available operation enforced by the DSH file sandbox cannot modify files in the standing mode. Do not refuse a required modification from this policy alone: try an available tool normally and follow any denial and escalation guidance it returns."},{"name":"approval:policy","text":"Approval prompts are disabled in this session: actions that require approval are rejected automatically — do not request sandbox escalation (do not set `sandbox_permissions`)."},{"name":"subagent:identity","text":"You are a subagent delegated by agent \"{{sessionId}}\".\nYour agent id is \"{{sessionId}}\".\nThe root agent of your collaboration tree is \"{{sessionId}}\".\n\nTo message other agents, use send_message({ agent_id: \"\", message: \"...\" }).\nUse list_agents({}) to find your collaborator agents and their ids."},{"name":"tool:subagent:depth","text":"Delegation depth for `subagent`: current 1, maximum 1, remaining levels 0. Do not call `subagent` at this depth; carry out the work directly."},{"name":"tool:subagent_fork:depth","text":"Delegation depth for `subagent_fork`: current 1, maximum 1, remaining levels 0. Do not call `subagent_fork` at this depth; carry out the work directly."},{"name":"subagent:delegation","text":"You are a delegated subagent: your permission scope was fixed when you were started and cannot be widened from inside this session — operations that require approval are rejected automatically. When the task needs access beyond that scope, do not retry the denied operation; state the limitation in your reply so the delegating agent can handle it."}]},"role":"user","id":"{{sessionId}}"},"surfaceOp":"append"} +{"type":"user/message","data":{"content":[{"type":"text","text":"Current runtime context. This snapshot supersedes earlier runtime-context snapshots.\n\nCurrent working directory: \"{{cwd}}\".\n\nCurrent DSH file policy: read-only. Any available operation enforced by the DSH file sandbox cannot modify files in the standing mode. Do not refuse a required modification from this policy alone: try an available tool normally and follow any denial and escalation guidance it returns.\n\nApproval prompts are disabled in this session: actions that require approval are rejected automatically — do not request sandbox escalation (do not set `sandbox_permissions`).\n\nYou are a subagent delegated by agent \"lead\".\nYour name is \"agent-1\".\nThe root agent of your collaboration tree is \"lead\".\n\nTo message other agents, use send_message({ agent: \"\", message: \"...\" }).\nUse list_agents({}) to find your collaborator agents and their names.\n\nDelegation depth for `subagent`: current 1, maximum 1, remaining levels 0. Do not call `subagent` at this depth; carry out the work directly.\n\nDelegation depth for `subagent_fork`: current 1, maximum 1, remaining levels 0. Do not call `subagent_fork` at this depth; carry out the work directly.\n\nYou are a delegated subagent: your permission scope was fixed when you were started and cannot be widened from inside this session — operations that require approval are rejected automatically. When the task needs access beyond that scope, do not retry the denied operation; state the limitation in your reply so the delegating agent can handle it."}],"source":{"kind":"runtime-context","form":"snapshot","sections":[{"name":"working-directory:current","text":"Current working directory: \"{{cwd}}\"."},{"name":"sandbox:policy","text":"Current DSH file policy: read-only. Any available operation enforced by the DSH file sandbox cannot modify files in the standing mode. Do not refuse a required modification from this policy alone: try an available tool normally and follow any denial and escalation guidance it returns."},{"name":"approval:policy","text":"Approval prompts are disabled in this session: actions that require approval are rejected automatically — do not request sandbox escalation (do not set `sandbox_permissions`)."},{"name":"subagent:identity","text":"You are a subagent delegated by agent \"lead\".\nYour name is \"agent-1\".\nThe root agent of your collaboration tree is \"lead\".\n\nTo message other agents, use send_message({ agent: \"\", message: \"...\" }).\nUse list_agents({}) to find your collaborator agents and their names."},{"name":"tool:subagent:depth","text":"Delegation depth for `subagent`: current 1, maximum 1, remaining levels 0. Do not call `subagent` at this depth; carry out the work directly."},{"name":"tool:subagent_fork:depth","text":"Delegation depth for `subagent_fork`: current 1, maximum 1, remaining levels 0. Do not call `subagent_fork` at this depth; carry out the work directly."},{"name":"subagent:delegation","text":"You are a delegated subagent: your permission scope was fixed when you were started and cannot be widened from inside this session — operations that require approval are rejected automatically. When the task needs access beyond that scope, do not retry the denied operation; state the limitation in your reply so the delegating agent can handle it."}]},"role":"user","id":"{{sessionId}}"},"surfaceOp":"append"} {"type":"request/header","data":{"header":{"config":{"provider":"deepseek-official","model":"deepseek-v4-flash","reasoningEffort":"low"},"tools":"{{tools}}"},"reason":"initial"}} {"type":"request/context","data":{"provider":"deepseek-official","model":"deepseek-v4-flash"}} {"type":"session/title","data":{"title":"Use the write tool exactly","messageSeqs":[8],"source":{"kind":"fallback"}}} diff --git a/apps/cli/tests/profiles/headless/tests/expected/subagent-inheritance/parent.expected.jsonl b/apps/cli/tests/profiles/headless/tests/expected/subagent-inheritance/parent.expected.jsonl index f8796478f5..bace11ea02 100644 --- a/apps/cli/tests/profiles/headless/tests/expected/subagent-inheritance/parent.expected.jsonl +++ b/apps/cli/tests/profiles/headless/tests/expected/subagent-inheritance/parent.expected.jsonl @@ -16,20 +16,20 @@ {"type":"step/start","data":{"turn":2,"step":1}} {"type":"system/message","data":{"turn":2,"step":1,"message":{"role":"system","content":[{"type":"text","text":"{{system}}"}],"source":{"kind":"system-prompt"},"id":"{{sessionId}}"}},"sourceEventSeqs":[2],"surfaceOp":{"op":"replace","startSeq":2,"endSeq":2}} {"type":"user/message","data":{"content":[{"type":"text","text":"Delegate the write probe to a subagent."}],"source":{"kind":"user"},"role":"user","id":"{{sessionId}}"},"surfaceOp":"append"} -{"type":"user/message","data":{"content":[{"type":"text","text":"Current runtime context. This snapshot supersedes earlier runtime-context snapshots.\n\nCurrent working directory: \"{{cwd}}\".\n\nCurrent DSH file policy: read-only. Any available operation enforced by the DSH file sandbox cannot modify files in the standing mode. Do not refuse a required modification from this policy alone: try an available tool normally and follow any denial and escalation guidance it returns.\n\nApproval prompts are enabled in this session: operations that require approval may ask through the configured answerers; without an available answerer, the request fails closed.\n\nYou are the root agent. Your agent id is \"{{sessionId}}\".\n\nTo message other agents, use send_message({ agent_id: \"\", message: \"...\" }).\nUse list_agents({}) to find your collaborator agents and their ids."}],"source":{"kind":"runtime-context","form":"snapshot","sections":[{"name":"working-directory:current","text":"Current working directory: \"{{cwd}}\"."},{"name":"sandbox:policy","text":"Current DSH file policy: read-only. Any available operation enforced by the DSH file sandbox cannot modify files in the standing mode. Do not refuse a required modification from this policy alone: try an available tool normally and follow any denial and escalation guidance it returns."},{"name":"approval:policy","text":"Approval prompts are enabled in this session: operations that require approval may ask through the configured answerers; without an available answerer, the request fails closed."},{"name":"subagent:identity","text":"You are the root agent. Your agent id is \"{{sessionId}}\".\n\nTo message other agents, use send_message({ agent_id: \"\", message: \"...\" }).\nUse list_agents({}) to find your collaborator agents and their ids."}]},"role":"user","id":"{{sessionId}}"},"surfaceOp":"append"} +{"type":"user/message","data":{"content":[{"type":"text","text":"Current runtime context. This snapshot supersedes earlier runtime-context snapshots.\n\nCurrent working directory: \"{{cwd}}\".\n\nCurrent DSH file policy: read-only. Any available operation enforced by the DSH file sandbox cannot modify files in the standing mode. Do not refuse a required modification from this policy alone: try an available tool normally and follow any denial and escalation guidance it returns.\n\nApproval prompts are enabled in this session: operations that require approval may ask through the configured answerers; without an available answerer, the request fails closed.\n\nYou are the root agent. Your name is \"lead\".\n\nTo message other agents, use send_message({ agent: \"\", message: \"...\" }).\nUse list_agents({}) to find your collaborator agents and their names."}],"source":{"kind":"runtime-context","form":"snapshot","sections":[{"name":"working-directory:current","text":"Current working directory: \"{{cwd}}\"."},{"name":"sandbox:policy","text":"Current DSH file policy: read-only. Any available operation enforced by the DSH file sandbox cannot modify files in the standing mode. Do not refuse a required modification from this policy alone: try an available tool normally and follow any denial and escalation guidance it returns."},{"name":"approval:policy","text":"Approval prompts are enabled in this session: operations that require approval may ask through the configured answerers; without an available answerer, the request fails closed."},{"name":"subagent:identity","text":"You are the root agent. Your name is \"lead\".\n\nTo message other agents, use send_message({ agent: \"\", message: \"...\" }).\nUse list_agents({}) to find your collaborator agents and their names."}]},"role":"user","id":"{{sessionId}}"},"surfaceOp":"append"} {"type":"request/header","data":{"header":{"config":{"provider":"deepseek-official","model":"deepseek-v4-flash","reasoningEffort":"low"},"tools":["apply_patch","bash","create_goal","edit","get_goal","glob","grep","interrupt_agent","job_kill","job_list","job_output","list_agents","read","read_image","send_message","skill","subagent","subagent_fork","todo_write","update_goal","wait_agent","web_fetch","web_search","workflow","working_directory","write"]},"reason":"resume","startsSeries":true}} {"type":"developer/message","data":{"turn":2,"step":1,"message":{"source":{"kind":"tool-registry"},"content":[{"type":"tool-addition","toolName":"apply_patch"},{"type":"tool-addition","toolName":"bash"},{"type":"tool-addition","toolName":"create_goal"},{"type":"tool-addition","toolName":"edit"},{"type":"tool-addition","toolName":"get_goal"},{"type":"tool-addition","toolName":"glob"},{"type":"tool-addition","toolName":"grep"},{"type":"tool-addition","toolName":"interrupt_agent"},{"type":"tool-addition","toolName":"job_kill"},{"type":"tool-addition","toolName":"job_list"},{"type":"tool-addition","toolName":"job_output"},{"type":"tool-addition","toolName":"list_agents"},{"type":"tool-addition","toolName":"read"},{"type":"tool-addition","toolName":"read_image"},{"type":"tool-addition","toolName":"send_message"},{"type":"tool-addition","toolName":"skill"},{"type":"tool-addition","toolName":"subagent"},{"type":"tool-addition","toolName":"subagent_fork"},{"type":"tool-addition","toolName":"todo_write"},{"type":"tool-addition","toolName":"update_goal"},{"type":"tool-addition","toolName":"wait_agent"},{"type":"tool-addition","toolName":"web_fetch"},{"type":"tool-addition","toolName":"web_search"},{"type":"tool-addition","toolName":"workflow"},{"type":"tool-addition","toolName":"working_directory"},{"type":"tool-addition","toolName":"write"}],"role":"developer","id":"{{sessionId}}"},"headerSeq":18},"surfaceOp":"append"} {"type":"request/context","data":{"provider":"deepseek-official","model":"deepseek-v4-flash"}} {"type":"session/title","data":{"title":"Tighten this session to read-only.","messageSeqs":[3],"source":{"kind":"fallback"}}} {"type":"assistant/message","data":{"turn":2,"step":1,"message":{"role":"assistant","content":[{"type":"tool-call","id":"delegate-write","name":"subagent","arguments":"{\"description\": \"Delegated write probe\", \"prompt\": \"Use the write tool exactly once with file_path set to exactly the relative path inherited.txt and content escaped. If the write is denied, reply with the single word CHILD_DENIED and the denial marker line; do not retry and do not request escalation. If it succeeds, reply CHILD_WROTE.\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{sessionId}}"},"usage":{"inputTokens":10,"outputTokens":5},"stream":[{"type":"chunk","time":0,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}},{"type":"tool-call-chunks","time0":0,"index":0,"dt":[],"id":"delegate-write","name":"subagent","args":["{\"description\": \"Delegated write probe\", \"prompt\": \"Use the write tool exactly once with file_path set to exactly the relative path inherited.txt and content escaped. If the write is denied, reply with the single word CHILD_DENIED and the denial marker line; do not retry and do not request escalation. If it succeeds, reply CHILD_WROTE.\"}"]},{"type":"chunk","time":0,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"delegate-write","name":"subagent","arguments":"{\"description\": \"Delegated write probe\", \"prompt\": \"Use the write tool exactly once with file_path set to exactly the relative path inherited.txt and content escaped. If the write is denied, reply with the single word CHILD_DENIED and the denial marker line; do not retry and do not request escalation. If it succeeds, reply CHILD_WROTE.\"}"}}},{"type":"chunk","time":0,"chunk":{"type":"usage","usage":{"inputTokens":10,"outputTokens":5}}},{"type":"chunk","time":0,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}]},"surfaceOp":"append"} {"type":"tool/call","data":{"turn":2,"step":1,"callId":"delegate-write","name":"subagent","arguments":"{\"description\": \"Delegated write probe\", \"prompt\": \"Use the write tool exactly once with file_path set to exactly the relative path inherited.txt and content escaped. If the write is denied, reply with the single word CHILD_DENIED and the denial marker line; do not retry and do not request escalation. If it succeeds, reply CHILD_WROTE.\"}"}} -{"type":"subagent/catalog","data":{"version":0,"childId":"{{sessionId}}","childCreatedAt":0,"mode":"continuable","label":"Delegated write probe"}} -{"type":"agent/inbox/spliced","data":{"target":"next-step","start":0,"inserted":[{"content":[{"type":"text","text":"Background subagent {{sessionId}} finished and will do no further work unless you send it more."},{"type":"text","text":"Its closing message:"},{"type":"text","text":"CHILD_DENIED [sandbox: file access denied under read-only mode]"}],"source":{"kind":"subagent-settled","form":"notice","summary":"Background subagent {{sessionId}} finished and will do no further work unless you send it more.","stopReason":"completed","senderSessionId":"{{sessionId}}"},"role":"user","id":"{{sessionId}}"}]}} -{"type":"tool/result","data":{"turn":2,"step":1,"message":{"role":"tool","source":{"kind":"tool","callId":"delegate-write"},"toolCallId":"delegate-write","content":[{"type":"text","text":"started subagent {{sessionId}}"}],"isError":false,"id":"{{sessionId}}"},"meta":{"kind":"activation","subagentId":"{{sessionId}}"}},"sourceEventSeqs":[23],"surfaceOp":"append"} +{"type":"subagent/catalog","data":{"version":3,"childId":"{{sessionId}}","childCreatedAt":0,"mode":"continuable","label":"Delegated write probe","name":"agent-1"}} +{"type":"agent/inbox/spliced","data":{"target":"next-step","start":0,"inserted":[{"content":[{"type":"text","text":"Background subagent agent-1 finished and will do no further work unless you send it more."},{"type":"text","text":"Its closing message:"},{"type":"text","text":"CHILD_DENIED [sandbox: file access denied under read-only mode]"}],"source":{"kind":"subagent-settled","form":"notice","summary":"Background subagent agent-1 finished and will do no further work unless you send it more.","stopReason":"completed","senderSessionId":"{{sessionId}}"},"role":"user","id":"{{sessionId}}"}]}} +{"type":"tool/result","data":{"turn":2,"step":1,"message":{"role":"tool","source":{"kind":"tool","callId":"delegate-write"},"toolCallId":"delegate-write","content":[{"type":"text","text":"started subagent agent-1"}],"isError":false,"id":"{{sessionId}}"},"meta":{"kind":"activation","name":"agent-1"}},"sourceEventSeqs":[23],"surfaceOp":"append"} {"type":"step/end","data":{"turn":2,"step":1}} {"type":"agent/inbox/spliced","data":{"target":"next-step","start":0,"removedCount":1,"inserted":[]}} {"type":"step/start","data":{"turn":2,"step":2}} -{"type":"user/message","data":{"content":[{"type":"text","text":"Background subagent {{sessionId}} finished and will do no further work unless you send it more."},{"type":"text","text":"Its closing message:"},{"type":"text","text":"CHILD_DENIED [sandbox: file access denied under read-only mode]"}],"source":{"kind":"subagent-settled","form":"notice","summary":"Background subagent {{sessionId}} finished and will do no further work unless you send it more.","stopReason":"completed","senderSessionId":"{{sessionId}}"},"role":"user","id":"{{sessionId}}"},"surfaceOp":"append"} +{"type":"user/message","data":{"content":[{"type":"text","text":"Background subagent agent-1 finished and will do no further work unless you send it more."},{"type":"text","text":"Its closing message:"},{"type":"text","text":"CHILD_DENIED [sandbox: file access denied under read-only mode]"}],"source":{"kind":"subagent-settled","form":"notice","summary":"Background subagent agent-1 finished and will do no further work unless you send it more.","stopReason":"completed","senderSessionId":"{{sessionId}}"},"role":"user","id":"{{sessionId}}"},"surfaceOp":"append"} {"type":"assistant/message","data":{"turn":2,"step":2,"message":{"role":"assistant","content":[{"type":"text","text":"The delegated child was denied by the sandbox. PARENT_DONE"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{sessionId}}"},"usage":{"inputTokens":10,"outputTokens":5},"stream":[{"type":"chunk","time":0,"chunk":{"type":"block-start","index":0,"blockType":"text"}},{"type":"text-chunks","time0":0,"index":0,"dt":[],"texts":["The delegated child was denied by the sandbox. PARENT_DONE"]},{"type":"chunk","time":0,"chunk":{"type":"block-end","index":0,"block":{"type":"text","text":"The delegated child was denied by the sandbox. PARENT_DONE"}}},{"type":"chunk","time":0,"chunk":{"type":"usage","usage":{"inputTokens":10,"outputTokens":5}}},{"type":"chunk","time":0,"chunk":{"type":"finish","reason":{"kind":"stop"}}}]},"surfaceOp":"append"} {"type":"step/end","data":{"turn":2,"step":2}} {"type":"turn/end","data":{"turn":2,"reason":{"kind":"completed"}}} diff --git a/apps/cli/tests/profiles/headless/tests/expected/subagent-settlement/child.expected.jsonl b/apps/cli/tests/profiles/headless/tests/expected/subagent-settlement/child.expected.jsonl index 2305a8a7c2..b968ceddde 100644 --- a/apps/cli/tests/profiles/headless/tests/expected/subagent-settlement/child.expected.jsonl +++ b/apps/cli/tests/profiles/headless/tests/expected/subagent-settlement/child.expected.jsonl @@ -8,7 +8,7 @@ {"type":"step/start","data":{"turn":1,"step":1}} {"type":"system/message","data":{"turn":1,"step":1,"message":{"role":"system","content":[{"type":"text","text":"{{system}}"}],"source":{"kind":"system-prompt"},"id":"{{sessionId}}"}},"surfaceOp":"append"} {"type":"user/message","data":{"content":[{"type":"text","text":"Reply with exactly CHILD_RESULT and nothing else. Do not call send_message."},{"type":"text","text":"Your final answer is delivered automatically if your parent is still online. Include the result and relevant evidence in that answer; the parent does not receive your full transcript, tool output, or reasoning. If your last action is a message to your parent, the completion notice omits your final answer; include the result and relevant evidence in that message."}],"source":{"kind":"user"},"role":"user","id":"{{sessionId}}"},"surfaceOp":"append"} -{"type":"user/message","data":{"content":[{"type":"text","text":"Current runtime context. This snapshot supersedes earlier runtime-context snapshots.\n\nCurrent working directory: \"{{cwd}}\".\n\nCurrent DSH file policy: workspace-write. Any available operation enforced by the DSH file sandbox may modify files under the session workspace: \"{{cwd}}\". Some platform temporary areas may also be writable.\n\nApproval prompts are disabled in this session: actions that require approval are rejected automatically — do not request sandbox escalation (do not set `sandbox_permissions`).\n\nYou are a subagent delegated by agent \"{{sessionId}}\".\nYour agent id is \"{{sessionId}}\".\nThe root agent of your collaboration tree is \"{{sessionId}}\".\n\nTo message other agents, use send_message({ agent_id: \"\", message: \"...\" }).\nUse list_agents({}) to find your collaborator agents and their ids.\n\nDelegation depth for `subagent`: current 1, maximum 1, remaining levels 0. Do not call `subagent` at this depth; carry out the work directly.\n\nDelegation depth for `subagent_fork`: current 1, maximum 1, remaining levels 0. Do not call `subagent_fork` at this depth; carry out the work directly.\n\nYou are a delegated subagent: your permission scope was fixed when you were started and cannot be widened from inside this session — operations that require approval are rejected automatically. When the task needs access beyond that scope, do not retry the denied operation; state the limitation in your reply so the delegating agent can handle it."}],"source":{"kind":"runtime-context","form":"snapshot","sections":[{"name":"working-directory:current","text":"Current working directory: \"{{cwd}}\"."},{"name":"sandbox:policy","text":"Current DSH file policy: workspace-write. Any available operation enforced by the DSH file sandbox may modify files under the session workspace: \"{{cwd}}\". Some platform temporary areas may also be writable."},{"name":"approval:policy","text":"Approval prompts are disabled in this session: actions that require approval are rejected automatically — do not request sandbox escalation (do not set `sandbox_permissions`)."},{"name":"subagent:identity","text":"You are a subagent delegated by agent \"{{sessionId}}\".\nYour agent id is \"{{sessionId}}\".\nThe root agent of your collaboration tree is \"{{sessionId}}\".\n\nTo message other agents, use send_message({ agent_id: \"\", message: \"...\" }).\nUse list_agents({}) to find your collaborator agents and their ids."},{"name":"tool:subagent:depth","text":"Delegation depth for `subagent`: current 1, maximum 1, remaining levels 0. Do not call `subagent` at this depth; carry out the work directly."},{"name":"tool:subagent_fork:depth","text":"Delegation depth for `subagent_fork`: current 1, maximum 1, remaining levels 0. Do not call `subagent_fork` at this depth; carry out the work directly."},{"name":"subagent:delegation","text":"You are a delegated subagent: your permission scope was fixed when you were started and cannot be widened from inside this session — operations that require approval are rejected automatically. When the task needs access beyond that scope, do not retry the denied operation; state the limitation in your reply so the delegating agent can handle it."}]},"role":"user","id":"{{sessionId}}"},"surfaceOp":"append"} +{"type":"user/message","data":{"content":[{"type":"text","text":"Current runtime context. This snapshot supersedes earlier runtime-context snapshots.\n\nCurrent working directory: \"{{cwd}}\".\n\nCurrent DSH file policy: workspace-write. Any available operation enforced by the DSH file sandbox may modify files under the session workspace: \"{{cwd}}\". Some platform temporary areas may also be writable.\n\nApproval prompts are disabled in this session: actions that require approval are rejected automatically — do not request sandbox escalation (do not set `sandbox_permissions`).\n\nYou are a subagent delegated by agent \"lead\".\nYour name is \"agent-1\".\nThe root agent of your collaboration tree is \"lead\".\n\nTo message other agents, use send_message({ agent: \"\", message: \"...\" }).\nUse list_agents({}) to find your collaborator agents and their names.\n\nDelegation depth for `subagent`: current 1, maximum 1, remaining levels 0. Do not call `subagent` at this depth; carry out the work directly.\n\nDelegation depth for `subagent_fork`: current 1, maximum 1, remaining levels 0. Do not call `subagent_fork` at this depth; carry out the work directly.\n\nYou are a delegated subagent: your permission scope was fixed when you were started and cannot be widened from inside this session — operations that require approval are rejected automatically. When the task needs access beyond that scope, do not retry the denied operation; state the limitation in your reply so the delegating agent can handle it."}],"source":{"kind":"runtime-context","form":"snapshot","sections":[{"name":"working-directory:current","text":"Current working directory: \"{{cwd}}\"."},{"name":"sandbox:policy","text":"Current DSH file policy: workspace-write. Any available operation enforced by the DSH file sandbox may modify files under the session workspace: \"{{cwd}}\". Some platform temporary areas may also be writable."},{"name":"approval:policy","text":"Approval prompts are disabled in this session: actions that require approval are rejected automatically — do not request sandbox escalation (do not set `sandbox_permissions`)."},{"name":"subagent:identity","text":"You are a subagent delegated by agent \"lead\".\nYour name is \"agent-1\".\nThe root agent of your collaboration tree is \"lead\".\n\nTo message other agents, use send_message({ agent: \"\", message: \"...\" }).\nUse list_agents({}) to find your collaborator agents and their names."},{"name":"tool:subagent:depth","text":"Delegation depth for `subagent`: current 1, maximum 1, remaining levels 0. Do not call `subagent` at this depth; carry out the work directly."},{"name":"tool:subagent_fork:depth","text":"Delegation depth for `subagent_fork`: current 1, maximum 1, remaining levels 0. Do not call `subagent_fork` at this depth; carry out the work directly."},{"name":"subagent:delegation","text":"You are a delegated subagent: your permission scope was fixed when you were started and cannot be widened from inside this session — operations that require approval are rejected automatically. When the task needs access beyond that scope, do not retry the denied operation; state the limitation in your reply so the delegating agent can handle it."}]},"role":"user","id":"{{sessionId}}"},"surfaceOp":"append"} {"type":"request/header","data":{"header":{"config":{"provider":"deepseek-official","model":"deepseek-v4-flash"},"tools":"{{tools}}"},"reason":"initial"}} {"type":"request/context","data":{"provider":"deepseek-official","model":"deepseek-v4-flash"}} {"type":"session/title","data":{"title":"Reply with exactly CHILD_RESULT and","messageSeqs":[8],"source":{"kind":"fallback"}}} diff --git a/apps/cli/tests/profiles/headless/tests/expected/subagent-settlement/stream-json.expected.jsonl b/apps/cli/tests/profiles/headless/tests/expected/subagent-settlement/stream-json.expected.jsonl index f05ae06cef..7c8b6c9606 100644 --- a/apps/cli/tests/profiles/headless/tests/expected/subagent-settlement/stream-json.expected.jsonl +++ b/apps/cli/tests/profiles/headless/tests/expected/subagent-settlement/stream-json.expected.jsonl @@ -4,7 +4,7 @@ {"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"step/start","seq":6,"time":0,"data":{"turn":1,"step":1}}} {"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"system/message","seq":7,"time":0,"data":{"turn":1,"step":1,"message":{"role":"system","content":[{"type":"text","text":"{{system}}"}],"source":{"kind":"system-prompt"},"id":"{{sessionId}}"}},"surfaceOp":"append"}} {"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"user/message","seq":8,"time":0,"data":{"content":[{"type":"text","text":"Start one continuable subagent and acknowledge its completion notice. Do not call list_agents or send_message."}],"source":{"kind":"user"},"role":"user","id":"{{sessionId}}"},"surfaceOp":"append"}} -{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"user/message","seq":9,"time":0,"data":{"content":[{"type":"text","text":"Current runtime context. This snapshot supersedes earlier runtime-context snapshots.\n\nCurrent working directory: \"{{cwd}}\".\n\nCurrent DSH file policy: workspace-write. Any available operation enforced by the DSH file sandbox may modify files under the session workspace: \"{{cwd}}\". Some platform temporary areas may also be writable.\n\nApproval prompts are enabled in this session: operations that require approval may ask through the configured answerers; without an available answerer, the request fails closed.\n\nYou are the root agent. Your agent id is \"{{sessionId}}\".\n\nTo message other agents, use send_message({ agent_id: \"\", message: \"...\" }).\nUse list_agents({}) to find your collaborator agents and their ids."}],"source":{"kind":"runtime-context","form":"snapshot","sections":[{"name":"working-directory:current","text":"Current working directory: \"{{cwd}}\"."},{"name":"sandbox:policy","text":"Current DSH file policy: workspace-write. Any available operation enforced by the DSH file sandbox may modify files under the session workspace: \"{{cwd}}\". Some platform temporary areas may also be writable."},{"name":"approval:policy","text":"Approval prompts are enabled in this session: operations that require approval may ask through the configured answerers; without an available answerer, the request fails closed."},{"name":"subagent:identity","text":"You are the root agent. Your agent id is \"{{sessionId}}\".\n\nTo message other agents, use send_message({ agent_id: \"\", message: \"...\" }).\nUse list_agents({}) to find your collaborator agents and their ids."}]},"role":"user","id":"{{sessionId}}"},"surfaceOp":"append"}} +{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"user/message","seq":9,"time":0,"data":{"content":[{"type":"text","text":"Current runtime context. This snapshot supersedes earlier runtime-context snapshots.\n\nCurrent working directory: \"{{cwd}}\".\n\nCurrent DSH file policy: workspace-write. Any available operation enforced by the DSH file sandbox may modify files under the session workspace: \"{{cwd}}\". Some platform temporary areas may also be writable.\n\nApproval prompts are enabled in this session: operations that require approval may ask through the configured answerers; without an available answerer, the request fails closed.\n\nYou are the root agent. Your name is \"lead\".\n\nTo message other agents, use send_message({ agent: \"\", message: \"...\" }).\nUse list_agents({}) to find your collaborator agents and their names."}],"source":{"kind":"runtime-context","form":"snapshot","sections":[{"name":"working-directory:current","text":"Current working directory: \"{{cwd}}\"."},{"name":"sandbox:policy","text":"Current DSH file policy: workspace-write. Any available operation enforced by the DSH file sandbox may modify files under the session workspace: \"{{cwd}}\". Some platform temporary areas may also be writable."},{"name":"approval:policy","text":"Approval prompts are enabled in this session: operations that require approval may ask through the configured answerers; without an available answerer, the request fails closed."},{"name":"subagent:identity","text":"You are the root agent. Your name is \"lead\".\n\nTo message other agents, use send_message({ agent: \"\", message: \"...\" }).\nUse list_agents({}) to find your collaborator agents and their names."}]},"role":"user","id":"{{sessionId}}"},"surfaceOp":"append"}} {"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"request/header","seq":10,"time":0,"data":{"header":{"config":{"provider":"deepseek-official","model":"deepseek-v4-flash"},"tools":"{{tools}}"},"reason":"initial"}}} {"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"request/context","seq":11,"time":0,"data":{"provider":"deepseek-official","model":"deepseek-v4-flash"}}} {"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"session/title","seq":12,"time":0,"data":{"title":"Start one continuable subagent and","messageSeqs":[8],"source":{"kind":"fallback"}}}} @@ -12,16 +12,16 @@ {"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/message","seq":14,"time":0,"data":{"turn":1,"step":1,"message":{"role":"assistant","content":[{"type":"tool-call","id":"start-child","name":"subagent","arguments":"{\"description\":\"Return child result\",\"prompt\":\"Reply with exactly CHILD_RESULT and nothing else. Do not call send_message.\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{sessionId}}"},"usage":{"inputTokens":10,"outputTokens":5},"stream":[{"type":"chunk","time":0,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}},{"type":"tool-call-chunks","time0":0,"index":0,"dt":[],"id":"start-child","name":"subagent","args":["{\"description\":\"Return child result\",\"prompt\":\"Reply with exactly CHILD_RESULT and nothing else. Do not call send_message.\"}"]},{"type":"chunk","time":0,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"start-child","name":"subagent","arguments":"{\"description\":\"Return child result\",\"prompt\":\"Reply with exactly CHILD_RESULT and nothing else. Do not call send_message.\"}"}}},{"type":"chunk","time":0,"chunk":{"type":"usage","usage":{"inputTokens":10,"outputTokens":5}}},{"type":"chunk","time":0,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}]},"surfaceOp":"append"}} {"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"tool/call","seq":15,"time":0,"data":{"turn":1,"step":1,"callId":"start-child","name":"subagent","arguments":"{\"description\":\"Return child result\",\"prompt\":\"Reply with exactly CHILD_RESULT and nothing else. Do not call send_message.\"}"}}} {"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"session/title","seq":16,"time":0,"data":{"title":"Subagent settlement","messageSeqs":[8],"source":{"kind":"provider","provider":"session-title-first-prompt-llm","model":{"provider":"deepseek-official","model":"deepseek-v4-flash"}}}}} -{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"subagent/catalog","seq":17,"time":0,"data":{"version":0,"childId":"{{sessionId}}","childCreatedAt":0,"mode":"continuable","label":"Return child result"}}} -{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"tool/result","seq":18,"time":0,"data":{"turn":1,"step":1,"message":{"role":"tool","source":{"kind":"tool","callId":"start-child"},"toolCallId":"start-child","content":[{"type":"text","text":"started subagent {{sessionId}}"}],"isError":false,"id":"{{sessionId}}"},"meta":{"kind":"activation","subagentId":"{{sessionId}}"}},"sourceEventSeqs":[15],"surfaceOp":"append"}} +{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"subagent/catalog","seq":17,"time":0,"data":{"version":3,"childId":"{{sessionId}}","childCreatedAt":0,"mode":"continuable","label":"Return child result","name":"agent-1"}}} +{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"tool/result","seq":18,"time":0,"data":{"turn":1,"step":1,"message":{"role":"tool","source":{"kind":"tool","callId":"start-child"},"toolCallId":"start-child","content":[{"type":"text","text":"started subagent agent-1"}],"isError":false,"id":"{{sessionId}}"},"meta":{"kind":"activation","name":"agent-1"}},"sourceEventSeqs":[15],"surfaceOp":"append"}} {"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"step/end","seq":19,"time":0,"data":{"turn":1,"step":1}}} -{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"agent/inbox/spliced","seq":20,"time":0,"data":{"target":"next-step","start":0,"inserted":[{"content":[{"type":"text","text":"Background subagent {{sessionId}} finished and will do no further work unless you send it more."},{"type":"text","text":"Its closing message:"},{"type":"text","text":"CHILD_RESULT"}],"source":{"kind":"subagent-settled","form":"notice","summary":"Background subagent {{sessionId}} finished and will do no further work unless you send it more.","stopReason":"completed","senderSessionId":"{{sessionId}}"},"role":"user","id":"{{sessionId}}"}]}}} +{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"agent/inbox/spliced","seq":20,"time":0,"data":{"target":"next-step","start":0,"inserted":[{"content":[{"type":"text","text":"Background subagent agent-1 finished and will do no further work unless you send it more."},{"type":"text","text":"Its closing message:"},{"type":"text","text":"CHILD_RESULT"}],"source":{"kind":"subagent-settled","form":"notice","summary":"Background subagent agent-1 finished and will do no further work unless you send it more.","stopReason":"completed","senderSessionId":"{{sessionId}}"},"role":"user","id":"{{sessionId}}"}]}}} {"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"step/start","seq":21,"time":0,"data":{"turn":1,"step":2}}} {"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/message","seq":22,"time":0,"data":{"turn":1,"step":2,"message":{"role":"assistant","content":[{"type":"text","text":"STARTED"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{sessionId}}"},"usage":{"inputTokens":10,"outputTokens":5},"stream":[{"type":"chunk","time":0,"chunk":{"type":"block-start","index":0,"blockType":"text"}},{"type":"text-chunks","time0":0,"index":0,"dt":[],"texts":["STARTED"]},{"type":"chunk","time":0,"chunk":{"type":"block-end","index":0,"block":{"type":"text","text":"STARTED"}}},{"type":"chunk","time":0,"chunk":{"type":"usage","usage":{"inputTokens":10,"outputTokens":5}}},{"type":"chunk","time":0,"chunk":{"type":"finish","reason":{"kind":"stop"}}}]},"surfaceOp":"append"}} {"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"step/end","seq":23,"time":0,"data":{"turn":1,"step":2}}} {"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"agent/inbox/spliced","seq":24,"time":0,"data":{"target":"next-step","start":0,"removedCount":1,"inserted":[]}}} {"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"step/start","seq":25,"time":0,"data":{"turn":1,"step":3}}} -{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"user/message","seq":26,"time":0,"data":{"content":[{"type":"text","text":"Background subagent {{sessionId}} finished and will do no further work unless you send it more."},{"type":"text","text":"Its closing message:"},{"type":"text","text":"CHILD_RESULT"}],"source":{"kind":"subagent-settled","form":"notice","summary":"Background subagent {{sessionId}} finished and will do no further work unless you send it more.","stopReason":"completed","senderSessionId":"{{sessionId}}"},"role":"user","id":"{{sessionId}}"},"surfaceOp":"append"}} +{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"user/message","seq":26,"time":0,"data":{"content":[{"type":"text","text":"Background subagent agent-1 finished and will do no further work unless you send it more."},{"type":"text","text":"Its closing message:"},{"type":"text","text":"CHILD_RESULT"}],"source":{"kind":"subagent-settled","form":"notice","summary":"Background subagent agent-1 finished and will do no further work unless you send it more.","stopReason":"completed","senderSessionId":"{{sessionId}}"},"role":"user","id":"{{sessionId}}"},"surfaceOp":"append"}} {"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/message","seq":27,"time":0,"data":{"turn":1,"step":3,"message":{"role":"assistant","content":[{"type":"text","text":"PARENT_RECEIVED_SETTLEMENT_NOTICE"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{sessionId}}"},"usage":{"inputTokens":10,"outputTokens":5},"stream":[{"type":"chunk","time":0,"chunk":{"type":"block-start","index":0,"blockType":"text"}},{"type":"text-chunks","time0":0,"index":0,"dt":[],"texts":["PARENT_RECEIVED_SETTLEMENT_NOTICE"]},{"type":"chunk","time":0,"chunk":{"type":"block-end","index":0,"block":{"type":"text","text":"PARENT_RECEIVED_SETTLEMENT_NOTICE"}}},{"type":"chunk","time":0,"chunk":{"type":"usage","usage":{"inputTokens":10,"outputTokens":5}}},{"type":"chunk","time":0,"chunk":{"type":"finish","reason":{"kind":"stop"}}}]},"surfaceOp":"append"}} {"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"step/end","seq":28,"time":0,"data":{"turn":1,"step":3}}} {"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"turn/end","seq":29,"time":0,"data":{"turn":1,"reason":{"kind":"completed"}}}} diff --git a/apps/cli/tests/profiles/headless/tests/expected/workspace-context-resume/offline-edit/session.expected.jsonl b/apps/cli/tests/profiles/headless/tests/expected/workspace-context-resume/offline-edit/session.expected.jsonl index 56b127865a..5a57e4bee6 100644 --- a/apps/cli/tests/profiles/headless/tests/expected/workspace-context-resume/offline-edit/session.expected.jsonl +++ b/apps/cli/tests/profiles/headless/tests/expected/workspace-context-resume/offline-edit/session.expected.jsonl @@ -17,7 +17,7 @@ {"type":"system/message","data":{"turn":2,"step":1,"message":{"role":"system","content":[{"type":"text","text":"{{system}}"}],"source":{"kind":"system-prompt"},"id":"{{sessionId}}"}},"sourceEventSeqs":[2],"surfaceOp":{"op":"replace","startSeq":2,"endSeq":2}} {"type":"user/message","data":{"content":[{"type":"text","text":"Acknowledge the current workspace instruction."}],"source":{"kind":"user"},"role":"user","id":"{{sessionId}}"},"surfaceOp":"append"} {"type":"user/message","data":{"content":[{"type":"text","text":"\nUpdated instructions from: AGENTS.md\n\nThis file changed after it was loaded. Use the following content instead of the previously loaded instructions from this file.\n\nNew workspace instruction after offline edit.\n\n"}],"source":{"kind":"agent-instructions","form":"instructions","changes":[{"action":"replace","scope":".\u0000AGENTS.md","path":"AGENTS.md","digest":"d8375b516f158718bd3463bc8eb7ed42c011b29f"}]},"role":"user","id":"{{sessionId}}"},"surfaceOp":"append"} -{"type":"user/message","data":{"content":[{"type":"text","text":"Current runtime context. This snapshot supersedes earlier runtime-context snapshots.\n\nCurrent working directory: \"{{cwd}}\".\n\nCurrent DSH file policy: workspace-write. Any available operation enforced by the DSH file sandbox may modify files under the session workspace: \"{{cwd}}\". Some platform temporary areas may also be writable.\n\nApproval prompts are enabled in this session: operations that require approval may ask through the configured answerers; without an available answerer, the request fails closed.\n\nYou are the root agent. Your agent id is \"{{sessionId}}\".\n\nTo message other agents, use send_message({ agent_id: \"\", message: \"...\" }).\nUse list_agents({}) to find your collaborator agents and their ids."}],"source":{"kind":"runtime-context","form":"snapshot","sections":[{"name":"working-directory:current","text":"Current working directory: \"{{cwd}}\"."},{"name":"sandbox:policy","text":"Current DSH file policy: workspace-write. Any available operation enforced by the DSH file sandbox may modify files under the session workspace: \"{{cwd}}\". Some platform temporary areas may also be writable."},{"name":"approval:policy","text":"Approval prompts are enabled in this session: operations that require approval may ask through the configured answerers; without an available answerer, the request fails closed."},{"name":"subagent:identity","text":"You are the root agent. Your agent id is \"{{sessionId}}\".\n\nTo message other agents, use send_message({ agent_id: \"\", message: \"...\" }).\nUse list_agents({}) to find your collaborator agents and their ids."}]},"role":"user","id":"{{sessionId}}"},"surfaceOp":"append"} +{"type":"user/message","data":{"content":[{"type":"text","text":"Current runtime context. This snapshot supersedes earlier runtime-context snapshots.\n\nCurrent working directory: \"{{cwd}}\".\n\nCurrent DSH file policy: workspace-write. Any available operation enforced by the DSH file sandbox may modify files under the session workspace: \"{{cwd}}\". Some platform temporary areas may also be writable.\n\nApproval prompts are enabled in this session: operations that require approval may ask through the configured answerers; without an available answerer, the request fails closed.\n\nYou are the root agent. Your name is \"lead\".\n\nTo message other agents, use send_message({ agent: \"\", message: \"...\" }).\nUse list_agents({}) to find your collaborator agents and their names."}],"source":{"kind":"runtime-context","form":"snapshot","sections":[{"name":"working-directory:current","text":"Current working directory: \"{{cwd}}\"."},{"name":"sandbox:policy","text":"Current DSH file policy: workspace-write. Any available operation enforced by the DSH file sandbox may modify files under the session workspace: \"{{cwd}}\". Some platform temporary areas may also be writable."},{"name":"approval:policy","text":"Approval prompts are enabled in this session: operations that require approval may ask through the configured answerers; without an available answerer, the request fails closed."},{"name":"subagent:identity","text":"You are the root agent. Your name is \"lead\".\n\nTo message other agents, use send_message({ agent: \"\", message: \"...\" }).\nUse list_agents({}) to find your collaborator agents and their names."}]},"role":"user","id":"{{sessionId}}"},"surfaceOp":"append"} {"type":"request/header","data":{"header":{"config":{"provider":"deepseek-official","model":"deepseek-v4-flash"},"tools":"{{tools}}"},"reason":"initial","startsSeries":true}} {"type":"request/context","data":{"provider":"deepseek-official","model":"deepseek-v4-flash"}} {"type":"session/title","data":{"title":"Remember the workspace instruction.","messageSeqs":[3],"source":{"kind":"fallback"}}} diff --git a/apps/cli/tests/profiles/headless/tests/expected/workspace-context-resume/precedence-change/session.expected.jsonl b/apps/cli/tests/profiles/headless/tests/expected/workspace-context-resume/precedence-change/session.expected.jsonl index dfe1d171a9..b70ee4a8df 100644 --- a/apps/cli/tests/profiles/headless/tests/expected/workspace-context-resume/precedence-change/session.expected.jsonl +++ b/apps/cli/tests/profiles/headless/tests/expected/workspace-context-resume/precedence-change/session.expected.jsonl @@ -17,7 +17,7 @@ {"type":"system/message","data":{"turn":2,"step":1,"message":{"role":"system","content":[{"type":"text","text":"{{system}}"}],"source":{"kind":"system-prompt"},"id":"{{sessionId}}"}},"sourceEventSeqs":[2],"surfaceOp":{"op":"replace","startSeq":2,"endSeq":2}} {"type":"user/message","data":{"content":[{"type":"text","text":"Acknowledge the current workspace instruction."}],"source":{"kind":"user"},"role":"user","id":"{{sessionId}}"},"surfaceOp":"append"} {"type":"user/message","data":{"content":[{"type":"text","text":"\nThis complete workspace instruction baseline replaces all earlier workspace instruction baselines. The following workspace instructions may be relevant to your work. Use them as guidance when applicable. More specific instructions take precedence over broader ones. They do not override system, developer, or direct user instructions.\n\nInstructions from: AGENTS.md\n\nCurrent AGENTS rule.\n\n\nInstructions from: CLAUDE.md\n\nCurrent CLAUDE rule.\n\n"}],"source":{"kind":"agent-instructions","form":"instructions","baseline":true,"baselineIdentity":"{\"projectRoot\":\"\",\"projectRootMarkers\":[\".git\"],\"maxBytes\":65536,\"maxSourceBytes\":1048576,\"instructionFileCandidates\":[\"AGENTS.md\",\"CLAUDE.md\"],\"localInstructionFileCandidates\":[\"AGENTS.local.md\",\"CLAUDE.local.md\"]}","changes":[{"action":"set","scope":".\u0000AGENTS.md","path":"AGENTS.md","digest":"7f53d2327837129750aef117f9754a001c46cf68"},{"action":"set","scope":".\u0000CLAUDE.md","path":"CLAUDE.md","digest":"5b1e9e3fd759eee6b43ceff899e47fb10c64701a"}]},"role":"user","id":"{{sessionId}}"},"surfaceOp":"append"} -{"type":"user/message","data":{"content":[{"type":"text","text":"Current runtime context. This snapshot supersedes earlier runtime-context snapshots.\n\nCurrent working directory: \"{{cwd}}\".\n\nCurrent DSH file policy: workspace-write. Any available operation enforced by the DSH file sandbox may modify files under the session workspace: \"{{cwd}}\". Some platform temporary areas may also be writable.\n\nApproval prompts are enabled in this session: operations that require approval may ask through the configured answerers; without an available answerer, the request fails closed.\n\nYou are the root agent. Your agent id is \"{{sessionId}}\".\n\nTo message other agents, use send_message({ agent_id: \"\", message: \"...\" }).\nUse list_agents({}) to find your collaborator agents and their ids."}],"source":{"kind":"runtime-context","form":"snapshot","sections":[{"name":"working-directory:current","text":"Current working directory: \"{{cwd}}\"."},{"name":"sandbox:policy","text":"Current DSH file policy: workspace-write. Any available operation enforced by the DSH file sandbox may modify files under the session workspace: \"{{cwd}}\". Some platform temporary areas may also be writable."},{"name":"approval:policy","text":"Approval prompts are enabled in this session: operations that require approval may ask through the configured answerers; without an available answerer, the request fails closed."},{"name":"subagent:identity","text":"You are the root agent. Your agent id is \"{{sessionId}}\".\n\nTo message other agents, use send_message({ agent_id: \"\", message: \"...\" }).\nUse list_agents({}) to find your collaborator agents and their ids."}]},"role":"user","id":"{{sessionId}}"},"surfaceOp":"append"} +{"type":"user/message","data":{"content":[{"type":"text","text":"Current runtime context. This snapshot supersedes earlier runtime-context snapshots.\n\nCurrent working directory: \"{{cwd}}\".\n\nCurrent DSH file policy: workspace-write. Any available operation enforced by the DSH file sandbox may modify files under the session workspace: \"{{cwd}}\". Some platform temporary areas may also be writable.\n\nApproval prompts are enabled in this session: operations that require approval may ask through the configured answerers; without an available answerer, the request fails closed.\n\nYou are the root agent. Your name is \"lead\".\n\nTo message other agents, use send_message({ agent: \"\", message: \"...\" }).\nUse list_agents({}) to find your collaborator agents and their names."}],"source":{"kind":"runtime-context","form":"snapshot","sections":[{"name":"working-directory:current","text":"Current working directory: \"{{cwd}}\"."},{"name":"sandbox:policy","text":"Current DSH file policy: workspace-write. Any available operation enforced by the DSH file sandbox may modify files under the session workspace: \"{{cwd}}\". Some platform temporary areas may also be writable."},{"name":"approval:policy","text":"Approval prompts are enabled in this session: operations that require approval may ask through the configured answerers; without an available answerer, the request fails closed."},{"name":"subagent:identity","text":"You are the root agent. Your name is \"lead\".\n\nTo message other agents, use send_message({ agent: \"\", message: \"...\" }).\nUse list_agents({}) to find your collaborator agents and their names."}]},"role":"user","id":"{{sessionId}}"},"surfaceOp":"append"} {"type":"request/header","data":{"header":{"config":{"provider":"deepseek-official","model":"deepseek-v4-flash"},"tools":"{{tools}}"},"reason":"initial","startsSeries":true}} {"type":"request/context","data":{"provider":"deepseek-official","model":"deepseek-v4-flash"}} {"type":"session/title","data":{"title":"Remember the workspace instruction.","messageSeqs":[3],"source":{"kind":"fallback"}}} diff --git a/apps/cli/tests/profiles/headless/tests/fixtures/team-llm.mjs b/apps/cli/tests/profiles/headless/tests/fixtures/team-llm.mjs index 62751cd93f..a6b334193a 100644 --- a/apps/cli/tests/profiles/headless/tests/fixtures/team-llm.mjs +++ b/apps/cli/tests/profiles/headless/tests/fixtures/team-llm.mjs @@ -87,7 +87,7 @@ function researcher(messages) { if (!names.includes('send_message')) { return toolChunks([ { name: 'team_task_update', args: { task_id: 'task-1', expected_revision: 2, action: 'complete' } }, - { name: 'send_message', args: { agent_id: sibling, message: 'Research complete: use the deterministic finding.' } }, + { name: 'send_message', args: { agent: sibling, message: 'Research complete: use the deterministic finding.' } }, ]) } return textChunks('Research teammate complete.') @@ -134,7 +134,7 @@ function implementer(messages, parentId) { if (!names.includes('send_message')) { return toolChunks([ { name: 'team_task_update', args: { task_id: 'task-2', expected_revision: 2, action: 'complete' } }, - { name: 'send_message', args: { agent_id: parentId, message: 'Implementation complete and verified.' } }, + { name: 'send_message', args: { agent: parentId, message: 'Implementation complete and verified.' } }, ]) } return textChunks('Implementation teammate complete.') @@ -203,7 +203,7 @@ class TeamFixtureAdapter extends LlmAdapter { if (workflowChild) chunks = textChunks('Fresh workflow child complete.') else if (task?.startsWith('RESEARCHER_MARK:')) chunks = researcher(options.messages) else if (task?.startsWith('IMPLEMENTER_MARK:')) chunks = implementer(options.messages, parentId) - else if (role?.startsWith('You are the root agent. Your agent id is')) chunks = lead(options.messages) + else if (role?.startsWith('You are the root agent. Your name is')) chunks = lead(options.messages) else throw new Error('Team runtime context is missing a recognized identity') for (const chunk of chunks) { options.signal?.throwIfAborted() diff --git a/apps/cli/tests/profiles/headless/tests/headless.expected.e2e.ts b/apps/cli/tests/profiles/headless/tests/headless.expected.e2e.ts index 9f53fb980a..69c95ef485 100644 --- a/apps/cli/tests/profiles/headless/tests/headless.expected.e2e.ts +++ b/apps/cli/tests/profiles/headless/tests/headless.expected.e2e.ts @@ -1254,18 +1254,18 @@ describe('headless stream-json snapshots', () => { "checkedAgents": true, "deliveredMessages": 0, "identities": [ - "You are a subagent delegated by agent "". - Your agent id is "". - The root agent of your collaboration tree is "". + "You are a subagent delegated by agent "lead". + Your name is "agent-2". + The root agent of your collaboration tree is "lead". - To message other agents, use send_message({ agent_id: "", message: "..." }). - Use list_agents({}) to find your collaborator agents and their ids.", - "You are a subagent delegated by agent "". - Your agent id is "". - The root agent of your collaboration tree is "". + To message other agents, use send_message({ agent: "", message: "..." }). + Use list_agents({}) to find your collaborator agents and their names.", + "You are a subagent delegated by agent "lead". + Your name is "agent-3". + The root agent of your collaboration tree is "lead". - To message other agents, use send_message({ agent_id: "", message: "..." }). - Use list_agents({}) to find your collaborator agents and their ids.", + To message other agents, use send_message({ agent: "", message: "..." }). + Use list_agents({}) to find your collaborator agents and their names.", ], "queuedMessages": 0, "sessions": 4, diff --git a/apps/cli/tests/profiles/headless/tests/subagent-diagnostic.expected.e2e.ts b/apps/cli/tests/profiles/headless/tests/subagent-diagnostic.expected.e2e.ts index 3aff474038..c89eb1703c 100644 --- a/apps/cli/tests/profiles/headless/tests/subagent-diagnostic.expected.e2e.ts +++ b/apps/cli/tests/profiles/headless/tests/subagent-diagnostic.expected.e2e.ts @@ -132,8 +132,8 @@ describe('parent-owned cold child catalog snapshot', () => { if (parent === undefined) throw new Error('missing persisted parent log') // Discovery reads child catalogs without requiring activation descriptors. - expect(parent).toContain(`${childId} [inactive] parent=${parentId} depth=1 — descriptorless child`) - expect(parent).not.toContain('[diagnostic: corrupt]') + expect(parent).toContain(`${childId} [inactive] — descriptorless child`) + expect(parent).not.toContain(`${childId} [corrupt]`) const context: NormalizeContext = { sessionIds: [parentId, childId], cwd } const normalizedParent = normalizeSessionSnapshot(parent, context) diff --git a/apps/cli/tests/web-agent-presets.e2e.ts b/apps/cli/tests/web-agent-presets.e2e.ts index ff5fd57cae..01aed139c7 100644 --- a/apps/cli/tests/web-agent-presets.e2e.ts +++ b/apps/cli/tests/web-agent-presets.e2e.ts @@ -345,7 +345,7 @@ describe('the shipped Web composition', () => { 'model', 'provider', 'reasoning_effort', ])) for (const agent of [disabled.agent, enabled.agent]) { - expect(toolParameterNames(ctx, agent, 'subagent_fork')).toEqual(['cwd', 'description', 'prompt']) + expect(toolParameterNames(ctx, agent, 'subagent_fork')).toEqual(['cwd', 'description', 'name', 'prompt']) } } finally { await policy.dispose() @@ -802,7 +802,7 @@ describe.each(['web', 'desktop'] as const)('%s native subagent bundles', (surfac }) try { for (const product of installed) { - expect(toolParameterNames(productCtx, handle.agent, toolName(product))).toEqual(['cwd', 'description', 'prompt']) + expect(toolParameterNames(productCtx, handle.agent, toolName(product))).toEqual(['cwd', 'description', 'name', 'prompt']) } } finally { await handle.dispose() } expect(spawn).not.toHaveBeenCalled() diff --git a/apps/desktop/README.i18n.yaml b/apps/desktop/README.i18n.yaml index 081d44f9f8..83dcfa1f5b 100644 --- a/apps/desktop/README.i18n.yaml +++ b/apps/desktop/README.i18n.yaml @@ -33,8 +33,8 @@ en: 372297005b57a08b zh: 074a635ac17e4362 /deepseek-harness-desktop/installation-ownership: - en: 160b500cdcd6a39a - zh: 6c267f1762ec3689 + en: 575d82acb5d61018 + zh: b1064786f63863f7 /deepseek-harness-desktop/installation-ownership/runtime-and-plugin-activation: en: 4951cd3ee659eb33 zh: 96bdd6358dad587a diff --git a/apps/desktop/README.md b/apps/desktop/README.md index 335991f722..972d66d424 100644 --- a/apps/desktop/README.md +++ b/apps/desktop/README.md @@ -161,7 +161,7 @@ Windows and macOS relay native fullscreen transitions and the state after each p Windows uses a 40-DIP caption with native window controls and colors synchronized from the application palette. Localized Application and Edit entries beside the sidebar toggle open native popup menus. They mount only after the application frame publishes its shell overlay seat, and remain absent during startup loading. Application provides Check for Updates and Exit; Edit provides undo, redo, cut, copy, paste, delete, and select all by sending the corresponding keys to the focused editor, independently of custom shortcut bindings. Plugin management uses the main application's Plugins page. No separate native menu row appears on Alt. Other platforms retain their native menus. Editable fields retain keyboard commands and a context menu without shortcut labels; Chromium supplies command availability, and selected read-only text offers Copy. -On macOS the custom menu retains Electron's standard Window menu and application hide commands, including Minimize (⌘M) and Hide (⌘H). Linux keeps the application and Edit menus. +On macOS the custom menu retains Electron's standard Window menu and application hide commands, including Minimize (⌘M) and Hide (⌘H). Its Edit menu copies Electron's, binds Paste and Match Style to ⇧⌘V, and keeps Electron's ⌥⇧⌘V as a hidden alias; the Substitutions and Speech titles come from the desktop locale, while the other items keep Electron's English labels. Linux keeps the application and Edit menus. ### Runtime and plugin activation diff --git a/apps/desktop/README.zh.md b/apps/desktop/README.zh.md index 82ccf994a4..446e5c7420 100644 --- a/apps/desktop/README.zh.md +++ b/apps/desktop/README.zh.md @@ -161,7 +161,7 @@ Windows 和 macOS 会在原生全屏切换及每次页面加载后向渲染器 Windows 使用 40 DIP 顶栏,保留原生窗口按钮,颜色随应用调色板同步。侧栏开关旁的本地化“应用”和“编辑”入口打开原生弹出菜单。仅当应用框架发布 shell overlay 席位后才挂载菜单,启动加载期间不显示。“应用”提供检查更新和退出;“编辑”向当前编辑器发送对应按键,提供撤销、重做、剪切、复制、粘贴、删除和全选,不受自定义快捷键绑定影响。插件管理使用主应用的“插件”页面。按 Alt 不会出现额外的原生菜单行。其他平台保留原生菜单。可编辑区域保留快捷键和不带快捷键标注的右键菜单;命令可用状态由 Chromium 提供,选中的只读文本提供“复制”命令。 -macOS 上自定义菜单保留 Electron 的标准 Window 菜单及应用隐藏命令,包括 Minimize(⌘M)和 Hide(⌘H)。Linux 保留应用菜单和 Edit 菜单。 +macOS 上自定义菜单保留 Electron 的标准 Window 菜单及应用隐藏命令,包括 Minimize(⌘M)和 Hide(⌘H)。其 Edit 菜单复制 Electron 的默认菜单,把 Paste and Match Style 绑定到 ⇧⌘V,并保留 Electron 默认的 ⌥⇧⌘V 作为隐藏别名;Substitutions 和 Speech 标题取自桌面端语言包,其余条目保留 Electron 的英文标签。Linux 保留应用菜单和 Edit 菜单。 ### 运行时与插件激活 diff --git a/apps/desktop/packaging/README.i18n.yaml b/apps/desktop/packaging/README.i18n.yaml index 5015126b05..5d25de6c86 100644 --- a/apps/desktop/packaging/README.i18n.yaml +++ b/apps/desktop/packaging/README.i18n.yaml @@ -24,11 +24,11 @@ en: 5b4f0f80a117f202 zh: ff05be196c181087 /desktop-packaging/windows-actions-packaging: - en: e0a852fdda949c40 - zh: b96c613022f6189e + en: 52f0d14ee575ad1a + zh: 94a7f76f4c15031e /desktop-packaging/macos-self-hosted-packaging: - en: 239d5ab433020745 - zh: e8916ba0f4682ae1 + en: 08619f0e26782636 + zh: 7c236cbe46be4a47 /desktop-packaging/unsigned-windows-test-installer: en: f429bc0c280e2dfa zh: 4adbcc9e906bdf80 diff --git a/apps/desktop/packaging/README.md b/apps/desktop/packaging/README.md index b5875363ae..7fdaa6f328 100644 --- a/apps/desktop/packaging/README.md +++ b/apps/desktop/packaging/README.md @@ -115,7 +115,7 @@ Select the workflow in Actions, choose the source branch, preset, signing mode a All Windows packaging modes, including test and unsigned, require the repository variable `DESKTOP_PUBLISH_RUNNERS`; configure the [original-machine route](../publishing/ci/README.md#machine-setup) before dispatch. -Open the completed run in Actions and download its Artifacts from the independent `upload-artifact` job. Installer names use the original `package_run_attempt`; diagnostic names use the current `run_attempt`. If archival fails after packaging succeeds, rerun only `upload-artifact` to reuse the retained installers. `windows-x64-signed---` and `windows-x64-unsigned---` contain the corresponding EXE; `windows-package-logs--` contains packaging diagnostics. The upload steps are `Retain verified signed installer`, `Retain verified unsigned installer`, and `Retain packaging diagnostics`; their step durations and timestamped logs show upload time. These artifacts are not a Release or download-site publication. +Open the completed run in Actions and download its Artifacts from the independent `upload-artifact` job. Installer names use the original `package_run_attempt`; diagnostic names use the current `run_attempt`. If archival fails after packaging succeeds, fix the [archival prerequisites](../publishing/ci/README.md#recovery-and-records) and rerun only `upload-artifact` to reuse the retained installers. `windows-x64-signed---.zip` and `windows-x64-unsigned---.zip` contain the corresponding EXE; `windows-package-logs--` contains packaging diagnostics. Installer ZIPs record each retained copy’s modification time as local time in the DOS field and absolute time in the Unix field; this is not a guarantee of the original build time. The upload steps are `Retain installers for the selected mode` and `Retain packaging diagnostics`; their step durations and timestamped logs show upload time. These artifacts are not a Release or download-site publication. For cache measurements, `cache_namespace` selects a retained subdirectory for both dependency stores and upstream downloads; leave it empty for normal shared caches. Use a new name for a cold sample and repeat that name for warm samples. Names contain 1–64 lowercase letters, digits or hyphens, start with a letter or digit, and cannot be Windows device names. This does not reset the separate signature cache or OS file cache; report those states and Job start-to-completion time alongside phase timings and artifact size. Before dependency installation, the workflow records the Node version, available CPU parallelism, logical CPU count, and total/free memory. @@ -127,7 +127,7 @@ Installer uploads store the already-compressed release files without ZIP recompr ## macOS self-hosted packaging -The [Apple Silicon workflow](../../../.github/workflows/macos-package.yml) and [Intel workflow](../../../.github/workflows/macos-intel-package.yml) produce separate arm64 and x64 packages on the Apple Silicon runner labeled `dsh-mac-package-trial`. Both share one concurrency group. The Intel workflow checks Rosetta execution before dependency installation; its selected source must include the target-aware macOS CI adapter. Both select `test` or `production` and use the existing signing, notarization and packaged-runtime checks. When the selected source's dsh ships the Computer Use bundle, each workflow builds, notarizes and stages the helper for both architectures with `scripts/cua-helper/package.ts` and `stage.ts` after the configuration check, the steps npm publication uses; `skip_notarization` does not skip the helper's notarization. A source that predates helper packaging only emits a warning, and Computer Use cannot prepare its helper in that package. Successful DMG/ZIP files and diagnostic logs are retained for 14 days without publishing a release. Installer uploads disable redundant ZIP compression. The operator must verify a complete Actions run and installation on the target architecture before release qualification. The `compression_level` dropdown defaults to `3` and also offers `7`; it overrides the machine preset for this run and affects only ZIP and automatic-update downloads, not DMG. +The [Apple Silicon workflow](../../../.github/workflows/macos-package.yml) and [Intel workflow](../../../.github/workflows/macos-intel-package.yml) produce separate arm64 and x64 packages on the Apple Silicon runner labeled `dsh-mac-package-trial`. Both share one concurrency group. The Intel workflow checks Rosetta execution before dependency installation; its selected source must include the target-aware macOS CI adapter. Both select `test` or `production` and use the existing signing, notarization and packaged-runtime checks. When the selected source's dsh ships the Computer Use bundle, each workflow builds, notarizes and stages the helper for both architectures with `scripts/cua-helper/package.ts` and `stage.ts` after the configuration check, the steps npm publication uses; `skip_notarization` does not skip the helper's notarization. A source that predates helper packaging only emits a warning, and Computer Use cannot prepare its helper in that package. Successful DMG/ZIP files and diagnostic logs are retained for 14 days without publishing a release. Installer uploads disable redundant ZIP compression. Artifacts are named `macos-----.zip`, with `arch` set to `arm64` or `x64`; entry timestamps record each retained copy’s modification time as local time in the DOS field and absolute time in the Unix field; this is not a guarantee of the original build time. The operator must verify a complete Actions run and installation on the target architecture before release qualification. The `compression_level` dropdown defaults to `3` and also offers `7`; it overrides the machine preset for this run and affects only ZIP and automatic-update downloads, not DMG. Both macOS workflows require the repository variable `DESKTOP_PUBLISH_RUNNERS`, including test and unnotarized modes. Their independent `upload-artifact` job retains installer names with the original build attempt; if archival fails after packaging succeeds, rerun only that job. See [original-machine routing and recovery](../publishing/ci/README.md#recovery-and-records). diff --git a/apps/desktop/packaging/README.zh.md b/apps/desktop/packaging/README.zh.md index eac441d256..9853318b24 100644 --- a/apps/desktop/packaging/README.zh.md +++ b/apps/desktop/packaging/README.zh.md @@ -115,7 +115,7 @@ runner 的受监督启动和恢复见 [Windows runner 机器准备](../windows-s 所有 Windows 打包模式(含 test 和 unsigned)都要求仓库变量 `DESKTOP_PUBLISH_RUNNERS`;触发前配置[原机器路由](../publishing/ci/README.zh.md#machine-setup)。 -在 Actions 打开完成的运行,下载独立 `upload-artifact` job 生成的 Artifacts。安装包名称使用原构建的 `package_run_attempt`,诊断名称使用当前 `run_attempt`。打包成功但归档失败时,仅重跑 `upload-artifact` 以复用保留的安装包。`windows-x64-signed---` 与 `windows-x64-unsigned---` 包含对应 EXE;`windows-package-logs--` 包含打包诊断。上传步骤名为 `Retain verified signed installer`、`Retain verified unsigned installer` 和 `Retain packaging diagnostics`;步骤耗时与带时间戳的日志显示上传用时。这些产物不等于发布 Release 或下载站内容。 +在 Actions 打开完成的运行,下载独立 `upload-artifact` job 生成的 Artifacts。安装包名称使用原构建的 `package_run_attempt`,诊断名称使用当前 `run_attempt`。打包成功但归档失败时,修复[归档前置条件](../publishing/ci/README.zh.md#recovery-and-records)后仅重跑 `upload-artifact`,复用保留的安装包。`windows-x64-signed---.zip` 与 `windows-x64-unsigned---.zip` 包含对应 EXE;`windows-package-logs--` 包含打包诊断。安装包 ZIP 用 DOS 字段的本地时间和 Unix 字段的绝对时间记录各留存副本的修改时间,不保证是原始构建时间。上传步骤名为 `Retain installers for the selected mode` 和 `Retain packaging diagnostics`;步骤耗时与带时间戳的日志显示上传用时。这些产物不等于发布 Release 或下载站内容。 测量缓存时,`cache_namespace` 为两个依赖 store 和上游下载选择保留的子目录;留空使用正常共享缓存。新名称用于冷缓存采样,再次使用同名用于热缓存采样。名称由 1–64 个小写字母、数字或连字符组成,以字母或数字开头,且不能为 Windows 设备名。这不会重置独立的签名缓存或操作系统文件缓存;应将其状态、Job 开始至完成的总耗时与阶段耗时和产物体积一并报告。workflow 在依赖安装前记录 Node 版本、可用 CPU 并行数、逻辑 CPU 数及总内存和空闲内存。 @@ -127,7 +127,7 @@ runner 的受监督启动和恢复见 [Windows runner 机器准备](../windows-s ## macOS 自托管打包 -[Apple Silicon 工作流](../../../.github/workflows/macos-package.yml)与 [Intel 工作流](../../../.github/workflows/macos-intel-package.yml)在带有 `dsh-mac-package-trial` 标签的 Apple Silicon runner 上分别生成 arm64 和 x64 安装包,两者共用一个并发组。Intel 工作流在安装依赖前检查 Rosetta 能否执行;所选源码必须包含按目标架构校验的 macOS CI 适配脚本。两者均选择 `test` 或 `production`,并复用现有签名、公证和打包运行时检查。所选源码的 dsh 随附 Computer Use 组合包时,两者都在配置检查之后用 `scripts/cua-helper/package.ts` 和 `stage.ts` 构建、公证并放入两种架构的 helper,与 npm 发布的步骤相同;`skip_notarization` 不会跳过 helper 的公证。源码早于 helper 打包支持时只输出警告,该安装包中的 Computer Use 无法准备 helper。成功的 DMG/ZIP 与诊断日志保留 14 天,不发布 release;安装包上传关闭重复 ZIP 压缩。操作人员须验收完整 Actions 运行及目标架构上的安装,才能确认可交付。`compression_level` 下拉选项默认为 `3`,也可选择 `7`;本次运行以该选项覆盖机器预设,只影响 ZIP 和自动升级下载,不影响 DMG。 +[Apple Silicon 工作流](../../../.github/workflows/macos-package.yml)与 [Intel 工作流](../../../.github/workflows/macos-intel-package.yml)在带有 `dsh-mac-package-trial` 标签的 Apple Silicon runner 上分别生成 arm64 和 x64 安装包,两者共用一个并发组。Intel 工作流在安装依赖前检查 Rosetta 能否执行;所选源码必须包含按目标架构校验的 macOS CI 适配脚本。两者均选择 `test` 或 `production`,并复用现有签名、公证和打包运行时检查。所选源码的 dsh 随附 Computer Use 组合包时,两者都在配置检查之后用 `scripts/cua-helper/package.ts` 和 `stage.ts` 构建、公证并放入两种架构的 helper,与 npm 发布的步骤相同;`skip_notarization` 不会跳过 helper 的公证。源码早于 helper 打包支持时只输出警告,该安装包中的 Computer Use 无法准备 helper。成功的 DMG/ZIP 与诊断日志保留 14 天,不发布 release;安装包上传关闭重复 ZIP 压缩。产物名为 `macos-----.zip`,其中 `arch` 为 `arm64` 或 `x64`;条目时间以 DOS 字段的本地时间和 Unix 字段的绝对时间记录留存副本的修改时间,不保证是原始构建时间。操作人员须验收完整 Actions 运行及目标架构上的安装,才能确认可交付。`compression_level` 下拉选项默认为 `3`,也可选择 `7`;本次运行以该选项覆盖机器预设,只影响 ZIP 和自动升级下载,不影响 DMG。 两个 macOS 工作流都要求仓库变量 `DESKTOP_PUBLISH_RUNNERS`,包括 test 和未公证模式。独立 `upload-artifact` job 的安装包名称保留原构建 attempt;打包成功但归档失败时,仅重跑该 job。参见[原机器路由与恢复](../publishing/ci/README.zh.md#recovery-and-records)。 diff --git a/apps/desktop/publishing/ci/README.i18n.yaml b/apps/desktop/publishing/ci/README.i18n.yaml index 6764ae324f..3a0b48db93 100644 --- a/apps/desktop/publishing/ci/README.i18n.yaml +++ b/apps/desktop/publishing/ci/README.i18n.yaml @@ -27,8 +27,8 @@ en: 3f58698708671202 zh: be0ba215a67168d6 /desktop-ci-publication/recovery-and-records: - en: 266afba2adeeadef - zh: 063114103585dae8 + en: d6eb9cbac5b819a0 + zh: 0de1ec24055d1007 /desktop-ci-publication/restore-a-channel: en: d82e2ccf70cce397 zh: d93dcb77cc4b463e diff --git a/apps/desktop/publishing/ci/README.md b/apps/desktop/publishing/ci/README.md index 2232ea39c7..d1e5f18fa1 100644 --- a/apps/desktop/publishing/ci/README.md +++ b/apps/desktop/publishing/ci/README.md @@ -80,6 +80,8 @@ Before installing dependencies on the original runner, preparation and the appro ## Recovery and records +The archival job creates a store-mode ZIP with system bsdtar: `%SystemRoot%\System32\tar.exe` on Windows, or `/usr/bin/tar` on macOS. `invalid ZIP output settings` rejects a missing or malformed archive name and missing retained-directory, temporary-directory or `GITHUB_OUTPUT` settings before file verification. `desktop archival: SystemRoot is required to locate Windows bsdtar` reports a missing Windows system directory setting. `ZIP creation failed with ` identifies the failed archive tool; inspect its stderr, tool availability and free space in `RUNNER_TEMP`. + The packaging workflows separate `package` from `upload-artifact` (GitHub artifact archival). All packaging modes, including test and unsigned builds, require `DESKTOP_PUBLISH_RUNNERS` before packaging; it routes archival to the original machine. Rerun only `upload-artifact` after an archival failure; it verifies the original manifest and hashes without rebuilding, signing or notarizing. Packaging diagnostics are best effort and do not change package success. If an archival retry stays queued without a runner, inspect the resolved runner label and upstream package outputs before treating the runner as offline. Missing outputs require operator recovery of the original retained directory and manifest; rerunning the whole workflow rebuilds the package and is not archival-only recovery. Verify output reuse in the Actions acceptance test. Production COS publication enables website installer upload and cache refresh by default (`upload_website=true`). Clear it to publish only versioned resources and automatic-update feeds; test publication never changes the production website. `upload-website-installer` uploads the fixed installer and `purge-website-installer` refreshes its URL. The website installer validator needs only the final DMG/EXE and retained manifest. It matches production qualification, build identity and target, hashes the installer once and uploads through the same open file handle. Both production nightly and stable packages can replace the fixed website installer. Operators select the intended version; the fixed object has no downgrade protection, so rerunning an older publication can replace a newer installer. The pre-approval summary names the fixed website URL, selected version and lack of downgrade protection when website upload is selected. The existing version/update publication retains its own checks. diff --git a/apps/desktop/publishing/ci/README.zh.md b/apps/desktop/publishing/ci/README.zh.md index 99d245bf1a..0ff96d3ba3 100644 --- a/apps/desktop/publishing/ci/README.zh.md +++ b/apps/desktop/publishing/ci/README.zh.md @@ -80,6 +80,8 @@ Environment 审批限制此工作流,不限制同一机器账户运行的任 ## 恢复与记录 +归档 job 使用系统 bsdtar 创建 store 模式 ZIP:Windows 为 `%SystemRoot%\System32\tar.exe`,macOS 为 `/usr/bin/tar`。`invalid ZIP output settings` 表示归档名称缺失或格式非法,或保留目录、临时目录、`GITHUB_OUTPUT` 缺失,会在校验文件前拒绝。`desktop archival: SystemRoot is required to locate Windows bsdtar` 表示缺失 Windows 系统目录设置。`ZIP creation failed with ` 指明失败的归档工具;检查其 stderr、工具是否可用,以及 `RUNNER_TEMP` 剩余空间。 + 打包 workflow 将 `package` 与 `upload-artifact`(GitHub 产物归档)分开。所有打包模式(包括 test 和 unsigned)都要求在打包前配置 `DESKTOP_PUBLISH_RUNNERS`,用于将归档路由到原机器。归档失败后仅重跑 `upload-artifact`;它校验原始 manifest 和 hash,不重新构建、签名或公证。打包诊断归档尽力执行,不改变构建成功状态。归档重跑若一直排队且未分配 runner,应先检查解析出的 runner 标签和上游 package 输出,不能直接认定机器离线。输出缺失时需由操作者从原留存目录和 manifest 恢复文件;重跑整个 workflow 会重新构建,不属于仅归档恢复。Actions 验收须验证输出复用。 生产 COS 发布默认启用官网安装包上传和缓存刷新(`upload_website=true`)。取消后仅发布版本化资源及自动更新清单;test 发布不修改生产官网。`upload-website-installer` 上传固定安装包,`purge-website-installer` 刷新该 URL。官网安装包校验器只需要最终 DMG/EXE 和保留的 manifest,匹配生产资格、构建身份及平台,只计算一次安装包 hash,并通过同一打开的文件句柄上传。production nightly 和 stable 包都可以替换官网固定安装包。操作者负责选择预期版本;固定对象没有防降级保护,重跑旧发布可能覆盖新安装包。勾选官网上传时,审批前摘要展示固定官网 URL、选定版本和无防降级保护的说明。原有版本与自动更新发布保留自身校验。 diff --git a/apps/desktop/scripts/archive-desktop-ci.ts b/apps/desktop/scripts/archive-desktop-ci.ts index 849433b698..1517d20dd4 100644 --- a/apps/desktop/scripts/archive-desktop-ci.ts +++ b/apps/desktop/scripts/archive-desktop-ci.ts @@ -1,5 +1,7 @@ -/** Validate the original machine and immutable inventory before GitHub artifact archival. */ -import { resolve } from 'node:path' +/** Create the verified installer ZIP and expose its path to the Actions upload step. */ +import { execFileSync } from 'node:child_process' +import { appendFile, mkdtemp } from 'node:fs/promises' +import { join, resolve } from 'node:path' import { desktopPublicationFailure } from './desktop-publication-failure.ts' import { desktopReleasesRoot } from './retain-desktop-ci.ts' import { retainedDesktopPath, verifyRetainedDesktopRelease } from './desktop-release-store.ts' @@ -7,9 +9,9 @@ import { retainedDesktopPath, verifyRetainedDesktopRelease } from './desktop-rel /** * Verify an original build without interpreting the archive job's attempt as a new build. * @param env Original build outputs and current Actions machine identity. - * @returns Resolves after the retained inventory passes all digest checks. + * @returns Verified file names to include alongside the manifest. */ -export async function verifyDesktopArchive(env: NodeJS.ProcessEnv): Promise { +export async function verifyDesktopArchive(env: NodeJS.ProcessEnv): Promise { if (!env.RUNNER_NAME || env.RUNNER_NAME !== env.DESKTOP_PACKAGE_RUNNER) throw new Error('desktop archival: wrong original machine') const root = desktopReleasesRoot(env) const runId = env.GITHUB_RUN_ID || '' @@ -20,11 +22,27 @@ export async function verifyDesktopArchive(env: NodeJS.ProcessEnv): Promise file.name)] } if (process.argv[1] !== undefined && resolve(process.argv[1]) === import.meta.filename) { - try { await verifyDesktopArchive(process.env) } - catch (error) { + try { + const { DESKTOP_ARCHIVE_NAME: name, DESKTOP_RETAINED_DIRECTORY: directory, RUNNER_TEMP: temp, GITHUB_OUTPUT: output } = process.env + if (!name || !/^[a-zA-Z0-9][a-zA-Z0-9.+_-]*\.zip$/u.test(name) || !directory || !temp || !output) throw new Error('desktop archival: invalid ZIP output settings') + const files = await verifyDesktopArchive(process.env) + // archive: false uses the file basename; keep it equal to the upload step's name used for overwrite deletion. + const path = join(await mkdtemp(join(temp, 'desktop-archive-')), name) + const windows = process.platform === 'win32' + if (windows && !process.env.SystemRoot) throw new Error('desktop archival: SystemRoot is required to locate Windows bsdtar') + const tar = windows ? join(process.env.SystemRoot!, 'System32', 'tar.exe') : '/usr/bin/tar' + const metadata = process.platform === 'darwin' ? ['--no-mac-metadata', '--no-xattrs'] : [] + try { + execFileSync(tar, ['--format', 'zip', '--options', 'zip:compression=store', ...metadata, '-cf', path, '--', ...files], { cwd: directory, stdio: 'inherit' }) + } catch (cause) { + throw new Error(`desktop archival: ZIP creation failed with ${tar}. Check system bsdtar availability, its stderr and free space in RUNNER_TEMP.`, { cause }) + } + await appendFile(output, `path=${path}\n`) + } catch (error) { process.stderr.write(`${JSON.stringify(desktopPublicationFailure(error, 'artifact archival'))}\n`) process.exitCode = 1 } diff --git a/apps/desktop/scripts/preflight-desktop-publish.mjs b/apps/desktop/scripts/preflight-desktop-publish.mjs index dfc1dcb4a6..fbe6947398 100644 --- a/apps/desktop/scripts/preflight-desktop-publish.mjs +++ b/apps/desktop/scripts/preflight-desktop-publish.mjs @@ -27,7 +27,7 @@ export function preflightDesktopPublish(repository, inputs, api) { throw new Error('desktop publish: GitHub returned invalid artifact metadata') } for (const { name } of pages.flatMap(page => page.artifacts)) { - if (!name.endsWith(`-${inputs.package_run_id}-${attempt}`)) continue + if (!name.replace(/\.zip$/u, '').endsWith(`-${inputs.package_run_id}-${attempt}`)) continue const qualification = name.startsWith('windows-x64-unsigned-') ? 'unsigned' : /^macos-(?:arm64|x64)-unnotarized-debug-/u.test(name) ? 'unnotarized' : '' const diagnostic = desktopPublishQualificationError(qualification) diff --git a/apps/desktop/src/locale.ts b/apps/desktop/src/locale.ts index bddf39b9f8..050548e879 100644 --- a/apps/desktop/src/locale.ts +++ b/apps/desktop/src/locale.ts @@ -37,6 +37,8 @@ export const en = { hideApplication: 'Hide DeepSeek Harness', hideOtherApplications: 'Hide Others', showAllApplications: 'Show All', + substitutionsMenu: 'Substitutions', + speechMenu: 'Speech', quitApplication: 'Quit DeepSeek Harness', openApplication: 'Open DeepSeek Harness', quit: 'Quit', @@ -228,6 +230,8 @@ export const zh = { hideApplication: '隐藏 DeepSeek Harness', hideOtherApplications: '隐藏其他', showAllApplications: '显示全部', + substitutionsMenu: '替换', + speechMenu: '语音', quitApplication: '退出 DeepSeek Harness', openApplication: '打开 DeepSeek Harness', quit: '退出', @@ -417,6 +421,8 @@ export const ja = { hideApplication: 'DeepSeek Harness を隠す', hideOtherApplications: 'ほかを隠す', showAllApplications: 'すべて表示', + substitutionsMenu: '自動置換', + speechMenu: 'スピーチ', quitApplication: 'DeepSeek Harness を終了', openApplication: 'DeepSeek Harness を開く', quit: '終了', @@ -606,6 +612,8 @@ export const es = { hideApplication: 'Ocultar DeepSeek Harness', hideOtherApplications: 'Ocultar otros', showAllApplications: 'Mostrar todo', + substitutionsMenu: 'Sustituciones', + speechMenu: 'Voz', quitApplication: 'Salir de DeepSeek Harness', openApplication: 'Abrir DeepSeek Harness', quit: 'Salir', @@ -795,6 +803,8 @@ export const fr = { hideApplication: 'Masquer DeepSeek Harness', hideOtherApplications: 'Masquer les autres', showAllApplications: 'Afficher tout', + substitutionsMenu: 'Substitutions', + speechMenu: 'Parole', quitApplication: 'Quitter DeepSeek Harness', openApplication: 'Ouvrir DeepSeek Harness', quit: 'Quitter', @@ -984,6 +994,8 @@ export const de = { hideApplication: 'DeepSeek Harness ausblenden', hideOtherApplications: 'Andere ausblenden', showAllApplications: 'Alle einblenden', + substitutionsMenu: 'Ersetzungen', + speechMenu: 'Sprachausgabe', quitApplication: 'DeepSeek Harness beenden', openApplication: 'DeepSeek Harness öffnen', quit: 'Beenden', @@ -1173,6 +1185,8 @@ export const ru = { hideApplication: 'Скрыть DeepSeek Harness', hideOtherApplications: 'Скрыть других', showAllApplications: 'Показать все', + substitutionsMenu: 'Замены', + speechMenu: 'Речь', quitApplication: 'Выйти из DeepSeek Harness', openApplication: 'Открыть DeepSeek Harness', quit: 'Выйти', @@ -1362,6 +1376,8 @@ export const pt = { hideApplication: 'Ocultar DeepSeek Harness', hideOtherApplications: 'Ocultar outros', showAllApplications: 'Mostrar tudo', + substitutionsMenu: 'Substituições', + speechMenu: 'Fala', quitApplication: 'Sair de DeepSeek Harness', openApplication: 'Abra DeepSeek Harness', quit: 'Sair', diff --git a/apps/desktop/src/main.ts b/apps/desktop/src/main.ts index 1a2488fe9d..dd3141228b 100644 --- a/apps/desktop/src/main.ts +++ b/apps/desktop/src/main.ts @@ -37,6 +37,7 @@ import { DesktopBackendController } from './backend-controller.ts' import { DESKTOP_IPC, SCHEME, assertDesktopSender, type DesktopUpdateState } from './ipc.ts' import { readDeviceInfo } from './device-info.ts' import { desktopUpdateReadyConfirmation, formatDesktopMessage, resolveDesktopLocale, resolveDesktopStartupLocale } from './locale.ts' +import type { DesktopMessages } from './locale.ts' import { claimDesktopSingleInstance } from './single-instance.ts' import { desktopUpdateChannel } from './update-channel.ts' import { DesktopUpdateCoordinator } from './update-coordinator.ts' @@ -1141,8 +1142,31 @@ async function main(): Promise { // its standard menus and application hide commands declared explicitly. // Keep app.name stable: Electron derives its default userData directory from it. const darwin = process.platform === 'darwin' + // A copy of Electron 44's macOS Edit menu that binds Paste and Match Style to Shift+Command+V + // (#7782) and keeps Electron's Option+Shift+Command+V as a hidden alias. + const macEditMenu = (messages: DesktopMessages): MenuItemConstructorOptions => ({ role: 'editMenu', submenu: [ + { role: 'undo' }, + { role: 'redo' }, + { type: 'separator' }, + { role: 'cut' }, + { role: 'copy' }, + { role: 'paste' }, + { role: 'pasteAndMatchStyle', accelerator: 'Shift+Command+V' }, + { role: 'pasteAndMatchStyle', accelerator: 'Option+Shift+Command+V', visible: false, acceleratorWorksWhenHidden: true }, + { role: 'delete' }, + { role: 'selectAll' }, + { type: 'separator' }, + { label: messages.substitutionsMenu, submenu: [ + { role: 'showSubstitutions' }, + { type: 'separator' }, + { role: 'toggleSmartQuotes' }, + { role: 'toggleSmartDashes' }, + { role: 'toggleTextReplacement' }, + ] }, + { label: messages.speechMenu, submenu: [{ role: 'startSpeaking' }, { role: 'stopSpeaking' }] }, + ] }) const platformMenus = (): MenuItemConstructorOptions[] => darwin - ? [shortcuts.fileMenu(currentDesktopLocale().messages), { role: 'editMenu' }, { role: 'windowMenu' }] + ? [shortcuts.fileMenu(currentDesktopLocale().messages), macEditMenu(currentDesktopLocale().messages), { role: 'windowMenu' }] : [{ role: 'editMenu' }] const hideCommands: MenuItemConstructorOptions[] = darwin ? [{ role: 'hide', label: currentDesktopLocale().messages.hideApplication }, diff --git a/apps/desktop/tests/desktop-publication-failure.spec.ts b/apps/desktop/tests/desktop-publication-failure.spec.ts index 80daeab539..d557c28e98 100644 --- a/apps/desktop/tests/desktop-publication-failure.spec.ts +++ b/apps/desktop/tests/desktop-publication-failure.spec.ts @@ -48,11 +48,11 @@ it('omits malformed provider receipt fields and never copies raw errors into COS it('prints structured archival failure through the real CLI', () => { const result = spawnSync(process.execPath, ['--import', 'tsx/esm', fileURLToPath(new URL('../scripts/archive-desktop-ci.ts', import.meta.url))], { - encoding: 'utf8', timeout: 30_000, env: { ...process.env, RUNNER_NAME: '', DESKTOP_PACKAGE_RUNNER: '' }, + encoding: 'utf8', timeout: 30_000, env: { ...process.env, DESKTOP_ARCHIVE_NAME: '', GITHUB_OUTPUT: '' }, }) expect(result.error).toBeUndefined() expect(result.signal).toBeNull() expect(result.status).toBe(1) expect(JSON.parse(result.stderr)).toEqual({ phase: 'artifact archival', code: 'validation', - message: 'desktop archival: wrong original machine' }) + message: 'desktop archival: invalid ZIP output settings' }) }) diff --git a/apps/desktop/tests/desktop-publish-preflight.spec.ts b/apps/desktop/tests/desktop-publish-preflight.spec.ts index f6c99ae280..755a0ce8a6 100644 --- a/apps/desktop/tests/desktop-publish-preflight.spec.ts +++ b/apps/desktop/tests/desktop-publish-preflight.spec.ts @@ -4,6 +4,8 @@ import { preflightDesktopPublish } from '../scripts/preflight-desktop-publish.mj it.each([ ['macos-x64-unnotarized-debug-1.0.0-42-2', '跳过了公证'], ['macos-arm64-unnotarized-debug-1.0.0-42-2', '跳过了公证'], + ['macos-arm64-unnotarized-debug-1.0.0-42-2.zip', '跳过了公证'], + ['windows-x64-unsigned-1.0.0-42-2.zip', '未签名'], ['windows-x64-unsigned-1.0.0-42-2', '未签名'], ])('rejects %s from paginated artifact metadata with rebuilding instructions', (name, reason) => { const paths: string[] = [] diff --git a/apps/desktop/tests/main-startup.spec.ts b/apps/desktop/tests/main-startup.spec.ts index cf3fd803c0..5a07c2d688 100644 --- a/apps/desktop/tests/main-startup.spec.ts +++ b/apps/desktop/tests/main-startup.spec.ts @@ -1328,7 +1328,7 @@ describe('desktop main startup', () => { await edit }) - it.each(['darwin', 'linux'] as const)('adds the product File menu and standard window commands only on macOS (%s)', async (platform) => { + it.each(['darwin', 'linux'] as const)('declares the platform application menus, with the product File, Edit, and Window menus on macOS (%s)', async (platform) => { vi.spyOn(process, 'platform', 'get').mockReturnValue(platform) await import('../src/main.ts') await harness.preparing.promise @@ -1341,6 +1341,17 @@ describe('desktop main startup', () => { expect(template.map(describeItem)).toEqual(platform === 'darwin' ? ['Desktop test', en.fileMenu, 'editMenu', 'windowMenu'] : ['Application', 'editMenu']) + const describeEdit = (items: MenuItemConstructorOptions[]): unknown[] => items.map(item => Array.isArray(item.submenu) + ? [describeItem(item), describeEdit(item.submenu)] + : [describeItem(item), item.accelerator, item.visible, item.acceleratorWorksWhenHidden].filter(value => value !== undefined)) + const edit = template.find(item => item.role === 'editMenu')!.submenu as MenuItemConstructorOptions[] | undefined + expect(edit === undefined ? undefined : describeEdit(edit)).toEqual(platform === 'darwin' + ? [['undo'], ['redo'], ['separator'], ['cut'], ['copy'], ['paste'], + ['pasteAndMatchStyle', 'Shift+Command+V'], ['pasteAndMatchStyle', 'Option+Shift+Command+V', false, true], + ['delete'], ['selectAll'], ['separator'], + [en.substitutionsMenu, [['showSubstitutions'], ['separator'], ['toggleSmartQuotes'], ['toggleSmartDashes'], ['toggleTextReplacement']]], + [en.speechMenu, [['startSpeaking'], ['stopSpeaking']]]] + : undefined) const application = template[0]!.submenu as MenuItemConstructorOptions[] expect(application.filter(item => item.visible !== false).map(describeItem)).toEqual(platform === 'darwin' ? ['about', 'separator', en.checkUpdatesMenu, en.cliCommandMenu, 'separator', 'toggleDevTools', 'separator', 'hide', 'hideOthers', 'unhide', 'separator', 'quit'] diff --git a/apps/desktop/tests/retain-desktop-ci.spec.ts b/apps/desktop/tests/retain-desktop-ci.spec.ts index cc26e3a2d6..fdddcdf451 100644 --- a/apps/desktop/tests/retain-desktop-ci.spec.ts +++ b/apps/desktop/tests/retain-desktop-ci.spec.ts @@ -1,6 +1,8 @@ -import { mkdtemp, mkdir, readFile, rm, writeFile } from 'node:fs/promises' +import { execFileSync, spawnSync } from 'node:child_process' +import { mkdtemp, mkdir, readFile, rm, utimes, writeFile } from 'node:fs/promises' import { tmpdir } from 'node:os' import { join } from 'node:path' +import { unzipSync } from 'fflate' import { afterEach, expect, it } from 'vitest' import { desktopReleasesRoot, retainDesktopCi, resolveDesktopRetentionRunner } from '../scripts/retain-desktop-ci.ts' import { verifyRetainedDesktopRelease } from '../scripts/desktop-release-store.ts' @@ -10,9 +12,7 @@ import { prepareDesktopPublication } from '../scripts/publish-desktop-ci.ts' const roots: string[] = [] afterEach(async () => { await Promise.all(roots.splice(0).map(root => rm(root, { recursive: true, force: true }))) }) -it.each([ - ['mac-arm64', 'notarized'], ['mac-x64', 'notarized'], ['mac-x64', 'unnotarized'], ['win-x64', 'signed'], ['mac-arm64', 'unnotarized'], ['win-x64', 'unsigned'], -] as const)('retains the complete %s %s release without signing or upload credentials', async (target, qualification) => { +async function retainedFixture(target: 'win-x64' | 'mac-x64' | 'mac-arm64', qualification: 'unsigned' | 'signed' | 'notarized' | 'unnotarized') { const root = await mkdtemp(join(tmpdir(), 'retain-ci-')) roots.push(root) const appRoot = join(root, 'checkout') @@ -29,7 +29,7 @@ it.each([ : [`deepseek-harness-1.0.0-${target}.dmg`, `deepseek-harness-1.0.0-${target}.zip`, `deepseek-harness-1.0.0-${target}.zip.blockmap`, `${target}-release.json`, 'nightly-mac.yml'] await Promise.all(names.map(name => writeFile(join(artifacts, name), 'fixture'))) const env = { - DSH_PACKAGING_CONFIG_DIR: config, DSH_PACKAGING_PRESET: 'test', DSH_DESKTOP_TARGET_PLATFORM: target === 'win-x64' ? 'win32' : 'darwin', + DSH_DESKTOP_RELEASES_DIR: '', DSH_PACKAGING_CONFIG_DIR: config, DSH_PACKAGING_PRESET: 'test', DSH_DESKTOP_TARGET_PLATFORM: target === 'win-x64' ? 'win32' : 'darwin', DSH_DESKTOP_TARGET_ARCH: target === 'mac-arm64' ? 'arm64' : 'x64', PACKAGE_SOURCE_REF: 'master', PACKAGE_SOURCE_SHA: 'b'.repeat(40), PACKAGE_VERSION: '1.0.0', PACKAGE_SIGNING: qualification === 'unsigned' ? 'unsigned' : 'signed', PACKAGE_SKIP_NOTARIZATION: qualification === 'unnotarized' ? 'true' : 'false', GITHUB_RUN_ID: '123', GITHUB_RUN_ATTEMPT: '2', GITHUB_STEP_SUMMARY: join(root, 'summary.md'), @@ -39,6 +39,66 @@ it.each([ const directory = await retainDesktopCi(env, appRoot) const archiveEnv = { ...env, GITHUB_RUN_ATTEMPT: '3', DESKTOP_RETAINED_DIRECTORY: directory, DESKTOP_PACKAGE_ATTEMPT: '2', DESKTOP_PACKAGE_RUNNER: env.RUNNER_NAME } + return { root, debug, names, env, directory, archiveEnv } +} + +const archiveScript = join(import.meta.dirname, '../scripts/archive-desktop-ci.ts') + +it.runIf(process.platform === 'darwin' || process.platform === 'win32')('stores installer bytes with local DOS and absolute Unix modification times', async () => { + const { root, directory, archiveEnv, names } = await retainedFixture('win-x64', 'signed') + const timestamp = Date.UTC(2026, 9, 23, 8, 2, 43) / 1000 + await utimes(join(directory, 'manifest.json'), timestamp, timestamp) + const output = join(root, 'archive-output') + execFileSync(process.execPath, ['--import', 'tsx', archiveScript], { + env: { ...process.env, ...archiveEnv, TZ: 'TST-3', DESKTOP_ARCHIVE_NAME: 'fixture.zip', GITHUB_OUTPUT: output, RUNNER_TEMP: root }, + }) + const path = (await readFile(output, 'utf8')).trim().slice('path='.length) + const bytes = await readFile(path) + const entries = unzipSync(bytes) + expect(Object.keys(entries)).toEqual(['manifest.json', ...names]) + for (const [name, content] of Object.entries(entries)) expect(Buffer.from(content)).toEqual(await readFile(join(directory, name))) + // UTC+3 is 11:02:43 on every test host. + const directoryOffset = bytes.readUInt32LE(bytes.length - 22 + 16) + expect(bytes.readUInt32LE(directoryOffset)).toBe(0x02014b50) + const nameLength = bytes.readUInt16LE(directoryOffset + 28) + expect(bytes.subarray(directoryOffset + 46, directoryOffset + 46 + nameLength).toString('utf8')).toBe('manifest.json') + expect(bytes.readUInt16LE(directoryOffset + 10)).toBe(0) + const dosTime = bytes.readUInt16LE(directoryOffset + 12) + expect([dosTime >>> 11, (dosTime >>> 5) & 63, (dosTime & 31) * 2]).toEqual([11, 2, 42]) + const start = directoryOffset + 46 + nameLength + const end = start + bytes.readUInt16LE(directoryOffset + 30) + let unixTime: number | undefined + for (let offset = start; offset < end; offset += 4 + bytes.readUInt16LE(offset + 2)) { + if (bytes.readUInt16LE(offset) === 0x5455 && (bytes[offset + 4]! & 1)) unixTime = bytes.readUInt32LE(offset + 5) + } + expect(unixTime).toBe(timestamp) +}) + +it.runIf(process.platform === 'darwin' || process.platform === 'win32')('reports a ZIP creation failure without emitting an upload path', async () => { + const { root, archiveEnv } = await retainedFixture('win-x64', 'signed') + const output = join(root, 'archive-output') + const result = spawnSync(process.execPath, ['--import', 'tsx', archiveScript], { encoding: 'utf8', + env: { ...process.env, ...archiveEnv, RUNNER_TEMP: root, GITHUB_OUTPUT: output, DESKTOP_ARCHIVE_NAME: 'a'.repeat(256) + '.zip' } }) + expect(result.status).toBe(1) + expect(result.stderr).toContain('desktop archival: ZIP creation failed') + await expect(readFile(output)).rejects.toMatchObject({ code: 'ENOENT' }) +}) + +it.each(['../escape.zip', '-option.zip', 'missing-extension', 'missing-output'])('rejects invalid archive settings %s without emitting an upload path', async (name) => { + const { root, archiveEnv } = await retainedFixture('win-x64', 'signed') + const output = join(root, 'archive-output') + const result = spawnSync(process.execPath, ['--import', 'tsx', archiveScript], { encoding: 'utf8', + env: { ...process.env, ...archiveEnv, RUNNER_TEMP: root, GITHUB_OUTPUT: name === 'missing-output' ? '' : output, + DESKTOP_ARCHIVE_NAME: name === 'missing-output' ? 'fixture.zip' : name, RUNNER_NAME: 'wrong-machine' } }) + expect(result.status).toBe(1) + expect(result.stderr).toContain('desktop archival: invalid ZIP output settings') + await expect(readFile(output)).rejects.toMatchObject({ code: 'ENOENT' }) +}) + +it.each([ + ['mac-arm64', 'notarized'], ['mac-x64', 'notarized'], ['mac-x64', 'unnotarized'], ['win-x64', 'signed'], ['mac-arm64', 'unnotarized'], ['win-x64', 'unsigned'], +] as const)('retains the complete %s %s release without signing or upload credentials', async (target, qualification) => { + const { debug, names, env, archiveEnv } = await retainedFixture(target, qualification) await verifyDesktopArchive(archiveEnv) await expect(verifyDesktopArchive({ ...archiveEnv, RUNNER_NAME: 'other' })).rejects.toThrow('wrong original machine') await expect(verifyDesktopArchive({ ...archiveEnv, DESKTOP_PACKAGE_ATTEMPT: '3' })).rejects.toThrow('original build') diff --git a/apps/web/tests/agent-team-panel.e2e.ts b/apps/web/tests/agent-team-panel.e2e.ts index 6da971cf03..a68c1908a7 100644 --- a/apps/web/tests/agent-team-panel.e2e.ts +++ b/apps/web/tests/agent-team-panel.e2e.ts @@ -420,7 +420,7 @@ describe('web e2e: agent teamwork panel', () => { taskId: task.id, expectedRevision: task.revision, action: 'claim', }) await row.getByRole('img', { name: 'In progress', exact: true }).waitFor() - await row.locator('[data-team-task-owner]').filter({ hasText: agent.id }).waitFor() + await row.locator('[data-team-task-owner]').filter({ hasText: 'Owner: lead' }).waitFor() await action.getByRole('heading', { name: 'Shared tasks 1 in progress', exact: true }).waitFor() expect(await action.getByRole('button', { name: /^(New task|Edit|Complete|Reopen|Delete)$/u }).count()).toBe(0) expect(await action.locator('input, select, textarea').count()).toBe(0) @@ -762,7 +762,7 @@ describe('web e2e: agent teamwork panel', () => { expect(await row.getAttribute('data-expanded')).toBe('false') expect(await row.locator('[data-team-task-details]').count()).toBe(0) expect(await board.locator('[data-team-task-details]').count()).toBe(1) - expect(await emptyRow.locator('[data-team-task-owner]').textContent()).toBe(`Owner: ${agent.id}`) + expect(await emptyRow.locator('[data-team-task-owner]').textContent()).toBe('Owner: lead') expect(await emptyRow.locator('[data-team-task-details] p:not([data-team-task-owner])').textContent()).toBe(completed.description) expect(await emptyRow.locator('dl, dt, dd').count()).toBe(0) expect(await emptyRow.locator('[data-team-task-details]').textContent()).not.toContain(completed.id) diff --git a/apps/web/tests/expected/subagent-conversation/navigation-only.expected.md b/apps/web/tests/expected/subagent-conversation/navigation-only.expected.md index 76df6f6c57..3474a2e8dd 100644 --- a/apps/web/tests/expected/subagent-conversation/navigation-only.expected.md +++ b/apps/web/tests/expected/subagent-conversation/navigation-only.expected.md @@ -1,8 +1,8 @@ - dialog "Subagent sessions": - tree "Subagent sessions": - - treeitem "event-sourcing researcher {{uuid}} · continuable · not running 15.7K tok · {{duration}}" [level=1]: + - treeitem "event-sourcing researcher agent-1 · continuable · not running 15.7K tok · {{duration}}" [level=1]: - button "Expand event-sourcing researcher descendants" - - text: event-sourcing researcher {{uuid}} 15.7K tok {{duration}} + - text: event-sourcing researcher agent-1 15.7K tok {{duration}} - treeitem "event-sourcing reviewer recorded-one-shot · one-shot · completed 0 tok · {{duration}}" [level=1]: - text: event-sourcing reviewer recorded-one-shot 0 tok ~6mo 12d - button "Open event-sourcing reviewer in sidebar" diff --git a/apps/web/tests/expected/subagent-result-notice/en.expected.md b/apps/web/tests/expected/subagent-result-notice/en.expected.md index a44d176b78..bd1394eded 100644 --- a/apps/web/tests/expected/subagent-result-notice/en.expected.md +++ b/apps/web/tests/expected/subagent-result-notice/en.expected.md @@ -2,37 +2,37 @@ - text: Subagent run completed - time: {{clock}} - paragraph: This notification triggered this response. -- text: Background subagent notice-result-child finished and will do no further work unless you send it more.Its closing message:## Research result The original child reply stays available. +- text: Background subagent agent-1 finished and will do no further work unless you send it more.Its closing message:## Research result The original child reply stays available. - button "Subagent run stopped {{clock}}" [expanded]: - text: Subagent run stopped - time: {{clock}} - paragraph: This notification triggered this response. -- text: Background subagent notice-result-child was stopped before it finished.Its closing message:## Research result The original child reply stays available. +- text: Background subagent agent-1 was stopped before it finished.Its closing message:## Research result The original child reply stays available. - button "Subagent run failed {{clock}}" [expanded]: - text: Subagent run failed - time: {{clock}} - paragraph: This notification triggered this response. -- text: Background subagent notice-result-child failed before it finished.Its closing message:## Research result The original child reply stays available. +- text: Background subagent agent-1 failed before it finished.Its closing message:## Research result The original child reply stays available. - button "Subagent reached the token limit {{clock}}" [expanded]: - text: Subagent reached the token limit - time: {{clock}} - paragraph: This notification triggered this response. -- text: Background subagent notice-result-child ran out of room before it finished.Its closing message:## Research result The original child reply stays available. +- text: Background subagent agent-1 ran out of room before it finished.Its closing message:## Research result The original child reply stays available. - button "Subagent declined the task {{clock}}" [expanded]: - text: Subagent declined the task - time: {{clock}} - paragraph: This notification triggered this response. -- text: Background subagent notice-result-child declined the task.Its closing message:## Research result The original child reply stays available. +- text: Background subagent agent-1 declined the task.Its closing message:## Research result The original child reply stays available. - button "Subagent run completed {{clock}}" [expanded]: - text: Subagent run completed - time: {{clock}} - paragraph: This notification triggered this response. -- text: Background subagent notice-result-child finished and will do no further work unless you send it more.It left no closing message. +- text: Background subagent agent-1 finished and will do no further work unless you send it more.It left no closing message. - button "Subtask status updated {{clock}}" [expanded]: - text: Subtask status updated diff --git a/apps/web/tests/expected/subagent-result-notice/zh.expected.md b/apps/web/tests/expected/subagent-result-notice/zh.expected.md index d26df1f590..a6e893576a 100644 --- a/apps/web/tests/expected/subagent-result-notice/zh.expected.md +++ b/apps/web/tests/expected/subagent-result-notice/zh.expected.md @@ -2,37 +2,37 @@ - text: 子智能体已完成任务 - time: {{clock}} - paragraph: 这条通知触发了本轮回复。 -- text: Background subagent notice-result-child finished and will do no further work unless you send it more.Its closing message:## Research result The original child reply stays available. +- text: Background subagent agent-1 finished and will do no further work unless you send it more.Its closing message:## Research result The original child reply stays available. - button "子智能体任务已停止 {{clock}}" [expanded]: - text: 子智能体任务已停止 - time: {{clock}} - paragraph: 这条通知触发了本轮回复。 -- text: Background subagent notice-result-child was stopped before it finished.Its closing message:## Research result The original child reply stays available. +- text: Background subagent agent-1 was stopped before it finished.Its closing message:## Research result The original child reply stays available. - button "子智能体执行失败 {{clock}}" [expanded]: - text: 子智能体执行失败 - time: {{clock}} - paragraph: 这条通知触发了本轮回复。 -- text: Background subagent notice-result-child failed before it finished.Its closing message:## Research result The original child reply stays available. +- text: Background subagent agent-1 failed before it finished.Its closing message:## Research result The original child reply stays available. - button "子智能体已达 token 上限 {{clock}}" [expanded]: - text: 子智能体已达 token 上限 - time: {{clock}} - paragraph: 这条通知触发了本轮回复。 -- text: Background subagent notice-result-child ran out of room before it finished.Its closing message:## Research result The original child reply stays available. +- text: Background subagent agent-1 ran out of room before it finished.Its closing message:## Research result The original child reply stays available. - button "子智能体拒绝执行 {{clock}}" [expanded]: - text: 子智能体拒绝执行 - time: {{clock}} - paragraph: 这条通知触发了本轮回复。 -- text: Background subagent notice-result-child declined the task.Its closing message:## Research result The original child reply stays available. +- text: Background subagent agent-1 declined the task.Its closing message:## Research result The original child reply stays available. - button "子智能体已完成任务 {{clock}}" [expanded]: - text: 子智能体已完成任务 - time: {{clock}} - paragraph: 这条通知触发了本轮回复。 -- text: Background subagent notice-result-child finished and will do no further work unless you send it more.It left no closing message. +- text: Background subagent agent-1 finished and will do no further work unless you send it more.It left no closing message. - button "子任务状态更新 {{clock}}" [expanded]: - text: 子任务状态更新 diff --git a/apps/web/tests/live-interactions.e2e.ts b/apps/web/tests/live-interactions.e2e.ts index 1eedb317fd..aef7c3c699 100644 --- a/apps/web/tests/live-interactions.e2e.ts +++ b/apps/web/tests/live-interactions.e2e.ts @@ -27,7 +27,7 @@ import { compareOrRefreshGolden, fixtureUserPrompts, launchWebScaffold, recordFixture, watchConsole, webSnapshotMode, type WebScaffold, } from './scaffold.ts' -import { connectFreshWorkspace, newEnglishPage, saveFailureShot } from './support.ts' +import { connectFreshWorkspace, newEnglishPage, saveFailureShot, writeComposerDraft } from './support.ts' const SNAPSHOT_DIR = fileURLToPath(new URL('../../../snapshots/web/live-interactions', import.meta.url)) const FIXTURE = join(SNAPSHOT_DIR, 'session.v3.jsonl') @@ -414,15 +414,16 @@ describe('web e2e: live-turn interactions (cancel / error / retry)', () => { expect(tripwire.warnings).toEqual([]) }, 120_000) - it.skipIf(MODE === 'record')('surfaces the terminal turn error after transient retries exhaust', async () => { + it.skipIf(MODE === 'record')('continues after transient retries exhaust without another user bubble', async () => { // A whole-script replacement: three throw entries cover the first request // plus both budgeted retries (patches cannot reach past the one-call // derived script). The scenario-owned policy keeps exhaustion fast and // jitter-free instead of walking the shared default's five backed-off // attempts. const failure: ReplayEntry = { kind: 'throw', chunks: [], message: 'upstream 503', code: 'SERVER' } + const derived = deriveReplayScript(parseSessionLog(await readFile(FIXTURE, 'utf8'))) await launch( - () => [failure, failure, failure], + () => [failure, failure, failure, ...derived], { mode: 'normal', maxRetries: 2, retryableCodes: ['SERVER'], backoff: { initialDelayMs: 25, maxDelayMs: 50, jitterRatio: 0 } }, ) onTestFailed(() => saveFailureShot(page, 'web-e2e-retry-exhausted')) @@ -443,6 +444,49 @@ describe('web e2e: live-turn interactions (cancel / error / retry)', () => { // context; the golden pins both. const snapshot = await captureStableAria(page, '[class*="centerCol"]', scaffold!.workspaceCwd) await compareOrRefreshGolden(RETRY_EXHAUSTED_EXPECTED, snapshot, MODE) + await page.reload({ waitUntil: 'load' }) + const resume = page.getByRole('button', { name: 'Continue generating', exact: true }) + await resume.waitFor() + const input = page.locator('[data-composer-input]').first() + await writeComposerDraft(page, input, '/plan ') + await input.press('Enter') + const plan = page.getByRole('button', { name: 'Plan mode on, press to turn off', exact: true }) + await plan.waitFor() + await expect.poll(() => input.textContent()).toBe('') + await plan.click() + await plan.waitFor({ state: 'hidden' }) + await resume.waitFor() + expect(await resume.isEnabled()).toBe(true) + expect(turnEndReasons(sessionEvents)).toEqual(['error']) + await writeComposerDraft(page, input, 'A different instruction') + expect(await resume.count()).toBe(0) + expect(await page.getByRole('button', { name: 'Send message', exact: true }).isEnabled()).toBe(true) + await writeComposerDraft(page, input, '') + await resume.waitFor() + await page.setViewportSize({ width: 390, height: 844 }) + // ResizeObserver collapses the model label after the viewport changes. + await expect.poll(async () => { + const bounds = await resume.boundingBox() + return bounds !== null && bounds.x + bounds.width <= 390 + }).toBe(true) + expect(await resume.isEnabled()).toBe(true) + const continued = scaffold!.whenTurnSettled() + await resume.click() + await continued + expect(turnEndReasons(sessionEvents)).toEqual(['error', 'completed']) + expect(sessionEvents.some(event => event.type === 'user/message' && event.data.source.kind === 'plan-mode')).toBe(true) + const userMessages = sessionEvents.flatMap(event => event.type === 'user/message' && event.data.source.kind === 'user' + ? [event.data] : []) + expect(userMessages.map(message => message.content)).toEqual([[{ type: 'text', text: PROMPT }]]) + const retries = sessionEvents.filter(event => event.type === 'user/message' && event.data.source.kind === 'retry') + expect(retries).toHaveLength(1) + expect(retries[0]?.data).toMatchObject({ content: [], source: { kind: 'retry' } }) + expect(sessionEvents.filter(event => event.type === 'turn/start')).toHaveLength(2) + expect(sessionEvents.filter(event => event.type === 'turn/end')).toHaveLength(2) + expect(await resume.count()).toBe(0) + await page.setViewportSize({ width: 1440, height: 900 }) + await compareOrRefreshGolden(join(SNAPSHOT_DIR, 'continued.expected.md'), + await captureStableAria(page, '[class*="centerCol"]', scaffold!.workspaceCwd), MODE) expect(tripwire.pageErrors).toEqual([]) expect(tripwire.warnings).toEqual([]) }, 120_000) @@ -451,7 +495,7 @@ describe('web e2e: live-turn interactions (cancel / error / retry)', () => { await assertFixtureInventory(SNAPSHOT_DIR, [ 'session.v3.jsonl', 'cancel.expected.md', 'cancel-expanded.expected.md', 'loading.expected.md', 'running-draft.expected.md', 'error-auth.expected.md', - 'retry.expected.md', 'retry-expanded.expected.md', 'retry-request.expected.md', 'retry-exhausted.expected.md', + 'retry.expected.md', 'retry-expanded.expected.md', 'retry-request.expected.md', 'retry-exhausted.expected.md', 'continued.expected.md', ]) }) }) diff --git a/apps/web/tests/official-subagent-bundle.e2e.ts b/apps/web/tests/official-subagent-bundle.e2e.ts index ef6268cd42..8dad28b2a1 100644 --- a/apps/web/tests/official-subagent-bundle.e2e.ts +++ b/apps/web/tests/official-subagent-bundle.e2e.ts @@ -141,7 +141,7 @@ describe.skipIf(MODE === 'record')('web snapshot: Official native subagent bundl const firstTurnEvents = agent.session.snapshotEvents() const toolResults = firstTurnEvents.filter(event => event.type === 'tool/result').map(event => event.data) expect(toolResults, `PTC execution must start the native child before waiting for its result: ${JSON.stringify(toolResults)}`) - .toMatchObject([{ message: { isError: false } }]) + .toMatchObject([{ message: { isError: false, content: [{ type: 'text', text: 'agent-1' }] } }]) const dispatches = firstTurnEvents.filter(event => event.type === 'tool/ptc-dispatch').map(event => event.data) expect(dispatches).toMatchObject([{ name: 'subagent_claude_code', isError: false }]) const catalog = firstTurnEvents.filter(event => event.type === 'subagent/catalog').map(event => event.data) @@ -161,7 +161,7 @@ describe.skipIf(MODE === 'record')('web snapshot: Official native subagent bundl if (notice?.data.source.kind !== 'subagent-settled') throw new Error('Native completion was not delivered to the parent') expect(notice.data.source.senderSessionId).toBe(catalog[0]?.childId) expect(notice.data.content).toContainEqual({ type: 'text', text: RESPONSE }) - expect(dispatches[0]?.content).toEqual([{ type: 'text', text: `started subagent ${notice.data.source.senderSessionId}` }]) + expect(dispatches[0]?.content).toEqual([{ type: 'text', text: 'started subagent agent-1' }]) expect(events.filter(event => event.type === 'turn/end')).toHaveLength(2) expect(server.requests).toHaveLength(1) expect(server.requests[0]?.body).toMatchObject({ model: 'fixture-model' }) diff --git a/apps/web/tests/shipped-composition.e2e.ts b/apps/web/tests/shipped-composition.e2e.ts index 1e0ae9dfad..5954bc5e3a 100644 --- a/apps/web/tests/shipped-composition.e2e.ts +++ b/apps/web/tests/shipped-composition.e2e.ts @@ -305,7 +305,7 @@ class ShippedChildAutoAdapter extends LlmAdapter { throw new Error('continuable child id was not observed before parent adjustment') } return toolChunks('parent-adjust', 'send_message', { - agent_id: this.continuableChildId, + agent: this.continuableChildId, message: [ AUTO_CHILD_ADJUSTED, `Replace the earlier no-deletion restriction: permanently delete exactly ${this.continuableDeletePath}.`, diff --git a/apps/web/tests/snapshots/agent-team-panel/task.expected.md b/apps/web/tests/snapshots/agent-team-panel/task.expected.md index 9032c3413b..091b670513 100644 --- a/apps/web/tests/snapshots/agent-team-panel/task.expected.md +++ b/apps/web/tests/snapshots/agent-team-panel/task.expected.md @@ -11,4 +11,4 @@ - img "In progress" - text: Agent task - paragraph: Created by the root agent - - paragraph: "Owner: session-{{uuid}}" + - paragraph: "Owner: lead" diff --git a/apps/web/tests/subagent-conversation.e2e.ts b/apps/web/tests/subagent-conversation.e2e.ts index 2b9cae7b84..9690154afe 100644 --- a/apps/web/tests/subagent-conversation.e2e.ts +++ b/apps/web/tests/subagent-conversation.e2e.ts @@ -39,6 +39,8 @@ const MIGRATING_CHILD_EXPECTED = fileURLToPath(new URL( )) const MODE = webSnapshotMode() const LABEL = 'event-sourcing researcher' +/** The live child's catalog name; it is the parent's first named child. */ +const CHILD_NAME = 'agent-1' const ONE_SHOT_LABEL = 'event-sourcing reviewer' const NESTED_LABEL = 'example editor' const CHILD_TITLE = 'Explain event sourcing in one' @@ -398,7 +400,7 @@ describe('web e2e: persisted subagent conversation and human continuation', () = } }) - it('shows complete descriptions and IDs without hover at desktop and touch widths', async () => { + it('shows complete descriptions and names without hover at desktop and touch widths', async () => { onTestFailed(() => saveFailureShot(page, 'web-e2e-subagent-catalog-labels')) const originalViewport = page.viewportSize()! const originalUrl = page.url() @@ -410,7 +412,7 @@ describe('web e2e: persisted subagent conversation and human continuation', () = const panel = page.locator('[data-subagent-panel]') const row = panel.getByRole('treeitem', { name: new RegExp(LABEL) }) const primary = row.getByText(LABEL, { exact: true }) - const secondary = row.getByText(childId, { exact: true }) + const secondary = row.getByText(CHILD_NAME, { exact: true }) const primaryBounds = await primary.boundingBox() const secondaryBounds = await secondary.boundingBox() expect(primaryBounds).not.toBeNull() @@ -420,7 +422,7 @@ describe('web e2e: persisted subagent conversation and human continuation', () = expect(await label.evaluate(element => element.scrollWidth <= element.clientWidth && element.scrollHeight <= element.clientHeight)).toBe(true) } - expect(await row.getAttribute('aria-label')).toContain(`${LABEL} ${childId} `) + expect(await row.getAttribute('aria-label')).toContain(`${LABEL} ${CHILD_NAME} `) expect(await row.getByRole('button', { name: /description/u }).count()).toBe(0) expect(await row.getByRole('button', { name: `Expand ${LABEL} descendants`, exact: true }).count()).toBe(1) expect(await row.getByRole('button', { name: `Open ${LABEL} in sidebar`, exact: true }).count()).toBe(1) @@ -776,7 +778,7 @@ describe('web e2e: persisted subagent conversation and human continuation', () = .getByRole('treeitem', { name: /Ask a research subagent to/ }) .click() await page.getByRole('button', { name: '2 subagents' }).hover() - await page.getByRole('treeitem', { name: new RegExp(LABEL) }).getByText(childId, { exact: true }).click() + await page.getByRole('treeitem', { name: new RegExp(LABEL) }).getByText(CHILD_NAME, { exact: true }).click() await page.getByRole('textbox', { name: 'Message or run a task, / commands, @ files or sessions' }).waitFor() const forkResponse = page.waitForResponse(response => new URL(response.url()).pathname === '/api/session/fork') @@ -805,7 +807,7 @@ describe('web e2e: persisted subagent conversation and human continuation', () = const sessions = page.getByRole('tree', { name: 'Sessions' }) await sessions.getByRole('treeitem', { name: /Ask a research subagent to/ }).click() await page.getByRole('button', { name: '2 subagents' }).hover() - await page.getByRole('treeitem', { name: new RegExp(LABEL) }).getByText(childId, { exact: true }).click() + await page.getByRole('treeitem', { name: new RegExp(LABEL) }).getByText(CHILD_NAME, { exact: true }).click() await page.locator('[data-composer-input][contenteditable="true"]').first().waitFor() expect(scaffold.ctx.agents.get(childId)).toBeUndefined() @@ -822,7 +824,7 @@ describe('web e2e: persisted subagent conversation and human continuation', () = await sessions.getByRole('treeitem', { name: /Ask a research subagent to/ }).click() await page.getByRole('button', { name: '2 subagents' }).press('ArrowDown') - await page.getByRole('treeitem', { name: new RegExp(LABEL) }).getByText(childId, { exact: true }).click() + await page.getByRole('treeitem', { name: new RegExp(LABEL) }).getByText(CHILD_NAME, { exact: true }).click() const input = page.locator('[data-composer-input][contenteditable="true"]').first() await input.waitFor() const promptResponse = page.waitForResponse(response => @@ -868,7 +870,7 @@ describe('web e2e: persisted subagent conversation and human continuation', () = await page.getByRole('button', { name: `Expand ${LABEL} descendants`, exact: true }).click() await page.getByRole('treeitem', { name: new RegExp(NESTED_LABEL) }).waitFor() expect(await rootHeader.textContent()).toBe(progress) - await page.getByRole('treeitem', { name: new RegExp(LABEL) }).getByText(childId, { exact: true }).click() + await page.getByRole('treeitem', { name: new RegExp(LABEL) }).getByText(CHILD_NAME, { exact: true }).click() const switcher = page.getByRole('button', { name: `Switch subagent: ${LABEL}`, exact: true }) await switcher.click() const panel = page.locator('[data-subagent-panel]') diff --git a/apps/web/tests/subagent-result-notice.e2e.ts b/apps/web/tests/subagent-result-notice.e2e.ts index cff9482035..cb8525f617 100644 --- a/apps/web/tests/subagent-result-notice.e2e.ts +++ b/apps/web/tests/subagent-result-notice.e2e.ts @@ -63,13 +63,13 @@ describe.skipIf(MODE === 'record')('web e2e: subagent result notices', () => { const childId = SessionId('notice-result-child') const notices: { title: string; message: ReturnType }[] = OUTCOMES.map(outcome => ({ title: outcome[locale], - message: createSettlementMessage(childId, { + message: createSettlementMessage(childId, 'agent-1', { stopReason: outcome.reason, output: [{ type: 'text', text: OUTPUT }], }), })) notices.push({ title: OUTCOMES[0][locale], - message: createSettlementMessage(childId, { stopReason: 'completed', output: [] }), + message: createSettlementMessage(childId, 'agent-1', { stopReason: 'completed', output: [] }), }) notices.push({ title: locale === 'en' ? 'Subtask status updated' : '子任务状态更新', diff --git a/docs/config-catalog.md b/docs/config-catalog.md index 6d42bc33a7..541f35bf98 100644 --- a/docs/config-catalog.md +++ b/docs/config-catalog.md @@ -177,7 +177,7 @@ export interface Config { ## `@deepseek-ai/dsh-agent-team` - `inject`: `agents` · `sessions` · `sessionPersistence` · `sessionProjections` · `subagents` -- `source`: [`packages/team/agent-team/src/types.ts:132`](../packages/team/agent-team/src/types.ts) +- `source`: [`packages/team/agent-team/src/types.ts:136`](../packages/team/agent-team/src/types.ts) ```ts config-catalog /** Team-service defaults and deployment limits. */ @@ -1231,7 +1231,7 @@ export interface InspectorOptions { readonly maxJournalBytes?: number /** Maximum active and completed fetch requests retained by the Worker. */ readonly maxRetainedRequests?: number - /** Maximum encoded bytes accepted in one source transport frame. */ + /** Maximum encoded bytes accepted in one source transport frame; values below 5121 leave no Cordis snapshot budget and fail. */ readonly maxSourceFrameBytes?: number /** Maximum observation records accepted in one source batch. */ readonly maxSourceRecordsPerFrame?: number @@ -2239,7 +2239,7 @@ export type PiAiThinkingTokenBudgetField = NonNullable @@ -1015,7 +1015,7 @@ Source: [`packages/core/session/src/types.ts:338`](../packages/core/session/src/ Types: [TeamId](subsystems/agent-team.md) · [TeamMemberSnapshot](subsystems/agent-team.md) -Source: [`packages/team/agent-team/src/types.ts:175`](../packages/team/agent-team/src/types.ts) +Source: [`packages/team/agent-team/src/types.ts:179`](../packages/team/agent-team/src/types.ts) @@ -1033,7 +1033,7 @@ Source: [`packages/team/agent-team/src/types.ts:175`](../packages/team/agent-tea Types: [TeamId](subsystems/agent-team.md) · [TeamMessageId](subsystems/agent-team.md) -Source: [`packages/team/agent-team/src/types.ts:181`](../packages/team/agent-team/src/types.ts) +Source: [`packages/team/agent-team/src/types.ts:185`](../packages/team/agent-team/src/types.ts) @@ -1046,7 +1046,7 @@ Source: [`packages/team/agent-team/src/types.ts:181`](../packages/team/agent-tea Types: [TeamId](subsystems/agent-team.md) · [TeamMessageSnapshot](subsystems/agent-team.md) -Source: [`packages/team/agent-team/src/types.ts:179`](../packages/team/agent-team/src/types.ts) +Source: [`packages/team/agent-team/src/types.ts:183`](../packages/team/agent-team/src/types.ts) @@ -1057,7 +1057,7 @@ Source: [`packages/team/agent-team/src/types.ts:179`](../packages/team/agent-tea 'team/mode': { enabled: boolean } ``` -Source: [`packages/team/agent-team/src/types.ts:173`](../packages/team/agent-team/src/types.ts) +Source: [`packages/team/agent-team/src/types.ts:177`](../packages/team/agent-team/src/types.ts) @@ -1070,7 +1070,7 @@ Source: [`packages/team/agent-team/src/types.ts:173`](../packages/team/agent-tea Types: [TeamId](subsystems/agent-team.md) · [TeamTaskSnapshot](subsystems/agent-team.md) -Source: [`packages/team/agent-team/src/types.ts:177`](../packages/team/agent-team/src/types.ts) +Source: [`packages/team/agent-team/src/types.ts:181`](../packages/team/agent-team/src/types.ts) ### `todo/*` @@ -2446,6 +2446,14 @@ SHA-256: `34d1ab5c5df378186d6054b1a1beea9a41e41965d6f336f0bc0025c441a82e66` `"resume"` + + +### `"retry"` + +SHA-256: `63ba8895cc09e4693cf0819fdcd18c084bef195febda5b6a23af279b3852be36` + +`"retry"` + ### `"runtime-context"` @@ -3102,6 +3110,14 @@ SHA-256: `a0f906856fc06f1c6f2083eb970e5a657a82b1a84c06c095445e5d6d161cda80` `2` + + +### `3` + +SHA-256: `137ac60e26bcb192210d9a32a704b73b0924ed34019323defa1b787be95bd45e` + +`3` + ### `4` @@ -3410,7 +3426,7 @@ Sources: [`packages/web/web-search-deepseek/src/provider.ts:55`](../packages/web | `body` | required | [`{ max_tokens, messages, model, thinking?, … }`](#persistence-type-sha256-9c001ecb5e1d3c3894410db2a1e383842e5f8454fb52182338686158abc1b3ee) | | `endpoint` | required | `string` | - + @@ -3418,7 +3434,7 @@ Sources: [`packages/web/web-search-deepseek/src/provider.ts:55`](../packages/web ### `DeveloperMessage` -SHA-256: `01c161379a3c3394a642807843e108ef911a8b7dbffd6d7de43f4484c88b0796` +SHA-256: `824b1d4d4f007bdaa5eee7994a5db3ede7707c6cd2bf8e2509be176c7609e3bc` Sources: [`packages/llm/llm/src/message.ts:157`](../packages/llm/llm/src/message.ts) @@ -3427,7 +3443,7 @@ Sources: [`packages/llm/llm/src/message.ts:157`](../packages/llm/llm/src/message | `content` | required | [`ContentBlock[]`](#persistence-type-sha256-b52f215a6cd691058a3413c12f161fa3b563a2f4895adb3df6f744ec4b0a6ef1) | | `id` | required | `string` | | `role` | required | `"developer"` | -| `source` | required | [`MessageSource`](#persistence-type-sha256-b120362fd216a16a40fe787f6d3286086aa131266322bab79c026a130ccd0f72) | +| `source` | required | [`MessageSource`](#persistence-type-sha256-dca3ba43188095fa7342e49e6c206d4685125497d4767595bf12a62ea2fd73ce) | Source compatibility: `source` — `session-source-attribution` v1; `session.developer-message.source`; `kind`; `preserve`. @@ -4126,7 +4142,7 @@ Sources: [`packages/llm/llm-retry/src/types.ts:43`](../packages/llm/llm-retry/sr | `step` | required | `number` | | `turn` | required | `number` | - + @@ -4134,15 +4150,15 @@ Sources: [`packages/llm/llm-retry/src/types.ts:43`](../packages/llm/llm-retry/sr ### `Message` -SHA-256: `e272493e3ea0b33b2e1d64b6a80e9d8bd3d1d466cc115f2facbdd598f8644a39` +SHA-256: `c51f0d0a405bb96fcb008c0dc560a512dcd8c3919b6b446937f449ea2f7d21d8` Sources: [`packages/llm/llm/src/message.ts:196`](../packages/llm/llm/src/message.ts) One of: - [`ToolResultMessage`](#persistence-type-sha256-4b259f7f8f0a44ad5e90b70a73553ced1df27012d126921d397ff403b6c86731) -- [`DeveloperMessage`](#persistence-type-sha256-01c161379a3c3394a642807843e108ef911a8b7dbffd6d7de43f4484c88b0796) -- [`UserMessage`](#persistence-type-sha256-613660455704fb82a825b5b766e000aa64b5b4d44b4f10e55cffe968d4ec6ab1) +- [`DeveloperMessage`](#persistence-type-sha256-824b1d4d4f007bdaa5eee7994a5db3ede7707c6cd2bf8e2509be176c7609e3bc) +- [`UserMessage`](#persistence-type-sha256-74e0e5885d2ddf04530ddf341b25cd65e1f85c00b30a88bd992f11fc06615a0c) - [`SystemMessage`](#persistence-type-sha256-09f3f8dc417f278257202714132f98ba7b52957d7b558c4a04456603890eb363) - [`AssistantMessage`](#persistence-type-sha256-fa87537f4a9c1e25602990a8bf686b383e9e00352ec8946e16ae24ba7c1625be) @@ -4219,7 +4235,7 @@ One of: - `"negative"` - `"positive"` - + @@ -4227,7 +4243,7 @@ One of: ### `MessageSource` -SHA-256: `b120362fd216a16a40fe787f6d3286086aa131266322bab79c026a130ccd0f72` +SHA-256: `dca3ba43188095fa7342e49e6c206d4685125497d4767595bf12a62ea2fd73ce` Sources: [`packages/llm/llm/src/message.ts:136`](../packages/llm/llm/src/message.ts) @@ -4289,6 +4305,7 @@ Sources: [`packages/llm/llm/src/message.ts:136`](../packages/llm/llm/src/message | `repeat-tool-reminder` | `"relay"` | none | [`{ kind: "repeat-tool-reminder", form: "relay" }`](#persistence-type-sha256-4991dfc415c9efebc36fa6969e1798c7d2e42396cc1e6e0ac7d7c89c5c5c4aea) | | `repeat-tool-reminder` | `"snapshot"` | `sections`: [`ContextSnapshotSection[]`](#persistence-type-sha256-c748fb42c80a120038a8c587af80ec39924803c401364db11c8974d5bf6d0262) | [`{ kind: "repeat-tool-reminder", form: "snapshot" }`](#persistence-type-sha256-db06ef35b27a38425046b2228fa6bce9582abe140d781d363137eb2f4d233a1c) | | `repeat-tool-reminder` | not declared | none | [`{ kind: "repeat-tool-reminder" }`](#persistence-type-sha256-b062078e899958f99ae464514578b8c093924dfe34bd9a835932b420ff2150b1) | +| `retry` | not declared | `rpcId`: `string` | [`{ kind: "retry" }`](#persistence-type-sha256-8f1062573ea9184129dfdec43df1e8136eb5808746fd809bf6b539f3fd11362e) | | `runtime-context` | `"catalog"` | none | [`{ kind: "runtime-context", form: "catalog" }`](#persistence-type-sha256-58015da1c1950a66daf66ae24913d6a1fc6d1d9ac441b155f8847f7f8584ba8e) | | `runtime-context` | `"instructions"` | none | [`{ kind: "runtime-context", form: "instructions" }`](#persistence-type-sha256-0eeb17e1df89b1ebc2902116fe7145e0d321ef0db26e6bdebc802cb8513a01c1) | | `runtime-context` | `"notice"` | `summary`: `string` | [`{ kind: "runtime-context", form: "notice" }`](#persistence-type-sha256-cda2345a9be9d139df49ccbd16dcba716f3440178bf20ff8b801fda1f5eb77dc) | @@ -4352,13 +4369,13 @@ Sources: [`packages/llm/llm/src/message.ts:136`](../packages/llm/llm/src/message | `webhook` | `"notice"` | `deliveryId`: `string`; `provider`: `string`; `ruleId`: `string`; `source`: `string`; `summary`: `string` | [`{ kind: "webhook", form: "notice" }`](#persistence-type-sha256-9edc162949abf93bd5ff049191b345454ba104f583937ce5580fb50f067d2b94) | | `working-directory` | not declared | none | [`{ kind: "working-directory" }`](#persistence-type-sha256-2235d957bf4b7c6cf959231d480f0ba1f3a6d72d82981493fb6c7c963021d3d5) | - + ### `Message[]` -SHA-256: `95b5cf90ea1f57da3319184d6f5f3811d0f651aa9113591c10e81c3d1e9b9f70` +SHA-256: `42e2ff61928fb7dfaf0f057d61686f3a32ff713da419d12d4f250efc96733fe0` -Array of [`Message`](#persistence-type-sha256-e272493e3ea0b33b2e1d64b6a80e9d8bd3d1d466cc115f2facbdd598f8644a39). +Array of [`Message`](#persistence-type-sha256-c51f0d0a405bb96fcb008c0dc560a512dcd8c3919b6b446937f449ea2f7d21d8). @@ -4726,7 +4743,7 @@ Sources: [`packages/session/session-title/src/types.ts:41`](../packages/session/ | `source` | required | [`SessionTitleSource`](#persistence-type-sha256-30d5a537b296685770b1241c4b4bbde19d5a31ff81aa23df73fab5e90b8fc65f) | | `title` | required | `string` | - + @@ -4734,7 +4751,7 @@ Sources: [`packages/session/session-title/src/types.ts:41`](../packages/session/ ### `SessionTitleLlmRequestEventData` -SHA-256: `601327bedca5f98a0fa4c27133bd35749f3af2baaaacf53badf074e59cea5d25` +SHA-256: `bec5ca3a376f56f3d69df7f12a48e1cc07d4ea8305968773394c8734799faeb4` Sources: [`packages/session/session-title-llm/src/index.ts:43`](../packages/session/session-title-llm/src/index.ts) @@ -4742,7 +4759,7 @@ Sources: [`packages/session/session-title-llm/src/index.ts:43`](../packages/sess |---|---|---| | `maxTokens` | required | `number` | | `messageSeqs` | required | [`number[]`](#persistence-type-sha256-5d03ba38734809bcbd2a55221bd938b3b3fc34b49bb686c6113e9e4931e3aa78) | -| `messages` | required | [`Message[]`](#persistence-type-sha256-95b5cf90ea1f57da3319184d6f5f3811d0f651aa9113591c10e81c3d1e9b9f70) | +| `messages` | required | [`Message[]`](#persistence-type-sha256-42e2ff61928fb7dfaf0f057d61686f3a32ff713da419d12d4f250efc96733fe0) | | `reasoningEffort` | optional | `string` | | `route` | required | [`SessionTitleModelIdentity`](#persistence-type-sha256-07e1a58c58b593f507b8e7f25723bb0aa42baae6e00f5ecfddf28cb1e64d3235) | | `system` | required | `string` | @@ -4873,7 +4890,7 @@ One of: - [`{ type: "finish" }`](#persistence-type-sha256-a2b49331716ba0a7078b026d145306a70eae64b7313c3e6204bd931e75ec3bb1) - [`{ type: "usage" }`](#persistence-type-sha256-f1a96afe7503ac1817de769cd0ba13d9b80111c7034c50106b3344ecc14cc515) - + @@ -4881,18 +4898,20 @@ One of: ### `SubagentCatalogEvent` -SHA-256: `f731ffe80810b0289b3e694d8f40af6f01865c02a622ee457be90ca808b66e87` +SHA-256: `058fc9a6b4fbd5d43437c3a64170002070dfc98e18d87de294b564ae446ca8ae` -Sources: [`packages/subagent/subagent/src/catalog.ts:28`](../packages/subagent/subagent/src/catalog.ts) +Sources: [`packages/subagent/subagent/src/catalog.ts:32`](../packages/subagent/subagent/src/catalog.ts) One of: +- [`{ childCreatedAt, childId, label, mode, … }`](#persistence-type-sha256-8faed5b52ab2d2df40b94a926d0f0faa75280bddcc4b17b6bdd9c8bfed7c34b5) +- [`{ childCreatedAt, childId, label, mode, … }`](#persistence-type-sha256-0e10d7c096b47e61defe372a5fc8bd37d835199410eac44367f95c45082498bd) - [`{ childCreatedAt, childId, label, mode, … }`](#persistence-type-sha256-e2ad8f5bcd813f268ffef1b10a12d7ddd2b8ced8b9b6d0275b3f6b7ed094a187) +- [`{ childCreatedAt, childId, label?, mode, … }`](#persistence-type-sha256-a43327a1739c3fa477f32981071fef7d8ba6ae5f32a84fd70f547b2eee59e93e) - [`{ childCreatedAt, childId, label?, mode, … }`](#persistence-type-sha256-cbbe8377ee744964537dbafd83607219e58ba79a13f6db0d0645c7ad3d5e8a09) - [`{ childCreatedAt, childId, label?, mode, … }`](#persistence-type-sha256-5d542ac7bdf13310c46e1a884dec9fb18ad8c6e153cff207e639cd7bf9d7e694) - [`{ childCreatedAt, childId, label?, mode, … }`](#persistence-type-sha256-b6896938660a1dfe4ddd100fb3164d9f8fa57feeabfe37441a80106c9942697a) - [`{ childCreatedAt, childId, label?, mode, … }`](#persistence-type-sha256-a0f25b5aeeebf2bf1542ce67726b095e3b139a39c71861d57e827f12dea1f499) -- [`{ childCreatedAt, childId, label, mode, … }`](#persistence-type-sha256-0e10d7c096b47e61defe372a5fc8bd37d835199410eac44367f95c45082498bd) @@ -5033,7 +5052,7 @@ Sources: [`packages/team/agent-team/src/types.ts:50`](../packages/team/agent-tea SHA-256: `2eafefdc6f79a4922d68a787a09eaf4dd2b2369c3777fba4c05e800b5678ac8e` -Sources: [`packages/team/agent-team/src/types.ts:108`](../packages/team/agent-team/src/types.ts) +Sources: [`packages/team/agent-team/src/types.ts:112`](../packages/team/agent-team/src/types.ts) | Property | Presence | Type | |---|---|---| @@ -5053,7 +5072,7 @@ Sources: [`packages/team/agent-team/src/types.ts:108`](../packages/team/agent-te SHA-256: `2152caf1a71e588e4df2358a806dea24936c1c47131134f01a12939d12cdc0c0` -Sources: [`packages/team/agent-team/src/types.ts:117`](../packages/team/agent-team/src/types.ts) +Sources: [`packages/team/agent-team/src/types.ts:121`](../packages/team/agent-team/src/types.ts) | Property | Presence | Type | |---|---|---| @@ -5063,7 +5082,7 @@ Sources: [`packages/team/agent-team/src/types.ts:117`](../packages/team/agent-te | `senderName` | required | `string` | | `teamId` | required | `string` | - + @@ -5071,7 +5090,7 @@ Sources: [`packages/team/agent-team/src/types.ts:117`](../packages/team/agent-te ### `TeamTaskSnapshot` -SHA-256: `51edec100659da3a9bd9c3f6ba1180f5e64ec9a1585e5057080df45c180bd357` +SHA-256: `4018a00144474b6c60dc1aa6e5c1f03611c66bd739833779a7d20a511df6d082` Sources: [`packages/team/agent-team/src/types.ts:64`](../packages/team/agent-team/src/types.ts) @@ -5081,6 +5100,7 @@ Sources: [`packages/team/agent-team/src/types.ts:64`](../packages/team/agent-tea | `description` | required | `string` | | `id` | required | `string` | | `ownerId` | optional | `string` | +| `ownerName` | optional | `string` | | `revision` | required | `number` | | `status` | required | [`TeamTaskStatus`](#persistence-type-sha256-b2d2a01e51341a3bfec809198952c8c830a7899f4cb6ecd3c1dc0b5d9a2af943) | | `subject` | required | `string` | @@ -5418,7 +5438,7 @@ Sources: [`packages/core/session/src/types.ts:238`](../packages/core/session/src | `interrupted` | not declared | none | [`{ kind: "interrupted" }`](#persistence-type-sha256-56b7c047694875a843ba020dfea3c8380d54ae4ff88ab349e72004dc21e07c23) | | `max-tokens` | not declared | none | [`{ kind: "max-tokens" }`](#persistence-type-sha256-ab7ec5f9eb2c6dfacca5da4c37cf7ba85d04172053ee6b1ebf1709ffcd99c1a7) | - + @@ -5426,7 +5446,7 @@ Sources: [`packages/core/session/src/types.ts:238`](../packages/core/session/src ### `UserMessage` -SHA-256: `613660455704fb82a825b5b766e000aa64b5b4d44b4f10e55cffe968d4ec6ab1` +SHA-256: `74e0e5885d2ddf04530ddf341b25cd65e1f85c00b30a88bd992f11fc06615a0c` Sources: [`packages/llm/llm/src/message.ts:162`](../packages/llm/llm/src/message.ts) @@ -5435,19 +5455,19 @@ Sources: [`packages/llm/llm/src/message.ts:162`](../packages/llm/llm/src/message | `content` | required | [`ContentBlock[]`](#persistence-type-sha256-b52f215a6cd691058a3413c12f161fa3b563a2f4895adb3df6f744ec4b0a6ef1) | | `id` | required | `string` | | `role` | required | `"user"` | -| `source` | required | [`MessageSource`](#persistence-type-sha256-b120362fd216a16a40fe787f6d3286086aa131266322bab79c026a130ccd0f72) | +| `source` | required | [`MessageSource`](#persistence-type-sha256-dca3ba43188095fa7342e49e6c206d4685125497d4767595bf12a62ea2fd73ce) | Source compatibility: `source` — `session-source-attribution` v1; `session.user-message.source`; `kind`; `preserve`. Attribution-only additions: `action-cards`, `tmux-context`, `user-question-reply`, `working-directory`. - + ### `UserMessage[]` -SHA-256: `690583582246babf6120f16eefd849dd760c5ec84619014951af403a1b3032c0` +SHA-256: `8a54d228b1b7d8453e4304d32723d489f28b4b33b221f335342146926ad94fc6` -Array of [`UserMessage`](#persistence-type-sha256-613660455704fb82a825b5b766e000aa64b5b4d44b4f10e55cffe968d4ec6ab1). +Array of [`UserMessage`](#persistence-type-sha256-74e0e5885d2ddf04530ddf341b25cd65e1f85c00b30a88bd992f11fc06615a0c). @@ -5639,7 +5659,7 @@ Array of `number`. SHA-256: `4cd48f3e5108bd6ebedf7301c3638839b8b2b9db8dbd493974177fbdeb91a01b` -Sources: [`packages/api/session-controller/src/types.ts:389`](../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/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/team/agent-team/src/types.ts:20`](../packages/team/agent-team/src/types.ts) · [`packages/team/agent-team/src/types.ts:32`](../packages/team/agent-team/src/types.ts) · [`packages/team/agent-team/src/types.ts:8`](../packages/team/agent-team/src/types.ts) · [`packages/workflow/workflow/src/types.ts:13`](../packages/workflow/workflow/src/types.ts) +Sources: [`packages/api/session-controller/src/types.ts:391`](../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/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/team/agent-team/src/types.ts:20`](../packages/team/agent-team/src/types.ts) · [`packages/team/agent-team/src/types.ts:32`](../packages/team/agent-team/src/types.ts) · [`packages/team/agent-team/src/types.ts:8`](../packages/team/agent-team/src/types.ts) · [`packages/workflow/workflow/src/types.ts:13`](../packages/workflow/workflow/src/types.ts) `string` @@ -5984,6 +6004,21 @@ SHA-256: `0e10d7c096b47e61defe372a5fc8bd37d835199410eac44367f95c45082498bd` | `mode` | required | `"continuable"` | | `version` | required | `0` | + + +### `{ childCreatedAt, childId, label, mode, … }` + +SHA-256: `8faed5b52ab2d2df40b94a926d0f0faa75280bddcc4b17b6bdd9c8bfed7c34b5` + +| Property | Presence | Type | +|---|---|---| +| `childCreatedAt` | required | `number` | +| `childId` | required | `string` | +| `label` | required | `string` | +| `mode` | required | `"continuable"` | +| `name` | required | `string` | +| `version` | required | `3` | + ### `{ childCreatedAt, childId, label, mode, … }` @@ -6026,6 +6061,21 @@ SHA-256: `a0f25b5aeeebf2bf1542ce67726b095e3b139a39c71861d57e827f12dea1f499` | `mode` | required | `"unknown"` | | `version` | required | `1` | + + +### `{ childCreatedAt, childId, label?, mode, … }` + +SHA-256: `a43327a1739c3fa477f32981071fef7d8ba6ae5f32a84fd70f547b2eee59e93e` + +| Property | Presence | Type | +|---|---|---| +| `childCreatedAt` | required | `number` | +| `childId` | required | `string` | +| `label` | optional | `string` | +| `mode` | required | `"external"` | +| `name` | required | `string` | +| `version` | required | `3` | + ### `{ childCreatedAt, childId, label?, mode, … }` @@ -6282,7 +6332,7 @@ Sources: [`packages/experimental/liveshare/src/host/viewer-principal.ts:29`](../ SHA-256: `c2a13242efc3bea4b36a843ddf1524ff4d33c765a71b582fa1fdbfa4fa148434` -Sources: [`packages/team/agent-team/src/types.ts:173`](../packages/team/agent-team/src/types.ts) +Sources: [`packages/team/agent-team/src/types.ts:177`](../packages/team/agent-team/src/types.ts) | Property | Presence | Type | |---|---|---| @@ -6384,18 +6434,18 @@ Sources: [`packages/core/session/src/types.ts:398`](../packages/core/session/src | `reason` | required | [`RequestHeaderReason`](#persistence-type-sha256-530da6c0267813bb4511af72883cc518834e624e3b3220a7062955fd57a788a6) | | `startsSeries` | optional | `true` | - + ### `{ headerSeq?, message, step, turn }` -SHA-256: `65377a76c6a58f785d95b89f89f2e13d289cb88a70ea74939d0ec08f429f0a6e` +SHA-256: `295809283ede248d14e6a431dec1c464cfd80a54b0d8f2a5994219fd8c8f9998` Sources: [`packages/core/session/src/types.ts:317`](../packages/core/session/src/types.ts) | Property | Presence | Type | |---|---|---| | `headerSeq` | optional | `number` | -| `message` | required | [`DeveloperMessage`](#persistence-type-sha256-01c161379a3c3394a642807843e108ef911a8b7dbffd6d7de43f4484c88b0796) | +| `message` | required | [`DeveloperMessage`](#persistence-type-sha256-824b1d4d4f007bdaa5eee7994a5db3ede7707c6cd2bf8e2509be176c7609e3bc) | | `step` | required | `number` | | `turn` | required | `number` | @@ -6479,17 +6529,17 @@ Sources: [`packages/core/session/src/types.ts:435`](../packages/core/session/src |---|---|---| | `inherited` | optional | `true` | - + ### `{ inserted, outcome?, removedCount?, start, … }` -SHA-256: `e1880c67e735e228f3555df8a55a492db2c0b0c71bc8859e938e184a46c7db51` +SHA-256: `f7752f518bb2f9165f2c01559df1f570c23d57373defbbd4512399a0ffaf2492` Sources: [`packages/core/agent/src/types.ts:110`](../packages/core/agent/src/types.ts) | Property | Presence | Type | |---|---|---| -| `inserted` | required | [`UserMessage[]`](#persistence-type-sha256-690583582246babf6120f16eefd849dd760c5ec84619014951af403a1b3032c0) | +| `inserted` | required | [`UserMessage[]`](#persistence-type-sha256-8a54d228b1b7d8453e4304d32723d489f28b4b33b221f335342146926ad94fc6) | | `outcome` | optional | `"canceled"` | | `removedCount` | optional | `number` | | `start` | required | `number` | @@ -7249,6 +7299,21 @@ SHA-256: `db06ef35b27a38425046b2228fa6bce9582abe140d781d363137eb2f4d233a1c` | `kind` | required | `"repeat-tool-reminder"` | | `sections` | required | [`ContextSnapshotSection[]`](#persistence-type-sha256-c748fb42c80a120038a8c587af80ec39924803c401364db11c8974d5bf6d0262) | + + +### `{ kind: "retry" }` + +SHA-256: `8f1062573ea9184129dfdec43df1e8136eb5808746fd809bf6b539f3fd11362e` + +Sources: [`packages/api/session-controller/src/types.ts:402`](../packages/api/session-controller/src/types.ts) + +| Property | Presence | Type | +|---|---|---| +| `clientTimeZone` | optional | `string` | +| `kind` | required | `"retry"` | +| `principal` | optional | [`union (2 variants)`](#persistence-type-sha256-824a4aad44a54e245c67196817d67946734a2dc0eee0b0b6834a5b2a6ef352ce) | +| `rpcId` | required | `string` | + ### `{ kind: "runtime-context" }` @@ -7759,7 +7824,7 @@ Sources: [`packages/core/tools/src/index.ts:28`](../packages/core/tools/src/inde SHA-256: `a4afec59b75aad5d13ef82d6931f35cc2d98918503916cf069355b77c5e42302` -Sources: [`packages/api/session-controller/src/types.ts:398`](../packages/api/session-controller/src/types.ts) +Sources: [`packages/api/session-controller/src/types.ts:400`](../packages/api/session-controller/src/types.ts) | Property | Presence | Type | |---|---|---| @@ -7912,7 +7977,7 @@ Sources: [`packages/web/web-search-deepseek/src/provider.ts:61`](../packages/web SHA-256: `b1ebd5cda47d90d980bb05bffc3f970c51537b9aff15b3bc3d639811727741b1` -Sources: [`packages/team/agent-team/src/types.ts:175`](../packages/team/agent-team/src/types.ts) +Sources: [`packages/team/agent-team/src/types.ts:179`](../packages/team/agent-team/src/types.ts) | Property | Presence | Type | |---|---|---| @@ -7940,7 +8005,7 @@ Sources: [`packages/core/session/src/types.ts:338`](../packages/core/session/src SHA-256: `ea08ec1df0c33108fd03345b9af199cf04dea450aa045d3c683f216311403403` -Sources: [`packages/team/agent-team/src/types.ts:179`](../packages/team/agent-team/src/types.ts) +Sources: [`packages/team/agent-team/src/types.ts:183`](../packages/team/agent-team/src/types.ts) | Property | Presence | Type | |---|---|---| @@ -7954,7 +8019,7 @@ Sources: [`packages/team/agent-team/src/types.ts:179`](../packages/team/agent-te SHA-256: `0bcfaf5566d271028429ac7b562cb59053c9d78b8ae14708c35fac835108d1b1` -Sources: [`packages/team/agent-team/src/types.ts:181`](../packages/team/agent-team/src/types.ts) +Sources: [`packages/team/agent-team/src/types.ts:185`](../packages/team/agent-team/src/types.ts) | Property | Presence | Type | |---|---|---| @@ -8094,17 +8159,17 @@ Sources: [`packages/compaction/compaction-image-offload/src/projection.ts:25`](. |---|---|---| | `targets` | required | [`ImageOffloadTarget[]`](#persistence-type-sha256-9e2c06d8653585b33d72d5c1a80da79c8a24a88c284409bca15cc0f0ead5ebfb) | - + ### `{ task, teamId, version }` -SHA-256: `a40d12070f6f4a124f32fb3cc86e7857554702e32f0eda3080a25c4b9ac9b18c` +SHA-256: `a9427866376b691aace0ce25aa0e1bdec2a14156a05152947a467da3f7967cb9` -Sources: [`packages/team/agent-team/src/types.ts:177`](../packages/team/agent-team/src/types.ts) +Sources: [`packages/team/agent-team/src/types.ts:181`](../packages/team/agent-team/src/types.ts) | Property | Presence | Type | |---|---|---| -| `task` | required | [`TeamTaskSnapshot`](#persistence-type-sha256-51edec100659da3a9bd9c3f6ba1180f5e64ec9a1585e5057080df45c180bd357) | +| `task` | required | [`TeamTaskSnapshot`](#persistence-type-sha256-4018a00144474b6c60dc1aa6e5c1f03611c66bd739833779a7d20a511df6d082) | | `teamId` | required | `string` | | `version` | required | `2` | @@ -8148,17 +8213,17 @@ SHA-256: `a10c17474eaf2ddab7095a099e0fe3d046fc18e56c3e344fc8894c05ff9ef97b` | `time` | required | `number` | | `type` | required | `"agent-preset/selected"` | - + ### `{ type: "agent/inbox/spliced" }` -SHA-256: `ddce54a3873dc57113b0cd38ad9b23b3c259186139e8847e5e5f415d86f52482` +SHA-256: `1682631f010d5ea717d181ed6f4ef46cde08d92a31ab461e7e98edfc98461f85` | Property | Presence | Type | |---|---|---| -| `data` | required | [`{ inserted, outcome?, removedCount?, start, … }`](#persistence-type-sha256-e1880c67e735e228f3555df8a55a492db2c0b0c71bc8859e938e184a46c7db51) | +| `data` | required | [`{ inserted, outcome?, removedCount?, start, … }`](#persistence-type-sha256-f7752f518bb2f9165f2c01559df1f570c23d57373defbbd4512399a0ffaf2492) | | `ignorable` | optional | `true` | | `seq` | required | `number` | | `time` | required | `number` | @@ -8399,17 +8464,17 @@ SHA-256: `13d3d180f977bf78081d487ffa0ecb75857349bcab29a5a3fb48189fca2a6176` | `time` | required | `number` | | `type` | required | `"deliverables/presented"` | - + ### `{ type: "developer/message" }` -SHA-256: `70ea8e7943c5e2d76905bcc2e694e8c3d5b138aaae3609f3e261b8d369a6e35a` +SHA-256: `510826cf4e1f9220d75c1efd90b349dd9a77fc5ba15d19e16f87e85a48db5f99` | Property | Presence | Type | |---|---|---| -| `data` | required | [`{ headerSeq?, message, step, turn }`](#persistence-type-sha256-65377a76c6a58f785d95b89f89f2e13d289cb88a70ea74939d0ec08f429f0a6e) | +| `data` | required | [`{ headerSeq?, message, step, turn }`](#persistence-type-sha256-295809283ede248d14e6a431dec1c464cfd80a54b0d8f2a5994219fd8c8f9998) | | `ignorable` | optional | `true` | | `seq` | required | `number` | | `sourceEventSeqs` | optional | [`number[]`](#persistence-type-sha256-5d03ba38734809bcbd2a55221bd938b3b3fc34b49bb686c6113e9e4931e3aa78) | @@ -8809,17 +8874,17 @@ SHA-256: `1b912703e2d64f91c99c675b8f805b01076c8325b905c1218ad81ef0b24909d5` | `time` | required | `number` | | `type` | required | `"session/title"` | - + ### `{ type: "session/title-llm-request" }` -SHA-256: `d95c624eddecdacf1ee74356196c09d2f3fcd625714be5e852a6b643fa12a7ca` +SHA-256: `3bca25b2baa6b22be9b577621a7603497f40870ed88a8dac4383d37dc2bb6e18` | Property | Presence | Type | |---|---|---| -| `data` | required | [`SessionTitleLlmRequestEventData`](#persistence-type-sha256-601327bedca5f98a0fa4c27133bd35749f3af2baaaacf53badf074e59cea5d25) | +| `data` | required | [`SessionTitleLlmRequestEventData`](#persistence-type-sha256-bec5ca3a376f56f3d69df7f12a48e1cc07d4ea8305968773394c8734799faeb4) | | `ignorable` | optional | `true` | | `seq` | required | `number` | | `time` | required | `number` | @@ -8857,17 +8922,17 @@ SHA-256: `4513e088d43e6c68425be30451b9f961cc264fe7318ca62681c41d4d78615986` | `time` | required | `number` | | `type` | required | `"step/start"` | - + ### `{ type: "subagent/catalog" }` -SHA-256: `53750b9abf61efb7992b0aadc3e247ec927449c63266df28230fd1139f5590ac` +SHA-256: `d49164d37eab0f0f70fa787c65d887abbea869c010ccb103d717fab3519c3a41` | Property | Presence | Type | |---|---|---| -| `data` | required | [`SubagentCatalogEvent`](#persistence-type-sha256-f731ffe80810b0289b3e694d8f40af6f01865c02a622ee457be90ca808b66e87) | +| `data` | required | [`SubagentCatalogEvent`](#persistence-type-sha256-058fc9a6b4fbd5d43437c3a64170002070dfc98e18d87de294b564ae446ca8ae) | | `ignorable` | optional | `true` | | `seq` | required | `number` | | `time` | required | `number` | @@ -8987,17 +9052,17 @@ SHA-256: `920d87e22b7409bcc7224f8b1dc7f5101c33574c75627c65baab12b85cc96e75` | `time` | required | `number` | | `type` | required | `"team/mode"` | - + ### `{ type: "team/task" }` -SHA-256: `d595ec73b32b016a6055333c67a5d646032b22e672da1d4a09c5b1ae398a093a` +SHA-256: `bca0f9cb63d8620b6954bb045b07bb07cb557513a7f0e2e177f5e87f704e7ba7` | Property | Presence | Type | |---|---|---| -| `data` | required | [`{ task, teamId, version }`](#persistence-type-sha256-a40d12070f6f4a124f32fb3cc86e7857554702e32f0eda3080a25c4b9ac9b18c) | +| `data` | required | [`{ task, teamId, version }`](#persistence-type-sha256-a9427866376b691aace0ce25aa0e1bdec2a14156a05152947a467da3f7967cb9) | | `ignorable` | optional | `true` | | `seq` | required | `number` | | `time` | required | `number` | @@ -9258,17 +9323,17 @@ Sources: [`packages/llm/llm/src/types.ts:502`](../packages/llm/llm/src/types.ts) | `type` | required | `"usage"` | | `usage` | required | [`TokenUsage`](#persistence-type-sha256-fec5442b9ee4122e10514d81d5a43648003fe8bfb7ee2ba50c0cdbdd383ed394) | - + ### `{ type: "user/message" }` -SHA-256: `dcb07e04496586d2664d72dab0e94312917da56927b2a0dc3ee53d6a33e32450` +SHA-256: `50a15408d511e9be3fa93abff37a38ae770f3ab905fc6849fee0d989200d2b97` | Property | Presence | Type | |---|---|---| -| `data` | required | [`UserMessage`](#persistence-type-sha256-613660455704fb82a825b5b766e000aa64b5b4d44b4f10e55cffe968d4ec6ab1) | +| `data` | required | [`UserMessage`](#persistence-type-sha256-74e0e5885d2ddf04530ddf341b25cd65e1f85c00b30a88bd992f11fc06615a0c) | | `ignorable` | optional | `true` | | `seq` | required | `number` | | `sourceEventSeqs` | optional | [`number[]`](#persistence-type-sha256-5d03ba38734809bcbd2a55221bd938b3b3fc34b49bb686c6113e9e4931e3aa78) | diff --git a/docs/persistence-catalog.zh.md b/docs/persistence-catalog.zh.md index 6b26e80ae8..73ebef9642 100644 --- a/docs/persistence-catalog.zh.md +++ b/docs/persistence-catalog.zh.md @@ -25,7 +25,7 @@ | `JsonlHeaderLine` | header | `18ee62b8900a4c3d046700f05d7a4d49d6cab2a660a020c87481d1603dd8bd4f` | [`HeaderLine`](#persistence-type-sha256-18ee62b8900a4c3d046700f05d7a4d49d6cab2a660a020c87481d1603dd8bd4f) | | `SessionEventEnvelope` | envelope | `5776e5553ff2dfe3f5bc202dbb1e7c9f93e35a531aebb7764c23b2b6153b2ccc` | [`union (3 variants)`](#persistence-type-sha256-5776e5553ff2dfe3f5bc202dbb1e7c9f93e35a531aebb7764c23b2b6153b2ccc) | | `event:agent-preset/selected` | event | `a10c17474eaf2ddab7095a099e0fe3d046fc18e56c3e344fc8894c05ff9ef97b` | [`{ type: "agent-preset/selected" }`](#persistence-type-sha256-a10c17474eaf2ddab7095a099e0fe3d046fc18e56c3e344fc8894c05ff9ef97b) | -| `event:agent/inbox/spliced` | event | `ddce54a3873dc57113b0cd38ad9b23b3c259186139e8847e5e5f415d86f52482` | [`{ type: "agent/inbox/spliced" }`](#persistence-type-sha256-ddce54a3873dc57113b0cd38ad9b23b3c259186139e8847e5e5f415d86f52482) | +| `event:agent/inbox/spliced` | event | `1682631f010d5ea717d181ed6f4ef46cde08d92a31ab461e7e98edfc98461f85` | [`{ type: "agent/inbox/spliced" }`](#persistence-type-sha256-1682631f010d5ea717d181ed6f4ef46cde08d92a31ab461e7e98edfc98461f85) | | `event:approval/asked` | event | `3bfeb47b58606f4661904bc723da612782214c463d01e6d61cd6d6193d7374e1` | [`{ type: "approval/asked" }`](#persistence-type-sha256-3bfeb47b58606f4661904bc723da612782214c463d01e6d61cd6d6193d7374e1) | | `event:approval/decided` | event | `bb1ab3d08f49a9f3b265f844cd78d5c49813062a7b34b54904b426f85d0ff6e3` | [`{ type: "approval/decided" }`](#persistence-type-sha256-bb1ab3d08f49a9f3b265f844cd78d5c49813062a7b34b54904b426f85d0ff6e3) | | `event:approval/policy` | event | `26718e15e7e395bce9642dba5bbe09b3b1a4ce2213d20d566cd9207d7fc5fb78` | [`{ type: "approval/policy" }`](#persistence-type-sha256-26718e15e7e395bce9642dba5bbe09b3b1a4ce2213d20d566cd9207d7fc5fb78) | @@ -38,7 +38,7 @@ | `event:compaction/start` | event | `db874d463b0fdec77e9da1c4568f37cb70bd6596781eb93800db44fb8a116965` | [`{ type: "compaction/start" }`](#persistence-type-sha256-db874d463b0fdec77e9da1c4568f37cb70bd6596781eb93800db44fb8a116965) | | `event:compaction/summary` | event | `e2f9a41e0989f54ed8cee80f8db2bcf9d60a5c810dc9d45b83fa050b9dce7602` | [`{ type: "compaction/summary" }`](#persistence-type-sha256-e2f9a41e0989f54ed8cee80f8db2bcf9d60a5c810dc9d45b83fa050b9dce7602) | | `event:deliverables/presented` | event | `13d3d180f977bf78081d487ffa0ecb75857349bcab29a5a3fb48189fca2a6176` | [`{ type: "deliverables/presented" }`](#persistence-type-sha256-13d3d180f977bf78081d487ffa0ecb75857349bcab29a5a3fb48189fca2a6176) | -| `event:developer/message` | event | `70ea8e7943c5e2d76905bcc2e694e8c3d5b138aaae3609f3e261b8d369a6e35a` | [`{ type: "developer/message" }`](#persistence-type-sha256-70ea8e7943c5e2d76905bcc2e694e8c3d5b138aaae3609f3e261b8d369a6e35a) | +| `event:developer/message` | event | `510826cf4e1f9220d75c1efd90b349dd9a77fc5ba15d19e16f87e85a48db5f99` | [`{ type: "developer/message" }`](#persistence-type-sha256-510826cf4e1f9220d75c1efd90b349dd9a77fc5ba15d19e16f87e85a48db5f99) | | `event:feedback/message-delete` | event | `3ee93b06f3a125850337602bcdf155d2538c43a5c944ec55b1b3c365152d6796` | [`{ type: "feedback/message-delete" }`](#persistence-type-sha256-3ee93b06f3a125850337602bcdf155d2538c43a5c944ec55b1b3c365152d6796) | | `event:feedback/message-put` | event | `b5086d249e8502e9ead1d39156bb8d559bde7951cac0f14ce150345b4e42a2bf` | [`{ type: "feedback/message-put" }`](#persistence-type-sha256-b5086d249e8502e9ead1d39156bb8d559bde7951cac0f14ce150345b4e42a2bf) | | `event:feedback/record` | event | `b54940ff095c17e874c5be03815f4c2145a256cf3a1d34dae4ab2f7769dfffe8` | [`{ type: "feedback/record" }`](#persistence-type-sha256-b54940ff095c17e874c5be03815f4c2145a256cf3a1d34dae4ab2f7769dfffe8) | @@ -60,10 +60,10 @@ | `event:session-log-deepseek/delivery-accepted` | event | `d63b8b8ffad9c02fd80c43a17df4f240c1fe8118ecca9de34f9d5871838ab5b9` | [`{ type: "session-log-deepseek/delivery-accepted" }`](#persistence-type-sha256-d63b8b8ffad9c02fd80c43a17df4f240c1fe8118ecca9de34f9d5871838ab5b9) | | `event:session/end-seed` | event | `5e6db6e24948d4a853c71cb9fabd252ad051ce93d4672c1266cf837c1c17b84e` | [`{ type: "session/end-seed" }`](#persistence-type-sha256-5e6db6e24948d4a853c71cb9fabd252ad051ce93d4672c1266cf837c1c17b84e) | | `event:session/title` | event | `1b912703e2d64f91c99c675b8f805b01076c8325b905c1218ad81ef0b24909d5` | [`{ type: "session/title" }`](#persistence-type-sha256-1b912703e2d64f91c99c675b8f805b01076c8325b905c1218ad81ef0b24909d5) | -| `event:session/title-llm-request` | event | `d95c624eddecdacf1ee74356196c09d2f3fcd625714be5e852a6b643fa12a7ca` | [`{ type: "session/title-llm-request" }`](#persistence-type-sha256-d95c624eddecdacf1ee74356196c09d2f3fcd625714be5e852a6b643fa12a7ca) | +| `event:session/title-llm-request` | event | `3bca25b2baa6b22be9b577621a7603497f40870ed88a8dac4383d37dc2bb6e18` | [`{ type: "session/title-llm-request" }`](#persistence-type-sha256-3bca25b2baa6b22be9b577621a7603497f40870ed88a8dac4383d37dc2bb6e18) | | `event:step/end` | event | `e0a787e6ec76c7c94fecbc501b489164ab0293db05bc947914077ad01e674f05` | [`{ type: "step/end" }`](#persistence-type-sha256-e0a787e6ec76c7c94fecbc501b489164ab0293db05bc947914077ad01e674f05) | | `event:step/start` | event | `4513e088d43e6c68425be30451b9f961cc264fe7318ca62681c41d4d78615986` | [`{ type: "step/start" }`](#persistence-type-sha256-4513e088d43e6c68425be30451b9f961cc264fe7318ca62681c41d4d78615986) | -| `event:subagent/catalog` | event | `53750b9abf61efb7992b0aadc3e247ec927449c63266df28230fd1139f5590ac` | [`{ type: "subagent/catalog" }`](#persistence-type-sha256-53750b9abf61efb7992b0aadc3e247ec927449c63266df28230fd1139f5590ac) | +| `event:subagent/catalog` | event | `d49164d37eab0f0f70fa787c65d887abbea869c010ccb103d717fab3519c3a41` | [`{ type: "subagent/catalog" }`](#persistence-type-sha256-d49164d37eab0f0f70fa787c65d887abbea869c010ccb103d717fab3519c3a41) | | `event:subagent/descriptor` | event | `b79ada42962cad0190a9d465805260567621fa3a4abd757eb31e6016b52d5ab5` | [`{ type: "subagent/descriptor" }`](#persistence-type-sha256-b79ada42962cad0190a9d465805260567621fa3a4abd757eb31e6016b52d5ab5) | | `event:subagent/model-selection-policy` | event | `a6567ccb2e530606b775371eb4fa31468d72084339968e8b0440a516a23b39dc` | [`{ type: "subagent/model-selection-policy" }`](#persistence-type-sha256-a6567ccb2e530606b775371eb4fa31468d72084339968e8b0440a516a23b39dc) | | `event:system/message` | event | `69081694be231d56fd9580ba14645fd5e35373202605d5c5c841a9435b5fa3b1` | [`{ type: "system/message" }`](#persistence-type-sha256-69081694be231d56fd9580ba14645fd5e35373202605d5c5c841a9435b5fa3b1) | @@ -71,7 +71,7 @@ | `event:team/message/delivered` | event | `48f9c19417a1abbedfa59f4667bba36b93ac2db407adf5e84cb3ba0de30942cb` | [`{ type: "team/message/delivered" }`](#persistence-type-sha256-48f9c19417a1abbedfa59f4667bba36b93ac2db407adf5e84cb3ba0de30942cb) | | `event:team/message/queued` | event | `21fb6a90d5068f6a0003b7ab316ed2f56342477146a65c00db0f13c4d8df667d` | [`{ type: "team/message/queued" }`](#persistence-type-sha256-21fb6a90d5068f6a0003b7ab316ed2f56342477146a65c00db0f13c4d8df667d) | | `event:team/mode` | event | `920d87e22b7409bcc7224f8b1dc7f5101c33574c75627c65baab12b85cc96e75` | [`{ type: "team/mode" }`](#persistence-type-sha256-920d87e22b7409bcc7224f8b1dc7f5101c33574c75627c65baab12b85cc96e75) | -| `event:team/task` | event | `d595ec73b32b016a6055333c67a5d646032b22e672da1d4a09c5b1ae398a093a` | [`{ type: "team/task" }`](#persistence-type-sha256-d595ec73b32b016a6055333c67a5d646032b22e672da1d4a09c5b1ae398a093a) | +| `event:team/task` | event | `bca0f9cb63d8620b6954bb045b07bb07cb557513a7f0e2e177f5e87f704e7ba7` | [`{ type: "team/task" }`](#persistence-type-sha256-bca0f9cb63d8620b6954bb045b07bb07cb557513a7f0e2e177f5e87f704e7ba7) | | `event:todo/write` | event | `b978cff734e62143eb56c9125423ec275405eda969802d42aaf73ecb987d3b26` | [`{ type: "todo/write" }`](#persistence-type-sha256-b978cff734e62143eb56c9125423ec275405eda969802d42aaf73ecb987d3b26) | | `event:tool-workflow/agent-end` | event | `babf9ee4d1af62bf6c3a8103737f7a5e4e78ce179be835ce05a38803e15884b7` | [`{ type: "tool-workflow/agent-end" }`](#persistence-type-sha256-babf9ee4d1af62bf6c3a8103737f7a5e4e78ce179be835ce05a38803e15884b7) | | `event:tool-workflow/agent-start` | event | `5f26a6c20b37632f8f57729d171c671def4683d994ac6257a8dffcd855101627` | [`{ type: "tool-workflow/agent-start" }`](#persistence-type-sha256-5f26a6c20b37632f8f57729d171c671def4683d994ac6257a8dffcd855101627) | @@ -83,7 +83,7 @@ | `event:tool/result` | event | `7c9f44e90a0058f4cc532ae20dad0c10afa6eba22e70a6c79fc79490bad64397` | [`{ type: "tool/result" }`](#persistence-type-sha256-7c9f44e90a0058f4cc532ae20dad0c10afa6eba22e70a6c79fc79490bad64397) | | `event:turn/end` | event | `0f8512903d94f57a4748fa1a2092e64342856796684e6b8343db685b192745ce` | [`{ type: "turn/end" }`](#persistence-type-sha256-0f8512903d94f57a4748fa1a2092e64342856796684e6b8343db685b192745ce) | | `event:turn/start` | event | `aa0957eca50aeb28bcd2e6930b95809926edacb550c8c340ba526ba6b861b3d8` | [`{ type: "turn/start" }`](#persistence-type-sha256-aa0957eca50aeb28bcd2e6930b95809926edacb550c8c340ba526ba6b861b3d8) | -| `event:user/message` | event | `dcb07e04496586d2664d72dab0e94312917da56927b2a0dc3ee53d6a33e32450` | [`{ type: "user/message" }`](#persistence-type-sha256-dcb07e04496586d2664d72dab0e94312917da56927b2a0dc3ee53d6a33e32450) | +| `event:user/message` | event | `50a15408d511e9be3fa93abff37a38ae770f3ab905fc6849fee0d989200d2b97` | [`{ type: "user/message" }`](#persistence-type-sha256-50a15408d511e9be3fa93abff37a38ae770f3ab905fc6849fee0d989200d2b97) | | `event:web/deepseek-search-llm-request` | event | `0c556c9b9f2a96238a6b9bbb99e748206cbff2ed6203041c9571f04ae5802f52` | [`{ type: "web/deepseek-search-llm-request" }`](#persistence-type-sha256-0c556c9b9f2a96238a6b9bbb99e748206cbff2ed6203041c9571f04ae5802f52) | | `event:working-directory/change` | event | `124aa62078ca3311353b39cc3bf6c75da281338be6bbf672f8b361d828cddca3` | [`{ type: "working-directory/change" }`](#persistence-type-sha256-124aa62078ca3311353b39cc3bf6c75da281338be6bbf672f8b361d828cddca3) | | `event:workspace/changes` | event | `e308ccf867a5398e316e0af8cb6ce238a8d33a63b9b384c8250a686786285f72` | [`{ type: "workspace/changes" }`](#persistence-type-sha256-e308ccf867a5398e316e0af8cb6ce238a8d33a63b9b384c8250a686786285f72) | @@ -940,7 +940,7 @@ export type SessionEvent = { 'subagent/catalog': SubagentCatalogEvent ``` -来源:[`packages/subagent/subagent/src/catalog.ts:44`](../packages/subagent/subagent/src/catalog.ts) +来源:[`packages/subagent/subagent/src/catalog.ts:52`](../packages/subagent/subagent/src/catalog.ts) @@ -1017,7 +1017,7 @@ export type SessionEvent = { 类型:[TeamId](subsystems/agent-team.zh.md) · [TeamMemberSnapshot](subsystems/agent-team.zh.md) -来源:[`packages/team/agent-team/src/types.ts:175`](../packages/team/agent-team/src/types.ts) +来源:[`packages/team/agent-team/src/types.ts:179`](../packages/team/agent-team/src/types.ts) @@ -1035,7 +1035,7 @@ export type SessionEvent = { 类型:[TeamId](subsystems/agent-team.zh.md) · [TeamMessageId](subsystems/agent-team.zh.md) -来源:[`packages/team/agent-team/src/types.ts:181`](../packages/team/agent-team/src/types.ts) +来源:[`packages/team/agent-team/src/types.ts:185`](../packages/team/agent-team/src/types.ts) @@ -1048,7 +1048,7 @@ export type SessionEvent = { 类型:[TeamId](subsystems/agent-team.zh.md) · [TeamMessageSnapshot](subsystems/agent-team.zh.md) -来源:[`packages/team/agent-team/src/types.ts:179`](../packages/team/agent-team/src/types.ts) +来源:[`packages/team/agent-team/src/types.ts:183`](../packages/team/agent-team/src/types.ts) @@ -1059,7 +1059,7 @@ export type SessionEvent = { 'team/mode': { enabled: boolean } ``` -来源:[`packages/team/agent-team/src/types.ts:173`](../packages/team/agent-team/src/types.ts) +来源:[`packages/team/agent-team/src/types.ts:177`](../packages/team/agent-team/src/types.ts) @@ -1072,7 +1072,7 @@ export type SessionEvent = { 类型:[TeamId](subsystems/agent-team.zh.md) · [TeamTaskSnapshot](subsystems/agent-team.zh.md) -来源:[`packages/team/agent-team/src/types.ts:177`](../packages/team/agent-team/src/types.ts) +来源:[`packages/team/agent-team/src/types.ts:181`](../packages/team/agent-team/src/types.ts) ### `todo/*` @@ -2448,6 +2448,14 @@ SHA-256: `34d1ab5c5df378186d6054b1a1beea9a41e41965d6f336f0bc0025c441a82e66` `"resume"` + + +### `"retry"` + +SHA-256: `63ba8895cc09e4693cf0819fdcd18c084bef195febda5b6a23af279b3852be36` + +`"retry"` + ### `"runtime-context"` @@ -3104,6 +3112,14 @@ SHA-256: `a0f906856fc06f1c6f2083eb970e5a657a82b1a84c06c095445e5d6d161cda80` `2` + + +### `3` + +SHA-256: `137ac60e26bcb192210d9a32a704b73b0924ed34019323defa1b787be95bd45e` + +`3` + ### `4` @@ -3412,7 +3428,7 @@ SHA-256: `abd6ca62a5ab166553848324a23fef90eed7f59c8021bd63e7ea5bc6fd666b0c` | `body` | 必需 | [`{ max_tokens, messages, model, thinking?, … }`](#persistence-type-sha256-9c001ecb5e1d3c3894410db2a1e383842e5f8454fb52182338686158abc1b3ee) | | `endpoint` | 必需 | `string` | - + @@ -3420,7 +3436,7 @@ SHA-256: `abd6ca62a5ab166553848324a23fef90eed7f59c8021bd63e7ea5bc6fd666b0c` ### `DeveloperMessage` -SHA-256: `01c161379a3c3394a642807843e108ef911a8b7dbffd6d7de43f4484c88b0796` +SHA-256: `824b1d4d4f007bdaa5eee7994a5db3ede7707c6cd2bf8e2509be176c7609e3bc` 来源:[`packages/llm/llm/src/message.ts:157`](../packages/llm/llm/src/message.ts) @@ -3429,7 +3445,7 @@ SHA-256: `01c161379a3c3394a642807843e108ef911a8b7dbffd6d7de43f4484c88b0796` | `content` | 必需 | [`ContentBlock[]`](#persistence-type-sha256-b52f215a6cd691058a3413c12f161fa3b563a2f4895adb3df6f744ec4b0a6ef1) | | `id` | 必需 | `string` | | `role` | 必需 | `"developer"` | -| `source` | 必需 | [`MessageSource`](#persistence-type-sha256-b120362fd216a16a40fe787f6d3286086aa131266322bab79c026a130ccd0f72) | +| `source` | 必需 | [`MessageSource`](#persistence-type-sha256-dca3ba43188095fa7342e49e6c206d4685125497d4767595bf12a62ea2fd73ce) | 消息源兼容策略:`source` — `session-source-attribution` v1; `session.developer-message.source`; `kind`; `preserve`. @@ -4128,7 +4144,7 @@ SHA-256: `6f72ece8f317cd080c4f20a93f1bf709965f5b81ac4669528f5a023191cfcf20` | `step` | 必需 | `number` | | `turn` | 必需 | `number` | - + @@ -4136,15 +4152,15 @@ SHA-256: `6f72ece8f317cd080c4f20a93f1bf709965f5b81ac4669528f5a023191cfcf20` ### `Message` -SHA-256: `e272493e3ea0b33b2e1d64b6a80e9d8bd3d1d466cc115f2facbdd598f8644a39` +SHA-256: `c51f0d0a405bb96fcb008c0dc560a512dcd8c3919b6b446937f449ea2f7d21d8` 来源:[`packages/llm/llm/src/message.ts:196`](../packages/llm/llm/src/message.ts) 以下类型之一: - [`ToolResultMessage`](#persistence-type-sha256-4b259f7f8f0a44ad5e90b70a73553ced1df27012d126921d397ff403b6c86731) -- [`DeveloperMessage`](#persistence-type-sha256-01c161379a3c3394a642807843e108ef911a8b7dbffd6d7de43f4484c88b0796) -- [`UserMessage`](#persistence-type-sha256-613660455704fb82a825b5b766e000aa64b5b4d44b4f10e55cffe968d4ec6ab1) +- [`DeveloperMessage`](#persistence-type-sha256-824b1d4d4f007bdaa5eee7994a5db3ede7707c6cd2bf8e2509be176c7609e3bc) +- [`UserMessage`](#persistence-type-sha256-74e0e5885d2ddf04530ddf341b25cd65e1f85c00b30a88bd992f11fc06615a0c) - [`SystemMessage`](#persistence-type-sha256-09f3f8dc417f278257202714132f98ba7b52957d7b558c4a04456603890eb363) - [`AssistantMessage`](#persistence-type-sha256-fa87537f4a9c1e25602990a8bf686b383e9e00352ec8946e16ae24ba7c1625be) @@ -4221,7 +4237,7 @@ SHA-256: `390eed1028aba02774f14408647acec10ec5516e97d4f15ecde2b9989d5a69f2` - `"negative"` - `"positive"` - + @@ -4229,7 +4245,7 @@ SHA-256: `390eed1028aba02774f14408647acec10ec5516e97d4f15ecde2b9989d5a69f2` ### `MessageSource` -SHA-256: `b120362fd216a16a40fe787f6d3286086aa131266322bab79c026a130ccd0f72` +SHA-256: `dca3ba43188095fa7342e49e6c206d4685125497d4767595bf12a62ea2fd73ce` 来源:[`packages/llm/llm/src/message.ts:136`](../packages/llm/llm/src/message.ts) @@ -4291,6 +4307,7 @@ SHA-256: `b120362fd216a16a40fe787f6d3286086aa131266322bab79c026a130ccd0f72` | `repeat-tool-reminder` | `"relay"` | 无 | [`{ kind: "repeat-tool-reminder", form: "relay" }`](#persistence-type-sha256-4991dfc415c9efebc36fa6969e1798c7d2e42396cc1e6e0ac7d7c89c5c5c4aea) | | `repeat-tool-reminder` | `"snapshot"` | `sections`: [`ContextSnapshotSection[]`](#persistence-type-sha256-c748fb42c80a120038a8c587af80ec39924803c401364db11c8974d5bf6d0262) | [`{ kind: "repeat-tool-reminder", form: "snapshot" }`](#persistence-type-sha256-db06ef35b27a38425046b2228fa6bce9582abe140d781d363137eb2f4d233a1c) | | `repeat-tool-reminder` | 未声明 | 无 | [`{ kind: "repeat-tool-reminder" }`](#persistence-type-sha256-b062078e899958f99ae464514578b8c093924dfe34bd9a835932b420ff2150b1) | +| `retry` | 未声明 | `rpcId`: `string` | [`{ kind: "retry" }`](#persistence-type-sha256-8f1062573ea9184129dfdec43df1e8136eb5808746fd809bf6b539f3fd11362e) | | `runtime-context` | `"catalog"` | 无 | [`{ kind: "runtime-context", form: "catalog" }`](#persistence-type-sha256-58015da1c1950a66daf66ae24913d6a1fc6d1d9ac441b155f8847f7f8584ba8e) | | `runtime-context` | `"instructions"` | 无 | [`{ kind: "runtime-context", form: "instructions" }`](#persistence-type-sha256-0eeb17e1df89b1ebc2902116fe7145e0d321ef0db26e6bdebc802cb8513a01c1) | | `runtime-context` | `"notice"` | `summary`: `string` | [`{ kind: "runtime-context", form: "notice" }`](#persistence-type-sha256-cda2345a9be9d139df49ccbd16dcba716f3440178bf20ff8b801fda1f5eb77dc) | @@ -4354,13 +4371,13 @@ SHA-256: `b120362fd216a16a40fe787f6d3286086aa131266322bab79c026a130ccd0f72` | `webhook` | `"notice"` | `deliveryId`: `string`; `provider`: `string`; `ruleId`: `string`; `source`: `string`; `summary`: `string` | [`{ kind: "webhook", form: "notice" }`](#persistence-type-sha256-9edc162949abf93bd5ff049191b345454ba104f583937ce5580fb50f067d2b94) | | `working-directory` | 未声明 | 无 | [`{ kind: "working-directory" }`](#persistence-type-sha256-2235d957bf4b7c6cf959231d480f0ba1f3a6d72d82981493fb6c7c963021d3d5) | - + ### `Message[]` -SHA-256: `95b5cf90ea1f57da3319184d6f5f3811d0f651aa9113591c10e81c3d1e9b9f70` +SHA-256: `42e2ff61928fb7dfaf0f057d61686f3a32ff713da419d12d4f250efc96733fe0` -[`Message`](#persistence-type-sha256-e272493e3ea0b33b2e1d64b6a80e9d8bd3d1d466cc115f2facbdd598f8644a39) 的数组。 +[`Message`](#persistence-type-sha256-c51f0d0a405bb96fcb008c0dc560a512dcd8c3919b6b446937f449ea2f7d21d8) 的数组。 @@ -4728,7 +4745,7 @@ SHA-256: `b56f6a885da3dc394c69a3e3cc5c0cfc4da15601b63fda4989eee8f40efc5be4` | `source` | 必需 | [`SessionTitleSource`](#persistence-type-sha256-30d5a537b296685770b1241c4b4bbde19d5a31ff81aa23df73fab5e90b8fc65f) | | `title` | 必需 | `string` | - + @@ -4736,7 +4753,7 @@ SHA-256: `b56f6a885da3dc394c69a3e3cc5c0cfc4da15601b63fda4989eee8f40efc5be4` ### `SessionTitleLlmRequestEventData` -SHA-256: `601327bedca5f98a0fa4c27133bd35749f3af2baaaacf53badf074e59cea5d25` +SHA-256: `bec5ca3a376f56f3d69df7f12a48e1cc07d4ea8305968773394c8734799faeb4` 来源:[`packages/session/session-title-llm/src/index.ts:43`](../packages/session/session-title-llm/src/index.ts) @@ -4744,7 +4761,7 @@ SHA-256: `601327bedca5f98a0fa4c27133bd35749f3af2baaaacf53badf074e59cea5d25` |---|---|---| | `maxTokens` | 必需 | `number` | | `messageSeqs` | 必需 | [`number[]`](#persistence-type-sha256-5d03ba38734809bcbd2a55221bd938b3b3fc34b49bb686c6113e9e4931e3aa78) | -| `messages` | 必需 | [`Message[]`](#persistence-type-sha256-95b5cf90ea1f57da3319184d6f5f3811d0f651aa9113591c10e81c3d1e9b9f70) | +| `messages` | 必需 | [`Message[]`](#persistence-type-sha256-42e2ff61928fb7dfaf0f057d61686f3a32ff713da419d12d4f250efc96733fe0) | | `reasoningEffort` | 可选 | `string` | | `route` | 必需 | [`SessionTitleModelIdentity`](#persistence-type-sha256-07e1a58c58b593f507b8e7f25723bb0aa42baae6e00f5ecfddf28cb1e64d3235) | | `system` | 必需 | `string` | @@ -4875,7 +4892,7 @@ SHA-256: `47e9095591ae36e7c39ee62553097772f2bfa16304536a72dbbc3f691f605180` - [`{ type: "finish" }`](#persistence-type-sha256-a2b49331716ba0a7078b026d145306a70eae64b7313c3e6204bd931e75ec3bb1) - [`{ type: "usage" }`](#persistence-type-sha256-f1a96afe7503ac1817de769cd0ba13d9b80111c7034c50106b3344ecc14cc515) - + @@ -4883,18 +4900,20 @@ SHA-256: `47e9095591ae36e7c39ee62553097772f2bfa16304536a72dbbc3f691f605180` ### `SubagentCatalogEvent` -SHA-256: `f731ffe80810b0289b3e694d8f40af6f01865c02a622ee457be90ca808b66e87` +SHA-256: `058fc9a6b4fbd5d43437c3a64170002070dfc98e18d87de294b564ae446ca8ae` -来源:[`packages/subagent/subagent/src/catalog.ts:28`](../packages/subagent/subagent/src/catalog.ts) +来源:[`packages/subagent/subagent/src/catalog.ts:32`](../packages/subagent/subagent/src/catalog.ts) 以下类型之一: +- [`{ childCreatedAt, childId, label, mode, … }`](#persistence-type-sha256-8faed5b52ab2d2df40b94a926d0f0faa75280bddcc4b17b6bdd9c8bfed7c34b5) +- [`{ childCreatedAt, childId, label, mode, … }`](#persistence-type-sha256-0e10d7c096b47e61defe372a5fc8bd37d835199410eac44367f95c45082498bd) - [`{ childCreatedAt, childId, label, mode, … }`](#persistence-type-sha256-e2ad8f5bcd813f268ffef1b10a12d7ddd2b8ced8b9b6d0275b3f6b7ed094a187) +- [`{ childCreatedAt, childId, label?, mode, … }`](#persistence-type-sha256-a43327a1739c3fa477f32981071fef7d8ba6ae5f32a84fd70f547b2eee59e93e) - [`{ childCreatedAt, childId, label?, mode, … }`](#persistence-type-sha256-cbbe8377ee744964537dbafd83607219e58ba79a13f6db0d0645c7ad3d5e8a09) - [`{ childCreatedAt, childId, label?, mode, … }`](#persistence-type-sha256-5d542ac7bdf13310c46e1a884dec9fb18ad8c6e153cff207e639cd7bf9d7e694) - [`{ childCreatedAt, childId, label?, mode, … }`](#persistence-type-sha256-b6896938660a1dfe4ddd100fb3164d9f8fa57feeabfe37441a80106c9942697a) - [`{ childCreatedAt, childId, label?, mode, … }`](#persistence-type-sha256-a0f25b5aeeebf2bf1542ce67726b095e3b139a39c71861d57e827f12dea1f499) -- [`{ childCreatedAt, childId, label, mode, … }`](#persistence-type-sha256-0e10d7c096b47e61defe372a5fc8bd37d835199410eac44367f95c45082498bd) @@ -5035,7 +5054,7 @@ SHA-256: `6598cd6da253948d6b207c6374a45335804c79b576866d6215649c2d1bc85e25` SHA-256: `2eafefdc6f79a4922d68a787a09eaf4dd2b2369c3777fba4c05e800b5678ac8e` -来源:[`packages/team/agent-team/src/types.ts:108`](../packages/team/agent-team/src/types.ts) +来源:[`packages/team/agent-team/src/types.ts:112`](../packages/team/agent-team/src/types.ts) | 属性 | 存在性 | 类型 | |---|---|---| @@ -5055,7 +5074,7 @@ SHA-256: `2eafefdc6f79a4922d68a787a09eaf4dd2b2369c3777fba4c05e800b5678ac8e` SHA-256: `2152caf1a71e588e4df2358a806dea24936c1c47131134f01a12939d12cdc0c0` -来源:[`packages/team/agent-team/src/types.ts:117`](../packages/team/agent-team/src/types.ts) +来源:[`packages/team/agent-team/src/types.ts:121`](../packages/team/agent-team/src/types.ts) | 属性 | 存在性 | 类型 | |---|---|---| @@ -5065,7 +5084,7 @@ SHA-256: `2152caf1a71e588e4df2358a806dea24936c1c47131134f01a12939d12cdc0c0` | `senderName` | 必需 | `string` | | `teamId` | 必需 | `string` | - + @@ -5073,7 +5092,7 @@ SHA-256: `2152caf1a71e588e4df2358a806dea24936c1c47131134f01a12939d12cdc0c0` ### `TeamTaskSnapshot` -SHA-256: `51edec100659da3a9bd9c3f6ba1180f5e64ec9a1585e5057080df45c180bd357` +SHA-256: `4018a00144474b6c60dc1aa6e5c1f03611c66bd739833779a7d20a511df6d082` 来源:[`packages/team/agent-team/src/types.ts:64`](../packages/team/agent-team/src/types.ts) @@ -5083,6 +5102,7 @@ SHA-256: `51edec100659da3a9bd9c3f6ba1180f5e64ec9a1585e5057080df45c180bd357` | `description` | 必需 | `string` | | `id` | 必需 | `string` | | `ownerId` | 可选 | `string` | +| `ownerName` | 可选 | `string` | | `revision` | 必需 | `number` | | `status` | 必需 | [`TeamTaskStatus`](#persistence-type-sha256-b2d2a01e51341a3bfec809198952c8c830a7899f4cb6ecd3c1dc0b5d9a2af943) | | `subject` | 必需 | `string` | @@ -5420,7 +5440,7 @@ SHA-256: `f1687f982fa3d41ef29e159feed154ecd13af4dd209acaee16038f223f2e9402` | `interrupted` | 未声明 | 无 | [`{ kind: "interrupted" }`](#persistence-type-sha256-56b7c047694875a843ba020dfea3c8380d54ae4ff88ab349e72004dc21e07c23) | | `max-tokens` | 未声明 | 无 | [`{ kind: "max-tokens" }`](#persistence-type-sha256-ab7ec5f9eb2c6dfacca5da4c37cf7ba85d04172053ee6b1ebf1709ffcd99c1a7) | - + @@ -5428,7 +5448,7 @@ SHA-256: `f1687f982fa3d41ef29e159feed154ecd13af4dd209acaee16038f223f2e9402` ### `UserMessage` -SHA-256: `613660455704fb82a825b5b766e000aa64b5b4d44b4f10e55cffe968d4ec6ab1` +SHA-256: `74e0e5885d2ddf04530ddf341b25cd65e1f85c00b30a88bd992f11fc06615a0c` 来源:[`packages/llm/llm/src/message.ts:162`](../packages/llm/llm/src/message.ts) @@ -5437,19 +5457,19 @@ SHA-256: `613660455704fb82a825b5b766e000aa64b5b4d44b4f10e55cffe968d4ec6ab1` | `content` | 必需 | [`ContentBlock[]`](#persistence-type-sha256-b52f215a6cd691058a3413c12f161fa3b563a2f4895adb3df6f744ec4b0a6ef1) | | `id` | 必需 | `string` | | `role` | 必需 | `"user"` | -| `source` | 必需 | [`MessageSource`](#persistence-type-sha256-b120362fd216a16a40fe787f6d3286086aa131266322bab79c026a130ccd0f72) | +| `source` | 必需 | [`MessageSource`](#persistence-type-sha256-dca3ba43188095fa7342e49e6c206d4685125497d4767595bf12a62ea2fd73ce) | 消息源兼容策略:`source` — `session-source-attribution` v1; `session.user-message.source`; `kind`; `preserve`. 仅表示归属的新增 kind:`action-cards`, `tmux-context`, `user-question-reply`, `working-directory`. - + ### `UserMessage[]` -SHA-256: `690583582246babf6120f16eefd849dd760c5ec84619014951af403a1b3032c0` +SHA-256: `8a54d228b1b7d8453e4304d32723d489f28b4b33b221f335342146926ad94fc6` -[`UserMessage`](#persistence-type-sha256-613660455704fb82a825b5b766e000aa64b5b4d44b4f10e55cffe968d4ec6ab1) 的数组。 +[`UserMessage`](#persistence-type-sha256-74e0e5885d2ddf04530ddf341b25cd65e1f85c00b30a88bd992f11fc06615a0c) 的数组。 @@ -5641,7 +5661,7 @@ SHA-256: `5d03ba38734809bcbd2a55221bd938b3b3fc34b49bb686c6113e9e4931e3aa78` SHA-256: `4cd48f3e5108bd6ebedf7301c3638839b8b2b9db8dbd493974177fbdeb91a01b` -来源:[`packages/api/session-controller/src/types.ts:389`](../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/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/team/agent-team/src/types.ts:20`](../packages/team/agent-team/src/types.ts) · [`packages/team/agent-team/src/types.ts:32`](../packages/team/agent-team/src/types.ts) · [`packages/team/agent-team/src/types.ts:8`](../packages/team/agent-team/src/types.ts) · [`packages/workflow/workflow/src/types.ts:13`](../packages/workflow/workflow/src/types.ts) +来源:[`packages/api/session-controller/src/types.ts:391`](../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/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/team/agent-team/src/types.ts:20`](../packages/team/agent-team/src/types.ts) · [`packages/team/agent-team/src/types.ts:32`](../packages/team/agent-team/src/types.ts) · [`packages/team/agent-team/src/types.ts:8`](../packages/team/agent-team/src/types.ts) · [`packages/workflow/workflow/src/types.ts:13`](../packages/workflow/workflow/src/types.ts) `string` @@ -5986,6 +6006,21 @@ SHA-256: `0e10d7c096b47e61defe372a5fc8bd37d835199410eac44367f95c45082498bd` | `mode` | 必需 | `"continuable"` | | `version` | 必需 | `0` | + + +### `{ childCreatedAt, childId, label, mode, … }` + +SHA-256: `8faed5b52ab2d2df40b94a926d0f0faa75280bddcc4b17b6bdd9c8bfed7c34b5` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `childCreatedAt` | 必需 | `number` | +| `childId` | 必需 | `string` | +| `label` | 必需 | `string` | +| `mode` | 必需 | `"continuable"` | +| `name` | 必需 | `string` | +| `version` | 必需 | `3` | + ### `{ childCreatedAt, childId, label, mode, … }` @@ -6028,6 +6063,21 @@ SHA-256: `a0f25b5aeeebf2bf1542ce67726b095e3b139a39c71861d57e827f12dea1f499` | `mode` | 必需 | `"unknown"` | | `version` | 必需 | `1` | + + +### `{ childCreatedAt, childId, label?, mode, … }` + +SHA-256: `a43327a1739c3fa477f32981071fef7d8ba6ae5f32a84fd70f547b2eee59e93e` + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `childCreatedAt` | 必需 | `number` | +| `childId` | 必需 | `string` | +| `label` | 可选 | `string` | +| `mode` | 必需 | `"external"` | +| `name` | 必需 | `string` | +| `version` | 必需 | `3` | + ### `{ childCreatedAt, childId, label?, mode, … }` @@ -6284,7 +6334,7 @@ SHA-256: `0a92c5bdfa06c2e2615b777728f3aa95f408d43b9012e7b754568311251db623` SHA-256: `c2a13242efc3bea4b36a843ddf1524ff4d33c765a71b582fa1fdbfa4fa148434` -来源:[`packages/team/agent-team/src/types.ts:173`](../packages/team/agent-team/src/types.ts) +来源:[`packages/team/agent-team/src/types.ts:177`](../packages/team/agent-team/src/types.ts) | 属性 | 存在性 | 类型 | |---|---|---| @@ -6386,18 +6436,18 @@ SHA-256: `ad0c38a0adb82a94c925456df41586d9b5f9202fca18593eae2213d4445b4585` | `reason` | 必需 | [`RequestHeaderReason`](#persistence-type-sha256-530da6c0267813bb4511af72883cc518834e624e3b3220a7062955fd57a788a6) | | `startsSeries` | 可选 | `true` | - + ### `{ headerSeq?, message, step, turn }` -SHA-256: `65377a76c6a58f785d95b89f89f2e13d289cb88a70ea74939d0ec08f429f0a6e` +SHA-256: `295809283ede248d14e6a431dec1c464cfd80a54b0d8f2a5994219fd8c8f9998` 来源:[`packages/core/session/src/types.ts:317`](../packages/core/session/src/types.ts) | 属性 | 存在性 | 类型 | |---|---|---| | `headerSeq` | 可选 | `number` | -| `message` | 必需 | [`DeveloperMessage`](#persistence-type-sha256-01c161379a3c3394a642807843e108ef911a8b7dbffd6d7de43f4484c88b0796) | +| `message` | 必需 | [`DeveloperMessage`](#persistence-type-sha256-824b1d4d4f007bdaa5eee7994a5db3ede7707c6cd2bf8e2509be176c7609e3bc) | | `step` | 必需 | `number` | | `turn` | 必需 | `number` | @@ -6481,17 +6531,17 @@ SHA-256: `17d1afb770d9941936130996da00dc86782cfef731d8d6526162c301256a4ac3` |---|---|---| | `inherited` | 可选 | `true` | - + ### `{ inserted, outcome?, removedCount?, start, … }` -SHA-256: `e1880c67e735e228f3555df8a55a492db2c0b0c71bc8859e938e184a46c7db51` +SHA-256: `f7752f518bb2f9165f2c01559df1f570c23d57373defbbd4512399a0ffaf2492` 来源:[`packages/core/agent/src/types.ts:110`](../packages/core/agent/src/types.ts) | 属性 | 存在性 | 类型 | |---|---|---| -| `inserted` | 必需 | [`UserMessage[]`](#persistence-type-sha256-690583582246babf6120f16eefd849dd760c5ec84619014951af403a1b3032c0) | +| `inserted` | 必需 | [`UserMessage[]`](#persistence-type-sha256-8a54d228b1b7d8453e4304d32723d489f28b4b33b221f335342146926ad94fc6) | | `outcome` | 可选 | `"canceled"` | | `removedCount` | 可选 | `number` | | `start` | 必需 | `number` | @@ -7251,6 +7301,21 @@ SHA-256: `db06ef35b27a38425046b2228fa6bce9582abe140d781d363137eb2f4d233a1c` | `kind` | 必需 | `"repeat-tool-reminder"` | | `sections` | 必需 | [`ContextSnapshotSection[]`](#persistence-type-sha256-c748fb42c80a120038a8c587af80ec39924803c401364db11c8974d5bf6d0262) | + + +### `{ kind: "retry" }` + +SHA-256: `8f1062573ea9184129dfdec43df1e8136eb5808746fd809bf6b539f3fd11362e` + +来源:[`packages/api/session-controller/src/types.ts:402`](../packages/api/session-controller/src/types.ts) + +| 属性 | 存在性 | 类型 | +|---|---|---| +| `clientTimeZone` | 可选 | `string` | +| `kind` | 必需 | `"retry"` | +| `principal` | 可选 | [`union (2 variants)`](#persistence-type-sha256-824a4aad44a54e245c67196817d67946734a2dc0eee0b0b6834a5b2a6ef352ce) | +| `rpcId` | 必需 | `string` | + ### `{ kind: "runtime-context" }` @@ -7761,7 +7826,7 @@ SHA-256: `8fcb0b44a575e998665c053643d1ab04c82f39253ebd190ac0c975b78e40b543` SHA-256: `a4afec59b75aad5d13ef82d6931f35cc2d98918503916cf069355b77c5e42302` -来源:[`packages/api/session-controller/src/types.ts:398`](../packages/api/session-controller/src/types.ts) +来源:[`packages/api/session-controller/src/types.ts:400`](../packages/api/session-controller/src/types.ts) | 属性 | 存在性 | 类型 | |---|---|---| @@ -7914,7 +7979,7 @@ SHA-256: `9c001ecb5e1d3c3894410db2a1e383842e5f8454fb52182338686158abc1b3ee` SHA-256: `b1ebd5cda47d90d980bb05bffc3f970c51537b9aff15b3bc3d639811727741b1` -来源:[`packages/team/agent-team/src/types.ts:175`](../packages/team/agent-team/src/types.ts) +来源:[`packages/team/agent-team/src/types.ts:179`](../packages/team/agent-team/src/types.ts) | 属性 | 存在性 | 类型 | |---|---|---| @@ -7942,7 +8007,7 @@ SHA-256: `6bc8e51124d0874bc89e1d0ceff381a9c3cd0fc240667d69f841ce4f60f65fe5` SHA-256: `ea08ec1df0c33108fd03345b9af199cf04dea450aa045d3c683f216311403403` -来源:[`packages/team/agent-team/src/types.ts:179`](../packages/team/agent-team/src/types.ts) +来源:[`packages/team/agent-team/src/types.ts:183`](../packages/team/agent-team/src/types.ts) | 属性 | 存在性 | 类型 | |---|---|---| @@ -7956,7 +8021,7 @@ SHA-256: `ea08ec1df0c33108fd03345b9af199cf04dea450aa045d3c683f216311403403` SHA-256: `0bcfaf5566d271028429ac7b562cb59053c9d78b8ae14708c35fac835108d1b1` -来源:[`packages/team/agent-team/src/types.ts:181`](../packages/team/agent-team/src/types.ts) +来源:[`packages/team/agent-team/src/types.ts:185`](../packages/team/agent-team/src/types.ts) | 属性 | 存在性 | 类型 | |---|---|---| @@ -8096,17 +8161,17 @@ SHA-256: `477614bca595a9e7adb5a1870be446b9a8684f3ba8950259d6289f2d3b74f028` |---|---|---| | `targets` | 必需 | [`ImageOffloadTarget[]`](#persistence-type-sha256-9e2c06d8653585b33d72d5c1a80da79c8a24a88c284409bca15cc0f0ead5ebfb) | - + ### `{ task, teamId, version }` -SHA-256: `a40d12070f6f4a124f32fb3cc86e7857554702e32f0eda3080a25c4b9ac9b18c` +SHA-256: `a9427866376b691aace0ce25aa0e1bdec2a14156a05152947a467da3f7967cb9` -来源:[`packages/team/agent-team/src/types.ts:177`](../packages/team/agent-team/src/types.ts) +来源:[`packages/team/agent-team/src/types.ts:181`](../packages/team/agent-team/src/types.ts) | 属性 | 存在性 | 类型 | |---|---|---| -| `task` | 必需 | [`TeamTaskSnapshot`](#persistence-type-sha256-51edec100659da3a9bd9c3f6ba1180f5e64ec9a1585e5057080df45c180bd357) | +| `task` | 必需 | [`TeamTaskSnapshot`](#persistence-type-sha256-4018a00144474b6c60dc1aa6e5c1f03611c66bd739833779a7d20a511df6d082) | | `teamId` | 必需 | `string` | | `version` | 必需 | `2` | @@ -8150,17 +8215,17 @@ SHA-256: `a10c17474eaf2ddab7095a099e0fe3d046fc18e56c3e344fc8894c05ff9ef97b` | `time` | 必需 | `number` | | `type` | 必需 | `"agent-preset/selected"` | - + ### `{ type: "agent/inbox/spliced" }` -SHA-256: `ddce54a3873dc57113b0cd38ad9b23b3c259186139e8847e5e5f415d86f52482` +SHA-256: `1682631f010d5ea717d181ed6f4ef46cde08d92a31ab461e7e98edfc98461f85` | 属性 | 存在性 | 类型 | |---|---|---| -| `data` | 必需 | [`{ inserted, outcome?, removedCount?, start, … }`](#persistence-type-sha256-e1880c67e735e228f3555df8a55a492db2c0b0c71bc8859e938e184a46c7db51) | +| `data` | 必需 | [`{ inserted, outcome?, removedCount?, start, … }`](#persistence-type-sha256-f7752f518bb2f9165f2c01559df1f570c23d57373defbbd4512399a0ffaf2492) | | `ignorable` | 可选 | `true` | | `seq` | 必需 | `number` | | `time` | 必需 | `number` | @@ -8401,17 +8466,17 @@ SHA-256: `13d3d180f977bf78081d487ffa0ecb75857349bcab29a5a3fb48189fca2a6176` | `time` | 必需 | `number` | | `type` | 必需 | `"deliverables/presented"` | - + ### `{ type: "developer/message" }` -SHA-256: `70ea8e7943c5e2d76905bcc2e694e8c3d5b138aaae3609f3e261b8d369a6e35a` +SHA-256: `510826cf4e1f9220d75c1efd90b349dd9a77fc5ba15d19e16f87e85a48db5f99` | 属性 | 存在性 | 类型 | |---|---|---| -| `data` | 必需 | [`{ headerSeq?, message, step, turn }`](#persistence-type-sha256-65377a76c6a58f785d95b89f89f2e13d289cb88a70ea74939d0ec08f429f0a6e) | +| `data` | 必需 | [`{ headerSeq?, message, step, turn }`](#persistence-type-sha256-295809283ede248d14e6a431dec1c464cfd80a54b0d8f2a5994219fd8c8f9998) | | `ignorable` | 可选 | `true` | | `seq` | 必需 | `number` | | `sourceEventSeqs` | 可选 | [`number[]`](#persistence-type-sha256-5d03ba38734809bcbd2a55221bd938b3b3fc34b49bb686c6113e9e4931e3aa78) | @@ -8811,17 +8876,17 @@ SHA-256: `1b912703e2d64f91c99c675b8f805b01076c8325b905c1218ad81ef0b24909d5` | `time` | 必需 | `number` | | `type` | 必需 | `"session/title"` | - + ### `{ type: "session/title-llm-request" }` -SHA-256: `d95c624eddecdacf1ee74356196c09d2f3fcd625714be5e852a6b643fa12a7ca` +SHA-256: `3bca25b2baa6b22be9b577621a7603497f40870ed88a8dac4383d37dc2bb6e18` | 属性 | 存在性 | 类型 | |---|---|---| -| `data` | 必需 | [`SessionTitleLlmRequestEventData`](#persistence-type-sha256-601327bedca5f98a0fa4c27133bd35749f3af2baaaacf53badf074e59cea5d25) | +| `data` | 必需 | [`SessionTitleLlmRequestEventData`](#persistence-type-sha256-bec5ca3a376f56f3d69df7f12a48e1cc07d4ea8305968773394c8734799faeb4) | | `ignorable` | 可选 | `true` | | `seq` | 必需 | `number` | | `time` | 必需 | `number` | @@ -8859,17 +8924,17 @@ SHA-256: `4513e088d43e6c68425be30451b9f961cc264fe7318ca62681c41d4d78615986` | `time` | 必需 | `number` | | `type` | 必需 | `"step/start"` | - + ### `{ type: "subagent/catalog" }` -SHA-256: `53750b9abf61efb7992b0aadc3e247ec927449c63266df28230fd1139f5590ac` +SHA-256: `d49164d37eab0f0f70fa787c65d887abbea869c010ccb103d717fab3519c3a41` | 属性 | 存在性 | 类型 | |---|---|---| -| `data` | 必需 | [`SubagentCatalogEvent`](#persistence-type-sha256-f731ffe80810b0289b3e694d8f40af6f01865c02a622ee457be90ca808b66e87) | +| `data` | 必需 | [`SubagentCatalogEvent`](#persistence-type-sha256-058fc9a6b4fbd5d43437c3a64170002070dfc98e18d87de294b564ae446ca8ae) | | `ignorable` | 可选 | `true` | | `seq` | 必需 | `number` | | `time` | 必需 | `number` | @@ -8989,17 +9054,17 @@ SHA-256: `920d87e22b7409bcc7224f8b1dc7f5101c33574c75627c65baab12b85cc96e75` | `time` | 必需 | `number` | | `type` | 必需 | `"team/mode"` | - + ### `{ type: "team/task" }` -SHA-256: `d595ec73b32b016a6055333c67a5d646032b22e672da1d4a09c5b1ae398a093a` +SHA-256: `bca0f9cb63d8620b6954bb045b07bb07cb557513a7f0e2e177f5e87f704e7ba7` | 属性 | 存在性 | 类型 | |---|---|---| -| `data` | 必需 | [`{ task, teamId, version }`](#persistence-type-sha256-a40d12070f6f4a124f32fb3cc86e7857554702e32f0eda3080a25c4b9ac9b18c) | +| `data` | 必需 | [`{ task, teamId, version }`](#persistence-type-sha256-a9427866376b691aace0ce25aa0e1bdec2a14156a05152947a467da3f7967cb9) | | `ignorable` | 可选 | `true` | | `seq` | 必需 | `number` | | `time` | 必需 | `number` | @@ -9260,17 +9325,17 @@ SHA-256: `f1a96afe7503ac1817de769cd0ba13d9b80111c7034c50106b3344ecc14cc515` | `type` | 必需 | `"usage"` | | `usage` | 必需 | [`TokenUsage`](#persistence-type-sha256-fec5442b9ee4122e10514d81d5a43648003fe8bfb7ee2ba50c0cdbdd383ed394) | - + ### `{ type: "user/message" }` -SHA-256: `dcb07e04496586d2664d72dab0e94312917da56927b2a0dc3ee53d6a33e32450` +SHA-256: `50a15408d511e9be3fa93abff37a38ae770f3ab905fc6849fee0d989200d2b97` | 属性 | 存在性 | 类型 | |---|---|---| -| `data` | 必需 | [`UserMessage`](#persistence-type-sha256-613660455704fb82a825b5b766e000aa64b5b4d44b4f10e55cffe968d4ec6ab1) | +| `data` | 必需 | [`UserMessage`](#persistence-type-sha256-74e0e5885d2ddf04530ddf341b25cd65e1f85c00b30a88bd992f11fc06615a0c) | | `ignorable` | 可选 | `true` | | `seq` | 必需 | `number` | | `sourceEventSeqs` | 可选 | [`number[]`](#persistence-type-sha256-5d03ba38734809bcbd2a55221bd938b3b3fc34b49bb686c6113e9e4931e3aa78) | diff --git a/docs/persistence-changes/2026-10-27-retry-control-input.i18n.yaml b/docs/persistence-changes/2026-10-27-retry-control-input.i18n.yaml new file mode 100644 index 0000000000..c9979c895d --- /dev/null +++ b/docs/persistence-changes/2026-10-27-retry-control-input.i18n.yaml @@ -0,0 +1,28 @@ +# Bilingual-pair consistency record for 2026-10-27-retry-control-input.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/persistence-changes/2026-10-27-retry-control-input.md +/: + en: 3d5a424ae7d7e46b + zh: c22a8e4a62d8cc1a +/2026-10-27-retry-control-input: + en: 32c7e9cc4a9f86b4 + zh: f1cb7169df15e8e4 +/2026-10-27-retry-control-input/summary: + en: 77dd9a1b2db8d968 + zh: c3d0111e34b27fe3 +/2026-10-27-retry-control-input/table-of-contents: + en: 6cf314a069ceb451 + zh: 9adff678e9ecab3b +/2026-10-27-retry-control-input/declaration: + en: 6907136f28e48c90 + zh: 02f8298485f3d8e7 +/2026-10-27-retry-control-input/compatibility: + en: 6dee29fbf0f77087 + zh: 72e0cfdef298a75e +/2026-10-27-retry-control-input/verification: + en: 06eee3f214f278b8 + zh: d044457dd6e5b8c3 +/2026-10-27-retry-control-input/dev-note: + en: b75c8458928b72b9 + zh: 003ba4e17b4b5269 diff --git a/docs/persistence-changes/2026-10-27-retry-control-input.md b/docs/persistence-changes/2026-10-27-retry-control-input.md new file mode 100644 index 0000000000..b97bfca4e8 --- /dev/null +++ b/docs/persistence-changes/2026-10-27-retry-control-input.md @@ -0,0 +1,60 @@ +--- +description: "Records a persistence type transition and its compatibility acknowledgement." +kind: persistence-change +--- + +# 2026-10-27-retry-control-input + +English | [中文](2026-10-27-retry-control-input.zh.md) + +## Summary + +Add the retry message source for empty Session API continuation prompts; ordinary user/message records retain the input identity and caller metadata. + +## Table of Contents + +- [Declaration](#declaration) +- [Compatibility](#compatibility) +- [Verification](#verification) +- [Dev Note](#dev-note) + + +## Declaration + +```yaml persistence-change +schemaVersion: 1 +id: 2026-10-27-retry-control-input +baseline: false +changes: + - root: "event:agent/inbox/spliced" + previous: "2026-10-27-subagent-settlement-attribution" + after: "1682631f010d5ea717d181ed6f4ef46cde08d92a31ab461e7e98edfc98461f85" + decision: same-version + - root: "event:developer/message" + previous: "2026-10-27-subagent-settlement-attribution" + after: "510826cf4e1f9220d75c1efd90b349dd9a77fc5ba15d19e16f87e85a48db5f99" + decision: same-version + - root: "event:session/title-llm-request" + previous: "2026-10-27-subagent-settlement-attribution" + after: "3bca25b2baa6b22be9b577621a7603497f40870ed88a8dac4383d37dc2bb6e18" + decision: same-version + - root: "event:user/message" + previous: "2026-10-27-subagent-settlement-attribution" + after: "50a15408d511e9be3fa93abff37a38ae770f3ab905fc6849fee0d989200d2b97" + decision: same-version +``` + + +## Compatibility + +The retry source is producer-owned metadata on the existing empty UserMessage representation. AgentLoop, model-history derivation, and SDK prompt behavior are unchanged. Older readers preserve extensible source metadata and consume these messages through ordinary user-message admission; they may display an empty context row. Updated readers retain historical ordinary messages and hide only empty retry messages in Chat. Existing event discriminators and the current Session version remain unchanged; no new required event is introduced. + + +## Verification + +The Session API suite passed 1112 tests across 51 files; continuation.ts has 100% statements, branches, functions, and lines. Chat and conversation tests passed 1875 tests across 113 files; final focused Chat and input regressions passed 96 and 31 tests. The browser continuation replay passed with an empty retry user message retained in the log, no empty Chat bubble, and normally closed turns. Build passed all 10 gates, typed lint exited 0, and doc-sync passed all 43 gates. Git comparison against the PR base confirms no AgentLoop, Core Agent, Core Session, or SDK changes. + + +## Dev Note + +None. diff --git a/docs/persistence-changes/2026-10-27-retry-control-input.schema.json b/docs/persistence-changes/2026-10-27-retry-control-input.schema.json new file mode 100644 index 0000000000..0a5d3dab79 --- /dev/null +++ b/docs/persistence-changes/2026-10-27-retry-control-input.schema.json @@ -0,0 +1,261 @@ +{ + "formatVersion": 2, + "roots": [ + {"key":"event:agent/inbox/spliced","kind":"event","event":"agent/inbox/spliced","surface":false,"digest":"1682631f010d5ea717d181ed6f4ef46cde08d92a31ab461e7e98edfc98461f85"}, + {"key":"event:developer/message","kind":"event","event":"developer/message","surface":true,"digest":"510826cf4e1f9220d75c1efd90b349dd9a77fc5ba15d19e16f87e85a48db5f99"}, + {"key":"event:session/title-llm-request","kind":"event","event":"session/title-llm-request","surface":false,"digest":"3bca25b2baa6b22be9b577621a7603497f40870ed88a8dac4383d37dc2bb6e18"}, + {"key":"event:user/message","kind":"event","event":"user/message","surface":true,"digest":"50a15408d511e9be3fa93abff37a38ae770f3ab905fc6849fee0d989200d2b97"} + ], + "types": [], + "nodes": { + "0203243b72fc867a": {"kind":"object","properties":[{"name":"kind","type":"24b10f7cdae64928","optional":false}],"indices":[]}, + "022623b9ef98ec47": {"kind":"object","properties":[{"name":"form","type":"383cf73ae4748e5b","optional":false},{"name":"kind","type":"f68c335306535a00","optional":false}],"indices":[]}, + "02b2c23f2d94b028": {"kind":"object","properties":[{"name":"kind","type":"c5687b1313206a6f","optional":false}],"indices":[]}, + "05205074b24d8340": {"kind":"literal","value":"action-cards"}, + "0657d3ca5ac4e7bf": {"kind":"primitive","type":"number"}, + "07e1a58c58b593f5": {"kind":"object","properties":[{"name":"model","type":"4cd48f3e5108bd6e","optional":false},{"name":"provider","type":"4cd48f3e5108bd6e","optional":false}],"indices":[]}, + "09655b34d7f3cf1e": {"kind":"literal","value":"system-prompt"}, + "09f3f8dc417f2782": {"kind":"object","properties":[{"name":"content","type":"b52f215a6cd69105","optional":false},{"name":"id","type":"4cd48f3e5108bd6e","optional":false},{"name":"role","type":"8af841fc9b265ade","optional":false},{"name":"source","type":"65a8400e451e667e","optional":false}],"indices":[]}, + "0a92c5bdfa06c2e2": {"kind":"object","properties":[{"name":"displayName","type":"4cd48f3e5108bd6e","optional":true},{"name":"providerId","type":"4cd48f3e5108bd6e","optional":false},{"name":"subjectId","type":"4cd48f3e5108bd6e","optional":false},{"name":"tenantId","type":"4cd48f3e5108bd6e","optional":false}],"indices":[]}, + "0ed8d1108fe7a5e1": {"kind":"object","properties":[{"name":"kind","type":"a9059a81430b3207","optional":false}],"indices":[]}, + "0eeb17e1df89b1eb": {"kind":"object","properties":[{"name":"form","type":"fee1caf8ab6a65c1","optional":false},{"name":"kind","type":"24b10f7cdae64928","optional":false}],"indices":[]}, + "0f46153645c29784": {"kind":"object","properties":[{"name":"height","type":"0657d3ca5ac4e7bf","optional":false},{"name":"width","type":"0657d3ca5ac4e7bf","optional":false}],"indices":[]}, + "0fe52387f6505270": {"kind":"literal","value":"plan-mode"}, + "11638dc58a31496f": {"kind":"object","properties":[{"name":"form","type":"6f9e00383836275e","optional":false},{"name":"kind","type":"2f3f201c8846e19c","optional":false},{"name":"sections","type":"c748fb42c80a1200","optional":false}],"indices":[]}, + "12d5808fac1996b9": {"kind":"object","properties":[{"name":"attachment","type":"b0b0eb1b16490f6b","optional":false},{"name":"offloaded","type":"dacf3d5f3e4ff619","optional":true},{"name":"type","type":"fb8b6a2e53cb9cf4","optional":false}],"indices":[]}, + "1379f0b72275994d": {"kind":"literal","value":"developer/message"}, + "1682631f010d5ea7": {"kind":"object","properties":[{"name":"data","type":"f7752f518bb2f916","optional":false},{"name":"ignorable","type":"dacf3d5f3e4ff619","optional":true},{"name":"seq","type":"0657d3ca5ac4e7bf","optional":false},{"name":"time","type":"0657d3ca5ac4e7bf","optional":false},{"name":"type","type":"829a2fb3be6efd4b","optional":false}],"indices":[]}, + "16d0507cb94b4cfc": {"kind":"literal","value":"relay"}, + "1922cd79a70806c1": {"kind":"literal","value":"skill-invocation"}, + "1938c8c20f1cba7c": {"kind":"object","properties":[{"name":"form","type":"fee1caf8ab6a65c1","optional":false},{"name":"kind","type":"d9edf1862e4471d6","optional":false}],"indices":[]}, + "1e0b0b66b6f0c53f": {"kind":"literal","value":"aborted"}, + "1e709346005826eb": {"kind":"object","properties":[{"name":"form","type":"aec150797b655c5f","optional":false},{"name":"kind","type":"d9edf1862e4471d6","optional":false}],"indices":[]}, + "1ebc6f9ff3aa9e3a": {"kind":"literal","value":"completed"}, + "1f0133217eeeffd8": {"kind":"literal","value":"tool-call"}, + "1f1385dbc3e875c0": {"kind":"literal","value":"repeat-tool-reminder"}, + "1fdad624334d3548": {"kind":"object","properties":[{"name":"form","type":"16d0507cb94b4cfc","optional":false},{"name":"kind","type":"bb94f3217aa56c88","optional":false}],"indices":[]}, + "2152caf1a71e588e": {"kind":"object","properties":[{"name":"kind","type":"2e4debca12f2c449","optional":false},{"name":"messageId","type":"4cd48f3e5108bd6e","optional":false},{"name":"senderId","type":"4cd48f3e5108bd6e","optional":false},{"name":"senderName","type":"4cd48f3e5108bd6e","optional":false},{"name":"teamId","type":"4cd48f3e5108bd6e","optional":false}],"indices":[]}, + "2235d957bf4b7c6c": {"kind":"object","properties":[{"name":"kind","type":"7b1ce60193fa8b69","optional":false}],"indices":[]}, + "224aa11d4d5f88c4": {"kind":"object","properties":[{"name":"form","type":"fee1caf8ab6a65c1","optional":false},{"name":"kind","type":"23af3759678a30de","optional":false}],"indices":[]}, + "23af3759678a30de": {"kind":"literal","value":"dsh-session-title-llm"}, + "24b10f7cdae64928": {"kind":"literal","value":"runtime-context"}, + "24ce31aa528272e5": {"kind":"object","properties":[{"name":"kind","type":"99e7e7d7fed55ae6","optional":false}],"indices":[]}, + "260523b412c19ad8": {"kind":"object","properties":[{"name":"form","type":"aec150797b655c5f","optional":false},{"name":"kind","type":"2f3f201c8846e19c","optional":false}],"indices":[]}, + "2765e9119edf5816": {"kind":"literal","value":"model"}, + "277b61f9c6f81704": {"kind":"literal","value":"file"}, + "28936c614bd4e7e2": {"kind":"object","properties":[{"name":"form","type":"6f9e00383836275e","optional":false},{"name":"kind","type":"d9edf1862e4471d6","optional":false},{"name":"sections","type":"c748fb42c80a1200","optional":false}],"indices":[]}, + "290f32bfd81ff85a": {"kind":"object","properties":[{"name":"kind","type":"23af3759678a30de","optional":false}],"indices":[]}, + "295809283ede248d": {"kind":"object","properties":[{"name":"headerSeq","type":"0657d3ca5ac4e7bf","optional":true},{"name":"message","type":"824b1d4d4f007bda","optional":false},{"name":"step","type":"0657d3ca5ac4e7bf","optional":false},{"name":"turn","type":"0657d3ca5ac4e7bf","optional":false}],"indices":[]}, + "297fbd8067d7815a": {"kind":"object","properties":[{"name":"form","type":"aec150797b655c5f","optional":false},{"name":"kind","type":"a9059a81430b3207","optional":false}],"indices":[]}, + "2aad1179f9576314": {"kind":"object","properties":[{"name":"form","type":"6f9e00383836275e","optional":false},{"name":"kind","type":"24b10f7cdae64928","optional":false},{"name":"sections","type":"c748fb42c80a1200","optional":false}],"indices":[]}, + "2ab12a0e345658f9": {"kind":"array","element":"83da72c6857601c7"}, + "2e4debca12f2c449": {"kind":"literal","value":"team-message"}, + "2f1e6a7ebace43d7": {"kind":"union","types":["3f74ba74acd10644","58f94390b982f8a5","de30b1fa12c75f81","ebb768d85ec87fb6"]}, + "2f3f201c8846e19c": {"kind":"literal","value":"tool-goal"}, + "312aee2f0c42aabb": {"kind":"object","properties":[{"name":"form","type":"e8de0f457fed5b9f","optional":false},{"name":"kind","type":"d9edf1862e4471d6","optional":false},{"name":"summary","type":"4cd48f3e5108bd6e","optional":false}],"indices":[]}, + "31907de956375182": {"kind":"object","properties":[{"name":"compactionId","type":"4cd48f3e5108bd6e","optional":false},{"name":"kind","type":"6b23ed9ce1b397e6","optional":false},{"name":"sourceCommandId","type":"4cd48f3e5108bd6e","optional":true}],"indices":[]}, + "3247e566f4340029": {"kind":"object","properties":[{"name":"form","type":"6f9e00383836275e","optional":false},{"name":"kind","type":"05205074b24d8340","optional":false},{"name":"sections","type":"c748fb42c80a1200","optional":false},{"name":"through","type":"0657d3ca5ac4e7bf","optional":false}],"indices":[]}, + "335e242de1fcc17b": {"kind":"union","types":["bcf0caf62d964b2f","e438a9d4fb883b3e"]}, + "383cf73ae4748e5b": {"kind":"literal","value":"recall"}, + "3b04790e08b35241": {"kind":"object","properties":[{"name":"form","type":"aec150797b655c5f","optional":false},{"name":"kind","type":"0fe52387f6505270","optional":false}],"indices":[]}, + "3b4f2c9ef2c1217e": {"kind":"object","properties":[{"name":"form","type":"383cf73ae4748e5b","optional":false},{"name":"kind","type":"bb94f3217aa56c88","optional":false}],"indices":[]}, + "3bca25b2baa6b22b": {"kind":"object","properties":[{"name":"data","type":"bec5ca3a376f56f3","optional":false},{"name":"ignorable","type":"dacf3d5f3e4ff619","optional":true},{"name":"seq","type":"0657d3ca5ac4e7bf","optional":false},{"name":"time","type":"0657d3ca5ac4e7bf","optional":false},{"name":"type","type":"587bb11da730e06a","optional":false}],"indices":[]}, + "3bd652ebfa8726b3": {"kind":"union","types":["0657d3ca5ac4e7bf","938f7c7357bc403e"]}, + "3bdb8dc6989655b0": {"kind":"object","properties":[{"name":"form","type":"6f9e00383836275e","optional":false},{"name":"kind","type":"a9059a81430b3207","optional":false},{"name":"sections","type":"c748fb42c80a1200","optional":false}],"indices":[]}, + "3c2535ca0a2062f1": {"kind":"literal","value":"reasoning"}, + "3e2ece4967cfebe9": {"kind":"literal","value":"next-step"}, + "3f74ba74acd10644": {"kind":"literal","value":"image/jpeg"}, + "408927267422a7b2": {"kind":"object","properties":[{"name":"form","type":"fee1caf8ab6a65c1","optional":false},{"name":"kind","type":"0fe52387f6505270","optional":false}],"indices":[]}, + "42e2ff61928fb7df": {"kind":"array","element":"c51f0d0a405bb96f"}, + "43e311235aa537df": {"kind":"object","properties":[{"name":"toolName","type":"4cd48f3e5108bd6e","optional":false},{"name":"type","type":"83d6916021eede8f","optional":false}],"indices":[]}, + "45f005e6bbb76452": {"kind":"object","properties":[{"name":"form","type":"16d0507cb94b4cfc","optional":false},{"name":"kind","type":"05205074b24d8340","optional":false},{"name":"through","type":"0657d3ca5ac4e7bf","optional":false}],"indices":[]}, + "4991dfc415c9efeb": {"kind":"object","properties":[{"name":"form","type":"16d0507cb94b4cfc","optional":false},{"name":"kind","type":"1f1385dbc3e875c0","optional":false}],"indices":[]}, + "49dab019d00e8c26": {"kind":"object","properties":[{"name":"form","type":"6f9e00383836275e","optional":false},{"name":"kind","type":"78a9be340090b735","optional":false},{"name":"sections","type":"c748fb42c80a1200","optional":false}],"indices":[]}, + "4a561c111a78d452": {"kind":"literal","value":"refusal"}, + "4a9bef9f27a94252": {"kind":"object","properties":[{"name":"form","type":"16d0507cb94b4cfc","optional":false},{"name":"kind","type":"82470020b5bfcb1a","optional":false},{"name":"senderSessionId","type":"4cd48f3e5108bd6e","optional":false}],"indices":[]}, + "4b259f7f8f0a44ad": {"kind":"object","properties":[{"name":"content","type":"b52f215a6cd69105","optional":false},{"name":"id","type":"4cd48f3e5108bd6e","optional":false},{"name":"isError","type":"aa93010d0e521ad7","optional":true},{"name":"role","type":"a13d8f379222ece8","optional":false},{"name":"source","type":"d9c462b9f62fdd3e","optional":false},{"name":"toolCallId","type":"4cd48f3e5108bd6e","optional":false}],"indices":[]}, + "4cd48f3e5108bd6e": {"kind":"primitive","type":"string"}, + "4d60dddaa65d3da8": {"kind":"object","properties":[{"name":"actor","type":"0a92c5bdfa06c2e2","optional":false},{"name":"kind","type":"6ba7edb6447b6a3e","optional":false},{"name":"shareId","type":"4cd48f3e5108bd6e","optional":false}],"indices":[]}, + "4e44c9118152f682": {"kind":"literal","value":"text"}, + "4e88776858652856": {"kind":"object","properties":[{"name":"text","type":"4cd48f3e5108bd6e","optional":false},{"name":"type","type":"4e44c9118152f682","optional":false}],"indices":[]}, + "4edec1b770e8ec4c": {"kind":"literal","value":"ptc-mode"}, + "4f91f187baeabef5": {"kind":"object","properties":[{"name":"capturedFormatVersion","type":"0657d3ca5ac4e7bf","optional":true},{"name":"capturedThroughSeq","type":"3bd652ebfa8726b3","optional":false},{"name":"compacted","type":"aa93010d0e521ad7","optional":false},{"name":"inputIndex","type":"0657d3ca5ac4e7bf","optional":false},{"name":"label","type":"4cd48f3e5108bd6e","optional":false},{"name":"omittedBytes","type":"0657d3ca5ac4e7bf","optional":false},{"name":"omittedMessages","type":"0657d3ca5ac4e7bf","optional":false},{"name":"originalMessages","type":"0657d3ca5ac4e7bf","optional":false},{"name":"retainedMessages","type":"0657d3ca5ac4e7bf","optional":false},{"name":"sessionId","type":"4cd48f3e5108bd6e","optional":false},{"name":"truncated","type":"aa93010d0e521ad7","optional":false}],"indices":[]}, + "50a15408d511e9be": {"kind":"object","properties":[{"name":"data","type":"74e0e5885d2ddf04","optional":false},{"name":"ignorable","type":"dacf3d5f3e4ff619","optional":true},{"name":"seq","type":"0657d3ca5ac4e7bf","optional":false},{"name":"sourceEventSeqs","type":"5d03ba38734809bc","optional":true},{"name":"surfaceOp","type":"335e242de1fcc17b","optional":false},{"name":"time","type":"0657d3ca5ac4e7bf","optional":false},{"name":"type","type":"de25352d2dc41963","optional":false}],"indices":[]}, + "510826cf4e1f9220": {"kind":"object","properties":[{"name":"data","type":"295809283ede248d","optional":false},{"name":"ignorable","type":"dacf3d5f3e4ff619","optional":true},{"name":"seq","type":"0657d3ca5ac4e7bf","optional":false},{"name":"sourceEventSeqs","type":"5d03ba38734809bc","optional":true},{"name":"surfaceOp","type":"335e242de1fcc17b","optional":false},{"name":"time","type":"0657d3ca5ac4e7bf","optional":false},{"name":"type","type":"1379f0b72275994d","optional":false}],"indices":[]}, + "52c6113cb0e53f34": {"kind":"object","properties":[{"name":"form","type":"6f9e00383836275e","optional":false},{"name":"kind","type":"9ac52f0f84fec2eb","optional":false},{"name":"sections","type":"c748fb42c80a1200","optional":false}],"indices":[]}, + "53cf1704ae0709c7": {"kind":"object","properties":[{"name":"form","type":"fee1caf8ab6a65c1","optional":false},{"name":"kind","type":"99e7e7d7fed55ae6","optional":false}],"indices":[]}, + "5654685d7557ec74": {"kind":"object","properties":[{"name":"form","type":"6f9e00383836275e","optional":false},{"name":"kind","type":"f68c335306535a00","optional":false},{"name":"sections","type":"c748fb42c80a1200","optional":false}],"indices":[]}, + "58015da1c1950a66": {"kind":"object","properties":[{"name":"form","type":"aec150797b655c5f","optional":false},{"name":"kind","type":"24b10f7cdae64928","optional":false}],"indices":[]}, + "587bb11da730e06a": {"kind":"literal","value":"session/title-llm-request"}, + "589d0d91239681f8": {"kind":"literal","value":"developer"}, + "58f94390b982f8a5": {"kind":"literal","value":"image/png"}, + "5bb69b88517f6214": {"kind":"object","properties":[{"name":"form","type":"e8de0f457fed5b9f","optional":false},{"name":"kind","type":"99e7e7d7fed55ae6","optional":false},{"name":"summary","type":"4cd48f3e5108bd6e","optional":false}],"indices":[]}, + "5bc66269cfaf614c": {"kind":"object","properties":[{"name":"form","type":"16d0507cb94b4cfc","optional":false},{"name":"kind","type":"d9edf1862e4471d6","optional":false}],"indices":[]}, + "5cdbf342b7748d15": {"kind":"object","properties":[{"name":"form","type":"16d0507cb94b4cfc","optional":false},{"name":"kind","type":"f68c335306535a00","optional":false}],"indices":[]}, + "5d03ba38734809bc": {"kind":"array","element":"0657d3ca5ac4e7bf"}, + "5d7a64ed6aac5551": {"kind":"object","properties":[{"name":"form","type":"16d0507cb94b4cfc","optional":false},{"name":"kind","type":"8067b0d232c350f1","optional":false}],"indices":[]}, + "6085488d223aeffd": {"kind":"object","properties":[{"name":"form","type":"fee1caf8ab6a65c1","optional":false},{"name":"kind","type":"2f3f201c8846e19c","optional":false}],"indices":[]}, + "6292bcbedaa97fea": {"kind":"object","properties":[{"name":"kind","type":"f68c335306535a00","optional":false}],"indices":[]}, + "62ecb62dc0fe1b5e": {"kind":"literal","value":"next-turn"}, + "63ba8895cc09e469": {"kind":"literal","value":"retry"}, + "65a8400e451e667e": {"kind":"object","properties":[{"name":"kind","type":"09655b34d7f3cf1e","optional":false}],"indices":[]}, + "65d583e66518c523": {"kind":"object","properties":[{"name":"entries","type":"aba175fb20ffc711","optional":false},{"name":"form","type":"aec150797b655c5f","optional":false},{"name":"incomplete","type":"dacf3d5f3e4ff619","optional":true},{"name":"kind","type":"6ebcc2dbec9f2dab","optional":false},{"name":"update","type":"dacf3d5f3e4ff619","optional":true}],"indices":[]}, + "672c4aa2a9b736e3": {"kind":"object","properties":[{"name":"form","type":"fee1caf8ab6a65c1","optional":false},{"name":"kind","type":"1922cd79a70806c1","optional":false},{"name":"name","type":"4cd48f3e5108bd6e","optional":false}],"indices":[]}, + "68141cbe3994a5ff": {"kind":"literal","value":"max-tokens"}, + "68f44f59e91c4139": {"kind":"literal","value":"user"}, + "6b23ed9ce1b397e6": {"kind":"literal","value":"compact-checkpoint"}, + "6ba7edb6447b6a3e": {"kind":"literal","value":"share-viewer"}, + "6ccb6bc423fb3952": {"kind":"object","properties":[{"name":"form","type":"e8de0f457fed5b9f","optional":false},{"name":"kind","type":"f68c335306535a00","optional":false},{"name":"summary","type":"4cd48f3e5108bd6e","optional":false}],"indices":[]}, + "6ea608bdc8a7a63d": {"kind":"object","properties":[{"name":"form","type":"16d0507cb94b4cfc","optional":false},{"name":"kind","type":"a9059a81430b3207","optional":false}],"indices":[]}, + "6ebcc2dbec9f2dab": {"kind":"literal","value":"skill-catalog"}, + "6f22a9d02b9a1f11": {"kind":"object","properties":[{"name":"baseline","type":"dacf3d5f3e4ff619","optional":true},{"name":"baselineIdentity","type":"4cd48f3e5108bd6e","optional":true},{"name":"changes","type":"2ab12a0e345658f9","optional":false},{"name":"form","type":"fee1caf8ab6a65c1","optional":false},{"name":"kind","type":"fbd2c74b346a1595","optional":false}],"indices":[]}, + "6f44f32be9bcd9a8": {"kind":"object","properties":[{"name":"form","type":"fee1caf8ab6a65c1","optional":false},{"name":"kind","type":"1f1385dbc3e875c0","optional":false}],"indices":[]}, + "6f9e00383836275e": {"kind":"literal","value":"snapshot"}, + "719c51f67074f970": {"kind":"object","properties":[{"name":"kind","type":"2765e9119edf5816","optional":false},{"name":"model","type":"4cd48f3e5108bd6e","optional":false},{"name":"provider","type":"4cd48f3e5108bd6e","optional":false},{"name":"replayState","type":"bbc5696e3f13c758","optional":true}],"indices":[]}, + "7382c4fc95fe8c5d": {"kind":"literal","value":"remove"}, + "74e0e5885d2ddf04": {"kind":"object","properties":[{"name":"content","type":"b52f215a6cd69105","optional":false},{"name":"id","type":"4cd48f3e5108bd6e","optional":false},{"name":"role","type":"68f44f59e91c4139","optional":false},{"name":"source","type":"dca3ba43188095fa","optional":false,"compatibility":{"version":1,"policy":"session-source-attribution","binding":"session.user-message.source","discriminator":"kind","unknownKinds":"preserve","attributionKinds":["action-cards","tmux-context","user-question-reply","working-directory"]}}],"indices":[]}, + "7554565be416b034": {"kind":"object","properties":[{"name":"form","type":"383cf73ae4748e5b","optional":false},{"name":"kind","type":"2f3f201c8846e19c","optional":false}],"indices":[]}, + "756b5e23a5cb2c7f": {"kind":"object","properties":[{"name":"form","type":"383cf73ae4748e5b","optional":false},{"name":"kind","type":"8067b0d232c350f1","optional":false}],"indices":[]}, + "78a9be340090b735": {"kind":"literal","value":"tmux-context"}, + "7b1ce60193fa8b69": {"kind":"literal","value":"working-directory"}, + "7df62978a2b7de85": {"kind":"object","properties":[{"name":"form","type":"aec150797b655c5f","optional":false},{"name":"kind","type":"78a9be340090b735","optional":false}],"indices":[]}, + "7eaef7a763ba5b94": {"kind":"object","properties":[{"name":"form","type":"16d0507cb94b4cfc","optional":false},{"name":"kind","type":"23af3759678a30de","optional":false}],"indices":[]}, + "7f13860ee89a2d35": {"kind":"literal","value":"session-reference"}, + "7f959241c24128b4": {"kind":"object","properties":[{"name":"goalId","type":"4cd48f3e5108bd6e","optional":false},{"name":"kind","type":"b815d7b91cdd9fc6","optional":false},{"name":"revision","type":"0657d3ca5ac4e7bf","optional":false},{"name":"round","type":"0657d3ca5ac4e7bf","optional":false}],"indices":[]}, + "8064c03c87c357fd": {"kind":"union","types":["12d5808fac1996b9","43e311235aa537df","4e88776858652856","814d9434e1ddf907","8e611bf46821e500","c1f0f17b6493b85d","f2da0f27c1e6add5"]}, + "80677c8c8b804189": {"kind":"object","properties":[{"name":"form","type":"aec150797b655c5f","optional":false},{"name":"kind","type":"23af3759678a30de","optional":false}],"indices":[]}, + "8067b0d232c350f1": {"kind":"literal","value":"time-context"}, + "814d9434e1ddf907": {"kind":"object","properties":[{"name":"text","type":"4cd48f3e5108bd6e","optional":false},{"name":"type","type":"3c2535ca0a2062f1","optional":false}],"indices":[]}, + "82470020b5bfcb1a": {"kind":"literal","value":"agent-message"}, + "824a4aad44a54e24": {"kind":"union","types":["4d60dddaa65d3da8","deebfc7c62177ea8"]}, + "824b1d4d4f007bda": {"kind":"object","properties":[{"name":"content","type":"b52f215a6cd69105","optional":false},{"name":"id","type":"4cd48f3e5108bd6e","optional":false},{"name":"role","type":"589d0d91239681f8","optional":false},{"name":"source","type":"dca3ba43188095fa","optional":false,"compatibility":{"version":1,"policy":"session-source-attribution","binding":"session.developer-message.source","discriminator":"kind","unknownKinds":"preserve","attributionKinds":["action-cards","tmux-context","user-question-reply","working-directory"]}}],"indices":[]}, + "825ca23416b1ea9d": {"kind":"object","properties":[{"name":"form","type":"aec150797b655c5f","optional":false},{"name":"kind","type":"f68c335306535a00","optional":false}],"indices":[]}, + "829a2fb3be6efd4b": {"kind":"literal","value":"agent/inbox/spliced"}, + "83079c8a3f733ac3": {"kind":"object","properties":[{"name":"description","type":"4cd48f3e5108bd6e","optional":false},{"name":"name","type":"4cd48f3e5108bd6e","optional":false}],"indices":[]}, + "8338ee303e2bd448": {"kind":"object","properties":[{"name":"form","type":"e8de0f457fed5b9f","optional":false},{"name":"kind","type":"23af3759678a30de","optional":false},{"name":"summary","type":"4cd48f3e5108bd6e","optional":false}],"indices":[]}, + "83d6916021eede8f": {"kind":"literal","value":"tool-removal"}, + "83da72c6857601c7": {"kind":"object","properties":[{"name":"action","type":"904bf499d98be4a3","optional":false},{"name":"digest","type":"4cd48f3e5108bd6e","optional":true},{"name":"path","type":"4cd48f3e5108bd6e","optional":false},{"name":"scope","type":"4cd48f3e5108bd6e","optional":false}],"indices":[]}, + "848639f8787f035b": {"kind":"object","properties":[{"name":"form","type":"e8de0f457fed5b9f","optional":false},{"name":"kind","type":"bf16d2e98a7f1389","optional":false},{"name":"senderSessionId","type":"4cd48f3e5108bd6e","optional":false},{"name":"stopReason","type":"866f7b2dbdc5b421","optional":true},{"name":"summary","type":"4cd48f3e5108bd6e","optional":false}],"indices":[]}, + "854db3efdfb0cd39": {"kind":"object","properties":[{"name":"form","type":"e8de0f457fed5b9f","optional":false},{"name":"kind","type":"bb94f3217aa56c88","optional":false},{"name":"summary","type":"4cd48f3e5108bd6e","optional":false}],"indices":[]}, + "85d6d96ff8842974": {"kind":"literal","value":"answered"}, + "85f9b505b7bdff1f": {"kind":"literal","value":"tool-addition"}, + "85fe96bf15d5c755": {"kind":"object","properties":[{"name":"form","type":"aec150797b655c5f","optional":false},{"name":"kind","type":"8067b0d232c350f1","optional":false}],"indices":[]}, + "8620189c8e335827": {"kind":"object","properties":[{"name":"form","type":"383cf73ae4748e5b","optional":false},{"name":"kind","type":"1f1385dbc3e875c0","optional":false}],"indices":[]}, + "866f7b2dbdc5b421": {"kind":"union","types":["1e0b0b66b6f0c53f","1ebc6f9ff3aa9e3a","4a561c111a78d452","68141cbe3994a5ff","a2be0f0cb59f0d4a"]}, + "86e1e384495ee09a": {"kind":"object","properties":[{"name":"name","type":"4cd48f3e5108bd6e","optional":false},{"name":"text","type":"4cd48f3e5108bd6e","optional":false}],"indices":[]}, + "87b1a33564b9a4d6": {"kind":"object","properties":[{"name":"form","type":"383cf73ae4748e5b","optional":false},{"name":"kind","type":"a9059a81430b3207","optional":false}],"indices":[]}, + "88841202942c7683": {"kind":"object","properties":[{"name":"form","type":"6f9e00383836275e","optional":false},{"name":"kind","type":"bb94f3217aa56c88","optional":false},{"name":"sections","type":"c748fb42c80a1200","optional":false}],"indices":[]}, + "8a046b52331959aa": {"kind":"object","properties":[{"name":"kind","type":"78a9be340090b735","optional":false}],"indices":[]}, + "8a54d228b1b7d845": {"kind":"array","element":"74e0e5885d2ddf04"}, + "8af841fc9b265ade": {"kind":"literal","value":"system"}, + "8c1c4f72755a78ea": {"kind":"object","properties":[{"name":"form","type":"6f9e00383836275e","optional":false},{"name":"kind","type":"0fe52387f6505270","optional":false},{"name":"sections","type":"c748fb42c80a1200","optional":false}],"indices":[]}, + "8c627d7a45fa406c": {"kind":"object","properties":[{"name":"form","type":"e8de0f457fed5b9f","optional":false},{"name":"kind","type":"2f3f201c8846e19c","optional":false},{"name":"summary","type":"4cd48f3e5108bd6e","optional":false}],"indices":[]}, + "8e611bf46821e500": {"kind":"object","properties":[{"name":"tool","type":"fcf427290c6213c2","optional":true},{"name":"toolName","type":"4cd48f3e5108bd6e","optional":false},{"name":"type","type":"85f9b505b7bdff1f","optional":false}],"indices":[]}, + "8f1062573ea91841": {"kind":"object","properties":[{"name":"clientTimeZone","type":"4cd48f3e5108bd6e","optional":true},{"name":"kind","type":"63ba8895cc09e469","optional":false},{"name":"principal","type":"824a4aad44a54e24","optional":true},{"name":"rpcId","type":"4cd48f3e5108bd6e","optional":false}],"indices":[]}, + "8f324cea3916c051": {"kind":"object","properties":[{"name":"form","type":"16d0507cb94b4cfc","optional":false},{"name":"kind","type":"2f3f201c8846e19c","optional":false}],"indices":[]}, + "8fcb0b44a575e998": {"kind":"object","properties":[{"name":"kind","type":"a720757f704a2512","optional":false}],"indices":[]}, + "904bf499d98be4a3": {"kind":"union","types":["7382c4fc95fe8c5d","b765ee31033cea46","f6cb462f808309e3"]}, + "938f7c7357bc403e": {"kind":"primitive","type":"null"}, + "95a3ffccbf3c8afc": {"kind":"literal","value":"owner"}, + "95c0e88fcf0bafb2": {"kind":"literal","value":"assistant"}, + "9645cf93769a6dfb": {"kind":"literal","value":"user-question-reply"}, + "96bfb916a727cd44": {"kind":"object","properties":[{"name":"form","type":"383cf73ae4748e5b","optional":false},{"name":"kind","type":"24b10f7cdae64928","optional":false}],"indices":[]}, + "96f4a9c81fc0f940": {"kind":"union","types":["3e2ece4967cfebe9","62ecb62dc0fe1b5e"]}, + "99135d8a39379779": {"kind":"object","properties":[{"name":"form","type":"aec150797b655c5f","optional":false},{"name":"kind","type":"9ac52f0f84fec2eb","optional":false}],"indices":[]}, + "99e7e7d7fed55ae6": {"kind":"literal","value":"tool-jobs"}, + "99f0e98184709ad1": {"kind":"object","properties":[{"name":"form","type":"aec150797b655c5f","optional":false},{"name":"kind","type":"bb94f3217aa56c88","optional":false}],"indices":[]}, + "9ac52f0f84fec2eb": {"kind":"literal","value":"model-selection"}, + "9edc162949abf93b": {"kind":"object","properties":[{"name":"deliveryId","type":"4cd48f3e5108bd6e","optional":false},{"name":"form","type":"e8de0f457fed5b9f","optional":false},{"name":"kind","type":"db6c5246911d47a7","optional":false},{"name":"provider","type":"4cd48f3e5108bd6e","optional":false},{"name":"ruleId","type":"4cd48f3e5108bd6e","optional":false},{"name":"source","type":"4cd48f3e5108bd6e","optional":false},{"name":"summary","type":"4cd48f3e5108bd6e","optional":false}],"indices":[]}, + "9f65c43e340bba31": {"kind":"object","properties":[{"name":"form","type":"fee1caf8ab6a65c1","optional":false},{"name":"kind","type":"78a9be340090b735","optional":false}],"indices":[]}, + "a13d8f379222ece8": {"kind":"literal","value":"tool"}, + "a15a19ef63cf5d1b": {"kind":"object","properties":[{"name":"form","type":"16d0507cb94b4cfc","optional":false},{"name":"kind","type":"9ac52f0f84fec2eb","optional":false}],"indices":[]}, + "a16e567c8cd2c55c": {"kind":"object","properties":[{"name":"form","type":"383cf73ae4748e5b","optional":false},{"name":"kind","type":"d9edf1862e4471d6","optional":false}],"indices":[]}, + "a2066bd52f61218b": {"kind":"object","properties":[{"name":"kind","type":"2f3f201c8846e19c","optional":false}],"indices":[]}, + "a2be0f0cb59f0d4a": {"kind":"literal","value":"error"}, + "a3c6f1ea38e9a61d": {"kind":"object","properties":[{"name":"form","type":"e8de0f457fed5b9f","optional":false},{"name":"kind","type":"9ac52f0f84fec2eb","optional":false},{"name":"summary","type":"4cd48f3e5108bd6e","optional":false}],"indices":[]}, + "a4afec59b75aad5d": {"kind":"object","properties":[{"name":"clientTimeZone","type":"4cd48f3e5108bd6e","optional":true},{"name":"kind","type":"68f44f59e91c4139","optional":false},{"name":"principal","type":"824a4aad44a54e24","optional":true},{"name":"rpcId","type":"4cd48f3e5108bd6e","optional":false}],"indices":[]}, + "a720757f704a2512": {"kind":"literal","value":"tool-registry"}, + "a9059a81430b3207": {"kind":"literal","value":"hooks-claude-code"}, + "aa2bf9e82b9fdeb9": {"kind":"object","properties":[{"name":"form","type":"fee1caf8ab6a65c1","optional":false},{"name":"kind","type":"f68c335306535a00","optional":false}],"indices":[]}, + "aa93010d0e521ad7": {"kind":"primitive","type":"boolean"}, + "aae343bc3d663c83": {"kind":"object","properties":[{"name":"form","type":"383cf73ae4748e5b","optional":false},{"name":"kind","type":"9ac52f0f84fec2eb","optional":false}],"indices":[]}, + "aba175fb20ffc711": {"kind":"array","element":"83079c8a3f733ac3"}, + "ada310bf0bdb8fed": {"kind":"object","properties":[{"name":"kind","type":"68f44f59e91c4139","optional":false}],"indices":[]}, + "ade057f4fdc387ae": {"kind":"object","properties":[{"name":"form","type":"16d0507cb94b4cfc","optional":false},{"name":"kind","type":"99e7e7d7fed55ae6","optional":false}],"indices":[]}, + "aec150797b655c5f": {"kind":"literal","value":"catalog"}, + "b062078e899958f9": {"kind":"object","properties":[{"name":"kind","type":"1f1385dbc3e875c0","optional":false}],"indices":[]}, + "b0b0eb1b16490f6b": {"kind":"object","properties":[{"name":"attachmentId","type":"4cd48f3e5108bd6e","optional":false},{"name":"bytes","type":"0657d3ca5ac4e7bf","optional":false},{"name":"height","type":"0657d3ca5ac4e7bf","optional":false},{"name":"mediaType","type":"2f1e6a7ebace43d7","optional":false},{"name":"name","type":"4cd48f3e5108bd6e","optional":true},{"name":"originalDimensions","type":"0f46153645c29784","optional":true},{"name":"width","type":"0657d3ca5ac4e7bf","optional":false}],"indices":[]}, + "b2a5c8c008a31e3d": {"kind":"object","properties":[{"name":"form","type":"383cf73ae4748e5b","optional":false},{"name":"kind","type":"23af3759678a30de","optional":false}],"indices":[]}, + "b3681c026a0b98e9": {"kind":"object","properties":[{"name":"form","type":"e8de0f457fed5b9f","optional":false},{"name":"kind","type":"78a9be340090b735","optional":false},{"name":"summary","type":"4cd48f3e5108bd6e","optional":false}],"indices":[]}, + "b4ec0af39fd52ed9": {"kind":"object","properties":[{"name":"kind","type":"bb94f3217aa56c88","optional":false}],"indices":[]}, + "b52f215a6cd69105": {"kind":"array","element":"8064c03c87c357fd"}, + "b613f83572fe2fbf": {"kind":"object","properties":[{"name":"form","type":"383cf73ae4748e5b","optional":false},{"name":"kind","type":"05205074b24d8340","optional":false},{"name":"through","type":"0657d3ca5ac4e7bf","optional":false}],"indices":[]}, + "b6f94c17dd9bbd7c": {"kind":"object","properties":[{"name":"form","type":"fee1caf8ab6a65c1","optional":false},{"name":"kind","type":"bb94f3217aa56c88","optional":false}],"indices":[]}, + "b70f3e81fe11b7a5": {"kind":"object","properties":[{"name":"form","type":"fee1caf8ab6a65c1","optional":false},{"name":"kind","type":"a9059a81430b3207","optional":false}],"indices":[]}, + "b765ee31033cea46": {"kind":"literal","value":"set"}, + "b79641a9d25e7566": {"kind":"object","properties":[{"name":"kind","type":"8067b0d232c350f1","optional":false}],"indices":[]}, + "b815d7b91cdd9fc6": {"kind":"literal","value":"goal"}, + "ba2a1a8f194b1bb2": {"kind":"object","properties":[{"name":"form","type":"fee1caf8ab6a65c1","optional":false},{"name":"kind","type":"05205074b24d8340","optional":false},{"name":"through","type":"0657d3ca5ac4e7bf","optional":false}],"indices":[]}, + "ba4c40b4381e0dcd": {"kind":"object","properties":[{"name":"form","type":"6f9e00383836275e","optional":false},{"name":"kind","type":"23af3759678a30de","optional":false},{"name":"sections","type":"c748fb42c80a1200","optional":false}],"indices":[]}, + "baccc97ec34be6c4": {"kind":"object","properties":[{"name":"form","type":"e8de0f457fed5b9f","optional":false},{"name":"kind","type":"0fe52387f6505270","optional":false},{"name":"summary","type":"4cd48f3e5108bd6e","optional":false}],"indices":[]}, + "bb94f3217aa56c88": {"kind":"literal","value":"hooks-codex"}, + "bbc5696e3f13c758": {"kind":"opaque","reason":"unknown"}, + "bcf0caf62d964b2f": {"kind":"object","properties":[{"name":"endSeq","type":"0657d3ca5ac4e7bf","optional":false},{"name":"op","type":"f6cb462f808309e3","optional":false},{"name":"startSeq","type":"0657d3ca5ac4e7bf","optional":false}],"indices":[]}, + "bec5ca3a376f56f3": {"kind":"object","properties":[{"name":"maxTokens","type":"0657d3ca5ac4e7bf","optional":false},{"name":"messageSeqs","type":"5d03ba38734809bc","optional":false},{"name":"messages","type":"42e2ff61928fb7df","optional":false},{"name":"reasoningEffort","type":"4cd48f3e5108bd6e","optional":true},{"name":"route","type":"07e1a58c58b593f5","optional":false},{"name":"system","type":"4cd48f3e5108bd6e","optional":false},{"name":"titleProvider","type":"4cd48f3e5108bd6e","optional":false}],"indices":[]}, + "bf16d2e98a7f1389": {"kind":"literal","value":"subagent-settled"}, + "c1f0f17b6493b85d": {"kind":"object","properties":[{"name":"arguments","type":"4cd48f3e5108bd6e","optional":false},{"name":"id","type":"4cd48f3e5108bd6e","optional":false},{"name":"name","type":"4cd48f3e5108bd6e","optional":false},{"name":"type","type":"1f0133217eeeffd8","optional":false}],"indices":[]}, + "c51f0d0a405bb96f": {"kind":"union","types":["09f3f8dc417f2782","4b259f7f8f0a44ad","74e0e5885d2ddf04","824b1d4d4f007bda","fa87537f4a9c1e25"]}, + "c5228b7a55498d84": {"kind":"object","properties":[{"name":"form","type":"6f9e00383836275e","optional":false},{"name":"kind","type":"99e7e7d7fed55ae6","optional":false},{"name":"sections","type":"c748fb42c80a1200","optional":false}],"indices":[]}, + "c55827fba7018198": {"kind":"object","properties":[{"name":"callId","type":"4cd48f3e5108bd6e","optional":false},{"name":"kind","type":"9645cf93769a6dfb","optional":false},{"name":"outcome","type":"85d6d96ff8842974","optional":false}],"indices":[]}, + "c5687b1313206a6f": {"kind":"literal","value":"cordis-host-runner"}, + "c748fb42c80a1200": {"kind":"array","element":"86e1e384495ee09a"}, + "cb1c8959e1726f82": {"kind":"object","properties":[{"name":"form","type":"16d0507cb94b4cfc","optional":false},{"name":"kind","type":"24b10f7cdae64928","optional":false}],"indices":[]}, + "cda2345a9be9d139": {"kind":"object","properties":[{"name":"form","type":"e8de0f457fed5b9f","optional":false},{"name":"kind","type":"24b10f7cdae64928","optional":false},{"name":"summary","type":"4cd48f3e5108bd6e","optional":false}],"indices":[]}, + "d4e4d575abeb4b72": {"kind":"literal","value":"canceled"}, + "d85590a5675c6e2f": {"kind":"object","properties":[{"name":"form","type":"aec150797b655c5f","optional":false},{"name":"kind","type":"1f1385dbc3e875c0","optional":false}],"indices":[]}, + "d9c462b9f62fdd3e": {"kind":"object","properties":[{"name":"callId","type":"4cd48f3e5108bd6e","optional":false},{"name":"kind","type":"a13d8f379222ece8","optional":false}],"indices":[]}, + "d9edf1862e4471d6": {"kind":"literal","value":"schedule"}, + "dacf3d5f3e4ff619": {"kind":"literal","value":true}, + "db06ef35b27a3842": {"kind":"object","properties":[{"name":"form","type":"6f9e00383836275e","optional":false},{"name":"kind","type":"1f1385dbc3e875c0","optional":false},{"name":"sections","type":"c748fb42c80a1200","optional":false}],"indices":[]}, + "db6c5246911d47a7": {"kind":"literal","value":"webhook"}, + "dba54c09c6e7aafc": {"kind":"object","properties":[{"name":"kind","type":"4edec1b770e8ec4c","optional":false}],"indices":[]}, + "dca3ba43188095fa": {"kind":"union","types":["0203243b72fc867a","022623b9ef98ec47","02b2c23f2d94b028","0ed8d1108fe7a5e1","0eeb17e1df89b1eb","11638dc58a31496f","1938c8c20f1cba7c","1e709346005826eb","1fdad624334d3548","2152caf1a71e588e","2235d957bf4b7c6c","224aa11d4d5f88c4","24ce31aa528272e5","260523b412c19ad8","28936c614bd4e7e2","290f32bfd81ff85a","297fbd8067d7815a","2aad1179f9576314","312aee2f0c42aabb","31907de956375182","3247e566f4340029","3b04790e08b35241","3b4f2c9ef2c1217e","3bdb8dc6989655b0","408927267422a7b2","45f005e6bbb76452","4991dfc415c9efeb","49dab019d00e8c26","4a9bef9f27a94252","52c6113cb0e53f34","53cf1704ae0709c7","5654685d7557ec74","58015da1c1950a66","5bb69b88517f6214","5bc66269cfaf614c","5cdbf342b7748d15","5d7a64ed6aac5551","6085488d223aeffd","6292bcbedaa97fea","65a8400e451e667e","65d583e66518c523","672c4aa2a9b736e3","6ccb6bc423fb3952","6ea608bdc8a7a63d","6f22a9d02b9a1f11","6f44f32be9bcd9a8","719c51f67074f970","7554565be416b034","756b5e23a5cb2c7f","7df62978a2b7de85","7eaef7a763ba5b94","7f959241c24128b4","80677c8c8b804189","825ca23416b1ea9d","8338ee303e2bd448","848639f8787f035b","854db3efdfb0cd39","85fe96bf15d5c755","8620189c8e335827","87b1a33564b9a4d6","88841202942c7683","8a046b52331959aa","8c1c4f72755a78ea","8c627d7a45fa406c","8f1062573ea91841","8f324cea3916c051","8fcb0b44a575e998","96bfb916a727cd44","99135d8a39379779","99f0e98184709ad1","9edc162949abf93b","9f65c43e340bba31","a15a19ef63cf5d1b","a16e567c8cd2c55c","a2066bd52f61218b","a3c6f1ea38e9a61d","a4afec59b75aad5d","aa2bf9e82b9fdeb9","aae343bc3d663c83","ada310bf0bdb8fed","ade057f4fdc387ae","b062078e899958f9","b2a5c8c008a31e3d","b3681c026a0b98e9","b4ec0af39fd52ed9","b613f83572fe2fbf","b6f94c17dd9bbd7c","b70f3e81fe11b7a5","b79641a9d25e7566","ba2a1a8f194b1bb2","ba4c40b4381e0dcd","baccc97ec34be6c4","c5228b7a55498d84","c55827fba7018198","cb1c8959e1726f82","cda2345a9be9d139","d85590a5675c6e2f","d9c462b9f62fdd3e","db06ef35b27a3842","dba54c09c6e7aafc","dd00cdccd0ba487b","dd5ee8762bd8a14b","dd6cc2bb2a8f2824","dde0cdf9d426768b","deaae5cd30987d4f","e7f4cbb3a57f4cbd","edbbfff1128099fd","ee577a0cc18664c9","f230c0b583e23b25","f29d63336e8266d8","f4a66f654996c093","f56c5b59ca016131","f6329fb30c7ea801","f6605d6c57933aea","f6afe41e3926f422","f7283223aacdc39b","f97f47b0eb87905e","fcf81d3c58c13593","fe1a7acdeed4d0f5"]}, + "dd00cdccd0ba487b": {"kind":"object","properties":[{"name":"form","type":"aec150797b655c5f","optional":false},{"name":"kind","type":"05205074b24d8340","optional":false},{"name":"through","type":"0657d3ca5ac4e7bf","optional":false}],"indices":[]}, + "dd5ee8762bd8a14b": {"kind":"object","properties":[{"name":"form","type":"aec150797b655c5f","optional":false},{"name":"kind","type":"99e7e7d7fed55ae6","optional":false}],"indices":[]}, + "dd6cc2bb2a8f2824": {"kind":"object","properties":[{"name":"form","type":"383cf73ae4748e5b","optional":false},{"name":"kind","type":"99e7e7d7fed55ae6","optional":false}],"indices":[]}, + "dde0cdf9d426768b": {"kind":"object","properties":[{"name":"kind","type":"05205074b24d8340","optional":false},{"name":"through","type":"0657d3ca5ac4e7bf","optional":false}],"indices":[]}, + "de25352d2dc41963": {"kind":"literal","value":"user/message"}, + "de30b1fa12c75f81": {"kind":"literal","value":"image/gif"}, + "deaae5cd30987d4f": {"kind":"object","properties":[{"name":"form","type":"16d0507cb94b4cfc","optional":false},{"name":"kind","type":"0fe52387f6505270","optional":false}],"indices":[]}, + "deebfc7c62177ea8": {"kind":"object","properties":[{"name":"kind","type":"95a3ffccbf3c8afc","optional":false}],"indices":[]}, + "df843efd87c78cf8": {"kind":"array","element":"4f91f187baeabef5"}, + "e438a9d4fb883b3e": {"kind":"literal","value":"append"}, + "e7f4cbb3a57f4cbd": {"kind":"object","properties":[{"name":"form","type":"e8de0f457fed5b9f","optional":false},{"name":"kind","type":"05205074b24d8340","optional":false},{"name":"summary","type":"4cd48f3e5108bd6e","optional":false},{"name":"through","type":"0657d3ca5ac4e7bf","optional":false}],"indices":[]}, + "e8de0f457fed5b9f": {"kind":"literal","value":"notice"}, + "ebb768d85ec87fb6": {"kind":"literal","value":"image/webp"}, + "edbbfff1128099fd": {"kind":"object","properties":[{"name":"form","type":"e8de0f457fed5b9f","optional":false},{"name":"kind","type":"a9059a81430b3207","optional":false},{"name":"summary","type":"4cd48f3e5108bd6e","optional":false}],"indices":[]}, + "ee577a0cc18664c9": {"kind":"object","properties":[{"name":"form","type":"e8de0f457fed5b9f","optional":false},{"name":"kind","type":"8067b0d232c350f1","optional":false},{"name":"summary","type":"4cd48f3e5108bd6e","optional":false}],"indices":[]}, + "f19bee84bf3d2090": {"kind":"object","properties":[{"name":"attachmentId","type":"4cd48f3e5108bd6e","optional":false},{"name":"bytes","type":"0657d3ca5ac4e7bf","optional":false},{"name":"name","type":"4cd48f3e5108bd6e","optional":false}],"indices":[]}, + "f230c0b583e23b25": {"kind":"object","properties":[{"name":"form","type":"6f9e00383836275e","optional":false},{"name":"kind","type":"8067b0d232c350f1","optional":false},{"name":"sections","type":"c748fb42c80a1200","optional":false}],"indices":[]}, + "f29d63336e8266d8": {"kind":"object","properties":[{"name":"kind","type":"d9edf1862e4471d6","optional":false}],"indices":[]}, + "f2da0f27c1e6add5": {"kind":"object","properties":[{"name":"attachment","type":"f19bee84bf3d2090","optional":false},{"name":"type","type":"277b61f9c6f81704","optional":false}],"indices":[]}, + "f4a66f654996c093": {"kind":"object","properties":[{"name":"kind","type":"0fe52387f6505270","optional":false}],"indices":[]}, + "f56c5b59ca016131": {"kind":"object","properties":[{"name":"form","type":"383cf73ae4748e5b","optional":false},{"name":"kind","type":"7f13860ee89a2d35","optional":false},{"name":"references","type":"df843efd87c78cf8","optional":false},{"name":"version","type":"f88f1b7b6bb733f6","optional":false}],"indices":[]}, + "f6329fb30c7ea801": {"kind":"object","properties":[{"name":"form","type":"383cf73ae4748e5b","optional":false},{"name":"kind","type":"0fe52387f6505270","optional":false}],"indices":[]}, + "f6605d6c57933aea": {"kind":"object","properties":[{"name":"form","type":"fee1caf8ab6a65c1","optional":false},{"name":"kind","type":"9ac52f0f84fec2eb","optional":false}],"indices":[]}, + "f68c335306535a00": {"kind":"literal","value":"user-approval"}, + "f6afe41e3926f422": {"kind":"object","properties":[{"name":"form","type":"fee1caf8ab6a65c1","optional":false},{"name":"kind","type":"8067b0d232c350f1","optional":false}],"indices":[]}, + "f6cb462f808309e3": {"kind":"literal","value":"replace"}, + "f7283223aacdc39b": {"kind":"object","properties":[{"name":"kind","type":"9ac52f0f84fec2eb","optional":false}],"indices":[]}, + "f7752f518bb2f916": {"kind":"object","properties":[{"name":"inserted","type":"8a54d228b1b7d845","optional":false},{"name":"outcome","type":"d4e4d575abeb4b72","optional":true},{"name":"removedCount","type":"0657d3ca5ac4e7bf","optional":true},{"name":"start","type":"0657d3ca5ac4e7bf","optional":false},{"name":"target","type":"96f4a9c81fc0f940","optional":false}],"indices":[]}, + "f88f1b7b6bb733f6": {"kind":"literal","value":1}, + "f97f47b0eb87905e": {"kind":"object","properties":[{"name":"form","type":"16d0507cb94b4cfc","optional":false},{"name":"kind","type":"78a9be340090b735","optional":false}],"indices":[]}, + "fa87537f4a9c1e25": {"kind":"object","properties":[{"name":"content","type":"b52f215a6cd69105","optional":false},{"name":"id","type":"4cd48f3e5108bd6e","optional":false},{"name":"role","type":"95c0e88fcf0bafb2","optional":false},{"name":"source","type":"719c51f67074f970","optional":false}],"indices":[]}, + "fb8b6a2e53cb9cf4": {"kind":"literal","value":"image"}, + "fbd2c74b346a1595": {"kind":"literal","value":"agent-instructions"}, + "fcf427290c6213c2": {"kind":"primitive","type":"never"}, + "fcf81d3c58c13593": {"kind":"object","properties":[{"name":"form","type":"383cf73ae4748e5b","optional":false},{"name":"kind","type":"78a9be340090b735","optional":false}],"indices":[]}, + "fe1a7acdeed4d0f5": {"kind":"object","properties":[{"name":"form","type":"e8de0f457fed5b9f","optional":false},{"name":"kind","type":"1f1385dbc3e875c0","optional":false},{"name":"summary","type":"4cd48f3e5108bd6e","optional":false}],"indices":[]}, + "fee1caf8ab6a65c1": {"kind":"literal","value":"instructions"} + } +} diff --git a/docs/persistence-changes/2026-10-27-retry-control-input.zh.md b/docs/persistence-changes/2026-10-27-retry-control-input.zh.md new file mode 100644 index 0000000000..119eab180a --- /dev/null +++ b/docs/persistence-changes/2026-10-27-retry-control-input.zh.md @@ -0,0 +1,60 @@ +--- +description: "记录持久化类型更改及其兼容性确认。" +kind: persistence-change +--- + +# 2026-10-27-retry-control-input + +[English](2026-10-27-retry-control-input.md) | 中文 + +## 概述 + +为空 Session API 继续提示词增加 retry 消息来源;普通 user/message 记录保留输入身份和调用方元数据。 + +## 目录 + +- [声明](#declaration) +- [兼容性](#compatibility) +- [验证](#verification) +- [开发备注](#dev-note) + + +## 声明 + +```yaml persistence-change +schemaVersion: 1 +id: 2026-10-27-retry-control-input +baseline: false +changes: + - root: "event:agent/inbox/spliced" + previous: "2026-10-27-subagent-settlement-attribution" + after: "1682631f010d5ea717d181ed6f4ef46cde08d92a31ab461e7e98edfc98461f85" + decision: same-version + - root: "event:developer/message" + previous: "2026-10-27-subagent-settlement-attribution" + after: "510826cf4e1f9220d75c1efd90b349dd9a77fc5ba15d19e16f87e85a48db5f99" + decision: same-version + - root: "event:session/title-llm-request" + previous: "2026-10-27-subagent-settlement-attribution" + after: "3bca25b2baa6b22be9b577621a7603497f40870ed88a8dac4383d37dc2bb6e18" + decision: same-version + - root: "event:user/message" + previous: "2026-10-27-subagent-settlement-attribution" + after: "50a15408d511e9be3fa93abff37a38ae770f3ab905fc6849fee0d989200d2b97" + decision: same-version +``` + + +## 兼容性 + +retry 来源是现有空 UserMessage 表示中的生产方元数据。AgentLoop、模型历史派生与 SDK 提示词行为保持不变。旧读取方保留可扩展来源元数据,并按普通用户消息准入消费;旧界面可能显示空上下文行。更新后的读取方保留历史普通消息,Chat 仅隐藏空重试消息。现有事件判别标签与当前 Session 版本不变,不新增必读事件。 + + +## 验证 + +Session API 测试通过:51 个文件、1112 个测试,continuation.ts 的语句、分支、函数和行覆盖率均为 100%。Chat 与 conversation 测试通过:113 个文件、1875 个测试;最终定向 Chat 与输入回归分别通过 96 和 31 个测试。浏览器继续回放通过,断言日志保留空 retry 用户消息、Chat 无空气泡且轮次正常闭合。构建 10 项全部通过,类型感知 lint 退出码为 0,doc-sync 的 43 项全部通过。与 PR 基线的 Git 比较确认 AgentLoop、Core Agent、Core Session 和 SDK 无改动。 + + +## 开发备注 + +无。 diff --git a/docs/persistence-changes/2026-11-02-subagent-catalog-names.i18n.yaml b/docs/persistence-changes/2026-11-02-subagent-catalog-names.i18n.yaml new file mode 100644 index 0000000000..95b4ae78d4 --- /dev/null +++ b/docs/persistence-changes/2026-11-02-subagent-catalog-names.i18n.yaml @@ -0,0 +1,28 @@ +# Bilingual-pair consistency record for 2026-11-02-subagent-catalog-names.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/persistence-changes/2026-11-02-subagent-catalog-names.md +/: + en: 3d5a424ae7d7e46b + zh: c22a8e4a62d8cc1a +/2026-11-02-subagent-catalog-names: + en: d60db721936ec588 + zh: 9271248e40f283c5 +/2026-11-02-subagent-catalog-names/summary: + en: af5f42653bb5d143 + zh: 4441c72b0ab5d2b8 +/2026-11-02-subagent-catalog-names/table-of-contents: + en: 6cf314a069ceb451 + zh: 9adff678e9ecab3b +/2026-11-02-subagent-catalog-names/declaration: + en: 6907136f28e48c90 + zh: 02f8298485f3d8e7 +/2026-11-02-subagent-catalog-names/compatibility: + en: 29b5c0a1e2ce852c + zh: 6ce9b7d6baf58fc2 +/2026-11-02-subagent-catalog-names/verification: + en: cf8533363c2d36f7 + zh: 75de24564998ca27 +/2026-11-02-subagent-catalog-names/dev-note: + en: b75c8458928b72b9 + zh: 003ba4e17b4b5269 diff --git a/docs/persistence-changes/2026-11-02-subagent-catalog-names.md b/docs/persistence-changes/2026-11-02-subagent-catalog-names.md new file mode 100644 index 0000000000..b6f784306e --- /dev/null +++ b/docs/persistence-changes/2026-11-02-subagent-catalog-names.md @@ -0,0 +1,48 @@ +--- +description: "Records a persistence type transition and its compatibility acknowledgement." +kind: persistence-change +--- + +# 2026-11-02-subagent-catalog-names + +English | [中文](2026-11-02-subagent-catalog-names.zh.md) + +## Summary + +Adds version 3 of the parent-owned subagent/catalog payload, which records each continuable or parent-delivered external child's name, unique among its creator's children. + +## Table of Contents + +- [Declaration](#declaration) +- [Compatibility](#compatibility) +- [Verification](#verification) +- [Dev Note](#dev-note) + + +## Declaration + +```yaml persistence-change +schemaVersion: 1 +id: 2026-11-02-subagent-catalog-names +baseline: false +changes: + - root: "event:subagent/catalog" + previous: "2026-09-19-external-subagent-catalog" + after: "d49164d37eab0f0f70fa787c65d887abbea869c010ccb103d717fab3519c3a41" + decision: same-version +``` + + +## Compatibility + +Version 0, 1, and 2 payloads keep their schemas and meaning; current readers restore them as unnamed children addressed by Session id. New local and parent-delivered external creation writes version 3. Projection stateVersion remains 6: unnamed checkpoints stay usable, and their suffix replay matches full replay with named events. Earlier releases reject the unknown payload version during native V4 admission and catalog projection restoration instead of misreading the entry, so a parent Session that recorded a named child fails loudly rather than losing a child. + + +## Verification + +pnpm exec vitest run packages/subagent/subagent/tests: 495 tests passed, including named catalog restoration, invalid version-3 facts, sibling-unique reservation, cold resume path recovery, and external parent-delivered names. pnpm exec vitest run packages/session/session-format-v3-to-v4/tests: 397 tests passed, including native version-3 admission and rejection. + + +## Dev Note + +None. diff --git a/docs/persistence-changes/2026-11-02-subagent-catalog-names.schema.json b/docs/persistence-changes/2026-11-02-subagent-catalog-names.schema.json new file mode 100644 index 0000000000..9a474fce46 --- /dev/null +++ b/docs/persistence-changes/2026-11-02-subagent-catalog-names.schema.json @@ -0,0 +1,31 @@ +{ + "formatVersion": 2, + "roots": [ + {"key":"event:subagent/catalog","kind":"event","event":"subagent/catalog","surface":false,"digest":"d49164d37eab0f0f70fa787c65d887abbea869c010ccb103d717fab3519c3a41"} + ], + "types": [], + "nodes": { + "058fc9a6b4fbd5d4": {"kind":"union","types":["0e10d7c096b47e61","5d542ac7bdf13310","8faed5b52ab2d2df","a0f25b5aeeebf2bf","a43327a1739c3fa4","b6896938660a1dfe","cbbe8377ee744964","e2ad8f5bcd813f26"]}, + "05a2796621b1ee6c": {"kind":"literal","value":"unknown"}, + "0657d3ca5ac4e7bf": {"kind":"primitive","type":"number"}, + "0e10d7c096b47e61": {"kind":"object","properties":[{"name":"childCreatedAt","type":"0657d3ca5ac4e7bf","optional":false},{"name":"childId","type":"4cd48f3e5108bd6e","optional":false},{"name":"label","type":"4cd48f3e5108bd6e","optional":false},{"name":"mode","type":"e5d3828df1ec3e2a","optional":false},{"name":"version","type":"93d38436347f67c9","optional":false}],"indices":[]}, + "137ac60e26bcb192": {"kind":"literal","value":3}, + "44c8c77aa9aa100b": {"kind":"literal","value":"subagent/catalog"}, + "4cd48f3e5108bd6e": {"kind":"primitive","type":"string"}, + "5d542ac7bdf13310": {"kind":"object","properties":[{"name":"childCreatedAt","type":"0657d3ca5ac4e7bf","optional":false},{"name":"childId","type":"4cd48f3e5108bd6e","optional":false},{"name":"label","type":"4cd48f3e5108bd6e","optional":true},{"name":"mode","type":"d28765f87d6b6ab4","optional":false},{"name":"version","type":"93d38436347f67c9","optional":false}],"indices":[]}, + "8faed5b52ab2d2df": {"kind":"object","properties":[{"name":"childCreatedAt","type":"0657d3ca5ac4e7bf","optional":false},{"name":"childId","type":"4cd48f3e5108bd6e","optional":false},{"name":"label","type":"4cd48f3e5108bd6e","optional":false},{"name":"mode","type":"e5d3828df1ec3e2a","optional":false},{"name":"name","type":"4cd48f3e5108bd6e","optional":false},{"name":"version","type":"137ac60e26bcb192","optional":false}],"indices":[]}, + "93d38436347f67c9": {"kind":"literal","value":0}, + "a0f25b5aeeebf2bf": {"kind":"object","properties":[{"name":"childCreatedAt","type":"0657d3ca5ac4e7bf","optional":false},{"name":"childId","type":"4cd48f3e5108bd6e","optional":false},{"name":"label","type":"4cd48f3e5108bd6e","optional":true},{"name":"mode","type":"05a2796621b1ee6c","optional":false},{"name":"version","type":"f88f1b7b6bb733f6","optional":false}],"indices":[]}, + "a0f906856fc06f1c": {"kind":"literal","value":2}, + "a43327a1739c3fa4": {"kind":"object","properties":[{"name":"childCreatedAt","type":"0657d3ca5ac4e7bf","optional":false},{"name":"childId","type":"4cd48f3e5108bd6e","optional":false},{"name":"label","type":"4cd48f3e5108bd6e","optional":true},{"name":"mode","type":"fc351843b8ecbd05","optional":false},{"name":"name","type":"4cd48f3e5108bd6e","optional":false},{"name":"version","type":"137ac60e26bcb192","optional":false}],"indices":[]}, + "b6896938660a1dfe": {"kind":"object","properties":[{"name":"childCreatedAt","type":"0657d3ca5ac4e7bf","optional":false},{"name":"childId","type":"4cd48f3e5108bd6e","optional":false},{"name":"label","type":"4cd48f3e5108bd6e","optional":true},{"name":"mode","type":"d28765f87d6b6ab4","optional":false},{"name":"version","type":"f88f1b7b6bb733f6","optional":false}],"indices":[]}, + "cbbe8377ee744964": {"kind":"object","properties":[{"name":"childCreatedAt","type":"0657d3ca5ac4e7bf","optional":false},{"name":"childId","type":"4cd48f3e5108bd6e","optional":false},{"name":"label","type":"4cd48f3e5108bd6e","optional":true},{"name":"mode","type":"fc351843b8ecbd05","optional":false},{"name":"version","type":"a0f906856fc06f1c","optional":false}],"indices":[]}, + "d28765f87d6b6ab4": {"kind":"literal","value":"one-shot"}, + "d49164d37eab0f0f": {"kind":"object","properties":[{"name":"data","type":"058fc9a6b4fbd5d4","optional":false},{"name":"ignorable","type":"dacf3d5f3e4ff619","optional":true},{"name":"seq","type":"0657d3ca5ac4e7bf","optional":false},{"name":"time","type":"0657d3ca5ac4e7bf","optional":false},{"name":"type","type":"44c8c77aa9aa100b","optional":false}],"indices":[]}, + "dacf3d5f3e4ff619": {"kind":"literal","value":true}, + "e2ad8f5bcd813f26": {"kind":"object","properties":[{"name":"childCreatedAt","type":"0657d3ca5ac4e7bf","optional":false},{"name":"childId","type":"4cd48f3e5108bd6e","optional":false},{"name":"label","type":"4cd48f3e5108bd6e","optional":false},{"name":"mode","type":"e5d3828df1ec3e2a","optional":false},{"name":"version","type":"f88f1b7b6bb733f6","optional":false}],"indices":[]}, + "e5d3828df1ec3e2a": {"kind":"literal","value":"continuable"}, + "f88f1b7b6bb733f6": {"kind":"literal","value":1}, + "fc351843b8ecbd05": {"kind":"literal","value":"external"} + } +} diff --git a/docs/persistence-changes/2026-11-02-subagent-catalog-names.zh.md b/docs/persistence-changes/2026-11-02-subagent-catalog-names.zh.md new file mode 100644 index 0000000000..15ad8ad6b5 --- /dev/null +++ b/docs/persistence-changes/2026-11-02-subagent-catalog-names.zh.md @@ -0,0 +1,48 @@ +--- +description: "记录持久化类型更改及其兼容性确认。" +kind: persistence-change +--- + +# 2026-11-02-subagent-catalog-names + +[English](2026-11-02-subagent-catalog-names.md) | 中文 + +## 概述 + +为父 Session 拥有的 subagent/catalog 载荷增加 version 3,记录每个 continuable 子代理或父级交付的 external 子代理在其创建者子代理中唯一的名称。 + +## 目录 + +- [声明](#declaration) +- [兼容性](#compatibility) +- [验证](#verification) +- [开发备注](#dev-note) + + +## 声明 + +```yaml persistence-change +schemaVersion: 1 +id: 2026-11-02-subagent-catalog-names +baseline: false +changes: + - root: "event:subagent/catalog" + previous: "2026-09-19-external-subagent-catalog" + after: "d49164d37eab0f0f70fa787c65d887abbea869c010ccb103d717fab3519c3a41" + decision: same-version +``` + + +## 兼容性 + +version 0、1、2 载荷的 schema 和含义保持不变;当前读取方将其恢复为按 Session id 寻址的无名子代理。新的本地创建和父级交付的 external 创建写入 version 3。投影 stateVersion 保持为 6:无名检查点仍可复用,后缀回放与包含具名事件的全量回放一致。较早版本在原生 V4 准入和目录投影恢复时拒绝未知载荷版本,而不会误读条目,因此记录了具名子代理的父 Session 会明确失败,而不是丢失子代理。 + + +## 验证 + +pnpm exec vitest run packages/subagent/subagent/tests:495 个测试通过,覆盖具名目录恢复、无效 version 3 事实、同级唯一预留、冷恢复路径还原以及父级交付 external 子代理的名称。pnpm exec vitest run packages/session/session-format-v3-to-v4/tests:397 个测试通过,覆盖原生 version 3 准入与拒绝。 + + +## 开发备注 + +无。 diff --git a/docs/persistence-changes/2026-11-02-team-task-owner-names.i18n.yaml b/docs/persistence-changes/2026-11-02-team-task-owner-names.i18n.yaml new file mode 100644 index 0000000000..95205ac30f --- /dev/null +++ b/docs/persistence-changes/2026-11-02-team-task-owner-names.i18n.yaml @@ -0,0 +1,28 @@ +# Bilingual-pair consistency record for 2026-11-02-team-task-owner-names.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/persistence-changes/2026-11-02-team-task-owner-names.md +/: + en: 3d5a424ae7d7e46b + zh: c22a8e4a62d8cc1a +/2026-11-02-team-task-owner-names: + en: a43808c05ced0aee + zh: 44561dea17e94aaa +/2026-11-02-team-task-owner-names/summary: + en: 4736e13a29707934 + zh: 7d9a2e65a31a5c65 +/2026-11-02-team-task-owner-names/table-of-contents: + en: 6cf314a069ceb451 + zh: 9adff678e9ecab3b +/2026-11-02-team-task-owner-names/declaration: + en: 6907136f28e48c90 + zh: 02f8298485f3d8e7 +/2026-11-02-team-task-owner-names/compatibility: + en: ffa0669cd780f696 + zh: cdc5a302b3fc4ee1 +/2026-11-02-team-task-owner-names/verification: + en: 90d1e1c177ff1fc0 + zh: 6438d6dcb53596b8 +/2026-11-02-team-task-owner-names/dev-note: + en: b75c8458928b72b9 + zh: 003ba4e17b4b5269 diff --git a/docs/persistence-changes/2026-11-02-team-task-owner-names.md b/docs/persistence-changes/2026-11-02-team-task-owner-names.md new file mode 100644 index 0000000000..5b65f23bed --- /dev/null +++ b/docs/persistence-changes/2026-11-02-team-task-owner-names.md @@ -0,0 +1,48 @@ +--- +description: "Records a persistence type transition and its compatibility acknowledgement." +kind: persistence-change +--- + +# 2026-11-02-team-task-owner-names + +English | [中文](2026-11-02-team-task-owner-names.zh.md) + +## Summary + +Adds optional ownerName to durable Team task snapshots, captured with ownerId during claim or reassignment and cleared with it when ownership ends. + +## Table of Contents + +- [Declaration](#declaration) +- [Compatibility](#compatibility) +- [Verification](#verification) +- [Dev Note](#dev-note) + + +## Declaration + +```yaml persistence-change +schemaVersion: 1 +id: 2026-11-02-team-task-owner-names +baseline: false +changes: + - root: "event:team/task" + previous: "2026-09-11-initial" + after: "bca0f9cb63d8620b6954bb045b07bb07cb557513a7f0e2e177f5e87f704e7ba7" + decision: same-version +``` + + +## Compatibility + +Current readers accept existing task payloads without ownerName and display ownerId without rewriting or backfilling historical logs. New task records retain the same ownerId authorization and version 2 task semantics. Earlier Team projections use a strict task schema and reject records containing ownerName, retaining their last valid tasks and reporting a projection failure rather than silently misinterpreting ownership. Session format version remains unchanged. The agentTeam projection state version remains 7: version-7 checkpoints without ownerName remain usable, and suffix replay preserves names from later task events. Version-6 checkpoints still rebuild from events. + + +## Verification + +Focused Agent Teams projection, task-board, tool, and JSONL/SQLite recovery tests pass. They cover saved root and nested owner names, clearing ownership, historical ID fallback, rejection of ownerName without ownerId, checkpoint rebuilds, and task reads and edits without descendant catalog queries. + + +## Dev Note + +None. diff --git a/docs/persistence-changes/2026-11-02-team-task-owner-names.schema.json b/docs/persistence-changes/2026-11-02-team-task-owner-names.schema.json new file mode 100644 index 0000000000..a75163d468 --- /dev/null +++ b/docs/persistence-changes/2026-11-02-team-task-owner-names.schema.json @@ -0,0 +1,23 @@ +{ + "formatVersion": 2, + "roots": [ + {"key":"event:team/task","kind":"event","event":"team/task","surface":false,"digest":"bca0f9cb63d8620b6954bb045b07bb07cb557513a7f0e2e177f5e87f704e7ba7"} + ], + "types": [], + "nodes": { + "0657d3ca5ac4e7bf": {"kind":"primitive","type":"number"}, + "1ebc6f9ff3aa9e3a": {"kind":"literal","value":"completed"}, + "234142ee4f996f38": {"kind":"literal","value":"pending"}, + "4018a00144474b6c": {"kind":"object","properties":[{"name":"blockedBy","type":"93c33d9687613293","optional":false},{"name":"description","type":"4cd48f3e5108bd6e","optional":false},{"name":"id","type":"4cd48f3e5108bd6e","optional":false},{"name":"ownerId","type":"4cd48f3e5108bd6e","optional":true},{"name":"ownerName","type":"4cd48f3e5108bd6e","optional":true},{"name":"revision","type":"0657d3ca5ac4e7bf","optional":false},{"name":"status","type":"b2d2a01e51341a3b","optional":false},{"name":"subject","type":"4cd48f3e5108bd6e","optional":false},{"name":"writeScopes","type":"93c33d9687613293","optional":false}],"indices":[]}, + "4cd48f3e5108bd6e": {"kind":"primitive","type":"string"}, + "93c33d9687613293": {"kind":"array","element":"4cd48f3e5108bd6e"}, + "94c56aeb1564ad73": {"kind":"literal","value":"in_progress"}, + "a0f906856fc06f1c": {"kind":"literal","value":2}, + "a9427866376b691a": {"kind":"object","properties":[{"name":"task","type":"4018a00144474b6c","optional":false},{"name":"teamId","type":"4cd48f3e5108bd6e","optional":false},{"name":"version","type":"a0f906856fc06f1c","optional":false}],"indices":[]}, + "b2d2a01e51341a3b": {"kind":"union","types":["1ebc6f9ff3aa9e3a","234142ee4f996f38","94c56aeb1564ad73","e7e8f1318170b828"]}, + "b57ae1b37e52bee0": {"kind":"literal","value":"team/task"}, + "bca0f9cb63d8620b": {"kind":"object","properties":[{"name":"data","type":"a9427866376b691a","optional":false},{"name":"ignorable","type":"dacf3d5f3e4ff619","optional":true},{"name":"seq","type":"0657d3ca5ac4e7bf","optional":false},{"name":"time","type":"0657d3ca5ac4e7bf","optional":false},{"name":"type","type":"b57ae1b37e52bee0","optional":false}],"indices":[]}, + "dacf3d5f3e4ff619": {"kind":"literal","value":true}, + "e7e8f1318170b828": {"kind":"literal","value":"deleted"} + } +} diff --git a/docs/persistence-changes/2026-11-02-team-task-owner-names.zh.md b/docs/persistence-changes/2026-11-02-team-task-owner-names.zh.md new file mode 100644 index 0000000000..c4c4f8200d --- /dev/null +++ b/docs/persistence-changes/2026-11-02-team-task-owner-names.zh.md @@ -0,0 +1,48 @@ +--- +description: "记录持久化类型更改及其兼容性确认。" +kind: persistence-change +--- + +# 2026-11-02-team-task-owner-names + +[English](2026-11-02-team-task-owner-names.md) | 中文 + +## 概述 + +为持久化 Team 任务快照增加可选的 ownerName,在认领或重新分配时与 ownerId 一起记录,并在结束归属时一起清除。 + +## 目录 + +- [声明](#declaration) +- [兼容性](#compatibility) +- [验证](#verification) +- [开发备注](#dev-note) + + +## 声明 + +```yaml persistence-change +schemaVersion: 1 +id: 2026-11-02-team-task-owner-names +baseline: false +changes: + - root: "event:team/task" + previous: "2026-09-11-initial" + after: "bca0f9cb63d8620b6954bb045b07bb07cb557513a7f0e2e177f5e87f704e7ba7" + decision: same-version +``` + + +## 兼容性 + +当前读取方接受没有 ownerName 的已有任务载荷,直接显示 ownerId,不改写或回填历史日志。新任务记录保留相同的 ownerId 授权和第 2 版任务语义。旧 Team 投影使用严格任务 schema,会拒绝包含 ownerName 的记录,保留最后的有效任务并报告投影失败,不会静默误读归属。Session 格式版本保持不变。agentTeam 投影状态版本保持为 7:缺少 ownerName 的第 7 版检查点仍可复用,后缀回放保留后续任务事件中的名称。第 6 版检查点仍从事件重建。 + + +## 验证 + +聚焦的 Agent Teams 投影、任务板、工具及 JSONL/SQLite 恢复测试通过,覆盖保存的根与嵌套所有者名称、清除归属、历史 ID 回退、拒绝没有 ownerId 的 ownerName、检查点重建,以及不查询后代目录的任务读取和编辑。 + + +## 开发备注 + +无。 diff --git a/docs/persistence-changes/historical-formats/README.i18n.yaml b/docs/persistence-changes/historical-formats/README.i18n.yaml index fcd95ef300..81275db31b 100644 --- a/docs/persistence-changes/historical-formats/README.i18n.yaml +++ b/docs/persistence-changes/historical-formats/README.i18n.yaml @@ -15,8 +15,8 @@ en: 14c57f30e676f6e3 zh: b1a0ccf26fab3727 /session-persistence-formats/format-references: - en: a660985fd2941e51 - zh: 0d4aed6be93be922 + en: 1ebef675a763819c + zh: 19457eb77b815c8c /session-persistence-formats/scope-and-evidence: en: b220062139ddac1e zh: 7c4c0efe05dafa9c diff --git a/docs/persistence-changes/historical-formats/README.md b/docs/persistence-changes/historical-formats/README.md index 24b42751fa..ad213e0c18 100644 --- a/docs/persistence-changes/historical-formats/README.md +++ b/docs/persistence-changes/historical-formats/README.md @@ -32,7 +32,7 @@ The index is generated from validated snapshots and the current writer constant. | 1 | PR #3349 | [V1](v1.md) | [JSON](v1.schema.json) | 54 / 415 | | 2 | `dsh-v0.1.3-alpha.2` | [V2](v2.md) | [JSON](v2.schema.json) | 56 / 435 | | 3 | PR #4320 | [V3](v3.md) | [JSON](v3.schema.json) | 60 / 467 | -| 4 | Current checkout | [Current catalog](../../persistence-catalog.md) | [JSON](../../persistence-schema.json) | 66 / 631 | +| 4 | Current checkout | [Current catalog](../../persistence-catalog.md) | [JSON](../../persistence-schema.json) | 66 / 636 | diff --git a/docs/persistence-changes/historical-formats/README.zh.md b/docs/persistence-changes/historical-formats/README.zh.md index ef48b880a4..e3ca2d1bd3 100644 --- a/docs/persistence-changes/historical-formats/README.zh.md +++ b/docs/persistence-changes/historical-formats/README.zh.md @@ -32,7 +32,7 @@ description: "查找从 V0 到工作区写入器版本的每个 Session 格式 | 1 | PR #3349 | [V1](v1.zh.md) | [JSON](v1.schema.json) | 54 / 415 | | 2 | `dsh-v0.1.3-alpha.2` | [V2](v2.zh.md) | [JSON](v2.schema.json) | 56 / 435 | | 3 | PR #4320 | [V3](v3.zh.md) | [JSON](v3.schema.json) | 60 / 467 | -| 4 | 当前工作树 | [当前目录](../../persistence-catalog.zh.md) | [JSON](../../persistence-schema.json) | 66 / 631 | +| 4 | 当前工作树 | [当前目录](../../persistence-catalog.zh.md) | [JSON](../../persistence-schema.json) | 66 / 636 | diff --git a/docs/persistence-schema.json b/docs/persistence-schema.json index a025a3f846..57c674e416 100644 --- a/docs/persistence-schema.json +++ b/docs/persistence-schema.json @@ -5,7 +5,7 @@ {"key":"JsonlHeaderLine","kind":"header","digest":"18ee62b8900a4c3d046700f05d7a4d49d6cab2a660a020c87481d1603dd8bd4f"}, {"key":"SessionEventEnvelope","kind":"envelope","digest":"5776e5553ff2dfe3f5bc202dbb1e7c9f93e35a531aebb7764c23b2b6153b2ccc"}, {"key":"event:agent-preset/selected","kind":"event","event":"agent-preset/selected","surface":false,"digest":"a10c17474eaf2ddab7095a099e0fe3d046fc18e56c3e344fc8894c05ff9ef97b"}, - {"key":"event:agent/inbox/spliced","kind":"event","event":"agent/inbox/spliced","surface":false,"digest":"ddce54a3873dc57113b0cd38ad9b23b3c259186139e8847e5e5f415d86f52482"}, + {"key":"event:agent/inbox/spliced","kind":"event","event":"agent/inbox/spliced","surface":false,"digest":"1682631f010d5ea717d181ed6f4ef46cde08d92a31ab461e7e98edfc98461f85"}, {"key":"event:approval/asked","kind":"event","event":"approval/asked","surface":false,"digest":"3bfeb47b58606f4661904bc723da612782214c463d01e6d61cd6d6193d7374e1"}, {"key":"event:approval/decided","kind":"event","event":"approval/decided","surface":false,"digest":"bb1ab3d08f49a9f3b265f844cd78d5c49813062a7b34b54904b426f85d0ff6e3"}, {"key":"event:approval/policy","kind":"event","event":"approval/policy","surface":false,"digest":"26718e15e7e395bce9642dba5bbe09b3b1a4ce2213d20d566cd9207d7fc5fb78"}, @@ -18,7 +18,7 @@ {"key":"event:compaction/start","kind":"event","event":"compaction/start","surface":false,"digest":"db874d463b0fdec77e9da1c4568f37cb70bd6596781eb93800db44fb8a116965"}, {"key":"event:compaction/summary","kind":"event","event":"compaction/summary","surface":false,"digest":"e2f9a41e0989f54ed8cee80f8db2bcf9d60a5c810dc9d45b83fa050b9dce7602"}, {"key":"event:deliverables/presented","kind":"event","event":"deliverables/presented","surface":false,"digest":"13d3d180f977bf78081d487ffa0ecb75857349bcab29a5a3fb48189fca2a6176"}, - {"key":"event:developer/message","kind":"event","event":"developer/message","surface":true,"digest":"70ea8e7943c5e2d76905bcc2e694e8c3d5b138aaae3609f3e261b8d369a6e35a"}, + {"key":"event:developer/message","kind":"event","event":"developer/message","surface":true,"digest":"510826cf4e1f9220d75c1efd90b349dd9a77fc5ba15d19e16f87e85a48db5f99"}, {"key":"event:feedback/message-delete","kind":"event","event":"feedback/message-delete","surface":false,"digest":"3ee93b06f3a125850337602bcdf155d2538c43a5c944ec55b1b3c365152d6796"}, {"key":"event:feedback/message-put","kind":"event","event":"feedback/message-put","surface":false,"digest":"b5086d249e8502e9ead1d39156bb8d559bde7951cac0f14ce150345b4e42a2bf"}, {"key":"event:feedback/record","kind":"event","event":"feedback/record","surface":false,"digest":"b54940ff095c17e874c5be03815f4c2145a256cf3a1d34dae4ab2f7769dfffe8"}, @@ -40,10 +40,10 @@ {"key":"event:session-log-deepseek/delivery-accepted","kind":"event","event":"session-log-deepseek/delivery-accepted","surface":false,"digest":"d63b8b8ffad9c02fd80c43a17df4f240c1fe8118ecca9de34f9d5871838ab5b9"}, {"key":"event:session/end-seed","kind":"event","event":"session/end-seed","surface":false,"digest":"5e6db6e24948d4a853c71cb9fabd252ad051ce93d4672c1266cf837c1c17b84e"}, {"key":"event:session/title","kind":"event","event":"session/title","surface":false,"digest":"1b912703e2d64f91c99c675b8f805b01076c8325b905c1218ad81ef0b24909d5"}, - {"key":"event:session/title-llm-request","kind":"event","event":"session/title-llm-request","surface":false,"digest":"d95c624eddecdacf1ee74356196c09d2f3fcd625714be5e852a6b643fa12a7ca"}, + {"key":"event:session/title-llm-request","kind":"event","event":"session/title-llm-request","surface":false,"digest":"3bca25b2baa6b22be9b577621a7603497f40870ed88a8dac4383d37dc2bb6e18"}, {"key":"event:step/end","kind":"event","event":"step/end","surface":false,"digest":"e0a787e6ec76c7c94fecbc501b489164ab0293db05bc947914077ad01e674f05"}, {"key":"event:step/start","kind":"event","event":"step/start","surface":false,"digest":"4513e088d43e6c68425be30451b9f961cc264fe7318ca62681c41d4d78615986"}, - {"key":"event:subagent/catalog","kind":"event","event":"subagent/catalog","surface":false,"digest":"53750b9abf61efb7992b0aadc3e247ec927449c63266df28230fd1139f5590ac"}, + {"key":"event:subagent/catalog","kind":"event","event":"subagent/catalog","surface":false,"digest":"d49164d37eab0f0f70fa787c65d887abbea869c010ccb103d717fab3519c3a41"}, {"key":"event:subagent/descriptor","kind":"event","event":"subagent/descriptor","surface":false,"digest":"b79ada42962cad0190a9d465805260567621fa3a4abd757eb31e6016b52d5ab5"}, {"key":"event:subagent/model-selection-policy","kind":"event","event":"subagent/model-selection-policy","surface":false,"digest":"a6567ccb2e530606b775371eb4fa31468d72084339968e8b0440a516a23b39dc"}, {"key":"event:system/message","kind":"event","event":"system/message","surface":true,"digest":"69081694be231d56fd9580ba14645fd5e35373202605d5c5c841a9435b5fa3b1"}, @@ -51,7 +51,7 @@ {"key":"event:team/message/delivered","kind":"event","event":"team/message/delivered","surface":false,"digest":"48f9c19417a1abbedfa59f4667bba36b93ac2db407adf5e84cb3ba0de30942cb"}, {"key":"event:team/message/queued","kind":"event","event":"team/message/queued","surface":false,"digest":"21fb6a90d5068f6a0003b7ab316ed2f56342477146a65c00db0f13c4d8df667d"}, {"key":"event:team/mode","kind":"event","event":"team/mode","surface":false,"digest":"920d87e22b7409bcc7224f8b1dc7f5101c33574c75627c65baab12b85cc96e75"}, - {"key":"event:team/task","kind":"event","event":"team/task","surface":false,"digest":"d595ec73b32b016a6055333c67a5d646032b22e672da1d4a09c5b1ae398a093a"}, + {"key":"event:team/task","kind":"event","event":"team/task","surface":false,"digest":"bca0f9cb63d8620b6954bb045b07bb07cb557513a7f0e2e177f5e87f704e7ba7"}, {"key":"event:todo/write","kind":"event","event":"todo/write","surface":false,"digest":"b978cff734e62143eb56c9125423ec275405eda969802d42aaf73ecb987d3b26"}, {"key":"event:tool-workflow/agent-end","kind":"event","event":"tool-workflow/agent-end","surface":false,"digest":"babf9ee4d1af62bf6c3a8103737f7a5e4e78ce179be835ce05a38803e15884b7"}, {"key":"event:tool-workflow/agent-start","kind":"event","event":"tool-workflow/agent-start","surface":false,"digest":"5f26a6c20b37632f8f57729d171c671def4683d994ac6257a8dffcd855101627"}, @@ -63,20 +63,20 @@ {"key":"event:tool/result","kind":"event","event":"tool/result","surface":true,"digest":"7c9f44e90a0058f4cc532ae20dad0c10afa6eba22e70a6c79fc79490bad64397"}, {"key":"event:turn/end","kind":"event","event":"turn/end","surface":false,"digest":"0f8512903d94f57a4748fa1a2092e64342856796684e6b8343db685b192745ce"}, {"key":"event:turn/start","kind":"event","event":"turn/start","surface":false,"digest":"aa0957eca50aeb28bcd2e6930b95809926edacb550c8c340ba526ba6b861b3d8"}, - {"key":"event:user/message","kind":"event","event":"user/message","surface":true,"digest":"dcb07e04496586d2664d72dab0e94312917da56927b2a0dc3ee53d6a33e32450"}, + {"key":"event:user/message","kind":"event","event":"user/message","surface":true,"digest":"50a15408d511e9be3fa93abff37a38ae770f3ab905fc6849fee0d989200d2b97"}, {"key":"event:web/deepseek-search-llm-request","kind":"event","event":"web/deepseek-search-llm-request","surface":false,"digest":"0c556c9b9f2a96238a6b9bbb99e748206cbff2ed6203041c9571f04ae5802f52"}, {"key":"event:working-directory/change","kind":"event","event":"working-directory/change","surface":false,"digest":"124aa62078ca3311353b39cc3bf6c75da281338be6bbf672f8b361d828cddca3"}, {"key":"event:workspace/changes","kind":"event","event":"workspace/changes","surface":false,"digest":"e308ccf867a5398e316e0af8cb6ce238a8d33a63b9b384c8250a686786285f72"} ], "types": [ {"digest":"0116b1f89c05221d56b0ba35c83d302bf4857bc7277d247e9bbaf74b27d2c66e","names":[],"sources":[]}, - {"digest":"01c161379a3c3394a642807843e108ef911a8b7dbffd6d7de43f4484c88b0796","names":["packages/llm/llm/src/message.ts#DeveloperMessage"],"sources":["packages/llm/llm/src/message.ts:157"]}, {"digest":"0203243b72fc867afc81aff5f4cf2167e564ed342534eb612fc92f295cf07789","names":[],"sources":[]}, {"digest":"022623b9ef98ec47ec3c3bae0c51027c70d2601141c5e92e26a0d83d1b4cef06","names":[],"sources":[]}, {"digest":"023a355b2be0d688fb6e4df8388dadb942761d46cfe96d0f499aae9631a159d4","names":[],"sources":["packages/core/session/src/types.ts:211"]}, {"digest":"02b2c23f2d94b028c9588a8faace3fce1217405db346da3389368b495457bf79","names":[],"sources":["packages/extensions/cordis-host-runner/src/index.ts:14"]}, {"digest":"0341d4c3dfcd53253cdc1e789d9130d3cd848b6f8b0706bf92f313a68b39ff23","names":[],"sources":[]}, {"digest":"05205074b24d8340cfd7995f6cb64779c7f1241490954700115601e264178877","names":[],"sources":[]}, + {"digest":"058fc9a6b4fbd5d43437c3a64170002070dfc98e18d87de294b564ae446ca8ae","names":["packages/subagent/subagent/src/catalog.ts#SubagentCatalogEvent"],"sources":["packages/subagent/subagent/src/catalog.ts:32"]}, {"digest":"05a2796621b1ee6c03ef7abe560b25116bb4da4d592312117242a78415a32b04","names":[],"sources":[]}, {"digest":"05d2ae1e0c7f8770f83f9a09047afb39a335d8ac986df3193659aa1e581472cf","names":["packages/interaction/user-approval/src/index.ts#ApprovalPolicy"],"sources":["packages/interaction/user-approval/src/index.ts:68"]}, {"digest":"0657d3ca5ac4e7bf79b00bcf860b1c7159d01a9da137497221ec2f1776e365f7","names":["packages/core/session/src/types.ts#SessionSeq"],"sources":["packages/core/session/src/types.ts:33"]}, @@ -92,7 +92,7 @@ {"digest":"0af3ecfb8c60d416fc40a7cc4fb2c4851a8e46608b2b38ab9e510670c971aa1f","names":[],"sources":[]}, {"digest":"0b6d718c693fdf7f06dcccb0bcbbabe78cc63514eafc62d6b2a3899735279d6f","names":["packages/goal/goal/src/types.ts#GoalRef"],"sources":["packages/goal/goal/src/types.ts:20"]}, {"digest":"0b9b8facbe2c19773b3fb0ecc824ccbcc603d41b8f18069faa3807d449572fce","names":[],"sources":[]}, - {"digest":"0bcfaf5566d271028429ac7b562cb59053c9d78b8ae14708c35fac835108d1b1","names":[],"sources":["packages/team/agent-team/src/types.ts:181"]}, + {"digest":"0bcfaf5566d271028429ac7b562cb59053c9d78b8ae14708c35fac835108d1b1","names":[],"sources":["packages/team/agent-team/src/types.ts:185"]}, {"digest":"0bdaf9cb63594be4ef034b68901fffe792fe09d6d5f6bac42d7f56f6e7834fb9","names":[],"sources":[]}, {"digest":"0c4205180f75b9ee1e0d878bd9a9851628b5dc18448486389d9c5fdc3f1ccda3","names":[],"sources":[]}, {"digest":"0c556c9b9f2a96238a6b9bbb99e748206cbff2ed6203041c9571f04ae5802f52","names":[],"sources":[]}, @@ -113,6 +113,7 @@ {"digest":"12a0cfa619ac4a5fc6c3e8e359c8dae15769edc61497a575935c78d5842f8e42","names":[],"sources":[]}, {"digest":"12d5808fac1996b9b3c2afa806e03022252ba2d7b88f835862ae1896591f60c7","names":["packages/llm/llm/src/types.ts#ImageBlock"],"sources":["packages/llm/llm/src/types.ts:86"]}, {"digest":"1379f0b72275994d20f1ddca2d60a96ab16ec80397ca9f1af21bdc67ba5c269c","names":[],"sources":[]}, + {"digest":"137ac60e26bcb192210d9a32a704b73b0924ed34019323defa1b787be95bd45e","names":[],"sources":[]}, {"digest":"13d3d180f977bf78081d487ffa0ecb75857349bcab29a5a3fb48189fca2a6176","names":[],"sources":[]}, {"digest":"14230f9b8b5797bb7e8c621fa636531cfbde2ffba1ef5f1fd058216ff21952a0","names":[],"sources":[]}, {"digest":"142c37d302aa22a0a57915b5255939d3ca91c1811ca13fddcf84cf76ea00758a","names":[],"sources":[]}, @@ -121,6 +122,7 @@ {"digest":"15495614ccfa9cbdeefb0ec2abd76406435f4c6ff3dae42acae8e09ef42025c9","names":[],"sources":[]}, {"digest":"1571525adc95a24e5d25b5a6440df401cd7cdd881b745178e85f5a333435cd1b","names":[],"sources":[]}, {"digest":"15d5dfdd822aa35e115afd74a8982825a493880457774e6850bc1520b50875e4","names":[],"sources":[]}, + {"digest":"1682631f010d5ea717d181ed6f4ef46cde08d92a31ab461e7e98edfc98461f85","names":[],"sources":[]}, {"digest":"16d0507cb94b4cfc84a87446b1ba7652d6ec1d65ee1684789e747e30d542800e","names":[],"sources":[]}, {"digest":"17aae616ef020b8b9f011ec398ec935450fb06d3e2a0722c456f63aeaf5ff728","names":[],"sources":[]}, {"digest":"17d1afb770d9941936130996da00dc86782cfef731d8d6526162c301256a4ac3","names":[],"sources":["packages/core/session/src/types.ts:435"]}, @@ -155,7 +157,7 @@ {"digest":"1fdad624334d354820dfb3a26e28d0bc9fc1b62a33f87bab63f715b3f4391bfd","names":[],"sources":[]}, {"digest":"20a57544bbf204dacd1ae6beb2ab29444365c3c869f2afdf489dcdcbc3d9c8c5","names":[],"sources":["packages/plan/plan-mode/src/index.ts:53"]}, {"digest":"2142e391b9ccb60d487afcf373ce74db98d952f69e8289eddb352a7e16e996c5","names":[],"sources":[]}, - {"digest":"2152caf1a71e588e4df2358a806dea24936c1c47131134f01a12939d12cdc0c0","names":["packages/team/agent-team/src/types.ts#TeamMessageSource"],"sources":["packages/team/agent-team/src/types.ts:117"]}, + {"digest":"2152caf1a71e588e4df2358a806dea24936c1c47131134f01a12939d12cdc0c0","names":["packages/team/agent-team/src/types.ts#TeamMessageSource"],"sources":["packages/team/agent-team/src/types.ts:121"]}, {"digest":"21fb6a90d5068f6a0003b7ab316ed2f56342477146a65c00db0f13c4d8df667d","names":[],"sources":[]}, {"digest":"2235d957bf4b7c6cf959231d480f0ba1f3a6d72d82981493fb6c7c963021d3d5","names":[],"sources":["packages/session/working-directory/src/index.ts:29"]}, {"digest":"224aa11d4d5f88c450822d01b99e6ca5e3a9c7f26a5ede10bae33384a09ef4dc","names":[],"sources":[]}, @@ -174,6 +176,7 @@ {"digest":"287211846beea1eccb5f9acee00d20388a38fcb2e95858fa2332d6f58529379a","names":[],"sources":["packages/llm/llm/src/types.ts:165"]}, {"digest":"28936c614bd4e7e2774806edcbb3cbfd3ee643ac1cbf0bbdff43d915505a8fe3","names":[],"sources":[]}, {"digest":"290f32bfd81ff85a8095886a8066fae06e885942b63a8bcd6a8d66d328445808","names":[],"sources":[]}, + {"digest":"295809283ede248d14e6a431dec1c464cfd80a54b0d8f2a5994219fd8c8f9998","names":[],"sources":["packages/core/session/src/types.ts:317"]}, {"digest":"297fbd8067d7815adae02b89790ec6ff5fb7c2cb0d0eb026e1746c24ec857761","names":[],"sources":[]}, {"digest":"2aad1179f957631477b582e57cd8f538cb82618fc3fb816bde1171154235b065","names":[],"sources":[]}, {"digest":"2ab12a0e345658f9342816d773fe610f049982bcad82631f43b9205abe43e5ee","names":[],"sources":[]}, @@ -185,7 +188,7 @@ {"digest":"2da725e554cd89301d829ed9dc45a572c3cd1b93b5e91d0d71f007976d8a0863","names":[],"sources":[]}, {"digest":"2e3523541e942ef6cc9fbc5b91f242e0ca4c6ada479b79b96025b797f6e41f3f","names":["packages/schedule/schedule/src/types.ts#ScheduleChange"],"sources":["packages/schedule/schedule/src/types.ts:232"]}, {"digest":"2e4debca12f2c449f96dc6574f3fbf2fb346193443114a241d01a236362ec48c","names":[],"sources":[]}, - {"digest":"2eafefdc6f79a4922d68a787a09eaf4dd2b2369c3777fba4c05e800b5678ac8e","names":["packages/team/agent-team/src/types.ts#TeamMessageSnapshot"],"sources":["packages/team/agent-team/src/types.ts:108"]}, + {"digest":"2eafefdc6f79a4922d68a787a09eaf4dd2b2369c3777fba4c05e800b5678ac8e","names":["packages/team/agent-team/src/types.ts#TeamMessageSnapshot"],"sources":["packages/team/agent-team/src/types.ts:112"]}, {"digest":"2f1e6a7ebace43d727ae138ddcd352eb3813960009e5805b8c5ac84300c97716","names":["packages/attachment/attachment/src/types.ts#ImageMediaType"],"sources":["packages/attachment/attachment/src/types.ts:8"]}, {"digest":"2f3f201c8846e19c20bb75c02280e3d4eb3c57509e4715f0c0a4d1d4f91a7a06","names":[],"sources":[]}, {"digest":"2fe5026daf14bd4ff2b7bfb7cf9791c302d9cbba06802178b6dfec00b892698f","names":["packages/core/tool-executor-ptc/src/types.ts#PtcDispatchStartEventData"],"sources":["packages/core/tool-executor-ptc/src/types.ts:12"]}, @@ -214,6 +217,7 @@ {"digest":"3b1be838223869fe0a08210db85bf773796ed3f2373ac16555dff227cade0c48","names":[],"sources":[]}, {"digest":"3b4f2c9ef2c1217eac596c7b070173cb7896e2fae09e729bc7c56c801e56bb29","names":[],"sources":[]}, {"digest":"3bc287e765d58dc3a22672a0495a6cfd561220dd38fbaecef80aa95b96caed79","names":[],"sources":[]}, + {"digest":"3bca25b2baa6b22be9b577621a7603497f40870ed88a8dac4383d37dc2bb6e18","names":[],"sources":[]}, {"digest":"3bd652ebfa8726b3ce3937a4f1bd2759e02f86b3a08a20f9e41a8513656fbc5f","names":["packages/core/session/src/types.ts#OptionalSessionSeq"],"sources":["packages/core/session/src/types.ts:66"]}, {"digest":"3bdb8dc6989655b0d4ec361edafb8e2629bc263e1ea591819414fdafc1a413b3","names":[],"sources":[]}, {"digest":"3bec87f9e6ab3da03346f49923d3c51621debc0159df68605e543c3b2a026f90","names":[],"sources":["packages/llm/llm/src/types.ts:497"]}, @@ -227,9 +231,11 @@ {"digest":"3ee93b06f3a125850337602bcdf155d2538c43a5c944ec55b1b3c365152d6796","names":[],"sources":[]}, {"digest":"3f74ba74acd10644c1ed6947a411d8088bd2cfac74f61bb8540f96d68e31f004","names":[],"sources":[]}, {"digest":"3fdf9582c3b5597df104d32d97dab6c6ee3a93794f3034ec6ada6272404ea27f","names":["packages/schedule/schedule/src/types.ts#LegacyAfterScheduleRecord"],"sources":["packages/schedule/schedule/src/types.ts:161"]}, + {"digest":"4018a00144474b6c60dc1aa6e5c1f03611c66bd739833779a7d20a511df6d082","names":["packages/team/agent-team/src/types.ts#TeamTaskSnapshot"],"sources":["packages/team/agent-team/src/types.ts:64"]}, {"digest":"408927267422a7b2beb6df354ff7c1406d929a5646554f48adf85eb8372f811c","names":[],"sources":[]}, {"digest":"4208123b50df5006b181481ab45fcf1cde807b88d3fd4d340090bc2e202fac41","names":[],"sources":[]}, {"digest":"42e0916e0dda5f6d1e7bb05d8514717147c036a79c9f36085683469516c1fd3f","names":[],"sources":[]}, + {"digest":"42e2ff61928fb7dfaf0f057d61686f3a32ff713da419d12d4f250efc96733fe0","names":[],"sources":[]}, {"digest":"4312134fc6f9cad507c31390bd3d147535492dd77621ec517c5e85f853d53a03","names":[],"sources":[]}, {"digest":"43e311235aa537df1bacdd92d144df8a952337a76e9ac892cdf670f1a797bad8","names":["packages/llm/llm/src/types.ts#ToolRemovalBlock"],"sources":["packages/llm/llm/src/types.ts:134"]}, {"digest":"44818000e56acb97afdb5045ce235eb55e3fb1ccabc9fc7d0750bb38f36a7f8e","names":[],"sources":[]}, @@ -253,7 +259,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:198"]}, - {"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/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/team/agent-team/src/types.ts#TeamId","packages/team/agent-team/src/types.ts#TeamMessageId","packages/team/agent-team/src/types.ts#TeamTaskId","packages/workflow/workflow/src/types.ts#WorkflowRunId"],"sources":["packages/api/session-controller/src/types.ts:389","packages/attachment/attachment/src/brand.ts:6","packages/compaction/compaction/src/brand.ts:4","packages/core/session/src/types.ts:21","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/team/agent-team/src/types.ts:20","packages/team/agent-team/src/types.ts:32","packages/team/agent-team/src/types.ts:8","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/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/team/agent-team/src/types.ts#TeamId","packages/team/agent-team/src/types.ts#TeamMessageId","packages/team/agent-team/src/types.ts#TeamTaskId","packages/workflow/workflow/src/types.ts#WorkflowRunId"],"sources":["packages/api/session-controller/src/types.ts:391","packages/attachment/attachment/src/brand.ts:6","packages/compaction/compaction/src/brand.ts:4","packages/core/session/src/types.ts:21","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/team/agent-team/src/types.ts:20","packages/team/agent-team/src/types.ts:32","packages/team/agent-team/src/types.ts:8","packages/workflow/workflow/src/types.ts:13"]}, {"digest":"4d60dddaa65d3da8d4cd014d85ce3d2c2875664dd0433e331d8e9d395289686b","names":["packages/experimental/liveshare/src/host/viewer-principal.ts#ShareViewerPrincipal"],"sources":["packages/experimental/liveshare/src/host/viewer-principal.ts:24"]}, {"digest":"4e011753f8263f436efaabfbb3b4db53a98fc55342c5ded2daf7208b217be159","names":[],"sources":[]}, {"digest":"4e44c9118152f6829634bfd508e47669ab0497caffa380c94b4be91f9390d35d","names":[],"sources":[]}, @@ -262,16 +268,16 @@ {"digest":"4f507598cf476214aa7646ce7841a7064a9dcb05d0a1eaaefaf79c2b738f160f","names":[],"sources":[]}, {"digest":"4f91f187baeabef5c7950c4780d31bbe39f3345dff591a6cf26ac7e135ac1cf4","names":[],"sources":["packages/context/session-reference/src/types.ts:18"]}, {"digest":"4fb59762612c3e3ac3a3bd4f84c9c148d3c3893bd422ba2b201cc039fabd49bc","names":[],"sources":[]}, + {"digest":"50a15408d511e9be3fa93abff37a38ae770f3ab905fc6849fee0d989200d2b97","names":[],"sources":[]}, {"digest":"50cf02d875f8a1f1411f4a6fbcffab9120ccef5f74a47331fbf29480e5f68f48","names":[],"sources":[]}, + {"digest":"510826cf4e1f9220d75c1efd90b349dd9a77fc5ba15d19e16f87e85a48db5f99","names":[],"sources":[]}, {"digest":"511801b0a6470d98566e8385d3dffddb2b67f79fcf73ed6056f46c3cc0a245a7","names":[],"sources":[]}, {"digest":"516da4cdd6d2f1e5ce488e648578ca51f40e458f707b803e5b24de870e799415","names":[],"sources":[]}, - {"digest":"51edec100659da3a9bd9c3f6ba1180f5e64ec9a1585e5057080df45c180bd357","names":["packages/team/agent-team/src/types.ts#TeamTaskSnapshot"],"sources":["packages/team/agent-team/src/types.ts:64"]}, {"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:383"]}, {"digest":"530da6c0267813bb4511af72883cc518834e624e3b3220a7062955fd57a788a6","names":["packages/core/session/src/types.ts#RequestHeaderReason"],"sources":["packages/core/session/src/types.ts:279"]}, - {"digest":"53750b9abf61efb7992b0aadc3e247ec927449c63266df28230fd1139f5590ac","names":[],"sources":[]}, {"digest":"53cf1704ae0709c7678bcf070c83c619fc48ca1b5c173b74cfa8702f22a8e492","names":[],"sources":[]}, {"digest":"54f9276a1617d7c12594722c89cfe864bcbe4517e9a6f9c98bab14f199a135e0","names":[],"sources":["packages/core/session/src/types.ts:363"]}, {"digest":"557e148d30b79ee48645850832b30c717d7c3b64641deb5d6133b8b4e91ee0b8","names":[],"sources":[]}, @@ -305,17 +311,15 @@ {"digest":"5f2117d1856a5ab43c28371faa978ebfaa48f8c7d734ea3fc94842210df83dca","names":["packages/llm/llm/src/types.ts#LlmFailure"],"sources":["packages/llm/llm/src/types.ts:48"]}, {"digest":"5f26a6c20b37632f8f57729d171c671def4683d994ac6257a8dffcd855101627","names":[],"sources":[]}, {"digest":"5f758f3de5f00c18968a7c6d347083aac5c9ae13f6a79c78f6611b23c4973564","names":["packages/subagent/subagent/src/descriptor.ts#OneShotSubagentDescriptorData"],"sources":["packages/subagent/subagent/src/descriptor.ts:61"]}, - {"digest":"601327bedca5f98a0fa4c27133bd35749f3af2baaaacf53badf074e59cea5d25","names":["packages/session/session-title-llm/src/index.ts#SessionTitleLlmRequestEventData"],"sources":["packages/session/session-title-llm/src/index.ts:43"]}, {"digest":"6085488d223aeffdef51d7ae17655fc26ab22ee13cbed82a50e62e2b6fb5b918","names":[],"sources":[]}, {"digest":"611cae9a3539733aa0c42f66035a7d90f19dcbbdfb5d9e3b628b13705253942d","names":[],"sources":[]}, {"digest":"611d82d2dc50df706cf08a0fc04bc8eaf78083391fe6f10313de943e615dd2da","names":["packages/jobs/jobs/src/types.ts#JobSettledData"],"sources":["packages/jobs/jobs/src/types.ts:40"]}, - {"digest":"613660455704fb82a825b5b766e000aa64b5b4d44b4f10e55cffe968d4ec6ab1","names":["packages/llm/llm/src/message.ts#UserMessage"],"sources":["packages/llm/llm/src/message.ts:162"]}, {"digest":"616f93a5047de668e1c30d57b1786abd76beeb4123599637ec1dc5290320ede5","names":[],"sources":[]}, {"digest":"6292bcbedaa97feaec5b48a03bb8144b581b93309d9d6c905f26da7a6a7a0a4f","names":[],"sources":[]}, {"digest":"62e6a429ff3f390a46ac39fb468692032f42936ca0db19b53454184189401379","names":[],"sources":[]}, {"digest":"62ecb62dc0fe1b5e70217f8a80c39256a40ee3a1917be14e5ca899d20c35f7fd","names":[],"sources":[]}, + {"digest":"63ba8895cc09e4693cf0819fdcd18c084bef195febda5b6a23af279b3852be36","names":[],"sources":[]}, {"digest":"6487b10ba7542f3c447b1e41a1c6a590b7bfafe0b9b66b49f34028da85bb970f","names":["packages/subagent/subagent/src/descriptor.ts#ContinuableSubagentDescriptorData"],"sources":["packages/subagent/subagent/src/descriptor.ts:72"]}, - {"digest":"65377a76c6a58f785d95b89f89f2e13d289cb88a70ea74939d0ec08f429f0a6e","names":[],"sources":["packages/core/session/src/types.ts:317"]}, {"digest":"6598cd6da253948d6b207c6374a45335804c79b576866d6215649c2d1bc85e25","names":["packages/team/agent-team/src/types.ts#TeamMemberSnapshot"],"sources":["packages/team/agent-team/src/types.ts:50"]}, {"digest":"65a8400e451e667e5b6e34df72ceb81fca8c12330330fa72083ad40279b189ad","names":["packages/llm/llm/src/message.ts#SystemPromptMessageSource"],"sources":["packages/llm/llm/src/message.ts:35"]}, {"digest":"65d583e66518c5236015e0846470fb32efcf92375ed306aef14e50a9d2cd2099","names":["packages/skill/tool-skill/src/index.ts#SkillCatalogSource"],"sources":["packages/skill/tool-skill/src/index.ts:35"]}, @@ -325,7 +329,6 @@ {"digest":"68141cbe3994a5ffcd064c07c75996538437fd9dbf77ce8a2927e89ec577fabe","names":[],"sources":[]}, {"digest":"688e853dc149f0d30b31765c12ec7e3be74169bdf1a4c6463a10b945d50cc1b8","names":[],"sources":[]}, {"digest":"68f44f59e91c41395076cb77265981a601680ec8a381bbbeb6ab754ffdc94573","names":[],"sources":[]}, - {"digest":"690583582246babf6120f16eefd849dd760c5ec84619014951af403a1b3032c0","names":[],"sources":[]}, {"digest":"69081694be231d56fd9580ba14645fd5e35373202605d5c5c841a9435b5fa3b1","names":[],"sources":[]}, {"digest":"693f4952fb5565da96c06bace8924b098ac2fbc915fde0ff8019701183abc057","names":[],"sources":["packages/llm/llm/src/types.ts:168"]}, {"digest":"69d238a6e9b08d67f601b1825962963d8d3523cb69ebf6208c697dc5d058c199","names":[],"sources":[]}, @@ -350,12 +353,12 @@ {"digest":"6f72ece8f317cd080c4f20a93f1bf709965f5b81ac4669528f5a023191cfcf20","names":["packages/llm/llm-retry/src/types.ts#LlmRetryStartedEventData"],"sources":["packages/llm/llm-retry/src/types.ts:43"]}, {"digest":"6f9e00383836275e46c0a9915767f9bb561be5fc30aae490174908a93e99a912","names":[],"sources":[]}, {"digest":"70b082fe78991edf13cf66e1b4d06cd2dcff9cacfd76f8cfb996bfb61939e7b2","names":[],"sources":[]}, - {"digest":"70ea8e7943c5e2d76905bcc2e694e8c3d5b138aaae3609f3e261b8d369a6e35a","names":[],"sources":[]}, {"digest":"7180844e1066230c5e891f1b9ccd942423b0fe48aac6ded7eef2a285b288a732","names":[],"sources":[]}, {"digest":"719c51f67074f97034a6c94297fe1f4b5d3c8d392c57586dab732aa5398c7a91","names":["packages/llm/llm/src/message.ts#ModelMessageSource"],"sources":["packages/llm/llm/src/message.ts:24"]}, {"digest":"71bb3254ec8f1e491ce63b762a7b5f18709de23aa4e8abcc8b886f4b6ce051dd","names":[],"sources":["packages/llm/llm/src/assistant-stream.ts:28"]}, {"digest":"72ec79127a9c0d0241b1106a74cc2b24c81ce467170f1c3c93f7b71a9496d227","names":[],"sources":[]}, {"digest":"7382c4fc95fe8c5db65ca4d9da572b115d0dbb818b7f32c22ab040318ffbb4bc","names":[],"sources":[]}, + {"digest":"74e0e5885d2ddf04530ddf341b25cd65e1f85c00b30a88bd992f11fc06615a0c","names":["packages/llm/llm/src/message.ts#UserMessage"],"sources":["packages/llm/llm/src/message.ts:162"]}, {"digest":"750a2b129d67704df675c06823c20c80b65cbae89d5aaa914fd5a72e3df395b5","names":["packages/jobs/jobs/src/types.ts#JobSettleCause"],"sources":["packages/jobs/jobs/src/types.ts:247"]}, {"digest":"7554565be416b0342053ee6a46256c9dab07c487349b4a5f10bab1edc151c619","names":[],"sources":[]}, {"digest":"756b5e23a5cb2c7f486f366a828f7461c88902af21125bd6810881f4ccbff6cc","names":[],"sources":[]}, @@ -386,6 +389,7 @@ {"digest":"814d9434e1ddf9078612b3b34322f26e9363b469213335007f7e9ba7fee9464e","names":["packages/llm/llm/src/types.ts#ReasoningBlock"],"sources":["packages/llm/llm/src/types.ts:75"]}, {"digest":"82470020b5bfcb1a843e2aa05602af7d37df99e82d01f015c7c589ba054fd89d","names":[],"sources":[]}, {"digest":"824a4aad44a54e245c67196817d67946734a2dc0eee0b0b6834a5b2a6ef352ce","names":[],"sources":[]}, + {"digest":"824b1d4d4f007bdaa5eee7994a5db3ede7707c6cd2bf8e2509be176c7609e3bc","names":["packages/llm/llm/src/message.ts#DeveloperMessage"],"sources":["packages/llm/llm/src/message.ts:157"]}, {"digest":"825ca23416b1ea9d81442afead5cf9229a6fa05842f042135cc3aa9710a6a2d8","names":[],"sources":[]}, {"digest":"829a2fb3be6efd4ba36aef8ed2d381a4c6fb2a0aaf50c823a6f3f8290786b809","names":[],"sources":[]}, {"digest":"83079c8a3f733ac3fa603eefa0fbb4737ca4d8b69e7e2e7298b60f9ac4098693","names":[],"sources":["packages/skill/tool-skill/src/index.ts:43"]}, @@ -409,6 +413,7 @@ {"digest":"88841202942c7683b3b7e5ea6a796047ec326b6701ac23e58cc236d85613b9fa","names":[],"sources":[]}, {"digest":"88a610b831be6d92612a464be5c7d0b88ec24d97bd299837bf74bf7672183c9a","names":[],"sources":["packages/llm/llm/src/types.ts:500"]}, {"digest":"8a046b52331959aa3394680d6acbe09b8a5447c6b61375f263445bfcef19b7f1","names":[],"sources":[]}, + {"digest":"8a54d228b1b7d8453e4304d32723d489f28b4b33b221f335342146926ad94fc6","names":[],"sources":[]}, {"digest":"8a6e1ec9e8db346b0e02f027db73c07a94f067a26d40c1aef1abd09c47ce7ba0","names":[],"sources":[]}, {"digest":"8a9c990773f798eac10ca8878e6bcc531ee080bc589cac956730e462cc6a09ad","names":[],"sources":["packages/interaction/permission-presets/src/index.ts:53"]}, {"digest":"8ad45ad053b4d89f8865c17cc9ff3b8748e86045f3f0fb816269a34af2619141","names":[],"sources":["packages/experimental/hook-protocol/src/types.ts:31"]}, @@ -421,8 +426,10 @@ {"digest":"8e611bf46821e5003a1605a73560a6f56388295149d449dfe2142d5ec335f29c","names":["packages/llm/llm/src/types.ts#ToolAdditionBlock"],"sources":["packages/llm/llm/src/types.ts:122"]}, {"digest":"8e8155594e07812356b67d732196dda894b0f9c91a5969d51612cf490b0a016d","names":[],"sources":[]}, {"digest":"8e8e91646a5cae3fc78f7532a0013ff2088ae47077642c2edd507a508209b8af","names":["packages/schedule/schedule/src/types.ts#OneShotScheduleDispatchChange"],"sources":["packages/schedule/schedule/src/types.ts:213"]}, + {"digest":"8f1062573ea9184129dfdec43df1e8136eb5808746fd809bf6b539f3fd11362e","names":[],"sources":["packages/api/session-controller/src/types.ts:402"]}, {"digest":"8f324cea3916c0517261e88167def8efb3a9994c1135e23d40ed9fd48f8c7bd4","names":[],"sources":[]}, {"digest":"8f6d609794bf5afc01d7ccf3e03811d32f4b8047f58a2c9a98db0154c2ad7cb9","names":[],"sources":[]}, + {"digest":"8faed5b52ab2d2df40b94a926d0f0faa75280bddcc4b17b6bdd9c8bfed7c34b5","names":[],"sources":[]}, {"digest":"8fcb0b44a575e998665c053643d1ab04c82f39253ebd190ac0c975b78e40b543","names":[],"sources":["packages/core/tools/src/index.ts:28"]}, {"digest":"904bf499d98be4a3a5f836fcac533b6c4899569b018071e6604e1d32657d00fd","names":[],"sources":[]}, {"digest":"920d87e22b7409bcc7224f8b1dc7f5101c33574c75627c65baab12b85cc96e75","names":[],"sources":[]}, @@ -435,7 +442,6 @@ {"digest":"94c56aeb1564ad735eb773d88636b40761d063efa1610f1308004d32923f5378","names":[],"sources":[]}, {"digest":"95080295115fbd83544520ba247b68a03790131f6a2eac323d388758cb542f65","names":[],"sources":["packages/llm/llm/src/types.ts:498"]}, {"digest":"95a3ffccbf3c8afcf9a2f3b355f724da8e07e98dc47ee741166dde7f9ea058bd","names":[],"sources":[]}, - {"digest":"95b5cf90ea1f57da3319184d6f5f3811d0f651aa9113591c10e81c3d1e9b9f70","names":[],"sources":[]}, {"digest":"95c0e88fcf0bafb2087f912ad9e2369de6ae6530cc0c4c2772c96205b57f7f60","names":[],"sources":[]}, {"digest":"9645cf93769a6dfb227bd400bd6cb9fa7bab9140f4a851e4ae92514ade6e3114","names":[],"sources":[]}, {"digest":"96bfb916a727cd4445a594df264c523fc039749a31bfed924b8cc7bb308a5bb0","names":[],"sources":[]}, @@ -473,8 +479,8 @@ {"digest":"a3a259a1aa5401af786ce08c4a8419681d3000d73467991b5fc563389bc4ebd2","names":[],"sources":[]}, {"digest":"a3c6f1ea38e9a61d7a9706057ba65aabe02dfe6d9dd90d4736aa62325d874531","names":[],"sources":[]}, {"digest":"a3edd1efd1fef21b72c55e213c8a8b24196b091abde2b89db52be0b2aaae3cfa","names":[],"sources":[]}, - {"digest":"a40d12070f6f4a124f32fb3cc86e7857554702e32f0eda3080a25c4b9ac9b18c","names":[],"sources":["packages/team/agent-team/src/types.ts:177"]}, - {"digest":"a4afec59b75aad5d13ef82d6931f35cc2d98918503916cf069355b77c5e42302","names":[],"sources":["packages/api/session-controller/src/types.ts:398"]}, + {"digest":"a43327a1739c3fa477f32981071fef7d8ba6ae5f32a84fd70f547b2eee59e93e","names":[],"sources":[]}, + {"digest":"a4afec59b75aad5d13ef82d6931f35cc2d98918503916cf069355b77c5e42302","names":[],"sources":["packages/api/session-controller/src/types.ts:400"]}, {"digest":"a6567ccb2e530606b775371eb4fa31468d72084339968e8b0440a516a23b39dc","names":[],"sources":[]}, {"digest":"a6b41f5bede8094d7bf635be5d69b1bd7a25e006ca9cf9415bceb9322f1a7feb","names":["packages/experimental/hook-protocol/src/types.ts#HookDialect"],"sources":["packages/experimental/hook-protocol/src/types.ts:48"]}, {"digest":"a6da9ad5d42ae83a6833a8288b076688e8e0801633ea36cbdd8a30a6d9f3160c","names":["packages/workflow/tool-workflow/src/types.ts#ToolWorkflowRunStartData"],"sources":["packages/workflow/tool-workflow/src/types.ts:14"]}, @@ -485,6 +491,7 @@ {"digest":"a8a2b9011fc067862df7ce40748868467e5778283d7ac193c13f77684a914c57","names":[],"sources":[]}, {"digest":"a9059a81430b320792bbb7c2ee1f8f6c77ff71e40ee44c18aec72e157c522694","names":[],"sources":[]}, {"digest":"a926dc71814edd01a4f041eb5fc766d153db3407ef4704e98f4c1b6527309ebb","names":["packages/schedule/schedule/src/types.ts#LegacyEveryScheduleRecord"],"sources":["packages/schedule/schedule/src/types.ts:173"]}, + {"digest":"a9427866376b691aace0ce25aa0e1bdec2a14156a05152947a467da3f7967cb9","names":[],"sources":["packages/team/agent-team/src/types.ts:181"]}, {"digest":"a99ec0993c62c058e50af9f68922202a3b54f5e259bc2abf1915a73381d2316d","names":[],"sources":[]}, {"digest":"a99f76fd149051c363f960bfeeb5b9509587ecaf7591a42797e4bfe810d8987a","names":["packages/todo/tool-todo/src/types.ts#TodoItem"],"sources":["packages/todo/tool-todo/src/types.ts:23"]}, {"digest":"aa0957eca50aeb28bcd2e6930b95809926edacb550c8c340ba526ba6b861b3d8","names":[],"sources":[]}, @@ -510,10 +517,9 @@ {"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":"b120362fd216a16a40fe787f6d3286086aa131266322bab79c026a130ccd0f72","names":["packages/llm/llm/src/message.ts#MessageSource"],"sources":["packages/llm/llm/src/message.ts:136"]}, {"digest":"b158f3ff6923714807c0d73882f0b05dc87f8fa85c9e90814852d48bbc866081","names":["packages/core/session/src/types.ts#RequestContext"],"sources":["packages/core/session/src/types.ts:260"]}, {"digest":"b1664fa89f8eab49a14e7e3168d8bc4da4aa9fd76332f6c4a053d839e5276ae7","names":[],"sources":[]}, - {"digest":"b1ebd5cda47d90d980bb05bffc3f970c51537b9aff15b3bc3d639811727741b1","names":[],"sources":["packages/team/agent-team/src/types.ts:175"]}, + {"digest":"b1ebd5cda47d90d980bb05bffc3f970c51537b9aff15b3bc3d639811727741b1","names":[],"sources":["packages/team/agent-team/src/types.ts:179"]}, {"digest":"b1f62380f6746fedd629e71065e3583cef83334875b499ac9665c2eb87acfbf5","names":[],"sources":[]}, {"digest":"b222069eea2d768065161c1147b1f2c78c1b54328c84b3586ae5c8f91b8ed35e","names":[],"sources":[]}, {"digest":"b2245a906e13aa94f2d3cc6cf7b04cfa0267f7b7f4d468de1b00b1a314e54626","names":[],"sources":[]}, @@ -553,18 +559,21 @@ {"digest":"bb1ab3d08f49a9f3b265f844cd78d5c49813062a7b34b54904b426f85d0ff6e3","names":[],"sources":[]}, {"digest":"bb94f3217aa56c8876bbff0b8460d6a73cbead545659abb29e76cd0cf2cb92d6","names":[],"sources":[]}, {"digest":"bbc5696e3f13c758237b316e3cf08cda0b9fd51ffe672539883457769faa185d","names":[],"sources":[]}, + {"digest":"bca0f9cb63d8620b6954bb045b07bb07cb557513a7f0e2e177f5e87f704e7ba7","names":[],"sources":[]}, {"digest":"bcf0caf62d964b2fcf5404bd5c909cfa9a21c3f3c96e6b7e36d9e33565223825","names":[],"sources":["packages/core/session/src/types.ts:472"]}, {"digest":"bd499eac047efe091a4df7382eadd06d25cf0cb31fee3981e8b24d85762841cd","names":[],"sources":[]}, + {"digest":"bec5ca3a376f56f3d69df7f12a48e1cc07d4ea8305968773394c8734799faeb4","names":["packages/session/session-title-llm/src/index.ts#SessionTitleLlmRequestEventData"],"sources":["packages/session/session-title-llm/src/index.ts:43"]}, {"digest":"bf16d2e98a7f13894ded2cffe5ce857bf473954a0e3c0ed9bc7739e2e1c7b78a","names":[],"sources":[]}, {"digest":"c0ea97bc89dfc46fa94eab956f5c3ee6af2f964aa7db6327cb18b451f207bef7","names":["packages/workflow/tool-workflow/src/types.ts#ToolWorkflowAgentEndData"],"sources":["packages/workflow/tool-workflow/src/types.ts:29"]}, {"digest":"c170da8ab7c37635b10867b2571811d9e317ac3ec394e8ff8efe53f902fc41c1","names":["packages/llm/llm-retry/src/types.ts#LlmRetryEventData"],"sources":["packages/llm/llm-retry/src/types.ts:16"]}, {"digest":"c1f0f17b6493b85db6453bb30e01b208d703731b25bc1e68e5d4fc72eea9cdea","names":["packages/llm/llm/src/types.ts#ToolCallBlock"],"sources":["packages/llm/llm/src/types.ts:112"]}, {"digest":"c1f9e0405de6d18cabb9ee70782a027f9bbdc57e5abec9dcccdd56119e2e9058","names":[],"sources":[]}, {"digest":"c219efbdfd53b836786202ab4532913d555798f0a8615a4e9629736e3799fb70","names":[],"sources":[]}, - {"digest":"c2a13242efc3bea4b36a843ddf1524ff4d33c765a71b582fa1fdbfa4fa148434","names":[],"sources":["packages/team/agent-team/src/types.ts:173"]}, + {"digest":"c2a13242efc3bea4b36a843ddf1524ff4d33c765a71b582fa1fdbfa4fa148434","names":[],"sources":["packages/team/agent-team/src/types.ts:177"]}, {"digest":"c2deb7c9183735d4e0fffddf5c623f4e34daa1c8e96b111982e957dfcbbcf896","names":["packages/workflow/workflow/src/types.ts#WorkflowAgentOutcome"],"sources":["packages/workflow/workflow/src/types.ts:110"]}, {"digest":"c2f49004d9ae38a964e80850c87bc6849d6a872091a1d43e99eedf00c641e2a3","names":[],"sources":[]}, {"digest":"c43b119ce579b3e9983a0d3adc4ba402ebb9ba773d89738a2dab01ecf5813943","names":[],"sources":[]}, + {"digest":"c51f0d0a405bb96fcb008c0dc560a512dcd8c3919b6b446937f449ea2f7d21d8","names":["packages/llm/llm/src/message.ts#Message"],"sources":["packages/llm/llm/src/message.ts:196"]}, {"digest":"c5228b7a55498d84f529591744a0ab26e0b93ade18a70a26db1377a1ecfa6b49","names":[],"sources":[]}, {"digest":"c55827fba7018198772c50e37cb7d3f60a3d8bb6e94b07de72dee0d9f8968005","names":[],"sources":["packages/interaction/user-questions/src/types.ts:134"]}, {"digest":"c5687b1313206a6ff334066047b6a0681611467dc4df8c5a8e71d0b6df39311f","names":[],"sources":[]}, @@ -586,17 +595,16 @@ {"digest":"cffcdc19881ab61ec0a9ce18743996f7ac44ac8889f34dfac36ae745574aa22f","names":["packages/goal/goal/src/domain.ts#GoalClearChangeMeta"],"sources":["packages/goal/goal/src/domain.ts:35"]}, {"digest":"d0fbb0ca1bbba059830826f33f801da1aced35a2504376d61e020bdfec8d50c0","names":[],"sources":[]}, {"digest":"d28765f87d6b6ab408e0b2f3e7e297791b004b806d8e302c49903ebae815feb2","names":[],"sources":[]}, + {"digest":"d49164d37eab0f0f70fa787c65d887abbea869c010ccb103d717fab3519c3a41","names":[],"sources":[]}, {"digest":"d4b739491689cc6bb13d07ffac1a32239875abda364c0d5edd8f74faf5e9c00d","names":[],"sources":["packages/llm/llm/src/types.ts:501"]}, {"digest":"d4c799e3d51cae1040362ba4968efc484739e14416c9c1df20c2f108b4ef2eb5","names":[],"sources":[]}, {"digest":"d4e4d575abeb4b72d616dc65c17ac0eaa943cc135609395044c38d5afcb10e31","names":[],"sources":[]}, - {"digest":"d595ec73b32b016a6055333c67a5d646032b22e672da1d4a09c5b1ae398a093a","names":[],"sources":[]}, {"digest":"d63b8b8ffad9c02fd80c43a17df4f240c1fe8118ecca9de34f9d5871838ab5b9","names":[],"sources":[]}, {"digest":"d66e11dddf5dfa3c71547e2cbd7b0608824cd8d6243fc16f532017ff28e8fba5","names":[],"sources":[]}, {"digest":"d6e654b88b584fcdf290a56802b1730bc7b9847ae86baa4265ab7769eb48990c","names":[],"sources":[]}, {"digest":"d85590a5675c6e2fd8164e5792a6cceac714605b8ac228adae5ee668facb1490","names":[],"sources":[]}, {"digest":"d8a476d2c6fd30df6ec0e799f91716d1518c780d23b4121dce545abfcfb7c5a5","names":[],"sources":[]}, {"digest":"d9196086e41e4dd5c2ce87f5c25529c8112a1731d258cf0728747d41a9ee3241","names":[],"sources":[]}, - {"digest":"d95c624eddecdacf1ee74356196c09d2f3fcd625714be5e852a6b643fa12a7ca","names":[],"sources":[]}, {"digest":"d9c462b9f62fdd3efc76a44b9524dc8781f6b91cd9c7e584b17d971defafebab","names":["packages/llm/llm/src/message.ts#ToolMessageSource"],"sources":["packages/llm/llm/src/message.ts:29"]}, {"digest":"d9edf1862e4471d6ad8a106a3f4160e0643874368707d50ecd8e27e5ee7a2567","names":[],"sources":[]}, {"digest":"da60ed58a8fa23d7aa4920ab5c1f4e3d28109cb0797ef9e5c8b125721b847582","names":[],"sources":["packages/session/working-directory/src/index.ts:36"]}, @@ -606,12 +614,11 @@ {"digest":"db874d463b0fdec77e9da1c4568f37cb70bd6596781eb93800db44fb8a116965","names":[],"sources":[]}, {"digest":"dba54c09c6e7aafc9acbed7792ecc920d99f92d0784aeeed10af55f7fe0bc8cd","names":[],"sources":["packages/core/tool-executor-ptc/src/types.ts:68"]}, {"digest":"dbdafceb9a900183cccc80596498d386f3bf7bddead2b8cfde68453aa4739edc","names":[],"sources":[]}, - {"digest":"dcb07e04496586d2664d72dab0e94312917da56927b2a0dc3ee53d6a33e32450","names":[],"sources":[]}, + {"digest":"dca3ba43188095fa7342e49e6c206d4685125497d4767595bf12a62ea2fd73ce","names":["packages/llm/llm/src/message.ts#MessageSource"],"sources":["packages/llm/llm/src/message.ts:136"]}, {"digest":"dd00cdccd0ba487b92362ef67db58cd264f48c1bfd368291424a1da9a899489a","names":[],"sources":[]}, {"digest":"dd2780e7e07684332f7a9ab047237798d260e7eaffb1321cb38eca695d184c3d","names":[],"sources":[]}, {"digest":"dd5ee8762bd8a14b6c6bffedd1753e4e78505bb0f9ea1621018d03a54eef59d5","names":[],"sources":[]}, {"digest":"dd6cc2bb2a8f28248347021ad93565360b196a042360b4cd16b569d3a2a91f2d","names":[],"sources":[]}, - {"digest":"ddce54a3873dc57113b0cd38ad9b23b3c259186139e8847e5e5f415d86f52482","names":[],"sources":[]}, {"digest":"dde0cdf9d426768b649b5a9783d2144e7f900c35ef65229cd89036dbf411d1b0","names":[],"sources":[]}, {"digest":"de25352d2dc4196309bd84b5bac6319f6d5c898ea0e82bb5ae66c5738d0d426f","names":[],"sources":[]}, {"digest":"de30b1fa12c75f81df6aa4096e1595296d2d04e2be14a7c29849cf8028b79048","names":[],"sources":[]}, @@ -621,8 +628,6 @@ {"digest":"df843efd87c78cf8de98f8e0d0216956cd568d0d0e56a22c853663e274aa1a18","names":[],"sources":[]}, {"digest":"dfce5db4aa42b7ebe0bb79eca92553587287e18c06b9eba85cbfb9d332e26acd","names":["packages/team/agent-team/src/types.ts#TeamMemberPhase"],"sources":["packages/team/agent-team/src/types.ts:47"]}, {"digest":"e0a787e6ec76c7c94fecbc501b489164ab0293db05bc947914077ad01e674f05","names":[],"sources":[]}, - {"digest":"e1880c67e735e228f3555df8a55a492db2c0b0c71bc8859e938e184a46c7db51","names":[],"sources":["packages/core/agent/src/types.ts:110"]}, - {"digest":"e272493e3ea0b33b2e1d64b6a80e9d8bd3d1d466cc115f2facbdd598f8644a39","names":["packages/llm/llm/src/message.ts#Message"],"sources":["packages/llm/llm/src/message.ts:196"]}, {"digest":"e2ad8f5bcd813f268ffef1b10a12d7ddd2b8ced8b9b6d0275b3f6b7ed094a187","names":[],"sources":[]}, {"digest":"e2d0367e5716bc188435e51718ebff8ce873190625fa93b1c5331102d98758fa","names":[],"sources":[]}, {"digest":"e2f9a41e0989f54ed8cee80f8db2bcf9d60a5c810dc9d45b83fa050b9dce7602","names":[],"sources":[]}, @@ -647,7 +652,7 @@ {"digest":"e7f4cbb3a57f4cbdb61ea41e95bcba626ad1fff6bb9b1e063b1d50a32da6e864","names":[],"sources":[]}, {"digest":"e8de0f457fed5b9ff94dc4950b59ef75fd8ba8af665cc7899485924a62653367","names":[],"sources":[]}, {"digest":"e95f957154b2b1b58692af53d4131180b6dd19e2264869f876dbaa959991494e","names":[],"sources":[]}, - {"digest":"ea08ec1df0c33108fd03345b9af199cf04dea450aa045d3c683f216311403403","names":[],"sources":["packages/team/agent-team/src/types.ts:179"]}, + {"digest":"ea08ec1df0c33108fd03345b9af199cf04dea450aa045d3c683f216311403403","names":[],"sources":["packages/team/agent-team/src/types.ts:183"]}, {"digest":"eaa71be0fbf0f702df8ea6c11d0aa2f9782263d45a10d0fb14eda662f4bfe04c","names":[],"sources":["packages/core/session/src/types.ts:201"]}, {"digest":"ebb768d85ec87fb68e42fc14fd7d8535b5ac11791b14d04c6770180f0a719bf8","names":[],"sources":[]}, {"digest":"ec38b5949af8eacaf00df002f4acbe344f934f8a061e9cdc65a52a48e5f6dd93","names":[],"sources":[]}, @@ -680,7 +685,7 @@ {"digest":"f6afe41e3926f422fe849debe90819fddd739f0f59e20be9c71018b9554a7f09","names":[],"sources":[]}, {"digest":"f6cb462f808309e315fea634f1ed86268b8346bbcee6774d9097ca6eed7ac1f8","names":[],"sources":[]}, {"digest":"f7283223aacdc39b0adca728c8cbd4c090a20006a6fecec74421c30e943b489c","names":[],"sources":[]}, - {"digest":"f731ffe80810b0289b3e694d8f40af6f01865c02a622ee457be90ca808b66e87","names":["packages/subagent/subagent/src/catalog.ts#SubagentCatalogEvent"],"sources":["packages/subagent/subagent/src/catalog.ts:28"]}, + {"digest":"f7752f518bb2f9165f2c01559df1f570c23d57373defbbd4512399a0ffaf2492","names":[],"sources":["packages/core/agent/src/types.ts:110"]}, {"digest":"f789af5ab844827eb5a4f357c0afae1eeed108c6c22d8ca1a56e586b349a7c85","names":[],"sources":[]}, {"digest":"f88f1b7b6bb733f685f5fb6a8744a5db9199fa53c90463ea1a33bad51153671d","names":[],"sources":[]}, {"digest":"f90eb4ab2d3897bc20c521a038e3119d581f791ec974b1a0004f63a8ab9e232d","names":[],"sources":["packages/core/session/src/types.ts:294","packages/deliverables/workspace-changes/src/types.ts:106"]}, @@ -703,13 +708,13 @@ ], "nodes": { "0116b1f89c05221d": {"kind":"literal","value":"web_search_20250305"}, - "01c161379a3c3394": {"kind":"object","properties":[{"name":"content","type":"b52f215a6cd69105","optional":false},{"name":"id","type":"4cd48f3e5108bd6e","optional":false},{"name":"role","type":"589d0d91239681f8","optional":false},{"name":"source","type":"b120362fd216a16a","optional":false,"compatibility":{"version":1,"policy":"session-source-attribution","binding":"session.developer-message.source","discriminator":"kind","unknownKinds":"preserve","attributionKinds":["action-cards","tmux-context","user-question-reply","working-directory"]}}],"indices":[]}, "0203243b72fc867a": {"kind":"object","properties":[{"name":"kind","type":"24b10f7cdae64928","optional":false}],"indices":[]}, "022623b9ef98ec47": {"kind":"object","properties":[{"name":"form","type":"383cf73ae4748e5b","optional":false},{"name":"kind","type":"f68c335306535a00","optional":false}],"indices":[]}, "023a355b2be0d688": {"kind":"object","properties":[{"name":"kind","type":"254dce209e735f9c","optional":false}],"indices":[]}, "02b2c23f2d94b028": {"kind":"object","properties":[{"name":"kind","type":"c5687b1313206a6f","optional":false}],"indices":[]}, "0341d4c3dfcd5325": {"kind":"literal","value":"product-interaction"}, "05205074b24d8340": {"kind":"literal","value":"action-cards"}, + "058fc9a6b4fbd5d4": {"kind":"union","types":["0e10d7c096b47e61","5d542ac7bdf13310","8faed5b52ab2d2df","a0f25b5aeeebf2bf","a43327a1739c3fa4","b6896938660a1dfe","cbbe8377ee744964","e2ad8f5bcd813f26"]}, "05a2796621b1ee6c": {"kind":"literal","value":"unknown"}, "05d2ae1e0c7f8770": {"kind":"union","types":["1571525adc95a24e","9e07693fd7cd9bab"]}, "0657d3ca5ac4e7bf": {"kind":"primitive","type":"number"}, @@ -746,6 +751,7 @@ "12a0cfa619ac4a5f": {"kind":"literal","value":"read-only"}, "12d5808fac1996b9": {"kind":"object","properties":[{"name":"attachment","type":"b0b0eb1b16490f6b","optional":false},{"name":"offloaded","type":"dacf3d5f3e4ff619","optional":true},{"name":"type","type":"fb8b6a2e53cb9cf4","optional":false}],"indices":[]}, "1379f0b72275994d": {"kind":"literal","value":"developer/message"}, + "137ac60e26bcb192": {"kind":"literal","value":3}, "13d3d180f977bf78": {"kind":"object","properties":[{"name":"data","type":"1528539c63db8b23","optional":false},{"name":"ignorable","type":"dacf3d5f3e4ff619","optional":true},{"name":"seq","type":"0657d3ca5ac4e7bf","optional":false},{"name":"time","type":"0657d3ca5ac4e7bf","optional":false},{"name":"type","type":"1a2718b00937b236","optional":false}],"indices":[]}, "14230f9b8b5797bb": {"kind":"literal","value":"chunk"}, "142c37d302aa22a0": {"kind":"literal","value":"always"}, @@ -754,6 +760,7 @@ "15495614ccfa9cbd": {"kind":"literal","value":"codex"}, "1571525adc95a24e": {"kind":"literal","value":"never"}, "15d5dfdd822aa35e": {"kind":"object","properties":[{"name":"data","type":"54f9276a1617d7c1","optional":false},{"name":"ignorable","type":"dacf3d5f3e4ff619","optional":true},{"name":"seq","type":"0657d3ca5ac4e7bf","optional":false},{"name":"time","type":"0657d3ca5ac4e7bf","optional":false},{"name":"type","type":"e95f957154b2b1b5","optional":false}],"indices":[]}, + "1682631f010d5ea7": {"kind":"object","properties":[{"name":"data","type":"f7752f518bb2f916","optional":false},{"name":"ignorable","type":"dacf3d5f3e4ff619","optional":true},{"name":"seq","type":"0657d3ca5ac4e7bf","optional":false},{"name":"time","type":"0657d3ca5ac4e7bf","optional":false},{"name":"type","type":"829a2fb3be6efd4b","optional":false}],"indices":[]}, "16d0507cb94b4cfc": {"kind":"literal","value":"relay"}, "17aae616ef020b8b": {"kind":"literal","value":"at"}, "17d1afb770d99419": {"kind":"object","properties":[{"name":"inherited","type":"dacf3d5f3e4ff619","optional":true}],"indices":[]}, @@ -807,6 +814,7 @@ "287211846beea1ec": {"kind":"object","properties":[{"name":"kind","type":"6c1cccb433ddc153","optional":false}],"indices":[]}, "28936c614bd4e7e2": {"kind":"object","properties":[{"name":"form","type":"6f9e00383836275e","optional":false},{"name":"kind","type":"d9edf1862e4471d6","optional":false},{"name":"sections","type":"c748fb42c80a1200","optional":false}],"indices":[]}, "290f32bfd81ff85a": {"kind":"object","properties":[{"name":"kind","type":"23af3759678a30de","optional":false}],"indices":[]}, + "295809283ede248d": {"kind":"object","properties":[{"name":"headerSeq","type":"0657d3ca5ac4e7bf","optional":true},{"name":"message","type":"824b1d4d4f007bda","optional":false},{"name":"step","type":"0657d3ca5ac4e7bf","optional":false},{"name":"turn","type":"0657d3ca5ac4e7bf","optional":false}],"indices":[]}, "297fbd8067d7815a": {"kind":"object","properties":[{"name":"form","type":"aec150797b655c5f","optional":false},{"name":"kind","type":"a9059a81430b3207","optional":false}],"indices":[]}, "2aad1179f9576314": {"kind":"object","properties":[{"name":"form","type":"6f9e00383836275e","optional":false},{"name":"kind","type":"24b10f7cdae64928","optional":false},{"name":"sections","type":"c748fb42c80a1200","optional":false}],"indices":[]}, "2ab12a0e345658f9": {"kind":"array","element":"83da72c6857601c7"}, @@ -847,6 +855,7 @@ "3b1be838223869fe": {"kind":"object","properties":[{"name":"data","type":"e4c18e294232c3ba","optional":false},{"name":"ignorable","type":"dacf3d5f3e4ff619","optional":true},{"name":"seq","type":"0657d3ca5ac4e7bf","optional":false},{"name":"time","type":"0657d3ca5ac4e7bf","optional":false},{"name":"type","type":"c589e938cc0e4989","optional":false}],"indices":[]}, "3b4f2c9ef2c1217e": {"kind":"object","properties":[{"name":"form","type":"383cf73ae4748e5b","optional":false},{"name":"kind","type":"bb94f3217aa56c88","optional":false}],"indices":[]}, "3bc287e765d58dc3": {"kind":"literal","value":"normal"}, + "3bca25b2baa6b22b": {"kind":"object","properties":[{"name":"data","type":"bec5ca3a376f56f3","optional":false},{"name":"ignorable","type":"dacf3d5f3e4ff619","optional":true},{"name":"seq","type":"0657d3ca5ac4e7bf","optional":false},{"name":"time","type":"0657d3ca5ac4e7bf","optional":false},{"name":"type","type":"587bb11da730e06a","optional":false}],"indices":[]}, "3bd652ebfa8726b3": {"kind":"union","types":["0657d3ca5ac4e7bf","938f7c7357bc403e"]}, "3bdb8dc6989655b0": {"kind":"object","properties":[{"name":"form","type":"6f9e00383836275e","optional":false},{"name":"kind","type":"a9059a81430b3207","optional":false},{"name":"sections","type":"c748fb42c80a1200","optional":false}],"indices":[]}, "3bec87f9e6ab3da0": {"kind":"object","properties":[{"name":"blockType","type":"7d65acf0a3a43a8f","optional":false},{"name":"index","type":"0657d3ca5ac4e7bf","optional":false},{"name":"type","type":"cbca49bde16b656d","optional":false}],"indices":[]}, @@ -860,9 +869,11 @@ "3ee93b06f3a12585": {"kind":"object","properties":[{"name":"data","type":"7c6129b6961cf4b2","optional":false},{"name":"ignorable","type":"dacf3d5f3e4ff619","optional":true},{"name":"seq","type":"0657d3ca5ac4e7bf","optional":false},{"name":"time","type":"0657d3ca5ac4e7bf","optional":false},{"name":"type","type":"44818000e56acb97","optional":false}],"indices":[]}, "3f74ba74acd10644": {"kind":"literal","value":"image/jpeg"}, "3fdf9582c3b5597d": {"kind":"object","properties":[{"name":"afterSeconds","type":"0657d3ca5ac4e7bf","optional":false},{"name":"id","type":"4cd48f3e5108bd6e","optional":false},{"name":"kind","type":"5b232a9b9bfcc0fc","optional":false},{"name":"prompt","type":"4cd48f3e5108bd6e","optional":false},{"name":"scheduledAt","type":"4cd48f3e5108bd6e","optional":false},{"name":"title","type":"4cd48f3e5108bd6e","optional":true}],"indices":[]}, + "4018a00144474b6c": {"kind":"object","properties":[{"name":"blockedBy","type":"93c33d9687613293","optional":false},{"name":"description","type":"4cd48f3e5108bd6e","optional":false},{"name":"id","type":"4cd48f3e5108bd6e","optional":false},{"name":"ownerId","type":"4cd48f3e5108bd6e","optional":true},{"name":"ownerName","type":"4cd48f3e5108bd6e","optional":true},{"name":"revision","type":"0657d3ca5ac4e7bf","optional":false},{"name":"status","type":"b2d2a01e51341a3b","optional":false},{"name":"subject","type":"4cd48f3e5108bd6e","optional":false},{"name":"writeScopes","type":"93c33d9687613293","optional":false}],"indices":[]}, "408927267422a7b2": {"kind":"object","properties":[{"name":"form","type":"fee1caf8ab6a65c1","optional":false},{"name":"kind","type":"0fe52387f6505270","optional":false}],"indices":[]}, "4208123b50df5006": {"kind":"object","properties":[{"name":"data","type":"ad0c38a0adb82a94","optional":false},{"name":"ignorable","type":"dacf3d5f3e4ff619","optional":true},{"name":"seq","type":"0657d3ca5ac4e7bf","optional":false},{"name":"time","type":"0657d3ca5ac4e7bf","optional":false},{"name":"type","type":"3e0eff5946255ff0","optional":false}],"indices":[]}, "42e0916e0dda5f6d": {"kind":"object","properties":[{"name":"data","type":"7f9365bae9fcb73e","optional":false},{"name":"ignorable","type":"dacf3d5f3e4ff619","optional":true},{"name":"seq","type":"0657d3ca5ac4e7bf","optional":false},{"name":"time","type":"0657d3ca5ac4e7bf","optional":false},{"name":"type","type":"fe792a6cd4304945","optional":false}],"indices":[]}, + "42e2ff61928fb7df": {"kind":"array","element":"c51f0d0a405bb96f"}, "4312134fc6f9cad5": {"kind":"literal","value":"turn/end"}, "43e311235aa537df": {"kind":"object","properties":[{"name":"toolName","type":"4cd48f3e5108bd6e","optional":false},{"name":"type","type":"83d6916021eede8f","optional":false}],"indices":[]}, "44818000e56acb97": {"kind":"literal","value":"feedback/message-delete"}, @@ -895,16 +906,16 @@ "4f507598cf476214": {"kind":"literal","value":"series"}, "4f91f187baeabef5": {"kind":"object","properties":[{"name":"capturedFormatVersion","type":"0657d3ca5ac4e7bf","optional":true},{"name":"capturedThroughSeq","type":"3bd652ebfa8726b3","optional":false},{"name":"compacted","type":"aa93010d0e521ad7","optional":false},{"name":"inputIndex","type":"0657d3ca5ac4e7bf","optional":false},{"name":"label","type":"4cd48f3e5108bd6e","optional":false},{"name":"omittedBytes","type":"0657d3ca5ac4e7bf","optional":false},{"name":"omittedMessages","type":"0657d3ca5ac4e7bf","optional":false},{"name":"originalMessages","type":"0657d3ca5ac4e7bf","optional":false},{"name":"retainedMessages","type":"0657d3ca5ac4e7bf","optional":false},{"name":"sessionId","type":"4cd48f3e5108bd6e","optional":false},{"name":"truncated","type":"aa93010d0e521ad7","optional":false}],"indices":[]}, "4fb59762612c3e3a": {"kind":"object","properties":[{"name":"data","type":"b1ebd5cda47d90d9","optional":false},{"name":"ignorable","type":"dacf3d5f3e4ff619","optional":true},{"name":"seq","type":"0657d3ca5ac4e7bf","optional":false},{"name":"time","type":"0657d3ca5ac4e7bf","optional":false},{"name":"type","type":"18fcdd273a2f2f9d","optional":false}],"indices":[]}, + "50a15408d511e9be": {"kind":"object","properties":[{"name":"data","type":"74e0e5885d2ddf04","optional":false},{"name":"ignorable","type":"dacf3d5f3e4ff619","optional":true},{"name":"seq","type":"0657d3ca5ac4e7bf","optional":false},{"name":"sourceEventSeqs","type":"5d03ba38734809bc","optional":true},{"name":"surfaceOp","type":"335e242de1fcc17b","optional":false},{"name":"time","type":"0657d3ca5ac4e7bf","optional":false},{"name":"type","type":"de25352d2dc41963","optional":false}],"indices":[]}, "50cf02d875f8a1f1": {"kind":"union","types":["2da725e554cd8930","dd2780e7e0768433"]}, + "510826cf4e1f9220": {"kind":"object","properties":[{"name":"data","type":"295809283ede248d","optional":false},{"name":"ignorable","type":"dacf3d5f3e4ff619","optional":true},{"name":"seq","type":"0657d3ca5ac4e7bf","optional":false},{"name":"sourceEventSeqs","type":"5d03ba38734809bc","optional":true},{"name":"surfaceOp","type":"335e242de1fcc17b","optional":false},{"name":"time","type":"0657d3ca5ac4e7bf","optional":false},{"name":"type","type":"1379f0b72275994d","optional":false}],"indices":[]}, "511801b0a6470d98": {"kind":"literal","value":"success"}, "516da4cdd6d2f1e5": {"kind":"object","properties":[{"name":"data","type":"9890113e97dd3541","optional":false},{"name":"ignorable","type":"dacf3d5f3e4ff619","optional":true},{"name":"seq","type":"0657d3ca5ac4e7bf","optional":false},{"name":"time","type":"0657d3ca5ac4e7bf","optional":false},{"name":"type","type":"ca085dba2c877fec","optional":false}],"indices":[]}, - "51edec100659da3a": {"kind":"object","properties":[{"name":"blockedBy","type":"93c33d9687613293","optional":false},{"name":"description","type":"4cd48f3e5108bd6e","optional":false},{"name":"id","type":"4cd48f3e5108bd6e","optional":false},{"name":"ownerId","type":"4cd48f3e5108bd6e","optional":true},{"name":"revision","type":"0657d3ca5ac4e7bf","optional":false},{"name":"status","type":"b2d2a01e51341a3b","optional":false},{"name":"subject","type":"4cd48f3e5108bd6e","optional":false},{"name":"writeScopes","type":"93c33d9687613293","optional":false}],"indices":[]}, "525254db03b1d1e6": {"kind":"object","properties":[{"name":"data","type":"c170da8ab7c37635","optional":false},{"name":"ignorable","type":"dacf3d5f3e4ff619","optional":true},{"name":"seq","type":"0657d3ca5ac4e7bf","optional":false},{"name":"time","type":"0657d3ca5ac4e7bf","optional":false},{"name":"type","type":"611cae9a3539733a","optional":false}],"indices":[]}, "529e0ccd0e34079a": {"kind":"object","properties":[],"indices":[{"key":"4cd48f3e5108bd6e","value":"c592ce75aab73fca"}]}, "52c6113cb0e53f34": {"kind":"object","properties":[{"name":"form","type":"6f9e00383836275e","optional":false},{"name":"kind","type":"9ac52f0f84fec2eb","optional":false},{"name":"sections","type":"c748fb42c80a1200","optional":false}],"indices":[]}, "5302e76315127761": {"kind":"object","properties":[{"name":"error","type":"a81059ca06999da1","optional":true},{"name":"message","type":"4b259f7f8f0a44ad","optional":false},{"name":"meta","type":"c592ce75aab73fca","optional":true},{"name":"step","type":"0657d3ca5ac4e7bf","optional":false},{"name":"turn","type":"0657d3ca5ac4e7bf","optional":false}],"indices":[]}, "530da6c0267813bb": {"kind":"union","types":["34d1ab5c5df37818","4f507598cf476214","e7ce49f12953583f","f789af5ab844827e"]}, - "53750b9abf61efb7": {"kind":"object","properties":[{"name":"data","type":"f731ffe80810b028","optional":false},{"name":"ignorable","type":"dacf3d5f3e4ff619","optional":true},{"name":"seq","type":"0657d3ca5ac4e7bf","optional":false},{"name":"time","type":"0657d3ca5ac4e7bf","optional":false},{"name":"type","type":"44c8c77aa9aa100b","optional":false}],"indices":[]}, "53cf1704ae0709c7": {"kind":"object","properties":[{"name":"form","type":"fee1caf8ab6a65c1","optional":false},{"name":"kind","type":"99e7e7d7fed55ae6","optional":false}],"indices":[]}, "54f9276a1617d7c1": {"kind":"object","properties":[{"name":"step","type":"0657d3ca5ac4e7bf","optional":false},{"name":"stream","type":"84bbfdce7d2eab5b","optional":false},{"name":"turn","type":"0657d3ca5ac4e7bf","optional":false}],"indices":[]}, "557e148d30b79ee4": {"kind":"literal","value":"agent-preset/selected"}, @@ -938,17 +949,15 @@ "5f2117d1856a5ab4": {"kind":"object","properties":[{"name":"code","type":"4cd48f3e5108bd6e","optional":false},{"name":"message","type":"4cd48f3e5108bd6e","optional":false},{"name":"offloadImages","type":"0657d3ca5ac4e7bf","optional":true},{"name":"providerRetryAfterMs","type":"0657d3ca5ac4e7bf","optional":true},{"name":"requestId","type":"4cd48f3e5108bd6e","optional":true},{"name":"status","type":"0657d3ca5ac4e7bf","optional":true}],"indices":[]}, "5f26a6c20b37632f": {"kind":"object","properties":[{"name":"data","type":"9a410ddf56792b2b","optional":false},{"name":"ignorable","type":"dacf3d5f3e4ff619","optional":true},{"name":"seq","type":"0657d3ca5ac4e7bf","optional":false},{"name":"time","type":"0657d3ca5ac4e7bf","optional":false},{"name":"type","type":"ad92f473a03ae725","optional":false}],"indices":[]}, "5f758f3de5f00c18": {"kind":"object","properties":[{"name":"label","type":"4cd48f3e5108bd6e","optional":true},{"name":"mode","type":"d28765f87d6b6ab4","optional":false},{"name":"provider","type":"4cd48f3e5108bd6e","optional":false},{"name":"version","type":"0657d3ca5ac4e7bf","optional":false}],"indices":[]}, - "601327bedca5f98a": {"kind":"object","properties":[{"name":"maxTokens","type":"0657d3ca5ac4e7bf","optional":false},{"name":"messageSeqs","type":"5d03ba38734809bc","optional":false},{"name":"messages","type":"95b5cf90ea1f57da","optional":false},{"name":"reasoningEffort","type":"4cd48f3e5108bd6e","optional":true},{"name":"route","type":"07e1a58c58b593f5","optional":false},{"name":"system","type":"4cd48f3e5108bd6e","optional":false},{"name":"titleProvider","type":"4cd48f3e5108bd6e","optional":false}],"indices":[]}, "6085488d223aeffd": {"kind":"object","properties":[{"name":"form","type":"fee1caf8ab6a65c1","optional":false},{"name":"kind","type":"2f3f201c8846e19c","optional":false}],"indices":[]}, "611cae9a3539733a": {"kind":"literal","value":"llm/retry"}, "611d82d2dc50df70": {"kind":"object","properties":[{"name":"cause","type":"750a2b129d67704d","optional":false},{"name":"detail","type":"4cd48f3e5108bd6e","optional":true},{"name":"finishedAt","type":"0657d3ca5ac4e7bf","optional":false},{"name":"jobId","type":"4cd48f3e5108bd6e","optional":false},{"name":"kind","type":"4cd48f3e5108bd6e","optional":false},{"name":"label","type":"4cd48f3e5108bd6e","optional":false},{"name":"owner","type":"4cd48f3e5108bd6e","optional":false},{"name":"producerReported","type":"aa93010d0e521ad7","optional":false},{"name":"startedAt","type":"0657d3ca5ac4e7bf","optional":false},{"name":"status","type":"c2f49004d9ae38a9","optional":false},{"name":"toolCall","type":"39cf2d3ff8bac81c","optional":true}],"indices":[]}, - "613660455704fb82": {"kind":"object","properties":[{"name":"content","type":"b52f215a6cd69105","optional":false},{"name":"id","type":"4cd48f3e5108bd6e","optional":false},{"name":"role","type":"68f44f59e91c4139","optional":false},{"name":"source","type":"b120362fd216a16a","optional":false,"compatibility":{"version":1,"policy":"session-source-attribution","binding":"session.user-message.source","discriminator":"kind","unknownKinds":"preserve","attributionKinds":["action-cards","tmux-context","user-question-reply","working-directory"]}}],"indices":[]}, "616f93a5047de668": {"kind":"literal","value":"tool-call-chunks"}, "6292bcbedaa97fea": {"kind":"object","properties":[{"name":"kind","type":"f68c335306535a00","optional":false}],"indices":[]}, "62e6a429ff3f390a": {"kind":"union","types":["1d8798b1a5e8c545","1e346446e183ee76","34d1ab5c5df37818","7624ca28c61ca0ea","ad22a5ca5bbaab2e","d9196086e41e4dd5"]}, "62ecb62dc0fe1b5e": {"kind":"literal","value":"next-turn"}, + "63ba8895cc09e469": {"kind":"literal","value":"retry"}, "6487b10ba7542f3c": {"kind":"object","properties":[{"name":"agentModel","type":"4cd48f3e5108bd6e","optional":true},{"name":"agentProvider","type":"4cd48f3e5108bd6e","optional":true},{"name":"agentReasoningEffort","type":"4cd48f3e5108bd6e","optional":true},{"name":"label","type":"4cd48f3e5108bd6e","optional":false},{"name":"mode","type":"e5d3828df1ec3e2a","optional":false},{"name":"persona","type":"4cd48f3e5108bd6e","optional":true},{"name":"provider","type":"4cd48f3e5108bd6e","optional":false},{"name":"toolFilter","type":"3cfc3a56502da1f8","optional":true},{"name":"version","type":"0657d3ca5ac4e7bf","optional":false}],"indices":[]}, - "65377a76c6a58f78": {"kind":"object","properties":[{"name":"headerSeq","type":"0657d3ca5ac4e7bf","optional":true},{"name":"message","type":"01c161379a3c3394","optional":false},{"name":"step","type":"0657d3ca5ac4e7bf","optional":false},{"name":"turn","type":"0657d3ca5ac4e7bf","optional":false}],"indices":[]}, "6598cd6da253948d": {"kind":"object","properties":[{"name":"context","type":"50cf02d875f8a1f1","optional":false},{"name":"description","type":"4cd48f3e5108bd6e","optional":false},{"name":"error","type":"4cd48f3e5108bd6e","optional":true},{"name":"id","type":"4cd48f3e5108bd6e","optional":false},{"name":"name","type":"4cd48f3e5108bd6e","optional":false},{"name":"phase","type":"dfce5db4aa42b7eb","optional":false},{"name":"provider","type":"4cd48f3e5108bd6e","optional":false}],"indices":[]}, "65a8400e451e667e": {"kind":"object","properties":[{"name":"kind","type":"09655b34d7f3cf1e","optional":false}],"indices":[]}, "65d583e66518c523": {"kind":"object","properties":[{"name":"entries","type":"aba175fb20ffc711","optional":false},{"name":"form","type":"aec150797b655c5f","optional":false},{"name":"incomplete","type":"dacf3d5f3e4ff619","optional":true},{"name":"kind","type":"6ebcc2dbec9f2dab","optional":false},{"name":"update","type":"dacf3d5f3e4ff619","optional":true}],"indices":[]}, @@ -958,7 +967,6 @@ "68141cbe3994a5ff": {"kind":"literal","value":"max-tokens"}, "688e853dc149f0d3": {"kind":"literal","value":"reasoning-chunks"}, "68f44f59e91c4139": {"kind":"literal","value":"user"}, - "690583582246babf": {"kind":"array","element":"613660455704fb82"}, "69081694be231d56": {"kind":"object","properties":[{"name":"data","type":"6bc8e51124d0874b","optional":false},{"name":"ignorable","type":"dacf3d5f3e4ff619","optional":true},{"name":"seq","type":"0657d3ca5ac4e7bf","optional":false},{"name":"sourceEventSeqs","type":"5d03ba38734809bc","optional":true},{"name":"surfaceOp","type":"335e242de1fcc17b","optional":false},{"name":"time","type":"0657d3ca5ac4e7bf","optional":false},{"name":"type","type":"1c5a58f4599bd4a9","optional":false}],"indices":[]}, "693f4952fb5565da": {"kind":"object","properties":[{"name":"failure","type":"5f2117d1856a5ab4","optional":false},{"name":"kind","type":"a2be0f0cb59f0d4a","optional":false}],"indices":[]}, "69d238a6e9b08d67": {"kind":"literal","value":"interrupted"}, @@ -983,12 +991,12 @@ "6f72ece8f317cd08": {"kind":"object","properties":[{"name":"retry","type":"0657d3ca5ac4e7bf","optional":false},{"name":"retryId","type":"4cd48f3e5108bd6e","optional":false},{"name":"step","type":"0657d3ca5ac4e7bf","optional":false},{"name":"turn","type":"0657d3ca5ac4e7bf","optional":false}],"indices":[]}, "6f9e00383836275e": {"kind":"literal","value":"snapshot"}, "70b082fe78991edf": {"kind":"literal","value":"request/context"}, - "70ea8e7943c5e2d7": {"kind":"object","properties":[{"name":"data","type":"65377a76c6a58f78","optional":false},{"name":"ignorable","type":"dacf3d5f3e4ff619","optional":true},{"name":"seq","type":"0657d3ca5ac4e7bf","optional":false},{"name":"sourceEventSeqs","type":"5d03ba38734809bc","optional":true},{"name":"surfaceOp","type":"335e242de1fcc17b","optional":false},{"name":"time","type":"0657d3ca5ac4e7bf","optional":false},{"name":"type","type":"1379f0b72275994d","optional":false}],"indices":[]}, "7180844e1066230c": {"kind":"literal","value":"service-stability"}, "719c51f67074f970": {"kind":"object","properties":[{"name":"kind","type":"2765e9119edf5816","optional":false},{"name":"model","type":"4cd48f3e5108bd6e","optional":false},{"name":"provider","type":"4cd48f3e5108bd6e","optional":false},{"name":"replayState","type":"bbc5696e3f13c758","optional":true}],"indices":[]}, "71bb3254ec8f1e49": {"kind":"object","properties":[{"name":"dt","type":"5d03ba38734809bc","optional":false},{"name":"index","type":"0657d3ca5ac4e7bf","optional":false},{"name":"texts","type":"93c33d9687613293","optional":false},{"name":"time0","type":"0657d3ca5ac4e7bf","optional":false},{"name":"type","type":"688e853dc149f0d3","optional":false}],"indices":[]}, "72ec79127a9c0d02": {"kind":"array","element":"c592ce75aab73fca"}, "7382c4fc95fe8c5d": {"kind":"literal","value":"remove"}, + "74e0e5885d2ddf04": {"kind":"object","properties":[{"name":"content","type":"b52f215a6cd69105","optional":false},{"name":"id","type":"4cd48f3e5108bd6e","optional":false},{"name":"role","type":"68f44f59e91c4139","optional":false},{"name":"source","type":"dca3ba43188095fa","optional":false,"compatibility":{"version":1,"policy":"session-source-attribution","binding":"session.user-message.source","discriminator":"kind","unknownKinds":"preserve","attributionKinds":["action-cards","tmux-context","user-question-reply","working-directory"]}}],"indices":[]}, "750a2b129d67704d": {"kind":"union","types":["5cb63db9fe57dc09","6cf082d0fb6034de","bab6865794007548"]}, "7554565be416b034": {"kind":"object","properties":[{"name":"form","type":"383cf73ae4748e5b","optional":false},{"name":"kind","type":"2f3f201c8846e19c","optional":false}],"indices":[]}, "756b5e23a5cb2c7f": {"kind":"object","properties":[{"name":"form","type":"383cf73ae4748e5b","optional":false},{"name":"kind","type":"8067b0d232c350f1","optional":false}],"indices":[]}, @@ -1019,6 +1027,7 @@ "814d9434e1ddf907": {"kind":"object","properties":[{"name":"text","type":"4cd48f3e5108bd6e","optional":false},{"name":"type","type":"3c2535ca0a2062f1","optional":false}],"indices":[]}, "82470020b5bfcb1a": {"kind":"literal","value":"agent-message"}, "824a4aad44a54e24": {"kind":"union","types":["4d60dddaa65d3da8","deebfc7c62177ea8"]}, + "824b1d4d4f007bda": {"kind":"object","properties":[{"name":"content","type":"b52f215a6cd69105","optional":false},{"name":"id","type":"4cd48f3e5108bd6e","optional":false},{"name":"role","type":"589d0d91239681f8","optional":false},{"name":"source","type":"dca3ba43188095fa","optional":false,"compatibility":{"version":1,"policy":"session-source-attribution","binding":"session.developer-message.source","discriminator":"kind","unknownKinds":"preserve","attributionKinds":["action-cards","tmux-context","user-question-reply","working-directory"]}}],"indices":[]}, "825ca23416b1ea9d": {"kind":"object","properties":[{"name":"form","type":"aec150797b655c5f","optional":false},{"name":"kind","type":"f68c335306535a00","optional":false}],"indices":[]}, "829a2fb3be6efd4b": {"kind":"literal","value":"agent/inbox/spliced"}, "83079c8a3f733ac3": {"kind":"object","properties":[{"name":"description","type":"4cd48f3e5108bd6e","optional":false},{"name":"name","type":"4cd48f3e5108bd6e","optional":false}],"indices":[]}, @@ -1042,6 +1051,7 @@ "88841202942c7683": {"kind":"object","properties":[{"name":"form","type":"6f9e00383836275e","optional":false},{"name":"kind","type":"bb94f3217aa56c88","optional":false},{"name":"sections","type":"c748fb42c80a1200","optional":false}],"indices":[]}, "88a610b831be6d92": {"kind":"object","properties":[{"name":"argumentsDelta","type":"4cd48f3e5108bd6e","optional":false},{"name":"id","type":"4cd48f3e5108bd6e","optional":false},{"name":"index","type":"0657d3ca5ac4e7bf","optional":false},{"name":"name","type":"4cd48f3e5108bd6e","optional":true},{"name":"type","type":"9b4fd974c124c837","optional":false}],"indices":[]}, "8a046b52331959aa": {"kind":"object","properties":[{"name":"kind","type":"78a9be340090b735","optional":false}],"indices":[]}, + "8a54d228b1b7d845": {"kind":"array","element":"74e0e5885d2ddf04"}, "8a6e1ec9e8db346b": {"kind":"object","properties":[{"name":"data","type":"119abe2b9c0b2f46","optional":false},{"name":"ignorable","type":"dacf3d5f3e4ff619","optional":true},{"name":"seq","type":"0657d3ca5ac4e7bf","optional":false},{"name":"time","type":"0657d3ca5ac4e7bf","optional":false},{"name":"type","type":"b9305f0ea75ccd6a","optional":false}],"indices":[]}, "8a9c990773f798ea": {"kind":"object","properties":[{"name":"preset","type":"4cd48f3e5108bd6e","optional":false}],"indices":[]}, "8ad45ad053b4d89f": {"kind":"object","properties":[{"name":"decision","type":"4cd48f3e5108bd6e","optional":false},{"name":"durationMs","type":"0657d3ca5ac4e7bf","optional":false},{"name":"exitCode","type":"0657d3ca5ac4e7bf","optional":true},{"name":"handlerId","type":"4cd48f3e5108bd6e","optional":false},{"name":"point","type":"4cd48f3e5108bd6e","optional":false},{"name":"stderrSummary","type":"4cd48f3e5108bd6e","optional":true},{"name":"turn","type":"0657d3ca5ac4e7bf","optional":false}],"indices":[]}, @@ -1054,8 +1064,10 @@ "8e611bf46821e500": {"kind":"object","properties":[{"name":"tool","type":"fcf427290c6213c2","optional":true},{"name":"toolName","type":"4cd48f3e5108bd6e","optional":false},{"name":"type","type":"85f9b505b7bdff1f","optional":false}],"indices":[]}, "8e8155594e078123": {"kind":"literal","value":"workspace/changes"}, "8e8e91646a5cae3f": {"kind":"object","properties":[{"name":"id","type":"4cd48f3e5108bd6e","optional":false},{"name":"operation","type":"26c879bdd130e8b8","optional":false},{"name":"version","type":"f88f1b7b6bb733f6","optional":false}],"indices":[]}, + "8f1062573ea91841": {"kind":"object","properties":[{"name":"clientTimeZone","type":"4cd48f3e5108bd6e","optional":true},{"name":"kind","type":"63ba8895cc09e469","optional":false},{"name":"principal","type":"824a4aad44a54e24","optional":true},{"name":"rpcId","type":"4cd48f3e5108bd6e","optional":false}],"indices":[]}, "8f324cea3916c051": {"kind":"object","properties":[{"name":"form","type":"16d0507cb94b4cfc","optional":false},{"name":"kind","type":"2f3f201c8846e19c","optional":false}],"indices":[]}, "8f6d609794bf5afc": {"kind":"tuple","elements":[{"type":"4e88776858652856","optional":false,"rest":false}]}, + "8faed5b52ab2d2df": {"kind":"object","properties":[{"name":"childCreatedAt","type":"0657d3ca5ac4e7bf","optional":false},{"name":"childId","type":"4cd48f3e5108bd6e","optional":false},{"name":"label","type":"4cd48f3e5108bd6e","optional":false},{"name":"mode","type":"e5d3828df1ec3e2a","optional":false},{"name":"name","type":"4cd48f3e5108bd6e","optional":false},{"name":"version","type":"137ac60e26bcb192","optional":false}],"indices":[]}, "8fcb0b44a575e998": {"kind":"object","properties":[{"name":"kind","type":"a720757f704a2512","optional":false}],"indices":[]}, "904bf499d98be4a3": {"kind":"union","types":["7382c4fc95fe8c5d","b765ee31033cea46","f6cb462f808309e3"]}, "920d87e22b7409bc": {"kind":"object","properties":[{"name":"data","type":"c2a13242efc3bea4","optional":false},{"name":"ignorable","type":"dacf3d5f3e4ff619","optional":true},{"name":"seq","type":"0657d3ca5ac4e7bf","optional":false},{"name":"time","type":"0657d3ca5ac4e7bf","optional":false},{"name":"type","type":"d8a476d2c6fd30df","optional":false}],"indices":[]}, @@ -1068,7 +1080,6 @@ "94c56aeb1564ad73": {"kind":"literal","value":"in_progress"}, "95080295115fbd83": {"kind":"object","properties":[{"name":"index","type":"0657d3ca5ac4e7bf","optional":false},{"name":"text","type":"4cd48f3e5108bd6e","optional":false},{"name":"type","type":"5abab3a27fd27366","optional":false}],"indices":[]}, "95a3ffccbf3c8afc": {"kind":"literal","value":"owner"}, - "95b5cf90ea1f57da": {"kind":"array","element":"e272493e3ea0b33b"}, "95c0e88fcf0bafb2": {"kind":"literal","value":"assistant"}, "9645cf93769a6dfb": {"kind":"literal","value":"user-question-reply"}, "96bfb916a727cd44": {"kind":"object","properties":[{"name":"form","type":"383cf73ae4748e5b","optional":false},{"name":"kind","type":"24b10f7cdae64928","optional":false}],"indices":[]}, @@ -1106,7 +1117,7 @@ "a3a259a1aa5401af": {"kind":"literal","value":"hook/result"}, "a3c6f1ea38e9a61d": {"kind":"object","properties":[{"name":"form","type":"e8de0f457fed5b9f","optional":false},{"name":"kind","type":"9ac52f0f84fec2eb","optional":false},{"name":"summary","type":"4cd48f3e5108bd6e","optional":false}],"indices":[]}, "a3edd1efd1fef21b": {"kind":"literal","value":"workspace-write"}, - "a40d12070f6f4a12": {"kind":"object","properties":[{"name":"task","type":"51edec100659da3a","optional":false},{"name":"teamId","type":"4cd48f3e5108bd6e","optional":false},{"name":"version","type":"a0f906856fc06f1c","optional":false}],"indices":[]}, + "a43327a1739c3fa4": {"kind":"object","properties":[{"name":"childCreatedAt","type":"0657d3ca5ac4e7bf","optional":false},{"name":"childId","type":"4cd48f3e5108bd6e","optional":false},{"name":"label","type":"4cd48f3e5108bd6e","optional":true},{"name":"mode","type":"fc351843b8ecbd05","optional":false},{"name":"name","type":"4cd48f3e5108bd6e","optional":false},{"name":"version","type":"137ac60e26bcb192","optional":false}],"indices":[]}, "a4afec59b75aad5d": {"kind":"object","properties":[{"name":"clientTimeZone","type":"4cd48f3e5108bd6e","optional":true},{"name":"kind","type":"68f44f59e91c4139","optional":false},{"name":"principal","type":"824a4aad44a54e24","optional":true},{"name":"rpcId","type":"4cd48f3e5108bd6e","optional":false}],"indices":[]}, "a6567ccb2e530606": {"kind":"object","properties":[{"name":"data","type":"0d47a8f3d847243c","optional":false},{"name":"ignorable","type":"dacf3d5f3e4ff619","optional":true},{"name":"seq","type":"0657d3ca5ac4e7bf","optional":false},{"name":"time","type":"0657d3ca5ac4e7bf","optional":false},{"name":"type","type":"0a8a062bc9c3c0d9","optional":false}],"indices":[]}, "a6b41f5bede8094d": {"kind":"union","types":["15495614ccfa9cbd","aff60ef947c18b01"]}, @@ -1118,6 +1129,7 @@ "a8a2b9011fc06786": {"kind":"literal","value":"team/message/delivered"}, "a9059a81430b3207": {"kind":"literal","value":"hooks-claude-code"}, "a926dc71814edd01": {"kind":"object","properties":[{"name":"everySeconds","type":"0657d3ca5ac4e7bf","optional":false},{"name":"id","type":"4cd48f3e5108bd6e","optional":false},{"name":"kind","type":"e42b0f40b5d0b628","optional":false},{"name":"prompt","type":"4cd48f3e5108bd6e","optional":false},{"name":"scheduledAt","type":"4cd48f3e5108bd6e","optional":false},{"name":"title","type":"4cd48f3e5108bd6e","optional":true}],"indices":[]}, + "a9427866376b691a": {"kind":"object","properties":[{"name":"task","type":"4018a00144474b6c","optional":false},{"name":"teamId","type":"4cd48f3e5108bd6e","optional":false},{"name":"version","type":"a0f906856fc06f1c","optional":false}],"indices":[]}, "a99ec0993c62c058": {"kind":"object","properties":[{"name":"compactionId","type":"4cd48f3e5108bd6e","optional":false},{"name":"llmStreamCall","type":"dacf3d5f3e4ff619","optional":false},{"name":"maxTokens","type":"0657d3ca5ac4e7bf","optional":true},{"name":"model","type":"4cd48f3e5108bd6e","optional":false},{"name":"provider","type":"4cd48f3e5108bd6e","optional":false},{"name":"rawOutput","type":"b52f215a6cd69105","optional":false},{"name":"shadowedRange","type":"9e41386b3a0c9572","optional":false},{"name":"shadowedSeqs","type":"5d03ba38734809bc","optional":false},{"name":"shadowedTokenCount","type":"0657d3ca5ac4e7bf","optional":false},{"name":"sourceCommandId","type":"4cd48f3e5108bd6e","optional":true},{"name":"summary","type":"b52f215a6cd69105","optional":false},{"name":"usage","type":"fec5442b9ee4122e","optional":true}],"indices":[]}, "a99f76fd149051c3": {"kind":"object","properties":[{"name":"content","type":"4cd48f3e5108bd6e","optional":false},{"name":"status","type":"fd0d91a1f9dd2efb","optional":false}],"indices":[]}, "aa0957eca50aeb28": {"kind":"object","properties":[{"name":"data","type":"f90eb4ab2d3897bc","optional":false},{"name":"ignorable","type":"dacf3d5f3e4ff619","optional":true},{"name":"seq","type":"0657d3ca5ac4e7bf","optional":false},{"name":"time","type":"0657d3ca5ac4e7bf","optional":false},{"name":"type","type":"0af3ecfb8c60d416","optional":false}],"indices":[]}, @@ -1143,7 +1155,6 @@ "b0127044ab31a702": {"kind":"object","properties":[{"name":"data","type":"ca59530d1a4f3e19","optional":false},{"name":"ignorable","type":"dacf3d5f3e4ff619","optional":true},{"name":"seq","type":"0657d3ca5ac4e7bf","optional":false},{"name":"time","type":"0657d3ca5ac4e7bf","optional":false},{"name":"type","type":"1986c2664009c991","optional":false}],"indices":[]}, "b062078e899958f9": {"kind":"object","properties":[{"name":"kind","type":"1f1385dbc3e875c0","optional":false}],"indices":[]}, "b0b0eb1b16490f6b": {"kind":"object","properties":[{"name":"attachmentId","type":"4cd48f3e5108bd6e","optional":false},{"name":"bytes","type":"0657d3ca5ac4e7bf","optional":false},{"name":"height","type":"0657d3ca5ac4e7bf","optional":false},{"name":"mediaType","type":"2f1e6a7ebace43d7","optional":false},{"name":"name","type":"4cd48f3e5108bd6e","optional":true},{"name":"originalDimensions","type":"0f46153645c29784","optional":true},{"name":"width","type":"0657d3ca5ac4e7bf","optional":false}],"indices":[]}, - "b120362fd216a16a": {"kind":"union","types":["0203243b72fc867a","022623b9ef98ec47","02b2c23f2d94b028","0ed8d1108fe7a5e1","0eeb17e1df89b1eb","11638dc58a31496f","1938c8c20f1cba7c","1e709346005826eb","1fdad624334d3548","2152caf1a71e588e","2235d957bf4b7c6c","224aa11d4d5f88c4","24ce31aa528272e5","260523b412c19ad8","28936c614bd4e7e2","290f32bfd81ff85a","297fbd8067d7815a","2aad1179f9576314","312aee2f0c42aabb","31907de956375182","3247e566f4340029","3b04790e08b35241","3b4f2c9ef2c1217e","3bdb8dc6989655b0","408927267422a7b2","45f005e6bbb76452","4991dfc415c9efeb","49dab019d00e8c26","4a9bef9f27a94252","52c6113cb0e53f34","53cf1704ae0709c7","5654685d7557ec74","58015da1c1950a66","5bb69b88517f6214","5bc66269cfaf614c","5cdbf342b7748d15","5d7a64ed6aac5551","6085488d223aeffd","6292bcbedaa97fea","65a8400e451e667e","65d583e66518c523","672c4aa2a9b736e3","6ccb6bc423fb3952","6ea608bdc8a7a63d","6f22a9d02b9a1f11","6f44f32be9bcd9a8","719c51f67074f970","7554565be416b034","756b5e23a5cb2c7f","7df62978a2b7de85","7eaef7a763ba5b94","7f959241c24128b4","80677c8c8b804189","825ca23416b1ea9d","8338ee303e2bd448","848639f8787f035b","854db3efdfb0cd39","85fe96bf15d5c755","8620189c8e335827","87b1a33564b9a4d6","88841202942c7683","8a046b52331959aa","8c1c4f72755a78ea","8c627d7a45fa406c","8f324cea3916c051","8fcb0b44a575e998","96bfb916a727cd44","99135d8a39379779","99f0e98184709ad1","9edc162949abf93b","9f65c43e340bba31","a15a19ef63cf5d1b","a16e567c8cd2c55c","a2066bd52f61218b","a3c6f1ea38e9a61d","a4afec59b75aad5d","aa2bf9e82b9fdeb9","aae343bc3d663c83","ada310bf0bdb8fed","ade057f4fdc387ae","b062078e899958f9","b2a5c8c008a31e3d","b3681c026a0b98e9","b4ec0af39fd52ed9","b613f83572fe2fbf","b6f94c17dd9bbd7c","b70f3e81fe11b7a5","b79641a9d25e7566","ba2a1a8f194b1bb2","ba4c40b4381e0dcd","baccc97ec34be6c4","c5228b7a55498d84","c55827fba7018198","cb1c8959e1726f82","cda2345a9be9d139","d85590a5675c6e2f","d9c462b9f62fdd3e","db06ef35b27a3842","dba54c09c6e7aafc","dd00cdccd0ba487b","dd5ee8762bd8a14b","dd6cc2bb2a8f2824","dde0cdf9d426768b","deaae5cd30987d4f","e7f4cbb3a57f4cbd","edbbfff1128099fd","ee577a0cc18664c9","f230c0b583e23b25","f29d63336e8266d8","f4a66f654996c093","f56c5b59ca016131","f6329fb30c7ea801","f6605d6c57933aea","f6afe41e3926f422","f7283223aacdc39b","f97f47b0eb87905e","fcf81d3c58c13593","fe1a7acdeed4d0f5"]}, "b158f3ff69237148": {"kind":"object","properties":[{"name":"contextWindow","type":"0657d3ca5ac4e7bf","optional":true},{"name":"model","type":"4cd48f3e5108bd6e","optional":false},{"name":"provider","type":"4cd48f3e5108bd6e","optional":false},{"name":"systemPromptUpdate","type":"f311671e07bc7fa6","optional":true}],"indices":[]}, "b1664fa89f8eab49": {"kind":"array","element":"bbc5696e3f13c758"}, "b1ebd5cda47d90d9": {"kind":"object","properties":[{"name":"member","type":"6598cd6da253948d","optional":false},{"name":"teamId","type":"4cd48f3e5108bd6e","optional":false},{"name":"version","type":"a0f906856fc06f1c","optional":false}],"indices":[]}, @@ -1186,8 +1197,10 @@ "bb1ab3d08f49a9f3": {"kind":"object","properties":[{"name":"data","type":"93cbbc5a7fd0b1aa","optional":false},{"name":"ignorable","type":"dacf3d5f3e4ff619","optional":true},{"name":"seq","type":"0657d3ca5ac4e7bf","optional":false},{"name":"time","type":"0657d3ca5ac4e7bf","optional":false},{"name":"type","type":"378f90f9f6022a09","optional":false}],"indices":[]}, "bb94f3217aa56c88": {"kind":"literal","value":"hooks-codex"}, "bbc5696e3f13c758": {"kind":"opaque","reason":"unknown"}, + "bca0f9cb63d8620b": {"kind":"object","properties":[{"name":"data","type":"a9427866376b691a","optional":false},{"name":"ignorable","type":"dacf3d5f3e4ff619","optional":true},{"name":"seq","type":"0657d3ca5ac4e7bf","optional":false},{"name":"time","type":"0657d3ca5ac4e7bf","optional":false},{"name":"type","type":"b57ae1b37e52bee0","optional":false}],"indices":[]}, "bcf0caf62d964b2f": {"kind":"object","properties":[{"name":"endSeq","type":"0657d3ca5ac4e7bf","optional":false},{"name":"op","type":"f6cb462f808309e3","optional":false},{"name":"startSeq","type":"0657d3ca5ac4e7bf","optional":false}],"indices":[]}, "bd499eac047efe09": {"kind":"literal","value":"finish"}, + "bec5ca3a376f56f3": {"kind":"object","properties":[{"name":"maxTokens","type":"0657d3ca5ac4e7bf","optional":false},{"name":"messageSeqs","type":"5d03ba38734809bc","optional":false},{"name":"messages","type":"42e2ff61928fb7df","optional":false},{"name":"reasoningEffort","type":"4cd48f3e5108bd6e","optional":true},{"name":"route","type":"07e1a58c58b593f5","optional":false},{"name":"system","type":"4cd48f3e5108bd6e","optional":false},{"name":"titleProvider","type":"4cd48f3e5108bd6e","optional":false}],"indices":[]}, "bf16d2e98a7f1389": {"kind":"literal","value":"subagent-settled"}, "c0ea97bc89dfc46f": {"kind":"object","properties":[{"name":"outcome","type":"c2deb7c9183735d4","optional":false},{"name":"runId","type":"4cd48f3e5108bd6e","optional":false},{"name":"seq","type":"0657d3ca5ac4e7bf","optional":false}],"indices":[]}, "c170da8ab7c37635": {"kind":"union","types":["374fdd68aee5ff84","cdee10e87dbed844"]}, @@ -1198,6 +1211,7 @@ "c2deb7c9183735d4": {"kind":"union","types":["1ebc6f9ff3aa9e3a","2142e391b9ccb60d","b57a2889408de36e"]}, "c2f49004d9ae38a9": {"kind":"union","types":["1ebc6f9ff3aa9e3a","b57a2889408de36e","ef226a90ddac6cd8"]}, "c43b119ce579b3e9": {"kind":"literal","value":"paused"}, + "c51f0d0a405bb96f": {"kind":"union","types":["09f3f8dc417f2782","4b259f7f8f0a44ad","74e0e5885d2ddf04","824b1d4d4f007bda","fa87537f4a9c1e25"]}, "c5228b7a55498d84": {"kind":"object","properties":[{"name":"form","type":"6f9e00383836275e","optional":false},{"name":"kind","type":"99e7e7d7fed55ae6","optional":false},{"name":"sections","type":"c748fb42c80a1200","optional":false}],"indices":[]}, "c55827fba7018198": {"kind":"object","properties":[{"name":"callId","type":"4cd48f3e5108bd6e","optional":false},{"name":"kind","type":"9645cf93769a6dfb","optional":false},{"name":"outcome","type":"85d6d96ff8842974","optional":false}],"indices":[]}, "c5687b1313206a6f": {"kind":"literal","value":"cordis-host-runner"}, @@ -1219,17 +1233,16 @@ "cffcdc19881ab61e": {"kind":"object","properties":[{"name":"cleared","type":"0b6d718c693fdf7f","optional":false},{"name":"clearedAt","type":"0657d3ca5ac4e7bf","optional":false},{"name":"kind","type":"237c004c73b6b288","optional":false},{"name":"operation","type":"e7e154d47d5fbc53","optional":false},{"name":"version","type":"f88f1b7b6bb733f6","optional":false}],"indices":[]}, "d0fbb0ca1bbba059": {"kind":"literal","value":"delete"}, "d28765f87d6b6ab4": {"kind":"literal","value":"one-shot"}, + "d49164d37eab0f0f": {"kind":"object","properties":[{"name":"data","type":"058fc9a6b4fbd5d4","optional":false},{"name":"ignorable","type":"dacf3d5f3e4ff619","optional":true},{"name":"seq","type":"0657d3ca5ac4e7bf","optional":false},{"name":"time","type":"0657d3ca5ac4e7bf","optional":false},{"name":"type","type":"44c8c77aa9aa100b","optional":false}],"indices":[]}, "d4b739491689cc6b": {"kind":"object","properties":[{"name":"block","type":"8064c03c87c357fd","optional":false},{"name":"index","type":"0657d3ca5ac4e7bf","optional":false},{"name":"type","type":"eefbea819caeeea9","optional":false}],"indices":[]}, "d4c799e3d51cae10": {"kind":"literal","value":"working-directory/change"}, "d4e4d575abeb4b72": {"kind":"literal","value":"canceled"}, - "d595ec73b32b016a": {"kind":"object","properties":[{"name":"data","type":"a40d12070f6f4a12","optional":false},{"name":"ignorable","type":"dacf3d5f3e4ff619","optional":true},{"name":"seq","type":"0657d3ca5ac4e7bf","optional":false},{"name":"time","type":"0657d3ca5ac4e7bf","optional":false},{"name":"type","type":"b57ae1b37e52bee0","optional":false}],"indices":[]}, "d63b8b8ffad9c02f": {"kind":"object","properties":[{"name":"data","type":"8bb8c3751a6ce64b","optional":false},{"name":"ignorable","type":"dacf3d5f3e4ff619","optional":true},{"name":"seq","type":"0657d3ca5ac4e7bf","optional":false},{"name":"time","type":"0657d3ca5ac4e7bf","optional":false},{"name":"type","type":"47e5d84f1a93450a","optional":false}],"indices":[]}, "d66e11dddf5dfa3c": {"kind":"object","properties":[{"name":"data","type":"cef171adf021a186","optional":false},{"name":"ignorable","type":"dacf3d5f3e4ff619","optional":true},{"name":"seq","type":"0657d3ca5ac4e7bf","optional":false},{"name":"time","type":"0657d3ca5ac4e7bf","optional":false},{"name":"type","type":"fb5e0517050d2c6d","optional":false}],"indices":[]}, "d6e654b88b584fcd": {"kind":"literal","value":"fallback"}, "d85590a5675c6e2f": {"kind":"object","properties":[{"name":"form","type":"aec150797b655c5f","optional":false},{"name":"kind","type":"1f1385dbc3e875c0","optional":false}],"indices":[]}, "d8a476d2c6fd30df": {"kind":"literal","value":"team/mode"}, "d9196086e41e4dd5": {"kind":"literal","value":"complete"}, - "d95c624eddecdacf": {"kind":"object","properties":[{"name":"data","type":"601327bedca5f98a","optional":false},{"name":"ignorable","type":"dacf3d5f3e4ff619","optional":true},{"name":"seq","type":"0657d3ca5ac4e7bf","optional":false},{"name":"time","type":"0657d3ca5ac4e7bf","optional":false},{"name":"type","type":"587bb11da730e06a","optional":false}],"indices":[]}, "d9c462b9f62fdd3e": {"kind":"object","properties":[{"name":"callId","type":"4cd48f3e5108bd6e","optional":false},{"name":"kind","type":"a13d8f379222ece8","optional":false}],"indices":[]}, "d9edf1862e4471d6": {"kind":"literal","value":"schedule"}, "da60ed58a8fa23d7": {"kind":"object","properties":[{"name":"cwd","type":"4cd48f3e5108bd6e","optional":false}],"indices":[]}, @@ -1239,12 +1252,11 @@ "db874d463b0fdec7": {"kind":"object","properties":[{"name":"data","type":"3e4e7683b0192c9f","optional":false},{"name":"ignorable","type":"dacf3d5f3e4ff619","optional":true},{"name":"seq","type":"0657d3ca5ac4e7bf","optional":false},{"name":"time","type":"0657d3ca5ac4e7bf","optional":false},{"name":"type","type":"e2d0367e5716bc18","optional":false}],"indices":[]}, "dba54c09c6e7aafc": {"kind":"object","properties":[{"name":"kind","type":"4edec1b770e8ec4c","optional":false}],"indices":[]}, "dbdafceb9a900183": {"kind":"literal","value":"hook"}, - "dcb07e04496586d2": {"kind":"object","properties":[{"name":"data","type":"613660455704fb82","optional":false},{"name":"ignorable","type":"dacf3d5f3e4ff619","optional":true},{"name":"seq","type":"0657d3ca5ac4e7bf","optional":false},{"name":"sourceEventSeqs","type":"5d03ba38734809bc","optional":true},{"name":"surfaceOp","type":"335e242de1fcc17b","optional":false},{"name":"time","type":"0657d3ca5ac4e7bf","optional":false},{"name":"type","type":"de25352d2dc41963","optional":false}],"indices":[]}, + "dca3ba43188095fa": {"kind":"union","types":["0203243b72fc867a","022623b9ef98ec47","02b2c23f2d94b028","0ed8d1108fe7a5e1","0eeb17e1df89b1eb","11638dc58a31496f","1938c8c20f1cba7c","1e709346005826eb","1fdad624334d3548","2152caf1a71e588e","2235d957bf4b7c6c","224aa11d4d5f88c4","24ce31aa528272e5","260523b412c19ad8","28936c614bd4e7e2","290f32bfd81ff85a","297fbd8067d7815a","2aad1179f9576314","312aee2f0c42aabb","31907de956375182","3247e566f4340029","3b04790e08b35241","3b4f2c9ef2c1217e","3bdb8dc6989655b0","408927267422a7b2","45f005e6bbb76452","4991dfc415c9efeb","49dab019d00e8c26","4a9bef9f27a94252","52c6113cb0e53f34","53cf1704ae0709c7","5654685d7557ec74","58015da1c1950a66","5bb69b88517f6214","5bc66269cfaf614c","5cdbf342b7748d15","5d7a64ed6aac5551","6085488d223aeffd","6292bcbedaa97fea","65a8400e451e667e","65d583e66518c523","672c4aa2a9b736e3","6ccb6bc423fb3952","6ea608bdc8a7a63d","6f22a9d02b9a1f11","6f44f32be9bcd9a8","719c51f67074f970","7554565be416b034","756b5e23a5cb2c7f","7df62978a2b7de85","7eaef7a763ba5b94","7f959241c24128b4","80677c8c8b804189","825ca23416b1ea9d","8338ee303e2bd448","848639f8787f035b","854db3efdfb0cd39","85fe96bf15d5c755","8620189c8e335827","87b1a33564b9a4d6","88841202942c7683","8a046b52331959aa","8c1c4f72755a78ea","8c627d7a45fa406c","8f1062573ea91841","8f324cea3916c051","8fcb0b44a575e998","96bfb916a727cd44","99135d8a39379779","99f0e98184709ad1","9edc162949abf93b","9f65c43e340bba31","a15a19ef63cf5d1b","a16e567c8cd2c55c","a2066bd52f61218b","a3c6f1ea38e9a61d","a4afec59b75aad5d","aa2bf9e82b9fdeb9","aae343bc3d663c83","ada310bf0bdb8fed","ade057f4fdc387ae","b062078e899958f9","b2a5c8c008a31e3d","b3681c026a0b98e9","b4ec0af39fd52ed9","b613f83572fe2fbf","b6f94c17dd9bbd7c","b70f3e81fe11b7a5","b79641a9d25e7566","ba2a1a8f194b1bb2","ba4c40b4381e0dcd","baccc97ec34be6c4","c5228b7a55498d84","c55827fba7018198","cb1c8959e1726f82","cda2345a9be9d139","d85590a5675c6e2f","d9c462b9f62fdd3e","db06ef35b27a3842","dba54c09c6e7aafc","dd00cdccd0ba487b","dd5ee8762bd8a14b","dd6cc2bb2a8f2824","dde0cdf9d426768b","deaae5cd30987d4f","e7f4cbb3a57f4cbd","edbbfff1128099fd","ee577a0cc18664c9","f230c0b583e23b25","f29d63336e8266d8","f4a66f654996c093","f56c5b59ca016131","f6329fb30c7ea801","f6605d6c57933aea","f6afe41e3926f422","f7283223aacdc39b","f97f47b0eb87905e","fcf81d3c58c13593","fe1a7acdeed4d0f5"]}, "dd00cdccd0ba487b": {"kind":"object","properties":[{"name":"form","type":"aec150797b655c5f","optional":false},{"name":"kind","type":"05205074b24d8340","optional":false},{"name":"through","type":"0657d3ca5ac4e7bf","optional":false}],"indices":[]}, "dd2780e7e0768433": {"kind":"literal","value":"fresh"}, "dd5ee8762bd8a14b": {"kind":"object","properties":[{"name":"form","type":"aec150797b655c5f","optional":false},{"name":"kind","type":"99e7e7d7fed55ae6","optional":false}],"indices":[]}, "dd6cc2bb2a8f2824": {"kind":"object","properties":[{"name":"form","type":"383cf73ae4748e5b","optional":false},{"name":"kind","type":"99e7e7d7fed55ae6","optional":false}],"indices":[]}, - "ddce54a3873dc571": {"kind":"object","properties":[{"name":"data","type":"e1880c67e735e228","optional":false},{"name":"ignorable","type":"dacf3d5f3e4ff619","optional":true},{"name":"seq","type":"0657d3ca5ac4e7bf","optional":false},{"name":"time","type":"0657d3ca5ac4e7bf","optional":false},{"name":"type","type":"829a2fb3be6efd4b","optional":false}],"indices":[]}, "dde0cdf9d426768b": {"kind":"object","properties":[{"name":"kind","type":"05205074b24d8340","optional":false},{"name":"through","type":"0657d3ca5ac4e7bf","optional":false}],"indices":[]}, "de25352d2dc41963": {"kind":"literal","value":"user/message"}, "de30b1fa12c75f81": {"kind":"literal","value":"image/gif"}, @@ -1254,8 +1266,6 @@ "df843efd87c78cf8": {"kind":"array","element":"4f91f187baeabef5"}, "dfce5db4aa42b7eb": {"kind":"union","types":["871bfd6f7bb91061","b57a2889408de36e","c8e6f48878cc2a2f"]}, "e0a787e6ec76c7c9": {"kind":"object","properties":[{"name":"data","type":"ef11a3b7fa2033ae","optional":false},{"name":"ignorable","type":"dacf3d5f3e4ff619","optional":true},{"name":"seq","type":"0657d3ca5ac4e7bf","optional":false},{"name":"time","type":"0657d3ca5ac4e7bf","optional":false},{"name":"type","type":"c219efbdfd53b836","optional":false}],"indices":[]}, - "e1880c67e735e228": {"kind":"object","properties":[{"name":"inserted","type":"690583582246babf","optional":false},{"name":"outcome","type":"d4e4d575abeb4b72","optional":true},{"name":"removedCount","type":"0657d3ca5ac4e7bf","optional":true},{"name":"start","type":"0657d3ca5ac4e7bf","optional":false},{"name":"target","type":"96f4a9c81fc0f940","optional":false}],"indices":[]}, - "e272493e3ea0b33b": {"kind":"union","types":["01c161379a3c3394","09f3f8dc417f2782","4b259f7f8f0a44ad","613660455704fb82","fa87537f4a9c1e25"]}, "e2ad8f5bcd813f26": {"kind":"object","properties":[{"name":"childCreatedAt","type":"0657d3ca5ac4e7bf","optional":false},{"name":"childId","type":"4cd48f3e5108bd6e","optional":false},{"name":"label","type":"4cd48f3e5108bd6e","optional":false},{"name":"mode","type":"e5d3828df1ec3e2a","optional":false},{"name":"version","type":"f88f1b7b6bb733f6","optional":false}],"indices":[]}, "e2d0367e5716bc18": {"kind":"literal","value":"compaction/start"}, "e2f9a41e0989f54e": {"kind":"object","properties":[{"name":"data","type":"9947aa5938fe19a8","optional":false},{"name":"ignorable","type":"dacf3d5f3e4ff619","optional":true},{"name":"seq","type":"0657d3ca5ac4e7bf","optional":false},{"name":"time","type":"0657d3ca5ac4e7bf","optional":false},{"name":"type","type":"ef4f00923b9edbae","optional":false}],"indices":[]}, @@ -1313,7 +1323,7 @@ "f6afe41e3926f422": {"kind":"object","properties":[{"name":"form","type":"fee1caf8ab6a65c1","optional":false},{"name":"kind","type":"8067b0d232c350f1","optional":false}],"indices":[]}, "f6cb462f808309e3": {"kind":"literal","value":"replace"}, "f7283223aacdc39b": {"kind":"object","properties":[{"name":"kind","type":"9ac52f0f84fec2eb","optional":false}],"indices":[]}, - "f731ffe80810b028": {"kind":"union","types":["0e10d7c096b47e61","5d542ac7bdf13310","a0f25b5aeeebf2bf","b6896938660a1dfe","cbbe8377ee744964","e2ad8f5bcd813f26"]}, + "f7752f518bb2f916": {"kind":"object","properties":[{"name":"inserted","type":"8a54d228b1b7d845","optional":false},{"name":"outcome","type":"d4e4d575abeb4b72","optional":true},{"name":"removedCount","type":"0657d3ca5ac4e7bf","optional":true},{"name":"start","type":"0657d3ca5ac4e7bf","optional":false},{"name":"target","type":"96f4a9c81fc0f940","optional":false}],"indices":[]}, "f789af5ab844827e": {"kind":"literal","value":"change"}, "f88f1b7b6bb733f6": {"kind":"literal","value":1}, "f90eb4ab2d3897bc": {"kind":"object","properties":[{"name":"turn","type":"0657d3ca5ac4e7bf","optional":false}],"indices":[]}, diff --git a/docs/subsystems/agent-team.i18n.yaml b/docs/subsystems/agent-team.i18n.yaml index 435e1b6bbb..0426fb7a10 100644 --- a/docs/subsystems/agent-team.i18n.yaml +++ b/docs/subsystems/agent-team.i18n.yaml @@ -15,8 +15,8 @@ en: c70f0fd199fc7db5 zh: c6b77cb5a5cfd1c2 /agent-teams/web-projection: - en: 059d4e5d6a9ddc71 - zh: cb3fd92096144e19 + en: af4ffca1efab0f56 + zh: 1f53c9c258cc5a75 /agent-teams/replay: en: 448d32856f87b067 zh: 7fafd96314c7e2c5 diff --git a/docs/subsystems/agent-team.md b/docs/subsystems/agent-team.md index 49b27ea176..b89ce4204d 100644 --- a/docs/subsystems/agent-team.md +++ b/docs/subsystems/agent-team.md @@ -64,6 +64,8 @@ interface TeamTaskSnapshot { readonly description: string readonly status: TeamTaskStatus readonly ownerId?: SessionId + /** Immutable agent path captured at assignment; absent on unnamed historical owners. */ + readonly ownerName?: string readonly blockedBy: TeamTaskId[] readonly writeScopes: string[] } @@ -77,7 +79,7 @@ interface TeamTaskSnapshot { `agentTeam.enabled` exposes the root Session’s saved selection. New Sessions default to false; `team/mode` records explicit selections. Historical tasks imply enabled until an explicit selection. Only the root can call `setEnabled`; descendants share that mode. The Web menu calls the same method through `remote.agentTeams.setEnabled`, with the root Session id resolved to its live Agent by the Gateway. Mode writes take effect before awaiting persistence. Tools resolve availability at step preparation; prompt providers read the selection when evaluated. Task mutations check the current mode when their queued operation starts; admitted mutations may finish. Mode changes do not end inbox waits. A failed flush leaves the appended selection active; retrying the same selection flushes it without a duplicate event. -The root Session publishes non-deleted task views through `SessionProjectionMap.agentTeam`. `failure` reports a rejected persisted task or mode record beside the last valid state. Historical roster and mailbox records are not projected. The task panel identifies every owner by its Session id. +The root Session publishes non-deleted task views through `SessionProjectionMap.agentTeam`. `failure` reports a rejected persisted task or mode record beside the last valid state. Historical roster and mailbox records are not projected. Views identify every owner by its Session id; the task panel and task tools display the owner's agent name, or the Session id when the owner has no name. ```ts type-equiv /** Runtime-enriched task view returned to tools and hosts. */ @@ -90,6 +92,8 @@ interface TeamTaskView { readonly blockedBy: TeamTaskId[] readonly writeScopes: string[] readonly ownerId?: SessionId + /** Immutable agent path captured at assignment; absent on unnamed historical owners. */ + readonly ownerName?: string readonly ready: boolean readonly writeScopeWarnings: string[] } diff --git a/docs/subsystems/agent-team.zh.md b/docs/subsystems/agent-team.zh.md index fb52d49be4..2746c47697 100644 --- a/docs/subsystems/agent-team.zh.md +++ b/docs/subsystems/agent-team.zh.md @@ -64,6 +64,8 @@ interface TeamTaskSnapshot { readonly description: string readonly status: TeamTaskStatus readonly ownerId?: SessionId + /** Immutable agent path captured at assignment; absent on unnamed historical owners. */ + readonly ownerName?: string readonly blockedBy: TeamTaskId[] readonly writeScopes: string[] } @@ -77,7 +79,7 @@ interface TeamTaskSnapshot { `agentTeam.enabled` 提供根 Session 保存的选择。新 Session 默认为 false;`team/mode` 记录显式选择。历史任务在显式选择前视为开启。仅根可调用 `setEnabled`;后代共享该模式。Web 菜单通过 `remote.agentTeams.setEnabled` 调用同一方法,Gateway 将根 Session id 解析为其存活 Agent。模式写入先立即生效,再等待刷盘。工具在步骤准备时确定可用性;提示词提供方在求值时读取选择。任务修改在排队操作开始时检查当前模式;已获准的修改可继续完成。模式变更不会结束收件箱等待。刷盘失败时已追加的选择仍然生效;重试相同选择会再次刷盘,不重复追加事件。 -根 Session 通过 `SessionProjectionMap.agentTeam` 发布未删除任务视图。`failure` 在最后有效状态旁报告被拒绝的持久化任务或模式记录。历史名册与邮箱记录不参与投影。任务面板以 Session id 标识每个负责人。 +根 Session 通过 `SessionProjectionMap.agentTeam` 发布未删除任务视图。`failure` 在最后有效状态旁报告被拒绝的持久化任务或模式记录。历史名册与邮箱记录不参与投影。视图以 Session id 标识每个负责人;任务面板和任务工具显示负责人的 agent 名称,负责人没有名称时显示其 Session id。 ```ts type-equiv /** Runtime-enriched task view returned to tools and hosts. */ @@ -90,6 +92,8 @@ interface TeamTaskView { readonly blockedBy: TeamTaskId[] readonly writeScopes: string[] readonly ownerId?: SessionId + /** Immutable agent path captured at assignment; absent on unnamed historical owners. */ + readonly ownerName?: string readonly ready: boolean readonly writeScopeWarnings: string[] } diff --git a/docs/subsystems/session-projection.md b/docs/subsystems/session-projection.md index 512542d505..01dbdd99e2 100644 --- a/docs/subsystems/session-projection.md +++ b/docs/subsystems/session-projection.md @@ -96,10 +96,10 @@ interface ProjectionDefinition { summary?: boolean } : never /** - * Persisted-cache invalidation version: bump whenever the serialized state fields or the - * fold semantics change, so persisted `(sessionId, key, ver, seq, val)` - * rows from an older unit are discarded instead of being forward-applied - * into garbage. Non-negative integer. + * Non-negative persisted-cache invalidation version. Bump when state fields or fold + * semantics change, except for optional additions whose absence preserves historical + * meaning and whose old-checkpoint suffix replay matches full replay. Test that + * equivalence before retaining a version; schema acceptance alone is insufficient. */ stateVersion: number } diff --git a/docs/subsystems/session-projection.zh.md b/docs/subsystems/session-projection.zh.md index d6b38f28d3..675d49b575 100644 --- a/docs/subsystems/session-projection.zh.md +++ b/docs/subsystems/session-projection.zh.md @@ -96,10 +96,10 @@ interface ProjectionDefinition { summary?: boolean } : never /** - * Persisted-cache invalidation version: bump whenever the serialized state fields or the - * fold semantics change, so persisted `(sessionId, key, ver, seq, val)` - * rows from an older unit are discarded instead of being forward-applied - * into garbage. Non-negative integer. + * Non-negative persisted-cache invalidation version. Bump when state fields or fold + * semantics change, except for optional additions whose absence preserves historical + * meaning and whose old-checkpoint suffix replay matches full replay. Test that + * equivalence before retaining a version; schema acceptance alone is insufficient. */ stateVersion: number } diff --git a/docs/subsystems/subagent.i18n.yaml b/docs/subsystems/subagent.i18n.yaml index b2d7d88b37..8a6bd71c02 100644 --- a/docs/subsystems/subagent.i18n.yaml +++ b/docs/subsystems/subagent.i18n.yaml @@ -11,6 +11,9 @@ /subagents/local-children-and-activations: en: 6f87231d18d82916 zh: 9f064b23058f8766 +/subagents/agent-names: + en: 55b2912080a2b021 + zh: d234521ecce44275 /subagents/messages-and-interruption: en: 9befacb931520842 zh: c214b4fffa779b06 @@ -24,5 +27,5 @@ en: 226ba8094a8cf96c zh: 719678662905d1eb /subagents/durable-enumeration-listdescendants-and-catalog-entries: - en: 8000138f84fd15fa - zh: 32fa91d3aebd3d01 + en: 992acbcc3ac77e30 + zh: 83b9dd42ade734ab diff --git a/docs/subsystems/subagent.md b/docs/subsystems/subagent.md index 0e3235cf91..488ef66ac4 100644 --- a/docs/subsystems/subagent.md +++ b/docs/subsystems/subagent.md @@ -33,6 +33,12 @@ interface SubagentActivationSpec extends Omit */ rootOf(caller: Agent): Agent +/** + * Report the model-facing names of a live tree member and its direct creator. + * The root is `lead`; a descendant is the slash-separated path of names from + * the root, or its Session id when it or a creator below the root has no name. + * @param agent - exact live root or resident tree member. + * @returns the member's name and, for a descendant, its creator's name. + * @throws when the caller or its runtime owner is unavailable. + */ +namesOf(agent: Agent): SubagentMemberNames + +/** + * Resolve a model-supplied agent reference within the caller's tree. `lead` + * selects the root and a slash-separated path is looked up through the + * catalogs along it. Any other text that is not a name in the tree is + * returned as a Session id, because a single token can be one; a + * slash-separated address never is, so an unmatched path fails instead of + * reaching a member lookup as an unknown id. Resolution grants no authority: + * messaging, interruption, and assignment authorize the result. + * @param caller - exact live Agent whose tree root anchors the lookup. + * @param name - `lead`, a full name from the root, or a Session id. + * @param signal - cancellation forwarded to each catalog read. + * @returns the referenced Session id. + * @throws {@link SubagentError} `AGENT_NAME_NOT_FOUND` when a path names no member; + * when the caller's root is unavailable; or when a catalog along the path cannot be read. + */ +async resolveName(caller: Agent, name: string, signal: AbortSignal): Promise + /** * Join progressing subagent tree work for its root. Idle members with parked input * stay resident without delaying host completion. Ordinary members return false. diff --git a/docs/subsystems/subagent.zh.md b/docs/subsystems/subagent.zh.md index 785644d1cf..8f1d6b74a2 100644 --- a/docs/subsystems/subagent.zh.md +++ b/docs/subsystems/subagent.zh.md @@ -33,6 +33,12 @@ interface SubagentActivationSpec extends Omit */ rootOf(caller: Agent): Agent +/** + * Report the model-facing names of a live tree member and its direct creator. + * The root is `lead`; a descendant is the slash-separated path of names from + * the root, or its Session id when it or a creator below the root has no name. + * @param agent - exact live root or resident tree member. + * @returns the member's name and, for a descendant, its creator's name. + * @throws when the caller or its runtime owner is unavailable. + */ +namesOf(agent: Agent): SubagentMemberNames + +/** + * Resolve a model-supplied agent reference within the caller's tree. `lead` + * selects the root and a slash-separated path is looked up through the + * catalogs along it. Any other text that is not a name in the tree is + * returned as a Session id, because a single token can be one; a + * slash-separated address never is, so an unmatched path fails instead of + * reaching a member lookup as an unknown id. Resolution grants no authority: + * messaging, interruption, and assignment authorize the result. + * @param caller - exact live Agent whose tree root anchors the lookup. + * @param name - `lead`, a full name from the root, or a Session id. + * @param signal - cancellation forwarded to each catalog read. + * @returns the referenced Session id. + * @throws {@link SubagentError} `AGENT_NAME_NOT_FOUND` when a path names no member; + * when the caller's root is unavailable; or when a catalog along the path cannot be read. + */ +async resolveName(caller: Agent, name: string, signal: AbortSignal): Promise + /** * Join progressing subagent tree work for its root. Idle members with parked input * stay resident without delaying host completion. Ordinary members return false. diff --git a/docs/tool-catalog.i18n.yaml b/docs/tool-catalog.i18n.yaml index 2c07846e9d..da22a1e124 100644 --- a/docs/tool-catalog.i18n.yaml +++ b/docs/tool-catalog.i18n.yaml @@ -9,8 +9,8 @@ en: 6cc2cd9ced70bb09 zh: 1c0e6cb4ba2ed637 /tool-schema-catalog/tool-package-map: - en: 7e4516e824b1500e - zh: b0ea6f61792d98a0 + en: 7b5b99bcc5cd46f4 + zh: c1697f88326440ff /tool-schema-catalog/deepseek-ai-dsh-plugin-manager: en: e0143916bb634762 zh: e0143916bb634762 @@ -129,8 +129,8 @@ en: 07d595ce1f1a5184 zh: 07d595ce1f1a5184 /tool-schema-catalog/deepseek-ai-dsh-tool-fs/apply-patch: - en: 882f2fa9fac236d6 - zh: e8320796a5cb038f + en: 50b4939c9a1d96ac + zh: e733cc1156e2853c /tool-schema-catalog/deepseek-ai-dsh-tool-fs/edit: en: 5b6a252adde51af6 zh: 7aa172a5d8b9cbd2 @@ -240,8 +240,8 @@ en: 8daafae6faf7898e zh: 8daafae6faf7898e /tool-schema-catalog/deepseek-ai-dsh-experimental-tool-subagent-oar/subagent-oar: - en: 6283c3023d6ea436 - zh: 9c018b8c12a3f1e7 + en: 4936c61a65f8cdb2 + zh: 5a1bfbb9738a62a9 /tool-schema-catalog/deepseek-ai-dsh-tool-subagent: en: 841abe0dd5913ea7 zh: 841abe0dd5913ea7 @@ -249,17 +249,17 @@ en: 0e21650bbe8c71c7 zh: fe4033efb38d51a3 /tool-schema-catalog/deepseek-ai-dsh-tool-subagent/subagent: - en: 430672da3c1a6ca6 - zh: bd3a9ab4089f9dbb + en: 9912eeda5bc40b43 + zh: 0cb70f9a0d923bee /tool-schema-catalog/deepseek-ai-dsh-tool-subagent-control: en: ab82e130c3413f04 zh: ab82e130c3413f04 /tool-schema-catalog/deepseek-ai-dsh-tool-subagent-control/interrupt-agent: en: a622b15cc2598d51 - zh: 48e1b05956d63e26 + zh: ece4b2af6a11c49c /tool-schema-catalog/deepseek-ai-dsh-tool-subagent-control/list-agents: - en: a56168133c21c6a0 - zh: f9df1c0fe49fa225 + en: 8d50c6e19c9517ab + zh: 6ae97d046c5915db /tool-schema-catalog/deepseek-ai-dsh-tool-subagent-control/send-message: en: b53326fedeab850d zh: ecb75b6ce31da009 diff --git a/docs/tool-catalog.md b/docs/tool-catalog.md index c6a06cef4b..6cc41a1a12 100644 --- a/docs/tool-catalog.md +++ b/docs/tool-catalog.md @@ -40,7 +40,7 @@ This table connects model-visible tool names to the plugin package and service s | `@deepseek-ai/dsh-tool-skill` | `skill` | `ctx.workingDirectory`, `ctx.tools`, `ctx.agents`, `ctx.skills` | `tool/call`, `tool/result`, `user/message replacement catalogs via agent.inject()` | - | - | | `@deepseek-ai/dsh-tool-session-query` | `session_event_read`, `session_event_search`, `session_event_trace`, `session_search`, `session_trace` | `ctx.tools`, `ctx.systemPrompt`, `ctx.sessionQuery`, `ctx.agents`, `a calling Agent for workspace authority` | `tool/call`, `tool/result` | - | The five read-only tools hide provider cursors and authorize every result from the immutable calling agent session. The package is opt-in; compositions that need enforced deadlines or bounded inline output also mount the generic timeout or spill policies. | | `@deepseek-ai/dsh-experimental-tool-subagent-oar` | `subagent_oar` | `ctx.tools`, `ctx.subagents` | `tool/call`, `tool/result`, `parent subagent catalog and completion notices` | - | The subagent_oar tool selects among configured aliases for external providers. This catalog shows Codex and Claude Code aliases; each deployment chooses its providers. Native model and permission settings belong to the selected provider configuration. | -| `@deepseek-ai/dsh-tool-subagent` | `list_subagent_models`, `subagent` | `ctx.tools`, `ctx.subagents`, `ctx.systemPrompt`, `ctx.sessionProjections`, `ctx.llm for model discovery and selected-route validation` | `tool/call`, `tool/result`, `child session events through the chosen provider` | `subagent`, `subagent_fork` | The load-time `toolName` selects the delegation name (default `subagent`); `modelSelection` adds optional route fields. `modelDiscovery` defaults off and registers shared discovery on one instance per scope. Web and Desktop presets enable spawn discovery and route fields and leave `subagent_fork` route fields disabled. The Host settings service records authorization for each new top-level Session; child Sessions inherit it. Without a recorded policy, discovery and explicit selection permit only the current parent route. Every delegation returns a child id promptly; local children accept follow-ups, while external backends report their single execution automatically. | +| `@deepseek-ai/dsh-tool-subagent` | `list_subagent_models`, `subagent` | `ctx.tools`, `ctx.subagents`, `ctx.systemPrompt`, `ctx.sessionProjections`, `ctx.llm for model discovery and selected-route validation` | `tool/call`, `tool/result`, `child session events through the chosen provider` | `subagent`, `subagent_fork` | The load-time `toolName` selects the delegation name (default `subagent`); `modelSelection` adds optional route fields. `modelDiscovery` defaults off and registers shared discovery on one instance per scope. Web and Desktop presets enable spawn discovery and route fields and leave `subagent_fork` route fields disabled. The Host settings service records authorization for each new top-level Session; child Sessions inherit it. Without a recorded policy, discovery and explicit selection permit only the current parent route. Every delegation returns the child's name promptly; local children accept follow-ups, while external backends report their single execution automatically. | | `@deepseek-ai/dsh-tool-subagent-control` | `interrupt_agent`, `list_agents`, `send_message`, `wait_agent` | `ctx.tools`, `ctx.subagents`, `ctx.agents` | `tool/call`, `tool/result`, `child session events through ctx.subagents` | - | The shared control tools discover and contact agents in the subagent tree, interrupt owned descendants, and wait for input in the caller’s inbox. Provider-bound `tool-subagent` instances supply delegation tools. | | `@deepseek-ai/dsh-tool-jobs` | `job_kill`, `job_list`, `job_output` | `ctx.tools`, `ctx.jobs`, `ctx.systemPrompt` | `tool/call`, `tool/result`, `user/message via agent.inject() for background completion notices` | - | The kind-agnostic background-job controller: background bash commands and PTY sends are read, listed, and killed through the same three tools. Loading the plugin attaches the controller that arms producers' `ctx.jobs.start()`. | | `@deepseek-ai/dsh-tool-agent-team` | `team_task_create`, `team_task_get`, `team_task_list`, `team_task_update` | `ctx.tools`, `ctx.systemPrompt`, `ctx.agentTeams`, `ctx.subagents`, `an exact live Team member Agent` | `tool/call`, `team/task`, `tool/result` | - | Four task-board tools share the subagent tree’s root Session. Enabling Team mode on the root Session adds task-board guidance alongside standard subagent delegation and control tools. Standard subagent controls provide required identity independently of Team mode. | @@ -1045,7 +1045,7 @@ Standalone view/create/unique literal replace/line insert tool over the filesyst ### `apply_patch` -Create, update, delete, or move UTF-8 text files with one Codex-style patch; prefer it over multiple edit calls when a change spans several files or separated regions. +Create, update, delete, or move UTF-8 text files with one patch; prefer it over multiple edit calls when a change spans several files or separated regions. ```json { @@ -1053,7 +1053,7 @@ Create, update, delete, or move UTF-8 text files with one Codex-style patch; pre "properties": { "input": { "type": "string", - "description": "Codex patch text: start with *** Begin Patch and end with *** End Patch. Use *** Add File: path with + lines; *** Update File: path, optionally followed by *** Move to: path, with @@ or @@ context and space-prefixed context, + added, or - removed lines; *** End of File anchors the last hunk to the file end. Use *** Delete File: path to delete. Paths are relative to the Session working directory." + "description": "Patch text: start with *** Begin Patch and end with *** End Patch. Use *** Add File: path with + lines; *** Update File: path, optionally followed by *** Move to: path, with @@ or @@ context and space-prefixed context, + added, or - removed lines; *** End of File anchors the last hunk to the file end. Use *** Delete File: path to delete. Paths are relative to the Session working directory." } }, "required": [ @@ -1994,7 +1994,7 @@ The five read-only tools hide provider cursors and authorize every result from t ### `subagent_oar` -Delegate a self-contained task to a configured external agent. Choose its runtime for each call. The child works in its own context and does not see this conversation. This tool returns a child id; a later completion notice includes its final answer. The child does not accept follow-up messages. Start independent tasks together and continue useful work while they run. When only waiting for their results remains, end your turn instead of polling. +Delegate a self-contained task to a configured external agent. Choose its runtime for each call. The child works in its own context and does not see this conversation. This tool returns the child's name; a later completion notice includes its final answer. The child does not accept follow-up messages. Start independent tasks together and continue useful work while they run. When only waiting for their results remains, end your turn instead of polling. ```json { @@ -2012,6 +2012,10 @@ Delegate a self-contained task to a configured external agent. Choose its runtim "type": "string", "description": "A short description of the delegated task, for display." }, + "name": { + "type": "string", + "description": "Optional short name for the subagent, unique among the subagents you create: lower-case letters, digits, and hyphens, starting with a letter, at most 32 characters; lead is reserved for the root agent. Omitted names default to agent-1, agent-2, and so on." + }, "prompt": { "type": "string", "description": "The complete, self-contained task. Include all context the external agent needs." @@ -2061,7 +2065,7 @@ Source: [`packages/subagent/tool-subagent/src/list-models.ts`](../packages/subag ### `subagent` -Delegate a self-contained task to a subagent (a separate agent that works in its own context) to offload focused, independent work — research, a scoped implementation, an analysis — so it does not consume this conversation's context. The subagent returns its result, not its intermediate steps. This tool starts an independently managed subagent and immediately returns its id. If you are still online when it finishes, the runtime automatically delivers its completion notice. The notice includes the final answer unless the child sent you a message just before finishing. Use `send_message` to steer it while running or continue its conversation after it finishes. +Delegate a self-contained task to a subagent (a separate agent that works in its own context) to offload focused, independent work — research, a scoped implementation, an analysis — so it does not consume this conversation's context. The subagent returns its result, not its intermediate steps. This tool starts an independently managed subagent and immediately returns its name. If you are still online when it finishes, the runtime automatically delivers its completion notice. The notice includes the final answer unless the child sent you a message just before finishing. Use `send_message` to steer it while running or continue its conversation after it finishes. ```json { @@ -2075,6 +2079,10 @@ Delegate a self-contained task to a subagent (a separate agent that works in its "type": "string", "description": "A short (3-5 word) description of the delegated task, for display. Use the language of the user's current request." }, + "name": { + "type": "string", + "description": "Optional short name for the subagent, unique among the subagents you create: lower-case letters, digits, and hyphens, starting with a letter, at most 32 characters; lead is reserved for the root agent. Omitted names default to agent-1, agent-2, and so on." + }, "prompt": { "type": "string", "description": "The complete, self-contained task for the subagent. It does not share this conversation's context, so include everything it needs." @@ -2089,7 +2097,7 @@ Delegate a self-contained task to a subagent (a separate agent that works in its Source: [`packages/subagent/tool-subagent/src/index.ts`](../packages/subagent/tool-subagent/src/index.ts) -The load-time `toolName` selects the delegation name (default `subagent`); `modelSelection` adds optional route fields. `modelDiscovery` defaults off and registers shared discovery on one instance per scope. Web and Desktop presets enable spawn discovery and route fields and leave `subagent_fork` route fields disabled. The Host settings service records authorization for each new top-level Session; child Sessions inherit it. Without a recorded policy, discovery and explicit selection permit only the current parent route. Every delegation returns a child id promptly; local children accept follow-ups, while external backends report their single execution automatically. +The load-time `toolName` selects the delegation name (default `subagent`); `modelSelection` adds optional route fields. `modelDiscovery` defaults off and registers shared discovery on one instance per scope. Web and Desktop presets enable spawn discovery and route fields and leave `subagent_fork` route fields disabled. The Host settings service records authorization for each new top-level Session; child Sessions inherit it. Without a recorded policy, discovery and explicit selection permit only the current parent route. Every delegation returns the child's name promptly; local children accept follow-ups, while external backends report their single execution automatically. @@ -2103,13 +2111,13 @@ Ask a subagent to stop its current work. This call returns without waiting for i { "type": "object", "properties": { - "agent_id": { + "agent": { "type": "string", - "description": "The id of an agent created under you: your direct child or a deeper descendant." + "description": "The name of an agent created under you: your direct child or a deeper descendant." } }, "required": [ - "agent_id" + "agent" ] } ``` @@ -2118,7 +2126,7 @@ Source: [`packages/subagent/tool-subagent-control/src/index.ts`](../packages/sub ### `list_agents` -List your entire subagent tree: the root agent and all reachable continuable descendants, including yourself. Rows carry ids, descriptions, and status; descendant rows carry parent ids and depth from the root. You can message any other agent in the subagent tree listed as running or inactive. running means it is working; inactive means no turn is executing; it does not indicate task completion, success, or failure. While you remain active, you will be notified when a direct child finishes; there is no need to keep checking its status. Use send_message to continue the conversation. +List your entire subagent tree: the root agent and all reachable continuable descendants, including yourself. Rows carry names, descriptions, and status. A descendant's name is its path from the root, such as reviewer/checker. You can message any other agent in the subagent tree. running means it is working; inactive means no turn is executing; it does not indicate task completion, success, or failure. corrupt, unsupported, or unavailable means this row's own descendants could not be read; the row itself is still a member you can message. While you remain active, you will be notified when a direct child finishes; there is no need to keep checking its status. Use send_message to continue the conversation. ```json { @@ -2137,9 +2145,9 @@ Send a message to an agent. A working agent receives it at its next step; an idl { "type": "object", "properties": { - "agent_id": { + "agent": { "type": "string", - "description": "The agent id of another member of your subagent tree, as shown by list_agents." + "description": "The name of another agent in your subagent tree, as shown by list_agents." }, "message": { "type": "string", @@ -2147,7 +2155,7 @@ Send a message to an agent. A working agent receives it at its next step; an idl } }, "required": [ - "agent_id", + "agent", "message" ] } @@ -2332,7 +2340,11 @@ List shared tasks, including readiness, owner, revision, blockers, and write-sco }, "owner": { "type": "string", - "description": "Optional exact ownerId filter; use unowned for tasks without an owner." + "description": "Optional owner agent name filter; cannot be combined with unowned." + }, + "unowned": { + "type": "boolean", + "description": "Filter tasks by whether they have no owner; cannot be combined with owner." }, "ready": { "type": "boolean", @@ -2406,7 +2418,7 @@ Compare-and-set a shared task action using the latest revision from team_task_ge }, "owner": { "type": "string", - "description": "Agent id of the root or any continuable descendant for root-only reassign; omit to unassign." + "description": "Agent name of the root or any continuable descendant for root-only reassign; omit to unassign." } }, "required": [ diff --git a/docs/tool-catalog.zh.md b/docs/tool-catalog.zh.md index ef5d06c5c1..1198462f5e 100644 --- a/docs/tool-catalog.zh.md +++ b/docs/tool-catalog.zh.md @@ -44,7 +44,7 @@ | `@deepseek-ai/dsh-tool-skill` | `skill` | `ctx.workingDirectory`、`ctx.tools`、`ctx.agents`、`ctx.skills` | `tool/call`、`tool/result`、`user/message replacement catalogs via agent.inject()` | - | - | | `@deepseek-ai/dsh-tool-session-query` | `session_event_read`、`session_event_search`、`session_event_trace`、`session_search`、`session_trace` | `ctx.tools`、`ctx.systemPrompt`、`ctx.sessionQuery`、`a calling Agent for workspace authority` | `tool/call`、`tool/result` | - | 这 5 个只读工具会隐藏提供方游标,并根据不可变的调用 agent 会话为每个结果授权。该包需要选择启用;需要强制截止时间或限制行内输出的组合还会挂载通用超时或 spill 策略。 | | `@deepseek-ai/dsh-experimental-tool-subagent-oar` | `subagent_oar` | `ctx.tools`, `ctx.subagents` | `tool/call`, `tool/result`, `parent subagent catalog and completion notices` | - | subagent_oar 工具在为外部提供方配置的别名之间选择。本目录展示 Codex 和 Claude Code 别名;每个部署自行选择提供方。原生模型和权限设置由所选提供方的配置决定。 | -| `@deepseek-ai/dsh-tool-subagent` | `list_subagent_models`、`subagent` | `ctx.tools`、`ctx.subagents`、`ctx.systemPrompt`、`ctx.sessionProjections`、`用于模型发现和所选路由校验的 ctx.llm` | `tool/call`、`tool/result`、`child session events through the chosen provider` | `subagent`、`subagent_fork` | 加载时的 `toolName` 选择委派名称(默认为 `subagent`);`modelSelection` 增加可选路由字段。`modelDiscovery` 默认关闭,每个作用域由一个实例注册共享发现工具。Web 与 Desktop preset 启用 spawn 发现和路由字段,并为 `subagent_fork` 保持路由字段关闭。Host 设置服务为每个新顶层 Session 记录授权;子 Session 继承该授权。没有已记录策略时,发现和显式选择只允许当前父级路由。每次委派都会立即返回子代理 id;本地子代理接受后续消息,外部后端自动汇报单次执行结果。 | +| `@deepseek-ai/dsh-tool-subagent` | `list_subagent_models`、`subagent` | `ctx.tools`、`ctx.subagents`、`ctx.systemPrompt`、`ctx.sessionProjections`、`用于模型发现和所选路由校验的 ctx.llm` | `tool/call`、`tool/result`、`child session events through the chosen provider` | `subagent`、`subagent_fork` | 加载时的 `toolName` 选择委派名称(默认为 `subagent`);`modelSelection` 增加可选路由字段。`modelDiscovery` 默认关闭,每个作用域由一个实例注册共享发现工具。Web 与 Desktop preset 启用 spawn 发现和路由字段,并为 `subagent_fork` 保持路由字段关闭。Host 设置服务为每个新顶层 Session 记录授权;子 Session 继承该授权。没有已记录策略时,发现和显式选择只允许当前父级路由。每次委派都会立即返回子代理的名称;本地子代理接受后续消息,外部后端自动汇报单次执行结果。 | | `@deepseek-ai/dsh-tool-subagent-control` | `interrupt_agent`、`list_agents`、`send_message`、`wait_agent` | `ctx.tools`、`ctx.subagents`、`ctx.agents` | `tool/call`、`tool/result`、`child session events through ctx.subagents` | - | 共享控制工具发现并联系 subagent 树中的 Agent,中断有权控制的后代,并等待调用者收件箱中的输入。绑定提供方的 `tool-subagent` 实例提供委派工具。 | | `@deepseek-ai/dsh-tool-jobs` | `job_kill`、`job_list`、`job_output` | `ctx.tools`、`ctx.jobs`、`ctx.systemPrompt` | `tool/call`、`tool/result`、`user/message via agent.inject() for background completion notices` | - | 与任务种类无关的后台任务控制器:后台 bash 命令与 PTY 发送 都通过相同的 3 个工具读取、列出和终止。加载该插件会挂接控制器,从而启用生产方的 `ctx.jobs.start()`。 | | `@deepseek-ai/dsh-tool-agent-team` | `team_task_create`, `team_task_get`, `team_task_list`, `team_task_update` | `ctx.tools`, `ctx.systemPrompt`, `ctx.agentTeams`, `ctx.subagents`, `an exact live Team member Agent` | `tool/call`, `team/task`, `tool/result` | - | 四个任务板工具共享 subagent 树的根 Session。在根 Session 开启 Team 模式,会在标准 subagent 委派和控制工具之外增加任务板指导。标准 subagent 控制工具提供必需身份,不受 Team 模式影响。 | @@ -1051,7 +1051,7 @@ pwsh 工具是 Windows 组合中 bash 执行器 seam 的 PowerShell 方言消费 ### `apply_patch` -用一个 Codex 风格补丁新增、更新、删除或移动 UTF-8 文本文件;变更跨越多个文件或分离区域时,优先于多次 edit 调用。 +用一个补丁新增、更新、删除或移动 UTF-8 文本文件;变更跨越多个文件或分离区域时,优先于多次 edit 调用。 ```json { @@ -1059,7 +1059,7 @@ pwsh 工具是 Windows 组合中 bash 执行器 seam 的 PowerShell 方言消费 "properties": { "input": { "type": "string", - "description": "Codex patch text: start with *** Begin Patch and end with *** End Patch. Use *** Add File: path with + lines; *** Update File: path, optionally followed by *** Move to: path, with @@ or @@ context and space-prefixed context, + added, or - removed lines; *** End of File anchors the last hunk to the file end. Use *** Delete File: path to delete. Paths are relative to the Session working directory." + "description": "Patch text: start with *** Begin Patch and end with *** End Patch. Use *** Add File: path with + lines; *** Update File: path, optionally followed by *** Move to: path, with @@ or @@ context and space-prefixed context, + added, or - removed lines; *** End of File anchors the last hunk to the file end. Use *** Delete File: path to delete. Paths are relative to the Session working directory." } }, "required": [ @@ -2000,7 +2000,7 @@ lsp 工具将提供方选择和语言服务器子进程置于 ctx.lsp 之后, ### `subagent_oar` -将上下文完整的任务委派给已配置的外部 agent。每次调用选择一个运行时。subagent 在独立上下文中工作,无法看到当前对话。工具返回子级 id,后续完成通知包含其最终回答。subagent 不接受后续消息。并发启动相互独立的任务,并在其运行期间继续其他有用工作。只剩等待结果时结束当前轮次,不要轮询。 +将上下文完整的任务委派给已配置的外部 agent。每次调用选择一个运行时。subagent 在独立上下文中工作,无法看到当前对话。工具返回子级的名称,后续完成通知包含其最终回答。subagent 不接受后续消息。并发启动相互独立的任务,并在其运行期间继续其他有用工作。只剩等待结果时结束当前轮次,不要轮询。 ```json { @@ -2018,6 +2018,10 @@ lsp 工具将提供方选择和语言服务器子进程置于 ctx.lsp 之后, "type": "string", "description": "A short description of the delegated task, for display." }, + "name": { + "type": "string", + "description": "Optional short name for the subagent, unique among the subagents you create: lower-case letters, digits, and hyphens, starting with a letter, at most 32 characters; lead is reserved for the root agent. Omitted names default to agent-1, agent-2, and so on." + }, "prompt": { "type": "string", "description": "The complete, self-contained task. Include all context the external agent needs." @@ -2067,7 +2071,7 @@ subagent_oar 工具在为外部提供方配置的别名之间选择。本目录 ### `subagent` -将一项自包含任务委派给 subagent(在自身上下文中工作的独立 agent),用它卸载聚焦且独立的工作,例如研究、限定范围的实现或分析,以免消耗当前对话的上下文。subagent 会返回结果,但不会返回中间步骤。此工具启动独立管理的 subagent 并立即返回其 id。如果它结束时你仍在线,运行时会自动递送其完成通知。通知包含最终回答,除非子任务在结束前刚给你发过消息。你可以使用 `send_message` 在运行时引导它,或在结束后继续对话。 +将一项自包含任务委派给 subagent(在自身上下文中工作的独立 agent),用它卸载聚焦且独立的工作,例如研究、限定范围的实现或分析,以免消耗当前对话的上下文。subagent 会返回结果,但不会返回中间步骤。此工具启动独立管理的 subagent 并立即返回其名称。如果它结束时你仍在线,运行时会自动递送其完成通知。通知包含最终回答,除非子任务在结束前刚给你发过消息。你可以使用 `send_message` 在运行时引导它,或在结束后继续对话。 ```json { @@ -2081,6 +2085,10 @@ subagent_oar 工具在为外部提供方配置的别名之间选择。本目录 "type": "string", "description": "A short (3-5 word) description of the delegated task, for display. Use the language of the user's current request." }, + "name": { + "type": "string", + "description": "Optional short name for the subagent, unique among the subagents you create: lower-case letters, digits, and hyphens, starting with a letter, at most 32 characters; lead is reserved for the root agent. Omitted names default to agent-1, agent-2, and so on." + }, "prompt": { "type": "string", "description": "The complete, self-contained task for the subagent. It does not share this conversation's context, so include everything it needs." @@ -2095,7 +2103,7 @@ subagent_oar 工具在为外部提供方配置的别名之间选择。本目录 来源:[`packages/subagent/tool-subagent/src/index.ts`](../packages/subagent/tool-subagent/src/index.ts) -加载时的 `toolName` 选择委派名称(默认为 `subagent`);`modelSelection` 增加可选路由字段。`modelDiscovery` 默认关闭,每个作用域由一个实例注册共享发现工具。Web 与 Desktop preset 启用 spawn 发现和路由字段,并为 `subagent_fork` 保持路由字段关闭。Host 设置服务为每个新顶层 Session 记录授权;子 Session 继承该授权。没有已记录策略时,发现和显式选择只允许当前父级路由。每次委派都会立即返回子代理 id;本地子代理接受后续消息,外部后端自动汇报单次执行结果。 +加载时的 `toolName` 选择委派名称(默认为 `subagent`);`modelSelection` 增加可选路由字段。`modelDiscovery` 默认关闭,每个作用域由一个实例注册共享发现工具。Web 与 Desktop preset 启用 spawn 发现和路由字段,并为 `subagent_fork` 保持路由字段关闭。Host 设置服务为每个新顶层 Session 记录授权;子 Session 继承该授权。没有已记录策略时,发现和显式选择只允许当前父级路由。每次委派都会立即返回子代理的名称;本地子代理接受后续消息,外部后端自动汇报单次执行结果。 @@ -2103,19 +2111,19 @@ subagent_oar 工具在为外部提供方配置的别名之间选择。本目录 ### `interrupt_agent` -根据 agent id 请求取消后台 agent 的当前轮次。目标可以是你的直接子级,也可以是在你下方创建的更深层 agent。对于本地 agent,只有当前轮次会停止:已经排队发给该 agent 的消息会一直搁置到后续的 send_message;它启动的 agent 会继续运行;该 agent 本身仍可接受后续操作。外部执行会永久停止,无法接收后续消息。停止请求被接受后,此调用立即返回,因此目标可能还会短暂运行;中断一个已经完成的 agent 是可接受的空操作。 +请求 subagent 停止当前工作。此调用不等待其停止即返回。之后可以用 send_message 继续本地 subagent 的对话。外部执行会永久停止,无法接收后续消息。它启动的 subagent 会继续运行。 ```json { "type": "object", "properties": { - "agent_id": { + "agent": { "type": "string", - "description": "The id of an agent created under you: your direct child or a deeper descendant." + "description": "The name of an agent created under you: your direct child or a deeper descendant." } }, "required": [ - "agent_id" + "agent" ] } ``` @@ -2124,7 +2132,7 @@ subagent_oar 工具在为外部提供方配置的别名之间选择。本目录 ### `list_agents` -列出整棵 subagent 树:根代理和所有可达的可继续后代,包括调用方自身。行包含 id、描述和状态;后代行包含父级 id 和相对根的深度。可以向树中列为 running 或 inactive 的任意其他代理发送消息。running 表示正在工作;inactive 表示当前没有轮次在执行,不表示任务完成、成功或失败。自身仍在线时,直属子代理结束会收到通知,无需反复查询其状态。使用 send_message 继续对话。 +列出整棵 subagent 树:根代理和所有可达的可继续后代,包括调用方自身。行包含名称、描述和状态。后代的名称是其相对根的路径,例如 reviewer/checker。可以向树中任意其他代理发送消息。running 表示正在工作;inactive 表示当前没有轮次在执行,不表示任务完成、成功或失败。corrupt、unsupported 或 unavailable 表示该行自身的后代目录无法读取,该行本身仍是可发送消息的成员。自身仍在线时,直属子代理结束会收到通知,无需反复查询其状态。使用 send_message 继续对话。 ```json { @@ -2143,9 +2151,9 @@ subagent_oar 工具在为外部提供方配置的别名之间选择。本目录 { "type": "object", "properties": { - "agent_id": { + "agent": { "type": "string", - "description": "The agent id of another member of your subagent tree, as shown by list_agents." + "description": "The name of another agent in your subagent tree, as shown by list_agents." }, "message": { "type": "string", @@ -2153,7 +2161,7 @@ subagent_oar 工具在为外部提供方配置的别名之间选择。本目录 } }, "required": [ - "agent_id", + "agent", "message" ] } @@ -2338,7 +2346,11 @@ subagent_oar 工具在为外部提供方配置的别名之间选择。本目录 }, "owner": { "type": "string", - "description": "Optional exact ownerId filter; use unowned for tasks without an owner." + "description": "Optional owner agent name filter; cannot be combined with unowned." + }, + "unowned": { + "type": "boolean", + "description": "Filter tasks by whether they have no owner; cannot be combined with owner." }, "ready": { "type": "boolean", @@ -2412,7 +2424,7 @@ subagent_oar 工具在为外部提供方配置的别名之间选择。本目录 }, "owner": { "type": "string", - "description": "Agent id of the root or any continuable descendant for root-only reassign; omit to unassign." + "description": "Agent name of the root or any continuable descendant for root-only reassign; omit to unassign." } }, "required": [ diff --git a/docs/upgrade-guide/v0.2.2-alpha.3/subagent-names/guide.i18n.yaml b/docs/upgrade-guide/v0.2.2-alpha.3/subagent-names/guide.i18n.yaml new file mode 100644 index 0000000000..30dd0072b8 --- /dev/null +++ b/docs/upgrade-guide/v0.2.2-alpha.3/subagent-names/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.2-alpha.3/subagent-names/guide.md +/: + en: 9d10fcdf4af74152 + zh: 1e932a7fe192df48 +/subagent-tools-address-agents-by-name: + en: 7aad2f3764a30b45 + zh: 4e24d2370e54bc37 +/subagent-tools-address-agents-by-name/change: + en: 6b457593371cf01e + zh: 730d30aad31ebd91 +/subagent-tools-address-agents-by-name/migration: + en: d416c6b1cef47655 + zh: edcae0ecc55dcfe5 diff --git a/docs/upgrade-guide/v0.2.2-alpha.3/subagent-names/guide.md b/docs/upgrade-guide/v0.2.2-alpha.3/subagent-names/guide.md new file mode 100644 index 0000000000..1d114a3e4d --- /dev/null +++ b/docs/upgrade-guide/v0.2.2-alpha.3/subagent-names/guide.md @@ -0,0 +1,29 @@ +--- +kind: upgrade-guide +description: "Subagent control and Team task tools address agents by name, list_agents rows change, and subagent catalogs write payload version 3." +--- + +# Subagent tools address agents by name + +English | [中文](guide.zh.md) + +## Change + +New subagents have sibling-unique names in their creator's `subagent/catalog`. The root is `lead`; descendant names are paths such as `reviewer/checker`. The [subagent runtime](../../../../packages/subagent/subagent/README.md#agent-names) defines naming rules. Historical children keep their Session ids. Scripts, PTC, SDK callers, and transcripts must adopt these changes: + +- `send_message({ agent_id, message })` becomes `send_message({ agent, message })`, and `interrupt_agent({ agent_id })` becomes `interrupt_agent({ agent })`. `agent` accepts a name or a Session id. A call that still passes `agent_id` fails argument validation. +- `subagent`, `subagent_fork`, and `subagent_oar` accept an optional `name`. They return `started subagent ` with result `{ kind: 'activation', name }`. +- `list_agents` returns `{ name, status, description? }` rows instead of rows with `kind`, `id`, `label`, `parent`, `depth`, and `reason`. Unreadable branches report `corrupt`, `unsupported`, or `unavailable` as `status`. Text rows read ` [] — `. +- Team task results replace `ownerId` with `owner`, the owner's name. `team_task_list` and `team_task_update` accept a name as `owner`. To list tasks without an owner, use `unowned: true` instead of `owner: "unowned"`. +- Local and parent-delivered external creation write `subagent/catalog` payload version 3. Releases before this one reject catalogs that contain it, so they cannot open Sessions that create subagents after upgrading. See the [persistence acknowledgement](../../../persistence-changes/2026-11-02-subagent-catalog-names.md). +- `SubagentActivation` has a required `name` field, and `SubagentActivationSpec` accepts an optional `name`. + +## Migration + +1. In scripts, PTC programs, and SDK calls, rename the `agent_id` argument of `send_message` and `interrupt_agent` to `agent`. Pass the name that `list_agents` or the start receipt reports; a saved Session id still works. +2. Update parsers of `list_agents` output to read `name`, `status`, and `description`. Only complete named paths encode creators: the prefix before the last `/`, or `lead` without `/`. Unnamed children or ancestors cause Session-id fallback; these rows expose neither creator nor depth. +3. Update Team task consumers to read `owner` instead of `ownerId`. Host code that calls `ctx.agentTeams` still reads `ownerId`; display `ownerName ?? ownerId`. New assignments persist optional `ownerName`; historical records remain unchanged. Older projections reject named tasks; see the [acknowledgement](../../../persistence-changes/2026-11-02-team-task-owner-names.md). +4. Read `name` instead of `subagentId` from delegation tool results. Update recorded transcripts or fixtures that contain `agent_id` arguments, `started subagent ` receipts, identity runtime context text, `Agent sent a message` signatures, `Background subagent ` notices, or the earlier `list_agents` rows. Signatures and notices now use names. +5. Add `name` when constructing `SubagentActivation` values. Code that reads catalog rows can read the optional `name` field. +6. Upgrade every process that opens the same Session store before creating subagents. Older releases cannot open Sessions that contain catalog payload version 3. +7. To confirm the change, start a subagent with `name: "reviewer"` and check that the receipt reads `started subagent reviewer`, that `list_agents` lists `reviewer`, and that `send_message({ agent: "reviewer", message })` succeeds. diff --git a/docs/upgrade-guide/v0.2.2-alpha.3/subagent-names/guide.zh.md b/docs/upgrade-guide/v0.2.2-alpha.3/subagent-names/guide.zh.md new file mode 100644 index 0000000000..e6e65415b3 --- /dev/null +++ b/docs/upgrade-guide/v0.2.2-alpha.3/subagent-names/guide.zh.md @@ -0,0 +1,29 @@ +--- +kind: upgrade-guide +description: "Subagent 控制工具和 Team 任务工具按名称寻址 agent,list_agents 行格式改变,subagent 目录写入第 3 版载荷。" +--- + +# Subagent 工具按名称寻址 agent + +[English](guide.md) | 中文 + +## 变更 + +新 subagent(子智能体)在创建者的 `subagent/catalog` 中拥有同级唯一的名称。根为 `lead`;后代名称是 `reviewer/checker` 这样的路径。[subagent 运行时](../../../../packages/subagent/subagent/README.zh.md#agent-names)定义名称规则。升级前创建的子级继续以 Session id 作为名称。脚本、PTC、SDK 调用方和 transcript(文本记录)需要适配以下变更: + +- `send_message({ agent_id, message })` 改为 `send_message({ agent, message })`,`interrupt_agent({ agent_id })` 改为 `interrupt_agent({ agent })`。`agent` 接受名称或 Session id。仍传入 `agent_id` 的调用无法通过参数校验。 +- `subagent`、`subagent_fork` 和 `subagent_oar` 接受可选的 `name`。它们返回 `started subagent `,结果为 `{ kind: 'activation', name }`。 +- `list_agents` 返回 `{ name, status, description? }` 行,取代含 `kind`、`id`、`label`、`parent`、`depth` 和 `reason` 的行。不可读分支以 `status` 报告 `corrupt`、`unsupported` 或 `unavailable`。文本行格式为 ` [] — `。 +- Team 任务结果以 `owner`(所有者名称)取代 `ownerId`。`team_task_list` 和 `team_task_update` 的 `owner` 接受名称。查询无所有者任务时,用 `unowned: true` 替代 `owner: "unowned"`。 +- 本地创建和父级投递的外部创建写入第 3 版 `subagent/catalog` 载荷。本版本之前的发布会拒绝包含该载荷的目录,因此无法打开升级后创建过 subagent 的 Session。参见[持久化确认记录](../../../persistence-changes/2026-11-02-subagent-catalog-names.zh.md)。 +- `SubagentActivation` 新增必需字段 `name`,`SubagentActivationSpec` 接受可选的 `name`。 + +## 迁移 + +1. 在脚本、PTC 程序和 SDK 调用中,将 `send_message` 和 `interrupt_agent` 的 `agent_id` 参数改名为 `agent`。传入 `list_agents` 或启动回执报告的名称;已保存的 Session id 仍可使用。 +2. 更新 `list_agents` 输出的解析器,读取 `name`、`status` 和 `description`。只有完整命名路径编码创建者:最后一个 `/` 之前的前缀,不含 `/` 时为 `lead`。未命名的子级或祖先导致回退到 Session id;这些行既不提供创建者,也不提供深度。 +3. 更新 Team 任务消费方,读取 `owner` 而非 `ownerId`。调用 `ctx.agentTeams` 的 host 代码仍读取 `ownerId`;展示时读取 `ownerName ?? ownerId`。新分配会持久化可选的 `ownerName`,历史记录保持不变。旧投影会拒绝带名称的任务;参见[确认记录](../../../persistence-changes/2026-11-02-team-task-owner-names.zh.md)。 +4. 从委派工具结果读取 `name` 而非 `subagentId`。更新包含 `agent_id` 参数、`started subagent ` 回执、身份运行时上下文文本、`Agent sent a message` 署名、`Background subagent ` 通知或旧 `list_agents` 行的录制 transcript 或 fixture。署名和通知现在使用名称。 +5. 构造 `SubagentActivation` 值时添加 `name`。读取目录行的代码可读取可选的 `name` 字段。 +6. 在创建 subagent 之前,升级所有打开同一 Session 存储的进程。旧版本无法打开包含第 3 版目录载荷的 Session。 +7. 验证迁移:以 `name: "reviewer"` 启动一个 subagent,确认回执为 `started subagent reviewer`,`list_agents` 列出 `reviewer`,且 `send_message({ agent: "reviewer", message })` 成功。 diff --git a/packages/api/session-controller/README.i18n.yaml b/packages/api/session-controller/README.i18n.yaml index e2dab90bf6..3d31867b67 100644 --- a/packages/api/session-controller/README.i18n.yaml +++ b/packages/api/session-controller/README.i18n.yaml @@ -15,8 +15,8 @@ en: 1fdf707322fb6996 zh: 0204f7e9d4aa3cce /session-controller/use-this-package: - en: 2e239f9d7ebdce08 - zh: 655e9c7fdc41aca3 + en: 9cac36e3c0a32959 + zh: 37c42cc3edafa798 /session-controller/client-references: en: e8979a803ec3e194 zh: c567efcd971728ba @@ -24,8 +24,8 @@ en: 954923654eebe2dc zh: 6bd9a7d2ea965aed /session-controller/configuration: - en: c92590fbaf75e45e - zh: fcac67017bb0e3ab + en: 8f62f7183c67fc02 + zh: 0e2db400b376629f /session-controller/model-experience: en: 30b917bf822bb4df zh: b0b023b5b526c317 @@ -33,8 +33,8 @@ en: 22fc0c9dbedd3bb6 zh: fad040ca55fd0e0a /session-controller/known-limitations-and-deferred-work: - en: 5db0f9f69a8be926 - zh: 6ba1cc4a3850fcbc + en: 23bc3db43e84daa6 + zh: 0242338ac7bd24fa /session-controller/known-limitations-and-deferred-work/dev-note: en: e67f633dc6fe7773 zh: e88aeb617ffb74ea diff --git a/packages/api/session-controller/README.md b/packages/api/session-controller/README.md index a9c58684d5..b430594b0e 100644 --- a/packages/api/session-controller/README.md +++ b/packages/api/session-controller/README.md @@ -66,7 +66,7 @@ During uninterrupted following, transcript and steering echoes stay in Chat thro The user-invocable `skills/list` metadata includes the winning provider’s optional instruction-file `path`. The composer can preview that file without loading every skill body or activating a cold Agent. -Fork copies the exact inclusive event prefix selected by `atSeq`, including a cut inside an open turn, into an independent Session without `parentSession`. Client placeholders likewise omit `parentSessionId`; list indentation applies only to subagent-origin rows, including when historical ordinary forks retain a parent id. Workspace attachment and optional title increments use the source selected for the operation. The child records its inherited marker before synthetic fork results and closing events. Omitting `atSeq` selects the latest completed turn and its standalone tail, stopping before the next turn or queued input; a nonexistent event is rejected. The chat action selects a completed turn. +Fork copies the exact inclusive event prefix selected by `atSeq`, including a cut inside an open turn, into an independent Session without `parentSession`. Client placeholders likewise omit `parentSessionId`; list indentation applies only to subagent-origin rows, including when historical ordinary forks retain a parent id. Workspace attachment and optional title increments use the source selected for the operation; an increment skips numbers that other Host-listed titles already use. The child records its inherited marker before synthetic fork results and closing events. Omitting `atSeq` selects the latest completed turn and its standalone tail, stopping before the next turn or queued input; a nonexistent event is rejected. The chat action selects a completed turn. A resume blocked by an existing write handle returns `session/writer-held` with the Session id; other resume failures retain `gateway/internal`. @@ -112,6 +112,8 @@ The generated [configuration catalog](../../../docs/config-catalog.md#deepseek-a Blockquotes travel as ordinary prompt text without quote metadata. Local submission echoes and durable messages use the same text rendering rules; queue edits replace content while retaining prompt correlation. +An empty `prompt.content` array requests a new turn only for an eligible failed, idle ordinary Session in queue mode. Pending human input prevents admission; non-waking injected context is retained. `conversationContinuation` supplies the shared six-code manual policy, independently of provider retry configuration. The input follows ordinary inbox and Loop admission and records an empty `user/message` with `source.kind: 'retry'`; its input identity and caller metadata support deduplication and recovery. Whitespace-only text parts remain invalid. + ## Model Experience @@ -129,6 +131,7 @@ No direct effect; model requests remain owned by the Agent and LLM packages. - The image byte cap does not validate decoded dimensions or pixel count. - A failed follow resumption remains visible to the caller instead of retrying indefinitely. - The raw browser upload is one streaming HTTP request without resumable offsets; a retry sends the file again from byte zero. +- Fork title increments compare candidates with the Client list before the Host normalizes them: concurrent forks of one source, or a title the Host truncates at its byte limit, can still produce duplicate titles. - File-reference completion uses the shared Agent lookup and can resume a cold Session; the `skills/list` catalog is the non-activating alternative for skill metadata. - Accepted/running display memory lives only in Client memory and is lost on page reload. - That memory is not shared between tabs: one tab can show a converted row while another still shows `New Session` for the same Session. diff --git a/packages/api/session-controller/README.zh.md b/packages/api/session-controller/README.zh.md index 41858dde25..314ec58840 100644 --- a/packages/api/session-controller/README.zh.md +++ b/packages/api/session-controller/README.zh.md @@ -66,7 +66,7 @@ Session 对象还承载本地提交回显:`session.beginSubmission` 在调用 面向用户调用的 `skills/list` 元数据包含胜出提供方可选的指令文件 `path`。输入框可据此预览文件,无需加载每个 skill 的正文或激活冷态 Agent。 -Fork 将 `atSeq` 选定的含边界事件前缀(包括开放轮次内的截点)复制到不带 `parentSession` 的独立 Session。客户端占位项同样省略 `parentSessionId`;列表缩进仅适用于 subagent 来源的行,历史普通 fork 即使保留父 ID 也不缩进。工作区绑定及可选标题递增使用本次操作选定的源会话。子会话在合成的 fork 结果和结束事件之前记录继承标记。省略 `atSeq` 时选择最近已结束轮次及其独立尾部,在下一轮次或排队输入之前停止;不存在的事件会被拒绝。聊天操作选择已结束轮次。 +Fork 将 `atSeq` 选定的含边界事件前缀(包括开放轮次内的截点)复制到不带 `parentSession` 的独立 Session。客户端占位项同样省略 `parentSessionId`;列表缩进仅适用于 subagent 来源的行,历史普通 fork 即使保留父 ID 也不缩进。工作区绑定及可选标题递增使用本次操作选定的源会话;递增时会跳过其他由 Host 列出的标题已使用的编号。子会话在合成的 fork 结果和结束事件之前记录继承标记。省略 `atSeq` 时选择最近已结束轮次及其独立尾部,在下一轮次或排队输入之前停止;不存在的事件会被拒绝。聊天操作选择已结束轮次。 恢复会话时若已有写句柄占用,返回 `session/writer-held`,并携带会话 id;其他恢复失败仍返回 `gateway/internal`。 @@ -112,6 +112,8 @@ GUI 模型选择要求确切提供方/模型对出现在可用目录中;不 Blockquote 作为普通 prompt 文本传递,不携带 quote 元数据。本地提交回显与持久消息使用同一文本渲染规则;队列编辑替换 content,同时保留 prompt 关联信息。 +空的 `prompt.content` 数组仅在普通 Session 空闲、最新失败符合继续条件且使用 queue 模式时请求新轮次。待消费的用户输入阻止准入,非唤醒的注入上下文保留。`conversationContinuation` 提供共用的六码手动策略,独立于提供方重试配置。输入遵循普通 inbox 和 Loop 准入,记录带 `source.kind: 'retry'` 的空 `user/message`;输入身份与调用方元数据用于去重和恢复。仅含空白的文本块仍无效。 + ## 模型体验 @@ -129,6 +131,7 @@ Blockquote 作为普通 prompt 文本传递,不携带 quote 元数据。本地 - 图片字节上限不校验解码后的尺寸或像素数。 - follow 恢复失败会对调用方可见,而不会无限重试。 - 浏览器原始字节上传使用一次不带断点续传偏移的流式 HTTP 请求;重试会从第零字节重新传输整个文件。 +- Fork 标题递增会在 Host 规范化候选标题之前,先将其与客户端列表比较:同一来源的并发 Fork,或被 Host 按字节上限截断的标题,仍可能产生重复标题。 - 文件引用补全使用共享 Agent lookup,因此可能恢复冷 Session;`skills/list` 目录是不激活 Agent 的 skill 元数据读取路径。 - 受理/运行的展示记忆只存在于客户端内存,页面重载后即丢失。 - 该记忆不在 tab 之间共享:同一会话可能在一个 tab 中已转正,在另一个 tab 中仍显示为 `New Session`。 diff --git a/packages/api/session-controller/src/client/contract/sessions.ts b/packages/api/session-controller/src/client/contract/sessions.ts index a52d2c155a..c1fede0937 100644 --- a/packages/api/session-controller/src/client/contract/sessions.ts +++ b/packages/api/session-controller/src/client/contract/sessions.ts @@ -128,7 +128,8 @@ export interface ISessions { * seq (a real event seq the caller already knows; a cut inside an open * turn is balanced Host-side with synthetic closers, and omission selects * the latest completed-turn prefix), and whether to increment an - * inherited durable title before resolving. `onCreated` observes the catalogued child before that optional rename. + * inherited durable title, skipping numbers Host-listed titles already use, + * before resolving. `onCreated` observes the catalogued child before that optional rename. * @returns the child session id. * @throws when the fork fails, or when a requested child-title rename fails after creation. */ diff --git a/packages/api/session-controller/src/client/sessions/service.ts b/packages/api/session-controller/src/client/sessions/service.ts index 4b70888468..86b1ad4757 100644 --- a/packages/api/session-controller/src/client/sessions/service.ts +++ b/packages/api/session-controller/src/client/sessions/service.ts @@ -130,12 +130,24 @@ function displayTitleOf(title: string | undefined, cwd: string | undefined, id: } /** - * Increment a trailing fork number while preserving its half-width or - * full-width parentheses; an unnumbered title starts with ` (1)`. + * Increment the fork number until the candidate is not taken. * @param title - source session's durable title. + * @param taken - durable titles of Host-listed sessions. * @returns the title assigned to the fork child. */ -function increasedForkTitle(title: string): string { +function increasedForkTitle(title: string, taken: ReadonlySet): string { + let next = incrementedTitle(title) + while (taken.has(next)) next = incrementedTitle(next) + return next +} + +/** + * Increment a trailing fork number while preserving its half-width or + * full-width parentheses; an unnumbered title starts with ` (1)`. + * @param title - title to increment. + * @returns the title with the next fork number. + */ +function incrementedTitle(title: string): string { const ascii = /^(.*?)\((\d+)\)$/u.exec(title) if (ascii?.[1] !== undefined && ascii[2] !== undefined) { return `${ascii[1]}(${BigInt(ascii[2]) + 1n})` @@ -455,7 +467,8 @@ export class ClientSessions implements ISessions { * seq (a real event seq the caller already knows; a cut inside an open * turn is balanced Host-side with synthetic closers, and omission selects * the latest completed-turn prefix), and whether to increment an - * inherited durable title before resolving, plus permission to start source migration. + * inherited durable title, skipping numbers Host-listed titles already use, + * before resolving, plus permission to start source migration. * @returns the child session id. * @throws {SessionForkError} with the source id. * @throws {Error} when a requested child-title rename fails after creation. @@ -480,7 +493,9 @@ export class ClientSessions implements ISessions { const childId = result.value.sessionId opts.onCreated?.(childId) if (sourceTitle !== undefined) { - const renamed = await this.manager.rename(childId, increasedForkTitle(sourceTitle)) + const list = this.list.getSnapshot() + const taken = new Set(list.ids.flatMap(id => list.byId[id]?.title ?? [])) + const renamed = await this.manager.rename(childId, increasedForkTitle(sourceTitle, taken)) if (!renamed.ok) throw new Error(`fork child rename failed: ${renamed.error.code}: ${renamed.error.message}`) } return childId diff --git a/packages/api/session-controller/src/commands.ts b/packages/api/session-controller/src/commands.ts index f0e644fb58..9888957fd5 100644 --- a/packages/api/session-controller/src/commands.ts +++ b/packages/api/session-controller/src/commands.ts @@ -1,5 +1,8 @@ /** Session commands whose activation policy is explicit at each Remote method. */ +import type { ProjectionHandle } from '@deepseek-ai/dsh-session-projection' +import { continuationProjectionDefinition, type ContinuationState } from './continuation.ts' + import { modelAvailable } from './catalog.ts' import { randomUUID } from 'node:crypto' import type { Context } from '@deepseek-ai/cordis' @@ -59,7 +62,7 @@ type PromptContentCandidate = /** * Whether prompt content carries non-whitespace text or an attachment. * @param content - submitted or edited prompt parts. - * @returns false for content the Agent must not receive. + * @returns whether any part supplies ordinary prompt content. */ export function hasPromptContent(content: readonly PromptContentCandidate[]): boolean { return content.some(part => part.type !== 'text' || part.text.trim().length > 0) @@ -90,6 +93,13 @@ export class SessionCommandController { requests: Set }>() + private continuation!: ProjectionHandle + + /** Register complete-history empty-prompt eligibility. @returns when command admission is ready. */ + async initialize(): Promise { + this.continuation = await this.ctx.sessionProjections.register(continuationProjectionDefinition) + } + /** * @param ctx - Host context carrying Agent, model, attachment, title, and Workspace services. * @param agents - sole owner of create, resume, and Agent composition. @@ -305,12 +315,28 @@ export class SessionCommandController { * Admit one prompt after Agent and attachment validation; the Remote method * has already validated the content and built the durable message source. * @param request - Session identity, prompt content, and delivery mode. - * @param source - the correlated user source recorded on the accepted message. + * @param source - caller metadata recorded on the accepted ordinary or retry user message. * @returns acknowledgement that the Agent accepted the prompt. */ async prompt(request: SessionPromptRequest, source: MessageSource): Promise { const agent = await this.resolveAgent(request.sessionId) if (this.hasPromptRequest(agent.session, request.requestId)) return { accepted: true } + if (request.content.length === 0) { + try { + return await agent.runMaintenance(() => { + const inbox = agent.inbox + if (request.mode !== 'queue' || this.continuation.stateOf(agent.session).ending === null + || inbox.nextTurn.length > 0 || inbox.nextStep.some(message => message.source.kind === 'user')) { + throw new RemoteError('session/agent-busy', 'generation continuation is unavailable', { reason: 'NO_CONTINUABLE_FAILURE_OR_PENDING_INPUT' }) + } + agent.followup(createUserMessage({ content: [], source })) + return Promise.resolve({ accepted: true as const }) + }) + } catch (error: unknown) { + if (remoteErrorOf(error) !== undefined) throw error + throw new RemoteError('session/agent-busy', 'generation continuation was not accepted', { reason: String(error) }) + } + } const admission = resolvePromptFileReceipts( request.content, receiptId => this.ctx.fileUploads.resolve(agent, receiptId), @@ -378,7 +404,7 @@ export class SessionCommandController { // A copied input is not a new request in the child, even if later reinserted there. if (event.seq < session.inheritedEventCount) continue const source = message.source - if (source.kind === 'user' && 'rpcId' in source) receipts.requests.add(source.rpcId) + if ((source.kind === 'user' || source.kind === 'retry') && 'rpcId' in source) receipts.requests.add(source.rpcId) } } receipts.offset = session.seq @@ -476,7 +502,7 @@ export class SessionCommandController { case 'remove': { agent.inbox.remove(request.itemId) const source = message.source - if (source.kind === 'user' && 'rpcId' in source) { + if ((source.kind === 'user' || source.kind === 'retry') && 'rpcId' in source) { this.ctx.fileUploads.retirePrompt(agent, source.rpcId) } break diff --git a/packages/api/session-controller/src/continuation.ts b/packages/api/session-controller/src/continuation.ts new file mode 100644 index 0000000000..3be2a2be1d --- /dev/null +++ b/packages/api/session-controller/src/continuation.ts @@ -0,0 +1,58 @@ +/** Constant-size continuation eligibility over the complete durable Session. */ +import type {} from './types.ts' +import type { ProjectionDefinition } from '@deepseek-ai/dsh-session-projection' +import type { SessionSeq } from '@deepseek-ai/dsh-session/types' +import { brandNumber } from '@deepseek-ai/dsh-brand' +import { z } from 'zod' + +// Explicit manual requests use a fixed product policy, independent of automatic retry configuration. +const CONTINUABLE_FAILURES: ReadonlySet = new Set([ + 'RATE_LIMIT', 'SERVER', 'TIMEOUT', 'TRANSPORT', 'EMPTY_RESPONSE', 'STREAM_CLOSED', +]) + +const endingSchema = z.number().int().nonnegative().transform(brandNumber).nullable() +const stateSchema = z.object({ + admitted: z.boolean(), + failedAttempt: z.boolean(), + ending: endingSchema, +}) + +/** Recoverable manual-continuation facts over admitted user input and empty retry messages. */ +export type ContinuationState = z.infer + +const EMPTY: ContinuationState = { admitted: false, failedAttempt: false, ending: null } + +/** Eligibility requires admitted human work and a failed settlement in the last request step. */ +export const continuationProjectionDefinition = { + key: 'conversationContinuation', + stateVersion: 4, + stateSchema, + init: (): ContinuationState => EMPTY, + apply: (state, event) => { + switch (event.type) { + case 'turn/start': + return EMPTY + case 'step/start': + case 'assistant/message': + return state.failedAttempt ? { ...state, failedAttempt: false } : state + case 'user/message': + return !state.admitted && event.surfaceOp === 'append' + && ((event.data.source.kind === 'user' && event.data.content.length > 0) + || (event.data.source.kind === 'retry' && event.data.content.length === 0)) + ? { ...state, admitted: true } : state + case 'assistant/attempt': + return state.failedAttempt ? state : { ...state, failedAttempt: true } + case 'turn/end': { + const ending = event.data.reason.kind === 'error' && CONTINUABLE_FAILURES.has(event.data.reason.error.code) + && state.admitted && state.failedAttempt ? event.seq : null + return ending === null ? EMPTY : { ...EMPTY, ending } + } + default: + return state + } + }, + wire: { + viewSchema: endingSchema, + view: (state: ContinuationState) => state.ending, + }, +} satisfies ProjectionDefinition<'conversationContinuation', ContinuationState> diff --git a/packages/api/session-controller/src/index.ts b/packages/api/session-controller/src/index.ts index 8e81986f0b..6303340cd8 100644 --- a/packages/api/session-controller/src/index.ts +++ b/packages/api/session-controller/src/index.ts @@ -209,7 +209,10 @@ export class SessionController extends TypertRemoteService { this.stateController = new StateController(ctx, this.historyController) this.webController = new WebController(ctx, this.historyController, (observation) => { this.promote(observation) }) this.listState = new ApiSessionList(ctx, this.listWorkSliceMs) + await this.commands.initialize() + ctx.fiber.assertActive() await this.listState.initialize() + ctx.fiber.assertActive() ctx.plugin(SessionFileReferences) ctx.plugin(SessionMediaReferences) ctx.plugin(SessionSkillCatalog) @@ -464,7 +467,7 @@ export class SessionController extends TypertRemoteService { @Remote('prompt') async prompt(request: SessionPromptRequest, signal: AbortSignal): Promise { signal.throwIfAborted() - if (!hasPromptContent(request.content)) { + if (request.content.length > 0 && !hasPromptContent(request.content)) { throw new RemoteError('gateway/bad-request', 'prompt content must include non-whitespace text or an attachment', {}) } const clientTimeZone = request.clientTimeZone === undefined @@ -480,7 +483,7 @@ export class SessionController extends TypertRemoteService { // The caller is recorded only when it is not the owner, so owner messages keep their exact source. const principal = principalOf(this.ctx.invocation) const source: MessageSource = { - kind: 'user', + kind: request.content.length === 0 ? 'retry' : 'user', rpcId: request.requestId, ...(clientTimeZone === undefined ? {} : { clientTimeZone }), ...(principal === undefined ? {} : { principal }), diff --git a/packages/api/session-controller/src/types.ts b/packages/api/session-controller/src/types.ts index 1d846d4c9a..49cd7c0f9d 100644 --- a/packages/api/session-controller/src/types.ts +++ b/packages/api/session-controller/src/types.ts @@ -8,7 +8,7 @@ import type { import type { Branded } from '@deepseek-ai/dsh-brand' import type { LlmAttemptId, MessageId } from '@deepseek-ai/dsh-llm/brand' import type { LlmModelBadge, TextBlock } from '@deepseek-ai/dsh-llm' -import type { SessionId, SessionSeqCursor } from '@deepseek-ai/dsh-session/types' +import type { SessionId, SessionSeq, SessionSeqCursor } from '@deepseek-ai/dsh-session/types' import type { SessionProjectionMap, SessionProjectionSummaryExcluded, SessionProjectionSummaryValues } from '@deepseek-ai/dsh-session-projection/types' import type { Principal } from '@deepseek-ai/dsh-typert-protocol' import type { JsonValue } from '@deepseek-ai/dsh-util-values' @@ -16,6 +16,8 @@ import type { WorkspaceId } from '@deepseek-ai/dsh-workspace/types' declare module '@deepseek-ai/dsh-session-projection/types' { interface SessionProjectionMap { + /** Eligible latest failed turn/end for an empty prompt, or null. */ + conversationContinuation: SessionSeq | null /** Persisted facts used to summarize a Session without activating it. */ sessionListMetadata: SessionListMetadata /** @@ -320,11 +322,11 @@ export interface SessionForkValue { /** Session prompt request. */ export interface SessionPromptRequest { - /** Client-minted identity persisted on the exact accepted user message. */ + /** Client-minted identity persisted on the accepted inbox input, including empty continuation. */ readonly requestId: SessionRequestId readonly sessionId: SessionId readonly mode: 'queue' | 'steer' - /** At least one non-whitespace text part or attachment. */ + /** Non-whitespace text or attachments; an empty array continues an eligible failed idle Session. */ readonly content: readonly PromptContentPart[] readonly clientTimeZone?: string } @@ -396,6 +398,8 @@ declare module '@deepseek-ai/dsh-llm' { * caller other than the owner, so an absent `principal` means the owner. */ 'user-rpc': { kind: 'user'; rpcId: SessionRequestId; clientTimeZone?: string; principal?: Principal } + /** Empty retry user message with browser prompt correlation and caller metadata. */ + 'retry-rpc': { kind: 'retry'; rpcId: SessionRequestId; clientTimeZone?: string; principal?: Principal } } } diff --git a/packages/api/session-controller/tests/continuation.host.spec.ts b/packages/api/session-controller/tests/continuation.host.spec.ts new file mode 100644 index 0000000000..e7d339761d --- /dev/null +++ b/packages/api/session-controller/tests/continuation.host.spec.ts @@ -0,0 +1,162 @@ +/** Complete-log continuation projection, including recovery and publication. */ +import { Context } from '@deepseek-ai/cordis' +import SessionStore, { SessionId, SessionSeq, SessionLogOffset } from '@deepseek-ai/dsh-session' +import SessionProjectionRegistry from '@deepseek-ai/dsh-session-projection' +import { createAssistantMessage, createUserMessage } from '@deepseek-ai/dsh-llm' +import type { SessionEvent, TurnEndReason } from '@deepseek-ai/dsh-session/types' +import { expect, it, onTestFinished, vi } from 'vitest' + +import { continuationProjectionDefinition as definition } from '../src/continuation.ts' +import { paginate } from '../src/history.ts' +import { continuationTurn as turn } from '../../../client/ui-conversation/tests/continuation-fixture.ts' + +const failed = (code: string): TurnEndReason => ({ kind: 'error', error: { code, message: code } }) +function fold(events: readonly SessionEvent[]) { + return events.reduce((state, event) => definition.apply(state, event), definition.init()) +} +const events = (reason: TurnEndReason) => turn(reason).map(entry => entry.event) + +it.each(['RATE_LIMIT', 'SERVER', 'TIMEOUT', 'TRANSPORT', 'EMPTY_RESPONSE', 'STREAM_CLOSED'])( + 'offers a manual new turn after %s independently of automatic retries', (code) => { + expect(definition.wire.view(fold(events(failed(code))))).toBe(5) + }, +) +it.each(['AUTH', 'QUOTA', 'ACCOUNT_QUOTA', 'MISSING_CREDENTIAL', 'INVALID_CREDENTIAL', 'UNKNOWN_MODEL', + 'INVALID_REQUEST', 'CONTEXT_WINDOW_EXCEEDED', 'TOOL_ACTIVATION_FAILED', 'MALFORMED_RESPONSE', 'PI_AI_ERROR', 'UNKNOWN'])( + 'leaves %s to its own recovery action', (code) => { + expect(definition.wire.view(fold(events(failed(code))))).toBeNull() + }, +) +it.each([ + { kind: 'completed' }, { kind: 'max-tokens' }, { kind: 'blocked' }, + { kind: 'interrupted' }, { kind: 'forked' }, { kind: 'aborted', reason: { kind: 'user' } }, +])('leaves a $kind turn unchanged', (reason) => { + expect(definition.wire.view(fold(events(reason)))).toBeNull() +}) + +it('requires admitted human input and a failed settlement in the last step', () => { + const base = events(failed('TIMEOUT')) + expect(fold(base.filter(event => event.type !== 'user/message')).ending).toBeNull() + expect(fold(base.filter(event => event.type !== 'assistant/attempt')).ending).toBeNull() + const user = base.find(event => event.type === 'user/message')! + const replacement: SessionEvent<'user/message'> = { ...user, + surfaceOp: { op: 'replace', startSeq: SessionSeq(0), endSeq: SessionSeq(1) }, + } + expect(fold(base.map(event => event === user ? replacement : event)).ending).toBeNull() + const injected: SessionEvent<'user/message'> = { ...user, data: createUserMessage({ + content: [{ type: 'text', text: 'mode context' }], source: { kind: 'user-approval' }, + }) } + expect(fold(base.map(event => event === user ? injected : event)).ending).toBeNull() + const prefix = base.slice(0, -1) + const step: SessionEvent<'step/start'> = { type: 'step/start', seq: SessionSeq(5), time: 0, data: { turn: 1, step: 2 } } + expect(fold([...prefix, step, base.at(-1)!]).ending).toBeNull() + const success: SessionEvent<'assistant/message'> = { type: 'assistant/message', seq: SessionSeq(5), time: 0, + surfaceOp: 'append', data: { turn: 1, step: 1, stream: [], message: createAssistantMessage({ + content: [{ type: 'text', text: 'done' }], source: { provider: 'test', model: 'test' }, + }) }, + } + expect(fold([...prefix, success, base.at(-1)!]).ending).toBeNull() +}) + +it('keeps unrelated events and repeated settlements reference-stable', () => { + const base = events(failed('SERVER')) + const state = fold(base.slice(0, -1)) + expect(definition.apply(state, base[2]!)).toBe(state) + expect(definition.apply(state, base[3]!)).toBe(state) + expect(definition.apply(state, base[4]!)).toBe(state) + expect(definition.apply(definition.init(), base[1]!)).toBe(definition.init()) + const reset = definition.apply(state, base[1]!) + expect(reset.failedAttempt).toBe(false) +}) + +it('restores a checkpoint plus suffix identically to full replay and retires on a new turn', () => { + const base = events(failed('SERVER')) + const prefix = fold(base.slice(0, 3)) + const restored = definition.stateSchema.parse(JSON.parse(JSON.stringify(prefix))) + expect(base.slice(3).reduce((state, event) => definition.apply(state, event), restored)).toEqual(fold(base)) + const ended = fold(base) + expect(definition.apply(ended, { type: 'turn/start', seq: SessionSeq(6), time: 1, data: { turn: 2 } }).ending).toBeNull() + expect(definition.wire.viewSchema.parse(ended.ending)).toBe(5) + expect(() => definition.stateSchema.parse({ ...ended, ending: -1 })).toThrow() + expect(() => definition.wire.viewSchema.parse('5')).toThrow() +}) + +it('publishes a complete-log result independently of the visible page and releases registration', async () => { + const ctx = new Context() + onTestFinished(() => ctx.fiber.dispose()) + await ctx.plugin(SessionStore) + await ctx.plugin(SessionProjectionRegistry) + const fiber = await ctx.sessionProjections.register(definition) + const session = ctx.sessions.create(SessionId('continued')) + expect(ctx.sessionProjections.snapshot(session).values.conversationContinuation).toBeNull() + const history: SessionEvent[] = [] + ctx.on('session/event', (_session, event) => { history.push(event) }) + const changed = vi.fn[0]>() + ctx.sessionProjections.onChanged(changed) + session.append('turn/start', { turn: 1 }) + expect(changed).not.toHaveBeenCalled() + session.append('step/start', { turn: 1, step: 1 }) + session.append('user/message', createUserMessage({ content: [{ type: 'text', text: 'task' }], source: { kind: 'user' } }), { surfaceOp: 'append' }) + // A long failed turn exceeds the browser's 500-message page budget. + for (let index = 0; index < 600; index++) { + session.append('assistant/message', { turn: 1, step: index + 1, stream: [], message: createAssistantMessage({ content: [{ type: 'text', text: 'progress' }], source: { provider: 'test', model: 'test' } }) }, { surfaceOp: 'append' }) + session.append('step/end', { turn: 1, step: index + 1 }) + session.append('step/start', { turn: 1, step: index + 2 }) + } + session.append('assistant/attempt', { turn: 1, step: 601, stream: [] }) + const ending = session.append('turn/end', { turn: 1, reason: failed('SERVER') }).seq + const page = paginate(history, undefined, 500, ending, { minMessages: 50, minTurns: 2 }) + expect(page.hasMore).toBe(true) + expect(page.events.some(event => event.type === 'turn/start')).toBe(false) + expect(ctx.sessionProjections.snapshot(session).values.conversationContinuation).toBe(ending) + expect(changed.mock.calls.map(([, key, value]) => [key, value])).toEqual([['conversationContinuation', null], ['conversationContinuation', ending]]) + expect(ctx.sessionProjections.checkpoint(session).conversationContinuation) + .toEqual({ ver: 4, seq: ending, val: { admitted: false, failedAttempt: false, ending } }) + session.append('turn/start', { turn: 2 }) + expect(ctx.sessionProjections.snapshot(session).values.conversationContinuation).toBeNull() + expect(changed).toHaveBeenCalledTimes(3) + await fiber.dispose() + expect(ctx.sessionProjections.snapshot(session).values).not.toHaveProperty('conversationContinuation') +}) + +it('restores valid, absent and outdated checkpoints through the registry', async () => { + const ctx = new Context() + onTestFinished(() => ctx.fiber.dispose()) + await ctx.plugin(SessionStore) + await ctx.plugin(SessionProjectionRegistry) + await ctx.sessionProjections.register(definition) + const session = ctx.sessions.create(SessionId('restored')) + const log = events(failed('SERVER')) + const checkpoint = { conversationContinuation: { ver: 4, seq: SessionSeq(2), val: fold(log.slice(0, 3)) } } + const restore = (rows: typeof checkpoint | Record, tail: readonly SessionEvent[], base: number) => + ctx.sessionProjections.restore(rows, tail, SessionLogOffset(base), session.header, session.inheritedEventCount) + expect(restore(checkpoint, log.slice(3), 3).snapshot.values.conversationContinuation).toBe(5) + expect(restore({}, log, 0).snapshot.values.conversationContinuation).toBe(5) + const outdated = { conversationContinuation: { ...checkpoint.conversationContinuation, ver: 3 } } + expect(restore(outdated, log, 0).snapshot.values.conversationContinuation).toBe(5) + expect(() => restore(outdated, log.slice(3), 3)).toThrow('re-read from seq 0') + expect(() => restore({}, log.slice(3), 3)).toThrow('re-read from seq 0') +}) + +it('admits empty retry messages while ignoring empty ordinary and non-empty retry messages', () => { + const base = events(failed('SERVER')) + const input = base.find(event => event.type === 'user/message')! + const empty: SessionEvent<'user/message'> = { ...input, type: 'user/message', data: createUserMessage({ + content: [], source: { kind: 'user' }, + }) } + expect(fold(base.map(event => event === input ? empty : event)).ending).toBeNull() + const retry: SessionEvent<'user/message'> = { ...empty, data: createUserMessage({ + content: [], source: { kind: 'retry', rpcId: 'retry' as import('../src/types.ts').SessionRequestId }, + }) } + const nonEmpty: SessionEvent<'user/message'> = { ...retry, data: { ...retry.data, + content: [{ type: 'text', text: 'not an empty retry' }], + } } + expect(fold(base.map(event => event === input ? nonEmpty : event)).ending).toBeNull() + const replacement: SessionEvent<'user/message'> = { ...retry, + surfaceOp: { op: 'replace', startSeq: SessionSeq(0), endSeq: SessionSeq(1) }, + } + expect(fold(base.map(event => event === input ? replacement : event)).ending).toBeNull() + expect(fold(base.map(event => event === input ? retry : event)).ending).toBe(5) + const admitted = definition.apply(definition.init(), retry) + expect(definition.apply(admitted, retry)).toBe(admitted) +}) diff --git a/packages/api/session-controller/tests/empty-prompt.host.spec.ts b/packages/api/session-controller/tests/empty-prompt.host.spec.ts new file mode 100644 index 0000000000..778b3fdee5 --- /dev/null +++ b/packages/api/session-controller/tests/empty-prompt.host.spec.ts @@ -0,0 +1,123 @@ +/** Empty prompt admission over the real AgentLoop and the Session Remote owner. */ +import { Context } from '@deepseek-ai/cordis' +import AgentLoop from '@deepseek-ai/dsh-agent-loop' +import { mountAgentLoopTestDependencies } from '@deepseek-ai/dsh-agent-loop-testkit' +import { createUserMessage, LlmError } from '@deepseek-ai/dsh-llm' +import { SessionId } from '@deepseek-ai/dsh-session' +import { expect, it, onTestFinished } from 'vitest' +import { MockAdapter, textResponse } from '../../../core/agent-loop/tests/mock-adapter.ts' +import type { SessionPromptRequest, SessionRequestId } from '../src/types.ts' +import { createSessionTestRemote } from './test-remote.ts' + +async function setup() { + const ctx = new Context() + onTestFinished(() => ctx.fiber.dispose()) + await mountAgentLoopTestDependencies(ctx) + await ctx.plugin(AgentLoop, { agents: [] }) + const fail = (): never => { throw new LlmError('busy', 'SERVER') } + const adapter = new MockAdapter([fail, fail, textResponse('done')]) + ctx.effect(() => ctx.llm.registerAdapter(['mock'], adapter)) + const remote = await createSessionTestRemote(ctx, { defaultModelSelection: () => ({ provider: 'mock', model: 'mock' }), cwd: '/workspace' }) + const agent = await ctx.agentLoop.create(SessionId('empty-prompt'), { provider: 'mock', model: 'mock' }) + const request = (id: string, mode: SessionPromptRequest['mode'] = 'queue'): SessionPromptRequest => ({ + sessionId: agent.id, requestId: id as SessionRequestId, content: [], mode, + }) + return { ctx, remote, agent, adapter, request } +} + +it('records empty retry user messages without duplicate requests', async () => { + const { remote, agent, adapter, request } = await setup() + agent.followup(createUserMessage({ content: [{ type: 'text', text: 'original task' }], source: { kind: 'user' } })) + await agent.whenIdle() + const first = request('continue-1') + expect((await remote.prompt(first)).ok).toBe(true) + await agent.whenIdle() + expect(adapter.requests).toHaveLength(2) + expect((await remote.prompt(first)).ok).toBe(true) + await agent.whenIdle() + expect(adapter.requests).toHaveLength(2) + expect((await remote.prompt(request('continue-2'))).ok).toBe(true) + await agent.whenIdle() + expect(adapter.requests).toHaveLength(3) + const events = agent.session.snapshotEvents() + const messages = events.flatMap(event => event.type === 'user/message' && event.data.source.kind === 'user' ? [event.data] : []) + expect(messages).toHaveLength(1) + const retries = events.flatMap(event => event.type === 'user/message' && event.data.source.kind === 'retry' ? [event.data] : []) + expect(retries).toHaveLength(2) + expect(retries).toMatchObject([ + { content: [], source: { kind: 'retry', rpcId: 'continue-1' } }, + { content: [], source: { kind: 'retry', rpcId: 'continue-2' } }, + ]) + const controls = events.flatMap(event => event.type === 'agent/inbox/spliced' ? event.data.inserted : []) + .filter(message => message.source.kind === 'retry') + expect(retries.map(retry => retry.id)).toEqual(controls.map(control => control.id)) + expect(adapter.requests[1]!.messages.filter(message => message.role === 'user').map(message => message.content)) + .toEqual([[{ type: 'text', text: 'original task' }], []]) + expect(adapter.requests[2]!.messages.filter(message => message.role === 'user').map(message => message.content)) + .toEqual([[{ type: 'text', text: 'original task' }], [], []]) + expect(events.flatMap(event => event.type === 'turn/end' ? [event.data.reason.kind] : [])).toEqual(['error', 'error', 'completed']) + expect(events.filter(event => event.type === 'turn/start')).toHaveLength(3) + expect((await remote.prompt(request('after-completion'))).ok).toBe(false) +}) + +it('refuses empty fresh sessions, steering, queued human input and maintenance without waking work', async () => { + const { remote, agent, adapter, request } = await setup() + expect((await remote.prompt(request('empty-fresh'))).ok).toBe(false) + expect(adapter.requests).toHaveLength(0) + agent.followup(createUserMessage({ content: [{ type: 'text', text: 'original task' }], source: { kind: 'user' } })) + await agent.whenIdle() + expect((await remote.prompt(request('empty-steer', 'steer'))).ok).toBe(false) + const pending = createUserMessage({ content: [{ type: 'text', text: 'queued' }], source: { kind: 'user' } }) + agent.inbox.append('next-turn', pending) + expect((await remote.prompt(request('empty-queued'))).ok).toBe(false) + agent.inbox.clear() + agent.inject(pending) + expect((await remote.prompt(request('empty-steering'))).ok).toBe(false) + agent.inbox.clear() + await agent.runMaintenance(async () => { + expect((await remote.prompt(request('empty-maintenance'))).ok).toBe(false) + }) + expect(adapter.requests).toHaveLength(1) +}) + +it('consumes injected context with the empty prompt', async () => { + const { ctx, remote, agent, adapter, request } = await setup() + agent.followup(createUserMessage({ content: [{ type: 'text', text: 'original task' }], source: { kind: 'user' } })) + await agent.whenIdle() + agent.inject(createUserMessage({ content: [{ type: 'text', text: 'approval context' }], source: { kind: 'user-approval' } })) + agent.model.select({ provider: 'mock', model: 'changed' }) + expect((await remote.prompt(request('empty-context'))).ok).toBe(true) + await agent.whenIdle() + expect(adapter.requests).toHaveLength(2) + expect(JSON.stringify(adapter.requests[1]!.messages)).toContain('approval context') + expect(adapter.requests[1]!.model).toBe('changed') + expect(agent.inbox.nextStep).toHaveLength(0) + expect(ctx.sessionProjections.snapshot(agent.session).values.conversationContinuation).not.toBeNull() +}) + +it('deduplicates empty continuation after claim and before user-message admission', async () => { + const { ctx, remote, agent, adapter, request } = await setup() + agent.followup(createUserMessage({ content: [{ type: 'text', text: 'original task' }], source: { kind: 'user' } })) + await agent.whenIdle() + const claimed = Promise.withResolvers() + const release = Promise.withResolvers() + onTestFinished(() => { release.resolve(undefined) }) + ctx.on('agent/pre-step', async ({ messages }, next) => { + if (messages.some(message => message.source.kind === 'retry')) { + claimed.resolve(undefined) + await release.promise + } + return next() + }) + const continuation = request('continue-once') + expect((await remote.prompt(continuation)).ok).toBe(true) + await claimed.promise + expect(agent.inbox.nextTurn).toEqual([]) + expect(agent.session.snapshotEvents().some(event => event.type === 'user/message' && event.data.source.kind === 'retry')).toBe(false) + expect((await remote.prompt(continuation)).ok).toBe(true) + release.resolve(undefined) + await agent.whenIdle() + expect(adapter.requests).toHaveLength(2) + expect(agent.session.snapshotEvents().flatMap(event => event.type === 'agent/inbox/spliced' ? event.data.inserted : []) + .filter(message => message.source.kind === 'retry')).toHaveLength(1) +}) diff --git a/packages/api/session-controller/tests/session-cold.host.spec.ts b/packages/api/session-controller/tests/session-cold.host.spec.ts index 49e0b3210d..3bdf40c59b 100644 --- a/packages/api/session-controller/tests/session-cold.host.spec.ts +++ b/packages/api/session-controller/tests/session-cold.host.spec.ts @@ -875,7 +875,7 @@ async function modelFor(ctx: Context, session: Session): Promise { } describe('sessions.prompt synchronous rejection', () => { - it('rejects content without non-whitespace text or an attachment before delivery or Session events', async () => { + it('rejects whitespace-only text parts before delivery or Session events', async () => { const ctx = new Context() await ctx.plugin(SessionStore) await ctx.plugin(SessionProjectionRegistry) @@ -925,7 +925,6 @@ describe('sessions.prompt synchronous rejection', () => { }) const initialEvents = session.snapshotEvents() const rejectedContent: readonly SessionPromptRequest['content'][] = [ - [], [{ type: 'text', text: '' }], [{ type: 'text', text: ' \t\n' }, { type: 'text', text: '' }], ] diff --git a/packages/api/session-controller/tests/session-projections.host.spec.ts b/packages/api/session-controller/tests/session-projections.host.spec.ts index fe8fc245c2..aa4ae6a702 100644 --- a/packages/api/session-controller/tests/session-projections.host.spec.ts +++ b/packages/api/session-controller/tests/session-projections.host.spec.ts @@ -417,11 +417,16 @@ describe('session.history projections block', () => { .toBe(false) seedMessages(session, 1) - const changed = await iterator.next() - expect(changed).toMatchObject({ - done: false, - value: { type: 'projection', changes: [{ key: 'sessionListMetadata' }] }, - }) + let changed = await iterator.next() + while (!changed.done && changed.value.type === 'projection' + && !changed.value.changes.some(change => change.key === 'sessionListMetadata')) { + expect(changed.value.changes.map(change => change.key)).not.toContain('test/internal-count') + changed = await iterator.next() + } + if (changed.done || changed.value.type !== 'projection') throw new Error('control stream ended before its projection') + const keys = changed.value.changes.map(change => change.key) + expect(keys).toContain('sessionListMetadata') + expect(keys).not.toContain('test/internal-count') abort.abort() await iterator.return?.() @@ -527,7 +532,7 @@ describe('session.list projections column', () => { expect(excludedApply).not.toHaveBeenCalled() }) - it('carries every registered summary key, which is only its own list metadata when no other unit is registered', async () => { + it('carries list metadata and unavailable retry eligibility through registered summary keys', async () => { const { ctx, session } = await harness(false) seedMessages(session, 1) const response = await (await remote(ctx)).list(request({})) @@ -535,7 +540,8 @@ describe('session.list projections column', () => { const row = response.value.items.find(item => item.sessionId === session.id) expect(row?.projections?.kind).toBe('sequenced') expect(Object.keys(row?.projections?.values ?? {})).toEqual([...ctx.sessionProjections.summaryKeys()]) - expect(Object.keys(row?.projections?.values ?? {})).toEqual(['sessionListMetadata']) + expect(Object.keys(row?.projections?.values ?? {})).toEqual(['conversationContinuation', 'sessionListMetadata']) + expect(row?.projections?.values.conversationContinuation).toBeNull() }) it('serves the summary projection hints from the cache with zero log loads', async () => { @@ -754,11 +760,12 @@ describe('Session control projection frames', () => { iterable: AsyncIterable, count: number, abort: AbortController, + keys: readonly string[], ): Promise { const frames: SessionControlFrame[] = [] for await (const frame of iterable) { frames.push(frame) - if (frames.filter(candidate => candidate.type === 'projection').length >= count) abort.abort() + if (frames.filter(candidate => candidate.type === 'projection' && candidate.changes.some(change => keys.includes(change.key))).length >= count) abort.abort() } return frames } @@ -772,7 +779,7 @@ describe('Session control projection frames', () => { await new Promise(resolve => setTimeout(resolve, 0)) const abort = new AbortController() const stream = proxy.control(abort.signal) - const collected = collect(stream, 3, abort) + const collected = collect(stream, 3, abort, ['test/last-user', 'sessionListMetadata']) const now = vi.spyOn(Date, 'now').mockReturnValue(100) seedMessages(session, 1) @@ -789,6 +796,7 @@ describe('Session control projection frames', () => { { type: 'projection', sessionId: session.id, seq: 0, changes: [ { key: 'test/last-user', val: { text: 'm0' } }, + { key: 'conversationContinuation', val: null }, { key: 'sessionListMetadata', val: { blank: true, lastPromptAt: 100 } }, ], }, @@ -829,6 +837,7 @@ describe('Session control projection frames', () => { value: { type: 'projection', seq: 0, changes: [ { key: 'test/last-user', val: { text: 'm0' } }, + { key: 'conversationContinuation', val: null }, { key: 'sessionListMetadata', val: { blank: true, lastPromptAt: 100 } }, ], }, diff --git a/packages/api/session-controller/tests/sessions-service.client.spec.ts b/packages/api/session-controller/tests/sessions-service.client.spec.ts index 4301be69d6..cf3a6b94cb 100644 --- a/packages/api/session-controller/tests/sessions-service.client.spec.ts +++ b/packages/api/session-controller/tests/sessions-service.client.spec.ts @@ -1010,6 +1010,29 @@ describe('fork', () => { }) }) + it('gives repeated forks distinct titles past numbers listed sessions use', async ({ bench }) => { + const b = bench() + for (const [id, value] of [['source', 'Roadmap'], ['sibling', 'Roadmap (2)']] as const) { + b.svc.handleControlFrame({ type: 'projection', sessionId: sid(id), changes: [{ key: 'title', val: value }], seq: 2 }) + } + await feedList(b, [{ id: 'source' }, { id: 'sibling' }]) + b.mock.remote.session.rename.mockImplementation((payload) => { + const { title } = payload as { title: string } + return Promise.resolve(ok({ title, seq: 3 })) + }) + + for (const child of ['child-1', 'child-2']) { + b.mock.remote.session.fork.mockResolvedValueOnce(ok({ sessionId: sid(child) })) + await b.svc.fork({ sessionId: sid('source'), increaseTitle: true }) + } + + expect(b.mock.remote.session.rename.mock.calls).toEqual([ + [{ sessionId: 'child-1', title: 'Roadmap (1)' }], + [{ sessionId: 'child-2', title: 'Roadmap (3)' }], + ]) + expect(b.svc.list.getSnapshot().byId[sid('child-2')]?.title).toBe('Roadmap (3)') + }) + it('sends the exact boundary seq verbatim: callers pass real event seqs', async ({ bench }) => { const b = bench() await feedList(b, [{ id: 'source', cwd: '/work' }]) diff --git a/packages/api/session-controller/tsconfig.host.json b/packages/api/session-controller/tsconfig.host.json index acadf82099..168fd5a0c7 100644 --- a/packages/api/session-controller/tsconfig.host.json +++ b/packages/api/session-controller/tsconfig.host.json @@ -25,7 +25,8 @@ "src/list.ts", "src/media-references.ts", "src/archived-session-gate.ts", - "src/skill-catalog.ts" + "src/skill-catalog.ts", + "src/continuation.ts" ], "references": [ { @@ -126,6 +127,9 @@ }, { "path": "../../session/working-directory" + }, + { + "path": "../../util/brand" } ] } diff --git a/packages/bundle/base/README.i18n.yaml b/packages/bundle/base/README.i18n.yaml index 8c6ebd500c..b475ce9b82 100644 --- a/packages/bundle/base/README.i18n.yaml +++ b/packages/bundle/base/README.i18n.yaml @@ -21,8 +21,8 @@ en: 0f971f7ac7c09139 zh: ceb866da681c709c /deepseek-ai-dsh-base/use-this-package/what-you-get: - en: 94430c891006526d - zh: 94ba771960ec6f71 + en: ab2fb279cdd726c5 + zh: ae84c61bddc00ddf /deepseek-ai-dsh-base/use-this-package/shell-tools-per-platform: en: 2dce12f82d6ee955 zh: d4599eb899a3cd88 diff --git a/packages/bundle/base/README.md b/packages/bundle/base/README.md index db77c345ec..5b5f163694 100644 --- a/packages/bundle/base/README.md +++ b/packages/bundle/base/README.md @@ -49,7 +49,7 @@ Run `dsh --profile my-profile "your task"` and you get a working agent with mode Out of the box, every profile built on this core provides: a DeepSeek model connection (the provider and model are configurable, and you can enable extra providers from your settings), the full tool set — file editing, shell commands, web search, HTTP(S) fetch, subagents, task and goal tracking — durable sessions that survive restarts, and the default permission policy that confines file writes to your workspace and asks before risky actions. Web fetch runs without per-call approval and can reach loopback and private-network hosts. Feedback stays in the Session log. [OTel session upload](../../session/session-telemetry-otel/README.md) defaults to `FEEDBACK_ONLY` for all users, including `deepseek-official`: new text feedback, message ratings, edits, and withdrawals release the complete canonical prefix through that event, including context. Later records wait for the next explicit feedback; sending an authorized batch needs no further interaction or model call. `DISABLED` prevents OTel capture. The default-on [DeepSeek session-log contributor](../../session/session-log-deepseek/README.md) remains a separate request path. -Both `subagent` and `subagent_fork` create managed children and return a child id immediately. Use `send_message` to steer active children or continue their conversations after completion. [Delegation-tool behavior](../../subagent/tool-subagent/README.md) describes result delivery and backend capabilities. +Both `subagent` and `subagent_fork` create managed children and return the child's name immediately. Use `send_message` to steer active children or continue their conversations after completion. [Delegation-tool behavior](../../subagent/tool-subagent/README.md) describes result delivery and backend capabilities. The bundle also mounts [Agent Teams](../../team/agent-team/README.md) and its task tools. Team mode defaults off per root Session; the root conversation’s **Use Agent Teams** menu switch enables collaboration for that tree without changing the profile. diff --git a/packages/bundle/base/README.zh.md b/packages/bundle/base/README.zh.md index 53c04f4b52..62d6ad03b9 100644 --- a/packages/bundle/base/README.zh.md +++ b/packages/bundle/base/README.zh.md @@ -49,7 +49,7 @@ kind: "package-bundle" 开箱即用,基于本核心构建的每个 profile 都提供:DeepSeek 模型连接(提供方与模型可配置,你还可以在设置中启用额外提供方)、完整工具集——文件编辑、shell 命令、web 搜索、HTTP(S) 抓取、subagent、任务与目标跟踪——可跨重启存活的持久会话,以及默认权限策略:把文件写入限制在工作区内,危险操作前征询许可。Web 抓取无需逐次审批,并且可以访问 loopback 与内网主机。反馈保存在会话日志中。[OTel 会话上传](../../session/session-telemetry-otel/README.zh.md)对所有用户默认使用 `FEEDBACK_ONLY`,包括 `deepseek-official`:新的文本反馈、消息评分、编辑与撤回会释放截至该事件的完整规范会话日志前缀,包含上下文。后续记录等待下一次显式反馈;发送已授权批次无需进一步交互或模型调用。`DISABLED` 阻止 OTel 捕获。默认开启的 [DeepSeek 会话日志贡献器](../../session/session-log-deepseek/README.zh.md)仍是独立的请求路径。 -`subagent` 与 `subagent_fork` 都创建受管理的子任务,并立即返回 child id。使用 `send_message` 可引导活跃子任务,或在完成后继续其对话。[委派工具行为](../../subagent/tool-subagent/README.zh.md)说明了结果交付和后端能力。 +`subagent` 与 `subagent_fork` 都创建受管理的子任务,并立即返回子任务名称。使用 `send_message` 可引导活跃子任务,或在完成后继续其对话。[委派工具行为](../../subagent/tool-subagent/README.zh.md)说明了结果交付和后端能力。 此 bundle 还挂载 [Agent Teams](../../team/agent-team/README.zh.md) 及其任务工具。每个根 Session 的 Team 模式默认关闭;根会话菜单中的**使用智能体团队**开关为当前树开启协作,无需修改 profile。 diff --git a/packages/client/tsdown.client.ts b/packages/client/tsdown.client.ts index 5eaf0b2a35..8895b1dce9 100644 --- a/packages/client/tsdown.client.ts +++ b/packages/client/tsdown.client.ts @@ -82,7 +82,7 @@ function styleInjectionModule( * Everything else under @deepseek-ai/* is either a module-table entry * (external) or a leak the purity gate rejects. */ -export const INLINE_SAFE = /^(?:@deepseek-ai\/dsh-(?:file-reference|session|llm|tools|brand|official-bundles|deque|output-retention|typert-protocol|util-crypto|util-time|util-values|util-workspace-path)(?:\/|$)|@deepseek-ai\/dsh-util-file-drag$|@deepseek-ai\/dsh-token-meter\/client$|@deepseek-ai\/dsh-commands\/builtin$|@deepseek-ai\/dsh-native-command\/types$|@deepseek-ai\/dsh-host-open-in-app\/shared$|@deepseek-ai\/dsh-plugin-manager\/registry$|@deepseek-ai\/dsh-agent-preset-registry\/display$|@deepseek-ai\/dsh-api-workspace-controller\/default-workspace$|@deepseek-ai\/dsh-spill-policy\/notice$)/ +export const INLINE_SAFE = /^(?:@deepseek-ai\/dsh-(?:file-reference|fs-patch|session|llm|tools|brand|official-bundles|deque|output-retention|typert-protocol|util-crypto|util-time|util-values|util-workspace-path)(?:\/|$)|@deepseek-ai\/dsh-util-file-drag$|@deepseek-ai\/dsh-token-meter\/client$|@deepseek-ai\/dsh-commands\/builtin$|@deepseek-ai\/dsh-native-command\/types$|@deepseek-ai\/dsh-host-open-in-app\/shared$|@deepseek-ai\/dsh-plugin-manager\/registry$|@deepseek-ai\/dsh-agent-preset-registry\/display$|@deepseek-ai\/dsh-api-workspace-controller\/default-workspace$|@deepseek-ai\/dsh-spill-policy\/notice$)/ /** * Vendored framework libraries: rescoped into @deepseek-ai, so the gate below diff --git a/packages/client/ui-agent-team/README.i18n.yaml b/packages/client/ui-agent-team/README.i18n.yaml index dfab72bf26..3f894b097c 100644 --- a/packages/client/ui-agent-team/README.i18n.yaml +++ b/packages/client/ui-agent-team/README.i18n.yaml @@ -18,8 +18,8 @@ en: d502ab38773eef34 zh: e1f9c4edbc74c38f /deepseek-ai-dsh-client-ui-agent-team/use-this-package/inspect-the-task-board: - en: 7e88fb00a3abd230 - zh: 08efcf80afecb0c0 + en: 2f606827b3ab14bc + zh: 7f713d10268e7498 /deepseek-ai-dsh-client-ui-agent-team/understand-the-implementation: en: 9b0b6a8505a9ebbf zh: beb5d89f80463b3e diff --git a/packages/client/ui-agent-team/README.md b/packages/client/ui-agent-team/README.md index d156e7b7cb..7e87010dcb 100644 --- a/packages/client/ui-agent-team/README.md +++ b/packages/client/ui-agent-team/README.md @@ -37,7 +37,7 @@ The [Web bundle](../../bundle/web-app/README.md) loads this package by default. Ready pending tasks use idle, blocked pending tasks use warning, in-progress tasks use ongoing, and completed tasks use done. -The noncollapsible Shared tasks header uses a Checklist icon and completed, in-progress, and pending counts, with zero counts omitted and wording and separators matching the input task list. Compact read-only rows show the subject, status, and a chevron, with 13px primary titles and hover geometry aligned to subagent rows; expanded details use 12px text. Task rows use 7px vertical padding, 6px horizontal padding, and 7px gaps to align their clickable content with subagent rows. All task details start closed; opening one closes the previous task. Details show only the full description when present, followed by a single-line owner label and Session id in the same color with a 4px gap. Long owner ids are ellipsized and reveal their full text in a tooltip only when clipped. Task-text and owner tooltips appear after 500ms of hover. Every owner is identified by its Session id. The shared menu is 360px wide with 6px outer padding, constrained to fit the viewport. Shared tasks have a 4px top margin rather than a divider. Both section headers keep a 7px icon/title gap and an additional 4px before their counts. Only the menu scrolls; task lists and details have no nested scrolling. Agents mutate tasks through tools; the panel provides no mutation controls. A projection failure appears separately above any retained tasks and remains visible when no tasks exist. +The noncollapsible Shared tasks header uses a Checklist icon and completed, in-progress, and pending counts, with zero counts omitted and wording and separators matching the input task list. Compact read-only rows show the subject, status, and a chevron, with 13px primary titles and hover geometry aligned to subagent rows; expanded details use 12px text. Task rows use 7px vertical padding, 6px horizontal padding, and 7px gaps to align their clickable content with subagent rows. All task details start closed; opening one closes the previous task. Details show only the full description when present, followed by a single-line owner label and owner name in the same color with a 4px gap. Long owner names are ellipsized and reveal their full text in a tooltip only when clipped. Task-text and owner tooltips appear after 500ms of hover. Owners display the task's saved `ownerName`, such as `lead` or `reviewer/checker`, independently of loaded subagent catalogs. A task without `ownerName` displays its `ownerId`; a task without either field displays the localized unowned label. The shared menu is 360px wide with 6px outer padding, constrained to fit the viewport. Shared tasks have a 4px top margin rather than a divider. Both section headers keep a 7px icon/title gap and an additional 4px before their counts. Only the menu scrolls; task lists and details have no nested scrolling. Agents mutate tasks through tools; the panel provides no mutation controls. A projection failure appears separately above any retained tasks and remains visible when no tasks exist. ----- diff --git a/packages/client/ui-agent-team/README.zh.md b/packages/client/ui-agent-team/README.zh.md index 6a370c6eeb..c0db84fe78 100644 --- a/packages/client/ui-agent-team/README.zh.md +++ b/packages/client/ui-agent-team/README.zh.md @@ -37,7 +37,7 @@ Chat 隐藏历史 `/team on` 和 `/team off` 记录中尚未完成或执行成 可开始的 pending 任务使用 idle 灰点,被依赖阻塞的 pending 任务使用 warning 橙点,in-progress 任务使用 ongoing loading,completed 任务使用 done 绿点。 -不可折叠的“共享任务”标题使用 Checklist 图标,并显示已完成、进行中和待处理数量;省略零值,文案和分隔符与输入区任务列表一致。紧凑只读行显示主题、状态和展开箭头,13px 主标题与悬停区域对齐子智能体行;展开详情使用 12px 文字。任务行使用 7px 垂直内边距、6px 水平内边距和 7px 间距,使可点击内容与 subagent 行对齐。所有任务详情初始关闭,打开一项会关闭上一项。详情仅显示完整描述(如有),下方以单行显示负责人标签和 Session id,两者使用相同颜色,间距为 4px。过长的负责人 id以省略号截断,仅在被截断时通过工具提示显示完整内容。任务文字和负责人的工具提示在悬停 500ms 后显示。每个负责人均通过其 Session id 标识。共享菜单宽度为 360px,外层内边距为 6px,并受视口可用宽度约束。共享任务上方保留 4px 外边距,不显示分隔线。两个区域标题均保留 7px 图标与文字间距,并在统计数量前额外留出 4px。仅菜单本身滚动,任务列表与详情不单独滚动。Agent 通过工具修改任务;面板不提供修改控件。投影失败以独立警告显示在保留的任务上方,即使没有任务也保持可见。 +不可折叠的“共享任务”标题使用 Checklist 图标,并显示已完成、进行中和待处理数量;省略零值,文案和分隔符与输入区任务列表一致。紧凑只读行显示主题、状态和展开箭头,13px 主标题与悬停区域对齐子智能体行;展开详情使用 12px 文字。任务行使用 7px 垂直内边距、6px 水平内边距和 7px 间距,使可点击内容与 subagent 行对齐。所有任务详情初始关闭,打开一项会关闭上一项。详情仅显示完整描述(如有),下方以单行显示负责人标签和负责人名称,两者使用相同颜色,间距为 4px。过长的负责人名称以省略号截断,仅在被截断时通过工具提示显示完整内容。任务文字和负责人的工具提示在悬停 500ms 后显示。负责人显示任务保存的 `ownerName`,例如 `lead` 或 `reviewer/checker`,不依赖已加载的 subagent 目录。缺少 `ownerName` 时显示 `ownerId`;两个字段都没有时显示本地化的无负责人标签。共享菜单宽度为 360px,外层内边距为 6px,并受视口可用宽度约束。共享任务上方保留 4px 外边距,不显示分隔线。两个区域标题均保留 7px 图标与文字间距,并在统计数量前额外留出 4px。仅菜单本身滚动,任务列表与详情不单独滚动。Agent 通过工具修改任务;面板不提供修改控件。投影失败以独立警告显示在保留的任务上方,即使没有任务也保持可见。 ----- diff --git a/packages/client/ui-agent-team/src/client/TeamBoard.tsx b/packages/client/ui-agent-team/src/client/TeamBoard.tsx index dbc554d33c..d6d0538fa9 100644 --- a/packages/client/ui-agent-team/src/client/TeamBoard.tsx +++ b/packages/client/ui-agent-team/src/client/TeamBoard.tsx @@ -43,7 +43,7 @@ function TaskRow({ task, rootId, expanded, onToggle, t }: Pick void }) { - const owner = task.ownerId ?? t('unowned') + const owner = task.ownerName ?? task.ownerId ?? t('unowned') const blocked = task.status === 'pending' && !task.ready const detailsId = `team-task-${rootId}-${task.id}` return ( diff --git a/packages/client/ui-agent-team/tests/team-board.client.spec.tsx b/packages/client/ui-agent-team/tests/team-board.client.spec.tsx index b09aedc4e5..f60eb99e4a 100644 --- a/packages/client/ui-agent-team/tests/team-board.client.spec.tsx +++ b/packages/client/ui-agent-team/tests/team-board.client.spec.tsx @@ -30,6 +30,7 @@ const task: TeamTask = { description: 'Build the Team runtime', status: 'in_progress', ownerId: SESSION, + ownerName: 'lead', blockedBy: [], writeScopes: ['src'], ready: false, @@ -131,7 +132,7 @@ describe('TeamBoard', () => { const description = 'First line\n'.repeat(30) + 'Final description line' const b = bench({ value: { ...team, tasks: [ { ...task, subject: longSubject, description }, - { ...task, id: TASK_2, subject: 'Review implementation', ownerId: WORKER }, + { ...task, id: TASK_2, subject: 'Review implementation', ownerId: WORKER, ownerName: 'worker' }, ] } }) render() const first = row(longSubject) @@ -141,8 +142,8 @@ describe('TeamBoard', () => { const details = document.getElementById(first.getAttribute('aria-controls')!)! const owner = details.querySelector('[data-team-task-owner]')! expect(owner.tagName).toBe('P') - expect(owner.textContent).toBe(`${zh.owner}: ${SESSION}`) - expect(ownerValue()).toBe(SESSION) + expect(owner.textContent).toBe(`${zh.owner}: lead`) + expect(ownerValue()).toBe('lead') const paragraphs = details.querySelectorAll('p') expect(paragraphs).toHaveLength(2) expect(paragraphs[0]?.textContent).toBe(description) @@ -154,7 +155,7 @@ describe('TeamBoard', () => { expect(screen.getAllByRole('button')).toHaveLength(2) fireEvent.click(row('Review implementation')) expect(first.getAttribute('aria-expanded')).toBe('false') - expect(ownerValue()).toBe(WORKER) + expect(ownerValue()).toBe('worker') expect(document.querySelectorAll('[data-team-task-details]')).toHaveLength(1) expect(screen.queryByText(description)).toBeNull() fireEvent.click(row('Review implementation')) @@ -179,12 +180,12 @@ describe('TeamBoard', () => { expect(row('Completed second').querySelector('[data-state="done"]')).toBeTruthy() fireEvent.click(row('Completed second')) expect(row('Completed second').getAttribute('aria-expanded')).toBe('true') - expect(ownerValue()).toBe(SESSION) + expect(ownerValue()).toBe('lead') expect(screen.getByText(task.description)).toBeTruthy() }) it('announces blocked status without displaying readiness, dependencies, scopes, warnings, or task ids', () => { - const { ownerId: _ownerId, ...unowned } = task + const { ownerId: _ownerId, ownerName: _ownerName, ...unowned } = task const b = bench({ value: { ...team, tasks: [ { ...unowned, status: 'pending', blockedBy: [TASK_2, 'missing' as TeamTaskId] }, { ...task, id: TASK_2, subject: 'Prepare shared types', status: 'completed' }, @@ -212,40 +213,31 @@ describe('TeamBoard', () => { fireEvent.click(row()) expect(within(row()).getByRole('img', { name: zh['status.pending'] })).toBeTruthy() expect(row().querySelector('[data-state="idle"]')).toBeTruthy() - expect(ownerValue()).toBe(SESSION) + expect(ownerValue()).toBe('lead') expect(document.querySelector('[data-team-task-details]')?.children).toHaveLength(1) expect(document.querySelector('[data-team-task-details] p:not([data-team-task-owner])')).toBeNull() }) - it('uses the owner id independently of catalog descriptions and Session titles', () => { - const b = bench({ - byId: { [SESSION]: summary(SESSION), [NESTED]: { ...summary(NESTED, 'Session title'), parentId: WORKER } }, - projections: { - [SESSION]: { state: 'ready', error: null, values: { - agentTeam: { ...team, tasks: [{ ...task, ownerId: NESTED }] }, - } }, - [WORKER]: { state: 'ready', error: null, values: { - subagentCatalog: [{ id: NESTED, createdAt: 0, mode: 'continuable', label: 'Catalog responsibility' }], - } }, - }, - }) + it('renders a saved owner path without loading its parent catalog', () => { + const b = bench({ value: { ...team, tasks: [{ ...task, ownerId: NESTED, ownerName: 'worker/checker' }] } }) render() fireEvent.click(row()) - expect(ownerValue()).toBe(NESTED) - setProjectionSnapshot(b.sessions, WORKER, { state: 'ready', error: null, values: {} }) + expect(ownerValue()).toBe('worker/checker') act(() => { b.sessions.update((draft) => { draft.byId[NESTED] = { ...summary(NESTED), displayTitle: 'Display title' } }) }) - expect(ownerValue()).toBe(NESTED) - setProjection(b.sessions, SESSION, { ...team, tasks: [{ ...task, ownerId: WORKER }] }) - expect(ownerValue()).toBe(WORKER) + expect(ownerValue()).toBe('worker/checker') }) - it('uses owner id when neither root nor parent projections exist', () => { - const b = bench({ value: { ...team, tasks: [{ ...task, ownerId: NESTED }] }, byId: { - [NESTED]: { ...summary(NESTED), parentId: WORKER }, + it('uses the owner Session ID when the saved task has no name', () => { + const { ownerName: _ownerName, ...historical } = task + const b = bench({ value: { ...team, tasks: [{ ...historical, ownerId: WORKER }] }, projections: { + [SESSION]: { state: 'ready', error: null, values: { + agentTeam: { ...team, tasks: [{ ...historical, ownerId: WORKER }] }, + subagentCatalog: [{ id: WORKER, createdAt: 0, mode: 'continuable', label: 'Worker', name: 'worker' }], + } }, } }) render() fireEvent.click(row()) - expect(ownerValue()).toBe(NESTED) + expect(ownerValue()).toBe(WORKER) }) it('hides retained tasks while Team is disabled and shows them when enabled', () => { @@ -344,8 +336,8 @@ describe('TeamBoard', () => { render() expect(screen.getByRole('heading').textContent).toBe(`${en.tasks}${makeTranslate(en)('progress.active', { count: 1 })}`) fireEvent.click(row()) - expect(ownerValue()).toBe(SESSION) - expect(document.querySelector('[data-team-task-owner]')?.textContent).toBe(`${en.owner}: ${SESSION}`) + expect(ownerValue()).toBe('lead') + expect(document.querySelector('[data-team-task-owner]')?.textContent).toBe(`${en.owner}: lead`) expect(screen.queryByText(TASK_1)).toBeNull() expect(screen.queryByText('Show more')).toBeNull() expect(screen.queryByText('Show less')).toBeNull() @@ -355,8 +347,9 @@ describe('TeamBoard', () => { vi.useFakeTimers() enableTooltips() const ownerId = '8c0404a0-4c67-48ab-9513-50b4a755d6de' as SessionId + const { ownerName: _ownerName, ...historical } = task const b = bench({ - value: { ...team, tasks: [{ ...task, ownerId }] }, + value: { ...team, tasks: [{ ...historical, ownerId }] }, }) const view = render() fireEvent.click(row()) diff --git a/packages/client/ui-chat/README.i18n.yaml b/packages/client/ui-chat/README.i18n.yaml index bbed78bfaf..3120b6b576 100644 --- a/packages/client/ui-chat/README.i18n.yaml +++ b/packages/client/ui-chat/README.i18n.yaml @@ -30,8 +30,8 @@ en: 382821ca3ffa60dd zh: 9840ffa07c13082a /deepseek-ai-dsh-client-ui-chat/turn-process-folding: - en: b0d806604bc17006 - zh: 18dabe5dc2d0d419 + en: 7cc6692b879aa500 + zh: e924733c88b526c9 /deepseek-ai-dsh-client-ui-chat/grouped-rendering: en: b1630d93a52f483e zh: 59cb81ca50ecffc4 diff --git a/packages/client/ui-chat/README.md b/packages/client/ui-chat/README.md index a430e12e74..d845c15bbd 100644 --- a/packages/client/ui-chat/README.md +++ b/packages/client/ui-chat/README.md @@ -98,6 +98,8 @@ The completed-turn action footer follows the recorded Turn end. Its action row s ## Turn Process Folding +Empty `user/message` records with `source.kind: 'retry'` remain in Session history while Chat renders a compact continuation-request receipt instead of a user bubble. Ordinary empty user messages and retry messages containing content retain their normal presentation. + During uninterrupted following, local transcript and steering echoes remain mounted through Inbox acceptance and claim until the durable message arrives, without triggering tail following twice. Pending steering follows Inbox order across clients, using matching local echoes in place. Admitted local steering also suppresses matching stale Inbox rows until the claim projection arrives; steering without a locally tracked submission continues to follow the Inbox projection. After reconnect, Host-owned rows replace receipt-confirmed local echoes; a claim awaiting admission may briefly have no bubble. When Chat ends with an open Turn control and that Turn has no visible input, the first local transcript echo precedes the control. Other echoes remain at the flow tail. The control and echoes share one keyed list, so arrival of the control preserves the echo's mounted identity. Durable inputs replace their matching echoes in the same render. diff --git a/packages/client/ui-chat/README.zh.md b/packages/client/ui-chat/README.zh.md index ecf93eed36..80402eadf2 100644 --- a/packages/client/ui-chat/README.zh.md +++ b/packages/client/ui-chat/README.zh.md @@ -98,6 +98,8 @@ Chat 在 `MarkdownDelegateProvider.getTriggerProps` 接入处适配 Markdown 目 ## 轮次过程折叠 +带 `source.kind: 'retry'` 的空 `user/message` 记录保留在 Session 历史中,Chat 显示轻量的继续请求记录,不生成用户气泡。普通空用户消息与包含内容的重试消息保持正常展示。 + 正常在线时,本地 transcript 与 steering 回显在 Inbox 接受与领取期间保持挂载,直到持久消息到达,不会重复触发跟随底部。跨客户端的待处理 steering 遵循 Inbox 顺序,在匹配位置使用本地回显。已入档的本地 steering 还会排除匹配的旧 Inbox 行,直到领取投影到达;没有本地提交身份的 steering 仍按 Inbox 投影显示。重连后,Host 消息替代已有接收回执的本地回显;已领取但尚未入档时,气泡可能短暂消失。 Chat 末尾为进行中的 Turn 控制行,且该轮尚无可见输入时,第一条本地 transcript 回显显示在控制行前。其他回显保留在正文末尾。控制行与回显共用一个 keyed 列表,因此控制行到达时不会重新挂载回显。持久输入在同一次渲染中替换匹配的回显。 diff --git a/packages/client/ui-chat/src/client/chat/TurnTriggerNodeView.module.css b/packages/client/ui-chat/src/client/chat/TurnTriggerNodeView.module.css index 4bf309274c..0d964a6790 100644 --- a/packages/client/ui-chat/src/client/chat/TurnTriggerNodeView.module.css +++ b/packages/client/ui-chat/src/client/chat/TurnTriggerNodeView.module.css @@ -26,6 +26,17 @@ .header:hover { color: var(--dsw-alias-label-secondary); } } .icon { display: inline-flex; flex: none; color: inherit; } +.continuation { + display: flex; + align-items: center; + gap: 6px; + min-width: 0; + padding: 2px 0; + color: var(--dsw-alias-label-tertiary); + font-size: var(--dsh-content-font-size-secondary, 13px); + line-height: calc(20px + var(--dsh-content-font-delta-secondary, 0px)); + overflow-wrap: anywhere; +} .title { flex: 1; min-width: 0; overflow-wrap: anywhere; font-size: var(--dsh-content-font-size, 14px); } .time { flex: none; margin-left: auto; color: inherit; font: var(--dsw-font-xxs-12); } .chevron, .openChevron { flex: none; color: inherit; } diff --git a/packages/client/ui-chat/src/client/chat/TurnTriggerNodeView.tsx b/packages/client/ui-chat/src/client/chat/TurnTriggerNodeView.tsx index e6e366666a..70b4ded7bc 100644 --- a/packages/client/ui-chat/src/client/chat/TurnTriggerNodeView.tsx +++ b/packages/client/ui-chat/src/client/chat/TurnTriggerNodeView.tsx @@ -1,10 +1,10 @@ -/** An independent, expandable notice explaining a non-human Turn trigger. */ +/** Recorded Turn triggers and compact manual-continuation receipts. */ import { useId, useState, type ComponentType } from 'react' import { IconAgentPresetOutlineRegular, IconClockOutlineRegular, IconBranchOutlineRegular, IconChevronDownOutlineRegular, IconContextInjectionOutlineRegular, IconCordisPluginOutlineRegular, IconGoalOutlineRegular, IconGlobeOutlineRegular, IconPaperPlaneOutlineRegular, IconQueueOutlineRegular, - IconUsersOutlineRegular, type IconProps, + IconUsersOutlineRegular, IconPlayOutlineRegular, type IconProps, } from '@deepseek-ai/dsh-client-ui-primitives' import type { ChatNodeViewProps } from '../contract/slots.ts' import { formatMessageClock } from './message-chrome.ts' @@ -13,6 +13,7 @@ import { turnTriggerDetails, type TurnTriggerIcon } from './turn-trigger.ts' import css from './TurnTriggerNodeView.module.css' const TRIGGER_ICONS: Record> = { + continue: IconPlayOutlineRegular, request: IconContextInjectionOutlineRegular, goal: IconGoalOutlineRegular, agent: IconPaperPlaneOutlineRegular, @@ -31,6 +32,12 @@ export function TurnTriggerNodeView({ node, t }: Pick + + {t(details.title)} + + ) const date = new Date(node.data.time) const time = formatMessageClock(node.data.time, t) return ( diff --git a/packages/client/ui-chat/src/client/chat/turn-trigger.ts b/packages/client/ui-chat/src/client/chat/turn-trigger.ts index ade8093490..f1e5a2397e 100644 --- a/packages/client/ui-chat/src/client/chat/turn-trigger.ts +++ b/packages/client/ui-chat/src/client/chat/turn-trigger.ts @@ -3,7 +3,7 @@ import type { ContextMessageNode } from '../contract/snapshot.ts' import type { ChatKey } from '../locale.ts' /** Existing primitive glyph selected for a Turn trigger's source family. */ -export type TurnTriggerIcon = 'agent' | 'github' | 'goal' | 'job' | 'plugin' | 'request' | 'schedule' | 'subagent' | 'team' | 'webhook' +export type TurnTriggerIcon = 'agent' | 'continue' | 'github' | 'goal' | 'job' | 'plugin' | 'request' | 'schedule' | 'subagent' | 'team' | 'webhook' function record(value: unknown): Record { return typeof value === 'object' && value !== null && !Array.isArray(value) ? value as Record : {} @@ -30,17 +30,21 @@ function subagentTitle(reason: unknown): ChatKey { /** * Describe a waking message using its recorded source. * @param node - durable context, including the original notification body. - * @returns localized title key and source-family icon. + * @returns localized title, source-family icon, and compact presentation for continuation receipts. */ export function turnTriggerDetails(node: ContextMessageNode): { title: ChatKey icon: TurnTriggerIcon + compact?: true } { const source = record(node.source) const kind = field(source, 'kind') let title: ChatKey = 'message.trigger.request' let icon: TurnTriggerIcon = 'request' switch (kind) { + case 'retry': + if (node.content.length === 0) return { title: 'message.continuation.requested', icon: 'continue', compact: true } + break case 'goal': { title = 'message.trigger.goal' icon = 'goal' diff --git a/packages/client/ui-chat/src/client/conversation-nodes/message.ts b/packages/client/ui-chat/src/client/conversation-nodes/message.ts index fb7684a8f7..9120812197 100644 --- a/packages/client/ui-chat/src/client/conversation-nodes/message.ts +++ b/packages/client/ui-chat/src/client/conversation-nodes/message.ts @@ -38,7 +38,7 @@ declare module '../contract/chat-nodes.ts' { steering: ReferencedSteeringMessageNode /** Non-user context injected into model history. */ context: ContextMessageNode - /** Non-human input that starts a Turn. */ + /** Recorded notification or manual continuation that starts a Turn. */ 'turn-trigger': ContextMessageNode } } @@ -136,12 +136,16 @@ export const messageDefinition: ConversationNodeDefinition = { update: context => context.state, buildViewNode: (context) => { if (context.state === undefined) return null + const location = contextLocation(context) + if (context.state.kind === 'context' && context.start?.event.type === 'user/message' + && context.start.event.data.source.kind === 'retry' && context.start.event.data.content.length === 0) { + return chatNode(context, 'turn-trigger', context.state.seq, context.state, { location, groupTree: 'input' }) + } const waking = context.state.kind === 'context' && context.start?.event.type === 'user/message' && context.state.waking === true // Human input claimed for Step 1 opens an exchange; Notice-woken Turns and // later steering stay in the current exchange, so they never fold earlier Turns. - const location = contextLocation(context) const human = context.state.kind === 'user' || context.state.kind === 'steering' const opensExchange = human && location.kind === 'step' && location.step.step === 1 return chatNode( diff --git a/packages/client/ui-chat/src/client/locale.ts b/packages/client/ui-chat/src/client/locale.ts index c21cbdad59..0b2bc2151d 100644 --- a/packages/client/ui-chat/src/client/locale.ts +++ b/packages/client/ui-chat/src/client/locale.ts @@ -171,6 +171,7 @@ export const zh = { 'message.retry.active': '正在重试模型请求', 'message.retry.cancelled': '模型请求重试已取消', 'message.retry.started': '已重试模型请求', + 'message.continuation.requested': '已请求继续生成', 'message.retry.scheduled': '等待重试模型请求', 'message.retry.status': '{label}({retry}/{maximum}) · {seconds}s', 'message.retry.delay': '重试延迟:', @@ -380,6 +381,7 @@ export const en = { 'message.retry.active': 'Retrying model request', 'message.retry.cancelled': 'Model request retry cancelled', 'message.retry.started': 'Retried model request', + 'message.continuation.requested': 'Requested to continue generation', 'message.retry.scheduled': 'Waiting to retry model request', 'message.retry.status': '{label} ({retry}/{maximum}) · {seconds}s', 'message.retry.delay': 'Retry delay: ', @@ -586,6 +588,7 @@ export const ja = { 'message.retry.active': 'モデルリクエストを再試行中', 'message.retry.cancelled': 'モデルリクエストの再試行をキャンセルしました', 'message.retry.started': 'モデルリクエストを再試行しました', + 'message.continuation.requested': '生成の続行をリクエストしました', 'message.retry.scheduled': 'モデルリクエストの再試行待ちです', 'message.retry.status': '{label} ({retry}/{maximum}) · {seconds}秒', 'message.retry.delay': '再試行までの待機時間: ', @@ -792,6 +795,7 @@ export const es = { 'message.retry.active': 'Reintentando solicitud de modelo', 'message.retry.cancelled': 'Reintento de solicitud de modelo cancelado', 'message.retry.started': 'Solicitud de modelo reintentada', + 'message.continuation.requested': 'Se ha solicitado continuar la generación', 'message.retry.scheduled': 'Esperando para volver a intentar la solicitud de modelo', 'message.retry.status': '{label} ({retry}/{maximum}) · {seconds}s', 'message.retry.delay': 'Retraso de reintento: ', @@ -998,6 +1002,7 @@ export const fr = { 'message.retry.active': 'Nouvelle tentative de demande de modèle', 'message.retry.cancelled': 'Nouvelle tentative de demande de modèle annulée', 'message.retry.started': 'Demande de modèle réessayée', + 'message.continuation.requested': 'Suite de la génération demandée', 'message.retry.scheduled': 'En attente de réessayer la demande de modèle', 'message.retry.status': '{label} ({retry}/{maximum}) · {seconds}', 'message.retry.delay': 'Délai de nouvelle tentative : ', @@ -1204,6 +1209,7 @@ export const de = { 'message.retry.active': 'Modellanforderung wird erneut versucht', 'message.retry.cancelled': 'Wiederholungsversuch der Modellanforderung abgebrochen', 'message.retry.started': 'Modellanfrage erneut versucht', + 'message.continuation.requested': 'Fortsetzung der Generierung angefordert', 'message.retry.scheduled': 'Warten auf erneuten Versuch der Modellanforderung', 'message.retry.status': '{label} ({retry}/{maximum}) · {seconds}s', 'message.retry.delay': 'Wiederholungsverzögerung: ', @@ -1410,6 +1416,7 @@ export const ru = { 'message.retry.active': 'Повторный запрос модели', 'message.retry.cancelled': 'Повтор запроса модели отменен.', 'message.retry.started': 'Повторный запрос модели', + 'message.continuation.requested': 'Запрошено продолжение генерации', 'message.retry.scheduled': 'Ожидание повторного запроса модели', 'message.retry.status': '{label} ({retry}/{maximum}) · {seconds}s', 'message.retry.delay': 'Задержка повтора: ', @@ -1616,6 +1623,7 @@ export const pt = { 'message.retry.active': 'Tentando novamente a solicitação de modelo', 'message.retry.cancelled': 'Nova tentativa de solicitação de modelo cancelada', 'message.retry.started': 'Solicitação de modelo repetida', + 'message.continuation.requested': 'Continuação da geração solicitada', 'message.retry.scheduled': 'Aguardando para tentar novamente a solicitação de modelo', 'message.retry.status': '{label} ({retry}/{maximum}) · {seconds}s', 'message.retry.delay': 'Atraso na nova tentativa: ', diff --git a/packages/client/ui-chat/tests/conversation-node-definitions.client.spec.ts b/packages/client/ui-chat/tests/conversation-node-definitions.client.spec.ts index 0151781d5b..57ed47cdcf 100644 --- a/packages/client/ui-chat/tests/conversation-node-definitions.client.spec.ts +++ b/packages/client/ui-chat/tests/conversation-node-definitions.client.spec.ts @@ -626,6 +626,39 @@ describe('built-in conversation node Definitions', () => { }, ) + it.each(['replay', 'live', 'prepend'] as const)('presents empty retry receipts through %s while retaining other input', (mode) => { + const retry = { id: 'empty-retry', role: 'user', content: [], source: { kind: 'retry' } } + const before = [ + at(1, 'agent/inbox/spliced', { target: 'next-turn', start: 0, inserted: [retry] }), + at(2, 'turn/start', { turn: 1 }), + at(3, 'agent/inbox/spliced', { target: 'next-turn', start: 0, removedCount: 1, inserted: [] }), + at(4, 'step/start', { turn: 1, step: 1 }), + ] + const message = at(5, 'user/message', retry, { surfaceOp: 'append' }) + const value = assembler(mode === 'replay' ? [...before, message] : mode === 'prepend' ? [message] : [], mode === 'prepend') + if (mode === 'live') for (const entry of [...before, message]) value.append(entry) + if (mode === 'prepend') value.prepend(before, false) + value.flush() + const current = snapshot(value) + const receipt = node(current, 'turn-trigger') + expect(receipt).toMatchObject({ anchorSeq: 5, groupTree: 'input', data: { content: [], source: { kind: 'retry' } } }) + expect(current.order).toContain(receipt?.key) + expect(node(current, 'unknown')).toBeUndefined() + + value.append(at(6, 'user/message', { ...retry, id: 'retry-with-content', + content: [{ type: 'text', text: 'retained context' }], + }, { surfaceOp: 'append' })) + value.append(at(7, 'user/message', { ...retry, id: 'ordinary-empty', source: { kind: 'user' } }, { surfaceOp: 'append' })) + value.append(at(8, 'developer/message', { turn: 1, step: 1, + message: { ...retry, id: 'developer-empty', role: 'developer' }, + }, { surfaceOp: 'append' })) + value.flush() + expect(node(snapshot(value), 'context')?.data).toMatchObject({ content: [{ type: 'text', text: 'retained context' }] }) + expect(node(snapshot(value), 'user')?.data).toMatchObject({ content: [], source: { kind: 'user' } }) + expect(snapshot(value).nodes.values().find(candidate => candidate.anchorSeq === 8)?.data) + .toMatchObject({ content: [], source: { kind: 'retry' } }) + }) + it.each(['replay', 'live', 'prepend'] as const)('classifies waking Inbox messages through %s', (mode) => { const notice = { ...textMessage('notice', 'scheduled work'), source: { kind: 'schedule' } } const human = textMessage('human', 'user task') diff --git a/packages/client/ui-chat/tests/turn-trigger.client.spec.tsx b/packages/client/ui-chat/tests/turn-trigger.client.spec.tsx index bbb2999cc7..e12ca7973e 100644 --- a/packages/client/ui-chat/tests/turn-trigger.client.spec.tsx +++ b/packages/client/ui-chat/tests/turn-trigger.client.spec.tsx @@ -24,6 +24,20 @@ function trigger(source: unknown): ChatNode<'turn-trigger'> { } describe('Turn trigger notices', () => { + it.each([ + [en, 'Requested to continue generation'], + [zh, '已请求继续生成'], + ])('shows an empty retry as a compact continuation receipt', (locale, title) => { + const node = trigger({ kind: 'retry' }) + node.data.content = [] + expect(turnTriggerDetails(node.data)).toEqual({ title: 'message.continuation.requested', icon: 'continue', compact: true }) + const view = render() + expect(view.getByText(title)).toBeDefined() + expect(view.queryByRole('button')).toBeNull() + expect(view.container.querySelector('[data-generation-continuation] svg')).not.toBeNull() + expect(view.container.querySelector('time')).toBeNull() + }) + it.each([ [{ kind: 'schedule' }, 'schedule', 'Automation task'], [{ kind: 'tool-jobs' }, 'job', 'Background task updated'], @@ -35,6 +49,7 @@ describe('Turn trigger notices', () => { [{ kind: 'webhook', provider: 'github' }, 'github', 'GitHub event received'], [{ kind: 'webhook', provider: 'custom' }, 'webhook', 'External event received'], [{ kind: 'custom-extension' }, 'request', 'Execution requested'], + [{ kind: 'retry' }, 'request', 'Execution requested'], ] as const)('presents the recorded %j source', (source, icon, title) => { const node = trigger(source) const details = turnTriggerDetails(node.data) diff --git a/packages/client/ui-conversation/README.i18n.yaml b/packages/client/ui-conversation/README.i18n.yaml index 00011393b7..f5821391a8 100644 --- a/packages/client/ui-conversation/README.i18n.yaml +++ b/packages/client/ui-conversation/README.i18n.yaml @@ -21,20 +21,29 @@ en: cc4dafd1aae02468 zh: be6b67724b7ac4a3 /deepseek-ai-dsh-client-ui-conversation/shell-and-standard-props: - en: c11cc27a337174f3 - zh: a971ef53fa6046a2 + en: 8994069b62a88825 + zh: 262ace7ad9bd35b7 /deepseek-ai-dsh-client-ui-conversation/temporary-composer-entries: en: 59cd63057dfb6eeb zh: b2e2c86e810b7bb8 /deepseek-ai-dsh-client-ui-conversation/model-experience: - en: e0a05b73ba3e4318 - zh: dc85ab8433bb4456 -/deepseek-ai-dsh-client-ui-conversation/model-experience/kv-cache-effect: - en: 9f4e0da7c8addf88 - zh: 1a33d9981af75643 + en: 215e7ba838619b7b + zh: a311da3843709f90 +/deepseek-ai-dsh-client-ui-conversation/model-experience/manual-continuation-request: + en: 6a7ae99570c9c007 + zh: 26e86063e97d82c7 +/deepseek-ai-dsh-client-ui-conversation/model-experience/manual-continuation-request/what-the-model-sees: + en: 017391d7ad0f9eb7 + zh: 2693ed29d44b1164 +/deepseek-ai-dsh-client-ui-conversation/model-experience/manual-continuation-request/token-effect: + en: 517c56dbd522c929 + zh: 55fa3a02d026e36a +/deepseek-ai-dsh-client-ui-conversation/model-experience/manual-continuation-request/kv-cache-effect: + en: f8621bbc481c26ae + zh: 5be844989dc80803 /deepseek-ai-dsh-client-ui-conversation/known-limitations-and-deferred-work: - en: edd7248fc7e110fb - zh: 643e313c9585b73b + en: b3f74c35f88ab2fa + zh: 8492b314debd130c /deepseek-ai-dsh-client-ui-conversation/known-limitations-and-deferred-work/dev-note: en: e67f633dc6fe7773 zh: e88aeb617ffb74ea diff --git a/packages/client/ui-conversation/README.md b/packages/client/ui-conversation/README.md index 76ed8e06ca..d9c67692b0 100644 --- a/packages/client/ui-conversation/README.md +++ b/packages/client/ui-conversation/README.md @@ -80,6 +80,12 @@ The composer measures its expanded control groups after size, content, visibilit The context meter follows the [statistics-control radius](../../../docs/ui-radius.md#radius-scale). +An empty, idle ordinary Session composer offers a play action after `RATE_LIMIT`, `SERVER`, `TIMEOUT`, `TRANSPORT`, `EMPTY_RESPONSE`, or `STREAM_CLOSED` ends its latest turn. The failed turn must include admitted ordinary user input and a settled failed model attempt. Clicking submits `content: []` through the existing Session prompt API; drafts and attachments keep the Send action. A new balanced turn uses committed history and records an empty `user/message` with `source.kind: 'retry'`. Refusal or transport failure leaves the draft empty and reports the error through the ordinary submission lifecycle. + +The Session API owns `conversationContinuation`, shared by Host admission and browser presentation. It restores eligibility from complete Session history and preserves it across repeated failed empty continuations, independently of loaded browser pages. + +The composer exposes `retry(failureSeq)` for failed-generation recovery. The input bar reads `conversationContinuation` and `inbox` through the standard `useProjection` prop. User-facing text calls the action Continue generating. + The composer uses the shared [text-input focus policy](../ui-primitives/README.md#use-this-package) on mount, Session switching, and unlock. Identified phones and tablets require tapping the input; desktop devices retain automatic focus. On these mobile devices, a submission that empties the focused draft moves focus to the non-text composer card, dismissing the keyboard while retaining its navigation position. Rejected submissions, retained newer draft text, and another control already holding focus preserve focus. The [Lexical patch](../../../patches/lexical@0.49.0.patch) keeps caret scrolling in the same coordinate system as DOM geometry when a mobile keyboard pans the page. The context-occupancy button shows a ring and percentage below the input card, after the Session statistics. Clicking it opens the token breakdown in a CSS-anchored panel bounded by the layout viewport, including when no statistics are shown; the button stays hidden until context usage and capacity are available. Browser zoom and panning move the panel with the page, so it may extend beyond the visual viewport. Outside the Hero, that row keeps one reading's height while it is empty, so statistics and context usage arriving later do not change the composer's height; the Hero shows no empty row. @@ -191,11 +197,19 @@ Session title context gestures use the shared [context menu](../ui-context-menu/ ## Model Experience -None, as this package renders browser state and sends user-admitted inputs through Session Controller APIs without constructing model requests. +### Manual continuation request + +#### What the model sees + +The play action submits `content: []` through the existing Session prompt API. Ordinary Loop admission records an empty `user/message` with `source.kind: 'retry'`. Chat presents the empty retry as a compact continuation-request receipt. The adapter applies its ordinary message serialization; the action adds no localized or hidden continuation text. Pending injected context follows ordinary admission. + +#### Token effect + +The action adds no continuation text. Empty-message serialization and framing costs depend on the adapter. The request still incurs the ordinary cost of retained history, current prompt sections, tool declarations, and any newly admitted context. #### KV Cache effect -None; Conversation assembly and browser input state do not alter provider-side prompt caching. +Serialization of the empty retry message depends on the adapter. Prefix reuse depends on the current model, prompt, tools, injected context, and provider cache policy. ## Known Limitations and Deferred Work @@ -203,6 +217,7 @@ None; Conversation assembly and browser input state do not alter provider-side p - **Only registered targets can render** — the shell deliberately has no implicit fallback target beyond the registered `chat` preference. - **Factory occurrences inherit their render-position Session** — `conversation.content` does not accept an independently addressed Session; that requires a separate Session-provider capability. +- **Manual continuation uses a fixed product allowlist** — the supported failure codes are independent of the provider's configurable `retryableCodes`; changing automatic retry policy does not expand or reduce this action. `STREAM_CLOSED` permits an explicit new user turn even when the default policy does not retry it. That code can also identify a protocol violation, so another request is not guaranteed to recover. - **Composer backdrop blur is verified only in Chromium** — with `will-change: transform` on the docked composer, descendant `backdrop-filter` still samples the transcript in Chromium; WebKit behavior has not been verified. - **A failing Definition costs a full replay per publication** — after an incremental flush fails, the assembler replays the complete loaded window to keep the views correct. A Definition that fails on every update therefore replays the whole window on each publication until its owner fixes it ([window update paths](../../../docs/subsystems/conversation.md#window-update-paths)). diff --git a/packages/client/ui-conversation/README.zh.md b/packages/client/ui-conversation/README.zh.md index 1101262976..c9d1b93019 100644 --- a/packages/client/ui-conversation/README.zh.md +++ b/packages/client/ui-conversation/README.zh.md @@ -80,6 +80,12 @@ root 作用域的 hoc Slot `conversation.hero.frame` 在所有阶段都包裹滚 上下文占用率入口遵循[统计控件圆角规则](../../../docs/ui-radius.zh.md#radius-scale)。 +空闲且草稿为空的普通 Session,在最新轮次以 `RATE_LIMIT`、`SERVER`、`TIMEOUT`、`TRANSPORT`、`EMPTY_RESPONSE` 或 `STREAM_CLOSED` 结束后显示播放按钮。失败工作必须有已准入的普通用户输入和失败请求尝试。点击通过现有 Session prompt API 提交 `content: []`;已有草稿或附件仍使用发送按钮。新轮次正常闭合,使用已提交历史,并记录 `source.kind: 'retry'` 的空 `user/message`。请求被拒绝或传输失败时,草稿保持为空,错误沿用普通提交流程展示。 + +Session API 拥有 `conversationContinuation`,Host 准入和浏览器展示共用该投影。它从完整 Session 历史恢复资格,并在空输入继续再次失败时保留资格,不依赖浏览器已加载的历史分页。 + +composer 提供 `retry(failureSeq)` 处理生成失败后的恢复。输入栏通过标准 `useProjection` prop 读取 `conversationContinuation` 和 `inbox`。面向用户的操作文案为“继续生成”。 + composer 在挂载、切换 Session 和解除锁定时使用共享的[文字输入框聚焦策略](../ui-primitives/README.zh.md#use-this-package)。识别出的手机和平板需要点击输入框;桌面设备保留自动聚焦。在这些移动设备上,提交清空正在聚焦的草稿后,焦点移到不接受文字输入的 composer 卡片,收起键盘并保留键盘导航位置。被拒绝的提交、保留的新草稿文字,以及已经聚焦的其他控件均保留原有焦点。移动端键盘平移页面时,[Lexical 补丁](../../../patches/lexical@0.49.0.patch)让光标滚动计算与 DOM 几何使用同一坐标系。 上下文占用按钮在输入卡片下方、会话统计右侧显示圆环和百分比。点击按钮可在受布局视口约束的 CSS 锚定面板中查看 token 构成,没有统计项时也可打开;上下文用量和容量尚不可用时,按钮保持隐藏。浏览器缩放和平移时面板随页面移动,因此可以超出视觉视口。Hero 之外,这一行为空时仍保留一项读数的高度,因此会话统计和上下文用量稍后到达不会改变 composer 的高度;Hero 不显示空行。 @@ -191,11 +197,19 @@ selector 必须是 owner currency 的纯函数。非 null 返回值作为 `match ## 模型体验 -无,因为本包渲染浏览器状态,并通过 Session Controller API 发送用户确认提交的输入,而不构造模型请求。 +### 手动继续请求 + +#### 模型看到什么 + +播放按钮通过现有 Session prompt API 提交 `content: []`。普通 Loop 准入记录带 `source.kind: 'retry'` 的空 `user/message`。Chat 将空重试消息显示为轻量的继续请求记录。适配器按普通消息序列化处理;该操作不添加本地化或隐藏的继续文本。待注入上下文遵循普通准入流程。 + +#### Token 影响 + +该操作不增加继续文本。空消息的序列化及封装开销取决于适配器。请求仍承担保留历史、当前提示词、工具声明以及新准入上下文的正常输入成本。 #### KV Cache 影响 -无;Conversation 组装和浏览器输入状态不会改变提供方侧的 prompt cache。 +空重试消息的序列化取决于适配器。前缀复用取决于当前模型、提示词、工具、注入上下文及提供方缓存策略。 ## 已知限制与暂缓事项 @@ -203,6 +217,7 @@ selector 必须是 owner currency 的纯函数。非 null 返回值作为 `match - **只有已注册 target 可以渲染**——除已注册的 `chat` 偏好外,shell 刻意不提供隐式 fallback target。 - **Factory occurrence 继承渲染位置的 Session**——`conversation.content` 不接受独立寻址的 Session;该能力需要单独的 Session provider。 +- **手动继续使用固定产品白名单**——支持的失败码独立于提供方可配置的 `retryableCodes`;修改自动重试策略不会扩展或缩小此操作的范围。即使默认策略不重试 `STREAM_CLOSED`,用户仍可明确发起新轮次。该错误码也可能表示协议违规,因此再次请求不保证能够恢复。 - **composer 内的毛玻璃只在 Chromium 中验证过**——docked composer 设置 `will-change: transform` 后,Chromium 中后代的 `backdrop-filter` 仍会采样背后的 transcript;WebKit 中的表现尚未验证。 - **出错的 Definition 让每次发布都完整回放**——增量 flush 失败后,assembler 回放已加载的完整窗口,以保持视图正确。若某个 Definition 在每次更新中都失败,在其 owner 修复前,每次发布都会回放整个窗口([Window 更新路径](../../../docs/subsystems/conversation.zh.md#window-update-paths))。 diff --git a/packages/client/ui-conversation/package.json b/packages/client/ui-conversation/package.json index 7cb2fb0bba..b9da8bb62e 100644 --- a/packages/client/ui-conversation/package.json +++ b/packages/client/ui-conversation/package.json @@ -59,7 +59,6 @@ "@deepseek-ai/dsh-api-session-controller": "workspace:*", "@deepseek-ai/dsh-api-workspace-controller": "workspace:*", "@deepseek-ai/dsh-attachment": "workspace:*", - "@deepseek-ai/dsh-brand": "workspace:*", "@deepseek-ai/dsh-client-locale": "workspace:*", "@deepseek-ai/dsh-client-file-upload": "workspace:*", "@deepseek-ai/dsh-client-store": "workspace:*", @@ -87,7 +86,6 @@ "react": "^18.2.0", "@lexical/headless": "^0.49.0", "react-dom": "^18.2.0", - "zod": "4.4.3", "lexical": "^0.49.0", "clsx": "^2.0.0", "@lexical/utils": "^0.49.0", @@ -99,6 +97,9 @@ "@deepseek-ai/dsh-client-shortcuts": "workspace:*", "@deepseek-ai/dsh-client-product-analytics": "workspace:*", "@deepseek-ai/dsh-message-quotes": "workspace:*", + "@deepseek-ai/dsh-session-projection": "workspace:*", + "@deepseek-ai/dsh-brand": "workspace:*", + "zod": "4.4.3", "@deepseek-ai/dsh-client-ui-context-menu": "workspace:*" }, "files": [ diff --git a/packages/client/ui-conversation/src/client/apply.ts b/packages/client/ui-conversation/src/client/apply.ts index aee9351ce0..aae71928be 100644 --- a/packages/client/ui-conversation/src/client/apply.ts +++ b/packages/client/ui-conversation/src/client/apply.ts @@ -484,6 +484,7 @@ export function apply(ctx: Context, config: Config = Config({})): void { retryFileUpload: undefined, toggleCommandMenu: undefined, stop: undefined, + retry: undefined, hooks: { stopShortcut, busyEnter: submissionPolicy.busyEnter, @@ -563,6 +564,7 @@ export function apply(ctx: Context, config: Config = Config({})): void { }) }, stop: () => { stop(sessionId) }, + retry: (failureSeq) => { inputHub.retry(sessionId, failureSeq) }, hooks: { stopShortcut, busyEnter: submissionPolicy.busyEnter, diff --git a/packages/client/ui-conversation/src/client/contract/input.ts b/packages/client/ui-conversation/src/client/contract/input.ts index 82f030c775..6f6b0f1436 100644 --- a/packages/client/ui-conversation/src/client/contract/input.ts +++ b/packages/client/ui-conversation/src/client/contract/input.ts @@ -352,6 +352,8 @@ export type InputEvent = /** Enter submission with the current clipboard projection, its reference chips, its quotes, and its attachments. */ | { readonly type: 'enter' + /** Explicit retry may submit an empty draft through the default sink. */ + readonly allowEmpty?: boolean readonly mode: InputSubmitMode readonly draft: string readonly occurrences: readonly Occurrence[] diff --git a/packages/client/ui-conversation/src/client/contract/slots.ts b/packages/client/ui-conversation/src/client/contract/slots.ts index 5ce37d9ab9..5ce7e7efb7 100644 --- a/packages/client/ui-conversation/src/client/contract/slots.ts +++ b/packages/client/ui-conversation/src/client/contract/slots.ts @@ -14,7 +14,7 @@ import type { } from '@deepseek-ai/dsh-client-ui-slots' import type { SessionPendingInteraction } from '@deepseek-ai/dsh-client-ui-session/client' import type {} from '@deepseek-ai/dsh-client-ui-layout/client' -import type { SessionId } from '@deepseek-ai/dsh-session/types' +import type { SessionId, SessionSeq } from '@deepseek-ai/dsh-session/types' import type { WorkspaceId } from '@deepseek-ai/dsh-workspace/types' import type { ComposerBlock } from './composer-blocks.ts' import type { DraftAttachmentId, InputActions, InputNotice, InputState } from './input.ts' @@ -568,6 +568,11 @@ export interface ComposerBarInjected { retryFileUpload: ((id: DraftAttachmentId) => void) | undefined toggleCommandMenu: ((selection: EditSelection) => void) | undefined stop: (() => void) | undefined + /** + * Submit empty input to retry the displayed failed generation. + * @param failureSeq - sequence of the displayed failed turn/end. + */ + retry: ((failureSeq: SessionSeq) => void) | undefined hooks: { /** Readable sequence while the fixed Stop command is registered. */ stopShortcut: ObservableSnapshot diff --git a/packages/client/ui-conversation/src/client/input/facade.ts b/packages/client/ui-conversation/src/client/input/facade.ts index 6306216b1c..cb8472f746 100644 --- a/packages/client/ui-conversation/src/client/input/facade.ts +++ b/packages/client/ui-conversation/src/client/input/facade.ts @@ -387,8 +387,9 @@ export class SessionInputShell implements SessionInput { * out from the machine; this method only feeds the event. Lock entry * (adjudicating/submitting/sending) force-closes the transient layers: the * popup dismisses and the menu tracks frozen. + * @param allowEmpty - explicitly admit empty continuation input through the default sink. */ - submit(mode: InputSubmitMode = 'queue', source?: 'click' | 'enter'): void { + submit(mode: InputSubmitMode = 'queue', source?: 'click' | 'enter', allowEmpty = false): void { if (this.disposed) return const timestamp = Date.now() let state: MessageSubmissionState | undefined @@ -409,6 +410,7 @@ export class SessionInputShell implements SessionInput { } this.dispatchRun({ type: 'enter', + ...allowEmpty ? { allowEmpty: true } : {}, mode, draft: this.projection.clipboardText, occurrences: [...this.projection.occurrences], @@ -726,6 +728,10 @@ export class SessionInputShell implements SessionInput { }) const send = (text: string): void => { if (this.dead(attempt)) return + if (text === '' && draft !== '' && attachmentIds.length === 0) { + this.settleSink(attempt, Promise.resolve({ kind: 'success' })) + return + } this.settleSink(attempt, this.deps.defaultSink(text, attachmentIds, mode, attempt.signal, () => { this.acceptSink(attempt) })) } if (!(prompt instanceof Promise)) { send(prompt); return } diff --git a/packages/client/ui-conversation/src/client/input/hub.ts b/packages/client/ui-conversation/src/client/input/hub.ts index 9ed94a567b..f6e9ce4183 100644 --- a/packages/client/ui-conversation/src/client/input/hub.ts +++ b/packages/client/ui-conversation/src/client/input/hub.ts @@ -11,7 +11,7 @@ import type { Context } from '@deepseek-ai/cordis' import type { ISessions, SessionBinding, SessionFace, } from '@deepseek-ai/dsh-api-session-controller/client' -import type { SessionId } from '@deepseek-ai/dsh-session/types' +import type { SessionId, SessionSeq } from '@deepseek-ai/dsh-session/types' import type { TranslateNS } from '@deepseek-ai/dsh-client-locale/client' import type { InboxState } from '@deepseek-ai/dsh-agent/types' import type { ModelSelectionProjection } from '@deepseek-ai/dsh-agent/types' @@ -207,6 +207,29 @@ export class InputHub implements SessionInputResolver { return this.shell(id) } + /** + * Submit empty input to retry a failed generation through the ordinary composer. Stale + * failures, active work, and drafts keep their current input unchanged. + * @param id - retained ordinary Session identity. + * @param failureSeq - failed turn/end sequence the displayed button addresses. + */ + retry(id: SessionId, failureSeq: SessionSeq): void { + const binding = this.sessions().binding(id) + if (binding === undefined + || binding.session.projections.faceOf('conversationContinuation').getSnapshot() !== failureSeq) return + const session = binding.session.getSnapshot() + const shell = this.shellFor(binding) + const input = shell.snapshot + const inbox = binding.session.projections.faceOf('inbox').getSnapshot() as InboxState | undefined + if (session.running || session.removed || session.openState !== 'open' || session.subagent !== null + || session.pendingSubmissions.length > 0 || input.phase !== 'plain' + || input.draft.trim() !== '' || input.attachmentIds.length > 0 + || (inbox?.['next-turn'].length ?? 0) > 0 + || inbox?.['next-step'].some(message => message.source.kind === 'user') + || this.conversation().blocks.storeFor(id).getSnapshot() !== undefined) return + shell.submit('queue', 'click', true) + } + /** * Query file intake without creating a Session input. * @param id - target Session. @@ -251,7 +274,9 @@ export class InputHub implements SessionInputResolver { signal: AbortSignal, accept: () => void, ): Promise { - if (text === '' && attachmentIds.length === 0) return Promise.resolve({ kind: 'success' }) + if (text === '' && attachmentIds.length === 0) { + return session.prompt([], mode, signal).then(result => result.ok ? { kind: 'success' } : { kind: 'error' }) + } return this.conversation().sendSession(session, text, attachmentIds, mode, signal, accept) } diff --git a/packages/client/ui-conversation/src/client/input/machine.ts b/packages/client/ui-conversation/src/client/input/machine.ts index 16fe7dd034..8545f964e5 100644 --- a/packages/client/ui-conversation/src/client/input/machine.ts +++ b/packages/client/ui-conversation/src/client/input/machine.ts @@ -144,7 +144,7 @@ export class SubmitMachine { return [{ type: 'begin-submit', attempt, claim: this.claim, args: argsAfter(draft, this.claim.token) }] } const trimmed = draft.trim() - if (trimmed === '' && attachmentIds.length === 0) return [] + if (trimmed === '' && attachmentIds.length === 0 && ev.allowEmpty !== true) return [] const attempt = this.beginAttempt(mode, draft, occurrences, quotes, attachmentIds, submission) if (trimmed.startsWith('/')) { this.phase = 'adjudicating' diff --git a/packages/client/ui-conversation/src/client/locales.ts b/packages/client/ui-conversation/src/client/locales.ts index d89b2e91c4..21446d59a2 100644 --- a/packages/client/ui-conversation/src/client/locales.ts +++ b/packages/client/ui-conversation/src/client/locales.ts @@ -27,6 +27,7 @@ export const zh = { 'input.file': '文件', 'input.stop': '停止生成', 'input.send': '发送消息', + 'input.continue': '继续生成', 'input.sending': '正在发送消息', 'input.send.queue': '排队发送', 'input.send.steer': '插话发送', @@ -198,6 +199,9 @@ export const zh = { 'detail.status.inactive': '未运行', 'detail.status.provisioning': '准备中', 'detail.status.failed': '失败', + 'detail.status.corrupt': '已损坏', + 'detail.status.unsupported': '不支持', + 'detail.status.unavailable': '不可用', 'detail.status.completed': '已完成', 'detail.status.deleted': '已删除', 'detail.status.killed': '已取消', @@ -329,7 +333,7 @@ export const zh = { 'tool.title.bash': '运行命令', 'tool.title.write': '写入', 'tool.title.edit': '编辑', - 'tool.title.applyPatch': '应用补丁', + 'tool.title.applyPatch': '编辑', 'tool.title.code': '代码', 'tool.title.generic': '工具调用', 'tool.title.inspect': '查询 Cordis 环境', @@ -418,6 +422,7 @@ export const en = { 'input.file': 'File', 'input.stop': 'Stop generating', 'input.send': 'Send message', + 'input.continue': 'Continue generating', 'input.sending': 'Sending message', 'input.send.queue': 'Queue message', 'input.send.steer': 'Steer message', @@ -589,6 +594,9 @@ export const en = { 'detail.status.inactive': 'Inactive', 'detail.status.provisioning': 'Provisioning', 'detail.status.failed': 'Failed', + 'detail.status.corrupt': 'Corrupt', + 'detail.status.unsupported': 'Unsupported', + 'detail.status.unavailable': 'Unavailable', 'detail.status.completed': 'Completed', 'detail.status.deleted': 'Deleted', 'detail.status.killed': 'Cancelled', @@ -720,7 +728,7 @@ export const en = { 'tool.title.bash': 'Bash', 'tool.title.write': 'Write', 'tool.title.edit': 'Edit', - 'tool.title.applyPatch': 'Apply patch', + 'tool.title.applyPatch': 'Edit', 'tool.title.code': 'Code', 'tool.title.generic': 'Tool call', 'tool.title.inspect': 'Query Cordis environment', @@ -808,6 +816,7 @@ export const ja = { 'input.file': 'ファイル', 'input.stop': '生成を停止', 'input.send': 'メッセージを送信', + 'input.continue': '生成を続ける', 'input.sending': 'メッセージを送信中', 'input.send.queue': 'メッセージをキューに追加', 'input.send.steer': '実行中の指示にメッセージを追加', @@ -979,6 +988,9 @@ export const ja = { 'detail.status.inactive': '非アクティブ', 'detail.status.provisioning': 'プロビジョニング中', 'detail.status.failed': '失敗', + 'detail.status.corrupt': '破損', + 'detail.status.unsupported': '未対応', + 'detail.status.unavailable': '利用不可', 'detail.status.completed': '完了', 'detail.status.deleted': '削除済み', 'detail.status.killed': 'キャンセル済み', @@ -1110,7 +1122,7 @@ export const ja = { 'tool.title.bash': 'Bash', 'tool.title.write': '書き込み', 'tool.title.edit': '編集', - 'tool.title.applyPatch': 'パッチを適用', + 'tool.title.applyPatch': '編集', 'tool.title.code': 'コード', 'tool.title.generic': 'ツール呼び出し', 'tool.title.inspect': 'Cordis 環境を照会', @@ -1196,6 +1208,7 @@ export const es = { 'input.file': 'Archivo', 'input.stop': 'Detener generación', 'input.send': 'Enviar mensaje', + 'input.continue': 'Continuar generando', 'input.sending': 'Enviando mensaje', 'input.send.queue': 'mensaje de cola', 'input.send.steer': 'Redirigir mensaje', @@ -1362,6 +1375,9 @@ export const es = { 'detail.status.inactive': 'Inactivo', 'detail.status.provisioning': 'Aprovisionamiento', 'detail.status.failed': 'Fallido', + 'detail.status.corrupt': 'Dañado', + 'detail.status.unsupported': 'No compatible', + 'detail.status.unavailable': 'No disponible', 'detail.status.completed': 'Completado', 'detail.status.deleted': 'Eliminado', 'detail.status.killed': 'Cancelado', @@ -1493,7 +1509,7 @@ export const es = { 'tool.title.bash': 'golpe', 'tool.title.write': 'escribir', 'tool.title.edit': 'Editar', - 'tool.title.applyPatch': 'Aplicar parche', + 'tool.title.applyPatch': 'Editar', 'tool.title.code': 'Código', 'tool.title.generic': 'llamada de herramienta', 'tool.title.inspect': 'Consulta entorno Cordis', @@ -1586,6 +1602,7 @@ export const fr = { 'input.file': 'Fichier', 'input.stop': 'Arrêter la génération', 'input.send': 'Envoyer le message', + 'input.continue': 'Continuer la génération', 'input.sending': 'Envoi du message', 'input.send.queue': "Message de file d'attente", 'input.send.steer': 'Guider avec ce message', @@ -1752,6 +1769,9 @@ export const fr = { 'detail.status.inactive': 'Inactif', 'detail.status.provisioning': 'Approvisionnement', 'detail.status.failed': 'Échec', + 'detail.status.corrupt': 'Corrompu', + 'detail.status.unsupported': 'Non pris en charge', + 'detail.status.unavailable': 'Indisponible', 'detail.status.completed': 'Terminé', 'detail.status.deleted': 'Supprimé', 'detail.status.killed': 'Annulé', @@ -1883,7 +1903,7 @@ export const fr = { 'tool.title.bash': 'Frapper', 'tool.title.write': 'Écrire', 'tool.title.edit': 'Modifier', - 'tool.title.applyPatch': 'Appliquer le patch', + 'tool.title.applyPatch': 'Modifier', 'tool.title.code': 'Coder', 'tool.title.generic': "Appel d'outil", 'tool.title.inspect': "Interroger l'environnement Cordis", @@ -1976,6 +1996,7 @@ export const de = { 'input.file': 'Datei', 'input.stop': 'Generierung stoppen', 'input.send': 'Nachricht senden', + 'input.continue': 'Generierung fortsetzen', 'input.sending': 'Nachricht wird gesendet', 'input.send.queue': 'Warteschlangennachricht', 'input.send.steer': 'Mit Nachricht lenken', @@ -2142,6 +2163,9 @@ export const de = { 'detail.status.inactive': 'Inaktiv', 'detail.status.provisioning': 'Bereitstellung', 'detail.status.failed': 'Fehlgeschlagen', + 'detail.status.corrupt': 'Beschädigt', + 'detail.status.unsupported': 'Nicht unterstützt', + 'detail.status.unavailable': 'Nicht verfügbar', 'detail.status.completed': 'Abgeschlossen', 'detail.status.deleted': 'Gelöscht', 'detail.status.killed': 'Abgesagt', @@ -2273,7 +2297,7 @@ export const de = { 'tool.title.bash': 'Bash', 'tool.title.write': 'Schreiben', 'tool.title.edit': 'Bearbeiten', - 'tool.title.applyPatch': 'Patch anwenden', + 'tool.title.applyPatch': 'Bearbeiten', 'tool.title.code': 'Code', 'tool.title.generic': 'Werkzeugaufruf', 'tool.title.inspect': 'Fragen Sie die Cordis-Umgebung ab', @@ -2366,6 +2390,7 @@ export const ru = { 'input.file': 'Файл', 'input.stop': 'Остановить генерацию', 'input.send': 'Отправить сообщение', + 'input.continue': 'Продолжить генерацию', 'input.sending': 'Отправка сообщения', 'input.send.queue': 'Сообщение в очереди', 'input.send.steer': 'Направить сообщение', @@ -2532,6 +2557,9 @@ export const ru = { 'detail.status.inactive': 'Неактивный', 'detail.status.provisioning': 'обеспечение', 'detail.status.failed': 'Не удалось', + 'detail.status.corrupt': 'Повреждено', + 'detail.status.unsupported': 'Не поддерживается', + 'detail.status.unavailable': 'Недоступно', 'detail.status.completed': 'Завершено', 'detail.status.deleted': 'Удалено', 'detail.status.killed': 'Отменено', @@ -2663,7 +2691,7 @@ export const ru = { 'tool.title.bash': 'Баш', 'tool.title.write': 'Написать', 'tool.title.edit': 'Редактировать', - 'tool.title.applyPatch': 'Применить патч', + 'tool.title.applyPatch': 'Редактировать', 'tool.title.code': 'Код', 'tool.title.generic': 'Вызов инструмента', 'tool.title.inspect': 'Запрос среды Cordis', @@ -2756,6 +2784,7 @@ export const pt = { 'input.file': 'Arquivo', 'input.stop': 'Parar geração', 'input.send': 'Enviar mensagem', + 'input.continue': 'Continuar gerando', 'input.sending': 'Enviando mensagem', 'input.send.queue': 'Mensagem de fila', 'input.send.steer': 'Orientar com mensagem', @@ -2922,6 +2951,9 @@ export const pt = { 'detail.status.inactive': 'Inativo', 'detail.status.provisioning': 'Provisionamento', 'detail.status.failed': 'Falha', + 'detail.status.corrupt': 'Corrompido', + 'detail.status.unsupported': 'Não suportado', + 'detail.status.unavailable': 'Indisponível', 'detail.status.completed': 'Concluído', 'detail.status.deleted': 'Excluído', 'detail.status.killed': 'Cancelado', @@ -3053,7 +3085,7 @@ export const pt = { 'tool.title.bash': 'Bash', 'tool.title.write': 'Escreva', 'tool.title.edit': 'Editar', - 'tool.title.applyPatch': 'Aplicar patch', + 'tool.title.applyPatch': 'Editar', 'tool.title.code': 'Código', 'tool.title.generic': 'Chamada de ferramenta', 'tool.title.inspect': 'Consultar ambiente Cordis', diff --git a/packages/client/ui-conversation/src/client/skeleton/InputBar.module.css b/packages/client/ui-conversation/src/client/skeleton/InputBar.module.css index b3cd1dd271..fec2079742 100644 --- a/packages/client/ui-conversation/src/client/skeleton/InputBar.module.css +++ b/packages/client/ui-conversation/src/client/skeleton/InputBar.module.css @@ -416,6 +416,11 @@ transform: translateY(-2px); } +/* Solid artwork uses a smaller footprint than the thin send arrow. */ +.continueIcon { + transform: scale(1.5); +} + @media (hover: hover) { .primary:hover:not(:disabled) { background: var(--dsw-alias-button-info-hover); diff --git a/packages/client/ui-conversation/src/client/skeleton/InputBar.tsx b/packages/client/ui-conversation/src/client/skeleton/InputBar.tsx index 2e66d24364..5b6407242d 100644 --- a/packages/client/ui-conversation/src/client/skeleton/InputBar.tsx +++ b/packages/client/ui-conversation/src/client/skeleton/InputBar.tsx @@ -17,7 +17,7 @@ import { memo, useCallback, useEffect, useLayoutEffect, useMemo, useRef, useStat import type { ChangeEvent, KeyboardEvent, MouseEvent } from 'react' import clsx from 'clsx' import { - focusWithoutRing, IconPlusOutlineMedium, IconWarningOutlineRegular, isMobileDevice, Toast, Tooltip, + focusWithoutRing, IconPlusOutlineMedium, IconTriangleRightFillRegular, IconWarningOutlineRegular, isMobileDevice, Toast, Tooltip, } from '@deepseek-ai/dsh-client-ui-primitives' // Type-only: the `plan` projection key merge (the TodoDock posture — the // composer reads a host-computed value; the domain owns the key). @@ -46,7 +46,7 @@ export type InputBarProps = ComposerBarProps export const InputBar = memo(function InputBar({ useSession, useInput, inputActions, keyboard, addFiles, removeAttachment, resolveDraftAttachments, retryFileUpload, - toggleCommandMenu, stop, t, + toggleCommandMenu, stop, retry, t, renderSlot, useBusyEnter, useFileUploads, useNotices, useLexicon, useMenuLauncher, useStopShortcut, useAccess, useProjection, sessionId, variant, disabled: inert = false, blocked, @@ -70,6 +70,14 @@ export const InputBar = memo(function InputBar({ useEffect(() => { setActivity(false) }, [sessionId]) const promptError = useSession(s => s.promptError) ?? null const running = useSession(s => s.running) ?? false + const retryableFailure = useProjection('conversationContinuation') ?? undefined + const pendingHumanInput = useProjection('inbox', inbox => + inbox?.['next-step'].some(message => + typeof message === 'object' && message !== null && 'source' in message + && typeof message.source === 'object' && message.source !== null && 'kind' in message.source + && message.source.kind === 'user') ?? false) + const historyOpen = useSession(s => s.openState === 'open') ?? false + const submissionPending = useSession(s => s.pendingSubmissions.length > 0) ?? false const subagent = useSession(s => s.subagent) ?? null const removed = useSession(s => s.removed) ?? false // Plan mode swaps the composer placeholder (the projection is the folded @@ -355,8 +363,12 @@ export const InputBar = memo(function InputBar({ // exposes Stop independently, and so does a running session while a // message waits for the Host. const primaryStops = running && subagent === null && !sending && (empty || blocked !== undefined) + const primaryRetries = !running && subagent === null && empty && retryableFailure !== undefined + && !pendingHumanInput && historyOpen && !submissionPending && !disabled && input.queue.length === 0 + && input.phase === 'plain' && retry !== undefined // Disabled native buttons may omit mouseleave; their tooltip must close from state. - const primaryDisabled = primaryStops ? stopAction === undefined : empty || disabled || machineBusy || uploadsPending + const primaryDisabled = primaryStops ? stopAction === undefined + : (!primaryRetries && empty) || disabled || machineBusy || uploadsPending const interruptible = running && (continuable || (sending && subagent === null)) const primarySubmitMode = resolveSubmitMode(busyEnter, running, 'enter', steeringAvailable) const plainMessageDraft = !empty && input?.phase === 'plain' && !draft.trimStart().startsWith('/') @@ -364,14 +376,20 @@ export const InputBar = memo(function InputBar({ ? t('input.stop') : sending ? t('input.sending') - : running && steeringAvailable && !disabled && !uploadsPending && plainMessageDraft - ? t(primarySubmitMode === 'steer' ? 'input.send.steer' : 'input.send.queue') - : t('input.send') + : primaryRetries + ? t('input.continue') + : running && steeringAvailable && !disabled && !uploadsPending && plainMessageDraft + ? t(primarySubmitMode === 'steer' ? 'input.send.steer' : 'input.send.queue') + : t('input.send') const onPrimary = (): void => { if (primaryStops) { stopAction?.() return } + if (primaryRetries) { + retry(retryableFailure) + return + } if (keyboard === undefined) return // absent machine: the button is disabled /* v8 ignore next -- defensive: the primary button is disabled for empty, disabled, and pending-upload states. */ if (!empty && !disabled && !machineBusy && !uploadsPending) keyboard.submit(primarySubmitMode, 'click') @@ -551,6 +569,8 @@ export const InputBar = memo(function InputBar({ + ) : primaryRetries ? ( + ) : ( diff --git a/packages/client/ui-conversation/src/index.ts b/packages/client/ui-conversation/src/index.ts index afb38b5fe0..90c4366a1a 100644 --- a/packages/client/ui-conversation/src/index.ts +++ b/packages/client/ui-conversation/src/index.ts @@ -1,4 +1,4 @@ -/** Host registration for browser conversation preferences. */ +/** Browser conversation preferences. */ import type {} from '@deepseek-ai/dsh-settings' import type { Volatile, Context } from '@deepseek-ai/cordis' @@ -24,7 +24,7 @@ export const Config = z.object({ [BUSY_ENTER_FIELD]: ConversationSettingsFields[BUSY_ENTER_FIELD].volatile(), }) -/** Host preferences are consumed through the configuration form projection. +/** Register browser conversation preferences. * @param ctx Plugin context used for optional settings presentation. */ export function apply(ctx: Context): void { diff --git a/packages/client/ui-conversation/tests/apply-inject.client.spec.tsx b/packages/client/ui-conversation/tests/apply-inject.client.spec.tsx index d968bdc4d8..e6384343ef 100644 --- a/packages/client/ui-conversation/tests/apply-inject.client.spec.tsx +++ b/packages/client/ui-conversation/tests/apply-inject.client.spec.tsx @@ -7,6 +7,7 @@ import { registerComposerKeymap } from '../src/client/input/editor/keymap.ts' import { createSnapshotStore } from '@deepseek-ai/dsh-client-store' import { describe, expect, it, onTestFinished, vi } from 'vitest' import type { CommandContribution, CommandUiContract } from '@deepseek-ai/dsh-client-ui-commands/client' +import type { SessionRequestId } from '@deepseek-ai/dsh-api-session-controller/types' import type { ISession, SessionReference } from '@deepseek-ai/dsh-api-session-controller/client' import { LocaleRuntime } from '@deepseek-ai/dsh-client-locale/client' import * as messageQuotes from '@deepseek-ai/dsh-message-quotes/client' @@ -24,6 +25,10 @@ import type { WorkspaceId } from '@deepseek-ai/dsh-workspace/types' import { createConversationStore } from '../src/client/stores.ts' import type { SessionInputShell } from '../src/client/input/facade.ts' import { RemoteError } from '@deepseek-ai/dsh-client-test-runtime' +import { SessionSeq } from '@deepseek-ai/dsh-session/types' +import { createUserMessage } from '@deepseek-ai/dsh-llm' +import type { InboxWireState } from '@deepseek-ai/dsh-agent/types' +import { continuationTurn } from './continuation-fixture.ts' declare module '@deepseek-ai/dsh-client-ui-slots' { interface SlotMap { @@ -161,6 +166,125 @@ async function bench(renderQuote = false) { } describe('Conversation inject API', () => { + it.each(['zh', 'en'])('submits empty continuation input in the %s locale', async (locale) => { + const b = await bench() + onTestFinished(() => b.runtime.dispose()) + await b.runtime.sessions.replaceEvents(ROOT, continuationTurn({ kind: 'error', error: { code: 'SERVER', message: 'busy' } })) + await b.runtime.sessions.setProjection(ROOT, 'conversationContinuation', SessionSeq(5)) + const composer = b.composerApi(ROOT) + b.runtime.ctx.locale.setLocale(locale) + const pending = Promise.withResolvers>>() + onTestFinished(() => { pending.resolve({ ok: true, value: { accepted: true } }) }) + b.sessionFake.prompt.mockImplementationOnce(() => pending.promise) + composer.retry!(SessionSeq(5)) + composer.retry!(SessionSeq(5)) + expect(composer.keyboard!.snapshot.phase).toBe('sending') + await vi.waitFor(() => { expect(b.sessionFake.prompt).toHaveBeenCalledOnce() }) + expect(b.sessionFake.prompt.mock.calls[0]?.[0]).toEqual([]) + expect(b.sessionFake.prompt.mock.calls[0]?.[1]).toBe('queue') + pending.resolve({ ok: true, value: { accepted: true } }) + await vi.waitFor(() => { expect(composer.keyboard!.snapshot.phase).toBe('plain') }) + expect(composer.keyboard!.snapshot.draft).toBe('') + }) + + it('rechecks the addressed failure, draft, and live activity before continuing', async () => { + const b = await bench() + onTestFinished(() => b.runtime.dispose()) + await b.runtime.sessions.replaceEvents(ROOT, continuationTurn({ kind: 'error', error: { code: 'TIMEOUT', message: 'timeout' } })) + await b.runtime.sessions.setProjection(ROOT, 'conversationContinuation', SessionSeq(5)) + const composer = b.composerApi(ROOT) + const input = b.inputApi(ROOT) + composer.retry!(SessionSeq(1)) + input.actions.setDraft('Keep my new instruction') + composer.retry!(SessionSeq(5)) + expect(input.state.getSnapshot().draft).toBe('Keep my new instruction') + input.actions.setDraft('') + await b.runtime.sessions.updateSessionSnapshot(ROOT, (state) => { state.running = true }) + composer.retry!(SessionSeq(5)) + await b.runtime.sessions.updateSessionSnapshot(ROOT, (state) => { state.running = false }) + await b.runtime.sessions.appendEvent(ROOT, { + type: 'event', event: { type: 'turn/start', seq: SessionSeq(6), time: 1, data: { turn: 2 } }, + }) + await b.runtime.sessions.setProjection(ROOT, 'conversationContinuation', null) + composer.retry!(SessionSeq(5)) + expect(input.state.getSnapshot().draft).toBe('') + expect(b.sessionFake.prompt).not.toHaveBeenCalled() + }) + + it('keeps continuation available with injected mode context but excludes pending human steering', async () => { + const b = await bench() + onTestFinished(() => b.runtime.dispose()) + await b.runtime.sessions.setProjection(ROOT, 'conversationContinuation', SessionSeq(5)) + const composer = b.composerApi(ROOT) + const context = { id: 'context', role: 'user', content: [{ type: 'text', text: 'approval policy context' }], source: { kind: 'user-approval' } } + const inbox: InboxWireState = { 'next-turn': [], 'next-step': [context] } + await b.runtime.sessions.setProjection(ROOT, 'inbox', inbox) + const user = createUserMessage({ content: [{ type: 'text', text: 'new instruction' }], source: { kind: 'user' } }) + await b.runtime.sessions.setProjection(ROOT, 'inbox', { ...inbox, 'next-step': [context, user] }) + composer.retry!(SessionSeq(5)) + expect(b.sessionFake.prompt).not.toHaveBeenCalled() + await b.runtime.sessions.setProjection(ROOT, 'inbox', inbox) + composer.retry!(SessionSeq(5)) + await vi.waitFor(() => { expect(b.sessionFake.prompt).toHaveBeenCalledOnce() }) + expect(b.sessionFake.prompt.mock.calls[0]?.[0]).toEqual([]) + }) + + it.each(['next-turn', 'pending', 'block', 'attachment', 'subagent', 'removed', 'closed'] as const)( + 'rejects a stale continuation click after %s changes', async (condition) => { + const b = await bench() + onTestFinished(() => b.runtime.dispose()) + await b.runtime.sessions.setProjection(ROOT, 'conversationContinuation', SessionSeq(5)) + const composer = b.composerApi(ROOT) + switch (condition) { + case 'pending': + await b.runtime.sessions.updateSessionSnapshot(ROOT, (state) => { state.pendingSubmissions = [{ requestId: 'pending' as SessionRequestId, placement: 'transcript', time: 0, text: 'newer message', attachments: [] }] }) + break + case 'next-turn': + await b.runtime.sessions.setProjection(ROOT, 'inbox', { 'next-turn': [createUserMessage({ content: [{ type: 'text', text: 'queued' }], source: { kind: 'user' } })], 'next-step': [] }) + break + case 'block': + b.runtime.ctx.conversation.blocks.set(ROOT, { reason: 'Choose a model' }) + break + case 'attachment': + expect(composer.addFiles?.([new File([Uint8Array.of(1)], 'draft.pdf', { type: 'application/pdf' })])).toBeNull() + break + case 'subagent': + await b.runtime.sessions.updateSessionSnapshot(ROOT, (state) => { state.subagent = { address: { parentSessionId: ROOT, childSessionId: ROOT, mode: 'continuable' } } }) + break + case 'removed': + await b.runtime.sessions.updateSessionSnapshot(ROOT, (state) => { state.removed = true }) + break + case 'closed': + await b.runtime.sessions.updateSessionSnapshot(ROOT, (state) => { state.openState = 'error' }) + break + } + const before = b.inputApi(ROOT).state.getSnapshot().draft + composer.retry!(SessionSeq(5)) + expect(b.inputApi(ROOT).state.getSnapshot().draft).toBe(before) + expect(b.sessionFake.prompt).not.toHaveBeenCalled() + }, + ) + + it.each(['refused', 'failed'] as const)('keeps continuation input empty and exposes submission failure when %s', async (outcome) => { + const b = await bench() + onTestFinished(() => b.runtime.dispose()) + await b.runtime.sessions.setProjection(ROOT, 'conversationContinuation', SessionSeq(5)) + const composer = b.composerApi(ROOT) + if (outcome === 'refused') b.sessionFake.prompt.mockImplementationOnce(async () => { + const error = new RemoteError('gateway/internal', 'request refused', {}) + await b.runtime.sessions.updateSessionSnapshot(ROOT, (state) => { state.promptError = { op: 'send', error } }) + return { ok: false, error } + }) + else b.sessionFake.prompt.mockRejectedValueOnce(new Error('connection lost')) + composer.retry!(SessionSeq(5)) + await vi.waitFor(() => { expect(b.sessionFake.prompt).toHaveBeenCalledOnce(); expect(composer.keyboard!.snapshot.phase).toBe('plain') }) + expect(composer.keyboard!.snapshot.draft).toBe('') + if (outcome === 'refused') expect(b.runtime.sessions.binding(ROOT)!.session.getSnapshot().promptError?.error.message).toBe('request refused') + else expect(composer.hooks.notices.getSnapshot()).toMatchObject({ level: 'error', text: 'connection lost' }) + composer.retry!(SessionSeq(5)) + await vi.waitFor(() => { expect(b.sessionFake.prompt).toHaveBeenCalledTimes(2) }) + }) + it('renders literal quote text through the actual Factory and keyed node registration', async () => { const b = await bench(true) onTestFinished(() => b.runtime.dispose()) diff --git a/packages/client/ui-conversation/tests/config.host.spec.ts b/packages/client/ui-conversation/tests/config.host.spec.ts index 7b87d23d59..25420eff00 100644 --- a/packages/client/ui-conversation/tests/config.host.spec.ts +++ b/packages/client/ui-conversation/tests/config.host.spec.ts @@ -1,17 +1,22 @@ +import SessionStore from '@deepseek-ai/dsh-session' +import SessionProjectionRegistry from '@deepseek-ai/dsh-session-projection' import { Context } from '@deepseek-ai/cordis' -import { describe, expect, it } from 'vitest' +import { describe, expect, it, onTestFinished } from 'vitest' import * as HostPlugin from '../src/index.ts' import { liveConfig, omitsGeneratedPage } from '../../../settings/settings/tests/live-config.ts' import { plainConfig } from '../../../settings/settings/src/schema.ts' import { - DEFAULT_BUSY_ENTER_BEHAVIOR, Config, apply, + DEFAULT_BUSY_ENTER_BEHAVIOR, } from '@deepseek-ai/dsh-client-ui-conversation' describe('ui-conversation host', () => { it('registers, validates, and disposes the durable busy-Enter preference', async () => { const ctx = new Context() - const configuration = await liveConfig(ctx, { Config, apply }) + onTestFinished(() => ctx.fiber.dispose()) + await ctx.plugin(SessionStore) + await ctx.plugin(SessionProjectionRegistry) + const configuration = await liveConfig(ctx, HostPlugin) const { fiber } = configuration expect(plainConfig(configuration.fiber.effectiveConfig)).toEqual({ busyEnter: DEFAULT_BUSY_ENTER_BEHAVIOR }) await configuration.update({ busyEnter: 'steer' }) @@ -21,4 +26,9 @@ describe('ui-conversation host', () => { }) }) -it('keeps its own instance off the generated Settings pages', () => omitsGeneratedPage(ctx => ctx.plugin(HostPlugin))) +it('keeps its own instance off the generated Settings pages', () => omitsGeneratedPage(async (ctx) => { + onTestFinished(() => ctx.fiber.dispose()) + await ctx.plugin(SessionStore) + await ctx.plugin(SessionProjectionRegistry) + return ctx.plugin(HostPlugin) +})) diff --git a/packages/client/ui-conversation/tests/continuation-fixture.ts b/packages/client/ui-conversation/tests/continuation-fixture.ts new file mode 100644 index 0000000000..392f01d39a --- /dev/null +++ b/packages/client/ui-conversation/tests/continuation-fixture.ts @@ -0,0 +1,28 @@ +/** Admitted input and a settled turn for manual-continuation tests. */ +import type { SessionEvent } from '@deepseek-ai/dsh-session/types' +import { createUserMessage } from '@deepseek-ai/dsh-llm' +import { SessionSeq } from '@deepseek-ai/dsh-session/types' +import type { TurnEndReason } from '@deepseek-ai/dsh-session/types' + +/** + * Build one settled turn with ordinary user input. + * @param reason - recorded turn ending. + * @param number - turn number and corresponding event offset. + * @returns ordered durable entries. + */ +export function continuationTurn(reason: TurnEndReason, number = 1): { type: 'event'; event: SessionEvent }[] { + const offset = (number - 1) * 6 + return [ + { type: 'event', event: { type: 'turn/start', seq: SessionSeq(offset), time: 0, data: { turn: number } } }, + { type: 'event', event: { type: 'step/start', seq: SessionSeq(offset + 1), time: 0, data: { turn: number, step: 1 } } }, + { type: 'event', event: { + type: 'user/message', seq: SessionSeq(offset + 2), time: 0, surfaceOp: 'append', + data: createUserMessage({ content: [{ type: 'text', text: 'task' }], source: { kind: 'user' } }), + } }, + { type: 'event', event: { + type: 'assistant/attempt', seq: SessionSeq(offset + 3), time: 0, data: { turn: number, step: 1, stream: [] }, + } }, + { type: 'event', event: { type: 'step/end', seq: SessionSeq(offset + 4), time: 0, data: { turn: number, step: 1 } } }, + { type: 'event', event: { type: 'turn/end', seq: SessionSeq(offset + 5), time: 0, data: { turn: number, reason } } }, + ] +} diff --git a/packages/client/ui-conversation/tests/input-bar.client.spec.tsx b/packages/client/ui-conversation/tests/input-bar.client.spec.tsx index a5aceea1b1..69499cdff4 100644 --- a/packages/client/ui-conversation/tests/input-bar.client.spec.tsx +++ b/packages/client/ui-conversation/tests/input-bar.client.spec.tsx @@ -26,7 +26,7 @@ import type { SessionListState, SessionSnapshot } from '@deepseek-ai/dsh-api-ses import type { ContextPressureProjection } from '@deepseek-ai/dsh-token-meter/client' import { zh as commonZh } from '@deepseek-ai/dsh-client-locale/src/locales/zh.ts' import type { Context } from '@deepseek-ai/cordis' -import type { SessionId } from '@deepseek-ai/dsh-session/types' +import type { SessionId, SessionSeq } from '@deepseek-ai/dsh-session/types' import type { SubmitOutcome } from '../src/client/contract/input.ts' import { SessionInputShell } from '../src/client/input/facade.ts' import { $replaceDetectSpanWithText, $selectDetectSpan } from '../src/client/input/editor/span-map.ts' @@ -81,6 +81,7 @@ interface BenchOptions { } draft?: string running?: boolean + retryableFailure?: SessionSeq subagent?: Exclude disabled?: boolean inert?: boolean @@ -161,6 +162,7 @@ function bench(over?: BenchOptions) { if (over?.draft !== undefined && over.draft !== '') shell.setDraft(over.draft) if (over?.attachments !== undefined) shell.addAttachments(over.attachments.map(attachment => attachment.id)) const stop = vi.fn() + const retry = vi.fn() const removeAttachment = vi.fn((id: DraftAttachmentId) => { shell.removeAttachment(id) }) const menuLauncher = createSnapshotStore(over?.commandMenuOpen === true ? 'command' : null) const busyEnter = createSnapshotStore<'queue' | 'steer'>(over?.busyEnter ?? 'queue') @@ -197,12 +199,14 @@ function bench(over?: BenchOptions) { ...allowAllAccess, useContextMenu: contextMenuHook(), useAccess: endpoint => !(over?.deniedEndpoints ?? []).includes(endpoint), - useProjection: ((key: string, selector?: (v: unknown) => unknown) => - (selector ?? (v => v))(key === 'plan' + useProjection: ((key: string, selector: (v: unknown) => unknown = v => v) => + selector(key === 'plan' ? over?.plan : key === 'goal' ? over?.goal - : key === 'imageLimits' ? over?.imageLimits - : key === 'contextPressure' ? over?.contextPressure : undefined)), + : key === 'conversationContinuation' ? over?.retryableFailure + : key === 'inbox' ? { 'next-turn': over?.queue ?? [], 'next-step': over?.nextStep ?? [] } + : key === 'imageLimits' ? over?.imageLimits + : key === 'contextPressure' ? over?.contextPressure : undefined)), useInput: bindSnapshotSelector(shell.state), inputActions: shell.actions, keyboard: shell, @@ -216,6 +220,7 @@ function bench(over?: BenchOptions) { }), toggleCommandMenu: over?.toggleCommandMenu ?? vi.fn(), useBusyEnter: bindSnapshotSelector(busyEnter), + retry, useStopShortcut: bindSnapshotSelector(stopShortcut), useNotices: bindSnapshotSelector(shell.notices), useLexicon: bindSnapshotSelector(shell.lexicon), @@ -252,20 +257,47 @@ function bench(over?: BenchOptions) { const plainMessageDraft = sendableDraft && !uploadsPending && !(over?.draft?.trimStart().startsWith('/') ?? false) const primaryLabel = primaryStops ? '停止生成' - : over?.running === true && steeringAvailable && !composerLocked && plainMessageDraft - ? (over.busyEnter === 'steer' ? '插话发送' : '排队发送') - : '发送消息' + : over?.retryableFailure !== undefined && !sendableDraft && over.running !== true && over.subagent === undefined && !composerLocked + && !(over.nextStep ?? []).some(message => message.source.kind === 'user') + ? '继续生成' + : over?.running === true && steeringAvailable && !composerLocked && plainMessageDraft + ? (over.busyEnter === 'steer' ? '插话发送' : '排队发送') + : '发送消息' const button = view.container.querySelector(`button[aria-label="${primaryLabel}"]`)! const interruptButton = view.container.querySelector('button[aria-label="停止生成"]') return { view, textarea, button, interruptButton, props, sink, shell, wiring: shell, session, stop, removeAttachment, slotCalls, - menuLauncher, busyEnter, stopShortcut, + menuLauncher, busyEnter, stopShortcut, retry, steerQueue: over?.steerQueue, get placeholder() { return placeholderOf(view.container) }, get inputDisabled() { return textarea.getAttribute('aria-disabled') === 'true' }, } } +it('offers the play action only for an empty, idle composer with an eligible failure', async () => { + const b = bench({ retryableFailure: 2 as SessionSeq }) + expect(b.button.disabled).toBe(false) + expect(b.button.querySelector('svg')).not.toBeNull() + fireEvent.click(b.button) + expect(b.retry).toHaveBeenCalledExactlyOnceWith(2) + expect(b.sink).not.toHaveBeenCalled() + await act(async () => { b.shell.setDraft('A new instruction') }) + const send = b.view.getByRole('button', { name: '发送消息' }) + fireEvent.click(send) + await vi.waitFor(() => { expect(b.sink).toHaveBeenCalledOnce() }) + expect(b.sink.mock.calls[0]?.[0]).toBe('A new instruction') + expect(b.retry).toHaveBeenCalledOnce() +}) + +it.each([ + { running: true }, { attachments: [{ kind: 'image' as const, id: 'image' as DraftAttachmentId, file: new File([], 'x.png'), previewUrl: 'blob:test' }] }, + { blocked: { reason: 'Select a model' } }, { subagent: CONTINUABLE_CHILD }, { deniedEndpoints: ['session/prompt'] }, + { nextStep: [row('new instruction')] }, +])('keeps the continue action unavailable with %j', (options) => { + const b = bench({ ...options, retryableFailure: 2 as SessionSeq }) + expect(b.view.queryByRole('button', { name: '继续生成' })).toBeNull() +}) + function attachmentOwner(slotCalls: readonly { key: string; owner: unknown }[]): ComposerAttachmentsOwnerProps { for (let i = slotCalls.length - 1; i >= 0; i -= 1) { const call = slotCalls[i] diff --git a/packages/client/ui-conversation/tests/input-matrix.client.spec.tsx b/packages/client/ui-conversation/tests/input-matrix.client.spec.tsx index 517848498a..a4963d15ac 100644 --- a/packages/client/ui-conversation/tests/input-matrix.client.spec.tsx +++ b/packages/client/ui-conversation/tests/input-matrix.client.spec.tsx @@ -86,6 +86,7 @@ function mountBar(shell: SessionInputShell, over?: { running?: boolean; disabled })), toggleCommandMenu: vi.fn(), useBusyEnter: bindSnapshotSelector(createSnapshotStore<'queue' | 'steer'>('queue')), + retry: undefined, useStopShortcut: bindSnapshotSelector(createSnapshotStore([])), useNotices: bindSnapshotSelector(shell.notices), useLexicon: bindSnapshotSelector(shell.lexicon), diff --git a/packages/client/ui-conversation/tests/input-scenarios.client.spec.tsx b/packages/client/ui-conversation/tests/input-scenarios.client.spec.tsx index 2129c605d2..82c9ba4d56 100644 --- a/packages/client/ui-conversation/tests/input-scenarios.client.spec.tsx +++ b/packages/client/ui-conversation/tests/input-scenarios.client.spec.tsx @@ -202,6 +202,7 @@ async function scopedBench(register?: (inputTriggers: InputTriggerService) => vo useMenuLauncher: bindSnapshotSelector(controller.launcher), renderSlot: (() => null) as InputBarProps['renderSlot'], stop: vi.fn(), + retry: undefined, useStopShortcut: bindSnapshotSelector(createSnapshotStore([])), t: makeTranslate(zh, commonZh), variant: 'composer', diff --git a/packages/client/ui-conversation/tests/skeleton.client.spec.tsx b/packages/client/ui-conversation/tests/skeleton.client.spec.tsx index 28910ea625..ff9f49b18c 100644 --- a/packages/client/ui-conversation/tests/skeleton.client.spec.tsx +++ b/packages/client/ui-conversation/tests/skeleton.client.spec.tsx @@ -315,6 +315,7 @@ function mount( resolveDraftAttachments={() => []} toggleCommandMenu={vi.fn()} useBusyEnter={bindSnapshotSelector(createSnapshotStore<'queue' | 'steer'>('queue'))} + retry={undefined} useStopShortcut={bindSnapshotSelector(createSnapshotStore([]))} useNotices={bindSnapshotSelector(wiring.notices)} useLexicon={bindSnapshotSelector(wiring.lexicon)} diff --git a/packages/client/ui-conversation/tsconfig.client.json b/packages/client/ui-conversation/tsconfig.client.json index 0187cf5d72..c75fd6b50d 100644 --- a/packages/client/ui-conversation/tsconfig.client.json +++ b/packages/client/ui-conversation/tsconfig.client.json @@ -110,6 +110,7 @@ } ], "exclude": [ - "src/index.ts" + "src/index.ts", + "src/host" ] } diff --git a/packages/client/ui-subagent/README.i18n.yaml b/packages/client/ui-subagent/README.i18n.yaml index 76f6abf9bd..32d15ae638 100644 --- a/packages/client/ui-subagent/README.i18n.yaml +++ b/packages/client/ui-subagent/README.i18n.yaml @@ -15,11 +15,11 @@ en: d152484eb41ac6b4 zh: 09388d293f9be9cb /deepseek-ai-dsh-client-ui-subagent/use-this-package: - en: 1a2c831af628c278 - zh: 42ad333c5010e708 + en: bc1c5164849937a8 + zh: e03adf54d2d5a668 /deepseek-ai-dsh-client-ui-subagent/use-this-package/browsing-the-tree: - en: 4ecdca030e42109d - zh: 406b08590ba8df83 + en: 5ea28139189887e9 + zh: f5a51f041c39b0fa /deepseek-ai-dsh-client-ui-subagent/use-this-package/continuing-a-conversation: en: e4ec261d3b122eb5 zh: 320bb2efc93dccdc diff --git a/packages/client/ui-subagent/README.md b/packages/client/ui-subagent/README.md index 971cc3c3cd..764025ddfa 100644 --- a/packages/client/ui-subagent/README.md +++ b/packages/client/ui-subagent/README.md @@ -25,7 +25,7 @@ Browse local subagent conversations and external tasks from the parent header. L ## Use this package -The session header uses the session title for ordinary breadcrumbs. Subagent breadcrumbs prefer the original creation description (`entry.label`), then the Session id. Ordinary and subagent breadcrumb titles both use 14px text with a 20px line height. When the session's direct catalog has entries or a read has failed, the descendant-count trigger renders after the preset label in the header actions band, with no breadcrumb separator. An absent or empty catalog hides the count trigger unless the root Session has an enabled, available Team board with shared tasks or a task-record error. Enabling Team mode alone does not show an empty entry. The trigger opens that direct catalog, uses the total count as its accessible name and the running count as its accessible description, and loads nested catalogs only when their rows expand. Select a local child at any depth to open that child's conversation with its exact `{parentSessionId, childSessionId, mode}` address, or use a noncurrent local row's trailing arrow to open the same address in the right Sidebar, preferring a separate pane when room permits. +The session header uses the session title for ordinary breadcrumbs. Subagent breadcrumbs prefer the original creation description (`entry.label`), then the agent name (`entry.name`), then the Session id. Ordinary and subagent breadcrumb titles both use 14px text with a 20px line height. When the session's direct catalog has entries or a read has failed, the descendant-count trigger renders after the preset label in the header actions band, with no breadcrumb separator. An absent or empty catalog hides the count trigger unless the root Session has an enabled, available Team board with shared tasks or a task-record error. Enabling Team mode alone does not show an empty entry. The trigger opens that direct catalog, uses the total count as its accessible name and the running count as its accessible description, and loads nested catalogs only when their rows expand. Select a local child at any depth to open that child's conversation with its exact `{parentSessionId, childSessionId, mode}` address, or use a noncurrent local row's trailing arrow to open the same address in the right Sidebar, preferring a separate pane when room permits. This package registers the `dsh-resource://subagentchat/session/?parent=&mode=` resource and builtin Sidebar tab type. The resource retains the child `SessionReference` directly from its address without refreshing the parent catalog, and releases the reference when the tab record closes. The tab renders the shared `conversation.content` Factory through `sidebar.chat.conversation`, fixes the local View to Chat, and omits the main Conversation header and width controls. @@ -39,7 +39,7 @@ The wide root count trigger shows a 14px Users icon in its 14px slot when no chi Count, owner, and sidebar-action tooltips appear after 500ms of hover. Hovering a text-visible trigger opens its catalog after 150ms; leaving both trigger and catalog closes it after 120ms. Clicking the descendant-count trigger opens and pins its catalog, or closes an already pinned catalog. The icon-only count trigger does not open on hover, including when a pending hover crosses into the narrow layout. Clicking toggles its pinned menu; ArrowDown opens and pins the menu and focuses its first row. Outside click or Escape dismisses a pinned menu. Clicking moves focus into the panel, where ArrowDown/Home enters the first tree row and ArrowUp/End enters the last; Escape returns focus when it was inside. Breadcrumb-title clicks navigate to the corresponding conversation. -Rows show the creation description, or an available Session title, above the Session id. Without either description, the row shows only its Session id. Local rows use compact 4px vertical padding; their clickable content uses 6px horizontal padding and 7px gaps, aligned with shared-task rows while retaining the tree's left offset. A decorative trailing check marks the current conversation and is not an action; other local rows retain the sidebar arrow. Primary titles use 13px text and secondary ids use 12px. All rows wrap descriptions and ids in full, including on touch screens. Running uses the shared ongoing loader, an inactive child whose latest closed turn completed normally uses the shared success dot, and other inactive children use the shared idle dot. Every row reserves the same 14px status column, centering smaller dots so titles align with the loader state. The text-visible header trigger vertically centers its activity glyph and count with a 4px gap. The trailing column stacks total durable provider usage above active-turn duration. Keyboard navigation works with ArrowRight/ArrowLeft to expand and collapse branches and ArrowUp/ArrowDown, Home, End, and Escape to navigate or close the tree. An unlabeled one-shot row falls back to its session id. A row is a known leaf only after its own catalog loads empty. +Rows show the creation description, or an available Session title, above the agent name, which is unique among its siblings. Entries recorded without a name show the Session id in its place. Without either description, the row shows only the name or Session id. Navigation, row identity, and Sidebar addresses always use the Session id. Local rows use compact 4px vertical padding; their clickable content uses 6px horizontal padding and 7px gaps, aligned with shared-task rows while retaining the tree's left offset. A decorative trailing check marks the current conversation and is not an action; other local rows retain the sidebar arrow. Primary titles use 13px text and secondary names use 12px. All rows wrap descriptions and names in full, including on touch screens. Running uses the shared ongoing loader, an inactive child whose latest closed turn completed normally uses the shared success dot, and other inactive children use the shared idle dot. Every row reserves the same 14px status column, centering smaller dots so titles align with the loader state. The text-visible header trigger vertically centers its activity glyph and count with a 4px gap. The trailing column stacks total durable provider usage above active-turn duration. Keyboard navigation works with ArrowRight/ArrowLeft to expand and collapse branches and ArrowUp/ArrowDown, Home, End, and Escape to navigate or close the tree. An unlabeled one-shot row falls back to its session id. A row is a known leaf only after its own catalog loads empty. ### Continuing a conversation diff --git a/packages/client/ui-subagent/README.zh.md b/packages/client/ui-subagent/README.zh.md index d45e0b49fa..52d9abc110 100644 --- a/packages/client/ui-subagent/README.zh.md +++ b/packages/client/ui-subagent/README.zh.md @@ -25,7 +25,7 @@ kind: "package-reference" ## 使用本包 -会话页头的普通面包屑使用会话标题。subagent 面包屑优先使用创建时的原始描述(`entry.label`),缺少时回退到 Session id。普通与 subagent 面包屑标题均使用 14px 文字和 20px 行高。当会话的直接目录有子项或读取失败时,后代数量触发器渲染在页头操作区中预设标签之后,不带任何面包屑分隔符。目录缺席或为空时隐藏数量触发器,除非根 Session 已开启且可用的 Team 任务板有共享任务或任务记录错误。仅开启 Team 模式不会显示空入口。触发器打开该直接目录,以总数作为无障碍名称、运行数作为无障碍描述,并且只在行展开时加载嵌套目录。选择任意深度,即可用该子会话的确切 `{parentSessionId, childSessionId, mode}` 地址打开其对话;也可以使用非当前本地行的行尾箭头在右侧 Sidebar 打开同一地址,并在空间允许时优先使用独立分栏。 +会话页头的普通面包屑使用会话标题。subagent 面包屑优先使用创建时的原始描述(`entry.label`),其次使用智能体名称(`entry.name`),最后回退到 Session id。普通与 subagent 面包屑标题均使用 14px 文字和 20px 行高。当会话的直接目录有子项或读取失败时,后代数量触发器渲染在页头操作区中预设标签之后,不带任何面包屑分隔符。目录缺席或为空时隐藏数量触发器,除非根 Session 已开启且可用的 Team 任务板有共享任务或任务记录错误。仅开启 Team 模式不会显示空入口。触发器打开该直接目录,以总数作为无障碍名称、运行数作为无障碍描述,并且只在行展开时加载嵌套目录。选择任意深度,即可用该子会话的确切 `{parentSessionId, childSessionId, mode}` 地址打开其对话;也可以使用非当前本地行的行尾箭头在右侧 Sidebar 打开同一地址,并在空间允许时优先使用独立分栏。 本包注册 `dsh-resource://subagentchat/session/?parent=&mode=` 资源与 builtin Sidebar tab 类型。资源直接根据地址保留 child 的 `SessionReference`,不刷新 parent 目录,并在 tab 记录关闭时释放 reference。tab 通过 `sidebar.chat.conversation` 渲染共享 `conversation.content` Factory,把局部 View 固定为 Chat,并省略主 Conversation 的 Header 与宽度控制。 @@ -39,7 +39,7 @@ kind: "package-reference" 数量、负责人及侧边栏操作的工具提示在悬停 500ms 后显示。悬停文字可见的触发器 150ms 后打开目录;指针离开触发器和目录后,经过 120ms 关闭。点击后代数量触发器会打开并固定目录,或关闭已固定的目录。纯图标数量触发器不会因悬停而打开,包括等待悬停打开期间切换到窄布局的情况。点击可切换固定菜单的开关状态;ArrowDown 会打开并固定菜单,并将焦点移至首行。点击外部或按 Escape 可关闭已固定的菜单。点击会将焦点移入面板,此时 ArrowDown/Home 进入首个树行,ArrowUp/End 进入最后一个树行;Escape 在焦点原本位于面板内时将其送回。点击面包屑标题会导航至对应会话。 -目录行在 Session id 上方显示创建描述,缺少创建描述时使用可用的 Session title。两者均缺少时,该行仅显示 Session id。本地行使用紧凑的 4px 垂直内边距;可点击内容使用 6px 水平内边距和 7px 间距,与共享任务行对齐,同时保留树的左侧偏移。当前对话在行尾显示装饰性对勾,该对勾不是操作控件;其他本地行保留侧边栏箭头。主标题使用 13px 文字,次级 id 使用 12px。所有行均将描述与 id 换行完整展示,包括在触屏上。running 使用共享 ongoing loading,最近一个已结束轮次正常完成的 inactive child 使用共享 success 绿点,其他 inactive child 使用共享 idle 灰点。每行都为状态图标预留相同的 14px 列宽,并将较小的圆点居中,使 title 与 loading 状态对齐。文字可见的页头触发器会垂直居中活动图标与数量,并保留 4px 水平间距。尾随列在上行显示提供方的持久化 token 用量总计,在下行显示活跃轮次耗时。键盘导航:ArrowRight/ArrowLeft 展开和折叠分支;ArrowUp/ArrowDown、Home、End 与 Escape 用于导航或关闭树。没有 label 的 one-shot 行回退到其会话 id。只有一行自身的目录加载为空后,它才是已知叶子。 +目录行在智能体名称上方显示创建描述,缺少创建描述时使用可用的 Session title;名称在同级子智能体中唯一。没有名称的历史目录项在相同位置显示 Session id。两者均缺少时,该行仅显示名称或 Session id。导航、行身份与 Sidebar 地址始终使用 Session id。本地行使用紧凑的 4px 垂直内边距;可点击内容使用 6px 水平内边距和 7px 间距,与共享任务行对齐,同时保留树的左侧偏移。当前对话在行尾显示装饰性对勾,该对勾不是操作控件;其他本地行保留侧边栏箭头。主标题使用 13px 文字,次级名称使用 12px。所有行均将描述与名称换行完整展示,包括在触屏上。running 使用共享 ongoing loading,最近一个已结束轮次正常完成的 inactive child 使用共享 success 绿点,其他 inactive child 使用共享 idle 灰点。每行都为状态图标预留相同的 14px 列宽,并将较小的圆点居中,使 title 与 loading 状态对齐。文字可见的页头触发器会垂直居中活动图标与数量,并保留 4px 水平间距。尾随列在上行显示提供方的持久化 token 用量总计,在下行显示活跃轮次耗时。键盘导航:ArrowRight/ArrowLeft 展开和折叠分支;ArrowUp/ArrowDown、Home、End 与 Escape 用于导航或关闭树。没有 label 的 one-shot 行回退到其会话 id。只有一行自身的目录加载为空后,它才是已知叶子。 ### 续接对话 diff --git a/packages/client/ui-subagent/src/client/SubagentHeaderLineage.tsx b/packages/client/ui-subagent/src/client/SubagentHeaderLineage.tsx index f49169838d..92a802ac66 100644 --- a/packages/client/ui-subagent/src/client/SubagentHeaderLineage.tsx +++ b/packages/client/ui-subagent/src/client/SubagentHeaderLineage.tsx @@ -208,6 +208,11 @@ function isKnownLeaf(catalog: SubagentCatalogSnapshot | undefined): boolean { return catalog?.state === 'ready' && catalog.entries.length === 0 } +/** The agent name unique among the row's siblings, or the Session ID for entries recorded without one. */ +function entryName(entry: SubagentCatalogSnapshot['entries'][number]): string { + return entry.mode === 'continuable' || entry.mode === 'external' ? entry.name ?? entry.id : entry.id +} + /** Only a local child's last closed, normally completed turn receives the completed marker. */ function completedEntry(entry: SubagentCatalogSnapshot['entries'][number], summary: SessionSummary | undefined): boolean { return entry.mode !== 'external' && entry.activity === 'inactive' @@ -282,8 +287,9 @@ function CatalogRows({ || (childCatalog.state === 'loading' && childCatalog.entries.length === 0) const summary = summaries[entry.id] const description = entry.label || summary?.title - const primaryLabel = description || entry.id - const secondaryLabel = description ? entry.id : undefined + const name = entryName(entry) + const primaryLabel = description || name + const secondaryLabel = description ? name : undefined const mode = external ? t('mode.external') : entry.mode === 'unknown' ? t('mode.unknown') : entry.mode === 'one-shot' ? t('mode.oneShot') : t('mode.continuable') const completed = completedEntry(entry, summary) @@ -531,7 +537,7 @@ function CatalogDropdown(props: CatalogDropdownProps) { ? undefined : catalog?.entries.find(entry => entry.id === currentSessionId) const switcherDisplayTitle = currentEntry !== undefined - ? currentEntry.label || currentEntry.id + ? currentEntry.label || entryName(currentEntry) : displayTitle const directChildren = catalog?.entries ?? [] const directCount = directChildren.length diff --git a/packages/client/ui-subagent/tests/conversation-ui.client.spec.tsx b/packages/client/ui-subagent/tests/conversation-ui.client.spec.tsx index 35afb40e1d..43d2255936 100644 --- a/packages/client/ui-subagent/tests/conversation-ui.client.spec.tsx +++ b/packages/client/ui-subagent/tests/conversation-ui.client.spec.tsx @@ -316,6 +316,29 @@ describe('SubagentHeaderLineage', () => { expect(row.getAttribute('aria-label')).toMatch(new RegExp(`^${CHILD}`)) }) + it('shows agent names in place of Session ids while navigation keeps the Session id', () => { + const external = 'external-id' as SessionId + const input = props(catalog({ + entries: [ + { id: CHILD, mode: 'continuable', label: 'Review the diff', name: 'reviewer', activity: 'running' }, + { id: GRANDCHILD, mode: 'continuable', label: '', name: 'checker', activity: 'inactive' }, + { id: external, mode: 'external', name: 'outside', activity: 'inactive' }, + ], + }), {}, { [CHILD]: { ...summary(CHILD, 1), running: true } }) + render() + fireEvent.click(screen.getByRole('button', { name: /\d+ 个子智能体$/ })) + const named = screen.getByRole('treeitem', { name: /^Review the diff reviewer/ }) + expect(within(named).getByText('Review the diff').compareDocumentPosition(within(named).getByText('reviewer')) + & Node.DOCUMENT_POSITION_FOLLOWING).toBeTruthy() + expect(within(named).queryByText(CHILD)).toBeNull() + const undescribed = screen.getByRole('treeitem', { name: /^checker/ }) + expect(within(undescribed).getAllByText('checker')).toHaveLength(1) + expect(within(undescribed).queryByText(GRANDCHILD)).toBeNull() + expect(screen.getByRole('treeitem', { name: /^outside/ }).getAttribute('aria-disabled')).toBe('true') + fireEvent.click(named) + expect(input.openChild).toHaveBeenCalledExactlyOnceWith({ parentSessionId: PARENT, childSessionId: CHILD, mode: 'continuable' }) + }) + it('hides an empty Team entry but keeps shared tasks and errors reachable without children', () => { const input = props(catalog({ entries: [] })) const initial = input.useSessions(state => state) @@ -1598,6 +1621,19 @@ describe('SubagentHeaderLineage', () => { expect(screen.getByRole('button', { name: `切换子智能体:${CHILD}` })).toBeTruthy() }) + it('names the breadcrumb by the agent name when the selected row has an empty description', () => { + const input = { + ...props(catalog({ entries: [{ id: CHILD, mode: 'continuable', label: '', name: 'reviewer', activity: 'inactive' }] }), {}, { + [CHILD]: { ...summary(CHILD, 1), parentId: PARENT, origin: 'subagent' as const }, + }), + sessionId: CHILD, + lineageSessionId: CHILD, + displayTitle: 'summary title', + } + render() + expect(screen.getByRole('button', { name: '切换子智能体:reviewer' }).textContent).toBe('reviewer') + }) + it('keeps an ancestor switcher muted and omits its descendant count and section heading', () => { const input = { ...props(catalog({ team: sharedTeam }), { diff --git a/packages/client/ui-tool/README.i18n.yaml b/packages/client/ui-tool/README.i18n.yaml index b2d8ee1464..258c39deb6 100644 --- a/packages/client/ui-tool/README.i18n.yaml +++ b/packages/client/ui-tool/README.i18n.yaml @@ -15,14 +15,14 @@ en: d152484eb41ac6b4 zh: 09388d293f9be9cb /deepseek-ai-dsh-client-ui-tool/use-this-package: - en: 2419beff9bcd8139 - zh: 5aafe9b168e571a5 + en: 09231e7cc6515a01 + zh: c306bb141cf9bf9d /deepseek-ai-dsh-client-ui-tool/use-this-package/registering-a-business-tool-view: en: e458aff61e634190 zh: 650e417f450b3edf /deepseek-ai-dsh-client-ui-tool/use-this-package/built-in-views: - en: 153498fd97c03524 - zh: 210731b119db29a5 + en: 4f141937224a0390 + zh: b3b8a22df4936742 /deepseek-ai-dsh-client-ui-tool/understand-the-implementation: en: 00bc7b0c84edc603 zh: 1cfcf5b435248a91 @@ -30,8 +30,8 @@ en: 672e63b2f92e689b zh: ba950ecb480325a6 /deepseek-ai-dsh-client-ui-tool/understand-the-implementation/cards: - en: d2ac2f855da27aff - zh: 61d257d60971f259 + en: cf7e57801571d443 + zh: fee3b0b00c6aab69 /deepseek-ai-dsh-client-ui-tool/understand-the-implementation/declared-optional-capabilities: en: c1926deb4e5f3734 zh: c5845f465b94a459 diff --git a/packages/client/ui-tool/README.md b/packages/client/ui-tool/README.md index a55e8ab7ed..ee44939e5a 100644 --- a/packages/client/ui-tool/README.md +++ b/packages/client/ui-tool/README.md @@ -25,15 +25,15 @@ English | [中文](README.zh.md) ## Use this package -Tool calls appear in the conversation as cards: a root call tree with its nested subcalls, each atomic call rendered by its owning view. Every lifecycle state retains the tool's ordinary business glyph; failure and interruption remain explicit through the frozen call/result state, accessible status text, and failure summary. Users can open files or inspect calls through the Host callbacks. A collapsed `web_fetch` row links its http(s) URL, which opens in a new browser tab. Control receipts display the agent ID supplied by the recorded call. Text agent lists show the ID above a single-line description, with compact spacing and recorded status. Click the description to expand or collapse its full text; its accessible name follows the selected locale. +Tool calls appear in the conversation as cards: a root call tree with its nested subcalls, each atomic call rendered by its owning view. Every lifecycle state retains the tool's ordinary business glyph; failure and interruption remain explicit through the frozen call/result state, accessible status text, and failure summary. Users can open files or inspect calls through the Host callbacks. A collapsed `web_fetch` row links its http(s) URL, which opens in a new browser tab. Control receipts display the agent name supplied by the recorded call, or the agent ID in historical calls. Text agent lists show each agent name, or the historical ID, above a single-line description, with compact spacing and recorded status. Click the description to expand or collapse its full text; its accessible name follows the selected locale. Settled foreground commands with a nonzero exit code, a terminating signal, or an explicit missing exit code keep their description in the ordinary gray text and show a neutral capsule with a red dot immediately after it. The capsule displays only the recorded code, signal, or localized missing-code status and stays on the same line; the description truncates with an ellipsis to reserve its space. Running, successful, and background calls omit it. Generic execution errors and stopped summaries retain their error and warning colors, including on hover. Before dispatch, a named model call appears as one non-expandable row with its tool-owned icon and title. A generic row shows `Tool call · `. Read/write/edit show an openable path once `file_path` closes and decodes without errors; write/edit show `NKB` after that path once content arrives, retaining it during execution and after success, before any diff totals. N rounds the decoded input's UTF-16 length up in units of 1024, summing old and new text for edit; it is not file bytes. Error and stopped rows omit the size and diff totals. Command rows show the streamed description. `tool/call` enables the existing call presentation; completing an argument block alone does not start execution. -`subagent` and `subagent_fork` creation rows stream the first line of `description`, retaining it during execution, after creation, and when expanded. After preparation, calls without a description fall back to the first nonempty `prompt` line; missing arguments leave only the tool title. Both tools and `list_subagent_models` use the existing Users icon; `subagent_fork` uses the distinct title “Fork subagent”. Creation receipts show the started state, the full `description` as the agent task description, the recorded agent Session id, and complete task instructions. Current receipts read `kind: activation` and `subagentId` from result metadata; only historical results without metadata use text parsing. Malformed metadata keeps the generic result view. Synchronous agent responses remain in the result body; errors retain their failure summary. +`subagent` and `subagent_fork` creation rows stream the first line of `description`, retaining it during execution, after creation, and when expanded. After preparation, calls without a description fall back to the first nonempty `prompt` line; missing arguments leave only the tool title. Both tools and `list_subagent_models` use the existing Users icon; `subagent_fork` uses the distinct title “Fork subagent”. Creation receipts show the started state, the full `description` as the agent task description, the agent name, and complete task instructions. Current receipts read `kind: activation` and `name` from result metadata. Historical metadata with `subagentId` also displays the agent Session id; only historical results without metadata use text parsing. Malformed metadata keeps the generic result view. Synchronous agent responses remain in the result body; errors retain their failure summary. -File and URL toolview Slots obtain `useContextMenu` directly and supply bound `fileContextMenuProps` or `urlContextMenuProps` to `ToolRow`. File registrations inject a gesture-time path resolver for the originating Session’s working directory, falling back to its workspace root. `ToolCallTree` supplies an explicit file adapter to its plain `GenericToolCard` fallback, including nested calls. No Markdown provider is required. Mouse and keyboard gestures retain the captured path, line, URL, and Session without expanding the row or opening the file. +File and URL toolview Slots obtain `useContextMenu` directly and supply bound `fileContextMenuProps` or `urlContextMenuProps` to `ToolRow`; file rows also supply `fileTargetContextMenuProps` for each per-file patch link. File registrations inject a gesture-time path resolver for the originating Session’s working directory, falling back to its workspace root. `ToolCallTree` supplies an explicit file adapter to its plain `GenericToolCard` fallback, including nested calls. No Markdown provider is required. Mouse and keyboard gestures retain the captured path, line, URL, and Session without expanding the row or opening the file. ### Registering a business tool view @@ -55,7 +55,7 @@ Every registered view receives the explicit `preparing`, `start`, and `result` p File-tool rows prefer a complete `file_path`; other generic rows, including search and unregistered tools, prefer a non-empty `description` before their variant-specific argument fallback. Read `args` during rendering or view construction: a preparing reader grows in place, and only previously observed answer changes trigger subsequent block publication. -This package owns the generic fallback and the built-in shell/pwsh, read, read_image, write/edit, `apply_patch`, running `str_replace_editor` `create`/`str_replace`, grep/glob, web, todo, question, and PTC dispatch presentations. The `apply_patch` row shares the write/edit component: it shows its title without a single-file summary, derives no diff while running, shows the applied hunks from settled `meta.diffs`, and a result whose metadata is marked stopped renders as an error with its failure text beside the known diffs. Structured cards derive directly from first-party raw event fields; Host `presentCall` and `presentResult` values never enter the Client. Running atomic rows share one left-to-right highlight across their titles, separators, summaries, and suffixes, while settled rows stay static. Running and settled foreground standard `bash`/`pwsh` and `terminal_send` calls use terminal cards at the root and in PTC dispatch children, subject to the same argument, result, and error checks. Persistent `bash`/`pwsh` calls use terminal cards only while running. Shell output ending in a recognized spill-policy notice uses expandable generic output in shell rows and generic output in Details; a displaced or omitted exit marker cannot establish success. Settled persistent-shell results stay generic because reset and partial-output diagnostics do not always describe one process exit status; root persistent results are expandable. Valid explicit background `bash`/`pwsh` calls use the terminal Start presentation; a successful launch acknowledgement retains the command and cwd in a static command-only card without output or execution status. Launch failures retain generic arguments and errors, while background `terminal_send` stays generic. Inspect preserves the original arguments and acknowledgement; later job output is not attached to this card ([decision](../../../.agents/notes/implemented/bug-fix/2026-10-10-background-shell-command-display.md)). Expanded terminal commands and background inputs wrap to the available width while preserving authored line breaks and selectable text; terminal output keeps its column-preserving layout. Only horizontal overflow adds a named keyboard focus target. Inspect is available when provided. The acknowledgement does not report the job's exit status. A native or PTC dispatch failure carrying `AUTO_REVIEW_DENIED` shows the Auto review verdict in its collapsed row and one normalized not-executed reason when expanded; a missing or whitespace-only reason uses localized fallback text. `ui-skill` demonstrates a business-owned registration for `skill`. +This package owns the generic fallback and the built-in shell/pwsh, read, read_image, write/edit, `apply_patch`, running `str_replace_editor` `create`/`str_replace`, grep/glob, web, todo, question, and PTC dispatch presentations. The `apply_patch` row shares the write/edit component and the Edit title. Once `input` completes, its summary lists the files that `dsh-fs-patch` `parsePatch` reads from the patch, with a move as `source → destination`; a malformed patch has no summary. A lone added or updated file is one openable path. After a successful result, several files or a move render one link per added, updated, or moved-to file, while move sources and deleted files stay plain text; running and failed rows show the plain list. The row derives no diff while running, shows the applied hunks from settled `meta.diffs`, and a result whose metadata is marked stopped renders as an error with its failure text beside the known diffs. Structured cards derive directly from first-party raw event fields; Host `presentCall` and `presentResult` values never enter the Client. Running atomic rows share one left-to-right highlight across their titles, separators, summaries, and suffixes, while settled rows stay static. Running and settled foreground standard `bash`/`pwsh` and `terminal_send` calls use terminal cards at the root and in PTC dispatch children, subject to the same argument, result, and error checks. Persistent `bash`/`pwsh` calls use terminal cards only while running. Shell output ending in a recognized spill-policy notice uses expandable generic output in shell rows and generic output in Details; a displaced or omitted exit marker cannot establish success. Settled persistent-shell results stay generic because reset and partial-output diagnostics do not always describe one process exit status; root persistent results are expandable. Valid explicit background `bash`/`pwsh` calls use the terminal Start presentation; a successful launch acknowledgement retains the command and cwd in a static command-only card without output or execution status. Launch failures retain generic arguments and errors, while background `terminal_send` stays generic. Inspect preserves the original arguments and acknowledgement; later job output is not attached to this card ([decision](../../../.agents/notes/implemented/bug-fix/2026-10-10-background-shell-command-display.md)). Expanded terminal commands and background inputs wrap to the available width while preserving authored line breaks and selectable text; terminal output keeps its column-preserving layout. Only horizontal overflow adds a named keyboard focus target. Inspect is available when provided. The acknowledgement does not report the job's exit status. A native or PTC dispatch failure carrying `AUTO_REVIEW_DENIED` shows the Auto review verdict in its collapsed row and one normalized not-executed reason when expanded; a missing or whitespace-only reason uses localized fallback text. `ui-skill` demonstrates a business-owned registration for `skill`. Question rows pair answers with questions by id, using the tool result or the `userQuestions` projection for late replies. An answerable call has a button to reopen its panel. Once a late reply is in the agent Inbox, the row shows its submitted answers; “View answers” expands its read-only transcript while admission is pending. A settled call with answers opens the panel read-only. Closed calls without answers and invalid records offer no button. Cancelled and interrupted rows show their verdict without inventing answers. If no panel provider accepts the button action, it expands the row. Unsupported or ambiguous input falls back to flattened Tool text. @@ -93,9 +93,9 @@ Chat diff cards keep nine rows before folding, enough for a file header, one rem An Auto denial takes precedence over keyed specialized views. Its generic row preserves the call identity, omits raw arguments, and normalizes the stored reason only for display: trim surrounding whitespace and collapse line separators to spaces, with localized fallback for an empty result. Session and SDK error details keep the original reason. -Recorded tool details cover goal and schedule tools, Cordis inspection, workflow and Ralph reports, Session event/search/trace queries, agent and teammate controls, background jobs, persistent terminals, and LSP navigation. These expanded bodies read successful logged results, preserve generic input/output for failures or unsupported data, and keep Inspect available. Dates include the viewer's time zone, and statuses reflect the call result rather than current session state. Agent control receipts display the recorded target Session id. `wait_agent` shows a single waiting, ended, or timed-out header without a repeated summary; historical `noProgress` results keep their recorded explanation. Session traces preserve descendant indentation. LSP results open filesystem paths through the Host callback and display other URIs as text. The browser adapter consumes recorded producer text and JSON; Host service objects and presenter callbacks do not cross into the Client. +Recorded tool details cover goal and schedule tools, Cordis inspection, workflow and Ralph reports, Session event/search/trace queries, agent and teammate controls, background jobs, persistent terminals, and LSP navigation. These expanded bodies read successful logged results, preserve generic input/output for failures or unsupported data, and keep Inspect available. Dates include the viewer's time zone, and statuses reflect the call result rather than current session state. Agent control receipts display the recorded target agent name, or the Session id in historical calls. `wait_agent` shows a single waiting, ended, or timed-out header without a repeated summary; historical `noProgress` results keep their recorded explanation. Session traces preserve descendant indentation. LSP results open filesystem paths through the Host callback and display other URIs as text. The browser adapter consumes recorded producer text and JSON; Host service objects and presenter callbacks do not cross into the Client. -Expanded status dots and labels use static semantic colors. Receipt and job-output headers keep neutral text and omit the status while expanded. An interruption receipt confirms only that interruption was requested. +Expanded status dots and labels use static semantic colors. Catalog failure statuses are localized. Team task cards localize the `owner` field; Cordis inspection retains provider-owned field names. Receipt and job-output headers keep neutral text and omit the status while expanded. An interruption receipt confirms only that interruption was requested. Terminal prompt labels use recorded result `cwd`. Older successful root shell calls fall back to their original workspace and authored workdir; running calls show a directory only when their workdir is absolute. Terminal sends do not infer a process directory from the Session. diff --git a/packages/client/ui-tool/README.zh.md b/packages/client/ui-tool/README.zh.md index 55e1fa9ad1..2d82432ef1 100644 --- a/packages/client/ui-tool/README.zh.md +++ b/packages/client/ui-tool/README.zh.md @@ -25,15 +25,15 @@ kind: "package-reference" ## 使用本包 -工具调用在对话中显示为卡片:一个根调用树带其嵌套子调用,每个原子调用由所属视图渲染。所有生命周期状态都保留工具的普通业务图标;失败与中断仍通过冻结调用/结果状态、无障碍状态文本和失败摘要明确表达。用户可通过宿主回调打开文件或检查调用。折叠的 `web_fetch` 行把其 http(s) URL 显示为链接,在新浏览器标签页中打开。控制工具回执显示记录的调用所提供的智能体 ID。文本形式的智能体列表以紧凑间距展示 ID、下方的单行描述及记录中的状态。点击描述可展开或收起全文;其无障碍名称使用当前语言。 +工具调用在对话中显示为卡片:一个根调用树带其嵌套子调用,每个原子调用由所属视图渲染。所有生命周期状态都保留工具的普通业务图标;失败与中断仍通过冻结调用/结果状态、无障碍状态文本和失败摘要明确表达。用户可通过宿主回调打开文件或检查调用。折叠的 `web_fetch` 行把其 http(s) URL 显示为链接,在新浏览器标签页中打开。控制工具回执显示记录的调用所提供的智能体名称,历史调用则显示智能体 ID。文本形式的智能体列表以紧凑间距展示智能体名称(历史记录为 ID)、下方的单行描述及记录中的状态。点击描述可展开或收起全文;其无障碍名称使用当前语言。 已结束的前台命令若返回非零退出码、终止信号,或明确记录为无退出码,描述保持普通灰色,后面紧接带红点的中性胶囊。胶囊仅显示记录的退出码、信号或本地化的“未正常退出”状态,并保持在同一行;描述超出可用宽度时显示省略号,为胶囊预留空间。运行中、成功和后台调用不显示胶囊。通用执行错误与停止摘要仍保留错误色和警告色,悬停时也不改变。 派发前,模型已给出名称的调用显示为不可展开的一行,使用工具自己的图标与标题。通用行显示为 `工具调用 · <工具名>`。read/write/edit 在 `file_path` 闭合且解码无误后显示可打开的路径;write/edit 从内容到达起在该路径后显示 `NKB`,执行中和成功后仍保留,位于差异统计之前。N 按解码后输入的 UTF-16 长度除以 1024 向上取整,edit 合计新旧文本长度;它不是文件字节数。失败和停止的行省略大小与差异统计。命令行显示流入中的描述。`tool/call` 才启用既有调用展示;参数块结束本身不代表开始执行。 -`subagent` 与 `subagent_fork` 的创建行逐步显示 `description` 的首行,执行中、创建完成后和展开时均保留。准备阶段结束后,缺少描述的调用回退到 `prompt` 的首个非空行;参数不可用时仅显示工具标题。两个工具与 `list_subagent_models` 均使用现有的 Users 图标;`subagent_fork` 使用独立标题“派生子智能体”。创建回执显示已启动状态、作为智能体任务描述的完整 `description`、记录的智能体 Session id,以及完整任务指令。当前回执从结果 metadata 读取 `kind: activation` 与 `subagentId`;仅缺少 metadata 的历史结果使用文本解析。metadata 无效时保留通用结果视图。同步返回的 agent 回复仍放在结果正文中;失败时保留错误摘要。 +`subagent` 与 `subagent_fork` 的创建行逐步显示 `description` 的首行,执行中、创建完成后和展开时均保留。准备阶段结束后,缺少描述的调用回退到 `prompt` 的首个非空行;参数不可用时仅显示工具标题。两个工具与 `list_subagent_models` 均使用现有的 Users 图标;`subagent_fork` 使用独立标题“派生子智能体”。创建回执显示已启动状态、作为智能体任务描述的完整 `description`、智能体名称,以及完整任务指令。当前回执从结果 metadata 读取 `kind: activation` 与 `name`。含有 `subagentId` 的历史 metadata 还会显示智能体 Session id;仅缺少 metadata 的历史结果使用文本解析。metadata 无效时保留通用结果视图。同步返回的 agent 回复仍放在结果正文中;失败时保留错误摘要。 -文件和 URL 工具视图 Slot 直接获取 `useContextMenu`,向 `ToolRow` 提供已绑定的 `fileContextMenuProps` 或 `urlContextMenuProps`。文件注册注入在触发时读取原始 Session 工作目录的路径解析器,工作目录缺失时使用工作区根目录。`ToolCallTree` 向普通 `GenericToolCard` fallback 显式提供文件适配函数,包含嵌套调用。无需 Markdown Provider。鼠标和键盘手势保留捕获的路径、行号、URL 与 Session,不会展开工具行或打开文件。 +文件和 URL 工具视图 Slot 直接获取 `useContextMenu`,向 `ToolRow` 提供已绑定的 `fileContextMenuProps` 或 `urlContextMenuProps`;文件行还为补丁的每个文件链接提供 `fileTargetContextMenuProps`。文件注册注入在触发时读取原始 Session 工作目录的路径解析器,工作目录缺失时使用工作区根目录。`ToolCallTree` 向普通 `GenericToolCard` fallback 显式提供文件适配函数,包含嵌套调用。无需 Markdown Provider。鼠标和键盘手势保留捕获的路径、行号、URL 与 Session,不会展开工具行或打开文件。 ### 注册业务工具视图 @@ -55,7 +55,7 @@ owner 载荷为 `ToolCallOwnerProps`:`callId`、`toolName`、`phase` 判别字 文件工具行优先使用完整的 `file_path`;其他通用行(包括搜索和未注册的工具)优先使用非空 `description`,再回退到各自类别的参数摘要。应在渲染或构造视图时读取 `args`:准备态读器原地增长,后续仅在已观察答案变化时重新发布块。 -本包拥有 generic fallback,以及 shell/pwsh、read、read_image、write/edit、`apply_patch`、运行中的 `str_replace_editor` `create`/`str_replace`、grep/glob、web、todo、question 与 PTC dispatch 的内置展示。`apply_patch` 行复用 write/edit 组件:显示工具标题而不给出单文件摘要,运行态不推导 diff,完成态展示 `meta.diffs` 中已应用的 hunk,元数据标记为停止的结果按错误呈现,并在已知 diff 旁保留失败文本。结构化卡片直接从第一方原始 event 字段派生;Host `presentCall` 与 `presentResult` 值不会进入 Client。运行中的原子工具行以同一道高光从左到右扫过标题、分隔符、摘要与后缀;已完成行保持静态。运行中与已完成的前台标准 `bash`/`pwsh` 和 `terminal_send` 调用,无论位于根还是 PTC dispatch 子调用中,都在通过相同的参数、结果和错误检查后使用 terminal 卡片。持久 `bash`/`pwsh` 调用仅在运行中使用 terminal 卡片。以已识别的 spill 策略提示结尾的 shell 输出,在 shell 行中使用可展开的 generic 输出,在 Details 中使用 generic 输出;位置被改变或被省略的退出标记无法证明成功。已完成的持久 shell 结果保持 generic 展示,因为 reset 与部分输出诊断不一定描述单个进程的退出状态;根调用的持久 shell 结果可展开。合法的主动后台 `bash`/`pwsh` 调用使用 terminal Start 展示;成功启动回执后,静态仅命令卡片保留 command 和 cwd,不显示输出或执行状态。启动失败保留通用参数与错误展示,后台 `terminal_send` 仍为 generic。Inspect 保留原始参数及回执,后续 job 输出不接回此卡片([决定](../../../.agents/notes/implemented/bug-fix/2026-10-10-background-shell-command-display.zh.md))。展开的终端命令与后台输入按可用宽度自动折行,保留原有换行和可选文本;终端输出保持按列对齐的排版。仅横向溢出时添加具名的键盘聚焦目标。提供 Inspect 时也可使用。回执不表示后台任务的退出状态。带有 `AUTO_REVIEW_DENIED` 的原生或 PTC dispatch 失败会在折叠行显示 Auto review 裁决,展开时显示一行归一化后的“未执行”原因;原因缺失或只有空白时使用本地化 fallback 文案。`ui-skill` 展示了业务包自行拥有的 `skill` 注册项。 +本包拥有 generic fallback,以及 shell/pwsh、read、read_image、write/edit、`apply_patch`、运行中的 `str_replace_editor` `create`/`str_replace`、grep/glob、web、todo、question 与 PTC dispatch 的内置展示。`apply_patch` 行复用 write/edit 组件与“编辑”标题。`input` 完整到达后,摘要列出 `dsh-fs-patch` 的 `parsePatch` 从补丁读出的文件,移动显示为 `源 → 目标`;格式不合法的补丁没有摘要。单个新增或修改的文件是一个可打开路径。成功结果中有多个文件或含移动时,每个新增、修改或移动目标文件各是一个链接,移动源与被删除文件保持纯文本;运行中与失败的行显示纯文本列表。该行运行态不推导 diff,完成态展示 `meta.diffs` 中已应用的 hunk,元数据标记为停止的结果按错误呈现,并在已知 diff 旁保留失败文本。结构化卡片直接从第一方原始 event 字段派生;Host `presentCall` 与 `presentResult` 值不会进入 Client。运行中的原子工具行以同一道高光从左到右扫过标题、分隔符、摘要与后缀;已完成行保持静态。运行中与已完成的前台标准 `bash`/`pwsh` 和 `terminal_send` 调用,无论位于根还是 PTC dispatch 子调用中,都在通过相同的参数、结果和错误检查后使用 terminal 卡片。持久 `bash`/`pwsh` 调用仅在运行中使用 terminal 卡片。以已识别的 spill 策略提示结尾的 shell 输出,在 shell 行中使用可展开的 generic 输出,在 Details 中使用 generic 输出;位置被改变或被省略的退出标记无法证明成功。已完成的持久 shell 结果保持 generic 展示,因为 reset 与部分输出诊断不一定描述单个进程的退出状态;根调用的持久 shell 结果可展开。合法的主动后台 `bash`/`pwsh` 调用使用 terminal Start 展示;成功启动回执后,静态仅命令卡片保留 command 和 cwd,不显示输出或执行状态。启动失败保留通用参数与错误展示,后台 `terminal_send` 仍为 generic。Inspect 保留原始参数及回执,后续 job 输出不接回此卡片([决定](../../../.agents/notes/implemented/bug-fix/2026-10-10-background-shell-command-display.zh.md))。展开的终端命令与后台输入按可用宽度自动折行,保留原有换行和可选文本;终端输出保持按列对齐的排版。仅横向溢出时添加具名的键盘聚焦目标。提供 Inspect 时也可使用。回执不表示后台任务的退出状态。带有 `AUTO_REVIEW_DENIED` 的原生或 PTC dispatch 失败会在折叠行显示 Auto review 裁决,展开时显示一行归一化后的“未执行”原因;原因缺失或只有空白时使用本地化 fallback 文案。`ui-skill` 展示了业务包自行拥有的 `skill` 注册项。 问题行按 id 配对问题与答案;答案来自工具结果,迟到回答则来自 `userQuestions` 投影。可回答的调用提供按钮以重新打开面板。迟到回复进入 agent Inbox 后,问题行显示已提交的答案;等待准入期间,「查看回答」展开只读的行内记录。带有答案的已结算调用则以只读方式打开面板。没有答案的已关闭调用和无效记录不提供按钮。已取消和已中断的行显示裁决,不虚构答案。若面板提供方不接受按钮操作,点击会展开该行。不受支持或含糊的输入回退为压平的工具文本。 @@ -93,9 +93,9 @@ Chat diff 卡片在折叠前保留九行,足以容纳文件标题、一对删 Auto 拒绝优先于按工具名选择的专门视图。其通用行保留调用身份、省略原始参数,并且只在显示时归一化存储的理由:去除首尾空白,把行分隔符折叠为空格,结果为空时使用本地化通用理由。Session 与 SDK 错误详情保留原始理由。 -记录结果的工具详情覆盖目标和定时任务工具、Cordis 检查、workflow 与 Ralph 报告、Session 事件/搜索/轨迹查询、Agent 与 teammate 控制、后台作业、持久终端以及 LSP 导航。展开内容读取成功的记录结果,为失败或不支持的数据保留通用输入/输出,并保留 Inspect。日期包含查看者的时区,状态反映调用结果而非当前会话状态。Agent 控制回执显示记录的目标 Session id。`wait_agent` 的行标题仅显示等待中、已结束或已超时,不重复追加摘要;历史 `noProgress` 结果保留记录中的说明。Session 轨迹保留后代的缩进。LSP 结果通过 Host 回调打开文件系统路径,其他 URI 则显示为文本。浏览器适配器消费已记录的 producer 文本与 JSON;Host service 对象和 presenter 回调不会进入 Client。 +记录结果的工具详情覆盖目标和定时任务工具、Cordis 检查、workflow 与 Ralph 报告、Session 事件/搜索/轨迹查询、Agent 与 teammate 控制、后台作业、持久终端以及 LSP 导航。展开内容读取成功的记录结果,为失败或不支持的数据保留通用输入/输出,并保留 Inspect。日期包含查看者的时区,状态反映调用结果而非当前会话状态。Agent 控制回执显示记录的目标智能体名称,历史调用则显示 Session id。`wait_agent` 的行标题仅显示等待中、已结束或已超时,不重复追加摘要;历史 `noProgress` 结果保留记录中的说明。Session 轨迹保留后代的缩进。LSP 结果通过 Host 回调打开文件系统路径,其他 URI 则显示为文本。浏览器适配器消费已记录的 producer 文本与 JSON;Host service 对象和 presenter 回调不会进入 Client。 -展开后的状态圆点和文字使用静态语义色。操作回执和任务输出的标题保持中性色,展开时省略标题中的状态。中断回执仅确认已发出中断请求。 +展开后的状态圆点和文字使用静态语义色。目录失败状态使用本地化标签。Team 任务卡片对 `owner` 字段进行本地化;Cordis 检查保留提供方自有的字段名。操作回执和任务输出的标题保持中性色,展开时省略标题中的状态。中断回执仅确认已发出中断请求。 终端提示标签使用结果记录的 `cwd`。成功的旧根 shell 调用回退到原始工作区与调用参数中的 workdir;运行中的调用只有在 workdir 为绝对路径时才显示目录。终端发送不会根据 Session 推测进程目录。 diff --git a/packages/client/ui-tool/package.json b/packages/client/ui-tool/package.json index feb4aa74bc..c46fbdedb2 100644 --- a/packages/client/ui-tool/package.json +++ b/packages/client/ui-tool/package.json @@ -48,6 +48,7 @@ }, "devDependencies": { "@deepseek-ai/dsh-spill-policy": "workspace:*", + "@deepseek-ai/dsh-fs-patch": "workspace:*", "@deepseek-ai/dsh-agent": "workspace:*", "@deepseek-ai/dsh-llm": "workspace:*", "@deepseek-ai/dsh-session": "workspace:*", diff --git a/packages/client/ui-tool/src/client/tool/components/ToolRow.module.css b/packages/client/ui-tool/src/client/tool/components/ToolRow.module.css index e7f99f96c4..7d5bd8a6a6 100644 --- a/packages/client/ui-tool/src/client/tool/components/ToolRow.module.css +++ b/packages/client/ui-tool/src/client/tool/components/ToolRow.module.css @@ -108,6 +108,36 @@ font-size: var(--dsh-content-font-size-secondary, 13px); line-height: calc(24px + var(--dsh-content-font-delta, 0px)); color: inherit; +} + +/* Multi-file patch summary: one ellipsized line of plain separators and per-file + links. Shrink-to-fit like .fileLink, so the row's empty remainder stays the + expand/collapse toggle. */ +.fileLinks { + flex: 0 1 auto; + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + font-size: var(--dsh-content-font-size-secondary, 13px); + line-height: calc(24px + var(--dsh-content-font-delta, 0px)); +} + +/* One file inside .fileLinks: .fileLink's affordance without its own box, so the + line keeps flowing and the parent's ellipsis applies. */ +.fileTargetLink { + display: inline; + margin: 0; + padding: 0; + border: none; + background: none; + font: inherit; + color: inherit; +} + +/* Path link affordance shared by the whole-summary and per-file links. */ +.fileLink, +.fileTargetLink { text-decoration: underline dotted; text-decoration-color: currentColor; text-decoration-thickness: 1px; @@ -115,6 +145,23 @@ cursor: pointer; } +/* Pointing at one file of a multi-file patch brightens that file alone: the + row keeps its idle color and diff totals instead of the whole-row hover. */ +@media (hover: hover) { + .row:has(.fileTargetLink:hover) { + color: var(--dsw-alias-label-tertiary); + } + + .row:not([aria-expanded='true']):has(.fileTargetLink:hover) .diffAdded, + .row:not([aria-expanded='true']):has(.fileTargetLink:hover) .diffRemoved { + color: inherit; + } + + .fileTargetLink:hover { + color: var(--dsw-alias-label-secondary); + } +} + /* Error row's collapsed summary: the failure's first line in the error color. */ .errorSummary { color: var(--dsw-alias-state-error-primary); diff --git a/packages/client/ui-tool/src/client/tool/components/ToolRow.tsx b/packages/client/ui-tool/src/client/tool/components/ToolRow.tsx index 851a151226..9985614f80 100644 --- a/packages/client/ui-tool/src/client/tool/components/ToolRow.tsx +++ b/packages/client/ui-tool/src/client/tool/components/ToolRow.tsx @@ -1,4 +1,4 @@ -import { memo, useCallback, useMemo, type KeyboardEvent, type MouseEvent, type ReactNode } from 'react' +import { Fragment, memo, useCallback, useMemo, type KeyboardEvent, type MouseEvent, type ReactNode } from 'react' import clsx from 'clsx' import { CodeBlock, DiffBlock, DisclosureRow, IconInspectOutlineRegular, ReadBlock, SearchBlock, @@ -21,7 +21,7 @@ import { } from '../models/primitive-labels.ts' import type { AskQuestionCardModel } from '../models/ask-question-card-model.ts' import { - formatToolBody, type ToolRowState, type ToolRowVariant, + FILE_TARGET_MOVE, FILE_TARGET_SEPARATOR, formatToolBody, type ToolRowFileTarget, type ToolRowState, type ToolRowVariant, } from '../models/tool-call-model.ts' import type { WebCardModelProps } from '../models/web-card-model.ts' import { AskQuestionCard } from './AskQuestionCard.tsx' @@ -93,6 +93,14 @@ export interface ToolRowProps { onOpenFile?: ((path: string, options?: OpenFileOptions) => void) | undefined /** File gesture bindings supplied by the owning tool view. */ fileContextMenuProps?: ContextMenuTriggerProps | undefined + /** + * Files a patch row names. When onOpenFile is set, the row state is `ok`, and + * at least one target has a `filePath`, each such target renders as its own + * link in place of the summary text; otherwise the row shows `summary`. + */ + fileTargets?: readonly ToolRowFileTarget[] | undefined + /** File gesture bindings for one `fileTargets` path, supplied by the owning tool view. */ + fileTargetContextMenuProps?: ((path: string) => ContextMenuTriggerProps) | undefined /** URL gesture bindings supplied by the owning tool view. */ urlContextMenuProps?: ContextMenuTriggerProps | undefined /** Safe http(s) URL from tool args; when set, the summary renders as a link that opens it in a new tab. */ @@ -109,6 +117,35 @@ function stopLinkClick(event: MouseEvent): void { event.stopPropagation() } +interface FileTargetLinkProps { + label: string + path: string + onOpenFile: (path: string, options?: OpenFileOptions) => void + contextMenuProps: ContextMenuTriggerProps | undefined + onLinkKeyDown: (event: KeyboardEvent) => void +} + +/** One openable file inside a multi-file summary; activating it never toggles the row. */ +function FileTargetLink({ label, path, onOpenFile, contextMenuProps, onLinkKeyDown }: FileTargetLinkProps) { + return ( + + ) +} + /** Visually hidden run-state label for color-only running and settlement cues. */ function stateStatus(state: ToolRowState, t: TranslateNS<'conversation'>): string | null { switch (state) { @@ -151,7 +188,7 @@ export const ToolRow = memo(function ToolRow({ filePath, filePathLine, onOpenFile, - fileContextMenuProps, urlContextMenuProps, + fileContextMenuProps, urlContextMenuProps, fileTargets, fileTargetContextMenuProps, href, inspect, useDisclosure, @@ -203,6 +240,10 @@ export const ToolRow = memo(function ToolRow({ } : undefined, [filePath, filePathLine, onOpenFile, settledWithCue]) const linkHref = settledWithCue ? undefined : href + // Per-file links appear only on a successful result: TextShimmer accepts no + // buttons, so running and failed rows keep the plain summary text. + const openTarget = state === 'ok' && fileTargets?.some(target => target.filePath !== undefined) === true + ? onOpenFile : undefined // Keep Enter/Space on the focused path or URL link from bubbling to the row's // keydown handler, which would preventDefault() the key and toggle expand // instead of activating the link — the keyboard analogue of the click @@ -219,7 +260,25 @@ export const ToolRow = memo(function ToolRow({ its title shows no trailing dot). */ <> - {exitLabel === null && openFile !== undefined ? ( + {exitLabel === null && fileTargets !== undefined && openTarget !== undefined ? ( + + {fileTargets.map((target, index) => ( + + {index > 0 && FILE_TARGET_SEPARATOR} + {target.from !== undefined && `${target.from}${FILE_TARGET_MOVE}`} + {target.filePath === undefined ? target.label : ( + + )} + + ))} + + ) : exitLabel === null && openFile !== undefined ? (