Functions
AgentRuntime
Alias of ::rt/AgentRuntime
ChatOptions
Alias of ::ai-chat/ChatOptions
Identity
Alias of ::session/Identity
ReplyDelta
Alias of ::ai-chat/ReplyDelta
Session
Alias of ::session/Session
bool-default
fn (value: Bool?, fallback: Bool): Bool
Treat null as "unset" and return fallback; otherwise return
value as-is. Avoids or(false, true) returning true — or
treats false as falsy in Hot, so it's the wrong primitive for
boolean opts with true defaults.
build-system
fn (cfg: TurnConfig, input: TurnInput): Str
Compose the system prompt for this turn.
Calls ::ai::rag/build-context-safe against memory as it stood
before the current turn is persisted, then appends a heading +
context block to cfg.system-base via
::ai::rag/with-memory-block.
now-secs
fn (): Int
ns
Alias of ::ai::agent::chat-turn/
One-call wrapper around the "memory-grounded LLM reply" lifecycle.
Every memory-keyed chat agent we've written (PersonalAgent, TeamAgent, …) reimplements the same five-step turn:
- Build a memory-grounded system prompt (RAG over prior state).
- Persist the new user turn to session memory.
- Bind the per-request session/identity into ctx so tools recover them safely.
- Stream the LLM response token-by-token, forwarding
TextDeltas to the agent's reply stream so clients render live. - (Optionally) persist the assistant turn so the next call has it as context.
Step ordering is load-bearing. A common bug — call it "RAG self poisoning" — is doing step 2 before step 1, which makes the user's fresh message land in their own retrieval results and convinces the model that everything they say is already in memory.
run-chat-turn enforces the correct order. Concrete agents pass
config + per-turn input; the helper returns {ok, text} ready to be
used as the event-handler return value.
Offline / no-key handling
Callers can set fallback-text to short-circuit the LLM call and
emit a deterministic reply instead. Use this when probing for a
provider key and the probe came back empty (e.g.
is-empty(::hot::ctx/get('anthropic.api.key', ''))). The library
intentionally does not own the key probe — that's provider-specific
and likely to live in ::ai::chat/provider-available? in a future
iteration.
persist-assistant-turn
fn (cfg: TurnConfig, input: TurnInput, text: Str): Null
Persist an assistant turn so future RAG retrievals can see it.
The record's metadata always carries role: "assistant". Skipped
silently when text is empty.
persist-user-turn
fn (cfg: TurnConfig, input: TurnInput): Null
Persist a user turn into the session-keyed agent memory.
The record's metadata always carries role: "user", even when the
caller supplies user-metadata. This keeps the role tag symmetric
with assistant records and lets synthesis handlers filter by role
via ::ai::rag/recent-text (include-roles / exclude-roles).
Returns null. Errors during persistence are swallowed so a
transient store failure doesn't kill the reply.
reply-payload
fn (input: TurnInput): Map
Normalize {session_id, message_id} for stream emits.
run-chat-turn
fn (cfg: TurnConfig, input: TurnInput): Map
Execute one memory-grounded chat turn.
Enforces ordering:
- Build the system prompt from prior memory (no self-poisoning).
- Persist the user turn (default; opt out via
persist-user). - Bind the per-request ctx for tools (default; opt out via
bind-tool-ctx). - Stream the LLM reply OR emit
fallback-textif non-null. - Persist the assistant turn (default; opt out via
persist-assistant).
Returns {ok: true, text: <final-text>}. The handler can return
this directly.
stream-llm
fn (cfg: TurnConfig, payload: Map, system: Str, prompt: Str): Str
Run the configured LLM with token-level streaming forwarded to the
agent reply stream. Internal helper — run-chat-turn orchestrates.
user-body
fn (input: TurnInput): Str
Compose the text we persist for a user turn (raw text + attachment summary).
user-prompt
fn (input: TurnInput): Str
Compose the user prompt sent to the LLM (raw text + attachment block).
Types
TurnConfig
TurnConfig type {
rt: ::ai::agent::runtime/AgentRuntime,
agent-name: Str,
stream-label: Str,
chat-opts: ::ai::chat/ChatOptions,
system-base: Str
}
Per-handler configuration: identity + memory scope + LLM transport.
Shared across every turn the handler serves. Build it once near the top of the handler and reuse for each call.
TurnInput
TurnInput type {
session: ::ai::session/Session,
sender: ::ai::session/Identity,
text: Str,
attachments: Vec?,
payload: Map?,
recall-opts: Map?,
memory-heading: Str?,
persist-user: Bool?,
persist-assistant: Bool?,
bind-tool-ctx: Bool?,
ctx-extras: Map?,
user-source: Str?,
user-metadata: Map?,
assistant-source: Str?,
assistant-metadata: Map?,
fallback-text: Str?,
system-override: Str?
}
Per-turn input: who's talking, what they said, optional knobs.
session/sender— resolved by the handler from the event.text— the user's message, raw.attachments—Vec<Attachment>?, summarized into the persisted body and woven into the user prompt.payload—{session_id?, message_id?}, forwarded onto everyreply:start|delta|endevent so the UI can correlate.recall-opts— passed to::ai::rag/build-context-safe. Defaults to{limit: 5, min-score: 0.3}.memory-heading— heading text for the appended memory block. Defaults to "## Memory".persist-user/persist-assistant— default true. Set to false for dry runs or alternative storage strategies.bind-tool-ctx— default true. When set, calls::ai::agent::request/bind(session, sender, ctx-extras)so LLM tools registered at namespace top-level can recover the caller via::ai::agent::request/session/::ai::agent::request/sender.ctx-extras— additional fields stored underai.agent.extras.user-source/user-metadata— source field + metadata map for the persisted user record. Default source iscfg.agent-name.assistant-source/assistant-metadata— same for the assistant record.fallback-text— when non-null, the LLM is skipped and this string is emitted as the final reply (and optionally persisted). Use for offline fallbacks when no provider key is wired.system-override— when non-null, replaces the system prompt the orchestrator would otherwise build fromcfg.system-base+ RAG. Use for synthesis-style handlers (e.g./summary,/tasks) that hand the LLM a pre-baked prompt over a recency window rather than memory-grounded free chat.