solana-agent 27.3.0__tar.gz → 27.3.2__tar.gz

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 (39) hide show
  1. {solana_agent-27.3.0 → solana_agent-27.3.2}/PKG-INFO +50 -4
  2. {solana_agent-27.3.0 → solana_agent-27.3.2}/README.md +48 -2
  3. {solana_agent-27.3.0 → solana_agent-27.3.2}/pyproject.toml +2 -2
  4. {solana_agent-27.3.0 → solana_agent-27.3.2}/solana_agent/services/agent.py +71 -28
  5. {solana_agent-27.3.0 → solana_agent-27.3.2}/solana_agent/services/query.py +8 -2
  6. {solana_agent-27.3.0 → solana_agent-27.3.2}/LICENSE +0 -0
  7. {solana_agent-27.3.0 → solana_agent-27.3.2}/solana_agent/__init__.py +0 -0
  8. {solana_agent-27.3.0 → solana_agent-27.3.2}/solana_agent/adapters/__init__.py +0 -0
  9. {solana_agent-27.3.0 → solana_agent-27.3.2}/solana_agent/adapters/mongodb_adapter.py +0 -0
  10. {solana_agent-27.3.0 → solana_agent-27.3.2}/solana_agent/adapters/openai_adapter.py +0 -0
  11. {solana_agent-27.3.0 → solana_agent-27.3.2}/solana_agent/adapters/pinecone_adapter.py +0 -0
  12. {solana_agent-27.3.0 → solana_agent-27.3.2}/solana_agent/client/__init__.py +0 -0
  13. {solana_agent-27.3.0 → solana_agent-27.3.2}/solana_agent/client/solana_agent.py +0 -0
  14. {solana_agent-27.3.0 → solana_agent-27.3.2}/solana_agent/domains/__init__.py +0 -0
  15. {solana_agent-27.3.0 → solana_agent-27.3.2}/solana_agent/domains/agent.py +0 -0
  16. {solana_agent-27.3.0 → solana_agent-27.3.2}/solana_agent/domains/routing.py +0 -0
  17. {solana_agent-27.3.0 → solana_agent-27.3.2}/solana_agent/factories/__init__.py +0 -0
  18. {solana_agent-27.3.0 → solana_agent-27.3.2}/solana_agent/factories/agent_factory.py +0 -0
  19. {solana_agent-27.3.0 → solana_agent-27.3.2}/solana_agent/interfaces/__init__.py +0 -0
  20. {solana_agent-27.3.0 → solana_agent-27.3.2}/solana_agent/interfaces/client/client.py +0 -0
  21. {solana_agent-27.3.0 → solana_agent-27.3.2}/solana_agent/interfaces/plugins/plugins.py +0 -0
  22. {solana_agent-27.3.0 → solana_agent-27.3.2}/solana_agent/interfaces/providers/data_storage.py +0 -0
  23. {solana_agent-27.3.0 → solana_agent-27.3.2}/solana_agent/interfaces/providers/llm.py +0 -0
  24. {solana_agent-27.3.0 → solana_agent-27.3.2}/solana_agent/interfaces/providers/memory.py +0 -0
  25. {solana_agent-27.3.0 → solana_agent-27.3.2}/solana_agent/interfaces/providers/vector_storage.py +0 -0
  26. {solana_agent-27.3.0 → solana_agent-27.3.2}/solana_agent/interfaces/services/agent.py +0 -0
  27. {solana_agent-27.3.0 → solana_agent-27.3.2}/solana_agent/interfaces/services/knowledge_base.py +0 -0
  28. {solana_agent-27.3.0 → solana_agent-27.3.2}/solana_agent/interfaces/services/query.py +0 -0
  29. {solana_agent-27.3.0 → solana_agent-27.3.2}/solana_agent/interfaces/services/routing.py +0 -0
  30. {solana_agent-27.3.0 → solana_agent-27.3.2}/solana_agent/plugins/__init__.py +0 -0
  31. {solana_agent-27.3.0 → solana_agent-27.3.2}/solana_agent/plugins/manager.py +0 -0
  32. {solana_agent-27.3.0 → solana_agent-27.3.2}/solana_agent/plugins/registry.py +0 -0
  33. {solana_agent-27.3.0 → solana_agent-27.3.2}/solana_agent/plugins/tools/__init__.py +0 -0
  34. {solana_agent-27.3.0 → solana_agent-27.3.2}/solana_agent/plugins/tools/auto_tool.py +0 -0
  35. {solana_agent-27.3.0 → solana_agent-27.3.2}/solana_agent/repositories/__init__.py +0 -0
  36. {solana_agent-27.3.0 → solana_agent-27.3.2}/solana_agent/repositories/memory.py +0 -0
  37. {solana_agent-27.3.0 → solana_agent-27.3.2}/solana_agent/services/__init__.py +0 -0
  38. {solana_agent-27.3.0 → solana_agent-27.3.2}/solana_agent/services/knowledge_base.py +0 -0
  39. {solana_agent-27.3.0 → solana_agent-27.3.2}/solana_agent/services/routing.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: solana-agent
