@tangle-network/agent-runtime 0.77.0 → 0.79.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent.d.ts +1 -1
- package/dist/agent.js +3 -3
- package/dist/analyst-loop.d.ts +1 -1
- package/dist/{chunk-O2UPHN7X.js → chunk-5JAUQZQA.js} +1 -1
- package/dist/chunk-5JAUQZQA.js.map +1 -0
- package/dist/{chunk-RQYPH2QE.js → chunk-EZ2QESTP.js} +871 -33
- package/dist/chunk-EZ2QESTP.js.map +1 -0
- package/dist/{chunk-LFL7K5FM.js → chunk-F6G3SSHY.js} +2 -2
- package/dist/{chunk-KKHMDE5I.js → chunk-GZX3PI7V.js} +3 -3
- package/dist/{chunk-JPURCA2O.js → chunk-LWGVVP2C.js} +2 -2
- package/dist/{chunk-CEW5BMGN.js → chunk-N2JJDGLJ.js} +2 -2
- package/dist/chunk-N2JJDGLJ.js.map +1 -0
- package/dist/{coordination-CZe4lTxy.d.ts → coordination-09JTQnlF.d.ts} +88 -25
- package/dist/index.d.ts +9 -9
- package/dist/index.js +6 -6
- package/dist/intelligence.d.ts +1 -1
- package/dist/lifecycle.d.ts +2 -2
- package/dist/lifecycle.js +2 -2
- package/dist/{local-harness-BE_h8szs.d.ts → local-harness-DU7yV6mG.d.ts} +1 -1
- package/dist/{loop-runner-bin-Dbtg787n.d.ts → loop-runner-bin-Ddgf4DkS.d.ts} +2 -2
- package/dist/loop-runner-bin.d.ts +5 -5
- package/dist/loop-runner-bin.js +4 -4
- package/dist/loops.d.ts +12 -11
- package/dist/loops.js +13 -3
- package/dist/mcp/bin.js +2 -2
- package/dist/mcp/bin.js.map +1 -1
- package/dist/mcp/index.d.ts +12 -12
- package/dist/mcp/index.js +4 -4
- package/dist/mcp/index.js.map +1 -1
- package/dist/{mcp-serve-verifier-CT1KLTG_.d.ts → mcp-serve-verifier-BvMAV_8U.d.ts} +1 -1
- package/dist/{openai-tools-D5tcirFF.d.ts → openai-tools-B-3v06BE.d.ts} +1 -1
- package/dist/profiles.d.ts +1 -1
- package/dist/{types-B-jWSfcu.d.ts → types-BF-MEsQB.d.ts} +21 -0
- package/dist/{worktree-CDxqwxGo.d.ts → worktree-CUn0d-ZT.d.ts} +2 -2
- package/dist/{worktree-fanout-CljF1L2v.d.ts → worktree-fanout-DwwatTdY.d.ts} +3 -3
- package/package.json +3 -7
- package/dist/chunk-CEW5BMGN.js.map +0 -1
- package/dist/chunk-O2UPHN7X.js.map +0 -1
- package/dist/chunk-RQYPH2QE.js.map +0 -1
- /package/dist/{chunk-LFL7K5FM.js.map → chunk-F6G3SSHY.js.map} +0 -0
- /package/dist/{chunk-KKHMDE5I.js.map → chunk-GZX3PI7V.js.map} +0 -0
- /package/dist/{chunk-JPURCA2O.js.map → chunk-LWGVVP2C.js.map} +0 -0
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
import {
|
|
8
8
|
harnessInvocation,
|
|
9
9
|
runLocalHarness
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-5JAUQZQA.js";
|
|
11
11
|
import {
|
|
12
12
|
AgentEvalError,
|
|
13
13
|
ConfigError,
|
|
@@ -208,6 +208,786 @@ function assertSeqUnique(root, events, ev) {
|
|
|
208
208
|
}
|
|
209
209
|
}
|
|
210
210
|
|
|
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
|
+
|
|
211
991
|
// src/runtime-hooks.ts
|
|
212
992
|
function defineRuntimeHooks(hooks) {
|
|
213
993
|
return hooks;
|
|
@@ -930,6 +1710,20 @@ async function executeIteration(args) {
|
|
|
930
1710
|
const events = [];
|
|
931
1711
|
for await (const event of stream) {
|
|
932
1712
|
events.push(event);
|
|
1713
|
+
if (args.ctx.onSandboxEvent) {
|
|
1714
|
+
try {
|
|
1715
|
+
const observerEvent = cloneEventForObserver(event);
|
|
1716
|
+
const result = args.ctx.onSandboxEvent(observerEvent, {
|
|
1717
|
+
iterationIndex: args.item.index,
|
|
1718
|
+
agentRunName: slot.agentRunName
|
|
1719
|
+
});
|
|
1720
|
+
if (result && typeof result.then === "function") {
|
|
1721
|
+
void result.then(void 0, () => {
|
|
1722
|
+
});
|
|
1723
|
+
}
|
|
1724
|
+
} catch {
|
|
1725
|
+
}
|
|
1726
|
+
}
|
|
933
1727
|
const llmCall = extractLlmCallEvent(event, slot.agentRunName);
|
|
934
1728
|
if (llmCall) {
|
|
935
1729
|
slot.costUsd += llmCall.costUsd ?? 0;
|
|
@@ -1206,6 +2000,30 @@ async function emitTrace(emitter, event) {
|
|
|
1206
2000
|
if (!emitter) return;
|
|
1207
2001
|
await emitter.emit(event);
|
|
1208
2002
|
}
|
|
2003
|
+
function cloneEventForObserver(event) {
|
|
2004
|
+
try {
|
|
2005
|
+
return structuredClone(event);
|
|
2006
|
+
} catch {
|
|
2007
|
+
return copyPlainSpine(event, /* @__PURE__ */ new WeakMap());
|
|
2008
|
+
}
|
|
2009
|
+
}
|
|
2010
|
+
function copyPlainSpine(value, seen) {
|
|
2011
|
+
if (value === null || typeof value !== "object") return value;
|
|
2012
|
+
const existing = seen.get(value);
|
|
2013
|
+
if (existing !== void 0) return existing;
|
|
2014
|
+
if (Array.isArray(value)) {
|
|
2015
|
+
const copy2 = [];
|
|
2016
|
+
seen.set(value, copy2);
|
|
2017
|
+
for (const item of value) copy2.push(copyPlainSpine(item, seen));
|
|
2018
|
+
return copy2;
|
|
2019
|
+
}
|
|
2020
|
+
const proto = Object.getPrototypeOf(value);
|
|
2021
|
+
if (proto !== Object.prototype && proto !== null) return {};
|
|
2022
|
+
const copy = {};
|
|
2023
|
+
seen.set(value, copy);
|
|
2024
|
+
for (const [key, v] of Object.entries(value)) copy[key] = copyPlainSpine(v, seen);
|
|
2025
|
+
return copy;
|
|
2026
|
+
}
|
|
1209
2027
|
function hashJson(value) {
|
|
1210
2028
|
let str;
|
|
1211
2029
|
try {
|
|
@@ -2169,7 +2987,8 @@ var sandboxSeamKey = "sandbox";
|
|
|
2169
2987
|
var cliSeamKey = "cli";
|
|
2170
2988
|
var bridgeSeamKey = "bridge";
|
|
2171
2989
|
var cliWorktreeSeamKey = "cli-worktree";
|
|
2172
|
-
|
|
2990
|
+
var providerSeamKey = "provider";
|
|
2991
|
+
function contentRef2(prefix, value) {
|
|
2173
2992
|
let str;
|
|
2174
2993
|
try {
|
|
2175
2994
|
str = JSON.stringify(value) ?? String(value);
|
|
@@ -2222,7 +3041,7 @@ var routerInlineExecutor = (spec, ctx) => {
|
|
|
2222
3041
|
ms: Date.now() - started
|
|
2223
3042
|
};
|
|
2224
3043
|
const out = { content: r.content };
|
|
2225
|
-
artifact = { outRef:
|
|
3044
|
+
artifact = { outRef: contentRef2("router", { model, content: r.content }), out, spent };
|
|
2226
3045
|
return artifact;
|
|
2227
3046
|
},
|
|
2228
3047
|
teardown(_grace) {
|
|
@@ -2276,7 +3095,7 @@ var routerToolsInlineExecutor = (spec, ctx) => {
|
|
|
2276
3095
|
if (pending.length) messages.push({ role: "user", content: inbox.fold(pending) });
|
|
2277
3096
|
return pending.length > 0;
|
|
2278
3097
|
};
|
|
2279
|
-
const external =
|
|
3098
|
+
const external = mergeAbortSignals2(signal, controller.signal);
|
|
2280
3099
|
for (let t = 0; t < maxTurns; t += 1) {
|
|
2281
3100
|
flush();
|
|
2282
3101
|
const interruptSig = inbox.freshInterrupt();
|
|
@@ -2380,7 +3199,7 @@ var routerToolsInlineExecutor = (spec, ctx) => {
|
|
|
2380
3199
|
const usd = isModelPriced2(model) ? estimateCost2(tokens.input, tokens.output, model) : 0;
|
|
2381
3200
|
const spent = { iterations: turns, tokens, usd, ms: Date.now() - started };
|
|
2382
3201
|
const out = { content: lastText };
|
|
2383
|
-
artifact = { outRef:
|
|
3202
|
+
artifact = { outRef: contentRef2("router-tools", { model, content: lastText }), out, spent };
|
|
2384
3203
|
return artifact;
|
|
2385
3204
|
},
|
|
2386
3205
|
teardown(_grace) {
|
|
@@ -2464,7 +3283,7 @@ async function* streamSandboxLeaf(args) {
|
|
|
2464
3283
|
}
|
|
2465
3284
|
const agentRun = {
|
|
2466
3285
|
profile: args.spec.profile,
|
|
2467
|
-
taskToPrompt: (t) =>
|
|
3286
|
+
taskToPrompt: (t) => taskToPrompt2(t),
|
|
2468
3287
|
name: args.spec.profile.name ?? args.harness,
|
|
2469
3288
|
sandboxOverrides: { backend: { type: args.harness } }
|
|
2470
3289
|
};
|
|
@@ -2494,7 +3313,7 @@ async function* streamSandboxLeaf(args) {
|
|
|
2494
3313
|
ms: Date.now() - started
|
|
2495
3314
|
};
|
|
2496
3315
|
args.onArtifact({
|
|
2497
|
-
outRef:
|
|
3316
|
+
outRef: contentRef2("sandbox", { harness: args.harness, out }),
|
|
2498
3317
|
out,
|
|
2499
3318
|
...verdict ? { verdict } : {},
|
|
2500
3319
|
spent
|
|
@@ -2551,7 +3370,7 @@ var cliExecutor = (_spec, ctx) => {
|
|
|
2551
3370
|
};
|
|
2552
3371
|
};
|
|
2553
3372
|
async function* streamCliLeaf(args) {
|
|
2554
|
-
const prompt =
|
|
3373
|
+
const prompt = taskToPrompt2(args.task);
|
|
2555
3374
|
const proc = spawn3(args.seam.bin, args.seam.args ?? [], {
|
|
2556
3375
|
...args.seam.cwd ? { cwd: args.seam.cwd } : {},
|
|
2557
3376
|
env: { ...process.env, ...args.seam.env ?? {} },
|
|
@@ -2589,7 +3408,7 @@ async function* streamCliLeaf(args) {
|
|
|
2589
3408
|
);
|
|
2590
3409
|
}
|
|
2591
3410
|
const out = { content: chunks.join("") };
|
|
2592
|
-
args.onArtifact({ outRef:
|
|
3411
|
+
args.onArtifact({ outRef: contentRef2("cli", out), out, spent: zeroSpend2() });
|
|
2593
3412
|
yield { kind: "iteration" };
|
|
2594
3413
|
}
|
|
2595
3414
|
function killWithGrace(proc, grace) {
|
|
@@ -2662,13 +3481,13 @@ async function* streamBridgeSession(args) {
|
|
|
2662
3481
|
const { seam, inbox } = args;
|
|
2663
3482
|
const started = Date.now();
|
|
2664
3483
|
const url = `${seam.bridgeUrl.replace(/\/$/, "")}/v1/chat/completions`;
|
|
2665
|
-
const external =
|
|
3484
|
+
const external = mergeAbortSignals2(args.signal, args.controller.signal);
|
|
2666
3485
|
const tokens = zeroTokenUsage();
|
|
2667
3486
|
let usd = 0;
|
|
2668
3487
|
let turns = 0;
|
|
2669
3488
|
let lastText = "";
|
|
2670
3489
|
const toolCalls = [];
|
|
2671
|
-
let nextPrompt =
|
|
3490
|
+
let nextPrompt = taskToPrompt2(args.task);
|
|
2672
3491
|
const system = args.spec.profile.prompt?.systemPrompt;
|
|
2673
3492
|
for (let t = 0; t < args.maxTurns; t += 1) {
|
|
2674
3493
|
const pending = inbox.drain();
|
|
@@ -2763,7 +3582,7 @@ ${folded}` : folded;
|
|
|
2763
3582
|
};
|
|
2764
3583
|
const out = { content: lastText, toolCalls };
|
|
2765
3584
|
args.onArtifact({
|
|
2766
|
-
outRef:
|
|
3585
|
+
outRef: contentRef2("bridge", { model: seam.model, session: args.sessionId, content: lastText }),
|
|
2767
3586
|
out,
|
|
2768
3587
|
spent
|
|
2769
3588
|
});
|
|
@@ -2857,6 +3676,14 @@ function createExecutor(config) {
|
|
|
2857
3676
|
return cliExecutor(spec, seamed);
|
|
2858
3677
|
case "cli-worktree":
|
|
2859
3678
|
return cliWorktreeExecutor(spec, seamed);
|
|
3679
|
+
case "provider": {
|
|
3680
|
+
const providerSeam = readSeam(seamed, providerSeamKey, "provider");
|
|
3681
|
+
const provider = resolveAgentEnvironmentProvider(
|
|
3682
|
+
providerSeam.provider,
|
|
3683
|
+
providerSeam.registry
|
|
3684
|
+
);
|
|
3685
|
+
return providerAsExecutor(provider, providerSeam)(spec, seamed);
|
|
3686
|
+
}
|
|
2860
3687
|
case "sandbox": {
|
|
2861
3688
|
const harness = spec.harness ?? config.harness ?? null;
|
|
2862
3689
|
return sandboxExecutor({ ...spec, harness }, seamed);
|
|
@@ -2906,7 +3733,7 @@ function readSeam(ctx, key, who) {
|
|
|
2906
3733
|
}
|
|
2907
3734
|
return seam;
|
|
2908
3735
|
}
|
|
2909
|
-
function
|
|
3736
|
+
function taskToPrompt2(task) {
|
|
2910
3737
|
if (typeof task === "string") return task;
|
|
2911
3738
|
if (task && typeof task === "object") {
|
|
2912
3739
|
const obj = task;
|
|
@@ -2922,7 +3749,7 @@ function taskToMessages(task, spec) {
|
|
|
2922
3749
|
if (typeof system === "string" && system.length > 0) {
|
|
2923
3750
|
messages.push({ role: "system", content: system });
|
|
2924
3751
|
}
|
|
2925
|
-
messages.push({ role: "user", content:
|
|
3752
|
+
messages.push({ role: "user", content: taskToPrompt2(task) });
|
|
2926
3753
|
return messages;
|
|
2927
3754
|
}
|
|
2928
3755
|
function singleShotDriver(maxIterations) {
|
|
@@ -2948,7 +3775,7 @@ function linkSignals2(a, b) {
|
|
|
2948
3775
|
b.addEventListener("abort", onAbort, { once: true });
|
|
2949
3776
|
return c.signal;
|
|
2950
3777
|
}
|
|
2951
|
-
function
|
|
3778
|
+
function mergeAbortSignals2(...signals) {
|
|
2952
3779
|
const c = new AbortController();
|
|
2953
3780
|
const onAbort = () => c.abort();
|
|
2954
3781
|
for (const s of signals) {
|
|
@@ -4461,7 +5288,7 @@ var DelegationTaskQueue = class _DelegationTaskQueue {
|
|
|
4461
5288
|
static async restore(options = {}) {
|
|
4462
5289
|
const queue = new _DelegationTaskQueue(options);
|
|
4463
5290
|
const loaded = await queue.store.loadAll();
|
|
4464
|
-
queue.rehydrate(loaded);
|
|
5291
|
+
await queue.rehydrate(loaded);
|
|
4465
5292
|
return queue;
|
|
4466
5293
|
}
|
|
4467
5294
|
/**
|
|
@@ -4643,17 +5470,18 @@ var DelegationTaskQueue = class _DelegationTaskQueue {
|
|
|
4643
5470
|
record.trace = trace;
|
|
4644
5471
|
if (truncated) record.traceTruncated = true;
|
|
4645
5472
|
}
|
|
4646
|
-
rehydrate(loaded) {
|
|
5473
|
+
async rehydrate(loaded) {
|
|
4647
5474
|
const records = [...loaded].sort((a, b) => a.startedAt.localeCompare(b.startedAt));
|
|
4648
5475
|
for (const record of records) {
|
|
4649
5476
|
this.records.set(record.taskId, record);
|
|
4650
5477
|
if (record.idempotencyKey) this.byIdempotencyKey.set(record.idempotencyKey, record.taskId);
|
|
4651
5478
|
}
|
|
5479
|
+
const restoreWrites = [];
|
|
4652
5480
|
for (const record of this.records.values()) {
|
|
4653
5481
|
if (isTerminal(record.status)) continue;
|
|
4654
5482
|
if (record.detachedSessionRef && this.resumeDelegate) {
|
|
4655
5483
|
record.status = "running";
|
|
4656
|
-
this.persist(record);
|
|
5484
|
+
restoreWrites.push(this.persist(record));
|
|
4657
5485
|
this.startResume(record, record.detachedSessionRef, this.resumeDelegate);
|
|
4658
5486
|
continue;
|
|
4659
5487
|
}
|
|
@@ -4663,9 +5491,12 @@ var DelegationTaskQueue = class _DelegationTaskQueue {
|
|
|
4663
5491
|
message: record.detachedSessionRef ? `delegation driver restarted while the task was in flight; detached session "${record.detachedSessionRef}" needs a resumeDelegate to be resumed` : "delegation driver restarted while the task was in flight; the run was not detached and cannot be resumed",
|
|
4664
5492
|
kind: "DriverRestartError"
|
|
4665
5493
|
};
|
|
4666
|
-
this.persist(record);
|
|
5494
|
+
restoreWrites.push(this.persist(record));
|
|
4667
5495
|
}
|
|
4668
|
-
this.enforceRetention();
|
|
5496
|
+
const retentionWrite = this.enforceRetention();
|
|
5497
|
+
if (retentionWrite) restoreWrites.push(retentionWrite);
|
|
5498
|
+
await Promise.all(restoreWrites);
|
|
5499
|
+
if (this.persistFailure) throw this.persistFailure;
|
|
4669
5500
|
}
|
|
4670
5501
|
startResume(record, detachedSessionRef, driver) {
|
|
4671
5502
|
const controller = new AbortController();
|
|
@@ -4748,7 +5579,7 @@ var DelegationTaskQueue = class _DelegationTaskQueue {
|
|
|
4748
5579
|
]);
|
|
4749
5580
|
}
|
|
4750
5581
|
persist(record) {
|
|
4751
|
-
if (this.persistFailure) return;
|
|
5582
|
+
if (this.persistFailure) return Promise.resolve();
|
|
4752
5583
|
const snapshot = structuredClone(record);
|
|
4753
5584
|
this.persistTail = this.persistTail.then(async () => {
|
|
4754
5585
|
if (this.persistFailure) return;
|
|
@@ -4758,9 +5589,10 @@ var DelegationTaskQueue = class _DelegationTaskQueue {
|
|
|
4758
5589
|
this.failPersistence(err);
|
|
4759
5590
|
}
|
|
4760
5591
|
});
|
|
5592
|
+
return this.persistTail;
|
|
4761
5593
|
}
|
|
4762
5594
|
persistRemoval(taskIds) {
|
|
4763
|
-
if (this.persistFailure || taskIds.length === 0) return;
|
|
5595
|
+
if (this.persistFailure || taskIds.length === 0) return void 0;
|
|
4764
5596
|
this.persistTail = this.persistTail.then(async () => {
|
|
4765
5597
|
if (this.persistFailure) return;
|
|
4766
5598
|
try {
|
|
@@ -4769,6 +5601,7 @@ var DelegationTaskQueue = class _DelegationTaskQueue {
|
|
|
4769
5601
|
this.failPersistence(err);
|
|
4770
5602
|
}
|
|
4771
5603
|
});
|
|
5604
|
+
return this.persistTail;
|
|
4772
5605
|
}
|
|
4773
5606
|
failPersistence(cause) {
|
|
4774
5607
|
if (this.persistFailure) return;
|
|
@@ -4780,13 +5613,13 @@ var DelegationTaskQueue = class _DelegationTaskQueue {
|
|
|
4780
5613
|
this.onPersistError(error);
|
|
4781
5614
|
}
|
|
4782
5615
|
enforceRetention() {
|
|
4783
|
-
if (!Number.isFinite(this.maxTerminalRecords)) return;
|
|
5616
|
+
if (!Number.isFinite(this.maxTerminalRecords)) return void 0;
|
|
4784
5617
|
const terminal = [];
|
|
4785
5618
|
for (const record of this.records.values()) {
|
|
4786
5619
|
if (isTerminal(record.status)) terminal.push(record);
|
|
4787
5620
|
}
|
|
4788
5621
|
const excess = terminal.length - this.maxTerminalRecords;
|
|
4789
|
-
if (excess <= 0) return;
|
|
5622
|
+
if (excess <= 0) return void 0;
|
|
4790
5623
|
terminal.sort(
|
|
4791
5624
|
(a, b) => (a.completedAt ?? a.startedAt).localeCompare(b.completedAt ?? b.startedAt)
|
|
4792
5625
|
);
|
|
@@ -4797,7 +5630,7 @@ var DelegationTaskQueue = class _DelegationTaskQueue {
|
|
|
4797
5630
|
this.byIdempotencyKey.delete(record.idempotencyKey);
|
|
4798
5631
|
}
|
|
4799
5632
|
}
|
|
4800
|
-
this.persistRemoval(evicted.map((record) => record.taskId));
|
|
5633
|
+
return this.persistRemoval(evicted.map((record) => record.taskId));
|
|
4801
5634
|
}
|
|
4802
5635
|
};
|
|
4803
5636
|
function isTerminal(status) {
|
|
@@ -5277,7 +6110,7 @@ var DELEGATE_FEEDBACK_DESCRIPTION = [
|
|
|
5277
6110
|
"on the same target are expected and never deduped.",
|
|
5278
6111
|
"",
|
|
5279
6112
|
"`refersTo.kind`:",
|
|
5280
|
-
' - "delegation": ref is a taskId returned by
|
|
6113
|
+
' - "delegation": ref is a taskId returned by delegate_ui_audit',
|
|
5281
6114
|
' - "artifact": ref is a URI/path/git-sha \u2014 anything you can dereference',
|
|
5282
6115
|
' - "outcome": ref is a free-form description of a downstream result',
|
|
5283
6116
|
"",
|
|
@@ -5749,13 +6582,13 @@ var DELEGATION_STATUS_DESCRIPTION = [
|
|
|
5749
6582
|
"(pending | running | completed | failed | cancelled), optional progress,",
|
|
5750
6583
|
'and the final result when status === "completed".',
|
|
5751
6584
|
"",
|
|
5752
|
-
"Use when: you previously
|
|
5753
|
-
"need to know whether the work is done. The agent's right rhythm is to",
|
|
6585
|
+
"Use when: you previously kicked off an async delegation (delegate_ui_audit)",
|
|
6586
|
+
"and need to know whether the work is done. The agent's right rhythm is to",
|
|
5754
6587
|
"call this every minute or two while waiting; do not busy-poll.",
|
|
5755
6588
|
"",
|
|
5756
|
-
"For a completed
|
|
5757
|
-
"
|
|
5758
|
-
"
|
|
6589
|
+
"For a completed delegate_ui_audit run, `result.output` is the array of UI",
|
|
6590
|
+
"findings \u2014 one self-contained Markdown finding per issue, each with an",
|
|
6591
|
+
"embedded screenshot and a suggested fix.",
|
|
5759
6592
|
"",
|
|
5760
6593
|
"Pass includeTrace: true to also receive the journaled loop-trace span",
|
|
5761
6594
|
"tree (loop \u2192 round \u2192 iteration, with placement/cost/verdict metadata).",
|
|
@@ -5767,7 +6600,7 @@ var DELEGATION_STATUS_DESCRIPTION = [
|
|
|
5767
6600
|
var DELEGATION_STATUS_INPUT_SCHEMA = {
|
|
5768
6601
|
type: "object",
|
|
5769
6602
|
properties: {
|
|
5770
|
-
taskId: { type: "string", description: "Returned by
|
|
6603
|
+
taskId: { type: "string", description: "Returned by delegate_ui_audit." },
|
|
5771
6604
|
includeTrace: {
|
|
5772
6605
|
type: "boolean",
|
|
5773
6606
|
description: "Also return the journaled loop-trace span tree for this delegation. Default false."
|
|
@@ -6142,6 +6975,11 @@ export {
|
|
|
6142
6975
|
contentAddress,
|
|
6143
6976
|
InMemoryResultBlobStore,
|
|
6144
6977
|
InMemorySpawnJournal,
|
|
6978
|
+
createAgentEnvironmentProviderRegistry,
|
|
6979
|
+
resolveAgentEnvironmentProvider,
|
|
6980
|
+
providerAsSandboxClient,
|
|
6981
|
+
sandboxClientAsProvider,
|
|
6982
|
+
providerAsExecutor,
|
|
6145
6983
|
defineRuntimeHooks,
|
|
6146
6984
|
composeRuntimeHooks,
|
|
6147
6985
|
notifyRuntimeHookEvent,
|
|
@@ -6231,4 +7069,4 @@ export {
|
|
|
6231
7069
|
createInProcessTransport,
|
|
6232
7070
|
serveCoordinationMcp
|
|
6233
7071
|
};
|
|
6234
|
-
//# sourceMappingURL=chunk-
|
|
7072
|
+
//# sourceMappingURL=chunk-EZ2QESTP.js.map
|