solana-agent 27.4.2__py3-none-any.whl → 27.5.0__py3-none-any.whl

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.
@@ -6,16 +6,29 @@ other services to provide comprehensive responses while maintaining
6
6
  clean separation of concerns.
7
7
  """
8
8
 
9
- from typing import Any, AsyncGenerator, Dict, Literal, Optional, Union
9
+ import logging
10
+ from typing import Any, AsyncGenerator, Dict, List, Literal, Optional, Union
10
11
 
12
+ # Interface imports
11
13
  from solana_agent.interfaces.services.query import QueryService as QueryServiceInterface
12
14
  from solana_agent.interfaces.services.routing import (
13
15
  RoutingService as RoutingServiceInterface,
14
16
  )
17
+ from solana_agent.interfaces.providers.memory import (
18
+ MemoryProvider as MemoryProviderInterface,
19
+ )
20
+ from solana_agent.interfaces.services.knowledge_base import (
21
+ KnowledgeBaseService as KnowledgeBaseInterface,
22
+ )
23
+ from solana_agent.interfaces.guardrails.guardrails import (
24
+ InputGuardrail,
25
+ ) # <-- Import InputGuardrail
26
+
27
+ # Service imports (assuming AgentService is the concrete implementation)
15
28
  from solana_agent.services.agent import AgentService
16
29
  from solana_agent.services.routing import RoutingService
17
- from solana_agent.services.knowledge_base import KnowledgeBaseService
18
- from solana_agent.interfaces.providers.memory import MemoryProvider
30
+
31
+ logger = logging.getLogger(__name__)
19
32
 
20
33
 
21
34
  class QueryService(QueryServiceInterface):
@@ -25,9 +38,10 @@ class QueryService(QueryServiceInterface):
25
38
  self,
26
39
  agent_service: AgentService,
27
40
  routing_service: RoutingService,
28
- memory_provider: Optional[MemoryProvider] = None,
29
- knowledge_base: Optional[KnowledgeBaseService] = None,
41
+ memory_provider: Optional[MemoryProviderInterface] = None,
42
+ knowledge_base: Optional[KnowledgeBaseInterface] = None,
30
43
  kb_results_count: int = 3,
44
+ input_guardrails: List[InputGuardrail] = None,
31
45
  ):
32
46
  """Initialize the query service.
33
47
 
@@ -35,12 +49,16 @@ class QueryService(QueryServiceInterface):
35
49
  agent_service: Service for AI agent management
36
50
  routing_service: Service for routing queries to appropriate agents
37
51
  memory_provider: Optional provider for memory storage and retrieval
52
+ knowledge_base: Optional provider for knowledge base interactions
53
+ kb_results_count: Number of results to retrieve from knowledge base
54
+ input_guardrails: List of input guardrail instances
38
55
  """
39
56
  self.agent_service = agent_service
40
57
  self.routing_service = routing_service
41
58
  self.memory_provider = memory_provider
42
59
  self.knowledge_base = knowledge_base
43
60
  self.kb_results_count = kb_results_count
61
+ self.input_guardrails = input_guardrails or [] # <-- Store guardrails
44
62
 
45
63
  async def process(
46
64
  self,
@@ -69,7 +87,7 @@ class QueryService(QueryServiceInterface):
69
87
  prompt: Optional[str] = None,
70
88
  router: Optional[RoutingServiceInterface] = None,
71
89
  ) -> AsyncGenerator[Union[str, bytes], None]: # pragma: no cover
72
- """Process the user request with appropriate agent.
90
+ """Process the user request with appropriate agent and apply input guardrails.
73
91
 
74
92
  Args:
75
93
  user_id: User ID
@@ -86,21 +104,48 @@ class QueryService(QueryServiceInterface):
86
104
  Response chunks (text strings or audio bytes)
87
105
  """
88
106
  try:
89
- # Handle audio input if provided
107
+ # --- 1. Handle Audio Input & Extract Text ---
90
108
  user_text = ""
91
109
  if not isinstance(query, str):
