ai 7.0.144 → 7.0.146
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 +21 -0
- package/dist/index.d.ts +15 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +36 -8
- package/dist/index.js.map +1 -1
- package/dist/internal/index.d.ts +10 -6
- package/dist/internal/index.d.ts.map +1 -1
- package/dist/internal/index.js +1 -1
- package/dist/internal/index.js.map +1 -1
- package/docs/03-ai-sdk-core/16-mcp-tools.mdx +29 -2
- package/docs/03-ai-sdk-core/18-tools.mdx +137 -0
- package/docs/03-ai-sdk-core/index.mdx +6 -0
- package/docs/03-ai-sdk-harnesses/05-harness-adapters.mdx +3 -3
- package/docs/07-reference/01-ai-sdk-core/14-decide.mdx +18 -13
- package/package.json +13 -12
- package/src/decide/decide-events.ts +6 -0
- package/src/decide/decide.ts +13 -0
- package/src/generate-text/prune-messages.ts +91 -32
- package/src/generate-text/tool-call.ts +1 -1
- package/src/generate-text/tool-error.ts +1 -1
- package/src/generate-text/tool-execution-events.ts +2 -2
- package/src/generate-text/tool-output-denied.ts +1 -1
- package/src/generate-text/tool-result.ts +1 -1
|
@@ -210,6 +210,33 @@ tokens are invalid.
|
|
|
210
210
|
|
|
211
211
|
### OAuth Authorization Server Validation
|
|
212
212
|
|
|
213
|
+
Pre-registered confidential clients must be bound to their authorization server
|
|
214
|
+
before starting OAuth. Set `issuer` on the credentials returned by
|
|
215
|
+
`clientInformation()` to the issuer of the server that registered the client:
|
|
216
|
+
|
|
217
|
+
```typescript
|
|
218
|
+
clientInformation() {
|
|
219
|
+
return {
|
|
220
|
+
client_id: process.env.OAUTH_CLIENT_ID!,
|
|
221
|
+
client_secret: process.env.OAUTH_CLIENT_SECRET!,
|
|
222
|
+
issuer: 'https://accounts.example.com',
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
The issuer must exactly match the discovered issuer. The SDK rejects a mismatch
|
|
228
|
+
before redirecting or sending credentials, even if a stored authorization flow
|
|
229
|
+
pin names the discovered server. Dynamic client registration attaches this
|
|
230
|
+
binding automatically.
|
|
231
|
+
|
|
232
|
+
Existing complete authorization server bindings on credentials, stored tokens,
|
|
233
|
+
or `authorizationServerInformation()` are also supported. Without a binding,
|
|
234
|
+
a pre-registered client secret or custom `addClientAuthentication` handler is
|
|
235
|
+
rejected, even when `validateAuthorizationServerURL` accepts the selected server.
|
|
236
|
+
Approving a server does not establish that the credentials belong to it.
|
|
237
|
+
Do not derive the credential issuer from the MCP server's metadata; configure it
|
|
238
|
+
from the client's registration.
|
|
239
|
+
|
|
213
240
|
When using MCP OAuth in server-side applications, the MCP server can advertise
|
|
214
241
|
the OAuth authorization server to use. If you connect to MCP servers outside
|
|
215
242
|
your control, implement `validateAuthorizationServerURL` on your
|
|
@@ -237,8 +264,8 @@ const myOAuthClientProvider = {
|
|
|
237
264
|
```
|
|
238
265
|
|
|
239
266
|
This hook is called before the SDK fetches authorization server metadata, so a
|
|
240
|
-
rejected URL is not requested.
|
|
241
|
-
|
|
267
|
+
rejected URL is not requested. The hook is an optional additional restriction;
|
|
268
|
+
it does not replace the credential binding required for confidential clients.
|
|
242
269
|
|
|
243
270
|
### OAuth Callback Issuer Validation
|
|
244
271
|
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Tools
|
|
3
|
+
description: Use first-party AI SDK tools to add capabilities to agents and applications.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Tools
|
|
7
|
+
|
|
8
|
+
The AI SDK provides first-party tools for agents and applications. Each tool
|
|
9
|
+
includes its input schema, model-facing description, and
|
|
10
|
+
execution logic, ready to use with `generateText`, `streamText`, or `ToolLoopAgent`.
|
|
11
|
+
These tools work with any model that supports function calling.
|
|
12
|
+
|
|
13
|
+
Install tools from their individual `@ai-sdk/tool-*` packages.
|
|
14
|
+
|
|
15
|
+
For defining your own tools and configuring tool execution, see
|
|
16
|
+
[Tools and Tool Calling](/docs/ai-sdk-core/tools-and-tool-calling).
|
|
17
|
+
|
|
18
|
+
## Bash Tool
|
|
19
|
+
|
|
20
|
+
`createBashTool` lets agents run Bash commands to search, analyze, and transform files.
|
|
21
|
+
Supply an `Experimental_SandboxSession` to choose where commands run. Use
|
|
22
|
+
`@ai-sdk/sandbox-just-bash` for an in-memory environment,
|
|
23
|
+
`@ai-sdk/sandbox-vercel` for Vercel Sandbox, or your own implementation.
|
|
24
|
+
The tool has no direct dependency on either runtime.
|
|
25
|
+
|
|
26
|
+
### Installation
|
|
27
|
+
|
|
28
|
+
Install the tool and the sandbox adapter you want to use. The following examples
|
|
29
|
+
use just-bash:
|
|
30
|
+
|
|
31
|
+
```sh
|
|
32
|
+
pnpm add ai @ai-sdk/tool-bash @ai-sdk/sandbox-just-bash
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Requires Node.js 22.13 or newer.
|
|
36
|
+
|
|
37
|
+
### Usage
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
import { createJustBashNetworkSandboxSession } from '@ai-sdk/sandbox-just-bash';
|
|
41
|
+
import { createBashTool } from '@ai-sdk/tool-bash';
|
|
42
|
+
import { generateText, isStepCount } from 'ai';
|
|
43
|
+
|
|
44
|
+
const session = await createJustBashNetworkSandboxSession();
|
|
45
|
+
|
|
46
|
+
try {
|
|
47
|
+
const sandbox = session.restricted();
|
|
48
|
+
await sandbox.writeTextFile({
|
|
49
|
+
path: 'notes.txt',
|
|
50
|
+
content: 'Apples: 10\nPears: 20\n',
|
|
51
|
+
});
|
|
52
|
+
const bash = await createBashTool({ sandbox });
|
|
53
|
+
|
|
54
|
+
const result = await generateText({
|
|
55
|
+
model, // Your configured model with function calling support.
|
|
56
|
+
tools: { bash },
|
|
57
|
+
stopWhen: isStepCount(5),
|
|
58
|
+
prompt: 'Read notes.txt and write a summary to summary.txt.',
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
console.log(result.text);
|
|
62
|
+
console.log(await sandbox.readTextFile({ path: 'summary.txt' }));
|
|
63
|
+
} finally {
|
|
64
|
+
await session.destroy();
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Vercel Sandbox
|
|
69
|
+
|
|
70
|
+
Install `@ai-sdk/sandbox-vercel` and `@vercel/sandbox` to use an existing native
|
|
71
|
+
Vercel Sandbox. Wrap it with the adapter before passing it to the tool:
|
|
72
|
+
|
|
73
|
+
```ts
|
|
74
|
+
import { createVercelSandboxSessionFromNativeSandbox } from '@ai-sdk/sandbox-vercel';
|
|
75
|
+
import { createBashTool } from '@ai-sdk/tool-bash';
|
|
76
|
+
import { Sandbox } from '@vercel/sandbox';
|
|
77
|
+
|
|
78
|
+
const nativeSandbox = await Sandbox.create();
|
|
79
|
+
|
|
80
|
+
try {
|
|
81
|
+
const sandbox = createVercelSandboxSessionFromNativeSandbox(nativeSandbox);
|
|
82
|
+
await sandbox.writeTextFile({
|
|
83
|
+
path: 'notes.txt',
|
|
84
|
+
content: 'Hello from Vercel Sandbox',
|
|
85
|
+
});
|
|
86
|
+
const bash = await createBashTool({ sandbox });
|
|
87
|
+
|
|
88
|
+
// Use bash with generateText, streamText, or ToolLoopAgent here.
|
|
89
|
+
} finally {
|
|
90
|
+
await nativeSandbox.stop();
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
You can also create a managed session with
|
|
95
|
+
`createVercelNetworkSandboxSession()` from `@ai-sdk/sandbox-vercel` and pass
|
|
96
|
+
`session.restricted()`. For an existing native just-bash `Sandbox`, use
|
|
97
|
+
`createJustBashSandboxSessionFromNativeSandbox()` from `@ai-sdk/sandbox-just-bash`.
|
|
98
|
+
Raw runtime instances need their respective adapters; a custom
|
|
99
|
+
`Experimental_SandboxSession` can be passed directly.
|
|
100
|
+
|
|
101
|
+
### Options
|
|
102
|
+
|
|
103
|
+
`createBashTool()` requires an options object:
|
|
104
|
+
|
|
105
|
+
| Option | Type | Description |
|
|
106
|
+
| ------------------ | ----------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
|
|
107
|
+
| `sandbox` | `Experimental_SandboxSession` | Required session for command execution and file operations. |
|
|
108
|
+
| `workingDirectory` | `string` | Optional absolute starting directory for each command, created if needed. When omitted, uses the sandbox's default directory. |
|
|
109
|
+
| `maxOutputLength` | `number` | Positive integer limiting characters retained from each output stream before a truncation notice. Defaults to `30000`. |
|
|
110
|
+
|
|
111
|
+
The model calls the tool with `{ command: string }` and receives
|
|
112
|
+
`{ stdout, stderr, exitCode }`. Nonzero exit codes are returned so the model can
|
|
113
|
+
inspect failures and recover. AI SDK cancellation is forwarded to the session.
|
|
114
|
+
Output truncation happens after execution and does not limit execution memory or
|
|
115
|
+
duration.
|
|
116
|
+
|
|
117
|
+
### Files and lifecycle
|
|
118
|
+
|
|
119
|
+
Commands use the sandbox's default working directory unless `workingDirectory`
|
|
120
|
+
is provided. Without an override, creating the tool runs no setup commands.
|
|
121
|
+
Seed files through `sandbox.writeTextFile({ path, content })` before running the
|
|
122
|
+
tool. With an explicit working directory, use absolute paths to write files there.
|
|
123
|
+
|
|
124
|
+
The sandbox controls which files commands can access. Available programs, network
|
|
125
|
+
access, shell state, and persistence depend on the supplied sandbox. Its
|
|
126
|
+
description is included in the tool's instructions.
|
|
127
|
+
|
|
128
|
+
Tools using the same session share files. Creating a tool does not reset existing
|
|
129
|
+
files or create a new sandbox. Use separate sessions for independent workflows.
|
|
130
|
+
The caller creates, reconnects, and destroys the sandbox.
|
|
131
|
+
|
|
132
|
+
`createBashTool()` returns the tool directly, ready to use as `tools: { bash }`.
|
|
133
|
+
Use the supplied sandbox's `readTextFile({ path })` to read generated text files;
|
|
134
|
+
it returns `null` if the file is missing. Relative read paths depend on the
|
|
135
|
+
sandbox adapter; just-bash resolves them against its default directory. With an
|
|
136
|
+
explicit working directory, use absolute paths to read files from that directory.
|
|
137
|
+
The same session provides other file operations.
|
|
@@ -28,6 +28,12 @@ description: Learn about AI SDK Core.
|
|
|
28
28
|
description: 'Learn how to do tool calling with AI SDK Core.',
|
|
29
29
|
href: '/docs/ai-sdk-core/tools-and-tool-calling',
|
|
30
30
|
},
|
|
31
|
+
{
|
|
32
|
+
title: 'Tools',
|
|
33
|
+
description:
|
|
34
|
+
'Add capabilities to agents and applications with first-party AI SDK tools.',
|
|
35
|
+
href: '/docs/ai-sdk-core/tools',
|
|
36
|
+
},
|
|
31
37
|
{
|
|
32
38
|
title: 'Tool Search',
|
|
33
39
|
description:
|
|
@@ -36,12 +36,12 @@ The AI SDK includes the following harness adapters:
|
|
|
36
36
|
| Adapter | Runtime location | Custom tools | Custom skills | Structured output | Built-in tool approval | Built-in tool filtering | Image input | History access |
|
|
37
37
|
| ------------------------------------------------------------ | ---------------- | ------------ | ------------- | ----------------- | ---------------------- | ---------------------------- | ----------- | -------------- |
|
|
38
38
|
| [Claude Code](/providers/ai-sdk-harnesses/claude-code) | Sandbox bridge | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Cross /> |
|
|
39
|
-
| [Cline](/providers/ai-sdk-harnesses/cline) | Host process | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <
|
|
40
|
-
| [Codex](/providers/ai-sdk-harnesses/codex) | Sandbox bridge | <Check /> | <Check /> | <Check /> | <Cross /> | <Cross /> | <
|
|
39
|
+
| [Cline](/providers/ai-sdk-harnesses/cline) | Host process | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Cross /> |
|
|
40
|
+
| [Codex](/providers/ai-sdk-harnesses/codex) | Sandbox bridge | <Check /> | <Check /> | <Check /> | <Cross /> | <Cross /> | <Check /> | <Cross /> |
|
|
41
41
|
| [Cursor](/providers/ai-sdk-harnesses/cursor) | Sandbox via ACP | <Check /> | <Check /> | <Cross /> | <Cross /> | <Cross /> | <Cross /> | <Cross /> |
|
|
42
42
|
| [Deep Agents](/providers/ai-sdk-harnesses/deepagents) | Sandbox bridge | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> via auto-rejection | <Cross /> | <Cross /> |
|
|
43
43
|
| [fx](/providers/ai-sdk-harnesses/fx) | Host process | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Cross /> | <Cross /> |
|
|
44
44
|
| [GitHub Copilot](/providers/ai-sdk-harnesses/github-copilot) | Sandbox via ACP | <Check /> | <Check /> | <Cross /> | <Cross /> | <Cross /> | <Cross /> | <Cross /> |
|
|
45
45
|
| [Grok Build](/providers/ai-sdk-harnesses/grok-build) | Sandbox via ACP | <Check /> | <Check /> | <Check /> | <Cross /> | <Cross /> | <Cross /> | <Cross /> |
|
|
46
46
|
| [OpenCode](/providers/ai-sdk-harnesses/opencode) | Sandbox bridge | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> | <Cross /> | <Cross /> |
|
|
47
|
-
| [Pi](/providers/ai-sdk-harnesses/pi) | Host process | <Check /> | <Check /> | <Cross /> | <Check /> | <Check /> | <
|
|
47
|
+
| [Pi](/providers/ai-sdk-harnesses/pi) | Host process | <Check /> | <Check /> | <Cross /> | <Check /> | <Check /> | <Check /> | <Cross /> |
|
|
@@ -14,19 +14,24 @@ state. See [Decisions](/docs/ai-sdk-core/decisions) for examples and semantics.
|
|
|
14
14
|
|
|
15
15
|
## Parameters
|
|
16
16
|
|
|
17
|
-
| Parameter | Type
|
|
18
|
-
| ----------------- |
|
|
19
|
-
| `model` | `Experimental_DecisionModel`
|
|
20
|
-
| `state` | `Experimental_DecisionState`
|
|
21
|
-
| `questions` | `Record<string, Experimental_DecisionQuestion>`
|
|
22
|
-
| `
|
|
23
|
-
| `
|
|
24
|
-
| `
|
|
25
|
-
| `
|
|
26
|
-
| `
|
|
27
|
-
| `
|
|
28
|
-
| `
|
|
29
|
-
| `
|
|
17
|
+
| Parameter | Type | Description |
|
|
18
|
+
| ----------------- | ---------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
|
|
19
|
+
| `model` | `Experimental_DecisionModel` | Required experimental v4 model instance or a string ID resolved by Gateway or an explicitly configured decision-capable default provider. |
|
|
20
|
+
| `state` | `Experimental_DecisionState` | Required string, JSON object, or ordered array of text, file, and JSON parts. |
|
|
21
|
+
| `questions` | `Record<string, Experimental_DecisionQuestion>` | Required nonempty question map. |
|
|
22
|
+
| `maxOutputTokens` | `number` | Optional maximum output tokens, an integer >= 1. |
|
|
23
|
+
| `reasoning` | `'provider-default' \| 'none' \| 'minimal' \| 'low' \| 'medium' \| 'high' \| 'xhigh' \| 'max'` | Optional reasoning effort. Language-model adapters default to `'none'`. Native decision providers return an unsupported-setting warning. |
|
|
24
|
+
| `maxRetries` | `number` | Nonnegative integer; defaults to 2. |
|
|
25
|
+
| `abortSignal` | `AbortSignal` | Cancels the decisions request. |
|
|
26
|
+
| `headers` | `Record<string, string>` | Additional HTTP headers. |
|
|
27
|
+
| `providerOptions` | `ProviderOptions` | Provider-specific options. |
|
|
28
|
+
| `telemetry` | `TelemetryOptions` | Telemetry configuration, including per-call integrations, input/output recording, and a function ID. |
|
|
29
|
+
| `runtimeContext` | `Record<string, unknown>` | Context available to lifecycle callbacks and selectively included in telemetry with `telemetry.includeRuntimeContext`. |
|
|
30
|
+
| `onStart` | `(event: Experimental_DecideStartEvent) => void` | Called when the decision operation begins. |
|
|
31
|
+
| `onEnd` | `(event: Experimental_DecideEndEvent) => void` | Called when the decision operation completes successfully. |
|
|
32
|
+
|
|
33
|
+
Set `reasoning: 'provider-default'` to use the underlying language model's default
|
|
34
|
+
reasoning effort instead of the adapter's `'none'` default.
|
|
30
35
|
|
|
31
36
|
See [Lifecycle Callbacks](/docs/ai-sdk-core/lifecycle-callbacks#experimental_decide)
|
|
32
37
|
for the complete `onStart` and `onEnd` event fields.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ai",
|
|
3
|
-
"version": "7.0.
|
|
3
|
+
"version": "7.0.146",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "AI SDK by Vercel - build apps like ChatGPT, Claude, Gemini, and more with a single interface for any model using the Vercel AI Gateway or go direct to OpenAI, Anthropic, Google, or any other model provider.",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -42,26 +42,27 @@
|
|
|
42
42
|
}
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"@ai-sdk/gateway": "4.0.
|
|
46
|
-
"@ai-sdk/provider": "4.0.
|
|
47
|
-
"@ai-sdk/provider-utils": "5.0.
|
|
45
|
+
"@ai-sdk/gateway": "4.0.119",
|
|
46
|
+
"@ai-sdk/provider": "4.0.31",
|
|
47
|
+
"@ai-sdk/provider-utils": "5.0.64"
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
|
-
"@ai-sdk/amazon-bedrock": "5.0.
|
|
51
|
-
"@ai-sdk/deepseek": "3.0.
|
|
52
|
-
"@ai-sdk/google": "4.0.
|
|
53
|
-
"@ai-sdk/groq": "4.0.
|
|
54
|
-
"@ai-sdk/huggingface": "2.0.
|
|
55
|
-
"@ai-sdk/moonshotai": "3.0.
|
|
56
|
-
"@ai-sdk/openai": "4.0.
|
|
50
|
+
"@ai-sdk/amazon-bedrock": "5.0.120",
|
|
51
|
+
"@ai-sdk/deepseek": "3.0.69",
|
|
52
|
+
"@ai-sdk/google": "4.0.101",
|
|
53
|
+
"@ai-sdk/groq": "4.0.66",
|
|
54
|
+
"@ai-sdk/huggingface": "2.0.74",
|
|
55
|
+
"@ai-sdk/moonshotai": "3.0.73",
|
|
56
|
+
"@ai-sdk/openai": "4.0.98",
|
|
57
57
|
"@ai-sdk/test-server": "2.0.4",
|
|
58
|
-
"@ai-sdk/xai": "5.0.
|
|
58
|
+
"@ai-sdk/xai": "5.0.26",
|
|
59
59
|
"@edge-runtime/vm": "^5.0.0",
|
|
60
60
|
"@smithy/eventstream-codec": "^4.3.3",
|
|
61
61
|
"@smithy/util-utf8": "^4.3.3",
|
|
62
62
|
"@types/json-schema": "7.0.15",
|
|
63
63
|
"@types/node": "22.19.19",
|
|
64
64
|
"@vercel/ai-tsconfig": "0.0.0",
|
|
65
|
+
"@vercel/ai-tsdown-config": "0.0.0",
|
|
65
66
|
"esbuild": "^0.28.2",
|
|
66
67
|
"tsdown": "^0.23.0",
|
|
67
68
|
"tsx": "4.23.12",
|
|
@@ -34,6 +34,12 @@ export type DecideStartEvent<RUNTIME_CONTEXT extends Context = Context> = {
|
|
|
34
34
|
/** The questions to decide against the shared state. */
|
|
35
35
|
readonly questions: Readonly<Record<string, DecisionQuestion>>;
|
|
36
36
|
|
|
37
|
+
/** Maximum output tokens requested for the decision. */
|
|
38
|
+
readonly maxOutputTokens?: number;
|
|
39
|
+
|
|
40
|
+
/** Reasoning effort requested for the decision. */
|
|
41
|
+
readonly reasoning?: DecisionModelV4CallOptions['reasoning'];
|
|
42
|
+
|
|
37
43
|
/** Maximum number of retries for the decision model call. */
|
|
38
44
|
readonly maxRetries: number;
|
|
39
45
|
|
package/src/decide/decide.ts
CHANGED
|
@@ -2,6 +2,7 @@ import {
|
|
|
2
2
|
Experimental_DecisionRefusalError as DecisionRefusalError,
|
|
3
3
|
Experimental_DecisionUnsupportedQuestionTypeError as DecisionUnsupportedQuestionTypeError,
|
|
4
4
|
type Experimental_DecisionModelV4Question as DecisionQuestion,
|
|
5
|
+
type Experimental_DecisionModelV4CallOptions as DecisionCallOptions,
|
|
5
6
|
} from '@ai-sdk/provider';
|
|
6
7
|
import {
|
|
7
8
|
createIdGenerator,
|
|
@@ -16,6 +17,7 @@ import type { TelemetryOptions } from '../telemetry/telemetry-options';
|
|
|
16
17
|
import type { Callback } from '../util/callback';
|
|
17
18
|
import { notify } from '../util/notify';
|
|
18
19
|
import { prepareRetries } from '../util/prepare-retries';
|
|
20
|
+
import { prepareLanguageModelCallOptions } from '../prompt/prepare-language-model-call-options';
|
|
19
21
|
import { VERSION } from '../version';
|
|
20
22
|
import type { DecideEndEvent, DecideStartEvent } from './decide-events';
|
|
21
23
|
import type { DecisionModel, DecisionResult } from './decision-result';
|
|
@@ -38,6 +40,8 @@ export async function decide<
|
|
|
38
40
|
model: modelArg,
|
|
39
41
|
state,
|
|
40
42
|
questions,
|
|
43
|
+
maxOutputTokens,
|
|
44
|
+
reasoning,
|
|
41
45
|
maxRetries,
|
|
42
46
|
abortSignal,
|
|
43
47
|
headers,
|
|
@@ -52,6 +56,10 @@ export async function decide<
|
|
|
52
56
|
model: DecisionModel;
|
|
53
57
|
state: DecisionState;
|
|
54
58
|
questions: QUESTIONS;
|
|
59
|
+
/** Maximum output tokens for supported models. Must be an integer >= 1. */
|
|
60
|
+
maxOutputTokens?: number;
|
|
61
|
+
/** Reasoning effort for supported models. Language-model adapters default to none. */
|
|
62
|
+
reasoning?: DecisionCallOptions['reasoning'];
|
|
55
63
|
/** Maximum retries for transient provider failures. Defaults to 2. */
|
|
56
64
|
maxRetries?: number;
|
|
57
65
|
abortSignal?: AbortSignal;
|
|
@@ -72,6 +80,7 @@ export async function decide<
|
|
|
72
80
|
}): Promise<DecisionResult<QUESTIONS>> {
|
|
73
81
|
const model = resolveDecisionModel(modelArg);
|
|
74
82
|
|
|
83
|
+
prepareLanguageModelCallOptions({ maxOutputTokens });
|
|
75
84
|
validateDecisionInput({ state, questions });
|
|
76
85
|
|
|
77
86
|
for (const [questionId, question] of Object.entries(questions)) {
|
|
@@ -105,6 +114,8 @@ export async function decide<
|
|
|
105
114
|
modelId: model.modelId,
|
|
106
115
|
state,
|
|
107
116
|
questions,
|
|
117
|
+
maxOutputTokens,
|
|
118
|
+
reasoning,
|
|
108
119
|
maxRetries: resolvedMaxRetries,
|
|
109
120
|
headers,
|
|
110
121
|
providerOptions,
|
|
@@ -139,6 +150,8 @@ export async function decide<
|
|
|
139
150
|
return await model.doDecide({
|
|
140
151
|
state: preparedState,
|
|
141
152
|
questions,
|
|
153
|
+
maxOutputTokens,
|
|
154
|
+
reasoning,
|
|
142
155
|
abortSignal,
|
|
143
156
|
headers: withUserAgentSuffix(headers ?? {}, `ai/${VERSION}`),
|
|
144
157
|
providerOptions,
|
|
@@ -163,42 +163,101 @@ export function pruneMessages({
|
|
|
163
163
|
return message;
|
|
164
164
|
}
|
|
165
165
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
166
|
+
const keepParts = message.content.map(part => {
|
|
167
|
+
// keep non-tool parts:
|
|
168
|
+
if (
|
|
169
|
+
part.type !== 'tool-call' &&
|
|
170
|
+
part.type !== 'tool-result' &&
|
|
171
|
+
part.type !== 'tool-approval-request' &&
|
|
172
|
+
part.type !== 'tool-approval-response'
|
|
173
|
+
) {
|
|
174
|
+
return true;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// keep parts that are associated with a tool call or approval that needs to be kept:
|
|
178
|
+
if (
|
|
179
|
+
((part.type === 'tool-call' || part.type === 'tool-result') &&
|
|
180
|
+
keptToolCallIds.has(part.toolCallId)) ||
|
|
181
|
+
((part.type === 'tool-approval-request' ||
|
|
182
|
+
part.type === 'tool-approval-response') &&
|
|
183
|
+
keptApprovalIds.has(part.approvalId))
|
|
184
|
+
) {
|
|
185
|
+
return true;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// keep parts that are not associated with a tool that should be removed:
|
|
189
|
+
const partToolName =
|
|
190
|
+
part.type === 'tool-call' || part.type === 'tool-result'
|
|
191
|
+
? part.toolName
|
|
192
|
+
: approvalIdToToolName.get(part.approvalId);
|
|
193
|
+
|
|
194
|
+
return (
|
|
195
|
+
toolCall.tools != null &&
|
|
196
|
+
partToolName != null &&
|
|
197
|
+
!toolCall.tools.includes(partToolName)
|
|
198
|
+
);
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
// Consecutive reasoning parts can belong to the same provider item.
|
|
202
|
+
// Remove the whole group when its following content was pruned.
|
|
203
|
+
if (message.role === 'assistant') {
|
|
204
|
+
for (
|
|
205
|
+
let reasoningIndex = 0;
|
|
206
|
+
reasoningIndex < message.content.length;
|
|
207
|
+
reasoningIndex++
|
|
208
|
+
) {
|
|
209
|
+
const part = message.content[reasoningIndex];
|
|
210
|
+
if (part.type !== 'reasoning' && part.type !== 'reasoning-file') {
|
|
211
|
+
continue;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
let reasoningEndIndex = reasoningIndex + 1;
|
|
215
|
+
while (reasoningEndIndex < message.content.length) {
|
|
216
|
+
const nextPart = message.content[reasoningEndIndex];
|
|
217
|
+
if (
|
|
218
|
+
nextPart.type !== 'reasoning' &&
|
|
219
|
+
nextPart.type !== 'reasoning-file'
|
|
220
|
+
) {
|
|
221
|
+
break;
|
|
222
|
+
}
|
|
223
|
+
reasoningEndIndex++;
|
|
177
224
|
}
|
|
178
225
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
226
|
+
let followingPartIndex = reasoningEndIndex;
|
|
227
|
+
let hasFollowingPart = false;
|
|
228
|
+
let hasKeptFollowingPart = false;
|
|
229
|
+
|
|
230
|
+
while (followingPartIndex < message.content.length) {
|
|
231
|
+
const followingPart = message.content[followingPartIndex];
|
|
232
|
+
if (
|
|
233
|
+
followingPart.type === 'reasoning' ||
|
|
234
|
+
followingPart.type === 'reasoning-file'
|
|
235
|
+
) {
|
|
236
|
+
break;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
hasFollowingPart = true;
|
|
240
|
+
hasKeptFollowingPart ||= keepParts[followingPartIndex];
|
|
241
|
+
followingPartIndex++;
|
|
188
242
|
}
|
|
189
243
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
}
|
|
244
|
+
if (hasFollowingPart && !hasKeptFollowingPart) {
|
|
245
|
+
for (
|
|
246
|
+
let index = reasoningIndex;
|
|
247
|
+
index < reasoningEndIndex;
|
|
248
|
+
index++
|
|
249
|
+
) {
|
|
250
|
+
keepParts[index] = false;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
reasoningIndex = followingPartIndex - 1;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
return {
|
|
259
|
+
...message,
|
|
260
|
+
content: message.content.filter((_, index) => keepParts[index]),
|
|
202
261
|
} as AssistantModelMessage | ToolModelMessage;
|
|
203
262
|
});
|
|
204
263
|
}
|
|
@@ -18,7 +18,7 @@ type BaseToolCall = {
|
|
|
18
18
|
* with an `input` type inferred from that tool's input schema.
|
|
19
19
|
*/
|
|
20
20
|
export type StaticToolCall<TOOLS extends ToolSet> = ValueOf<{
|
|
21
|
-
[NAME in keyof TOOLS]
|
|
21
|
+
[NAME in keyof TOOLS]-?: BaseToolCall & {
|
|
22
22
|
toolName: NAME & string;
|
|
23
23
|
input: InferToolInput<TOOLS[NAME]>;
|
|
24
24
|
dynamic?: false | undefined;
|
|
@@ -4,7 +4,7 @@ import type { ProviderMetadata } from '../types';
|
|
|
4
4
|
import type { ValueOf } from '../util/value-of';
|
|
5
5
|
|
|
6
6
|
export type StaticToolError<TOOLS extends ToolSet> = ValueOf<{
|
|
7
|
-
[NAME in keyof TOOLS]
|
|
7
|
+
[NAME in keyof TOOLS]-?: {
|
|
8
8
|
type: 'tool-error';
|
|
9
9
|
toolCallId: string;
|
|
10
10
|
toolName: NAME & string;
|
|
@@ -36,7 +36,7 @@ type BaseToolExecutionStartFields = {
|
|
|
36
36
|
* validated `toolContext` type.
|
|
37
37
|
*/
|
|
38
38
|
type StaticToolExecutionStartEvent<TOOLS extends ToolSet> = ValueOf<{
|
|
39
|
-
[NAME in keyof TOOLS]
|
|
39
|
+
[NAME in keyof TOOLS]-?: BaseToolExecutionStartFields & {
|
|
40
40
|
readonly toolCall: Extract<StaticToolCall<TOOLS>, { toolName: NAME }>;
|
|
41
41
|
readonly toolContext: ToolContextFor<TOOLS[NAME]>;
|
|
42
42
|
};
|
|
@@ -93,7 +93,7 @@ type BaseToolExecutionEndFields = {
|
|
|
93
93
|
* corresponding validated `toolContext`, and the tool execution result.
|
|
94
94
|
*/
|
|
95
95
|
type StaticToolExecutionEndEvent<TOOLS extends ToolSet> = ValueOf<{
|
|
96
|
-
[NAME in keyof TOOLS]
|
|
96
|
+
[NAME in keyof TOOLS]-?: BaseToolExecutionEndFields & {
|
|
97
97
|
readonly toolCall: Extract<StaticToolCall<TOOLS>, { toolName: NAME }>;
|
|
98
98
|
readonly toolContext: ToolContextFor<TOOLS[NAME]>;
|
|
99
99
|
readonly toolOutput: ToolOutput<TOOLS>;
|
|
@@ -5,7 +5,7 @@ import type { ToolSet } from '@ai-sdk/provider-utils';
|
|
|
5
5
|
* Tool output when the tool execution has been denied (for static tools).
|
|
6
6
|
*/
|
|
7
7
|
export type StaticToolOutputDenied<TOOLS extends ToolSet> = ValueOf<{
|
|
8
|
-
[NAME in keyof TOOLS]
|
|
8
|
+
[NAME in keyof TOOLS]-?: {
|
|
9
9
|
type: 'tool-output-denied';
|
|
10
10
|
toolCallId: string;
|
|
11
11
|
toolName: NAME & string;
|
|
@@ -8,7 +8,7 @@ import type { ProviderMetadata } from '../types';
|
|
|
8
8
|
import type { ValueOf } from '../../src/util/value-of';
|
|
9
9
|
|
|
10
10
|
export type StaticToolResult<TOOLS extends ToolSet> = ValueOf<{
|
|
11
|
-
[NAME in keyof TOOLS]
|
|
11
|
+
[NAME in keyof TOOLS]-?: {
|
|
12
12
|
type: 'tool-result';
|
|
13
13
|
toolCallId: string;
|
|
14
14
|
toolName: NAME & string;
|