@stigmer/runner 3.9.0 → 3.11.0

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.
Files changed (270) hide show
  1. package/README.md +12 -1
  2. package/dist/.build-fingerprint +1 -1
  3. package/dist/activities/call-llm.js +9 -10
  4. package/dist/activities/call-llm.js.map +1 -1
  5. package/dist/activities/classify-tool-approvals.d.ts +2 -1
  6. package/dist/activities/classify-tool-approvals.js +28 -2
  7. package/dist/activities/classify-tool-approvals.js.map +1 -1
  8. package/dist/activities/discover-mcp-server.d.ts +32 -0
  9. package/dist/activities/discover-mcp-server.js +162 -27
  10. package/dist/activities/discover-mcp-server.js.map +1 -1
  11. package/dist/activities/execute-cursor/__test-utils__/cursor-hook-harness.d.ts +8 -0
  12. package/dist/activities/execute-cursor/__test-utils__/cursor-hook-harness.js +1 -1
  13. package/dist/activities/execute-cursor/__test-utils__/cursor-hook-harness.js.map +1 -1
  14. package/dist/activities/execute-cursor/approval-state.d.ts +28 -2
  15. package/dist/activities/execute-cursor/approval-state.js +7 -1
  16. package/dist/activities/execute-cursor/approval-state.js.map +1 -1
  17. package/dist/activities/execute-cursor/attachment-resolver.d.ts +14 -0
  18. package/dist/activities/execute-cursor/attachment-resolver.js +25 -4
  19. package/dist/activities/execute-cursor/attachment-resolver.js.map +1 -1
  20. package/dist/activities/execute-cursor/blueprint-resolver.d.ts +1 -9
  21. package/dist/activities/execute-cursor/blueprint-resolver.js +6 -22
  22. package/dist/activities/execute-cursor/blueprint-resolver.js.map +1 -1
  23. package/dist/activities/execute-cursor/env-resolver.js +3 -1
  24. package/dist/activities/execute-cursor/env-resolver.js.map +1 -1
  25. package/dist/activities/execute-cursor/error-classifier.d.ts +40 -3
  26. package/dist/activities/execute-cursor/error-classifier.js +81 -3
  27. package/dist/activities/execute-cursor/error-classifier.js.map +1 -1
  28. package/dist/activities/execute-cursor/extract-structured-output.d.ts +29 -0
  29. package/dist/activities/execute-cursor/extract-structured-output.js +58 -0
  30. package/dist/activities/execute-cursor/extract-structured-output.js.map +1 -0
  31. package/dist/activities/execute-cursor/hook-script.d.ts +14 -3
  32. package/dist/activities/execute-cursor/hook-script.js +72 -10
  33. package/dist/activities/execute-cursor/hook-script.js.map +1 -1
  34. package/dist/activities/execute-cursor/index.d.ts +5 -1
  35. package/dist/activities/execute-cursor/index.js +59 -58
  36. package/dist/activities/execute-cursor/index.js.map +1 -1
  37. package/dist/activities/execute-cursor/mcp-resolver.d.ts +24 -1
  38. package/dist/activities/execute-cursor/mcp-resolver.js +5 -2
  39. package/dist/activities/execute-cursor/mcp-resolver.js.map +1 -1
  40. package/dist/activities/execute-cursor/prompt-builder.d.ts +18 -4
  41. package/dist/activities/execute-cursor/prompt-builder.js +12 -7
  42. package/dist/activities/execute-cursor/prompt-builder.js.map +1 -1
  43. package/dist/activities/execute-cursor/turn-stream.js +4 -1
  44. package/dist/activities/execute-cursor/turn-stream.js.map +1 -1
  45. package/dist/activities/execute-deep-agent/attachment-injector.d.ts +18 -1
  46. package/dist/activities/execute-deep-agent/attachment-injector.js +68 -23
  47. package/dist/activities/execute-deep-agent/attachment-injector.js.map +1 -1
  48. package/dist/activities/execute-deep-agent/environment.js +3 -1
  49. package/dist/activities/execute-deep-agent/environment.js.map +1 -1
  50. package/dist/activities/execute-deep-agent/index.js +15 -0
  51. package/dist/activities/execute-deep-agent/index.js.map +1 -1
  52. package/dist/activities/execute-deep-agent/prompt-builder.d.ts +7 -7
  53. package/dist/activities/execute-deep-agent/prompt-builder.js +8 -2
  54. package/dist/activities/execute-deep-agent/prompt-builder.js.map +1 -1
  55. package/dist/activities/execute-deep-agent/setup.d.ts +10 -0
  56. package/dist/activities/execute-deep-agent/setup.js +65 -26
  57. package/dist/activities/execute-deep-agent/setup.js.map +1 -1
  58. package/dist/activities/execute-deep-agent/subagent-transformer.d.ts +18 -1
  59. package/dist/activities/execute-deep-agent/subagent-transformer.js +8 -1
  60. package/dist/activities/execute-deep-agent/subagent-transformer.js.map +1 -1
  61. package/dist/activities/execute-deep-agent/subagent-wiring.d.ts +11 -4
  62. package/dist/activities/execute-deep-agent/subagent-wiring.js +13 -4
  63. package/dist/activities/execute-deep-agent/subagent-wiring.js.map +1 -1
  64. package/dist/activities/hydrate-workflow-execution.js +3 -1
  65. package/dist/activities/hydrate-workflow-execution.js.map +1 -1
  66. package/dist/activities/workflow-event-activities.d.ts +28 -10
  67. package/dist/activities/workflow-event-activities.js +87 -58
  68. package/dist/activities/workflow-event-activities.js.map +1 -1
  69. package/dist/claimcheck/payload-codec.js +21 -1
  70. package/dist/claimcheck/payload-codec.js.map +1 -1
  71. package/dist/client/stigmer-client.d.ts +9 -4
  72. package/dist/client/stigmer-client.js +28 -15
  73. package/dist/client/stigmer-client.js.map +1 -1
  74. package/dist/encryption/config.d.ts +32 -0
  75. package/dist/encryption/config.js +68 -0
  76. package/dist/encryption/config.js.map +1 -0
  77. package/dist/encryption/index.d.ts +3 -0
  78. package/dist/encryption/index.js +3 -0
  79. package/dist/encryption/index.js.map +1 -0
  80. package/dist/encryption/payload-codec.d.ts +41 -0
  81. package/dist/encryption/payload-codec.js +130 -0
  82. package/dist/encryption/payload-codec.js.map +1 -0
  83. package/dist/payload-codecs.d.ts +16 -0
  84. package/dist/payload-codecs.js +38 -0
  85. package/dist/payload-codecs.js.map +1 -0
  86. package/dist/preflight.d.ts +31 -0
  87. package/dist/preflight.js +43 -0
  88. package/dist/preflight.js.map +1 -1
  89. package/dist/runner-manager.js +5 -15
  90. package/dist/runner-manager.js.map +1 -1
  91. package/dist/runner.js +5 -16
  92. package/dist/runner.js.map +1 -1
  93. package/dist/shared/approval-policy.d.ts +9 -3
  94. package/dist/shared/approval-policy.js +15 -6
  95. package/dist/shared/approval-policy.js.map +1 -1
  96. package/dist/shared/attachment-naming.d.ts +53 -0
  97. package/dist/shared/attachment-naming.js +59 -0
  98. package/dist/shared/attachment-naming.js.map +1 -0
  99. package/dist/shared/attachment-vision.d.ts +43 -2
  100. package/dist/shared/attachment-vision.js +72 -6
  101. package/dist/shared/attachment-vision.js.map +1 -1
  102. package/dist/shared/caller-identity.d.ts +23 -2
  103. package/dist/shared/caller-identity.js +36 -5
  104. package/dist/shared/caller-identity.js.map +1 -1
  105. package/dist/shared/channel-attachment.js +1 -0
  106. package/dist/shared/channel-attachment.js.map +1 -1
  107. package/dist/shared/checkpointer/http-saver.d.ts +42 -1
  108. package/dist/shared/checkpointer/http-saver.js +96 -8
  109. package/dist/shared/checkpointer/http-saver.js.map +1 -1
  110. package/dist/shared/conversation-attachment.js +1 -0
  111. package/dist/shared/conversation-attachment.js.map +1 -1
  112. package/dist/shared/datastore-attachment.d.ts +50 -7
  113. package/dist/shared/datastore-attachment.js +93 -11
  114. package/dist/shared/datastore-attachment.js.map +1 -1
  115. package/dist/shared/http-retry.d.ts +43 -0
  116. package/dist/shared/http-retry.js +50 -0
  117. package/dist/shared/http-retry.js.map +1 -0
  118. package/dist/shared/llm-backend.d.ts +275 -0
  119. package/dist/shared/llm-backend.js +425 -0
  120. package/dist/shared/llm-backend.js.map +1 -0
  121. package/dist/shared/llm-proxy.d.ts +8 -0
  122. package/dist/shared/llm-proxy.js +15 -0
  123. package/dist/shared/llm-proxy.js.map +1 -1
  124. package/dist/shared/mcp-enabled-tools.d.ts +57 -0
  125. package/dist/shared/mcp-enabled-tools.js +86 -0
  126. package/dist/shared/mcp-enabled-tools.js.map +1 -0
  127. package/dist/shared/mcp-manager.d.ts +17 -2
  128. package/dist/shared/mcp-manager.js +37 -25
  129. package/dist/shared/mcp-manager.js.map +1 -1
  130. package/dist/shared/mcp-resolver.d.ts +39 -2
  131. package/dist/shared/mcp-resolver.js +38 -2
  132. package/dist/shared/mcp-resolver.js.map +1 -1
  133. package/dist/shared/model-client.d.ts +12 -5
  134. package/dist/shared/model-client.js +138 -18
  135. package/dist/shared/model-client.js.map +1 -1
  136. package/dist/shared/model-error.js +198 -5
  137. package/dist/shared/model-error.js.map +1 -1
  138. package/dist/shared/model-registry.d.ts +20 -2
  139. package/dist/shared/model-registry.js +37 -2
  140. package/dist/shared/model-registry.js.map +1 -1
  141. package/dist/shared/plan-mode-permissions.d.ts +26 -0
  142. package/dist/shared/plan-mode-permissions.js +28 -0
  143. package/dist/shared/plan-mode-permissions.js.map +1 -0
  144. package/dist/worker.d.ts +2 -1
  145. package/dist/worker.js +2 -4
  146. package/dist/worker.js.map +1 -1
  147. package/dist/workflow-engine/types.d.ts +18 -0
  148. package/dist/workflow-engine/types.js.map +1 -1
  149. package/dist/workflows/call-agent-orchestrator.d.ts +9 -0
  150. package/dist/workflows/call-agent-orchestrator.js +1 -0
  151. package/dist/workflows/call-agent-orchestrator.js.map +1 -1
  152. package/dist/workflows/connect-mcp-server.js +7 -0
  153. package/dist/workflows/connect-mcp-server.js.map +1 -1
  154. package/dist/workflows/engine-core.js +23 -2
  155. package/dist/workflows/engine-core.js.map +1 -1
  156. package/dist/workflows/execute-from-execution.d.ts +1 -1
  157. package/dist/workflows/execute-from-execution.js +11 -1
  158. package/dist/workflows/execute-from-execution.js.map +1 -1
  159. package/package.json +8 -2
  160. package/src/__tests__/claimcheck-codec.test.ts +36 -0
  161. package/src/__tests__/encryption-codec.test.ts +234 -0
  162. package/src/__tests__/fixtures/encrypted-payload-fixture.json +15 -0
  163. package/src/__tests__/history-encryption-e2e.test.ts +243 -0
  164. package/src/__tests__/preflight.test.ts +50 -2
  165. package/src/activities/__tests__/call-llm.test.ts +75 -0
  166. package/src/activities/__tests__/classify-tool-approvals.test.ts +117 -1
  167. package/src/activities/__tests__/discover-mcp-server.hang.test.ts +103 -0
  168. package/src/activities/__tests__/discover-mcp-server.test.ts +203 -0
  169. package/src/activities/__tests__/workflow-event-activities.test.ts +107 -8
  170. package/src/activities/call-llm.ts +9 -16
  171. package/src/activities/classify-tool-approvals.ts +34 -4
  172. package/src/activities/discover-mcp-server.ts +190 -32
  173. package/src/activities/execute-cursor/__test-utils__/cursor-hook-harness.ts +9 -0
  174. package/src/activities/execute-cursor/__tests__/approval-gate.test.ts +14 -0
  175. package/src/activities/execute-cursor/__tests__/attachment-resolver.test.ts +92 -0
  176. package/src/activities/execute-cursor/__tests__/build-prompt.test.ts +40 -14
  177. package/src/activities/execute-cursor/__tests__/error-classifier-extraction.test.ts +208 -0
  178. package/src/activities/execute-cursor/__tests__/extract-structured-output.test.ts +120 -0
  179. package/src/activities/execute-cursor/__tests__/hook-script.test.ts +93 -0
  180. package/src/activities/execute-cursor/__tests__/mcp-resolver.test.ts +125 -0
  181. package/src/activities/execute-cursor/__tests__/prompt-builder-delegation.test.ts +1 -1
  182. package/src/activities/execute-cursor/__tests__/turn-stream.test.ts +13 -0
  183. package/src/activities/execute-cursor/approval-state.ts +30 -1
  184. package/src/activities/execute-cursor/attachment-resolver.ts +38 -3
  185. package/src/activities/execute-cursor/blueprint-resolver.ts +7 -27
  186. package/src/activities/execute-cursor/env-resolver.ts +3 -1
  187. package/src/activities/execute-cursor/error-classifier.ts +91 -4
  188. package/src/activities/execute-cursor/extract-structured-output.ts +72 -0
  189. package/src/activities/execute-cursor/hook-script.ts +74 -10
  190. package/src/activities/execute-cursor/index.ts +63 -72
  191. package/src/activities/execute-cursor/mcp-resolver.ts +36 -2
  192. package/src/activities/execute-cursor/prompt-builder.ts +34 -9
  193. package/src/activities/execute-cursor/turn-stream.ts +5 -2
  194. package/src/activities/execute-deep-agent/__tests__/attachment-injector.test.ts +132 -8
  195. package/src/activities/execute-deep-agent/__tests__/datastore-degradation.test.ts +104 -0
  196. package/src/activities/execute-deep-agent/__tests__/hitl-reject.test.ts +2 -0
  197. package/src/activities/execute-deep-agent/__tests__/hitl-resume-approve-all.test.ts +1 -0
  198. package/src/activities/execute-deep-agent/__tests__/hitl-resume-history.test.ts +1 -0
  199. package/src/activities/execute-deep-agent/__tests__/prompt-builder.test.ts +34 -5
  200. package/src/activities/execute-deep-agent/__tests__/sequential-gate-resume.test.ts +1 -0
  201. package/src/activities/execute-deep-agent/__tests__/subagent-plan-mode-permissions.test.ts +173 -0
  202. package/src/activities/execute-deep-agent/__tests__/subagent-wiring.test.ts +12 -7
  203. package/src/activities/execute-deep-agent/attachment-injector.ts +94 -30
  204. package/src/activities/execute-deep-agent/environment.ts +3 -1
  205. package/src/activities/execute-deep-agent/index.ts +20 -0
  206. package/src/activities/execute-deep-agent/prompt-builder.ts +20 -10
  207. package/src/activities/execute-deep-agent/setup.ts +86 -31
  208. package/src/activities/execute-deep-agent/subagent-transformer.ts +23 -1
  209. package/src/activities/execute-deep-agent/subagent-wiring.ts +14 -4
  210. package/src/activities/hydrate-workflow-execution.ts +3 -1
  211. package/src/activities/workflow-event-activities.ts +96 -69
  212. package/src/claimcheck/payload-codec.ts +33 -1
  213. package/src/client/__tests__/stigmer-client.test.ts +8 -8
  214. package/src/client/stigmer-client.ts +32 -18
  215. package/src/encryption/config.ts +91 -0
  216. package/src/encryption/index.ts +3 -0
  217. package/src/encryption/payload-codec.ts +152 -0
  218. package/src/payload-codecs.ts +56 -0
  219. package/src/preflight.ts +45 -0
  220. package/src/runner-manager.ts +6 -24
  221. package/src/runner.ts +6 -25
  222. package/src/shared/__tests__/approval-policy.test.ts +82 -39
  223. package/src/shared/__tests__/attachment-naming.test.ts +159 -0
  224. package/src/shared/__tests__/attachment-vision.test.ts +97 -0
  225. package/src/shared/__tests__/bedrock-adapter.test.ts +213 -0
  226. package/src/shared/__tests__/bedrock-seam.test.ts +390 -0
  227. package/src/shared/__tests__/caller-identity.test.ts +25 -0
  228. package/src/shared/__tests__/channel-attachment.test.ts +1 -1
  229. package/src/shared/__tests__/connect-backfill.test.ts +1 -0
  230. package/src/shared/__tests__/conversation-attachment.test.ts +1 -1
  231. package/src/shared/__tests__/datastore-attachment.test.ts +129 -1
  232. package/src/shared/__tests__/foundry-adapter.test.ts +276 -0
  233. package/src/shared/__tests__/foundry-seam.test.ts +482 -0
  234. package/src/shared/__tests__/http-retry.test.ts +67 -0
  235. package/src/shared/__tests__/llm-backend.test.ts +616 -0
  236. package/src/shared/__tests__/mcp-enabled-tools.test.ts +86 -0
  237. package/src/shared/__tests__/mcp-manager.test.ts +170 -2
  238. package/src/shared/__tests__/mcp-resolver.test.ts +146 -3
  239. package/src/shared/__tests__/model-client.test.ts +154 -0
  240. package/src/shared/__tests__/model-error.test.ts +289 -1
  241. package/src/shared/__tests__/model-registry.test.ts +71 -0
  242. package/src/shared/__tests__/synthesized-attachment.test.ts +1 -0
  243. package/src/shared/__tests__/vertex-adapter.test.ts +169 -0
  244. package/src/shared/__tests__/vertex-seam.test.ts +295 -0
  245. package/src/shared/approval-policy.ts +14 -7
  246. package/src/shared/attachment-naming.ts +78 -0
  247. package/src/shared/attachment-vision.ts +92 -9
  248. package/src/shared/caller-identity.ts +40 -5
  249. package/src/shared/channel-attachment.ts +1 -0
  250. package/src/shared/checkpointer/__tests__/http-saver.test.ts +196 -1
  251. package/src/shared/checkpointer/http-saver.ts +117 -9
  252. package/src/shared/conversation-attachment.ts +1 -0
  253. package/src/shared/datastore-attachment.ts +106 -11
  254. package/src/shared/http-retry.ts +50 -0
  255. package/src/shared/llm-backend.ts +544 -0
  256. package/src/shared/llm-proxy.ts +15 -0
  257. package/src/shared/mcp-enabled-tools.ts +105 -0
  258. package/src/shared/mcp-manager.ts +43 -26
  259. package/src/shared/mcp-resolver.ts +73 -2
  260. package/src/shared/model-client.ts +161 -19
  261. package/src/shared/model-error.ts +222 -4
  262. package/src/shared/model-registry.ts +50 -2
  263. package/src/shared/plan-mode-permissions.ts +30 -0
  264. package/src/worker.ts +4 -5
  265. package/src/workflow-engine/types.ts +18 -0
  266. package/src/workflows/__tests__/execute-serverless-workflow.test.ts +68 -2
  267. package/src/workflows/call-agent-orchestrator.ts +10 -0
  268. package/src/workflows/connect-mcp-server.ts +7 -0
  269. package/src/workflows/engine-core.ts +23 -2
  270. package/src/workflows/execute-from-execution.ts +12 -2
