Summary#
An agent is stateless by default. Each turn is answered on its own: nothing from the previous exchange is in scope unless a call names the conversation it belongs to. That is the right shape for an agent that classifies a document or answers one question.
A conversation is stored as a ChatSession with its turns as ChatMessage rows, and an agent asked a
follow-up can see what came before. Both entities ride Osyrin.Agents — the capability an agent declaration
already requires — so a conversation needs no second import.
using Osyrin.Agents;Signature#
using Osyrin.Agents;Two entities enter the app's model:
| entity | what it holds |
|---|---|
ChatSession | one conversation — which agent, its title, when it was last active, who it belongs to, and optionally the record it is about |
ChatMessage | one turn — a user message, an assistant reply, a tool call or a tool result, in Sequence order |
Description#
Conversations are part of what the agent surface is. They are not a second thing to import: a session and its
turns are what an agent that holds a conversation, parks for a human, or reports an outcome would otherwise
re-implement, so they ride Osyrin.Agents itself. Nothing about your agents changes to get them: the same agent
declaration, the same calls.
Which conversation, if any, is decided per call. A request that carries a conversationId continues that
conversation; one that does not starts a new one. An app whose agents only ever classify a document names no
conversation and its tables stay empty.
A conversation belongs to one user. It is stamped with the user who created it, listings return only that user's
conversations, and asking for someone else's by id answers 404 — the same answer as an id that does not exist, so
no one can probe for which conversations exist. Anonymous visitors own no conversations: an anonymous caller gets an
empty list, and creating one requires a signed-in user.
A long conversation is summarised rather than truncated. When the history outgrows the model's context window, earlier turns are replaced by a summary turn, so the beginning of the conversation is still represented instead of being dropped.
Entity context is optional. A conversation can record the record it is about — "ask the agent about this order" — so it can be listed alongside that record rather than in one undifferentiated pile.
Examples#
An app whose agent holds a conversation:
using Osyrin.Agents;
[Principal] entity User {
[MaxLength(255)] string Email;
}
entity Order {
[Required, MaxLength(50)] string Reference;
}A chat request that carries a conversationId continues that conversation; one that does not starts a new one.
See also#
- default LLM model (app.DefaultModel) — the model an agent talks to.