@zhushanwen/subagent-core 0.4.0 → 0.5.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/dist/{chunk-4KN4TTG7.js → chunk-43ONBFZX.js} +1 -1
- package/dist/{chunk-X7SZ5HLQ.js → chunk-V3VHZ2VX.js} +20 -27
- package/dist/execution/engine/engines/zcode/constants.cjs +29 -41
- package/dist/execution/engine/engines/zcode/constants.d.cts +65 -53
- package/dist/execution/engine/engines/zcode/constants.d.ts +65 -53
- package/dist/execution/engine/engines/zcode/constants.js +17 -27
- package/dist/execution/engine/engines/zcode/reader.d.cts +2 -1
- package/dist/execution/engine/engines/zcode/reader.d.ts +2 -1
- package/dist/execution/engine/engines/zcode/reader.js +2 -2
- package/dist/index.cjs +16418 -14070
- package/dist/index.d.cts +5136 -4016
- package/dist/index.d.ts +5136 -4016
- package/dist/index.js +16343 -14048
- package/dist/{types-DpUO16pj.d.cts → types-Dv4QhSJ_.d.cts} +215 -112
- package/dist/{types-DpUO16pj.d.ts → types-Dv4QhSJ_.d.ts} +215 -112
- package/package.json +3 -3
- package/src/__tests__/agent-opts-resolver-schema-prompt.test.ts +0 -1
- package/src/__tests__/append-system-prompt-assembly.test.ts +8 -7
- package/src/__tests__/fr4-get-state-handshake.test.ts +2 -2
- package/src/__tests__/m2-append-content-probe.test.ts +0 -1
- package/src/__tests__/manifest-store.test.ts +10 -9
- package/src/__tests__/record-store-cache.test.ts +0 -2
- package/src/__tests__/record-store-index.test.ts +1 -2
- package/src/__tests__/review-fix-loop-script.test.ts +4 -2
- package/src/__tests__/review-fix-loop-utils.test.ts +10 -10
- package/src/__tests__/robustness-low-batch1.test.ts +6 -5
- package/src/__tests__/robustness-medium-batch1.test.ts +2 -2
- package/src/__tests__/robustness-medium-batch2.test.ts +17 -6
- package/src/__tests__/robustness-medium-batch4.test.ts +2 -2
- package/src/__tests__/session-runner.test.ts +1 -1
- package/src/core/__tests__/host-services.test.ts +2 -2
- package/src/core/__tests__/logger.test.ts +1 -1
- package/src/core/error-message.ts +9 -0
- package/src/core/host-services.ts +21 -5
- package/src/core/notify-ports.ts +18 -5
- package/src/execution/__tests__/agent-profile.test.ts +4 -4
- package/src/execution/__tests__/agent-registry.test.ts +370 -0
- package/src/execution/__tests__/agent-result-mapper.test.ts +18 -2
- package/src/execution/__tests__/agents-assembly.test.ts +2 -2
- package/src/execution/__tests__/ask-user-transit-e2e.test.ts +6 -6
- package/src/execution/__tests__/chat-engine-routing.test.ts +68 -33
- package/src/execution/__tests__/chatmode-first-round-closure-spawn.test.ts +4 -4
- package/src/execution/__tests__/cold-resurrect.test.ts +283 -0
- package/src/execution/__tests__/delivery-methods.test.ts +75 -62
- package/src/execution/__tests__/descendant-sweep-guards.test.ts +220 -0
- package/src/execution/__tests__/descendant-sweep.test.ts +6 -6
- package/src/execution/__tests__/dialog-queue.test.ts +2 -2
- package/src/execution/__tests__/engine-model-validation.test.ts +741 -0
- package/src/execution/__tests__/epipe-fallback.test.ts +29 -24
- package/src/execution/__tests__/execute-and-await-worktree.test.ts +21 -91
- package/src/execution/__tests__/execute-nesting.test.ts +34 -188
- package/src/execution/__tests__/execution-record.test.ts +217 -60
- package/src/execution/__tests__/execution-runtime-face.test.ts +5 -5
- package/src/execution/__tests__/explicit-agent-ref-guard.test.ts +3 -3
- package/src/execution/__tests__/finalize-record.test.ts +173 -17
- package/src/execution/__tests__/gc-timer.test.ts +55 -2
- package/src/execution/__tests__/get-record-for-action-restart.test.ts +12 -12
- package/src/execution/__tests__/get-state-handshake.test.ts +1 -1
- package/src/execution/__tests__/helpers/mock-extension-api.ts +1 -1
- package/src/execution/__tests__/helpers/session-runner-mocks.ts +113 -0
- package/src/execution/__tests__/helpers/spawn-mock.ts +150 -3
- package/src/execution/__tests__/helpers/subagent-service-mocks.ts +137 -0
- package/src/execution/__tests__/keep-alive-no-progress.test.ts +50 -148
- package/src/execution/__tests__/kill-all-escalation.test.ts +2 -2
- package/src/execution/__tests__/lifecycle-predicates.test.ts +1 -2
- package/src/execution/__tests__/manifest-parentid.test.ts +4 -4
- package/src/execution/__tests__/max-turns-to-watchdog-ms.test.ts +1 -1
- package/src/execution/__tests__/model-resolver.test.ts +2 -2
- package/src/execution/__tests__/nested-visibility-env-propagation.test.ts +23 -121
- package/src/execution/__tests__/nested-visibility.test.ts +2 -0
- package/src/execution/__tests__/notify-ledger.test.ts +973 -18
- package/src/execution/__tests__/output-collector.test.ts +117 -6
- package/src/execution/__tests__/pi-invocation.test.ts +1 -1
- package/src/execution/__tests__/record-store.test.ts +10 -9
- package/src/execution/__tests__/records-cwd-isolation.test.ts +2 -2
- package/src/execution/__tests__/recursive-visibility-baseline.test.ts +29 -132
- package/src/execution/__tests__/recursive-visibility-env.test.ts +55 -179
- package/src/execution/__tests__/rpc-mode.test.ts +2 -2
- package/src/execution/__tests__/run-and-finalize-anchoring.test.ts +387 -0
- package/src/execution/__tests__/run-and-finalize-chatmode.test.ts +15 -9
- package/src/execution/__tests__/run-spawn-chatmode-settled.test.ts +4 -4
- package/src/execution/__tests__/run-spawn-edges.test.ts +17 -15
- package/src/execution/__tests__/run-spawn-integration.test.ts +2 -2
- package/src/execution/__tests__/run-spawn-resume.test.ts +2 -2
- package/src/execution/__tests__/run-spawn-rpc-mode.test.ts +2 -2
- package/src/execution/__tests__/run-spawn-stdout-callback-throw.test.ts +4 -4
- package/src/execution/__tests__/service-kill-escalation.test.ts +7 -5
- package/src/execution/__tests__/session-context-resolver.test.ts +0 -2
- package/src/execution/__tests__/session-file-gc.test.ts +35 -0
- package/src/execution/__tests__/session-pending.test.ts +257 -14
- package/src/execution/__tests__/session-reconstructor.test.ts +366 -15
- package/src/execution/__tests__/session-runner-branch-cache-lru.test.ts +1 -1
- package/src/execution/__tests__/session-runner-close-prune.test.ts +2 -2
- package/src/execution/__tests__/session-runner-dispatch.test.ts +489 -0
- package/src/execution/__tests__/session-runner-epipe.test.ts +3 -3
- package/src/execution/__tests__/session-runner-heartbeat-idle-fallback.test.ts +5 -4
- package/src/execution/__tests__/session-runner-lifecycle-helpers.test.ts +290 -0
- package/src/execution/__tests__/session-runner-schema-env.test.ts +7 -5
- package/src/execution/__tests__/settled-watchdog.test.ts +282 -47
- package/src/execution/__tests__/spawn-args.test.ts +11 -10
- package/src/execution/__tests__/spawn-event-adapter-rpc.test.ts +26 -23
- package/src/execution/__tests__/spawn-event-adapter.test.ts +1 -1
- package/src/execution/__tests__/spawn-worktree-guidance.test.ts +5 -4
- package/src/execution/__tests__/spawned-children.test.ts +2 -1
- package/src/execution/__tests__/start-sync-model-guard.test.ts +4 -4
- package/src/execution/__tests__/stdin-writer.test.ts +6 -4
- package/src/execution/__tests__/stream-sink-retirement.test.ts +6 -6
- package/src/execution/__tests__/subagent-actions-core.test.ts +42 -22
- package/src/execution/__tests__/subagent-service-message-close.test.ts +29 -26
- package/src/execution/__tests__/subagent-service-multiproc-guard.test.ts +8 -8
- package/src/execution/__tests__/subagent-service-notify-gate.test.ts +27 -22
- package/src/execution/__tests__/subagent-service-parent-guard.test.ts +30 -29
- package/src/execution/__tests__/subagent-service-recovery-bounds.test.ts +45 -20
- package/src/execution/__tests__/subagent-service.test.ts +37 -30
- package/src/execution/__tests__/subprocess-agent-runner-routing.test.ts +88 -12
- package/src/execution/__tests__/subprocess-agent-runner-timeout.test.ts +75 -0
- package/src/execution/__tests__/subprocess-agent-runner.test.ts +22 -20
- package/src/execution/__tests__/temp-prompt.test.ts +1 -1
- package/src/execution/__tests__/timeout-integration.test.ts +6 -5
- package/src/execution/__tests__/turn-limiter-semantics.test.ts +1 -1
- package/src/execution/__tests__/turn-limiter.test.ts +1 -1
- package/src/execution/__tests__/ui-request-handler-factory.test.ts +12 -6
- package/src/execution/__tests__/ui-request-handler.test.ts +4 -3
- package/src/execution/__tests__/ui-request-queue.test.ts +142 -2
- package/src/execution/__tests__/worktree-manager.test.ts +14 -5
- package/src/execution/__tests__/worktree-pid-registration.integration.test.ts +4 -3
- package/src/execution/agent-registry.ts +74 -30
- package/src/execution/agent-result-mapper.ts +3 -0
- package/src/execution/cold-resurrect.ts +199 -0
- package/src/execution/engine/__tests__/common/capability-gate.test.ts +91 -0
- package/src/execution/engine/__tests__/common/data-dir.test.ts +1 -1
- package/src/execution/engine/__tests__/common/journal-wiring.test.ts +84 -0
- package/src/execution/engine/__tests__/common/kill-chain.test.ts +34 -7
- package/src/execution/engine/__tests__/common/persona-router.test.ts +4 -5
- package/src/execution/engine/__tests__/common/pool-manager.test.ts +211 -51
- package/src/execution/engine/__tests__/common/session-view-service-zcode-dbpath.test.ts +149 -0
- package/src/execution/engine/__tests__/common/session-view-service.test.ts +499 -0
- package/src/execution/engine/__tests__/conformance/contract.abort.test.ts +22 -112
- package/src/execution/engine/__tests__/conformance/contract.agent-events.test.ts +15 -28
- package/src/execution/engine/__tests__/conformance/engine-conformance.live.test.ts +12 -12
- package/src/execution/engine/__tests__/conformance/golden-replay.pi.test.ts +1 -1
- package/src/execution/engine/__tests__/conformance/golden-replay.zcode.test.ts +21 -82
- package/src/execution/engine/__tests__/conformance/zcode-appserver-harness.ts +4 -7
- package/src/execution/engine/__tests__/engine-discovery.test.ts +15 -3
- package/src/execution/engine/__tests__/model-prompt.test.ts +15 -3
- package/src/execution/engine/__tests__/registry.test.ts +4 -2
- package/src/execution/engine/__tests__/routing.test.ts +115 -6
- package/src/execution/engine/common/capability-gate.ts +92 -0
- package/src/execution/engine/common/journal-wiring.ts +97 -0
- package/src/execution/engine/common/kill-chain.ts +42 -10
- package/src/execution/engine/common/nesting-guard.ts +66 -0
- package/src/execution/engine/common/persona-router.ts +18 -8
- package/src/execution/engine/common/pool-manager.ts +332 -78
- package/src/execution/engine/common/session-view-service.ts +506 -0
- package/src/execution/engine/common/session-view-types.ts +125 -0
- package/src/execution/engine/engines/pi/__tests__/pi-engine.test.ts +174 -28
- package/src/execution/engine/engines/pi/__tests__/spawn-opts-direct.test.ts +257 -0
- package/src/execution/{argv-mirror.ts → engine/engines/pi/argv-mirror.ts} +43 -21
- package/src/execution/{get-state-handshake.ts → engine/engines/pi/get-state-handshake.ts} +1 -1
- package/src/execution/{output-collector.ts → engine/engines/pi/output-collector.ts} +108 -19
- package/src/execution/engine/engines/pi/pi-engine.ts +434 -38
- package/src/execution/{pi-invocation.ts → engine/engines/pi/pi-invocation.ts} +2 -2
- package/src/execution/engine/engines/pi/reader.ts +11 -0
- package/src/execution/engine/engines/pi/registration.ts +4 -2
- package/src/execution/{session-runner.ts → engine/engines/pi/session-runner.ts} +617 -412
- package/src/execution/{spawn-event-adapter.ts → engine/engines/pi/spawn-event-adapter.ts} +75 -34
- package/src/execution/{stdin-writer.ts → engine/engines/pi/stdin-writer.ts} +10 -9
- package/src/execution/{temp-prompt.ts → engine/engines/pi/temp-prompt.ts} +2 -2
- package/src/execution/{turn-limiter.ts → engine/engines/pi/turn-limiter.ts} +1 -1
- package/src/execution/engine/engines/zcode/__tests__/__fixtures__/fake-appserver.mjs +54 -27
- package/src/execution/engine/engines/zcode/__tests__/appserver-launcher.test.ts +321 -0
- package/src/execution/engine/engines/zcode/__tests__/connection.test.ts +13 -12
- package/src/execution/engine/engines/zcode/__tests__/parser.test.ts +7 -210
- package/src/execution/engine/engines/zcode/__tests__/preparer.test.ts +6 -110
- package/src/execution/engine/engines/zcode/__tests__/session-channel-dispose-harvest.test.ts +247 -0
- package/src/execution/engine/engines/zcode/__tests__/session-channel-turn-timers.test.ts +451 -0
- package/src/execution/engine/engines/zcode/__tests__/session-channel.test.ts +20 -8
- package/src/execution/engine/engines/zcode/__tests__/zcode-engine-appserver.test.ts +77 -110
- package/src/execution/engine/engines/zcode/__tests__/zcode-engine-degrade.test.ts +25 -319
- package/src/execution/engine/engines/zcode/__tests__/zcode-engine-dispose.test.ts +210 -0
- package/src/execution/engine/engines/zcode/__tests__/zcode-engine-retry.test.ts +353 -0
- package/src/execution/engine/engines/zcode/__tests__/zcode-engine-status.test.ts +282 -0
- package/src/execution/engine/engines/zcode/__tests__/zcode-engine-timeout.test.ts +372 -0
- package/src/execution/engine/engines/zcode/__tests__/zcode-engine.live.test.ts +48 -148
- package/src/execution/engine/engines/zcode/appserver-launcher.ts +167 -0
- package/src/execution/engine/engines/zcode/connection.ts +24 -11
- package/src/execution/engine/engines/zcode/constants.ts +75 -71
- package/src/execution/engine/engines/zcode/golden-sample.ts +8 -46
- package/src/execution/engine/engines/zcode/parser.ts +12 -346
- package/src/execution/engine/engines/zcode/preparer.ts +12 -143
- package/src/execution/engine/engines/zcode/session-channel.ts +351 -39
- package/src/execution/engine/engines/zcode/zcode-engine.ts +665 -760
- package/src/execution/engine/host-task-spec.ts +32 -36
- package/src/execution/engine/model-validation.ts +177 -0
- package/src/execution/engine/port.ts +24 -6
- package/src/execution/engine/routing.ts +75 -1
- package/src/execution/engine/types.ts +30 -103
- package/src/execution/execution-record.ts +222 -144
- package/src/execution/finalize-record.ts +131 -93
- package/src/execution/idle-gc.ts +28 -0
- package/src/execution/lifecycle-predicates.ts +1 -1
- package/src/execution/notify-host.ts +212 -0
- package/src/execution/record-store.ts +119 -73
- package/src/execution/round-settlement.ts +93 -0
- package/src/execution/session-file-gc.ts +96 -62
- package/src/execution/session-reconstructor.ts +256 -143
- package/src/execution/sessions-index.ts +117 -47
- package/src/execution/settled-watchdog.ts +264 -52
- package/src/execution/subagent-actions-core.ts +22 -22
- package/src/execution/subagent-service.ts +815 -963
- package/src/execution/subprocess-agent-runner.ts +144 -97
- package/src/execution/types.ts +9 -0
- package/src/execution/ui-request-handler-factory.ts +102 -74
- package/src/execution/ui-request-queue.ts +50 -19
- package/src/index.ts +442 -316
- package/src/orchestration/__tests__/agent-call-catch-fallback.test.ts +1 -1
- package/src/orchestration/__tests__/agent-call-stream.test.ts +2 -2
- package/src/orchestration/__tests__/args-validator.test.ts +14 -0
- package/src/orchestration/__tests__/error-recovery-rebuild-failure.test.ts +1 -1
- package/src/orchestration/__tests__/error-recovery-terminal-hardening.test.ts +11 -9
- package/src/orchestration/__tests__/execute-agent-call.test.ts +151 -11
- package/src/orchestration/__tests__/file-run-store.test.ts +7 -6
- package/src/orchestration/__tests__/launcher-nested-workflow.test.ts +2 -2
- package/src/orchestration/__tests__/lifecycle-abort-broadcast-signal.test.ts +1 -1
- package/src/orchestration/__tests__/lifecycle-runid-injection.test.ts +3 -3
- package/src/orchestration/__tests__/lifecycle.test.ts +7 -5
- package/src/orchestration/__tests__/non-cloneable-return-e2e.test.ts +1 -1
- package/src/orchestration/__tests__/run-snapshot.test.ts +8 -5
- package/src/orchestration/__tests__/script-lint.test.ts +17 -0
- package/src/orchestration/__tests__/test-mocks.ts +2 -0
- package/src/orchestration/__tests__/worker-exit-without-result.test.ts +7 -6
- package/src/orchestration/__tests__/worker-message-pump-finalize-run.test.ts +229 -0
- package/src/orchestration/__tests__/{error-recovery-handlers.test.ts → worker-message-pump-handlers.test.ts} +27 -19
- package/src/orchestration/__tests__/{error-recovery-postmessage-defense.test.ts → worker-message-pump-postmessage-defense.test.ts} +8 -8
- package/src/orchestration/__tests__/{error-recovery-serialize-failed-result.test.ts → worker-message-pump-serialize-failed-result.test.ts} +2 -2
- package/src/orchestration/__tests__/{error-recovery-workflow-call.test.ts → worker-message-pump-workflow-call.test.ts} +1 -1
- package/src/orchestration/__tests__/worker-pending-timeout-abort.test.ts +1 -1
- package/src/orchestration/__tests__/worker-script-builder.test.ts +1 -1
- package/src/orchestration/__tests__/workflow-nesting-e2e.test.ts +1 -1
- package/src/orchestration/agent-opts-resolver.ts +1 -1
- package/src/orchestration/args-validator.ts +53 -31
- package/src/orchestration/execute-agent-call.ts +19 -73
- package/src/orchestration/launcher.ts +128 -81
- package/src/orchestration/lifecycle.ts +43 -45
- package/src/orchestration/models/ports.ts +4 -4
- package/src/orchestration/models/run-runtime.ts +2 -2
- package/src/orchestration/models/trace.ts +1 -1
- package/src/orchestration/models/types.ts +111 -22
- package/src/orchestration/models/workflow-run.ts +1 -1
- package/src/orchestration/script-lint.ts +91 -58
- package/src/orchestration/{error-recovery.ts → worker-message-pump.ts} +157 -150
- package/src/shared/__tests__/meta-parser.test.ts +151 -0
- package/src/shared/__tests__/resource-discovery.test.ts +258 -215
- package/src/shared/atomic-write.ts +12 -9
- package/src/shared/meta-parser.ts +158 -84
- package/src/shared/model-ref.ts +15 -2
- package/src/shared/resource-discovery.ts +9 -183
- package/src/shared/schema-jsonify.ts +1 -1
- package/workflows/review-fix-loop-utils.cjs +151 -89
- package/workflows/review-fix-loop-utils.d.cts +287 -0
- package/src/execution/__tests__/execute-options-mapper.test.ts +0 -200
- package/src/execution/engine/engines/pi/__tests__/task-spec-mapper.test.ts +0 -164
- package/src/execution/engine/engines/pi/task-spec-mapper.ts +0 -100
- package/src/execution/engine/engines/zcode/__tests__/__fixtures__/zcode-golden-spawn.json +0 -39
- package/src/execution/engine/engines/zcode/__tests__/launcher.test.ts +0 -150
- package/src/execution/engine/engines/zcode/__tests__/preparer-appserver.test.ts +0 -387
- package/src/execution/engine/engines/zcode/__tests__/zcode-engine.test.ts +0 -710
- package/src/execution/engine/engines/zcode/appserver-home.ts +0 -442
- package/src/execution/engine/engines/zcode/appserver-probe.ts +0 -141
- package/src/execution/engine/engines/zcode/launcher.ts +0 -161
- package/src/execution/execute-options-mapper.ts +0 -115
- package/src/shared/__tests__/resource-discovery-manifest-cache.test.ts +0 -288
|
@@ -1,200 +0,0 @@
|
|
|
1
|
-
// src/execution/__tests__/execute-options-mapper.test.ts
|
|
2
|
-
//
|
|
3
|
-
// T3.4 (边界): cwd 透传(非 git worktree)
|
|
4
|
-
// T3.5 (边界): model 填底——opts.model 空 → ctxModel(D-008)
|
|
5
|
-
// T3.9 (边界): schemaEnv 透传——opts.schemaEnv → ExecuteOptions.schemaEnv
|
|
6
|
-
// T3.6 (异常): timeoutMs 超时 → 合并 signal abort → T3.17 listener 清理
|
|
7
|
-
//
|
|
8
|
-
// 测试范围: mapToExecuteOptions 全字段映射 + mergeTimeoutSignal 行为
|
|
9
|
-
|
|
10
|
-
import { describe, expect, it, vi } from "vitest";
|
|
11
|
-
|
|
12
|
-
import type { AgentCallOpts } from "../../orchestration/models/types.ts";
|
|
13
|
-
import { mapToExecuteOptions, mergeTimeoutSignal } from "../execute-options-mapper.ts";
|
|
14
|
-
import type { ModelInfo } from "../model-resolver.ts";
|
|
15
|
-
|
|
16
|
-
describe("mapToExecuteOptions (D-A2)", () => {
|
|
17
|
-
const baseOpts: AgentCallOpts = {
|
|
18
|
-
prompt: "test task",
|
|
19
|
-
agent: "worker",
|
|
20
|
-
schema: { type: "object" },
|
|
21
|
-
cwd: "/tmp/work",
|
|
22
|
-
skillPath: "/path/to/skill.md",
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
it("T3.10 slug 截断: description > SLUG_MAX_LENGTH(35) → 截断到 35", () => {
|
|
26
|
-
const opts: AgentCallOpts = { ...baseOpts, description: "a".repeat(36) };
|
|
27
|
-
const result = mapToExecuteOptions(opts);
|
|
28
|
-
expect(result.slug).toHaveLength(35);
|
|
29
|
-
expect(result.slug).toBe("a".repeat(35));
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
it("T3.10 slug 边界: description = 35 → 不截断", () => {
|
|
33
|
-
const opts: AgentCallOpts = { ...baseOpts, description: "a".repeat(35) };
|
|
34
|
-
const result = mapToExecuteOptions(opts);
|
|
35
|
-
expect(result.slug).toHaveLength(35);
|
|
36
|
-
expect(result.slug).toBe("a".repeat(35));
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
it("T3.10 slug 回落: 无 description → agentName", () => {
|
|
40
|
-
const result = mapToExecuteOptions(baseOpts);
|
|
41
|
-
expect(result.slug).toBe("worker");
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
it("T3.4 基本映射: prompt→task, agent→agent, cwd→cwd", () => {
|
|
45
|
-
const result = mapToExecuteOptions(baseOpts);
|
|
46
|
-
expect(result.task).toBe("test task");
|
|
47
|
-
expect(result.agent).toBe("worker");
|
|
48
|
-
expect(result.cwd).toBe("/tmp/work");
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
it("T3.4 schema 透传", () => {
|
|
52
|
-
const result = mapToExecuteOptions(baseOpts);
|
|
53
|
-
expect(result.schema).toEqual({ type: "object" });
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
it("T3.9 schemaEnv 透传 (D-A6 bridge)", () => {
|
|
57
|
-
const opts: AgentCallOpts = { ...baseOpts, schemaEnv: '{"type":"object"}' };
|
|
58
|
-
const result = mapToExecuteOptions(opts);
|
|
59
|
-
expect(result.schemaEnv).toBe('{"type":"object"}');
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
it("T3.9 schemaEnv 不传 → schemaEnv undefined", () => {
|
|
63
|
-
const result = mapToExecuteOptions(baseOpts);
|
|
64
|
-
expect(result.schemaEnv).toBeUndefined();
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
it("T3.5 model: opts.model 优先(显式 override 透传,不与 ctxModel 混合)", () => {
|
|
68
|
-
const opts: AgentCallOpts = { ...baseOpts, model: "explicit-model" };
|
|
69
|
-
const ctxModel: ModelInfo = { id: "ctx-model", provider: "test", input: [] } as ModelInfo;
|
|
70
|
-
const result = mapToExecuteOptions(opts, ctxModel);
|
|
71
|
-
expect(result.model).toBe("explicit-model");
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
it("T3.5 model: opts.model 空 → model undefined(不再从 ctxModel.id 填底)", () => {
|
|
75
|
-
const ctxModel: ModelInfo = { id: "ctx-model", provider: "test", input: [] } as ModelInfo;
|
|
76
|
-
const result = mapToExecuteOptions(baseOpts, ctxModel);
|
|
77
|
-
expect(result.model).toBeUndefined();
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
it("T3.5 ctxModel 透传: opts.model 空时 ctxModel 作为完整 ModelInfo 对象传入 ExecuteOptions.ctxModel", () => {
|
|
81
|
-
const ctxModel: ModelInfo = { id: "mimo-v2.5-pro", provider: "router-openai", input: [] } as ModelInfo;
|
|
82
|
-
const result = mapToExecuteOptions(baseOpts, ctxModel);
|
|
83
|
-
expect(result.ctxModel).toBe(ctxModel);
|
|
84
|
-
expect(result.ctxModel?.id).toBe("mimo-v2.5-pro");
|
|
85
|
-
expect(result.ctxModel?.provider).toBe("router-openai");
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
it("T3.5 ctxModel 透传: opts.model 有值时 ctxModel 仍透传(双层可用)", () => {
|
|
89
|
-
const opts: AgentCallOpts = { ...baseOpts, model: "explicit-model" };
|
|
90
|
-
const ctxModel: ModelInfo = { id: "ctx-model", provider: "test", input: [] } as ModelInfo;
|
|
91
|
-
const result = mapToExecuteOptions(opts, ctxModel);
|
|
92
|
-
expect(result.model).toBe("explicit-model");
|
|
93
|
-
expect(result.ctxModel).toBe(ctxModel);
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
it("T3.5 ctxModel: 两层均空 → model/ctxModel 都 undefined", () => {
|
|
97
|
-
const result = mapToExecuteOptions(baseOpts);
|
|
98
|
-
expect(result.model).toBeUndefined();
|
|
99
|
-
expect(result.ctxModel).toBeUndefined();
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
it("skillPath 透传", () => {
|
|
103
|
-
const result = mapToExecuteOptions(baseOpts);
|
|
104
|
-
expect(result.skillPath).toBe("/path/to/skill.md");
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
it("thinkingLevel 透传 (M1)", () => {
|
|
108
|
-
const opts: AgentCallOpts = { ...baseOpts, thinkingLevel: "high" };
|
|
109
|
-
const result = mapToExecuteOptions(opts);
|
|
110
|
-
expect(result.thinkingLevel).toBe("high");
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
it("thinkingLevel 不传 → thinkingLevel undefined", () => {
|
|
114
|
-
const result = mapToExecuteOptions(baseOpts);
|
|
115
|
-
expect(result.thinkingLevel).toBeUndefined();
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
it("appendSystemPrompt → appendSystemPrompt 透传", () => {
|
|
119
|
-
const opts: AgentCallOpts = { ...baseOpts, appendSystemPrompt: ["SO instruction content"] };
|
|
120
|
-
const result = mapToExecuteOptions(opts);
|
|
121
|
-
expect(result.appendSystemPrompt).toEqual(["SO instruction content"]);
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
it("appendSystemPrompt 不传 → appendSystemPrompt undefined", () => {
|
|
125
|
-
const result = mapToExecuteOptions(baseOpts);
|
|
126
|
-
expect(result.appendSystemPrompt).toBeUndefined();
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
it("maxTurns 透传(预算语义对齐:workflow agent() 可显式传 turn 上限)", () => {
|
|
130
|
-
const opts: AgentCallOpts = { ...baseOpts, maxTurns: 20 };
|
|
131
|
-
const result = mapToExecuteOptions(opts);
|
|
132
|
-
expect(result.maxTurns).toBe(20);
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
it("maxTurns 不传 → undefined(不限 turn,不挂 turns 估算 watchdog)", () => {
|
|
136
|
-
const result = mapToExecuteOptions(baseOpts);
|
|
137
|
-
expect(result.maxTurns).toBeUndefined();
|
|
138
|
-
});
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
describe("mergeTimeoutSignal (D-A9)", () => {
|
|
142
|
-
it("T3.6 timeoutMs===undefined → 原样返回 external signal", () => {
|
|
143
|
-
const ctrl = new AbortController();
|
|
144
|
-
const result = mergeTimeoutSignal(ctrl.signal, undefined);
|
|
145
|
-
expect(result).toBe(ctrl.signal);
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
it("T3.6 timeoutMs<=0 → 原样返回 external signal", () => {
|
|
149
|
-
const ctrl = new AbortController();
|
|
150
|
-
const result = mergeTimeoutSignal(ctrl.signal, 0);
|
|
151
|
-
expect(result).toBe(ctrl.signal);
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
it("T3.6 timeoutMs>0 → 返回新 signal(合并外部+超时两路)", () => {
|
|
155
|
-
const ctrl = new AbortController();
|
|
156
|
-
const result = mergeTimeoutSignal(ctrl.signal, 50);
|
|
157
|
-
expect(result).not.toBe(ctrl.signal);
|
|
158
|
-
expect(result.aborted).toBe(false);
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
it("T3.6 timeoutMs 到期 → merged signal abort", async () => {
|
|
162
|
-
vi.useFakeTimers();
|
|
163
|
-
const ctrl = new AbortController();
|
|
164
|
-
const merged = mergeTimeoutSignal(ctrl.signal, 50);
|
|
165
|
-
|
|
166
|
-
expect(merged.aborted).toBe(false);
|
|
167
|
-
vi.advanceTimersByTime(51);
|
|
168
|
-
expect(merged.aborted).toBe(true);
|
|
169
|
-
vi.useRealTimers();
|
|
170
|
-
});
|
|
171
|
-
|
|
172
|
-
it("T3.6 外部 signal abort → merged signal abort", () => {
|
|
173
|
-
const ctrl = new AbortController();
|
|
174
|
-
const merged = mergeTimeoutSignal(ctrl.signal, 5000);
|
|
175
|
-
ctrl.abort();
|
|
176
|
-
expect(merged.aborted).toBe(true);
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
it("T3.6 外部 signal 已 abort → 返回已 abort 的 signal", () => {
|
|
180
|
-
const ctrl = new AbortController();
|
|
181
|
-
ctrl.abort();
|
|
182
|
-
const merged = mergeTimeoutSignal(ctrl.signal, 5000);
|
|
183
|
-
expect(merged.aborted).toBe(true);
|
|
184
|
-
});
|
|
185
|
-
|
|
186
|
-
it("T3.17 NFR: merged signal abort → timeout timer 清理", () => {
|
|
187
|
-
vi.useFakeTimers();
|
|
188
|
-
const ctrl = new AbortController();
|
|
189
|
-
const merged = mergeTimeoutSignal(ctrl.signal, 50);
|
|
190
|
-
|
|
191
|
-
ctrl.abort(); // 外部 abort → merged 也 abort
|
|
192
|
-
expect(merged.aborted).toBe(true);
|
|
193
|
-
|
|
194
|
-
// 推进时间,不应再有副作用
|
|
195
|
-
vi.advanceTimersByTime(100);
|
|
196
|
-
// timer 应被清理(通过 abort event listener)
|
|
197
|
-
// 无异常 = timer 已正确清理
|
|
198
|
-
vi.useRealTimers();
|
|
199
|
-
});
|
|
200
|
-
});
|
|
@@ -1,164 +0,0 @@
|
|
|
1
|
-
// src/execution/engine/engines/pi/__tests__/task-spec-mapper.test.ts
|
|
2
|
-
//
|
|
3
|
-
// AgentTaskSpec ↔ ExecuteOptions 映射测试(P1 验收 3:往返保真)。
|
|
4
|
-
// 覆盖:effort/thinkingLevel 双向映射、persona/skillPath 归并还原、
|
|
5
|
-
// conversation/idleTimeoutMs 透传、schemaEnv 派生逐字节等值(D-A6 bridge)、
|
|
6
|
-
// 运行期字段(signal/ctxModel/onComplete)不入任务声明。
|
|
7
|
-
|
|
8
|
-
import { describe, expect, it } from "vitest";
|
|
9
|
-
|
|
10
|
-
import type { ExecuteOptions } from "../../../../types.ts";
|
|
11
|
-
import type { AgentTaskSpec } from "../../../types.ts";
|
|
12
|
-
import { executeOptionsToTaskSpec, taskSpecToExecuteOptions } from "../task-spec-mapper.ts";
|
|
13
|
-
|
|
14
|
-
describe("task-spec-mapper(ExecuteOptions ↔ AgentTaskSpec 往返保真)", () => {
|
|
15
|
-
/** 全字段样例(含全部泛化点)。 */
|
|
16
|
-
function makeFullOpts(): ExecuteOptions {
|
|
17
|
-
return {
|
|
18
|
-
task: "review the diff",
|
|
19
|
-
slug: "review-diff",
|
|
20
|
-
agent: "/agents/reviewer.md",
|
|
21
|
-
model: "zai-coding-cn/glm-5.2",
|
|
22
|
-
thinkingLevel: "high",
|
|
23
|
-
skillPath: "/skills/code-review/SKILL.md",
|
|
24
|
-
appendSystemPrompt: ["extra system prompt line"],
|
|
25
|
-
schema: { type: "object", properties: { verdict: { type: "string" } }, required: ["verdict"] },
|
|
26
|
-
maxTurns: 20,
|
|
27
|
-
graceTurns: 3,
|
|
28
|
-
fork: true,
|
|
29
|
-
worktree: true,
|
|
30
|
-
cwd: "/repo/worktree-x",
|
|
31
|
-
conversation: true,
|
|
32
|
-
idleTimeoutMs: 600_000,
|
|
33
|
-
};
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
it("全字段往返恒等(P1 行为零变化的映射层证据)", () => {
|
|
37
|
-
const opts = makeFullOpts();
|
|
38
|
-
const round = taskSpecToExecuteOptions(executeOptionsToTaskSpec(opts));
|
|
39
|
-
// schemaEnv 是派生字段(派生正确性单独断言),其余逐字段恒等
|
|
40
|
-
const { schemaEnv, ...rest } = round;
|
|
41
|
-
expect(rest).toEqual(opts);
|
|
42
|
-
expect(schemaEnv).toBe(JSON.stringify(opts.schema));
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
it("effort ↔ thinkingLevel 双向映射(pi 恒等透传,含 7 档外的缺省)", () => {
|
|
46
|
-
for (const level of ["off", "low", "medium", "high", "max", undefined]) {
|
|
47
|
-
const opts: ExecuteOptions = { task: "t", slug: "s", thinkingLevel: level };
|
|
48
|
-
const spec = executeOptionsToTaskSpec(opts);
|
|
49
|
-
expect(spec.effort).toBe(level);
|
|
50
|
-
expect(taskSpecToExecuteOptions(spec).thinkingLevel).toBe(level);
|
|
51
|
-
}
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
it("persona 归并:skillPath + appendSystemPrompt 收拢进 persona", () => {
|
|
55
|
-
const spec = executeOptionsToTaskSpec({
|
|
56
|
-
task: "t",
|
|
57
|
-
slug: "s",
|
|
58
|
-
skillPath: "/skills/x/SKILL.md",
|
|
59
|
-
appendSystemPrompt: ["line1", "line2"],
|
|
60
|
-
});
|
|
61
|
-
expect(spec.persona).toEqual({ skillPath: "/skills/x/SKILL.md", appendSystemPrompt: ["line1", "line2"] });
|
|
62
|
-
// 还原
|
|
63
|
-
const back = taskSpecToExecuteOptions(spec);
|
|
64
|
-
expect(back.skillPath).toBe("/skills/x/SKILL.md");
|
|
65
|
-
expect(back.appendSystemPrompt).toEqual(["line1", "line2"]);
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
it("persona 缺省:无 skillPath/appendSystemPrompt 时 persona 不存在(无空对象噪声)", () => {
|
|
69
|
-
const spec = executeOptionsToTaskSpec({ task: "t", slug: "s" });
|
|
70
|
-
expect(spec.persona).toBeUndefined();
|
|
71
|
-
expect(taskSpecToExecuteOptions(spec).skillPath).toBeUndefined();
|
|
72
|
-
expect(taskSpecToExecuteOptions(spec).appendSystemPrompt).toBeUndefined();
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
it("persona 单字段归并:仅 skillPath(appendSystemPrompt 保持 undefined)", () => {
|
|
76
|
-
const spec = executeOptionsToTaskSpec({ task: "t", slug: "s", skillPath: "/s" });
|
|
77
|
-
expect(spec.persona).toEqual({ skillPath: "/s" });
|
|
78
|
-
const back = taskSpecToExecuteOptions(spec);
|
|
79
|
-
expect(back.skillPath).toBe("/s");
|
|
80
|
-
expect(back.appendSystemPrompt).toBeUndefined();
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
it("conversation / idleTimeoutMs 原名透传(interact 控制面的 task 标志)", () => {
|
|
84
|
-
const opts: ExecuteOptions = { task: "t", slug: "s", conversation: true, idleTimeoutMs: 12345 };
|
|
85
|
-
const spec = executeOptionsToTaskSpec(opts);
|
|
86
|
-
expect(spec.conversation).toBe(true);
|
|
87
|
-
expect(spec.idleTimeoutMs).toBe(12345);
|
|
88
|
-
const back = taskSpecToExecuteOptions(spec);
|
|
89
|
-
expect(back.conversation).toBe(true);
|
|
90
|
-
expect(back.idleTimeoutMs).toBe(12345);
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
it("schemaEnv 派生:与 agent-opts-resolver 同函数(stringifySchemaCached compact),逐字节等值", () => {
|
|
94
|
-
const schema = { type: "object", properties: { a: { type: "number" } } };
|
|
95
|
-
const spec = executeOptionsToTaskSpec({ task: "t", slug: "s", schema });
|
|
96
|
-
// 无 schema 时 schemaEnv 不设(BC-6:childEnv 不注入)
|
|
97
|
-
expect(taskSpecToExecuteOptions({ task: "t", slug: "s" }).schemaEnv).toBeUndefined();
|
|
98
|
-
// 有 schema 时派生 = JSON.stringify(schema)(resolver 的 compact 形态)
|
|
99
|
-
expect(taskSpecToExecuteOptions(spec).schemaEnv).toBe(JSON.stringify(schema));
|
|
100
|
-
// 原 schemaEnv(resolver 产物)经往返后逐字节保持
|
|
101
|
-
const optsWithEnv: ExecuteOptions = {
|
|
102
|
-
task: "t",
|
|
103
|
-
slug: "s",
|
|
104
|
-
schema,
|
|
105
|
-
schemaEnv: JSON.stringify(schema),
|
|
106
|
-
};
|
|
107
|
-
const round = taskSpecToExecuteOptions(executeOptionsToTaskSpec(optsWithEnv));
|
|
108
|
-
expect(round.schemaEnv).toBe(optsWithEnv.schemaEnv);
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
it("解耦形态(有 schemaEnv 无 schema,生产不可达):经 RunContext 兜底透传,派生优先", () => {
|
|
112
|
-
const spec = executeOptionsToTaskSpec({ task: "t", slug: "s", schemaEnv: '{"type":"object"}' });
|
|
113
|
-
// 声明侧无 schema(schemaEnv 不入任务声明,§3.3.5 删字段去向)
|
|
114
|
-
expect(spec.schema).toBeUndefined();
|
|
115
|
-
// 兜底通道(RunContext.schemaEnv → mapper schemaEnvFallback)
|
|
116
|
-
const back = taskSpecToExecuteOptions(spec, { schemaEnvFallback: '{"type":"object"}' });
|
|
117
|
-
expect(back.schemaEnv).toBe('{"type":"object"}');
|
|
118
|
-
// 派生优先:schema 存在时 fallback 被忽略(派生值 = JSON.stringify(schema))
|
|
119
|
-
const coupled = { ...spec, schema: { type: "object" } };
|
|
120
|
-
expect(taskSpecToExecuteOptions(coupled, { schemaEnvFallback: "STALE" }).schemaEnv).toBe('{"type":"object"}');
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
it("运行期字段不入任务声明:signal/ctxModel/onComplete 从 ExecuteOptions 剥离(移入 RunContext)", () => {
|
|
124
|
-
const ctxModel = { id: "m", name: "Test Model", provider: "p", reasoning: false };
|
|
125
|
-
const opts: ExecuteOptions = {
|
|
126
|
-
task: "t",
|
|
127
|
-
slug: "s",
|
|
128
|
-
ctxModel,
|
|
129
|
-
onComplete: () => {},
|
|
130
|
-
};
|
|
131
|
-
const spec = executeOptionsToTaskSpec(opts);
|
|
132
|
-
expect("ctxModel" in spec).toBe(false);
|
|
133
|
-
expect("onComplete" in spec).toBe(false);
|
|
134
|
-
expect("signal" in spec).toBe(false);
|
|
135
|
-
// ctxModel 从 RunContext 回填(SAR 接线的 D-008 兼底链路)
|
|
136
|
-
expect(taskSpecToExecuteOptions(spec, { ctxModel }).ctxModel).toBe(ctxModel);
|
|
137
|
-
expect(taskSpecToExecuteOptions(spec).ctxModel).toBeUndefined();
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
it("中立新字段 denyTools/permissionMode:pi 侧映射回 ExecuteOptions 时忽略(无对应面)", () => {
|
|
141
|
-
const spec: AgentTaskSpec = { task: "t", slug: "s", denyTools: ["bash"], permissionMode: "yolo" };
|
|
142
|
-
const opts = taskSpecToExecuteOptions(spec);
|
|
143
|
-
expect("denyTools" in opts).toBe(false);
|
|
144
|
-
expect("permissionMode" in opts).toBe(false);
|
|
145
|
-
// 声明侧字段保真(不因 pi 不支持而丢弃——P2 公共层消费)
|
|
146
|
-
expect(spec.denyTools).toEqual(["bash"]);
|
|
147
|
-
expect(spec.permissionMode).toBe("yolo");
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
it("归一化:appendSystemPrompt: [] 与 undefined 往返后等价(下游 spread 空数组为 no-op)", () => {
|
|
151
|
-
const spec = executeOptionsToTaskSpec({ task: "t", slug: "s", appendSystemPrompt: [] });
|
|
152
|
-
expect(spec.persona).toEqual({ appendSystemPrompt: [] });
|
|
153
|
-
const back = taskSpecToExecuteOptions(spec);
|
|
154
|
-
expect(back.appendSystemPrompt).toEqual([]);
|
|
155
|
-
});
|
|
156
|
-
|
|
157
|
-
it("worktree 三态(true/false/handle)往返保持", () => {
|
|
158
|
-
const handle = { path: "/wt", branch: "b", baseCommit: "c", mainCwd: "/repo" };
|
|
159
|
-
for (const wt of [true, false, handle] as const) {
|
|
160
|
-
const opts: ExecuteOptions = { task: "t", slug: "s", worktree: wt };
|
|
161
|
-
expect(taskSpecToExecuteOptions(executeOptionsToTaskSpec(opts)).worktree).toBe(wt);
|
|
162
|
-
}
|
|
163
|
-
});
|
|
164
|
-
});
|
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
// src/execution/engine/engines/pi/task-spec-mapper.ts
|
|
2
|
-
//
|
|
3
|
-
// AgentTaskSpec ↔ ExecuteOptions 映射(P1 回填)。pi 专有语义的隔离点(设计 §3.3.5
|
|
4
|
-
// 删字段去向 + P1 行「ExecuteOptions→AgentTaskSpec 映射层」):
|
|
5
|
-
// - effort ↔ thinkingLevel:pi 的 7 档枚举是引擎私有语义,中立层只透传字符串——
|
|
6
|
-
// pi 侧恒等映射(不识别的档位与现状一致:交 resolveModel 层处理);
|
|
7
|
-
// - persona ↔ skillPath + appendSystemPrompt:skillPath 并入 persona 语义(D2),
|
|
8
|
-
// pi 侧原样还原(pi 的 persona 注入通道 = --skill/--append-system-prompt flag);
|
|
9
|
-
// - schemaEnv 内化:中立层无此字段,PiEngine 从 task.schema 派生(stringifySchemaCached
|
|
10
|
-
// compact——与 agent-opts-resolver 同一函数同一缓存,逐字节等值,D-A6 bridge 保真);
|
|
11
|
-
// - conversation/idleTimeoutMs:interact 控制面的 task 标志,原名透传。
|
|
12
|
-
//
|
|
13
|
-
// 往返保真(验收 A1 的映射层证据):executeOptionsToTaskSpec ∘ taskSpecToExecuteOptions
|
|
14
|
-
// 对全部 ExecuteOptions 字段恒等(schemaEnv 由 schema 派生后逐字节等于原值——resolver
|
|
15
|
-
// 与本 mapper 共用 WeakMap 缓存的同一 compact 串)。唯一归一化:appendSystemPrompt: []
|
|
16
|
-
// 归一为 persona 缺省(下游 spread 空数组与 undefined 均为 no-op,行为等价)。
|
|
17
|
-
|
|
18
|
-
import type { ModelInfo } from "../../../model-resolver.ts";
|
|
19
|
-
import type { ExecuteOptions } from "../../../types.ts";
|
|
20
|
-
import { stringifySchemaCached } from "../../../../shared/schema-jsonify.ts";
|
|
21
|
-
import type { AgentTaskSpec, PersonaSpec } from "../../types.ts";
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* ExecuteOptions → AgentTaskSpec(宿主侧声明 → 引擎中立声明)。
|
|
25
|
-
* 纯函数、无副作用——同一 opts 可重复转换(幂等)。
|
|
26
|
-
*/
|
|
27
|
-
export function executeOptionsToTaskSpec(opts: ExecuteOptions): AgentTaskSpec {
|
|
28
|
-
// persona 归并:skillPath / appendSystemPrompt 有其一即建 persona,避免空对象噪声。
|
|
29
|
-
const persona: PersonaSpec | undefined =
|
|
30
|
-
opts.skillPath !== undefined || opts.appendSystemPrompt !== undefined
|
|
31
|
-
? {
|
|
32
|
-
...(opts.skillPath !== undefined ? { skillPath: opts.skillPath } : {}),
|
|
33
|
-
...(opts.appendSystemPrompt !== undefined ? { appendSystemPrompt: opts.appendSystemPrompt } : {}),
|
|
34
|
-
}
|
|
35
|
-
: undefined;
|
|
36
|
-
return {
|
|
37
|
-
task: opts.task,
|
|
38
|
-
slug: opts.slug,
|
|
39
|
-
agent: opts.agent,
|
|
40
|
-
model: opts.model,
|
|
41
|
-
// pi 7 档枚举 → 引擎无关 effort(恒等:档位集合是 pi 私有语义,中立层透传)
|
|
42
|
-
effort: opts.thinkingLevel,
|
|
43
|
-
...(persona !== undefined ? { persona } : {}),
|
|
44
|
-
schema: opts.schema,
|
|
45
|
-
maxTurns: opts.maxTurns,
|
|
46
|
-
graceTurns: opts.graceTurns,
|
|
47
|
-
fork: opts.fork,
|
|
48
|
-
worktree: opts.worktree,
|
|
49
|
-
cwd: opts.cwd,
|
|
50
|
-
conversation: opts.conversation,
|
|
51
|
-
idleTimeoutMs: opts.idleTimeoutMs,
|
|
52
|
-
// ExecuteOptions 不携带的运行期字段(signal/ctxModel/onComplete)归 RunContext;
|
|
53
|
-
// schemaEnv 由 taskSpecToExecuteOptions 从 schema 派生。
|
|
54
|
-
};
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* AgentTaskSpec → ExecuteOptions(pi 引擎侧还原)。
|
|
59
|
-
*
|
|
60
|
-
* @param spec 中立任务声明
|
|
61
|
-
* @param runCtx 运行期上下文:ctxModel 是 ExecuteOptions 的运行期字段(从 RunContext
|
|
62
|
-
* 回填);schemaEnvFallback 是解耦形态(有 schemaEnv 无 schema,生产
|
|
63
|
-
* 不可达)的兜底透传——schema 可派生时派生优先(逐字节等值)
|
|
64
|
-
*/
|
|
65
|
-
export function taskSpecToExecuteOptions(
|
|
66
|
-
spec: AgentTaskSpec,
|
|
67
|
-
runCtx?: { ctxModel?: ModelInfo; schemaEnvFallback?: string },
|
|
68
|
-
): ExecuteOptions {
|
|
69
|
-
return {
|
|
70
|
-
task: spec.task,
|
|
71
|
-
slug: spec.slug,
|
|
72
|
-
// 身份解析键:spec.agent 优先;persona.agentRef 是 persona 注入通道的定位符,
|
|
73
|
-
// 仅在 spec.agent 缺失时兜底(flag/file 通道引擎的主路径;pi 恒走 spec.agent)
|
|
74
|
-
agent: spec.agent ?? spec.persona?.agentRef,
|
|
75
|
-
model: spec.model,
|
|
76
|
-
// effort → pi thinkingLevel(恒等映射)
|
|
77
|
-
thinkingLevel: spec.effort,
|
|
78
|
-
// persona 还原:pi 的注入通道是 --skill / --append-system-prompt flag
|
|
79
|
-
skillPath: spec.persona?.skillPath,
|
|
80
|
-
appendSystemPrompt: spec.persona?.appendSystemPrompt,
|
|
81
|
-
schema: spec.schema,
|
|
82
|
-
// schemaEnv 内化派生(D-A6 bridge):与 agent-opts-resolver 共用 stringifySchemaCached
|
|
83
|
-
// compact 缓存,输出逐字节等值。schema 缺失(无法派生)且调用方持有预编码值时兜底
|
|
84
|
-
// 透传(解耦形态,生产不可达);无 schema 亦无兜底时不设(BC-6:childEnv 不注入)。
|
|
85
|
-
schemaEnv: spec.schema !== undefined
|
|
86
|
-
? stringifySchemaCached(spec.schema, "compact")
|
|
87
|
-
: runCtx?.schemaEnvFallback,
|
|
88
|
-
maxTurns: spec.maxTurns,
|
|
89
|
-
graceTurns: spec.graceTurns,
|
|
90
|
-
ctxModel: runCtx?.ctxModel,
|
|
91
|
-
fork: spec.fork,
|
|
92
|
-
worktree: spec.worktree,
|
|
93
|
-
cwd: spec.cwd,
|
|
94
|
-
conversation: spec.conversation,
|
|
95
|
-
idleTimeoutMs: spec.idleTimeoutMs,
|
|
96
|
-
// signal 不入 opts(PiEngine 直接传给 executeAndAwait 第 2 参,与 SAR 现行为一致);
|
|
97
|
-
// onComplete 不经引擎(workflow 路径从不设置;background 完成通知走 service 内部 notifier)。
|
|
98
|
-
// denyTools/permissionMode:中立新字段,pi 链路暂无对应面(P2 公共层接 denylist 映射)。
|
|
99
|
-
};
|
|
100
|
-
}
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"_meta": {
|
|
3
|
-
"description": "zcode CLI spawn 单轮模式 golden 实录(2026-08-25 验收前置门)",
|
|
4
|
-
"engineVersion": "0.16.5",
|
|
5
|
-
"recordedAt": "2026-08-25T01:41:43Z",
|
|
6
|
-
"recordedOn": "macOS arm64, node v24.11.1",
|
|
7
|
-
"argv": [
|
|
8
|
-
"node",
|
|
9
|
-
"/Applications/ZCode.app/Contents/Resources/glm/zcode.cjs",
|
|
10
|
-
"--json",
|
|
11
|
-
"--cwd",
|
|
12
|
-
"<临时目录>",
|
|
13
|
-
"--mode",
|
|
14
|
-
"yolo",
|
|
15
|
-
"--prompt",
|
|
16
|
-
"Reply with the single word: ok"
|
|
17
|
-
],
|
|
18
|
-
"envSummary": {
|
|
19
|
-
"HOME": "<隔离池目录>(config.json = model.main + 目标 provider 条目,无 plugins 块)",
|
|
20
|
-
"stdin": "/dev/null(stdio ignore——CLI 不读 stdin,否则挂起)",
|
|
21
|
-
"XYZ_AGENT_SUBAGENT": "实录未注入;引擎实现注入 =1"
|
|
22
|
-
},
|
|
23
|
-
"exitCode": 0,
|
|
24
|
-
"durationMs": 4914,
|
|
25
|
-
"fieldStructure": {
|
|
26
|
-
"sessionId": "string,sess_<uuid>",
|
|
27
|
-
"traceId": "string(诊断用)",
|
|
28
|
-
"turnId": "string,turn_<uuid>",
|
|
29
|
-
"response": "string——assistant 全文",
|
|
30
|
-
"usage": "object:source/modelRequestCount/inputTokens/outputTokens/totalTokens/cacheReadTokens/cacheWriteTokens/reasoningTokens/webFetchRequests/webSearchRequests",
|
|
31
|
-
"eventCount": "number",
|
|
32
|
-
"projection": "object:status/turnCount/totalTokenCount/contextUsed/contextWindow"
|
|
33
|
-
},
|
|
34
|
-
"usageMapping": "inputTokens→input、outputTokens→output、cacheReadTokens→cacheRead、cacheWriteTokens→cacheWrite;cost 无来源(cost 回传 ❌ 与调研一致)",
|
|
35
|
-
"credentialNote": "stdout 不含凭据;凭据只存在于池内 config.json(此处不收录)。隔离 HOME 的凭据源用 ~/.zcode/v2/config.json(桌面登录态)——本机 ~/.zcode/cli/config.json 的 router provider 指向局域网网关 192.168.1.202:9981,实录时不可达",
|
|
36
|
-
"sigtermTiming": "SIGTERM → exit 实测 103ms(exit code 143,stderr \"Turn was cancelled\");引擎杀链 grace 取 5000ms(zsub 同构,保守)"
|
|
37
|
-
},
|
|
38
|
-
"stdoutRaw": "{\n \"sessionId\": \"sess_35852a0f-1302-4e20-9e48-87f47527abe3\",\n \"traceId\": \"9fffaebd-749e-468b-af3f-2a89e3347785\",\n \"turnId\": \"turn_99879260-1c9b-4e97-afe1-c2e7abeaf5b9\",\n \"response\": \"ok\",\n \"usage\": {\n \"source\": \"provider\",\n \"modelRequestCount\": 1,\n \"inputTokens\": 12599,\n \"outputTokens\": 17,\n \"totalTokens\": 12616,\n \"cacheReadTokens\": 512,\n \"cacheWriteTokens\": 0,\n \"reasoningTokens\": 0,\n \"webFetchRequests\": 0,\n \"webSearchRequests\": 0\n },\n \"eventCount\": 17,\n \"projection\": {\n \"status\": \"idle\",\n \"turnCount\": 1,\n \"totalTokenCount\": 12616,\n \"contextUsed\": 12616,\n \"contextWindow\": 1000000\n }\n}\n"
|
|
39
|
-
}
|
|
@@ -1,150 +0,0 @@
|
|
|
1
|
-
// launcher.test.ts —— argv 组装 / 字节估算超限 / env 构造 / 真实子进程杀链(用 node -e
|
|
2
|
-
// 代替 zcode CLI,验证 SIGTERM→grace→SIGKILL 与 exited 标志机制本身)。
|
|
3
|
-
|
|
4
|
-
import { execFileSync } from "node:child_process";
|
|
5
|
-
|
|
6
|
-
import { describe, expect, it } from "vitest";
|
|
7
|
-
|
|
8
|
-
import { DEFAULT_ARGV_BUDGET_BYTES, estimateArgvBytes } from "../../../common/persona-router.ts";
|
|
9
|
-
import {
|
|
10
|
-
assertZcodeArgvBudget,
|
|
11
|
-
buildZcodeArgv,
|
|
12
|
-
buildZcodeEnv,
|
|
13
|
-
launchZcodeProcess,
|
|
14
|
-
} from "../launcher.ts";
|
|
15
|
-
|
|
16
|
-
describe("buildZcodeArgv", () => {
|
|
17
|
-
it("基础形态:--json --cwd --mode yolo --prompt 尾置", () => {
|
|
18
|
-
const args = buildZcodeArgv({ cwd: "/tmp/w", prompt: "do it" });
|
|
19
|
-
expect(args).toEqual(["--json", "--cwd", "/tmp/w", "--mode", "yolo", "--prompt", "do it"]);
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
it("denyTools 逗号连接进 --disallowed-tools", () => {
|
|
23
|
-
const args = buildZcodeArgv({ cwd: "/w", prompt: "p", denyTools: ["bash", "edit"] });
|
|
24
|
-
expect(args).toContain("--disallowed-tools");
|
|
25
|
-
expect(args[args.indexOf("--disallowed-tools") + 1]).toBe("bash,edit");
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
it("denyTools 空/空白项过滤,全空不加 flag", () => {
|
|
29
|
-
expect(buildZcodeArgv({ cwd: "/w", prompt: "p", denyTools: [] })).not.toContain("--disallowed-tools");
|
|
30
|
-
expect(buildZcodeArgv({ cwd: "/w", prompt: "p", denyTools: [" ", ""] })).not.toContain("--disallowed-tools");
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
it("resumeSessionId 落 --resume(prompt 之前)", () => {
|
|
34
|
-
const args = buildZcodeArgv({ cwd: "/w", prompt: "p", resumeSessionId: "sess_x" });
|
|
35
|
-
expect(args.indexOf("--resume")).toBeLessThan(args.indexOf("--prompt"));
|
|
36
|
-
expect(args[args.indexOf("--resume") + 1]).toBe("sess_x");
|
|
37
|
-
});
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
describe("assertZcodeArgvBudget(对齐点②:公共 persona-router 权威预算的引擎侧消费)", () => {
|
|
41
|
-
it("估算含 node 与 cliPath 前导(NUL 分隔近似),中文 prompt 按字节计", () => {
|
|
42
|
-
// 公共 estimateArgvBytes 的口径回归:前导两元素计入 + 多字节按 UTF-8 字节
|
|
43
|
-
const est = estimateArgvBytes(["n", "c", "--prompt", "中文"]);
|
|
44
|
-
expect(est).toBe(2 + 2 + ("--prompt".length + 1) + Buffer.byteLength("中文") + 1);
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
it("超 128KB 阈值抛 prompt_too_large(含恢复指引;阈值 = DEFAULT_ARGV_BUDGET_BYTES)", () => {
|
|
48
|
-
const bigPrompt = "x".repeat(DEFAULT_ARGV_BUDGET_BYTES);
|
|
49
|
-
expect(() => assertZcodeArgvBudget("node", "/cli.cjs", ["--prompt", bigPrompt])).toThrowError(
|
|
50
|
-
/prompt_too_large/,
|
|
51
|
-
);
|
|
52
|
-
try {
|
|
53
|
-
assertZcodeArgvBudget("node", "/cli.cjs", ["--prompt", bigPrompt]);
|
|
54
|
-
} catch (err) {
|
|
55
|
-
// 公共 EngineError 形态:message 是 code 前缀 detail,恢复指引在 recovery 字段
|
|
56
|
-
expect((err as { code: string }).code).toBe("prompt_too_large");
|
|
57
|
-
expect((err as { recovery: string }).recovery).toContain("Shorten the task text");
|
|
58
|
-
}
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
it("阈值内不抛", () => {
|
|
62
|
-
expect(() => assertZcodeArgvBudget("node", "/cli.cjs", ["--prompt", "x".repeat(1024)])).not.toThrow();
|
|
63
|
-
});
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
describe("buildZcodeEnv", () => {
|
|
67
|
-
it("HOME 强制覆盖(同名键不许覆盖隔离值)+ 统一嵌套标记(经公共 nesting-guard)", () => {
|
|
68
|
-
const env = buildZcodeEnv("/pool/home", { HOME: "/real/home", PATH: "/usr/bin" });
|
|
69
|
-
expect(env["HOME"]).toBe("/pool/home");
|
|
70
|
-
expect(env["XYZ_AGENT_SUBAGENT"]).toBe("1");
|
|
71
|
-
expect(env["PATH"]).toBe("/usr/bin");
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
it("剥离引擎原生嵌套标记(D8:防孙代理误判已在嵌套层)", () => {
|
|
75
|
-
const env = buildZcodeEnv("/pool/home", {
|
|
76
|
-
ZSW_NESTED: "1",
|
|
77
|
-
CLAUDECODE: "1",
|
|
78
|
-
PI_SUBAGENT_SELF_RECORD_ID: "sa-x",
|
|
79
|
-
PI_SUBAGENT_DEPTH: "2",
|
|
80
|
-
});
|
|
81
|
-
expect(env["ZSW_NESTED"]).toBeUndefined();
|
|
82
|
-
expect(env["CLAUDECODE"]).toBeUndefined();
|
|
83
|
-
expect(env["PI_SUBAGENT_SELF_RECORD_ID"]).toBeUndefined();
|
|
84
|
-
expect(env["PI_SUBAGENT_DEPTH"]).toBeUndefined();
|
|
85
|
-
expect(env["XYZ_AGENT_SUBAGENT"]).toBe("1");
|
|
86
|
-
});
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
describe("launchZcodeProcess:真实子进程杀链(node -e 代替 CLI)", () => {
|
|
90
|
-
// 杀链/exited 机制与 CLI 无关(对子进程发信号 + close 事件),用 `node -e <script>`
|
|
91
|
-
// 验证机制本身:launchZcodeProcess 的 spawn 形态是 `node <cliPath> <args...>`,
|
|
92
|
-
// 测试借 cliPath 槽位传 -e、args 传脚本内容。
|
|
93
|
-
it("child 句柄暴露(D10 记账数据源):proc.child 即 spawn 出的进程,退出码可读", async () => {
|
|
94
|
-
const proc = launchZcodeProcess({
|
|
95
|
-
cliPath: "-e",
|
|
96
|
-
args: ["process.stdout.write('hi'); process.exit(0)"],
|
|
97
|
-
env: process.env,
|
|
98
|
-
});
|
|
99
|
-
// 句柄与 pid 同源(宿主经 RunContext.onChildSpawned 注册进 spawnedChildren)
|
|
100
|
-
expect(proc.child.pid).toBe(proc.pid);
|
|
101
|
-
expect(proc.child.killed).toBe(false);
|
|
102
|
-
const exited = await proc.exited;
|
|
103
|
-
expect(exited.code).toBe(0);
|
|
104
|
-
expect(proc.child.exitCode).toBe(0); // close 后 exitCode 可读(close 事件先于 exited resolve)
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
it("正常退出:exited 带退出码,stdout 可收集", async () => {
|
|
108
|
-
const proc = launchZcodeProcess({
|
|
109
|
-
cliPath: "-e",
|
|
110
|
-
args: ["process.stdout.write('hello'); process.exit(0)"],
|
|
111
|
-
env: process.env,
|
|
112
|
-
});
|
|
113
|
-
let out = "";
|
|
114
|
-
proc.stdout.on("data", (d: Buffer) => {
|
|
115
|
-
out += d.toString();
|
|
116
|
-
});
|
|
117
|
-
const exited = await proc.exited;
|
|
118
|
-
expect(out).toBe("hello");
|
|
119
|
-
expect(exited.code).toBe(0);
|
|
120
|
-
expect(proc.killedByUs()).toBe(false);
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
it("abort 触发杀链:SIGTERM 后进程退出,killedByUs 标记", async () => {
|
|
124
|
-
const proc = launchZcodeProcess({
|
|
125
|
-
cliPath: "-e",
|
|
126
|
-
args: ["setInterval(() => {}, 1000)"],
|
|
127
|
-
env: process.env,
|
|
128
|
-
});
|
|
129
|
-
expect(proc.pid).toBeGreaterThan(0);
|
|
130
|
-
// 实测 zcode 对 SIGTERM ~103ms 退出;普通 node 进程无 handler 直接终止
|
|
131
|
-
const abortPromise = proc.abort(3000);
|
|
132
|
-
const exited = await proc.exited;
|
|
133
|
-
await abortPromise;
|
|
134
|
-
expect(exited.code === null || exited.code === 143 || exited.code === 1).toBe(true);
|
|
135
|
-
expect(proc.killedByUs()).toBe(true);
|
|
136
|
-
// 无僵尸:进程已从系统进程表消失
|
|
137
|
-
expect(() => execFileSync("ps", ["-p", String(proc.pid)])).toThrow();
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
it("abort 幂等:重复调用不再触发第二条杀链", async () => {
|
|
141
|
-
const proc = launchZcodeProcess({
|
|
142
|
-
cliPath: "-e",
|
|
143
|
-
args: ["setInterval(() => {}, 1000)"],
|
|
144
|
-
env: process.env,
|
|
145
|
-
});
|
|
146
|
-
await proc.abort(2000);
|
|
147
|
-
await proc.abort(2000); // 不应抛
|
|
148
|
-
await proc.exited;
|
|
149
|
-
});
|
|
150
|
-
});
|