statestore

package
v1.3.5 Latest Latest
Warning

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

Go to latest
Published: Mar 1, 2026 License: Apache-2.0 Imports: 12 Imported by: 5

Documentation

Overview

Package statestore provides conversation state persistence and management.

Index

Constants

View Source
const (
	SortByCreatedAt = "created_at"
	SortByUpdatedAt = "updated_at"
)

Sort field constants for ListOptions.SortBy.

Variables

View Source
var ErrInvalidID = errors.New("invalid conversation ID")

ErrInvalidID is returned when an invalid conversation ID is provided.

View Source
var ErrInvalidState = errors.New("invalid conversation state")

ErrInvalidState is returned when a conversation state is invalid.

View Source
var ErrNotFound = errors.New("conversation not found")

ErrNotFound is returned when a conversation doesn't exist in the store.

Functions

This section is empty.

Types

type ConversationState

type ConversationState struct {
	ID             string                 // Unique conversation identifier
	UserID         string                 // User who owns this conversation
	Messages       []types.Message        // Message history (using unified types.Message)
	SystemPrompt   string                 // System prompt for this conversation
	Summaries      []Summary              // Compressed summaries of old turns
	TokenCount     int                    // Total tokens in messages
	LastAccessedAt time.Time              // Last time conversation was accessed
	Metadata       map[string]interface{} // Arbitrary metadata (e.g., extracted context)
}

ConversationState represents stored conversation state in the state store. This is the primary data structure for persisting and loading conversation history.

type InMemoryIndex added in v1.3.1

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

InMemoryIndex provides an in-memory implementation of MessageIndex using brute-force cosine similarity search. Suitable for development, testing, and conversations with up to ~10K messages.

func NewInMemoryIndex added in v1.3.1

func NewInMemoryIndex(provider providers.EmbeddingProvider) *InMemoryIndex

NewInMemoryIndex creates a new in-memory message index.

func (*InMemoryIndex) Delete added in v1.3.1

func (idx *InMemoryIndex) Delete(_ context.Context, conversationID string) error

Delete removes all indexed messages for a conversation.

func (*InMemoryIndex) Index added in v1.3.1

func (idx *InMemoryIndex) Index(
	ctx context.Context, conversationID string, turnIndex int, message types.Message,
) error

Index adds a message to the search index by computing its embedding.

func (*InMemoryIndex) Search added in v1.3.1

func (idx *InMemoryIndex) Search(ctx context.Context, conversationID, query string, k int) ([]IndexResult, error)

Search finds the top-k messages most relevant to the query string.

type IndexResult added in v1.3.1

type IndexResult struct {
	// TurnIndex is the position of the message in the conversation history.
	TurnIndex int

	// Message is the full message content.
	Message types.Message

	// Score is the relevance score (higher is more relevant, typically 0.0-1.0).
	Score float64
}

IndexResult represents a single search result from the message index.

type LLMSummarizer added in v1.3.1

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

LLMSummarizer uses an LLM provider to compress messages into summaries.

func NewLLMSummarizer added in v1.3.1

func NewLLMSummarizer(provider providers.Provider) *LLMSummarizer

NewLLMSummarizer creates a new LLM-based summarizer. A cheaper/faster model is recommended (e.g., GPT-3.5, Claude Haiku).

func (*LLMSummarizer) Summarize added in v1.3.1

func (s *LLMSummarizer) Summarize(ctx context.Context, messages []types.Message) (string, error)

Summarize compresses the given messages into a concise summary.

type ListOptions

type ListOptions struct {
	// UserID filters conversations by the user who owns them.
	// If empty, all conversations are returned (subject to pagination).
	UserID string

	// Limit is the maximum number of conversation IDs to return.
	// If 0, a default limit (e.g., 100) should be applied.
	Limit int

	// Offset is the number of conversations to skip (for pagination).
	Offset int

	// SortBy specifies the field to sort by (e.g., "created_at", "updated_at").
	// If empty, implementation-specific default sorting is used.
	SortBy string

	// SortOrder specifies sort direction: "asc" or "desc".
	// If empty, defaults to "desc" (newest first).
	SortOrder string
}

ListOptions provides filtering and pagination options for listing conversations.

type MemoryStore

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

MemoryStore provides an in-memory implementation of the Store interface. It is thread-safe and suitable for development, testing, and single-instance deployments. For distributed systems, use RedisStore or a database-backed implementation.

func NewMemoryStore

func NewMemoryStore(opts ...MemoryStoreOption) *MemoryStore

NewMemoryStore creates a new in-memory state store. Options can be provided to configure TTL, max entries, and background eviction.

func (*MemoryStore) AppendMessages added in v1.3.1

func (s *MemoryStore) AppendMessages(ctx context.Context, id string, messages []types.Message) error

AppendMessages appends messages to the conversation's message history. If the entry is expired, it is treated as non-existent and a new state is created.

func (*MemoryStore) Close added in v1.3.2

func (s *MemoryStore) Close()

Close stops the background eviction goroutine, if running. It is safe to call Close multiple times.

