// Three-reaction LLM chat loop, plus an Init reaction that seeds the loop.
//
// The cycle TerminalPrompt -> LlmCall -> TerminalWrite -> TerminalPrompt is
// allowed by the verifier because every step crosses a builtin Effect actor
// that paces the loop on external I/O (user input, LLM HTTP, stdout flush).
//
// Default `provider: "mock"` echoes the prompt back. To use a real LLM:
//
// 1. Run whatever auth tool produces a token file. For Codex, use Codex
// CLI's login. For a manual paste: `thal login codex`.
// 2. Edit Init to emit an `LlmProvider` molecule alongside the
// `TerminalPrompt`, pointing at the token file and base URL.
// 3. Switch `OnUserInput`'s provider field to "codex".
// 4. Run `cargo run -- examples/chat.thal`.
//
// If you skip step 2 and use a non-mock provider, the runtime will prompt
// you for a token file path on first use and register the provider for you.
reaction OnUserInput {
when: TerminalPrompt(p)
where: p.status == "Done"
emit: LlmCall { provider: "codex", model: "gpt-5.3-codex", prompt: p.answer }
}
reaction StartThinking {
when: LlmCall(c)
where: c.status == "Pending"
emit: Spinner { label: "thinking…", running: true }
}
reaction OnLlmResponse {
when: LlmCall(c)
where: c.status == "Done"
emit:
Spinner { label: "", running: false },
TerminalWrite { content: c.text, markdown: true }
}
reaction OnPrintDone {
when: TerminalWrite(w)
where: w.status == "Done"
emit: TerminalPrompt { question: "❯ " }
}
reaction Init {
when: Boot(b)
emit:
TerminalPrompt { question: "❯ " }
}