@oyasmi/pipiclaw 0.3.4 → 0.4.0
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/CHANGELOG.md +3 -0
- package/LICENSE +184 -0
- package/README.md +230 -231
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +2 -19
- package/dist/agent.js.map +1 -1
- package/dist/command-extension.d.ts.map +1 -1
- package/dist/command-extension.js.map +1 -1
- package/dist/commands.d.ts.map +1 -1
- package/dist/commands.js.map +1 -1
- package/dist/config-loader.d.ts.map +1 -1
- package/dist/config-loader.js.map +1 -1
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +0 -2
- package/dist/context.js.map +1 -1
- package/dist/delivery.d.ts.map +1 -1
- package/dist/delivery.js +11 -14
- package/dist/delivery.js.map +1 -1
- package/dist/dingtalk.d.ts.map +1 -1
- package/dist/dingtalk.js +26 -26
- package/dist/dingtalk.js.map +1 -1
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js +5 -8
- package/dist/events.js.map +1 -1
- package/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/dist/log.d.ts.map +1 -1
- package/dist/log.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js.map +1 -1
- package/dist/memory-consolidation.d.ts.map +1 -1
- package/dist/memory-consolidation.js.map +1 -1
- package/dist/memory-files.d.ts.map +1 -1
- package/dist/memory-files.js.map +1 -1
- package/dist/memory-lifecycle.d.ts.map +1 -1
- package/dist/memory-lifecycle.js +1 -2
- package/dist/memory-lifecycle.js.map +1 -1
- package/dist/model-utils.d.ts.map +1 -1
- package/dist/model-utils.js.map +1 -1
- package/dist/paths.d.ts.map +1 -1
- package/dist/prompt-builder.d.ts.map +1 -1
- package/dist/prompt-builder.js.map +1 -1
- package/dist/sandbox.d.ts.map +1 -1
- package/dist/sandbox.js +0 -1
- package/dist/sandbox.js.map +1 -1
- package/dist/shell-escape.d.ts.map +1 -1
- package/dist/shell-escape.js.map +1 -1
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +2 -3
- package/dist/store.js.map +1 -1
- package/dist/sub-agents.d.ts.map +1 -1
- package/dist/sub-agents.js +42 -10
- package/dist/sub-agents.js.map +1 -1
- package/dist/tools/attach.d.ts.map +1 -1
- package/dist/tools/attach.js.map +1 -1
- package/dist/tools/bash.d.ts.map +1 -1
- package/dist/tools/bash.js.map +1 -1
- package/dist/tools/edit.d.ts.map +1 -1
- package/dist/tools/edit.js.map +1 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/read.d.ts.map +1 -1
- package/dist/tools/read.js.map +1 -1
- package/dist/tools/subagent.d.ts.map +1 -1
- package/dist/tools/subagent.js.map +1 -1
- package/dist/tools/truncate.d.ts.map +1 -1
- package/dist/tools/truncate.js.map +1 -1
- package/dist/tools/write-content.d.ts.map +1 -1
- package/dist/tools/write-content.js.map +1 -1
- package/dist/tools/write.d.ts.map +1 -1
- package/dist/tools/write.js.map +1 -1
- package/docs/memory-rfc.md +291 -0
- package/docs/subagent/pi-subagent-analyse.txt +190 -0
- package/docs/subagent/pi-subagent-design.txt +266 -0
- package/docs/subagent/pi-subagent-phase1-plan.txt +529 -0
- package/package.json +69 -53
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
# Pipiclaw Memory Model RFC
|
|
2
|
+
|
|
3
|
+
## Status
|
|
4
|
+
|
|
5
|
+
Draft
|
|
6
|
+
|
|
7
|
+
## Goals
|
|
8
|
+
|
|
9
|
+
1. Define a minimal memory model for `pipiclaw` aligned with the `nanobot` style.
|
|
10
|
+
2. Make memory flow explicit: record, read, consolidate, and reuse.
|
|
11
|
+
3. Keep raw transport/session files cold and separate from memory.
|
|
12
|
+
4. Limit what is loaded into session context by default.
|
|
13
|
+
5. Preserve simple file-based operations and avoid introducing a dedicated memory database or memory-specific tools.
|
|
14
|
+
|
|
15
|
+
## Non-Goals
|
|
16
|
+
|
|
17
|
+
1. No OpenClaw-style vector retrieval, embedding index, or memory plugins.
|
|
18
|
+
2. No `memory_search` or `memory_get` tool.
|
|
19
|
+
3. No automatic runtime mutation of workspace-level `MEMORY.md`, `SOUL.md`, or `AGENTS.md`.
|
|
20
|
+
4. No automatic loading or scanning of `log.jsonl` or `context.jsonl` as part of memory behavior.
|
|
21
|
+
|
|
22
|
+
## Design Summary
|
|
23
|
+
|
|
24
|
+
Pipiclaw memory is split into two channel-level files plus one workspace-level admin file:
|
|
25
|
+
|
|
26
|
+
- `workspace/MEMORY.md`
|
|
27
|
+
- Stable, admin-managed, shared background memory.
|
|
28
|
+
- Not automatically updated by runtime consolidation.
|
|
29
|
+
- `<channel>/MEMORY.md`
|
|
30
|
+
- Durable channel memory.
|
|
31
|
+
- Updated automatically by consolidation.
|
|
32
|
+
- May also be updated manually by the agent.
|
|
33
|
+
- `<channel>/HISTORY.md`
|
|
34
|
+
- Channel history summaries.
|
|
35
|
+
- Updated automatically by consolidation only.
|
|
36
|
+
- Not intended for direct manual maintenance by the agent.
|
|
37
|
+
|
|
38
|
+
Raw storage remains separate:
|
|
39
|
+
|
|
40
|
+
- `<channel>/log.jsonl`
|
|
41
|
+
- Raw message log only.
|
|
42
|
+
- Cold storage.
|
|
43
|
+
- Not proactively loaded or scanned by runtime.
|
|
44
|
+
- `<channel>/context.jsonl`
|
|
45
|
+
- Raw session persistence only.
|
|
46
|
+
- Cold storage.
|
|
47
|
+
- Not proactively loaded or scanned by runtime for memory purposes.
|
|
48
|
+
|
|
49
|
+
## File Model
|
|
50
|
+
|
|
51
|
+
### Workspace-Level Files
|
|
52
|
+
|
|
53
|
+
- `SOUL.md`
|
|
54
|
+
- Loaded into session context at session start.
|
|
55
|
+
- Read-only from the agent's perspective unless a human explicitly changes it.
|
|
56
|
+
- `AGENTS.md`
|
|
57
|
+
- Loaded into session context at session start.
|
|
58
|
+
- Read-only from the agent's perspective unless a human explicitly changes it.
|
|
59
|
+
- `MEMORY.md`
|
|
60
|
+
- Not loaded by default.
|
|
61
|
+
- Listed in the system prompt with its role and path.
|
|
62
|
+
- Intended to be read on demand by the agent.
|
|
63
|
+
- Stable and admin-managed.
|
|
64
|
+
|
|
65
|
+
### Channel-Level Files
|
|
66
|
+
|
|
67
|
+
- `MEMORY.md`
|
|
68
|
+
- Not loaded by default.
|
|
69
|
+
- Listed in the system prompt with its role and path.
|
|
70
|
+
- Intended to be read on demand by the agent.
|
|
71
|
+
- Primary durable memory for the channel.
|
|
72
|
+
- `HISTORY.md`
|
|
73
|
+
- Not loaded by default.
|
|
74
|
+
- Listed in the system prompt with its role and path.
|
|
75
|
+
- Intended to be read on demand by the agent.
|
|
76
|
+
- Append-oriented summary history for older context.
|
|
77
|
+
- `log.jsonl`
|
|
78
|
+
- Raw archive only.
|
|
79
|
+
- Not memory.
|
|
80
|
+
- Runtime must not proactively load or scan it.
|
|
81
|
+
- `context.jsonl`
|
|
82
|
+
- Raw session archive only.
|
|
83
|
+
- Not memory.
|
|
84
|
+
- Runtime must not proactively load or scan it.
|
|
85
|
+
|
|
86
|
+
## Default Context Loading
|
|
87
|
+
|
|
88
|
+
At session start, runtime loads the following into session context:
|
|
89
|
+
|
|
90
|
+
1. Workspace-level `SOUL.md`
|
|
91
|
+
2. Workspace-level `AGENTS.md`
|
|
92
|
+
3. Built-in tool descriptions
|
|
93
|
+
4. Summaries of both workspace-level and channel-level skills
|
|
94
|
+
|
|
95
|
+
At session start, runtime does not load the following by default:
|
|
96
|
+
|
|
97
|
+
1. Workspace-level `MEMORY.md`
|
|
98
|
+
2. Channel-level `MEMORY.md`
|
|
99
|
+
3. Channel-level `HISTORY.md`
|
|
100
|
+
4. `<channel>/log.jsonl`
|
|
101
|
+
5. `<channel>/context.jsonl`
|
|
102
|
+
|
|
103
|
+
The system prompt must explicitly tell the agent:
|
|
104
|
+
|
|
105
|
+
1. Where `workspace/MEMORY.md`, `<channel>/MEMORY.md`, and `<channel>/HISTORY.md` live.
|
|
106
|
+
2. What each file is for.
|
|
107
|
+
3. That these files are not preloaded.
|
|
108
|
+
4. That the agent is encouraged to read them on demand when memory or history is relevant.
|
|
109
|
+
|
|
110
|
+
Changes to workspace-level `SOUL.md` and `AGENTS.md` take effect on new sessions. They are not reloaded on every turn.
|
|
111
|
+
|
|
112
|
+
## Agent Read/Write Rules
|
|
113
|
+
|
|
114
|
+
### Reads
|
|
115
|
+
|
|
116
|
+
The agent should prefer:
|
|
117
|
+
|
|
118
|
+
1. `<channel>/MEMORY.md` for durable channel facts, decisions, preferences, and ongoing state.
|
|
119
|
+
2. `<channel>/HISTORY.md` for older summarized context.
|
|
120
|
+
3. `workspace/MEMORY.md` for stable shared background.
|
|
121
|
+
|
|
122
|
+
The agent should not treat `log.jsonl` or `context.jsonl` as normal memory sources. Those files are for raw recovery, debugging, or explicit transcript-level investigation only.
|
|
123
|
+
|
|
124
|
+
### Writes
|
|
125
|
+
|
|
126
|
+
The agent may:
|
|
127
|
+
|
|
128
|
+
1. Read `workspace/MEMORY.md`
|
|
129
|
+
2. Read `<channel>/MEMORY.md`
|
|
130
|
+
3. Read `<channel>/HISTORY.md`
|
|
131
|
+
4. Manually update `<channel>/MEMORY.md` when necessary
|
|
132
|
+
|
|
133
|
+
The agent should not manually maintain `<channel>/HISTORY.md` during normal operation. `HISTORY.md` is runtime-managed.
|
|
134
|
+
|
|
135
|
+
The runtime must never automatically update:
|
|
136
|
+
|
|
137
|
+
1. `workspace/SOUL.md`
|
|
138
|
+
2. `workspace/AGENTS.md`
|
|
139
|
+
3. `workspace/MEMORY.md`
|
|
140
|
+
|
|
141
|
+
## Consolidation
|
|
142
|
+
|
|
143
|
+
Consolidation is the primary mechanism that keeps memory moving.
|
|
144
|
+
|
|
145
|
+
Consolidation takes recent session material and produces two outputs:
|
|
146
|
+
|
|
147
|
+
1. Durable facts and live channel state in `<channel>/MEMORY.md`
|
|
148
|
+
2. Older summarized history in `<channel>/HISTORY.md`
|
|
149
|
+
|
|
150
|
+
Consolidation must not write to workspace-level `MEMORY.md`.
|
|
151
|
+
|
|
152
|
+
### Trigger Model
|
|
153
|
+
|
|
154
|
+
Runtime should run consolidation automatically only when a session is about to compact or trim context.
|
|
155
|
+
|
|
156
|
+
There is no separate turn-count trigger, token-watermark trigger, or per-turn memory-dirty trigger in this RFC.
|
|
157
|
+
|
|
158
|
+
### Consolidation Input
|
|
159
|
+
|
|
160
|
+
Consolidation operates on recent session material already in the active session state. It does not scan `log.jsonl` or `context.jsonl`.
|
|
161
|
+
|
|
162
|
+
### Consolidation Output Rules
|
|
163
|
+
|
|
164
|
+
`<channel>/MEMORY.md` should contain:
|
|
165
|
+
|
|
166
|
+
1. Durable facts about the channel, user, project, preferences, constraints, and long-lived open threads.
|
|
167
|
+
2. Current state that matters across turns.
|
|
168
|
+
3. Cleaned and deduplicated entries.
|
|
169
|
+
4. Structured sections rather than free-form prose.
|
|
170
|
+
|
|
171
|
+
`<channel>/HISTORY.md` should contain:
|
|
172
|
+
|
|
173
|
+
1. Append-oriented summaries of older conversation chunks.
|
|
174
|
+
2. Resolved decisions and notable milestones.
|
|
175
|
+
3. Enough context for later recovery without replaying raw transcripts.
|
|
176
|
+
|
|
177
|
+
### Consolidation Semantics
|
|
178
|
+
|
|
179
|
+
Consolidation should:
|
|
180
|
+
|
|
181
|
+
1. Extract durable facts from recent session material.
|
|
182
|
+
2. Append new channel-memory entries into `<channel>/MEMORY.md` during normal operation.
|
|
183
|
+
3. Periodically clean up `<channel>/MEMORY.md` with a larger sweep that removes outdated entries, merges duplicates, and tightens wording.
|
|
184
|
+
4. Append or roll forward summarized older material into `<channel>/HISTORY.md`.
|
|
185
|
+
5. Periodically fold older `HISTORY.md` blocks into coarser summaries while keeping newer blocks more detailed.
|
|
186
|
+
6. Remove redundancy between the two files.
|
|
187
|
+
7. Prefer stable facts in `MEMORY.md` and narrative progression in `HISTORY.md`.
|
|
188
|
+
|
|
189
|
+
This RFC adopts an append-first strategy for `MEMORY.md`, with periodic cleanup passes rather than full rewrite on every consolidation.
|
|
190
|
+
|
|
191
|
+
Consolidation should not:
|
|
192
|
+
|
|
193
|
+
1. Dump raw message transcripts into `HISTORY.md`
|
|
194
|
+
2. Copy large blocks from `context.jsonl` or `log.jsonl`
|
|
195
|
+
3. Preserve outdated facts just because they were once true
|
|
196
|
+
|
|
197
|
+
## Suggested File Semantics
|
|
198
|
+
|
|
199
|
+
`<channel>/MEMORY.md` should be organized as stable sections such as:
|
|
200
|
+
|
|
201
|
+
1. `## Identity / Participants`
|
|
202
|
+
2. `## Preferences`
|
|
203
|
+
3. `## Ongoing Work`
|
|
204
|
+
4. `## Constraints`
|
|
205
|
+
5. `## Decisions`
|
|
206
|
+
6. `## Open Loops`
|
|
207
|
+
|
|
208
|
+
`<channel>/HISTORY.md` should be organized as chronological summary blocks such as:
|
|
209
|
+
|
|
210
|
+
1. Dated headings
|
|
211
|
+
2. Short summaries of work periods
|
|
212
|
+
3. Key decisions and outcomes
|
|
213
|
+
|
|
214
|
+
Exact formatting can evolve, but the split between durable memory and summarized history should remain stable.
|
|
215
|
+
|
|
216
|
+
## Consolidation Execution Model
|
|
217
|
+
|
|
218
|
+
Consolidation uses a two-phase execution model:
|
|
219
|
+
|
|
220
|
+
1. Inline phase
|
|
221
|
+
- Runs synchronously when a compaction or trim is about to happen.
|
|
222
|
+
- Responsible for producing the minimum safe memory updates needed before context is reduced.
|
|
223
|
+
2. Background phase
|
|
224
|
+
- Runs later as a per-channel queued maintenance pass.
|
|
225
|
+
- Responsible for larger cleanup work, including `MEMORY.md` cleanup sweeps and `HISTORY.md` folding.
|
|
226
|
+
|
|
227
|
+
The background phase must not replace the inline phase for compaction safety. It is an additional maintenance pass, not the primary durability guarantee.
|
|
228
|
+
|
|
229
|
+
## Compaction And Trimming Contract
|
|
230
|
+
|
|
231
|
+
Consolidation is hard-gated before compaction or trim.
|
|
232
|
+
|
|
233
|
+
This means:
|
|
234
|
+
|
|
235
|
+
1. If a compaction or trim would discard context, runtime must first run inline consolidation.
|
|
236
|
+
2. If inline consolidation fails, compaction or trim must not proceed.
|
|
237
|
+
3. After successful inline consolidation, the runtime may compact or trim.
|
|
238
|
+
|
|
239
|
+
This RFC does not allow trim-first or compact-first behavior when memory durability depends on consolidation.
|
|
240
|
+
|
|
241
|
+
## Runtime Responsibilities
|
|
242
|
+
|
|
243
|
+
Runtime is responsible for:
|
|
244
|
+
|
|
245
|
+
1. Loading only the default context described in this RFC.
|
|
246
|
+
2. Exposing file locations and roles clearly in the system prompt.
|
|
247
|
+
3. Running automatic consolidation.
|
|
248
|
+
4. Updating `<channel>/MEMORY.md` and `<channel>/HISTORY.md` during consolidation.
|
|
249
|
+
5. Keeping `log.jsonl` and `context.jsonl` cold.
|
|
250
|
+
|
|
251
|
+
Runtime is not responsible for:
|
|
252
|
+
|
|
253
|
+
1. Auto-loading memory files into every turn
|
|
254
|
+
2. Indexing memory into a vector database
|
|
255
|
+
3. Providing special memory-only tools
|
|
256
|
+
|
|
257
|
+
## Session Model
|
|
258
|
+
|
|
259
|
+
Session context is warm.
|
|
260
|
+
|
|
261
|
+
Memory files are warm-on-demand.
|
|
262
|
+
|
|
263
|
+
`log.jsonl` and `context.jsonl` are cold.
|
|
264
|
+
|
|
265
|
+
The intended flow is:
|
|
266
|
+
|
|
267
|
+
1. Session starts with `SOUL.md`, `AGENTS.md`, built-in tool descriptions, and skill summaries.
|
|
268
|
+
2. Agent reads channel or workspace memory files if the task needs them.
|
|
269
|
+
3. Conversation progresses in session state.
|
|
270
|
+
4. Runtime consolidates session material into `<channel>/MEMORY.md` and `<channel>/HISTORY.md`.
|
|
271
|
+
5. Older raw storage remains available but is not part of ordinary memory behavior.
|
|
272
|
+
|
|
273
|
+
## Migration Impact
|
|
274
|
+
|
|
275
|
+
This RFC implies the following behavior changes from the current implementation:
|
|
276
|
+
|
|
277
|
+
1. `workspace/MEMORY.md` and `<channel>/MEMORY.md` are no longer injected into the system prompt by default.
|
|
278
|
+
2. `SOUL.md` and `AGENTS.md` are no longer reloaded on every turn.
|
|
279
|
+
3. `log.jsonl` is no longer scanned to rebuild context as part of normal turn processing.
|
|
280
|
+
4. `context.jsonl` is no longer treated as a memory source.
|
|
281
|
+
5. Consolidation becomes the main persistence path for channel memory.
|
|
282
|
+
|
|
283
|
+
## Fixed Decisions
|
|
284
|
+
|
|
285
|
+
This RFC fixes the following design choices:
|
|
286
|
+
|
|
287
|
+
1. Consolidation triggers only before compaction or trim.
|
|
288
|
+
2. `<channel>/MEMORY.md` uses append-first updates with periodic cleanup sweeps.
|
|
289
|
+
3. `<channel>/HISTORY.md` uses append-first updates with periodic folding of older blocks.
|
|
290
|
+
4. Consolidation uses a two-phase execution model: inline for safety, background for maintenance.
|
|
291
|
+
5. Consolidation is hard-gated before compaction or trim.
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
多 Agent / Sub-Agent 模式分析
|
|
2
|
+
|
|
3
|
+
一、pi-coding-agent 当前支持到什么程度?
|
|
4
|
+
|
|
5
|
+
当前已有完整但处于 example 状态的 sub-agent 实现:
|
|
6
|
+
|
|
7
|
+
1. 进程级隔离的 SubAgent 扩展 (packages/coding-agent/examples/extensions/subagent/)
|
|
8
|
+
|
|
9
|
+
这是一个完整的 Extension,支持三种执行模式:
|
|
10
|
+
|
|
11
|
+
┌──────────┬────────────────────────────────────────────────┬────────────────────────────────┐
|
|
12
|
+
│ 模式 │ 语法 │ 描述 │
|
|
13
|
+
├──────────┼────────────────────────────────────────────────┼────────────────────────────────┤
|
|
14
|
+
│ Single │ { agent: "name", task: "..." } │ 单个子代理执行单个任务 │
|
|
15
|
+
├──────────┼────────────────────────────────────────────────┼────────────────────────────────┤
|
|
16
|
+
│ Parallel │ { tasks: [{agent, task}, ...] } │ 最多 8 个任务,并发度 4 │
|
|
17
|
+
├──────────┼────────────────────────────────────────────────┼────────────────────────────────┤
|
|
18
|
+
│ Chain │ { chain: [{agent, task: "...{previous}..."}] } │ 链式执行,前一个输出注入后一个 │
|
|
19
|
+
└──────────┴────────────────────────────────────────────────┴────────────────────────────────┘
|
|
20
|
+
|
|
21
|
+
实现方式是 spawn 独立 pi 子进程(--mode json --no-session),通过 NDJSON
|
|
22
|
+
事件流收集结果。每个子代理有完全独立的 context window。
|
|
23
|
+
|
|
24
|
+
2. Agent 发现系统 (agents.ts)
|
|
25
|
+
|
|
26
|
+
- 从 ~/.pi/agents/*.md(用户级)和 .pi/agents/*.md(项目级)加载 Agent 定义
|
|
27
|
+
- 每个 Agent 是一个带 YAML frontmatter 的 Markdown 文件,定义
|
|
28
|
+
name、description、tools、model、systemPrompt
|
|
29
|
+
- 项目级 Agent 覆盖同名的用户级 Agent
|
|
30
|
+
|
|
31
|
+
3. 轻量 Worker Agent 模式 (pipiclaw/src/memory-consolidation.ts:208-243)
|
|
32
|
+
|
|
33
|
+
pipiclaw 已经在用一种极简 sub-agent 模式:直接在进程内 new Agent() 创建一个无工具、纯文本生成的
|
|
34
|
+
worker,用于内存整理。这是最低开销的 sub-agent 形态。
|
|
35
|
+
|
|
36
|
+
4. 底层基础设施
|
|
37
|
+
|
|
38
|
+
- Agent 类完全支持独立实例化,构造参数灵活(tools、model、systemPrompt、thinkingLevel 等均可定制)
|
|
39
|
+
- AgentSession 的 Extension 系统提供 60+ 事件钩子,可以拦截/增强工具调用
|
|
40
|
+
- registerTool() API 可以在运行时注入新工具(包括"调用子代理"这个工具)
|
|
41
|
+
|
|
42
|
+
总结:核心能力已就绪,但 subagent 扩展还在 examples/ 目录,不是标准内置功能。
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
二、Multi-Agent vs Sub-Agent 的区别
|
|
46
|
+
|
|
47
|
+
这是两种根本不同的协作范式:
|
|
48
|
+
|
|
49
|
+
Sub-Agent(主从模式) Multi-Agent(对等协作模式)
|
|
50
|
+
┌───────────┐ ┌──────────┐ ┌──────────┐
|
|
51
|
+
│ 主 Agent │ │ Agent A │◄──►│ Agent B │
|
|
52
|
+
│ │ │ (编码) │ │ (测试) │
|
|
53
|
+
│ ┌──────┐ │ └──────────┘ └──────────┘
|
|
54
|
+
│ │子Agent│ │ ▲ ▲
|
|
55
|
+
│ │(工具) │ │ │ │
|
|
56
|
+
│ └──────┘ │ ┌──────────┐ │
|
|
57
|
+
└───────────┘ │ 协调层 │◄────────┘
|
|
58
|
+
└──────────┘
|
|
59
|
+
|
|
60
|
+
┌──────────┬──────────────────────────────────────────┬────────────────────────────────────────┐
|
|
61
|
+
│ 维度 │ Sub-Agent │ Multi-Agent │
|
|
62
|
+
├──────────┼──────────────────────────────────────────┼────────────────────────────────────────┤
|
|
63
|
+
│ 关系 │ 主从/调用方-被调用方 │ 对等/协作 │
|
|
64
|
+
├──────────┼──────────────────────────────────────────┼────────────────────────────────────────┤
|
|
65
|
+
│ 发起方 │ 主 Agent 通过 tool call 发起 │ 协调层编排,或 Agent 互相触发 │
|
|
66
|
+
├──────────┼──────────────────────────────────────────┼────────────────────────────────────────┤
|
|
67
|
+
│ 上下文 │ 子 Agent 只看到主 Agent 传入的 task 描述 │ 每个 Agent 有自己的完整上下文 │
|
|
68
|
+
├──────────┼──────────────────────────────────────────┼────────────────────────────────────────┤
|
|
69
|
+
│ 生命周期 │ 短暂——完成任务即销毁 │ 长期运行,可持续对话 │
|
|
70
|
+
├──────────┼──────────────────────────────────────────┼────────────────────────────────────────┤
|
|
71
|
+
│ 结果流向 │ 子 → 主(返回文本结果) │ 双向或多向(共享状态/消息传递) │
|
|
72
|
+
├──────────┼──────────────────────────────────────────┼────────────────────────────────────────┤
|
|
73
|
+
│ 决策权 │ 主 Agent 决定何时调用、给什么任务 │ 各 Agent 可自主决策 │
|
|
74
|
+
├──────────┼──────────────────────────────────────────┼────────────────────────────────────────┤
|
|
75
|
+
│ 复杂度 │ 低(现有 tool 框架直接支持) │ 高(需要消息总线、共享状态、冲突解决) │
|
|
76
|
+
├──────────┼──────────────────────────────────────────┼────────────────────────────────────────┤
|
|
77
|
+
│ 典型场景 │ "帮我搜索这个"、"审查这段代码" │ "一个写代码、一个写测试、一个做Review" │
|
|
78
|
+
└──────────┴──────────────────────────────────────────┴────────────────────────────────────────┘
|
|
79
|
+
|
|
80
|
+
对 pipiclaw 的实际建议:先做 Sub-Agent,这是投入产出比最高的路径。 Multi-Agent
|
|
81
|
+
的协调成本和调试复杂度目前不适合 DingTalk bot 场景。
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
三、在 pipiclaw 中如何设计和规划
|
|
85
|
+
|
|
86
|
+
Phase 1:内置 Sub-Agent 工具(短期,投入小)
|
|
87
|
+
|
|
88
|
+
将 examples/extensions/subagent/ 的核心能力集成到 pipiclaw 中,但做适配:
|
|
89
|
+
|
|
90
|
+
pipiclaw 适配要点:
|
|
91
|
+
1. 不能 spawn `pi` CLI 子进程(pipiclaw 无 CLI)
|
|
92
|
+
→ 改为进程内 new Agent() + 注入精简 tool 集
|
|
93
|
+
2. Agent 发现:复用 .pi/agents/*.md 机制
|
|
94
|
+
→ 或从 AGENTS.md 中解析 agent 定义
|
|
95
|
+
3. 输出回传:子 Agent 结果直接返回给主 Agent 的 tool result
|
|
96
|
+
4. 资源限制:子 Agent 的 token 消耗需要计入总量
|
|
97
|
+
|
|
98
|
+
核心实现路径:
|
|
99
|
+
|
|
100
|
+
// pipiclaw 的 sub-agent tool 骨架
|
|
101
|
+
function createSubAgentTool(parentConfig: ChannelConfig): AgentTool {
|
|
102
|
+
return {
|
|
103
|
+
name: "subagent",
|
|
104
|
+
execute: async (toolCallId, { agent, task }, signal) => {
|
|
105
|
+
const agentConfig = discoverAgents(workDir, "both")
|
|
106
|
+
.agents.find(a => a.name === agent);
|
|
107
|
+
|
|
108
|
+
// 进程内创建,比 spawn 更轻量
|
|
109
|
+
const worker = new Agent({
|
|
110
|
+
initialState: {
|
|
111
|
+
systemPrompt: agentConfig.systemPrompt,
|
|
112
|
+
model: agentConfig.model ?? parentModel,
|
|
113
|
+
tools: resolveTools(agentConfig.tools), // bash, read, write 等
|
|
114
|
+
},
|
|
115
|
+
getApiKey,
|
|
116
|
+
beforeToolCall, // 可复用主 Agent 的安全拦截
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
await worker.prompt(task);
|
|
120
|
+
await worker.waitForIdle();
|
|
121
|
+
return extractResult(worker);
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
Phase 2:Parallel Sub-Agent 支持(中期)
|
|
127
|
+
|
|
128
|
+
当 LLM 判断任务可分解时,允许并行派发多个 sub-agent:
|
|
129
|
+
|
|
130
|
+
- 实现 parallel 模式(复用 examples 中的 mapWithConcurrencyLimit)
|
|
131
|
+
- 添加 chain 模式用于流水线式任务
|
|
132
|
+
|
|
133
|
+
Phase 3:Agent 自主决策触发(长期,实验性)
|
|
134
|
+
|
|
135
|
+
让主 Agent 学会在适当场景自动使用 sub-agent,而不是用户手动指定:
|
|
136
|
+
|
|
137
|
+
- 在 SOUL.md 中定义策略(如"代码修改量超过 3 个文件时,自动启用 sub-agent 做代码审查")
|
|
138
|
+
- 或者通过 Extension 监听 tool call 事件,在特定条件下自动触发
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
四、目标效果
|
|
142
|
+
|
|
143
|
+
┌──────────────┬─────────────────────────────────────────┬────────────────────────────────────┐
|
|
144
|
+
│ 场景 │ 无 Sub-Agent │ 有 Sub-Agent │
|
|
145
|
+
├──────────────┼─────────────────────────────────────────┼────────────────────────────────────┤
|
|
146
|
+
│ 复杂代码任务 │ 主 Agent 在单一 context │ 拆分子任务,每个子 Agent │
|
|
147
|
+
│ │ 中处理所有文件,容易超长截断 │ 聚焦具体文件/模块 │
|
|
148
|
+
├──────────────┼─────────────────────────────────────────┼────────────────────────────────────┤
|
|
149
|
+
│ 代码审查 │ 改完即结束 │ 主 Agent 改代码 → sub-agent 自动 │
|
|
150
|
+
│ │ │ review → 反馈改进 │
|
|
151
|
+
├──────────────┼─────────────────────────────────────────┼────────────────────────────────────┤
|
|
152
|
+
│ 信息搜集 │ 串行搜索,效率低 │ 并行派 3 个 sub-agent │
|
|
153
|
+
│ │ │ 同时搜不同方向 │
|
|
154
|
+
├──────────────┼─────────────────────────────────────────┼────────────────────────────────────┤
|
|
155
|
+
│ 测试 │ 手动让 Agent 跑测试 │ 代码写完后 sub-agent │
|
|
156
|
+
│ │ │ 自动运行测试并汇总 │
|
|
157
|
+
├──────────────┼─────────────────────────────────────────┼────────────────────────────────────┤
|
|
158
|
+
│ 长对话场景 │ context window 膨胀,质量下降 │ 重计算子任务卸载到独立 context 的 │
|
|
159
|
+
│ │ │ sub-agent │
|
|
160
|
+
└──────────────┴─────────────────────────────────────────┴────────────────────────────────────┘
|
|
161
|
+
|
|
162
|
+
核心价值:context window 分治。 DingTalk bot
|
|
163
|
+
场景中,用户可能在一个频道里提出复杂的多步骤需求,sub-agent 让主 Agent
|
|
164
|
+
可以将重计算子任务卸载,保持主 context 的精简和高质量。
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
五、怎样决定是否启用 Sub-Agent
|
|
168
|
+
|
|
169
|
+
不应该让用户手动决定——由 Agent 自主判断,但需要给出决策框架:
|
|
170
|
+
|
|
171
|
+
适合启用 sub-agent 的条件(可写入 SOUL.md 作为 Agent 指令):
|
|
172
|
+
|
|
173
|
+
1. 任务可分解性:当前任务可以拆分成独立子问题(如"搜索 A 并搜索 B"→ parallel)
|
|
174
|
+
2. context 压力:主 context 已接近上限,或需要处理大量代码文件
|
|
175
|
+
3. 专业化需求:任务需要不同"人格"(如编码 Agent vs 审查 Agent)
|
|
176
|
+
4. 耗时操作:长时间运行的 bash 命令或大范围文件搜索
|
|
177
|
+
5. 质量保证:写代码后希望有独立视角的审查
|
|
178
|
+
|
|
179
|
+
不适合使用的场景:
|
|
180
|
+
|
|
181
|
+
1. 简单问答:用户问一个简单问题,没有调用开销的必要
|
|
182
|
+
2. 上下文密集:子任务严重依赖当前对话上下文,传递成本高
|
|
183
|
+
3. 交互式任务:需要频繁和用户确认的任务(sub-agent 是批处理模式)
|
|
184
|
+
4. 成本敏感:每个 sub-agent 都有额外的 token 开销
|
|
185
|
+
|
|
186
|
+
实现建议:在 pipiclaw 中,初期可以不做自动决策,而是:
|
|
187
|
+
- 在 AGENTS.md 中定义可用的 Agent 列表和各自能力
|
|
188
|
+
- 在 SOUL.md 中告诉主 Agent "当遇到 X 场景时,可以使用 subagent 工具"
|
|
189
|
+
- 让 LLM 基于指令自主判断——这本身就是 LLM 擅长的决策
|
|
190
|
+
|