Sessions, Runs & Memory
Three Layers: Session, Run, Transcript
Goa-AI separates conversation state into three layers:
Session (
SessionID) – a conversation or workflow over time:- e.g., a chat session, a remediation ticket, a research task.
- multiple runs can belong to the same session.
Run (
RunID) – one execution of an agent:- each call to an agent client (
Run/Start) creates a run, - runs have status, phases, and labels (see Runtime Concepts).
- each call to an agent client (
Transcript – the full history of messages and tool interactions for a run:
- represented as
[]*model.Message, - persisted via
memory.Storeas ordered memory events.
- represented as
You choose when to start a new run vs resume an existing one, but the identifiers always have these roles.
SessionID & TurnID in Practice
When calling an agent:
client := chat.NewClient(rt)
out, err := client.Run(ctx, messages,
runtime.WithSessionID("chat-session-123"), // required
runtime.WithTurnID("turn-1"), // optional but recommended for chat
)
SessionID:- groups all runs for a conversation,
- is often used as a search key in run stores and dashboards.
TurnID:- groups events for a single user → assistant interaction,
- is optional but helpful for UIs and logs.
The runtime records these in run.Context and run.Record; streaming and
memory subscribers can use them for correlation and indexing.
Memory Store vs Run Store vs Session Store
Goa-AI’s feature modules provide three complementary stores:
Memory store (
memory.Store)persists per-run event history:
- user/assistant messages,
- tool calls and results,
- planner notes and thinking.
API:
type Store interface { LoadRun(ctx context.Context, agentID, runID string) (memory.Snapshot, error) AppendEvents(ctx context.Context, agentID, runID string, events ...memory.Event) error }
Run store (
run.Store)persists coarse-grained run metadata:
RunID,AgentID,SessionID,TurnID,- status, timestamps, labels.
API:
type Store interface { Upsert(ctx context.Context, record run.Record) error Load(ctx context.Context, runID string) (run.Record, error) }
Session store (
session.Store) (in the runtime features)- tracks session-level metadata and search indexes where needed,
- typically used for cross-run views (e.g., list sessions, last activity).
For many applications, a combination of run store + memory store is enough; add a dedicated session store when you need richer session-level queries.
Common Patterns
Chat sessions:
- use one
SessionIDper chat session, - start a new run per user turn or per “task”,
- persist transcripts per run; use session metadata to stitch the conversation.
- use one
Long-running workflows:
- use a single run per logical workflow (potentially with pause/resume),
- use
SessionIDto group related workflows (e.g., per ticket or incident), - rely on
run.PhaseandRunCompletedevents for status tracking.
Search and dashboards:
- query
run.StorebySessionID, labels, status, - load transcripts from
memory.Storeon demand for selected runs.
- query
Wiring Stores
With the Mongo-backed implementations:
memStore, _ := memorymongo.NewStore(memorymongo.Options{Client: mongoClient})
runStore, _ := runmongo.NewStore(runmongo.Options{Client: mongoClient})
rt := runtime.New(
runtime.WithMemoryStore(memStore),
runtime.WithRunStore(runStore),
)
Once configured:
- default subscribers persist memory and run metadata automatically,
- you can rebuild transcripts from
memory.Storeat any time to:- re-call models,
- power UIs,
- or run offline analysis.