@stigmer/runner 3.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +212 -0
- package/dist/.build-fingerprint +1 -0
- package/dist/activities/call-agent-status.d.ts +37 -0
- package/dist/activities/call-agent-status.js +91 -0
- package/dist/activities/call-agent-status.js.map +1 -0
- package/dist/activities/call-agent.d.ts +25 -0
- package/dist/activities/call-agent.js +233 -0
- package/dist/activities/call-agent.js.map +1 -0
- package/dist/activities/call-eval.d.ts +50 -0
- package/dist/activities/call-eval.js +244 -0
- package/dist/activities/call-eval.js.map +1 -0
- package/dist/activities/call-function.d.ts +21 -0
- package/dist/activities/call-function.js +54 -0
- package/dist/activities/call-function.js.map +1 -0
- package/dist/activities/call-grpc.d.ts +22 -0
- package/dist/activities/call-grpc.js +101 -0
- package/dist/activities/call-grpc.js.map +1 -0
- package/dist/activities/call-http.d.ts +32 -0
- package/dist/activities/call-http.js +134 -0
- package/dist/activities/call-http.js.map +1 -0
- package/dist/activities/call-llm.d.ts +39 -0
- package/dist/activities/call-llm.js +260 -0
- package/dist/activities/call-llm.js.map +1 -0
- package/dist/activities/call-transform.d.ts +20 -0
- package/dist/activities/call-transform.js +33 -0
- package/dist/activities/call-transform.js.map +1 -0
- package/dist/activities/call-validate.d.ts +41 -0
- package/dist/activities/call-validate.js +163 -0
- package/dist/activities/call-validate.js.map +1 -0
- package/dist/activities/classify-tool-approvals.d.ts +47 -0
- package/dist/activities/classify-tool-approvals.js +207 -0
- package/dist/activities/classify-tool-approvals.js.map +1 -0
- package/dist/activities/discover-mcp-server.d.ts +65 -0
- package/dist/activities/discover-mcp-server.js +269 -0
- package/dist/activities/discover-mcp-server.js.map +1 -0
- package/dist/activities/emit-event.d.ts +46 -0
- package/dist/activities/emit-event.js +125 -0
- package/dist/activities/emit-event.js.map +1 -0
- package/dist/activities/ensure-thread.d.ts +24 -0
- package/dist/activities/ensure-thread.js +44 -0
- package/dist/activities/ensure-thread.js.map +1 -0
- package/dist/activities/evaluate-expressions.d.ts +21 -0
- package/dist/activities/evaluate-expressions.js +39 -0
- package/dist/activities/evaluate-expressions.js.map +1 -0
- package/dist/activities/execute-cursor/approval-policy.d.ts +104 -0
- package/dist/activities/execute-cursor/approval-policy.js +193 -0
- package/dist/activities/execute-cursor/approval-policy.js.map +1 -0
- package/dist/activities/execute-cursor/approval-state.d.ts +157 -0
- package/dist/activities/execute-cursor/approval-state.js +223 -0
- package/dist/activities/execute-cursor/approval-state.js.map +1 -0
- package/dist/activities/execute-cursor/attachment-resolver.d.ts +19 -0
- package/dist/activities/execute-cursor/attachment-resolver.js +52 -0
- package/dist/activities/execute-cursor/attachment-resolver.js.map +1 -0
- package/dist/activities/execute-cursor/blueprint-resolver.d.ts +66 -0
- package/dist/activities/execute-cursor/blueprint-resolver.js +169 -0
- package/dist/activities/execute-cursor/blueprint-resolver.js.map +1 -0
- package/dist/activities/execute-cursor/connect-backfill.d.ts +18 -0
- package/dist/activities/execute-cursor/connect-backfill.js +27 -0
- package/dist/activities/execute-cursor/connect-backfill.js.map +1 -0
- package/dist/activities/execute-cursor/cursor-event-recorder.d.ts +24 -0
- package/dist/activities/execute-cursor/cursor-event-recorder.js +66 -0
- package/dist/activities/execute-cursor/cursor-event-recorder.js.map +1 -0
- package/dist/activities/execute-cursor/cursor-mode.d.ts +32 -0
- package/dist/activities/execute-cursor/cursor-mode.js +36 -0
- package/dist/activities/execute-cursor/cursor-mode.js.map +1 -0
- package/dist/activities/execute-cursor/delta-enricher.d.ts +87 -0
- package/dist/activities/execute-cursor/delta-enricher.js +265 -0
- package/dist/activities/execute-cursor/delta-enricher.js.map +1 -0
- package/dist/activities/execute-cursor/env-resolver.d.ts +19 -0
- package/dist/activities/execute-cursor/env-resolver.js +47 -0
- package/dist/activities/execute-cursor/env-resolver.js.map +1 -0
- package/dist/activities/execute-cursor/error-classifier.d.ts +73 -0
- package/dist/activities/execute-cursor/error-classifier.js +185 -0
- package/dist/activities/execute-cursor/error-classifier.js.map +1 -0
- package/dist/activities/execute-cursor/fetch-interceptor.d.ts +59 -0
- package/dist/activities/execute-cursor/fetch-interceptor.js +317 -0
- package/dist/activities/execute-cursor/fetch-interceptor.js.map +1 -0
- package/dist/activities/execute-cursor/hitl-diagnostics.d.ts +32 -0
- package/dist/activities/execute-cursor/hitl-diagnostics.js +73 -0
- package/dist/activities/execute-cursor/hitl-diagnostics.js.map +1 -0
- package/dist/activities/execute-cursor/hook-script.d.ts +47 -0
- package/dist/activities/execute-cursor/hook-script.js +156 -0
- package/dist/activities/execute-cursor/hook-script.js.map +1 -0
- package/dist/activities/execute-cursor/http2-interceptor.d.ts +94 -0
- package/dist/activities/execute-cursor/http2-interceptor.js +209 -0
- package/dist/activities/execute-cursor/http2-interceptor.js.map +1 -0
- package/dist/activities/execute-cursor/index.d.ts +67 -0
- package/dist/activities/execute-cursor/index.js +1176 -0
- package/dist/activities/execute-cursor/index.js.map +1 -0
- package/dist/activities/execute-cursor/mcp-config.d.ts +30 -0
- package/dist/activities/execute-cursor/mcp-config.js +39 -0
- package/dist/activities/execute-cursor/mcp-config.js.map +1 -0
- package/dist/activities/execute-cursor/mcp-resolver.d.ts +91 -0
- package/dist/activities/execute-cursor/mcp-resolver.js +178 -0
- package/dist/activities/execute-cursor/mcp-resolver.js.map +1 -0
- package/dist/activities/execute-cursor/message-translator.d.ts +211 -0
- package/dist/activities/execute-cursor/message-translator.js +786 -0
- package/dist/activities/execute-cursor/message-translator.js.map +1 -0
- package/dist/activities/execute-cursor/model-pricing-data.d.ts +40 -0
- package/dist/activities/execute-cursor/model-pricing-data.js +114 -0
- package/dist/activities/execute-cursor/model-pricing-data.js.map +1 -0
- package/dist/activities/execute-cursor/model-pricing.d.ts +42 -0
- package/dist/activities/execute-cursor/model-pricing.js +141 -0
- package/dist/activities/execute-cursor/model-pricing.js.map +1 -0
- package/dist/activities/execute-cursor/placeholder-resolver.d.ts +34 -0
- package/dist/activities/execute-cursor/placeholder-resolver.js +82 -0
- package/dist/activities/execute-cursor/placeholder-resolver.js.map +1 -0
- package/dist/activities/execute-cursor/prompt-builder.d.ts +80 -0
- package/dist/activities/execute-cursor/prompt-builder.js +280 -0
- package/dist/activities/execute-cursor/prompt-builder.js.map +1 -0
- package/dist/activities/execute-cursor/rejection-capture.d.ts +30 -0
- package/dist/activities/execute-cursor/rejection-capture.js +80 -0
- package/dist/activities/execute-cursor/rejection-capture.js.map +1 -0
- package/dist/activities/execute-cursor/session-lifecycle.d.ts +189 -0
- package/dist/activities/execute-cursor/session-lifecycle.js +285 -0
- package/dist/activities/execute-cursor/session-lifecycle.js.map +1 -0
- package/dist/activities/execute-cursor/skill-resolver.d.ts +29 -0
- package/dist/activities/execute-cursor/skill-resolver.js +134 -0
- package/dist/activities/execute-cursor/skill-resolver.js.map +1 -0
- package/dist/activities/execute-cursor/subagent-config.d.ts +34 -0
- package/dist/activities/execute-cursor/subagent-config.js +55 -0
- package/dist/activities/execute-cursor/subagent-config.js.map +1 -0
- package/dist/activities/execute-cursor/todo-tracker.d.ts +35 -0
- package/dist/activities/execute-cursor/todo-tracker.js +108 -0
- package/dist/activities/execute-cursor/todo-tracker.js.map +1 -0
- package/dist/activities/execute-cursor/usage-accumulator.d.ts +55 -0
- package/dist/activities/execute-cursor/usage-accumulator.js +89 -0
- package/dist/activities/execute-cursor/usage-accumulator.js.map +1 -0
- package/dist/activities/execute-cursor/workspace-provision.d.ts +22 -0
- package/dist/activities/execute-cursor/workspace-provision.js +37 -0
- package/dist/activities/execute-cursor/workspace-provision.js.map +1 -0
- package/dist/activities/execute-cursor/workspace-setup.d.ts +27 -0
- package/dist/activities/execute-cursor/workspace-setup.js +61 -0
- package/dist/activities/execute-cursor/workspace-setup.js.map +1 -0
- package/dist/activities/execute-deep-agent/__test-utils__/v3-event-fixtures.d.ts +71 -0
- package/dist/activities/execute-deep-agent/__test-utils__/v3-event-fixtures.js +182 -0
- package/dist/activities/execute-deep-agent/__test-utils__/v3-event-fixtures.js.map +1 -0
- package/dist/activities/execute-deep-agent/attachment-injector.d.ts +67 -0
- package/dist/activities/execute-deep-agent/attachment-injector.js +306 -0
- package/dist/activities/execute-deep-agent/attachment-injector.js.map +1 -0
- package/dist/activities/execute-deep-agent/auto-publish.d.ts +17 -0
- package/dist/activities/execute-deep-agent/auto-publish.js +71 -0
- package/dist/activities/execute-deep-agent/auto-publish.js.map +1 -0
- package/dist/activities/execute-deep-agent/environment.d.ts +24 -0
- package/dist/activities/execute-deep-agent/environment.js +50 -0
- package/dist/activities/execute-deep-agent/environment.js.map +1 -0
- package/dist/activities/execute-deep-agent/event-recorder.d.ts +21 -0
- package/dist/activities/execute-deep-agent/event-recorder.js +67 -0
- package/dist/activities/execute-deep-agent/event-recorder.js.map +1 -0
- package/dist/activities/execute-deep-agent/execution-state.d.ts +61 -0
- package/dist/activities/execute-deep-agent/execution-state.js +76 -0
- package/dist/activities/execute-deep-agent/execution-state.js.map +1 -0
- package/dist/activities/execute-deep-agent/execution-status-writer.d.ts +17 -0
- package/dist/activities/execute-deep-agent/execution-status-writer.js +9 -0
- package/dist/activities/execute-deep-agent/execution-status-writer.js.map +1 -0
- package/dist/activities/execute-deep-agent/hitl.d.ts +58 -0
- package/dist/activities/execute-deep-agent/hitl.js +155 -0
- package/dist/activities/execute-deep-agent/hitl.js.map +1 -0
- package/dist/activities/execute-deep-agent/index.d.ts +14 -0
- package/dist/activities/execute-deep-agent/index.js +286 -0
- package/dist/activities/execute-deep-agent/index.js.map +1 -0
- package/dist/activities/execute-deep-agent/inline-publisher.d.ts +36 -0
- package/dist/activities/execute-deep-agent/inline-publisher.js +105 -0
- package/dist/activities/execute-deep-agent/inline-publisher.js.map +1 -0
- package/dist/activities/execute-deep-agent/post-stream.d.ts +23 -0
- package/dist/activities/execute-deep-agent/post-stream.js +71 -0
- package/dist/activities/execute-deep-agent/post-stream.js.map +1 -0
- package/dist/activities/execute-deep-agent/prompt-builder.d.ts +27 -0
- package/dist/activities/execute-deep-agent/prompt-builder.js +200 -0
- package/dist/activities/execute-deep-agent/prompt-builder.js.map +1 -0
- package/dist/activities/execute-deep-agent/setup.d.ts +55 -0
- package/dist/activities/execute-deep-agent/setup.js +411 -0
- package/dist/activities/execute-deep-agent/setup.js.map +1 -0
- package/dist/activities/execute-deep-agent/status-builder-shared.d.ts +39 -0
- package/dist/activities/execute-deep-agent/status-builder-shared.js +120 -0
- package/dist/activities/execute-deep-agent/status-builder-shared.js.map +1 -0
- package/dist/activities/execute-deep-agent/status-builder.d.ts +81 -0
- package/dist/activities/execute-deep-agent/status-builder.js +312 -0
- package/dist/activities/execute-deep-agent/status-builder.js.map +1 -0
- package/dist/activities/execute-deep-agent/streaming-scheduler.d.ts +60 -0
- package/dist/activities/execute-deep-agent/streaming-scheduler.js +114 -0
- package/dist/activities/execute-deep-agent/streaming-scheduler.js.map +1 -0
- package/dist/activities/execute-deep-agent/streaming-side-effects.d.ts +22 -0
- package/dist/activities/execute-deep-agent/streaming-side-effects.js +83 -0
- package/dist/activities/execute-deep-agent/streaming-side-effects.js.map +1 -0
- package/dist/activities/execute-deep-agent/streaming-terminal.d.ts +12 -0
- package/dist/activities/execute-deep-agent/streaming-terminal.js +71 -0
- package/dist/activities/execute-deep-agent/streaming-terminal.js.map +1 -0
- package/dist/activities/execute-deep-agent/streaming-v3.d.ts +13 -0
- package/dist/activities/execute-deep-agent/streaming-v3.js +170 -0
- package/dist/activities/execute-deep-agent/streaming-v3.js.map +1 -0
- package/dist/activities/execute-deep-agent/streaming.d.ts +66 -0
- package/dist/activities/execute-deep-agent/streaming.js +169 -0
- package/dist/activities/execute-deep-agent/streaming.js.map +1 -0
- package/dist/activities/execute-deep-agent/subagent-tracker.d.ts +90 -0
- package/dist/activities/execute-deep-agent/subagent-tracker.js +364 -0
- package/dist/activities/execute-deep-agent/subagent-tracker.js.map +1 -0
- package/dist/activities/execute-deep-agent/subagent-transformer.d.ts +150 -0
- package/dist/activities/execute-deep-agent/subagent-transformer.js +450 -0
- package/dist/activities/execute-deep-agent/subagent-transformer.js.map +1 -0
- package/dist/activities/execute-deep-agent/subagent-wiring.d.ts +28 -0
- package/dist/activities/execute-deep-agent/subagent-wiring.js +40 -0
- package/dist/activities/execute-deep-agent/subagent-wiring.js.map +1 -0
- package/dist/activities/execute-deep-agent/v3-event-recorder.d.ts +31 -0
- package/dist/activities/execute-deep-agent/v3-event-recorder.js +71 -0
- package/dist/activities/execute-deep-agent/v3-event-recorder.js.map +1 -0
- package/dist/activities/execute-deep-agent/v3-events.d.ts +102 -0
- package/dist/activities/execute-deep-agent/v3-events.js +35 -0
- package/dist/activities/execute-deep-agent/v3-events.js.map +1 -0
- package/dist/activities/execute-deep-agent/v3-protocol-normalizer.d.ts +15 -0
- package/dist/activities/execute-deep-agent/v3-protocol-normalizer.js +235 -0
- package/dist/activities/execute-deep-agent/v3-protocol-normalizer.js.map +1 -0
- package/dist/activities/execute-deep-agent/v3-status-builder.d.ts +68 -0
- package/dist/activities/execute-deep-agent/v3-status-builder.js +394 -0
- package/dist/activities/execute-deep-agent/v3-status-builder.js.map +1 -0
- package/dist/activities/execute-deep-agent/writeback-coordinator.d.ts +71 -0
- package/dist/activities/execute-deep-agent/writeback-coordinator.js +295 -0
- package/dist/activities/execute-deep-agent/writeback-coordinator.js.map +1 -0
- package/dist/activities/hydrate-workflow-execution.d.ts +32 -0
- package/dist/activities/hydrate-workflow-execution.js +212 -0
- package/dist/activities/hydrate-workflow-execution.js.map +1 -0
- package/dist/activities/notification.d.ts +19 -0
- package/dist/activities/notification.js +47 -0
- package/dist/activities/notification.js.map +1 -0
- package/dist/activities/promote-task-output.d.ts +38 -0
- package/dist/activities/promote-task-output.js +90 -0
- package/dist/activities/promote-task-output.js.map +1 -0
- package/dist/activities/run-command.d.ts +15 -0
- package/dist/activities/run-command.js +123 -0
- package/dist/activities/run-command.js.map +1 -0
- package/dist/activities/workflow-event-activities.d.ts +48 -0
- package/dist/activities/workflow-event-activities.js +415 -0
- package/dist/activities/workflow-event-activities.js.map +1 -0
- package/dist/bootstrap.d.ts +80 -0
- package/dist/bootstrap.js +114 -0
- package/dist/bootstrap.js.map +1 -0
- package/dist/budget/index.d.ts +1 -0
- package/dist/budget/index.js +2 -0
- package/dist/budget/index.js.map +1 -0
- package/dist/budget/tracker.d.ts +52 -0
- package/dist/budget/tracker.js +123 -0
- package/dist/budget/tracker.js.map +1 -0
- package/dist/claimcheck/compressor.d.ts +2 -0
- package/dist/claimcheck/compressor.js +8 -0
- package/dist/claimcheck/compressor.js.map +1 -0
- package/dist/claimcheck/config.d.ts +7 -0
- package/dist/claimcheck/config.js +10 -0
- package/dist/claimcheck/config.js.map +1 -0
- package/dist/claimcheck/index.d.ts +3 -0
- package/dist/claimcheck/index.js +4 -0
- package/dist/claimcheck/index.js.map +1 -0
- package/dist/claimcheck/payload-codec.d.ts +23 -0
- package/dist/claimcheck/payload-codec.js +81 -0
- package/dist/claimcheck/payload-codec.js.map +1 -0
- package/dist/client/server-contracts.d.ts +52 -0
- package/dist/client/server-contracts.js +72 -0
- package/dist/client/server-contracts.js.map +1 -0
- package/dist/client/stigmer-client.d.ts +131 -0
- package/dist/client/stigmer-client.js +239 -0
- package/dist/client/stigmer-client.js.map +1 -0
- package/dist/config.d.ts +64 -0
- package/dist/config.js +123 -0
- package/dist/config.js.map +1 -0
- package/dist/idle-watchdog.d.ts +11 -0
- package/dist/idle-watchdog.js +24 -0
- package/dist/idle-watchdog.js.map +1 -0
- package/dist/index.d.ts +43 -0
- package/dist/index.js +42 -0
- package/dist/index.js.map +1 -0
- package/dist/interceptors/workflow-metrics-sink.d.ts +11 -0
- package/dist/interceptors/workflow-metrics-sink.js +51 -0
- package/dist/interceptors/workflow-metrics-sink.js.map +1 -0
- package/dist/ipc-protocol-fixtures.d.ts +32 -0
- package/dist/ipc-protocol-fixtures.js +69 -0
- package/dist/ipc-protocol-fixtures.js.map +1 -0
- package/dist/ipc-protocol.d.ts +60 -0
- package/dist/ipc-protocol.js +19 -0
- package/dist/ipc-protocol.js.map +1 -0
- package/dist/main.d.ts +19 -0
- package/dist/main.js +292 -0
- package/dist/main.js.map +1 -0
- package/dist/middleware/approval-gate.d.ts +30 -0
- package/dist/middleware/approval-gate.js +125 -0
- package/dist/middleware/approval-gate.js.map +1 -0
- package/dist/middleware/cost-cap.d.ts +22 -0
- package/dist/middleware/cost-cap.js +159 -0
- package/dist/middleware/cost-cap.js.map +1 -0
- package/dist/middleware/error-hints.d.ts +27 -0
- package/dist/middleware/error-hints.js +116 -0
- package/dist/middleware/error-hints.js.map +1 -0
- package/dist/middleware/execution-budget.d.ts +20 -0
- package/dist/middleware/execution-budget.js +151 -0
- package/dist/middleware/execution-budget.js.map +1 -0
- package/dist/middleware/graceful-stop.d.ts +17 -0
- package/dist/middleware/graceful-stop.js +63 -0
- package/dist/middleware/graceful-stop.js.map +1 -0
- package/dist/middleware/index.d.ts +27 -0
- package/dist/middleware/index.js +45 -0
- package/dist/middleware/index.js.map +1 -0
- package/dist/middleware/loop-detection.d.ts +14 -0
- package/dist/middleware/loop-detection.js +156 -0
- package/dist/middleware/loop-detection.js.map +1 -0
- package/dist/middleware/otel-spans.d.ts +11 -0
- package/dist/middleware/otel-spans.js +177 -0
- package/dist/middleware/otel-spans.js.map +1 -0
- package/dist/middleware/think-tool.d.ts +23 -0
- package/dist/middleware/think-tool.js +33 -0
- package/dist/middleware/think-tool.js.map +1 -0
- package/dist/middleware/tool-truncation.d.ts +16 -0
- package/dist/middleware/tool-truncation.js +67 -0
- package/dist/middleware/tool-truncation.js.map +1 -0
- package/dist/middleware/types.d.ts +100 -0
- package/dist/middleware/types.js +9 -0
- package/dist/middleware/types.js.map +1 -0
- package/dist/notification/index.d.ts +2 -0
- package/dist/notification/index.js +6 -0
- package/dist/notification/index.js.map +1 -0
- package/dist/notification/provider.d.ts +29 -0
- package/dist/notification/provider.js +25 -0
- package/dist/notification/provider.js.map +1 -0
- package/dist/notification/webhook.d.ts +13 -0
- package/dist/notification/webhook.js +55 -0
- package/dist/notification/webhook.js.map +1 -0
- package/dist/otel-metrics.d.ts +21 -0
- package/dist/otel-metrics.js +54 -0
- package/dist/otel-metrics.js.map +1 -0
- package/dist/otel.d.ts +57 -0
- package/dist/otel.js +164 -0
- package/dist/otel.js.map +1 -0
- package/dist/runner-manager.d.ts +113 -0
- package/dist/runner-manager.js +412 -0
- package/dist/runner-manager.js.map +1 -0
- package/dist/runner-token-coordinator.d.ts +56 -0
- package/dist/runner-token-coordinator.js +84 -0
- package/dist/runner-token-coordinator.js.map +1 -0
- package/dist/runner.d.ts +104 -0
- package/dist/runner.js +234 -0
- package/dist/runner.js.map +1 -0
- package/dist/shared/approval-policy.d.ts +45 -0
- package/dist/shared/approval-policy.js +122 -0
- package/dist/shared/approval-policy.js.map +1 -0
- package/dist/shared/artifact-storage.d.ts +44 -0
- package/dist/shared/artifact-storage.js +162 -0
- package/dist/shared/artifact-storage.js.map +1 -0
- package/dist/shared/checkpointer/factory.d.ts +28 -0
- package/dist/shared/checkpointer/factory.js +55 -0
- package/dist/shared/checkpointer/factory.js.map +1 -0
- package/dist/shared/checkpointer/http-saver.d.ts +34 -0
- package/dist/shared/checkpointer/http-saver.js +274 -0
- package/dist/shared/checkpointer/http-saver.js.map +1 -0
- package/dist/shared/checkpointer/types.d.ts +12 -0
- package/dist/shared/checkpointer/types.js +2 -0
- package/dist/shared/checkpointer/types.js.map +1 -0
- package/dist/shared/connect-backfill.d.ts +58 -0
- package/dist/shared/connect-backfill.js +119 -0
- package/dist/shared/connect-backfill.js.map +1 -0
- package/dist/shared/extract-json.d.ts +26 -0
- package/dist/shared/extract-json.js +140 -0
- package/dist/shared/extract-json.js.map +1 -0
- package/dist/shared/grpc-retry.d.ts +35 -0
- package/dist/shared/grpc-retry.js +78 -0
- package/dist/shared/grpc-retry.js.map +1 -0
- package/dist/shared/heartbeat.d.ts +22 -0
- package/dist/shared/heartbeat.js +55 -0
- package/dist/shared/heartbeat.js.map +1 -0
- package/dist/shared/json-schema-to-zod.d.ts +13 -0
- package/dist/shared/json-schema-to-zod.js +49 -0
- package/dist/shared/json-schema-to-zod.js.map +1 -0
- package/dist/shared/llm-proxy.d.ts +57 -0
- package/dist/shared/llm-proxy.js +116 -0
- package/dist/shared/llm-proxy.js.map +1 -0
- package/dist/shared/mcp-manager.d.ts +47 -0
- package/dist/shared/mcp-manager.js +118 -0
- package/dist/shared/mcp-manager.js.map +1 -0
- package/dist/shared/mcp-resolver.d.ts +41 -0
- package/dist/shared/mcp-resolver.js +96 -0
- package/dist/shared/mcp-resolver.js.map +1 -0
- package/dist/shared/model-pricing-data.d.ts +18 -0
- package/dist/shared/model-pricing-data.js +78 -0
- package/dist/shared/model-pricing-data.js.map +1 -0
- package/dist/shared/model-pricing.d.ts +24 -0
- package/dist/shared/model-pricing.js +58 -0
- package/dist/shared/model-pricing.js.map +1 -0
- package/dist/shared/model-registry.d.ts +55 -0
- package/dist/shared/model-registry.js +178 -0
- package/dist/shared/model-registry.js.map +1 -0
- package/dist/shared/placeholder-resolver.d.ts +27 -0
- package/dist/shared/placeholder-resolver.js +75 -0
- package/dist/shared/placeholder-resolver.js.map +1 -0
- package/dist/shared/plan-artifact.d.ts +56 -0
- package/dist/shared/plan-artifact.js +98 -0
- package/dist/shared/plan-artifact.js.map +1 -0
- package/dist/shared/skill-relevance.d.ts +65 -0
- package/dist/shared/skill-relevance.js +175 -0
- package/dist/shared/skill-relevance.js.map +1 -0
- package/dist/shared/skill-writer.d.ts +73 -0
- package/dist/shared/skill-writer.js +230 -0
- package/dist/shared/skill-writer.js.map +1 -0
- package/dist/shared/status.d.ts +37 -0
- package/dist/shared/status.js +73 -0
- package/dist/shared/status.js.map +1 -0
- package/dist/shared/subagent-gate.d.ts +41 -0
- package/dist/shared/subagent-gate.js +93 -0
- package/dist/shared/subagent-gate.js.map +1 -0
- package/dist/shared/tool-kind.d.ts +22 -0
- package/dist/shared/tool-kind.js +79 -0
- package/dist/shared/tool-kind.js.map +1 -0
- package/dist/shared/workspace/file-tree.d.ts +13 -0
- package/dist/shared/workspace/file-tree.js +101 -0
- package/dist/shared/workspace/file-tree.js.map +1 -0
- package/dist/shared/workspace/local-backend.d.ts +41 -0
- package/dist/shared/workspace/local-backend.js +113 -0
- package/dist/shared/workspace/local-backend.js.map +1 -0
- package/dist/shared/workspace/platform-dir.d.ts +25 -0
- package/dist/shared/workspace/platform-dir.js +36 -0
- package/dist/shared/workspace/platform-dir.js.map +1 -0
- package/dist/shared/workspace/platform-mount.d.ts +95 -0
- package/dist/shared/workspace/platform-mount.js +157 -0
- package/dist/shared/workspace/platform-mount.js.map +1 -0
- package/dist/shared/workspace/provisioner.d.ts +47 -0
- package/dist/shared/workspace/provisioner.js +84 -0
- package/dist/shared/workspace/provisioner.js.map +1 -0
- package/dist/shared/workspace/sources/empty.d.ts +8 -0
- package/dist/shared/workspace/sources/empty.js +18 -0
- package/dist/shared/workspace/sources/empty.js.map +1 -0
- package/dist/shared/workspace/sources/git.d.ts +22 -0
- package/dist/shared/workspace/sources/git.js +207 -0
- package/dist/shared/workspace/sources/git.js.map +1 -0
- package/dist/shared/workspace/sources/local-path.d.ts +17 -0
- package/dist/shared/workspace/sources/local-path.js +57 -0
- package/dist/shared/workspace/sources/local-path.js.map +1 -0
- package/dist/shared/workspace/types.d.ts +58 -0
- package/dist/shared/workspace/types.js +25 -0
- package/dist/shared/workspace/types.js.map +1 -0
- package/dist/shared/zip-extract.d.ts +30 -0
- package/dist/shared/zip-extract.js +150 -0
- package/dist/shared/zip-extract.js.map +1 -0
- package/dist/worker.d.ts +27 -0
- package/dist/worker.js +65 -0
- package/dist/worker.js.map +1 -0
- package/dist/workflow-engine/clone.d.ts +11 -0
- package/dist/workflow-engine/clone.js +21 -0
- package/dist/workflow-engine/clone.js.map +1 -0
- package/dist/workflow-engine/do-executor.d.ts +27 -0
- package/dist/workflow-engine/do-executor.js +418 -0
- package/dist/workflow-engine/do-executor.js.map +1 -0
- package/dist/workflow-engine/duration.d.ts +12 -0
- package/dist/workflow-engine/duration.js +25 -0
- package/dist/workflow-engine/duration.js.map +1 -0
- package/dist/workflow-engine/error-utils.d.ts +42 -0
- package/dist/workflow-engine/error-utils.js +77 -0
- package/dist/workflow-engine/error-utils.js.map +1 -0
- package/dist/workflow-engine/errors.d.ts +46 -0
- package/dist/workflow-engine/errors.js +105 -0
- package/dist/workflow-engine/errors.js.map +1 -0
- package/dist/workflow-engine/expression-utils.d.ts +60 -0
- package/dist/workflow-engine/expression-utils.js +108 -0
- package/dist/workflow-engine/expression-utils.js.map +1 -0
- package/dist/workflow-engine/expression.d.ts +132 -0
- package/dist/workflow-engine/expression.js +366 -0
- package/dist/workflow-engine/expression.js.map +1 -0
- package/dist/workflow-engine/loader.d.ts +23 -0
- package/dist/workflow-engine/loader.js +429 -0
- package/dist/workflow-engine/loader.js.map +1 -0
- package/dist/workflow-engine/recovery.d.ts +53 -0
- package/dist/workflow-engine/recovery.js +46 -0
- package/dist/workflow-engine/recovery.js.map +1 -0
- package/dist/workflow-engine/resolve.d.ts +83 -0
- package/dist/workflow-engine/resolve.js +257 -0
- package/dist/workflow-engine/resolve.js.map +1 -0
- package/dist/workflow-engine/retry.d.ts +30 -0
- package/dist/workflow-engine/retry.js +97 -0
- package/dist/workflow-engine/retry.js.map +1 -0
- package/dist/workflow-engine/state.d.ts +26 -0
- package/dist/workflow-engine/state.js +49 -0
- package/dist/workflow-engine/state.js.map +1 -0
- package/dist/workflow-engine/task-factory.d.ts +20 -0
- package/dist/workflow-engine/task-factory.js +133 -0
- package/dist/workflow-engine/task-factory.js.map +1 -0
- package/dist/workflow-engine/task-status-accumulator.d.ts +59 -0
- package/dist/workflow-engine/task-status-accumulator.js +164 -0
- package/dist/workflow-engine/task-status-accumulator.js.map +1 -0
- package/dist/workflow-engine/tasks/call-agent-output.d.ts +26 -0
- package/dist/workflow-engine/tasks/call-agent-output.js +109 -0
- package/dist/workflow-engine/tasks/call-agent-output.js.map +1 -0
- package/dist/workflow-engine/tasks/call-agent.d.ts +31 -0
- package/dist/workflow-engine/tasks/call-agent.js +161 -0
- package/dist/workflow-engine/tasks/call-agent.js.map +1 -0
- package/dist/workflow-engine/tasks/call-function.d.ts +19 -0
- package/dist/workflow-engine/tasks/call-function.js +64 -0
- package/dist/workflow-engine/tasks/call-function.js.map +1 -0
- package/dist/workflow-engine/tasks/call-grpc.d.ts +15 -0
- package/dist/workflow-engine/tasks/call-grpc.js +27 -0
- package/dist/workflow-engine/tasks/call-grpc.js.map +1 -0
- package/dist/workflow-engine/tasks/call-http.d.ts +19 -0
- package/dist/workflow-engine/tasks/call-http.js +31 -0
- package/dist/workflow-engine/tasks/call-http.js.map +1 -0
- package/dist/workflow-engine/tasks/for.d.ts +39 -0
- package/dist/workflow-engine/tasks/for.js +154 -0
- package/dist/workflow-engine/tasks/for.js.map +1 -0
- package/dist/workflow-engine/tasks/fork.d.ts +42 -0
- package/dist/workflow-engine/tasks/fork.js +142 -0
- package/dist/workflow-engine/tasks/fork.js.map +1 -0
- package/dist/workflow-engine/tasks/human-input.d.ts +33 -0
- package/dist/workflow-engine/tasks/human-input.js +109 -0
- package/dist/workflow-engine/tasks/human-input.js.map +1 -0
- package/dist/workflow-engine/tasks/listen.d.ts +34 -0
- package/dist/workflow-engine/tasks/listen.js +119 -0
- package/dist/workflow-engine/tasks/listen.js.map +1 -0
- package/dist/workflow-engine/tasks/raise.d.ts +18 -0
- package/dist/workflow-engine/tasks/raise.js +60 -0
- package/dist/workflow-engine/tasks/raise.js.map +1 -0
- package/dist/workflow-engine/tasks/run.d.ts +39 -0
- package/dist/workflow-engine/tasks/run.js +114 -0
- package/dist/workflow-engine/tasks/run.js.map +1 -0
- package/dist/workflow-engine/tasks/set.d.ts +15 -0
- package/dist/workflow-engine/tasks/set.js +31 -0
- package/dist/workflow-engine/tasks/set.js.map +1 -0
- package/dist/workflow-engine/tasks/switch.d.ts +25 -0
- package/dist/workflow-engine/tasks/switch.js +76 -0
- package/dist/workflow-engine/tasks/switch.js.map +1 -0
- package/dist/workflow-engine/tasks/try.d.ts +49 -0
- package/dist/workflow-engine/tasks/try.js +189 -0
- package/dist/workflow-engine/tasks/try.js.map +1 -0
- package/dist/workflow-engine/tasks/wait.d.ts +24 -0
- package/dist/workflow-engine/tasks/wait.js +39 -0
- package/dist/workflow-engine/tasks/wait.js.map +1 -0
- package/dist/workflow-engine/types.d.ts +682 -0
- package/dist/workflow-engine/types.js +47 -0
- package/dist/workflow-engine/types.js.map +1 -0
- package/dist/workflows/call-agent-orchestrator.d.ts +31 -0
- package/dist/workflows/call-agent-orchestrator.js +214 -0
- package/dist/workflows/call-agent-orchestrator.js.map +1 -0
- package/dist/workflows/connect-mcp-server.d.ts +20 -0
- package/dist/workflows/connect-mcp-server.js +113 -0
- package/dist/workflows/connect-mcp-server.js.map +1 -0
- package/dist/workflows/engine-core.d.ts +36 -0
- package/dist/workflows/engine-core.js +272 -0
- package/dist/workflows/engine-core.js.map +1 -0
- package/dist/workflows/execute-from-execution.d.ts +32 -0
- package/dist/workflows/execute-from-execution.js +71 -0
- package/dist/workflows/execute-from-execution.js.map +1 -0
- package/dist/workflows/execute-serverless-workflow.d.ts +32 -0
- package/dist/workflows/execute-serverless-workflow.js +36 -0
- package/dist/workflows/execute-serverless-workflow.js.map +1 -0
- package/dist/workflows/human-input-orchestrator.d.ts +19 -0
- package/dist/workflows/human-input-orchestrator.js +59 -0
- package/dist/workflows/human-input-orchestrator.js.map +1 -0
- package/dist/workflows/index.d.ts +22 -0
- package/dist/workflows/index.js +23 -0
- package/dist/workflows/index.js.map +1 -0
- package/dist/workflows/listen-orchestrator.d.ts +29 -0
- package/dist/workflows/listen-orchestrator.js +143 -0
- package/dist/workflows/listen-orchestrator.js.map +1 -0
- package/dist/workflows/metrics-sink.d.ts +33 -0
- package/dist/workflows/metrics-sink.js +21 -0
- package/dist/workflows/metrics-sink.js.map +1 -0
- package/dist/workflows/run-orchestrator.d.ts +15 -0
- package/dist/workflows/run-orchestrator.js +27 -0
- package/dist/workflows/run-orchestrator.js.map +1 -0
- package/dist/workflows/types.d.ts +46 -0
- package/dist/workflows/types.js +15 -0
- package/dist/workflows/types.js.map +1 -0
- package/dist/workflows/workflow-signals.d.ts +29 -0
- package/dist/workflows/workflow-signals.js +46 -0
- package/dist/workflows/workflow-signals.js.map +1 -0
- package/package.json +108 -0
- package/src/__test-utils__/__tests__/replay-fetch.test.ts +155 -0
- package/src/__test-utils__/mock-client.ts +44 -0
- package/src/__test-utils__/mock-workspace.ts +28 -0
- package/src/__test-utils__/proto-helpers.ts +41 -0
- package/src/__test-utils__/replay-fetch.ts +523 -0
- package/src/__tests__/bootstrap.test.ts +221 -0
- package/src/__tests__/claimcheck-codec.test.ts +257 -0
- package/src/__tests__/config.test.ts +150 -0
- package/src/__tests__/deterministic-eval-llm.test.ts +269 -0
- package/src/__tests__/deterministic-mcp-hitl.test.ts +405 -0
- package/src/__tests__/golden-e2e.test.ts +250 -0
- package/src/__tests__/ipc-protocol-fixtures.test.ts +66 -0
- package/src/__tests__/ipc-protocol.test.ts +32 -0
- package/src/__tests__/otel-metrics.test.ts +40 -0
- package/src/__tests__/runner-manager.test.ts +55 -0
- package/src/__tests__/runner-token-coordinator.test.ts +166 -0
- package/src/__tests__/runner.test.ts +182 -0
- package/src/__tests__/worker.test.ts +18 -0
- package/src/activities/__tests__/call-agent-contracts.test.ts +483 -0
- package/src/activities/__tests__/call-agent.test.ts +263 -0
- package/src/activities/__tests__/call-function.test.ts +47 -0
- package/src/activities/__tests__/call-grpc.test.ts +39 -0
- package/src/activities/__tests__/call-http.test.ts +288 -0
- package/src/activities/__tests__/call-llm.test.ts +301 -0
- package/src/activities/__tests__/classify-tool-approvals.test.ts +430 -0
- package/src/activities/__tests__/discover-mcp-server.test.ts +641 -0
- package/src/activities/__tests__/ensure-thread.test.ts +96 -0
- package/src/activities/__tests__/error-classifier.test.ts +372 -0
- package/src/activities/__tests__/evaluate-expressions.test.ts +114 -0
- package/src/activities/__tests__/hydrate-workflow-execution.test.ts +321 -0
- package/src/activities/__tests__/notification.test.ts +151 -0
- package/src/activities/__tests__/workflow-event-activities.test.ts +664 -0
- package/src/activities/call-agent-status.ts +130 -0
- package/src/activities/call-agent.ts +302 -0
- package/src/activities/call-eval.ts +333 -0
- package/src/activities/call-function.ts +73 -0
- package/src/activities/call-grpc.ts +140 -0
- package/src/activities/call-http.ts +185 -0
- package/src/activities/call-llm.ts +379 -0
- package/src/activities/call-transform.ts +54 -0
- package/src/activities/call-validate.ts +223 -0
- package/src/activities/classify-tool-approvals.ts +319 -0
- package/src/activities/discover-mcp-server.ts +411 -0
- package/src/activities/emit-event.ts +195 -0
- package/src/activities/ensure-thread.ts +45 -0
- package/src/activities/evaluate-expressions.ts +47 -0
- package/src/activities/execute-cursor/__tests__/approval-gate.test.ts +188 -0
- package/src/activities/execute-cursor/__tests__/build-prompt.test.ts +111 -0
- package/src/activities/execute-cursor/__tests__/cursor-baseurl-routing.test.ts +86 -0
- package/src/activities/execute-cursor/__tests__/cursor-fetch-interceptor-bypass.test.ts +64 -0
- package/src/activities/execute-cursor/__tests__/cursor-mode.test.ts +95 -0
- package/src/activities/execute-cursor/__tests__/cursor-sdk-auth-smoke.test.ts +90 -0
- package/src/activities/execute-cursor/__tests__/delta-enricher.test.ts +242 -0
- package/src/activities/execute-cursor/__tests__/error-classifier-introspection.test.ts +156 -0
- package/src/activities/execute-cursor/__tests__/fetch-interceptor.test.ts +211 -0
- package/src/activities/execute-cursor/__tests__/hitl-ledger.test.ts +298 -0
- package/src/activities/execute-cursor/__tests__/http2-interceptor.test.ts +360 -0
- package/src/activities/execute-cursor/__tests__/message-translator.test.ts +657 -0
- package/src/activities/execute-cursor/__tests__/model-pricing.test.ts +92 -0
- package/src/activities/execute-cursor/__tests__/prompt-builder-delegation.test.ts +101 -0
- package/src/activities/execute-cursor/__tests__/runner-error-regressions.test.ts +144 -0
- package/src/activities/execute-cursor/__tests__/session-lifecycle.test.ts +65 -0
- package/src/activities/execute-cursor/__tests__/skill-resolver.test.ts +265 -0
- package/src/activities/execute-cursor/__tests__/subagent-config.test.ts +107 -0
- package/src/activities/execute-cursor/__tests__/todo-tracker.test.ts +498 -0
- package/src/activities/execute-cursor/__tests__/workspace-provision.test.ts +283 -0
- package/src/activities/execute-cursor/approval-policy.ts +224 -0
- package/src/activities/execute-cursor/approval-state.ts +311 -0
- package/src/activities/execute-cursor/attachment-resolver.ts +78 -0
- package/src/activities/execute-cursor/blueprint-resolver.ts +234 -0
- package/src/activities/execute-cursor/connect-backfill.ts +49 -0
- package/src/activities/execute-cursor/cursor-event-recorder.ts +83 -0
- package/src/activities/execute-cursor/cursor-mode.ts +42 -0
- package/src/activities/execute-cursor/delta-enricher.ts +307 -0
- package/src/activities/execute-cursor/env-resolver.ts +64 -0
- package/src/activities/execute-cursor/error-classifier.ts +247 -0
- package/src/activities/execute-cursor/fetch-interceptor.ts +382 -0
- package/src/activities/execute-cursor/hitl-diagnostics.ts +82 -0
- package/src/activities/execute-cursor/hook-script.ts +159 -0
- package/src/activities/execute-cursor/http2-interceptor.ts +253 -0
- package/src/activities/execute-cursor/index.ts +1439 -0
- package/src/activities/execute-cursor/mcp-config.ts +66 -0
- package/src/activities/execute-cursor/mcp-resolver.ts +271 -0
- package/src/activities/execute-cursor/message-translator.ts +896 -0
- package/src/activities/execute-cursor/model-pricing-data.ts +167 -0
- package/src/activities/execute-cursor/model-pricing.ts +167 -0
- package/src/activities/execute-cursor/placeholder-resolver.ts +109 -0
- package/src/activities/execute-cursor/prompt-builder.ts +349 -0
- package/src/activities/execute-cursor/rejection-capture.ts +100 -0
- package/src/activities/execute-cursor/session-lifecycle.ts +429 -0
- package/src/activities/execute-cursor/skill-resolver.ts +176 -0
- package/src/activities/execute-cursor/subagent-config.ts +62 -0
- package/src/activities/execute-cursor/todo-tracker.ts +133 -0
- package/src/activities/execute-cursor/usage-accumulator.ts +126 -0
- package/src/activities/execute-cursor/workspace-provision.ts +55 -0
- package/src/activities/execute-cursor/workspace-setup.ts +75 -0
- package/src/activities/execute-deep-agent/__test-utils__/v3-event-fixtures.ts +281 -0
- package/src/activities/execute-deep-agent/__tests__/attachment-injector.test.ts +720 -0
- package/src/activities/execute-deep-agent/__tests__/auto-publish.test.ts +146 -0
- package/src/activities/execute-deep-agent/__tests__/environment.test.ts +103 -0
- package/src/activities/execute-deep-agent/__tests__/event-recorder.test.ts +150 -0
- package/src/activities/execute-deep-agent/__tests__/execution-state-extended.test.ts +150 -0
- package/src/activities/execute-deep-agent/__tests__/execution-state.test.ts +157 -0
- package/src/activities/execute-deep-agent/__tests__/hitl-integration.test.ts +223 -0
- package/src/activities/execute-deep-agent/__tests__/hitl.test.ts +244 -0
- package/src/activities/execute-deep-agent/__tests__/index.test.ts +91 -0
- package/src/activities/execute-deep-agent/__tests__/inline-publisher.test.ts +240 -0
- package/src/activities/execute-deep-agent/__tests__/post-stream.test.ts +112 -0
- package/src/activities/execute-deep-agent/__tests__/prompt-builder.test.ts +208 -0
- package/src/activities/execute-deep-agent/__tests__/status-builder.test.ts +1771 -0
- package/src/activities/execute-deep-agent/__tests__/streaming-scheduler.test.ts +199 -0
- package/src/activities/execute-deep-agent/__tests__/streaming-v3.test.ts +527 -0
- package/src/activities/execute-deep-agent/__tests__/streaming.test.ts +508 -0
- package/src/activities/execute-deep-agent/__tests__/subagent-tracker.test.ts +474 -0
- package/src/activities/execute-deep-agent/__tests__/subagent-transformer.test.ts +734 -0
- package/src/activities/execute-deep-agent/__tests__/subagent-wiring.test.ts +71 -0
- package/src/activities/execute-deep-agent/__tests__/summarization-verification.test.ts +323 -0
- package/src/activities/execute-deep-agent/__tests__/v3-event-recorder.test.ts +186 -0
- package/src/activities/execute-deep-agent/__tests__/v3-protocol-normalizer.test.ts +324 -0
- package/src/activities/execute-deep-agent/__tests__/v3-status-builder.test.ts +504 -0
- package/src/activities/execute-deep-agent/__tests__/writeback-coordinator.test.ts +399 -0
- package/src/activities/execute-deep-agent/attachment-injector.ts +470 -0
- package/src/activities/execute-deep-agent/auto-publish.ts +80 -0
- package/src/activities/execute-deep-agent/environment.ts +67 -0
- package/src/activities/execute-deep-agent/event-recorder.ts +95 -0
- package/src/activities/execute-deep-agent/execution-state.ts +87 -0
- package/src/activities/execute-deep-agent/execution-status-writer.ts +19 -0
- package/src/activities/execute-deep-agent/hitl.ts +221 -0
- package/src/activities/execute-deep-agent/index.ts +342 -0
- package/src/activities/execute-deep-agent/inline-publisher.ts +134 -0
- package/src/activities/execute-deep-agent/post-stream.ts +109 -0
- package/src/activities/execute-deep-agent/prompt-builder.ts +264 -0
- package/src/activities/execute-deep-agent/setup.ts +599 -0
- package/src/activities/execute-deep-agent/status-builder-shared.ts +136 -0
- package/src/activities/execute-deep-agent/status-builder.ts +412 -0
- package/src/activities/execute-deep-agent/streaming-scheduler.ts +159 -0
- package/src/activities/execute-deep-agent/streaming-side-effects.ts +89 -0
- package/src/activities/execute-deep-agent/streaming-terminal.ts +96 -0
- package/src/activities/execute-deep-agent/streaming-v3.ts +272 -0
- package/src/activities/execute-deep-agent/streaming.ts +303 -0
- package/src/activities/execute-deep-agent/subagent-tracker.ts +445 -0
- package/src/activities/execute-deep-agent/subagent-transformer.ts +648 -0
- package/src/activities/execute-deep-agent/subagent-wiring.ts +56 -0
- package/src/activities/execute-deep-agent/v3-event-recorder.ts +111 -0
- package/src/activities/execute-deep-agent/v3-events.ts +153 -0
- package/src/activities/execute-deep-agent/v3-protocol-normalizer.ts +264 -0
- package/src/activities/execute-deep-agent/v3-status-builder.ts +490 -0
- package/src/activities/execute-deep-agent/writeback-coordinator.ts +420 -0
- package/src/activities/hydrate-workflow-execution.ts +306 -0
- package/src/activities/notification.ts +71 -0
- package/src/activities/promote-task-output.ts +126 -0
- package/src/activities/run-command.ts +148 -0
- package/src/activities/workflow-event-activities.ts +481 -0
- package/src/bootstrap.ts +173 -0
- package/src/budget/__tests__/tracker.test.ts +293 -0
- package/src/budget/index.ts +9 -0
- package/src/budget/tracker.ts +171 -0
- package/src/claimcheck/compressor.ts +9 -0
- package/src/claimcheck/config.ts +20 -0
- package/src/claimcheck/index.ts +3 -0
- package/src/claimcheck/payload-codec.ts +107 -0
- package/src/client/__tests__/server-contracts.test.ts +149 -0
- package/src/client/__tests__/stigmer-client.test.ts +142 -0
- package/src/client/server-contracts.ts +125 -0
- package/src/client/stigmer-client.ts +339 -0
- package/src/config.ts +185 -0
- package/src/idle-watchdog.ts +28 -0
- package/src/index.ts +48 -0
- package/src/interceptors/workflow-metrics-sink.ts +56 -0
- package/src/ipc-protocol-fixtures.ts +117 -0
- package/src/ipc-protocol.ts +113 -0
- package/src/main.ts +324 -0
- package/src/middleware/__tests__/approval-gate.test.ts +231 -0
- package/src/middleware/__tests__/cost-cap.test.ts +192 -0
- package/src/middleware/__tests__/error-hints.test.ts +90 -0
- package/src/middleware/__tests__/execution-budget.test.ts +138 -0
- package/src/middleware/__tests__/graceful-stop.test.ts +105 -0
- package/src/middleware/__tests__/loop-detection.test.ts +137 -0
- package/src/middleware/__tests__/otel-spans.test.ts +89 -0
- package/src/middleware/__tests__/think-tool.test.ts +26 -0
- package/src/middleware/__tests__/tool-truncation.test.ts +112 -0
- package/src/middleware/approval-gate.ts +179 -0
- package/src/middleware/cost-cap.ts +213 -0
- package/src/middleware/error-hints.ts +136 -0
- package/src/middleware/execution-budget.ts +176 -0
- package/src/middleware/graceful-stop.ts +86 -0
- package/src/middleware/index.ts +70 -0
- package/src/middleware/loop-detection.ts +192 -0
- package/src/middleware/otel-spans.ts +205 -0
- package/src/middleware/think-tool.ts +38 -0
- package/src/middleware/tool-truncation.ts +94 -0
- package/src/middleware/types.ts +114 -0
- package/src/notification/__tests__/provider.test.ts +85 -0
- package/src/notification/__tests__/webhook.test.ts +127 -0
- package/src/notification/index.ts +15 -0
- package/src/notification/provider.ts +52 -0
- package/src/notification/webhook.ts +61 -0
- package/src/otel-metrics.ts +73 -0
- package/src/otel.ts +194 -0
- package/src/runner-manager.ts +652 -0
- package/src/runner-token-coordinator.ts +135 -0
- package/src/runner.ts +380 -0
- package/src/shared/__tests__/approval-policy.test.ts +256 -0
- package/src/shared/__tests__/artifact-storage-extended.test.ts +208 -0
- package/src/shared/__tests__/artifact-storage.test.ts +365 -0
- package/src/shared/__tests__/connect-backfill.test.ts +346 -0
- package/src/shared/__tests__/extract-json.test.ts +153 -0
- package/src/shared/__tests__/grpc-retry-extended.test.ts +176 -0
- package/src/shared/__tests__/grpc-retry.test.ts +172 -0
- package/src/shared/__tests__/json-schema-to-zod.test.ts +227 -0
- package/src/shared/__tests__/llm-proxy.test.ts +179 -0
- package/src/shared/__tests__/mcp-manager.test.ts +154 -0
- package/src/shared/__tests__/model-pricing.test.ts +85 -0
- package/src/shared/__tests__/model-registry.test.ts +197 -0
- package/src/shared/__tests__/placeholder-resolver.test.ts +210 -0
- package/src/shared/__tests__/plan-artifact.test.ts +142 -0
- package/src/shared/__tests__/skill-relevance.test.ts +292 -0
- package/src/shared/__tests__/skill-writer.test.ts +349 -0
- package/src/shared/__tests__/status.test.ts +142 -0
- package/src/shared/__tests__/subagent-gate.test.ts +112 -0
- package/src/shared/__tests__/tool-kind.test.ts +58 -0
- package/src/shared/__tests__/zip-extract.test.ts +204 -0
- package/src/shared/approval-policy.ts +146 -0
- package/src/shared/artifact-storage.ts +207 -0
- package/src/shared/checkpointer/__tests__/factory.test.ts +42 -0
- package/src/shared/checkpointer/__tests__/http-saver.test.ts +176 -0
- package/src/shared/checkpointer/factory.ts +73 -0
- package/src/shared/checkpointer/http-saver.ts +349 -0
- package/src/shared/checkpointer/types.ts +12 -0
- package/src/shared/connect-backfill.ts +162 -0
- package/src/shared/extract-json.ts +153 -0
- package/src/shared/grpc-retry.ts +113 -0
- package/src/shared/heartbeat.ts +70 -0
- package/src/shared/json-schema-to-zod.ts +53 -0
- package/src/shared/llm-proxy.ts +138 -0
- package/src/shared/mcp-manager.ts +150 -0
- package/src/shared/mcp-resolver.ts +150 -0
- package/src/shared/model-pricing-data.ts +109 -0
- package/src/shared/model-pricing.ts +81 -0
- package/src/shared/model-registry.ts +214 -0
- package/src/shared/placeholder-resolver.ts +102 -0
- package/src/shared/plan-artifact.ts +120 -0
- package/src/shared/skill-relevance.ts +222 -0
- package/src/shared/skill-writer.ts +300 -0
- package/src/shared/status.ts +94 -0
- package/src/shared/subagent-gate.ts +117 -0
- package/src/shared/tool-kind.ts +91 -0
- package/src/shared/workspace/__tests__/file-tree.test.ts +210 -0
- package/src/shared/workspace/__tests__/git-source.test.ts +423 -0
- package/src/shared/workspace/__tests__/local-backend-platform.test.ts +259 -0
- package/src/shared/workspace/__tests__/local-backend.test.ts +154 -0
- package/src/shared/workspace/__tests__/platform-mount.test.ts +378 -0
- package/src/shared/workspace/__tests__/provisioner.test.ts +145 -0
- package/src/shared/workspace/file-tree.ts +116 -0
- package/src/shared/workspace/local-backend.ts +140 -0
- package/src/shared/workspace/platform-dir.ts +38 -0
- package/src/shared/workspace/platform-mount.ts +190 -0
- package/src/shared/workspace/provisioner.ts +150 -0
- package/src/shared/workspace/sources/empty.ts +20 -0
- package/src/shared/workspace/sources/git.ts +285 -0
- package/src/shared/workspace/sources/local-path.ts +89 -0
- package/src/shared/workspace/types.ts +69 -0
- package/src/shared/zip-extract.ts +193 -0
- package/src/worker.ts +98 -0
- package/src/workflow-engine/__tests__/do-executor-recovery.test.ts +382 -0
- package/src/workflow-engine/__tests__/do-executor.test.ts +963 -0
- package/src/workflow-engine/__tests__/errors.test.ts +174 -0
- package/src/workflow-engine/__tests__/expression.test.ts +776 -0
- package/src/workflow-engine/__tests__/for.test.ts +575 -0
- package/src/workflow-engine/__tests__/fork.test.ts +838 -0
- package/src/workflow-engine/__tests__/golden-execution.test.ts +1085 -0
- package/src/workflow-engine/__tests__/jq-wasm-spike.test.ts +90 -0
- package/src/workflow-engine/__tests__/loader.test.ts +1393 -0
- package/src/workflow-engine/__tests__/pause-resume.test.ts +267 -0
- package/src/workflow-engine/__tests__/recovery.test.ts +115 -0
- package/src/workflow-engine/__tests__/resolve.test.ts +432 -0
- package/src/workflow-engine/__tests__/retry.test.ts +306 -0
- package/src/workflow-engine/__tests__/state.test.ts +174 -0
- package/src/workflow-engine/__tests__/task-status-accumulator.test.ts +373 -0
- package/src/workflow-engine/__tests__/tasks/call-agent-output.test.ts +120 -0
- package/src/workflow-engine/__tests__/tasks/call-agent.test.ts +816 -0
- package/src/workflow-engine/__tests__/tasks/call-function.test.ts +205 -0
- package/src/workflow-engine/__tests__/tasks/call-grpc.test.ts +133 -0
- package/src/workflow-engine/__tests__/tasks/call-http.test.ts +150 -0
- package/src/workflow-engine/__tests__/tasks/emit-event.test.ts +322 -0
- package/src/workflow-engine/__tests__/tasks/human-input.test.ts +416 -0
- package/src/workflow-engine/__tests__/tasks/listen.test.ts +422 -0
- package/src/workflow-engine/__tests__/tasks/raise.test.ts +166 -0
- package/src/workflow-engine/__tests__/tasks/run.test.ts +272 -0
- package/src/workflow-engine/__tests__/tasks/set.test.ts +127 -0
- package/src/workflow-engine/__tests__/tasks/switch.test.ts +277 -0
- package/src/workflow-engine/__tests__/tasks/try.test.ts +590 -0
- package/src/workflow-engine/__tests__/tasks/wait.test.ts +173 -0
- package/src/workflow-engine/clone.ts +18 -0
- package/src/workflow-engine/do-executor.ts +569 -0
- package/src/workflow-engine/duration.ts +22 -0
- package/src/workflow-engine/error-utils.ts +97 -0
- package/src/workflow-engine/errors.ts +130 -0
- package/src/workflow-engine/expression-utils.ts +129 -0
- package/src/workflow-engine/expression.ts +430 -0
- package/src/workflow-engine/loader.ts +524 -0
- package/src/workflow-engine/recovery.ts +80 -0
- package/src/workflow-engine/resolve.ts +342 -0
- package/src/workflow-engine/retry.ts +109 -0
- package/src/workflow-engine/state.ts +56 -0
- package/src/workflow-engine/task-factory.ts +160 -0
- package/src/workflow-engine/task-status-accumulator.ts +204 -0
- package/src/workflow-engine/tasks/call-agent-output.ts +132 -0
- package/src/workflow-engine/tasks/call-agent.ts +221 -0
- package/src/workflow-engine/tasks/call-function.ts +107 -0
- package/src/workflow-engine/tasks/call-grpc.ts +47 -0
- package/src/workflow-engine/tasks/call-http.ts +51 -0
- package/src/workflow-engine/tasks/for.ts +244 -0
- package/src/workflow-engine/tasks/fork.ts +228 -0
- package/src/workflow-engine/tasks/human-input.ts +147 -0
- package/src/workflow-engine/tasks/listen.ts +166 -0
- package/src/workflow-engine/tasks/raise.ts +81 -0
- package/src/workflow-engine/tasks/run.ts +142 -0
- package/src/workflow-engine/tasks/set.ts +47 -0
- package/src/workflow-engine/tasks/switch.ts +102 -0
- package/src/workflow-engine/tasks/try.ts +274 -0
- package/src/workflow-engine/tasks/wait.ts +53 -0
- package/src/workflow-engine/types.ts +911 -0
- package/src/workflows/__tests__/connect-mcp-server.test.ts +359 -0
- package/src/workflows/__tests__/execute-serverless-workflow.test.ts +277 -0
- package/src/workflows/call-agent-orchestrator.ts +283 -0
- package/src/workflows/connect-mcp-server.ts +152 -0
- package/src/workflows/engine-core.ts +406 -0
- package/src/workflows/execute-from-execution.ts +101 -0
- package/src/workflows/execute-serverless-workflow.ts +60 -0
- package/src/workflows/human-input-orchestrator.ts +76 -0
- package/src/workflows/index.ts +32 -0
- package/src/workflows/listen-orchestrator.ts +200 -0
- package/src/workflows/metrics-sink.ts +48 -0
- package/src/workflows/run-orchestrator.ts +34 -0
- package/src/workflows/types.ts +64 -0
- package/src/workflows/workflow-signals.ts +55 -0
|
@@ -0,0 +1,1439 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ExecuteCursor Temporal activity — the core of the cursor-runner service.
|
|
3
|
+
*
|
|
4
|
+
* Implements the same Slim-Payload Pattern as ExecuteGraphton:
|
|
5
|
+
* - Receives only executionId + harnessStateId (Cursor agentId)
|
|
6
|
+
* - Hydrates execution from DB via gRPC
|
|
7
|
+
* - Resolves full agent blueprint (instructions, MCP servers, skills, sub-agents)
|
|
8
|
+
* - Runs the Cursor agent, streams events, reports status
|
|
9
|
+
* - Returns slim AgentExecutionStatus to workflow
|
|
10
|
+
*
|
|
11
|
+
* Durable HITL Model:
|
|
12
|
+
* When a tool requires approval, the preToolUse hook denies it. The activity
|
|
13
|
+
* captures the denied tool details, reports WAITING_FOR_APPROVAL, and RETURNS
|
|
14
|
+
* to the workflow. The workflow waits for the approvalGateResolved signal,
|
|
15
|
+
* then reinvokes this activity. On reinvocation, the activity resumes the
|
|
16
|
+
* Cursor Agent and prompts it to execute the approved tool.
|
|
17
|
+
*
|
|
18
|
+
* This is identical to the LangGraph flow from the workflow's perspective.
|
|
19
|
+
*
|
|
20
|
+
* Durable Continuation Model:
|
|
21
|
+
* Conversation continuity is carried by the Cursor SDK's native local agent
|
|
22
|
+
* state, whose SQLite store is persisted on the durable workspace volume
|
|
23
|
+
* (see resolvePlatformOptions) so Agent.resume() survives pod restart,
|
|
24
|
+
* reschedule, and snapshot restore. When resume fails (store lost/corrupted
|
|
25
|
+
* or agent unknown), resolveAgent() creates a fresh agent and the next turn
|
|
26
|
+
* starts from the user message plus re-injected instructions.
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
import { heartbeat, Context, CancelledFailure } from "@temporalio/activity";
|
|
30
|
+
import { create, type JsonObject } from "@bufbuild/protobuf";
|
|
31
|
+
import { AgentExecutionStatusSchema } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/api_pb";
|
|
32
|
+
import { AgentMessageSchema } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/message_pb";
|
|
33
|
+
import type { PendingApproval } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/approval_pb";
|
|
34
|
+
import type { AgentExecutionStatus } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/api_pb";
|
|
35
|
+
import { ExecutionControlSignal, ExecutionPhase, InteractionMode, MessageType, ApprovalAction } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
|
|
36
|
+
import type { SDKMessage, Run, ConversationTurn } from "@cursor/sdk";
|
|
37
|
+
|
|
38
|
+
import type { Config } from "../../config.js";
|
|
39
|
+
import { StigmerClient } from "../../client/stigmer-client.js";
|
|
40
|
+
import { resolveAgent } from "./session-lifecycle.js";
|
|
41
|
+
import type { AgentResolution, CreateAgentOptions, CreateCloudAgentOptions } from "./session-lifecycle.js";
|
|
42
|
+
import { CursorMode } from "@stigmer/protos/ai/stigmer/agentic/session/v1/enum_pb";
|
|
43
|
+
import { determineCursorMode, isCloudMode } from "./cursor-mode.js";
|
|
44
|
+
import { MessageAccumulator, reconcileDeniedToolCalls, cancelInProgressSubAgentProtos } from "./message-translator.js";
|
|
45
|
+
import { utcTimestamp, persistStatus, reportSetupProgress, slimStatus } from "../../shared/status.js";
|
|
46
|
+
import { createArtifactStorage, loadArtifactStorageConfig } from "../../shared/artifact-storage.js";
|
|
47
|
+
import { publishPlanArtifact } from "../../shared/plan-artifact.js";
|
|
48
|
+
import { DeltaEnricher } from "./delta-enricher.js";
|
|
49
|
+
import { TodoTracker } from "./todo-tracker.js";
|
|
50
|
+
import { createCursorEventRecorder } from "./cursor-event-recorder.js";
|
|
51
|
+
import { resolveMcpServers, validateMcpServerEnv } from "./mcp-resolver.js";
|
|
52
|
+
import { mergeApprovalPolicies } from "./approval-policy.js";
|
|
53
|
+
import { hasApproveAllDecision } from "../../shared/approval-policy.js";
|
|
54
|
+
import { backfillMcpServersIfNeeded } from "./connect-backfill.js";
|
|
55
|
+
import { resolveExecutionEnv } from "./env-resolver.js";
|
|
56
|
+
import { resolveBlueprint } from "./blueprint-resolver.js";
|
|
57
|
+
import { buildCursorSubAgentDefinitions } from "./subagent-config.js";
|
|
58
|
+
import { resolveSkills } from "./skill-resolver.js";
|
|
59
|
+
import { resolveAttachments } from "./attachment-resolver.js";
|
|
60
|
+
import { buildEnhancedPrompt, buildReinvocationPrompt } from "./prompt-builder.js";
|
|
61
|
+
import { writeHooksToWorkspace } from "./workspace-setup.js";
|
|
62
|
+
import { buildApprovalState, buildApprovalGrants, readDenialLedger, reconstructAdjudicatedApprovals } from "./approval-state.js";
|
|
63
|
+
import { provisionCursorWorkspace } from "./workspace-provision.js";
|
|
64
|
+
import { setInterceptorExecutionId, runWithExecutionContext } from "./fetch-interceptor.js";
|
|
65
|
+
import { closeProxySessions } from "./http2-interceptor.js";
|
|
66
|
+
import { resolveModelId, ensureLoaded as ensurePricingLoaded } from "./model-pricing.js";
|
|
67
|
+
import { UsageAccumulator } from "./usage-accumulator.js";
|
|
68
|
+
import { StreamingUsageSummarySchema } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/usage_pb";
|
|
69
|
+
import { activityStarted, activityFinished } from "../../idle-watchdog.js";
|
|
70
|
+
import { getCapturedRejection, clearCapturedRejection } from "./rejection-capture.js";
|
|
71
|
+
import { synthesizeError, formatClassifiedError, shouldRetryWithFreshAgent } from "./error-classifier.js";
|
|
72
|
+
import type { ClassifiedError } from "./error-classifier.js";
|
|
73
|
+
import { createAgent, createCloudAgent } from "./session-lifecycle.js";
|
|
74
|
+
import { setMaxListeners } from "node:events";
|
|
75
|
+
import { startHeartbeat } from "../../shared/heartbeat.js";
|
|
76
|
+
import { getShutdownSignalForQueue } from "../../runner-manager.js";
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Creates the activity functions bound to the runner config.
|
|
80
|
+
* Returned object is passed to Temporal Worker.create({ activities }).
|
|
81
|
+
*/
|
|
82
|
+
export function createCursorActivities(config: Config) {
|
|
83
|
+
const client = new StigmerClient({
|
|
84
|
+
endpoint: config.stigmerBackendEndpoint,
|
|
85
|
+
token: config.stigmerToken,
|
|
86
|
+
tokenRef: config.stigmerTokenRef,
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
return {
|
|
90
|
+
ExecuteCursor: async (executionId: string, threadId: string): Promise<unknown> => {
|
|
91
|
+
activityStarted();
|
|
92
|
+
try {
|
|
93
|
+
return await executeCursor(config, client, executionId, threadId);
|
|
94
|
+
} finally {
|
|
95
|
+
activityFinished();
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
async function executeCursor(
|
|
102
|
+
config: Config,
|
|
103
|
+
client: StigmerClient,
|
|
104
|
+
executionId: string,
|
|
105
|
+
threadId: string,
|
|
106
|
+
): Promise<unknown> {
|
|
107
|
+
console.log(`ExecuteCursor started: execution=${executionId}, threadId=${threadId || "(new)"}`);
|
|
108
|
+
|
|
109
|
+
// Ensure fresh HTTP/2 transport — prevents a degraded session from a
|
|
110
|
+
// prior workflow task from poisoning this execution's agent stream.
|
|
111
|
+
closeProxySessions();
|
|
112
|
+
|
|
113
|
+
setInterceptorExecutionId(executionId);
|
|
114
|
+
return runWithExecutionContext(executionId, () => executeCursorInner(config, client, executionId, threadId));
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
async function executeCursorInner(
|
|
118
|
+
config: Config,
|
|
119
|
+
client: StigmerClient,
|
|
120
|
+
executionId: string,
|
|
121
|
+
threadId: string,
|
|
122
|
+
): Promise<unknown> {
|
|
123
|
+
|
|
124
|
+
const status = create(AgentExecutionStatusSchema, {
|
|
125
|
+
phase: ExecutionPhase.EXECUTION_IN_PROGRESS,
|
|
126
|
+
startedAt: utcTimestamp(),
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
let sessionId: string | undefined;
|
|
130
|
+
let session: import("@stigmer/protos/ai/stigmer/agentic/session/v1/api_pb").Session | undefined;
|
|
131
|
+
let pauseDetected = false;
|
|
132
|
+
let workerShutdownDetected = false;
|
|
133
|
+
let periodicHeartbeat: ReturnType<typeof startHeartbeat> | undefined;
|
|
134
|
+
// Carries model/mode/agentId out to the outer catch so a thrown CursorSdkError
|
|
135
|
+
// can be classified with the same context as the run.wait() error path.
|
|
136
|
+
let errorContext = { model: "default", mode: "local", agentId: "" };
|
|
137
|
+
|
|
138
|
+
try {
|
|
139
|
+
// Phase 1: Hydrate execution from DB
|
|
140
|
+
await reportSetupProgress(client, executionId, "Fetching execution");
|
|
141
|
+
const execution = await client.getExecution(executionId);
|
|
142
|
+
const spec = execution.spec!;
|
|
143
|
+
sessionId = spec.sessionId;
|
|
144
|
+
|
|
145
|
+
// Phase 2: Load session and resolve full agent blueprint
|
|
146
|
+
await reportSetupProgress(client, executionId, "Resolving agent blueprint");
|
|
147
|
+
session = await client.getSession(sessionId);
|
|
148
|
+
const blueprint = await resolveBlueprint(client, session, config.workspaceRootDir);
|
|
149
|
+
|
|
150
|
+
// Phase 2b: Resolve execution environment (MCP server credentials)
|
|
151
|
+
await reportSetupProgress(client, executionId, "Resolving environment");
|
|
152
|
+
const { envVars, secretKeys } = await resolveExecutionEnv(client, executionId);
|
|
153
|
+
heartbeat();
|
|
154
|
+
|
|
155
|
+
// Phase 2c: Provision the workspace (clone git repos / mount local paths)
|
|
156
|
+
// so the LOCAL Cursor agent operates on the actual repo. Cursor previously
|
|
157
|
+
// relied on cloud agents to clone git-repo workspace entries; with cloud
|
|
158
|
+
// disabled the runner must provision the workspace itself, mirroring the
|
|
159
|
+
// native harness. Git provisioning is idempotent across multi-turn and
|
|
160
|
+
// HITL reinvocations.
|
|
161
|
+
await reportSetupProgress(client, executionId, "Provisioning workspace");
|
|
162
|
+
blueprint.workspaceDirs = await provisionCursorWorkspace(
|
|
163
|
+
config, session, envVars, sessionId ?? "",
|
|
164
|
+
);
|
|
165
|
+
heartbeat();
|
|
166
|
+
|
|
167
|
+
// Set OTel baggage so downstream calls carry execution context.
|
|
168
|
+
try {
|
|
169
|
+
const { setBaggage, BAGGAGE_EXECUTION_ID, BAGGAGE_SESSION_ID, BAGGAGE_ORG_ID } = await import("../../otel.js");
|
|
170
|
+
await setBaggage({
|
|
171
|
+
[BAGGAGE_EXECUTION_ID]: executionId,
|
|
172
|
+
[BAGGAGE_SESSION_ID]: sessionId ?? "",
|
|
173
|
+
[BAGGAGE_ORG_ID]: session?.metadata?.org ?? "",
|
|
174
|
+
});
|
|
175
|
+
} catch {
|
|
176
|
+
// Tracing not initialized — silently skip.
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// Cloud Cursor agents are disabled platform-wide (see determineCursorMode),
|
|
180
|
+
// so every session runs LOCAL. We intentionally ignore any persisted
|
|
181
|
+
// cursor_mode here so a session can never route to the cloud path while
|
|
182
|
+
// it is disabled — even one that was created when cloud was enabled.
|
|
183
|
+
const cursorMode = determineCursorMode(
|
|
184
|
+
blueprint.sessionSpec.workspaceEntries,
|
|
185
|
+
config.cloudModeEnabled,
|
|
186
|
+
);
|
|
187
|
+
const agentMode = isCloudMode(cursorMode) ? "cloud" as const : "local" as const;
|
|
188
|
+
|
|
189
|
+
heartbeat();
|
|
190
|
+
|
|
191
|
+
// Phase 3: Check if this is a reinvocation after approval
|
|
192
|
+
const isReinvocation = !!threadId;
|
|
193
|
+
let approvalDecisions: Map<string, ApprovalAction> | undefined;
|
|
194
|
+
// Adjudicated approvals reconstructed from the tool calls (the source of
|
|
195
|
+
// truth for a decision). The backend projects pending_approvals from
|
|
196
|
+
// tool-call status and clears decided entries, so pending_approvals is empty
|
|
197
|
+
// by reinvocation time — the decision survives only on the tool call. This
|
|
198
|
+
// feeds both the grant builder and the reinvocation prompt below.
|
|
199
|
+
let adjudicatedApprovals: PendingApproval[] = [];
|
|
200
|
+
|
|
201
|
+
if (isReinvocation) {
|
|
202
|
+
const existingStatus = execution.status;
|
|
203
|
+
const adjudicated = reconstructAdjudicatedApprovals(existingStatus?.messages ?? []);
|
|
204
|
+
if (adjudicated.decisions.size > 0) {
|
|
205
|
+
approvalDecisions = adjudicated.decisions;
|
|
206
|
+
adjudicatedApprovals = adjudicated.pendingApprovals;
|
|
207
|
+
|
|
208
|
+
const hasReject = [...approvalDecisions.values()].some(
|
|
209
|
+
(a) => a === ApprovalAction.REJECT,
|
|
210
|
+
);
|
|
211
|
+
if (hasReject) {
|
|
212
|
+
status.phase = ExecutionPhase.EXECUTION_FAILED;
|
|
213
|
+
status.error = "Execution rejected by user";
|
|
214
|
+
status.completedAt = utcTimestamp();
|
|
215
|
+
status.messages.push(create(AgentMessageSchema, {
|
|
216
|
+
type: MessageType.MESSAGE_SYSTEM,
|
|
217
|
+
content: "Execution was rejected by the user during tool approval.",
|
|
218
|
+
timestamp: utcTimestamp(),
|
|
219
|
+
}));
|
|
220
|
+
await persistStatus(client, executionId, status);
|
|
221
|
+
return slimStatus(status);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// Phase 4: Resolve MCP servers with approval policies
|
|
227
|
+
await reportSetupProgress(client, executionId, "Resolving MCP servers");
|
|
228
|
+
let mcpResolution = await resolveMcpServers(
|
|
229
|
+
client, blueprint.mergedMcpServerUsages, envVars,
|
|
230
|
+
);
|
|
231
|
+
|
|
232
|
+
// Phase 4a: Connect backfill for undiscovered MCP servers
|
|
233
|
+
const sessionOrg = session.metadata?.org ?? "";
|
|
234
|
+
mcpResolution = await backfillMcpServersIfNeeded(
|
|
235
|
+
client, mcpResolution, blueprint.mergedMcpServerUsages, envVars, sessionOrg,
|
|
236
|
+
heartbeat, secretKeys,
|
|
237
|
+
);
|
|
238
|
+
const mcpConfig = mcpResolution.cursorConfig;
|
|
239
|
+
|
|
240
|
+
// Phase 4b: Merge approval policies from all layers.
|
|
241
|
+
//
|
|
242
|
+
// Effective auto-approve is true when EITHER the execution was pre-armed via
|
|
243
|
+
// spec.auto_approve_all OR a user chose APPROVE_ALL ("approve and don't ask
|
|
244
|
+
// again") at some gate earlier in this run. The shared hasApproveAllDecision
|
|
245
|
+
// helper (used by the native harness too) keeps this contract defined once.
|
|
246
|
+
// When true, the merged policy map is empty and the hook state file disables
|
|
247
|
+
// gating for the rest of the run.
|
|
248
|
+
const effectiveAutoApproveAll =
|
|
249
|
+
(execution.spec?.autoApproveAll ?? false) || hasApproveAllDecision(execution);
|
|
250
|
+
const agentOverrides = blueprint.mergedMcpServerUsages
|
|
251
|
+
.flatMap((u) => u.toolApprovalOverrides ?? []);
|
|
252
|
+
const mergedPolicies = mergeApprovalPolicies(
|
|
253
|
+
mcpResolution.resolvedServers,
|
|
254
|
+
agentOverrides,
|
|
255
|
+
effectiveAutoApproveAll,
|
|
256
|
+
);
|
|
257
|
+
heartbeat();
|
|
258
|
+
|
|
259
|
+
// Phase 4c: Validate MCP server env health (diagnostic, non-blocking)
|
|
260
|
+
const mcpWarnings = validateMcpServerEnv(
|
|
261
|
+
mcpResolution.resolvedServers,
|
|
262
|
+
blueprint.mergedMcpServerUsages,
|
|
263
|
+
envVars,
|
|
264
|
+
);
|
|
265
|
+
if (mcpWarnings.length > 0) {
|
|
266
|
+
console.warn(
|
|
267
|
+
`ExecuteCursor MCP pre-flight warnings: execution=${executionId}\n` +
|
|
268
|
+
mcpWarnings.map((w) => ` - ${w}`).join("\n"),
|
|
269
|
+
);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// Phase 5: Resolve skills (merged from agent + session)
|
|
273
|
+
await reportSetupProgress(client, executionId, "Resolving skills");
|
|
274
|
+
const primaryWorkspaceDir = blueprint.workspaceDirs[0];
|
|
275
|
+
const skillMetadata = await resolveSkills(client, blueprint.mergedSkillRefs, {
|
|
276
|
+
sessionId,
|
|
277
|
+
primaryWorkspaceDir,
|
|
278
|
+
});
|
|
279
|
+
heartbeat();
|
|
280
|
+
|
|
281
|
+
// Phase 5b: Resolve attachments
|
|
282
|
+
const attachmentResults = await resolveAttachments(
|
|
283
|
+
spec.attachments,
|
|
284
|
+
sessionId,
|
|
285
|
+
primaryWorkspaceDir,
|
|
286
|
+
config.mode,
|
|
287
|
+
);
|
|
288
|
+
const attachmentPaths = attachmentResults.map((a) => a.relativePath);
|
|
289
|
+
|
|
290
|
+
// Phase 5c: Ensure model pricing registry is populated before validation
|
|
291
|
+
await ensurePricingLoaded();
|
|
292
|
+
|
|
293
|
+
// Phase 6: Validate model selection
|
|
294
|
+
const requestedModel = spec.executionConfig?.modelName || "default";
|
|
295
|
+
const validatedModel = resolveModelId(requestedModel);
|
|
296
|
+
if (validatedModel !== requestedModel) {
|
|
297
|
+
console.log(
|
|
298
|
+
`ExecuteCursor model resolved: execution=${executionId}, requested="${requestedModel}", using="${validatedModel}"`,
|
|
299
|
+
);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
heartbeat();
|
|
303
|
+
|
|
304
|
+
// Phase 7: Resolve Cursor Agent (create, resume, or graceful fallback)
|
|
305
|
+
await reportSetupProgress(client, executionId, "Initializing Cursor agent");
|
|
306
|
+
|
|
307
|
+
// In proxy mode, use the stigmer token as the API key — the proxy
|
|
308
|
+
// validates it and injects the real Cursor API key server-side.
|
|
309
|
+
// In direct mode, use the user's own CURSOR_API_KEY.
|
|
310
|
+
const effectiveApiKey = config.proxyEndpoint
|
|
311
|
+
? (config.stigmerTokenRef?.current ?? config.stigmerToken ?? config.cursorApiKey)
|
|
312
|
+
: config.cursorApiKey;
|
|
313
|
+
|
|
314
|
+
if (!effectiveApiKey || effectiveApiKey === "proxy-managed") {
|
|
315
|
+
const source = config.proxyEndpoint ? "proxy (STIGMER_TOKEN)" : "direct (CURSOR_API_KEY)";
|
|
316
|
+
throw new Error(
|
|
317
|
+
`No Cursor API credential available. Mode=${source}, ` +
|
|
318
|
+
`proxyEndpoint=${config.proxyEndpoint ?? "unset"}, ` +
|
|
319
|
+
`hasStigmerToken=${!!config.stigmerToken}, ` +
|
|
320
|
+
`hasTokenRef=${!!config.stigmerTokenRef?.current}`,
|
|
321
|
+
);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// Register blueprint sub-agents with the Cursor SDK so the parent can
|
|
325
|
+
// delegate to them by name via the Task tool. Re-supplied on every
|
|
326
|
+
// create/resume (the SDK does not persist agent config across resume).
|
|
327
|
+
const cursorSubAgents = buildCursorSubAgentDefinitions(blueprint.subAgents);
|
|
328
|
+
if (cursorSubAgents) {
|
|
329
|
+
console.log(
|
|
330
|
+
`ExecuteCursor registering ${Object.keys(cursorSubAgents).length} custom sub-agent(s): ` +
|
|
331
|
+
`execution=${executionId}, names=${Object.keys(cursorSubAgents).join(", ")}`,
|
|
332
|
+
);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
const createOptions: CreateAgentOptions | CreateCloudAgentOptions = agentMode === "cloud"
|
|
336
|
+
? {
|
|
337
|
+
apiKey: effectiveApiKey,
|
|
338
|
+
model: validatedModel || undefined,
|
|
339
|
+
repos: blueprint.cloudRepos,
|
|
340
|
+
sessionId,
|
|
341
|
+
mcpServers: mcpConfig,
|
|
342
|
+
agents: cursorSubAgents,
|
|
343
|
+
}
|
|
344
|
+
: {
|
|
345
|
+
apiKey: effectiveApiKey,
|
|
346
|
+
model: validatedModel,
|
|
347
|
+
workspaceDirs: blueprint.workspaceDirs,
|
|
348
|
+
sessionId,
|
|
349
|
+
workspaceRootDir: config.workspaceRootDir,
|
|
350
|
+
mcpServers: mcpConfig,
|
|
351
|
+
agents: cursorSubAgents,
|
|
352
|
+
};
|
|
353
|
+
|
|
354
|
+
let resolution: AgentResolution = await resolveAgent(
|
|
355
|
+
threadId,
|
|
356
|
+
createOptions,
|
|
357
|
+
agentMode,
|
|
358
|
+
);
|
|
359
|
+
|
|
360
|
+
console.log(
|
|
361
|
+
`ExecuteCursor agent resolved: execution=${executionId}, ` +
|
|
362
|
+
`reason=${resolution.reason}, mode=${resolution.mode}, ` +
|
|
363
|
+
`agentId=${resolution.agentId}, resumed=${resolution.resumed}` +
|
|
364
|
+
(resolution.resumeFailureDetail ? `, failureDetail=${resolution.resumeFailureDetail}` : ""),
|
|
365
|
+
);
|
|
366
|
+
|
|
367
|
+
errorContext = { model: validatedModel, mode: agentMode, agentId: resolution.agentId };
|
|
368
|
+
|
|
369
|
+
// Phase 8: Write hooks for HITL with policy-aware state. On reinvocation,
|
|
370
|
+
// turn the user's approvals into tool-identity grants so the resumed agent's
|
|
371
|
+
// re-attempt (which carries a fresh tool-call id) is allowed through.
|
|
372
|
+
const approvalGrants = approvalDecisions
|
|
373
|
+
? buildApprovalGrants(adjudicatedApprovals, approvalDecisions)
|
|
374
|
+
: undefined;
|
|
375
|
+
const approvalState = buildApprovalState(
|
|
376
|
+
mergedPolicies,
|
|
377
|
+
effectiveAutoApproveAll,
|
|
378
|
+
approvalGrants,
|
|
379
|
+
);
|
|
380
|
+
await writeHooksToWorkspace(primaryWorkspaceDir, approvalState);
|
|
381
|
+
|
|
382
|
+
// Phase 9: Store new agentId as harness_state_id and persist cursor_mode
|
|
383
|
+
if (resolution.isNew && resolution.agentId) {
|
|
384
|
+
try {
|
|
385
|
+
blueprint.sessionSpec.harnessStateId = resolution.agentId;
|
|
386
|
+
if (blueprint.sessionSpec.cursorMode === CursorMode.UNSPECIFIED) {
|
|
387
|
+
blueprint.sessionSpec.cursorMode = cursorMode;
|
|
388
|
+
}
|
|
389
|
+
// Clear slug to avoid re-validation of potentially invalid
|
|
390
|
+
// server-generated slugs. BuildUpdateStateStep preserves the
|
|
391
|
+
// existing slug from the database record.
|
|
392
|
+
if (blueprint.session.metadata) {
|
|
393
|
+
blueprint.session.metadata.slug = "";
|
|
394
|
+
}
|
|
395
|
+
await client.updateSession(blueprint.session);
|
|
396
|
+
console.log(
|
|
397
|
+
`Stored Cursor agentId=${resolution.agentId} as harness_state_id, ` +
|
|
398
|
+
`cursorMode=${CursorMode[cursorMode]} on session ${sessionId}`,
|
|
399
|
+
);
|
|
400
|
+
} catch (err) {
|
|
401
|
+
console.warn("Failed to persist harness_state_id/cursorMode on session (non-fatal):", err);
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
// Phase 9b: Detect structured output schema from execution config
|
|
406
|
+
const structuredOutputSchema = spec.executionConfig?.structuredOutputSchema as
|
|
407
|
+
Record<string, unknown> | undefined;
|
|
408
|
+
|
|
409
|
+
// Phase 10: Build the prompt
|
|
410
|
+
const interactionMode = spec.executionConfig?.interactionMode
|
|
411
|
+
?? InteractionMode.UNSPECIFIED;
|
|
412
|
+
|
|
413
|
+
const prompt = buildPrompt({
|
|
414
|
+
resolution,
|
|
415
|
+
approvalDecisions,
|
|
416
|
+
instructions: blueprint.instructions,
|
|
417
|
+
userMessage: spec.message,
|
|
418
|
+
skills: skillMetadata,
|
|
419
|
+
subAgents: blueprint.subAgents,
|
|
420
|
+
workspaceDirs: blueprint.workspaceDirs,
|
|
421
|
+
workspaceFileRefs: spec.workspaceFileRefs ?? [],
|
|
422
|
+
attachmentPaths,
|
|
423
|
+
pendingApprovals: adjudicatedApprovals,
|
|
424
|
+
interactionMode,
|
|
425
|
+
});
|
|
426
|
+
|
|
427
|
+
// Phase 10a: Inject structured output instruction for Cursor harness
|
|
428
|
+
let effectivePrompt = prompt;
|
|
429
|
+
if (structuredOutputSchema) {
|
|
430
|
+
const schemaStr = JSON.stringify(structuredOutputSchema, null, 2);
|
|
431
|
+
effectivePrompt += `\n\n---\nCRITICAL OUTPUT REQUIREMENT:\nYour final response MUST be a single valid JSON object (no markdown, no commentary, no code fences) that matches this schema:\n${schemaStr}\n\nRespond with ONLY the JSON object. Nothing else.`;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
// Phase 10a2: Log Stigmer preamble size for context trimming diagnostics
|
|
435
|
+
const promptChars = effectivePrompt.length;
|
|
436
|
+
const promptEstimatedTokens = Math.ceil(promptChars / 4);
|
|
437
|
+
console.log(
|
|
438
|
+
`ExecuteCursor prompt built: execution=${executionId}, ` +
|
|
439
|
+
`chars=${promptChars}, estimatedTokens=${promptEstimatedTokens}, ` +
|
|
440
|
+
`resolution=${resolution.reason}, mode=${resolution.mode}`,
|
|
441
|
+
);
|
|
442
|
+
|
|
443
|
+
// Phase 10b: Initialize usage accumulator for runner-side token tracking
|
|
444
|
+
await ensurePricingLoaded();
|
|
445
|
+
const usageAccumulator = new UsageAccumulator(validatedModel);
|
|
446
|
+
|
|
447
|
+
// Phase 10c: Start OTel turn span (coarse-grained — wraps entire agent.send + stream)
|
|
448
|
+
const { startCursorTurnSpan } = await import("../../otel.js");
|
|
449
|
+
const turnSpan = await startCursorTurnSpan({
|
|
450
|
+
model: validatedModel,
|
|
451
|
+
mode: agentMode,
|
|
452
|
+
sessionId: sessionId ?? "",
|
|
453
|
+
});
|
|
454
|
+
|
|
455
|
+
// Phase 11: Send message and stream events
|
|
456
|
+
status.phase = ExecutionPhase.EXECUTION_IN_PROGRESS;
|
|
457
|
+
|
|
458
|
+
const deltaEnricher = new DeltaEnricher();
|
|
459
|
+
const todoTracker = new TodoTracker(status.todos);
|
|
460
|
+
const eventRecorder = createCursorEventRecorder(executionId);
|
|
461
|
+
|
|
462
|
+
let platformStopSignaled = false;
|
|
463
|
+
let firstTurnAttributionLogged = false;
|
|
464
|
+
let streamErrorMessage: string | undefined;
|
|
465
|
+
let alreadyRetriedWithFreshAgent = false;
|
|
466
|
+
|
|
467
|
+
// Periodic heartbeat keeps Temporal informed during silent SDK operations
|
|
468
|
+
// (e.g. long tool calls, MCP requests, model thinking). Without this,
|
|
469
|
+
// the 2-minute heartbeat timeout can cancel the activity and mislabel
|
|
470
|
+
// the execution as "paused by user".
|
|
471
|
+
const taskQueue = Context.current().info.taskQueue;
|
|
472
|
+
const shutdownSignal = getShutdownSignalForQueue(taskQueue);
|
|
473
|
+
periodicHeartbeat = startHeartbeat(30_000, () => ({
|
|
474
|
+
phase: "cursor_streaming",
|
|
475
|
+
execution: executionId,
|
|
476
|
+
}), { shutdownSignal });
|
|
477
|
+
|
|
478
|
+
// The Cursor SDK registers abort listeners on the cancellation signal for
|
|
479
|
+
// each concurrent tool call (fetch, MCP, shell). With 10+ parallel tools,
|
|
480
|
+
// Node's default limit of 10 triggers MaxListenersExceededWarning. This is
|
|
481
|
+
// a diagnostic warning, not a functional error — reproduction tests confirm
|
|
482
|
+
// zero tool call loss — but it pollutes logs and creates false alarm fatigue.
|
|
483
|
+
// Raise the limit on the Temporal cancellation signal used throughout this
|
|
484
|
+
// activity. 25 covers observed peaks (~12 concurrent tools + heartbeat +
|
|
485
|
+
// shutdown signal + SDK internals) with headroom.
|
|
486
|
+
try {
|
|
487
|
+
setMaxListeners(25, Context.current().cancellationSignal);
|
|
488
|
+
} catch {
|
|
489
|
+
// Fallback: if the Temporal signal doesn't support setMaxListeners
|
|
490
|
+
// (e.g. older SDK), the warning is harmless — ignore.
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
const run = await resolution.agent.send(effectivePrompt, {
|
|
494
|
+
onDelta: ({ update }) => {
|
|
495
|
+
if (update.type === "turn-ended" && update.usage) {
|
|
496
|
+
usageAccumulator.addTurn(update.usage);
|
|
497
|
+
|
|
498
|
+
if (!firstTurnAttributionLogged) {
|
|
499
|
+
firstTurnAttributionLogged = true;
|
|
500
|
+
const sdkInputTokens = update.usage.inputTokens ?? 0;
|
|
501
|
+
const cursorOverhead = Math.max(0, sdkInputTokens - promptEstimatedTokens);
|
|
502
|
+
console.log(
|
|
503
|
+
`ExecuteCursor context attribution (first turn): execution=${executionId}, ` +
|
|
504
|
+
`sdkInputTokens=${sdkInputTokens}, stigmerPreamble=${promptEstimatedTokens}, ` +
|
|
505
|
+
`cursorOverhead=${cursorOverhead} (estimated)`,
|
|
506
|
+
);
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
deltaEnricher.processDelta(update);
|
|
510
|
+
try {
|
|
511
|
+
heartbeat();
|
|
512
|
+
} catch (hbErr) {
|
|
513
|
+
if (hbErr instanceof CancelledFailure) {
|
|
514
|
+
pauseDetected = true;
|
|
515
|
+
return;
|
|
516
|
+
}
|
|
517
|
+
throw hbErr;
|
|
518
|
+
}
|
|
519
|
+
},
|
|
520
|
+
});
|
|
521
|
+
|
|
522
|
+
const accumulator = new MessageAccumulator(status.messages, { mergedPolicies });
|
|
523
|
+
let eventCount = 0;
|
|
524
|
+
|
|
525
|
+
for await (const event of run.stream()) {
|
|
526
|
+
if (pauseDetected || Context.current().cancellationSignal.aborted) {
|
|
527
|
+
pauseDetected = true;
|
|
528
|
+
break;
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
eventRecorder?.record(event, eventCount);
|
|
532
|
+
|
|
533
|
+
accumulator.processEvent(event);
|
|
534
|
+
todoTracker.processEvent(event);
|
|
535
|
+
|
|
536
|
+
if (event.type === "tool_call" && event.name === "task") {
|
|
537
|
+
accumulator.trackSubAgentExecution(
|
|
538
|
+
event as Extract<SDKMessage, { type: "tool_call" }>,
|
|
539
|
+
);
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
deltaEnricher.applyEnrichments(status.messages);
|
|
543
|
+
eventCount++;
|
|
544
|
+
|
|
545
|
+
if (event.type === "status") {
|
|
546
|
+
console.log(
|
|
547
|
+
`ExecuteCursor stream status: execution=${executionId}, status=${JSON.stringify(event)}`,
|
|
548
|
+
);
|
|
549
|
+
const statusEvent = event as { status?: string; message?: string };
|
|
550
|
+
if (statusEvent.status === "ERROR" && statusEvent.message) {
|
|
551
|
+
streamErrorMessage = statusEvent.message;
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
const shouldPersist = eventCount % 20 === 0 || deltaEnricher.isDirty ||
|
|
556
|
+
todoTracker.isDirty || accumulator.subAgentDirty;
|
|
557
|
+
if (usageAccumulator.hasTurns) {
|
|
558
|
+
status.streamingUsage = create(StreamingUsageSummarySchema, usageAccumulator.snapshot());
|
|
559
|
+
}
|
|
560
|
+
if (shouldPersist) {
|
|
561
|
+
// Sync sub-agent executions into status before every persist so the
|
|
562
|
+
// live UI reflects delegation (including the IN_PROGRESS state) while
|
|
563
|
+
// the parent is still running — matching the native harness, which
|
|
564
|
+
// calls syncSubAgentExecutions() on each persist. Without this, the
|
|
565
|
+
// accumulator tracked sub-agents in memory but they only reached the
|
|
566
|
+
// status (and the subscriber stream) after the loop ended.
|
|
567
|
+
status.subAgentExecutions = accumulator.subAgentExecutions;
|
|
568
|
+
const signal = await persistStatus(client, executionId, status);
|
|
569
|
+
deltaEnricher.markPersisted();
|
|
570
|
+
todoTracker.markPersisted();
|
|
571
|
+
accumulator.markSubAgentPersisted();
|
|
572
|
+
heartbeat();
|
|
573
|
+
if (signal === ExecutionControlSignal.STOP) {
|
|
574
|
+
platformStopSignaled = true;
|
|
575
|
+
console.warn(
|
|
576
|
+
`ExecuteCursor platform stop signal received: execution=${executionId}`,
|
|
577
|
+
);
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
if (platformStopSignaled) {
|
|
582
|
+
console.log(`ExecuteCursor stopping stream due to platform stop signal: execution=${executionId}`);
|
|
583
|
+
break;
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
periodicHeartbeat.stop();
|
|
588
|
+
// Check both the heartbeat flag AND the shutdown signal directly.
|
|
589
|
+
// Race condition: the heartbeat timer may detect Temporal's CancelledFailure
|
|
590
|
+
// (from worker.shutdown()) before the AbortSignal microtask propagates,
|
|
591
|
+
// causing it to set `cancelled` instead of `workerShutdown`. The direct
|
|
592
|
+
// signal check catches this case.
|
|
593
|
+
const isShutdown = periodicHeartbeat.workerShutdown || (shutdownSignal?.aborted ?? false);
|
|
594
|
+
if (isShutdown) {
|
|
595
|
+
pauseDetected = false;
|
|
596
|
+
} else if (periodicHeartbeat.cancelled) {
|
|
597
|
+
pauseDetected = true;
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
workerShutdownDetected = isShutdown;
|
|
601
|
+
|
|
602
|
+
accumulator.finalize();
|
|
603
|
+
deltaEnricher.finalize(status.messages);
|
|
604
|
+
// A pause / cancel / worker shutdown aborts the Cursor SDK run, so any
|
|
605
|
+
// sub-agent the parent had delegated is no longer executing. Mark it
|
|
606
|
+
// CANCELLED rather than leaving a permanent IN_PROGRESS "zombie" in the
|
|
607
|
+
// final snapshot (parity with the native harness's cancelSubAgents()).
|
|
608
|
+
if (pauseDetected || workerShutdownDetected || Context.current().cancellationSignal.aborted) {
|
|
609
|
+
accumulator.cancelInProgressSubAgents();
|
|
610
|
+
}
|
|
611
|
+
status.subAgentExecutions = accumulator.subAgentExecutions;
|
|
612
|
+
await eventRecorder?.flush();
|
|
613
|
+
if (usageAccumulator.hasTurns) {
|
|
614
|
+
status.streamingUsage = create(StreamingUsageSummarySchema, usageAccumulator.snapshot());
|
|
615
|
+
}
|
|
616
|
+
console.log(
|
|
617
|
+
`ExecuteCursor stream ended: execution=${executionId}, events=${eventCount}, messages=${status.messages.length}, subAgents=${status.subAgentExecutions.length}`,
|
|
618
|
+
);
|
|
619
|
+
|
|
620
|
+
// Persist immediately after finalize so the UI sees correct tool
|
|
621
|
+
// call statuses before run.wait() / structured output extraction.
|
|
622
|
+
// This is unconditional (not throttled) because finalize is a
|
|
623
|
+
// once-per-execution correctness boundary.
|
|
624
|
+
await persistStatus(client, executionId, status);
|
|
625
|
+
heartbeat();
|
|
626
|
+
|
|
627
|
+
// End OTel turn span with accumulated token usage
|
|
628
|
+
const usageSnapshot = usageAccumulator.snapshot();
|
|
629
|
+
turnSpan.setTokens(Number(usageSnapshot.inputTokens), Number(usageSnapshot.outputTokens));
|
|
630
|
+
turnSpan.end();
|
|
631
|
+
|
|
632
|
+
// Record cursor turn metrics (duration, tokens)
|
|
633
|
+
try {
|
|
634
|
+
const { recordTurnMetrics } = await import("../../otel.js");
|
|
635
|
+
const turnDurationMs = Date.now() - (status.startedAt ? new Date(status.startedAt).getTime() : Date.now());
|
|
636
|
+
await recordTurnMetrics({
|
|
637
|
+
durationMs: turnDurationMs,
|
|
638
|
+
inputTokens: Number(usageSnapshot.inputTokens),
|
|
639
|
+
outputTokens: Number(usageSnapshot.outputTokens),
|
|
640
|
+
model: validatedModel,
|
|
641
|
+
mode: agentMode,
|
|
642
|
+
});
|
|
643
|
+
} catch {
|
|
644
|
+
// Metrics not initialized — silently skip.
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
|
|
648
|
+
// Phase 11a: Handle worker shutdown, pause, or infrastructure cancellation.
|
|
649
|
+
|
|
650
|
+
// Worker shutdown: the runner-manager aborted the shutdown signal before
|
|
651
|
+
// calling worker.shutdown(). This is NOT a user-initiated pause — it's
|
|
652
|
+
// an infrastructure event (e.g., premature removal from UI race).
|
|
653
|
+
if (workerShutdownDetected) {
|
|
654
|
+
status.phase = ExecutionPhase.EXECUTION_FAILED;
|
|
655
|
+
status.error = "Execution interrupted: runner worker was shut down. Retry or resume.";
|
|
656
|
+
status.completedAt = utcTimestamp();
|
|
657
|
+
status.messages.push(create(AgentMessageSchema, {
|
|
658
|
+
type: MessageType.MESSAGE_SYSTEM,
|
|
659
|
+
content: "Execution interrupted: the runner worker was shut down while the agent was still running. You can retry or resume.",
|
|
660
|
+
timestamp: utcTimestamp(),
|
|
661
|
+
}));
|
|
662
|
+
await persistStatus(client, executionId, status); console.log(`ExecuteCursor interrupted (worker shutdown): execution=${executionId}, events=${eventCount}`);
|
|
663
|
+
throw new CancelledFailure("Activity cancelled (worker shutdown, not user pause)");
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
// pauseDetected is only true if a heartbeat() call threw CancelledFailure,
|
|
667
|
+
// confirming the orchestrator explicitly requested a pause.
|
|
668
|
+
if (pauseDetected) {
|
|
669
|
+
status.phase = ExecutionPhase.EXECUTION_PAUSED;
|
|
670
|
+
status.messages.push(create(AgentMessageSchema, {
|
|
671
|
+
type: MessageType.MESSAGE_SYSTEM,
|
|
672
|
+
content: "Execution paused by user. Use resume to continue.",
|
|
673
|
+
timestamp: utcTimestamp(),
|
|
674
|
+
}));
|
|
675
|
+
await persistStatus(client, executionId, status); console.log(`ExecuteCursor paused: execution=${executionId}, events=${eventCount}`);
|
|
676
|
+
throw new CancelledFailure("Activity paused by orchestrator");
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
// If cancellation arrived without pauseDetected (e.g. heartbeat timeout
|
|
680
|
+
// that slipped past the periodic heartbeat, or worker shutdown), report
|
|
681
|
+
// as failed rather than misleadingly labeling it as user-paused.
|
|
682
|
+
if (Context.current().cancellationSignal.aborted) {
|
|
683
|
+
status.phase = ExecutionPhase.EXECUTION_FAILED;
|
|
684
|
+
status.error = "Execution interrupted: agent was unresponsive (heartbeat timeout). Retry or resume.";
|
|
685
|
+
status.completedAt = utcTimestamp();
|
|
686
|
+
status.messages.push(create(AgentMessageSchema, {
|
|
687
|
+
type: MessageType.MESSAGE_SYSTEM,
|
|
688
|
+
content: "Execution interrupted: the agent was unresponsive for too long. You can retry or resume.",
|
|
689
|
+
timestamp: utcTimestamp(),
|
|
690
|
+
}));
|
|
691
|
+
await persistStatus(client, executionId, status); console.log(`ExecuteCursor interrupted (infrastructure cancel): execution=${executionId}, events=${eventCount}`);
|
|
692
|
+
throw new CancelledFailure("Activity cancelled (heartbeat timeout, not user pause)");
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
// Phase 11b: Handle platform stop signal early exit
|
|
696
|
+
if (platformStopSignaled) {
|
|
697
|
+
status.phase = ExecutionPhase.EXECUTION_COMPLETED;
|
|
698
|
+
status.completedAt = utcTimestamp();
|
|
699
|
+
status.messages.push(create(AgentMessageSchema, {
|
|
700
|
+
type: MessageType.MESSAGE_SYSTEM,
|
|
701
|
+
content: "Execution stopped by the platform.",
|
|
702
|
+
timestamp: utcTimestamp(),
|
|
703
|
+
}));
|
|
704
|
+
await persistStatus(client, executionId, status); try { resolution.agent.close(); } catch { /* best effort */ }
|
|
705
|
+
console.log(`ExecuteCursor completed (platform stop): execution=${executionId}`);
|
|
706
|
+
return slimStatus(status);
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
// Phase 12: Surface tools the preToolUse hook gated (HITL).
|
|
710
|
+
//
|
|
711
|
+
// The hook records each denial to the ledger; we mark the corresponding tool
|
|
712
|
+
// calls WAITING_APPROVAL. The backend projects pending_approvals from that
|
|
713
|
+
// tool-call status (PendingApprovalComputer), so — exactly like the native
|
|
714
|
+
// harness — the approval surface is driven entirely by tool-call status. We
|
|
715
|
+
// deliberately do NOT set status.pendingApprovals here: any value would be
|
|
716
|
+
// discarded by the backend's recompute on the next updateStatus.
|
|
717
|
+
const deniedLedger = await readDenialLedger(primaryWorkspaceDir);
|
|
718
|
+
const deniedToolCalls = reconcileDeniedToolCalls(status.messages, deniedLedger, mergedPolicies);
|
|
719
|
+
if (deniedToolCalls.length > 0) {
|
|
720
|
+
status.phase = ExecutionPhase.EXECUTION_WAITING_FOR_APPROVAL;
|
|
721
|
+
await persistStatus(client, executionId, status);
|
|
722
|
+
console.log(`ExecuteCursor returning WAITING_FOR_APPROVAL: ${deniedToolCalls.length} tools pending`);
|
|
723
|
+
return slimStatus(status);
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
// Phase 13: Map final result
|
|
727
|
+
const result = await run.wait();
|
|
728
|
+
const sdkResolvedModel = result.model?.id || undefined;
|
|
729
|
+
console.log(
|
|
730
|
+
`ExecuteCursor run.wait() result: execution=${executionId}, result=${JSON.stringify(result)}`,
|
|
731
|
+
);
|
|
732
|
+
if (sdkResolvedModel && sdkResolvedModel !== validatedModel) {
|
|
733
|
+
console.log(
|
|
734
|
+
`ExecuteCursor model divergence: execution=${executionId}, requested=${validatedModel}, sdkResolved=${sdkResolvedModel}`,
|
|
735
|
+
);
|
|
736
|
+
}
|
|
737
|
+
status.completedAt = utcTimestamp();
|
|
738
|
+
|
|
739
|
+
switch (result.status) {
|
|
740
|
+
case "finished":
|
|
741
|
+
status.phase = ExecutionPhase.EXECUTION_COMPLETED;
|
|
742
|
+
break;
|
|
743
|
+
case "error": {
|
|
744
|
+
const resultAny = result as unknown as Record<string, unknown>;
|
|
745
|
+
const sdkError = result.result
|
|
746
|
+
?? resultAny.error
|
|
747
|
+
?? resultAny.message
|
|
748
|
+
?? resultAny.reason;
|
|
749
|
+
const sdkErrorStr = sdkError ? String(sdkError) : undefined;
|
|
750
|
+
|
|
751
|
+
// The SDK frequently resolves run.wait() to a bare { status: "error" }
|
|
752
|
+
// while the real reason (e.g. the original grpc-status 12 routing
|
|
753
|
+
// failure) lives on the failing conversation turn. Capture it here so
|
|
754
|
+
// the classified error is actionable instead of "no detail from SDK".
|
|
755
|
+
const conversationErrorText = await introspectConversation(run, executionId);
|
|
756
|
+
|
|
757
|
+
const capturedRejection = getCapturedRejection(executionId);
|
|
758
|
+
if (capturedRejection) clearCapturedRejection(executionId);
|
|
759
|
+
|
|
760
|
+
const classified = synthesizeError({
|
|
761
|
+
sdkResultFields: sdkErrorStr,
|
|
762
|
+
streamErrorMessage,
|
|
763
|
+
capturedRejection,
|
|
764
|
+
conversationErrorText,
|
|
765
|
+
isResumedHandle: resolution.reason === "resumed_successfully",
|
|
766
|
+
fallbackContext: { model: validatedModel, mode: agentMode, agentId: resolution.agentId },
|
|
767
|
+
durationMs: (result as unknown as Record<string, unknown>).durationMs as number | undefined,
|
|
768
|
+
messageCount: status.messages.length,
|
|
769
|
+
});
|
|
770
|
+
|
|
771
|
+
console.error(
|
|
772
|
+
`ExecuteCursor agent error: execution=${executionId}, ` +
|
|
773
|
+
`classified=${JSON.stringify(classified)}, rawResult=${JSON.stringify(result)}`,
|
|
774
|
+
);
|
|
775
|
+
|
|
776
|
+
if (
|
|
777
|
+
shouldRetryWithFreshAgent(classified)
|
|
778
|
+
&& resolution.reason === "resumed_successfully"
|
|
779
|
+
&& !alreadyRetriedWithFreshAgent
|
|
780
|
+
) {
|
|
781
|
+
alreadyRetriedWithFreshAgent = true;
|
|
782
|
+
console.warn(
|
|
783
|
+
`ExecuteCursor poisoned-handle recovery: execution=${executionId}, ` +
|
|
784
|
+
`disposing agent ${resolution.agentId} and creating fresh agent`,
|
|
785
|
+
);
|
|
786
|
+
|
|
787
|
+
try { resolution.agent.close(); } catch { /* best effort */ }
|
|
788
|
+
|
|
789
|
+
const freshAgent = agentMode === "cloud"
|
|
790
|
+
? await createCloudAgent(createOptions as CreateCloudAgentOptions)
|
|
791
|
+
: await createAgent(createOptions as CreateAgentOptions);
|
|
792
|
+
|
|
793
|
+
const freshPrompt = buildPrompt({
|
|
794
|
+
resolution: {
|
|
795
|
+
...resolution,
|
|
796
|
+
agent: freshAgent,
|
|
797
|
+
agentId: freshAgent.agentId,
|
|
798
|
+
isNew: true,
|
|
799
|
+
resumed: false,
|
|
800
|
+
reason: "created_after_resume_failure",
|
|
801
|
+
resumeFailureDetail: `poisoned-handle recovery: ${classified.message}`,
|
|
802
|
+
},
|
|
803
|
+
approvalDecisions,
|
|
804
|
+
instructions: blueprint.instructions,
|
|
805
|
+
userMessage: spec.message,
|
|
806
|
+
skills: skillMetadata,
|
|
807
|
+
subAgents: blueprint.subAgents,
|
|
808
|
+
workspaceDirs: blueprint.workspaceDirs,
|
|
809
|
+
workspaceFileRefs: spec.workspaceFileRefs ?? [],
|
|
810
|
+
attachmentPaths,
|
|
811
|
+
pendingApprovals: adjudicatedApprovals,
|
|
812
|
+
interactionMode,
|
|
813
|
+
});
|
|
814
|
+
|
|
815
|
+
console.log(
|
|
816
|
+
`ExecuteCursor retry with fresh agent: execution=${executionId}, ` +
|
|
817
|
+
`newAgentId=${freshAgent.agentId}`,
|
|
818
|
+
);
|
|
819
|
+
|
|
820
|
+
try {
|
|
821
|
+
blueprint.sessionSpec.harnessStateId = freshAgent.agentId;
|
|
822
|
+
if (blueprint.session.metadata) blueprint.session.metadata.slug = "";
|
|
823
|
+
await client.updateSession(blueprint.session);
|
|
824
|
+
} catch (updateErr) {
|
|
825
|
+
console.warn("Failed to update session with fresh agentId (non-fatal):", updateErr);
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
const retryRun = await freshAgent.send(freshPrompt, {
|
|
829
|
+
onDelta: ({ update }) => {
|
|
830
|
+
if (update.type === "turn-ended" && update.usage) {
|
|
831
|
+
usageAccumulator.addTurn(update.usage);
|
|
832
|
+
}
|
|
833
|
+
deltaEnricher.processDelta(update);
|
|
834
|
+
try { heartbeat(); } catch { /* swallow during retry */ }
|
|
835
|
+
},
|
|
836
|
+
});
|
|
837
|
+
|
|
838
|
+
streamErrorMessage = undefined;
|
|
839
|
+
|
|
840
|
+
for await (const retryEvent of retryRun.stream()) {
|
|
841
|
+
if (Context.current().cancellationSignal.aborted) break;
|
|
842
|
+
accumulator.processEvent(retryEvent);
|
|
843
|
+
if (retryEvent.type === "status") {
|
|
844
|
+
const retryStatusEvent = retryEvent as { status?: string; message?: string };
|
|
845
|
+
if (retryStatusEvent.status === "ERROR" && retryStatusEvent.message) {
|
|
846
|
+
streamErrorMessage = retryStatusEvent.message;
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
heartbeat();
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
const retryResult = await retryRun.wait();
|
|
853
|
+
console.log(
|
|
854
|
+
`ExecuteCursor retry run.wait(): execution=${executionId}, ` +
|
|
855
|
+
`retryResult=${JSON.stringify(retryResult)}`,
|
|
856
|
+
);
|
|
857
|
+
|
|
858
|
+
if (retryResult.status === "finished") {
|
|
859
|
+
status.phase = ExecutionPhase.EXECUTION_COMPLETED;
|
|
860
|
+
console.log(
|
|
861
|
+
`ExecuteCursor poisoned-handle recovery SUCCEEDED: execution=${executionId}`,
|
|
862
|
+
);
|
|
863
|
+
break;
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
if (retryResult.status === "cancelled") {
|
|
867
|
+
status.phase = ExecutionPhase.EXECUTION_CANCELLED;
|
|
868
|
+
break;
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
const retryRejection = getCapturedRejection(executionId);
|
|
872
|
+
if (retryRejection) clearCapturedRejection(executionId);
|
|
873
|
+
|
|
874
|
+
const retryConversationErrorText = await introspectConversation(retryRun, executionId);
|
|
875
|
+
|
|
876
|
+
const retryClassified = synthesizeError({
|
|
877
|
+
sdkResultFields: retryResult.result ? String(retryResult.result) : undefined,
|
|
878
|
+
streamErrorMessage,
|
|
879
|
+
capturedRejection: retryRejection,
|
|
880
|
+
conversationErrorText: retryConversationErrorText,
|
|
881
|
+
isResumedHandle: false,
|
|
882
|
+
fallbackContext: { model: validatedModel, mode: agentMode, agentId: freshAgent.agentId },
|
|
883
|
+
});
|
|
884
|
+
|
|
885
|
+
status.phase = ExecutionPhase.EXECUTION_FAILED;
|
|
886
|
+
status.error = formatClassifiedError(retryClassified);
|
|
887
|
+
console.error(
|
|
888
|
+
`ExecuteCursor poisoned-handle recovery FAILED: execution=${executionId}, ` +
|
|
889
|
+
`retryError=${status.error}`,
|
|
890
|
+
);
|
|
891
|
+
break;
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
// Transport-timeout retry: fresh agent got 0 messages (degraded h2 session).
|
|
895
|
+
// Reset proxy sessions and try once with a new connection.
|
|
896
|
+
if (
|
|
897
|
+
classified.category === "network"
|
|
898
|
+
&& classified.retryable
|
|
899
|
+
&& resolution.reason !== "resumed_successfully"
|
|
900
|
+
&& !alreadyRetriedWithFreshAgent
|
|
901
|
+
) {
|
|
902
|
+
alreadyRetriedWithFreshAgent = true;
|
|
903
|
+
console.warn(
|
|
904
|
+
`ExecuteCursor transport-timeout recovery: execution=${executionId}, ` +
|
|
905
|
+
`resetting proxy sessions and retrying with fresh agent`,
|
|
906
|
+
);
|
|
907
|
+
|
|
908
|
+
try { resolution.agent.close(); } catch { /* best effort */ }
|
|
909
|
+
closeProxySessions();
|
|
910
|
+
|
|
911
|
+
const freshAgent = agentMode === "cloud"
|
|
912
|
+
? await createCloudAgent(createOptions as CreateCloudAgentOptions)
|
|
913
|
+
: await createAgent(createOptions as CreateAgentOptions);
|
|
914
|
+
|
|
915
|
+
try {
|
|
916
|
+
blueprint.sessionSpec.harnessStateId = freshAgent.agentId;
|
|
917
|
+
if (blueprint.session.metadata) blueprint.session.metadata.slug = "";
|
|
918
|
+
await client.updateSession(blueprint.session);
|
|
919
|
+
} catch (updateErr) {
|
|
920
|
+
console.warn("Failed to update session with fresh agentId (non-fatal):", updateErr);
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
const retryRun = await freshAgent.send(effectivePrompt, {
|
|
924
|
+
onDelta: ({ update }) => {
|
|
925
|
+
if (update.type === "turn-ended" && update.usage) {
|
|
926
|
+
usageAccumulator.addTurn(update.usage);
|
|
927
|
+
}
|
|
928
|
+
deltaEnricher.processDelta(update);
|
|
929
|
+
try { heartbeat(); } catch { /* swallow during retry */ }
|
|
930
|
+
},
|
|
931
|
+
});
|
|
932
|
+
|
|
933
|
+
streamErrorMessage = undefined;
|
|
934
|
+
|
|
935
|
+
for await (const retryEvent of retryRun.stream()) {
|
|
936
|
+
if (Context.current().cancellationSignal.aborted) break;
|
|
937
|
+
accumulator.processEvent(retryEvent);
|
|
938
|
+
if (retryEvent.type === "status") {
|
|
939
|
+
const retryStatusEvent = retryEvent as { status?: string; message?: string };
|
|
940
|
+
if (retryStatusEvent.status === "ERROR" && retryStatusEvent.message) {
|
|
941
|
+
streamErrorMessage = retryStatusEvent.message;
|
|
942
|
+
}
|
|
943
|
+
}
|
|
944
|
+
heartbeat();
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
const retryResult = await retryRun.wait();
|
|
948
|
+
if (retryResult.status === "finished") {
|
|
949
|
+
status.phase = ExecutionPhase.EXECUTION_COMPLETED;
|
|
950
|
+
resolution = { ...resolution, agent: freshAgent, agentId: freshAgent.agentId, isNew: true };
|
|
951
|
+
break;
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
status.phase = ExecutionPhase.EXECUTION_FAILED;
|
|
955
|
+
status.error = `Transport recovery failed: ${formatClassifiedError(classified)}`;
|
|
956
|
+
break;
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
status.phase = ExecutionPhase.EXECUTION_FAILED;
|
|
960
|
+
status.error = formatClassifiedError(classified);
|
|
961
|
+
break;
|
|
962
|
+
}
|
|
963
|
+
case "cancelled":
|
|
964
|
+
status.phase = ExecutionPhase.EXECUTION_CANCELLED;
|
|
965
|
+
break;
|
|
966
|
+
default:
|
|
967
|
+
status.phase = ExecutionPhase.EXECUTION_COMPLETED;
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
// Extract structured output BEFORE persisting, so the subscriber sees
|
|
971
|
+
// COMPLETED + structured_output atomically.
|
|
972
|
+
let structuredOutput: unknown = undefined;
|
|
973
|
+
let finalText: string | undefined;
|
|
974
|
+
|
|
975
|
+
if (status.phase === ExecutionPhase.EXECUTION_COMPLETED) {
|
|
976
|
+
const lastAiMsg = [...status.messages]
|
|
977
|
+
.reverse()
|
|
978
|
+
.find(m => m.type === MessageType.MESSAGE_AI);
|
|
979
|
+
finalText = lastAiMsg?.content;
|
|
980
|
+
|
|
981
|
+
if (structuredOutputSchema && finalText) {
|
|
982
|
+
const { extractJsonFromText } = await import("../../shared/extract-json.js");
|
|
983
|
+
|
|
984
|
+
// Tier 1 + 1.5: JSON.parse, code-fence extraction, heuristic brace match
|
|
985
|
+
structuredOutput = extractJsonFromText(finalText);
|
|
986
|
+
if (structuredOutput !== undefined) {
|
|
987
|
+
console.log(
|
|
988
|
+
`ExecuteCursor structured output extracted (text): execution=${executionId}, ` +
|
|
989
|
+
`finalTextLength=${finalText.length}`,
|
|
990
|
+
);
|
|
991
|
+
}
|
|
992
|
+
|
|
993
|
+
if (structuredOutput === undefined) {
|
|
994
|
+
// Tier 2: LLM extraction with withStructuredOutput — deterministic,
|
|
995
|
+
// uses function-calling to guarantee schema-conformant output
|
|
996
|
+
console.log(
|
|
997
|
+
`ExecuteCursor text extraction failed, trying LLM extraction: execution=${executionId}, ` +
|
|
998
|
+
`finalTextLength=${finalText.length}`,
|
|
999
|
+
);
|
|
1000
|
+
try {
|
|
1001
|
+
structuredOutput = await extractStructuredOutput(
|
|
1002
|
+
finalText, structuredOutputSchema, config, requestedModel,
|
|
1003
|
+
);
|
|
1004
|
+
if (structuredOutput !== undefined) {
|
|
1005
|
+
console.log(
|
|
1006
|
+
`ExecuteCursor structured output extracted (LLM): execution=${executionId}`,
|
|
1007
|
+
);
|
|
1008
|
+
}
|
|
1009
|
+
} catch (extractErr) {
|
|
1010
|
+
const errMsg = extractErr instanceof Error ? extractErr.message : String(extractErr);
|
|
1011
|
+
console.error(
|
|
1012
|
+
`ExecuteCursor structured output extraction FAILED: execution=${executionId}, ` +
|
|
1013
|
+
`requestedModel=${requestedModel}, ` +
|
|
1014
|
+
`finalTextLength=${finalText.length}, ` +
|
|
1015
|
+
`error=${errMsg}`,
|
|
1016
|
+
);
|
|
1017
|
+
}
|
|
1018
|
+
}
|
|
1019
|
+
}
|
|
1020
|
+
|
|
1021
|
+
if (structuredOutput !== undefined) {
|
|
1022
|
+
status.structuredOutput = structuredOutput as JsonObject;
|
|
1023
|
+
}
|
|
1024
|
+
|
|
1025
|
+
// Plan mode: publish the final plan message as a plan.md artifact. The
|
|
1026
|
+
// Cursor harness has no auto-publish pipeline, so this is the only
|
|
1027
|
+
// artifact path; build storage from the same config-driven factory the
|
|
1028
|
+
// native harness uses.
|
|
1029
|
+
if (interactionMode === InteractionMode.PLAN && finalText) {
|
|
1030
|
+
try {
|
|
1031
|
+
const artifactStorage = createArtifactStorage(loadArtifactStorageConfig(config));
|
|
1032
|
+
await publishPlanArtifact({ status, executionId, planText: finalText, artifactStorage });
|
|
1033
|
+
} catch (err) {
|
|
1034
|
+
console.warn(
|
|
1035
|
+
`ExecuteCursor plan artifact publish skipped (non-fatal): ` +
|
|
1036
|
+
`execution=${executionId}, error=${err}`,
|
|
1037
|
+
);
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
// NOW persist — subscriber sees COMPLETED + structured_output atomically
|
|
1043
|
+
await persistStatus(client, executionId, status);
|
|
1044
|
+
|
|
1045
|
+
console.log(
|
|
1046
|
+
`ExecuteCursor completed: execution=${executionId}, phase=${ExecutionPhase[status.phase]}, ` +
|
|
1047
|
+
`hasStructuredOutput=${structuredOutput !== undefined}` +
|
|
1048
|
+
(status.error ? `, error=${status.error}` : ""),
|
|
1049
|
+
);
|
|
1050
|
+
|
|
1051
|
+
// Release SDK executor lease to prevent cache buildup across workflow tasks
|
|
1052
|
+
try { resolution.agent.close(); } catch { /* best effort */ }
|
|
1053
|
+
|
|
1054
|
+
const slim = slimStatus(status) as Record<string, unknown>;
|
|
1055
|
+
if (finalText !== undefined) {
|
|
1056
|
+
slim.final_text = finalText;
|
|
1057
|
+
}
|
|
1058
|
+
if (structuredOutput !== undefined) {
|
|
1059
|
+
slim.structured = structuredOutput;
|
|
1060
|
+
}
|
|
1061
|
+
return slim;
|
|
1062
|
+
|
|
1063
|
+
} catch (err) {
|
|
1064
|
+
periodicHeartbeat?.stop();
|
|
1065
|
+
|
|
1066
|
+
if (err instanceof CancelledFailure) {
|
|
1067
|
+
// workerShutdownDetected means the runner-manager signaled shutdown
|
|
1068
|
+
// before the worker drained. This is infrastructure failure, not pause.
|
|
1069
|
+
if (workerShutdownDetected) {
|
|
1070
|
+
console.log(`ExecuteCursor cancelled (worker shutdown) for execution ${executionId}`);
|
|
1071
|
+
status.phase = ExecutionPhase.EXECUTION_FAILED;
|
|
1072
|
+
status.error = "Execution interrupted: runner worker was shut down. Retry or resume.";
|
|
1073
|
+
status.completedAt = utcTimestamp();
|
|
1074
|
+
status.messages.push(create(AgentMessageSchema, {
|
|
1075
|
+
type: MessageType.MESSAGE_SYSTEM,
|
|
1076
|
+
content: "Execution interrupted: the runner worker was shut down while the agent was still running. You can retry or resume.",
|
|
1077
|
+
timestamp: utcTimestamp(),
|
|
1078
|
+
}));
|
|
1079
|
+
} else if (pauseDetected) {
|
|
1080
|
+
console.log(`ExecuteCursor cancelled (pause) for execution ${executionId}`);
|
|
1081
|
+
status.phase = ExecutionPhase.EXECUTION_PAUSED;
|
|
1082
|
+
status.messages.push(create(AgentMessageSchema, {
|
|
1083
|
+
type: MessageType.MESSAGE_SYSTEM,
|
|
1084
|
+
content: "Execution paused by user. Use resume to continue.",
|
|
1085
|
+
timestamp: utcTimestamp(),
|
|
1086
|
+
}));
|
|
1087
|
+
} else {
|
|
1088
|
+
console.log(`ExecuteCursor cancelled (infrastructure) for execution ${executionId}`);
|
|
1089
|
+
status.phase = ExecutionPhase.EXECUTION_FAILED;
|
|
1090
|
+
status.error = "Execution interrupted: agent was unresponsive (heartbeat timeout). Retry or resume.";
|
|
1091
|
+
status.completedAt = utcTimestamp();
|
|
1092
|
+
status.messages.push(create(AgentMessageSchema, {
|
|
1093
|
+
type: MessageType.MESSAGE_SYSTEM,
|
|
1094
|
+
content: "Execution interrupted: the agent was unresponsive for too long. You can retry or resume.",
|
|
1095
|
+
timestamp: utcTimestamp(),
|
|
1096
|
+
}));
|
|
1097
|
+
}
|
|
1098
|
+
// The aborted Cursor run leaves no live sub-agent — mark any in-flight
|
|
1099
|
+
// delegation CANCELLED so the final snapshot has no zombie sub-agent.
|
|
1100
|
+
cancelInProgressSubAgentProtos(status.subAgentExecutions);
|
|
1101
|
+
await persistStatus(client, executionId, status).catch(() => {}); throw err;
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1104
|
+
// If a non-CancelledFailure error occurs while a pause is in progress,
|
|
1105
|
+
// treat the execution as paused rather than failed. The error was likely
|
|
1106
|
+
// caused by the cancellation (e.g. SDK stream teardown) and should not
|
|
1107
|
+
// overwrite the PAUSED state that the Pause RPC already set in the DB.
|
|
1108
|
+
if (pauseDetected) {
|
|
1109
|
+
const errDetail = err instanceof Error ? err.message : String(err);
|
|
1110
|
+
console.log(
|
|
1111
|
+
`ExecuteCursor error during pause (treating as pause): execution=${executionId}, error=${errDetail}`,
|
|
1112
|
+
);
|
|
1113
|
+
status.phase = ExecutionPhase.EXECUTION_PAUSED;
|
|
1114
|
+
status.messages.push(create(AgentMessageSchema, {
|
|
1115
|
+
type: MessageType.MESSAGE_SYSTEM,
|
|
1116
|
+
content: "Execution paused by user. Use resume to continue.",
|
|
1117
|
+
timestamp: utcTimestamp(),
|
|
1118
|
+
}));
|
|
1119
|
+
cancelInProgressSubAgentProtos(status.subAgentExecutions);
|
|
1120
|
+
await persistStatus(client, executionId, status).catch(() => {}); throw new CancelledFailure("Activity paused by orchestrator (error during pause)");
|
|
1121
|
+
}
|
|
1122
|
+
|
|
1123
|
+
// Infrastructure cancellation (e.g. heartbeat timeout) with a
|
|
1124
|
+
// non-CancelledFailure error — report as failed, not paused.
|
|
1125
|
+
if (Context.current().cancellationSignal.aborted) {
|
|
1126
|
+
const errDetail = err instanceof Error ? err.message : String(err);
|
|
1127
|
+
console.log(
|
|
1128
|
+
`ExecuteCursor error during infrastructure cancel: execution=${executionId}, error=${errDetail}`,
|
|
1129
|
+
);
|
|
1130
|
+
status.phase = ExecutionPhase.EXECUTION_FAILED;
|
|
1131
|
+
status.error = `Execution interrupted: ${errDetail}`;
|
|
1132
|
+
status.completedAt = utcTimestamp();
|
|
1133
|
+
status.messages.push(create(AgentMessageSchema, {
|
|
1134
|
+
type: MessageType.MESSAGE_SYSTEM,
|
|
1135
|
+
content: "Execution interrupted: the agent was unresponsive for too long. You can retry or resume.",
|
|
1136
|
+
timestamp: utcTimestamp(),
|
|
1137
|
+
}));
|
|
1138
|
+
cancelInProgressSubAgentProtos(status.subAgentExecutions);
|
|
1139
|
+
await persistStatus(client, executionId, status).catch(() => {}); throw new CancelledFailure("Activity cancelled (infrastructure, not user pause)");
|
|
1140
|
+
}
|
|
1141
|
+
|
|
1142
|
+
// A thrown CursorSdkError carries structured fields (code/status/endpoint/
|
|
1143
|
+
// requestId) that the generic format below would flatten to a bare message.
|
|
1144
|
+
// Route it through the same classifier as the run.wait() error path so the
|
|
1145
|
+
// failure category and full diagnostics are preserved.
|
|
1146
|
+
const { CursorSdkError } = await import("@cursor/sdk");
|
|
1147
|
+
if (err instanceof CursorSdkError) {
|
|
1148
|
+
const sdkErrorJson = err.toJSON();
|
|
1149
|
+
console.error(
|
|
1150
|
+
`ExecuteCursor SDK error: execution=${executionId}, sdkError=${JSON.stringify(sdkErrorJson)}`,
|
|
1151
|
+
);
|
|
1152
|
+
const classified = synthesizeError({
|
|
1153
|
+
sdkError: { code: err.code, status: err.status, message: err.message },
|
|
1154
|
+
sdkResultFields: undefined,
|
|
1155
|
+
streamErrorMessage: undefined,
|
|
1156
|
+
capturedRejection: getCapturedRejection(executionId),
|
|
1157
|
+
isResumedHandle: false,
|
|
1158
|
+
fallbackContext: errorContext,
|
|
1159
|
+
});
|
|
1160
|
+
clearCapturedRejection(executionId);
|
|
1161
|
+
status.phase = ExecutionPhase.EXECUTION_FAILED;
|
|
1162
|
+
status.error = formatClassifiedError(classified);
|
|
1163
|
+
status.completedAt = utcTimestamp();
|
|
1164
|
+
status.messages.push(
|
|
1165
|
+
create(AgentMessageSchema, {
|
|
1166
|
+
type: MessageType.MESSAGE_SYSTEM,
|
|
1167
|
+
content: "Internal system error occurred. Please contact support if this issue persists.",
|
|
1168
|
+
timestamp: utcTimestamp(),
|
|
1169
|
+
}),
|
|
1170
|
+
create(AgentMessageSchema, {
|
|
1171
|
+
type: MessageType.MESSAGE_SYSTEM,
|
|
1172
|
+
content: `Error details: ${status.error}`,
|
|
1173
|
+
timestamp: utcTimestamp(),
|
|
1174
|
+
}),
|
|
1175
|
+
);
|
|
1176
|
+
try {
|
|
1177
|
+
await persistStatus(client, executionId, status);
|
|
1178
|
+
} catch (persistErr) {
|
|
1179
|
+
console.error("Failed to persist error status (best-effort):", persistErr);
|
|
1180
|
+
} return slimStatus(status);
|
|
1181
|
+
}
|
|
1182
|
+
|
|
1183
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
1184
|
+
const errType = err instanceof Error ? err.constructor.name : "Unknown";
|
|
1185
|
+
console.error(`ExecuteCursor failed: execution=${executionId}, [${errType}] ${errMsg}`);
|
|
1186
|
+
|
|
1187
|
+
status.phase = ExecutionPhase.EXECUTION_FAILED;
|
|
1188
|
+
status.error = `Execution failed: [${errType}] ${errMsg}`;
|
|
1189
|
+
status.completedAt = utcTimestamp();
|
|
1190
|
+
status.messages.push(
|
|
1191
|
+
create(AgentMessageSchema, {
|
|
1192
|
+
type: MessageType.MESSAGE_SYSTEM,
|
|
1193
|
+
content: "Internal system error occurred. Please contact support if this issue persists.",
|
|
1194
|
+
timestamp: utcTimestamp(),
|
|
1195
|
+
}),
|
|
1196
|
+
create(AgentMessageSchema, {
|
|
1197
|
+
type: MessageType.MESSAGE_SYSTEM,
|
|
1198
|
+
content: `Error details: [${errType}] ${errMsg}`,
|
|
1199
|
+
timestamp: utcTimestamp(),
|
|
1200
|
+
}),
|
|
1201
|
+
);
|
|
1202
|
+
|
|
1203
|
+
try {
|
|
1204
|
+
await persistStatus(client, executionId, status);
|
|
1205
|
+
} catch (persistErr) {
|
|
1206
|
+
console.error("Failed to persist error status (best-effort):", persistErr);
|
|
1207
|
+
}
|
|
1208
|
+
|
|
1209
|
+
return slimStatus(status);
|
|
1210
|
+
}
|
|
1211
|
+
}
|
|
1212
|
+
|
|
1213
|
+
// ---------------------------------------------------------------------------
|
|
1214
|
+
// Structured Output Extraction (Cursor Harness Tier 2)
|
|
1215
|
+
// ---------------------------------------------------------------------------
|
|
1216
|
+
|
|
1217
|
+
/**
|
|
1218
|
+
* Extract structured data from an agent's free-text response using an
|
|
1219
|
+
* economy-tier LLM with withStructuredOutput (function-calling).
|
|
1220
|
+
* Guarantees schema-conformant JSON output via the API's tool-use mechanism.
|
|
1221
|
+
*
|
|
1222
|
+
* Provider-aware: resolves the economy model via the registry, infers its
|
|
1223
|
+
* provider (anthropic / openai), and constructs the correct LangChain client
|
|
1224
|
+
* with the matching proxy endpoint. Follows the same pattern as
|
|
1225
|
+
* call-llm.ts constructModel().
|
|
1226
|
+
*/
|
|
1227
|
+
async function extractStructuredOutput(
|
|
1228
|
+
agentResponse: string,
|
|
1229
|
+
schema: Record<string, unknown>,
|
|
1230
|
+
config: Config,
|
|
1231
|
+
primaryModel: string,
|
|
1232
|
+
): Promise<unknown | null> {
|
|
1233
|
+
const { ChatOpenAI } = await import("@langchain/openai");
|
|
1234
|
+
const { ChatAnthropic } = await import("@langchain/anthropic");
|
|
1235
|
+
const { inferProvider, resolveProxyBaseUrl, buildProxyHeaders } = await import("../../shared/llm-proxy.js");
|
|
1236
|
+
const { getEconomyModel } = await import("../../shared/model-registry.js");
|
|
1237
|
+
|
|
1238
|
+
const extractionModel = await getEconomyModel(primaryModel);
|
|
1239
|
+
const provider = inferProvider(extractionModel);
|
|
1240
|
+
|
|
1241
|
+
const proxyEndpoint = config.proxyEndpoint ?? config.stigmerBackendEndpoint;
|
|
1242
|
+
const baseUrl = resolveProxyBaseUrl(proxyEndpoint, provider);
|
|
1243
|
+
const headers = config.stigmerToken
|
|
1244
|
+
? buildProxyHeaders(config.stigmerToken, {})
|
|
1245
|
+
: {};
|
|
1246
|
+
|
|
1247
|
+
const apiKey = provider === "openai"
|
|
1248
|
+
? (config.stigmerToken ?? process.env.OPENAI_API_KEY ?? "proxy-managed")
|
|
1249
|
+
: (config.stigmerToken ?? process.env.ANTHROPIC_API_KEY ?? "proxy-managed");
|
|
1250
|
+
|
|
1251
|
+
const llm = provider === "openai"
|
|
1252
|
+
? new ChatOpenAI({
|
|
1253
|
+
model: extractionModel,
|
|
1254
|
+
apiKey,
|
|
1255
|
+
temperature: 0,
|
|
1256
|
+
maxTokens: 4096,
|
|
1257
|
+
configuration: { baseURL: baseUrl, defaultHeaders: headers },
|
|
1258
|
+
})
|
|
1259
|
+
: new ChatAnthropic({
|
|
1260
|
+
model: extractionModel,
|
|
1261
|
+
apiKey,
|
|
1262
|
+
temperature: 0,
|
|
1263
|
+
maxTokens: 4096,
|
|
1264
|
+
clientOptions: { baseURL: baseUrl, defaultHeaders: headers },
|
|
1265
|
+
});
|
|
1266
|
+
|
|
1267
|
+
const zodSchema = jsonSchemaToZod(schema);
|
|
1268
|
+
const structured = llm.withStructuredOutput(zodSchema);
|
|
1269
|
+
|
|
1270
|
+
const result = await structured.invoke([
|
|
1271
|
+
{ role: "system", content: "Extract the structured data from the agent's response. Return only the data that matches the schema." },
|
|
1272
|
+
{ role: "user", content: agentResponse },
|
|
1273
|
+
]);
|
|
1274
|
+
|
|
1275
|
+
return result ?? null;
|
|
1276
|
+
}
|
|
1277
|
+
|
|
1278
|
+
// Re-export for use within this module; shared implementation eliminates
|
|
1279
|
+
// the three duplicate converters that previously drifted independently.
|
|
1280
|
+
import { jsonSchemaToZod } from "../../shared/json-schema-to-zod.js";
|
|
1281
|
+
|
|
1282
|
+
// ---------------------------------------------------------------------------
|
|
1283
|
+
// Prompt selection
|
|
1284
|
+
// ---------------------------------------------------------------------------
|
|
1285
|
+
|
|
1286
|
+
export interface BuildPromptInput {
|
|
1287
|
+
resolution: AgentResolution;
|
|
1288
|
+
approvalDecisions: Map<string, ApprovalAction> | undefined;
|
|
1289
|
+
instructions: string;
|
|
1290
|
+
userMessage: string;
|
|
1291
|
+
skills: import("./prompt-builder.js").SkillMetadata[];
|
|
1292
|
+
subAgents: import("@stigmer/protos/ai/stigmer/agentic/agent/v1/spec_pb").SubAgent[];
|
|
1293
|
+
workspaceDirs: string[];
|
|
1294
|
+
workspaceFileRefs: string[];
|
|
1295
|
+
attachmentPaths: string[];
|
|
1296
|
+
pendingApprovals: import("@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/approval_pb").PendingApproval[];
|
|
1297
|
+
interactionMode?: InteractionMode;
|
|
1298
|
+
}
|
|
1299
|
+
|
|
1300
|
+
/**
|
|
1301
|
+
* Select and build the appropriate prompt based on resolution reason and
|
|
1302
|
+
* HITL state.
|
|
1303
|
+
*
|
|
1304
|
+
* Conversation continuation is carried entirely by the Cursor SDK's native
|
|
1305
|
+
* agent state (the local SQLite store persisted on the durable workspace
|
|
1306
|
+
* volume, or cloud server-side state) — there is no separate continuation
|
|
1307
|
+
* store. The prompt therefore depends only on how the agent was resolved:
|
|
1308
|
+
*
|
|
1309
|
+
* 1. HITL reinvocation -> buildReinvocationPrompt (approval decisions;
|
|
1310
|
+
* the resumed agent's native context carries
|
|
1311
|
+
* the prior conversation)
|
|
1312
|
+
* 2. resumed_successfully -> raw userMessage (native context carries it)
|
|
1313
|
+
* 3. first execution / fresh -> buildEnhancedPrompt (full instructions +
|
|
1314
|
+
* agent after resume failure skills; no prior conversation to inherit)
|
|
1315
|
+
*/
|
|
1316
|
+
export function buildPrompt(input: BuildPromptInput): string {
|
|
1317
|
+
const {
|
|
1318
|
+
resolution,
|
|
1319
|
+
approvalDecisions,
|
|
1320
|
+
instructions,
|
|
1321
|
+
userMessage,
|
|
1322
|
+
skills,
|
|
1323
|
+
subAgents,
|
|
1324
|
+
workspaceDirs,
|
|
1325
|
+
workspaceFileRefs,
|
|
1326
|
+
attachmentPaths,
|
|
1327
|
+
interactionMode,
|
|
1328
|
+
} = input;
|
|
1329
|
+
|
|
1330
|
+
const isHitlReinvocation = approvalDecisions !== undefined && approvalDecisions.size > 0;
|
|
1331
|
+
|
|
1332
|
+
// HITL reinvocation: the agent is resumed, so its native context carries the
|
|
1333
|
+
// prior conversation; the reinvocation prompt conveys the approval decisions.
|
|
1334
|
+
if (isHitlReinvocation) {
|
|
1335
|
+
return buildReinvocationPrompt(input.pendingApprovals, approvalDecisions);
|
|
1336
|
+
}
|
|
1337
|
+
|
|
1338
|
+
// A successfully resumed agent carries its own conversation context via the
|
|
1339
|
+
// SDK's native store — send the raw user message with no preamble.
|
|
1340
|
+
if (resolution.reason === "resumed_successfully") {
|
|
1341
|
+
return userMessage;
|
|
1342
|
+
}
|
|
1343
|
+
|
|
1344
|
+
// First execution, or a fresh agent created after a resume failure: there is
|
|
1345
|
+
// no prior conversation to inherit, so start a new turn with full context.
|
|
1346
|
+
return buildEnhancedPrompt({
|
|
1347
|
+
instructions,
|
|
1348
|
+
userMessage,
|
|
1349
|
+
skills,
|
|
1350
|
+
subAgents,
|
|
1351
|
+
workspaceDirs,
|
|
1352
|
+
workspaceFileRefs,
|
|
1353
|
+
attachmentPaths,
|
|
1354
|
+
interactionMode,
|
|
1355
|
+
});
|
|
1356
|
+
}
|
|
1357
|
+
|
|
1358
|
+
// ---------------------------------------------------------------------------
|
|
1359
|
+
// Helpers
|
|
1360
|
+
// ---------------------------------------------------------------------------
|
|
1361
|
+
|
|
1362
|
+
/**
|
|
1363
|
+
* Best-effort: read the failing run's conversation to recover the real error
|
|
1364
|
+
* reason the SDK swallowed in run.wait(). Logs the (bounded) raw turns for deep
|
|
1365
|
+
* diagnostics and returns a concise error string for the classifier.
|
|
1366
|
+
*
|
|
1367
|
+
* Strictly non-fatal — any failure (unsupported operation, transport error)
|
|
1368
|
+
* returns undefined and never propagates into the execution's error path.
|
|
1369
|
+
*/
|
|
1370
|
+
async function introspectConversation(
|
|
1371
|
+
run: Run,
|
|
1372
|
+
executionId: string,
|
|
1373
|
+
): Promise<string | undefined> {
|
|
1374
|
+
try {
|
|
1375
|
+
if (!run.supports("conversation")) {
|
|
1376
|
+
console.log(
|
|
1377
|
+
`ExecuteCursor conversation introspection unsupported: execution=${executionId}, ` +
|
|
1378
|
+
`reason=${run.unsupportedReason("conversation") ?? "n/a"}`,
|
|
1379
|
+
);
|
|
1380
|
+
return undefined;
|
|
1381
|
+
}
|
|
1382
|
+
const turns = await run.conversation();
|
|
1383
|
+
const raw = JSON.stringify(turns);
|
|
1384
|
+
const bounded = raw.length > 8000 ? `${raw.slice(0, 8000)}…(truncated ${raw.length} chars)` : raw;
|
|
1385
|
+
console.error(
|
|
1386
|
+
`ExecuteCursor conversation introspection: execution=${executionId}, ` +
|
|
1387
|
+
`turns=${turns.length}, raw=${bounded}`,
|
|
1388
|
+
);
|
|
1389
|
+
return extractConversationErrorText(turns);
|
|
1390
|
+
} catch (introspectErr) {
|
|
1391
|
+
console.warn(
|
|
1392
|
+
`ExecuteCursor conversation introspection failed (non-fatal): execution=${executionId}, ` +
|
|
1393
|
+
`error=${introspectErr instanceof Error ? introspectErr.message : String(introspectErr)}`,
|
|
1394
|
+
);
|
|
1395
|
+
return undefined;
|
|
1396
|
+
}
|
|
1397
|
+
}
|
|
1398
|
+
|
|
1399
|
+
/**
|
|
1400
|
+
* Walk the last conversation turn and collect human-meaningful error text
|
|
1401
|
+
* (error-status payloads and `text`/`message`/`reason` strings). Schema-agnostic
|
|
1402
|
+
* by design so it tolerates SDK conversation-shape changes. Returns undefined
|
|
1403
|
+
* when nothing useful is found.
|
|
1404
|
+
*/
|
|
1405
|
+
function extractConversationErrorText(turns: ConversationTurn[]): string | undefined {
|
|
1406
|
+
if (!turns || turns.length === 0) return undefined;
|
|
1407
|
+
const collected: string[] = [];
|
|
1408
|
+
|
|
1409
|
+
const visit = (node: unknown, depth: number): void => {
|
|
1410
|
+
if (node == null || depth > 6 || typeof node !== "object") return;
|
|
1411
|
+
if (Array.isArray(node)) {
|
|
1412
|
+
for (const item of node) visit(item, depth + 1);
|
|
1413
|
+
return;
|
|
1414
|
+
}
|
|
1415
|
+
const obj = node as Record<string, unknown>;
|
|
1416
|
+
if (obj.status === "error" && obj.error != null) {
|
|
1417
|
+
collected.push(
|
|
1418
|
+
typeof obj.error === "string" ? obj.error : JSON.stringify(obj.error),
|
|
1419
|
+
);
|
|
1420
|
+
}
|
|
1421
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
1422
|
+
if (
|
|
1423
|
+
(key === "text" || key === "message" || key === "reason")
|
|
1424
|
+
&& typeof value === "string"
|
|
1425
|
+
&& value.trim().length > 0
|
|
1426
|
+
) {
|
|
1427
|
+
collected.push(value.trim());
|
|
1428
|
+
} else if (typeof value === "object" && value != null) {
|
|
1429
|
+
visit(value, depth + 1);
|
|
1430
|
+
}
|
|
1431
|
+
}
|
|
1432
|
+
};
|
|
1433
|
+
|
|
1434
|
+
visit(turns[turns.length - 1], 0);
|
|
1435
|
+
if (collected.length === 0) return undefined;
|
|
1436
|
+
|
|
1437
|
+
const joined = [...new Set(collected)].join(" | ");
|
|
1438
|
+
return joined.length > 600 ? `${joined.slice(0, 600)}…` : joined;
|
|
1439
|
+
}
|