solana-agent 19.0.2__tar.gz → 19.1.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.
Files changed (35) hide show
  1. {solana_agent-19.0.2 → solana_agent-19.1.0}/PKG-INFO +40 -26
  2. {solana_agent-19.0.2 → solana_agent-19.1.0}/README.md +37 -23
  3. {solana_agent-19.0.2 → solana_agent-19.1.0}/pyproject.toml +3 -3
  4. {solana_agent-19.0.2 → solana_agent-19.1.0}/solana_agent/adapters/llm_adapter.py +0 -13
  5. {solana_agent-19.0.2 → solana_agent-19.1.0}/solana_agent/client/solana_agent.py +3 -0
  6. {solana_agent-19.0.2 → solana_agent-19.1.0}/solana_agent/factories/agent_factory.py +28 -6
  7. {solana_agent-19.0.2 → solana_agent-19.1.0}/solana_agent/interfaces/client/client.py +3 -2
  8. {solana_agent-19.0.2 → solana_agent-19.1.0}/solana_agent/interfaces/providers/llm.py +0 -5
  9. {solana_agent-19.0.2 → solana_agent-19.1.0}/solana_agent/interfaces/services/agent.py +3 -7
  10. {solana_agent-19.0.2 → solana_agent-19.1.0}/solana_agent/interfaces/services/query.py +1 -0
  11. {solana_agent-19.0.2 → solana_agent-19.1.0}/solana_agent/repositories/memory.py +42 -31
  12. {solana_agent-19.0.2 → solana_agent-19.1.0}/solana_agent/services/agent.py +5 -15
  13. {solana_agent-19.0.2 → solana_agent-19.1.0}/solana_agent/services/query.py +11 -4
  14. {solana_agent-19.0.2 → solana_agent-19.1.0}/LICENSE +0 -0
  15. {solana_agent-19.0.2 → solana_agent-19.1.0}/solana_agent/__init__.py +0 -0
  16. {solana_agent-19.0.2 → solana_agent-19.1.0}/solana_agent/adapters/__init__.py +0 -0
  17. {solana_agent-19.0.2 → solana_agent-19.1.0}/solana_agent/adapters/mongodb_adapter.py +0 -0
  18. {solana_agent-19.0.2 → solana_agent-19.1.0}/solana_agent/client/__init__.py +0 -0
  19. {solana_agent-19.0.2 → solana_agent-19.1.0}/solana_agent/domains/__init__.py +0 -0
  20. {solana_agent-19.0.2 → solana_agent-19.1.0}/solana_agent/domains/agent.py +0 -0
  21. {solana_agent-19.0.2 → solana_agent-19.1.0}/solana_agent/domains/routing.py +0 -0
  22. {solana_agent-19.0.2 → solana_agent-19.1.0}/solana_agent/factories/__init__.py +0 -0
  23. {solana_agent-19.0.2 → solana_agent-19.1.0}/solana_agent/interfaces/__init__.py +0 -0
  24. {solana_agent-19.0.2 → solana_agent-19.1.0}/solana_agent/interfaces/plugins/plugins.py +0 -0
  25. {solana_agent-19.0.2 → solana_agent-19.1.0}/solana_agent/interfaces/providers/data_storage.py +0 -0
  26. {solana_agent-19.0.2 → solana_agent-19.1.0}/solana_agent/interfaces/providers/memory.py +0 -0
  27. {solana_agent-19.0.2 → solana_agent-19.1.0}/solana_agent/interfaces/services/routing.py +0 -0
  28. {solana_agent-19.0.2 → solana_agent-19.1.0}/solana_agent/plugins/__init__.py +0 -0
  29. {solana_agent-19.0.2 → solana_agent-19.1.0}/solana_agent/plugins/manager.py +0 -0
  30. {solana_agent-19.0.2 → solana_agent-19.1.0}/solana_agent/plugins/registry.py +0 -0
  31. {solana_agent-19.0.2 → solana_agent-19.1.0}/solana_agent/plugins/tools/__init__.py +0 -0
  32. {solana_agent-19.0.2 → solana_agent-19.1.0}/solana_agent/plugins/tools/auto_tool.py +0 -0
  33. {solana_agent-19.0.2 → solana_agent-19.1.0}/solana_agent/repositories/__init__.py +0 -0
  34. {solana_agent-19.0.2 → solana_agent-19.1.0}/solana_agent/services/__init__.py +0 -0
  35. {solana_agent-19.0.2 → solana_agent-19.1.0}/solana_agent/services/routing.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: solana-agent
