session

package
v0.36.1 Latest Latest
Warning

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

Go to latest
Published: Sep 14, 2026 License: MIT Imports: 6 Imported by: 0

Documentation

Index

Constants

View Source
const (
	DefaultSearchFetchTopK = 4
	DefaultSearchPageChars = 6000
)

Deep-research tuning defaults and bounds. Defaults mirror the pipeline's built-in constants; bounds keep user-entered values sane.

View Source
const (
	SearchProviderNative = "native"
	SearchProviderTavily = "tavily"
)

Search providers. Native is the built-in engine compiled into the binary; Tavily is a third-party API keyed by the user's own token. The value is stored as a string so future providers slot in without a schema change.

View Source
const MaskedAPIKey = "__SET__"

MaskedAPIKey is the sentinel the UI receives in place of a stored secret, and sends back unchanged to mean "keep the key you already have". Shared with the provider-config masking so both credential surfaces behave identically.

Variables

This section is empty.

Functions

func DeleteModelCacheSupport added in v0.26.1

func DeleteModelCacheSupport(database *db.DB, modelID string) error

DeleteModelCacheSupport clears a persisted verdict so the pair is observed again on next use. An empty modelID clears every verdict — the escape hatch for an endpoint that changed behaviour under a stable URL.

func DeleteModelCapability added in v0.6.0

func DeleteModelCapability(database *db.DB, modelID string) error

DeleteModelCapability clears a model's cached capability so it is re-probed on next use. An empty modelID clears every cached capability. Used by the manual-refresh path.

func DeleteModelPreference

func DeleteModelPreference(database *db.DB, id string) error

DeleteModelPreference removes a model preference from the database.

func FinishedNaturally added in v0.26.0

func FinishedNaturally(finish *string) bool

FinishedNaturally reports whether a finish reason means the model was done.

Only three are: the model saying it finished, and the user saying stop. Every other reason — none recorded at all, a request for tools that nothing ran, an error, the output cap — describes a turn that stopped without reaching an end, which is what makes it something to pick back up.

The default is deliberately "not finished". A finish reason this code has never seen is far more likely to be a provider spelling one of the failures its own way than a fourth kind of success, and the cost of the two mistakes is not symmetric: offering a resume that turns out to be unnecessary wastes a click, while withholding one strands the conversation.

func GetModelCacheSupport added in v0.26.1

func GetModelCacheSupport(database *db.DB, modelID, endpoint string) (string, bool, error)

GetModelCacheSupport returns the persisted cache verdict for a model on a specific endpoint. The second return value is false when the pair has not been resolved yet.

func LearnModelContextWindow added in v0.35.0

func LearnModelContextWindow(database *db.DB, modelID string, window int) error

LearnModelContextWindow records a context window discovered from a context-overflow error body, without disturbing whatever else is known about the model. Windows ≤ 0 (nothing parsed) are ignored. When no capability record exists yet, one is created carrying only the window — the image fields stay at their defaults until a probe writes them.

func Now

func Now() int64

func SetModelCacheSupport added in v0.26.1

func SetModelCacheSupport(database *db.DB, modelID, endpoint, verdict string, observedAt int64) error

SetModelCacheSupport records a resolved cache verdict so later sessions skip the observation window entirely.

func SetModelCapability added in v0.6.0

func SetModelCapability(database *db.DB, c *ModelCapability) error

SetModelCapability upserts a probed capability record for a model.

The upsert MERGES rather than replaces: supports_images and probed_at are taken from the incoming record (an image probe is authoritative each time it runs), but a learned context window survives a write that carries none — otherwise the image probe (which always writes ContextWindow 0) would erase a window the loop learned from an overflow error. Only an explicit positive ContextWindow in the incoming record overwrites the stored one.

func SetModelPreference

func SetModelPreference(database *db.DB, p *ModelPreference) error

SetModelPreference upserts a model preference into the database.

func SetProviderConfig added in v0.2.1

func SetProviderConfig(database *db.DB, c *ProviderConfig) error

SetProviderConfig upserts a provider config row.

func SetSearchConfig added in v0.8.0

func SetSearchConfig(database *db.DB, c *SearchConfig) error

SetSearchConfig upserts the singleton config row, clamping the research params before persisting so an invalid client payload can never store bad values.

Types

type Delivery added in v0.29.0

