@ai-sdk/xai
Advanced tools
+3
-3
| { | ||
| "name": "@ai-sdk/xai", | ||
| "version": "4.0.21", | ||
| "version": "4.0.22", | ||
| "type": "module", | ||
@@ -32,5 +32,5 @@ "license": "Apache-2.0", | ||
| "dependencies": { | ||
| "@ai-sdk/openai-compatible": "3.0.17", | ||
| "@ai-sdk/provider": "4.0.4", | ||
| "@ai-sdk/provider-utils": "5.0.14", | ||
| "@ai-sdk/openai-compatible": "3.0.16" | ||
| "@ai-sdk/provider-utils": "5.0.15" | ||
| }, | ||
@@ -37,0 +37,0 @@ "devDependencies": { |
| import { | ||
| AISDKError, | ||
| APICallError, | ||
| type Experimental_VideoModelV4, | ||
@@ -8,3 +9,2 @@ type Experimental_VideoModelV4File, | ||
| import { | ||
| cancelResponseBody, | ||
| combineHeaders, | ||
@@ -19,2 +19,3 @@ convertUint8ArrayToBase64, | ||
| postJsonToApi, | ||
| safeParseJSON, | ||
| type FetchFunction, | ||
@@ -554,12 +555,76 @@ type ResponseHandler, | ||
| // Generous bound for a `{status, progress}` payload of ~50 bytes. | ||
| const MAX_PENDING_BODY_BYTES = 1024 * 1024; | ||
| const textDecoder = new TextDecoder(); | ||
| // Bounded replacement for `response.text()`. Throws on overflow without | ||
| // cancelling the body: cancelling a tee branch neither settles nor releases | ||
| // the underlying source while the sibling branch is live. | ||
| async function readPendingBody({ | ||
| response, | ||
| url, | ||
| requestBodyValues, | ||
| }: Parameters<ResponseHandler<unknown>>[0]): Promise<string> { | ||
| if (response.body == null) { | ||
| return ''; | ||
| } | ||
| const reader = response.body.getReader(); | ||
| const chunks: Uint8Array[] = []; | ||
| let totalBytes = 0; | ||
| try { | ||
| while (true) { | ||
| const { done, value } = await reader.read(); | ||
| if (done) break; | ||
| totalBytes += value.length; | ||
| if (totalBytes > MAX_PENDING_BODY_BYTES) { | ||
| throw new APICallError({ | ||
| message: `xAI video status response exceeded ${MAX_PENDING_BODY_BYTES} bytes`, | ||
| url, | ||
| requestBodyValues, | ||
| statusCode: response.status, | ||
| responseHeaders: extractResponseHeaders(response), | ||
| }); | ||
| } | ||
| chunks.push(value); | ||
| } | ||
| } finally { | ||
| reader.releaseLock(); | ||
| } | ||
| const merged = new Uint8Array(totalBytes); | ||
| let offset = 0; | ||
| for (const chunk of chunks) { | ||
| merged.set(chunk, offset); | ||
| offset += chunk.length; | ||
| } | ||
| return textDecoder.decode(merged); | ||
| } | ||
| const xaiVideoStatusResponseHandler: ResponseHandler< | ||
| z.infer<typeof xaiVideoStatusResponseSchema> | ||
| > = async options => { | ||
| // xAI answers 202 while a generation is still running, sometimes with an | ||
| // empty body. Read it rather than cancelling: `body.cancel()` never settles | ||
| // on a tee branch, which `Response.clone()` in fetch instrumentation creates. | ||
| if (options.response.status === 202) { | ||
| const responseHeaders = extractResponseHeaders(options.response); | ||
| await cancelResponseBody(options.response); | ||
| const text = await readPendingBody(options); | ||
| if (text.trim().length === 0) { | ||
| return { responseHeaders, value: { status: 'pending' } }; | ||
| } | ||
| const parsed = await safeParseJSON({ | ||
| text, | ||
| schema: xaiVideoStatusResponseSchema, | ||
| }); | ||
| return { | ||
| responseHeaders, | ||
| value: { status: 'pending' }, | ||
| value: parsed.success ? parsed.value : { status: 'pending' }, | ||
| }; | ||
@@ -566,0 +631,0 @@ } |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
813467
0.84%11613
0.89%+ Added
+ Added
+ Added
- Removed
- Removed