solana-agent 27.3.6__py3-none-any.whl → 27.3.8__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.
Files changed (33) hide show
  1. solana_agent/__init__.py +1 -3
  2. solana_agent/adapters/mongodb_adapter.py +5 -2
  3. solana_agent/adapters/openai_adapter.py +32 -27
  4. solana_agent/adapters/pinecone_adapter.py +91 -63
  5. solana_agent/client/solana_agent.py +38 -23
  6. solana_agent/domains/agent.py +7 -13
  7. solana_agent/domains/routing.py +5 -5
  8. solana_agent/factories/agent_factory.py +49 -34
  9. solana_agent/interfaces/client/client.py +22 -13
  10. solana_agent/interfaces/plugins/plugins.py +2 -1
  11. solana_agent/interfaces/providers/data_storage.py +9 -2
  12. solana_agent/interfaces/providers/llm.py +26 -12
  13. solana_agent/interfaces/providers/memory.py +1 -1
  14. solana_agent/interfaces/providers/vector_storage.py +3 -9
  15. solana_agent/interfaces/services/agent.py +21 -6
  16. solana_agent/interfaces/services/knowledge_base.py +6 -8
  17. solana_agent/interfaces/services/query.py +16 -5
  18. solana_agent/interfaces/services/routing.py +0 -1
  19. solana_agent/plugins/manager.py +14 -9
  20. solana_agent/plugins/registry.py +13 -11
  21. solana_agent/plugins/tools/__init__.py +0 -5
  22. solana_agent/plugins/tools/auto_tool.py +1 -0
  23. solana_agent/repositories/memory.py +20 -22
  24. solana_agent/services/__init__.py +1 -1
  25. solana_agent/services/agent.py +119 -89
  26. solana_agent/services/knowledge_base.py +182 -131
  27. solana_agent/services/query.py +48 -24
  28. solana_agent/services/routing.py +30 -18
  29. {solana_agent-27.3.6.dist-info → solana_agent-27.3.8.dist-info}/METADATA +6 -5
  30. solana_agent-27.3.8.dist-info/RECORD +39 -0
  31. solana_agent-27.3.6.dist-info/RECORD +0 -39
  32. {solana_agent-27.3.6.dist-info → solana_agent-27.3.8.dist-info}/LICENSE +0 -0
  33. {solana_agent-27.3.6.dist-info → solana_agent-27.3.8.dist-info}/WHEEL +0 -0
@@ -4,6 +4,7 @@ Simplified client interface for interacting with the Solana Agent system.
4
4
  This module provides a clean API for end users to interact with
5
5
  the agent system without dealing with internal implementation details.
6
6
  """
7
+
7
8
  import json
8
9
  import importlib.util
9
10
  from typing import AsyncGenerator, Dict, Any, List, Literal, Optional, Union
@@ -34,8 +35,7 @@ class SolanaAgent(SolanaAgentInterface):
34
35
  config = json.load(f)
35
36
  else:
36
37
  # Assume it's a Python file
37
- spec = importlib.util.spec_from_file_location(
38
- "config", config_path)
38
+ spec = importlib.util.spec_from_file_location("config", config_path)
39
39
  config_module = importlib.util.module_from_spec(spec)
40
40
  spec.loader.exec_module(config_module)
41
41
  config = config_module.config
@@ -48,11 +48,22 @@ class SolanaAgent(SolanaAgentInterface):
48
48
  message: Union[str, bytes],
49
49
  prompt: Optional[str] = None,
50
50
  output_format: Literal["text", "audio"] = "text",
51
- audio_voice: Literal["alloy", "ash", "ballad", "coral", "echo",
52
- "fable", "onyx", "nova", "sage", "shimmer"] = "nova",
51
+ audio_voice: Literal[
52
+ "alloy",
53
+ "ash",
54
+ "ballad",
55
+ "coral",
56
+ "echo",
57
+ "fable",
58
+ "onyx",
59
+ "nova",
60
+ "sage",
61
+ "shimmer",
62
+ ] = "nova",
53
63
  audio_instructions: str = "You speak in a friendly and helpful manner.",
54
- audio_output_format: Literal['mp3', 'opus',
55
- 'aac', 'flac', 'wav', 'pcm'] = "aac",
64
+ audio_output_format: Literal[
65
+ "mp3", "opus", "aac", "flac", "wav", "pcm"
66
+ ] = "aac",
56
67
  audio_input_format: Literal[
57
68
  "flac", "mp3", "mp4", "mpeg", "mpga", "m4a", "ogg", "wav", "webm"
58
69
  ] = "mp4",
@@ -101,7 +112,7 @@ class SolanaAgent(SolanaAgentInterface):
101
112
  user_id: str,
102
113
  page_num: int = 1,
103
114
  page_size: int = 20,
104
- sort_order: str = "desc" # "asc" for oldest-first, "desc" for newest-first
115
+ sort_order: str = "desc", # "asc" for oldest-first, "desc" for newest-first
105
116
  ) -> Dict[str, Any]: # pragma: no cover
106
117
  """
