Memory-Quilt / src /app_kit /tracing.py
Abhishek
Initialize project files and updated hackathon tags
485459a
Raw
History Blame Contribute Delete
4.09 kB
from __future__ import annotations
import json
import uuid
from dataclasses import asdict, is_dataclass
from datetime import datetime, timezone
from pathlib import Path
from typing import Any
_CANONICAL_INPUT_KEYS = (
'inputs',
'input',
'pack',
'pack_id',
'pack_name',
'pack_path',
'project',
'scenario_id',
'scenario_count',
'query',
'prompt',
'transcript',
'text',
)
_MODEL_HINT_KEYS = (
'model_name',
'base_model_id',
'base_model',
'model_id',
'adapter_name',
'loaded_from',
'adapter_path',
)
def utc_now() -> str:
return datetime.now(timezone.utc).isoformat(timespec='seconds')
def _json_safe(value: Any) -> Any:
if is_dataclass(value):
return _json_safe(asdict(value))
if isinstance(value, Path):
return str(value)
if isinstance(value, dict):
return {str(key): _json_safe(item) for key, item in value.items()}
if isinstance(value, (list, tuple)):
return [_json_safe(item) for item in value]
return value
def _nonempty(value: Any) -> bool:
return value not in (None, '', [], {}, ())
def _infer_input_payload(payload: dict[str, Any]) -> Any:
existing_inputs = payload.get('inputs')
if _nonempty(existing_inputs):
return existing_inputs
inputs: dict[str, Any] = {}
for key in _CANONICAL_INPUT_KEYS:
if key in payload and key != 'inputs' and _nonempty(payload[key]):
inputs[key] = payload[key]
if inputs:
return inputs
for key in ('project', 'pack_id', 'pack_name', 'pack_path', 'pack'):
if key in payload and _nonempty(payload[key]):
inputs[key] = payload[key]
return inputs
def _infer_model_name(value: Any) -> str | None:
if isinstance(value, dict):
for key in _MODEL_HINT_KEYS:
candidate = value.get(key)
if isinstance(candidate, str) and candidate.strip():
return candidate.strip()
for item in value.values():
candidate = _infer_model_name(item)
if candidate:
return candidate
elif isinstance(value, list):
for item in value:
candidate = _infer_model_name(item)
if candidate:
return candidate
return None
def canonicalize_trace_payload(payload: dict[str, Any]) -> dict[str, Any]:
normalized = _json_safe(payload)
timestamp = normalized.get('timestamp') or normalized.get('finished_at') or normalized.get('started_at') or utc_now()
parsed_outputs = normalized.get('parsed_outputs')
if not _nonempty(parsed_outputs):
parsed_outputs = normalized.get('result')
if not _nonempty(parsed_outputs):
parsed_outputs = normalized.get('results')
if not _nonempty(parsed_outputs):
parsed_outputs = normalized.get('output')
if not _nonempty(parsed_outputs):
parsed_outputs = {}
model_name = normalized.get('model_name')
if not _nonempty(model_name):
model_name = _infer_model_name(parsed_outputs) or _infer_model_name(normalized)
if not _nonempty(model_name):
model_name = 'unknown'
normalized['timestamp'] = str(timestamp)
normalized['inputs'] = _infer_input_payload(normalized)
normalized['parsed_outputs'] = parsed_outputs
normalized['model_name'] = str(model_name)
return normalized
def write_trace_artifact(artifact_dir: str | Path, payload: dict[str, Any]) -> Path:
artifact_dir = Path(artifact_dir)
trace_dir = artifact_dir / 'traces'
trace_dir.mkdir(parents=True, exist_ok=True)
run_id = str(payload.get('run_id') or uuid.uuid4().hex)
kind = str(payload.get('kind', 'trace')).strip().replace('/', '_').replace(' ', '_') or 'trace'
trace_path = trace_dir / f'{kind}-{run_id}.json'
normalized = canonicalize_trace_payload(payload)
normalized['run_id'] = run_id
normalized['trace_path'] = str(trace_path)
trace_path.write_text(json.dumps(normalized, indent=2, ensure_ascii=False, sort_keys=True, default=str), encoding='utf-8')
return trace_path