Documentation
¶
Overview ¶
Package statestore provides conversation state persistence and management.
Index ¶
- Constants
- Variables
- type ConversationState
- type InMemoryIndex
- type IndexResult
- type LLMSummarizer
- type ListOptions
- type MemoryStore
- func (s *MemoryStore) AppendMessages(ctx context.Context, id string, messages []types.Message) error
- func (s *MemoryStore) Close()
- func (s *MemoryStore) Delete(ctx context.Context, id string) error
- func (s *MemoryStore) Fork(ctx context.Context, sourceID, newID string) error
- func (s *MemoryStore) Len() int
- func (s *MemoryStore) List(ctx context.Context, opts ListOptions) ([]string, error)
- func (s *MemoryStore) Load(ctx context.Context, id string) (*ConversationState, error)
- func (s *MemoryStore) LoadRecentMessages(ctx context.Context, id string, n int) ([]types.Message, error)
- func (s *MemoryStore) LoadSummaries(ctx context.Context, id string) ([]Summary, error)
- func (s *MemoryStore) MessageCount(ctx context.Context, id string) (int, error)
- func (s *MemoryStore) Save(ctx context.Context, state *ConversationState) error
- func (s *MemoryStore) SaveSummary(ctx context.Context, id string, summary Summary) error
- type MemoryStoreOption
- type MessageAppender
- type MessageIndex
- type MessageReader
- type RedisOption
- type RedisStore
- func (s *RedisStore) AppendMessages(ctx context.Context, id string, messages []types.Message) error
- func (s *RedisStore) Delete(ctx context.Context, id string) error
- func (s *RedisStore) Fork(ctx context.Context, sourceID, newID string) error
- func (s *RedisStore) List(ctx context.Context, opts ListOptions) ([]string, error)
- func (s *RedisStore) Load(ctx context.Context, id string) (*ConversationState, error)
- func (s *RedisStore) LoadRecentMessages(ctx context.Context, id string, n int) ([]types.Message, error)
- func (s *RedisStore) LoadSummaries(ctx context.Context, id string) ([]Summary, error)
- func (s *RedisStore) MessageCount(ctx context.Context, id string) (int, error)
- func (s *RedisStore) Save(ctx context.Context, state *ConversationState) error
- func (s *RedisStore) SaveSummary(ctx context.Context, id string, summary Summary) error
- type Store
- type Summarizer
- type Summary
- type SummaryAccessor
Constants ¶
const ( SortByCreatedAt = "created_at" SortByUpdatedAt = "updated_at" )
Sort field constants for ListOptions.SortBy.
Variables ¶
var ErrInvalidID = errors.New("invalid conversation ID")
ErrInvalidID is returned when an invalid conversation ID is provided.
var ErrInvalidState = errors.New("invalid conversation state")
ErrInvalidState is returned when a conversation state is invalid.
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).
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 ¶
func (s *MemoryStore) Load(ctx context.Context, id string) (*ConversationState, error)
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
LoadSummaries returns all summaries for the given conversation. Expired entries return nil.
func (*MemoryStore) MessageCount ¶ added in v1.3.1
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
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
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
LoadSummaries returns all summaries for the conversation.
func (*RedisStore) MessageCount ¶ added in v1.3.1
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
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.