@@ -0,0 +1,425 @@
1
+ /**
2
+ * LLM provider-backend utilities — pure routing helpers for serving a
3
+ * provider's models through an alternative cloud backend (GCP Vertex AI,
4
+ * AWS Bedrock, Microsoft Foundry) instead of the provider's public API.
5
+ *
6
+ * Layering mirrors `llm-proxy.ts`: this module is pure string/config
7
+ * utilities with no LangChain or SDK dependency. Consumers: the runner
8
+ * factories run `preflightLlmBackends` at startup, and `model-client.ts`
9
+ * resolves the backend and translates model ids at construction time; see
10
+ * `__tests__/vertex-seam.test.ts` for the pinned seam behavior.
11
+ *
12
+ * Design decision record: stigmer-cloud
13
+ * `_projects/2026-08/20260809.01.multi-cloud-llm-provider-endpoints/`
14
+ * `design-decisions/001-provider-backends.md`.
15
+ */
16
+ // ─── Backend selection ───────────────────────────────────────────────────────
17
+ /** Env var selecting where Anthropic models are served. */
18
+ export const ANTHROPIC_BACKEND_ENV = "STIGMER_ANTHROPIC_BACKEND";
19
+ /** Env var selecting where OpenAI models are served. */
20
+ export const OPENAI_BACKEND_ENV = "STIGMER_OPENAI_BACKEND";
21
+ /** Operator guide for backend configuration; the single copy of this URL. */
22
+ export const BACKEND_DOC_URL = "https://docs.stigmer.ai/guides/runners/model-backends";
23
+ /** Planned-but-unshipped values get a "not in this build" message. */
24
+ const PLANNED_ANTHROPIC = [];
25
+ const PLANNED_OPENAI = ["azure"];
26
+ function parseBackend(envVar, raw, supported, planned) {
27
+ const value = raw?.trim().toLowerCase() ?? "";
28
+ if (value === "") {
29
+ // Unset means the provider's public API — the zero-config default.
30
+ return { ok: true, backend: "public" };
31
+ }
32
+ if (supported.includes(value)) {
33
+ return { ok: true, backend: value };
34
+ }
35
+ if (planned.includes(value)) {
36
+ return {
37
+ ok: false,
38
+ message: `${envVar}="${value}" is not implemented in this build yet. ` +
39
+ `Supported today: ${supported.join(", ")}. See ${BACKEND_DOC_URL}.`,
40
+ };
41
+ }
42
+ return {
43
+ ok: false,
44
+ message: `${envVar}="${raw?.trim()}" is not a supported backend. ` +
45
+ `Supported: ${supported.join(", ")}. See ${BACKEND_DOC_URL}.`,
46
+ };
47
+ }
48
+ /** Parse `STIGMER_ANTHROPIC_BACKEND` (unset → `public`). */
49
+ export function parseAnthropicBackend(env = process.env) {
50
+ return parseBackend(ANTHROPIC_BACKEND_ENV, env[ANTHROPIC_BACKEND_ENV], ["public", "vertex", "bedrock", "foundry"], PLANNED_ANTHROPIC);
51
+ }
52
+ /** Parse `STIGMER_OPENAI_BACKEND` (unset → `public`). */
53
+ export function parseOpenAiBackend(env = process.env) {
54
+ return parseBackend(OPENAI_BACKEND_ENV, env[OPENAI_BACKEND_ENV], ["public"],
55
+ // `vertex`/`bedrock` under the OpenAI var are wrong-provider values, not
56
+ // planned ones — they fall through to the unsupported-value message.
57
+ PLANNED_OPENAI);
58
+ }
59
+ /**
60
+ * Resolve the Anthropic backend for model construction, throwing the
61
+ * parser's message on an invalid value.
62
+ *
63
+ * The runner factories run {@link preflightLlmBackends} at startup, so in a
64
+ * normally-booted process this never throws — the throw is defense in depth
65
+ * for paths that construct models without the factories (tests, direct
66
+ * library use), keeping "invalid value" impossible to ride past silently.
67
+ */
68
+ export function resolveAnthropicBackend(env = process.env) {
69
+ const parsed = parseAnthropicBackend(env);
70
+ if (!parsed.ok)
71
+ throw new Error(parsed.message);
72
+ return parsed.backend;
73
+ }
74
+ /**
75
+ * Static prerequisite check for the vertex backend, or null when satisfied.
76
+ *
77
+ * Region is the ONE hard requirement checkable without I/O: the Vertex SDK
78
+ * throws without it. Project id and credentials are deliberately NOT
79
+ * checked here — both are legitimately resolvable at request time from
80
+ * Application Default Credentials (workload identity, metadata server,
81
+ * gcloud login), so requiring env vars for them would reject perfectly
82
+ * valid GCP deployments. Runtime credential failures get actionable
83
+ * classification in `model-error.ts` instead.
84
+ */
85
+ export function checkVertexPrerequisites(env = process.env) {
86
+ if (env.CLOUD_ML_REGION?.trim())
87
+ return null;
88
+ return (`The vertex backend requires CLOUD_ML_REGION (e.g. "asia-south1", or ` +
89
+ `"global" for the global endpoint). See ${BACKEND_DOC_URL}.`);
90
+ }
91
+ /** Operator override map: canonical id -> exact Bedrock id, consulted first. */
92
+ export const BEDROCK_MODEL_MAP_ENV = "STIGMER_BEDROCK_MODEL_MAP";
93
+ /** Inference-profile geography prefix (`us`, `eu`, `global`, …), no default. */
94
+ export const BEDROCK_INFERENCE_PREFIX_ENV = "STIGMER_BEDROCK_INFERENCE_PREFIX";
95
+ /**
96
+ * Static prerequisite check for the bedrock backend, or null when satisfied.
97
+ *
98
+ * AWS_REGION is REQUIRED even though the Bedrock SDK would default it to
99
+ * us-east-1 (pinned by bedrock-seam.test.ts): for a deployment-controlled
100
+ * data-residency feature, silently routing model traffic to a US region on
101
+ * a missing var is exactly the failure backends exist to prevent. Same
102
+ * shape as vertex's CLOUD_ML_REGION requirement. Credentials are
103
+ * deliberately NOT checked — the AWS chain (env keys, IRSA / instance
104
+ * metadata, config files, AWS_BEARER_TOKEN_BEDROCK) legitimately resolves
105
+ * at request time; requiring env keys would reject valid deployments.
106
+ * Runtime credential failures get actionable classification in
107
+ * `model-error.ts` instead.
108
+ *
109
+ * A malformed STIGMER_BEDROCK_MODEL_MAP is also fatal here: it is
110
+ * deployment-static, and finding out at the first model call would fail
111
+ * executions a boot check could have refused.
112
+ */
113
+ export function checkBedrockPrerequisites(env = process.env) {
114
+ if (!env.AWS_REGION?.trim()) {
115
+ return (`The bedrock backend requires AWS_REGION (e.g. "ap-south-1"). It is ` +
116
+ `required even though the AWS SDK would default to us-east-1 — a ` +
117
+ `deployment that chose Bedrock for data residency must never fall ` +
118
+ `back to another region silently. See ${BACKEND_DOC_URL}.`);
119
+ }
120
+ const map = parseBedrockModelMap(env);
121
+ if (!map.ok)
122
+ return map.message;
123
+ return null;
124
+ }
125
+ /**
126
+ * Shared parser for the per-backend override maps: comma-separated
127
+ * `canonical=target` pairs. Unset or blank parses to an empty map (the
128
+ * backend's deterministic rule serves every model). Each env var keeps its
129
+ * own single copy of the malformed-entry text through `form`/`example` —
130
+ * preflight and translation surface the same string.
131
+ */
132
+ function parseModelMap(envVar, raw, form, example) {
133
+ const trimmed = raw?.trim();
134
+ const map = new Map();
135
+ if (!trimmed)
136
+ return { ok: true, map };
137
+ for (const entry of trimmed.split(",")) {
138
+ const pair = entry.trim();
139
+ if (pair === "")
140
+ continue;
141
+ const eq = pair.indexOf("=");
142
+ const canonical = eq === -1 ? "" : pair.slice(0, eq).trim();
143
+ const target = eq === -1 ? "" : pair.slice(eq + 1).trim();
144
+ if (!canonical || !target) {
145
+ return {
146
+ ok: false,
147
+ message: `${envVar} entry "${pair}" is not of the form ${form} ` +
148
+ `(e.g. "${example}"). Entries are comma-separated. ` +
149
+ `See ${BACKEND_DOC_URL}.`,
150
+ };
151
+ }
152
+ map.set(canonical, target);
153
+ }
154
+ return { ok: true, map };
155
+ }
156
+ /**
157
+ * Parse `STIGMER_BEDROCK_MODEL_MAP`: comma-separated `canonical=bedrockId`
158
+ * pairs, e.g. "claude-sonnet-4-6=us.anthropic.claude-sonnet-4-6-v1:0".
159
+ */
160
+ export function parseBedrockModelMap(env = process.env) {
161
+ return parseModelMap(BEDROCK_MODEL_MAP_ENV, env[BEDROCK_MODEL_MAP_ENV], "canonical=bedrockId", "claude-sonnet-4-6=us.anthropic.claude-sonnet-4-6-v1:0");
162
+ }
163
+ // ─── Microsoft Foundry (Azure) ───────────────────────────────────────────────
164
+ /**
165
+ * Operator override map: canonical id -> Foundry deployment name, consulted
166
+ * first. Named DEPLOYMENT_MAP, not MODEL_MAP, because the target is Azure's
167
+ * term of art — the operator-chosen deployment name, not another model id.
168
+ */
169
+ export const FOUNDRY_DEPLOYMENT_MAP_ENV = "STIGMER_FOUNDRY_DEPLOYMENT_MAP";
170
+ /** The Foundry resource name (SDK-native; builds the endpoint host). */
171
+ export const FOUNDRY_RESOURCE_ENV = "ANTHROPIC_FOUNDRY_RESOURCE";
172
+ /** Full endpoint override (SDK-native; mutually exclusive with resource). */
173
+ export const FOUNDRY_BASE_URL_ENV = "ANTHROPIC_FOUNDRY_BASE_URL";
174
+ /**
175
+ * Parse `STIGMER_FOUNDRY_DEPLOYMENT_MAP`: comma-separated
176
+ * `canonical=deploymentName` pairs, e.g.
177
+ * "claude-sonnet-4-6=my-sonnet-deployment".
178
+ */
179
+ export function parseFoundryDeploymentMap(env = process.env) {
180
+ return parseModelMap(FOUNDRY_DEPLOYMENT_MAP_ENV, env[FOUNDRY_DEPLOYMENT_MAP_ENV], "canonical=deploymentName", "claude-sonnet-4-6=my-sonnet-deployment");
181
+ }
182
+ /**
183
+ * Static prerequisite check for the foundry backend, or null when satisfied.
184
+ *
185
+ * The endpoint is the ONE hard requirement checkable without I/O: the
186
+ * Foundry SDK's constructor throws without exactly one of the resource
187
+ * name or a full base URL, so both halves of its contract (missing AND
188
+ * both-set) are refused here at boot with catalog messages instead of at
189
+ * the first model call. Credentials are deliberately NOT checked —
190
+ * ANTHROPIC_FOUNDRY_API_KEY is optional by design (without it the adapter
191
+ * authenticates through Microsoft Entra ID via the Azure credential chain,
192
+ * which resolves at request time exactly like Vertex ADC and the AWS
193
+ * chain), so requiring it would reject correctly-configured keyless
194
+ * deployments. Runtime credential failures get actionable classification
195
+ * in `model-error.ts` instead.
196
+ *
197
+ * A malformed STIGMER_FOUNDRY_DEPLOYMENT_MAP is also fatal here: it is
198
+ * deployment-static, and finding out at the first model call would fail
199
+ * executions a boot check could have refused.
200
+ */
201
+ export function checkFoundryPrerequisites(env = process.env) {
202
+ const resource = env[FOUNDRY_RESOURCE_ENV]?.trim();
203
+ const baseUrl = env[FOUNDRY_BASE_URL_ENV]?.trim();
204
+ if (!resource && !baseUrl) {
205
+ return (`The foundry backend requires ${FOUNDRY_RESOURCE_ENV} (your Microsoft ` +
206
+ `Foundry resource name, e.g. "my-foundry-resource") or ` +
207
+ `${FOUNDRY_BASE_URL_ENV} (the full endpoint, e.g. ` +
208
+ `"https://my-foundry-resource.services.ai.azure.com/anthropic/"). ` +
209
+ `See ${BACKEND_DOC_URL}.`);
210
+ }
211
+ if (resource && baseUrl) {
212
+ return (`${FOUNDRY_RESOURCE_ENV} and ${FOUNDRY_BASE_URL_ENV} are mutually ` +
213
+ `exclusive — the base URL is derived from the resource name. Set ` +
214
+ `exactly one. See ${BACKEND_DOC_URL}.`);
215
+ }
216
+ const map = parseFoundryDeploymentMap(env);
217
+ if (!map.ok)
218
+ return map.message;
219
+ return null;
220
+ }
221
+ /**
222
+ * Check that direct-mode (unproxied) calls to `provider` have a usable
223
+ * credential path, or return the operator message describing what is
224
+ * missing. Null means "a request can authenticate":
225
+ *
226
+ * - `anthropic`: a non-blank `ANTHROPIC_API_KEY`, or any non-public backend
227
+ * (vertex authenticates through Application Default Credentials, and
228
+ * `ChatAnthropic` waives its API-key requirement when `createClient` is
229
+ * supplied — pinned by vertex-seam.test.ts).
230
+ * - `openai`: a non-blank `OPENAI_API_KEY`. The message deliberately offers
231
+ * no backend remedy until the azure adapter ships — advertising
232
+ * STIGMER_OPENAI_BACKEND today would point the operator at a value that
233
+ * fails with "not implemented in this build".
234
+ *
235
+ * An invalid backend value also returns null: `resolveAnthropicBackend` at
236
+ * model construction owns that condition's precise catalog message, and
237
+ * reporting it here too would create a second copy that can drift.
238
+ *
239
+ * This is the single copy of the "do we have a credential?" question. The
240
+ * reaction stays with each caller, because the right one differs per site:
241
+ * `call-llm.ts` raises a non-retryable LLM_MISSING_API_KEY, tool
242
+ * classification fails closed (every tool gated), and Cursor tier-2
243
+ * extraction skips to "no structured output". Callers consult it only when
244
+ * no proxy is configured — a proxied deployment authenticates with
245
+ * STIGMER_TOKEN and holds no provider credentials at all.
246
+ */
247
+ export function checkDirectCredentials(provider, env = process.env) {
248
+ if (provider === "openai") {
249
+ if (env.OPENAI_API_KEY?.trim())
250
+ return null;
251
+ return (`OPENAI_API_KEY is not set and no proxy is configured. Set the API ` +
252
+ `key in your environment or connect to a Stigmer Cloud deployment. ` +
253
+ `See ${BACKEND_DOC_URL}.`);
254
+ }
255
+ if (env.ANTHROPIC_API_KEY?.trim())
256
+ return null;
257
+ const parsed = parseAnthropicBackend(env);
258
+ if (!parsed.ok || parsed.backend !== "public")
259
+ return null;
260
+ return (`ANTHROPIC_API_KEY is not set, no model backend is configured, and no ` +
261
+ `proxy is configured. Set the API key, configure a backend (e.g. ` +
262
+ `${ANTHROPIC_BACKEND_ENV}=vertex, bedrock, or foundry), or connect to ` +
263
+ `a Stigmer Cloud deployment. See ${BACKEND_DOC_URL}.`);
264
+ }
265
+ /**
266
+ * Validate the deployment's backend configuration once, at startup.
267
+ *
268
+ * Called by the runner factories (`createStigmerRunner` /
269
+ * `createStigmerRunnerManager`) — the construction boundary every entry
270
+ * path shares (static, pool, and manager modes in main.ts, plus in-process
271
+ * embedders of `@stigmer/runner`) — so a misconfigured deployment refuses
272
+ * to accept work instead of failing every execution mid-flight. Mirrors the
273
+ * `preflightNodeRuntime` pattern: pure check in, operator message out.
274
+ *
275
+ * Precedence rule: when `STIGMER_PROXY_ENDPOINT` is set the proxy owns
276
+ * provider routing and backend vars are inert, so they downgrade to
277
+ * warnings (never silence, but never fail a proxied fleet over an ignored
278
+ * var either). Without a proxy, invalid values and missing prerequisites
279
+ * are fatal.
280
+ */
281
+ export function preflightLlmBackends(env = process.env) {
282
+ const proxySet = !!env.STIGMER_PROXY_ENDPOINT?.trim();
283
+ if (proxySet) {
284
+ const warnings = [];
285
+ for (const envVar of [ANTHROPIC_BACKEND_ENV, OPENAI_BACKEND_ENV]) {
286
+ const raw = env[envVar]?.trim();
287
+ if (raw && raw.toLowerCase() !== "public") {
288
+ warnings.push(`STIGMER_PROXY_ENDPOINT is set; ${envVar}=${raw} is ignored — ` +
289
+ `the proxy owns provider routing.`);
290
+ }
291
+ }
292
+ return { error: null, warnings };
293
+ }
294
+ const errors = [];
295
+ const anthropic = parseAnthropicBackend(env);
296
+ if (!anthropic.ok) {
297
+ errors.push(anthropic.message);
298
+ }
299
+ else if (anthropic.backend === "vertex") {
300
+ const prereq = checkVertexPrerequisites(env);
301
+ if (prereq !== null)
302
+ errors.push(prereq);
303
+ }
304
+ else if (anthropic.backend === "bedrock") {
305
+ const prereq = checkBedrockPrerequisites(env);
306
+ if (prereq !== null)
307
+ errors.push(prereq);
308
+ }
309
+ else if (anthropic.backend === "foundry") {
310
+ const prereq = checkFoundryPrerequisites(env);
311
+ if (prereq !== null)
312
+ errors.push(prereq);
313
+ }
314
+ const openai = parseOpenAiBackend(env);
315
+ if (!openai.ok)
316
+ errors.push(openai.message);
317
+ return { error: errors.length > 0 ? errors.join("\n") : null, warnings: [] };
318
+ }
319
+ // ─── Model-id translation ────────────────────────────────────────────────────
320
+ /**
321
+ * Matches a registry `apiModelId` that ends in a pre-4.6 snapshot date
322
+ * (`-YYYYMMDD`), e.g. "claude-sonnet-4-5-20250929".
323
+ */
324
+ const TRAILING_SNAPSHOT_DATE = /-(\d{8})$/;
325
+ /**
326
+ * Translate a canonical Anthropic API model id into Vertex AI's form.
327
+ *
328
+ * The model registry serves two id shapes, and Vertex treats them
329
+ * differently (platform.claude.com "Model IDs and versions"):
330
+ *
331
+ * - Pre-4.6 models carry a snapshot date, and Vertex separates it with `@`
332
+ * instead of `-`: "claude-sonnet-4-5-20250929" -> "claude-sonnet-4-5@20250929".
333
+ * - 4.6-generation and later ids are dateless AND canonical on every
334
+ * platform: "claude-sonnet-4-6" is used verbatim on Vertex. Appending a
335
+ * date to them 404s — a real bug shipped by other integrations (Dify
336
+ * langgenius/dify-official-plugins#2905, Roo-Code #11625) — so dateless
337
+ * ids MUST pass through untouched.
338
+ *
339
+ * The translated id is Vertex wire detail only: it goes into the request
340
+ * URL path and must never escape the adapter into usage metrics or pricing,
341
+ * which key on the canonical id (the canonical-id invariant in the design
342
+ * decision record).
343
+ *
344
+ * Already-translated ids (`name@date`) and Bedrock-shaped ids
345
+ * (`anthropic.…-v1:0`) don't match the trailing-date pattern, so a second
346
+ * pass is a no-op by construction.
347
+ */
348
+ export function toVertexModelId(apiModelId) {
349
+ return apiModelId.replace(TRAILING_SNAPSHOT_DATE, "@$1");
350
+ }
351
+ /**
352
+ * Translate a canonical Anthropic API model id into Bedrock's form, in
353
+ * three layers (approved design, T04) — each a deployment-level knob:
354
+ *
355
+ * 1. `STIGMER_BEDROCK_MODEL_MAP` override, consulted first: the escape
356
+ * hatch for ids the deterministic rule cannot derive (Bedrock ids for
357
+ * dateless canonicals may carry AWS-side snapshot dates we cannot know).
358
+ * 2. `STIGMER_BEDROCK_INFERENCE_PREFIX` (e.g. "us", "eu", "global"),
359
+ * applied to the derived id. Newer Claude models on Bedrock are invoked
360
+ * through geography-prefixed inference profiles (AWS lists the base id's
361
+ * in-region endpoint as N/A) — but WHICH geography is a deployment
362
+ * decision (data residency), underivable from the model id, and never
363
+ * defaulted: a missing prefix yields the bare id, and if AWS rejects it
364
+ * with its "use an inference profile" error, model-error.ts translates
365
+ * that into "set ${BEDROCK_INFERENCE_PREFIX_ENV}".
366
+ * 3. Deterministic rule: `anthropic.{canonical}-v1:0` — verified against
367
+ * AWS's model catalog for the registry's dated ids (e.g.
368
+ * claude-sonnet-4-5-20250929 -> anthropic.claude-sonnet-4-5-20250929-v1:0).
369
+ *
370
+ * Like the Vertex translation, the result is wire detail only: it rides in
371
+ * the request URL and must never escape the adapter into usage metrics or
372
+ * pricing, which key on the canonical id (the canonical-id invariant).
373
+ *
374
+ * Throws the catalog message on a malformed map — defense in depth for
375
+ * paths that construct models without the factories; a normally-booted
376
+ * runner already refused to start in `checkBedrockPrerequisites`.
377
+ */
378
+ export function toBedrockModelId(apiModelId, env = process.env) {
379
+ const parsed = parseBedrockModelMap(env);
380
+ if (!parsed.ok)
381
+ throw new Error(parsed.message);
382
+ const mapped = parsed.map.get(apiModelId);
383
+ if (mapped !== undefined)
384
+ return mapped;
385
+ // Lenient on a trailing dot ("us." and "us" both read as intent).
386
+ const prefix = env[BEDROCK_INFERENCE_PREFIX_ENV]?.trim().replace(/\.$/, "");
387
+ const derived = `anthropic.${apiModelId}-v1:0`;
388
+ return prefix ? `${prefix}.${derived}` : derived;
389
+ }
390
+ /**
391
+ * Translate a canonical Anthropic API model id into a Microsoft Foundry
392
+ * deployment name, in two layers (approved design, T05):
393
+ *
394
+ * 1. `STIGMER_FOUNDRY_DEPLOYMENT_MAP` override, consulted first: Foundry
395
+ * routes by DEPLOYMENT NAME, and the portal lets operators name
396
+ * deployments anything ("my-sonnet-deployment"). This is the escape
397
+ * hatch for those custom names.
398
+ * 2. Deterministic rule: strip a trailing `-YYYYMMDD` snapshot date —
399
+ * Foundry's DEFAULT deployment names are the dateless Claude ids
400
+ * (claude-sonnet-4-5-20250929 -> claude-sonnet-4-5; dateless ids pass
401
+ * through unchanged). Verified against Anthropic's published Foundry
402
+ * model table: every native-catalog id maps onto a real default
403
+ * deployment name. Note this is the INVERSE of toVertexModelId, which
404
+ * keeps the date and reseparates it with `@`.
405
+ *
406
+ * Like the other translations, the result is wire detail only: it rides in
407
+ * the request body's `model` field (Foundry keeps it in the body — see
408
+ * foundry-seam.test.ts — unlike Vertex/Bedrock, which move it into the URL
409
+ * path) and must never escape the adapter into usage metrics or pricing,
410
+ * which key on the canonical id (the canonical-id invariant).
411
+ *
412
+ * Throws the catalog message on a malformed map — defense in depth for
413
+ * paths that construct models without the factories; a normally-booted
414
+ * runner already refused to start in `checkFoundryPrerequisites`.
415
+ */
416
+ export function toFoundryDeploymentName(apiModelId, env = process.env) {
417
+ const parsed = parseFoundryDeploymentMap(env);
418
+ if (!parsed.ok)
419
+ throw new Error(parsed.message);
420
+ const mapped = parsed.map.get(apiModelId);
421
+ if (mapped !== undefined)
422
+ return mapped;
423
+ return apiModelId.replace(TRAILING_SNAPSHOT_DATE, "");
424
+ }
425
+ //# sourceMappingURL=llm-backend.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"llm-backend.js","sourceRoot":"","sources":["../../src/shared/llm-backend.ts"],"names":[],"mappings":"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"}
@@ -25,6 +25,14 @@ export type LlmProvider = "anthropic" | "openai";
25
25
  * fall back to a default provider when an unknown model is requested.