3
- Version: 19.0.2
3
+ Version: 19.1.0
4
4
  Summary: Agentic IQ
5
5
  License: MIT
6
6
  Keywords: ai,openai,ai agents,agi
@@ -13,8 +13,8 @@ Classifier: Programming Language :: Python :: 3.12
13
13
  Classifier: Programming Language :: Python :: 3.13
14
14
  Classifier: Programming Language :: Python :: 3 :: Only
15
15
  Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
16
- Requires-Dist: openai (>=1.68.2,<2.0.0)
17
- Requires-Dist: pydantic (>=2.10.6,<3.0.0)
16
+ Requires-Dist: openai (>=1.69.0,<2.0.0)
17
+ Requires-Dist: pydantic (>=2.11.0,<3.0.0)
18
18
  Requires-Dist: pymongo (>=4.11.3,<5.0.0)
19
19
  Requires-Dist: zep-cloud (>=2.8.0,<3.0.0)
20
20
  Requires-Dist: zep-python (>=2.0.2,<3.0.0)
@@ -64,7 +64,7 @@ Build your AI business in three lines of code!
64
64
 
65
65
  * [Python](https://python.org) - Programming Language
66
66
  * [OpenAI](https://openai.com) - LLMs
67
- * [MongoDB](https://mongodb.com) - Conversational History
67
+ * [MongoDB](https://mongodb.com) - Conversational History (optional)
68
68
  * [Zep](https://getzep.com) - Conversational Memory (optional)
69
69
 
70
70
  ## Installation
@@ -90,17 +90,17 @@ config = {
90
90
  ],
91
91
  "voice": "The voice of the brand is that of a research business."
92
92
  },
93
- "mongo": {
93
+ "mongo": { # optional
94
94
  "connection_string": "mongodb://localhost:27017",
95
95
  "database": "solana_agent"
96
96
  },
97
- "openai": {
98
- "api_key": "your-openai-api-key",
99
- },
100
97
  "zep": { # optional
101
98
  "api_key": "your-zep-api-key",
102
99
  "base_url": "your-zep-base-url", # not applicable if using Zep Cloud
103
100
  },
101
+ "openai": {
102
+ "api_key": "your-openai-api-key",
103
+ },
104
104
  "agents": [
105
105
  {
106
106
  "name": "research_specialist",
@@ -142,23 +142,26 @@ config = {
142
142
  ],
143
143
  "voice": "The voice of the brand is that of a research business."
144
144
  },
145
- "mongo": {
145
+ "openai": { # optional
146
+ "api_key": "your-openai-api-key",
147
+ },
148
+ "ollama": { # optional
149
+ "url": "your-ollama-url",
150
+ },
151
+ "mongo": { # optional
146
152
  "connection_string": "mongodb://localhost:27017",
147
153
  "database": "solana_agent"
148
154
  },
149
- "openai": {
150
- "api_key": "your-openai-api-key",
151
- },
152
155
  "zep": { # optional
153
156
  "api_key": "your-zep-api-key",
154
157
  "base_url": "your-zep-base-url", # not applicable if using Zep Cloud
155
158
  },
156
159
  "tools": {
157
- "search_internet": {
158
- "api_key": "your-perplexity-key", # Required
159
- "citations": True, # Optional, defaults to True
160
- "model": "sonar" # Optional, defaults to "sonar"
161
- },
160
+ "search_internet": {
161
+ "api_key": "your-perplexity-key", # Required
162
+ "citations": True, # Optional, defaults to True
163
+ "model": "sonar" # Optional, defaults to "sonar"
164
+ },
162
165
  },
163
166
  "agents": [
164
167
  {
@@ -247,13 +250,16 @@ config = {
247
250
  ],
248
251
  "voice": "The voice of the brand is that of a research business."
249
252
  },
250
- "mongo": {
253
+ "openai": { # optional
254
+ "api_key": "your-openai-api-key",
255
+ },
256
+ "ollama": { # optional
257
+ "url": "your-ollama-url",
258
+ },
259
+ "mongo": { # optional
251
260
  "connection_string": "mongodb://localhost:27017",
252
261
  "database": "solana_agent"
253
262
  },
254
- "openai": {
255
- "api_key": "your-openai-api-key",
256
- },
257
263
  "zep": { # optional
258
264
  "api_key": "your-zep-api-key",
259
265
  "base_url": "your-zep-base-url", # not applicable if using Zep Cloud
@@ -282,24 +288,32 @@ async for response in solana_agent.process("user123", "What are the latest AI de
282
288
  print(response, end="")
283
289
  ```
284
290
 
285
- ## Notes on Tools
291
+ ## Notes
286
292
  * Solana Agent agents can only call one tool per response.
287
293
  * Solana Agent agents choose the best tool for the job.
288
294
  * Solana Agent tools do not use OpenAI function calling.
289
295
  * Solana Agent tools are async functions.
296
+ * Solana Agent will use OpenAI for audio and Ollama and for text if both config vars are set
297
+
298
+ ## Local Setup
299
+
300
+ A Docker Compose and Zep Config file is available at the root of this project
290
301
 
291
302
  ## API Documentation
292
- * Available at [Solana Agent Documentation Site](https://docs.solana-agent.com)
293
303
 
294
- ## Solana Agent Kit
304
+ The official up-to-date documentation site
305
+
306
+ [Solana Agent Documentation Site](https://docs.solana-agent.com)
307
+
308
+ ## Official Tools
295
309
 
296
- A collection of Solana Agent tools
310
+ The official collection of tools in one plugin
297
311
 
298
312
  [Solana Agent Kit](https://github.com/truemagic-coder/solana-agent-kit)
299
313
 
300
314
  ## Example App
301
315
 
302
- A Solana Agent example app written in FastAPI and Next.js
316
+ The official example app written in FastAPI and Next.js
303
317
 
304
318
  [Solana Agent Example App](https://github.com/truemagic-coder/solana-agent-app)
305
319
 
@@ -41,7 +41,7 @@ Build your AI business in three lines of code!
41
41
 
42
42
  * [Python](https://python.org) - Programming Language
43
43
  * [OpenAI](https://openai.com) - LLMs
44
- * [MongoDB](https://mongodb.com) - Conversational History
44
+ * [MongoDB](https://mongodb.com) - Conversational History (optional)
45
45
  * [Zep](https://getzep.com) - Conversational Memory (optional)
46
46
 
47
47
  ## Installation
@@ -67,17 +67,17 @@ config = {
67
67
  ],
68
68
  "voice": "The voice of the brand is that of a research business."
69
69
  },
70
- "mongo": {
70
+ "mongo": { # optional
71
71
  "connection_string": "mongodb://localhost:27017",
72
72
  "database": "solana_agent"
73
73
  },
74
- "openai": {
75
- "api_key": "your-openai-api-key",
76
- },
77
74
  "zep": { # optional
78
75
  "api_key": "your-zep-api-key",
79
76
  "base_url": "your-zep-base-url", # not applicable if using Zep Cloud
80
77
  },
78
+ "openai": {
79
+ "api_key": "your-openai-api-key",
80
+ },
81
81
  "agents": [
82
82
  {
83
83
  "name": "research_specialist",
@@ -119,23 +119,26 @@ config = {
119
119
  ],
120
120
  "voice": "The voice of the brand is that of a research business."
121
121
  },
122
- "mongo": {
122
+ "openai": { # optional
123
+ "api_key": "your-openai-api-key",
124
+ },
125
+ "ollama": { # optional
126
+ "url": "your-ollama-url",
127
+ },
128
+ "mongo": { # optional
123
129
  "connection_string": "mongodb://localhost:27017",
124
130
  "database": "solana_agent"
125
131
  },
126
- "openai": {
127
- "api_key": "your-openai-api-key",
128
- },
129
132
  "zep": { # optional
130
133
  "api_key": "your-zep-api-key",
131
134
  "base_url": "your-zep-base-url", # not applicable if using Zep Cloud
132
135
  },
133
136
  "tools": {
134
- "search_internet": {
135
- "api_key": "your-perplexity-key", # Required
136
- "citations": True, # Optional, defaults to True
137
- "model": "sonar" # Optional, defaults to "sonar"
138
- },
137
+ "search_internet": {
138
+ "api_key": "your-perplexity-key", # Required
139
+ "citations": True, # Optional, defaults to True
140
+ "model": "sonar" # Optional, defaults to "sonar"
141
+ },
139
142
  },
140
143
  "agents": [
141
144
  {
@@ -224,13 +227,16 @@ config = {
224
227
  ],
225
228
  "voice": "The voice of the brand is that of a research business."
226
229
  },
227
- "mongo": {
230
+ "openai": { # optional
231
+ "api_key": "your-openai-api-key",
232
+ },
233
+ "ollama": { # optional
234
+ "url": "your-ollama-url",
235
+ },
236
+ "mongo": { # optional
228
237
  "connection_string": "mongodb://localhost:27017",
229
238
  "database": "solana_agent"
230
239
  },
231
- "openai": {
232
- "api_key": "your-openai-api-key",
233
- },
234
240
  "zep": { # optional
235
241
  "api_key": "your-zep-api-key",
236
242
  "base_url": "your-zep-base-url", # not applicable if using Zep Cloud
@@ -259,24 +265,32 @@ async for response in solana_agent.process("user123", "What are the latest AI de
259
265
  print(response, end="")
260
266
  ```
261
267
 
262
- ## Notes on Tools
268
+ ## Notes
263
269
  * Solana Agent agents can only call one tool per response.
264
270
  * Solana Agent agents choose the best tool for the job.
265
271
  * Solana Agent tools do not use OpenAI function calling.
266
272
  * Solana Agent tools are async functions.
273
+ * Solana Agent will use OpenAI for audio and Ollama and for text if both config vars are set
274
+
275
+ ## Local Setup
276
+
277
+ A Docker Compose and Zep Config file is available at the root of this project
267
278
 
268
279
  ## API Documentation
269
- * Available at [Solana Agent Documentation Site](https://docs.solana-agent.com)
270
280
 
271
- ## Solana Agent Kit
281
+ The official up-to-date documentation site
282
+
283
+ [Solana Agent Documentation Site](https://docs.solana-agent.com)
284
+
285
+ ## Official Tools
272
286
 
273
- A collection of Solana Agent tools
287
+ The official collection of tools in one plugin
274
288
 
275
289
  [Solana Agent Kit](https://github.com/truemagic-coder/solana-agent-kit)
276
290
 
277
291
  ## Example App
278
292
 
279
- A Solana Agent example app written in FastAPI and Next.js
293
+ The official example app written in FastAPI and Next.js
280
294
 
281
295
  [Solana Agent Example App](https://github.com/truemagic-coder/solana-agent-app)
282
296
 
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "solana-agent"
3
- version = "19.0.2"
3
+ version = "19.1.0"
4
4
  description = "Agentic IQ"
5
5
  authors = ["Bevan Hunt <bevan@bevanhunt.com>"]
6
6
  license = "MIT"
@@ -18,8 +18,8 @@ python_paths = [".", "tests"]
18
18
 
19
19
  [tool.poetry.dependencies]
20
20
  python = ">=3.12,<4.0"
21
- openai = "^1.68.2"
22
- pydantic = "^2.10.6"
21
+ openai = "^1.69.0"
22
+ pydantic = "^2.11.0"
23
23
  pymongo = "^4.11.3"
24
24
  zep-cloud = "^2.8.0"
25
25
  zep-python = "^2.0.2"
@@ -135,19 +135,6 @@ class OpenAIAdapter(LLMProvider):
135
135
  print(traceback.format_exc())
136
136
  yield f"I apologize, but I encountered an error: {str(e)}"
137
137
 
138
- def generate_embedding(self, text: str) -> List[float]: # pragma: no cover
139
- """Generate embeddings for a given text using OpenAI's embedding model."""
140
- try:
141
- response = self.client.embeddings.create(
142
- model="text-embedding-3-small",
143
- input=text
144
- )
145
- return response.data[0].embedding
146
- except Exception as e:
147
- print(f"Error generating embedding: {e}")
148
- # Return a zero vector as fallback (not ideal but prevents crashing)
149
- return [0.0] * 1536 # Standard size for text-embedding-3-small
150
-
151
138
  async def parse_structured_output(
152
139
  self,
153
140
  prompt: str,
@@ -44,6 +44,7 @@ class SolanaAgent(SolanaAgentInterface):
44
44
  self,
45
45
  user_id: str,
46
46
  message: Union[str, bytes],
47
+ prompt: Optional[str] = None,
47
48
  output_format: Literal["text", "audio"] = "text",
48
49
  audio_voice: Literal["alloy", "ash", "ballad", "coral", "echo",
49
50
  "fable", "onyx", "nova", "sage", "shimmer"] = "nova",
@@ -59,6 +60,7 @@ class SolanaAgent(SolanaAgentInterface):
59
60
  Args:
60
61
  user_id: User ID
61
62
  message: Text message or audio bytes
63
+ prompt: Optional prompt for the agent
62
64
  output_format: Response format ("text" or "audio")
63
65
  audio_voice: Voice to use for audio output
64
66
  audio_instructions: Optional instructions for audio synthesis
@@ -76,6 +78,7 @@ class SolanaAgent(SolanaAgentInterface):
76
78
  audio_instructions=audio_instructions,
77
79
  audio_output_format=audio_output_format,
78
80
  audio_input_format=audio_input_format,
81
+ prompt=prompt,
79
82
  ):
80
83
  yield chunk
81
84
 
@@ -37,10 +37,19 @@ class SolanaAgentFactory:
37
37
  Configured QueryService instance
38
38
  """
39
39
  # Create adapters
40
- db_adapter = MongoDBAdapter(
41
- connection_string=config["mongo"]["connection_string"],
42
- database_name=config["mongo"]["database"],
43
- )
40
+
41
+ if "mongo" in config:
42
+ # MongoDB connection string and database name
43
+ if "connection_string" not in config["mongo"]:
44
+ raise ValueError("MongoDB connection string is required.")
45
+ if "database" not in config["mongo"]:
46
+ raise ValueError("MongoDB database name is required.")
47
+ db_adapter = MongoDBAdapter(
48
+ connection_string=config["mongo"]["connection_string"],
49
+ database_name=config["mongo"]["database"],
50
+ )
51
+ else:
52
+ db_adapter = None
44
53
 
45
54
  llm_adapter = OpenAIAdapter(
46
55
  api_key=config["openai"]["api_key"],
@@ -59,12 +68,25 @@ class SolanaAgentFactory:
59
68
  )
60
69
 
61
70
  # Create repositories
62
- if "zep" in config:
71
+ memory_provider = None
72
+
73
+ if "zep" in config and "mongo" in config:
74
+ if "api_key" not in config["zep"]:
75
+ raise ValueError("Zep API key is required.")
63
76
  memory_provider = MemoryRepository(
64
77
  db_adapter, config["zep"].get("api_key"), config["zep"].get("base_url"))
65
- else:
78
+
79
+ if "mongo" in config and not "zep" in config:
66
80
  memory_provider = MemoryRepository(db_adapter)
67
81
 
82
+ if "zep" in config and not "mongo" in config:
83
+ if "api_key" not in config["zep"]:
84
+ raise ValueError("Zep API key is required.")
85
+ memory_provider = MemoryRepository(
86
+ zep_api_key=config["zep"].get("api_key"),
87
+ zep_base_url=config["zep"].get("base_url")
88
+ )
89
+
68
90
  # Create primary services
69
91
  agent_service = AgentService(
70
92
  llm_provider=llm_adapter,
@@ -1,5 +1,5 @@
1
1
  from abc import ABC, abstractmethod
2
- from typing import Any, AsyncGenerator, Dict, Literal, Union
2
+ from typing import Any, AsyncGenerator, Dict, Literal, Optional, Union
3
3
 
4
4
  from solana_agent.interfaces.plugins.plugins import Tool
5
5
 
@@ -15,12 +15,13 @@ class SolanaAgent(ABC):
15
15
  output_format: Literal["text", "audio"] = "text",
16
16
  audio_voice: Literal["alloy", "ash", "ballad", "coral", "echo",
17
17
  "fable", "onyx", "nova", "sage", "shimmer"] = "nova",
18
- audio_instructions: str = None,
18
+ audio_instructions: Optional[str] = None,
19
19
  audio_output_format: Literal['mp3', 'opus',
20
20
  'aac', 'flac', 'wav', 'pcm'] = "aac",
21
21
  audio_input_format: Literal[
22
22
  "flac", "mp3", "mp4", "mpeg", "mpga", "m4a", "ogg", "wav", "webm"
23
23
  ] = "mp4",
24
+ prompt: Optional[str] = None,
24
25
  ) -> AsyncGenerator[Union[str, bytes], None]:
25
26
  """Process a user message and return the response stream."""
26
27
  pass
@@ -19,11 +19,6 @@ class LLMProvider(ABC):
19
19
  """Generate text from the language model."""
20
20
  pass
21
21
 
22
- @abstractmethod
23
- def generate_embedding(self, text: str) -> List[float]:
24
- """Generate embedding vector for text."""
25
- pass
26
-
27
22
  @abstractmethod
28
23
  async def parse_structured_output(
29
24
  self, prompt: str, system_prompt: str, model_class: Type[T],
@@ -1,5 +1,5 @@
1
1
  from abc import ABC, abstractmethod
2
- from typing import Any, AsyncGenerator, Dict, List, Literal, Union
2
+ from typing import Any, AsyncGenerator, Dict, List, Literal, Optional, Union
3
3
 
4
4
  from solana_agent.domains.agent import AIAgent
5
5
 
@@ -17,11 +17,6 @@ class AgentService(ABC):
17
17
  """Get the system prompt for an agent."""
18
18
  pass
19
19
 
20
- @abstractmethod
21
- def get_specializations(self) -> Dict[str, str]:
22
- """Get all registered specializations."""
23
- pass
24
-
25
20
  @abstractmethod
26
21
  async def generate_response(
27
22
  self,
@@ -32,12 +27,13 @@ class AgentService(ABC):
32
27
  output_format: Literal["text", "audio"] = "text",
33
28
  audio_voice: Literal["alloy", "ash", "ballad", "coral", "echo",
34
29
  "fable", "onyx", "nova", "sage", "shimmer"] = "nova",
35
- audio_instructions: str = None,
30
+ audio_instructions: Optional[str] = None,
36
31
  audio_output_format: Literal['mp3', 'opus',
37
32
  'aac', 'flac', 'wav', 'pcm'] = "aac",
38
33
  audio_input_format: Literal[
39
34
  "flac", "mp3", "mp4", "mpeg", "mpga", "m4a", "ogg", "wav", "webm"
40
35
  ] = "mp4",
36
+ prompt: Optional[str] = None,
41
37
  ) -> AsyncGenerator[Union[str, bytes], None]:
42
38
  """Generate a response from an agent."""
43
39
  pass
@@ -19,6 +19,7 @@ class QueryService(ABC):
19
19
  audio_input_format: Literal[
20
20
  "flac", "mp3", "mp4", "mpeg", "mpga", "m4a", "ogg", "wav", "webm"
21
21
  ] = "mp4",
22
+ prompt: Optional[str] = None,
22
23
  ) -> AsyncGenerator[Union[str, bytes], None]:
23
24
  """Process the user request and generate a response."""
24
25
  pass
@@ -12,19 +12,23 @@ class MemoryRepository(MemoryProvider):
12
12
 
13
13
  def __init__(
14
14
  self,
15
- mongo_adapter: MongoDBAdapter,
15
+ mongo_adapter: Optional[MongoDBAdapter] = None,
16
16
  zep_api_key: Optional[str] = None,
17
17
  zep_base_url: Optional[str] = None
18
18
  ):
19
19
  """Initialize the combined memory provider."""
20
- # Initialize MongoDB
21
- self.mongo = mongo_adapter
22
- self.collection = "conversations"
20
+ if not mongo_adapter:
21
+ self.mongo = None
22
+ self.collection = None
23
+ else:
24
+ # Initialize MongoDB
25
+ self.mongo = mongo_adapter
26
+ self.collection = "conversations"
23
27
 
24
- # Ensure MongoDB collection and indexes
25
- self.mongo.create_collection(self.collection)
26
- self.mongo.create_index(self.collection, [("user_id", 1)])
27
- self.mongo.create_index(self.collection, [("timestamp", 1)])
28
+ # Ensure MongoDB collection and indexes
29
+ self.mongo.create_collection(self.collection)
30
+ self.mongo.create_index(self.collection, [("user_id", 1)])
31
+ self.mongo.create_index(self.collection, [("timestamp", 1)])
28
32
 
29
33
  # Initialize Zep
30
34
  if zep_api_key and not zep_base_url:
@@ -37,22 +41,23 @@ class MemoryRepository(MemoryProvider):
37
41
  async def store(self, user_id: str, messages: List[Dict[str, Any]]) -> None:
38
42
  """Store messages in both Zep and MongoDB."""
39
43
  # Store in MongoDB as single document
40
- try:
41
- # Extract user and assistant messages
42
- user_message = next(msg["content"]
43
- for msg in messages if msg["role"] == "user")
44
- assistant_message = next(
45
- msg["content"] for msg in messages if msg["role"] == "assistant")
46
-
47
- doc = {
48
- "user_id": user_id,
49
- "user_message": user_message,
50
- "assistant_message": assistant_message,
51
- "timestamp": datetime.now(timezone.utc)
52
- }
53
- self.mongo.insert_one(self.collection, doc)
54
- except Exception as e:
55
- print(f"MongoDB storage error: {e}")
44
+ if self.mongo:
45
+ try:
46
+ # Extract user and assistant messages
47
+ user_message = next(msg["content"]
48
+ for msg in messages if msg["role"] == "user")
49
+ assistant_message = next(
50
+ msg["content"] for msg in messages if msg["role"] == "assistant")
51
+
52
+ doc = {
53
+ "user_id": user_id,
54
+ "user_message": user_message,
55
+ "assistant_message": assistant_message,
56
+ "timestamp": datetime.now(timezone.utc)
57
+ }
58
+ self.mongo.insert_one(self.collection, doc)
59
+ except Exception as e:
60
+ print(f"MongoDB storage error: {e}")
56
61
 
57
62
  # Store in Zep with role-based format
58
63
  if not self.zep:
@@ -99,13 +104,14 @@ class MemoryRepository(MemoryProvider):
99
104
 
100
105
  async def delete(self, user_id: str) -> None:
101
106
  """Delete memory from both systems."""
102
- try:
103
- self.mongo.delete_all(
104
- self.collection,
105
- {"user_id": user_id}
106
- )
107
- except Exception as e:
108
- print(f"MongoDB deletion error: {e}")
107
+ if self.mongo:
108
+ try:
109
+ self.mongo.delete_all(
110
+ self.collection,
111
+ {"user_id": user_id}
112
+ )
113
+ except Exception as e:
114
+ print(f"MongoDB deletion error: {e}")
109
115
 
110
116
  if not self.zep:
111
117
  return
@@ -125,9 +131,14 @@ class MemoryRepository(MemoryProvider):
125
131
  skip: int = 0
126
132
  ) -> List[Dict]:
127
133
  """Find documents matching query."""
134
+ if not self.mongo:
135
+ return []
128
136
  return self.mongo.find(collection, query, sort=sort, limit=limit, skip=skip)
129
137
 
130
138
  def count_documents(self, collection: str, query: Dict) -> int:
139
+ """Count documents matching query."""
140
+ if not self.mongo:
141
+ return 0
131
142
  return self.mongo.count_documents(collection, query)
132
143
 
133
144
  def _truncate(self, text: str, limit: int = 2500) -> str:
@@ -108,20 +108,6 @@ class AgentService(AgentServiceInterface):
108
108
  """
109
109
  return {agent.name: agent for agent in self.agents}
110
110
 
111
- def get_specializations(self) -> Dict[str, str]:
112
- """Get all registered specializations.
113
-
114
- Returns:
115
- Dictionary mapping specialization names to descriptions
116
- """
117
- specializations = {}
118
-
119
- for agent in self.agents:
120
- if agent.specialization:
121
- specializations[agent.specialization] = f"AI expertise in {agent.specialization}"
122
-
123
- return specializations
124
-
125
111
  def assign_tool_for_agent(self, agent_name: str, tool_name: str) -> bool:
126
112
  """Assign a tool to an agent.
127
113
 
@@ -187,6 +173,7 @@ class AgentService(AgentServiceInterface):
187
173
  audio_input_format: Literal[
188
174
  "flac", "mp3", "mp4", "mpeg", "mpga", "m4a", "ogg", "wav", "webm"
189
175
  ] = "mp4",
176
+ prompt: Optional[str] = None,
190
177
  ) -> AsyncGenerator[Union[str, bytes], None]: # pragma: no cover
191
178
  """Generate a response with support for text/audio input/output.
192
179
 
@@ -200,6 +187,7 @@ class AgentService(AgentServiceInterface):
200
187
  audio_instructions: Optional instructions for audio synthesis
201
188
  audio_output_format: Audio output format
202
189
  audio_input_format: Audio input format
190
+ prompt: Optional prompt for the agent
203
191
 
204
192
  Yields:
205
193
  Text chunks or audio bytes depending on output_format
@@ -233,7 +221,9 @@ class AgentService(AgentServiceInterface):
233
221
  # Add User ID and memory context
234
222
  system_prompt += f"\n\nUser ID: {user_id}"
235
223
  if memory_context:
236
- system_prompt += f"\n\nMemory Context: {memory_context}"
224
+ system_prompt += f"\n\nMEMORY CONTEXT: {memory_context}"
225
+ if prompt:
226
+ system_prompt += f"\n\nADDITIONAL PROMPT: {prompt}"
237
227
 
238
228
  # Keep track of the complete text response
239
229
  complete_text_response = ""
@@ -46,14 +46,19 @@ class QueryService(QueryServiceInterface):
46
46
  audio_input_format: Literal[
47
47
  "flac", "mp3", "mp4", "mpeg", "mpga", "m4a", "ogg", "wav", "webm"
48
48
  ] = "mp4",
49
+ prompt: Optional[str] = None,
49
50
  ) -> AsyncGenerator[Union[str, bytes], None]: # pragma: no cover
50
51
  """Process the user request with appropriate agent.
51
52
 
52
53
  Args:
53
54
  user_id: User ID
54
55
  query: Text query or audio bytes
55
- output_format: Response format ("text" or "audio")
56
- voice: Voice to use for audio output
56
+ output_format: Response format ("text" or "audio")
57
+ audio_voice: Voice for TTS (text-to-speech)
58
+ audio_instructions: Optional instructions for TTS
59
+ audio_output_format: Audio output format
60
+ audio_input_format: Audio input format
61
+ prompt: Optional prompt for the agent
57
62
 
58
63
  Yields:
59
64
  Response chunks (text strings or audio bytes)
@@ -105,7 +110,8 @@ class QueryService(QueryServiceInterface):
105
110
  audio_voice=audio_voice,
106
111
  audio_input_format=audio_input_format,
107
112
  audio_output_format=audio_output_format,
108
- audio_instructions=audio_instructions
113
+ audio_instructions=audio_instructions,
114
+ prompt=prompt,
109
115
  ):
110
116
  yield audio_chunk
111
117
 
@@ -122,7 +128,8 @@ class QueryService(QueryServiceInterface):
122
128
  user_id=user_id,
123
129
  query=user_text,
124
130
  memory_context=memory_context,
125
- output_format="text"
131
+ output_format="text",
132
+ prompt=prompt,
126
133
  ):
127
134
  yield chunk
128
135
  full_text_response += chunk
File without changes