solana-agent 10.0.0__py3-none-any.whl → 11.0.1__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 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
  #############################################
@@ -4268,9 +4263,8 @@ class SolanaAgentFactory:
4268
4263
  llm_adapter, task_planning_service
4269
4264
  )
4270
4265
 
4271
- # Initialize plugin system if plugins directory is configured
4272
- plugins_dir = config.get("plugins_dir", "plugins")
4273
- agent_service.plugin_manager = PluginManager(plugins_dir)
4266
+ # Initialize plugin system if plugins directory is configured)
4267
+ agent_service.plugin_manager = PluginManager()
4274
4268
  loaded_plugins = agent_service.plugin_manager.load_all_plugins()
4275
4269
  print(f"Loaded {loaded_plugins} plugins")
4276
4270
 
@@ -5033,182 +5027,47 @@ tool_registry = ToolRegistry()
5033
5027
  class PluginManager:
5034
5028
  """Manages discovery, loading and execution of plugins."""
5035
5029
 
5036
- def __init__(self, plugins_dir: str = "plugins"):
5037
- self.plugins_dir = Path(plugins_dir)
5038
- self.loaded_plugins = {}
5039
- self.plugin_envs = {}
5040
-
5041
- def discover_plugins(self) -> List[Dict[str, Any]]:
5042
- """Find all plugins in the plugins directory."""
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.
5030
+ def __init__(self):
5031
+ self.tools = {}
5069
5032
 
5070
- Args:
5071
- plugin_metadata: Plugin metadata including path
5033
+ def load_all_plugins(self) -> int:
5034
+ """Load all plugins using setuptools entry points.
5072
5035
 
5073
- Returns:
5074
- Path to the plugin's virtual environment
5036
+ Returns the number of plugins loaded for backwards compatibility.
5075
5037
  """
5076
- plugin_name = plugin_metadata["name"]
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"
5038
+ import importlib.metadata
5091
5039
 
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"
5114
-
5115
- # Install dependencies using uv if available
5040
+ count = 0
5041
+ # Discover plugins registered via entry_points
5042
+ for entry_point in importlib.metadata.entry_points(group='solana_agent.plugins'):
5116
5043
  try:
5117
- if use_uv:
5118
- # Use UV for faster dependency installation
5119
- target_file = "pyproject.toml" if pyproject_file.exists() else "requirements.txt"
5120
- subprocess.check_call([
5121
- "uv", "pip", "install",
5122
- "-r" if target_file == "requirements.txt" else ".",
5123
- str(plugin_path / target_file)
5124
- ])
5125
- else:
5126
- # Fall back to regular pip
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)
5044
+ plugin_class = entry_point.load()
5045
+ plugin = plugin_class()
5046
+
5047
+ # Register all tools from this plugin
5048
+ for tool in plugin.get_tools():
5049
+ self.tools[tool.name] = tool
5050
+ print(f"Registered tool: {tool.name}")
5051
+ count += 1
5052
+ except Exception as e:
5053
+ print(f"Error loading plugin {entry_point.name}: {e}")
5178
5054
 
5179
- def load_all_plugins(self) -> int:
5180
- """Discover and load all available plugins."""
5181
- plugins = self.discover_plugins()
5182
- loaded_count = 0
5055
+ return count
5183
5056
 
5184
- for plugin_metadata in plugins:
5185
- if self.load_plugin(plugin_metadata):
5186
- loaded_count += 1
5057
+ def get_tool(self, name):
5058
+ """Get a tool by name."""
5059
+ return self.tools.get(name)
5187
5060
 
5188
- return loaded_count
5061
+ def list_tools(self):
5062
+ """List all available tools."""
5063
+ return list(self.tools.keys())
5189
5064
 
5190
5065
  def execute_tool(self, tool_name: str, **kwargs) -> Dict[str, Any]:
5191
5066
  """Execute a tool with provided parameters."""
5192
- tool = tool_registry.get_tool(tool_name)
5067
+ tool = self.tools.get(tool_name)
5193
5068
  if not tool:
5194
5069
  raise ValueError(f"Tool {tool_name} not found")
5195
5070
 
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
5071
  try:
