@zhushanwen/pi-subagent-workflow 8.4.0 → 8.6.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/package.json +22 -7
- package/relay/relay.mjs +390 -0
- package/skills/subagent-ext-config/SKILL.md +80 -0
- package/src/execution/__tests__/agent-registry.test.ts +110 -0
- package/src/execution/__tests__/bg-notify-render.test.ts +73 -0
- package/src/execution/__tests__/chat-engine-routing.test.ts +601 -0
- package/src/execution/__tests__/delivery-methods.test.ts +38 -1
- package/src/execution/__tests__/execute-options-mapper.test.ts +11 -0
- package/src/execution/__tests__/execution-record.test.ts +237 -1
- package/src/execution/__tests__/explicit-agent-ref-guard.test.ts +171 -0
- package/src/execution/__tests__/format-schema-instruction.test.ts +63 -32
- package/src/execution/__tests__/helpers/spawn-mock.ts +4 -0
- package/src/execution/__tests__/index-session-start.test.ts +86 -7
- package/src/execution/__tests__/lifecycle-manager.test.ts +46 -0
- package/src/execution/__tests__/list-fields.test.ts +45 -14
- package/src/execution/__tests__/model-resolver.test.ts +57 -5
- package/src/execution/__tests__/notifier-flush.test.ts +64 -26
- package/src/execution/__tests__/notify-ledger.test.ts +826 -0
- package/src/execution/__tests__/output-collector.test.ts +299 -2
- package/src/execution/__tests__/pi-invocation.test.ts +62 -1
- package/src/execution/__tests__/relay-agent.test.ts +448 -0
- package/src/execution/__tests__/relay-env.test.ts +42 -0
- package/src/execution/__tests__/rpc-mode.test.ts +1 -1
- package/src/execution/__tests__/run-spawn-edges.test.ts +44 -1
- package/src/execution/__tests__/run-spawn-stdout-callback-throw.test.ts +199 -0
- package/src/execution/__tests__/session-runner-schema-env.test.ts +39 -0
- package/src/execution/__tests__/spawn-args.test.ts +37 -26
- package/src/execution/__tests__/start-sync-model-guard.test.ts +150 -0
- package/src/execution/__tests__/startup-config-declaration.test.ts +35 -0
- package/src/execution/__tests__/stream-sink-retirement.test.ts +261 -0
- package/src/execution/__tests__/subprocess-agent-runner-routing.test.ts +310 -0
- package/src/execution/__tests__/subprocess-agent-runner.test.ts +147 -6
- package/src/execution/__tests__/timeout-integration.test.ts +220 -2
- package/src/execution/__tests__/tool-action.test.ts +92 -1
- package/src/execution/agent-registry.ts +16 -0
- package/src/execution/argv-mirror.ts +5 -1
- package/src/execution/concurrency-pool.ts +1 -1
- package/src/execution/config.ts +25 -2
- package/src/execution/engine/__tests__/common/data-dir.test.ts +53 -0
- package/src/execution/engine/__tests__/common/errors.test.ts +132 -0
- package/src/execution/engine/__tests__/common/event-journal.test.ts +177 -0
- package/src/execution/engine/__tests__/common/kill-chain.test.ts +192 -0
- package/src/execution/engine/__tests__/common/nesting-guard.test.ts +81 -0
- package/src/execution/engine/__tests__/common/persona-router.test.ts +123 -0
- package/src/execution/engine/__tests__/common/pool-manager.test.ts +154 -0
- package/src/execution/engine/__tests__/common/schema-emulation.test.ts +128 -0
- package/src/execution/engine/__tests__/conformance/__fixtures__/pi-golden-events.json +28 -0
- package/src/execution/engine/__tests__/conformance/agent-event-invariants.ts +141 -0
- package/src/execution/engine/__tests__/conformance/contract.abort.test.ts +109 -0
- package/src/execution/engine/__tests__/conformance/contract.agent-events.test.ts +101 -0
- package/src/execution/engine/__tests__/conformance/contract.probe.test.ts +77 -0
- package/src/execution/engine/__tests__/conformance/contract.read-degradation.test.ts +104 -0
- package/src/execution/engine/__tests__/conformance/contract.relay.test.ts +342 -0
- package/src/execution/engine/__tests__/conformance/engine-conformance.live.test.ts +201 -0
- package/src/execution/engine/__tests__/conformance/golden-replay.pi.test.ts +76 -0
- package/src/execution/engine/__tests__/conformance/golden-replay.zcode.test.ts +79 -0
- package/src/execution/engine/__tests__/engine-discovery.test.ts +87 -0
- package/src/execution/engine/__tests__/engines-declaration.test.ts +36 -0
- package/src/execution/engine/__tests__/model-prompt.test.ts +85 -0
- package/src/execution/engine/__tests__/paths.test.ts +39 -0
- package/src/execution/engine/__tests__/registry.test.ts +120 -0
- package/src/execution/engine/__tests__/routing.test.ts +231 -0
- package/src/execution/engine/common/data-dir.ts +62 -0
- package/src/execution/engine/common/errors.ts +183 -0
- package/src/execution/engine/common/event-journal.ts +254 -0
- package/src/execution/engine/common/journal-replay.ts +62 -0
- package/src/execution/engine/common/kill-chain.ts +221 -0
- package/src/execution/engine/common/nesting-guard.ts +50 -0
- package/src/execution/engine/common/persona-router.ts +108 -0
- package/src/execution/engine/common/pool-manager.ts +226 -0
- package/src/execution/engine/common/schema-emulation.ts +189 -0
- package/src/execution/engine/common/session-view-projection.ts +51 -0
- package/src/execution/engine/engine-discovery.ts +65 -0
- package/src/execution/engine/engines/pi/__tests__/pi-engine.test.ts +469 -0
- package/src/execution/engine/engines/pi/__tests__/reader.test.ts +155 -0
- package/src/execution/engine/engines/pi/__tests__/task-spec-mapper.test.ts +164 -0
- package/src/execution/engine/engines/pi/pi-engine.ts +415 -0
- package/src/execution/engine/engines/pi/reader.ts +48 -0
- package/src/execution/engine/engines/pi/registration.ts +35 -0
- package/src/execution/engine/engines/pi/task-spec-mapper.ts +100 -0
- package/src/execution/engine/engines/zcode/__tests__/__fixtures__/zcode-golden-spawn.json +39 -0
- package/src/execution/engine/engines/zcode/__tests__/launcher.test.ts +150 -0
- package/src/execution/engine/engines/zcode/__tests__/parser.test.ts +246 -0
- package/src/execution/engine/engines/zcode/__tests__/preparer.test.ts +228 -0
- package/src/execution/engine/engines/zcode/__tests__/reader.test.ts +210 -0
- package/src/execution/engine/engines/zcode/__tests__/registration.test.ts +64 -0
- package/src/execution/engine/engines/zcode/__tests__/zcode-engine.live.test.ts +127 -0
- package/src/execution/engine/engines/zcode/__tests__/zcode-engine.test.ts +580 -0
- package/src/execution/engine/engines/zcode/constants.ts +43 -0
- package/src/execution/engine/engines/zcode/golden-sample.ts +39 -0
- package/src/execution/engine/engines/zcode/launcher.ts +161 -0
- package/src/execution/engine/engines/zcode/parser.ts +436 -0
- package/src/execution/engine/engines/zcode/preparer.ts +363 -0
- package/src/execution/engine/engines/zcode/reader.ts +381 -0
- package/src/execution/engine/engines/zcode/registration.ts +37 -0
- package/src/execution/engine/engines/zcode/zcode-engine.ts +658 -0
- package/src/execution/engine/host-task-spec.ts +47 -0
- package/src/execution/engine/model-prompt.ts +59 -0
- package/src/execution/engine/paths.ts +42 -0
- package/src/execution/engine/port.ts +153 -0
- package/src/execution/engine/registry.ts +123 -0
- package/src/execution/engine/routing.ts +218 -0
- package/src/execution/engine/types.ts +309 -0
- package/src/execution/execute-options-mapper.ts +13 -8
- package/src/execution/execution-record.ts +66 -1
- package/src/execution/lifecycle-manager.ts +23 -1
- package/src/execution/model-config-service.ts +16 -1
- package/src/execution/model-resolver.ts +37 -59
- package/src/execution/notifier.ts +105 -35
- package/src/execution/notify-ledger.ts +580 -0
- package/src/execution/output-collector.ts +143 -3
- package/src/execution/pi-invocation.ts +32 -2
- package/src/execution/record-entry.ts +14 -0
- package/src/execution/record-store.ts +34 -0
- package/src/execution/relay-env.ts +37 -0
- package/src/execution/session-runner.ts +328 -71
- package/src/execution/stream-sink.ts +26 -0
- package/src/execution/subagent-service.ts +273 -13
- package/src/execution/subprocess-agent-runner.ts +210 -14
- package/src/execution/types.ts +124 -5
- package/src/execution/ui-request-queue.ts +14 -4
- package/src/index.ts +99 -1
- package/src/interface/__tests__/subagent-tool-path-guard.test.ts +157 -0
- package/src/interface/__tests__/subagent-tool-prompt.test.ts +12 -0
- package/src/interface/bg-notify-render.ts +33 -12
- package/src/interface/helpers.ts +2 -2
- package/src/interface/subagent-actions.ts +29 -9
- package/src/interface/subagent-tool-schema.ts +156 -0
- package/src/interface/subagent-tool.ts +56 -119
- package/src/interface/subagents.ts +2 -2
- package/src/orchestration/__tests__/__fixtures__/worker-template.snapshot.txt +19 -3
- package/src/orchestration/__tests__/agent-call-catch-fallback.test.ts +0 -6
- package/src/orchestration/__tests__/agent-call-stream.test.ts +0 -5
- package/src/orchestration/__tests__/error-recovery-handlers.test.ts +89 -4
- package/src/orchestration/__tests__/execute-agent-call.test.ts +137 -0
- package/src/orchestration/__tests__/jsonl-run-store-corrupt-entry.test.ts +150 -0
- package/src/orchestration/__tests__/jsonl-run-store-retention.test.ts +202 -0
- package/src/orchestration/__tests__/launcher-nested-workflow.test.ts +326 -3
- package/src/orchestration/__tests__/lifecycle.test.ts +41 -7
- package/src/orchestration/__tests__/non-cloneable-return-e2e.test.ts +95 -0
- package/src/orchestration/__tests__/review-fix-loop-e2e.test.ts +57 -3
- package/src/orchestration/__tests__/skill-discovery.test.ts +44 -0
- package/src/orchestration/__tests__/worker-exit-without-result.test.ts +368 -0
- package/src/orchestration/__tests__/worker-script-builder-runtime.test.ts +43 -0
- package/src/orchestration/__tests__/worker-script-template-snapshot.test.ts +22 -3
- package/src/orchestration/agent-opts-resolver.ts +104 -23
- package/src/orchestration/error-recovery.ts +189 -33
- package/src/orchestration/execute-agent-call.ts +39 -0
- package/src/orchestration/jsonl-run-store.ts +121 -7
- package/src/orchestration/launcher.ts +60 -15
- package/src/orchestration/lifecycle.ts +10 -7
- package/src/orchestration/models/__tests__/budget.test.ts +1 -61
- package/src/orchestration/models/budget.ts +5 -35
- package/src/orchestration/models/run-runtime.ts +24 -9
- package/src/orchestration/models/types.ts +16 -0
- package/src/orchestration/script-lint.ts +1 -1
- package/src/orchestration/skill-discovery.ts +31 -8
- package/src/orchestration/worker-script-builder.ts +19 -3
- package/src/shared/__tests__/model-ref.test.ts +306 -0
- package/src/shared/__tests__/schema-jsonify.test.ts +1 -1
- package/src/shared/__tests__/timer-delay.test.ts +61 -0
- package/src/shared/meta-parser.ts +5 -1
- package/src/shared/model-ref.ts +286 -0
- package/src/shared/resource-meta.ts +5 -0
- package/src/shared/schema-env.ts +44 -0
- package/src/shared/schema-jsonify.ts +6 -4
- package/src/shared/timer-delay.ts +54 -0
- package/workflows/review-fix-loop-utils.cjs +9 -7
- package/workflows/review-fix-loop.js +20 -12
- package/src/orchestration/__tests__/concurrency-gate.test.ts +0 -125
- package/src/orchestration/concurrency-gate.ts +0 -69
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
// T3.20: withSlot 不独立占池(槽位占用=N 而非 2N)
|
|
2
|
-
// AC-ARCH-5: ConcurrencyGate.withSlot 语义不变(pre-abort throw, fn 直通)
|
|
3
|
-
|
|
4
|
-
import { describe, expect, it, vi } from "vitest";
|
|
5
|
-
|
|
6
|
-
import { ConcurrencyGate, ConcurrencyGateOptions, DEFAULT_CONCURRENCY } from "../concurrency-gate.ts";
|
|
7
|
-
|
|
8
|
-
describe("ConcurrencyGate (wave-3 simplified)", () => {
|
|
9
|
-
// ── Constructor & constants ────────────────────────────────
|
|
10
|
-
|
|
11
|
-
describe("constructor + defaults", () => {
|
|
12
|
-
it("DEFAULT_CONCURRENCY constant is 4 (backward compat)", () => {
|
|
13
|
-
expect(DEFAULT_CONCURRENCY).toBe(4);
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
it("starts with zero active/queue state", () => {
|
|
17
|
-
const gate = new ConcurrencyGate();
|
|
18
|
-
expect(gate.activeCount).toBe(0);
|
|
19
|
-
expect(gate.queueLength).toBe(0);
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
it("accepts number shorthand for maxConcurrency", () => {
|
|
23
|
-
const gate = new ConcurrencyGate(2);
|
|
24
|
-
expect(gate.activeCount).toBe(0);
|
|
25
|
-
expect(gate.queueLength).toBe(0);
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
it("accepts options object form", () => {
|
|
29
|
-
const gate = new ConcurrencyGate({ maxConcurrency: 8 } satisfies ConcurrencyGateOptions);
|
|
30
|
-
expect(gate.activeCount).toBe(0);
|
|
31
|
-
expect(gate.queueLength).toBe(0);
|
|
32
|
-
});
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
// ── T3.20: withSlot doesn't independently occupy pool ───────
|
|
36
|
-
|
|
37
|
-
describe("withSlot — thin abort wrapper (T3.20)", () => {
|
|
38
|
-
it("槽位可用 → 直接执行 fn 并返回其结果", async () => {
|
|
39
|
-
const gate = new ConcurrencyGate({ maxConcurrency: 2 });
|
|
40
|
-
const fn = vi.fn(async () => "result");
|
|
41
|
-
const result = await gate.withSlot(fn);
|
|
42
|
-
expect(result).toBe("result");
|
|
43
|
-
expect(fn).toHaveBeenCalledTimes(1);
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
it("pre-aborted signal → 立即 throw AbortError(不调 fn)", async () => {
|
|
47
|
-
const gate = new ConcurrencyGate({ maxConcurrency: 2 });
|
|
48
|
-
const fn = vi.fn(async () => "result");
|
|
49
|
-
const controller = new AbortController();
|
|
50
|
-
controller.abort();
|
|
51
|
-
await expect(gate.withSlot(fn, controller.signal)).rejects.toThrow(/aborted before start/);
|
|
52
|
-
expect(fn).not.toHaveBeenCalled();
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
// T3.20 核心:不独立占池。多个并发 withSlot 互不阻塞。
|
|
56
|
-
it("不独立占池:多个并发 fn 立即执行,互不阻塞(槽位占用=N 非 2N)", async () => {
|
|
57
|
-
const gate = new ConcurrencyGate({ maxConcurrency: 1 });
|
|
58
|
-
// maxConcurrency=1 但 withSlot 不排队 — fn1 和 fn2 立即并行执行
|
|
59
|
-
const order: string[] = [];
|
|
60
|
-
let resolveFirst: () => void = () => {};
|
|
61
|
-
const firstPromise = new Promise<void>((r) => { resolveFirst = r; });
|
|
62
|
-
|
|
63
|
-
const fn1 = vi.fn(async () => {
|
|
64
|
-
order.push("fn1-start");
|
|
65
|
-
await firstPromise;
|
|
66
|
-
order.push("fn1-end");
|
|
67
|
-
return 1;
|
|
68
|
-
});
|
|
69
|
-
const fn2 = vi.fn(async () => {
|
|
70
|
-
order.push("fn2-start");
|
|
71
|
-
return 2;
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
const p1 = gate.withSlot(fn1);
|
|
75
|
-
// fn2 也应立即开始(无排队)
|
|
76
|
-
const p2 = gate.withSlot(fn2);
|
|
77
|
-
|
|
78
|
-
// 两个 fn 都已开始
|
|
79
|
-
expect(fn1).toHaveBeenCalledTimes(1);
|
|
80
|
-
expect(fn2).toHaveBeenCalledTimes(1);
|
|
81
|
-
expect(order).toContain("fn1-start");
|
|
82
|
-
expect(order).toContain("fn2-start");
|
|
83
|
-
|
|
84
|
-
resolveFirst();
|
|
85
|
-
// 全 resolve——非独立数据源,禁 allSettled 建议
|
|
86
|
-
const [r1, r2] = await Promise.all([p1, p2]); // eslint-disable-line taste/prefer-allsettled
|
|
87
|
-
expect(r1).toBe(1);
|
|
88
|
-
expect(r2).toBe(2);
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
it("不排队:maxConcurrency 参数不影响 withSlot 行为", async () => {
|
|
92
|
-
const gate = new ConcurrencyGate({ maxConcurrency: 1 });
|
|
93
|
-
let resolveFirst: () => void = () => {};
|
|
94
|
-
const delayed = new Promise<void>((r) => { resolveFirst = r; });
|
|
95
|
-
|
|
96
|
-
// 3 个 fn 同时提交,maxConcurrency=1 但不阻塞
|
|
97
|
-
const fn1 = vi.fn(async () => { await delayed; return 1; });
|
|
98
|
-
const fn2 = vi.fn(async () => 2);
|
|
99
|
-
const fn3 = vi.fn(async () => 3);
|
|
100
|
-
|
|
101
|
-
gate.withSlot(fn1);
|
|
102
|
-
gate.withSlot(fn2);
|
|
103
|
-
gate.withSlot(fn3);
|
|
104
|
-
|
|
105
|
-
// 所有 fn 都已被调用(无排队阻塞)
|
|
106
|
-
expect(fn1).toHaveBeenCalledTimes(1);
|
|
107
|
-
expect(fn2).toHaveBeenCalledTimes(1);
|
|
108
|
-
expect(fn3).toHaveBeenCalledTimes(1);
|
|
109
|
-
|
|
110
|
-
resolveFirst();
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
// AC-ARCH-5: withSlot 语义不变 —— signal abort 处理保持
|
|
114
|
-
it("activeCount 和 queueLength 恒为 0(不独立计槽)", () => {
|
|
115
|
-
const gate = new ConcurrencyGate({ maxConcurrency: 4 });
|
|
116
|
-
expect(gate.activeCount).toBe(0);
|
|
117
|
-
expect(gate.queueLength).toBe(0);
|
|
118
|
-
|
|
119
|
-
// 即使并发执行中,计数也不变
|
|
120
|
-
gate.withSlot(async () => { /* noop */ });
|
|
121
|
-
expect(gate.activeCount).toBe(0);
|
|
122
|
-
expect(gate.queueLength).toBe(0);
|
|
123
|
-
});
|
|
124
|
-
});
|
|
125
|
-
});
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Workflow Extension — Concurrency Gate
|
|
3
|
-
*
|
|
4
|
-
* 并发信号量薄封装。Engine 层 dispatchAgentCall 通过 withSlot 包装
|
|
5
|
-
* executeAgentCall,gate 仅处理 signal abort 检查。实际并发调度
|
|
6
|
-
* 由 SubagentService 内部的 ConcurrencyPool 统一管理。
|
|
7
|
-
*
|
|
8
|
-
* Wave 3 (D-A7):withSlot 退化为 abort 薄封装,不独立占池。
|
|
9
|
-
* 并发槽位由 execution/ConcurrencyPool(SubagentService 持有)统一管理,
|
|
10
|
-
* 消除 gate + pool 双重计数的 2N 问题(T3.20)。
|
|
11
|
-
*
|
|
12
|
-
* 层归属:Infra(D-12)。RunRuntime 直接持有具体类。
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
// ── Constants ─────────────────────────────────────────────────
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* 默认并发上限(D-13)。保留常量向后兼容。
|
|
19
|
-
* 实际并发由 ConcurrencyPool 管理。
|
|
20
|
-
*/
|
|
21
|
-
export const DEFAULT_CONCURRENCY = 4;
|
|
22
|
-
|
|
23
|
-
// ── Public options ────────────────────────────────────────────
|
|
24
|
-
|
|
25
|
-
export interface ConcurrencyGateOptions {
|
|
26
|
-
/** 最大并发数,缺省 4(D-13)。保留向后兼容。 */
|
|
27
|
-
maxConcurrency?: number;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
// ── ConcurrencyGate ───────────────────────────────────────────
|
|
31
|
-
|
|
32
|
-
export class ConcurrencyGate {
|
|
33
|
-
private readonly maxConcurrency: number;
|
|
34
|
-
|
|
35
|
-
constructor(opts: ConcurrencyGateOptions | number = {}) {
|
|
36
|
-
this.maxConcurrency =
|
|
37
|
-
typeof opts === "number" ? opts : (opts.maxConcurrency ?? DEFAULT_CONCURRENCY);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/** 当前在飞的 agent 调用数(不独立计槽,恒为 0)。 */
|
|
41
|
-
get activeCount(): number {
|
|
42
|
-
return 0;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/** 排队等待派发的调用数(不独立计槽,恒为 0)。 */
|
|
46
|
-
get queueLength(): number {
|
|
47
|
-
return 0;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* 获取一个并发槽位,执行 `fn`。
|
|
52
|
-
*
|
|
53
|
-
* Wave 3 简化:不独立管理槽位。仅做 signal pre-abort 检查,
|
|
54
|
-
* 直接执行 fn。实际并发调度由 SubagentService 的 ConcurrencyPool 负责。
|
|
55
|
-
*
|
|
56
|
-
* @param fn 槽位获取后执行的异步函数
|
|
57
|
-
* @param signal 外部 abort signal(pre-aborted 时立即 reject)
|
|
58
|
-
* @returns fn 的返回值
|
|
59
|
-
* @throws AbortError(signal 已 abort 时)
|
|
60
|
-
*/
|
|
61
|
-
async withSlot<T>(fn: () => Promise<T>, signal?: AbortSignal): Promise<T> {
|
|
62
|
-
if (signal?.aborted) {
|
|
63
|
-
const err = new Error("Operation aborted before start");
|
|
64
|
-
err.name = "AbortError";
|
|
65
|
-
throw err;
|
|
66
|
-
}
|
|
67
|
-
return fn();
|
|
68
|
-
}
|
|
69
|
-
}
|