Skip to content

Commit 9694aa4

Browse files
committed
fix LLM stream
1 parent 5c04e0b commit 9694aa4

2 files changed

Lines changed: 20 additions & 1 deletion

File tree

agents/src/llm/fallback_adapter.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,11 @@ class FallbackLLMStream extends LLMStream {
209209
extraKwargs: this.extraKwargs,
210210
});
211211

212+
// Suppress unhandled 'error' events from the child LLM — error detection
213+
// is done via stream._runError to avoid cross-request contamination.
214+
const noop = () => {};
215+
llm.on('error', noop);
216+
212217
try {
213218
let shouldSetCurrent = !checkRecovery;
214219
for await (const chunk of stream) {
@@ -218,6 +223,10 @@ class FallbackLLMStream extends LLMStream {
218223
}
219224
yield chunk;
220225
}
226+
227+
if (stream._runError) {
228+
throw stream._runError;
229+
}
221230
} catch (error) {
222231
if (error instanceof APIError) {
223232
if (checkRecovery) {
@@ -245,6 +254,8 @@ class FallbackLLMStream extends LLMStream {
245254
this._log.error({ llm: llm.label(), error }, 'unexpected error, switching to next LLM');
246255
}
247256
throw error;
257+
} finally {
258+
llm.off('error', noop);
248259
}
249260
}
250261

agents/src/llm/llm.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,8 @@ export abstract class LLMStream implements AsyncIterableIterator<ChatChunk> {
115115
protected abortController = new AbortController();
116116
protected _connOptions: APIConnectOptions;
117117
protected logger = log();
118+
/** @internal – Captured when run() fails so callers can inspect after iteration ends. */
119+
_runError?: Error;
118120

119121
#llm: LLM;
120122
#chatCtx: ChatContext;
@@ -148,7 +150,13 @@ export abstract class LLMStream implements AsyncIterableIterator<ChatChunk> {
148150
// is run **after** the constructor has finished. Otherwise we get
149151
// runtime error when trying to access class variables in the
150152
// `run` method.
151-
startSoon(() => this.mainTask().finally(() => this.queue.close()));
153+
startSoon(() =>
154+
this.mainTask()
155+
.catch((e) => {
156+
this._runError = e instanceof Error ? e : new Error(String(e));
157+
})
158+
.finally(() => this.queue.close()),
159+
);
152160
}
153161

154162
private _mainTaskImpl = async (span: Span) => {

0 commit comments

Comments
 (0)