solana-agent 11.3.0__py3-none-any.whl → 14.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/__init__.py +33 -1
- solana_agent/adapters/__init__.py +6 -0
- solana_agent/adapters/llm_adapter.py +123 -0
- solana_agent/adapters/mongodb_adapter.py +69 -0
- solana_agent/client/__init__.py +0 -0
- solana_agent/client/solana_agent.py +75 -0
- solana_agent/domains/__init__.py +6 -0
- solana_agent/domains/agents.py +80 -0
- solana_agent/domains/routing.py +14 -0
- solana_agent/factories/__init__.py +0 -0
- solana_agent/factories/agent_factory.py +148 -0
- solana_agent/interfaces/__init__.py +11 -0
- solana_agent/interfaces/plugins/plugins.py +118 -0
- solana_agent/interfaces/providers/data_storage.py +53 -0
- solana_agent/interfaces/providers/llm.py +34 -0
- solana_agent/interfaces/providers/memory.py +38 -0
- solana_agent/interfaces/repositories/agent.py +33 -0
- solana_agent/interfaces/services/agent.py +41 -0
- solana_agent/interfaces/services/query.py +11 -0
- solana_agent/interfaces/services/routing.py +19 -0
- solana_agent/plugins/__init__.py +6 -0
- solana_agent/plugins/manager.py +147 -0
- solana_agent/plugins/registry.py +64 -0
- solana_agent/plugins/tools/__init__.py +10 -0
- solana_agent/plugins/tools/auto_tool.py +47 -0
- solana_agent/repositories/__init__.py +6 -0
- solana_agent/repositories/agent.py +99 -0
- solana_agent/repositories/memory.py +134 -0
- solana_agent/services/__init__.py +6 -0
- solana_agent/services/agent.py +320 -0
- solana_agent/services/query.py +223 -0
- solana_agent/services/routing.py +149 -0
- solana_agent-14.0.0.dist-info/METADATA +121 -0
- solana_agent-14.0.0.dist-info/RECORD +36 -0
- solana_agent/ai.py +0 -7590
- solana_agent-11.3.0.dist-info/METADATA +0 -443
- solana_agent-11.3.0.dist-info/RECORD +0 -6
- {solana_agent-11.3.0.dist-info → solana_agent-14.0.0.dist-info}/LICENSE +0 -0
- {solana_agent-11.3.0.dist-info → solana_agent-14.0.0.dist-info}/WHEEL +0 -0
solana_agent/__init__.py
CHANGED
@@ -1 +1,33 @@
|
|
1
|
-
|
1
|
+
"""
|
2
|
+
Solana Agent - An AI agent framework with routing, memory, and specialized agents.
|
3
|
+
|
4
|
+
This package provides a modular framework for building AI agent systems with
|
5
|
+
multiple specialized agents, memory management, and conversation routing.
|
6
|
+
"""
|
7
|
+
|
8
|
+
__version__ = "14.0.0" # Update with your actual version
|
9
|
+
|
10
|
+
# Client interface (main entry point)
|
11
|
+
from solana_agent.client.solana_agent import SolanaAgent
|
12
|
+
|
13
|
+
# Factory for creating agent systems
|
14
|
+
from solana_agent.factories.agent_factory import SolanaAgentFactory
|
15
|
+
|
16
|
+
# Useful tools and utilities
|
17
|
+
from solana_agent.plugins.manager import PluginManager
|
18
|
+
from solana_agent.plugins.registry import ToolRegistry
|
19
|
+
from solana_agent.plugins.tools import AutoTool
|
20
|
+
|
21
|
+
# Package metadata
|
22
|
+
__all__ = [
|
23
|
+
# Main client interfaces
|
24
|
+
"SolanaAgent",
|
25
|
+
|
26
|
+
# Factories
|
27
|
+
"SolanaAgentFactory",
|
28
|
+
|
29
|
+
# Tools
|
30
|
+
"PluginManager",
|
31
|
+
"ToolRegistry",
|
32
|
+
"AutoTool",
|
33
|
+
]
|
@@ -0,0 +1,123 @@
|
|
1
|
+
"""
|
2
|
+
LLM provider adapters for the Solana Agent system.
|
3
|
+
|
4
|
+
These adapters implement the LLMProvider interface for different LLM services.
|
5
|
+
"""
|
6
|
+
from typing import AsyncGenerator, List, Type, TypeVar
|
7
|
+
|
8
|
+
from openai import OpenAI
|
9
|
+
from pydantic import BaseModel
|
10
|
+
|
11
|
+
from solana_agent.interfaces.providers.llm import LLMProvider
|
12
|
+
|
13
|
+
T = TypeVar('T', bound=BaseModel)
|
14
|
+
|
15
|
+
|
16
|
+
class OpenAIAdapter(LLMProvider):
|
17
|
+
"""OpenAI implementation of LLMProvider with web search capabilities."""
|
18
|
+
|
19
|
+
def __init__(self, api_key: str, model: str = "gpt-4o-mini"):
|
20
|
+
self.client = OpenAI(api_key=api_key)
|
21
|
+
self.model = model
|
22
|
+
# Add search-enabled model variants
|
23
|
+
self.search_models = {
|
24
|
+
"gpt-4o": "gpt-4o-search-preview",
|
25
|
+
"gpt-4o-mini": "gpt-4o-mini-search-preview"
|
26
|
+
}
|
27
|
+
|
28
|
+
async def generate_text(
|
29
|
+
self,
|
30
|
+
prompt: str,
|
31
|
+
system_prompt: str = "",
|
32
|
+
needs_search: bool = False,
|
33
|
+
**kwargs,
|
34
|
+
) -> AsyncGenerator[str, None]:
|
35
|
+
"""Generate text from OpenAI models with web search capability."""
|
36
|
+
messages = []
|
37
|
+
|
38
|
+
if system_prompt:
|
39
|
+
messages.append({"role": "system", "content": system_prompt})
|
40
|
+
|
41
|
+
messages.append({"role": "user", "content": prompt})
|
42
|
+
|
43
|
+
# Prepare request parameters
|
44
|
+
request_params = {
|
45
|
+
"messages": messages,
|
46
|
+
"stream": kwargs.get("stream", True),
|
47
|
+
"response_format": kwargs.get("response_format", None),
|
48
|
+
}
|
49
|
+
|
50
|
+
# If search is needed, update model and add search options
|
51
|
+
if needs_search:
|
52
|
+
base_model = kwargs.get("model", self.model)
|
53
|
+
request_params["model"] = self.search_models.get(
|
54
|
+
base_model, "gpt-4o-mini-search-preview")
|
55
|
+
request_params["web_search_options"] = {
|
56
|
+
"search_context_size": "medium",
|
57
|
+
"user_location": {
|
58
|
+
"type": "approximate",
|
59
|
+
"approximate": {
|
60
|
+
"country": "US",
|
61
|
+
"timezone": "America/Los_Angeles"
|
62
|
+
}
|
63
|
+
}
|
64
|
+
}
|
65
|
+
else:
|
66
|
+
request_params["model"] = kwargs.get("model", self.model)
|
67
|
+
|
68
|
+
try:
|
69
|
+
response = self.client.chat.completions.create(**request_params)
|
70
|
+
current_text = ""
|
71
|
+
|
72
|
+
for chunk in response:
|
73
|
+
if chunk.choices:
|
74
|
+
# Handle content
|
75
|
+
if chunk.choices[0].delta.content:
|
76
|
+
text = chunk.choices[0].delta.content
|
77
|
+
current_text += text
|
78
|
+
yield text
|
79
|
+
|
80
|
+
except Exception as e:
|
81
|
+
print(f"Error in generate_text: {str(e)}")
|
82
|
+
import traceback
|
83
|
+
print(traceback.format_exc())
|
84
|
+
yield f"I apologize, but I encountered an error: {str(e)}"
|
85
|
+
|
86
|
+
def generate_embedding(self, text: str) -> List[float]:
|
87
|
+
"""Generate embeddings for a given text using OpenAI's embedding model."""
|
88
|
+
try:
|
89
|
+
response = self.client.embeddings.create(
|
90
|
+
model="text-embedding-3-small",
|
91
|
+
input=text
|
92
|
+
)
|
93
|
+
return response.data[0].embedding
|
94
|
+
except Exception as e:
|
95
|
+
print(f"Error generating embedding: {e}")
|
96
|
+
# Return a zero vector as fallback (not ideal but prevents crashing)
|
97
|
+
return [0.0] * 1536 # Standard size for text-embedding-3-small
|
98
|
+
|
99
|
+
async def parse_structured_output(
|
100
|
+
self,
|
101
|
+
prompt: str,
|
102
|
+
system_prompt: str,
|
103
|
+
model_class: Type[T],
|
104
|
+
**kwargs
|
105
|
+
) -> T:
|
106
|
+
"""Generate structured output using Pydantic model parsing."""
|
107
|
+
messages = []
|
108
|
+
if system_prompt:
|
109
|
+
messages.append({"role": "system", "content": system_prompt})
|
110
|
+
|
111
|
+
messages.append({"role": "user", "content": prompt})
|
112
|
+
|
113
|
+
try:
|
114
|
+
# First try the beta parsing API
|
115
|
+
completion = self.client.beta.chat.completions.parse(
|
116
|
+
model=kwargs.get("model", self.model),
|
117
|
+
messages=messages,
|
118
|
+
response_format=model_class,
|
119
|
+
temperature=kwargs.get("temperature", 0.2),
|
120
|
+
)
|
121
|
+
return completion.choices[0].message.parsed
|
122
|
+
except Exception as e:
|
123
|
+
print(f"Error with beta.parse method: {e}")
|
@@ -0,0 +1,69 @@
|
|
1
|
+
"""
|
2
|
+
MongoDB adapter for the Solana Agent system.
|
3
|
+
|
4
|
+
This adapter implements the DataStorageProvider interface for MongoDB.
|
5
|
+
"""
|
6
|
+
import uuid
|
7
|
+
from typing import Dict, List, Tuple, Optional
|
8
|
+
|
9
|
+
from pymongo import MongoClient
|
10
|
+
|
11
|
+
from solana_agent.interfaces.providers.data_storage import DataStorageProvider
|
12
|
+
|
13
|
+
|
14
|
+
class MongoDBAdapter(DataStorageProvider):
|
15
|
+
"""MongoDB implementation of DataStorageProvider."""
|
16
|
+
|
17
|
+
def __init__(self, connection_string: str, database_name: str):
|
18
|
+
self.client = MongoClient(connection_string)
|
19
|
+
self.db = self.client[database_name]
|
20
|
+
|
21
|
+
def create_collection(self, name: str) -> None:
|
22
|
+
if name not in self.db.list_collection_names():
|
23
|
+
self.db.create_collection(name)
|
24
|
+
|
25
|
+
def collection_exists(self, name: str) -> bool:
|
26
|
+
return name in self.db.list_collection_names()
|
27
|
+
|
28
|
+
def insert_one(self, collection: str, document: Dict) -> str:
|
29
|
+
if "_id" not in document:
|
30
|
+
document["_id"] = str(uuid.uuid4())
|
31
|
+
self.db[collection].insert_one(document)
|
32
|
+
return document["_id"]
|
33
|
+
|
34
|
+
def find_one(self, collection: str, query: Dict) -> Optional[Dict]:
|
35
|
+
return self.db[collection].find_one(query)
|
36
|
+
|
37
|
+
def find(
|
38
|
+
self,
|
39
|
+
collection: str,
|
40
|
+
query: Dict,
|
41
|
+
sort: Optional[List[Tuple]] = None,
|
42
|
+
limit: int = 0,
|
43
|
+
skip: int = 0
|
44
|
+
) -> List[Dict]:
|
45
|
+
cursor = self.db[collection].find(query)
|
46
|
+
if sort:
|
47
|
+
cursor = cursor.sort(sort)
|
48
|
+
if limit > 0:
|
49
|
+
cursor = cursor.limit(limit)
|
50
|
+
if skip > 0:
|
51
|
+
cursor = cursor.skip(skip)
|
52
|
+
return list(cursor)
|
53
|
+
|
54
|
+
def update_one(self, collection: str, query: Dict, update: Dict, upsert: bool = False) -> bool:
|
55
|
+
result = self.db[collection].update_one(query, update, upsert=upsert)
|
56
|
+
return result.modified_count > 0 or (upsert and result.upserted_id is not None)
|
57
|
+
|
58
|
+
def delete_one(self, collection: str, query: Dict) -> bool:
|
59
|
+
result = self.db[collection].delete_one(query)
|
60
|
+
return result.deleted_count > 0
|
61
|
+
|
62
|
+
def count_documents(self, collection: str, query: Dict) -> int:
|
63
|
+
return self.db[collection].count_documents(query)
|
64
|
+
|
65
|
+
def aggregate(self, collection: str, pipeline: List[Dict]) -> List[Dict]:
|
66
|
+
return list(self.db[collection].aggregate(pipeline))
|
67
|
+
|
68
|
+
def create_index(self, collection: str, keys: List[Tuple], **kwargs) -> None:
|
69
|
+
self.db[collection].create_index(keys, **kwargs)
|
File without changes
|
@@ -0,0 +1,75 @@
|
|
1
|
+
"""
|
2
|
+
Simplified client interface for interacting with the Solana Agent system.
|
3
|
+
|
4
|
+
This module provides a clean API for end users to interact with
|
5
|
+
the agent system without dealing with internal implementation details.
|
6
|
+
"""
|
7
|
+
import json
|
8
|
+
import importlib.util
|
9
|
+
from typing import AsyncGenerator, Dict, Any
|
10
|
+
|
11
|
+
from solana_agent.factories.agent_factory import SolanaAgentFactory
|
12
|
+
|
13
|
+
|
14
|
+
class SolanaAgent:
|
15
|
+
"""Simplified client interface for interacting with the agent system."""
|
16
|
+
|
17
|
+
def __init__(self, config_path: str = None, config: Dict[str, Any] = None):
|
18
|
+
"""Initialize the agent system from config file or dictionary.
|
19
|
+
|
20
|
+
Args:
|
21
|
+
config_path: Path to configuration file (JSON or Python)
|
22
|
+
config: Configuration dictionary
|
23
|
+
"""
|
24
|
+
if not config and not config_path:
|
25
|
+
raise ValueError("Either config or config_path must be provided")
|
26
|
+
|
27
|
+
if config_path:
|
28
|
+
with open(config_path, "r") as f:
|
29
|
+
if config_path.endswith(".json"):
|
30
|
+
config = json.load(f)
|
31
|
+
else:
|
32
|
+
# Assume it's a Python file
|
33
|
+
spec = importlib.util.spec_from_file_location(
|
34
|
+
"config", config_path)
|
35
|
+
config_module = importlib.util.module_from_spec(spec)
|
36
|
+
spec.loader.exec_module(config_module)
|
37
|
+
config = config_module.config
|
38
|
+
|
39
|
+
self.query_service = SolanaAgentFactory.create_from_config(config)
|
40
|
+
|
41
|
+
async def process(self, user_id: str, message: str) -> AsyncGenerator[str, None]:
|
42
|
+
"""Process a user message and return the response stream.
|
43
|
+
|
44
|
+
Args:
|
45
|
+
user_id: User ID
|
46
|
+
message: User message
|
47
|
+
|
48
|
+
Returns:
|
49
|
+
Async generator yielding response chunks
|
50
|
+
"""
|
51
|
+
async for chunk in self.query_service.process(user_id, message):
|
52
|
+
yield chunk
|
53
|
+
|
54
|
+
async def get_user_history(
|
55
|
+
self,
|
56
|
+
user_id: str,
|
57
|
+
page_num: int = 1,
|
58
|
+
page_size: int = 20,
|
59
|
+
sort_order: str = "asc" # "asc" for oldest-first, "desc" for newest-first
|
60
|
+
) -> Dict[str, Any]:
|
61
|
+
"""
|
62
|
+
Get paginated message history for a user.
|
63
|
+
|
64
|
+
Args:
|
65
|
+
user_id: User ID
|
66
|
+
page_num: Page number (starting from 1)
|
67
|
+
page_size: Number of messages per page
|
68
|
+
sort_order: Sort order ("asc" or "desc")
|
69
|
+
|
70
|
+
Returns:
|
71
|
+
Dictionary with paginated results and metadata
|
72
|
+
"""
|
73
|
+
return await self.query_service.get_user_history(
|
74
|
+
user_id, page_num, page_size, sort_order
|
75
|
+
)
|
@@ -0,0 +1,80 @@
|
|
1
|
+
"""
|
2
|
+
Domain models for AI and human agents.
|
3
|
+
|
4
|
+
This module defines the core domain models for representing
|
5
|
+
AI agents, human agents, and organization mission/values.
|
6
|
+
"""
|
7
|
+
from typing import List, Optional, Dict, Any, Union
|
8
|
+
# Import the class directly, not the module
|
9
|
+
from datetime import datetime
|
10
|
+
from pydantic import BaseModel, Field, field_validator
|
11
|
+
|
12
|
+
|
13
|
+
class OrganizationMission(BaseModel):
|
14
|
+
"""Organization mission and values to guide agent behavior."""
|
15
|
+
|
16
|
+
mission_statement: str = Field(...,
|
17
|
+
description="Organization mission statement")
|
18
|
+
values: List[Dict[str, str]] = Field(
|
19
|
+
default_factory=list,
|
20
|
+
description="Organization values as name-description pairs"
|
21
|
+
)
|
22
|
+
goals: List[str] = Field(
|
23
|
+
default_factory=list,
|
24
|
+
description="Organization goals"
|
25
|
+
)
|
26
|
+
guidance: Optional[str] = Field(
|
27
|
+
None, description="Additional guidance for agents")
|
28
|
+
|
29
|
+
@field_validator("mission_statement")
|
30
|
+
@classmethod
|
31
|
+
def mission_statement_not_empty(cls, v: str) -> str:
|
32
|
+
"""Validate that mission statement is not empty."""
|
33
|
+
if not v.strip():
|
34
|
+
raise ValueError("Mission statement cannot be empty")
|
35
|
+
return v
|
36
|
+
|
37
|
+
@field_validator("values")
|
38
|
+
@classmethod
|
39
|
+
def validate_values(cls, values: List[Dict[str, str]]) -> List[Dict[str, str]]:
|
40
|
+
"""Validate that values have proper format."""
|
41
|
+
for value in values:
|
42
|
+
if "name" not in value or "description" not in value:
|
43
|
+
raise ValueError("Each value must have a name and description")
|
44
|
+
return values
|
45
|
+
|
46
|
+
|
47
|
+
class AIAgent(BaseModel):
|
48
|
+
"""AI agent with specialized capabilities."""
|
49
|
+
|
50
|
+
model_config = {"arbitrary_types_allowed": True}
|
51
|
+
|
52
|
+
name: str = Field(..., description="Unique agent identifier name")
|
53
|
+
instructions: str = Field(...,
|
54
|
+
description="Base instructions for the agent")
|
55
|
+
specialization: str = Field(..., description="Agent's specialized domain")
|
56
|
+
model: str = Field("gpt-4o-mini", description="Language model to use")
|
57
|
+
created_at: datetime = Field(
|
58
|
+
default_factory=datetime.now, description="Creation timestamp")
|
59
|
+
updated_at: datetime = Field(
|
60
|
+
default_factory=datetime.now, description="Last update timestamp")
|
61
|
+
description: Optional[str] = Field(
|
62
|
+
None, description="Agent description or summary")
|
63
|
+
|
64
|
+
@field_validator("name", "specialization")
|
65
|
+
@classmethod
|
66
|
+
def not_empty(cls, v: str) -> str:
|
67
|
+
"""Validate that string fields are not empty."""
|
68
|
+
if not v.strip():
|
69
|
+
raise ValueError("Field cannot be empty")
|
70
|
+
return v
|
71
|
+
|
72
|
+
@field_validator("instructions")
|
73
|
+
@classmethod
|
74
|
+
def instructions_not_empty(cls, v: str) -> str:
|
75
|
+
"""Validate that instructions are not empty."""
|
76
|
+
if not v.strip():
|
77
|
+
raise ValueError("Instructions cannot be empty")
|
78
|
+
if len(v) < 10:
|
79
|
+
raise ValueError("Instructions must be at least 10 characters")
|
80
|
+
return v
|
@@ -0,0 +1,14 @@
|
|
1
|
+
from typing import List
|
2
|
+
from pydantic import BaseModel, Field
|
3
|
+
|
4
|
+
|
5
|
+
class QueryAnalysis(BaseModel):
|
6
|
+
"""Analysis of a user query for routing purposes."""
|
7
|
+
primary_specialization: str = Field(...,
|
8
|
+
description="Main specialization needed")
|
9
|
+
secondary_specializations: List[str] = Field(
|
10
|
+
..., description="Other helpful specializations")
|
11
|
+
complexity_level: int = Field(...,
|
12
|
+
description="Complexity level (1-5)")
|
13
|
+
topics: List[str] = Field(..., description="Key topics in the query")
|
14
|
+
confidence: float = Field(..., description="Confidence in the analysis")
|
File without changes
|
@@ -0,0 +1,148 @@
|
|
1
|
+
"""
|
2
|
+
Factory for creating and wiring components of the Solana Agent system.
|
3
|
+
|
4
|
+
This module handles the creation and dependency injection for all
|
5
|
+
services and components used in the system.
|
6
|
+
"""
|
7
|
+
from typing import Dict, Any
|
8
|
+
|
9
|
+
# Service imports
|
10
|
+
from solana_agent.services.query import QueryService
|
11
|
+
from solana_agent.services.agent import AgentService
|
12
|
+
from solana_agent.services.routing import RoutingService
|
13
|
+
|
14
|
+
# Repository imports
|
15
|
+
from solana_agent.repositories.memory import MemoryRepository
|
16
|
+
from solana_agent.repositories.agent import MongoAgentRepository
|
17
|
+
|
18
|
+
# Adapter imports
|
19
|
+
from solana_agent.adapters.llm_adapter import OpenAIAdapter
|
20
|
+
from solana_agent.adapters.mongodb_adapter import MongoDBAdapter
|
21
|
+
|
22
|
+
# Domain and plugin imports
|
23
|
+
from solana_agent.domains.agents import OrganizationMission
|
24
|
+
from solana_agent.plugins.manager import PluginManager
|
25
|
+
|
26
|
+
|
27
|
+
class SolanaAgentFactory:
|
28
|
+
"""Factory for creating and wiring components of the Solana Agent system."""
|
29
|
+
|
30
|
+
@staticmethod
|
31
|
+
def create_from_config(config: Dict[str, Any]) -> QueryService:
|
32
|
+
"""Create the agent system from configuration.
|
33
|
+
|
34
|
+
Args:
|
35
|
+
config: Configuration dictionary
|
36
|
+
|
37
|
+
Returns:
|
38
|
+
Configured QueryService instance
|
39
|
+
"""
|
40
|
+
# Create adapters
|
41
|
+
db_adapter = MongoDBAdapter(
|
42
|
+
connection_string=config["mongo"]["connection_string"],
|
43
|
+
database_name=config["mongo"]["database"],
|
44
|
+
)
|
45
|
+
|
46
|
+
llm_adapter = OpenAIAdapter(
|
47
|
+
api_key=config["openai"]["api_key"],
|
48
|
+
model=config.get("openai", {}).get("default_model", "gpt-4o-mini"),
|
49
|
+
)
|
50
|
+
|
51
|
+
# Create organization mission if specified in config
|
52
|
+
organization_mission = None
|
53
|
+
if "organization" in config:
|
54
|
+
org_config = config["organization"]
|
55
|
+
organization_mission = OrganizationMission(
|
56
|
+
mission_statement=org_config.get("mission_statement", ""),
|
57
|
+
values=[{"name": k, "description": v}
|
58
|
+
for k, v in org_config.get("values", {}).items()],
|
59
|
+
goals=org_config.get("goals", []),
|
60
|
+
guidance=org_config.get("guidance", "")
|
61
|
+
)
|
62
|
+
|
63
|
+
# Create repositories
|
64
|
+
memory_provider = MemoryRepository(
|
65
|
+
db_adapter, config["zep"].get("api_key"), config["zep"].get("base_url"))
|
66
|
+
agent_repo = MongoAgentRepository(db_adapter)
|
67
|
+
|
68
|
+
# Create primary services
|
69
|
+
agent_service = AgentService(
|
70
|
+
agent_repository=agent_repo,
|
71
|
+
llm_provider=llm_adapter,
|
72
|
+
organization_mission=organization_mission,
|
73
|
+
)
|
74
|
+
|
75
|
+
# Debug the agent service tool registry
|
76
|
+
print(
|
77
|
+
f"Agent service tools after initialization: {agent_service.tool_registry.list_all_tools()}")
|
78
|
+
|
79
|
+
# Create routing service
|
80
|
+
routing_service = RoutingService(
|
81
|
+
llm_provider=llm_adapter,
|
82
|
+
agent_service=agent_service,
|
83
|
+
)
|
84
|
+
|
85
|
+
# Initialize plugin system
|
86
|
+
agent_service.plugin_manager = PluginManager(
|
87
|
+
config=config,
|
88
|
+
tool_registry=agent_service.tool_registry
|
89
|
+
)
|
90
|
+
loaded_plugins = agent_service.plugin_manager.load_plugins()
|
91
|
+
print(f"Loaded {loaded_plugins} plugins")
|
92
|
+
|
93
|
+
# Sync MongoDB with config-defined agents
|
94
|
+
config_defined_agents = [agent["name"]
|
95
|
+
for agent in config.get("agents", [])]
|
96
|
+
all_db_agents = agent_repo.get_all_ai_agents()
|
97
|
+
db_agent_names = [agent.name for agent in all_db_agents]
|
98
|
+
|
99
|
+
# Delete agents not in config
|
100
|
+
agents_to_delete = [
|
101
|
+
name for name in db_agent_names if name not in config_defined_agents]
|
102
|
+
for agent_name in agents_to_delete:
|
103
|
+
print(
|
104
|
+
f"Deleting agent '{agent_name}' from MongoDB - no longer defined in config")
|
105
|
+
agent_repo.delete_ai_agent(agent_name)
|
106
|
+
|
107
|
+
# Register predefined agents
|
108
|
+
for agent_config in config.get("ai_agents", []):
|
109
|
+
agent_service.register_ai_agent(
|
110
|
+
name=agent_config["name"],
|
111
|
+
instructions=agent_config["instructions"],
|
112
|
+
specialization=agent_config["specialization"],
|
113
|
+
model=agent_config.get("model", "gpt-4o-mini"),
|
114
|
+
)
|
115
|
+
|
116
|
+
# Register tools for this agent
|
117
|
+
if "tools" in agent_config:
|
118
|
+
for tool_name in agent_config["tools"]:
|
119
|
+
print(
|
120
|
+
f"Available tools before registering {tool_name}: {agent_service.tool_registry.list_all_tools()}")
|
121
|
+
try:
|
122
|
+
agent_service.assign_tool_for_agent(
|
123
|
+
agent_config["name"], tool_name
|
124
|
+
)
|
125
|
+
print(
|
126
|
+
f"Successfully registered {tool_name} for agent {agent_config['name']}")
|
127
|
+
except ValueError as e:
|
128
|
+
print(
|
129
|
+
f"Error registering tool {tool_name} for agent {agent_config['name']}: {e}")
|
130
|
+
|
131
|
+
# Global tool registrations
|
132
|
+
if "agent_tools" in config:
|
133
|
+
for agent_name, tools in config["agent_tools"].items():
|
134
|
+
for tool_name in tools:
|
135
|
+
try:
|
136
|
+
agent_service.assign_tool_for_agent(
|
137
|
+
agent_name, tool_name)
|
138
|
+
except ValueError as e:
|
139
|
+
print(f"Error registering tool: {e}")
|
140
|
+
|
141
|
+
# Create and return the query service
|
142
|
+
query_service = QueryService(
|
143
|
+
agent_service=agent_service,
|
144
|
+
routing_service=routing_service,
|
145
|
+
memory_provider=memory_provider,
|
146
|
+
)
|
147
|
+
|
148
|
+
return query_service
|
@@ -0,0 +1,11 @@
|
|
1
|
+
"""
|
2
|
+
Abstract interfaces for the Solana Agent system.
|
3
|
+
|
4
|
+
These interfaces define the contracts that concrete implementations
|
5
|
+
must adhere to, following the Dependency Inversion Principle.
|
6
|
+
|
7
|
+
This package contains:
|
8
|
+
- Repository interfaces for data access
|
9
|
+
- Provider interfaces for external service adapters
|
10
|
+
- Service interfaces for business logic components
|
11
|
+
"""
|