Expand description
A minimal built-in mock LLM for the observe-to-validate E2E suite.
Hidden mode: agentd --internal-mock-llm <addr-file> [script].
Binds a loopback TCP listener on 127.0.0.1:0 and writes the bound
host:port into <addr-file> atomically, via tmp-plus-rename, so the
launching harness can discover the endpoint by waiting for the file to
appear and is never able to read a half-written address. The harness then
hands agentd --intelligence http://<addr>; loopback plaintext is the
dev/test carve-out, since production intelligence is HTTPS-only.
Speaks just enough OpenAI-compatible /chat/completions over that listener
to drive a real agentic loop without a live model: it reads the request and
returns a scripted assistant turn — a final answer or a tool call — switching
to a final answer once a tool result appears in the transcript, so the ReAct
cycle closes instead of spinning. Scripts: final (answer at once), read
(call resource.read then answer), schedule (call the schedule self-tool
then answer), subscribe (call the subscribe self-tool then answer),
spawn-churn (call subagent.spawn on every turn, never converging, so a
run issues a rapid burst of spawns and trips the spawn-rate limiter);
slow/hang hold the response to exercise the stuck/deadline detectors.
Small enough to ship, and it makes the loop and the self-* tools observable
end to end.
Programmable scripts: file:<path> loads a JSON playbook, so a test can
script any conversation without adding a new built-in:
{ "turns": [ {"tool_calls": [{"name": "memory.set", "arguments": {"key": "k", "value": 1}}]},
{"content": "done", "usage": {"prompt_tokens": 100, "completion_tokens": 20}} ],
"match": [ {"when_contains": "\"preflight\"", "content": "{\"intent\":\"task\"}"} ] }match[] rules are tried first (the first whose when_contains substring
appears in the request body answers); otherwise turns[i] answers where i
is the number of role: tool messages already in the transcript (clamped to
the last turn). A turn carries content (final text) or tool_calls, an
optional usage, and an optional delay_ms.
Functions§
- inprocess
- Start the mock IN-PROCESS and return its loopback address. This backs the
intelligence.endpoints: mock:<script>convenience, so a config runs fully offline in ONE process: no key, no network, no second terminal. At most one server is started per distinct script string and the address is memoised, so repeated resolves of the same script share a listener instead of leaking a thread per call. Scripts are the same as the hidden mode’s (final|read|schedule|file:<playbook.json>). - run
- Serve the mock LLM until the process is killed, announcing the bound
loopback address through
addr_file. Returns the exit code.