@stigmer/runner 3.12.4 → 3.12.6
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/dist/.build-fingerprint +1 -1
- package/dist/activities/call-agent.js +19 -6
- package/dist/activities/call-agent.js.map +1 -1
- package/dist/activities/execute-cursor/cursor-mcp-config.d.ts +45 -0
- package/dist/activities/execute-cursor/cursor-mcp-config.js +76 -0
- package/dist/activities/execute-cursor/cursor-mcp-config.js.map +1 -0
- package/dist/activities/execute-cursor/error-classifier.d.ts +9 -0
- package/dist/activities/execute-cursor/error-classifier.js +30 -1
- package/dist/activities/execute-cursor/error-classifier.js.map +1 -1
- package/dist/activities/execute-cursor/index.d.ts +10 -1
- package/dist/activities/execute-cursor/index.js +62 -36
- package/dist/activities/execute-cursor/index.js.map +1 -1
- package/dist/activities/execute-cursor/prompt-builder.d.ts +13 -2
- package/dist/activities/execute-cursor/prompt-builder.js +11 -0
- package/dist/activities/execute-cursor/prompt-builder.js.map +1 -1
- package/dist/activities/execute-cursor/service-tier.d.ts +38 -29
- package/dist/activities/execute-cursor/service-tier.js +92 -63
- package/dist/activities/execute-cursor/service-tier.js.map +1 -1
- package/dist/activities/execute-cursor/session-lifecycle.d.ts +1 -1
- package/dist/activities/execute-cursor/skill-resolver.d.ts +2 -21
- package/dist/activities/execute-cursor/skill-resolver.js +5 -108
- package/dist/activities/execute-cursor/skill-resolver.js.map +1 -1
- package/dist/activities/execute-cursor/usage-accumulator.d.ts +16 -2
- package/dist/activities/execute-cursor/usage-accumulator.js +12 -2
- package/dist/activities/execute-cursor/usage-accumulator.js.map +1 -1
- package/dist/activities/execute-deep-agent/approval-file-change.d.ts +9 -0
- package/dist/activities/execute-deep-agent/approval-file-change.js +2 -1
- package/dist/activities/execute-deep-agent/approval-file-change.js.map +1 -1
- package/dist/activities/execute-deep-agent/cas-capture-backend.d.ts +18 -1
- package/dist/activities/execute-deep-agent/cas-capture-backend.js +20 -3
- package/dist/activities/execute-deep-agent/cas-capture-backend.js.map +1 -1
- package/dist/activities/execute-deep-agent/index.js +57 -5
- package/dist/activities/execute-deep-agent/index.js.map +1 -1
- package/dist/activities/execute-deep-agent/prompt-builder.d.ts +9 -0
- package/dist/activities/execute-deep-agent/prompt-builder.js +10 -0
- package/dist/activities/execute-deep-agent/prompt-builder.js.map +1 -1
- package/dist/activities/execute-deep-agent/setup.js +17 -16
- package/dist/activities/execute-deep-agent/setup.js.map +1 -1
- package/dist/activities/execute-deep-agent/subagent-transformer.js +17 -11
- package/dist/activities/execute-deep-agent/subagent-transformer.js.map +1 -1
- package/dist/activities/execute-deep-agent/subagent-wiring.d.ts +3 -3
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/middleware/path-normalization.d.ts +49 -49
- package/dist/middleware/path-normalization.js +73 -84
- package/dist/middleware/path-normalization.js.map +1 -1
- package/dist/middleware/types.d.ts +3 -3
- package/dist/runner-manager.d.ts +1 -1
- package/dist/runner-manager.js +22 -15
- package/dist/runner-manager.js.map +1 -1
- package/dist/runner.js +11 -0
- package/dist/runner.js.map +1 -1
- package/dist/shared/args-preview.d.ts +8 -0
- package/dist/shared/args-preview.js +14 -3
- package/dist/shared/args-preview.js.map +1 -1
- package/dist/shared/artifact-storage.d.ts +11 -1
- package/dist/shared/artifact-storage.js +10 -1
- package/dist/shared/artifact-storage.js.map +1 -1
- package/dist/shared/caller-identity.d.ts +10 -7
- package/dist/shared/caller-identity.js +10 -7
- package/dist/shared/caller-identity.js.map +1 -1
- package/dist/shared/declared-preferences.d.ts +47 -0
- package/dist/shared/declared-preferences.js +64 -0
- package/dist/shared/declared-preferences.js.map +1 -0
- package/dist/shared/mcp-enabled-tools.d.ts +2 -3
- package/dist/shared/mcp-enabled-tools.js +2 -3
- package/dist/shared/mcp-enabled-tools.js.map +1 -1
- package/dist/shared/mcp-resolver.d.ts +20 -15
- package/dist/shared/mcp-resolver.js +11 -12
- package/dist/shared/mcp-resolver.js.map +1 -1
- package/dist/shared/placeholder-resolver.d.ts +9 -2
- package/dist/shared/placeholder-resolver.js +9 -2
- package/dist/shared/placeholder-resolver.js.map +1 -1
- package/dist/shared/plan-mode-permissions.d.ts +26 -46
- package/dist/shared/plan-mode-permissions.js +27 -55
- package/dist/shared/plan-mode-permissions.js.map +1 -1
- package/dist/shared/skill-mount.d.ts +89 -0
- package/dist/shared/skill-mount.js +142 -0
- package/dist/shared/skill-mount.js.map +1 -0
- package/dist/shared/skill-writer.d.ts +28 -26
- package/dist/shared/skill-writer.js +79 -102
- package/dist/shared/skill-writer.js.map +1 -1
- package/dist/shared/thinking-mode.d.ts +35 -0
- package/dist/shared/thinking-mode.js +43 -0
- package/dist/shared/thinking-mode.js.map +1 -0
- package/dist/shared/worker-shutdown.d.ts +67 -0
- package/dist/shared/worker-shutdown.js +79 -0
- package/dist/shared/worker-shutdown.js.map +1 -0
- package/dist/shared/workspace/types.d.ts +3 -2
- package/dist/workflow-engine/loader.js +82 -6
- package/dist/workflow-engine/loader.js.map +1 -1
- package/dist/workflow-engine/tasks/human-input.d.ts +2 -1
- package/dist/workflow-engine/tasks/human-input.js +31 -3
- package/dist/workflow-engine/tasks/human-input.js.map +1 -1
- package/dist/workflow-engine/types.d.ts +17 -3
- package/dist/workflow-engine/types.js.map +1 -1
- package/dist/workflows/human-input-orchestrator.d.ts +4 -0
- package/dist/workflows/human-input-orchestrator.js +13 -0
- package/dist/workflows/human-input-orchestrator.js.map +1 -1
- package/package.json +15 -11
- package/src/activities/call-agent.ts +20 -6
- package/src/activities/execute-cursor/__tests__/build-prompt.test.ts +50 -0
- package/src/activities/execute-cursor/__tests__/cursor-mcp-config.test.ts +111 -0
- package/src/activities/execute-cursor/__tests__/error-classifier-billing.test.ts +67 -0
- package/src/activities/execute-cursor/__tests__/service-tier.test.ts +67 -7
- package/src/activities/execute-cursor/__tests__/skill-resolver.test.ts +3 -94
- package/src/activities/execute-cursor/__tests__/usage-accumulator.test.ts +33 -1
- package/src/activities/execute-cursor/cursor-mcp-config.ts +107 -0
- package/src/activities/execute-cursor/error-classifier.ts +42 -1
- package/src/activities/execute-cursor/index.ts +78 -41
- package/src/activities/execute-cursor/prompt-builder.ts +29 -2
- package/src/activities/execute-cursor/service-tier.ts +94 -63
- package/src/activities/execute-cursor/session-lifecycle.ts +1 -1
- package/src/activities/execute-cursor/skill-resolver.ts +10 -137
- package/src/activities/execute-cursor/usage-accumulator.ts +11 -1
- package/src/activities/execute-deep-agent/__tests__/approval-file-change.test.ts +15 -0
- package/src/activities/execute-deep-agent/__tests__/cas-capture-backend.test.ts +75 -0
- package/src/activities/execute-deep-agent/__tests__/hitl-reject.test.ts +1 -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__/index.test.ts +1 -0
- package/src/activities/execute-deep-agent/__tests__/plan-mode-path-normalization.test.ts +42 -29
- package/src/activities/execute-deep-agent/__tests__/prompt-builder.test.ts +52 -0
- package/src/activities/execute-deep-agent/__tests__/sequential-gate-resume.test.ts +1 -0
- package/src/activities/execute-deep-agent/__tests__/subagent-plan-mode-permissions.test.ts +11 -8
- package/src/activities/execute-deep-agent/approval-file-change.ts +11 -1
- package/src/activities/execute-deep-agent/cas-capture-backend.ts +20 -3
- package/src/activities/execute-deep-agent/index.ts +57 -5
- package/src/activities/execute-deep-agent/prompt-builder.ts +22 -0
- package/src/activities/execute-deep-agent/setup.ts +21 -19
- package/src/activities/execute-deep-agent/subagent-transformer.ts +19 -12
- package/src/activities/execute-deep-agent/subagent-wiring.ts +3 -3
- package/src/index.ts +1 -1
- package/src/middleware/__tests__/path-normalization.test.ts +32 -32
- package/src/middleware/path-normalization.ts +78 -90
- package/src/middleware/types.ts +3 -3
- package/src/runner-manager.ts +26 -16
- package/src/runner.ts +14 -0
- package/src/shared/__tests__/artifact-storage.test.ts +28 -0
- package/src/shared/__tests__/bedrock-seam.test.ts +5 -5
- package/src/shared/__tests__/declared-preferences.test.ts +109 -0
- package/src/shared/__tests__/foundry-seam.test.ts +5 -5
- package/src/shared/__tests__/plan-mode-permissions.test.ts +15 -44
- package/src/shared/__tests__/skill-mount.test.ts +238 -0
- package/src/shared/__tests__/skill-writer.test.ts +151 -128
- package/src/shared/__tests__/vertex-adapter.test.ts +30 -3
- package/src/shared/__tests__/vertex-seam.test.ts +5 -5
- package/src/shared/__tests__/worker-shutdown.test.ts +101 -0
- package/src/shared/args-preview.ts +17 -3
- package/src/shared/artifact-storage.ts +20 -1
- package/src/shared/caller-identity.ts +10 -7
- package/src/shared/declared-preferences.ts +84 -0
- package/src/shared/mcp-enabled-tools.ts +2 -3
- package/src/shared/mcp-resolver.ts +20 -20
- package/src/shared/placeholder-resolver.ts +9 -2
- package/src/shared/plan-mode-permissions.ts +27 -58
- package/src/shared/skill-mount.ts +179 -0
- package/src/shared/skill-writer.ts +96 -130
- package/src/shared/thinking-mode.ts +52 -0
- package/src/shared/worker-shutdown.ts +99 -0
- package/src/shared/workspace/types.ts +3 -2
- package/src/workflow-engine/__tests__/loader.test.ts +95 -0
- package/src/workflow-engine/__tests__/tasks/human-input.test.ts +156 -0
- package/src/workflow-engine/loader.ts +97 -6
- package/src/workflow-engine/tasks/human-input.ts +41 -6
- package/src/workflow-engine/types.ts +18 -3
- package/src/workflows/human-input-orchestrator.ts +20 -2
- package/dist/activities/execute-cursor/connect-backfill.d.ts +0 -19
- package/dist/activities/execute-cursor/connect-backfill.js +0 -27
- package/dist/activities/execute-cursor/connect-backfill.js.map +0 -1
- package/dist/activities/execute-cursor/mcp-resolver.d.ts +0 -120
- package/dist/activities/execute-cursor/mcp-resolver.js +0 -194
- package/dist/activities/execute-cursor/mcp-resolver.js.map +0 -1
- package/dist/activities/execute-cursor/placeholder-resolver.d.ts +0 -34
- package/dist/activities/execute-cursor/placeholder-resolver.js +0 -82
- package/dist/activities/execute-cursor/placeholder-resolver.js.map +0 -1
- package/src/activities/execute-cursor/__tests__/mcp-resolver.test.ts +0 -125
- package/src/activities/execute-cursor/connect-backfill.ts +0 -52
- package/src/activities/execute-cursor/mcp-resolver.ts +0 -324
- package/src/activities/execute-cursor/placeholder-resolver.ts +0 -109
|
@@ -56,6 +56,7 @@ import {
|
|
|
56
56
|
resolveCallerIdentity,
|
|
57
57
|
} from "../../shared/caller-identity.js";
|
|
58
58
|
import { readSessionContext } from "../../shared/session-context.js";
|
|
59
|
+
import { readDeclaredPreferences } from "../../shared/declared-preferences.js";
|
|
59
60
|
import { withholdSecretContentFromMessages } from "../../shared/tool-row.js";
|
|
60
61
|
import { StallTimeoutError, formatStallFailure } from "../../shared/stall-watchdog.js";
|
|
61
62
|
import { resolveUsableArtifactStorage, loadArtifactStorageConfig, type ArtifactStorage } from "../../shared/artifact-storage.js";
|
|
@@ -71,7 +72,8 @@ import { DeltaEnricher } from "./delta-enricher.js";
|
|
|
71
72
|
import { TodoTracker } from "./todo-tracker.js";
|
|
72
73
|
import { StreamingUpdateScheduler, loadStreamingConfig } from "../../shared/streaming-scheduler.js";
|
|
73
74
|
import { createCursorEventRecorder } from "./cursor-event-recorder.js";
|
|
74
|
-
import { resolveMcpServers
|
|
75
|
+
import { resolveMcpServers } from "../../shared/mcp-resolver.js";
|
|
76
|
+
import { toCursorMcpConfig, validateMcpServerEnv } from "./cursor-mcp-config.js";
|
|
75
77
|
import { resolveMcpTransportPosture } from "../../shared/mcp-transport-guard.js";
|
|
76
78
|
import {
|
|
77
79
|
discoverChannelMessaging,
|
|
@@ -85,7 +87,7 @@ import { injectSynthesizedAttachment } from "../../shared/synthesized-attachment
|
|
|
85
87
|
import { mergeApprovalPolicies } from "./approval-policy.js";
|
|
86
88
|
import { deriveActiveLeases, isUnattendedApprovalMode } from "../../shared/approval-policy.js";
|
|
87
89
|
import { enabledToolsBySlug } from "../../shared/mcp-enabled-tools.js";
|
|
88
|
-
import { backfillMcpServersIfNeeded } from "
|
|
90
|
+
import { backfillMcpServersIfNeeded } from "../../shared/connect-backfill.js";
|
|
89
91
|
import { resolveExecutionEnv } from "./env-resolver.js";
|
|
90
92
|
import { resolveBlueprint } from "./blueprint-resolver.js";
|
|
91
93
|
import { buildCursorSubAgentDefinitions } from "./subagent-config.js";
|
|
@@ -136,6 +138,7 @@ import { setInterceptorExecutionId, runWithExecutionContext } from "./fetch-inte
|
|
|
136
138
|
import { closeProxySessions } from "./http2-interceptor.js";
|
|
137
139
|
import { resolveModelId, ensureLoaded as ensurePricingLoaded } from "./model-pricing.js";
|
|
138
140
|
import { resolveEffectiveServiceTier } from "../../shared/service-tier.js";
|
|
141
|
+
import { resolveEffectiveThinkingMode } from "../../shared/thinking-mode.js";
|
|
139
142
|
import { resolveServiceTierParams } from "./service-tier.js";
|
|
140
143
|
import { UsageAccumulator } from "./usage-accumulator.js";
|
|
141
144
|
import { StreamingUsageSummarySchema } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/usage_pb";
|
|
@@ -147,7 +150,7 @@ import type { ClassifiedError } from "./error-classifier.js";
|
|
|
147
150
|
import { createAgent, createCloudAgent } from "./session-lifecycle.js";
|
|
148
151
|
import { setMaxListeners } from "node:events";
|
|
149
152
|
import { startHeartbeat } from "../../shared/heartbeat.js";
|
|
150
|
-
import { getShutdownSignalForQueue } from "../../
|
|
153
|
+
import { classifyTurnInterruption, getShutdownSignalForQueue } from "../../shared/worker-shutdown.js";
|
|
151
154
|
|
|
152
155
|
/**
|
|
153
156
|
* Creates the activity functions bound to the runner config.
|
|
@@ -627,16 +630,19 @@ async function executeCursorInner(
|
|
|
627
630
|
),
|
|
628
631
|
sessionId,
|
|
629
632
|
);
|
|
630
|
-
|
|
633
|
+
// The resolved-server list mutates through backfill and attachment
|
|
634
|
+
// injection below; the Cursor SDK config is projected from it exactly
|
|
635
|
+
// once, after the last mutation (see toCursorMcpConfig).
|
|
636
|
+
let resolvedMcpServers = (await resolveMcpServers(
|
|
631
637
|
client, blueprint.mergedMcpServerUsages, mcpEnvVars, transportPosture,
|
|
632
|
-
);
|
|
638
|
+
)).resolvedServers;
|
|
633
639
|
setupTiming.mark("resolve_mcp_servers");
|
|
634
640
|
|
|
635
641
|
// Phase 4a: Connect backfill for undiscovered MCP servers
|
|
636
642
|
heartbeatPhase = "resolving_mcp_servers";
|
|
637
643
|
const sessionOrg = session.metadata?.org ?? "";
|
|
638
|
-
|
|
639
|
-
client,
|
|
644
|
+
resolvedMcpServers = await backfillMcpServersIfNeeded(
|
|
645
|
+
client, resolvedMcpServers, blueprint.mergedMcpServerUsages, mcpEnvVars, sessionOrg,
|
|
640
646
|
transportPosture, heartbeat, secretKeys,
|
|
641
647
|
);
|
|
642
648
|
setupTiming.mark("backfill_mcp");
|
|
@@ -684,13 +690,9 @@ async function executeCursorInner(
|
|
|
684
690
|
backendEndpoint: config.stigmerBackendEndpoint,
|
|
685
691
|
});
|
|
686
692
|
if (attachment) {
|
|
687
|
-
|
|
688
|
-
|
|
693
|
+
resolvedMcpServers = injectSynthesizedAttachment(
|
|
694
|
+
resolvedMcpServers, attachment, "channel messaging",
|
|
689
695
|
);
|
|
690
|
-
mcpResolution = {
|
|
691
|
-
resolvedServers,
|
|
692
|
-
cursorConfig: toCursorMcpConfig(resolvedServers),
|
|
693
|
-
};
|
|
694
696
|
}
|
|
695
697
|
}
|
|
696
698
|
|
|
@@ -710,15 +712,13 @@ async function executeCursorInner(
|
|
|
710
712
|
},
|
|
711
713
|
);
|
|
712
714
|
if (conversationAttachment) {
|
|
713
|
-
|
|
714
|
-
|
|
715
|
+
resolvedMcpServers = injectSynthesizedAttachment(
|
|
716
|
+
resolvedMcpServers, conversationAttachment, "conversation participation",
|
|
715
717
|
);
|
|
716
|
-
mcpResolution = {
|
|
717
|
-
resolvedServers,
|
|
718
|
-
cursorConfig: toCursorMcpConfig(resolvedServers),
|
|
719
|
-
};
|
|
720
718
|
}
|
|
721
|
-
|
|
719
|
+
// The one projection point: every mutation above is now visible in the
|
|
720
|
+
// Cursor SDK config by construction (no per-mutation rebuild to forget).
|
|
721
|
+
const mcpConfig = toCursorMcpConfig(resolvedMcpServers);
|
|
722
722
|
|
|
723
723
|
// Phase 4b: Merge approval policies from all layers.
|
|
724
724
|
//
|
|
@@ -734,16 +734,15 @@ async function executeCursorInner(
|
|
|
734
734
|
// see ResolvedMcpServer.toolApprovalOverrides (issue #349) — so there
|
|
735
735
|
// is no separate override input to pass here.
|
|
736
736
|
const mergedPolicies = mergeApprovalPolicies(
|
|
737
|
-
|
|
737
|
+
resolvedMcpServers,
|
|
738
738
|
leases,
|
|
739
739
|
);
|
|
740
740
|
heartbeat();
|
|
741
741
|
|
|
742
742
|
// Phase 4c: Validate MCP server env health (diagnostic, non-blocking)
|
|
743
743
|
const mcpWarnings = validateMcpServerEnv(
|
|
744
|
-
|
|
744
|
+
resolvedMcpServers,
|
|
745
745
|
blueprint.mergedMcpServerUsages,
|
|
746
|
-
envVars,
|
|
747
746
|
);
|
|
748
747
|
if (mcpWarnings.length > 0) {
|
|
749
748
|
console.warn(
|
|
@@ -910,7 +909,7 @@ async function executeCursorInner(
|
|
|
910
909
|
// servers' allow-lists, enforced by the hook's "disabled" arm ahead of
|
|
911
910
|
// every approval bypass. The Cursor SDK config cannot hide a server's
|
|
912
911
|
// tools, so this deny-at-call is the harness's enforcement.
|
|
913
|
-
enabledToolsBySlug(
|
|
912
|
+
enabledToolsBySlug(resolvedMcpServers),
|
|
914
913
|
);
|
|
915
914
|
const hitlGate = await installHitlGate({
|
|
916
915
|
workspaceRoot: primaryWorkspaceDir,
|
|
@@ -962,9 +961,10 @@ async function executeCursorInner(
|
|
|
962
961
|
await ensurePricingLoaded();
|
|
963
962
|
setupTiming.mark("load_pricing");
|
|
964
963
|
|
|
965
|
-
// Phase 6: Validate model selection and resolve the
|
|
966
|
-
// UNSPECIFIED → STANDARD
|
|
967
|
-
// upstream layer preserves the
|
|
964
|
+
// Phase 6: Validate model selection and resolve the variant attributes.
|
|
965
|
+
// UNSPECIFIED → STANDARD (#357) and UNSPECIFIED → DISABLED (#772)
|
|
966
|
+
// resolve here and nowhere else: every upstream layer preserves the
|
|
967
|
+
// caller's raw enum values.
|
|
968
968
|
const requestedModel = spec.executionConfig?.modelName || "default";
|
|
969
969
|
const validatedModel = resolveModelId(requestedModel);
|
|
970
970
|
if (validatedModel !== requestedModel) {
|
|
@@ -973,6 +973,7 @@ async function executeCursorInner(
|
|
|
973
973
|
);
|
|
974
974
|
}
|
|
975
975
|
const requestedServiceTier = resolveEffectiveServiceTier(spec.executionConfig?.serviceTier);
|
|
976
|
+
const requestedThinkingMode = resolveEffectiveThinkingMode(spec.executionConfig?.thinkingMode);
|
|
976
977
|
|
|
977
978
|
heartbeat();
|
|
978
979
|
|
|
@@ -1007,13 +1008,15 @@ async function executeCursorInner(
|
|
|
1007
1008
|
);
|
|
1008
1009
|
}
|
|
1009
1010
|
|
|
1010
|
-
// Translate the tier into the explicit variant params
|
|
1011
|
-
// create/resume. Never a bare { id }: the catalog's
|
|
1012
|
-
// account-influenced and picks the
|
|
1011
|
+
// Translate the tier + thinking mode into the explicit variant params
|
|
1012
|
+
// sent with every create/resume. Never a bare { id }: the catalog's
|
|
1013
|
+
// default variant is account-influenced and picks the served variant
|
|
1014
|
+
// (#357 fast pricing, #772 thinking).
|
|
1013
1015
|
const modelParams = await resolveServiceTierParams({
|
|
1014
1016
|
apiKey: effectiveApiKey,
|
|
1015
1017
|
modelId: validatedModel,
|
|
1016
1018
|
tier: requestedServiceTier,
|
|
1019
|
+
thinking: requestedThinkingMode,
|
|
1017
1020
|
executionId,
|
|
1018
1021
|
});
|
|
1019
1022
|
|
|
@@ -1175,6 +1178,7 @@ async function executeCursorInner(
|
|
|
1175
1178
|
contextBridge: readContextBridge(blueprint.sessionSpec.metadata),
|
|
1176
1179
|
senderIdentity: readSenderIdentity(blueprint.sessionSpec.metadata),
|
|
1177
1180
|
sessionContext: readSessionContext(blueprint.sessionSpec.metadata),
|
|
1181
|
+
declaredPreferences: readDeclaredPreferences(spec.declaredPreferences),
|
|
1178
1182
|
conversationCatchup: readConversationCatchup(spec.conversationCatchup),
|
|
1179
1183
|
// The turn's recorded transcript, seeded from the persisted execution
|
|
1180
1184
|
// on a reinvocation (Phase 3). Consumed only by the HITL-recovery
|
|
@@ -1229,6 +1233,7 @@ async function executeCursorInner(
|
|
|
1229
1233
|
validatedModel,
|
|
1230
1234
|
requestedServiceTier,
|
|
1231
1235
|
modelParams,
|
|
1236
|
+
requestedThinkingMode,
|
|
1232
1237
|
);
|
|
1233
1238
|
|
|
1234
1239
|
// Phase 10c: Start OTel turn span. Coarse-grained — spans the whole turn
|
|
@@ -1401,13 +1406,21 @@ async function executeCursorInner(
|
|
|
1401
1406
|
// classifies a shutdown from the shutdown signal directly (in
|
|
1402
1407
|
// resolvePreBoundaryTerminal). The heartbeat timer may set `cancelled` before
|
|
1403
1408
|
// the AbortSignal microtask propagates; the direct signal check catches that.
|
|
1404
|
-
|
|
1405
|
-
|
|
1409
|
+
// The decision table (including #776's grace-window guard: an aborted
|
|
1410
|
+
// shutdown signal with NO interruption evidence stays "none") lives in
|
|
1411
|
+
// classifyTurnInterruption — shared/worker-shutdown.ts.
|
|
1412
|
+
const interruption = classifyTurnInterruption({
|
|
1413
|
+
heartbeatCancelled: periodicHeartbeat.cancelled,
|
|
1414
|
+
heartbeatWorkerShutdown: periodicHeartbeat.workerShutdown,
|
|
1415
|
+
cancellationSignalAborted: Context.current().cancellationSignal.aborted,
|
|
1416
|
+
shutdownSignalAborted: shutdownSignal?.aborted ?? false,
|
|
1417
|
+
});
|
|
1418
|
+
if (interruption === "worker-shutdown") {
|
|
1406
1419
|
turnState.pauseDetected = false;
|
|
1407
|
-
} else if (
|
|
1420
|
+
} else if (interruption === "pause") {
|
|
1408
1421
|
turnState.pauseDetected = true;
|
|
1409
1422
|
}
|
|
1410
|
-
workerShutdownDetected =
|
|
1423
|
+
workerShutdownDetected = interruption === "worker-shutdown";
|
|
1411
1424
|
|
|
1412
1425
|
// Post-stream finalize, shared by the primary turn and both recovery retries:
|
|
1413
1426
|
// finalize the transcript + streaming flags, mark any in-flight sub-agent
|
|
@@ -1505,10 +1518,16 @@ async function executeCursorInner(
|
|
|
1505
1518
|
return { kind: "return" };
|
|
1506
1519
|
}
|
|
1507
1520
|
|
|
1508
|
-
// Worker shutdown: the runner
|
|
1521
|
+
// Worker shutdown: the runner/manager aborted the shutdown signal. NOT a
|
|
1509
1522
|
// user pause. Checked via the shutdown signal directly so a retry (whose
|
|
1510
|
-
// periodic heartbeat is already stopped) still classifies it correctly
|
|
1511
|
-
|
|
1523
|
+
// periodic heartbeat is already stopped) still classifies it correctly —
|
|
1524
|
+
// but only alongside a delivered cancellation: a retry that completed
|
|
1525
|
+
// normally inside the drain grace window must stay a completion (#776's
|
|
1526
|
+
// grace-window guard, mirroring the primary's `interrupted` gate).
|
|
1527
|
+
if (
|
|
1528
|
+
workerShutdownDetected ||
|
|
1529
|
+
((shutdownSignal?.aborted ?? false) && Context.current().cancellationSignal.aborted)
|
|
1530
|
+
) {
|
|
1512
1531
|
status.phase = ExecutionPhase.EXECUTION_FAILED;
|
|
1513
1532
|
status.error = "Execution interrupted: runner worker was shut down. Retry or resume.";
|
|
1514
1533
|
status.completedAt = utcTimestamp();
|
|
@@ -1806,6 +1825,7 @@ async function executeCursorInner(
|
|
|
1806
1825
|
fallbackContext: { model: validatedModel, mode: agentMode, agentId: resolution.agentId },
|
|
1807
1826
|
durationMs: (result as unknown as Record<string, unknown>).durationMs as number | undefined,
|
|
1808
1827
|
messageCount: status.messages.length,
|
|
1828
|
+
proxyMode: !!config.proxyEndpoint,
|
|
1809
1829
|
});
|
|
1810
1830
|
|
|
1811
1831
|
console.error(
|
|
@@ -1865,6 +1885,7 @@ async function executeCursorInner(
|
|
|
1865
1885
|
contextBridge: readContextBridge(blueprint.sessionSpec.metadata),
|
|
1866
1886
|
senderIdentity: readSenderIdentity(blueprint.sessionSpec.metadata),
|
|
1867
1887
|
sessionContext: readSessionContext(blueprint.sessionSpec.metadata),
|
|
1888
|
+
declaredPreferences: readDeclaredPreferences(spec.declaredPreferences),
|
|
1868
1889
|
conversationCatchup: readConversationCatchup(spec.conversationCatchup),
|
|
1869
1890
|
// Composed fresh (not reused from Phase 10): the failed primary
|
|
1870
1891
|
// stream may have appended partial work onto status.messages,
|
|
@@ -1944,6 +1965,7 @@ async function executeCursorInner(
|
|
|
1944
1965
|
conversationErrorText: retryConversationErrorText,
|
|
1945
1966
|
isResumedHandle: false,
|
|
1946
1967
|
fallbackContext: { model: validatedModel, mode: agentMode, agentId: freshAgent.agentId },
|
|
1968
|
+
proxyMode: !!config.proxyEndpoint,
|
|
1947
1969
|
});
|
|
1948
1970
|
|
|
1949
1971
|
status.phase = ExecutionPhase.EXECUTION_FAILED;
|
|
@@ -2150,9 +2172,12 @@ async function executeCursorInner(
|
|
|
2150
2172
|
periodicHeartbeat?.stop();
|
|
2151
2173
|
|
|
2152
2174
|
if (err instanceof CancelledFailure) {
|
|
2153
|
-
//
|
|
2154
|
-
//
|
|
2155
|
-
|
|
2175
|
+
// Worker shutdown is infrastructure failure, not pause. The direct
|
|
2176
|
+
// signal check covers a CancelledFailure thrown BEFORE the post-stream
|
|
2177
|
+
// classification ran (workerShutdownDetected still false); no extra
|
|
2178
|
+
// interruption-evidence gate is needed here — the caught
|
|
2179
|
+
// CancelledFailure IS the evidence (#776).
|
|
2180
|
+
if (workerShutdownDetected || (shutdownSignal?.aborted ?? false)) {
|
|
2156
2181
|
console.log(`ExecuteCursor cancelled (worker shutdown) for execution ${executionId}`);
|
|
2157
2182
|
status.phase = ExecutionPhase.EXECUTION_FAILED;
|
|
2158
2183
|
status.error = "Execution interrupted: runner worker was shut down. Retry or resume.";
|
|
@@ -2242,6 +2267,7 @@ async function executeCursorInner(
|
|
|
2242
2267
|
capturedRejection: getCapturedRejection(executionId),
|
|
2243
2268
|
isResumedHandle: false,
|
|
2244
2269
|
fallbackContext: errorContext,
|
|
2270
|
+
proxyMode: !!config.proxyEndpoint,
|
|
2245
2271
|
});
|
|
2246
2272
|
clearCapturedRejection(executionId);
|
|
2247
2273
|
status.phase = ExecutionPhase.EXECUTION_FAILED;
|
|
@@ -2451,10 +2477,19 @@ export interface BuildPromptInput {
|
|
|
2451
2477
|
* turn.
|
|
2452
2478
|
*/
|
|
2453
2479
|
sessionContext?: string;
|
|
2480
|
+
/**
|
|
2481
|
+
* Platform-declared standing preferences from the execution spec's
|
|
2482
|
+
* `declared_preferences` (stigmer/stigmer#293). Like the bridge, only
|
|
2483
|
+
* the enhanced-prompt path consumes it — deliberately frozen per Cursor
|
|
2484
|
+
* session (DD-002 D3): the first turn delivers it into the agent's own
|
|
2485
|
+
* conversation store, and repeating it on resumed turns would bloat the
|
|
2486
|
+
* store with identical content.
|
|
2487
|
+
*/
|
|
2488
|
+
declaredPreferences?: import("../../shared/declared-preferences.js").DeclaredPreferencesContent;
|
|
2454
2489
|
/**
|
|
2455
2490
|
* Conversation catchup from the execution spec's `conversation_catchup`
|
|
2456
2491
|
* (cloud DD-006): what happened on the channel conversation that the
|
|
2457
|
-
* agent has not seen. PER-TURN, so unlike the
|
|
2492
|
+
* agent has not seen. PER-TURN, so unlike the standing values
|
|
2458
2493
|
* above it rides BOTH prompt paths — the enhanced prompt and a resumed
|
|
2459
2494
|
* turn's prefix (the `interaction_mode` shape). Handback lands
|
|
2460
2495
|
* mid-session on a resumed agent: the resumed path is the one that
|
|
@@ -2589,6 +2624,7 @@ export function buildPrompt(input: BuildPromptInput): string {
|
|
|
2589
2624
|
contextBridge: input.contextBridge,
|
|
2590
2625
|
senderIdentity: input.senderIdentity,
|
|
2591
2626
|
sessionContext: input.sessionContext,
|
|
2627
|
+
declaredPreferences: input.declaredPreferences,
|
|
2592
2628
|
conversationCatchup,
|
|
2593
2629
|
},
|
|
2594
2630
|
{
|
|
@@ -2655,6 +2691,7 @@ export function buildPrompt(input: BuildPromptInput): string {
|
|
|
2655
2691
|
contextBridge: input.contextBridge,
|
|
2656
2692
|
senderIdentity: input.senderIdentity,
|
|
2657
2693
|
sessionContext: input.sessionContext,
|
|
2694
|
+
declaredPreferences: input.declaredPreferences,
|
|
2658
2695
|
conversationCatchup,
|
|
2659
2696
|
});
|
|
2660
2697
|
}
|
|
@@ -31,6 +31,10 @@ import {
|
|
|
31
31
|
type SenderIdentity,
|
|
32
32
|
} from "../../shared/sender-identity.js";
|
|
33
33
|
import { formatSessionContextText } from "../../shared/session-context.js";
|
|
34
|
+
import {
|
|
35
|
+
formatDeclaredPreferencesText,
|
|
36
|
+
type DeclaredPreferencesContent,
|
|
37
|
+
} from "../../shared/declared-preferences.js";
|
|
34
38
|
import {
|
|
35
39
|
visionDisclosureLines,
|
|
36
40
|
type NotViewableEntry,
|
|
@@ -147,11 +151,20 @@ export interface EnhancedPromptOptions {
|
|
|
147
151
|
* store — the context is constant for the session's lifetime.
|
|
148
152
|
*/
|
|
149
153
|
sessionContext?: string;
|
|
154
|
+
/**
|
|
155
|
+
* Platform-declared standing preferences (stigmer/stigmer#293): the org's
|
|
156
|
+
* and user's standing context, server-snapshotted onto the execution
|
|
157
|
+
* spec's `declared_preferences` at create. Like the bridge, it lands in
|
|
158
|
+
* the first message and persists in the cursor agent's own conversation
|
|
159
|
+
* store — deliberately frozen per Cursor session (DD-002 D3): repeating
|
|
160
|
+
* it every resumed turn would bloat the store with identical content.
|
|
161
|
+
*/
|
|
162
|
+
declaredPreferences?: DeclaredPreferencesContent;
|
|
150
163
|
/**
|
|
151
164
|
* Conversation catchup (cloud DD-006): what happened on the channel
|
|
152
165
|
* conversation that the agent has not seen, read from the execution
|
|
153
|
-
* spec's `conversation_catchup`. PER-TURN, unlike the
|
|
154
|
-
*
|
|
166
|
+
* spec's `conversation_catchup`. PER-TURN, unlike the standing siblings
|
|
167
|
+
* above: it rides BOTH prompt paths — this enhanced prompt and
|
|
155
168
|
* a resumed turn's prefix (the `interaction_mode` shape) — because
|
|
156
169
|
* handback lands mid-session on a resumed agent, the exact case the
|
|
157
170
|
* metadata lane cannot reach.
|
|
@@ -232,6 +245,14 @@ export function buildEnhancedPrompt(options: EnhancedPromptOptions): string {
|
|
|
232
245
|
sections.push(formatSenderIdentitySection(options.senderIdentity));
|
|
233
246
|
}
|
|
234
247
|
|
|
248
|
+
// Platform-declared standing facts precede embedder-supplied context
|
|
249
|
+
// (DD-002 D3): both are standing background, but the declared preferences
|
|
250
|
+
// are platform-authored while session context is the embedder's overlay —
|
|
251
|
+
// the more specific overlay reads later and naturally refines.
|
|
252
|
+
if (options.declaredPreferences) {
|
|
253
|
+
sections.push(formatDeclaredPreferencesSection(options.declaredPreferences));
|
|
254
|
+
}
|
|
255
|
+
|
|
235
256
|
// Standing facts about the user (session context) come before the
|
|
236
257
|
// carried conversation (bridge): the bridge may refer back to them.
|
|
237
258
|
if (options.sessionContext) {
|
|
@@ -445,6 +466,12 @@ export function formatSenderIdentitySection(identity: SenderIdentity): string {
|
|
|
445
466
|
return `<conversation_sender>\n${formatSenderIdentityText(identity)}\n</conversation_sender>`;
|
|
446
467
|
}
|
|
447
468
|
|
|
469
|
+
export function formatDeclaredPreferencesSection(
|
|
470
|
+
preferences: DeclaredPreferencesContent,
|
|
471
|
+
): string {
|
|
472
|
+
return `<declared_preferences>\n${formatDeclaredPreferencesText(preferences)}\n</declared_preferences>`;
|
|
473
|
+
}
|
|
474
|
+
|
|
448
475
|
export function formatSessionContextSection(context: string): string {
|
|
449
476
|
return `<session_context>\n${formatSessionContextText(context)}\n</session_context>`;
|
|
450
477
|
}
|
|
@@ -1,18 +1,23 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Variant-attribute → Cursor variant-parameter translation
|
|
3
|
+
* (stigmer/stigmer#357 service tier, #772 thinking mode).
|
|
3
4
|
*
|
|
4
5
|
* The platform contract: an execution's model selection is ALWAYS explicit.
|
|
5
|
-
* A bare `{ id }` lets the Cursor catalog's default variant decide the
|
|
6
|
-
* (observed 2026-08-06: composer-2.5 defaults to fast=true at ~4x
|
|
7
|
-
* rates, claude-haiku-4-5 to thinking=true), and that default follows
|
|
8
|
-
* out-of-band account setting. This module pins every
|
|
9
|
-
* parameter the model declares, so the
|
|
10
|
-
* function of
|
|
6
|
+
* A bare `{ id }` lets the Cursor catalog's default variant decide the
|
|
7
|
+
* variant (observed 2026-08-06: composer-2.5 defaults to fast=true at ~4x
|
|
8
|
+
* base rates, claude-haiku-4-5 to thinking=true), and that default follows
|
|
9
|
+
* an out-of-band account setting. This module pins every user-selectable
|
|
10
|
+
* variant parameter the model declares, so the served variant is a
|
|
11
|
+
* deterministic function of the execution config:
|
|
11
12
|
*
|
|
12
|
-
* -
|
|
13
|
-
*
|
|
14
|
-
* -
|
|
15
|
-
*
|
|
13
|
+
* - fast: pinned from ExecutionConfig.service_tier (FAST → true).
|
|
14
|
+
* Price-bearing — the fast variant bills at pricingVariants.fast rates.
|
|
15
|
+
* - thinking: pinned from ExecutionConfig.thinking_mode (ENABLED → true).
|
|
16
|
+
* Per-token price-neutral (ledger-verified 2026-08-15: thinking wire ids
|
|
17
|
+
* bill exactly base rates; thinking+fast bills exactly the fast rate) —
|
|
18
|
+
* pinned anyway because the served variant must never follow the account
|
|
19
|
+
* default, and ENABLED turns consume more output (reasoning) tokens.
|
|
20
|
+
* - Parameters that are neither (e.g. effort) are deliberately NOT pinned —
|
|
16
21
|
* they follow the catalog default and do not change the bill.
|
|
17
22
|
*
|
|
18
23
|
* Parameter bundles come from Cursor.models.list() (worker-cached): the
|
|
@@ -20,17 +25,19 @@
|
|
|
20
25
|
* rides the same proxy fetch-interceptor as every other SDK call, so it
|
|
21
26
|
* works identically in proxy and direct modes.
|
|
22
27
|
*
|
|
23
|
-
* The harness-neutral halves — the
|
|
24
|
-
* UNSPECIFIED→
|
|
25
|
-
*
|
|
26
|
-
*
|
|
28
|
+
* The harness-neutral halves — the enum semantics and the single
|
|
29
|
+
* UNSPECIFIED→default resolution points — live in `shared/service-tier.ts`
|
|
30
|
+
* (since #361 extended tiers to the native harness) and
|
|
31
|
+
* `shared/thinking-mode.ts`; this module keeps only the Cursor-catalog
|
|
32
|
+
* translation.
|
|
27
33
|
*/
|
|
28
34
|
|
|
29
35
|
import { Cursor } from "@cursor/sdk";
|
|
30
36
|
import type { ModelListItem, ModelParameterValue } from "@cursor/sdk";
|
|
31
|
-
import { ServiceTier } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
|
|
37
|
+
import { ServiceTier, ThinkingMode } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
|
|
32
38
|
|
|
33
39
|
import { serviceTierLabel, type EffectiveServiceTier } from "../../shared/service-tier.js";
|
|
40
|
+
import { thinkingModeLabel, type EffectiveThinkingMode } from "../../shared/thinking-mode.js";
|
|
34
41
|
|
|
35
42
|
/**
|
|
36
43
|
* Catalog ids that mean "Cursor picks the model" (Auto). Auto's single
|
|
@@ -42,9 +49,11 @@ import { serviceTierLabel, type EffectiveServiceTier } from "../../shared/servic
|
|
|
42
49
|
const AUTO_MODEL_IDS = new Set(["default", "auto"]);
|
|
43
50
|
|
|
44
51
|
/**
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
52
|
+
* The user-selectable variant parameter ids. Pinning exactly these keeps
|
|
53
|
+
* the served variant deterministic while leaving effort knobs on their
|
|
54
|
+
* catalog defaults. `fast` changes the per-token price; `thinking` is
|
|
55
|
+
* price-neutral but changes token consumption and must never follow the
|
|
56
|
+
* account default. Sourced from the Cursor catalog survey
|
|
48
57
|
* (stigmer-cloud _projects/2026-08/20260806.04.model-service-tier).
|
|
49
58
|
*/
|
|
50
59
|
const FAST_PARAM_ID = "fast";
|
|
@@ -108,46 +117,55 @@ export interface ResolveServiceTierParamsOptions {
|
|
|
108
117
|
/** Validated model id the execution runs on (may be "default" for Auto). */
|
|
109
118
|
readonly modelId: string;
|
|
110
119
|
readonly tier: EffectiveServiceTier;
|
|
120
|
+
readonly thinking: EffectiveThinkingMode;
|
|
111
121
|
/** For log correlation only. */
|
|
112
122
|
readonly executionId: string;
|
|
113
123
|
}
|
|
114
124
|
|
|
115
125
|
/**
|
|
116
|
-
* Translate the effective tier into the explicit variant
|
|
117
|
-
* with every Agent.create/resume for this execution.
|
|
126
|
+
* Translate the effective tier + thinking mode into the explicit variant
|
|
127
|
+
* parameters to send with every Agent.create/resume for this execution.
|
|
118
128
|
*
|
|
119
|
-
* Fail-closed posture:
|
|
120
|
-
* never a silent downgrade —
|
|
121
|
-
*
|
|
122
|
-
* must be heard about, not
|
|
129
|
+
* Fail-closed posture: an ACTIVE selection (FAST tier, ENABLED thinking)
|
|
130
|
+
* with no pinnable dimension is an error, never a silent downgrade —
|
|
131
|
+
* create-time validation makes this unreachable unless the registry and the
|
|
132
|
+
* provider catalog have drifted, and that drift must be heard about, not
|
|
133
|
+
* absorbed.
|
|
123
134
|
*
|
|
124
|
-
* STANDARD degrades to empty params on
|
|
125
|
-
* the execution — but be clear about
|
|
126
|
-
*
|
|
127
|
-
*
|
|
128
|
-
* exists to prevent). Failing every
|
|
129
|
-
* endpoint blips would be the worse trade; the WARN
|
|
130
|
-
* requested-vs-billed mismatch
|
|
131
|
-
* are the compensating controls.
|
|
135
|
+
* The base selection (STANDARD + DISABLED) degrades to empty params on
|
|
136
|
+
* catalog failures rather than failing the execution — but be clear about
|
|
137
|
+
* what that costs: an unpinned selection falls to the catalog default
|
|
138
|
+
* variant, which for several models IS the fast/thinking variant (the
|
|
139
|
+
* incident this module exists to prevent). Failing every base execution
|
|
140
|
+
* whenever the catalog endpoint blips would be the worse trade; the WARN
|
|
141
|
+
* below plus billing's requested-vs-billed mismatch alarms (which catch
|
|
142
|
+
* exactly this window) are the compensating controls.
|
|
132
143
|
*/
|
|
133
144
|
export async function resolveServiceTierParams(
|
|
134
145
|
options: ResolveServiceTierParamsOptions,
|
|
135
146
|
): Promise<ModelParameterValue[]> {
|
|
136
|
-
const { apiKey, modelId, tier, executionId } = options;
|
|
147
|
+
const { apiKey, modelId, tier, thinking, executionId } = options;
|
|
137
148
|
const tierName = serviceTierLabel(tier);
|
|
149
|
+
const thinkingName = thinkingModeLabel(thinking);
|
|
150
|
+
// Selections that actively deviate from the base variant must fail loudly
|
|
151
|
+
// when they cannot be pinned; the base selection may degrade with a WARN.
|
|
152
|
+
const active: string[] = [];
|
|
153
|
+
if (tier === ServiceTier.FAST) active.push("service_tier=fast");
|
|
154
|
+
if (thinking === ThinkingMode.ENABLED) active.push("thinking=enabled");
|
|
138
155
|
|
|
139
156
|
if (AUTO_MODEL_IDS.has(modelId)) {
|
|
140
|
-
if (
|
|
157
|
+
if (active.length > 0) {
|
|
141
158
|
throw new Error(
|
|
142
|
-
|
|
143
|
-
`
|
|
144
|
-
`create time; the model registry and provider catalog may
|
|
159
|
+
`${active.join(" + ")} requires a pinned model — Auto ("${modelId}") has ` +
|
|
160
|
+
`no variant dimensions. Execution ${executionId} should have been ` +
|
|
161
|
+
`refused at create time; the model registry and provider catalog may ` +
|
|
162
|
+
`have drifted.`,
|
|
145
163
|
);
|
|
146
164
|
}
|
|
147
165
|
console.log(
|
|
148
|
-
`
|
|
149
|
-
`Auto has no variant parameters; Cursor picks
|
|
150
|
-
`(documented v1 limitation).`,
|
|
166
|
+
`VariantParams: execution=${executionId} model=${modelId} tier=${tierName} ` +
|
|
167
|
+
`thinking=${thinkingName} — Auto has no variant parameters; Cursor picks ` +
|
|
168
|
+
`the model and variant (documented v1 limitation).`,
|
|
151
169
|
);
|
|
152
170
|
return [];
|
|
153
171
|
}
|
|
@@ -156,37 +174,38 @@ export async function resolveServiceTierParams(
|
|
|
156
174
|
try {
|
|
157
175
|
models = await listCatalogModels(apiKey);
|
|
158
176
|
} catch (err) {
|
|
159
|
-
if (
|
|
177
|
+
if (active.length > 0) {
|
|
160
178
|
throw new Error(
|
|
161
|
-
|
|
162
|
-
`catalog to resolve variant params for "${modelId}", and the
|
|
163
|
-
`fetch failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
179
|
+
`${active.join(" + ")} for execution ${executionId} needs the Cursor ` +
|
|
180
|
+
`model catalog to resolve variant params for "${modelId}", and the ` +
|
|
181
|
+
`catalog fetch failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
164
182
|
);
|
|
165
183
|
}
|
|
166
184
|
console.warn(
|
|
167
|
-
`
|
|
168
|
-
`catalog fetch failed
|
|
169
|
-
`
|
|
170
|
-
`
|
|
171
|
-
`expensive direction).
|
|
172
|
-
`
|
|
185
|
+
`VariantParams UNPINNED: execution=${executionId} model=${modelId} tier=${tierName} ` +
|
|
186
|
+
`thinking=${thinkingName} — catalog fetch failed ` +
|
|
187
|
+
`(${err instanceof Error ? err.message : err}); sending no variant params, ` +
|
|
188
|
+
`so the catalog DEFAULT variant decides the served variant for this ` +
|
|
189
|
+
`execution (fast/thinking on several models — the expensive direction). ` +
|
|
190
|
+
`Billing's requested-vs-billed mismatch alarms cover this window.`,
|
|
173
191
|
);
|
|
174
192
|
return [];
|
|
175
193
|
}
|
|
176
194
|
|
|
177
195
|
const model = findCatalogModel(models, modelId);
|
|
178
196
|
if (!model) {
|
|
179
|
-
if (
|
|
197
|
+
if (active.length > 0) {
|
|
180
198
|
throw new Error(
|
|
181
|
-
|
|
182
|
-
`but the Cursor catalog does not list that model — cannot pin
|
|
183
|
-
`variant. The model registry and provider catalog have drifted.`,
|
|
199
|
+
`${active.join(" + ")} requested for "${modelId}" (execution ${executionId}) ` +
|
|
200
|
+
`but the Cursor catalog does not list that model — cannot pin its ` +
|
|
201
|
+
`variant parameters. The model registry and provider catalog have drifted.`,
|
|
184
202
|
);
|
|
185
203
|
}
|
|
186
204
|
console.warn(
|
|
187
|
-
`
|
|
188
|
-
`model not in the Cursor catalog; sending no
|
|
189
|
-
`catalog DEFAULT variant decides the
|
|
205
|
+
`VariantParams UNPINNED: execution=${executionId} model=${modelId} tier=${tierName} ` +
|
|
206
|
+
`thinking=${thinkingName} — model not in the Cursor catalog; sending no ` +
|
|
207
|
+
`variant params, so the catalog DEFAULT variant decides the served ` +
|
|
208
|
+
`variant for this execution.`,
|
|
190
209
|
);
|
|
191
210
|
return [];
|
|
192
211
|
}
|
|
@@ -196,10 +215,13 @@ export async function resolveServiceTierParams(
|
|
|
196
215
|
if (def.id === FAST_PARAM_ID) {
|
|
197
216
|
params.push({ id: FAST_PARAM_ID, value: tier === ServiceTier.FAST ? "true" : "false" });
|
|
198
217
|
} else if (def.id === THINKING_PARAM_ID) {
|
|
199
|
-
params.push({
|
|
218
|
+
params.push({
|
|
219
|
+
id: THINKING_PARAM_ID,
|
|
220
|
+
value: thinking === ThinkingMode.ENABLED ? "true" : "false",
|
|
221
|
+
});
|
|
200
222
|
}
|
|
201
|
-
// Any other parameter (e.g. effort) is price-neutral
|
|
202
|
-
// catalog default variant on purpose.
|
|
223
|
+
// Any other parameter (e.g. effort) is price-neutral and not
|
|
224
|
+
// user-selectable: left to the catalog default variant on purpose.
|
|
203
225
|
}
|
|
204
226
|
|
|
205
227
|
if (tier === ServiceTier.FAST && !params.some((p) => p.id === FAST_PARAM_ID)) {
|
|
@@ -211,10 +233,19 @@ export async function resolveServiceTierParams(
|
|
|
211
233
|
);
|
|
212
234
|
}
|
|
213
235
|
|
|
236
|
+
if (thinking === ThinkingMode.ENABLED && !params.some((p) => p.id === THINKING_PARAM_ID)) {
|
|
237
|
+
throw new Error(
|
|
238
|
+
`thinking=enabled requested for "${modelId}" (execution ${executionId}) ` +
|
|
239
|
+
`but the Cursor catalog declares no "thinking" parameter for it. The ` +
|
|
240
|
+
`model registry claims a thinking capability the provider no longer ` +
|
|
241
|
+
`offers — refusing rather than silently serving the base variant.`,
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
|
|
214
245
|
params.sort((a, b) => a.id.localeCompare(b.id));
|
|
215
246
|
console.log(
|
|
216
|
-
`
|
|
217
|
-
`params=${JSON.stringify(params)}`,
|
|
247
|
+
`VariantParams: execution=${executionId} model=${modelId} tier=${tierName} ` +
|
|
248
|
+
`thinking=${thinkingName} params=${JSON.stringify(params)}`,
|
|
218
249
|
);
|
|
219
250
|
return params;
|
|
220
251
|
}
|
|
@@ -47,7 +47,7 @@ import type {
|
|
|
47
47
|
ModelParameterValue,
|
|
48
48
|
} from "@cursor/sdk";
|
|
49
49
|
import { withTimeout, TimeoutError } from "../../shared/with-timeout.js";
|
|
50
|
-
import type { CursorMcpServerConfig } from "./mcp-
|
|
50
|
+
import type { CursorMcpServerConfig } from "./cursor-mcp-config.js";
|
|
51
51
|
|
|
52
52
|
// ---------------------------------------------------------------------------
|
|
53
53
|
// Constants
|