fix(agent): unify logging API + add molecular-cot coverage to agent module
Phase 1 — API unification: - Replace direct log() from cot_logger with canonical logger.reason/reflect/explore across _confirmation.py, _persistence.py, _tool_resolver.py, app.py Phase 2 — Gap filling: - tools.py: add REASON/REFLECT/EXPLORE to 17 C3 tool functions (was 0 logs) - app.py agent_handler (C4): add lifecycle REASON on entry, REFLECT on exit, EXPLORE on OutputParserException + general exception - langgraph_setup.py create_agent (C4): add REASON with model/config_source, EXPLORE on env-var/InMemorySaver fallback, REFLECT on graph compilation - _tool_resolver.py infer_tool_from_text (C3, 13 branches): REASON on inference - _persistence.py: REFLECT on save_conversation success, EXPLORE on prefetch Phase 3 — Plain log migration: - middleware.py: plain logger.info() -> logger.reason() - run.py: 7 plain logger.info/warning/error -> molecular REASON/EXPLORE Phase 4 — Cleanup: - cot_logger.py: deprecate MarkerLogger (@DEPRECATED + @REPLACED_BY) - molecular-cot-logging SKILL.md: remove cot_span Section IV (never implemented), renumber sections V-VII -> IV-VI, add cot_span rejection rationale Verification: pytest 27/27, axiom rebuild 5844/2993/0 warnings
This commit is contained in:
@@ -9,7 +9,7 @@ description: Structured logging protocol for agent-driven development, based on
|
||||
@RELATION DISPATCHES -> [Std.Semantics.Python]
|
||||
@RELATION DISPATCHES -> [Std.Semantics.Svelte]
|
||||
@RATIONALE Long CoT chains need stabilisation through explicit reasoning bonds. The three-marker system (REASON/REFLECT/EXPLORE) maps directly to the molecular CoT paper and produces machine-readable execution traces that LLM agents can parse, analyse, and use for fine-tuning (MoLE-Syn bond distributions). Without structured markers, agent-generated code exhibits invisible failures: a function returns `None` instead of raising — the agent's attention never sees it because there's no log; a fallback path activates silently — no EXPLORE marker, no trace. JSON-line format ensures every log entry is a self-contained, parseable unit that survives log rotation, aggregation, and agent parsing — unlike plain-text logs that require regex heuristics.
|
||||
@REJECTED Legacy Entry/Exit/Action/Coherence markers rejected — they are too generic, do not map to reasoning structure, and prevent traceability graph analysis. Plain-text logging rejected — JSON lines are mandatory for agent parsing. Unstructured printf-style logging rejected — agents cannot reliably extract structured fields (trace_id, marker, intent) from free-form text, making automated diagnosis impossible.
|
||||
@REJECTED Legacy Entry/Exit/Action/Coherence markers rejected — they are too generic, do not map to reasoning structure, and prevent traceability graph analysis. Plain-text logging rejected — JSON lines are mandatory for agent parsing. Unstructured printf-style logging rejected — agents cannot reliably extract structured fields (trace_id, marker, intent) from free-form text, making automated diagnosis impossible. cot_span decorator rejected — replaced by belief_scope context manager + logger.reason/reflect/explore which gives more granular intent control per logical branch.
|
||||
@DATA_CONTRACT LogEntry -> { ts: str, level: str, trace_id: str, span_id?: str, src: str, marker: REASON|REFLECT|EXPLORE, intent: str, payload?: object, error?: str }
|
||||
@INVARIANT Every log line MUST carry exactly one valid marker (REASON | REFLECT | EXPLORE). No markerless log lines in C4/C5 code.
|
||||
@INVARIANT trace_id MUST propagate via ContextVar across async boundaries. Every incoming request or background job seeds a new trace_id.
|
||||
@@ -207,58 +207,7 @@ class TraceMiddleware(BaseHTTPMiddleware):
|
||||
return response
|
||||
```
|
||||
|
||||
## IV. Python Decorator (Span + Marker)
|
||||
|
||||
For C4/C5 functions, a decorator that auto-emits REASON / REFLECT markers:
|
||||
|
||||
```python
|
||||
import asyncio
|
||||
from functools import wraps
|
||||
|
||||
def cot_span(marker: str = "REASON", intent: str | None = None):
|
||||
"""Wrap a function in a CoT span. On enter → REASON, on success → REFLECT,
|
||||
on exception → EXPLORE."""
|
||||
def decorator(func):
|
||||
@wraps(func)
|
||||
async def async_wrapper(*args, **kwargs):
|
||||
src = f"{func.__module__}.{func.__qualname__}"
|
||||
prev_span = push_span(func.__qualname__)
|
||||
default_intent = intent or f"Execute {func.__qualname__}"
|
||||
try:
|
||||
log(src, marker, default_intent, payload=_summarise_args(args, kwargs))
|
||||
result = await func(*args, **kwargs)
|
||||
log(src, "REFLECT", f"{func.__qualname__} completed",
|
||||
payload={"result": _summarise_value(result)})
|
||||
return result
|
||||
except Exception as e:
|
||||
log(src, "EXPLORE", f"{func.__qualname__} failed",
|
||||
error=str(e), payload={"args": _summarise_args(args, kwargs)})
|
||||
raise
|
||||
finally:
|
||||
pop_span(prev_span)
|
||||
|
||||
@wraps(func)
|
||||
def sync_wrapper(*args, **kwargs):
|
||||
... # same logic, sync variant
|
||||
return async_wrapper if asyncio.iscoroutinefunction(func) else sync_wrapper
|
||||
return decorator
|
||||
|
||||
|
||||
def _summarise_value(val, max_len: int = 200) -> str:
|
||||
s = str(val)
|
||||
return s[:max_len] + "..." if len(s) > max_len else s
|
||||
|
||||
def _summarise_args(args, kwargs) -> dict:
|
||||
# Skip 'self', 'cls', 'db', 'request' — too verbose
|
||||
skip = {"self", "cls", "db", "request", "session"}
|
||||
result = {}
|
||||
for k, v in kwargs.items():
|
||||
if k not in skip:
|
||||
result[k] = _summarise_value(v)
|
||||
return result
|
||||
```
|
||||
|
||||
## V. Svelte / Frontend Pattern
|
||||
## IV. Svelte / Frontend Pattern
|
||||
|
||||
The frontend implementation lives at `frontend/src/lib/cot-logger.ts` (installed as `$lib/cot-logger`).
|
||||
|
||||
@@ -321,7 +270,7 @@ const res = await requestApi("/api/endpoint");
|
||||
if (res.trace_id) setTraceId(res.trace_id);
|
||||
```
|
||||
|
||||
## VI. CLI / Stdout Reader (for humans)
|
||||
## V. CLI / Stdout Reader (for humans)
|
||||
|
||||
To make JSON lines readable in development:
|
||||
|
||||
@@ -341,7 +290,7 @@ for line in sys.stdin:
|
||||
"
|
||||
```
|
||||
|
||||
## VII. Anti-patterns
|
||||
## VI. Anti-patterns
|
||||
|
||||
| ❌ Don't | ✅ Do |
|
||||
|----------|-------|
|
||||
|
||||
Reference in New Issue
Block a user