81 lines
2.4 KiB
Python
81 lines
2.4 KiB
Python
"""Agent orchestration observability model.
|
|
|
|
Tracks OpenClaw, Hermes and sub-agent execution chains. Token usage is optional
|
|
and depends on model adapter instrumentation.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from dataclasses import asdict, dataclass, field
|
|
from datetime import datetime, timezone
|
|
from typing import Any
|
|
|
|
|
|
def utc_now():
|
|
return datetime.now(timezone.utc).isoformat()
|
|
|
|
|
|
@dataclass
|
|
class AgentExecutionRecord:
|
|
execution_id: str
|
|
user_id: str
|
|
visible_scope: str
|
|
entry_agent: str
|
|
path: list[str]
|
|
used_hermes: bool
|
|
closed_by: str
|
|
duration_ms: int = 0
|
|
input_tokens: int | None = None
|
|
output_tokens: int | None = None
|
|
total_tokens: int | None = None
|
|
status: str = "completed"
|
|
started_at: str = field(default_factory=utc_now)
|
|
ended_at: str = field(default_factory=utc_now)
|
|
|
|
def to_dict(self):
|
|
return asdict(self)
|
|
|
|
|
|
class AgentObservability:
|
|
def __init__(self):
|
|
self.records: list[AgentExecutionRecord] = []
|
|
|
|
def record(self, record: AgentExecutionRecord):
|
|
self.records.append(record)
|
|
return record.to_dict()
|
|
|
|
def summary(self, user_id: str | None = None) -> dict[str, Any]:
|
|
records = [r for r in self.records if not user_id or r.user_id == user_id]
|
|
hermes = [r for r in records if r.used_hermes]
|
|
direct = [r for r in records if not r.used_hermes]
|
|
return {
|
|
"total_executions": len(records),
|
|
"openclaw_independent_loops": len(direct),
|
|
"hermes_orchestrated_loops": len(hermes),
|
|
"average_duration_ms": (
|
|
sum(r.duration_ms for r in records) / len(records) if records else 0
|
|
),
|
|
"token_usage": {
|
|
"input": sum(r.input_tokens or 0 for r in records),
|
|
"output": sum(r.output_tokens or 0 for r in records),
|
|
"total": sum(r.total_tokens or 0 for r in records),
|
|
},
|
|
}
|
|
|
|
def hermes_tree(self, user_id: str | None = None):
|
|
return [
|
|
{
|
|
"execution_id": r.execution_id,
|
|
"entry": r.entry_agent,
|
|
"used_hermes": r.used_hermes,
|
|
"children": r.path,
|
|
"duration_ms": r.duration_ms,
|
|
"tokens": r.total_tokens,
|
|
}
|
|
for r in self.records
|
|
if (not user_id or r.user_id == user_id)
|
|
]
|
|
|
|
|
|
__all__ = ["AgentExecutionRecord", "AgentObservability"]
|