@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.
- package/dist/agent-session/TurnResourceResolver.d.ts.map +1 -1
- package/dist/agent-session/TurnResourceResolver.js +1 -4
- package/dist/agent-session/TurnResourceResolver.js.map +1 -1
- package/dist/agent-session/TurnResourceResolver.mjs +1 -4
- package/dist/agent-session/TurnResourceResolver.mjs.map +1 -1
- package/dist/agent-session/index.d.ts +1 -1
- package/dist/agent-session/index.d.ts.map +1 -1
- package/dist/agent-session/index.js.map +1 -1
- package/dist/agent-session/index.mjs.map +1 -1
- package/dist/agent-session/schemas/agentSpec.d.ts +7 -28
- package/dist/agent-session/schemas/agentSpec.d.ts.map +1 -1
- package/dist/agent-session/schemas/agentSpec.js +15 -43
- package/dist/agent-session/schemas/agentSpec.js.map +1 -1
- package/dist/agent-session/schemas/agentSpec.mjs +15 -43
- package/dist/agent-session/schemas/agentSpec.mjs.map +1 -1
- package/dist/agent-session/schemas/session.d.ts +0 -39
- package/dist/agent-session/schemas/session.d.ts.map +1 -1
- package/dist/core/index.d.ts +4 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +12 -0
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.mjs +7 -0
- package/dist/core/index.mjs.map +1 -1
- package/dist/core/runtime/AgentThread.d.ts.map +1 -1
- package/dist/core/runtime/AgentThread.js +25 -11
- package/dist/core/runtime/AgentThread.js.map +1 -1
- package/dist/core/runtime/AgentThread.mjs +25 -11
- package/dist/core/runtime/AgentThread.mjs.map +1 -1
- package/dist/core/sandbox/Sandbox.d.ts +15 -5
- package/dist/core/sandbox/Sandbox.d.ts.map +1 -1
- package/dist/core/sandbox/Sandbox.js +200 -84
- package/dist/core/sandbox/Sandbox.js.map +1 -1
- package/dist/core/sandbox/Sandbox.mjs +201 -85
- package/dist/core/sandbox/Sandbox.mjs.map +1 -1
- package/dist/core/sandbox/SandboxErrors.d.ts +7 -3
- package/dist/core/sandbox/SandboxErrors.d.ts.map +1 -1
- package/dist/core/sandbox/SandboxErrors.js +6 -6
- package/dist/core/sandbox/SandboxErrors.js.map +1 -1
- package/dist/core/sandbox/SandboxErrors.mjs +6 -6
- package/dist/core/sandbox/SandboxErrors.mjs.map +1 -1
- package/dist/core/sandbox/codeMode/CodeModeTransport.d.ts +22 -0
- package/dist/core/sandbox/codeMode/CodeModeTransport.d.ts.map +1 -1
- package/dist/core/sandbox/codeMode/CodeModeTransport.js.map +1 -1
- package/dist/core/sandbox/codeMode/nats/CodeModeNatsTransport.d.ts +9 -1
- package/dist/core/sandbox/codeMode/nats/CodeModeNatsTransport.d.ts.map +1 -1
- package/dist/core/sandbox/codeMode/nats/CodeModeNatsTransport.js +12 -0
- package/dist/core/sandbox/codeMode/nats/CodeModeNatsTransport.js.map +1 -1
- package/dist/core/sandbox/codeMode/nats/CodeModeNatsTransport.mjs +12 -0
- package/dist/core/sandbox/codeMode/nats/CodeModeNatsTransport.mjs.map +1 -1
- package/dist/core/sandbox/constants.d.ts +0 -2
- package/dist/core/sandbox/constants.d.ts.map +1 -1
- package/dist/core/sandbox/constants.js +2 -5
- package/dist/core/sandbox/constants.js.map +1 -1
- package/dist/core/sandbox/constants.mjs +1 -3
- package/dist/core/sandbox/constants.mjs.map +1 -1
- package/dist/core/sandbox/provider/DaytonaProvider.d.ts +4 -0
- package/dist/core/sandbox/provider/DaytonaProvider.d.ts.map +1 -1
- package/dist/core/sandbox/provider/DaytonaProvider.js +27 -5
- package/dist/core/sandbox/provider/DaytonaProvider.js.map +1 -1
- package/dist/core/sandbox/provider/DaytonaProvider.mjs +27 -4
- package/dist/core/sandbox/provider/DaytonaProvider.mjs.map +1 -1
- package/dist/core/sandbox/provider/Provider.d.ts +13 -1
- package/dist/core/sandbox/provider/Provider.d.ts.map +1 -1
- package/dist/core/sandbox/provider/Provider.js.map +1 -1
- package/dist/core/sandbox/provider/Provider.mjs.map +1 -1
- package/dist/core/sandbox/provider/TFYSandboxProvider.d.ts +17 -2
- package/dist/core/sandbox/provider/TFYSandboxProvider.d.ts.map +1 -1
- package/dist/core/sandbox/provider/TFYSandboxProvider.js +81 -17
- package/dist/core/sandbox/provider/TFYSandboxProvider.js.map +1 -1
- package/dist/core/sandbox/provider/TFYSandboxProvider.mjs +82 -13
- package/dist/core/sandbox/provider/TFYSandboxProvider.mjs.map +1 -1
- package/dist/core/sandbox/provider/execEnv.d.ts +6 -0
- package/dist/core/sandbox/provider/execEnv.d.ts.map +1 -0
- package/dist/core/sandbox/provider/execEnv.js +55 -0
- package/dist/core/sandbox/provider/execEnv.js.map +1 -0
- package/dist/core/sandbox/provider/execEnv.mjs +30 -0
- package/dist/core/sandbox/provider/execEnv.mjs.map +1 -0
- package/dist/core/sandbox/sandboxImage.d.ts +2 -5
- package/dist/core/sandbox/sandboxImage.d.ts.map +1 -1
- package/dist/core/sandbox/sandboxImage.js +8 -1
- package/dist/core/sandbox/sandboxImage.js.map +1 -1
- package/dist/core/sandbox/sandboxImage.mjs +6 -1
- package/dist/core/sandbox/sandboxImage.mjs.map +1 -1
- package/dist/core/sandbox/sandboxRef.d.ts +26 -0
- package/dist/core/sandbox/sandboxRef.d.ts.map +1 -0
- package/dist/core/sandbox/sandboxRef.js +69 -0
- package/dist/core/sandbox/sandboxRef.js.map +1 -0
- package/dist/core/sandbox/sandboxRef.mjs +41 -0
- package/dist/core/sandbox/sandboxRef.mjs.map +1 -0
- package/dist/core/sandbox/sandboxScripts.gen.d.ts +1 -1
- package/dist/core/sandbox/sandboxScripts.gen.d.ts.map +1 -1
- package/dist/core/sandbox/sandboxScripts.gen.js +1 -1
- package/dist/core/sandbox/sandboxScripts.gen.js.map +1 -1
- package/dist/core/sandbox/sandboxScripts.gen.mjs +1 -1
- package/dist/core/sandbox/sandboxScripts.gen.mjs.map +1 -1
- package/dist/core/sandbox/skills/ISkillMounter.d.ts +7 -2
- package/dist/core/sandbox/skills/ISkillMounter.d.ts.map +1 -1
- package/dist/core/sandbox/skills/ISkillMounter.js.map +1 -1
- package/dist/core/sandbox/skills/SkillMounter.d.ts +7 -2
- package/dist/core/sandbox/skills/SkillMounter.d.ts.map +1 -1
- package/dist/core/sandbox/skills/SkillMounter.js +5 -6
- package/dist/core/sandbox/skills/SkillMounter.js.map +1 -1
- package/dist/core/sandbox/skills/SkillMounter.mjs +5 -6
- package/dist/core/sandbox/skills/SkillMounter.mjs.map +1 -1
- package/dist/core/sandbox/skills/constants.d.ts +4 -2
- package/dist/core/sandbox/skills/constants.d.ts.map +1 -1
- package/dist/core/sandbox/skills/constants.js +2 -5
- package/dist/core/sandbox/skills/constants.js.map +1 -1
- package/dist/core/sandbox/skills/constants.mjs +2 -4
- package/dist/core/sandbox/skills/constants.mjs.map +1 -1
- package/dist/core/sandbox/skills/index.d.ts +1 -1
- package/dist/core/sandbox/skills/index.d.ts.map +1 -1
- package/dist/core/sandbox/skills/index.js +0 -2
- package/dist/core/sandbox/skills/index.js.map +1 -1
- package/dist/core/sandbox/skills/index.mjs +1 -2
- package/dist/core/sandbox/skills/index.mjs.map +1 -1
- package/package.json +1 -1
|
@@ -14,29 +14,36 @@ import {
|
|
|
14
14
|
} from "../runtime/DeferredTool.mjs";
|
|
15
15
|
import { extractErrorLogFields } from "../util/errorLogFields.mjs";
|
|
16
16
|
import { CodeModeDispatcher } from "./codeMode/CodeModeDispatcher.mjs";
|
|
17
|
-
import
|
|
17
|
+
import "./codeMode/CodeModeTransport.mjs";
|
|
18
18
|
import { ensureExecSuccess, shellEscape } from "./provider/Provider.mjs";
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
19
|
+
import { SandboxNotAvailableError, validateNoPathTraversal } from "./SandboxErrors.mjs";
|
|
20
|
+
import { formatSandboxId, rawSandboxId } from "./sandboxRef.mjs";
|
|
21
|
+
import { dirname, join, relative } from "path";
|
|
22
|
+
function mcpClientLayout(remotePath) {
|
|
23
|
+
const pythonPath = dirname(remotePath);
|
|
24
|
+
const binDir = join(pythonPath, "bin");
|
|
25
|
+
return { pythonPath, binDir, binLink: join(binDir, "mcp-client") };
|
|
26
|
+
}
|
|
22
27
|
var SKILL_DOWNLOAD_TIMEOUT_SECONDS = 180;
|
|
23
28
|
var NATS_REQUEST_TIMEOUT_BUFFER_SECONDS = 30;
|
|
24
29
|
function buildWriteAndRunScriptCommand(params) {
|
|
25
30
|
const b64 = Buffer.from(params.scriptContent, "utf-8").toString("base64");
|
|
31
|
+
const scriptPath = shellEscape(params.scriptPath);
|
|
26
32
|
return [
|
|
27
|
-
`mkdir -p "$(dirname ${
|
|
28
|
-
`rm -f ${
|
|
29
|
-
`echo ${shellEscape(b64)} | base64 -d > ${
|
|
30
|
-
`chmod a-w ${
|
|
31
|
-
`python3 ${
|
|
33
|
+
`mkdir -p "$(dirname ${scriptPath})"`,
|
|
34
|
+
`rm -f ${scriptPath}`,
|
|
35
|
+
`echo ${shellEscape(b64)} | base64 -d > ${scriptPath}`,
|
|
36
|
+
`chmod a-w ${scriptPath}`,
|
|
37
|
+
`python3 ${scriptPath}`
|
|
32
38
|
].join(" && ");
|
|
33
39
|
}
|
|
34
40
|
function buildSyncGitCredentialsCommand(credentialsContent, credentialsPath) {
|
|
41
|
+
const path = shellEscape(credentialsPath);
|
|
35
42
|
if (credentialsContent === null) {
|
|
36
|
-
return `rm -f ${
|
|
43
|
+
return `rm -f ${path}`;
|
|
37
44
|
}
|
|
38
45
|
const b64 = Buffer.from(credentialsContent, "utf-8").toString("base64");
|
|
39
|
-
return `mkdir -p "$(dirname ${
|
|
46
|
+
return `mkdir -p "$(dirname ${path})" && echo '${b64}' | base64 -d > ${path} && chmod 600 ${path}`;
|
|
40
47
|
}
|
|
41
48
|
function buildGitCredentialHelperEnv(credentialsPath) {
|
|
42
49
|
return {
|
|
@@ -50,9 +57,6 @@ var SANDBOX_MCP_REMINDER_TAG = "sandbox-mcp-code-mode";
|
|
|
50
57
|
var SANDBOX_FILE_OUTPUT_TAG = "sandbox-file-output";
|
|
51
58
|
var SANDBOX_SCHEMA_INFER_TAG = "sandbox-schema-infer";
|
|
52
59
|
var SANDBOX_FILE_UPLOADS_TAG = "sandbox-file-uploads";
|
|
53
|
-
var MCP_CLIENT_DIR = "/opt/tfy/mcp-client";
|
|
54
|
-
var MCP_CLIENT_PATH = `${MCP_CLIENT_DIR}/mcp_client.py`;
|
|
55
|
-
var MCP_CLIENT_BIN_SYMLINK = "/usr/local/bin/mcp-client";
|
|
56
60
|
function injectTraceContextEnv() {
|
|
57
61
|
const carrier = {};
|
|
58
62
|
propagation.inject(context.active(), carrier);
|
|
@@ -68,10 +72,13 @@ function injectTraceContextEnv() {
|
|
|
68
72
|
function injectMCPClientEnv(params) {
|
|
69
73
|
const codeModeEnv = params.codeModeEnv ?? {};
|
|
70
74
|
const hasCodeModeTransport = Object.keys(codeModeEnv).length > 0;
|
|
75
|
+
const install = params.mcpClientInstall;
|
|
76
|
+
const layout = install === void 0 ? void 0 : mcpClientLayout(install.remotePath);
|
|
71
77
|
return {
|
|
72
|
-
...params.execExtraEnv ?? {},
|
|
73
78
|
...params.env ?? {},
|
|
74
|
-
|
|
79
|
+
...layout !== void 0 && {
|
|
80
|
+
PYTHONPATH: layout.pythonPath
|
|
81
|
+
},
|
|
75
82
|
...Object.keys(params.mcpServers).length > 0 && {
|
|
76
83
|
TFY_MCP_SERVERS: Buffer.from(JSON.stringify(params.mcpServers)).toString("base64")
|
|
77
84
|
},
|
|
@@ -103,14 +110,12 @@ function createSandboxLargeToolResponseGuidance() {
|
|
|
103
110
|
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}>.`;
|
|
104
111
|
}
|
|
105
112
|
var SANDBOX_MCP_SERVER_ID = "sandbox";
|
|
106
|
-
var Sandbox = class
|
|
113
|
+
var Sandbox = class extends LocalToolMCP {
|
|
107
114
|
name = SANDBOX_MCP_SERVER_ID;
|
|
108
115
|
displayName = "Sandbox";
|
|
109
116
|
description = "Persistent sandbox environment for code execution";
|
|
110
|
-
static FILE_UPLOADS_DIR = SANDBOX_FILE_UPLOADS_DIR;
|
|
111
117
|
provider;
|
|
112
118
|
existingSandboxId;
|
|
113
|
-
tenantName;
|
|
114
119
|
existingSandboxInfo;
|
|
115
120
|
// Cached promise to prevent concurrent sub-agents from creating duplicate sandboxes.
|
|
116
121
|
sandboxCreationPromise;
|
|
@@ -118,15 +123,15 @@ var Sandbox = class _Sandbox extends LocalToolMCP {
|
|
|
118
123
|
codeExecToolSets = [];
|
|
119
124
|
fileDownloadEnabled;
|
|
120
125
|
requestTimeoutSeconds;
|
|
121
|
-
execExtraEnv;
|
|
122
126
|
skillMounter;
|
|
123
127
|
cachedSkillsSection;
|
|
124
|
-
mcpClientScriptBase64;
|
|
125
128
|
logger;
|
|
126
129
|
// Pre-resolved credential-store file content (null = clear / no git auth).
|
|
127
130
|
resolvedGitCredentialsContent;
|
|
128
131
|
codeModeDispatcher;
|
|
129
132
|
codeModeTransport;
|
|
133
|
+
/** Cached from transport.getClientInstall after sandbox init (when Code Mode is configured). */
|
|
134
|
+
mcpClientInstall;
|
|
130
135
|
tools = [
|
|
131
136
|
defineTool({
|
|
132
137
|
name: SANDBOX_EXEC_TOOL_NAME,
|
|
@@ -139,20 +144,24 @@ var Sandbox = class _Sandbox extends LocalToolMCP {
|
|
|
139
144
|
super({ tracing: options.tracing });
|
|
140
145
|
this.provider = options.provider;
|
|
141
146
|
this.existingSandboxId = options.existingSandboxId;
|
|
142
|
-
this.tenantName = options.execExtraEnv?.["TFY_TENANT_NAME"] ?? "";
|
|
143
147
|
this.skillMounter = options.skillMounter;
|
|
144
148
|
this.fileDownloadEnabled = options.fileDownloadEnabled ?? false;
|
|
145
149
|
const mcpBoundTimeoutMs = options.mcpRequestTimeoutMs + options.mcpConnectTimeoutMs;
|
|
146
150
|
this.requestTimeoutSeconds = Math.ceil(mcpBoundTimeoutMs / 1e3) + NATS_REQUEST_TIMEOUT_BUFFER_SECONDS;
|
|
147
|
-
this.execExtraEnv = options.execExtraEnv;
|
|
148
|
-
this.mcpClientScriptBase64 = Buffer.from(sandboxScripts.mcpClient, "utf-8").toString("base64");
|
|
149
151
|
this.logger = options.logger.child({ module: "Sandbox" });
|
|
150
152
|
this.resolvedGitCredentialsContent = options.resolvedGitCredentialsContent ?? null;
|
|
151
153
|
if (this.existingSandboxId) {
|
|
152
|
-
validateSandboxOwnedByTenant(this.existingSandboxId, this.tenantName);
|
|
153
154
|
this.existingSandboxInfo = { sandbox_id: this.existingSandboxId };
|
|
154
155
|
}
|
|
155
156
|
}
|
|
157
|
+
/** Provider-facing id (unwraps `v1:type:raw`; legacy ids pass through). */
|
|
158
|
+
providerSandboxId(sessionId) {
|
|
159
|
+
return rawSandboxId(sessionId);
|
|
160
|
+
}
|
|
161
|
+
/** Raw id for prompt layout paths before create (empty when this turn has no existing sandbox). */
|
|
162
|
+
promptSandboxId() {
|
|
163
|
+
return this.existingSandboxId === void 0 ? "" : rawSandboxId(this.existingSandboxId);
|
|
164
|
+
}
|
|
156
165
|
buildMcpServersEnvelope() {
|
|
157
166
|
const out = {};
|
|
158
167
|
for (const server of this.codeExecToolSets) {
|
|
@@ -182,7 +191,7 @@ var Sandbox = class _Sandbox extends LocalToolMCP {
|
|
|
182
191
|
renderSkillsSection() {
|
|
183
192
|
if (this.cachedSkillsSection === void 0) {
|
|
184
193
|
const skills = new InstructionBuilder("skills");
|
|
185
|
-
this.skillMounter?.instruction(skills);
|
|
194
|
+
this.skillMounter?.instruction(skills, { skillsDir: this.provider.getSkillsDir(this.promptSandboxId()) });
|
|
186
195
|
this.cachedSkillsSection = skills.build();
|
|
187
196
|
}
|
|
188
197
|
return this.cachedSkillsSection;
|
|
@@ -206,7 +215,7 @@ var Sandbox = class _Sandbox extends LocalToolMCP {
|
|
|
206
215
|
buildFileUploadsSection(builder) {
|
|
207
216
|
builder.addSection(
|
|
208
217
|
SANDBOX_FILE_UPLOADS_TAG,
|
|
209
|
-
`User-uploaded files are placed in ${
|
|
218
|
+
`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.`
|
|
210
219
|
);
|
|
211
220
|
}
|
|
212
221
|
buildSchemaSection(builder) {
|
|
@@ -328,87 +337,168 @@ var Sandbox = class _Sandbox extends LocalToolMCP {
|
|
|
328
337
|
}
|
|
329
338
|
return this.existingSandboxInfo;
|
|
330
339
|
}
|
|
340
|
+
clearExistingSandbox() {
|
|
341
|
+
this.existingSandboxInfo = void 0;
|
|
342
|
+
this.sandboxCreationPromise = void 0;
|
|
343
|
+
this.sandboxInitPromise = void 0;
|
|
344
|
+
this.mcpClientInstall = void 0;
|
|
345
|
+
}
|
|
331
346
|
async ensureSandboxCreated() {
|
|
332
347
|
if (this.existingSandboxInfo) {
|
|
333
348
|
return { sandboxInfo: this.existingSandboxInfo, sandboxCreated: void 0 };
|
|
334
349
|
}
|
|
335
|
-
this.sandboxCreationPromise ??= this.provider.createSandbox().then(({ sandboxId }) => {
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
}).catch((e) => {
|
|
350
|
+
this.sandboxCreationPromise ??= this.provider.createSandbox().then(({ sandboxId }) => ({
|
|
351
|
+
sandbox_id: formatSandboxId({ providerType: this.provider.type, rawId: sandboxId })
|
|
352
|
+
})).catch((e) => {
|
|
339
353
|
this.sandboxCreationPromise = void 0;
|
|
340
354
|
throw e;
|
|
341
355
|
});
|
|
342
356
|
const sandboxInfo = await this.sandboxCreationPromise;
|
|
343
|
-
const
|
|
344
|
-
|
|
357
|
+
const raced = this.peekExistingSandboxInfo();
|
|
358
|
+
if (raced !== void 0) {
|
|
359
|
+
return { sandboxInfo: raced, sandboxCreated: void 0 };
|
|
360
|
+
}
|
|
345
361
|
this.existingSandboxInfo = sandboxInfo;
|
|
346
|
-
return { sandboxInfo, sandboxCreated:
|
|
362
|
+
return { sandboxInfo, sandboxCreated: sandboxInfo };
|
|
347
363
|
}
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
364
|
+
peekExistingSandboxInfo() {
|
|
365
|
+
return this.existingSandboxInfo;
|
|
366
|
+
}
|
|
367
|
+
/** Same-type missing remote/local root: drop the stale id and create a new fancy id. */
|
|
368
|
+
async recreateAfterUnavailable() {
|
|
369
|
+
this.clearExistingSandbox();
|
|
370
|
+
const created = await this.ensureSandboxCreated();
|
|
371
|
+
if (created.sandboxCreated === void 0) {
|
|
372
|
+
throw new Error("Sandbox recreate did not create a new sandbox");
|
|
373
|
+
}
|
|
374
|
+
return { sandboxInfo: created.sandboxInfo, sandboxCreated: created.sandboxCreated };
|
|
375
|
+
}
|
|
376
|
+
/**
|
|
377
|
+
* Create or reattach, then init. A missing same-type sandbox throws
|
|
378
|
+
* `SandboxNotAvailableError` from the provider; reattach then recreates.
|
|
379
|
+
*/
|
|
380
|
+
async ensureReadySandbox() {
|
|
381
|
+
const first = await this.ensureSandboxCreated();
|
|
351
382
|
try {
|
|
352
383
|
await this.ensureSandboxInitialized();
|
|
384
|
+
return first;
|
|
385
|
+
} catch (error) {
|
|
386
|
+
if (!(error instanceof SandboxNotAvailableError) || first.sandboxCreated !== void 0) {
|
|
387
|
+
throw error;
|
|
388
|
+
}
|
|
389
|
+
const recreated = await this.recreateAfterUnavailable();
|
|
390
|
+
await this.ensureSandboxInitialized();
|
|
391
|
+
return recreated;
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
async handleExec(input) {
|
|
395
|
+
let sandboxInfo;
|
|
396
|
+
let sandboxCreated;
|
|
397
|
+
try {
|
|
398
|
+
({ sandboxInfo, sandboxCreated } = await this.ensureReadySandbox());
|
|
353
399
|
} catch (e) {
|
|
354
400
|
this.logger.error("Sandbox initialization failed", extractErrorLogFields(e));
|
|
355
401
|
const message = e instanceof Error ? e.message : "Sandbox initialization failed";
|
|
402
|
+
const fallback = this.existingSandboxInfo;
|
|
356
403
|
return toolResultResponse({
|
|
357
404
|
text: `Sandbox initialization failed: ${message}`,
|
|
358
405
|
isError: true,
|
|
359
|
-
overrides: {
|
|
406
|
+
overrides: {
|
|
407
|
+
sandboxCreated: Boolean(fallback),
|
|
408
|
+
...fallback !== void 0 ? { sandboxInfo: fallback } : {}
|
|
409
|
+
}
|
|
360
410
|
});
|
|
361
411
|
}
|
|
362
|
-
const
|
|
412
|
+
const sandboxCreatedFlag = Boolean(sandboxCreated);
|
|
413
|
+
const rawId = this.providerSandboxId(sandboxInfo.sandbox_id);
|
|
414
|
+
const codeModeEnv = await this.ensureCodeModeStarted(rawId);
|
|
363
415
|
const mcpClientEnv = injectMCPClientEnv({
|
|
364
416
|
env: input.env,
|
|
365
417
|
mcpServers: this.buildMcpServersEnvelope(),
|
|
366
|
-
|
|
367
|
-
|
|
418
|
+
codeModeEnv,
|
|
419
|
+
mcpClientInstall: this.mcpClientInstall
|
|
368
420
|
});
|
|
369
|
-
const gitAuthEnv = this.resolvedGitCredentialsContent !== null ? buildGitCredentialHelperEnv(this.provider.getGitCredentialsPath(
|
|
421
|
+
const gitAuthEnv = this.resolvedGitCredentialsContent !== null ? buildGitCredentialHelperEnv(this.provider.getGitCredentialsPath(rawId)) : {};
|
|
370
422
|
const env = { ...mcpClientEnv, ...gitAuthEnv };
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
423
|
+
try {
|
|
424
|
+
const result = await this.provider.exec({
|
|
425
|
+
sandboxId: rawId,
|
|
426
|
+
command: input.command,
|
|
427
|
+
cwd: input.cwd,
|
|
428
|
+
env
|
|
429
|
+
});
|
|
430
|
+
return {
|
|
431
|
+
result: {
|
|
432
|
+
content: [{ type: "text", text: JSON.stringify(result) }],
|
|
433
|
+
isError: !result.success
|
|
434
|
+
},
|
|
435
|
+
wasInitialized: void 0,
|
|
436
|
+
sandboxCreated: sandboxCreatedFlag,
|
|
437
|
+
sandboxInfo
|
|
438
|
+
};
|
|
439
|
+
} catch (error) {
|
|
440
|
+
if (!(error instanceof SandboxNotAvailableError) || sandboxCreated !== void 0) {
|
|
441
|
+
throw error;
|
|
442
|
+
}
|
|
443
|
+
const recreated = await this.recreateAfterUnavailable();
|
|
444
|
+
await this.ensureSandboxInitialized();
|
|
445
|
+
const recreatedRawId = this.providerSandboxId(recreated.sandboxInfo.sandbox_id);
|
|
446
|
+
const retryCodeModeEnv = await this.ensureCodeModeStarted(recreatedRawId);
|
|
447
|
+
const retryEnv = {
|
|
448
|
+
...injectMCPClientEnv({
|
|
449
|
+
env: input.env,
|
|
450
|
+
mcpServers: this.buildMcpServersEnvelope(),
|
|
451
|
+
codeModeEnv: retryCodeModeEnv,
|
|
452
|
+
mcpClientInstall: this.mcpClientInstall
|
|
453
|
+
}),
|
|
454
|
+
...this.resolvedGitCredentialsContent !== null ? buildGitCredentialHelperEnv(this.provider.getGitCredentialsPath(recreatedRawId)) : {}
|
|
455
|
+
};
|
|
456
|
+
const retryResult = await this.provider.exec({
|
|
457
|
+
sandboxId: recreatedRawId,
|
|
458
|
+
command: input.command,
|
|
459
|
+
cwd: input.cwd,
|
|
460
|
+
env: retryEnv
|
|
461
|
+
});
|
|
462
|
+
return {
|
|
463
|
+
result: {
|
|
464
|
+
content: [{ type: "text", text: JSON.stringify(retryResult) }],
|
|
465
|
+
isError: !retryResult.success
|
|
466
|
+
},
|
|
467
|
+
wasInitialized: void 0,
|
|
468
|
+
sandboxCreated: true,
|
|
469
|
+
sandboxInfo: recreated.sandboxInfo
|
|
470
|
+
};
|
|
471
|
+
}
|
|
386
472
|
}
|
|
387
473
|
async getToolResultDumpDir() {
|
|
388
|
-
const { sandboxCreated } = await this.ensureSandboxCreated();
|
|
389
|
-
const dir = this.provider.getToolResultDumpDir(this.
|
|
474
|
+
const { sandboxCreated, sandboxInfo } = await this.ensureSandboxCreated();
|
|
475
|
+
const dir = this.provider.getToolResultDumpDir(this.providerSandboxId(sandboxInfo.sandbox_id)).replace(/\/+$/, "");
|
|
390
476
|
return { dir, sandboxCreated };
|
|
391
477
|
}
|
|
392
478
|
async uploadFile(params) {
|
|
393
|
-
const { sandboxCreated } = await this.
|
|
394
|
-
await this.ensureSandboxInitialized();
|
|
395
|
-
const { sandbox_id: sandboxId } = this.requiredSandboxInfo;
|
|
479
|
+
const { sandboxCreated, sandboxInfo } = await this.ensureReadySandbox();
|
|
396
480
|
const fileName = params.fileName.replace(/^\/+/, "");
|
|
397
481
|
const targetDir = params.targetDir.replace(/\/+$/, "");
|
|
398
482
|
const filePath = `${targetDir}/${fileName}`;
|
|
399
|
-
await this.provider.uploadFile({
|
|
483
|
+
await this.provider.uploadFile({
|
|
484
|
+
sandboxId: this.providerSandboxId(sandboxInfo.sandbox_id),
|
|
485
|
+
remotePath: filePath,
|
|
486
|
+
content: params.content
|
|
487
|
+
});
|
|
400
488
|
return { filePath, sandboxCreated };
|
|
401
489
|
}
|
|
402
490
|
async uploadUserFile(input) {
|
|
403
491
|
validateNoPathTraversal(input.fileName);
|
|
492
|
+
const { sandboxCreated, sandboxInfo } = await this.ensureReadySandbox();
|
|
404
493
|
const result = await this.uploadFile({
|
|
405
|
-
targetDir:
|
|
494
|
+
targetDir: this.provider.getFileUploadsDir(this.providerSandboxId(sandboxInfo.sandbox_id)),
|
|
406
495
|
fileName: input.fileName,
|
|
407
496
|
content: input.content
|
|
408
497
|
});
|
|
498
|
+
const created = sandboxCreated ?? result.sandboxCreated;
|
|
409
499
|
return {
|
|
410
500
|
filePath: result.filePath,
|
|
411
|
-
...
|
|
501
|
+
...created && { sandboxCreated: created }
|
|
412
502
|
};
|
|
413
503
|
}
|
|
414
504
|
async writeArtifact(input) {
|
|
@@ -437,7 +527,7 @@ var Sandbox = class _Sandbox extends LocalToolMCP {
|
|
|
437
527
|
await this.sandboxInitPromise;
|
|
438
528
|
}
|
|
439
529
|
async writeGitCredentials() {
|
|
440
|
-
const sandboxId = this.requiredSandboxInfo.sandbox_id;
|
|
530
|
+
const sandboxId = this.providerSandboxId(this.requiredSandboxInfo.sandbox_id);
|
|
441
531
|
const credentialsPath = this.provider.getGitCredentialsPath(sandboxId);
|
|
442
532
|
const result = await this.provider.exec({
|
|
443
533
|
sandboxId,
|
|
@@ -446,30 +536,56 @@ var Sandbox = class _Sandbox extends LocalToolMCP {
|
|
|
446
536
|
ensureExecSuccess(result);
|
|
447
537
|
}
|
|
448
538
|
async initSandboxEnvironment() {
|
|
449
|
-
const
|
|
539
|
+
const sandboxId = this.providerSandboxId(this.requiredSandboxInfo.sandbox_id);
|
|
540
|
+
const fileUploadsDir = this.provider.getFileUploadsDir(sandboxId);
|
|
541
|
+
const skillsDir = this.provider.getSkillsDir(sandboxId);
|
|
542
|
+
const toolResultDumpDir = this.provider.getToolResultDumpDir(sandboxId);
|
|
450
543
|
this.logger.info("Uploading MCP client script and preparing skills directory in sandbox");
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
544
|
+
this.mcpClientInstall = this.codeModeTransport?.getClientInstall({ sandboxId });
|
|
545
|
+
const install = this.mcpClientInstall;
|
|
546
|
+
const dirs = [shellEscape(fileUploadsDir), shellEscape(toolResultDumpDir), shellEscape(skillsDir)];
|
|
547
|
+
if (install !== void 0) {
|
|
548
|
+
const { pythonPath, binDir } = mcpClientLayout(install.remotePath);
|
|
549
|
+
dirs.push(shellEscape(pythonPath));
|
|
550
|
+
if (install.pathBinSymlink === void 0) {
|
|
551
|
+
dirs.push(shellEscape(binDir));
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
ensureExecSuccess(await this.provider.exec({ sandboxId, command: `mkdir -p ${dirs.join(" ")}` }));
|
|
555
|
+
const initSteps = [];
|
|
556
|
+
if (install !== void 0) {
|
|
557
|
+
await this.provider.uploadFile({
|
|
558
|
+
sandboxId,
|
|
559
|
+
remotePath: install.remotePath,
|
|
560
|
+
content: Buffer.from(install.content, "utf-8")
|
|
561
|
+
});
|
|
562
|
+
initSteps.push(`chmod 0555 ${shellEscape(install.remotePath)}`);
|
|
563
|
+
if (install.pathBinSymlink !== void 0) {
|
|
564
|
+
initSteps.push(`ln -sf ${shellEscape(install.remotePath)} ${shellEscape(install.pathBinSymlink)}`);
|
|
565
|
+
} else {
|
|
566
|
+
const { binDir, binLink } = mcpClientLayout(install.remotePath);
|
|
567
|
+
initSteps.push(`ln -sf ${shellEscape(relative(binDir, install.remotePath))} ${shellEscape(binLink)}`);
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
const skillInit = this.skillMounter?.getSandboxInit({
|
|
571
|
+
skillsDir,
|
|
572
|
+
gitDownloaderPath: this.provider.getGitDownloaderPath(sandboxId)
|
|
573
|
+
});
|
|
460
574
|
if (skillInit) {
|
|
461
575
|
initSteps.push(skillInit.command);
|
|
462
576
|
}
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
577
|
+
if (initSteps.length > 0) {
|
|
578
|
+
ensureExecSuccess(
|
|
579
|
+
await this.provider.exec({
|
|
580
|
+
sandboxId,
|
|
581
|
+
command: initSteps.join(" && "),
|
|
582
|
+
env: skillInit?.env,
|
|
583
|
+
timeoutSeconds: skillInit?.timeoutSeconds
|
|
584
|
+
})
|
|
585
|
+
);
|
|
586
|
+
}
|
|
471
587
|
this.logger.info(
|
|
472
|
-
`Sandbox initialized:
|
|
588
|
+
install === void 0 ? `Sandbox initialized: skills dir ${skillsDir}` : `Sandbox initialized: MCP client at ${install.remotePath}; skills dir ${skillsDir}`
|
|
473
589
|
);
|
|
474
590
|
await this.writeGitCredentials();
|
|
475
591
|
}
|