110
+ logger.info(
111
+ f"Received audio input, transcribing format: {audio_input_format}"
112
+ )
92
113
  async for (
93
114
  transcript
94
115
  ) in self.agent_service.llm_provider.transcribe_audio(
95
116
  query, audio_input_format
96
117
  ):
97
118
  user_text += transcript
119
+ logger.info(f"Transcription result length: {len(user_text)}")
98
120
  else:
99
121
  user_text = query
122
+ logger.info(f"Received text input length: {len(user_text)}")
123
+
124
+ # --- 2. Apply Input Guardrails ---
125
+ original_text = user_text
126
+ processed_text = user_text
127
+ for guardrail in self.input_guardrails:
128
+ try:
129
+ processed_text = await guardrail.process(processed_text)
130
+ logger.debug(
131
+ f"Applied input guardrail: {guardrail.__class__.__name__}"
132
+ )
133
+ except Exception as e:
134
+ logger.error(
135
+ f"Error applying input guardrail {guardrail.__class__.__name__}: {e}",
136
+ exc_info=True,
137
+ )
138
+ if processed_text != original_text:
139
+ logger.info(
140
+ f"Input guardrails modified user text. Original length: {len(original_text)}, New length: {len(processed_text)}"
141
+ )
142
+ user_text = processed_text # Use the processed text going forward
143
+ # --- End Apply Input Guardrails ---
100
144
 
101
- # Handle simple greetings
145
+ # --- 3. Handle Simple Greetings ---
102
146
  if user_text.strip().lower() in ["test", "hello", "hi", "hey", "ping"]:
103
147
  response = "Hello! How can I help you today?"
148
+ logger.info("Handling simple greeting.")
104
149
  if output_format == "audio":
