@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
package/src/harness/types.ts
CHANGED
|
@@ -54,8 +54,14 @@
|
|
|
54
54
|
* - No persist cadence. The runtime's chokepoint is single-flight and
|
|
55
55
|
* unconditional at settle; WHEN a streaming turn asks for a write is the
|
|
56
56
|
* adapter's (`shared/persist-decision.ts` over its own dirty flags, since
|
|
57
|
-
* what counts as a discrete change is engine knowledge)
|
|
58
|
-
*
|
|
57
|
+
* what counts as a discrete change is engine knowledge). Revisited with
|
|
58
|
+
* both loops in view at S3 M4 and kept (Q-S3-13): the cadence RULE is
|
|
59
|
+
* shared, the timing is the engine's.
|
|
60
|
+
* - No capture. The file-review capture is the runtime's whole
|
|
61
|
+
* (`harness/capture.ts`): the baseline before `runTurn`, the candidate
|
|
62
|
+
* after it, the stamp, the review decision. The one capture fact an
|
|
63
|
+
* adapter holds — what its engine observed touching CAS-owned paths — it
|
|
64
|
+
* binds through `TurnSink.bindCasObservations`.
|
|
59
65
|
*
|
|
60
66
|
* Module shape follows `shared/checkpointer/`: `types.ts`, `capabilities.ts`,
|
|
61
67
|
* `registry.ts`, no barrel.
|
|
@@ -82,6 +88,7 @@ import type { EffectiveThinkingMode } from "../shared/thinking-mode.js";
|
|
|
82
88
|
import type { SenderIdentity } from "../shared/sender-identity.js";
|
|
83
89
|
import type { DeclaredPreferencesContent } from "../shared/declared-preferences.js";
|
|
84
90
|
import type { RecalledMemoriesContent } from "../shared/recalled-memories.js";
|
|
91
|
+
import type { CasTouchedReader } from "../shared/filereview/cas-touched.js";
|
|
85
92
|
import type { HarnessCapabilities } from "./capabilities.js";
|
|
86
93
|
|
|
87
94
|
/**
|
|
@@ -196,6 +203,21 @@ export interface TurnMcp {
|
|
|
196
203
|
readonly policies: ReadonlyMap<string, MergedToolPolicy>;
|
|
197
204
|
}
|
|
198
205
|
|
|
206
|
+
/**
|
|
207
|
+
* The mounted skills (phase 5), each under the session's platform dir and
|
|
208
|
+
* reachable from the workspace through its `.stigmer` link; the harness
|
|
209
|
+
* renders them into its prompt shapes. Resolved per OWNER, because a
|
|
210
|
+
* sub-agent's skills are its own prompt's, not the root's: the root's are
|
|
211
|
+
* `blueprint.mergedSkillRefs` (agent plus session), a sub-agent's are its
|
|
212
|
+
* `skillRefs` on the blueprint, keyed by the sub-agent's name (the key its
|
|
213
|
+
* compiler uses). A sub-agent with no skills has no entry. Empty for a
|
|
214
|
+
* harness whose `capabilities.subAgents` is false.
|
|
215
|
+
*/
|
|
216
|
+
export interface TurnSkills {
|
|
217
|
+
readonly root: readonly SkillMetadata[];
|
|
218
|
+
readonly bySubAgent: ReadonlyMap<string, readonly SkillMetadata[]>;
|
|
219
|
+
}
|
|
220
|
+
|
|
199
221
|
/** The turn's explicit inputs (phase 5b), resolved into the workspace with the vision facts derived once. */
|
|
200
222
|
export interface TurnAttachments {
|
|
201
223
|
readonly results: readonly ResolvedAttachment[];
|
|
@@ -245,9 +267,13 @@ export interface TurnStandingContext {
|
|
|
245
267
|
* `engine-minted` harness's first turn (nothing minted yet) and the id the
|
|
246
268
|
* adapter bound through {@link TurnSink.bindHarnessState} on every later
|
|
247
269
|
* invocation; the runtime-minted id on every turn of a `deterministic`
|
|
248
|
-
* harness. An adapter derives create-vs-resume from it and its
|
|
249
|
-
*
|
|
250
|
-
*
|
|
270
|
+
* harness. An adapter derives create-vs-resume for its ENGINE from it and its
|
|
271
|
+
* own state; the runtime derives its own reinvocation fact (the seed, the
|
|
272
|
+
* reconcile) in `turn-context.ts`'s `isReinvocation`, one arm per
|
|
273
|
+
* `stateIdSource`. The contract carries no flag because the two readings
|
|
274
|
+
* answer different questions ("does the engine hold state for this session"
|
|
275
|
+
* vs "does this execution have a transcript") and one name over two meanings
|
|
276
|
+
* would be the divergence a contract exists to prevent.
|
|
251
277
|
*
|
|
252
278
|
* Adapter-only facts (the Cursor mode, the service-tier params, the seeded
|
|
253
279
|
* sub-agent rows) are read by the adapter from these records, never resolved
|
|
@@ -278,8 +304,7 @@ export interface TurnInput extends NormalizedActivityInput {
|
|
|
278
304
|
readonly environment: TurnEnvironment;
|
|
279
305
|
readonly workspace: TurnWorkspace;
|
|
280
306
|
readonly mcp: TurnMcp;
|
|
281
|
-
|
|
282
|
-
readonly skills: readonly SkillMetadata[];
|
|
307
|
+
readonly skills: TurnSkills;
|
|
283
308
|
readonly attachments: TurnAttachments;
|
|
284
309
|
/** Approved whole-file writes the runtime applied itself this turn (exact-apply); the harness issues no grant for them. */
|
|
285
310
|
readonly appliedToolCallIds: ReadonlySet<string>;
|
|
@@ -304,11 +329,10 @@ export interface TurnInput extends NormalizedActivityInput {
|
|
|
304
329
|
* the adapter appends the engine's transcript rows (assistant messages,
|
|
305
330
|
* tool-call rows and their approval status, sub-agent rows, todos); the
|
|
306
331
|
* runtime writes the phase, the terminal system messages, `streamingUsage`,
|
|
307
|
-
* artifacts, write-backs
|
|
308
|
-
*
|
|
309
|
-
*
|
|
310
|
-
*
|
|
311
|
-
* says so.)
|
|
332
|
+
* artifacts, write-backs, `fileChangeProgress`, the file-review ledger
|
|
333
|
+
* events and the change-set stamp on a flowed edit row (S3 M4,
|
|
334
|
+
* `harness/capture.ts`). An adapter never writes a phase or a terminal copy:
|
|
335
|
+
* those are Temporal semantics the runtime owns once.
|
|
312
336
|
*/
|
|
313
337
|
export interface TurnSink {
|
|
314
338
|
/**
|
|
@@ -398,6 +422,26 @@ export interface TurnSink {
|
|
|
398
422
|
* that error and executes nothing further.
|
|
399
423
|
*/
|
|
400
424
|
bindHarnessState(harnessStateId: string): Promise<void>;
|
|
425
|
+
|
|
426
|
+
/**
|
|
427
|
+
* What the engine observed touching CAS-owned paths this turn — gitignored
|
|
428
|
+
* paths in a git tree, every path in a non-git one: the pre-turn bytes of
|
|
429
|
+
* each first-touched path and the paths the gate blocked as secrets
|
|
430
|
+
* (`shared/filereview/cas-touched.ts`). The one fact about a turn's file
|
|
431
|
+
* changes the runtime cannot read from the tree: the pre-edit bytes exist
|
|
432
|
+
* only at mutation time, in whatever sits between the engine and the disk
|
|
433
|
+
* (the deep-agent's filesystem backend and gate, the Cursor hook's
|
|
434
|
+
* sidecar). The runtime reads the AFTER bytes itself and owns everything
|
|
435
|
+
* else of the capture (`harness/capture.ts`): the baseline, the progress,
|
|
436
|
+
* the candidate, the stamp, the review decision.
|
|
437
|
+
*
|
|
438
|
+
* Bound once, before the first persist, as `bindHarnessState` is; the
|
|
439
|
+
* runtime pulls it at each progress refresh and at the turn boundary, so
|
|
440
|
+
* it must return an atomic snapshot (copy live state before any await). A
|
|
441
|
+
* harness that observes nothing binds nothing and gets git-only capture.
|
|
442
|
+
* Never throws.
|
|
443
|
+
*/
|
|
444
|
+
bindCasObservations(read: CasTouchedReader): void;
|
|
401
445
|
}
|
|
402
446
|
|
|
403
447
|
/**
|
|
@@ -460,6 +504,15 @@ export type FailureSurface = "engine" | "actionable" | "internal";
|
|
|
460
504
|
* takes, `cause` is for the log. The runtime persists FAILED and RETURNS
|
|
461
505
|
* (Temporal does not retry a returned activity; re-running the same
|
|
462
506
|
* prompt would fail the same way).
|
|
507
|
+
* - `tool_call_limit`: the engine exhausted the tool-round budget the
|
|
508
|
+
* execution set (`max_tool_rounds`, `shared/tool-rounds.ts`) and stopped
|
|
509
|
+
* at a step boundary with its work checkpointed. Not `failed`: the
|
|
510
|
+
* platform deliberately stopped the run, and the conversation continues
|
|
511
|
+
* on the next message. The runtime writes TERMINATED with the cross-repo
|
|
512
|
+
* prefix and the user copy, and RETURNS (a retry would spend the same
|
|
513
|
+
* budget again). Every surveyed SDK ends a turn on a budget with a
|
|
514
|
+
* distinct outcome (Claude's `maxTurns` subtype, Codex's turn reason), so
|
|
515
|
+
* this is a cross-harness fact, not an engine quirk.
|
|
463
516
|
* - `interrupted`: `sink.stopSignal` aborted and the adapter stopped. WHY it
|
|
464
517
|
* aborted is the runtime's evidence (its watchdog, its accounting, its
|
|
465
518
|
* chokepoint, the cancellation it was delivered), so no reason rides here;
|
|
@@ -469,5 +522,6 @@ export type TurnOutcome =
|
|
|
469
522
|
| { readonly kind: "completed" }
|
|
470
523
|
| { readonly kind: "cancelled" }
|
|
471
524
|
| { readonly kind: "awaiting_approval" }
|
|
525
|
+
| { readonly kind: "tool_call_limit" }
|
|
472
526
|
| { readonly kind: "failed"; readonly message: string; readonly surface: FailureSurface; readonly cause?: unknown }
|
|
473
527
|
| { readonly kind: "interrupted" };
|
package/src/harness-adapters.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The harnesses this worker serves: one registry row per adapter, in boot
|
|
3
3
|
* order. The ONE place an adapter's factory is named outside its own
|
|
4
|
-
* directory
|
|
4
|
+
* directory; both composition roots read this table and nothing else to
|
|
5
|
+
* learn which harnesses exist.
|
|
5
6
|
*
|
|
6
7
|
* Lives at the source root, beside the composition roots that read it, and
|
|
7
8
|
* not in `harness/registry.ts`: a row imports its adapter from
|
|
@@ -11,20 +12,27 @@
|
|
|
11
12
|
*
|
|
12
13
|
* ORDER IS LOAD-BEARING (`registry.ts` `bootHarnesses`): the Cursor
|
|
13
14
|
* adapter's interceptors must patch `node:http2` before anything dials the
|
|
14
|
-
* control plane, so it boots first. The native deep-agent
|
|
15
|
-
*
|
|
16
|
-
*
|
|
15
|
+
* control plane, so it boots first. The native deep-agent adapter boots
|
|
16
|
+
* second; its `boot` registers the deepagents harness profiles and loads
|
|
17
|
+
* LangChain, both after the patch (S3 M2b, 2026-09-13; until then the roots
|
|
18
|
+
* imported the native orchestrator directly beside this table).
|
|
17
19
|
*
|
|
18
20
|
* THIS MODULE'S STATIC GRAPH MUST STAY CONNECT- AND SDK-FREE. The roots
|
|
19
21
|
* import it BEFORE they boot the harnesses, and the Cursor adapter's boot is
|
|
20
22
|
* where `node:http2` is patched and `@cursor/sdk` first loaded; an adapter
|
|
21
|
-
* factory that imported its SDK statically would defeat both.
|
|
22
|
-
* named here loads its vendor SDK inside `boot` (`adapter.ts`
|
|
23
|
-
*
|
|
24
|
-
*
|
|
23
|
+
* factory that imported its SDK statically would defeat both. Every adapter
|
|
24
|
+
* named here loads its vendor SDK inside `boot` (`execute-cursor/adapter.ts`
|
|
25
|
+
* and `execute-deep-agent/adapter.ts` show the shape; each has a fence that
|
|
26
|
+
* walks its static graph). `__tests__/harness-boot-order.test.ts` boots a
|
|
27
|
+
* fresh process through this module — both rows — and fails if the graph
|
|
28
|
+
* regresses.
|
|
25
29
|
*/
|
|
26
30
|
|
|
27
31
|
import { createCursorAdapter } from "./activities/execute-cursor/adapter.js";
|
|
32
|
+
import { createDeepAgentAdapter } from "./activities/execute-deep-agent/adapter.js";
|
|
28
33
|
import type { HarnessRow } from "./harness/registry.js";
|
|
29
34
|
|
|
30
|
-
export const HARNESS_ADAPTERS: readonly HarnessRow[] = [
|
|
35
|
+
export const HARNESS_ADAPTERS: readonly HarnessRow[] = [
|
|
36
|
+
{ harness: "cursor", adapter: createCursorAdapter() },
|
|
37
|
+
{ harness: "deep-agent", adapter: createDeepAgentAdapter() },
|
|
38
|
+
];
|
|
@@ -48,7 +48,7 @@ describe("ApprovalGateMiddleware", () => {
|
|
|
48
48
|
});
|
|
49
49
|
|
|
50
50
|
// The global pre-arm (spec.auto_approve_all) is no longer the gate's concern:
|
|
51
|
-
// setup.ts simply does not install the gate when it is set. The gate is always
|
|
51
|
+
// turn-setup.ts simply does not install the gate when it is set. The gate is always
|
|
52
52
|
// active once built; scoped leases (below) decide what it lets through.
|
|
53
53
|
|
|
54
54
|
it("auto-approves a built-in whose category holds a run-lifetime lease", async () => {
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The cost advisory: prices each model call off `usage_metadata`, keeps one
|
|
3
|
+
* running total the sub-agent views share, and warns the model ONCE at the
|
|
4
|
+
* configured share of `max_cost_usd`. Nothing here caps: the enforcement is
|
|
5
|
+
* the turn runtime's (`shared/__tests__/cost-guard.test.ts`,
|
|
6
|
+
* `harness/__tests__/run-turn.test.ts`'s cost-cap arm). Until S3 M2b this
|
|
7
|
+
* file was `cost-cap.test.ts` and also pinned the in-graph tool block and
|
|
8
|
+
* the "exceeded" message — retired with that half (Q-S3-3, Q-M2b-9).
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { describe, it, expect } from "vitest";
|
|
12
|
+
import { AIMessage } from "@langchain/core/messages";
|
|
13
|
+
import { createCostAdvisoryMiddleware } from "../cost-advisory.js";
|
|
14
|
+
|
|
15
|
+
function stateWithUsage(inputTokens: number, outputTokens: number, cacheRead = 0): Record<string, unknown> {
|
|
16
|
+
const aiMsg = new AIMessage({ content: "response" });
|
|
17
|
+
(aiMsg as unknown as Record<string, unknown>).usage_metadata = {
|
|
18
|
+
input_tokens: inputTokens,
|
|
19
|
+
output_tokens: outputTokens,
|
|
20
|
+
input_token_details: { cache_read: cacheRead },
|
|
21
|
+
};
|
|
22
|
+
return { messages: [aiMsg] };
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const BASE_CONFIG = {
|
|
26
|
+
maxCostUsd: 1.0,
|
|
27
|
+
inputPricePerMillion: 3.0,
|
|
28
|
+
outputPricePerMillion: 15.0,
|
|
29
|
+
cacheReadPricePerMillion: 0.3,
|
|
30
|
+
warningPct: 80,
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
function warningOf(result: unknown): string | undefined {
|
|
34
|
+
const messages = (result as { messages?: Array<{ content: unknown }> } | undefined)?.messages;
|
|
35
|
+
return messages?.[0] ? String(messages[0].content) : undefined;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
describe("CostAdvisoryMiddleware", () => {
|
|
39
|
+
it("prices a model call from usage_metadata", () => {
|
|
40
|
+
const mw = createCostAdvisoryMiddleware(BASE_CONFIG);
|
|
41
|
+
mw.afterModel!(stateWithUsage(1000, 500), {});
|
|
42
|
+
// (1000 * 3 + 500 * 15) / 1_000_000 = 0.0105
|
|
43
|
+
expect(mw.runningCost).toBeCloseTo(0.0105, 4);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it("prices cache reads at their own rate when configured", () => {
|
|
47
|
+
const mw = createCostAdvisoryMiddleware(BASE_CONFIG);
|
|
48
|
+
mw.afterModel!(stateWithUsage(1000, 500, 600), {});
|
|
49
|
+
// regular input 400 * 3 + cache 600 * 0.3 + output 500 * 15 = 8,880 / 1M
|
|
50
|
+
expect(mw.runningCost).toBeCloseTo(0.00888, 4);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it("accumulates across model calls", () => {
|
|
54
|
+
const mw = createCostAdvisoryMiddleware(BASE_CONFIG);
|
|
55
|
+
mw.afterModel!(stateWithUsage(1000, 500), {});
|
|
56
|
+
mw.afterModel!(stateWithUsage(2000, 1000), {});
|
|
57
|
+
expect(mw.runningCost).toBeCloseTo(0.0315, 4);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it("skips a message without usage_metadata", () => {
|
|
61
|
+
const mw = createCostAdvisoryMiddleware(BASE_CONFIG);
|
|
62
|
+
mw.afterModel!({ messages: [new AIMessage({ content: "no usage" })] }, {});
|
|
63
|
+
expect(mw.runningCost).toBe(0);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it("warns once at the warning share of the cap, and never blocks a tool", () => {
|
|
67
|
+
const mw = createCostAdvisoryMiddleware({ ...BASE_CONFIG, maxCostUsd: 0.01, warningPct: 80 });
|
|
68
|
+
// $0.0105 crosses 80% of $0.01.
|
|
69
|
+
const first = warningOf(mw.afterModel!(stateWithUsage(1000, 500), {}));
|
|
70
|
+
expect(first).toContain("Budget warning");
|
|
71
|
+
expect(first).toContain("$0.01");
|
|
72
|
+
// Far past the cap: still no second message, and no tool hook exists to block with.
|
|
73
|
+
const second = mw.afterModel!(stateWithUsage(100_000, 50_000), {});
|
|
74
|
+
expect(second).toBeUndefined();
|
|
75
|
+
expect(mw.wrapToolCall, "the advisory has no power over tool calls; the runtime enforces the cap").toBeUndefined();
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it("resets its total on beforeAgent", () => {
|
|
79
|
+
const mw = createCostAdvisoryMiddleware(BASE_CONFIG);
|
|
80
|
+
mw.afterModel!(stateWithUsage(1000, 500), {});
|
|
81
|
+
mw.beforeAgent!({}, {});
|
|
82
|
+
expect(mw.runningCost).toBe(0);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it("rejects a non-positive cap and a warning share outside 50–95", () => {
|
|
86
|
+
expect(() => createCostAdvisoryMiddleware({ ...BASE_CONFIG, maxCostUsd: 0 })).toThrow("maxCostUsd");
|
|
87
|
+
expect(() => createCostAdvisoryMiddleware({ ...BASE_CONFIG, maxCostUsd: -1 })).toThrow("maxCostUsd");
|
|
88
|
+
expect(() => createCostAdvisoryMiddleware({ ...BASE_CONFIG, warningPct: 49 })).toThrow("warningPct");
|
|
89
|
+
expect(() => createCostAdvisoryMiddleware({ ...BASE_CONFIG, warningPct: 96 })).toThrow("warningPct");
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
describe("forSubAgent", () => {
|
|
93
|
+
it("advances the parent's running total", () => {
|
|
94
|
+
const parent = createCostAdvisoryMiddleware(BASE_CONFIG);
|
|
95
|
+
parent.forSubAgent().afterModel!(stateWithUsage(1000, 500), {});
|
|
96
|
+
expect(parent.runningCost).toBeCloseTo(0.0105, 4);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it("does not reset the total when the sub-agent starts", () => {
|
|
100
|
+
const parent = createCostAdvisoryMiddleware(BASE_CONFIG);
|
|
101
|
+
parent.afterModel!(stateWithUsage(1000, 500), {});
|
|
102
|
+
const child = parent.forSubAgent();
|
|
103
|
+
expect(child.beforeAgent, "the view has no beforeAgent on purpose").toBeUndefined();
|
|
104
|
+
expect(parent.runningCost).toBeCloseTo(0.0105, 4);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it("warns inside the sub-agent when its call crosses the parent's threshold", () => {
|
|
108
|
+
const parent = createCostAdvisoryMiddleware({ ...BASE_CONFIG, maxCostUsd: 0.01 });
|
|
109
|
+
const warning = warningOf(parent.forSubAgent().afterModel!(stateWithUsage(1000, 500), {}));
|
|
110
|
+
expect(warning).toContain("Budget warning");
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
});
|
|
@@ -109,7 +109,7 @@ export interface ApprovalGateConfig {
|
|
|
109
109
|
* gitignored path stays on the interrupt gate exactly as before.
|
|
110
110
|
*
|
|
111
111
|
* True only for gates whose backend a CAS observer wraps: the parent gate
|
|
112
|
-
* always (setup.ts), and — since DD-19 — sub-agent gates too, because
|
|
112
|
+
* always (turn-setup.ts), and — since DD-19 — sub-agent gates too, because
|
|
113
113
|
* `compileSubagents` gives every sub-agent a CAS-observing backend wired to
|
|
114
114
|
* the SAME shared observer and `buildSubAgentMiddleware` then inherits this
|
|
115
115
|
* config verbatim. A gate over an UNOBSERVED backend must keep this false:
|
|
@@ -199,7 +199,7 @@ export function createApprovalGateMiddleware(
|
|
|
199
199
|
const leasedCategories = config.leasedCategories ?? EMPTY_CATEGORY_SET;
|
|
200
200
|
|
|
201
201
|
// No global-bypass early return: a pre-armed spec.auto_approve_all means the
|
|
202
|
-
// gate is never even installed (setup.ts builds this config only when not
|
|
202
|
+
// gate is never even installed (turn-setup.ts builds this config only when not
|
|
203
203
|
// global). Scoped leases keep the gate active so non-leased actions still gate.
|
|
204
204
|
|
|
205
205
|
return {
|
|
@@ -1,29 +1,46 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Cost
|
|
2
|
+
* Cost advisory middleware: warns the model once as the execution's estimated
|
|
3
|
+
* spend nears `max_cost_usd`, so it can wrap up before the cap.
|
|
3
4
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
5
|
+
* It ADVISES; it does not cap. The one enforcement of `max_cost_usd` is the
|
|
6
|
+
* turn runtime's (`harness/run-turn.ts` over `shared/cost-guard.ts`): every
|
|
7
|
+
* usage delta the adapter reports moves the runtime's estimate, and when the
|
|
8
|
+
* estimate crosses the cap the runtime stops the turn and settles TERMINATED
|
|
9
|
+
* with the cost-limit copy. The graph learns of the stop through its abort
|
|
10
|
+
* signal, the same way it learns of a platform STOP or a stall. This is the
|
|
11
|
+
* shape `execution-budget.ts` already has beside LangGraph's `recursionLimit`:
|
|
12
|
+
* the middleware warns inside the graph, the engine's own limit enforces.
|
|
6
13
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
14
|
+
* Until S3 M2b (Q-S3-3) this module was `cost-cap.ts` and did both: it also
|
|
15
|
+
* blocked every tool call once the running cost passed the cap and gave the
|
|
16
|
+
* model one tool-free round to summarize. That second enforcement lived
|
|
17
|
+
* inside the graph, where the runtime could not see it, and a platform STOP
|
|
18
|
+
* had a sibling (`graceful-stop.ts`, deleted with it) that let the run spend
|
|
19
|
+
* a summary round after the platform said stop. Both went when the runtime
|
|
20
|
+
* became the one place a turn is stopped (harness runtime program, S3).
|
|
10
21
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
22
|
+
* afterModel — reads `usage_metadata` off the latest AIMessage, prices the
|
|
23
|
+
* call at the parent's rates (a sub-agent on its own model is priced the
|
|
24
|
+
* same way the enforcement prices it; per-sub-agent pricing is an S5 item),
|
|
25
|
+
* accumulates the running total, and injects the warning SystemMessage once
|
|
26
|
+
* at `warningPct` of the cap.
|
|
13
27
|
*
|
|
14
|
-
*
|
|
28
|
+
* forSubAgent — a view that shares the running total, so a sub-agent's calls
|
|
29
|
+
* advance the same figure the parent's warning reads.
|
|
30
|
+
*
|
|
31
|
+
* Only built when `max_cost_usd > 0` is explicitly configured.
|
|
15
32
|
*/
|
|
16
33
|
|
|
17
|
-
import {
|
|
18
|
-
import type { StigmerMiddleware,
|
|
34
|
+
import { SystemMessage } from "@langchain/core/messages";
|
|
35
|
+
import type { StigmerMiddleware, CostAdvisoryConfig } from "./types.js";
|
|
19
36
|
|
|
20
37
|
const DEFAULT_WARNING_PCT = 80;
|
|
21
38
|
const MIN_WARNING_PCT = 50;
|
|
22
39
|
const MAX_WARNING_PCT = 95;
|
|
23
40
|
|
|
24
|
-
export interface
|
|
41
|
+
export interface CostAdvisoryMiddleware extends StigmerMiddleware {
|
|
42
|
+
/** The running estimate this advisory has priced, in USD. */
|
|
25
43
|
readonly runningCost: number;
|
|
26
|
-
readonly exceeded: boolean;
|
|
27
44
|
forSubAgent(): StigmerMiddleware;
|
|
28
45
|
}
|
|
29
46
|
|
|
@@ -49,7 +66,7 @@ function extractUsage(aiMessage: Record<string, unknown>): {
|
|
|
49
66
|
return { totalInput, output, cacheRead };
|
|
50
67
|
}
|
|
51
68
|
|
|
52
|
-
export function
|
|
69
|
+
export function createCostAdvisoryMiddleware(config: CostAdvisoryConfig): CostAdvisoryMiddleware {
|
|
53
70
|
const {
|
|
54
71
|
maxCostUsd,
|
|
55
72
|
inputPricePerMillion,
|
|
@@ -65,7 +82,6 @@ export function createCostCapMiddleware(config: CostCapConfig): CostCapMiddlewar
|
|
|
65
82
|
|
|
66
83
|
let runningCost = 0;
|
|
67
84
|
let warned = false;
|
|
68
|
-
let exceeded = false;
|
|
69
85
|
let modelCallCount = 0;
|
|
70
86
|
|
|
71
87
|
function computeCallCost(totalInput: number, output: number, cacheRead: number): number {
|
|
@@ -99,21 +115,7 @@ export function createCostCapMiddleware(config: CostCapConfig): CostCapMiddlewar
|
|
|
99
115
|
});
|
|
100
116
|
}
|
|
101
117
|
|
|
102
|
-
function createExceededMessage(): SystemMessage {
|
|
103
|
-
return new SystemMessage({
|
|
104
|
-
content:
|
|
105
|
-
`Budget exceeded: This execution has consumed ` +
|
|
106
|
-
`$${runningCost.toFixed(4)}, exceeding the ` +
|
|
107
|
-
`$${maxCostUsd.toFixed(2)} budget. ` +
|
|
108
|
-
`All tool calls are now blocked. ` +
|
|
109
|
-
`Respond with a summary of what you accomplished and ` +
|
|
110
|
-
`what work remains so the user can continue.`,
|
|
111
|
-
});
|
|
112
|
-
}
|
|
113
|
-
|
|
114
118
|
function processAfterModel(state: Record<string, unknown>): { messages: SystemMessage[] } | void {
|
|
115
|
-
if (exceeded) return;
|
|
116
|
-
|
|
117
119
|
const messages = (state.messages ?? []) as unknown[];
|
|
118
120
|
let lastAi: Record<string, unknown> | null = null;
|
|
119
121
|
for (let i = messages.length - 1; i >= 0; i--) {
|
|
@@ -128,57 +130,28 @@ export function createCostCapMiddleware(config: CostCapConfig): CostCapMiddlewar
|
|
|
128
130
|
const { totalInput, output, cacheRead } = extractUsage(lastAi);
|
|
129
131
|
if (totalInput === 0 && output === 0) return;
|
|
130
132
|
|
|
131
|
-
|
|
132
|
-
runningCost += callCost;
|
|
133
|
+
runningCost += computeCallCost(totalInput, output, cacheRead);
|
|
133
134
|
modelCallCount++;
|
|
134
135
|
|
|
135
136
|
const warningThreshold = maxCostUsd * warningPct / 100;
|
|
136
|
-
|
|
137
|
-
if (runningCost >= maxCostUsd) {
|
|
138
|
-
exceeded = true;
|
|
139
|
-
console.warn(
|
|
140
|
-
`[CostCap] EXCEEDED: $${runningCost.toFixed(4)} >= $${maxCostUsd.toFixed(2)} ` +
|
|
141
|
-
`after ${modelCallCount} calls. Tool execution will be blocked.`,
|
|
142
|
-
);
|
|
143
|
-
return { messages: [createExceededMessage()] };
|
|
144
|
-
}
|
|
145
|
-
|
|
146
137
|
if (!warned && runningCost >= warningThreshold) {
|
|
147
138
|
warned = true;
|
|
148
139
|
console.warn(
|
|
149
|
-
`[
|
|
140
|
+
`[CostAdvisory] WARNING: $${runningCost.toFixed(4)} >= $${warningThreshold.toFixed(4)} ` +
|
|
150
141
|
`(${warningPct}% of $${maxCostUsd.toFixed(2)}) after ${modelCallCount} calls.`,
|
|
151
142
|
);
|
|
152
143
|
return { messages: [createWarningMessage()] };
|
|
153
144
|
}
|
|
154
145
|
}
|
|
155
146
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
handler: Parameters<NonNullable<StigmerMiddleware["wrapToolCall"]>>[1],
|
|
159
|
-
) {
|
|
160
|
-
if (exceeded) {
|
|
161
|
-
return new ToolMessage({
|
|
162
|
-
content:
|
|
163
|
-
`[Budget exceeded: tool execution blocked. ` +
|
|
164
|
-
`Summarize your progress for the user.]`,
|
|
165
|
-
tool_call_id: request.toolCall.id,
|
|
166
|
-
name: request.toolCall.name,
|
|
167
|
-
});
|
|
168
|
-
}
|
|
169
|
-
return await handler(request);
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
const middleware: CostCapMiddleware = {
|
|
173
|
-
name: "CostCapMiddleware",
|
|
147
|
+
const middleware: CostAdvisoryMiddleware = {
|
|
148
|
+
name: "CostAdvisoryMiddleware",
|
|
174
149
|
|
|
175
150
|
get runningCost() { return runningCost; },
|
|
176
|
-
get exceeded() { return exceeded; },
|
|
177
151
|
|
|
178
152
|
beforeAgent() {
|
|
179
153
|
runningCost = 0;
|
|
180
154
|
warned = false;
|
|
181
|
-
exceeded = false;
|
|
182
155
|
modelCallCount = 0;
|
|
183
156
|
},
|
|
184
157
|
|
|
@@ -186,25 +159,22 @@ export function createCostCapMiddleware(config: CostCapConfig): CostCapMiddlewar
|
|
|
186
159
|
return processAfterModel(state);
|
|
187
160
|
},
|
|
188
161
|
|
|
189
|
-
wrapToolCall: processWrapToolCall,
|
|
190
|
-
|
|
191
162
|
afterAgent() {
|
|
192
163
|
const pctUsed = maxCostUsd > 0
|
|
193
164
|
? (runningCost / maxCostUsd * 100)
|
|
194
165
|
: 0;
|
|
195
166
|
console.log(
|
|
196
|
-
`[
|
|
197
|
-
`(~${pctUsed.toFixed(0)}%) across ${modelCallCount} calls,
|
|
198
|
-
`warned=${warned}, exceeded=${exceeded}`,
|
|
167
|
+
`[CostAdvisory] Summary: $${runningCost.toFixed(4)} of $${maxCostUsd.toFixed(2)} ` +
|
|
168
|
+
`(~${pctUsed.toFixed(0)}%) across ${modelCallCount} calls, warned=${warned}`,
|
|
199
169
|
);
|
|
200
170
|
},
|
|
201
171
|
|
|
202
172
|
forSubAgent(): StigmerMiddleware {
|
|
203
173
|
return {
|
|
204
|
-
name: "
|
|
205
|
-
//
|
|
174
|
+
name: "CostAdvisorySubAgentView",
|
|
175
|
+
// The view does NOT reset the running total on beforeAgent: a
|
|
176
|
+
// sub-agent's calls advance the parent's figure.
|
|
206
177
|
afterModel(state) { return processAfterModel(state); },
|
|
207
|
-
wrapToolCall: processWrapToolCall,
|
|
208
178
|
};
|
|
209
179
|
},
|
|
210
180
|
};
|
package/src/middleware/index.ts
CHANGED
|
@@ -1,43 +1,53 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Middleware stack factory.
|
|
2
|
+
* Middleware stack factory for the native harness's root graph.
|
|
3
3
|
*
|
|
4
|
-
* Assembles the ordered middleware array from a MiddlewareStackConfig.
|
|
5
|
-
*
|
|
4
|
+
* Assembles the ordered middleware array from a MiddlewareStackConfig. The
|
|
5
|
+
* order is load-bearing and reads top to bottom:
|
|
6
6
|
*
|
|
7
7
|
* 0. Path normalization (conditional: only on permission-rule-bearing
|
|
8
8
|
* graphs — FIRST, so every downstream middleware observes canonical
|
|
9
9
|
* workspace-absolute paths)
|
|
10
10
|
* 1. Loop detection (always)
|
|
11
|
-
* 2. Execution budget (always
|
|
11
|
+
* 2. Execution budget (always — advises at ~80% of the tool-round budget
|
|
12
|
+
* that LangGraph's `recursionLimit` enforces)
|
|
12
13
|
* 3. Tool intent (always — bind-time shell schema extension, issue #276)
|
|
13
14
|
* 4. Tool truncation (always)
|
|
14
|
-
* 5.
|
|
15
|
-
* 6. Cost
|
|
15
|
+
* 5. Approval gate (conditional: absent under the global bypass)
|
|
16
|
+
* 6. Cost advisory (conditional: only when maxCostUsd > 0 — advises at
|
|
17
|
+
* ~80% of the cap that the turn runtime enforces)
|
|
16
18
|
* 7. Error hints (always)
|
|
17
19
|
* 8. OTel spans (always, no-op when OTel not configured)
|
|
20
|
+
*
|
|
21
|
+
* Every middleware here either shapes the graph's tool surface or ADVISES
|
|
22
|
+
* the model; none of them stops the run. A stop — the platform's, the
|
|
23
|
+
* cost cap's, a stall's — is the turn runtime's, delivered to the graph
|
|
24
|
+
* through its abort signal (harness runtime program, S3 Q-S3-3; until M2b a
|
|
25
|
+
* graceful-stop middleware and the cost cap's tool block were second stops
|
|
26
|
+
* inside the graph that the runtime could not see).
|
|
27
|
+
*
|
|
28
|
+
* The sub-agent stack is `execute-deep-agent/subagent-wiring.ts`'s: the same
|
|
29
|
+
* order over the parent's shared instances where one exists (the advisory's
|
|
30
|
+
* running total), fresh ones otherwise.
|
|
18
31
|
*/
|
|
19
32
|
|
|
20
33
|
import type { StigmerMiddleware, MiddlewareStackConfig } from "./types.js";
|
|
21
|
-
import type { GracefulStopMiddleware } from "./graceful-stop.js";
|
|
22
34
|
import { createPathNormalizationMiddleware } from "./path-normalization.js";
|
|
23
35
|
import { createLoopDetectionMiddleware } from "./loop-detection.js";
|
|
24
36
|
import { createExecutionBudgetMiddleware } from "./execution-budget.js";
|
|
25
37
|
import { createToolIntentMiddleware } from "./tool-intent.js";
|
|
26
38
|
import { createToolTruncationMiddleware } from "./tool-truncation.js";
|
|
27
|
-
import { createGracefulStopMiddleware } from "./graceful-stop.js";
|
|
28
39
|
import { createApprovalGateMiddleware } from "./approval-gate.js";
|
|
29
|
-
import {
|
|
40
|
+
import { createCostAdvisoryMiddleware, type CostAdvisoryMiddleware } from "./cost-advisory.js";
|
|
30
41
|
import { createErrorHintsMiddleware } from "./error-hints.js";
|
|
31
42
|
import { createOtelSpansMiddleware } from "./otel-spans.js";
|
|
32
43
|
|
|
33
|
-
export type {
|
|
34
|
-
export type { CostCapMiddleware } from "./cost-cap.js";
|
|
44
|
+
export type { CostAdvisoryMiddleware } from "./cost-advisory.js";
|
|
35
45
|
export type { StigmerMiddleware, MiddlewareStackConfig } from "./types.js";
|
|
36
46
|
|
|
37
47
|
export interface MiddlewareStackResult {
|
|
38
48
|
readonly middleware: StigmerMiddleware[];
|
|
39
|
-
|
|
40
|
-
readonly
|
|
49
|
+
/** The advisory's instance, for the sub-agent stacks to share its running total; null when no cap is configured. */
|
|
50
|
+
readonly costAdvisory: CostAdvisoryMiddleware | null;
|
|
41
51
|
}
|
|
42
52
|
|
|
43
53
|
export function buildMiddlewareStack(
|
|
@@ -50,32 +60,22 @@ export function buildMiddlewareStack(
|
|
|
50
60
|
}
|
|
51
61
|
|
|
52
62
|
stack.push(createLoopDetectionMiddleware(config.loopDetection));
|
|
53
|
-
|
|
54
63
|
stack.push(createExecutionBudgetMiddleware(config.executionBudget));
|
|
55
|
-
|
|
56
64
|
stack.push(createToolIntentMiddleware());
|
|
57
|
-
|
|
58
65
|
stack.push(createToolTruncationMiddleware(config.toolTruncation));
|
|
59
66
|
|
|
60
|
-
const gracefulStop = createGracefulStopMiddleware();
|
|
61
|
-
stack.push(gracefulStop);
|
|
62
|
-
|
|
63
67
|
if (config.approvalGate) {
|
|
64
68
|
stack.push(createApprovalGateMiddleware(config.approvalGate));
|
|
65
69
|
}
|
|
66
70
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
stack.push(createOtelSpansMiddleware(config.otelSpans));
|
|
73
|
-
|
|
74
|
-
return { middleware: stack, gracefulStop, costCap: costCapMiddleware };
|
|
75
|
-
}
|
|
71
|
+
const costAdvisory =
|
|
72
|
+
config.costAdvisory && config.costAdvisory.maxCostUsd > 0
|
|
73
|
+
? createCostAdvisoryMiddleware(config.costAdvisory)
|
|
74
|
+
: null;
|
|
75
|
+
if (costAdvisory) stack.push(costAdvisory);
|
|
76
76
|
|
|
77
77
|
stack.push(createErrorHintsMiddleware());
|
|
78
78
|
stack.push(createOtelSpansMiddleware(config.otelSpans));
|
|
79
79
|
|
|
80
|
-
return { middleware: stack,
|
|
80
|
+
return { middleware: stack, costAdvisory };
|
|
81
81
|
}
|
package/src/middleware/types.ts
CHANGED
|
@@ -82,7 +82,8 @@ export interface ToolTruncationConfig {
|
|
|
82
82
|
readonly onTruncation?: (toolName: string, charsTruncated: number) => void;
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
-
|
|
85
|
+
/** The cap the advisory warns toward; the turn runtime enforces it (`shared/cost-guard.ts`). */
|
|
86
|
+
export interface CostAdvisoryConfig {
|
|
86
87
|
readonly maxCostUsd: number;
|
|
87
88
|
readonly inputPricePerMillion: number;
|
|
88
89
|
readonly outputPricePerMillion: number;
|
|
@@ -113,7 +114,7 @@ export interface MiddlewareStackConfig {
|
|
|
113
114
|
readonly loopDetection?: Partial<LoopDetectionConfig>;
|
|
114
115
|
readonly executionBudget?: Partial<ExecutionBudgetConfig>;
|
|
115
116
|
readonly toolTruncation?: Partial<ToolTruncationConfig>;
|
|
116
|
-
readonly
|
|
117
|
+
readonly costAdvisory?: CostAdvisoryConfig | null;
|
|
117
118
|
readonly otelSpans?: Partial<OtelSpansConfig>;
|
|
118
119
|
readonly approvalGate?: ApprovalGateConfig | null;
|
|
119
120
|
/**
|