3
- Version: 27.3.0
3
+ Version: 27.3.2
4
4
  Summary: Agentic IQ
5
5
  License: MIT
6
6
  Keywords: ai,openai,ai agents,agi
@@ -19,7 +19,7 @@ Requires-Dist: llama-index-core (>=0.12.30,<0.13.0)
19
19
  Requires-Dist: llama-index-embeddings-openai (>=0.3.1,<0.4.0)
20
20
  Requires-Dist: openai (>=1.74.0,<2.0.0)
21
21
  Requires-Dist: pinecone (>=6.0.2,<7.0.0)
22
- Requires-Dist: pydantic (>=2.11.3,<3.0.0)
22
+ Requires-Dist: pydantic (>=2)
23
23
  Requires-Dist: pymongo (>=4.12.0,<5.0.0)
24
24
  Requires-Dist: pypdf (>=5.4.0,<6.0.0)
25
25
  Requires-Dist: zep-cloud (>=2.10.1,<3.0.0)
@@ -47,6 +47,7 @@ Build your AI business in three lines of code!
47
47
  ## Why?
48
48
  * Three lines of code setup
49
49
  * Fast Responses
50
+ * Solana Integration
50
51
  * Multi-Agent Swarm
51
52
  * Multi-Modal Streaming (Text & Audio)
52
53
  * Conversational Memory & History
@@ -64,6 +65,7 @@ Build your AI business in three lines of code!
64
65
 
65
66
  * Easy three lines of code setup
66
67
  * Fast AI responses
68
+ * Solana Integration via [AgentiPy](https://github.com/niceberginc/agentipy)
67
69
  * Designed for a multi-agent swarm
68
70
  * Seamless text and audio streaming with real-time multi-modal processing
69
71
  * Configurable audio voice characteristics via prompting
@@ -452,7 +454,7 @@ Tools can be used from plugins like Solana Agent Kit (sakit) or via inline tools
452
454
  * Solana Agent doesn't use OpenAI function calling (tools) as they don't support async functions
453
455
  * Solana Agent tools are async functions
454
456
 
455
- ### Internet Search (Plugin Example)
457
+ ### Internet Search
456
458
 
457
459
  `pip install sakit`
458
460
 
@@ -482,10 +484,54 @@ config = {
482
484
  }
483
485
  ],
484
486
  }
487
+ ```
488
+
489
+ ### Solana Actions
490
+
491
+ `pip install sakit`
492
+
493
+ ```python
494
+ config = {
495
+ "tools": {
496
+ "solana": {
497
+ # Core Solana Settings
498
+ "private_key": "YOUR_SOLANA_WALLET_PRIVATE_KEY", # Required (unless generate_wallet=True): Your wallet's private key (base58 encoded string).
499
+ "rpc_url": "https://api.mainnet-beta.solana.com", # Optional: Defaults to Solana mainnet RPC.
500
+ "generate_wallet": False, # Optional: If True, ignores private_key and generates a new wallet. Defaults to False.
501
+
502
+ # Optional RPC/Service API Keys & URLs
503
+ "helius_api_key": "YOUR_HELIUS_API_KEY", # Optional: Helius API key for enhanced data/RPC.
504
+ "helius_rpc_url": "YOUR_HELIUS_RPC_URL", # Optional: Specific Helius RPC URL.
505
+ "quicknode_rpc_url": "YOUR_QUICKNODE_RPC_URL", # Optional: QuickNode RPC URL.
506
+ "jito_block_engine_url": "YOUR_JITO_BLOCK_ENGINE_URL", # Optional: Jito block engine URL for bundles.
507
+ "jito_uuid": "YOUR_JITO_UUID", # Optional: Jito authentication UUID.
508
+
509
+ # Optional Integration API Keys
510
+ "openai_api_key": "YOUR_OPENAI_API_KEY", # Optional: OpenAI API key (if needed by specific agentipy features).
511
+ "backpack_api_key": "YOUR_BACKPACK_API_KEY", # Optional: Backpack Exchange API key.
512
+ "backpack_api_secret": "YOUR_BACKPACK_API_SECRET", # Optional: Backpack Exchange API secret.
513
+ "stork_api_key": "YOUR_STORK_API_KEY", # Optional: Stork oracle API key.
514
+ "coingecko_api_key": "YOUR_COINGECKO_PRO_API_KEY", # Optional: CoinGecko Pro API key.
515
+ "coingecko_demo_api_key": "YOUR_COINGECKO_DEMO_KEY", # Optional: CoinGecko Demo API key.
516
+ "elfa_ai_api_key": "YOUR_ELFA_AI_API_KEY", # Optional: Elfa AI API key.
517
+ "flexland_api_key": "YOUR_FLEXLAND_API_KEY", # Optional: Flexlend API key.
518
+ "allora_api_key": "YOUR_ALLORA_API_KEY", # Optional: Allora Network API key.
519
+ "solutiofi_api_key": "YOUR_SOLUTIOFI_API_KEY" # Optional: Solutio Finance API key.
520
+ },
521
+ },
522
+ "ai_agents": [
523
+ {
524
+ "name": "solana_expert",
525
+ "instructions": "You are an expert Solana blockchain assistant. You always use the Solana tool to perform actions on the Solana blockchain.",
526
+ "specialization": "Solana blockchain interaction",
527
+ "tools": ["solana"], # Enable the tool for this agent
528
+ }
529
+ ]
530
+ }
485
531
 
486
532
  solana_agent = SolanaAgent(config=config)
487
533
 
488
- async for response in solana_agent.process("user123", "What are the latest AI developments?"):
534
+ async for response in solana_agent.process("user123", "What is my SOL balance?"):
489
535
  print(response, end="")