type Delivery struct {
	// DispatchedAt is when the StreamChat attempt that succeeded left for the
	// provider. Re-stamped on every attempt so that retry backoff, which can run
	// to seconds, never lands inside TTFTMs.
	DispatchedAt int64 `json:"dispatchedAt,omitempty"`
	// ConnectedAt is when the provider answered 200 and the stream opened. This
	// is the moment the request is known to have reached the model.
	ConnectedAt int64 `json:"connectedAt,omitempty"`
	// FirstTokenAt is when the first content event of any kind arrived — text,
	// reasoning or a tool call. Reasoning counts: on a thinking model it is what
	// arrives first, and waiting for text instead would report the whole
	// thinking phase as latency.
	FirstTokenAt int64 `json:"firstTokenAt,omitempty"`
	// TTFTMs is FirstTokenAt − DispatchedAt: time to first token, the model's
	// own queue and prefill, free of ogcode's prompt building and of backoff.
	TTFTMs int64 `json:"ttftMs,omitempty"`
	// QueuedMs is DispatchedAt − the prompt's CreatedAt: everything ogcode did
	// before the request left, which is prompt building, memory retrieval and
	// compaction. Kept apart from TTFTMs so a slow turn can be attributed.
	QueuedMs int64 `json:"queuedMs,omitempty"`
	// Attempts is how many StreamChat tries the connection took. Above 1 means
	// the stream was opened more than once before it held.
	Attempts int `json:"attempts,omitempty"`
	// FirstTokenKind is what opened the response: "text", "reasoning" or "tool".
	FirstTokenKind string `json:"firstTokenKind,omitempty"`
}

Delivery records how far a turn got on its way to the model, and how long the model took to say its first word.

It hangs off the assistant message rather than the prompt that caused it: the loop owns that record from the moment it creates it, and ParentID already points back at the prompt, so the pairing costs nothing. Only the first step of a turn can point at a human prompt — from step 2 on, the preceding user message is the tool-result message the loop wrote itself — so a client reading Delivery through ParentID never has to reason about steps.

type ImagePartData added in v0.14.0

type ImagePartData struct {
	MediaType string `json:"mediaType"`
	Data      string `json:"data"`
	Name      string `json:"name,omitempty"`
}

ImagePartData stores a user-uploaded image attachment. Data is base64-encoded image bytes; MediaType is e.g. "image/jpeg" or "image/png". The Name field carries the original filename (optional, for display only).

type InterruptReason added in v0.26.0

type InterruptReason string

InterruptReason classifies why a turn stopped short.

const (
	// InterruptRateLimit is a 429 or a provider quota, the case where waiting
	// is the whole fix. RetryAfter carries when waiting is over, where the
	// provider said.
	InterruptRateLimit InterruptReason = "rate_limit"
	// InterruptServerError is a 5xx or an overloaded provider.
	InterruptServerError InterruptReason = "server_error"
	// InterruptNetwork is a connection that dropped, timed out or was refused.
	InterruptNetwork InterruptReason = "network"
	// InterruptAuth is a rejected key, an expired token, an exhausted balance —
	// resumable, but only once a human has fixed the account behind it.
	InterruptAuth InterruptReason = "auth"
	// InterruptContext is a request too large for the model's window that
	// compaction could not bring back under it.
	InterruptContext InterruptReason = "context"
	// InterruptModelCapability is a 400 because the model lacks a capability the
	// request used (e.g. image input). Resumable: resume strips the offending
	// content and retries, or the user switches to a model that has the capability.
	InterruptModelCapability InterruptReason = "model_capability"
	// InterruptCrashed marks a turn found unfinished at startup: the process
	// died mid-stream and never got to record anything about why.
	InterruptCrashed InterruptReason = "crashed"
	// InterruptStalled marks a turn that recorded a finish reason but not one
	// the model chose — it asked for a tool and nothing ran it, or it hit the
	// output cap mid-answer. The loop that would have carried on is gone.
	InterruptStalled InterruptReason = "stalled"
	// InterruptFatal is everything a retry cannot help — a malformed request, a
	// model that does not exist, a provider rejecting the tool schema.
	InterruptFatal InterruptReason = "fatal"
)

type Interruption added in v0.26.0

