@stigmer/runner 3.15.0 → 3.15.2-dev.20260913223433
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 +2 -4
- package/dist/.build-fingerprint +1 -1
- package/dist/__test-utils__/execution-record-fixture.d.ts +14 -0
- package/dist/__test-utils__/execution-record-fixture.js +4 -0
- package/dist/__test-utils__/execution-record-fixture.js.map +1 -1
- package/dist/__test-utils__/file-review-projection.d.ts +40 -0
- package/dist/__test-utils__/file-review-projection.js +136 -0
- package/dist/__test-utils__/file-review-projection.js.map +1 -0
- package/dist/__test-utils__/harness-contract/types.d.ts +23 -1
- package/dist/__test-utils__/harness-contract/types.js +15 -0
- package/dist/__test-utils__/harness-contract/types.js.map +1 -1
- package/dist/__test-utils__/hermetic-activity.d.ts +44 -12
- package/dist/__test-utils__/hermetic-activity.js +52 -14
- package/dist/__test-utils__/hermetic-activity.js.map +1 -1
- package/dist/__test-utils__/model-registry-fixture.d.ts +32 -7
- package/dist/__test-utils__/model-registry-fixture.js +31 -7
- package/dist/__test-utils__/model-registry-fixture.js.map +1 -1
- package/dist/__test-utils__/turn-input-fixture.d.ts +1 -1
- package/dist/__test-utils__/turn-input-fixture.js +1 -1
- package/dist/__test-utils__/turn-input-fixture.js.map +1 -1
- package/dist/activities/call-agent.js +2 -2
- package/dist/activities/call-agent.js.map +1 -1
- package/dist/activities/execute-cursor/__test-utils__/contract-subject.js +45 -3
- package/dist/activities/execute-cursor/__test-utils__/contract-subject.js.map +1 -1
- package/dist/activities/execute-cursor/__test-utils__/hermetic-cursor.d.ts +0 -9
- package/dist/activities/execute-cursor/__test-utils__/hermetic-cursor.js +2 -41
- package/dist/activities/execute-cursor/__test-utils__/hermetic-cursor.js.map +1 -1
- package/dist/activities/execute-cursor/adapter.d.ts +7 -5
- package/dist/activities/execute-cursor/adapter.js +7 -5
- package/dist/activities/execute-cursor/adapter.js.map +1 -1
- package/dist/activities/execute-cursor/approval-policy.d.ts +5 -2
- package/dist/activities/execute-cursor/approval-policy.js +5 -2
- package/dist/activities/execute-cursor/approval-policy.js.map +1 -1
- package/dist/activities/execute-cursor/approval-state.d.ts +16 -8
- package/dist/activities/execute-cursor/approval-state.js +6 -3
- package/dist/activities/execute-cursor/approval-state.js.map +1 -1
- package/dist/activities/execute-cursor/cas-observations.d.ts +14 -2
- package/dist/activities/execute-cursor/cas-observations.js +19 -2
- package/dist/activities/execute-cursor/cas-observations.js.map +1 -1
- package/dist/activities/execute-cursor/cursor-capabilities.d.ts +8 -4
- package/dist/activities/execute-cursor/cursor-capabilities.js +21 -4
- package/dist/activities/execute-cursor/cursor-capabilities.js.map +1 -1
- package/dist/activities/execute-cursor/message-translator.d.ts +12 -20
- package/dist/activities/execute-cursor/message-translator.js +19 -32
- package/dist/activities/execute-cursor/message-translator.js.map +1 -1
- package/dist/activities/execute-cursor/prompt-builder.d.ts +48 -58
- package/dist/activities/execute-cursor/prompt-builder.js +76 -95
- package/dist/activities/execute-cursor/prompt-builder.js.map +1 -1
- package/dist/activities/execute-cursor/turn-boundary.d.ts +27 -55
- package/dist/activities/execute-cursor/turn-boundary.js +30 -90
- package/dist/activities/execute-cursor/turn-boundary.js.map +1 -1
- package/dist/activities/execute-cursor/turn-settle.d.ts +11 -7
- package/dist/activities/execute-cursor/turn-settle.js +37 -49
- package/dist/activities/execute-cursor/turn-settle.js.map +1 -1
- package/dist/activities/execute-cursor/turn-setup.d.ts +16 -24
- package/dist/activities/execute-cursor/turn-setup.js +29 -59
- package/dist/activities/execute-cursor/turn-setup.js.map +1 -1
- package/dist/activities/execute-cursor/turn-stream.d.ts +3 -8
- package/dist/activities/execute-cursor/turn-stream.js +9 -22
- package/dist/activities/execute-cursor/turn-stream.js.map +1 -1
- package/dist/activities/execute-cursor/turn.js +5 -1
- package/dist/activities/execute-cursor/turn.js.map +1 -1
- package/dist/activities/execute-deep-agent/__test-utils__/contract-subject.d.ts +93 -0
- package/dist/activities/execute-deep-agent/__test-utils__/contract-subject.js +348 -0
- package/dist/activities/execute-deep-agent/__test-utils__/contract-subject.js.map +1 -0
- package/dist/activities/execute-deep-agent/__test-utils__/hermetic-deep-agent.d.ts +170 -0
- package/dist/activities/execute-deep-agent/__test-utils__/hermetic-deep-agent.js +225 -0
- package/dist/activities/execute-deep-agent/__test-utils__/hermetic-deep-agent.js.map +1 -0
- package/dist/activities/execute-deep-agent/__test-utils__/hitl-script.d.ts +24 -0
- package/dist/activities/execute-deep-agent/__test-utils__/hitl-script.js +41 -0
- package/dist/activities/execute-deep-agent/__test-utils__/hitl-script.js.map +1 -0
- package/dist/activities/execute-deep-agent/__test-utils__/scripted-model-module.d.ts +54 -0
- package/dist/activities/execute-deep-agent/__test-utils__/scripted-model-module.js +72 -0
- package/dist/activities/execute-deep-agent/__test-utils__/scripted-model-module.js.map +1 -0
- package/dist/activities/execute-deep-agent/__test-utils__/scripted-model.d.ts +187 -23
- package/dist/activities/execute-deep-agent/__test-utils__/scripted-model.js +238 -27
- package/dist/activities/execute-deep-agent/__test-utils__/scripted-model.js.map +1 -1
- package/dist/activities/execute-deep-agent/adapter.d.ts +41 -0
- package/dist/activities/execute-deep-agent/adapter.js +78 -0
- package/dist/activities/execute-deep-agent/adapter.js.map +1 -0
- package/dist/activities/execute-deep-agent/cas-capture-observer.d.ts +8 -0
- package/dist/activities/execute-deep-agent/cas-capture-observer.js +9 -0
- package/dist/activities/execute-deep-agent/cas-capture-observer.js.map +1 -1
- package/dist/activities/execute-deep-agent/deep-agent-capabilities.d.ts +31 -0
- package/dist/activities/execute-deep-agent/deep-agent-capabilities.js +40 -0
- package/dist/activities/execute-deep-agent/deep-agent-capabilities.js.map +1 -0
- package/dist/activities/execute-deep-agent/execution-state.d.ts +4 -11
- package/dist/activities/execute-deep-agent/execution-state.js +4 -12
- package/dist/activities/execute-deep-agent/execution-state.js.map +1 -1
- package/dist/activities/execute-deep-agent/hitl.d.ts +49 -47
- package/dist/activities/execute-deep-agent/hitl.js +77 -103
- package/dist/activities/execute-deep-agent/hitl.js.map +1 -1
- package/dist/activities/execute-deep-agent/prompt-builder.d.ts +51 -23
- package/dist/activities/execute-deep-agent/prompt-builder.js +115 -76
- package/dist/activities/execute-deep-agent/prompt-builder.js.map +1 -1
- package/dist/activities/execute-deep-agent/status-builder-shared.d.ts +18 -32
- package/dist/activities/execute-deep-agent/status-builder-shared.js +10 -65
- package/dist/activities/execute-deep-agent/status-builder-shared.js.map +1 -1
- package/dist/activities/execute-deep-agent/streaming-side-effects.d.ts +10 -8
- package/dist/activities/execute-deep-agent/streaming-side-effects.js +12 -14
- package/dist/activities/execute-deep-agent/streaming-side-effects.js.map +1 -1
- package/dist/activities/execute-deep-agent/subagent-tracker.d.ts +36 -13
- package/dist/activities/execute-deep-agent/subagent-tracker.js +76 -39
- package/dist/activities/execute-deep-agent/subagent-tracker.js.map +1 -1
- package/dist/activities/execute-deep-agent/subagent-transformer.d.ts +25 -28
- package/dist/activities/execute-deep-agent/subagent-transformer.js +29 -82
- package/dist/activities/execute-deep-agent/subagent-transformer.js.map +1 -1
- package/dist/activities/execute-deep-agent/subagent-wiring.d.ts +3 -2
- package/dist/activities/execute-deep-agent/subagent-wiring.js +2 -2
- package/dist/activities/execute-deep-agent/subagent-wiring.js.map +1 -1
- package/dist/activities/execute-deep-agent/turn-settle.d.ts +42 -0
- package/dist/activities/execute-deep-agent/turn-settle.js +146 -0
- package/dist/activities/execute-deep-agent/turn-settle.js.map +1 -0
- package/dist/activities/execute-deep-agent/turn-setup.d.ts +212 -0
- package/dist/activities/execute-deep-agent/turn-setup.js +430 -0
- package/dist/activities/execute-deep-agent/turn-setup.js.map +1 -0
- package/dist/activities/execute-deep-agent/turn-stream.d.ts +97 -0
- package/dist/activities/execute-deep-agent/turn-stream.js +242 -0
- package/dist/activities/execute-deep-agent/turn-stream.js.map +1 -0
- package/dist/activities/execute-deep-agent/turn.d.ts +42 -0
- package/dist/activities/execute-deep-agent/turn.js +116 -0
- package/dist/activities/execute-deep-agent/turn.js.map +1 -0
- package/dist/activities/execute-deep-agent/v3-event-recorder.d.ts +6 -5
- package/dist/activities/execute-deep-agent/v3-event-recorder.js +6 -5
- package/dist/activities/execute-deep-agent/v3-event-recorder.js.map +1 -1
- package/dist/activities/execute-deep-agent/v3-events.d.ts +1 -1
- package/dist/activities/execute-deep-agent/v3-events.js +1 -1
- package/dist/activities/execute-deep-agent/v3-status-builder.d.ts +60 -17
- package/dist/activities/execute-deep-agent/v3-status-builder.js +72 -57
- package/dist/activities/execute-deep-agent/v3-status-builder.js.map +1 -1
- package/dist/harness/approval-decisions.d.ts +61 -0
- package/dist/harness/approval-decisions.js +102 -0
- package/dist/harness/approval-decisions.js.map +1 -0
- package/dist/harness/capabilities.d.ts +16 -5
- package/dist/harness/capabilities.js +9 -0
- package/dist/harness/capabilities.js.map +1 -1
- package/dist/harness/capture.d.ts +144 -0
- package/dist/harness/capture.js +219 -0
- package/dist/harness/capture.js.map +1 -0
- package/dist/harness/persist-chokepoint.d.ts +19 -4
- package/dist/harness/persist-chokepoint.js +17 -4
- package/dist/harness/persist-chokepoint.js.map +1 -1
- package/dist/harness/run-turn.js +115 -29
- package/dist/harness/run-turn.js.map +1 -1
- package/dist/harness/terminal-table.d.ts +40 -11
- package/dist/harness/terminal-table.js +58 -19
- package/dist/harness/terminal-table.js.map +1 -1
- package/dist/harness/turn-context.d.ts +141 -76
- package/dist/harness/turn-context.js +194 -99
- package/dist/harness/turn-context.js.map +1 -1
- package/dist/harness/types.d.ts +65 -12
- package/dist/harness/types.js +8 -2
- package/dist/harness/types.js.map +1 -1
- package/dist/harness-adapters.d.ts +12 -8
- package/dist/harness-adapters.js +17 -9
- package/dist/harness-adapters.js.map +1 -1
- package/dist/middleware/approval-gate.d.ts +1 -1
- package/dist/middleware/approval-gate.js +1 -1
- package/dist/middleware/approval-gate.js.map +1 -1
- package/dist/middleware/cost-advisory.d.ts +39 -0
- package/dist/middleware/{cost-cap.js → cost-advisory.js} +37 -55
- package/dist/middleware/cost-advisory.js.map +1 -0
- package/dist/middleware/index.d.ts +23 -12
- package/dist/middleware/index.js +26 -18
- package/dist/middleware/index.js.map +1 -1
- package/dist/middleware/types.d.ts +3 -2
- package/dist/runner-manager.js +1 -5
- package/dist/runner-manager.js.map +1 -1
- package/dist/runner.js +1 -5
- package/dist/runner.js.map +1 -1
- package/dist/shared/attachment-resolver.d.ts +41 -18
- package/dist/shared/attachment-resolver.js +178 -46
- package/dist/shared/attachment-resolver.js.map +1 -1
- package/dist/shared/attachment-zip.d.ts +85 -0
- package/dist/shared/attachment-zip.js +185 -0
- package/dist/shared/attachment-zip.js.map +1 -0
- package/dist/shared/connect-backfill.js +5 -4
- package/dist/shared/connect-backfill.js.map +1 -1
- package/dist/shared/cost-guard.d.ts +3 -3
- package/dist/shared/cost-guard.js +3 -3
- package/dist/shared/execution-status-writer.d.ts +5 -5
- package/dist/shared/execution-status-writer.js +5 -5
- package/dist/shared/extract-structured-output.d.ts +8 -7
- package/dist/shared/extract-structured-output.js +8 -7
- package/dist/shared/extract-structured-output.js.map +1 -1
- package/dist/shared/filereview/cas-progress.d.ts +1 -18
- package/dist/shared/filereview/cas-progress.js +4 -0
- package/dist/shared/filereview/cas-progress.js.map +1 -1
- package/dist/shared/filereview/cas-touched.d.ts +56 -0
- package/dist/shared/filereview/cas-touched.js +63 -0
- package/dist/shared/filereview/cas-touched.js.map +1 -0
- package/dist/shared/filereview/index.d.ts +2 -1
- package/dist/shared/filereview/index.js +2 -1
- package/dist/shared/filereview/index.js.map +1 -1
- package/dist/shared/mcp-resolver.d.ts +4 -5
- package/dist/shared/mcp-resolver.js +4 -5
- package/dist/shared/mcp-resolver.js.map +1 -1
- package/dist/shared/persist-decision.d.ts +3 -4
- package/dist/shared/persist-decision.js +3 -4
- package/dist/shared/persist-decision.js.map +1 -1
- package/dist/shared/plan-mode-permissions.d.ts +2 -2
- package/dist/shared/plan-mode-permissions.js +2 -2
- package/dist/shared/plan-mode-prompt.d.ts +1 -1
- package/dist/shared/plan-mode-prompt.js +1 -1
- package/dist/shared/prompt-sections.d.ts +163 -0
- package/dist/shared/prompt-sections.js +164 -0
- package/dist/shared/prompt-sections.js.map +1 -0
- package/dist/shared/skill-resolver.d.ts +4 -2
- package/dist/shared/skill-resolver.js +4 -2
- package/dist/shared/skill-resolver.js.map +1 -1
- package/dist/shared/tool-rounds.d.ts +32 -0
- package/dist/shared/tool-rounds.js +43 -0
- package/dist/shared/tool-rounds.js.map +1 -1
- package/dist/shared/tool-row.d.ts +34 -0
- package/dist/shared/tool-row.js +52 -0
- package/dist/shared/tool-row.js.map +1 -1
- package/dist/shared/workspace/session-provision.d.ts +3 -3
- package/dist/shared/workspace/session-provision.js +3 -3
- package/dist/shared/workspace/stigmer-link.d.ts +3 -3
- package/dist/shared/workspace/stigmer-link.js +3 -3
- package/dist/shared/workspace/writeback-coordinator.d.ts +15 -22
- package/dist/shared/workspace/writeback-coordinator.js +16 -53
- package/dist/shared/workspace/writeback-coordinator.js.map +1 -1
- package/dist/tools/index.d.ts +1 -1
- package/dist/tools/index.js +1 -1
- package/package.json +4 -4
- package/src/__test-utils__/__tests__/harness-contract-self-check.test.ts +1 -0
- package/src/__test-utils__/execution-record-fixture.ts +18 -2
- package/src/__test-utils__/file-review-projection.ts +156 -0
- package/src/__test-utils__/git-workspace-fixture.ts +58 -0
- package/src/__test-utils__/harness-boot-order-child.ts +7 -2
- package/src/__test-utils__/harness-contract/contract.ts +33 -20
- package/src/__test-utils__/harness-contract/recording-sink.ts +11 -1
- package/src/__test-utils__/harness-contract/runtime-contract.ts +328 -10
- package/src/__test-utils__/harness-contract/scripted-adapter.ts +38 -6
- package/src/__test-utils__/harness-contract/types.ts +27 -3
- package/src/__test-utils__/hermetic-activity.ts +52 -14
- package/src/__test-utils__/model-registry-fixture.ts +32 -7
- package/src/__test-utils__/module-specifiers.ts +24 -0
- package/src/__test-utils__/turn-input-fixture.ts +2 -2
- package/src/__tests__/harness-boot-order.test.ts +9 -2
- package/src/activities/call-agent.ts +2 -2
- package/src/activities/execute-cursor/__test-utils__/contract-subject.ts +47 -3
- package/src/activities/execute-cursor/__test-utils__/hermetic-cursor.ts +2 -48
- package/src/activities/execute-cursor/__tests__/approval-decisions-agree.test.ts +1 -1
- package/src/activities/execute-cursor/__tests__/approval-gate.test.ts +6 -1
- package/src/activities/execute-cursor/__tests__/build-prompt.test.ts +52 -27
- package/src/activities/execute-cursor/__tests__/cas-observations.test.ts +25 -0
- package/src/activities/execute-cursor/__tests__/goldens/prompt.enhanced.everything.prompt.md +166 -0
- package/src/activities/execute-cursor/__tests__/goldens/prompt.enhanced.plan-mode.prompt.md +186 -0
- package/src/activities/execute-cursor/__tests__/goldens/prompt.hitl.recovery.prompt.md +191 -0
- package/src/activities/execute-cursor/__tests__/goldens/prompt.hitl.reinvocation.prompt.md +13 -0
- package/src/activities/execute-cursor/__tests__/goldens/prompt.resumed.prefixed.prompt.md +32 -0
- package/src/activities/execute-cursor/__tests__/goldens/prompt.resumed.raw.prompt.md +1 -0
- package/src/activities/execute-cursor/__tests__/hermetic/file-review-capture.test.ts +1 -2
- package/src/activities/execute-cursor/__tests__/hermetic/goldens/sdk-error-at-create.status.json +4 -0
- package/src/activities/execute-cursor/__tests__/hermetic/harness-contract.test.ts +24 -4
- package/src/activities/execute-cursor/__tests__/hermetic/stream-self-stop-arms.test.ts +6 -5
- package/src/activities/execute-cursor/__tests__/hermetic/thrown-error-arms.test.ts +9 -0
- package/src/activities/execute-cursor/__tests__/hitl-resume-history.test.ts +11 -8
- package/src/activities/execute-cursor/__tests__/prompt-goldens.test.ts +229 -0
- package/src/activities/execute-cursor/__tests__/same-identity-reproposal.test.ts +3 -3
- package/src/activities/execute-cursor/__tests__/sequential-gate-resume.test.ts +2 -2
- package/src/activities/execute-cursor/__tests__/turn-boundary.test.ts +78 -234
- package/src/activities/execute-cursor/__tests__/turn-stream.test.ts +1 -26
- package/src/activities/execute-cursor/adapter.ts +7 -5
- package/src/activities/execute-cursor/approval-policy.ts +5 -2
- package/src/activities/execute-cursor/approval-state.ts +16 -8
- package/src/activities/execute-cursor/cas-observations.ts +20 -2
- package/src/activities/execute-cursor/cursor-capabilities.ts +24 -5
- package/src/activities/execute-cursor/message-translator.ts +29 -41
- package/src/activities/execute-cursor/prompt-builder.ts +99 -157
- package/src/activities/execute-cursor/turn-boundary.ts +34 -140
- package/src/activities/execute-cursor/turn-settle.ts +37 -51
- package/src/activities/execute-cursor/turn-setup.ts +30 -70
- package/src/activities/execute-cursor/turn-stream.ts +8 -31
- package/src/activities/execute-cursor/turn.ts +5 -1
- package/src/activities/execute-deep-agent/__test-utils__/contract-subject.ts +391 -0
- package/src/activities/execute-deep-agent/__test-utils__/hermetic-deep-agent.ts +313 -0
- package/src/activities/execute-deep-agent/__test-utils__/hitl-script.ts +48 -0
- package/src/activities/execute-deep-agent/__test-utils__/scripted-model-module.ts +85 -0
- package/src/activities/execute-deep-agent/__test-utils__/scripted-model.ts +383 -36
- package/src/activities/execute-deep-agent/__tests__/adapter-graph-is-sdk-free.test.ts +76 -0
- package/src/activities/execute-deep-agent/__tests__/adapter-is-temporal-free.test.ts +47 -0
- package/src/activities/execute-deep-agent/__tests__/adapter.test.ts +80 -0
- package/src/activities/execute-deep-agent/__tests__/cas-capture-backend.test.ts +1 -1
- package/src/activities/execute-deep-agent/__tests__/execution-state-extended.test.ts +0 -2
- package/src/activities/execute-deep-agent/__tests__/execution-state.test.ts +0 -3
- package/src/activities/execute-deep-agent/__tests__/goldens/system-prompt.build-from-plan.prompt.md +172 -0
- package/src/activities/execute-deep-agent/__tests__/goldens/system-prompt.everything.prompt.md +167 -0
- package/src/activities/execute-deep-agent/__tests__/goldens/system-prompt.minimal.prompt.md +36 -0
- package/src/activities/execute-deep-agent/__tests__/goldens/system-prompt.plan-mode.prompt.md +178 -0
- package/src/activities/execute-deep-agent/__tests__/goldens/system-prompt.skills-below-threshold.prompt.md +158 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/file-review-capture.test.ts +210 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/approve-all-lease.turn1.status.json +74 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/approve-all-lease.turn2.status.json +104 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/approve.turn2.status.json +78 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/file-review-capture.status.json +138 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/gate.turn1.status.json +68 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/inline-artifact.turn1.status.json +154 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/inline-artifact.turn2.status.json +116 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/pause.loop.after-tool.status.json +69 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/pause.loop.mid-tool.status.json +67 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/plain-turn.status.json +47 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/platform-stop.status.json +68 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/recursion-limit.persisted.status.json +280 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/reject.turn2.status.json +77 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/resolution-error.status.json +18 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/sequential-gates.turn2.status.json +99 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/sequential-gates.turn3.status.json +109 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/skip.turn2.status.json +76 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/structured-output.text-fallback.status.json +51 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/structured-output.tier2.status.json +51 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/structured-output.tool-strategy.status.json +56 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/sub-agent-delegation.status.json +90 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/tool-call.status.json +70 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/worker-shutdown.status.json +71 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/harness-contract.test.ts +144 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/hitl-approve-all-lease.test.ts +184 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/hitl-round-trips.test.ts +203 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/hitl-sequential-gates.test.ts +170 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/inline-artifact-across-gate.test.ts +175 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/pause-vs-shutdown.test.ts +206 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/plain-turn.test.ts +142 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/platform-stop.test.ts +126 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/recursion-limit.test.ts +139 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/resolution-error.test.ts +122 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/structured-output.test.ts +236 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/sub-agent-delegation.test.ts +161 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/tool-call.test.ts +157 -0
- package/src/activities/execute-deep-agent/__tests__/hermetic/workspace-lock-timeout.test.ts +152 -0
- package/src/activities/execute-deep-agent/__tests__/hitl.test.ts +50 -122
- package/src/activities/execute-deep-agent/__tests__/inline-publisher.test.ts +8 -6
- package/src/activities/execute-deep-agent/__tests__/plan-mode-path-normalization.test.ts +2 -2
- package/src/activities/execute-deep-agent/__tests__/prompt-builder.test.ts +35 -35
- package/src/activities/execute-deep-agent/__tests__/prompt-goldens.test.ts +247 -0
- package/src/activities/execute-deep-agent/__tests__/scripted-model.test.ts +329 -0
- package/src/activities/execute-deep-agent/__tests__/status-builder-shared.test.ts +1 -20
- package/src/activities/execute-deep-agent/__tests__/streaming-side-effects.test.ts +78 -0
- package/src/activities/execute-deep-agent/__tests__/subagent-gitignored-capture.test.ts +1 -1
- package/src/activities/execute-deep-agent/__tests__/subagent-plan-mode-permissions.test.ts +2 -2
- package/src/activities/execute-deep-agent/__tests__/subagent-tracker.test.ts +57 -31
- package/src/activities/execute-deep-agent/__tests__/subagent-transformer.test.ts +19 -79
- package/src/activities/execute-deep-agent/__tests__/subagent-wiring.test.ts +15 -15
- package/src/activities/execute-deep-agent/__tests__/summarization-verification.test.ts +1 -1
- package/src/activities/execute-deep-agent/__tests__/turn-stream.test.ts +391 -0
- package/src/activities/execute-deep-agent/__tests__/v3-status-builder.test.ts +343 -38
- package/src/activities/execute-deep-agent/__tests__/vision-input.test.ts +5 -5
- package/src/activities/execute-deep-agent/adapter.ts +94 -0
- package/src/activities/execute-deep-agent/cas-capture-observer.ts +11 -0
- package/src/activities/execute-deep-agent/deep-agent-capabilities.ts +43 -0
- package/src/activities/execute-deep-agent/execution-state.ts +4 -13
- package/src/activities/execute-deep-agent/hitl.ts +100 -123
- package/src/activities/execute-deep-agent/prompt-builder.ts +141 -115
- package/src/activities/execute-deep-agent/status-builder-shared.ts +21 -84
- package/src/activities/execute-deep-agent/streaming-side-effects.ts +13 -19
- package/src/activities/execute-deep-agent/subagent-tracker.ts +77 -42
- package/src/activities/execute-deep-agent/subagent-transformer.ts +46 -105
- package/src/activities/execute-deep-agent/subagent-wiring.ts +5 -4
- package/src/activities/execute-deep-agent/turn-settle.ts +164 -0
- package/src/activities/execute-deep-agent/turn-setup.ts +541 -0
- package/src/activities/execute-deep-agent/turn-stream.ts +313 -0
- package/src/activities/execute-deep-agent/turn.ts +131 -0
- package/src/activities/execute-deep-agent/v3-event-recorder.ts +6 -5
- package/src/activities/execute-deep-agent/v3-events.ts +1 -1
- package/src/activities/execute-deep-agent/v3-status-builder.ts +84 -63
- package/src/harness/__tests__/approval-decisions.test.ts +116 -0
- package/src/harness/__tests__/capture.test.ts +268 -0
- package/src/harness/__tests__/mount-skills.test.ts +169 -0
- package/src/harness/__tests__/persist-chokepoint.test.ts +38 -2
- package/src/harness/__tests__/run-turn-deterministic.test.ts +94 -0
- package/src/harness/__tests__/run-turn.test.ts +39 -23
- package/src/harness/__tests__/turn-attachments-vision.test.ts +80 -0
- package/src/harness/__tests__/turn-context.test.ts +73 -26
- package/src/harness/approval-decisions.ts +104 -0
- package/src/harness/capabilities.ts +16 -5
- package/src/harness/capture.ts +301 -0
- package/src/harness/persist-chokepoint.ts +24 -4
- package/src/harness/run-turn.ts +120 -29
- package/src/harness/terminal-table.ts +61 -20
- package/src/harness/turn-context.ts +208 -111
- package/src/harness/types.ts +66 -12
- package/src/harness-adapters.ts +17 -9
- package/src/middleware/__tests__/approval-gate.test.ts +1 -1
- package/src/middleware/__tests__/cost-advisory.test.ts +113 -0
- package/src/middleware/approval-gate.ts +2 -2
- package/src/middleware/{cost-cap.ts → cost-advisory.ts} +40 -70
- package/src/middleware/index.ts +29 -29
- package/src/middleware/types.ts +3 -2
- package/src/runner-manager.ts +0 -8
- package/src/runner.ts +0 -8
- package/src/shared/__tests__/attachment-naming.test.ts +6 -19
- package/src/shared/__tests__/attachment-resolver.test.ts +158 -8
- package/src/shared/__tests__/attachment-zip.test.ts +236 -0
- package/src/shared/__tests__/bedrock-adapter.test.ts +1 -1
- package/src/shared/__tests__/blueprint-resolver.test.ts +43 -0
- package/src/shared/__tests__/cost-guard.test.ts +3 -3
- package/src/shared/__tests__/prompt-sections.test.ts +167 -0
- package/src/shared/__tests__/secret-leak-scan.test.ts +2 -2
- package/src/{activities/execute-deep-agent → shared}/__tests__/stamp-flowed-rows.test.ts +33 -10
- package/src/shared/__tests__/vertex-adapter.test.ts +1 -1
- package/src/shared/attachment-resolver.ts +218 -55
- package/src/shared/attachment-zip.ts +281 -0
- package/src/shared/connect-backfill.ts +9 -11
- package/src/shared/cost-guard.ts +3 -3
- package/src/shared/execution-status-writer.ts +5 -5
- package/src/shared/extract-structured-output.ts +8 -7
- package/src/shared/filereview/__tests__/capture.test.ts +86 -4
- package/src/shared/filereview/__tests__/cas-progress.test.ts +2 -1
- package/src/shared/filereview/cas-progress.ts +5 -19
- package/src/shared/filereview/cas-touched.ts +89 -0
- package/src/shared/filereview/index.ts +4 -2
- package/src/shared/mcp-resolver.ts +4 -5
- package/src/shared/persist-decision.ts +3 -4
- package/src/shared/plan-mode-permissions.ts +2 -2
- package/src/shared/plan-mode-prompt.ts +1 -1
- package/src/shared/prompt-sections.ts +256 -0
- package/src/shared/skill-resolver.ts +4 -2
- package/src/shared/tool-rounds.ts +48 -0
- package/src/shared/tool-row.ts +61 -0
- package/src/shared/workspace/__tests__/stigmer-link.test.ts +7 -22
- package/src/shared/workspace/__tests__/writeback-coordinator.test.ts +20 -61
- package/src/shared/workspace/session-provision.ts +3 -3
- package/src/shared/workspace/stigmer-link.ts +3 -3
- package/src/shared/workspace/writeback-coordinator.ts +16 -64
- package/src/tools/index.ts +1 -1
- package/dist/activities/execute-cursor/capture-flow.d.ts +0 -142
- package/dist/activities/execute-cursor/capture-flow.js +0 -285
- package/dist/activities/execute-cursor/capture-flow.js.map +0 -1
- package/dist/activities/execute-cursor/command-provenance.d.ts +0 -48
- package/dist/activities/execute-cursor/command-provenance.js +0 -38
- package/dist/activities/execute-cursor/command-provenance.js.map +0 -1
- package/dist/activities/execute-deep-agent/attachment-injector.d.ts +0 -134
- package/dist/activities/execute-deep-agent/attachment-injector.js +0 -386
- package/dist/activities/execute-deep-agent/attachment-injector.js.map +0 -1
- package/dist/activities/execute-deep-agent/command-provenance.d.ts +0 -61
- package/dist/activities/execute-deep-agent/command-provenance.js +0 -72
- package/dist/activities/execute-deep-agent/command-provenance.js.map +0 -1
- package/dist/activities/execute-deep-agent/environment.d.ts +0 -24
- package/dist/activities/execute-deep-agent/environment.js +0 -58
- package/dist/activities/execute-deep-agent/environment.js.map +0 -1
- package/dist/activities/execute-deep-agent/event-recorder.d.ts +0 -21
- package/dist/activities/execute-deep-agent/event-recorder.js +0 -67
- package/dist/activities/execute-deep-agent/event-recorder.js.map +0 -1
- package/dist/activities/execute-deep-agent/index.d.ts +0 -15
- package/dist/activities/execute-deep-agent/index.js +0 -918
- package/dist/activities/execute-deep-agent/index.js.map +0 -1
- package/dist/activities/execute-deep-agent/mcp-gate.d.ts +0 -28
- package/dist/activities/execute-deep-agent/mcp-gate.js +0 -22
- package/dist/activities/execute-deep-agent/mcp-gate.js.map +0 -1
- package/dist/activities/execute-deep-agent/post-stream.d.ts +0 -23
- package/dist/activities/execute-deep-agent/post-stream.js +0 -71
- package/dist/activities/execute-deep-agent/post-stream.js.map +0 -1
- package/dist/activities/execute-deep-agent/setup.d.ts +0 -136
- package/dist/activities/execute-deep-agent/setup.js +0 -767
- package/dist/activities/execute-deep-agent/setup.js.map +0 -1
- package/dist/activities/execute-deep-agent/stamp-flowed-rows.d.ts +0 -36
- package/dist/activities/execute-deep-agent/stamp-flowed-rows.js +0 -56
- package/dist/activities/execute-deep-agent/stamp-flowed-rows.js.map +0 -1
- package/dist/activities/execute-deep-agent/status-builder.d.ts +0 -93
- package/dist/activities/execute-deep-agent/status-builder.js +0 -365
- package/dist/activities/execute-deep-agent/status-builder.js.map +0 -1
- package/dist/activities/execute-deep-agent/streaming-terminal.d.ts +0 -21
- package/dist/activities/execute-deep-agent/streaming-terminal.js +0 -80
- package/dist/activities/execute-deep-agent/streaming-terminal.js.map +0 -1
- package/dist/activities/execute-deep-agent/streaming-v3.d.ts +0 -13
- package/dist/activities/execute-deep-agent/streaming-v3.js +0 -174
- package/dist/activities/execute-deep-agent/streaming-v3.js.map +0 -1
- package/dist/activities/execute-deep-agent/streaming.d.ts +0 -81
- package/dist/activities/execute-deep-agent/streaming.js +0 -160
- package/dist/activities/execute-deep-agent/streaming.js.map +0 -1
- package/dist/middleware/cost-cap.d.ts +0 -22
- package/dist/middleware/cost-cap.js.map +0 -1
- package/dist/middleware/graceful-stop.d.ts +0 -17
- package/dist/middleware/graceful-stop.js +0 -63
- package/dist/middleware/graceful-stop.js.map +0 -1
- package/dist/shared/skill-writer.d.ts +0 -75
- package/dist/shared/skill-writer.js +0 -207
- package/dist/shared/skill-writer.js.map +0 -1
- package/src/activities/execute-cursor/__tests__/capture-flow.test.ts +0 -1032
- package/src/activities/execute-cursor/__tests__/command-provenance.test.ts +0 -240
- package/src/activities/execute-cursor/__tests__/progress-substrate.test.ts +0 -169
- package/src/activities/execute-cursor/capture-flow.ts +0 -379
- package/src/activities/execute-cursor/command-provenance.ts +0 -73
- package/src/activities/execute-deep-agent/__tests__/attachment-injector.test.ts +0 -1161
- package/src/activities/execute-deep-agent/__tests__/command-provenance.test.ts +0 -252
- package/src/activities/execute-deep-agent/__tests__/environment.test.ts +0 -108
- package/src/activities/execute-deep-agent/__tests__/event-recorder.test.ts +0 -150
- package/src/activities/execute-deep-agent/__tests__/hitl-integration.test.ts +0 -226
- package/src/activities/execute-deep-agent/__tests__/hitl-reject.test.ts +0 -318
- package/src/activities/execute-deep-agent/__tests__/hitl-resume-approve-all.test.ts +0 -351
- package/src/activities/execute-deep-agent/__tests__/hitl-resume-history.test.ts +0 -293
- package/src/activities/execute-deep-agent/__tests__/index.test.ts +0 -99
- package/src/activities/execute-deep-agent/__tests__/mcp-gate.test.ts +0 -44
- package/src/activities/execute-deep-agent/__tests__/post-stream.test.ts +0 -112
- package/src/activities/execute-deep-agent/__tests__/sequential-gate-resume.test.ts +0 -358
- package/src/activities/execute-deep-agent/__tests__/status-builder.test.ts +0 -1933
- package/src/activities/execute-deep-agent/__tests__/streaming-terminal.test.ts +0 -40
- package/src/activities/execute-deep-agent/__tests__/streaming-v3.test.ts +0 -597
- package/src/activities/execute-deep-agent/__tests__/streaming.test.ts +0 -508
- package/src/activities/execute-deep-agent/attachment-injector.ts +0 -627
- package/src/activities/execute-deep-agent/command-provenance.ts +0 -102
- package/src/activities/execute-deep-agent/environment.ts +0 -76
- package/src/activities/execute-deep-agent/event-recorder.ts +0 -95
- package/src/activities/execute-deep-agent/index.ts +0 -1072
- package/src/activities/execute-deep-agent/mcp-gate.ts +0 -37
- package/src/activities/execute-deep-agent/post-stream.ts +0 -109
- package/src/activities/execute-deep-agent/setup.ts +0 -1081
- package/src/activities/execute-deep-agent/stamp-flowed-rows.ts +0 -64
- package/src/activities/execute-deep-agent/status-builder.ts +0 -481
- package/src/activities/execute-deep-agent/streaming-terminal.ts +0 -106
- package/src/activities/execute-deep-agent/streaming-v3.ts +0 -277
- package/src/activities/execute-deep-agent/streaming.ts +0 -313
- package/src/middleware/__tests__/cost-cap.test.ts +0 -192
- package/src/middleware/__tests__/graceful-stop.test.ts +0 -105
- package/src/middleware/graceful-stop.ts +0 -86
- package/src/shared/__tests__/skill-writer.test.ts +0 -372
- package/src/shared/skill-writer.ts +0 -266
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The scripted model's own contract: the properties every consumer of
|
|
3
|
+
* `__test-utils__/scripted-model.ts` leans on, pinned here so a change to the
|
|
4
|
+
* double is caught before it silently reshapes a golden.
|
|
5
|
+
*
|
|
6
|
+
* 1. The two-turn sugar `{ toolCalls, done }` means exactly "propose on round
|
|
7
|
+
* 0, say `done` on every round after".
|
|
8
|
+
* 2. A turn is chosen by the transcript's completed tool rounds, never by a
|
|
9
|
+
* call counter: the same instance answers a fresh thread and a resumed
|
|
10
|
+
* thread identically (the memory-replay vs sqlite-resume equivalence the
|
|
11
|
+
* hermetic HITL arms depend on), and one instance drives two whole graph
|
|
12
|
+
* runs to the same result.
|
|
13
|
+
* 3. Running out of script throws with a diagnosing message; `repeatLast`
|
|
14
|
+
* keeps playing the final turn.
|
|
15
|
+
* 4. Streaming produces the production event sequence: reasoning as an
|
|
16
|
+
* opener plus a delta, text as a delta, a tool call as a `tool_call_chunk`
|
|
17
|
+
* whose `args` is a JSON STRING, usage on `message-finish` (the cache
|
|
18
|
+
* buckets under `input_token_details`) — and the aggregated streamed
|
|
19
|
+
* message equals the `invoke` message.
|
|
20
|
+
* 5. A `TurnPlayer` script is asked with the whole transcript and its
|
|
21
|
+
* answer is played, whatever the round.
|
|
22
|
+
* 6. A turn's ending takes the call: `fail` throws after the chunks; `hang`
|
|
23
|
+
* parks on the call's abort signal (reporting the park), throws the
|
|
24
|
+
* abort when it fires, and refuses a call with no signal. On a REAL
|
|
25
|
+
* deepagents graph aborted mid-hang through the run's own signal, the
|
|
26
|
+
* parked model unparks, the stream rejects with the abort, and the
|
|
27
|
+
* process sees no orphaned rejection — the posture the contract kit's
|
|
28
|
+
* hang arms and the runtime's stall watchdog rely on (S3 M2a F-M2a-18
|
|
29
|
+
* measured one orphan for a forced mid-step abort of a WEDGED engine;
|
|
30
|
+
* an engine that honours its signal leaves none, and this arm is where
|
|
31
|
+
* that fact is pinned).
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
import { describe, expect, it } from "vitest";
|
|
35
|
+
import {
|
|
36
|
+
AIMessage,
|
|
37
|
+
AIMessageChunk,
|
|
38
|
+
HumanMessage,
|
|
39
|
+
SystemMessage,
|
|
40
|
+
ToolMessage,
|
|
41
|
+
type BaseMessage,
|
|
42
|
+
} from "@langchain/core/messages";
|
|
43
|
+
import { tool } from "@langchain/core/tools";
|
|
44
|
+
import { z } from "zod";
|
|
45
|
+
import { MemorySaver } from "@langchain/langgraph";
|
|
46
|
+
import { createDeepAgent, StateBackend } from "deepagents";
|
|
47
|
+
|
|
48
|
+
import {
|
|
49
|
+
ScriptedModel,
|
|
50
|
+
completedToolRounds,
|
|
51
|
+
type RoleScript,
|
|
52
|
+
type ScriptedTurnInfo,
|
|
53
|
+
type TurnPlayer,
|
|
54
|
+
} from "../__test-utils__/scripted-model.js";
|
|
55
|
+
|
|
56
|
+
const CALL = { name: "probe", args: { path: "a.txt" }, id: "call_1" };
|
|
57
|
+
|
|
58
|
+
function transcriptWithRounds(rounds: number): BaseMessage[] {
|
|
59
|
+
const out: BaseMessage[] = [new SystemMessage("sys"), new HumanMessage("go")];
|
|
60
|
+
for (let i = 0; i < rounds; i++) {
|
|
61
|
+
out.push(new AIMessage({ content: "", tool_calls: [{ ...CALL, id: `call_${i}`, type: "tool_call" }] }));
|
|
62
|
+
out.push(new ToolMessage({ content: "ok", tool_call_id: `call_${i}` }));
|
|
63
|
+
}
|
|
64
|
+
return out;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
describe("ScriptedModel — the two-turn sugar", () => {
|
|
68
|
+
it("proposes on round 0 and says done on every later round", async () => {
|
|
69
|
+
const model = new ScriptedModel(() => ({ toolCalls: [CALL], done: "finished" }));
|
|
70
|
+
|
|
71
|
+
const first = await model.invoke(transcriptWithRounds(0));
|
|
72
|
+
expect(first.tool_calls?.map((tc) => tc.name)).toEqual(["probe"]);
|
|
73
|
+
expect(first.content).toBe("");
|
|
74
|
+
|
|
75
|
+
const second = await model.invoke(transcriptWithRounds(1));
|
|
76
|
+
expect(second.tool_calls ?? []).toHaveLength(0);
|
|
77
|
+
expect(second.content).toBe("finished");
|
|
78
|
+
|
|
79
|
+
const third = await model.invoke(transcriptWithRounds(2));
|
|
80
|
+
expect(third.content, "the sugar repeats its last turn").toBe("finished");
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
describe("ScriptedModel — turns are indexed by the transcript, not by a counter", () => {
|
|
85
|
+
const script: RoleScript = {
|
|
86
|
+
turns: [{ toolCalls: [CALL] }, { toolCalls: [{ ...CALL, id: "call_b" }] }, { text: "done" }],
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
it("counts completed tool rounds from AI messages carrying tool_calls", () => {
|
|
90
|
+
expect(completedToolRounds(transcriptWithRounds(0))).toBe(0);
|
|
91
|
+
expect(completedToolRounds(transcriptWithRounds(2))).toBe(2);
|
|
92
|
+
expect(completedToolRounds([new AIMessage("plain text, no tools")])).toBe(0);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it("answers the same transcript the same way regardless of what it was asked before", async () => {
|
|
96
|
+
const model = new ScriptedModel(() => script);
|
|
97
|
+
// A "resumed" thread asks round 1 first; a "replayed" thread asks 0 then 1.
|
|
98
|
+
const resumed = await model.invoke(transcriptWithRounds(1));
|
|
99
|
+
await model.invoke(transcriptWithRounds(0));
|
|
100
|
+
const replayed = await model.invoke(transcriptWithRounds(1));
|
|
101
|
+
expect(replayed.tool_calls).toEqual(resumed.tool_calls);
|
|
102
|
+
expect(replayed.tool_calls?.[0]?.id).toBe("call_b");
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it("reports the role and round to onTurn before rendering", async () => {
|
|
106
|
+
const seen: ScriptedTurnInfo[] = [];
|
|
107
|
+
const model = new ScriptedModel(() => script, [], { onTurn: (info) => void seen.push(info) });
|
|
108
|
+
const bound = model.bindTools([{ name: "probe" }]);
|
|
109
|
+
await bound.invoke(transcriptWithRounds(2));
|
|
110
|
+
expect(seen).toEqual([{ boundToolNames: ["probe"], round: 2 }]);
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it("throws a diagnosing error when the script runs out", async () => {
|
|
114
|
+
const model = new ScriptedModel(() => script).bindTools([{ name: "probe" }, { name: "task" }]);
|
|
115
|
+
await expect(model.invoke(transcriptWithRounds(3))).rejects.toThrow(
|
|
116
|
+
/role \[probe, task\] has 3 turn\(s\) but the transcript already holds 3 completed tool round\(s\)/,
|
|
117
|
+
);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it("repeats the final turn when repeatLast is set", async () => {
|
|
121
|
+
const model = new ScriptedModel(() => ({ turns: [{ toolCalls: [CALL] }], repeatLast: true }));
|
|
122
|
+
const late = await model.invoke(transcriptWithRounds(7));
|
|
123
|
+
expect(late.tool_calls?.map((tc) => tc.name)).toEqual(["probe"]);
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
it("drives two whole graph runs from one instance to the same result", async () => {
|
|
127
|
+
let executions = 0;
|
|
128
|
+
const probe = tool(
|
|
129
|
+
async () => {
|
|
130
|
+
executions += 1;
|
|
131
|
+
return "ok";
|
|
132
|
+
},
|
|
133
|
+
{ name: "probe", description: "probe", schema: z.object({ path: z.string() }) },
|
|
134
|
+
);
|
|
135
|
+
const model = new ScriptedModel(() => ({ toolCalls: [CALL], done: "all done" }));
|
|
136
|
+
const runOnce = async (threadId: string): Promise<string> => {
|
|
137
|
+
const agent = await createDeepAgent({
|
|
138
|
+
model,
|
|
139
|
+
checkpointer: new MemorySaver() as never,
|
|
140
|
+
backend: new StateBackend(),
|
|
141
|
+
tools: [probe],
|
|
142
|
+
} as unknown as Parameters<typeof createDeepAgent>[0]);
|
|
143
|
+
const result = (await agent.invoke(
|
|
144
|
+
{ messages: [new HumanMessage("go")] },
|
|
145
|
+
{ configurable: { thread_id: threadId }, recursionLimit: 50 },
|
|
146
|
+
)) as { messages: BaseMessage[] };
|
|
147
|
+
const last = result.messages[result.messages.length - 1];
|
|
148
|
+
return typeof last.content === "string" ? last.content : JSON.stringify(last.content);
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
expect(await runOnce("thread-a")).toBe("all done");
|
|
152
|
+
expect(await runOnce("thread-b")).toBe("all done");
|
|
153
|
+
expect(executions, "one tool execution per run").toBe(2);
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
describe("ScriptedModel — streaming is the production event path", () => {
|
|
158
|
+
const turn = {
|
|
159
|
+
reasoning: "Let me think.",
|
|
160
|
+
text: "Reading the file.",
|
|
161
|
+
toolCalls: [CALL],
|
|
162
|
+
usage: { inputTokens: 1_000, outputTokens: 40 },
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
it("emits opener + delta for reasoning, a text delta, a JSON-string tool_call_chunk, and usage on finish", async () => {
|
|
166
|
+
const model = new ScriptedModel(() => ({ turns: [turn] }));
|
|
167
|
+
const events: Array<Record<string, unknown>> = [];
|
|
168
|
+
for await (const ev of model.streamEvents(transcriptWithRounds(0))) {
|
|
169
|
+
events.push(ev as unknown as Record<string, unknown>);
|
|
170
|
+
}
|
|
171
|
+
const kinds = events.map((e) => e.event);
|
|
172
|
+
expect(kinds[0]).toBe("message-start");
|
|
173
|
+
expect(kinds.at(-1)).toBe("message-finish");
|
|
174
|
+
|
|
175
|
+
const deltas = events.filter((e) => e.event === "content-block-delta").map((e) => e.delta as Record<string, unknown>);
|
|
176
|
+
expect(deltas.map((d) => d.type)).toEqual(["reasoning-delta", "text-delta", "block-delta"]);
|
|
177
|
+
expect(deltas[0].reasoning).toBe("Let me think.");
|
|
178
|
+
expect(deltas[1].text).toBe("Reading the file.");
|
|
179
|
+
const fields = deltas[2].fields as Record<string, unknown>;
|
|
180
|
+
expect(fields.type).toBe("tool_call_chunk");
|
|
181
|
+
expect(fields.id).toBe("call_1");
|
|
182
|
+
expect(fields.name).toBe("probe");
|
|
183
|
+
expect(fields.args, "args ride the stream as a JSON string, as every provider sends them").toBe(
|
|
184
|
+
JSON.stringify(CALL.args),
|
|
185
|
+
);
|
|
186
|
+
|
|
187
|
+
const start = events[0] as { usage?: unknown };
|
|
188
|
+
expect(start.usage, "usage never rides message-start").toBeUndefined();
|
|
189
|
+
const finish = events.at(-1) as { usage?: { input_tokens: number; output_tokens: number; total_tokens: number } };
|
|
190
|
+
expect(finish.usage).toEqual({ input_tokens: 1_000, output_tokens: 40, total_tokens: 1_040 });
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
it("aggregates the streamed chunks to the message invoke returns", async () => {
|
|
194
|
+
const model = new ScriptedModel(() => ({ turns: [turn] }));
|
|
195
|
+
const invoked = await model.invoke(transcriptWithRounds(0));
|
|
196
|
+
let streamed: AIMessageChunk | undefined;
|
|
197
|
+
for await (const chunk of await model.stream(transcriptWithRounds(0))) {
|
|
198
|
+
streamed = streamed ? streamed.concat(chunk) : chunk;
|
|
199
|
+
}
|
|
200
|
+
expect(streamed).toBeDefined();
|
|
201
|
+
expect(streamed!.tool_calls?.map((tc) => ({ id: tc.id, name: tc.name, args: tc.args }))).toEqual(
|
|
202
|
+
invoked.tool_calls?.map((tc) => ({ id: tc.id, name: tc.name, args: tc.args })),
|
|
203
|
+
);
|
|
204
|
+
expect(streamed!.text).toBe(invoked.text);
|
|
205
|
+
// Core's chunk merge adds empty `*_token_details` maps; the three counts the runner reads must agree.
|
|
206
|
+
expect(streamed!.usage_metadata).toMatchObject(invoked.usage_metadata!);
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
it("keeps a plain-text turn as string content, the shape every provider gives", async () => {
|
|
210
|
+
const model = new ScriptedModel(() => ({ turns: [{ text: "hello" }] }));
|
|
211
|
+
const invoked = await model.invoke(transcriptWithRounds(0));
|
|
212
|
+
expect(invoked.content).toBe("hello");
|
|
213
|
+
let streamed: AIMessageChunk | undefined;
|
|
214
|
+
for await (const chunk of await model.stream(transcriptWithRounds(0))) {
|
|
215
|
+
streamed = streamed ? streamed.concat(chunk) : chunk;
|
|
216
|
+
}
|
|
217
|
+
expect(streamed!.content).toBe("hello");
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
it("puts the cache buckets under input_token_details on message-finish, the Anthropic adapter's shape", async () => {
|
|
221
|
+
const model = new ScriptedModel(() => ({
|
|
222
|
+
turns: [{ text: "cached", usage: { inputTokens: 30, outputTokens: 4, cacheReadTokens: 20, cacheWriteTokens: 5 } }],
|
|
223
|
+
}));
|
|
224
|
+
let finish: { usage?: Record<string, unknown> } | undefined;
|
|
225
|
+
for await (const ev of model.streamEvents(transcriptWithRounds(0))) {
|
|
226
|
+
if ((ev as { event: string }).event === "message-finish") finish = ev as typeof finish;
|
|
227
|
+
}
|
|
228
|
+
expect(finish?.usage).toEqual({
|
|
229
|
+
input_tokens: 30,
|
|
230
|
+
output_tokens: 4,
|
|
231
|
+
total_tokens: 34,
|
|
232
|
+
input_token_details: { cache_read: 20, cache_creation: 5 },
|
|
233
|
+
});
|
|
234
|
+
});
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
describe("ScriptedModel — a TurnPlayer script reads the transcript itself", () => {
|
|
238
|
+
it("is asked with the whole transcript and its turn is played whatever the round", async () => {
|
|
239
|
+
const asked: number[] = [];
|
|
240
|
+
const player: TurnPlayer = (transcript) => {
|
|
241
|
+
asked.push(transcript.length);
|
|
242
|
+
return { text: `saw ${transcript.length} messages` };
|
|
243
|
+
};
|
|
244
|
+
const model = new ScriptedModel(() => player);
|
|
245
|
+
expect((await model.invoke(transcriptWithRounds(0))).content).toBe("saw 2 messages");
|
|
246
|
+
expect((await model.invoke(transcriptWithRounds(3))).content).toBe("saw 8 messages");
|
|
247
|
+
expect(asked).toEqual([2, 8]);
|
|
248
|
+
});
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
describe("ScriptedModel — a turn's ending takes the call", () => {
|
|
252
|
+
const boom = new Error("Engine rejected the request: invalid API key");
|
|
253
|
+
|
|
254
|
+
it("fail: streams the turn's chunks, never finishes the message, then throws the error", async () => {
|
|
255
|
+
const model = new ScriptedModel(() => ({ turns: [{ text: "Checking.", ends: { kind: "fail", error: boom } }] }));
|
|
256
|
+
const seen: string[] = [];
|
|
257
|
+
await expect(
|
|
258
|
+
(async () => {
|
|
259
|
+
for await (const ev of model.streamEvents(transcriptWithRounds(0))) seen.push((ev as { event: string }).event);
|
|
260
|
+
})(),
|
|
261
|
+
).rejects.toBe(boom);
|
|
262
|
+
expect(seen).toContain("content-block-delta");
|
|
263
|
+
expect(seen, "an ending turn never reaches message-finish").not.toContain("message-finish");
|
|
264
|
+
await expect(model.invoke(transcriptWithRounds(0)), "invoke ends the same way").rejects.toBe(boom);
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
it("hang: refuses a call that carries no abort signal, diagnosing", async () => {
|
|
268
|
+
const model = new ScriptedModel(() => ({ turns: [{ ends: { kind: "hang" } }] }));
|
|
269
|
+
await expect(model.invoke(transcriptWithRounds(0))).rejects.toThrow(/parks on the call's abort signal and this call carried none/);
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
it("hang: parks after its chunks, reports the park, and throws the abort when the signal fires", async () => {
|
|
273
|
+
let parked = false;
|
|
274
|
+
const model = new ScriptedModel(() => ({ turns: [{ text: "Working…", ends: { kind: "hang" } }] }), [], { onPark: () => (parked = true) });
|
|
275
|
+
const controller = new AbortController();
|
|
276
|
+
const seen: string[] = [];
|
|
277
|
+
const consumed = (async () => {
|
|
278
|
+
for await (const ev of model.streamEvents(transcriptWithRounds(0), { signal: controller.signal })) {
|
|
279
|
+
seen.push((ev as { event: string }).event);
|
|
280
|
+
}
|
|
281
|
+
})();
|
|
282
|
+
await waitUntil(() => parked);
|
|
283
|
+
expect(seen, "the text reached the consumer before the park").toContain("content-block-delta");
|
|
284
|
+
controller.abort("stopped by the runtime");
|
|
285
|
+
await expect(consumed).rejects.toThrow(/stopped by the runtime/);
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
it("hang on a REAL graph: the run's abort signal unparks the model, the stream rejects, and no rejection is orphaned", async () => {
|
|
289
|
+
let parked = false;
|
|
290
|
+
const model = new ScriptedModel(() => ({ turns: [{ text: "Working…", ends: { kind: "hang" } }] }), [], { onPark: () => (parked = true) });
|
|
291
|
+
const agent = await createDeepAgent({
|
|
292
|
+
model,
|
|
293
|
+
checkpointer: new MemorySaver() as never,
|
|
294
|
+
backend: new StateBackend(),
|
|
295
|
+
} as unknown as Parameters<typeof createDeepAgent>[0]);
|
|
296
|
+
const controller = new AbortController();
|
|
297
|
+
const orphans: unknown[] = [];
|
|
298
|
+
const onOrphan = (reason: unknown): void => void orphans.push(reason);
|
|
299
|
+
process.on("unhandledRejection", onOrphan);
|
|
300
|
+
try {
|
|
301
|
+
const run = await agent.streamEvents(
|
|
302
|
+
{ messages: [new HumanMessage("go")] },
|
|
303
|
+
{ configurable: { thread_id: "hang-probe" }, version: "v3", signal: controller.signal },
|
|
304
|
+
);
|
|
305
|
+
const consumed = (async () => {
|
|
306
|
+
let events = 0;
|
|
307
|
+
for await (const _event of run) events += 1;
|
|
308
|
+
return events;
|
|
309
|
+
})();
|
|
310
|
+
await waitUntil(() => parked);
|
|
311
|
+
controller.abort("stopped by the runtime");
|
|
312
|
+
await expect(consumed, "the aborted run rejects out of the pull").rejects.toThrow();
|
|
313
|
+
// Give any orphan the macrotask turns it needs to surface as unhandled.
|
|
314
|
+
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
315
|
+
expect(orphans, "an engine that honours its signal leaves no orphaned rejection behind").toEqual([]);
|
|
316
|
+
} finally {
|
|
317
|
+
process.off("unhandledRejection", onOrphan);
|
|
318
|
+
}
|
|
319
|
+
});
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
/** Poll a predicate on the microtask/macrotask boundary — never a fixed sleep. */
|
|
323
|
+
async function waitUntil(ready: () => boolean, budgetMs = 5_000): Promise<void> {
|
|
324
|
+
const deadline = Date.now() + budgetMs;
|
|
325
|
+
while (!ready()) {
|
|
326
|
+
if (Date.now() > deadline) throw new Error("waitUntil: the condition did not become true in time");
|
|
327
|
+
await new Promise((resolve) => setTimeout(resolve, 5));
|
|
328
|
+
}
|
|
329
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, it, expect } from "vitest";
|
|
2
|
-
import {
|
|
2
|
+
import { extractToolResultV3 } from "../status-builder-shared.js";
|
|
3
3
|
|
|
4
4
|
// Image/mixed content blocks (e.g. a computer-use screenshot). The extractor
|
|
5
5
|
// must serialize the BLOCKS ARRAY — not the LangChain envelope around it — so
|
|
@@ -45,22 +45,3 @@ describe("extractToolResultV3", () => {
|
|
|
45
45
|
expect(extractToolResultV3({ foo: "bar" })).toBe(JSON.stringify({ foo: "bar" }));
|
|
46
46
|
});
|
|
47
47
|
});
|
|
48
|
-
|
|
49
|
-
describe("extractToolResult (v2)", () => {
|
|
50
|
-
it("passes a string output through unchanged", () => {
|
|
51
|
-
expect(extractToolResult({ output: "text" })).toBe("text");
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
it("returns output.content when it is a text string", () => {
|
|
55
|
-
expect(extractToolResult({ output: { content: "hello" } })).toBe("hello");
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
it("serializes the blocks array when output.content is an array", () => {
|
|
59
|
-
const data = { output: { content: [imageBlock] } };
|
|
60
|
-
expect(JSON.parse(extractToolResult(data))).toEqual([imageBlock]);
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
it("falls back to JSON.stringify when there is no usable content", () => {
|
|
64
|
-
expect(extractToolResult({ output: { other: 1 } })).toBe(JSON.stringify({ other: 1 }));
|
|
65
|
-
});
|
|
66
|
-
});
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `StreamingSideEffects`: the v3 `tools` events carry the tool INPUT on
|
|
3
|
+
* `tool-started` and the OUTPUT on `tool-finished`, so the trigger correlates
|
|
4
|
+
* the two by `tool_call_id` and publishes a file-modifying tool's target path
|
|
5
|
+
* once the call has finished.
|
|
6
|
+
*
|
|
7
|
+
* Carried from the legacy v3 loop's suite (`streaming-v3.test.ts`, retired
|
|
8
|
+
* with the loop at S3 M2b) — the trigger itself never had a test of its own.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { describe, it, expect, vi } from "vitest";
|
|
12
|
+
|
|
13
|
+
import { StreamingSideEffects } from "../streaming-side-effects.js";
|
|
14
|
+
import type { InlinePublisher } from "../inline-publisher.js";
|
|
15
|
+
import { makeToolFinished, makeToolStarted, resetSeq } from "../__test-utils__/v3-event-fixtures.js";
|
|
16
|
+
|
|
17
|
+
function publisherDouble(): { publisher: InlinePublisher; publish: ReturnType<typeof vi.fn> } {
|
|
18
|
+
const publish = vi.fn(async (_path: string) => undefined);
|
|
19
|
+
// The trigger reads exactly one member of the publisher.
|
|
20
|
+
return { publisher: { publish } as unknown as InlinePublisher, publish };
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
describe("StreamingSideEffects", () => {
|
|
24
|
+
it("publishes a file-modifying tool's path once tool-started and tool-finished have both arrived", () => {
|
|
25
|
+
resetSeq();
|
|
26
|
+
const { publisher, publish } = publisherDouble();
|
|
27
|
+
const effects = new StreamingSideEffects({ inlinePublisher: publisher });
|
|
28
|
+
|
|
29
|
+
effects.onProtocolEvent(makeToolStarted("toolu_1", "write_file", { file_path: "/ws/index.ts", content: "x" }));
|
|
30
|
+
expect(publish, "not before the call finishes").not.toHaveBeenCalled();
|
|
31
|
+
|
|
32
|
+
effects.onProtocolEvent(makeToolFinished("toolu_1", "written"));
|
|
33
|
+
expect(publish).toHaveBeenCalledWith("/ws/index.ts");
|
|
34
|
+
expect(effects.pendingPublishPromises).toHaveLength(1);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it("ignores tools that do not modify files", () => {
|
|
38
|
+
resetSeq();
|
|
39
|
+
const { publisher, publish } = publisherDouble();
|
|
40
|
+
const effects = new StreamingSideEffects({ inlinePublisher: publisher });
|
|
41
|
+
|
|
42
|
+
effects.onProtocolEvent(makeToolStarted("toolu_2", "read_file", { path: "/ws/index.ts" }));
|
|
43
|
+
effects.onProtocolEvent(makeToolFinished("toolu_2", "contents"));
|
|
44
|
+
expect(publish).not.toHaveBeenCalled();
|
|
45
|
+
expect(effects.pendingPublishPromises).toHaveLength(0);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it("reads the path from every key the two taxonomies use, camelCase included", () => {
|
|
49
|
+
resetSeq();
|
|
50
|
+
const { publisher, publish } = publisherDouble();
|
|
51
|
+
const effects = new StreamingSideEffects({ inlinePublisher: publisher });
|
|
52
|
+
|
|
53
|
+
effects.onProtocolEvent(makeToolStarted("toolu_3", "edit", { filePath: "/ws/a.ts" }));
|
|
54
|
+
effects.onProtocolEvent(makeToolFinished("toolu_3", "ok"));
|
|
55
|
+
effects.onProtocolEvent(makeToolStarted("toolu_4", "write", JSON.stringify({ path: "/ws/b.ts" })));
|
|
56
|
+
effects.onProtocolEvent(makeToolFinished("toolu_4", "ok"));
|
|
57
|
+
expect(publish.mock.calls.map((c) => c[0])).toEqual(["/ws/a.ts", "/ws/b.ts"]);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it("a finish with no matching start, or a start with no path, publishes nothing", () => {
|
|
61
|
+
resetSeq();
|
|
62
|
+
const { publisher, publish } = publisherDouble();
|
|
63
|
+
const effects = new StreamingSideEffects({ inlinePublisher: publisher });
|
|
64
|
+
|
|
65
|
+
effects.onProtocolEvent(makeToolFinished("toolu_never_started", "ok"));
|
|
66
|
+
effects.onProtocolEvent(makeToolStarted("toolu_5", "write_file", { content: "no path" }));
|
|
67
|
+
effects.onProtocolEvent(makeToolFinished("toolu_5", "ok"));
|
|
68
|
+
expect(publish).not.toHaveBeenCalled();
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it("does nothing at all without a publisher", () => {
|
|
72
|
+
resetSeq();
|
|
73
|
+
const effects = new StreamingSideEffects({});
|
|
74
|
+
effects.onProtocolEvent(makeToolStarted("toolu_6", "write_file", { path: "/ws/x" }));
|
|
75
|
+
effects.onProtocolEvent(makeToolFinished("toolu_6", "ok"));
|
|
76
|
+
expect(effects.pendingPublishPromises).toHaveLength(0);
|
|
77
|
+
});
|
|
78
|
+
});
|
|
@@ -58,7 +58,7 @@ describe("sub-agent gitignored capture (DD-19)", () => {
|
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
/**
|
|
61
|
-
* A capture-mode gate wired to `observer`, exactly as setup.ts builds the parent
|
|
61
|
+
* A capture-mode gate wired to `observer`, exactly as turn-setup.ts builds the parent
|
|
62
62
|
* gate and buildSubAgentMiddleware inherits it when a CAS observer backs the
|
|
63
63
|
* sub-agent (captureIgnored true).
|
|
64
64
|
*/
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* End-to-end proof (real deepagents + LangGraph runtime, no LLM/network) that a
|
|
3
3
|
* plan-mode SUB-AGENT is read-only BY CONSTRUCTION (issue #255).
|
|
4
4
|
*
|
|
5
|
-
* The parent graph receives PLAN_MODE_PERMISSIONS in setup.ts, but deepagents'
|
|
5
|
+
* The parent graph receives PLAN_MODE_PERMISSIONS in turn-setup.ts, but deepagents'
|
|
6
6
|
* parent-permission inheritance covers only spec-style sub-agents — our
|
|
7
7
|
* pre-built CompiledSubAgents bypass `normalizeSubagentSpec` entirely, so
|
|
8
8
|
* `compileSubagents` must bake the rules into each sub-agent graph itself.
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* delta.
|
|
15
15
|
*
|
|
16
16
|
* The rules under test are the PRODUCTION buildPlanModePermissions output
|
|
17
|
-
* from shared/plan-mode-permissions.ts (the same setup.ts applies to both
|
|
17
|
+
* from shared/plan-mode-permissions.ts (the same turn-setup.ts applies to both
|
|
18
18
|
* graph sites), not a test copy, so a change to the plan-mode permission set
|
|
19
19
|
* re-proves sub-agent coverage automatically.
|
|
20
20
|
*/
|