@stigmer/runner 3.10.0 → 3.11.1-dev.20260812192248
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 +14 -1
- package/dist/.build-fingerprint +1 -1
- package/dist/activities/call-llm.js +9 -10
- package/dist/activities/call-llm.js.map +1 -1
- package/dist/activities/classify-tool-approvals.d.ts +2 -1
- package/dist/activities/classify-tool-approvals.js +28 -2
- package/dist/activities/classify-tool-approvals.js.map +1 -1
- package/dist/activities/discover-mcp-server.d.ts +39 -0
- package/dist/activities/discover-mcp-server.js +165 -28
- package/dist/activities/discover-mcp-server.js.map +1 -1
- package/dist/activities/emit-event.d.ts +14 -2
- package/dist/activities/emit-event.js +52 -17
- package/dist/activities/emit-event.js.map +1 -1
- package/dist/activities/execute-cursor/__test-utils__/cursor-hook-harness.d.ts +8 -0
- package/dist/activities/execute-cursor/__test-utils__/cursor-hook-harness.js +1 -1
- package/dist/activities/execute-cursor/__test-utils__/cursor-hook-harness.js.map +1 -1
- package/dist/activities/execute-cursor/approval-state.d.ts +28 -2
- package/dist/activities/execute-cursor/approval-state.js +7 -1
- package/dist/activities/execute-cursor/approval-state.js.map +1 -1
- package/dist/activities/execute-cursor/attachment-resolver.d.ts +14 -0
- package/dist/activities/execute-cursor/attachment-resolver.js +18 -4
- package/dist/activities/execute-cursor/attachment-resolver.js.map +1 -1
- package/dist/activities/execute-cursor/blueprint-resolver.d.ts +1 -9
- package/dist/activities/execute-cursor/blueprint-resolver.js +6 -22
- package/dist/activities/execute-cursor/blueprint-resolver.js.map +1 -1
- package/dist/activities/execute-cursor/env-resolver.js +3 -1
- package/dist/activities/execute-cursor/env-resolver.js.map +1 -1
- package/dist/activities/execute-cursor/error-classifier.d.ts +59 -3
- package/dist/activities/execute-cursor/error-classifier.js +115 -6
- package/dist/activities/execute-cursor/error-classifier.js.map +1 -1
- package/dist/activities/execute-cursor/extract-structured-output.d.ts +29 -0
- package/dist/activities/execute-cursor/extract-structured-output.js +58 -0
- package/dist/activities/execute-cursor/extract-structured-output.js.map +1 -0
- package/dist/activities/execute-cursor/hook-script.d.ts +14 -3
- package/dist/activities/execute-cursor/hook-script.js +72 -10
- package/dist/activities/execute-cursor/hook-script.js.map +1 -1
- package/dist/activities/execute-cursor/index.d.ts +51 -11
- package/dist/activities/execute-cursor/index.js +177 -93
- package/dist/activities/execute-cursor/index.js.map +1 -1
- package/dist/activities/execute-cursor/mcp-resolver.d.ts +24 -1
- package/dist/activities/execute-cursor/mcp-resolver.js +5 -2
- package/dist/activities/execute-cursor/mcp-resolver.js.map +1 -1
- package/dist/activities/execute-cursor/model-pricing-data.d.ts +2 -0
- package/dist/activities/execute-cursor/model-pricing-data.js +13 -3
- package/dist/activities/execute-cursor/model-pricing-data.js.map +1 -1
- package/dist/activities/execute-cursor/prompt-builder.d.ts +51 -4
- package/dist/activities/execute-cursor/prompt-builder.js +49 -7
- package/dist/activities/execute-cursor/prompt-builder.js.map +1 -1
- package/dist/activities/execute-cursor/turn-recovery.d.ts +52 -0
- package/dist/activities/execute-cursor/turn-recovery.js +193 -0
- package/dist/activities/execute-cursor/turn-recovery.js.map +1 -0
- package/dist/activities/execute-cursor/turn-stream.js +4 -1
- package/dist/activities/execute-cursor/turn-stream.js.map +1 -1
- package/dist/activities/execute-deep-agent/attachment-injector.d.ts +18 -1
- package/dist/activities/execute-deep-agent/attachment-injector.js +68 -23
- package/dist/activities/execute-deep-agent/attachment-injector.js.map +1 -1
- package/dist/activities/execute-deep-agent/environment.js +3 -1
- package/dist/activities/execute-deep-agent/environment.js.map +1 -1
- package/dist/activities/execute-deep-agent/index.js +15 -0
- package/dist/activities/execute-deep-agent/index.js.map +1 -1
- package/dist/activities/execute-deep-agent/prompt-builder.d.ts +7 -7
- package/dist/activities/execute-deep-agent/prompt-builder.js +8 -2
- package/dist/activities/execute-deep-agent/prompt-builder.js.map +1 -1
- package/dist/activities/execute-deep-agent/setup.d.ts +10 -0
- package/dist/activities/execute-deep-agent/setup.js +65 -24
- package/dist/activities/execute-deep-agent/setup.js.map +1 -1
- package/dist/activities/execute-deep-agent/shell-env.d.ts +5 -1
- package/dist/activities/execute-deep-agent/shell-env.js +7 -9
- package/dist/activities/execute-deep-agent/shell-env.js.map +1 -1
- package/dist/activities/execute-deep-agent/subagent-transformer.d.ts +18 -1
- package/dist/activities/execute-deep-agent/subagent-transformer.js +15 -2
- package/dist/activities/execute-deep-agent/subagent-transformer.js.map +1 -1
- package/dist/activities/execute-deep-agent/subagent-wiring.d.ts +27 -6
- package/dist/activities/execute-deep-agent/subagent-wiring.js +26 -5
- package/dist/activities/execute-deep-agent/subagent-wiring.js.map +1 -1
- package/dist/activities/hydrate-workflow-execution.js +8 -3
- package/dist/activities/hydrate-workflow-execution.js.map +1 -1
- package/dist/activities/run-command.d.ts +5 -2
- package/dist/activities/run-command.js +22 -10
- package/dist/activities/run-command.js.map +1 -1
- package/dist/activities/run-env.d.ts +40 -0
- package/dist/activities/run-env.js +66 -0
- package/dist/activities/run-env.js.map +1 -0
- package/dist/activities/workflow-event-activities.d.ts +28 -10
- package/dist/activities/workflow-event-activities.js +87 -58
- package/dist/activities/workflow-event-activities.js.map +1 -1
- package/dist/bootstrap.js +5 -0
- package/dist/bootstrap.js.map +1 -1
- package/dist/claimcheck/payload-codec.js +21 -1
- package/dist/claimcheck/payload-codec.js.map +1 -1
- package/dist/client/stigmer-client.d.ts +83 -21
- package/dist/client/stigmer-client.js +106 -29
- package/dist/client/stigmer-client.js.map +1 -1
- package/dist/encryption/config.d.ts +64 -0
- package/dist/encryption/config.js +108 -0
- package/dist/encryption/config.js.map +1 -0
- package/dist/encryption/index.d.ts +3 -0
- package/dist/encryption/index.js +3 -0
- package/dist/encryption/index.js.map +1 -0
- package/dist/encryption/payload-codec.d.ts +41 -0
- package/dist/encryption/payload-codec.js +130 -0
- package/dist/encryption/payload-codec.js.map +1 -0
- package/dist/middleware/index.d.ts +3 -0
- package/dist/middleware/index.js +7 -0
- package/dist/middleware/index.js.map +1 -1
- package/dist/middleware/path-normalization.d.ts +57 -0
- package/dist/middleware/path-normalization.js +109 -0
- package/dist/middleware/path-normalization.js.map +1 -0
- package/dist/middleware/types.d.ts +8 -0
- package/dist/payload-codecs.d.ts +17 -0
- package/dist/payload-codecs.js +42 -0
- package/dist/payload-codecs.js.map +1 -0
- package/dist/preflight.d.ts +31 -0
- package/dist/preflight.js +43 -0
- package/dist/preflight.js.map +1 -1
- package/dist/runner-manager.js +21 -17
- package/dist/runner-manager.js.map +1 -1
- package/dist/runner.js +11 -18
- package/dist/runner.js.map +1 -1
- package/dist/shared/approval-policy.d.ts +9 -3
- package/dist/shared/approval-policy.js +15 -6
- package/dist/shared/approval-policy.js.map +1 -1
- package/dist/shared/artifact-storage.d.ts +23 -1
- package/dist/shared/artifact-storage.js +51 -10
- package/dist/shared/artifact-storage.js.map +1 -1
- package/dist/shared/attachment-naming.d.ts +53 -0
- package/dist/shared/attachment-naming.js +59 -0
- package/dist/shared/attachment-naming.js.map +1 -0
- package/dist/shared/caller-identity.d.ts +23 -2
- package/dist/shared/caller-identity.js +36 -5
- package/dist/shared/caller-identity.js.map +1 -1
- package/dist/shared/channel-attachment.js +1 -0
- package/dist/shared/channel-attachment.js.map +1 -1
- package/dist/shared/checkpointer/http-saver.d.ts +26 -1
- package/dist/shared/checkpointer/http-saver.js +54 -8
- package/dist/shared/checkpointer/http-saver.js.map +1 -1
- package/dist/shared/conversation-attachment.js +1 -0
- package/dist/shared/conversation-attachment.js.map +1 -1
- package/dist/shared/conversation-catchup.d.ts +9 -2
- package/dist/shared/conversation-catchup.js +39 -6
- package/dist/shared/conversation-catchup.js.map +1 -1
- package/dist/shared/datastore-attachment.d.ts +50 -7
- package/dist/shared/datastore-attachment.js +93 -11
- package/dist/shared/datastore-attachment.js.map +1 -1
- package/dist/shared/grpc-retry.d.ts +5 -1
- package/dist/shared/grpc-retry.js +5 -1
- package/dist/shared/grpc-retry.js.map +1 -1
- package/dist/shared/http-retry.d.ts +85 -0
- package/dist/shared/http-retry.js +101 -0
- package/dist/shared/http-retry.js.map +1 -0
- package/dist/shared/llm-backend.d.ts +275 -0
- package/dist/shared/llm-backend.js +425 -0
- package/dist/shared/llm-backend.js.map +1 -0
- package/dist/shared/llm-proxy.d.ts +8 -0
- package/dist/shared/llm-proxy.js +15 -0
- package/dist/shared/llm-proxy.js.map +1 -1
- package/dist/shared/mcp-enabled-tools.d.ts +57 -0
- package/dist/shared/mcp-enabled-tools.js +86 -0
- package/dist/shared/mcp-enabled-tools.js.map +1 -0
- package/dist/shared/mcp-manager.d.ts +11 -5
- package/dist/shared/mcp-manager.js +47 -8
- package/dist/shared/mcp-manager.js.map +1 -1
- package/dist/shared/mcp-resolver.d.ts +39 -2
- package/dist/shared/mcp-resolver.js +38 -2
- package/dist/shared/mcp-resolver.js.map +1 -1
- package/dist/shared/mcp-schema-sanitizer.d.ts +70 -0
- package/dist/shared/mcp-schema-sanitizer.js +197 -0
- package/dist/shared/mcp-schema-sanitizer.js.map +1 -0
- package/dist/shared/model-client.d.ts +18 -5
- package/dist/shared/model-client.js +149 -18
- package/dist/shared/model-client.js.map +1 -1
- package/dist/shared/model-error.js +198 -5
- package/dist/shared/model-error.js.map +1 -1
- package/dist/shared/model-pricing-data.d.ts +2 -0
- package/dist/shared/model-pricing-data.js +13 -3
- package/dist/shared/model-pricing-data.js.map +1 -1
- package/dist/shared/model-registry.js +3 -2
- package/dist/shared/model-registry.js.map +1 -1
- package/dist/shared/plan-mode-permissions.d.ts +33 -0
- package/dist/shared/plan-mode-permissions.js +35 -0
- package/dist/shared/plan-mode-permissions.js.map +1 -0
- package/dist/shared/registry-endpoint.d.ts +20 -0
- package/dist/shared/registry-endpoint.js +25 -0
- package/dist/shared/registry-endpoint.js.map +1 -1
- package/dist/shared/runner-credential-keys.d.ts +24 -0
- package/dist/shared/runner-credential-keys.js +47 -0
- package/dist/shared/runner-credential-keys.js.map +1 -0
- package/dist/worker.d.ts +2 -1
- package/dist/worker.js +2 -4
- package/dist/worker.js.map +1 -1
- package/dist/workflow-engine/resolve.d.ts +19 -1
- package/dist/workflow-engine/resolve.js +37 -2
- package/dist/workflow-engine/resolve.js.map +1 -1
- package/dist/workflow-engine/types.d.ts +18 -0
- package/dist/workflow-engine/types.js.map +1 -1
- package/dist/workflows/call-agent-orchestrator.d.ts +9 -0
- package/dist/workflows/call-agent-orchestrator.js +1 -0
- package/dist/workflows/call-agent-orchestrator.js.map +1 -1
- package/dist/workflows/connect-mcp-server.js +9 -0
- package/dist/workflows/connect-mcp-server.js.map +1 -1
- package/dist/workflows/engine-core.js +23 -2
- package/dist/workflows/engine-core.js.map +1 -1
- package/dist/workflows/execute-from-execution.d.ts +1 -1
- package/dist/workflows/execute-from-execution.js +11 -1
- package/dist/workflows/execute-from-execution.js.map +1 -1
- package/dist/workflows/types.d.ts +8 -0
- package/package.json +9 -4
- package/src/__test-utils__/__tests__/vitest-global-setup.test.ts +37 -0
- package/src/__test-utils__/vitest-global-setup.ts +50 -0
- package/src/__tests__/bootstrap.test.ts +43 -0
- package/src/__tests__/claimcheck-codec.test.ts +36 -0
- package/src/__tests__/encryption-codec.test.ts +287 -0
- package/src/__tests__/fixtures/encrypted-payload-fixture.json +15 -0
- package/src/__tests__/history-encryption-e2e.test.ts +243 -0
- package/src/__tests__/preflight.test.ts +65 -2
- package/src/activities/__tests__/call-llm.test.ts +75 -0
- package/src/activities/__tests__/classify-tool-approvals.test.ts +117 -1
- package/src/activities/__tests__/discover-mcp-server.hang.test.ts +103 -0
- package/src/activities/__tests__/discover-mcp-server.test.ts +242 -1
- package/src/activities/__tests__/error-classifier.test.ts +94 -2
- package/src/activities/__tests__/run-command.test.ts +221 -0
- package/src/activities/__tests__/workflow-event-activities.test.ts +107 -8
- package/src/activities/call-llm.ts +9 -16
- package/src/activities/classify-tool-approvals.ts +34 -4
- package/src/activities/discover-mcp-server.ts +203 -31
- package/src/activities/emit-event.ts +65 -21
- package/src/activities/execute-cursor/__test-utils__/cursor-hook-harness.ts +9 -0
- package/src/activities/execute-cursor/__tests__/approval-gate.test.ts +14 -0
- package/src/activities/execute-cursor/__tests__/attachment-resolver.test.ts +53 -0
- package/src/activities/execute-cursor/__tests__/build-prompt.test.ts +151 -16
- package/src/activities/execute-cursor/__tests__/error-classifier-extraction.test.ts +208 -0
- package/src/activities/execute-cursor/__tests__/extract-structured-output.test.ts +120 -0
- package/src/activities/execute-cursor/__tests__/hook-script.test.ts +93 -0
- package/src/activities/execute-cursor/__tests__/mcp-resolver.test.ts +125 -0
- package/src/activities/execute-cursor/__tests__/model-pricing.test.ts +62 -1
- package/src/activities/execute-cursor/__tests__/prompt-builder-delegation.test.ts +1 -1
- package/src/activities/execute-cursor/__tests__/turn-recovery.test.ts +160 -0
- package/src/activities/execute-cursor/__tests__/turn-stream.test.ts +13 -0
- package/src/activities/execute-cursor/approval-state.ts +30 -1
- package/src/activities/execute-cursor/attachment-resolver.ts +31 -3
- package/src/activities/execute-cursor/blueprint-resolver.ts +7 -27
- package/src/activities/execute-cursor/env-resolver.ts +3 -1
- package/src/activities/execute-cursor/error-classifier.ts +131 -7
- package/src/activities/execute-cursor/extract-structured-output.ts +72 -0
- package/src/activities/execute-cursor/hook-script.ts +74 -10
- package/src/activities/execute-cursor/index.ts +209 -109
- package/src/activities/execute-cursor/mcp-resolver.ts +36 -2
- package/src/activities/execute-cursor/model-pricing-data.ts +22 -3
- package/src/activities/execute-cursor/prompt-builder.ts +85 -9
- package/src/activities/execute-cursor/turn-recovery.ts +208 -0
- package/src/activities/execute-cursor/turn-stream.ts +5 -2
- package/src/activities/execute-deep-agent/__tests__/attachment-injector.test.ts +110 -8
- package/src/activities/execute-deep-agent/__tests__/datastore-degradation.test.ts +104 -0
- package/src/activities/execute-deep-agent/__tests__/hitl-reject.test.ts +2 -0
- package/src/activities/execute-deep-agent/__tests__/hitl-resume-approve-all.test.ts +1 -0
- package/src/activities/execute-deep-agent/__tests__/hitl-resume-history.test.ts +1 -0
- package/src/activities/execute-deep-agent/__tests__/plan-mode-path-normalization.test.ts +174 -0
- package/src/activities/execute-deep-agent/__tests__/prompt-builder.test.ts +34 -5
- package/src/activities/execute-deep-agent/__tests__/sequential-gate-resume.test.ts +1 -0
- package/src/activities/execute-deep-agent/__tests__/shell-env.test.ts +24 -10
- package/src/activities/execute-deep-agent/__tests__/subagent-plan-mode-permissions.test.ts +178 -0
- package/src/activities/execute-deep-agent/__tests__/subagent-wiring.test.ts +12 -7
- package/src/activities/execute-deep-agent/attachment-injector.ts +94 -30
- package/src/activities/execute-deep-agent/environment.ts +3 -1
- package/src/activities/execute-deep-agent/index.ts +20 -0
- package/src/activities/execute-deep-agent/prompt-builder.ts +20 -10
- package/src/activities/execute-deep-agent/setup.ts +85 -29
- package/src/activities/execute-deep-agent/shell-env.ts +8 -9
- package/src/activities/execute-deep-agent/subagent-transformer.ts +30 -2
- package/src/activities/execute-deep-agent/subagent-wiring.ts +39 -6
- package/src/activities/hydrate-workflow-execution.ts +8 -3
- package/src/activities/run-command.ts +25 -12
- package/src/activities/run-env.ts +79 -0
- package/src/activities/workflow-event-activities.ts +96 -69
- package/src/bootstrap.ts +5 -0
- package/src/claimcheck/payload-codec.ts +33 -1
- package/src/client/__tests__/stigmer-client.test.ts +110 -11
- package/src/client/stigmer-client.ts +150 -37
- package/src/encryption/config.ts +155 -0
- package/src/encryption/index.ts +3 -0
- package/src/encryption/payload-codec.ts +152 -0
- package/src/middleware/__tests__/path-normalization.test.ts +140 -0
- package/src/middleware/index.ts +8 -0
- package/src/middleware/path-normalization.ts +125 -0
- package/src/middleware/types.ts +11 -0
- package/src/payload-codecs.ts +62 -0
- package/src/preflight.ts +45 -0
- package/src/runner-manager.ts +26 -26
- package/src/runner.ts +12 -27
- package/src/shared/__tests__/approval-policy.test.ts +82 -39
- package/src/shared/__tests__/artifact-storage.test.ts +145 -2
- package/src/shared/__tests__/attachment-naming.test.ts +159 -0
- package/src/shared/__tests__/bedrock-adapter.test.ts +213 -0
- package/src/shared/__tests__/bedrock-seam.test.ts +390 -0
- package/src/shared/__tests__/caller-identity.test.ts +25 -0
- package/src/shared/__tests__/channel-attachment.test.ts +1 -1
- package/src/shared/__tests__/connect-backfill.test.ts +1 -0
- package/src/shared/__tests__/conversation-attachment.test.ts +1 -1
- package/src/shared/__tests__/conversation-catchup.test.ts +24 -0
- package/src/shared/__tests__/datastore-attachment.test.ts +129 -1
- package/src/shared/__tests__/foundry-adapter.test.ts +276 -0
- package/src/shared/__tests__/foundry-seam.test.ts +482 -0
- package/src/shared/__tests__/http-retry.test.ts +68 -0
- package/src/shared/__tests__/llm-backend.test.ts +616 -0
- package/src/shared/__tests__/mcp-enabled-tools.test.ts +86 -0
- package/src/shared/__tests__/mcp-manager.test.ts +137 -15
- package/src/shared/__tests__/mcp-resolver.test.ts +146 -3
- package/src/shared/__tests__/mcp-schema-sanitizer.test.ts +267 -0
- package/src/shared/__tests__/model-client.test.ts +200 -0
- package/src/shared/__tests__/model-error.test.ts +289 -1
- package/src/shared/__tests__/model-pricing.test.ts +62 -2
- package/src/shared/__tests__/model-registry.test.ts +22 -0
- package/src/shared/__tests__/synthesized-attachment.test.ts +1 -0
- package/src/shared/__tests__/vertex-adapter.test.ts +169 -0
- package/src/shared/__tests__/vertex-seam.test.ts +295 -0
- package/src/shared/approval-policy.ts +14 -7
- package/src/shared/artifact-storage.ts +75 -10
- package/src/shared/attachment-naming.ts +78 -0
- package/src/shared/caller-identity.ts +40 -5
- package/src/shared/channel-attachment.ts +1 -0
- package/src/shared/checkpointer/__tests__/http-saver.test.ts +196 -1
- package/src/shared/checkpointer/http-saver.ts +71 -8
- package/src/shared/conversation-attachment.ts +1 -0
- package/src/shared/conversation-catchup.ts +39 -6
- package/src/shared/datastore-attachment.ts +106 -11
- package/src/shared/grpc-retry.ts +5 -1
- package/src/shared/http-retry.ts +139 -0
- package/src/shared/llm-backend.ts +544 -0
- package/src/shared/llm-proxy.ts +15 -0
- package/src/shared/mcp-enabled-tools.ts +105 -0
- package/src/shared/mcp-manager.ts +56 -8
- package/src/shared/mcp-resolver.ts +73 -2
- package/src/shared/mcp-schema-sanitizer.ts +224 -0
- package/src/shared/model-client.ts +179 -19
- package/src/shared/model-error.ts +222 -4
- package/src/shared/model-pricing-data.ts +22 -3
- package/src/shared/model-registry.ts +7 -2
- package/src/shared/plan-mode-permissions.ts +37 -0
- package/src/shared/registry-endpoint.ts +27 -0
- package/src/shared/runner-credential-keys.ts +46 -0
- package/src/worker.ts +4 -5
- package/src/workflow-engine/__tests__/tasks/emit-event.test.ts +127 -49
- package/src/workflow-engine/resolve.ts +48 -2
- package/src/workflow-engine/types.ts +18 -0
- package/src/workflows/__tests__/connect-mcp-server.test.ts +25 -0
- package/src/workflows/__tests__/execute-serverless-workflow.test.ts +68 -2
- package/src/workflows/call-agent-orchestrator.ts +10 -0
- package/src/workflows/connect-mcp-server.ts +9 -0
- package/src/workflows/engine-core.ts +23 -2
- package/src/workflows/execute-from-execution.ts +12 -2
- package/src/workflows/types.ts +8 -0
- package/dist/activities/execute-cursor/mcp-config.d.ts +0 -30
- package/dist/activities/execute-cursor/mcp-config.js +0 -39
- package/dist/activities/execute-cursor/mcp-config.js.map +0 -1
- package/src/activities/execute-cursor/mcp-config.ts +0 -66
|
@@ -41,7 +41,7 @@ import type { Config } from "../../config.js";
|
|
|
41
41
|
import { StigmerClient } from "../../client/stigmer-client.js";
|
|
42
42
|
import { describeExecutionError } from "../../shared/model-error.js";
|
|
43
43
|
import { resolveAgentWithTransportRecovery } from "./session-lifecycle.js";
|
|
44
|
-
import type { AgentResolution, CreateAgentOptions, CreateCloudAgentOptions } from "./session-lifecycle.js";
|
|
44
|
+
import type { AgentResolution, AgentResolutionReason, CreateAgentOptions, CreateCloudAgentOptions } from "./session-lifecycle.js";
|
|
45
45
|
import { CursorMode } from "@stigmer/protos/ai/stigmer/agentic/session/v1/enum_pb";
|
|
46
46
|
import { determineCursorMode, isCloudMode } from "./cursor-mode.js";
|
|
47
47
|
import { MessageAccumulator, cancelInProgressSubAgentProtos, collapseRedundantToolCallTwins } from "./message-translator.js";
|
|
@@ -84,6 +84,7 @@ import {
|
|
|
84
84
|
import { injectSynthesizedAttachment } from "../../shared/synthesized-attachment.js";
|
|
85
85
|
import { mergeApprovalPolicies } from "./approval-policy.js";
|
|
86
86
|
import { deriveActiveLeases, isUnattendedApprovalMode } from "../../shared/approval-policy.js";
|
|
87
|
+
import { enabledToolsBySlug } from "../../shared/mcp-enabled-tools.js";
|
|
87
88
|
import { backfillMcpServersIfNeeded } from "./connect-backfill.js";
|
|
88
89
|
import { resolveExecutionEnv } from "./env-resolver.js";
|
|
89
90
|
import { resolveBlueprint } from "./blueprint-resolver.js";
|
|
@@ -91,7 +92,8 @@ import { buildCursorSubAgentDefinitions } from "./subagent-config.js";
|
|
|
91
92
|
import { resolveSkills } from "./skill-resolver.js";
|
|
92
93
|
import { removeStigmerSymlink } from "../../shared/workspace/stigmer-link.js";
|
|
93
94
|
import { resolveAttachments } from "./attachment-resolver.js";
|
|
94
|
-
import { buildEnhancedPrompt, buildReinvocationPrompt, formatConversationCatchupSection, formatInputFiles, formatInteractionModePrefix, formatImplementPlanSection } from "./prompt-builder.js";
|
|
95
|
+
import { buildEnhancedPrompt, buildHitlRecoveryPrompt, buildReinvocationPrompt, formatConversationCatchupSection, formatInputFiles, formatInteractionModePrefix, formatImplementPlanSection } from "./prompt-builder.js";
|
|
96
|
+
import { composeTurnRecoveryDigest } from "./turn-recovery.js";
|
|
95
97
|
import { installHitlGate, removeHitlGate } from "./workspace-setup.js";
|
|
96
98
|
import { ensureHitlDir } from "../../shared/workspace/platform-dir.js";
|
|
97
99
|
import {
|
|
@@ -139,7 +141,7 @@ import { StreamingUsageSummarySchema } from "@stigmer/protos/ai/stigmer/agentic/
|
|
|
139
141
|
import { activityStarted, activityFinished } from "../../idle-watchdog.js";
|
|
140
142
|
import { normalizeActivityInput, type ExecuteActivityInput } from "../../shared/activity-input.js";
|
|
141
143
|
import { getCapturedRejection, clearCapturedRejection } from "./rejection-capture.js";
|
|
142
|
-
import { synthesizeError, formatClassifiedError, shouldRetryWithFreshAgent } from "./error-classifier.js";
|
|
144
|
+
import { synthesizeError, formatClassifiedError, shouldRetryWithFreshAgent, extractRunErrorSources } from "./error-classifier.js";
|
|
143
145
|
import type { ClassifiedError } from "./error-classifier.js";
|
|
144
146
|
import { createAgent, createCloudAgent } from "./session-lifecycle.js";
|
|
145
147
|
import { setMaxListeners } from "node:events";
|
|
@@ -644,9 +646,21 @@ async function executeCursorInner(
|
|
|
644
646
|
// the messaging reach; undefined lets a cloud sandbox runner's
|
|
645
647
|
// ambient session-scoped token or OSS's no-auth apply). The
|
|
646
648
|
// attachment header falls back to the ambient credential where no
|
|
647
|
-
// exchange happens.
|
|
648
|
-
|
|
649
|
-
|
|
649
|
+
// exchange happens. Unlike the env read (which hard-fails on a broken
|
|
650
|
+
// exchange — secrets are load-bearing there), this exchange is
|
|
651
|
+
// opportunistic: every consumer below degrades to an empty answer by
|
|
652
|
+
// contract, and the server refuses the ambient fallback safely, so a
|
|
653
|
+
// failed exchange must not kill the run.
|
|
654
|
+
let exchangedRunnerToken: string | undefined;
|
|
655
|
+
try {
|
|
656
|
+
exchangedRunnerToken =
|
|
657
|
+
await client.acquireScopedRunnerToken({ agentExecutionId: executionId });
|
|
658
|
+
} catch (err) {
|
|
659
|
+
console.warn(
|
|
660
|
+
"[execute-cursor] Scoped-token exchange failed for attachment/discovery " +
|
|
661
|
+
`reads; degrading to the ambient credential: ${err instanceof Error ? err.message : err}`,
|
|
662
|
+
);
|
|
663
|
+
}
|
|
650
664
|
const attachmentCredential = exchangedRunnerToken
|
|
651
665
|
?? config.stigmerTokenRef?.current
|
|
652
666
|
?? config.stigmerToken;
|
|
@@ -734,11 +748,11 @@ async function executeCursorInner(
|
|
|
734
748
|
// them as auto-approved); the global bypass empties the map entirely.
|
|
735
749
|
const leases = deriveActiveLeases(execution);
|
|
736
750
|
const globalBypass = leases.global;
|
|
737
|
-
|
|
738
|
-
|
|
751
|
+
// Layer-3 overrides ride each resolved server from its merged usage —
|
|
752
|
+
// see ResolvedMcpServer.toolApprovalOverrides (issue #349) — so there
|
|
753
|
+
// is no separate override input to pass here.
|
|
739
754
|
const mergedPolicies = mergeApprovalPolicies(
|
|
740
755
|
mcpResolution.resolvedServers,
|
|
741
|
-
agentOverrides,
|
|
742
756
|
leases,
|
|
743
757
|
);
|
|
744
758
|
heartbeat();
|
|
@@ -785,7 +799,10 @@ async function executeCursorInner(
|
|
|
785
799
|
storage: artifactStorage,
|
|
786
800
|
visionBudget,
|
|
787
801
|
});
|
|
788
|
-
const
|
|
802
|
+
const attachmentEntries = attachmentResults.map((a) => ({
|
|
803
|
+
path: a.relativePath,
|
|
804
|
+
...(a.renamedFrom !== undefined ? { renamedFrom: a.renamedFrom } : {}),
|
|
805
|
+
}));
|
|
789
806
|
// Vision facts, derived once from the single resolution result: the
|
|
790
807
|
// images the model will see inline (in attachment order) and the ones
|
|
791
808
|
// that degraded to path-only, disclosed in the prompt.
|
|
@@ -906,6 +923,11 @@ async function executeCursorInner(
|
|
|
906
923
|
captureIgnored,
|
|
907
924
|
gitWorkspace,
|
|
908
925
|
isUnattendedApprovalMode(execution),
|
|
926
|
+
// The enabled_tools capability manifest (issue #350): restricted
|
|
927
|
+
// servers' allow-lists, enforced by the hook's "disabled" arm ahead of
|
|
928
|
+
// every approval bypass. The Cursor SDK config cannot hide a server's
|
|
929
|
+
// tools, so this deny-at-call is the harness's enforcement.
|
|
930
|
+
enabledToolsBySlug(mcpResolution.resolvedServers),
|
|
909
931
|
);
|
|
910
932
|
const hitlGate = await installHitlGate({
|
|
911
933
|
workspaceRoot: primaryWorkspaceDir,
|
|
@@ -1130,7 +1152,7 @@ async function executeCursorInner(
|
|
|
1130
1152
|
subAgents: blueprint.subAgents,
|
|
1131
1153
|
workspaceDirs: blueprint.workspaceDirs,
|
|
1132
1154
|
workspaceFileRefs: spec.workspaceFileRefs ?? [],
|
|
1133
|
-
|
|
1155
|
+
attachments: attachmentEntries,
|
|
1134
1156
|
vision: visionPromptInfo,
|
|
1135
1157
|
pendingApprovals: adjudicatedApprovals,
|
|
1136
1158
|
appliedToolCallIds,
|
|
@@ -1140,28 +1162,43 @@ async function executeCursorInner(
|
|
|
1140
1162
|
senderIdentity: readSenderIdentity(blueprint.sessionSpec.metadata),
|
|
1141
1163
|
sessionContext: readSessionContext(blueprint.sessionSpec.metadata),
|
|
1142
1164
|
conversationCatchup: readConversationCatchup(spec.conversationCatchup),
|
|
1165
|
+
// The turn's recorded transcript, seeded from the persisted execution
|
|
1166
|
+
// on a reinvocation (Phase 3). Consumed only by the HITL-recovery
|
|
1167
|
+
// shape — reached from HERE when the stored handle failed to resume
|
|
1168
|
+
// at resolution time (issue #366 crossing 2).
|
|
1169
|
+
turnRecoveryDigest: isReinvocation
|
|
1170
|
+
? composeTurnRecoveryDigest(status.messages)
|
|
1171
|
+
: undefined,
|
|
1143
1172
|
});
|
|
1144
1173
|
|
|
1145
|
-
// Phase 10a: Inject structured output instruction for Cursor
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1174
|
+
// Phase 10a: Inject the structured output instruction for the Cursor
|
|
1175
|
+
// harness. A per-turn directive, so like buildFromPlan it must ride every
|
|
1176
|
+
// prompt this turn sends — the primary AND the poisoned-handle recovery
|
|
1177
|
+
// rebuild (the transport retry re-sends effectivePrompt and inherits it).
|
|
1178
|
+
const withStructuredOutputDirective = (basePrompt: string): string =>
|
|
1179
|
+
appendStructuredOutputDirective(basePrompt, structuredOutputSchema);
|
|
1180
|
+
const effectivePrompt = withStructuredOutputDirective(prompt);
|
|
1151
1181
|
|
|
1152
1182
|
// Phase 10a1: The turn's vision payload. The invariant is "images
|
|
1153
|
-
// accompany the user's turn message
|
|
1154
|
-
//
|
|
1155
|
-
//
|
|
1156
|
-
//
|
|
1157
|
-
//
|
|
1158
|
-
//
|
|
1159
|
-
//
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
const
|
|
1164
|
-
|
|
1183
|
+
// accompany the user's turn message, wherever the conversation does not
|
|
1184
|
+
// already hold them" (primarySendCarriesImages): the ONLY send that
|
|
1185
|
+
// skips them is a HITL re-invocation of a successfully RESUMED agent,
|
|
1186
|
+
// whose native conversation carries the images from the original send.
|
|
1187
|
+
// Every send that starts an empty conversation re-delivers them — the
|
|
1188
|
+
// ordinary first/fresh-agent primary send, the HITL primary send after a
|
|
1189
|
+
// resolution-time resume failure, and both mid-send recovery retries
|
|
1190
|
+
// (which always run on a fresh agent, so their sites pass turnImages
|
|
1191
|
+
// unconditionally). Attachments re-resolve on every invocation
|
|
1192
|
+
// (Phase 5b), so the bytes are in hand even on a re-invocation.
|
|
1193
|
+
const turnImages = toCursorImages(visionImages);
|
|
1194
|
+
const primarySendImages = primarySendCarriesImages(approvalDecisions, resolution.reason)
|
|
1195
|
+
? turnImages
|
|
1196
|
+
: [];
|
|
1197
|
+
const toSendMessage = (
|
|
1198
|
+
sendPrompt: string,
|
|
1199
|
+
images: { data: string; mimeType: string }[],
|
|
1200
|
+
): string | SDKUserMessage =>
|
|
1201
|
+
images.length > 0 ? { text: sendPrompt, images } : sendPrompt;
|
|
1165
1202
|
|
|
1166
1203
|
// Phase 10a2: Log Stigmer preamble size for context trimming diagnostics
|
|
1167
1204
|
const promptChars = effectivePrompt.length;
|
|
@@ -1277,7 +1314,7 @@ async function executeCursorInner(
|
|
|
1277
1314
|
// The stall watchdog is armed inside consumeCursorTurnStream (it needs the
|
|
1278
1315
|
// run to cancel), stored on turnState.stallWatchdog so this shared onDelta can
|
|
1279
1316
|
// reset it and the activity's finally can stop it as a backstop.
|
|
1280
|
-
const run = await resolution.agent.send(toSendMessage(effectivePrompt), {
|
|
1317
|
+
const run = await resolution.agent.send(toSendMessage(effectivePrompt, primarySendImages), {
|
|
1281
1318
|
onDelta: (event) => {
|
|
1282
1319
|
if (!turnFirstEventEmitted) {
|
|
1283
1320
|
turnFirstEventEmitted = true;
|
|
@@ -1648,10 +1685,11 @@ async function executeCursorInner(
|
|
|
1648
1685
|
// poisoned-handle path leaked the fresh agent — it closed the stale one.)
|
|
1649
1686
|
resolution = { ...resolution, agent: freshAgent, agentId: freshAgent.agentId, isNew: true };
|
|
1650
1687
|
turnState.streamErrorMessage = undefined;
|
|
1651
|
-
// The retry carries the turn's
|
|
1652
|
-
//
|
|
1653
|
-
// silently lose the user's photo on
|
|
1654
|
-
|
|
1688
|
+
// The retry always carries the turn's full image payload — never the
|
|
1689
|
+
// primary send's HITL-trimmed set: the fresh agent's conversation is
|
|
1690
|
+
// empty, so skipping them here would silently lose the user's photo on
|
|
1691
|
+
// a recovered turn (issue #366's vision corollary).
|
|
1692
|
+
const retryRun = await freshAgent.send(toSendMessage(retryPrompt, turnImages), {
|
|
1655
1693
|
onDelta: makeCursorTurnOnDelta(onDeltaDeps),
|
|
1656
1694
|
});
|
|
1657
1695
|
await consumeCursorTurnStream(retryRun, streamDeps);
|
|
@@ -1721,12 +1759,10 @@ async function executeCursorInner(
|
|
|
1721
1759
|
status.phase = ExecutionPhase.EXECUTION_COMPLETED;
|
|
1722
1760
|
break;
|
|
1723
1761
|
case "error": {
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
?? resultAny.reason;
|
|
1729
|
-
const sdkErrorStr = sdkError ? String(sdkError) : undefined;
|
|
1762
|
+
// Shape-aware extraction, NOT String(): the result's error fields are
|
|
1763
|
+
// structured at runtime often enough that a bare coercion showed users
|
|
1764
|
+
// "[object Object]" and shadowed every fallback source below (oss#299).
|
|
1765
|
+
const runErrorSources = extractRunErrorSources(result);
|
|
1730
1766
|
|
|
1731
1767
|
// The SDK frequently resolves run.wait() to a bare { status: "error" }
|
|
1732
1768
|
// while the real reason (e.g. the original grpc-status 12 routing
|
|
@@ -1738,7 +1774,8 @@ async function executeCursorInner(
|
|
|
1738
1774
|
if (capturedRejection) clearCapturedRejection(executionId);
|
|
1739
1775
|
|
|
1740
1776
|
const classified = synthesizeError({
|
|
1741
|
-
|
|
1777
|
+
sdkError: runErrorSources.sdkError,
|
|
1778
|
+
sdkResultFields: runErrorSources.sdkResultFields,
|
|
1742
1779
|
streamErrorMessage: turnState.streamErrorMessage,
|
|
1743
1780
|
capturedRejection,
|
|
1744
1781
|
conversationErrorText,
|
|
@@ -1789,9 +1826,13 @@ async function executeCursorInner(
|
|
|
1789
1826
|
subAgents: blueprint.subAgents,
|
|
1790
1827
|
workspaceDirs: blueprint.workspaceDirs,
|
|
1791
1828
|
workspaceFileRefs: spec.workspaceFileRefs ?? [],
|
|
1792
|
-
|
|
1829
|
+
attachments: attachmentEntries,
|
|
1793
1830
|
vision: visionPromptInfo,
|
|
1794
1831
|
pendingApprovals: adjudicatedApprovals,
|
|
1832
|
+
// Without the applied set, the HITL-recovery prompt would tell
|
|
1833
|
+
// the fresh agent to carry out writes the runner already
|
|
1834
|
+
// exact-applied (the primary call at Phase 10 passes it too).
|
|
1835
|
+
appliedToolCallIds,
|
|
1795
1836
|
interactionMode,
|
|
1796
1837
|
// buildFromPlan was silently dropped here until T03 Sitting 3 —
|
|
1797
1838
|
// a build turn that hit handle recovery lost its directive. The
|
|
@@ -1802,6 +1843,10 @@ async function executeCursorInner(
|
|
|
1802
1843
|
senderIdentity: readSenderIdentity(blueprint.sessionSpec.metadata),
|
|
1803
1844
|
sessionContext: readSessionContext(blueprint.sessionSpec.metadata),
|
|
1804
1845
|
conversationCatchup: readConversationCatchup(spec.conversationCatchup),
|
|
1846
|
+
// Composed fresh (not reused from Phase 10): the failed primary
|
|
1847
|
+
// stream may have appended partial work onto status.messages,
|
|
1848
|
+
// and the replacement agent should know about that too.
|
|
1849
|
+
turnRecoveryDigest: composeTurnRecoveryDigest(status.messages),
|
|
1805
1850
|
});
|
|
1806
1851
|
|
|
1807
1852
|
console.log(
|
|
@@ -1817,7 +1862,14 @@ async function executeCursorInner(
|
|
|
1817
1862
|
console.warn("Failed to update session with fresh agentId (non-fatal):", updateErr);
|
|
1818
1863
|
}
|
|
1819
1864
|
|
|
1820
|
-
|
|
1865
|
+
// Same per-turn directive rule as buildFromPlan above: a
|
|
1866
|
+
// structured-output turn keeps its output contract on the rebuilt
|
|
1867
|
+
// prompt (the transport retry re-sends effectivePrompt and
|
|
1868
|
+
// inherits it without help).
|
|
1869
|
+
const outcome = await runRecoveryStream(
|
|
1870
|
+
freshAgent,
|
|
1871
|
+
withStructuredOutputDirective(freshPrompt),
|
|
1872
|
+
);
|
|
1821
1873
|
if (!outcome.proceeded) {
|
|
1822
1874
|
if (outcome.terminal.kind === "return") return slimStatus(status);
|
|
1823
1875
|
throw new CancelledFailure(outcome.terminal.message);
|
|
@@ -1856,8 +1908,14 @@ async function executeCursorInner(
|
|
|
1856
1908
|
|
|
1857
1909
|
const retryConversationErrorText = await introspectConversation(retryRun, executionId);
|
|
1858
1910
|
|
|
1911
|
+
// Same shape-aware extraction as the primary error arm — the retry
|
|
1912
|
+
// previously String()-coerced result.result alone, so a structured
|
|
1913
|
+
// retry failure both read "[object Object]" and ignored the
|
|
1914
|
+
// error/message/reason fields the primary arm consults.
|
|
1915
|
+
const retryErrorSources = extractRunErrorSources(retryResult);
|
|
1859
1916
|
const retryClassified = synthesizeError({
|
|
1860
|
-
|
|
1917
|
+
sdkError: retryErrorSources.sdkError,
|
|
1918
|
+
sdkResultFields: retryErrorSources.sdkResultFields,
|
|
1861
1919
|
streamErrorMessage: turnState.streamErrorMessage,
|
|
1862
1920
|
capturedRejection: retryRejection,
|
|
1863
1921
|
conversationErrorText: retryConversationErrorText,
|
|
@@ -1974,6 +2032,7 @@ async function executeCursorInner(
|
|
|
1974
2032
|
`finalTextLength=${finalText.length}`,
|
|
1975
2033
|
);
|
|
1976
2034
|
try {
|
|
2035
|
+
const { extractStructuredOutput } = await import("./extract-structured-output.js");
|
|
1977
2036
|
structuredOutput = await extractStructuredOutput(
|
|
1978
2037
|
finalText, structuredOutputSchema, config, requestedModel,
|
|
1979
2038
|
);
|
|
@@ -2298,53 +2357,6 @@ function seedCursorTranscriptFromExecution(
|
|
|
2298
2357
|
return persisted.subAgentExecutions.map((sub) => clone(SubAgentExecutionSchema, sub));
|
|
2299
2358
|
}
|
|
2300
2359
|
|
|
2301
|
-
// ---------------------------------------------------------------------------
|
|
2302
|
-
// Structured Output Extraction (Cursor Harness Tier 2)
|
|
2303
|
-
// ---------------------------------------------------------------------------
|
|
2304
|
-
|
|
2305
|
-
/**
|
|
2306
|
-
* Extract structured data from an agent's free-text response using an
|
|
2307
|
-
* economy-tier LLM with withStructuredOutput (function-calling).
|
|
2308
|
-
* Guarantees schema-conformant JSON output via the API's tool-use mechanism.
|
|
2309
|
-
*
|
|
2310
|
-
* Construction (registry-id resolution, provider inference, proxy wiring) is
|
|
2311
|
-
* delegated to the shared buildChatModel so the economy model's registry id is
|
|
2312
|
-
* always resolved to a provider API id before the call.
|
|
2313
|
-
*/
|
|
2314
|
-
async function extractStructuredOutput(
|
|
2315
|
-
agentResponse: string,
|
|
2316
|
-
schema: Record<string, unknown>,
|
|
2317
|
-
config: Config,
|
|
2318
|
-
primaryModel: string,
|
|
2319
|
-
): Promise<unknown | null> {
|
|
2320
|
-
const { getEconomyModel } = await import("../../shared/model-registry.js");
|
|
2321
|
-
const { buildChatModel } = await import("../../shared/model-client.js");
|
|
2322
|
-
|
|
2323
|
-
const extractionModel = await getEconomyModel(primaryModel);
|
|
2324
|
-
const proxyEndpoint = config.proxyEndpoint ?? config.stigmerBackendEndpoint;
|
|
2325
|
-
|
|
2326
|
-
const { model: llm } = await buildChatModel({
|
|
2327
|
-
modelName: extractionModel,
|
|
2328
|
-
proxyEndpoint,
|
|
2329
|
-
stigmerToken: config.stigmerToken ?? undefined,
|
|
2330
|
-
maxTokens: 4096,
|
|
2331
|
-
});
|
|
2332
|
-
|
|
2333
|
-
const zodSchema = jsonSchemaToZod(schema);
|
|
2334
|
-
const structured = llm.withStructuredOutput(zodSchema);
|
|
2335
|
-
|
|
2336
|
-
const result = await structured.invoke([
|
|
2337
|
-
{ role: "system", content: "Extract the structured data from the agent's response. Return only the data that matches the schema." },
|
|
2338
|
-
{ role: "user", content: agentResponse },
|
|
2339
|
-
]);
|
|
2340
|
-
|
|
2341
|
-
return result ?? null;
|
|
2342
|
-
}
|
|
2343
|
-
|
|
2344
|
-
// Re-export for use within this module; shared implementation eliminates
|
|
2345
|
-
// the three duplicate converters that previously drifted independently.
|
|
2346
|
-
import { jsonSchemaToZod } from "../../shared/json-schema-to-zod.js";
|
|
2347
|
-
|
|
2348
2360
|
// ---------------------------------------------------------------------------
|
|
2349
2361
|
// Prompt selection
|
|
2350
2362
|
// ---------------------------------------------------------------------------
|
|
@@ -2365,7 +2377,11 @@ export interface BuildPromptInput {
|
|
|
2365
2377
|
subAgents: import("@stigmer/protos/ai/stigmer/agentic/agent/v1/spec_pb").SubAgent[];
|
|
2366
2378
|
workspaceDirs: string[];
|
|
2367
2379
|
workspaceFileRefs: string[];
|
|
2368
|
-
|
|
2380
|
+
/**
|
|
2381
|
+
* This turn's resolved attachments for the `<input_files>` section —
|
|
2382
|
+
* final paths plus duplicate-rename disclosure (attachment-resolver.ts).
|
|
2383
|
+
*/
|
|
2384
|
+
attachments: import("./prompt-builder.js").AttachmentPromptEntry[];
|
|
2369
2385
|
/**
|
|
2370
2386
|
* Vision facts for the input-files section (T04): which attachments the
|
|
2371
2387
|
* model sees inline and which degraded to path-only. PER-TURN like the
|
|
@@ -2416,6 +2432,15 @@ export interface BuildPromptInput {
|
|
|
2416
2432
|
* usually blank.
|
|
2417
2433
|
*/
|
|
2418
2434
|
conversationCatchup?: string;
|
|
2435
|
+
/**
|
|
2436
|
+
* The turn's recorded transcript rendered as digest lines
|
|
2437
|
+
* (turn-recovery.ts), composed from `status.messages` at the call site.
|
|
2438
|
+
* Consumed ONLY by the HITL-recovery shape — a fresh agent that replaced
|
|
2439
|
+
* a lost one mid-HITL needs the story of the work it no longer remembers
|
|
2440
|
+
* (issue #366); every other shape either has native context or no prior
|
|
2441
|
+
* work to tell.
|
|
2442
|
+
*/
|
|
2443
|
+
turnRecoveryDigest?: string;
|
|
2419
2444
|
}
|
|
2420
2445
|
|
|
2421
2446
|
/**
|
|
@@ -2427,20 +2452,28 @@ export interface BuildPromptInput {
|
|
|
2427
2452
|
* volume, or cloud server-side state) — there is no separate continuation
|
|
2428
2453
|
* store. The prompt therefore depends only on how the agent was resolved:
|
|
2429
2454
|
*
|
|
2430
|
-
* 1. HITL reinvocation -> buildReinvocationPrompt (approval decisions
|
|
2431
|
-
*
|
|
2432
|
-
*
|
|
2433
|
-
* 2.
|
|
2434
|
-
*
|
|
2455
|
+
* 1. HITL reinvocation, -> buildReinvocationPrompt (approval decisions
|
|
2456
|
+
* resumed agent only; the resumed agent's native context
|
|
2457
|
+
* carries the prior conversation)
|
|
2458
|
+
* 2. HITL reinvocation, -> buildHitlRecoveryPrompt (full context +
|
|
2459
|
+
* fresh agent after the turn's recorded transcript + decisions;
|
|
2460
|
+
* resume failure the replacement agent's conversation is
|
|
2461
|
+
* empty, and both fresh-agent crossings —
|
|
2462
|
+
* resolution-time resume failure and mid-send
|
|
2463
|
+
* poisoned-handle recovery — land here by
|
|
2464
|
+
* keying on the reason, issue #366)
|
|
2465
|
+
* 3. resumed_successfully -> raw userMessage (native context carries it)
|
|
2466
|
+
* 4. first execution / fresh -> buildEnhancedPrompt (full instructions +
|
|
2435
2467
|
* agent after resume failure skills; no prior conversation to inherit)
|
|
2436
2468
|
*/
|
|
2437
2469
|
/**
|
|
2438
2470
|
* Whether this activity invocation is a HITL re-invocation — the turn resumes
|
|
2439
2471
|
* an agent purely to convey approval decisions, carrying NO user message.
|
|
2440
|
-
*
|
|
2441
|
-
*
|
|
2442
|
-
* vision payload
|
|
2443
|
-
*
|
|
2472
|
+
* Discriminates the two surfaces that depend on the agent already holding
|
|
2473
|
+
* this turn's content natively — the prompt shape (below) and the primary
|
|
2474
|
+
* send's vision payload — but never alone: both pair it with
|
|
2475
|
+
* `resolution.reason`, because a FRESH agent mid-HITL holds nothing and
|
|
2476
|
+
* needs the full re-delivery (issue #366).
|
|
2444
2477
|
*/
|
|
2445
2478
|
export function isHitlReinvocation(
|
|
2446
2479
|
approvalDecisions: Map<string, ApprovalAction> | undefined,
|
|
@@ -2448,6 +2481,39 @@ export function isHitlReinvocation(
|
|
|
2448
2481
|
return approvalDecisions !== undefined && approvalDecisions.size > 0;
|
|
2449
2482
|
}
|
|
2450
2483
|
|
|
2484
|
+
/**
|
|
2485
|
+
* Whether the PRIMARY send delivers the turn's vision payload. The invariant
|
|
2486
|
+
* is "images accompany the user's turn message, wherever the conversation
|
|
2487
|
+
* does not already hold them" — so the only send that skips them is a HITL
|
|
2488
|
+
* re-invocation of a successfully RESUMED agent, whose native conversation
|
|
2489
|
+
* carries the images from the original send. A fresh agent mid-HITL
|
|
2490
|
+
* (resolution-time resume failure — issue #366's vision corollary) holds
|
|
2491
|
+
* nothing and needs the re-delivery. The mid-send recovery retries always
|
|
2492
|
+
* run on a fresh agent, so their send sites carry the payload
|
|
2493
|
+
* unconditionally rather than consulting this.
|
|
2494
|
+
*/
|
|
2495
|
+
export function primarySendCarriesImages(
|
|
2496
|
+
approvalDecisions: Map<string, ApprovalAction> | undefined,
|
|
2497
|
+
reason: AgentResolutionReason,
|
|
2498
|
+
): boolean {
|
|
2499
|
+
return !(isHitlReinvocation(approvalDecisions) && reason === "resumed_successfully");
|
|
2500
|
+
}
|
|
2501
|
+
|
|
2502
|
+
/**
|
|
2503
|
+
* Append the structured-output contract to a prompt when the execution
|
|
2504
|
+
* requests one. A per-turn directive (the buildFromPlan rule): it must ride
|
|
2505
|
+
* every prompt this turn sends — the primary send AND the poisoned-handle
|
|
2506
|
+
* recovery rebuild, which previously lost it (issue #366 ride-along).
|
|
2507
|
+
*/
|
|
2508
|
+
export function appendStructuredOutputDirective(
|
|
2509
|
+
basePrompt: string,
|
|
2510
|
+
schema: Record<string, unknown> | undefined,
|
|
2511
|
+
): string {
|
|
2512
|
+
if (!schema) return basePrompt;
|
|
2513
|
+
const schemaStr = JSON.stringify(schema, null, 2);
|
|
2514
|
+
return basePrompt + `\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.`;
|
|
2515
|
+
}
|
|
2516
|
+
|
|
2451
2517
|
export function buildPrompt(input: BuildPromptInput): string {
|
|
2452
2518
|
const {
|
|
2453
2519
|
resolution,
|
|
@@ -2458,16 +2524,50 @@ export function buildPrompt(input: BuildPromptInput): string {
|
|
|
2458
2524
|
subAgents,
|
|
2459
2525
|
workspaceDirs,
|
|
2460
2526
|
workspaceFileRefs,
|
|
2461
|
-
|
|
2527
|
+
attachments,
|
|
2462
2528
|
interactionMode,
|
|
2463
2529
|
buildFromPlan,
|
|
2464
2530
|
conversationCatchup,
|
|
2465
2531
|
} = input;
|
|
2466
2532
|
|
|
2467
|
-
// HITL reinvocation: the
|
|
2468
|
-
//
|
|
2469
|
-
//
|
|
2533
|
+
// HITL reinvocation: the decisions-only prompt is correct ONLY while the
|
|
2534
|
+
// agent's native context still carries the prior conversation — which only
|
|
2535
|
+
// resumed_successfully guarantees. Any other reason means a fresh agent
|
|
2536
|
+
// mid-HITL (in practice created_after_resume_failure: the stored handle
|
|
2537
|
+
// failed to resume, or a poisoned handle was replaced mid-send), which
|
|
2538
|
+
// gets the full recovery shape instead — enhanced context + the turn's
|
|
2539
|
+
// recorded transcript + the same decisions — because the bare decisions on
|
|
2540
|
+
// an empty conversation strand the agent with instructions and no story,
|
|
2541
|
+
// and the session inherits that amnesia permanently (issue #366).
|
|
2470
2542
|
if (isHitlReinvocation(approvalDecisions)) {
|
|
2543
|
+
if (resolution.reason !== "resumed_successfully") {
|
|
2544
|
+
return buildHitlRecoveryPrompt(
|
|
2545
|
+
{
|
|
2546
|
+
instructions,
|
|
2547
|
+
userMessage,
|
|
2548
|
+
skills,
|
|
2549
|
+
datastoreUsages: input.datastoreUsages ?? [],
|
|
2550
|
+
channelMessaging: input.channelMessaging ?? [],
|
|
2551
|
+
subAgents,
|
|
2552
|
+
workspaceDirs,
|
|
2553
|
+
workspaceFileRefs,
|
|
2554
|
+
attachments,
|
|
2555
|
+
vision: input.vision,
|
|
2556
|
+
interactionMode,
|
|
2557
|
+
buildFromPlan,
|
|
2558
|
+
contextBridge: input.contextBridge,
|
|
2559
|
+
senderIdentity: input.senderIdentity,
|
|
2560
|
+
sessionContext: input.sessionContext,
|
|
2561
|
+
conversationCatchup,
|
|
2562
|
+
},
|
|
2563
|
+
{
|
|
2564
|
+
turnDigest: input.turnRecoveryDigest,
|
|
2565
|
+
pendingApprovals: input.pendingApprovals,
|
|
2566
|
+
approvalDecisions,
|
|
2567
|
+
appliedToolCallIds: input.appliedToolCallIds,
|
|
2568
|
+
},
|
|
2569
|
+
);
|
|
2570
|
+
}
|
|
2471
2571
|
return buildReinvocationPrompt(
|
|
2472
2572
|
input.pendingApprovals,
|
|
2473
2573
|
approvalDecisions,
|
|
@@ -2492,9 +2592,9 @@ export function buildPrompt(input: BuildPromptInput): string {
|
|
|
2492
2592
|
if (resolution.reason === "resumed_successfully") {
|
|
2493
2593
|
const prefixes = [
|
|
2494
2594
|
formatInteractionModePrefix(interactionMode),
|
|
2495
|
-
formatImplementPlanSection(buildFromPlan,
|
|
2496
|
-
|
|
2497
|
-
? formatInputFiles(
|
|
2595
|
+
formatImplementPlanSection(buildFromPlan, attachments),
|
|
2596
|
+
attachments.length > 0
|
|
2597
|
+
? formatInputFiles(attachments, input.vision)
|
|
2498
2598
|
: undefined,
|
|
2499
2599
|
conversationCatchup !== undefined
|
|
2500
2600
|
? formatConversationCatchupSection(conversationCatchup)
|
|
@@ -2517,7 +2617,7 @@ export function buildPrompt(input: BuildPromptInput): string {
|
|
|
2517
2617
|
subAgents,
|
|
2518
2618
|
workspaceDirs,
|
|
2519
2619
|
workspaceFileRefs,
|
|
2520
|
-
|
|
2620
|
+
attachments,
|
|
2521
2621
|
vision: input.vision,
|
|
2522
2622
|
interactionMode,
|
|
2523
2623
|
buildFromPlan,
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* same pipeline as the Python agent-runner's config_transformer.py.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
import type { McpServerUsage } from "@stigmer/protos/ai/stigmer/agentic/agent/v1/spec_pb";
|
|
17
|
+
import type { McpServerUsage, ToolApprovalOverride } from "@stigmer/protos/ai/stigmer/agentic/agent/v1/spec_pb";
|
|
18
18
|
import type { McpServer } from "@stigmer/protos/ai/stigmer/agentic/mcpserver/v1/api_pb";
|
|
19
19
|
import type { ToolApprovalPolicy } from "@stigmer/protos/ai/stigmer/agentic/mcpserver/v1/spec_pb";
|
|
20
20
|
import type { StigmerClient } from "../../client/stigmer-client.js";
|
|
@@ -29,6 +29,7 @@ import {
|
|
|
29
29
|
filterEnvToDeclaredKeys,
|
|
30
30
|
PlaceholderResolutionError,
|
|
31
31
|
} from "./placeholder-resolver.js";
|
|
32
|
+
import { effectiveEnabledTools } from "../../shared/mcp-enabled-tools.js";
|
|
32
33
|
|
|
33
34
|
/**
|
|
34
35
|
* Cursor SDK MCP server config shape (matches @cursor/sdk McpServerConfig).
|
|
@@ -70,6 +71,29 @@ export interface ResolvedMcpServer {
|
|
|
70
71
|
pinnedToolApprovals: ToolApprovalPolicy[];
|
|
71
72
|
/** True when the server has never been connected (no tool discovery yet). */
|
|
72
73
|
discoveredCapabilitiesEmpty: boolean;
|
|
74
|
+
/**
|
|
75
|
+
* The EFFECTIVE tool allow-list for this server (issue #350): the usage's
|
|
76
|
+
* enabled_tools, falling back to the server's default_enabled_tools when
|
|
77
|
+
* the usage's list is empty (see shared/mcp-enabled-tools.ts). Absent when
|
|
78
|
+
* unrestricted. The Cursor SDK config cannot hide tools, so this harness
|
|
79
|
+
* enforces it in the HITL hook: the restricted map is written into the
|
|
80
|
+
* approval state (mcpServerEnabledTools) and non-enabled calls are denied
|
|
81
|
+
* with the non-pausing "disabled" kind (see hook-script.ts).
|
|
82
|
+
*/
|
|
83
|
+
enabledTools?: string[];
|
|
84
|
+
/**
|
|
85
|
+
* Layer-3 per-agent approval overrides from the usage that resolved this
|
|
86
|
+
* server (issue #349): riding the resolved server is what SCOPES an
|
|
87
|
+
* override to its own server — a flat cross-server list is how an
|
|
88
|
+
* override once leaked onto (or silently un-gated) a same-named tool on
|
|
89
|
+
* another server. Deliberately REQUIRED, not optional: empty means "no
|
|
90
|
+
* overrides", and every construction site — including the shared
|
|
91
|
+
* resolver this one mirrors and the synthesized attachments, which have
|
|
92
|
+
* no usage and therefore no layer 3 — must say so explicitly, so a
|
|
93
|
+
* forgotten mirror cannot compile. Consumed by mergeApprovalPolicies
|
|
94
|
+
* (shared/approval-policy.ts).
|
|
95
|
+
*/
|
|
96
|
+
toolApprovalOverrides: ToolApprovalOverride[];
|
|
73
97
|
}
|
|
74
98
|
|
|
75
99
|
/**
|
|
@@ -115,7 +139,13 @@ export async function resolveMcpServers(
|
|
|
115
139
|
envVars,
|
|
116
140
|
ref.slug,
|
|
117
141
|
);
|
|
118
|
-
const server = mcpServerToResolved(
|
|
142
|
+
const server = mcpServerToResolved(
|
|
143
|
+
mcpServer,
|
|
144
|
+
ref.slug,
|
|
145
|
+
serverEnv,
|
|
146
|
+
usage.enabledTools,
|
|
147
|
+
usage.toolApprovalOverrides ?? [],
|
|
148
|
+
);
|
|
119
149
|
if (server) {
|
|
120
150
|
assertTransportAllowed(server.slug, server.connectionType, transportPosture);
|
|
121
151
|
resolved.push(server);
|
|
@@ -152,6 +182,8 @@ function mcpServerToResolved(
|
|
|
152
182
|
server: McpServer,
|
|
153
183
|
slug: string,
|
|
154
184
|
envVars: Record<string, string>,
|
|
185
|
+
usageEnabledTools?: readonly string[],
|
|
186
|
+
usageToolApprovalOverrides: ToolApprovalOverride[] = [],
|
|
155
187
|
): ResolvedMcpServer | null {
|
|
156
188
|
const spec = server.spec;
|
|
157
189
|
if (!spec) return null;
|
|
@@ -167,6 +199,8 @@ function mcpServerToResolved(
|
|
|
167
199
|
toolApprovals,
|
|
168
200
|
pinnedToolApprovals,
|
|
169
201
|
discoveredCapabilitiesEmpty,
|
|
202
|
+
enabledTools: effectiveEnabledTools(usageEnabledTools, spec.defaultEnabledTools),
|
|
203
|
+
toolApprovalOverrides: usageToolApprovalOverrides,
|
|
170
204
|
};
|
|
171
205
|
|
|
172
206
|
switch (spec.serverType.case) {
|
|
@@ -8,7 +8,12 @@
|
|
|
8
8
|
* endpoint is unreachable.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
import {
|
|
11
|
+
import {
|
|
12
|
+
resolveModelRegistryUrl,
|
|
13
|
+
buildRegistryHeaders,
|
|
14
|
+
REGISTRY_RETRY_POLICY,
|
|
15
|
+
} from "../../shared/registry-endpoint.js";
|
|
16
|
+
import { fetchWithRetry } from "../../shared/http-retry.js";
|
|
12
17
|
|
|
13
18
|
/** Per-million rates for a speed/mode variant (e.g. "fast") of a base model. */
|
|
14
19
|
export interface CursorVariantPricing {
|
|
@@ -53,6 +58,10 @@ interface RegistryEntry {
|
|
|
53
58
|
}
|
|
54
59
|
|
|
55
60
|
const CACHE_TTL_MS = 3_600_000; // 1 hour
|
|
61
|
+
// Failed fetches are cached much shorter than successes (the model-registry.ts
|
|
62
|
+
// policy): a transient failure must not pin DEFAULT_PRICING — wrong rates for
|
|
63
|
+
// cost tracking — for a full hour.
|
|
64
|
+
const FAILURE_CACHE_TTL_MS = 60_000;
|
|
56
65
|
|
|
57
66
|
const DEFAULT_PRICING: CursorModelPricing = {
|
|
58
67
|
model: "unknown",
|
|
@@ -104,7 +113,11 @@ function parseVariants(
|
|
|
104
113
|
}
|
|
105
114
|
|
|
106
115
|
async function fetchFromApi(): Promise<readonly CursorModelPricing[]> {
|
|
107
|
-
const res = await
|
|
116
|
+
const res = await fetchWithRetry(
|
|
117
|
+
resolveModelRegistryUrl(),
|
|
118
|
+
{ headers: buildRegistryHeaders() },
|
|
119
|
+
REGISTRY_RETRY_POLICY,
|
|
120
|
+
);
|
|
108
121
|
if (!res.ok) throw new Error(`Model registry fetch failed: ${res.status}`);
|
|
109
122
|
const data: unknown = await res.json();
|
|
110
123
|
const table = parsePricingTable(data);
|
|
@@ -138,7 +151,7 @@ export async function getPricingTable(): Promise<readonly CursorModelPricing[]>
|
|
|
138
151
|
`Failed to fetch model registry from API, using default pricing: ${err}`,
|
|
139
152
|
);
|
|
140
153
|
const fallback = [DEFAULT_PRICING];
|
|
141
|
-
cache = { data: fallback, expiresAt: Date.now() +
|
|
154
|
+
cache = { data: fallback, expiresAt: Date.now() + FAILURE_CACHE_TTL_MS };
|
|
142
155
|
return fallback;
|
|
143
156
|
})
|
|
144
157
|
.finally(() => {
|
|
@@ -148,4 +161,10 @@ export async function getPricingTable(): Promise<readonly CursorModelPricing[]>
|
|
|
148
161
|
return inflightFetch;
|
|
149
162
|
}
|
|
150
163
|
|
|
164
|
+
/** Exposed for testing — resets the in-memory cache. */
|
|
165
|
+
export function _resetPricingCache(): void {
|
|
166
|
+
cache = null;
|
|
167
|
+
inflightFetch = null;
|
|
168
|
+
}
|
|
169
|
+
|
|
151
170
|
export { DEFAULT_PRICING };
|