func (*MemoryStore) Delete

func (s *MemoryStore) Delete(ctx context.Context, id string) error

Delete removes a conversation state by ID.

func (*MemoryStore) Fork added in v1.1.6

func (s *MemoryStore) Fork(ctx context.Context, sourceID, newID string) error

Fork creates a copy of an existing conversation state with a new ID.

func (*MemoryStore) Len added in v1.3.2

func (s *MemoryStore) Len() int

Len returns the number of entries currently in the store, including expired entries that have not yet been evicted. This is primarily useful for testing.

func (*MemoryStore) List

func (s *MemoryStore) List(ctx context.Context, opts ListOptions) ([]string, error)

List returns conversation IDs matching the given criteria. Expired entries are excluded from results.

func (*MemoryStore) Load

Load retrieves a conversation state by ID. Returns a deep copy to prevent external mutations. Expired entries are lazily evicted on access and return ErrNotFound.

func (*MemoryStore) LoadRecentMessages added in v1.3.1

func (s *MemoryStore) LoadRecentMessages(ctx context.Context, id string, n int) ([]types.Message, error)

LoadRecentMessages returns the last n messages for the given conversation. Expired entries return ErrNotFound.

func (*MemoryStore) LoadSummaries added in v1.3.1

func (s *MemoryStore) LoadSummaries(ctx context.Context, id string) ([]Summary, error)

LoadSummaries returns all summaries for the given conversation. Expired entries return nil.

func (*MemoryStore) MessageCount added in v1.3.1

func (s *MemoryStore) MessageCount(ctx context.Context, id string) (int, error)

MessageCount returns the total number of messages in the conversation. Expired entries return ErrNotFound.

func (*MemoryStore) Save

func (s *MemoryStore) Save(ctx context.Context, state *ConversationState) error

Save persists a conversation state. If it already exists, it will be updated. When a max entries limit is set and the store is full, the least-recently-accessed entry is evicted to make room.

func (*MemoryStore) SaveSummary added in v1.3.1

func (s *MemoryStore) SaveSummary(ctx context.Context, id string, summary Summary) error

SaveSummary appends a summary to the conversation's summary list. Expired entries return ErrNotFound.

type MemoryStoreOption added in v1.3.2

type MemoryStoreOption func(*MemoryStore)

MemoryStoreOption configures optional behavior for MemoryStore.

func WithMemoryEvictionInterval added in v1.3.2

func WithMemoryEvictionInterval(d time.Duration) MemoryStoreOption

WithMemoryEvictionInterval sets the interval for the background cleanup goroutine that removes expired entries. If zero, no background cleanup runs and eviction happens only lazily on access. Requires a non-zero TTL to have any effect.

func WithMemoryMaxEntries added in v1.3.2

func WithMemoryMaxEntries(n int) MemoryStoreOption

WithMemoryMaxEntries sets the maximum number of entries the store will hold. When the limit is reached, the least-recently-accessed entry is evicted. A zero value means no limit (the default).

func WithMemoryTTL added in v1.3.2

func WithMemoryTTL(ttl time.Duration) MemoryStoreOption

WithMemoryTTL sets the time-to-live for conversation states. Entries that have not been accessed within the TTL are considered expired and eligible for eviction. A zero or negative TTL means entries never expire (the default).

type MessageAppender added in v1.3.1

type MessageAppender interface {
	// AppendMessages appends messages to the conversation's message history.
	// Creates the conversation if it doesn't exist.
	AppendMessages(ctx context.Context, id string, messages []types.Message) error
}

MessageAppender allows appending messages without a full load+replace+save cycle. This is an optional interface — stores that implement it enable incremental saves. Pipeline stages type-assert for this interface and fall back to Store.Save when unavailable.

type MessageIndex added in v1.3.1

type MessageIndex interface {
	// Index adds a message to the search index for the given conversation.
	// turnIndex is the position of the message in the conversation history.
	Index(ctx context.Context, conversationID string, turnIndex int, message types.Message) error

	// Search finds the top-k messages most relevant to the query string.
	// Results are ordered by descending relevance score.
	Search(ctx context.Context, conversationID string, query string, k int) ([]IndexResult, error)

	// Delete removes all indexed messages for a conversation.
	Delete(ctx context.Context, conversationID string) error
}

MessageIndex provides semantic search over conversation messages. Implementations can use embedding-based vector search or other similarity methods to find messages relevant to a given query.

type MessageReader added in v1.3.1

type MessageReader interface {
	// LoadRecentMessages returns the last n messages for the given conversation.
	// Returns ErrNotFound if the conversation doesn't exist.
	LoadRecentMessages(ctx context.Context, id string, n int) ([]types.Message, error)

	// MessageCount returns the total number of messages in the conversation.
	// Returns ErrNotFound if the conversation doesn't exist.
	MessageCount(ctx context.Context, id string) (int, error)
}

MessageReader allows loading a subset of messages without full state deserialization. This is an optional interface — stores that implement it enable efficient partial reads. Pipeline stages type-assert for this interface and fall back to Store.Load when unavailable.

