4 · Tools & Executors — what it uses to act¶
apps/cli/src/local-runtime.ts(route executors) ·packages/dql-agent/src/answer-loop.ts·research-loop.ts·app-planner.ts·kg/sqlite-fts.ts(traversal)
ZLens acts through two layers: route executors (one per route, injected into the engine) and a set of read-only grounding tools the executors compose. Everything the agent acts with is governed, read-only, and preview-bounded.
Route executors¶
Each route in the plan maps to an AgentRouteExecutor — a function that receives the question,
intent, prior evaluations, a repair hint, and the step goal, and returns a result + artifacts.
flowchart TD
ENG["AgentRunEngine"] -->|route| REG{{"AgentRunExecutors map"}}
REG --> A1["certified_answer / generated_answer<br/>→ answerRunExecutor"]
REG --> A2["research<br/>→ research executor"]
REG --> A3["app_build<br/>→ app planner"]
REG --> A4["sql_cell<br/>→ SQL cell generator"]
REG --> A5["dql_block_draft<br/>→ draft + certifier"]
REG --> A6["clarify<br/>→ single question"]
A1 --> ANS["answer-loop: ground → query-plan → SQL → preview → repair"]
A2 --> RES["research-loop: plan investigate steps → dossier + preview"]
| Executor | Backed by | Output artifact |
|---|---|---|
answerRunExecutor (certified + generated) |
answer-loop.ts |
answer (result + SQL + trust) |
| research | research-loop.ts + notebook research storage |
research_run (dossier + result preview) |
| app | app-planner.ts |
app_draft |
| sql cell | grounded SQL gen | sql_cell |
| block draft | draft + certifier verdict | dql_block_draft |
The read-only tool registry (the grounding toolbox)¶
The executors compose a small set of read-only tools — each a thin wrapper over code that already exists. Tools observe; they never mutate governed state, never certify, and never write SQL to the warehouse beyond a bounded preview.
flowchart LR
subgraph Tools["Read-only tool set"]
T1["search_catalog(query, kinds, domain)<br/>→ KGStore.search"]
T2["lookup_metric(question)<br/>→ matchSemanticMetric + governed SQL"]
T3["inspect_schema / sample(relation)<br/>→ schema context + bounded LIMIT preview"]
T4["traverse_domain_graph(nodeId, edgeKinds)<br/>→ KGStore.neighbors / findJoinPath"]
T5["plan_query(question, context)<br/>→ CoT grain/measures/dims/joins"]
T6["run_sql_preview(sql)<br/>→ executeGeneratedSql (bounded)"]
T7["recall_experience(question, scope)<br/>→ memory + approved hints"]
end
EXEC["Executor"] --> Tools
Tools --> OBS["Observations → reason → propose SQL → gate"]
| Tool | Wraps | Purpose |
|---|---|---|
search_catalog |
KGStore.search (FTS5) |
find relevant blocks / metrics / models |
lookup_metric |
matchSemanticMetric |
resolve a governed metric to executable SQL |
inspect_schema / sample |
schema context + executeGeneratedSql (LIMIT) |
see real columns + sample values |
traverse_domain_graph |
KGStore.neighbors / findJoinPath |
relate entities/models across domains |
plan_query |
prompt stage | CoT grain + join path before SQL |
run_sql_preview |
executeGeneratedSql |
execution-guided check (bounded rows) |
recall_experience |
MemoryStore + retrieveScopedHints |
reuse prior corrections/lessons |
The safety envelope¶
flowchart TD
T["Any tool call"] --> RO{"read-only?"}
RO -->|yes| OK["✅ allowed"]
RO -->|no| NO["🚫 not in the toolbox"]
OK --> G1["never bypasses certification (human-gated)"]
OK --> G2["generated SQL stays review-required"]
OK --> G3["warehouse access is a bounded preview (LIMIT)"]
OK --> G4["audience constraints: stakeholders never author SQL/blocks"]
Model provider¶
The LLM itself is a pluggable provider (pickProvider): Anthropic, OpenAI, Gemini, Ollama
(local), or custom-OpenAI-compatible — each with optional base-URL for enterprise gateways. When no
provider is available, the deterministic paths still work (templated SQL + deterministic planner), so
the loop degrades gracefully offline.
Current vs roadmap¶
- ✅ Route executors — fully wired; the engine calls them per step.
- ✅ Grounding tools' building blocks — all exist (
KGStore.search/neighbors/findJoinPath,matchSemanticMetric,executeGeneratedSql, memory/hints). - ⚙️ Iterative ReAct tool-loop — the executor currently proposes SQL largely one-shot then
repairs; converting
generated_answer/researchinto a bounded 2–3 iterationplan → search → inspect → preview → reflectloop is the documented next increment (kept out of the one-shot path to avoid regressing what works).
→ Next: Evaluation & trust