107
118
  Get paginated message history for a user.
@@ -130,27 +141,29 @@ class SolanaAgent(SolanaAgentInterface):
130
141
  Returns:
131
142
  True if successful, False
132
143
  """
133
- success = self.query_service.agent_service.tool_registry.register_tool(
134
- tool)
144
+ success = self.query_service.agent_service.tool_registry.register_tool(tool)
135
145
  if success:
136
146
  self.query_service.agent_service.assign_tool_for_agent(
137
- agent_name, tool.name)
147
+ agent_name, tool.name
148
+ )
138
149
  return success
139
150
 
140
151
  def _ensure_kb(self) -> KnowledgeBaseService:
141
152
  """Checks if the knowledge base service is available and returns it."""
142
- if hasattr(self.query_service, 'knowledge_base') and self.query_service.knowledge_base:
153
+ if (
154
+ hasattr(self.query_service, "knowledge_base")
155
+ and self.query_service.knowledge_base
156
+ ):
143
157
  return self.query_service.knowledge_base
144
158
  else:
145
- raise AttributeError(
146
- "Knowledge base service not configured or available.")
159
+ raise AttributeError("Knowledge base service not configured or available.")
147
160
 
148
161
  async def kb_add_document(
149
162
  self,
150
163
  text: str,
151
164
  metadata: Dict[str, Any],
152
165
  document_id: Optional[str] = None,
153
- namespace: Optional[str] = None
166
+ namespace: Optional[str] = None,
154
167
  ) -> str:
155
168
  """
156
169
  Add a document to the knowledge base.
@@ -174,7 +187,7 @@ class SolanaAgent(SolanaAgentInterface):
174
187
  top_k: int = 5,
175
188
  namespace: Optional[str] = None,
176
189
  include_content: bool = True,
177
- include_metadata: bool = True
190
+ include_metadata: bool = True,
178
191
  ) -> List[Dict[str, Any]]:
179
192
  """
180
193
  Query the knowledge base.
@@ -191,12 +204,12 @@ class SolanaAgent(SolanaAgentInterface):
191
204
  List of matching documents.
192
205
  """
193
206
  kb = self._ensure_kb()
194
- return await kb.query(query_text, filter, top_k, namespace, include_content, include_metadata)
207
+ return await kb.query(
208
+ query_text, filter, top_k, namespace, include_content, include_metadata
209
+ )
195
210
 
196
211
  async def kb_delete_document(
197
- self,
198
- document_id: str,
199
- namespace: Optional[str] = None
212
+ self, document_id: str, namespace: Optional[str] = None
200
213
  ) -> bool:
