session

package
v1.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 31, 2026 License: MIT Imports: 16 Imported by: 0

Documentation

Overview

Package session — writelock.go implements file-based session write locks (REQ-460).

Before writing to a session JSONL file, an exclusive lock is acquired using atomic file creation (O_CREATE|O_EXCL). The lock file contains a JSON payload with PID, creation time, and process start time for stale detection.

Stale lock detection:

  • Dead PID (process not alive)
  • Recycled PID (process start time mismatch)
  • Age > maxLockAge (30 minutes)

A watchdog goroutine periodically reclaims over-held locks. Signal handlers release all locks on SIGINT/SIGTERM.

Index

Constants

This section is empty.

Variables

View Source
var ErrSessionNotFound = errors.New("session not found")

ErrSessionNotFound is returned when a session key does not match any active session.

Functions

func EstimateTokens

func EstimateTokens(msgs []Message) int

EstimateTokens exposes the token estimator for external callers (e.g. soft trim).

func ToOpenAI

func ToOpenAI(msgs []Message) []openai.ChatCompletionMessage

ToOpenAI converts Messages to the openai.ChatCompletionMessage format. Orphaned tool result messages (ToolCallID not matching any preceding assistant's ToolCalls) are silently dropped as a safety net; the primary cleanup happens in GetHistory which persists the fix.

Types

type Entry

type Entry struct {
	SessionID string `json:"sessionId"`
	UpdatedAt int64  `json:"updatedAt"` // unix ms
}

Entry tracks metadata for a session.

type LockManager

type LockManager struct {
	// contains filtered or unexported fields
}

LockManager manages file-based write locks with watchdog and cleanup.

func NewLockManager

func NewLockManager(logger *zap.SugaredLogger) *LockManager

NewLockManager creates a lock manager and starts the watchdog goroutine.

func (*LockManager) Acquire

func (lm *LockManager) Acquire(sessionPath string) (*WriteLock, error)

Acquire attempts to acquire a write lock for a session JSONL file. Returns a WriteLock that must be Released when done.

func (*LockManager) Release

func (lm *LockManager) Release(lock *WriteLock)

Release releases a specific lock and removes it from tracking.

func (*LockManager) ReleaseAll

func (lm *LockManager) ReleaseAll()

ReleaseAll releases all currently held locks (used on signal shutdown).

func (*LockManager) Stop

func (lm *LockManager) Stop()

Stop shuts down the watchdog and releases all held locks.

type LockPayload

type LockPayload struct {
	PID       int    `json:"pid"`
	CreatedAt string `json:"createdAt"` // ISO8601
	StartTime int64  `json:"starttime"` // process start time (jiffies or boot-relative)
}

LockPayload is stored in the lock file for stale detection.

type Manager

type Manager struct {
	// contains filtered or unexported fields
}

Manager handles session persistence.

func New

func New(logger *zap.SugaredLogger, dir string, ttl time.Duration) (*Manager, error)

New creates a session Manager. dir is the sessions directory (e.g. ~/.roger/agents/main/sessions).

func (*Manager) ActiveSessions

func (m *Manager) ActiveSessions() map[string]time.Time

ActiveSessions returns a snapshot of all active session keys and their last update time.

func (*Manager) AppendMessages

func (m *Manager) AppendMessages(key string, msgs []Message) error

AppendMessages adds messages to a session's history.

func (*Manager) Close added in v1.2.0

func (m *Manager) Close()

Close stops background goroutines (lock manager watchdog).

func (*Manager) FlushSave

func (m *Manager) FlushSave()

FlushSave forces an immediate write of sessions.json. Call on shutdown. Always writes regardless of dirty flag to ensure no data is lost.

func (*Manager) GetHistory

func (m *Manager) GetHistory(key string) ([]Message, error)

GetHistory returns the message history for a session key. Returns nil if the session is new or expired.

func (*Manager) Reap

func (m *Manager) Reap(maxAge time.Duration) (int, error)

Reap deletes JSONL files in the sessions directory that are older than maxAge and have no corresponding active session. Returns count of files removed.

func (*Manager) ReplaceHistory

func (m *Manager) ReplaceHistory(key string, msgs []Message) error

ReplaceHistory replaces the entire session JSONL with msgs. Returns nil if the session doesn't exist.

func (*Manager) Reset

func (m *Manager) Reset(key string)

Reset clears a session's history.

func (*Manager) ResetAll

func (m *Manager) ResetAll()

ResetAll clears all sessions.

func (*Manager) ResetIdle

func (m *Manager) ResetIdle(maxIdle time.Duration) int

ResetIdle resets sessions that have been idle longer than the given duration.

func (*Manager) SetPruning

func (m *Manager) SetPruning(p PruningPolicy)

SetPruning configures token-based context pruning.

func (*Manager) StartReapLoop

func (m *Manager) StartReapLoop(ctx context.Context, interval, maxAge time.Duration)

StartReapLoop runs Reap periodically in the background until ctx is cancelled.

func (*Manager) StartResetLoop

func (m *Manager) StartResetLoop(ctx context.Context, dailyMode string, atHour int, idleMinutes int, logFn func(string, ...any))

StartResetLoop starts background goroutines for daily and idle resets.

func (*Manager) Stop

func (m *Manager) Stop()

Stop shuts down the lock manager and flushes pending saves. Call on shutdown.

func (*Manager) TouchAPICall

func (m *Manager) TouchAPICall(key string)

TouchAPICall records the current time as the last API call for a session. When CacheTTL > 0 in the pruning policy, pruning is deferred until the TTL after this timestamp expires, preserving the provider's prompt cache.

func (*Manager) TrimMessages

func (m *Manager) TrimMessages(key string, maxMessages int) error

TrimMessages caps a session's history to the last maxMessages entries. No-op if maxMessages <= 0, session doesn't exist, or history is already within the limit.

type Message

type Message struct {
	Role       string            `json:"role"`
	Content    string            `json:"content,omitempty"`
	ImageURLs  []string          `json:"image_urls,omitempty"` // base64 data URLs or HTTP URLs for vision
	ToolCalls  []openai.ToolCall `json:"tool_calls,omitempty"`
	ToolCallID string            `json:"tool_call_id,omitempty"`
	Name       string            `json:"name,omitempty"`
	TS         int64             `json:"ts"`
}

Message is a single conversation entry stored in JSONL.

func FromOpenAI

func FromOpenAI(msgs []openai.ChatCompletionMessage) []Message

FromOpenAI converts openai messages to session Messages.

func PruneToolResults

func PruneToolResults(msgs []Message, keepRecent int) []Message

PruneToolResults performs surgical pruning: compresses old tool-result messages to short placeholders while preserving user and assistant messages. The last keepRecent assistant+tool sequences are left untouched so the model has recent tool context available.

This keeps the conversation flow intact (user questions and assistant reasoning) while reclaiming the majority of tokens — tool results are typically 80%+ of a long session's token budget.

func SanitizeOrphans

func SanitizeOrphans(msgs []Message) ([]Message, int)

SanitizeOrphans removes tool result messages whose ToolCallID doesn't match any preceding assistant message's ToolCalls. Returns the cleaned slice and the number of messages removed.

type PruningPolicy

type PruningPolicy struct {
	HardClearRatio     float64       // fraction of model max tokens to trigger clear (default 0.5)
	ModelMaxTokens     int           // model context window size (default 16384)
	KeepLastAssistants int           // assistant messages to keep after hard clear (default 2)
	SoftTrimRatio      float64       // fraction of model max tokens to trigger soft trim (default 0.0 = disabled)
	SurgicalPruning    bool          // when true, prefer trimming tool results before hard clear
	CacheTTL           time.Duration // prompt-cache lifetime to respect before pruning (default 0 = prune immediately)
}

PruningPolicy holds token-based context pruning parameters.

type WriteLock

type WriteLock struct {
	// contains filtered or unexported fields
}

WriteLock represents an acquired file lock.

func (*WriteLock) Release

func (l *WriteLock) Release() error

Release removes the lock file.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL