@witqq/agent-sdk 0.7.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{types-CqvUAYxt.d.ts → agent-C6H2CgJA.d.cts} +139 -102
- package/dist/{types-CqvUAYxt.d.cts → agent-F7oB6eKp.d.ts} +139 -102
- package/dist/auth/index.cjs +72 -1
- package/dist/auth/index.cjs.map +1 -1
- package/dist/auth/index.d.cts +21 -154
- package/dist/auth/index.d.ts +21 -154
- package/dist/auth/index.js +72 -1
- package/dist/auth/index.js.map +1 -1
- package/dist/backends/claude.cjs +480 -261
- package/dist/backends/claude.cjs.map +1 -1
- package/dist/backends/claude.d.cts +3 -1
- package/dist/backends/claude.d.ts +3 -1
- package/dist/backends/claude.js +480 -261
- package/dist/backends/claude.js.map +1 -1
- package/dist/backends/copilot.cjs +337 -112
- package/dist/backends/copilot.cjs.map +1 -1
- package/dist/backends/copilot.d.cts +12 -4
- package/dist/backends/copilot.d.ts +12 -4
- package/dist/backends/copilot.js +337 -112
- package/dist/backends/copilot.js.map +1 -1
- package/dist/backends/mock-llm.cjs +719 -0
- package/dist/backends/mock-llm.cjs.map +1 -0
- package/dist/backends/mock-llm.d.cts +37 -0
- package/dist/backends/mock-llm.d.ts +37 -0
- package/dist/backends/mock-llm.js +717 -0
- package/dist/backends/mock-llm.js.map +1 -0
- package/dist/backends/vercel-ai.cjs +301 -61
- package/dist/backends/vercel-ai.cjs.map +1 -1
- package/dist/backends/vercel-ai.d.cts +3 -1
- package/dist/backends/vercel-ai.d.ts +3 -1
- package/dist/backends/vercel-ai.js +301 -61
- package/dist/backends/vercel-ai.js.map +1 -1
- package/dist/backends-Cno0gZjy.d.cts +114 -0
- package/dist/backends-Cno0gZjy.d.ts +114 -0
- package/dist/chat/accumulator.cjs +1 -1
- package/dist/chat/accumulator.cjs.map +1 -1
- package/dist/chat/accumulator.d.cts +5 -2
- package/dist/chat/accumulator.d.ts +5 -2
- package/dist/chat/accumulator.js +1 -1
- package/dist/chat/accumulator.js.map +1 -1
- package/dist/chat/backends.cjs +1084 -821
- package/dist/chat/backends.cjs.map +1 -1
- package/dist/chat/backends.d.cts +10 -6
- package/dist/chat/backends.d.ts +10 -6
- package/dist/chat/backends.js +1082 -800
- package/dist/chat/backends.js.map +1 -1
- package/dist/chat/context.cjs +50 -0
- package/dist/chat/context.cjs.map +1 -1
- package/dist/chat/context.d.cts +27 -3
- package/dist/chat/context.d.ts +27 -3
- package/dist/chat/context.js +50 -0
- package/dist/chat/context.js.map +1 -1
- package/dist/chat/core.cjs +60 -27
- package/dist/chat/core.cjs.map +1 -1
- package/dist/chat/core.d.cts +41 -382
- package/dist/chat/core.d.ts +41 -382
- package/dist/chat/core.js +58 -28
- package/dist/chat/core.js.map +1 -1
- package/dist/chat/errors.cjs +48 -26
- package/dist/chat/errors.cjs.map +1 -1
- package/dist/chat/errors.d.cts +6 -31
- package/dist/chat/errors.d.ts +6 -31
- package/dist/chat/errors.js +48 -25
- package/dist/chat/errors.js.map +1 -1
- package/dist/chat/events.cjs.map +1 -1
- package/dist/chat/events.d.cts +6 -2
- package/dist/chat/events.d.ts +6 -2
- package/dist/chat/events.js.map +1 -1
- package/dist/chat/index.cjs +1612 -1125
- package/dist/chat/index.cjs.map +1 -1
- package/dist/chat/index.d.cts +35 -10
- package/dist/chat/index.d.ts +35 -10
- package/dist/chat/index.js +1600 -1097
- package/dist/chat/index.js.map +1 -1
- package/dist/chat/react/theme.css +2517 -0
- package/dist/chat/react.cjs +2212 -1158
- package/dist/chat/react.cjs.map +1 -1
- package/dist/chat/react.d.cts +665 -122
- package/dist/chat/react.d.ts +665 -122
- package/dist/chat/react.js +2191 -1156
- package/dist/chat/react.js.map +1 -1
- package/dist/chat/runtime.cjs +405 -186
- package/dist/chat/runtime.cjs.map +1 -1
- package/dist/chat/runtime.d.cts +92 -28
- package/dist/chat/runtime.d.ts +92 -28
- package/dist/chat/runtime.js +405 -186
- package/dist/chat/runtime.js.map +1 -1
- package/dist/chat/server.cjs +2247 -212
- package/dist/chat/server.cjs.map +1 -1
- package/dist/chat/server.d.cts +451 -90
- package/dist/chat/server.d.ts +451 -90
- package/dist/chat/server.js +2234 -213
- package/dist/chat/server.js.map +1 -1
- package/dist/chat/sessions.cjs +64 -66
- package/dist/chat/sessions.cjs.map +1 -1
- package/dist/chat/sessions.d.cts +37 -118
- package/dist/chat/sessions.d.ts +37 -118
- package/dist/chat/sessions.js +65 -67
- package/dist/chat/sessions.js.map +1 -1
- package/dist/chat/sqlite.cjs +536 -0
- package/dist/chat/sqlite.cjs.map +1 -0
- package/dist/chat/sqlite.d.cts +164 -0
- package/dist/chat/sqlite.d.ts +164 -0
- package/dist/chat/sqlite.js +527 -0
- package/dist/chat/sqlite.js.map +1 -0
- package/dist/chat/state.cjs +14 -1
- package/dist/chat/state.cjs.map +1 -1
- package/dist/chat/state.d.cts +5 -2
- package/dist/chat/state.d.ts +5 -2
- package/dist/chat/state.js +14 -1
- package/dist/chat/state.js.map +1 -1
- package/dist/chat/storage.cjs +58 -33
- package/dist/chat/storage.cjs.map +1 -1
- package/dist/chat/storage.d.cts +18 -8
- package/dist/chat/storage.d.ts +18 -8
- package/dist/chat/storage.js +59 -34
- package/dist/chat/storage.js.map +1 -1
- package/dist/errors-C-so0M4t.d.cts +33 -0
- package/dist/errors-C-so0M4t.d.ts +33 -0
- package/dist/errors-CmVvczxZ.d.cts +28 -0
- package/dist/errors-CmVvczxZ.d.ts +28 -0
- package/dist/{in-process-transport-C2oPTYs6.d.ts → in-process-transport-7EIit9Xk.d.ts} +72 -33
- package/dist/{in-process-transport-DG-w5G6k.d.cts → in-process-transport-Ct9YcX8I.d.cts} +72 -33
- package/dist/index.cjs +354 -60
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +294 -123
- package/dist/index.d.ts +294 -123
- package/dist/index.js +347 -60
- package/dist/index.js.map +1 -1
- package/dist/provider-types-PTSlRPNB.d.cts +39 -0
- package/dist/provider-types-PTSlRPNB.d.ts +39 -0
- package/dist/refresh-manager-B81PpYBr.d.cts +153 -0
- package/dist/refresh-manager-Dlv_iNZi.d.ts +153 -0
- package/dist/testing.cjs +1107 -0
- package/dist/testing.cjs.map +1 -0
- package/dist/testing.d.cts +144 -0
- package/dist/testing.d.ts +144 -0
- package/dist/testing.js +1101 -0
- package/dist/testing.js.map +1 -0
- package/dist/token-store-CSUBgYwn.d.ts +48 -0
- package/dist/token-store-CuC4hB9Z.d.cts +48 -0
- package/dist/{transport-DX1Nhm4N.d.cts → transport-DLWCN18G.d.cts} +5 -4
- package/dist/{transport-D1OaUgRk.d.ts → transport-DsuS-GeM.d.ts} +5 -4
- package/dist/{types-CGF7AEX1.d.cts → types-4vbcmPTp.d.cts} +4 -2
- package/dist/{types-Bh5AhqD-.d.ts → types-BxggH0Yh.d.ts} +4 -2
- package/dist/types-DgtI1hzh.d.ts +364 -0
- package/dist/types-DkSXALKg.d.cts +364 -0
- package/package.json +41 -5
- package/LICENSE +0 -21
- package/README.md +0 -948
- package/dist/errors-BDLbNu9w.d.cts +0 -13
- package/dist/errors-BDLbNu9w.d.ts +0 -13
- package/dist/types-DLZzlJxt.d.ts +0 -39
- package/dist/types-tE0CXwBl.d.cts +0 -39
package/dist/chat/runtime.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
// src/chat/
|
|
3
|
+
// src/chat/types.ts
|
|
4
4
|
function createChatId() {
|
|
5
5
|
return crypto.randomUUID();
|
|
6
6
|
}
|
|
@@ -11,6 +11,8 @@ function toChatId(value) {
|
|
|
11
11
|
}
|
|
12
12
|
return value;
|
|
13
13
|
}
|
|
14
|
+
|
|
15
|
+
// src/chat/bridge.ts
|
|
14
16
|
function chatEventToAgentEvent(event) {
|
|
15
17
|
switch (event.type) {
|
|
16
18
|
case "message:delta":
|
|
@@ -36,7 +38,7 @@ function chatEventToAgentEvent(event) {
|
|
|
36
38
|
result: event.result
|
|
37
39
|
};
|
|
38
40
|
case "error":
|
|
39
|
-
return { type: "error", error: event.error, recoverable: event.recoverable };
|
|
41
|
+
return { type: "error", error: event.error, recoverable: event.recoverable, code: event.code };
|
|
40
42
|
default:
|
|
41
43
|
return null;
|
|
42
44
|
}
|
|
@@ -150,6 +152,56 @@ var ContextWindowManager = class {
|
|
|
150
152
|
});
|
|
151
153
|
return { ...result, messages: updatedMessages };
|
|
152
154
|
}
|
|
155
|
+
/**
|
|
156
|
+
* Trim messages using real token usage data from the previous API call.
|
|
157
|
+
* Uses average-based algorithm: `avgTokensPerMessage = lastPromptTokens / messageCount`.
|
|
158
|
+
* Removes oldest non-system messages until freed budget brings usage under modelContextWindow.
|
|
159
|
+
*
|
|
160
|
+
* @param messages - All messages in the session
|
|
161
|
+
* @param lastPromptTokens - Real prompt tokens from the last API response
|
|
162
|
+
* @param modelContextWindow - Model's total context window size in tokens
|
|
163
|
+
* @returns Result with fitted messages and metadata
|
|
164
|
+
*/
|
|
165
|
+
fitMessagesWithUsage(messages, lastPromptTokens, modelContextWindow) {
|
|
166
|
+
if (messages.length === 0) {
|
|
167
|
+
return { messages: [], totalTokens: 0, removedCount: 0, wasTruncated: false };
|
|
168
|
+
}
|
|
169
|
+
const budget = modelContextWindow - this.config.reservedTokens;
|
|
170
|
+
if (budget <= 0 || lastPromptTokens <= budget) {
|
|
171
|
+
return {
|
|
172
|
+
messages: [...messages],
|
|
173
|
+
totalTokens: lastPromptTokens,
|
|
174
|
+
removedCount: 0,
|
|
175
|
+
wasTruncated: false
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
const avgTokensPerMessage = lastPromptTokens / messages.length;
|
|
179
|
+
const tokensToFree = lastPromptTokens - budget;
|
|
180
|
+
const messagesToRemove = Math.ceil(tokensToFree / avgTokensPerMessage);
|
|
181
|
+
const nonSystemIndices = [];
|
|
182
|
+
for (let i = 0; i < messages.length; i++) {
|
|
183
|
+
if (messages[i].role === "system") ; else {
|
|
184
|
+
nonSystemIndices.push(i);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
const removableCount = Math.min(messagesToRemove, nonSystemIndices.length);
|
|
188
|
+
const removedIndices = new Set(nonSystemIndices.slice(0, removableCount));
|
|
189
|
+
const result = [];
|
|
190
|
+
for (let i = 0; i < messages.length; i++) {
|
|
191
|
+
if (!removedIndices.has(i)) {
|
|
192
|
+
result.push(messages[i]);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
const estimatedTokens = Math.round(
|
|
196
|
+
lastPromptTokens * (result.length / messages.length)
|
|
197
|
+
);
|
|
198
|
+
return {
|
|
199
|
+
messages: result,
|
|
200
|
+
totalTokens: estimatedTokens,
|
|
201
|
+
removedCount: removableCount,
|
|
202
|
+
wasTruncated: removableCount > 0
|
|
203
|
+
};
|
|
204
|
+
}
|
|
153
205
|
/**
|
|
154
206
|
* Truncate oldest: keeps system messages, removes oldest non-system messages first.
|
|
155
207
|
* Always keeps the most recent user message.
|
|
@@ -270,9 +322,18 @@ var ContextWindowManager = class {
|
|
|
270
322
|
var AgentSDKError = class extends Error {
|
|
271
323
|
/** @internal Marker for cross-bundle identity checks */
|
|
272
324
|
_agentSDKError = true;
|
|
325
|
+
/** Machine-readable error code. Prefer values from the ErrorCode enum. */
|
|
326
|
+
code;
|
|
327
|
+
/** Whether this error is safe to retry */
|
|
328
|
+
retryable;
|
|
329
|
+
/** HTTP status code hint for error classification */
|
|
330
|
+
httpStatus;
|
|
273
331
|
constructor(message, options) {
|
|
274
332
|
super(message, options);
|
|
275
333
|
this.name = "AgentSDKError";
|
|
334
|
+
this.code = options?.code;
|
|
335
|
+
this.retryable = options?.retryable ?? false;
|
|
336
|
+
this.httpStatus = options?.httpStatus;
|
|
276
337
|
}
|
|
277
338
|
/** Check if an error is an AgentSDKError (works across bundled copies) */
|
|
278
339
|
static is(error) {
|
|
@@ -287,7 +348,11 @@ var ChatError = class extends AgentSDKError {
|
|
|
287
348
|
retryAfter;
|
|
288
349
|
timestamp;
|
|
289
350
|
constructor(message, options) {
|
|
290
|
-
super(message, {
|
|
351
|
+
super(message, {
|
|
352
|
+
cause: options.cause,
|
|
353
|
+
code: options.code,
|
|
354
|
+
retryable: options.retryable
|
|
355
|
+
});
|
|
291
356
|
this.name = "ChatError";
|
|
292
357
|
this.code = options.code;
|
|
293
358
|
this.retryable = options.retryable ?? false;
|
|
@@ -608,6 +673,35 @@ var CancellableTimeout = class {
|
|
|
608
673
|
}
|
|
609
674
|
};
|
|
610
675
|
|
|
676
|
+
// src/chat/listener-set.ts
|
|
677
|
+
var ListenerSet = class {
|
|
678
|
+
_listeners = /* @__PURE__ */ new Set();
|
|
679
|
+
/** Add a listener. Returns an unsubscribe function. */
|
|
680
|
+
add(callback) {
|
|
681
|
+
this._listeners.add(callback);
|
|
682
|
+
return () => {
|
|
683
|
+
this._listeners.delete(callback);
|
|
684
|
+
};
|
|
685
|
+
}
|
|
686
|
+
/** Notify all listeners with the given arguments. Errors are isolated per listener. */
|
|
687
|
+
notify(...args) {
|
|
688
|
+
for (const cb of this._listeners) {
|
|
689
|
+
try {
|
|
690
|
+
cb(...args);
|
|
691
|
+
} catch {
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
/** Remove all listeners. */
|
|
696
|
+
clear() {
|
|
697
|
+
this._listeners.clear();
|
|
698
|
+
}
|
|
699
|
+
/** Current number of listeners. */
|
|
700
|
+
get size() {
|
|
701
|
+
return this._listeners.size;
|
|
702
|
+
}
|
|
703
|
+
};
|
|
704
|
+
|
|
611
705
|
// src/chat/runtime.ts
|
|
612
706
|
var ChatRuntime = class {
|
|
613
707
|
_state;
|
|
@@ -615,26 +709,29 @@ var ChatRuntime = class {
|
|
|
615
709
|
_backends;
|
|
616
710
|
_sessionStore;
|
|
617
711
|
_contextConfig;
|
|
712
|
+
_ctxManager;
|
|
618
713
|
_middleware;
|
|
619
714
|
_tools = /* @__PURE__ */ new Map();
|
|
620
715
|
_retryConfig;
|
|
621
716
|
_contextStats = /* @__PURE__ */ new Map();
|
|
717
|
+
_sessionUsage = /* @__PURE__ */ new Map();
|
|
718
|
+
_modelContextWindows = /* @__PURE__ */ new Map();
|
|
622
719
|
_onContextTrimmed;
|
|
623
720
|
_streamTimeoutMs;
|
|
624
|
-
_sessionListeners =
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
_currentModel;
|
|
628
|
-
_activeSessionId = null;
|
|
721
|
+
_sessionListeners = new ListenerSet();
|
|
722
|
+
_adapterPool = /* @__PURE__ */ new Map();
|
|
723
|
+
_defaultBackend;
|
|
629
724
|
_abortController = null;
|
|
630
725
|
constructor(options) {
|
|
631
726
|
this._state = new StateMachine("idle", RUNTIME_TRANSITIONS);
|
|
632
727
|
this._guard = new ChatReentrancyGuard();
|
|
633
728
|
this._backends = options.backends;
|
|
634
|
-
this.
|
|
635
|
-
this._currentModel = options.defaultModel;
|
|
729
|
+
this._defaultBackend = options.defaultBackend;
|
|
636
730
|
this._sessionStore = options.sessionStore;
|
|
637
731
|
this._contextConfig = options.context;
|
|
732
|
+
if (this._contextConfig) {
|
|
733
|
+
this._ctxManager = new ContextWindowManager(this._contextConfig);
|
|
734
|
+
}
|
|
638
735
|
this._middleware = [...options.middleware ?? []];
|
|
639
736
|
this._retryConfig = options.retryConfig;
|
|
640
737
|
this._onContextTrimmed = options.onContextTrimmed;
|
|
@@ -645,6 +742,11 @@ var ChatRuntime = class {
|
|
|
645
742
|
{ code: "INVALID_INPUT" /* INVALID_INPUT */ }
|
|
646
743
|
);
|
|
647
744
|
}
|
|
745
|
+
if (options.tools) {
|
|
746
|
+
for (const tool of options.tools) {
|
|
747
|
+
this._tools.set(tool.name, tool);
|
|
748
|
+
}
|
|
749
|
+
}
|
|
648
750
|
}
|
|
649
751
|
// ── Lifecycle ──────────────────────────────────────────────
|
|
650
752
|
get status() {
|
|
@@ -656,24 +758,23 @@ var ChatRuntime = class {
|
|
|
656
758
|
this._abortController?.dispose();
|
|
657
759
|
this._abortController = null;
|
|
658
760
|
this._state.transition("disposed");
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
761
|
+
for (const adapter of this._adapterPool.values()) {
|
|
762
|
+
try {
|
|
763
|
+
await adapter.dispose();
|
|
764
|
+
} catch {
|
|
765
|
+
}
|
|
662
766
|
}
|
|
767
|
+
this._adapterPool.clear();
|
|
663
768
|
}
|
|
664
769
|
// ── Sessions ───────────────────────────────────────────────
|
|
665
|
-
get activeSessionId() {
|
|
666
|
-
return this._activeSessionId;
|
|
667
|
-
}
|
|
668
770
|
async createSession(options) {
|
|
669
771
|
this.assertNotDisposed();
|
|
670
772
|
const config = {
|
|
671
|
-
model: options.config?.model ??
|
|
672
|
-
backend: options.config?.backend ?? this.
|
|
773
|
+
model: options.config?.model ?? "",
|
|
774
|
+
backend: options.config?.backend ?? this._defaultBackend,
|
|
673
775
|
...options.config
|
|
674
776
|
};
|
|
675
777
|
const session = await this._sessionStore.createSession({ ...options, config });
|
|
676
|
-
this._activeSessionId = session.id;
|
|
677
778
|
this._notifySessionChange();
|
|
678
779
|
return session;
|
|
679
780
|
}
|
|
@@ -693,36 +794,12 @@ var ChatRuntime = class {
|
|
|
693
794
|
if (!session) return;
|
|
694
795
|
await this._sessionStore.deleteSession(cid);
|
|
695
796
|
this._contextStats.delete(cid);
|
|
696
|
-
|
|
697
|
-
this._activeSessionId = null;
|
|
698
|
-
}
|
|
797
|
+
this._sessionUsage.delete(cid);
|
|
699
798
|
this._notifySessionChange();
|
|
700
799
|
}
|
|
701
|
-
async archiveSession(id) {
|
|
702
|
-
this.assertNotDisposed();
|
|
703
|
-
const cid = toChatId(id);
|
|
704
|
-
await this._sessionStore.archiveSession(cid);
|
|
705
|
-
this._notifySessionChange();
|
|
706
|
-
}
|
|
707
|
-
async switchSession(id) {
|
|
708
|
-
this.assertNotDisposed();
|
|
709
|
-
const cid = toChatId(id);
|
|
710
|
-
const session = await this._sessionStore.getSession(cid);
|
|
711
|
-
if (!session) {
|
|
712
|
-
throw new ChatError(
|
|
713
|
-
`Session "${id}" not found`,
|
|
714
|
-
{ code: "SESSION_NOT_FOUND" /* SESSION_NOT_FOUND */ }
|
|
715
|
-
);
|
|
716
|
-
}
|
|
717
|
-
this._activeSessionId = session.id;
|
|
718
|
-
return session;
|
|
719
|
-
}
|
|
720
800
|
// ── Messaging ──────────────────────────────────────────────
|
|
721
801
|
async *send(sessionId, message, options) {
|
|
722
|
-
this.
|
|
723
|
-
if (!message || message.trim().length === 0) {
|
|
724
|
-
throw new ChatError("Message cannot be empty", { code: "INVALID_INPUT" /* INVALID_INPUT */ });
|
|
725
|
-
}
|
|
802
|
+
this.validateSendInput(message, options);
|
|
726
803
|
this._guard.acquire();
|
|
727
804
|
const cid = toChatId(sessionId);
|
|
728
805
|
this._abortController = new ChatAbortController(options?.signal);
|
|
@@ -731,150 +808,274 @@ var ChatRuntime = class {
|
|
|
731
808
|
this._state.transition("idle");
|
|
732
809
|
}
|
|
733
810
|
this._state.transition("streaming");
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
throw new ChatError(
|
|
737
|
-
`Session "${cid}" not found`,
|
|
738
|
-
{ code: "SESSION_NOT_FOUND" /* SESSION_NOT_FOUND */ }
|
|
739
|
-
);
|
|
740
|
-
}
|
|
741
|
-
const middlewareContext = {
|
|
811
|
+
await this.loadSession(cid);
|
|
812
|
+
const mwCtx = {
|
|
742
813
|
sessionId: cid,
|
|
743
814
|
signal: this._abortController.signal
|
|
744
815
|
};
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
const updatedSession = await this._sessionStore.getSession(cid);
|
|
753
|
-
let messagesToSend = updatedSession.messages;
|
|
754
|
-
if (this._contextConfig) {
|
|
755
|
-
const ctxManager = new ContextWindowManager(this._contextConfig);
|
|
756
|
-
const result = await ctxManager.fitMessagesAsync(messagesToSend);
|
|
757
|
-
this._contextStats.set(cid, {
|
|
758
|
-
totalTokens: result.totalTokens,
|
|
759
|
-
removedCount: result.removedCount,
|
|
760
|
-
wasTruncated: result.wasTruncated,
|
|
761
|
-
availableBudget: ctxManager.availableBudget
|
|
762
|
-
});
|
|
763
|
-
if (result.wasTruncated && this._onContextTrimmed) {
|
|
764
|
-
const keptIds = new Set(result.messages.map((m) => m.id));
|
|
765
|
-
const removed = messagesToSend.filter((m) => !keptIds.has(m.id));
|
|
766
|
-
if (removed.length > 0) {
|
|
767
|
-
try {
|
|
768
|
-
this._onContextTrimmed(cid, removed);
|
|
769
|
-
} catch {
|
|
770
|
-
}
|
|
771
|
-
}
|
|
772
|
-
}
|
|
773
|
-
messagesToSend = result.messages;
|
|
816
|
+
const userMessage = await this.applyBeforeSendMiddleware(
|
|
817
|
+
this.createUserMessage(message),
|
|
818
|
+
mwCtx
|
|
819
|
+
);
|
|
820
|
+
if (userMessage === null) {
|
|
821
|
+
this._state.transition("idle");
|
|
822
|
+
return;
|
|
774
823
|
}
|
|
775
|
-
const
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
824
|
+
const updatedSession = await this.persistAndReload(cid, userMessage);
|
|
825
|
+
const sessionForAdapter = await this.trimSessionContext(cid, updatedSession, options.model);
|
|
826
|
+
const stream = await this.prepareEventStream(
|
|
827
|
+
cid,
|
|
828
|
+
sessionForAdapter,
|
|
829
|
+
updatedSession,
|
|
830
|
+
message,
|
|
831
|
+
options
|
|
832
|
+
);
|
|
780
833
|
const accumulator = new MessageAccumulator();
|
|
781
|
-
const runtimeTools = this._tools.size > 0 ? this.injectToolContext([...this._tools.values()], {
|
|
782
|
-
sessionId: cid,
|
|
783
|
-
custom: updatedSession.metadata?.custom
|
|
784
|
-
}) : void 0;
|
|
785
|
-
const streamOptions = {
|
|
786
|
-
...options,
|
|
787
|
-
signal: this._abortController.signal,
|
|
788
|
-
model: options?.model ?? this._currentModel,
|
|
789
|
-
tools: runtimeTools
|
|
790
|
-
};
|
|
791
|
-
const stream = await this.createStreamWithRetry(adapter, sessionForAdapter, message, streamOptions);
|
|
792
834
|
const eventSource = this._streamTimeoutMs ? withStreamWatchdog(stream, { timeoutMs: this._streamTimeoutMs, signal: this._abortController.signal }) : stream;
|
|
793
835
|
for await (const event of eventSource) {
|
|
794
836
|
if (this._abortController.isAborted) break;
|
|
795
837
|
this.feedAccumulator(accumulator, event);
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
}
|
|
801
|
-
|
|
802
|
-
if (processedEvent) {
|
|
803
|
-
yield processedEvent;
|
|
804
|
-
}
|
|
805
|
-
}
|
|
806
|
-
if (this._state.current === "disposed") {
|
|
807
|
-
return;
|
|
808
|
-
}
|
|
809
|
-
let assistantMessage = accumulator.finalize();
|
|
810
|
-
for (const mw of this._middleware) {
|
|
811
|
-
if (mw.onAfterReceive) {
|
|
812
|
-
assistantMessage = await mw.onAfterReceive(assistantMessage, middlewareContext);
|
|
838
|
+
if (event.type === "usage") {
|
|
839
|
+
this._sessionUsage.set(cid, {
|
|
840
|
+
promptTokens: event.promptTokens,
|
|
841
|
+
completionTokens: event.completionTokens
|
|
842
|
+
});
|
|
843
|
+
this.updateContextStatsWithUsage(cid, event.promptTokens, event.completionTokens, options);
|
|
813
844
|
}
|
|
845
|
+
const processed = await this.applyOnEventMiddleware(event, mwCtx);
|
|
846
|
+
if (processed) yield processed;
|
|
814
847
|
}
|
|
815
|
-
|
|
816
|
-
this.
|
|
848
|
+
if (this._state.current === "disposed") return;
|
|
849
|
+
await this.finalizeAssistantMessage(cid, accumulator, mwCtx);
|
|
817
850
|
this._state.transition("idle");
|
|
818
851
|
} catch (error) {
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
sessionId: cid,
|
|
822
|
-
signal: this._abortController?.signal ?? new AbortController().signal
|
|
823
|
-
};
|
|
824
|
-
for (const mw of this._middleware) {
|
|
825
|
-
if (mw.onError) {
|
|
826
|
-
const result = await mw.onError(processedError, middlewareContext);
|
|
827
|
-
if (result === null) {
|
|
828
|
-
if (this._state.canTransition("idle")) {
|
|
829
|
-
this._state.transition("idle");
|
|
830
|
-
}
|
|
831
|
-
return;
|
|
832
|
-
}
|
|
833
|
-
processedError = result;
|
|
834
|
-
}
|
|
835
|
-
}
|
|
836
|
-
if (this._state.canTransition("error")) {
|
|
837
|
-
this._state.transition("error");
|
|
838
|
-
}
|
|
839
|
-
throw processedError;
|
|
852
|
+
const result = await this.handleSendError(error, cid);
|
|
853
|
+
if (result !== null) throw result;
|
|
840
854
|
} finally {
|
|
841
855
|
this._guard.release();
|
|
842
856
|
this._abortController?.dispose();
|
|
843
857
|
this._abortController = null;
|
|
844
858
|
}
|
|
845
859
|
}
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
// ── Backend / Model ────────────────────────────────────────
|
|
850
|
-
get currentBackend() {
|
|
851
|
-
return this._currentBackend;
|
|
852
|
-
}
|
|
853
|
-
get currentModel() {
|
|
854
|
-
return this._currentModel;
|
|
855
|
-
}
|
|
856
|
-
async switchBackend(name) {
|
|
860
|
+
// ── Send Pipeline Stages ──────────────────────────────────────
|
|
861
|
+
/** Stage 1: Validate send inputs (message content + required fields). */
|
|
862
|
+
validateSendInput(message, options) {
|
|
857
863
|
this.assertNotDisposed();
|
|
858
|
-
if (!
|
|
864
|
+
if (!message || message.trim().length === 0) {
|
|
865
|
+
throw new ChatError("Message cannot be empty", { code: "INVALID_INPUT" /* INVALID_INPUT */ });
|
|
866
|
+
}
|
|
867
|
+
if (!options.model) {
|
|
859
868
|
throw new ChatError(
|
|
860
|
-
|
|
869
|
+
"options.model is required \u2014 caller must specify which model to use",
|
|
861
870
|
{ code: "INVALID_INPUT" /* INVALID_INPUT */ }
|
|
862
871
|
);
|
|
863
872
|
}
|
|
864
|
-
if (
|
|
865
|
-
|
|
866
|
-
|
|
873
|
+
if (!options.backend) {
|
|
874
|
+
throw new ChatError(
|
|
875
|
+
"options.backend is required \u2014 caller must specify which backend to use",
|
|
876
|
+
{ code: "INVALID_INPUT" /* INVALID_INPUT */ }
|
|
877
|
+
);
|
|
878
|
+
}
|
|
879
|
+
if (!options.credentials) {
|
|
880
|
+
throw new ChatError(
|
|
881
|
+
"options.credentials is required \u2014 caller must provide authentication credentials",
|
|
882
|
+
{ code: "INVALID_INPUT" /* INVALID_INPUT */ }
|
|
883
|
+
);
|
|
867
884
|
}
|
|
868
|
-
this._currentBackend = name;
|
|
869
885
|
}
|
|
870
|
-
|
|
886
|
+
/** Stage 2: Load session from store. */
|
|
887
|
+
async loadSession(cid) {
|
|
888
|
+
const session = await this._sessionStore.getSession(cid);
|
|
889
|
+
if (!session) {
|
|
890
|
+
throw new ChatError(
|
|
891
|
+
`Session "${cid}" not found`,
|
|
892
|
+
{ code: "SESSION_NOT_FOUND" /* SESSION_NOT_FOUND */ }
|
|
893
|
+
);
|
|
894
|
+
}
|
|
895
|
+
return session;
|
|
896
|
+
}
|
|
897
|
+
/** Stage 3: Apply onBeforeSend middleware pipeline. Returns null if middleware rejected the send. */
|
|
898
|
+
async applyBeforeSendMiddleware(userMessage, ctx) {
|
|
899
|
+
let msg = userMessage;
|
|
900
|
+
for (const mw of this._middleware) {
|
|
901
|
+
if (mw.onBeforeSend && msg) {
|
|
902
|
+
msg = await mw.onBeforeSend(msg, ctx);
|
|
903
|
+
if (msg === null) return null;
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
return msg;
|
|
907
|
+
}
|
|
908
|
+
/** Stage 4: Persist user message and reload session with full history. */
|
|
909
|
+
async persistAndReload(cid, userMessage) {
|
|
910
|
+
await this._sessionStore.appendMessage(cid, userMessage);
|
|
911
|
+
return await this._sessionStore.getSession(cid);
|
|
912
|
+
}
|
|
913
|
+
/** Stage 5: Auto-trim context window if configured. Returns session snapshot for adapter. */
|
|
914
|
+
async trimSessionContext(cid, session, model) {
|
|
915
|
+
if (!this._ctxManager) return session;
|
|
916
|
+
const ctxManager = this._ctxManager;
|
|
917
|
+
const lastUsage = this._sessionUsage.get(cid);
|
|
918
|
+
const modelContextWindow = model ? this._modelContextWindows.get(model) : void 0;
|
|
919
|
+
if (lastUsage && modelContextWindow) {
|
|
920
|
+
const result2 = ctxManager.fitMessagesWithUsage(
|
|
921
|
+
session.messages,
|
|
922
|
+
lastUsage.promptTokens,
|
|
923
|
+
modelContextWindow
|
|
924
|
+
);
|
|
925
|
+
this._contextStats.set(cid, {
|
|
926
|
+
totalTokens: result2.totalTokens,
|
|
927
|
+
removedCount: result2.removedCount,
|
|
928
|
+
wasTruncated: result2.wasTruncated,
|
|
929
|
+
availableBudget: Math.max(0, modelContextWindow - result2.totalTokens),
|
|
930
|
+
realPromptTokens: lastUsage.promptTokens,
|
|
931
|
+
realCompletionTokens: lastUsage.completionTokens,
|
|
932
|
+
modelContextWindow
|
|
933
|
+
});
|
|
934
|
+
if (result2.wasTruncated && this._onContextTrimmed) {
|
|
935
|
+
const keptIds = new Set(result2.messages.map((m) => m.id));
|
|
936
|
+
const removed = session.messages.filter((m) => !keptIds.has(m.id));
|
|
937
|
+
if (removed.length > 0) {
|
|
938
|
+
try {
|
|
939
|
+
this._onContextTrimmed(cid, removed);
|
|
940
|
+
} catch {
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
}
|
|
944
|
+
return { ...session, messages: result2.messages };
|
|
945
|
+
}
|
|
946
|
+
const result = await ctxManager.fitMessagesAsync(session.messages);
|
|
947
|
+
this._contextStats.set(cid, {
|
|
948
|
+
totalTokens: result.totalTokens,
|
|
949
|
+
removedCount: result.removedCount,
|
|
950
|
+
wasTruncated: result.wasTruncated,
|
|
951
|
+
availableBudget: ctxManager.availableBudget,
|
|
952
|
+
modelContextWindow
|
|
953
|
+
});
|
|
954
|
+
if (result.wasTruncated && this._onContextTrimmed) {
|
|
955
|
+
const keptIds = new Set(result.messages.map((m) => m.id));
|
|
956
|
+
const removed = session.messages.filter((m) => !keptIds.has(m.id));
|
|
957
|
+
if (removed.length > 0) {
|
|
958
|
+
try {
|
|
959
|
+
this._onContextTrimmed(cid, removed);
|
|
960
|
+
} catch {
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
return { ...session, messages: result.messages };
|
|
965
|
+
}
|
|
966
|
+
/** Update context stats with real usage data from a usage event. */
|
|
967
|
+
updateContextStatsWithUsage(cid, promptTokens, completionTokens, options) {
|
|
968
|
+
const modelContextWindow = options.model ? this._modelContextWindows.get(options.model) : void 0;
|
|
969
|
+
const existing = this._contextStats.get(cid);
|
|
970
|
+
this._contextStats.set(cid, {
|
|
971
|
+
totalTokens: promptTokens,
|
|
972
|
+
removedCount: existing?.removedCount ?? 0,
|
|
973
|
+
wasTruncated: existing?.wasTruncated ?? false,
|
|
974
|
+
availableBudget: modelContextWindow ? Math.max(0, modelContextWindow - promptTokens) : existing?.availableBudget ?? 0,
|
|
975
|
+
realPromptTokens: promptTokens,
|
|
976
|
+
realCompletionTokens: completionTokens,
|
|
977
|
+
modelContextWindow
|
|
978
|
+
});
|
|
979
|
+
}
|
|
980
|
+
/** Stage 6: Prepare event stream — adapter with retry, tool injection. */
|
|
981
|
+
async prepareEventStream(cid, sessionForAdapter, fullSession, message, options) {
|
|
982
|
+
const adapter = await this.getOrCreateAdapterWithRetry(options.backend, options.credentials);
|
|
983
|
+
const runtimeTools = this._tools.size > 0 ? this.injectToolContext([...this._tools.values()], {
|
|
984
|
+
sessionId: cid,
|
|
985
|
+
custom: fullSession.metadata?.custom
|
|
986
|
+
}) : void 0;
|
|
987
|
+
const streamOptions = {
|
|
988
|
+
signal: this._abortController.signal,
|
|
989
|
+
model: options.model,
|
|
990
|
+
systemPrompt: options.systemPrompt,
|
|
991
|
+
tools: runtimeTools
|
|
992
|
+
};
|
|
993
|
+
return this.createStreamWithRetry(
|
|
994
|
+
adapter,
|
|
995
|
+
sessionForAdapter,
|
|
996
|
+
message,
|
|
997
|
+
streamOptions,
|
|
998
|
+
options.backend,
|
|
999
|
+
options.credentials
|
|
1000
|
+
);
|
|
1001
|
+
}
|
|
1002
|
+
/** Stage 7: Apply onEvent middleware pipeline (sequential transform/suppress). */
|
|
1003
|
+
async applyOnEventMiddleware(event, ctx) {
|
|
1004
|
+
let processed = event;
|
|
1005
|
+
for (const mw of this._middleware) {
|
|
1006
|
+
if (mw.onEvent && processed) {
|
|
1007
|
+
processed = await mw.onEvent(processed, ctx);
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1010
|
+
return processed;
|
|
1011
|
+
}
|
|
1012
|
+
/** Stage 8: Finalize accumulator, apply afterReceive middleware, persist assistant message. */
|
|
1013
|
+
async finalizeAssistantMessage(cid, accumulator, ctx) {
|
|
1014
|
+
let assistantMessage = accumulator.finalize();
|
|
1015
|
+
for (const mw of this._middleware) {
|
|
1016
|
+
if (mw.onAfterReceive) {
|
|
1017
|
+
assistantMessage = await mw.onAfterReceive(assistantMessage, ctx);
|
|
1018
|
+
}
|
|
1019
|
+
}
|
|
1020
|
+
await this._sessionStore.appendMessage(cid, assistantMessage);
|
|
1021
|
+
this._notifySessionChange();
|
|
1022
|
+
}
|
|
1023
|
+
/** Stage 9: Error handling — apply onError middleware, transition state. Returns null if suppressed. */
|
|
1024
|
+
async handleSendError(error, cid) {
|
|
1025
|
+
let processedError = error instanceof Error ? error : new Error(String(error));
|
|
1026
|
+
const ctx = {
|
|
1027
|
+
sessionId: cid,
|
|
1028
|
+
signal: this._abortController?.signal ?? new AbortController().signal
|
|
1029
|
+
};
|
|
1030
|
+
for (const mw of this._middleware) {
|
|
1031
|
+
if (mw.onError) {
|
|
1032
|
+
const result = await mw.onError(processedError, ctx);
|
|
1033
|
+
if (result === null) {
|
|
1034
|
+
if (this._state.canTransition("idle")) {
|
|
1035
|
+
this._state.transition("idle");
|
|
1036
|
+
}
|
|
1037
|
+
return null;
|
|
1038
|
+
}
|
|
1039
|
+
processedError = result;
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
1042
|
+
if (this._state.canTransition("error")) {
|
|
1043
|
+
this._state.transition("error");
|
|
1044
|
+
}
|
|
1045
|
+
return processedError;
|
|
1046
|
+
}
|
|
1047
|
+
abort() {
|
|
1048
|
+
this._abortController?.abort("User abort");
|
|
1049
|
+
}
|
|
1050
|
+
// ── Backend / Model ────────────────────────────────────────
|
|
1051
|
+
async listModels(options) {
|
|
871
1052
|
this.assertNotDisposed();
|
|
872
|
-
|
|
1053
|
+
let models = [];
|
|
1054
|
+
const firstAdapter = [...this._adapterPool.values()][0];
|
|
1055
|
+
if (firstAdapter) {
|
|
1056
|
+
try {
|
|
1057
|
+
models = await firstAdapter.listModels();
|
|
1058
|
+
} catch {
|
|
1059
|
+
return [];
|
|
1060
|
+
}
|
|
1061
|
+
} else if (options?.backend && options?.credentials) {
|
|
1062
|
+
try {
|
|
1063
|
+
const adapter = await this.getOrCreateAdapter(options.backend, options.credentials);
|
|
1064
|
+
models = await adapter.listModels();
|
|
1065
|
+
} catch {
|
|
1066
|
+
return [];
|
|
1067
|
+
}
|
|
1068
|
+
}
|
|
1069
|
+
for (const model of models) {
|
|
1070
|
+
if (model.contextWindow != null) {
|
|
1071
|
+
this._modelContextWindows.set(model.id, model.contextWindow);
|
|
1072
|
+
}
|
|
1073
|
+
}
|
|
1074
|
+
return models;
|
|
873
1075
|
}
|
|
874
|
-
async
|
|
1076
|
+
async listBackends() {
|
|
875
1077
|
this.assertNotDisposed();
|
|
876
|
-
|
|
877
|
-
return adapter.listModels();
|
|
1078
|
+
return Object.keys(this._backends).map((name) => ({ name }));
|
|
878
1079
|
}
|
|
879
1080
|
// ── Tools ──────────────────────────────────────────────────
|
|
880
1081
|
get registeredTools() {
|
|
@@ -899,37 +1100,46 @@ var ChatRuntime = class {
|
|
|
899
1100
|
if (idx >= 0) this._middleware.splice(idx, 1);
|
|
900
1101
|
}
|
|
901
1102
|
// ── Context Stats ─────────────────────────────────────────
|
|
902
|
-
getContextStats(sessionId) {
|
|
1103
|
+
async getContextStats(sessionId) {
|
|
903
1104
|
const cid = toChatId(sessionId);
|
|
904
1105
|
return this._contextStats.get(cid) ?? null;
|
|
905
1106
|
}
|
|
906
1107
|
// ── Session Subscription ──────────────────────────────────
|
|
907
1108
|
onSessionChange(callback) {
|
|
908
|
-
this._sessionListeners.add(callback);
|
|
909
|
-
return () => {
|
|
910
|
-
this._sessionListeners.delete(callback);
|
|
911
|
-
};
|
|
1109
|
+
return this._sessionListeners.add(callback);
|
|
912
1110
|
}
|
|
913
1111
|
_notifySessionChange() {
|
|
914
|
-
|
|
915
|
-
try {
|
|
916
|
-
cb();
|
|
917
|
-
} catch {
|
|
918
|
-
}
|
|
919
|
-
}
|
|
1112
|
+
this._sessionListeners.notify();
|
|
920
1113
|
}
|
|
921
1114
|
// ── Private Helpers ────────────────────────────────────────
|
|
922
|
-
async getOrCreateAdapter() {
|
|
923
|
-
|
|
924
|
-
const
|
|
1115
|
+
async getOrCreateAdapter(backend, credentials) {
|
|
1116
|
+
const key = this.getPoolKey(backend, credentials);
|
|
1117
|
+
const existing = this._adapterPool.get(key);
|
|
1118
|
+
if (existing) return existing;
|
|
1119
|
+
for (const [oldKey, oldAdapter] of this._adapterPool) {
|
|
1120
|
+
if (oldKey.startsWith(backend + ":")) {
|
|
1121
|
+
try {
|
|
1122
|
+
await oldAdapter.dispose();
|
|
1123
|
+
} catch {
|
|
1124
|
+
}
|
|
1125
|
+
this._adapterPool.delete(oldKey);
|
|
1126
|
+
}
|
|
1127
|
+
}
|
|
1128
|
+
const factory = this._backends[backend];
|
|
925
1129
|
if (!factory) {
|
|
926
1130
|
throw new ChatError(
|
|
927
|
-
`Backend "${
|
|
1131
|
+
`Backend "${backend}" not found`,
|
|
928
1132
|
{ code: "INVALID_INPUT" /* INVALID_INPUT */ }
|
|
929
1133
|
);
|
|
930
1134
|
}
|
|
931
|
-
|
|
932
|
-
|
|
1135
|
+
const adapter = await factory(credentials);
|
|
1136
|
+
this._adapterPool.set(key, adapter);
|
|
1137
|
+
return adapter;
|
|
1138
|
+
}
|
|
1139
|
+
getPoolKey(backend, credentials) {
|
|
1140
|
+
const token = credentials.accessToken;
|
|
1141
|
+
const hash = token.length > 16 ? token.slice(0, 8) + token.slice(-8) : token;
|
|
1142
|
+
return `${backend}:${hash}`;
|
|
933
1143
|
}
|
|
934
1144
|
/** Wrap each tool's execute to inject ToolContext as 2nd argument */
|
|
935
1145
|
injectToolContext(tools, context) {
|
|
@@ -961,17 +1171,25 @@ var ChatRuntime = class {
|
|
|
961
1171
|
}
|
|
962
1172
|
}
|
|
963
1173
|
/** Get or create adapter with retry on connection errors */
|
|
964
|
-
async getOrCreateAdapterWithRetry() {
|
|
1174
|
+
async getOrCreateAdapterWithRetry(backend, credentials) {
|
|
965
1175
|
const maxAttempts = this._retryConfig?.maxAttempts ?? 1;
|
|
966
1176
|
const delayMs = this._retryConfig?.delayMs ?? 0;
|
|
967
1177
|
let lastError;
|
|
968
1178
|
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
969
1179
|
try {
|
|
970
|
-
return await this.getOrCreateAdapter();
|
|
1180
|
+
return await this.getOrCreateAdapter(backend, credentials);
|
|
971
1181
|
} catch (err) {
|
|
972
1182
|
lastError = err instanceof Error ? err : new Error(String(err));
|
|
973
1183
|
if (attempt < maxAttempts) {
|
|
974
|
-
this.
|
|
1184
|
+
const key = this.getPoolKey(backend, credentials);
|
|
1185
|
+
const old = this._adapterPool.get(key);
|
|
1186
|
+
if (old) {
|
|
1187
|
+
try {
|
|
1188
|
+
await old.dispose();
|
|
1189
|
+
} catch {
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1192
|
+
this._adapterPool.delete(key);
|
|
975
1193
|
await delay(delayMs);
|
|
976
1194
|
}
|
|
977
1195
|
}
|
|
@@ -984,7 +1202,7 @@ var ChatRuntime = class {
|
|
|
984
1202
|
* retries with a fresh adapter. Once first event is received,
|
|
985
1203
|
* the stream is committed (no more retries).
|
|
986
1204
|
*/
|
|
987
|
-
async createStreamWithRetry(adapter, session, message, options) {
|
|
1205
|
+
async createStreamWithRetry(adapter, session, message, options, backend, credentials) {
|
|
988
1206
|
const maxAttempts = this._retryConfig?.maxAttempts ?? 1;
|
|
989
1207
|
const delayMs = this._retryConfig?.delayMs ?? 0;
|
|
990
1208
|
let lastError;
|
|
@@ -1005,13 +1223,14 @@ var ChatRuntime = class {
|
|
|
1005
1223
|
} catch (err) {
|
|
1006
1224
|
lastError = err instanceof Error ? err : new Error(String(err));
|
|
1007
1225
|
if (attempt < maxAttempts) {
|
|
1008
|
-
|
|
1009
|
-
await
|
|
1010
|
-
|
|
1226
|
+
try {
|
|
1227
|
+
await currentAdapter.dispose();
|
|
1228
|
+
} catch {
|
|
1011
1229
|
}
|
|
1012
|
-
this.
|
|
1230
|
+
const key = this.getPoolKey(backend, credentials);
|
|
1231
|
+
this._adapterPool.delete(key);
|
|
1013
1232
|
await delay(delayMs);
|
|
1014
|
-
currentAdapter = await this.getOrCreateAdapter();
|
|
1233
|
+
currentAdapter = await this.getOrCreateAdapter(backend, credentials);
|
|
1015
1234
|
}
|
|
1016
1235
|
}
|
|
1017
1236
|
}
|