solana-agent 17.1.10__tar.gz → 18.0.0__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.
- {solana_agent-17.1.10 → solana_agent-18.0.0}/PKG-INFO +1 -1
- {solana_agent-17.1.10 → solana_agent-18.0.0}/pyproject.toml +1 -1
- {solana_agent-17.1.10 → solana_agent-18.0.0}/solana_agent/interfaces/plugins/plugins.py +2 -2
- {solana_agent-17.1.10 → solana_agent-18.0.0}/solana_agent/interfaces/services/agent.py +1 -1
- {solana_agent-17.1.10 → solana_agent-18.0.0}/solana_agent/plugins/manager.py +2 -2
- {solana_agent-17.1.10 → solana_agent-18.0.0}/solana_agent/plugins/registry.py +9 -7
- {solana_agent-17.1.10 → solana_agent-18.0.0}/solana_agent/plugins/tools/auto_tool.py +1 -1
- {solana_agent-17.1.10 → solana_agent-18.0.0}/solana_agent/services/agent.py +37 -101
- {solana_agent-17.1.10 → solana_agent-18.0.0}/LICENSE +0 -0
- {solana_agent-17.1.10 → solana_agent-18.0.0}/README.md +0 -0
- {solana_agent-17.1.10 → solana_agent-18.0.0}/solana_agent/__init__.py +0 -0
- {solana_agent-17.1.10 → solana_agent-18.0.0}/solana_agent/adapters/__init__.py +0 -0
- {solana_agent-17.1.10 → solana_agent-18.0.0}/solana_agent/adapters/llm_adapter.py +0 -0
- {solana_agent-17.1.10 → solana_agent-18.0.0}/solana_agent/adapters/mongodb_adapter.py +0 -0
- {solana_agent-17.1.10 → solana_agent-18.0.0}/solana_agent/client/__init__.py +0 -0
- {solana_agent-17.1.10 → solana_agent-18.0.0}/solana_agent/client/solana_agent.py +0 -0
- {solana_agent-17.1.10 → solana_agent-18.0.0}/solana_agent/domains/__init__.py +0 -0
- {solana_agent-17.1.10 → solana_agent-18.0.0}/solana_agent/domains/agent.py +0 -0
- {solana_agent-17.1.10 → solana_agent-18.0.0}/solana_agent/domains/routing.py +0 -0
- {solana_agent-17.1.10 → solana_agent-18.0.0}/solana_agent/factories/__init__.py +0 -0
- {solana_agent-17.1.10 → solana_agent-18.0.0}/solana_agent/factories/agent_factory.py +0 -0
- {solana_agent-17.1.10 → solana_agent-18.0.0}/solana_agent/interfaces/__init__.py +0 -0
- {solana_agent-17.1.10 → solana_agent-18.0.0}/solana_agent/interfaces/client/client.py +0 -0
- {solana_agent-17.1.10 → solana_agent-18.0.0}/solana_agent/interfaces/providers/data_storage.py +0 -0
- {solana_agent-17.1.10 → solana_agent-18.0.0}/solana_agent/interfaces/providers/llm.py +0 -0
- {solana_agent-17.1.10 → solana_agent-18.0.0}/solana_agent/interfaces/providers/memory.py +0 -0
- {solana_agent-17.1.10 → solana_agent-18.0.0}/solana_agent/interfaces/services/query.py +0 -0
- {solana_agent-17.1.10 → solana_agent-18.0.0}/solana_agent/interfaces/services/routing.py +0 -0
- {solana_agent-17.1.10 → solana_agent-18.0.0}/solana_agent/plugins/__init__.py +0 -0
- {solana_agent-17.1.10 → solana_agent-18.0.0}/solana_agent/plugins/tools/__init__.py +0 -0
- {solana_agent-17.1.10 → solana_agent-18.0.0}/solana_agent/repositories/__init__.py +0 -0
- {solana_agent-17.1.10 → solana_agent-18.0.0}/solana_agent/repositories/memory.py +0 -0
- {solana_agent-17.1.10 → solana_agent-18.0.0}/solana_agent/services/__init__.py +0 -0
- {solana_agent-17.1.10 → solana_agent-18.0.0}/solana_agent/services/query.py +0 -0
- {solana_agent-17.1.10 → solana_agent-18.0.0}/solana_agent/services/routing.py +0 -0
@@ -34,7 +34,7 @@ class Tool(ABC):
|
|
34
34
|
pass
|
35
35
|
|
36
36
|
@abstractmethod
|
37
|
-
def execute(self, **params) -> Dict[str, Any]:
|
37
|
+
async def execute(self, **params) -> Dict[str, Any]:
|
38
38
|
"""Execute the tool with the given parameters."""
|
39
39
|
pass
|
40
40
|
|
@@ -118,7 +118,7 @@ class PluginManager(ABC):
|
|
118
118
|
pass
|
119
119
|
|
120
120
|
@abstractmethod
|
121
|
-
def execute_tool(self, tool_name: str, **kwargs) -> Dict[str, Any]:
|
121
|
+
async def execute_tool(self, tool_name: str, **kwargs) -> Dict[str, Any]:
|
122
122
|
"""Execute a tool with the given parameters."""
|
123
123
|
pass
|
124
124
|
|
@@ -53,7 +53,7 @@ class AgentService(ABC):
|
|
53
53
|
pass
|
54
54
|
|
55
55
|
@abstractmethod
|
56
|
-
def execute_tool(self, agent_name: str, tool_name: str, parameters: Dict[str, Any]) -> Dict[str, Any]:
|
56
|
+
async def execute_tool(self, agent_name: str, tool_name: str, parameters: Dict[str, Any]) -> Dict[str, Any]:
|
57
57
|
"""Execute a tool on behalf of an agent."""
|
58
58
|
pass
|
59
59
|
|
@@ -111,7 +111,7 @@ class PluginManager(PluginManagerInterface):
|
|
111
111
|
for plugin in self._plugins.values()
|
112
112
|
]
|
113
113
|
|
114
|
-
def execute_tool(self, tool_name: str, **kwargs) -> Dict[str, Any]:
|
114
|
+
async def execute_tool(self, tool_name: str, **kwargs) -> Dict[str, Any]:
|
115
115
|
"""Execute a tool with the given parameters.
|
116
116
|
|
117
117
|
Args:
|
@@ -126,7 +126,7 @@ class PluginManager(PluginManagerInterface):
|
|
126
126
|
return {"status": "error", "message": f"Tool {tool_name} not found"}
|
127
127
|
|
128
128
|
try:
|
129
|
-
return tool.execute(**kwargs)
|
129
|
+
return await tool.execute(**kwargs)
|
130
130
|
except Exception as e:
|
131
131
|
return {"status": "error", "message": str(e)}
|
132
132
|
|
@@ -42,15 +42,17 @@ class ToolRegistry(ToolRegistryInterface):
|
|
42
42
|
f"Error: Tool {tool_name} is not registered. Available tools: {list(self._tools.keys())}")
|
43
43
|
return False
|
44
44
|
|
45
|
+
# Initialize agent's tool list if not exists
|
45
46
|
if agent_name not in self._agent_tools:
|
46
|
-
self._agent_tools[agent_name] = []
|
47
|
+
self._agent_tools[agent_name] = [tool_name]
|
48
|
+
elif tool_name not in self._agent_tools[agent_name]:
|
49
|
+
# Add new tool to existing list
|
50
|
+
self._agent_tools[agent_name] = [
|
51
|
+
*self._agent_tools[agent_name], tool_name]
|
47
52
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
f"Successfully assigned tool {tool_name} to agent {agent_name}")
|
52
|
-
print(
|
53
|
-
f"Agent {agent_name} now has access to: {self._agent_tools[agent_name]}")
|
53
|
+
print(f"Successfully assigned tool {tool_name} to agent {agent_name}")
|
54
|
+
print(
|
55
|
+
f"Agent {agent_name} now has access to: {self._agent_tools[agent_name]}")
|
54
56
|
|
55
57
|
return True
|
56
58
|
|
@@ -41,7 +41,7 @@ class AutoTool(Tool):
|
|
41
41
|
# Override in subclasses
|
42
42
|
return {}
|
43
43
|
|
44
|
-
def execute(self, **params) -> Dict[str, Any]:
|
44
|
+
async def execute(self, **params) -> Dict[str, Any]:
|
45
45
|
"""Execute the tool with the provided parameters."""
|
46
46
|
# Override in subclasses
|
47
47
|
raise NotImplementedError("Tool must implement execute method")
|
@@ -145,7 +145,7 @@ class AgentService(AgentServiceInterface):
|
|
145
145
|
"""
|
146
146
|
return self.tool_registry.get_agent_tools(agent_name)
|
147
147
|
|
148
|
-
def execute_tool(self, agent_name: str, tool_name: str, parameters: Dict[str, Any]) -> Dict[str, Any]:
|
148
|
+
async def execute_tool(self, agent_name: str, tool_name: str, parameters: Dict[str, Any]) -> Dict[str, Any]:
|
149
149
|
"""Execute a tool on behalf of an agent."""
|
150
150
|
|
151
151
|
if not self.tool_registry:
|
@@ -165,7 +165,7 @@ class AgentService(AgentServiceInterface):
|
|
165
165
|
}
|
166
166
|
|
167
167
|
try:
|
168
|
-
result = tool.execute(**parameters)
|
168
|
+
result = await tool.execute(**parameters)
|
169
169
|
return result
|
170
170
|
except Exception as e:
|
171
171
|
import traceback
|
@@ -241,8 +241,6 @@ class AgentService(AgentServiceInterface):
|
|
241
241
|
is_json = False
|
242
242
|
text_buffer = ""
|
243
243
|
|
244
|
-
print("\n=== Starting Response Generation ===")
|
245
|
-
|
246
244
|
# Generate and stream response
|
247
245
|
async for chunk in self.llm_provider.generate_text(
|
248
246
|
prompt=query_text,
|
@@ -260,42 +258,23 @@ class AgentService(AgentServiceInterface):
|
|
260
258
|
try:
|
261
259
|
# Try to parse complete JSON
|
262
260
|
data = json.loads(json_buffer)
|
263
|
-
print(
|
264
|
-
f"Successfully parsed JSON: {json.dumps(data, indent=2)}")
|
265
261
|
|
266
262
|
# Valid JSON found, handle it
|
267
|
-
if "
|
268
|
-
|
269
|
-
|
263
|
+
if "tool_call" in data:
|
264
|
+
# Process tool call with existing method
|
265
|
+
response_text = await self._handle_tool_call(
|
270
266
|
agent_name=agent_name,
|
271
267
|
json_chunk=json_buffer
|
272
|
-
)
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
tool_response = "\n".join(tool_results)
|
277
|
-
process_prompt = f"""
|
278
|
-
{tool_response}
|
279
|
-
|
280
|
-
IMPORTANT INSTRUCTIONS:
|
281
|
-
1. Maintain ALL factual details
|
282
|
-
2. Include ALL statistics, numbers, and specific data points
|
283
|
-
3. Use direct quotes where relevant
|
284
|
-
4. Keep ALL source citations and references
|
285
|
-
5. DO NOT omit or summarize away important details
|
286
|
-
6. DO NOT add any information not present in the results
|
287
|
-
7. DO NOT make any new tool calls or return JSON
|
288
|
-
"""
|
289
|
-
|
290
|
-
# Process combined results through LLM with modified system prompt
|
291
|
-
summary_system_prompt = self.get_agent_system_prompt(agent_name) + \
|
292
|
-
"\n DO NOT make any tool calls or return JSON. Present ALL facts and maintain ALL details from the source material."
|
268
|
+
)
|
269
|
+
|
270
|
+
system_prompt = self.get_agent_system_prompt(agent_name) + \
|
271
|
+
"\n DO NOT make any tool calls or return JSON."
|
293
272
|
|
294
273
|
# Collect all processed text first
|
295
274
|
processed_text = ""
|
296
275
|
async for processed_chunk in self.llm_provider.generate_text(
|
297
|
-
prompt=
|
298
|
-
system_prompt=
|
276
|
+
prompt=response_text,
|
277
|
+
system_prompt=system_prompt,
|
299
278
|
):
|
300
279
|
processed_text += processed_chunk
|
301
280
|
# For text output, yield chunks as they come
|
@@ -388,6 +367,30 @@ class AgentService(AgentServiceInterface):
|
|
388
367
|
import traceback
|
389
368
|
print(traceback.format_exc())
|
390
369
|
|
370
|
+
async def _handle_tool_call(
|
371
|
+
self,
|
372
|
+
agent_name: str,
|
373
|
+
json_chunk: str,
|
374
|
+
) -> str:
|
375
|
+
"""Handle tool calls and return formatted response."""
|
376
|
+
try:
|
377
|
+
data = json.loads(json_chunk)
|
378
|
+
if "tool_call" in data:
|
379
|
+
tool_data = data["tool_call"]
|
380
|
+
tool_name = tool_data.get("name")
|
381
|
+
parameters = tool_data.get("parameters", {})
|
382
|
+
|
383
|
+
if tool_name:
|
384
|
+
result = await self.execute_tool(
|
385
|
+
agent_name, tool_name, parameters)
|
386
|
+
if result.get("status") == "success":
|
387
|
+
return result.get("result", "")
|
388
|
+
else:
|
389
|
+
return f"I apologize, but I encountered an issue: {result.get('message', 'Unknown error')}"
|
390
|
+
return json_chunk
|
391
|
+
except json.JSONDecodeError:
|
392
|
+
return json_chunk
|
393
|
+
|
391
394
|
def _get_tool_usage_prompt(self, agent_name: str) -> str:
|
392
395
|
"""Generate JSON-based instructions for tool usage."""
|
393
396
|
# Get tools assigned to this agent
|
@@ -399,94 +402,27 @@ class AgentService(AgentServiceInterface):
|
|
399
402
|
available_tool_names = [tool.get("name", "") for tool in tools]
|
400
403
|
tools_json = json.dumps(tools, indent=2)
|
401
404
|
|
402
|
-
# Create tool example if search is available
|
403
|
-
tool_example = ""
|
404
|
-
if "search_internet" in available_tool_names:
|
405
|
-
tool_example = """
|
406
|
-
For latest news query:
|
407
|
-
{
|
408
|
-
"tool_calls": [{
|
409
|
-
"name": "search_internet",
|
410
|
-
"parameters": {
|
411
|
-
"query": "latest Solana blockchain news March 2025"
|
412
|
-
}
|
413
|
-
}]
|
414
|
-
}"""
|
415
|
-
|
416
405
|
return f"""
|
417
406
|
AVAILABLE TOOLS:
|
418
407
|
{tools_json}
|
419
408
|
|
420
409
|
TOOL USAGE FORMAT:
|
421
410
|
{{
|
422
|
-
"
|
411
|
+
"tool_call": {{
|
423
412
|
"name": "<one_of:{', '.join(available_tool_names)}>",
|
424
413
|
"parameters": {{
|
425
414
|
// parameters as specified in tool definition above
|
426
415
|
}}
|
427
|
-
}}
|
416
|
+
}}
|
428
417
|
}}
|
429
418
|
|
430
|
-
{tool_example if tool_example else ''}
|
431
|
-
|
432
419
|
RESPONSE RULES:
|
433
420
|
1. For tool usage:
|
434
421
|
- Only use tools from the AVAILABLE TOOLS list above
|
435
422
|
- Follow the exact parameter format shown in the tool definition
|
436
|
-
- Include "March 2025" in any search queries for current information
|
437
423
|
|
438
424
|
2. Format Requirements:
|
439
425
|
- Return ONLY the JSON object for tool calls
|
440
426
|
- No explanation text before or after
|
441
427
|
- Use exact tool names as shown in AVAILABLE TOOLS
|
442
428
|
"""
|
443
|
-
|
444
|
-
async def _handle_multiple_tool_calls(
|
445
|
-
self,
|
446
|
-
agent_name: str,
|
447
|
-
json_chunk: str,
|
448
|
-
) -> AsyncGenerator[str, None]:
|
449
|
-
"""Handle multiple tool calls concurrently and yield results as they complete."""
|
450
|
-
try:
|
451
|
-
data = json.loads(json_chunk)
|
452
|
-
if "tool_calls" not in data:
|
453
|
-
yield json_chunk
|
454
|
-
return
|
455
|
-
|
456
|
-
tool_calls = data["tool_calls"]
|
457
|
-
|
458
|
-
if not isinstance(tool_calls, list):
|
459
|
-
print("Error: tool_calls is not a list")
|
460
|
-
yield "Error: 'tool_calls' must be an array of tool calls."
|
461
|
-
return
|
462
|
-
|
463
|
-
# Define individual tool execution coroutine
|
464
|
-
async def execute_single_tool(tool_info):
|
465
|
-
tool_name = tool_info.get("name")
|
466
|
-
parameters = tool_info.get("parameters", {})
|
467
|
-
print(f"\nExecuting tool: {tool_name}")
|
468
|
-
print(f"With parameters: {parameters}")
|
469
|
-
|
470
|
-
if not tool_name:
|
471
|
-
return f"Error: Missing tool name in tool call."
|
472
|
-
|
473
|
-
result = self.execute_tool(agent_name, tool_name, parameters)
|
474
|
-
|
475
|
-
if result.get("status") == "success":
|
476
|
-
return f"Result from {tool_name}: {result.get('result', '')}"
|
477
|
-
else:
|
478
|
-
return f"Error from {tool_name}: {result.get('message', 'Unknown error')}"
|
479
|
-
|
480
|
-
# Execute all tool calls concurrently
|
481
|
-
tasks = [execute_single_tool(tool_call)
|
482
|
-
for tool_call in tool_calls]
|
483
|
-
for task in asyncio.as_completed(tasks):
|
484
|
-
result = await task
|
485
|
-
yield result
|
486
|
-
|
487
|
-
except json.JSONDecodeError:
|
488
|
-
yield "Error: Could not parse tool calls JSON."
|
489
|
-
except Exception as e:
|
490
|
-
import traceback
|
491
|
-
print(traceback.format_exc())
|
492
|
-
yield f"Error processing tool calls: {str(e)}"
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{solana_agent-17.1.10 → solana_agent-18.0.0}/solana_agent/interfaces/providers/data_storage.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|