From 92da5861f4fded8f21315cb18dbe620535214000 Mon Sep 17 00:00:00 2001 From: Tuomas Date: Tue, 25 Feb 2025 11:30:50 -0600 Subject: [PATCH 1/3] Fix resetTimeoutOnProgress option not being checked --- src/shared/protocol.ts | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/shared/protocol.ts b/src/shared/protocol.ts index 97213bf0..ccfcdbc1 100644 --- a/src/shared/protocol.ts +++ b/src/shared/protocol.ts @@ -98,6 +98,7 @@ type TimeoutInfo = { startTime: number; timeout: number; maxTotalTimeout?: number; + resetTimeoutOnProgress: boolean; onTimeout: () => void; }; @@ -179,13 +180,15 @@ export abstract class Protocol< messageId: number, timeout: number, maxTotalTimeout: number | undefined, - onTimeout: () => void + onTimeout: () => void, + resetTimeoutOnProgress: boolean = false ) { this._timeoutInfo.set(messageId, { timeoutId: setTimeout(onTimeout, timeout), startTime: Date.now(), timeout, maxTotalTimeout, + resetTimeoutOnProgress, onTimeout }); } @@ -358,7 +361,9 @@ export abstract class Protocol< } const responseHandler = this._responseHandlers.get(messageId); - if (this._timeoutInfo.has(messageId) && responseHandler) { + const timeoutInfo = this._timeoutInfo.get(messageId); + + if (timeoutInfo && responseHandler && timeoutInfo.resetTimeoutOnProgress) { try { this._resetTimeout(messageId); } catch (error) { @@ -520,7 +525,7 @@ export abstract class Protocol< { timeout } )); - this._setupTimeout(messageId, timeout, options?.maxTotalTimeout, timeoutHandler); + this._setupTimeout(messageId, timeout, options?.maxTotalTimeout, timeoutHandler, options?.resetTimeoutOnProgress ?? false); this._transport.send(jsonrpcRequest).catch((error) => { this._cleanupTimeout(messageId); From d63324e34e07cd32feeb919bf3a9565e2051cf90 Mon Sep 17 00:00:00 2001 From: Tuomas Date: Tue, 25 Feb 2025 11:32:24 -0600 Subject: [PATCH 2/3] Fix resetTimeoutOnProgress option not being checked, add test --- src/shared/protocol.test.ts | 38 +++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/shared/protocol.test.ts b/src/shared/protocol.test.ts index 1d037b98..fb5ecd13 100644 --- a/src/shared/protocol.test.ts +++ b/src/shared/protocol.test.ts @@ -71,6 +71,44 @@ describe("protocol tests", () => { jest.useRealTimers(); }); + test("should not reset timeout when resetTimeoutOnProgress is false", async () => { + await protocol.connect(transport); + const request = { method: "example", params: {} }; + const mockSchema: ZodType<{ result: string }> = z.object({ + result: z.string(), + }); + const onProgressMock = jest.fn(); + const requestPromise = protocol.request(request, mockSchema, { + timeout: 1000, + resetTimeoutOnProgress: false, + onprogress: onProgressMock, + }); + + jest.advanceTimersByTime(800); + + if (transport.onmessage) { + transport.onmessage({ + jsonrpc: "2.0", + method: "notifications/progress", + params: { + progressToken: 0, + progress: 50, + total: 100, + }, + }); + } + await Promise.resolve(); + + expect(onProgressMock).toHaveBeenCalledWith({ + progress: 50, + total: 100, + }); + + jest.advanceTimersByTime(201); + + await expect(requestPromise).rejects.toThrow("Request timed out"); + }); + test("should reset timeout when progress notification is received", async () => { await protocol.connect(transport); const request = { method: "example", params: {} }; From 9f5b4bf00d506eb5914e001773143e5408a35133 Mon Sep 17 00:00:00 2001 From: Nathan Arseneau Date: Tue, 1 Apr 2025 19:01:22 -0400 Subject: [PATCH 3/3] Add audio content --- src/types.ts | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/src/types.ts b/src/types.ts index d051d8f7..b9c0ab37 100644 --- a/src/types.ts +++ b/src/types.ts @@ -666,6 +666,23 @@ export const ImageContentSchema = z }) .passthrough(); +/** + * An Audio provided to or from an LLM. + */ +export const AudioContentSchema = z + .object({ + type: z.literal("audio"), + /** + * The base64-encoded audio data. + */ + data: z.string().base64(), + /** + * The MIME type of the audio. Different providers may support different audio types. + */ + mimeType: z.string(), + }) + .passthrough(); + /** * The contents of a resource, embedded into a prompt or tool call result. */ @@ -685,6 +702,7 @@ export const PromptMessageSchema = z content: z.union([ TextContentSchema, ImageContentSchema, + AudioContentSchema, EmbeddedResourceSchema, ]), }) @@ -753,7 +771,7 @@ export const ListToolsResultSchema = PaginatedResultSchema.extend({ */ export const CallToolResultSchema = ResultSchema.extend({ content: z.array( - z.union([TextContentSchema, ImageContentSchema, EmbeddedResourceSchema]), + z.union([TextContentSchema, ImageContentSchema, AudioContentSchema, EmbeddedResourceSchema]), ), isError: z.boolean().default(false).optional(), }); @@ -877,7 +895,7 @@ export const ModelPreferencesSchema = z export const SamplingMessageSchema = z .object({ role: z.enum(["user", "assistant"]), - content: z.union([TextContentSchema, ImageContentSchema]), + content: z.union([TextContentSchema, ImageContentSchema, AudioContentSchema]), }) .passthrough(); @@ -931,6 +949,7 @@ export const CreateMessageResultSchema = ResultSchema.extend({ content: z.discriminatedUnion("type", [ TextContentSchema, ImageContentSchema, + AudioContentSchema ]), }); @@ -1195,6 +1214,7 @@ export type ListPromptsResult = Infer; export type GetPromptRequest = Infer; export type TextContent = Infer; export type ImageContent = Infer; +export type AudioContent = Infer; export type EmbeddedResource = Infer; export type PromptMessage = Infer; export type GetPromptResult = Infer;