diff --git a/libs/sdk-js/src/client.ts b/libs/sdk-js/src/client.ts index 102b1ba95..b66a6f168 100644 --- a/libs/sdk-js/src/client.ts +++ b/libs/sdk-js/src/client.ts @@ -130,6 +130,7 @@ class BaseClient { json?: unknown; params?: Record; timeoutMs?: number | null; + withResponse?: boolean; }, ): [url: URL, init: RequestInit] { const mutatedOptions = { @@ -146,6 +147,10 @@ class BaseClient { delete mutatedOptions.json; } + if (mutatedOptions.withResponse) { + delete mutatedOptions.withResponse; + } + let timeoutSignal: AbortSignal | null = null; if (typeof options?.timeoutMs !== "undefined") { if (options.timeoutMs != null) { @@ -175,6 +180,17 @@ class BaseClient { return [targetUrl, mutatedOptions]; } + protected async fetch( + path: string, + options: RequestInit & { + json?: unknown; + params?: Record; + timeoutMs?: number | null; + signal?: AbortSignal; + withResponse: true; + }, + ): Promise<[T, Response]>; + protected async fetch( path: string, options?: RequestInit & { @@ -182,15 +198,36 @@ class BaseClient { params?: Record; timeoutMs?: number | null; signal?: AbortSignal; + withResponse?: false; }, - ): Promise { + ): Promise; + + protected async fetch( + path: string, + options?: RequestInit & { + json?: unknown; + params?: Record; + timeoutMs?: number | null; + signal?: AbortSignal; + withResponse?: boolean; + }, + ): Promise { const response = await this.asyncCaller.fetch( ...this.prepareFetchOptions(path, options), ); - if (response.status === 202 || response.status === 204) { - return undefined as T; + + const body = (() => { + if (response.status === 202 || response.status === 204) { + return undefined as T; + } + return response.json() as Promise; + })(); + + if (options?.withResponse) { + return [await body, response]; } - return response.json() as T; + + return body; } } @@ -856,6 +893,7 @@ export class RunsClient< const endpoint = threadId == null ? `/runs/stream` : `/threads/${threadId}/runs/stream`; + const response = await this.asyncCaller.fetch( ...this.prepareFetchOptions(endpoint, { method: "POST", @@ -865,6 +903,9 @@ export class RunsClient< }), ); + const contentLocation = response.headers.get("Content-Location"); + if (contentLocation) payload?.onResponse?.(response); + const stream: ReadableStream<{ event: any; data: any }> = ( response.body || new ReadableStream({ start: (ctrl) => ctrl.close() }) ) @@ -905,11 +946,18 @@ export class RunsClient< if_not_exists: payload?.ifNotExists, checkpoint_during: payload?.checkpointDuring, }; - return this.fetch(`/threads/${threadId}/runs`, { + + const [run, response] = await this.fetch(`/threads/${threadId}/runs`, { method: "POST", json, signal: payload?.signal, + withResponse: true, }); + + const contentLocation = response.headers.get("Content-Location"); + if (contentLocation) payload?.onResponse?.(response); + + return run; } /** @@ -980,27 +1028,30 @@ export class RunsClient< }; const endpoint = threadId == null ? `/runs/wait` : `/threads/${threadId}/runs/wait`; - const response = await this.fetch(endpoint, { + const [run, response] = await this.fetch(endpoint, { method: "POST", json, timeoutMs: null, signal: payload?.signal, + withResponse: true, }); + + const contentLocation = response.headers.get("Content-Location"); + if (contentLocation) payload?.onResponse?.(response); + const raiseError = payload?.raiseError !== undefined ? payload.raiseError : true; if ( raiseError && - "__error__" in response && - typeof response.__error__ === "object" && - response.__error__ && - "error" in response.__error__ && - "message" in response.__error__ + "__error__" in run && + typeof run.__error__ === "object" && + run.__error__ && + "error" in run.__error__ && + "message" in run.__error__ ) { - throw new Error( - `${response.__error__?.error}: ${response.__error__?.message}`, - ); + throw new Error(`${run.__error__?.error}: ${run.__error__?.message}`); } - return response; + return run; } /** diff --git a/libs/sdk-js/src/types.ts b/libs/sdk-js/src/types.ts index 9f30adf4c..4cc4733e5 100644 --- a/libs/sdk-js/src/types.ts +++ b/libs/sdk-js/src/types.ts @@ -135,6 +135,12 @@ interface RunsInvokePayload { * One or more commands to invoke the graph with. */ command?: Command; + + /** + * Callback when request is completed. + * Useful when obtaining headers from the response. + */ + onResponse?: (response: Response) => void; } export interface RunsStreamPayload<