490
536
  ```
491
537
 
@@ -18,6 +18,7 @@ Build your AI business in three lines of code!
18
18
  ## Why?
19
19
  * Three lines of code setup
20
20
  * Fast Responses
21
+ * Solana Integration
21
22
  * Multi-Agent Swarm
22
23
  * Multi-Modal Streaming (Text & Audio)
23
24
  * Conversational Memory & History
@@ -35,6 +36,7 @@ Build your AI business in three lines of code!
35
36
 
36
37
  * Easy three lines of code setup
37
38
  * Fast AI responses
39
+ * Solana Integration via [AgentiPy](https://github.com/niceberginc/agentipy)
38
40
  * Designed for a multi-agent swarm
39
41
  * Seamless text and audio streaming with real-time multi-modal processing
40
42
  * Configurable audio voice characteristics via prompting
@@ -423,7 +425,7 @@ Tools can be used from plugins like Solana Agent Kit (sakit) or via inline tools
423
425
  * Solana Agent doesn't use OpenAI function calling (tools) as they don't support async functions
424
426
  * Solana Agent tools are async functions
425
427
 
426
- ### Internet Search (Plugin Example)
428
+ ### Internet Search
427
429
 
428
430
  `pip install sakit`
429
431
 
@@ -453,10 +455,54 @@ config = {
453
455
  }
454
456
  ],
455
457
  }
458
+ ```
459
+
460
+ ### Solana Actions
461
+
462
+ `pip install sakit`
463
+
464
+ ```python
465
+ config = {
466
+ "tools": {
467
+ "solana": {
468
+ # Core Solana Settings
469
+ "private_key": "YOUR_SOLANA_WALLET_PRIVATE_KEY", # Required (unless generate_wallet=True): Your wallet's private key (base58 encoded string).
470
+ "rpc_url": "https://api.mainnet-beta.solana.com", # Optional: Defaults to Solana mainnet RPC.
471
+ "generate_wallet": False, # Optional: If True, ignores private_key and generates a new wallet. Defaults to False.
472
+
473
+ # Optional RPC/Service API Keys & URLs
474
+ "helius_api_key": "YOUR_HELIUS_API_KEY", # Optional: Helius API key for enhanced data/RPC.
475
+ "helius_rpc_url": "YOUR_HELIUS_RPC_URL", # Optional: Specific Helius RPC URL.
476
+ "quicknode_rpc_url": "YOUR_QUICKNODE_RPC_URL", # Optional: QuickNode RPC URL.
477
+ "jito_block_engine_url": "YOUR_JITO_BLOCK_ENGINE_URL", # Optional: Jito block engine URL for bundles.
478
+ "jito_uuid": "YOUR_JITO_UUID", # Optional: Jito authentication UUID.
479
+
480
+ # Optional Integration API Keys
481
+ "openai_api_key": "YOUR_OPENAI_API_KEY", # Optional: OpenAI API key (if needed by specific agentipy features).
482
+ "backpack_api_key": "YOUR_BACKPACK_API_KEY", # Optional: Backpack Exchange API key.
483
+ "backpack_api_secret": "YOUR_BACKPACK_API_SECRET", # Optional: Backpack Exchange API secret.
484
+ "stork_api_key": "YOUR_STORK_API_KEY", # Optional: Stork oracle API key.
485
+ "coingecko_api_key": "YOUR_COINGECKO_PRO_API_KEY", # Optional: CoinGecko Pro API key.
486
+ "coingecko_demo_api_key": "YOUR_COINGECKO_DEMO_KEY", # Optional: CoinGecko Demo API key.
487
+ "elfa_ai_api_key": "YOUR_ELFA_AI_API_KEY", # Optional: Elfa AI API key.
488
+ "flexland_api_key": "YOUR_FLEXLAND_API_KEY", # Optional: Flexlend API key.
489
+ "allora_api_key": "YOUR_ALLORA_API_KEY", # Optional: Allora Network API key.
490
+ "solutiofi_api_key": "YOUR_SOLUTIOFI_API_KEY" # Optional: Solutio Finance API key.
491
+ },
492
+ },
493
+ "ai_agents": [
494
+ {
495
+ "name": "solana_expert",
496
+ "instructions": "You are an expert Solana blockchain assistant. You always use the Solana tool to perform actions on the Solana blockchain.",
497
+ "specialization": "Solana blockchain interaction",
498
+ "tools": ["solana"], # Enable the tool for this agent
499
+ }
500
+ ]
501
+ }
456
502
 
457
503
  solana_agent = SolanaAgent(config=config)
458
504
 
459
- async for response in solana_agent.process("user123", "What are the latest AI developments?"):
505
+ async for response in solana_agent.process("user123", "What is my SOL balance?"):
460
506
  print(response, end="")
461
507
  ```
462
508
 
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "solana-agent"
3
- version = "27.3.0"
3
+ version = "27.3.2"
4
4
  description = "Agentic IQ"
5
5
  authors = ["Bevan Hunt <bevan@bevanhunt.com>"]
6
6
  license = "MIT"
@@ -24,7 +24,7 @@ python_paths = [".", "tests"]
24
24
  [tool.poetry.dependencies]
25
25
  python = ">=3.12,<4.0"
26
26
  openai = "^1.74.0"
27
- pydantic = "^2.11.3"
27
+ pydantic = ">=2"
28
28
  pymongo = "^4.12.0"
29
29
  zep-cloud = "^2.10.1"
30
30
  instructor = "^1.7.9"
@@ -194,25 +194,41 @@ class AgentService(AgentServiceInterface):
194
194
  return
195
195
 
196
196
  try:
197
- # Get system prompt
198
- system_prompt = self.get_agent_system_prompt(agent_name)
197
+ # --- 1. Get Base System Prompt ---
198
+ system_prompt_parts = [self.get_agent_system_prompt(agent_name)]
199
199
 
