@agentium/harness 4.1.0 → 4.6.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/CONVERSATIONAL-RUNS.md +173 -0
- package/README.md +13 -5
- package/dist/definition.d.cts +39 -0
- package/dist/{driver-Cr2BGG4h.cjs → driver-Bh_wLWCP.cjs} +285 -15
- package/dist/{driver-BvzvqvpB.js → driver-reTLBJ_o.js} +280 -16
- package/dist/drivers.d.cts +14 -0
- package/dist/drivers.d.ts.map +1 -1
- package/dist/index.cjs +103 -46
- package/dist/index.d.cts +19 -0
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +103 -48
- package/dist/input-tool.d.cts +7 -0
- package/dist/input-tool.d.ts +7 -0
- package/dist/input-tool.d.ts.map +1 -0
- package/dist/mcp-resources.d.cts +42 -0
- package/dist/policies.d.cts +31 -0
- package/dist/policies.d.ts +2 -0
- package/dist/policies.d.ts.map +1 -1
- package/dist/presets.d.cts +41 -0
- package/dist/runtime/context-policy.d.cts +21 -0
- package/dist/runtime/context-policy.d.ts +1 -0
- package/dist/runtime/context-policy.d.ts.map +1 -1
- package/dist/runtime/context.d.cts +15 -0
- package/dist/runtime/controller.d.cts +51 -0
- package/dist/runtime/driver.d.cts +157 -0
- package/dist/runtime/driver.d.ts +14 -3
- package/dist/runtime/driver.d.ts.map +1 -1
- package/dist/runtime/events.d.cts +116 -0
- package/dist/runtime/events.d.ts +35 -2
- package/dist/runtime/events.d.ts.map +1 -1
- package/dist/runtime/index.d.cts +9 -0
- package/dist/runtime/input.d.cts +46 -0
- package/dist/runtime/input.d.ts +46 -0
- package/dist/runtime/input.d.ts.map +1 -0
- package/dist/runtime/middleware.d.cts +10 -0
- package/dist/runtime/resolve.d.cts +20 -0
- package/dist/runtime/runtime-registry.d.cts +35 -0
- package/dist/runtime/session-bindings.d.cts +60 -0
- package/dist/runtime/types.d.cts +176 -0
- package/dist/testing.cjs +1 -1
- package/dist/testing.d.cts +7 -0
- package/dist/testing.js +1 -1
- package/dist/watch/definition.d.cts +11 -0
- package/dist/watch/gmail.d.cts +104 -0
- package/dist/watch/quiet-hours.d.cts +10 -0
- package/dist/watch/runtime.d.cts +42 -0
- package/dist/watch/types.d.cts +147 -0
- package/package.json +21 -10
|
@@ -71,7 +71,7 @@ async function projectHarnessContext(policy, history, ctx, entries = []) {
|
|
|
71
71
|
history: structuredClone(original),
|
|
72
72
|
entries: structuredClone(entries)
|
|
73
73
|
}, ctx);
|
|
74
|
-
(0, _agentium_core.validateConversationTransform)(original, result.messages);
|
|
74
|
+
(0, _agentium_core.validateConversationTransform)(original, result.messages, policy.grouping);
|
|
75
75
|
if (!Array.isArray(result.provenance) || result.provenance.some((item) => !item || typeof item.sourceId !== "string" || typeof item.included !== "boolean" || item.reason !== void 0 && typeof item.reason !== "string")) throw new Error("Context policy must return provenance");
|
|
76
76
|
return {
|
|
77
77
|
messages: structuredClone(result.messages),
|
|
@@ -397,6 +397,183 @@ var InMemoryHarnessEventStore = class {
|
|
|
397
397
|
}
|
|
398
398
|
};
|
|
399
399
|
//#endregion
|
|
400
|
+
//#region src/runtime/input.ts
|
|
401
|
+
var HarnessInputError = class extends Error {
|
|
402
|
+
code;
|
|
403
|
+
constructor(code, message) {
|
|
404
|
+
super(message);
|
|
405
|
+
this.code = code;
|
|
406
|
+
this.name = "HarnessInputError";
|
|
407
|
+
}
|
|
408
|
+
};
|
|
409
|
+
const text = zod_v3.z.object({
|
|
410
|
+
type: zod_v3.z.literal("text"),
|
|
411
|
+
text: zod_v3.z.string()
|
|
412
|
+
}).strict();
|
|
413
|
+
const media = zod_v3.z.discriminatedUnion("type", [
|
|
414
|
+
text,
|
|
415
|
+
zod_v3.z.object({
|
|
416
|
+
type: zod_v3.z.literal("image"),
|
|
417
|
+
data: zod_v3.z.string(),
|
|
418
|
+
mimeType: zod_v3.z.enum([
|
|
419
|
+
"image/png",
|
|
420
|
+
"image/jpeg",
|
|
421
|
+
"image/gif",
|
|
422
|
+
"image/webp"
|
|
423
|
+
]).optional()
|
|
424
|
+
}).strict(),
|
|
425
|
+
zod_v3.z.object({
|
|
426
|
+
type: zod_v3.z.literal("audio"),
|
|
427
|
+
data: zod_v3.z.string(),
|
|
428
|
+
mimeType: zod_v3.z.enum([
|
|
429
|
+
"audio/mp3",
|
|
430
|
+
"audio/wav",
|
|
431
|
+
"audio/ogg",
|
|
432
|
+
"audio/webm"
|
|
433
|
+
]).optional()
|
|
434
|
+
}).strict(),
|
|
435
|
+
zod_v3.z.object({
|
|
436
|
+
type: zod_v3.z.literal("file"),
|
|
437
|
+
data: zod_v3.z.string(),
|
|
438
|
+
mimeType: zod_v3.z.string(),
|
|
439
|
+
filename: zod_v3.z.string().optional()
|
|
440
|
+
}).strict()
|
|
441
|
+
]);
|
|
442
|
+
const message = zod_v3.z.union([zod_v3.z.string(), zod_v3.z.array(media).min(1)]);
|
|
443
|
+
const question = zod_v3.z.object({
|
|
444
|
+
question: zod_v3.z.string().trim().min(1),
|
|
445
|
+
choices: zod_v3.z.array(zod_v3.z.string().min(1)).min(1).max(100).optional(),
|
|
446
|
+
timeoutMs: zod_v3.z.number().int().positive().safe().optional()
|
|
447
|
+
}).strict();
|
|
448
|
+
function validateRunInput(input) {
|
|
449
|
+
const parsed = message.safeParse(input);
|
|
450
|
+
if (!parsed.success || Buffer.byteLength(JSON.stringify(parsed.data)) > 65536) throw new HarnessInputError("invalid_input", "Input must be valid message content no larger than 64KB");
|
|
451
|
+
return parsed.data;
|
|
452
|
+
}
|
|
453
|
+
function validateTimeout(value) {
|
|
454
|
+
if (value !== void 0 && (!Number.isSafeInteger(value) || value <= 0)) throw new HarnessInputError("invalid_input", "Timeout must be a positive safe integer");
|
|
455
|
+
}
|
|
456
|
+
/** Owns live promises only; this is not a restart checkpoint. */
|
|
457
|
+
var LiveInput = class {
|
|
458
|
+
runId;
|
|
459
|
+
signal;
|
|
460
|
+
timeouts;
|
|
461
|
+
emit;
|
|
462
|
+
expire;
|
|
463
|
+
pending;
|
|
464
|
+
resolved = /* @__PURE__ */ new Set();
|
|
465
|
+
timer;
|
|
466
|
+
activeTimer;
|
|
467
|
+
activeSince = Date.now();
|
|
468
|
+
activeRemaining;
|
|
469
|
+
closed = false;
|
|
470
|
+
onAbort = () => {
|
|
471
|
+
const pending = this.pending;
|
|
472
|
+
this.pending = void 0;
|
|
473
|
+
this.clearTimers();
|
|
474
|
+
pending?.reject(this.signal.reason);
|
|
475
|
+
};
|
|
476
|
+
constructor(runId, signal, timeouts, emit, expire) {
|
|
477
|
+
this.runId = runId;
|
|
478
|
+
this.signal = signal;
|
|
479
|
+
this.timeouts = timeouts;
|
|
480
|
+
this.emit = emit;
|
|
481
|
+
this.expire = expire;
|
|
482
|
+
this.activeRemaining = timeouts.activeTimeoutMs ?? Infinity;
|
|
483
|
+
signal.addEventListener("abort", this.onAbort, { once: true });
|
|
484
|
+
if (!signal.aborted) this.resumeClock();
|
|
485
|
+
}
|
|
486
|
+
get request() {
|
|
487
|
+
return this.pending && structuredClone(this.pending.request);
|
|
488
|
+
}
|
|
489
|
+
assertActive() {
|
|
490
|
+
if (this.closed || this.signal.aborted) throw new HarnessInputError("run_finished", "Run is no longer active");
|
|
491
|
+
}
|
|
492
|
+
assertNotWaiting() {
|
|
493
|
+
this.assertActive();
|
|
494
|
+
if (this.pending) throw new HarnessInputError("input_pending", "No model calls are allowed while waiting for input");
|
|
495
|
+
}
|
|
496
|
+
requestInput(options) {
|
|
497
|
+
this.assertNotWaiting();
|
|
498
|
+
const parsed = question.safeParse(options);
|
|
499
|
+
if (!parsed.success || Buffer.byteLength(JSON.stringify(parsed.data)) > 32768) throw new HarnessInputError("invalid_input", "Question must be valid and no larger than 32KB");
|
|
500
|
+
const request = {
|
|
501
|
+
...parsed.data,
|
|
502
|
+
id: `${this.runId}:${(0, node_crypto.randomUUID)()}`,
|
|
503
|
+
runId: this.runId
|
|
504
|
+
};
|
|
505
|
+
const promise = new Promise((resolve, reject) => {
|
|
506
|
+
this.pending = {
|
|
507
|
+
request,
|
|
508
|
+
resolve,
|
|
509
|
+
reject
|
|
510
|
+
};
|
|
511
|
+
});
|
|
512
|
+
if (this.activeTimer) clearTimeout(this.activeTimer);
|
|
513
|
+
this.activeRemaining -= Date.now() - this.activeSince;
|
|
514
|
+
const timeoutMs = request.timeoutMs ?? this.timeouts.inputTimeoutMs;
|
|
515
|
+
if (timeoutMs !== void 0) {
|
|
516
|
+
const deadline = Date.now() + timeoutMs;
|
|
517
|
+
const tick = () => {
|
|
518
|
+
if (Date.now() >= deadline) this.expire("input_timeout");
|
|
519
|
+
else this.timer = setTimeout(tick, Math.min(deadline - Date.now(), 2147483647));
|
|
520
|
+
};
|
|
521
|
+
tick();
|
|
522
|
+
}
|
|
523
|
+
this.emit({
|
|
524
|
+
type: "input.requested",
|
|
525
|
+
request
|
|
526
|
+
});
|
|
527
|
+
return promise;
|
|
528
|
+
}
|
|
529
|
+
reply(requestId, input) {
|
|
530
|
+
this.assertActive();
|
|
531
|
+
if (this.resolved.has(requestId)) throw new HarnessInputError("input_already_resolved", "Input request already resolved");
|
|
532
|
+
const pending = this.pending;
|
|
533
|
+
if (!pending) throw new HarnessInputError("input_not_pending", "There is no pending input request");
|
|
534
|
+
if (pending.request.id !== requestId) throw new HarnessInputError("input_mismatch", "Reply does not match the pending input request");
|
|
535
|
+
const value = validateRunInput(input);
|
|
536
|
+
this.resolved.add(requestId);
|
|
537
|
+
this.pending = void 0;
|
|
538
|
+
if (this.timer) clearTimeout(this.timer);
|
|
539
|
+
this.emit({
|
|
540
|
+
type: "input.resolved",
|
|
541
|
+
requestId
|
|
542
|
+
});
|
|
543
|
+
this.resumeClock();
|
|
544
|
+
this.emit({
|
|
545
|
+
type: "run.resumed",
|
|
546
|
+
requestId
|
|
547
|
+
});
|
|
548
|
+
pending.resolve({
|
|
549
|
+
requestId,
|
|
550
|
+
input: value
|
|
551
|
+
});
|
|
552
|
+
}
|
|
553
|
+
close() {
|
|
554
|
+
this.closed = true;
|
|
555
|
+
this.clearTimers();
|
|
556
|
+
this.signal.removeEventListener("abort", this.onAbort);
|
|
557
|
+
const pending = this.pending;
|
|
558
|
+
this.pending = void 0;
|
|
559
|
+
pending?.reject(new HarnessInputError("run_finished", "Run finished with unresolved input"));
|
|
560
|
+
}
|
|
561
|
+
resumeClock() {
|
|
562
|
+
this.activeSince = Date.now();
|
|
563
|
+
if (!Number.isFinite(this.activeRemaining)) return;
|
|
564
|
+
const tick = () => {
|
|
565
|
+
const remaining = this.activeRemaining - (Date.now() - this.activeSince);
|
|
566
|
+
if (remaining <= 0) this.expire("active_timeout");
|
|
567
|
+
else this.activeTimer = setTimeout(tick, Math.min(remaining, 2147483647));
|
|
568
|
+
};
|
|
569
|
+
tick();
|
|
570
|
+
}
|
|
571
|
+
clearTimers() {
|
|
572
|
+
if (this.timer) clearTimeout(this.timer);
|
|
573
|
+
if (this.activeTimer) clearTimeout(this.activeTimer);
|
|
574
|
+
}
|
|
575
|
+
};
|
|
576
|
+
//#endregion
|
|
400
577
|
//#region src/runtime/runtime-registry.ts
|
|
401
578
|
/** Registry resolution is static; it never initializes providers or executes drivers. */
|
|
402
579
|
function resolveHarnessRuntime(definition) {
|
|
@@ -1222,6 +1399,7 @@ var HarnessRuntime = class {
|
|
|
1222
1399
|
})])),
|
|
1223
1400
|
contextPolicy: config.contextPolicy && Object.freeze({
|
|
1224
1401
|
id: config.contextPolicy.id,
|
|
1402
|
+
grouping: config.contextPolicy.grouping,
|
|
1225
1403
|
project: config.contextPolicy.project.bind(config.contextPolicy)
|
|
1226
1404
|
}),
|
|
1227
1405
|
completionPolicy: config.completionPolicy && Object.freeze({
|
|
@@ -1269,6 +1447,8 @@ var HarnessRuntime = class {
|
|
|
1269
1447
|
} : config.grants;
|
|
1270
1448
|
if (grants.requiredToolIds?.some((id) => !grants.toolIds.includes(id))) throw new Error("Required tool omitted by grants");
|
|
1271
1449
|
if (options.deadline !== void 0 && !Number.isFinite(options.deadline)) throw new Error("Deadline must be finite");
|
|
1450
|
+
validateTimeout(config.activeTimeoutMs);
|
|
1451
|
+
validateTimeout(config.inputTimeoutMs);
|
|
1272
1452
|
const controller = new AbortController();
|
|
1273
1453
|
const runId = (0, node_crypto.randomUUID)();
|
|
1274
1454
|
const request = Object.freeze({
|
|
@@ -1358,6 +1538,7 @@ var HarnessRuntime = class {
|
|
|
1358
1538
|
const generateObserved = async (provider, messages, supplied) => {
|
|
1359
1539
|
const end = observeModel(provider);
|
|
1360
1540
|
try {
|
|
1541
|
+
liveInput.assertNotWaiting();
|
|
1361
1542
|
const response = await provider.generate(messages, supplied);
|
|
1362
1543
|
end(!controller.signal.aborted, response.usage);
|
|
1363
1544
|
return response;
|
|
@@ -1367,6 +1548,9 @@ var HarnessRuntime = class {
|
|
|
1367
1548
|
}
|
|
1368
1549
|
};
|
|
1369
1550
|
let terminal = false;
|
|
1551
|
+
let acceptingInput = true;
|
|
1552
|
+
let acceptingSteering = true;
|
|
1553
|
+
let cancellationCode = "cancelled";
|
|
1370
1554
|
const inbox = [];
|
|
1371
1555
|
const cancel = (reason = "Run cancelled") => {
|
|
1372
1556
|
if (!terminal && !controller.signal.aborted) {
|
|
@@ -1378,6 +1562,10 @@ var HarnessRuntime = class {
|
|
|
1378
1562
|
controller.abort(new Error(reason));
|
|
1379
1563
|
}
|
|
1380
1564
|
};
|
|
1565
|
+
const liveInput = new LiveInput(runId, controller.signal, config, (event) => events.append(event), (code) => {
|
|
1566
|
+
cancellationCode = code;
|
|
1567
|
+
cancel(code === "input_timeout" ? "User input timeout exceeded" : "Active execution timeout exceeded");
|
|
1568
|
+
});
|
|
1381
1569
|
const onAbort = () => cancel("Caller cancelled the run");
|
|
1382
1570
|
const callerSignal = options.signal;
|
|
1383
1571
|
callerSignal?.addEventListener("abort", onAbort, { once: true });
|
|
@@ -1386,8 +1574,10 @@ var HarnessRuntime = class {
|
|
|
1386
1574
|
const scheduleDeadline = () => {
|
|
1387
1575
|
if (request.deadline === void 0 || controller.signal.aborted) return;
|
|
1388
1576
|
const remaining = request.deadline - Date.now();
|
|
1389
|
-
if (remaining <= 0)
|
|
1390
|
-
|
|
1577
|
+
if (remaining <= 0) {
|
|
1578
|
+
cancellationCode = "deadline_exceeded";
|
|
1579
|
+
cancel("Run deadline exceeded");
|
|
1580
|
+
} else timer = setTimeout(scheduleDeadline, Math.min(remaining, 2147483647));
|
|
1391
1581
|
};
|
|
1392
1582
|
scheduleDeadline();
|
|
1393
1583
|
const result = Promise.resolve().then(async () => {
|
|
@@ -1420,7 +1610,10 @@ var HarnessRuntime = class {
|
|
|
1420
1610
|
return operation;
|
|
1421
1611
|
};
|
|
1422
1612
|
const ensureActive = () => {
|
|
1423
|
-
if (request.deadline !== void 0 && Date.now() >= request.deadline)
|
|
1613
|
+
if (request.deadline !== void 0 && Date.now() >= request.deadline) {
|
|
1614
|
+
cancellationCode = "deadline_exceeded";
|
|
1615
|
+
cancel("Run deadline exceeded");
|
|
1616
|
+
}
|
|
1424
1617
|
controller.signal.throwIfAborted();
|
|
1425
1618
|
if (!acceptingOperations) throw new Error("Run has finished accepting operations");
|
|
1426
1619
|
};
|
|
@@ -1508,6 +1701,7 @@ var HarnessRuntime = class {
|
|
|
1508
1701
|
}));
|
|
1509
1702
|
const prepare = async (provider, messages, supplied = {}, callCtx = ctx) => {
|
|
1510
1703
|
ensureActive();
|
|
1704
|
+
liveInput.assertNotWaiting();
|
|
1511
1705
|
if (modelCalls >= (config.budgets?.maxModelCalls ?? Infinity) || usage.totalTokens >= (config.budgets?.maxTokens ?? Infinity)) throw new HarnessBudgetError("Aggregate model/token budget exhausted");
|
|
1512
1706
|
const index = modelCalls++;
|
|
1513
1707
|
const next = config.controller?.prepareStep ? await observeControl("prepareStep", () => config.controller.prepareStep({
|
|
@@ -1604,6 +1798,7 @@ var HarnessRuntime = class {
|
|
|
1604
1798
|
},
|
|
1605
1799
|
controlModel: (role, messages, options = {}) => track((async () => {
|
|
1606
1800
|
ensureActive();
|
|
1801
|
+
liveInput.assertNotWaiting();
|
|
1607
1802
|
if (!request.grants.modelRoles.includes(role)) throw new Error("Ungranted control model role");
|
|
1608
1803
|
const binding = config.models?.[role];
|
|
1609
1804
|
if (!binding) throw new Error("Control model requires an explicit host binding");
|
|
@@ -1662,9 +1857,12 @@ var HarnessRuntime = class {
|
|
|
1662
1857
|
let amount = zero();
|
|
1663
1858
|
let reason = "stop";
|
|
1664
1859
|
let extras;
|
|
1860
|
+
let publicMessages;
|
|
1861
|
+
let phase;
|
|
1665
1862
|
const calls = [];
|
|
1666
1863
|
try {
|
|
1667
1864
|
ensureActive();
|
|
1865
|
+
liveInput.assertNotWaiting();
|
|
1668
1866
|
stream = call.provider.stream(call.messages, call.options);
|
|
1669
1867
|
while (true) {
|
|
1670
1868
|
const next = await stream.next();
|
|
@@ -1673,6 +1871,8 @@ var HarnessRuntime = class {
|
|
|
1673
1871
|
finished = true;
|
|
1674
1872
|
reason = next.value.finishReason;
|
|
1675
1873
|
extras = next.value.providerExtras;
|
|
1874
|
+
publicMessages = next.value.publicMessages;
|
|
1875
|
+
phase = next.value.phase;
|
|
1676
1876
|
amount = next.value.usage ?? zero();
|
|
1677
1877
|
account(call.provider, amount);
|
|
1678
1878
|
}
|
|
@@ -1695,6 +1895,7 @@ var HarnessRuntime = class {
|
|
|
1695
1895
|
message: {
|
|
1696
1896
|
role: "assistant",
|
|
1697
1897
|
content: text || null,
|
|
1898
|
+
...phase ? { phase } : {},
|
|
1698
1899
|
...calls.length ? { toolCalls: calls.map((item) => ({
|
|
1699
1900
|
id: item.id,
|
|
1700
1901
|
name: item.name,
|
|
@@ -1704,7 +1905,8 @@ var HarnessRuntime = class {
|
|
|
1704
1905
|
},
|
|
1705
1906
|
usage: amount,
|
|
1706
1907
|
finishReason: reason === "tool_calls" || reason === "length" || reason === "content_filter" ? reason : "stop",
|
|
1707
|
-
raw: { streamed: true }
|
|
1908
|
+
raw: { streamed: true },
|
|
1909
|
+
...publicMessages ? { publicMessages } : {}
|
|
1708
1910
|
};
|
|
1709
1911
|
await runAfterModel(middleware, response, callCtx ?? ctx);
|
|
1710
1912
|
succeeded = true;
|
|
@@ -1808,14 +2010,47 @@ var HarnessRuntime = class {
|
|
|
1808
2010
|
canonical.push(...structuredClone(messages));
|
|
1809
2011
|
},
|
|
1810
2012
|
emit: (payload) => {
|
|
1811
|
-
ensureActive();
|
|
2013
|
+
if (payload.type !== "compaction.failed" || terminal) ensureActive();
|
|
1812
2014
|
if (Buffer.byteLength(JSON.stringify(payload)) > 65536) throw new Error("Generic event exceeds 64KB; store an artifact reference instead");
|
|
1813
2015
|
events.append(payload);
|
|
1814
2016
|
},
|
|
1815
|
-
|
|
2017
|
+
finishInput: (context) => {
|
|
2018
|
+
if (context.runId === request.runId) acceptingSteering = false;
|
|
2019
|
+
},
|
|
2020
|
+
publishMessage: (event) => {
|
|
2021
|
+
if (terminal) return;
|
|
2022
|
+
if (event.type === "message.completed" && Buffer.byteLength(JSON.stringify(event)) > 6e4) {
|
|
2023
|
+
const artifactId = (0, node_crypto.randomUUID)();
|
|
2024
|
+
this.artifacts.set(artifactId, {
|
|
2025
|
+
owner: services.sessionKey,
|
|
2026
|
+
value: structuredClone(event.message)
|
|
2027
|
+
});
|
|
2028
|
+
events.append({
|
|
2029
|
+
...event,
|
|
2030
|
+
message: {
|
|
2031
|
+
...event.message,
|
|
2032
|
+
text: ""
|
|
2033
|
+
},
|
|
2034
|
+
artifactId
|
|
2035
|
+
});
|
|
2036
|
+
} else events.append(event);
|
|
2037
|
+
},
|
|
2038
|
+
requestInput: (question) => {
|
|
2039
|
+
ensureActive();
|
|
2040
|
+
return track(liveInput.requestInput(question));
|
|
2041
|
+
},
|
|
2042
|
+
takeInput: (context) => {
|
|
1816
2043
|
ensureActive();
|
|
2044
|
+
if (context && context.runId !== request.runId) return void 0;
|
|
1817
2045
|
const index = inbox.findIndex((item) => item.mode === "steer");
|
|
1818
|
-
|
|
2046
|
+
if (index < 0) return void 0;
|
|
2047
|
+
const item = inbox.splice(index, 1)[0];
|
|
2048
|
+
events.append({
|
|
2049
|
+
type: "input.applied",
|
|
2050
|
+
inputId: item.id,
|
|
2051
|
+
mode: "steer"
|
|
2052
|
+
});
|
|
2053
|
+
return item;
|
|
1819
2054
|
},
|
|
1820
2055
|
resource: (id, scope, initialize) => track((async () => {
|
|
1821
2056
|
ensureActive();
|
|
@@ -1847,7 +2082,9 @@ var HarnessRuntime = class {
|
|
|
1847
2082
|
let current = request;
|
|
1848
2083
|
while (true) {
|
|
1849
2084
|
ensureActive();
|
|
2085
|
+
acceptingSteering = true;
|
|
1850
2086
|
final = await config.driver.start(current, services);
|
|
2087
|
+
acceptingSteering = false;
|
|
1851
2088
|
if (streams.size) throw new Error("Driver returned with an unfinished model stream");
|
|
1852
2089
|
ensureActive();
|
|
1853
2090
|
if (!final || typeof final.text !== "string" || final.status !== void 0 && ![
|
|
@@ -1910,11 +2147,18 @@ var HarnessRuntime = class {
|
|
|
1910
2147
|
}
|
|
1911
2148
|
const followUp = inbox.findIndex((item) => item.mode === "follow_up");
|
|
1912
2149
|
if (followUp < 0) break;
|
|
2150
|
+
const item = inbox.splice(followUp, 1)[0];
|
|
2151
|
+
events.append({
|
|
2152
|
+
type: "input.applied",
|
|
2153
|
+
inputId: item.id,
|
|
2154
|
+
mode: "follow_up"
|
|
2155
|
+
});
|
|
1913
2156
|
current = {
|
|
1914
2157
|
...request,
|
|
1915
|
-
input:
|
|
2158
|
+
input: item.input
|
|
1916
2159
|
};
|
|
1917
2160
|
}
|
|
2161
|
+
acceptingInput = false;
|
|
1918
2162
|
const rejected = (await Promise.allSettled([...owned])).find((entry) => entry.status === "rejected");
|
|
1919
2163
|
if (rejected?.status === "rejected") throw rejected.reason;
|
|
1920
2164
|
ensureActive();
|
|
@@ -1935,6 +2179,8 @@ var HarnessRuntime = class {
|
|
|
1935
2179
|
}
|
|
1936
2180
|
};
|
|
1937
2181
|
} finally {
|
|
2182
|
+
acceptingInput = false;
|
|
2183
|
+
liveInput.close();
|
|
1938
2184
|
acceptingOperations = false;
|
|
1939
2185
|
await Promise.allSettled([...streams].map((stream) => stream.return(void 0)));
|
|
1940
2186
|
await Promise.allSettled([...owned]);
|
|
@@ -1971,8 +2217,8 @@ var HarnessRuntime = class {
|
|
|
1971
2217
|
...final,
|
|
1972
2218
|
status: "cancelled",
|
|
1973
2219
|
reason: {
|
|
1974
|
-
code:
|
|
1975
|
-
message: "Cancellation acknowledged"
|
|
2220
|
+
code: cancellationCode,
|
|
2221
|
+
message: controller.signal.reason instanceof Error ? controller.signal.reason.message : "Cancellation acknowledged"
|
|
1976
2222
|
}
|
|
1977
2223
|
};
|
|
1978
2224
|
const terminalResult = {
|
|
@@ -2026,21 +2272,39 @@ var HarnessRuntime = class {
|
|
|
2026
2272
|
});
|
|
2027
2273
|
return {
|
|
2028
2274
|
runId,
|
|
2275
|
+
get state() {
|
|
2276
|
+
return terminal ? "finished" : controller.signal.aborted ? "cancelling" : liveInput.request ? "awaiting_input" : "running";
|
|
2277
|
+
},
|
|
2278
|
+
get pendingInput() {
|
|
2279
|
+
return liveInput.request;
|
|
2280
|
+
},
|
|
2281
|
+
reply: async (requestId, input) => {
|
|
2282
|
+
if (!acceptingInput) throw new HarnessInputError("run_finished", "Run is no longer active");
|
|
2283
|
+
liveInput.reply(requestId, input);
|
|
2284
|
+
},
|
|
2029
2285
|
events: (options) => events.events(options),
|
|
2030
2286
|
result: () => result.then((value) => structuredClone(value)),
|
|
2031
2287
|
cancel,
|
|
2032
2288
|
send: async (input, options) => {
|
|
2033
|
-
if (terminal || controller.signal.aborted) throw new
|
|
2289
|
+
if (!acceptingInput || options.mode === "steer" && !acceptingSteering || terminal || controller.signal.aborted) throw new HarnessInputError("run_finished", "Run is no longer active");
|
|
2034
2290
|
if (!config.driver.capabilities.controls.includes(options.mode)) throw new HarnessUnsupportedError(options.mode);
|
|
2035
2291
|
if (inbox.length >= 32) throw new Error("Run input queue is full");
|
|
2036
|
-
|
|
2037
|
-
|
|
2292
|
+
if (options.mode === "replace") throw new HarnessUnsupportedError(options.mode);
|
|
2293
|
+
const item = {
|
|
2294
|
+
id: (0, node_crypto.randomUUID)(),
|
|
2295
|
+
input: validateRunInput(input),
|
|
2038
2296
|
mode: options.mode
|
|
2039
|
-
}
|
|
2297
|
+
};
|
|
2298
|
+
inbox.push(item);
|
|
2040
2299
|
events.append({
|
|
2041
2300
|
type: "control",
|
|
2042
2301
|
operation: options.mode
|
|
2043
2302
|
});
|
|
2303
|
+
events.append({
|
|
2304
|
+
type: "input.received",
|
|
2305
|
+
inputId: item.id,
|
|
2306
|
+
mode: options.mode
|
|
2307
|
+
});
|
|
2044
2308
|
}
|
|
2045
2309
|
};
|
|
2046
2310
|
}
|
|
@@ -2058,6 +2322,12 @@ Object.defineProperty(exports, "HarnessEventGapError", {
|
|
|
2058
2322
|
return HarnessEventGapError;
|
|
2059
2323
|
}
|
|
2060
2324
|
});
|
|
2325
|
+
Object.defineProperty(exports, "HarnessInputError", {
|
|
2326
|
+
enumerable: true,
|
|
2327
|
+
get: function() {
|
|
2328
|
+
return HarnessInputError;
|
|
2329
|
+
}
|
|
2330
|
+
});
|
|
2061
2331
|
Object.defineProperty(exports, "HarnessResourcePool", {
|
|
2062
2332
|
enumerable: true,
|
|
2063
2333
|
get: function() {
|