sbox-sdk 0.0.2
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/LICENSE +21 -0
- package/README.md +137 -0
- package/dist/adapter/index.d.ts +22 -0
- package/dist/adapter/index.d.ts.map +1 -0
- package/dist/adapter/index.js +16 -0
- package/dist/agent-tools/index.d.ts +13 -0
- package/dist/agent-tools/index.d.ts.map +1 -0
- package/dist/agent-tools/index.js +9 -0
- package/dist/agent-tools/policy.d.ts +48 -0
- package/dist/agent-tools/policy.d.ts.map +1 -0
- package/dist/agent-tools/policy.js +51 -0
- package/dist/agent-tools/registry.d.ts +9 -0
- package/dist/agent-tools/registry.d.ts.map +1 -0
- package/dist/agent-tools/registry.js +412 -0
- package/dist/agent-tools/result.d.ts +32 -0
- package/dist/agent-tools/result.d.ts.map +1 -0
- package/dist/agent-tools/result.js +14 -0
- package/dist/agent-tools/types.d.ts +76 -0
- package/dist/agent-tools/types.d.ts.map +1 -0
- package/dist/agent-tools/types.js +1 -0
- package/dist/ai/index.d.ts +36 -0
- package/dist/ai/index.d.ts.map +1 -0
- package/dist/ai/index.js +40 -0
- package/dist/ai-sdk/index.d.ts +31 -0
- package/dist/ai-sdk/index.d.ts.map +1 -0
- package/dist/ai-sdk/index.js +80 -0
- package/dist/anthropic/index.d.ts +42 -0
- package/dist/anthropic/index.d.ts.map +1 -0
- package/dist/anthropic/index.js +64 -0
- package/dist/aws-lambda/index.d.ts +87 -0
- package/dist/aws-lambda/index.d.ts.map +1 -0
- package/dist/aws-lambda/index.js +290 -0
- package/dist/beam/index.d.ts +92 -0
- package/dist/beam/index.d.ts.map +1 -0
- package/dist/beam/index.js +222 -0
- package/dist/blaxel/index.d.ts +125 -0
- package/dist/blaxel/index.d.ts.map +1 -0
- package/dist/blaxel/index.js +220 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +249 -0
- package/dist/cloudflare/index.d.ts +64 -0
- package/dist/cloudflare/index.d.ts.map +1 -0
- package/dist/cloudflare/index.js +259 -0
- package/dist/codesandbox/index.d.ts +100 -0
- package/dist/codesandbox/index.d.ts.map +1 -0
- package/dist/codesandbox/index.js +227 -0
- package/dist/conformance/index.d.ts +20 -0
- package/dist/conformance/index.d.ts.map +1 -0
- package/dist/conformance/index.js +189 -0
- package/dist/daytona/index.d.ts +64 -0
- package/dist/daytona/index.d.ts.map +1 -0
- package/dist/daytona/index.js +258 -0
- package/dist/e2b/index.d.ts +63 -0
- package/dist/e2b/index.d.ts.map +1 -0
- package/dist/e2b/index.js +411 -0
- package/dist/fly/index.d.ts +75 -0
- package/dist/fly/index.d.ts.map +1 -0
- package/dist/fly/index.js +222 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +16 -0
- package/dist/internal/capabilities.d.ts +57 -0
- package/dist/internal/capabilities.d.ts.map +1 -0
- package/dist/internal/capabilities.js +68 -0
- package/dist/internal/client.d.ts +9 -0
- package/dist/internal/client.d.ts.map +1 -0
- package/dist/internal/client.js +126 -0
- package/dist/internal/encoding.d.ts +8 -0
- package/dist/internal/encoding.d.ts.map +1 -0
- package/dist/internal/encoding.js +20 -0
- package/dist/internal/errors.d.ts +45 -0
- package/dist/internal/errors.d.ts.map +1 -0
- package/dist/internal/errors.js +79 -0
- package/dist/internal/exec.d.ts +19 -0
- package/dist/internal/exec.d.ts.map +1 -0
- package/dist/internal/exec.js +208 -0
- package/dist/internal/plugin.d.ts +38 -0
- package/dist/internal/plugin.d.ts.map +1 -0
- package/dist/internal/plugin.js +1 -0
- package/dist/internal/runtime.d.ts +8 -0
- package/dist/internal/runtime.d.ts.map +1 -0
- package/dist/internal/runtime.js +21 -0
- package/dist/internal/sandbox.d.ts +12 -0
- package/dist/internal/sandbox.d.ts.map +1 -0
- package/dist/internal/sandbox.js +438 -0
- package/dist/internal/shell.d.ts +36 -0
- package/dist/internal/shell.d.ts.map +1 -0
- package/dist/internal/shell.js +88 -0
- package/dist/internal/stream.d.ts +15 -0
- package/dist/internal/stream.d.ts.map +1 -0
- package/dist/internal/stream.js +58 -0
- package/dist/internal/types.d.ts +381 -0
- package/dist/internal/types.d.ts.map +1 -0
- package/dist/internal/types.js +1 -0
- package/dist/langchain/index.d.ts +25 -0
- package/dist/langchain/index.d.ts.map +1 -0
- package/dist/langchain/index.js +61 -0
- package/dist/mastra/index.d.ts +43 -0
- package/dist/mastra/index.d.ts.map +1 -0
- package/dist/mastra/index.js +69 -0
- package/dist/memory/index.d.ts +57 -0
- package/dist/memory/index.d.ts.map +1 -0
- package/dist/memory/index.js +573 -0
- package/dist/modal/index.d.ts +67 -0
- package/dist/modal/index.d.ts.map +1 -0
- package/dist/modal/index.js +223 -0
- package/dist/morph/index.d.ts +91 -0
- package/dist/morph/index.d.ts.map +1 -0
- package/dist/morph/index.js +221 -0
- package/dist/northflank/index.d.ts +74 -0
- package/dist/northflank/index.d.ts.map +1 -0
- package/dist/northflank/index.js +265 -0
- package/dist/openai/index.d.ts +25 -0
- package/dist/openai/index.d.ts.map +1 -0
- package/dist/openai/index.js +71 -0
- package/dist/railway/index.d.ts +109 -0
- package/dist/railway/index.d.ts.map +1 -0
- package/dist/railway/index.js +219 -0
- package/dist/runloop/index.d.ts +69 -0
- package/dist/runloop/index.d.ts.map +1 -0
- package/dist/runloop/index.js +226 -0
- package/dist/testing/index.d.ts +44 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +61 -0
- package/dist/vercel/index.d.ts +63 -0
- package/dist/vercel/index.d.ts.map +1 -0
- package/dist/vercel/index.js +241 -0
- package/package.json +252 -0
- package/src/aws-lambda/runner/Dockerfile +15 -0
- package/src/aws-lambda/runner/README.md +59 -0
- package/src/aws-lambda/runner/server.mjs +91 -0
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `sbox-sdk/northflank` — adapter for Northflank (`@northflank/js-client`).
|
|
3
|
+
* Northflank is a services platform, so a "sandbox" is a deployment service that
|
|
4
|
+
* runs a base image with a `sleep infinity` keep-alive command. exec uses
|
|
5
|
+
* `apiClient.exec.execServiceSession`, which streams stdout/stderr over Node
|
|
6
|
+
* EventEmitters and resolves an exit code via `waitForCommandResult()`; the
|
|
7
|
+
* adapter buffers it. There is no per-call cwd/env, so the core folds those into
|
|
8
|
+
* a `cd … && KEY=v …` wrapper (`perCommandEnvCwd: false`). Filesystem is exec +
|
|
9
|
+
* base64.
|
|
10
|
+
*
|
|
11
|
+
* `pause()` scales the service to zero (volume retained, memory lost),
|
|
12
|
+
* `resume()` scales it back, `destroy()` deletes the service and its children.
|
|
13
|
+
* Ports are made public via the service port config and resolved to their public
|
|
14
|
+
* DNS. Node-only (the SDK uses EventEmitters). Requires the optional peer
|
|
15
|
+
* dependency `@northflank/js-client`.
|
|
16
|
+
*/
|
|
17
|
+
import { AsyncQueue, base64ToBytes, bytesToBase64, defineProvider, SandboxError, shellQuote as sq, } from "../adapter/index.js";
|
|
18
|
+
export const NORTHFLANK_CAPS = {
|
|
19
|
+
background: "unsupported",
|
|
20
|
+
codeInterpreter: "unsupported",
|
|
21
|
+
egressControl: "unsupported",
|
|
22
|
+
exposePort: "native",
|
|
23
|
+
filesUpload: "native",
|
|
24
|
+
filesWatch: "unsupported",
|
|
25
|
+
fork: "unsupported",
|
|
26
|
+
gpu: "unsupported",
|
|
27
|
+
killProcess: "unsupported",
|
|
28
|
+
list: "native",
|
|
29
|
+
metrics: "unsupported",
|
|
30
|
+
pause: "native",
|
|
31
|
+
privatePreview: "unsupported",
|
|
32
|
+
proxiedFetch: "unsupported",
|
|
33
|
+
pty: "unsupported",
|
|
34
|
+
region: "unsupported",
|
|
35
|
+
secretsVault: "unsupported",
|
|
36
|
+
setTimeout: "unsupported",
|
|
37
|
+
snapshot: "unsupported",
|
|
38
|
+
ssh: "unsupported",
|
|
39
|
+
statefulKernel: "unsupported",
|
|
40
|
+
stdin: "unsupported",
|
|
41
|
+
stop: "unsupported",
|
|
42
|
+
streaming: "emulated",
|
|
43
|
+
volumes: "unsupported",
|
|
44
|
+
};
|
|
45
|
+
const NORTHFLANK_FLAGS = {
|
|
46
|
+
exitCodeNative: true, // waitForCommandResult() returns the exit code
|
|
47
|
+
perCommandEnvCwd: false, // execServiceSession has no cwd/env — core wraps it
|
|
48
|
+
preservesDiskOnStop: false,
|
|
49
|
+
preservesMemoryOnPause: false, // scale-to-zero loses memory (volume retained)
|
|
50
|
+
previewModel: "subdomain",
|
|
51
|
+
};
|
|
52
|
+
let cached = null;
|
|
53
|
+
async function loadNorthflank() {
|
|
54
|
+
if (!cached) {
|
|
55
|
+
cached = (await import("@northflank/js-client"));
|
|
56
|
+
}
|
|
57
|
+
return cached;
|
|
58
|
+
}
|
|
59
|
+
function mapState(state) {
|
|
60
|
+
switch ((state ?? "").toLowerCase()) {
|
|
61
|
+
case "running": {
|
|
62
|
+
return "running";
|
|
63
|
+
}
|
|
64
|
+
case "paused": {
|
|
65
|
+
return "paused";
|
|
66
|
+
}
|
|
67
|
+
case "deploying":
|
|
68
|
+
case "building":
|
|
69
|
+
case "deploymentongoing": {
|
|
70
|
+
return "creating";
|
|
71
|
+
}
|
|
72
|
+
case "failed":
|
|
73
|
+
case "unhealthy": {
|
|
74
|
+
return "error";
|
|
75
|
+
}
|
|
76
|
+
default: {
|
|
77
|
+
return "unknown";
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
export const northflank = defineProvider((opts) => {
|
|
82
|
+
const { projectId } = opts;
|
|
83
|
+
let clientP = null;
|
|
84
|
+
const getClient = () => {
|
|
85
|
+
if (!clientP) {
|
|
86
|
+
clientP = (async () => {
|
|
87
|
+
const mod = await loadNorthflank();
|
|
88
|
+
const ctx = new mod.ApiClientInMemoryContextProvider();
|
|
89
|
+
await ctx.addContext({ name: "sbox", token: opts.token });
|
|
90
|
+
return new mod.ApiClient(ctx, { throwErrorOnHttpErrorCode: true });
|
|
91
|
+
})();
|
|
92
|
+
}
|
|
93
|
+
return clientP;
|
|
94
|
+
};
|
|
95
|
+
const makeHandle = (ref, client) => {
|
|
96
|
+
const params = { projectId: ref.projectId, serviceId: ref.serviceId };
|
|
97
|
+
const exec1 = async (cmd) => {
|
|
98
|
+
const handle = await client.exec.execServiceSession({ parameters: params }, { shell: "sh -c", command: cmd });
|
|
99
|
+
const out = [];
|
|
100
|
+
const err = [];
|
|
101
|
+
handle.stdOut.on("data", (d) => out.push(String(d)));
|
|
102
|
+
handle.stdErr.on("data", (d) => err.push(String(d)));
|
|
103
|
+
const result = await handle.waitForCommandResult();
|
|
104
|
+
return {
|
|
105
|
+
stdout: out.join(""),
|
|
106
|
+
stderr: err.join(""),
|
|
107
|
+
exitCode: result.exitCode ?? 0,
|
|
108
|
+
};
|
|
109
|
+
};
|
|
110
|
+
return {
|
|
111
|
+
id: ref.serviceId,
|
|
112
|
+
raw: ref,
|
|
113
|
+
async getInfo() {
|
|
114
|
+
const res = await client.get.service({ parameters: params });
|
|
115
|
+
return {
|
|
116
|
+
id: ref.serviceId,
|
|
117
|
+
state: mapState(res.data?.status),
|
|
118
|
+
provider: "northflank",
|
|
119
|
+
metadata: {},
|
|
120
|
+
raw: ref,
|
|
121
|
+
};
|
|
122
|
+
},
|
|
123
|
+
async destroy() {
|
|
124
|
+
await client.delete.service({
|
|
125
|
+
parameters: params,
|
|
126
|
+
options: { delete_child_objects: true },
|
|
127
|
+
});
|
|
128
|
+
},
|
|
129
|
+
async pause() {
|
|
130
|
+
await client.pause.service({ parameters: params });
|
|
131
|
+
},
|
|
132
|
+
async resume() {
|
|
133
|
+
await client.resume.service({ parameters: params });
|
|
134
|
+
},
|
|
135
|
+
exec(cmd) {
|
|
136
|
+
const queue = new AsyncQueue();
|
|
137
|
+
void exec1(cmd)
|
|
138
|
+
.then((r) => {
|
|
139
|
+
if (r.stdout) {
|
|
140
|
+
queue.push({ type: "stdout", data: r.stdout });
|
|
141
|
+
}
|
|
142
|
+
if (r.stderr) {
|
|
143
|
+
queue.push({ type: "stderr", data: r.stderr });
|
|
144
|
+
}
|
|
145
|
+
queue.push({ type: "exit", exitCode: r.exitCode });
|
|
146
|
+
queue.close();
|
|
147
|
+
})
|
|
148
|
+
.catch((error) => queue.fail(error instanceof SandboxError
|
|
149
|
+
? error
|
|
150
|
+
: SandboxError.wrap(error, "northflank")));
|
|
151
|
+
return {
|
|
152
|
+
pid: Promise.resolve(""),
|
|
153
|
+
async kill() {
|
|
154
|
+
/* execServiceSession is buffered here; no kill handle */
|
|
155
|
+
},
|
|
156
|
+
[Symbol.asyncIterator]: () => queue.iterator(),
|
|
157
|
+
};
|
|
158
|
+
},
|
|
159
|
+
async readFile(path) {
|
|
160
|
+
const r = await exec1(`base64 ${sq(path)}`);
|
|
161
|
+
if (r.exitCode !== 0) {
|
|
162
|
+
throw new SandboxError("NotFound", `no such file: '${path}'`, {
|
|
163
|
+
provider: "northflank",
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
return base64ToBytes(r.stdout);
|
|
167
|
+
},
|
|
168
|
+
async writeFile(path, data) {
|
|
169
|
+
const b64 = bytesToBase64(data);
|
|
170
|
+
const r = await exec1(`mkdir -p "$(dirname ${sq(path)})" && printf %s ${sq(b64)} | base64 -d > ${sq(path)}`);
|
|
171
|
+
if (r.exitCode !== 0) {
|
|
172
|
+
throw new SandboxError("Provider", `write failed: '${path}'`, {
|
|
173
|
+
provider: "northflank",
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
},
|
|
177
|
+
async exposePort(port) {
|
|
178
|
+
await client.update.service.ports({
|
|
179
|
+
parameters: params,
|
|
180
|
+
data: {
|
|
181
|
+
ports: [
|
|
182
|
+
{
|
|
183
|
+
name: `p${port}`,
|
|
184
|
+
internalPort: port,
|
|
185
|
+
public: true,
|
|
186
|
+
protocol: "HTTP",
|
|
187
|
+
},
|
|
188
|
+
],
|
|
189
|
+
},
|
|
190
|
+
});
|
|
191
|
+
const got = await client.get.service.ports({ parameters: params });
|
|
192
|
+
const dns = got.data?.ports?.find((p) => p.internalPort === port)?.dns;
|
|
193
|
+
return { url: dns ? `https://${dns}` : "", port };
|
|
194
|
+
},
|
|
195
|
+
};
|
|
196
|
+
};
|
|
197
|
+
const provider = {
|
|
198
|
+
name: "northflank",
|
|
199
|
+
capabilities: NORTHFLANK_CAPS,
|
|
200
|
+
flags: NORTHFLANK_FLAGS,
|
|
201
|
+
async create(spec) {
|
|
202
|
+
const client = await getClient();
|
|
203
|
+
const serviceId = spec.name ?? `sandbox-${globalThis.crypto.randomUUID().slice(0, 8)}`;
|
|
204
|
+
await client.create.service.deployment({
|
|
205
|
+
parameters: { projectId },
|
|
206
|
+
data: {
|
|
207
|
+
name: serviceId,
|
|
208
|
+
billing: { deploymentPlan: opts.deploymentPlan ?? "nf-compute-200" },
|
|
209
|
+
deployment: {
|
|
210
|
+
instances: 1,
|
|
211
|
+
docker: {
|
|
212
|
+
configType: "customCommand",
|
|
213
|
+
customCommand: "sleep infinity",
|
|
214
|
+
},
|
|
215
|
+
external: {
|
|
216
|
+
imagePath: spec.template ?? opts.image ?? "ubuntu:22.04",
|
|
217
|
+
},
|
|
218
|
+
storage: {
|
|
219
|
+
ephemeralStorage: {
|
|
220
|
+
storageSize: opts.ephemeralStorageMB ?? 2048,
|
|
221
|
+
},
|
|
222
|
+
},
|
|
223
|
+
},
|
|
224
|
+
runtimeEnvironment: spec.env ?? {},
|
|
225
|
+
},
|
|
226
|
+
});
|
|
227
|
+
const ref = { projectId, serviceId };
|
|
228
|
+
// Best-effort wait for the service to come up before returning.
|
|
229
|
+
for (let i = 0; i < 60; i++) {
|
|
230
|
+
const res = await client.get
|
|
231
|
+
.service({ parameters: { projectId, serviceId } })
|
|
232
|
+
.catch(() => null);
|
|
233
|
+
const status = res?.data?.status;
|
|
234
|
+
if (status === "running") {
|
|
235
|
+
break;
|
|
236
|
+
}
|
|
237
|
+
if (status === "failed") {
|
|
238
|
+
throw new SandboxError("Provider", `service ${serviceId} failed to start`, {
|
|
239
|
+
provider: "northflank",
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
await new Promise((r) => setTimeout(r, 2000));
|
|
243
|
+
}
|
|
244
|
+
return makeHandle(ref, client);
|
|
245
|
+
},
|
|
246
|
+
async connect(id) {
|
|
247
|
+
const client = await getClient();
|
|
248
|
+
return makeHandle({ projectId, serviceId: id }, client);
|
|
249
|
+
},
|
|
250
|
+
async *list() {
|
|
251
|
+
const client = await getClient();
|
|
252
|
+
const res = await client.list.services({ parameters: { projectId } });
|
|
253
|
+
for (const s of res.data?.services ?? []) {
|
|
254
|
+
yield {
|
|
255
|
+
id: s.id,
|
|
256
|
+
state: mapState(s.status),
|
|
257
|
+
provider: "northflank",
|
|
258
|
+
metadata: {},
|
|
259
|
+
raw: { projectId, serviceId: s.id },
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
},
|
|
263
|
+
};
|
|
264
|
+
return provider;
|
|
265
|
+
});
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { Tool } from "@openai/agents";
|
|
2
|
+
import type { FrameworkAdapter, ToolSetOptions, ToolSpec } from "../agent-tools/types.js";
|
|
3
|
+
import type { Sandbox } from "../internal/types.js";
|
|
4
|
+
export type OpenAIToolOptions = ToolSetOptions;
|
|
5
|
+
/** OpenAI Agents takes tools as an array. */
|
|
6
|
+
export type OpenAIToolSet = Tool[];
|
|
7
|
+
/**
|
|
8
|
+
* Build OpenAI Agents tools from a live sandbox (capability-gated) or a
|
|
9
|
+
* pre-built `ToolSpec[]`. Pass the result to `new Agent({ tools })`.
|
|
10
|
+
*/
|
|
11
|
+
export declare function toOpenAITools(source: Sandbox | ToolSpec[], opts?: OpenAIToolOptions): OpenAIToolSet;
|
|
12
|
+
/**
|
|
13
|
+
* The OpenAI Agents framework adapter for the `ai()` plugin:
|
|
14
|
+
*
|
|
15
|
+
* ```ts
|
|
16
|
+
* import { ai } from "sbox-sdk/ai";
|
|
17
|
+
* import { openaiAgents } from "sbox-sdk/openai";
|
|
18
|
+
*
|
|
19
|
+
* const client = createSandboxClient({ provider: e2b(), plugins: [ai({ framework: openaiAgents() })] });
|
|
20
|
+
* const sandbox = await client.create();
|
|
21
|
+
* const agent = new Agent({ name: "coder", tools: sandbox.tools });
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export declare function openaiAgents(): FrameworkAdapter<OpenAIToolSet>;
|
|
25
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/openai/index.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAI3C,OAAO,KAAK,EACV,gBAAgB,EAEhB,cAAc,EACd,QAAQ,EACT,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAEpD,MAAM,MAAM,iBAAiB,GAAG,cAAc,CAAC;AAE/C,6CAA6C;AAC7C,MAAM,MAAM,aAAa,GAAG,IAAI,EAAE,CAAC;AAanC;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,OAAO,GAAG,QAAQ,EAAE,EAC5B,IAAI,GAAE,iBAAsB,GAC3B,aAAa,CAyBf;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,IAAI,gBAAgB,CAAC,aAAa,CAAC,CAK9D"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `sbox-sdk/openai` — OpenAI Agents SDK adapter. Projects the provider-neutral
|
|
3
|
+
* sandbox tool registry into `tool()` objects, returned as an **array** for
|
|
4
|
+
* `new Agent({ tools })`.
|
|
5
|
+
*
|
|
6
|
+
* Approval: the OpenAI Agents SDK has native human-in-the-loop, so this adapter
|
|
7
|
+
* wires the policy into `needsApproval` — `"ask"` → the agent surfaces a
|
|
8
|
+
* `tool_approval_requested` interruption on the `RunResult` (the host resolves
|
|
9
|
+
* it via `result.state.approve()/reject()` + re-run). `"deny"` is enforced
|
|
10
|
+
* inside `execute` (returns a message the model reads).
|
|
11
|
+
*
|
|
12
|
+
* Schema: our zod schemas are passed directly with `strict: true`; the SDK
|
|
13
|
+
* converts optional fields to nullable+required (OpenAI strict-mode valid).
|
|
14
|
+
*
|
|
15
|
+
* Peer dependency: `@openai/agents` (optional).
|
|
16
|
+
*/
|
|
17
|
+
import { tool } from "@openai/agents";
|
|
18
|
+
import { decide } from "../agent-tools/policy.js";
|
|
19
|
+
import { createSandboxTools } from "../agent-tools/registry.js";
|
|
20
|
+
function resolve(source, opts) {
|
|
21
|
+
return Array.isArray(source)
|
|
22
|
+
? { specs: source }
|
|
23
|
+
: { sandbox: source, specs: createSandboxTools(source, opts) };
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Build OpenAI Agents tools from a live sandbox (capability-gated) or a
|
|
27
|
+
* pre-built `ToolSpec[]`. Pass the result to `new Agent({ tools })`.
|
|
28
|
+
*/
|
|
29
|
+
export function toOpenAITools(source, opts = {}) {
|
|
30
|
+
const { specs, sandbox } = resolve(source, opts);
|
|
31
|
+
const { policy } = opts;
|
|
32
|
+
return specs.map((spec) => {
|
|
33
|
+
const ctx = { sandbox };
|
|
34
|
+
return tool({
|
|
35
|
+
name: spec.name,
|
|
36
|
+
description: spec.description,
|
|
37
|
+
// `inputSchema` is erased to z.ZodType but is a z.object() at runtime, which
|
|
38
|
+
// the SDK accepts and converts to a strict JSON schema (verified by the
|
|
39
|
+
// round-trip test). The SDK's ZodObjectLike param type is modeled on zod 3,
|
|
40
|
+
// so this type-only cast bridges the boundary; the runtime value is unchanged.
|
|
41
|
+
parameters: spec.inputSchema,
|
|
42
|
+
strict: true,
|
|
43
|
+
// Native HITL: "ask" -> the SDK raises a tool-approval interruption.
|
|
44
|
+
needsApproval: async (_runContext, input) => decide(spec, input, ctx, policy) === "ask",
|
|
45
|
+
execute: async (input) => {
|
|
46
|
+
if (decide(spec, input, ctx, policy) === "deny") {
|
|
47
|
+
return `Denied by policy: ${spec.name} is not permitted.`;
|
|
48
|
+
}
|
|
49
|
+
return (await spec.execute(input, ctx)).text;
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* The OpenAI Agents framework adapter for the `ai()` plugin:
|
|
56
|
+
*
|
|
57
|
+
* ```ts
|
|
58
|
+
* import { ai } from "sbox-sdk/ai";
|
|
59
|
+
* import { openaiAgents } from "sbox-sdk/openai";
|
|
60
|
+
*
|
|
61
|
+
* const client = createSandboxClient({ provider: e2b(), plugins: [ai({ framework: openaiAgents() })] });
|
|
62
|
+
* const sandbox = await client.create();
|
|
63
|
+
* const agent = new Agent({ name: "coder", tools: sandbox.tools });
|
|
64
|
+
* ```
|
|
65
|
+
*/
|
|
66
|
+
export function openaiAgents() {
|
|
67
|
+
return {
|
|
68
|
+
build: (sandbox, opts) => toOpenAITools(sandbox, opts),
|
|
69
|
+
name: "openai",
|
|
70
|
+
};
|
|
71
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import type { SandboxProvider } from "../adapter/index.js";
|
|
2
|
+
export interface RailwayOptions {
|
|
3
|
+
/** Railway API token (falls back to RAILWAY_API_TOKEN in the environment). */
|
|
4
|
+
token?: string;
|
|
5
|
+
/** Target environment id (falls back to RAILWAY_ENVIRONMENT_ID). */
|
|
6
|
+
environmentId?: string;
|
|
7
|
+
/** Network isolation for new sandboxes (default "ISOLATED"). */
|
|
8
|
+
networkIsolation?: "ISOLATED" | "PRIVATE";
|
|
9
|
+
}
|
|
10
|
+
export declare const RAILWAY_CAPS: {
|
|
11
|
+
readonly background: "unsupported";
|
|
12
|
+
readonly codeInterpreter: "unsupported";
|
|
13
|
+
readonly egressControl: "unsupported";
|
|
14
|
+
readonly exposePort: "unsupported";
|
|
15
|
+
readonly filesUpload: "native";
|
|
16
|
+
readonly filesWatch: "unsupported";
|
|
17
|
+
readonly fork: "native";
|
|
18
|
+
readonly gpu: "unsupported";
|
|
19
|
+
readonly killProcess: "unsupported";
|
|
20
|
+
readonly list: "native";
|
|
21
|
+
readonly metrics: "unsupported";
|
|
22
|
+
readonly pause: "unsupported";
|
|
23
|
+
readonly privatePreview: "unsupported";
|
|
24
|
+
readonly proxiedFetch: "unsupported";
|
|
25
|
+
readonly pty: "unsupported";
|
|
26
|
+
readonly region: "unsupported";
|
|
27
|
+
readonly secretsVault: "unsupported";
|
|
28
|
+
readonly setTimeout: "unsupported";
|
|
29
|
+
readonly snapshot: "native";
|
|
30
|
+
readonly ssh: "unsupported";
|
|
31
|
+
readonly statefulKernel: "unsupported";
|
|
32
|
+
readonly stdin: "unsupported";
|
|
33
|
+
readonly stop: "unsupported";
|
|
34
|
+
readonly streaming: "native";
|
|
35
|
+
readonly volumes: "unsupported";
|
|
36
|
+
};
|
|
37
|
+
export type RailwayCaps = typeof RAILWAY_CAPS;
|
|
38
|
+
interface RailwayExecResult {
|
|
39
|
+
exitCode?: number | null;
|
|
40
|
+
stdout?: string;
|
|
41
|
+
stderr?: string;
|
|
42
|
+
}
|
|
43
|
+
interface RailwayFiles {
|
|
44
|
+
read(path: string, opts?: {
|
|
45
|
+
format?: "text" | "bytes" | "stream";
|
|
46
|
+
}): Promise<Uint8Array | string>;
|
|
47
|
+
write(path: string, content: Uint8Array | string): Promise<void>;
|
|
48
|
+
list(dir: string): Promise<{
|
|
49
|
+
name: string;
|
|
50
|
+
type?: string;
|
|
51
|
+
isDir?: boolean;
|
|
52
|
+
}[]>;
|
|
53
|
+
stat(path: string): Promise<{
|
|
54
|
+
size?: number;
|
|
55
|
+
isDir?: boolean;
|
|
56
|
+
type?: string;
|
|
57
|
+
mtime?: number;
|
|
58
|
+
}>;
|
|
59
|
+
mkdir(dir: string): Promise<void>;
|
|
60
|
+
rename(from: string, to: string): Promise<void>;
|
|
61
|
+
remove(path: string): Promise<void>;
|
|
62
|
+
}
|
|
63
|
+
interface RailwaySandbox {
|
|
64
|
+
id?: string;
|
|
65
|
+
sandboxId?: string;
|
|
66
|
+
exec(command: string, opts?: {
|
|
67
|
+
timeoutSec?: number;
|
|
68
|
+
cwd?: string;
|
|
69
|
+
env?: Record<string, string>;
|
|
70
|
+
onStdout?: (chunk: string) => void;
|
|
71
|
+
onStderr?: (chunk: string) => void;
|
|
72
|
+
}): Promise<RailwayExecResult>;
|
|
73
|
+
files: RailwayFiles;
|
|
74
|
+
fork(opts?: Record<string, unknown>): Promise<RailwaySandbox>;
|
|
75
|
+
checkpoint(name: string): Promise<{
|
|
76
|
+
name?: string;
|
|
77
|
+
id?: string;
|
|
78
|
+
} | string>;
|
|
79
|
+
destroy(): Promise<void>;
|
|
80
|
+
}
|
|
81
|
+
export declare const railway: (opts: RailwayOptions) => SandboxProvider<{
|
|
82
|
+
readonly background: "unsupported";
|
|
83
|
+
readonly codeInterpreter: "unsupported";
|
|
84
|
+
readonly egressControl: "unsupported";
|
|
85
|
+
readonly exposePort: "unsupported";
|
|
86
|
+
readonly filesUpload: "native";
|
|
87
|
+
readonly filesWatch: "unsupported";
|
|
88
|
+
readonly fork: "native";
|
|
89
|
+
readonly gpu: "unsupported";
|
|
90
|
+
readonly killProcess: "unsupported";
|
|
91
|
+
readonly list: "native";
|
|
92
|
+
readonly metrics: "unsupported";
|
|
93
|
+
readonly pause: "unsupported";
|
|
94
|
+
readonly privatePreview: "unsupported";
|
|
95
|
+
readonly proxiedFetch: "unsupported";
|
|
96
|
+
readonly pty: "unsupported";
|
|
97
|
+
readonly region: "unsupported";
|
|
98
|
+
readonly secretsVault: "unsupported";
|
|
99
|
+
readonly setTimeout: "unsupported";
|
|
100
|
+
readonly snapshot: "native";
|
|
101
|
+
readonly ssh: "unsupported";
|
|
102
|
+
readonly statefulKernel: "unsupported";
|
|
103
|
+
readonly stdin: "unsupported";
|
|
104
|
+
readonly stop: "unsupported";
|
|
105
|
+
readonly streaming: "native";
|
|
106
|
+
readonly volumes: "unsupported";
|
|
107
|
+
}, RailwaySandbox>;
|
|
108
|
+
export {};
|
|
109
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/railway/index.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAUV,eAAe,EAIhB,MAAM,qBAAqB,CAAC;AAE7B,MAAM,WAAW,cAAc;IAC7B,8EAA8E;IAC9E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,oEAAoE;IACpE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,gEAAgE;IAChE,gBAAgB,CAAC,EAAE,UAAU,GAAG,SAAS,CAAC;CAC3C;AAED,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;CA0BS,CAAC;AAEnC,MAAM,MAAM,WAAW,GAAG,OAAO,YAAY,CAAC;AAW9C,UAAU,iBAAiB;IACzB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AACD,UAAU,YAAY;IACpB,IAAI,CACF,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,QAAQ,CAAA;KAAE,GAC9C,OAAO,CAAC,UAAU,GAAG,MAAM,CAAC,CAAC;IAChC,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,GAAG,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACjE,IAAI,CACF,GAAG,EAAE,MAAM,GACV,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,EAAE,CAAC,CAAC;IAC/D,IAAI,CACF,IAAI,EAAE,MAAM,GACX,OAAO,CAAC;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC9E,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAClC,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAChD,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACrC;AACD,UAAU,cAAc;IACtB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CACF,OAAO,EAAE,MAAM,EACf,IAAI,CAAC,EAAE;QACL,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAC7B,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;QACnC,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;KACpC,GACA,OAAO,CAAC,iBAAiB,CAAC,CAAC;IAC9B,KAAK,EAAE,YAAY,CAAC;IACpB,IAAI,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;IAC9D,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,EAAE,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,MAAM,CAAC,CAAC;IAC3E,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1B;AA6DD,eAAO,MAAM,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;kBA6JlB,CAAC"}
|