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

@@ -20,6 +20,8 @@ from langgraph.checkpoint.postgres.aio import AsyncPostgresSaver
from langgraph.prebuilt import create_react_agent
from psycopg.rows import dict_row
from src.core.logger import logger
# ── Monkey-patch: OpenAI SDK for Pydantic BaseModel classes ──
# LangChain BaseTool objects carry an ``args_schema`` field that is a Pydantic
# BaseModel *class* reference (not an instance). When the OpenAI SDK recursively
@@ -111,8 +113,9 @@ async def _fetch_llm_config() -> dict | None:
if config.get("configured"):
_llm_config = config
return config
except Exception:
pass # Keep existing config on failure
except Exception as e:
logger.explore("Failed to fetch LLM config from FastAPI", error=str(e),
extra={"src": "AgentChat.LangGraph.Setup"})
return _llm_config
@@ -151,10 +154,24 @@ async def create_agent(
api_key = config["api_key"]
base_url = config.get("base_url") or "https://api.openai.com/v1"
model = config.get("default_model") or "gpt-4o-mini"
config_source = "FastAPI"
else:
api_key = os.getenv("LLM_API_KEY")
base_url = os.getenv("LLM_BASE_URL", "https://api.openai.com/v1")
model = os.getenv("LLM_MODEL", "gpt-4o")
config_source = "env vars"
logger.explore(
"LLM config not found in FastAPI, falling back to env vars",
payload={"model": model, "provider_type": config.get("provider_type") if config else None},
error="No configured LLM provider in FastAPI",
extra={"src": "AgentChat.LangGraph.Setup"},
)
logger.reason(
"Creating LangGraph agent",
payload={"model": model, "config_source": config_source, "tools_count": len(tools), "env_id": env_id},
extra={"src": "AgentChat.LangGraph.Setup"},
)
llm = ChatOpenAI(
model=model,
@@ -179,6 +196,11 @@ async def create_agent(
checkpointer = _CHECKPOINTER
else:
checkpointer = InMemorySaver()
logger.explore(
"Postgres checkpointer unavailable, falling back to InMemorySaver",
error="_CHECKPOINTER is None — checkpoints will be lost on restart",
extra={"src": "AgentChat.LangGraph.Setup"},
)
graph = create_react_agent(
model=llm,
@@ -189,5 +211,10 @@ async def create_agent(
interrupt_before=_interrupt_before_from_env() if interrupt_before is None else interrupt_before,
)
logger.reflect(
"LangGraph agent created",
payload={"model": model, "checkpointer_type": type(checkpointer).__name__, "tools_count": len(tools)},
extra={"src": "AgentChat.LangGraph.Setup"},
)
return graph
# #endregion AgentChat.LangGraph.Setup