history

package
v0.1.7 Latest Latest
Warning

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

Go to latest
Published: Jul 16, 2026 License: MIT Imports: 29 Imported by: 0

Documentation

Overview

Package history manages conversation transcripts: append messages, load them back fitted to a model's context window, and (optionally) compact older turns into hierarchical summaries to keep that window finite. Long-term fact recall lives in sdk/recall.

Layering

  • History is the strategy interface returned by NewBuffer and NewCompacted. Pick Buffer for short sessions or tests; pick Compacted when a conversation needs to outgrow a single context window.
  • Coordinator is the lifecycle + maintenance interface that the compacted History additionally satisfies. It exposes Compact / Archive / Shutdown and serializes them per conversation against History.Append and the background ingest/archive worker.
  • Store is the persistence interface. The package ships InMemoryStore and NewFileStore; bring your own for Redis, Postgres, etc.
  • SummaryDAG / FileSummaryStore are the building blocks behind compacted's hierarchical summarization. Most callers do not touch them directly.

Lifecycle

NewBuffer returns a stateless History; nothing to drain. The History returned by NewCompacted owns one serial worker goroutine per conversation plus a startup archive-recovery goroutine. Callers that own its lifetime should type-assert to Coordinator and call Shutdown(ctx) on shutdown so the queues drain cleanly:

hist := history.NewCompacted(store, llm, ws)
if coord, ok := hist.(history.Coordinator); ok {
    defer func() {
        ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
        defer cancel()
        _ = coord.Shutdown(ctx)
    }()
}

Tools

Two graph tools surface this package to LLMs: history_expand fetches the verbatim messages behind a summary node, history_compact triggers a manual compaction. The in-tree tool wrappers (taking a Coordinator for per-conversation serialization) live in an adapter package outside sdk; this package exposes only the underlying primitives.

v0.3.0 surface

The v0.3 surface narrows on the History / Coordinator interfaces. The following v0.2 entry points were removed in v0.3.0:

  • Closer / compactor.Close — replaced by Coordinator.Shutdown (context-aware, refuses late writes).
  • Top-level RecoverArchive, SaveManifest helpers — folded into the internal recoverArchiveImpl/saveManifestImpl helpers exercised by Coordinator. The exported Archive, LoadManifest and LoadArchivedMessages survive for adapter packages that need direct archive access; Coordinator auto-recovers in-flight archives at construction.
  • SummaryCacheStore — superseded by SummaryStore which the DAG already consumes.
  • In-package ToolDeps / RegisterTools — moved out of sdk into the adapter layer.

Naming history

This package was renamed from sdk/memory in v0.2.0. The previous Save(fullHistory) method was replaced by Append(newOnly) — the old signature was lossy under concurrent writers (read-modify-write race) and silently accepted truncated histories. There is no compat shim; call sites pass only the freshly produced messages.

Index

Constants

This section is empty.

Variables

View Source
var ErrClosed = errors.New("history: coordinator closed")

ErrClosed is returned by Coordinator.Shutdown's downstream operations (Append, Compact, Archive) once Shutdown has been initiated. Callers observing this should treat the History as drained and avoid further writes; reading via Load remains valid as long as the underlying Store is still usable.

Functions

func ApplyLoadOptions

func ApplyLoadOptions(msgs []model.Message, opts LoadOptions) []model.Message

ApplyLoadOptions filters msgs in memory according to opts. It is the reference implementation reused by both the in-memory fallback in LoadFiltered and any FilterableHistory implementation that prefers to do its own Load and then defer filtering to the shared helper.

The returned slice is a fresh allocation; the input slice is not mutated. msgs[i] are NOT cloned — IncludeTools=false strips tool-bearing Parts via model.Message.Clone only on the messages that actually carry them, so callers can rely on the returned slice being safe to retain.

func BuildSummaryIndex

func BuildSummaryIndex(ctx context.Context, store SummaryStore, convID string, budget int) string

BuildSummaryIndex generates a summary index string from the top-level summaries of a conversation. The result is intended to be injected into the LLM system prompt via the workflow.VarSummaryIndex board variable.

