@truefoundry/trueforge-core 0.1.2 → 0.1.4-rc.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 (117) hide show
  1. package/dist/agent-session/TurnResourceResolver.d.ts.map +1 -1
  2. package/dist/agent-session/TurnResourceResolver.js +1 -4
  3. package/dist/agent-session/TurnResourceResolver.js.map +1 -1
  4. package/dist/agent-session/TurnResourceResolver.mjs +1 -4
  5. package/dist/agent-session/TurnResourceResolver.mjs.map +1 -1
  6. package/dist/agent-session/index.d.ts +1 -1
  7. package/dist/agent-session/index.d.ts.map +1 -1
  8. package/dist/agent-session/index.js.map +1 -1
  9. package/dist/agent-session/index.mjs.map +1 -1
  10. package/dist/agent-session/schemas/agentSpec.d.ts +7 -28
  11. package/dist/agent-session/schemas/agentSpec.d.ts.map +1 -1
  12. package/dist/agent-session/schemas/agentSpec.js +15 -43
  13. package/dist/agent-session/schemas/agentSpec.js.map +1 -1
  14. package/dist/agent-session/schemas/agentSpec.mjs +15 -43
  15. package/dist/agent-session/schemas/agentSpec.mjs.map +1 -1
  16. package/dist/agent-session/schemas/session.d.ts +0 -39
  17. package/dist/agent-session/schemas/session.d.ts.map +1 -1
  18. package/dist/core/index.d.ts +4 -1
  19. package/dist/core/index.d.ts.map +1 -1
  20. package/dist/core/index.js +12 -0
  21. package/dist/core/index.js.map +1 -1
  22. package/dist/core/index.mjs +7 -0
  23. package/dist/core/index.mjs.map +1 -1
  24. package/dist/core/runtime/AgentThread.d.ts.map +1 -1
  25. package/dist/core/runtime/AgentThread.js +25 -11
  26. package/dist/core/runtime/AgentThread.js.map +1 -1
  27. package/dist/core/runtime/AgentThread.mjs +25 -11
  28. package/dist/core/runtime/AgentThread.mjs.map +1 -1
  29. package/dist/core/sandbox/Sandbox.d.ts +15 -5
  30. package/dist/core/sandbox/Sandbox.d.ts.map +1 -1
  31. package/dist/core/sandbox/Sandbox.js +200 -84
  32. package/dist/core/sandbox/Sandbox.js.map +1 -1
  33. package/dist/core/sandbox/Sandbox.mjs +201 -85
  34. package/dist/core/sandbox/Sandbox.mjs.map +1 -1
  35. package/dist/core/sandbox/SandboxErrors.d.ts +7 -3
  36. package/dist/core/sandbox/SandboxErrors.d.ts.map +1 -1
  37. package/dist/core/sandbox/SandboxErrors.js +6 -6
  38. package/dist/core/sandbox/SandboxErrors.js.map +1 -1
  39. package/dist/core/sandbox/SandboxErrors.mjs +6 -6
  40. package/dist/core/sandbox/SandboxErrors.mjs.map +1 -1
  41. package/dist/core/sandbox/codeMode/CodeModeTransport.d.ts +22 -0
  42. package/dist/core/sandbox/codeMode/CodeModeTransport.d.ts.map +1 -1
  43. package/dist/core/sandbox/codeMode/CodeModeTransport.js.map +1 -1
  44. package/dist/core/sandbox/codeMode/nats/CodeModeNatsTransport.d.ts +9 -1
  45. package/dist/core/sandbox/codeMode/nats/CodeModeNatsTransport.d.ts.map +1 -1
  46. package/dist/core/sandbox/codeMode/nats/CodeModeNatsTransport.js +12 -0
  47. package/dist/core/sandbox/codeMode/nats/CodeModeNatsTransport.js.map +1 -1
  48. package/dist/core/sandbox/codeMode/nats/CodeModeNatsTransport.mjs +12 -0
  49. package/dist/core/sandbox/codeMode/nats/CodeModeNatsTransport.mjs.map +1 -1
  50. package/dist/core/sandbox/constants.d.ts +0 -2
  51. package/dist/core/sandbox/constants.d.ts.map +1 -1
  52. package/dist/core/sandbox/constants.js +2 -5
  53. package/dist/core/sandbox/constants.js.map +1 -1
  54. package/dist/core/sandbox/constants.mjs +1 -3
  55. package/dist/core/sandbox/constants.mjs.map +1 -1
  56. package/dist/core/sandbox/provider/DaytonaProvider.d.ts +4 -0
  57. package/dist/core/sandbox/provider/DaytonaProvider.d.ts.map +1 -1
  58. package/dist/core/sandbox/provider/DaytonaProvider.js +27 -5
  59. package/dist/core/sandbox/provider/DaytonaProvider.js.map +1 -1
  60. package/dist/core/sandbox/provider/DaytonaProvider.mjs +27 -4
  61. package/dist/core/sandbox/provider/DaytonaProvider.mjs.map +1 -1
  62. package/dist/core/sandbox/provider/Provider.d.ts +13 -1
  63. package/dist/core/sandbox/provider/Provider.d.ts.map +1 -1
  64. package/dist/core/sandbox/provider/Provider.js.map +1 -1
  65. package/dist/core/sandbox/provider/Provider.mjs.map +1 -1
  66. package/dist/core/sandbox/provider/TFYSandboxProvider.d.ts +17 -2
  67. package/dist/core/sandbox/provider/TFYSandboxProvider.d.ts.map +1 -1
  68. package/dist/core/sandbox/provider/TFYSandboxProvider.js +81 -17
  69. package/dist/core/sandbox/provider/TFYSandboxProvider.js.map +1 -1
  70. package/dist/core/sandbox/provider/TFYSandboxProvider.mjs +82 -13
  71. package/dist/core/sandbox/provider/TFYSandboxProvider.mjs.map +1 -1
  72. package/dist/core/sandbox/provider/execEnv.d.ts +6 -0
  73. package/dist/core/sandbox/provider/execEnv.d.ts.map +1 -0
  74. package/dist/core/sandbox/provider/execEnv.js +55 -0
  75. package/dist/core/sandbox/provider/execEnv.js.map +1 -0
  76. package/dist/core/sandbox/provider/execEnv.mjs +30 -0
  77. package/dist/core/sandbox/provider/execEnv.mjs.map +1 -0
  78. package/dist/core/sandbox/sandboxImage.d.ts +2 -5
  79. package/dist/core/sandbox/sandboxImage.d.ts.map +1 -1
  80. package/dist/core/sandbox/sandboxImage.js +8 -1
  81. package/dist/core/sandbox/sandboxImage.js.map +1 -1
  82. package/dist/core/sandbox/sandboxImage.mjs +6 -1
  83. package/dist/core/sandbox/sandboxImage.mjs.map +1 -1
  84. package/dist/core/sandbox/sandboxRef.d.ts +26 -0
  85. package/dist/core/sandbox/sandboxRef.d.ts.map +1 -0
  86. package/dist/core/sandbox/sandboxRef.js +69 -0
  87. package/dist/core/sandbox/sandboxRef.js.map +1 -0
  88. package/dist/core/sandbox/sandboxRef.mjs +41 -0
  89. package/dist/core/sandbox/sandboxRef.mjs.map +1 -0
  90. package/dist/core/sandbox/sandboxScripts.gen.d.ts +1 -1
  91. package/dist/core/sandbox/sandboxScripts.gen.d.ts.map +1 -1
  92. package/dist/core/sandbox/sandboxScripts.gen.js +1 -1
  93. package/dist/core/sandbox/sandboxScripts.gen.js.map +1 -1
  94. package/dist/core/sandbox/sandboxScripts.gen.mjs +1 -1
  95. package/dist/core/sandbox/sandboxScripts.gen.mjs.map +1 -1
  96. package/dist/core/sandbox/skills/ISkillMounter.d.ts +7 -2
  97. package/dist/core/sandbox/skills/ISkillMounter.d.ts.map +1 -1
  98. package/dist/core/sandbox/skills/ISkillMounter.js.map +1 -1
  99. package/dist/core/sandbox/skills/SkillMounter.d.ts +7 -2
  100. package/dist/core/sandbox/skills/SkillMounter.d.ts.map +1 -1
  101. package/dist/core/sandbox/skills/SkillMounter.js +5 -6
  102. package/dist/core/sandbox/skills/SkillMounter.js.map +1 -1
  103. package/dist/core/sandbox/skills/SkillMounter.mjs +5 -6
  104. package/dist/core/sandbox/skills/SkillMounter.mjs.map +1 -1
  105. package/dist/core/sandbox/skills/constants.d.ts +4 -2
  106. package/dist/core/sandbox/skills/constants.d.ts.map +1 -1
  107. package/dist/core/sandbox/skills/constants.js +2 -5
  108. package/dist/core/sandbox/skills/constants.js.map +1 -1
  109. package/dist/core/sandbox/skills/constants.mjs +2 -4
  110. package/dist/core/sandbox/skills/constants.mjs.map +1 -1
  111. package/dist/core/sandbox/skills/index.d.ts +1 -1
  112. package/dist/core/sandbox/skills/index.d.ts.map +1 -1
  113. package/dist/core/sandbox/skills/index.js +0 -2
  114. package/dist/core/sandbox/skills/index.js.map +1 -1
  115. package/dist/core/sandbox/skills/index.mjs +1 -2
  116. package/dist/core/sandbox/skills/index.mjs.map +1 -1
  117. package/package.json +1 -1
