@stigmer/server 3.20.0 → 3.22.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 (257) hide show
  1. package/dist/authorization/evaluator.d.ts +7 -1
  2. package/dist/authorization/evaluator.d.ts.map +1 -1
  3. package/dist/authorization/evaluator.js.map +1 -1
  4. package/dist/authorization/list-read-scope.d.ts.map +1 -1
  5. package/dist/authorization/list-read-scope.js +19 -11
  6. package/dist/authorization/list-read-scope.js.map +1 -1
  7. package/dist/authorization/model/organization.d.ts.map +1 -1
  8. package/dist/authorization/model/organization.js +2 -0
  9. package/dist/authorization/model/organization.js.map +1 -1
  10. package/dist/boot/compose.d.ts.map +1 -1
  11. package/dist/boot/compose.js +0 -1
  12. package/dist/boot/compose.js.map +1 -1
  13. package/dist/boot/inprocess.d.ts +0 -2
  14. package/dist/boot/inprocess.d.ts.map +1 -1
  15. package/dist/boot/inprocess.js +0 -6
  16. package/dist/boot/inprocess.js.map +1 -1
  17. package/dist/domain/agent/controller.d.ts +2 -2
  18. package/dist/domain/agent/controller.d.ts.map +1 -1
  19. package/dist/domain/agent/controller.js +3 -17
  20. package/dist/domain/agent/controller.js.map +1 -1
  21. package/dist/domain/agent/steps.d.ts +0 -1
  22. package/dist/domain/agent/steps.d.ts.map +1 -1
  23. package/dist/domain/agent/steps.js +1 -40
  24. package/dist/domain/agent/steps.js.map +1 -1
  25. package/dist/domain/agentchannel/controller.d.ts.map +1 -1
  26. package/dist/domain/agentchannel/controller.js +6 -1
  27. package/dist/domain/agentchannel/controller.js.map +1 -1
  28. package/dist/domain/agentchannel/steps.d.ts +19 -0
  29. package/dist/domain/agentchannel/steps.d.ts.map +1 -1
  30. package/dist/domain/agentchannel/steps.js +32 -0
  31. package/dist/domain/agentchannel/steps.js.map +1 -1
  32. package/dist/domain/agentexecution/controller.d.ts.map +1 -1
  33. package/dist/domain/agentexecution/controller.js +7 -9
  34. package/dist/domain/agentexecution/controller.js.map +1 -1
  35. package/dist/domain/agentexecution/create-execution-context-step.d.ts +0 -2
  36. package/dist/domain/agentexecution/create-execution-context-step.d.ts.map +1 -1
  37. package/dist/domain/agentexecution/create-execution-context-step.js +179 -60
  38. package/dist/domain/agentexecution/create-execution-context-step.js.map +1 -1
  39. package/dist/domain/agentexecution/create-steps.d.ts +16 -31
  40. package/dist/domain/agentexecution/create-steps.d.ts.map +1 -1
  41. package/dist/domain/agentexecution/create-steps.js +36 -102
  42. package/dist/domain/agentexecution/create-steps.js.map +1 -1
  43. package/dist/domain/agentexecution/run-target.d.ts +7 -3
  44. package/dist/domain/agentexecution/run-target.d.ts.map +1 -1
  45. package/dist/domain/agentexecution/run-target.js.map +1 -1
  46. package/dist/domain/agentinstance/controller.d.ts +5 -5
  47. package/dist/domain/agentinstance/controller.d.ts.map +1 -1
  48. package/dist/domain/agentinstance/controller.js +6 -1
  49. package/dist/domain/agentinstance/controller.js.map +1 -1
  50. package/dist/domain/agentinstance/steps.d.ts +43 -8
  51. package/dist/domain/agentinstance/steps.d.ts.map +1 -1
  52. package/dist/domain/agentinstance/steps.js +71 -8
  53. package/dist/domain/agentinstance/steps.js.map +1 -1
  54. package/dist/domain/agentshare/controller.d.ts.map +1 -1
  55. package/dist/domain/agentshare/controller.js +7 -1
  56. package/dist/domain/agentshare/controller.js.map +1 -1
  57. package/dist/domain/agentshare/steps.d.ts +58 -0
  58. package/dist/domain/agentshare/steps.d.ts.map +1 -1
  59. package/dist/domain/agentshare/steps.js +109 -4
  60. package/dist/domain/agentshare/steps.js.map +1 -1
  61. package/dist/domain/artifact/controller.js +21 -25
  62. package/dist/domain/artifact/controller.js.map +1 -1
  63. package/dist/domain/channelapp/controller.d.ts.map +1 -1
  64. package/dist/domain/channelapp/controller.js +2 -0
  65. package/dist/domain/channelapp/controller.js.map +1 -1
  66. package/dist/domain/environment/controller.d.ts.map +1 -1
  67. package/dist/domain/environment/controller.js +2 -0
  68. package/dist/domain/environment/controller.js.map +1 -1
  69. package/dist/domain/environment/personal.d.ts +42 -0
  70. package/dist/domain/environment/personal.d.ts.map +1 -0
  71. package/dist/domain/environment/personal.js +96 -0
  72. package/dist/domain/environment/personal.js.map +1 -0
  73. package/dist/domain/executioncontext/controller.d.ts.map +1 -1
  74. package/dist/domain/executioncontext/controller.js +2 -0
  75. package/dist/domain/executioncontext/controller.js.map +1 -1
  76. package/dist/domain/executioncontext/steps.d.ts.map +1 -1
  77. package/dist/domain/executioncontext/steps.js +2 -1
  78. package/dist/domain/executioncontext/steps.js.map +1 -1
  79. package/dist/domain/mcpserver/connect.d.ts +0 -2
  80. package/dist/domain/mcpserver/connect.d.ts.map +1 -1
  81. package/dist/domain/mcpserver/connect.js +24 -79
  82. package/dist/domain/mcpserver/connect.js.map +1 -1
  83. package/dist/domain/mcpserver/controller.d.ts.map +1 -1
  84. package/dist/domain/mcpserver/controller.js +2 -0
  85. package/dist/domain/mcpserver/controller.js.map +1 -1
  86. package/dist/domain/mcpserver/start-connect.d.ts.map +1 -1
  87. package/dist/domain/mcpserver/start-connect.js +8 -7
  88. package/dist/domain/mcpserver/start-connect.js.map +1 -1
  89. package/dist/domain/memory/controller.d.ts.map +1 -1
  90. package/dist/domain/memory/controller.js +6 -1
  91. package/dist/domain/memory/controller.js.map +1 -1
  92. package/dist/domain/memory/steps.d.ts +23 -0
  93. package/dist/domain/memory/steps.d.ts.map +1 -1
  94. package/dist/domain/memory/steps.js +35 -0
  95. package/dist/domain/memory/steps.js.map +1 -1
  96. package/dist/domain/oauthapp/controller.d.ts.map +1 -1
  97. package/dist/domain/oauthapp/controller.js +2 -0
  98. package/dist/domain/oauthapp/controller.js.map +1 -1
  99. package/dist/domain/plugin/controller.d.ts.map +1 -1
  100. package/dist/domain/plugin/controller.js +5 -24
  101. package/dist/domain/plugin/controller.js.map +1 -1
  102. package/dist/domain/plugin/overlay/sanitize.js +2 -2
  103. package/dist/domain/schedule/controller.d.ts.map +1 -1
  104. package/dist/domain/schedule/controller.js +7 -1
  105. package/dist/domain/schedule/controller.js.map +1 -1
  106. package/dist/domain/schedule/steps.d.ts +19 -0
  107. package/dist/domain/schedule/steps.d.ts.map +1 -1
  108. package/dist/domain/schedule/steps.js +32 -0
  109. package/dist/domain/schedule/steps.js.map +1 -1
  110. package/dist/domain/session/controller.d.ts +0 -7
  111. package/dist/domain/session/controller.d.ts.map +1 -1
  112. package/dist/domain/session/controller.js +11 -16
  113. package/dist/domain/session/controller.js.map +1 -1
  114. package/dist/domain/session/run-target.d.ts +9 -8
  115. package/dist/domain/session/run-target.d.ts.map +1 -1
  116. package/dist/domain/session/run-target.js.map +1 -1
  117. package/dist/domain/session/steps.d.ts +8 -36
  118. package/dist/domain/session/steps.d.ts.map +1 -1
  119. package/dist/domain/session/steps.js +27 -172
  120. package/dist/domain/session/steps.js.map +1 -1
  121. package/dist/domain/skill/controller.d.ts.map +1 -1
  122. package/dist/domain/skill/controller.js +8 -17
  123. package/dist/domain/skill/controller.js.map +1 -1
  124. package/dist/domain/workflow/controller.d.ts.map +1 -1
  125. package/dist/domain/workflow/controller.js +30 -107
  126. package/dist/domain/workflow/controller.js.map +1 -1
  127. package/dist/domain/workflow/version-resolution.d.ts +5 -0
  128. package/dist/domain/workflow/version-resolution.d.ts.map +1 -0
  129. package/dist/domain/workflow/version-resolution.js +113 -0
  130. package/dist/domain/workflow/version-resolution.js.map +1 -0
  131. package/dist/domain/workflowexecution/create-steps.d.ts +4 -3
  132. package/dist/domain/workflowexecution/create-steps.d.ts.map +1 -1
  133. package/dist/domain/workflowexecution/create-steps.js +4 -3
  134. package/dist/domain/workflowexecution/create-steps.js.map +1 -1
  135. package/dist/domain/workflowinstance/controller.d.ts.map +1 -1
  136. package/dist/domain/workflowinstance/controller.js +6 -1
  137. package/dist/domain/workflowinstance/controller.js.map +1 -1
  138. package/dist/domain/workflowinstance/steps.d.ts +20 -0
  139. package/dist/domain/workflowinstance/steps.d.ts.map +1 -1
  140. package/dist/domain/workflowinstance/steps.js +39 -0
  141. package/dist/domain/workflowinstance/steps.js.map +1 -1
  142. package/dist/extensions/identity.d.ts +19 -0
  143. package/dist/extensions/identity.d.ts.map +1 -1
  144. package/dist/extensions/identity.js +22 -3
  145. package/dist/extensions/identity.js.map +1 -1
  146. package/dist/extensions/list-read-scope.d.ts +41 -7
  147. package/dist/extensions/list-read-scope.d.ts.map +1 -1
  148. package/dist/extensions/list-read-scope.js +13 -2
  149. package/dist/extensions/list-read-scope.js.map +1 -1
  150. package/dist/pipeline/apiresource-labels.d.ts +2 -2
  151. package/dist/pipeline/apiresource-labels.js +2 -2
  152. package/dist/pipeline/errors.d.ts +2 -2
  153. package/dist/pipeline/errors.js +2 -2
  154. package/dist/pipeline/steps/authorize-resolved-target.d.ts +88 -0
  155. package/dist/pipeline/steps/authorize-resolved-target.d.ts.map +1 -0
  156. package/dist/pipeline/steps/authorize-resolved-target.js +36 -0
  157. package/dist/pipeline/steps/authorize-resolved-target.js.map +1 -0
  158. package/dist/pipeline/steps/authorize.d.ts +27 -0
  159. package/dist/pipeline/steps/authorize.d.ts.map +1 -1
  160. package/dist/pipeline/steps/authorize.js +49 -10
  161. package/dist/pipeline/steps/authorize.js.map +1 -1
  162. package/dist/pipeline/steps/guard-memory-capture.d.ts.map +1 -1
  163. package/dist/pipeline/steps/guard-memory-capture.js +2 -1
  164. package/dist/pipeline/steps/guard-memory-capture.js.map +1 -1
  165. package/dist/pipeline/steps/guard-reserved-labels.d.ts.map +1 -1
  166. package/dist/pipeline/steps/guard-reserved-labels.js +12 -12
  167. package/dist/pipeline/steps/guard-reserved-labels.js.map +1 -1
  168. package/dist/pipeline/steps/helpers.d.ts +9 -5
  169. package/dist/pipeline/steps/helpers.d.ts.map +1 -1
  170. package/dist/pipeline/steps/helpers.js +11 -15
  171. package/dist/pipeline/steps/helpers.js.map +1 -1
  172. package/dist/pipeline/steps/version-history.d.ts +11 -0
  173. package/dist/pipeline/steps/version-history.d.ts.map +1 -1
  174. package/dist/pipeline/steps/version-history.js +26 -0
  175. package/dist/pipeline/steps/version-history.js.map +1 -1
  176. package/package.json +6 -6
  177. package/src/authorization/__tests__/list-read-scope.test.ts +23 -12
  178. package/src/authorization/__tests__/skip-lane-inventory.test.ts +160 -0
  179. package/src/authorization/__tests__/wire-permissions.test.ts +5 -5
  180. package/src/authorization/evaluator.ts +7 -0
  181. package/src/authorization/list-read-scope.ts +22 -11
  182. package/src/authorization/model/__tests__/registry.test.ts +2 -0
  183. package/src/authorization/model/organization.ts +2 -0
  184. package/src/boot/compose.ts +0 -1
  185. package/src/boot/inprocess.ts +0 -9
  186. package/src/domain/agent/__tests__/agent.test.ts +0 -68
  187. package/src/domain/agent/controller.ts +11 -36
  188. package/src/domain/agent/steps.ts +1 -60
  189. package/src/domain/agentchannel/__tests__/create-authorization.test.ts +58 -0
  190. package/src/domain/agentchannel/controller.ts +19 -0
  191. package/src/domain/agentchannel/steps.ts +40 -0
  192. package/src/domain/agentexecution/__tests__/create-execution-context-step.test.ts +216 -0
  193. package/src/domain/agentexecution/__tests__/create-steps.test.ts +70 -145
  194. package/src/domain/agentexecution/controller.ts +6 -10
  195. package/src/domain/agentexecution/create-execution-context-step.ts +271 -83
  196. package/src/domain/agentexecution/create-steps.ts +38 -138
  197. package/src/domain/agentexecution/run-target.ts +7 -3
  198. package/src/domain/agentinstance/__tests__/create-authorization.composed.test.ts +243 -0
  199. package/src/domain/agentinstance/__tests__/create-authorization.test.ts +144 -0
  200. package/src/domain/agentinstance/controller.ts +24 -5
  201. package/src/domain/agentinstance/steps.ts +82 -8
  202. package/src/domain/agentshare/__tests__/create-authorization.test.ts +86 -0
  203. package/src/domain/agentshare/__tests__/member-audience.test.ts +113 -0
  204. package/src/domain/agentshare/controller.ts +21 -0
  205. package/src/domain/agentshare/steps.ts +181 -15
  206. package/src/domain/artifact/controller.ts +18 -22
  207. package/src/domain/channelapp/controller.ts +10 -0
  208. package/src/domain/environment/__tests__/personal.test.ts +143 -0
  209. package/src/domain/environment/controller.ts +10 -0
  210. package/src/domain/environment/personal.ts +141 -0
  211. package/src/domain/executioncontext/__tests__/executioncontext.test.ts +1 -0
  212. package/src/domain/executioncontext/controller.ts +10 -0
  213. package/src/domain/executioncontext/steps.ts +2 -1
  214. package/src/domain/mcpserver/connect.ts +32 -92
  215. package/src/domain/mcpserver/controller.ts +13 -1
  216. package/src/domain/mcpserver/start-connect.ts +17 -11
  217. package/src/domain/memory/__tests__/create-authorization.test.ts +59 -0
  218. package/src/domain/memory/controller.ts +11 -0
  219. package/src/domain/memory/steps.ts +41 -0
  220. package/src/domain/oauthapp/controller.ts +10 -0
  221. package/src/domain/plugin/controller.ts +22 -36
  222. package/src/domain/plugin/overlay/sanitize.ts +2 -2
  223. package/src/domain/schedule/__tests__/create-authorization.test.ts +58 -0
  224. package/src/domain/schedule/controller.ts +20 -0
  225. package/src/domain/schedule/steps.ts +45 -2
  226. package/src/domain/session/__tests__/run-gate.test.ts +19 -52
  227. package/src/domain/session/__tests__/session.test.ts +27 -203
  228. package/src/domain/session/controller.ts +10 -30
  229. package/src/domain/session/run-target.ts +9 -8
  230. package/src/domain/session/steps.ts +33 -267
  231. package/src/domain/skill/controller.ts +24 -23
  232. package/src/domain/workflow/controller.ts +58 -145
  233. package/src/domain/workflow/version-resolution.ts +166 -0
  234. package/src/domain/workflowexecution/create-steps.ts +4 -3
  235. package/src/domain/workflowinstance/__tests__/create-authorization.test.ts +109 -0
  236. package/src/domain/workflowinstance/controller.ts +19 -0
  237. package/src/domain/workflowinstance/steps.ts +49 -1
  238. package/src/extensions/__tests__/composed-support.ts +38 -4
  239. package/src/extensions/__tests__/identity.test.ts +44 -1
  240. package/src/extensions/__tests__/list-read-scope-composed.test.ts +87 -1
  241. package/src/extensions/__tests__/list-read-scope.test.ts +63 -0
  242. package/src/extensions/identity.ts +23 -5
  243. package/src/extensions/list-read-scope.ts +47 -7
  244. package/src/pipeline/apiresource-labels.ts +2 -2
  245. package/src/pipeline/errors.ts +2 -2
  246. package/src/pipeline/steps/__tests__/authorize-resolved-target.test.ts +285 -0
  247. package/src/pipeline/steps/authorize-resolved-target.ts +129 -0
  248. package/src/pipeline/steps/authorize.ts +70 -13
  249. package/src/pipeline/steps/guard-memory-capture.ts +2 -1
  250. package/src/pipeline/steps/guard-reserved-labels.ts +12 -14
  251. package/src/pipeline/steps/helpers.ts +11 -15
  252. package/src/pipeline/steps/version-history.ts +34 -0
  253. package/dist/domain/agent/defaultagent.d.ts +0 -37
  254. package/dist/domain/agent/defaultagent.d.ts.map +0 -1
  255. package/dist/domain/agent/defaultagent.js +0 -104
  256. package/dist/domain/agent/defaultagent.js.map +0 -1
  257. package/src/domain/agent/defaultagent.ts +0 -135
