@zhushanwen/pi-subagents 0.0.1
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/agents/context-builder.md +19 -0
- package/agents/oracle.md +19 -0
- package/agents/planner.md +19 -0
- package/agents/researcher.md +19 -0
- package/agents/reviewer.md +19 -0
- package/agents/scout.md +19 -0
- package/agents/worker.md +18 -0
- package/index.ts +1 -0
- package/package.json +59 -0
- package/src/commands/subagents.ts +78 -0
- package/src/core/agent-registry.ts +222 -0
- package/src/core/concurrency-pool.ts +78 -0
- package/src/core/event-bridge.ts +199 -0
- package/src/core/execution-record.ts +500 -0
- package/src/core/model-resolver.ts +206 -0
- package/src/core/output-collector.ts +118 -0
- package/src/core/path-encoding.ts +16 -0
- package/src/core/session-factory.ts +365 -0
- package/src/core/session-runner.ts +303 -0
- package/src/core/turn-limiter.ts +71 -0
- package/src/index.ts +104 -0
- package/src/runtime/config/config.ts +170 -0
- package/src/runtime/discovery-config.ts +135 -0
- package/src/runtime/execution/history-store.ts +196 -0
- package/src/runtime/execution/notifier.ts +209 -0
- package/src/runtime/execution/record-store.ts +280 -0
- package/src/runtime/model-config-service.ts +265 -0
- package/src/runtime/session-file-gc.ts +70 -0
- package/src/runtime/subagent-service.ts +549 -0
- package/src/tools/subagent-tool.ts +286 -0
- package/src/tui/bg-notify-render.ts +139 -0
- package/src/tui/config-wizard.ts +253 -0
- package/src/tui/format-helpers.ts +37 -0
- package/src/tui/format.ts +332 -0
- package/src/tui/list-view.ts +883 -0
- package/src/tui/tool-render.ts +467 -0
- package/src/types.ts +334 -0
package/src/types.ts
ADDED
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
// src/types.ts
|
|
2
|
+
//
|
|
3
|
+
// 跨层共享的核心类型契约。Core/Runtime/TUI 三层均可 import 本文件。
|
|
4
|
+
//
|
|
5
|
+
// 分层铁律:
|
|
6
|
+
// - Core 不 import Runtime/TUI(零 Pi 依赖,可单测)
|
|
7
|
+
// - Runtime 编排 Core,产出 Details/Record 给 TUI
|
|
8
|
+
// - TUI 只读 Record/Details 快照,永不持有可变引用
|
|
9
|
+
|
|
10
|
+
import type { AgentConfig, ResolvedModel } from "./core/model-resolver.ts";
|
|
11
|
+
|
|
12
|
+
// ============================================================
|
|
13
|
+
// 执行状态机
|
|
14
|
+
// ============================================================
|
|
15
|
+
|
|
16
|
+
/** 唯一执行状态。所有路径(sync/bg/poll)共用。 */
|
|
17
|
+
export type ExecutionStatus = "running" | "done" | "failed" | "cancelled";
|
|
18
|
+
|
|
19
|
+
/** 执行模式。sync = 调用方 await;background = 调用方立即拿 handle 返回。 */
|
|
20
|
+
export type ExecutionMode = "sync" | "background";
|
|
21
|
+
|
|
22
|
+
// ============================================================
|
|
23
|
+
// Agent 事件流(Core → Record 的唯一更新驱动)
|
|
24
|
+
// ============================================================
|
|
25
|
+
|
|
26
|
+
/** Pi session.subscribe 上报的事件。Runtime 把它喂给 updateFromEvent。 */
|
|
27
|
+
export type AgentEvent =
|
|
28
|
+
| { type: "tool_start"; toolName: string; args?: unknown }
|
|
29
|
+
| { type: "tool_end"; toolName: string; args?: unknown; isError?: boolean }
|
|
30
|
+
| { type: "text_delta"; delta: string }
|
|
31
|
+
| { type: "thinking_delta"; delta: string }
|
|
32
|
+
| { type: "turn_end"; summary?: string }
|
|
33
|
+
| { type: "message_end"; usage?: AgentUsage; error?: string }
|
|
34
|
+
| { type: "compaction" }
|
|
35
|
+
| { type: "error"; message: string };
|
|
36
|
+
|
|
37
|
+
/** token 用量(message_end 时由 Core 累加进 record.totalTokens)。 */
|
|
38
|
+
export interface AgentUsage {
|
|
39
|
+
input: number;
|
|
40
|
+
output: number;
|
|
41
|
+
cacheRead: number;
|
|
42
|
+
cacheWrite: number;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface AgentUsageTotal extends AgentUsage {
|
|
46
|
+
/** 上述四项之和。投影时不再手工求和。 */
|
|
47
|
+
total: number;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** eventLog 条目(Record.eventLog 的元素)。所有字段 readonly。 */
|
|
51
|
+
export interface AgentEventLogEntry {
|
|
52
|
+
readonly type: "tool_start" | "tool_end" | "text_output" | "thinking" | "turn_end" | "error";
|
|
53
|
+
readonly label: string;
|
|
54
|
+
readonly ts: number;
|
|
55
|
+
readonly status?: "running" | "done" | "failed";
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// ============================================================
|
|
59
|
+
// Agent 结果(一次执行的 outcome)
|
|
60
|
+
// ============================================================
|
|
61
|
+
|
|
62
|
+
/** tool 调用结果(tool_execution_end 时 bridge 累积,含 structured-output 的 details)。 */
|
|
63
|
+
export interface ToolCallResult {
|
|
64
|
+
content?: unknown[];
|
|
65
|
+
details?: unknown;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export interface ToolCall {
|
|
69
|
+
toolName: string;
|
|
70
|
+
args?: unknown;
|
|
71
|
+
result?: ToolCallResult;
|
|
72
|
+
isError?: boolean;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** 一次 session 执行的完整结果。collectResult 产出,写入 Record.outcome。 */
|
|
76
|
+
export interface AgentResult {
|
|
77
|
+
text: string;
|
|
78
|
+
turns: number;
|
|
79
|
+
durationMs: number;
|
|
80
|
+
success: boolean;
|
|
81
|
+
error?: string;
|
|
82
|
+
sessionId: string;
|
|
83
|
+
toolCalls: ToolCall[];
|
|
84
|
+
usage?: AgentUsageTotal;
|
|
85
|
+
/** /resume /fork 可恢复的 session 文件名(不含目录)。 */
|
|
86
|
+
sessionFile?: string;
|
|
87
|
+
/** schema 模式下,structured-output tool 的 result.details(已通过 schema 校验)。 */
|
|
88
|
+
parsedOutput?: unknown;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// ============================================================
|
|
92
|
+
// ExecutionRecord —— 唯一状态对象(Core 拥有,Runtime 引用)
|
|
93
|
+
// ============================================================
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* 所有执行路径的唯一状态源。
|
|
97
|
+
*
|
|
98
|
+
* 生命周期:createRecord() 创建 → updateFromEvent() 实时更新 →
|
|
99
|
+
* completeRecord() 冻结 → archive/history 持久化。
|
|
100
|
+
*
|
|
101
|
+
* TUI 永远拿 RecordSnapshot(.slice() 快照),不直接持此可变对象。
|
|
102
|
+
*/
|
|
103
|
+
export interface ExecutionRecord {
|
|
104
|
+
/** 唯一 ID(sync: "run-N",bg: "bg-N-xxx")。 */
|
|
105
|
+
readonly id: string;
|
|
106
|
+
|
|
107
|
+
// ── 身份(创建时确定,不可变)──
|
|
108
|
+
readonly agent: string;
|
|
109
|
+
readonly model: string;
|
|
110
|
+
readonly thinkingLevel: string | undefined;
|
|
111
|
+
readonly mode: ExecutionMode;
|
|
112
|
+
readonly task: string;
|
|
113
|
+
readonly startedAt: number;
|
|
114
|
+
|
|
115
|
+
// ── 状态(实时更新)──
|
|
116
|
+
status: ExecutionStatus;
|
|
117
|
+
eventLog: AgentEventLogEntry[];
|
|
118
|
+
turns: number;
|
|
119
|
+
totalTokens: number;
|
|
120
|
+
|
|
121
|
+
// ── 完成 ──
|
|
122
|
+
endedAt: number | undefined;
|
|
123
|
+
result: string | undefined;
|
|
124
|
+
error: string | undefined;
|
|
125
|
+
/** 完整 AgentResult(含 usage/toolCalls,完成时填)。 */
|
|
126
|
+
agentResult: AgentResult | undefined;
|
|
127
|
+
|
|
128
|
+
// ── 控制(仅 background 持有)──
|
|
129
|
+
controller: AbortController | undefined;
|
|
130
|
+
|
|
131
|
+
// ── eventLog chunking 缓冲(跨事件持久,修复 sink reset bug)──
|
|
132
|
+
_currentTurnText: string;
|
|
133
|
+
_currentThinking: string;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// ============================================================
|
|
137
|
+
// Runtime → TUI 的投影契约
|
|
138
|
+
// ============================================================
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Tool 返回的 details(renderResult 消费)。
|
|
142
|
+
* 由 project(record) 唯一产出——sync/bg/poll 三路径字段一致。
|
|
143
|
+
*/
|
|
144
|
+
export interface SubagentToolDetails {
|
|
145
|
+
status: ExecutionStatus;
|
|
146
|
+
agent: string;
|
|
147
|
+
model: string;
|
|
148
|
+
thinkingLevel: string | undefined;
|
|
149
|
+
turns: number;
|
|
150
|
+
totalTokens: number;
|
|
151
|
+
elapsedSeconds: number;
|
|
152
|
+
eventLog: AgentEventLogEntry[];
|
|
153
|
+
result?: string;
|
|
154
|
+
error?: string;
|
|
155
|
+
/** running 时的当前活动行(tool/thinking/text 优先级)。 */
|
|
156
|
+
currentActivity?: { type: "tool" | "text" | "thinking"; label: string };
|
|
157
|
+
/** 仅 background 模式返回,供 LLM 后续 poll。 */
|
|
158
|
+
backgroundId?: string;
|
|
159
|
+
/** schema 模式下,structured-output tool 的 result.details(对齐 workflow agent-pool)。 */
|
|
160
|
+
parsedOutput?: unknown;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// ============================================================
|
|
164
|
+
// Runtime 公共 API 的入参/出参
|
|
165
|
+
// ============================================================
|
|
166
|
+
|
|
167
|
+
/** Hub.execute 的入参(sync/bg 共用)。mode 由 Hub 内部判定,不暴露给调用方。 */
|
|
168
|
+
export interface ExecuteOptions {
|
|
169
|
+
task: string;
|
|
170
|
+
agent?: string;
|
|
171
|
+
/**
|
|
172
|
+
* 执行模式意图(不直接指定 mode):
|
|
173
|
+
* false → background(用户显式要求异步)
|
|
174
|
+
* true → sync(用户显式要求同步)
|
|
175
|
+
* undefined → Hub 按 agentConfig.defaultBackground 判定
|
|
176
|
+
* Hub 内部据此 + agent 配置解析出最终 ExecutionMode。
|
|
177
|
+
*/
|
|
178
|
+
wait?: boolean;
|
|
179
|
+
model?: string;
|
|
180
|
+
thinkingLevel?: string;
|
|
181
|
+
skillPath?: string;
|
|
182
|
+
appendSystemPrompt?: string[];
|
|
183
|
+
schema?: Record<string, unknown>;
|
|
184
|
+
maxTurns?: number;
|
|
185
|
+
graceTurns?: number;
|
|
186
|
+
/** sync 模式来自 Pi tool 框架;background 模式 hub 忽略,自建 controller。 */
|
|
187
|
+
signal?: AbortSignal;
|
|
188
|
+
/** live 状态回流(对话流 block 实时刷新)。 */
|
|
189
|
+
onUpdate?: (details: SubagentToolDetails) => void;
|
|
190
|
+
/** background 完成回调(sync 不调)。 */
|
|
191
|
+
onComplete?: (record: RecordSnapshot) => void;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* execute 返回值。
|
|
196
|
+
* sync: { mode:"sync", record, details } —— 调用方 await,record 已 settled。
|
|
197
|
+
* record 是只读快照(持久化/poll 用),details 是 TUI 渲染投影(含 elapsedSeconds/currentActivity)。
|
|
198
|
+
* background: { mode:"background", backgroundId } —— 立即返回。
|
|
199
|
+
*/
|
|
200
|
+
export type ExecutionHandle =
|
|
201
|
+
| { mode: "sync"; record: RecordSnapshot; details: SubagentToolDetails }
|
|
202
|
+
| { mode: "background"; backgroundId: string; details: SubagentToolDetails };
|
|
203
|
+
|
|
204
|
+
/** poll(backgroundId) 返回。record 的只读视图。 */
|
|
205
|
+
export interface QueryResult {
|
|
206
|
+
id: string;
|
|
207
|
+
status: ExecutionStatus;
|
|
208
|
+
agent: string;
|
|
209
|
+
model: string;
|
|
210
|
+
thinkingLevel: string | undefined;
|
|
211
|
+
turns: number;
|
|
212
|
+
totalTokens: number;
|
|
213
|
+
startedAt: number;
|
|
214
|
+
endedAt: number | undefined;
|
|
215
|
+
elapsedSeconds: number;
|
|
216
|
+
result?: string;
|
|
217
|
+
error?: string;
|
|
218
|
+
eventLog: AgentEventLogEntry[];
|
|
219
|
+
mode: ExecutionMode;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// ============================================================
|
|
223
|
+
// TUI list 视图的合并 record(4 源 merge 后的形状)
|
|
224
|
+
// ============================================================
|
|
225
|
+
|
|
226
|
+
/** /subagents list 左列展示单元。合并自 live/completed/bg/history 四源。 */
|
|
227
|
+
export interface SubagentRecord {
|
|
228
|
+
id: string;
|
|
229
|
+
agent: string;
|
|
230
|
+
status: ExecutionStatus;
|
|
231
|
+
mode: ExecutionMode;
|
|
232
|
+
startedAt: number;
|
|
233
|
+
endedAt: number | undefined;
|
|
234
|
+
turns: number;
|
|
235
|
+
totalTokens: number;
|
|
236
|
+
model: string;
|
|
237
|
+
thinkingLevel: string | undefined;
|
|
238
|
+
eventLog: AgentEventLogEntry[];
|
|
239
|
+
result?: string;
|
|
240
|
+
error?: string;
|
|
241
|
+
sessionFile?: string;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// ============================================================
|
|
245
|
+
// 持久化(history.jsonl 一行)
|
|
246
|
+
// ============================================================
|
|
247
|
+
|
|
248
|
+
export interface PersistedAgentRecord {
|
|
249
|
+
id: string;
|
|
250
|
+
agent: string;
|
|
251
|
+
status: ExecutionStatus;
|
|
252
|
+
mode: ExecutionMode;
|
|
253
|
+
taskPreview: string;
|
|
254
|
+
startedAt: number;
|
|
255
|
+
endedAt?: number;
|
|
256
|
+
turns?: number;
|
|
257
|
+
totalTokens?: number;
|
|
258
|
+
error?: string;
|
|
259
|
+
resultPreview?: string;
|
|
260
|
+
sessionFile?: string;
|
|
261
|
+
cwd: string;
|
|
262
|
+
sessionId?: string;
|
|
263
|
+
model?: string;
|
|
264
|
+
thinkingLevel?: string;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// ============================================================
|
|
268
|
+
// 配置(global + session)
|
|
269
|
+
// ============================================================
|
|
270
|
+
|
|
271
|
+
export interface SubagentsGlobalConfig {
|
|
272
|
+
version: number;
|
|
273
|
+
yoloByDefault: boolean;
|
|
274
|
+
maxConcurrent: number;
|
|
275
|
+
categories: Record<string, CategoryDefinition>;
|
|
276
|
+
agentCategoryOverrides: Record<string, string>;
|
|
277
|
+
fallback: { model: string; thinkingLevel?: string };
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
export interface CategoryDefinition {
|
|
281
|
+
label: string;
|
|
282
|
+
model: string;
|
|
283
|
+
thinkingLevel?: string;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* 资源发现契约(<agentDir>/subagents/discovery.json)。
|
|
288
|
+
* 宿主(如 xyz-agent GUI)启动 pi 前写入,subagents 在 session_start 与 resources_discover 时读取。
|
|
289
|
+
* 文件缺失/字段缺失时各数组视为空,走默认行为(零破坏)。详见 ADR-025。
|
|
290
|
+
*/
|
|
291
|
+
export interface DiscoveryConfig {
|
|
292
|
+
version: number;
|
|
293
|
+
/** skill 目录列表(靠前覆盖靠后)。空数组 = 不额外注入,走默认。 */
|
|
294
|
+
skillDirs: string[];
|
|
295
|
+
/** agent .md 目录列表(靠前覆盖靠后)。空数组 = 走默认 getAgentDir()。 */
|
|
296
|
+
agentDirs: string[];
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/** 首次 category 模型确认后的 per-session 覆盖。 */
|
|
300
|
+
export interface SessionModelState {
|
|
301
|
+
yoloMode: boolean;
|
|
302
|
+
/** @deprecated D-1:取消首次确认后此字段恒为 true,仅 restoreSessionState 保留读写以向后兼容。 */
|
|
303
|
+
categoryConfirmed: boolean;
|
|
304
|
+
categoryModels: Record<string, { model: string; thinkingLevel?: string }>;
|
|
305
|
+
agentModels: Record<string, { model: string; thinkingLevel?: string }>;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// ============================================================
|
|
309
|
+
// 只读快照(TUI 消费,永不 mutate)
|
|
310
|
+
// ============================================================
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Record 的只读视图。store.snapshot() 返回。
|
|
314
|
+
* TUI 拿到此类型,保证不会回写 Core 状态。
|
|
315
|
+
*/
|
|
316
|
+
export interface RecordSnapshot {
|
|
317
|
+
readonly id: string;
|
|
318
|
+
readonly agent: string;
|
|
319
|
+
readonly model: string;
|
|
320
|
+
readonly thinkingLevel: string | undefined;
|
|
321
|
+
readonly mode: ExecutionMode;
|
|
322
|
+
readonly task: string;
|
|
323
|
+
readonly status: ExecutionStatus;
|
|
324
|
+
readonly eventLog: readonly AgentEventLogEntry[];
|
|
325
|
+
readonly turns: number;
|
|
326
|
+
readonly totalTokens: number;
|
|
327
|
+
readonly startedAt: number;
|
|
328
|
+
readonly endedAt: number | undefined;
|
|
329
|
+
readonly result: string | undefined;
|
|
330
|
+
readonly error: string | undefined;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// Re-export 用于 ExecuteOptions 的 agent/model 契约
|
|
334
|
+
export type { AgentConfig, ResolvedModel };
|