@@ -49,29 +49,36 @@ var import_LocalToolMCP = require("../mcp/LocalToolMCP.js");
49
49
  var import_DeferredTool = require("../runtime/DeferredTool.js");
50
50
  var import_errorLogFields = require("../util/errorLogFields.js");
51
51
  var import_CodeModeDispatcher = require("./codeMode/CodeModeDispatcher.js");
52
- var import_constants = require("./constants.js");
52
+ var import_CodeModeTransport = require("./codeMode/CodeModeTransport.js");
53
53
  var import_Provider = require("./provider/Provider.js");
54
54
  var import_SandboxErrors = require("./SandboxErrors.js");
55
- var import_sandboxScripts = require("./sandboxScripts.gen.js");
56
- var import_constants2 = require("./skills/constants.js");
55
+ var import_sandboxRef = require("./sandboxRef.js");
56
+ var import_node_path = require("path");
57
+ function mcpClientLayout(remotePath) {
58
+ const pythonPath = (0, import_node_path.dirname)(remotePath);
59
+ const binDir = (0, import_node_path.join)(pythonPath, "bin");
60
+ return { pythonPath, binDir, binLink: (0, import_node_path.join)(binDir, "mcp-client") };
61
+ }
57
62
  var SKILL_DOWNLOAD_TIMEOUT_SECONDS = 180;
58
63
  var NATS_REQUEST_TIMEOUT_BUFFER_SECONDS = 30;
59
64
  function buildWriteAndRunScriptCommand(params) {
60
65
  const b64 = Buffer.from(params.scriptContent, "utf-8").toString("base64");
66
+ const scriptPath = (0, import_Provider.shellEscape)(params.scriptPath);
61
67
  return [
62
- `mkdir -p "$(dirname ${params.scriptPath})"`,
63
- `rm -f ${params.scriptPath}`,
64
- `echo ${(0, import_Provider.shellEscape)(b64)} | base64 -d > ${params.scriptPath}`,
65
- `chmod a-w ${params.scriptPath}`,
66
- `python3 ${params.scriptPath}`
68
+ `mkdir -p "$(dirname ${scriptPath})"`,
69
+ `rm -f ${scriptPath}`,
70
+ `echo ${(0, import_Provider.shellEscape)(b64)} | base64 -d > ${scriptPath}`,
71
+ `chmod a-w ${scriptPath}`,
72
+ `python3 ${scriptPath}`
67
73
  ].join(" && ");
68
74
  }
69
75
  function buildSyncGitCredentialsCommand(credentialsContent, credentialsPath) {
76
+ const path = (0, import_Provider.shellEscape)(credentialsPath);
70
77
  if (credentialsContent === null) {
71
- return `rm -f ${credentialsPath}`;
78
+ return `rm -f ${path}`;
72
79
  }
73
80
  const b64 = Buffer.from(credentialsContent, "utf-8").toString("base64");
74
- return `mkdir -p "$(dirname ${credentialsPath})" && echo '${b64}' | base64 -d > ${credentialsPath} && chmod 600 ${credentialsPath}`;
81
+ return `mkdir -p "$(dirname ${path})" && echo '${b64}' | base64 -d > ${path} && chmod 600 ${path}`;
75
82
  }