201
214
  """
202
215
  Delete a document from the knowledge base.
@@ -216,7 +229,7 @@ class SolanaAgent(SolanaAgentInterface):
216
229
  document_id: str,
217
230
  text: Optional[str] = None,
218
231
  metadata: Optional[Dict[str, Any]] = None,
219
- namespace: Optional[str] = None
232
+ namespace: Optional[str] = None,
220
233
  ) -> bool:
221
234
  """
222
235
  Update an existing document in the knowledge base.
@@ -237,7 +250,7 @@ class SolanaAgent(SolanaAgentInterface):
237
250
  self,
238
251
  documents: List[Dict[str, Any]],
239
252
  namespace: Optional[str] = None,
240
- batch_size: int = 50
253
+ batch_size: int = 50,
241
254
  ) -> List[str]:
242
255
  """
243
256
  Add multiple documents to the knowledge base in batches.
@@ -259,7 +272,7 @@ class SolanaAgent(SolanaAgentInterface):
259
272
  metadata: Dict[str, Any],
260
273
  document_id: Optional[str] = None,
261
274
  namespace: Optional[str] = None,
262
- chunk_batch_size: int = 50
275
+ chunk_batch_size: int = 50,
263
276
  ) -> str:
264
277
  """
265
278
  Add a PDF document to the knowledge base via the client.
@@ -278,4 +291,6 @@ class SolanaAgent(SolanaAgentInterface):
278
291
  # Type check added for clarity, though handled in service
279
292
  if not isinstance(pdf_data, (bytes, str)):
280
293
  raise TypeError("pdf_data must be bytes or a file path string.")
281
- return await kb.add_pdf_document(pdf_data, metadata, document_id, namespace, chunk_batch_size)
294
+ return await kb.add_pdf_document(
295
+ pdf_data, metadata, document_id, namespace, chunk_batch_size
296
+ )
@@ -4,25 +4,20 @@ Domain models for AI and human agents.
4
4
  This module defines the core domain models for representing
5
5
  AI agents, human agents, and business mission/values.
6
6
  """
7
- from typing import List, Dict, Any
7
+
8
+ from typing import List, Dict
8
9
  from pydantic import BaseModel, Field, field_validator
9
10
 
10
11
 
11
12
  class BusinessMission(BaseModel):
12
13
  """Business mission and values to guide agent behavior."""
13
14
 
14
- mission: str = Field(...,
15
- description="Business mission statement")
15
+ mission: str = Field(..., description="Business mission statement")
16
16
  values: List[Dict[str, str]] = Field(
17
- default_factory=list,
18
- description="Business values as name-description pairs"
19
- )
20
- goals: List[str] = Field(
21
- default_factory=list,
22
- description="Business goals"
17
+ default_factory=list, description="Business values as name-description pairs"
23
18
  )
24
- voice: str = Field(
25
- None, description="Business voice or tone")
19
+ goals: List[str] = Field(default_factory=list, description="Business goals")
20
+ voice: str = Field(None, description="Business voice or tone")
26
21
 
27
22
  @field_validator("mission")
28
23
  @classmethod
@@ -56,8 +51,7 @@ class AIAgent(BaseModel):
56
51
  model_config = {"arbitrary_types_allowed": True}
57
52
 
58
53
  name: str = Field(..., description="Unique agent identifier name")
59
- instructions: str = Field(...,
60
- description="Base instructions for the agent")
54
+ instructions: str = Field(..., description="Base instructions for the agent")
61
55
  specialization: str = Field(..., description="Agent's specialized domain")
62
56
 
63
57
  @field_validator("name", "specialization")
@@ -4,11 +4,11 @@ from pydantic import BaseModel, Field
4
4
 
5
5
  class QueryAnalysis(BaseModel):
6
6
  """Analysis of a user query for routing purposes."""
7
- primary_specialization: str = Field(...,
8
- description="Main specialization needed")
7
+
8
+ primary_specialization: str = Field(..., description="Main specialization needed")
9
9
  secondary_specializations: List[str] = Field(
10
- ..., description="Other helpful specializations")
11
- complexity_level: int = Field(...,
12
- description="Complexity level (1-5)")
10
+ ..., description="Other helpful specializations"
11
+ )
12
+ complexity_level: int = Field(..., description="Complexity level (1-5)")
13
13
  topics: List[str] = Field(..., description="Key topics in the query")
14
14
  confidence: float = Field(..., description="Confidence in the analysis")
@@ -4,6 +4,7 @@ Factory for creating and wiring components of the Solana Agent system.
4
4
  This module handles the creation and dependency injection for all
5
5
  services and components used in the system.
6
6
  """
