sessionquery

package
v0.1.3 Latest Latest
Warning

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

Go to latest
Published: Oct 9, 2026 License: MIT Imports: 13 Imported by: 0

README

sessionquery

Extension. Ejectable — the loop never names it. Without it, compaction is lossy in practice: once the loop summarizes an older span, the detail is gone from the model's context even though it is sitting intact in the append-only log.

This is the read path that makes compaction safe. With it, the context can shrink freely, because anything dropped is one query away.

Model Experience

The model searches its own history
What the model sees

One tool, session_query, taking a free-text query and returning ranked matches from this session's durable log — including spans compaction has already summarized away.

Verbatim text for this field
3 matches (searched 412 entries):

[seq 118, turn 9, tool] score 2.0
run_sql returned 1,284 rows; top account by spend was acct_9931 at $41,208.55…

[seq 61, turn 4, assistant] score 1.0
…

An empty query returns the most recent entries, which is how a model browses rather than searches.

Token effect

Capped. Limit matches (default 10, hard cap 50) × ExcerptBytes per excerpt (default 600). A query cannot return more than roughly 30 KB regardless of how large the log is.

KV cache effect

Append-only. The result enters as an ordinary tool result.

The run is not durable and no provider was supplied
What the model sees

Nothing. The plugin declines the run, so the tool is never advertised.

That is deliberate: a tool that can only ever answer "nothing" is worse than no tool, because the model will call it, wait, and learn nothing.

Token effect

Zero-direct.

KV cache effect

Independent.

Impact on the agent

  • Adds one tool that bypasses the permission gate. It is SelfGated: the search is pinned to the run's own SessionID before every call, so a model-supplied value cannot widen the scope — it reads only text this agent already produced and was already shown.
  • Changes the economics of compaction. An agent with this plugin can be given a much more aggressive KeepRecentTokens without losing the ability to answer questions about its own earlier work.
  • The built-in provider scans one session's log. That is a bounded, already-scoped set, which is the only reason a scan is acceptable here.

Known limitations and deferred work

  • A cross-session Provider is the consumer's responsibility to index. The repo's standing search rule applies: it must be typo/accent tolerant and index-backed (pg_trgm GIN over a normalized key, queried with % / similarity) — never a bare ILIKE '%q%' and never a full scan. Nothing in this package enforces that.
  • Scoring is token-count then recency. There is no phrase matching, no field weighting, and no relevance feedback. A query whose terms are common in the log returns near-arbitrary ordering.
  • Messages only by default. Bookkeeping entries (compaction brackets, goal, tool-disable) are reachable only by naming Kinds explicitly, and the model is not told they exist.
  • No pagination. Past MaxLimit there is no cursor; the model must re-query with narrower terms.

Documentation

Overview

Package sessionquery gives an agent authorized retrieval over its own durable session log.

It is the read path that makes compaction safe. Compaction is lossy on purpose: once the loop summarizes an older span, the detail is gone from the model's context — but it is still sitting in the append-only log, fully intact. Without a way back in, a long run reasons from a summary of a summary and re-runs tools it already ran to recover facts it already had. With this plugin, the context can shrink freely, because anything dropped is one query away.

It is deliberately NOT part of compaction (a run may query without ever compacting, and a compacting run need not query), and the fence is the same one spill and jobs use: a query is scoped to the session the run owns.

Ported from deepseek-harness's session-query capability family (packages/session-query, MIT), whose reference provider is SQLite FTS.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Plugin

type Plugin struct {
	// Native enables retrieval over this run's original native checkpoint and
	// newly appended messages, including detail hidden by request compaction.
	Native bool
	// Provider performs the search. nil uses the built-in provider over the
	// run's own SessionStore, which therefore requires a durable run.
	Provider SessionQuery
	// MaxLimit caps what one query may return regardless of what the model asks
	// for. 0 uses maxSessionQueryLimit.
	MaxLimit int
}

Plugin installs retrieval over the durable log.

func OwnSession

func OwnSession() Plugin

OwnSession searches the run's own durable log. It needs a durable run and declines any other.

func Via

func Via(q SessionQuery) Plugin

Via searches through a caller-supplied provider — use this to reach beyond one session, and make it index-backed (see the SessionQuery contract).

func (Plugin) BeginRun

BeginRun resolves the provider for this run.

Without a supplied provider AND without a durable session there is nothing to search, so the plugin DECLINES rather than advertising a tool that can only ever answer "nothing" — a tool the model will call, wait for, and learn nothing from is worse than no tool.

func (Plugin) Name

func (Plugin) Name() string

Name identifies the plugin and the extension it installs.

func (Plugin) Register

func (p Plugin) Register(r *agentcore.Registry) error

Register adds the plugin as a run extension.

type SessionMatch

type SessionMatch struct {
	SessionID string                     `json:"session_id"`
	EntryID   string                     `json:"entry_id,omitempty"`
	Seq       int                        `json:"seq"`
	Kind      agentcore.SessionEntryKind `json:"kind"`
	Turn      int                        `json:"turn,omitempty"`
	Role      agentcore.Role             `json:"role,omitempty"`
	Excerpt   string                     `json:"excerpt"`
	CreatedAt time.Time                  `json:"created_at,omitempty"`
	// Score is the provider's relevance score; higher is better. The built-in
	// provider scores by matched-token count then recency.
	Score float64 `json:"score,omitempty"`
}

SessionMatch is one hit.

type SessionQuery

type SessionQuery interface {
	Search(ctx context.Context, req SessionQueryRequest) (SessionQueryResult, error)
}

SessionQuery is the retrieval seam. The built-in provider searches the current session's own log; a consumer supplies its own to search across a workspace's sessions.

IMPORTANT for cross-session providers: a provider that searches an UNBOUNDED set must be index-backed and fuzzy (this repo's standing search rule — pg_trgm GIN over a normalized key, queried with % / similarity, never a bare ILIKE '%q%' and never a full scan). The built-in provider is exempt only because one session's log is a bounded, already-scoped set.

type SessionQueryRequest

type SessionQueryRequest struct {
	// SessionID is the log to search. The loop always sets it to the run's own
	// session before calling a provider, so a model-supplied value can never
	// widen the scope.
	SessionID string
	// Query is free text. Empty means "return the most recent entries", which is
	// how a model browses rather than searches.
	Query string
	// Kinds filters by entry kind. Empty searches messages only — the model
	// almost always wants what was said, not bookkeeping entries.
	Kinds []agentcore.SessionEntryKind
	// Limit caps the matches returned. 0 uses defaultSessionQueryLimit.
	Limit int
	// ExcerptBytes caps each match's excerpt. 0 uses defaultSessionExcerptBytes.
	ExcerptBytes int
}

SessionQueryRequest is one retrieval request.

type SessionQueryResult

type SessionQueryResult struct {
	Matches []SessionMatch
	// Searched is how many entries were considered, so the model can tell "no
	// matches in a big log" from "the log is nearly empty".
	Searched int
}

SessionQueryResult is a page of matches.

Jump to

Keyboard shortcuts

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