Returns an empty string when no summaries exist or the store is nil. The budget parameter controls the maximum character length of the output; older summaries are omitted (with a note) when the budget is exceeded.

func ConversationIDFrom

func ConversationIDFrom(ctx context.Context) string

ConversationIDFrom retrieves the conversation ID from the context.

func LoadArchivedMessages

func LoadArchivedMessages(ctx context.Context, ws workspace.Workspace, prefix, archivePrefix, convID string, startSeq, endSeq int) ([]model.Message, error)

LoadArchivedMessages reads messages from gzip archive segments. It powers history_expand's cold-segment path; callers outside the history package should obtain archived turns via the history_expand tool wrapper, not by reading archive files directly.

func LoadFiltered

func LoadFiltered(ctx context.Context, h History, conversationID string, opts LoadOptions) ([]model.Message, error)

LoadFiltered returns the messages selected by opts. If h satisfies FilterableHistory the call is delegated to it; otherwise this helper performs a plain h.Load(ctx, conversationID, opts.Budget) and applies the filters in memory.

LoadFiltered is the recommended entry point for callers that need post-Load filtering: it picks the most efficient path automatically and shields callers from the FilterableHistory type assertion.

func NewSummaryNodeID

func NewSummaryNodeID() string

NewSummaryNodeID generates a unique ID for a summary node.

func WithConversationID

func WithConversationID(ctx context.Context, id string) context.Context

WithConversationID injects the conversation ID into the context.

Types

type ArchiveConfig

type ArchiveConfig struct {
	ArchiveThreshold int
	ArchiveBatchSize int
	ArchivePrefix    string
}

ArchiveConfig controls message archiving behavior.

type ArchiveManifest

type ArchiveManifest struct {
	Segments    []ArchiveSegment `json:"segments"`
	HotStartSeq int              `json:"hot_start_seq"`
}

ArchiveManifest tracks archived message segments.

func LoadManifest

func LoadManifest(ctx context.Context, ws workspace.Workspace, prefix, archivePrefix, convID string) (*ArchiveManifest, error)

LoadManifest reads the archive manifest for a conversation.

type ArchiveResult

type ArchiveResult struct {
	MessagesArchived int    `json:"messages_archived"`
	ArchiveFile      string `json:"archive_file,omitempty"`
	HotStartSeq      int    `json:"hot_start_seq"`
}

ArchiveResult holds the result of an archive operation.

func Archive

func Archive(ctx context.Context, ws workspace.Workspace, store Store, prefix, convID string, cfg ArchiveConfig) (ArchiveResult, error)

Archive moves old messages to gzip-compressed archive files. The Coordinator drives it through its per-conversation worker queue; LLM tools (history_compact in particular) call it directly when the caller has not wired a Coordinator.

Crash recovery is handled by recoverArchiveImpl, which the Coordinator runs lazily on first contact with a conversation. Callers that own a History from NewCompacted should always reach archive through Coordinator.Archive to inherit the per-conversation serialization that protects against racing Append/trim sequences.

type ArchiveSegment

type ArchiveSegment struct {
	File      string    `json:"file"`
	StartSeq  int       `json:"start_seq"`
	EndSeq    int       `json:"end_seq"`
	Count     int       `json:"count"`
	CreatedAt time.Time `json:"created_at"`
}

ArchiveSegment describes a single archived file.

type Budget

type Budget struct {
	// MaxTokens caps the estimated token count of returned messages.
	// Implementations that do not track tokens treat this as a hint.
	MaxTokens int
	// MaxMessages caps the raw message count.
	MaxMessages int
}

Budget caps how much transcript History.Load returns. Zero means "use the implementation default"; set either field to clamp.

func (Budget) IsZero

func (b Budget) IsZero() bool

IsZero reports whether b carries no explicit limits.

type BufferOption

type BufferOption func(*buffer)

BufferOption customizes a History built by NewBuffer.

func WithBufferMax

func WithBufferMax(n int) BufferOption

