@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.
Files changed (80) hide show
  1. package/README.md +100 -16
  2. package/dist/cjs/core/Agent.d.ts +25 -0
  3. package/dist/cjs/core/Agent.d.ts.map +1 -1
  4. package/dist/cjs/core/Agent.js +130 -0
  5. package/dist/cjs/core/Agent.js.map +1 -1
  6. package/dist/cjs/index.d.ts +2 -0
  7. package/dist/cjs/index.d.ts.map +1 -1
  8. package/dist/cjs/index.js +3 -1
  9. package/dist/cjs/index.js.map +1 -1
  10. package/dist/cjs/providers/AnthropicProvider.d.ts +43 -0
  11. package/dist/cjs/providers/AnthropicProvider.d.ts.map +1 -0
  12. package/dist/cjs/providers/AnthropicProvider.js +328 -0
  13. package/dist/cjs/providers/AnthropicProvider.js.map +1 -0
  14. package/dist/cjs/providers/GeminiProvider.d.ts +4 -1
  15. package/dist/cjs/providers/GeminiProvider.d.ts.map +1 -1
  16. package/dist/cjs/providers/GeminiProvider.js +96 -0
  17. package/dist/cjs/providers/GeminiProvider.js.map +1 -1
  18. package/dist/cjs/providers/OpenAIProvider.d.ts +4 -1
  19. package/dist/cjs/providers/OpenAIProvider.d.ts.map +1 -1
  20. package/dist/cjs/providers/OpenAIProvider.js +115 -0
  21. package/dist/cjs/providers/OpenAIProvider.js.map +1 -1
  22. package/dist/cjs/providers/OpenRouterProvider.d.ts +4 -1
  23. package/dist/cjs/providers/OpenRouterProvider.d.ts.map +1 -1
  24. package/dist/cjs/providers/OpenRouterProvider.js +115 -0
  25. package/dist/cjs/providers/OpenRouterProvider.js.map +1 -1
  26. package/dist/cjs/providers/index.d.ts +13 -0
  27. package/dist/cjs/providers/index.d.ts.map +1 -0
  28. package/dist/cjs/providers/index.js +16 -0
  29. package/dist/cjs/providers/index.js.map +1 -0
  30. package/dist/cjs/types/ai.d.ts +28 -0
  31. package/dist/cjs/types/ai.d.ts.map +1 -1
  32. package/dist/core/Agent.d.ts +25 -0
  33. package/dist/core/Agent.d.ts.map +1 -1
  34. package/dist/core/Agent.js +130 -0
  35. package/dist/core/Agent.js.map +1 -1
  36. package/dist/index.d.ts +2 -0
  37. package/dist/index.d.ts.map +1 -1
  38. package/dist/index.js +1 -0
  39. package/dist/index.js.map +1 -1
  40. package/dist/providers/AnthropicProvider.d.ts +43 -0
  41. package/dist/providers/AnthropicProvider.d.ts.map +1 -0
  42. package/dist/providers/AnthropicProvider.js +321 -0
  43. package/dist/providers/AnthropicProvider.js.map +1 -0
  44. package/dist/providers/GeminiProvider.d.ts +4 -1
  45. package/dist/providers/GeminiProvider.d.ts.map +1 -1
  46. package/dist/providers/GeminiProvider.js +96 -0
  47. package/dist/providers/GeminiProvider.js.map +1 -1
  48. package/dist/providers/OpenAIProvider.d.ts +4 -1
  49. package/dist/providers/OpenAIProvider.d.ts.map +1 -1
  50. package/dist/providers/OpenAIProvider.js +115 -0
  51. package/dist/providers/OpenAIProvider.js.map +1 -1
  52. package/dist/providers/OpenRouterProvider.d.ts +4 -1
  53. package/dist/providers/OpenRouterProvider.d.ts.map +1 -1
  54. package/dist/providers/OpenRouterProvider.js +115 -0
  55. package/dist/providers/OpenRouterProvider.js.map +1 -1
  56. package/dist/providers/index.d.ts +13 -0
  57. package/dist/providers/index.d.ts.map +1 -0
  58. package/dist/providers/index.js +9 -0
  59. package/dist/providers/index.js.map +1 -0
  60. package/dist/types/ai.d.ts +28 -0
  61. package/dist/types/ai.d.ts.map +1 -1
  62. package/docs/API_REFERENCE.md +260 -2
  63. package/docs/PROVIDERS.md +139 -2
  64. package/examples/business-onboarding.ts +5 -4
  65. package/examples/declarative-agent.ts +1 -1
  66. package/examples/domain-scoping.ts +5 -4
  67. package/examples/healthcare-agent.ts +4 -4
  68. package/examples/openai-agent.ts +6 -4
  69. package/examples/rules-prohibitions.ts +4 -4
  70. package/examples/streaming-agent.ts +371 -0
  71. package/examples/travel-agent.ts +7 -4
  72. package/package.json +2 -1
  73. package/src/core/Agent.ts +174 -0
  74. package/src/index.ts +2 -0
  75. package/src/providers/AnthropicProvider.ts +467 -0
  76. package/src/providers/GeminiProvider.ts +135 -0
  77. package/src/providers/OpenAIProvider.ts +157 -0
  78. package/src/providers/OpenRouterProvider.ts +157 -0
  79. package/src/providers/index.ts +16 -0
  80. 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 };
@@ -6,7 +6,7 @@
6
6
  import {
7
7
  Agent,
8
8
  defineTool,
9
- GeminiProvider,
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 GeminiProvider({
117
- apiKey: process.env.GEMINI_API_KEY || "test-key",
118
- model: "models/gemini-2.0-flash-exp",
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.10",
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";