solana-agent 10.0.0__py3-none-any.whl → 11.0.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.
- solana_agent/ai.py +27 -166
- {solana_agent-10.0.0.dist-info → solana_agent-11.0.0.dist-info}/METADATA +61 -15
- solana_agent-11.0.0.dist-info/RECORD +6 -0
- solana_agent-10.0.0.dist-info/RECORD +0 -6
- {solana_agent-10.0.0.dist-info → solana_agent-11.0.0.dist-info}/LICENSE +0 -0
- {solana_agent-10.0.0.dist-info → solana_agent-11.0.0.dist-info}/WHEEL +0 -0
solana_agent/ai.py
CHANGED
@@ -13,7 +13,6 @@ This module implements a clean architecture approach with:
|
|
13
13
|
import asyncio
|
14
14
|
import datetime
|
15
15
|
import json
|
16
|
-
import os
|
17
16
|
import re
|
18
17
|
import traceback
|
19
18
|
import uuid
|
@@ -39,10 +38,6 @@ from zep_python.client import AsyncZep
|
|
39
38
|
from zep_cloud.types import Message
|
40
39
|
from pinecone import Pinecone
|
41
40
|
from abc import ABC, abstractmethod
|
42
|
-
import sys
|
43
|
-
import importlib
|
44
|
-
import subprocess
|
45
|
-
from pathlib import Path
|
46
41
|
|
47
42
|
|
48
43
|
#############################################
|
@@ -5034,181 +5029,47 @@ class PluginManager:
|
|
5034
5029
|
"""Manages discovery, loading and execution of plugins."""
|
5035
5030
|
|
5036
5031
|
def __init__(self, plugins_dir: str = "plugins"):
|
5037
|
-
self.plugins_dir =
|
5038
|
-
self.
|
5039
|
-
self.plugin_envs = {}
|
5032
|
+
self.plugins_dir = plugins_dir
|
5033
|
+
self.tools = {}
|
5040
5034
|
|
5041
|
-
def
|
5042
|
-
"""
|
5043
|
-
plugins = []
|
5044
|
-
|
5045
|
-
if not self.plugins_dir.exists():
|
5046
|
-
return plugins
|
5047
|
-
|
5048
|
-
for plugin_dir in self.plugins_dir.iterdir():
|
5049
|
-
if not plugin_dir.is_dir():
|
5050
|
-
continue
|
5051
|
-
|
5052
|
-
metadata_file = plugin_dir / "plugin.json"
|
5053
|
-
|
5054
|
-
if metadata_file.exists():
|
5055
|
-
try:
|
5056
|
-
with open(metadata_file, "r") as f:
|
5057
|
-
metadata = json.load(f)
|
5058
|
-
|
5059
|
-
metadata["path"] = str(plugin_dir)
|
5060
|
-
plugins.append(metadata)
|
5061
|
-
except Exception as e:
|
5062
|
-
print(
|
5063
|
-
f"Error loading plugin metadata from {metadata_file}: {e}")
|
5064
|
-
|
5065
|
-
return plugins
|
5066
|
-
|
5067
|
-
def setup_plugin_environment(self, plugin_metadata: Dict[str, Any]) -> str:
|
5068
|
-
"""Setup virtual environment for a plugin and install its dependencies.
|
5069
|
-
|
5070
|
-
Args:
|
5071
|
-
plugin_metadata: Plugin metadata including path
|
5035
|
+
def load_all_plugins(self) -> int:
|
5036
|
+
"""Load all plugins using setuptools entry points.
|
5072
5037
|
|
5073
|
-
Returns
|
5074
|
-
Path to the plugin's virtual environment
|
5038
|
+
Returns the number of plugins loaded for backwards compatibility.
|
5075
5039
|
"""
|
5076
|
-
|
5077
|
-
plugin_path = Path(plugin_metadata["path"])
|
5078
|
-
|
5079
|
-
# Create virtual environment for plugin
|
5080
|
-
env_dir = Path(self.plugins_dir) / f"{plugin_name}_env"
|
5081
|
-
|
5082
|
-
# If environment already exists, return its path
|
5083
|
-
if env_dir.exists():
|
5084
|
-
return str(env_dir)
|
5085
|
-
|
5086
|
-
print(f"Creating virtual environment for plugin {plugin_name}")
|
5087
|
-
|
5088
|
-
# Check if requirements file exists
|
5089
|
-
requirements_file = plugin_path / "requirements.txt"
|
5090
|
-
pyproject_file = plugin_path / "pyproject.toml"
|
5091
|
-
|
5092
|
-
# Create virtual environment
|
5093
|
-
import venv
|
5094
|
-
venv.create(env_dir, with_pip=True)
|
5095
|
-
|
5096
|
-
# Determine package installation command (prefer uv if available)
|
5097
|
-
try:
|
5098
|
-
# Try to import uv to check if it's installed
|
5099
|
-
import importlib.util
|
5100
|
-
uv_spec = importlib.util.find_spec("uv")
|
5101
|
-
use_uv = uv_spec is not None
|
5102
|
-
except ImportError:
|
5103
|
-
use_uv = False
|
5104
|
-
|
5105
|
-
# Install dependencies if requirements file exists
|
5106
|
-
if requirements_file.exists() or pyproject_file.exists():
|
5107
|
-
print(f"Installing requirements for plugin {plugin_name}")
|
5108
|
-
|
5109
|
-
# Prepare pip command
|
5110
|
-
if sys.platform == "win32":
|
5111
|
-
pip_path = env_dir / "Scripts" / "pip"
|
5112
|
-
else:
|
5113
|
-
pip_path = env_dir / "bin" / "pip"
|
5040
|
+
import importlib.metadata
|
5114
5041
|
|
5115
|
-
|
5042
|
+
count = 0
|
5043
|
+
# Discover plugins registered via entry_points
|
5044
|
+
for entry_point in importlib.metadata.entry_points(group='solana_agent.plugins'):
|
5116
5045
|
try:
|
5117
|
-
|
5118
|
-
|
5119
|
-
|
5120
|
-
|
5121
|
-
|
5122
|
-
|
5123
|
-
|
5124
|
-
|
5125
|
-
|
5126
|
-
|
5127
|
-
if requirements_file.exists():
|
5128
|
-
subprocess.check_call([
|
5129
|
-
str(pip_path), "install", "-r",
|
5130
|
-
str(requirements_file)
|
5131
|
-
])
|
5132
|
-
elif pyproject_file.exists():
|
5133
|
-
subprocess.check_call([
|
5134
|
-
str(pip_path), "install",
|
5135
|
-
str(plugin_path)
|
5136
|
-
])
|
5137
|
-
except subprocess.CalledProcessError as e:
|
5138
|
-
print(
|
5139
|
-
f"Failed to install dependencies for plugin {plugin_name}: {e}")
|
5140
|
-
|
5141
|
-
return str(env_dir)
|
5142
|
-
|
5143
|
-
def load_plugin(self, plugin_metadata: Dict[str, Any]) -> bool:
|
5144
|
-
"""Load a plugin and register its tools."""
|
5145
|
-
plugin_name = plugin_metadata["name"]
|
5146
|
-
plugin_path = plugin_metadata["path"]
|
5147
|
-
|
5148
|
-
# Setup environment for plugin
|
5149
|
-
env_dir = self.setup_plugin_environment(plugin_metadata)
|
5150
|
-
self.plugin_envs[plugin_name] = env_dir
|
5151
|
-
|
5152
|
-
# Add plugin directory to path temporarily (fix for import discovery)
|
5153
|
-
# We need to add the parent directory, not just the plugin directory itself
|
5154
|
-
parent_dir = os.path.dirname(str(plugin_path))
|
5155
|
-
sys.path.insert(0, parent_dir)
|
5156
|
-
|
5157
|
-
try:
|
5158
|
-
# Import the plugin module
|
5159
|
-
plugin_module = importlib.import_module(plugin_name)
|
5160
|
-
|
5161
|
-
# Call the plugin's setup function if it exists
|
5162
|
-
if hasattr(plugin_module, "register_tools"):
|
5163
|
-
plugin_module.register_tools(tool_registry)
|
5164
|
-
|
5165
|
-
self.loaded_plugins[plugin_name] = plugin_metadata
|
5166
|
-
return True
|
5167
|
-
|
5168
|
-
except Exception as e:
|
5169
|
-
print(f"Error loading plugin {plugin_name}: {e}")
|
5170
|
-
import traceback
|
5171
|
-
traceback.print_exc() # This will help debug import issues
|
5172
|
-
return False
|
5173
|
-
|
5174
|
-
finally:
|
5175
|
-
# Remove the plugin directory from path
|
5176
|
-
if parent_dir in sys.path:
|
5177
|
-
sys.path.remove(parent_dir)
|
5046
|
+
plugin_class = entry_point.load()
|
5047
|
+
plugin = plugin_class()
|
5048
|
+
|
5049
|
+
# Register all tools from this plugin
|
5050
|
+
for tool in plugin.get_tools():
|
5051
|
+
self.tools[tool.name] = tool
|
5052
|
+
print(f"Registered tool: {tool.name}")
|
5053
|
+
count += 1
|
5054
|
+
except Exception as e:
|
5055
|
+
print(f"Error loading plugin {entry_point.name}: {e}")
|
5178
5056
|
|
5179
|
-
|
5180
|
-
"""Discover and load all available plugins."""
|
5181
|
-
plugins = self.discover_plugins()
|
5182
|
-
loaded_count = 0
|
5057
|
+
return count
|
5183
5058
|
|
5184
|
-
|
5185
|
-
|
5186
|
-
|
5059
|
+
def get_tool(self, name):
|
5060
|
+
"""Get a tool by name."""
|
5061
|
+
return self.tools.get(name)
|
5187
5062
|
|
5188
|
-
|
5063
|
+
def list_tools(self):
|
5064
|
+
"""List all available tools."""
|
5065
|
+
return list(self.tools.keys())
|
5189
5066
|
|
5190
5067
|
def execute_tool(self, tool_name: str, **kwargs) -> Dict[str, Any]:
|
5191
5068
|
"""Execute a tool with provided parameters."""
|
5192
|
-
tool =
|
5069
|
+
tool = self.tools.get(tool_name)
|
5193
5070
|
if not tool:
|
5194
5071
|
raise ValueError(f"Tool {tool_name} not found")
|
5195
5072
|
|
5196
|
-
# Get the plugin name for this tool
|
5197
|
-
plugin_name = None
|
5198
|
-
for name, metadata in self.loaded_plugins.items():
|
5199
|
-
tool_list = metadata.get("tools", [])
|
5200
|
-
if isinstance(tool_list, list) and tool_name in tool_list:
|
5201
|
-
plugin_name = name
|
5202
|
-
break
|
5203
|
-
|
5204
|
-
if not plugin_name or plugin_name not in self.plugin_envs:
|
5205
|
-
# If we can't identify the plugin, execute in the current environment
|
5206
|
-
try:
|
5207
|
-
return tool.execute(**kwargs)
|
5208
|
-
except Exception as e:
|
5209
|
-
return {"error": str(e), "status": "error"}
|
5210
|
-
|
5211
|
-
# Execute in isolated environment
|
5212
5073
|
try:
|
5213
5074
|
return tool.execute(**kwargs)
|
5214
5075
|
except Exception as e:
|
@@ -1,30 +1,27 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: solana-agent
|
3
|
-
Version:
|
3
|
+
Version: 11.0.0
|
4
4
|
Summary: The Future of Work
|
5
5
|
License: MIT
|
6
6
|
Keywords: ai,openai,ai agents,agi
|
7
7
|
Author: Bevan Hunt
|
8
8
|
Author-email: bevan@bevanhunt.com
|
9
|
-
Requires-Python: >=3.
|
9
|
+
Requires-Python: >=3.12,<4.0
|
10
10
|
Classifier: License :: OSI Approved :: MIT License
|
11
11
|
Classifier: Programming Language :: Python :: 3
|
12
|
-
Classifier: Programming Language :: Python :: 3.9
|
13
|
-
Classifier: Programming Language :: Python :: 3.10
|
14
|
-
Classifier: Programming Language :: Python :: 3.11
|
15
12
|
Classifier: Programming Language :: Python :: 3.12
|
16
13
|
Classifier: Programming Language :: Python :: 3.13
|
17
14
|
Classifier: Programming Language :: Python :: 3 :: Only
|
18
15
|
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
19
16
|
Requires-Dist: ntplib (>=0.4.0,<0.5.0)
|
20
|
-
Requires-Dist: openai (>=1.
|
17
|
+
Requires-Dist: openai (>=1.66.1,<2.0.0)
|
21
18
|
Requires-Dist: pandas (>=2.2.3,<3.0.0)
|
22
19
|
Requires-Dist: pinecone (>=6.0.1,<7.0.0)
|
23
20
|
Requires-Dist: pydantic (>=2.10.6,<3.0.0)
|
24
21
|
Requires-Dist: pymongo (>=4.11.2,<5.0.0)
|
25
22
|
Requires-Dist: qdrant-client (>=1.13.3,<2.0.0)
|
26
23
|
Requires-Dist: requests (>=2.32.3,<3.0.0)
|
27
|
-
Requires-Dist: zep-cloud (>=2.
|
24
|
+
Requires-Dist: zep-cloud (>=2.6.1,<3.0.0)
|
28
25
|
Requires-Dist: zep-python (>=2.0.2,<3.0.0)
|
29
26
|
Project-URL: Repository, https://github.com/truemagic-coder/solana-agent
|
30
27
|
Description-Content-Type: text/markdown
|
@@ -33,7 +30,7 @@ Description-Content-Type: text/markdown
|
|
33
30
|
|
34
31
|
[](https://pypi.org/project/solana-agent/)
|
35
32
|
[](https://opensource.org/licenses/MIT)
|
36
|
-
[](https://www.python.org/downloads/)
|
37
34
|
[](https://codecov.io/gh/truemagic-coder/solana-agent)
|
38
35
|
[](https://github.com/truemagic-coder/solana-agent/actions/workflows/test.yml)
|
39
36
|
|
@@ -246,15 +243,15 @@ Solana Agent transforms organizations into living systems that continuously lear
|
|
246
243
|
Standardized interfaces across all tenants.
|
247
244
|
Efficient multi-tenant scaling with shared infrastructure.
|
248
245
|
|
249
|
-
- **🔌 Plugin System:**
|
250
|
-
Extensible architecture
|
251
|
-
|
246
|
+
- **🔌 Standard Python Plugin System:**
|
247
|
+
Extensible architecture using Python's native package ecosystem.
|
248
|
+
PyPI-compatible plugin distribution with standard dependency management.
|
249
|
+
Entry point registration (`solana_agent.plugins`) for seamless discovery.
|
252
250
|
Tool registry for AI agent capability extension.
|
253
251
|
Permission-based tool access for security and control.
|
254
|
-
|
252
|
+
Clean interface for third-party integrations through standard Python APIs.
|
255
253
|
Built-in internet search capabilities via Perplexity API.
|
256
|
-
|
257
|
-
Runtime tool discovery without code modification.
|
254
|
+
Runtime tool discovery without service restarts.
|
258
255
|
|
259
256
|
## Implementation Technologies
|
260
257
|
|
@@ -281,7 +278,7 @@ You can install Solana Agent using pip:
|
|
281
278
|
|
282
279
|
Each public method has a docstring for real-time IDE hinting.
|
283
280
|
|
284
|
-
## Example
|
281
|
+
## Example App
|
285
282
|
|
286
283
|
```python
|
287
284
|
from solana_agent import SolanaAgent
|
@@ -356,6 +353,55 @@ async for response in solana_agent.process("user123", "What are the latest AI de
|
|
356
353
|
print(response, end="")
|
357
354
|
```
|
358
355
|
|
356
|
+
## Example Plugin
|
357
|
+
|
358
|
+
`my_plugin/plugin.py`
|
359
|
+
|
360
|
+
```python
|
361
|
+
from solana_agent import Tool
|
362
|
+
|
363
|
+
class MyCustomTool(Tool):
|
364
|
+
@property
|
365
|
+
def name(self) -> str:
|
366
|
+
return "my_custom_tool"
|
367
|
+
|
368
|
+
@property
|
369
|
+
def description(self) -> str:
|
370
|
+
return "Does something amazing"
|
371
|
+
|
372
|
+
@property
|
373
|
+
def parameters_schema(self) -> dict:
|
374
|
+
return {
|
375
|
+
"type": "object",
|
376
|
+
"properties": {
|
377
|
+
"parameter1": {"type": "string", "description": "First parameter"}
|
378
|
+
}
|
379
|
+
}
|
380
|
+
|
381
|
+
def execute(self, **kwargs) -> dict:
|
382
|
+
# Tool implementation here
|
383
|
+
return {"result": "success", "data": "Something amazing"}
|
384
|
+
|
385
|
+
class SolanaPlugin:
|
386
|
+
def get_tools(self):
|
387
|
+
return [MyCustomTool()]
|
388
|
+
```
|
389
|
+
|
390
|
+
`pyproject.toml`
|
391
|
+
|
392
|
+
```toml
|
393
|
+
[build-system]
|
394
|
+
requires = ["setuptools>=42", "wheel"]
|
395
|
+
build-backend = "setuptools.build_meta"
|
396
|
+
|
397
|
+
[project]
|
398
|
+
name = "my-solana-plugin"
|
399
|
+
version = "0.1.0"
|
400
|
+
|
401
|
+
[project.entry-points."solana_agent.plugins"]
|
402
|
+
my_plugin = "my_plugin.plugin:SolanaPlugin"
|
403
|
+
```
|
404
|
+
|
359
405
|
## Example App
|
360
406
|
|
361
407
|
[Solana Agent Example App](https://github.com/truemagic-coder/solana-agent-app)
|
@@ -0,0 +1,6 @@
|
|
1
|
+
solana_agent/__init__.py,sha256=zpfnWqANd3OHGWm7NCF5Y6m01BWG4NkNk8SK9Ex48nA,18
|
2
|
+
solana_agent/ai.py,sha256=XM_bqGz5XLga5SEaKIgSD8_H09DbB6_ir7Tt1tbuJFw,188008
|
3
|
+
solana_agent-11.0.0.dist-info/LICENSE,sha256=BnSRc-NSFuyF2s496l_4EyrwAP6YimvxWcjPiJ0J7g4,1057
|
4
|
+
solana_agent-11.0.0.dist-info/METADATA,sha256=Ufhql8QGmSGdcQeu5FnFMmnd8qhgVEFDOFb5amIFlQY,17761
|
5
|
+
solana_agent-11.0.0.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88
|
6
|
+
solana_agent-11.0.0.dist-info/RECORD,,
|
@@ -1,6 +0,0 @@
|
|
1
|
-
solana_agent/__init__.py,sha256=zpfnWqANd3OHGWm7NCF5Y6m01BWG4NkNk8SK9Ex48nA,18
|
2
|
-
solana_agent/ai.py,sha256=434Wvowzpw48_fGlMWsBUo9oZswwK7DCcsmI_e9bcyI,193201
|
3
|
-
solana_agent-10.0.0.dist-info/LICENSE,sha256=BnSRc-NSFuyF2s496l_4EyrwAP6YimvxWcjPiJ0J7g4,1057
|
4
|
-
solana_agent-10.0.0.dist-info/METADATA,sha256=q1dcqNEPYC3wX8dcSoe08z5SWnKkO2qvAIeK1EQC-4E,16816
|
5
|
-
solana_agent-10.0.0.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88
|
6
|
-
solana_agent-10.0.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|