7
+
7
8
  from typing import Dict, Any
8
9
 
9
10
  # Service imports
@@ -58,10 +59,12 @@ class SolanaAgentFactory:
58
59
  org_config = config["business"]
59
60
  business_mission = BusinessMission(
60
61
  mission=org_config.get("mission", ""),
61
- values=[{"name": k, "description": v}
62
- for k, v in org_config.get("values", {}).items()],
62
+ values=[
63
+ {"name": k, "description": v}
64
+ for k, v in org_config.get("values", {}).items()
65
+ ],
63
66
  goals=org_config.get("goals", []),
64
- voice=org_config.get("voice", "")
67
+ voice=org_config.get("voice", ""),
65
68
  )
66
69
 
67
70
  # Create repositories
@@ -69,19 +72,22 @@ class SolanaAgentFactory:
69
72
 
70
73
  if "zep" in config and "mongo" in config:
71
74
  memory_provider = MemoryRepository(
72
- mongo_adapter=db_adapter, zep_api_key=config["zep"].get("api_key"))
75
+ mongo_adapter=db_adapter, zep_api_key=config["zep"].get("api_key")
76
+ )
73
77
 
74
- if "mongo" in config and not "zep" in config:
78
+ if "mongo" in config and "zep" not in config:
75
79
  memory_provider = MemoryRepository(mongo_adapter=db_adapter)
76
80
 
77
- if "zep" in config and not "mongo" in config:
81
+ if "zep" in config and "mongo" not in config:
78
82
  if "api_key" not in config["zep"]:
79
83
  raise ValueError("Zep API key is required.")
80
- memory_provider = MemoryRepository(
81
- zep_api_key=config["zep"].get("api_key")
82
- )
84
+ memory_provider = MemoryRepository(zep_api_key=config["zep"].get("api_key"))
83
85
 
84
- if "gemini" in config and "api_key" in config["gemini"] and not "grok" in config:
86
+ if (
87
+ "gemini" in config
88
+ and "api_key" in config["gemini"]
89
+ and "grok" not in config
90
+ ):
85
91
  # Create primary services
86
92
  agent_service = AgentService(
87
93
  llm_provider=llm_adapter,
@@ -101,7 +107,12 @@ class SolanaAgentFactory:
101
107
  model="gemini-2.0-flash",
102
108
  )
103
109
 
104
- elif "gemini" in config and "api_key" in config["gemini"] and "grok" in config and "api_key" in config["grok"]:
110
+ elif (
111
+ "gemini" in config
112
+ and "api_key" in config["gemini"]
113
+ and "grok" in config
114
+ and "api_key" in config["grok"]
115
+ ):
105
116
  # Create primary services
106
117
  agent_service = AgentService(
107
118
  llm_provider=llm_adapter,
@@ -120,7 +131,9 @@ class SolanaAgentFactory:
120
131
  model="gemini-2.0-flash",
121
132
  )
122
133
 
123
- elif "grok" in config and "api_key" in config["grok"] and not "gemini" in config:
134
+ elif (
135
+ "grok" in config and "api_key" in config["grok"] and "gemini" not in config
136
+ ):
124
137
  # Create primary services
