@noetaris/harness 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +201 -0
- package/dist/index.d.ts +628 -40
- package/dist/index.js +461 -75
- package/dist/index.js.map +1 -1
- package/package.json +12 -2
package/dist/index.js
CHANGED
|
@@ -304,6 +304,12 @@ var HarnessInternalsError = class extends Error {
|
|
|
304
304
|
this.name = "HarnessInternalsError";
|
|
305
305
|
}
|
|
306
306
|
};
|
|
307
|
+
var LoopNotDefinedError = class extends Error {
|
|
308
|
+
constructor() {
|
|
309
|
+
super("loop is not defined \u2014 call h.loop() before accessing h.definition()");
|
|
310
|
+
this.name = "LoopNotDefinedError";
|
|
311
|
+
}
|
|
312
|
+
};
|
|
307
313
|
function createHarness() {
|
|
308
314
|
return (stateSchema) => {
|
|
309
315
|
const internals = {
|
|
@@ -367,14 +373,17 @@ function createBuilderInstance(internals) {
|
|
|
367
373
|
};
|
|
368
374
|
return createBuilderInstance(newInternals);
|
|
369
375
|
},
|
|
376
|
+
definition() {
|
|
377
|
+
if (internals.loopDef === void 0) {
|
|
378
|
+
throw new LoopNotDefinedError();
|
|
379
|
+
}
|
|
380
|
+
return internals.loopDef;
|
|
381
|
+
},
|
|
370
382
|
[_internals]: internals
|
|
371
383
|
};
|
|
372
384
|
return builder;
|
|
373
385
|
}
|
|
374
386
|
|
|
375
|
-
// src/agent/session-lifecycle.ts
|
|
376
|
-
import { randomUUID } from "crypto";
|
|
377
|
-
|
|
378
387
|
// src/agent/ctx-interrupt.ts
|
|
379
388
|
var InterruptPause = class extends Error {
|
|
380
389
|
interruptId;
|
|
@@ -406,9 +415,12 @@ function createInterruptFn(state, callCountRef) {
|
|
|
406
415
|
}
|
|
407
416
|
|
|
408
417
|
// src/agent/ctx-emit.ts
|
|
409
|
-
function createEmitFn(listeners) {
|
|
418
|
+
function createEmitFn(listeners, observer, stepCtxRef) {
|
|
410
419
|
return (name, payload) => {
|
|
411
420
|
listeners[name]?.(payload);
|
|
421
|
+
if (observer !== void 0 && stepCtxRef !== void 0 && stepCtxRef.current !== null) {
|
|
422
|
+
observer.onEvent?.(stepCtxRef.current, name, payload);
|
|
423
|
+
}
|
|
412
424
|
};
|
|
413
425
|
}
|
|
414
426
|
function extractRunListeners(resources) {
|
|
@@ -462,21 +474,42 @@ function applyUpdate(state, update, schema) {
|
|
|
462
474
|
}
|
|
463
475
|
async function runLoop(graph, state, ctx, schema, shouldStop, startCursor, callbacks) {
|
|
464
476
|
const { onBeforeStep, onAfterStep, onError, onComplete, onInterrupt } = callbacks ?? {};
|
|
477
|
+
const obs = callbacks?.observer;
|
|
465
478
|
const implicitNextMap = buildImplicitNextMap(graph);
|
|
466
479
|
if (!("$error" in state)) state.$error = null;
|
|
467
480
|
if (!("$interrupt" in state)) state.$interrupt = null;
|
|
468
481
|
if (!("$interruptResponses" in state)) state.$interruptResponses = {};
|
|
482
|
+
const runStart = Date.now();
|
|
483
|
+
const runCtx = {
|
|
484
|
+
agentId: ctx.agentId,
|
|
485
|
+
sessionId: ctx.sessionId,
|
|
486
|
+
runId: typeof callbacks?.runId === "string" ? callbacks.runId : "",
|
|
487
|
+
...typeof callbacks?.parentRunId === "string" ? { parentRunId: callbacks.parentRunId } : {},
|
|
488
|
+
...typeof ctx.instanceId === "string" ? { instanceId: ctx.instanceId } : {}
|
|
489
|
+
};
|
|
490
|
+
obs?.onRunStart?.(runCtx);
|
|
469
491
|
const callCountRef = { current: 0 };
|
|
492
|
+
const stepCtxRef = { current: null };
|
|
470
493
|
ctx["interrupt"] = createInterruptFn(state, callCountRef);
|
|
471
|
-
ctx["emit"] = createEmitFn(callbacks?.listeners ?? {});
|
|
494
|
+
ctx["emit"] = createEmitFn(callbacks?.listeners ?? {}, obs, stepCtxRef);
|
|
472
495
|
let cursor = startCursor ?? graph.entryStep;
|
|
473
496
|
while (true) {
|
|
474
497
|
if (shouldStop?.()) {
|
|
498
|
+
obs?.onRunEnd?.(runCtx, { signal: "$stopped", durationMs: Date.now() - runStart });
|
|
475
499
|
return { state, signal: null, cursor, paused: true };
|
|
476
500
|
}
|
|
477
501
|
onBeforeStep?.(cursor, { ...state });
|
|
478
502
|
const step = graph.steps.find((s) => s.name === cursor);
|
|
479
503
|
callCountRef.current = 0;
|
|
504
|
+
const stepCtx = { agentId: ctx.agentId, sessionId: ctx.sessionId, stepName: cursor };
|
|
505
|
+
stepCtxRef.current = stepCtx;
|
|
506
|
+
const stepStart = Date.now();
|
|
507
|
+
obs?.onStepStart?.(stepCtx);
|
|
508
|
+
if (callbacks?.setStepContextSlots !== void 0) {
|
|
509
|
+
for (const slot of callbacks.setStepContextSlots) {
|
|
510
|
+
slot.setStepContext(stepCtx);
|
|
511
|
+
}
|
|
512
|
+
}
|
|
480
513
|
let runSucceeded = false;
|
|
481
514
|
if (step.run !== void 0) {
|
|
482
515
|
const hadResponses = Object.keys(state.$interruptResponses).length > 0;
|
|
@@ -494,15 +527,19 @@ async function runLoop(graph, state, ctx, schema, shouldStop, startCursor, callb
|
|
|
494
527
|
} catch (e) {
|
|
495
528
|
if (isInterruptPause(e)) {
|
|
496
529
|
onInterrupt?.(e.prompt, e.interruptId);
|
|
530
|
+
obs?.onInterrupt?.(stepCtx, { prompt: e.prompt, interruptId: e.interruptId });
|
|
531
|
+
obs?.onRunEnd?.(runCtx, { signal: "$interrupt", durationMs: Date.now() - runStart });
|
|
497
532
|
return { state, signal: "$interrupt", cursor, paused: true };
|
|
498
533
|
}
|
|
499
534
|
state.$error = e instanceof Error ? e : new Error(String(e));
|
|
500
535
|
onError?.(state.$error, cursor);
|
|
536
|
+
obs?.onStepError?.(stepCtx, { error: state.$error, durationMs: Date.now() - stepStart });
|
|
501
537
|
}
|
|
502
538
|
}
|
|
503
539
|
if (runSucceeded) {
|
|
504
540
|
state.$error = null;
|
|
505
541
|
onAfterStep?.(cursor, state);
|
|
542
|
+
obs?.onStepEnd?.(stepCtx, { durationMs: Date.now() - stepStart });
|
|
506
543
|
}
|
|
507
544
|
const callRoute = step.route !== void 0 && (runSucceeded || step.run === void 0 || step.errorAware);
|
|
508
545
|
if (callRoute) {
|
|
@@ -512,6 +549,7 @@ async function runLoop(graph, state, ctx, schema, shouldStop, startCursor, callb
|
|
|
512
549
|
signal = routeFn(state);
|
|
513
550
|
} catch (e) {
|
|
514
551
|
state.$error = e instanceof Error ? e : new Error(String(e));
|
|
552
|
+
obs?.onRunEnd?.(runCtx, { signal: "$error", durationMs: Date.now() - runStart });
|
|
515
553
|
return { state, signal: "$error", cursor, paused: true };
|
|
516
554
|
}
|
|
517
555
|
const transition = step.transitions.find((t) => t.signal === signal);
|
|
@@ -520,6 +558,7 @@ async function runLoop(graph, state, ctx, schema, shouldStop, startCursor, callb
|
|
|
520
558
|
}
|
|
521
559
|
if (transition.target.kind === "end") {
|
|
522
560
|
onComplete?.(state, signal);
|
|
561
|
+
obs?.onRunEnd?.(runCtx, { signal, durationMs: Date.now() - runStart });
|
|
523
562
|
return { state, signal, cursor: null, paused: false };
|
|
524
563
|
}
|
|
525
564
|
cursor = transition.target.name;
|
|
@@ -527,6 +566,7 @@ async function runLoop(graph, state, ctx, schema, shouldStop, startCursor, callb
|
|
|
527
566
|
if (graph.onError !== void 0) {
|
|
528
567
|
cursor = graph.onError;
|
|
529
568
|
} else {
|
|
569
|
+
obs?.onRunEnd?.(runCtx, { signal: "$error", durationMs: Date.now() - runStart });
|
|
530
570
|
return { state, signal: "$error", cursor, paused: true };
|
|
531
571
|
}
|
|
532
572
|
} else {
|
|
@@ -604,6 +644,7 @@ function buildResumedState(stored, initialStateArg, argKeys, schema) {
|
|
|
604
644
|
|
|
605
645
|
// src/agent/concurrency-errors.ts
|
|
606
646
|
var SessionInFlightError = class extends Error {
|
|
647
|
+
/** The session that was already in-flight. */
|
|
607
648
|
sessionId;
|
|
608
649
|
constructor(sessionId) {
|
|
609
650
|
super(`session "${sessionId}" is already in-flight`);
|
|
@@ -612,6 +653,7 @@ var SessionInFlightError = class extends Error {
|
|
|
612
653
|
}
|
|
613
654
|
};
|
|
614
655
|
var SessionPendingInterruptError = class extends Error {
|
|
656
|
+
/** The session that is awaiting an interrupt response. */
|
|
615
657
|
sessionId;
|
|
616
658
|
constructor(sessionId) {
|
|
617
659
|
super(`session "${sessionId}" is paused on an interrupt \u2014 use agent.resume() instead of agent.run()`);
|
|
@@ -627,6 +669,67 @@ var StoreLoadError = class extends Error {
|
|
|
627
669
|
this.cause = cause;
|
|
628
670
|
}
|
|
629
671
|
};
|
|
672
|
+
var SessionBusyError = class extends Error {
|
|
673
|
+
/** The session that is currently claimed by another instance. */
|
|
674
|
+
sessionId;
|
|
675
|
+
constructor(sessionId, retryAfter) {
|
|
676
|
+
super(`session "${sessionId}" is currently claimed by another instance`);
|
|
677
|
+
this.name = "SessionBusyError";
|
|
678
|
+
this.sessionId = sessionId;
|
|
679
|
+
if (retryAfter !== void 0) this.retryAfter = retryAfter;
|
|
680
|
+
}
|
|
681
|
+
};
|
|
682
|
+
var LeaseExpiredError = class extends Error {
|
|
683
|
+
/** The session whose lease expired. */
|
|
684
|
+
sessionId;
|
|
685
|
+
constructor(sessionId) {
|
|
686
|
+
super(`lease for session "${sessionId}" has expired \u2014 run stopped without saving`);
|
|
687
|
+
this.name = "LeaseExpiredError";
|
|
688
|
+
this.sessionId = sessionId;
|
|
689
|
+
}
|
|
690
|
+
};
|
|
691
|
+
|
|
692
|
+
// src/agent/ctx-keep-alive.ts
|
|
693
|
+
function createKeepAliveFn(leaseRef, store, originalTtlMs) {
|
|
694
|
+
function keepAlive(options) {
|
|
695
|
+
const isBackground = typeof options === "object" && options !== null && "every" in options;
|
|
696
|
+
const extendClaim = store?.extendClaim;
|
|
697
|
+
if (isBackground) {
|
|
698
|
+
if (leaseRef.current === null || typeof extendClaim !== "function") {
|
|
699
|
+
return noopStop;
|
|
700
|
+
}
|
|
701
|
+
let handle = setInterval(() => {
|
|
702
|
+
if (leaseRef.current === null) {
|
|
703
|
+
return;
|
|
704
|
+
}
|
|
705
|
+
void (async () => {
|
|
706
|
+
try {
|
|
707
|
+
const renewed = await extendClaim.call(store, leaseRef.current, { ttlMs: originalTtlMs });
|
|
708
|
+
leaseRef.current = renewed;
|
|
709
|
+
} catch {
|
|
710
|
+
}
|
|
711
|
+
})();
|
|
712
|
+
}, options.every);
|
|
713
|
+
return function stop() {
|
|
714
|
+
if (handle !== null) {
|
|
715
|
+
clearInterval(handle);
|
|
716
|
+
handle = null;
|
|
717
|
+
}
|
|
718
|
+
};
|
|
719
|
+
}
|
|
720
|
+
if (leaseRef.current === null || typeof extendClaim !== "function") {
|
|
721
|
+
return Promise.resolve();
|
|
722
|
+
}
|
|
723
|
+
const snapshot = leaseRef.current;
|
|
724
|
+
return (async () => {
|
|
725
|
+
const renewed = await extendClaim.call(store, snapshot, { ttlMs: originalTtlMs });
|
|
726
|
+
leaseRef.current = renewed;
|
|
727
|
+
})();
|
|
728
|
+
}
|
|
729
|
+
return keepAlive;
|
|
730
|
+
}
|
|
731
|
+
function noopStop() {
|
|
732
|
+
}
|
|
630
733
|
|
|
631
734
|
// src/agent/session-lifecycle.ts
|
|
632
735
|
function resolveSessionStore(storeEntries) {
|
|
@@ -646,21 +749,43 @@ function resolveSessionStore(storeEntries) {
|
|
|
646
749
|
}
|
|
647
750
|
return result;
|
|
648
751
|
}
|
|
649
|
-
async function querySessionPhase(store, sessionId) {
|
|
752
|
+
async function querySessionPhase(store, agentId, sessionId) {
|
|
650
753
|
if (store === void 0) {
|
|
651
754
|
return { phase: "fresh" };
|
|
652
755
|
}
|
|
653
|
-
const loaded = await store.load(sessionId);
|
|
756
|
+
const loaded = await store.load(agentId, sessionId);
|
|
654
757
|
return storedSessionToPhase(loaded);
|
|
655
758
|
}
|
|
656
|
-
async function runWithSession(store, sessionId, graph, initialStateArg, schema, ctx, options) {
|
|
759
|
+
async function runWithSession(store, agentId, sessionId, runId, graph, initialStateArg, schema, ctx, options) {
|
|
760
|
+
const leaseRef = options?.leaseRef ?? { current: null };
|
|
761
|
+
const keepAlive = createKeepAliveFn(leaseRef, store, options?.claimTtlMs ?? 3e4);
|
|
762
|
+
ctx["keepAlive"] = keepAlive;
|
|
763
|
+
let leaseExpired = false;
|
|
764
|
+
const composedShouldStop = () => {
|
|
765
|
+
if (options?.shouldStop?.() === true) return true;
|
|
766
|
+
if (leaseRef.current !== null && leaseRef.current.expiresAt <= Date.now()) {
|
|
767
|
+
leaseExpired = true;
|
|
768
|
+
return true;
|
|
769
|
+
}
|
|
770
|
+
return false;
|
|
771
|
+
};
|
|
657
772
|
if (store === void 0) {
|
|
658
773
|
const state2 = initializeState(null, initialStateArg, schema);
|
|
659
|
-
|
|
774
|
+
const result2 = await runLoop(graph, state2, ctx, schema, composedShouldStop, void 0, {
|
|
775
|
+
...options,
|
|
776
|
+
runId,
|
|
777
|
+
...options?.parentRunId !== void 0 ? { parentRunId: options.parentRunId } : {}
|
|
778
|
+
});
|
|
779
|
+
if (leaseExpired) {
|
|
780
|
+
const expiredError = new LeaseExpiredError(sessionId);
|
|
781
|
+
options?.onStoreError?.(expiredError, "claim");
|
|
782
|
+
throw expiredError;
|
|
783
|
+
}
|
|
784
|
+
return result2;
|
|
660
785
|
}
|
|
661
786
|
let loaded;
|
|
662
787
|
try {
|
|
663
|
-
loaded = await store.load(sessionId);
|
|
788
|
+
loaded = await store.load(agentId, sessionId);
|
|
664
789
|
} catch (error) {
|
|
665
790
|
const storeError = new StoreLoadError(error);
|
|
666
791
|
options?.onStoreError?.(storeError, "load");
|
|
@@ -668,38 +793,62 @@ async function runWithSession(store, sessionId, graph, initialStateArg, schema,
|
|
|
668
793
|
failState["$error"] = storeError;
|
|
669
794
|
return { state: failState, signal: "$error", paused: false, cursor: null };
|
|
670
795
|
}
|
|
671
|
-
|
|
796
|
+
if (loaded !== null && loaded.phase === "completed") {
|
|
797
|
+
return {
|
|
798
|
+
state: loaded.finalState,
|
|
799
|
+
signal: loaded.signal ?? null,
|
|
800
|
+
cursor: null,
|
|
801
|
+
paused: false
|
|
802
|
+
};
|
|
803
|
+
}
|
|
672
804
|
const state = initializeState(loaded, initialStateArg, schema);
|
|
673
805
|
const initialStateSnapshot = { ...state };
|
|
674
806
|
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
675
|
-
const result = await runLoop(graph, state, ctx, schema,
|
|
807
|
+
const result = await runLoop(graph, state, ctx, schema, composedShouldStop, loaded?.step, {
|
|
808
|
+
...options,
|
|
809
|
+
runId,
|
|
810
|
+
...options?.parentRunId !== void 0 ? { parentRunId: options.parentRunId } : {}
|
|
811
|
+
});
|
|
812
|
+
if (leaseExpired) {
|
|
813
|
+
const expiredError = new LeaseExpiredError(sessionId);
|
|
814
|
+
options?.onStoreError?.(expiredError, "claim");
|
|
815
|
+
throw expiredError;
|
|
816
|
+
}
|
|
676
817
|
const settledAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
818
|
+
const metadata = options?.instanceId !== void 0 ? { instanceId: options.instanceId } : void 0;
|
|
677
819
|
try {
|
|
820
|
+
const version = (loaded?.version ?? -1) + 1;
|
|
678
821
|
if (result.paused) {
|
|
679
822
|
const saved = {
|
|
823
|
+
agentId,
|
|
680
824
|
runId,
|
|
681
825
|
sessionId,
|
|
826
|
+
version,
|
|
682
827
|
startedAt,
|
|
683
828
|
settledAt,
|
|
684
829
|
phase: "paused",
|
|
685
830
|
initialState: initialStateSnapshot,
|
|
686
831
|
finalState: result.state,
|
|
687
832
|
step: result.cursor,
|
|
688
|
-
...result.signal !== null ? { signal: result.signal } : {}
|
|
833
|
+
...result.signal !== null ? { signal: result.signal } : {},
|
|
834
|
+
...metadata !== void 0 ? { metadata } : {}
|
|
689
835
|
};
|
|
690
|
-
await store.save(sessionId, saved);
|
|
836
|
+
await store.save(agentId, sessionId, saved);
|
|
691
837
|
} else {
|
|
692
838
|
const saved = {
|
|
839
|
+
agentId,
|
|
693
840
|
runId,
|
|
694
841
|
sessionId,
|
|
842
|
+
version,
|
|
695
843
|
startedAt,
|
|
696
844
|
settledAt,
|
|
697
845
|
phase: "completed",
|
|
698
846
|
initialState: initialStateSnapshot,
|
|
699
847
|
finalState: result.state,
|
|
700
|
-
...result.signal !== null ? { signal: result.signal } : {}
|
|
848
|
+
...result.signal !== null ? { signal: result.signal } : {},
|
|
849
|
+
...metadata !== void 0 ? { metadata } : {}
|
|
701
850
|
};
|
|
702
|
-
await store.save(sessionId, saved);
|
|
851
|
+
await store.save(agentId, sessionId, saved);
|
|
703
852
|
}
|
|
704
853
|
} catch (error) {
|
|
705
854
|
options?.onStoreError?.(error, "persist");
|
|
@@ -716,8 +865,8 @@ var NoInterruptError = class extends Error {
|
|
|
716
865
|
this.name = "NoInterruptError";
|
|
717
866
|
}
|
|
718
867
|
};
|
|
719
|
-
async function injectInterruptResponse(store, sessionId, interruptId, response) {
|
|
720
|
-
const loaded = await store.load(sessionId);
|
|
868
|
+
async function injectInterruptResponse(store, agentId, sessionId, interruptId, response) {
|
|
869
|
+
const loaded = await store.load(agentId, sessionId);
|
|
721
870
|
if (loaded === null) throw new NoInterruptError();
|
|
722
871
|
if (loaded.phase !== "paused") throw new NoInterruptError();
|
|
723
872
|
const interrupt = loaded.finalState.$interrupt;
|
|
@@ -730,8 +879,10 @@ async function injectInterruptResponse(store, sessionId, interruptId, response)
|
|
|
730
879
|
$interruptResponses: { ...existingResponses, [interruptId]: response }
|
|
731
880
|
};
|
|
732
881
|
const updated = {
|
|
882
|
+
agentId: loaded.agentId,
|
|
733
883
|
runId: loaded.runId,
|
|
734
884
|
sessionId: loaded.sessionId,
|
|
885
|
+
version: loaded.version + 1,
|
|
735
886
|
startedAt: loaded.startedAt,
|
|
736
887
|
settledAt: loaded.settledAt,
|
|
737
888
|
phase: "paused",
|
|
@@ -740,11 +891,11 @@ async function injectInterruptResponse(store, sessionId, interruptId, response)
|
|
|
740
891
|
...loaded.step !== void 0 ? { step: loaded.step } : {},
|
|
741
892
|
...loaded.signal !== void 0 ? { signal: loaded.signal } : {}
|
|
742
893
|
};
|
|
743
|
-
await store.save(sessionId, updated);
|
|
894
|
+
await store.save(agentId, sessionId, updated);
|
|
744
895
|
}
|
|
745
896
|
|
|
746
897
|
// src/agent/run-handle.ts
|
|
747
|
-
function createRunHandle(sessionId, execution, stopFlag, stepRef, resumeFn) {
|
|
898
|
+
function createRunHandle(sessionId, runId, execution, stopFlag, stepRef, resumeFn) {
|
|
748
899
|
let settledOutcome = null;
|
|
749
900
|
const settled = execution.then(
|
|
750
901
|
(outcome) => {
|
|
@@ -782,6 +933,9 @@ function createRunHandle(sessionId, execution, stopFlag, stepRef, resumeFn) {
|
|
|
782
933
|
get sessionId() {
|
|
783
934
|
return sessionId;
|
|
784
935
|
},
|
|
936
|
+
get runId() {
|
|
937
|
+
return runId;
|
|
938
|
+
},
|
|
785
939
|
get currentStep() {
|
|
786
940
|
return stepRef.current;
|
|
787
941
|
}
|
|
@@ -790,7 +944,7 @@ function createRunHandle(sessionId, execution, stopFlag, stepRef, resumeFn) {
|
|
|
790
944
|
}
|
|
791
945
|
|
|
792
946
|
// src/agent/create-agent.ts
|
|
793
|
-
import { randomUUID
|
|
947
|
+
import { randomUUID } from "crypto";
|
|
794
948
|
|
|
795
949
|
// src/agent/event-callbacks.ts
|
|
796
950
|
function extractRunEvents(resources) {
|
|
@@ -802,13 +956,20 @@ function extractRunEvents(resources) {
|
|
|
802
956
|
}
|
|
803
957
|
|
|
804
958
|
// src/agent/create-agent.ts
|
|
959
|
+
var NOOP_OBSERVER = {};
|
|
960
|
+
function extractRunObserver(resources) {
|
|
961
|
+
const raw = resources["observer"];
|
|
962
|
+
if (raw === null || typeof raw !== "object" || Array.isArray(raw)) return void 0;
|
|
963
|
+
return raw;
|
|
964
|
+
}
|
|
805
965
|
var MissingLoopError = class extends Error {
|
|
806
966
|
constructor() {
|
|
807
|
-
super("harness has no loop \u2014 call h.loop() before createAgent()");
|
|
967
|
+
super("harness has no loop \u2014 call h.loop() before createAgent(id, h, slots)");
|
|
808
968
|
this.name = "MissingLoopError";
|
|
809
969
|
}
|
|
810
970
|
};
|
|
811
971
|
var MissingSlotError = class extends Error {
|
|
972
|
+
/** The missing slot key. */
|
|
812
973
|
key;
|
|
813
974
|
constructor(key) {
|
|
814
975
|
super(`required slot "${key}" was not provided in createAgent slots`);
|
|
@@ -817,6 +978,7 @@ var MissingSlotError = class extends Error {
|
|
|
817
978
|
}
|
|
818
979
|
};
|
|
819
980
|
var RuntimeSlotInAgentError = class extends Error {
|
|
981
|
+
/** The offending slot key. */
|
|
820
982
|
key;
|
|
821
983
|
constructor(key) {
|
|
822
984
|
super(`slot "${key}" is a runtime() slot \u2014 provide it in agent.run(), not createAgent()`);
|
|
@@ -825,6 +987,7 @@ var RuntimeSlotInAgentError = class extends Error {
|
|
|
825
987
|
}
|
|
826
988
|
};
|
|
827
989
|
var UnknownSlotError = class extends Error {
|
|
990
|
+
/** The unknown slot key. */
|
|
828
991
|
key;
|
|
829
992
|
constructor(key) {
|
|
830
993
|
super(`slot "${key}" is not declared in the harness \u2014 remove it or add h.provide("${key}", required())`);
|
|
@@ -833,6 +996,7 @@ var UnknownSlotError = class extends Error {
|
|
|
833
996
|
}
|
|
834
997
|
};
|
|
835
998
|
var MissingRuntimeSlotError = class extends Error {
|
|
999
|
+
/** The missing runtime slot key. */
|
|
836
1000
|
key;
|
|
837
1001
|
constructor(key) {
|
|
838
1002
|
super(`runtime slot "${key}" was not provided in agent.run() resources`);
|
|
@@ -841,6 +1005,7 @@ var MissingRuntimeSlotError = class extends Error {
|
|
|
841
1005
|
}
|
|
842
1006
|
};
|
|
843
1007
|
var RequiredSlotInRunError = class extends Error {
|
|
1008
|
+
/** The offending slot key. */
|
|
844
1009
|
key;
|
|
845
1010
|
constructor(key) {
|
|
846
1011
|
super(`slot "${key}" is a required() slot \u2014 provide it in createAgent(), not agent.run()`);
|
|
@@ -849,6 +1014,7 @@ var RequiredSlotInRunError = class extends Error {
|
|
|
849
1014
|
}
|
|
850
1015
|
};
|
|
851
1016
|
var UnknownRunSlotError = class extends Error {
|
|
1017
|
+
/** The unknown resource key. */
|
|
852
1018
|
key;
|
|
853
1019
|
constructor(key) {
|
|
854
1020
|
super(`slot "${key}" is not a runtime() slot \u2014 do not pass it in agent.run() resources`);
|
|
@@ -857,7 +1023,7 @@ var UnknownRunSlotError = class extends Error {
|
|
|
857
1023
|
}
|
|
858
1024
|
};
|
|
859
1025
|
var _agentInternals = /* @__PURE__ */ Symbol("_agentInternals");
|
|
860
|
-
function createAgent(h, slots) {
|
|
1026
|
+
function createAgent(id, h, slots, agentOptions) {
|
|
861
1027
|
const internals = getInternals(h);
|
|
862
1028
|
if (internals.loopDef === void 0) {
|
|
863
1029
|
throw new MissingLoopError();
|
|
@@ -906,6 +1072,7 @@ function createAgent(h, slots) {
|
|
|
906
1072
|
}
|
|
907
1073
|
const capturedStore = resolveSessionStore(storeEntries);
|
|
908
1074
|
const agentInternals = {
|
|
1075
|
+
agentId: id,
|
|
909
1076
|
resolvedProviders,
|
|
910
1077
|
storeEntries,
|
|
911
1078
|
loopDef: internals.loopDef,
|
|
@@ -914,38 +1081,104 @@ function createAgent(h, slots) {
|
|
|
914
1081
|
runtimeKeys,
|
|
915
1082
|
requiredKeys
|
|
916
1083
|
};
|
|
917
|
-
const reservedRunKeys = /* @__PURE__ */ new Set(["sessionId", "signal", "events", "listeners"]);
|
|
1084
|
+
const reservedRunKeys = /* @__PURE__ */ new Set(["sessionId", "signal", "events", "listeners", "observer", "claimOptions", "parentRunId"]);
|
|
918
1085
|
const inFlightSessions = /* @__PURE__ */ new Set();
|
|
919
1086
|
const interruptPendingSessions = /* @__PURE__ */ new Set();
|
|
920
|
-
const makeAgentResumeHandle = (resp, sId, iId) => {
|
|
921
|
-
|
|
1087
|
+
const makeAgentResumeHandle = (resp, sId, iId, resumeOpts, observer, setStepContextSlots) => {
|
|
1088
|
+
let _stopped = false;
|
|
1089
|
+
const abortController = new AbortController();
|
|
1090
|
+
const flag = {
|
|
1091
|
+
get stopped() {
|
|
1092
|
+
return _stopped;
|
|
1093
|
+
},
|
|
1094
|
+
set stopped(v) {
|
|
1095
|
+
_stopped = v;
|
|
1096
|
+
if (v) abortController.abort();
|
|
1097
|
+
}
|
|
1098
|
+
};
|
|
922
1099
|
const ref = { current: null };
|
|
1100
|
+
const rId = randomUUID();
|
|
923
1101
|
const exec = (async () => {
|
|
924
1102
|
await Promise.resolve();
|
|
1103
|
+
const claimOptions = { ttlMs: 3e4 };
|
|
1104
|
+
let leaseRef = void 0;
|
|
925
1105
|
try {
|
|
926
|
-
if (capturedStore ===
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
1106
|
+
if (typeof capturedStore?.claim === "function") {
|
|
1107
|
+
let lease;
|
|
1108
|
+
try {
|
|
1109
|
+
lease = await capturedStore.claim(id, sId, claimOptions);
|
|
1110
|
+
} catch (claimError) {
|
|
1111
|
+
const loadError = new StoreLoadError(claimError);
|
|
1112
|
+
resumeOpts?.onStoreError?.(loadError, "claim");
|
|
1113
|
+
const failState = initializeState(null, {}, agentInternals.stateSchema);
|
|
1114
|
+
failState["$error"] = loadError;
|
|
1115
|
+
return { state: failState, signal: "$error" };
|
|
1116
|
+
}
|
|
1117
|
+
if (lease === null) {
|
|
1118
|
+
const busyError = new SessionBusyError(sId);
|
|
1119
|
+
resumeOpts?.onStoreError?.(busyError, "claim");
|
|
1120
|
+
const failState = initializeState(null, {}, agentInternals.stateSchema);
|
|
1121
|
+
failState["$error"] = busyError;
|
|
1122
|
+
return { state: failState, signal: "$error" };
|
|
1123
|
+
}
|
|
1124
|
+
leaseRef = { current: lease };
|
|
1125
|
+
}
|
|
1126
|
+
try {
|
|
1127
|
+
if (capturedStore === void 0) throw new NoInterruptError();
|
|
1128
|
+
try {
|
|
1129
|
+
await injectInterruptResponse(capturedStore, id, sId, iId, resp);
|
|
1130
|
+
} catch (injectError) {
|
|
1131
|
+
if (injectError instanceof NoInterruptError) throw injectError;
|
|
1132
|
+
const storeError = new StoreLoadError(injectError);
|
|
1133
|
+
resumeOpts?.onStoreError?.(storeError, "claim");
|
|
1134
|
+
const failState = initializeState(null, {}, agentInternals.stateSchema);
|
|
1135
|
+
failState["$error"] = storeError;
|
|
1136
|
+
return { state: failState, signal: "$error" };
|
|
1137
|
+
}
|
|
1138
|
+
const agentCtx = {
|
|
1139
|
+
...Object.fromEntries(agentInternals.resolvedProviders),
|
|
1140
|
+
agentId: id,
|
|
1141
|
+
sessionId: sId,
|
|
1142
|
+
runId: rId,
|
|
1143
|
+
signal: abortController.signal
|
|
1144
|
+
};
|
|
1145
|
+
const r = await runWithSession(
|
|
1146
|
+
capturedStore,
|
|
1147
|
+
id,
|
|
1148
|
+
sId,
|
|
1149
|
+
rId,
|
|
1150
|
+
agentInternals.loopDef,
|
|
1151
|
+
{},
|
|
1152
|
+
agentInternals.stateSchema,
|
|
1153
|
+
agentCtx,
|
|
1154
|
+
{
|
|
1155
|
+
shouldStop: () => flag.stopped,
|
|
1156
|
+
onBeforeStep: (n) => {
|
|
1157
|
+
ref.current = n;
|
|
1158
|
+
},
|
|
1159
|
+
...resumeOpts?.onStoreError !== void 0 ? { onStoreError: resumeOpts.onStoreError } : {},
|
|
1160
|
+
...leaseRef !== void 0 ? { leaseRef, claimTtlMs: claimOptions.ttlMs } : {},
|
|
1161
|
+
...observer !== void 0 ? { observer } : {},
|
|
1162
|
+
...setStepContextSlots !== void 0 && setStepContextSlots.length > 0 ? { setStepContextSlots } : {}
|
|
943
1163
|
}
|
|
944
|
-
|
|
1164
|
+
);
|
|
1165
|
+
if (r.signal === "$interrupt") interruptPendingSessions.add(sId);
|
|
1166
|
+
return { state: r.state, signal: r.signal };
|
|
1167
|
+
} catch (error) {
|
|
1168
|
+
if (error instanceof LeaseExpiredError) {
|
|
1169
|
+
const failState = initializeState(null, {}, agentInternals.stateSchema);
|
|
1170
|
+
failState["$error"] = error;
|
|
1171
|
+
return { state: failState, signal: "$error" };
|
|
945
1172
|
}
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
1173
|
+
throw error;
|
|
1174
|
+
} finally {
|
|
1175
|
+
if (leaseRef !== void 0 && typeof capturedStore?.release === "function") {
|
|
1176
|
+
try {
|
|
1177
|
+
await capturedStore.release(leaseRef.current);
|
|
1178
|
+
} catch {
|
|
1179
|
+
}
|
|
1180
|
+
}
|
|
1181
|
+
}
|
|
949
1182
|
} finally {
|
|
950
1183
|
inFlightSessions.delete(sId);
|
|
951
1184
|
}
|
|
@@ -956,9 +1189,10 @@ function createAgent(h, slots) {
|
|
|
956
1189
|
inFlightSessions.add(sId);
|
|
957
1190
|
return makeAgentResumeHandle(r, sId, i);
|
|
958
1191
|
};
|
|
959
|
-
return createRunHandle(sId, exec, flag, ref, resumeFn);
|
|
1192
|
+
return createRunHandle(sId, rId, exec, flag, ref, resumeFn);
|
|
960
1193
|
};
|
|
961
1194
|
const agent = {
|
|
1195
|
+
id,
|
|
962
1196
|
run: (initialState, resources) => {
|
|
963
1197
|
for (const key of Object.keys(resources)) {
|
|
964
1198
|
if (reservedRunKeys.has(key)) continue;
|
|
@@ -977,15 +1211,29 @@ function createAgent(h, slots) {
|
|
|
977
1211
|
throw new MissingRuntimeSlotError(key);
|
|
978
1212
|
}
|
|
979
1213
|
}
|
|
980
|
-
const sessionId = typeof resources["sessionId"] === "string" ? resources["sessionId"] :
|
|
1214
|
+
const sessionId = typeof resources["sessionId"] === "string" ? resources["sessionId"] : randomUUID();
|
|
1215
|
+
const runId = randomUUID();
|
|
981
1216
|
if (inFlightSessions.has(sessionId)) throw new SessionInFlightError(sessionId);
|
|
982
1217
|
if (interruptPendingSessions.has(sessionId)) throw new SessionPendingInterruptError(sessionId);
|
|
983
1218
|
inFlightSessions.add(sessionId);
|
|
984
|
-
|
|
1219
|
+
let _stopped = false;
|
|
1220
|
+
const abortController = new AbortController();
|
|
1221
|
+
const stopFlag = {
|
|
1222
|
+
get stopped() {
|
|
1223
|
+
return _stopped;
|
|
1224
|
+
},
|
|
1225
|
+
set stopped(v) {
|
|
1226
|
+
_stopped = v;
|
|
1227
|
+
if (v) abortController.abort();
|
|
1228
|
+
}
|
|
1229
|
+
};
|
|
985
1230
|
const rawSignal = resources["signal"];
|
|
1231
|
+
let ctxSignal = abortController.signal;
|
|
986
1232
|
if (rawSignal instanceof AbortSignal) {
|
|
1233
|
+
ctxSignal = rawSignal;
|
|
987
1234
|
rawSignal.addEventListener("abort", () => {
|
|
988
1235
|
stopFlag.stopped = true;
|
|
1236
|
+
abortController.abort();
|
|
989
1237
|
}, { once: true });
|
|
990
1238
|
if (rawSignal.aborted) stopFlag.stopped = true;
|
|
991
1239
|
}
|
|
@@ -998,10 +1246,27 @@ function createAgent(h, slots) {
|
|
|
998
1246
|
const ctx = {
|
|
999
1247
|
...Object.fromEntries(agentInternals.resolvedProviders),
|
|
1000
1248
|
...runtimeSlots,
|
|
1001
|
-
|
|
1249
|
+
agentId: id,
|
|
1250
|
+
sessionId,
|
|
1251
|
+
runId,
|
|
1252
|
+
signal: ctxSignal,
|
|
1253
|
+
...agentOptions?.instanceId !== void 0 ? { instanceId: agentOptions.instanceId } : {}
|
|
1002
1254
|
};
|
|
1003
1255
|
const events = extractRunEvents(resources);
|
|
1004
1256
|
const listeners = extractRunListeners(resources);
|
|
1257
|
+
const observer = extractRunObserver(resources);
|
|
1258
|
+
for (const slot of [...agentInternals.resolvedProviders.values(), ...Object.values(runtimeSlots)]) {
|
|
1259
|
+
if (slot !== null && typeof slot === "object" && typeof slot["bindObserver"] === "function") {
|
|
1260
|
+
slot.bindObserver(observer ?? NOOP_OBSERVER);
|
|
1261
|
+
}
|
|
1262
|
+
}
|
|
1263
|
+
const setStepContextSlots = [];
|
|
1264
|
+
for (const slot of [...agentInternals.resolvedProviders.values(), ...Object.values(runtimeSlots)]) {
|
|
1265
|
+
if (slot !== null && typeof slot === "object" && typeof slot["setStepContext"] === "function") {
|
|
1266
|
+
setStepContextSlots.push(slot);
|
|
1267
|
+
}
|
|
1268
|
+
}
|
|
1269
|
+
const parentRunId = typeof resources["parentRunId"] === "string" ? resources["parentRunId"] : void 0;
|
|
1005
1270
|
const options = {
|
|
1006
1271
|
shouldStop: () => stopFlag.stopped,
|
|
1007
1272
|
onBeforeStep: (name, state) => {
|
|
@@ -1014,24 +1279,72 @@ function createAgent(h, slots) {
|
|
|
1014
1279
|
...events.onError !== void 0 ? { onError: events.onError } : {},
|
|
1015
1280
|
...events.onComplete !== void 0 ? { onComplete: events.onComplete } : {},
|
|
1016
1281
|
...events.onInterrupt !== void 0 ? { onInterrupt: events.onInterrupt } : {},
|
|
1017
|
-
...Object.keys(listeners).length > 0 ? { listeners } : {}
|
|
1282
|
+
...Object.keys(listeners).length > 0 ? { listeners } : {},
|
|
1283
|
+
...observer !== void 0 ? { observer } : {},
|
|
1284
|
+
...agentOptions?.instanceId !== void 0 ? { instanceId: agentOptions.instanceId } : {},
|
|
1285
|
+
...parentRunId !== void 0 ? { parentRunId } : {},
|
|
1286
|
+
...setStepContextSlots.length > 0 ? { setStepContextSlots } : {}
|
|
1018
1287
|
};
|
|
1019
1288
|
let lastResult = null;
|
|
1020
1289
|
const execution = (async () => {
|
|
1021
1290
|
await Promise.resolve();
|
|
1291
|
+
const rawClaimOpts = resources["claimOptions"];
|
|
1292
|
+
const claimOptions = typeof rawClaimOpts === "object" && rawClaimOpts !== null && typeof rawClaimOpts["ttlMs"] === "number" ? rawClaimOpts : { ttlMs: 3e4 };
|
|
1293
|
+
let leaseRef = void 0;
|
|
1022
1294
|
try {
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1295
|
+
if (typeof capturedStore?.claim === "function") {
|
|
1296
|
+
let lease;
|
|
1297
|
+
try {
|
|
1298
|
+
lease = await capturedStore.claim(id, sessionId, claimOptions);
|
|
1299
|
+
} catch (claimError) {
|
|
1300
|
+
const loadError = new StoreLoadError(claimError);
|
|
1301
|
+
events.onStoreError?.(loadError, "claim");
|
|
1302
|
+
const failState = initializeState(null, initialState, agentInternals.stateSchema);
|
|
1303
|
+
failState["$error"] = loadError;
|
|
1304
|
+
return { state: failState, signal: "$error" };
|
|
1305
|
+
}
|
|
1306
|
+
if (lease === null) {
|
|
1307
|
+
const busyError = new SessionBusyError(sessionId);
|
|
1308
|
+
events.onStoreError?.(busyError, "claim");
|
|
1309
|
+
const failState = initializeState(null, initialState, agentInternals.stateSchema);
|
|
1310
|
+
failState["$error"] = busyError;
|
|
1311
|
+
return { state: failState, signal: "$error" };
|
|
1312
|
+
}
|
|
1313
|
+
leaseRef = { current: lease };
|
|
1314
|
+
}
|
|
1315
|
+
try {
|
|
1316
|
+
const r = await runWithSession(
|
|
1317
|
+
capturedStore,
|
|
1318
|
+
id,
|
|
1319
|
+
sessionId,
|
|
1320
|
+
runId,
|
|
1321
|
+
agentInternals.loopDef,
|
|
1322
|
+
initialState,
|
|
1323
|
+
agentInternals.stateSchema,
|
|
1324
|
+
ctx,
|
|
1325
|
+
{
|
|
1326
|
+
...options,
|
|
1327
|
+
...leaseRef !== void 0 ? { leaseRef, claimTtlMs: claimOptions.ttlMs } : {}
|
|
1328
|
+
}
|
|
1329
|
+
);
|
|
1330
|
+
if (r.signal === "$interrupt") interruptPendingSessions.add(sessionId);
|
|
1331
|
+
lastResult = { state: r.state, cursor: r.cursor };
|
|
1332
|
+
return { state: r.state, signal: r.signal };
|
|
1333
|
+
} catch (error) {
|
|
1334
|
+
if (error instanceof LeaseExpiredError) {
|
|
1335
|
+
const failState = initializeState(null, initialState, agentInternals.stateSchema);
|
|
1336
|
+
failState["$error"] = error;
|
|
1337
|
+
return { state: failState, signal: "$error" };
|
|
1338
|
+
}
|
|
1339
|
+
throw error;
|
|
1340
|
+
} finally {
|
|
1341
|
+
if (leaseRef !== void 0 && typeof capturedStore?.release === "function") {
|
|
1342
|
+
try {
|
|
1343
|
+
await capturedStore.release(leaseRef.current);
|
|
1344
|
+
} catch {
|
|
1345
|
+
}
|
|
1346
|
+
}
|
|
1347
|
+
}
|
|
1035
1348
|
} finally {
|
|
1036
1349
|
inFlightSessions.delete(sessionId);
|
|
1037
1350
|
}
|
|
@@ -1041,20 +1354,38 @@ function createAgent(h, slots) {
|
|
|
1041
1354
|
if (inFlightSessions.has(sessionId)) throw new SessionInFlightError(sessionId);
|
|
1042
1355
|
interruptPendingSessions.delete(sessionId);
|
|
1043
1356
|
inFlightSessions.add(sessionId);
|
|
1044
|
-
|
|
1357
|
+
let _resumeStopped = false;
|
|
1358
|
+
const resumeAbortController = new AbortController();
|
|
1359
|
+
const resumeStopFlag = {
|
|
1360
|
+
get stopped() {
|
|
1361
|
+
return _resumeStopped;
|
|
1362
|
+
},
|
|
1363
|
+
set stopped(v) {
|
|
1364
|
+
_resumeStopped = v;
|
|
1365
|
+
if (v) resumeAbortController.abort();
|
|
1366
|
+
}
|
|
1367
|
+
};
|
|
1045
1368
|
const resumeStepRef = { current: null };
|
|
1369
|
+
const resumeRunId = randomUUID();
|
|
1046
1370
|
const resumeExecution = (async () => {
|
|
1047
1371
|
await Promise.resolve();
|
|
1048
1372
|
try {
|
|
1373
|
+
const resumeCtx = {
|
|
1374
|
+
...ctx,
|
|
1375
|
+
runId: resumeRunId,
|
|
1376
|
+
signal: resumeAbortController.signal
|
|
1377
|
+
};
|
|
1049
1378
|
if (capturedStore !== void 0) {
|
|
1050
|
-
await injectInterruptResponse(capturedStore, sessionId, interruptId, response);
|
|
1379
|
+
await injectInterruptResponse(capturedStore, id, sessionId, interruptId, response);
|
|
1051
1380
|
const r2 = await runWithSession(
|
|
1052
1381
|
capturedStore,
|
|
1382
|
+
id,
|
|
1053
1383
|
sessionId,
|
|
1384
|
+
resumeRunId,
|
|
1054
1385
|
agentInternals.loopDef,
|
|
1055
1386
|
{},
|
|
1056
1387
|
agentInternals.stateSchema,
|
|
1057
|
-
|
|
1388
|
+
resumeCtx,
|
|
1058
1389
|
{
|
|
1059
1390
|
shouldStop: () => resumeStopFlag.stopped,
|
|
1060
1391
|
onBeforeStep: (n, s) => {
|
|
@@ -1067,7 +1398,9 @@ function createAgent(h, slots) {
|
|
|
1067
1398
|
...events.onError !== void 0 ? { onError: events.onError } : {},
|
|
1068
1399
|
...events.onComplete !== void 0 ? { onComplete: events.onComplete } : {},
|
|
1069
1400
|
...events.onInterrupt !== void 0 ? { onInterrupt: events.onInterrupt } : {},
|
|
1070
|
-
...Object.keys(listeners).length > 0 ? { listeners } : {}
|
|
1401
|
+
...Object.keys(listeners).length > 0 ? { listeners } : {},
|
|
1402
|
+
...observer !== void 0 ? { observer } : {},
|
|
1403
|
+
...setStepContextSlots.length > 0 ? { setStepContextSlots } : {}
|
|
1071
1404
|
}
|
|
1072
1405
|
);
|
|
1073
1406
|
if (r2.signal === "$interrupt") interruptPendingSessions.add(sessionId);
|
|
@@ -1084,11 +1417,12 @@ function createAgent(h, slots) {
|
|
|
1084
1417
|
const r = await runLoop(
|
|
1085
1418
|
agentInternals.loopDef,
|
|
1086
1419
|
state,
|
|
1087
|
-
|
|
1420
|
+
resumeCtx,
|
|
1088
1421
|
agentInternals.stateSchema,
|
|
1089
1422
|
() => resumeStopFlag.stopped,
|
|
1090
1423
|
cursor,
|
|
1091
1424
|
{
|
|
1425
|
+
runId: resumeRunId,
|
|
1092
1426
|
onBeforeStep: (n, s) => {
|
|
1093
1427
|
resumeStepRef.current = n;
|
|
1094
1428
|
events.onBeforeStep?.(n, s);
|
|
@@ -1097,39 +1431,91 @@ function createAgent(h, slots) {
|
|
|
1097
1431
|
...events.onError !== void 0 ? { onError: events.onError } : {},
|
|
1098
1432
|
...events.onComplete !== void 0 ? { onComplete: events.onComplete } : {},
|
|
1099
1433
|
...events.onInterrupt !== void 0 ? { onInterrupt: events.onInterrupt } : {},
|
|
1100
|
-
...Object.keys(listeners).length > 0 ? { listeners } : {}
|
|
1434
|
+
...Object.keys(listeners).length > 0 ? { listeners } : {},
|
|
1435
|
+
...observer !== void 0 ? { observer } : {},
|
|
1436
|
+
...setStepContextSlots.length > 0 ? { setStepContextSlots } : {}
|
|
1101
1437
|
}
|
|
1102
1438
|
);
|
|
1103
1439
|
if (r.signal === "$interrupt") interruptPendingSessions.add(sessionId);
|
|
1104
1440
|
lastResult = { state: r.state, cursor: r.cursor };
|
|
1105
1441
|
return { state: r.state, signal: r.signal };
|
|
1442
|
+
} catch (error) {
|
|
1443
|
+
if (error instanceof LeaseExpiredError) {
|
|
1444
|
+
const failState = initializeState(null, initialState, agentInternals.stateSchema);
|
|
1445
|
+
failState["$error"] = error;
|
|
1446
|
+
return { state: failState, signal: "$error" };
|
|
1447
|
+
}
|
|
1448
|
+
throw error;
|
|
1106
1449
|
} finally {
|
|
1107
1450
|
inFlightSessions.delete(sessionId);
|
|
1108
1451
|
}
|
|
1109
1452
|
})();
|
|
1110
|
-
return createRunHandle(sessionId, resumeExecution, resumeStopFlag, resumeStepRef, buildResumeFn());
|
|
1453
|
+
return createRunHandle(sessionId, resumeRunId, resumeExecution, resumeStopFlag, resumeStepRef, buildResumeFn());
|
|
1111
1454
|
};
|
|
1112
1455
|
};
|
|
1113
|
-
return createRunHandle(sessionId, execution, stopFlag, stepRef, buildResumeFn());
|
|
1456
|
+
return createRunHandle(sessionId, runId, execution, stopFlag, stepRef, buildResumeFn());
|
|
1114
1457
|
},
|
|
1115
|
-
resume: (response, sessionId, interruptId) => {
|
|
1458
|
+
resume: (response, sessionId, interruptId, resources) => {
|
|
1116
1459
|
if (inFlightSessions.has(sessionId)) throw new SessionInFlightError(sessionId);
|
|
1117
1460
|
interruptPendingSessions.delete(sessionId);
|
|
1118
1461
|
inFlightSessions.add(sessionId);
|
|
1119
|
-
|
|
1462
|
+
const events = extractRunEvents(resources ?? {});
|
|
1463
|
+
const resumeOpts = events.onStoreError !== void 0 ? { onStoreError: events.onStoreError } : void 0;
|
|
1464
|
+
const observer = extractRunObserver(resources ?? {});
|
|
1465
|
+
for (const slot of agentInternals.resolvedProviders.values()) {
|
|
1466
|
+
if (slot !== null && typeof slot === "object" && typeof slot["bindObserver"] === "function") {
|
|
1467
|
+
slot.bindObserver(observer ?? NOOP_OBSERVER);
|
|
1468
|
+
}
|
|
1469
|
+
}
|
|
1470
|
+
const setStepContextSlots = [];
|
|
1471
|
+
for (const slot of agentInternals.resolvedProviders.values()) {
|
|
1472
|
+
if (slot !== null && typeof slot === "object" && typeof slot["setStepContext"] === "function") {
|
|
1473
|
+
setStepContextSlots.push(slot);
|
|
1474
|
+
}
|
|
1475
|
+
}
|
|
1476
|
+
return makeAgentResumeHandle(response, sessionId, interruptId, resumeOpts, observer ?? void 0, setStepContextSlots.length > 0 ? setStepContextSlots : void 0);
|
|
1120
1477
|
},
|
|
1121
|
-
status: (sessionId) => querySessionPhase(capturedStore, sessionId),
|
|
1478
|
+
status: (sessionId) => querySessionPhase(capturedStore, id, sessionId),
|
|
1122
1479
|
[_agentInternals]: agentInternals
|
|
1123
1480
|
};
|
|
1124
1481
|
return agent;
|
|
1125
1482
|
}
|
|
1483
|
+
|
|
1484
|
+
// src/agent/observer.ts
|
|
1485
|
+
function composeObservers(...observers) {
|
|
1486
|
+
return {
|
|
1487
|
+
onRunStart: (ctx) => {
|
|
1488
|
+
for (const o of observers) o.onRunStart?.(ctx);
|
|
1489
|
+
},
|
|
1490
|
+
onRunEnd: (ctx, event) => {
|
|
1491
|
+
for (const o of observers) o.onRunEnd?.(ctx, event);
|
|
1492
|
+
},
|
|
1493
|
+
onStepStart: (ctx) => {
|
|
1494
|
+
for (const o of observers) o.onStepStart?.(ctx);
|
|
1495
|
+
},
|
|
1496
|
+
onStepEnd: (ctx, event) => {
|
|
1497
|
+
for (const o of observers) o.onStepEnd?.(ctx, event);
|
|
1498
|
+
},
|
|
1499
|
+
onStepError: (ctx, event) => {
|
|
1500
|
+
for (const o of observers) o.onStepError?.(ctx, event);
|
|
1501
|
+
},
|
|
1502
|
+
onInterrupt: (ctx, event) => {
|
|
1503
|
+
for (const o of observers) o.onInterrupt?.(ctx, event);
|
|
1504
|
+
},
|
|
1505
|
+
onEvent: (ctx, type, payload) => {
|
|
1506
|
+
for (const o of observers) o.onEvent?.(ctx, type, payload);
|
|
1507
|
+
}
|
|
1508
|
+
};
|
|
1509
|
+
}
|
|
1126
1510
|
export {
|
|
1511
|
+
LoopNotDefinedError,
|
|
1127
1512
|
NoInterruptError,
|
|
1128
1513
|
REQUIRED_TAG,
|
|
1129
1514
|
RUNTIME_TAG,
|
|
1130
1515
|
SessionInFlightError,
|
|
1131
1516
|
SessionPendingInterruptError,
|
|
1132
1517
|
StoreLoadError,
|
|
1518
|
+
composeObservers,
|
|
1133
1519
|
createAgent,
|
|
1134
1520
|
createHarness,
|
|
1135
1521
|
field,
|