solana-agent 17.0.2__py3-none-any.whl → 17.0.4__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/services/agent.py +30 -13
- solana_agent/services/query.py +73 -34
- {solana_agent-17.0.2.dist-info → solana_agent-17.0.4.dist-info}/METADATA +2 -2
- {solana_agent-17.0.2.dist-info → solana_agent-17.0.4.dist-info}/RECORD +6 -6
- {solana_agent-17.0.2.dist-info → solana_agent-17.0.4.dist-info}/LICENSE +0 -0
- {solana_agent-17.0.2.dist-info → solana_agent-17.0.4.dist-info}/WHEEL +0 -0
solana_agent/services/agent.py
CHANGED
@@ -39,6 +39,7 @@ class AgentService(AgentServiceInterface):
|
|
39
39
|
self.agent_repository = agent_repository
|
40
40
|
self.organization_mission = organization_mission
|
41
41
|
self.config = config or {}
|
42
|
+
self.last_text_response = ""
|
42
43
|
|
43
44
|
# Initialize tool registry with concrete implementation
|
44
45
|
if tool_registry:
|
@@ -247,6 +248,8 @@ class AgentService(AgentServiceInterface):
|
|
247
248
|
if memory_context:
|
248
249
|
system_prompt += f"\n\nMemory Context: {memory_context}"
|
249
250
|
|
251
|
+
# Keep track of the complete text response
|
252
|
+
complete_text_response = ""
|
250
253
|
json_buffer = ""
|
251
254
|
is_json = False
|
252
255
|
text_buffer = ""
|
@@ -277,6 +280,9 @@ class AgentService(AgentServiceInterface):
|
|
277
280
|
json_chunk=json_buffer
|
278
281
|
)
|
279
282
|
|
283
|
+
# Add to complete text response
|
284
|
+
complete_text_response += response_text
|
285
|
+
|
280
286
|
# Output response based on format
|
281
287
|
if output_format == "audio":
|
282
288
|
async for audio_chunk in self.llm_provider.tts(
|
@@ -288,7 +294,9 @@ class AgentService(AgentServiceInterface):
|
|
288
294
|
else:
|
289
295
|
yield response_text
|
290
296
|
else:
|
291
|
-
#
|
297
|
+
# For non-tool JSON, still capture the text
|
298
|
+
complete_text_response += json_buffer
|
299
|
+
|
292
300
|
if output_format == "audio":
|
293
301
|
async for audio_chunk in self.llm_provider.tts(
|
294
302
|
text=json_buffer,
|
@@ -304,10 +312,12 @@ class AgentService(AgentServiceInterface):
|
|
304
312
|
json_buffer = ""
|
305
313
|
|
306
314
|
except json.JSONDecodeError:
|
307
|
-
# Incomplete JSON, continue collecting
|
308
315
|
pass
|
309
316
|
else:
|
310
|
-
#
|
317
|
+
# For regular text, always add to the complete response
|
318
|
+
complete_text_response += chunk
|
319
|
+
|
320
|
+
# Handle audio buffering or direct text output
|
311
321
|
if output_format == "audio":
|
312
322
|
text_buffer += chunk
|
313
323
|
if any(punct in chunk for punct in ".!?"):
|
@@ -326,18 +336,25 @@ class AgentService(AgentServiceInterface):
|
|
326
336
|
if text_buffer:
|
327
337
|
remaining_text += text_buffer
|
328
338
|
if is_json and json_buffer:
|
329
|
-
# If we have incomplete JSON at the end, yield it as text
|
330
339
|
remaining_text += json_buffer
|
331
340
|
|
332
|
-
if remaining_text
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
+
if remaining_text:
|
342
|
+
# Add remaining text to complete response
|
343
|
+
complete_text_response += remaining_text
|
344
|
+
|
345
|
+
if output_format == "audio":
|
346
|
+
async for audio_chunk in self.llm_provider.tts(
|
347
|
+
text=remaining_text,
|
348
|
+
voice=audio_voice,
|
349
|
+
response_format=audio_output_format
|
350
|
+
):
|
351
|
+
yield audio_chunk
|
352
|
+
else:
|
353
|
+
yield remaining_text
|
354
|
+
|
355
|
+
# Store the complete text response for the caller to access
|
356
|
+
# This needs to be done in the query service using the self.last_text_response
|
357
|
+
self.last_text_response = complete_text_response
|
341
358
|
|
342
359
|
except Exception as e:
|
343
360
|
error_msg = f"I apologize, but I encountered an error: {str(e)}"
|
solana_agent/services/query.py
CHANGED
@@ -52,11 +52,8 @@ class QueryService(QueryServiceInterface):
|
|
52
52
|
Args:
|
53
53
|
user_id: User ID
|
54
54
|
query: Text query or audio bytes
|
55
|
-
output_format: Response format ("text" or "audio")
|
56
|
-
|
57
|
-
audio_instructions: Optional instructions for audio synthesis
|
58
|
-
audio_output_format: Audio output format
|
59
|
-
audio_input_format: Audio input format
|
55
|
+
output_format: Response format ("text" or "audio")
|
56
|
+
voice: Voice to use for audio output
|
60
57
|
|
61
58
|
Yields:
|
62
59
|
Response chunks (text strings or audio bytes)
|
@@ -74,7 +71,11 @@ class QueryService(QueryServiceInterface):
|
|
74
71
|
if user_text.strip().lower() in ["test", "hello", "hi", "hey", "ping"]:
|
75
72
|
response = "Hello! How can I help you today?"
|
76
73
|
if output_format == "audio":
|
77
|
-
async for chunk in self.agent_service.llm_provider.tts(
|
74
|
+
async for chunk in self.agent_service.llm_provider.tts(
|
75
|
+
text=response,
|
76
|
+
voice=audio_voice,
|
77
|
+
response_format=audio_output_format
|
78
|
+
):
|
78
79
|
yield chunk
|
79
80
|
else:
|
80
81
|
yield response
|
@@ -91,25 +92,17 @@ class QueryService(QueryServiceInterface):
|
|
91
92
|
|
92
93
|
# Route query to appropriate agent
|
93
94
|
agent_name = await self.routing_service.route_query(user_text)
|
95
|
+
print(f"Routed to agent: {agent_name}")
|
94
96
|
|
95
|
-
#
|
96
|
-
|
97
|
-
async for chunk in self.agent_service.generate_response(
|
98
|
-
agent_name=agent_name,
|
99
|
-
user_id=user_id,
|
100
|
-
query=user_text,
|
101
|
-
memory_context=memory_context,
|
102
|
-
output_format=output_format,
|
103
|
-
audio_voice=audio_voice,
|
104
|
-
audio_output_format=audio_output_format,
|
105
|
-
):
|
106
|
-
yield chunk
|
107
|
-
if output_format == "text":
|
108
|
-
full_response += chunk
|
109
|
-
|
110
|
-
# For audio responses, get transcription for storage
|
97
|
+
# For audio mode, we need to carefully handle the response to make sure
|
98
|
+
# tool calls are properly executed and formatted for audio
|
111
99
|
if output_format == "audio":
|
112
|
-
#
|
100
|
+
# Use the agent service to generate the response
|
101
|
+
text_response = ""
|
102
|
+
|
103
|
+
# First, get complete text response
|
104
|
+
# Note: This is a separate call from the audio generation
|
105
|
+
temp_response = ""
|
113
106
|
async for chunk in self.agent_service.generate_response(
|
114
107
|
agent_name=agent_name,
|
115
108
|
user_id=user_id,
|
@@ -117,16 +110,61 @@ class QueryService(QueryServiceInterface):
|
|
117
110
|
memory_context=memory_context,
|
118
111
|
output_format="text"
|
119
112
|
):
|
120
|
-
|
113
|
+
temp_response += chunk
|
121
114
|
|
122
|
-
|
123
|
-
|
124
|
-
|
115
|
+
# Store the complete text for memory
|
116
|
+
text_response = temp_response
|
117
|
+
|
118
|
+
# Now generate audio from same request
|
119
|
+
async for audio_chunk in self.agent_service.generate_response(
|
120
|
+
agent_name=agent_name,
|
121
|
+
user_id=user_id,
|
122
|
+
query=user_text,
|
123
|
+
memory_context=memory_context,
|
124
|
+
output_format="audio",
|
125
|
+
audio_voice=audio_voice,
|
126
|
+
audio_input_format=audio_input_format,
|
127
|
+
audio_output_format=audio_output_format,
|
128
|
+
audio_instructions=audio_instructions
|
129
|
+
):
|
130
|
+
yield audio_chunk
|
131
|
+
|
132
|
+
# Store conversation in memory
|
133
|
+
if self.memory_provider and text_response:
|
134
|
+
await self._store_conversation(
|
135
|
+
user_id=user_id,
|
136
|
+
user_message=user_text,
|
137
|
+
assistant_message=text_response
|
138
|
+
)
|
139
|
+
else:
|
140
|
+
# For text mode, we can collect the response and store it directly
|
141
|
+
full_text_response = ""
|
142
|
+
async for chunk in self.agent_service.generate_response(
|
143
|
+
agent_name=agent_name,
|
144
|
+
user_id=user_id,
|
145
|
+
query=user_text,
|
146
|
+
memory_context=memory_context,
|
147
|
+
output_format="text"
|
148
|
+
):
|
149
|
+
yield chunk
|
150
|
+
full_text_response += chunk
|
151
|
+
|
152
|
+
# Store conversation in memory
|
153
|
+
if self.memory_provider and full_text_response:
|
154
|
+
await self._store_conversation(
|
155
|
+
user_id=user_id,
|
156
|
+
user_message=user_text,
|
157
|
+
assistant_message=full_text_response
|
158
|
+
)
|
125
159
|
|
126
160
|
except Exception as e:
|
127
161
|
error_msg = f"I apologize for the technical difficulty. {str(e)}"
|
128
162
|
if output_format == "audio":
|
129
|
-
async for chunk in self.agent_service.llm_provider.tts(
|
163
|
+
async for chunk in self.agent_service.llm_provider.tts(
|
164
|
+
text=error_msg,
|
165
|
+
voice=audio_voice,
|
166
|
+
response_format=audio_output_format
|
167
|
+
):
|
130
168
|
yield chunk
|
131
169
|
else:
|
132
170
|
yield error_msg
|
@@ -242,25 +280,26 @@ class QueryService(QueryServiceInterface):
|
|
242
280
|
}
|
243
281
|
|
244
282
|
async def _store_conversation(
|
245
|
-
self, user_id: str,
|
283
|
+
self, user_id: str, user_message: str, assistant_message: str
|
246
284
|
) -> None:
|
247
285
|
"""Store conversation history in memory provider.
|
248
286
|
|
249
287
|
Args:
|
250
288
|
user_id: User ID
|
251
|
-
|
252
|
-
|
289
|
+
user_message: User message
|
290
|
+
assistant_message: Assistant message
|
253
291
|
"""
|
254
292
|
if self.memory_provider:
|
255
293
|
try:
|
256
294
|
# Truncate excessively long responses
|
257
|
-
|
295
|
+
truncated_assistant_message = self._truncate(assistant_message)
|
296
|
+
truncated_user_message = self._truncate(user_message)
|
258
297
|
|
259
298
|
await self.memory_provider.store(
|
260
299
|
user_id,
|
261
300
|
[
|
262
|
-
{"role": "user", "content":
|
263
|
-
{"role": "assistant", "content":
|
301
|
+
{"role": "user", "content": truncated_user_message},
|
302
|
+
{"role": "assistant", "content": truncated_assistant_message},
|
264
303
|
],
|
265
304
|
)
|
266
305
|
except Exception as e:
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: solana-agent
|
3
|
-
Version: 17.0.
|
3
|
+
Version: 17.0.4
|
4
4
|
Summary: The Future of Work
|
5
5
|
License: MIT
|
6
6
|
Keywords: ai,openai,ai agents,agi
|
@@ -13,7 +13,7 @@ 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.
|
16
|
+
Requires-Dist: openai (>=1.68.1,<2.0.0)
|
17
17
|
Requires-Dist: pydantic (>=2.10.6,<3.0.0)
|
18
18
|
Requires-Dist: pymongo (>=4.11.3,<5.0.0)
|
19
19
|
Requires-Dist: zep-cloud (>=2.7.0,<3.0.0)
|
@@ -28,10 +28,10 @@ solana_agent/repositories/__init__.py,sha256=fP83w83CGzXLnSdq-C5wbw9EhWTYtqE2lQT
|
|
28
28
|
solana_agent/repositories/agent.py,sha256=e1rnsQiigkKwJNLKro86a3b6TBiky3GMfmCRc5b_jPw,3187
|
29
29
|
solana_agent/repositories/memory.py,sha256=GABGwaz00thjviHewLvb18NeKE8dkBROxy_stsiiWrE,4722
|
30
30
|
solana_agent/services/__init__.py,sha256=ab_NXJmwYUCmCrCzuTlZ47bJZINW0Y0F5jfQ9OovidU,163
|
31
|
-
solana_agent/services/agent.py,sha256=
|
32
|
-
solana_agent/services/query.py,sha256=
|
31
|
+
solana_agent/services/agent.py,sha256=j0aI_BGaY5Nhkb9ga0r4BqI3qMKu5TOc4QPQsU3NHyQ,17000
|
32
|
+
solana_agent/services/query.py,sha256=_RHcT7LDvaVhgie96--l7N4ktEtL6UDtgk1_2t25PtQ,12305
|
33
33
|
solana_agent/services/routing.py,sha256=TPJ2Pas4acE93QzMEV6ZP670OtTNrVEPa76fz6urEV4,4996
|
34
|
-
solana_agent-17.0.
|
35
|
-
solana_agent-17.0.
|
36
|
-
solana_agent-17.0.
|
37
|
-
solana_agent-17.0.
|
34
|
+
solana_agent-17.0.4.dist-info/LICENSE,sha256=BnSRc-NSFuyF2s496l_4EyrwAP6YimvxWcjPiJ0J7g4,1057
|
35
|
+
solana_agent-17.0.4.dist-info/METADATA,sha256=_QLt1zJUJQ-wBy6qYBycjZ6w8bxvcpdwYrxbr2vZWZk,4888
|
36
|
+
solana_agent-17.0.4.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88
|
37
|
+
solana_agent-17.0.4.dist-info/RECORD,,
|
File without changes
|
File without changes
|