125
138
  agent_service = AgentService(
126
139
  llm_provider=llm_adapter,
@@ -153,12 +166,12 @@ class SolanaAgentFactory:
153
166
 
154
167
  # Debug the agent service tool registry
155
168
  print(
156
- f"Agent service tools after initialization: {agent_service.tool_registry.list_all_tools()}")
169
+ f"Agent service tools after initialization: {agent_service.tool_registry.list_all_tools()}"
170
+ )
157
171
 
158
172
  # Initialize plugin system
159
173
  agent_service.plugin_manager = PluginManager(
160
- config=config,
161
- tool_registry=agent_service.tool_registry
174
+ config=config, tool_registry=agent_service.tool_registry
162
175
  )
163
176
  try:
164
177
  loaded_plugins = agent_service.plugin_manager.load_plugins()
@@ -179,19 +192,18 @@ class SolanaAgentFactory:
179
192
  if "tools" in agent_config:
180
193
  for tool_name in agent_config["tools"]:
181
194
  print(
182
- f"Available tools before registering {tool_name}: {agent_service.tool_registry.list_all_tools()}")
183
- agent_service.assign_tool_for_agent(
184
- agent_config["name"], tool_name
195
+ f"Available tools before registering {tool_name}: {agent_service.tool_registry.list_all_tools()}"
185
196
  )
197
+ agent_service.assign_tool_for_agent(agent_config["name"], tool_name)
186
198
  print(
187
- f"Successfully registered {tool_name} for agent {agent_config['name']}")
199
+ f"Successfully registered {tool_name} for agent {agent_config['name']}"
200
+ )
188
201
 
189
202
  # Global tool registrations
190
203
  if "agent_tools" in config:
191
204
  for agent_name, tools in config["agent_tools"].items():
192
205
  for tool_name in tools:
193
- agent_service.assign_tool_for_agent(
194
- agent_name, tool_name)
206
+ agent_service.assign_tool_for_agent(agent_name, tool_name)
195
207
 
196
208
  # Initialize Knowledge Base if configured
197
209
  knowledge_base = None
@@ -206,7 +218,8 @@ class SolanaAgentFactory:
206
218
 
207
219
  # Determine OpenAI model and dimensions for KBService
208
220
  openai_model_name = openai_embed_config.get(
209
- "model_name", "text-embedding-3-large")
221
+ "model_name", "text-embedding-3-large"
222
+ )
210
223
  if openai_model_name == "text-embedding-3-large":
211
224
  openai_dimensions = 3072
212
225
  elif openai_model_name == "text-embedding-3-small": # pragma: no cover
@@ -219,20 +232,20 @@ class SolanaAgentFactory:
219
232
  index_name=pinecone_config.get("index_name"),
220
233
  # This dimension MUST match the OpenAI model used by KBService
221
234
  embedding_dimensions=openai_dimensions,
222
- cloud_provider=pinecone_config.get(
223
- "cloud_provider", "aws"),
235
+ cloud_provider=pinecone_config.get("cloud_provider", "aws"),
224
236
  region=pinecone_config.get("region", "us-east-1"),
225
237
  metric=pinecone_config.get("metric", "cosine"),
226
238
  create_index_if_not_exists=pinecone_config.get(
227
- "create_index", True),
239
+ "create_index", True
240
+ ),
228
241
  # Reranking config
229
242
  use_reranking=pinecone_config.get("use_reranking", False),
230
243
  rerank_model=pinecone_config.get("rerank_model"),
231
244
  rerank_top_k=pinecone_config.get("rerank_top_k", 3),
232
245
  initial_query_top_k_multiplier=pinecone_config.get(
233
- "initial_query_top_k_multiplier", 5),
234
- rerank_text_field=pinecone_config.get(
235
- "rerank_text_field", "text"),
246
+ "initial_query_top_k_multiplier", 5
247
+ ),
248
+ rerank_text_field=pinecone_config.get("rerank_text_field", "text"),
236
249
  )
237
250
 
238
251
  # Create the KB service using OpenAI embeddings
@@ -240,24 +253,27 @@ class SolanaAgentFactory:
240
253
  pinecone_adapter=pinecone_adapter,