@@ -11,15 +11,26 @@
11
11
  * Resolution chain:
12
12
  * - Path A (preResolvedInstanceId): agentInstanceLoader → agentLoader
13
13
  * - Path B (session_id): sessionLoader → session.agent_instance_id →
14
- * agentInstanceLoader → agentLoader
14
+ * agentInstanceLoader → agentLoader; an EMPTY agent_instance_id is the
15
+ * built-in assistant (session/v1/spec.proto): no instance, no agent,
16
+ * no instance layers, and the session's own MCP servers are the whole
17
+ * tool set.
15
18
  *
16
19
  * Merge priority (lowest to highest): schedule/workflow-task
17
20
  * environment_refs (the share/channel/schedule/agent_call layering) →
18
21
  * instance environment_refs (via the environment RuntimeResolutionService
19
22
  * — decrypted, the RPC surface redacts, oss#405) → spec.runtime_env.
20
- * Then the declared-key least-privilege filter, the
21
- * workspace-provisioning re-injection + personal-environment fallback,
22
- * the MCP OAuth injection with inline pre-flight refresh, and the
23
+ *
24
+ * Then ONE declaration rule for every shape: the run declares what its
25
+ * agent declares and what its session's MCP servers declare, and the
26
+ * least-privilege filter keeps exactly those keys. A session server rides
27
+ * no agent instance, so its declared variables have no environment_refs
28
+ * to arrive through; the ones still missing after the merge are resolved
29
+ * the way the MCP connect lane resolves them — OAuth tokens from the
30
+ * managed grant, the rest from the caller's personal environment, by
31
+ * declared key only (domain/environment/personal.ts). The built-in
32
+ * assistant is the case with no agent half, not an arm of its own.
33
+ * Around that rule: the workspace-provisioning re-injection, and the
23
34
  * required-keys warning.
24
35
  */
25
36
  import { create } from "@bufbuild/protobuf";
@@ -37,12 +48,16 @@ import {
37
48
  ListEnvironmentsRequestSchema,
38
49
  } from "@stigmer/protos/ai/stigmer/agentic/environment/v1/io_pb";
39
50
  import { EnvironmentValueSchema } from "@stigmer/protos/ai/stigmer/agentic/environment/v1/spec_pb";
40
- import type { EnvironmentValue } from "@stigmer/protos/ai/stigmer/agentic/environment/v1/spec_pb";
51
+ import type {
52
+ EnvVarDeclaration,
53
+ EnvironmentValue,
54
+ } from "@stigmer/protos/ai/stigmer/agentic/environment/v1/spec_pb";
41
55
  import type { ExecutionContext } from "@stigmer/protos/ai/stigmer/agentic/executioncontext/v1/api_pb";
42
56
  import { ExecutionContextSchema } from "@stigmer/protos/ai/stigmer/agentic/executioncontext/v1/api_pb";
43
57
  import type { ExecutionValue } from "@stigmer/protos/ai/stigmer/agentic/executioncontext/v1/spec_pb";
44
58
  import { ExecutionValueSchema } from "@stigmer/protos/ai/stigmer/agentic/executioncontext/v1/spec_pb";
45
59
  import { McpServerSchema } from "@stigmer/protos/ai/stigmer/agentic/mcpserver/v1/api_pb";
60
+ import type { McpServer } from "@stigmer/protos/ai/stigmer/agentic/mcpserver/v1/api_pb";
46
61
  import { ScheduleSchema } from "@stigmer/protos/ai/stigmer/agentic/schedule/v1/api_pb";
47
62
  import type { Session } from "@stigmer/protos/ai/stigmer/agentic/session/v1/api_pb";
48
63
  import { WorkflowSchema } from "@stigmer/protos/ai/stigmer/agentic/workflow/v1/api_pb";
@@ -72,6 +87,12 @@ import type { PipelineStep } from "../../pipeline/pipeline.js";
72
87
  import { findResourceBySlug } from "../../pipeline/steps/helpers.js";
73
88
  import { ResourceNotFoundError } from "../../store/interface.js";
74
89
  import type { OAuthGrant, Store } from "../../store/interface.js";
90
+ import {
91
+ PERSONAL_LABEL_KEY,
92
+ PERSONAL_LABEL_VALUE,
93
+ } from "../environment/constants.js";
94
+ import { resolveDeclaredFromPersonalEnvironment } from "../environment/personal.js";
95
+ import type { PersonalEnvironmentResolution } from "../environment/personal.js";
75
96
  import type { RuntimeResolutionService } from "../environment/resolution/resolution.js";
76
97
  import type { ManagedEnvironmentService } from "../mcpserver/oauth/managed-env.js";
77
98
  import { refreshTokenIfExpired } from "../mcpserver/oauth/refresh.js";
@@ -107,9 +128,6 @@ export const WORKFLOW_TASK_LABEL_KEY = "stigmer.ai/workflow-task";
107
128
  */
108
129
  export const WORKSPACE_PROVISIONING_KEYS = ["GITHUB_TOKEN"];
109
130
 
110
- /** The well-known label identifying a user's personal environment. */
111
- export const PERSONAL_ENV_LABEL = "stigmer.ai/personal";
112
-
113
131
  // ---------------------------------------------------------------------------
114
132
  // The narrow in-process edges the builder consumes (DD-002 lazy providers).
115
133
  // ---------------------------------------------------------------------------
@@ -206,48 +224,77 @@ export async function buildAndPersistExecutionContext(
206
224
  const executionId = execution.metadata?.id ?? "";
207
225
  const executionOrg = execution.metadata?.org ?? "";
208
226
 
209
- // 1. Resolve agent_instance_id.
210
- let agentInstanceId: string;
227
+ // 1. Resolve the target: the instance the run is bound to, and the
228
+ // session when Path B loaded it on the way. An empty instance id with a
229
+ // session is the built-in assistant.
230
+ let target: ResolvedTarget;
211
231
  try {
212
- agentInstanceId = await resolveAgentInstanceId(
213
- deps,
214
- execution,
215
- preResolvedInstanceId,
216
- );
232
+ target = await resolveTarget(deps, execution, preResolvedInstanceId);
217
233
  } catch (error) {
218
234
  chainError("resolve agent instance", error);
219
235
  }
236
+ const { agentInstanceId } = target;
237
+ let session = target.session;
220
238
 
221
239
  // 2.–3. Load the instance (environment_refs + agent_id), then the
222
240
  // agent (env declarations) — in-process, full chain traversal. Load
223
- // failures keep the inner status code with Go's wrap prefix.
224
- let instance: AgentInstance;
225
- try {
226
- instance = await deps.agentInstanceLoader().get(agentInstanceId);
227
- } catch (error) {
228
- if (error instanceof ConnectError) {
229
- throw goWrappedStatusError(
230
- `load agent instance ${agentInstanceId}`,
231
- error,
232
- );
241
+ // failures keep the inner status code with Go's wrap prefix. Neither
242
+ // exists for the built-in assistant.
243
+ let instance: AgentInstance | undefined;
244
+ let agentResource: Agent | undefined;
245
+ let agentId = "";
246
+ if (agentInstanceId !== "") {
247
+ try {
248
+ instance = await deps.agentInstanceLoader().get(agentInstanceId);
249
+ } catch (error) {
250
+ if (error instanceof ConnectError) {
251
+ throw goWrappedStatusError(
252
+ `load agent instance ${agentInstanceId}`,
253
+ error,
254
+ );
255
+ }
256
+ chainError(`load agent instance ${agentInstanceId}`, error);
257
+ }
258
+ agentId = instance.spec?.agentId ?? "";
259
+ try {
260
+ agentResource = await deps.agentLoader().get(agentId);
261
+ } catch (error) {
262
+ if (error instanceof ConnectError) {
263
+ throw goWrappedStatusError(`load agent ${agentId}`, error);
264
+ }
265
+ chainError(`load agent ${agentId}`, error);
233
266
  }
234
- chainError(`load agent instance ${agentInstanceId}`, error);
235
267
  }
236
- const agentId = instance.spec?.agentId ?? "";
237
- let agentResource: Agent;
238
- try {
239
- agentResource = await deps.agentLoader().get(agentId);
240
- } catch (error) {
241
- if (error instanceof ConnectError) {
242
- throw goWrappedStatusError(`load agent ${agentId}`, error);
268
+
269
+ // 3.5 The session, when Path A did not load it: its workspace entries
270
+ // and its own MCP servers shape the environment below. A failed load is
271
+ // non-fatal for an agent-bound run (the agent's declarations still
272
+ // stand); the built-in assistant always arrives through Path B, so its
273
+ // session is already in hand or the resolve above refused.
274
+ const sessionId = execution.spec?.sessionId ?? "";
275
+ if (session === undefined && sessionId !== "") {
276
+ try {
277
+ session = await deps.sessionLoader().get(sessionId);
278
+ } catch (error) {
279
+ deps.logger.warn(
280
+ "Failed to load session for environment resolution (non-fatal)",
281
+ {
282
+ executionId,
283
+ error: error instanceof Error ? error.message : String(error),
284
+ },
285
+ );
243
286
  }
244
- chainError(`load agent ${agentId}`, error);
245
287
  }
288
+ const sessionMcpServers = await loadSessionMcpServers(
289
+ deps,
290
+ session,
291
+ executionOrg,
292
+ );
246
293
 
247
294
  // 4. Resolve environments from instance environment_refs.
248
295
  let environments = await resolveEnvironments(
249
296
  deps,
250
- instance.spec?.environmentRefs ?? [],
297
+ instance?.spec?.environmentRefs ?? [],
251
298
  );
252
299
 
253
300
  // 4.5 Schedule-created executions: the schedule's own environment_refs
@@ -282,13 +329,17 @@ export async function buildAndPersistExecutionContext(
282
329
  execution.spec?.runtimeEnv ?? {},
283
330
  );
284
331
 
285
- // 6. Least-privilege whitelist: agents only receive variables they
286
- // explicitly declared; nil/empty declarations pass everything through.
287
- const agentEnvDecls = agentResource.spec?.env ?? {};
288
- const filterResult = filterByDeclaredKeys(merged, agentEnvDecls);
332
+ // 6. Least-privilege whitelist over the ONE declared set: the agent's
333
+ // env united with the session servers' env (the module header's rule).
334
+ // Empty declarations pass everything through.
335
+ const declarations = unionDeclarations(
336
+ agentResource?.spec?.env ?? {},
337
+ sessionMcpServers,
338
+ );
339
+ const filterResult = filterByDeclaredKeys(merged, declarations);
289
340
  let filtered = filterResult.filtered;
290
341
  if (filterResult.excludedKeys.length > 0) {
291
- deps.logger.warn("Filtered env vars not declared in agent env", {
342
+ deps.logger.warn("Filtered env vars not declared by the agent or the session's servers", {
292
343
  executionId,
293
344
  agentId,
294
345
  excludedKeys: filterResult.excludedKeys,
@@ -297,40 +348,25 @@ export async function buildAndPersistExecutionContext(
297
348
 
298
349
  // 6.5 Re-inject workspace-provisioning keys excluded by the filter,
299
350
  // and fall back to the caller's personal environment for keys never in
300
- // the merge chain at all. Session load failures are non-fatal.
301
- const sessionId = execution.spec?.sessionId ?? "";
302
- let session: Session | undefined;
303
- if (sessionId !== "") {
304
- try {
305
- session = await deps.sessionLoader().get(sessionId);
306
- } catch (error) {
307
- deps.logger.warn(
308
- "Failed to load session for workspace provisioning key injection (non-fatal)",
309
- {
310
- executionId,
311
- error: error instanceof Error ? error.message : String(error),
312
- },
313
- );
314
- }
315
- if (session !== undefined) {
316
- filtered = injectWorkspaceProvisioningKeys(
317
- deps.logger,
318
- filtered,
319
- merged,
320
- session,
321
- executionId,
322
- );
323
- filtered = await injectFromPersonalEnvironment(
324
- deps,
325
- filtered,
326
- session,
327
- executionOrg,
328
- executionId,
329
- );
330
- }
351
+ // the merge chain at all.
352
+ if (session !== undefined) {
353
+ filtered = injectWorkspaceProvisioningKeys(
354
+ deps.logger,
355
+ filtered,
356
+ merged,
357
+ session,
358
+ executionId,
359
+ );
360
+ filtered = await injectFromPersonalEnvironment(
361
+ deps,
362
+ filtered,
363
+ session,
364
+ executionOrg,
365
+ executionId,
366
+ );
331
367
  }
332
368
 
333
- // 6.7 Inject OAuth-managed MCP variables from managed environments,
369
+ // 6.8 Inject OAuth tokens from managed environments — iterated
334
370
  // over the merged agent + session MCP usages so session-level servers
335
371
  // (added at runtime) get their tokens too. Refresh failures are FATAL
336
372
  // (FailedPrecondition): an expired token must prevent execution rather
@@ -353,9 +389,21 @@ export async function buildAndPersistExecutionContext(
353
389
  );
354
390
  }
355
391
 
392
+ // 6.85 The session servers' declared variables the chain did not carry
393
+ // (no instance layer ever could): the caller's personal environment, by
394
+ // declared key. Non-fatal — the run fails at the tool with a clearer
395
+ // error if a key is truly required, the posture of every fallback here.
396
+ filtered = await injectSessionServerDeclaredFromPersonalEnvironment(
397
+ deps,
398
+ filtered,
399
+ sessionMcpServers,
400
+ executionOrg,
401
+ executionId,
402
+ );
403
+
356
404
  // 6.9 Warn on missing required declared vars — the downstream
357
405
  // execution fails with a clearer error if truly needed.
358
- const missingRequired = validateRequiredKeys(filtered, agentEnvDecls);
406
+ const missingRequired = validateRequiredKeys(filtered, declarations);
359
407
  if (missingRequired.length > 0) {
360
408
  deps.logger.warn(
361
409
  "Required env vars missing after environment merge — execution may fail",
@@ -367,7 +415,8 @@ export async function buildAndPersistExecutionContext(
367
415
  executionId,
368
416
  mergedCount: merged.size,
369
417
  filteredCount: filtered.size,
370
- environmentRefsCount: instance.spec?.environmentRefs.length ?? 0,
418
+ environmentRefsCount: instance?.spec?.environmentRefs.length ?? 0,
419
+ builtInAssistant: agentInstanceId === "",
371
420
  });
372
421
 
373
422
  // 7. Build and persist the ExecutionContext through the in-process
@@ -423,14 +472,26 @@ function chainError(prefix: string, error: unknown): never {
423
472
  );
424
473
  }
425
474
 
426
- /** Path A/Path B instance resolution (Go resolveAgentInstanceID). */
427
- async function resolveAgentInstanceId(
475
+ /**
476
+ * The run's target (Go resolveAgentInstanceID, widened): Path A answers
477
+ * the pre-resolved instance alone; Path B loads the session and answers
478
+ * its instance, which is "" for the built-in assistant, together with the
479
+ * session so the caller does not load it twice. A persisted execution
480
+ * always carries session_id (lifecycle.ts recover), so the no-session arm
481
+ * is an invariant, not a shape.
482
+ */
483
+ interface ResolvedTarget {
484
+ readonly agentInstanceId: string;
485
+ readonly session: Session | undefined;
486
+ }
487
+
488
+ async function resolveTarget(
428
489
  deps: ExecutionContextBuilderDeps,
429
490
  execution: AgentExecution,
430
491
  preResolvedInstanceId: string,
431
- ): Promise<string> {
492
+ ): Promise<ResolvedTarget> {
432
493
  if (preResolvedInstanceId !== "") {
433
- return preResolvedInstanceId;
494
+ return { agentInstanceId: preResolvedInstanceId, session: undefined };
434
495
  }
435
496
  const sessionId = execution.spec?.sessionId ?? "";
436
497
  if (sessionId === "") {
@@ -449,11 +510,138 @@ async function resolveAgentInstanceId(
449
510
  `load session ${sessionId}: ${error instanceof Error ? error.message : String(error)}`,
450
511
  );
451
512
  }
452
- const agentInstanceId = session.spec?.agentInstanceId ?? "";
453
- if (agentInstanceId === "") {
454
- throw new Error(`session ${sessionId} has no agent_instance_id`);
513
+ return { agentInstanceId: session.spec?.agentInstanceId ?? "", session };
514
+ }
515
+
516
+ /**
517
+ * Loads the MCP servers a session declares on its own (spec.mcp_server_usages),
518
+ * by slug in the usage's org or the execution's. A server that cannot be
519
+ * found is skipped: the runner resolves the same usages for real and
520
+ * refuses there with the tool's own error; this pass only needs the
521
+ * declarations of the servers that exist.
522
+ */
523
+ async function loadSessionMcpServers(
524
+ deps: ExecutionContextBuilderDeps,
525
+ session: Session | undefined,
526
+ executionOrg: string,
527
+ ): Promise<McpServer[]> {
528
+ const servers: McpServer[] = [];
529
+ for (const usage of session?.spec?.mcpServerUsages ?? []) {
530
+ const slug = usage.mcpServerRef?.slug ?? "";
531
+ const org = usage.mcpServerRef?.org || executionOrg;
532
+ if (slug === "" || org === "") {
533
+ continue;
534
+ }
535
+ let server: McpServer | undefined;
536
+ try {
537
+ server = await findResourceBySlug(
538
+ deps.store,
539
+ ApiResourceKind.mcp_server,
540
+ McpServerSchema,
541
+ slug,
542
+ org,
543
+ );
544
+ } catch {
545
+ continue;
546
+ }
547
+ if (server !== undefined) {
548
+ servers.push(server);
549
+ }
455
550
  }
456
- return agentInstanceId;
551
+ return servers;
552
+ }
553
+
554
+ /**
555
+ * The one declared set of a run: the agent's env declarations united with
556
+ * every session server's. On a key both declare, the agent's declaration
557
+ * wins (it is the author's word for the run as a whole; the server's is
558
+ * the tool's word for itself).
559
+ */
560
+ function unionDeclarations(
561
+ agentEnv: { readonly [key: string]: EnvVarDeclaration },
562
+ sessionMcpServers: readonly McpServer[],
563
+ ): { [key: string]: EnvVarDeclaration } {
564
+ const union: { [key: string]: EnvVarDeclaration } = {};
565
+ for (const server of sessionMcpServers) {
566
+ Object.assign(union, server.spec?.env ?? {});
567
+ }
568
+ Object.assign(union, agentEnv);
569
+ return union;
570
+ }
571
+
572
+ /**
573
+ * Resolves the session servers' declared variables still missing after
574
+ * the merge and the OAuth injection from the caller's personal
575
+ * environment, by declared key. OAuth-target variables are left to the
576
+ * managed grant (an absent grant is the sign-in the console asks for, not
577
+ * a personal-environment lookup). Every failure is non-fatal here: a
578
+ * missing key is logged and the run meets the tool's own error.
579
+ */
580
+ async function injectSessionServerDeclaredFromPersonalEnvironment(
581
+ deps: ExecutionContextBuilderDeps,
582
+ filtered: Map<string, ExecutionValue>,
583
+ sessionMcpServers: readonly McpServer[],
584
+ executionOrg: string,
585
+ executionId: string,
586
+ ): Promise<Map<string, ExecutionValue>> {
587
+ const wanted: { [key: string]: EnvVarDeclaration } = {};
588
+ for (const server of sessionMcpServers) {
589
+ const oauthKey = server.spec?.auth?.targetEnvVar ?? "";
590
+ for (const [key, decl] of Object.entries(server.spec?.env ?? {})) {
591
+ if (key === oauthKey || filtered.has(key)) {
592
+ continue;
593
+ }
594
+ wanted[key] = decl;
595
+ }
596
+ }
597
+ if (Object.keys(wanted).length === 0 || executionOrg === "") {
598
+ return filtered;
599
+ }
600
+
601
+ let resolution: PersonalEnvironmentResolution;
602
+ try {
603
+ resolution = await resolveDeclaredFromPersonalEnvironment(
604
+ deps.environmentReader(),
605
+ deps.logger,
606
+ executionOrg,
607
+ wanted,
608
+ );
609
+ } catch (error) {
610
+ deps.logger.warn(
611
+ "Failed to resolve session servers' variables from the personal environment (non-fatal)",
612
+ {
613
+ executionId,
614
+ error: error instanceof Error ? error.message : String(error),
615
+ },
616
+ );
617
+ return filtered;
618
+ }
619
+ if (resolution.kind === "no-personal-environment") {
620
+ deps.logger.debug(
621
+ "No personal environment — session servers' declared variables stay unresolved",
622
+ { executionId, keys: Object.keys(wanted).sort() },
623
+ );
624
+ return filtered;
625
+ }
626
+ if (resolution.missing.length > 0) {
627
+ deps.logger.warn(
628
+ "Session servers declare required variables the personal environment does not hold",
629
+ { executionId, missing: [...resolution.missing].sort() },
630
+ );
631
+ }
632
+ const entries = Object.entries(resolution.values);
633
+ if (entries.length === 0) {
634
+ return filtered;
635
+ }
636
+ const out = new Map(filtered);
637
+ for (const [key, value] of entries) {
638
+ out.set(key, value);
639
+ }
640
+ deps.logger.info(
641
+ "Injected session servers' declared variables from the caller's personal environment",
642
+ { executionId, keys: entries.map(([key]) => key).sort() },
643
+ );
644
+ return out;
457
645
  }
458
646
 
459
647
  /**
@@ -785,7 +973,7 @@ async function injectFromPersonalEnvironment(
785
973
  listResponse = await deps.environmentReader().list(
786
974
  create(ListEnvironmentsRequestSchema, {
787
975
  org: executionOrg,
788
- labels: { [PERSONAL_ENV_LABEL]: "true" },
976
+ labels: { [PERSONAL_LABEL_KEY]: PERSONAL_LABEL_VALUE },
789
977
  }),
790
978
  );
791
979
  } catch (error) {