Documentation
¶
Index ¶
- Variables
- func ConversationIDFromContext(ctx context.Context) string
- func MessageIDFromContext(ctx context.Context) string
- func NewChildConversation(ctx context.Context, hist History, parentID, title, visibility string) string
- type Attachment
- type Attachments
- type CombinedPolicy
- type ConversationMeta
- type EmbedFunc
- type ExecutionStore
- func (t *ExecutionStore) Add(ctx context.Context, convID string, trace *ExecutionTrace) (int, error)
- func (t *ExecutionStore) Get(ctx context.Context, convID string, traceID int) (*ExecutionTrace, error)
- func (t *ExecutionStore) List(ctx context.Context, convID string) ([]*ExecutionTrace, error)
- func (t *ExecutionStore) ListByParent(ctx context.Context, convID string, parentMsgID string) ([]*ExecutionTrace, error)
- func (t *ExecutionStore) ListOutcome(ctx context.Context, convID string, parentID string) ([]*plan.Outcome, error)
- func (t *ExecutionStore) Update(ctx context.Context, convID string, traceID int, fn func(*ExecutionTrace)) error
- type ExecutionTrace
- type History
- type HistoryStore
- func (h *HistoryStore) AddMessage(ctx context.Context, msg Message) error
- func (h *HistoryStore) Children(ctx context.Context, parentID string) ([]ConversationMeta, bool)
- func (h *HistoryStore) CreateMeta(ctx context.Context, id, parentID, title, visibility string)
- func (h *HistoryStore) Delete(ctx context.Context, convID string) error
- func (h *HistoryStore) EnsureConversation(convID string)
- func (h *HistoryStore) GetMessages(ctx context.Context, convID string) ([]Message, error)
- func (h *HistoryStore) LatestMessage(ctx context.Context) (*Message, error)
- func (h *HistoryStore) ListIDs(ctx context.Context) ([]string, error)
- func (h *HistoryStore) LookupMessage(ctx context.Context, messageID string) (*Message, error)
- func (h *HistoryStore) MessagesSince(ctx context.Context, convID string, sinceID string) ([]Message, error)
- func (h *HistoryStore) Meta(ctx context.Context, id string) (*ConversationMeta, bool)
- func (h *HistoryStore) Retrieve(ctx context.Context, convID string, policy Policy) ([]Message, error)
- func (h *HistoryStore) UpdateMessage(ctx context.Context, messageId string, mutate func(*Message)) error
- func (h *HistoryStore) UpdateMeta(ctx context.Context, id string, mutate func(*ConversationMeta)) bool
- type LastNPolicy
- type Message
- type NextTokenPolicy
- type Policy
- type PolicyApproval
- type RolePolicy
- type StageStore
- type SummarizerFunc
- type SummaryPolicy
- type TokenEstimatorFunc
- type UsageStore
- func (s *UsageStore) Add(convID, model string, prompt, completion, embed, cached int)
- func (s *UsageStore) Aggregator(convID string) *usage.Aggregator
- func (s *UsageStore) Conversations() []string
- func (s *UsageStore) OnUsage(convID, model string, u *llm.Usage)
- func (s *UsageStore) Totals(convID string) (prompt, completion, embed, cached int)
- type UserInteraction
- type VisibilityPolicy
Constants ¶
This section is empty.
Variables ¶
var ConversationIDKey = conversationID("conversationID")
var MessageIDKey = messageID("messageID")
Functions ¶
func MessageIDFromContext ¶
Types ¶
type Attachment ¶
type Attachment struct {
Name string `json:"name,omitempty" yaml:"name"`
URL string `json:"url,omitempty" yaml:"url"`
Size int64 `json:"size,omitempty" yaml:"size"` // bytes
// MediaType allows UI to decide how to display or download.
MediaType string `json:"mediaType,omitempty" yaml:"mediaType,omitempty"`
}
Attachment describes a file linked to the message.
type Attachments ¶
type Attachments []Attachment
type CombinedPolicy ¶
type CombinedPolicy struct {
Policies []Policy
}
CombinedPolicy composes multiple policies in order.
func NewCombinedPolicy ¶
func NewCombinedPolicy(policies ...Policy) *CombinedPolicy
NewCombinedPolicy creates a policy that applies all given policies sequentially.
type ConversationMeta ¶
type ConversationMeta struct {
ID string `json:"id"`
ParentID string `json:"parentId,omitempty"`
Title string `json:"title,omitempty"`
Visibility string `json:"visibility,omitempty"` // full|summary|none
CreatedAt time.Time `json:"createdAt"`
// Model stores the last LLM model explicitly chosen by the user within
// this conversation. When a subsequent turn omits the model override the
// orchestration can fall back to this value so that the user does not
// have to repeat the flag every time.
Model string `json:"model,omitempty"`
// Tools keeps the last explicit per-turn tool allow-list requested by the
// user. When a subsequent turn sends an empty tools slice, orchestration
// falls back to this stored list so the preference persists.
Tools []string `json:"tools,omitempty"`
// Agent records the last agent configuration reference (path or name)
// explicitly used in the conversation so that subsequent requests can
// omit the field and still continue the thread with the same agent.
Agent string `json:"agent,omitempty"`
// Context holds the latest accepted elicitation payload so that the user
// does not have to resend the same data every turn when the same agent
// schema still applies.
Context map[string]interface{} `json:"context,omitempty"`
}
ConversationMeta captures hierarchical metadata for a conversation. It is kept minimal so that additional fields can be added without breaking existing callers.
type EmbedFunc ¶
EmbedFunc defines a function that creates embeddings for given texts. It should return one embedding per input text.
type ExecutionStore ¶
type ExecutionStore struct {
// contains filtered or unexported fields
}
ExecutionStore is an in-memory registry of execution traces keyed by conversation ID.
func NewExecutionStore ¶
func NewExecutionStore() *ExecutionStore
NewExecutionStore returns an empty store.
func (*ExecutionStore) Add ¶
func (t *ExecutionStore) Add(ctx context.Context, convID string, trace *ExecutionTrace) (int, error)
Add appends a trace and assigns a sequential ID.
func (*ExecutionStore) Get ¶
func (t *ExecutionStore) Get(ctx context.Context, convID string, traceID int) (*ExecutionTrace, error)
Get returns a single execution trace by conversation ID and trace ID (1-based). A nil pointer is returned when not found.
func (*ExecutionStore) List ¶
func (t *ExecutionStore) List(ctx context.Context, convID string) ([]*ExecutionTrace, error)
List returns a copy of all traces for conversation.
func (*ExecutionStore) ListByParent ¶
func (t *ExecutionStore) ListByParent(ctx context.Context, convID string, parentMsgID string) ([]*ExecutionTrace, error)
ListByParent returns a subset of traces for the supplied conversation filtered by the ParentMsgID. A nil slice is returned when the conversation ID is unknown or no trace matches the filter. The returned slice is a shallow copy and can be modified by the caller without affecting the store.
func (*ExecutionStore) ListOutcome ¶
func (t *ExecutionStore) ListOutcome(ctx context.Context, convID string, parentID string) ([]*plan.Outcome, error)
ListOutcome groups traces by PlanID and converts them into plan.Outcome
func (*ExecutionStore) Update ¶
func (t *ExecutionStore) Update(ctx context.Context, convID string, traceID int, fn func(*ExecutionTrace)) error
Update applies an in-place mutation to a previously stored trace identified by conversation ID and trace ID. A no-op when the trace cannot be found.
type ExecutionTrace ¶
type ExecutionTrace struct {
// Auto-incremented per-conversation identifier.
ID int `json:"id" yaml:"id"`
// Parent assistant message ID that triggered this tool call.
ParentMsgID string `json:"parentId" yaml:"parentId"`
// Canonical service method, e.g. "file.count".
Name string `json:"name" yaml:"name"`
// Marshalled JSON argument object supplied to the tool.
Request json.RawMessage `json:"request" yaml:"request"`
// Whether the call succeeded.
Success bool `json:"success" yaml:"success"`
// Result (when Success==true) or nil.
Result json.RawMessage `json:"result,omitempty" yaml:"result,omitempty"`
// Error message when Success==false.
Error string `json:"error,omitempty" yaml:"error,omitempty"`
StartedAt time.Time `json:"startedAt" yaml:"startedAt"`
EndedAt time.Time `json:"endedAt" yaml:"endedAt"`
// Optional plan context – allows UI to tie tool invocation back to the
// generating plan step.
PlanID string `json:"planId,omitempty" yaml:"planId,omitempty"`
StepIndex int `json:"stepIndex,omitempty" yaml:"stepIndex,omitempty"`
Step *plan.Step `json:"step,omitempty" yaml:"step,omitempty"`
Plan *plan.Plan `json:"plan,omitempty" yaml:"plan,omitempty"`
// When the step requested additional user input, surface the elicitation so
// that callers can render an appropriate prompt.
Elicitation *plan.Elicitation `json:"elicitation,omitempty" yaml:"elicitation,omitempty"`
}
ExecutionTrace captures a single tool invocation (request + result) and optional execution-plan context. It is intended for auditing / UI inspection and is NOT sent back to the LLM as part of the conversation context.
type History ¶
type History interface {
AddMessage(ctx context.Context, msg Message) error
GetMessages(ctx context.Context, convID string) ([]Message, error)
Retrieve(ctx context.Context, convID string, policy Policy) ([]Message, error)
// UpdateMessage finds message by id within convID and applies mutator.
UpdateMessage(ctx context.Context, messageId string, mutate func(*Message)) error
// LookupMessage searches all conversations and returns the first message
LookupMessage(ctx context.Context, messageID string) (*Message, error)
LatestMessage(ctx context.Context) (msg *Message, err error)
// --- Conversation meta management ------------------------------
CreateMeta(ctx context.Context, id, parentID, title, visibility string)
Meta(ctx context.Context, id string) (*ConversationMeta, bool)
Children(ctx context.Context, parentID string) ([]ConversationMeta, bool)
}
History defines behaviour for conversation history storage.
type HistoryStore ¶
type HistoryStore struct {
// contains filtered or unexported fields
}
HistoryStore manages conversation messages by conversation ID.
func NewHistoryStore ¶
func NewHistoryStore() *HistoryStore
NewHistoryStore creates a new in-memory history store.
func (*HistoryStore) AddMessage ¶
func (h *HistoryStore) AddMessage(ctx context.Context, msg Message) error
AddMessage stores a message under the given conversation ID.
func (*HistoryStore) Children ¶
func (h *HistoryStore) Children(ctx context.Context, parentID string) ([]ConversationMeta, bool)
Children returns all direct children for parentID.
func (*HistoryStore) CreateMeta ¶
func (h *HistoryStore) CreateMeta(ctx context.Context, id, parentID, title, visibility string)
CreateMeta registers metadata for a conversation id. If meta already exists it is left unchanged.
func (*HistoryStore) Delete ¶
func (h *HistoryStore) Delete(ctx context.Context, convID string) error
Delete removes every message belonging to the supplied conversation ID.
func (*HistoryStore) EnsureConversation ¶
func (h *HistoryStore) EnsureConversation(convID string)
EnsureConversation makes sure a conversation key exists even if no messages have been added yet. It is safe to call concurrently and will not overwrite existing entries. The method is useful for adapters that need to create a conversation before the first user message arrives (e.g. when the UI offers a "new chat" button).
func (*HistoryStore) GetMessages ¶
GetMessages retrieves all messages for the conversation ID.
func (*HistoryStore) LatestMessage ¶
func (h *HistoryStore) LatestMessage(ctx context.Context) (*Message, error)
LatestMessage scans all conversations and returns the latest message encountered. For the simple in-memory store we assume messages are appended in chronological order, therefore the last conversation inspected with a matching message provides the overall latest. While not perfectly accurate in concurrent scenarios it is good enough for local/CLI usage.
func (*HistoryStore) ListIDs ¶
func (h *HistoryStore) ListIDs(ctx context.Context) ([]string, error)
ListIDs returns all conversation IDs currently stored.
func (*HistoryStore) LookupMessage ¶
LookupMessage implements History.LookupMessage by scanning all conversations for the first message whose ID matches messageID. As the in-memory store keeps each conversation in a simple slice, a linear scan is acceptable for local usage. The returned Message is a copy so callers cannot mutate the store inadvertently.
func (*HistoryStore) MessagesSince ¶
func (h *HistoryStore) MessagesSince(ctx context.Context, convID string, sinceID string) ([]Message, error)
MessagesSince returns the slice of messages beginning with the one whose ID matches sinceID (inclusive) followed by every subsequent message in chronological order. If sinceID is empty the full history is returned. When the supplied ID cannot be found the returned slice is empty and no error is raised so that callers can treat it identical to "not yet available".
func (*HistoryStore) Meta ¶
func (h *HistoryStore) Meta(ctx context.Context, id string) (*ConversationMeta, bool)
Meta fetches conversation meta by id.
func (*HistoryStore) Retrieve ¶
func (h *HistoryStore) Retrieve(ctx context.Context, convID string, policy Policy) ([]Message, error)
Retrieve returns messages filtered by the provided policy. If policy is nil, all messages are returned.
func (*HistoryStore) UpdateMessage ¶
func (h *HistoryStore) UpdateMessage(ctx context.Context, messageId string, mutate func(*Message)) error
UpdateMessage applies a mutator function to the message with the given ID across all conversations. If the message is not found the call is a no-op and returns nil so that callers do not have to care about races between polling and updates.
func (*HistoryStore) UpdateMeta ¶
func (h *HistoryStore) UpdateMeta(ctx context.Context, id string, mutate func(*ConversationMeta)) bool
UpdateMeta applies a mutator function to the ConversationMeta identified by id. If the entry does not yet exist it will be created first so that the mutator always receives a valid pointer. The method returns true when an entry existed or was created, false when id is empty.
type LastNPolicy ¶
type LastNPolicy struct {
N int
}
LastNPolicy keeps only the last N messages.
func NewLastNPolicy ¶
func NewLastNPolicy(n int) *LastNPolicy
NewLastNPolicy creates a policy that retains the last N messages.
type Message ¶
type Message struct {
ID string `json:"id"`
ConversationID string `json:"conversationId"`
ParentID string `json:"parentId,omitempty"`
Role string `json:"role"`
Actor string `json:"actor,omitempty" yaml:"actor,omitempty"`
Content string `json:"content"`
ToolName *string `json:"toolName,omitempty"` // Optional tool name, can be nil
// When messages include file uploads the Attachments slice describes each
// uploaded asset (or generated/downloadable asset on assistant side).
Attachments Attachments `json:"attachments,omitempty" yaml:"attachments,omitempty" sqlx:"-"`
Executions []*plan.Outcome `json:"executions,omitempty" yaml:"executions,omitempty" sqlx:"-"`
CreatedAt time.Time `json:"createdAt" yaml:"createdAt"`
// Elicitation carries a structured schema-driven prompt when the assistant
// needs additional user input. When non-nil the UI can render an
// interactive form instead of plain text. It is omitted for all other
// message kinds.
Elicitation *plan.Elicitation `json:"elicitation,omitempty" yaml:"elicitation,omitempty"`
// CallbackURL is set when the message requires a user action through a
// dedicated REST callback (e.g. MCP elicitation). Empty for normal chat
// messages.
CallbackURL string `json:"callbackURL,omitempty" yaml:"callbackURL,omitempty"`
// Status indicates the resolution state of interactive MCP prompts.
// "open" – waiting for user
// "done" – accepted and finished
// "declined" – user declined
Status string `json:"status,omitempty" yaml:"status,omitempty"`
// Interaction contains details for an MCP user-interaction request (e.g.
// "open the following URL and confirm when done"). When non-nil the UI
// should render an approval card with a link and Accept/Decline buttons.
Interaction *UserInteraction `json:"interaction,omitempty" yaml:"interaction,omitempty"`
// PolicyApproval is non-nil when the system requires explicit user
// approval before executing a potentially sensitive action (e.g. running
// an external tool). The UI should show the approval dialog when the
// message role == "policyapproval" and Status == "open".
PolicyApproval *PolicyApproval `json:"policyApproval,omitempty" yaml:"policyApproval,omitempty"`
}
Message represents a conversation message for memory storage.
type NextTokenPolicy ¶
type NextTokenPolicy struct {
Threshold int
Keep int
Summarizer SummarizerFunc
Estimator TokenEstimatorFunc
}
NextTokenPolicy triggers summarization if total estimated tokens exceed Threshold. It keeps the last Keep messages and replaces earlier ones with a summary.
func NewNextTokenPolicy ¶
func NewNextTokenPolicy(threshold, keep int, summarizer SummarizerFunc, estimator TokenEstimatorFunc) *NextTokenPolicy
NewNextTokenPolicy creates a policy that summarizes if tokens > threshold. If estimator is nil, a default estimator (len(Result)/4) is used.
type Policy ¶
type Policy interface {
// Apply processes messages, potentially invoking summarization, returning filtered messages or an error.
Apply(ctx context.Context, messages []Message) ([]Message, error)
}
Policy defines a filter over conversation messages. It may transform, filter, or summarize messages and return the set to include.
func OnlySummariesPolicy ¶
func OnlySummariesPolicy() Policy
OnlySummariesPolicy keeps only messages whose Status is "summary".
func SkipSummariesPolicy ¶
func SkipSummariesPolicy() Policy
SkipSummariesPolicy returns a Policy that removes messages flagged with Status=="summary" or "summarized".
type PolicyApproval ¶
type PolicyApproval struct {
Tool string `json:"tool" yaml:"tool"` // tool/function name such as "system.exec"
Args map[string]interface{} `json:"args,omitempty" yaml:"args,omitempty"` // flattened argument map
Reason string `json:"reason,omitempty" yaml:"reason,omitempty"`
}
PolicyApproval captures the details of an approval request that needs an explicit Accept/Reject decision by the user.
type RolePolicy ¶
type RolePolicy struct {
// contains filtered or unexported fields
}
RolePolicy includes only messages whose Role matches one of the allowed roles.
func NewRolePolicy ¶
func NewRolePolicy(roles ...string) *RolePolicy
NewRolePolicy creates a policy that retains messages with specified roles.
type StageStore ¶
type StageStore struct {
// contains filtered or unexported fields
}
StageStore keeps the latest Stage snapshot per conversation in memory. All operations are concurrency-safe.
type SummarizerFunc ¶
SummarizerFunc defines a function that summarizes a slice of messages. It should return a single Message containing the summary.
type SummaryPolicy ¶
type SummaryPolicy struct {
Threshold int
Summarizer SummarizerFunc
}
SummaryPolicy summarizes older messages when count exceeds Threshold. It replaces the earliest messages with a single summary Message.
func NewSummaryPolicy ¶
func NewSummaryPolicy(threshold int, summarizer SummarizerFunc) *SummaryPolicy
NewSummaryPolicy creates a policy that summarizes messages when count > threshold.
type TokenEstimatorFunc ¶
TokenEstimatorFunc estimates token count for a Message.
type UsageStore ¶
type UsageStore struct {
// contains filtered or unexported fields
}
UsageStore keeps token-usage statistics per conversation entirely in memory. It is a lightweight helper for tests and CLI use-cases where persisting to a database is overkill. All operations are concurrency-safe.
The layout mirrors the relational design:
– aggregated totals on conversation level (for quick summary) – one-to-many breakdown per model via usage.Aggregator.
The store purposefully exposes only additive updates – callers cannot decrease counts so that race conditions never lead to negative numbers.
func (*UsageStore) Add ¶
func (s *UsageStore) Add(convID, model string, prompt, completion, embed, cached int)
Add is a lower-level helper that directly increments the counters for convID / model. It is mainly intended for tests.
func (*UsageStore) Aggregator ¶
func (s *UsageStore) Aggregator(convID string) *usage.Aggregator
Aggregator returns the live aggregator for convID or nil when the conversation is unknown. The returned instance is concurrency-safe; callers should treat its contents as read-only.
func (*UsageStore) Conversations ¶
func (s *UsageStore) Conversations() []string
Conversations lists the IDs currently present in the store.
func (*UsageStore) OnUsage ¶
func (s *UsageStore) OnUsage(convID, model string, u *llm.Usage)
OnUsage updates the statistics for convID / model by applying the supplied llm.Usage delta (implements the provider/base.UsageListener contract at the store level).
func (*UsageStore) Totals ¶
func (s *UsageStore) Totals(convID string) (prompt, completion, embed, cached int)
Totals returns the rolled-up counts (prompt, completion, embedding) for the given conversation. When convID is unknown, all numbers are zero.
type UserInteraction ¶
type UserInteraction struct {
URL string `json:"url" yaml:"url"`
Description string `json:"description,omitempty" yaml:"description,omitempty"`
}
UserInteraction represents a structured prompt created via the MCP user-interaction feature.
type VisibilityPolicy ¶
type VisibilityPolicy struct {
Mode string
Summarizer SummarizerFunc
}
VisibilityPolicy filters or transforms a message slice according to the conversation visibility setting as defined by ConversationMeta.Visibility.
full – include all messages unchanged.
none – hide every message (empty slice).
summary – collapse the entire slice into a single synthetic summary
message produced by the supplied Summarizer function.
When Mode == "summary" the Summarizer callback must not be nil. All other modes ignore the field.
func NewVisibilityPolicy ¶
func NewVisibilityPolicy(mode string, summarizer SummarizerFunc) *VisibilityPolicy
NewVisibilityPolicy returns a VisibilityPolicy initialised with the supplied mode and summarizer. The mode string is compared case-insensitively. Callers may pass nil summarizer when mode != "summary".