241
254
  mongodb_adapter=db_adapter,
242
255
  # Pass OpenAI config directly
243
- openai_api_key=openai_embed_config.get("api_key") or config.get("openai", {}).get(
244
- "api_key"),
256
+ openai_api_key=openai_embed_config.get("api_key")
257
+ or config.get("openai", {}).get("api_key"),
245
258
  openai_model_name=openai_model_name,
246
259
  collection_name=kb_config.get(
247
- "collection_name", "knowledge_documents"),
260
+ "collection_name", "knowledge_documents"
261
+ ),
248
262
  # Pass rerank config (though PineconeAdapter handles the logic)
249
263
  rerank_results=pinecone_config.get("use_reranking", False),
250
264
  rerank_top_k=pinecone_config.get("rerank_top_k", 3),
251
265
  # Pass splitter config
252
266
  splitter_buffer_size=splitter_config.get("buffer_size", 1),
253
267
  splitter_breakpoint_percentile=splitter_config.get(
254
- "breakpoint_percentile", 95)
268
+ "breakpoint_percentile", 95
269
+ ),
255
270
  )
256
271
  print("Knowledge Base Service initialized successfully.")
257
272
 
258
273
  except Exception as e:
259
274
  print(f"Failed to initialize Knowledge Base: {e}")
260
275
  import traceback
276
+
261
277
  print(traceback.format_exc())
262
278
  knowledge_base = None # Ensure KB is None if init fails
263
279
 
@@ -267,8 +283,7 @@ class SolanaAgentFactory:
267
283
  routing_service=routing_service,
268
284
  memory_provider=memory_provider,
269
285
  knowledge_base=knowledge_base, # Pass the potentially created KB
270
- kb_results_count=kb_config.get(
271
- "results_count", 3) if kb_config else 3
286
+ kb_results_count=kb_config.get("results_count", 3) if kb_config else 3,
272
287
  )
273
288
 
274
289
  return query_service
@@ -14,11 +14,22 @@ class SolanaAgent(ABC):
14
14
  message: Union[str, bytes],
15
15
  prompt: Optional[str] = None,
16
16
  output_format: Literal["text", "audio"] = "text",
17
- audio_voice: Literal["alloy", "ash", "ballad", "coral", "echo",
18
- "fable", "onyx", "nova", "sage", "shimmer"] = "nova",
17
+ audio_voice: Literal[
18
+ "alloy",
19
+ "ash",
20
+ "ballad",
21
+ "coral",
22
+ "echo",
23
+ "fable",
24
+ "onyx",
25
+ "nova",
26
+ "sage",
27
+ "shimmer",
28
+ ] = "nova",
19
29
  audio_instructions: str = "You speak in a friendly and helpful manner.",
20
- audio_output_format: Literal['mp3', 'opus',
21
- 'aac', 'flac', 'wav', 'pcm'] = "aac",
30
+ audio_output_format: Literal[
31
+ "mp3", "opus", "aac", "flac", "wav", "pcm"
32
+ ] = "aac",
22
33
  audio_input_format: Literal[
23
34
  "flac", "mp3", "mp4", "mpeg", "mpga", "m4a", "ogg", "wav", "webm"
24
35
  ] = "mp4",
@@ -38,7 +49,7 @@ class SolanaAgent(ABC):
38
49
  user_id: str,
39
50
  page_num: int = 1,
40
51
  page_size: int = 20,
41
- sort_order: str = "desc"
52
+ sort_order: str = "desc",
42
53
  ) -> Dict[str, Any]:
43
54
  """Get paginated message history for a user."""
44
55
  pass
@@ -54,7 +65,7 @@ class SolanaAgent(ABC):
54
65
  text: str,
55
66
  metadata: Dict[str, Any],
56
67
  document_id: Optional[str] = None,
57
- namespace: Optional[str] = None
68
+ namespace: Optional[str] = None,
58
69
  ) -> str:
