@truefoundry/trueforge-core 0.1.3 → 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 -4
- package/dist/core/sandbox/Sandbox.d.ts.map +1 -1
- package/dist/core/sandbox/Sandbox.js +200 -80
- package/dist/core/sandbox/Sandbox.js.map +1 -1
- package/dist/core/sandbox/Sandbox.mjs +201 -81
- 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/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,9 +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
78
|
...params.env ?? {},
|
|
73
|
-
|
|
79
|
+
...layout !== void 0 && {
|
|
80
|
+
PYTHONPATH: layout.pythonPath
|
|
81
|
+
},
|
|
74
82
|
...Object.keys(params.mcpServers).length > 0 && {
|
|
75
83
|
TFY_MCP_SERVERS: Buffer.from(JSON.stringify(params.mcpServers)).toString("base64")
|
|
76
84
|
},
|
|
@@ -102,14 +110,12 @@ function createSandboxLargeToolResponseGuidance() {
|
|
|
102
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}>.`;
|
|
103
111
|
}
|
|
104
112
|
var SANDBOX_MCP_SERVER_ID = "sandbox";
|
|
105
|
-
var Sandbox = class
|
|
113
|
+
var Sandbox = class extends LocalToolMCP {
|
|
106
114
|
name = SANDBOX_MCP_SERVER_ID;
|
|
107
115
|
displayName = "Sandbox";
|
|
108
116
|
description = "Persistent sandbox environment for code execution";
|
|
109
|
-
static FILE_UPLOADS_DIR = SANDBOX_FILE_UPLOADS_DIR;
|
|
110
117
|
provider;
|
|
111
118
|
existingSandboxId;
|
|
112
|
-
tenantName;
|
|
113
119
|
existingSandboxInfo;
|
|
114
120
|
// Cached promise to prevent concurrent sub-agents from creating duplicate sandboxes.
|
|
115
121
|
sandboxCreationPromise;
|
|
@@ -119,12 +125,13 @@ var Sandbox = class _Sandbox extends LocalToolMCP {
|
|
|
119
125
|
requestTimeoutSeconds;
|
|
120
126
|
skillMounter;
|
|
121
127
|
cachedSkillsSection;
|
|
122
|
-
mcpClientScriptBase64;
|
|
123
128
|
logger;
|
|
124
129
|
// Pre-resolved credential-store file content (null = clear / no git auth).
|
|
125
130
|
resolvedGitCredentialsContent;
|
|
126
131
|
codeModeDispatcher;
|
|
127
132
|
codeModeTransport;
|
|
133
|
+
/** Cached from transport.getClientInstall after sandbox init (when Code Mode is configured). */
|
|
134
|
+
mcpClientInstall;
|
|
128
135
|
tools = [
|
|
129
136
|
defineTool({
|
|
130
137
|
name: SANDBOX_EXEC_TOOL_NAME,
|
|
@@ -137,19 +144,24 @@ var Sandbox = class _Sandbox extends LocalToolMCP {
|
|
|
137
144
|
super({ tracing: options.tracing });
|
|
138
145
|
this.provider = options.provider;
|
|
139
146
|
this.existingSandboxId = options.existingSandboxId;
|
|
140
|
-
this.tenantName = options.tenantName;
|
|
141
147
|
this.skillMounter = options.skillMounter;
|
|
142
148
|
this.fileDownloadEnabled = options.fileDownloadEnabled ?? false;
|
|
143
149
|
const mcpBoundTimeoutMs = options.mcpRequestTimeoutMs + options.mcpConnectTimeoutMs;
|
|
144
150
|
this.requestTimeoutSeconds = Math.ceil(mcpBoundTimeoutMs / 1e3) + NATS_REQUEST_TIMEOUT_BUFFER_SECONDS;
|
|
145
|
-
this.mcpClientScriptBase64 = Buffer.from(sandboxScripts.mcpClient, "utf-8").toString("base64");
|
|
146
151
|
this.logger = options.logger.child({ module: "Sandbox" });
|
|
147
152
|
this.resolvedGitCredentialsContent = options.resolvedGitCredentialsContent ?? null;
|
|
148
153
|
if (this.existingSandboxId) {
|
|
149
|
-
validateSandboxOwnedByTenant(this.existingSandboxId, this.tenantName);
|
|
150
154
|
this.existingSandboxInfo = { sandbox_id: this.existingSandboxId };
|
|
151
155
|
}
|
|
152
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
|
+
}
|
|
153
165
|
buildMcpServersEnvelope() {
|
|
154
166
|
const out = {};
|
|
155
167
|
for (const server of this.codeExecToolSets) {
|
|
@@ -179,7 +191,7 @@ var Sandbox = class _Sandbox extends LocalToolMCP {
|
|
|
179
191
|
renderSkillsSection() {
|
|
180
192
|
if (this.cachedSkillsSection === void 0) {
|
|
181
193
|
const skills = new InstructionBuilder("skills");
|
|
182
|
-
this.skillMounter?.instruction(skills);
|
|
194
|
+
this.skillMounter?.instruction(skills, { skillsDir: this.provider.getSkillsDir(this.promptSandboxId()) });
|
|
183
195
|
this.cachedSkillsSection = skills.build();
|
|
184
196
|
}
|
|
185
197
|
return this.cachedSkillsSection;
|
|
@@ -203,7 +215,7 @@ var Sandbox = class _Sandbox extends LocalToolMCP {
|
|
|
203
215
|
buildFileUploadsSection(builder) {
|
|
204
216
|
builder.addSection(
|
|
205
217
|
SANDBOX_FILE_UPLOADS_TAG,
|
|
206
|
-
`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.`
|
|
207
219
|
);
|
|
208
220
|
}
|
|
209
221
|
buildSchemaSection(builder) {
|
|
@@ -325,86 +337,168 @@ var Sandbox = class _Sandbox extends LocalToolMCP {
|
|
|
325
337
|
}
|
|
326
338
|
return this.existingSandboxInfo;
|
|
327
339
|
}
|
|
340
|
+
clearExistingSandbox() {
|
|
341
|
+
this.existingSandboxInfo = void 0;
|
|
342
|
+
this.sandboxCreationPromise = void 0;
|
|
343
|
+
this.sandboxInitPromise = void 0;
|
|
344
|
+
this.mcpClientInstall = void 0;
|
|
345
|
+
}
|
|
328
346
|
async ensureSandboxCreated() {
|
|
329
347
|
if (this.existingSandboxInfo) {
|
|
330
348
|
return { sandboxInfo: this.existingSandboxInfo, sandboxCreated: void 0 };
|
|
331
349
|
}
|
|
332
|
-
this.sandboxCreationPromise ??= this.provider.createSandbox().then(({ sandboxId }) => {
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
}).catch((e) => {
|
|
350
|
+
this.sandboxCreationPromise ??= this.provider.createSandbox().then(({ sandboxId }) => ({
|
|
351
|
+
sandbox_id: formatSandboxId({ providerType: this.provider.type, rawId: sandboxId })
|
|
352
|
+
})).catch((e) => {
|
|
336
353
|
this.sandboxCreationPromise = void 0;
|
|
337
354
|
throw e;
|
|
338
355
|
});
|
|
339
356
|
const sandboxInfo = await this.sandboxCreationPromise;
|
|
340
|
-
const
|
|
341
|
-
|
|
357
|
+
const raced = this.peekExistingSandboxInfo();
|
|
358
|
+
if (raced !== void 0) {
|
|
359
|
+
return { sandboxInfo: raced, sandboxCreated: void 0 };
|
|
360
|
+
}
|
|
342
361
|
this.existingSandboxInfo = sandboxInfo;
|
|
343
|
-
return { sandboxInfo, sandboxCreated:
|
|
362
|
+
return { sandboxInfo, sandboxCreated: sandboxInfo };
|
|
344
363
|
}
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
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();
|
|
348
382
|
try {
|
|
349
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());
|
|
350
399
|
} catch (e) {
|
|
351
400
|
this.logger.error("Sandbox initialization failed", extractErrorLogFields(e));
|
|
352
401
|
const message = e instanceof Error ? e.message : "Sandbox initialization failed";
|
|
402
|
+
const fallback = this.existingSandboxInfo;
|
|
353
403
|
return toolResultResponse({
|
|
354
404
|
text: `Sandbox initialization failed: ${message}`,
|
|
355
405
|
isError: true,
|
|
356
|
-
overrides: {
|
|
406
|
+
overrides: {
|
|
407
|
+
sandboxCreated: Boolean(fallback),
|
|
408
|
+
...fallback !== void 0 ? { sandboxInfo: fallback } : {}
|
|
409
|
+
}
|
|
357
410
|
});
|
|
358
411
|
}
|
|
359
|
-
const
|
|
412
|
+
const sandboxCreatedFlag = Boolean(sandboxCreated);
|
|
413
|
+
const rawId = this.providerSandboxId(sandboxInfo.sandbox_id);
|
|
414
|
+
const codeModeEnv = await this.ensureCodeModeStarted(rawId);
|
|
360
415
|
const mcpClientEnv = injectMCPClientEnv({
|
|
361
416
|
env: input.env,
|
|
362
417
|
mcpServers: this.buildMcpServersEnvelope(),
|
|
363
|
-
codeModeEnv
|
|
418
|
+
codeModeEnv,
|
|
419
|
+
mcpClientInstall: this.mcpClientInstall
|
|
364
420
|
});
|
|
365
|
-
const gitAuthEnv = this.resolvedGitCredentialsContent !== null ? buildGitCredentialHelperEnv(this.provider.getGitCredentialsPath(
|
|
421
|
+
const gitAuthEnv = this.resolvedGitCredentialsContent !== null ? buildGitCredentialHelperEnv(this.provider.getGitCredentialsPath(rawId)) : {};
|
|
366
422
|
const env = { ...mcpClientEnv, ...gitAuthEnv };
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
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
|
+
}
|
|
382
472
|
}
|
|
383
473
|
async getToolResultDumpDir() {
|
|
384
|
-
const { sandboxCreated } = await this.ensureSandboxCreated();
|
|
385
|
-
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(/\/+$/, "");
|
|
386
476
|
return { dir, sandboxCreated };
|
|
387
477
|
}
|
|
388
478
|
async uploadFile(params) {
|
|
389
|
-
const { sandboxCreated } = await this.
|
|
390
|
-
await this.ensureSandboxInitialized();
|
|
391
|
-
const { sandbox_id: sandboxId } = this.requiredSandboxInfo;
|
|
479
|
+
const { sandboxCreated, sandboxInfo } = await this.ensureReadySandbox();
|
|
392
480
|
const fileName = params.fileName.replace(/^\/+/, "");
|
|
393
481
|
const targetDir = params.targetDir.replace(/\/+$/, "");
|
|
394
482
|
const filePath = `${targetDir}/${fileName}`;
|
|
395
|
-
await this.provider.uploadFile({
|
|
483
|
+
await this.provider.uploadFile({
|
|
484
|
+
sandboxId: this.providerSandboxId(sandboxInfo.sandbox_id),
|
|
485
|
+
remotePath: filePath,
|
|
486
|
+
content: params.content
|
|
487
|
+
});
|
|
396
488
|
return { filePath, sandboxCreated };
|
|
397
489
|
}
|
|
398
490
|
async uploadUserFile(input) {
|
|
399
491
|
validateNoPathTraversal(input.fileName);
|
|
492
|
+
const { sandboxCreated, sandboxInfo } = await this.ensureReadySandbox();
|
|
400
493
|
const result = await this.uploadFile({
|
|
401
|
-
targetDir:
|
|
494
|
+
targetDir: this.provider.getFileUploadsDir(this.providerSandboxId(sandboxInfo.sandbox_id)),
|
|
402
495
|
fileName: input.fileName,
|
|
403
496
|
content: input.content
|
|
404
497
|
});
|
|
498
|
+
const created = sandboxCreated ?? result.sandboxCreated;
|
|
405
499
|
return {
|
|
406
500
|
filePath: result.filePath,
|
|
407
|
-
...
|
|
501
|
+
...created && { sandboxCreated: created }
|
|
408
502
|
};
|
|
409
503
|
}
|
|
410
504
|
async writeArtifact(input) {
|
|
@@ -433,7 +527,7 @@ var Sandbox = class _Sandbox extends LocalToolMCP {
|
|
|
433
527
|
await this.sandboxInitPromise;
|
|
434
528
|
}
|
|
435
529
|
async writeGitCredentials() {
|
|
436
|
-
const sandboxId = this.requiredSandboxInfo.sandbox_id;
|
|
530
|
+
const sandboxId = this.providerSandboxId(this.requiredSandboxInfo.sandbox_id);
|
|
437
531
|
const credentialsPath = this.provider.getGitCredentialsPath(sandboxId);
|
|
438
532
|
const result = await this.provider.exec({
|
|
439
533
|
sandboxId,
|
|
@@ -442,30 +536,56 @@ var Sandbox = class _Sandbox extends LocalToolMCP {
|
|
|
442
536
|
ensureExecSuccess(result);
|
|
443
537
|
}
|
|
444
538
|
async initSandboxEnvironment() {
|
|
445
|
-
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);
|
|
446
543
|
this.logger.info("Uploading MCP client script and preparing skills directory in sandbox");
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
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
|
+
});
|
|
456
574
|
if (skillInit) {
|
|
457
575
|
initSteps.push(skillInit.command);
|
|
458
576
|
}
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
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
|
+
}
|
|
467
587
|
this.logger.info(
|
|
468
|
-
`Sandbox initialized:
|
|
588
|
+
install === void 0 ? `Sandbox initialized: skills dir ${skillsDir}` : `Sandbox initialized: MCP client at ${install.remotePath}; skills dir ${skillsDir}`
|
|
469
589
|
);
|
|
470
590
|
await this.writeGitCredentials();
|
|
471
591
|
}
|