WithBufferMax sets the maximum message count kept in the returned History. Must be > 0; values ≤ 0 are ignored and the default (50) is kept.

type CompactConfig

type CompactConfig struct {
	CompactThreshold int
	PruneLeafContent bool
	RequireParent    bool
}

CompactConfig controls the compact behavior.

type CompactOption

type CompactOption func(*compactOptions)

CompactOption customizes a History built by NewCompacted.

Compaction knobs (chunk size, recent ratio, leaf pruning, archive threshold, …) used to live in a dedicated Config struct; they are now functional options so adding a new knob does not break every caller passing a struct literal.

func WithArchiveBatchSize

func WithArchiveBatchSize(n int) CompactOption

WithArchiveBatchSize sets how many messages move per archive run.

func WithArchiveThreshold

func WithArchiveThreshold(n int) CompactOption

WithArchiveThreshold sets the hot-message count that triggers archival of the oldest batch to cold storage.

func WithChunkSize

func WithChunkSize(n int) CompactOption

WithChunkSize sets how many messages feed into each leaf summary.

func WithCompactThreshold

func WithCompactThreshold(n int) CompactOption

WithCompactThreshold triggers compaction once the hot message count crosses this number.

func WithCondenseThreshold

func WithCondenseThreshold(n int) CompactOption

WithCondenseThreshold sets the sibling-count that triggers a depth+1 condensation.

func WithDAGConfig

func WithDAGConfig(cfg DAGConfig) CompactOption

WithDAGConfig overrides the entire DAGConfig used by the DAG summarizer. Individual knobs below compose on top of a default config; use this when you need to set many at once or inherit from a DefaultDAGConfig.

func WithLeafPrune

func WithLeafPrune(b bool) CompactOption

WithLeafPrune turns on/off deleting the leaf content after its summary is absorbed into a parent node.

func WithMaxDepth

func WithMaxDepth(n int) CompactOption

WithMaxDepth caps the summary tree height.

func WithRecentRatio

func WithRecentRatio(r float64) CompactOption

WithRecentRatio splits the token budget between "recent verbatim messages" and "older summaries".

func WithStoragePrefix

func WithStoragePrefix(p string) CompactOption

WithStoragePrefix sets the workspace prefix for summary/archive files. Default "memory" for backwards compatibility with files written by prior builds.

func WithTokenBudget

func WithTokenBudget(n int) CompactOption

WithTokenBudget caps the assembled context size in estimated tokens.

func WithTokenCounter

func WithTokenCounter(c TokenCounter) CompactOption

WithTokenCounter swaps the TokenCounter used during assembly. Defaults to EstimateCounter.

type CompactResult

type CompactResult struct {
	DeletedRemoved int `json:"deleted_removed"`
	LeafPruned     int `json:"leaf_pruned"`
	TotalRemaining int `json:"total_remaining"`
}

CompactResult holds the result of a compact operation.

type Coordinator

type Coordinator interface {
	// Compact runs DAG compact for one conversation. Serialized against
	// concurrent Append/Archive on the same conversationID.
	Compact(ctx context.Context, conversationID string) (CompactResult, error)
	// Archive runs message archiving for one conversation. Serialized
	// against concurrent Append/Compact on the same conversationID.
	Archive(ctx context.Context, conversationID string) (ArchiveResult, error)
	// Shutdown stops accepting new work and waits for in-flight per-
	// conversation queues to drain. After Shutdown is observed,
	// Append/Compact/Archive return [ErrClosed]; subsequent Shutdown
	// calls block on the same drain and return its result.
	//
	// Shutdown is the canonical "S3" semantics: it does NOT cancel the
	// background workers when ctx expires. A ctx-deadline return value
	// signals "drain in progress, partial work may still finalize after
	// this returns"; the Coordinator stays in the closing/closed state
	// regardless. To observe the eventual drain after a deadline-bounded
	// Shutdown, call Shutdown again with a longer (or unbounded) ctx —
	// the second call falls onto the same drain and returns nil once
	// all workers have exited.
	Shutdown(ctx context.Context) error
}