59
70
  """Add a document to the knowledge base."""
60
71
  pass
@@ -67,16 +78,14 @@ class SolanaAgent(ABC):
67
78
  top_k: int = 5,
68
79
  namespace: Optional[str] = None,
69
80
  include_content: bool = True,
70
- include_metadata: bool = True
81
+ include_metadata: bool = True,
71
82
  ) -> List[Dict[str, Any]]:
72
83
  """Query the knowledge base."""
73
84
  pass
74
85
 
75
86
  @abstractmethod
76
87
  async def kb_delete_document(
77
- self,
78
- document_id: str,
79
- namespace: Optional[str] = None
88
+ self, document_id: str, namespace: Optional[str] = None
80
89
  ) -> bool:
81
90
  """Delete a document from the knowledge base."""
82
91
  pass
@@ -87,7 +96,7 @@ class SolanaAgent(ABC):
87
96
  document_id: str,
88
97
  text: Optional[str] = None,
89
98
  metadata: Optional[Dict[str, Any]] = None,
90
- namespace: Optional[str] = None
99
+ namespace: Optional[str] = None,
91
100
  ) -> bool:
92
101
  """Update an existing document in the knowledge base."""
93
102
  pass
@@ -97,7 +106,7 @@ class SolanaAgent(ABC):
97
106
  self,
98
107
  documents: List[Dict[str, Any]],
99
108
  namespace: Optional[str] = None,
100
- batch_size: int = 50
109
+ batch_size: int = 50,
101
110
  ) -> List[str]:
102
111
  """Add multiple documents to the knowledge base in batches."""
103
112
  pass
@@ -109,7 +118,7 @@ class SolanaAgent(ABC):
109
118
  metadata: Dict[str, Any],
110
119
  document_id: Optional[str] = None,
111
120
  namespace: Optional[str] = None,
112
- chunk_batch_size: int = 50
121
+ chunk_batch_size: int = 50,
113
122
  ) -> str:
114
123
  """Add a PDF document to the knowledge base."""
115
124
  pass
@@ -4,8 +4,9 @@ Plugin system interfaces.
4
4
  These interfaces define the contracts for the plugin system,
5
5
  enabling extensibility through tools and plugins.