200
- # Add User ID and memory context
201
- system_prompt += f"\n\nUser ID: {user_id}"
202
- if memory_context:
203
- system_prompt += f"\n\nMEMORY CONTEXT: {memory_context}"
204
- if prompt:
205
- system_prompt += f"\n\nADDITIONAL PROMPT: {prompt}"
206
-
207
- # Add tool usage prompt if tools are available
208
- tool_calling_system_prompt = deepcopy(system_prompt)
200
+ # --- 2. Add Tool Usage Instructions EARLY ---
201
+ tool_usage_prompt_text = ""
209
202
  if self.tool_registry:
210
- tool_usage_prompt = self._get_tool_usage_prompt(agent_name)
211
- if tool_usage_prompt:
212
- tool_calling_system_prompt += f"\n\nTOOL CALLING PROMPT: {tool_usage_prompt}"
203
+ tool_usage_prompt_text = self._get_tool_usage_prompt(
204
+ agent_name)
205
+ if tool_usage_prompt_text:
206
+ system_prompt_parts.append(
207
+ f"\n\n--- TOOL USAGE INSTRUCTIONS ---{tool_usage_prompt_text}")
213
208
  print(
214
209
  f"Tools available to agent {agent_name}: {[t.get('name') for t in self.get_agent_tools(agent_name)]}")
215
210
 
211
+ # --- 3. Add User ID ---
212
+ system_prompt_parts.append(f"\n\n--- USER & SESSION INFO ---")
213
+ system_prompt_parts.append(f"User ID: {user_id}")
214
+
215
+ # --- 4. Add Memory Context ---
216
+ if memory_context:
217
+ # Make the header clearly separate it
218
+ system_prompt_parts.append(
219
+ f"\n\n--- CONVERSATION HISTORY (Memory Context) ---")
220
+ system_prompt_parts.append(memory_context)
221
+
222
+ # --- 5. Add Additional Prompt (if provided) ---
223
+ if prompt:
224
+ # Make the header clearly separate it
225
+ system_prompt_parts.append(
226
+ f"\n\n--- ADDITIONAL INSTRUCTIONS FOR THIS TURN ---")
227
+ system_prompt_parts.append(prompt)
228
+
229
+ # --- Assemble the final system prompt ---
230
+ final_system_prompt = "\n".join(system_prompt_parts)
231
+
216
232
  # Variables for tracking the complete response
217
233
  complete_text_response = ""
218
234
  full_response_buffer = ""
@@ -232,7 +248,7 @@ class AgentService(AgentServiceInterface):
232
248
  f"Generating response with {len(query)} characters of query text")
233
249
  async for chunk in self.llm_provider.generate_text(
234
250
  prompt=query,
235
- system_prompt=tool_calling_system_prompt,
251
+ system_prompt=final_system_prompt,
236
252
  api_key=self.api_key,
237
253
  base_url=self.base_url,
238
254
  model=self.model,
@@ -285,10 +301,36 @@ class AgentService(AgentServiceInterface):
285
301
  f"Tool execution complete, result size: {len(response_text)}")
286
302
 
287
303
  # Create new prompt with search/tool results
288
- # Using "Search Result" instead of "TOOL RESPONSE" to avoid model repeating "TOOL"
289
- user_prompt = f"{query}\n\nSearch Result: {response_text}"
290
- tool_system_prompt = system_prompt + \
291
- "\n DO NOT use the tool calling format again."
304
+ # Ensure query is string
305
+ user_prompt = f"{str(query)}\n\nTOOL RESULT: {response_text}"
306
+
307
+ # --- REBUILD the system prompt for the follow-up call ---
308
+ # Start with base prompt again
309
+ follow_up_system_prompt_parts = [
310
+ self.get_agent_system_prompt(agent_name)]
311
+ # Add the instruction NOT to use tools again
312
+ follow_up_system_prompt_parts.append(
313
+ "\n\nCRITICAL: You have received the results from a tool. Base your response on the 'Search Result' provided in the user prompt. DO NOT use the tool calling format again for this turn.")
314
+ follow_up_system_prompt_parts.append(
315
+ f"\n\n--- USER & SESSION INFO ---")
316
+ follow_up_system_prompt_parts.append(
317
+ f"User ID: {user_id}")
318
+ if memory_context:
319
+ # Make the header clearly separate it
320
+ follow_up_system_prompt_parts.append(
321
+ f"\n\n--- CONVERSATION HISTORY (Memory Context) ---")
322
+ follow_up_system_prompt_parts.append(
323
+ memory_context)
324
+ if prompt:
325
+ # Make the header clearly separate it
326
+ follow_up_system_prompt_parts.append(
327
+ f"\n\n--- ADDITIONAL INSTRUCTIONS FOR THIS TURN ---")
328
+ follow_up_system_prompt_parts.append(prompt)
329
+
330
+ # --- Assemble the final follow_up prompt ---
331
+ final_follow_up_system_prompt = "\n".join(
332
+ follow_up_system_prompt_parts)
333
+ # --- End Rebuild ---"
292
334
 