Coordinator is the lifecycle + maintenance interface that the History returned by NewCompacted additionally satisfies. All maintenance operations (compact, archive, shutdown) are serialized per conversation alongside History.Append, so callers no longer need to coordinate locks themselves.

Production callers typically grab it once at construction:

hist := history.NewCompacted(store, llm, ws)
coord, _ := hist.(history.Coordinator)
defer func() { _ = coord.Shutdown(context.Background()) }()

Coordinator offers context-aware shutdown plus first-class maintenance entry points (Compact / Archive) that internally share the per-conversation queue used by background ingest/archive.

type DAGConfig

type DAGConfig struct {
	ChunkSize         int
	CondenseThreshold int
	CondenseGroupSize int
	MaxDepth          int
	TokenBudget       int
	RecentRatio       float64
	MidRatio          float64
	Compact           CompactConfig
	Archive           ArchiveConfig
}

DAGConfig controls the summary DAG behavior.

func DefaultDAGConfig

func DefaultDAGConfig() DAGConfig

DefaultDAGConfig returns a DAGConfig with sensible defaults.

type EstimateCounter

type EstimateCounter struct{}

EstimateCounter uses a heuristic: ~4 ASCII chars/token, ~1.5 CJK chars/token.

func (*EstimateCounter) Count

func (c *EstimateCounter) Count(text string) int

func (*EstimateCounter) CountMessages

func (c *EstimateCounter) CountMessages(msgs []model.Message) int

type FileStore

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

FileStore is a Workspace-backed Store that persists messages as JSONL files. Each conversation is stored at {prefix}/{conversationID}/messages.jsonl with one JSON-encoded model.Message per line. Saves are incremental.

func NewFileStore

func NewFileStore(ws workspace.Workspace, prefix string) *FileStore

NewFileStore creates a FileStore rooted at the given prefix directory within the workspace (e.g. "memory").

func (*FileStore) DeleteMessages

func (s *FileStore) DeleteMessages(ctx context.Context, conversationID string) error

func (*FileStore) GetMessageRange

func (s *FileStore) GetMessageRange(ctx context.Context, conversationID string, start, end int) ([]model.Message, error)

GetMessageRange returns messages in the range [start, end).

func (*FileStore) GetMessages

func (s *FileStore) GetMessages(ctx context.Context, conversationID string) ([]model.Message, error)

func (*FileStore) SaveMessages

func (s *FileStore) SaveMessages(ctx context.Context, conversationID string, messages []model.Message) error

type FileSummaryStore

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

FileSummaryStore is a Workspace-backed SummaryStore using JSONL files. It caches parsed nodes per conversation to avoid repeated disk reads.

The cache is bounded (LRU): the previous implementation grew the in-memory map for every conversation ever touched, which leaked memory in long-running services; here we evict the least-recently-used conversation when capacity is exceeded.

func NewFileSummaryStore

func NewFileSummaryStore(ws workspace.Workspace, prefix string, opts ...FileSummaryStoreOption) *FileSummaryStore

NewFileSummaryStore creates a FileSummaryStore rooted at the given prefix.

func (*FileSummaryStore) DeleteByConvID

func (s *FileSummaryStore) DeleteByConvID(ctx context.Context, convID, id string) error

func (*FileSummaryStore) GetByConvID

func (s *FileSummaryStore) GetByConvID(ctx context.Context, convID, id string) (*SummaryNode, error)

func (*FileSummaryStore) List

func (s *FileSummaryStore) List(ctx context.Context, convID string, opts SummaryListOptions) ([]*SummaryNode, error)

func (*FileSummaryStore) ListAll

func (s *FileSummaryStore) ListAll(ctx context.Context, convID string) ([]*SummaryNode, error)

func (*FileSummaryStore) Rewrite

func (s *FileSummaryStore) Rewrite(ctx context.Context, convID string, nodes []*SummaryNode) error

func (*FileSummaryStore) Save

