eve 0.58.0 → 0.59.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/CHANGELOG.md +28 -0
- package/README.md +1 -0
- package/dist/src/channel/session.d.ts +2 -0
- package/dist/src/channel/session.js +1 -1
- package/dist/src/channel/types.d.ts +8 -1
- package/dist/src/chunks/{use-eve-agent-X0asmJg-.js → use-eve-agent-Dmc6sX4d.js} +558 -233
- package/dist/src/chunks/{use-eve-agent-CxWcZCsU.js → use-eve-agent-jSR8P4nK.js} +565 -235
- package/dist/src/cli/dev/tui/runner.d.ts +4 -0
- package/dist/src/cli/dev/tui/runner.js +1 -1
- package/dist/src/cli/dev/tui/setup-issues.js +1 -1
- package/dist/src/cli/dev/tui/terminal-renderer.js +12 -12
- package/dist/src/client/eve-agent-projection.d.ts +10 -0
- package/dist/src/client/eve-agent-projection.js +1 -0
- package/dist/src/client/eve-agent-store-helpers.d.ts +6 -2
- package/dist/src/client/eve-agent-store-helpers.js +2 -2
- package/dist/src/client/eve-agent-store-state.d.ts +54 -1
- package/dist/src/client/eve-agent-store.d.ts +12 -82
- package/dist/src/client/eve-agent-store.js +1 -1
- package/dist/src/client/index.d.ts +2 -2
- package/dist/src/client/index.js +1 -1
- package/dist/src/client/message-response.d.ts +5 -1
- package/dist/src/client/message-response.js +1 -1
- package/dist/src/client/ndjson.d.ts +1 -0
- package/dist/src/client/ndjson.js +2 -2
- package/dist/src/client/open-stream.d.ts +4 -1
- package/dist/src/client/open-stream.js +1 -1
- package/dist/src/client/session-event-stream.d.ts +30 -0
- package/dist/src/client/session-event-stream.js +1 -0
- package/dist/src/client/session-utils.d.ts +2 -1
- package/dist/src/client/session-utils.js +1 -1
- package/dist/src/client/session.d.ts +14 -1
- package/dist/src/client/session.js +1 -1
- package/dist/src/client/sessions.d.ts +8 -2
- package/dist/src/client/sessions.js +1 -1
- package/dist/src/client/types.d.ts +7 -0
- package/dist/src/compiled/.vendor-stamp.json +2 -3
- package/dist/src/compiled/@vercel/sandbox/api-client/api-client.d.ts +88 -1
- package/dist/src/compiled/@vercel/sandbox/api-client/index.d.ts +1 -1
- package/dist/src/compiled/@vercel/sandbox/api-client/validators.d.ts +41 -1
- package/dist/src/compiled/@vercel/sandbox/constants.d.ts +3 -3
- package/dist/src/compiled/@vercel/{sandbox-drives → sandbox}/drive.d.ts +13 -2
- package/dist/src/compiled/@vercel/sandbox/index.d.ts +3 -2
- package/dist/src/compiled/@vercel/sandbox/index.js +15 -9
- package/dist/src/compiled/@vercel/sandbox/sandbox.d.ts +40 -5
- package/dist/src/compiled/_chunks/node/auth-DDrvYko5.js +2 -0
- package/dist/src/compiled/_chunks/node/version-C__MqbLM.js +1 -0
- package/dist/src/compiler/extension-compatibility.d.ts +14 -14
- package/dist/src/compiler/extension-compatibility.js +1 -1
- package/dist/src/context/build-dynamic-tools.js +1 -1
- package/dist/src/context/dynamic-tool-lifecycle.js +1 -1
- package/dist/src/context/memory-tools.js +1 -1
- package/dist/src/evals/context.d.ts +1 -1
- package/dist/src/evals/context.js +1 -1
- package/dist/src/evals/define-eval.d.ts +1 -1
- package/dist/src/evals/define-eval.js +1 -1
- package/dist/src/evals/index.js +1 -1
- package/dist/src/evals/judge.d.ts +1 -1
- package/dist/src/evals/runner/execute-task.d.ts +1 -1
- package/dist/src/evals/runner/execute-task.js +1 -1
- package/dist/src/evals/session-manager.d.ts +27 -0
- package/dist/src/evals/session-manager.js +1 -0
- package/dist/src/evals/session.d.ts +8 -28
- package/dist/src/evals/session.js +2 -1
- package/dist/src/evals/target.d.ts +1 -1
- package/dist/src/evals/target.js +1 -1
- package/dist/src/evals/types.d.ts +19 -15
- package/dist/src/eve-channel/create-request.d.ts +24 -0
- package/dist/src/eve-channel/create-request.js +1 -0
- package/dist/src/eve-channel/index.js +1 -1
- package/dist/src/eve-channel/request.d.ts +3 -12
- package/dist/src/eve-channel/request.js +2 -2
- package/dist/src/eve-channel/types.d.ts +4 -2
- package/dist/src/execution/dynamic-workflow/tool.js +1 -1
- package/dist/src/execution/legacy-session/turn-workflow.js +1 -1
- package/dist/src/execution/runtime-context.js +1 -1
- package/dist/src/execution/sandbox/bindings/vercel-lifecycle.d.ts +3 -3
- package/dist/src/execution/sandbox/bindings/vercel-lifecycle.js +1 -1
- package/dist/src/execution/sandbox/bindings/vercel-sdk-types.d.ts +1 -4
- package/dist/src/execution/sandbox/bindings/vercel.d.ts +1 -2
- package/dist/src/execution/sandbox/bindings/vercel.js +1 -1
- package/dist/src/execution/session/entry.js +1 -1
- package/dist/src/execution/session/handoff-steps.js +1 -1
- package/dist/src/execution/session/program.d.ts +2 -0
- package/dist/src/execution/session/program.js +1 -1
- package/dist/src/execution/session/turn-step.js +1 -1
- package/dist/src/execution/session/turn.js +1 -1
- package/dist/src/execution/session-inbox/protocol.js +1 -1
- package/dist/src/execution/tools/connection-search.js +1 -1
- package/dist/src/execution/tools/sleep-workflow.js +1 -1
- package/dist/src/execution/workflow-runtime.js +1 -1
- package/dist/src/experimental/evaluate/auto-model.js +2 -2
- package/dist/src/experimental/evaluate/evaluate.d.ts +7 -0
- package/dist/src/experimental/evaluate/evaluate.js +1 -0
- package/dist/src/harness/compaction.d.ts +3 -3
- package/dist/src/harness/compaction.js +1 -1
- package/dist/src/harness/request-envelope.d.ts +11 -0
- package/dist/src/harness/request-envelope.js +1 -0
- package/dist/src/harness/tool-loop.js +2 -2
- package/dist/src/instrumentation/prepare-trace-context.d.ts +2 -1
- package/dist/src/instrumentation/prepare-trace-context.js +1 -1
- package/dist/src/internal/application/package.js +1 -1
- package/dist/src/internal/authored-module-loader.d.ts +4 -1
- package/dist/src/internal/authored-module-loader.js +1 -1
- package/dist/src/internal/bundler/nitro-rolldown.d.ts +2 -0
- package/dist/src/internal/model-auth/transport.d.ts +3 -1
- package/dist/src/internal/model-auth/transport.js +1 -1
- package/dist/src/internal/nitro/host/build-extension.js +1 -1
- package/dist/src/internal/nitro/host/extension-capability-requirements.d.ts +1 -0
- package/dist/src/internal/nitro/host/extension-capability-requirements.js +1 -1
- package/dist/src/internal/nitro/host/extension-distribution.d.ts +1 -1
- package/dist/src/internal/nitro/host/extension-distribution.js +1 -1
- package/dist/src/internal/workflow-bundle/dynamic-tool-transform.js +1 -1
- package/dist/src/public/experimental/evaluate/index.d.ts +1 -0
- package/dist/src/public/experimental/evaluate/index.js +1 -1
- package/dist/src/public/models/anthropic/index.js +1 -1
- package/dist/src/public/sandbox/vercel-sandbox.d.ts +1 -1
- package/dist/src/public/sandbox/vercel.d.ts +1 -1
- package/dist/src/public/sandbox/vercel.js +1 -1
- package/dist/src/public/tools/index.d.ts +1 -0
- package/dist/src/public/tools/index.js +1 -1
- package/dist/src/react/use-eve-agent.d.ts +4 -0
- package/dist/src/react/use-eve-agent.js +1 -1
- package/dist/src/runtime/agent/resolve-model.js +1 -1
- package/dist/src/setup/flows/model-login-connection.js +1 -1
- package/dist/src/setup/scaffold/create/project.js +1 -1
- package/dist/src/subagents/handle-dispatch.js +1 -1
- package/dist/src/svelte/index.js +1 -1
- package/dist/src/svelte/use-eve-agent.d.ts +4 -0
- package/dist/src/svelte/use-eve-agent.js +1 -1
- package/dist/src/tools/definition.d.ts +2 -0
- package/dist/src/tools/definition.js +1 -1
- package/dist/src/tools/durable-callbacks.d.ts +8 -2
- package/dist/src/tools/durable-callbacks.js +1 -1
- package/dist/src/tools/durable-schema.d.ts +16 -0
- package/dist/src/tools/durable-schema.js +1 -0
- package/dist/src/vue/index.js +1 -1
- package/dist/src/vue/use-eve-agent.d.ts +4 -0
- package/dist/src/vue/use-eve-agent.js +1 -1
- package/docs/README.md +1 -0
- package/docs/channels/eve.mdx +20 -10
- package/docs/concepts/context-control.md +4 -0
- package/docs/concepts/sessions-runs-and-streaming.md +18 -3
- package/docs/evals/assertions.mdx +6 -6
- package/docs/evals/cases.mdx +59 -23
- package/docs/evals/judge.mdx +10 -8
- package/docs/evals/overview.mdx +6 -6
- package/docs/evals/reporters.mdx +1 -1
- package/docs/evals/targets.mdx +5 -0
- package/docs/guides/client/messages.mdx +5 -5
- package/docs/guides/client/overview.mdx +15 -1
- package/docs/guides/dynamic-capabilities.md +22 -0
- package/docs/guides/evaluate.md +58 -4
- package/docs/guides/frontend/overview.mdx +54 -5
- package/docs/guides/frontend/use-eve-agent-svelte.mdx +13 -8
- package/docs/guides/frontend/use-eve-agent-vue.mdx +13 -8
- package/docs/reference/typescript-api.md +38 -36
- package/package.json +2 -3
- package/dist/src/compiled/@vercel/sandbox-drives/LICENSE +0 -201
- package/dist/src/compiled/@vercel/sandbox-drives/_async-retry.d.ts +0 -8
- package/dist/src/compiled/@vercel/sandbox-drives/_workflow-serde.d.ts +0 -5
- package/dist/src/compiled/@vercel/sandbox-drives/api-client/api-client.d.ts +0 -1815
- package/dist/src/compiled/@vercel/sandbox-drives/api-client/api-error.d.ts +0 -29
- package/dist/src/compiled/@vercel/sandbox-drives/api-client/base-client.d.ts +0 -39
- package/dist/src/compiled/@vercel/sandbox-drives/api-client/file-writer.d.ts +0 -66
- package/dist/src/compiled/@vercel/sandbox-drives/api-client/index.d.ts +0 -2
- package/dist/src/compiled/@vercel/sandbox-drives/api-client/validators.d.ts +0 -932
- package/dist/src/compiled/@vercel/sandbox-drives/api-client/with-retry.d.ts +0 -10
- package/dist/src/compiled/@vercel/sandbox-drives/auth/error.d.ts +0 -15
- package/dist/src/compiled/@vercel/sandbox-drives/auth/file.d.ts +0 -18
- package/dist/src/compiled/@vercel/sandbox-drives/auth/index.d.ts +0 -6
- package/dist/src/compiled/@vercel/sandbox-drives/auth/oauth.d.ts +0 -111
- package/dist/src/compiled/@vercel/sandbox-drives/auth/poll-for-token.d.ts +0 -28
- package/dist/src/compiled/@vercel/sandbox-drives/auth/project.d.ts +0 -40
- package/dist/src/compiled/@vercel/sandbox-drives/command.d.ts +0 -292
- package/dist/src/compiled/@vercel/sandbox-drives/constants.d.ts +0 -15
- package/dist/src/compiled/@vercel/sandbox-drives/execution-context.d.ts +0 -116
- package/dist/src/compiled/@vercel/sandbox-drives/filesystem.d.ts +0 -258
- package/dist/src/compiled/@vercel/sandbox-drives/index.d.ts +0 -14
- package/dist/src/compiled/@vercel/sandbox-drives/index.js +0 -9
- package/dist/src/compiled/@vercel/sandbox-drives/network-policy.d.ts +0 -169
- package/dist/src/compiled/@vercel/sandbox-drives/proxy.d.ts +0 -55
- package/dist/src/compiled/@vercel/sandbox-drives/sandbox-user.d.ts +0 -211
- package/dist/src/compiled/@vercel/sandbox-drives/sandbox.d.ts +0 -1287
- package/dist/src/compiled/@vercel/sandbox-drives/session.d.ts +0 -435
- package/dist/src/compiled/@vercel/sandbox-drives/snapshot.d.ts +0 -238
- package/dist/src/compiled/@vercel/sandbox-drives/utils/get-credentials.d.ts +0 -21
- package/dist/src/compiled/@vercel/sandbox-drives/utils/paginator.d.ts +0 -16
- package/dist/src/compiled/@vercel/sandbox-drives/utils/resolveSignal.d.ts +0 -15
- package/dist/src/compiled/@vercel/sandbox-drives/utils/sandbox-snapshot.d.ts +0 -11
- package/dist/src/compiled/@vercel/sandbox-drives/utils/types.d.ts +0 -11
- package/dist/src/compiled/_chunks/node/auth-8aQozzfi.js +0 -2
- package/dist/src/compiled/_chunks/node/auth-Bvv0xGTY.js +0 -2
- package/dist/src/compiled/_chunks/node/esm-Fqlolk7e.js +0 -7
- package/dist/src/compiled/_chunks/node/version-BC6t2Txc.js +0 -1
- package/dist/src/compiled/_chunks/node/version-DSQqVZ5T.js +0 -1
- package/dist/src/compiled/_chunks/node/xdg-app-paths-F-QHrdza.js +0 -1
|
@@ -686,17 +686,6 @@ function isTurnFailureEvent(event) {
|
|
|
686
686
|
return event.type === "session.failed" || event.type === "step.failed" || event.type === "turn.failed";
|
|
687
687
|
}
|
|
688
688
|
|
|
689
|
-
//#endregion
|
|
690
|
-
//#region src/client/output-schema.ts
|
|
691
|
-
function extractCompletedResult(events) {
|
|
692
|
-
let result;
|
|
693
|
-
for (const event of events) if (isResultCompletedEvent(event)) result = event.data.result;
|
|
694
|
-
return result;
|
|
695
|
-
}
|
|
696
|
-
function isResultCompletedEvent(event) {
|
|
697
|
-
return event.type === "result.completed";
|
|
698
|
-
}
|
|
699
|
-
|
|
700
689
|
//#endregion
|
|
701
690
|
//#region src/client/session-utils.ts
|
|
702
691
|
function summarizeTurnEvents(events) {
|
|
@@ -725,9 +714,25 @@ function summarizeTurnEvents(events) {
|
|
|
725
714
|
function isFinalMessageCompleted(event) {
|
|
726
715
|
return event.type === "message.completed" && event.data.finishReason !== "tool-calls";
|
|
727
716
|
}
|
|
717
|
+
function updatePendingAuthorizations(pending, event) {
|
|
718
|
+
if (event.type === "authorization.required" && event.data.webhookUrl !== void 0) pending.add(event.data.name);
|
|
719
|
+
else if (event.type === "authorization.completed") pending.delete(event.data.name);
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
//#endregion
|
|
723
|
+
//#region src/client/output-schema.ts
|
|
724
|
+
function extractCompletedResult(events) {
|
|
725
|
+
let result;
|
|
726
|
+
for (const event of events) if (isResultCompletedEvent(event)) result = event.data.result;
|
|
727
|
+
return result;
|
|
728
|
+
}
|
|
729
|
+
function isResultCompletedEvent(event) {
|
|
730
|
+
return event.type === "result.completed";
|
|
731
|
+
}
|
|
728
732
|
|
|
729
733
|
//#endregion
|
|
730
734
|
//#region src/client/message-response.ts
|
|
735
|
+
const consumeResponse = Symbol("consumeMessageResponse");
|
|
731
736
|
var MessageResponse = class {
|
|
732
737
|
sessionId;
|
|
733
738
|
#cancelTurn;
|
|
@@ -765,13 +770,16 @@ var MessageResponse = class {
|
|
|
765
770
|
};
|
|
766
771
|
}
|
|
767
772
|
[Symbol.asyncIterator]() {
|
|
773
|
+
return this[consumeResponse]();
|
|
774
|
+
}
|
|
775
|
+
[consumeResponse](source) {
|
|
768
776
|
if (this.#consumed) throw new Error("MessageResponse has already been consumed.");
|
|
769
777
|
this.#consumed = true;
|
|
770
|
-
return this.#observeStream();
|
|
778
|
+
return this.#observeStream(source);
|
|
771
779
|
}
|
|
772
|
-
async *#observeStream() {
|
|
780
|
+
async *#observeStream(source) {
|
|
773
781
|
try {
|
|
774
|
-
for await (const event of this.#createStream()) {
|
|
782
|
+
for await (const event of this.#createStream(source)) {
|
|
775
783
|
if (event.type === "turn.started") this.#turnId.resolve(event.data.turnId);
|
|
776
784
|
else if (isCurrentTurnBoundaryEvent(event)) {
|
|
777
785
|
this.#settled = true;
|
|
@@ -784,6 +792,9 @@ var MessageResponse = class {
|
|
|
784
792
|
}
|
|
785
793
|
}
|
|
786
794
|
};
|
|
795
|
+
function consumeMessageResponse(response, source) {
|
|
796
|
+
return response[consumeResponse](source);
|
|
797
|
+
}
|
|
787
798
|
|
|
788
799
|
//#endregion
|
|
789
800
|
//#region src/protocol/message-version.ts
|
|
@@ -893,9 +904,15 @@ async function* readNdjsonStream(body, options) {
|
|
|
893
904
|
const decoder = new TextDecoder();
|
|
894
905
|
let buffer = "";
|
|
895
906
|
let reachedEof = false;
|
|
907
|
+
const abort = () => {
|
|
908
|
+
reader.cancel().catch(() => {});
|
|
909
|
+
};
|
|
910
|
+
options.signal?.addEventListener("abort", abort, { once: true });
|
|
896
911
|
try {
|
|
897
912
|
while (true) {
|
|
913
|
+
options.signal?.throwIfAborted();
|
|
898
914
|
const result = await readWithIdleTimeout(reader, options?.idleTimeoutMs);
|
|
915
|
+
options.signal?.throwIfAborted();
|
|
899
916
|
if (result.done) {
|
|
900
917
|
reachedEof = true;
|
|
901
918
|
buffer += decoder.decode();
|
|
@@ -921,6 +938,7 @@ async function* readNdjsonStream(body, options) {
|
|
|
921
938
|
else yield parseMessageStreamEvent(value, options.streamVersion);
|
|
922
939
|
}
|
|
923
940
|
} finally {
|
|
941
|
+
options.signal?.removeEventListener("abort", abort);
|
|
924
942
|
if (!reachedEof) reader.cancel().catch(() => {});
|
|
925
943
|
reader.releaseLock();
|
|
926
944
|
}
|
|
@@ -1065,45 +1083,56 @@ function resolveRetryPolicy(policy, defaults) {
|
|
|
1065
1083
|
...policy
|
|
1066
1084
|
};
|
|
1067
1085
|
}
|
|
1068
|
-
function resolveStreamReconnectPolicy(policy) {
|
|
1086
|
+
function resolveStreamReconnectPolicy(policy, keepAlive = false) {
|
|
1069
1087
|
if (policy && "reconnect" in policy && policy.reconnect === false) return NO_STREAM_RECONNECT_POLICY;
|
|
1070
1088
|
const configured = policy;
|
|
1071
1089
|
return {
|
|
1072
1090
|
retryableErrorStatuses: configured?.retryableErrorStatuses ? new Set(configured.retryableErrorStatuses) : DEFAULT_STREAM_RECONNECT_POLICY.retryableErrorStatuses,
|
|
1073
|
-
streamIdleReconnectPolicy: resolveRetryPolicy(configured?.streamIdleReconnectPolicy,
|
|
1091
|
+
streamIdleReconnectPolicy: resolveRetryPolicy(configured?.streamIdleReconnectPolicy, {
|
|
1092
|
+
...DEFAULT_STREAM_RECONNECT_POLICY.streamIdleReconnectPolicy,
|
|
1093
|
+
maxAttempts: keepAlive ? Infinity : DEFAULT_STREAM_RECONNECT_POLICY.streamIdleReconnectPolicy.maxAttempts
|
|
1094
|
+
}),
|
|
1074
1095
|
streamOpenReconnectPolicy: resolveRetryPolicy(configured?.streamOpenReconnectPolicy, DEFAULT_STREAM_RECONNECT_POLICY.streamOpenReconnectPolicy)
|
|
1075
1096
|
};
|
|
1076
1097
|
}
|
|
1077
1098
|
async function* followStreamIterable(input) {
|
|
1078
1099
|
if (input.follow === false && input.startIndex < 0) throw new Error("stream({ follow: false }) requires a nonnegative startIndex; a tail-relative cursor cannot be bounded.");
|
|
1079
|
-
const
|
|
1080
|
-
|
|
1100
|
+
const resolvePolicy = () => resolveStreamReconnectPolicy(input.resolveReconnectPolicy === void 0 ? input.streamReconnectPolicy : input.resolveReconnectPolicy(), input.keepAlive);
|
|
1101
|
+
let retryPolicy = resolvePolicy();
|
|
1102
|
+
let idleRetryPolicy = retryPolicy.streamIdleReconnectPolicy;
|
|
1081
1103
|
let startIndex = input.startIndex;
|
|
1082
1104
|
let reconnectDelayMs = idleRetryPolicy.baseDelayMs;
|
|
1083
1105
|
let idleReconnects = 0;
|
|
1084
1106
|
let initialConnection = true;
|
|
1085
1107
|
let tailIndex;
|
|
1108
|
+
let caughtUp = false;
|
|
1086
1109
|
while (true) {
|
|
1110
|
+
retryPolicy = resolvePolicy();
|
|
1111
|
+
idleRetryPolicy = retryPolicy.streamIdleReconnectPolicy;
|
|
1087
1112
|
let connection;
|
|
1088
1113
|
try {
|
|
1089
1114
|
connection = await openStreamBody({
|
|
1090
1115
|
...input,
|
|
1091
1116
|
retryPolicy,
|
|
1092
1117
|
startIndex,
|
|
1093
|
-
requestTailIndex: input.follow === false && tailIndex === void 0
|
|
1118
|
+
requestTailIndex: (input.follow === false || input.onCaughtUp !== void 0) && tailIndex === void 0
|
|
1094
1119
|
});
|
|
1095
1120
|
} catch (error) {
|
|
1096
1121
|
if (input.signal?.aborted) return;
|
|
1097
1122
|
throw error;
|
|
1098
1123
|
}
|
|
1099
|
-
if (input.follow === false && tailIndex === void 0) {
|
|
1124
|
+
if ((input.follow === false || input.onCaughtUp !== void 0) && tailIndex === void 0) {
|
|
1100
1125
|
tailIndex = connection.tailIndex;
|
|
1101
1126
|
if (tailIndex === void 0) {
|
|
1102
1127
|
connection.close();
|
|
1103
1128
|
throw new Error(`stream({ follow: false }) requires the server to report the ${EVE_STREAM_TAIL_INDEX_HEADER} header. The agent may be running an older eve version.`);
|
|
1104
1129
|
}
|
|
1105
1130
|
}
|
|
1106
|
-
if (tailIndex !== void 0 && startIndex > tailIndex) {
|
|
1131
|
+
if (!caughtUp && tailIndex !== void 0 && startIndex > tailIndex) {
|
|
1132
|
+
caughtUp = true;
|
|
1133
|
+
input.onCaughtUp?.();
|
|
1134
|
+
}
|
|
1135
|
+
if (input.follow === false && tailIndex !== void 0 && startIndex > tailIndex) {
|
|
1107
1136
|
connection.close();
|
|
1108
1137
|
return;
|
|
1109
1138
|
}
|
|
@@ -1111,6 +1140,7 @@ async function* followStreamIterable(input) {
|
|
|
1111
1140
|
let leaseEnded = false;
|
|
1112
1141
|
try {
|
|
1113
1142
|
for await (const event of readNdjsonStream(connection.body, {
|
|
1143
|
+
signal: input.signal,
|
|
1114
1144
|
controlVersion: connection.controlVersion,
|
|
1115
1145
|
idleTimeoutMs: input.streamReadIdleTimeoutMs ?? DEFAULT_STREAM_READ_IDLE_TIMEOUT_MS,
|
|
1116
1146
|
onLeaseEnded: () => {
|
|
@@ -1123,16 +1153,21 @@ async function* followStreamIterable(input) {
|
|
|
1123
1153
|
reconnectDelayMs = idleRetryPolicy.baseDelayMs;
|
|
1124
1154
|
idleReconnects = 0;
|
|
1125
1155
|
yield event;
|
|
1126
|
-
if (tailIndex !== void 0 && startIndex > tailIndex)
|
|
1156
|
+
if (!caughtUp && tailIndex !== void 0 && startIndex > tailIndex) {
|
|
1157
|
+
caughtUp = true;
|
|
1158
|
+
input.onCaughtUp?.();
|
|
1159
|
+
}
|
|
1160
|
+
if (input.follow === false && tailIndex !== void 0 && startIndex > tailIndex) return;
|
|
1127
1161
|
}
|
|
1128
1162
|
} catch (error) {
|
|
1129
1163
|
if (!isStreamDisconnectError(error)) throw error;
|
|
1130
1164
|
} finally {
|
|
1131
1165
|
connection.close();
|
|
1132
1166
|
}
|
|
1167
|
+
idleRetryPolicy = resolvePolicy().streamIdleReconnectPolicy;
|
|
1133
1168
|
if (input.signal?.aborted || input.startIndex < 0 || idleRetryPolicy.maxAttempts === 0) return;
|
|
1134
1169
|
if (leaseEnded) continue;
|
|
1135
|
-
if (
|
|
1170
|
+
if (!deliveredEvent && !initialConnection && (idleReconnects += 1) >= idleRetryPolicy.maxAttempts) return;
|
|
1136
1171
|
initialConnection = false;
|
|
1137
1172
|
await sleep(reconnectDelayMs, input.signal);
|
|
1138
1173
|
if (input.signal?.aborted) return;
|
|
@@ -1140,7 +1175,7 @@ async function* followStreamIterable(input) {
|
|
|
1140
1175
|
}
|
|
1141
1176
|
}
|
|
1142
1177
|
async function openStreamBody(input) {
|
|
1143
|
-
const retryPolicy = input.retryPolicy ?? resolveStreamReconnectPolicy(input.streamReconnectPolicy);
|
|
1178
|
+
const retryPolicy = input.retryPolicy ?? resolveStreamReconnectPolicy(input.streamReconnectPolicy, input.keepAlive);
|
|
1144
1179
|
const openRetryPolicy = retryPolicy.streamOpenReconnectPolicy;
|
|
1145
1180
|
let lastStatus;
|
|
1146
1181
|
let lastBody;
|
|
@@ -1152,8 +1187,10 @@ async function openStreamBody(input) {
|
|
|
1152
1187
|
if (input.startIndex !== 0) searchParams.startIndex = String(input.startIndex);
|
|
1153
1188
|
if (input.requestTailIndex === true) searchParams.includeTailIndex = "1";
|
|
1154
1189
|
for (let attempt = 0; attempt < openRetryPolicy.maxAttempts; attempt += 1) {
|
|
1190
|
+
input.signal?.throwIfAborted();
|
|
1155
1191
|
const url = createClientUrl(input.host, createEveSessionStreamRoutePath(input.sessionId), Object.keys(searchParams).length > 0 ? searchParams : void 0);
|
|
1156
1192
|
const headers = await input.resolveHeaders();
|
|
1193
|
+
input.signal?.throwIfAborted();
|
|
1157
1194
|
const connectionController = new AbortController();
|
|
1158
1195
|
const signal = input.signal ? AbortSignal.any([input.signal, connectionController.signal]) : connectionController.signal;
|
|
1159
1196
|
let response;
|
|
@@ -1434,8 +1471,10 @@ function getStandardSchemaProperties(value) {
|
|
|
1434
1471
|
|
|
1435
1472
|
//#endregion
|
|
1436
1473
|
//#region src/client/session.ts
|
|
1437
|
-
const SESSION_SEND_RETRY_COUNT = 3;
|
|
1438
1474
|
const SESSION_SEND_RETRY_BASE_DELAY_MS = 250;
|
|
1475
|
+
const SESSION_SEND_RETRY_MAX_DELAY_MS = 2e3;
|
|
1476
|
+
const SESSION_SEND_READY_TIMEOUT_MS = 2e4;
|
|
1477
|
+
const followSession = Symbol("followClientSession");
|
|
1439
1478
|
var ClientSession = class ClientSession {
|
|
1440
1479
|
#context;
|
|
1441
1480
|
#state;
|
|
@@ -1455,6 +1494,13 @@ var ClientSession = class ClientSession {
|
|
|
1455
1494
|
session
|
|
1456
1495
|
};
|
|
1457
1496
|
}
|
|
1497
|
+
static async prewarm(context, options = {}) {
|
|
1498
|
+
const { sessionId } = await readAcceptedMessage(await postCreateSession(context, options));
|
|
1499
|
+
return new ClientSession(context, {
|
|
1500
|
+
sessionId,
|
|
1501
|
+
streamIndex: 0
|
|
1502
|
+
});
|
|
1503
|
+
}
|
|
1458
1504
|
get state() {
|
|
1459
1505
|
return this.#state;
|
|
1460
1506
|
}
|
|
@@ -1488,10 +1534,10 @@ var ClientSession = class ClientSession {
|
|
|
1488
1534
|
inputResponses
|
|
1489
1535
|
}, false);
|
|
1490
1536
|
}
|
|
1491
|
-
async #send(input,
|
|
1537
|
+
async #send(input, retrySessionNotReady) {
|
|
1492
1538
|
const initialStreamIndex = this.#state.streamIndex;
|
|
1493
1539
|
const path = createEveSessionRoutePath(this.#state.sessionId);
|
|
1494
|
-
const response =
|
|
1540
|
+
const response = retrySessionNotReady ? await postSessionSend(this.#context, path, input) : await postTurn(this.#context, path, input, false);
|
|
1495
1541
|
const { sessionId: responseSessionId, deliveryId } = await readAcceptedMessage(response, this.#state.sessionId);
|
|
1496
1542
|
if (responseSessionId !== this.#state.sessionId) throw new Error("Message route returned a different session id.");
|
|
1497
1543
|
if (input.message !== void 0 && deliveryId === void 0) throw new Error("Message route did not return a delivery id. Update the server before sending with this client.");
|
|
@@ -1527,23 +1573,29 @@ var ClientSession = class ClientSession {
|
|
|
1527
1573
|
if (options?.follow === false && (options.startIndex ?? this.#state.streamIndex) < 0) throw new Error("stream({ follow: false }) requires a nonnegative startIndex; a tail-relative cursor cannot be bounded.");
|
|
1528
1574
|
return this.#streamAndAdvance(options);
|
|
1529
1575
|
}
|
|
1576
|
+
[followSession](options) {
|
|
1577
|
+
return this.#streamAndAdvance({
|
|
1578
|
+
...options,
|
|
1579
|
+
keepAlive: true
|
|
1580
|
+
});
|
|
1581
|
+
}
|
|
1530
1582
|
#messageResponse(response, input, initialStreamIndex, deliveryId) {
|
|
1531
1583
|
response.body?.cancel().catch(() => {});
|
|
1532
1584
|
return new MessageResponse({
|
|
1533
1585
|
cancelTurn: async (turnId) => await this.cancel({ turnId }),
|
|
1534
|
-
createStream: () => this.#createEventStream(initialStreamIndex, input, deliveryId),
|
|
1586
|
+
createStream: (source) => this.#createEventStream(initialStreamIndex, input, deliveryId, source),
|
|
1535
1587
|
sessionId: this.#state.sessionId
|
|
1536
1588
|
});
|
|
1537
1589
|
}
|
|
1538
|
-
async *#createEventStream(initialStreamIndex, input, deliveryId) {
|
|
1590
|
+
async *#createEventStream(initialStreamIndex, input, deliveryId, source) {
|
|
1539
1591
|
let eventCount = 0;
|
|
1540
1592
|
let started = deliveryId === void 0;
|
|
1541
1593
|
let reachedBoundary = false;
|
|
1542
1594
|
const pendingAuthorizations = /* @__PURE__ */ new Set();
|
|
1543
1595
|
try {
|
|
1544
|
-
for await (const event of this.#readStream({
|
|
1596
|
+
for await (const event of source ?? this.#readStream({
|
|
1545
1597
|
headers: input.headers,
|
|
1546
|
-
keepAlive:
|
|
1598
|
+
keepAlive: true,
|
|
1547
1599
|
signal: input.signal,
|
|
1548
1600
|
startIndex: initialStreamIndex,
|
|
1549
1601
|
streamReconnectPolicy: input.streamReconnectPolicy
|
|
@@ -1557,73 +1609,92 @@ var ClientSession = class ClientSession {
|
|
|
1557
1609
|
if (!terminal && event.meta?.deliveryIds !== void 0 && !matches) continue;
|
|
1558
1610
|
started = true;
|
|
1559
1611
|
}
|
|
1560
|
-
|
|
1561
|
-
else if (event.type === "authorization.completed") pendingAuthorizations.delete(event.data.name);
|
|
1612
|
+
updatePendingAuthorizations(pendingAuthorizations, event);
|
|
1562
1613
|
reachedBoundary = isCurrentTurnBoundaryEvent(event) && (event.type !== "session.waiting" || pendingAuthorizations.size === 0);
|
|
1563
1614
|
yield event;
|
|
1564
1615
|
if (reachedBoundary) break;
|
|
1565
1616
|
}
|
|
1566
1617
|
if (deliveryId !== void 0 && !reachedBoundary && !input.signal?.aborted) throw new Error("The response stream ended before the accepted message reached its turn boundary.");
|
|
1567
1618
|
} finally {
|
|
1568
|
-
this.#
|
|
1569
|
-
sessionId: this.#state.sessionId,
|
|
1570
|
-
streamIndex: Math.max(this.#state.streamIndex, initialStreamIndex + eventCount)
|
|
1571
|
-
};
|
|
1619
|
+
this.#advanceStreamIndex(initialStreamIndex + eventCount);
|
|
1572
1620
|
}
|
|
1573
1621
|
}
|
|
1574
1622
|
async *#streamAndAdvance(options) {
|
|
1575
1623
|
const startIndex = options?.startIndex ?? this.#state.streamIndex;
|
|
1576
1624
|
let eventCount = 0;
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
}
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
};
|
|
1625
|
+
for await (const event of this.#readStream({
|
|
1626
|
+
follow: options?.follow,
|
|
1627
|
+
headers: options?.headers,
|
|
1628
|
+
keepAlive: options?.keepAlive,
|
|
1629
|
+
onCaughtUp: options?.onCaughtUp,
|
|
1630
|
+
resolveHeaders: options?.resolveHeaders,
|
|
1631
|
+
resolveReconnectPolicy: options?.resolveReconnectPolicy,
|
|
1632
|
+
signal: options?.signal,
|
|
1633
|
+
startIndex,
|
|
1634
|
+
streamReconnectPolicy: options?.streamReconnectPolicy
|
|
1635
|
+
})) {
|
|
1636
|
+
eventCount += 1;
|
|
1637
|
+
if (startIndex >= 0) this.#advanceStreamIndex(startIndex + eventCount);
|
|
1638
|
+
yield event;
|
|
1592
1639
|
}
|
|
1593
1640
|
}
|
|
1641
|
+
#advanceStreamIndex(streamIndex) {
|
|
1642
|
+
this.#state = {
|
|
1643
|
+
sessionId: this.#state.sessionId,
|
|
1644
|
+
streamIndex: Math.max(this.#state.streamIndex, streamIndex)
|
|
1645
|
+
};
|
|
1646
|
+
}
|
|
1594
1647
|
#readStream(input) {
|
|
1595
1648
|
return followStreamIterable({
|
|
1649
|
+
onCaughtUp: input.onCaughtUp,
|
|
1596
1650
|
follow: input.follow,
|
|
1597
1651
|
host: this.#context.host,
|
|
1598
1652
|
keepAlive: input.keepAlive,
|
|
1599
|
-
resolveHeaders: () => this.#context.resolveHeaders(input.headers),
|
|
1653
|
+
resolveHeaders: () => this.#context.resolveHeaders(input.resolveHeaders?.() ?? input.headers),
|
|
1600
1654
|
redirect: this.#context.redirect,
|
|
1601
1655
|
sessionId: this.#state.sessionId,
|
|
1602
1656
|
signal: input.signal,
|
|
1603
1657
|
startIndex: input.startIndex,
|
|
1604
|
-
streamReconnectPolicy: input.streamReconnectPolicy
|
|
1658
|
+
streamReconnectPolicy: input.streamReconnectPolicy,
|
|
1659
|
+
resolveReconnectPolicy: input.resolveReconnectPolicy
|
|
1605
1660
|
});
|
|
1606
1661
|
}
|
|
1607
1662
|
};
|
|
1663
|
+
function followClientSession(session, options) {
|
|
1664
|
+
return session[followSession](options);
|
|
1665
|
+
}
|
|
1608
1666
|
async function postSessionSend(context, path, input) {
|
|
1667
|
+
const readyDeadline = Date.now() + SESSION_SEND_READY_TIMEOUT_MS;
|
|
1609
1668
|
let retryDelayMs = SESSION_SEND_RETRY_BASE_DELAY_MS;
|
|
1610
|
-
for (
|
|
1669
|
+
for (;;) {
|
|
1611
1670
|
try {
|
|
1612
1671
|
return await postTurn(context, path, input, false);
|
|
1613
1672
|
} catch (error) {
|
|
1614
|
-
if (!
|
|
1673
|
+
if (!isSessionNotReady(error)) throw error;
|
|
1674
|
+
const remainingMs = readyDeadline - Date.now();
|
|
1675
|
+
if (remainingMs <= 0) throw error;
|
|
1676
|
+
await sleep(Math.min(retryDelayMs, remainingMs), input.signal);
|
|
1615
1677
|
}
|
|
1616
|
-
await sleep(retryDelayMs, input.signal);
|
|
1617
1678
|
input.signal?.throwIfAborted();
|
|
1618
|
-
retryDelayMs
|
|
1679
|
+
retryDelayMs = Math.min(retryDelayMs * 2, SESSION_SEND_RETRY_MAX_DELAY_MS);
|
|
1619
1680
|
}
|
|
1620
1681
|
}
|
|
1621
|
-
function
|
|
1622
|
-
|
|
1682
|
+
async function postCreateSession(context, options) {
|
|
1683
|
+
const headers = await context.resolveHeaders(options.headers);
|
|
1684
|
+
const response = await fetch(createClientUrl(context.host, EVE_SESSION_ROUTE_PATH), {
|
|
1685
|
+
headers,
|
|
1686
|
+
method: "POST",
|
|
1687
|
+
redirect: context.redirect,
|
|
1688
|
+
signal: options.signal ?? null
|
|
1689
|
+
});
|
|
1690
|
+
if (!response.ok) {
|
|
1691
|
+
const responseBody = await response.text();
|
|
1692
|
+
throw new ClientError(response.status, responseBody, response.headers);
|
|
1693
|
+
}
|
|
1694
|
+
return response;
|
|
1623
1695
|
}
|
|
1624
|
-
function
|
|
1625
|
-
|
|
1626
|
-
return policy?.streamIdleReconnectPolicy?.maxAttempts === void 0;
|
|
1696
|
+
function isSessionNotReady(error) {
|
|
1697
|
+
return error instanceof ClientError && error.status === 409 && error.code === "session_not_ready";
|
|
1627
1698
|
}
|
|
1628
1699
|
async function postTurn(context, path, input, requireMessage) {
|
|
1629
1700
|
const body = createMessageBody(input, requireMessage);
|
|
@@ -1672,8 +1743,9 @@ var ClientSessions = class {
|
|
|
1672
1743
|
constructor(context) {
|
|
1673
1744
|
this.#context = context;
|
|
1674
1745
|
}
|
|
1675
|
-
async create(input) {
|
|
1676
|
-
return await ClientSession.create(this.#context, input);
|
|
1746
|
+
async create(input = {}) {
|
|
1747
|
+
if ("message" in input) return await ClientSession.create(this.#context, input);
|
|
1748
|
+
return { session: await ClientSession.prewarm(this.#context, input) };
|
|
1677
1749
|
}
|
|
1678
1750
|
attach(sessionId, options) {
|
|
1679
1751
|
if (sessionId.length === 0) throw new Error("sessionId must be a non-empty string.");
|
|
@@ -1803,6 +1875,151 @@ function withRedirectPolicy(init, redirect) {
|
|
|
1803
1875
|
};
|
|
1804
1876
|
}
|
|
1805
1877
|
|
|
1878
|
+
//#endregion
|
|
1879
|
+
//#region src/client/session-event-stream.ts
|
|
1880
|
+
var SessionEventStream = class {
|
|
1881
|
+
#controller = new AbortController();
|
|
1882
|
+
#readers = /* @__PURE__ */ new Set();
|
|
1883
|
+
#caughtUp = Promise.withResolvers();
|
|
1884
|
+
caughtUp = this.#caughtUp.promise;
|
|
1885
|
+
#ended = false;
|
|
1886
|
+
#error;
|
|
1887
|
+
#headers;
|
|
1888
|
+
#reconnectPolicy;
|
|
1889
|
+
constructor(session, options) {
|
|
1890
|
+
this.setOptions(options);
|
|
1891
|
+
this.caughtUp.catch(() => {});
|
|
1892
|
+
if (!options.catchUp) this.#caughtUp.resolve();
|
|
1893
|
+
(async () => {
|
|
1894
|
+
try {
|
|
1895
|
+
for await (const event of followClientSession(session, {
|
|
1896
|
+
signal: this.#controller.signal,
|
|
1897
|
+
resolveHeaders: () => this.#headers,
|
|
1898
|
+
resolveReconnectPolicy: () => this.#reconnectPolicy,
|
|
1899
|
+
startIndex: options.startIndex,
|
|
1900
|
+
onCaughtUp: options.catchUp ? () => this.#caughtUp.resolve() : void 0
|
|
1901
|
+
})) {
|
|
1902
|
+
if (this.#controller.signal.aborted) return;
|
|
1903
|
+
options.onEvent(event);
|
|
1904
|
+
for (const reader of this.#readers) reader.push(event);
|
|
1905
|
+
if (event.type === "session.completed" || event.type === "session.failed") break;
|
|
1906
|
+
}
|
|
1907
|
+
this.#caughtUp.resolve();
|
|
1908
|
+
this.#finish();
|
|
1909
|
+
} catch (error) {
|
|
1910
|
+
this.#caughtUp.reject(error);
|
|
1911
|
+
this.#finish(error);
|
|
1912
|
+
if (!this.#controller.signal.aborted) options.onError(error);
|
|
1913
|
+
}
|
|
1914
|
+
})();
|
|
1915
|
+
}
|
|
1916
|
+
subscribe(signal) {
|
|
1917
|
+
const reader = new SessionEventReader(() => this.#readers.delete(reader), signal);
|
|
1918
|
+
if (this.#ended) reader.end(this.#error);
|
|
1919
|
+
else this.#readers.add(reader);
|
|
1920
|
+
return reader;
|
|
1921
|
+
}
|
|
1922
|
+
get ended() {
|
|
1923
|
+
return this.#ended;
|
|
1924
|
+
}
|
|
1925
|
+
setOptions(options) {
|
|
1926
|
+
if ("headers" in options) this.#headers = options.headers;
|
|
1927
|
+
if ("streamReconnectPolicy" in options) this.#reconnectPolicy = options.streamReconnectPolicy;
|
|
1928
|
+
}
|
|
1929
|
+
close() {
|
|
1930
|
+
const error = new DOMException("Session stream was detached.", "AbortError");
|
|
1931
|
+
this.#controller.abort(error);
|
|
1932
|
+
this.#caughtUp.reject(error);
|
|
1933
|
+
this.#finish(error);
|
|
1934
|
+
}
|
|
1935
|
+
#finish(error) {
|
|
1936
|
+
if (this.#ended) return;
|
|
1937
|
+
this.#ended = true;
|
|
1938
|
+
this.#error = error;
|
|
1939
|
+
for (const reader of this.#readers) reader.end(error);
|
|
1940
|
+
}
|
|
1941
|
+
};
|
|
1942
|
+
var SessionEventReader = class {
|
|
1943
|
+
#events = [];
|
|
1944
|
+
#wake = Promise.withResolvers();
|
|
1945
|
+
#ended = false;
|
|
1946
|
+
#error;
|
|
1947
|
+
#dispose;
|
|
1948
|
+
constructor(unsubscribe, signal) {
|
|
1949
|
+
const abort = () => this.end(signal?.reason);
|
|
1950
|
+
signal?.addEventListener("abort", abort, { once: true });
|
|
1951
|
+
this.#dispose = () => {
|
|
1952
|
+
signal?.removeEventListener("abort", abort);
|
|
1953
|
+
unsubscribe();
|
|
1954
|
+
};
|
|
1955
|
+
if (signal?.aborted) abort();
|
|
1956
|
+
}
|
|
1957
|
+
push(event) {
|
|
1958
|
+
if (this.#ended) return;
|
|
1959
|
+
this.#events.push(event);
|
|
1960
|
+
this.#wake.resolve();
|
|
1961
|
+
}
|
|
1962
|
+
end(error) {
|
|
1963
|
+
if (this.#ended) return;
|
|
1964
|
+
this.#ended = true;
|
|
1965
|
+
this.#error = error;
|
|
1966
|
+
this.#wake.resolve();
|
|
1967
|
+
}
|
|
1968
|
+
[Symbol.dispose]() {
|
|
1969
|
+
this.end();
|
|
1970
|
+
this.#events = [];
|
|
1971
|
+
this.#dispose();
|
|
1972
|
+
}
|
|
1973
|
+
discard() {
|
|
1974
|
+
this.#events = [];
|
|
1975
|
+
}
|
|
1976
|
+
async *[Symbol.asyncIterator]() {
|
|
1977
|
+
for (;;) {
|
|
1978
|
+
while (this.#events.length > 0) yield this.#events.shift();
|
|
1979
|
+
if (this.#ended) {
|
|
1980
|
+
if (this.#error !== void 0) throw this.#error;
|
|
1981
|
+
return;
|
|
1982
|
+
}
|
|
1983
|
+
this.#wake = Promise.withResolvers();
|
|
1984
|
+
await this.#wake.promise;
|
|
1985
|
+
}
|
|
1986
|
+
}
|
|
1987
|
+
};
|
|
1988
|
+
|
|
1989
|
+
//#endregion
|
|
1990
|
+
//#region src/client/eve-agent-projection.ts
|
|
1991
|
+
var EveAgentProjection = class {
|
|
1992
|
+
#reducer;
|
|
1993
|
+
#events;
|
|
1994
|
+
#data;
|
|
1995
|
+
constructor(reducer, events) {
|
|
1996
|
+
this.#reducer = reducer;
|
|
1997
|
+
this.#events = events;
|
|
1998
|
+
this.#data = this.#reduce();
|
|
1999
|
+
}
|
|
2000
|
+
get data() {
|
|
2001
|
+
return this.#data;
|
|
2002
|
+
}
|
|
2003
|
+
reset() {
|
|
2004
|
+
this.#events = [];
|
|
2005
|
+
this.#data = this.#reducer.initial();
|
|
2006
|
+
}
|
|
2007
|
+
append(event) {
|
|
2008
|
+
this.#events = [...this.#events, event];
|
|
2009
|
+
this.#data = this.#reducer.reduce(this.#data, event);
|
|
2010
|
+
}
|
|
2011
|
+
replace(predicate, replacement) {
|
|
2012
|
+
const index = this.#events.findIndex(predicate);
|
|
2013
|
+
this.#events = index === -1 ? [...this.#events, replacement] : this.#events.map((event, i) => i === index ? replacement : event);
|
|
2014
|
+
this.#data = this.#reduce();
|
|
2015
|
+
}
|
|
2016
|
+
#reduce() {
|
|
2017
|
+
let data = this.#reducer.initial();
|
|
2018
|
+
for (const event of this.#events) data = this.#reducer.reduce(data, event);
|
|
2019
|
+
return data;
|
|
2020
|
+
}
|
|
2021
|
+
};
|
|
2022
|
+
|
|
1806
2023
|
//#endregion
|
|
1807
2024
|
//#region src/protocol/event-dedupe.ts
|
|
1808
2025
|
function createEventDeduper() {
|
|
@@ -1832,10 +2049,6 @@ function collectPendingAuthorizations(events) {
|
|
|
1832
2049
|
for (const event of events) updatePendingAuthorizations(pending, event);
|
|
1833
2050
|
return pending;
|
|
1834
2051
|
}
|
|
1835
|
-
function updatePendingAuthorizations(pending, event) {
|
|
1836
|
-
if (event.type === "authorization.required" && event.data.webhookUrl !== void 0) pending.add(event.data.name);
|
|
1837
|
-
else if (event.type === "authorization.completed") pending.delete(event.data.name);
|
|
1838
|
-
}
|
|
1839
2052
|
function assertExclusiveTurnInput(input) {
|
|
1840
2053
|
if (input.message !== void 0 === (input.inputResponses !== void 0)) throw new Error("A turn requires exactly one of message or inputResponses.");
|
|
1841
2054
|
}
|
|
@@ -1865,29 +2078,78 @@ function toTerminalStreamFailureError(event) {
|
|
|
1865
2078
|
error.name = event.data.code;
|
|
1866
2079
|
return error;
|
|
1867
2080
|
}
|
|
2081
|
+
function createActiveTurn(cancel) {
|
|
2082
|
+
const response = Promise.withResolvers();
|
|
2083
|
+
const completion = Promise.withResolvers();
|
|
2084
|
+
const turn = {
|
|
2085
|
+
abortController: new AbortController(),
|
|
2086
|
+
acceptedFollowUps: 0,
|
|
2087
|
+
cancel: () => cancel(turn),
|
|
2088
|
+
completion: completion.promise,
|
|
2089
|
+
followUpDispatches: /* @__PURE__ */ new Set(),
|
|
2090
|
+
receivedFollowUps: 0,
|
|
2091
|
+
receivedFollowUpEvents: /* @__PURE__ */ new Set(),
|
|
2092
|
+
followUpSubmissionIds: /* @__PURE__ */ new Set(),
|
|
2093
|
+
resolveCompletion: completion.resolve,
|
|
2094
|
+
response: response.promise,
|
|
2095
|
+
resolveResponse: response.resolve
|
|
2096
|
+
};
|
|
2097
|
+
return turn;
|
|
2098
|
+
}
|
|
2099
|
+
async function followSteeredTurns(turn, events, isActive) {
|
|
2100
|
+
while (turn.followUpDispatches.size > 0) await Promise.allSettled(turn.followUpDispatches);
|
|
2101
|
+
if (turn.receivedFollowUps >= turn.acceptedFollowUps) return;
|
|
2102
|
+
for await (const event of events) {
|
|
2103
|
+
if (!isActive()) return;
|
|
2104
|
+
if (turn.receivedFollowUpEvents.delete(event)) turn.receivedFollowUps += 1;
|
|
2105
|
+
if (isCurrentTurnBoundaryEvent(event)) {
|
|
2106
|
+
while (turn.followUpDispatches.size > 0) await Promise.allSettled(turn.followUpDispatches);
|
|
2107
|
+
if (turn.receivedFollowUps >= turn.acceptedFollowUps) return;
|
|
2108
|
+
}
|
|
2109
|
+
}
|
|
2110
|
+
}
|
|
2111
|
+
async function waitWithSignal(promise, signal) {
|
|
2112
|
+
if (signal === void 0) return await promise;
|
|
2113
|
+
const aborted = Promise.withResolvers();
|
|
2114
|
+
const onAbort = () => aborted.reject(signal.reason);
|
|
2115
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
2116
|
+
if (signal.aborted) onAbort();
|
|
2117
|
+
try {
|
|
2118
|
+
return await Promise.race([aborted.promise, promise]);
|
|
2119
|
+
} finally {
|
|
2120
|
+
signal.removeEventListener("abort", onAbort);
|
|
2121
|
+
}
|
|
2122
|
+
}
|
|
1868
2123
|
|
|
1869
2124
|
//#endregion
|
|
1870
2125
|
//#region src/client/eve-agent-store.ts
|
|
1871
2126
|
const detachStore = Symbol("detachEveAgentStore");
|
|
2127
|
+
const attachStore = Symbol("attachEveAgentStore");
|
|
1872
2128
|
var EveAgentStore = class {
|
|
1873
2129
|
#client;
|
|
2130
|
+
#autoPrewarm;
|
|
2131
|
+
#attached = false;
|
|
2132
|
+
#stream;
|
|
2133
|
+
#pendingAuthorizations = /* @__PURE__ */ new Set();
|
|
1874
2134
|
#externalSession;
|
|
1875
2135
|
#optimistic;
|
|
1876
|
-
#
|
|
2136
|
+
#projection;
|
|
1877
2137
|
#subscribers = /* @__PURE__ */ new Set();
|
|
1878
2138
|
#seenEvents = createEventDeduper();
|
|
1879
2139
|
#activeTurn;
|
|
1880
2140
|
#callbacks = {};
|
|
1881
|
-
#data;
|
|
1882
2141
|
#error;
|
|
1883
2142
|
#events;
|
|
1884
2143
|
#pendingMessageSubmissions = [];
|
|
1885
|
-
#
|
|
2144
|
+
#prewarmGeneration = 0;
|
|
2145
|
+
#prewarmPromise;
|
|
2146
|
+
#prewarmController;
|
|
1886
2147
|
#resumePromise;
|
|
1887
2148
|
#session;
|
|
1888
2149
|
#snapshot;
|
|
1889
2150
|
#status = "ready";
|
|
1890
2151
|
constructor(init) {
|
|
2152
|
+
this.#autoPrewarm = init.prewarm ?? false;
|
|
1891
2153
|
this.#externalSession = init.session !== void 0;
|
|
1892
2154
|
this.#client = this.#externalSession ? void 0 : new Client({
|
|
1893
2155
|
auth: init.auth,
|
|
@@ -1895,13 +2157,14 @@ var EveAgentStore = class {
|
|
|
1895
2157
|
host: init.host ?? ""
|
|
1896
2158
|
});
|
|
1897
2159
|
const initialEvents = [];
|
|
1898
|
-
for (const event of init.initialEvents ?? [])
|
|
2160
|
+
for (const event of init.initialEvents ?? []) {
|
|
2161
|
+
if (this.#seenEvents.admit(event)) initialEvents.push(event);
|
|
2162
|
+
updatePendingAuthorizations(this.#pendingAuthorizations, event);
|
|
2163
|
+
}
|
|
1899
2164
|
this.#events = initialEvents;
|
|
1900
|
-
this.#
|
|
2165
|
+
this.#projection = new EveAgentProjection(init.reducer, this.#events);
|
|
1901
2166
|
this.#optimistic = init.optimistic ?? true;
|
|
1902
|
-
this.#reducer = init.reducer;
|
|
1903
2167
|
this.#session = init.session ?? (init.initialSession === void 0 ? void 0 : this.#client?.sessions.attach(init.initialSession.sessionId, { streamIndex: init.initialSession.streamIndex }));
|
|
1904
|
-
this.#data = this.#reduceProjectionEvents(this.#projectionEvents);
|
|
1905
2168
|
this.#snapshot = this.#createSnapshot();
|
|
1906
2169
|
}
|
|
1907
2170
|
get snapshot() {
|
|
@@ -1916,31 +2179,63 @@ var EveAgentStore = class {
|
|
|
1916
2179
|
this.#subscribers.delete(callback);
|
|
1917
2180
|
};
|
|
1918
2181
|
}
|
|
2182
|
+
prewarm() {
|
|
2183
|
+
if (this.#prewarmPromise !== void 0) return this.#prewarmPromise;
|
|
2184
|
+
if (this.#session !== void 0 || this.#externalSession) return Promise.resolve();
|
|
2185
|
+
if (this.#activeTurn !== void 0) return this.#activeTurn.response.then((response) => {
|
|
2186
|
+
if (response === void 0) throw this.#error ?? new DOMException("Session creation was aborted.", "AbortError");
|
|
2187
|
+
});
|
|
2188
|
+
const client = this.#client;
|
|
2189
|
+
if (client === void 0) return Promise.reject(/* @__PURE__ */ new Error("This eve agent store does not own a session client."));
|
|
2190
|
+
const generation = this.#prewarmGeneration;
|
|
2191
|
+
const controller = new AbortController();
|
|
2192
|
+
this.#prewarmController = controller;
|
|
2193
|
+
const promise = (async () => {
|
|
2194
|
+
try {
|
|
2195
|
+
const created = await client.sessions.create({ signal: controller.signal });
|
|
2196
|
+
if (generation !== this.#prewarmGeneration) return;
|
|
2197
|
+
this.#session = created.session;
|
|
2198
|
+
this.#error = void 0;
|
|
2199
|
+
if (this.#status === "error") this.#status = "ready";
|
|
2200
|
+
this.#callbacks.onSessionChange?.(created.session.state);
|
|
2201
|
+
this.#publish();
|
|
2202
|
+
this.#ensureStream();
|
|
2203
|
+
} catch (error) {
|
|
2204
|
+
if (generation === this.#prewarmGeneration && this.#activeTurn === void 0 && this.#error === void 0) {
|
|
2205
|
+
this.#error = toError(error);
|
|
2206
|
+
this.#status = "error";
|
|
2207
|
+
this.#callbacks.onError?.(this.#error);
|
|
2208
|
+
this.#publish();
|
|
2209
|
+
}
|
|
2210
|
+
throw error;
|
|
2211
|
+
}
|
|
2212
|
+
})();
|
|
2213
|
+
this.#prewarmPromise = promise;
|
|
2214
|
+
const clear = () => {
|
|
2215
|
+
if (this.#prewarmPromise === promise) {
|
|
2216
|
+
this.#prewarmPromise = void 0;
|
|
2217
|
+
this.#prewarmController = void 0;
|
|
2218
|
+
}
|
|
2219
|
+
};
|
|
2220
|
+
promise.then(clear, clear);
|
|
2221
|
+
return promise;
|
|
2222
|
+
}
|
|
1919
2223
|
async send(input) {
|
|
2224
|
+
return await this.#submit(input, this.#callbacks.prepareSend);
|
|
2225
|
+
}
|
|
2226
|
+
async #submit(input, prepareSend) {
|
|
1920
2227
|
if (this.#activeTurn !== void 0) {
|
|
1921
2228
|
if (this.#status === "resuming") throw new Error("eve session is resuming.");
|
|
1922
|
-
return await this.#sendFollowUp(this.#activeTurn, input);
|
|
2229
|
+
return await this.#sendFollowUp(this.#activeTurn, input, prepareSend);
|
|
1923
2230
|
}
|
|
1924
|
-
const
|
|
1925
|
-
const completion = Promise.withResolvers();
|
|
1926
|
-
const turn = {
|
|
1927
|
-
abortController: new AbortController(),
|
|
1928
|
-
acceptedFollowUps: 0,
|
|
1929
|
-
cancel: () => turn.acceptedFollowUps > 0 && this.#session !== void 0 ? this.#session.cancel() : response.promise.then((messageResponse) => messageResponse === void 0 ? { status: "no_active_turn" } : messageResponse.cancel()),
|
|
1930
|
-
completion: completion.promise,
|
|
1931
|
-
followUpDispatches: /* @__PURE__ */ new Set(),
|
|
1932
|
-
receivedFollowUps: 0,
|
|
1933
|
-
followUpSubmissionIds: /* @__PURE__ */ new Set(),
|
|
1934
|
-
resolveCompletion: completion.resolve,
|
|
1935
|
-
response: response.promise,
|
|
1936
|
-
resolveResponse: response.resolve
|
|
1937
|
-
};
|
|
2231
|
+
const turn = createActiveTurn((turn) => turn.acceptedFollowUps > 0 && this.#session !== void 0 ? this.#session.cancel() : turn.response.then((response) => response === void 0 ? { status: "no_active_turn" } : response.cancel()));
|
|
1938
2232
|
this.#activeTurn = turn;
|
|
1939
2233
|
this.#error = void 0;
|
|
1940
2234
|
this.#status = "submitted";
|
|
1941
2235
|
this.#publish();
|
|
2236
|
+
let reader;
|
|
1942
2237
|
try {
|
|
1943
|
-
const preparedInput = await
|
|
2238
|
+
const preparedInput = await (prepareSend === void 0 ? input : waitWithSignal(Promise.resolve(prepareSend(input)), createAbortSignal(input.signal, turn.abortController.signal)));
|
|
1944
2239
|
assertExclusiveTurnInput(preparedInput);
|
|
1945
2240
|
if (!this.#isActiveTurn(turn)) return;
|
|
1946
2241
|
this.#projectOptimisticMessage(preparedInput);
|
|
@@ -1950,15 +2245,17 @@ var EveAgentStore = class {
|
|
|
1950
2245
|
...preparedInput,
|
|
1951
2246
|
signal: createAbortSignal(preparedInput.signal, turn.abortController.signal)
|
|
1952
2247
|
};
|
|
1953
|
-
const
|
|
2248
|
+
const dispatched = await this.#dispatchTurn(turnInput);
|
|
2249
|
+
const response = dispatched.response;
|
|
2250
|
+
reader = dispatched.reader;
|
|
1954
2251
|
if (!this.#isActiveTurn(turn)) return;
|
|
1955
2252
|
turn.resolveResponse(response);
|
|
1956
|
-
for await (const event of response) {
|
|
2253
|
+
for await (const event of consumeMessageResponse(response, reader)) {
|
|
1957
2254
|
if (!this.#isActiveTurn(turn)) return;
|
|
1958
|
-
|
|
2255
|
+
if (turn.receivedFollowUpEvents.delete(event)) turn.receivedFollowUps += 1;
|
|
1959
2256
|
}
|
|
1960
2257
|
if (!this.#isActiveTurn(turn)) return;
|
|
1961
|
-
await this.#
|
|
2258
|
+
await followSteeredTurns(turn, reader, () => this.#isActiveTurn(turn));
|
|
1962
2259
|
if (!this.#isActiveTurn(turn)) return;
|
|
1963
2260
|
this.#status = this.#error === void 0 ? "ready" : "error";
|
|
1964
2261
|
} catch (error) {
|
|
@@ -1967,20 +2264,15 @@ var EveAgentStore = class {
|
|
|
1967
2264
|
this.#status = "ready";
|
|
1968
2265
|
this.#failPendingMessageSubmission(toError(error));
|
|
1969
2266
|
} else {
|
|
1970
|
-
this.#error
|
|
2267
|
+
const reported = this.#error !== void 0;
|
|
2268
|
+
this.#error ??= toError(error);
|
|
1971
2269
|
this.#status = "error";
|
|
1972
2270
|
this.#failPendingMessageSubmission(this.#error);
|
|
1973
|
-
this.#callbacks.onError?.(this.#error);
|
|
2271
|
+
if (!reported) this.#callbacks.onError?.(this.#error);
|
|
1974
2272
|
}
|
|
1975
2273
|
} finally {
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
this.#activeTurn = void 0;
|
|
1979
|
-
this.#callbacks.onSessionChange?.(this.#session?.state);
|
|
1980
|
-
this.#publish();
|
|
1981
|
-
this.#callbacks.onFinish?.(this.#snapshot);
|
|
1982
|
-
turn.resolveCompletion();
|
|
1983
|
-
}
|
|
2274
|
+
reader?.[Symbol.dispose]();
|
|
2275
|
+
this.#finishTurn(turn);
|
|
1984
2276
|
}
|
|
1985
2277
|
}
|
|
1986
2278
|
resume() {
|
|
@@ -1996,70 +2288,34 @@ var EveAgentStore = class {
|
|
|
1996
2288
|
async #resume() {
|
|
1997
2289
|
if (this.#status === "resuming" || this.#status === "streaming" || this.#status === "submitted") throw new Error("eve session is already processing a turn.");
|
|
1998
2290
|
if (this.#session === void 0) throw new Error("An eve session is required before resuming.");
|
|
1999
|
-
const response = Promise.withResolvers();
|
|
2000
|
-
const completion = Promise.withResolvers();
|
|
2001
2291
|
const session = this.#session;
|
|
2002
|
-
const turn =
|
|
2003
|
-
abortController: new AbortController(),
|
|
2004
|
-
acceptedFollowUps: 0,
|
|
2005
|
-
cancel: () => session.cancel(),
|
|
2006
|
-
completion: completion.promise,
|
|
2007
|
-
followUpDispatches: /* @__PURE__ */ new Set(),
|
|
2008
|
-
receivedFollowUps: 0,
|
|
2009
|
-
followUpSubmissionIds: /* @__PURE__ */ new Set(),
|
|
2010
|
-
resolveCompletion: completion.resolve,
|
|
2011
|
-
response: response.promise,
|
|
2012
|
-
resolveResponse: response.resolve
|
|
2013
|
-
};
|
|
2292
|
+
const turn = createActiveTurn(() => session.cancel());
|
|
2014
2293
|
this.#activeTurn = turn;
|
|
2015
2294
|
turn.resolveResponse(void 0);
|
|
2016
2295
|
this.#error = void 0;
|
|
2017
2296
|
this.#status = "resuming";
|
|
2018
2297
|
this.#publish();
|
|
2019
2298
|
try {
|
|
2020
|
-
const
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
})) {
|
|
2027
|
-
if (!this.#isActiveTurn(turn)) return;
|
|
2028
|
-
replayed.push(event);
|
|
2029
|
-
this.#acceptServerEvent(event, {
|
|
2030
|
-
publish: false,
|
|
2031
|
-
transitionToStreaming: false
|
|
2032
|
-
});
|
|
2033
|
-
}
|
|
2299
|
+
const stream = this.#ensureStream({
|
|
2300
|
+
catchUp: true,
|
|
2301
|
+
startIndex: this.#events.length === session.state.streamIndex ? session.state.streamIndex : 0
|
|
2302
|
+
});
|
|
2303
|
+
using reader = stream.subscribe(turn.abortController.signal);
|
|
2304
|
+
await stream.caughtUp;
|
|
2034
2305
|
if (!this.#isActiveTurn(turn)) return;
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
if (this.#error === void 0 && (
|
|
2039
|
-
|
|
2040
|
-
if (!replaySettled) this.#status = "streaming";
|
|
2306
|
+
reader.discard();
|
|
2307
|
+
const tail = this.#events.at(-1);
|
|
2308
|
+
if (tail !== void 0) this.#applyTerminalStreamFailure(tail);
|
|
2309
|
+
if (tail !== void 0 && this.#error === void 0 && !isSettledSessionTail(this.#events)) {
|
|
2310
|
+
this.#status = "streaming";
|
|
2041
2311
|
this.#publish();
|
|
2042
|
-
|
|
2043
|
-
for (;;) {
|
|
2044
|
-
for await (const event of session.stream({
|
|
2045
|
-
follow: followLive ? void 0 : false,
|
|
2046
|
-
signal: turn.abortController.signal
|
|
2047
|
-
})) {
|
|
2048
|
-
if (!this.#isActiveTurn(turn)) return;
|
|
2049
|
-
replayed.push(event);
|
|
2050
|
-
this.#acceptServerEvent(event);
|
|
2051
|
-
updatePendingAuthorizations(pendingAuthorizations, event);
|
|
2052
|
-
if (followLive && isCurrentTurnBoundaryEvent(event) && (event.type !== "session.waiting" || pendingAuthorizations.size === 0)) break;
|
|
2053
|
-
}
|
|
2312
|
+
for await (const event of reader) {
|
|
2054
2313
|
if (!this.#isActiveTurn(turn)) return;
|
|
2055
|
-
if (
|
|
2056
|
-
|
|
2314
|
+
if (turn.receivedFollowUpEvents.delete(event)) turn.receivedFollowUps += 1;
|
|
2315
|
+
if (isCurrentTurnBoundaryEvent(event) && this.#pendingAuthorizations.size === 0) break;
|
|
2057
2316
|
}
|
|
2058
|
-
} else {
|
|
2059
|
-
this.#status = this.#error === void 0 ? "ready" : "error";
|
|
2060
|
-
this.#publish();
|
|
2061
2317
|
}
|
|
2062
|
-
await this.#
|
|
2318
|
+
await followSteeredTurns(turn, reader, () => this.#isActiveTurn(turn));
|
|
2063
2319
|
if (this.#isActiveTurn(turn)) this.#status = this.#error === void 0 ? "ready" : "error";
|
|
2064
2320
|
} catch (error) {
|
|
2065
2321
|
if (!this.#isActiveTurn(turn)) return;
|
|
@@ -2070,61 +2326,81 @@ var EveAgentStore = class {
|
|
|
2070
2326
|
this.#callbacks.onError?.(this.#error);
|
|
2071
2327
|
}
|
|
2072
2328
|
} finally {
|
|
2073
|
-
|
|
2074
|
-
turn.resolveResponse(void 0);
|
|
2075
|
-
this.#activeTurn = void 0;
|
|
2076
|
-
this.#callbacks.onSessionChange?.(session.state);
|
|
2077
|
-
this.#publish();
|
|
2078
|
-
this.#callbacks.onFinish?.(this.#snapshot);
|
|
2079
|
-
turn.resolveCompletion();
|
|
2080
|
-
}
|
|
2329
|
+
this.#finishTurn(turn);
|
|
2081
2330
|
}
|
|
2082
2331
|
}
|
|
2083
2332
|
cancel() {
|
|
2084
2333
|
const turn = this.#activeTurn;
|
|
2085
|
-
if (turn === void 0) return Promise.resolve({ status: "no_active_turn" });
|
|
2334
|
+
if (turn === void 0) return this.#status === "streaming" && this.#session !== void 0 ? this.#session.cancel() : Promise.resolve({ status: "no_active_turn" });
|
|
2086
2335
|
return turn.cancel();
|
|
2087
2336
|
}
|
|
2337
|
+
[attachStore]() {
|
|
2338
|
+
this.#attached = true;
|
|
2339
|
+
if (this.#autoPrewarm && this.#session === void 0) this.prewarm().catch(() => {});
|
|
2340
|
+
}
|
|
2088
2341
|
[detachStore]() {
|
|
2342
|
+
this.#attached = false;
|
|
2343
|
+
this.#stream?.close();
|
|
2344
|
+
this.#stream = void 0;
|
|
2089
2345
|
this.#activeTurn?.abortController.abort();
|
|
2346
|
+
this.#resetPrewarm();
|
|
2347
|
+
this.#resumePromise = void 0;
|
|
2090
2348
|
}
|
|
2091
2349
|
reset() {
|
|
2350
|
+
this.#stream?.close();
|
|
2351
|
+
this.#stream = void 0;
|
|
2352
|
+
this.#pendingAuthorizations.clear();
|
|
2092
2353
|
const turn = this.#activeTurn;
|
|
2093
2354
|
this.#activeTurn = void 0;
|
|
2094
2355
|
turn?.resolveResponse(void 0);
|
|
2095
2356
|
turn?.resolveCompletion();
|
|
2096
2357
|
turn?.abortController.abort();
|
|
2358
|
+
this.#resetPrewarm();
|
|
2359
|
+
this.#resumePromise = void 0;
|
|
2097
2360
|
if (!this.#externalSession) this.#session = void 0;
|
|
2098
2361
|
this.#events = [];
|
|
2099
2362
|
this.#seenEvents = createEventDeduper();
|
|
2100
2363
|
this.#pendingMessageSubmissions = [];
|
|
2101
|
-
this.#
|
|
2102
|
-
this.#data = this.#reducer.initial();
|
|
2364
|
+
this.#projection.reset();
|
|
2103
2365
|
this.#error = void 0;
|
|
2104
2366
|
this.#status = "ready";
|
|
2105
2367
|
this.#callbacks.onSessionChange?.(this.#session?.state);
|
|
2106
2368
|
this.#publish();
|
|
2369
|
+
if (this.#autoPrewarm && this.#attached) this.prewarm().catch(() => {});
|
|
2107
2370
|
}
|
|
2108
|
-
async #sendFollowUp(turn, input) {
|
|
2371
|
+
async #sendFollowUp(turn, input, prepareSend) {
|
|
2109
2372
|
if (input.message === void 0 || input.turnPolicy !== "steer") throw new Error("eve session is already processing a turn. Send a message with turnPolicy: \"steer\" to guide it at the next boundary.");
|
|
2110
|
-
const
|
|
2373
|
+
const generation = this.#prewarmGeneration;
|
|
2374
|
+
const signal = createAbortSignal(input.signal, turn.abortController.signal);
|
|
2375
|
+
const preparedInput = await waitWithSignal(Promise.resolve(prepareSend?.(input)), signal) ?? input;
|
|
2376
|
+
if (generation !== this.#prewarmGeneration) return;
|
|
2111
2377
|
assertExclusiveTurnInput(preparedInput);
|
|
2112
2378
|
if (preparedInput.message === void 0 || preparedInput.turnPolicy !== "steer") throw new Error("An in-flight follow-up requires a message with turnPolicy: \"steer\".");
|
|
2113
|
-
if (!this.#isActiveTurn(turn)) return await this
|
|
2379
|
+
if (!this.#isActiveTurn(turn)) return await this.#submit(preparedInput);
|
|
2114
2380
|
const submissionId = this.#projectOptimisticMessage(preparedInput);
|
|
2115
2381
|
if (submissionId !== void 0) turn.followUpSubmissionIds.add(submissionId);
|
|
2116
2382
|
this.#publish();
|
|
2383
|
+
this.#ensureStream({
|
|
2384
|
+
headers: preparedInput.headers,
|
|
2385
|
+
streamReconnectPolicy: preparedInput.streamReconnectPolicy
|
|
2386
|
+
});
|
|
2117
2387
|
let dispatch;
|
|
2118
2388
|
dispatch = (async () => {
|
|
2119
2389
|
try {
|
|
2120
|
-
|
|
2390
|
+
const signal = createAbortSignal(preparedInput.signal, turn.abortController.signal);
|
|
2391
|
+
await waitWithSignal(turn.response, signal);
|
|
2121
2392
|
if (!this.#isActiveTurn(turn) || this.#session === void 0) throw new Error("The active eve turn ended before the follow-up could be sent.");
|
|
2122
2393
|
const { message, ...options } = preparedInput;
|
|
2123
|
-
await this.#session.send(message,
|
|
2394
|
+
await this.#session.send(message, {
|
|
2395
|
+
...options,
|
|
2396
|
+
signal
|
|
2397
|
+
});
|
|
2124
2398
|
turn.acceptedFollowUps += 1;
|
|
2125
2399
|
} catch (error) {
|
|
2126
|
-
this.#
|
|
2127
|
-
|
|
2400
|
+
if (this.#isActiveTurn(turn)) {
|
|
2401
|
+
this.#failPendingMessageSubmission(toError(error), submissionId);
|
|
2402
|
+
this.#publish();
|
|
2403
|
+
}
|
|
2128
2404
|
throw error;
|
|
2129
2405
|
} finally {
|
|
2130
2406
|
turn.followUpDispatches.delete(dispatch);
|
|
@@ -2134,38 +2410,94 @@ var EveAgentStore = class {
|
|
|
2134
2410
|
await dispatch;
|
|
2135
2411
|
await turn.completion;
|
|
2136
2412
|
}
|
|
2137
|
-
async #
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2413
|
+
async #dispatchTurn(input) {
|
|
2414
|
+
const streamOptions = {
|
|
2415
|
+
headers: input.headers,
|
|
2416
|
+
streamReconnectPolicy: input.streamReconnectPolicy
|
|
2417
|
+
};
|
|
2418
|
+
if (this.#prewarmPromise !== void 0) {
|
|
2419
|
+
await waitWithSignal(this.#prewarmPromise.catch((error) => {
|
|
2420
|
+
if (this.#session !== void 0) throw error;
|
|
2421
|
+
}), input.signal);
|
|
2422
|
+
input.signal?.throwIfAborted();
|
|
2423
|
+
}
|
|
2424
|
+
if (this.#session === void 0) {
|
|
2425
|
+
if (this.#client === void 0) throw new Error("An external eve session is required before sending.");
|
|
2426
|
+
if (input.message === void 0) throw new Error("Cannot answer an input request before the session starts.");
|
|
2427
|
+
const created = await this.#client.sessions.create({
|
|
2428
|
+
...input,
|
|
2429
|
+
message: input.message
|
|
2430
|
+
});
|
|
2431
|
+
input.signal?.throwIfAborted();
|
|
2432
|
+
this.#session = created.session;
|
|
2433
|
+
this.#callbacks.onSessionChange?.(created.session.state);
|
|
2434
|
+
this.#publish();
|
|
2435
|
+
return {
|
|
2436
|
+
response: created.response,
|
|
2437
|
+
reader: this.#ensureStream(streamOptions).subscribe(input.signal)
|
|
2438
|
+
};
|
|
2439
|
+
}
|
|
2440
|
+
const reader = this.#ensureStream(streamOptions).subscribe(input.signal);
|
|
2441
|
+
try {
|
|
2442
|
+
if (input.inputResponses === void 0) {
|
|
2443
|
+
const { message, ...options } = input;
|
|
2444
|
+
return {
|
|
2445
|
+
response: await this.#session.send(message, options),
|
|
2446
|
+
reader
|
|
2447
|
+
};
|
|
2146
2448
|
}
|
|
2449
|
+
const { inputResponses, ...options } = input;
|
|
2450
|
+
return {
|
|
2451
|
+
response: await this.#session.respond(inputResponses, options),
|
|
2452
|
+
reader
|
|
2453
|
+
};
|
|
2454
|
+
} catch (error) {
|
|
2455
|
+
reader[Symbol.dispose]();
|
|
2456
|
+
throw error;
|
|
2147
2457
|
}
|
|
2148
2458
|
}
|
|
2149
|
-
|
|
2150
|
-
if (this.#
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2459
|
+
#ensureStream(options = {}) {
|
|
2460
|
+
if (this.#stream !== void 0 && !this.#stream.ended) {
|
|
2461
|
+
this.#stream.setOptions(options);
|
|
2462
|
+
return this.#stream;
|
|
2463
|
+
}
|
|
2464
|
+
if (this.#session === void 0) throw new Error("A session is required before opening its stream.");
|
|
2465
|
+
const session = this.#session;
|
|
2466
|
+
const generation = this.#prewarmGeneration;
|
|
2467
|
+
this.#stream = new SessionEventStream(session, {
|
|
2468
|
+
...options,
|
|
2469
|
+
onEvent: (event) => {
|
|
2470
|
+
if (generation === this.#prewarmGeneration) this.#acceptServerEvent(event);
|
|
2471
|
+
},
|
|
2472
|
+
onError: (error) => {
|
|
2473
|
+
if (generation !== this.#prewarmGeneration) return;
|
|
2474
|
+
this.#stream = void 0;
|
|
2475
|
+
if (this.#activeTurn !== void 0) return;
|
|
2476
|
+
this.#error = toError(error);
|
|
2477
|
+
this.#status = "error";
|
|
2478
|
+
this.#callbacks.onError?.(this.#error);
|
|
2479
|
+
this.#publish();
|
|
2480
|
+
}
|
|
2155
2481
|
});
|
|
2156
|
-
this.#
|
|
2157
|
-
this.#callbacks.onSessionChange?.(created.session.state);
|
|
2158
|
-
this.#publish();
|
|
2159
|
-
return created.response;
|
|
2482
|
+
return this.#stream;
|
|
2160
2483
|
}
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2484
|
+
#resetPrewarm() {
|
|
2485
|
+
this.#prewarmGeneration += 1;
|
|
2486
|
+
this.#prewarmController?.abort();
|
|
2487
|
+
this.#prewarmController = void 0;
|
|
2488
|
+
this.#prewarmPromise = void 0;
|
|
2489
|
+
}
|
|
2490
|
+
#finishTurn(turn) {
|
|
2491
|
+
if (!this.#isActiveTurn(turn)) return;
|
|
2492
|
+
turn.resolveResponse(void 0);
|
|
2493
|
+
this.#activeTurn = void 0;
|
|
2494
|
+
try {
|
|
2495
|
+
this.#callbacks.onSessionChange?.(this.#session?.state);
|
|
2496
|
+
this.#publish();
|
|
2497
|
+
this.#callbacks.onFinish?.(this.#snapshot);
|
|
2498
|
+
} finally {
|
|
2499
|
+
turn.resolveCompletion();
|
|
2166
2500
|
}
|
|
2167
|
-
const { inputResponses, ...options } = input;
|
|
2168
|
-
return await this.#session.respond(inputResponses, options);
|
|
2169
2501
|
}
|
|
2170
2502
|
#isActiveTurn(turn) {
|
|
2171
2503
|
return this.#activeTurn === turn;
|
|
@@ -2179,7 +2511,7 @@ var EveAgentStore = class {
|
|
|
2179
2511
|
message: summarizeUserContent(input.message)
|
|
2180
2512
|
};
|
|
2181
2513
|
this.#pendingMessageSubmissions = [...this.#pendingMessageSubmissions, pending];
|
|
2182
|
-
if (this.#optimistic) this.#
|
|
2514
|
+
if (this.#optimistic) this.#projection.append({
|
|
2183
2515
|
data: {
|
|
2184
2516
|
createdAt: pending.createdAt,
|
|
2185
2517
|
message: pending.message,
|
|
@@ -2191,7 +2523,7 @@ var EveAgentStore = class {
|
|
|
2191
2523
|
}
|
|
2192
2524
|
#projectInputResponses(input) {
|
|
2193
2525
|
if (input.inputResponses === void 0 || input.inputResponses.length === 0) return;
|
|
2194
|
-
this.#
|
|
2526
|
+
this.#projection.append({
|
|
2195
2527
|
data: {
|
|
2196
2528
|
createdAt: Date.now(),
|
|
2197
2529
|
responses: input.inputResponses
|
|
@@ -2199,25 +2531,33 @@ var EveAgentStore = class {
|
|
|
2199
2531
|
type: "client.input.responded"
|
|
2200
2532
|
});
|
|
2201
2533
|
}
|
|
2202
|
-
#acceptServerEvent(event
|
|
2534
|
+
#acceptServerEvent(event) {
|
|
2203
2535
|
if (!this.#seenEvents.admit(event)) return;
|
|
2536
|
+
const wasStreaming = this.#status === "streaming";
|
|
2537
|
+
updatePendingAuthorizations(this.#pendingAuthorizations, event);
|
|
2204
2538
|
this.#events = [...this.#events, event];
|
|
2205
2539
|
this.#applyServerEvent(event);
|
|
2206
2540
|
this.#callbacks.onEvent?.(event);
|
|
2207
|
-
if (options.transitionToStreaming ?? true) this.#status = "streaming";
|
|
2208
2541
|
this.#applyTerminalStreamFailure(event);
|
|
2209
|
-
|
|
2542
|
+
const settled = isCurrentTurnBoundaryEvent(event) && this.#pendingAuthorizations.size === 0;
|
|
2543
|
+
if (this.#status !== "resuming" && this.#error === void 0) {
|
|
2544
|
+
if ("data" in event && "turnId" in event.data) this.#status = "streaming";
|
|
2545
|
+
if (this.#activeTurn === void 0 && settled) this.#status = "ready";
|
|
2546
|
+
}
|
|
2547
|
+
this.#callbacks.onSessionChange?.(this.#session?.state);
|
|
2548
|
+
this.#publish();
|
|
2549
|
+
if (this.#activeTurn === void 0 && wasStreaming && settled) this.#callbacks.onFinish?.(this.#snapshot);
|
|
2210
2550
|
}
|
|
2211
2551
|
#applyServerEvent(event) {
|
|
2212
2552
|
const pendingSubmission = this.#pendingMessageSubmissions[0];
|
|
2213
2553
|
if (event.type === "message.received" && pendingSubmission !== void 0) {
|
|
2214
2554
|
const submissionId = pendingSubmission.id;
|
|
2215
|
-
if (this.#activeTurn?.followUpSubmissionIds.delete(submissionId)) this.#activeTurn.
|
|
2555
|
+
if (this.#activeTurn?.followUpSubmissionIds.delete(submissionId)) this.#activeTurn.receivedFollowUpEvents.add(event);
|
|
2216
2556
|
this.#pendingMessageSubmissions = this.#pendingMessageSubmissions.slice(1);
|
|
2217
|
-
this.#
|
|
2557
|
+
this.#projection.replace((candidate) => candidate.type === "client.message.submitted" && candidate.data.submissionId === submissionId, event);
|
|
2218
2558
|
return;
|
|
2219
2559
|
}
|
|
2220
|
-
this.#
|
|
2560
|
+
this.#projection.append(event);
|
|
2221
2561
|
}
|
|
2222
2562
|
#applyTerminalStreamFailure(event) {
|
|
2223
2563
|
const error = toTerminalStreamFailureError(event);
|
|
@@ -2233,7 +2573,7 @@ var EveAgentStore = class {
|
|
|
2233
2573
|
const pending = submissionId === void 0 ? this.#pendingMessageSubmissions[0] : this.#pendingMessageSubmissions.find((candidate) => candidate.id === submissionId);
|
|
2234
2574
|
if (pending === void 0) return;
|
|
2235
2575
|
this.#pendingMessageSubmissions = this.#pendingMessageSubmissions.filter((candidate) => candidate.id !== pending.id);
|
|
2236
|
-
this.#
|
|
2576
|
+
this.#projection.replace((event) => event.type === "client.message.submitted" && event.data.submissionId === pending.id, {
|
|
2237
2577
|
data: {
|
|
2238
2578
|
createdAt: pending.createdAt,
|
|
2239
2579
|
error: { message: error.message },
|
|
@@ -2243,30 +2583,9 @@ var EveAgentStore = class {
|
|
|
2243
2583
|
type: "client.message.failed"
|
|
2244
2584
|
});
|
|
2245
2585
|
}
|
|
2246
|
-
#appendProjectionEvent(event) {
|
|
2247
|
-
this.#projectionEvents = [...this.#projectionEvents, event];
|
|
2248
|
-
this.#data = this.#reducer.reduce(this.#data, event);
|
|
2249
|
-
}
|
|
2250
|
-
#replaceProjectionEvent(predicate, replacement) {
|
|
2251
|
-
let replaced = false;
|
|
2252
|
-
this.#projectionEvents = this.#projectionEvents.map((event) => {
|
|
2253
|
-
if (!replaced && predicate(event)) {
|
|
2254
|
-
replaced = true;
|
|
2255
|
-
return replacement;
|
|
2256
|
-
}
|
|
2257
|
-
return event;
|
|
2258
|
-
});
|
|
2259
|
-
if (!replaced) this.#projectionEvents = [...this.#projectionEvents, replacement];
|
|
2260
|
-
this.#data = this.#reduceProjectionEvents(this.#projectionEvents);
|
|
2261
|
-
}
|
|
2262
|
-
#reduceProjectionEvents(events) {
|
|
2263
|
-
let data = this.#reducer.initial();
|
|
2264
|
-
for (const event of events) data = this.#reducer.reduce(data, event);
|
|
2265
|
-
return data;
|
|
2266
|
-
}
|
|
2267
2586
|
#createSnapshot() {
|
|
2268
2587
|
return {
|
|
2269
|
-
data: this.#data,
|
|
2588
|
+
data: this.#projection.data,
|
|
2270
2589
|
error: this.#error,
|
|
2271
2590
|
events: this.#events,
|
|
2272
2591
|
session: this.#session?.state,
|
|
@@ -2281,6 +2600,9 @@ var EveAgentStore = class {
|
|
|
2281
2600
|
function detachEveAgentStore(store) {
|
|
2282
2601
|
store[detachStore]();
|
|
2283
2602
|
}
|
|
2603
|
+
function attachEveAgentStore(store) {
|
|
2604
|
+
store[attachStore]();
|
|
2605
|
+
}
|
|
2284
2606
|
|
|
2285
2607
|
//#endregion
|
|
2286
2608
|
//#region src/client/agent-host.ts
|
|
@@ -2935,6 +3257,7 @@ function useEveAgent(options = {}) {
|
|
|
2935
3257
|
initialEvents: options.initialEvents,
|
|
2936
3258
|
initialSession: options.initialSession,
|
|
2937
3259
|
optimistic: options.optimistic,
|
|
3260
|
+
prewarm: options.prewarm,
|
|
2938
3261
|
reducer,
|
|
2939
3262
|
session: options.session
|
|
2940
3263
|
});
|
|
@@ -2950,6 +3273,7 @@ function useEveAgent(options = {}) {
|
|
|
2950
3273
|
const unsubscribe = store.subscribe(() => {
|
|
2951
3274
|
snapshot.value = store.snapshot;
|
|
2952
3275
|
});
|
|
3276
|
+
attachEveAgentStore(store);
|
|
2953
3277
|
if (options.resume) store.resume();
|
|
2954
3278
|
onScopeDispose(() => {
|
|
2955
3279
|
unsubscribe();
|
|
@@ -2961,6 +3285,7 @@ function useEveAgent(options = {}) {
|
|
|
2961
3285
|
data: computed(() => snapshot.value.data),
|
|
2962
3286
|
error: computed(() => snapshot.value.error),
|
|
2963
3287
|
events: computed(() => snapshot.value.events),
|
|
3288
|
+
prewarm: () => store.prewarm(),
|
|
2964
3289
|
reset: () => store.reset(),
|
|
2965
3290
|
respond: (inputResponses, options) => store.send({
|
|
2966
3291
|
...options,
|