@qlzt/dsh-tool-subagent-control 0.0.0-stage → 0.2.1-alpha.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.i18n.yaml +106 -0
- package/README.md +180 -2
- package/README.zh.md +181 -0
- package/lib/index.js +95 -0
- package/lib/types/index.d.ts +19 -0
- package/lib/types/index.js +98 -0
- package/lib/types/list-agents.d.ts +17 -0
- package/lib/types/list-agents.js +136 -0
- package/package.json +60 -4
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 DeepSeek
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.i18n.yaml
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# Bilingual-pair consistency record for README.md (docs/i18n/README.md): per heading
|
|
2
|
+
# section, a hash of its English and Chinese blocks outside code blocks and generated regions.
|
|
3
|
+
# After editing either side, bring the other along and re-record with:
|
|
4
|
+
# pnpm run verify-translation-pairing --write packages/subagent/tool-subagent-control/README.md
|
|
5
|
+
/:
|
|
6
|
+
en: 5413b8e52a0c8e3d
|
|
7
|
+
zh: 9b6d0385209ff9bb
|
|
8
|
+
/deepseek-ai-dsh-tool-subagent-control:
|
|
9
|
+
en: 465d36925c792167
|
|
10
|
+
zh: 269cac314f638827
|
|
11
|
+
/deepseek-ai-dsh-tool-subagent-control/summary:
|
|
12
|
+
en: 7464eb99b6f618eb
|
|
13
|
+
zh: 8c7628c8e9f163ca
|
|
14
|
+
/deepseek-ai-dsh-tool-subagent-control/table-of-contents:
|
|
15
|
+
en: d152484eb41ac6b4
|
|
16
|
+
zh: 09388d293f9be9cb
|
|
17
|
+
/deepseek-ai-dsh-tool-subagent-control/use-this-package:
|
|
18
|
+
en: 27c5bbe682f0b72b
|
|
19
|
+
zh: b16aeb2c43f3692e
|
|
20
|
+
/deepseek-ai-dsh-tool-subagent-control/use-this-package/minimal-configuration:
|
|
21
|
+
en: 4a52c81317ec9001
|
|
22
|
+
zh: ebd9f1ba920da50a
|
|
23
|
+
/deepseek-ai-dsh-tool-subagent-control/use-this-package/send-message:
|
|
24
|
+
en: d80bb1df2eb740b7
|
|
25
|
+
zh: e3203d9868a82910
|
|
26
|
+
/deepseek-ai-dsh-tool-subagent-control/use-this-package/interrupt-agent:
|
|
27
|
+
en: af01696cc8deaf83
|
|
28
|
+
zh: 86e40bc28d5362b1
|
|
29
|
+
/deepseek-ai-dsh-tool-subagent-control/use-this-package/list-agents:
|
|
30
|
+
en: 631c0a34dadcb8f8
|
|
31
|
+
zh: dbc536512cae070f
|
|
32
|
+
/deepseek-ai-dsh-tool-subagent-control/understand-the-implementation:
|
|
33
|
+
en: c5cdf01a78c990f2
|
|
34
|
+
zh: 53c180d726ce4502
|
|
35
|
+
/deepseek-ai-dsh-tool-subagent-control/understand-the-implementation/design-concept:
|
|
36
|
+
en: 0af7238c690ee8d6
|
|
37
|
+
zh: 5049eea23770ffed
|
|
38
|
+
/deepseek-ai-dsh-tool-subagent-control/understand-the-implementation/delivery-and-signal-ownership:
|
|
39
|
+
en: 4c7698ccea49a60b
|
|
40
|
+
zh: fbf129ff583e6ab9
|
|
41
|
+
/deepseek-ai-dsh-tool-subagent-control/understand-the-implementation/listing-projection:
|
|
42
|
+
en: 70e344022e6e535e
|
|
43
|
+
zh: 355488590648a82e
|
|
44
|
+
/deepseek-ai-dsh-tool-subagent-control/understand-the-implementation/source-map:
|
|
45
|
+
en: 95f73146f8735ab1
|
|
46
|
+
zh: 9c67e064c4000613
|
|
47
|
+
/deepseek-ai-dsh-tool-subagent-control/further-exploration:
|
|
48
|
+
en: df2bf39d0ffffd43
|
|
49
|
+
zh: 4cd02551f7433c90
|
|
50
|
+
/deepseek-ai-dsh-tool-subagent-control/model-experience:
|
|
51
|
+
en: 215e7ba838619b7b
|
|
52
|
+
zh: a311da3843709f90
|
|
53
|
+
/deepseek-ai-dsh-tool-subagent-control/model-experience/tool-schema:
|
|
54
|
+
en: e4c7376d4f29dbd5
|
|
55
|
+
zh: 6b7a9eaf69c9ea53
|
|
56
|
+
/deepseek-ai-dsh-tool-subagent-control/model-experience/tool-schema/what-the-model-sees:
|
|
57
|
+
en: b32bc9bcb45a8c77
|
|
58
|
+
zh: 4bd3eba1e8612da7
|
|
59
|
+
/deepseek-ai-dsh-tool-subagent-control/model-experience/tool-schema/token-effect:
|
|
60
|
+
en: db207dc8d5860684
|
|
61
|
+
zh: ad2663b4967fbca9
|
|
62
|
+
/deepseek-ai-dsh-tool-subagent-control/model-experience/tool-schema/kv-cache-effect:
|
|
63
|
+
en: 4b77d42b96b3519d
|
|
64
|
+
zh: dd393d8f0f6536c1
|
|
65
|
+
/deepseek-ai-dsh-tool-subagent-control/model-experience/interrupt-result:
|
|
66
|
+
en: d64e936e83e89a2b
|
|
67
|
+
zh: b9905c33af6cca45
|
|
68
|
+
/deepseek-ai-dsh-tool-subagent-control/model-experience/interrupt-result/what-the-model-sees:
|
|
69
|
+
en: 89305619897680ba
|
|
70
|
+
zh: e610a844fc09c53f
|
|
71
|
+
/deepseek-ai-dsh-tool-subagent-control/model-experience/interrupt-result/token-effect:
|
|
72
|
+
en: 5d1bcef28b5f18da
|
|
73
|
+
zh: 027d67d93d660e76
|
|
74
|
+
/deepseek-ai-dsh-tool-subagent-control/model-experience/interrupt-result/kv-cache-effect:
|
|
75
|
+
en: 4a629edb36a17e32
|
|
76
|
+
zh: 5a7539cfbf404c54
|
|
77
|
+
/deepseek-ai-dsh-tool-subagent-control/model-experience/delivery-result:
|
|
78
|
+
en: ab964e307bd37dca
|
|
79
|
+
zh: 03f975252f838a42
|
|
80
|
+
/deepseek-ai-dsh-tool-subagent-control/model-experience/delivery-result/what-the-model-sees:
|
|
81
|
+
en: 4a0a4955589012ae
|
|
82
|
+
zh: 2bbbb5196a8aa4fd
|
|
83
|
+
/deepseek-ai-dsh-tool-subagent-control/model-experience/delivery-result/token-effect:
|
|
84
|
+
en: 0f134e37e4bd9965
|
|
85
|
+
zh: ceb858d01266e976
|
|
86
|
+
/deepseek-ai-dsh-tool-subagent-control/model-experience/delivery-result/kv-cache-effect:
|
|
87
|
+
en: f5d5f97a153f7c70
|
|
88
|
+
zh: 3d6bc05b9eadfbc2
|
|
89
|
+
/deepseek-ai-dsh-tool-subagent-control/model-experience/listing-result:
|
|
90
|
+
en: 094e55d258f2ec2e
|
|
91
|
+
zh: f364bc9046530bff
|
|
92
|
+
/deepseek-ai-dsh-tool-subagent-control/model-experience/listing-result/what-the-model-sees:
|
|
93
|
+
en: efbbd1e36c7b2edd
|
|
94
|
+
zh: a8a95475666ed1dc
|
|
95
|
+
/deepseek-ai-dsh-tool-subagent-control/model-experience/listing-result/token-effect:
|
|
96
|
+
en: 4688e849b3143dfc
|
|
97
|
+
zh: f22b5520c454f9e7
|
|
98
|
+
/deepseek-ai-dsh-tool-subagent-control/model-experience/listing-result/kv-cache-effect:
|
|
99
|
+
en: 4a629edb36a17e32
|
|
100
|
+
zh: 5a7539cfbf404c54
|
|
101
|
+
/deepseek-ai-dsh-tool-subagent-control/known-limitations-and-deferred-work:
|
|
102
|
+
en: 31cd8a1934cf0093
|
|
103
|
+
zh: 2fd07e05c8e58e9a
|
|
104
|
+
/deepseek-ai-dsh-tool-subagent-control/known-limitations-and-deferred-work/dev-note:
|
|
105
|
+
en: e67f633dc6fe7773
|
|
106
|
+
zh: 3bb0c20c93f16f98
|
package/README.md
CHANGED
|
@@ -1,3 +1,181 @@
|
|
|
1
|
-
|
|
1
|
+
---
|
|
2
|
+
description: "Global send_message, interrupt_agent, and list_agents tools for users and maintainers composing or debugging continuable-child control."
|
|
3
|
+
kind: "package-reference"
|
|
4
|
+
---
|
|
2
5
|
|
|
3
|
-
|
|
6
|
+
# @deepseek-ai/dsh-tool-subagent-control
|
|
7
|
+
|
|
8
|
+
English | [中文](README.zh.md)
|
|
9
|
+
|
|
10
|
+
## Summary
|
|
11
|
+
|
|
12
|
+
`dsh-tool-subagent-control` adds the global control tools for continuable children: `send_message` steers between a direct parent and child, `interrupt_agent` stops a child's current turn while keeping its inbox and descendants intact, and `list_agents` (from the separately loadable `list-agents` plugin) lists continuable children by durable id and label. Parents and continuable children inherit the same `send_message` definition and ordering, so model communication adds no child-only tool schema. No tool's presence decides whether a delegation tool starts continuable work.
|
|
13
|
+
|
|
14
|
+
## Table of Contents
|
|
15
|
+
|
|
16
|
+
- [Use this package](#use-this-package)
|
|
17
|
+
- [Understand the implementation](#understand-the-implementation)
|
|
18
|
+
- [Further Exploration](#further-exploration)
|
|
19
|
+
- [Model Experience](#model-experience)
|
|
20
|
+
- [Known Limitations and Deferred Work](#known-limitations-and-deferred-work)
|
|
21
|
+
- [Dev Note](#dev-note)
|
|
22
|
+
|
|
23
|
+
-----
|
|
24
|
+
|
|
25
|
+
<a id="use-this-package"></a>
|
|
26
|
+
## Use this package
|
|
27
|
+
|
|
28
|
+
Mount this package in any composition with continuable children the model should message, interrupt, or list. The root plugin needs only the subagent service; the list tool is a separate plugin a deployment can omit.
|
|
29
|
+
|
|
30
|
+
### Minimal configuration
|
|
31
|
+
|
|
32
|
+
Load the subagent service, a backend, the delegation tool, and this package. Adding the separate list plugin exposes all three tools:
|
|
33
|
+
|
|
34
|
+
```yaml
|
|
35
|
+
- name: '@deepseek-ai/dsh-subagent'
|
|
36
|
+
- name: '@deepseek-ai/dsh-subagent-spawn-in-process'
|
|
37
|
+
- name: '@deepseek-ai/dsh-tool-subagent'
|
|
38
|
+
config:
|
|
39
|
+
provider: spawn
|
|
40
|
+
- name: '@deepseek-ai/dsh-tool-subagent-control'
|
|
41
|
+
- name: '@deepseek-ai/dsh-tool-subagent-control/list-agents'
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
This package takes no configuration: the root plugin provides `send_message` and `interrupt_agent`, and the list plugin provides `list_agents`.
|
|
45
|
+
|
|
46
|
+
### send_message
|
|
47
|
+
|
|
48
|
+
Sends a message to an Agent named by `agent_id`: any exact live Agent may target its direct continuable child, while a resident continuable child may also target its direct parent. A working target receives the message at its nearest step boundary through Steer; an inactive target starts or resumes a turn through the continuation lifecycle. The call returns only acceptance (the accepted message's stable `messageId`), never a reply. A failure — an unsupported target, unavailable parent, unknown child, descriptor-less child that cannot be resumed, or rejected admission — states the message was not delivered.
|
|
49
|
+
|
|
50
|
+
### interrupt_agent
|
|
51
|
+
|
|
52
|
+
External executions stop permanently and cannot receive follow-ups. Local targets stop only their current turn: queued messages stay parked until a later `send_message`, descendants keep running, and the child stays available for follow-ups. The call returns when the stop request is accepted, not when the target is quiet; interrupting an already-finished agent is an accepted no-op, and self, sibling, stale, and non-ancestor callers get errored results.
|
|
53
|
+
|
|
54
|
+
### list_agents
|
|
55
|
+
|
|
56
|
+
Lists the continuable children below the calling agent: `children` (default) reads direct children from the parent catalog without opening child logs; `descendants` recursively reads child catalogs in stable pre-order, annotating each entry with its durable direct-parent session id and depth. Status comes from the live Agent registry — `running` or `inactive`. External entries are omitted without reading a child Session. Readable one-shot children are omitted from output but their catalogs remain traversal nodes. Unknown modes and unreadable child catalogs, including one-shot children, appear as diagnostics only in `descendants` scope. Ordinary Session forks are not catalog entries, so neither those forks nor their descendants are listed from the source Session.
|
|
57
|
+
|
|
58
|
+
-----
|
|
59
|
+
|
|
60
|
+
<a id="understand-the-implementation"></a>
|
|
61
|
+
## Understand the implementation
|
|
62
|
+
|
|
63
|
+
<details>
|
|
64
|
+
<summary>Implementation internals — click to expand</summary>
|
|
65
|
+
|
|
66
|
+
This section explains what the tools delegate to the subagent service; the observable behavior is covered in [Use this package](#use-this-package).
|
|
67
|
+
|
|
68
|
+
### Design concept
|
|
69
|
+
|
|
70
|
+
Thin adapters over `ctx.subagents.sendMessage()`, `interrupt()`, and the list projections; the tools perform no lifecycle routing. Residency, cold resume, and authorization belong to the service, and the tools pass the exact live calling agent (`exec.agent`) as both sender and authority.
|
|
71
|
+
|
|
72
|
+
### Delivery and signal ownership
|
|
73
|
+
|
|
74
|
+
The tool forwards its execution signal, which owns admission only until inbox acceptance. Once the target accepts a message, it cannot be cancelled through this tool. Every message is framed as `Agent <sender-id> sent a message:` and recorded with `{ kind: 'agent-message', form: 'relay', senderSessionId: sender.id }`; the service derives that attribution and never treats it as authority.
|
|
75
|
+
|
|
76
|
+
### Listing projection
|
|
77
|
+
|
|
78
|
+
`list_agents` derives the root id from the calling agent, reads the service catalog without a cursor, refines each candidate's status through the live Agent registry, and omits one-shot children because they cannot accept `send_message`. Descendant traversal preserves each parent catalog's event order. Unknown modes produce diagnostics while their catalogs remain traversable; unreadable catalogs produce diagnostics and stop that branch. Descendants absent from reachable catalogs cannot be discovered.
|
|
79
|
+
|
|
80
|
+
### Source map
|
|
81
|
+
|
|
82
|
+
| File | Role |
|
|
83
|
+
|---|---|
|
|
84
|
+
| [`src/index.ts`](src/index.ts) | `send_message` and `interrupt_agent` registration |
|
|
85
|
+
| [`src/list-agents.ts`](src/list-agents.ts) | `list_agents` registration: direct-child discovery and status refinement |
|
|
86
|
+
|
|
87
|
+
</details>
|
|
88
|
+
|
|
89
|
+
-----
|
|
90
|
+
|
|
91
|
+
<a id="further-exploration"></a>
|
|
92
|
+
## Further Exploration
|
|
93
|
+
|
|
94
|
+
Read these pages when the package-level contract is not enough; they move from the tool schemas to the continuation service behind them.
|
|
95
|
+
|
|
96
|
+
- [Subagent subsystem](../../../docs/subsystems/subagent.md) — continuable children, activations, inbox, interrupt, and follow-up authority.
|
|
97
|
+
- [dsh-tool-subagent](../tool-subagent/README.md) — the delegation tool that starts continuable children.
|
|
98
|
+
- [Generated tool catalog](../../../docs/tool-catalog.md#deepseek-aidsh-tool-subagent-control) — the three tool schemas.
|
|
99
|
+
|
|
100
|
+
-----
|
|
101
|
+
|
|
102
|
+
<a id="model-experience"></a>
|
|
103
|
+
## Model Experience
|
|
104
|
+
|
|
105
|
+
### Tool schema
|
|
106
|
+
|
|
107
|
+
#### What the model sees
|
|
108
|
+
|
|
109
|
+
The generated [schemas](../../../docs/tool-catalog.md#deepseek-aidsh-tool-subagent-control): `send_message` takes `agent_id` and `message`; `interrupt_agent` takes `agent_id`; `list_agents` takes no parameters.
|
|
110
|
+
|
|
111
|
+
#### Token effect
|
|
112
|
+
|
|
113
|
+
Fixed schema cost per parent request.
|
|
114
|
+
|
|
115
|
+
#### KV Cache effect
|
|
116
|
+
|
|
117
|
+
Prefix-stable; the schema does not change at runtime.
|
|
118
|
+
|
|
119
|
+
### Interrupt result
|
|
120
|
+
|
|
121
|
+
#### What the model sees
|
|
122
|
+
|
|
123
|
+
`interrupt requested for agent <agent_id>` on acceptance. An unauthorized caller — self, sibling, stale, or non-ancestor — is an errored result naming the rejection; an absent or settled target still renders the acceptance line.
|
|
124
|
+
|
|
125
|
+
#### Token effect
|
|
126
|
+
|
|
127
|
+
One short acknowledgement per call; the interrupted turn's abort is visible only in the child's own transcript.
|
|
128
|
+
|
|
129
|
+
#### KV Cache effect
|
|
130
|
+
|
|
131
|
+
Append-only; each result follows the reusable request prefix.
|
|
132
|
+
|
|
133
|
+
### Delivery result
|
|
134
|
+
|
|
135
|
+
#### What the model sees
|
|
136
|
+
|
|
137
|
+
`message delivered to agent <agent_id>` on acceptance; the canonical output carries the accepted `messageId`. A failure — a non-adjacent target, unavailable parent, unknown child, descriptor-less child that cannot be resumed, or admission rejected — is an errored result whose message states the message was not delivered.
|
|
138
|
+
|
|
139
|
+
#### Token effect
|
|
140
|
+
|
|
141
|
+
One short acknowledgement per call; the target's response never returns through this call. A child uses the same tool with its initial task's parent id to append selected content to parent history.
|
|
142
|
+
|
|
143
|
+
#### KV Cache effect
|
|
144
|
+
|
|
145
|
+
Append-only; newly visible content follows the reusable request prefix and does not invalidate existing KV-cache entries.
|
|
146
|
+
|
|
147
|
+
### Listing result
|
|
148
|
+
|
|
149
|
+
#### What the model sees
|
|
150
|
+
|
|
151
|
+
One line per continuable child in stable catalog order: `<id> [<status>] — <label>` (`running` = executing a turn; `inactive` = no turn executing, whether loaded or stored; neither status describes task completion or outcome). Only `descendants` scope adds `<id> [diagnostic: <reason>]` for an unknown mode or unreadable child catalog, including an unreadable one-shot child. The `descendants` scope inserts ` parent=<id> depth=<n>` before the label dash on every line, in pre-order. Readable one-shot children are omitted; `(no subagents)` means no continuable child or diagnostic survived the projection.
|
|
152
|
+
|
|
153
|
+
#### Token effect
|
|
154
|
+
|
|
155
|
+
Grows linearly with the listed continuable children and diagnostics — reachable catalog descendants under the `descendants` scope; there is no cursor or cap, so long-lived parents with many persisted children pay the full list each call.
|
|
156
|
+
|
|
157
|
+
#### KV Cache effect
|
|
158
|
+
|
|
159
|
+
Append-only; each result follows the reusable request prefix.
|
|
160
|
+
|
|
161
|
+
## Known Limitations and Deferred Work
|
|
162
|
+
|
|
163
|
+
<a id="known-limitations-and-deferred-work"></a>
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
These limits define what the control tools cannot observe or steer; they are current package constraints.
|
|
167
|
+
|
|
168
|
+
- **A delivered message has no independent result** — acceptance returns only its inbox `messageId`; later target work lands in that target's durable Session and is never collected through this tool. A reply is another explicitly addressed `send_message`, not this call's result.
|
|
169
|
+
- **Only supported adjacent Agents can communicate** — every sender may target a direct continuable child, only a sender with a resident continuable Activation may target its direct parent, and that parent must remain live; siblings and deeper descendants are not message targets, and only direct-child delivery supports cold activation.
|
|
170
|
+
- **Listing is a snapshot, not a delivery promise** — it may race publication, disposal, or a later message, and another process may activate a child this process reports as `inactive`; cross-process accuracy requires a shared lease. `interrupt_agent` performs the authoritative live-lineage check itself, so discovery staleness cannot grant authority.
|
|
171
|
+
- **No pagination or deletion** — the complete stably ordered set is returned, and persisted children remain listed for as long as their sessions remain in persistence; a service-level bound or delete operation is a later product decision.
|
|
172
|
+
|
|
173
|
+
<a id="dev-note"></a>
|
|
174
|
+
### Dev Note
|
|
175
|
+
|
|
176
|
+
<details>
|
|
177
|
+
<summary>Working context for maintainers — click to expand</summary>
|
|
178
|
+
|
|
179
|
+
None.
|
|
180
|
+
|
|
181
|
+
</details>
|
package/README.zh.md
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "供用户与维护者在组合或调试可继续子级控制功能时使用的全局 send_message、interrupt_agent 与 list_agents 工具。"
|
|
3
|
+
kind: "package-reference"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# @deepseek-ai/dsh-tool-subagent-control
|
|
7
|
+
|
|
8
|
+
[English](README.md) | 中文
|
|
9
|
+
|
|
10
|
+
## 概述
|
|
11
|
+
|
|
12
|
+
`dsh-tool-subagent-control` 为可继续子级添加全局控制工具:`send_message` 在直接父级与子级之间进行 steering(中途引导),`interrupt_agent` 停止子级当前轮次但保留其收件箱与后代,`list_agents`(来自可单独加载的 `list-agents` 插件)按持久化 ID 与标签列出可继续子级。父级与可继续子级继承相同的 `send_message` 定义和顺序,因此模型通信不会增加子级专属工具 schema。是否加载这些工具不会决定委派工具是否启动可继续工作。
|
|
13
|
+
|
|
14
|
+
## 目录
|
|
15
|
+
|
|
16
|
+
- [使用本包](#use-this-package)
|
|
17
|
+
- [理解实现](#understand-the-implementation)
|
|
18
|
+
- [进一步探索](#further-exploration)
|
|
19
|
+
- [模型体验](#model-experience)
|
|
20
|
+
- [已知限制与延期工作](#known-limitations-and-deferred-work)
|
|
21
|
+
- [开发备注](#dev-note)
|
|
22
|
+
|
|
23
|
+
-----
|
|
24
|
+
|
|
25
|
+
<a id="use-this-package"></a>
|
|
26
|
+
## 使用本包
|
|
27
|
+
|
|
28
|
+
在模型需要对可继续子级发消息、中断或列出的任何组合中挂载本包。根插件只需要 subagent 服务;列表工具是独立插件,部署方可以省略。
|
|
29
|
+
|
|
30
|
+
### 最小配置
|
|
31
|
+
|
|
32
|
+
先加载 subagent 服务、一个后端、委派工具与本包。加上独立的列表插件即可公开全部三个工具:
|
|
33
|
+
|
|
34
|
+
```yaml
|
|
35
|
+
- name: '@deepseek-ai/dsh-subagent'
|
|
36
|
+
- name: '@deepseek-ai/dsh-subagent-spawn-in-process'
|
|
37
|
+
- name: '@deepseek-ai/dsh-tool-subagent'
|
|
38
|
+
config:
|
|
39
|
+
provider: spawn
|
|
40
|
+
- name: '@deepseek-ai/dsh-tool-subagent-control'
|
|
41
|
+
- name: '@deepseek-ai/dsh-tool-subagent-control/list-agents'
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
本包不接收任何配置:根插件提供 `send_message` 与 `interrupt_agent`,列表插件提供 `list_agents`。
|
|
45
|
+
|
|
46
|
+
### send_message
|
|
47
|
+
|
|
48
|
+
向 `agent_id` 指定的 Agent 发送消息:任何确切在线 Agent 都可以向自己的直接可继续子级发送消息,驻留的可继续子级还可以向自己的直接父级发送消息。正在工作的目标通过 Steer 在最近的步骤边界接收消息;非活跃目标会通过继续执行生命周期启动或恢复一个轮次。调用只返回接受结果(被接受消息的稳定 `messageId`),绝不返回回复。失败——不受支持的目标、不可用的父级、未知子级、缺少描述符而无法恢复的子级,或准入被拒——会明确说明消息未送达。
|
|
49
|
+
|
|
50
|
+
### interrupt_agent
|
|
51
|
+
|
|
52
|
+
外部执行会永久停止,不能接收后续消息。本地目标只停止当前轮次:已排队消息保持暂停,直到之后调用 `send_message`;后代继续运行,子级仍可接受后续消息。调用在停止请求被接受后立即返回,不等待目标完全停稳;中断已结束的 agent 会被接受并按空操作处理,而自身、同级、陈旧及非祖先调用方会收到出错结果。
|
|
53
|
+
|
|
54
|
+
### list_agents
|
|
55
|
+
|
|
56
|
+
列出调用方 agent 下方的可继续子级:`children`(默认)从父目录读取直接子级,不打开子日志;`descendants` 按稳定前序递归读取子级目录,并为每个条目标注其持久化直接父级会话 ID 与深度。状态来自在线 Agent 注册表——`running` 或 `inactive`。外部条目被省略,不读取子 Session。可读取的一次性子级不出现在输出中,但其目录仍是遍历节点。未知模式与无法读取的子级目录(包括一次性子级)仅在 `descendants` 作用域中以诊断信息呈现。普通 Session fork 不是目录条目,因此从源 Session 列表中既无法发现这些 fork,也无法发现其后代。
|
|
57
|
+
|
|
58
|
+
-----
|
|
59
|
+
|
|
60
|
+
<a id="understand-the-implementation"></a>
|
|
61
|
+
## 理解实现
|
|
62
|
+
|
|
63
|
+
<details>
|
|
64
|
+
<summary>实现细节——点击展开</summary>
|
|
65
|
+
|
|
66
|
+
本节解释工具把什么委托给 subagent 服务;可观察行为已在[使用本包](#use-this-package)中说明。
|
|
67
|
+
|
|
68
|
+
### 设计理念
|
|
69
|
+
|
|
70
|
+
`ctx.subagents.sendMessage()`、`interrupt()` 与列表投影之上的轻量适配器;工具不执行任何生命周期路由。驻留、冷恢复与授权归服务所有,工具把确切在线的调用 Agent(`exec.agent`)同时作为 sender 与权限凭据传入。
|
|
71
|
+
|
|
72
|
+
### 投递与信号所有权
|
|
73
|
+
|
|
74
|
+
工具转发其执行信号,该信号只在 inbox 接受之前掌管准入。目标一旦接受消息,该消息便无法再通过本工具取消。每条消息都以 `Agent <sender-id> sent a message:` 作为前缀,并记录 `{ kind: 'agent-message', form: 'relay', senderSessionId: sender.id }`;该来源信息由服务推导,且绝不被视为权限。
|
|
75
|
+
|
|
76
|
+
### 列表投影
|
|
77
|
+
|
|
78
|
+
`list_agents` 从调用 agent 推导根 id,不使用 cursor 读取服务目录,通过在线 Agent 注册表细化每个候选的状态,并省略无法接受 `send_message` 的一次性子级。后代遍历保留每个父目录的事件顺序。未知模式产生诊断,但其目录仍可遍历;无法读取的目录产生诊断,并停止该分支。可达目录中不存在的后代无法被发现。
|
|
79
|
+
|
|
80
|
+
### 源码地图
|
|
81
|
+
|
|
82
|
+
| 文件 | 职责 |
|
|
83
|
+
|---|---|
|
|
84
|
+
| [`src/index.ts`](src/index.ts) | `send_message` 与 `interrupt_agent` 注册 |
|
|
85
|
+
| [`src/list-agents.ts`](src/list-agents.ts) | `list_agents` 注册:直接子级发现与状态细化 |
|
|
86
|
+
|
|
87
|
+
</details>
|
|
88
|
+
|
|
89
|
+
-----
|
|
90
|
+
|
|
91
|
+
<a id="further-exploration"></a>
|
|
92
|
+
## 进一步探索
|
|
93
|
+
|
|
94
|
+
当包级约定不够用时阅读以下页面;它们从工具 schema 进入其背后的继续执行服务。
|
|
95
|
+
|
|
96
|
+
- [Subagent 子系统](../../../docs/subsystems/subagent.zh.md)——可继续子级、Activation、inbox、中断与后续消息权限。
|
|
97
|
+
- [dsh-tool-subagent](../tool-subagent/README.zh.md)——启动可继续子级的委派工具。
|
|
98
|
+
- [生成工具目录](../../../docs/tool-catalog.zh.md#deepseek-aidsh-tool-subagent-control)——三个工具的 schema。
|
|
99
|
+
|
|
100
|
+
-----
|
|
101
|
+
|
|
102
|
+
<a id="model-experience"></a>
|
|
103
|
+
## 模型体验
|
|
104
|
+
|
|
105
|
+
### 工具 schema
|
|
106
|
+
|
|
107
|
+
#### 模型看到什么
|
|
108
|
+
|
|
109
|
+
已生成的 [schema](../../../docs/tool-catalog.zh.md#deepseek-aidsh-tool-subagent-control):`send_message` 接受 `agent_id` 与 `message`;`interrupt_agent` 接受 `agent_id`;`list_agents` 不接受参数。
|
|
110
|
+
|
|
111
|
+
#### Token 影响
|
|
112
|
+
|
|
113
|
+
每个父级请求支付固定的 schema 成本。
|
|
114
|
+
|
|
115
|
+
#### KV Cache 影响
|
|
116
|
+
|
|
117
|
+
前缀保持稳定;schema 不会在运行时改变。
|
|
118
|
+
|
|
119
|
+
### 中断结果
|
|
120
|
+
|
|
121
|
+
#### 模型看到什么
|
|
122
|
+
|
|
123
|
+
接受时返回 `interrupt requested for agent <agent_id>`。未授权的调用方——self、sibling、陈旧或非 ancestor——会成为指明拒绝原因的出错结果;目标不存在或已结算仍渲染接受行。
|
|
124
|
+
|
|
125
|
+
#### Token 影响
|
|
126
|
+
|
|
127
|
+
每次调用产生一条简短确认消息;被中断轮次的中止只在子级自己的 transcript(文本记录)中可见。
|
|
128
|
+
|
|
129
|
+
#### KV Cache 影响
|
|
130
|
+
|
|
131
|
+
仅追加;每个结果都位于可复用请求前缀之后。
|
|
132
|
+
|
|
133
|
+
### 投递结果
|
|
134
|
+
|
|
135
|
+
#### 模型看到什么
|
|
136
|
+
|
|
137
|
+
接受时返回 `message delivered to agent <agent_id>`;规范输出携带被接受的 `messageId`。失败——非相邻目标、不可用的父级、未知子级、缺少描述符而无法恢复的子级,或准入被拒——会成为出错的结果,其消息说明该消息未送达。
|
|
138
|
+
|
|
139
|
+
#### Token 影响
|
|
140
|
+
|
|
141
|
+
每次调用产生一条简短确认消息;目标的响应绝不会通过本次调用返回。子级使用同一个工具,并传入其初始任务中的父级 ID,将选定内容追加到父级历史中。
|
|
142
|
+
|
|
143
|
+
#### KV Cache 影响
|
|
144
|
+
|
|
145
|
+
仅追加;新增可见内容位于可复用请求前缀之后,不会使现有 KV Cache 条目失效。
|
|
146
|
+
|
|
147
|
+
### 列表结果
|
|
148
|
+
|
|
149
|
+
#### 模型看到什么
|
|
150
|
+
|
|
151
|
+
按稳定目录顺序,每个可继续子级占一行:`<id> [<status>] — <label>`(`running` 表示正在执行轮次;`inactive` 表示没有轮次在执行,包括已加载和仅存于存储的情况;两种状态均不表示任务完成或结果)。仅 `descendants` 作用域会为未知模式或无法读取的子级目录添加 `<id> [diagnostic: <reason>]`,包括无法读取的一次性子级。`descendants` 作用域会在每行标签的破折号之前按前序插入 ` parent=<id> depth=<n>`。可读取的一次性子级会被省略;`(no subagents)` 表示投影后没有留下可继续子级或诊断信息。
|
|
152
|
+
|
|
153
|
+
#### Token 影响
|
|
154
|
+
|
|
155
|
+
随所列可继续子级和诊断数量线性增长——`descendants` 作用域下为目录可达后代;没有游标或上限,因此长期存活且有许多持久化子级的父级每次调用都会承担完整列表成本。
|
|
156
|
+
|
|
157
|
+
#### KV Cache 影响
|
|
158
|
+
|
|
159
|
+
仅追加;每个结果都位于可复用请求前缀之后。
|
|
160
|
+
|
|
161
|
+
## 已知限制与延期工作
|
|
162
|
+
|
|
163
|
+
<a id="known-limitations-and-deferred-work"></a>
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
这些限制说明控制工具无法观察或引导什么;它们是当前包约束。
|
|
167
|
+
|
|
168
|
+
- **已投递消息没有独立结果**——接受时只返回其 inbox `messageId`;目标后续工作会落入该目标的持久化会话,绝不会通过本工具收集。回复是另一条显式指定地址的 `send_message`,而非本次调用的结果。
|
|
169
|
+
- **只有受支持的相邻 Agent 可以通信**——每个发送方都可以向直接可继续子级发送消息;只有具备驻留可继续 Activation 的发送方可以向自己的直接父级发送消息,且该父级必须仍在线;同级与更深的后代不能作为消息目标,只有向直接子级投递才支持冷激活。
|
|
170
|
+
- **列表是快照,而非投递承诺**——它可能与发布、dispose(资源释放)或后续消息发生竞态,另一个进程也可能激活当前进程报告为 `inactive` 的子级;跨进程准确性需要共享租约。`interrupt_agent` 自己执行权威的在线 lineage 检查,因此过期的发现结果不会授予权限。
|
|
171
|
+
- **没有分页或删除**——系统返回完整且稳定排序的集合;只要子级会话仍在持久化存储中,它就会继续出现在列表中,服务级上限或删除操作留待后续产品决策。
|
|
172
|
+
|
|
173
|
+
<a id="dev-note"></a>
|
|
174
|
+
### 开发备注
|
|
175
|
+
|
|
176
|
+
<details>
|
|
177
|
+
<summary>维护者的工作上下文——点击展开</summary>
|
|
178
|
+
|
|
179
|
+
无。
|
|
180
|
+
|
|
181
|
+
</details>
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { brandString } from "@qlzt/dsh-brand";
|
|
2
|
+
import { defineTool } from "@qlzt/dsh-tools";
|
|
3
|
+
import { markAdjacentAgentSendMessageTool } from "@qlzt/dsh-subagent/internal";
|
|
4
|
+
//#region lib/types/index.js
|
|
5
|
+
/**
|
|
6
|
+
* The globally named `send_message` and `interrupt_agent` tools: thin
|
|
7
|
+
* model-facing adapters over `ctx.subagents.sendMessage()` and
|
|
8
|
+
* `ctx.subagents.interrupt()`. They perform no lifecycle routing of their own —
|
|
9
|
+
* residency, cold resume, and interrupt authorization belong to the subagent
|
|
10
|
+
* service — and they live apart from the provider-bound
|
|
11
|
+
* `@qlzt/dsh-tool-subagent` instances so multiple delegation tools share
|
|
12
|
+
* one control API.
|
|
13
|
+
* @module @qlzt/dsh-tool-subagent-control
|
|
14
|
+
*/
|
|
15
|
+
const name = "tool-subagent-control";
|
|
16
|
+
const inject = ["tools", "subagents"];
|
|
17
|
+
/**
|
|
18
|
+
* Register the `send_message` and `interrupt_agent` tools.
|
|
19
|
+
* @param ctx - context carrying the tool registry and subagent service.
|
|
20
|
+
*/
|
|
21
|
+
function apply(ctx) {
|
|
22
|
+
ctx.tools.register(markAdjacentAgentSendMessageTool(defineTool({
|
|
23
|
+
name: "send_message",
|
|
24
|
+
description: "Send a message to an agent. A working agent receives it at its next step; an idle agent starts a new turn with it. Returns delivery confirmation, not the agent's answer.",
|
|
25
|
+
parameters: {
|
|
26
|
+
agent_id: {
|
|
27
|
+
type: "string",
|
|
28
|
+
required: true,
|
|
29
|
+
description: "The agent id of your direct continuable child, or your direct parent when you are a resident continuable child."
|
|
30
|
+
},
|
|
31
|
+
message: {
|
|
32
|
+
type: "string",
|
|
33
|
+
required: true,
|
|
34
|
+
description: "The message to deliver to the agent."
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
output: {
|
|
38
|
+
schema: {
|
|
39
|
+
type: "object",
|
|
40
|
+
additionalProperties: false,
|
|
41
|
+
properties: { messageId: {
|
|
42
|
+
type: "string",
|
|
43
|
+
required: true
|
|
44
|
+
} }
|
|
45
|
+
},
|
|
46
|
+
render: (args, _value) => [{
|
|
47
|
+
type: "text",
|
|
48
|
+
text: `message delivered to agent ${args.agent_id}`
|
|
49
|
+
}]
|
|
50
|
+
},
|
|
51
|
+
async execute(args, exec) {
|
|
52
|
+
const sender = exec.agent;
|
|
53
|
+
if (!sender) throw new Error("send_message requires a calling agent (exec.agent was undefined)");
|
|
54
|
+
const message = [{
|
|
55
|
+
type: "text",
|
|
56
|
+
text: args.message
|
|
57
|
+
}];
|
|
58
|
+
return { messageId: await ctx.subagents.sendMessage(sender, brandString(args.agent_id), message, { signal: exec.signal }) };
|
|
59
|
+
}
|
|
60
|
+
})));
|
|
61
|
+
ctx.tools.register(defineTool({
|
|
62
|
+
name: "interrupt_agent",
|
|
63
|
+
description: "Ask a subagent to stop its current work. This call returns without waiting for it to stop. You can continue a local direct child's conversation later with send_message. External executions stop permanently and cannot receive follow-ups. Subagents it started will keep running.",
|
|
64
|
+
parameters: { agent_id: {
|
|
65
|
+
type: "string",
|
|
66
|
+
required: true,
|
|
67
|
+
description: "The id of an agent created under you: your direct child or a deeper descendant."
|
|
68
|
+
} },
|
|
69
|
+
output: {
|
|
70
|
+
schema: {
|
|
71
|
+
type: "object",
|
|
72
|
+
additionalProperties: false,
|
|
73
|
+
properties: { accepted: {
|
|
74
|
+
type: "boolean",
|
|
75
|
+
required: true
|
|
76
|
+
} }
|
|
77
|
+
},
|
|
78
|
+
render: (args, _value) => [{
|
|
79
|
+
type: "text",
|
|
80
|
+
text: `interrupt requested for agent ${args.agent_id}`
|
|
81
|
+
}]
|
|
82
|
+
},
|
|
83
|
+
execute(args, exec) {
|
|
84
|
+
const caller = exec.agent;
|
|
85
|
+
if (!caller) throw new Error("interrupt_agent requires a calling agent (exec.agent was undefined)");
|
|
86
|
+
ctx.subagents.interrupt(brandString(args.agent_id), {
|
|
87
|
+
kind: "ancestor",
|
|
88
|
+
agent: caller
|
|
89
|
+
});
|
|
90
|
+
return Promise.resolve({ accepted: true });
|
|
91
|
+
}
|
|
92
|
+
}));
|
|
93
|
+
}
|
|
94
|
+
//#endregion
|
|
95
|
+
export { apply, inject, name };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The globally named `send_message` and `interrupt_agent` tools: thin
|
|
3
|
+
* model-facing adapters over `ctx.subagents.sendMessage()` and
|
|
4
|
+
* `ctx.subagents.interrupt()`. They perform no lifecycle routing of their own —
|
|
5
|
+
* residency, cold resume, and interrupt authorization belong to the subagent
|
|
6
|
+
* service — and they live apart from the provider-bound
|
|
7
|
+
* `@qlzt/dsh-tool-subagent` instances so multiple delegation tools share
|
|
8
|
+
* one control API.
|
|
9
|
+
* @module @qlzt/dsh-tool-subagent-control
|
|
10
|
+
*/
|
|
11
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
12
|
+
export declare const name = "tool-subagent-control";
|
|
13
|
+
export declare const inject: string[];
|
|
14
|
+
/**
|
|
15
|
+
* Register the `send_message` and `interrupt_agent` tools.
|
|
16
|
+
* @param ctx - context carrying the tool registry and subagent service.
|
|
17
|
+
*/
|
|
18
|
+
export declare function apply(ctx: Context): void;
|
|
19
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The globally named `send_message` and `interrupt_agent` tools: thin
|
|
3
|
+
* model-facing adapters over `ctx.subagents.sendMessage()` and
|
|
4
|
+
* `ctx.subagents.interrupt()`. They perform no lifecycle routing of their own —
|
|
5
|
+
* residency, cold resume, and interrupt authorization belong to the subagent
|
|
6
|
+
* service — and they live apart from the provider-bound
|
|
7
|
+
* `@qlzt/dsh-tool-subagent` instances so multiple delegation tools share
|
|
8
|
+
* one control API.
|
|
9
|
+
* @module @qlzt/dsh-tool-subagent-control
|
|
10
|
+
*/
|
|
11
|
+
import { brandString } from '@qlzt/dsh-brand';
|
|
12
|
+
import { defineTool } from '@qlzt/dsh-tools';
|
|
13
|
+
import { markAdjacentAgentSendMessageTool } from '@qlzt/dsh-subagent/internal';
|
|
14
|
+
export const name = 'tool-subagent-control';
|
|
15
|
+
export const inject = ['tools', 'subagents'];
|
|
16
|
+
/**
|
|
17
|
+
* Register the `send_message` and `interrupt_agent` tools.
|
|
18
|
+
* @param ctx - context carrying the tool registry and subagent service.
|
|
19
|
+
*/
|
|
20
|
+
export function apply(ctx) {
|
|
21
|
+
ctx.tools.register(markAdjacentAgentSendMessageTool(defineTool({
|
|
22
|
+
name: 'send_message',
|
|
23
|
+
description: 'Send a message to an agent. A working agent receives it at its next step; an idle agent starts a new turn with it. '
|
|
24
|
+
+ 'Returns delivery confirmation, not the agent\'s answer.',
|
|
25
|
+
parameters: {
|
|
26
|
+
agent_id: {
|
|
27
|
+
type: 'string',
|
|
28
|
+
required: true,
|
|
29
|
+
description: 'The agent id of your direct continuable child, or your direct parent when you are a resident continuable child.',
|
|
30
|
+
},
|
|
31
|
+
message: {
|
|
32
|
+
type: 'string',
|
|
33
|
+
required: true,
|
|
34
|
+
description: 'The message to deliver to the agent.',
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
output: {
|
|
38
|
+
schema: {
|
|
39
|
+
type: 'object',
|
|
40
|
+
additionalProperties: false,
|
|
41
|
+
properties: {
|
|
42
|
+
messageId: { type: 'string', required: true },
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
render: (args, _value) => [{
|
|
46
|
+
type: 'text',
|
|
47
|
+
text: `message delivered to agent ${args.agent_id}`,
|
|
48
|
+
}],
|
|
49
|
+
},
|
|
50
|
+
async execute(args, exec) {
|
|
51
|
+
const sender = exec.agent;
|
|
52
|
+
if (!sender) {
|
|
53
|
+
throw new Error('send_message requires a calling agent (exec.agent was undefined)');
|
|
54
|
+
}
|
|
55
|
+
const message = [{ type: 'text', text: args.message }];
|
|
56
|
+
const messageId = await ctx.subagents.sendMessage(sender, brandString(args.agent_id), message, { signal: exec.signal });
|
|
57
|
+
return { messageId };
|
|
58
|
+
},
|
|
59
|
+
})));
|
|
60
|
+
ctx.tools.register(defineTool({
|
|
61
|
+
name: 'interrupt_agent',
|
|
62
|
+
description: 'Ask a subagent to stop its current work. This call returns without waiting for it to stop. '
|
|
63
|
+
+ 'You can continue a local direct child\'s conversation later with send_message. '
|
|
64
|
+
+ 'External executions stop permanently and cannot receive follow-ups. Subagents it started will keep running.',
|
|
65
|
+
parameters: {
|
|
66
|
+
agent_id: {
|
|
67
|
+
type: 'string',
|
|
68
|
+
required: true,
|
|
69
|
+
description: 'The id of an agent created under you: your direct child or a deeper descendant.',
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
output: {
|
|
73
|
+
schema: {
|
|
74
|
+
type: 'object',
|
|
75
|
+
additionalProperties: false,
|
|
76
|
+
properties: {
|
|
77
|
+
accepted: { type: 'boolean', required: true },
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
render: (args, _value) => [{
|
|
81
|
+
type: 'text',
|
|
82
|
+
text: `interrupt requested for agent ${args.agent_id}`,
|
|
83
|
+
}],
|
|
84
|
+
},
|
|
85
|
+
execute(args, exec) {
|
|
86
|
+
const caller = exec.agent;
|
|
87
|
+
if (!caller) {
|
|
88
|
+
// Ancestor authority requires an exact live calling agent.
|
|
89
|
+
throw new Error('interrupt_agent requires a calling agent (exec.agent was undefined)');
|
|
90
|
+
}
|
|
91
|
+
// The service authorizes the exact live caller against the target's
|
|
92
|
+
// recorded lineage; the tool adds no authority of its own.
|
|
93
|
+
ctx.subagents.interrupt(brandString(args.agent_id), { kind: 'ancestor', agent: caller });
|
|
94
|
+
return Promise.resolve({ accepted: true });
|
|
95
|
+
},
|
|
96
|
+
}));
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The globally named `list_agents` tool: a thin model-facing adapter over
|
|
3
|
+
* the continuable projection of `ctx.subagents.listChildren()` and, for the
|
|
4
|
+
* `descendants` scope, `ctx.subagents.listDescendants()`. It stays separately
|
|
5
|
+
* loadable from the root `send_message` plugin so a deployment can register
|
|
6
|
+
* continuation delivery without exposing discovery.
|
|
7
|
+
* @module @qlzt/dsh-tool-subagent-control/list-agents
|
|
8
|
+
*/
|
|
9
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
10
|
+
export declare const name = "tool-subagent-list-agents";
|
|
11
|
+
export declare const inject: string[];
|
|
12
|
+
/**
|
|
13
|
+
* Register the `list_agents` tool.
|
|
14
|
+
* @param ctx - context carrying the tool registry, subagent service, and live Agent registry.
|
|
15
|
+
*/
|
|
16
|
+
export declare function apply(ctx: Context): void;
|
|
17
|
+
//# sourceMappingURL=list-agents.d.ts.map
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The globally named `list_agents` tool: a thin model-facing adapter over
|
|
3
|
+
* the continuable projection of `ctx.subagents.listChildren()` and, for the
|
|
4
|
+
* `descendants` scope, `ctx.subagents.listDescendants()`. It stays separately
|
|
5
|
+
* loadable from the root `send_message` plugin so a deployment can register
|
|
6
|
+
* continuation delivery without exposing discovery.
|
|
7
|
+
* @module @qlzt/dsh-tool-subagent-control/list-agents
|
|
8
|
+
*/
|
|
9
|
+
import { defineTool } from '@qlzt/dsh-tools';
|
|
10
|
+
import { assertNever } from '@qlzt/dsh-util-values';
|
|
11
|
+
export const name = 'tool-subagent-list-agents';
|
|
12
|
+
export const inject = ['tools', 'subagents', 'agents'];
|
|
13
|
+
/** Resolve the optional model request into an internal required-scope spec. */
|
|
14
|
+
function resolveListAgentsRequest(request) {
|
|
15
|
+
return { scope: request.scope ?? 'children' };
|
|
16
|
+
}
|
|
17
|
+
/** Report turn activity without exposing whether the child is loaded. */
|
|
18
|
+
function statusOf(agents, id) {
|
|
19
|
+
return agents.get(id)?.status === 'running' ? 'running' : 'inactive';
|
|
20
|
+
}
|
|
21
|
+
/** Project one service row into the model-facing entry, or omit a one-shot child. */
|
|
22
|
+
function project(agents, entry, position) {
|
|
23
|
+
const at = position === undefined ? {} : { parent: position.parentId, depth: position.depth };
|
|
24
|
+
if ('kind' in entry && entry.kind === 'diagnostic') {
|
|
25
|
+
return { kind: 'diagnostic', id: entry.id, reason: entry.reason, ...at };
|
|
26
|
+
}
|
|
27
|
+
// One-shot children cannot be continued by send_message, so the model
|
|
28
|
+
// never selects them; discovery still traversed them for descendants.
|
|
29
|
+
if (entry.mode !== 'continuable')
|
|
30
|
+
return undefined;
|
|
31
|
+
return {
|
|
32
|
+
kind: 'child',
|
|
33
|
+
id: entry.id,
|
|
34
|
+
label: entry.label,
|
|
35
|
+
status: statusOf(agents, entry.id),
|
|
36
|
+
...at,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Register the `list_agents` tool.
|
|
41
|
+
* @param ctx - context carrying the tool registry, subagent service, and live Agent registry.
|
|
42
|
+
*/
|
|
43
|
+
export function apply(ctx) {
|
|
44
|
+
ctx.tools.register(defineTool({
|
|
45
|
+
name: 'list_agents',
|
|
46
|
+
description: 'List subagents you started, with their ids, labels, and status. '
|
|
47
|
+
+ 'running means it is working; inactive means it is not currently working. '
|
|
48
|
+
+ 'You will be notified when a subagent finishes; there is no need to keep checking its status. '
|
|
49
|
+
+ 'Use send_message to continue the conversation.',
|
|
50
|
+
parameters: {
|
|
51
|
+
scope: {
|
|
52
|
+
type: 'string',
|
|
53
|
+
enum: ['children', 'descendants'],
|
|
54
|
+
description: 'children (default) lists direct children, which accept send_message in any status. '
|
|
55
|
+
+ 'descendants lists the whole tree below you with each entry\'s parent session id and depth; entries deeper than 1 accept only interrupt_agent.',
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
output: {
|
|
59
|
+
schema: {
|
|
60
|
+
type: 'array',
|
|
61
|
+
items: {
|
|
62
|
+
oneOf: [
|
|
63
|
+
{
|
|
64
|
+
type: 'object',
|
|
65
|
+
additionalProperties: false,
|
|
66
|
+
properties: {
|
|
67
|
+
kind: { type: 'string', required: true, enum: ['child'] },
|
|
68
|
+
id: { type: 'string', required: true },
|
|
69
|
+
label: { type: 'string', required: true },
|
|
70
|
+
status: { type: 'string', required: true, enum: ['running', 'inactive'] },
|
|
71
|
+
parent: { type: 'string' },
|
|
72
|
+
depth: { type: 'number' },
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
type: 'object',
|
|
77
|
+
additionalProperties: false,
|
|
78
|
+
properties: {
|
|
79
|
+
kind: { type: 'string', required: true, enum: ['diagnostic'] },
|
|
80
|
+
id: { type: 'string', required: true },
|
|
81
|
+
reason: { type: 'string', required: true, enum: ['corrupt', 'unsupported', 'unavailable'] },
|
|
82
|
+
parent: { type: 'string' },
|
|
83
|
+
depth: { type: 'number' },
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
],
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
render: (args, entries) => {
|
|
90
|
+
const request = resolveListAgentsRequest(args);
|
|
91
|
+
return [{
|
|
92
|
+
type: 'text',
|
|
93
|
+
text: entries.length === 0
|
|
94
|
+
? '(no subagents)'
|
|
95
|
+
: entries.map((entry) => {
|
|
96
|
+
// A descendants row always carries its position; children rows
|
|
97
|
+
// never render it. String() spans the schema-optional shape
|
|
98
|
+
// without a dead fallback branch.
|
|
99
|
+
const at = request.scope === 'descendants'
|
|
100
|
+
? ` parent=${String(entry.parent)} depth=${String(entry.depth)}`
|
|
101
|
+
: '';
|
|
102
|
+
return entry.kind === 'child'
|
|
103
|
+
? `${entry.id} [${entry.status}]${at} — ${entry.label}`
|
|
104
|
+
: `${entry.id} [diagnostic: ${entry.reason}]${at}`;
|
|
105
|
+
}).join('\n'),
|
|
106
|
+
}];
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
async execute(args, exec) {
|
|
110
|
+
const parent = exec.agent;
|
|
111
|
+
if (!parent) {
|
|
112
|
+
// Non-agent callers have no session whose children could be listed.
|
|
113
|
+
throw new Error('list_agents requires a calling agent (exec.agent was undefined)');
|
|
114
|
+
}
|
|
115
|
+
const request = resolveListAgentsRequest(args);
|
|
116
|
+
switch (request.scope) {
|
|
117
|
+
case 'children': {
|
|
118
|
+
const entries = await ctx.subagents.listChildren(parent.id, exec.signal);
|
|
119
|
+
return entries
|
|
120
|
+
.map(entry => project(ctx.agents, entry))
|
|
121
|
+
.filter(entry => entry !== undefined);
|
|
122
|
+
}
|
|
123
|
+
case 'descendants': {
|
|
124
|
+
const entries = await ctx.subagents.listDescendants(parent.id, exec.signal);
|
|
125
|
+
return entries
|
|
126
|
+
.map(entry => project(ctx.agents, entry, entry))
|
|
127
|
+
.filter(entry => entry !== undefined);
|
|
128
|
+
}
|
|
129
|
+
/* v8 ignore next 2 -- the resolver normalizes the schema-validated closed scope before dispatch. */
|
|
130
|
+
default:
|
|
131
|
+
return assertNever(request.scope, 'list_agents scope');
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
}));
|
|
135
|
+
}
|
|
136
|
+
//# sourceMappingURL=list-agents.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,62 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@qlzt/dsh-tool-subagent-control",
|
|
3
|
-
"
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"description": "Globally named send_message, interrupt_agent, and list_agents tools over ctx.subagents continuations",
|
|
4
|
+
"version": "0.2.1-alpha.3",
|
|
5
|
+
"publishConfig": {
|
|
6
|
+
"access": "public"
|
|
7
|
+
},
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "https://gitee.com/zsping1989/deepseek-harness.git",
|
|
11
|
+
"directory": "packages/subagent/tool-subagent-control"
|
|
12
|
+
},
|
|
13
|
+
"type": "module",
|
|
14
|
+
"main": "lib/index.js",
|
|
15
|
+
"types": "lib/types/index.d.ts",
|
|
16
|
+
"exports": {
|
|
17
|
+
".": {
|
|
18
|
+
"types": "./lib/types/index.d.ts",
|
|
19
|
+
"default": "./lib/index.js"
|
|
20
|
+
},
|
|
21
|
+
"./list-agents": {
|
|
22
|
+
"types": "./lib/types/list-agents.d.ts",
|
|
23
|
+
"default": "./lib/types/list-agents.js"
|
|
24
|
+
},
|
|
25
|
+
"./src/*": "./src/*",
|
|
26
|
+
"./package.json": "./package.json"
|
|
27
|
+
},
|
|
28
|
+
"files": [
|
|
29
|
+
"lib/index.js",
|
|
30
|
+
"lib/types/**/*.js",
|
|
31
|
+
"lib/types/**/*.d.ts"
|
|
32
|
+
],
|
|
33
|
+
"license": "MIT",
|
|
34
|
+
"peerDependencies": {
|
|
35
|
+
"@deepseek-ai/cordis": "~4.0.5-alpha.1",
|
|
36
|
+
"@qlzt/dsh-llm": "0.2.1-alpha.3",
|
|
37
|
+
"@qlzt/dsh-session": "0.2.1-alpha.3",
|
|
38
|
+
"@qlzt/dsh-subagent": "0.2.1-alpha.3",
|
|
39
|
+
"@qlzt/dsh-tools": "0.2.1-alpha.3"
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"@deepseek-ai/cordis": "~4.0.5-alpha.1",
|
|
43
|
+
"@deepseek-ai/dsh-agent": "0.2.1-alpha.3",
|
|
44
|
+
"@deepseek-ai/dsh-agent-loop": "0.2.1-alpha.3",
|
|
45
|
+
"@deepseek-ai/dsh-agent-loop-testkit": "0.2.1-alpha.3",
|
|
46
|
+
"@deepseek-ai/dsh-llm": "0.2.1-alpha.3",
|
|
47
|
+
"@deepseek-ai/dsh-session": "0.2.1-alpha.3",
|
|
48
|
+
"@deepseek-ai/dsh-session-persistence": "0.2.1-alpha.3",
|
|
49
|
+
"@deepseek-ai/dsh-session-persistence-jsonl": "0.2.1-alpha.3",
|
|
50
|
+
"@deepseek-ai/dsh-session-projection": "0.2.1-alpha.3",
|
|
51
|
+
"@deepseek-ai/dsh-session-query": "0.2.1-alpha.3",
|
|
52
|
+
"@deepseek-ai/dsh-subagent": "0.2.1-alpha.3",
|
|
53
|
+
"@deepseek-ai/dsh-subagent-fork-in-process": "0.2.1-alpha.3",
|
|
54
|
+
"@deepseek-ai/dsh-subagent-spawn-in-process": "0.2.1-alpha.3",
|
|
55
|
+
"@deepseek-ai/dsh-tools": "0.2.1-alpha.3"
|
|
56
|
+
},
|
|
57
|
+
"dependencies": {
|
|
58
|
+
"@qlzt/dsh-brand": "0.2.1-alpha.3",
|
|
59
|
+
"@qlzt/dsh-util-values": "0.2.1-alpha.3"
|
|
60
|
+
},
|
|
61
|
+
"dsh": {}
|
|
62
|
+
}
|