Skip to content

Sessions

Sessions turn an Agent into an app interaction. They are responsible for history, persistence, transport behavior, and tool feedback loops.

Use direct agent.Run calls only when you are manually managing history. For normal applications, use sessions.

NeedUse
Simple API routeHTTPSession.RunSingleInteractionWithRequest
CLI or background jobHTTPSession.RunSingleInteraction
Token-by-token UI updatesRunStreamInteraction or SSE
Browser EventSourceRunSSEInteractionWithRequest
Full chat UI with tool approval/tracesAgentSession WebSocket
session := godantic.NewHTTPSession("conversation-1", &agent, store)
response, err := session.RunSingleInteraction(models.User_Message{
Role: "user",
Content: models.Content{Parts: []models.User_Part{{Text: "Hello"}}},
})

Most HTTP APIs receive models.Model_Request as JSON:

var request models.Model_Request
if err := c.ShouldBindJSON(&request); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
session := godantic.NewHTTPSession(c.Param("conversationID"), &agent, store)
response, err := session.RunSingleInteractionWithRequest(request)

Streaming returns model chunks as they arrive. Each chunk is a models.Model_Response with one or more parts.

stream, errs := session.RunStreamInteraction(userMessage)
for stream != nil || errs != nil {
select {
case chunk, ok := <-stream:
if !ok {
stream = nil
continue
}
for _, part := range chunk.Parts {
if part.Text != nil {
fmt.Print(*part.Text)
}
}
case err, ok := <-errs:
if ok && err != nil {
return err
}
errs = nil
}
}

SSE is a good fit for browser streaming when you do not need bidirectional WebSocket behavior.

type GinSSEWriter struct{ Context *gin.Context }
func (w *GinSSEWriter) WriteSSE(data string) error {
w.Context.SSEvent("message", data)
w.Context.Writer.Flush()
return nil
}
func (w *GinSSEWriter) WriteSSEError(err error) error {
w.Context.SSEvent("error", err.Error())
w.Context.Writer.Flush()
return nil
}
func (w *GinSSEWriter) Flush() { w.Context.Writer.Flush() }

Run with request cancellation:

err := session.RunSSEInteractionWithRequest(
request,
&GinSSEWriter{Context: c},
c.Request.Context(),
)

Use WebSockets when your frontend needs interactive behavior beyond one-way streaming.

WebSocket sessions support:

  • Model streaming.
  • Tool call and tool result messages.
  • Frontend action requests.
  • Execution trace events.
  • Optional memory injection.
  • Optional ElevenLabs TTS handling.
session := godantic.NewAgentSession(
sessionID,
userID,
conn,
&agent,
store,
memoryManager,
)
if traceStore != nil {
session.SetTraceStore(traceStore)
}
err := session.RunInteraction(request)

memoryManager can be nil. If you pass one, it must implement:

type MemoryManager interface {
AddMemory(content string, metadata map[string]interface{}) error
RetrieveMemories(queryText string, limit int) ([]string, error)
}

Use memory for cross-conversation facts or user preferences. Use the message store for the current conversation transcript.

WebSocket sessions can report high-level flow events through FlowLogger.

type FlowLogger interface {
LogUserMessage(sessionID string, text string)
LogAgentMessage(sessionID string, text string)
LogToolCall(sessionID string, toolName string, args map[string]interface{})
LogToolResult(sessionID string, toolName string, resultPreview string)
}

This is useful for debugging without logging every raw provider payload.

WebSocket sessions can return *godantic.AgentError.

if err := session.RunInteraction(request); err != nil {
if agentErr, ok := err.(*godantic.AgentError); ok {
if agentErr.Fatal {
return err // close connection
}
// report and continue
}
}

Fatal errors mean the connection/session should end. Non-fatal errors can be surfaced to the user while keeping the session alive.

GotchaFix
Duplicate messagesDo not save the same user message outside the session unless you own the full loop.
Missing historyUse the same conversation/session ID for the same thread.
Streaming never endsAlways handle both stream and error channel closure.
Client disconnects keep work runningPass request contexts into SSE methods.
WebSocket writes raceUse the provided WebSocketWriter; it serializes writes.