agentkernel 0.2.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/README.md +114 -0
- package/dist/index.cjs +384 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +178 -0
- package/dist/index.d.ts +178 -0
- package/dist/index.js +349 -0
- package/dist/index.js.map +1 -0
- package/package.json +63 -0
package/README.md
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# agentkernel
|
|
2
|
+
|
|
3
|
+
Node.js SDK for [agentkernel](https://github.com/thrashr888/agentkernel) — run AI coding agents in secure, isolated microVMs.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install agentkernel
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Requires Node.js 20+. Zero HTTP dependencies (uses native `fetch`).
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
import { AgentKernel } from "agentkernel";
|
|
17
|
+
|
|
18
|
+
const client = new AgentKernel();
|
|
19
|
+
|
|
20
|
+
// Run a command in a temporary sandbox
|
|
21
|
+
const result = await client.run(["echo", "hello"]);
|
|
22
|
+
console.log(result.output); // "hello\n"
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Sandbox Sessions
|
|
26
|
+
|
|
27
|
+
Create a persistent sandbox with automatic cleanup:
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
await using sb = await client.sandbox("my-project", {
|
|
31
|
+
image: "python:3.12-alpine",
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
await sb.run(["pip", "install", "numpy"]);
|
|
35
|
+
const result = await sb.run(["python3", "-c", "import numpy; print(numpy.__version__)"]);
|
|
36
|
+
console.log(result.output);
|
|
37
|
+
// sandbox auto-removed when scope exits
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Streaming
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
for await (const event of client.runStream(["python3", "script.py"])) {
|
|
44
|
+
if (event.type === "output") process.stdout.write(String(event.data.data));
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Configuration
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
const client = new AgentKernel({
|
|
52
|
+
baseUrl: "http://localhost:18888", // default
|
|
53
|
+
apiKey: "sk-...", // optional
|
|
54
|
+
timeout: 30000, // default: 30s
|
|
55
|
+
});
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Or use environment variables:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
export AGENTKERNEL_BASE_URL=http://localhost:18888
|
|
62
|
+
export AGENTKERNEL_API_KEY=sk-...
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## API
|
|
66
|
+
|
|
67
|
+
### `client.health()`
|
|
68
|
+
|
|
69
|
+
Health check. Returns `"ok"`.
|
|
70
|
+
|
|
71
|
+
### `client.run(command, options?)`
|
|
72
|
+
|
|
73
|
+
Run a command in a temporary sandbox.
|
|
74
|
+
|
|
75
|
+
```typescript
|
|
76
|
+
await client.run(["echo", "hello"]);
|
|
77
|
+
await client.run(["python3", "-c", "print(1)"], {
|
|
78
|
+
image: "python:3.12-alpine",
|
|
79
|
+
profile: "restrictive",
|
|
80
|
+
fast: false,
|
|
81
|
+
});
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### `client.runStream(command, options?)`
|
|
85
|
+
|
|
86
|
+
Run a command with SSE streaming output. Returns an `AsyncGenerator<StreamEvent>`.
|
|
87
|
+
|
|
88
|
+
### `client.listSandboxes()`
|
|
89
|
+
|
|
90
|
+
List all sandboxes.
|
|
91
|
+
|
|
92
|
+
### `client.createSandbox(name, options?)`
|
|
93
|
+
|
|
94
|
+
Create a new sandbox.
|
|
95
|
+
|
|
96
|
+
### `client.getSandbox(name)`
|
|
97
|
+
|
|
98
|
+
Get sandbox info.
|
|
99
|
+
|
|
100
|
+
### `client.removeSandbox(name)`
|
|
101
|
+
|
|
102
|
+
Remove a sandbox.
|
|
103
|
+
|
|
104
|
+
### `client.execInSandbox(name, command)`
|
|
105
|
+
|
|
106
|
+
Run a command in an existing sandbox.
|
|
107
|
+
|
|
108
|
+
### `client.sandbox(name, options?)`
|
|
109
|
+
|
|
110
|
+
Create a sandbox session with automatic cleanup. Returns a `SandboxSession` that implements `AsyncDisposable`.
|
|
111
|
+
|
|
112
|
+
## License
|
|
113
|
+
|
|
114
|
+
MIT
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,384 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
AgentKernel: () => AgentKernel,
|
|
24
|
+
AgentKernelError: () => AgentKernelError,
|
|
25
|
+
AuthError: () => AuthError,
|
|
26
|
+
NetworkError: () => NetworkError,
|
|
27
|
+
NotFoundError: () => NotFoundError,
|
|
28
|
+
SandboxSession: () => SandboxSession,
|
|
29
|
+
ServerError: () => ServerError,
|
|
30
|
+
StreamError: () => StreamError,
|
|
31
|
+
ValidationError: () => ValidationError
|
|
32
|
+
});
|
|
33
|
+
module.exports = __toCommonJS(index_exports);
|
|
34
|
+
|
|
35
|
+
// src/config.ts
|
|
36
|
+
var DEFAULT_BASE_URL = "http://localhost:18888";
|
|
37
|
+
var DEFAULT_TIMEOUT = 3e4;
|
|
38
|
+
function resolveConfig(opts) {
|
|
39
|
+
const baseUrl = opts?.baseUrl ?? process.env.AGENTKERNEL_BASE_URL ?? DEFAULT_BASE_URL;
|
|
40
|
+
const apiKey = opts?.apiKey ?? process.env.AGENTKERNEL_API_KEY ?? void 0;
|
|
41
|
+
const timeout = opts?.timeout ?? DEFAULT_TIMEOUT;
|
|
42
|
+
return {
|
|
43
|
+
baseUrl: baseUrl.replace(/\/+$/, ""),
|
|
44
|
+
apiKey,
|
|
45
|
+
timeout
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// src/errors.ts
|
|
50
|
+
var AgentKernelError = class extends Error {
|
|
51
|
+
constructor(message) {
|
|
52
|
+
super(message);
|
|
53
|
+
this.name = "AgentKernelError";
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
var AuthError = class extends AgentKernelError {
|
|
57
|
+
status = 401;
|
|
58
|
+
constructor(message = "Unauthorized") {
|
|
59
|
+
super(message);
|
|
60
|
+
this.name = "AuthError";
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
var NotFoundError = class extends AgentKernelError {
|
|
64
|
+
status = 404;
|
|
65
|
+
constructor(message = "Not found") {
|
|
66
|
+
super(message);
|
|
67
|
+
this.name = "NotFoundError";
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
var ValidationError = class extends AgentKernelError {
|
|
71
|
+
status = 400;
|
|
72
|
+
constructor(message = "Bad request") {
|
|
73
|
+
super(message);
|
|
74
|
+
this.name = "ValidationError";
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
var ServerError = class extends AgentKernelError {
|
|
78
|
+
status = 500;
|
|
79
|
+
constructor(message = "Internal server error") {
|
|
80
|
+
super(message);
|
|
81
|
+
this.name = "ServerError";
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
var NetworkError = class extends AgentKernelError {
|
|
85
|
+
constructor(message = "Network error") {
|
|
86
|
+
super(message);
|
|
87
|
+
this.name = "NetworkError";
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
var StreamError = class extends AgentKernelError {
|
|
91
|
+
constructor(message = "Stream error") {
|
|
92
|
+
super(message);
|
|
93
|
+
this.name = "StreamError";
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
function errorFromStatus(status, body) {
|
|
97
|
+
let message;
|
|
98
|
+
try {
|
|
99
|
+
const parsed = JSON.parse(body);
|
|
100
|
+
message = parsed.error ?? body;
|
|
101
|
+
} catch {
|
|
102
|
+
message = body;
|
|
103
|
+
}
|
|
104
|
+
switch (status) {
|
|
105
|
+
case 400:
|
|
106
|
+
return new ValidationError(message);
|
|
107
|
+
case 401:
|
|
108
|
+
return new AuthError(message);
|
|
109
|
+
case 404:
|
|
110
|
+
return new NotFoundError(message);
|
|
111
|
+
default:
|
|
112
|
+
return new ServerError(message);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// src/sandbox.ts
|
|
117
|
+
var SandboxSession = class {
|
|
118
|
+
name;
|
|
119
|
+
_removed = false;
|
|
120
|
+
_execInSandbox;
|
|
121
|
+
_removeSandbox;
|
|
122
|
+
_getSandbox;
|
|
123
|
+
/** @internal */
|
|
124
|
+
constructor(name, execInSandbox, removeSandbox, getSandbox) {
|
|
125
|
+
this.name = name;
|
|
126
|
+
this._execInSandbox = execInSandbox;
|
|
127
|
+
this._removeSandbox = removeSandbox;
|
|
128
|
+
this._getSandbox = getSandbox;
|
|
129
|
+
}
|
|
130
|
+
/** Run a command in this sandbox. */
|
|
131
|
+
async run(command) {
|
|
132
|
+
return this._execInSandbox(this.name, command);
|
|
133
|
+
}
|
|
134
|
+
/** Get sandbox info. */
|
|
135
|
+
async info() {
|
|
136
|
+
return this._getSandbox(this.name);
|
|
137
|
+
}
|
|
138
|
+
/** Remove the sandbox. Idempotent. */
|
|
139
|
+
async remove() {
|
|
140
|
+
if (this._removed) return;
|
|
141
|
+
this._removed = true;
|
|
142
|
+
await this._removeSandbox(this.name);
|
|
143
|
+
}
|
|
144
|
+
/** Auto-cleanup for `await using`. */
|
|
145
|
+
async [Symbol.asyncDispose]() {
|
|
146
|
+
await this.remove();
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
// src/sse.ts
|
|
151
|
+
var import_eventsource_parser = require("eventsource-parser");
|
|
152
|
+
var KNOWN_EVENTS = /* @__PURE__ */ new Set(["started", "progress", "output", "done", "error"]);
|
|
153
|
+
function pushEvent(state, event) {
|
|
154
|
+
state.events.push(event);
|
|
155
|
+
if (state.resolve) {
|
|
156
|
+
const cb = state.resolve;
|
|
157
|
+
state.resolve = null;
|
|
158
|
+
cb();
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
async function* parseSSE(body) {
|
|
162
|
+
const reader = body.getReader();
|
|
163
|
+
const decoder = new TextDecoder();
|
|
164
|
+
const state = { events: [], resolve: null, done: false };
|
|
165
|
+
const parser = (0, import_eventsource_parser.createParser)({
|
|
166
|
+
onEvent(event) {
|
|
167
|
+
const type = event.event ?? "message";
|
|
168
|
+
if (!KNOWN_EVENTS.has(type)) return;
|
|
169
|
+
let data;
|
|
170
|
+
try {
|
|
171
|
+
data = JSON.parse(event.data);
|
|
172
|
+
} catch {
|
|
173
|
+
data = { raw: event.data };
|
|
174
|
+
}
|
|
175
|
+
pushEvent(state, { type, data });
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
const pump = (async () => {
|
|
179
|
+
try {
|
|
180
|
+
for (; ; ) {
|
|
181
|
+
const result = await reader.read();
|
|
182
|
+
if (result.done) break;
|
|
183
|
+
parser.feed(decoder.decode(result.value, { stream: true }));
|
|
184
|
+
}
|
|
185
|
+
} catch (err) {
|
|
186
|
+
pushEvent(state, {
|
|
187
|
+
type: "error",
|
|
188
|
+
data: { message: err instanceof Error ? err.message : String(err) }
|
|
189
|
+
});
|
|
190
|
+
} finally {
|
|
191
|
+
state.done = true;
|
|
192
|
+
if (state.resolve) {
|
|
193
|
+
const cb = state.resolve;
|
|
194
|
+
state.resolve = null;
|
|
195
|
+
cb();
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
})();
|
|
199
|
+
try {
|
|
200
|
+
for (; ; ) {
|
|
201
|
+
while (state.events.length > 0) {
|
|
202
|
+
const event = state.events.shift();
|
|
203
|
+
yield event;
|
|
204
|
+
if (event.type === "done" || event.type === "error") return;
|
|
205
|
+
}
|
|
206
|
+
if (state.done) return;
|
|
207
|
+
await new Promise((r) => {
|
|
208
|
+
state.resolve = r;
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
} finally {
|
|
212
|
+
reader.cancel().catch(() => {
|
|
213
|
+
});
|
|
214
|
+
await pump.catch(() => {
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// src/client.ts
|
|
220
|
+
var SDK_VERSION = "0.1.0";
|
|
221
|
+
var AgentKernel = class {
|
|
222
|
+
baseUrl;
|
|
223
|
+
apiKey;
|
|
224
|
+
timeout;
|
|
225
|
+
constructor(opts) {
|
|
226
|
+
const config = resolveConfig(opts);
|
|
227
|
+
this.baseUrl = config.baseUrl;
|
|
228
|
+
this.apiKey = config.apiKey;
|
|
229
|
+
this.timeout = config.timeout;
|
|
230
|
+
}
|
|
231
|
+
// -- Core API methods --
|
|
232
|
+
/** Health check. Returns "ok" if the server is running. */
|
|
233
|
+
async health() {
|
|
234
|
+
const res = await this.request("GET", "/health");
|
|
235
|
+
return res;
|
|
236
|
+
}
|
|
237
|
+
/** Run a command in a temporary sandbox. */
|
|
238
|
+
async run(command, opts) {
|
|
239
|
+
return this.request("POST", "/run", {
|
|
240
|
+
command,
|
|
241
|
+
image: opts?.image,
|
|
242
|
+
profile: opts?.profile,
|
|
243
|
+
fast: opts?.fast ?? true
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Run a command with SSE streaming output.
|
|
248
|
+
*
|
|
249
|
+
* @example
|
|
250
|
+
* ```ts
|
|
251
|
+
* for await (const event of client.runStream(["python3", "script.py"])) {
|
|
252
|
+
* if (event.type === "output") process.stdout.write(String(event.data.data));
|
|
253
|
+
* }
|
|
254
|
+
* ```
|
|
255
|
+
*/
|
|
256
|
+
async *runStream(command, opts) {
|
|
257
|
+
const body = JSON.stringify({
|
|
258
|
+
command,
|
|
259
|
+
image: opts?.image,
|
|
260
|
+
profile: opts?.profile,
|
|
261
|
+
fast: opts?.fast ?? true
|
|
262
|
+
});
|
|
263
|
+
const response = await this.fetch("/run/stream", {
|
|
264
|
+
method: "POST",
|
|
265
|
+
headers: this.headers("application/json"),
|
|
266
|
+
body
|
|
267
|
+
});
|
|
268
|
+
if (!response.ok) {
|
|
269
|
+
const text = await response.text();
|
|
270
|
+
throw errorFromStatus(response.status, text);
|
|
271
|
+
}
|
|
272
|
+
if (!response.body) {
|
|
273
|
+
throw new AgentKernelError("No response body for SSE stream");
|
|
274
|
+
}
|
|
275
|
+
yield* parseSSE(response.body);
|
|
276
|
+
}
|
|
277
|
+
/** List all sandboxes. */
|
|
278
|
+
async listSandboxes() {
|
|
279
|
+
return this.request("GET", "/sandboxes");
|
|
280
|
+
}
|
|
281
|
+
/** Create a new sandbox. */
|
|
282
|
+
async createSandbox(name, opts) {
|
|
283
|
+
return this.request("POST", "/sandboxes", {
|
|
284
|
+
name,
|
|
285
|
+
image: opts?.image
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
/** Get info about a sandbox. */
|
|
289
|
+
async getSandbox(name) {
|
|
290
|
+
return this.request("GET", `/sandboxes/${encodeURIComponent(name)}`);
|
|
291
|
+
}
|
|
292
|
+
/** Remove a sandbox. */
|
|
293
|
+
async removeSandbox(name) {
|
|
294
|
+
await this.request("DELETE", `/sandboxes/${encodeURIComponent(name)}`);
|
|
295
|
+
}
|
|
296
|
+
/** Run a command in an existing sandbox. */
|
|
297
|
+
async execInSandbox(name, command) {
|
|
298
|
+
return this.request(
|
|
299
|
+
"POST",
|
|
300
|
+
`/sandboxes/${encodeURIComponent(name)}/exec`,
|
|
301
|
+
{ command }
|
|
302
|
+
);
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* Create a sandbox session with automatic cleanup.
|
|
306
|
+
*
|
|
307
|
+
* The returned SandboxSession implements AsyncDisposable,
|
|
308
|
+
* so it works with `await using` (TS 5.2+):
|
|
309
|
+
*
|
|
310
|
+
* @example
|
|
311
|
+
* ```ts
|
|
312
|
+
* await using sb = await client.sandbox("test", { image: "python:3.12-alpine" });
|
|
313
|
+
* await sb.run(["pip", "install", "numpy"]);
|
|
314
|
+
* // sandbox auto-removed when scope exits
|
|
315
|
+
* ```
|
|
316
|
+
*/
|
|
317
|
+
async sandbox(name, opts) {
|
|
318
|
+
await this.createSandbox(name, opts);
|
|
319
|
+
return new SandboxSession(
|
|
320
|
+
name,
|
|
321
|
+
(n, cmd) => this.execInSandbox(n, cmd),
|
|
322
|
+
(n) => this.removeSandbox(n),
|
|
323
|
+
(n) => this.getSandbox(n)
|
|
324
|
+
);
|
|
325
|
+
}
|
|
326
|
+
// -- Internal helpers --
|
|
327
|
+
headers(contentType) {
|
|
328
|
+
const h = {
|
|
329
|
+
"User-Agent": `agentkernel-nodejs-sdk/${SDK_VERSION}`
|
|
330
|
+
};
|
|
331
|
+
if (contentType) h["Content-Type"] = contentType;
|
|
332
|
+
if (this.apiKey) h["Authorization"] = `Bearer ${this.apiKey}`;
|
|
333
|
+
return h;
|
|
334
|
+
}
|
|
335
|
+
async fetch(path, init) {
|
|
336
|
+
const url = `${this.baseUrl}${path}`;
|
|
337
|
+
try {
|
|
338
|
+
return await fetch(url, {
|
|
339
|
+
...init,
|
|
340
|
+
signal: AbortSignal.timeout(this.timeout)
|
|
341
|
+
});
|
|
342
|
+
} catch (err) {
|
|
343
|
+
if (err instanceof DOMException && err.name === "TimeoutError") {
|
|
344
|
+
throw new NetworkError(`Request timed out after ${this.timeout}ms`);
|
|
345
|
+
}
|
|
346
|
+
if (err instanceof TypeError) {
|
|
347
|
+
throw new NetworkError(`Failed to connect to ${this.baseUrl}: ${err.message}`);
|
|
348
|
+
}
|
|
349
|
+
throw new NetworkError(
|
|
350
|
+
err instanceof Error ? err.message : String(err)
|
|
351
|
+
);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
async request(method, path, body) {
|
|
355
|
+
const init = {
|
|
356
|
+
method,
|
|
357
|
+
headers: this.headers(body ? "application/json" : void 0)
|
|
358
|
+
};
|
|
359
|
+
if (body) init.body = JSON.stringify(body);
|
|
360
|
+
const response = await this.fetch(path, init);
|
|
361
|
+
const text = await response.text();
|
|
362
|
+
if (!response.ok) {
|
|
363
|
+
throw errorFromStatus(response.status, text);
|
|
364
|
+
}
|
|
365
|
+
const parsed = JSON.parse(text);
|
|
366
|
+
if (!parsed.success) {
|
|
367
|
+
throw new AgentKernelError(parsed.error ?? "Unknown error");
|
|
368
|
+
}
|
|
369
|
+
return parsed.data;
|
|
370
|
+
}
|
|
371
|
+
};
|
|
372
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
373
|
+
0 && (module.exports = {
|
|
374
|
+
AgentKernel,
|
|
375
|
+
AgentKernelError,
|
|
376
|
+
AuthError,
|
|
377
|
+
NetworkError,
|
|
378
|
+
NotFoundError,
|
|
379
|
+
SandboxSession,
|
|
380
|
+
ServerError,
|
|
381
|
+
StreamError,
|
|
382
|
+
ValidationError
|
|
383
|
+
});
|
|
384
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/config.ts","../src/errors.ts","../src/sandbox.ts","../src/sse.ts","../src/client.ts"],"sourcesContent":["export { AgentKernel } from \"./client.js\";\nexport { SandboxSession } from \"./sandbox.js\";\nexport {\n AgentKernelError,\n AuthError,\n NotFoundError,\n ValidationError,\n ServerError,\n NetworkError,\n StreamError,\n} from \"./errors.js\";\nexport type {\n AgentKernelOptions,\n RunOptions,\n CreateSandboxOptions,\n RunOutput,\n SandboxInfo,\n StreamEvent,\n StreamEventType,\n SecurityProfile,\n SandboxStatus,\n ApiResponse,\n} from \"./types.js\";\n","import type { AgentKernelOptions } from \"./types.js\";\n\nconst DEFAULT_BASE_URL = \"http://localhost:18888\";\nconst DEFAULT_TIMEOUT = 30_000;\n\n/** Resolve configuration from constructor args, env vars, and defaults. */\nexport function resolveConfig(opts?: AgentKernelOptions) {\n const baseUrl =\n opts?.baseUrl ??\n process.env.AGENTKERNEL_BASE_URL ??\n DEFAULT_BASE_URL;\n\n const apiKey =\n opts?.apiKey ??\n process.env.AGENTKERNEL_API_KEY ??\n undefined;\n\n const timeout = opts?.timeout ?? DEFAULT_TIMEOUT;\n\n return {\n baseUrl: baseUrl.replace(/\\/+$/, \"\"),\n apiKey,\n timeout,\n };\n}\n","/** Base error for all agentkernel SDK errors. */\nexport class AgentKernelError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"AgentKernelError\";\n }\n}\n\n/** 401 Unauthorized. */\nexport class AuthError extends AgentKernelError {\n readonly status = 401;\n constructor(message = \"Unauthorized\") {\n super(message);\n this.name = \"AuthError\";\n }\n}\n\n/** 404 Not Found. */\nexport class NotFoundError extends AgentKernelError {\n readonly status = 404;\n constructor(message = \"Not found\") {\n super(message);\n this.name = \"NotFoundError\";\n }\n}\n\n/** 400 Bad Request. */\nexport class ValidationError extends AgentKernelError {\n readonly status = 400;\n constructor(message = \"Bad request\") {\n super(message);\n this.name = \"ValidationError\";\n }\n}\n\n/** 500 Internal Server Error. */\nexport class ServerError extends AgentKernelError {\n readonly status = 500;\n constructor(message = \"Internal server error\") {\n super(message);\n this.name = \"ServerError\";\n }\n}\n\n/** Network / connection error. */\nexport class NetworkError extends AgentKernelError {\n constructor(message = \"Network error\") {\n super(message);\n this.name = \"NetworkError\";\n }\n}\n\n/** SSE streaming error. */\nexport class StreamError extends AgentKernelError {\n constructor(message = \"Stream error\") {\n super(message);\n this.name = \"StreamError\";\n }\n}\n\n/** Map an HTTP status code + body to the appropriate error. */\nexport function errorFromStatus(status: number, body: string): AgentKernelError {\n let message: string;\n try {\n const parsed = JSON.parse(body);\n message = parsed.error ?? body;\n } catch {\n message = body;\n }\n\n switch (status) {\n case 400:\n return new ValidationError(message);\n case 401:\n return new AuthError(message);\n case 404:\n return new NotFoundError(message);\n default:\n return new ServerError(message);\n }\n}\n","import type { RunOutput, SandboxInfo } from \"./types.js\";\n\ntype ExecFn = (name: string, command: string[]) => Promise<RunOutput>;\ntype RemoveFn = (name: string) => Promise<void>;\ntype GetFn = (name: string) => Promise<SandboxInfo>;\n\n/**\n * A sandbox session that auto-removes the sandbox on dispose.\n *\n * Supports both explicit cleanup via remove() and automatic cleanup via\n * Symbol.asyncDispose (TS 5.2+ `await using`).\n *\n * @example\n * ```ts\n * await using sb = await client.sandbox(\"test\");\n * await sb.exec([\"echo\", \"hello\"]);\n * // sandbox auto-removed when scope exits\n * ```\n */\nexport class SandboxSession implements AsyncDisposable {\n readonly name: string;\n private _removed = false;\n private readonly _execInSandbox: ExecFn;\n private readonly _removeSandbox: RemoveFn;\n private readonly _getSandbox: GetFn;\n\n /** @internal */\n constructor(\n name: string,\n execInSandbox: ExecFn,\n removeSandbox: RemoveFn,\n getSandbox: GetFn,\n ) {\n this.name = name;\n this._execInSandbox = execInSandbox;\n this._removeSandbox = removeSandbox;\n this._getSandbox = getSandbox;\n }\n\n /** Run a command in this sandbox. */\n async run(command: string[]): Promise<RunOutput> {\n return this._execInSandbox(this.name, command);\n }\n\n /** Get sandbox info. */\n async info(): Promise<SandboxInfo> {\n return this._getSandbox(this.name);\n }\n\n /** Remove the sandbox. Idempotent. */\n async remove(): Promise<void> {\n if (this._removed) return;\n this._removed = true;\n await this._removeSandbox(this.name);\n }\n\n /** Auto-cleanup for `await using`. */\n async [Symbol.asyncDispose](): Promise<void> {\n await this.remove();\n }\n}\n","import { createParser, type EventSourceMessage } from \"eventsource-parser\";\nimport type { StreamEvent, StreamEventType } from \"./types.js\";\n\nconst KNOWN_EVENTS = new Set<string>([\"started\", \"progress\", \"output\", \"done\", \"error\"]);\n\n/** Shared mutable state between the pump and the generator. */\ninterface PumpState {\n events: StreamEvent[];\n resolve: (() => void) | null;\n done: boolean;\n}\n\nfunction pushEvent(state: PumpState, event: StreamEvent): void {\n state.events.push(event);\n if (state.resolve) {\n const cb = state.resolve;\n state.resolve = null;\n cb();\n }\n}\n\n/**\n * Parse an SSE response body into an async generator of StreamEvents.\n *\n * Consumes a ReadableStream<Uint8Array> from fetch() and yields typed events\n * until the stream closes or a \"done\"/\"error\" event is received.\n */\nexport async function* parseSSE(\n body: ReadableStream<Uint8Array>,\n): AsyncGenerator<StreamEvent> {\n const reader = body.getReader();\n const decoder = new TextDecoder();\n const state: PumpState = { events: [], resolve: null, done: false };\n\n const parser = createParser({\n onEvent(event: EventSourceMessage) {\n const type = event.event ?? \"message\";\n if (!KNOWN_EVENTS.has(type)) return;\n\n let data: Record<string, unknown>;\n try {\n data = JSON.parse(event.data);\n } catch {\n data = { raw: event.data };\n }\n\n pushEvent(state, { type: type as StreamEventType, data });\n },\n });\n\n // Read the stream in the background\n const pump = (async () => {\n try {\n for (;;) {\n const result = await reader.read();\n if (result.done) break;\n parser.feed(decoder.decode(result.value, { stream: true }));\n }\n } catch (err) {\n pushEvent(state, {\n type: \"error\",\n data: { message: err instanceof Error ? err.message : String(err) },\n });\n } finally {\n state.done = true;\n if (state.resolve) {\n const cb = state.resolve;\n state.resolve = null;\n cb();\n }\n }\n })();\n\n try {\n for (;;) {\n // Yield all buffered events\n while (state.events.length > 0) {\n const event = state.events.shift()!;\n yield event;\n if (event.type === \"done\" || event.type === \"error\") return;\n }\n\n // If the stream is done and no more events, exit\n if (state.done) return;\n\n // Wait for the next event\n await new Promise<void>((r) => {\n state.resolve = r;\n });\n }\n } finally {\n reader.cancel().catch(() => {});\n await pump.catch(() => {});\n }\n}\n","import { resolveConfig } from \"./config.js\";\nimport {\n AgentKernelError,\n NetworkError,\n errorFromStatus,\n} from \"./errors.js\";\nimport { SandboxSession } from \"./sandbox.js\";\nimport { parseSSE } from \"./sse.js\";\nimport type {\n AgentKernelOptions,\n ApiResponse,\n CreateSandboxOptions,\n RunOptions,\n RunOutput,\n SandboxInfo,\n StreamEvent,\n} from \"./types.js\";\n\nconst SDK_VERSION = \"0.1.0\";\n\n/**\n * Client for the agentkernel HTTP API.\n *\n * @example\n * ```ts\n * const client = new AgentKernel();\n * const result = await client.run([\"echo\", \"hello\"]);\n * console.log(result.output); // \"hello\\n\"\n * ```\n */\nexport class AgentKernel {\n private readonly baseUrl: string;\n private readonly apiKey: string | undefined;\n private readonly timeout: number;\n\n constructor(opts?: AgentKernelOptions) {\n const config = resolveConfig(opts);\n this.baseUrl = config.baseUrl;\n this.apiKey = config.apiKey;\n this.timeout = config.timeout;\n }\n\n // -- Core API methods --\n\n /** Health check. Returns \"ok\" if the server is running. */\n async health(): Promise<string> {\n const res = await this.request<string>(\"GET\", \"/health\");\n return res;\n }\n\n /** Run a command in a temporary sandbox. */\n async run(command: string[], opts?: RunOptions): Promise<RunOutput> {\n return this.request<RunOutput>(\"POST\", \"/run\", {\n command,\n image: opts?.image,\n profile: opts?.profile,\n fast: opts?.fast ?? true,\n });\n }\n\n /**\n * Run a command with SSE streaming output.\n *\n * @example\n * ```ts\n * for await (const event of client.runStream([\"python3\", \"script.py\"])) {\n * if (event.type === \"output\") process.stdout.write(String(event.data.data));\n * }\n * ```\n */\n async *runStream(\n command: string[],\n opts?: RunOptions,\n ): AsyncGenerator<StreamEvent> {\n const body = JSON.stringify({\n command,\n image: opts?.image,\n profile: opts?.profile,\n fast: opts?.fast ?? true,\n });\n\n const response = await this.fetch(\"/run/stream\", {\n method: \"POST\",\n headers: this.headers(\"application/json\"),\n body,\n });\n\n if (!response.ok) {\n const text = await response.text();\n throw errorFromStatus(response.status, text);\n }\n\n if (!response.body) {\n throw new AgentKernelError(\"No response body for SSE stream\");\n }\n\n yield* parseSSE(response.body);\n }\n\n /** List all sandboxes. */\n async listSandboxes(): Promise<SandboxInfo[]> {\n return this.request<SandboxInfo[]>(\"GET\", \"/sandboxes\");\n }\n\n /** Create a new sandbox. */\n async createSandbox(\n name: string,\n opts?: CreateSandboxOptions,\n ): Promise<SandboxInfo> {\n return this.request<SandboxInfo>(\"POST\", \"/sandboxes\", {\n name,\n image: opts?.image,\n });\n }\n\n /** Get info about a sandbox. */\n async getSandbox(name: string): Promise<SandboxInfo> {\n return this.request<SandboxInfo>(\"GET\", `/sandboxes/${encodeURIComponent(name)}`);\n }\n\n /** Remove a sandbox. */\n async removeSandbox(name: string): Promise<void> {\n await this.request<string>(\"DELETE\", `/sandboxes/${encodeURIComponent(name)}`);\n }\n\n /** Run a command in an existing sandbox. */\n async execInSandbox(name: string, command: string[]): Promise<RunOutput> {\n return this.request<RunOutput>(\n \"POST\",\n `/sandboxes/${encodeURIComponent(name)}/exec`,\n { command },\n );\n }\n\n /**\n * Create a sandbox session with automatic cleanup.\n *\n * The returned SandboxSession implements AsyncDisposable,\n * so it works with `await using` (TS 5.2+):\n *\n * @example\n * ```ts\n * await using sb = await client.sandbox(\"test\", { image: \"python:3.12-alpine\" });\n * await sb.run([\"pip\", \"install\", \"numpy\"]);\n * // sandbox auto-removed when scope exits\n * ```\n */\n async sandbox(\n name: string,\n opts?: CreateSandboxOptions,\n ): Promise<SandboxSession> {\n await this.createSandbox(name, opts);\n return new SandboxSession(\n name,\n (n, cmd) => this.execInSandbox(n, cmd),\n (n) => this.removeSandbox(n),\n (n) => this.getSandbox(n),\n );\n }\n\n // -- Internal helpers --\n\n private headers(contentType?: string): Record<string, string> {\n const h: Record<string, string> = {\n \"User-Agent\": `agentkernel-nodejs-sdk/${SDK_VERSION}`,\n };\n if (contentType) h[\"Content-Type\"] = contentType;\n if (this.apiKey) h[\"Authorization\"] = `Bearer ${this.apiKey}`;\n return h;\n }\n\n private async fetch(path: string, init: RequestInit): Promise<Response> {\n const url = `${this.baseUrl}${path}`;\n try {\n return await fetch(url, {\n ...init,\n signal: AbortSignal.timeout(this.timeout),\n });\n } catch (err) {\n if (err instanceof DOMException && err.name === \"TimeoutError\") {\n throw new NetworkError(`Request timed out after ${this.timeout}ms`);\n }\n if (err instanceof TypeError) {\n throw new NetworkError(`Failed to connect to ${this.baseUrl}: ${err.message}`);\n }\n throw new NetworkError(\n err instanceof Error ? err.message : String(err),\n );\n }\n }\n\n private async request<T>(\n method: string,\n path: string,\n body?: unknown,\n ): Promise<T> {\n const init: RequestInit = {\n method,\n headers: this.headers(body ? \"application/json\" : undefined),\n };\n if (body) init.body = JSON.stringify(body);\n\n const response = await this.fetch(path, init);\n\n const text = await response.text();\n if (!response.ok) {\n throw errorFromStatus(response.status, text);\n }\n\n const parsed: ApiResponse<T> = JSON.parse(text);\n if (!parsed.success) {\n throw new AgentKernelError(parsed.error ?? \"Unknown error\");\n }\n return parsed.data as T;\n }\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
/** Security profile for sandbox execution. */
|
|
2
|
+
type SecurityProfile = "permissive" | "moderate" | "restrictive";
|
|
3
|
+
/** Sandbox status. */
|
|
4
|
+
type SandboxStatus = "running" | "stopped";
|
|
5
|
+
/** SSE event types emitted by /run/stream. */
|
|
6
|
+
type StreamEventType = "started" | "progress" | "output" | "done" | "error";
|
|
7
|
+
/** Configuration options for the AgentKernel client. */
|
|
8
|
+
interface AgentKernelOptions {
|
|
9
|
+
/** Base URL of the agentkernel HTTP API. Default: AGENTKERNEL_BASE_URL or http://localhost:18888 */
|
|
10
|
+
baseUrl?: string;
|
|
11
|
+
/** API key for Bearer authentication. Default: AGENTKERNEL_API_KEY env var */
|
|
12
|
+
apiKey?: string;
|
|
13
|
+
/** Request timeout in milliseconds. Default: 30000 */
|
|
14
|
+
timeout?: number;
|
|
15
|
+
}
|
|
16
|
+
/** Options for the run command. */
|
|
17
|
+
interface RunOptions {
|
|
18
|
+
/** Docker image to use (auto-detected if not specified). */
|
|
19
|
+
image?: string;
|
|
20
|
+
/** Security profile. Default: moderate */
|
|
21
|
+
profile?: SecurityProfile;
|
|
22
|
+
/** Use container pool for faster execution. Default: true */
|
|
23
|
+
fast?: boolean;
|
|
24
|
+
}
|
|
25
|
+
/** Options for creating a sandbox. */
|
|
26
|
+
interface CreateSandboxOptions {
|
|
27
|
+
/** Docker image to use. Default: alpine:3.20 */
|
|
28
|
+
image?: string;
|
|
29
|
+
}
|
|
30
|
+
/** Output from a command execution. */
|
|
31
|
+
interface RunOutput {
|
|
32
|
+
output: string;
|
|
33
|
+
}
|
|
34
|
+
/** Information about a sandbox. */
|
|
35
|
+
interface SandboxInfo {
|
|
36
|
+
name: string;
|
|
37
|
+
status: SandboxStatus;
|
|
38
|
+
backend: string;
|
|
39
|
+
}
|
|
40
|
+
/** SSE stream event. */
|
|
41
|
+
interface StreamEvent {
|
|
42
|
+
type: StreamEventType;
|
|
43
|
+
data: Record<string, unknown>;
|
|
44
|
+
}
|
|
45
|
+
/** API response wrapper. */
|
|
46
|
+
interface ApiResponse<T> {
|
|
47
|
+
success: boolean;
|
|
48
|
+
data?: T;
|
|
49
|
+
error?: string;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
type ExecFn = (name: string, command: string[]) => Promise<RunOutput>;
|
|
53
|
+
type RemoveFn = (name: string) => Promise<void>;
|
|
54
|
+
type GetFn = (name: string) => Promise<SandboxInfo>;
|
|
55
|
+
/**
|
|
56
|
+
* A sandbox session that auto-removes the sandbox on dispose.
|
|
57
|
+
*
|
|
58
|
+
* Supports both explicit cleanup via remove() and automatic cleanup via
|
|
59
|
+
* Symbol.asyncDispose (TS 5.2+ `await using`).
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* ```ts
|
|
63
|
+
* await using sb = await client.sandbox("test");
|
|
64
|
+
* await sb.exec(["echo", "hello"]);
|
|
65
|
+
* // sandbox auto-removed when scope exits
|
|
66
|
+
* ```
|
|
67
|
+
*/
|
|
68
|
+
declare class SandboxSession implements AsyncDisposable {
|
|
69
|
+
readonly name: string;
|
|
70
|
+
private _removed;
|
|
71
|
+
private readonly _execInSandbox;
|
|
72
|
+
private readonly _removeSandbox;
|
|
73
|
+
private readonly _getSandbox;
|
|
74
|
+
/** @internal */
|
|
75
|
+
constructor(name: string, execInSandbox: ExecFn, removeSandbox: RemoveFn, getSandbox: GetFn);
|
|
76
|
+
/** Run a command in this sandbox. */
|
|
77
|
+
run(command: string[]): Promise<RunOutput>;
|
|
78
|
+
/** Get sandbox info. */
|
|
79
|
+
info(): Promise<SandboxInfo>;
|
|
80
|
+
/** Remove the sandbox. Idempotent. */
|
|
81
|
+
remove(): Promise<void>;
|
|
82
|
+
/** Auto-cleanup for `await using`. */
|
|
83
|
+
[Symbol.asyncDispose](): Promise<void>;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Client for the agentkernel HTTP API.
|
|
88
|
+
*
|
|
89
|
+
* @example
|
|
90
|
+
* ```ts
|
|
91
|
+
* const client = new AgentKernel();
|
|
92
|
+
* const result = await client.run(["echo", "hello"]);
|
|
93
|
+
* console.log(result.output); // "hello\n"
|
|
94
|
+
* ```
|
|
95
|
+
*/
|
|
96
|
+
declare class AgentKernel {
|
|
97
|
+
private readonly baseUrl;
|
|
98
|
+
private readonly apiKey;
|
|
99
|
+
private readonly timeout;
|
|
100
|
+
constructor(opts?: AgentKernelOptions);
|
|
101
|
+
/** Health check. Returns "ok" if the server is running. */
|
|
102
|
+
health(): Promise<string>;
|
|
103
|
+
/** Run a command in a temporary sandbox. */
|
|
104
|
+
run(command: string[], opts?: RunOptions): Promise<RunOutput>;
|
|
105
|
+
/**
|
|
106
|
+
* Run a command with SSE streaming output.
|
|
107
|
+
*
|
|
108
|
+
* @example
|
|
109
|
+
* ```ts
|
|
110
|
+
* for await (const event of client.runStream(["python3", "script.py"])) {
|
|
111
|
+
* if (event.type === "output") process.stdout.write(String(event.data.data));
|
|
112
|
+
* }
|
|
113
|
+
* ```
|
|
114
|
+
*/
|
|
115
|
+
runStream(command: string[], opts?: RunOptions): AsyncGenerator<StreamEvent>;
|
|
116
|
+
/** List all sandboxes. */
|
|
117
|
+
listSandboxes(): Promise<SandboxInfo[]>;
|
|
118
|
+
/** Create a new sandbox. */
|
|
119
|
+
createSandbox(name: string, opts?: CreateSandboxOptions): Promise<SandboxInfo>;
|
|
120
|
+
/** Get info about a sandbox. */
|
|
121
|
+
getSandbox(name: string): Promise<SandboxInfo>;
|
|
122
|
+
/** Remove a sandbox. */
|
|
123
|
+
removeSandbox(name: string): Promise<void>;
|
|
124
|
+
/** Run a command in an existing sandbox. */
|
|
125
|
+
execInSandbox(name: string, command: string[]): Promise<RunOutput>;
|
|
126
|
+
/**
|
|
127
|
+
* Create a sandbox session with automatic cleanup.
|
|
128
|
+
*
|
|
129
|
+
* The returned SandboxSession implements AsyncDisposable,
|
|
130
|
+
* so it works with `await using` (TS 5.2+):
|
|
131
|
+
*
|
|
132
|
+
* @example
|
|
133
|
+
* ```ts
|
|
134
|
+
* await using sb = await client.sandbox("test", { image: "python:3.12-alpine" });
|
|
135
|
+
* await sb.run(["pip", "install", "numpy"]);
|
|
136
|
+
* // sandbox auto-removed when scope exits
|
|
137
|
+
* ```
|
|
138
|
+
*/
|
|
139
|
+
sandbox(name: string, opts?: CreateSandboxOptions): Promise<SandboxSession>;
|
|
140
|
+
private headers;
|
|
141
|
+
private fetch;
|
|
142
|
+
private request;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/** Base error for all agentkernel SDK errors. */
|
|
146
|
+
declare class AgentKernelError extends Error {
|
|
147
|
+
constructor(message: string);
|
|
148
|
+
}
|
|
149
|
+
/** 401 Unauthorized. */
|
|
150
|
+
declare class AuthError extends AgentKernelError {
|
|
151
|
+
readonly status = 401;
|
|
152
|
+
constructor(message?: string);
|
|
153
|
+
}
|
|
154
|
+
/** 404 Not Found. */
|
|
155
|
+
declare class NotFoundError extends AgentKernelError {
|
|
156
|
+
readonly status = 404;
|
|
157
|
+
constructor(message?: string);
|
|
158
|
+
}
|
|
159
|
+
/** 400 Bad Request. */
|
|
160
|
+
declare class ValidationError extends AgentKernelError {
|
|
161
|
+
readonly status = 400;
|
|
162
|
+
constructor(message?: string);
|
|
163
|
+
}
|
|
164
|
+
/** 500 Internal Server Error. */
|
|
165
|
+
declare class ServerError extends AgentKernelError {
|
|
166
|
+
readonly status = 500;
|
|
167
|
+
constructor(message?: string);
|
|
168
|
+
}
|
|
169
|
+
/** Network / connection error. */
|
|
170
|
+
declare class NetworkError extends AgentKernelError {
|
|
171
|
+
constructor(message?: string);
|
|
172
|
+
}
|
|
173
|
+
/** SSE streaming error. */
|
|
174
|
+
declare class StreamError extends AgentKernelError {
|
|
175
|
+
constructor(message?: string);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export { AgentKernel, AgentKernelError, type AgentKernelOptions, type ApiResponse, AuthError, type CreateSandboxOptions, NetworkError, NotFoundError, type RunOptions, type RunOutput, type SandboxInfo, SandboxSession, type SandboxStatus, type SecurityProfile, ServerError, StreamError, type StreamEvent, type StreamEventType, ValidationError };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
/** Security profile for sandbox execution. */
|
|
2
|
+
type SecurityProfile = "permissive" | "moderate" | "restrictive";
|
|
3
|
+
/** Sandbox status. */
|
|
4
|
+
type SandboxStatus = "running" | "stopped";
|
|
5
|
+
/** SSE event types emitted by /run/stream. */
|
|
6
|
+
type StreamEventType = "started" | "progress" | "output" | "done" | "error";
|
|
7
|
+
/** Configuration options for the AgentKernel client. */
|
|
8
|
+
interface AgentKernelOptions {
|
|
9
|
+
/** Base URL of the agentkernel HTTP API. Default: AGENTKERNEL_BASE_URL or http://localhost:18888 */
|
|
10
|
+
baseUrl?: string;
|
|
11
|
+
/** API key for Bearer authentication. Default: AGENTKERNEL_API_KEY env var */
|
|
12
|
+
apiKey?: string;
|
|
13
|
+
/** Request timeout in milliseconds. Default: 30000 */
|
|
14
|
+
timeout?: number;
|
|
15
|
+
}
|
|
16
|
+
/** Options for the run command. */
|
|
17
|
+
interface RunOptions {
|
|
18
|
+
/** Docker image to use (auto-detected if not specified). */
|
|
19
|
+
image?: string;
|
|
20
|
+
/** Security profile. Default: moderate */
|
|
21
|
+
profile?: SecurityProfile;
|
|
22
|
+
/** Use container pool for faster execution. Default: true */
|
|
23
|
+
fast?: boolean;
|
|
24
|
+
}
|
|
25
|
+
/** Options for creating a sandbox. */
|
|
26
|
+
interface CreateSandboxOptions {
|
|
27
|
+
/** Docker image to use. Default: alpine:3.20 */
|
|
28
|
+
image?: string;
|
|
29
|
+
}
|
|
30
|
+
/** Output from a command execution. */
|
|
31
|
+
interface RunOutput {
|
|
32
|
+
output: string;
|
|
33
|
+
}
|
|
34
|
+
/** Information about a sandbox. */
|
|
35
|
+
interface SandboxInfo {
|
|
36
|
+
name: string;
|
|
37
|
+
status: SandboxStatus;
|
|
38
|
+
backend: string;
|
|
39
|
+
}
|
|
40
|
+
/** SSE stream event. */
|
|
41
|
+
interface StreamEvent {
|
|
42
|
+
type: StreamEventType;
|
|
43
|
+
data: Record<string, unknown>;
|
|
44
|
+
}
|
|
45
|
+
/** API response wrapper. */
|
|
46
|
+
interface ApiResponse<T> {
|
|
47
|
+
success: boolean;
|
|
48
|
+
data?: T;
|
|
49
|
+
error?: string;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
type ExecFn = (name: string, command: string[]) => Promise<RunOutput>;
|
|
53
|
+
type RemoveFn = (name: string) => Promise<void>;
|
|
54
|
+
type GetFn = (name: string) => Promise<SandboxInfo>;
|
|
55
|
+
/**
|
|
56
|
+
* A sandbox session that auto-removes the sandbox on dispose.
|
|
57
|
+
*
|
|
58
|
+
* Supports both explicit cleanup via remove() and automatic cleanup via
|
|
59
|
+
* Symbol.asyncDispose (TS 5.2+ `await using`).
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* ```ts
|
|
63
|
+
* await using sb = await client.sandbox("test");
|
|
64
|
+
* await sb.exec(["echo", "hello"]);
|
|
65
|
+
* // sandbox auto-removed when scope exits
|
|
66
|
+
* ```
|
|
67
|
+
*/
|
|
68
|
+
declare class SandboxSession implements AsyncDisposable {
|
|
69
|
+
readonly name: string;
|
|
70
|
+
private _removed;
|
|
71
|
+
private readonly _execInSandbox;
|
|
72
|
+
private readonly _removeSandbox;
|
|
73
|
+
private readonly _getSandbox;
|
|
74
|
+
/** @internal */
|
|
75
|
+
constructor(name: string, execInSandbox: ExecFn, removeSandbox: RemoveFn, getSandbox: GetFn);
|
|
76
|
+
/** Run a command in this sandbox. */
|
|
77
|
+
run(command: string[]): Promise<RunOutput>;
|
|
78
|
+
/** Get sandbox info. */
|
|
79
|
+
info(): Promise<SandboxInfo>;
|
|
80
|
+
/** Remove the sandbox. Idempotent. */
|
|
81
|
+
remove(): Promise<void>;
|
|
82
|
+
/** Auto-cleanup for `await using`. */
|
|
83
|
+
[Symbol.asyncDispose](): Promise<void>;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Client for the agentkernel HTTP API.
|
|
88
|
+
*
|
|
89
|
+
* @example
|
|
90
|
+
* ```ts
|
|
91
|
+
* const client = new AgentKernel();
|
|
92
|
+
* const result = await client.run(["echo", "hello"]);
|
|
93
|
+
* console.log(result.output); // "hello\n"
|
|
94
|
+
* ```
|
|
95
|
+
*/
|
|
96
|
+
declare class AgentKernel {
|
|
97
|
+
private readonly baseUrl;
|
|
98
|
+
private readonly apiKey;
|
|
99
|
+
private readonly timeout;
|
|
100
|
+
constructor(opts?: AgentKernelOptions);
|
|
101
|
+
/** Health check. Returns "ok" if the server is running. */
|
|
102
|
+
health(): Promise<string>;
|
|
103
|
+
/** Run a command in a temporary sandbox. */
|
|
104
|
+
run(command: string[], opts?: RunOptions): Promise<RunOutput>;
|
|
105
|
+
/**
|
|
106
|
+
* Run a command with SSE streaming output.
|
|
107
|
+
*
|
|
108
|
+
* @example
|
|
109
|
+
* ```ts
|
|
110
|
+
* for await (const event of client.runStream(["python3", "script.py"])) {
|
|
111
|
+
* if (event.type === "output") process.stdout.write(String(event.data.data));
|
|
112
|
+
* }
|
|
113
|
+
* ```
|
|
114
|
+
*/
|
|
115
|
+
runStream(command: string[], opts?: RunOptions): AsyncGenerator<StreamEvent>;
|
|
116
|
+
/** List all sandboxes. */
|
|
117
|
+
listSandboxes(): Promise<SandboxInfo[]>;
|
|
118
|
+
/** Create a new sandbox. */
|
|
119
|
+
createSandbox(name: string, opts?: CreateSandboxOptions): Promise<SandboxInfo>;
|
|
120
|
+
/** Get info about a sandbox. */
|
|
121
|
+
getSandbox(name: string): Promise<SandboxInfo>;
|
|
122
|
+
/** Remove a sandbox. */
|
|
123
|
+
removeSandbox(name: string): Promise<void>;
|
|
124
|
+
/** Run a command in an existing sandbox. */
|
|
125
|
+
execInSandbox(name: string, command: string[]): Promise<RunOutput>;
|
|
126
|
+
/**
|
|
127
|
+
* Create a sandbox session with automatic cleanup.
|
|
128
|
+
*
|
|
129
|
+
* The returned SandboxSession implements AsyncDisposable,
|
|
130
|
+
* so it works with `await using` (TS 5.2+):
|
|
131
|
+
*
|
|
132
|
+
* @example
|
|
133
|
+
* ```ts
|
|
134
|
+
* await using sb = await client.sandbox("test", { image: "python:3.12-alpine" });
|
|
135
|
+
* await sb.run(["pip", "install", "numpy"]);
|
|
136
|
+
* // sandbox auto-removed when scope exits
|
|
137
|
+
* ```
|
|
138
|
+
*/
|
|
139
|
+
sandbox(name: string, opts?: CreateSandboxOptions): Promise<SandboxSession>;
|
|
140
|
+
private headers;
|
|
141
|
+
private fetch;
|
|
142
|
+
private request;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/** Base error for all agentkernel SDK errors. */
|
|
146
|
+
declare class AgentKernelError extends Error {
|
|
147
|
+
constructor(message: string);
|
|
148
|
+
}
|
|
149
|
+
/** 401 Unauthorized. */
|
|
150
|
+
declare class AuthError extends AgentKernelError {
|
|
151
|
+
readonly status = 401;
|
|
152
|
+
constructor(message?: string);
|
|
153
|
+
}
|
|
154
|
+
/** 404 Not Found. */
|
|
155
|
+
declare class NotFoundError extends AgentKernelError {
|
|
156
|
+
readonly status = 404;
|
|
157
|
+
constructor(message?: string);
|
|
158
|
+
}
|
|
159
|
+
/** 400 Bad Request. */
|
|
160
|
+
declare class ValidationError extends AgentKernelError {
|
|
161
|
+
readonly status = 400;
|
|
162
|
+
constructor(message?: string);
|
|
163
|
+
}
|
|
164
|
+
/** 500 Internal Server Error. */
|
|
165
|
+
declare class ServerError extends AgentKernelError {
|
|
166
|
+
readonly status = 500;
|
|
167
|
+
constructor(message?: string);
|
|
168
|
+
}
|
|
169
|
+
/** Network / connection error. */
|
|
170
|
+
declare class NetworkError extends AgentKernelError {
|
|
171
|
+
constructor(message?: string);
|
|
172
|
+
}
|
|
173
|
+
/** SSE streaming error. */
|
|
174
|
+
declare class StreamError extends AgentKernelError {
|
|
175
|
+
constructor(message?: string);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export { AgentKernel, AgentKernelError, type AgentKernelOptions, type ApiResponse, AuthError, type CreateSandboxOptions, NetworkError, NotFoundError, type RunOptions, type RunOutput, type SandboxInfo, SandboxSession, type SandboxStatus, type SecurityProfile, ServerError, StreamError, type StreamEvent, type StreamEventType, ValidationError };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
// src/config.ts
|
|
2
|
+
var DEFAULT_BASE_URL = "http://localhost:18888";
|
|
3
|
+
var DEFAULT_TIMEOUT = 3e4;
|
|
4
|
+
function resolveConfig(opts) {
|
|
5
|
+
const baseUrl = opts?.baseUrl ?? process.env.AGENTKERNEL_BASE_URL ?? DEFAULT_BASE_URL;
|
|
6
|
+
const apiKey = opts?.apiKey ?? process.env.AGENTKERNEL_API_KEY ?? void 0;
|
|
7
|
+
const timeout = opts?.timeout ?? DEFAULT_TIMEOUT;
|
|
8
|
+
return {
|
|
9
|
+
baseUrl: baseUrl.replace(/\/+$/, ""),
|
|
10
|
+
apiKey,
|
|
11
|
+
timeout
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// src/errors.ts
|
|
16
|
+
var AgentKernelError = class extends Error {
|
|
17
|
+
constructor(message) {
|
|
18
|
+
super(message);
|
|
19
|
+
this.name = "AgentKernelError";
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
var AuthError = class extends AgentKernelError {
|
|
23
|
+
status = 401;
|
|
24
|
+
constructor(message = "Unauthorized") {
|
|
25
|
+
super(message);
|
|
26
|
+
this.name = "AuthError";
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
var NotFoundError = class extends AgentKernelError {
|
|
30
|
+
status = 404;
|
|
31
|
+
constructor(message = "Not found") {
|
|
32
|
+
super(message);
|
|
33
|
+
this.name = "NotFoundError";
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
var ValidationError = class extends AgentKernelError {
|
|
37
|
+
status = 400;
|
|
38
|
+
constructor(message = "Bad request") {
|
|
39
|
+
super(message);
|
|
40
|
+
this.name = "ValidationError";
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
var ServerError = class extends AgentKernelError {
|
|
44
|
+
status = 500;
|
|
45
|
+
constructor(message = "Internal server error") {
|
|
46
|
+
super(message);
|
|
47
|
+
this.name = "ServerError";
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
var NetworkError = class extends AgentKernelError {
|
|
51
|
+
constructor(message = "Network error") {
|
|
52
|
+
super(message);
|
|
53
|
+
this.name = "NetworkError";
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
var StreamError = class extends AgentKernelError {
|
|
57
|
+
constructor(message = "Stream error") {
|
|
58
|
+
super(message);
|
|
59
|
+
this.name = "StreamError";
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
function errorFromStatus(status, body) {
|
|
63
|
+
let message;
|
|
64
|
+
try {
|
|
65
|
+
const parsed = JSON.parse(body);
|
|
66
|
+
message = parsed.error ?? body;
|
|
67
|
+
} catch {
|
|
68
|
+
message = body;
|
|
69
|
+
}
|
|
70
|
+
switch (status) {
|
|
71
|
+
case 400:
|
|
72
|
+
return new ValidationError(message);
|
|
73
|
+
case 401:
|
|
74
|
+
return new AuthError(message);
|
|
75
|
+
case 404:
|
|
76
|
+
return new NotFoundError(message);
|
|
77
|
+
default:
|
|
78
|
+
return new ServerError(message);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// src/sandbox.ts
|
|
83
|
+
var SandboxSession = class {
|
|
84
|
+
name;
|
|
85
|
+
_removed = false;
|
|
86
|
+
_execInSandbox;
|
|
87
|
+
_removeSandbox;
|
|
88
|
+
_getSandbox;
|
|
89
|
+
/** @internal */
|
|
90
|
+
constructor(name, execInSandbox, removeSandbox, getSandbox) {
|
|
91
|
+
this.name = name;
|
|
92
|
+
this._execInSandbox = execInSandbox;
|
|
93
|
+
this._removeSandbox = removeSandbox;
|
|
94
|
+
this._getSandbox = getSandbox;
|
|
95
|
+
}
|
|
96
|
+
/** Run a command in this sandbox. */
|
|
97
|
+
async run(command) {
|
|
98
|
+
return this._execInSandbox(this.name, command);
|
|
99
|
+
}
|
|
100
|
+
/** Get sandbox info. */
|
|
101
|
+
async info() {
|
|
102
|
+
return this._getSandbox(this.name);
|
|
103
|
+
}
|
|
104
|
+
/** Remove the sandbox. Idempotent. */
|
|
105
|
+
async remove() {
|
|
106
|
+
if (this._removed) return;
|
|
107
|
+
this._removed = true;
|
|
108
|
+
await this._removeSandbox(this.name);
|
|
109
|
+
}
|
|
110
|
+
/** Auto-cleanup for `await using`. */
|
|
111
|
+
async [Symbol.asyncDispose]() {
|
|
112
|
+
await this.remove();
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
// src/sse.ts
|
|
117
|
+
import { createParser } from "eventsource-parser";
|
|
118
|
+
var KNOWN_EVENTS = /* @__PURE__ */ new Set(["started", "progress", "output", "done", "error"]);
|
|
119
|
+
function pushEvent(state, event) {
|
|
120
|
+
state.events.push(event);
|
|
121
|
+
if (state.resolve) {
|
|
122
|
+
const cb = state.resolve;
|
|
123
|
+
state.resolve = null;
|
|
124
|
+
cb();
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
async function* parseSSE(body) {
|
|
128
|
+
const reader = body.getReader();
|
|
129
|
+
const decoder = new TextDecoder();
|
|
130
|
+
const state = { events: [], resolve: null, done: false };
|
|
131
|
+
const parser = createParser({
|
|
132
|
+
onEvent(event) {
|
|
133
|
+
const type = event.event ?? "message";
|
|
134
|
+
if (!KNOWN_EVENTS.has(type)) return;
|
|
135
|
+
let data;
|
|
136
|
+
try {
|
|
137
|
+
data = JSON.parse(event.data);
|
|
138
|
+
} catch {
|
|
139
|
+
data = { raw: event.data };
|
|
140
|
+
}
|
|
141
|
+
pushEvent(state, { type, data });
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
const pump = (async () => {
|
|
145
|
+
try {
|
|
146
|
+
for (; ; ) {
|
|
147
|
+
const result = await reader.read();
|
|
148
|
+
if (result.done) break;
|
|
149
|
+
parser.feed(decoder.decode(result.value, { stream: true }));
|
|
150
|
+
}
|
|
151
|
+
} catch (err) {
|
|
152
|
+
pushEvent(state, {
|
|
153
|
+
type: "error",
|
|
154
|
+
data: { message: err instanceof Error ? err.message : String(err) }
|
|
155
|
+
});
|
|
156
|
+
} finally {
|
|
157
|
+
state.done = true;
|
|
158
|
+
if (state.resolve) {
|
|
159
|
+
const cb = state.resolve;
|
|
160
|
+
state.resolve = null;
|
|
161
|
+
cb();
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
})();
|
|
165
|
+
try {
|
|
166
|
+
for (; ; ) {
|
|
167
|
+
while (state.events.length > 0) {
|
|
168
|
+
const event = state.events.shift();
|
|
169
|
+
yield event;
|
|
170
|
+
if (event.type === "done" || event.type === "error") return;
|
|
171
|
+
}
|
|
172
|
+
if (state.done) return;
|
|
173
|
+
await new Promise((r) => {
|
|
174
|
+
state.resolve = r;
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
} finally {
|
|
178
|
+
reader.cancel().catch(() => {
|
|
179
|
+
});
|
|
180
|
+
await pump.catch(() => {
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// src/client.ts
|
|
186
|
+
var SDK_VERSION = "0.1.0";
|
|
187
|
+
var AgentKernel = class {
|
|
188
|
+
baseUrl;
|
|
189
|
+
apiKey;
|
|
190
|
+
timeout;
|
|
191
|
+
constructor(opts) {
|
|
192
|
+
const config = resolveConfig(opts);
|
|
193
|
+
this.baseUrl = config.baseUrl;
|
|
194
|
+
this.apiKey = config.apiKey;
|
|
195
|
+
this.timeout = config.timeout;
|
|
196
|
+
}
|
|
197
|
+
// -- Core API methods --
|
|
198
|
+
/** Health check. Returns "ok" if the server is running. */
|
|
199
|
+
async health() {
|
|
200
|
+
const res = await this.request("GET", "/health");
|
|
201
|
+
return res;
|
|
202
|
+
}
|
|
203
|
+
/** Run a command in a temporary sandbox. */
|
|
204
|
+
async run(command, opts) {
|
|
205
|
+
return this.request("POST", "/run", {
|
|
206
|
+
command,
|
|
207
|
+
image: opts?.image,
|
|
208
|
+
profile: opts?.profile,
|
|
209
|
+
fast: opts?.fast ?? true
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Run a command with SSE streaming output.
|
|
214
|
+
*
|
|
215
|
+
* @example
|
|
216
|
+
* ```ts
|
|
217
|
+
* for await (const event of client.runStream(["python3", "script.py"])) {
|
|
218
|
+
* if (event.type === "output") process.stdout.write(String(event.data.data));
|
|
219
|
+
* }
|
|
220
|
+
* ```
|
|
221
|
+
*/
|
|
222
|
+
async *runStream(command, opts) {
|
|
223
|
+
const body = JSON.stringify({
|
|
224
|
+
command,
|
|
225
|
+
image: opts?.image,
|
|
226
|
+
profile: opts?.profile,
|
|
227
|
+
fast: opts?.fast ?? true
|
|
228
|
+
});
|
|
229
|
+
const response = await this.fetch("/run/stream", {
|
|
230
|
+
method: "POST",
|
|
231
|
+
headers: this.headers("application/json"),
|
|
232
|
+
body
|
|
233
|
+
});
|
|
234
|
+
if (!response.ok) {
|
|
235
|
+
const text = await response.text();
|
|
236
|
+
throw errorFromStatus(response.status, text);
|
|
237
|
+
}
|
|
238
|
+
if (!response.body) {
|
|
239
|
+
throw new AgentKernelError("No response body for SSE stream");
|
|
240
|
+
}
|
|
241
|
+
yield* parseSSE(response.body);
|
|
242
|
+
}
|
|
243
|
+
/** List all sandboxes. */
|
|
244
|
+
async listSandboxes() {
|
|
245
|
+
return this.request("GET", "/sandboxes");
|
|
246
|
+
}
|
|
247
|
+
/** Create a new sandbox. */
|
|
248
|
+
async createSandbox(name, opts) {
|
|
249
|
+
return this.request("POST", "/sandboxes", {
|
|
250
|
+
name,
|
|
251
|
+
image: opts?.image
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
/** Get info about a sandbox. */
|
|
255
|
+
async getSandbox(name) {
|
|
256
|
+
return this.request("GET", `/sandboxes/${encodeURIComponent(name)}`);
|
|
257
|
+
}
|
|
258
|
+
/** Remove a sandbox. */
|
|
259
|
+
async removeSandbox(name) {
|
|
260
|
+
await this.request("DELETE", `/sandboxes/${encodeURIComponent(name)}`);
|
|
261
|
+
}
|
|
262
|
+
/** Run a command in an existing sandbox. */
|
|
263
|
+
async execInSandbox(name, command) {
|
|
264
|
+
return this.request(
|
|
265
|
+
"POST",
|
|
266
|
+
`/sandboxes/${encodeURIComponent(name)}/exec`,
|
|
267
|
+
{ command }
|
|
268
|
+
);
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Create a sandbox session with automatic cleanup.
|
|
272
|
+
*
|
|
273
|
+
* The returned SandboxSession implements AsyncDisposable,
|
|
274
|
+
* so it works with `await using` (TS 5.2+):
|
|
275
|
+
*
|
|
276
|
+
* @example
|
|
277
|
+
* ```ts
|
|
278
|
+
* await using sb = await client.sandbox("test", { image: "python:3.12-alpine" });
|
|
279
|
+
* await sb.run(["pip", "install", "numpy"]);
|
|
280
|
+
* // sandbox auto-removed when scope exits
|
|
281
|
+
* ```
|
|
282
|
+
*/
|
|
283
|
+
async sandbox(name, opts) {
|
|
284
|
+
await this.createSandbox(name, opts);
|
|
285
|
+
return new SandboxSession(
|
|
286
|
+
name,
|
|
287
|
+
(n, cmd) => this.execInSandbox(n, cmd),
|
|
288
|
+
(n) => this.removeSandbox(n),
|
|
289
|
+
(n) => this.getSandbox(n)
|
|
290
|
+
);
|
|
291
|
+
}
|
|
292
|
+
// -- Internal helpers --
|
|
293
|
+
headers(contentType) {
|
|
294
|
+
const h = {
|
|
295
|
+
"User-Agent": `agentkernel-nodejs-sdk/${SDK_VERSION}`
|
|
296
|
+
};
|
|
297
|
+
if (contentType) h["Content-Type"] = contentType;
|
|
298
|
+
if (this.apiKey) h["Authorization"] = `Bearer ${this.apiKey}`;
|
|
299
|
+
return h;
|
|
300
|
+
}
|
|
301
|
+
async fetch(path, init) {
|
|
302
|
+
const url = `${this.baseUrl}${path}`;
|
|
303
|
+
try {
|
|
304
|
+
return await fetch(url, {
|
|
305
|
+
...init,
|
|
306
|
+
signal: AbortSignal.timeout(this.timeout)
|
|
307
|
+
});
|
|
308
|
+
} catch (err) {
|
|
309
|
+
if (err instanceof DOMException && err.name === "TimeoutError") {
|
|
310
|
+
throw new NetworkError(`Request timed out after ${this.timeout}ms`);
|
|
311
|
+
}
|
|
312
|
+
if (err instanceof TypeError) {
|
|
313
|
+
throw new NetworkError(`Failed to connect to ${this.baseUrl}: ${err.message}`);
|
|
314
|
+
}
|
|
315
|
+
throw new NetworkError(
|
|
316
|
+
err instanceof Error ? err.message : String(err)
|
|
317
|
+
);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
async request(method, path, body) {
|
|
321
|
+
const init = {
|
|
322
|
+
method,
|
|
323
|
+
headers: this.headers(body ? "application/json" : void 0)
|
|
324
|
+
};
|
|
325
|
+
if (body) init.body = JSON.stringify(body);
|
|
326
|
+
const response = await this.fetch(path, init);
|
|
327
|
+
const text = await response.text();
|
|
328
|
+
if (!response.ok) {
|
|
329
|
+
throw errorFromStatus(response.status, text);
|
|
330
|
+
}
|
|
331
|
+
const parsed = JSON.parse(text);
|
|
332
|
+
if (!parsed.success) {
|
|
333
|
+
throw new AgentKernelError(parsed.error ?? "Unknown error");
|
|
334
|
+
}
|
|
335
|
+
return parsed.data;
|
|
336
|
+
}
|
|
337
|
+
};
|
|
338
|
+
export {
|
|
339
|
+
AgentKernel,
|
|
340
|
+
AgentKernelError,
|
|
341
|
+
AuthError,
|
|
342
|
+
NetworkError,
|
|
343
|
+
NotFoundError,
|
|
344
|
+
SandboxSession,
|
|
345
|
+
ServerError,
|
|
346
|
+
StreamError,
|
|
347
|
+
ValidationError
|
|
348
|
+
};
|
|
349
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/config.ts","../src/errors.ts","../src/sandbox.ts","../src/sse.ts","../src/client.ts"],"sourcesContent":["import type { AgentKernelOptions } from \"./types.js\";\n\nconst DEFAULT_BASE_URL = \"http://localhost:18888\";\nconst DEFAULT_TIMEOUT = 30_000;\n\n/** Resolve configuration from constructor args, env vars, and defaults. */\nexport function resolveConfig(opts?: AgentKernelOptions) {\n const baseUrl =\n opts?.baseUrl ??\n process.env.AGENTKERNEL_BASE_URL ??\n DEFAULT_BASE_URL;\n\n const apiKey =\n opts?.apiKey ??\n process.env.AGENTKERNEL_API_KEY ??\n undefined;\n\n const timeout = opts?.timeout ?? DEFAULT_TIMEOUT;\n\n return {\n baseUrl: baseUrl.replace(/\\/+$/, \"\"),\n apiKey,\n timeout,\n };\n}\n","/** Base error for all agentkernel SDK errors. */\nexport class AgentKernelError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"AgentKernelError\";\n }\n}\n\n/** 401 Unauthorized. */\nexport class AuthError extends AgentKernelError {\n readonly status = 401;\n constructor(message = \"Unauthorized\") {\n super(message);\n this.name = \"AuthError\";\n }\n}\n\n/** 404 Not Found. */\nexport class NotFoundError extends AgentKernelError {\n readonly status = 404;\n constructor(message = \"Not found\") {\n super(message);\n this.name = \"NotFoundError\";\n }\n}\n\n/** 400 Bad Request. */\nexport class ValidationError extends AgentKernelError {\n readonly status = 400;\n constructor(message = \"Bad request\") {\n super(message);\n this.name = \"ValidationError\";\n }\n}\n\n/** 500 Internal Server Error. */\nexport class ServerError extends AgentKernelError {\n readonly status = 500;\n constructor(message = \"Internal server error\") {\n super(message);\n this.name = \"ServerError\";\n }\n}\n\n/** Network / connection error. */\nexport class NetworkError extends AgentKernelError {\n constructor(message = \"Network error\") {\n super(message);\n this.name = \"NetworkError\";\n }\n}\n\n/** SSE streaming error. */\nexport class StreamError extends AgentKernelError {\n constructor(message = \"Stream error\") {\n super(message);\n this.name = \"StreamError\";\n }\n}\n\n/** Map an HTTP status code + body to the appropriate error. */\nexport function errorFromStatus(status: number, body: string): AgentKernelError {\n let message: string;\n try {\n const parsed = JSON.parse(body);\n message = parsed.error ?? body;\n } catch {\n message = body;\n }\n\n switch (status) {\n case 400:\n return new ValidationError(message);\n case 401:\n return new AuthError(message);\n case 404:\n return new NotFoundError(message);\n default:\n return new ServerError(message);\n }\n}\n","import type { RunOutput, SandboxInfo } from \"./types.js\";\n\ntype ExecFn = (name: string, command: string[]) => Promise<RunOutput>;\ntype RemoveFn = (name: string) => Promise<void>;\ntype GetFn = (name: string) => Promise<SandboxInfo>;\n\n/**\n * A sandbox session that auto-removes the sandbox on dispose.\n *\n * Supports both explicit cleanup via remove() and automatic cleanup via\n * Symbol.asyncDispose (TS 5.2+ `await using`).\n *\n * @example\n * ```ts\n * await using sb = await client.sandbox(\"test\");\n * await sb.exec([\"echo\", \"hello\"]);\n * // sandbox auto-removed when scope exits\n * ```\n */\nexport class SandboxSession implements AsyncDisposable {\n readonly name: string;\n private _removed = false;\n private readonly _execInSandbox: ExecFn;\n private readonly _removeSandbox: RemoveFn;\n private readonly _getSandbox: GetFn;\n\n /** @internal */\n constructor(\n name: string,\n execInSandbox: ExecFn,\n removeSandbox: RemoveFn,\n getSandbox: GetFn,\n ) {\n this.name = name;\n this._execInSandbox = execInSandbox;\n this._removeSandbox = removeSandbox;\n this._getSandbox = getSandbox;\n }\n\n /** Run a command in this sandbox. */\n async run(command: string[]): Promise<RunOutput> {\n return this._execInSandbox(this.name, command);\n }\n\n /** Get sandbox info. */\n async info(): Promise<SandboxInfo> {\n return this._getSandbox(this.name);\n }\n\n /** Remove the sandbox. Idempotent. */\n async remove(): Promise<void> {\n if (this._removed) return;\n this._removed = true;\n await this._removeSandbox(this.name);\n }\n\n /** Auto-cleanup for `await using`. */\n async [Symbol.asyncDispose](): Promise<void> {\n await this.remove();\n }\n}\n","import { createParser, type EventSourceMessage } from \"eventsource-parser\";\nimport type { StreamEvent, StreamEventType } from \"./types.js\";\n\nconst KNOWN_EVENTS = new Set<string>([\"started\", \"progress\", \"output\", \"done\", \"error\"]);\n\n/** Shared mutable state between the pump and the generator. */\ninterface PumpState {\n events: StreamEvent[];\n resolve: (() => void) | null;\n done: boolean;\n}\n\nfunction pushEvent(state: PumpState, event: StreamEvent): void {\n state.events.push(event);\n if (state.resolve) {\n const cb = state.resolve;\n state.resolve = null;\n cb();\n }\n}\n\n/**\n * Parse an SSE response body into an async generator of StreamEvents.\n *\n * Consumes a ReadableStream<Uint8Array> from fetch() and yields typed events\n * until the stream closes or a \"done\"/\"error\" event is received.\n */\nexport async function* parseSSE(\n body: ReadableStream<Uint8Array>,\n): AsyncGenerator<StreamEvent> {\n const reader = body.getReader();\n const decoder = new TextDecoder();\n const state: PumpState = { events: [], resolve: null, done: false };\n\n const parser = createParser({\n onEvent(event: EventSourceMessage) {\n const type = event.event ?? \"message\";\n if (!KNOWN_EVENTS.has(type)) return;\n\n let data: Record<string, unknown>;\n try {\n data = JSON.parse(event.data);\n } catch {\n data = { raw: event.data };\n }\n\n pushEvent(state, { type: type as StreamEventType, data });\n },\n });\n\n // Read the stream in the background\n const pump = (async () => {\n try {\n for (;;) {\n const result = await reader.read();\n if (result.done) break;\n parser.feed(decoder.decode(result.value, { stream: true }));\n }\n } catch (err) {\n pushEvent(state, {\n type: \"error\",\n data: { message: err instanceof Error ? err.message : String(err) },\n });\n } finally {\n state.done = true;\n if (state.resolve) {\n const cb = state.resolve;\n state.resolve = null;\n cb();\n }\n }\n })();\n\n try {\n for (;;) {\n // Yield all buffered events\n while (state.events.length > 0) {\n const event = state.events.shift()!;\n yield event;\n if (event.type === \"done\" || event.type === \"error\") return;\n }\n\n // If the stream is done and no more events, exit\n if (state.done) return;\n\n // Wait for the next event\n await new Promise<void>((r) => {\n state.resolve = r;\n });\n }\n } finally {\n reader.cancel().catch(() => {});\n await pump.catch(() => {});\n }\n}\n","import { resolveConfig } from \"./config.js\";\nimport {\n AgentKernelError,\n NetworkError,\n errorFromStatus,\n} from \"./errors.js\";\nimport { SandboxSession } from \"./sandbox.js\";\nimport { parseSSE } from \"./sse.js\";\nimport type {\n AgentKernelOptions,\n ApiResponse,\n CreateSandboxOptions,\n RunOptions,\n RunOutput,\n SandboxInfo,\n StreamEvent,\n} from \"./types.js\";\n\nconst SDK_VERSION = \"0.1.0\";\n\n/**\n * Client for the agentkernel HTTP API.\n *\n * @example\n * ```ts\n * const client = new AgentKernel();\n * const result = await client.run([\"echo\", \"hello\"]);\n * console.log(result.output); // \"hello\\n\"\n * ```\n */\nexport class AgentKernel {\n private readonly baseUrl: string;\n private readonly apiKey: string | undefined;\n private readonly timeout: number;\n\n constructor(opts?: AgentKernelOptions) {\n const config = resolveConfig(opts);\n this.baseUrl = config.baseUrl;\n this.apiKey = config.apiKey;\n this.timeout = config.timeout;\n }\n\n // -- Core API methods --\n\n /** Health check. Returns \"ok\" if the server is running. */\n async health(): Promise<string> {\n const res = await this.request<string>(\"GET\", \"/health\");\n return res;\n }\n\n /** Run a command in a temporary sandbox. */\n async run(command: string[], opts?: RunOptions): Promise<RunOutput> {\n return this.request<RunOutput>(\"POST\", \"/run\", {\n command,\n image: opts?.image,\n profile: opts?.profile,\n fast: opts?.fast ?? true,\n });\n }\n\n /**\n * Run a command with SSE streaming output.\n *\n * @example\n * ```ts\n * for await (const event of client.runStream([\"python3\", \"script.py\"])) {\n * if (event.type === \"output\") process.stdout.write(String(event.data.data));\n * }\n * ```\n */\n async *runStream(\n command: string[],\n opts?: RunOptions,\n ): AsyncGenerator<StreamEvent> {\n const body = JSON.stringify({\n command,\n image: opts?.image,\n profile: opts?.profile,\n fast: opts?.fast ?? true,\n });\n\n const response = await this.fetch(\"/run/stream\", {\n method: \"POST\",\n headers: this.headers(\"application/json\"),\n body,\n });\n\n if (!response.ok) {\n const text = await response.text();\n throw errorFromStatus(response.status, text);\n }\n\n if (!response.body) {\n throw new AgentKernelError(\"No response body for SSE stream\");\n }\n\n yield* parseSSE(response.body);\n }\n\n /** List all sandboxes. */\n async listSandboxes(): Promise<SandboxInfo[]> {\n return this.request<SandboxInfo[]>(\"GET\", \"/sandboxes\");\n }\n\n /** Create a new sandbox. */\n async createSandbox(\n name: string,\n opts?: CreateSandboxOptions,\n ): Promise<SandboxInfo> {\n return this.request<SandboxInfo>(\"POST\", \"/sandboxes\", {\n name,\n image: opts?.image,\n });\n }\n\n /** Get info about a sandbox. */\n async getSandbox(name: string): Promise<SandboxInfo> {\n return this.request<SandboxInfo>(\"GET\", `/sandboxes/${encodeURIComponent(name)}`);\n }\n\n /** Remove a sandbox. */\n async removeSandbox(name: string): Promise<void> {\n await this.request<string>(\"DELETE\", `/sandboxes/${encodeURIComponent(name)}`);\n }\n\n /** Run a command in an existing sandbox. */\n async execInSandbox(name: string, command: string[]): Promise<RunOutput> {\n return this.request<RunOutput>(\n \"POST\",\n `/sandboxes/${encodeURIComponent(name)}/exec`,\n { command },\n );\n }\n\n /**\n * Create a sandbox session with automatic cleanup.\n *\n * The returned SandboxSession implements AsyncDisposable,\n * so it works with `await using` (TS 5.2+):\n *\n * @example\n * ```ts\n * await using sb = await client.sandbox(\"test\", { image: \"python:3.12-alpine\" });\n * await sb.run([\"pip\", \"install\", \"numpy\"]);\n * // sandbox auto-removed when scope exits\n * ```\n */\n async sandbox(\n name: string,\n opts?: CreateSandboxOptions,\n ): Promise<SandboxSession> {\n await this.createSandbox(name, opts);\n return new SandboxSession(\n name,\n (n, cmd) => this.execInSandbox(n, cmd),\n (n) => this.removeSandbox(n),\n (n) => this.getSandbox(n),\n );\n }\n\n // -- Internal helpers --\n\n private headers(contentType?: string): Record<string, string> {\n const h: Record<string, string> = {\n \"User-Agent\": `agentkernel-nodejs-sdk/${SDK_VERSION}`,\n };\n if (contentType) h[\"Content-Type\"] = contentType;\n if (this.apiKey) h[\"Authorization\"] = `Bearer ${this.apiKey}`;\n return h;\n }\n\n private async fetch(path: string, init: RequestInit): Promise<Response> {\n const url = `${this.baseUrl}${path}`;\n try {\n return await fetch(url, {\n ...init,\n signal: AbortSignal.timeout(this.timeout),\n });\n } catch (err) {\n if (err instanceof DOMException && err.name === \"TimeoutError\") {\n throw new NetworkError(`Request timed out after ${this.timeout}ms`);\n }\n if (err instanceof TypeError) {\n throw new NetworkError(`Failed to connect to ${this.baseUrl}: ${err.message}`);\n }\n throw new NetworkError(\n err instanceof Error ? err.message : String(err),\n );\n }\n }\n\n private async request<T>(\n method: string,\n path: string,\n body?: unknown,\n ): Promise<T> {\n const init: RequestInit = {\n method,\n headers: this.headers(body ? \"application/json\" : undefined),\n };\n if (body) init.body = JSON.stringify(body);\n\n const response = await this.fetch(path, init);\n\n const text = await response.text();\n if (!response.ok) {\n throw errorFromStatus(response.status, text);\n }\n\n const parsed: ApiResponse<T> = JSON.parse(text);\n if (!parsed.success) {\n throw new AgentKernelError(parsed.error ?? \"Unknown error\");\n }\n return parsed.data as T;\n }\n}\n"],"mappings":"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","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "agentkernel",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Node.js SDK for agentkernel — run AI coding agents in secure, isolated microVMs",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.cjs",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"default": "./dist/index.js"
|
|
14
|
+
},
|
|
15
|
+
"require": {
|
|
16
|
+
"types": "./dist/index.d.cts",
|
|
17
|
+
"default": "./dist/index.cjs"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"dist",
|
|
23
|
+
"README.md"
|
|
24
|
+
],
|
|
25
|
+
"scripts": {
|
|
26
|
+
"build": "tsup",
|
|
27
|
+
"test": "vitest run",
|
|
28
|
+
"test:watch": "vitest",
|
|
29
|
+
"typecheck": "tsc --noEmit",
|
|
30
|
+
"lint": "tsc --noEmit",
|
|
31
|
+
"prepublishOnly": "npm run build"
|
|
32
|
+
},
|
|
33
|
+
"keywords": [
|
|
34
|
+
"agentkernel",
|
|
35
|
+
"sandbox",
|
|
36
|
+
"microvm",
|
|
37
|
+
"ai",
|
|
38
|
+
"agent",
|
|
39
|
+
"firecracker",
|
|
40
|
+
"isolation"
|
|
41
|
+
],
|
|
42
|
+
"author": "Paul Thrasher <thrashr888@gmail.com>",
|
|
43
|
+
"license": "MIT",
|
|
44
|
+
"repository": {
|
|
45
|
+
"type": "git",
|
|
46
|
+
"url": "https://github.com/thrashr888/agentkernel.git",
|
|
47
|
+
"directory": "sdk/nodejs"
|
|
48
|
+
},
|
|
49
|
+
"homepage": "https://thrashr888.github.io/agentkernel/",
|
|
50
|
+
"engines": {
|
|
51
|
+
"node": ">=20"
|
|
52
|
+
},
|
|
53
|
+
"dependencies": {
|
|
54
|
+
"eventsource-parser": "^3.0.0"
|
|
55
|
+
},
|
|
56
|
+
"devDependencies": {
|
|
57
|
+
"@types/node": "^25.1.0",
|
|
58
|
+
"msw": "^2.7.0",
|
|
59
|
+
"tsup": "^8.4.0",
|
|
60
|
+
"typescript": "^5.7.0",
|
|
61
|
+
"vitest": "^3.0.0"
|
|
62
|
+
}
|
|
63
|
+
}
|