ai 6.0.41 → 6.0.43
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 +18 -0
- package/dist/index.d.mts +23 -13
- package/dist/index.d.ts +23 -13
- package/dist/index.js +450 -355
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +381 -287
- package/dist/index.mjs.map +1 -1
- package/dist/internal/index.js +138 -45
- package/dist/internal/index.js.map +1 -1
- package/dist/internal/index.mjs +127 -34
- package/dist/internal/index.mjs.map +1 -1
- package/docs/02-getting-started/02-nextjs-app-router.mdx +3 -3
- package/docs/02-getting-started/03-nextjs-pages-router.mdx +2 -2
- package/docs/02-getting-started/04-svelte.mdx +2 -2
- package/docs/02-getting-started/05-nuxt.mdx +2 -2
- package/docs/02-getting-started/06-nodejs.mdx +2 -2
- package/docs/02-getting-started/07-expo.mdx +1 -1
- package/docs/02-getting-started/08-tanstack-start.mdx +2 -2
- package/docs/05-ai-sdk-rsc/03-generative-ui-state.mdx +1 -1
- package/docs/05-ai-sdk-rsc/05-streaming-values.mdx +1 -1
- package/docs/06-advanced/02-stopping-streams.mdx +2 -2
- package/docs/07-reference/02-ai-sdk-ui/02-use-completion.mdx +1 -1
- package/docs/08-migration-guides/26-migration-guide-5-0.mdx +3 -3
- package/docs/09-troubleshooting/15-abort-breaks-resumable-streams.mdx +1 -1
- package/docs/09-troubleshooting/21-missing-tool-results-error.mdx +82 -0
- package/package.json +2 -2
- package/src/error/index.ts +1 -1
- package/src/error/missing-tool-result-error.ts +28 -0
- package/src/prompt/__snapshots__/convert-to-language-model-prompt.validation.test.ts.snap +76 -0
- package/src/prompt/convert-to-language-model-prompt.ts +85 -1
- package/src/prompt/convert-to-language-model-prompt.validation.test.ts +138 -0
|
@@ -50,7 +50,7 @@ Allows you to create text completion based capabilities for your application. It
|
|
|
50
50
|
name: 'id',
|
|
51
51
|
type: 'string',
|
|
52
52
|
description:
|
|
53
|
-
'
|
|
53
|
+
'A unique identifier for the completion. If not provided, a random one will be generated. When provided, the `useCompletion` hook with the same `id` will have shared states across components. This is useful when you have multiple components showing the same chat stream',
|
|
54
54
|
},
|
|
55
55
|
{
|
|
56
56
|
name: 'initialInput',
|
|
@@ -1386,7 +1386,7 @@ const { messages } = useChat({
|
|
|
1386
1386
|
});
|
|
1387
1387
|
```
|
|
1388
1388
|
|
|
1389
|
-
For a complete example of sharing chat state across components, see the [Share Chat State Across Components](/
|
|
1389
|
+
For a complete example of sharing chat state across components, see the [Share Chat State Across Components](/cookbook/next/use-shared-chat-context) recipe.
|
|
1390
1390
|
|
|
1391
1391
|
#### Chat Transport Architecture
|
|
1392
1392
|
|
|
@@ -3104,7 +3104,7 @@ const result = await generateObject({
|
|
|
3104
3104
|
}),
|
|
3105
3105
|
providerOptions: {
|
|
3106
3106
|
openai: {
|
|
3107
|
-
strictSchemas: true, // default
|
|
3107
|
+
strictSchemas: true, // default behavior in AI SDK 4
|
|
3108
3108
|
} satisfies OpenAIResponsesProviderOptions,
|
|
3109
3109
|
},
|
|
3110
3110
|
});
|
|
@@ -3122,7 +3122,7 @@ const result = await generateObject({
|
|
|
3122
3122
|
}),
|
|
3123
3123
|
providerOptions: {
|
|
3124
3124
|
openai: {
|
|
3125
|
-
strictJsonSchema: true, // defaults to false, opt back in to the AI SDK 4 strict
|
|
3125
|
+
strictJsonSchema: true, // defaults to false, opt back in to the AI SDK 4 strict behavior
|
|
3126
3126
|
} satisfies OpenAIResponsesProviderOptions,
|
|
3127
3127
|
},
|
|
3128
3128
|
});
|
|
@@ -45,7 +45,7 @@ If you need to allow users to stop streams manually:
|
|
|
45
45
|
```tsx
|
|
46
46
|
const { messages, sendMessage, stop } = useChat({
|
|
47
47
|
id: chatId,
|
|
48
|
-
resume: false, // Disable stream resumption (default
|
|
48
|
+
resume: false, // Disable stream resumption (default behavior)
|
|
49
49
|
});
|
|
50
50
|
```
|
|
51
51
|
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Missing Tool Results Error
|
|
3
|
+
description: How to fix the "Tool results are missing for tool calls" error when using the AI SDK.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Missing Tool Results Error
|
|
7
|
+
|
|
8
|
+
## Issue
|
|
9
|
+
|
|
10
|
+
You encounter the error `AI_MissingToolResultsError` with a message like:
|
|
11
|
+
|
|
12
|
+
> Tool results are missing for tool calls: ...
|
|
13
|
+
|
|
14
|
+
## Cause
|
|
15
|
+
|
|
16
|
+
This error occurs when you attempt to send a new message to the Large Language Model (LLM) while there are pending tool calls from a previous turn that have not yet been resolved.
|
|
17
|
+
|
|
18
|
+
The AI SDK core logic validates that all `tool-call` parts in the conversation history are resolved before proceeding. "Resolved" typically means:
|
|
19
|
+
|
|
20
|
+
1. The tool has been executed and a `tool-result` has been added to the history.
|
|
21
|
+
2. Or, the tool call has triggered a `tool-approval-response` (if using tool approvals).
|
|
22
|
+
|
|
23
|
+
If a tool call is found without a corresponding result or approval response, this error is thrown to prevent sending an invalid conversation history to the model.
|
|
24
|
+
|
|
25
|
+
## Solution
|
|
26
|
+
|
|
27
|
+
Ensure that every tool call in your conversation history is properly handled.
|
|
28
|
+
|
|
29
|
+
### 1. Provide Tool Results
|
|
30
|
+
|
|
31
|
+
For standard tool calls, ensure that you provide the output of the tool execution.
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
const messages = [
|
|
35
|
+
{ role: 'user', content: 'What is the weather in NY?' },
|
|
36
|
+
{
|
|
37
|
+
role: 'assistant',
|
|
38
|
+
content: [
|
|
39
|
+
{
|
|
40
|
+
type: 'tool-call',
|
|
41
|
+
toolCallId: 'call_123',
|
|
42
|
+
toolName: 'getWeather',
|
|
43
|
+
args: { location: 'New York' },
|
|
44
|
+
},
|
|
45
|
+
],
|
|
46
|
+
},
|
|
47
|
+
// You MUST include this tool message with the result:
|
|
48
|
+
{
|
|
49
|
+
role: 'tool',
|
|
50
|
+
content: [
|
|
51
|
+
{
|
|
52
|
+
type: 'tool-result',
|
|
53
|
+
toolCallId: 'call_123',
|
|
54
|
+
toolName: 'getWeather',
|
|
55
|
+
result: 'Sunny, 25°C',
|
|
56
|
+
},
|
|
57
|
+
],
|
|
58
|
+
},
|
|
59
|
+
// Now you can add a new user message
|
|
60
|
+
{ role: 'user', content: 'And in London?' },
|
|
61
|
+
];
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### 2. Handle Tool Approvals
|
|
65
|
+
|
|
66
|
+
If you are using the tool approval workflow, ensure that you include the `tool-approval-response`.
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
const messages = [
|
|
70
|
+
// ... assistant requests tool execution (needs approval)
|
|
71
|
+
{
|
|
72
|
+
role: 'tool',
|
|
73
|
+
content: [
|
|
74
|
+
{
|
|
75
|
+
type: 'tool-approval-response',
|
|
76
|
+
approvalId: 'approval_123',
|
|
77
|
+
approved: true, // or false
|
|
78
|
+
},
|
|
79
|
+
],
|
|
80
|
+
},
|
|
81
|
+
];
|
|
82
|
+
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ai",
|
|
3
|
-
"version": "6.0.
|
|
3
|
+
"version": "6.0.43",
|
|
4
4
|
"description": "AI SDK by Vercel - The AI Toolkit for TypeScript and JavaScript",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
44
|
"@opentelemetry/api": "1.9.0",
|
|
45
|
-
"@ai-sdk/gateway": "3.0.
|
|
45
|
+
"@ai-sdk/gateway": "3.0.17",
|
|
46
46
|
"@ai-sdk/provider": "3.0.4",
|
|
47
47
|
"@ai-sdk/provider-utils": "4.0.8"
|
|
48
48
|
},
|
package/src/error/index.ts
CHANGED
|
@@ -19,6 +19,7 @@ export { InvalidStreamPartError } from './invalid-stream-part-error';
|
|
|
19
19
|
export { InvalidToolApprovalError } from './invalid-tool-approval-error';
|
|
20
20
|
export { InvalidToolInputError } from './invalid-tool-input-error';
|
|
21
21
|
export { ToolCallNotFoundForApprovalError } from './tool-call-not-found-for-approval-error';
|
|
22
|
+
export { MissingToolResultsError } from './missing-tool-result-error';
|
|
22
23
|
export { NoImageGeneratedError } from './no-image-generated-error';
|
|
23
24
|
export { NoObjectGeneratedError } from './no-object-generated-error';
|
|
24
25
|
export { NoOutputGeneratedError } from './no-output-generated-error';
|
|
@@ -27,7 +28,6 @@ export { NoSuchToolError } from './no-such-tool-error';
|
|
|
27
28
|
export { ToolCallRepairError } from './tool-call-repair-error';
|
|
28
29
|
export { UnsupportedModelVersionError } from './unsupported-model-version-error';
|
|
29
30
|
export { UIMessageStreamError } from './ui-message-stream-error';
|
|
30
|
-
|
|
31
31
|
export { InvalidDataContentError } from '../prompt/invalid-data-content-error';
|
|
32
32
|
export { InvalidMessageRoleError } from '../prompt/invalid-message-role-error';
|
|
33
33
|
export { MessageConversionError } from '../prompt/message-conversion-error';
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { AISDKError } from '@ai-sdk/provider';
|
|
2
|
+
|
|
3
|
+
const name = 'AI_MissingToolResultsError';
|
|
4
|
+
const marker = `vercel.ai.error.${name}`;
|
|
5
|
+
const symbol = Symbol.for(marker);
|
|
6
|
+
|
|
7
|
+
export class MissingToolResultsError extends AISDKError {
|
|
8
|
+
private readonly [symbol] = true;
|
|
9
|
+
|
|
10
|
+
readonly toolCallIds: string[];
|
|
11
|
+
|
|
12
|
+
constructor({ toolCallIds }: { toolCallIds: string[] }) {
|
|
13
|
+
super({
|
|
14
|
+
name,
|
|
15
|
+
message: `Tool result${
|
|
16
|
+
toolCallIds.length > 1 ? 's are' : ' is'
|
|
17
|
+
} missing for tool call${toolCallIds.length > 1 ? 's' : ''} ${toolCallIds.join(
|
|
18
|
+
', ',
|
|
19
|
+
)}.`,
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
this.toolCallIds = toolCallIds;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
static isInstance(error: unknown): error is MissingToolResultsError {
|
|
26
|
+
return AISDKError.hasMarker(error, marker);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
|
2
|
+
|
|
3
|
+
exports[`tool validation > should pass validation for provider-executed tools (deferred results) 1`] = `
|
|
4
|
+
[
|
|
5
|
+
{
|
|
6
|
+
"content": [
|
|
7
|
+
{
|
|
8
|
+
"input": {
|
|
9
|
+
"code": "print("hello")",
|
|
10
|
+
},
|
|
11
|
+
"providerExecuted": true,
|
|
12
|
+
"providerOptions": undefined,
|
|
13
|
+
"toolCallId": "call_1",
|
|
14
|
+
"toolName": "code_interpreter",
|
|
15
|
+
"type": "tool-call",
|
|
16
|
+
},
|
|
17
|
+
],
|
|
18
|
+
"providerOptions": undefined,
|
|
19
|
+
"role": "assistant",
|
|
20
|
+
},
|
|
21
|
+
]
|
|
22
|
+
`;
|
|
23
|
+
|
|
24
|
+
exports[`tool validation > should pass validation for tool-approval-response 1`] = `
|
|
25
|
+
[
|
|
26
|
+
{
|
|
27
|
+
"content": [
|
|
28
|
+
{
|
|
29
|
+
"input": {
|
|
30
|
+
"action": "delete_db",
|
|
31
|
+
},
|
|
32
|
+
"providerExecuted": undefined,
|
|
33
|
+
"providerOptions": undefined,
|
|
34
|
+
"toolCallId": "call_to_approve",
|
|
35
|
+
"toolName": "dangerous_action",
|
|
36
|
+
"type": "tool-call",
|
|
37
|
+
},
|
|
38
|
+
],
|
|
39
|
+
"providerOptions": undefined,
|
|
40
|
+
"role": "assistant",
|
|
41
|
+
},
|
|
42
|
+
]
|
|
43
|
+
`;
|
|
44
|
+
|
|
45
|
+
exports[`tool validation > should preserve provider-executed tool-approval-response 1`] = `
|
|
46
|
+
[
|
|
47
|
+
{
|
|
48
|
+
"content": [
|
|
49
|
+
{
|
|
50
|
+
"input": {
|
|
51
|
+
"action": "execute",
|
|
52
|
+
},
|
|
53
|
+
"providerExecuted": true,
|
|
54
|
+
"providerOptions": undefined,
|
|
55
|
+
"toolCallId": "call_provider_executed",
|
|
56
|
+
"toolName": "mcp_tool",
|
|
57
|
+
"type": "tool-call",
|
|
58
|
+
},
|
|
59
|
+
],
|
|
60
|
+
"providerOptions": undefined,
|
|
61
|
+
"role": "assistant",
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
"content": [
|
|
65
|
+
{
|
|
66
|
+
"approvalId": "approval_provider",
|
|
67
|
+
"approved": true,
|
|
68
|
+
"reason": undefined,
|
|
69
|
+
"type": "tool-approval-response",
|
|
70
|
+
},
|
|
71
|
+
],
|
|
72
|
+
"providerOptions": undefined,
|
|
73
|
+
"role": "tool",
|
|
74
|
+
},
|
|
75
|
+
]
|
|
76
|
+
`;
|
|
@@ -29,6 +29,7 @@ import { convertToLanguageModelV3DataContent } from './data-content';
|
|
|
29
29
|
import { InvalidMessageRoleError } from './invalid-message-role-error';
|
|
30
30
|
import { StandardizedPrompt } from './standardize-prompt';
|
|
31
31
|
import { asArray } from '../util/as-array';
|
|
32
|
+
import { MissingToolResultsError } from '../error/missing-tool-result-error';
|
|
32
33
|
|
|
33
34
|
export async function convertToLanguageModelPrompt({
|
|
34
35
|
prompt,
|
|
@@ -45,6 +46,38 @@ export async function convertToLanguageModelPrompt({
|
|
|
45
46
|
supportedUrls,
|
|
46
47
|
);
|
|
47
48
|
|
|
49
|
+
const approvalIdToToolCallId = new Map<string, string>();
|
|
50
|
+
for (const message of prompt.messages) {
|
|
51
|
+
if (message.role === 'assistant' && Array.isArray(message.content)) {
|
|
52
|
+
for (const part of message.content) {
|
|
53
|
+
if (
|
|
54
|
+
part.type === 'tool-approval-request' &&
|
|
55
|
+
'approvalId' in part &&
|
|
56
|
+
'toolCallId' in part
|
|
57
|
+
) {
|
|
58
|
+
approvalIdToToolCallId.set(
|
|
59
|
+
part.approvalId as string,
|
|
60
|
+
part.toolCallId as string,
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const approvedToolCallIds = new Set<string>();
|
|
68
|
+
for (const message of prompt.messages) {
|
|
69
|
+
if (message.role === 'tool') {
|
|
70
|
+
for (const part of message.content) {
|
|
71
|
+
if (part.type === 'tool-approval-response') {
|
|
72
|
+
const toolCallId = approvalIdToToolCallId.get(part.approvalId);
|
|
73
|
+
if (toolCallId) {
|
|
74
|
+
approvedToolCallIds.add(toolCallId);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
48
81
|
const messages = [
|
|
49
82
|
...(prompt.system != null
|
|
50
83
|
? typeof prompt.system === 'string'
|
|
@@ -76,7 +109,58 @@ export async function convertToLanguageModelPrompt({
|
|
|
76
109
|
}
|
|
77
110
|
}
|
|
78
111
|
|
|
79
|
-
|
|
112
|
+
const toolCallIds = new Set<string>();
|
|
113
|
+
|
|
114
|
+
for (const message of combinedMessages) {
|
|
115
|
+
switch (message.role) {
|
|
116
|
+
case 'assistant': {
|
|
117
|
+
for (const content of message.content) {
|
|
118
|
+
if (content.type === 'tool-call' && !content.providerExecuted) {
|
|
119
|
+
toolCallIds.add(content.toolCallId);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
break;
|
|
123
|
+
}
|
|
124
|
+
case 'tool': {
|
|
125
|
+
for (const content of message.content) {
|
|
126
|
+
if (content.type === 'tool-result') {
|
|
127
|
+
toolCallIds.delete(content.toolCallId);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
break;
|
|
131
|
+
}
|
|
132
|
+
case 'user':
|
|
133
|
+
case 'system':
|
|
134
|
+
// remove approved tool calls from the set before checking:
|
|
135
|
+
for (const id of approvedToolCallIds) {
|
|
136
|
+
toolCallIds.delete(id);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (toolCallIds.size > 0) {
|
|
140
|
+
throw new MissingToolResultsError({
|
|
141
|
+
toolCallIds: Array.from(toolCallIds),
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
break;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// remove approved tool calls from the set before checking:
|
|
149
|
+
for (const id of approvedToolCallIds) {
|
|
150
|
+
toolCallIds.delete(id);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (toolCallIds.size > 0) {
|
|
154
|
+
throw new MissingToolResultsError({ toolCallIds: Array.from(toolCallIds) });
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return combinedMessages.filter(
|
|
158
|
+
// Filter out empty tool messages (e.g. if they only contained
|
|
159
|
+
// tool-approval-response parts that were removed).
|
|
160
|
+
// This prevents sending invalid empty messages to the provider.
|
|
161
|
+
// Note: provider-executed tool-approval-response parts are preserved.
|
|
162
|
+
message => message.role !== 'tool' || message.content.length > 0,
|
|
163
|
+
);
|
|
80
164
|
}
|
|
81
165
|
|
|
82
166
|
/**
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { convertToLanguageModelPrompt } from './convert-to-language-model-prompt';
|
|
3
|
+
import { MissingToolResultsError } from '../error/missing-tool-result-error';
|
|
4
|
+
|
|
5
|
+
describe('tool validation', () => {
|
|
6
|
+
it('should pass validation for provider-executed tools (deferred results)', async () => {
|
|
7
|
+
const result = await convertToLanguageModelPrompt({
|
|
8
|
+
prompt: {
|
|
9
|
+
messages: [
|
|
10
|
+
{
|
|
11
|
+
role: 'assistant',
|
|
12
|
+
content: [
|
|
13
|
+
{
|
|
14
|
+
type: 'tool-call',
|
|
15
|
+
toolCallId: 'call_1',
|
|
16
|
+
toolName: 'code_interpreter',
|
|
17
|
+
input: { code: 'print("hello")' },
|
|
18
|
+
providerExecuted: true,
|
|
19
|
+
},
|
|
20
|
+
],
|
|
21
|
+
},
|
|
22
|
+
],
|
|
23
|
+
},
|
|
24
|
+
supportedUrls: {},
|
|
25
|
+
download: undefined,
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
expect(result).toMatchSnapshot();
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('should pass validation for tool-approval-response', async () => {
|
|
32
|
+
const result = await convertToLanguageModelPrompt({
|
|
33
|
+
prompt: {
|
|
34
|
+
messages: [
|
|
35
|
+
{
|
|
36
|
+
role: 'assistant',
|
|
37
|
+
content: [
|
|
38
|
+
{
|
|
39
|
+
type: 'tool-call',
|
|
40
|
+
toolCallId: 'call_to_approve',
|
|
41
|
+
toolName: 'dangerous_action',
|
|
42
|
+
input: { action: 'delete_db' },
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
type: 'tool-approval-request',
|
|
46
|
+
toolCallId: 'call_to_approve',
|
|
47
|
+
approvalId: 'approval_123',
|
|
48
|
+
toolName: 'dangerous_action',
|
|
49
|
+
input: { action: 'delete_db' },
|
|
50
|
+
} as any,
|
|
51
|
+
],
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
role: 'tool',
|
|
55
|
+
content: [
|
|
56
|
+
{
|
|
57
|
+
type: 'tool-approval-response',
|
|
58
|
+
approvalId: 'approval_123',
|
|
59
|
+
approved: true,
|
|
60
|
+
} as any,
|
|
61
|
+
],
|
|
62
|
+
},
|
|
63
|
+
],
|
|
64
|
+
},
|
|
65
|
+
supportedUrls: {},
|
|
66
|
+
download: undefined,
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
expect(result).toMatchSnapshot();
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it('should preserve provider-executed tool-approval-response', async () => {
|
|
73
|
+
const result = await convertToLanguageModelPrompt({
|
|
74
|
+
prompt: {
|
|
75
|
+
messages: [
|
|
76
|
+
{
|
|
77
|
+
role: 'assistant',
|
|
78
|
+
content: [
|
|
79
|
+
{
|
|
80
|
+
type: 'tool-call',
|
|
81
|
+
toolCallId: 'call_provider_executed',
|
|
82
|
+
toolName: 'mcp_tool',
|
|
83
|
+
input: { action: 'execute' },
|
|
84
|
+
providerExecuted: true,
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
type: 'tool-approval-request',
|
|
88
|
+
toolCallId: 'call_provider_executed',
|
|
89
|
+
approvalId: 'approval_provider',
|
|
90
|
+
toolName: 'mcp_tool',
|
|
91
|
+
input: { action: 'execute' },
|
|
92
|
+
} as any,
|
|
93
|
+
],
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
role: 'tool',
|
|
97
|
+
content: [
|
|
98
|
+
{
|
|
99
|
+
type: 'tool-approval-response',
|
|
100
|
+
approvalId: 'approval_provider',
|
|
101
|
+
approved: true,
|
|
102
|
+
providerExecuted: true,
|
|
103
|
+
},
|
|
104
|
+
],
|
|
105
|
+
},
|
|
106
|
+
],
|
|
107
|
+
},
|
|
108
|
+
supportedUrls: {},
|
|
109
|
+
download: undefined,
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
expect(result).toMatchSnapshot();
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it('should throw error for actual missing results', async () => {
|
|
116
|
+
await expect(async () => {
|
|
117
|
+
await convertToLanguageModelPrompt({
|
|
118
|
+
prompt: {
|
|
119
|
+
messages: [
|
|
120
|
+
{
|
|
121
|
+
role: 'assistant',
|
|
122
|
+
content: [
|
|
123
|
+
{
|
|
124
|
+
type: 'tool-call',
|
|
125
|
+
toolCallId: 'call_missing_result',
|
|
126
|
+
toolName: 'regular_tool',
|
|
127
|
+
input: {},
|
|
128
|
+
},
|
|
129
|
+
],
|
|
130
|
+
},
|
|
131
|
+
],
|
|
132
|
+
},
|
|
133
|
+
supportedUrls: {},
|
|
134
|
+
download: undefined,
|
|
135
|
+
});
|
|
136
|
+
}).rejects.toThrow(MissingToolResultsError);
|
|
137
|
+
});
|
|
138
|
+
});
|