mirror of
https://github.com/trustgraph-ai/trustgraph.git
synced 2026-07-08 21:02:12 +02:00
Addresses recommendations from the UX developer's agent experience report. Adds provenance predicates, DAG structure changes, error resilience, and a published OWL ontology. Explainability additions: - Tool candidates: tg:toolCandidate on Analysis events lists the tools visible to the LLM for each iteration (names only, descriptions in config) - Termination reason: tg:terminationReason on Conclusion/Synthesis events (final-answer, plan-complete, subagents-complete) - Step counter: tg:stepNumber on iteration events - Pattern decision: new tg:PatternDecision entity in the DAG between session and first iteration, carrying tg:pattern and tg:taskType - Latency: tg:llmDurationMs on Analysis events, tg:toolDurationMs on Observation events - Token counts on events: tg:inToken/tg:outToken/tg:llmModel on Grounding, Focus, Synthesis, and Analysis events - Tool/parse errors: tg:toolError on Observation events with tg:Error mixin type. Parse failures return as error observations instead of crashing the agent, giving it a chance to retry. Envelope unification: - Rename chunk_type to message_type across AgentResponse schema, translator, SDK types, socket clients, CLI, and all tests. Agent and RAG services now both use message_type on the wire. Ontology: - specs/ontology/trustgraph.ttl — OWL vocabulary covering all 26 classes, 7 object properties, and 36+ datatype properties including new predicates. DAG structure tests: - tests/unit/test_provenance/test_dag_structure.py verifies the wasDerivedFrom chain for GraphRAG, DocumentRAG, and all three agent patterns (react, plan, supervisor) including the pattern-decision link.
94 lines
2.8 KiB
Python
94 lines
2.8 KiB
Python
|
|
|
|
from .. schema import AgentRequest, AgentResponse
|
|
from .. schema import agent_request_queue
|
|
from .. schema import agent_response_queue
|
|
from . base import BaseClient
|
|
|
|
# Ugly
|
|
|
|
class AgentClient(BaseClient):
|
|
|
|
def __init__(
|
|
self,
|
|
subscriber=None,
|
|
input_queue=None,
|
|
output_queue=None,
|
|
pulsar_host="pulsar://pulsar:6650",
|
|
pulsar_api_key=None,
|
|
):
|
|
|
|
if input_queue is None: input_queue = agent_request_queue
|
|
if output_queue is None: output_queue = agent_response_queue
|
|
|
|
super(AgentClient, self).__init__(
|
|
subscriber=subscriber,
|
|
input_queue=input_queue,
|
|
output_queue=output_queue,
|
|
pulsar_host=pulsar_host,
|
|
input_schema=AgentRequest,
|
|
output_schema=AgentResponse,
|
|
pulsar_api_key=pulsar_api_key
|
|
)
|
|
|
|
def request(
|
|
self,
|
|
question,
|
|
think=None,
|
|
observe=None,
|
|
answer_callback=None,
|
|
error_callback=None,
|
|
timeout=300
|
|
):
|
|
"""
|
|
Request an agent query with optional streaming callbacks.
|
|
|
|
Args:
|
|
question: The question to ask
|
|
think: Optional callback(content, end_of_message) for thought chunks
|
|
observe: Optional callback(content, end_of_message) for observation chunks
|
|
answer_callback: Optional callback(content, end_of_message) for answer chunks
|
|
error_callback: Optional callback(content) for error messages
|
|
timeout: Request timeout in seconds
|
|
|
|
Returns:
|
|
Complete answer text (accumulated from all answer chunks)
|
|
"""
|
|
accumulated_answer = []
|
|
|
|
def inspect(x):
|
|
# Handle errors
|
|
if x.message_type == 'error' or x.error:
|
|
if error_callback:
|
|
error_callback(x.content or (x.error.message if x.error else ""))
|
|
# Continue to check end_of_dialog
|
|
|
|
# Handle thought chunks
|
|
elif x.message_type == 'thought':
|
|
if think:
|
|
think(x.content, x.end_of_message)
|
|
|
|
# Handle observation chunks
|
|
elif x.message_type == 'observation':
|
|
if observe:
|
|
observe(x.content, x.end_of_message)
|
|
|
|
# Handle answer chunks
|
|
elif x.message_type == 'answer':
|
|
if x.content:
|
|
accumulated_answer.append(x.content)
|
|
if answer_callback:
|
|
answer_callback(x.content, x.end_of_message)
|
|
|
|
# Complete when dialog ends
|
|
if x.end_of_dialog:
|
|
return True
|
|
|
|
return False # Continue receiving
|
|
|
|
self.call(
|
|
question=question, inspect=inspect, timeout=timeout
|
|
)
|
|
|
|
return "".join(accumulated_answer)
|
|
|