From 219be197c9cbecc02de4250d1471d710ba9f660b Mon Sep 17 00:00:00 2001 From: Dudu-0223 Date: Tue, 13 Oct 2026 11:12:49 +0800 Subject: [PATCH 1/3] fix(agent-team): inject member identity through required runtime context --- ...13-team-identity-runtime-context.i18n.yaml | 19 ++++++ ...026-10-13-team-identity-runtime-context.md | 31 +++++++++ ...-10-13-team-identity-runtime-context.zh.md | 31 +++++++++ .../feature/2026-08-05-agent-teams.i18n.yaml | 8 +-- .../feature/2026-08-05-agent-teams.md | 4 +- .../feature/2026-08-05-agent-teams.zh.md | 4 +- .../headless/tests/fixtures/team-llm.mjs | 19 +++--- .../headless/tests/headless.expected.e2e.ts | 34 +++++----- docs/config-catalog.md | 2 +- docs/config-catalog.zh.md | 2 +- packages/core/system-prompt/README.i18n.yaml | 4 +- packages/core/system-prompt/README.md | 2 +- packages/core/system-prompt/README.zh.md | 2 +- packages/core/system-prompt/src/index.ts | 1 + .../tool-agent-team/README.i18n.yaml | 16 ++--- .../experimental/tool-agent-team/README.md | 8 +-- .../experimental/tool-agent-team/README.zh.md | 8 +-- .../experimental/tool-agent-team/src/index.ts | 26 ++++---- .../tool-agent-team/tests/tool-team.spec.ts | 66 ++++++++++--------- .../session/team-targets/session.v4.jsonl | 2 +- 20 files changed, 191 insertions(+), 98 deletions(-) create mode 100644 .agents/notes/implemented/architecture/2026-10-13-team-identity-runtime-context.i18n.yaml create mode 100644 .agents/notes/implemented/architecture/2026-10-13-team-identity-runtime-context.md create mode 100644 .agents/notes/implemented/architecture/2026-10-13-team-identity-runtime-context.zh.md 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 new file mode 100644 index 0000000000..65205260c3 --- /dev/null +++ b/.agents/notes/implemented/architecture/2026-10-13-team-identity-runtime-context.i18n.yaml @@ -0,0 +1,19 @@ +# Bilingual-pair consistency record for 2026-10-13-team-identity-runtime-context.md (docs/i18n/README.md): per heading +# section, a hash of its English and Chinese blocks outside code blocks and generated regions. +# After editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write .agents/notes/implemented/architecture/2026-10-13-team-identity-runtime-context.md +/agent-note-team-identity-in-required-runtime-context: + en: 8c88759320ae8481 + zh: 4068b18723907eb9 +/agent-note-team-identity-in-required-runtime-context/problem: + en: c9a81cb731ddf7b2 + zh: 428c0e6f8937d7c5 +/agent-note-team-identity-in-required-runtime-context/decision: + en: 6c73479973c1e378 + zh: 98677c77f77f8d81 +/agent-note-team-identity-in-required-runtime-context/alternatives-considered: + en: 774566ffbf9e9db8 + zh: ea761d876af462f2 +/agent-note-team-identity-in-required-runtime-context/consequences: + en: 18d1aa67936f1227 + zh: 7e06c1f51553ecdd 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 new file mode 100644 index 0000000000..39794f02d3 --- /dev/null +++ b/.agents/notes/implemented/architecture/2026-10-13-team-identity-runtime-context.md @@ -0,0 +1,31 @@ +# Agent Note: Team identity in required runtime context + +Status: implemented + +English | [中文](2026-10-13-team-identity-runtime-context.zh.md) + +## 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 current membership while keeping shared system instructions uniform. + +## Decision + +`tool-agent-team` contributes `team:identity` through the Agent-scoped `systemPrompt.context()` registry with `required: true`. Its provider reads the existing Team membership and renders the member's role, name, and addressing instructions. Optional-context suppression cannot remove it. Fixed collaboration policy stays in the system prompt; roster and task state remain tool queries. Initial tasks contain only their supplied content. + +The loop owns logging, retained-snapshot comparison, and re-admission after compaction. A changed role appends the current full runtime-context snapshot after inherited history; unchanged retained context adds no message. No Team-specific retention state, event type, or log migration is introduced. Existing recorded reminders remain historical messages. + +This supersedes only the initial-task identity decision in [Agent Teams](../feature/2026-08-05-agent-teams.md#team-identity); its roster, mailbox, and task decisions remain active. + +## Alternatives considered + +**Keep identity in the initial task.** Preserves a uniform system prompt but cannot restore removed identity or correct a fork's inherited role without another mechanism. + +**Put identity in the system prompt.** Makes system text differ across members and can rewrite the inherited request prefix on routes without in-history system updates. + +**Add custom reminder retention and reinjection.** Duplicates the loop's existing runtime-context projection and recovery responsibilities. + +## Consequences + +Members pay for identity within the full runtime-context snapshot. Other context changes repeat it, while stable retained context adds no new message. Forks preserve inherited history and append current identity; actual provider cache hits remain best-effort. Existing Team authorization remains in tool execution. + +Verification covers fresh and fork teammates, an independent fork from a teammate, optional-context suppression, compaction restoration, cold resume, and registration disposal. The recorded `team-targets` scenario pins Lead context; the keyless headless Team workflow pins teammate context through the shipped profile. 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 new file mode 100644 index 0000000000..d0e333a71e --- /dev/null +++ b/.agents/notes/implemented/architecture/2026-10-13-team-identity-runtime-context.zh.md @@ -0,0 +1,31 @@ +# Agent Note: 必需 runtime context 中的 Team 身份 + +Status: implemented + +[English](2026-10-13-team-identity-runtime-context.md) | 中文 + +## Problem + +嵌入初始任务的 teammate 身份依赖普通历史保留。压缩可能移除它;从 teammate 创建的普通 fork 即使已成为独立 Lead,也可能保留旧角色。身份必须反映当前 membership,同时保持共享系统指令一致。 + +## Decision + +`tool-agent-team` 通过 Agent 作用域的 `systemPrompt.context()` 注册 `team:identity`,并设置 `required: true`。提供方读取现有 Team membership,渲染成员角色、名字与寻址说明。关闭可选 context 不能移除它。固定协作策略保留在 system prompt;roster 和 task 状态仍通过工具查询。初始任务只包含传入的正文。 + +Loop 负责日志记录、保留快照比较和压缩后的重新接纳。角色变化会在继承历史之后追加当前完整 runtime-context 快照;保留的 context 未变化时不追加消息。不引入 Team 专属的保留状态、事件类型或日志迁移。已有身份提醒仍作为历史消息保留。 + +本决策仅取代 [Agent Teams](../feature/2026-08-05-agent-teams.zh.md#team-identity) 中的初始任务身份决策;其 roster、mailbox 和 task 决策仍然有效。 + +## Alternatives considered + +**身份留在初始任务中。** 保持 system prompt 一致,但恢复被移除的身份或纠正 fork 继承的角色需要额外机制。 + +**身份放进 system prompt。** 成员之间的 system 文本会不同;不支持历史内 system 更新的路由可能重写继承的请求前缀。 + +**添加自定义提醒保留与重新注入。** 重复了 loop 已有的 runtime-context 投影和恢复职责。 + +## Consequences + +成员承担完整 runtime-context 快照中的身份 token 成本。其他 context 变化会重复身份,保留的 context 稳定时则不追加消息。Fork 保留继承历史并追加当前身份;提供方实际缓存命中仍为尽力而为。现有 Team 授权仍在工具执行时落实。 + +验证覆盖 fresh 和 fork teammate、从 teammate 创建的独立 fork、关闭可选 context、压缩后恢复、冷恢复和注册释放。录制的 `team-targets` 场景固定 Lead context;无密钥 headless Team 工作流通过内置 profile 固定 teammate context。 diff --git a/.agents/notes/implemented/feature/2026-08-05-agent-teams.i18n.yaml b/.agents/notes/implemented/feature/2026-08-05-agent-teams.i18n.yaml index aab0051c22..d0705de595 100644 --- a/.agents/notes/implemented/feature/2026-08-05-agent-teams.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-08-05-agent-teams.i18n.yaml @@ -12,11 +12,11 @@ en: 95e7d723d6b00930 zh: d18fdf9b2bf69bdb /agent-note-durable-agent-teams-over-continuable-children/profile-delegation: - en: 3a66308576f74247 - zh: 3453f0bcce88033d + en: 28ed9e222a1af6c4 + zh: 7b7ce5f66cd2f9b9 /agent-note-durable-agent-teams-over-continuable-children/team-identity: - en: 83e446c928a20c47 - zh: b0a2bd24419dd815 + en: 6d8a88e3d689a990 + zh: 8906b0befa2fb617 /agent-note-durable-agent-teams-over-continuable-children/provisioning-and-recovery: en: 4345ac9a6ac7ad04 zh: 1d19ecbb128a75a3 diff --git a/.agents/notes/implemented/feature/2026-08-05-agent-teams.md b/.agents/notes/implemented/feature/2026-08-05-agent-teams.md index 2643101a91..65afb914c4 100644 --- a/.agents/notes/implemented/feature/2026-08-05-agent-teams.md +++ b/.agents/notes/implemented/feature/2026-08-05-agent-teams.md @@ -22,10 +22,12 @@ The Lead must wait for required work before its final answer. Process teardown r ## Profile delegation -The [Team profile](../../../../packages/experimental/agent-team-profile/README.md) disables `subagent` and `subagent_fork` together with the overlapping global controls. Direct model delegation uses `spawn_teammate` with fresh or fork context, keeping those children in the durable roster. Workflow remains available through the base profile’s fresh `spawn` provider for scripted orchestration; it cannot inherit a teammate’s conversation identity through the model tool. The Subagent services and providers remain shared infrastructure. Ordinary Session forks retain their history without identity correction. Provider-owned child tool visibility remains a [documented limitation](../../../../packages/experimental/tool-agent-team/README.md#known-limitations-and-deferred-work). +The [Team profile](../../../../packages/experimental/agent-team-profile/README.md) disables `subagent` and `subagent_fork` together with the overlapping global controls. Direct model delegation uses `spawn_teammate` with fresh or fork context, keeping those children in the durable roster. Workflow remains available through the base profile’s fresh `spawn` provider for scripted orchestration; it cannot inherit a teammate’s conversation identity through the model tool. The Subagent services and providers remain shared infrastructure. Ordinary Session forks retain their history; [current identity handling](../architecture/2026-10-13-team-identity-runtime-context.md) supplies the fork’s own role. Provider-owned child tool visibility remains a [documented limitation](../../../../packages/experimental/tool-agent-team/README.md#known-limitations-and-deferred-work). ## Team identity +The initial-task identity decision below is superseded by [required runtime-context identity](../architecture/2026-10-13-team-identity-runtime-context.md). The roster, mailbox, and task decisions remain active. + The `spawn_teammate` tool prefixes the initial task with a user-role `` stating `You are teammate "".`. Identity and task enter the same durable inbox message. Shared system policy and all tool schemas stay uniform across members; execution owns role restrictions. Team tools resolve the caller’s Team and accept member names, so the model needs no Team id. Identity follows ordinary history through cold recovery and compaction; the plugin does not inspect reminder retention or add replacement messages. Forks inherit the recorded text without a Lead identity correction. Putting identity in the system prompt changes the prefix before inherited history; keeping it in the initial task preserves that prefix without per-step identity bookkeeping. Existing system-embedded identities may require a one-time prompt reconciliation; retained event generations are unchanged. ## Provisioning and recovery diff --git a/.agents/notes/implemented/feature/2026-08-05-agent-teams.zh.md b/.agents/notes/implemented/feature/2026-08-05-agent-teams.zh.md index 92af6e1afb..e3ea5c8cdb 100644 --- a/.agents/notes/implemented/feature/2026-08-05-agent-teams.zh.md +++ b/.agents/notes/implemented/feature/2026-08-05-agent-teams.zh.md @@ -22,10 +22,12 @@ Lead 必须等待所需工作后才能给出最终答案。进程 teardown 仍 ## Profile delegation -[Team profile](../../../../packages/experimental/agent-team-profile/README.zh.md) 禁用 `subagent`、`subagent_fork` 以及名称重叠的全局控件。模型直接委派使用支持 fresh 或 fork 上下文的 `spawn_teammate`,使这些子代理进入持久 roster。Workflow 仍通过 base profile 的 fresh `spawn` 提供方执行脚本编排;经模型工具创建的 workflow 子代理不会继承 teammate 的对话身份。Subagent 服务和提供方仍是共享基础设施。普通 Session fork 保留历史,不纠正身份。提供方所拥有的子代理工具可见性仍是[已记录的限制](../../../../packages/experimental/tool-agent-team/README.zh.md#known-limitations-and-deferred-work)。 +[Team profile](../../../../packages/experimental/agent-team-profile/README.zh.md) 禁用 `subagent`、`subagent_fork` 以及名称重叠的全局控件。模型直接委派使用支持 fresh 或 fork 上下文的 `spawn_teammate`,使这些子代理进入持久 roster。Workflow 仍通过 base profile 的 fresh `spawn` 提供方执行脚本编排;经模型工具创建的 workflow 子代理不会继承 teammate 的对话身份。Subagent 服务和提供方仍是共享基础设施。普通 Session fork 保留历史;[当前身份处理](../architecture/2026-10-13-team-identity-runtime-context.zh.md)提供 fork 自己的角色。提供方所拥有的子代理工具可见性仍是[已记录的限制](../../../../packages/experimental/tool-agent-team/README.zh.md#known-limitations-and-deferred-work)。 ## Team identity +下述初始任务身份决策由[必需 runtime-context 身份](../architecture/2026-10-13-team-identity-runtime-context.zh.md)取代。Roster、mailbox 和 task 决策仍然有效。 + 工具 `spawn_teammate` 在初始任务前加上 user-role ``,声明 `You are teammate "".`。身份和任务进入同一条持久化收件箱消息。共享 system 策略和全部工具 schema 在成员间保持一致;执行时检查角色权限。Team 工具根据调用者确定 Team,并接受成员名字,因此模型不需要 Team id。身份随普通历史经历冷恢复和压缩;插件不检查提醒是否保留,也不添加替代消息。fork 继承已记录文本,不补发 Lead 身份修正。把身份放进 system prompt 会在继承历史之前改变前缀;把它留在初始任务中既保留此前缀,也无需每步维护身份提醒。已有的 system 内嵌身份可能需要一次提示词协调;保留的事件格式代际保持不变。 ## Provisioning and recovery 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 119380327b..9c1bedd00e 100644 --- a/apps/cli/tests/profiles/headless/tests/fixtures/team-llm.mjs +++ b/apps/cli/tests/profiles/headless/tests/fixtures/team-llm.mjs @@ -183,17 +183,18 @@ class TeamFixtureAdapter extends LlmAdapter { throw new Error('Team profile exposes a direct subagent tool') } const initial = options.messages.findLast(message => message.role === 'user' && message.source.kind === 'user') - const identity = initial?.content[0]?.text?.trimEnd() - if (identity !== 'TEAM_WORKFLOW_CHILD' && (!tools.includes('spawn_teammate') || !tools.includes('workflow'))) { + const workflowChild = initial?.content[0]?.text === 'TEAM_WORKFLOW_CHILD' + const context = options.messages.findLast(message => message.source?.kind === 'runtime-context') + const identity = context?.source.sections?.find(section => section.name === 'team:identity')?.text + if (!workflowChild && (!tools.includes('spawn_teammate') || !tools.includes('workflow'))) { throw new Error('Team profile is missing teammate or workflow tools') } - const chunks = identity === 'TEAM_WORKFLOW_CHILD' - ? textChunks('Fresh workflow child complete.') - : identity === '\nYou are teammate "researcher".\nYour Team Lead is named "lead".\nUse list_agents({}) to find your teammates and their names.\nTo message your Team Lead, use send_message({ target: "lead", message: "..." }).\nTo message another teammate, use send_message({ target: "", message: "..." }).\n' - ? researcher(options.messages) - : identity === '\nYou are teammate "implementer".\nYour Team Lead is named "lead".\nUse list_agents({}) to find your teammates and their names.\nTo message your Team Lead, use send_message({ target: "lead", message: "..." }).\nTo message another teammate, use send_message({ target: "", message: "..." }).\n' - ? implementer(options.messages) - : lead(options.messages) + let chunks + if (workflowChild) chunks = textChunks('Fresh workflow child complete.') + else if (identity?.startsWith('You are teammate "researcher".')) chunks = researcher(options.messages) + else if (identity?.startsWith('You are teammate "implementer".')) chunks = implementer(options.messages) + else if (identity?.startsWith('You are the Team Lead named "lead".')) chunks = lead(options.messages) + else throw new Error('Team runtime context is missing a recognized identity') for (const chunk of chunks) { options.signal?.throwIfAborted() yield chunk 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 6406d63753..2e45acbb6c 100644 --- a/apps/cli/tests/profiles/headless/tests/headless.expected.e2e.ts +++ b/apps/cli/tests/profiles/headless/tests/headless.expected.e2e.ts @@ -985,22 +985,26 @@ describe('headless stream-json snapshots', () => { if (data.name !== 'team_task_update' || typeof data.arguments !== 'string') return false return (JSON.parse(data.arguments) as JsonObject).action === 'complete' }) - const identityReminders = logs.flatMap((log) => { + const identities = logs.flatMap((log) => { if (log === parent || log === workflowChild) return [] const initial = parseJsonl(log.content).find(row => row.type === 'user/message' && ((row.data as JsonObject).source as JsonObject).kind === 'user') if (initial === undefined) throw new Error('Teammate Session has no initial task') const content = (initial.data as JsonObject).content as JsonObject[] - expect(content).toHaveLength(2) - const identity = content[0]!.text - if (typeof identity !== 'string') throw new Error('Teammate initial task has no identity text') - return [identity.trimEnd()] + expect(content).toHaveLength(1) + const context = parseJsonl(log.content).find(row => row.type === 'user/message' + && ((row.data as JsonObject).source as JsonObject).kind === 'runtime-context') + const source = (context?.data as JsonObject)?.source as JsonObject + const sections = source?.sections as JsonObject[] | undefined + const identity = sections?.find(section => section.name === 'team:identity')?.text + if (typeof identity !== 'string') throw new Error('Teammate runtime context has no identity') + return [identity] }).sort() projection = { sessions: logs.length, workflowStopReason: (rows.find(row => row.type === 'tool-workflow/run-end')?.data as JsonObject)?.stopReason, memberEdges: members.length, - identityReminders, + identities, activeMembers: members.filter(member => member.phase === 'active').map(member => member.name).sort(), tasks: latestTasks.map(task => ({ subject: task.subject, @@ -1035,21 +1039,17 @@ describe('headless stream-json snapshots', () => { ], "checkedRoster": true, "deliveredMessages": 0, - "identityReminders": [ - " - You are teammate "implementer". + "identities": [ + "You are teammate "implementer". Your Team Lead is named "lead". - Use list_agents({}) to find your teammates and their names. To message your Team Lead, use send_message({ target: "lead", message: "..." }). - To message another teammate, use send_message({ target: "", message: "..." }). - ", - " - You are teammate "researcher". + Use list_agents({}) to find your teammates and their names. + To message another teammate, use send_message({ target: "", message: "..." }).", + "You are teammate "researcher". Your Team Lead is named "lead". - Use list_agents({}) to find your teammates and their names. To message your Team Lead, use send_message({ target: "lead", message: "..." }). - To message another teammate, use send_message({ target: "", message: "..." }). - ", + Use list_agents({}) to find your teammates and their names. + To message another teammate, use send_message({ target: "", message: "..." }).", ], "memberEdges": 4, "queuedMessages": 0, diff --git a/docs/config-catalog.md b/docs/config-catalog.md index 6c163884c0..7528787923 100644 --- a/docs/config-catalog.md +++ b/docs/config-catalog.md @@ -3492,7 +3492,7 @@ export interface Config { ## `@deepseek-ai/dsh-system-prompt` -- `source`: [`packages/core/system-prompt/src/index.ts:257`](../packages/core/system-prompt/src/index.ts) +- `source`: [`packages/core/system-prompt/src/index.ts:258`](../packages/core/system-prompt/src/index.ts) ```ts config-catalog /** Plugin config: the deployment-authored fragment of the system prompt (see {@link Config.personaPrefix} for its contract). */ diff --git a/docs/config-catalog.zh.md b/docs/config-catalog.zh.md index 02a7f69dfa..acb7216b6c 100644 --- a/docs/config-catalog.zh.md +++ b/docs/config-catalog.zh.md @@ -3494,7 +3494,7 @@ export interface Config { ## `@deepseek-ai/dsh-system-prompt` -- `source`: [`packages/core/system-prompt/src/index.ts:257`](../packages/core/system-prompt/src/index.ts) +- `source`: [`packages/core/system-prompt/src/index.ts:258`](../packages/core/system-prompt/src/index.ts) ```ts config-catalog /** Plugin config: the deployment-authored fragment of the system prompt (see {@link Config.personaPrefix} for its contract). */ diff --git a/packages/core/system-prompt/README.i18n.yaml b/packages/core/system-prompt/README.i18n.yaml index a5c3f5913c..18a88159b7 100644 --- a/packages/core/system-prompt/README.i18n.yaml +++ b/packages/core/system-prompt/README.i18n.yaml @@ -21,8 +21,8 @@ en: 87e28893e6cf58d7 zh: 06f476b38c4d2038 /deepseek-ai-dsh-system-prompt/use-this-package/contribute-a-prompt-section: - en: 165fecb5329b00b6 - zh: a7c595d1787916c9 + en: c81c70536209de26 + zh: 83d4fa9fc6890d55 /deepseek-ai-dsh-system-prompt/use-this-package/contribute-a-prompt-variable: en: b3e4c9b4ced59488 zh: d80c791e72bd5821 diff --git a/packages/core/system-prompt/README.md b/packages/core/system-prompt/README.md index 6c9d7338ec..11ee659d88 100644 --- a/packages/core/system-prompt/README.md +++ b/packages/core/system-prompt/README.md @@ -53,7 +53,7 @@ The generated [configuration catalog](../../../docs/config-catalog.md#deepseek-a ### Contribute a prompt section -Sections carry static or context-resolved text with an `order`; they are concatenated in ascending order and equal orders use code-unit name order. Repository-owned contributors resolve centrally allocated positions through `ctx.systemPrompt.getSectionOrder(name)`; runtime-context contributors use `getContextOrder(name)`. External contributions may use any finite order. A `complete: true` section becomes the exact complete prompt after assembly; more than one effective complete section makes assembly fail. +Sections carry static or context-resolved text with an `order`; they are concatenated in ascending order and equal orders use code-unit name order. Repository-owned contributors resolve centrally allocated positions through `ctx.systemPrompt.getSectionOrder(name)`; runtime-context contributors use `getContextOrder(name)`. Team identity uses the `TEAM_IDENTITY` context position after subagent delegation. External contributions may use any finite order. A `complete: true` section becomes the exact complete prompt after assembly; more than one effective complete section makes assembly fail. ```text ctx.systemPrompt.section({ diff --git a/packages/core/system-prompt/README.zh.md b/packages/core/system-prompt/README.zh.md index 1807bf0411..1fa564a4b8 100644 --- a/packages/core/system-prompt/README.zh.md +++ b/packages/core/system-prompt/README.zh.md @@ -53,7 +53,7 @@ kind: "package-reference" ### 贡献提示词段 -段携带静态或按上下文解析的文本与 `order`;它们先按顺序值升序拼接,顺序值相同时再按名称的代码单元顺序排列。仓库自带贡献方通过 `ctx.systemPrompt.getSectionOrder(name)` 解析集中分配的位置;runtime-context 贡献方使用 `getContextOrder(name)`。外部贡献可以使用任意有限的顺序值。`complete: true` 段会在组装后成为精确的完整提示词;有效的 complete 段超过一个时,组装会失败。 +段携带静态或按上下文解析的文本与 `order`;它们先按顺序值升序拼接,顺序值相同时再按名称的代码单元顺序排列。仓库自带贡献方通过 `ctx.systemPrompt.getSectionOrder(name)` 解析集中分配的位置;runtime-context 贡献方使用 `getContextOrder(name)`。外部贡献可以使用任意有限的顺序值。`complete: true` 段会在组装后成为精确的完整提示词;有效的 complete 段超过一个时,组装会失败。 Team 身份使用位于 subagent delegation 之后的 `TEAM_IDENTITY` context 位置。 ```text ctx.systemPrompt.section({ diff --git a/packages/core/system-prompt/src/index.ts b/packages/core/system-prompt/src/index.ts index d3b719f818..519afe060d 100644 --- a/packages/core/system-prompt/src/index.ts +++ b/packages/core/system-prompt/src/index.ts @@ -172,6 +172,7 @@ const CONTEXT_ORDERS = { SANDBOX_POLICY: 110, APPROVAL_POLICY: 115, SUBAGENT_DELEGATION: 120, + TEAM_IDENTITY: 125, // Process-specific paths and endpoints stay out of the cached system prompt. HARNESS_SOURCE: 200, WEB_SURFACE: 210, diff --git a/packages/experimental/tool-agent-team/README.i18n.yaml b/packages/experimental/tool-agent-team/README.i18n.yaml index 2766c8e359..8d66841273 100644 --- a/packages/experimental/tool-agent-team/README.i18n.yaml +++ b/packages/experimental/tool-agent-team/README.i18n.yaml @@ -15,8 +15,8 @@ en: d152484eb41ac6b4 zh: 09388d293f9be9cb /deepseek-ai-dsh-experimental-tool-agent-team/use-this-package: - en: 1e928b05f250c945 - zh: 0281800e08a58fce + en: 5a56781cb7bf4d3b + zh: 74df21efd6321afd /deepseek-ai-dsh-experimental-tool-agent-team/use-this-package/when-to-choose-it: en: 5261677934ea6e71 zh: a8bafd94d2b293ec @@ -54,14 +54,14 @@ en: 8e1e365ff3b0dfb2 zh: c6c91fbf1e1df934 /deepseek-ai-dsh-experimental-tool-agent-team/model-experience/team-policy-and-tools/what-the-model-sees: - en: 601ef7bfff117b60 - zh: 50435d70524c12e2 + en: 8887cc2b9eab8738 + zh: 892c17ae0613000a /deepseek-ai-dsh-experimental-tool-agent-team/model-experience/team-policy-and-tools/token-effect: - en: fe314af98a2130b8 - zh: ea89cb40dd11d57c + en: 3f49674f937a8ca3 + zh: 79d34d605732abb1 /deepseek-ai-dsh-experimental-tool-agent-team/model-experience/team-policy-and-tools/kv-cache-effect: - en: cba54e491b29b664 - zh: 288015d4794998f9 + en: 2ba143e89873e768 + zh: 4f09446c0fb13cdb /deepseek-ai-dsh-experimental-tool-agent-team/known-limitations-and-deferred-work: en: c459b2e8236e6a6c zh: 7cd2af569e9b751a diff --git a/packages/experimental/tool-agent-team/README.md b/packages/experimental/tool-agent-team/README.md index bb849dc717..ce0ae1e0d8 100644 --- a/packages/experimental/tool-agent-team/README.md +++ b/packages/experimental/tool-agent-team/README.md @@ -25,7 +25,7 @@ This package lets the model create named teammates, send them messages, inspect ## Use this package -Add this package on top of `@deepseek-ai/dsh-experimental-agent-team` when the model should run a team through tools. Once mounted, every team member — the Lead and each teammate — gets the same nine tools plus the same coordination policy. `spawn_teammate` prefixes the initial task with the teammate’s role and name. +Add this package on top of `@deepseek-ai/dsh-experimental-agent-team` when the model should run a team through tools. Once mounted, every team member — the Lead and each teammate — gets the same nine tools plus the same coordination policy. Each member receives its current role and name through required runtime context; `spawn_teammate` sends the initial task unchanged. ### When to choose it @@ -124,15 +124,15 @@ Read these pages when the package-level contract is not enough. They move from t #### What the model sees -One shared system policy covers explicit delegation, shared-cwd safety, task coordination, Steer delivery, inbox acceptance, and the Lead’s duty to wait. All nine schemas are identical for Leads and teammates; execution enforces Lead-only operations. `spawn_teammate` prefixes the initial task with a user-role reminder of the teammate name, Lead name, and messaging tools. The reminder follows ordinary history through recovery and compaction. +One shared system policy covers explicit delegation, shared-cwd safety, task coordination, Steer delivery, inbox acceptance, and the Lead’s duty to wait. All nine schemas are identical for Leads and teammates; execution enforces Lead-only operations. Required runtime context states `You are the Team Lead named "lead".` or `You are teammate "".` with `Your Team Lead is named "lead".`, plus roster and messaging instructions. Identity comes from current Team membership, survives optional-context suppression, and is restored when compaction removes its snapshot. An ordinary fork from a teammate receives its current Lead identity. #### Token effect -Fixed policy and schema cost on every Team member request. The initial identity text follows ordinary history through later steps, cold recovery, and compaction; the plugin neither scans for it nor reinserts it. Tool calls add compact JSON roster, task, wait, or receipt results. Peer content is retained by the Team domain in the target's history. +Fixed policy and schema cost on every Team member request. Identity is part of the complete runtime-context snapshot. An unchanged retained snapshot adds no message; changed or removed context causes the loop to append a complete snapshot, including identity. Tool calls add compact JSON roster, task, wait, or receipt results. Peer content is retained by the Team domain in the target's history. #### KV Cache effect -With the same provider/model, shared system policy, and tool schemas, a fork retains the parent request prefix and appends the initial task with its identity prefix. Tool results and peer messages append after the reusable request prefix. Sessions recorded with identity inside the system prompt can change that prefix on their first request under this layout; actual provider cache hits remain best-effort. +With the same provider/model, shared system policy, and tool schemas, a fork retains the parent request prefix and appends its task and current runtime context. Tool results and peer messages append after the reusable request prefix. Sessions recorded with identity inside the system prompt can change that prefix on their first request under this layout; actual provider cache hits remain best-effort. ## Known Limitations and Deferred Work diff --git a/packages/experimental/tool-agent-team/README.zh.md b/packages/experimental/tool-agent-team/README.zh.md index 931f60c424..cba2d69292 100644 --- a/packages/experimental/tool-agent-team/README.zh.md +++ b/packages/experimental/tool-agent-team/README.zh.md @@ -25,7 +25,7 @@ kind: "package-reference" ## 使用本包 -当模型应该通过工具运行一支团队时,在 `@deepseek-ai/dsh-experimental-agent-team` 之上挂载本包。挂载后,每个团队成员——Lead 与每个 teammate——都会获得相同的九个工具,以及相同的协作策略。`spawn_teammate` 在初始任务前加上 teammate 的角色和名字。 +当模型应该通过工具运行一支团队时,在 `@deepseek-ai/dsh-experimental-agent-team` 之上挂载本包。挂载后,每个团队成员——Lead 与每个 teammate——都会获得相同的九个工具,以及相同的协作策略。`spawn_teammate` 原样发送初始任务;每个成员通过必需的 runtime context 接收当前角色和名字。 ### 何时选择 @@ -124,15 +124,15 @@ member scope 上的一个 `team:policy` 段落说明共享的协作规则;固 #### 模型看到什么 -共享系统 policy 覆盖显式委派、共享 cwd 安全、任务协调、Steer 投递、inbox 接收和 Lead 等待责任。Lead 与 teammate 使用相同的九个 schema;执行时落实 Lead-only 操作。`spawn_teammate` 在初始任务前加入用户角色提醒,说明 teammate 名称、Lead 名称与消息工具。提醒随普通历史经历恢复与压缩。 +共享系统 policy 覆盖显式委派、共享 cwd 安全、任务协调、Steer 投递、inbox 接收和 Lead 等待责任。Lead 与 teammate 使用相同的九个 schema;执行时落实 Lead-only 操作。必需的 runtime context 声明 `You are the Team Lead named "lead".`,或 `You are teammate "".` 与 `Your Team Lead is named "lead".`,并提供 roster 和消息操作说明。身份来自当前 Team membership,关闭可选 context 时仍保留,压缩移除快照后会恢复。从 teammate 创建的普通 fork 会收到当前 Lead 身份。 #### Token 影响 -每次 Team member 请求都有固定策略与 schema 成本。初始身份文本随普通历史经历后续步骤、冷恢复和压缩;插件不扫描或重新插入它。工具调用会增加紧凑 JSON roster、task、wait 或 receipt 结果。Peer 内容由 Team 领域保留在 target 历史中。 +每次 Team member 请求都有固定策略与 schema 成本。身份是完整 runtime-context 快照的一部分。保留的快照未变化时不追加消息;context 变化或被移除时,loop 追加包含身份的完整快照。工具调用会增加紧凑 JSON roster、task、wait 或 receipt 结果。Peer 内容由 Team 领域保留在 target 历史中。 #### KV Cache 影响 -provider/model、共享 system 策略和工具 schema 相同时,fork 保留父请求前缀并追加带身份前缀的初始任务。工具结果与 peer 消息追加在可复用请求前缀之后。原先在 system prompt 中记录身份的 Session,首次使用此布局请求时可能改变该前缀;提供方实际缓存命中仍为尽力而为。 +provider/model、共享 system 策略和工具 schema 相同时,fork 保留父请求前缀并追加任务与当前 runtime context。工具结果与 peer 消息追加在可复用请求前缀之后。原先在 system prompt 中记录身份的 Session,首次使用此布局请求时可能改变该前缀;提供方实际缓存命中仍为尽力而为。 ## 已知限制与延期工作 diff --git a/packages/experimental/tool-agent-team/src/index.ts b/packages/experimental/tool-agent-team/src/index.ts index 6c87762fb0..9f4ecf8e67 100644 --- a/packages/experimental/tool-agent-team/src/index.ts +++ b/packages/experimental/tool-agent-team/src/index.ts @@ -175,6 +175,19 @@ function install(agent: Agent, ctx: Context, config: Required): () => vo order: scoped.systemPrompt.getSectionOrder('TEAM_POLICY'), text: teamPolicy(config.interrupt), })) + register(scoped.systemPrompt.context({ + name: 'team:identity', + order: scoped.systemPrompt.getContextOrder('TEAM_IDENTITY'), + required: true, + text: () => { + const { role, name } = ctx.agentTeams.membership(agent) + return `${role === 'lead' + ? 'You are the Team Lead named "lead".' + : `You are teammate "${name}".\nYour Team Lead is named "lead".\nTo message your Team Lead, use send_message({ target: "lead", message: "..." }).`} +Use list_agents({}) to find your teammates and their names. +To message another teammate, use send_message({ target: "", message: "..." }).` + }, + })) register(scoped.tools.register(defineTool({ name: 'spawn_teammate', @@ -196,18 +209,7 @@ function install(agent: Agent, ctx: Context, config: Required): () => vo const result = await ctx.agentTeams.spawnTeammate(agent, { name: args.name, description: args.description, - prompt: [ - { type: 'text', text: ` -You are teammate "${args.name.trim()}". -Your Team Lead is named "lead". -Use list_agents({}) to find your teammates and their names. -To message your Team Lead, use send_message({ target: "lead", message: "..." }). -To message another teammate, use send_message({ target: "", message: "..." }). - - -` }, - { type: 'text', text: args.prompt }, - ], + prompt: [{ type: 'text', text: args.prompt }], context, provider: context === 'fork' ? config.forkProvider : config.freshProvider, signal: exec.signal, diff --git a/packages/experimental/tool-agent-team/tests/tool-team.spec.ts b/packages/experimental/tool-agent-team/tests/tool-team.spec.ts index fe4e05bb20..5d7194fdd9 100644 --- a/packages/experimental/tool-agent-team/tests/tool-team.spec.ts +++ b/packages/experimental/tool-agent-team/tests/tool-team.spec.ts @@ -30,6 +30,11 @@ function serializeRequest(request: GenerateOptions) { return serialize(request, connection, request.messages, new Map(), () => undefined) } +function runtimeContextText(request: GenerateOptions) { + const context = request.messages.findLast(message => message.source?.kind === 'runtime-context') + return context?.content.flatMap(block => block.type === 'text' ? [block.text] : []).join('\n') +} + const SIGNAL = new AbortController().signal const TOOL_NAMES = [ 'spawn_teammate', @@ -250,7 +255,7 @@ describe('dsh-tool-team', () => { expect(leadPrompt).toContain('Task readiness never starts an owner') expect(leadPrompt).toContain('returns noProgress immediately') expect(leadPrompt).not.toContain('Your Team role') - expect(renderContextSnapshot(leadAssembly)).toBe('') + expect(renderContextSnapshot(leadAssembly)).toContain('You are the Team Lead named "lead".') const spawned = await execute(ctx, lead, 'spawn_teammate', { name: 'tool-worker', @@ -264,14 +269,13 @@ describe('dsh-tool-team', () => { expect(childAssembly.tools.map(schema => schema.name).filter(name => TOOL_NAMES.includes(name)).sort()) .toEqual(TOOL_NAMES) expect(renderPrompt(childAssembly)).toBe(leadPrompt) - expect(renderContextSnapshot(childAssembly)).not.toContain('team:identity') - expect(child.session.deriveMessages().some(message => message.content.some(block => - block.type === 'text' && block.text === '\nYou are teammate "tool-worker".\nYour Team Lead is named "lead".\nUse list_agents({}) to find your teammates and their names.\nTo message your Team Lead, use send_message({ target: "lead", message: "..." }).\nTo message another teammate, use send_message({ target: "", message: "..." }).\n\n\n'))).toBe(true) + expect(renderContextSnapshot(childAssembly)).toContain('You are teammate "tool-worker".') + expect(childAssembly.contexts).toContainEqual(expect.objectContaining({ name: 'team:identity' })) const initialPrompt = child.session.snapshotEvents().find(event => event.type === 'user/message' && event.data.source.kind === 'user') expect(initialPrompt?.type === 'user/message' ? initialPrompt.data.content.flatMap(block => block.type === 'text' ? [block.text] : []) - : []).toEqual(['\nYou are teammate "tool-worker".\nYour Team Lead is named "lead".\nUse list_agents({}) to find your teammates and their names.\nTo message your Team Lead, use send_message({ target: "lead", message: "..." }).\nTo message another teammate, use send_message({ target: "", message: "..." }).\n\n\n', 'stay available']) + : []).toEqual(['stay available']) const denied = await execute(ctx, child, 'spawn_teammate', { name: 'nested', description: 'not allowed', prompt: 'no', @@ -306,20 +310,17 @@ describe('dsh-tool-team', () => { } else { expect(JSON.stringify(childRequest.messages)).not.toContain('Parent task') } - expect(childRequest.messages.at(-1)?.content.slice(0, 2)).toEqual([ - { type: 'text', text: '\nYou are teammate "reviewer".\nYour Team Lead is named "lead".\nUse list_agents({}) to find your teammates and their names.\nTo message your Team Lead, use send_message({ target: "lead", message: "..." }).\nTo message another teammate, use send_message({ target: "", message: "..." }).\n\n\n' }, - { type: 'text', text: 'Review the work' }, - ]) + expect(runtimeContextText(adapter.requests[1]!)).toContain('You are teammate "reviewer".') + expect(childRequest.messages.at(-1)?.content).toContainEqual({ type: 'text', text: 'Review the work' }) await using persisted = await ctx.sessionPersistence.open(childId, 'read') const { events } = await persisted.read() const initial = events.findLast(event => event.type === 'user/message' && event.data.source.kind === 'user') expect(initial?.type === 'user/message' ? initial.data.content : []).toEqual([ - { type: 'text', text: '\nYou are teammate "reviewer".\nYour Team Lead is named "lead".\nUse list_agents({}) to find your teammates and their names.\nTo message your Team Lead, use send_message({ target: "lead", message: "..." }).\nTo message another teammate, use send_message({ target: "", message: "..." }).\n\n\n' }, { type: 'text', text: 'Review the work' }, ]) }) - it('keeps an ordinary Lead fork free of identity reminders without replacing the inherited prefix', async () => { + it('reuses unchanged Lead identity in an ordinary Lead fork', async () => { const { ctx, lead, adapter } = await setup([textResponse('parent answer'), textResponse('fork answer')]) await runTurn(lead, 'Parent task') const seed = lead.session.snapshotEvents() @@ -344,7 +345,7 @@ describe('dsh-tool-team', () => { await handle.dispose() }) - it.each([undefined, 'in-history'] as const)('keeps a teammate fork prefix with update mode %s without a Lead correction', async (systemPromptUpdate) => { + it.each([undefined, 'in-history'] as const)('appends current Lead identity to a teammate fork with update mode %s', async (systemPromptUpdate) => { const { ctx, lead, adapter } = await setup([textResponse('review done'), textResponse('lead notified'), textResponse('fork answer')]) if (systemPromptUpdate !== undefined) adapter.systemPromptUpdate = systemPromptUpdate const spawned = await execute(ctx, lead, 'spawn_teammate', { @@ -372,14 +373,14 @@ describe('dsh-tool-team', () => { expect(fork.messages.slice(0, original.messages.length)).toEqual(original.messages) expect(forkRequest.messages.slice(0, inheritedHistory.length)).toEqual(inheritedHistory) expect(fork.messages.at(-1)?.content).toContainEqual({ type: 'text', text: 'Continue independently' }) - expect(JSON.stringify(fork.messages)).not.toContain('You are the Team Lead') + expect(runtimeContextText(forkRequest)).toContain('You are the Team Lead named "lead".') expect(handle.agent.session.snapshotEvents().slice(0, seed.length)).toEqual(seed) } finally { await handle.dispose() } }) - it('leaves initial identity to ordinary history compaction without reinserting it', async () => { + it('restores compacted identity and does not repeat an unchanged retained snapshot', async () => { const { ctx, lead, adapter } = await setup([ toolCallResponse('first-list', 'list_agents', {}), toolCallResponse('second-list', 'list_agents', {}), @@ -388,8 +389,8 @@ describe('dsh-tool-team', () => { ctx.on('agent/pre-step', async ({ agent, step }, next) => { if (step === 3) { const identity = agent.session.snapshotEvents().find(event => event.type === 'user/message' - && event.data.source.kind === 'user') - if (identity === undefined) throw new Error('expected initial teammate reminder') + && event.data.source.kind === 'runtime-context') + if (identity === undefined) throw new Error('expected teammate runtime context') agent.session.append('user/message', createUserMessage({ content: [{ type: 'text', text: 'Compacted earlier context.' }], source: { kind: 'test-compaction' }, @@ -405,16 +406,15 @@ describe('dsh-tool-team', () => { }) const childId = spawnedChildId(ctx, lead, spawned) await waitNoAgent(ctx, childId) - const reminder = '\nYou are teammate "reviewer".\nYour Team Lead is named "lead".\nUse list_agents({}) to find your teammates and their names.\nTo message your Team Lead, use send_message({ target: "lead", message: "..." }).\nTo message another teammate, use send_message({ target: "", message: "..." }).\n\n\n' - const first = serializeRequest(adapter.requests[0]!).messages - expect(first.at(-1)?.content.slice(0, 2)).toEqual([{ type: 'text', text: reminder }, { type: 'text', text: 'Review the work' }]) - expect(adapter.requests[1]!.messages.filter(message => message.content.some(block => - block.type === 'text' && block.text === reminder))).toHaveLength(1) - expect(JSON.stringify(serializeRequest(adapter.requests[2]!).messages)).not.toContain('You are teammate') + for (const request of adapter.requests.filter(request => request.sessionId === childId)) { + const snapshots = request.messages.filter(message => message.source?.kind === 'runtime-context') + expect(snapshots).toHaveLength(1) + expect(runtimeContextText(request)).toContain('You are teammate "reviewer".') + } await using persisted = await ctx.sessionPersistence.open(childId, 'read') const { events } = await persisted.read() expect(events.filter(event => event.type === 'user/message' - && (event.data.source as { readonly kind?: unknown }).kind === toolTeam.name)).toHaveLength(0) + && event.data.source.kind === 'runtime-context')).toHaveLength(2) }) it.each(['reject', 'empty', 'abort'] as const)('does not revive a teammate step after %s', async (mode) => { @@ -438,7 +438,7 @@ describe('dsh-tool-team', () => { && event.data.source.kind === 'user')).toEqual([]) }) - it('keeps teammate reminders when runtime context is suppressed', async () => { + it('keeps required Team identities when optional runtime context is suppressed', async () => { const { ctx, lead, adapter } = await setup([textResponse('worker done')]) ctx.systemPrompt.suppressRuntimeContext() const spawned = await execute(ctx, lead, 'spawn_teammate', { @@ -446,10 +446,8 @@ describe('dsh-tool-team', () => { }) expect(spawned.isError, text(spawned)).toBe(false) await waitNoAgent(ctx, spawnedChildId(ctx, lead, spawned)) - expect(serializeRequest(adapter.requests[0]!).messages.at(-1)?.content).toEqual([ - { type: 'text', text: '\nYou are teammate "reviewer".\nYour Team Lead is named "lead".\nUse list_agents({}) to find your teammates and their names.\nTo message your Team Lead, use send_message({ target: "lead", message: "..." }).\nTo message another teammate, use send_message({ target: "", message: "..." }).\n\n\n' }, - { type: 'text', text: 'Review the work' }, - ]) + expect(renderContextSnapshot(await assembly(ctx, lead))).toContain('You are the Team Lead named "lead".') + expect(runtimeContextText(adapter.requests[0]!)).toContain('You are teammate "reviewer".') }) it('returns actionable no-progress output and renders structured wait cancellation', async () => { @@ -646,6 +644,9 @@ describe('dsh-tool-team', () => { expect((await assembly(ctx, lead)).tools.map(schema => schema.name).some(name => TOOL_NAMES.includes(name))).toBe(false) expect((await assembly(ctx, child)).tools.map(schema => schema.name).some(name => TOOL_NAMES.includes(name))).toBe(false) expect(ctx.agents.get(childId)).toBe(child) + for (const agent of [lead, child]) { + expect((await assembly(ctx, agent)).contexts.some(context => context.name === 'team:identity')).toBe(false) + } const disabled = await ctx.plugin(toolTeam, { interrupt: false }) for (const agent of [lead, child]) { @@ -692,11 +693,11 @@ describe('dsh-tool-team', () => { const assembled = await assembly(ctx, lead) expect(assembled.tools.filter(schema => TOOL_NAMES.includes(schema.name)).map(schema => schema.name)) .toEqual(['spawn_teammate']) - expect(renderContextSnapshot(assembled)).not.toContain('Your Team role is lead') + expect(assembled.contexts.some(context => context.name === 'team:identity')).toBe(false) }) it('resolves direct-apply defaults without Loader schema normalization', async () => { - const { ctx, lead, fiber } = await setup([textResponse('ordinary child')]) + const { ctx, lead, fiber, adapter } = await setup([textResponse('ordinary child')]) await fiber.dispose() toolTeam.apply(ctx, {}) expect((await assembly(ctx, lead)).tools.map(schema => schema.name).filter(name => TOOL_NAMES.includes(name)).sort()) @@ -709,6 +710,9 @@ describe('dsh-tool-team', () => { signal: SIGNAL, }) await vi.waitFor(() => { expect(ctx.agents.get(ordinary.childId)).toBeUndefined() }, { timeout: 5_000 }) + const request = adapter.requests.find(request => request.sessionId === ordinary.childId) + expect(request).toBeDefined() + expect(JSON.stringify(request?.messages)).not.toContain('You are the Team Lead') }) it.each([true, false])('reinstalls Team scope with interrupt=%s before a cold-resumed request', async (interrupt) => { @@ -739,7 +743,7 @@ describe('dsh-tool-team', () => { expect((await assembly(ctx, resumed)).tools.map(schema => schema.name) .filter(name => TOOL_NAMES.includes(name)).sort()).toEqual(TOOL_NAMES.filter(name => interrupt || name !== 'interrupt_agent')) expect(renderPrompt(await assembly(ctx, resumed)).includes('interrupt_agent')).toBe(interrupt) - expect(renderContextSnapshot(await assembly(ctx, resumed))).not.toContain('You are teammate') + expect(renderContextSnapshot(await assembly(ctx, resumed))).toContain('You are teammate "cold-worker".') const childRequests = () => adapter.requests.filter(request => request.messages.some(message => message.role === 'user' && message.content.some(block => block.type === 'text' && block.text.includes('You are teammate "cold-worker".')))) await vi.waitFor(() => { expect(childRequests()).toHaveLength(2) }) diff --git a/snapshots/session/team-targets/session.v4.jsonl b/snapshots/session/team-targets/session.v4.jsonl index 60162b0153..7c4441b685 100644 --- a/snapshots/session/team-targets/session.v4.jsonl +++ b/snapshots/session/team-targets/session.v4.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":"{{message:2}}"}},"surfaceOp":"append"} {"type":"user/message","data":{"content":[{"type":"text","text":"Use Agent Teams list_agents to inspect the roster, attempt to send yourself a message and observe its rejection, then reply TEAM_TARGETS_OK."}],"source":{"kind":"user"},"role":"user","id":"{{message:1}}"},"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`)."}],"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`)."}]},"role":"user","id":"{{message:3}}"},"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 Team Lead named \"lead\".\nUse list_agents({}) to find your teammates and their names.\nTo message another teammate, use send_message({ target: \"\", message: \"...\" })."}],"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":"team:identity","text":"You are the Team Lead named \"lead\".\nUse list_agents({}) to find your teammates and their names.\nTo message another teammate, use send_message({ target: \"\", message: \"...\" })."}]},"role":"user","id":"{{message:3}}"},"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":"Use Agent Teams list_agents to","messageSeqs":[8],"source":{"kind":"fallback"}}} From 44d41c9473c620df808798680eaf7f96c60d057e Mon Sep 17 00:00:00 2001 From: Dudu-0223 Date: Tue, 13 Oct 2026 11:20:53 +0800 Subject: [PATCH 2/3] test(agent-team): refresh direct inbox identity snapshots --- snapshots/session/team-direct-inbox/session.1.v4.jsonl | 8 ++++---- snapshots/session/team-direct-inbox/session.v4.jsonl | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/snapshots/session/team-direct-inbox/session.1.v4.jsonl b/snapshots/session/team-direct-inbox/session.1.v4.jsonl index 471d8e3f16..3bd7f3102c 100644 --- a/snapshots/session/team-direct-inbox/session.1.v4.jsonl +++ b/snapshots/session/team-direct-inbox/session.1.v4.jsonl @@ -3,16 +3,16 @@ {"type":"sandbox/mode","data":{"mode":"danger-full-access","source":"delegation"}} {"type":"approval/policy","data":{"policy":"never","source":"delegation"}} {"type":"permission/preset","data":{"preset":"danger-full-access"}} -{"type":"agent/inbox/spliced","data":{"target":"next-turn","start":0,"inserted":[{"content":[{"type":"text","text":"\nYou are teammate \"reviewer\".\nYour Team Lead is named \"lead\".\nUse list_agents({}) to find your teammates and their names.\nTo message your Team Lead, use send_message({ target: \"lead\", message: \"...\" }).\nTo message another teammate, use send_message({ target: \"\", message: \"...\" }).\n\n\n"},{"type":"text","text":"Create the empty file team-ready, then wait in Bash until interrupted."}],"source":{"kind":"user"},"role":"user","id":"{{message:13}}"}]}} +{"type":"agent/inbox/spliced","data":{"target":"next-turn","start":0,"inserted":[{"content":[{"type":"text","text":"Create the empty file team-ready, then wait in Bash until interrupted."}],"source":{"kind":"user"},"role":"user","id":"{{message:13}}"}]}} {"type":"turn/start","data":{"turn":1}} {"type":"agent/inbox/spliced","data":{"target":"next-turn","start":0,"removedCount":1,"inserted":[]}} {"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":"{{message:14}}"}},"surfaceOp":"append"} -{"type":"user/message","data":{"content":[{"type":"text","text":"\nYou are teammate \"reviewer\".\nYour Team Lead is named \"lead\".\nUse list_agents({}) to find your teammates and their names.\nTo message your Team Lead, use send_message({ target: \"lead\", message: \"...\" }).\nTo message another teammate, use send_message({ target: \"\", message: \"...\" }).\n\n\n"},{"type":"text","text":"Create the empty file team-ready, then wait in Bash until interrupted."}],"source":{"kind":"user"},"role":"user","id":"{{message:13}}"},"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 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: 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: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":"{{message:15}}"},"surfaceOp":"append"} +{"type":"user/message","data":{"content":[{"type":"text","text":"Create the empty file team-ready, then wait in Bash until interrupted."}],"source":{"kind":"user"},"role":"user","id":"{{message:13}}"},"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 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.\n\nYou are teammate \"reviewer\".\nYour Team Lead is named \"lead\".\nTo message your Team Lead, use send_message({ target: \"lead\", message: \"...\" }).\nUse list_agents({}) to find your teammates and their names.\nTo message another teammate, use send_message({ target: \"\", message: \"...\" })."}],"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: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."},{"name":"team:identity","text":"You are teammate \"reviewer\".\nYour Team Lead is named \"lead\".\nTo message your Team Lead, use send_message({ target: \"lead\", message: \"...\" }).\nUse list_agents({}) to find your teammates and their names.\nTo message another teammate, use send_message({ target: \"\", message: \"...\" })."}]},"role":"user","id":"{{message:15}}"},"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":" You are teammate \"revi","messageSeqs":[9],"source":{"kind":"fallback"}}} +{"type":"session/title","data":{"title":"Create the empty file team-ready,","messageSeqs":[9],"source":{"kind":"fallback"}}} {"type":"assistant/message","data":{"turn":1,"step":1,"message":{"role":"assistant","content":[{"type":"tool-call","id":"direct-1","name":"bash","arguments":"{\"command\":\"touch team-ready; while :; do sleep 1; done\",\"description\":\"Signal readiness and wait for interruption\",\"timeoutMs\":60000}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{message:16}}"},"usage":{"inputTokens":3,"outputTokens":3},"stream":[{"type":"chunk","time":1791450215117,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}},{"type":"tool-call-chunks","time0":1791450215117,"index":0,"dt":[],"id":"direct-1","name":"bash","args":["{\"command\":\"touch team-ready; while :; do sleep 1; done\",\"description\":\"Signal readiness and wait for interruption\",\"timeoutMs\":60000}"]},{"type":"chunk","time":1791450215117,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"direct-1","name":"bash","arguments":"{\"command\":\"touch team-ready; while :; do sleep 1; done\",\"description\":\"Signal readiness and wait for interruption\",\"timeoutMs\":60000}"}}},{"type":"chunk","time":1791450215117,"chunk":{"type":"usage","usage":{"inputTokens":3,"outputTokens":3}}},{"type":"chunk","time":1791450215117,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}]},"surfaceOp":"append"} {"type":"tool/call","data":{"turn":1,"step":1,"callId":"direct-1","name":"bash","arguments":"{\"command\":\"touch team-ready; while :; do sleep 1; done\",\"description\":\"Signal readiness and wait for interruption\",\"timeoutMs\":60000}"}} {"type":"job/registered","data":{"jobId":"{{id:2}}","owner":"{{session:2}}","kind":"bash","label":"touch team-ready; while :; do sleep 1; done","startedAt":1791450215128,"toolCall":{"callId":"direct-1","rootCallId":"direct-1"}}} diff --git a/snapshots/session/team-direct-inbox/session.v4.jsonl b/snapshots/session/team-direct-inbox/session.v4.jsonl index 7c5206096b..6d6adeb5d3 100644 --- a/snapshots/session/team-direct-inbox/session.v4.jsonl +++ b/snapshots/session/team-direct-inbox/session.v4.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":"{{message:2}}"}},"surfaceOp":"append"} {"type":"user/message","data":{"content":[{"type":"text","text":"Spawn teammate reviewer, wait for its team-ready file, send it the message Review the direct inbox delivery., interrupt its waiting turn, then reply TEAM_DIRECT_INBOX_OK."}],"source":{"kind":"user"},"role":"user","id":"{{message:1}}"},"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`)."}],"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`)."}]},"role":"user","id":"{{message:3}}"},"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 Team Lead named \"lead\".\nUse list_agents({}) to find your teammates and their names.\nTo message another teammate, use send_message({ target: \"\", message: \"...\" })."}],"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":"team:identity","text":"You are the Team Lead named \"lead\".\nUse list_agents({}) to find your teammates and their names.\nTo message another teammate, use send_message({ target: \"\", message: \"...\" })."}]},"role":"user","id":"{{message:3}}"},"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":"Spawn teammate reviewer, wait for","messageSeqs":[8],"source":{"kind":"fallback"}}} From 85259d7cfd98663a6625d169393c4b136a589ddb Mon Sep 17 00:00:00 2001 From: Dudu-0223 Date: Tue, 13 Oct 2026 12:51:29 +0800 Subject: [PATCH 3/3] docs(agent-team): clean up identity review feedback --- .../implemented/feature/2026-08-05-agent-teams.i18n.yaml | 8 ++++---- .../notes/implemented/feature/2026-08-05-agent-teams.md | 6 ++---- .../implemented/feature/2026-08-05-agent-teams.zh.md | 6 ++---- packages/core/system-prompt/README.i18n.yaml | 4 ++-- packages/core/system-prompt/README.md | 2 +- packages/core/system-prompt/README.zh.md | 2 +- packages/core/system-prompt/tests/system-prompt.spec.ts | 2 +- packages/experimental/agent-team-profile/README.i18n.yaml | 4 ++-- packages/experimental/agent-team-profile/README.md | 2 +- packages/experimental/agent-team-profile/README.zh.md | 2 +- packages/experimental/agent-team/README.i18n.yaml | 8 ++++---- packages/experimental/agent-team/README.md | 4 ++-- packages/experimental/agent-team/README.zh.md | 4 ++-- packages/experimental/tool-agent-team/README.i18n.yaml | 4 ++-- packages/experimental/tool-agent-team/README.md | 2 -- packages/experimental/tool-agent-team/README.zh.md | 2 -- 16 files changed, 27 insertions(+), 35 deletions(-) diff --git a/.agents/notes/implemented/feature/2026-08-05-agent-teams.i18n.yaml b/.agents/notes/implemented/feature/2026-08-05-agent-teams.i18n.yaml index d0705de595..3ef2bd6bfb 100644 --- a/.agents/notes/implemented/feature/2026-08-05-agent-teams.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-08-05-agent-teams.i18n.yaml @@ -12,11 +12,11 @@ en: 95e7d723d6b00930 zh: d18fdf9b2bf69bdb /agent-note-durable-agent-teams-over-continuable-children/profile-delegation: - en: 28ed9e222a1af6c4 - zh: 7b7ce5f66cd2f9b9 + en: 4835fb8c0c0d8a0d + zh: 5f9438a0d58104c4 /agent-note-durable-agent-teams-over-continuable-children/team-identity: - en: 6d8a88e3d689a990 - zh: 8906b0befa2fb617 + en: f82812d6ac0ac78d + zh: 7dd80a6ad13674ca /agent-note-durable-agent-teams-over-continuable-children/provisioning-and-recovery: en: 4345ac9a6ac7ad04 zh: 1d19ecbb128a75a3 diff --git a/.agents/notes/implemented/feature/2026-08-05-agent-teams.md b/.agents/notes/implemented/feature/2026-08-05-agent-teams.md index 65afb914c4..82864e2552 100644 --- a/.agents/notes/implemented/feature/2026-08-05-agent-teams.md +++ b/.agents/notes/implemented/feature/2026-08-05-agent-teams.md @@ -22,13 +22,11 @@ The Lead must wait for required work before its final answer. Process teardown r ## Profile delegation -The [Team profile](../../../../packages/experimental/agent-team-profile/README.md) disables `subagent` and `subagent_fork` together with the overlapping global controls. Direct model delegation uses `spawn_teammate` with fresh or fork context, keeping those children in the durable roster. Workflow remains available through the base profile’s fresh `spawn` provider for scripted orchestration; it cannot inherit a teammate’s conversation identity through the model tool. The Subagent services and providers remain shared infrastructure. Ordinary Session forks retain their history; [current identity handling](../architecture/2026-10-13-team-identity-runtime-context.md) supplies the fork’s own role. Provider-owned child tool visibility remains a [documented limitation](../../../../packages/experimental/tool-agent-team/README.md#known-limitations-and-deferred-work). +The [Team profile](../../../../packages/experimental/agent-team-profile/README.md) disables `subagent` and `subagent_fork` together with the overlapping global controls. Direct model delegation uses `spawn_teammate` with fresh or fork context, keeping those children in the durable roster. Workflow remains available through the base profile’s fresh `spawn` provider for scripted orchestration; it cannot inherit a teammate’s conversation identity through the model tool. The Subagent services and providers remain shared infrastructure. Ordinary Session forks retain their history; [current identity handling](../architecture/2026-10-13-team-identity-runtime-context.md) supplies the fork’s own role. ## Team identity -The initial-task identity decision below is superseded by [required runtime-context identity](../architecture/2026-10-13-team-identity-runtime-context.md). The roster, mailbox, and task decisions remain active. - -The `spawn_teammate` tool prefixes the initial task with a user-role `` stating `You are teammate "".`. Identity and task enter the same durable inbox message. Shared system policy and all tool schemas stay uniform across members; execution owns role restrictions. Team tools resolve the caller’s Team and accept member names, so the model needs no Team id. Identity follows ordinary history through cold recovery and compaction; the plugin does not inspect reminder retention or add replacement messages. Forks inherit the recorded text without a Lead identity correction. Putting identity in the system prompt changes the prefix before inherited history; keeping it in the initial task preserves that prefix without per-step identity bookkeeping. Existing system-embedded identities may require a one-time prompt reconciliation; retained event generations are unchanged. +Shared system policy and all tool schemas stay uniform across members; execution owns role restrictions. Team tools resolve the caller’s Team and accept member names, so the model needs no Team id. [Required runtime-context identity](../architecture/2026-10-13-team-identity-runtime-context.md) owns identity injection, retention, and fork handling. ## Provisioning and recovery diff --git a/.agents/notes/implemented/feature/2026-08-05-agent-teams.zh.md b/.agents/notes/implemented/feature/2026-08-05-agent-teams.zh.md index e3ea5c8cdb..7a292f2d7e 100644 --- a/.agents/notes/implemented/feature/2026-08-05-agent-teams.zh.md +++ b/.agents/notes/implemented/feature/2026-08-05-agent-teams.zh.md @@ -22,13 +22,11 @@ Lead 必须等待所需工作后才能给出最终答案。进程 teardown 仍 ## Profile delegation -[Team profile](../../../../packages/experimental/agent-team-profile/README.zh.md) 禁用 `subagent`、`subagent_fork` 以及名称重叠的全局控件。模型直接委派使用支持 fresh 或 fork 上下文的 `spawn_teammate`,使这些子代理进入持久 roster。Workflow 仍通过 base profile 的 fresh `spawn` 提供方执行脚本编排;经模型工具创建的 workflow 子代理不会继承 teammate 的对话身份。Subagent 服务和提供方仍是共享基础设施。普通 Session fork 保留历史;[当前身份处理](../architecture/2026-10-13-team-identity-runtime-context.zh.md)提供 fork 自己的角色。提供方所拥有的子代理工具可见性仍是[已记录的限制](../../../../packages/experimental/tool-agent-team/README.zh.md#known-limitations-and-deferred-work)。 +[Team profile](../../../../packages/experimental/agent-team-profile/README.zh.md) 禁用 `subagent`、`subagent_fork` 以及名称重叠的全局控件。模型直接委派使用支持 fresh 或 fork 上下文的 `spawn_teammate`,使这些子代理进入持久 roster。Workflow 仍通过 base profile 的 fresh `spawn` 提供方执行脚本编排;经模型工具创建的 workflow 子代理不会继承 teammate 的对话身份。Subagent 服务和提供方仍是共享基础设施。普通 Session fork 保留历史;[当前身份处理](../architecture/2026-10-13-team-identity-runtime-context.zh.md)提供 fork 自己的角色。 ## Team identity -下述初始任务身份决策由[必需 runtime-context 身份](../architecture/2026-10-13-team-identity-runtime-context.zh.md)取代。Roster、mailbox 和 task 决策仍然有效。 - -工具 `spawn_teammate` 在初始任务前加上 user-role ``,声明 `You are teammate "".`。身份和任务进入同一条持久化收件箱消息。共享 system 策略和全部工具 schema 在成员间保持一致;执行时检查角色权限。Team 工具根据调用者确定 Team,并接受成员名字,因此模型不需要 Team id。身份随普通历史经历冷恢复和压缩;插件不检查提醒是否保留,也不添加替代消息。fork 继承已记录文本,不补发 Lead 身份修正。把身份放进 system prompt 会在继承历史之前改变前缀;把它留在初始任务中既保留此前缀,也无需每步维护身份提醒。已有的 system 内嵌身份可能需要一次提示词协调;保留的事件格式代际保持不变。 +共享 system 策略和全部工具 schema 在成员间保持一致;执行时检查角色权限。Team 工具根据调用者确定 Team,并接受成员名字,因此模型不需要 Team id。[必需 runtime-context 身份](../architecture/2026-10-13-team-identity-runtime-context.zh.md)负责身份注入、保留与 fork 处理。 ## Provisioning and recovery diff --git a/packages/core/system-prompt/README.i18n.yaml b/packages/core/system-prompt/README.i18n.yaml index 18a88159b7..a5c3f5913c 100644 --- a/packages/core/system-prompt/README.i18n.yaml +++ b/packages/core/system-prompt/README.i18n.yaml @@ -21,8 +21,8 @@ en: 87e28893e6cf58d7 zh: 06f476b38c4d2038 /deepseek-ai-dsh-system-prompt/use-this-package/contribute-a-prompt-section: - en: c81c70536209de26 - zh: 83d4fa9fc6890d55 + en: 165fecb5329b00b6 + zh: a7c595d1787916c9 /deepseek-ai-dsh-system-prompt/use-this-package/contribute-a-prompt-variable: en: b3e4c9b4ced59488 zh: d80c791e72bd5821 diff --git a/packages/core/system-prompt/README.md b/packages/core/system-prompt/README.md index 11ee659d88..6c9d7338ec 100644 --- a/packages/core/system-prompt/README.md +++ b/packages/core/system-prompt/README.md @@ -53,7 +53,7 @@ The generated [configuration catalog](../../../docs/config-catalog.md#deepseek-a ### Contribute a prompt section -Sections carry static or context-resolved text with an `order`; they are concatenated in ascending order and equal orders use code-unit name order. Repository-owned contributors resolve centrally allocated positions through `ctx.systemPrompt.getSectionOrder(name)`; runtime-context contributors use `getContextOrder(name)`. Team identity uses the `TEAM_IDENTITY` context position after subagent delegation. External contributions may use any finite order. A `complete: true` section becomes the exact complete prompt after assembly; more than one effective complete section makes assembly fail. +Sections carry static or context-resolved text with an `order`; they are concatenated in ascending order and equal orders use code-unit name order. Repository-owned contributors resolve centrally allocated positions through `ctx.systemPrompt.getSectionOrder(name)`; runtime-context contributors use `getContextOrder(name)`. External contributions may use any finite order. A `complete: true` section becomes the exact complete prompt after assembly; more than one effective complete section makes assembly fail. ```text ctx.systemPrompt.section({ diff --git a/packages/core/system-prompt/README.zh.md b/packages/core/system-prompt/README.zh.md index 1fa564a4b8..1807bf0411 100644 --- a/packages/core/system-prompt/README.zh.md +++ b/packages/core/system-prompt/README.zh.md @@ -53,7 +53,7 @@ kind: "package-reference" ### 贡献提示词段 -段携带静态或按上下文解析的文本与 `order`;它们先按顺序值升序拼接,顺序值相同时再按名称的代码单元顺序排列。仓库自带贡献方通过 `ctx.systemPrompt.getSectionOrder(name)` 解析集中分配的位置;runtime-context 贡献方使用 `getContextOrder(name)`。外部贡献可以使用任意有限的顺序值。`complete: true` 段会在组装后成为精确的完整提示词;有效的 complete 段超过一个时,组装会失败。 Team 身份使用位于 subagent delegation 之后的 `TEAM_IDENTITY` context 位置。 +段携带静态或按上下文解析的文本与 `order`;它们先按顺序值升序拼接,顺序值相同时再按名称的代码单元顺序排列。仓库自带贡献方通过 `ctx.systemPrompt.getSectionOrder(name)` 解析集中分配的位置;runtime-context 贡献方使用 `getContextOrder(name)`。外部贡献可以使用任意有限的顺序值。`complete: true` 段会在组装后成为精确的完整提示词;有效的 complete 段超过一个时,组装会失败。 ```text ctx.systemPrompt.section({ diff --git a/packages/core/system-prompt/tests/system-prompt.spec.ts b/packages/core/system-prompt/tests/system-prompt.spec.ts index a8bef706d1..d19daf5465 100644 --- a/packages/core/system-prompt/tests/system-prompt.spec.ts +++ b/packages/core/system-prompt/tests/system-prompt.spec.ts @@ -25,7 +25,7 @@ const SECTION_ORDER_NAMES = [ ] as const satisfies readonly PromptSectionOrderName[] const CONTEXT_ORDER_NAMES = [ 'WORKING_DIRECTORY', - 'SANDBOX_POLICY', 'APPROVAL_POLICY', 'SUBAGENT_DELEGATION', + 'SANDBOX_POLICY', 'APPROVAL_POLICY', 'SUBAGENT_DELEGATION', 'TEAM_IDENTITY', 'HARNESS_SOURCE', 'WEB_SURFACE', ] as const satisfies readonly PromptContextOrderName[] function contributed(assembly: PromptAssembly): PromptAssembly['sections'] { diff --git a/packages/experimental/agent-team-profile/README.i18n.yaml b/packages/experimental/agent-team-profile/README.i18n.yaml index 53c1049097..cf0a7e983a 100644 --- a/packages/experimental/agent-team-profile/README.i18n.yaml +++ b/packages/experimental/agent-team-profile/README.i18n.yaml @@ -42,8 +42,8 @@ en: da8c178179ba50ba zh: c53d5863bc14be79 /deepseek-ai-dsh-experimental-agent-team-profile/model-experience/team-policy-and-tools/kv-cache-effect: - en: e331337b094aacde - zh: bb2e5df5ebeb9305 + en: ac4c8d0ba492fa6a + zh: 16d4a05f2e719651 /deepseek-ai-dsh-experimental-agent-team-profile/known-limitations-and-deferred-work: en: 0413821c2fc20bea zh: 53e135425dd82e12 diff --git a/packages/experimental/agent-team-profile/README.md b/packages/experimental/agent-team-profile/README.md index 0b6f52423b..08cde7a032 100644 --- a/packages/experimental/agent-team-profile/README.md +++ b/packages/experimental/agent-team-profile/README.md @@ -95,7 +95,7 @@ The bundle adds the Team policy and tool schemas described by `@deepseek-ai/dsh- #### KV Cache effect -The bundle's composition is prefix-stable while its patch, Team identity, and configured tool schemas remain unchanged. +The shared system prompt and tool schemas remain prefix-stable while the bundle patch and configured tool schemas remain unchanged. Team identity is appended through runtime-context snapshots; [Team tools](../tool-agent-team/README.md#model-experience) define snapshot reuse. ## Known Limitations and Deferred Work diff --git a/packages/experimental/agent-team-profile/README.zh.md b/packages/experimental/agent-team-profile/README.zh.md index a656710a56..96979fdf3d 100644 --- a/packages/experimental/agent-team-profile/README.zh.md +++ b/packages/experimental/agent-team-profile/README.zh.md @@ -95,7 +95,7 @@ Team 策略与 schema 由 [`@deepseek-ai/dsh-experimental-tool-agent-team`](../t #### KV Cache 影响 -只要 bundle patch、Team identity 与配置的工具 schema 不变,本 bundle 的 composition 就保持前缀稳定。 +只要 bundle patch 与配置的工具 schema 不变,共享 system prompt 和工具 schema 就保持前缀稳定。Team 身份通过 runtime-context 快照追加;[Team 工具](../tool-agent-team/README.zh.md#model-experience)定义快照复用方式。 ## 已知限制与延期工作 diff --git a/packages/experimental/agent-team/README.i18n.yaml b/packages/experimental/agent-team/README.i18n.yaml index e4f3b0666e..017a9d603e 100644 --- a/packages/experimental/agent-team/README.i18n.yaml +++ b/packages/experimental/agent-team/README.i18n.yaml @@ -42,8 +42,8 @@ en: 6a18034f1ccc247a zh: e08b0eb0ccb41ea8 /deepseek-ai-dsh-experimental-agent-team/understand-the-implementation/design-philosophy: - en: 4b154ca76747dd92 - zh: 8fcd239fcf1c460b + en: 9034f3b96f68dee4 + zh: 4ea926474d3a8c24 /deepseek-ai-dsh-experimental-agent-team/understand-the-implementation/source-map: en: d96ba512b8327751 zh: 21481c29cf5af19a @@ -66,8 +66,8 @@ en: a12fb358183cc6d8 zh: 7fdb0434d3c407fe /deepseek-ai-dsh-experimental-agent-team/further-exploration: - en: 020d07f96ef2077d - zh: 9e771d38a02048e1 + en: 067ed50203315774 + zh: 7b4dfd41eea2208b /deepseek-ai-dsh-experimental-agent-team/further-exploration/browser-projection: en: 4b3033806e6db528 zh: 53e0dfef7309840e diff --git a/packages/experimental/agent-team/README.md b/packages/experimental/agent-team/README.md index 2d8abc7409..69d602f079 100644 --- a/packages/experimental/agent-team/README.md +++ b/packages/experimental/agent-team/README.md @@ -106,7 +106,7 @@ The service is built on one separation and three commitments: - **Explicit authority.** Every service method takes the exact live calling `Agent`; only the Lead spawns, reassigns, or interrupts. - **Bounds that fail loud.** Every limit is a validated deployment value, and exhaustion reports a typed error instead of reusing an id or name. -The [Agent Teams Agent Note](../../../.agents/notes/implemented/feature/2026-08-05-agent-teams.md) owns the identity, mailbox, task, and shared-checkout decisions. +The [Agent Teams Agent Note](../../../.agents/notes/implemented/feature/2026-08-05-agent-teams.md) owns the roster, mailbox, task, and shared-checkout decisions. The [runtime-context identity decision](../../../.agents/notes/implemented/architecture/2026-10-13-team-identity-runtime-context.md) owns model-facing identity. ### Source map @@ -162,7 +162,7 @@ Read these pages when the package-level contract is not enough. They move from t - [Agent Teams subsystem](../../../docs/subsystems/agent-team.md) — durable Team types and the `ctx.agentTeams` service API. - [tool-agent-team package](../tool-agent-team/README.md) — the tools that let the model create, message, and coordinate teammates. -- [Agent Teams Agent Note](../../../.agents/notes/implemented/feature/2026-08-05-agent-teams.md) — identity, mailbox, task, and shared-checkout decisions. +- [Agent Teams Agent Note](../../../.agents/notes/implemented/feature/2026-08-05-agent-teams.md) — roster, mailbox, task, and shared-checkout decisions. - [Experimental package reference](../AGENTS.md) — placement, publication, and dependency isolation. ----- diff --git a/packages/experimental/agent-team/README.zh.md b/packages/experimental/agent-team/README.zh.md index e60d93b255..37bcdafded 100644 --- a/packages/experimental/agent-team/README.zh.md +++ b/packages/experimental/agent-team/README.zh.md @@ -106,7 +106,7 @@ Lead 可以停止 teammate 的当前轮次,而不会删除其排队的消息 - **显式权限。** 每个服务方法都接收确切的实时调用方 `Agent`;只有 Lead 可以 spawn、reassign 或 interrupt。 - **超出上限时明确失败。** 每个限制都是经过校验的部署值,耗尽时报告类型化错误,而不是复用 id 或名字。 -[Agent Teams Agent Note](../../../.agents/notes/implemented/feature/2026-08-05-agent-teams.zh.md)负责身份、mailbox、任务与共享 checkout 决策。 +[Agent Teams Agent Note](../../../.agents/notes/implemented/feature/2026-08-05-agent-teams.zh.md)负责 roster、mailbox、任务与共享 checkout 决策。[runtime-context 身份决策](../../../.agents/notes/implemented/architecture/2026-10-13-team-identity-runtime-context.zh.md)负责面向模型的身份。 ### 源码地图 @@ -162,7 +162,7 @@ Mailbox 投影与 checkpoint 准入保留本地声明的校验器之外获准内 - [Agent Teams 子系统](../../../docs/subsystems/agent-team.zh.md)——持久 Team 类型与 `ctx.agentTeams` 服务 API。 - [tool-agent-team 包](../tool-agent-team/README.zh.md)——让模型创建 teammate、向其发送消息并进行协调的工具。 -- [Agent Teams Agent Note](../../../.agents/notes/implemented/feature/2026-08-05-agent-teams.zh.md)——身份、mailbox、任务与共享 checkout 决策。 +- [Agent Teams Agent Note](../../../.agents/notes/implemented/feature/2026-08-05-agent-teams.zh.md)——roster、mailbox、任务与共享 checkout 决策。 - [实验包参考](../AGENTS.md)——位置、公开发布与依赖隔离。 ----- diff --git a/packages/experimental/tool-agent-team/README.i18n.yaml b/packages/experimental/tool-agent-team/README.i18n.yaml index 8d66841273..536f4a8e2e 100644 --- a/packages/experimental/tool-agent-team/README.i18n.yaml +++ b/packages/experimental/tool-agent-team/README.i18n.yaml @@ -63,8 +63,8 @@ en: 2ba143e89873e768 zh: 4f09446c0fb13cdb /deepseek-ai-dsh-experimental-tool-agent-team/known-limitations-and-deferred-work: - en: c459b2e8236e6a6c - zh: 7cd2af569e9b751a + en: 0fb9ccc715a43f3a + zh: baf04d4b1cf2a7f6 /deepseek-ai-dsh-experimental-tool-agent-team/known-limitations-and-deferred-work/dev-note: en: e67f633dc6fe7773 zh: 3bb0c20c93f16f98 diff --git a/packages/experimental/tool-agent-team/README.md b/packages/experimental/tool-agent-team/README.md index ce0ae1e0d8..c4599ca754 100644 --- a/packages/experimental/tool-agent-team/README.md +++ b/packages/experimental/tool-agent-team/README.md @@ -138,8 +138,6 @@ With the same provider/model, shared system policy, and tool schemas, a fork ret -- **One-shot child tool visibility** — in-process one-shot children receive their subagent descriptor after publication. Team installation can therefore mistake them for Leads and expose Team policy and tools. Calls are rejected once the descriptor identifies them as non-members. Correcting installation timing is deferred. - These limits describe what the policy and tools cannot guarantee for a team. They are current package constraints, not a comparison with other collaboration surfaces. - **Prompt policy is coordination, not confinement** — it cannot stop Bash or external processes from writing overlapping files. diff --git a/packages/experimental/tool-agent-team/README.zh.md b/packages/experimental/tool-agent-team/README.zh.md index cba2d69292..018edc7509 100644 --- a/packages/experimental/tool-agent-team/README.zh.md +++ b/packages/experimental/tool-agent-team/README.zh.md @@ -138,8 +138,6 @@ provider/model、共享 system 策略和工具 schema 相同时,fork 保留 -- **一次性子代理工具可见性**——进程内一次性子代理在发布后才获得 subagent descriptor。Team 安装因此可能将它们误认作 Lead 并暴露 Team 策略和工具。descriptor 将它们识别为非成员后,调用会被拒绝。安装时序修复留待以后处理。 - 这些限制说明策略与工具无法为一支团队保证什么。它们是当前包约束,不是与其他协作方式的对比。 - **提示词策略只负责协调,不负责 confinement**——它无法阻止 Bash 或外部进程写入重叠文件。