Session
Session manages conversation context across synapse calls.
Constructor
func NewSession() *Session
Create a new empty session.
session := zyn.NewSession()
Read Methods
Messages
func (s *Session) Messages() []Message
Get all messages in the session.
messages := session.Messages()
for _, msg := range messages {
fmt.Printf("%s: %s\n", msg.Role, msg.Content)
}
Len
func (s *Session) Len() int
Get the number of messages.
count := session.Len()
At
func (s *Session) At(index int) (Message, error)
Get message at index. Returns error if out of bounds.
msg, err := session.At(0)
if err != nil {
// Index out of bounds
}
LastUsage
func (s *Session) LastUsage() *TokenUsage
Get token usage from the last successful call. Returns nil if no usage recorded.
if usage := session.LastUsage(); usage != nil {
fmt.Printf("Tokens: %d\n", usage.Total)
}
Write Methods
Append
func (s *Session) Append(role Role, content string)
Add a message to the end.
session.Append(zyn.RoleUser, "Hello")
session.Append(zyn.RoleAssistant, "Hi there!")
Clear
func (s *Session) Clear()
Remove all messages.
session.Clear()
Remove
func (s *Session) Remove(index int) error
Remove message at index. Returns error if out of bounds.
err := session.Remove(0)
Replace
func (s *Session) Replace(index int, msg Message) error
Replace message at index. Returns error if out of bounds.
err := session.Replace(0, zyn.Message{
Role: zyn.RoleUser,
Content: "Updated message",
})
Insert
func (s *Session) Insert(index int, msg Message) error
Insert message at index. Returns error if out of bounds.
err := session.Insert(0, zyn.Message{
Role: zyn.RoleSystem,
Content: "You are a helpful assistant",
})
Bulk Methods
Prune
func (s *Session) Prune(n int) error
Remove the last n message pairs (user + assistant). Each pair is 2 messages, so n=1 removes 2 messages. Returns error if n is negative.
err := session.Prune(2) // Remove last 2 exchanges (4 messages)
Truncate
func (s *Session) Truncate(keepFirst, keepLast int) error
Keep first keepFirst and last keepLast messages, remove middle.
err := session.Truncate(2, 2) // Keep first 2 and last 2
SetMessages
func (s *Session) SetMessages(messages []Message)
Replace entire message history.
session.SetMessages([]zyn.Message{
{Role: zyn.RoleUser, Content: "Summary of previous conversation"},
{Role: zyn.RoleAssistant, Content: "Acknowledged"},
})
SetUsage
func (s *Session) SetUsage(usage *TokenUsage)
Set token usage (typically called internally by synapses).
session.SetUsage(&zyn.TokenUsage{
Prompt: 100,
Completion: 50,
Total: 150,
})
Types
Message
type Message struct {
Role string // RoleUser, RoleAssistant, or RoleSystem
Content string
}
Role Constants
const (
RoleUser = "user"
RoleAssistant = "assistant"
RoleSystem = "system"
)
TokenUsage
type TokenUsage struct {
Prompt int
Completion int
Total int
}
Behavior
Transactional Updates
Synapses update sessions atomically:
session := zyn.NewSession()
initialLen := session.Len() // 0
_, err := synapse.Fire(ctx, session, "input")
if err != nil {
// Session unchanged on error
assert(session.Len() == initialLen)
} else {
// Session has user message + assistant response
assert(session.Len() == initialLen + 2)
}
Thread Safety
Sessions are safe for concurrent use by multiple goroutines. All methods are protected by a read-write mutex.
// ✅ OK: Concurrent access
go func() { synapse.Fire(ctx, session, "input1") }()
go func() { synapse.Fire(ctx, session, "input2") }()
// ✅ Also OK: Sequential access
synapse.Fire(ctx, session, "input1")
synapse.Fire(ctx, session, "input2")
// ✅ Also OK: Separate sessions for independent conversations
go func() { synapse.Fire(ctx, zyn.NewSession(), "input1") }()
go func() { synapse.Fire(ctx, zyn.NewSession(), "input2") }()
Note: While concurrent access is safe, the message ordering in concurrent scenarios depends on which goroutine completes first. For deterministic conversation flow, sequential access is recommended.