105
150
  async for chunk in self.agent_service.llm_provider.tts(
106
151
  text=response,
@@ -112,25 +157,32 @@ class QueryService(QueryServiceInterface):
112
157
  else:
113
158
  yield response
114
159
 
115
- # Store simple interaction in memory
160
+ # Store simple interaction in memory (using processed user_text)
116
161
  if self.memory_provider:
117
162
  await self._store_conversation(user_id, user_text, response)
118
163
  return
119
164
 
120
- # Get memory context if available
165
+ # --- 4. Get Memory Context ---
121
166
  memory_context = ""
122
167
  if self.memory_provider:
123
- memory_context = await self.memory_provider.retrieve(user_id)
168
+ try:
169
+ memory_context = await self.memory_provider.retrieve(user_id)
170
+ logger.info(
171
+ f"Retrieved memory context length: {len(memory_context)}"
172
+ )
173
+ except Exception as e:
174
+ logger.error(f"Error retrieving memory context: {e}", exc_info=True)
124
175
 
125
- # Retrieve relevant knowledge from the KB
176
+ # --- 5. Retrieve Relevant Knowledge ---
126
177
  kb_context = ""
127
178
  if self.knowledge_base:
128
179
  try:
180
+ # Use processed user_text for KB query
129
181
  kb_results = await self.knowledge_base.query(
130
182
  query_text=user_text,
131
183
  top_k=self.kb_results_count,
132
184
  include_content=True,
133
- include_metadata=False,
185
+ include_metadata=False, # Keep metadata minimal for context
134
186
  )
135
187
 
136
188
  if kb_results:
@@ -138,36 +190,47 @@ class QueryService(QueryServiceInterface):
138
190
  for i, result in enumerate(kb_results, 1):
139
191
  content = result.get("content", "").strip()
140
192
  kb_context += f"[{i}] {content}\n\n"
193
+ logger.info(
194
+ f"Retrieved {len(kb_results)} results from Knowledge Base."
195
+ )
196
+ else:
197
+ logger.info("No relevant results found in Knowledge Base.")
141
198
  except Exception as e:
142
- print(f"Error retrieving knowledge: {e}")
199
+ logger.error(f"Error retrieving knowledge: {e}", exc_info=True)
143
200
 
144
- # Route query to appropriate agent
145
- if router:
146
- agent_name = await router.route_query(user_text)
147
- else:
148
- agent_name = await self.routing_service.route_query(user_text)
201
+ # --- 6. Route Query ---
202
+ agent_name = "default" # Fallback agent
203
+ try:
204
+ # Use processed user_text for routing
205
+ if router:
206
+ agent_name = await router.route_query(user_text)
207
+ else:
208
+ agent_name = await self.routing_service.route_query(user_text)
209
+ logger.info(f"Routed query to agent: {agent_name}")
210
+ except Exception as e:
211
+ logger.error(
212
+ f"Error during routing, falling back to default agent: {e}",
213
+ exc_info=True,
214
+ )
149
215
 
150
- # Combine context from memory and knowledge base
216
+ # --- 7. Combine Context ---
151
217
  combined_context = ""
152
218
  if memory_context:
153
- # Add a note about memory priority
154
219
  combined_context += f"CONVERSATION HISTORY (Use for context, but prioritize tools/KB for facts):\n{memory_context}\n\n"
155
220
  if kb_context:
156
- # Keep KB context strong
157
221
  combined_context += f"{kb_context}\n"
158
222
 
159
- # Add an overall instruction about prioritization if both are present
160
223
  if memory_context or kb_context:
161
224
  combined_context += "CRITICAL PRIORITIZATION GUIDE: For factual or current information, prioritize Knowledge Base results and Tool results (if applicable) over Conversation History.\n\n"
225
+ logger.debug(f"Combined context length: {len(combined_context)}")
162
226
 
163
- print(f"Routed to agent: {agent_name}")
164
-
165
- # Generate response
227
+ # --- 8. Generate Response ---
228
+ # Pass the processed user_text to the agent service
166
229
  if output_format == "audio":
167
230
  async for audio_chunk in self.agent_service.generate_response(
168
231
  agent_name=agent_name,
169
232
  user_id=user_id,
170
- query=user_text,
233
+ query=user_text, # Pass processed text
171
234
  memory_context=combined_context,
172
235
  output_format="audio",
173
236
  audio_voice=audio_voice,
@@ -177,6 +240,7 @@ class QueryService(QueryServiceInterface):
177
240
  ):
178
241
  yield audio_chunk
179
242
 
243
+ # Store conversation using processed user_text
180
244
  if self.memory_provider:
181
245
  await self._store_conversation(
182
246
  user_id=user_id,
@@ -188,7 +252,7 @@ class QueryService(QueryServiceInterface):
188
252
  async for chunk in self.agent_service.generate_response(
189
253
  agent_name=agent_name,
190
254
  user_id=user_id,
191
- query=user_text,
255
+ query=user_text, # Pass processed text
192
256
  memory_context=combined_context,
193
257
  output_format="text",
194
258
  prompt=prompt,
@@ -196,6 +260,7 @@ class QueryService(QueryServiceInterface):
196
260
  yield chunk
197
261
  full_text_response += chunk
198
262
 
263
+ # Store conversation using processed user_text
199
264
  if self.memory_provider and full_text_response:
200
265
  await self._store_conversation(
201
266
  user_id=user_id,
@@ -204,22 +269,28 @@ class QueryService(QueryServiceInterface):
204
269
  )
205
270
 
206
271
  except Exception as e:
207
- error_msg = f"I apologize for the technical difficulty. {str(e)}"
272
+ import traceback
273
+
274
+ error_msg = (
275
+ "I apologize for the technical difficulty. Please try again later."
276
+ )
277
+ logger.error(f"Error in query processing: {e}\n{traceback.format_exc()}")
278
+
208
279
  if output_format == "audio":
209
- async for chunk in self.agent_service.llm_provider.tts(
210
- text=error_msg,
211
- voice=audio_voice,
212
- response_format=audio_output_format,
213
- ):
214
- yield chunk
280
+ try:
281
+ async for chunk in self.agent_service.llm_provider.tts(
282
+ text=error_msg,
283
+ voice=audio_voice,
284
+ response_format=audio_output_format,
285
+ ):
286
+ yield chunk
287
+ except Exception as tts_e:
288
+ logger.error(f"Error during TTS for error message: {tts_e}")
289
+ # Fallback to yielding text error if TTS fails
290
+ yield error_msg + f" (TTS Error: {tts_e})"
215
291
  else:
216
292
  yield error_msg
217
293
 
218
- print(f"Error in query processing: {str(e)}")
219
- import traceback
220
-
221
- print(traceback.format_exc())
222
-
223
294
  async def delete_user_history(self, user_id: str) -> None:
224
295
  """Delete all conversation history for a user.
225
296
 
@@ -229,8 +300,15 @@ class QueryService(QueryServiceInterface):
229
300
  if self.memory_provider:
230
301
  try:
231
302
  await self.memory_provider.delete(user_id)
303
+ logger.info(f"Deleted conversation history for user: {user_id}")
232
304
  except Exception as e:
233
- print(f"Error deleting user history: {str(e)}")
305
+ logger.error(
306
+ f"Error deleting user history for {user_id}: {e}", exc_info=True
307
+ )
308
+ else:
309
+ logger.warning(
310
+ "Attempted to delete user history, but no memory provider is configured."
311
+ )
234
312
 
235
313
  async def get_user_history(
236
314
  self,
@@ -248,17 +326,12 @@ class QueryService(QueryServiceInterface):
248
326
  sort_order: Sort order ("asc" or "desc")
249
327
 
250
328
  Returns:
251
- Dictionary with paginated results and metadata:
252
- {
253
- "data": List of conversation entries,
254
- "total": Total number of entries,
255
- "page": Current page number,
256
- "page_size": Number of items per page,
257
- "total_pages": Total number of pages,
258
- "error": Error message if any
259
- }
329
+ Dictionary with paginated results and metadata.
260
330
  """
261
331
  if not self.memory_provider:
332
+ logger.warning(
333
+ "Attempted to get user history, but no memory provider is configured."
334
+ )
262
335
  return {
263
336
  "data": [],
264
337
  "total": 0,
@@ -278,7 +351,7 @@ class QueryService(QueryServiceInterface):
278
351
  )
279
352
 
280
353
  # Calculate total pages
281
- total_pages = (total + page_size - 1) // page_size
354
+ total_pages = (total + page_size - 1) // page_size if total > 0 else 0
282
355
 
283
356
  # Get paginated results
284
357
  conversations = self.memory_provider.find(
@@ -292,13 +365,11 @@ class QueryService(QueryServiceInterface):
292
365
  # Format the results
293
366
  formatted_conversations = []
294
367
  for conv in conversations:
295
- # Convert datetime to Unix timestamp (seconds since epoch)
296
368
  timestamp = (
297
369
  int(conv.get("timestamp").timestamp())
298
370
  if conv.get("timestamp")
299
371
  else None
300
372
  )
301
-
302
373
  formatted_conversations.append(
303
374
  {
304
375
  "id": str(conv.get("_id")),
@@ -308,6 +379,9 @@ class QueryService(QueryServiceInterface):
308
379
  }
309
380
  )
310
381
 
382
+ logger.info(
383
+ f"Retrieved page {page_num}/{total_pages} of history for user {user_id}"
384
+ )
311
385
  return {
312
386
  "data": formatted_conversations,
313
387
  "total": total,
@@ -318,10 +392,11 @@ class QueryService(QueryServiceInterface):
318
392
  }
319
393
 
320
394
  except Exception as e:
321
- print(f"Error retrieving user history: {str(e)}")
322
395
  import traceback
323
396
 
324
- print(traceback.format_exc())
397
+ logger.error(
398
+ f"Error retrieving user history for {user_id}: {e}\n{traceback.format_exc()}"
399
+ )
325
400
  return {
326
401
  "data": [],
327
402
  "total": 0,
@@ -338,8 +413,8 @@ class QueryService(QueryServiceInterface):
338
413
 
339
414
  Args:
340
415
  user_id: User ID
341
- user_message: User message
342
- assistant_message: Assistant message
416
+ user_message: User message (potentially processed by input guardrails)
417
+ assistant_message: Assistant message (potentially processed by output guardrails)
343
418
  """
344
419
  if self.memory_provider:
345
420
  try:
@@ -350,5 +425,12 @@ class QueryService(QueryServiceInterface):
350
425
  {"role": "assistant", "content": assistant_message},
351
426
  ],
352
427
  )
428
+ logger.info(f"Stored conversation for user {user_id}")
353
429
  except Exception as e:
354
- print(f"Error storing conversation: {e}")
430
+ logger.error(
431
+ f"Error storing conversation for user {user_id}: {e}", exc_info=True
432
+ )
433
+ else:
434
+ logger.debug(
435
+ "Memory provider not configured, skipping conversation storage."
436
+ )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: solana-agent
3
- Version: 27.4.2
3
+ Version: 27.5.0
4
4
  Summary: AI Agents for Solana
5
5
  License: MIT
6
6
  Keywords: solana,solana ai,solana agent,ai,ai agent,ai agents
@@ -22,8 +22,10 @@ Requires-Dist: pinecone (>=6.0.2,<7.0.0)
22
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
+ Requires-Dist: scrubadub (>=2.0.1,<3.0.0)
25
26
  Requires-Dist: zep-cloud (>=2.10.1,<3.0.0)
26
27
  Project-URL: Documentation, https://docs.solana-agent.com
28
+ Project-URL: Homepage, https://solana-agent.com
27
29
  Project-URL: Repository, https://github.com/truemagic-coder/solana-agent
28
30
  Description-Content-Type: text/markdown
29
31
 
@@ -59,9 +61,10 @@ Build your AI agents in three lines of code!
59
61
  * Extensible Tooling
60
62
  * Knowledge Base
61
63
  * MCP Support
64
+ * Guardrails
62
65
  * Tested & Secure
63
66
  * Built in Python
64
- * Powers [CometHeart](https://cometheart.com) & [WalletBubbles](https://walletbubbles.com)
67
+ * Powers [CometHeart](https://cometheart.com)
65
68
 
66
69
  ## Features
67
70
 
@@ -80,6 +83,7 @@ Build your AI agents in three lines of code!
80
83
  * Powerful tool integration using standard Python packages and/or inline tools
81
84
  * Assigned tools are utilized by agents automatically and effectively
82
85
  * Integrated Knowledge Base with semantic search and automatic PDF chunking
86
+ * Input and output guardrails for content filtering, safety, and data sanitization
83
87
 
84
88
  ## Stack
85
89
 
@@ -447,6 +451,84 @@ async for response in solana_agent.process("user123", "Summarize the annual repo
447
451
  print(response, end="")
448
452
  ```
449
453
 
454
+ ### Guardrails
455
+
456
+ Guardrails allow you to process and potentially modify user input before it reaches the agent (Input Guardrails) and agent output before it's sent back to the user (Output Guardrails). This is useful for implementing safety checks, content moderation, data sanitization, or custom transformations.
457
+
458
+ Solana Agent provides a built-in PII scrubber based on [scrubadub](https://github.com/LeapBeyond/scrubadub).
459
+
460
+ ```python
461
+ from solana_agent import SolanaAgent
462
+
463
+ config = {
464
+ "guardrails": {
465
+ "input": [
466
+ # Example using a custom input guardrail
467
+ {
468
+ "class": "MyInputGuardrail",
469
+ "config": {"setting1": "value1"}
470
+ },
471
+ # Example using the built-in PII guardrail for input
472
+ {
473
+ "class": "solana_agent.guardrails.pii.PII",
474
+ "config": {
475
+ "locale": "en_GB", # Optional: Specify locale (default: en_US)
476
+ "replacement": "[REDACTED]" # Optional: Custom replacement format
477
+ }
478
+ }
479
+ ],
480
+ "output": [
481
+ # Example using a custom output guardrail
482
+ {
483
+ "class": "MyOutputGuardrail",
484
+ "config": {"filter_level": "high"}
485
+ },
486
+ # Example using the built-in PII guardrail for output (with defaults)
487
+ {
488
+ "class": "solana_agent.guardrails.pii.PII"
489
+ # No config needed to use defaults
490
+ }
491
+ ]
492
+ },
493
+ }
494
+ ```
495
+
496
+ #### Example Custom Guardrails
497
+
498
+ ```python
499
+ from solana_agent import InputGuardrail, OutputGuardrail
500
+ import logging
501
+
502
+ logger = logging.getLogger(__name__)
503
+
504
+ class MyInputGuardrail(InputGuardrail):
505
+ def __init__(self, config=None):
506
+ super().__init__(config)
507
+ self.setting1 = self.config.get("setting1", "default_value")
508
+ logger.info(f"MyInputGuardrail initialized with setting1: {self.setting1}")
509
+
510
+ async def process(self, text: str) -> str:
511
+ # Example: Convert input to lowercase
512
+ processed_text = text.lower()
513
+ logger.debug(f"Input Guardrail processed: {text} -> {processed_text}")
514
+ return processed_text
515
+
516
+ class MyOutputGuardrail(OutputGuardrail):
517
+ def __init__(self, config=None):
518
+ super().__init__(config)
519
+ self.filter_level = self.config.get("filter_level", "low")
520
+ logger.info(f"MyOutputGuardrail initialized with filter_level: {self.filter_level}")
521
+
522
+ async def process(self, text: str) -> str:
523
+ # Example: Basic profanity filtering (replace with a real library)
524
+ if self.filter_level == "high" and "badword" in text:
525
+ processed_text = text.replace("badword", "*******")
526
+ logger.warning(f"Output Guardrail filtered content.")
527
+ return processed_text
528
+ logger.debug("Output Guardrail passed text through.")
529
+ return text
530
+ ```
531
+
450
532
  ## Tools
451
533
 
452
534
  Tools can be used from plugins like Solana Agent Kit (sakit) or via inline tools. Tools available via plugins integrate automatically with Solana Agent.
@@ -527,7 +609,6 @@ Other MCP servers may work but are not supported.
527
609
  `pip install sakit`
528
610
 
529
611
  ```python
530
-
531
612
  from solana_agent import SolanaAgent
532
613
 
533
614
  config = {
@@ -1,4 +1,4 @@
1
- solana_agent/__init__.py,sha256=s_Dq2yqss83jp9DnHgXsxjpf9HWGRmRW2EwqroH0XKk,895
1
+ solana_agent/__init__.py,sha256=g83qhMOCwcWL19V4CYbQwl0Ykpb0xn49OUh05i-pu3g,1001
2
2
  solana_agent/adapters/__init__.py,sha256=tiEEuuy0NF3ngc_tGEcRTt71zVI58v3dYY9RvMrF2Cg,204
3
3
  solana_agent/adapters/mongodb_adapter.py,sha256=0KWIa6kaFbUFvtKUzuV_0p0RFlPPGKrDVIEU2McVY3k,2734
4
4
  solana_agent/adapters/openai_adapter.py,sha256=NZ35mJ80yVWTbdQOAYUh7hDzOFclgfdeJ1Z8v_gfQG8,10922
@@ -9,9 +9,11 @@ solana_agent/domains/__init__.py,sha256=HiC94wVPRy-QDJSSRywCRrhrFfTBeHjfi5z-QfZv
9
9
  solana_agent/domains/agent.py,sha256=3Q1wg4eIul0CPpaYBOjEthKTfcdhf1SAiWc2R-IMGO8,2561
10
10
  solana_agent/domains/routing.py,sha256=1yR4IswGcmREGgbOOI6TKCfuM7gYGOhQjLkBqnZ-rNo,582
11
11
  solana_agent/factories/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
- solana_agent/factories/agent_factory.py,sha256=y11a_OiaoWUF-xxjyVkwu6yxIo0zYq8amd3de63INq8,11729
12
+ solana_agent/factories/agent_factory.py,sha256=AsQTS2aMvt25OiQUyYsmIVsp3VLqBbnxD58qcpJ2Urk,14115
13
+ solana_agent/guardrails/pii.py,sha256=FCz1IC3mmkr41QFFf5NaC0fwJrVkwFsxgyOCS2POO5I,4428
13
14
  solana_agent/interfaces/__init__.py,sha256=IQs1WIM1FeKP1-kY2FEfyhol_dB-I-VAe2rD6jrVF6k,355
14
15
  solana_agent/interfaces/client/client.py,sha256=hsvaQiQdz3MLMNc77oD6ocvvnyl7Ez2n087ptFDA19M,3687
16
+ solana_agent/interfaces/guardrails/guardrails.py,sha256=gZCQ1FrirW-mX6s7FoYrbRs6golsp-x269kk4kQiZzc,572
15
17
  solana_agent/interfaces/plugins/plugins.py,sha256=Rz52cWBLdotwf4kV-2mC79tRYlN29zHSu1z9-y1HVPk,3329
16
18
  solana_agent/interfaces/providers/data_storage.py,sha256=Y92Cq8BtC55VlsYLD7bo3ofqQabNnlg7Q4H1Q6CDsLU,1713
17
19
  solana_agent/interfaces/providers/llm.py,sha256=SPCXsnCXj7p04E24xB0Wj1q36h2Ci4mmcNCkpHGS8LY,2417
@@ -29,11 +31,11 @@ solana_agent/plugins/tools/auto_tool.py,sha256=uihijtlc9CCqCIaRcwPuuN7o1SHIpWL2G
29
31
  solana_agent/repositories/__init__.py,sha256=fP83w83CGzXLnSdq-C5wbw9EhWTYtqE2lQTgp46-X_4,163
30
32
  solana_agent/repositories/memory.py,sha256=YYpCyiDVi3a5ZOFYFkzBS6MDjo9g2TnwbEZ5KKfKbII,7204
31
33
  solana_agent/services/__init__.py,sha256=iko0c2MlF8b_SA_nuBGFllr2E3g_JowOrOzGcnU9tkA,162
32
- solana_agent/services/agent.py,sha256=2ngtuJucGsEyNPKaWu4axd1pPgKofY-H8FeSY-MPBCU,27229
34
+ solana_agent/services/agent.py,sha256=7JRI8TcZVoVCDeIeGY9el-ingL-lRPrOneJO1uQmWFQ,35652
33
35
  solana_agent/services/knowledge_base.py,sha256=J9V8dNoCCcko3EasiGwK2JJ_A_oG_e-Ni9pgNg0T6wA,33486
34
- solana_agent/services/query.py,sha256=J81IGpy_1xsHFR3tEQkNDNoLcX9mFBJBrUcXz0pTW2w,13279
36
+ solana_agent/services/query.py,sha256=bAoUfe_2EBVEVeh99-2E9KZ0zaHUzf7Lqel3rlHyNX8,17459
35
37
  solana_agent/services/routing.py,sha256=-0fNIKDtCn0-TLUYDFYAE4jPLMeI_jCXIpgtgWDpdf8,6986
36
- solana_agent-27.4.2.dist-info/LICENSE,sha256=BnSRc-NSFuyF2s496l_4EyrwAP6YimvxWcjPiJ0J7g4,1057
37
- solana_agent-27.4.2.dist-info/METADATA,sha256=sTp--xyWhC_8TP0yt61jW9i3f1mwDBE70_vmytal9o8,23946
38
- solana_agent-27.4.2.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
39
- solana_agent-27.4.2.dist-info/RECORD,,
38
+ solana_agent-27.5.0.dist-info/LICENSE,sha256=BnSRc-NSFuyF2s496l_4EyrwAP6YimvxWcjPiJ0J7g4,1057
39
+ solana_agent-27.5.0.dist-info/METADATA,sha256=3hSaou5hzrEL1jowM6_KsofHg_VnMFnbNf7ORPGFJUM,26977
40
+ solana_agent-27.5.0.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
41
+ solana_agent-27.5.0.dist-info/RECORD,,