@ai-sdk/openai 4.0.51 → 4.0.52

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-sdk/openai",
3
- "version": "4.0.51",
3
+ "version": "4.0.52",
4
4
  "type": "module",
5
5
  "license": "Apache-2.0",
6
6
  "sideEffects": false,
@@ -35,8 +35,8 @@
35
35
  }
36
36
  },
37
37
  "dependencies": {
38
- "@ai-sdk/provider": "4.0.8",
39
- "@ai-sdk/provider-utils": "5.0.33"
38
+ "@ai-sdk/provider": "4.0.9",
39
+ "@ai-sdk/provider-utils": "5.0.34"
40
40
  },
41
41
  "devDependencies": {
42
42
  "@ai-sdk/test-server": "2.0.1",
@@ -71,12 +71,14 @@ async function convertFunctionToolResultOutput({
71
71
  output,
72
72
  toolName,
73
73
  outputSchemaToolNames,
74
+ promptCacheBreakpoint,
74
75
  providerOptionsName,
75
76
  warnings,
76
77
  }: {
77
78
  output: LanguageModelV4ToolResultOutput;
78
79
  toolName: string;
79
80
  outputSchemaToolNames: Set<string> | undefined;
81
+ promptCacheBreakpoint?: OpenAIPromptCacheBreakpoint;
80
82
  providerOptionsName: string;
81
83
  warnings: Array<SharedV4Warning>;
82
84
  }): Promise<OpenAIResponsesFunctionCallOutput['output']> {
@@ -84,18 +86,34 @@ async function convertFunctionToolResultOutput({
84
86
  // parses the contents of that string as JSON. Text-like results therefore
85
87
  // need JSON.stringify to become valid JSON string literals.
86
88
  const hasOutputSchema = outputSchemaToolNames?.has(toolName);
89
+ const convertScalarOutput = (
90
+ value: string,
91
+ ): OpenAIResponsesFunctionCallOutput['output'] =>
92
+ promptCacheBreakpoint == null
93
+ ? value
94
+ : [
95
+ {
96
+ type: 'input_text',
97
+ text: value,
98
+ prompt_cache_breakpoint: promptCacheBreakpoint,
99
+ },
100
+ ];
87
101
 
88
102
  switch (output.type) {
89
103
  case 'text':
90
104
  case 'error-text':
91
- return hasOutputSchema ? JSON.stringify(output.value) : output.value;
105
+ return convertScalarOutput(
106
+ hasOutputSchema ? JSON.stringify(output.value) : output.value,
107
+ );
92
108
  case 'execution-denied': {
93
109
  const reason = output.reason ?? 'Tool call execution denied.';
94
- return hasOutputSchema ? JSON.stringify(reason) : reason;
110
+ return convertScalarOutput(
111
+ hasOutputSchema ? JSON.stringify(reason) : reason,
112
+ );
95
113
  }
96
114
  case 'json':
97
115
  case 'error-json':
98
- return JSON.stringify(output.value);
116
+ return convertScalarOutput(JSON.stringify(output.value));
99
117
  case 'content':
100
118
  return output.value
101
119
  .map(item => {
@@ -289,6 +307,24 @@ function getPromptCacheBreakpoint(
289
307
  | undefined;
290
308
  }
291
309
 
310
+ function getScalarToolResultPromptCacheBreakpoint({
311
+ output,
312
+ toolResultProviderOptions,
313
+ providerOptionsName,
314
+ }: {
315
+ output: LanguageModelV4ToolResultOutput;
316
+ toolResultProviderOptions: SharedV4ProviderOptions | undefined;
317
+ providerOptionsName: string;
318
+ }): OpenAIPromptCacheBreakpoint | undefined {
319
+ return output.type === 'content'
320
+ ? undefined
321
+ : (getPromptCacheBreakpoint(output.providerOptions, providerOptionsName) ??
322
+ getPromptCacheBreakpoint(
323
+ toolResultProviderOptions,
324
+ providerOptionsName,
325
+ ));
326
+ }
327
+
292
328
  /**
293
329
  * This is soft-deprecated. Use provider references instead. Kept for backward compatibility
294
330
  * with the `fileIdPrefixes` option.
@@ -1218,15 +1254,31 @@ export async function convertToOpenAIResponsesInput({
1218
1254
  );
1219
1255
 
1220
1256
  const toolOutputs = await Promise.all(
1221
- parallelToolResultGroup.results.map(async result =>
1222
- convertFunctionToolResultOutput({
1223
- output: result.output,
1224
- toolName: result.toolName,
1225
- outputSchemaToolNames,
1226
- providerOptionsName,
1227
- warnings,
1228
- }),
1229
- ),
1257
+ parallelToolResultGroup.results.map(async result => {
1258
+ const promptCacheBreakpoint =
1259
+ getScalarToolResultPromptCacheBreakpoint({
1260
+ output: result.output,
1261
+ toolResultProviderOptions: result.providerOptions,
1262
+ providerOptionsName,
1263
+ });
1264
+
1265
+ return {
1266
+ output: await convertFunctionToolResultOutput({
1267
+ output: result.output,
1268
+ toolName: result.toolName,
1269
+ outputSchemaToolNames,
1270
+ providerOptionsName,
1271
+ warnings,
1272
+ }),
1273
+ promptCacheBreakpoint,
1274
+ };
1275
+ }),
1276
+ );
1277
+ const serializedToolOutputs = toolOutputs.map(({ output }) =>
1278
+ typeof output === 'string' ? output : JSON.stringify(output),
1279
+ );
1280
+ const hasPromptCacheBreakpoint = toolOutputs.some(
1281
+ ({ promptCacheBreakpoint }) => promptCacheBreakpoint != null,
1230
1282
  );
1231
1283
 
1232
1284
  input.push({
@@ -1234,13 +1286,16 @@ export async function convertToOpenAIResponsesInput({
1234
1286
  call_id: parallelToolResultGroup.metadata.toolCallId,
1235
1287
  // The internal wrapper returns one output containing the child
1236
1288
  // results in the same order as the original tool_uses array.
1237
- output: toolOutputs
1238
- .map(output =>
1239
- typeof output === 'string'
1240
- ? output
1241
- : JSON.stringify(output),
1242
- )
1243
- .join('\n'),
1289
+ output: hasPromptCacheBreakpoint
1290
+ ? serializedToolOutputs.map((text, index) => ({
1291
+ type: 'input_text',
1292
+ text: index === 0 ? text : `\n${text}`,
1293
+ ...(toolOutputs[index].promptCacheBreakpoint != null && {
1294
+ prompt_cache_breakpoint:
1295
+ toolOutputs[index].promptCacheBreakpoint,
1296
+ }),
1297
+ }))
1298
+ : serializedToolOutputs.join('\n'),
1244
1299
  });
1245
1300
  }
1246
1301
  continue;
@@ -1374,18 +1429,38 @@ export async function convertToOpenAIResponsesInput({
1374
1429
  }
1375
1430
 
1376
1431
  if (customProviderToolNames?.has(resolvedToolName)) {
1432
+ const promptCacheBreakpoint =
1433
+ getScalarToolResultPromptCacheBreakpoint({
1434
+ output,
1435
+ toolResultProviderOptions: part.providerOptions,
1436
+ providerOptionsName,
1437
+ });
1438
+ const convertScalarOutput = (
1439
+ value: string,
1440
+ ): OpenAIResponsesCustomToolCallOutput['output'] =>
1441
+ promptCacheBreakpoint == null
1442
+ ? value
1443
+ : [
1444
+ {
1445
+ type: 'input_text',
1446
+ text: value,
1447
+ prompt_cache_breakpoint: promptCacheBreakpoint,
1448
+ },
1449
+ ];
1377
1450
  let outputValue: OpenAIResponsesCustomToolCallOutput['output'];
1378
1451
  switch (output.type) {
1379
1452
  case 'text':
1380
1453
  case 'error-text':
1381
- outputValue = output.value;
1454
+ outputValue = convertScalarOutput(output.value);
1382
1455
  break;
1383
1456
  case 'execution-denied':
1384
- outputValue = output.reason ?? 'Tool call execution denied.';
1457
+ outputValue = convertScalarOutput(
1458
+ output.reason ?? 'Tool call execution denied.',
1459
+ );
1385
1460
  break;
1386
1461
  case 'json':
1387
1462
  case 'error-json':
1388
- outputValue = JSON.stringify(output.value);
1463
+ outputValue = convertScalarOutput(JSON.stringify(output.value));
1389
1464
  break;
1390
1465
  case 'content':
1391
1466
  outputValue = output.value
@@ -1484,6 +1559,11 @@ export async function convertToOpenAIResponsesInput({
1484
1559
  output,
1485
1560
  toolName: part.toolName,
1486
1561
  outputSchemaToolNames,
1562
+ promptCacheBreakpoint: getScalarToolResultPromptCacheBreakpoint({
1563
+ output,
1564
+ toolResultProviderOptions: part.providerOptions,
1565
+ providerOptionsName,
1566
+ }),
1487
1567
  providerOptionsName,
1488
1568
  warnings,
1489
1569
  });