func (s *FileSummaryStore) Save(ctx context.Context, node *SummaryNode) error

func (*FileSummaryStore) Search

func (s *FileSummaryStore) Search(ctx context.Context, convID, query string, topK int) ([]*SummaryNode, error)

type FileSummaryStoreOption

type FileSummaryStoreOption func(*FileSummaryStore)

FileSummaryStoreOption configures a FileSummaryStore.

func WithSummaryStoreCapacity

func WithSummaryStoreCapacity(n int) FileSummaryStoreOption

WithSummaryStoreCapacity overrides the default LRU cache capacity. A value <= 0 leaves the default in place.

type FilterableHistory

type FilterableHistory interface {
	History
	// LoadFiltered returns messages for the next inspection / display
	// the same way [History.Load] does, additionally honouring
	// LoadOptions. Implementations MAY apply filters lazily (push down
	// to the store) or eagerly (call Load + filter); both are correct
	// as long as the result respects LoadOptions semantics documented
	// above.
	LoadFiltered(ctx context.Context, conversationID string, opts LoadOptions) ([]model.Message, error)
}

FilterableHistory is the optional sub-interface that History implementations can satisfy to honour LoadOptions efficiently. For example, a store-backed History may push role filtering down to the database instead of materialising the whole conversation.

History implementations that do NOT satisfy FilterableHistory still work with LoadFiltered: the helper falls back to a plain Load and applies the filters in memory. This keeps adding the new entry point non-breaking for downstream code that built its own History.

type History

type History interface {
	// Load returns messages suited for the next LLM call. Implementations
	// MAY compress, summarize, or window the underlying transcript.
	//
	// budget is a hint; implementations fall back to their configured
	// defaults when the corresponding [Budget] field is zero. A fully
	// zero Budget explicitly means "use defaults" and is the most
	// common value (the common case: "give me whatever you'd send to
	// the model").
	Load(ctx context.Context, conversationID string, budget Budget) ([]model.Message, error)

	// Append durably persists newMessages — and only newMessages — to the
	// conversation. It MUST be safe to call from multiple goroutines for
	// the same conversationID; implementations serialize per-conversation
	// writes internally. After Append returns nil, the messages are
	// guaranteed visible to subsequent Load calls.
	Append(ctx context.Context, conversationID string, newMessages []model.Message) error

	// Clear removes the conversation and any derived state (summaries,
	// archives) owned by this History implementation.
	Clear(ctx context.Context, conversationID string) error
}

History is the strategy-layer interface that decides which messages to return to the LLM and how new turns are persisted. See the package doc comment for the per-method contract.

func NewBuffer

func NewBuffer(store Store, opts ...BufferOption) History

NewBuffer returns a History that keeps the most recent messages for each conversation up to a cap (default 50; override with WithBufferMax).

It is the simplest History implementation — appends concatenate, loads truncate. Use it for short sessions, tests, and examples; switch to NewCompacted when a conversation needs to outgrow a single context window.

func NewCompacted

func NewCompacted(store Store, l llm.LLM, ws workspace.Workspace, opts ...CompactOption) History

NewCompacted returns a History that keeps the full transcript but summarizes older turns through a DAG to stay within a token budget. Requires both an LLM (for summarization) and a workspace.Workspace (for summary + archive persistence).

This is the recommended default for any agent that holds multi-session conversations; use NewBuffer for short or single-turn interactions.

type InMemoryStore

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

InMemoryStore is a simple in-memory message store for development and testing. It supports a maximum conversation count and TTL-based eviction.

func NewInMemoryStore

func NewInMemoryStore(opts ...InMemoryStoreOption) *InMemoryStore

NewInMemoryStore creates a new in-memory message store with optional limits.

func (*InMemoryStore) AppendMessages

func (s *InMemoryStore) AppendMessages(_ context.Context, conversationID string, messages []model.Message) error

AppendMessages implements MessageAppender atomically under s.mu so concurrent same-conversation Append calls cannot read-modify- write each other's batches. The pre-fix path (no MessageAppender implementation here) forced callers into a manual GetMessages+SaveMessages loop where the two sides were unlocked between calls — issue #154's documented failure mode.

