@giselles-ai/sandbox-agent 0.1.11 → 0.1.13
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/index.d.ts +25 -1
- package/dist/index.js +119 -20
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,30 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { Sandbox } from '@vercel/sandbox';
|
|
3
3
|
|
|
4
|
+
type AgentType = "codex" | "gemini";
|
|
5
|
+
declare class Agent {
|
|
6
|
+
private _type;
|
|
7
|
+
private _snapshotId;
|
|
8
|
+
private _pendingOps;
|
|
9
|
+
private constructor();
|
|
10
|
+
static create(type: AgentType, options: {
|
|
11
|
+
snapshotId: string;
|
|
12
|
+
}): Agent;
|
|
13
|
+
get type(): AgentType;
|
|
14
|
+
get snapshotId(): string;
|
|
15
|
+
get dirty(): boolean;
|
|
16
|
+
addFiles(files: Array<{
|
|
17
|
+
path: string;
|
|
18
|
+
content: Buffer;
|
|
19
|
+
}>): this;
|
|
20
|
+
setAgentMd(content: string | Buffer): this;
|
|
21
|
+
runCommands(commands: Array<{
|
|
22
|
+
cmd: string;
|
|
23
|
+
args?: string[];
|
|
24
|
+
}>): this;
|
|
25
|
+
prepare(): Promise<void>;
|
|
26
|
+
}
|
|
27
|
+
|
|
4
28
|
type BaseChatRequest = {
|
|
5
29
|
message: string;
|
|
6
30
|
session_id?: string;
|
|
@@ -78,4 +102,4 @@ type GeminiAgentOptions = {
|
|
|
78
102
|
};
|
|
79
103
|
declare function createGeminiAgent(options?: GeminiAgentOptions): ChatAgent<GeminiAgentRequest>;
|
|
80
104
|
|
|
81
|
-
export { type BaseChatRequest, type ChatAgent, type ChatCommand, type RunChatInput, type StdoutMapper, createCodexAgent, createCodexStdoutMapper, createGeminiAgent, runChat };
|
|
105
|
+
export { Agent, type BaseChatRequest, type ChatAgent, type ChatCommand, type RunChatInput, type StdoutMapper, createCodexAgent, createCodexStdoutMapper, createGeminiAgent, runChat };
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,87 @@
|
|
|
1
|
+
// src/agent.ts
|
|
2
|
+
import { Sandbox } from "@vercel/sandbox";
|
|
3
|
+
var Agent = class _Agent {
|
|
4
|
+
_type;
|
|
5
|
+
_snapshotId;
|
|
6
|
+
_pendingOps = [];
|
|
7
|
+
constructor(type, snapshotId) {
|
|
8
|
+
this._type = type;
|
|
9
|
+
this._snapshotId = snapshotId;
|
|
10
|
+
}
|
|
11
|
+
static create(type, options) {
|
|
12
|
+
const trimmed = options.snapshotId.trim();
|
|
13
|
+
if (!trimmed) {
|
|
14
|
+
throw new Error("snapshotId is required.");
|
|
15
|
+
}
|
|
16
|
+
return new _Agent(type, trimmed);
|
|
17
|
+
}
|
|
18
|
+
get type() {
|
|
19
|
+
return this._type;
|
|
20
|
+
}
|
|
21
|
+
get snapshotId() {
|
|
22
|
+
return this._snapshotId;
|
|
23
|
+
}
|
|
24
|
+
get dirty() {
|
|
25
|
+
return this._pendingOps.length > 0;
|
|
26
|
+
}
|
|
27
|
+
addFiles(files) {
|
|
28
|
+
if (files.length === 0) {
|
|
29
|
+
return this;
|
|
30
|
+
}
|
|
31
|
+
this._pendingOps.push({
|
|
32
|
+
kind: "writeFiles",
|
|
33
|
+
files
|
|
34
|
+
});
|
|
35
|
+
return this;
|
|
36
|
+
}
|
|
37
|
+
setAgentMd(content) {
|
|
38
|
+
const buffer = typeof content === "string" ? Buffer.from(content) : content;
|
|
39
|
+
console.log(`[agent] setAgentMd called, content length=${buffer.length}`);
|
|
40
|
+
return this.addFiles([
|
|
41
|
+
{ path: "/home/vercel-sandbox/AGENTS.md", content: buffer }
|
|
42
|
+
]);
|
|
43
|
+
}
|
|
44
|
+
runCommands(commands) {
|
|
45
|
+
for (const command of commands) {
|
|
46
|
+
this._pendingOps.push({
|
|
47
|
+
kind: "runCommand",
|
|
48
|
+
cmd: command.cmd,
|
|
49
|
+
args: command.args ?? []
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
return this;
|
|
53
|
+
}
|
|
54
|
+
async prepare() {
|
|
55
|
+
console.log(
|
|
56
|
+
`[agent] prepare called, dirty=${this.dirty}, pendingOps=${this._pendingOps.length}`
|
|
57
|
+
);
|
|
58
|
+
if (!this.dirty) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
const ops = this._pendingOps;
|
|
62
|
+
const sandbox = await Sandbox.create({
|
|
63
|
+
source: { type: "snapshot", snapshotId: this._snapshotId }
|
|
64
|
+
});
|
|
65
|
+
console.log(
|
|
66
|
+
`[sandbox] created sandbox=${sandbox.sandboxId} from snapshot=${this._snapshotId}`
|
|
67
|
+
);
|
|
68
|
+
for (const op of ops) {
|
|
69
|
+
switch (op.kind) {
|
|
70
|
+
case "writeFiles":
|
|
71
|
+
await sandbox.writeFiles(op.files);
|
|
72
|
+
break;
|
|
73
|
+
case "runCommand":
|
|
74
|
+
await sandbox.runCommand(op.cmd, op.args);
|
|
75
|
+
break;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
const snapshot = await sandbox.snapshot();
|
|
79
|
+
console.log(`[agent] prepare done, new snapshotId=${snapshot.snapshotId}`);
|
|
80
|
+
this._snapshotId = snapshot.snapshotId;
|
|
81
|
+
this._pendingOps = [];
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
|
|
1
85
|
// src/agents/codex-agent.ts
|
|
2
86
|
import * as TOML from "@iarna/toml";
|
|
3
87
|
import { z } from "zod";
|
|
@@ -39,6 +123,18 @@ function mapEvent(event) {
|
|
|
39
123
|
content: typeof event.message === "string" ? event.message : JSON.stringify(event)
|
|
40
124
|
};
|
|
41
125
|
}
|
|
126
|
+
if (type === "item.completed") {
|
|
127
|
+
const item = event.item;
|
|
128
|
+
if (item?.type === "agent_message" && typeof item.text === "string") {
|
|
129
|
+
return {
|
|
130
|
+
type: "message",
|
|
131
|
+
role: "assistant",
|
|
132
|
+
content: item.text,
|
|
133
|
+
delta: false
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
42
138
|
if (type === "response.completed") {
|
|
43
139
|
return null;
|
|
44
140
|
}
|
|
@@ -158,18 +254,11 @@ function assertBrowserToolRelayCredentials(parsed) {
|
|
|
158
254
|
function createCodexAgent(options = {}) {
|
|
159
255
|
const env = options.env ?? {};
|
|
160
256
|
const snapshotId = options.snapshotId?.trim() || requiredEnv(env, "SANDBOX_SNAPSHOT_ID");
|
|
161
|
-
const apiKey = env
|
|
162
|
-
if (!apiKey) {
|
|
163
|
-
throw new Error(
|
|
164
|
-
"Missing required environment variable: CODEX_API_KEY or OPENAI_API_KEY"
|
|
165
|
-
);
|
|
166
|
-
}
|
|
257
|
+
const apiKey = requiredEnv(env, "CODEX_API_KEY");
|
|
167
258
|
const browserToolEnabled = options.tools?.browser !== void 0;
|
|
168
259
|
const browserToolRelayUrl = options.tools?.browser?.relayUrl?.trim();
|
|
169
260
|
if (browserToolEnabled) {
|
|
170
261
|
requiredEnv(env, "BROWSER_TOOL_RELAY_URL");
|
|
171
|
-
requiredEnv(env, "BROWSER_TOOL_RELAY_SESSION_ID");
|
|
172
|
-
requiredEnv(env, "BROWSER_TOOL_RELAY_TOKEN");
|
|
173
262
|
}
|
|
174
263
|
if (browserToolEnabled && !browserToolRelayUrl) {
|
|
175
264
|
throw new Error("tools.browser.relayUrl is empty.");
|
|
@@ -181,9 +270,13 @@ function createCodexAgent(options = {}) {
|
|
|
181
270
|
if (!browserToolEnabled) {
|
|
182
271
|
return;
|
|
183
272
|
}
|
|
184
|
-
requiredEnv(env, "VERCEL_OIDC_TOKEN");
|
|
185
273
|
assertBrowserToolRelayCredentials(_input.input);
|
|
186
|
-
|
|
274
|
+
const patchEnv = {
|
|
275
|
+
...env,
|
|
276
|
+
BROWSER_TOOL_RELAY_SESSION_ID: _input.input.relay_session_id,
|
|
277
|
+
BROWSER_TOOL_RELAY_TOKEN: _input.input.relay_token
|
|
278
|
+
};
|
|
279
|
+
await patchCodexConfigTransportEnv(_input.sandbox, patchEnv);
|
|
187
280
|
},
|
|
188
281
|
createCommand({ input }) {
|
|
189
282
|
const args = ["exec"];
|
|
@@ -194,9 +287,7 @@ function createCodexAgent(options = {}) {
|
|
|
194
287
|
return {
|
|
195
288
|
cmd: "codex",
|
|
196
289
|
args,
|
|
197
|
-
env: {
|
|
198
|
-
OPENAI_API_KEY: apiKey
|
|
199
|
-
}
|
|
290
|
+
env: { CODEX_API_KEY: apiKey }
|
|
200
291
|
};
|
|
201
292
|
},
|
|
202
293
|
createStdoutMapper() {
|
|
@@ -283,8 +374,6 @@ function createGeminiAgent(options = {}) {
|
|
|
283
374
|
const browserToolRelayUrl = options.tools?.browser?.relayUrl?.trim();
|
|
284
375
|
if (browserToolEnabled) {
|
|
285
376
|
requiredEnv2(env, "BROWSER_TOOL_RELAY_URL");
|
|
286
|
-
requiredEnv2(env, "BROWSER_TOOL_RELAY_SESSION_ID");
|
|
287
|
-
requiredEnv2(env, "BROWSER_TOOL_RELAY_TOKEN");
|
|
288
377
|
}
|
|
289
378
|
if (browserToolEnabled && !browserToolRelayUrl) {
|
|
290
379
|
throw new Error("tools.browser.relayUrl is empty.");
|
|
@@ -296,9 +385,13 @@ function createGeminiAgent(options = {}) {
|
|
|
296
385
|
if (!browserToolEnabled) {
|
|
297
386
|
return;
|
|
298
387
|
}
|
|
299
|
-
requiredEnv2(env, "VERCEL_OIDC_TOKEN");
|
|
300
388
|
assertBrowserToolRelayCredentials2(input);
|
|
301
|
-
|
|
389
|
+
const patchEnv = {
|
|
390
|
+
...env,
|
|
391
|
+
BROWSER_TOOL_RELAY_SESSION_ID: input.relay_session_id,
|
|
392
|
+
BROWSER_TOOL_RELAY_TOKEN: input.relay_token
|
|
393
|
+
};
|
|
394
|
+
await patchGeminiSettingsTransportEnv(sandbox, patchEnv);
|
|
302
395
|
},
|
|
303
396
|
createCommand({ input }) {
|
|
304
397
|
const args = [
|
|
@@ -325,7 +418,7 @@ function createGeminiAgent(options = {}) {
|
|
|
325
418
|
|
|
326
419
|
// src/chat-run.ts
|
|
327
420
|
import { Writable } from "stream";
|
|
328
|
-
import { Sandbox } from "@vercel/sandbox";
|
|
421
|
+
import { Sandbox as Sandbox2 } from "@vercel/sandbox";
|
|
329
422
|
function emitText(controller, text, encoder) {
|
|
330
423
|
if (text.length === 0) {
|
|
331
424
|
return;
|
|
@@ -379,19 +472,23 @@ function runChat(input) {
|
|
|
379
472
|
const mapper = input.agent.createStdoutMapper?.();
|
|
380
473
|
void (async () => {
|
|
381
474
|
try {
|
|
382
|
-
const sandbox = parsed.sandbox_id ? await
|
|
475
|
+
const sandbox = parsed.sandbox_id ? await Sandbox2.get({ sandboxId: parsed.sandbox_id }) : await (async () => {
|
|
383
476
|
const snapshotId = input.agent.snapshotId?.trim();
|
|
384
477
|
if (!snapshotId) {
|
|
385
478
|
throw new Error(
|
|
386
479
|
"Agent must provide snapshotId when sandbox_id is not provided."
|
|
387
480
|
);
|
|
388
481
|
}
|
|
389
|
-
|
|
482
|
+
const created = await Sandbox2.create({
|
|
390
483
|
source: {
|
|
391
484
|
type: "snapshot",
|
|
392
485
|
snapshotId
|
|
393
486
|
}
|
|
394
487
|
});
|
|
488
|
+
console.log(
|
|
489
|
+
`[sandbox] created sandbox=${created.sandboxId} from snapshot=${snapshotId}`
|
|
490
|
+
);
|
|
491
|
+
return created;
|
|
395
492
|
})();
|
|
396
493
|
enqueueEvent({ type: "sandbox", sandbox_id: sandbox.sandboxId });
|
|
397
494
|
await input.agent.prepareSandbox({
|
|
@@ -408,6 +505,7 @@ function runChat(input) {
|
|
|
408
505
|
stdout: new Writable({
|
|
409
506
|
write(chunk, _encoding, callback) {
|
|
410
507
|
const text = typeof chunk === "string" ? chunk : chunk.toString("utf8");
|
|
508
|
+
console.log("[sandbox-agent] raw stdout:", text);
|
|
411
509
|
if (mapper) {
|
|
412
510
|
for (const line of mapper.push(text)) {
|
|
413
511
|
enqueueStdout(line);
|
|
@@ -455,6 +553,7 @@ function runChat(input) {
|
|
|
455
553
|
);
|
|
456
554
|
}
|
|
457
555
|
export {
|
|
556
|
+
Agent,
|
|
458
557
|
createCodexAgent,
|
|
459
558
|
createCodexStdoutMapper,
|
|
460
559
|
createGeminiAgent,
|