@tangle-network/agent-runtime 0.79.0 → 0.79.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent.js +3 -2
- package/dist/agent.js.map +1 -1
- package/dist/{chunk-GZX3PI7V.js → chunk-2DS6T46I.js} +3 -3
- package/dist/{chunk-N2JJDGLJ.js → chunk-75V2XXYJ.js} +8 -6
- package/dist/{chunk-N2JJDGLJ.js.map → chunk-75V2XXYJ.js.map} +1 -1
- package/dist/{chunk-F6G3SSHY.js → chunk-SONQUREI.js} +2 -2
- package/dist/{chunk-EZ2QESTP.js → chunk-TSDKBFZP.js} +34 -925
- package/dist/chunk-TSDKBFZP.js.map +1 -0
- package/dist/chunk-Z3RRRPRB.js +916 -0
- package/dist/chunk-Z3RRRPRB.js.map +1 -0
- package/dist/{coordination-09JTQnlF.d.ts → coordination-BoEPhGas.d.ts} +7 -62
- package/dist/environment-provider.d.ts +66 -0
- package/dist/environment-provider.js +16 -0
- package/dist/environment-provider.js.map +1 -0
- package/dist/index.d.ts +4 -3
- package/dist/index.js +5 -4
- package/dist/index.js.map +1 -1
- package/dist/{loop-runner-bin-Ddgf4DkS.d.ts → loop-runner-bin-DCr5OMe5.d.ts} +2 -2
- package/dist/loop-runner-bin.d.ts +4 -3
- package/dist/loop-runner-bin.js +4 -3
- package/dist/loops.d.ts +9 -6
- package/dist/loops.js +9 -7
- package/dist/mcp/bin.js +2 -1
- package/dist/mcp/bin.js.map +1 -1
- package/dist/mcp/index.d.ts +6 -4
- package/dist/mcp/index.js +9 -7
- package/dist/mcp/index.js.map +1 -1
- package/dist/{worktree-CUn0d-ZT.d.ts → types-C1sozrte.d.ts} +1 -123
- package/dist/worktree-CpptK3oF.d.ts +125 -0
- package/dist/{worktree-fanout-DwwatTdY.d.ts → worktree-fanout-CtQrRDME.d.ts} +2 -1
- package/package.json +9 -1
- package/dist/chunk-EZ2QESTP.js.map +0 -1
- /package/dist/{chunk-GZX3PI7V.js.map → chunk-2DS6T46I.js.map} +0 -0
- /package/dist/{chunk-F6G3SSHY.js.map → chunk-SONQUREI.js.map} +0 -0
|
@@ -1,6 +1,21 @@
|
|
|
1
1
|
import {
|
|
2
2
|
buildLoopSpanNodes
|
|
3
3
|
} from "./chunk-VMNEQHJR.js";
|
|
4
|
+
import {
|
|
5
|
+
addTokenUsage,
|
|
6
|
+
deleteBoxSafe,
|
|
7
|
+
mapWithConcurrency,
|
|
8
|
+
providerAsExecutor,
|
|
9
|
+
randomSuffix,
|
|
10
|
+
randomUuid,
|
|
11
|
+
resolveAgentEnvironmentProvider,
|
|
12
|
+
sleep,
|
|
13
|
+
stringifySafe,
|
|
14
|
+
throwAbort,
|
|
15
|
+
throwIfAborted,
|
|
16
|
+
withTimeout,
|
|
17
|
+
zeroTokenUsage
|
|
18
|
+
} from "./chunk-Z3RRRPRB.js";
|
|
4
19
|
import {
|
|
5
20
|
extractLlmCallEvent
|
|
6
21
|
} from "./chunk-T2HVQVB4.js";
|
|
@@ -31,118 +46,6 @@ function assertModelAllowed(model, allowed) {
|
|
|
31
46
|
|
|
32
47
|
// src/durable/spawn-journal.ts
|
|
33
48
|
import { createHash } from "crypto";
|
|
34
|
-
|
|
35
|
-
// src/runtime/util.ts
|
|
36
|
-
async function deleteBoxSafe(box) {
|
|
37
|
-
if (!box || typeof box.delete !== "function") return true;
|
|
38
|
-
try {
|
|
39
|
-
await box.delete();
|
|
40
|
-
return true;
|
|
41
|
-
} catch {
|
|
42
|
-
return false;
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
function randomSuffix(len = 8) {
|
|
46
|
-
return Math.random().toString(36).slice(2, 2 + len);
|
|
47
|
-
}
|
|
48
|
-
function randomUuid() {
|
|
49
|
-
return crypto.randomUUID();
|
|
50
|
-
}
|
|
51
|
-
function abortError() {
|
|
52
|
-
const err = new Error("aborted");
|
|
53
|
-
err.name = "AbortError";
|
|
54
|
-
return err;
|
|
55
|
-
}
|
|
56
|
-
function throwAbort() {
|
|
57
|
-
throw abortError();
|
|
58
|
-
}
|
|
59
|
-
function throwIfAborted(signal) {
|
|
60
|
-
if (signal?.aborted) throw abortError();
|
|
61
|
-
}
|
|
62
|
-
function isAbortError(err) {
|
|
63
|
-
return err instanceof Error && err.name === "AbortError";
|
|
64
|
-
}
|
|
65
|
-
function sleep(ms, signal) {
|
|
66
|
-
return new Promise((resolve) => {
|
|
67
|
-
if (signal?.aborted) {
|
|
68
|
-
resolve();
|
|
69
|
-
return;
|
|
70
|
-
}
|
|
71
|
-
let onAbort;
|
|
72
|
-
const timer = setTimeout(() => {
|
|
73
|
-
if (onAbort && signal) signal.removeEventListener("abort", onAbort);
|
|
74
|
-
resolve();
|
|
75
|
-
}, ms);
|
|
76
|
-
if (signal) {
|
|
77
|
-
onAbort = () => {
|
|
78
|
-
clearTimeout(timer);
|
|
79
|
-
resolve();
|
|
80
|
-
};
|
|
81
|
-
signal.addEventListener("abort", onAbort, { once: true });
|
|
82
|
-
}
|
|
83
|
-
});
|
|
84
|
-
}
|
|
85
|
-
function withTimeout(promise, ms) {
|
|
86
|
-
return new Promise((resolve) => {
|
|
87
|
-
const timer = setTimeout(() => resolve(void 0), ms);
|
|
88
|
-
promise.then(
|
|
89
|
-
(value) => {
|
|
90
|
-
clearTimeout(timer);
|
|
91
|
-
resolve(value);
|
|
92
|
-
},
|
|
93
|
-
() => {
|
|
94
|
-
clearTimeout(timer);
|
|
95
|
-
resolve(void 0);
|
|
96
|
-
}
|
|
97
|
-
);
|
|
98
|
-
});
|
|
99
|
-
}
|
|
100
|
-
function stringifySafe(value, opts = {}) {
|
|
101
|
-
let s;
|
|
102
|
-
try {
|
|
103
|
-
if (typeof value === "string") {
|
|
104
|
-
s = value;
|
|
105
|
-
} else {
|
|
106
|
-
const json = opts.pretty ? JSON.stringify(value, null, 2) : JSON.stringify(value);
|
|
107
|
-
s = json ?? String(value);
|
|
108
|
-
}
|
|
109
|
-
} catch {
|
|
110
|
-
s = String(value);
|
|
111
|
-
}
|
|
112
|
-
if (opts.max !== void 0 && s.length > opts.max) return `${s.slice(0, opts.max)}\u2026`;
|
|
113
|
-
return s;
|
|
114
|
-
}
|
|
115
|
-
function zeroTokenUsage() {
|
|
116
|
-
return { input: 0, output: 0 };
|
|
117
|
-
}
|
|
118
|
-
function addTokenUsage(acc, delta) {
|
|
119
|
-
acc.input += delta.input ?? 0;
|
|
120
|
-
acc.output += delta.output ?? 0;
|
|
121
|
-
}
|
|
122
|
-
async function mapWithConcurrency(items, limit, fn) {
|
|
123
|
-
const bound = Math.max(1, Math.floor(limit));
|
|
124
|
-
const results = new Array(items.length);
|
|
125
|
-
let next = 0;
|
|
126
|
-
let failed = false;
|
|
127
|
-
const worker = async () => {
|
|
128
|
-
while (!failed) {
|
|
129
|
-
const i = next;
|
|
130
|
-
next += 1;
|
|
131
|
-
if (i >= items.length) return;
|
|
132
|
-
try {
|
|
133
|
-
results[i] = await fn(items[i], i);
|
|
134
|
-
} catch (err) {
|
|
135
|
-
failed = true;
|
|
136
|
-
throw err;
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
};
|
|
140
|
-
const workerCount = Math.min(bound, items.length);
|
|
141
|
-
await Promise.all(Array.from({ length: workerCount }, () => worker()));
|
|
142
|
-
return results;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
// src/durable/spawn-journal.ts
|
|
146
49
|
function contentAddress(artifact) {
|
|
147
50
|
const hex = createHash("sha256").update(stableStringify(artifact), "utf-8").digest("hex");
|
|
148
51
|
return `sha256:${hex}`;
|
|
@@ -208,786 +111,6 @@ function assertSeqUnique(root, events, ev) {
|
|
|
208
111
|
}
|
|
209
112
|
}
|
|
210
113
|
|
|
211
|
-
// src/runtime/environment-provider.ts
|
|
212
|
-
function createAgentEnvironmentProviderRegistry(providers = []) {
|
|
213
|
-
const entries = /* @__PURE__ */ new Map();
|
|
214
|
-
const registry = {
|
|
215
|
-
register(provider, options = {}) {
|
|
216
|
-
if (!provider.name) {
|
|
217
|
-
throw new ValidationError("agent environment provider registry: provider.name required");
|
|
218
|
-
}
|
|
219
|
-
if (!options.replace && entries.has(provider.name)) {
|
|
220
|
-
throw new ValidationError(
|
|
221
|
-
`agent environment provider registry: provider "${provider.name}" already registered`
|
|
222
|
-
);
|
|
223
|
-
}
|
|
224
|
-
entries.set(provider.name, provider);
|
|
225
|
-
},
|
|
226
|
-
has(name) {
|
|
227
|
-
return entries.has(name);
|
|
228
|
-
},
|
|
229
|
-
get(name) {
|
|
230
|
-
return entries.get(name);
|
|
231
|
-
},
|
|
232
|
-
require(name) {
|
|
233
|
-
const provider = entries.get(name);
|
|
234
|
-
if (!provider) {
|
|
235
|
-
const available = Array.from(entries.keys()).sort();
|
|
236
|
-
const suffix = available.length > 0 ? `; available: ${available.join(", ")}` : "";
|
|
237
|
-
throw new ValidationError(
|
|
238
|
-
`agent environment provider registry: provider "${name}" is not registered${suffix}`
|
|
239
|
-
);
|
|
240
|
-
}
|
|
241
|
-
return provider;
|
|
242
|
-
},
|
|
243
|
-
names() {
|
|
244
|
-
return Array.from(entries.keys()).sort();
|
|
245
|
-
},
|
|
246
|
-
providers() {
|
|
247
|
-
return registry.names().map((name) => registry.require(name));
|
|
248
|
-
},
|
|
249
|
-
async capabilities(name) {
|
|
250
|
-
return registry.require(name).capabilities();
|
|
251
|
-
}
|
|
252
|
-
};
|
|
253
|
-
for (const provider of providers) registry.register(provider);
|
|
254
|
-
return registry;
|
|
255
|
-
}
|
|
256
|
-
function resolveAgentEnvironmentProvider(provider, registry) {
|
|
257
|
-
if (typeof provider !== "string") return provider;
|
|
258
|
-
if (!registry) {
|
|
259
|
-
throw new ValidationError(
|
|
260
|
-
`agent environment provider "${provider}" requires an AgentEnvironmentProviderRegistry`
|
|
261
|
-
);
|
|
262
|
-
}
|
|
263
|
-
return registry.require(provider);
|
|
264
|
-
}
|
|
265
|
-
function providerAsSandboxClient(provider, options = {}) {
|
|
266
|
-
return {
|
|
267
|
-
async create(createOptions) {
|
|
268
|
-
const mapped = {
|
|
269
|
-
...options.defaults ?? {},
|
|
270
|
-
...createInputFromSandboxOptions(createOptions),
|
|
271
|
-
...options.mapCreateOptions?.(createOptions) ?? {}
|
|
272
|
-
};
|
|
273
|
-
if (mapped.profile === void 0) {
|
|
274
|
-
throw new ValidationError(
|
|
275
|
-
`providerAsSandboxClient(${provider.name}): profile required in defaults or CreateSandboxOptions.backend.profile`
|
|
276
|
-
);
|
|
277
|
-
}
|
|
278
|
-
const environment = await provider.create(mapped);
|
|
279
|
-
return environmentAsSandboxInstance(environment, {
|
|
280
|
-
requireTerminalEvent: options.requireTerminalEvent ?? true
|
|
281
|
-
});
|
|
282
|
-
}
|
|
283
|
-
};
|
|
284
|
-
}
|
|
285
|
-
function sandboxClientAsProvider(client, options = {}) {
|
|
286
|
-
const providerName = options.name ?? "tangle-sandbox";
|
|
287
|
-
return {
|
|
288
|
-
name: providerName,
|
|
289
|
-
capabilities: async () => {
|
|
290
|
-
if (options.capabilities) {
|
|
291
|
-
return typeof options.capabilities === "function" ? options.capabilities() : options.capabilities;
|
|
292
|
-
}
|
|
293
|
-
return defaultTangleSandboxCapabilities();
|
|
294
|
-
},
|
|
295
|
-
...options.validateProfile ? { validateProfile: options.validateProfile } : {},
|
|
296
|
-
async create(input) {
|
|
297
|
-
const createOptions = options.mapCreateInput?.(input) ?? sandboxOptionsFromCreateInput(input, options.defaultBackend ?? "opencode");
|
|
298
|
-
const box = await client.create(createOptions);
|
|
299
|
-
return sandboxInstanceAsEnvironment(box, providerName, client);
|
|
300
|
-
},
|
|
301
|
-
...hasGet(client) ? {
|
|
302
|
-
async get(id) {
|
|
303
|
-
const box = await client.get(id);
|
|
304
|
-
return box ? sandboxInstanceAsEnvironment(box, providerName, client) : null;
|
|
305
|
-
}
|
|
306
|
-
} : {},
|
|
307
|
-
...hasList(client) ? {
|
|
308
|
-
async list(query) {
|
|
309
|
-
const boxes = await client.list(query?.providerOptions);
|
|
310
|
-
return boxes.map((box) => ({
|
|
311
|
-
id: String(box.id),
|
|
312
|
-
provider: providerName,
|
|
313
|
-
name: typeof box.name === "string" ? box.name : void 0,
|
|
314
|
-
status: statusFromUnknown(readBoxStatus(box)),
|
|
315
|
-
metadata: readBoxMetadata(box)
|
|
316
|
-
}));
|
|
317
|
-
}
|
|
318
|
-
} : {}
|
|
319
|
-
};
|
|
320
|
-
}
|
|
321
|
-
function providerAsExecutor(provider, options = {}) {
|
|
322
|
-
return (spec, ctx) => createProviderExecutor(provider, spec.profile, ctx, options);
|
|
323
|
-
}
|
|
324
|
-
function createProviderExecutor(provider, profile, ctx, options) {
|
|
325
|
-
const controller = new AbortController();
|
|
326
|
-
const abortIfSignalled = () => {
|
|
327
|
-
if (ctx.signal.aborted) controller.abort();
|
|
328
|
-
};
|
|
329
|
-
abortIfSignalled();
|
|
330
|
-
if (!ctx.signal.aborted) ctx.signal.addEventListener("abort", abortIfSignalled, { once: true });
|
|
331
|
-
let environment;
|
|
332
|
-
let artifact;
|
|
333
|
-
return {
|
|
334
|
-
runtime: options.runtime ?? provider.name,
|
|
335
|
-
execute(task, signal) {
|
|
336
|
-
return streamProviderExecutor({
|
|
337
|
-
provider,
|
|
338
|
-
profile,
|
|
339
|
-
task,
|
|
340
|
-
signal,
|
|
341
|
-
controller,
|
|
342
|
-
options,
|
|
343
|
-
onEnvironment: (env) => {
|
|
344
|
-
environment = env;
|
|
345
|
-
},
|
|
346
|
-
onArtifact: (next) => {
|
|
347
|
-
artifact = next;
|
|
348
|
-
}
|
|
349
|
-
});
|
|
350
|
-
},
|
|
351
|
-
async teardown(_grace) {
|
|
352
|
-
controller.abort();
|
|
353
|
-
await environment?.destroy?.();
|
|
354
|
-
return { destroyed: true };
|
|
355
|
-
},
|
|
356
|
-
resultArtifact() {
|
|
357
|
-
if (!artifact) {
|
|
358
|
-
throw new ValidationError(
|
|
359
|
-
`providerAsExecutor(${provider.name}): resultArtifact() read before stream drained`
|
|
360
|
-
);
|
|
361
|
-
}
|
|
362
|
-
return artifact;
|
|
363
|
-
}
|
|
364
|
-
};
|
|
365
|
-
}
|
|
366
|
-
async function* streamProviderExecutor(args) {
|
|
367
|
-
const started = Date.now();
|
|
368
|
-
const linked = mergeAbortSignals(args.signal, args.controller.signal);
|
|
369
|
-
const environment = await args.provider.create({
|
|
370
|
-
...args.options.defaults ?? {},
|
|
371
|
-
profile: args.profile,
|
|
372
|
-
signal: linked
|
|
373
|
-
});
|
|
374
|
-
args.onEnvironment(environment);
|
|
375
|
-
const turn = args.options.taskToTurn?.(args.task, args.profile) ?? taskToTurnInput(args.task, linked);
|
|
376
|
-
const events = [];
|
|
377
|
-
const tokens = zeroTokenUsage();
|
|
378
|
-
let usd = 0;
|
|
379
|
-
let text = "";
|
|
380
|
-
let terminal = false;
|
|
381
|
-
try {
|
|
382
|
-
for await (const event of environment.stream({ ...turn, signal: linked })) {
|
|
383
|
-
events.push(event);
|
|
384
|
-
text += textFromEnvironmentEvent(event);
|
|
385
|
-
const usage = usageFromEnvironmentEvent(event);
|
|
386
|
-
if (usage.input || usage.output) {
|
|
387
|
-
tokens.input += usage.input;
|
|
388
|
-
tokens.output += usage.output;
|
|
389
|
-
yield { kind: "tokens", input: usage.input, output: usage.output };
|
|
390
|
-
}
|
|
391
|
-
if (usage.usd) {
|
|
392
|
-
usd += usage.usd;
|
|
393
|
-
yield { kind: "cost", usd: usage.usd };
|
|
394
|
-
}
|
|
395
|
-
if (isTerminalEnvironmentEvent(event)) terminal = true;
|
|
396
|
-
}
|
|
397
|
-
if ((args.options.requireTerminalEvent ?? true) && !terminal) {
|
|
398
|
-
throw new ValidationError(
|
|
399
|
-
`providerAsExecutor(${args.provider.name}): stream ended without a terminal result/done/status event`
|
|
400
|
-
);
|
|
401
|
-
}
|
|
402
|
-
yield { kind: "iteration" };
|
|
403
|
-
const result = resultFromEvents(events, text);
|
|
404
|
-
const spent = {
|
|
405
|
-
iterations: 1,
|
|
406
|
-
tokens,
|
|
407
|
-
usd,
|
|
408
|
-
ms: Date.now() - started
|
|
409
|
-
};
|
|
410
|
-
args.onArtifact({
|
|
411
|
-
outRef: contentRef(`provider:${args.provider.name}`, result),
|
|
412
|
-
out: result,
|
|
413
|
-
spent
|
|
414
|
-
});
|
|
415
|
-
} finally {
|
|
416
|
-
if (args.options.destroyOnSettle ?? true) await environment.destroy?.();
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
function createInputFromSandboxOptions(options) {
|
|
420
|
-
const profile = options?.backend?.profile;
|
|
421
|
-
const backend = options?.backend?.type;
|
|
422
|
-
return {
|
|
423
|
-
...profile !== void 0 ? { profile } : {},
|
|
424
|
-
...backend ? { backend } : {},
|
|
425
|
-
workspace: {
|
|
426
|
-
...options?.environment ? { environment: options.environment } : {},
|
|
427
|
-
...options?.image ? { image: options.image } : {},
|
|
428
|
-
...options?.git?.url ? { repoUrl: options.git.url } : {},
|
|
429
|
-
...options?.git?.ref ? { gitRef: options.git.ref } : {}
|
|
430
|
-
},
|
|
431
|
-
...options?.resources ? { resources: options.resources } : {},
|
|
432
|
-
...options?.env ? { env: options.env } : {},
|
|
433
|
-
...options?.secrets ? { secrets: options.secrets } : {},
|
|
434
|
-
...options?.metadata ? { metadata: options.metadata } : {},
|
|
435
|
-
...options?.name ? { name: options.name } : {},
|
|
436
|
-
...options?.idempotencyKey ? { idempotencyKey: options.idempotencyKey } : {},
|
|
437
|
-
providerOptions: { sandboxCreateOptions: options ?? {} }
|
|
438
|
-
};
|
|
439
|
-
}
|
|
440
|
-
function sandboxOptionsFromCreateInput(input, defaultBackend) {
|
|
441
|
-
const backendType = input.backend ?? defaultBackend;
|
|
442
|
-
const workspace = input.workspace ?? {};
|
|
443
|
-
const providerOptions = input.providerOptions?.sandboxCreateOptions;
|
|
444
|
-
const base = providerOptions && typeof providerOptions === "object" ? { ...providerOptions } : {};
|
|
445
|
-
return {
|
|
446
|
-
...base,
|
|
447
|
-
...workspace.environment ? { environment: workspace.environment } : {},
|
|
448
|
-
...workspace.image ? { image: workspace.image } : {},
|
|
449
|
-
...workspace.repoUrl ? { git: { url: workspace.repoUrl, ref: workspace.gitRef } } : {},
|
|
450
|
-
...input.resources ? { resources: input.resources } : {},
|
|
451
|
-
...input.env ? { env: input.env } : {},
|
|
452
|
-
...Array.isArray(input.secrets) ? { secrets: input.secrets } : {},
|
|
453
|
-
...input.metadata ? { metadata: input.metadata } : {},
|
|
454
|
-
...input.name ? { name: input.name } : {},
|
|
455
|
-
...input.idempotencyKey ? { idempotencyKey: input.idempotencyKey } : {},
|
|
456
|
-
backend: {
|
|
457
|
-
...base.backend ?? {},
|
|
458
|
-
type: backendType,
|
|
459
|
-
profile: input.profile
|
|
460
|
-
}
|
|
461
|
-
};
|
|
462
|
-
}
|
|
463
|
-
function environmentAsSandboxInstance(environment, options) {
|
|
464
|
-
const box = {
|
|
465
|
-
id: environment.id,
|
|
466
|
-
name: environment.name,
|
|
467
|
-
status: "running",
|
|
468
|
-
async refresh() {
|
|
469
|
-
await environment.refresh?.();
|
|
470
|
-
},
|
|
471
|
-
async *streamPrompt(message, promptOptions) {
|
|
472
|
-
let terminal = false;
|
|
473
|
-
const input = turnInputFromPrompt(message, promptOptions);
|
|
474
|
-
for await (const event of environment.stream(input)) {
|
|
475
|
-
if (isTerminalEnvironmentEvent(event)) terminal = true;
|
|
476
|
-
const usageEvent = usageSandboxEvent(event);
|
|
477
|
-
if (usageEvent) yield usageEvent;
|
|
478
|
-
yield sandboxEventFromEnvironmentEvent(event);
|
|
479
|
-
}
|
|
480
|
-
if (options.requireTerminalEvent && !terminal) {
|
|
481
|
-
throw new ValidationError(
|
|
482
|
-
`providerAsSandboxClient(${environment.provider}): stream ended without a terminal result/done/status event`
|
|
483
|
-
);
|
|
484
|
-
}
|
|
485
|
-
},
|
|
486
|
-
async prompt(message, promptOptions) {
|
|
487
|
-
const events = [];
|
|
488
|
-
let text = "";
|
|
489
|
-
let usage;
|
|
490
|
-
let terminal = false;
|
|
491
|
-
for await (const event of environment.stream(turnInputFromPrompt(message, promptOptions))) {
|
|
492
|
-
events.push(event);
|
|
493
|
-
if (isTerminalEnvironmentEvent(event)) terminal = true;
|
|
494
|
-
text += textFromEnvironmentEvent(event);
|
|
495
|
-
usage = mergeTokenUsage(usage, event.usage);
|
|
496
|
-
}
|
|
497
|
-
if (options.requireTerminalEvent && !terminal) {
|
|
498
|
-
throw new ValidationError(
|
|
499
|
-
`providerAsSandboxClient(${environment.provider}): prompt ended without a terminal result/done/status event`
|
|
500
|
-
);
|
|
501
|
-
}
|
|
502
|
-
return {
|
|
503
|
-
response: resultFromEvents(events, text).content,
|
|
504
|
-
success: true,
|
|
505
|
-
durationMs: 0,
|
|
506
|
-
...usage ? { usage } : {}
|
|
507
|
-
};
|
|
508
|
-
},
|
|
509
|
-
...environment.dispatch ? {
|
|
510
|
-
async dispatchPrompt(message, promptOptions) {
|
|
511
|
-
const session = await environment.dispatch?.(
|
|
512
|
-
turnInputFromPrompt(message, promptOptions)
|
|
513
|
-
);
|
|
514
|
-
if (!session)
|
|
515
|
-
throw new ValidationError("providerAsSandboxClient: dispatch returned no session");
|
|
516
|
-
return sandboxDispatchResultFromSessionRef(session);
|
|
517
|
-
}
|
|
518
|
-
} : {},
|
|
519
|
-
...environment.session ? {
|
|
520
|
-
session(id) {
|
|
521
|
-
return sessionAsSandboxSession(environment.session?.(id));
|
|
522
|
-
}
|
|
523
|
-
} : {},
|
|
524
|
-
...environment.read ? { read: environment.read.bind(environment) } : {},
|
|
525
|
-
...environment.write ? { write: environment.write.bind(environment) } : {},
|
|
526
|
-
...environment.exec ? {
|
|
527
|
-
exec: environment.exec.bind(environment)
|
|
528
|
-
} : {},
|
|
529
|
-
...environment.checkpoint ? {
|
|
530
|
-
async checkpoint(checkpointOptions) {
|
|
531
|
-
const checkpoint = await environment.checkpoint?.(checkpointOptions);
|
|
532
|
-
return { checkpointId: checkpoint?.id, id: checkpoint?.id };
|
|
533
|
-
}
|
|
534
|
-
} : {},
|
|
535
|
-
...environment.fork ? {
|
|
536
|
-
async fork(checkpointId, forkOptions) {
|
|
537
|
-
const forked = await environment.fork?.({ id: checkpointId }, forkOptions);
|
|
538
|
-
if (!forked)
|
|
539
|
-
throw new ValidationError("providerAsSandboxClient: fork returned no environment");
|
|
540
|
-
return environmentAsSandboxInstance(forked, options);
|
|
541
|
-
}
|
|
542
|
-
} : {},
|
|
543
|
-
async delete() {
|
|
544
|
-
await environment.destroy?.();
|
|
545
|
-
}
|
|
546
|
-
};
|
|
547
|
-
return box;
|
|
548
|
-
}
|
|
549
|
-
function sandboxInstanceAsEnvironment(box, providerName, client) {
|
|
550
|
-
const environment = {
|
|
551
|
-
id: String(box.id),
|
|
552
|
-
provider: providerName,
|
|
553
|
-
...typeof box.name === "string" ? { name: box.name } : {},
|
|
554
|
-
async status() {
|
|
555
|
-
await maybeRefresh(box);
|
|
556
|
-
return statusFromUnknown(readBoxStatus(box));
|
|
557
|
-
},
|
|
558
|
-
async *stream(input) {
|
|
559
|
-
for await (const event of box.streamPrompt(
|
|
560
|
-
promptFromTurnInput(input),
|
|
561
|
-
promptOptionsFromTurnInput(input)
|
|
562
|
-
)) {
|
|
563
|
-
yield environmentEventFromSandboxEvent(event);
|
|
564
|
-
}
|
|
565
|
-
},
|
|
566
|
-
...hasDispatchPrompt(box) ? {
|
|
567
|
-
async dispatch(input) {
|
|
568
|
-
const dispatched = await box.dispatchPrompt(
|
|
569
|
-
promptFromTurnInput(input),
|
|
570
|
-
promptOptionsFromTurnInput(input)
|
|
571
|
-
);
|
|
572
|
-
return sessionRefFromSandboxDispatch(dispatched, providerName);
|
|
573
|
-
}
|
|
574
|
-
} : {},
|
|
575
|
-
...hasSession(box) ? {
|
|
576
|
-
session(id) {
|
|
577
|
-
return sandboxSessionAsAgentSession(box.session(id));
|
|
578
|
-
}
|
|
579
|
-
} : {},
|
|
580
|
-
...hasRead(box) ? { read: box.read.bind(box) } : {},
|
|
581
|
-
...hasWrite(box) ? { write: box.write.bind(box) } : {},
|
|
582
|
-
...hasExec(box) ? {
|
|
583
|
-
async exec(command, options) {
|
|
584
|
-
return execResultFromSandboxExecResult(await box.exec(command, options));
|
|
585
|
-
}
|
|
586
|
-
} : {},
|
|
587
|
-
...hasCheckpoint(box) ? {
|
|
588
|
-
async checkpoint(options) {
|
|
589
|
-
const result = await box.checkpoint(options);
|
|
590
|
-
return { id: checkpointIdFromResult(result), provider: providerName };
|
|
591
|
-
}
|
|
592
|
-
} : {},
|
|
593
|
-
...hasFork(box) ? {
|
|
594
|
-
async fork(checkpoint, options) {
|
|
595
|
-
const forked = await box.fork(checkpoint.id, options);
|
|
596
|
-
return sandboxInstanceAsEnvironment(forked, providerName, client);
|
|
597
|
-
}
|
|
598
|
-
} : {},
|
|
599
|
-
async placement() {
|
|
600
|
-
return placementInfoFromLoopPlacement(client.describePlacement?.(box), box);
|
|
601
|
-
},
|
|
602
|
-
async refresh() {
|
|
603
|
-
await maybeRefresh(box);
|
|
604
|
-
},
|
|
605
|
-
async destroy() {
|
|
606
|
-
await destroyBox(box);
|
|
607
|
-
}
|
|
608
|
-
};
|
|
609
|
-
return environment;
|
|
610
|
-
}
|
|
611
|
-
function sandboxSessionAsAgentSession(session) {
|
|
612
|
-
return {
|
|
613
|
-
id: session.id,
|
|
614
|
-
async status() {
|
|
615
|
-
const status = await session.status();
|
|
616
|
-
if (!status) return null;
|
|
617
|
-
return sessionStatusFromUnknown(status.status);
|
|
618
|
-
},
|
|
619
|
-
async *events(options) {
|
|
620
|
-
for await (const event of session.events(options))
|
|
621
|
-
yield environmentEventFromSandboxEvent(event);
|
|
622
|
-
},
|
|
623
|
-
async result() {
|
|
624
|
-
return agentTurnResultFromPromptResult(await session.result());
|
|
625
|
-
},
|
|
626
|
-
async prompt(input) {
|
|
627
|
-
return agentTurnResultFromPromptResult(
|
|
628
|
-
await session.prompt(promptFromTurnInput(input), promptOptionsFromTurnInput(input))
|
|
629
|
-
);
|
|
630
|
-
},
|
|
631
|
-
cancel() {
|
|
632
|
-
return session.cancel();
|
|
633
|
-
}
|
|
634
|
-
};
|
|
635
|
-
}
|
|
636
|
-
function sessionAsSandboxSession(session) {
|
|
637
|
-
if (!session) throw new ValidationError("providerAsSandboxClient: session(id) returned undefined");
|
|
638
|
-
return {
|
|
639
|
-
id: session.id,
|
|
640
|
-
status: session.status.bind(session),
|
|
641
|
-
async *events(options) {
|
|
642
|
-
for await (const event of session.events(options))
|
|
643
|
-
yield sandboxEventFromEnvironmentEvent(event);
|
|
644
|
-
},
|
|
645
|
-
async result() {
|
|
646
|
-
return promptResultFromAgentTurnResult(await session.result());
|
|
647
|
-
},
|
|
648
|
-
async prompt(message, options) {
|
|
649
|
-
return promptResultFromAgentTurnResult(
|
|
650
|
-
await session.prompt(turnInputFromPrompt(message, options))
|
|
651
|
-
);
|
|
652
|
-
},
|
|
653
|
-
cancel: session.cancel.bind(session)
|
|
654
|
-
};
|
|
655
|
-
}
|
|
656
|
-
function environmentEventFromSandboxEvent(event) {
|
|
657
|
-
const data = event.data && typeof event.data === "object" ? event.data : {};
|
|
658
|
-
return {
|
|
659
|
-
type: String(event.type),
|
|
660
|
-
data,
|
|
661
|
-
...event.id ? { id: event.id } : {},
|
|
662
|
-
usage: tokenUsageFromData(data),
|
|
663
|
-
providerEvent: event
|
|
664
|
-
};
|
|
665
|
-
}
|
|
666
|
-
function sandboxEventFromEnvironmentEvent(event) {
|
|
667
|
-
return {
|
|
668
|
-
type: event.type,
|
|
669
|
-
data: {
|
|
670
|
-
...event.data,
|
|
671
|
-
...event.usage ? { usage: tokenUsageData(event.usage) } : {}
|
|
672
|
-
},
|
|
673
|
-
...event.id ? { id: event.id } : {}
|
|
674
|
-
};
|
|
675
|
-
}
|
|
676
|
-
function usageSandboxEvent(event) {
|
|
677
|
-
if (!event.usage || isUsageType(event.type)) return void 0;
|
|
678
|
-
const usage = tokenUsageData(event.usage);
|
|
679
|
-
if (usage.inputTokens === void 0 && usage.outputTokens === void 0 && usage.totalCostUsd === void 0) {
|
|
680
|
-
return void 0;
|
|
681
|
-
}
|
|
682
|
-
return { type: "llm_call", data: usage };
|
|
683
|
-
}
|
|
684
|
-
function tokenUsageData(usage) {
|
|
685
|
-
return {
|
|
686
|
-
inputTokens: usage.inputTokens,
|
|
687
|
-
outputTokens: usage.outputTokens,
|
|
688
|
-
totalCostUsd: usage.cost
|
|
689
|
-
};
|
|
690
|
-
}
|
|
691
|
-
function turnInputFromPrompt(message, options) {
|
|
692
|
-
return {
|
|
693
|
-
...typeof message === "string" ? { prompt: message } : { parts: message },
|
|
694
|
-
...options?.sessionId ? { sessionId: options.sessionId } : {},
|
|
695
|
-
...options?.model ? { model: options.model } : {},
|
|
696
|
-
...options?.timeoutMs ? { timeoutMs: options.timeoutMs } : {},
|
|
697
|
-
...options?.executionId ? { executionId: options.executionId } : {},
|
|
698
|
-
...options?.lastEventId ? { lastEventId: options.lastEventId } : {},
|
|
699
|
-
...options?.turnId ? { turnId: options.turnId } : {},
|
|
700
|
-
...options?.detach !== void 0 ? { detach: options.detach } : {},
|
|
701
|
-
...options?.context ? { context: options.context } : {},
|
|
702
|
-
...options?.signal ? { signal: options.signal } : {},
|
|
703
|
-
...options?.backend ? { providerOptions: { backend: options.backend } } : {}
|
|
704
|
-
};
|
|
705
|
-
}
|
|
706
|
-
function promptFromTurnInput(input) {
|
|
707
|
-
if (input.parts) return input.parts;
|
|
708
|
-
return input.prompt ?? "";
|
|
709
|
-
}
|
|
710
|
-
function promptOptionsFromTurnInput(input) {
|
|
711
|
-
return {
|
|
712
|
-
...input.sessionId ? { sessionId: input.sessionId } : {},
|
|
713
|
-
...input.model ? { model: input.model } : {},
|
|
714
|
-
...input.timeoutMs ? { timeoutMs: input.timeoutMs } : {},
|
|
715
|
-
...input.context ? { context: input.context } : {},
|
|
716
|
-
...input.signal ? { signal: input.signal } : {},
|
|
717
|
-
...input.executionId ? { executionId: input.executionId } : {},
|
|
718
|
-
...input.lastEventId ? { lastEventId: input.lastEventId } : {},
|
|
719
|
-
...input.turnId ? { turnId: input.turnId } : {},
|
|
720
|
-
...input.detach !== void 0 ? { detach: input.detach } : {}
|
|
721
|
-
};
|
|
722
|
-
}
|
|
723
|
-
function taskToTurnInput(task, signal) {
|
|
724
|
-
return { prompt: taskToPrompt(task), signal };
|
|
725
|
-
}
|
|
726
|
-
function taskToPrompt(task) {
|
|
727
|
-
if (typeof task === "string") return task;
|
|
728
|
-
if (task && typeof task === "object") {
|
|
729
|
-
const record = task;
|
|
730
|
-
for (const key of ["prompt", "content", "task", "message"]) {
|
|
731
|
-
if (typeof record[key] === "string") return record[key];
|
|
732
|
-
}
|
|
733
|
-
}
|
|
734
|
-
return JSON.stringify(task);
|
|
735
|
-
}
|
|
736
|
-
function resultFromEvents(events, fallbackText) {
|
|
737
|
-
for (let i = events.length - 1; i >= 0; i -= 1) {
|
|
738
|
-
const event = events[i];
|
|
739
|
-
const text = event ? resultTextFromData(event.data) : void 0;
|
|
740
|
-
if (text !== void 0) return { content: text, events };
|
|
741
|
-
}
|
|
742
|
-
return { content: fallbackText, events };
|
|
743
|
-
}
|
|
744
|
-
function textFromEnvironmentEvent(event) {
|
|
745
|
-
if (typeof event.normalized === "object" && event.normalized && event.normalized.type === "message.part.updated") {
|
|
746
|
-
return typeof event.normalized.delta === "string" ? event.normalized.delta : "";
|
|
747
|
-
}
|
|
748
|
-
const data = event.data;
|
|
749
|
-
for (const key of ["delta", "chunk", "content", "text"]) {
|
|
750
|
-
if (typeof data[key] === "string" && !isTerminalEnvironmentEvent(event)) return data[key];
|
|
751
|
-
}
|
|
752
|
-
return "";
|
|
753
|
-
}
|
|
754
|
-
function resultTextFromData(data) {
|
|
755
|
-
for (const key of ["finalText", "text", "response", "resultSummary", "content"]) {
|
|
756
|
-
if (typeof data[key] === "string") return data[key];
|
|
757
|
-
}
|
|
758
|
-
return void 0;
|
|
759
|
-
}
|
|
760
|
-
function isTerminalEnvironmentEvent(event) {
|
|
761
|
-
if (event.type === "result" || event.type === "done" || event.type === "final") return true;
|
|
762
|
-
if (event.type.endsWith(".completed") || event.type.endsWith(".failed")) return true;
|
|
763
|
-
if (event.type === "status") {
|
|
764
|
-
const status = event.data.status;
|
|
765
|
-
return status === "completed" || status === "failed" || status === "cancelled";
|
|
766
|
-
}
|
|
767
|
-
return false;
|
|
768
|
-
}
|
|
769
|
-
function isUsageType(type) {
|
|
770
|
-
return type === "llm_call" || type === "usage" || type === "cost.usage";
|
|
771
|
-
}
|
|
772
|
-
function usageFromEnvironmentEvent(event) {
|
|
773
|
-
const usage = event.usage ?? tokenUsageFromData(event.data);
|
|
774
|
-
return {
|
|
775
|
-
input: finiteNumber(usage?.inputTokens) ?? 0,
|
|
776
|
-
output: finiteNumber(usage?.outputTokens) ?? 0,
|
|
777
|
-
usd: finiteNumber(usage?.cost) ?? finiteNumber(event.data.costUsd) ?? finiteNumber(event.data.totalCostUsd) ?? 0
|
|
778
|
-
};
|
|
779
|
-
}
|
|
780
|
-
function tokenUsageFromData(data) {
|
|
781
|
-
const usageRecord = data.usage && typeof data.usage === "object" ? data.usage : data.tokenUsage && typeof data.tokenUsage === "object" ? data.tokenUsage : data;
|
|
782
|
-
const inputTokens = finiteNumber(usageRecord.inputTokens) ?? finiteNumber(usageRecord.tokensIn) ?? finiteNumber(usageRecord.prompt_tokens);
|
|
783
|
-
const outputTokens = finiteNumber(usageRecord.outputTokens) ?? finiteNumber(usageRecord.tokensOut) ?? finiteNumber(usageRecord.completion_tokens);
|
|
784
|
-
const cost = finiteNumber(usageRecord.cost) ?? finiteNumber(usageRecord.costUsd) ?? finiteNumber(usageRecord.totalCostUsd) ?? finiteNumber(data.costUsd) ?? finiteNumber(data.totalCostUsd);
|
|
785
|
-
if (inputTokens === void 0 && outputTokens === void 0 && cost === void 0)
|
|
786
|
-
return void 0;
|
|
787
|
-
return {
|
|
788
|
-
inputTokens: inputTokens ?? 0,
|
|
789
|
-
outputTokens: outputTokens ?? 0,
|
|
790
|
-
...cost !== void 0 ? { cost } : {}
|
|
791
|
-
};
|
|
792
|
-
}
|
|
793
|
-
function mergeTokenUsage(left, right) {
|
|
794
|
-
if (!left) return right;
|
|
795
|
-
if (!right) return left;
|
|
796
|
-
return {
|
|
797
|
-
inputTokens: left.inputTokens + right.inputTokens,
|
|
798
|
-
outputTokens: left.outputTokens + right.outputTokens,
|
|
799
|
-
...left.cost !== void 0 || right.cost !== void 0 ? { cost: (left.cost ?? 0) + (right.cost ?? 0) } : {}
|
|
800
|
-
};
|
|
801
|
-
}
|
|
802
|
-
function finiteNumber(value) {
|
|
803
|
-
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
804
|
-
}
|
|
805
|
-
function promptResultFromAgentTurnResult(result) {
|
|
806
|
-
return {
|
|
807
|
-
response: result.text,
|
|
808
|
-
success: result.success,
|
|
809
|
-
durationMs: 0,
|
|
810
|
-
...result.error ? { error: result.error } : {},
|
|
811
|
-
...result.usage ? { usage: result.usage } : {}
|
|
812
|
-
};
|
|
813
|
-
}
|
|
814
|
-
function agentTurnResultFromPromptResult(result) {
|
|
815
|
-
const record = result;
|
|
816
|
-
const text = typeof record.response === "string" ? record.response : typeof record.text === "string" ? record.text : typeof record.finalText === "string" ? record.finalText : "";
|
|
817
|
-
const success = typeof record.success === "boolean" ? record.success : true;
|
|
818
|
-
return {
|
|
819
|
-
text,
|
|
820
|
-
success,
|
|
821
|
-
...typeof record.error === "string" ? { error: record.error } : {},
|
|
822
|
-
usage: tokenUsageFromData(record)
|
|
823
|
-
};
|
|
824
|
-
}
|
|
825
|
-
function sandboxDispatchResultFromSessionRef(session) {
|
|
826
|
-
const hasStatus = session.metadata && Object.hasOwn(session.metadata, "status");
|
|
827
|
-
const status = hasStatus ? sessionStatusFromUnknown(session.metadata?.status) : "running";
|
|
828
|
-
return {
|
|
829
|
-
sessionId: session.id,
|
|
830
|
-
status,
|
|
831
|
-
alreadyExisted: session.metadata?.alreadyExisted === true
|
|
832
|
-
};
|
|
833
|
-
}
|
|
834
|
-
function sessionRefFromSandboxDispatch(dispatched, providerName) {
|
|
835
|
-
const record = dispatched && typeof dispatched === "object" ? dispatched : void 0;
|
|
836
|
-
const id = record?.sessionId ?? record?.id;
|
|
837
|
-
if (typeof id !== "string" || id.length === 0) {
|
|
838
|
-
throw new ValidationError("sandboxClientAsProvider: dispatch returned no session id");
|
|
839
|
-
}
|
|
840
|
-
if (!record) {
|
|
841
|
-
throw new ValidationError("sandboxClientAsProvider: dispatch returned no session record");
|
|
842
|
-
}
|
|
843
|
-
return {
|
|
844
|
-
id,
|
|
845
|
-
provider: providerName,
|
|
846
|
-
metadata: {
|
|
847
|
-
...record.status ? { status: record.status } : {},
|
|
848
|
-
...record.alreadyExisted !== void 0 ? { alreadyExisted: record.alreadyExisted } : {}
|
|
849
|
-
}
|
|
850
|
-
};
|
|
851
|
-
}
|
|
852
|
-
function execResultFromSandboxExecResult(result) {
|
|
853
|
-
const record = result;
|
|
854
|
-
const exitCode = finiteNumber(record.exitCode) ?? finiteNumber(record.code);
|
|
855
|
-
if (exitCode === void 0) {
|
|
856
|
-
throw new ValidationError("sandboxClientAsProvider: exec returned no exit code");
|
|
857
|
-
}
|
|
858
|
-
return {
|
|
859
|
-
exitCode,
|
|
860
|
-
stdout: typeof record.stdout === "string" ? record.stdout : "",
|
|
861
|
-
stderr: typeof record.stderr === "string" ? record.stderr : ""
|
|
862
|
-
};
|
|
863
|
-
}
|
|
864
|
-
function statusFromUnknown(status) {
|
|
865
|
-
if (status === "pending" || status === "provisioning" || status === "running") return status;
|
|
866
|
-
if (status === "stopped" || status === "failed" || status === "expired") return status;
|
|
867
|
-
if (status === "completed") return "stopped";
|
|
868
|
-
if (status === "cancelled") return "stopped";
|
|
869
|
-
return "unknown";
|
|
870
|
-
}
|
|
871
|
-
function sessionStatusFromUnknown(status) {
|
|
872
|
-
if (status === "completed" || status === "cancelled") return status;
|
|
873
|
-
return statusFromUnknown(status);
|
|
874
|
-
}
|
|
875
|
-
function readBoxStatus(box) {
|
|
876
|
-
return box.status;
|
|
877
|
-
}
|
|
878
|
-
function readBoxMetadata(box) {
|
|
879
|
-
const metadata = box.metadata;
|
|
880
|
-
return metadata && typeof metadata === "object" ? metadata : void 0;
|
|
881
|
-
}
|
|
882
|
-
async function maybeRefresh(box) {
|
|
883
|
-
const refresh = box.refresh;
|
|
884
|
-
if (typeof refresh === "function") await refresh.call(box);
|
|
885
|
-
}
|
|
886
|
-
async function destroyBox(box) {
|
|
887
|
-
const deleteBox = box.delete;
|
|
888
|
-
if (typeof deleteBox === "function") await deleteBox.call(box);
|
|
889
|
-
}
|
|
890
|
-
function placementInfoFromLoopPlacement(placement, box) {
|
|
891
|
-
if (!placement) return { kind: "sandbox", sandboxId: String(box.id) };
|
|
892
|
-
return {
|
|
893
|
-
kind: placement.kind === "fleet" ? "fleet" : "sandbox",
|
|
894
|
-
...placement.sandboxId ? { sandboxId: placement.sandboxId } : { sandboxId: String(box.id) },
|
|
895
|
-
...placement.fleetId ? { fleetId: placement.fleetId } : {},
|
|
896
|
-
...placement.machineId ? { machineId: placement.machineId } : {}
|
|
897
|
-
};
|
|
898
|
-
}
|
|
899
|
-
function checkpointIdFromResult(result) {
|
|
900
|
-
const record = result && typeof result === "object" ? result : {};
|
|
901
|
-
const id = record.checkpointId ?? record.id;
|
|
902
|
-
if (typeof id !== "string" || id.length === 0) {
|
|
903
|
-
throw new ValidationError("sandboxClientAsProvider: checkpoint returned no checkpoint id");
|
|
904
|
-
}
|
|
905
|
-
return id;
|
|
906
|
-
}
|
|
907
|
-
function defaultTangleSandboxCapabilities() {
|
|
908
|
-
return {
|
|
909
|
-
profile: {
|
|
910
|
-
namedProfiles: true,
|
|
911
|
-
systemPrompt: true,
|
|
912
|
-
instructions: true,
|
|
913
|
-
tools: true,
|
|
914
|
-
permissions: true,
|
|
915
|
-
mcp: true,
|
|
916
|
-
subagents: true,
|
|
917
|
-
resources: {
|
|
918
|
-
files: true,
|
|
919
|
-
instructions: true,
|
|
920
|
-
tools: true,
|
|
921
|
-
skills: true,
|
|
922
|
-
agents: true,
|
|
923
|
-
commands: true
|
|
924
|
-
},
|
|
925
|
-
hooks: true,
|
|
926
|
-
modes: true,
|
|
927
|
-
runtimeUpdate: true,
|
|
928
|
-
validation: true
|
|
929
|
-
},
|
|
930
|
-
streaming: { live: true, replay: true, detach: true, turnIdempotency: true },
|
|
931
|
-
sessions: { continue: true, list: true, messages: true },
|
|
932
|
-
workspace: { read: true, write: true, exec: true, git: true, upload: true, download: true },
|
|
933
|
-
branching: { checkpoint: true, fork: true },
|
|
934
|
-
placement: true,
|
|
935
|
-
usage: true,
|
|
936
|
-
confidential: true
|
|
937
|
-
};
|
|
938
|
-
}
|
|
939
|
-
function mergeAbortSignals(a, b) {
|
|
940
|
-
const controller = new AbortController();
|
|
941
|
-
const abort = () => controller.abort();
|
|
942
|
-
if (a.aborted || b.aborted) controller.abort();
|
|
943
|
-
else {
|
|
944
|
-
a.addEventListener("abort", abort, { once: true });
|
|
945
|
-
b.addEventListener("abort", abort, { once: true });
|
|
946
|
-
}
|
|
947
|
-
return controller.signal;
|
|
948
|
-
}
|
|
949
|
-
function contentRef(prefix, value) {
|
|
950
|
-
let str;
|
|
951
|
-
try {
|
|
952
|
-
str = JSON.stringify(value) ?? String(value);
|
|
953
|
-
} catch {
|
|
954
|
-
str = String(value);
|
|
955
|
-
}
|
|
956
|
-
let hash = 2166136261;
|
|
957
|
-
for (let i = 0; i < str.length; i += 1) {
|
|
958
|
-
hash ^= str.charCodeAt(i);
|
|
959
|
-
hash = Math.imul(hash, 16777619);
|
|
960
|
-
}
|
|
961
|
-
return `${prefix}:${(hash >>> 0).toString(16).padStart(8, "0")}`;
|
|
962
|
-
}
|
|
963
|
-
function hasGet(client) {
|
|
964
|
-
return typeof client.get === "function";
|
|
965
|
-
}
|
|
966
|
-
function hasList(client) {
|
|
967
|
-
return typeof client.list === "function";
|
|
968
|
-
}
|
|
969
|
-
function hasDispatchPrompt(box) {
|
|
970
|
-
return typeof box.dispatchPrompt === "function";
|
|
971
|
-
}
|
|
972
|
-
function hasSession(box) {
|
|
973
|
-
return typeof box.session === "function";
|
|
974
|
-
}
|
|
975
|
-
function hasRead(box) {
|
|
976
|
-
return typeof box.read === "function";
|
|
977
|
-
}
|
|
978
|
-
function hasWrite(box) {
|
|
979
|
-
return typeof box.write === "function";
|
|
980
|
-
}
|
|
981
|
-
function hasExec(box) {
|
|
982
|
-
return typeof box.exec === "function";
|
|
983
|
-
}
|
|
984
|
-
function hasCheckpoint(box) {
|
|
985
|
-
return typeof box.checkpoint === "function";
|
|
986
|
-
}
|
|
987
|
-
function hasFork(box) {
|
|
988
|
-
return typeof box.fork === "function";
|
|
989
|
-
}
|
|
990
|
-
|
|
991
114
|
// src/runtime-hooks.ts
|
|
992
115
|
function defineRuntimeHooks(hooks) {
|
|
993
116
|
return hooks;
|
|
@@ -1770,13 +893,13 @@ async function executeIteration(args) {
|
|
|
1770
893
|
await destroySandboxSafe(box, args.ctx.traceEmitter, args.runId, args.now);
|
|
1771
894
|
}
|
|
1772
895
|
}
|
|
1773
|
-
if (
|
|
896
|
+
if (isAbortError(slot.error) || args.signal.aborted) {
|
|
1774
897
|
if (slot.error) throw slot.error;
|
|
1775
898
|
throwAbort();
|
|
1776
899
|
}
|
|
1777
900
|
if (slot.error instanceof ValidationError) throw slot.error;
|
|
1778
901
|
}
|
|
1779
|
-
function
|
|
902
|
+
function isAbortError(err) {
|
|
1780
903
|
return err instanceof Error && err.name === "AbortError";
|
|
1781
904
|
}
|
|
1782
905
|
var TEARDOWN_TIMEOUT_MS2 = 15e3;
|
|
@@ -2384,7 +1507,7 @@ async function runChild(live, executor, childAbort, task, opts, pool, ticket, bl
|
|
|
2384
1507
|
} catch (err) {
|
|
2385
1508
|
reconcileOnce(live.spent);
|
|
2386
1509
|
await teardownSafe(executor, "brutalKill");
|
|
2387
|
-
const aborted = childAbort.signal.aborted ||
|
|
1510
|
+
const aborted = childAbort.signal.aborted || isAbortError2(err);
|
|
2388
1511
|
return downRecord(errMessage(err), aborted || isInfraError(err), executor.metered?.());
|
|
2389
1512
|
}
|
|
2390
1513
|
}
|
|
@@ -2486,7 +1609,7 @@ function isAgentSpec(value) {
|
|
|
2486
1609
|
const v = value;
|
|
2487
1610
|
return "profile" in v && "harness" in v;
|
|
2488
1611
|
}
|
|
2489
|
-
function
|
|
1612
|
+
function isAbortError2(err) {
|
|
2490
1613
|
return typeof err === "object" && err !== null && "name" in err && err.name === "AbortError";
|
|
2491
1614
|
}
|
|
2492
1615
|
function isInfraError(err) {
|
|
@@ -2988,7 +2111,7 @@ var cliSeamKey = "cli";
|
|
|
2988
2111
|
var bridgeSeamKey = "bridge";
|
|
2989
2112
|
var cliWorktreeSeamKey = "cli-worktree";
|
|
2990
2113
|
var providerSeamKey = "provider";
|
|
2991
|
-
function
|
|
2114
|
+
function contentRef(prefix, value) {
|
|
2992
2115
|
let str;
|
|
2993
2116
|
try {
|
|
2994
2117
|
str = JSON.stringify(value) ?? String(value);
|
|
@@ -3041,7 +2164,7 @@ var routerInlineExecutor = (spec, ctx) => {
|
|
|
3041
2164
|
ms: Date.now() - started
|
|
3042
2165
|
};
|
|
3043
2166
|
const out = { content: r.content };
|
|
3044
|
-
artifact = { outRef:
|
|
2167
|
+
artifact = { outRef: contentRef("router", { model, content: r.content }), out, spent };
|
|
3045
2168
|
return artifact;
|
|
3046
2169
|
},
|
|
3047
2170
|
teardown(_grace) {
|
|
@@ -3095,7 +2218,7 @@ var routerToolsInlineExecutor = (spec, ctx) => {
|
|
|
3095
2218
|
if (pending.length) messages.push({ role: "user", content: inbox.fold(pending) });
|
|
3096
2219
|
return pending.length > 0;
|
|
3097
2220
|
};
|
|
3098
|
-
const external =
|
|
2221
|
+
const external = mergeAbortSignals(signal, controller.signal);
|
|
3099
2222
|
for (let t = 0; t < maxTurns; t += 1) {
|
|
3100
2223
|
flush();
|
|
3101
2224
|
const interruptSig = inbox.freshInterrupt();
|
|
@@ -3199,7 +2322,7 @@ var routerToolsInlineExecutor = (spec, ctx) => {
|
|
|
3199
2322
|
const usd = isModelPriced2(model) ? estimateCost2(tokens.input, tokens.output, model) : 0;
|
|
3200
2323
|
const spent = { iterations: turns, tokens, usd, ms: Date.now() - started };
|
|
3201
2324
|
const out = { content: lastText };
|
|
3202
|
-
artifact = { outRef:
|
|
2325
|
+
artifact = { outRef: contentRef("router-tools", { model, content: lastText }), out, spent };
|
|
3203
2326
|
return artifact;
|
|
3204
2327
|
},
|
|
3205
2328
|
teardown(_grace) {
|
|
@@ -3283,7 +2406,7 @@ async function* streamSandboxLeaf(args) {
|
|
|
3283
2406
|
}
|
|
3284
2407
|
const agentRun = {
|
|
3285
2408
|
profile: args.spec.profile,
|
|
3286
|
-
taskToPrompt: (t) =>
|
|
2409
|
+
taskToPrompt: (t) => taskToPrompt(t),
|
|
3287
2410
|
name: args.spec.profile.name ?? args.harness,
|
|
3288
2411
|
sandboxOverrides: { backend: { type: args.harness } }
|
|
3289
2412
|
};
|
|
@@ -3313,7 +2436,7 @@ async function* streamSandboxLeaf(args) {
|
|
|
3313
2436
|
ms: Date.now() - started
|
|
3314
2437
|
};
|
|
3315
2438
|
args.onArtifact({
|
|
3316
|
-
outRef:
|
|
2439
|
+
outRef: contentRef("sandbox", { harness: args.harness, out }),
|
|
3317
2440
|
out,
|
|
3318
2441
|
...verdict ? { verdict } : {},
|
|
3319
2442
|
spent
|
|
@@ -3370,7 +2493,7 @@ var cliExecutor = (_spec, ctx) => {
|
|
|
3370
2493
|
};
|
|
3371
2494
|
};
|
|
3372
2495
|
async function* streamCliLeaf(args) {
|
|
3373
|
-
const prompt =
|
|
2496
|
+
const prompt = taskToPrompt(args.task);
|
|
3374
2497
|
const proc = spawn3(args.seam.bin, args.seam.args ?? [], {
|
|
3375
2498
|
...args.seam.cwd ? { cwd: args.seam.cwd } : {},
|
|
3376
2499
|
env: { ...process.env, ...args.seam.env ?? {} },
|
|
@@ -3408,7 +2531,7 @@ async function* streamCliLeaf(args) {
|
|
|
3408
2531
|
);
|
|
3409
2532
|
}
|
|
3410
2533
|
const out = { content: chunks.join("") };
|
|
3411
|
-
args.onArtifact({ outRef:
|
|
2534
|
+
args.onArtifact({ outRef: contentRef("cli", out), out, spent: zeroSpend2() });
|
|
3412
2535
|
yield { kind: "iteration" };
|
|
3413
2536
|
}
|
|
3414
2537
|
function killWithGrace(proc, grace) {
|
|
@@ -3481,13 +2604,13 @@ async function* streamBridgeSession(args) {
|
|
|
3481
2604
|
const { seam, inbox } = args;
|
|
3482
2605
|
const started = Date.now();
|
|
3483
2606
|
const url = `${seam.bridgeUrl.replace(/\/$/, "")}/v1/chat/completions`;
|
|
3484
|
-
const external =
|
|
2607
|
+
const external = mergeAbortSignals(args.signal, args.controller.signal);
|
|
3485
2608
|
const tokens = zeroTokenUsage();
|
|
3486
2609
|
let usd = 0;
|
|
3487
2610
|
let turns = 0;
|
|
3488
2611
|
let lastText = "";
|
|
3489
2612
|
const toolCalls = [];
|
|
3490
|
-
let nextPrompt =
|
|
2613
|
+
let nextPrompt = taskToPrompt(args.task);
|
|
3491
2614
|
const system = args.spec.profile.prompt?.systemPrompt;
|
|
3492
2615
|
for (let t = 0; t < args.maxTurns; t += 1) {
|
|
3493
2616
|
const pending = inbox.drain();
|
|
@@ -3582,7 +2705,7 @@ ${folded}` : folded;
|
|
|
3582
2705
|
};
|
|
3583
2706
|
const out = { content: lastText, toolCalls };
|
|
3584
2707
|
args.onArtifact({
|
|
3585
|
-
outRef:
|
|
2708
|
+
outRef: contentRef("bridge", { model: seam.model, session: args.sessionId, content: lastText }),
|
|
3586
2709
|
out,
|
|
3587
2710
|
spent
|
|
3588
2711
|
});
|
|
@@ -3733,7 +2856,7 @@ function readSeam(ctx, key, who) {
|
|
|
3733
2856
|
}
|
|
3734
2857
|
return seam;
|
|
3735
2858
|
}
|
|
3736
|
-
function
|
|
2859
|
+
function taskToPrompt(task) {
|
|
3737
2860
|
if (typeof task === "string") return task;
|
|
3738
2861
|
if (task && typeof task === "object") {
|
|
3739
2862
|
const obj = task;
|
|
@@ -3749,7 +2872,7 @@ function taskToMessages(task, spec) {
|
|
|
3749
2872
|
if (typeof system === "string" && system.length > 0) {
|
|
3750
2873
|
messages.push({ role: "system", content: system });
|
|
3751
2874
|
}
|
|
3752
|
-
messages.push({ role: "user", content:
|
|
2875
|
+
messages.push({ role: "user", content: taskToPrompt(task) });
|
|
3753
2876
|
return messages;
|
|
3754
2877
|
}
|
|
3755
2878
|
function singleShotDriver(maxIterations) {
|
|
@@ -3775,7 +2898,7 @@ function linkSignals2(a, b) {
|
|
|
3775
2898
|
b.addEventListener("abort", onAbort, { once: true });
|
|
3776
2899
|
return c.signal;
|
|
3777
2900
|
}
|
|
3778
|
-
function
|
|
2901
|
+
function mergeAbortSignals(...signals) {
|
|
3779
2902
|
const c = new AbortController();
|
|
3780
2903
|
const onAbort = () => c.abort();
|
|
3781
2904
|
for (const s of signals) {
|
|
@@ -6963,23 +6086,9 @@ function routerBrainFromProfile(profile, deps) {
|
|
|
6963
6086
|
|
|
6964
6087
|
export {
|
|
6965
6088
|
assertModelAllowed,
|
|
6966
|
-
deleteBoxSafe,
|
|
6967
|
-
randomSuffix,
|
|
6968
|
-
throwAbort,
|
|
6969
|
-
throwIfAborted,
|
|
6970
|
-
isAbortError,
|
|
6971
|
-
sleep,
|
|
6972
|
-
stringifySafe,
|
|
6973
|
-
zeroTokenUsage,
|
|
6974
|
-
addTokenUsage,
|
|
6975
6089
|
contentAddress,
|
|
6976
6090
|
InMemoryResultBlobStore,
|
|
6977
6091
|
InMemorySpawnJournal,
|
|
6978
|
-
createAgentEnvironmentProviderRegistry,
|
|
6979
|
-
resolveAgentEnvironmentProvider,
|
|
6980
|
-
providerAsSandboxClient,
|
|
6981
|
-
sandboxClientAsProvider,
|
|
6982
|
-
providerAsExecutor,
|
|
6983
6092
|
defineRuntimeHooks,
|
|
6984
6093
|
composeRuntimeHooks,
|
|
6985
6094
|
notifyRuntimeHookEvent,
|
|
@@ -7069,4 +6178,4 @@ export {
|
|
|
7069
6178
|
createInProcessTransport,
|
|
7070
6179
|
serveCoordinationMcp
|
|
7071
6180
|
};
|
|
7072
|
-
//# sourceMappingURL=chunk-
|
|
6181
|
+
//# sourceMappingURL=chunk-TSDKBFZP.js.map
|