11 KiB
description, kind
| description | kind |
|---|---|
| The unified session-history query service for consumers and backend authors: exact reads, relationship traces, and provider-independent filters over live and durable session logs. | package-reference |
@deepseek-ai/dsh-session-query
English | 中文
Summary
dsh-session-query gives code callers one service for retrieving session history: read a complete raw log, list and filter sessions, fold titles, read events with bounded context, trace session lineage and event relationships, and run full-text search. Live sessions take precedence over persisted ones, and every returned record is a detached clone, so results always describe one consistent moment. Exact reads, filters, and traces are built in; full-text search comes from a mounted backend such as dsh-session-query-sqlite. Use it directly from code when you need programmatic access to what the model saw. Setup and usage come first; the implementation internals live in a collapsible developer section below.
Table of Contents
- Use this package
- Understand the implementation
- Further Exploration
- Model Experience
- Known Limitations and Deferred Work
- Dev Note
Use this package
Use ctx.sessionQuery from application code when you need to read or search session history without touching the session service or a storage backend directly. The service is provided by a concrete backend plugin — the shipped composition mounts @deepseek-ai/dsh-session-query-sqlite (README) — so this package is never mounted alone. Everything below is available on ctx.sessionQuery once a backend is composed.
What you can do
| Operation | What you get |
|---|---|
listSessions() |
Every logical session, newest first, with live and persisted availability flags |
readSession(id) |
The complete replay-validated raw event log, without making the session live |
filterSessions(filters) |
Sessions matching ANDed metadata and availability predicates |
filterEvents(id, filters) |
Semantic event documents matching metadata and literal-text predicates |
readTitleSnapshots(ids) |
The latest folded title per session, bound to its source header |
listEvents(id) / readSurface(id) |
Lightweight per-event records, or the complete current model surface |
readEvent(request) |
One full event plus a bounded raw-log window around it |
traceSession(id) |
The known ancestor chain and recursive descendant trees |
traceEvent(request) |
One event's positional replacements and cited source-event relationships |
searchSessions(request) / searchEvents(request) |
Full-text search pages, implemented by the mounted backend |
Filters
SessionResultFilter narrows sessions by id, nullable cwd, created-at range, nullable parent, or source availability; SessionEventResultFilter narrows events by seq/time range, event type, surface, or literal text. Filter arrays are ANDed and list values within one clause are ORed; empty list values match nothing, ranges are inclusive, and malformed ranges or unknown closed-union values fail with SESSION_QUERY_INVALID_FILTER.
The text clause is a literal, case-insensitive, whitespace-flexible scan of extracted semantic text — not a full-text query. Use it for arbitrary substring recall; use the mounted backend's search methods when you need ranked full-text results.
Configuration
The two inherited knobs are set through the mounted backend's config:
| Field | Default | Meaning |
|---|---|---|
readWindowMax |
50 |
Maximum before/after raw events accepted by readEvent |
persistedInspectConcurrency |
4 |
Concurrent persisted-log inspections in one batch title read |
Failures and recovery
Failures are typed with a stable SessionQueryError.code. The ones you will meet: SESSION_QUERY_SESSION_NOT_FOUND when an id is absent; SESSION_QUERY_SOURCE_CONFLICT when live and persisted observations of one session disagree on immutable headers; SESSION_QUERY_PERSISTENCE_FAILED when mounted persistence is unreadable; SESSION_QUERY_CORRUPT_SESSION when a durable record fails Session validation; and SESSION_QUERY_INVALID_SURFACE when a loaded log breaks the surface contract. Reads targeting a known live session never consult persistence, so a failing backend cannot make current in-memory history unreadable.
Understand the implementation
Implementation internals — click to expand
This section explains the design decisions behind the service and points at the code that realizes them; the observable behavior is fully covered in Use this package.
Design philosophy
The service is built on one separation and three commitments:
- Live-preferred logical corpus. Every read resolves one consistent observation: live
ctx.sessionswins, optionalctx.sessionPersistencefills the rest, and conflicting immutable headers fail rather than merge. - Detached results. All returned headers, events, and records are cloned; nothing exposes live state or a retained subscription.
- Exact reads concrete, search abstract. Reads, filters, and traces are implemented here once; the two full-text methods are the only abstract surface a backend owns.
- One canonical surface fold.
listEvents,readSurface, andtraceEventvalidate the whole log with the samedsh-sessionfold, so search and traces agree with model-history derivation.
The decision history lives in the unified service decision, the tracing note, and the SQLite provider note.
Source map
| File | Role |
|---|---|
src/index.ts |
Service definition: the abstract SessionQueryEngine, concrete reads, config validation |
src/corpus.ts |
Live-preferred corpus resolution, optional persistence binding, batch projections |
src/types.ts |
Public records, filters, requests, and page types |
src/config.ts |
Inherited config and the closed SessionQueryError taxonomy |
src/filters.ts |
Provider-independent predicates and the literal text scan |
src/extraction.ts |
First-party semantic text extraction per event type |
src/documents.ts |
Surface-aware semantic document projection |
src/tracing.ts |
One-shot session-lineage and event-relationship tracing |
src/sources.ts |
Immutable-header compatibility check |
src/invariant.ts |
Invariant companion (no runtime invariant; results are per-call projections) |
Corpus resolution
SessionCorpus binds optional ctx.sessionPersistence through a fiber and resolves each read live-first: a known live target is snapshotted without consulting persistence; otherwise the session is listed, inspected non-mutatingly, and re-checked for a live attachment before cloning. Header compatibility is asserted between listed and loaded observations. Batch title reads run one metadata listing and bounded-concurrency inspections, isolating per-session failures while cancellation rejects the whole batch.
Reads and traces
readSession replays the log through Session.create to reuse resume's validation. readSurface, listEvents, and traceEvent share one foldSurface pass that classifies events as current, shadowed, or log-only and validates zero-based contiguous seqs, surface-marker eligibility, and replacement or citation integrity; any violation fails with SESSION_QUERY_INVALID_SURFACE. Traces are one-shot: session lineage reads the corpus once and walks parents and descendant trees deterministically, and event traces follow positional replacers to the final node while keeping cited-source links non-transitive.
Further Exploration
Read these pages when the package-level contract is not enough. They move from the shared query vocabulary to the concrete backend and the decision evidence.
- Session Query subsystem reference — the full type-level contract: records, filters, search pages, lineage, bounded reads, and errors.
- dsh-session-query-sqlite — the shipped full-text backend and its index lifecycle.
- dsh-tool-session-query — the model-facing consumer built on this service.
- Session query relationship tracing — trace semantics and the validation boundary.
- SQLite FTS5 session search — how the search surface is implemented and reconciled.
Model Experience
None, as the trusted query service exposes cloned records only to callers and registers nothing model-facing.
KV Cache effect
None; this package neither assembles nor sends a provider request.
Known Limitations and Deferred Work
These limits define when this package is a poor fit or needs special operational care. They are current package constraints, not a task backlog.
- No caller authorization — this is trusted context-wide infrastructure; a model tool or UI must constrain which sessions its caller may inspect.
- No provider coordinator or fallback — the service is abstract over search, so a composition must mount a concrete backend; there is no search-provider registry or fallback implementation.
- Exact reads replay whole logs —
readSession,readSurface,filterEvents, and event traces load and validate the complete logical log, so very large histories pay full inspection per call;listSessionsstays lightweight. - Literal text scan, not full-text search — the
textfilter scans extracted documents with a regular expression and does not rank; ranked search requires the mounted backend.
Dev Note
Working context for maintainers — click to expand
This Dev Note is working context for maintainers: open design questions and directions that are not decided. It is explicitly non-authoritative — shipped behavior, limits, and accepted rationale live in the sections above, the package code, and the linked Agent Notes.
Future: extractor and search-provider registries
Recursive traversal through cited source events, extractor and search-provider registries, and additional model-facing surfaces are deferred; the model-facing tools note records the current consumer surface.