@zhushanwen/subagent-core 0.2.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/README.md +45 -2
- package/agents/analyst.md +60 -0
- package/agents/coder.md +69 -0
- package/agents/debugger.md +66 -0
- package/agents/doc-reviewer.md +49 -0
- package/agents/explorer.md +63 -0
- package/agents/general-purpose.md +32 -0
- package/agents/orchestrator.md +61 -0
- package/agents/planner.md +53 -0
- package/agents/researcher.md +67 -0
- package/agents/reviewer.md +73 -0
- package/dist/chunk-43ONBFZX.js +240 -0
- package/dist/chunk-APZY4IME.js +27 -0
- package/dist/chunk-V3VHZ2VX.js +59 -0
- package/dist/execution/engine/engines/zcode/constants.cjs +62 -9
- package/dist/execution/engine/engines/zcode/constants.d.cts +116 -12
- package/dist/execution/engine/engines/zcode/constants.d.ts +116 -12
- package/dist/execution/engine/engines/zcode/constants.js +39 -7
- 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 +4 -234
- package/dist/execution/engine/paths.js +7 -19
- package/dist/index.cjs +18234 -1277
- package/dist/index.d.cts +5646 -673
- package/dist/index.d.ts +5646 -673
- package/dist/index.js +17828 -1277
- package/dist/{types-BxyAidGf.d.cts → types-Dv4QhSJ_.d.cts} +678 -112
- package/dist/{types-BxyAidGf.d.ts → types-Dv4QhSJ_.d.ts} +678 -112
- package/package.json +7 -4
- 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 +93 -3
- package/src/__tests__/review-fix-loop-utils.test.ts +31 -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/__tests__/smoke.test.ts +9 -2
- 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 +232 -0
- 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 +219 -0
- package/src/execution/__tests__/ask-user-transit-e2e.test.ts +6 -6
- package/src/execution/__tests__/chat-engine-routing.test.ts +136 -30
- package/src/execution/__tests__/chatmode-first-round-closure-spawn.test.ts +5 -4
- package/src/execution/__tests__/cold-resurrect.test.ts +283 -0
- package/src/execution/__tests__/create-concurrency-pool.test.ts +194 -0
- package/src/execution/__tests__/delivery-methods.test.ts +77 -62
- package/src/execution/__tests__/descendant-sweep-guards.test.ts +220 -0
- package/src/execution/__tests__/descendant-sweep.test.ts +269 -0
- package/src/execution/__tests__/dialog-queue.test.ts +199 -1
- package/src/execution/__tests__/engine-model-validation.test.ts +741 -0
- package/src/execution/__tests__/epipe-fallback.test.ts +31 -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 +272 -0
- package/src/execution/__tests__/explicit-agent-ref-guard.test.ts +3 -3
- package/src/execution/__tests__/finalize-record.test.ts +278 -16
- package/src/execution/__tests__/gc-timer.test.ts +57 -2
- package/src/execution/__tests__/get-record-for-action-restart.test.ts +14 -12
- package/src/execution/__tests__/get-state-handshake.test.ts +127 -0
- 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 +280 -0
- package/src/execution/__tests__/kill-all-escalation.test.ts +196 -0
- package/src/execution/__tests__/lifecycle-manager-idle-timer-identity.test.ts +117 -0
- package/src/execution/__tests__/lifecycle-manager.test.ts +39 -0
- package/src/execution/__tests__/lifecycle-predicates.test.ts +1 -2
- package/src/execution/__tests__/manifest-parentid.test.ts +4 -4
- package/src/execution/__tests__/manifest-store-tmp-recovery.test.ts +99 -0
- package/src/execution/__tests__/max-turns-to-watchdog-ms.test.ts +113 -0
- 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 +1249 -0
- 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-orphan-revive.test.ts +159 -0
- package/src/execution/__tests__/record-store.test.ts +89 -5
- 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 +19 -9
- package/src/execution/__tests__/run-spawn-chatmode-settled.test.ts +5 -4
- package/src/execution/__tests__/run-spawn-edges.test.ts +418 -26
- package/src/execution/__tests__/run-spawn-integration.test.ts +3 -3
- 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 +16 -8
- package/src/execution/__tests__/service-kill-escalation.test.ts +91 -0
- 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 +471 -0
- package/src/execution/__tests__/session-reconstructor.test.ts +366 -15
- package/src/execution/__tests__/session-runner-branch-cache-lru.test.ts +110 -0
- package/src/execution/__tests__/session-runner-close-prune.test.ts +181 -0
- package/src/execution/__tests__/session-runner-dispatch.test.ts +489 -0
- package/src/execution/__tests__/session-runner-epipe.test.ts +4 -3
- package/src/execution/__tests__/session-runner-heartbeat-idle-fallback.test.ts +227 -0
- 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 +524 -0
- 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 +155 -11
- 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 +1017 -0
- package/src/execution/__tests__/subagent-service-message-close.test.ts +99 -35
- package/src/execution/__tests__/subagent-service-multiproc-guard.test.ts +174 -0
- package/src/execution/__tests__/subagent-service-notify-gate.test.ts +271 -0
- package/src/execution/__tests__/subagent-service-parent-guard.test.ts +33 -29
- package/src/execution/__tests__/subagent-service-recovery-bounds.test.ts +341 -0
- 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 +13 -12
- 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 +107 -7
- package/src/execution/__tests__/ui-request-handler.test.ts +4 -3
- package/src/execution/__tests__/ui-request-queue.test.ts +167 -2
- package/src/execution/__tests__/worktree-git-ops.test.ts +571 -0
- 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/__tests__/worktree-reconcile-aging.test.ts +204 -0
- package/src/execution/agent-registry.ts +298 -30
- package/src/execution/agent-result-mapper.ts +3 -0
- package/src/execution/agents-assembly.ts +88 -0
- package/src/execution/cold-resurrect.ts +199 -0
- package/src/execution/concurrency-pool.ts +71 -9
- package/src/execution/dialog-queue.ts +101 -3
- 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 +56 -99
- package/src/execution/engine/__tests__/conformance/contract.agent-events.test.ts +88 -15
- package/src/execution/engine/__tests__/conformance/engine-conformance.live.test.ts +33 -7
- package/src/execution/engine/__tests__/conformance/golden-replay.pi.test.ts +1 -1
- package/src/execution/engine/__tests__/conformance/golden-replay.zcode.test.ts +75 -54
- package/src/execution/engine/__tests__/conformance/zcode-appserver-harness.ts +128 -0
- 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 +94 -3
- 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/engine-discovery.ts +12 -16
- 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} +86 -11
- 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/engine/engines/pi/session-runner.ts +2840 -0
- 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 +301 -0
- package/src/execution/engine/engines/zcode/__tests__/__fixtures__/zcode-golden-appserver.json +36 -0
- package/src/execution/engine/engines/zcode/__tests__/appserver-launcher.test.ts +321 -0
- package/src/execution/engine/engines/zcode/__tests__/connection.test.ts +473 -0
- 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 +792 -0
- package/src/execution/engine/engines/zcode/__tests__/zcode-engine-appserver.test.ts +782 -0
- package/src/execution/engine/engines/zcode/__tests__/zcode-engine-degrade.test.ts +168 -0
- 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 +65 -47
- package/src/execution/engine/engines/zcode/appserver-launcher.ts +167 -0
- package/src/execution/engine/engines/zcode/connection.ts +598 -0
- package/src/execution/engine/engines/zcode/constants.ts +147 -14
- package/src/execution/engine/engines/zcode/golden-sample.ts +42 -34
- package/src/execution/engine/engines/zcode/parser.ts +12 -346
- package/src/execution/engine/engines/zcode/preparer.ts +22 -150
- package/src/execution/engine/engines/zcode/session-channel.ts +968 -0
- package/src/execution/engine/engines/zcode/zcode-engine.ts +1023 -250
- 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 +65 -7
- package/src/execution/engine/registry.ts +53 -0
- 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 +181 -85
- package/src/execution/idle-gc.ts +28 -0
- package/src/execution/lifecycle-manager.ts +27 -3
- package/src/execution/lifecycle-predicates.ts +1 -1
- package/src/execution/manifest-store.ts +53 -62
- package/src/execution/notifier.ts +10 -10
- package/src/execution/notify-host.ts +212 -0
- package/src/execution/notify-ledger.ts +117 -16
- package/src/execution/record-entry.ts +8 -2
- package/src/execution/record-store.ts +148 -88
- package/src/execution/round-settlement.ts +93 -0
- package/src/execution/session-file-gc.ts +96 -62
- package/src/execution/session-pending.ts +213 -62
- package/src/execution/session-reconstructor.ts +256 -143
- package/src/execution/sessions-index.ts +127 -102
- package/src/execution/settled-watchdog.ts +311 -0
- package/src/execution/subagent-actions-core.ts +686 -0
- package/src/execution/subagent-service.ts +1106 -907
- package/src/execution/subprocess-agent-runner.ts +144 -97
- package/src/execution/types.ts +9 -0
- package/src/execution/ui-request-handler-factory.ts +126 -75
- package/src/execution/ui-request-queue.ts +50 -19
- package/src/execution/worktree-git-ops.ts +397 -0
- package/src/execution/worktree-manager.ts +72 -10
- package/src/execution/worktree-registry.ts +6 -12
- package/src/index.ts +542 -9
- package/src/orchestration/__tests__/__fixtures__/worker-template.snapshot.txt +42 -3
- package/src/orchestration/__tests__/agent-call-catch-fallback.test.ts +3 -5
- package/src/orchestration/__tests__/agent-call-stream.test.ts +2 -2
- package/src/orchestration/__tests__/args-meta.test.ts +358 -0
- package/src/orchestration/__tests__/args-validator.test.ts +14 -0
- package/src/orchestration/__tests__/error-recovery-rebuild-failure.test.ts +312 -0
- package/src/orchestration/__tests__/error-recovery-terminal-hardening.test.ts +384 -0
- package/src/orchestration/__tests__/execute-agent-call.test.ts +151 -11
- package/src/orchestration/__tests__/file-run-store-prune.test.ts +168 -0
- package/src/orchestration/__tests__/file-run-store-throttle.test.ts +168 -0
- package/src/orchestration/__tests__/file-run-store.test.ts +390 -0
- package/src/orchestration/__tests__/helpers/flush-microtasks.ts +13 -0
- package/src/orchestration/__tests__/launcher-nested-workflow.test.ts +34 -0
- package/src/orchestration/__tests__/lifecycle-abort-broadcast-signal.test.ts +357 -0
- package/src/orchestration/__tests__/lifecycle-recover-crashed.test.ts +289 -0
- package/src/orchestration/__tests__/lifecycle-runid-injection.test.ts +3 -3
- package/src/orchestration/__tests__/lifecycle.test.ts +84 -5
- package/src/orchestration/__tests__/non-cloneable-return-e2e.test.ts +1 -1
- package/src/orchestration/__tests__/run-snapshot.test.ts +356 -0
- package/src/orchestration/__tests__/script-generate.test.ts +314 -0
- 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} +28 -27
- 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 +275 -0
- package/src/orchestration/__tests__/worker-script-builder-runtime.test.ts +78 -1
- package/src/orchestration/__tests__/worker-script-builder.test.ts +1 -1
- package/src/orchestration/__tests__/workflow-files.test.ts +186 -0
- package/src/orchestration/__tests__/workflow-nesting-e2e.test.ts +1 -1
- package/src/orchestration/__tests__/workflow-run-summary.test.ts +119 -0
- package/src/orchestration/__tests__/workflow-script-registry-impl.test.ts +124 -0
- package/src/orchestration/agent-opts-resolver.ts +8 -8
- package/src/orchestration/args-meta.ts +198 -0
- package/src/orchestration/args-validator.ts +53 -31
- package/src/orchestration/execute-agent-call.ts +25 -79
- package/src/orchestration/file-run-store.ts +327 -0
- package/src/orchestration/launcher.ts +160 -104
- package/src/orchestration/lifecycle.ts +371 -97
- package/src/orchestration/models/agent-call.ts +7 -7
- package/src/orchestration/models/budget.ts +5 -5
- package/src/orchestration/models/ports.ts +4 -4
- package/src/orchestration/models/run-runtime.ts +15 -15
- package/src/orchestration/models/trace.ts +9 -9
- package/src/orchestration/models/types.ts +111 -22
- package/src/orchestration/models/workflow-run.ts +28 -28
- package/src/orchestration/models/workflow-script.ts +4 -4
- package/src/orchestration/run-snapshot.ts +266 -0
- package/src/orchestration/script-generate.ts +154 -0
- package/src/orchestration/script-lint.ts +123 -90
- package/src/orchestration/worker-handle.ts +10 -10
- package/src/orchestration/worker-host.ts +10 -10
- package/src/orchestration/{error-recovery.ts → worker-message-pump.ts} +498 -221
- package/src/orchestration/worker-script-builder.ts +401 -346
- package/src/orchestration/workflow-files.ts +37 -11
- package/src/orchestration/workflow-run-summary.ts +69 -0
- package/src/orchestration/workflow-script-registry-impl.ts +31 -9
- package/src/shared/__tests__/agent-ref.test.ts +209 -2
- package/src/shared/__tests__/atomic-write.test.ts +267 -0
- package/src/shared/__tests__/bounded-serialize.test.ts +236 -0
- package/src/shared/__tests__/injection-render.test.ts +518 -0
- package/src/shared/__tests__/meta-parser.test.ts +151 -0
- package/src/shared/__tests__/resource-discovery-host-roots.test.ts +474 -0
- package/src/shared/__tests__/resource-discovery.test.ts +261 -217
- package/src/shared/agent-ref.ts +143 -2
- package/src/shared/atomic-write.ts +323 -0
- package/src/shared/bounded-serialize.ts +154 -0
- package/src/shared/injection-render.ts +279 -0
- package/src/shared/meta-parser.ts +182 -68
- package/src/shared/model-ref.ts +15 -2
- package/src/shared/resource-discovery.ts +97 -204
- package/src/shared/resource-meta.ts +14 -0
- package/src/shared/schema-jsonify.ts +1 -1
- package/src/shared/xml-injection.ts +9 -9
- package/workflows/README.md +9 -9
- package/workflows/chain.js +4 -2
- package/workflows/map-reduce.js +5 -3
- package/workflows/parallel.js +5 -3
- package/workflows/review-fix-loop-utils.cjs +165 -92
- package/workflows/review-fix-loop-utils.d.cts +287 -0
- package/workflows/review-fix-loop.js +18 -7
- package/workflows/scatter-gather.js +4 -2
- package/dist/chunk-3VOERJPJ.js +0 -22
- 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__/zcode-engine.test.ts +0 -580
- package/src/execution/engine/engines/zcode/launcher.ts +0 -161
- package/src/execution/execute-options-mapper.ts +0 -115
- package/src/execution/session-runner.ts +0 -1789
- package/src/shared/__tests__/resource-discovery-manifest-cache.test.ts +0 -288
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
// src/shared/injection-render.ts
|
|
2
|
+
//
|
|
3
|
+
// 三段 XML 注入渲染(<available_subagents> / <available_workflows> /
|
|
4
|
+
// <available_provider_models>)——从 pi-sw 插件层下沉的平台无关纯函数
|
|
5
|
+
// (convergence D-3)。渲染骨架 escapeXml/renderXmlSection 见同目录
|
|
6
|
+
// xml-injection.ts。pi 侧原函数曾内嵌于三 injector(基线 5557e109b,C5 起改调
|
|
7
|
+
// 本模块,逐字节等价证据见
|
|
8
|
+
// docs/design/subagent-core-convergence.probe-a2-baseline.md)。
|
|
9
|
+
//
|
|
10
|
+
// 与 pi-sw 原实现的差异(本模块定约):
|
|
11
|
+
// - guide 文案必填注入:core 不内嵌任何平台文案,宿主(pi-sw / zsw)各自传入;
|
|
12
|
+
// - ModelEntry 并集口径:除 id/name 外全字段 optional(红线 5)——undefined
|
|
13
|
+
// 消费点显式守卫(input 缺席不抛、contextWindow 缺席不渲染该元素、
|
|
14
|
+
// provider 缺席/空串时 id 裸渲染),不是自然降级;
|
|
15
|
+
// - 分段条目预算:subagents/workflows 可传 maxEntries,超限按排序键码点序
|
|
16
|
+
// 截尾 + 追加宿主注入的兜底指引行(红线 7:内置条目无截断豁免,不做
|
|
17
|
+
// 「内置优先保留」两段式);models 段无预算参数,完整渲染永不截(设计钉死);
|
|
18
|
+
// - format 内部先排后截:pi 调用链数据已排时重排幂等,不破坏「pi 现调用
|
|
19
|
+
// 形态下输出逐字节等价」(CA2 快照验收前提)。
|
|
20
|
+
//
|
|
21
|
+
// 设计权威源:docs/design/subagent-core-convergence.md §3.2 D-3 / §3.3 红线 5、7。
|
|
22
|
+
|
|
23
|
+
import { escapeXml, renderXmlSection } from "./xml-injection.ts";
|
|
24
|
+
|
|
25
|
+
/** 从 agent .md frontmatter 提取的最小 agent 信息(随 D-3 从 pi-sw 下沉) */
|
|
26
|
+
export interface AgentEntry {
|
|
27
|
+
name: string;
|
|
28
|
+
description: string;
|
|
29
|
+
when?: string;
|
|
30
|
+
examples?: Array<{ match: string; action: string; positive: boolean }>;
|
|
31
|
+
/** agentRef:agent .md 文件的绝对路径(注入段 <location>,模型直接引用) */
|
|
32
|
+
path: string;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** 解析后的 workflow 条目(name + 摘要后的 description + 脚本路径) */
|
|
36
|
+
export interface WorkflowEntry {
|
|
37
|
+
name: string;
|
|
38
|
+
description: string;
|
|
39
|
+
/** workflowRef:脚本 .js 文件的绝对路径(注入段 <location>,模型直接引用) */
|
|
40
|
+
path: string;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** reasoning 对象形态(zsw 投影的档位结构);渲染面仅按 truthy 消费,字段值不进输出 */
|
|
44
|
+
export interface ModelReasoningInfo {
|
|
45
|
+
variants?: unknown[];
|
|
46
|
+
defaultVariant?: unknown;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* 注入段的最小模型投影——pi 与 zsw 两侧数据形态的并集(D-3 + 本仓 provider 补充):
|
|
51
|
+
* id/name 为条目最小必填(缺则无渲染意义),其余字段 optional(红线 5)。
|
|
52
|
+
* - pi 投影:provider/reasoning:boolean/input[]/contextWindow 全给;
|
|
53
|
+
* - zsw 投影:reasoning:{variants} 档位对象、input 缺席;
|
|
54
|
+
* - label 与 reasoning.variants 进类型并集但渲染面暂不消费(宿主按需再扩)。
|
|
55
|
+
*/
|
|
56
|
+
export interface ModelEntry {
|
|
57
|
+
id: string;
|
|
58
|
+
name: string;
|
|
59
|
+
provider?: string;
|
|
60
|
+
label?: string;
|
|
61
|
+
contextWindow?: number;
|
|
62
|
+
reasoning?: boolean | ModelReasoningInfo;
|
|
63
|
+
input?: string[];
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** 条目段(subagents/workflows)渲染选项:guide 宿主注入 + 可选条目预算 */
|
|
67
|
+
export interface ListFormatOptions {
|
|
68
|
+
/** 注入段引导文案——必填,core 不内嵌平台文案(D-3 guide 参数化) */
|
|
69
|
+
guide: string;
|
|
70
|
+
/**
|
|
71
|
+
* 条目预算上限:超限按排序键码点序截尾(保留靠前条目)。缺省不限制
|
|
72
|
+
* (pi 现行为全量)。models 段无此参数(永不截,设计钉死)。
|
|
73
|
+
*/
|
|
74
|
+
maxEntries?: number;
|
|
75
|
+
/** 截断发生时在段末追加的兜底指引行(宿主注入,如查看全量的命令);未提供则不追加 */
|
|
76
|
+
truncationNotice?: string;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** models 段渲染选项:仅 guide——无条目预算(完整渲染永不截,D-3 钉死) */
|
|
80
|
+
export interface ModelListFormatOptions {
|
|
81
|
+
guide: string;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* 码点序排序(显式契约,禁 localeCompare——宿主 locale 差异会破坏跨环境
|
|
86
|
+
* 字节一致;注入段进每 turn system prompt,顺序必须与枚举序解耦)。
|
|
87
|
+
* 非变异:返回排序副本,入参数组不动(core 纯函数定位;截尾语义依赖此序)。
|
|
88
|
+
*/
|
|
89
|
+
export function sortByCodepoint<T>(
|
|
90
|
+
items: readonly T[],
|
|
91
|
+
key: (item: T) => string,
|
|
92
|
+
): T[] {
|
|
93
|
+
return [...items].sort((a, b) => {
|
|
94
|
+
const ka = key(a);
|
|
95
|
+
const kb = key(b);
|
|
96
|
+
return ka < kb ? -1 : ka > kb ? 1 : 0;
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/** 注入段中单个 workflow 的最大描述长度(控制每 turn prompt 体积) */
|
|
101
|
+
const MAX_DESC_LEN = 160;
|
|
102
|
+
|
|
103
|
+
/** 断句阈值比例:句末标点位置须 >= maxLen 的 40% 才采用,否则硬截断保留更多信息 */
|
|
104
|
+
const DESC_BOUNDARY_MIN_RATIO = 0.4;
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* 将 workflow description 截断为 prompt 友好的摘要。
|
|
108
|
+
* 优先在 limit 内的最后一个句末标点处断句;无合适断点则硬截断 + 省略号。
|
|
109
|
+
*/
|
|
110
|
+
export function summarizeDescription(
|
|
111
|
+
desc: string,
|
|
112
|
+
maxLen = MAX_DESC_LEN,
|
|
113
|
+
): string {
|
|
114
|
+
const trimmed = desc.trim();
|
|
115
|
+
if (trimmed.length <= maxLen) return trimmed;
|
|
116
|
+
const slice = trimmed.slice(0, maxLen);
|
|
117
|
+
const boundary = Math.max(
|
|
118
|
+
slice.lastIndexOf("。"),
|
|
119
|
+
slice.lastIndexOf(";"),
|
|
120
|
+
slice.lastIndexOf(";"),
|
|
121
|
+
slice.lastIndexOf(". "),
|
|
122
|
+
);
|
|
123
|
+
// 断点过靠前(< 阈值比例)时不采用,改硬截断保留更多信息
|
|
124
|
+
if (boundary > maxLen * DESC_BOUNDARY_MIN_RATIO) return slice.slice(0, boundary + 1);
|
|
125
|
+
return `${slice}…`;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* 排序后应用条目预算:超限截尾(保留码点序靠前条目)。返回保留条目与是否截断。
|
|
130
|
+
* 红线 7:内置条目无截断豁免——不做「内置优先保留」两段式。
|
|
131
|
+
*/
|
|
132
|
+
function applyEntryBudget<T>(
|
|
133
|
+
sorted: T[],
|
|
134
|
+
maxEntries: number | undefined,
|
|
135
|
+
): { kept: T[]; truncated: boolean } {
|
|
136
|
+
if (maxEntries === undefined || sorted.length <= maxEntries) {
|
|
137
|
+
return { kept: sorted, truncated: false };
|
|
138
|
+
}
|
|
139
|
+
return { kept: sorted.slice(0, maxEntries), truncated: true };
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* 将 agent 列表格式化为 XML 注入段。
|
|
144
|
+
*
|
|
145
|
+
* 内部先按 name 码点序排序再渲染截断(超预算截尾语义依赖码点序;pi 调用链
|
|
146
|
+
* 数据已排时重排幂等,不破坏与 pi 现输出的逐字节等价)。空列表返回空串
|
|
147
|
+
* (不注入);预算截断发生时在段末追加宿主注入的兜底指引行(缺省不追加)。
|
|
148
|
+
*/
|
|
149
|
+
export function formatAgentList(
|
|
150
|
+
agents: AgentEntry[],
|
|
151
|
+
opts: ListFormatOptions,
|
|
152
|
+
): string {
|
|
153
|
+
if (agents.length === 0) return "";
|
|
154
|
+
|
|
155
|
+
const sorted = sortByCodepoint(agents, (a) => a.name);
|
|
156
|
+
const { kept, truncated } = applyEntryBudget(sorted, opts.maxEntries);
|
|
157
|
+
|
|
158
|
+
const items = kept.map((agent) => {
|
|
159
|
+
let block = ` <agent><name>${escapeXml(agent.name)}</name><description>${escapeXml(agent.description)}</description>`;
|
|
160
|
+
// 路由样本(when + examples 正反原样渲染——negative 的 action 由作者写
|
|
161
|
+
// 「不调用(原因)」,渲染器不硬编码;全部内容 escapeXml 防 XML 注入段破坏)
|
|
162
|
+
if (agent.when) {
|
|
163
|
+
block += `<when>${escapeXml(agent.when)}</when>`;
|
|
164
|
+
}
|
|
165
|
+
if (agent.examples && agent.examples.length > 0) {
|
|
166
|
+
const exampleLines = agent.examples.map(
|
|
167
|
+
(e) => ` - "${escapeXml(e.match)}" → ${escapeXml(e.action)}`,
|
|
168
|
+
);
|
|
169
|
+
block += `\n <examples>\n${exampleLines.join("\n")}\n </examples>`;
|
|
170
|
+
}
|
|
171
|
+
block += `<location>${escapeXml(agent.path)}</location></agent>`;
|
|
172
|
+
return block;
|
|
173
|
+
});
|
|
174
|
+
if (truncated && opts.truncationNotice !== undefined) {
|
|
175
|
+
items.push(opts.truncationNotice);
|
|
176
|
+
}
|
|
177
|
+
return renderXmlSection({
|
|
178
|
+
tag: "available_subagents",
|
|
179
|
+
guide: opts.guide,
|
|
180
|
+
items,
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* 将 workflow 列表格式化为 XML 注入段。
|
|
186
|
+
*
|
|
187
|
+
* 与 formatAgentList 同约:先按 name 码点序排序再渲染截尾;空列表返回空串
|
|
188
|
+
* (不注入);截断时追加宿主注入的兜底指引行(缺省不追加)。
|
|
189
|
+
*/
|
|
190
|
+
export function formatWorkflowList(
|
|
191
|
+
workflows: WorkflowEntry[],
|
|
192
|
+
opts: ListFormatOptions,
|
|
193
|
+
): string {
|
|
194
|
+
if (workflows.length === 0) return "";
|
|
195
|
+
|
|
196
|
+
const sorted = sortByCodepoint(workflows, (w) => w.name);
|
|
197
|
+
const { kept, truncated } = applyEntryBudget(sorted, opts.maxEntries);
|
|
198
|
+
|
|
199
|
+
const items = kept.map((wf) =>
|
|
200
|
+
` <workflow><name>${escapeXml(wf.name)}</name><description>${escapeXml(wf.description)}</description><location>${escapeXml(wf.path)}</location></workflow>`,
|
|
201
|
+
);
|
|
202
|
+
if (truncated && opts.truncationNotice !== undefined) {
|
|
203
|
+
items.push(opts.truncationNotice);
|
|
204
|
+
}
|
|
205
|
+
return renderXmlSection({
|
|
206
|
+
tag: "available_workflows",
|
|
207
|
+
guide: opts.guide,
|
|
208
|
+
items,
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/** 码点序比较(显式契约,禁 localeCompare——同 sortByCodepoint 注释) */
|
|
213
|
+
function compareByCodepoint(a: string, b: string): number {
|
|
214
|
+
return a < b ? -1 : a > b ? 1 : 0;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* models 段排序:provider 归一为非空串参与比较(缺席/空串 → "")——
|
|
219
|
+
* pi 投影(provider 全给且非空)下与 pi 现实现 (provider, id) 两段码点序一致;
|
|
220
|
+
* zsw 投影(provider 缺席)整体退化为 id 码点序;混合形态下无 provider 条目
|
|
221
|
+
* 排最前(空串码点最小),口径确定可复现。
|
|
222
|
+
*/
|
|
223
|
+
function compareModelEntries(a: ModelEntry, b: ModelEntry): number {
|
|
224
|
+
const pa = a.provider ?? "";
|
|
225
|
+
const pb = b.provider ?? "";
|
|
226
|
+
return pa === pb
|
|
227
|
+
? compareByCodepoint(a.id, b.id)
|
|
228
|
+
: compareByCodepoint(pa, pb);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* 能力标记:reasoning truthy(布尔 true 或对象形态——zsw 的 {variants} 投影)
|
|
233
|
+
* → "reasoning";input 含 image → "vision"。空则省略 caps 段。
|
|
234
|
+
* 红线 5 守卫:input 缺席经 optional chaining 不抛(pi 版此处对 undefined 抛
|
|
235
|
+
* TypeError,本仓 L73 已核实)。
|
|
236
|
+
*/
|
|
237
|
+
function formatCaps(entry: ModelEntry): string {
|
|
238
|
+
const caps: string[] = [];
|
|
239
|
+
if (entry.reasoning) caps.push("reasoning");
|
|
240
|
+
if (entry.input?.includes("image") ?? false) caps.push("vision");
|
|
241
|
+
return caps.join(",");
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* 将模型列表格式化为 XML 注入段。
|
|
246
|
+
*
|
|
247
|
+
* 输入按归一 (provider, id) 码点序排序(见 compareModelEntries)——同一数据集
|
|
248
|
+
* 输出字节稳定(KV-cache 契约)。空列表返回空串(不注入)。
|
|
249
|
+
* models 段无条目预算(完整渲染永不截,D-3 钉死)。
|
|
250
|
+
* 红线 5 守卫:contextWindow 缺席不渲染该元素(不输出 "undefined" 垃圾);
|
|
251
|
+
* provider 缺席/空串时 id 裸渲染。
|
|
252
|
+
*/
|
|
253
|
+
export function formatModelList(
|
|
254
|
+
models: ModelEntry[],
|
|
255
|
+
opts: ModelListFormatOptions,
|
|
256
|
+
): string {
|
|
257
|
+
if (models.length === 0) return "";
|
|
258
|
+
|
|
259
|
+
const sorted = [...models].sort(compareModelEntries);
|
|
260
|
+
|
|
261
|
+
const items = sorted.map((m) => {
|
|
262
|
+
const caps = formatCaps(m);
|
|
263
|
+
const idText = m.provider ? `${m.provider}/${m.id}` : m.id;
|
|
264
|
+
return (
|
|
265
|
+
` <model><id>${escapeXml(idText)}</id>`
|
|
266
|
+
+ `<name>${escapeXml(m.name)}</name>`
|
|
267
|
+
+ (caps ? `<caps>${caps}</caps>` : "")
|
|
268
|
+
+ (m.contextWindow !== undefined
|
|
269
|
+
? `<contextWindow>${m.contextWindow}</contextWindow>`
|
|
270
|
+
: "")
|
|
271
|
+
+ `</model>`
|
|
272
|
+
);
|
|
273
|
+
});
|
|
274
|
+
return renderXmlSection({
|
|
275
|
+
tag: "available_provider_models",
|
|
276
|
+
guide: opts.guide,
|
|
277
|
+
items,
|
|
278
|
+
});
|
|
279
|
+
}
|
|
@@ -75,6 +75,10 @@ function isPlainObject(v: unknown): v is Record<string, unknown> {
|
|
|
75
75
|
* 把 parseYaml 结果(unknown)校验为类型化 ResourceMeta,失败返 null(语义非法,非语法错)。
|
|
76
76
|
* 严格化(exec-review minor-2..5):kind 专属字段不可串类、description 必填、
|
|
77
77
|
* phase detail 非字符串/parameters 非对象均 reject(消除「静默丢弃非法字段」)。
|
|
78
|
+
*
|
|
79
|
+
* 结构(行为保持提取,主函数只留公共校验 + kind 分派;各分支校验顺序不可调换):
|
|
80
|
+
* workflow → typecheckWorkflowMeta(串类 → phases → parameters);
|
|
81
|
+
* agent → typecheckAgentMeta(串类 → examples → tools → model/engine → maxTurns → disallowedTools → skills)。
|
|
78
82
|
*/
|
|
79
83
|
function typecheckMeta(raw: unknown, kind: ResourceKind): ResourceMeta | null {
|
|
80
84
|
if (!isPlainObject(raw)) return null;
|
|
@@ -87,91 +91,201 @@ function typecheckMeta(raw: unknown, kind: ResourceKind): ResourceMeta | null {
|
|
|
87
91
|
const notFor = isString(o.notFor) ? o.notFor : undefined;
|
|
88
92
|
|
|
89
93
|
if (kind === "workflow") {
|
|
90
|
-
|
|
91
|
-
if (o.examples !== undefined || o.tools !== undefined || o.model !== undefined || o.engine !== undefined) {
|
|
92
|
-
return null;
|
|
93
|
-
}
|
|
94
|
-
// phases 必填数组,元素为 string | {title:string, detail?:string}
|
|
95
|
-
if (!Array.isArray(o.phases)) return null;
|
|
96
|
-
const phases: WorkflowMeta["phases"] = [];
|
|
97
|
-
for (const p of o.phases) {
|
|
98
|
-
if (isString(p)) {
|
|
99
|
-
phases.push(p);
|
|
100
|
-
} else if (isPlainObject(p) && isNonEmptyString(p.title)) {
|
|
101
|
-
// minor-4:detail 存在但非字符串 → reject(不再静默丢弃)
|
|
102
|
-
if (p.detail !== undefined && !isString(p.detail)) return null;
|
|
103
|
-
phases.push(isString(p.detail) ? { title: p.title, detail: p.detail } : { title: p.title });
|
|
104
|
-
} else {
|
|
105
|
-
return null;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
// minor-5:parameters 存在但非 plain object → reject(不再静默当 undefined)
|
|
109
|
-
const parameters = o.parameters;
|
|
110
|
-
if (parameters !== undefined && !isPlainObject(parameters)) return null;
|
|
111
|
-
const usage = isString(o.usage) ? o.usage : undefined;
|
|
112
|
-
|
|
113
|
-
const meta: WorkflowMeta = {
|
|
114
|
-
kind: "workflow",
|
|
115
|
-
name: o.name,
|
|
116
|
-
description: o.description,
|
|
117
|
-
phases,
|
|
118
|
-
...(parameters !== undefined ? { parameters: parameters as Record<string, unknown> } : {}),
|
|
119
|
-
...(usage !== undefined ? { usage } : {}),
|
|
120
|
-
...(when !== undefined ? { when } : {}),
|
|
121
|
-
...(notFor !== undefined ? { notFor } : {}),
|
|
122
|
-
};
|
|
123
|
-
return meta;
|
|
94
|
+
return typecheckWorkflowMeta(o, o.name, o.description, when, notFor);
|
|
124
95
|
}
|
|
96
|
+
return typecheckAgentMeta(o, o.name, o.description, when, notFor);
|
|
97
|
+
}
|
|
125
98
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
99
|
+
/** minor-2 串类守卫(workflow 分支):agent 专属字段任一出现 → reject。 */
|
|
100
|
+
function hasAgentOnlyFields(o: Record<string, unknown>): boolean {
|
|
101
|
+
return (
|
|
102
|
+
o.examples !== undefined || o.tools !== undefined || o.model !== undefined
|
|
103
|
+
|| o.engine !== undefined || o.maxTurns !== undefined
|
|
104
|
+
|| o.disallowedTools !== undefined || o.skills !== undefined
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/** minor-2 串类守卫(agent 分支):workflow 专属字段任一出现 → reject。 */
|
|
109
|
+
function hasWorkflowOnlyFields(o: Record<string, unknown>): boolean {
|
|
110
|
+
return o.phases !== undefined || o.parameters !== undefined || o.usage !== undefined;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* phases 元素校验(string | {title:string, detail?:string}):合法元素逐个投影,
|
|
115
|
+
* 任一非法 → null。
|
|
116
|
+
* minor-4:detail 存在但非字符串 → reject(不再静默丢弃)。
|
|
117
|
+
*/
|
|
118
|
+
function typecheckPhases(rawPhases: unknown[]): WorkflowMeta["phases"] | null {
|
|
119
|
+
const phases: WorkflowMeta["phases"] = [];
|
|
120
|
+
for (const p of rawPhases) {
|
|
121
|
+
if (isString(p)) {
|
|
122
|
+
phases.push(p);
|
|
123
|
+
} else if (isPlainObject(p) && isNonEmptyString(p.title)) {
|
|
124
|
+
if (p.detail !== undefined && !isString(p.detail)) return null;
|
|
125
|
+
phases.push(isString(p.detail) ? { title: p.title, detail: p.detail } : { title: p.title });
|
|
126
|
+
} else {
|
|
127
|
+
return null;
|
|
144
128
|
}
|
|
145
|
-
examples = exs;
|
|
146
129
|
}
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
130
|
+
return phases;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/** workflow meta 组装(校验全过后的纯投影——可选字段缺席不进键)。 */
|
|
134
|
+
function buildWorkflowMeta(
|
|
135
|
+
name: string,
|
|
136
|
+
description: string,
|
|
137
|
+
phases: WorkflowMeta["phases"],
|
|
138
|
+
parameters: Record<string, unknown> | undefined,
|
|
139
|
+
usage: string | undefined,
|
|
140
|
+
when: string | undefined,
|
|
141
|
+
notFor: string | undefined,
|
|
142
|
+
): WorkflowMeta {
|
|
143
|
+
return {
|
|
144
|
+
kind: "workflow",
|
|
145
|
+
name,
|
|
146
|
+
description,
|
|
147
|
+
phases,
|
|
148
|
+
...(parameters !== undefined ? { parameters } : {}),
|
|
149
|
+
...(usage !== undefined ? { usage } : {}),
|
|
150
|
+
...(when !== undefined ? { when } : {}),
|
|
151
|
+
...(notFor !== undefined ? { notFor } : {}),
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/** workflow 分支校验(顺序 = 串类 → phases → parameters;usage 宽容投影)。 */
|
|
156
|
+
function typecheckWorkflowMeta(
|
|
157
|
+
o: Record<string, unknown>,
|
|
158
|
+
name: string,
|
|
159
|
+
description: string,
|
|
160
|
+
when: string | undefined,
|
|
161
|
+
notFor: string | undefined,
|
|
162
|
+
): WorkflowMeta | null {
|
|
163
|
+
// minor-2:agent 专属字段不可出现在 workflow(串类 reject)
|
|
164
|
+
if (hasAgentOnlyFields(o)) return null;
|
|
165
|
+
// phases 必填数组,元素为 string | {title:string, detail?:string}
|
|
166
|
+
const rawPhases = o.phases;
|
|
167
|
+
if (!Array.isArray(rawPhases)) return null;
|
|
168
|
+
const phases = typecheckPhases(rawPhases);
|
|
169
|
+
if (phases === null) return null;
|
|
170
|
+
// minor-5:parameters 存在但非 plain object → reject(不再静默当 undefined)
|
|
171
|
+
const parameters = o.parameters;
|
|
172
|
+
if (parameters !== undefined && !isPlainObject(parameters)) return null;
|
|
173
|
+
const usage = isString(o.usage) ? o.usage : undefined;
|
|
174
|
+
return buildWorkflowMeta(name, description, phases, parameters, usage, when, notFor);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* examples 校验三态:undefined → 缺席(不进 meta);非数组 → null;
|
|
179
|
+
* 元素须为 {match: string, action: string, positive: boolean},任一非法 → null。
|
|
180
|
+
*/
|
|
181
|
+
function typecheckExamples(raw: unknown): RoutingExample[] | null | undefined {
|
|
182
|
+
if (raw === undefined) return undefined;
|
|
183
|
+
if (!Array.isArray(raw)) return null;
|
|
184
|
+
const exs: RoutingExample[] = [];
|
|
185
|
+
for (const e of raw) {
|
|
186
|
+
if (
|
|
187
|
+
isPlainObject(e) &&
|
|
188
|
+
isString(e.match) &&
|
|
189
|
+
isString(e.action) &&
|
|
190
|
+
typeof e.positive === "boolean"
|
|
191
|
+
) {
|
|
192
|
+
exs.push({ match: e.match, action: e.action, positive: e.positive });
|
|
156
193
|
} else {
|
|
157
194
|
return null;
|
|
158
195
|
}
|
|
159
196
|
}
|
|
160
|
-
|
|
161
|
-
|
|
197
|
+
return exs;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* maxTurns 校验三态:undefined → 缺席;非 number 或非有限值(NaN/Infinity)→ null;
|
|
202
|
+
* 合法 number 原样投影。
|
|
203
|
+
*/
|
|
204
|
+
function typecheckMaxTurns(raw: unknown): number | null | undefined {
|
|
205
|
+
if (raw === undefined) return undefined;
|
|
206
|
+
if (typeof raw !== "number" || !Number.isFinite(raw)) return null;
|
|
207
|
+
return raw;
|
|
208
|
+
}
|
|
162
209
|
|
|
163
|
-
|
|
210
|
+
/** agent meta 组装(校验全过后的纯投影——可选字段缺席不进键)。 */
|
|
211
|
+
function buildAgentMeta(
|
|
212
|
+
name: string,
|
|
213
|
+
description: string,
|
|
214
|
+
examples: RoutingExample[] | undefined,
|
|
215
|
+
tools: string[] | undefined,
|
|
216
|
+
model: string | undefined,
|
|
217
|
+
engine: string | undefined,
|
|
218
|
+
maxTurns: number | undefined,
|
|
219
|
+
disallowedTools: string[] | undefined,
|
|
220
|
+
skills: string[] | undefined,
|
|
221
|
+
when: string | undefined,
|
|
222
|
+
notFor: string | undefined,
|
|
223
|
+
): AgentMeta {
|
|
224
|
+
return {
|
|
164
225
|
kind: "agent",
|
|
165
|
-
name
|
|
166
|
-
description
|
|
226
|
+
name,
|
|
227
|
+
description,
|
|
167
228
|
...(examples !== undefined ? { examples } : {}),
|
|
168
229
|
...(tools !== undefined ? { tools } : {}),
|
|
169
230
|
...(model !== undefined ? { model } : {}),
|
|
170
231
|
...(engine !== undefined ? { engine } : {}),
|
|
232
|
+
...(maxTurns !== undefined ? { maxTurns } : {}),
|
|
233
|
+
...(disallowedTools !== undefined ? { disallowedTools } : {}),
|
|
234
|
+
...(skills !== undefined ? { skills } : {}),
|
|
171
235
|
...(when !== undefined ? { when } : {}),
|
|
172
236
|
...(notFor !== undefined ? { notFor } : {}),
|
|
173
237
|
};
|
|
174
|
-
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/** agent 分支校验(顺序 = 串类 → examples → tools → model/engine → maxTurns → disallowedTools → skills)。 */
|
|
241
|
+
function typecheckAgentMeta(
|
|
242
|
+
o: Record<string, unknown>,
|
|
243
|
+
name: string,
|
|
244
|
+
description: string,
|
|
245
|
+
when: string | undefined,
|
|
246
|
+
notFor: string | undefined,
|
|
247
|
+
): AgentMeta | null {
|
|
248
|
+
// minor-2:workflow 专属字段不可出现在 agent(串类 reject)
|
|
249
|
+
if (hasWorkflowOnlyFields(o)) return null;
|
|
250
|
+
const examples = typecheckExamples(o.examples);
|
|
251
|
+
if (examples === null) return null;
|
|
252
|
+
// tools 三态经 parseStringListField(数组逐元素 string / 逗号分隔字符串 / 非法形态 → null)
|
|
253
|
+
const tools = parseStringListField(o.tools);
|
|
254
|
+
if (tools === null) return null;
|
|
255
|
+
const model = isString(o.model) ? o.model : undefined;
|
|
256
|
+
const engine = isString(o.engine) ? o.engine : undefined;
|
|
257
|
+
// D3 可选执行字段(maxTurns/disallowedTools/skills):与 tools 同风格投影
|
|
258
|
+
// (空数组 [] 同 tools 保留键——列表字段族空列表语义一致)。严格层对非法类型
|
|
259
|
+
// reject(minor-2..5 既有精神:不静默丢弃非法字段)——宽容降级是
|
|
260
|
+
// parseAgentProfile(agent-registry)的职责,不在本严格层。
|
|
261
|
+
const maxTurns = typecheckMaxTurns(o.maxTurns);
|
|
262
|
+
if (maxTurns === null) return null;
|
|
263
|
+
const disallowedTools = parseStringListField(o.disallowedTools);
|
|
264
|
+
if (disallowedTools === null) return null;
|
|
265
|
+
const skills = parseStringListField(o.skills);
|
|
266
|
+
if (skills === null) return null;
|
|
267
|
+
return buildAgentMeta(name, description, examples, tools, model, engine, maxTurns, disallowedTools, skills, when, notFor);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* 字符串列表字段解析(tools 先例的泛化):数组形态逐元素校验 string,空数组保留
|
|
272
|
+
* 为 [](键进 meta——与 tools 数组形态 `tools: []` 语义一致,列表字段族同语义);
|
|
273
|
+
* 逗号分隔字符串按 `tools: read, bash` 约定拆分 trim,全空串(`skills: ,`)视同
|
|
274
|
+
* 缺席;字段缺席 → undefined(不进 meta);非法形态(数字/对象/数组含非字符串)
|
|
275
|
+
* → null(调用方 reject——minor-2..5 既有精神:非法字段显式拒绝,不静默丢弃)。
|
|
276
|
+
* 三态返回是为区分「缺席」与「非法」。
|
|
277
|
+
*/
|
|
278
|
+
function parseStringListField(raw: unknown): string[] | null | undefined {
|
|
279
|
+
if (raw === undefined) return undefined;
|
|
280
|
+
if (Array.isArray(raw)) {
|
|
281
|
+
if (!raw.every(isString)) return null;
|
|
282
|
+
return raw as string[];
|
|
283
|
+
}
|
|
284
|
+
if (isString(raw)) {
|
|
285
|
+
const parts = raw.split(",").map((s) => s.trim()).filter(Boolean);
|
|
286
|
+
return parts.length > 0 ? parts : undefined;
|
|
287
|
+
}
|
|
288
|
+
return null;
|
|
175
289
|
}
|
|
176
290
|
|
|
177
291
|
// ── IF1: parseResourceMeta(discovery,fail-safe null)─────────────────
|
package/src/shared/model-ref.ts
CHANGED
|
@@ -188,6 +188,16 @@ function findSimilarSuggestions(
|
|
|
188
188
|
.slice(0, MODEL_LIST_LIMIT);
|
|
189
189
|
}
|
|
190
190
|
|
|
191
|
+
/**
|
|
192
|
+
* [u-h2 D2-4] notFoundError 的结构化标记:编排层(pi 未命中跨引擎反查)据此区分
|
|
193
|
+
* 「pi registry 未命中」与孪生歧义/auth 等其他裁决失败——只有未命中形态做反查。
|
|
194
|
+
*/
|
|
195
|
+
interface NotFoundMarker {
|
|
196
|
+
refNotFound: true;
|
|
197
|
+
/** 裁决的原始输入串(strip thinking 后缀前的原样值),跨引擎反查的匹配源。 */
|
|
198
|
+
refInput: string;
|
|
199
|
+
}
|
|
200
|
+
|
|
191
201
|
/** 规则⑤未命中错误:问句候选 + 合法串全集(无候选时)+ 继承指引。 */
|
|
192
202
|
function notFoundError(
|
|
193
203
|
input: string,
|
|
@@ -195,7 +205,7 @@ function notFoundError(
|
|
|
195
205
|
provider: string,
|
|
196
206
|
id: string,
|
|
197
207
|
source: ModelRefSource,
|
|
198
|
-
): Error {
|
|
208
|
+
): Error & NotFoundMarker {
|
|
199
209
|
const lines = [
|
|
200
210
|
`Model "${input}"${prefix} is not a registry entry. ` +
|
|
201
211
|
`Registry match is case-sensitive — the string must equal a registry entry exactly, including letter case.`,
|
|
@@ -230,7 +240,10 @@ function notFoundError(
|
|
|
230
240
|
}
|
|
231
241
|
|
|
232
242
|
lines.push(`Or omit the \`model\` param to inherit the main agent model.`);
|
|
233
|
-
|
|
243
|
+
const err = new Error(lines.join("\n")) as Error & NotFoundMarker;
|
|
244
|
+
err.refNotFound = true;
|
|
245
|
+
err.refInput = input;
|
|
246
|
+
return err;
|
|
234
247
|
}
|
|
235
248
|
|
|
236
249
|
// ============================================================
|