@falai/agent 0.9.0-alpha-2 → 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 +42 -34
- package/dist/cjs/src/core/Agent.d.ts +48 -44
- package/dist/cjs/src/core/Agent.d.ts.map +1 -1
- package/dist/cjs/src/core/Agent.js +151 -1110
- package/dist/cjs/src/core/Agent.js.map +1 -1
- package/dist/cjs/src/core/ResponseModal.d.ts +211 -0
- package/dist/cjs/src/core/ResponseModal.d.ts.map +1 -0
- package/dist/cjs/src/core/ResponseModal.js +1394 -0
- package/dist/cjs/src/core/ResponseModal.js.map +1 -0
- package/dist/cjs/src/core/ResponsePipeline.d.ts +8 -4
- package/dist/cjs/src/core/ResponsePipeline.d.ts.map +1 -1
- package/dist/cjs/src/core/ResponsePipeline.js +48 -20
- package/dist/cjs/src/core/ResponsePipeline.js.map +1 -1
- package/dist/cjs/src/core/Route.d.ts +12 -5
- package/dist/cjs/src/core/Route.d.ts.map +1 -1
- package/dist/cjs/src/core/Route.js +26 -5
- package/dist/cjs/src/core/Route.js.map +1 -1
- package/dist/cjs/src/core/RoutingEngine.d.ts +5 -0
- package/dist/cjs/src/core/RoutingEngine.d.ts.map +1 -1
- package/dist/cjs/src/core/RoutingEngine.js +37 -25
- package/dist/cjs/src/core/RoutingEngine.js.map +1 -1
- package/dist/cjs/src/core/SessionManager.d.ts +9 -1
- package/dist/cjs/src/core/SessionManager.d.ts.map +1 -1
- package/dist/cjs/src/core/SessionManager.js +27 -5
- package/dist/cjs/src/core/SessionManager.js.map +1 -1
- package/dist/cjs/src/core/Step.d.ts +60 -7
- package/dist/cjs/src/core/Step.d.ts.map +1 -1
- package/dist/cjs/src/core/Step.js +151 -4
- package/dist/cjs/src/core/Step.js.map +1 -1
- package/dist/cjs/src/core/ToolManager.d.ts +234 -0
- package/dist/cjs/src/core/ToolManager.d.ts.map +1 -0
- package/dist/cjs/src/core/ToolManager.js +1117 -0
- package/dist/cjs/src/core/ToolManager.js.map +1 -0
- package/dist/cjs/src/index.d.ts +5 -4
- package/dist/cjs/src/index.d.ts.map +1 -1
- package/dist/cjs/src/index.js +11 -3
- package/dist/cjs/src/index.js.map +1 -1
- package/dist/cjs/src/types/agent.d.ts +2 -1
- package/dist/cjs/src/types/agent.d.ts.map +1 -1
- package/dist/cjs/src/types/ai.d.ts +1 -1
- package/dist/cjs/src/types/ai.d.ts.map +1 -1
- package/dist/cjs/src/types/index.d.ts +3 -2
- package/dist/cjs/src/types/index.d.ts.map +1 -1
- package/dist/cjs/src/types/index.js +3 -1
- package/dist/cjs/src/types/index.js.map +1 -1
- package/dist/cjs/src/types/route.d.ts +6 -4
- package/dist/cjs/src/types/route.d.ts.map +1 -1
- package/dist/cjs/src/types/tool.d.ts +84 -14
- package/dist/cjs/src/types/tool.d.ts.map +1 -1
- package/dist/cjs/src/types/tool.js +13 -0
- package/dist/cjs/src/types/tool.js.map +1 -1
- package/dist/cjs/src/utils/clone.d.ts.map +1 -1
- package/dist/cjs/src/utils/clone.js +0 -4
- package/dist/cjs/src/utils/clone.js.map +1 -1
- package/dist/cjs/src/utils/history.d.ts +30 -1
- package/dist/cjs/src/utils/history.d.ts.map +1 -1
- package/dist/cjs/src/utils/history.js +169 -23
- package/dist/cjs/src/utils/history.js.map +1 -1
- package/dist/cjs/src/utils/index.d.ts +1 -1
- package/dist/cjs/src/utils/index.d.ts.map +1 -1
- package/dist/cjs/src/utils/index.js +5 -1
- package/dist/cjs/src/utils/index.js.map +1 -1
- package/dist/src/core/Agent.d.ts +48 -44
- package/dist/src/core/Agent.d.ts.map +1 -1
- package/dist/src/core/Agent.js +152 -1111
- package/dist/src/core/Agent.js.map +1 -1
- package/dist/src/core/ResponseModal.d.ts +211 -0
- package/dist/src/core/ResponseModal.d.ts.map +1 -0
- package/dist/src/core/ResponseModal.js +1389 -0
- package/dist/src/core/ResponseModal.js.map +1 -0
- package/dist/src/core/ResponsePipeline.d.ts +8 -4
- package/dist/src/core/ResponsePipeline.d.ts.map +1 -1
- package/dist/src/core/ResponsePipeline.js +48 -20
- package/dist/src/core/ResponsePipeline.js.map +1 -1
- package/dist/src/core/Route.d.ts +12 -5
- package/dist/src/core/Route.d.ts.map +1 -1
- package/dist/src/core/Route.js +26 -5
- package/dist/src/core/Route.js.map +1 -1
- package/dist/src/core/RoutingEngine.d.ts +5 -0
- package/dist/src/core/RoutingEngine.d.ts.map +1 -1
- package/dist/src/core/RoutingEngine.js +37 -25
- package/dist/src/core/RoutingEngine.js.map +1 -1
- package/dist/src/core/SessionManager.d.ts +9 -1
- package/dist/src/core/SessionManager.d.ts.map +1 -1
- package/dist/src/core/SessionManager.js +27 -5
- package/dist/src/core/SessionManager.js.map +1 -1
- package/dist/src/core/Step.d.ts +60 -7
- package/dist/src/core/Step.d.ts.map +1 -1
- package/dist/src/core/Step.js +151 -4
- package/dist/src/core/Step.js.map +1 -1
- package/dist/src/core/ToolManager.d.ts +234 -0
- package/dist/src/core/ToolManager.d.ts.map +1 -0
- package/dist/src/core/ToolManager.js +1111 -0
- package/dist/src/core/ToolManager.js.map +1 -0
- package/dist/src/index.d.ts +5 -4
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +3 -2
- package/dist/src/index.js.map +1 -1
- package/dist/src/types/agent.d.ts +2 -1
- package/dist/src/types/agent.d.ts.map +1 -1
- package/dist/src/types/ai.d.ts +1 -1
- package/dist/src/types/ai.d.ts.map +1 -1
- package/dist/src/types/index.d.ts +3 -2
- package/dist/src/types/index.d.ts.map +1 -1
- package/dist/src/types/index.js +1 -0
- package/dist/src/types/index.js.map +1 -1
- package/dist/src/types/route.d.ts +6 -4
- package/dist/src/types/route.d.ts.map +1 -1
- package/dist/src/types/tool.d.ts +84 -14
- package/dist/src/types/tool.d.ts.map +1 -1
- package/dist/src/types/tool.js +12 -1
- package/dist/src/types/tool.js.map +1 -1
- package/dist/src/utils/clone.d.ts.map +1 -1
- package/dist/src/utils/clone.js +0 -4
- package/dist/src/utils/clone.js.map +1 -1
- package/dist/src/utils/history.d.ts +30 -1
- package/dist/src/utils/history.d.ts.map +1 -1
- package/dist/src/utils/history.js +165 -23
- package/dist/src/utils/history.js.map +1 -1
- package/dist/src/utils/index.d.ts +1 -1
- package/dist/src/utils/index.d.ts.map +1 -1
- package/dist/src/utils/index.js +1 -1
- package/dist/src/utils/index.js.map +1 -1
- package/docs/CONTRIBUTING.md +40 -0
- package/docs/README.md +14 -6
- package/docs/api/README.md +235 -45
- package/docs/api/overview.md +140 -33
- package/docs/core/agent/session-management.md +152 -5
- package/docs/core/ai-integration/response-processing.md +115 -4
- package/docs/core/conversation-flows/routes.md +130 -0
- package/docs/core/error-handling.md +638 -0
- package/docs/core/tools/tool-definition.md +684 -60
- package/docs/core/tools/tool-scoping.md +244 -53
- package/docs/guides/error-handling-patterns.md +578 -0
- package/docs/guides/getting-started/README.md +139 -28
- package/docs/guides/migration/README.md +72 -0
- package/docs/guides/migration/response-modal-refactor.md +518 -0
- package/examples/advanced-patterns/knowledge-based-agent.ts +6 -6
- package/examples/advanced-patterns/persistent-onboarding.ts +30 -43
- package/examples/advanced-patterns/streaming-responses.ts +169 -96
- package/examples/ai-providers/anthropic-integration.ts +9 -5
- package/examples/ai-providers/openai-integration.ts +11 -7
- package/examples/core-concepts/basic-agent.ts +106 -67
- package/examples/core-concepts/modern-streaming-api.ts +309 -0
- package/examples/core-concepts/schema-driven-extraction.ts +10 -7
- package/examples/core-concepts/session-management.ts +71 -18
- package/examples/integrations/healthcare-integration.ts +15 -29
- package/examples/integrations/server-session-management.ts +3 -3
- package/examples/persistence/memory-sessions.ts +3 -3
- package/examples/tools/basic-tools.ts +293 -89
- package/examples/tools/data-enrichment-tools.ts +185 -75
- package/package.json +1 -1
- package/src/core/Agent.ts +190 -1529
- package/src/core/ResponseModal.ts +1798 -0
- package/src/core/ResponsePipeline.ts +83 -57
- package/src/core/Route.ts +39 -12
- package/src/core/RoutingEngine.ts +46 -42
- package/src/core/SessionManager.ts +39 -7
- package/src/core/Step.ts +198 -20
- package/src/core/ToolManager.ts +1394 -0
- package/src/index.ts +19 -3
- package/src/types/agent.ts +2 -1
- package/src/types/ai.ts +1 -1
- package/src/types/index.ts +13 -2
- package/src/types/route.ts +6 -4
- package/src/types/tool.ts +116 -25
- package/src/utils/clone.ts +6 -8
- package/src/utils/history.ts +190 -27
- package/src/utils/index.ts +4 -0
- package/dist/cjs/src/core/ToolExecutor.d.ts +0 -45
- package/dist/cjs/src/core/ToolExecutor.d.ts.map +0 -1
- package/dist/cjs/src/core/ToolExecutor.js +0 -84
- package/dist/cjs/src/core/ToolExecutor.js.map +0 -1
- package/dist/src/core/ToolExecutor.d.ts +0 -45
- package/dist/src/core/ToolExecutor.d.ts.map +0 -1
- package/dist/src/core/ToolExecutor.js +0 -80
- package/dist/src/core/ToolExecutor.js.map +0 -1
- package/docs/core/tools/tool-execution.md +0 -815
- package/src/core/ToolExecutor.ts +0 -126
|
@@ -1,815 +0,0 @@
|
|
|
1
|
-
# Dynamic Tool Execution
|
|
2
|
-
|
|
3
|
-
@falai/agent provides a sophisticated tool execution system that enables AI agents to perform actions, access external data, and modify context dynamically during conversations. Unlike static tool calling, this system supports intelligent tool selection, context updates, and seamless integration with conversation flows.
|
|
4
|
-
|
|
5
|
-
## Overview
|
|
6
|
-
|
|
7
|
-
The tool execution system provides:
|
|
8
|
-
|
|
9
|
-
- **Dynamic Tool Calling**: AI selects and executes tools based on conversation context
|
|
10
|
-
- **Context Modification**: Tools can update agent context and collected data
|
|
11
|
-
- **Streaming Execution**: Tools work with both streaming and non-streaming responses
|
|
12
|
-
- **Error Recovery**: Robust handling of tool execution failures
|
|
13
|
-
- **Multi-Step Tools**: Support for complex tool interaction patterns
|
|
14
|
-
|
|
15
|
-
## Tool Definition
|
|
16
|
-
|
|
17
|
-
### Basic Tool Structure
|
|
18
|
-
|
|
19
|
-
```typescript
|
|
20
|
-
interface Tool<TContext, TData, TArgs extends unknown[], TResult> {
|
|
21
|
-
id: string;
|
|
22
|
-
name?: string; // Human-readable name shown to AI models
|
|
23
|
-
description: string;
|
|
24
|
-
parameters: StructuredSchema; // JSON Schema for tool arguments
|
|
25
|
-
handler: ToolHandler<TContext, TArgs, TResult, TData>;
|
|
26
|
-
}
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
### Creating Tools
|
|
30
|
-
|
|
31
|
-
```typescript
|
|
32
|
-
import { Tool } from "@falai/agent";
|
|
33
|
-
|
|
34
|
-
// Simple data retrieval tool
|
|
35
|
-
const getWeather: Tool<unknown, WeatherData, [], string> = {
|
|
36
|
-
id: "get_weather",
|
|
37
|
-
name: "Weather Checker",
|
|
38
|
-
description: "Get current weather for a location",
|
|
39
|
-
parameters: {
|
|
40
|
-
type: "object",
|
|
41
|
-
properties: {
|
|
42
|
-
location: { type: "string", description: "City or location name" },
|
|
43
|
-
},
|
|
44
|
-
required: ["location"],
|
|
45
|
-
},
|
|
46
|
-
handler: async (toolContext, args) => {
|
|
47
|
-
const weather = await weatherAPI.getCurrentWeather(args.location);
|
|
48
|
-
return {
|
|
49
|
-
data: `Current weather in ${args.location}: ${weather.temperature}°C, ${weather.condition}`,
|
|
50
|
-
contextUpdate: {
|
|
51
|
-
lastWeatherCheck: new Date().toISOString(),
|
|
52
|
-
currentLocation: args.location,
|
|
53
|
-
},
|
|
54
|
-
};
|
|
55
|
-
},
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
// Data modification tool
|
|
59
|
-
const updateUserProfile: Tool<unknown, ProfileData, [], string> = {
|
|
60
|
-
id: "update_profile",
|
|
61
|
-
name: "Profile Updater",
|
|
62
|
-
description: "Update user profile information",
|
|
63
|
-
parameters: {
|
|
64
|
-
type: "object",
|
|
65
|
-
properties: {
|
|
66
|
-
field: { type: "string", description: "Field to update" },
|
|
67
|
-
value: { type: "string", description: "New value" },
|
|
68
|
-
},
|
|
69
|
-
required: ["field", "value"],
|
|
70
|
-
},
|
|
71
|
-
handler: async (toolContext, args) => {
|
|
72
|
-
// Validate field exists in schema
|
|
73
|
-
if (!toolContext.data || !(args.field in toolContext.data)) {
|
|
74
|
-
throw new Error(`Invalid field: ${args.field}`);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
return {
|
|
78
|
-
data: `Updated ${args.field} to: ${args.value}`,
|
|
79
|
-
dataUpdate: { [args.field]: args.value }, // Update session data
|
|
80
|
-
};
|
|
81
|
-
},
|
|
82
|
-
};
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
## Tool Execution Flow
|
|
86
|
-
|
|
87
|
-
### Automatic Tool Calling
|
|
88
|
-
|
|
89
|
-
Tools are executed automatically when the AI decides to use them:
|
|
90
|
-
|
|
91
|
-
```typescript
|
|
92
|
-
const agent = new Agent({
|
|
93
|
-
name: "Smart Assistant",
|
|
94
|
-
provider: openaiProvider,
|
|
95
|
-
tools: [getWeather, updateUserProfile],
|
|
96
|
-
|
|
97
|
-
routes: [
|
|
98
|
-
agent.createRoute({
|
|
99
|
-
title: "Weather Query",
|
|
100
|
-
initialStep: {
|
|
101
|
-
prompt: "What's the weather like? I can check for you.",
|
|
102
|
-
tools: ["get_weather"], // Make tool available in this step
|
|
103
|
-
},
|
|
104
|
-
}),
|
|
105
|
-
],
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
// Conversation flow:
|
|
109
|
-
// User: "What's the weather in Paris?"
|
|
110
|
-
// AI: Decides to call get_weather tool
|
|
111
|
-
// Tool executes and updates context
|
|
112
|
-
// AI: "Current weather in Paris: 22°C, Sunny"
|
|
113
|
-
```
|
|
114
|
-
|
|
115
|
-
### Tool Result Processing
|
|
116
|
-
|
|
117
|
-
```typescript
|
|
118
|
-
interface ToolExecutionResult<TContext, TData> {
|
|
119
|
-
toolName: string;
|
|
120
|
-
success: boolean;
|
|
121
|
-
result?: {
|
|
122
|
-
data: unknown; // User-visible result
|
|
123
|
-
contextUpdate?: Partial<TContext>; // Context modifications
|
|
124
|
-
dataUpdate?: Partial<TData>; // Session data updates
|
|
125
|
-
};
|
|
126
|
-
error?: string;
|
|
127
|
-
}
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
## Context Integration
|
|
131
|
-
|
|
132
|
-
### Context Updates
|
|
133
|
-
|
|
134
|
-
Tools can modify agent context:
|
|
135
|
-
|
|
136
|
-
```typescript
|
|
137
|
-
const locationTracker: Tool<
|
|
138
|
-
{ currentLocation?: string; locationHistory?: string[] },
|
|
139
|
-
{ location: string },
|
|
140
|
-
[],
|
|
141
|
-
string
|
|
142
|
-
> = {
|
|
143
|
-
id: "track_location",
|
|
144
|
-
description: "Track and update location information",
|
|
145
|
-
parameters: {
|
|
146
|
-
type: "object",
|
|
147
|
-
properties: {
|
|
148
|
-
location: { type: "string", description: "Location to track" },
|
|
149
|
-
},
|
|
150
|
-
required: ["location"],
|
|
151
|
-
},
|
|
152
|
-
handler: async ({ context }, { location }) => {
|
|
153
|
-
return {
|
|
154
|
-
data: `Location set to: ${location}`,
|
|
155
|
-
contextUpdate: {
|
|
156
|
-
currentLocation: location,
|
|
157
|
-
lastLocationUpdate: new Date().toISOString(),
|
|
158
|
-
locationHistory: (prev: string[]) => [...(prev || []), location],
|
|
159
|
-
},
|
|
160
|
-
};
|
|
161
|
-
},
|
|
162
|
-
};
|
|
163
|
-
```
|
|
164
|
-
|
|
165
|
-
### Context-Aware Tools
|
|
166
|
-
|
|
167
|
-
Tools can access current context:
|
|
168
|
-
|
|
169
|
-
```typescript
|
|
170
|
-
const contextualTool: Tool<
|
|
171
|
-
{ userName?: string; currentLocation?: string },
|
|
172
|
-
{},
|
|
173
|
-
[],
|
|
174
|
-
string
|
|
175
|
-
> = {
|
|
176
|
-
id: "personalized_greeting",
|
|
177
|
-
description: "Generate personalized greeting based on context",
|
|
178
|
-
handler: async ({ context }) => {
|
|
179
|
-
const userName = context.userName || "friend";
|
|
180
|
-
const location = context.currentLocation || "unknown";
|
|
181
|
-
|
|
182
|
-
return {
|
|
183
|
-
data: `Hello ${userName} from ${location}! How can I help you today?`,
|
|
184
|
-
contextUpdate: {
|
|
185
|
-
lastInteraction: new Date().toISOString(),
|
|
186
|
-
},
|
|
187
|
-
};
|
|
188
|
-
},
|
|
189
|
-
};
|
|
190
|
-
```
|
|
191
|
-
|
|
192
|
-
## Data Collection Integration
|
|
193
|
-
|
|
194
|
-
### Updating Collected Data
|
|
195
|
-
|
|
196
|
-
Tools can modify session-collected data:
|
|
197
|
-
|
|
198
|
-
```typescript
|
|
199
|
-
const dataEnrichmentTool: Tool<{}, { email?: string }, [], string> = {
|
|
200
|
-
id: "enrich_user_data",
|
|
201
|
-
description: "Enrich user profile with additional information",
|
|
202
|
-
handler: async ({ data }) => {
|
|
203
|
-
if (!data?.email) {
|
|
204
|
-
throw new Error("Email required for enrichment");
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
const enriched = await userAPI.enrichProfile(data.email);
|
|
208
|
-
|
|
209
|
-
return {
|
|
210
|
-
data: "Profile enriched with additional information",
|
|
211
|
-
dataUpdate: {
|
|
212
|
-
enrichedAt: new Date().toISOString(),
|
|
213
|
-
profileComplete: true,
|
|
214
|
-
...enriched, // Merge enriched data
|
|
215
|
-
},
|
|
216
|
-
};
|
|
217
|
-
},
|
|
218
|
-
};
|
|
219
|
-
```
|
|
220
|
-
|
|
221
|
-
### Validation Integration
|
|
222
|
-
|
|
223
|
-
```typescript
|
|
224
|
-
const validatingTool: Tool<{}, any, [], string> = {
|
|
225
|
-
id: "validate_and_save",
|
|
226
|
-
description: "Validate collected data and save to database",
|
|
227
|
-
handler: async ({ data }) => {
|
|
228
|
-
// Validate collected data
|
|
229
|
-
const validation = validateUserData(data);
|
|
230
|
-
|
|
231
|
-
if (!validation.valid) {
|
|
232
|
-
return {
|
|
233
|
-
data: `Validation failed: ${validation.errors.join(", ")}`,
|
|
234
|
-
dataUpdate: {
|
|
235
|
-
validationErrors: validation.errors,
|
|
236
|
-
needsCorrection: true,
|
|
237
|
-
},
|
|
238
|
-
};
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
// Save to database
|
|
242
|
-
await saveUserData(data);
|
|
243
|
-
|
|
244
|
-
return {
|
|
245
|
-
data: "Data validated and saved successfully",
|
|
246
|
-
dataUpdate: {
|
|
247
|
-
savedAt: new Date().toISOString(),
|
|
248
|
-
validationStatus: "passed",
|
|
249
|
-
},
|
|
250
|
-
};
|
|
251
|
-
},
|
|
252
|
-
};
|
|
253
|
-
```
|
|
254
|
-
|
|
255
|
-
## Tool Scoping
|
|
256
|
-
|
|
257
|
-
### Agent-Level Tools
|
|
258
|
-
|
|
259
|
-
Available to all routes and steps:
|
|
260
|
-
|
|
261
|
-
```typescript
|
|
262
|
-
const agent = new Agent({
|
|
263
|
-
name: "Multi-Purpose Agent",
|
|
264
|
-
provider: provider,
|
|
265
|
-
tools: [globalSearchTool, userManagementTool], // Available everywhere
|
|
266
|
-
|
|
267
|
-
routes: [
|
|
268
|
-
route1, // Can use global tools
|
|
269
|
-
route2, // Can use global tools
|
|
270
|
-
],
|
|
271
|
-
});
|
|
272
|
-
```
|
|
273
|
-
|
|
274
|
-
### Route-Level Tools
|
|
275
|
-
|
|
276
|
-
Specific to a route:
|
|
277
|
-
|
|
278
|
-
```typescript
|
|
279
|
-
const supportRoute = agent.createRoute({
|
|
280
|
-
title: "Customer Support",
|
|
281
|
-
tools: [ticketCreationTool, knowledgeBaseTool], // Route-specific
|
|
282
|
-
|
|
283
|
-
initialStep: {
|
|
284
|
-
prompt: "How can I help you?",
|
|
285
|
-
tools: ["ticketCreationTool"], // Available in this step
|
|
286
|
-
},
|
|
287
|
-
});
|
|
288
|
-
```
|
|
289
|
-
|
|
290
|
-
### Step-Level Tools
|
|
291
|
-
|
|
292
|
-
Limited to specific conversation steps:
|
|
293
|
-
|
|
294
|
-
```typescript
|
|
295
|
-
const dataCollectionStep = {
|
|
296
|
-
prompt: "Please provide your information",
|
|
297
|
-
collect: ["personalInfo"],
|
|
298
|
-
tools: ["dataValidationTool", "privacyCheckTool"], // Step-specific only
|
|
299
|
-
requires: ["userConsent"],
|
|
300
|
-
};
|
|
301
|
-
```
|
|
302
|
-
|
|
303
|
-
### Tool Resolution Priority
|
|
304
|
-
|
|
305
|
-
Tools are resolved in order of specificity:
|
|
306
|
-
|
|
307
|
-
```typescript
|
|
308
|
-
// 1. Step-level tools (highest priority)
|
|
309
|
-
// 2. Route-level tools
|
|
310
|
-
// 3. Agent-level tools (lowest priority)
|
|
311
|
-
|
|
312
|
-
// Same tool ID in multiple scopes:
|
|
313
|
-
// Step tool overrides route tool overrides agent tool
|
|
314
|
-
```
|
|
315
|
-
|
|
316
|
-
## Streaming Tool Execution
|
|
317
|
-
|
|
318
|
-
### Real-Time Tool Calls
|
|
319
|
-
|
|
320
|
-
Tools work seamlessly with streaming responses:
|
|
321
|
-
|
|
322
|
-
```typescript
|
|
323
|
-
// Streaming response with tool execution
|
|
324
|
-
for await (const chunk of agent.respondStream({ history, session })) {
|
|
325
|
-
if (chunk.toolCalls) {
|
|
326
|
-
console.log("AI called tools:", chunk.toolCalls);
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
if (chunk.done) {
|
|
330
|
-
console.log("Final response:", chunk.accumulated);
|
|
331
|
-
console.log("Updated session:", chunk.session);
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
```
|
|
335
|
-
|
|
336
|
-
### Multi-Step Tool Loops
|
|
337
|
-
|
|
338
|
-
AI can make follow-up tool calls during streaming:
|
|
339
|
-
|
|
340
|
-
```typescript
|
|
341
|
-
// AI might:
|
|
342
|
-
// 1. Call tool A
|
|
343
|
-
// 2. Process results
|
|
344
|
-
// 3. Call tool B based on A's results
|
|
345
|
-
// 4. Continue until satisfied
|
|
346
|
-
|
|
347
|
-
const MAX_TOOL_LOOPS = 5; // Prevent infinite loops
|
|
348
|
-
let toolLoopCount = 0;
|
|
349
|
-
|
|
350
|
-
while (hasToolCalls && toolLoopCount < MAX_TOOL_LOOPS) {
|
|
351
|
-
// Execute tools
|
|
352
|
-
// Update context with results
|
|
353
|
-
// Allow AI to make follow-up calls
|
|
354
|
-
toolLoopCount++;
|
|
355
|
-
}
|
|
356
|
-
```
|
|
357
|
-
|
|
358
|
-
## Error Handling & Recovery
|
|
359
|
-
|
|
360
|
-
### Tool Execution Failures
|
|
361
|
-
|
|
362
|
-
```typescript
|
|
363
|
-
const robustTool: Tool<
|
|
364
|
-
{ lastApiCall?: string; errorCount?: number },
|
|
365
|
-
{ endpoint: string },
|
|
366
|
-
[],
|
|
367
|
-
string
|
|
368
|
-
> = {
|
|
369
|
-
id: "api_call",
|
|
370
|
-
description: "Make external API call with error handling",
|
|
371
|
-
parameters: {
|
|
372
|
-
type: "object",
|
|
373
|
-
properties: {
|
|
374
|
-
endpoint: { type: "string", description: "API endpoint to call" },
|
|
375
|
-
},
|
|
376
|
-
required: ["endpoint"],
|
|
377
|
-
},
|
|
378
|
-
handler: async ({ context }, { endpoint }) => {
|
|
379
|
-
try {
|
|
380
|
-
const result = await externalAPI.call(endpoint);
|
|
381
|
-
return {
|
|
382
|
-
data: `API call successful: ${result}`,
|
|
383
|
-
contextUpdate: { lastApiCall: "success" },
|
|
384
|
-
};
|
|
385
|
-
} catch (error) {
|
|
386
|
-
return {
|
|
387
|
-
data: `API call failed: ${(error as Error).message}`,
|
|
388
|
-
contextUpdate: {
|
|
389
|
-
lastApiCall: "failed",
|
|
390
|
-
errorCount: (count: number) => (count || 0) + 1,
|
|
391
|
-
},
|
|
392
|
-
};
|
|
393
|
-
}
|
|
394
|
-
},
|
|
395
|
-
};
|
|
396
|
-
```
|
|
397
|
-
|
|
398
|
-
### Fallback Tools
|
|
399
|
-
|
|
400
|
-
```typescript
|
|
401
|
-
const fallbackTool: Tool<
|
|
402
|
-
{ searchFallbackUsed?: boolean },
|
|
403
|
-
{ query: string },
|
|
404
|
-
[],
|
|
405
|
-
string
|
|
406
|
-
> = {
|
|
407
|
-
id: "fallback_search",
|
|
408
|
-
description: "Search with automatic fallback mechanisms",
|
|
409
|
-
parameters: {
|
|
410
|
-
type: "object",
|
|
411
|
-
properties: {
|
|
412
|
-
query: { type: "string", description: "Search query" },
|
|
413
|
-
},
|
|
414
|
-
required: ["query"],
|
|
415
|
-
},
|
|
416
|
-
handler: async ({ context }, { query }) => {
|
|
417
|
-
// Try primary search
|
|
418
|
-
try {
|
|
419
|
-
const result = await primarySearchAPI.search(query);
|
|
420
|
-
return {
|
|
421
|
-
data: `Primary search results: ${result}`,
|
|
422
|
-
contextUpdate: { searchFallbackUsed: false },
|
|
423
|
-
};
|
|
424
|
-
} catch (primaryError) {
|
|
425
|
-
// Fallback to secondary search
|
|
426
|
-
try {
|
|
427
|
-
const result = await secondarySearchAPI.search(query);
|
|
428
|
-
return {
|
|
429
|
-
data: `Secondary search results: ${result}`,
|
|
430
|
-
contextUpdate: { searchFallbackUsed: true },
|
|
431
|
-
};
|
|
432
|
-
} catch (secondaryError) {
|
|
433
|
-
// Final fallback
|
|
434
|
-
return {
|
|
435
|
-
data: "Search temporarily unavailable. Please try again later.",
|
|
436
|
-
contextUpdate: { searchFallbackUsed: true },
|
|
437
|
-
};
|
|
438
|
-
}
|
|
439
|
-
}
|
|
440
|
-
},
|
|
441
|
-
};
|
|
442
|
-
```
|
|
443
|
-
|
|
444
|
-
## Advanced Tool Patterns
|
|
445
|
-
|
|
446
|
-
### Stateful Tools
|
|
447
|
-
|
|
448
|
-
Tools that maintain state across calls:
|
|
449
|
-
|
|
450
|
-
```typescript
|
|
451
|
-
let toolState = { conversationId: null };
|
|
452
|
-
|
|
453
|
-
const conversationalTool: Tool<
|
|
454
|
-
{ conversationState?: any; lastMessage?: string },
|
|
455
|
-
{ message: string },
|
|
456
|
-
[],
|
|
457
|
-
string
|
|
458
|
-
> = {
|
|
459
|
-
id: "continue_conversation",
|
|
460
|
-
description: "Continue multi-turn conversation with state management",
|
|
461
|
-
parameters: {
|
|
462
|
-
type: "object",
|
|
463
|
-
properties: {
|
|
464
|
-
message: { type: "string", description: "Message to send" },
|
|
465
|
-
},
|
|
466
|
-
required: ["message"],
|
|
467
|
-
},
|
|
468
|
-
handler: async ({ context }, { message }) => {
|
|
469
|
-
if (!toolState.conversationId) {
|
|
470
|
-
toolState.conversationId = generateId();
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
const response = await conversationAPI.sendMessage(
|
|
474
|
-
toolState.conversationId,
|
|
475
|
-
message
|
|
476
|
-
);
|
|
477
|
-
|
|
478
|
-
return {
|
|
479
|
-
data: response.message,
|
|
480
|
-
contextUpdate: {
|
|
481
|
-
conversationState: toolState,
|
|
482
|
-
lastMessage: message,
|
|
483
|
-
},
|
|
484
|
-
};
|
|
485
|
-
},
|
|
486
|
-
};
|
|
487
|
-
```
|
|
488
|
-
|
|
489
|
-
### Chainable Tools
|
|
490
|
-
|
|
491
|
-
Tools that set up data for other tools:
|
|
492
|
-
|
|
493
|
-
```typescript
|
|
494
|
-
const setupTool: Tool<
|
|
495
|
-
{ activeWorkflowId?: string; workflowType?: string; workflowStep?: number },
|
|
496
|
-
{ workflowType: string },
|
|
497
|
-
[],
|
|
498
|
-
string
|
|
499
|
-
> = {
|
|
500
|
-
id: "setup_workflow",
|
|
501
|
-
description: "Initialize a new workflow process",
|
|
502
|
-
parameters: {
|
|
503
|
-
type: "object",
|
|
504
|
-
properties: {
|
|
505
|
-
workflowType: {
|
|
506
|
-
type: "string",
|
|
507
|
-
enum: ["onboarding", "support", "sales"],
|
|
508
|
-
description: "Type of workflow to create",
|
|
509
|
-
},
|
|
510
|
-
},
|
|
511
|
-
required: ["workflowType"],
|
|
512
|
-
},
|
|
513
|
-
handler: async ({ context }, { workflowType }) => {
|
|
514
|
-
const workflowId = await workflowAPI.create(workflowType);
|
|
515
|
-
|
|
516
|
-
return {
|
|
517
|
-
data: `Workflow ${workflowId} created`,
|
|
518
|
-
contextUpdate: {
|
|
519
|
-
activeWorkflowId: workflowId,
|
|
520
|
-
workflowType,
|
|
521
|
-
workflowStep: 1,
|
|
522
|
-
},
|
|
523
|
-
};
|
|
524
|
-
},
|
|
525
|
-
};
|
|
526
|
-
|
|
527
|
-
const stepTool: Tool<
|
|
528
|
-
{ activeWorkflowId?: string; workflowStep?: number; lastStepResult?: any },
|
|
529
|
-
{},
|
|
530
|
-
[],
|
|
531
|
-
string
|
|
532
|
-
> = {
|
|
533
|
-
id: "execute_workflow_step",
|
|
534
|
-
description: "Execute the next step in active workflow",
|
|
535
|
-
handler: async ({ context }) => {
|
|
536
|
-
if (!context.activeWorkflowId) {
|
|
537
|
-
throw new Error("No active workflow");
|
|
538
|
-
}
|
|
539
|
-
|
|
540
|
-
const result = await workflowAPI.executeStep(
|
|
541
|
-
context.activeWorkflowId,
|
|
542
|
-
context.workflowStep || 1
|
|
543
|
-
);
|
|
544
|
-
|
|
545
|
-
return {
|
|
546
|
-
data: `Step ${context.workflowStep || 1} completed: ${result}`,
|
|
547
|
-
contextUpdate: {
|
|
548
|
-
workflowStep: (context.workflowStep || 1) + 1,
|
|
549
|
-
lastStepResult: result,
|
|
550
|
-
},
|
|
551
|
-
};
|
|
552
|
-
},
|
|
553
|
-
};
|
|
554
|
-
```
|
|
555
|
-
|
|
556
|
-
## Performance Optimization
|
|
557
|
-
|
|
558
|
-
### Efficient Tool Execution
|
|
559
|
-
|
|
560
|
-
```typescript
|
|
561
|
-
// Cache expensive operations
|
|
562
|
-
const cachedTool: Tool<{ lastCacheHit?: boolean }, { key: string }, [], any> = {
|
|
563
|
-
id: "cached_data_lookup",
|
|
564
|
-
description: "Lookup data with caching for performance",
|
|
565
|
-
parameters: {
|
|
566
|
-
type: "object",
|
|
567
|
-
properties: {
|
|
568
|
-
key: { type: "string", description: "Cache key for lookup" },
|
|
569
|
-
},
|
|
570
|
-
required: ["key"],
|
|
571
|
-
},
|
|
572
|
-
handler: async ({ context }, { key }) => {
|
|
573
|
-
// Check cache first
|
|
574
|
-
const cacheKey = `tool_cache_${key}`;
|
|
575
|
-
let result = cache.get(cacheKey);
|
|
576
|
-
|
|
577
|
-
if (!result) {
|
|
578
|
-
result = await expensiveOperation(key);
|
|
579
|
-
cache.set(cacheKey, result, 300000); // 5 minute cache
|
|
580
|
-
}
|
|
581
|
-
|
|
582
|
-
return {
|
|
583
|
-
data: result,
|
|
584
|
-
contextUpdate: { lastCacheHit: !!cache.get(cacheKey) },
|
|
585
|
-
};
|
|
586
|
-
},
|
|
587
|
-
};
|
|
588
|
-
```
|
|
589
|
-
|
|
590
|
-
### Batch Operations
|
|
591
|
-
|
|
592
|
-
```typescript
|
|
593
|
-
const batchTool: Tool<
|
|
594
|
-
{},
|
|
595
|
-
{ items: string[]; processedItems?: any[]; batchCompletedAt?: string },
|
|
596
|
-
[],
|
|
597
|
-
string
|
|
598
|
-
> = {
|
|
599
|
-
id: "batch_process",
|
|
600
|
-
description: "Process multiple items in a single batch operation",
|
|
601
|
-
parameters: {
|
|
602
|
-
type: "object",
|
|
603
|
-
properties: {
|
|
604
|
-
items: {
|
|
605
|
-
type: "array",
|
|
606
|
-
items: { type: "string" },
|
|
607
|
-
description: "Items to process",
|
|
608
|
-
},
|
|
609
|
-
},
|
|
610
|
-
required: ["items"],
|
|
611
|
-
},
|
|
612
|
-
handler: async ({ context }, { items }) => {
|
|
613
|
-
// Process multiple items efficiently
|
|
614
|
-
const results = await Promise.all(items.map((item) => processItem(item)));
|
|
615
|
-
|
|
616
|
-
return {
|
|
617
|
-
data: `Processed ${results.length} items`,
|
|
618
|
-
dataUpdate: {
|
|
619
|
-
processedItems: results,
|
|
620
|
-
batchCompletedAt: new Date().toISOString(),
|
|
621
|
-
},
|
|
622
|
-
};
|
|
623
|
-
},
|
|
624
|
-
};
|
|
625
|
-
```
|
|
626
|
-
|
|
627
|
-
## Security & Access Control
|
|
628
|
-
|
|
629
|
-
### Tool Permissions
|
|
630
|
-
|
|
631
|
-
```typescript
|
|
632
|
-
const secureTool: Tool<{ userRole?: string }, { action: string }, [], any> = {
|
|
633
|
-
id: "admin_action",
|
|
634
|
-
description: "Perform administrative actions with permission checks",
|
|
635
|
-
parameters: {
|
|
636
|
-
type: "object",
|
|
637
|
-
properties: {
|
|
638
|
-
action: { type: "string", description: "Admin action to perform" },
|
|
639
|
-
},
|
|
640
|
-
required: ["action"],
|
|
641
|
-
},
|
|
642
|
-
handler: async ({ context }, { action }) => {
|
|
643
|
-
// Check permissions
|
|
644
|
-
if (context.userRole !== "admin") {
|
|
645
|
-
throw new Error("Insufficient permissions");
|
|
646
|
-
}
|
|
647
|
-
|
|
648
|
-
// Execute privileged action
|
|
649
|
-
const result = await performAdminAction(action);
|
|
650
|
-
return {
|
|
651
|
-
data: `Admin action completed: ${result}`,
|
|
652
|
-
contextUpdate: {
|
|
653
|
-
lastAdminAction: new Date().toISOString(),
|
|
654
|
-
},
|
|
655
|
-
};
|
|
656
|
-
},
|
|
657
|
-
};
|
|
658
|
-
```
|
|
659
|
-
|
|
660
|
-
### Input Validation
|
|
661
|
-
|
|
662
|
-
```typescript
|
|
663
|
-
const validatedTool: Tool<
|
|
664
|
-
{ userId?: string; userRole?: string },
|
|
665
|
-
{ userId: string; updates: any },
|
|
666
|
-
[],
|
|
667
|
-
any
|
|
668
|
-
> = {
|
|
669
|
-
id: "user_update",
|
|
670
|
-
description: "Update user data with validation and permission checks",
|
|
671
|
-
parameters: {
|
|
672
|
-
type: "object",
|
|
673
|
-
properties: {
|
|
674
|
-
userId: { type: "string", description: "User ID to update" },
|
|
675
|
-
updates: { type: "object", description: "Fields to update" },
|
|
676
|
-
},
|
|
677
|
-
required: ["userId", "updates"],
|
|
678
|
-
},
|
|
679
|
-
handler: async ({ context }, { userId, updates }) => {
|
|
680
|
-
// Validate user can only update their own data
|
|
681
|
-
if (context.userId !== userId && context.userRole !== "admin") {
|
|
682
|
-
throw new Error("Cannot update other users' data");
|
|
683
|
-
}
|
|
684
|
-
|
|
685
|
-
// Validate input data
|
|
686
|
-
const validatedUpdates = validateUpdates(updates);
|
|
687
|
-
|
|
688
|
-
const result = await updateUser(userId, validatedUpdates);
|
|
689
|
-
return {
|
|
690
|
-
data: `User ${userId} updated successfully`,
|
|
691
|
-
contextUpdate: {
|
|
692
|
-
lastUserUpdate: new Date().toISOString(),
|
|
693
|
-
},
|
|
694
|
-
};
|
|
695
|
-
},
|
|
696
|
-
};
|
|
697
|
-
```
|
|
698
|
-
|
|
699
|
-
## Debugging & Monitoring
|
|
700
|
-
|
|
701
|
-
### Tool Execution Logging
|
|
702
|
-
|
|
703
|
-
```typescript
|
|
704
|
-
// Enable debug mode for detailed logging
|
|
705
|
-
const agent = new Agent({
|
|
706
|
-
name: "Debug Agent",
|
|
707
|
-
debug: true,
|
|
708
|
-
provider: provider,
|
|
709
|
-
});
|
|
710
|
-
|
|
711
|
-
// Logs will show:
|
|
712
|
-
// [Agent] Executing dynamic tool: get_weather (success: true)
|
|
713
|
-
// [Agent] Tool updated collected data: { temperature: 22, condition: "sunny" }
|
|
714
|
-
// [Agent] Tool updated context: { lastWeatherCheck: "2024-01-15T10:30:00Z" }
|
|
715
|
-
```
|
|
716
|
-
|
|
717
|
-
### Performance Monitoring
|
|
718
|
-
|
|
719
|
-
```typescript
|
|
720
|
-
const monitoredTool: Tool<{}, { args: any }, [], any> = {
|
|
721
|
-
id: "monitored_operation",
|
|
722
|
-
description: "Execute operation with performance monitoring",
|
|
723
|
-
parameters: {
|
|
724
|
-
type: "object",
|
|
725
|
-
properties: {
|
|
726
|
-
args: { type: "object", description: "Arguments for the operation" },
|
|
727
|
-
},
|
|
728
|
-
required: ["args"],
|
|
729
|
-
},
|
|
730
|
-
handler: async ({ context }, { args }) => {
|
|
731
|
-
const startTime = Date.now();
|
|
732
|
-
|
|
733
|
-
try {
|
|
734
|
-
const result = await performOperation(args);
|
|
735
|
-
|
|
736
|
-
// Log success metrics
|
|
737
|
-
metrics.record("tool_execution", {
|
|
738
|
-
tool: "monitored_operation",
|
|
739
|
-
duration: Date.now() - startTime,
|
|
740
|
-
success: true,
|
|
741
|
-
});
|
|
742
|
-
|
|
743
|
-
return {
|
|
744
|
-
data: `Operation completed: ${result}`,
|
|
745
|
-
contextUpdate: {
|
|
746
|
-
lastOperationDuration: Date.now() - startTime,
|
|
747
|
-
lastOperationSuccess: true,
|
|
748
|
-
},
|
|
749
|
-
};
|
|
750
|
-
} catch (error) {
|
|
751
|
-
// Log error metrics
|
|
752
|
-
metrics.record("tool_execution", {
|
|
753
|
-
tool: "monitored_operation",
|
|
754
|
-
duration: Date.now() - startTime,
|
|
755
|
-
success: false,
|
|
756
|
-
error: (error as Error).message,
|
|
757
|
-
});
|
|
758
|
-
|
|
759
|
-
return {
|
|
760
|
-
data: `Operation failed: ${(error as Error).message}`,
|
|
761
|
-
contextUpdate: {
|
|
762
|
-
lastOperationDuration: Date.now() - startTime,
|
|
763
|
-
lastOperationSuccess: false,
|
|
764
|
-
lastOperationError: (error as Error).message,
|
|
765
|
-
},
|
|
766
|
-
};
|
|
767
|
-
}
|
|
768
|
-
},
|
|
769
|
-
};
|
|
770
|
-
```
|
|
771
|
-
|
|
772
|
-
## Best Practices
|
|
773
|
-
|
|
774
|
-
### Tool Design
|
|
775
|
-
|
|
776
|
-
1. **Clear Purpose**: Each tool should do one thing well
|
|
777
|
-
2. **Robust Error Handling**: Plan for failures and edge cases
|
|
778
|
-
3. **Input Validation**: Validate all inputs thoroughly
|
|
779
|
-
4. **Idempotent Operations**: Safe to call multiple times
|
|
780
|
-
|
|
781
|
-
### Performance
|
|
782
|
-
|
|
783
|
-
1. **Efficient Execution**: Cache results when possible
|
|
784
|
-
2. **Resource Limits**: Implement timeouts and rate limits
|
|
785
|
-
3. **Batch Operations**: Group related operations
|
|
786
|
-
4. **Lazy Loading**: Load heavy dependencies only when needed
|
|
787
|
-
|
|
788
|
-
### Security
|
|
789
|
-
|
|
790
|
-
1. **Access Control**: Check permissions before execution
|
|
791
|
-
2. **Input Sanitization**: Clean and validate all inputs
|
|
792
|
-
3. **Audit Logging**: Log all tool executions
|
|
793
|
-
4. **Rate Limiting**: Prevent abuse with rate limits
|
|
794
|
-
|
|
795
|
-
### Testing
|
|
796
|
-
|
|
797
|
-
```typescript
|
|
798
|
-
import { ToolExecutor } from "@falai/agent";
|
|
799
|
-
|
|
800
|
-
// Test tool execution
|
|
801
|
-
const executor = new ToolExecutor();
|
|
802
|
-
const result = await executor.executeTool({
|
|
803
|
-
tool,
|
|
804
|
-
context: mockContext,
|
|
805
|
-
data: mockData,
|
|
806
|
-
updateContext: async (updates) => {
|
|
807
|
-
/* mock implementation */
|
|
808
|
-
},
|
|
809
|
-
});
|
|
810
|
-
|
|
811
|
-
expect(result.success).toBe(true);
|
|
812
|
-
expect(result.data).toBeDefined();
|
|
813
|
-
```
|
|
814
|
-
|
|
815
|
-
The dynamic tool execution system transforms static AI responses into interactive, context-aware conversations where the AI can perform real actions and adapt based on results.
|