Same eviction rules as [SaveMessages]: a new conversation that pushes len(s.data) past maxConversations triggers LRU eviction.

func (*InMemoryStore) Close

func (s *InMemoryStore) Close()

Close stops the background cleanup goroutine.

func (*InMemoryStore) DeleteMessages

func (s *InMemoryStore) DeleteMessages(_ context.Context, conversationID string) error

func (*InMemoryStore) GetMessages

func (s *InMemoryStore) GetMessages(_ context.Context, conversationID string) ([]model.Message, error)

func (*InMemoryStore) Len

func (s *InMemoryStore) Len() int

Len returns the number of stored conversations (useful for testing/monitoring).

func (*InMemoryStore) SaveMessages

func (s *InMemoryStore) SaveMessages(_ context.Context, conversationID string, messages []model.Message) error

type InMemoryStoreOption

type InMemoryStoreOption func(*InMemoryStore)

InMemoryStoreOption configures an InMemoryStore.

func WithMaxConversations

func WithMaxConversations(n int) InMemoryStoreOption

WithMaxConversations sets the upper bound on stored conversations. When exceeded, the least-recently-accessed conversation is evicted.

func WithTTL

WithTTL sets how long an idle conversation is kept before eviction.

type LoadOptions

type LoadOptions struct {
	Budget       Budget
	Roles        []model.Role
	SinceSeq     int
	LimitN       int
	IncludeTools bool
}

LoadOptions filters the messages returned by LoadFiltered / a FilterableHistory implementation. Zero values mean "no filter on this dimension" — the empty LoadOptions is identical to a plain Load with Budget==zero.

LoadOptions is the moderation-friendly counterpart to Budget: where Budget caps how much transcript reaches the LLM, LoadOptions shapes which slice of the transcript is read for inspection, debugging, audit views, or selective replay.

Filter semantics are evaluated AFTER the underlying History strategy returns its working set:

  • Budget: forwarded to the underlying Load. Implementations apply compaction / windowing the same way they always do.
  • Roles: if non-empty, only messages whose Role is in the set are kept. The empty set means "all roles".
  • SinceSeq: 0-based message sequence index. Messages at index < SinceSeq are dropped. SinceSeq is a position cutoff because model.Message does not carry a wall-clock timestamp; callers wanting a time cutoff should look up the sequence index in their own audit log first. SinceSeq is applied against the position in the slice returned by Load (i.e. AFTER compaction), so it is stable for callers that always pass the same Budget. Negative values are treated as 0.
  • LimitN: caps the number of messages returned AFTER role + SinceSeq filtering. 0 means "no cap"; the most recent LimitN surviving messages are kept (tail-biased to match the typical "show me the last N user/assistant turns" use case).
  • IncludeTools: when false (the default), strips tool-call / tool-result parts as well as RoleTool messages from the result. This matches the common moderation case where reviewers want the human-readable conversation only. When true, tool messages and tool-call parts are preserved verbatim.

Filters compose: callers can mix Roles + LimitN to e.g. "give me the last 20 assistant messages". The empty LoadOptions is a no-op and returns whatever the underlying Load produces.

func (LoadOptions) IsZero

func (opts LoadOptions) IsZero() bool

IsZero reports whether opts carries no explicit filters and is equivalent to a plain Load with the zero Budget.

type MessageAppender

type MessageAppender interface {
	AppendMessages(ctx context.Context, conversationID string, messages []model.Message) error
}

MessageAppender is an optional interface for stores that can append only the newly generated messages without reloading the full history.

type RangeReader

type RangeReader interface {
	GetMessageRange(ctx context.Context, conversationID string, start, end int) ([]model.Message, error)
}

RangeReader is an optional interface for stores that support reading a subset of messages by sequence range.

type RecentReader

type RecentReader interface {
	GetRecentMessages(ctx context.Context, conversationID string, limit int) ([]model.Message, error)
}

