@falai/agent 0.3.10 → 0.3.11
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 +100 -16
- package/dist/cjs/core/Agent.d.ts +25 -0
- package/dist/cjs/core/Agent.d.ts.map +1 -1
- package/dist/cjs/core/Agent.js +130 -0
- package/dist/cjs/core/Agent.js.map +1 -1
- package/dist/cjs/index.d.ts +2 -0
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +3 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/providers/AnthropicProvider.d.ts +43 -0
- package/dist/cjs/providers/AnthropicProvider.d.ts.map +1 -0
- package/dist/cjs/providers/AnthropicProvider.js +328 -0
- package/dist/cjs/providers/AnthropicProvider.js.map +1 -0
- package/dist/cjs/providers/GeminiProvider.d.ts +4 -1
- package/dist/cjs/providers/GeminiProvider.d.ts.map +1 -1
- package/dist/cjs/providers/GeminiProvider.js +96 -0
- package/dist/cjs/providers/GeminiProvider.js.map +1 -1
- package/dist/cjs/providers/OpenAIProvider.d.ts +4 -1
- package/dist/cjs/providers/OpenAIProvider.d.ts.map +1 -1
- package/dist/cjs/providers/OpenAIProvider.js +115 -0
- package/dist/cjs/providers/OpenAIProvider.js.map +1 -1
- package/dist/cjs/providers/OpenRouterProvider.d.ts +4 -1
- package/dist/cjs/providers/OpenRouterProvider.d.ts.map +1 -1
- package/dist/cjs/providers/OpenRouterProvider.js +115 -0
- package/dist/cjs/providers/OpenRouterProvider.js.map +1 -1
- package/dist/cjs/providers/index.d.ts +13 -0
- package/dist/cjs/providers/index.d.ts.map +1 -0
- package/dist/cjs/providers/index.js +16 -0
- package/dist/cjs/providers/index.js.map +1 -0
- package/dist/cjs/types/ai.d.ts +28 -0
- package/dist/cjs/types/ai.d.ts.map +1 -1
- package/dist/core/Agent.d.ts +25 -0
- package/dist/core/Agent.d.ts.map +1 -1
- package/dist/core/Agent.js +130 -0
- package/dist/core/Agent.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/providers/AnthropicProvider.d.ts +43 -0
- package/dist/providers/AnthropicProvider.d.ts.map +1 -0
- package/dist/providers/AnthropicProvider.js +321 -0
- package/dist/providers/AnthropicProvider.js.map +1 -0
- package/dist/providers/GeminiProvider.d.ts +4 -1
- package/dist/providers/GeminiProvider.d.ts.map +1 -1
- package/dist/providers/GeminiProvider.js +96 -0
- package/dist/providers/GeminiProvider.js.map +1 -1
- package/dist/providers/OpenAIProvider.d.ts +4 -1
- package/dist/providers/OpenAIProvider.d.ts.map +1 -1
- package/dist/providers/OpenAIProvider.js +115 -0
- package/dist/providers/OpenAIProvider.js.map +1 -1
- package/dist/providers/OpenRouterProvider.d.ts +4 -1
- package/dist/providers/OpenRouterProvider.d.ts.map +1 -1
- package/dist/providers/OpenRouterProvider.js +115 -0
- package/dist/providers/OpenRouterProvider.js.map +1 -1
- package/dist/providers/index.d.ts +13 -0
- package/dist/providers/index.d.ts.map +1 -0
- package/dist/providers/index.js +9 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/types/ai.d.ts +28 -0
- package/dist/types/ai.d.ts.map +1 -1
- package/docs/API_REFERENCE.md +260 -2
- package/docs/PROVIDERS.md +139 -2
- package/examples/business-onboarding.ts +5 -4
- package/examples/declarative-agent.ts +1 -1
- package/examples/domain-scoping.ts +5 -4
- package/examples/healthcare-agent.ts +4 -4
- package/examples/openai-agent.ts +6 -4
- package/examples/rules-prohibitions.ts +4 -4
- package/examples/streaming-agent.ts +371 -0
- package/examples/travel-agent.ts +7 -4
- package/package.json +2 -1
- package/src/core/Agent.ts +174 -0
- package/src/index.ts +2 -0
- package/src/providers/AnthropicProvider.ts +467 -0
- package/src/providers/GeminiProvider.ts +135 -0
- package/src/providers/OpenAIProvider.ts +157 -0
- package/src/providers/OpenRouterProvider.ts +157 -0
- package/src/providers/index.ts +16 -0
- package/src/types/ai.ts +32 -0
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Example: Streaming Responses
|
|
3
|
+
*
|
|
4
|
+
* This example demonstrates how to use the respondStream method
|
|
5
|
+
* to stream AI responses in real-time for better user experience
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
Agent,
|
|
10
|
+
createMessageEvent,
|
|
11
|
+
EventSource,
|
|
12
|
+
AnthropicProvider,
|
|
13
|
+
OpenAIProvider,
|
|
14
|
+
GeminiProvider,
|
|
15
|
+
} from "../src/index";
|
|
16
|
+
|
|
17
|
+
// Custom context type
|
|
18
|
+
interface ConversationContext {
|
|
19
|
+
userId: string;
|
|
20
|
+
sessionId: string;
|
|
21
|
+
preferences: {
|
|
22
|
+
streamingEnabled: boolean;
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
async function streamingWithAnthropic() {
|
|
27
|
+
console.log("\n🤖 Example 1: Streaming with Anthropic (Claude)\n");
|
|
28
|
+
|
|
29
|
+
// Initialize Anthropic provider
|
|
30
|
+
const provider = new AnthropicProvider({
|
|
31
|
+
apiKey: process.env.ANTHROPIC_API_KEY || "",
|
|
32
|
+
model: "claude-sonnet-4-5",
|
|
33
|
+
config: {
|
|
34
|
+
temperature: 0.7,
|
|
35
|
+
max_tokens: 1000,
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
// Create agent
|
|
40
|
+
const agent = new Agent<ConversationContext>({
|
|
41
|
+
name: "StreamingAssistant",
|
|
42
|
+
description: "An AI assistant that streams responses in real-time",
|
|
43
|
+
goal: "Provide helpful information with streaming responses",
|
|
44
|
+
context: {
|
|
45
|
+
userId: "user123",
|
|
46
|
+
sessionId: "session456",
|
|
47
|
+
preferences: {
|
|
48
|
+
streamingEnabled: true,
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
ai: provider,
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
// Add guidelines
|
|
55
|
+
agent.createGuideline({
|
|
56
|
+
action: "Be concise but informative in your responses",
|
|
57
|
+
enabled: true,
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
// Create conversation history
|
|
61
|
+
const history = [
|
|
62
|
+
createMessageEvent(
|
|
63
|
+
EventSource.CUSTOMER,
|
|
64
|
+
"User",
|
|
65
|
+
"Explain quantum computing in simple terms."
|
|
66
|
+
),
|
|
67
|
+
];
|
|
68
|
+
|
|
69
|
+
try {
|
|
70
|
+
console.log("📤 Streaming response from Claude...\n");
|
|
71
|
+
console.log("Response: ");
|
|
72
|
+
|
|
73
|
+
// Use respondStream for real-time streaming
|
|
74
|
+
let fullMessage = "";
|
|
75
|
+
for await (const chunk of agent.respondStream({ history })) {
|
|
76
|
+
// chunk.delta contains the new text
|
|
77
|
+
// chunk.accumulated contains the full text so far
|
|
78
|
+
// chunk.done indicates if this is the final chunk
|
|
79
|
+
|
|
80
|
+
if (chunk.delta) {
|
|
81
|
+
process.stdout.write(chunk.delta);
|
|
82
|
+
fullMessage += chunk.delta;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (chunk.done) {
|
|
86
|
+
console.log("\n\n✅ Stream complete!");
|
|
87
|
+
console.log(`\n📊 Metadata:`);
|
|
88
|
+
console.log(` - Route: ${chunk.route?.title || "None"}`);
|
|
89
|
+
console.log(` - State: ${chunk.state?.description || "None"}`);
|
|
90
|
+
console.log(` - Tool Calls: ${chunk.toolCalls?.length || 0}`);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
} catch (error) {
|
|
94
|
+
console.error("❌ Error:", error);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
async function streamingWithOpenAI() {
|
|
99
|
+
console.log("\n🤖 Example 2: Streaming with OpenAI\n");
|
|
100
|
+
|
|
101
|
+
const provider = new OpenAIProvider({
|
|
102
|
+
apiKey: process.env.OPENAI_API_KEY || "",
|
|
103
|
+
model: "gpt-5",
|
|
104
|
+
config: {
|
|
105
|
+
temperature: 0.8,
|
|
106
|
+
},
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
const agent = new Agent<ConversationContext>({
|
|
110
|
+
name: "CreativeAssistant",
|
|
111
|
+
description: "A creative AI assistant",
|
|
112
|
+
context: {
|
|
113
|
+
userId: "user123",
|
|
114
|
+
sessionId: "session789",
|
|
115
|
+
preferences: {
|
|
116
|
+
streamingEnabled: true,
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
ai: provider,
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
const history = [
|
|
123
|
+
createMessageEvent(
|
|
124
|
+
EventSource.CUSTOMER,
|
|
125
|
+
"User",
|
|
126
|
+
"Write a short poem about TypeScript"
|
|
127
|
+
),
|
|
128
|
+
];
|
|
129
|
+
|
|
130
|
+
try {
|
|
131
|
+
console.log("📤 Streaming response from OpenAI...\n");
|
|
132
|
+
console.log("Response: ");
|
|
133
|
+
|
|
134
|
+
for await (const chunk of agent.respondStream({ history })) {
|
|
135
|
+
if (chunk.delta) {
|
|
136
|
+
process.stdout.write(chunk.delta);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (chunk.done) {
|
|
140
|
+
console.log("\n\n✅ Stream complete!");
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
} catch (error) {
|
|
144
|
+
console.error("❌ Error:", error);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
async function streamingWithGemini() {
|
|
149
|
+
console.log("\n🤖 Example 3: Streaming with Google Gemini\n");
|
|
150
|
+
|
|
151
|
+
const provider = new GeminiProvider({
|
|
152
|
+
apiKey: process.env.GEMINI_API_KEY || "",
|
|
153
|
+
model: "models/gemini-2.0-flash-exp",
|
|
154
|
+
config: {
|
|
155
|
+
temperature: 0.7,
|
|
156
|
+
},
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
const agent = new Agent<ConversationContext>({
|
|
160
|
+
name: "AnalyticalAssistant",
|
|
161
|
+
description: "An analytical AI assistant",
|
|
162
|
+
context: {
|
|
163
|
+
userId: "user123",
|
|
164
|
+
sessionId: "session101",
|
|
165
|
+
preferences: {
|
|
166
|
+
streamingEnabled: true,
|
|
167
|
+
},
|
|
168
|
+
},
|
|
169
|
+
ai: provider,
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
const history = [
|
|
173
|
+
createMessageEvent(
|
|
174
|
+
EventSource.CUSTOMER,
|
|
175
|
+
"User",
|
|
176
|
+
"What are the key differences between REST and GraphQL?"
|
|
177
|
+
),
|
|
178
|
+
];
|
|
179
|
+
|
|
180
|
+
try {
|
|
181
|
+
console.log("📤 Streaming response from Gemini...\n");
|
|
182
|
+
console.log("Response: ");
|
|
183
|
+
|
|
184
|
+
for await (const chunk of agent.respondStream({ history })) {
|
|
185
|
+
if (chunk.delta) {
|
|
186
|
+
process.stdout.write(chunk.delta);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
if (chunk.done) {
|
|
190
|
+
console.log("\n\n✅ Stream complete!");
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
} catch (error) {
|
|
194
|
+
console.error("❌ Error:", error);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
async function streamingWithRoutes() {
|
|
199
|
+
console.log("\n🤖 Example 4: Streaming with Routes and States\n");
|
|
200
|
+
|
|
201
|
+
const provider = new AnthropicProvider({
|
|
202
|
+
apiKey: process.env.ANTHROPIC_API_KEY || "",
|
|
203
|
+
model: "claude-sonnet-4-5",
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
const agent = new Agent<ConversationContext>({
|
|
207
|
+
name: "SupportAgent",
|
|
208
|
+
description: "A customer support agent with conversation routes",
|
|
209
|
+
context: {
|
|
210
|
+
userId: "user123",
|
|
211
|
+
sessionId: "session202",
|
|
212
|
+
preferences: {
|
|
213
|
+
streamingEnabled: true,
|
|
214
|
+
},
|
|
215
|
+
},
|
|
216
|
+
ai: provider,
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
// Create a route
|
|
220
|
+
const supportRoute = agent.createRoute({
|
|
221
|
+
title: "Product Support",
|
|
222
|
+
description: "Help users with product questions",
|
|
223
|
+
conditions: ["User asks about product features or issues"],
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
supportRoute.initialState.transitionTo({
|
|
227
|
+
chatState: "Understand the user's product question",
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
const history = [
|
|
231
|
+
createMessageEvent(
|
|
232
|
+
EventSource.CUSTOMER,
|
|
233
|
+
"User",
|
|
234
|
+
"How do I reset my password?"
|
|
235
|
+
),
|
|
236
|
+
];
|
|
237
|
+
|
|
238
|
+
try {
|
|
239
|
+
console.log("📤 Streaming response with route detection...\n");
|
|
240
|
+
console.log("Response: ");
|
|
241
|
+
|
|
242
|
+
for await (const chunk of agent.respondStream({ history })) {
|
|
243
|
+
if (chunk.delta) {
|
|
244
|
+
process.stdout.write(chunk.delta);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
if (chunk.done) {
|
|
248
|
+
console.log("\n\n✅ Stream complete!");
|
|
249
|
+
if (chunk.route) {
|
|
250
|
+
console.log(`\n🗺️ Route detected: ${chunk.route.title}`);
|
|
251
|
+
}
|
|
252
|
+
if (chunk.state) {
|
|
253
|
+
console.log(`📍 State: ${chunk.state.description}`);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
} catch (error) {
|
|
258
|
+
console.error("❌ Error:", error);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
async function streamingWithAbortSignal() {
|
|
263
|
+
console.log("\n🤖 Example 5: Streaming with Abort Control\n");
|
|
264
|
+
|
|
265
|
+
const provider = new AnthropicProvider({
|
|
266
|
+
apiKey: process.env.ANTHROPIC_API_KEY || "",
|
|
267
|
+
model: "claude-sonnet-4-5",
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
const agent = new Agent<ConversationContext>({
|
|
271
|
+
name: "Assistant",
|
|
272
|
+
description: "An assistant that can be interrupted",
|
|
273
|
+
context: {
|
|
274
|
+
userId: "user123",
|
|
275
|
+
sessionId: "session303",
|
|
276
|
+
preferences: {
|
|
277
|
+
streamingEnabled: true,
|
|
278
|
+
},
|
|
279
|
+
},
|
|
280
|
+
ai: provider,
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
const history = [
|
|
284
|
+
createMessageEvent(
|
|
285
|
+
EventSource.CUSTOMER,
|
|
286
|
+
"User",
|
|
287
|
+
"Tell me a very long story about space exploration."
|
|
288
|
+
),
|
|
289
|
+
];
|
|
290
|
+
|
|
291
|
+
// Create an AbortController to cancel the stream
|
|
292
|
+
const abortController = new AbortController();
|
|
293
|
+
|
|
294
|
+
// Automatically abort after 3 seconds
|
|
295
|
+
const timeout = setTimeout(() => {
|
|
296
|
+
console.log("\n\n⚠️ Aborting stream after 3 seconds...");
|
|
297
|
+
abortController.abort();
|
|
298
|
+
}, 3000);
|
|
299
|
+
|
|
300
|
+
try {
|
|
301
|
+
console.log("📤 Streaming response (will abort after 3s)...\n");
|
|
302
|
+
console.log("Response: ");
|
|
303
|
+
|
|
304
|
+
for await (const chunk of agent.respondStream({
|
|
305
|
+
history,
|
|
306
|
+
signal: abortController.signal,
|
|
307
|
+
})) {
|
|
308
|
+
if (chunk.delta) {
|
|
309
|
+
process.stdout.write(chunk.delta);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
if (chunk.done) {
|
|
313
|
+
console.log("\n\n✅ Stream complete!");
|
|
314
|
+
clearTimeout(timeout);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
} catch (error) {
|
|
318
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
319
|
+
console.log("\n\n🛑 Stream was aborted successfully!");
|
|
320
|
+
} else {
|
|
321
|
+
console.error("❌ Error:", error);
|
|
322
|
+
}
|
|
323
|
+
clearTimeout(timeout);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
async function main() {
|
|
328
|
+
console.log("🚀 Starting Streaming Examples\n");
|
|
329
|
+
console.log("=".repeat(60));
|
|
330
|
+
|
|
331
|
+
const examples = [
|
|
332
|
+
{ name: "Anthropic Streaming", fn: streamingWithAnthropic },
|
|
333
|
+
{ name: "OpenAI Streaming", fn: streamingWithOpenAI },
|
|
334
|
+
{ name: "Gemini Streaming", fn: streamingWithGemini },
|
|
335
|
+
{ name: "Streaming with Routes", fn: streamingWithRoutes },
|
|
336
|
+
{ name: "Streaming with Abort", fn: streamingWithAbortSignal },
|
|
337
|
+
];
|
|
338
|
+
|
|
339
|
+
console.log("\nAvailable Examples:");
|
|
340
|
+
examples.forEach((ex, i) => {
|
|
341
|
+
console.log(` ${i + 1}. ${ex.name}`);
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
console.log("\n💡 Tips:");
|
|
345
|
+
console.log(" - Set ANTHROPIC_API_KEY, OPENAI_API_KEY, or GEMINI_API_KEY");
|
|
346
|
+
console.log(" - Streaming provides real-time responses for better UX");
|
|
347
|
+
console.log(" - Use AbortSignal to cancel long-running streams");
|
|
348
|
+
console.log(" - Access chunk.route and chunk.state for flow information");
|
|
349
|
+
|
|
350
|
+
console.log("\n" + "=".repeat(60));
|
|
351
|
+
|
|
352
|
+
// Run first example if API key is available
|
|
353
|
+
if (process.env.ANTHROPIC_API_KEY) {
|
|
354
|
+
await streamingWithAnthropic();
|
|
355
|
+
} else if (process.env.OPENAI_API_KEY) {
|
|
356
|
+
await streamingWithOpenAI();
|
|
357
|
+
} else if (process.env.GEMINI_API_KEY) {
|
|
358
|
+
await streamingWithGemini();
|
|
359
|
+
} else {
|
|
360
|
+
console.log(
|
|
361
|
+
"\n⚠️ No API keys found. Set one of the environment variables to run examples."
|
|
362
|
+
);
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
// Run if executed directly
|
|
367
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
368
|
+
main().catch(console.error);
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
export { main };
|
package/examples/travel-agent.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
import {
|
|
7
7
|
Agent,
|
|
8
8
|
defineTool,
|
|
9
|
-
|
|
9
|
+
OpenRouterProvider,
|
|
10
10
|
END_ROUTE,
|
|
11
11
|
EventSource,
|
|
12
12
|
createMessageEvent,
|
|
@@ -113,9 +113,12 @@ const getBookingStatus = defineTool<
|
|
|
113
113
|
|
|
114
114
|
// Initialize agent
|
|
115
115
|
async function createTravelAgent() {
|
|
116
|
-
const provider = new
|
|
117
|
-
apiKey: process.env.
|
|
118
|
-
model: "
|
|
116
|
+
const provider = new OpenRouterProvider({
|
|
117
|
+
apiKey: process.env.OPENROUTER_API_KEY || "test-key",
|
|
118
|
+
model: "google/gemini-2.0-flash-exp",
|
|
119
|
+
backupModels: ["anthropic/claude-sonnet-4-5", "openai/gpt-5"],
|
|
120
|
+
siteUrl: "https://github.com/gusnips/falai",
|
|
121
|
+
siteName: "Falai Travel Agent Example",
|
|
119
122
|
retryConfig: {
|
|
120
123
|
timeout: 60000,
|
|
121
124
|
retries: 3,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@falai/agent",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.11",
|
|
4
4
|
"description": "Standalone, strongly-typed AI Agent framework with route DSL and AI provider strategy",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/cjs/index.js",
|
|
@@ -77,6 +77,7 @@
|
|
|
77
77
|
"typescript-eslint": "^8.18.2"
|
|
78
78
|
},
|
|
79
79
|
"dependencies": {
|
|
80
|
+
"@anthropic-ai/sdk": "^0.65.0",
|
|
80
81
|
"@google/genai": "^0.3.0",
|
|
81
82
|
"openai": "^6.3.0"
|
|
82
83
|
}
|
package/src/core/Agent.ts
CHANGED
|
@@ -211,6 +211,180 @@ export class Agent<TContext = unknown> {
|
|
|
211
211
|
return this.context;
|
|
212
212
|
}
|
|
213
213
|
|
|
214
|
+
/**
|
|
215
|
+
* Generate a response based on history and context as a stream
|
|
216
|
+
*/
|
|
217
|
+
async *respondStream(params: {
|
|
218
|
+
history: Event[];
|
|
219
|
+
state?: StateRef;
|
|
220
|
+
contextOverride?: Partial<TContext>;
|
|
221
|
+
signal?: AbortSignal;
|
|
222
|
+
}): AsyncGenerator<{
|
|
223
|
+
delta: string;
|
|
224
|
+
accumulated: string;
|
|
225
|
+
done: boolean;
|
|
226
|
+
route?: { id: string; title: string } | null;
|
|
227
|
+
state?: { id: string; description?: string } | null;
|
|
228
|
+
toolCalls?: Array<{ toolName: string; arguments: Record<string, unknown> }>;
|
|
229
|
+
}> {
|
|
230
|
+
const { history, contextOverride, signal } = params;
|
|
231
|
+
|
|
232
|
+
// Get current context (may fetch from provider)
|
|
233
|
+
let currentContext = await this.getContext();
|
|
234
|
+
|
|
235
|
+
// Call beforeRespond hook if configured
|
|
236
|
+
if (this.options.hooks?.beforeRespond && currentContext !== undefined) {
|
|
237
|
+
currentContext = await this.options.hooks.beforeRespond(currentContext);
|
|
238
|
+
// Update stored context with the result from beforeRespond
|
|
239
|
+
this.context = currentContext;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// Merge context with override
|
|
243
|
+
const effectiveContext = {
|
|
244
|
+
...(currentContext as Record<string, unknown>),
|
|
245
|
+
...(contextOverride as Record<string, unknown>),
|
|
246
|
+
} as TContext;
|
|
247
|
+
|
|
248
|
+
// Build prompt (same as respond method)
|
|
249
|
+
const promptBuilder = new PromptBuilder();
|
|
250
|
+
|
|
251
|
+
// Add agent identity
|
|
252
|
+
if (this.options.description) {
|
|
253
|
+
promptBuilder.addAgentIdentity({
|
|
254
|
+
name: this.options.name,
|
|
255
|
+
description: this.options.description,
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// Add interaction history
|
|
260
|
+
promptBuilder.addInteractionHistoryForMessageGeneration(history);
|
|
261
|
+
|
|
262
|
+
// Add glossary
|
|
263
|
+
if (this.terms.length > 0) {
|
|
264
|
+
promptBuilder.addGlossary(this.terms);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// Add guidelines (convert to GuidelineMatch format, filter enabled only)
|
|
268
|
+
const enabledGuidelines = this.guidelines.filter(
|
|
269
|
+
(g) => g.enabled !== false
|
|
270
|
+
);
|
|
271
|
+
if (enabledGuidelines.length > 0) {
|
|
272
|
+
const guidelineMatches: GuidelineMatch[] = enabledGuidelines.map((g) => ({
|
|
273
|
+
guideline: g,
|
|
274
|
+
}));
|
|
275
|
+
promptBuilder.addGuidelinesForMessageGeneration(guidelineMatches);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// Add capabilities
|
|
279
|
+
if (this.capabilities.length > 0) {
|
|
280
|
+
promptBuilder.addCapabilitiesForMessageGeneration(this.capabilities);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// Add observations
|
|
284
|
+
if (this.observations.length > 0) {
|
|
285
|
+
const observationsWithRoutes = this.observations
|
|
286
|
+
.map((obs) => ({
|
|
287
|
+
description: obs.description,
|
|
288
|
+
routes: obs.getRoutes().map((routeRef) => {
|
|
289
|
+
const route = this.routes.find((r) => r.id === routeRef.id);
|
|
290
|
+
return { title: route?.title || routeRef.id };
|
|
291
|
+
}),
|
|
292
|
+
}))
|
|
293
|
+
.filter((obs) => obs.routes.length > 0);
|
|
294
|
+
|
|
295
|
+
if (observationsWithRoutes.length > 0) {
|
|
296
|
+
promptBuilder.addObservations(observationsWithRoutes);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// Add active routes with their rules and prohibitions
|
|
301
|
+
if (this.routes.length > 0) {
|
|
302
|
+
promptBuilder.addActiveRoutes(
|
|
303
|
+
this.routes.map((r) => ({
|
|
304
|
+
title: r.title,
|
|
305
|
+
description: r.description,
|
|
306
|
+
conditions: r.conditions,
|
|
307
|
+
domains: r.getDomains(),
|
|
308
|
+
rules: r.getRules(),
|
|
309
|
+
prohibitions: r.getProhibitions(),
|
|
310
|
+
}))
|
|
311
|
+
);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// Add domains (tools) information if any domains are registered
|
|
315
|
+
const allDomains = this.domainRegistry.all();
|
|
316
|
+
if (Object.keys(allDomains).length > 0) {
|
|
317
|
+
promptBuilder.addDomains(allDomains);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
// Add JSON response schema instructions
|
|
321
|
+
promptBuilder.addJsonResponseSchema();
|
|
322
|
+
|
|
323
|
+
// Build final prompt
|
|
324
|
+
const prompt = promptBuilder.build();
|
|
325
|
+
|
|
326
|
+
// Generate message stream using AI provider with JSON mode enabled
|
|
327
|
+
const stream = this.options.ai.generateMessageStream({
|
|
328
|
+
prompt,
|
|
329
|
+
history,
|
|
330
|
+
context: effectiveContext,
|
|
331
|
+
signal,
|
|
332
|
+
parameters: {
|
|
333
|
+
jsonMode: true,
|
|
334
|
+
},
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
// Stream chunks to caller
|
|
338
|
+
for await (const chunk of stream) {
|
|
339
|
+
// Extract route and state from structured response on final chunk
|
|
340
|
+
let route: { id: string; title: string } | null = null;
|
|
341
|
+
let state: { id: string; description?: string } | null = null;
|
|
342
|
+
let toolCalls:
|
|
343
|
+
| Array<{ toolName: string; arguments: Record<string, unknown> }>
|
|
344
|
+
| undefined;
|
|
345
|
+
|
|
346
|
+
if (chunk.done && chunk.structured) {
|
|
347
|
+
// Find route by title
|
|
348
|
+
if (chunk.structured.route) {
|
|
349
|
+
const foundRoute = this.routes.find(
|
|
350
|
+
(r) => r.title === chunk.structured?.route
|
|
351
|
+
);
|
|
352
|
+
if (foundRoute) {
|
|
353
|
+
route = {
|
|
354
|
+
id: foundRoute.id,
|
|
355
|
+
title: foundRoute.title,
|
|
356
|
+
};
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// Create state reference if provided
|
|
361
|
+
if (chunk.structured.state) {
|
|
362
|
+
state = {
|
|
363
|
+
id: "dynamic_state",
|
|
364
|
+
description: chunk.structured.state,
|
|
365
|
+
};
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
// Extract tool calls
|
|
369
|
+
if (
|
|
370
|
+
chunk.structured.toolCalls &&
|
|
371
|
+
chunk.structured.toolCalls.length > 0
|
|
372
|
+
) {
|
|
373
|
+
toolCalls = chunk.structured.toolCalls;
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
yield {
|
|
378
|
+
delta: chunk.delta,
|
|
379
|
+
accumulated: chunk.accumulated,
|
|
380
|
+
done: chunk.done,
|
|
381
|
+
route: route || undefined,
|
|
382
|
+
state: state || undefined,
|
|
383
|
+
toolCalls,
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
|
|
214
388
|
/**
|
|
215
389
|
* Generate a response based on history and context
|
|
216
390
|
*/
|
package/src/index.ts
CHANGED
|
@@ -24,6 +24,8 @@ export { OpenAIProvider } from "./providers/OpenAIProvider";
|
|
|
24
24
|
export type { OpenAIProviderOptions } from "./providers/OpenAIProvider";
|
|
25
25
|
export { OpenRouterProvider } from "./providers/OpenRouterProvider";
|
|
26
26
|
export type { OpenRouterProviderOptions } from "./providers/OpenRouterProvider";
|
|
27
|
+
export { AnthropicProvider } from "./providers/AnthropicProvider";
|
|
28
|
+
export type { AnthropicProviderOptions } from "./providers/AnthropicProvider";
|
|
27
29
|
|
|
28
30
|
// Constants
|
|
29
31
|
export { END_ROUTE } from "./constants";
|