Runtime view — tool-calling path¶
Status: Implemented (v3)
This page describes how engineering calculation requests are handled, including validation errors and the retry loop.
Flow diagram¶
The router is not a LangGraph node — it is the conditional edge
route_after_intent() evaluated after the intent node.
graph TD
Start([User: calculation query]) --> Intent[Intent node]
Intent -->|calculation| Tools[Tools node]
Tools --> Guard{refuse_unsafe<br/>calculations?}
Guard -->|stress without FoS context| Refuse[Append error, skip tool]
Guard -->|ok| Select{LLM or regex<br/>tool selection}
Select --> Validate{Pydantic<br/>validation}
Validate -->|invalid args| Err[Append to state.errors]
Err -->|retry if attempts < 3| Select
Validate -->|valid| Exec[Execute pure Python tool]
Exec --> Result[tool_results in state]
Refuse --> Report[Report node]
Result --> Report
Report --> End([Answer to user])
classDef error fill:#fdd,stroke:#333;
class Err error;
class Refuse error;
The loop from validation errors back to tool selection is the LangGraph conditional edge on the tools node: the LLM (or regex fallback) sees prior errors and can correct inputs on the next attempt.
Tool selection modes¶
| Mode | When | Mechanism |
|---|---|---|
| LLM tool-calling | CAEC_LLM_API_KEY set |
langchain bind_tools + ToolMessage loop |
| Regex dispatch | No API key | Pattern rules in nodes/tools.py |
| Input parsing | Regex mode | name=value pairs extracted from query |
Max attempts: 3 (_MAX_TOOL_ATTEMPTS in nodes/tools.py).
Registered tools¶
| Tool | Purpose |
|---|---|
estimate_particle_count |
Estimate particle count from geometry and packing density |
convert_units |
Convert length/mass/time units (mm/m, g/kg, ms/s) |
check_timestep_heuristic |
Heuristic DEM timestep check from particle size and density |
All tools are pure functions — no I/O, no LLM calls inside the tool body.
Validation and self-correction¶
- LLM proposes tool name + JSON arguments.
validate_tool_inputs()checks against the JSON Schema intools/registry.py.- On failure, error message is appended to
state["errors"]. - Graph retries up to
_MAX_TOOL_ATTEMPTS. - On success,
ToolResultis stored and the report node formats the answer.
Guardrails¶
When CAEC_REFUSE_UNSAFE_CALCULATIONS=true, the tools node refuses to run
a calculation when the query mentions stress without safety-factor context or
explicit yield_stress / max_stress parameters. The report node then
formats the refusal message for the user.
Related¶
- Principles — pure tools
- Data flow — RAG path
- API contract