diff --git a/docs/tool-catalog.i18n.yaml b/docs/tool-catalog.i18n.yaml index 55047ce349..2ab2f56624 100644 --- a/docs/tool-catalog.i18n.yaml +++ b/docs/tool-catalog.i18n.yaml @@ -264,8 +264,8 @@ en: f9457f033f75f00a zh: a2d60ec44118c34c /tool-schema-catalog/deepseek-ai-dsh-experimental-tool-agent-team/send-message: - en: 0746bb11dae8db55 - zh: 8b634add76c4d88a + en: ec50e6a0b86aecc6 + zh: 29c8728536a5adf1 /tool-schema-catalog/deepseek-ai-dsh-experimental-tool-agent-team/spawn-teammate: en: 02d6cc746e234b99 zh: 49bc60ac098bca48 diff --git a/docs/tool-catalog.md b/docs/tool-catalog.md index bb9c962421..8aa9fb0096 100644 --- a/docs/tool-catalog.md +++ b/docs/tool-catalog.md @@ -2257,7 +2257,7 @@ Source: [`packages/experimental/tool-agent-team/src/index.ts`](../packages/exper ### `send_message` -Send one message to another Team member and return its accepted message id. A running target receives it at the nearest step boundary; an inactive target starts or resumes a turn. +Send one message to another Team member. A running target receives it at the nearest step boundary; an inactive target starts or resumes a turn. ```json { diff --git a/docs/tool-catalog.zh.md b/docs/tool-catalog.zh.md index a8e14e9970..b505568dde 100644 --- a/docs/tool-catalog.zh.md +++ b/docs/tool-catalog.zh.md @@ -2263,7 +2263,7 @@ lsp 工具将提供方选择和语言服务器子进程置于 ctx.lsp 之后, ### `send_message` -向另一名 Team member 发送一条消息,并返回获准消息 id。running target 会在最近的步骤边界收到消息;inactive target 会启动或恢复一个 turn。 +向另一名 Team member 发送一条消息。running target 会在最近的步骤边界收到消息;inactive target 会启动或恢复一个 turn。 ```json { diff --git a/docs/upgrade-guide/v0.2.1-alpha.1/team-direct-inbox/guide.i18n.yaml b/docs/upgrade-guide/v0.2.1-alpha.1/team-direct-inbox/guide.i18n.yaml index d56c61bdd0..0f10d46677 100644 --- a/docs/upgrade-guide/v0.2.1-alpha.1/team-direct-inbox/guide.i18n.yaml +++ b/docs/upgrade-guide/v0.2.1-alpha.1/team-direct-inbox/guide.i18n.yaml @@ -9,8 +9,8 @@ en: 04d7dcbdc1679eae zh: 8b083641a9262d80 /agent-teams-messages-use-target-inboxes/change: - en: 94d62cf9d98270ab - zh: c589725cd35ccd06 + en: 9968decf3dd340af + zh: 736a32caac4b5103 /agent-teams-messages-use-target-inboxes/migration: - en: f7811928da727edc - zh: 9a28b6b745725a6d + en: 7ffd442bfd55769e + zh: ffb11a143f11ce7f diff --git a/docs/upgrade-guide/v0.2.1-alpha.1/team-direct-inbox/guide.md b/docs/upgrade-guide/v0.2.1-alpha.1/team-direct-inbox/guide.md index 5e718a02dd..974c1aa13c 100644 --- a/docs/upgrade-guide/v0.2.1-alpha.1/team-direct-inbox/guide.md +++ b/docs/upgrade-guide/v0.2.1-alpha.1/team-direct-inbox/guide.md @@ -9,7 +9,7 @@ English | [中文](guide.zh.md) ## Change -The experimental Agent Teams plugin sends new messages directly to the target Agent inbox instead of retaining a separate Team mailbox. `send_message` returns only `messageId`; it no longer returns an `accepted` or `queued` status. Acceptance does not confirm model processing or a synchronous storage flush. Failed sends are not retained for retry, and explicit resends are not deduplicated. +The experimental Agent Teams plugin sends new messages directly to the target Agent inbox instead of retaining a separate Team mailbox. `send_message` returns only `{ "sent": true }`; it exposes neither a message ID nor an `accepted` or `queued` status. Acceptance does not confirm model processing or a synchronous storage flush. Failed sends are not retained for retry, and explicit resends are not deduplicated. The `maxPendingMessagesPerMember` configuration key is removed. Historical `team/message/queued` and `team/message/delivered` records remain readable, but queued messages that were not delivered before upgrading are never dispatched. Roster and task state remain durable. @@ -17,5 +17,5 @@ The `maxPendingMessagesPerMember` configuration key is removed. Historical `team 1. Before upgrading, let pending Team messages finish and confirm that their targets received them. After upgrading, explicitly resend any required undelivered message; check the target's history first to avoid duplicates. Do not edit historical Session records. 2. Remove `maxPendingMessagesPerMember` from the `@deepseek-ai/dsh-experimental-agent-team` plugin configuration in your `cordis.yml` or overlays. There is no replacement Team queue limit; `maxMessageBytes` still bounds each complete sender-framed message. -3. Update any consumer of `send_message` results to use `messageId` alone and handle send errors explicitly. Do not treat success as completed target work. -4. Start your Team-enabled profile, send a message to another member, and confirm that the tool returns `messageId` and that the target receives it. Consult the [package reference](../../../../packages/experimental/agent-team/README.md#use-this-package) for delivery semantics. +3. Update any consumer of `send_message` results to read `sent` instead of message IDs or delivery statuses, and handle send errors explicitly. Do not treat success as completed target work. The `ctx.agentTeams.sendMessage()` service still returns `messageId`. +4. Start your Team-enabled profile, send a message to another member, and confirm that the tool returns `{ "sent": true }` and that the target receives it. Consult the [package reference](../../../../packages/experimental/agent-team/README.md#use-this-package) for delivery semantics. diff --git a/docs/upgrade-guide/v0.2.1-alpha.1/team-direct-inbox/guide.zh.md b/docs/upgrade-guide/v0.2.1-alpha.1/team-direct-inbox/guide.zh.md index 4015095c70..c10791fbf7 100644 --- a/docs/upgrade-guide/v0.2.1-alpha.1/team-direct-inbox/guide.zh.md +++ b/docs/upgrade-guide/v0.2.1-alpha.1/team-direct-inbox/guide.zh.md @@ -9,7 +9,7 @@ description: "Agent Teams 移除待投递消息数量限制,并停止投递历 ## 变更 -实验性 Agent Teams 插件将新消息直接发送到目标 Agent 收件箱,不再保留独立的 Team 邮箱。`send_message` 仅返回 `messageId`,不再返回 `accepted` 或 `queued` 状态。接收成功不表示模型已处理消息,也不保证同步刷新到存储。失败的发送不会保留以供重试,显式重发也不会去重。 +实验性 Agent Teams 插件将新消息直接发送到目标 Agent 收件箱,不再保留独立的 Team 邮箱。`send_message` 仅返回 `{ "sent": true }`,不暴露消息 ID,也不返回 `accepted` 或 `queued` 状态。接收成功不表示模型已处理消息,也不保证同步刷新到存储。失败的发送不会保留以供重试,显式重发也不会去重。 配置键 `maxPendingMessagesPerMember` 已移除。历史 `team/message/queued` 和 `team/message/delivered` 记录仍可读取,但升级前尚未投递的排队消息永远不会被派发。成员名单与任务状态仍然持久保存。 @@ -17,5 +17,5 @@ description: "Agent Teams 移除待投递消息数量限制,并停止投递历 1. 升级前,让待投递的 Team 消息完成投递,并确认目标已收到。升级后,显式重发仍需处理的未投递消息;先检查目标历史,避免重复。不要编辑历史 Session 记录。 2. 从 `cordis.yml` 或覆盖配置中 `@deepseek-ai/dsh-experimental-agent-team` 插件的配置移除 `maxPendingMessagesPerMember`。没有替代的 Team 队列限制;`maxMessageBytes` 仍限制包含发送者标识的完整消息大小。 -3. 更新所有读取 `send_message` 结果的调用方,仅使用 `messageId`,并显式处理发送错误。不要把发送成功视为目标工作已完成。 -4. 启动启用 Team 的 profile,向其他成员发送消息,确认工具返回 `messageId` 且目标收到消息。投递语义参见[包参考](../../../../packages/experimental/agent-team/README.zh.md#use-this-package)。 +3. 更新所有读取 `send_message` 结果的调用方,改为读取 `sent` 而非消息 ID 或投递状态,并显式处理发送错误。不要把发送成功视为目标工作已完成。`ctx.agentTeams.sendMessage()` 服务仍返回 `messageId`。 +4. 启动启用 Team 的 profile,向其他成员发送消息,确认工具返回 `{ "sent": true }` 且目标收到消息。投递语义参见[包参考](../../../../packages/experimental/agent-team/README.zh.md#use-this-package)。 diff --git a/packages/experimental/tool-agent-team/README.i18n.yaml b/packages/experimental/tool-agent-team/README.i18n.yaml index d456c7b266..2766c8e359 100644 --- a/packages/experimental/tool-agent-team/README.i18n.yaml +++ b/packages/experimental/tool-agent-team/README.i18n.yaml @@ -27,8 +27,8 @@ en: be42811bbcc3b438 zh: 014bd055ca694315 /deepseek-ai-dsh-experimental-tool-agent-team/use-this-package/what-success-and-failure-look-like: - en: 259e9d39e1d1579a - zh: c61feed86e1ba2d2 + en: e49a980372c55892 + zh: d4bcdd36278d040d /deepseek-ai-dsh-experimental-tool-agent-team/understand-the-implementation: en: 3952eb1d9de1f988 zh: 789d51b88f41b710 diff --git a/packages/experimental/tool-agent-team/README.md b/packages/experimental/tool-agent-team/README.md index 52ca014795..bb849dc717 100644 --- a/packages/experimental/tool-agent-team/README.md +++ b/packages/experimental/tool-agent-team/README.md @@ -65,7 +65,7 @@ Creation and listing results identify members by `target`, with no member Sessio ### What success and failure look like -Sending a message succeeds as soon as it is safely stored: the result is `accepted` (delivered now) or `queued` (waiting), and a queued message must not be resent. `wait_agent` returns `noProgress` right away when no other member is running or provisioning, telling the caller to wake a teammate first; otherwise it waits for the next change and the caller re-reads state afterward. Task edits based on an outdated revision are rejected rather than overwriting newer work. +`send_message` returns `{ "sent": true }` after inbox acceptance, without exposing the message ID. Success does not confirm recipient processing or a synchronous storage flush; send failures are reported as tool errors. `wait_agent` returns `noProgress` right away when no other member is running or provisioning, telling the caller to wake a teammate first; otherwise it waits for the next change and the caller re-reads state afterward. Task edits based on an outdated revision are rejected rather than overwriting newer work. ----- diff --git a/packages/experimental/tool-agent-team/README.zh.md b/packages/experimental/tool-agent-team/README.zh.md index bf4d7e606c..931f60c424 100644 --- a/packages/experimental/tool-agent-team/README.zh.md +++ b/packages/experimental/tool-agent-team/README.zh.md @@ -65,7 +65,7 @@ kind: "package-reference" ### 成功与失败的表现 -发送消息在安全存储后即成功:结果为 `accepted`(已立即送达)或 `queued`(等待中),排队的消息绝不能重发。当没有其他成员 running 或 provisioning 时,`wait_agent` 会立即返回 `noProgress`,提示调用方先唤醒 teammate;否则它会等待下一次变化,调用方随后重新读取状态。基于过期 revision 的任务编辑会被拒绝,而不是覆盖更新的成果。 +`send_message` 在收件箱接收消息后返回 `{ "sent": true }`,不暴露消息 ID。成功不表示接收方已处理消息,也不保证同步刷新到存储;发送失败会作为工具错误报告。当没有其他成员 running 或 provisioning 时,`wait_agent` 会立即返回 `noProgress`,提示调用方先唤醒 teammate;否则它会等待下一次变化,调用方随后重新读取状态。基于过期 revision 的任务编辑会被拒绝,而不是覆盖更新的成果。 ----- diff --git a/packages/experimental/tool-agent-team/src/index.ts b/packages/experimental/tool-agent-team/src/index.ts index 598c6d45d2..28f9cc62b7 100644 --- a/packages/experimental/tool-agent-team/src/index.ts +++ b/packages/experimental/tool-agent-team/src/index.ts @@ -34,7 +34,7 @@ The Team Lead and all teammates share the same working directory and filesystem. Prefer read/edit/write for file changes. If a file operation returns FS_STALE_VERSION, read the current file, rebase your intended change onto the new content, and retry. Bash, formatters, code generators, and scripts are not fully protected by the filesystem version guard; coordinate them explicitly and have the Lead review the final diff and run tests. -Use the target returned by spawn_teammate or list_agents for send_message and interrupt_agent, or as owner when assigning or filtering shared tasks. send_message steers a running target at its nearest step boundary and starts or resumes an inactive target. inactive means no turn is executing; it does not describe task completion, success, failure, or waiting for other agents. provisioning means member creation is in progress; failed means member creation failed. A peer message starts with its sender name. A successful send returns the accepted message id; it does not mean the recipient has processed it. Shared-task workflow is list, get, claim with the current revision, perform the work, then complete. Task readiness never starts an owner. Before wait_agent, use list_agents and make sure another required member is running or provisioning; use send_message first when the required member is inactive. wait_agent observes only changes after that call starts, never wakes a member, and returns noProgress immediately when no other member can produce a change. Re-list after wakeup or timeout. The Lead must wait for required teammates before giving the final answer.` +Use the target returned by spawn_teammate or list_agents for send_message and interrupt_agent, or as owner when assigning or filtering shared tasks. send_message steers a running target at its nearest step boundary and starts or resumes an inactive target. inactive means no turn is executing; it does not describe task completion, success, failure, or waiting for other agents. provisioning means member creation is in progress; failed means member creation failed. A peer message starts with its sender name. A successful send does not mean the recipient has processed it. Shared-task workflow is list, get, claim with the current revision, perform the work, then complete. Task readiness never starts an owner. Before wait_agent, use list_agents and make sure another required member is running or provisioning; use send_message first when the required member is inactive. wait_agent observes only changes after that call starts, never wakes a member, and returns noProgress immediately when no other member can produce a change. Re-list after wakeup or timeout. The Lead must wait for required teammates before giving the final answer.` const ACTIVE_WAIT_STATUSES: ReadonlySet = new Set(['running', 'provisioning']) const NO_ACTIVE_PEER_MESSAGE = 'No other Team member is running or provisioning. wait_agent cannot make progress or wake inactive teammates. Re-list with list_agents and team_task_list, then use send_message to wake each required inactive teammate before waiting again.' @@ -97,7 +97,7 @@ const SEND_VALUE_SCHEMA = { type: 'object', additionalProperties: false, properties: { - messageId: { type: 'string', required: true }, + sent: { type: 'boolean', required: true, const: true }, }, } as const @@ -213,18 +213,19 @@ To message another teammate, use send_message({ target: "", messa register(scoped.tools.register(defineTool({ name: 'send_message', - description: 'Send one message to another Team member and return its accepted message id. A running target receives it at the nearest step boundary; an inactive target starts or resumes a turn.', + description: 'Send one message to another Team member. A running target receives it at the nearest step boundary; an inactive target starts or resumes a turn.', parameters: { target: { type: 'string', required: true, description: 'Member target returned by spawn_teammate or list_agents, including lead.' }, message: { type: 'string', required: true, description: 'Self-contained message for the target.' }, }, output: jsonOutput(SEND_VALUE_SCHEMA), - execute(args, exec) { - return ctx.agentTeams.sendMessage(callingAgent(exec.agent, 'send_message'), { + async execute(args, exec) { + await ctx.agentTeams.sendMessage(callingAgent(exec.agent, 'send_message'), { target: args.target, content: [{ type: 'text', text: args.message }], signal: exec.signal, }) + return { sent: true } }, }))) 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 7bb450908d..ec4c795c01 100644 --- a/packages/experimental/tool-agent-team/tests/tool-team.spec.ts +++ b/packages/experimental/tool-agent-team/tests/tool-team.spec.ts @@ -202,6 +202,7 @@ describe('dsh-tool-team', () => { expect(JSON.parse(text(tasks))).toMatchObject({ tasks: [{ id: task.id, ownerName: member.target }] }) const sent = await execute(ctx, lead, 'send_message', { target: member.target, message: 'review the diff' }) expect(sent.isError).toBe(false) + expect(JSON.parse(text(sent))).toEqual({ sent: true }) const interrupted = await execute(ctx, lead, 'interrupt_agent', { target: listed[1]!.target }) expect(interrupted.isError).toBe(false) await child.whenIdle() @@ -483,10 +484,10 @@ describe('dsh-tool-team', () => { expect(text(roster)).toBe(JSON.stringify(JSON.parse(text(roster)))) const peer = await execute(ctx, child, 'send_message', { target: 'lead', message: 'progress report' }) expect(peer.isError).toBe(false) - expect(JSON.parse(text(peer))).toHaveProperty('messageId') + expect(JSON.parse(text(peer))).toEqual({ sent: true }) const followup = await execute(ctx, child, 'send_message', { target: 'lead', message: 'review the report' }) expect(followup.isError).toBe(false) - expect(JSON.parse(text(followup))).toHaveProperty('messageId') + expect(JSON.parse(text(followup))).toEqual({ sent: true }) await lead.whenIdle() const created = await execute(ctx, lead, 'team_task_create', { diff --git a/snapshots/session/team-direct-inbox/session.v4.jsonl b/snapshots/session/team-direct-inbox/session.v4.jsonl index ca4c1e1d63..f96005610c 100644 --- a/snapshots/session/team-direct-inbox/session.v4.jsonl +++ b/snapshots/session/team-direct-inbox/session.v4.jsonl @@ -27,7 +27,7 @@ {"type":"step/start","data":{"turn":1,"step":3}} {"type":"assistant/message","data":{"turn":1,"step":3,"message":{"role":"assistant","content":[{"type":"tool-call","id":"direct-3","name":"send_message","arguments":"{\"target\":\"reviewer\",\"message\":\"Review the direct inbox delivery.\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{message:8}}"},"usage":{"inputTokens":3,"outputTokens":3},"stream":[{"type":"chunk","time":1790429366017,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}},{"type":"tool-call-chunks","time0":1790429366017,"index":0,"dt":[],"id":"direct-3","name":"send_message","args":["{\"target\":\"reviewer\",\"message\":\"Review the direct inbox delivery.\"}"]},{"type":"chunk","time":1790429366017,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"direct-3","name":"send_message","arguments":"{\"target\":\"reviewer\",\"message\":\"Review the direct inbox delivery.\"}"}}},{"type":"chunk","time":1790429366017,"chunk":{"type":"usage","usage":{"inputTokens":3,"outputTokens":3}}},{"type":"chunk","time":1790429366017,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}]},"surfaceOp":"append"} {"type":"tool/call","data":{"turn":1,"step":3,"callId":"direct-3","name":"send_message","arguments":"{\"target\":\"reviewer\",\"message\":\"Review the direct inbox delivery.\"}"}} -{"type":"tool/result","data":{"turn":1,"step":3,"message":{"role":"tool","source":{"kind":"tool","callId":"direct-3"},"toolCallId":"direct-3","content":[{"type":"text","text":"{\"messageId\":\"{{message:17}}\"}"}],"isError":false,"id":"{{message:9}}"}},"sourceEventSeqs":[27],"surfaceOp":"append"} +{"type":"tool/result","data":{"turn":1,"step":3,"message":{"role":"tool","source":{"kind":"tool","callId":"direct-3"},"toolCallId":"direct-3","content":[{"type":"text","text":"{\"sent\":true}"}],"isError":false,"id":"{{message:9}}"}},"sourceEventSeqs":[27],"surfaceOp":"append"} {"type":"step/end","data":{"turn":1,"step":3}} {"type":"step/start","data":{"turn":1,"step":4}} {"type":"assistant/message","data":{"turn":1,"step":4,"message":{"role":"assistant","content":[{"type":"tool-call","id":"direct-4","name":"interrupt_agent","arguments":"{\"target\":\"reviewer\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{message:10}}"},"usage":{"inputTokens":3,"outputTokens":3},"stream":[{"type":"chunk","time":1790429366033,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}},{"type":"tool-call-chunks","time0":1790429366033,"index":0,"dt":[],"id":"direct-4","name":"interrupt_agent","args":["{\"target\":\"reviewer\"}"]},{"type":"chunk","time":1790429366033,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"direct-4","name":"interrupt_agent","arguments":"{\"target\":\"reviewer\"}"}}},{"type":"chunk","time":1790429366033,"chunk":{"type":"usage","usage":{"inputTokens":3,"outputTokens":3}}},{"type":"chunk","time":1790429366033,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}]},"surfaceOp":"append"} diff --git a/snapshots/session/team-targets/system-prompt.expected.md b/snapshots/session/team-targets/system-prompt.expected.md index 0328526de4..d0a6acd972 100644 --- a/snapshots/session/team-targets/system-prompt.expected.md +++ b/snapshots/session/team-targets/system-prompt.expected.md @@ -11,7 +11,7 @@ The Team Lead and all teammates share the same working directory and filesystem. Prefer read/edit/write for file changes. If a file operation returns FS_STALE_VERSION, read the current file, rebase your intended change onto the new content, and retry. Bash, formatters, code generators, and scripts are not fully protected by the filesystem version guard; coordinate them explicitly and have the Lead review the final diff and run tests. -Use the target returned by spawn_teammate or list_agents for send_message and interrupt_agent, or as owner when assigning or filtering shared tasks. send_message steers a running target at its nearest step boundary and starts or resumes an inactive target. inactive means no turn is executing; it does not describe task completion, success, failure, or waiting for other agents. provisioning means member creation is in progress; failed means member creation failed. A peer message starts with its sender name. A successful send returns the accepted message id; it does not mean the recipient has processed it. Shared-task workflow is list, get, claim with the current revision, perform the work, then complete. Task readiness never starts an owner. Before wait_agent, use list_agents and make sure another required member is running or provisioning; use send_message first when the required member is inactive. wait_agent observes only changes after that call starts, never wakes a member, and returns noProgress immediately when no other member can produce a change. Re-list after wakeup or timeout. The Lead must wait for required teammates before giving the final answer. +Use the target returned by spawn_teammate or list_agents for send_message and interrupt_agent, or as owner when assigning or filtering shared tasks. send_message steers a running target at its nearest step boundary and starts or resumes an inactive target. inactive means no turn is executing; it does not describe task completion, success, failure, or waiting for other agents. provisioning means member creation is in progress; failed means member creation failed. A peer message starts with its sender name. A successful send does not mean the recipient has processed it. Shared-task workflow is list, get, claim with the current revision, perform the work, then complete. Task readiness never starts an owner. Before wait_agent, use list_agents and make sure another required member is running or provisioning; use send_message first when the required member is inactive. wait_agent observes only changes after that call starts, never wakes a member, and returns noProgress immediately when no other member can produce a change. Re-list after wakeup or timeout. The Lead must wait for required teammates before giving the final answer. Check the [exit code: N] marker on every bash result; investigate failures before moving on. diff --git a/snapshots/session/team-targets/tool-schemas.expected.json b/snapshots/session/team-targets/tool-schemas.expected.json index c639cbf790..4926edb120 100644 --- a/snapshots/session/team-targets/tool-schemas.expected.json +++ b/snapshots/session/team-targets/tool-schemas.expected.json @@ -293,7 +293,7 @@ }, { "name": "send_message", - "description": "Send one message to another Team member and return its accepted message id. A running target receives it at the nearest step boundary; an inactive target starts or resumes a turn.", + "description": "Send one message to another Team member. A running target receives it at the nearest step boundary; an inactive target starts or resumes a turn.", "parameters": { "type": "object", "properties": {