A GenServer that owns one agent's conversation and drives its agentic
loop: send the context to the model, execute any tool calls it asks for,
feed the results back, and repeat until the model produces a final
answer (or :max_turns is hit).
Each session is a process, so many independent coding-agent
conversations can run concurrently under CodingAgent.SessionSupervisor.
The read/write/edit tools never touch the real filesystem -- they
operate on an in-memory map of path => content that lives for the
duration of the session. send_message/3 returns that map alongside the
reply so the caller decides what to do with it (write it to disk, diff
it, send it elsewhere, discard it, ...).
Summary
Functions
Returns a specification to start this module under a supervisor.
Returns the full conversation context so far.
Returns the session's current in-memory workspace (path => content).
Sends a user message and runs the agent loop to completion.
Starts a session.
Starts a session under CodingAgent.SessionSupervisor, registered under
id in CodingAgent.SessionRegistry so it can be reached as
{:via, Registry, {CodingAgent.SessionRegistry, id}}.
Sends a user message and runs the agent loop to completion, just like
send_message/3, but streams text as the model produces it.
Functions
Returns a specification to start this module under a supervisor.
See Supervisor.
@spec context(GenServer.server()) :: ReqLLM.Context.t()
Returns the full conversation context so far.
@spec files(GenServer.server()) :: %{required(String.t()) => String.t()}
Returns the session's current in-memory workspace (path => content).
@spec send_message(GenServer.server(), String.t(), timeout()) :: {:ok, String.t(), %{required(String.t()) => String.t()}} | {:error, term()}
Sends a user message and runs the agent loop to completion.
Returns {:ok, reply_text, files}, where files is the session's
in-memory workspace (a path => content map) after every tool call from
this turn has been applied.
@spec start_link(keyword()) :: GenServer.on_start()
Starts a session.
Options:
:model- areq_llmmodel id, e.g."openrouter:anthropic/claude-sonnet-4.5"(defaults toCodingAgent.OpenRouter.default_model/0):system_prompt- extra system prompt text; the skill catalog (if any) is appended automatically:skills_dirs- list of directories to scan forSKILL.mdfiles:tools- list ofReqLLM.Toolstructs (defaults toCodingAgent.Tools.defaults/1built from the discovered skills):max_turns- safety cap on tool-call round-trips (default10):files- initial in-memory workspace as apath => contentmap, seeded before theread/write/edittools see it (default%{}):name- optional GenServer name, e.g.{:via, Registry, ...}- any other option is forwarded to
ReqLLM.generate_text/3(e.g.:temperature,:max_tokens)
Starts a session under CodingAgent.SessionSupervisor, registered under
id in CodingAgent.SessionRegistry so it can be reached as
{:via, Registry, {CodingAgent.SessionRegistry, id}}.
@spec stream_message(GenServer.server(), String.t(), (String.t() -> any()), timeout()) :: {:ok, String.t(), %{required(String.t()) => String.t()}} | {:error, term()}
Sends a user message and runs the agent loop to completion, just like
send_message/3, but streams text as the model produces it.
on_chunk is called with each text chunk (a String.t()) as it arrives,
across every turn of the loop -- including turns that precede a tool
call. It runs inside the session's own process, so it blocks the session
for the duration of the call; this mirrors send_message/3, which
already processes a whole turn synchronously.
Returns the same {:ok, reply_text, files} / {:error, reason} shape as
send_message/3 once the whole turn (including any tool round-trips)
has finished.
@spec via(term()) :: GenServer.server()