@tangle-network/agent-runtime 0.78.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.js +3 -3
- package/dist/{chunk-O2UPHN7X.js → chunk-5JAUQZQA.js} +1 -1
- package/dist/chunk-5JAUQZQA.js.map +1 -0
- package/dist/{chunk-OLPH6W3J.js → chunk-EZ2QESTP.js} +833 -33
- package/dist/chunk-EZ2QESTP.js.map +1 -0
- package/dist/{chunk-OL2SEETC.js → chunk-F6G3SSHY.js} +2 -2
- package/dist/{chunk-QJ6BWENI.js → chunk-GZX3PI7V.js} +3 -3
- package/dist/{chunk-JPURCA2O.js → chunk-LWGVVP2C.js} +2 -2
- package/dist/{chunk-YHS6I2IS.js → chunk-N2JJDGLJ.js} +2 -2
- package/dist/chunk-N2JJDGLJ.js.map +1 -0
- package/dist/{coordination-Csxsy39a.d.ts → coordination-09JTQnlF.d.ts} +87 -24
- package/dist/index.d.ts +6 -6
- package/dist/index.js +6 -6
- 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-BTMpf1oY.d.ts → loop-runner-bin-Ddgf4DkS.d.ts} +2 -2
- package/dist/loop-runner-bin.d.ts +4 -4
- package/dist/loop-runner-bin.js +4 -4
- package/dist/loops.d.ts +10 -9
- 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 +10 -10
- 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/{worktree-DH_Y0brm.d.ts → worktree-CUn0d-ZT.d.ts} +1 -1
- package/dist/{worktree-fanout-DGC7jS7i.d.ts → worktree-fanout-DwwatTdY.d.ts} +2 -2
- package/package.json +3 -3
- package/dist/chunk-O2UPHN7X.js.map +0 -1
- package/dist/chunk-OLPH6W3J.js.map +0 -1
- package/dist/chunk-YHS6I2IS.js.map +0 -1
- /package/dist/{chunk-OL2SEETC.js.map → chunk-F6G3SSHY.js.map} +0 -0
- /package/dist/{chunk-QJ6BWENI.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;
|
|
@@ -2207,7 +2987,8 @@ var sandboxSeamKey = "sandbox";
|
|
|
2207
2987
|
var cliSeamKey = "cli";
|
|
2208
2988
|
var bridgeSeamKey = "bridge";
|
|
2209
2989
|
var cliWorktreeSeamKey = "cli-worktree";
|
|
2210
|
-
|
|
2990
|
+
var providerSeamKey = "provider";
|
|
2991
|
+
function contentRef2(prefix, value) {
|
|
2211
2992
|
let str;
|
|
2212
2993
|
try {
|
|
2213
2994
|
str = JSON.stringify(value) ?? String(value);
|
|
@@ -2260,7 +3041,7 @@ var routerInlineExecutor = (spec, ctx) => {
|
|
|
2260
3041
|
ms: Date.now() - started
|
|
2261
3042
|
};
|
|
2262
3043
|
const out = { content: r.content };
|
|
2263
|
-
artifact = { outRef:
|
|
3044
|
+
artifact = { outRef: contentRef2("router", { model, content: r.content }), out, spent };
|
|
2264
3045
|
return artifact;
|
|
2265
3046
|
},
|
|
2266
3047
|
teardown(_grace) {
|
|
@@ -2314,7 +3095,7 @@ var routerToolsInlineExecutor = (spec, ctx) => {
|
|
|
2314
3095
|
if (pending.length) messages.push({ role: "user", content: inbox.fold(pending) });
|
|
2315
3096
|
return pending.length > 0;
|
|
2316
3097
|
};
|
|
2317
|
-
const external =
|
|
3098
|
+
const external = mergeAbortSignals2(signal, controller.signal);
|
|
2318
3099
|
for (let t = 0; t < maxTurns; t += 1) {
|
|
2319
3100
|
flush();
|
|
2320
3101
|
const interruptSig = inbox.freshInterrupt();
|
|
@@ -2418,7 +3199,7 @@ var routerToolsInlineExecutor = (spec, ctx) => {
|
|
|
2418
3199
|
const usd = isModelPriced2(model) ? estimateCost2(tokens.input, tokens.output, model) : 0;
|
|
2419
3200
|
const spent = { iterations: turns, tokens, usd, ms: Date.now() - started };
|
|
2420
3201
|
const out = { content: lastText };
|
|
2421
|
-
artifact = { outRef:
|
|
3202
|
+
artifact = { outRef: contentRef2("router-tools", { model, content: lastText }), out, spent };
|
|
2422
3203
|
return artifact;
|
|
2423
3204
|
},
|
|
2424
3205
|
teardown(_grace) {
|
|
@@ -2502,7 +3283,7 @@ async function* streamSandboxLeaf(args) {
|
|
|
2502
3283
|
}
|
|
2503
3284
|
const agentRun = {
|
|
2504
3285
|
profile: args.spec.profile,
|
|
2505
|
-
taskToPrompt: (t) =>
|
|
3286
|
+
taskToPrompt: (t) => taskToPrompt2(t),
|
|
2506
3287
|
name: args.spec.profile.name ?? args.harness,
|
|
2507
3288
|
sandboxOverrides: { backend: { type: args.harness } }
|
|
2508
3289
|
};
|
|
@@ -2532,7 +3313,7 @@ async function* streamSandboxLeaf(args) {
|
|
|
2532
3313
|
ms: Date.now() - started
|
|
2533
3314
|
};
|
|
2534
3315
|
args.onArtifact({
|
|
2535
|
-
outRef:
|
|
3316
|
+
outRef: contentRef2("sandbox", { harness: args.harness, out }),
|
|
2536
3317
|
out,
|
|
2537
3318
|
...verdict ? { verdict } : {},
|
|
2538
3319
|
spent
|
|
@@ -2589,7 +3370,7 @@ var cliExecutor = (_spec, ctx) => {
|
|
|
2589
3370
|
};
|
|
2590
3371
|
};
|
|
2591
3372
|
async function* streamCliLeaf(args) {
|
|
2592
|
-
const prompt =
|
|
3373
|
+
const prompt = taskToPrompt2(args.task);
|
|
2593
3374
|
const proc = spawn3(args.seam.bin, args.seam.args ?? [], {
|
|
2594
3375
|
...args.seam.cwd ? { cwd: args.seam.cwd } : {},
|
|
2595
3376
|
env: { ...process.env, ...args.seam.env ?? {} },
|
|
@@ -2627,7 +3408,7 @@ async function* streamCliLeaf(args) {
|
|
|
2627
3408
|
);
|
|
2628
3409
|
}
|
|
2629
3410
|
const out = { content: chunks.join("") };
|
|
2630
|
-
args.onArtifact({ outRef:
|
|
3411
|
+
args.onArtifact({ outRef: contentRef2("cli", out), out, spent: zeroSpend2() });
|
|
2631
3412
|
yield { kind: "iteration" };
|
|
2632
3413
|
}
|
|
2633
3414
|
function killWithGrace(proc, grace) {
|
|
@@ -2700,13 +3481,13 @@ async function* streamBridgeSession(args) {
|
|
|
2700
3481
|
const { seam, inbox } = args;
|
|
2701
3482
|
const started = Date.now();
|
|
2702
3483
|
const url = `${seam.bridgeUrl.replace(/\/$/, "")}/v1/chat/completions`;
|
|
2703
|
-
const external =
|
|
3484
|
+
const external = mergeAbortSignals2(args.signal, args.controller.signal);
|
|
2704
3485
|
const tokens = zeroTokenUsage();
|
|
2705
3486
|
let usd = 0;
|
|
2706
3487
|
let turns = 0;
|
|
2707
3488
|
let lastText = "";
|
|
2708
3489
|
const toolCalls = [];
|
|
2709
|
-
let nextPrompt =
|
|
3490
|
+
let nextPrompt = taskToPrompt2(args.task);
|
|
2710
3491
|
const system = args.spec.profile.prompt?.systemPrompt;
|
|
2711
3492
|
for (let t = 0; t < args.maxTurns; t += 1) {
|
|
2712
3493
|
const pending = inbox.drain();
|
|
@@ -2801,7 +3582,7 @@ ${folded}` : folded;
|
|
|
2801
3582
|
};
|
|
2802
3583
|
const out = { content: lastText, toolCalls };
|
|
2803
3584
|
args.onArtifact({
|
|
2804
|
-
outRef:
|
|
3585
|
+
outRef: contentRef2("bridge", { model: seam.model, session: args.sessionId, content: lastText }),
|
|
2805
3586
|
out,
|
|
2806
3587
|
spent
|
|
2807
3588
|
});
|
|
@@ -2895,6 +3676,14 @@ function createExecutor(config) {
|
|
|
2895
3676
|
return cliExecutor(spec, seamed);
|
|
2896
3677
|
case "cli-worktree":
|
|
2897
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
|
+
}
|
|
2898
3687
|
case "sandbox": {
|
|
2899
3688
|
const harness = spec.harness ?? config.harness ?? null;
|
|
2900
3689
|
return sandboxExecutor({ ...spec, harness }, seamed);
|
|
@@ -2944,7 +3733,7 @@ function readSeam(ctx, key, who) {
|
|
|
2944
3733
|
}
|
|
2945
3734
|
return seam;
|
|
2946
3735
|
}
|
|
2947
|
-
function
|
|
3736
|
+
function taskToPrompt2(task) {
|
|
2948
3737
|
if (typeof task === "string") return task;
|
|
2949
3738
|
if (task && typeof task === "object") {
|
|
2950
3739
|
const obj = task;
|
|
@@ -2960,7 +3749,7 @@ function taskToMessages(task, spec) {
|
|
|
2960
3749
|
if (typeof system === "string" && system.length > 0) {
|
|
2961
3750
|
messages.push({ role: "system", content: system });
|
|
2962
3751
|
}
|
|
2963
|
-
messages.push({ role: "user", content:
|
|
3752
|
+
messages.push({ role: "user", content: taskToPrompt2(task) });
|
|
2964
3753
|
return messages;
|
|
2965
3754
|
}
|
|
2966
3755
|
function singleShotDriver(maxIterations) {
|
|
@@ -2986,7 +3775,7 @@ function linkSignals2(a, b) {
|
|
|
2986
3775
|
b.addEventListener("abort", onAbort, { once: true });
|
|
2987
3776
|
return c.signal;
|
|
2988
3777
|
}
|
|
2989
|
-
function
|
|
3778
|
+
function mergeAbortSignals2(...signals) {
|
|
2990
3779
|
const c = new AbortController();
|
|
2991
3780
|
const onAbort = () => c.abort();
|
|
2992
3781
|
for (const s of signals) {
|
|
@@ -4499,7 +5288,7 @@ var DelegationTaskQueue = class _DelegationTaskQueue {
|
|
|
4499
5288
|
static async restore(options = {}) {
|
|
4500
5289
|
const queue = new _DelegationTaskQueue(options);
|
|
4501
5290
|
const loaded = await queue.store.loadAll();
|
|
4502
|
-
queue.rehydrate(loaded);
|
|
5291
|
+
await queue.rehydrate(loaded);
|
|
4503
5292
|
return queue;
|
|
4504
5293
|
}
|
|
4505
5294
|
/**
|
|
@@ -4681,17 +5470,18 @@ var DelegationTaskQueue = class _DelegationTaskQueue {
|
|
|
4681
5470
|
record.trace = trace;
|
|
4682
5471
|
if (truncated) record.traceTruncated = true;
|
|
4683
5472
|
}
|
|
4684
|
-
rehydrate(loaded) {
|
|
5473
|
+
async rehydrate(loaded) {
|
|
4685
5474
|
const records = [...loaded].sort((a, b) => a.startedAt.localeCompare(b.startedAt));
|
|
4686
5475
|
for (const record of records) {
|
|
4687
5476
|
this.records.set(record.taskId, record);
|
|
4688
5477
|
if (record.idempotencyKey) this.byIdempotencyKey.set(record.idempotencyKey, record.taskId);
|
|
4689
5478
|
}
|
|
5479
|
+
const restoreWrites = [];
|
|
4690
5480
|
for (const record of this.records.values()) {
|
|
4691
5481
|
if (isTerminal(record.status)) continue;
|
|
4692
5482
|
if (record.detachedSessionRef && this.resumeDelegate) {
|
|
4693
5483
|
record.status = "running";
|
|
4694
|
-
this.persist(record);
|
|
5484
|
+
restoreWrites.push(this.persist(record));
|
|
4695
5485
|
this.startResume(record, record.detachedSessionRef, this.resumeDelegate);
|
|
4696
5486
|
continue;
|
|
4697
5487
|
}
|
|
@@ -4701,9 +5491,12 @@ var DelegationTaskQueue = class _DelegationTaskQueue {
|
|
|
4701
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",
|
|
4702
5492
|
kind: "DriverRestartError"
|
|
4703
5493
|
};
|
|
4704
|
-
this.persist(record);
|
|
5494
|
+
restoreWrites.push(this.persist(record));
|
|
4705
5495
|
}
|
|
4706
|
-
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;
|
|
4707
5500
|
}
|
|
4708
5501
|
startResume(record, detachedSessionRef, driver) {
|
|
4709
5502
|
const controller = new AbortController();
|
|
@@ -4786,7 +5579,7 @@ var DelegationTaskQueue = class _DelegationTaskQueue {
|
|
|
4786
5579
|
]);
|
|
4787
5580
|
}
|
|
4788
5581
|
persist(record) {
|
|
4789
|
-
if (this.persistFailure) return;
|
|
5582
|
+
if (this.persistFailure) return Promise.resolve();
|
|
4790
5583
|
const snapshot = structuredClone(record);
|
|
4791
5584
|
this.persistTail = this.persistTail.then(async () => {
|
|
4792
5585
|
if (this.persistFailure) return;
|
|
@@ -4796,9 +5589,10 @@ var DelegationTaskQueue = class _DelegationTaskQueue {
|
|
|
4796
5589
|
this.failPersistence(err);
|
|
4797
5590
|
}
|
|
4798
5591
|
});
|
|
5592
|
+
return this.persistTail;
|
|
4799
5593
|
}
|
|
4800
5594
|
persistRemoval(taskIds) {
|
|
4801
|
-
if (this.persistFailure || taskIds.length === 0) return;
|
|
5595
|
+
if (this.persistFailure || taskIds.length === 0) return void 0;
|
|
4802
5596
|
this.persistTail = this.persistTail.then(async () => {
|
|
4803
5597
|
if (this.persistFailure) return;
|
|
4804
5598
|
try {
|
|
@@ -4807,6 +5601,7 @@ var DelegationTaskQueue = class _DelegationTaskQueue {
|
|
|
4807
5601
|
this.failPersistence(err);
|
|
4808
5602
|
}
|
|
4809
5603
|
});
|
|
5604
|
+
return this.persistTail;
|
|
4810
5605
|
}
|
|
4811
5606
|
failPersistence(cause) {
|
|
4812
5607
|
if (this.persistFailure) return;
|
|
@@ -4818,13 +5613,13 @@ var DelegationTaskQueue = class _DelegationTaskQueue {
|
|
|
4818
5613
|
this.onPersistError(error);
|
|
4819
5614
|
}
|
|
4820
5615
|
enforceRetention() {
|
|
4821
|
-
if (!Number.isFinite(this.maxTerminalRecords)) return;
|
|
5616
|
+
if (!Number.isFinite(this.maxTerminalRecords)) return void 0;
|
|
4822
5617
|
const terminal = [];
|
|
4823
5618
|
for (const record of this.records.values()) {
|
|
4824
5619
|
if (isTerminal(record.status)) terminal.push(record);
|
|
4825
5620
|
}
|
|
4826
5621
|
const excess = terminal.length - this.maxTerminalRecords;
|
|
4827
|
-
if (excess <= 0) return;
|
|
5622
|
+
if (excess <= 0) return void 0;
|
|
4828
5623
|
terminal.sort(
|
|
4829
5624
|
(a, b) => (a.completedAt ?? a.startedAt).localeCompare(b.completedAt ?? b.startedAt)
|
|
4830
5625
|
);
|
|
@@ -4835,7 +5630,7 @@ var DelegationTaskQueue = class _DelegationTaskQueue {
|
|
|
4835
5630
|
this.byIdempotencyKey.delete(record.idempotencyKey);
|
|
4836
5631
|
}
|
|
4837
5632
|
}
|
|
4838
|
-
this.persistRemoval(evicted.map((record) => record.taskId));
|
|
5633
|
+
return this.persistRemoval(evicted.map((record) => record.taskId));
|
|
4839
5634
|
}
|
|
4840
5635
|
};
|
|
4841
5636
|
function isTerminal(status) {
|
|
@@ -5315,7 +6110,7 @@ var DELEGATE_FEEDBACK_DESCRIPTION = [
|
|
|
5315
6110
|
"on the same target are expected and never deduped.",
|
|
5316
6111
|
"",
|
|
5317
6112
|
"`refersTo.kind`:",
|
|
5318
|
-
' - "delegation": ref is a taskId returned by
|
|
6113
|
+
' - "delegation": ref is a taskId returned by delegate_ui_audit',
|
|
5319
6114
|
' - "artifact": ref is a URI/path/git-sha \u2014 anything you can dereference',
|
|
5320
6115
|
' - "outcome": ref is a free-form description of a downstream result',
|
|
5321
6116
|
"",
|
|
@@ -5787,13 +6582,13 @@ var DELEGATION_STATUS_DESCRIPTION = [
|
|
|
5787
6582
|
"(pending | running | completed | failed | cancelled), optional progress,",
|
|
5788
6583
|
'and the final result when status === "completed".',
|
|
5789
6584
|
"",
|
|
5790
|
-
"Use when: you previously
|
|
5791
|
-
"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",
|
|
5792
6587
|
"call this every minute or two while waiting; do not busy-poll.",
|
|
5793
6588
|
"",
|
|
5794
|
-
"For a completed
|
|
5795
|
-
"
|
|
5796
|
-
"
|
|
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.",
|
|
5797
6592
|
"",
|
|
5798
6593
|
"Pass includeTrace: true to also receive the journaled loop-trace span",
|
|
5799
6594
|
"tree (loop \u2192 round \u2192 iteration, with placement/cost/verdict metadata).",
|
|
@@ -5805,7 +6600,7 @@ var DELEGATION_STATUS_DESCRIPTION = [
|
|
|
5805
6600
|
var DELEGATION_STATUS_INPUT_SCHEMA = {
|
|
5806
6601
|
type: "object",
|
|
5807
6602
|
properties: {
|
|
5808
|
-
taskId: { type: "string", description: "Returned by
|
|
6603
|
+
taskId: { type: "string", description: "Returned by delegate_ui_audit." },
|
|
5809
6604
|
includeTrace: {
|
|
5810
6605
|
type: "boolean",
|
|
5811
6606
|
description: "Also return the journaled loop-trace span tree for this delegation. Default false."
|
|
@@ -6180,6 +6975,11 @@ export {
|
|
|
6180
6975
|
contentAddress,
|
|
6181
6976
|
InMemoryResultBlobStore,
|
|
6182
6977
|
InMemorySpawnJournal,
|
|
6978
|
+
createAgentEnvironmentProviderRegistry,
|
|
6979
|
+
resolveAgentEnvironmentProvider,
|
|
6980
|
+
providerAsSandboxClient,
|
|
6981
|
+
sandboxClientAsProvider,
|
|
6982
|
+
providerAsExecutor,
|
|
6183
6983
|
defineRuntimeHooks,
|
|
6184
6984
|
composeRuntimeHooks,
|
|
6185
6985
|
notifyRuntimeHookEvent,
|
|
@@ -6269,4 +7069,4 @@ export {
|
|
|
6269
7069
|
createInProcessTransport,
|
|
6270
7070
|
serveCoordinationMcp
|
|
6271
7071
|
};
|
|
6272
|
-
//# sourceMappingURL=chunk-
|
|
7072
|
+
//# sourceMappingURL=chunk-EZ2QESTP.js.map
|