@nextsparkjs/plugin-langchain 0.1.0-beta.1

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 (67) hide show
  1. package/.env.example +41 -0
  2. package/api/observability/metrics/route.ts +110 -0
  3. package/api/observability/traces/[traceId]/route.ts +398 -0
  4. package/api/observability/traces/route.ts +205 -0
  5. package/api/sessions/route.ts +332 -0
  6. package/components/observability/CollapsibleJson.tsx +71 -0
  7. package/components/observability/CompactTimeline.tsx +75 -0
  8. package/components/observability/ConversationFlow.tsx +271 -0
  9. package/components/observability/DisabledMessage.tsx +21 -0
  10. package/components/observability/FiltersPanel.tsx +82 -0
  11. package/components/observability/ObservabilityDashboard.tsx +230 -0
  12. package/components/observability/SpansList.tsx +210 -0
  13. package/components/observability/TraceDetail.tsx +335 -0
  14. package/components/observability/TraceStatusBadge.tsx +39 -0
  15. package/components/observability/TracesTable.tsx +97 -0
  16. package/components/observability/index.ts +7 -0
  17. package/docs/01-getting-started/01-overview.md +196 -0
  18. package/docs/01-getting-started/02-installation.md +368 -0
  19. package/docs/01-getting-started/03-configuration.md +794 -0
  20. package/docs/02-core-concepts/01-architecture.md +566 -0
  21. package/docs/02-core-concepts/02-agents.md +597 -0
  22. package/docs/02-core-concepts/03-tools.md +689 -0
  23. package/docs/03-orchestration/01-graph-orchestrator.md +809 -0
  24. package/docs/03-orchestration/02-legacy-react.md +650 -0
  25. package/docs/04-advanced/01-observability.md +645 -0
  26. package/docs/04-advanced/02-token-tracking.md +469 -0
  27. package/docs/04-advanced/03-streaming.md +476 -0
  28. package/docs/04-advanced/04-guardrails.md +597 -0
  29. package/docs/05-reference/01-api-reference.md +1403 -0
  30. package/docs/05-reference/02-customization.md +646 -0
  31. package/docs/05-reference/03-examples.md +881 -0
  32. package/docs/index.md +85 -0
  33. package/hooks/observability/useMetrics.ts +31 -0
  34. package/hooks/observability/useTraceDetail.ts +48 -0
  35. package/hooks/observability/useTraces.ts +59 -0
  36. package/lib/agent-factory.ts +354 -0
  37. package/lib/agent-helpers.ts +201 -0
  38. package/lib/db-memory-store.ts +417 -0
  39. package/lib/graph/index.ts +58 -0
  40. package/lib/graph/nodes/combiner.ts +399 -0
  41. package/lib/graph/nodes/router.ts +440 -0
  42. package/lib/graph/orchestrator-graph.ts +386 -0
  43. package/lib/graph/prompts/combiner.md +131 -0
  44. package/lib/graph/prompts/router.md +193 -0
  45. package/lib/graph/types.ts +365 -0
  46. package/lib/guardrails.ts +230 -0
  47. package/lib/index.ts +44 -0
  48. package/lib/logger.ts +70 -0
  49. package/lib/memory-store.ts +168 -0
  50. package/lib/message-serializer.ts +110 -0
  51. package/lib/prompt-renderer.ts +94 -0
  52. package/lib/providers.ts +226 -0
  53. package/lib/streaming.ts +232 -0
  54. package/lib/token-tracker.ts +298 -0
  55. package/lib/tools-builder.ts +192 -0
  56. package/lib/tracer-callbacks.ts +342 -0
  57. package/lib/tracer.ts +350 -0
  58. package/migrations/001_langchain_memory.sql +83 -0
  59. package/migrations/002_token_usage.sql +127 -0
  60. package/migrations/003_observability.sql +257 -0
  61. package/package.json +28 -0
  62. package/plugin.config.ts +170 -0
  63. package/presets/lib/langchain.config.ts.preset +142 -0
  64. package/presets/templates/sector7/ai-observability/[traceId]/page.tsx +91 -0
  65. package/presets/templates/sector7/ai-observability/page.tsx +54 -0
  66. package/types/langchain.types.ts +274 -0
  67. package/types/observability.types.ts +270 -0
