mirror of
https://github.com/trustgraph-ai/trustgraph.git
synced 2026-04-25 00:16:23 +02:00
Split Analysis into Analysis+ToolUse and Observation, add message_id (#747)
Refactor agent provenance so that the decision (thought + tool selection) and the result (observation) are separate DAG entities: Question ← Analysis+ToolUse ← Observation ← ... ← Conclusion Analysis gains tg:ToolUse as a mixin RDF type and is emitted before tool execution via an on_action callback in react(). This ensures sub-traces (e.g. GraphRAG) appear after their parent Analysis in the streaming event order. Observation becomes a standalone prov:Entity with tg:Observation type, emitted after tool execution. The linear DAG chain runs through Observation — subsequent iterations and the Conclusion derive from it, not from the Analysis. message_id is populated on streaming AgentResponse for thought and observation chunks, using the provenance URI of the entity being built. This lets clients group streamed chunks by entity. Wire changes: - provenance/agent.py: Add ToolUse type, new agent_observation_triples(), remove observation from iteration - agent_manager.py: Add on_action callback between reason() and tool execution - orchestrator/pattern_base.py: Split emit, wire message_id, chain through observation URIs - orchestrator/react_pattern.py: Emit Analysis via on_action before tool runs - agent/react/service.py: Same for non-orchestrator path - api/explainability.py: New Observation class, updated dispatch and chain walker - api/types.py: Add message_id to AgentThought/AgentObservation - cli: Render Observation separately, [analysis: tool] labels
This commit is contained in:
parent
89e13a756a
commit
153ae9ad30
28 changed files with 661 additions and 350 deletions
|
|
@ -12,6 +12,7 @@ from trustgraph.api import (
|
|||
ProvenanceEvent,
|
||||
Question,
|
||||
Analysis,
|
||||
Observation,
|
||||
Conclusion,
|
||||
Decomposition,
|
||||
Finding,
|
||||
|
|
@ -206,13 +207,13 @@ def question_explainable(
|
|||
print(f" Time: {entity.timestamp}", file=sys.stderr)
|
||||
|
||||
elif isinstance(entity, Analysis):
|
||||
print(f"\n [iteration] {prov_id}", file=sys.stderr)
|
||||
if entity.action:
|
||||
print(f" Action: {entity.action}", file=sys.stderr)
|
||||
if entity.thought:
|
||||
print(f" Thought: {entity.thought}", file=sys.stderr)
|
||||
if entity.observation:
|
||||
print(f" Observation: {entity.observation}", file=sys.stderr)
|
||||
action_label = f": {entity.action}" if entity.action else ""
|
||||
print(f"\n [analysis{action_label}] {prov_id}", file=sys.stderr)
|
||||
|
||||
elif isinstance(entity, Observation):
|
||||
print(f"\n [observation] {prov_id}", file=sys.stderr)
|
||||
if entity.document:
|
||||
print(f" Document: {entity.document}", file=sys.stderr)
|
||||
|
||||
elif isinstance(entity, Decomposition):
|
||||
print(f"\n [decompose] {prov_id}", file=sys.stderr)
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ from trustgraph.api import (
|
|||
Focus,
|
||||
Synthesis,
|
||||
Analysis,
|
||||
Observation,
|
||||
Conclusion,
|
||||
Decomposition,
|
||||
Finding,
|
||||
|
|
@ -379,11 +380,13 @@ def print_agent_text(trace, explain_client, api, user):
|
|||
print(f" {line}")
|
||||
except Exception:
|
||||
print(f" Arguments: {step.arguments}")
|
||||
print()
|
||||
|
||||
obs = step.observation or 'N/A'
|
||||
if obs and len(obs) > 200:
|
||||
obs = obs[:200] + "... [truncated]"
|
||||
print(f" Observation: {obs}")
|
||||
elif isinstance(step, Observation):
|
||||
print("--- Observation ---")
|
||||
_print_document_content(
|
||||
explain_client, api, user, step.document, "Content",
|
||||
)
|
||||
print()
|
||||
|
||||
elif isinstance(step, Synthesis):
|
||||
|
|
@ -437,6 +440,12 @@ def trace_to_dict(trace, trace_type):
|
|||
"step": step.step,
|
||||
"document": step.document,
|
||||
}
|
||||
elif isinstance(step, Observation):
|
||||
return {
|
||||
"type": "observation",
|
||||
"id": step.uri,
|
||||
"document": step.document,
|
||||
}
|
||||
elif isinstance(step, Analysis):
|
||||
return {
|
||||
"type": "analysis",
|
||||
|
|
@ -444,7 +453,6 @@ def trace_to_dict(trace, trace_type):
|
|||
"action": step.action,
|
||||
"arguments": step.arguments,
|
||||
"thought": step.thought,
|
||||
"observation": step.observation,
|
||||
}
|
||||
elif isinstance(step, Synthesis):
|
||||
return {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue