@noetaris/harness 0.1.0 → 0.2.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 +555 -40
- package/dist/index.js +405 -73
- package/dist/index.js.map +1 -1
- package/package.json +12 -2
package/dist/index.js
CHANGED
|
@@ -372,9 +372,6 @@ function createBuilderInstance(internals) {
|
|
|
372
372
|
return builder;
|
|
373
373
|
}
|
|
374
374
|
|
|
375
|
-
// src/agent/session-lifecycle.ts
|
|
376
|
-
import { randomUUID } from "crypto";
|
|
377
|
-
|
|
378
375
|
// src/agent/ctx-interrupt.ts
|
|
379
376
|
var InterruptPause = class extends Error {
|
|
380
377
|
interruptId;
|
|
@@ -406,9 +403,12 @@ function createInterruptFn(state, callCountRef) {
|
|
|
406
403
|
}
|
|
407
404
|
|
|
408
405
|
// src/agent/ctx-emit.ts
|
|
409
|
-
function createEmitFn(listeners) {
|
|
406
|
+
function createEmitFn(listeners, observer, stepCtxRef) {
|
|
410
407
|
return (name, payload) => {
|
|
411
408
|
listeners[name]?.(payload);
|
|
409
|
+
if (observer !== void 0 && stepCtxRef !== void 0 && stepCtxRef.current !== null) {
|
|
410
|
+
observer.onEvent?.(stepCtxRef.current, name, payload);
|
|
411
|
+
}
|
|
412
412
|
};
|
|
413
413
|
}
|
|
414
414
|
function extractRunListeners(resources) {
|
|
@@ -462,21 +462,37 @@ function applyUpdate(state, update, schema) {
|
|
|
462
462
|
}
|
|
463
463
|
async function runLoop(graph, state, ctx, schema, shouldStop, startCursor, callbacks) {
|
|
464
464
|
const { onBeforeStep, onAfterStep, onError, onComplete, onInterrupt } = callbacks ?? {};
|
|
465
|
+
const obs = callbacks?.observer;
|
|
465
466
|
const implicitNextMap = buildImplicitNextMap(graph);
|
|
466
467
|
if (!("$error" in state)) state.$error = null;
|
|
467
468
|
if (!("$interrupt" in state)) state.$interrupt = null;
|
|
468
469
|
if (!("$interruptResponses" in state)) state.$interruptResponses = {};
|
|
470
|
+
const runStart = Date.now();
|
|
471
|
+
const runCtx = {
|
|
472
|
+
agentId: ctx.agentId,
|
|
473
|
+
sessionId: ctx.sessionId,
|
|
474
|
+
runId: typeof callbacks?.runId === "string" ? callbacks.runId : "",
|
|
475
|
+
...typeof callbacks?.parentRunId === "string" ? { parentRunId: callbacks.parentRunId } : {},
|
|
476
|
+
...typeof ctx.instanceId === "string" ? { instanceId: ctx.instanceId } : {}
|
|
477
|
+
};
|
|
478
|
+
obs?.onRunStart?.(runCtx);
|
|
469
479
|
const callCountRef = { current: 0 };
|
|
480
|
+
const stepCtxRef = { current: null };
|
|
470
481
|
ctx["interrupt"] = createInterruptFn(state, callCountRef);
|
|
471
|
-
ctx["emit"] = createEmitFn(callbacks?.listeners ?? {});
|
|
482
|
+
ctx["emit"] = createEmitFn(callbacks?.listeners ?? {}, obs, stepCtxRef);
|
|
472
483
|
let cursor = startCursor ?? graph.entryStep;
|
|
473
484
|
while (true) {
|
|
474
485
|
if (shouldStop?.()) {
|
|
486
|
+
obs?.onRunEnd?.(runCtx, { signal: "$stopped", durationMs: Date.now() - runStart });
|
|
475
487
|
return { state, signal: null, cursor, paused: true };
|
|
476
488
|
}
|
|
477
489
|
onBeforeStep?.(cursor, { ...state });
|
|
478
490
|
const step = graph.steps.find((s) => s.name === cursor);
|
|
479
491
|
callCountRef.current = 0;
|
|
492
|
+
const stepCtx = { agentId: ctx.agentId, sessionId: ctx.sessionId, stepName: cursor };
|
|
493
|
+
stepCtxRef.current = stepCtx;
|
|
494
|
+
const stepStart = Date.now();
|
|
495
|
+
obs?.onStepStart?.(stepCtx);
|
|
480
496
|
let runSucceeded = false;
|
|
481
497
|
if (step.run !== void 0) {
|
|
482
498
|
const hadResponses = Object.keys(state.$interruptResponses).length > 0;
|
|
@@ -494,15 +510,19 @@ async function runLoop(graph, state, ctx, schema, shouldStop, startCursor, callb
|
|
|
494
510
|
} catch (e) {
|
|
495
511
|
if (isInterruptPause(e)) {
|
|
496
512
|
onInterrupt?.(e.prompt, e.interruptId);
|
|
513
|
+
obs?.onInterrupt?.(stepCtx, { prompt: e.prompt, interruptId: e.interruptId });
|
|
514
|
+
obs?.onRunEnd?.(runCtx, { signal: "$interrupt", durationMs: Date.now() - runStart });
|
|
497
515
|
return { state, signal: "$interrupt", cursor, paused: true };
|
|
498
516
|
}
|
|
499
517
|
state.$error = e instanceof Error ? e : new Error(String(e));
|
|
500
518
|
onError?.(state.$error, cursor);
|
|
519
|
+
obs?.onStepError?.(stepCtx, { error: state.$error, durationMs: Date.now() - stepStart });
|
|
501
520
|
}
|
|
502
521
|
}
|
|
503
522
|
if (runSucceeded) {
|
|
504
523
|
state.$error = null;
|
|
505
524
|
onAfterStep?.(cursor, state);
|
|
525
|
+
obs?.onStepEnd?.(stepCtx, { durationMs: Date.now() - stepStart });
|
|
506
526
|
}
|
|
507
527
|
const callRoute = step.route !== void 0 && (runSucceeded || step.run === void 0 || step.errorAware);
|
|
508
528
|
if (callRoute) {
|
|
@@ -512,6 +532,7 @@ async function runLoop(graph, state, ctx, schema, shouldStop, startCursor, callb
|
|
|
512
532
|
signal = routeFn(state);
|
|
513
533
|
} catch (e) {
|
|
514
534
|
state.$error = e instanceof Error ? e : new Error(String(e));
|
|
535
|
+
obs?.onRunEnd?.(runCtx, { signal: "$error", durationMs: Date.now() - runStart });
|
|
515
536
|
return { state, signal: "$error", cursor, paused: true };
|
|
516
537
|
}
|
|
517
538
|
const transition = step.transitions.find((t) => t.signal === signal);
|
|
@@ -520,6 +541,7 @@ async function runLoop(graph, state, ctx, schema, shouldStop, startCursor, callb
|
|
|
520
541
|
}
|
|
521
542
|
if (transition.target.kind === "end") {
|
|
522
543
|
onComplete?.(state, signal);
|
|
544
|
+
obs?.onRunEnd?.(runCtx, { signal, durationMs: Date.now() - runStart });
|
|
523
545
|
return { state, signal, cursor: null, paused: false };
|
|
524
546
|
}
|
|
525
547
|
cursor = transition.target.name;
|
|
@@ -527,6 +549,7 @@ async function runLoop(graph, state, ctx, schema, shouldStop, startCursor, callb
|
|
|
527
549
|
if (graph.onError !== void 0) {
|
|
528
550
|
cursor = graph.onError;
|
|
529
551
|
} else {
|
|
552
|
+
obs?.onRunEnd?.(runCtx, { signal: "$error", durationMs: Date.now() - runStart });
|
|
530
553
|
return { state, signal: "$error", cursor, paused: true };
|
|
531
554
|
}
|
|
532
555
|
} else {
|
|
@@ -604,6 +627,7 @@ function buildResumedState(stored, initialStateArg, argKeys, schema) {
|
|
|
604
627
|
|
|
605
628
|
// src/agent/concurrency-errors.ts
|
|
606
629
|
var SessionInFlightError = class extends Error {
|
|
630
|
+
/** The session that was already in-flight. */
|
|
607
631
|
sessionId;
|
|
608
632
|
constructor(sessionId) {
|
|
609
633
|
super(`session "${sessionId}" is already in-flight`);
|
|
@@ -612,6 +636,7 @@ var SessionInFlightError = class extends Error {
|
|
|
612
636
|
}
|
|
613
637
|
};
|
|
614
638
|
var SessionPendingInterruptError = class extends Error {
|
|
639
|
+
/** The session that is awaiting an interrupt response. */
|
|
615
640
|
sessionId;
|
|
616
641
|
constructor(sessionId) {
|
|
617
642
|
super(`session "${sessionId}" is paused on an interrupt \u2014 use agent.resume() instead of agent.run()`);
|
|
@@ -627,6 +652,67 @@ var StoreLoadError = class extends Error {
|
|
|
627
652
|
this.cause = cause;
|
|
628
653
|
}
|
|
629
654
|
};
|
|
655
|
+
var SessionBusyError = class extends Error {
|
|
656
|
+
/** The session that is currently claimed by another instance. */
|
|
657
|
+
sessionId;
|
|
658
|
+
constructor(sessionId, retryAfter) {
|
|
659
|
+
super(`session "${sessionId}" is currently claimed by another instance`);
|
|
660
|
+
this.name = "SessionBusyError";
|
|
661
|
+
this.sessionId = sessionId;
|
|
662
|
+
if (retryAfter !== void 0) this.retryAfter = retryAfter;
|
|
663
|
+
}
|
|
664
|
+
};
|
|
665
|
+
var LeaseExpiredError = class extends Error {
|
|
666
|
+
/** The session whose lease expired. */
|
|
667
|
+
sessionId;
|
|
668
|
+
constructor(sessionId) {
|
|
669
|
+
super(`lease for session "${sessionId}" has expired \u2014 run stopped without saving`);
|
|
670
|
+
this.name = "LeaseExpiredError";
|
|
671
|
+
this.sessionId = sessionId;
|
|
672
|
+
}
|
|
673
|
+
};
|
|
674
|
+
|
|
675
|
+
// src/agent/ctx-keep-alive.ts
|
|
676
|
+
function createKeepAliveFn(leaseRef, store, originalTtlMs) {
|
|
677
|
+
function keepAlive(options) {
|
|
678
|
+
const isBackground = typeof options === "object" && options !== null && "every" in options;
|
|
679
|
+
const extendClaim = store?.extendClaim;
|
|
680
|
+
if (isBackground) {
|
|
681
|
+
if (leaseRef.current === null || typeof extendClaim !== "function") {
|
|
682
|
+
return noopStop;
|
|
683
|
+
}
|
|
684
|
+
let handle = setInterval(() => {
|
|
685
|
+
if (leaseRef.current === null) {
|
|
686
|
+
return;
|
|
687
|
+
}
|
|
688
|
+
void (async () => {
|
|
689
|
+
try {
|
|
690
|
+
const renewed = await extendClaim.call(store, leaseRef.current, { ttlMs: originalTtlMs });
|
|
691
|
+
leaseRef.current = renewed;
|
|
692
|
+
} catch {
|
|
693
|
+
}
|
|
694
|
+
})();
|
|
695
|
+
}, options.every);
|
|
696
|
+
return function stop() {
|
|
697
|
+
if (handle !== null) {
|
|
698
|
+
clearInterval(handle);
|
|
699
|
+
handle = null;
|
|
700
|
+
}
|
|
701
|
+
};
|
|
702
|
+
}
|
|
703
|
+
if (leaseRef.current === null || typeof extendClaim !== "function") {
|
|
704
|
+
return Promise.resolve();
|
|
705
|
+
}
|
|
706
|
+
const snapshot = leaseRef.current;
|
|
707
|
+
return (async () => {
|
|
708
|
+
const renewed = await extendClaim.call(store, snapshot, { ttlMs: originalTtlMs });
|
|
709
|
+
leaseRef.current = renewed;
|
|
710
|
+
})();
|
|
711
|
+
}
|
|
712
|
+
return keepAlive;
|
|
713
|
+
}
|
|
714
|
+
function noopStop() {
|
|
715
|
+
}
|
|
630
716
|
|
|
631
717
|
// src/agent/session-lifecycle.ts
|
|
632
718
|
function resolveSessionStore(storeEntries) {
|
|
@@ -646,21 +732,43 @@ function resolveSessionStore(storeEntries) {
|
|
|
646
732
|
}
|
|
647
733
|
return result;
|
|
648
734
|
}
|
|
649
|
-
async function querySessionPhase(store, sessionId) {
|
|
735
|
+
async function querySessionPhase(store, agentId, sessionId) {
|
|
650
736
|
if (store === void 0) {
|
|
651
737
|
return { phase: "fresh" };
|
|
652
738
|
}
|
|
653
|
-
const loaded = await store.load(sessionId);
|
|
739
|
+
const loaded = await store.load(agentId, sessionId);
|
|
654
740
|
return storedSessionToPhase(loaded);
|
|
655
741
|
}
|
|
656
|
-
async function runWithSession(store, sessionId, graph, initialStateArg, schema, ctx, options) {
|
|
742
|
+
async function runWithSession(store, agentId, sessionId, runId, graph, initialStateArg, schema, ctx, options) {
|
|
743
|
+
const leaseRef = options?.leaseRef ?? { current: null };
|
|
744
|
+
const keepAlive = createKeepAliveFn(leaseRef, store, options?.claimTtlMs ?? 3e4);
|
|
745
|
+
ctx["keepAlive"] = keepAlive;
|
|
746
|
+
let leaseExpired = false;
|
|
747
|
+
const composedShouldStop = () => {
|
|
748
|
+
if (options?.shouldStop?.() === true) return true;
|
|
749
|
+
if (leaseRef.current !== null && leaseRef.current.expiresAt <= Date.now()) {
|
|
750
|
+
leaseExpired = true;
|
|
751
|
+
return true;
|
|
752
|
+
}
|
|
753
|
+
return false;
|
|
754
|
+
};
|
|
657
755
|
if (store === void 0) {
|
|
658
756
|
const state2 = initializeState(null, initialStateArg, schema);
|
|
659
|
-
|
|
757
|
+
const result2 = await runLoop(graph, state2, ctx, schema, composedShouldStop, void 0, {
|
|
758
|
+
...options,
|
|
759
|
+
runId,
|
|
760
|
+
...options?.parentRunId !== void 0 ? { parentRunId: options.parentRunId } : {}
|
|
761
|
+
});
|
|
762
|
+
if (leaseExpired) {
|
|
763
|
+
const expiredError = new LeaseExpiredError(sessionId);
|
|
764
|
+
options?.onStoreError?.(expiredError, "claim");
|
|
765
|
+
throw expiredError;
|
|
766
|
+
}
|
|
767
|
+
return result2;
|
|
660
768
|
}
|
|
661
769
|
let loaded;
|
|
662
770
|
try {
|
|
663
|
-
loaded = await store.load(sessionId);
|
|
771
|
+
loaded = await store.load(agentId, sessionId);
|
|
664
772
|
} catch (error) {
|
|
665
773
|
const storeError = new StoreLoadError(error);
|
|
666
774
|
options?.onStoreError?.(storeError, "load");
|
|
@@ -668,38 +776,62 @@ async function runWithSession(store, sessionId, graph, initialStateArg, schema,
|
|
|
668
776
|
failState["$error"] = storeError;
|
|
669
777
|
return { state: failState, signal: "$error", paused: false, cursor: null };
|
|
670
778
|
}
|
|
671
|
-
|
|
779
|
+
if (loaded !== null && loaded.phase === "completed") {
|
|
780
|
+
return {
|
|
781
|
+
state: loaded.finalState,
|
|
782
|
+
signal: loaded.signal ?? null,
|
|
783
|
+
cursor: null,
|
|
784
|
+
paused: false
|
|
785
|
+
};
|
|
786
|
+
}
|
|
672
787
|
const state = initializeState(loaded, initialStateArg, schema);
|
|
673
788
|
const initialStateSnapshot = { ...state };
|
|
674
789
|
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
675
|
-
const result = await runLoop(graph, state, ctx, schema,
|
|
790
|
+
const result = await runLoop(graph, state, ctx, schema, composedShouldStop, loaded?.step, {
|
|
791
|
+
...options,
|
|
792
|
+
runId,
|
|
793
|
+
...options?.parentRunId !== void 0 ? { parentRunId: options.parentRunId } : {}
|
|
794
|
+
});
|
|
795
|
+
if (leaseExpired) {
|
|
796
|
+
const expiredError = new LeaseExpiredError(sessionId);
|
|
797
|
+
options?.onStoreError?.(expiredError, "claim");
|
|
798
|
+
throw expiredError;
|
|
799
|
+
}
|
|
676
800
|
const settledAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
801
|
+
const metadata = options?.instanceId !== void 0 ? { instanceId: options.instanceId } : void 0;
|
|
677
802
|
try {
|
|
803
|
+
const version = (loaded?.version ?? -1) + 1;
|
|
678
804
|
if (result.paused) {
|
|
679
805
|
const saved = {
|
|
806
|
+
agentId,
|
|
680
807
|
runId,
|
|
681
808
|
sessionId,
|
|
809
|
+
version,
|
|
682
810
|
startedAt,
|
|
683
811
|
settledAt,
|
|
684
812
|
phase: "paused",
|
|
685
813
|
initialState: initialStateSnapshot,
|
|
686
814
|
finalState: result.state,
|
|
687
815
|
step: result.cursor,
|
|
688
|
-
...result.signal !== null ? { signal: result.signal } : {}
|
|
816
|
+
...result.signal !== null ? { signal: result.signal } : {},
|
|
817
|
+
...metadata !== void 0 ? { metadata } : {}
|
|
689
818
|
};
|
|
690
|
-
await store.save(sessionId, saved);
|
|
819
|
+
await store.save(agentId, sessionId, saved);
|
|
691
820
|
} else {
|
|
692
821
|
const saved = {
|
|
822
|
+
agentId,
|
|
693
823
|
runId,
|
|
694
824
|
sessionId,
|
|
825
|
+
version,
|
|
695
826
|
startedAt,
|
|
696
827
|
settledAt,
|
|
697
828
|
phase: "completed",
|
|
698
829
|
initialState: initialStateSnapshot,
|
|
699
830
|
finalState: result.state,
|
|
700
|
-
...result.signal !== null ? { signal: result.signal } : {}
|
|
831
|
+
...result.signal !== null ? { signal: result.signal } : {},
|
|
832
|
+
...metadata !== void 0 ? { metadata } : {}
|
|
701
833
|
};
|
|
702
|
-
await store.save(sessionId, saved);
|
|
834
|
+
await store.save(agentId, sessionId, saved);
|
|
703
835
|
}
|
|
704
836
|
} catch (error) {
|
|
705
837
|
options?.onStoreError?.(error, "persist");
|
|
@@ -716,8 +848,8 @@ var NoInterruptError = class extends Error {
|
|
|
716
848
|
this.name = "NoInterruptError";
|
|
717
849
|
}
|
|
718
850
|
};
|
|
719
|
-
async function injectInterruptResponse(store, sessionId, interruptId, response) {
|
|
720
|
-
const loaded = await store.load(sessionId);
|
|
851
|
+
async function injectInterruptResponse(store, agentId, sessionId, interruptId, response) {
|
|
852
|
+
const loaded = await store.load(agentId, sessionId);
|
|
721
853
|
if (loaded === null) throw new NoInterruptError();
|
|
722
854
|
if (loaded.phase !== "paused") throw new NoInterruptError();
|
|
723
855
|
const interrupt = loaded.finalState.$interrupt;
|
|
@@ -730,8 +862,10 @@ async function injectInterruptResponse(store, sessionId, interruptId, response)
|
|
|
730
862
|
$interruptResponses: { ...existingResponses, [interruptId]: response }
|
|
731
863
|
};
|
|
732
864
|
const updated = {
|
|
865
|
+
agentId: loaded.agentId,
|
|
733
866
|
runId: loaded.runId,
|
|
734
867
|
sessionId: loaded.sessionId,
|
|
868
|
+
version: loaded.version + 1,
|
|
735
869
|
startedAt: loaded.startedAt,
|
|
736
870
|
settledAt: loaded.settledAt,
|
|
737
871
|
phase: "paused",
|
|
@@ -740,11 +874,11 @@ async function injectInterruptResponse(store, sessionId, interruptId, response)
|
|
|
740
874
|
...loaded.step !== void 0 ? { step: loaded.step } : {},
|
|
741
875
|
...loaded.signal !== void 0 ? { signal: loaded.signal } : {}
|
|
742
876
|
};
|
|
743
|
-
await store.save(sessionId, updated);
|
|
877
|
+
await store.save(agentId, sessionId, updated);
|
|
744
878
|
}
|
|
745
879
|
|
|
746
880
|
// src/agent/run-handle.ts
|
|
747
|
-
function createRunHandle(sessionId, execution, stopFlag, stepRef, resumeFn) {
|
|
881
|
+
function createRunHandle(sessionId, runId, execution, stopFlag, stepRef, resumeFn) {
|
|
748
882
|
let settledOutcome = null;
|
|
749
883
|
const settled = execution.then(
|
|
750
884
|
(outcome) => {
|
|
@@ -782,6 +916,9 @@ function createRunHandle(sessionId, execution, stopFlag, stepRef, resumeFn) {
|
|
|
782
916
|
get sessionId() {
|
|
783
917
|
return sessionId;
|
|
784
918
|
},
|
|
919
|
+
get runId() {
|
|
920
|
+
return runId;
|
|
921
|
+
},
|
|
785
922
|
get currentStep() {
|
|
786
923
|
return stepRef.current;
|
|
787
924
|
}
|
|
@@ -790,7 +927,7 @@ function createRunHandle(sessionId, execution, stopFlag, stepRef, resumeFn) {
|
|
|
790
927
|
}
|
|
791
928
|
|
|
792
929
|
// src/agent/create-agent.ts
|
|
793
|
-
import { randomUUID
|
|
930
|
+
import { randomUUID } from "crypto";
|
|
794
931
|
|
|
795
932
|
// src/agent/event-callbacks.ts
|
|
796
933
|
function extractRunEvents(resources) {
|
|
@@ -802,13 +939,20 @@ function extractRunEvents(resources) {
|
|
|
802
939
|
}
|
|
803
940
|
|
|
804
941
|
// src/agent/create-agent.ts
|
|
942
|
+
var NOOP_OBSERVER = {};
|
|
943
|
+
function extractRunObserver(resources) {
|
|
944
|
+
const raw = resources["observer"];
|
|
945
|
+
if (raw === null || typeof raw !== "object" || Array.isArray(raw)) return void 0;
|
|
946
|
+
return raw;
|
|
947
|
+
}
|
|
805
948
|
var MissingLoopError = class extends Error {
|
|
806
949
|
constructor() {
|
|
807
|
-
super("harness has no loop \u2014 call h.loop() before createAgent()");
|
|
950
|
+
super("harness has no loop \u2014 call h.loop() before createAgent(id, h, slots)");
|
|
808
951
|
this.name = "MissingLoopError";
|
|
809
952
|
}
|
|
810
953
|
};
|
|
811
954
|
var MissingSlotError = class extends Error {
|
|
955
|
+
/** The missing slot key. */
|
|
812
956
|
key;
|
|
813
957
|
constructor(key) {
|
|
814
958
|
super(`required slot "${key}" was not provided in createAgent slots`);
|
|
@@ -817,6 +961,7 @@ var MissingSlotError = class extends Error {
|
|
|
817
961
|
}
|
|
818
962
|
};
|
|
819
963
|
var RuntimeSlotInAgentError = class extends Error {
|
|
964
|
+
/** The offending slot key. */
|
|
820
965
|
key;
|
|
821
966
|
constructor(key) {
|
|
822
967
|
super(`slot "${key}" is a runtime() slot \u2014 provide it in agent.run(), not createAgent()`);
|
|
@@ -825,6 +970,7 @@ var RuntimeSlotInAgentError = class extends Error {
|
|
|
825
970
|
}
|
|
826
971
|
};
|
|
827
972
|
var UnknownSlotError = class extends Error {
|
|
973
|
+
/** The unknown slot key. */
|
|
828
974
|
key;
|
|
829
975
|
constructor(key) {
|
|
830
976
|
super(`slot "${key}" is not declared in the harness \u2014 remove it or add h.provide("${key}", required())`);
|
|
@@ -833,6 +979,7 @@ var UnknownSlotError = class extends Error {
|
|
|
833
979
|
}
|
|
834
980
|
};
|
|
835
981
|
var MissingRuntimeSlotError = class extends Error {
|
|
982
|
+
/** The missing runtime slot key. */
|
|
836
983
|
key;
|
|
837
984
|
constructor(key) {
|
|
838
985
|
super(`runtime slot "${key}" was not provided in agent.run() resources`);
|
|
@@ -841,6 +988,7 @@ var MissingRuntimeSlotError = class extends Error {
|
|
|
841
988
|
}
|
|
842
989
|
};
|
|
843
990
|
var RequiredSlotInRunError = class extends Error {
|
|
991
|
+
/** The offending slot key. */
|
|
844
992
|
key;
|
|
845
993
|
constructor(key) {
|
|
846
994
|
super(`slot "${key}" is a required() slot \u2014 provide it in createAgent(), not agent.run()`);
|
|
@@ -849,6 +997,7 @@ var RequiredSlotInRunError = class extends Error {
|
|
|
849
997
|
}
|
|
850
998
|
};
|
|
851
999
|
var UnknownRunSlotError = class extends Error {
|
|
1000
|
+
/** The unknown resource key. */
|
|
852
1001
|
key;
|
|
853
1002
|
constructor(key) {
|
|
854
1003
|
super(`slot "${key}" is not a runtime() slot \u2014 do not pass it in agent.run() resources`);
|
|
@@ -857,7 +1006,7 @@ var UnknownRunSlotError = class extends Error {
|
|
|
857
1006
|
}
|
|
858
1007
|
};
|
|
859
1008
|
var _agentInternals = /* @__PURE__ */ Symbol("_agentInternals");
|
|
860
|
-
function createAgent(h, slots) {
|
|
1009
|
+
function createAgent(id, h, slots, agentOptions) {
|
|
861
1010
|
const internals = getInternals(h);
|
|
862
1011
|
if (internals.loopDef === void 0) {
|
|
863
1012
|
throw new MissingLoopError();
|
|
@@ -906,6 +1055,7 @@ function createAgent(h, slots) {
|
|
|
906
1055
|
}
|
|
907
1056
|
const capturedStore = resolveSessionStore(storeEntries);
|
|
908
1057
|
const agentInternals = {
|
|
1058
|
+
agentId: id,
|
|
909
1059
|
resolvedProviders,
|
|
910
1060
|
storeEntries,
|
|
911
1061
|
loopDef: internals.loopDef,
|
|
@@ -914,38 +1064,93 @@ function createAgent(h, slots) {
|
|
|
914
1064
|
runtimeKeys,
|
|
915
1065
|
requiredKeys
|
|
916
1066
|
};
|
|
917
|
-
const reservedRunKeys = /* @__PURE__ */ new Set(["sessionId", "signal", "events", "listeners"]);
|
|
1067
|
+
const reservedRunKeys = /* @__PURE__ */ new Set(["sessionId", "signal", "events", "listeners", "observer", "claimOptions", "parentRunId"]);
|
|
918
1068
|
const inFlightSessions = /* @__PURE__ */ new Set();
|
|
919
1069
|
const interruptPendingSessions = /* @__PURE__ */ new Set();
|
|
920
|
-
const makeAgentResumeHandle = (resp, sId, iId) => {
|
|
921
|
-
|
|
1070
|
+
const makeAgentResumeHandle = (resp, sId, iId, resumeOpts) => {
|
|
1071
|
+
let _stopped = false;
|
|
1072
|
+
const abortController = new AbortController();
|
|
1073
|
+
const flag = {
|
|
1074
|
+
get stopped() {
|
|
1075
|
+
return _stopped;
|
|
1076
|
+
},
|
|
1077
|
+
set stopped(v) {
|
|
1078
|
+
_stopped = v;
|
|
1079
|
+
if (v) abortController.abort();
|
|
1080
|
+
}
|
|
1081
|
+
};
|
|
922
1082
|
const ref = { current: null };
|
|
1083
|
+
const rId = randomUUID();
|
|
923
1084
|
const exec = (async () => {
|
|
924
1085
|
await Promise.resolve();
|
|
1086
|
+
const claimOptions = { ttlMs: 3e4 };
|
|
1087
|
+
let leaseRef = void 0;
|
|
925
1088
|
try {
|
|
926
|
-
if (capturedStore ===
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
1089
|
+
if (typeof capturedStore?.claim === "function") {
|
|
1090
|
+
let lease;
|
|
1091
|
+
try {
|
|
1092
|
+
lease = await capturedStore.claim(id, sId, claimOptions);
|
|
1093
|
+
} catch (claimError) {
|
|
1094
|
+
const loadError = new StoreLoadError(claimError);
|
|
1095
|
+
resumeOpts?.onStoreError?.(loadError, "claim");
|
|
1096
|
+
const failState = initializeState(null, {}, agentInternals.stateSchema);
|
|
1097
|
+
failState["$error"] = loadError;
|
|
1098
|
+
return { state: failState, signal: "$error" };
|
|
1099
|
+
}
|
|
1100
|
+
if (lease === null) {
|
|
1101
|
+
const busyError = new SessionBusyError(sId);
|
|
1102
|
+
resumeOpts?.onStoreError?.(busyError, "claim");
|
|
1103
|
+
const failState = initializeState(null, {}, agentInternals.stateSchema);
|
|
1104
|
+
failState["$error"] = busyError;
|
|
1105
|
+
return { state: failState, signal: "$error" };
|
|
1106
|
+
}
|
|
1107
|
+
leaseRef = { current: lease };
|
|
1108
|
+
}
|
|
1109
|
+
try {
|
|
1110
|
+
if (capturedStore === void 0) throw new NoInterruptError();
|
|
1111
|
+
await injectInterruptResponse(capturedStore, id, sId, iId, resp);
|
|
1112
|
+
const agentCtx = {
|
|
1113
|
+
...Object.fromEntries(agentInternals.resolvedProviders),
|
|
1114
|
+
agentId: id,
|
|
1115
|
+
sessionId: sId,
|
|
1116
|
+
runId: rId,
|
|
1117
|
+
signal: abortController.signal
|
|
1118
|
+
};
|
|
1119
|
+
const r = await runWithSession(
|
|
1120
|
+
capturedStore,
|
|
1121
|
+
id,
|
|
1122
|
+
sId,
|
|
1123
|
+
rId,
|
|
1124
|
+
agentInternals.loopDef,
|
|
1125
|
+
{},
|
|
1126
|
+
agentInternals.stateSchema,
|
|
1127
|
+
agentCtx,
|
|
1128
|
+
{
|
|
1129
|
+
shouldStop: () => flag.stopped,
|
|
1130
|
+
onBeforeStep: (n) => {
|
|
1131
|
+
ref.current = n;
|
|
1132
|
+
},
|
|
1133
|
+
...resumeOpts?.onStoreError !== void 0 ? { onStoreError: resumeOpts.onStoreError } : {},
|
|
1134
|
+
...leaseRef !== void 0 ? { leaseRef, claimTtlMs: claimOptions.ttlMs } : {}
|
|
943
1135
|
}
|
|
944
|
-
|
|
1136
|
+
);
|
|
1137
|
+
if (r.signal === "$interrupt") interruptPendingSessions.add(sId);
|
|
1138
|
+
return { state: r.state, signal: r.signal };
|
|
1139
|
+
} catch (error) {
|
|
1140
|
+
if (error instanceof LeaseExpiredError) {
|
|
1141
|
+
const failState = initializeState(null, {}, agentInternals.stateSchema);
|
|
1142
|
+
failState["$error"] = error;
|
|
1143
|
+
return { state: failState, signal: "$error" };
|
|
945
1144
|
}
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
1145
|
+
throw error;
|
|
1146
|
+
} finally {
|
|
1147
|
+
if (leaseRef !== void 0 && typeof capturedStore?.release === "function") {
|
|
1148
|
+
try {
|
|
1149
|
+
await capturedStore.release(leaseRef.current);
|
|
1150
|
+
} catch {
|
|
1151
|
+
}
|
|
1152
|
+
}
|
|
1153
|
+
}
|
|
949
1154
|
} finally {
|
|
950
1155
|
inFlightSessions.delete(sId);
|
|
951
1156
|
}
|
|
@@ -956,9 +1161,10 @@ function createAgent(h, slots) {
|
|
|
956
1161
|
inFlightSessions.add(sId);
|
|
957
1162
|
return makeAgentResumeHandle(r, sId, i);
|
|
958
1163
|
};
|
|
959
|
-
return createRunHandle(sId, exec, flag, ref, resumeFn);
|
|
1164
|
+
return createRunHandle(sId, rId, exec, flag, ref, resumeFn);
|
|
960
1165
|
};
|
|
961
1166
|
const agent = {
|
|
1167
|
+
id,
|
|
962
1168
|
run: (initialState, resources) => {
|
|
963
1169
|
for (const key of Object.keys(resources)) {
|
|
964
1170
|
if (reservedRunKeys.has(key)) continue;
|
|
@@ -977,15 +1183,29 @@ function createAgent(h, slots) {
|
|
|
977
1183
|
throw new MissingRuntimeSlotError(key);
|
|
978
1184
|
}
|
|
979
1185
|
}
|
|
980
|
-
const sessionId = typeof resources["sessionId"] === "string" ? resources["sessionId"] :
|
|
1186
|
+
const sessionId = typeof resources["sessionId"] === "string" ? resources["sessionId"] : randomUUID();
|
|
1187
|
+
const runId = randomUUID();
|
|
981
1188
|
if (inFlightSessions.has(sessionId)) throw new SessionInFlightError(sessionId);
|
|
982
1189
|
if (interruptPendingSessions.has(sessionId)) throw new SessionPendingInterruptError(sessionId);
|
|
983
1190
|
inFlightSessions.add(sessionId);
|
|
984
|
-
|
|
1191
|
+
let _stopped = false;
|
|
1192
|
+
const abortController = new AbortController();
|
|
1193
|
+
const stopFlag = {
|
|
1194
|
+
get stopped() {
|
|
1195
|
+
return _stopped;
|
|
1196
|
+
},
|
|
1197
|
+
set stopped(v) {
|
|
1198
|
+
_stopped = v;
|
|
1199
|
+
if (v) abortController.abort();
|
|
1200
|
+
}
|
|
1201
|
+
};
|
|
985
1202
|
const rawSignal = resources["signal"];
|
|
1203
|
+
let ctxSignal = abortController.signal;
|
|
986
1204
|
if (rawSignal instanceof AbortSignal) {
|
|
1205
|
+
ctxSignal = rawSignal;
|
|
987
1206
|
rawSignal.addEventListener("abort", () => {
|
|
988
1207
|
stopFlag.stopped = true;
|
|
1208
|
+
abortController.abort();
|
|
989
1209
|
}, { once: true });
|
|
990
1210
|
if (rawSignal.aborted) stopFlag.stopped = true;
|
|
991
1211
|
}
|
|
@@ -998,10 +1218,21 @@ function createAgent(h, slots) {
|
|
|
998
1218
|
const ctx = {
|
|
999
1219
|
...Object.fromEntries(agentInternals.resolvedProviders),
|
|
1000
1220
|
...runtimeSlots,
|
|
1001
|
-
|
|
1221
|
+
agentId: id,
|
|
1222
|
+
sessionId,
|
|
1223
|
+
runId,
|
|
1224
|
+
signal: ctxSignal,
|
|
1225
|
+
...agentOptions?.instanceId !== void 0 ? { instanceId: agentOptions.instanceId } : {}
|
|
1002
1226
|
};
|
|
1003
1227
|
const events = extractRunEvents(resources);
|
|
1004
1228
|
const listeners = extractRunListeners(resources);
|
|
1229
|
+
const observer = extractRunObserver(resources);
|
|
1230
|
+
for (const slot of [...agentInternals.resolvedProviders.values(), ...Object.values(runtimeSlots)]) {
|
|
1231
|
+
if (slot !== null && typeof slot === "object" && typeof slot["bindObserver"] === "function") {
|
|
1232
|
+
slot.bindObserver(observer ?? NOOP_OBSERVER);
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1235
|
+
const parentRunId = typeof resources["parentRunId"] === "string" ? resources["parentRunId"] : void 0;
|
|
1005
1236
|
const options = {
|
|
1006
1237
|
shouldStop: () => stopFlag.stopped,
|
|
1007
1238
|
onBeforeStep: (name, state) => {
|
|
@@ -1014,24 +1245,71 @@ function createAgent(h, slots) {
|
|
|
1014
1245
|
...events.onError !== void 0 ? { onError: events.onError } : {},
|
|
1015
1246
|
...events.onComplete !== void 0 ? { onComplete: events.onComplete } : {},
|
|
1016
1247
|
...events.onInterrupt !== void 0 ? { onInterrupt: events.onInterrupt } : {},
|
|
1017
|
-
...Object.keys(listeners).length > 0 ? { listeners } : {}
|
|
1248
|
+
...Object.keys(listeners).length > 0 ? { listeners } : {},
|
|
1249
|
+
...observer !== void 0 ? { observer } : {},
|
|
1250
|
+
...agentOptions?.instanceId !== void 0 ? { instanceId: agentOptions.instanceId } : {},
|
|
1251
|
+
...parentRunId !== void 0 ? { parentRunId } : {}
|
|
1018
1252
|
};
|
|
1019
1253
|
let lastResult = null;
|
|
1020
1254
|
const execution = (async () => {
|
|
1021
1255
|
await Promise.resolve();
|
|
1256
|
+
const rawClaimOpts = resources["claimOptions"];
|
|
1257
|
+
const claimOptions = typeof rawClaimOpts === "object" && rawClaimOpts !== null && typeof rawClaimOpts["ttlMs"] === "number" ? rawClaimOpts : { ttlMs: 3e4 };
|
|
1258
|
+
let leaseRef = void 0;
|
|
1022
1259
|
try {
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1260
|
+
if (typeof capturedStore?.claim === "function") {
|
|
1261
|
+
let lease;
|
|
1262
|
+
try {
|
|
1263
|
+
lease = await capturedStore.claim(id, sessionId, claimOptions);
|
|
1264
|
+
} catch (claimError) {
|
|
1265
|
+
const loadError = new StoreLoadError(claimError);
|
|
1266
|
+
events.onStoreError?.(loadError, "claim");
|
|
1267
|
+
const failState = initializeState(null, initialState, agentInternals.stateSchema);
|
|
1268
|
+
failState["$error"] = loadError;
|
|
1269
|
+
return { state: failState, signal: "$error" };
|
|
1270
|
+
}
|
|
1271
|
+
if (lease === null) {
|
|
1272
|
+
const busyError = new SessionBusyError(sessionId);
|
|
1273
|
+
events.onStoreError?.(busyError, "claim");
|
|
1274
|
+
const failState = initializeState(null, initialState, agentInternals.stateSchema);
|
|
1275
|
+
failState["$error"] = busyError;
|
|
1276
|
+
return { state: failState, signal: "$error" };
|
|
1277
|
+
}
|
|
1278
|
+
leaseRef = { current: lease };
|
|
1279
|
+
}
|
|
1280
|
+
try {
|
|
1281
|
+
const r = await runWithSession(
|
|
1282
|
+
capturedStore,
|
|
1283
|
+
id,
|
|
1284
|
+
sessionId,
|
|
1285
|
+
runId,
|
|
1286
|
+
agentInternals.loopDef,
|
|
1287
|
+
initialState,
|
|
1288
|
+
agentInternals.stateSchema,
|
|
1289
|
+
ctx,
|
|
1290
|
+
{
|
|
1291
|
+
...options,
|
|
1292
|
+
...leaseRef !== void 0 ? { leaseRef, claimTtlMs: claimOptions.ttlMs } : {}
|
|
1293
|
+
}
|
|
1294
|
+
);
|
|
1295
|
+
if (r.signal === "$interrupt") interruptPendingSessions.add(sessionId);
|
|
1296
|
+
lastResult = { state: r.state, cursor: r.cursor };
|
|
1297
|
+
return { state: r.state, signal: r.signal };
|
|
1298
|
+
} catch (error) {
|
|
1299
|
+
if (error instanceof LeaseExpiredError) {
|
|
1300
|
+
const failState = initializeState(null, initialState, agentInternals.stateSchema);
|
|
1301
|
+
failState["$error"] = error;
|
|
1302
|
+
return { state: failState, signal: "$error" };
|
|
1303
|
+
}
|
|
1304
|
+
throw error;
|
|
1305
|
+
} finally {
|
|
1306
|
+
if (leaseRef !== void 0 && typeof capturedStore?.release === "function") {
|
|
1307
|
+
try {
|
|
1308
|
+
await capturedStore.release(leaseRef.current);
|
|
1309
|
+
} catch {
|
|
1310
|
+
}
|
|
1311
|
+
}
|
|
1312
|
+
}
|
|
1035
1313
|
} finally {
|
|
1036
1314
|
inFlightSessions.delete(sessionId);
|
|
1037
1315
|
}
|
|
@@ -1041,20 +1319,38 @@ function createAgent(h, slots) {
|
|
|
1041
1319
|
if (inFlightSessions.has(sessionId)) throw new SessionInFlightError(sessionId);
|
|
1042
1320
|
interruptPendingSessions.delete(sessionId);
|
|
1043
1321
|
inFlightSessions.add(sessionId);
|
|
1044
|
-
|
|
1322
|
+
let _resumeStopped = false;
|
|
1323
|
+
const resumeAbortController = new AbortController();
|
|
1324
|
+
const resumeStopFlag = {
|
|
1325
|
+
get stopped() {
|
|
1326
|
+
return _resumeStopped;
|
|
1327
|
+
},
|
|
1328
|
+
set stopped(v) {
|
|
1329
|
+
_resumeStopped = v;
|
|
1330
|
+
if (v) resumeAbortController.abort();
|
|
1331
|
+
}
|
|
1332
|
+
};
|
|
1045
1333
|
const resumeStepRef = { current: null };
|
|
1334
|
+
const resumeRunId = randomUUID();
|
|
1046
1335
|
const resumeExecution = (async () => {
|
|
1047
1336
|
await Promise.resolve();
|
|
1048
1337
|
try {
|
|
1338
|
+
const resumeCtx = {
|
|
1339
|
+
...ctx,
|
|
1340
|
+
runId: resumeRunId,
|
|
1341
|
+
signal: resumeAbortController.signal
|
|
1342
|
+
};
|
|
1049
1343
|
if (capturedStore !== void 0) {
|
|
1050
|
-
await injectInterruptResponse(capturedStore, sessionId, interruptId, response);
|
|
1344
|
+
await injectInterruptResponse(capturedStore, id, sessionId, interruptId, response);
|
|
1051
1345
|
const r2 = await runWithSession(
|
|
1052
1346
|
capturedStore,
|
|
1347
|
+
id,
|
|
1053
1348
|
sessionId,
|
|
1349
|
+
resumeRunId,
|
|
1054
1350
|
agentInternals.loopDef,
|
|
1055
1351
|
{},
|
|
1056
1352
|
agentInternals.stateSchema,
|
|
1057
|
-
|
|
1353
|
+
resumeCtx,
|
|
1058
1354
|
{
|
|
1059
1355
|
shouldStop: () => resumeStopFlag.stopped,
|
|
1060
1356
|
onBeforeStep: (n, s) => {
|
|
@@ -1084,7 +1380,7 @@ function createAgent(h, slots) {
|
|
|
1084
1380
|
const r = await runLoop(
|
|
1085
1381
|
agentInternals.loopDef,
|
|
1086
1382
|
state,
|
|
1087
|
-
|
|
1383
|
+
resumeCtx,
|
|
1088
1384
|
agentInternals.stateSchema,
|
|
1089
1385
|
() => resumeStopFlag.stopped,
|
|
1090
1386
|
cursor,
|
|
@@ -1103,26 +1399,61 @@ function createAgent(h, slots) {
|
|
|
1103
1399
|
if (r.signal === "$interrupt") interruptPendingSessions.add(sessionId);
|
|
1104
1400
|
lastResult = { state: r.state, cursor: r.cursor };
|
|
1105
1401
|
return { state: r.state, signal: r.signal };
|
|
1402
|
+
} catch (error) {
|
|
1403
|
+
if (error instanceof LeaseExpiredError) {
|
|
1404
|
+
const failState = initializeState(null, initialState, agentInternals.stateSchema);
|
|
1405
|
+
failState["$error"] = error;
|
|
1406
|
+
return { state: failState, signal: "$error" };
|
|
1407
|
+
}
|
|
1408
|
+
throw error;
|
|
1106
1409
|
} finally {
|
|
1107
1410
|
inFlightSessions.delete(sessionId);
|
|
1108
1411
|
}
|
|
1109
1412
|
})();
|
|
1110
|
-
return createRunHandle(sessionId, resumeExecution, resumeStopFlag, resumeStepRef, buildResumeFn());
|
|
1413
|
+
return createRunHandle(sessionId, resumeRunId, resumeExecution, resumeStopFlag, resumeStepRef, buildResumeFn());
|
|
1111
1414
|
};
|
|
1112
1415
|
};
|
|
1113
|
-
return createRunHandle(sessionId, execution, stopFlag, stepRef, buildResumeFn());
|
|
1416
|
+
return createRunHandle(sessionId, runId, execution, stopFlag, stepRef, buildResumeFn());
|
|
1114
1417
|
},
|
|
1115
|
-
resume: (response, sessionId, interruptId) => {
|
|
1418
|
+
resume: (response, sessionId, interruptId, resumeOptions) => {
|
|
1116
1419
|
if (inFlightSessions.has(sessionId)) throw new SessionInFlightError(sessionId);
|
|
1117
1420
|
interruptPendingSessions.delete(sessionId);
|
|
1118
1421
|
inFlightSessions.add(sessionId);
|
|
1119
|
-
|
|
1422
|
+
const resumeOpts = resumeOptions?.events?.onStoreError !== void 0 ? { onStoreError: resumeOptions.events.onStoreError } : void 0;
|
|
1423
|
+
return makeAgentResumeHandle(response, sessionId, interruptId, resumeOpts);
|
|
1120
1424
|
},
|
|
1121
|
-
status: (sessionId) => querySessionPhase(capturedStore, sessionId),
|
|
1425
|
+
status: (sessionId) => querySessionPhase(capturedStore, id, sessionId),
|
|
1122
1426
|
[_agentInternals]: agentInternals
|
|
1123
1427
|
};
|
|
1124
1428
|
return agent;
|
|
1125
1429
|
}
|
|
1430
|
+
|
|
1431
|
+
// src/agent/observer.ts
|
|
1432
|
+
function composeObservers(...observers) {
|
|
1433
|
+
return {
|
|
1434
|
+
onRunStart: (ctx) => {
|
|
1435
|
+
for (const o of observers) o.onRunStart?.(ctx);
|
|
1436
|
+
},
|
|
1437
|
+
onRunEnd: (ctx, event) => {
|
|
1438
|
+
for (const o of observers) o.onRunEnd?.(ctx, event);
|
|
1439
|
+
},
|
|
1440
|
+
onStepStart: (ctx) => {
|
|
1441
|
+
for (const o of observers) o.onStepStart?.(ctx);
|
|
1442
|
+
},
|
|
1443
|
+
onStepEnd: (ctx, event) => {
|
|
1444
|
+
for (const o of observers) o.onStepEnd?.(ctx, event);
|
|
1445
|
+
},
|
|
1446
|
+
onStepError: (ctx, event) => {
|
|
1447
|
+
for (const o of observers) o.onStepError?.(ctx, event);
|
|
1448
|
+
},
|
|
1449
|
+
onInterrupt: (ctx, event) => {
|
|
1450
|
+
for (const o of observers) o.onInterrupt?.(ctx, event);
|
|
1451
|
+
},
|
|
1452
|
+
onEvent: (ctx, type, payload) => {
|
|
1453
|
+
for (const o of observers) o.onEvent?.(ctx, type, payload);
|
|
1454
|
+
}
|
|
1455
|
+
};
|
|
1456
|
+
}
|
|
1126
1457
|
export {
|
|
1127
1458
|
NoInterruptError,
|
|
1128
1459
|
REQUIRED_TAG,
|
|
@@ -1130,6 +1461,7 @@ export {
|
|
|
1130
1461
|
SessionInFlightError,
|
|
1131
1462
|
SessionPendingInterruptError,
|
|
1132
1463
|
StoreLoadError,
|
|
1464
|
+
composeObservers,
|
|
1133
1465
|
createAgent,
|
|
1134
1466
|
createHarness,
|
|
1135
1467
|
field,
|