type Interruption struct {
	Reason    InterruptReason `json:"reason"`
	Resumable bool            `json:"resumable"`
	// Detail is a short human-facing sentence naming what to do about it. The
	// raw provider error stays in Error.
	Detail string `json:"detail,omitempty"`
	// RetryAfter is the unix second the provider said to come back at, or 0
	// where it said nothing. Only a rate limit tends to carry one.
	RetryAfter int64 `json:"retryAfter,omitempty"`
	// Step is the loop step the turn died on, for the UI to say how far it got.
	Step int `json:"step,omitempty"`
}

Interruption records why a turn stopped short of finishing and whether picking it up again is worth trying.

It sits beside Error rather than replacing it. Error is the provider's own words, which a user needs to read; this is the classification the resume path acts on, and the two answer different questions.

type MessageID

type MessageID = id.MessageID

func NewMessageID

func NewMessageID() MessageID

type MessageInfo

type MessageInfo struct {
	ID        MessageID    `json:"id"`
	SessionID SessionID    `json:"sessionId"`
	Role      MessageRole  `json:"role"`
	Agent     string       `json:"agent,omitempty"`
	ParentID  *MessageID   `json:"parentId,omitempty"`
	Finish    *string      `json:"finish,omitempty"`
	Cost      float64      `json:"cost,omitempty"`
	Tokens    *TokenCounts `json:"tokens,omitempty"`
	Error     *string      `json:"error,omitempty"`
	// Interrupted is set when a loop stopped part-way through this turn rather
	// than because the model finished. It is what a resume decides from.
	Interrupted *Interruption `json:"interrupted,omitempty"`
	// Delivery records how far this turn got on its way to the model and how
	// long the model took to start answering. Set on assistant messages only,
	// and nil on any written before the field existed.
	Delivery  *Delivery `json:"delivery,omitempty"`
	CreatedAt int64     `json:"createdAt"`
}

func (*MessageInfo) CanResume added in v0.26.0

func (m *MessageInfo) CanResume() bool

CanResume reports whether a message is one a resume should act on.

type MessageRole

type MessageRole string
const (
	RoleUser      MessageRole = "user"
	RoleAssistant MessageRole = "assistant"
)

type MessageWithParts

type MessageWithParts struct {
	Info  MessageInfo `json:"info"`
	Parts []Part      `json:"parts"`
}

type ModelCapability added in v0.6.0

type ModelCapability struct {
	ModelID        string `json:"modelId"`
	SupportsImages bool   `json:"supportsImages"`
	ProbedAt       int64  `json:"probedAt"`
	ContextWindow  int    `json:"contextWindow"`
}

ModelCapability is a probed/known capability record for a model, persisted so the image-support probe runs at most once per model (until manually refreshed). ContextWindow carries a window learned from a context-overflow error body (0 = unknown); see session.LearnModelContextWindow.

func GetModelCapability added in v0.6.0

func GetModelCapability(database *db.DB, modelID string) (*ModelCapability, bool, error)

GetModelCapability returns the persisted capability record for a model. The second return value is false when no record exists (not yet probed).

type ModelPreference

type ModelPreference struct {
	ID          string `json:"id"`
	Enabled     bool   `json:"enabled"`
	ProviderID  string `json:"providerId"`
	DisplayName string `json:"displayName"`
	IsCustom    bool   `json:"isCustom"`
	// Collection is an optional group name for custom models so OpenAI-compatible
	// providers added through the OpenAI provider (Gemini, DeepSeek, Groq, …) can
	// be grouped together in the UI instead of all collapsing under "OpenAI".
	// Empty for built-in models and legacy custom models (falls back to providerId).
	Collection string `json:"collection"`
	CreatedAt  int64  `json:"createdAt"`
	UpdatedAt  int64  `json:"updatedAt"`
}

func GetModelPreferences

func GetModelPreferences(database *db.DB) ([]*ModelPreference, error)

GetModelPreferences returns all model preference overrides from the database.

type ModelPreferenceStore

type ModelPreferenceStore struct{}

type Part

type Part struct {
	ID        PartID          `json:"id"`
	MessageID MessageID       `json:"messageId"`
	SessionID SessionID       `json:"sessionId"`
	Type      PartType        `json:"type"`
	Data      json.RawMessage `json:"data"`
	CreatedAt int64           `json:"createdAt"`
	UpdatedAt int64           `json:"updatedAt"`
}

type PartID

type PartID = id.PartID

func NewPartID

func NewPartID() PartID

type PartType

type PartType string
const (
	PartText      PartType = "text"
	PartTool      PartType = "tool"
	PartReasoning PartType = "reasoning"
	PartFile      PartType = "file"
	PartImage     PartType = "image"
)