5213
5072
  return tool.execute(**kwargs)
5214
5073
  except Exception as e:
@@ -1,30 +1,27 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: solana-agent
3
- Version: 10.0.0
3
+ Version: 11.0.1
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,<4.0
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.65.5,<2.0.0)
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.5.0,<3.0.0)
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
  [![PyPI - Version](https://img.shields.io/pypi/v/solana-agent)](https://pypi.org/project/solana-agent/)
35
32
  [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](https://opensource.org/licenses/MIT)
36
- [![Python 3.9+](https://img.shields.io/badge/python-3.9+-orange.svg)](https://www.python.org/downloads/)
33
+ [![Python 3.12+](https://img.shields.io/badge/python-3.12+-orange.svg)](https://www.python.org/downloads/)
37
34
  [![codecov](https://img.shields.io/codecov/c/github/truemagic-coder/solana-agent/main.svg)](https://codecov.io/gh/truemagic-coder/solana-agent)
38
35
  [![Build Status](https://img.shields.io/github/actions/workflow/status/truemagic-coder/solana-agent/test.yml?branch=main)](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 with dynamic tool loading capabilities.
251
- Isolated plugin environments with dependency management.
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
- Standard interface for third-party integrations.
252
+ Clean interface for third-party integrations through standard Python APIs.
255
253
  Built-in internet search capabilities via Perplexity API.
256
- Seamless AI agent interaction with external services.
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 Setup
281
+ ## Example App
285
282
 
286
283
  ```python
287
284
  from solana_agent import SolanaAgent
@@ -315,7 +312,6 @@ config = {
315
312
  "api_key": "your-pinecone-key",
316
313
  "index": "your-index"
317
314
  },
318
- "plugins_dir": "plugins",
319
315
  "ai_agents": [
320
316
  {
321
317
  "name": "research_specialist",
@@ -356,6 +352,55 @@ async for response in solana_agent.process("user123", "What are the latest AI de
356
352
  print(response, end="")
357
353
  ```
358
354
 
355
+ ## Example Plugin
356
+
357
+ `my_plugin/plugin.py`
358
+
359
+ ```python
360
+ from solana_agent import Tool
361
+
362
+ class MyCustomTool(Tool):
363
+ @property
364
+ def name(self) -> str:
365
+ return "my_custom_tool"
366
+
367
+ @property
368
+ def description(self) -> str:
369
+ return "Does something amazing"
370
+
371
+ @property
372
+ def parameters_schema(self) -> dict:
373
+ return {
374
+ "type": "object",
375
+ "properties": {
376
+ "parameter1": {"type": "string", "description": "First parameter"}
377
+ }
378
+ }
379
+
380
+ def execute(self, **kwargs) -> dict:
381
+ # Tool implementation here
382
+ return {"result": "success", "data": "Something amazing"}
383
+
384
+ class SolanaPlugin:
385
+ def get_tools(self):
386
+ return [MyCustomTool()]
387
+ ```
388
+
389
+ `pyproject.toml`
390
+
391
+ ```toml
392
+ [build-system]
393
+ requires = ["setuptools>=42", "wheel"]
394
+ build-backend = "setuptools.build_meta"
395
+
396
+ [project]
397
+ name = "my-solana-plugin"
398
+ version = "0.1.0"
399
+
400
+ [project.entry-points."solana_agent.plugins"]
401
+ my_plugin = "my_plugin.plugin:SolanaPlugin"
402
+ ```
403
+
359
404
  ## Example App
360
405
 
361
406
  [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=zhJAPg8fFGlCToQEC0XczSPmOPS_DJ97upHLAYwvhDI,187870
3
+ solana_agent-11.0.1.dist-info/LICENSE,sha256=BnSRc-NSFuyF2s496l_4EyrwAP6YimvxWcjPiJ0J7g4,1057
4
+ solana_agent-11.0.1.dist-info/METADATA,sha256=ArtGnRtBJUKKqr2DYn4DfL-bgV4_axjNLOAJvwAbEAY,17731
5
+ solana_agent-11.0.1.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88
6
+ solana_agent-11.0.1.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,,