@zhushanwen/pi-subagent-workflow 8.6.0 → 8.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +9 -13
- package/relay/relay.mjs +1 -1
- package/src/host/__tests__/pi-host.test.ts +214 -0
- package/src/host/pi-host.ts +109 -0
- package/src/index.ts +89 -32
- package/src/injectors/__tests__/engine-awareness.test.ts +292 -0
- package/src/injectors/__tests__/engine-section-stability.test.ts +341 -0
- package/src/injectors/__tests__/subagent-list-injector.test.ts +5 -5
- package/src/injectors/__tests__/workflow-list-injector.test.ts +5 -5
- package/src/injectors/engine-awareness.ts +123 -0
- package/src/injectors/model-list-injector.ts +1 -1
- package/src/injectors/subagent-list-injector.ts +8 -8
- package/src/injectors/workflow-list-injector.ts +8 -8
- package/src/interface/__tests__/detectors.test.ts +3 -3
- package/src/interface/__tests__/subagent-tool-path-guard.test.ts +2 -2
- package/src/interface/__tests__/tool-workflow-script-generate.test.ts +2 -2
- package/src/interface/__tests__/tool-workflow-throw-paths.test.ts +1 -1
- package/src/interface/bg-notify-render.ts +4 -4
- package/src/interface/commands.ts +3 -3
- package/src/interface/format.ts +2 -2
- package/src/interface/helpers.ts +1 -1
- package/src/interface/list-component.ts +4 -4
- package/src/interface/list-shared.ts +2 -2
- package/src/interface/list-view.ts +2 -2
- package/src/interface/subagent-actions.ts +263 -11
- package/src/interface/subagent-tool-schema.ts +20 -13
- package/src/interface/subagent-tool.ts +11 -6
- package/src/interface/subagents.ts +3 -3
- package/src/interface/tool-render.ts +34 -2
- package/src/interface/tool-workflow-script.ts +4 -4
- package/src/interface/tool-workflow.ts +6 -6
- package/src/interface/views/WorkflowsView.ts +5 -5
- package/src/interface/views/__tests__/WorkflowsView-signature.test.ts +3 -3
- package/src/interface/views/__tests__/detail-content-session-file.test.ts +2 -2
- package/src/interface/views/detail-content.ts +4 -4
- package/src/interface/views/format.ts +4 -4
- package/src/{orchestration/jsonl-run-store.ts → jsonl-run-store.ts} +11 -11
- package/src/execution/__tests__/__fixtures__/notifier-golden-snapshots.json +0 -53
- package/src/execution/__tests__/__fixtures__/truncline.snapshot.json +0 -1
- package/src/execution/__tests__/agent-registry.test.ts +0 -363
- package/src/execution/__tests__/agent-result-mapper.test.ts +0 -150
- package/src/execution/__tests__/alive-store.test.ts +0 -147
- package/src/execution/__tests__/ask-user-transit-e2e.test.ts +0 -490
- package/src/execution/__tests__/before-agent-start-injection.test.ts +0 -132
- package/src/execution/__tests__/bg-notify-render.test.ts +0 -329
- package/src/execution/__tests__/channel-registry-handshake.test.ts +0 -243
- package/src/execution/__tests__/chat-engine-routing.test.ts +0 -601
- package/src/execution/__tests__/chatmode-first-round-closure-service.test.ts +0 -365
- package/src/execution/__tests__/chatmode-first-round-closure-spawn.test.ts +0 -190
- package/src/execution/__tests__/chatmode-round-notify-real-chain.test.ts +0 -215
- package/src/execution/__tests__/concurrency-pool.test.ts +0 -250
- package/src/execution/__tests__/config.test.ts +0 -110
- package/src/execution/__tests__/conversation-wiring.test.ts +0 -198
- package/src/execution/__tests__/crash-recovery.test.ts +0 -320
- package/src/execution/__tests__/delivery-methods.test.ts +0 -422
- package/src/execution/__tests__/dialog-queue.test.ts +0 -299
- package/src/execution/__tests__/epipe-fallback.test.ts +0 -241
- package/src/execution/__tests__/execute-and-await-worktree.test.ts +0 -243
- package/src/execution/__tests__/execute-nesting.test.ts +0 -323
- package/src/execution/__tests__/execute-options-mapper.test.ts +0 -200
- package/src/execution/__tests__/execution-record.test.ts +0 -1394
- package/src/execution/__tests__/explicit-agent-ref-guard.test.ts +0 -171
- package/src/execution/__tests__/finalize-record.test.ts +0 -368
- package/src/execution/__tests__/finalized-marker.test.ts +0 -82
- package/src/execution/__tests__/format-schema-instruction.test.ts +0 -169
- package/src/execution/__tests__/format.test.ts +0 -458
- package/src/execution/__tests__/gc-timer.test.ts +0 -184
- package/src/execution/__tests__/get-record-for-action-restart.test.ts +0 -254
- package/src/execution/__tests__/gui-mode-dispatch.test.ts +0 -59
- package/src/execution/__tests__/helpers/mock-extension-api.ts +0 -30
- package/src/execution/__tests__/helpers/spawn-mock.ts +0 -242
- package/src/execution/__tests__/host-mode.test.ts +0 -87
- package/src/execution/__tests__/index-session-start-identity.test.ts +0 -371
- package/src/execution/__tests__/index-session-start.test.ts +0 -672
- package/src/execution/__tests__/lifecycle-manager-lock.test.ts +0 -211
- package/src/execution/__tests__/lifecycle-manager.test.ts +0 -383
- package/src/execution/__tests__/lifecycle-predicates.test.ts +0 -116
- package/src/execution/__tests__/list-component.test.ts +0 -401
- package/src/execution/__tests__/list-fields.test.ts +0 -140
- package/src/execution/__tests__/manifest-parentid.test.ts +0 -117
- package/src/execution/__tests__/model-resolver.test.ts +0 -465
- package/src/execution/__tests__/nested-visibility-env-propagation.test.ts +0 -287
- package/src/execution/__tests__/nested-visibility.test.ts +0 -325
- package/src/execution/__tests__/notifier-flush.test.ts +0 -612
- package/src/execution/__tests__/notifier-golden-snapshot.test.ts +0 -261
- package/src/execution/__tests__/notify-ledger.test.ts +0 -826
- package/src/execution/__tests__/one-shot-upgrade.test.ts +0 -205
- package/src/execution/__tests__/output-collector.test.ts +0 -358
- package/src/execution/__tests__/parent-child-matrix.test.ts +0 -336
- package/src/execution/__tests__/path-encoding.test.ts +0 -104
- package/src/execution/__tests__/pi-invocation.test.ts +0 -134
- package/src/execution/__tests__/record-store.test.ts +0 -1057
- package/src/execution/__tests__/records-cwd-isolation.test.ts +0 -91
- package/src/execution/__tests__/recursive-visibility-baseline.test.ts +0 -339
- package/src/execution/__tests__/recursive-visibility-env.test.ts +0 -273
- package/src/execution/__tests__/relay-agent.test.ts +0 -448
- package/src/execution/__tests__/relay-env.test.ts +0 -42
- package/src/execution/__tests__/resource-policy.test.ts +0 -109
- package/src/execution/__tests__/rpc-mode.test.ts +0 -89
- package/src/execution/__tests__/run-and-finalize-chatmode.test.ts +0 -267
- package/src/execution/__tests__/run-spawn-chatmode-settled.test.ts +0 -253
- package/src/execution/__tests__/run-spawn-edges.test.ts +0 -687
- package/src/execution/__tests__/run-spawn-integration.test.ts +0 -933
- package/src/execution/__tests__/run-spawn-resume.test.ts +0 -322
- package/src/execution/__tests__/run-spawn-rpc-mode.test.ts +0 -196
- package/src/execution/__tests__/run-spawn-stdout-callback-throw.test.ts +0 -199
- package/src/execution/__tests__/sdk-contract.test.ts +0 -273
- package/src/execution/__tests__/session-context-resolver.test.ts +0 -167
- package/src/execution/__tests__/session-file-gc.test.ts +0 -293
- package/src/execution/__tests__/session-pending.test.ts +0 -197
- package/src/execution/__tests__/session-reconstructor.test.ts +0 -379
- package/src/execution/__tests__/session-runner-epipe.test.ts +0 -178
- package/src/execution/__tests__/session-runner-schema-env.test.ts +0 -350
- package/src/execution/__tests__/session-start-reaper.test.ts +0 -233
- package/src/execution/__tests__/spawn-args.test.ts +0 -445
- package/src/execution/__tests__/spawn-event-adapter-rpc.test.ts +0 -189
- package/src/execution/__tests__/spawn-event-adapter.test.ts +0 -167
- package/src/execution/__tests__/spawn-worktree-guidance.test.ts +0 -207
- package/src/execution/__tests__/spawned-children.test.ts +0 -92
- package/src/execution/__tests__/start-sync-model-guard.test.ts +0 -150
- package/src/execution/__tests__/startup-config-declaration.test.ts +0 -35
- package/src/execution/__tests__/status-refactor.test.ts +0 -345
- package/src/execution/__tests__/stdin-writer.test.ts +0 -463
- package/src/execution/__tests__/stream-sink-retirement.test.ts +0 -261
- package/src/execution/__tests__/subagent-service-abort.test.ts +0 -60
- package/src/execution/__tests__/subagent-service-message-close.test.ts +0 -629
- package/src/execution/__tests__/subagent-service-parent-guard.test.ts +0 -180
- package/src/execution/__tests__/subagent-service.test.ts +0 -788
- package/src/execution/__tests__/subprocess-agent-runner-routing.test.ts +0 -310
- package/src/execution/__tests__/subprocess-agent-runner.test.ts +0 -599
- package/src/execution/__tests__/temp-prompt.test.ts +0 -53
- package/src/execution/__tests__/timeout-integration.test.ts +0 -615
- package/src/execution/__tests__/tombstone-store.test.ts +0 -73
- package/src/execution/__tests__/tool-action.test.ts +0 -476
- package/src/execution/__tests__/truncline-snapshot.test.ts +0 -81
- package/src/execution/__tests__/turn-limiter-semantics.test.ts +0 -194
- package/src/execution/__tests__/turn-limiter.test.ts +0 -65
- package/src/execution/__tests__/ui-channels.test.ts +0 -187
- package/src/execution/__tests__/ui-interaction-model.test.ts +0 -67
- package/src/execution/__tests__/ui-request-handler-factory.test.ts +0 -370
- package/src/execution/__tests__/ui-request-handler.test.ts +0 -204
- package/src/execution/__tests__/ui-request-observability.test.ts +0 -114
- package/src/execution/__tests__/ui-request-queue.test.ts +0 -133
- package/src/execution/__tests__/worktree-manager.test.ts +0 -633
- package/src/execution/__tests__/worktree-pid-registration.integration.test.ts +0 -229
- package/src/execution/__tests__/worktree-reconcile.integration.test.ts +0 -181
- package/src/execution/__tests__/worktree-registry.test.ts +0 -199
- package/src/execution/agent-registry.ts +0 -199
- package/src/execution/agent-result-mapper.ts +0 -90
- package/src/execution/alive-store.ts +0 -92
- package/src/execution/argv-mirror.ts +0 -113
- package/src/execution/best-effort.ts +0 -38
- package/src/execution/channel-registry-access.ts +0 -144
- package/src/execution/concurrency-pool.ts +0 -116
- package/src/execution/config.ts +0 -96
- package/src/execution/dialog-queue.ts +0 -330
- package/src/execution/engine/__tests__/common/data-dir.test.ts +0 -53
- package/src/execution/engine/__tests__/common/errors.test.ts +0 -132
- package/src/execution/engine/__tests__/common/event-journal.test.ts +0 -177
- package/src/execution/engine/__tests__/common/kill-chain.test.ts +0 -192
- package/src/execution/engine/__tests__/common/nesting-guard.test.ts +0 -81
- package/src/execution/engine/__tests__/common/persona-router.test.ts +0 -123
- package/src/execution/engine/__tests__/common/pool-manager.test.ts +0 -154
- package/src/execution/engine/__tests__/common/schema-emulation.test.ts +0 -128
- package/src/execution/engine/__tests__/conformance/__fixtures__/pi-golden-events.json +0 -28
- package/src/execution/engine/__tests__/conformance/agent-event-invariants.ts +0 -141
- package/src/execution/engine/__tests__/conformance/contract.abort.test.ts +0 -109
- package/src/execution/engine/__tests__/conformance/contract.agent-events.test.ts +0 -101
- package/src/execution/engine/__tests__/conformance/contract.probe.test.ts +0 -77
- package/src/execution/engine/__tests__/conformance/contract.read-degradation.test.ts +0 -104
- package/src/execution/engine/__tests__/conformance/contract.relay.test.ts +0 -342
- package/src/execution/engine/__tests__/conformance/engine-conformance.live.test.ts +0 -201
- package/src/execution/engine/__tests__/conformance/golden-replay.pi.test.ts +0 -76
- package/src/execution/engine/__tests__/conformance/golden-replay.zcode.test.ts +0 -79
- package/src/execution/engine/__tests__/engine-discovery.test.ts +0 -87
- package/src/execution/engine/__tests__/engines-declaration.test.ts +0 -36
- package/src/execution/engine/__tests__/model-prompt.test.ts +0 -85
- package/src/execution/engine/__tests__/paths.test.ts +0 -39
- package/src/execution/engine/__tests__/registry.test.ts +0 -120
- package/src/execution/engine/__tests__/routing.test.ts +0 -231
- package/src/execution/engine/common/data-dir.ts +0 -62
- package/src/execution/engine/common/errors.ts +0 -183
- package/src/execution/engine/common/event-journal.ts +0 -254
- package/src/execution/engine/common/journal-replay.ts +0 -62
- package/src/execution/engine/common/kill-chain.ts +0 -221
- package/src/execution/engine/common/nesting-guard.ts +0 -50
- package/src/execution/engine/common/persona-router.ts +0 -108
- package/src/execution/engine/common/pool-manager.ts +0 -226
- package/src/execution/engine/common/schema-emulation.ts +0 -189
- package/src/execution/engine/common/session-view-projection.ts +0 -51
- package/src/execution/engine/engine-discovery.ts +0 -65
- package/src/execution/engine/engines/pi/__tests__/pi-engine.test.ts +0 -469
- package/src/execution/engine/engines/pi/__tests__/reader.test.ts +0 -155
- package/src/execution/engine/engines/pi/__tests__/task-spec-mapper.test.ts +0 -164
- package/src/execution/engine/engines/pi/pi-engine.ts +0 -415
- package/src/execution/engine/engines/pi/reader.ts +0 -48
- package/src/execution/engine/engines/pi/registration.ts +0 -35
- 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__/parser.test.ts +0 -246
- package/src/execution/engine/engines/zcode/__tests__/preparer.test.ts +0 -228
- package/src/execution/engine/engines/zcode/__tests__/reader.test.ts +0 -210
- package/src/execution/engine/engines/zcode/__tests__/registration.test.ts +0 -64
- package/src/execution/engine/engines/zcode/__tests__/zcode-engine.live.test.ts +0 -127
- package/src/execution/engine/engines/zcode/__tests__/zcode-engine.test.ts +0 -580
- package/src/execution/engine/engines/zcode/constants.ts +0 -43
- package/src/execution/engine/engines/zcode/golden-sample.ts +0 -39
- package/src/execution/engine/engines/zcode/launcher.ts +0 -161
- package/src/execution/engine/engines/zcode/parser.ts +0 -436
- package/src/execution/engine/engines/zcode/preparer.ts +0 -363
- package/src/execution/engine/engines/zcode/reader.ts +0 -381
- package/src/execution/engine/engines/zcode/registration.ts +0 -37
- package/src/execution/engine/engines/zcode/zcode-engine.ts +0 -658
- package/src/execution/engine/host-task-spec.ts +0 -47
- package/src/execution/engine/model-prompt.ts +0 -59
- package/src/execution/engine/paths.ts +0 -42
- package/src/execution/engine/port.ts +0 -153
- package/src/execution/engine/registry.ts +0 -123
- package/src/execution/engine/routing.ts +0 -218
- package/src/execution/engine/types.ts +0 -309
- package/src/execution/execute-options-mapper.ts +0 -112
- package/src/execution/execution-record.ts +0 -965
- package/src/execution/finalize-record.ts +0 -251
- package/src/execution/finalized-marker.ts +0 -51
- package/src/execution/get-state-handshake.ts +0 -104
- package/src/execution/host-mode.ts +0 -56
- package/src/execution/idle-gc.ts +0 -47
- package/src/execution/lifecycle-manager.ts +0 -513
- package/src/execution/lifecycle-predicates.ts +0 -65
- package/src/execution/manifest-store.ts +0 -256
- package/src/execution/model-config-service.ts +0 -219
- package/src/execution/model-resolver.ts +0 -248
- package/src/execution/notifier.ts +0 -330
- package/src/execution/notify-ledger.ts +0 -580
- package/src/execution/output-collector.ts +0 -228
- package/src/execution/path-encoding.ts +0 -60
- package/src/execution/pi-invocation.ts +0 -120
- package/src/execution/record-entry.ts +0 -132
- package/src/execution/record-store.ts +0 -1234
- package/src/execution/relay-env.ts +0 -37
- package/src/execution/session-context-resolver.ts +0 -64
- package/src/execution/session-file-gc.ts +0 -120
- package/src/execution/session-pending.ts +0 -164
- package/src/execution/session-reconstructor.ts +0 -678
- package/src/execution/session-runner.ts +0 -1781
- package/src/execution/sessions-index.ts +0 -304
- package/src/execution/spawn-event-adapter.ts +0 -363
- package/src/execution/stdin-writer.ts +0 -198
- package/src/execution/stream-sink.ts +0 -126
- package/src/execution/subagent-service.ts +0 -2141
- package/src/execution/subprocess-agent-runner.ts +0 -317
- package/src/execution/temp-prompt.ts +0 -62
- package/src/execution/tombstone-store.ts +0 -72
- package/src/execution/turn-limiter.ts +0 -102
- package/src/execution/types.ts +0 -973
- package/src/execution/ui-channels.ts +0 -216
- package/src/execution/ui-interaction-model.ts +0 -48
- package/src/execution/ui-request-handler-factory.ts +0 -212
- package/src/execution/ui-request-observability.ts +0 -81
- package/src/execution/ui-request-queue.ts +0 -184
- package/src/execution/worktree-manager.ts +0 -688
- package/src/execution/worktree-registry.ts +0 -222
- package/src/orchestration/__tests__/__fixtures__/worker-template.snapshot.txt +0 -349
- package/src/orchestration/__tests__/agent-call-catch-fallback.test.ts +0 -202
- package/src/orchestration/__tests__/agent-call-stream.test.ts +0 -152
- package/src/orchestration/__tests__/args-validator.test.ts +0 -143
- package/src/orchestration/__tests__/config-loader.test.ts +0 -503
- package/src/orchestration/__tests__/error-recovery-handlers.test.ts +0 -809
- package/src/orchestration/__tests__/error-recovery-postmessage-defense.test.ts +0 -405
- package/src/orchestration/__tests__/error-recovery-serialize-failed-result.test.ts +0 -56
- package/src/orchestration/__tests__/error-recovery-workflow-call.test.ts +0 -166
- package/src/orchestration/__tests__/execute-agent-call.test.ts +0 -451
- package/src/orchestration/__tests__/jsonl-run-store-corrupt-entry.test.ts +0 -150
- package/src/orchestration/__tests__/jsonl-run-store-loadall-sources.test.ts +0 -171
- package/src/orchestration/__tests__/jsonl-run-store-retention.test.ts +0 -202
- package/src/orchestration/__tests__/jsonl-run-store-session-file.test.ts +0 -1030
- package/src/orchestration/__tests__/launcher-nested-workflow.test.ts +0 -600
- package/src/orchestration/__tests__/lifecycle-runid-injection.test.ts +0 -96
- package/src/orchestration/__tests__/lifecycle.test.ts +0 -659
- package/src/orchestration/__tests__/non-cloneable-return-e2e.test.ts +0 -95
- package/src/orchestration/__tests__/review-fix-loop-e2e.test.ts +0 -2025
- package/src/orchestration/__tests__/script-lint.test.ts +0 -831
- package/src/orchestration/__tests__/skill-discovery.test.ts +0 -201
- package/src/orchestration/__tests__/test-mocks.ts +0 -197
- package/src/orchestration/__tests__/worker-exit-without-result.test.ts +0 -368
- package/src/orchestration/__tests__/worker-host.test.ts +0 -120
- package/src/orchestration/__tests__/worker-returnmeta-passthrough.test.ts +0 -164
- package/src/orchestration/__tests__/worker-script-builder-runtime.test.ts +0 -563
- package/src/orchestration/__tests__/worker-script-builder.test.ts +0 -309
- package/src/orchestration/__tests__/worker-script-template-snapshot.test.ts +0 -129
- package/src/orchestration/__tests__/workflow-nesting-e2e.test.ts +0 -317
- package/src/orchestration/__tests__/workflow-script-lint-memo.test.ts +0 -110
- package/src/orchestration/__tests__/workflows-e2e.test.ts +0 -537
- package/src/orchestration/agent-opts-resolver.ts +0 -174
- package/src/orchestration/args-validator.ts +0 -127
- package/src/orchestration/config-loader.ts +0 -315
- package/src/orchestration/error-recovery.ts +0 -1018
- package/src/orchestration/execute-agent-call.ts +0 -256
- package/src/orchestration/launcher.ts +0 -455
- package/src/orchestration/lifecycle.ts +0 -399
- package/src/orchestration/models/__tests__/budget.test.ts +0 -307
- package/src/orchestration/models/__tests__/trace.test.ts +0 -408
- package/src/orchestration/models/agent-call.ts +0 -83
- package/src/orchestration/models/budget.ts +0 -118
- package/src/orchestration/models/ports.ts +0 -164
- package/src/orchestration/models/run-runtime.ts +0 -104
- package/src/orchestration/models/run-spec.ts +0 -83
- package/src/orchestration/models/run-state.ts +0 -44
- package/src/orchestration/models/trace.ts +0 -183
- package/src/orchestration/models/types.ts +0 -301
- package/src/orchestration/models/workflow-run.ts +0 -254
- package/src/orchestration/models/workflow-script-registry.ts +0 -35
- package/src/orchestration/models/workflow-script.ts +0 -117
- package/src/orchestration/script-lint.ts +0 -766
- package/src/orchestration/skill-discovery.ts +0 -115
- package/src/orchestration/worker-handle.ts +0 -115
- package/src/orchestration/worker-host.ts +0 -98
- package/src/orchestration/worker-script-builder.ts +0 -421
- package/src/orchestration/workflow-files.ts +0 -85
- package/src/orchestration/workflow-script-registry-impl.ts +0 -133
- package/src/shared/__tests__/agent-ref.test.ts +0 -34
- package/src/shared/__tests__/meta-parser.test.ts +0 -304
- package/src/shared/__tests__/model-ref.test.ts +0 -306
- package/src/shared/__tests__/resource-discovery-manifest-cache.test.ts +0 -280
- package/src/shared/__tests__/resource-discovery.test.ts +0 -736
- package/src/shared/__tests__/resource-meta.test.ts +0 -51
- package/src/shared/__tests__/schema-jsonify.test.ts +0 -81
- package/src/shared/__tests__/timer-delay.test.ts +0 -61
- package/src/shared/agent-event.ts +0 -13
- package/src/shared/agent-ref.ts +0 -57
- package/src/shared/meta-parser.ts +0 -261
- package/src/shared/model-ref.ts +0 -286
- package/src/shared/resource-discovery.ts +0 -811
- package/src/shared/resource-meta.ts +0 -65
- package/src/shared/schema-env.ts +0 -44
- package/src/shared/schema-jsonify.ts +0 -58
- package/src/shared/timer-delay.ts +0 -54
- package/src/shared/xml-injection.ts +0 -35
- package/workflows/README.md +0 -81
- package/workflows/_shared/agent-refs.cjs +0 -40
- package/workflows/chain.js +0 -131
- package/workflows/map-reduce.js +0 -174
- package/workflows/parallel.js +0 -148
- package/workflows/review-fix-loop-utils.cjs +0 -1309
- package/workflows/review-fix-loop.js +0 -1404
- package/workflows/scatter-gather.js +0 -178
|
@@ -16,25 +16,27 @@ import {
|
|
|
16
16
|
isGuiCapable,
|
|
17
17
|
} from "@xyz-agent/extension-protocol";
|
|
18
18
|
|
|
19
|
-
import { SLUG_MAX_LENGTH } from "
|
|
20
|
-
import { computeElapsedSeconds, projectOutcome } from "
|
|
21
|
-
import { isResumable } from "
|
|
22
|
-
import type { ExecutionRecord } from "
|
|
23
|
-
import type { ModelInfo } from "
|
|
24
|
-
import type { SubagentService } from "
|
|
25
|
-
import { displayAgentName } from "
|
|
19
|
+
import { SLUG_MAX_LENGTH } from "@zhushanwen/subagent-core/execution/execute-options-mapper.ts";
|
|
20
|
+
import { computeElapsedSeconds, projectOutcome } from "@zhushanwen/subagent-core/execution/execution-record.ts";
|
|
21
|
+
import { isResumable } from "@zhushanwen/subagent-core/execution/lifecycle-predicates.ts";
|
|
22
|
+
import type { ExecutionRecord } from "@zhushanwen/subagent-core/execution/types.ts";
|
|
23
|
+
import type { ModelInfo } from "@zhushanwen/subagent-core/execution/model-resolver.ts";
|
|
24
|
+
import type { SubagentService } from "@zhushanwen/subagent-core/execution/subagent-service.ts";
|
|
25
|
+
import { displayAgentName } from "@zhushanwen/subagent-core/shared/agent-ref.ts";
|
|
26
26
|
import type {
|
|
27
27
|
BgResponse,
|
|
28
28
|
CancelResponse,
|
|
29
29
|
CloseResponse,
|
|
30
30
|
ExecutionStatus,
|
|
31
31
|
ExternalState,
|
|
32
|
+
ForkFromResponse,
|
|
32
33
|
ListResponse,
|
|
33
34
|
MessageResponse,
|
|
34
35
|
SubagentListItem,
|
|
35
36
|
SubagentRecord,
|
|
36
37
|
SubagentToolResult,
|
|
37
|
-
} from "
|
|
38
|
+
} from "@zhushanwen/subagent-core/execution/types.ts";
|
|
39
|
+
import { ResurrectDeniedError } from "@zhushanwen/subagent-core/execution/types.ts";
|
|
38
40
|
import { mapRunIcon, mapRunStatus } from "./gui-mappers.ts";
|
|
39
41
|
|
|
40
42
|
// ============================================================
|
|
@@ -126,6 +128,100 @@ export interface CancelHandlerResult {
|
|
|
126
128
|
response: CancelResponse;
|
|
127
129
|
}
|
|
128
130
|
|
|
131
|
+
// ============================================================
|
|
132
|
+
// [v8.5 A1/B] message 拒绝文案分流 + fork-from 引导语框架
|
|
133
|
+
// ============================================================
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* [v8.5 A1] message 拒绝时的可行动文案分流。
|
|
137
|
+
*
|
|
138
|
+
* 背景:getRecordForAction 冷查只认 status==='running'(SP-2 可续聊重建),任何终态/
|
|
139
|
+
* 异归属记录都落到同一个「not found or not owned」错误,把两类完全不同的场景混为一谈:
|
|
140
|
+
* - user-close/cancelled:用户主动告别,记录真没了 → 引导 start 新的
|
|
141
|
+
* - parent-shutdown/gc/orphan 等:父会话重启/进程退出导致的断联,对话 jsonl 完好,
|
|
142
|
+
* resume/fork 基建现成 → 引导 fork-from 从旧记录接续
|
|
143
|
+
*
|
|
144
|
+
* 分流规则(消费方是 LLM,保持正交简单):
|
|
145
|
+
* - 找不到记录 → 原样透传 getRecordForAction 错误(id 打错最常见,原文案最准)
|
|
146
|
+
* - closed + user-close/cancelled →「已主动关闭,无法续聊」文案
|
|
147
|
+
* - 其余(closed 其他 reason / running 但异归属)→「断联可接续」文案
|
|
148
|
+
*/
|
|
149
|
+
export function endedMessageGuard(service: SubagentService, id: string, original: unknown): Error {
|
|
150
|
+
// [v8.5 D] 透明重生守卫拒绝(worktree/异进程占用)原样透传——错误自带完整行动语言,
|
|
151
|
+
// 若被下方 fork-from 指引改写会误导 agent 走已被判死的通道(types.ts 契约声明)。
|
|
152
|
+
if (original instanceof ResurrectDeniedError) return original;
|
|
153
|
+
let snap: SubagentRecord | undefined;
|
|
154
|
+
try {
|
|
155
|
+
snap = service.lookupRecordAnyState(id);
|
|
156
|
+
} catch {
|
|
157
|
+
snap = undefined;
|
|
158
|
+
}
|
|
159
|
+
if (!snap) {
|
|
160
|
+
return original instanceof Error ? original : new Error(String(original));
|
|
161
|
+
}
|
|
162
|
+
if (snap.status === "closed") {
|
|
163
|
+
if (snap.closedReason === "cancelled" || snap.closedReason === "user-close") {
|
|
164
|
+
return new Error(
|
|
165
|
+
`subagent ${id} was deliberately closed by user (closedReason: ${snap.closedReason}) — ` +
|
|
166
|
+
`it cannot be messaged or resumed; nothing can reattach to it. ` +
|
|
167
|
+
`Recovery: start a new subagent (action:'start'); use action:'list' with includeFinished:true to review its final output.`,
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
return new Error(
|
|
171
|
+
`subagent ${id} is ended but reconnectable (closedReason: ${snap.closedReason ?? "unknown"}` +
|
|
172
|
+
`${describeClosedContext(snap)}). Its conversation history is intact at ${snap.sessionFile ?? "(session file unavailable)"}. ` +
|
|
173
|
+
`Recovery: resume from that history with {"action":"fork-from","forkFromParam":{"sourceSubagentId":"${id}"}}, ` +
|
|
174
|
+
`or read key points directly from the session file.`,
|
|
175
|
+
);
|
|
176
|
+
}
|
|
177
|
+
// running 但未通过 getRecordForAction:记录属于当前进程外的另一个 session 树
|
|
178
|
+
//(主会话重启前的遗留态,或其他并发 pi 进程的活跃 subagent)。无论哪种,历史
|
|
179
|
+
// jsonl 只读安全,fork-from 快照接续均有效。
|
|
180
|
+
return new Error(
|
|
181
|
+
`subagent ${id} is alive but belongs to a different session tree than this one` +
|
|
182
|
+
`${describeClosedContext(snap)}. You cannot message it from here. ` +
|
|
183
|
+
`Recovery: branch from its history with {"action":"fork-from","forkFromParam":{"sourceSubagentId":"${id}"}}` +
|
|
184
|
+
`${snap.sessionFile ? ` (source session: ${snap.sessionFile})` : ``}; otherwise start a new subagent.`,
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/** 终态快照的上下文人话短语(仅作补充描述,主分支逻辑在 endedMessageGuard)。 */
|
|
189
|
+
function describeClosedContext(r: SubagentRecord): string {
|
|
190
|
+
switch (r.closedReason) {
|
|
191
|
+
case "parent-shutdown":
|
|
192
|
+
return " — it was disconnected when the previous parent session exited";
|
|
193
|
+
case "parent-fork":
|
|
194
|
+
return " — it was detached when the previous parent session forked";
|
|
195
|
+
case "parent-new":
|
|
196
|
+
return " — it was detached when the previous parent session switched";
|
|
197
|
+
case "disconnected":
|
|
198
|
+
return " — it ended in a previous session (exact cause unknown)";
|
|
199
|
+
default:
|
|
200
|
+
return "";
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* [v8.5 B] fork-from 开场引导语框架(prompt 未指定时注入):先从继承的历史重建状态
|
|
206
|
+
* 再继续,防猜。
|
|
207
|
+
*/
|
|
208
|
+
const FORK_FROM_DEFAULT_PROMPT =
|
|
209
|
+
"You are taking over work from a previous subagent whose full conversation history you inherited (--fork). " +
|
|
210
|
+
"First reconstruct state from that history: list what was already done, decided, and left unfinished (a few bullet lines). " +
|
|
211
|
+
"Then continue the remaining work to completion.";
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* [v8.5 B] 有显式接续指令时的包裹框架:指令在前、上下文重建要求在后——指令首见即达,
|
|
215
|
+
* 不湮没在元说明里(弱模型友好)。
|
|
216
|
+
*/
|
|
217
|
+
function wrapForkFromPrompt(prompt: string): string {
|
|
218
|
+
return (
|
|
219
|
+
prompt.trim() +
|
|
220
|
+
"\n\n(You are continuing a previous subagent's inherited conversation via --fork. " +
|
|
221
|
+
"Reconstruct state from that history first — what was done, decided, and remains — then execute the instruction above.)"
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
|
|
129
225
|
// ============================================================
|
|
130
226
|
// helpers(模块内)
|
|
131
227
|
// ============================================================
|
|
@@ -386,8 +482,16 @@ export async function messageHandler(
|
|
|
386
482
|
);
|
|
387
483
|
const interrupt = input?.interrupt === true;
|
|
388
484
|
|
|
389
|
-
// 归属守卫(决策 3):getRecordForAction 内部校验 rootSessionId
|
|
390
|
-
|
|
485
|
+
// 归属守卫(决策 3):getRecordForAction 内部校验 rootSessionId。
|
|
486
|
+
// [v8.5 A1] 拒绝时经 endedMessageGuard 分流:找不到 → 原错误;user-close/cancelled
|
|
487
|
+
// → 「已主动关闭」;断联/已完成/异归属 → fork-from 可行动指引。仅 message action
|
|
488
|
+
// 升级文案——close/cancel 维持原语义(它们不需要恢复通道)。
|
|
489
|
+
let record: ExecutionRecord;
|
|
490
|
+
try {
|
|
491
|
+
record = service.getRecordForAction(id, { allowReconnect: true });
|
|
492
|
+
} catch (err) {
|
|
493
|
+
throw endedMessageGuard(service, id, err);
|
|
494
|
+
}
|
|
391
495
|
|
|
392
496
|
// SP-5 one-shot upgrade:非 chatMode 的 active record(running/idle)收到 message 时
|
|
393
497
|
// 自动升级为 chatMode,后续走 deliverMessage 统一投递路径(热路径或冷路径 resume)。
|
|
@@ -462,6 +566,140 @@ export async function closeHandler(
|
|
|
462
566
|
return { kind: "close", subagentId: id, response: { closed: true } };
|
|
463
567
|
}
|
|
464
568
|
|
|
569
|
+
// ============================================================
|
|
570
|
+
// fork-from handler([v8.5 B] 断联恢复通道)
|
|
571
|
+
// ============================================================
|
|
572
|
+
|
|
573
|
+
export interface ForkFromHandlerInput {
|
|
574
|
+
sourceSubagentId?: string;
|
|
575
|
+
prompt?: string;
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
/** fork-from 领域对象(adapter 包成 forkFromResponse)。 */
|
|
579
|
+
export type ForkFromHandlerResult = {
|
|
580
|
+
kind: "fork-from";
|
|
581
|
+
/** 新 subagent 的 record id(后续续聊用 action:'message')。 */
|
|
582
|
+
subagentId: string;
|
|
583
|
+
/** 作为 --fork 继承源的旧记录 session 文件。 */
|
|
584
|
+
sourceSessionFile: string;
|
|
585
|
+
response: ForkFromResponse;
|
|
586
|
+
};
|
|
587
|
+
|
|
588
|
+
/**
|
|
589
|
+
* fork-from action handler:从旧 subagent 的会话历史 spawn 新 id 接续。
|
|
590
|
+
*
|
|
591
|
+
* 用于 subagent 因会话重启/进程退出而断联后的恢复:新进程以 --fork 指向旧 session
|
|
592
|
+
* 文件(copy-on-write 建分支会话),继承全部对话历史;源文件只读不续写。
|
|
593
|
+
* 旧记录本身不动——closed 单向状态机不变量、tryTransition 语义均不触碰。
|
|
594
|
+
*
|
|
595
|
+
* 守卫链(拒绝原因与行动语言对齐现有 MF-4 风格):
|
|
596
|
+
* 1. 本进程内存 running → 还活着,应走 message(防双写同一子 session 文件)
|
|
597
|
+
* 2. 不存在 → 引导 list 确认
|
|
598
|
+
* 3. 异进程活跃(磁盘 .alive pid 存活 / running 快照)→ 别处正跑,不可从此接续
|
|
599
|
+
* (同 id 双写风险;等待其结束或在其所属会话内操作)
|
|
600
|
+
* 4. tombstone/cancelled → 用户主动取消,真没了(不提供接续通道)
|
|
601
|
+
* 5. worktree 记录 → checkout 不可复用,fork 子进程 cwd 会回落主仓破坏隔离
|
|
602
|
+
* (对齐 deliverMessage 的 hadWorktree 守卫语义)
|
|
603
|
+
* 6. 无子 session 文件 → 无历史可继承(entry-only 孤儿:spawn 窗口期中断)
|
|
604
|
+
*
|
|
605
|
+
* @throws Error 各守卫命中 / service.execute 失败(引擎不支持等)
|
|
606
|
+
*/
|
|
607
|
+
export async function forkFromHandler(
|
|
608
|
+
service: SubagentService,
|
|
609
|
+
input: ForkFromHandlerInput | undefined,
|
|
610
|
+
): Promise<ForkFromHandlerResult> {
|
|
611
|
+
const id = input?.sourceSubagentId?.trim();
|
|
612
|
+
if (!id) throw new Error("forkFromParam.sourceSubagentId is required for action:'fork-from'");
|
|
613
|
+
const prompt = input?.prompt?.trim() ?? "";
|
|
614
|
+
const task = prompt ? wrapForkFromPrompt(prompt) : FORK_FROM_DEFAULT_PROMPT;
|
|
615
|
+
|
|
616
|
+
const source = assertAndLookupForkFromSource(service, id);
|
|
617
|
+
|
|
618
|
+
// slug 派生:源 slug + -resumed 后缀(截断到上限)。仅展示标签,不需唯一。
|
|
619
|
+
const baseSlug = (source.slug || source.agent || "resumed").slice(0, SLUG_MAX_LENGTH - "-resumed".length);
|
|
620
|
+
const handle = await service.execute({
|
|
621
|
+
task,
|
|
622
|
+
slug: `${baseSlug}-resumed`,
|
|
623
|
+
forkFromSessionFile: source.sessionFile,
|
|
624
|
+
});
|
|
625
|
+
|
|
626
|
+
return {
|
|
627
|
+
kind: "fork-from",
|
|
628
|
+
subagentId: handle.subagentId,
|
|
629
|
+
sourceSessionFile: source.sessionFile,
|
|
630
|
+
response: { newSubagentId: handle.subagentId, sourceSessionFile: source.sessionFile },
|
|
631
|
+
};
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
/** forkFromHandler 的守卫链(fork-from handler doc 的守卫 1–6 原样提取):按序校验
|
|
635
|
+
* 源记录可接续,命中即抛带行动语言的 Error;全部通过则返回源 SubagentRecord
|
|
636
|
+
* (守卫 6 已保证 sessionFile 非空,返回类型随之收窄)。 */
|
|
637
|
+
function assertAndLookupForkFromSource(service: SubagentService, id: string): SubagentRecord & { sessionFile: string } {
|
|
638
|
+
// 守卫 1:本进程内存 running —— 直接 message 即可,fork-from 会双写其 session 文件。
|
|
639
|
+
if (service.findRecord(id)) {
|
|
640
|
+
throw new Error(
|
|
641
|
+
`subagent ${id} is still active in this process — use action:'message' to continue it directly. ` +
|
|
642
|
+
`If you want a parallel branch from its history, close it first (action:'close'), then fork-from.`,
|
|
643
|
+
);
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
// 守卫 2:全态查找(内存 archived + 磁盘重建)。
|
|
647
|
+
const source = service.lookupRecordAnyState(id);
|
|
648
|
+
if (!source) {
|
|
649
|
+
throw new Error(
|
|
650
|
+
`No subagent record with id "${id}". It may never have existed or been garbage-collected — ` +
|
|
651
|
+
`use action:'list' with includeFinished:true to verify the id.`,
|
|
652
|
+
);
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
// 守卫 3:异进程活跃(磁盘分支 3 externalInstance = 另一进程的活 pid marker)。
|
|
656
|
+
// 双写防护:fork 虽 copy-on-write(历史 jsonl 只读),但源仍在异进程运行时接续容易
|
|
657
|
+
// 读到半截历史,等它结束再接更安全。判据只认 externalInstance(真实活 pid 探针
|
|
658
|
+
// 命中),不拦 status==='running' 的快照——后者含 B-1 跨重启回退重建的 running 记录
|
|
659
|
+
//(无活 pid,历史已完整落盘),它们正是 endedMessageGuard 指引 fork-from 的目标;
|
|
660
|
+
// 拦了会让 agent 在「建议 fork-from」与「fork-from 拒绝 running」两条错误间死循环。
|
|
661
|
+
if (source.externalInstance !== undefined) {
|
|
662
|
+
throw new Error(
|
|
663
|
+
`subagent ${id} is still running in another process (alive pid marker present). ` +
|
|
664
|
+
`Recovery: wait until it finishes, or operate it in its own session; then retry fork-from.`,
|
|
665
|
+
);
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
// 守卫 4:主动告别(cancelled tombstone / user-close 正式关闭)——close 语义无旁路:
|
|
669
|
+
// fork-from 与 message 一致拒绝(guard 一致性规格),文案升级为统一「主动关闭」形态
|
|
670
|
+
// (含 closedReason 显式列入),与 deliverMessage 的 X 分支同语系不同落地(此处强调不可 branch)。
|
|
671
|
+
if (source.status === "closed" && (source.closedReason === "cancelled" || source.closedReason === "user-close")) {
|
|
672
|
+
throw new Error(
|
|
673
|
+
`subagent ${id} was deliberately closed by user (closedReason: ${source.closedReason}) — ` +
|
|
674
|
+
`deliberately-closed records cannot be resumed or branched from; nothing can reattach to them. ` +
|
|
675
|
+
`Recovery: start a fresh subagent (action:'start'); use action:'list' with includeFinished:true to review its final output.`,
|
|
676
|
+
);
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
// 守卫 5:worktree 记录 —— WorktreeHandle 不可序列化,checkout 已被 reaper/cleanup
|
|
680
|
+
// 回收;fork 子进程若复用旧路径会回落主 repo(破坏文件隔离)。与 deliverMessage 的
|
|
681
|
+
// hadWorktree 守卫同一判据同一理由。
|
|
682
|
+
if (source.worktree === true) {
|
|
683
|
+
throw new Error(
|
|
684
|
+
`subagent ${id} was created with worktree isolation; that binding was lost when its parent process ended. ` +
|
|
685
|
+
`Resuming from its history would run outside the original worktree isolation. ` +
|
|
686
|
+
`Recovery: start a new subagent with action:'start' and carry over key findings manually ` +
|
|
687
|
+
`(read ${source.sessionFile ?? "its session file"} if needed).`,
|
|
688
|
+
);
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
// 守卫 6:无子 session 文件(entry-born 孤儿:spawn 窗口期中断,从未开跑)。
|
|
692
|
+
const sessionFile = source.sessionFile;
|
|
693
|
+
if (!sessionFile) {
|
|
694
|
+
throw new Error(
|
|
695
|
+
`subagent ${id} has no child session file to inherit from (it never started successfully). ` +
|
|
696
|
+
`Recovery: start a fresh subagent (action:'start') describing the task again.`,
|
|
697
|
+
);
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
return { ...source, sessionFile };
|
|
701
|
+
}
|
|
702
|
+
|
|
465
703
|
// ============================================================
|
|
466
704
|
// adapter(领域对象 → SubagentToolResult + {content, details})
|
|
467
705
|
// ============================================================
|
|
@@ -475,7 +713,8 @@ type AdapterInput =
|
|
|
475
713
|
| { action: "list"; domain: ListHandlerResult }
|
|
476
714
|
| { action: "cancel"; domain: CancelHandlerResult }
|
|
477
715
|
| { action: "message"; domain: MessageHandlerResult }
|
|
478
|
-
| { action: "close"; domain: CloseHandlerResult }
|
|
716
|
+
| { action: "close"; domain: CloseHandlerResult }
|
|
717
|
+
| { action: "fork-from"; domain: ForkFromHandlerResult };
|
|
479
718
|
|
|
480
719
|
export function adapter(
|
|
481
720
|
input: AdapterInput,
|
|
@@ -495,6 +734,11 @@ export function adapter(
|
|
|
495
734
|
result = { action, subagentId: input.domain.subagentId, sessionFile: null, cancelResponse: input.domain.response };
|
|
496
735
|
} else if (action === "message") {
|
|
497
736
|
result = { action, subagentId: input.domain.subagentId, sessionFile: null, messageResponse: input.domain.response };
|
|
737
|
+
} else if (action === "fork-from") {
|
|
738
|
+
// MF-3 同款瘦身:sourceSessionFile 真实路径只在 forkFromResponse 内层(LLM 接续
|
|
739
|
+
// 不需要拼路径,需要时 list/details 可取);顶层 sessionFile 保持 null 一致性。
|
|
740
|
+
const d = input.domain;
|
|
741
|
+
result = { action, subagentId: d.subagentId, sessionFile: null, forkFromResponse: d.response };
|
|
498
742
|
} else {
|
|
499
743
|
// action === "close"
|
|
500
744
|
result = { action, subagentId: input.domain.subagentId, sessionFile: null, closeResponse: input.domain.response };
|
|
@@ -565,6 +809,14 @@ export function buildGuiComponent(
|
|
|
565
809
|
items: [{ label: "messaged", value: input.domain.subagentId, severity: "ok" }],
|
|
566
810
|
});
|
|
567
811
|
}
|
|
812
|
+
if (action === "fork-from") {
|
|
813
|
+
return guiComponent("stats-line", {
|
|
814
|
+
items: [
|
|
815
|
+
{ label: "forked-from", value: input.domain.sourceSessionFile },
|
|
816
|
+
{ label: "new subagent", value: input.domain.subagentId, severity: "ok" },
|
|
817
|
+
],
|
|
818
|
+
});
|
|
819
|
+
}
|
|
568
820
|
if (action === "close") {
|
|
569
821
|
return guiComponent("stats-line", {
|
|
570
822
|
items: [{ label: "closed", value: input.domain.subagentId, severity: "warn" }],
|
|
@@ -12,22 +12,18 @@
|
|
|
12
12
|
// 编译本 schema 并断言 required/description/enum/pattern 存活——SW 自身测试环境
|
|
13
13
|
// 把 typebox alias 到 mock(丢 options),SO 侧测试以真实构造为对照基准。
|
|
14
14
|
//
|
|
15
|
-
// 层归属:Interface(工具 schema 的家)。SLUG_MAX_LENGTH
|
|
16
|
-
//
|
|
17
|
-
//
|
|
15
|
+
// 层归属:Interface(工具 schema 的家)。SLUG_MAX_LENGTH 权威定义回归 core 侧
|
|
16
|
+
// execution/execute-options-mapper.ts(subagent-core 包抽离 u1-move:core 切面不得
|
|
17
|
+
// 反向 import 壳侧 interface,常量随之内化)——此处 re-export 保持既有 import 路径。
|
|
18
18
|
|
|
19
19
|
import { StringEnum } from "@earendil-works/pi-ai";
|
|
20
20
|
import { type Static, Type } from "typebox";
|
|
21
21
|
|
|
22
|
-
import { THINKING_ORDER } from "
|
|
22
|
+
import { THINKING_ORDER } from "@zhushanwen/subagent-core/shared/model-ref.ts";
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
* 历史值 20 偏紧——描述性 slug 如 "audit-structured-output"(23)/"fix-subagent-wf-tools"(21)
|
|
28
|
-
* 会撞上限,放宽到 35 兼顾「短到能塞进 TUI 标题行」与「容纳合理描述性 kebab-case 名」。
|
|
29
|
-
*/
|
|
30
|
-
export const SLUG_MAX_LENGTH = 35;
|
|
24
|
+
import { SLUG_MAX_LENGTH } from "@zhushanwen/subagent-core/execution/execute-options-mapper.ts";
|
|
25
|
+
|
|
26
|
+
export { SLUG_MAX_LENGTH };
|
|
31
27
|
|
|
32
28
|
// Params schema(跨包契约测试的真实 typebox 校验入口)。
|
|
33
29
|
//
|
|
@@ -42,8 +38,8 @@ export const SLUG_MAX_LENGTH = 35;
|
|
|
42
38
|
// (subagent_start / subagent_list / subagent_cancel),让每个 tool 的 schema 真实
|
|
43
39
|
// 反映必填性。勿在此基础上继续堆 action 条件逻辑——要加就拆 tool。
|
|
44
40
|
export const SubagentParams = Type.Object({
|
|
45
|
-
action: StringEnum(["start", "list", "cancel", "message", "close"], {
|
|
46
|
-
description: "Operation: 'start' runs a subagent, 'list' shows subagents, 'cancel' stops a background subagent, 'message' sends a follow-up to a running subagent (one-shot subagents are auto-upgraded to conversation mode on first message), 'close' ends a running subagent (conversation-mode or one-shot).",
|
|
41
|
+
action: StringEnum(["start", "list", "cancel", "message", "close", "fork-from"], {
|
|
42
|
+
description: "Operation: 'start' runs a subagent, 'list' shows subagents, 'cancel' stops a background subagent, 'message' sends a follow-up to a running subagent (one-shot subagents are auto-upgraded to conversation mode on first message), 'close' ends a running subagent (conversation-mode or one-shot), 'fork-from' spawns a NEW subagent inheriting an older one's history (recovery for restart-disconnected subagents; the old record is untouched).",
|
|
47
43
|
}),
|
|
48
44
|
// ── action:"start" fields (flattened to top level). task/slug REQUIRED for start. ──
|
|
49
45
|
// Missing/empty task or slug throws at runtime (startHandler).
|
|
@@ -150,6 +146,17 @@ export const SubagentParams = Type.Object({
|
|
|
150
146
|
description: "If true, terminate immediately even if mid-round (in-progress work is lost). If false (default), let the current round finish, then close. When idle, the subagent closes immediately regardless.",
|
|
151
147
|
})),
|
|
152
148
|
})),
|
|
149
|
+
// action:"fork-from" → forkFromParam.sourceSubagentId REQUIRED ([v8.5 B] 断联恢复通道).
|
|
150
|
+
// 从旧 subagent 的会话历史 spawn 新 id:新进程 --fork 指向旧 session 文件(copy-on-write,
|
|
151
|
+
// 源文件只读不续写);旧记录/状态机不动。pi 引擎限定(非 pi 在 execute 层拒绝)。
|
|
152
|
+
forkFromParam: Type.Optional(Type.Object({
|
|
153
|
+
sourceSubagentId: Type.String({
|
|
154
|
+
description: "REQUIRED for action:'fork-from'. The OLD subagentId whose conversation history becomes the inherited context of the new subagent. Works for records disconnected by a session restart or already finished; cancelled/worktree-bound/still-running ones are rejected with guidance.",
|
|
155
|
+
}),
|
|
156
|
+
prompt: Type.Optional(Type.String({
|
|
157
|
+
description: "Continuation instruction for the new subagent (what to do next on top of the inherited history). When omitted, a standard handover frame is injected: reconstruct done/decided/remaining from the inherited history, then continue to completion. Whitespace-only treated as omitted.",
|
|
158
|
+
})),
|
|
159
|
+
})),
|
|
153
160
|
});
|
|
154
161
|
|
|
155
162
|
/** Params schema 的 Static 投影(消费方经 `Static<typeof SubagentParams>` 使用,见 subagent-tool.ts)。 */
|
|
@@ -16,11 +16,11 @@ import type { AgentToolResult, ExtensionAPI, ExtensionContext, Theme } from "@ea
|
|
|
16
16
|
import { getLogger } from "@zhushanwen/pi-extension-logger";
|
|
17
17
|
import type { Static } from "typebox";
|
|
18
18
|
|
|
19
|
-
import { getSubagentService } from "
|
|
20
|
-
import type { SubagentToolResult } from "
|
|
19
|
+
import { getSubagentService } from "@zhushanwen/subagent-core/execution/subagent-service.ts";
|
|
20
|
+
import type { SubagentToolResult } from "@zhushanwen/subagent-core/execution/types.ts";
|
|
21
21
|
import { extractAgentName } from "./format.ts";
|
|
22
22
|
import { toGuiCtx } from "./gui-mappers.ts";
|
|
23
|
-
import { adapter, cancelHandler, closeHandler, listHandler, messageHandler, startHandler } from "./subagent-actions.ts";
|
|
23
|
+
import { adapter, cancelHandler, closeHandler, forkFromHandler, listHandler, messageHandler, startHandler } from "./subagent-actions.ts";
|
|
24
24
|
import { SubagentParams } from "./subagent-tool-schema.ts";
|
|
25
25
|
import { type RenderContext,renderSubagentCall, renderSubagentResult } from "./tool-render.ts";
|
|
26
26
|
|
|
@@ -71,13 +71,14 @@ function assertNever(value: never): string {
|
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
/** Subagent action 字面量联合(与 parameters schema 的 StringEnum 取值一致)。 */
|
|
74
|
-
type SubagentAction = "start" | "list" | "cancel" | "message" | "close";
|
|
74
|
+
type SubagentAction = "start" | "list" | "cancel" | "message" | "close" | "fork-from";
|
|
75
75
|
|
|
76
76
|
/** 类型守卫:把 schema 投影出的 string 形式 action 收窄回字面量联合。
|
|
77
77
|
* typebox v1 的 StringEnum Static 退化为 string,需运行时校验 + 类型收窄
|
|
78
78
|
* 才能恢复 switch 的 exhaustiveness 约束。 */
|
|
79
79
|
function isSubagentAction(value: string): value is SubagentAction {
|
|
80
|
-
return value === "start" || value === "list" || value === "cancel" || value === "message"
|
|
80
|
+
return value === "start" || value === "list" || value === "cancel" || value === "message"
|
|
81
|
+
|| value === "close" || value === "fork-from";
|
|
81
82
|
}
|
|
82
83
|
|
|
83
84
|
/** unknown 是否为含 model/thinkingLevel 的对象(类型守卫,替代全可选结构 `as`)。 */
|
|
@@ -165,6 +166,7 @@ action:"list" before action:"start" — a reusable running subagent may exist; c
|
|
|
165
166
|
- action:"close" — end a running subagent and release its resources. REQUIRED closeParam: { subagentId }. Optional: force (default false; true terminates mid-round immediately). Always close when done.
|
|
166
167
|
- action:"list" — list subagents. Pass listParam: { includeFinished?, limit? } (all optional). Read an item's sessionFile for full detail.
|
|
167
168
|
- action:"cancel" — stop a background subagent (legacy verb; for conversation-mode use close). REQUIRED cancelParam: { subagentId }.
|
|
169
|
+
- action:"fork-from" — recovery for subagents disconnected by a session restart/exit: spawns a NEW subagent inheriting the old one's full history via --fork (source read-only, old record untouched). REQUIRED forkFromParam: { sourceSubagentId }. Optional: prompt (continuation instruction; handover frame injected if omitted). Returns { newSubagentId, sourceSessionFile }. Rejected with guidance: cancelled / worktree-bound / still-running sources.
|
|
168
170
|
|
|
169
171
|
## Examples
|
|
170
172
|
|
|
@@ -177,6 +179,7 @@ action:"list" before action:"start" — a reusable running subagent may exist; c
|
|
|
177
179
|
{"action":"close","closeParam":{"subagentId":"sa-550e8400"}}
|
|
178
180
|
{"action":"list","listParam":{"includeFinished":false,"limit":20}}
|
|
179
181
|
{"action":"cancel","cancelParam":{"subagentId":"sa-550e8400"}}
|
|
182
|
+
{"action":"fork-from","forkFromParam":{"sourceSubagentId":"sa-550e8400","prompt":"continue from where it stopped; verify tests first"}}
|
|
180
183
|
\`\`\`
|
|
181
184
|
|
|
182
185
|
## After launching — do NOT wait
|
|
@@ -204,7 +207,7 @@ When to use:
|
|
|
204
207
|
- ✅ Long-interval rounds (>5min apart) → conversation:true + idleTimeoutMs increased
|
|
205
208
|
- ❌ Single exploration/lookup → default (one-shot)
|
|
206
209
|
|
|
207
|
-
idleTimeoutMs: per-subagent idle timeout (default 300000 / 5min). Env XYZ_SUBAGENT_IDLE_TIMEOUT_MS sets the global default; per-call param takes precedence.
|
|
210
|
+
idleTimeoutMs: per-subagent idle timeout (default 300000 / 5min). Env XYZ_SUBAGENT_IDLE_TIMEOUT_MS sets the global default; per-call param takes precedence.
|
|
208
211
|
|
|
209
212
|
## You cannot
|
|
210
213
|
|
|
@@ -323,6 +326,8 @@ const executeSubagent: SubagentExecuteCb = async (
|
|
|
323
326
|
return adapter({ action: "message", domain: await messageHandler(service, params.messageParam) }, toGuiCtx(_ctx));
|
|
324
327
|
case "close":
|
|
325
328
|
return adapter({ action: "close", domain: await closeHandler(service, params.closeParam) }, toGuiCtx(_ctx));
|
|
329
|
+
case "fork-from":
|
|
330
|
+
return adapter({ action: "fork-from", domain: await forkFromHandler(service, params.forkFromParam) }, toGuiCtx(_ctx));
|
|
326
331
|
default:
|
|
327
332
|
// assertNever:让 exhaustiveness 成为承重约束——新增 action 时 tsc 报错,
|
|
328
333
|
// 而非悄悄落入此分支。
|
|
@@ -9,9 +9,9 @@
|
|
|
9
9
|
|
|
10
10
|
import type { ExtensionAPI, ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
|
|
11
11
|
|
|
12
|
-
import { getSubagentService } from "
|
|
13
|
-
import type { SubagentService } from "
|
|
14
|
-
import { displayAgentName } from "
|
|
12
|
+
import { getSubagentService } from "@zhushanwen/subagent-core/execution/subagent-service.ts";
|
|
13
|
+
import type { SubagentService } from "@zhushanwen/subagent-core/execution/subagent-service.ts";
|
|
14
|
+
import { displayAgentName } from "@zhushanwen/subagent-core/shared/agent-ref.ts";
|
|
15
15
|
import { messageHandler, startHandler } from "./subagent-actions.ts";
|
|
16
16
|
import { parseSubagentRpcCommand } from "./command-actions.ts";
|
|
17
17
|
import type { SubagentRpcAction } from "./command-actions.ts";
|
|
@@ -24,8 +24,8 @@ import type { AgentToolResult, Theme } from "@earendil-works/pi-coding-agent";
|
|
|
24
24
|
import type {
|
|
25
25
|
ListResponse,
|
|
26
26
|
SubagentToolResult,
|
|
27
|
-
} from "
|
|
28
|
-
import { displayAgentName } from "
|
|
27
|
+
} from "@zhushanwen/subagent-core/execution/types.ts";
|
|
28
|
+
import { displayAgentName } from "@zhushanwen/subagent-core/shared/agent-ref.ts";
|
|
29
29
|
import {
|
|
30
30
|
extractAgentName,
|
|
31
31
|
firstLine,
|
|
@@ -208,6 +208,15 @@ function buildCompactLines(d: SubagentToolResult, theme: ThemeLike): string[] {
|
|
|
208
208
|
width,
|
|
209
209
|
)];
|
|
210
210
|
}
|
|
211
|
+
// ── fork-from 分支:接续确认行([v8.5 B])──
|
|
212
|
+
if (d.action === "fork-from" && d.forkFromResponse) {
|
|
213
|
+
const src = shortSessionLabel(d.forkFromResponse.sourceSessionFile);
|
|
214
|
+
return [truncLine(
|
|
215
|
+
`${theme.fg("accent", "⑂")} ${theme.fg("dim", "forked-from ")}${theme.fg("accent", src)}` +
|
|
216
|
+
` ${theme.fg("dim", "→ new: ")}${theme.fg("accent", d.subagentId ?? "?")}`,
|
|
217
|
+
width,
|
|
218
|
+
)];
|
|
219
|
+
}
|
|
211
220
|
// ── start 分支:background ──
|
|
212
221
|
if ("bgResponse" in d) {
|
|
213
222
|
return [truncLine(
|
|
@@ -234,6 +243,16 @@ function buildExpandedLines(d: SubagentToolResult, theme: ThemeLike): string[] {
|
|
|
234
243
|
width,
|
|
235
244
|
)];
|
|
236
245
|
}
|
|
246
|
+
if (d.action === "fork-from" && d.forkFromResponse) {
|
|
247
|
+
// expanded 与 compact 同形(一次性 block 无细节可展开),另附源文件完整路径行。
|
|
248
|
+
return [
|
|
249
|
+
truncLine(
|
|
250
|
+
`${theme.fg("accent", "⑂")} ${theme.fg("dim", "forked-from ")}${theme.fg("accent", d.forkFromResponse.sourceSessionFile)}` +
|
|
251
|
+
` ${theme.fg("dim", "→ new: ")}${theme.fg("accent", d.subagentId ?? "?")}`,
|
|
252
|
+
width,
|
|
253
|
+
),
|
|
254
|
+
];
|
|
255
|
+
}
|
|
237
256
|
|
|
238
257
|
const lines: string[] = [];
|
|
239
258
|
// bg 占位 expanded 与 compact 同(一次性 block 无细节可展开)
|
|
@@ -261,11 +280,24 @@ function isDetailsStructurallyComplete(d: SubagentToolResult): boolean {
|
|
|
261
280
|
return "listResponse" in d;
|
|
262
281
|
case "cancel":
|
|
263
282
|
return "cancelResponse" in d;
|
|
283
|
+
case "fork-from":
|
|
284
|
+
// [v8.5 B] 新 action 直接纳入 guard:缺内层分组才 fallback。
|
|
285
|
+
// message/close 维持历史现状(不落此 switch 显式分支,走 extractResultError
|
|
286
|
+
// 回显 content 首行)不变,避免触碰现有渲染回归面——review MF-13 曾引入
|
|
287
|
+
// message/close 显式分支后回退:无对应渲染分支却判「结构完整」会改走
|
|
288
|
+
// generic 无响应渲染,属静默行为变更。
|
|
289
|
+
return "forkFromResponse" in d;
|
|
264
290
|
default:
|
|
265
291
|
return false;
|
|
266
292
|
}
|
|
267
293
|
}
|
|
268
294
|
|
|
295
|
+
/** fork-from 渲染用的源文件短标签(basename;失败时原样返回——渲染不应抛错)。 */
|
|
296
|
+
function shortSessionLabel(file: string): string {
|
|
297
|
+
const idx = file.lastIndexOf("/");
|
|
298
|
+
return idx >= 0 ? file.slice(idx + 1) : file;
|
|
299
|
+
}
|
|
300
|
+
|
|
269
301
|
/**
|
|
270
302
|
* 从 tool result 的 content 里提取错误文本。
|
|
271
303
|
*
|
|
@@ -30,12 +30,12 @@ import {
|
|
|
30
30
|
guiResult,
|
|
31
31
|
isGuiCapable,
|
|
32
32
|
} from "@xyz-agent/extension-protocol";
|
|
33
|
-
import type { WorkflowScriptRegistry } from "
|
|
34
|
-
import { lintScript } from "
|
|
35
|
-
import { deleteWorkflow, saveWorkflow } from "
|
|
33
|
+
import type { WorkflowScriptRegistry } from "@zhushanwen/subagent-core/orchestration/models/workflow-script-registry.ts";
|
|
34
|
+
import { lintScript } from "@zhushanwen/subagent-core/orchestration/script-lint.ts";
|
|
35
|
+
import { deleteWorkflow, saveWorkflow } from "@zhushanwen/subagent-core/orchestration/workflow-files.ts";
|
|
36
36
|
import { toGuiCtx } from "./gui-mappers.ts";
|
|
37
37
|
import { renderTextFallback } from "./views/format.ts";
|
|
38
|
-
import { parseResourceMetaDetailed } from "
|
|
38
|
+
import { parseResourceMetaDetailed } from "@zhushanwen/subagent-core/shared/meta-parser.ts";
|
|
39
39
|
|
|
40
40
|
// ── Parameter schema ─────────────────────────────────────────
|
|
41
41
|
|
|
@@ -31,12 +31,12 @@ import {
|
|
|
31
31
|
} from "@xyz-agent/extension-protocol";
|
|
32
32
|
import { type Static, Type } from "typebox";
|
|
33
33
|
|
|
34
|
-
import { SLUG_MAX_LENGTH } from "
|
|
35
|
-
import { THINKING_ORDER } from "
|
|
36
|
-
import type { LauncherDeps } from "
|
|
37
|
-
import { abortRun, runWorkflow } from "
|
|
38
|
-
import type { RunStore } from "
|
|
39
|
-
import type { WorkflowRun } from "
|
|
34
|
+
import { SLUG_MAX_LENGTH } from "@zhushanwen/subagent-core/execution/execute-options-mapper.ts";
|
|
35
|
+
import { THINKING_ORDER } from "@zhushanwen/subagent-core/execution/model-resolver.ts";
|
|
36
|
+
import type { LauncherDeps } from "@zhushanwen/subagent-core/orchestration/launcher.ts";
|
|
37
|
+
import { abortRun, runWorkflow } from "@zhushanwen/subagent-core/orchestration/lifecycle.ts";
|
|
38
|
+
import type { RunStore } from "@zhushanwen/subagent-core/orchestration/models/ports.ts";
|
|
39
|
+
import type { WorkflowRun } from "@zhushanwen/subagent-core/orchestration/models/workflow-run.ts";
|
|
40
40
|
import { mapRunIcon, mapRunStatus, toGuiCtx } from "./gui-mappers.ts";
|
|
41
41
|
import {
|
|
42
42
|
acquireReentryGuard,
|
|
@@ -33,11 +33,11 @@ import {
|
|
|
33
33
|
countAllToolCalls,
|
|
34
34
|
getAllToolCalls,
|
|
35
35
|
projectLiveProgress,
|
|
36
|
-
} from "
|
|
37
|
-
import type { ExecutionTraceNode } from "
|
|
38
|
-
import type { WorkflowRun } from "
|
|
39
|
-
import { saveWorkflow } from "
|
|
40
|
-
import { displayAgentName } from "
|
|
36
|
+
} from "@zhushanwen/subagent-core/execution/execution-record.ts";
|
|
37
|
+
import type { ExecutionTraceNode } from "@zhushanwen/subagent-core/orchestration/models/types.ts";
|
|
38
|
+
import type { WorkflowRun } from "@zhushanwen/subagent-core/orchestration/models/workflow-run.ts";
|
|
39
|
+
import { saveWorkflow } from "@zhushanwen/subagent-core/orchestration/workflow-files.ts";
|
|
40
|
+
import { displayAgentName } from "@zhushanwen/subagent-core/shared/agent-ref.ts";
|
|
41
41
|
import {
|
|
42
42
|
BOX_BORDER_CHARS,
|
|
43
43
|
BUDGET_TOKENS_DIVISOR,
|
|
@@ -13,9 +13,9 @@
|
|
|
13
13
|
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
|
14
14
|
|
|
15
15
|
import { computeRenderSignature } from "../WorkflowsView.ts";
|
|
16
|
-
import type { ExecutionRecord } from "
|
|
17
|
-
import type { ExecutionTraceNode, WorkerLogEntry } from "
|
|
18
|
-
import type { WorkflowRun } from "
|
|
16
|
+
import type { ExecutionRecord } from "@zhushanwen/subagent-core/execution/types.ts";
|
|
17
|
+
import type { ExecutionTraceNode, WorkerLogEntry } from "@zhushanwen/subagent-core/orchestration/models/types.ts";
|
|
18
|
+
import type { WorkflowRun } from "@zhushanwen/subagent-core/orchestration/models/workflow-run.ts";
|
|
19
19
|
|
|
20
20
|
// ── Fixtures(duck typing,对齐 detail-content-session-file.test.ts 先例)──
|
|
21
21
|
|
|
@@ -9,8 +9,8 @@ import { describe, expect, it } from "vitest";
|
|
|
9
9
|
|
|
10
10
|
import { buildDetailContent } from "../detail-content.ts";
|
|
11
11
|
import type { ThemeLike } from "../format.ts";
|
|
12
|
-
import type { ExecutionTraceNode } from "
|
|
13
|
-
import type { WorkflowRun } from "
|
|
12
|
+
import type { ExecutionTraceNode } from "@zhushanwen/subagent-core/orchestration/models/types.ts";
|
|
13
|
+
import type { WorkflowRun } from "@zhushanwen/subagent-core/orchestration/models/workflow-run.ts";
|
|
14
14
|
|
|
15
15
|
/** plain theme: fg/bold 直接返回原文,无 ANSI 色码——测试断言纯文本。 */
|
|
16
16
|
const plainTheme: ThemeLike = {
|
|
@@ -12,10 +12,10 @@
|
|
|
12
12
|
|
|
13
13
|
import { Key, matchesKey } from "@earendil-works/pi-tui";
|
|
14
14
|
|
|
15
|
-
import { getAllToolCalls, projectLiveProgress } from "
|
|
16
|
-
import type { AgentEventLogEntry } from "
|
|
17
|
-
import type { ExecutionTraceNode } from "
|
|
18
|
-
import type { WorkflowRun } from "
|
|
15
|
+
import { getAllToolCalls, projectLiveProgress } from "@zhushanwen/subagent-core/execution/execution-record.ts";
|
|
16
|
+
import type { AgentEventLogEntry } from "@zhushanwen/subagent-core/execution/types.ts";
|
|
17
|
+
import type { ExecutionTraceNode } from "@zhushanwen/subagent-core/orchestration/models/types.ts";
|
|
18
|
+
import type { WorkflowRun } from "@zhushanwen/subagent-core/orchestration/models/workflow-run.ts";
|
|
19
19
|
import {
|
|
20
20
|
BOX_BORDER_CHARS,
|
|
21
21
|
BUDGET_TOKENS_DIVISOR,
|