@tanstack/ai 0.8.1 → 0.9.2
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/README.md +9 -5
- package/dist/esm/activities/chat/index.js +74 -4
- package/dist/esm/activities/chat/index.js.map +1 -1
- package/dist/esm/activities/chat/tools/lazy-tool-manager.d.ts +57 -0
- package/dist/esm/activities/chat/tools/lazy-tool-manager.js +159 -0
- package/dist/esm/activities/chat/tools/lazy-tool-manager.js.map +1 -0
- package/dist/esm/activities/chat/tools/tool-calls.js +3 -0
- package/dist/esm/activities/chat/tools/tool-calls.js.map +1 -1
- package/dist/esm/activities/chat/tools/tool-definition.d.ts +2 -0
- package/dist/esm/activities/chat/tools/tool-definition.js.map +1 -1
- package/dist/esm/activities/generateVideo/index.js +5 -4
- package/dist/esm/activities/generateVideo/index.js.map +1 -1
- package/dist/esm/types.d.ts +6 -0
- package/package.json +2 -2
- package/src/activities/chat/index.ts +88 -5
- package/src/activities/chat/tools/lazy-tool-manager.ts +254 -0
- package/src/activities/chat/tools/tool-calls.ts +3 -0
- package/src/activities/chat/tools/tool-definition.ts +2 -0
- package/src/activities/generateVideo/index.ts +7 -7
- package/src/types.ts +7 -0
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
import { devtoolsMiddleware } from '@tanstack/ai-event-client'
|
|
9
9
|
import { streamToText } from '../../stream-to-response.js'
|
|
10
|
+
import { LazyToolManager } from './tools/lazy-tool-manager'
|
|
10
11
|
import {
|
|
11
12
|
MiddlewareAbortError,
|
|
12
13
|
ToolCallManager,
|
|
@@ -237,7 +238,8 @@ class TextEngine<
|
|
|
237
238
|
private systemPrompts: Array<string>
|
|
238
239
|
private tools: Array<Tool>
|
|
239
240
|
private readonly loopStrategy: AgentLoopStrategy
|
|
240
|
-
private
|
|
241
|
+
private toolCallManager: ToolCallManager
|
|
242
|
+
private readonly lazyToolManager: LazyToolManager
|
|
241
243
|
private readonly initialMessageCount: number
|
|
242
244
|
private readonly requestId: string
|
|
243
245
|
private readonly streamId: string
|
|
@@ -273,10 +275,8 @@ class TextEngine<
|
|
|
273
275
|
this.adapter = config.adapter
|
|
274
276
|
this.params = config.params
|
|
275
277
|
this.systemPrompts = config.params.systemPrompts || []
|
|
276
|
-
this.tools = config.params.tools || []
|
|
277
278
|
this.loopStrategy =
|
|
278
279
|
config.params.agentLoopStrategy || maxIterationsStrategy(5)
|
|
279
|
-
this.toolCallManager = new ToolCallManager(this.tools)
|
|
280
280
|
this.initialMessageCount = config.params.messages.length
|
|
281
281
|
|
|
282
282
|
// Extract client state (approvals, client tool results) from original messages BEFORE conversion
|
|
@@ -293,6 +293,14 @@ class TextEngine<
|
|
|
293
293
|
this.messages = convertMessagesToModelMessages(
|
|
294
294
|
config.params.messages as Array<any>,
|
|
295
295
|
)
|
|
296
|
+
|
|
297
|
+
// Initialize lazy tool manager after messages are converted (needs message history for scanning)
|
|
298
|
+
this.lazyToolManager = new LazyToolManager(
|
|
299
|
+
config.params.tools || [],
|
|
300
|
+
this.messages,
|
|
301
|
+
)
|
|
302
|
+
this.tools = this.lazyToolManager.getActiveTools()
|
|
303
|
+
this.toolCallManager = new ToolCallManager(this.tools)
|
|
296
304
|
this.requestId = this.createId('chat')
|
|
297
305
|
this.streamId = this.createId('stream')
|
|
298
306
|
this.effectiveRequest = config.params.abortController
|
|
@@ -643,10 +651,42 @@ class TextEngine<
|
|
|
643
651
|
|
|
644
652
|
const finishEvent = this.createSyntheticFinishedEvent()
|
|
645
653
|
|
|
654
|
+
// Handle undiscovered lazy tool calls with self-correcting error messages
|
|
655
|
+
const undiscoveredLazyResults: Array<ToolResult> = []
|
|
656
|
+
const executablePendingCalls = pendingToolCalls.filter((tc) => {
|
|
657
|
+
if (this.lazyToolManager.isUndiscoveredLazyTool(tc.function.name)) {
|
|
658
|
+
undiscoveredLazyResults.push({
|
|
659
|
+
toolCallId: tc.id,
|
|
660
|
+
toolName: tc.function.name,
|
|
661
|
+
result: {
|
|
662
|
+
error: this.lazyToolManager.getUndiscoveredToolError(
|
|
663
|
+
tc.function.name,
|
|
664
|
+
),
|
|
665
|
+
},
|
|
666
|
+
state: 'output-error',
|
|
667
|
+
})
|
|
668
|
+
return false
|
|
669
|
+
}
|
|
670
|
+
return true
|
|
671
|
+
})
|
|
672
|
+
|
|
673
|
+
if (undiscoveredLazyResults.length > 0) {
|
|
674
|
+
for (const chunk of this.buildToolResultChunks(
|
|
675
|
+
undiscoveredLazyResults,
|
|
676
|
+
finishEvent,
|
|
677
|
+
)) {
|
|
678
|
+
yield chunk
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
if (executablePendingCalls.length === 0) {
|
|
683
|
+
return 'continue'
|
|
684
|
+
}
|
|
685
|
+
|
|
646
686
|
const { approvals, clientToolResults } = this.collectClientState()
|
|
647
687
|
|
|
648
688
|
const generator = executeToolCalls(
|
|
649
|
-
|
|
689
|
+
executablePendingCalls,
|
|
650
690
|
this.tools,
|
|
651
691
|
approvals,
|
|
652
692
|
clientToolResults,
|
|
@@ -750,12 +790,47 @@ class TextEngine<
|
|
|
750
790
|
|
|
751
791
|
this.addAssistantToolCallMessage(toolCalls)
|
|
752
792
|
|
|
793
|
+
// Handle undiscovered lazy tool calls with self-correcting error messages
|
|
794
|
+
const undiscoveredLazyResults: Array<ToolResult> = []
|
|
795
|
+
const executableToolCalls = toolCalls.filter((tc) => {
|
|
796
|
+
if (this.lazyToolManager.isUndiscoveredLazyTool(tc.function.name)) {
|
|
797
|
+
undiscoveredLazyResults.push({
|
|
798
|
+
toolCallId: tc.id,
|
|
799
|
+
toolName: tc.function.name,
|
|
800
|
+
result: {
|
|
801
|
+
error: this.lazyToolManager.getUndiscoveredToolError(
|
|
802
|
+
tc.function.name,
|
|
803
|
+
),
|
|
804
|
+
},
|
|
805
|
+
state: 'output-error',
|
|
806
|
+
})
|
|
807
|
+
return false
|
|
808
|
+
}
|
|
809
|
+
return true
|
|
810
|
+
})
|
|
811
|
+
|
|
812
|
+
if (undiscoveredLazyResults.length > 0) {
|
|
813
|
+
const finishEvt = this.finishedEvent!
|
|
814
|
+
for (const chunk of this.buildToolResultChunks(
|
|
815
|
+
undiscoveredLazyResults,
|
|
816
|
+
finishEvt,
|
|
817
|
+
)) {
|
|
818
|
+
yield chunk
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
if (executableToolCalls.length === 0) {
|
|
823
|
+
// All tool calls were undiscovered lazy tools — errors emitted, continue loop
|
|
824
|
+
this.toolCallManager.clear()
|
|
825
|
+
this.setToolPhase('continue')
|
|
826
|
+
return
|
|
827
|
+
}
|
|
753
828
|
this.middlewareCtx.phase = 'beforeTools'
|
|
754
829
|
|
|
755
830
|
const { approvals, clientToolResults } = this.collectClientState()
|
|
756
831
|
|
|
757
832
|
const generator = executeToolCalls(
|
|
758
|
-
|
|
833
|
+
executableToolCalls,
|
|
759
834
|
this.tools,
|
|
760
835
|
approvals,
|
|
761
836
|
clientToolResults,
|
|
@@ -842,6 +917,14 @@ class TextEngine<
|
|
|
842
917
|
yield chunk
|
|
843
918
|
}
|
|
844
919
|
|
|
920
|
+
// Refresh tools if lazy tools were discovered in this batch
|
|
921
|
+
if (this.lazyToolManager.hasNewlyDiscoveredTools()) {
|
|
922
|
+
this.tools = this.lazyToolManager.getActiveTools()
|
|
923
|
+
this.toolCallManager = new ToolCallManager(this.tools)
|
|
924
|
+
this.setToolPhase('continue')
|
|
925
|
+
return
|
|
926
|
+
}
|
|
927
|
+
|
|
845
928
|
this.toolCallManager.clear()
|
|
846
929
|
|
|
847
930
|
this.setToolPhase('continue')
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
import { convertSchemaToJsonSchema } from './schema-converter'
|
|
2
|
+
import type { Tool } from '../../../types'
|
|
3
|
+
|
|
4
|
+
const DISCOVERY_TOOL_NAME = '__lazy__tool__discovery__'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Manages lazy tool discovery for the chat agent loop.
|
|
8
|
+
*
|
|
9
|
+
* Lazy tools are not sent to the LLM initially. Instead, a synthetic
|
|
10
|
+
* "discovery tool" is provided that lets the LLM discover lazy tools
|
|
11
|
+
* by name, receiving their full descriptions and schemas on demand.
|
|
12
|
+
*/
|
|
13
|
+
export class LazyToolManager {
|
|
14
|
+
private readonly eagerTools: ReadonlyArray<Tool>
|
|
15
|
+
private readonly lazyToolMap: Map<string, Tool>
|
|
16
|
+
private readonly discoveredTools: Set<string>
|
|
17
|
+
private hasNewDiscoveries: boolean
|
|
18
|
+
private readonly discoveryTool: Tool | null
|
|
19
|
+
|
|
20
|
+
constructor(
|
|
21
|
+
tools: ReadonlyArray<Tool>,
|
|
22
|
+
messages: ReadonlyArray<{
|
|
23
|
+
role: string
|
|
24
|
+
content?: any
|
|
25
|
+
toolCalls?: Array<{
|
|
26
|
+
id: string
|
|
27
|
+
type: string
|
|
28
|
+
function: { name: string; arguments: string }
|
|
29
|
+
}>
|
|
30
|
+
toolCallId?: string
|
|
31
|
+
}>,
|
|
32
|
+
) {
|
|
33
|
+
const eager: Array<Tool> = []
|
|
34
|
+
this.lazyToolMap = new Map()
|
|
35
|
+
this.discoveredTools = new Set()
|
|
36
|
+
this.hasNewDiscoveries = false
|
|
37
|
+
|
|
38
|
+
// Separate tools into eager and lazy
|
|
39
|
+
for (const tool of tools) {
|
|
40
|
+
if (tool.lazy) {
|
|
41
|
+
this.lazyToolMap.set(tool.name, tool)
|
|
42
|
+
} else {
|
|
43
|
+
eager.push(tool)
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
this.eagerTools = eager
|
|
47
|
+
|
|
48
|
+
// If no lazy tools, no discovery tool needed
|
|
49
|
+
if (this.lazyToolMap.size === 0) {
|
|
50
|
+
this.discoveryTool = null
|
|
51
|
+
return
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Scan message history to pre-populate discoveredTools
|
|
55
|
+
this.scanMessageHistory(messages)
|
|
56
|
+
|
|
57
|
+
// Create the synthetic discovery tool
|
|
58
|
+
this.discoveryTool = this.createDiscoveryTool()
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Returns the set of tools that should be sent to the LLM:
|
|
63
|
+
* eager tools + discovered lazy tools + discovery tool (if undiscovered tools remain).
|
|
64
|
+
* Resets the hasNewDiscoveries flag.
|
|
65
|
+
*/
|
|
66
|
+
getActiveTools(): Array<Tool> {
|
|
67
|
+
this.hasNewDiscoveries = false
|
|
68
|
+
|
|
69
|
+
const active: Array<Tool> = [...this.eagerTools]
|
|
70
|
+
|
|
71
|
+
// Add discovered lazy tools
|
|
72
|
+
for (const name of this.discoveredTools) {
|
|
73
|
+
const tool = this.lazyToolMap.get(name)
|
|
74
|
+
if (tool) {
|
|
75
|
+
active.push(tool)
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Add discovery tool if there are still undiscovered lazy tools
|
|
80
|
+
if (
|
|
81
|
+
this.discoveryTool &&
|
|
82
|
+
this.discoveredTools.size < this.lazyToolMap.size
|
|
83
|
+
) {
|
|
84
|
+
active.push(this.discoveryTool)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return active
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Returns whether new tools have been discovered since the last getActiveTools() call.
|
|
92
|
+
*/
|
|
93
|
+
hasNewlyDiscoveredTools(): boolean {
|
|
94
|
+
return this.hasNewDiscoveries
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Returns true if the given name is a lazy tool that has not yet been discovered.
|
|
99
|
+
*/
|
|
100
|
+
isUndiscoveredLazyTool(name: string): boolean {
|
|
101
|
+
return this.lazyToolMap.has(name) && !this.discoveredTools.has(name)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Returns a helpful error message for when an undiscovered lazy tool is called.
|
|
106
|
+
*/
|
|
107
|
+
getUndiscoveredToolError(name: string): string {
|
|
108
|
+
return `Error: Tool '${name}' must be discovered first. Call ${DISCOVERY_TOOL_NAME} with toolNames: ['${name}'] to discover it.`
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Scans message history to find previously discovered lazy tools.
|
|
113
|
+
* Looks for assistant messages with discovery tool calls and their
|
|
114
|
+
* corresponding tool result messages.
|
|
115
|
+
*/
|
|
116
|
+
private scanMessageHistory(
|
|
117
|
+
messages: ReadonlyArray<{
|
|
118
|
+
role: string
|
|
119
|
+
content?: any
|
|
120
|
+
toolCalls?: Array<{
|
|
121
|
+
id: string
|
|
122
|
+
type: string
|
|
123
|
+
function: { name: string; arguments: string }
|
|
124
|
+
}>
|
|
125
|
+
toolCallId?: string
|
|
126
|
+
}>,
|
|
127
|
+
): void {
|
|
128
|
+
// Collect tool call IDs for discovery tool invocations
|
|
129
|
+
const discoveryCallIds = new Set<string>()
|
|
130
|
+
|
|
131
|
+
for (const msg of messages) {
|
|
132
|
+
if (msg.role === 'assistant' && msg.toolCalls) {
|
|
133
|
+
for (const tc of msg.toolCalls) {
|
|
134
|
+
if (tc.function.name === DISCOVERY_TOOL_NAME) {
|
|
135
|
+
discoveryCallIds.add(tc.id)
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
if (discoveryCallIds.size === 0) return
|
|
142
|
+
|
|
143
|
+
// Find corresponding tool result messages
|
|
144
|
+
for (const msg of messages) {
|
|
145
|
+
if (
|
|
146
|
+
msg.role === 'tool' &&
|
|
147
|
+
msg.toolCallId &&
|
|
148
|
+
discoveryCallIds.has(msg.toolCallId)
|
|
149
|
+
) {
|
|
150
|
+
try {
|
|
151
|
+
const content =
|
|
152
|
+
typeof msg.content === 'string'
|
|
153
|
+
? msg.content
|
|
154
|
+
: JSON.stringify(msg.content)
|
|
155
|
+
const parsed = JSON.parse(content)
|
|
156
|
+
if (parsed && Array.isArray(parsed.tools)) {
|
|
157
|
+
for (const tool of parsed.tools) {
|
|
158
|
+
if (
|
|
159
|
+
tool &&
|
|
160
|
+
typeof tool.name === 'string' &&
|
|
161
|
+
this.lazyToolMap.has(tool.name)
|
|
162
|
+
) {
|
|
163
|
+
this.discoveredTools.add(tool.name)
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
} catch {
|
|
168
|
+
// Malformed JSON — skip gracefully
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Creates the synthetic discovery tool that the LLM can call
|
|
176
|
+
* to discover lazy tools' descriptions and schemas.
|
|
177
|
+
*/
|
|
178
|
+
private createDiscoveryTool(): Tool {
|
|
179
|
+
const undiscoveredNames = (): Array<string> => {
|
|
180
|
+
const names: Array<string> = []
|
|
181
|
+
for (const [name] of this.lazyToolMap) {
|
|
182
|
+
if (!this.discoveredTools.has(name)) {
|
|
183
|
+
names.push(name)
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
return names
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const lazyToolMap = this.lazyToolMap
|
|
190
|
+
|
|
191
|
+
// Build the static description with all lazy tool names
|
|
192
|
+
const allLazyNames = Array.from(this.lazyToolMap.keys())
|
|
193
|
+
const description = `You have access to additional tools that can be discovered. Available tools: [${allLazyNames.join(', ')}]. Call this tool with a list of tool names to discover their full descriptions and argument schemas before using them.`
|
|
194
|
+
|
|
195
|
+
// Use the arrow function to capture `this` context
|
|
196
|
+
const manager = this
|
|
197
|
+
|
|
198
|
+
return {
|
|
199
|
+
name: DISCOVERY_TOOL_NAME,
|
|
200
|
+
description,
|
|
201
|
+
inputSchema: {
|
|
202
|
+
type: 'object',
|
|
203
|
+
properties: {
|
|
204
|
+
toolNames: {
|
|
205
|
+
type: 'array',
|
|
206
|
+
items: { type: 'string' },
|
|
207
|
+
description:
|
|
208
|
+
'List of tool names to discover. Each name must match one of the available tools.',
|
|
209
|
+
},
|
|
210
|
+
},
|
|
211
|
+
required: ['toolNames'],
|
|
212
|
+
},
|
|
213
|
+
execute: (args: { toolNames: Array<string> }) => {
|
|
214
|
+
const tools: Array<{
|
|
215
|
+
name: string
|
|
216
|
+
description: string
|
|
217
|
+
inputSchema?: any
|
|
218
|
+
}> = []
|
|
219
|
+
const errors: Array<string> = []
|
|
220
|
+
|
|
221
|
+
for (const name of args.toolNames) {
|
|
222
|
+
const tool = lazyToolMap.get(name)
|
|
223
|
+
if (tool) {
|
|
224
|
+
manager.discoveredTools.add(name)
|
|
225
|
+
manager.hasNewDiscoveries = true
|
|
226
|
+
const jsonSchema = tool.inputSchema
|
|
227
|
+
? convertSchemaToJsonSchema(tool.inputSchema)
|
|
228
|
+
: undefined
|
|
229
|
+
tools.push({
|
|
230
|
+
name: tool.name,
|
|
231
|
+
description: tool.description,
|
|
232
|
+
...(jsonSchema ? { inputSchema: jsonSchema } : {}),
|
|
233
|
+
})
|
|
234
|
+
} else {
|
|
235
|
+
errors.push(
|
|
236
|
+
`Unknown tool: '${name}'. Available tools: [${undiscoveredNames().join(', ')}]`,
|
|
237
|
+
)
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
const result: {
|
|
242
|
+
tools: typeof tools
|
|
243
|
+
errors?: Array<string>
|
|
244
|
+
} = { tools }
|
|
245
|
+
|
|
246
|
+
if (errors.length > 0) {
|
|
247
|
+
result.errors = errors
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
return result
|
|
251
|
+
},
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
@@ -32,6 +32,7 @@ export interface ClientTool<
|
|
|
32
32
|
inputSchema?: TInput
|
|
33
33
|
outputSchema?: TOutput
|
|
34
34
|
needsApproval?: boolean
|
|
35
|
+
lazy?: boolean
|
|
35
36
|
metadata?: Record<string, unknown>
|
|
36
37
|
execute?: (
|
|
37
38
|
args: InferSchemaType<TInput>,
|
|
@@ -96,6 +97,7 @@ export interface ToolDefinitionConfig<
|
|
|
96
97
|
inputSchema?: TInput
|
|
97
98
|
outputSchema?: TOutput
|
|
98
99
|
needsApproval?: boolean
|
|
100
|
+
lazy?: boolean
|
|
99
101
|
metadata?: Record<string, unknown>
|
|
100
102
|
}
|
|
101
103
|
|
|
@@ -427,25 +427,25 @@ export async function getVideoJobStatus<
|
|
|
427
427
|
url: urlResult.url,
|
|
428
428
|
}
|
|
429
429
|
} catch (error) {
|
|
430
|
+
const errorMessage =
|
|
431
|
+
error instanceof Error ? error.message : 'Failed to get video URL'
|
|
430
432
|
aiEventClient.emit('video:request:completed', {
|
|
431
433
|
requestId,
|
|
432
434
|
provider: adapter.name,
|
|
433
435
|
model: adapter.model,
|
|
434
436
|
requestType: 'status',
|
|
435
437
|
jobId,
|
|
436
|
-
status:
|
|
438
|
+
status: 'failed',
|
|
437
439
|
progress: statusResult.progress,
|
|
438
|
-
error:
|
|
439
|
-
error instanceof Error ? error.message : 'Failed to get video URL',
|
|
440
|
+
error: errorMessage,
|
|
440
441
|
duration: Date.now() - startTime,
|
|
441
442
|
timestamp: Date.now(),
|
|
442
443
|
})
|
|
443
|
-
//
|
|
444
|
+
// Provider reported completed but result fetch failed — treat as failed
|
|
444
445
|
return {
|
|
445
|
-
status:
|
|
446
|
+
status: 'failed' as const,
|
|
446
447
|
progress: statusResult.progress,
|
|
447
|
-
error:
|
|
448
|
-
error instanceof Error ? error.message : 'Failed to get video URL',
|
|
448
|
+
error: errorMessage,
|
|
449
449
|
}
|
|
450
450
|
}
|
|
451
451
|
}
|
package/src/types.ts
CHANGED
|
@@ -91,6 +91,8 @@ export interface ToolCall {
|
|
|
91
91
|
name: string
|
|
92
92
|
arguments: string // JSON string
|
|
93
93
|
}
|
|
94
|
+
/** Provider-specific metadata to carry through the tool call lifecycle */
|
|
95
|
+
providerMetadata?: Record<string, unknown>
|
|
94
96
|
}
|
|
95
97
|
|
|
96
98
|
// ============================================================================
|
|
@@ -493,6 +495,9 @@ export interface Tool<
|
|
|
493
495
|
/** If true, tool execution requires user approval before running. Works with both server and client tools. */
|
|
494
496
|
needsApproval?: boolean
|
|
495
497
|
|
|
498
|
+
/** If true, this tool is lazy and will only be sent to the LLM after being discovered via the lazy tool discovery mechanism. Only meaningful when used with chat(). */
|
|
499
|
+
lazy?: boolean
|
|
500
|
+
|
|
496
501
|
/** Additional metadata for adapters or custom extensions */
|
|
497
502
|
metadata?: Record<string, any>
|
|
498
503
|
}
|
|
@@ -846,6 +851,8 @@ export interface ToolCallStartEvent extends BaseAGUIEvent {
|
|
|
846
851
|
parentMessageId?: string
|
|
847
852
|
/** Index for parallel tool calls */
|
|
848
853
|
index?: number
|
|
854
|
+
/** Provider-specific metadata to carry into the ToolCall */
|
|
855
|
+
providerMetadata?: Record<string, unknown>
|
|
849
856
|
}
|
|
850
857
|
|
|
851
858
|
/**
|