26
26
  */
27
27
  export declare function inferProvider(modelName: string): LlmProvider;
28
+ /**
29
+ * {@link inferProvider}, returning null instead of throwing on an unknown
30
+ * prefix. For credential pre-checks that must not preempt the construction
31
+ * path: when the provider cannot be determined here, the caller proceeds and
32
+ * lets `buildChatModel` raise inferProvider's precise message inside its own
33
+ * error handling, instead of a guess being made up front.
34
+ */
35
+ export declare function tryInferProvider(modelName: string): LlmProvider | null;
28
36
  /**
29
37
  * Strip an explicit "provider:" prefix from the model name, returning
30
38
  * just the model ID portion. If no explicit prefix is present, returns
@@ -61,6 +61,21 @@ export function inferProvider(modelName) {
61
61
  `Known prefixes: claude* (anthropic), gpt*/o1*/o3*/o4*/chatgpt* (openai). ` +
62
62
  `Use explicit prefix syntax "provider:model-name" for non-standard model names.`);
63
63
  }
64
+ /**
65
+ * {@link inferProvider}, returning null instead of throwing on an unknown
66
+ * prefix. For credential pre-checks that must not preempt the construction
67
+ * path: when the provider cannot be determined here, the caller proceeds and
68
+ * lets `buildChatModel` raise inferProvider's precise message inside its own
69
+ * error handling, instead of a guess being made up front.
70
+ */
71
+ export function tryInferProvider(modelName) {
72
+ try {
73
+ return inferProvider(modelName);
74
+ }
75
+ catch {
76
+ return null;
77
+ }
78
+ }
64
79
  /**
65
80
  * Strip an explicit "provider:" prefix from the model name, returning
66
81
  * just the model ID portion. If no explicit prefix is present, returns
@@ -1 +1 @@
1
- {"version":3,"file":"llm-proxy.js","sourceRoot":"","sources":["../../src/shared/llm-proxy.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"llm-proxy.js","sourceRoot":"","sources":["../../src/shared/llm-proxy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Enforcement semantics for McpServerUsage.enabled_tools (issue #350).
3
+ *
4
+ * The proto contract (agent/v1/spec.proto McpServerUsage.enabled_tools,
5
+ * mcpserver/v1/spec.proto McpServerSpec.default_enabled_tools):
6
+ * - A non-empty enabled_tools on the usage is the allow-list for that server.
7
+ * - An empty usage list falls back to the server's default_enabled_tools.
8
+ * - Both empty means NO restriction — every discovered tool is available.
9
+ *
10
+ * Both harnesses import THIS module so they can never drift on these
11
+ * semantics (the mcp-transport-guard precedent for logic shared across the
12
+ * duplicated resolvers — see the header of shared/mcp-resolver.ts):
13
+ * - The deep-agent harness filters the discovered toolset before it reaches
14
+ * the model (shared/mcp-manager.ts connectMcpServers).
15
+ * - The Cursor harness cannot hide tools (the Cursor SDK's McpServerConfig
16
+ * has no allow-list field), so it denies non-enabled calls in the HITL
17
+ * hook instead (execute-cursor/approval-state.ts mcpServerEnabledTools +
18
+ * the "disabled" arm in hook-script.ts). Same guarantee, fail-closed.
19
+ *
20
+ * Names are bare tool names exactly as reported by tools/list — the same
21
+ * identity space as the sub-agent McpAccess filter and the approval-policy
22
+ * maps. An enabled name the server does not expose is warned and dropped
23
+ * (enforce the intersection): the restriction still holds and the run
24
+ * proceeds with the valid subset; apply-time validation against
25
+ * discovered_capabilities is the server-side follow-up that catches typos.
26
+ */
27
+ /**
28
+ * Compute the effective allow-list for one resolved MCP server.
29
+ *
30
+ * Returns `undefined` when the server is unrestricted (both lists empty) —
31
+ * the absent-field shape ResolvedMcpServer carries so synthesized attachment
32
+ * servers and the discovery path stay unfiltered by construction.
33
+ */
34
+ export declare function effectiveEnabledTools(usageEnabledTools: readonly string[] | undefined, defaultEnabledTools: readonly string[] | undefined): string[] | undefined;
35
+ /**
36
+ * Filter a server's discovered tools by its effective allow-list.
37
+ *
38
+ * `undefined` enabledTools → unrestricted, tools pass through untouched.
39
+ * Otherwise only tools whose bare name is on the list survive; enabled names
40
+ * the server does not expose are warned and ignored (warn-and-intersect —
41
+ * a stale or mistyped name must narrow the toolset, never widen it or fail
42
+ * the run).
43
+ */
44
+ export declare function filterToolsByEnabledTools<T extends {
45
+ name: string;
46
+ }>(slug: string, tools: readonly T[], enabledTools: readonly string[] | undefined): T[];
47
+ /**
48
+ * Collect the restricted servers' allow-lists keyed by slug — the shape the
49
+ * Cursor harness writes into the approval state file (mcpServerEnabledTools)
50
+ * for the hook's "disabled" arm. Unrestricted servers are ABSENT (the hook
51
+ * treats an absent slug as unrestricted), so the common no-restriction case
52
+ * stays an empty object.
53
+ */
54
+ export declare function enabledToolsBySlug(servers: readonly {
55
+ slug: string;
56
+ enabledTools?: string[];
57
+ }[]): Record<string, string[]>;
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Enforcement semantics for McpServerUsage.enabled_tools (issue #350).
3
+ *
4
+ * The proto contract (agent/v1/spec.proto McpServerUsage.enabled_tools,
5
+ * mcpserver/v1/spec.proto McpServerSpec.default_enabled_tools):
6
+ * - A non-empty enabled_tools on the usage is the allow-list for that server.
7
+ * - An empty usage list falls back to the server's default_enabled_tools.
8
+ * - Both empty means NO restriction — every discovered tool is available.
9
+ *
10
+ * Both harnesses import THIS module so they can never drift on these
11
+ * semantics (the mcp-transport-guard precedent for logic shared across the
12
+ * duplicated resolvers — see the header of shared/mcp-resolver.ts):
13
+ * - The deep-agent harness filters the discovered toolset before it reaches
14
+ * the model (shared/mcp-manager.ts connectMcpServers).
15
+ * - The Cursor harness cannot hide tools (the Cursor SDK's McpServerConfig
16
+ * has no allow-list field), so it denies non-enabled calls in the HITL
17
+ * hook instead (execute-cursor/approval-state.ts mcpServerEnabledTools +
18
+ * the "disabled" arm in hook-script.ts). Same guarantee, fail-closed.
19
+ *
20
+ * Names are bare tool names exactly as reported by tools/list — the same
21
+ * identity space as the sub-agent McpAccess filter and the approval-policy
22
+ * maps. An enabled name the server does not expose is warned and dropped
23
+ * (enforce the intersection): the restriction still holds and the run
24
+ * proceeds with the valid subset; apply-time validation against
25
+ * discovered_capabilities is the server-side follow-up that catches typos.
26
+ */
27
+ /**
28
+ * Compute the effective allow-list for one resolved MCP server.
29
+ *
30
+ * Returns `undefined` when the server is unrestricted (both lists empty) —
31
+ * the absent-field shape ResolvedMcpServer carries so synthesized attachment
32
+ * servers and the discovery path stay unfiltered by construction.
33
+ */
34
+ export function effectiveEnabledTools(usageEnabledTools, defaultEnabledTools) {
35
+ if (usageEnabledTools && usageEnabledTools.length > 0) {
36
+ return [...usageEnabledTools];
37
+ }
38
+ if (defaultEnabledTools && defaultEnabledTools.length > 0) {
39
+ return [...defaultEnabledTools];
40
+ }
41
+ return undefined;
42
+ }
43
+ /**
44
+ * Filter a server's discovered tools by its effective allow-list.
45
+ *
46
+ * `undefined` enabledTools → unrestricted, tools pass through untouched.
47
+ * Otherwise only tools whose bare name is on the list survive; enabled names
48
+ * the server does not expose are warned and ignored (warn-and-intersect —
49
+ * a stale or mistyped name must narrow the toolset, never widen it or fail
50
+ * the run).
51
+ */
52
+ export function filterToolsByEnabledTools(slug, tools, enabledTools) {
53
+ if (!enabledTools) {
54
+ return [...tools];
55
+ }
56
+ const allowed = new Set(enabledTools);
57
+ const filtered = tools.filter((tool) => allowed.has(tool.name));
58
+ const discovered = new Set(tools.map((t) => t.name));
59
+ const unknown = enabledTools.filter((name) => !discovered.has(name));
60
+ if (unknown.length > 0) {
61
+ console.warn(`[MCP] Server '${slug}': enabled_tools lists [${unknown.join(", ")}] ` +
62
+ `which the server does not expose — ignoring (the run proceeds with ` +
63
+ `the ${filtered.length} matching tool(s)). Fix the agent's ` +
64
+ `enabled_tools to match the server's discovered tools.`);
65
+ }
66
+ console.log(`[MCP] Server '${slug}': enabled_tools restricts ${tools.length} ` +
67
+ `discovered tool(s) to ${filtered.length}`);
68
+ return filtered;
69
+ }
70
+ /**
71
+ * Collect the restricted servers' allow-lists keyed by slug — the shape the
72
+ * Cursor harness writes into the approval state file (mcpServerEnabledTools)
73
+ * for the hook's "disabled" arm. Unrestricted servers are ABSENT (the hook
74
+ * treats an absent slug as unrestricted), so the common no-restriction case
75
+ * stays an empty object.
76
+ */
77
+ export function enabledToolsBySlug(servers) {
78
+ const bySlug = {};
79
+ for (const server of servers) {
80
+ if (server.enabledTools) {
81
+ bySlug[server.slug] = [...server.enabledTools];
82
+ }
83
+ }
84
+ return bySlug;
85
+ }
86
+ //# sourceMappingURL=mcp-enabled-tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-enabled-tools.js","sourceRoot":"","sources":["../../src/shared/mcp-enabled-tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH;;;;;;GAMG;AACH,MAAM,UAAU,qBAAqB,CACnC,iBAAgD,EAChD,mBAAkD;IAElD,IAAI,iBAAiB,IAAI,iBAAiB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACtD,OAAO,CAAC,GAAG,iBAAiB,CAAC,CAAC;IAChC,CAAC;IACD,IAAI,mBAAmB,IAAI,mBAAmB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC1D,OAAO,CAAC,GAAG,mBAAmB,CAAC,CAAC;IAClC,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,yBAAyB,CACvC,IAAY,EACZ,KAAmB,EACnB,YAA2C;IAE3C,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,OAAO,CAAC,GAAG,KAAK,CAAC,CAAC;IACpB,CAAC;IAED,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,YAAY,CAAC,CAAC;IACtC,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IAEhE,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IACrD,MAAM,OAAO,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;IACrE,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,OAAO,CAAC,IAAI,CACV,iBAAiB,IAAI,2BAA2B,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI;YACtE,qEAAqE;YACrE,OAAO,QAAQ,CAAC,MAAM,sCAAsC;YAC5D,uDAAuD,CACxD,CAAC;IACJ,CAAC;IAED,OAAO,CAAC,GAAG,CACT,iBAAiB,IAAI,8BAA8B,KAAK,CAAC,MAAM,GAAG;QAClE,yBAAyB,QAAQ,CAAC,MAAM,EAAE,CAC3C,CAAC;IAEF,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB,CAChC,OAA6D;IAE7D,MAAM,MAAM,GAA6B,EAAE,CAAC;IAC5C,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,IAAI,MAAM,CAAC,YAAY,EAAE,CAAC;YACxB,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,YAAY,CAAC,CAAC;QACjD,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}