76
83
  function buildGitCredentialHelperEnv(credentialsPath) {
77
84
  return {
@@ -85,9 +92,6 @@ var SANDBOX_MCP_REMINDER_TAG = "sandbox-mcp-code-mode";
85
92
  var SANDBOX_FILE_OUTPUT_TAG = "sandbox-file-output";
86
93
  var SANDBOX_SCHEMA_INFER_TAG = "sandbox-schema-infer";
87
94
  var SANDBOX_FILE_UPLOADS_TAG = "sandbox-file-uploads";
88
- var MCP_CLIENT_DIR = "/opt/tfy/mcp-client";
89
- var MCP_CLIENT_PATH = `${MCP_CLIENT_DIR}/mcp_client.py`;
90
- var MCP_CLIENT_BIN_SYMLINK = "/usr/local/bin/mcp-client";
91
95
  function injectTraceContextEnv() {
92
96
  const carrier = {};
93
97
  import_api.propagation.inject(import_api.context.active(), carrier);
@@ -103,10 +107,13 @@ function injectTraceContextEnv() {
103
107
  function injectMCPClientEnv(params) {
104
108
  const codeModeEnv = params.codeModeEnv ?? {};
105
109
  const hasCodeModeTransport = Object.keys(codeModeEnv).length > 0;
110
+ const install = params.mcpClientInstall;
111
+ const layout = install === void 0 ? void 0 : mcpClientLayout(install.remotePath);
106
112
  return {
107
- ...params.execExtraEnv ?? {},
108
113
  ...params.env ?? {},
109
- PYTHONPATH: MCP_CLIENT_DIR,
114
+ ...layout !== void 0 && {
115
+ PYTHONPATH: layout.pythonPath
116
+ },
110
117
  ...Object.keys(params.mcpServers).length > 0 && {
111
118
  TFY_MCP_SERVERS: Buffer.from(JSON.stringify(params.mcpServers)).toString("base64")
112
119
  },
@@ -138,14 +145,12 @@ function createSandboxLargeToolResponseGuidance() {
138
145
  return `For use cases where the Agent needs a subset of fields from the MCP response or needs deterministic processing, write code with the provided MCP client and use <${SANDBOX_MCP_REMINDER_TAG}>.`;
139
146
  }
140
147
  var SANDBOX_MCP_SERVER_ID = "sandbox";
141
- var Sandbox = class _Sandbox extends import_LocalToolMCP.LocalToolMCP {
148
+ var Sandbox = class extends import_LocalToolMCP.LocalToolMCP {
142
149
  name = SANDBOX_MCP_SERVER_ID;
143
150
  displayName = "Sandbox";
144
151
  description = "Persistent sandbox environment for code execution";
145
- static FILE_UPLOADS_DIR = import_constants.SANDBOX_FILE_UPLOADS_DIR;
146
152
  provider;
147
153
  existingSandboxId;
148
- tenantName;
149
154
  existingSandboxInfo;
150
155
  // Cached promise to prevent concurrent sub-agents from creating duplicate sandboxes.
151
156
  sandboxCreationPromise;
@@ -153,15 +158,15 @@ var Sandbox = class _Sandbox extends import_LocalToolMCP.LocalToolMCP {
153
158
  codeExecToolSets = [];
154
159
  fileDownloadEnabled;
155
160
  requestTimeoutSeconds;
156
- execExtraEnv;
157
161
  skillMounter;
158
162
  cachedSkillsSection;
159
- mcpClientScriptBase64;
160
163
  logger;
161
164
  // Pre-resolved credential-store file content (null = clear / no git auth).
162
165
  resolvedGitCredentialsContent;
163
166
  codeModeDispatcher;
164
167
  codeModeTransport;
168
+ /** Cached from transport.getClientInstall after sandbox init (when Code Mode is configured). */
169
+ mcpClientInstall;
165
170
  tools = [
166
171
  (0, import_LocalToolMCP.defineTool)({
167
172
  name: SANDBOX_EXEC_TOOL_NAME,
@@ -174,20 +179,24 @@ var Sandbox = class _Sandbox extends import_LocalToolMCP.LocalToolMCP {
174
179
  super({ tracing: options.tracing });
175
180
  this.provider = options.provider;
176
181
  this.existingSandboxId = options.existingSandboxId;
177
- this.tenantName = options.execExtraEnv?.["TFY_TENANT_NAME"] ?? "";
178
182
  this.skillMounter = options.skillMounter;
179
183
  this.fileDownloadEnabled = options.fileDownloadEnabled ?? false;
180
184
  const mcpBoundTimeoutMs = options.mcpRequestTimeoutMs + options.mcpConnectTimeoutMs;
181
185
  this.requestTimeoutSeconds = Math.ceil(mcpBoundTimeoutMs / 1e3) + NATS_REQUEST_TIMEOUT_BUFFER_SECONDS;
182
- this.execExtraEnv = options.execExtraEnv;
183
- this.mcpClientScriptBase64 = Buffer.from(import_sandboxScripts.sandboxScripts.mcpClient, "utf-8").toString("base64");
184
186
  this.logger = options.logger.child({ module: "Sandbox" });
185
187
  this.resolvedGitCredentialsContent = options.resolvedGitCredentialsContent ?? null;
186
188
  if (this.existingSandboxId) {
187
- (0, import_SandboxErrors.validateSandboxOwnedByTenant)(this.existingSandboxId, this.tenantName);
188
189
  this.existingSandboxInfo = { sandbox_id: this.existingSandboxId };
189
190
  }
190
191
  }
192
+ /** Provider-facing id (unwraps `v1:type:raw`; legacy ids pass through). */
193
+ providerSandboxId(sessionId) {
194
+ return (0, import_sandboxRef.rawSandboxId)(sessionId);
195
+ }
196
+ /** Raw id for prompt layout paths before create (empty when this turn has no existing sandbox). */
197
+ promptSandboxId() {
198
+ return this.existingSandboxId === void 0 ? "" : (0, import_sandboxRef.rawSandboxId)(this.existingSandboxId);
199
+ }
191
200
  buildMcpServersEnvelope() {
192
201
  const out = {};
193
202
  for (const server of this.codeExecToolSets) {
@@ -217,7 +226,7 @@ var Sandbox = class _Sandbox extends import_LocalToolMCP.LocalToolMCP {
217
226
  renderSkillsSection() {
218
227
  if (this.cachedSkillsSection === void 0) {
219
228
  const skills = new import_InstructionBuilder.InstructionBuilder("skills");
220
- this.skillMounter?.instruction(skills);
229
+ this.skillMounter?.instruction(skills, { skillsDir: this.provider.getSkillsDir(this.promptSandboxId()) });
221
230
  this.cachedSkillsSection = skills.build();
222
231
  }
223
232
  return this.cachedSkillsSection;
@@ -241,7 +250,7 @@ var Sandbox = class _Sandbox extends import_LocalToolMCP.LocalToolMCP {
241
250
  buildFileUploadsSection(builder) {
242
251
  builder.addSection(
243
252
  SANDBOX_FILE_UPLOADS_TAG,
244
- `User-uploaded files are placed in ${_Sandbox.FILE_UPLOADS_DIR}/. The Agent must not modify files in this directory. Always create a copy at a different location and work on the copy.`
253
+ `User-uploaded files are placed in ${this.provider.getFileUploadsDir(this.promptSandboxId())}/. The Agent must not modify files in this directory. Always create a copy at a different location and work on the copy.`
245
254
  );
246
255
  }
247
256
  buildSchemaSection(builder) {
@@ -363,87 +372,168 @@ var Sandbox = class _Sandbox extends import_LocalToolMCP.LocalToolMCP {
363
372
  }
364
373
  return this.existingSandboxInfo;
365
374
  }
375
+ clearExistingSandbox() {
376
+ this.existingSandboxInfo = void 0;
377
+ this.sandboxCreationPromise = void 0;
378
+ this.sandboxInitPromise = void 0;
379
+ this.mcpClientInstall = void 0;
380
+ }
366
381
  async ensureSandboxCreated() {
367
382
  if (this.existingSandboxInfo) {
368
383
  return { sandboxInfo: this.existingSandboxInfo, sandboxCreated: void 0 };
369
384
  }
370
- this.sandboxCreationPromise ??= this.provider.createSandbox().then(({ sandboxId }) => {
371
- (0, import_SandboxErrors.validateSandboxOwnedByTenant)(sandboxId, this.tenantName);
372
- return { sandbox_id: sandboxId };
373
- }).catch((e) => {
385
+ this.sandboxCreationPromise ??= this.provider.createSandbox().then(({ sandboxId }) => ({
386
+ sandbox_id: (0, import_sandboxRef.formatSandboxId)({ providerType: this.provider.type, rawId: sandboxId })
387
+ })).catch((e) => {
374
388
  this.sandboxCreationPromise = void 0;
375
389
  throw e;
376
390
  });
377
391
  const sandboxInfo = await this.sandboxCreationPromise;
378
- const prior = this.existingSandboxInfo;
379
- const isNew = prior === void 0;
392
+ const raced = this.peekExistingSandboxInfo();
393
+ if (raced !== void 0) {
394
+ return { sandboxInfo: raced, sandboxCreated: void 0 };
395
+ }
380
396
  this.existingSandboxInfo = sandboxInfo;
381
- return { sandboxInfo, sandboxCreated: isNew ? sandboxInfo : void 0 };
397
+ return { sandboxInfo, sandboxCreated: sandboxInfo };
382
398
  }
383
- async handleExec(input) {
384
- const { sandboxInfo, sandboxCreated } = await this.ensureSandboxCreated();
385
- const sandboxCreatedFlag = Boolean(sandboxCreated);
399
+ peekExistingSandboxInfo() {
400
+ return this.existingSandboxInfo;
401
+ }
402
+ /** Same-type missing remote/local root: drop the stale id and create a new fancy id. */
403
+ async recreateAfterUnavailable() {
404
+ this.clearExistingSandbox();
405
+ const created = await this.ensureSandboxCreated();
406
+ if (created.sandboxCreated === void 0) {
407
+ throw new Error("Sandbox recreate did not create a new sandbox");
408
+ }
409
+ return { sandboxInfo: created.sandboxInfo, sandboxCreated: created.sandboxCreated };
410
+ }
411
+ /**
412
+ * Create or reattach, then init. A missing same-type sandbox throws
413
+ * `SandboxNotAvailableError` from the provider; reattach then recreates.
414
+ */
415
+ async ensureReadySandbox() {
416
+ const first = await this.ensureSandboxCreated();
386
417
  try {
387
418
  await this.ensureSandboxInitialized();
419
+ return first;
420
+ } catch (error) {
421
+ if (!(error instanceof import_SandboxErrors.SandboxNotAvailableError) || first.sandboxCreated !== void 0) {
422
+ throw error;
423
+ }
424
+ const recreated = await this.recreateAfterUnavailable();
425
+ await this.ensureSandboxInitialized();
426
+ return recreated;
427
+ }
428
+ }
429
+ async handleExec(input) {
430
+ let sandboxInfo;
431
+ let sandboxCreated;
432
+ try {
433
+ ({ sandboxInfo, sandboxCreated } = await this.ensureReadySandbox());
388
434
  } catch (e) {
389
435
  this.logger.error("Sandbox initialization failed", (0, import_errorLogFields.extractErrorLogFields)(e));
390
436
  const message = e instanceof Error ? e.message : "Sandbox initialization failed";
437
+ const fallback = this.existingSandboxInfo;
391
438
  return (0, import_IMCPServer.toolResultResponse)({
392
439
  text: `Sandbox initialization failed: ${message}`,
393
440
  isError: true,
394
- overrides: { sandboxCreated: sandboxCreatedFlag, sandboxInfo }
441
+ overrides: {
442
+ sandboxCreated: Boolean(fallback),
443
+ ...fallback !== void 0 ? { sandboxInfo: fallback } : {}
444
+ }
395
445
  });
396
446
  }
397
- const codeModeEnv = await this.ensureCodeModeStarted(sandboxInfo.sandbox_id);
447
+ const sandboxCreatedFlag = Boolean(sandboxCreated);
448
+ const rawId = this.providerSandboxId(sandboxInfo.sandbox_id);
449
+ const codeModeEnv = await this.ensureCodeModeStarted(rawId);
398
450
  const mcpClientEnv = injectMCPClientEnv({
399
451
  env: input.env,
400
452
  mcpServers: this.buildMcpServersEnvelope(),
401
- execExtraEnv: this.execExtraEnv,
402
- codeModeEnv
453
+ codeModeEnv,
454
+ mcpClientInstall: this.mcpClientInstall
403
455
  });
404
- const gitAuthEnv = this.resolvedGitCredentialsContent !== null ? buildGitCredentialHelperEnv(this.provider.getGitCredentialsPath(sandboxInfo.sandbox_id)) : {};
456
+ const gitAuthEnv = this.resolvedGitCredentialsContent !== null ? buildGitCredentialHelperEnv(this.provider.getGitCredentialsPath(rawId)) : {};
405
457
  const env = { ...mcpClientEnv, ...gitAuthEnv };
406
- const result = await this.provider.exec({
407
- sandboxId: sandboxInfo.sandbox_id,
408
- command: input.command,
409
- cwd: input.cwd,
410
- env
411
- });
412
- return {
413
- result: {
414
- content: [{ type: "text", text: JSON.stringify(result) }],
415
- isError: !result.success
416
- },
417
- wasInitialized: void 0,
418
- sandboxCreated: sandboxCreatedFlag,
419
- sandboxInfo
420
- };
458
+ try {
459
+ const result = await this.provider.exec({
460
+ sandboxId: rawId,
461
+ command: input.command,
462
+ cwd: input.cwd,
463
+ env
464
+ });
465
+ return {
466
+ result: {
467
+ content: [{ type: "text", text: JSON.stringify(result) }],
468
+ isError: !result.success
469
+ },
470
+ wasInitialized: void 0,
471
+ sandboxCreated: sandboxCreatedFlag,
472
+ sandboxInfo
473
+ };
474
+ } catch (error) {
475
+ if (!(error instanceof import_SandboxErrors.SandboxNotAvailableError) || sandboxCreated !== void 0) {
476
+ throw error;
477
+ }
478
+ const recreated = await this.recreateAfterUnavailable();
479
+ await this.ensureSandboxInitialized();
480
+ const recreatedRawId = this.providerSandboxId(recreated.sandboxInfo.sandbox_id);
481
+ const retryCodeModeEnv = await this.ensureCodeModeStarted(recreatedRawId);
482
+ const retryEnv = {
483
+ ...injectMCPClientEnv({
484
+ env: input.env,
485
+ mcpServers: this.buildMcpServersEnvelope(),
486
+ codeModeEnv: retryCodeModeEnv,
487
+ mcpClientInstall: this.mcpClientInstall
488
+ }),
489
+ ...this.resolvedGitCredentialsContent !== null ? buildGitCredentialHelperEnv(this.provider.getGitCredentialsPath(recreatedRawId)) : {}
490
+ };
491
+ const retryResult = await this.provider.exec({
492
+ sandboxId: recreatedRawId,
493
+ command: input.command,
494
+ cwd: input.cwd,
495
+ env: retryEnv
496
+ });
497
+ return {
498
+ result: {
499
+ content: [{ type: "text", text: JSON.stringify(retryResult) }],
500
+ isError: !retryResult.success
501
+ },
502
+ wasInitialized: void 0,
503
+ sandboxCreated: true,
504
+ sandboxInfo: recreated.sandboxInfo
505
+ };
506
+ }
421
507
  }
422
508
  async getToolResultDumpDir() {
423
- const { sandboxCreated } = await this.ensureSandboxCreated();
424
- const dir = this.provider.getToolResultDumpDir(this.requiredSandboxInfo.sandbox_id).replace(/\/+$/, "");
509
+ const { sandboxCreated, sandboxInfo } = await this.ensureSandboxCreated();
510
+ const dir = this.provider.getToolResultDumpDir(this.providerSandboxId(sandboxInfo.sandbox_id)).replace(/\/+$/, "");
425
511
  return { dir, sandboxCreated };
426
512
  }
427
513
  async uploadFile(params) {
428
- const { sandboxCreated } = await this.ensureSandboxCreated();
429
- await this.ensureSandboxInitialized();
430
- const { sandbox_id: sandboxId } = this.requiredSandboxInfo;
514
+ const { sandboxCreated, sandboxInfo } = await this.ensureReadySandbox();
431
515
  const fileName = params.fileName.replace(/^\/+/, "");
432
516
  const targetDir = params.targetDir.replace(/\/+$/, "");
433
517
  const filePath = `${targetDir}/${fileName}`;
434
- await this.provider.uploadFile({ sandboxId, remotePath: filePath, content: params.content });
518
+ await this.provider.uploadFile({
519
+ sandboxId: this.providerSandboxId(sandboxInfo.sandbox_id),
520
+ remotePath: filePath,
521
+ content: params.content
522
+ });
435
523
  return { filePath, sandboxCreated };
436
524
  }
437
525
  async uploadUserFile(input) {
438
526
  (0, import_SandboxErrors.validateNoPathTraversal)(input.fileName);
527
+ const { sandboxCreated, sandboxInfo } = await this.ensureReadySandbox();
439
528
  const result = await this.uploadFile({
440
- targetDir: _Sandbox.FILE_UPLOADS_DIR,
529
+ targetDir: this.provider.getFileUploadsDir(this.providerSandboxId(sandboxInfo.sandbox_id)),
441
530
  fileName: input.fileName,
442
531
  content: input.content
443
532
  });
533
+ const created = sandboxCreated ?? result.sandboxCreated;
444
534
  return {
445
535
  filePath: result.filePath,
446
- ...result.sandboxCreated && { sandboxCreated: result.sandboxCreated }
536
+ ...created && { sandboxCreated: created }
447
537
  };
448
538
  }
449
539
  async writeArtifact(input) {
@@ -472,7 +562,7 @@ var Sandbox = class _Sandbox extends import_LocalToolMCP.LocalToolMCP {
472
562
  await this.sandboxInitPromise;
473
563
  }
474
564
  async writeGitCredentials() {
475
- const sandboxId = this.requiredSandboxInfo.sandbox_id;
565
+ const sandboxId = this.providerSandboxId(this.requiredSandboxInfo.sandbox_id);
476
566
  const credentialsPath = this.provider.getGitCredentialsPath(sandboxId);
477
567
  const result = await this.provider.exec({
478
568
  sandboxId,
@@ -481,30 +571,56 @@ var Sandbox = class _Sandbox extends import_LocalToolMCP.LocalToolMCP {
481
571
  (0, import_Provider.ensureExecSuccess)(result);
482
572
  }
483
573
  async initSandboxEnvironment() {
484
- const toolResultDumpDir = this.provider.getToolResultDumpDir(this.requiredSandboxInfo.sandbox_id);
574
+ const sandboxId = this.providerSandboxId(this.requiredSandboxInfo.sandbox_id);
575
+ const fileUploadsDir = this.provider.getFileUploadsDir(sandboxId);
576
+ const skillsDir = this.provider.getSkillsDir(sandboxId);
577
+ const toolResultDumpDir = this.provider.getToolResultDumpDir(sandboxId);
485
578
  this.logger.info("Uploading MCP client script and preparing skills directory in sandbox");
486
- const initSteps = [
487
- `mkdir -p ${MCP_CLIENT_DIR} ${_Sandbox.FILE_UPLOADS_DIR} ${toolResultDumpDir} ${import_constants2.SKILLS_DIR}`,
488
- `rm -f ${MCP_CLIENT_PATH}`,
489
- `echo '${this.mcpClientScriptBase64}' | base64 -d > ${MCP_CLIENT_PATH}`,
490
- // Make executable + symlink onto PATH so `mcp-client` runs by name.
491
- `chmod 0555 ${MCP_CLIENT_PATH}`,
492
- `ln -sf ${MCP_CLIENT_PATH} ${MCP_CLIENT_BIN_SYMLINK}`
493
- ];
494
- const skillInit = this.skillMounter?.getSandboxInit();
579
+ this.mcpClientInstall = this.codeModeTransport?.getClientInstall({ sandboxId });
580
+ const install = this.mcpClientInstall;
581
+ const dirs = [(0, import_Provider.shellEscape)(fileUploadsDir), (0, import_Provider.shellEscape)(toolResultDumpDir), (0, import_Provider.shellEscape)(skillsDir)];
582
+ if (install !== void 0) {
583
+ const { pythonPath, binDir } = mcpClientLayout(install.remotePath);
584
+ dirs.push((0, import_Provider.shellEscape)(pythonPath));
585
+ if (install.pathBinSymlink === void 0) {
586
+ dirs.push((0, import_Provider.shellEscape)(binDir));
587
+ }
588
+ }
589
+ (0, import_Provider.ensureExecSuccess)(await this.provider.exec({ sandboxId, command: `mkdir -p ${dirs.join(" ")}` }));
590
+ const initSteps = [];
591
+ if (install !== void 0) {
592
+ await this.provider.uploadFile({
593
+ sandboxId,
594
+ remotePath: install.remotePath,
595
+ content: Buffer.from(install.content, "utf-8")
596
+ });
597
+ initSteps.push(`chmod 0555 ${(0, import_Provider.shellEscape)(install.remotePath)}`);
598
+ if (install.pathBinSymlink !== void 0) {
599
+ initSteps.push(`ln -sf ${(0, import_Provider.shellEscape)(install.remotePath)} ${(0, import_Provider.shellEscape)(install.pathBinSymlink)}`);
600
+ } else {
601
+ const { binDir, binLink } = mcpClientLayout(install.remotePath);
602
+ initSteps.push(`ln -sf ${(0, import_Provider.shellEscape)((0, import_node_path.relative)(binDir, install.remotePath))} ${(0, import_Provider.shellEscape)(binLink)}`);
603
+ }
604
+ }
605
+ const skillInit = this.skillMounter?.getSandboxInit({
606
+ skillsDir,
607
+ gitDownloaderPath: this.provider.getGitDownloaderPath(sandboxId)
608
+ });
495
609
  if (skillInit) {
496
610
  initSteps.push(skillInit.command);
497
611
  }
498
- const script = initSteps.join(" && ");
499
- const result = await this.provider.exec({
500
- sandboxId: this.requiredSandboxInfo.sandbox_id,
501
- command: script,
502
- env: skillInit?.env,
503
- timeoutSeconds: skillInit?.timeoutSeconds
504
- });
505
- (0, import_Provider.ensureExecSuccess)(result);
612
+ if (initSteps.length > 0) {
613
+ (0, import_Provider.ensureExecSuccess)(
614
+ await this.provider.exec({
615
+ sandboxId,
616
+ command: initSteps.join(" && "),
617
+ env: skillInit?.env,
618
+ timeoutSeconds: skillInit?.timeoutSeconds
619
+ })
620
+ );
621
+ }
506
622
  this.logger.info(
507
- `Sandbox initialized: MCP client at ${MCP_CLIENT_PATH} (symlinked to ${MCP_CLIENT_BIN_SYMLINK}); skills dir ${import_constants2.SKILLS_DIR}`
623
+ install === void 0 ? `Sandbox initialized: skills dir ${skillsDir}` : `Sandbox initialized: MCP client at ${install.remotePath}; skills dir ${skillsDir}`
508
624
  );
509
625
  await this.writeGitCredentials();
510
626
  }