Documentation
¶
Overview ¶
Package history defines provider-neutral conversation history contracts and model middleware.
Reader, Writer, Clearer, and Store use core/chat protocol values directly. WindowStore is an explicit read-side retention decorator. It merges system messages and retains only complete user-led turns, so assistant Tool calls, Tool results, reasoning, and final text cannot be split at the read boundary. Optional cross-conversation and replacement capabilities remain separate interfaces. The reference implementation lives in core/history/inmemory.
Conversation IDs are runtime scope carried with WithConversationID, not serialized request metadata. Middleware binds that scope to model calls.
Writes preserve message order within one call. Conversation listing is an optional capability and returns unique IDs in lexical order. Concurrent writes and writes through distinct Store instances have no common ordering guarantee unless a backend documents one. Writer returns WriteOutcome even on failure; errors never silently mean that no messages were stored. A CommitError identifies history failure after model completion and preserves the attempted messages and write outcome.
The Host owns conversation turn ordering. Concurrent-safe store methods do not isolate the whole Read/model/Write sequence; multi-instance hosts must coordinate that sequence across instances if they require serial turns.
Persistent backends live in independent leaf modules so database drivers do not enter Core:
historystores/postgres/ — PostgreSQL (pgx + JSONB) historystores/redis/ — Redis (RPUSH / LRANGE lists) historystores/mongodb/ — MongoDB (document per message) historystores/cassandra/ — Cassandra (TIMEUUID clustering key) historystores/neo4j/ — Neo4j (node per message) historystores/cosmosdb/ — Azure Cosmos DB (NoSQL API)
Every backend reads and writes only the current core/chat tagged JSON wire.
Example ¶
package main
import (
"fmt"
"github.com/Tangerg/scope/core/history"
)
func main() {
conversationID, err := history.NewConversationID("customer-42")
if err != nil {
panic(err)
}
fmt.Println(conversationID)
}
Output: customer-42
Index ¶
- Variables
- func WithConversationID(ctx context.Context, conversationID ConversationID) context.Context
- type Clearer
- type CommitError
- type ConversationID
- type Lister
- type Middleware
- type ReadWriter
- type Reader
- type Sequence
- type Store
- type WindowStore
- func (w WindowStore) Clear(ctx context.Context, conversationID ConversationID) error
- func (w WindowStore) Read(ctx context.Context, conversationID ConversationID) ([]chat.Message, error)
- func (w WindowStore) Write(ctx context.Context, conversationID ConversationID, messages ...chat.Message) (WriteOutcome, error)
- type WriteOutcome
- type Writer
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ( ErrInvalidWindow = errors.New("history: invalid message window") ErrWindowTooSmall = errors.New("history: message window too small") )
var ErrInvalidConversationID = errors.New("history: invalid conversation ID")
var ErrInvalidWriteOutcome = errors.New("history: invalid write outcome")
var ErrNilStore = errors.New("history: nil store")
var ErrNilStream = errors.New("history: middleware: nil stream sequence")
Functions ¶
func WithConversationID ¶
func WithConversationID(ctx context.Context, conversationID ConversationID) context.Context
WithConversationID returns a child context carrying the history partition key for one model call. An empty ID deliberately shadows and disables an ID inherited from a parent context. As with context.WithValue, ctx must not be nil.
Types ¶
type Clearer ¶
type Clearer interface {
// Clear removes the complete conversation and is idempotent when it is
// already absent. Implementations must honor ctx.
Clear(ctx context.Context, conversationID ConversationID) error
}
type CommitError ¶ added in v0.20.0
type CommitError struct {
// contains filtered or unexported fields
}
CommitError means model generation completed but history persistence failed. It owns the exact batch submitted to Write, so recovery need not call the model again. Outcome governs whether a suffix is safe to submit: uncertain writes require reconciliation, and Accepted messages must not be appended again. During streaming this error can follow the terminal model delta.
func (*CommitError) ConversationID ¶ added in v0.20.0
func (c *CommitError) ConversationID() ConversationID
func (*CommitError) Error ¶ added in v0.20.0
func (c *CommitError) Error() string
func (*CommitError) Messages ¶ added in v0.20.0
func (c *CommitError) Messages() []chat.Message
Messages returns an independently owned copy of the complete attempted batch.
func (*CommitError) Outcome ¶ added in v0.20.0
func (c *CommitError) Outcome() WriteOutcome
func (*CommitError) Unwrap ¶ added in v0.20.0
func (c *CommitError) Unwrap() error
type ConversationID ¶
type ConversationID string
ConversationID identifies one history partition. Its zero value is invalid. Use NewConversationID when converting runtime input; string constants may be converted directly when the value is known at compile time.
func ConversationIDFromContext ¶
func ConversationIDFromContext(ctx context.Context) (ConversationID, bool)
ConversationIDFromContext returns the ID carried by ctx. Empty values behave as absent so middleware can transparently skip history for unbound calls.
func NewConversationID ¶
func NewConversationID(value string) (ConversationID, error)
func (ConversationID) String ¶
func (c ConversationID) String() string
func (ConversationID) Validate ¶
func (c ConversationID) Validate() error
type Lister ¶
type Lister interface {
// Conversations returns detached, unique identifiers in lexical order. An
// empty store yields a non-nil empty slice; concurrent writes may appear or
// not according to the backend's snapshot boundary.
Conversations(ctx context.Context) ([]ConversationID, error)
}
type Middleware ¶
type Middleware struct {
// contains filtered or unexported fields
}
Middleware replays and persists history around synchronous and streaming chat capabilities. It is immutable and as safe for concurrent use as its Store, but it does not serialize Read/model/Write turns of one conversation.
func NewMiddleware ¶
func NewMiddleware(store ReadWriter) (Middleware, error)
func (Middleware) Call ¶
func (m Middleware) Call(next chat.Model) chat.Model
Call is a chat.CallMiddleware. The response result is the canonical assistant message persisted to history.
func (Middleware) Stream ¶
func (m Middleware) Stream(next chat.Streamer) chat.Streamer
Stream is a chat.StreamMiddleware. History I/O remains lazy: no read occurs until the returned sequence is iterated. Fresh input and the accumulated assistant response are persisted only after natural, error-free completion.
type ReadWriter ¶
type Sequence ¶ added in v0.16.0
type Sequence struct {
// contains filtered or unexported fields
}
Sequence reserves contiguous, strictly increasing positions despite wall-clock regression or repeated instants. It never reissues a position through the same value; ordering across separate Store instances remains implementation-defined.
func NewSequence ¶ added in v0.16.0
NewSequence spaces positions by stride. Use one nanosecond unless the store needs a coarser unit, such as TIMEUUID's 100-nanosecond ticks.
type Store ¶
type Store interface {
ReadWriter
Clearer
}
type WindowStore ¶
type WindowStore struct {
// contains filtered or unexported fields
}
WindowStore projects reads to at most limit messages while preserving a merged system message followed by a suffix of complete conversation turns. A user message starts a turn; every following assistant and tool message remains in that turn until the next user message. Writes and clears pass through to the authoritative Store. Read returns ErrWindowTooSmall rather than splitting the newest complete turn, and the merged system message counts toward the configured limit.
func NewWindowStore ¶
func NewWindowStore(store Store, limit int) (WindowStore, error)
func (WindowStore) Clear ¶
func (w WindowStore) Clear(ctx context.Context, conversationID ConversationID) error
func (WindowStore) Read ¶
func (w WindowStore) Read(ctx context.Context, conversationID ConversationID) ([]chat.Message, error)
func (WindowStore) Write ¶
func (w WindowStore) Write(ctx context.Context, conversationID ConversationID, messages ...chat.Message) (WriteOutcome, error)
type WriteOutcome ¶ added in v0.20.0
WriteOutcome describes the acknowledged facts of one Write attempt. It never implies idempotency or rollback. The zero value confirms that nothing was written. Accepted counts the confirmed prefix in argument order. Uncertain means additional messages after that prefix may have been stored; the caller must reconcile them before retrying. Otherwise all remaining messages are confirmed unwritten. All messages may be accepted even if ancillary work fails.
func (WriteOutcome) ValidateFor ¶ added in v0.41.0
func (w WriteOutcome) ValidateFor(count int, err error) error
ValidateFor checks the outcome against the attempted batch size and error. Successful calls must acknowledge the full batch without uncertainty.
type Writer ¶
type Writer interface {
// Write validates and snapshots the full argument batch before appending it
// in argument order. The outcome must account for every acknowledged or
// uncertain effect even on error; validation failures return the zero outcome.
// A nil error acknowledges the complete batch.
Write(ctx context.Context, conversationID ConversationID, messages ...chat.Message) (WriteOutcome, error)
}
Writer leaves the relative order of concurrent calls, or of writes through separate Store instances, implementation-defined.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package inmemory provides the in-process reference history store.
|
Package inmemory provides the in-process reference history store. |
|
Package storetest provides reusable conformance checks for history stores.
|
Package storetest provides reusable conformance checks for history stores. |