6
6
  """
7
+
7
8
  from abc import ABC, abstractmethod
8
- from typing import Dict, List, Any, Optional, Callable
9
+ from typing import Dict, List, Any, Optional
9
10
 
10
11
 
11
12
  class Tool(ABC):
@@ -27,13 +27,20 @@ class DataStorageProvider(ABC):
27
27
 
28
28
  @abstractmethod
29
29
  def find(
30
- self, collection: str, query: Dict, sort: Optional[List] = None, limit: int = 0, skip: int = 0
30
+ self,
31
+ collection: str,
32
+ query: Dict,
33
+ sort: Optional[List] = None,
34
+ limit: int = 0,
35
+ skip: int = 0,
31
36
  ) -> List[Dict]:
32
37
  """Find documents matching query."""
33
38
  pass
34
39
 
35
40
  @abstractmethod
36
- def update_one(self, collection: str, query: Dict, update: Dict, upsert: bool = False) -> bool:
41
+ def update_one(
42
+ self, collection: str, query: Dict, update: Dict, upsert: bool = False
43
+ ) -> bool:
37
44
  """Update a document."""
38
45
  pass
39
46
 
@@ -1,10 +1,17 @@
1
1
  from abc import ABC, abstractmethod
2
- from typing import Any, AsyncGenerator, Callable, Dict, List, Literal, Optional, Type, TypeVar, Union
2
+ from typing import (
3
+ AsyncGenerator,
4
+ List,
5
+ Literal,
6
+ Optional,
7
+ Type,
8
+ TypeVar,
9
+ )
3
10
 
4
11
  from pydantic import BaseModel
5
12
 
6
13
 
7
- T = TypeVar('T', bound=BaseModel)
14
+ T = TypeVar("T", bound=BaseModel)
8
15
 
9
16
 
10
17
  class LLMProvider(ABC):
@@ -24,12 +31,13 @@ class LLMProvider(ABC):
24
31
 
25
32
  @abstractmethod
26
33
  async def parse_structured_output(
27
- self, prompt: str,
34
+ self,
35
+ prompt: str,
28
36
  system_prompt: str,
29
37
  model_class: Type[T],
30
38
  api_key: Optional[str] = None,
31
39
  base_url: Optional[str] = None,
32
- model: Optional[str] = None
40
+ model: Optional[str] = None,
33
41
  ) -> T:
34
42
  """Generate structured output using a specific model class."""
35
43
  pass
@@ -39,10 +47,19 @@ class LLMProvider(ABC):
39
47
  self,
40
48
  text: str,
41
49
  instructions: str = "You speak in a friendly and helpful manner.",
42
- voice: Literal["alloy", "ash", "ballad", "coral", "echo",
43
- "fable", "onyx", "nova", "sage", "shimmer"] = "nova",
44
- response_format: Literal['mp3', 'opus',
45
- 'aac', 'flac', 'wav', 'pcm'] = "aac",
50
+ voice: Literal[
51
+ "alloy",
52
+ "ash",
53
+ "ballad",
54
+ "coral",
55
+ "echo",
56
+ "fable",
57
+ "onyx",
58
+ "nova",
59
+ "sage",
60
+ "shimmer",
61
+ ] = "nova",
62
+ response_format: Literal["mp3", "opus", "aac", "flac", "wav", "pcm"] = "aac",
46
63
  ) -> AsyncGenerator[bytes, None]:
47
64
  """Stream text-to-speech audio from the language model."""
48
65
  pass
@@ -60,10 +77,7 @@ class LLMProvider(ABC):
60
77
 
61
78
  @abstractmethod
62
79
  async def embed_text(
63
- self,
64
- text: str,
65
- model: Optional[str] = None,
66
- dimensions: Optional[int] = None
80
+ self, text: str, model: Optional[str] = None, dimensions: Optional[int] = None
67
81
  ) -> List[float]:
68
82
  """
69
83
  Generate an embedding for the given text.
@@ -27,7 +27,7 @@ class MemoryProvider(ABC):
27
27
  query: Dict,
28
28
  sort: Optional[List[Tuple]] = None,
29
29
  limit: int = 0,
30
- skip: int = 0
30
+ skip: int = 0,
31
31
  ) -> List[Dict]:
32
32
  """Find documents matching query."""
33
33
  pass
@@ -5,9 +5,7 @@ class VectorStorageProvider:
5
5
  """Interface for Vector Storage Providers."""
6
6
 
7
7
  async def upsert(
8
- self,
9
- vectors: List[Dict[str, Any]],
10
- namespace: Optional[str] = None
8
+ self, vectors: List[Dict[str, Any]], namespace: Optional[str] = None
11
9
  ) -> None:
12
10
  """Upsert vectors into the storage."""
13
11
  pass
@@ -17,7 +15,7 @@ class VectorStorageProvider:
17
15
  texts: List[str],
18
16
  ids: List[str],
19
17
  metadatas: Optional[List[Dict[str, Any]]] = None,
20
- namespace: Optional[str] = None
18
+ namespace: Optional[str] = None,
21
19
  ) -> None:
22
20
  """Embeds texts and upserts them into the storage."""
23
21
  pass
@@ -46,11 +44,7 @@ class VectorStorageProvider:
46
44
  """Embeds query text and queries the storage."""
47
45
  pass
48
46
 
49
- async def delete(
50
- self,
51
- ids: List[str],
52
- namespace: Optional[str] = None
53
- ) -> None:
47
+ async def delete(self, ids: List[str], namespace: Optional[str] = None) -> None:
54
48
  """Delete vectors by IDs."""
55
49
  pass
56
50