type PermissionID

type PermissionID = id.PermissionID

func NewPermissionID

func NewPermissionID() PermissionID

type ProviderConfig added in v0.2.1

type ProviderConfig struct {
	ProviderID string `json:"providerId"`
	APIKey     string `json:"apiKey"`
	BaseURL    string `json:"baseUrl"`
	UpdatedAt  int64  `json:"updatedAt"`
}

ProviderConfig holds credentials for a single LLM provider stored in the DB.

func GetAllProviderConfigs added in v0.2.1

func GetAllProviderConfigs(database *db.DB) ([]*ProviderConfig, error)

GetAllProviderConfigs returns stored configs for all providers.

func GetProviderConfig added in v0.2.1

func GetProviderConfig(database *db.DB, providerID string) (*ProviderConfig, error)

GetProviderConfig returns the stored config for a provider. Returns a zero-value config (empty fields) when no row exists.

func MaskedProviderConfig added in v0.2.1

func MaskedProviderConfig(c *ProviderConfig) *ProviderConfig

MaskedProviderConfig returns a copy with the API key replaced by a sentinel so it can be sent to the UI without leaking the real value.

type ReasoningPartData

type ReasoningPartData struct {
	Text      string `json:"text"`
	Signature string `json:"signature,omitempty"`
	// RedactedData is the opaque payload of an Anthropic redacted_thinking
	// block. Such a block has no readable text, and dropping it — or replaying
	// it as an ordinary thinking block — breaks the round-trip the API
	// requires within a tool-use turn.
	RedactedData string `json:"redactedData,omitempty"`
	// Model is the model that produced this block. Thinking blocks are tied to
	// the model that generated them: replayed to any other model they are
	// silently ignored but still billed as input, and an unsigned block from an
	// OpenAI-family model is rejected outright. Recording the origin lets the
	// conversion drop what the current model cannot use.
	Model string `json:"model,omitempty"`
}

type SearchConfig added in v0.8.0

type SearchConfig struct {
	Enabled bool `json:"enabled"`
	// Provider selects the search backend: "native" (default) or "tavily".
	Provider string `json:"provider"`
	// TavilyAPIKey is the token for the Tavily provider. Masked to MaskedAPIKey
	// on read so it never reaches the UI in the clear.
	TavilyAPIKey string `json:"tavilyApiKey"`
	FetchTopK    int    `json:"fetchTopK"`
	PageChars    int    `json:"pageChars"`
	UpdatedAt    int64  `json:"updatedAt"`
}

SearchConfig holds the global web-search toggle, the active search provider and its credential, plus the deep-research pipeline tuning knobs (pages fetched, per-page size).

func GetSearchConfig added in v0.8.0

func GetSearchConfig(database *db.DB) (*SearchConfig, error)

GetSearchConfig returns the stored config. If no row exists it returns the defaults, which have search ENABLED: the backend is compiled into the binary and needs nothing installed, so there is no setup step to gate it behind. A user who does not want outbound requests turns the toggle off, and that stored choice is honoured on every later read. Research params are always clamped so callers never receive zero/invalid values.

func MaskedSearchConfig added in v0.32.0

func MaskedSearchConfig(c *SearchConfig) *SearchConfig

MaskedSearchConfig returns a copy with the Tavily key replaced by the mask sentinel so the config can be sent to the UI without leaking the real value. Mirrors MaskedProviderConfig.

type Session

type Session struct {
	ID                SessionID `json:"id"`
	ProjectID         string    `json:"projectId"`
	Directory         string    `json:"directory"`
	Title             string    `json:"title"`
	Model             string    `json:"model,omitempty"`
	SessionType       string    `json:"sessionType,omitempty"`
	Permission        string    `json:"permission,omitempty"`
	CompactionSummary string    `json:"compactionSummary,omitempty"`
	MemoryTokensSaved int       `json:"memoryTokensSaved,omitempty"`
	CreatedAt         int64     `json:"createdAt"`
	UpdatedAt         int64     `json:"updatedAt"`
}

type SessionID

type SessionID = id.SessionID

func NewSessionID

func NewSessionID() SessionID

type Store

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

func NewStore

func NewStore(database *db.DB) *Store

func (*Store) Create

func (s *Store) Create(session *Session) error

func (*Store) CreateMessage

func (s *Store) CreateMessage(msg *MessageInfo) error

