@ai-sdk/openai 4.0.24 → 4.0.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,26 @@
1
1
  # @ai-sdk/openai
2
2
 
3
+ ## 4.0.26
4
+
5
+ ### Patch Changes
6
+
7
+ - f7c4a38: Serialize file upload expiry settings in the multipart field shape accepted by OpenAI.
8
+ - Updated dependencies [fa95504]
9
+ - @ai-sdk/provider-utils@5.0.17
10
+
11
+ ## 4.0.25
12
+
13
+ ### Patch Changes
14
+
15
+ - beaecb3: fix(provider/openai): resolve responses doStream at response.in_progress instead of first output token
16
+
17
+ The early-stream-error peek treated `response.in_progress` as an unknown chunk, so `doStream` did not resolve until the first output item arrived — delaying stream availability (and downstream TTFB for proxies/gateways) by the model's full time-to-first-token. `response.in_progress` is now modeled in the chunk schema and marks the request as accepted: the peek keeps watching for error frames for a short grace window (50ms) so quota/rate-limit errors flushed alongside `response.in_progress` still throw as retryable `APICallError`s, while healthy streams become available right after upstream acknowledges the request.
18
+
19
+ - b192878: feat: add experimental_toolCaller routing to generateText for code mode
20
+ - Updated dependencies [d8210b6]
21
+ - Updated dependencies [b192878]
22
+ - @ai-sdk/provider-utils@5.0.16
23
+
3
24
  ## 4.0.24
4
25
 
5
26
  ### Patch Changes
package/dist/index.d.ts CHANGED
@@ -311,6 +311,14 @@ declare const openaiResponsesChunkSchema: _ai_sdk_provider_utils.LazySchema<{
311
311
  model: string;
312
312
  service_tier?: string | null | undefined;
313
313
  };
314
+ } | {
315
+ type: "response.in_progress";
316
+ response: {
317
+ id: string;
318
+ created_at: number;
319
+ model: string;
320
+ service_tier?: string | null | undefined;
321
+ };
314
322
  } | {
315
323
  type: "response.output_item.added";
316
324
  output_index: number;
@@ -1300,13 +1308,13 @@ declare const openaiTools: {
1300
1308
  * Programmatic Tool Calling lets OpenAI Responses models write and execute
1301
1309
  * JavaScript that orchestrates eligible tools.
1302
1310
  */
1303
- programmaticToolCalling: () => _ai_sdk_provider_utils.ProviderExecutedTool<{
1311
+ programmaticToolCalling: () => _ai_sdk_provider_utils.Experimental_ToolCallerTool<_ai_sdk_provider_utils.ProviderExecutedTool<{
1304
1312
  code: string;
1305
1313
  fingerprint: string;
1306
1314
  }, {
1307
1315
  result: string;
1308
1316
  status: "completed" | "incomplete";
1309
- }, {}>;
1317
+ }, {}>>;
1310
1318
  /**
1311
1319
  * Tool search allows the model to dynamically search for and load deferred
1312
1320
  * tools into the model's context as needed. This helps reduce overall token
package/dist/index.js CHANGED
@@ -83,15 +83,28 @@ async function throwIfOpenAIStreamErrorBeforeOutput({
83
83
  stream,
84
84
  getError,
85
85
  isOutputChunk,
86
+ isAcceptedChunk,
87
+ acceptedGraceMs = 50,
86
88
  url,
87
89
  requestBodyValues,
88
90
  responseHeaders
89
91
  }) {
90
92
  const [streamForEarlyError, streamForConsumer] = stream.tee();
91
93
  const reader = streamForEarlyError.getReader();
94
+ let drainAfterError = false;
92
95
  try {
96
+ let accepted = false;
93
97
  while (true) {
94
- const result = await reader.read();
98
+ let result;
99
+ if (accepted) {
100
+ const raced = await raceWithTimeout(reader.read(), acceptedGraceMs);
101
+ if (raced.timedOut) {
102
+ return streamForConsumer;
103
+ }
104
+ result = raced.value;
105
+ } else {
106
+ result = await reader.read();
107
+ }
95
108
  if (result.done) {
96
109
  return streamForConsumer;
97
110
  }
@@ -101,7 +114,10 @@ async function throwIfOpenAIStreamErrorBeforeOutput({
101
114
  }
102
115
  const errorFrame = getError(chunk.value);
103
116
  if (errorFrame != null) {
104
- streamForConsumer.cancel().catch(() => {
117
+ drainAfterError = true;
118
+ drainReader(reader).catch(() => {
119
+ });
120
+ drainReader(streamForConsumer.getReader()).catch(() => {
105
121
  });
106
122
  throw createOpenAIStreamError({
107
123
  frame: errorFrame,
@@ -113,13 +129,46 @@ async function throwIfOpenAIStreamErrorBeforeOutput({
113
129
  if (isOutputChunk(chunk.value)) {
114
130
  return streamForConsumer;
115
131
  }
132
+ if (!accepted && (isAcceptedChunk == null ? void 0 : isAcceptedChunk(chunk.value)) === true) {
133
+ accepted = true;
134
+ }
116
135
  }
117
136
  } finally {
118
- reader.cancel().catch(() => {
119
- });
137
+ if (!drainAfterError) {
138
+ reader.cancel().catch(() => {
139
+ });
140
+ reader.releaseLock();
141
+ }
142
+ }
143
+ }
144
+ async function drainReader(reader) {
145
+ try {
146
+ while (!(await reader.read()).done) {
147
+ }
148
+ } catch (e) {
149
+ } finally {
120
150
  reader.releaseLock();
121
151
  }
122
152
  }
153
+ async function raceWithTimeout(promise, timeoutMs) {
154
+ let timer;
155
+ const wrapped = promise.then((value) => ({ timedOut: false, value }));
156
+ try {
157
+ const raced = await Promise.race([
158
+ wrapped,
159
+ new Promise((resolve) => {
160
+ timer = setTimeout(() => resolve({ timedOut: true }), timeoutMs);
161
+ })
162
+ ]);
163
+ if (raced.timedOut) {
164
+ wrapped.catch(() => {
165
+ });
166
+ }
167
+ return raced;
168
+ } finally {
169
+ clearTimeout(timer);
170
+ }
171
+ }
123
172
  function createOpenAIStreamError({
124
173
  frame,
125
174
  url,
@@ -2065,7 +2114,11 @@ var OpenAIFiles = class {
2065
2114
  }
2066
2115
  formData.append("purpose", (_a = openaiOptions == null ? void 0 : openaiOptions.purpose) != null ? _a : "assistants");
2067
2116
  if ((openaiOptions == null ? void 0 : openaiOptions.expiresAfter) != null) {
2068
- formData.append("expires_after", String(openaiOptions.expiresAfter));
2117
+ formData.append("expires_after[anchor]", "created_at");
2118
+ formData.append(
2119
+ "expires_after[seconds]",
2120
+ String(openaiOptions.expiresAfter)
2121
+ );
2069
2122
  }
2070
2123
  const { value: response } = await postFormDataToApi({
2071
2124
  url: `${this.config.baseURL}/files`,
@@ -3114,6 +3167,7 @@ var mcp = (args) => mcpToolFactory(args);
3114
3167
  // src/tool/programmatic-tool-calling.ts
3115
3168
  import {
3116
3169
  createProviderExecutedToolFactory as createProviderExecutedToolFactory7,
3170
+ experimental_toolCaller,
3117
3171
  lazySchema as lazySchema23,
3118
3172
  zodSchema as zodSchema23
3119
3173
  } from "@ai-sdk/provider-utils";
@@ -3140,7 +3194,25 @@ var programmaticToolCallingFactory = createProviderExecutedToolFactory7({
3140
3194
  outputSchema: programmaticToolCallingOutputSchema,
3141
3195
  supportsDeferredResults: true
3142
3196
  });
3143
- var programmaticToolCalling = () => programmaticToolCallingFactory({});
3197
+ var programmaticToolCalling = () => experimental_toolCaller(programmaticToolCallingFactory({}), {
3198
+ type: "provider",
3199
+ prepareProviderOptions: (providerOptions) => {
3200
+ var _a;
3201
+ const openaiOptions = providerOptions == null ? void 0 : providerOptions.openai;
3202
+ return {
3203
+ ...providerOptions,
3204
+ openai: {
3205
+ ...openaiOptions,
3206
+ allowedCallers: [
3207
+ .../* @__PURE__ */ new Set([
3208
+ ...(_a = openaiOptions == null ? void 0 : openaiOptions.allowedCallers) != null ? _a : [],
3209
+ "programmatic"
3210
+ ])
3211
+ ]
3212
+ }
3213
+ };
3214
+ }
3215
+ });
3144
3216
 
