@ai-sdk/openai 4.0.94 → 4.0.96
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 +19 -0
- package/dist/index.d.ts +68 -50
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +33 -13
- package/dist/index.js.map +1 -1
- package/dist/internal/index.d.ts +18 -4
- package/dist/internal/index.d.ts.map +1 -1
- package/dist/internal/index.js +30 -12
- package/dist/internal/index.js.map +1 -1
- package/docs/03-openai.mdx +117 -6
- package/package.json +3 -3
- package/src/index.ts +1 -0
- package/src/openai-tools.ts +2 -0
- package/src/responses/convert-to-openai-responses-input.ts +17 -1
- package/src/responses/openai-responses-api.ts +6 -0
- package/src/responses/openai-responses-language-model-options.ts +23 -0
- package/src/responses/openai-responses-language-model.ts +2 -15
- package/src/responses/openai-responses-prepare-tools.ts +27 -0
package/docs/03-openai.mdx
CHANGED
|
@@ -720,6 +720,12 @@ the operation is idempotent, and set explicit step limits.
|
|
|
720
720
|
|
|
721
721
|
The OpenAI responses API supports web search through the `openai.tools.webSearch` tool.
|
|
722
722
|
|
|
723
|
+
<Note>
|
|
724
|
+
`openai.tools.webSearchPreview()` is deprecated. Use
|
|
725
|
+
`openai.tools.webSearch()` instead. The existing `searchContextSize` and
|
|
726
|
+
`userLocation` options are supported by both tools.
|
|
727
|
+
</Note>
|
|
728
|
+
|
|
723
729
|
```ts
|
|
724
730
|
const result = await generateText({
|
|
725
731
|
model: openai('gpt-6-astra'),
|
|
@@ -1538,6 +1544,111 @@ In client mode, the flow spans two steps:
|
|
|
1538
1544
|
|
|
1539
1545
|
For more details, see the [OpenAI Tool Search documentation](https://platform.openai.com/docs/guides/tools-tool-search).
|
|
1540
1546
|
|
|
1547
|
+
##### Load tools after an ordinary tool result
|
|
1548
|
+
|
|
1549
|
+
When your own search function discovers tools, attach
|
|
1550
|
+
`providerOptions.openai.additionalTools` to its tool-result part. The Responses
|
|
1551
|
+
provider preserves the ordinary result and emits an `additional_tools` item
|
|
1552
|
+
immediately after it. Replaying the same messages preserves that insertion point.
|
|
1553
|
+
|
|
1554
|
+
```ts
|
|
1555
|
+
import {
|
|
1556
|
+
openai,
|
|
1557
|
+
type OpenAIResponsesToolResultOptions,
|
|
1558
|
+
type OpenAIToolOptions,
|
|
1559
|
+
} from '@ai-sdk/openai';
|
|
1560
|
+
import { generateText, tool, type ModelMessage } from 'ai';
|
|
1561
|
+
import { z } from 'zod/v4';
|
|
1562
|
+
|
|
1563
|
+
const messages: ModelMessage[] = [
|
|
1564
|
+
{ role: 'user', content: 'Find Linear and list my issues.' },
|
|
1565
|
+
{
|
|
1566
|
+
role: 'assistant',
|
|
1567
|
+
content: [
|
|
1568
|
+
{
|
|
1569
|
+
type: 'tool-call',
|
|
1570
|
+
toolCallId: 'search-1',
|
|
1571
|
+
toolName: 'search',
|
|
1572
|
+
input: {},
|
|
1573
|
+
},
|
|
1574
|
+
],
|
|
1575
|
+
},
|
|
1576
|
+
{
|
|
1577
|
+
role: 'tool',
|
|
1578
|
+
content: [
|
|
1579
|
+
{
|
|
1580
|
+
type: 'tool-result',
|
|
1581
|
+
toolCallId: 'search-1',
|
|
1582
|
+
toolName: 'search',
|
|
1583
|
+
output: {
|
|
1584
|
+
type: 'json',
|
|
1585
|
+
value: { connection: 'linear', connected: true },
|
|
1586
|
+
},
|
|
1587
|
+
providerOptions: {
|
|
1588
|
+
openai: {
|
|
1589
|
+
additionalTools: [
|
|
1590
|
+
{
|
|
1591
|
+
type: 'function',
|
|
1592
|
+
name: 'list_issues',
|
|
1593
|
+
description: 'List Linear issues.',
|
|
1594
|
+
parameters: {
|
|
1595
|
+
type: 'object',
|
|
1596
|
+
properties: {},
|
|
1597
|
+
additionalProperties: false,
|
|
1598
|
+
},
|
|
1599
|
+
},
|
|
1600
|
+
],
|
|
1601
|
+
} satisfies OpenAIResponsesToolResultOptions,
|
|
1602
|
+
},
|
|
1603
|
+
},
|
|
1604
|
+
],
|
|
1605
|
+
},
|
|
1606
|
+
];
|
|
1607
|
+
|
|
1608
|
+
const tools = {
|
|
1609
|
+
search: tool({ inputSchema: z.object({}) }),
|
|
1610
|
+
list_issues: tool({
|
|
1611
|
+
inputSchema: z.object({}),
|
|
1612
|
+
execute: async () => ({ issues: ['Example issue'] }),
|
|
1613
|
+
providerOptions: {
|
|
1614
|
+
openai: { omitFromRequestTools: true } satisfies OpenAIToolOptions,
|
|
1615
|
+
},
|
|
1616
|
+
}),
|
|
1617
|
+
};
|
|
1618
|
+
|
|
1619
|
+
const result = await generateText({
|
|
1620
|
+
model: openai.responses('gpt-5.4'),
|
|
1621
|
+
tools,
|
|
1622
|
+
messages,
|
|
1623
|
+
providerOptions: { openai: { store: false } },
|
|
1624
|
+
});
|
|
1625
|
+
|
|
1626
|
+
// Keep the original messages, including the additionalTools option, on replay.
|
|
1627
|
+
messages.push(...result.responseMessages);
|
|
1628
|
+
messages.push({ role: 'user', content: 'List my issues again.' });
|
|
1629
|
+
await generateText({
|
|
1630
|
+
model: openai.responses('gpt-5.4'),
|
|
1631
|
+
tools,
|
|
1632
|
+
messages,
|
|
1633
|
+
providerOptions: { openai: { store: false } },
|
|
1634
|
+
});
|
|
1635
|
+
```
|
|
1636
|
+
|
|
1637
|
+
`additionalTools` currently accepts function definitions with `type: 'function'`,
|
|
1638
|
+
`name`, `parameters`, and optional `description` and `strict`. An empty array emits
|
|
1639
|
+
no item. These are OpenAI-format definitions; keep their names and schemas aligned
|
|
1640
|
+
with the SDK tools used for local validation and execution.
|
|
1641
|
+
|
|
1642
|
+
`omitFromRequestTools: true` omits only the function's top-level Responses tool
|
|
1643
|
+
definition. Keep the function in `tools` and, if you use `activeTools`, include it
|
|
1644
|
+
there too: inactive tools cannot be executed. Use automatic tool choice for these
|
|
1645
|
+
functions; OpenAI cannot force or allow-list a tool absent from the top-level list.
|
|
1646
|
+
|
|
1647
|
+
Both `generateText` and `streamText` support this representation. For streaming,
|
|
1648
|
+
append `await result.responseMessages` when replaying the conversation. This
|
|
1649
|
+
support is for direct `@ai-sdk/openai` Responses requests; AI Gateway support is
|
|
1650
|
+
not guaranteed by this provider option.
|
|
1651
|
+
|
|
1541
1652
|
#### Custom Tool
|
|
1542
1653
|
|
|
1543
1654
|
The OpenAI Responses API supports
|
|
@@ -1657,12 +1768,12 @@ canonical name — two MCP servers, for example — that name is ambiguous, so i
|
|
|
1657
1768
|
name those tools as you declared them instead.
|
|
1658
1769
|
|
|
1659
1770
|
<Note>
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
one of these in `allowedTools` removes it from the
|
|
1664
|
-
warning; if that leaves no tools at all, the request
|
|
1665
|
-
instead of silently sending no restriction.
|
|
1771
|
+
Some tools cannot be allow-listed, because OpenAI's `allowed_tools` only sees
|
|
1772
|
+
the eagerly-loaded tool list: the [tool search tool](#tool-search), tools
|
|
1773
|
+
marked with `deferLoading` or `omitFromRequestTools`, and tools grouped into a
|
|
1774
|
+
namespace. Naming one of these in `allowedTools` removes it from the
|
|
1775
|
+
allow-list and emits a warning; if that leaves no tools at all, the request
|
|
1776
|
+
fails with an error instead of silently sending no restriction.
|
|
1666
1777
|
</Note>
|
|
1667
1778
|
|
|
1668
1779
|
<Note>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ai-sdk/openai",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.96",
|
|
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.
|
|
39
|
-
"@ai-sdk/provider-utils": "5.0.
|
|
38
|
+
"@ai-sdk/provider": "4.0.29",
|
|
39
|
+
"@ai-sdk/provider-utils": "5.0.62"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@ai-sdk/test-server": "2.0.4",
|
package/src/index.ts
CHANGED
|
@@ -15,6 +15,7 @@ export type { OpenAIRealtimeModelConfig as Experimental_OpenAIRealtimeModelConfi
|
|
|
15
15
|
export type {
|
|
16
16
|
OpenAILanguageModelResponsesOptions,
|
|
17
17
|
OpenAIResponsesSystemMessageOptions,
|
|
18
|
+
OpenAIResponsesToolResultOptions,
|
|
18
19
|
/** @deprecated Use `OpenAILanguageModelResponsesOptions` instead. */
|
|
19
20
|
OpenAILanguageModelResponsesOptions as OpenAIResponsesProviderOptions,
|
|
20
21
|
} from './responses/openai-responses-language-model-options';
|
package/src/openai-tools.ts
CHANGED
|
@@ -107,6 +107,8 @@ export const openaiTools = {
|
|
|
107
107
|
* Web search allows models to access up-to-date information from the internet
|
|
108
108
|
* and provide answers with sourced citations.
|
|
109
109
|
*
|
|
110
|
+
* @deprecated Use `webSearch` instead.
|
|
111
|
+
*
|
|
110
112
|
* @param searchContextSize - The search context size to use for the web search.
|
|
111
113
|
* @param userLocation - The user location to use for the web search.
|
|
112
114
|
*/
|
|
@@ -20,7 +20,10 @@ import {
|
|
|
20
20
|
type ToolNameMapping,
|
|
21
21
|
} from '@ai-sdk/provider-utils';
|
|
22
22
|
import { z } from 'zod/v4';
|
|
23
|
-
import {
|
|
23
|
+
import {
|
|
24
|
+
openaiResponsesSystemMessageOptionsSchema,
|
|
25
|
+
openaiResponsesToolResultOptionsSchema,
|
|
26
|
+
} from './openai-responses-language-model-options';
|
|
24
27
|
import {
|
|
25
28
|
applyPatchInputSchema,
|
|
26
29
|
applyPatchOutputSchema,
|
|
@@ -1794,6 +1797,19 @@ export async function convertToOpenAIResponsesInput({
|
|
|
1794
1797
|
output: contentValue,
|
|
1795
1798
|
...(caller != null && { caller }),
|
|
1796
1799
|
});
|
|
1800
|
+
|
|
1801
|
+
const options = await parseProviderOptions({
|
|
1802
|
+
provider: providerOptionsName,
|
|
1803
|
+
providerOptions: part.providerOptions,
|
|
1804
|
+
schema: openaiResponsesToolResultOptionsSchema,
|
|
1805
|
+
});
|
|
1806
|
+
if (options?.additionalTools?.length) {
|
|
1807
|
+
input.push({
|
|
1808
|
+
type: 'additional_tools',
|
|
1809
|
+
role: 'developer',
|
|
1810
|
+
tools: options.additionalTools,
|
|
1811
|
+
});
|
|
1812
|
+
}
|
|
1797
1813
|
}
|
|
1798
1814
|
|
|
1799
1815
|
break;
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
type InferSchema,
|
|
7
7
|
} from '@ai-sdk/provider-utils';
|
|
8
8
|
import { z } from 'zod/v4';
|
|
9
|
+
import type { OpenAIResponsesToolResultOptions } from './openai-responses-language-model-options';
|
|
9
10
|
|
|
10
11
|
const jsonValueSchema: z.ZodType<JSONValue> = z.lazy(() =>
|
|
11
12
|
z.union([
|
|
@@ -162,6 +163,11 @@ export type OpenAIResponsesInputItem =
|
|
|
162
163
|
| OpenAIResponsesAssistantMessage
|
|
163
164
|
| OpenAIResponsesFunctionCall
|
|
164
165
|
| OpenAIResponsesFunctionCallOutput
|
|
166
|
+
| {
|
|
167
|
+
type: 'additional_tools';
|
|
168
|
+
role: 'developer';
|
|
169
|
+
tools: NonNullable<OpenAIResponsesToolResultOptions['additionalTools']>;
|
|
170
|
+
}
|
|
165
171
|
| OpenAIResponsesProgram
|
|
166
172
|
| OpenAIResponsesProgramOutput
|
|
167
173
|
| OpenAIResponsesCustomToolCall
|
|
@@ -457,3 +457,26 @@ export const openaiResponsesSystemMessageOptionsSchema = lazySchema(() =>
|
|
|
457
457
|
export type OpenAIResponsesSystemMessageOptions = InferSchema<
|
|
458
458
|
typeof openaiResponsesSystemMessageOptionsSchema
|
|
459
459
|
>;
|
|
460
|
+
|
|
461
|
+
export const openaiResponsesToolResultOptionsSchema = lazySchema(() =>
|
|
462
|
+
zodSchema(
|
|
463
|
+
z.object({
|
|
464
|
+
/** Function definitions to load immediately after this ordinary tool result. */
|
|
465
|
+
additionalTools: z
|
|
466
|
+
.array(
|
|
467
|
+
z.strictObject({
|
|
468
|
+
type: z.literal('function'),
|
|
469
|
+
name: z.string().min(1),
|
|
470
|
+
description: z.string().optional(),
|
|
471
|
+
parameters: z.record(z.string(), z.json()),
|
|
472
|
+
strict: z.boolean().optional(),
|
|
473
|
+
}),
|
|
474
|
+
)
|
|
475
|
+
.optional(),
|
|
476
|
+
}),
|
|
477
|
+
),
|
|
478
|
+
);
|
|
479
|
+
|
|
480
|
+
export type OpenAIResponsesToolResultOptions = InferSchema<
|
|
481
|
+
typeof openaiResponsesToolResultOptionsSchema
|
|
482
|
+
>;
|
|
@@ -1739,14 +1739,7 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV4 {
|
|
|
1739
1739
|
type: 'tool-input-start',
|
|
1740
1740
|
id: value.item.call_id,
|
|
1741
1741
|
toolName,
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
// Custom tool input is a string, so stream its JSON encoding
|
|
1745
|
-
// consistently with the final tool call input.
|
|
1746
|
-
controller.enqueue({
|
|
1747
|
-
type: 'tool-input-delta',
|
|
1748
|
-
id: value.item.call_id,
|
|
1749
|
-
delta: '"',
|
|
1742
|
+
inputEncoding: 'text',
|
|
1750
1743
|
});
|
|
1751
1744
|
} else if (value.item.type === 'web_search_call') {
|
|
1752
1745
|
ongoingToolCalls[value.output_index] = {
|
|
@@ -2146,12 +2139,6 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV4 {
|
|
|
2146
2139
|
value.item.name,
|
|
2147
2140
|
);
|
|
2148
2141
|
|
|
2149
|
-
controller.enqueue({
|
|
2150
|
-
type: 'tool-input-delta',
|
|
2151
|
-
id: value.item.call_id,
|
|
2152
|
-
delta: '"',
|
|
2153
|
-
});
|
|
2154
|
-
|
|
2155
2142
|
controller.enqueue({
|
|
2156
2143
|
type: 'tool-input-end',
|
|
2157
2144
|
id: value.item.call_id,
|
|
@@ -2649,7 +2636,7 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV4 {
|
|
|
2649
2636
|
controller.enqueue({
|
|
2650
2637
|
type: 'tool-input-delta',
|
|
2651
2638
|
id: toolCall.toolCallId,
|
|
2652
|
-
delta:
|
|
2639
|
+
delta: value.delta,
|
|
2653
2640
|
});
|
|
2654
2641
|
}
|
|
2655
2642
|
} else if (isResponseApplyPatchCallOperationDiffDeltaChunk(value)) {
|
|
@@ -40,6 +40,12 @@ export type OpenAIToolOptions = {
|
|
|
40
40
|
*/
|
|
41
41
|
async?: boolean;
|
|
42
42
|
deferLoading?: boolean;
|
|
43
|
+
/**
|
|
44
|
+
* Omit this function from the Responses request's top-level tools array.
|
|
45
|
+
* Use for tools supplied in history through additionalTools. Keep the tool
|
|
46
|
+
* active in the SDK so its calls can still be validated and executed.
|
|
47
|
+
*/
|
|
48
|
+
omitFromRequestTools?: boolean;
|
|
43
49
|
outputSchema?: JSONObject;
|
|
44
50
|
namespace?: {
|
|
45
51
|
name: string;
|
|
@@ -145,6 +151,27 @@ export async function prepareResponsesTools({
|
|
|
145
151
|
if (openaiOptions?.outputSchema != null) {
|
|
146
152
|
outputSchemaToolNames?.add(tool.name);
|
|
147
153
|
}
|
|
154
|
+
if (openaiOptions?.omitFromRequestTools === true) {
|
|
155
|
+
recordAllowedTool(
|
|
156
|
+
tool.name,
|
|
157
|
+
{
|
|
158
|
+
supported: false,
|
|
159
|
+
reason:
|
|
160
|
+
'tools omitted from the request tools array cannot be allow-listed',
|
|
161
|
+
},
|
|
162
|
+
undefined,
|
|
163
|
+
);
|
|
164
|
+
if (
|
|
165
|
+
allowedTools == null &&
|
|
166
|
+
toolChoice?.type === 'tool' &&
|
|
167
|
+
toolChoice.toolName === tool.name
|
|
168
|
+
) {
|
|
169
|
+
throw new UnsupportedFunctionalityError({
|
|
170
|
+
functionality: `forcing tool "${tool.name}" omitted from the request tools array; use automatic tool choice for history-loaded tools`,
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
break;
|
|
174
|
+
}
|
|
148
175
|
const openaiFunctionTool = prepareFunctionTool({
|
|
149
176
|
tool,
|
|
150
177
|
options: openaiOptions,
|