@@ -0,0 +1,650 @@
1
+ # Orchestration (Legacy)
2
+
3
+ > **DEPRECATED**: This document describes the legacy ReAct-based orchestration approach.
4
+ > For new implementations, use the **Graph-Based Orchestrator** which is 25-50x faster.
5
+ >
6
+ > **Recommended**: See [Graph Orchestrator](./01-graph-orchestrator.md) for the modern approach.
7
+ >
8
+ > **Migration**: Set `LANGCHAIN_USE_GRAPH_ORCHESTRATOR=true` to enable the new system.
9
+
10
+ ---
11
+
12
+ Orchestration enables complex multi-agent systems where a central orchestrator routes requests to specialized agents. This guide covers orchestration patterns, implementation, and best practices.
13
+
14
+ ## Why Orchestration?
15
+
16
+ As applications grow, a single agent with many tools becomes:
17
+ - **Hard to maintain**: Too many tools, complex prompts
18
+ - **Slow**: LLM must consider all tools for every request
19
+ - **Error-prone**: More tools = more chance of wrong tool selection
20
+
21
+ Orchestration solves this by:
22
+ - **Separating concerns**: Each agent handles one domain
23
+ - **Improving focus**: Smaller tool sets = better accuracy
24
+ - **Enabling specialization**: Different models/temps per domain
25
+
26
+ ## Architecture
27
+
28
+ ```
29
+ ┌─────────────────────────────────────────────────────────────────┐
30
+ │ USER REQUEST │
31
+ │ "Show me customer details" │
32
+ └─────────────────────────────────────────────────────────────────┘
33
+
34
+
35
+ ┌─────────────────────────────────────────────────────────────────┐
36
+ │ ORCHESTRATOR │
37
+ │ │
38
+ │ ┌─────────────────────────────────────────────────────────┐ │
39
+ │ │ System Prompt │ │
40
+ │ │ "Analyze intent and route to appropriate agent" │ │
41
+ │ └─────────────────────────────────────────────────────────┘ │
42
+ │ │ │
43
+ │ ┌─────────────────────────────────────────────────────────┐ │
44
+ │ │ Routing Tools │ │
45
+ │ │ route_to_task | route_to_customer | route_to_page │ │
46
+ │ └─────────────────────────────────────────────────────────┘ │
47
+ │ │
48
+ │ Decision: route_to_customer │
49
+ └─────────────────────────────────────────────────────────────────┘
50
+
51
+
52
+ ┌─────────────────────────────────────────────────────────────────┐
53
+ │ CUSTOMER AGENT │
54
+ │ │
55
+ │ Tools: search_customers, get_customer, update_customer, ... │
56
+ │ │
57
+ │ *Executes request and returns response* │
58
+ └─────────────────────────────────────────────────────────────────┘
59
+
60
+
61
+ ┌─────────────────────────────────────────────────────────────────┐
62
+ │ RESPONSE │
63
+ │ "Here's the customer..." │
64
+ └─────────────────────────────────────────────────────────────────┘
65
+ ```
66
+
67
+ ## Implementation
68
+
69
+ ### Step 1: Configure Agents
70
+
71
+ ```typescript
72
+ // langchain.config.ts
73
+ export const AGENTS = {
74
+ // Orchestrator - low temperature for consistent routing
75
+ 'orchestrator': {
76
+ provider: 'ollama',
77
+ temperature: 0.1,
78
+ description: 'Routes requests to specialized agents',
79
+ systemPrompt: 'orchestrator',
80
+ createTools: () => createOrchestratorTools(),
81
+ },
82
+
83
+ // Specialized agents
84
+ 'task-assistant': {
85
+ provider: 'ollama',
86
+ temperature: 0.3,
87
+ systemPrompt: 'task-assistant',
88
+ createTools: (ctx) => createTaskTools(ctx),
89
+ },
90
+ 'customer-assistant': {
91
+ provider: 'ollama',
92
+ temperature: 0.3,
93
+ systemPrompt: 'customer-assistant',
94
+ createTools: (ctx) => createCustomerTools(ctx),
95
+ },
96
+ 'page-assistant': {
97
+ provider: 'ollama',
98
+ temperature: 0.3,
99
+ systemPrompt: 'page-assistant',
100
+ createTools: (ctx) => createPageTools(ctx),
101
+ },
102
+ }
103
+ ```
104
+
105
+ ### Step 2: Create Routing Tools
106
+
107
+ ```typescript
108
+ // tools/orchestrator.ts
109
+ import { z } from 'zod'
110
+
111
+ export interface RoutingResult {
112
+ agent: 'task' | 'customer' | 'page'
113
+ message: string
114
+ }
115
+
116
+ export interface ClarificationResult {
117
+ action: 'clarify'
118
+ question: string
119
+ options: Array<{ label: string; description: string }>
120
+ }
121
+
122
+ export function createOrchestratorTools() {
123
+ return [
124
+ {
125
+ name: 'route_to_task',
126
+ description: 'Route to task agent when user mentions tasks, todos, or work items.',
127
+ schema: z.object({
128
+ message: z.string().describe('User message to forward'),
129
+ }),
130
+ func: async ({ message }) => {
131
+ return JSON.stringify({ agent: 'task', message })
132
+ },
133
+ },
134
+ {
135
+ name: 'route_to_customer',
136
+ description: 'Route to customer agent when user mentions customers, clients, or accounts.',
137
+ schema: z.object({
138
+ message: z.string().describe('User message to forward'),
139
+ }),
140
+ func: async ({ message }) => {
141
+ return JSON.stringify({ agent: 'customer', message })
142
+ },
143
+ },
144
+ {
145
+ name: 'route_to_page',
146
+ description: 'Route to page agent when user mentions pages, content, or blocks.',
147
+ schema: z.object({
148
+ message: z.string().describe('User message to forward'),
149
+ }),
150
+ func: async ({ message }) => {
151
+ return JSON.stringify({ agent: 'page', message })
152
+ },
153
+ },
154
+ {
155
+ name: 'ask_clarification',
156
+ description: 'Ask user for clarification when intent is unclear.',
157
+ schema: z.object({
158
+ question: z.string(),
159
+ options: z.array(z.object({
160
+ label: z.string(),
161
+ description: z.string(),
162
+ })),
163
+ }),
164
+ func: async ({ question, options }) => {
165
+ return JSON.stringify({ action: 'clarify', question, options })
166
+ },
167
+ },
168
+ ]
169
+ }
170
+ ```
171
+
172
+ ### Step 3: Orchestrator System Prompt
173
+
174
+ ```markdown
175
+ <!-- agents/orchestrator.md -->
176
+
177
+ You are an AI Orchestrator that routes user requests to specialized agents.
178
+
179
+ ## CRITICAL RULE
180
+
181
+ **YOU CAN ONLY DO TWO THINGS:**
182
+ 1. Call a routing tool (route_to_task, route_to_customer, route_to_page)
183
+ 2. Respond to simple greetings
184
+
185
+ **NEVER claim to perform actions like creating, updating, or deleting data.** You don't have those tools. Only the specialized agents do.
186
+
187
+ ## Routing Rules
188
+
189
+ **route_to_customer** - Use when:
190
+ - User mentions customers, clients, accounts (cliente, customer, cuenta)
191
+ - User wants to modify something about a previously discussed customer
192
+ - User references a customer from earlier ("modificalo", "cambialo")
193
+
194
+ **route_to_task** - Use when:
195
+ - User mentions tasks, to-dos, work items (tarea, task, pendiente)
196
+ - User wants to create, update, or list tasks
197
+ - User asks for suggestions to add to a task
198
+
199
+ **route_to_page** - Use when:
200
+ - User mentions pages, content, website (página, page, contenido)
201
+ - User wants to create or modify landing pages, blocks
202
+
203
+ ## Context Awareness
204
+
205
+ When the user says "modificalo", "cambialo", "actualízalo":
206
+ - Look at the conversation history to determine WHAT they're referring to
207
+ - If discussing a customer → route_to_customer
208
+ - If discussing a task → route_to_task
209
+ - If discussing a page → route_to_page
210
+
211
+ ## Direct Response (ONLY for greetings)
212
+
213
+ Respond directly ONLY for:
214
+ - "Hola" → "¡Hola! ¿En qué puedo ayudarte?"
215
+ - "Hello" → "Hello! How can I help you?"
216
+
217
+ For EVERYTHING else, use a routing tool.
218
+ ```
219
+
220
+ ### Step 4: Orchestrator Handler
221
+
222
+ ```typescript
223
+ // orchestrator.ts
224
+ import { createAgent } from '@/contents/plugins/langchain/lib/agent-factory'
225
+ import { loadSystemPrompt } from './agents'
226
+ import { getAgentConfig, getAgentModelConfig, getAgentTools } from './langchain.config'
227
+ import type { RoutingResult, ClarificationResult } from './tools/orchestrator'
228
+
229
+ type AgentType = 'task' | 'customer' | 'page'
230
+
231
+ const AGENT_NAME_MAP: Record<AgentType, string> = {
232
+ task: 'task-assistant',
233
+ customer: 'customer-assistant',
234
+ page: 'page-assistant',
235
+ }
236
+
237
+ export interface OrchestratorContext {
238
+ userId: string
239
+ teamId: string
240
+ sessionId: string
241
+ }
242
+
243
+ export interface OrchestratorResponse {
244
+ content: string
245
+ sessionId: string
246
+ agentUsed?: 'orchestrator' | AgentType
247
+ }
248
+
249
+ /**
250
+ * Extract routing decision from the LATEST turn only
251
+ */
252
+ function extractRoutingFromMessages(messages: any[]): RoutingResult | ClarificationResult | null {
253
+ // Find last human message (start of current turn)
254
+ let lastHumanIndex = -1
255
+ for (let i = messages.length - 1; i >= 0; i--) {
256
+ if (messages[i]._getType() === 'human') {
257
+ lastHumanIndex = i
258
+ break
259
+ }
260
+ }
261
+
262
+ // Only search for tool results AFTER the last human message
263
+ for (let i = messages.length - 1; i > lastHumanIndex; i--) {
264
+ const msg = messages[i]
265
+ if (msg._getType() === 'tool') {
266
+ const content = typeof msg.content === 'string'
267
+ ? msg.content
268
+ : JSON.stringify(msg.content)
269
+ try {
270
+ const parsed = JSON.parse(content)
271
+ if (parsed.action === 'clarify' || parsed.agent) {
272
+ return parsed
273
+ }
274
+ } catch {
275
+ // Not JSON
276
+ }
277
+ }
278
+ }
279
+ return null
280
+ }
281
+
282
+ /**
283
+ * Invoke a specialized sub-agent
284
+ */
285
+ async function invokeSubAgent(
286
+ agentType: AgentType,
287
+ message: string,
288
+ context: OrchestratorContext
289
+ ): Promise<OrchestratorResponse> {
290
+ const { userId, teamId, sessionId } = context
291
+ const agentName = AGENT_NAME_MAP[agentType]
292
+
293
+ const config = getAgentConfig(agentName)
294
+ if (!config?.systemPrompt) {
295
+ throw new Error(`Agent not found: ${agentName}`)
296
+ }
297
+
298
+ const agent = await createAgent({
299
+ sessionId: `${sessionId}-${agentType}`,
300
+ systemPrompt: loadSystemPrompt(config.systemPrompt as any),
301
+ tools: getAgentTools(agentName, { userId, teamId }),
302
+ modelConfig: getAgentModelConfig(agentName),
303
+ context: { userId, teamId },
304
+ })
305
+
306
+ const response = await agent.chat(message)
307
+
308
+ return {
309
+ content: response.content,
310
+ sessionId,
311
+ agentUsed: agentType,
312
+ }
313
+ }
314
+
315
+ /**
316
+ * Process a message through the orchestrator
317
+ */
318
+ export async function processWithOrchestrator(
319
+ message: string,
320
+ context: OrchestratorContext
321
+ ): Promise<OrchestratorResponse> {
322
+ const { userId, teamId, sessionId } = context
323
+
324
+ try {
325
+ // Step 1: Create orchestrator
326
+ const orchestratorAgent = await createAgent({
327
+ sessionId: `${sessionId}-orchestrator`,
328
+ systemPrompt: loadSystemPrompt('orchestrator'),
329
+ tools: getAgentTools('orchestrator', { userId, teamId }),
330
+ modelConfig: getAgentModelConfig('orchestrator'),
331
+ context: { userId, teamId },
332
+ })
333
+
334
+ // Step 2: Get routing decision
335
+ const routingResponse = await orchestratorAgent.chat(message)
336
+
337
+ // Step 3: Extract routing from tool results
338
+ const decision = extractRoutingFromMessages(routingResponse.messages || [])
339
+
340
+ if (!decision) {
341
+ // Orchestrator responded directly (greeting, meta-question)
342
+ return {
343
+ content: routingResponse.content,
344
+ sessionId,
345
+ agentUsed: 'orchestrator',
346
+ }
347
+ }
348
+
349
+ // Step 4: Handle clarification
350
+ if ('action' in decision && decision.action === 'clarify') {
351
+ let response = decision.question + '\n\n'
352
+ decision.options.forEach((opt, i) => {
353
+ response += `${i + 1}. **${opt.label}**: ${opt.description}\n`
354
+ })
355
+ return {
356
+ content: response,
357
+ sessionId,
358
+ agentUsed: 'orchestrator',
359
+ }
360
+ }
361
+
362
+ // Step 5: Route to specialized agent
363
+ if ('agent' in decision) {
364
+ return await invokeSubAgent(
365
+ decision.agent,
366
+ decision.message || message,
367
+ context
368
+ )
369
+ }
370
+
371
+ return {
372
+ content: routingResponse.content,
373
+ sessionId,
374
+ agentUsed: 'orchestrator',
375
+ }
376
+ } catch (error) {
377
+ console.error('[Orchestrator] Error:', error)
378
+ throw new Error(
379
+ error instanceof Error ? error.message : 'Failed to process message'
380
+ )
381
+ }
382
+ }
383
+ ```
384
+
385
+ ### Step 5: API Integration
386
+
387
+ ```typescript
388
+ // api/ai/chat/route.ts
389
+ import { NextRequest, NextResponse } from 'next/server'
390
+ import { authenticateRequest } from '@/core/lib/auth/server'
391
+ import { processWithOrchestrator } from '@/themes/default/lib/langchain/orchestrator'
392
+
393
+ export async function POST(request: NextRequest) {
394
+ try {
395
+ const { user, teamId } = await authenticateRequest(request)
396
+ if (!user || !teamId) {
397
+ return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
398
+ }
399
+
400
+ const { message, sessionId } = await request.json()
401
+
402
+ const response = await processWithOrchestrator(message, {
403
+ userId: user.id,
404
+ teamId,
405
+ sessionId: sessionId || `session-${Date.now()}`,
406
+ })
407
+
408
+ return NextResponse.json(response)
409
+ } catch (error) {
410
+ return NextResponse.json(
411
+ { error: error instanceof Error ? error.message : 'Error' },
412
+ { status: 500 }
413
+ )
414
+ }
415
+ }
416
+ ```
417
+
418
+ ## Session Management
419
+
420
+ Orchestration creates separate sessions for each agent:
421
+
422
+ ```
423
+ Main session: user-123-session-1
424
+ ├── Orchestrator: user-123-session-1-orchestrator
425
+ ├── Task Agent: user-123-session-1-task
426
+ ├── Customer Agent: user-123-session-1-customer
427
+ └── Page Agent: user-123-session-1-page
428
+ ```
429
+
430
+ This allows:
431
+ - Independent conversation history per agent
432
+ - Context isolation between domains
433
+ - Parallel conversations if needed
434
+
435
+ ## Handling Context References
436
+
437
+ A key challenge is handling contextual references like "modificalo" (modify it):
438
+
439
+ ### Problem
440
+
441
+ ```
442
+ User: "Show me customer StartupXYZ"
443
+ Agent: *shows customer details*
444
+ User: "modificalo, su nuevo telefono es +1 555..."
445
+ ^^^^^^^^^^
446
+ What is "it"?
447
+ ```
448
+
449
+ ### Solution: Context Awareness in Prompt
450
+
451
+ ```markdown
452
+ ## Context Awareness
453
+
454
+ When the user says "modificalo", "cambialo", "actualízalo":
455
+ - Look at the conversation history to determine WHAT they're referring to
456
+ - If you were just discussing a customer → route_to_customer
457
+ - If you were just discussing a task → route_to_task
458
+ - If you were just discussing a page → route_to_page
459
+ ```
460
+
461
+ ### Solution: Extracting Only Current Turn
462
+
463
+ ```typescript
464
+ // Only look at messages after the last human message
465
+ function extractRoutingFromMessages(messages) {
466
+ let lastHumanIndex = -1
467
+ for (let i = messages.length - 1; i >= 0; i--) {
468
+ if (messages[i]._getType() === 'human') {
469
+ lastHumanIndex = i
470
+ break
471
+ }
472
+ }
473
+
474
+ // Search only in current turn
475
+ for (let i = messages.length - 1; i > lastHumanIndex; i--) {
476
+ // Extract routing...
477
+ }
478
+ }
479
+ ```
480
+
481
+ ## Orchestration Patterns
482
+
483
+ ### Pattern 1: Simple Router
484
+
485
+ Route based on keywords only:
486
+
487
+ ```typescript
488
+ 'orchestrator': {
489
+ temperature: 0.1,
490
+ systemPrompt: 'simple-router',
491
+ createTools: () => [routeToTask, routeToCustomer, routeToPage],
492
+ }
493
+ ```
494
+
495
+ ### Pattern 2: Intent Classifier
496
+
497
+ More sophisticated intent analysis:
498
+
499
+ ```markdown
500
+ ## Intent Classification
501
+
502
+ Before routing, classify the user's intent:
503
+
504
+ 1. **CRUD Operations**: Create, Read, Update, Delete
505
+ 2. **Search/Query**: Finding specific items
506
+ 3. **Aggregation**: Summaries, counts, reports
507
+ 4. **Action**: Workflows, multi-step operations
508
+
509
+ Then route to the appropriate agent.
510
+ ```
511
+
512
+ ### Pattern 3: Hierarchical Orchestration
513
+
514
+ For very complex systems:
515
+
516
+ ```
517
+ Main Orchestrator
518
+ ├── Domain A Orchestrator
519
+ │ ├── Agent A1
520
+ │ └── Agent A2
521
+ └── Domain B Orchestrator
522
+ ├── Agent B1
523
+ └── Agent B2
524
+ ```
525
+
526
+ ### Pattern 4: Fallback Chain
527
+
528
+ Try agents in order:
529
+
530
+ ```typescript
531
+ async function processWithFallback(message, context) {
532
+ try {
533
+ return await processWithOrchestrator(message, context)
534
+ } catch {
535
+ // Fallback to single agent
536
+ return await processSingleAgent(message, context)
537
+ }
538
+ }
539
+ ```
540
+
541
+ ## Clarification Flow
542
+
543
+ When intent is unclear, ask for clarification:
544
+
545
+ ```typescript
546
+ {
547
+ name: 'ask_clarification',
548
+ description: 'Ask user for clarification when intent is ambiguous.',
549
+ schema: z.object({
550
+ question: z.string(),
551
+ options: z.array(z.object({
552
+ label: z.string(),
553
+ description: z.string(),
554
+ })),
555
+ }),
556
+ func: async ({ question, options }) => {
557
+ return JSON.stringify({
558
+ action: 'clarify',
559
+ question,
560
+ options,
561
+ })
562
+ },
563
+ }
564
+ ```
565
+
566
+ **Example:**
567
+
568
+ ```
569
+ User: "Create a new entry"
570
+ Orchestrator: *calls ask_clarification*
571
+ Response:
572
+ "What type of entry would you like to create?"
573
+
574
+ 1. **Task**: Create a new task or todo item
575
+ 2. **Customer**: Create a new customer record
576
+ 3. **Page**: Create a new content page
577
+ ```
578
+
579
+ ## Debugging Orchestration
580
+
581
+ ### Enable Logging
582
+
583
+ ```env
584
+ LOG_ENABLED=true
585
+ ```
586
+
587
+ ### Check Logs
588
+
589
+ ```bash
590
+ # View orchestrator decisions
591
+ cat logger/ai/session-*-orchestrator.log
592
+
593
+ # View sub-agent execution
594
+ cat logger/ai/session-*-task.log
595
+ cat logger/ai/session-*-customer.log
596
+ ```
597
+
598
+ ### Common Issues
599
+
600
+ | Issue | Cause | Solution |
601
+ |-------|-------|----------|
602
+ | Wrong agent selected | Unclear routing rules | Improve prompt keywords |
603
+ | Stale routing | Using old tool results | Only check current turn |
604
+ | Direct response instead of routing | Too permissive direct response rules | Restrict to greetings only |
605
+ | Infinite loops | Agent calling itself | Check recursion limits |
606
+
607
+ ## Best Practices
608
+
609
+ ### 1. Keep Orchestrator Lightweight
610
+
611
+ ```typescript
612
+ 'orchestrator': {
613
+ temperature: 0.1, // Low for consistency
614
+ // Only routing tools, no data tools
615
+ createTools: () => createOrchestratorTools(),
616
+ }
617
+ ```
618
+
619
+ ### 2. Be Explicit About Routing Rules
620
+
621
+ ```markdown
622
+ ## Routing Rules
623
+
624
+ **route_to_customer** - Use when message contains:
625
+ - "customer", "cliente", "client"
626
+ - "account", "cuenta"
627
+ - "phone", "teléfono"
628
+ - OR when referring to a previously discussed customer
629
+ ```
630
+
631
+ ### 3. Handle Edge Cases
632
+
633
+ ```markdown
634
+ ## Edge Cases
635
+
636
+ - If message could match multiple agents, ask for clarification
637
+ - If user says "undo", route to the same agent as previous action
638
+ - If user says "help", respond directly with capability list
639
+ ```
640
+
641
+ ### 4. Monitor and Iterate
642
+
643
+ - Track routing accuracy
644
+ - Log misrouted requests
645
+ - Continuously improve prompts
646
+
647
+ ## Next Steps
648
+
649
+ - [Advanced customization](../05-reference/02-customization.md)
650
+ - [API reference](../05-reference/01-api-reference.md)