RecentReader is an optional interface for stores that can efficiently read only the most recent N messages for a conversation.

type Store

type Store interface {
	GetMessages(ctx context.Context, conversationID string) ([]model.Message, error)
	SaveMessages(ctx context.Context, conversationID string, messages []model.Message) error
	DeleteMessages(ctx context.Context, conversationID string) error
}

Store is the persistence-layer interface for short-term message storage.

type SummaryDAG

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

SummaryDAG manages the multi-layer summary DAG for a conversation.

func NewSummaryDAG

func NewSummaryDAG(store SummaryStore, msgStore Store, l llm.LLM, cfg DAGConfig, counter TokenCounter) *SummaryDAG

NewSummaryDAG creates a new SummaryDAG.

func (*SummaryDAG) Assemble

func (d *SummaryDAG) Assemble(ctx context.Context, convID string, tokenBudget int) ([]llm.Message, error)

Assemble constructs the context window from summaries + recent messages.

func (*SummaryDAG) Compact

func (d *SummaryDAG) Compact(ctx context.Context, convID string) (CompactResult, error)

Compact removes deleted nodes and prunes leaf content.

func (*SummaryDAG) Ingest

func (d *SummaryDAG) Ingest(ctx context.Context, convID string, messages []llm.Message, startSeq int) error

Ingest processes new messages and generates leaf summaries.

type SummaryListOptions

type SummaryListOptions struct {
	Depth  *int
	MinSeq int
	MaxSeq int
	Limit  int
}

SummaryListOptions controls List filtering.

type SummaryNode

type SummaryNode struct {
	ID             string    `json:"id"`
	ConversationID string    `json:"conversation_id"`
	Depth          int       `json:"depth"`
	Content        string    `json:"content"`
	ExpandHint     string    `json:"expand_hint,omitempty"`
	SourceIDs      []string  `json:"source_ids,omitempty"`
	EarliestSeq    int       `json:"earliest_seq"`
	LatestSeq      int       `json:"latest_seq"`
	TokenCount     int       `json:"token_count"`
	CreatedAt      time.Time `json:"created_at"`
	Deleted        bool      `json:"deleted,omitempty"`
}

SummaryNode represents a node in the summary DAG.

type SummaryStore

type SummaryStore interface {
	Save(ctx context.Context, node *SummaryNode) error
	GetByConvID(ctx context.Context, convID, id string) (*SummaryNode, error)
	List(ctx context.Context, convID string, opts SummaryListOptions) ([]*SummaryNode, error)
	Search(ctx context.Context, convID, query string, topK int) ([]*SummaryNode, error)
	DeleteByConvID(ctx context.Context, convID, id string) error
	ListAll(ctx context.Context, convID string) ([]*SummaryNode, error)
	Rewrite(ctx context.Context, convID string, nodes []*SummaryNode) error
}

SummaryStore persists and retrieves summary DAG nodes. All operations are scoped by conversation ID.

type TiktokenCounter

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

TiktokenCounter uses tiktoken-go for precise BPE token counting.

func NewTiktokenCounter

func NewTiktokenCounter(model string) (*TiktokenCounter, error)

NewTiktokenCounter creates a TiktokenCounter for the given model name (e.g. "gpt-4o", "gpt-4", "gpt-3.5-turbo"). Falls back to cl100k_base encoding if the model is not recognized.

func NewTiktokenCounterFromEncoding

func NewTiktokenCounterFromEncoding(encoding string) (*TiktokenCounter, error)

NewTiktokenCounterFromEncoding creates a TiktokenCounter for a specific encoding name (e.g. "cl100k_base", "o200k_base").

func (*TiktokenCounter) Count

func (c *TiktokenCounter) Count(text string) int

func (*TiktokenCounter) CountMessages

func (c *TiktokenCounter) CountMessages(msgs []model.Message) int

type TokenCounter

type TokenCounter interface {
	Count(text string) int
	CountMessages(msgs []model.Message) int
}

TokenCounter estimates or calculates the token count for text and messages.

Jump to

Keyboard shortcuts

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