solana-agent 31.1.2__tar.gz → 31.1.3__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.
- {solana_agent-31.1.2 → solana_agent-31.1.3}/PKG-INFO +1 -1
- {solana_agent-31.1.2 → solana_agent-31.1.3}/pyproject.toml +1 -1
- {solana_agent-31.1.2 → solana_agent-31.1.3}/solana_agent/services/query.py +97 -24
- {solana_agent-31.1.2 → solana_agent-31.1.3}/LICENSE +0 -0
- {solana_agent-31.1.2 → solana_agent-31.1.3}/README.md +0 -0
- {solana_agent-31.1.2 → solana_agent-31.1.3}/solana_agent/__init__.py +0 -0
- {solana_agent-31.1.2 → solana_agent-31.1.3}/solana_agent/adapters/__init__.py +0 -0
- {solana_agent-31.1.2 → solana_agent-31.1.3}/solana_agent/adapters/mongodb_adapter.py +0 -0
- {solana_agent-31.1.2 → solana_agent-31.1.3}/solana_agent/adapters/openai_adapter.py +0 -0
- {solana_agent-31.1.2 → solana_agent-31.1.3}/solana_agent/adapters/pinecone_adapter.py +0 -0
- {solana_agent-31.1.2 → solana_agent-31.1.3}/solana_agent/cli.py +0 -0
- {solana_agent-31.1.2 → solana_agent-31.1.3}/solana_agent/client/__init__.py +0 -0
- {solana_agent-31.1.2 → solana_agent-31.1.3}/solana_agent/client/solana_agent.py +0 -0
- {solana_agent-31.1.2 → solana_agent-31.1.3}/solana_agent/domains/__init__.py +0 -0
- {solana_agent-31.1.2 → solana_agent-31.1.3}/solana_agent/domains/agent.py +0 -0
- {solana_agent-31.1.2 → solana_agent-31.1.3}/solana_agent/domains/routing.py +0 -0
- {solana_agent-31.1.2 → solana_agent-31.1.3}/solana_agent/factories/__init__.py +0 -0
- {solana_agent-31.1.2 → solana_agent-31.1.3}/solana_agent/factories/agent_factory.py +0 -0
- {solana_agent-31.1.2 → solana_agent-31.1.3}/solana_agent/guardrails/pii.py +0 -0
- {solana_agent-31.1.2 → solana_agent-31.1.3}/solana_agent/interfaces/__init__.py +0 -0
- {solana_agent-31.1.2 → solana_agent-31.1.3}/solana_agent/interfaces/client/client.py +0 -0
- {solana_agent-31.1.2 → solana_agent-31.1.3}/solana_agent/interfaces/guardrails/guardrails.py +0 -0
- {solana_agent-31.1.2 → solana_agent-31.1.3}/solana_agent/interfaces/plugins/plugins.py +0 -0
- {solana_agent-31.1.2 → solana_agent-31.1.3}/solana_agent/interfaces/providers/data_storage.py +0 -0
- {solana_agent-31.1.2 → solana_agent-31.1.3}/solana_agent/interfaces/providers/llm.py +0 -0
- {solana_agent-31.1.2 → solana_agent-31.1.3}/solana_agent/interfaces/providers/memory.py +0 -0
- {solana_agent-31.1.2 → solana_agent-31.1.3}/solana_agent/interfaces/providers/vector_storage.py +0 -0
- {solana_agent-31.1.2 → solana_agent-31.1.3}/solana_agent/interfaces/services/agent.py +0 -0
- {solana_agent-31.1.2 → solana_agent-31.1.3}/solana_agent/interfaces/services/knowledge_base.py +0 -0
- {solana_agent-31.1.2 → solana_agent-31.1.3}/solana_agent/interfaces/services/query.py +0 -0
- {solana_agent-31.1.2 → solana_agent-31.1.3}/solana_agent/interfaces/services/routing.py +0 -0
- {solana_agent-31.1.2 → solana_agent-31.1.3}/solana_agent/plugins/__init__.py +0 -0
- {solana_agent-31.1.2 → solana_agent-31.1.3}/solana_agent/plugins/manager.py +0 -0
- {solana_agent-31.1.2 → solana_agent-31.1.3}/solana_agent/plugins/registry.py +0 -0
- {solana_agent-31.1.2 → solana_agent-31.1.3}/solana_agent/plugins/tools/__init__.py +0 -0
- {solana_agent-31.1.2 → solana_agent-31.1.3}/solana_agent/plugins/tools/auto_tool.py +0 -0
- {solana_agent-31.1.2 → solana_agent-31.1.3}/solana_agent/repositories/__init__.py +0 -0
- {solana_agent-31.1.2 → solana_agent-31.1.3}/solana_agent/repositories/memory.py +0 -0
- {solana_agent-31.1.2 → solana_agent-31.1.3}/solana_agent/services/__init__.py +0 -0
- {solana_agent-31.1.2 → solana_agent-31.1.3}/solana_agent/services/agent.py +0 -0
- {solana_agent-31.1.2 → solana_agent-31.1.3}/solana_agent/services/knowledge_base.py +0 -0
- {solana_agent-31.1.2 → solana_agent-31.1.3}/solana_agent/services/routing.py +0 -0
@@ -80,7 +80,7 @@ class QueryService(QueryServiceInterface):
|
|
80
80
|
router: Optional[RoutingServiceInterface] = None,
|
81
81
|
output_model: Optional[Type[BaseModel]] = None,
|
82
82
|
capture_schema: Optional[Dict[str, Any]] = None,
|
83
|
-
capture_name: Optional[str] = None,
|
83
|
+
capture_name: Optional[Dict[str, Any]] = None,
|
84
84
|
) -> AsyncGenerator[Union[str, bytes, BaseModel], None]: # pragma: no cover
|
85
85
|
"""Process the user request and generate a response."""
|
86
86
|
try:
|
@@ -241,31 +241,102 @@ class QueryService(QueryServiceInterface):
|
|
241
241
|
options[idx] = label
|
242
242
|
return options
|
243
243
|
|
244
|
-
|
244
|
+
# LLM-backed field detection (gpt-4.1-mini) with graceful fallbacks
|
245
|
+
class _FieldDetect(BaseModel):
|
246
|
+
field: Optional[str] = None
|
247
|
+
|
248
|
+
async def _detect_field_from_prev_question(
|
245
249
|
prev_text: str, schema: Optional[Dict[str, Any]]
|
246
250
|
) -> Optional[str]:
|
247
251
|
if not prev_text or not isinstance(schema, dict):
|
248
252
|
return None
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
if
|
268
|
-
|
253
|
+
props = list((schema.get("properties") or {}).keys())
|
254
|
+
if not props:
|
255
|
+
return None
|
256
|
+
|
257
|
+
question = prev_text.strip()
|
258
|
+
instruction = (
|
259
|
+
"You are a strict classifier. Given the assistant's last question and a list of "
|
260
|
+
"permitted schema field keys, choose exactly one key that the question is asking the user to answer. "
|
261
|
+
"If none apply, return null."
|
262
|
+
)
|
263
|
+
user_prompt = (
|
264
|
+
f"Schema field keys (choose exactly one of these): {props}\n"
|
265
|
+
f"Assistant question:\n{question}\n\n"
|
266
|
+
'Return strictly JSON like: {"field": "<one_of_the_keys_or_null>"}'
|
267
|
+
)
|
268
|
+
|
269
|
+
# Try llm_provider.parse_structured_output with mini
|
270
|
+
try:
|
271
|
+
if hasattr(
|
272
|
+
self.agent_service.llm_provider, "parse_structured_output"
|
273
|
+
):
|
274
|
+
try:
|
275
|
+
result = await self.agent_service.llm_provider.parse_structured_output(
|
276
|
+
prompt=user_prompt,
|
277
|
+
system_prompt=instruction,
|
278
|
+
model_class=_FieldDetect,
|
279
|
+
model="gpt-4.1-nano",
|
280
|
+
)
|
281
|
+
except TypeError:
|
282
|
+
# Provider may not accept 'model' kwarg
|
283
|
+
result = await self.agent_service.llm_provider.parse_structured_output(
|
284
|
+
prompt=user_prompt,
|
285
|
+
system_prompt=instruction,
|
286
|
+
model_class=_FieldDetect,
|
287
|
+
)
|
288
|
+
# Read result
|
289
|
+
sel = None
|
290
|
+
try:
|
291
|
+
sel = getattr(result, "field", None)
|
292
|
+
except Exception:
|
293
|
+
sel = None
|
294
|
+
if sel is None:
|
295
|
+
try:
|
296
|
+
d = result.model_dump()
|
297
|
+
sel = d.get("field")
|
298
|
+
except Exception:
|
299
|
+
sel = None
|
300
|
+
if sel in props:
|
301
|
+
return sel
|
302
|
+
except Exception as e:
|
303
|
+
logger.debug(
|
304
|
+
f"LLM parse_structured_output field detection failed: {e}"
|
305
|
+
)
|
306
|
+
|
307
|
+
# Fallback: use generate_response with output_model=_FieldDetect
|
308
|
+
try:
|
309
|
+
async for r in self.agent_service.generate_response(
|
310
|
+
agent_name=agent_name,
|
311
|
+
user_id=user_id,
|
312
|
+
query=user_text,
|
313
|
+
images=images,
|
314
|
+
memory_context="",
|
315
|
+
output_format="text",
|
316
|
+
prompt=f"{instruction}\n\n{user_prompt}",
|
317
|
+
output_model=_FieldDetect,
|
318
|
+
):
|
319
|
+
fd = r
|
320
|
+
sel = None
|
321
|
+
try:
|
322
|
+
sel = fd.field # type: ignore[attr-defined]
|
323
|
+
except Exception:
|
324
|
+
try:
|
325
|
+
d = fd.model_dump()
|
326
|
+
sel = d.get("field")
|
327
|
+
except Exception:
|
328
|
+
sel = None
|
329
|
+
if sel in props:
|
330
|
+
return sel
|
331
|
+
break
|
332
|
+
except Exception as e:
|
333
|
+
logger.debug(f"LLM generate_response field detection failed: {e}")
|
334
|
+
|
335
|
+
# Final heuristic fallback (keeps system working if LLM unavailable)
|
336
|
+
t = question.lower()
|
337
|
+
for key in props:
|
338
|
+
if key in t:
|
339
|
+
return key
|
269
340
|
return None
|
270
341
|
|
271
342
|
# Resolve active capture from args or agent config
|
@@ -334,7 +405,9 @@ class QueryService(QueryServiceInterface):
|
|
334
405
|
missing_required = _missing(required_fields)
|
335
406
|
missing_optional = _missing(optional_fields)
|
336
407
|
|
337
|
-
target_field: Optional[
|
408
|
+
target_field: Optional[
|
409
|
+
str
|
410
|
+
] = await _detect_field_from_prev_question(
|
338
411
|
prev_assistant, active_capture_schema
|
339
412
|
)
|
340
413
|
if not target_field:
|
@@ -758,5 +831,5 @@ class QueryService(QueryServiceInterface):
|
|
758
831
|
else:
|
759
832
|
fields[field_name] = (typ, default)
|
760
833
|
|
761
|
-
Model = create_model(name, **fields)
|
834
|
+
Model = create_model(name, **fields) # type: ignore
|
762
835
|
return Model
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{solana_agent-31.1.2 → solana_agent-31.1.3}/solana_agent/interfaces/guardrails/guardrails.py
RENAMED
File without changes
|
File without changes
|
{solana_agent-31.1.2 → solana_agent-31.1.3}/solana_agent/interfaces/providers/data_storage.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
{solana_agent-31.1.2 → solana_agent-31.1.3}/solana_agent/interfaces/providers/vector_storage.py
RENAMED
File without changes
|
File without changes
|
{solana_agent-31.1.2 → solana_agent-31.1.3}/solana_agent/interfaces/services/knowledge_base.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|