Files
deepseek-harness/packages/session-query/session-query
Hypatia May 0a0f19cf57 Merge remote-tracking branch 'origin/master' into session-query-search
# Conflicts:
#	.agents/notes/implemented/feature/2026-07-10-session-query-service.md
#	.agents/notes/implemented/feature/2026-07-10-sqlite-session-query-provider.md
#	.agents/notes/proposed/feature/2026-07-10-sqlite-session-query-provider.md
#	docs/architecture.md
#	docs/capability-seams.md
#	docs/config-catalog.md
#	docs/cordis-catalog/services.md
#	docs/core-data-structures/core.md
#	docs/core-data-structures/persistence.md
#	docs/core-data-structures/session-query.md
#	docs/module-graph.md
#	docs/rfc/INDEX.md
#	packages/README.md
#	packages/cordis/tool-cordis/src/api-catalog.ts
#	packages/hooks/hooks-claude/tests/coverage.spec.ts
#	packages/session-persistence/session-persistence-jsonl/src/index.ts
#	packages/session-persistence/session-persistence-jsonl/tests/jsonl.spec.ts
#	packages/session-persistence/session-persistence-sqlite/README.md
#	packages/session-persistence/session-persistence-sqlite/src/index.ts
#	packages/session-persistence/session-persistence-sqlite/src/schema.ts
#	packages/session-persistence/session-persistence-sqlite/tests/sqlite.spec.ts
#	packages/session-persistence/session-persistence/README.md
#	packages/session-persistence/session-persistence/package.json
#	packages/session-query/README.md
#	packages/session-query/session-query/README.md
#	packages/session-query/session-query/package.json
#	packages/session-query/session-query/src/config.ts
#	packages/session-query/session-query/src/index.ts
#	packages/session-query/session-query/src/types.ts
#	pnpm-lock.yaml
#	scripts/gen-doc-graphs.ts
#	scripts/type-equiv.manifest.json
#	tsconfig.host.json
#	tsconfig.json
2026-07-23 13:56:56 +08:00
..

@deepseek-ai/dsh-session-query

Exact session-history retrieval, relationship tracing, and provider-independent filtering through ctx.sessionQuery. The service presents live ctx.sessions and an optional, dynamically mounted ctx.sessionPersistence as one logical corpus. Matching ids produce one record: live events win, while live and persisted report both source availabilities. Conflicting immutable headers fail with SESSION_QUERY_SOURCE_CONFLICT. The abstract ctx.sessionSearch service defines full-text search without introducing a provider registry.

Reads

  • listSessions() reads current persistence metadata, merges live records with live precedence, and returns cloned records in deterministic newest-first order.
  • filterSessions(filters) applies provider-independent session metadata and availability predicates to that same cloned logical corpus.
  • filterEvents(sessionId, filters) extracts first-party semantic documents and applies provider-independent metadata and literal-text predicates in ascending seq order.
  • readTitle(sessionId) loads one live-preferred or persisted log and folds its latest session/title event into a SessionTitleSnapshot; it returns undefined when the known session has no title.
  • listEvents(sessionId) loads the live-preferred raw log and classifies each event as current, shadowed, or log-only with the shared dsh-session surface fold.
  • readSurface(sessionId) returns one cloned header, raw-log capture boundary, and the complete folded current surface in model-history order. A live session wins over persistence; compaction is observed before or after its replacement append, never as a synthetic mixture.
  • readEvent(request) returns a cloned header, the full target event, and a bounded raw-seq window. before and after default to zero and may not exceed readWindowMax.
  • traceSession(sessionId) reads the corpus once and returns immediate-to-outward ancestors plus deterministic recursive descendant trees. complete: false identifies the first missing parent; a target-connected cycle fails with SESSION_QUERY_INVALID_LINEAGE.
  • traceEvent(request) loads the logical log once and returns direct positional replacements and direct logged provenance. replacementChain follows positional replacers to the final replacement; provenance links remain non-transitive.

Persistence is optional and may mount or unmount dynamically. Cross-corpus listing and lineage tracing fail with SESSION_QUERY_PERSISTENCE_FAILED while mounted persistence is unreadable. A title, event read, or trace targeting a known live session does not consult persistence, so durable backend health cannot make current in-memory state unreadable. Persisted title and event operations list before loading and reject a metadata mismatch rather than combining inconsistent observations. listSessions() remains lightweight and does not load logs or index titles.

Filtering and extraction

SessionResultFilter covers id, nullable cwd, created-at range, nullable parent, and source availability. SessionEventResultFilter covers seq/time ranges, event type, surface, and semantic text. Filter arrays are ANDed; values within one list clause are ORed. Empty list values match nothing, ranges are inclusive, and malformed ranges or closed-union values fail with SESSION_QUERY_INVALID_FILTER.

The text clause is deliberately independent of FTS providers: caller text is escaped into a Unicode, case-insensitive regular expression, and each whitespace run matches one or more whitespace characters. It is a literal semantic-text scan, not a full-text query. extractSessionEventText() and buildSessionEventSearchDocuments() define the shared first-party document projection; structural boundaries, stream chunks, request headers, and unknown declaration-merged variants produce no document.

Full-text seam

SessionSearchService owns the independent ctx.sessionSearch key. searchSessions(request, exec?) groups the logical corpus by strongest matching event; searchEvents(request, exec?) searches one logical session. Both return pages whose continuation is an owned branded SessionSearchCursor, accept optional cancellation, and expose snippets without provider-specific numeric scores. Search requests accept only metadata event filters, because literal-text filtering is the scan path described above.

The package has no provider coordinator or registration protocol. A concrete backend owns observation, reconciliation, ranking, cursor generations, and query execution as one lifecycle; the first implementation is @deepseek-ai/dsh-session-query-sqlite.

SessionQueryError.code is a closed union covering request validation, missing targets, malformed surfaces, source conflicts, persistence/index failures, cancellation, and invalid or stale cursors; the exact literals are defined in src/config.ts.

listEvents(), readSurface(), and traceEvent() run the same one-pass dsh-session surface fold. A loaded log is valid only when event seqs are zero-based and contiguous, surface markers obey event-type eligibility, provenance arrays are nonempty and duplicate-free, references name earlier events, and each positional replacement names and cites every surface node it removes; every violation fails with SESSION_QUERY_INVALID_SURFACE.

Configuration

Key Default Contract
readWindowMax 50 Maximum before or after raw-event count.

Model Experience

None, as this trusted query service returns cloned session records only to its callers and registers no model-facing prompt, schema, tool, or message.

KV Cache effect

None; this package neither assembles nor sends a provider request.

Known Limitations and Deferred Work

  • No caller authorization — this is trusted context-wide infrastructure; a future model tool or UI must constrain which sessions its caller may inspect.
  • No registries or model-facing tool — extractor and search-provider registries, recursive event-provenance traversal, and a model-facing tool are absent. The tracing decision owns relationship semantics; SQLite ownership and tokenizer decisions live in the implemented search note.