Skip to content

Commit 4f6bc94

Browse files
yjp20RobertCraigie
authored andcommitted
fix(tool-runner): fix unhandled promise error for streams
1 parent bfe12c8 commit 4f6bc94

File tree

3 files changed

+34
-0
lines changed

3 files changed

+34
-0
lines changed

src/lib/tools/BetaToolRunner.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,9 @@ export class BetaToolRunner<Stream extends boolean> {
105105
if (params.stream) {
106106
stream = this.client.beta.messages.stream({ ...params }, this.#options);
107107
this.#message = stream.finalMessage();
108+
// Make sure that this promise doesn't throw before we get the option to do something about it.
109+
// Error will be caught when we call await this.#message ultimately
110+
this.#message.catch(() => {});
108111
yield stream as any;
109112
} else {
110113
this.#message = this.client.beta.messages.create({ ...params, stream: false }, this.#options);

src/lib/tools/ToolRunner.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,9 @@ export class BetaToolRunner<Stream extends boolean> {
9797
if (params.stream) {
9898
stream = this.client.beta.messages.stream({ ...params });
9999
this.#message = stream.finalMessage();
100+
// Make sure that this promise doesn't throw before we get the option to do something about it.
101+
// Error will be caught when we call await this.#message ultimately
102+
this.#message.catch(() => {});
100103
yield stream as any;
101104
} else {
102105
this.#message = this.client.beta.messages.create({ ...params, stream: false });

tests/lib/tools/ToolRunner.test.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -505,6 +505,34 @@ describe('ToolRunner', () => {
505505
await expectDone(iterator);
506506
});
507507

508+
it('handles api errors streaming', async () => {
509+
const { runner, handleRequest, handleAssistantMessageStream } = setupTest({
510+
messages: [{ role: 'user', content: 'Test error handling' }],
511+
tools: [weatherTool],
512+
stream: true,
513+
});
514+
515+
handleRequest(async () => {
516+
return new Response(null, {
517+
status: 400,
518+
});
519+
});
520+
const iterator1 = runner[Symbol.asyncIterator]();
521+
await expectEvent(iterator1, async (stream) => {
522+
await expect(stream.finalMessage()).rejects.toThrow('400');
523+
});
524+
await expect(iterator1.next()).rejects.toThrow('400');
525+
await expectDone(iterator1);
526+
527+
// We let you consume the iterator again to continue the conversation when there is an error.
528+
handleAssistantMessageStream(getTextContent());
529+
const iterator2 = runner[Symbol.asyncIterator]();
530+
await expectEvent(iterator2, (message) => {
531+
expect(message.finalMessage()).resolves.toMatchObject({ content: [getTextContent()] });
532+
});
533+
await expectDone(iterator2);
534+
});
535+
508536
it('handles api errors', async () => {
509537
const { runner, handleRequest, handleAssistantMessage } = setupTest({
510538
messages: [{ role: 'user', content: 'Test error handling' }],

0 commit comments

Comments
 (0)