# agent: Agent core, Tools, goal verifier, RAG stats, scheduler Literal port of tai.py 1.44.2 (lines 9016-9335, 17071-20640, 40391-40460). Namespace `detz::agent`, sources in `src/agent`. ## Layout | File | tai.py origin | |---|---| | `data.cpp` (generated) | `TOOL_SCHEMAS`, `TOOL_TAGS`, `CORE_TOOLS`, `LAZY_NAME_STOP`, prompt texts. Regenerate: `python3 -I src/agent/gen/gen_data.py > src/agent/data.cpp` | | `data_html.cpp` (generated) | `html.entities.html5` for `html.unescape` | | `agent.cpp/.h` | `Agent`, `select_tools`, `tool_catalog`, `compact_messages`, `resume_turn`, `update_models_command`, `default_runner`, mentions | | `tools_*.cpp`, `tools.h` | `Tools` (61 handlers, `dispatch`, secrets, audit, box helpers) | | `goal.cpp` | `Denied`, `AgentsFull`, `Approval`, `GoalFailure`, `GoalVerdict`, `GoalVerifier` | | `rag.cpp` | `RetrievalEval`, `RagStats` | | `registry.cpp` | `spawn_agent`, `poll_agent`, `list_agents`, `clear_agents`, `running_agents` | | `scheduler.cpp` | `note_schedule_result`, `watch_schedule`, `schedule_running`, `scheduler_tick`, `run_scheduler_loop`/`start_scheduler` (class `Scheduler`) | | `text.cpp` | `truncate`-family helpers, tags, `chunk_lines`, `spill_*`, tmux/history helpers, `html.unescape`, schedule helpers | | `tui_control.cpp` | `grr_control_path`, `grr_control_call` (client only) | | `zipfile.cpp` | `zipfile.extractall` (stored + deflate) for `install_skill` | | `ports.h` | the narrow interfaces to everything this module does not own | ## Ports (declared here, implemented elsewhere) `StorePort` (mirrors Python `Store` method names), `RuntimePort` (worker store), `ShellPort` (run_live, LiveStream, LaneBoard, box), `UiPort` (Spinner, Glow, markdown, diff; optional, plain fallbacks exist), `McpPort`, `SkillsPort`, `PlexerPort`, `TuiControlPort` (optional, built-in client otherwise), `OpsPort` (install, release, sysinfo, speech), `SchedulerDbPort`. Unwired required ports raise `PortNotWired`, shown to the model as `error: port not wired: X`. Plexer unwired means "no session", exactly like no tmux. ## Behaviour notes - All string lengths and slices are code points (`detz::py`, `src/llm/py.h`). - Integers beyond int64 clamp in `int()` conversions (Python is unbounded); JSON keeps big ints verbatim. - `html.unescape`, `str.lower/upper` (including final sigma) use tables generated from Python. ## Verification (what was actually run) - `tests/agent_diff.py`: 7601 cases per seed (seeds 1-4 run, 0 mismatches). Includes the full `json.dumps(TOOL_SCHEMAS)` byte comparison, `select_tools` on 24 prompts plus fuzz, `tool_catalog`, all prompt texts, goal verdicts, CLI output parsers, history cleanup, tag helpers, html/url helpers, schedule helpers, candidate ordering of `ChatClient`. - `tests/agent_e2e.py`: 43 scripted conversations through the real Agent loop in both programs (messages, HTTP request bodies, store events, audit rows identical). Covers file tools, shell, secrets, schedules, bots/mentions, compaction, retries, 400 tool fallback, ask_user, approval deny, verify loop, remember, web_fetch/search, fork/poll, streaming quirks, deadline. - `tests/agent_sched.py`: `scheduler_tick` against a real sqlite vault. - Build for these tests: compile `src/llm/*.cpp src/agent/*.cpp tests/agent_*.cpp` with `-lcurl -lpthread` (see wiring doc). ## Not verified / gaps (honest list) - Tools needing FTS or other modules were only checked on argument validation paths: `search`, `record_search`, `graph_*`, `tags`, `recall`, `audit` search, `export_terminal_log`. - Port-backed tools (MCP, skills install/create, plexer, install, release, sysinfo, speak, listen, sandbox `box_*` paths, LaneBoard) are ported but no test drives a real implementation: the ports are fakes or unwired. - `RagStats`/`RetrievalEval` compile and follow the Python line by line but have no differential test (needs a real vault). - Interactive tty paths (`ask_approval` console branch with `Denied` guidance, `shell_ask` getpass) are unexercised. - urllib error strings are approximated from libcurl codes (`` etc.). - Muse session map/locking and CLI runners (`muse_run`, grok, claude, codex, gemini, opencode) are ported; only their output parsers are differentially tested, the process runners were not run against the real CLIs. - `zipfile`: bzip2/lzma members unsupported. - `str.lower` final-sigma uses derived property sets; `repr` printable test is approximated for exotic code points.