3145
3217
  // src/openai-tools.ts
3146
3218
  var openaiTools = {
@@ -4870,6 +4942,15 @@ var openaiResponsesChunkSchema = lazySchema24(
4870
4942
  service_tier: z26.string().nullish()
4871
4943
  })
4872
4944
  }),
4945
+ z26.object({
4946
+ type: z26.literal("response.in_progress"),
4947
+ response: z26.object({
4948
+ id: z26.string(),
4949
+ created_at: z26.number(),
4950
+ model: z26.string(),
4951
+ service_tier: z26.string().nullish()
4952
+ })
4953
+ }),
4873
4954
  z26.object({
4874
4955
  type: z26.literal("response.output_item.added"),
4875
4956
  output_index: z26.number(),
@@ -7275,6 +7356,7 @@ var OpenAIResponsesLanguageModel = class _OpenAIResponsesLanguageModel {
7275
7356
  stream: response,
7276
7357
  getError: (chunk) => isErrorChunk(chunk) || isResponseFailedChunk(chunk) && chunk.response.error != null ? chunk : void 0,
7277
7358
  isOutputChunk: isResponseOutputChunk,
7359
+ isAcceptedChunk: isResponseInProgressChunk,
7278
7360
  url,
7279
7361
  requestBodyValues: body,
7280
7362
  responseHeaders
@@ -8316,8 +8398,11 @@ function isResponseAnnotationAddedChunk(chunk) {
8316
8398
  function isErrorChunk(chunk) {
8317
8399
  return chunk.type === "error";
8318
8400
  }
8401
+ function isResponseInProgressChunk(chunk) {
8402
+ return chunk.type === "response.in_progress";
8403
+ }
8319
8404
  function isResponseOutputChunk(chunk) {
8320
- return !(chunk.type === "response.created" || chunk.type === "response.failed" || chunk.type === "error" || chunk.type === "unknown_chunk");
8405
+ return !(chunk.type === "response.created" || chunk.type === "response.in_progress" || chunk.type === "response.failed" || chunk.type === "error" || chunk.type === "unknown_chunk");
8321
8406
  }
8322
8407
  function mapWebSearchOutput(action) {
8323
8408
  var _a;
@@ -9422,7 +9507,7 @@ var OpenAISkills = class {
9422
9507
  };
9423
9508
 
9424
9509
  // src/version.ts
9425
- var VERSION = true ? "4.0.24" : "0.0.0-test";
9510
+ var VERSION = true ? "4.0.26" : "0.0.0-test";
9426
9511
 
9427
9512
  // src/openai-provider.ts
9428
9513
  function createOpenAI(options = {}) {