@stigmer/runner 3.15.1 → 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
|
@@ -1,13 +1,33 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* V3StatusBuilder — consumes StigmerRunEvents from the V3ProtocolNormalizer
|
|
3
|
-
* and progressively builds the AgentExecutionStatus
|
|
3
|
+
* and progressively builds the transcript half of the AgentExecutionStatus
|
|
4
|
+
* proto it is handed: messages, tool-call rows and their approval status,
|
|
5
|
+
* sub-agent rows, todos, artifacts, write-backs.
|
|
4
6
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
7
|
+
* The one transcript builder of the native harness since S3 M2b: v3 event
|
|
8
|
+
* semantics (tool_call_id keying, content-block-level deltas, explicit tool
|
|
9
|
+
* lifecycle). Its predecessor, the v2 `StatusBuilder` over LangChain's
|
|
10
|
+
* `streamEvents` v2, was retired with the v2 stream (Q-S3-1); the eight
|
|
11
|
+
* golden sequences both once had to agree on are this builder's test's.
|
|
8
12
|
*
|
|
9
|
-
*
|
|
13
|
+
* What this builder deliberately does NOT write, and who does (the adapter
|
|
14
|
+
* contract's field ownership, `harness/types.ts` `TurnSink`): the phase,
|
|
15
|
+
* `startedAt` and `streamingUsage` are the turn runtime's. A gated tool
|
|
16
|
+
* start is reported as the {@link awaitingApproval} fact and the caller
|
|
17
|
+
* (`turn-stream.ts`) decides what that means for the turn; usage is reported
|
|
18
|
+
* raw through {@link V3StatusBuilderOptions.onUsage} and the caller prices
|
|
19
|
+
* it into the sink (until S3 M2a this builder flipped WAITING_FOR_APPROVAL
|
|
20
|
+
* itself and summed usage into `streamingUsage` — a second writer of each
|
|
21
|
+
* field beside the runtime's).
|
|
22
|
+
*
|
|
23
|
+
* Usage is reported on message_finish only (standalone usage events are
|
|
10
24
|
* no-ops) to prevent double-counting — v3 emits both for the same turn.
|
|
25
|
+
* EVERY graph's usage is reported, the sub-agents' included (S3 M2b,
|
|
26
|
+
* Q-M2b-1): a sub-agent's `message_finish` fires the same hook before it is
|
|
27
|
+
* routed to the tracker, so the execution's usage — and the cost cap the
|
|
28
|
+
* runtime enforces over it — is the whole execution's spend. Until M2b the
|
|
29
|
+
* sub-agents' turns were discarded (S3 M2a finding F-M2a-12); the cost cap
|
|
30
|
+
* then lived inside the graph, where a middleware saw every model call.
|
|
11
31
|
*/
|
|
12
32
|
|
|
13
33
|
import { create, type JsonObject } from "@bufbuild/protobuf";
|
|
@@ -20,7 +40,6 @@ import type { AgentMessage, ToolCall } from "@stigmer/protos/ai/stigmer/agentic/
|
|
|
20
40
|
import type { ExecutionArtifact } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/artifact_pb";
|
|
21
41
|
import type { WorkspaceWriteBack } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/writeback_pb";
|
|
22
42
|
import {
|
|
23
|
-
ExecutionPhase,
|
|
24
43
|
MessageType,
|
|
25
44
|
ToolCallStatus,
|
|
26
45
|
ToolKind,
|
|
@@ -31,48 +50,61 @@ import { applyTodoUpdate } from "../../shared/todos.js";
|
|
|
31
50
|
import { ExecutionState } from "./execution-state.js";
|
|
32
51
|
import { utcTimestamp } from "../../shared/status.js";
|
|
33
52
|
import type { ExecutionStatusWriter } from "../../shared/execution-status-writer.js";
|
|
34
|
-
import type { ApprovalPolicyProvider } from "./status-builder.js";
|
|
35
53
|
import type { StigmerRunEvent, V3UsagePayload } from "./v3-events.js";
|
|
36
54
|
import { namespaceDepth } from "./v3-events.js";
|
|
37
55
|
import {
|
|
38
|
-
UsageAccumulator,
|
|
39
56
|
extractToolResultV3,
|
|
40
57
|
sanitizeArgsPreview,
|
|
41
58
|
stampApprovalProvenance,
|
|
59
|
+
type ApprovalPolicyProvider,
|
|
42
60
|
} from "./status-builder-shared.js";
|
|
43
61
|
import { SubAgentTracker } from "./subagent-tracker.js";
|
|
44
62
|
|
|
63
|
+
export interface V3StatusBuilderOptions {
|
|
64
|
+
/**
|
|
65
|
+
* Fired once per `message_finish` that carries usage — the parent graph's
|
|
66
|
+
* and every sub-agent's — with the payload exactly as the protocol
|
|
67
|
+
* delivered it. The builder never sums or prices: the caller accounts (the
|
|
68
|
+
* turn runtime through `TurnSink.reportUsage`, priced at the turn's model;
|
|
69
|
+
* a sub-agent on its own model is priced at the parent's rate, as the
|
|
70
|
+
* in-graph cost cap always did — per-sub-agent pricing is an S5 item).
|
|
71
|
+
*/
|
|
72
|
+
readonly onUsage?: (usage: V3UsagePayload) => void;
|
|
73
|
+
}
|
|
74
|
+
|
|
45
75
|
export class V3StatusBuilder implements ExecutionStatusWriter {
|
|
46
76
|
readonly executionId: string;
|
|
47
77
|
private readonly state: ExecutionState;
|
|
48
78
|
private _forceNextUpdate = false;
|
|
79
|
+
private _awaitingApproval = false;
|
|
49
80
|
private approvalProvider: ApprovalPolicyProvider | null = null;
|
|
50
|
-
private readonly
|
|
81
|
+
private readonly onUsage: ((usage: V3UsagePayload) => void) | undefined;
|
|
51
82
|
private readonly subAgentTracker: SubAgentTracker;
|
|
52
83
|
|
|
53
84
|
/** Progressive tool call arg accumulation keyed by callId. */
|
|
54
85
|
private readonly toolArgBuffers = new Map<string, string>();
|
|
55
86
|
|
|
56
|
-
|
|
87
|
+
/**
|
|
88
|
+
* Builds INTO `status`, by reference: its `messages` and
|
|
89
|
+
* `subAgentExecutions` arrays are the ones indexed and pushed into, never
|
|
90
|
+
* replaced, so a caller that wraps the same status (the write-back
|
|
91
|
+
* coordinator's writer, the runtime's chokepoint) keeps seeing every row.
|
|
92
|
+
*/
|
|
93
|
+
constructor(executionId: string, status: AgentExecutionStatus, options: V3StatusBuilderOptions = {}) {
|
|
57
94
|
this.executionId = executionId;
|
|
58
|
-
this.state = new ExecutionState(
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
//
|
|
62
|
-
//
|
|
63
|
-
//
|
|
64
|
-
//
|
|
65
|
-
|
|
95
|
+
this.state = new ExecutionState(status);
|
|
96
|
+
this.onUsage = options.onUsage;
|
|
97
|
+
|
|
98
|
+
// Resume path: when constructed over a persisted transcript (seeded by the
|
|
99
|
+
// caller on a reinvocation), rebuild the tool-call index so resumed
|
|
100
|
+
// tool_started/tool_finished events reconcile to the existing calls
|
|
101
|
+
// instead of duplicating them. A first run carries no messages, so this
|
|
102
|
+
// is a no-op. The tracker does the same for the seeded sub-agent rows.
|
|
103
|
+
if (status.messages.length > 0) {
|
|
66
104
|
this.state.rebuildToolCallIndex();
|
|
67
105
|
}
|
|
68
106
|
|
|
69
|
-
|
|
70
|
-
if (!initialStatus.startedAt) {
|
|
71
|
-
initialStatus.startedAt = utcTimestamp();
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
this.usageAccumulator = new UsageAccumulator();
|
|
75
|
-
this.subAgentTracker = new SubAgentTracker();
|
|
107
|
+
this.subAgentTracker = new SubAgentTracker(status.subAgentExecutions);
|
|
76
108
|
}
|
|
77
109
|
|
|
78
110
|
setApprovalProvider(provider: ApprovalPolicyProvider): void {
|
|
@@ -83,6 +115,16 @@ export class V3StatusBuilder implements ExecutionStatusWriter {
|
|
|
83
115
|
return this.state.proto;
|
|
84
116
|
}
|
|
85
117
|
|
|
118
|
+
/**
|
|
119
|
+
* True once a tool call this turn was gated and left WAITING_APPROVAL: the
|
|
120
|
+
* engine has interrupted (or will, at this step's end) and the turn should
|
|
121
|
+
* end awaiting a decision. A fact about the transcript, not a phase — the
|
|
122
|
+
* caller owns the phase.
|
|
123
|
+
*/
|
|
124
|
+
get awaitingApproval(): boolean {
|
|
125
|
+
return this._awaitingApproval;
|
|
126
|
+
}
|
|
127
|
+
|
|
86
128
|
get forceNextUpdate(): boolean {
|
|
87
129
|
return this._forceNextUpdate;
|
|
88
130
|
}
|
|
@@ -119,6 +161,9 @@ export class V3StatusBuilder implements ExecutionStatusWriter {
|
|
|
119
161
|
}
|
|
120
162
|
|
|
121
163
|
if (this.subAgentTracker.isSubAgentNamespace(event.namespace)) {
|
|
164
|
+
// A sub-agent's spend is the execution's spend (Q-M2b-1): report it
|
|
165
|
+
// through the one hook before the tracker folds the message.
|
|
166
|
+
if (event.kind === "message_finish" && event.usage) this.onUsage?.(event.usage);
|
|
122
167
|
this.subAgentTracker.routeEvent(event);
|
|
123
168
|
return;
|
|
124
169
|
}
|
|
@@ -219,7 +264,7 @@ export class V3StatusBuilder implements ExecutionStatusWriter {
|
|
|
219
264
|
}
|
|
220
265
|
|
|
221
266
|
if (usage) {
|
|
222
|
-
this.
|
|
267
|
+
this.onUsage?.(usage);
|
|
223
268
|
}
|
|
224
269
|
}
|
|
225
270
|
|
|
@@ -257,8 +302,9 @@ export class V3StatusBuilder implements ExecutionStatusWriter {
|
|
|
257
302
|
namespace: string,
|
|
258
303
|
): void {
|
|
259
304
|
// Resume reconciliation: the gated tool call already exists, seeded from the
|
|
260
|
-
// persisted transcript of a prior invocation (
|
|
261
|
-
//
|
|
305
|
+
// persisted transcript of a prior invocation (the runtime's
|
|
306
|
+
// `seedFromPersistedStatus`, `harness/turn-context.ts`). The durable
|
|
307
|
+
// checkpoint re-emits tool_started now that approval
|
|
262
308
|
// is granted — flip the existing call to RUNNING in place rather than
|
|
263
309
|
// appending a duplicate or re-triggering the approval gate. v3 keys by
|
|
264
310
|
// tool_call_id, so this is an exact match (no name heuristics needed).
|
|
@@ -270,7 +316,6 @@ export class V3StatusBuilder implements ExecutionStatusWriter {
|
|
|
270
316
|
if (Object.keys(input).length > 0 && !existing.args) {
|
|
271
317
|
existing.args = input as JsonObject;
|
|
272
318
|
}
|
|
273
|
-
this.state.toolStartTimes.set(callId, performance.now());
|
|
274
319
|
this._forceNextUpdate = true;
|
|
275
320
|
return;
|
|
276
321
|
}
|
|
@@ -304,7 +349,8 @@ export class V3StatusBuilder implements ExecutionStatusWriter {
|
|
|
304
349
|
|
|
305
350
|
// Stamp authorization provenance in the same spot as tool_kind, for every
|
|
306
351
|
// observed tool call (gated or auto-approved). A gated call is re-seeded on
|
|
307
|
-
// reinvocation (
|
|
352
|
+
// reinvocation (the runtime's wide seed) with the same source carried
|
|
353
|
+
// through the interrupt.
|
|
308
354
|
stampApprovalProvenance(tc, this.approvalProvider);
|
|
309
355
|
|
|
310
356
|
if (approvalReq.requiresApproval) {
|
|
@@ -317,12 +363,11 @@ export class V3StatusBuilder implements ExecutionStatusWriter {
|
|
|
317
363
|
tc.argsPreview = argsPreview;
|
|
318
364
|
}
|
|
319
365
|
|
|
320
|
-
this.
|
|
366
|
+
this._awaitingApproval = true;
|
|
321
367
|
}
|
|
322
368
|
|
|
323
369
|
parentMsg.toolCalls.push(tc);
|
|
324
370
|
this.state.toolCalls.set(callId, tc);
|
|
325
|
-
this.state.toolStartTimes.set(callId, performance.now());
|
|
326
371
|
|
|
327
372
|
this._forceNextUpdate = true;
|
|
328
373
|
}
|
|
@@ -339,7 +384,6 @@ export class V3StatusBuilder implements ExecutionStatusWriter {
|
|
|
339
384
|
tc.result = extractToolResultV3(output);
|
|
340
385
|
tc.completedAt = utcTimestamp();
|
|
341
386
|
tc.isStreaming = false;
|
|
342
|
-
this.state.toolStartTimes.delete(callId);
|
|
343
387
|
this.toolArgBuffers.delete(callId);
|
|
344
388
|
|
|
345
389
|
// Project a completed to-do write into status.todos. deepagents' write_todos
|
|
@@ -364,7 +408,6 @@ export class V3StatusBuilder implements ExecutionStatusWriter {
|
|
|
364
408
|
tc.error = message;
|
|
365
409
|
tc.completedAt = utcTimestamp();
|
|
366
410
|
tc.isStreaming = false;
|
|
367
|
-
this.state.toolStartTimes.delete(callId);
|
|
368
411
|
this.toolArgBuffers.delete(callId);
|
|
369
412
|
|
|
370
413
|
this._forceNextUpdate = true;
|
|
@@ -498,21 +541,6 @@ export class V3StatusBuilder implements ExecutionStatusWriter {
|
|
|
498
541
|
return msg;
|
|
499
542
|
}
|
|
500
543
|
|
|
501
|
-
// ── Usage ──────────────────────────────────────────────────────────
|
|
502
|
-
|
|
503
|
-
private accumulateV3Usage(usage: V3UsagePayload): void {
|
|
504
|
-
const meta: Record<string, unknown> = {
|
|
505
|
-
input_tokens: usage.input_tokens,
|
|
506
|
-
output_tokens: usage.output_tokens,
|
|
507
|
-
};
|
|
508
|
-
if (usage.input_token_details) {
|
|
509
|
-
meta.cache_read_input_tokens = usage.input_token_details.cache_read;
|
|
510
|
-
meta.cache_creation_input_tokens = usage.input_token_details.cache_creation;
|
|
511
|
-
}
|
|
512
|
-
this.usageAccumulator.accumulate(meta);
|
|
513
|
-
this.state.proto.streamingUsage = this.usageAccumulator.toProto();
|
|
514
|
-
}
|
|
515
|
-
|
|
516
544
|
// ── Sub-Agent Integration ──────────────────────────────────────────
|
|
517
545
|
|
|
518
546
|
/**
|
|
@@ -525,20 +553,13 @@ export class V3StatusBuilder implements ExecutionStatusWriter {
|
|
|
525
553
|
}
|
|
526
554
|
|
|
527
555
|
/**
|
|
528
|
-
*
|
|
529
|
-
*
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
this.state.proto.subAgentExecutions = this.subAgentTracker.getExecutions();
|
|
534
|
-
}
|
|
535
|
-
}
|
|
536
|
-
|
|
537
|
-
/**
|
|
538
|
-
* Cancel all in-progress sub-agents (called on parent cancellation).
|
|
556
|
+
* Clear the streaming flag on every sub-agent message still marked as
|
|
557
|
+
* streaming — what a turn that stopped mid-delegation owes the transcript
|
|
558
|
+
* beside the CANCELLED status the caller stamps on the row itself
|
|
559
|
+
* (`shared/subagent-rows.ts` `cancelInProgressSubAgentProtos`, the one
|
|
560
|
+
* home of that transition for every harness).
|
|
539
561
|
*/
|
|
540
|
-
|
|
541
|
-
this.subAgentTracker.
|
|
542
|
-
this.syncSubAgentExecutions();
|
|
562
|
+
finalizeSubAgentStreaming(): void {
|
|
563
|
+
this.subAgentTracker.finalizeAllStreaming();
|
|
543
564
|
}
|
|
544
565
|
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `harness/approval-decisions.ts` — the runtime's one settler of a decision
|
|
3
|
+
* that never runs the tool. These arms came with the function from the
|
|
4
|
+
* native harness's `hitl.ts` (`reconcileNonExecutingDecisions`, S3 M1 /
|
|
5
|
+
* M2a): SKIP and REJECT settle to SKIPPED (REJECT with the pinned reason),
|
|
6
|
+
* APPROVE and APPROVE_ALL are left to the engine's own events, sub-agent
|
|
7
|
+
* transcripts are settled alike, and an undecided row is untouched. The
|
|
8
|
+
* reader half (`approvalDecisionsOf`) is pinned against the Cursor adapter's
|
|
9
|
+
* own reader in `execute-cursor/__tests__/approval-decisions-agree.test.ts`
|
|
10
|
+
* and exercised through `turn-context.test.ts`.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { describe, it, expect } from "vitest";
|
|
14
|
+
import { create } from "@bufbuild/protobuf";
|
|
15
|
+
import { AgentExecutionStatusSchema } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/api_pb";
|
|
16
|
+
import { AgentMessageSchema, ToolCallSchema } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/message_pb";
|
|
17
|
+
import { SubAgentExecutionSchema } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/subagent_pb";
|
|
18
|
+
import { ApprovalAction, ToolCallStatus } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
|
|
19
|
+
import { REJECTED_BY_USER_ERROR, terminalizeNonExecutingDecisions } from "../approval-decisions.js";
|
|
20
|
+
|
|
21
|
+
describe("terminalizeNonExecutingDecisions", () => {
|
|
22
|
+
function statusWith(
|
|
23
|
+
toolCalls: Array<{ id: string; status: ToolCallStatus; approvalAction: ApprovalAction }>,
|
|
24
|
+
) {
|
|
25
|
+
return create(AgentExecutionStatusSchema, {
|
|
26
|
+
messages: [
|
|
27
|
+
create(AgentMessageSchema, {
|
|
28
|
+
toolCalls: toolCalls.map(tc =>
|
|
29
|
+
create(ToolCallSchema, {
|
|
30
|
+
id: tc.id,
|
|
31
|
+
name: "test_tool",
|
|
32
|
+
status: tc.status,
|
|
33
|
+
approvalAction: tc.approvalAction,
|
|
34
|
+
}),
|
|
35
|
+
),
|
|
36
|
+
}),
|
|
37
|
+
],
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
it("terminalizes a REJECT decision to SKIPPED with the pinned reason (does not FAIL)", () => {
|
|
42
|
+
const status = statusWith([{
|
|
43
|
+
id: "call-reject",
|
|
44
|
+
status: ToolCallStatus.TOOL_CALL_WAITING_APPROVAL,
|
|
45
|
+
approvalAction: ApprovalAction.REJECT,
|
|
46
|
+
}]);
|
|
47
|
+
|
|
48
|
+
terminalizeNonExecutingDecisions(status);
|
|
49
|
+
|
|
50
|
+
const tc = status.messages[0].toolCalls[0];
|
|
51
|
+
expect(tc.status).toBe(ToolCallStatus.TOOL_CALL_SKIPPED);
|
|
52
|
+
expect(tc.error).toBe(REJECTED_BY_USER_ERROR);
|
|
53
|
+
// The REJECT decision is preserved so the audit trail stays honest.
|
|
54
|
+
expect(tc.approvalAction).toBe(ApprovalAction.REJECT);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it("terminalizes a SKIP decision to SKIPPED (fixes the stuck-WAITING for skip too)", () => {
|
|
58
|
+
const status = statusWith([{
|
|
59
|
+
id: "call-skip",
|
|
60
|
+
status: ToolCallStatus.TOOL_CALL_WAITING_APPROVAL,
|
|
61
|
+
approvalAction: ApprovalAction.SKIP,
|
|
62
|
+
}]);
|
|
63
|
+
|
|
64
|
+
terminalizeNonExecutingDecisions(status);
|
|
65
|
+
|
|
66
|
+
expect(status.messages[0].toolCalls[0].status).toBe(ToolCallStatus.TOOL_CALL_SKIPPED);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it("leaves APPROVE / APPROVE_ALL untouched (the tool executes)", () => {
|
|
70
|
+
const status = statusWith([
|
|
71
|
+
{ id: "call-approve", status: ToolCallStatus.TOOL_CALL_WAITING_APPROVAL, approvalAction: ApprovalAction.APPROVE },
|
|
72
|
+
{ id: "call-approve-all", status: ToolCallStatus.TOOL_CALL_WAITING_APPROVAL, approvalAction: ApprovalAction.APPROVE_ALL },
|
|
73
|
+
]);
|
|
74
|
+
|
|
75
|
+
terminalizeNonExecutingDecisions(status);
|
|
76
|
+
|
|
77
|
+
// Still WAITING — real tool events (not this reconciler) terminalize them.
|
|
78
|
+
expect(status.messages[0].toolCalls[0].status).toBe(ToolCallStatus.TOOL_CALL_WAITING_APPROVAL);
|
|
79
|
+
expect(status.messages[0].toolCalls[1].status).toBe(ToolCallStatus.TOOL_CALL_WAITING_APPROVAL);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it("settles sub-agent transcripts too", () => {
|
|
83
|
+
const status = create(AgentExecutionStatusSchema, {
|
|
84
|
+
subAgentExecutions: [
|
|
85
|
+
create(SubAgentExecutionSchema, {
|
|
86
|
+
id: "sub-1",
|
|
87
|
+
messages: [
|
|
88
|
+
create(AgentMessageSchema, {
|
|
89
|
+
toolCalls: [create(ToolCallSchema, {
|
|
90
|
+
id: "sub-call-skip",
|
|
91
|
+
name: "test_tool",
|
|
92
|
+
status: ToolCallStatus.TOOL_CALL_WAITING_APPROVAL,
|
|
93
|
+
approvalAction: ApprovalAction.SKIP,
|
|
94
|
+
})],
|
|
95
|
+
}),
|
|
96
|
+
],
|
|
97
|
+
}),
|
|
98
|
+
],
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
terminalizeNonExecutingDecisions(status);
|
|
102
|
+
|
|
103
|
+
expect(status.subAgentExecutions[0].messages[0].toolCalls[0].status).toBe(ToolCallStatus.TOOL_CALL_SKIPPED);
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it("is a no-op when there are no decided tool calls", () => {
|
|
107
|
+
const status = statusWith([{
|
|
108
|
+
id: "call-pending",
|
|
109
|
+
status: ToolCallStatus.TOOL_CALL_WAITING_APPROVAL,
|
|
110
|
+
approvalAction: ApprovalAction.UNSPECIFIED,
|
|
111
|
+
}]);
|
|
112
|
+
|
|
113
|
+
expect(() => terminalizeNonExecutingDecisions(status)).not.toThrow();
|
|
114
|
+
expect(status.messages[0].toolCalls[0].status).toBe(ToolCallStatus.TOOL_CALL_WAITING_APPROVAL);
|
|
115
|
+
});
|
|
116
|
+
});
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The runtime's capture (`harness/capture.ts`) over a REAL git work tree,
|
|
3
|
+
* without any engine: the pin, the candidate, the stamp, the provenance and
|
|
4
|
+
* the review decision, each as the runtime performs it between the
|
|
5
|
+
* resolution phases and the outcome table.
|
|
6
|
+
*
|
|
7
|
+
* What is asserted here and nowhere else are the two rules the lift made
|
|
8
|
+
* one for every harness (S3 M4, Q-M4-5, Q-M4-6):
|
|
9
|
+
*
|
|
10
|
+
* - the stamp reads the ROW's status: a COMPLETED write row created this
|
|
11
|
+
* turn is badged, a FAILED or WAITING one is not, a seeded prior-turn row
|
|
12
|
+
* keeps its own change set;
|
|
13
|
+
* - the provenance scopes by id-novelty and consents by the row's own
|
|
14
|
+
* approval: the approved command that executed ON ITS SEEDED ROW (message
|
|
15
|
+
* 0, the shape both engines produce — F-M4-P3) qualifies the turn, where
|
|
16
|
+
* a positional scope missed it.
|
|
17
|
+
*
|
|
18
|
+
* The ledger shape itself is `shared/filereview/capture.ts`'s and is pinned
|
|
19
|
+
* by its own tests and the two harnesses' `file-review-capture` goldens; the
|
|
20
|
+
* end-to-end pause and reconcile are the kit's runtime arm. The git fixture
|
|
21
|
+
* is the shared one every file-review scenario stands on.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
25
|
+
import { tmpdir } from "node:os";
|
|
26
|
+
import { join } from "node:path";
|
|
27
|
+
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
28
|
+
import { create, type JsonObject } from "@bufbuild/protobuf";
|
|
29
|
+
import { AgentExecutionStatusSchema, type AgentExecutionStatus } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/api_pb";
|
|
30
|
+
import { AgentMessageSchema, ToolCallSchema, type ToolCall } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/message_pb";
|
|
31
|
+
import { SubAgentExecutionSchema } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/subagent_pb";
|
|
32
|
+
import { ApprovalAction, FileChangeKind, MessageType, SnapshotKind, ToolCallStatus } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
|
|
33
|
+
|
|
34
|
+
import { makeInMemoryArtifactStorage } from "../../__test-utils__/fake-artifact-storage.js";
|
|
35
|
+
import { initGitWorkspace } from "../../__test-utils__/git-workspace-fixture.js";
|
|
36
|
+
import { mockWorkspaceBackend } from "../../__test-utils__/mock-workspace.js";
|
|
37
|
+
import type { FileReviewIdentity } from "../capabilities.js";
|
|
38
|
+
import { captureCandidate, deriveCommandProvenance, pinCaptureBaseline } from "../capture.js";
|
|
39
|
+
import type { TurnWorkspace } from "../types.js";
|
|
40
|
+
|
|
41
|
+
const EXECUTION_ID = "aex-capture-unit";
|
|
42
|
+
const FILE_REVIEW: FileReviewIdentity = { harnessId: "unit", excludePaths: [".unit/scratch.json"] };
|
|
43
|
+
|
|
44
|
+
function workspaceOver(root: string, turnSeq = 0): TurnWorkspace {
|
|
45
|
+
return {
|
|
46
|
+
dirs: [root],
|
|
47
|
+
primaryDir: root,
|
|
48
|
+
gitWorkspace: true,
|
|
49
|
+
captureMode: true,
|
|
50
|
+
changeSetId: `${EXECUTION_ID}:${turnSeq}`,
|
|
51
|
+
provision: { workspaceDirs: [root], provisionResults: [], workspaceBackend: mockWorkspaceBackend() },
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** The three row facts these arms vary: the args (a path for the stamp), the server's verdict, a prior stamp. */
|
|
56
|
+
interface RowFacts {
|
|
57
|
+
readonly args?: JsonObject;
|
|
58
|
+
readonly approvalAction?: ApprovalAction;
|
|
59
|
+
readonly fileChangeSetId?: string;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function row(id: string, name: string, status: ToolCallStatus, extra: RowFacts = {}): ToolCall {
|
|
63
|
+
return create(ToolCallSchema, { id, name, status, ...extra });
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function messageWith(...toolCalls: ToolCall[]) {
|
|
67
|
+
return create(AgentMessageSchema, { type: MessageType.MESSAGE_AI, toolCalls });
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
describe("harness/capture over a git work tree", () => {
|
|
71
|
+
let root: string;
|
|
72
|
+
let status: AgentExecutionStatus;
|
|
73
|
+
|
|
74
|
+
beforeEach(() => {
|
|
75
|
+
root = mkdtempSync(join(tmpdir(), "stigmer-capture-unit-"));
|
|
76
|
+
initGitWorkspace(root, { "notes.md": "one\n", "keep.md": "keep\n" });
|
|
77
|
+
status = create(AgentExecutionStatusSchema, {});
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
afterEach(() => {
|
|
81
|
+
rmSync(root, { recursive: true, force: true });
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it("outside capture mode there is nothing to pin", async () => {
|
|
85
|
+
const capture = await pinCaptureBaseline({
|
|
86
|
+
status,
|
|
87
|
+
executionId: EXECUTION_ID,
|
|
88
|
+
workspace: { ...workspaceOver(root), captureMode: false },
|
|
89
|
+
fileReview: FILE_REVIEW,
|
|
90
|
+
artifactStorage: undefined,
|
|
91
|
+
});
|
|
92
|
+
expect(capture).toBeUndefined();
|
|
93
|
+
expect(status.fileReviewEventStream).toBeUndefined();
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it("pins the baseline, captures the net change after the turn, stamps only the COMPLETED write rows, and reports the review pending", async () => {
|
|
97
|
+
const workspace = workspaceOver(root);
|
|
98
|
+
const capture = (await pinCaptureBaseline({ status, executionId: EXECUTION_ID, workspace, fileReview: FILE_REVIEW, artifactStorage: undefined }))!;
|
|
99
|
+
expect(capture.baselineTree).toMatch(/^[0-9a-f]{40}$/);
|
|
100
|
+
expect(status.fileReviewEventStream?.events.map((e) => e.payload.case)).toEqual(["baselineCaptured"]);
|
|
101
|
+
|
|
102
|
+
// The engine's turn: one edit flowed, one edit failed, one write is still
|
|
103
|
+
// waiting at a gate (a deny-and-retry harness's denied row); an excluded
|
|
104
|
+
// path written by the harness itself must never reach the diff.
|
|
105
|
+
writeFileSync(join(root, "notes.md"), "one\ntwo\n");
|
|
106
|
+
mkdirSync(join(root, ".unit"));
|
|
107
|
+
writeFileSync(join(root, ".unit/scratch.json"), "{}");
|
|
108
|
+
status.messages.push(
|
|
109
|
+
messageWith(
|
|
110
|
+
row("tc-flowed", "write_file", ToolCallStatus.TOOL_CALL_COMPLETED, { args: { file_path: "notes.md", content: "one\ntwo\n" } }),
|
|
111
|
+
row("tc-failed", "write_file", ToolCallStatus.TOOL_CALL_FAILED, { args: { file_path: "other.md" } }),
|
|
112
|
+
row("tc-denied", "write_file", ToolCallStatus.TOOL_CALL_WAITING_APPROVAL, { args: { file_path: ".env" } }),
|
|
113
|
+
),
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
const pending = await captureCandidate({
|
|
117
|
+
status,
|
|
118
|
+
executionId: EXECUTION_ID,
|
|
119
|
+
workspace,
|
|
120
|
+
fileReview: FILE_REVIEW,
|
|
121
|
+
artifactStorage: undefined,
|
|
122
|
+
capture,
|
|
123
|
+
globalBypass: false,
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
expect(pending).toBe(true);
|
|
127
|
+
const events = status.fileReviewEventStream?.events ?? [];
|
|
128
|
+
expect(events.map((e) => e.payload.case)).toEqual(["baselineCaptured", "candidateCaptured"]);
|
|
129
|
+
const candidate = events[1]!.payload;
|
|
130
|
+
if (candidate.case !== "candidateCaptured") throw new Error("unreachable");
|
|
131
|
+
expect(candidate.value.changes.map((c) => c.pathAfter), "the excluded path never enters the diff").toEqual(["notes.md"]);
|
|
132
|
+
expect(candidate.value.candidateSnapshot?.kind).toBe(SnapshotKind.GIT_TREE_REF);
|
|
133
|
+
expect(candidate.value.commandProvenance, "a file-tool turn never qualifies for auto-keep").toBeUndefined();
|
|
134
|
+
|
|
135
|
+
const byId = new Map(status.messages.flatMap((m) => m.toolCalls).map((tc) => [tc.id, tc.fileChangeSetId]));
|
|
136
|
+
expect(byId.get("tc-flowed"), "the COMPLETED write is badged").toBe(workspace.changeSetId);
|
|
137
|
+
expect(byId.get("tc-failed"), "a FAILED write did not land").toBe("");
|
|
138
|
+
expect(byId.get("tc-denied"), "a WAITING write did not land").toBe("");
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
it("a turn that changed nothing authors no candidate and pends no review", async () => {
|
|
142
|
+
const workspace = workspaceOver(root);
|
|
143
|
+
const capture = (await pinCaptureBaseline({ status, executionId: EXECUTION_ID, workspace, fileReview: FILE_REVIEW, artifactStorage: undefined }))!;
|
|
144
|
+
const pending = await captureCandidate({ status, executionId: EXECUTION_ID, workspace, fileReview: FILE_REVIEW, artifactStorage: undefined, capture, globalBypass: false });
|
|
145
|
+
expect(pending).toBe(false);
|
|
146
|
+
expect(status.fileReviewEventStream?.events.map((e) => e.payload.case)).toEqual(["baselineCaptured"]);
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
it("a turn that changed nothing on the tree stamps no row, even a COMPLETED write whose edit was reverted before the boundary", async () => {
|
|
150
|
+
const workspace = workspaceOver(root);
|
|
151
|
+
const capture = (await pinCaptureBaseline({ status, executionId: EXECUTION_ID, workspace, fileReview: FILE_REVIEW, artifactStorage: undefined }))!;
|
|
152
|
+
status.messages.push(messageWith(row("tc-reverted", "write_file", ToolCallStatus.TOOL_CALL_COMPLETED, { args: { file_path: "notes.md" } })));
|
|
153
|
+
// The engine wrote and then wrote the original back: no net change.
|
|
154
|
+
writeFileSync(join(root, "notes.md"), "one\n");
|
|
155
|
+
|
|
156
|
+
const pending = await captureCandidate({ status, executionId: EXECUTION_ID, workspace, fileReview: FILE_REVIEW, artifactStorage: undefined, capture, globalBypass: false });
|
|
157
|
+
|
|
158
|
+
expect(pending).toBe(false);
|
|
159
|
+
expect(status.messages[0]!.toolCalls[0]!.fileChangeSetId, "a row must never reference a change set that does not exist").toBe("");
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
it("the progress substrate follows the workspace shape: git-only without storage surfaces the tracked change; CAS reads what the adapter bound", async () => {
|
|
163
|
+
const gitOnly = (await pinCaptureBaseline({ status, executionId: EXECUTION_ID, workspace: workspaceOver(root), fileReview: FILE_REVIEW, artifactStorage: undefined }))!;
|
|
164
|
+
writeFileSync(join(root, "notes.md"), "one\ntwo\n");
|
|
165
|
+
const tracked = await gitOnly.progress.substrate.capture();
|
|
166
|
+
expect(tracked.changed).toBe(true);
|
|
167
|
+
expect(tracked.delta.entries.map((e) => e.pathAfter)).toEqual(["notes.md"]);
|
|
168
|
+
|
|
169
|
+
// A non-git workspace with storage: the CAS slice alone, over the reader
|
|
170
|
+
// the adapter binds; unbound it reads nothing observed.
|
|
171
|
+
const casRoot = mkdtempSync(join(tmpdir(), "stigmer-capture-cas-"));
|
|
172
|
+
try {
|
|
173
|
+
const casWorkspace: TurnWorkspace = { ...workspaceOver(casRoot), gitWorkspace: false };
|
|
174
|
+
const cas = (await pinCaptureBaseline({
|
|
175
|
+
status: create(AgentExecutionStatusSchema, {}),
|
|
176
|
+
executionId: EXECUTION_ID,
|
|
177
|
+
workspace: casWorkspace,
|
|
178
|
+
fileReview: FILE_REVIEW,
|
|
179
|
+
artifactStorage: makeInMemoryArtifactStorage().storage,
|
|
180
|
+
}))!;
|
|
181
|
+
expect(cas.baselineTree, "a non-git baseline is the CAS manifest, not a tree").toBe("");
|
|
182
|
+
writeFileSync(join(casRoot, "scratch.log"), "line\n");
|
|
183
|
+
expect((await cas.progress.substrate.capture()).delta.entries, "nothing bound, nothing observed").toEqual([]);
|
|
184
|
+
cas.casObservations = () => ({ before: new Map([["scratch.log", null]]), blockedSecretPaths: new Set() });
|
|
185
|
+
const observed = await cas.progress.substrate.capture();
|
|
186
|
+
expect(observed.delta.entries.map((e) => [e.pathAfter, e.kind])).toEqual([["scratch.log", FileChangeKind.ADD]]);
|
|
187
|
+
} finally {
|
|
188
|
+
rmSync(casRoot, { recursive: true, force: true });
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
it("scopes the stamp to this turn: a seeded prior-turn row keeps its change set, a sub-agent row created this turn takes the parent's", async () => {
|
|
193
|
+
// The seed a reinvocation carries: a prior turn's flowed row and a prior sub-agent row.
|
|
194
|
+
status.messages.push(messageWith(row("tc-prior", "write_file", ToolCallStatus.TOOL_CALL_COMPLETED, { fileChangeSetId: `${EXECUTION_ID}:0` })));
|
|
195
|
+
status.subAgentExecutions.push(
|
|
196
|
+
create(SubAgentExecutionSchema, { id: "sa-prior", name: "editor", messages: [messageWith(row("sa-tc-prior", "write_file", ToolCallStatus.TOOL_CALL_COMPLETED))] }),
|
|
197
|
+
);
|
|
198
|
+
const workspace = workspaceOver(root, 1);
|
|
199
|
+
const capture = (await pinCaptureBaseline({ status, executionId: EXECUTION_ID, workspace, fileReview: FILE_REVIEW, artifactStorage: undefined }))!;
|
|
200
|
+
|
|
201
|
+
writeFileSync(join(root, "keep.md"), "kept and changed\n");
|
|
202
|
+
status.subAgentExecutions[0]!.messages.push(messageWith(row("sa-tc-new", "write_file", ToolCallStatus.TOOL_CALL_COMPLETED)));
|
|
203
|
+
|
|
204
|
+
await captureCandidate({ status, executionId: EXECUTION_ID, workspace, fileReview: FILE_REVIEW, artifactStorage: undefined, capture, globalBypass: false });
|
|
205
|
+
|
|
206
|
+
expect(status.messages[0]!.toolCalls[0]!.fileChangeSetId, "the prior turn's row is untouched").toBe(`${EXECUTION_ID}:0`);
|
|
207
|
+
const sub = status.subAgentExecutions[0]!.messages.flatMap((m) => m.toolCalls);
|
|
208
|
+
expect(sub.find((tc) => tc.id === "sa-tc-prior")!.fileChangeSetId, "the prior sub-agent row is untouched").toBe("");
|
|
209
|
+
expect(sub.find((tc) => tc.id === "sa-tc-new")!.fileChangeSetId, "this turn's sub-agent row takes the parent set").toBe(`${EXECUTION_ID}:1`);
|
|
210
|
+
});
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
describe("deriveCommandProvenance — one rule for both engines (F-M4-P3)", () => {
|
|
214
|
+
const seededShell = (status: ToolCallStatus, approvalAction: ApprovalAction) =>
|
|
215
|
+
row("tc-shell", "shell", status, { approvalAction, args: { command: "make generate" } });
|
|
216
|
+
|
|
217
|
+
it("qualifies the approved command that executed ON ITS SEEDED ROW — the shape a positional scope missed", () => {
|
|
218
|
+
// Turn 1 left the gate row WAITING at message 0; the reinvocation
|
|
219
|
+
// reconciled the re-attempt onto it: same id, same position, COMPLETED,
|
|
220
|
+
// the server's APPROVE preserved. It had NOT settled before this turn.
|
|
221
|
+
const status = create(AgentExecutionStatusSchema, {
|
|
222
|
+
messages: [
|
|
223
|
+
messageWith(seededShell(ToolCallStatus.TOOL_CALL_COMPLETED, ApprovalAction.APPROVE)),
|
|
224
|
+
create(AgentMessageSchema, { type: MessageType.MESSAGE_AI, content: "Generated." }),
|
|
225
|
+
],
|
|
226
|
+
});
|
|
227
|
+
const provenance = deriveCommandProvenance(status, { priorSettledToolCallIds: new Set(), priorSubAgentToolCallIds: new Set() }, false);
|
|
228
|
+
expect(provenance?.consentToolCallIds).toEqual(["tc-shell"]);
|
|
229
|
+
expect(provenance?.authorizedByAutoApproveAll).toBe(false);
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
it("the gate turn itself does not qualify: the proposed command is WAITING, not executed", () => {
|
|
233
|
+
const status = create(AgentExecutionStatusSchema, {
|
|
234
|
+
messages: [messageWith(seededShell(ToolCallStatus.TOOL_CALL_WAITING_APPROVAL, ApprovalAction.UNSPECIFIED))],
|
|
235
|
+
});
|
|
236
|
+
expect(deriveCommandProvenance(status, { priorSettledToolCallIds: new Set(), priorSubAgentToolCallIds: new Set() }, false)).toBeUndefined();
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
it("a command settled before this turn is prior history and cannot qualify or disqualify it", () => {
|
|
240
|
+
const status = create(AgentExecutionStatusSchema, {
|
|
241
|
+
messages: [
|
|
242
|
+
messageWith(seededShell(ToolCallStatus.TOOL_CALL_COMPLETED, ApprovalAction.APPROVE)),
|
|
243
|
+
messageWith(row("tc-read", "read_file", ToolCallStatus.TOOL_CALL_COMPLETED)),
|
|
244
|
+
],
|
|
245
|
+
});
|
|
246
|
+
expect(
|
|
247
|
+
deriveCommandProvenance(status, { priorSettledToolCallIds: new Set(["tc-shell"]), priorSubAgentToolCallIds: new Set() }, false),
|
|
248
|
+
"no executed consented command THIS turn",
|
|
249
|
+
).toBeUndefined();
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
it("any sub-agent activity this turn fails closed (DD-28 D1)", () => {
|
|
253
|
+
const status = create(AgentExecutionStatusSchema, {
|
|
254
|
+
messages: [messageWith(seededShell(ToolCallStatus.TOOL_CALL_COMPLETED, ApprovalAction.APPROVE))],
|
|
255
|
+
subAgentExecutions: [create(SubAgentExecutionSchema, { id: "sa", messages: [messageWith(row("sa-tc", "write_file", ToolCallStatus.TOOL_CALL_COMPLETED))] })],
|
|
256
|
+
});
|
|
257
|
+
expect(deriveCommandProvenance(status, { priorSettledToolCallIds: new Set(), priorSubAgentToolCallIds: new Set() }, false)).toBeUndefined();
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
it("under the global bypass an executed unconsented command is attributed to auto_approve_all", () => {
|
|
261
|
+
const status = create(AgentExecutionStatusSchema, {
|
|
262
|
+
messages: [messageWith(row("tc-shell", "shell", ToolCallStatus.TOOL_CALL_COMPLETED, { args: { command: "make" } }))],
|
|
263
|
+
});
|
|
264
|
+
const provenance = deriveCommandProvenance(status, { priorSettledToolCallIds: new Set(), priorSubAgentToolCallIds: new Set() }, true);
|
|
265
|
+
expect(provenance?.authorizedByAutoApproveAll).toBe(true);
|
|
266
|
+
expect(provenance?.consentToolCallIds).toEqual([]);
|
|
267
|
+
});
|
|
268
|
+
});
|