type RedisOption

type RedisOption func(*RedisStore)

RedisOption configures a RedisStore.

func WithPrefix

func WithPrefix(prefix string) RedisOption

WithPrefix sets the key prefix for Redis keys. Default is "promptkit".

func WithTTL

func WithTTL(ttl time.Duration) RedisOption

WithTTL sets the time-to-live for conversation states. After this duration, conversations will be automatically deleted. Default is 24 hours. Set to 0 for no expiration.

type RedisStore

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

RedisStore provides a Redis-backed implementation of the Store interface. It uses JSON serialization for state storage and supports automatic TTL-based cleanup. This implementation is suitable for distributed systems and production deployments.

func NewRedisStore

func NewRedisStore(client *redis.Client, opts ...RedisOption) *RedisStore

NewRedisStore creates a new Redis-backed state store.

Example:

store := NewRedisStore(
    redis.NewClient(&redis.Options{Addr: "localhost:6379"}),
    WithTTL(24 * time.Hour),
    WithPrefix("myapp"),
)

func (*RedisStore) AppendMessages added in v1.3.1

func (s *RedisStore) AppendMessages(ctx context.Context, id string, messages []types.Message) error

AppendMessages appends messages to the conversation's message list using RPUSH. Uses Redis pipelining to batch the RPUSH, EXPIRE, and meta update in a single round-trip.

func (*RedisStore) Delete

func (s *RedisStore) Delete(ctx context.Context, id string) error

Delete removes a conversation state from Redis. Uses a pipeline to batch the DEL and optional user index cleanup.

func (*RedisStore) Fork added in v1.1.6

func (s *RedisStore) Fork(ctx context.Context, sourceID, newID string) error

Fork creates a copy of an existing conversation state with a new ID.

func (*RedisStore) List

func (s *RedisStore) List(ctx context.Context, opts ListOptions) ([]string, error)

List returns conversation IDs matching the given criteria.

func (*RedisStore) Load

func (s *RedisStore) Load(ctx context.Context, id string) (*ConversationState, error)

Load retrieves a conversation state by ID from Redis.

func (*RedisStore) LoadRecentMessages added in v1.3.1

func (s *RedisStore) LoadRecentMessages(ctx context.Context, id string, n int) ([]types.Message, error)

LoadRecentMessages returns the last n messages using LRANGE on the messages list. Falls back to loading from the monolithic key if the list doesn't exist.

func (*RedisStore) LoadSummaries added in v1.3.1

func (s *RedisStore) LoadSummaries(ctx context.Context, id string) ([]Summary, error)

LoadSummaries returns all summaries for the conversation.

func (*RedisStore) MessageCount added in v1.3.1

func (s *RedisStore) MessageCount(ctx context.Context, id string) (int, error)

MessageCount returns the total number of messages. Falls back to loading from the monolithic key if the list doesn't exist.

func (*RedisStore) Save

func (s *RedisStore) Save(ctx context.Context, state *ConversationState) error

Save persists a conversation state to Redis with TTL. Uses a pipeline to batch the SET and optional user index update into a single round-trip.

func (*RedisStore) SaveSummary added in v1.3.1

func (s *RedisStore) SaveSummary(ctx context.Context, id string, summary Summary) error

SaveSummary appends a summary to the conversation's summary list. Uses a pipeline to batch RPUSH and EXPIRE into a single round-trip.

type Store

type Store interface {
	// Load retrieves conversation state by ID
	Load(ctx context.Context, id string) (*ConversationState, error)

	// Save persists conversation state
	Save(ctx context.Context, state *ConversationState) error

	// Fork creates a copy of an existing conversation state with a new ID
	// The original conversation is left unchanged. Returns ErrNotFound if sourceID doesn't exist.
	Fork(ctx context.Context, sourceID, newID string) error
}

Store defines the interface for persistent conversation state storage.

type Summarizer added in v1.3.1

type Summarizer interface {
	// Summarize compresses the given messages into a concise summary.
	Summarize(ctx context.Context, messages []types.Message) (string, error)
}

Summarizer compresses a batch of messages into a summary string. Implementations may use LLM providers, extractive methods, or other compression strategies.

type Summary

type Summary struct {
	StartTurn  int       // First turn included in this summary
	EndTurn    int       // Last turn included in this summary
	Content    string    // Summarized content
	TokenCount int       // Token count of the summary
	CreatedAt  time.Time // When this summary was created
}

Summary represents a compressed version of conversation turns. Used to maintain context while reducing token count for older conversations.

type SummaryAccessor added in v1.3.1

type SummaryAccessor interface {
	// LoadSummaries returns all summaries for the given conversation.
	// Returns nil (not an error) if no summaries exist.
	LoadSummaries(ctx context.Context, id string) ([]Summary, error)

	// SaveSummary appends a summary to the conversation's summary list.
	SaveSummary(ctx context.Context, id string, summary Summary) error
}

SummaryAccessor allows reading and writing summaries independently of the full state. This is an optional interface for stores that support efficient summary operations.

Jump to

Keyboard shortcuts

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