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:
2026-06-30 15:48:46 +03:00
parent 131c7cdfa4
commit a0619ca049
10 changed files with 359 additions and 148 deletions

View File

@@ -11,9 +11,8 @@
import os
import socket
import httpx
import logging
logger = logging.getLogger("cot")
from src.core.logger import logger
FASTAPI_URL = os.getenv("FASTAPI_URL", "http://localhost:8000")
@@ -46,16 +45,37 @@ def _fetch_llm_config() -> dict | None:
resp.raise_for_status()
config = resp.json()
if config.get("configured"):
logger.info("LLM config fetched from FastAPI: %s (%s)", config.get("provider_type"), config.get("default_model"))
logger.reason(
"LLM config fetched from FastAPI",
payload={"provider_type": config.get("provider_type"), "model": config.get("default_model")},
extra={"src": "AgentChat.Run.FetchLlmConfig"},
)
return config
logger.warning("FastAPI returned no active LLM provider: %s", config.get("reason"))
logger.explore(
"FastAPI returned no active LLM provider",
payload={"reason": config.get("reason")},
error="No configured LLM provider",
extra={"src": "AgentChat.Run.FetchLlmConfig"},
)
except Exception as e:
if attempt < 5:
logger.info("Waiting for FastAPI (attempt %d/6): %s", attempt + 1, e)
logger.reason(
f"Waiting for FastAPI (attempt {attempt + 1}/6)",
payload={"error": str(e)},
extra={"src": "AgentChat.Run.FetchLlmConfig"},
)
time.sleep(5)
else:
logger.warning("Failed to fetch LLM config from FastAPI after 6 attempts: %s", e)
logger.info("Falling back to env vars for LLM config")
logger.explore(
"Failed to fetch LLM config after 6 attempts",
error=str(e),
extra={"src": "AgentChat.Run.FetchLlmConfig"},
)
logger.explore(
"Falling back to env vars for LLM config",
error="FastAPI unreachable",
extra={"src": "AgentChat.Run.FetchLlmConfig"},
)
return None
@@ -85,9 +105,18 @@ if __name__ == "__main__":
try:
port = _find_free_port(configured_port)
if port != configured_port:
logger.warning("Port %d is in use, falling back to port %d", configured_port, port)
logger.explore(
"Port in use, falling back",
payload={"configured_port": configured_port, "actual_port": port},
error=f"Port {configured_port} is in use",
extra={"src": "AgentChat.Run.PortBinding"},
)
except OSError as e:
logger.error("Failed to find a free port: %s", e)
logger.explore(
"Failed to find a free port",
error=str(e),
extra={"src": "AgentChat.Run.PortBinding"},
)
raise
else:
port = configured_port