func (*Store) CreatePart

func (s *Store) CreatePart(part *Part) error

func (*Store) DB added in v0.6.0

func (s *Store) DB() *db.DB

DB returns the underlying database handle, used by helpers that operate on other tables (e.g. model capability records).

func (*Store) Delete

func (s *Store) Delete(id SessionID) error

func (*Store) DeleteMessage added in v0.19.1

func (s *Store) DeleteMessage(messageID MessageID) error

DeleteMessage removes a message and all of its parts. Foreign-key cascade handles part deletion automatically. Used to clean up partial assistant messages left behind when mid-loop guidance cancels a text-only stream — keeping them would produce two consecutive assistant role messages on the next prompt, which the Anthropic and OpenAI APIs reject with a 400.

func (*Store) Get

func (s *Store) Get(id SessionID) (*Session, error)

func (*Store) GetMessage

func (s *Store) GetMessage(messageID MessageID) (*MessageWithParts, error)

func (*Store) GetMessages

func (s *Store) GetMessages(sessionID SessionID, before MessageID, limit int) ([]*MessageWithParts, error)

func (*Store) GetPart

func (s *Store) GetPart(partID PartID) (*Part, error)

func (*Store) GetParts

func (s *Store) GetParts(messageID MessageID) ([]Part, error)

func (*Store) List

func (s *Store) List(directory string) ([]*Session, error)

func (*Store) ListAll added in v0.23.0

func (s *Store) ListAll() ([]*Session, error)

ListAll returns every session row regardless of directory or type, including the note/index/search sessions List hides. Agentic memory uses it to backfill project identity onto nodes written before that column existed.

func (*Store) Update

func (s *Store) Update(session *Session) error

func (*Store) UpdateCompactionSummary

func (s *Store) UpdateCompactionSummary(id SessionID, summary string) error

UpdateCompactionSummary updates only the compaction_summary column for a session, avoiding the race condition of overwriting other fields (e.g., title, model) that may have changed concurrently.

func (*Store) UpdateMemoryTokensSaved added in v0.2.1

func (s *Store) UpdateMemoryTokensSaved(id SessionID, delta int) error

UpdateMemoryTokensSaved atomically increments memory_tokens_saved by delta (may be negative). delta is clamped above at 1_000_000_000 to prevent overflow; negative values are preserved so callers can track memory overhead accurately.

func (*Store) UpdateMessage

func (s *Store) UpdateMessage(msg *MessageInfo) error

func (*Store) UpdatePart

func (s *Store) UpdatePart(part *Part) error

type TextPartData

type TextPartData struct {
	Text string `json:"text"`
}

type TokenCounts

type TokenCounts struct {
	Total      int `json:"total,omitempty"`
	Input      int `json:"input,omitempty"`
	Output     int `json:"output,omitempty"`
	Reasoning  int `json:"reasoning,omitempty"`
	CacheRead  int `json:"cacheRead,omitempty"`
	CacheWrite int `json:"cacheWrite,omitempty"`
}

type ToolImage added in v0.6.0

type ToolImage struct {
	MediaType string `json:"mediaType"`
	Data      string `json:"data"`
}

ToolImage is an image produced by a tool, persisted so the model can be re-sent the image on history replay. Data is base64-encoded image bytes.

type ToolPartData

type ToolPartData struct {
	Tool   string    `json:"tool"`
	CallID string    `json:"callId"`
	State  ToolState `json:"state"`
}

type ToolState

type ToolState struct {
	Status   ToolStatus      `json:"status"`
	Input    json.RawMessage `json:"input"`
	Output   *string         `json:"output,omitempty"`
	Error    *string         `json:"error,omitempty"`
	Title    *string         `json:"title,omitempty"`
	Metadata json.RawMessage `json:"metadata,omitempty"`
	Image    *ToolImage      `json:"image,omitempty"`
	Time     ToolTime        `json:"time"`
}

type ToolStatus

type ToolStatus string
const (
	ToolPending   ToolStatus = "pending"
	ToolRunning   ToolStatus = "running"
	ToolCompleted ToolStatus = "completed"
	ToolError     ToolStatus = "error"
	ToolDenied    ToolStatus = "denied"
)

type ToolTime

type ToolTime struct {
	Start int64 `json:"start,omitempty"`
	End   int64 `json:"end,omitempty"`
}

Jump to

Keyboard shortcuts

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