293
335
  # Generate a new response with the tool results
294
336
  print("Generating new response with tool results")
@@ -296,7 +338,7 @@ class AgentService(AgentServiceInterface):
296
338
  # Stream the follow-up response for text output
297
339
  async for processed_chunk in self.llm_provider.generate_text(
298
340
  prompt=user_prompt,
299
- system_prompt=tool_system_prompt,
341
+ system_prompt=final_follow_up_system_prompt,
300
342
  api_key=self.api_key,
301
343
  base_url=self.base_url,
302
344
  model=self.model,
@@ -308,7 +350,7 @@ class AgentService(AgentServiceInterface):
308
350
  tool_response = ""
309
351
  async for processed_chunk in self.llm_provider.generate_text(
310
352
  prompt=user_prompt,
311
- system_prompt=tool_system_prompt,
353
+ system_prompt=final_follow_up_system_prompt,
312
354
  ):
313
355
  tool_response += processed_chunk
314
356
 
@@ -489,18 +531,18 @@ class AgentService(AgentServiceInterface):
489
531
  return f"""
490
532
  AVAILABLE TOOLS:
491
533
  {tools_json}
492
-
534
+
493
535
  ⚠️ CRITICAL INSTRUCTION: When using a tool, NEVER include explanatory text.
494
536
  Only output the exact tool call format shown below with NO other text.
495
-
537
+ Always call the necessary tool to give the latest information.
538
+
496
539
  TOOL USAGE FORMAT:
497
540
  [TOOL]
498
541
  name: tool_name
499
542
  parameters: key1=value1, key2=value2
500
543
  [/TOOL]
501
-
544
+
502
545
  EXAMPLES:
503
-
504
546
  ✅ CORRECT - ONLY the tool call with NOTHING else:
505
547
  [TOOL]
506
548
  name: search_internet
@@ -513,11 +555,12 @@ class AgentService(AgentServiceInterface):
513
555
  name: search_internet
514
556
  parameters: query=latest news on Solana
515
557
  [/TOOL]
516
-
558
+
517
559
  REMEMBER:
518
560
  1. Output ONLY the exact tool call format with NO additional text
519
- 2. After seeing your tool call, I will execute it automatically
520
- 3. You will receive the tool results and can then respond to the user
561
+ 2. If the query is time-sensitive (latest news, current status, etc.), ALWAYS use the tool.
562
+ 3. After seeing your tool call, I will execute it automatically
563
+ 4. You will receive the tool results and can then respond to the user
521
564
  """
522
565
 
523
566
  def _clean_for_audio(self, text: str) -> str:
@@ -129,13 +129,19 @@ class QueryService(QueryServiceInterface):
129
129
  else:
130
130
  agent_name = await self.routing_service.route_query(user_text)
131
131
 
132
- # Combine context from memory and knowledge base
132
+ # Combine context from memory and knowledge base
133
133
  combined_context = ""
134
134
  if memory_context:
135
- combined_context += f"CONVERSATION HISTORY:\n{memory_context}\n\n"
135
+ # Add a note about memory priority
136
+ combined_context += f"CONVERSATION HISTORY (Use for context, but prioritize tools/KB for facts):\n{memory_context}\n\n"
136
137
  if kb_context:
138
+ # Keep KB context strong
137
139
  combined_context += f"{kb_context}\n"
138
140
 
141
+ # Add an overall instruction about prioritization if both are present
142
+ if memory_context or kb_context:
143
+ combined_context += "CRITICAL PRIORITIZATION GUIDE: For factual or current information, prioritize Knowledge Base results and Tool results (if applicable) over Conversation History.\n\n"
144
+
139
145
  print(f"Routed to agent: {agent_name}")
140
146
 
141
147
  # Generate response
File without changes