@pyxmate/memory 1.19.8 → 1.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,1435 +1,1472 @@
1
1
  import { StoreInput as StoreInput$1, MemoryEntry as MemoryEntry$1, MemorySearchParams as MemorySearchParams$1, MemorySearchResult as MemorySearchResult$1, MemoryType as MemoryType$1, PrincipalContext as PrincipalContext$1, SensitivityLevel as SensitivityLevel$1, MemoryStats as MemoryStats$1, MemoryInsights as MemoryInsights$1, LineageParams as LineageParams$1, LineageResult as LineageResult$1, ReinforceParams as ReinforceParams$1, ReinforceResult as ReinforceResult$1, WikiLintReport as WikiLintReport$1, GraphRepairResult as GraphRepairResult$1, ExtractedImageMeta as ExtractedImageMeta$1, IngestEntity as IngestEntity$1, IngestRelationship as IngestRelationship$1, EntityExtractionResult as EntityExtractionResult$1, Topology as Topology$1, IngestEvent as IngestEvent$1, GraphEnrichEvent as GraphEnrichEvent$1, GraphNode as GraphNode$1, GraphTraversalResult as GraphTraversalResult$1, CorrectionRecord as CorrectionRecord$1 } from '@pyx-memory/shared';
2
2
  export { documentContentSource, documentGraphSource, documentImageSource } from '@pyx-memory/shared';
3
- export { e as encodeListCursorToken, p as parseListCursorToken } from './data-plane-contract-CmosA5XV.js';
3
+ export { e as encodeListCursorToken, p as parseListCursorToken } from './data-plane-contract-webbeMs5.js';
4
4
 
5
- /** Parameters for paginated entry listing. */
6
- interface MemoryListParams {
7
- /** 1-based page number. Default: 1 */
8
- page?: number;
9
- /** Entries per page (1–100). Default: 20 */
10
- limit?: number;
11
- /**
12
- * Opaque keyset-pagination token from a previous result's `nextCursor`.
13
- * Guarantees exactly-once traversal even while strictly-newer entries
14
- * are being written (offset/page pagination can repeat or skip there).
15
- * A cursor is only valid for the same filter set that produced it.
16
- * Mutually exclusive with `page` — supplying both is an error. Not a
17
- * snapshot: rows backdated behind the cursor position can still appear.
18
- */
19
- cursor?: string;
5
+ /** ISO 8601 timestamp string */
6
+ type Timestamp = string;
7
+ /** Unique agent identifier */
8
+ type AgentId = string;
9
+
10
+ /**
11
+ * Caller identity for ReBAC authorization.
12
+ *
13
+ * The canonical "subject" in Zanzibar terms — passed alongside requests so the
14
+ * memory layer can compute an AuthzPlan (visible namespaces + entry overrides)
15
+ * before any retrieval source fans out.
16
+ *
17
+ * Identity comes from authenticated request context (X-Tenant-Id / auth token
18
+ * claims), never from request bodies or multipart form fields. The legacy
19
+ * `userId` / `teamId` / `agentId` columns on MemoryEntry remain for audit and
20
+ * legacy filters but MUST NOT drive authorization decisions — they are
21
+ * collision-prone aliases (a service principal sharing an ID with a human
22
+ * user has no protection against confused-deputy attacks).
23
+ *
24
+ * Sensitivity / clearance is intentionally NOT on this object. It is a
25
+ * MAC-style classification, orthogonal to RBAC, and continues to be carried
26
+ * via the `X-Caller-Access-Level` header → `MemorySearchParams.maxSensitivity`.
27
+ * Conflating the two couples future changes (e.g. per-namespace classification
28
+ * rules) to identity propagation.
29
+ */
30
+ interface PrincipalContext {
20
31
  /**
21
- * Opt-in lifecycle-status filter. Omitted preserves today's behavior:
22
- * active, superseded, and archived entries are all returned.
32
+ * Hard isolation boundary. Required even in single-tenant deployments —
33
+ * single-mode passes a stable sentinel (`SINGLE_TENANT_ID`) so authz code
34
+ * paths look identical regardless of mode.
23
35
  */
24
- status?: 'active' | 'superseded' | 'archived';
25
- /** Filter by memory type. */
26
- type?: MemoryType$1;
27
- /** Filter by agent ID. */
28
- agentId?: string;
29
- /** Filter by tenant ID for multi-tenant isolation. */
30
- tenantId?: string;
31
- /** Exact namespace scope. Excludes legacy tenant-root entries. */
32
- namespaceId?: string;
36
+ tenantId: string;
33
37
  /**
34
- * Calling principal. When supplied, list applies the AuthzPlan
35
- * visibility filter so entries in forbidden namespaces never reach
36
- * the response. Single-tenant / library-direct callers may omit it
37
- * and get the legacy tenant-only scope.
38
+ * Stable subject ID (within the tenant). For humans this is the userId;
39
+ * for AI runtimes it is the agentId; for system actors it is a service
40
+ * identifier. Combined with `kind`, forms the Zanzibar subject coordinate
41
+ * `<kind>:<principalId>`.
38
42
  */
39
- principal?: PrincipalContext$1;
40
- /** Maximum sensitivity level to include. Omitted preserves legacy behavior. */
41
- maxSensitivity?: SensitivityLevel$1;
43
+ principalId: string;
42
44
  /**
43
- * R1/R2 — opt-in list of `metadata._kind` values to include in the
44
- * response. When omitted or empty, the default-set returns only entries
45
- * with NO `_kind` system metadata (e.g. `_kind:'entity-summary'` rows
46
- * are hidden). When supplied, the listed kinds are returned IN ADDITION
47
- * to the default-set (additive, not replacement). See
48
- * `docs/specs/topic-org-v025-f1-include-kinds/spec.md`.
45
+ * Subject namespace. Distinguishes humans from AI agents from internal
46
+ * services so a userId/agentId/serviceId collision cannot grant
47
+ * unintended access.
48
+ * - `user`: human end user
49
+ * - `agent`: AI runtime acting on a user's behalf or autonomously
50
+ * - `service`: non-AI internal system (cron, ETL, admin tooling)
49
51
  */
50
- includeKinds?: string[];
52
+ kind: 'user' | 'agent' | 'service';
51
53
  }
52
- /** Result of a paginated entry listing. */
53
- interface MemoryListResult {
54
- entries: MemoryEntry$1[];
55
- totalCount: number;
56
- /** Present in page/offset mode only — a keyset traversal has no page number. */
57
- page?: number;
58
- limit: number;
59
- /** Keyset token for the next page; null when this page is the last. */
60
- nextCursor: string | null;
54
+ /** Sentinel tenant ID used in single-tenant deployments. */
55
+ declare const SINGLE_TENANT_ID = "_single";
56
+
57
+ declare const MemoryType: {
58
+ readonly SHORT_TERM: "short-term";
59
+ readonly LONG_TERM: "long-term";
60
+ readonly WORKING: "working";
61
+ readonly EPISODIC: "episodic";
62
+ readonly SUMMARY: "summary";
63
+ };
64
+ type MemoryType = (typeof MemoryType)[keyof typeof MemoryType];
65
+ declare const SensitivityLevel: {
66
+ readonly PUBLIC: "public";
67
+ readonly INTERNAL: "internal";
68
+ readonly SECRET: "secret";
69
+ };
70
+ type SensitivityLevel = (typeof SensitivityLevel)[keyof typeof SensitivityLevel];
71
+ declare const RAGStrategy: {
72
+ readonly NAIVE: "naive";
73
+ readonly GRAPH: "graph";
74
+ readonly HYBRID: "hybrid";
75
+ };
76
+ type RAGStrategy = (typeof RAGStrategy)[keyof typeof RAGStrategy];
77
+ /**
78
+ * Strategy identifiers that were public in earlier versions and have been
79
+ * removed. Server/SDK reject requests using these with a stable
80
+ * `strategy.deprecated:<name>` error code (not the generic "invalid
81
+ * strategy" message) so callers and dashboards can detect the removal
82
+ * cleanly across a version bump.
83
+ *
84
+ * v0.26: `agentic` removed (Codex pair: silent-catch in agentic.ts
85
+ * violated Production-ready; behavior subsumed by HybridRAGEngine).
86
+ */
87
+ declare const DEPRECATED_RAG_STRATEGIES: ReadonlyMap<string, string>;
88
+ declare const VectorProvider: {
89
+ readonly LANCEDB: "lancedb";
90
+ };
91
+ type VectorProvider = (typeof VectorProvider)[keyof typeof VectorProvider];
92
+ declare const EmbeddingProviderName: {
93
+ readonly STUB: "stub";
94
+ /** @deprecated Vestigial — pyx-memory uses internal EmbeddingGemma embeddings. */
95
+ readonly ANTHROPIC: "anthropic";
96
+ /** @deprecated Vestigial — pyx-memory uses internal EmbeddingGemma embeddings. */
97
+ readonly OPENAI: "openai";
98
+ /** In-process ONNX model (default: EmbeddingGemma-300M). */
99
+ readonly LOCAL: "local";
100
+ /** Remote OpenAI-compatible embedding service (pyx-cloud shared, custom, etc.). */
101
+ readonly HTTP: "http";
102
+ };
103
+ type EmbeddingProviderName = (typeof EmbeddingProviderName)[keyof typeof EmbeddingProviderName];
104
+ type GraphEnrichmentStatus = 'caller-provided' | 'extracted' | 'merged' | 'opted-out' | 'skipped-duplicate' | 'skipped-sensitive' | 'skipped-unprovisioned' | 'extracted-empty' | 'failed-graph-write' | 'failed-best-effort';
105
+ interface GraphEnrichment {
106
+ status: GraphEnrichmentStatus;
107
+ provider?: 'http' | 'local' | 'none';
108
+ reason?: string;
109
+ action?: string;
61
110
  }
62
- /** Filters for temporal queries (queryAsOf, queryByEventTime). */
63
- interface TemporalQueryFilters {
64
- type?: MemoryType$1;
65
- agentId?: string;
66
- source?: string;
67
- limit?: number;
68
- /**
69
- * Number of matching rows to skip. Offset pages can shift under concurrent
70
- * deletion; use cursor for a deletion-stable queryAsOf walk.
71
- */
72
- offset?: number;
111
+ /**
112
+ * A caller-supplied relationship whose source or target name did not resolve to
113
+ * any entity in the same store call (after name normalization), so the edge was
114
+ * not written. Surfaced on the store response so the agent — not just the server
115
+ * log — can see which edges to re-send.
116
+ */
117
+ interface DroppedGraphRelationship {
118
+ source: string;
119
+ target: string;
120
+ type: string;
121
+ }
122
+ type VectorStatus = 'pending' | 'stored' | 'skipped';
123
+ /**
124
+ * Upper bound of a caller-declared `sessionOrdinal`: `n + 2` stays an exact
125
+ * integer, so the ±2 neighbor operator needs no runtime arithmetic guard.
126
+ */
127
+ declare const SESSION_ORDINAL_MAX: number;
128
+ declare function isSessionOrdinal(value: unknown): value is number;
129
+ interface MemoryEntry {
130
+ id: string;
131
+ content: string;
132
+ type: MemoryType;
133
+ agentId?: AgentId;
134
+ sessionId?: string;
73
135
  /**
74
- * Opaque keyset token for a deletion-stable queryAsOf walk. Derive it from
75
- * the last returned entry with `encodeListCursorToken`; mutually exclusive
76
- * with offset.
136
+ * Caller-declared turn coordinate inside `sessionId` (0 ≤ n ≤ SESSION_ORDINAL_MAX).
137
+ * Never inferred from timestamps or insertion order; unique per
138
+ * (tenant, namespace, session) while declared.
77
139
  */
78
- cursor?: string;
79
- /** Maximum sensitivity level to include. Omitted preserves legacy behavior. */
80
- maxSensitivity?: SensitivityLevel$1;
81
- }
82
- /** Filters for the chronological feed (`log`, Karpathy `log.md` primitive). */
83
- interface MemoryLogFilters {
84
- /** Inclusive lower bound on `created_at` (ISO 8601). Cursor for "what's new since X". */
85
- since?: string;
86
- /** Maximum entries to return. The HTTP layer clamps to [1, 100]. */
87
- limit?: number;
88
- type?: MemoryType$1;
89
- agentId?: string;
140
+ sessionOrdinal?: number;
141
+ metadata: Record<string, unknown>;
142
+ /** @deprecated Vestigial — embeddings are managed internally by the vector store. */
143
+ embedding?: number[];
144
+ createdAt: Timestamp;
145
+ /** SHA-256 hash of content for deduplication. */
146
+ contentHash?: string;
147
+ /** Importance score (1-10). */
148
+ importance?: number;
149
+ /** Number of times this entry has been accessed via search. */
150
+ accessCount?: number;
151
+ /** ISO timestamp of last access via search. */
152
+ lastAccessed?: string;
153
+ /** Parent entry ID for hierarchical storage (e.g., doc → section → chunk). */
154
+ parentId?: string;
155
+ /** Source identifier (e.g., filename, URL, session). */
90
156
  source?: string;
91
- /** Maximum sensitivity level to include. Omitted preserves legacy behavior. */
92
- maxSensitivity?: SensitivityLevel$1;
93
- }
94
- /** Options for scoping operations to a specific tenant. */
95
- interface TenantScopeOptions {
157
+ /** When the event described by this memory occurred. */
158
+ eventTime?: string;
159
+ /** When this entry was ingested into the system. */
160
+ ingestTime?: string;
161
+ /** Sensitivity classification based on content analysis. */
162
+ sensitivity?: SensitivityLevel;
163
+ /** Whether the content field is encrypted at rest. */
164
+ encrypted?: boolean;
165
+ /** Number of graph entities written by this store call. Present on store responses. */
166
+ graphEntitiesWritten?: number;
167
+ /** Number of graph relationships written by this store call. Present on store responses. */
168
+ graphRelationshipsWritten?: number;
169
+ /** Count of caller relationships dropped because an endpoint name did not match any entity in the call. Present (and >0) only when edges were dropped. */
170
+ graphRelationshipsDropped?: number;
171
+ /** Up to 20 of the dropped relationships (source/target/type), so the agent can re-send them. Present only when edges were dropped. */
172
+ graphRelationshipsDroppedDetail?: DroppedGraphRelationship[];
173
+ /** Graph extraction/enrichment outcome for this store call. Present on graph-targeted store responses. */
174
+ graphEnrichment?: GraphEnrichment;
175
+ /** Store response vector outcome. Pending means SQLite is durable and vector indexing is eventually consistent. */
176
+ vectorStatus?: VectorStatus;
177
+ /** Tenant ID for multi-tenant isolation. */
96
178
  tenantId?: string;
97
- /** Optional strict namespace coordinate for exact get/delete operations. */
179
+ /** User ID within the tenant. */
180
+ userId?: string;
181
+ /** Team/group ID within the tenant. */
182
+ teamId?: string;
183
+ /**
184
+ * Namespace ID — the primary protected resource for ReBAC authorization.
185
+ * `undefined` (NULL on the row) means the entry lives in the legacy
186
+ * "tenant-root" bucket and is visible to anyone with tenant access (the
187
+ * pre-ReBAC posture). Setting `namespaceId` opts the entry into AuthzPlan-
188
+ * based filtering, where visibility is computed from `authz_tuples` for
189
+ * the calling principal.
190
+ */
98
191
  namespaceId?: string;
99
192
  /**
100
- * Graph count mode for stats(). Use raw on admin-health paths
101
- * that should avoid the visible graph projection.
193
+ * When true, consolidation leaves this entry alone — it is never archived by
194
+ * decay and never merged (nor merged-into) by semantic deduplication. Use for
195
+ * stable anchor entries whose ID is referenced by external systems (e.g. a
196
+ * file-catalog row pointed at by another service's foreign key).
102
197
  */
103
- graphVisibility?: 'visible' | 'raw';
198
+ pinned?: boolean;
104
199
  /**
105
- * Calling principal. When supplied alongside or instead of tenantId,
106
- * the operation applies the AuthzPlan visibility filter — get/delete
107
- * will treat entries in forbidden namespaces as if they did not exist.
108
- * Single-tenant / library-direct callers may omit it and get the
109
- * legacy tenant-only scope.
200
+ * Lifecycle status (H8). Optional on write (absent means `'active'`), but
201
+ * every entry READ back from the store carries it explicitly — a caller can
202
+ * compare `entry.status === 'active'` without special-casing an absent field.
203
+ * `'active'` is a normal retrievable entry. `'superseded'` means a newer near-duplicate
204
+ * UPDATE replaced this one during consolidation. `'archived'` (1b) means decay
205
+ * retired it (no successor) — kept, strength 0, `deep`-tier only. All three
206
+ * are kept (history / lineage / deep recall) but `superseded`/`archived` are
207
+ * excluded from default/quick/medium search. Only `forget()` and exact-byte-
208
+ * duplicate collapse hard-delete. See `docs/H8-MEMORY-MODEL-DESIGN.md`.
110
209
  */
111
- principal?: PrincipalContext$1;
112
- /** Maximum sensitivity level to include. Omitted preserves legacy behavior. */
113
- maxSensitivity?: SensitivityLevel$1;
114
- }
115
- /** Abstract interface for memory systems (local or remote). */
116
- interface MemoryInterface {
117
- initialize(): Promise<void>;
118
- store(entry: StoreInput$1): Promise<MemoryEntry$1>;
119
- search(params: MemorySearchParams$1): Promise<MemorySearchResult$1>;
120
- /** List entries with SQL LIMIT/OFFSET pagination. */
121
- list(params?: MemoryListParams): Promise<MemoryListResult>;
122
- get(id: string, options?: TenantScopeOptions): Promise<MemoryEntry$1 | null>;
123
- delete(id: string, options?: TenantScopeOptions): Promise<boolean>;
124
- clearSession(sessionId: string, options?: TenantScopeOptions): Promise<number>;
125
- stats(options?: TenantScopeOptions): Promise<MemoryStats$1>;
126
- insights(options?: TenantScopeOptions): Promise<MemoryInsights$1>;
127
- /** Query entries as they existed at a point in time (by ingest time). */
128
- queryAsOf(asOfDate: string, filters?: TemporalQueryFilters, options?: TenantScopeOptions): Promise<MemoryEntry$1[]>;
129
- /** Read the time-ordered lineage of a graph fact or superseded entry chain. */
130
- lineage(params: LineageParams$1): Promise<LineageResult$1>;
131
- /** Reinforce memories that were actually used by the caller. */
132
- reinforce(params: ReinforceParams$1): Promise<ReinforceResult$1>;
133
- /** Query entries by event time range (when things actually happened). */
134
- queryByEventTime(startTime: string, endTime: string, filters?: TemporalQueryFilters): Promise<MemoryEntry$1[]>;
135
- shutdown(): Promise<void>;
136
- }
137
- /** Consolidation run result. */
138
- interface ConsolidationRunResult {
139
- entriesProcessed: number;
140
- entriesMerged: number;
141
- entriesArchived: number;
142
- durationMs: number;
143
- }
144
- /** Extended interface with lifecycle operations. Non-breaking for existing consumers. */
145
- interface ExtendedMemoryInterface extends MemoryInterface {
146
- /** Run consolidation: score, dedup, decay, and summarize memories. */
147
- consolidate(): Promise<ConsolidationRunResult>;
148
- /** Soft-delete a memory with a reason (marks as archived). */
149
- forget(id: string, reason?: string): Promise<boolean>;
150
- /** Summarize a session's memories into a long-term entry. */
151
- summarizeSession(sessionId: string): Promise<MemoryEntry$1 | null>;
210
+ status?: 'active' | 'superseded' | 'archived';
152
211
  /**
153
- * Read-only memory-wide lint report (v0.18.0 Karpathy-wiki Item B):
154
- * orphans, decay candidates, stale entries, dedup candidates. Pure
155
- * projection — no writes.
212
+ * When `status==='superseded'`, the id of the newer entry that replaced this
213
+ * one — the backward link used by `Memory.lineage()` chain traversal. Cleared
214
+ * to NULL (never resurrected to active) if the successor is later forgotten.
156
215
  */
157
- lint(options?: {
158
- limit?: number;
159
- }): Promise<WikiLintReport$1>;
160
- /** Run decay on all entries, archiving those below threshold. */
161
- runDecay(): Promise<number>;
162
- /** Reindex the FTS5 full-text search index. */
163
- reindex(): Promise<void>;
164
- /** Delete all entries matching a source, cleaning up all stores. */
165
- deleteBySource(source: string, options?: TenantScopeOptions): Promise<number>;
166
- /** Repair stale graph references left by older delete paths or crashed cleanup. */
167
- repairGraph(): Promise<GraphRepairResult$1>;
216
+ supersededByEntryId?: string;
168
217
  /**
169
- * Chronological feed of memory entries (Karpathy `log.md` primitive).
170
- * Cursor-based via `since` (created_at lower bound). No totalCount.
218
+ * @internal Hosted data-plane only. SHA-256 of the canonical caller store
219
+ * payload (server-stamped timestamps excluded), persisted for caller-id
220
+ * stores so a re-send of the same `metadata.dbRef.revision` can be
221
+ * classified as an idempotent no-op (digest match) or a
222
+ * `revision_reuse_conflict` (digest mismatch). Graph entities/relationships
223
+ * are part of the payload but not of the row, so the digest cannot be
224
+ * recomputed from stored state.
171
225
  */
172
- log(filters?: MemoryLogFilters): Promise<MemoryEntry$1[]>;
226
+ payloadDigest?: string;
227
+ }
228
+ interface MemorySearchParams {
229
+ query: string;
230
+ type?: MemoryType;
231
+ agentId?: AgentId;
232
+ /** Optional caller session identifier used for in-process hygiene telemetry. */
233
+ sessionId?: string;
234
+ limit?: number;
235
+ strategy?: RAGStrategy;
236
+ /** Filter results to entries whose eventTime falls within [start, end] (ISO 8601). */
237
+ eventTimeRange?: [string, string];
238
+ /** Filter results to entries ingested before this cutoff (ISO 8601). Falls back to createdAt when ingestTime is null. */
239
+ asOf?: string;
173
240
  /**
174
- * Synthesize a per-entity profile (Karpathy-wiki "wiki page" primitive).
175
- * LLM-driven, caller-triggered. Stores a pinned `_kind:'entity-summary'`
176
- * entry with `_search_visibility:'on-demand'` so it never enters the
177
- * default retrieval pool. Re-running replaces the prior synthesis.
241
+ * Soft recency ANCHOR (ISO 8601) — never a filter. Candidates are ranked by
242
+ * proximity to this time instead of now, and conflicting assertions
243
+ * re-order around it. Resolving relative-time expressions ("two months
244
+ * ago", "3년 전") to an absolute timestamp is the CALLER's side of the
245
+ * agentic contract — language understanding never enters the engine. Wins
246
+ * over the query-text year parse (hybrid strategy).
178
247
  */
179
- summarizeEntity(name: string): Promise<MemoryEntry$1>;
248
+ anchorTime?: string;
180
249
  /**
181
- * Fetch a previously-synthesized entity profile. Returns `null` when no
182
- * synthesis exists yet. O(1) — the read side of the amortized pattern.
250
+ * The category the user is asking to count/list (e.g. "fitness classes",
251
+ * "운동 수업", any language). Presence signals enumeration intent and supplies
252
+ * the category for graph resolution; the caller (which understands the user's
253
+ * language) sets it. When omitted, pyx falls back to a deterministic EN/KO
254
+ * marker detector.
183
255
  */
184
- getEntitySynthesis(name: string): Promise<MemoryEntry$1 | null>;
185
- }
186
-
187
- /**
188
- * No-op {@link MemoryInterface} for hosts that run without a memory backend
189
- * (e.g. `MEMORY_URL` is unset). Every method returns a safe default, so the
190
- * rest of the system functions without branching on `memory == null`.
191
- *
192
- * Canonical single source: this lives in the SAME package as `MemoryInterface`,
193
- * so any method added to the interface fails THIS class's compile in the same
194
- * build. The null-object can never silently drift behind the contract — the
195
- * failure mode that left hand-rolled copies in downstream repos missing
196
- * `lineage`/`reinforce` after the interface grew them.
197
- *
198
- * `initialize()` emits a single `console.warn`; pass nothing else — it is a
199
- * pure null-object. Hosts wanting structured logging should log at the wiring
200
- * site where they choose `DisabledMemory` over a real client.
201
- */
202
- declare class DisabledMemory implements MemoryInterface {
203
- initialize(): Promise<void>;
204
- store(entry: StoreInput$1): Promise<MemoryEntry$1>;
205
- search(): Promise<MemorySearchResult$1>;
206
- list(params?: MemoryListParams): Promise<MemoryListResult>;
207
- get(): Promise<MemoryEntry$1 | null>;
208
- delete(): Promise<boolean>;
209
- clearSession(): Promise<number>;
210
- stats(): Promise<MemoryStats$1>;
211
- insights(): Promise<MemoryInsights$1>;
212
- queryAsOf(): Promise<MemoryEntry$1[]>;
213
- lineage(): Promise<LineageResult$1>;
214
- reinforce(): Promise<ReinforceResult$1>;
215
- queryByEventTime(): Promise<MemoryEntry$1[]>;
216
- shutdown(): Promise<void>;
217
- }
218
-
219
- /**
220
- * Callbacks for two-phase file enrichment. All callbacks are optional:
221
- * - Image-rich PDF + describeImage only → describes images, no entity extraction
222
- * - Image-rich PDF + describeImage + extractEntitiesV2 → describes + extracts
223
- * - Text-only file + extractEntitiesV2 only → extracts from textWindows
224
- * - Mixed file + both → describes images + extracts from both sources
225
- *
226
- * Without any callback, the ingest stream emits the server result with no
227
- * SDK-side enrichment. Server-side text/entity extraction may still run when
228
- * configured; image understanding still requires caller-provided
229
- * descriptions/hooks.
230
- */
231
- interface EnrichmentCallbacks {
256
+ enumerationConcept?: string;
257
+ /** Confidence threshold below which the system recommends abstention (0.0–1.0). Default: 0.3. */
258
+ abstentionThreshold?: number;
232
259
  /**
233
- * Describe an image using LLM vision. Receives the raw image buffer and
234
- * metadata. Required for image-bearing files; safe to omit for text-only
235
- * uploads where the server emits zero images.
260
+ * Rerank with the cross-encoder before final truncation (hybrid strategy
261
+ * only). The pipeline retrieves and dedups a deeper candidate pool (≥50),
262
+ * scores it through the cross-encoder, then truncates to `limit` —
263
+ * reranking after truncation cannot change top-`limit` set membership.
264
+ * Forwarded by `MemoryClient.search` and the HTTP route; core enforces
265
+ * hybrid-only usage.
236
266
  */
237
- describeImage?: (imageBuffer: ArrayBuffer, meta: ExtractedImageMeta$1) => Promise<string>;
267
+ enableRerank?: boolean;
238
268
  /**
239
- * Entity-extraction callback. Receives text windows and image descriptions
240
- * separately so callers can apply different prompts per source. Triggers
241
- * the `X-Pyx-Enrichment-Capabilities: text_windows_v1` negotiation header
242
- * on ingest.
269
+ * Iterative multi-hop candidate generation (hybrid strategy only). After the
270
+ * first retrieval pass, non-oracle bridge entities are mined from the top
271
+ * seed passages, a second dense+lexical pass is seeded by those bridges, and
272
+ * both passes' ranked lists are fused into a single RRF before scoring and
273
+ * (optional) rerank-then-truncate. Grows the candidate pool to surface
274
+ * later-hop passages the single-pass query misses. Deterministic: no
275
+ * query-time LLM, fixed bridge order. Default off keeps the pipeline
276
+ * byte-identical. EMBEDDED ONLY: `MemoryClient.search` rejects it (the HTTP
277
+ * API does not forward it).
243
278
  */
244
- extractEntitiesV2?: (input: {
245
- textWindows: string[];
246
- imageDescriptions: string[];
247
- mimeType: string;
248
- filename: string;
249
- }) => Promise<{
250
- entities: IngestEntity$1[];
251
- relationships: IngestRelationship$1[];
252
- }>;
253
- }
254
- /**
255
- * Options for {@link MemoryClient.ingestFileEvents}. `signal` lets
256
- * long-running ingests (LLM enrichment + graph writes) be cancelled cleanly.
257
- *
258
- * `namespaceId` opts the upload into ReBAC AuthzPlan visibility — the server
259
- * thread the namespace through parsing → enrichment → store calls so the
260
- * resulting catalog row and chunk entries land in the named namespace
261
- * (server v0.17.4+; required when `requireNamespaceForTenantWrites=true`).
262
- */
263
- interface IngestFileOptions {
264
- description?: string;
265
- enrichment?: EnrichmentCallbacks;
266
- signal?: AbortSignal;
267
- namespaceId?: string;
279
+ enableMultiHop?: boolean;
268
280
  /**
269
- * Stable logical document identity used for replaceable content, image,
270
- * and graph projections. Requires `enrichment.extractEntitiesV2` so the
271
- * client can negotiate text windows and complete the stable replacement.
281
+ * Explicit bridge entities for the second multi-hop pass, bypassing mining.
282
+ * EVAL ONLY — used by the benchmark oracle-ceiling probe to isolate fusion
283
+ * capacity from mining quality; never set on a production path. Ignored
284
+ * unless `enableMultiHop` is also set.
272
285
  */
273
- documentKey?: string;
286
+ multiHopBridges?: string[];
274
287
  /**
275
- * Migration-only pinned file-ingestion catalog for this document's first
276
- * stable replacement. The server validates its exact scope and uses its
277
- * bounded provenance to detach legacy graph references. Omit this after the
278
- * stable anchor is established: the first pass may retire catalog-owned
279
- * projections, so later revisions should use `documentKey` alone.
288
+ * Set false for a read-only search that does NOT bump access counts /
289
+ * lastAccessed on returned entries. Access feeds ranking (WEIGHT_ACCESS and
290
+ * the no-eventTime recency fallback), so a measurement that searches the
291
+ * store mutates what it measures — repeated benchmark runs over a persisted
292
+ * index drift. Default true (access tracking is the product's usage signal).
280
293
  */
281
- catalogEntryId?: string;
282
- }
283
- /**
284
- * Options for {@link MemoryClient.graphEnrichFileEvents}. `documentKey` is the
285
- * caller's stable logical identity for the document whose graph is being
286
- * rebuilt — the server derives the graph anchor id from
287
- * (tenant, namespace, documentKey), so repeating the same key replaces the
288
- * document's graph references instead of multiplying them.
289
- *
290
- * `enrichment.extractEntitiesV2` is required: graph-only re-enrichment is
291
- * caller-extraction by definition (there is no server-side fallback).
292
- */
293
- interface GraphEnrichFileOptions {
294
- documentKey: string;
294
+ trackAccess?: boolean;
295
295
  /**
296
- * Migration-only pinned file-ingestion catalog for the first stable graph
297
- * replacement. The server resolves it in the current tenant/namespace and
298
- * detaches its bounded graph references. Omit it on later revisions once
299
- * the `documentKey` anchor exists.
300
- */
301
- catalogEntryId?: string;
302
- namespaceId?: string;
303
- signal?: AbortSignal;
304
- enrichment: EnrichmentCallbacks;
305
- }
306
- interface FileDownloadOptions {
307
- /** Stable logical document identity used by documentKey-aware ingest. */
308
- documentKey?: string;
309
- /** Exact namespace containing the uploaded document. */
310
- namespaceId?: string;
311
- }
312
- /**
313
- * Caller-supplied enrichment for the per-call store path. Mirrors
314
- * {@link EnrichmentCallbacks} for file ingest. When supplied, the SDK invokes
315
- * the callback and merges the result into the payload before POSTing. Without
316
- * a callback, server-side text/entity extraction can run only when the server
317
- * has an extraction brain configured; otherwise callers must pass graph data
318
- * or use caller-side hooks. Images always require caller-provided
319
- * descriptions/hooks.
320
- */
321
- interface StoreEnrichmentCallbacks {
322
- /**
323
- * Extract entities + relationships from `content`. The caller's LLM does
324
- * the work; the SDK passes the result through {@link mergeExtractedEntities}
325
- * (caller-wins, case-insensitive) before sending to the server.
326
- *
327
- * Skipped when `entry.extractEntities === false`. When
328
- * `entry.extractEntities === true` but this callback is not supplied,
329
- * `MemoryClient.store()` forwards the hint so the server-side extraction
330
- * brain can run and loud-fail if it is not configured.
331
- */
332
- extractEntities?: (input: {
333
- content: string;
334
- metadata?: Record<string, unknown>;
335
- signal?: AbortSignal;
336
- }) => Promise<EntityExtractionResult$1>;
337
- }
338
- /** Options accepted by {@link MemoryClient.store}. */
339
- interface StoreOptions {
340
- enrichment?: StoreEnrichmentCallbacks;
341
- /** Propagated into the `extractEntities` callback and the underlying fetch. */
342
- signal?: AbortSignal;
343
- /** Stable logical request key. Reuse this exact value after a lost response. */
344
- idempotencyKey?: string;
345
- }
346
- interface RequestAuthorityOptions {
347
- /** Stable logical request key. Reuse this exact value after a lost response. */
348
- idempotencyKey?: string;
349
- }
350
- /** Error thrown by MemoryClient when the server returns a non-success response. */
351
- declare class MemoryServerError extends Error {
352
- readonly status: number;
353
- /** Stable machine-readable discriminator returned by the memory server. */
354
- readonly code?: string;
355
- /** Exact HTTP Retry-After value returned by the memory server. */
356
- readonly retryAfter?: string;
357
- /** Retry delay normalized to seconds when Retry-After is parseable. */
358
- readonly retryAfterSeconds?: number;
359
- constructor(message: string, status: number, code?: string, retryAfter?: string);
360
- /** True when the server returned HTTP 404 (not found). */
361
- get isNotFound(): boolean;
362
- }
363
- interface MemoryClientOptions {
364
- /** API key for authentication. */
365
- apiKey?: string;
366
- /** Additional headers to send with every request (e.g., X-Caller-Access-Level). */
367
- defaultHeaders?: Record<string, string>;
368
- /**
369
- * Default per-request timeout in milliseconds. Without this, a wedged
370
- * memory server (e.g. event-loop blocked by inference) makes every
371
- * caller hang forever — that was the Korens demo wedge in 2026-04 where
372
- * a 161-second pyx-memory stall propagated through the runtime to the
373
- * browser. Defaults to 30 s, which is high enough that normal
374
- * `/search` and `/stats` requests never hit it but low enough that a
375
- * stuck server fails loudly.
376
- *
377
- * Only applied when the caller does NOT pass their own `signal` via
378
- * RequestInit. Long-running operations (large `consolidate`, `reindex`,
379
- * file ingest with enrichment) should pass their own AbortSignal —
380
- * that signal fully replaces the default ceiling.
381
- */
382
- requestTimeoutMs?: number;
383
- }
384
- declare class MemoryClient implements ExtendedMemoryInterface {
385
- protected baseUrl: string;
386
- private readonly _authHeaders;
387
- private readonly _requestTimeoutMs;
388
- constructor(memoryUrl: string, apiKeyOrOptions?: string | MemoryClientOptions);
389
- /** Encode a path segment to prevent URL injection */
390
- private encodePathSegment;
391
- private authorityHeaders;
392
- private exactReadAuthority;
393
- initialize(): Promise<void>;
394
- store(entry: StoreInput$1, options?: StoreOptions): Promise<MemoryEntry$1>;
395
- search(params: MemorySearchParams$1, authority?: RequestAuthorityOptions & Pick<TenantScopeOptions, 'tenantId' | 'namespaceId'>): Promise<MemorySearchResult$1>;
396
- get(id: string, authority?: TenantScopeOptions & RequestAuthorityOptions): Promise<MemoryEntry$1 | null>;
397
- delete(id: string, authority?: TenantScopeOptions & RequestAuthorityOptions): Promise<boolean>;
398
- clearSession(sessionId: string): Promise<number>;
399
- stats(options?: TenantScopeOptions): Promise<MemoryStats$1>;
400
- insights(options?: TenantScopeOptions & RequestAuthorityOptions): Promise<MemoryInsights$1>;
401
- /**
402
- * Fetch the running server's topology snapshot (build variant, declared
403
- * role, embedding location, active model profile). Round-trips the
404
- * server's `GET /status` envelope through {@link fetchApi}, surfacing any
405
- * non-success response as {@link MemoryServerError}. Auth-header
406
- * forwarding is unchanged from other client methods even though `/status`
407
- * is server-side public — the server simply ignores credentials on that
408
- * route.
409
- */
410
- status(): Promise<Topology$1>;
411
- shutdown(): Promise<void>;
412
- list(params?: MemoryListParams, authority?: RequestAuthorityOptions & Pick<TenantScopeOptions, 'tenantId' | 'namespaceId'>): Promise<MemoryListResult>;
413
- /**
414
- * Native streaming file ingest. Yields typed {@link IngestEvent}s as the
415
- * server (parsing/storing) and the SDK (enrichment/result) make progress.
416
- *
417
- * Wire contract: SDK POSTs with `Accept: application/x-ndjson`; the server
418
- * MUST respond with NDJSON. There is no JSON fallback — older servers
419
- * that emit `application/json` for this endpoint are not supported, and
420
- * the SDK yields a terminal `error` event in that case.
421
- *
422
- * After the server's terminal `result`, the SDK runs its own enrichment
423
- * phase (image-describe → entity-extract → `/enrich` POST), emitting
424
- * progress + heartbeat events around each step, then yields the single
425
- * terminal `result` event with the merged SDK + server result.
426
- *
427
- * Promise-shaped consumers should iterate the returned AsyncIterable and
428
- * collect the terminal event; there is no separate `ingestFile()` Promise
429
- * method by design (one wire format, one SDK method).
430
- */
431
- ingestFileEvents(file: File, options?: IngestFileOptions): AsyncIterable<IngestEvent$1>;
432
- /**
433
- * Graph-only re-enrichment for a document whose chunks are already stored
434
- * and searchable but whose graph build failed. Uploads the original to
435
- * `/api/memory/graph/enrich/file` (prepare-only — the server performs zero
436
- * store/delete before the final graph write), runs the SAME enrichment
437
- * callback engine as {@link ingestFileEvents}, then finalizes into one
438
- * stable graph anchor keyed by `documentKey`. Repeating the same key
439
- * replaces the document's graph references idempotently.
440
- *
441
- * The terminal `result` is a {@link GraphEnrichResult} event carrying the
442
- * ACTUAL persisted graph counts; abort and failures yield a terminal
443
- * `error` event instead (the server retains the pending session for retry).
444
- */
445
- graphEnrichFileEvents(file: File, options: GraphEnrichFileOptions): AsyncIterable<GraphEnrichEvent$1>;
446
- /**
447
- * POST a multipart body to an NDJSON streaming endpoint and relay its
448
- * progress/heartbeat events. Returns the raw terminal `result` record, or
449
- * null after yielding a terminal error (transport failure, server error
450
- * event, non-NDJSON response, stream ending without a result). One
451
- * implementation for both streaming surfaces so the wire protocol cannot
452
- * fork.
296
+ * Retrieval EFFORT tier (H8 slice 1b) — admits candidates by activation
297
+ * strength BEFORE RRF fusion (like LLM thinking-mode depth): `quick` = the
298
+ * strongest (sharpest top), `medium` = strong+mid, `deep` = everything
299
+ * including cold + superseded + archived rows. **Omitted ⇒ byte-identical to
300
+ * pre-1b behavior** (no activation lookup; all rows admitted, superseded/
301
+ * archived hidden as in 1a). Strength rises only via `Memory.reinforce` (recall
302
+ * reinforces); idle alone never revives. See `docs/H8-MEMORY-MODEL-DESIGN.md`.
453
303
  */
454
- private streamNdjsonUpload;
304
+ effort?: 'quick' | 'medium' | 'deep';
305
+ /** Maximum sensitivity level to include in results. Entries above this level are excluded. */
306
+ maxSensitivity?: SensitivityLevel;
307
+ /** Tenant ID for multi-tenant isolation. */
308
+ tenantId?: string;
309
+ /** User ID within the tenant. */
310
+ userId?: string;
311
+ /** Team/group ID within the tenant. */
312
+ teamId?: string;
455
313
  /**
456
- * Run the SDK-side enrichment phase for an ingest result and yield the
457
- * single terminal {@link IngestResultEvent} at the end. Skips work cleanly
458
- * when the server emitted no enrichment block or the caller wired no
459
- * callbacks. The callback work itself lives in
460
- * {@link runEnrichmentCallbacks} — shared with the graph-only surface.
314
+ * Exact namespace requested by a trusted transport boundary. `Memory.search`
315
+ * validates it against the calling principal's AuthzPlan and compiles it to
316
+ * a singleton prefilter. Exact scope excludes legacy NULL rows.
461
317
  */
462
- private completeIngestFileEvents;
318
+ namespaceId?: string;
463
319
  /**
464
- * The ONE enrichment callback engine, shared by {@link ingestFileEvents}
465
- * and {@link graphEnrichFileEvents}: fetches extracted images, invokes
466
- * `describeImage` with bounded concurrency, invokes `extractEntitiesV2`
467
- * exactly once, and POSTs `/files/{fileId}/enrich` — emitting progress and
468
- * heartbeat events around each slow step. Throws on any failure; the
469
- * purpose-specific wrappers translate that into their terminal error.
320
+ * AuthzPlan-derived visibility list. Populated internally by `Memory.search`
321
+ * after computing the plan from the calling principal — callers should
322
+ * NOT set this directly. Empty array means "no granted namespaces" (only
323
+ * legacy NULL-namespace entries are visible). `undefined` skips the
324
+ * filter (single-tenant / pre-ReBAC compat).
470
325
  *
471
- * Legacy ingest keeps its existing partial add-on behavior. Graph-only and
472
- * documentKey-aware full ingest may replace a prior graph only from a
473
- * complete input set (no truncated text windows or undescribed images). A
474
- * complete extractor result containing zero entities remains a valid clear.
475
- */
476
- private runEnrichmentCallbacks;
477
- /**
478
- * Race a Promise against a periodic heartbeat tick. Yields a heartbeat
479
- * IngestEvent every {@link INGEST_EVENT_HEARTBEAT_MS} until the promise
480
- * settles, then returns the resolved value (or rethrows). Lets callers
481
- * keep upstream sockets alive through long LLM/HTTP work without
482
- * coupling the heartbeat cadence to the work itself.
326
+ * Callers must not set this directly; use `namespaceId` for exact scope.
483
327
  */
484
- private withSdkHeartbeats;
485
- private normalizeActiveIngestStage;
486
- private fileIngestResultFromEvent;
487
- private ingestErrorEvent;
328
+ namespaceIds?: string[];
329
+ /** Strict namespace equality compiled internally from `namespaceId`. */
330
+ exactNamespaceId?: string;
488
331
  /**
489
- * Get the download URL for an uploaded file.
490
- * Returns a URL that serves the original file binary with proper Content-Type.
332
+ * AuthzPlan-derived list of strict-mode namespaces in the caller's
333
+ * tenant the principal CANNOT see (v0.17.0). Graph traversal MUST
334
+ * drop edges whose `namespace_id` matches the supplied set even when
335
+ * the surrounding KG node is otherwise reachable. Populated
336
+ * internally by `Memory.search` from `AuthzPlan.forbiddenStrict
337
+ * NamespaceIds` — callers should NOT set this directly.
491
338
  */
492
- getFileDownloadUrl(filename: string, options?: FileDownloadOptions): string;
339
+ forbiddenStrictNamespaceIds?: string[];
340
+ }
341
+ interface MemorySearchResult {
342
+ entries: MemoryEntry[];
343
+ totalCount: number;
344
+ strategy: RAGStrategy;
345
+ /** Visible graph slice that supported the returned entries, when graph traversal contributed. */
346
+ graph?: GraphTraversalResult;
493
347
  /**
494
- * Download an uploaded file by filename.
495
- * Returns the raw Response (caller handles the body — arrayBuffer, blob, stream, etc.).
348
+ * Optional scored entries for ranked results. `score` is the fused RANK score
349
+ * (RRF + recency/importance/access priors) — good for ordering, NOT a relevance
350
+ * magnitude. `vectorSimilarity` is the raw dense query-similarity (LanceDB
351
+ * transformed-L2, 1/(1+distance)); null when the entry has no dense signal
352
+ * (FTS/graph-only). Surface vectorSimilarity, not score, as a "% match".
496
353
  */
497
- downloadFile(filename: string, options?: FileDownloadOptions): Promise<Response>;
498
- /** @deprecated Use {@link list} instead. Kept for backwards compatibility. */
499
- listEntries(params?: {
500
- page?: number;
501
- limit?: number;
502
- }): Promise<MemoryEntry$1[]>;
503
- graphNodes(): Promise<GraphNode$1[]>;
504
- graphEdges(): Promise<{
505
- stats: {
506
- nodeCount: number;
507
- edgeCount: number;
508
- rawNodeCount?: number;
509
- rawEdgeCount?: number;
510
- };
354
+ scoredEntries?: Array<{
355
+ entry: MemoryEntry;
356
+ score: number;
357
+ vectorSimilarity?: number | null;
511
358
  }>;
512
- graphQuery(query: {
513
- nodeId: string;
514
- depth?: number;
515
- }): Promise<GraphTraversalResult$1>;
516
- consolidate(): Promise<ConsolidationRunResult>;
517
- forget(id: string, reason?: string): Promise<boolean>;
518
- summarizeSession(sessionId: string): Promise<MemoryEntry$1 | null>;
519
- lint(options?: {
520
- limit?: number;
521
- }): Promise<WikiLintReport$1>;
522
- runDecay(): Promise<number>;
523
- reindex(): Promise<void>;
524
- clearGraph(): Promise<number>;
525
- repairGraph(): Promise<GraphRepairResult$1>;
526
- deleteBySource(source: string, authority?: TenantScopeOptions): Promise<number>;
527
- setFolder(from: string, to: string, options?: {
528
- dryRun?: boolean;
529
- }): Promise<{
530
- from: string;
531
- to: string;
532
- updated: number;
533
- dryRun: boolean;
534
- }>;
535
- queryAsOf(asOfDate: string, filters?: TemporalQueryFilters, authority?: TenantScopeOptions): Promise<MemoryEntry$1[]>;
536
- lineage(params: LineageParams$1, authority?: RequestAuthorityOptions): Promise<LineageResult$1>;
537
- reinforce(params: ReinforceParams$1, authority?: RequestAuthorityOptions): Promise<ReinforceResult$1>;
538
- log(filters?: MemoryLogFilters): Promise<MemoryEntry$1[]>;
539
- queryByEventTime(startTime: string, endTime: string, filters?: TemporalQueryFilters): Promise<MemoryEntry$1[]>;
540
- summarizeEntity(name: string): Promise<MemoryEntry$1>;
541
- getEntitySynthesis(name: string): Promise<MemoryEntry$1 | null>;
542
- /**
543
- * v0.26 user-profile snapshot — upsert. The server derives `userId`
544
- * from `X-User-Id` (caller wires it via `defaultHeaders` on the
545
- * client constructor or per-request middleware); the body cannot
546
- * override it. See spec §Requirements 10.
547
- */
548
- upsertUserProfile(input: {
549
- namespaceId: string;
550
- content: string;
551
- }): Promise<{
552
- updatedAt: string;
553
- contentSize: number;
554
- }>;
555
- /**
556
- * v0.26 user-profile snapshot — fetch by namespace. Returns `null` on
557
- * HTTP 404 (`isNotFound`), rethrows any other non-2xx as
558
- * `MemoryServerError`. Mirrors `get()`'s 404-to-null pattern so callers
559
- * can branch on "no profile yet" without inspecting status codes.
560
- */
561
- getUserProfile(namespaceId: string): Promise<{
562
- content: string;
563
- updatedAt: string;
564
- contentSize: number;
565
- } | null>;
566
- /**
567
- * v0.28 correction-memory — record an explicit correction. POSTs to
568
- * `/api/memory/corrections`; tenant is header-derived (server-side), so
569
- * the body carries only the correction fields. Returns `{ id, createdAt }`.
570
- */
571
- recordCorrection(input: {
572
- /** Omit in single-tenant deployments — corrections are stored namespace-free. */
573
- namespaceId?: string;
574
- whatWasWrong: string;
575
- whatToDoInstead: string;
576
- appliesWhen: string;
577
- project?: string;
578
- taskShape?: string;
579
- }): Promise<{
580
- id: string;
581
- createdAt: string;
582
- }>;
583
- /**
584
- * v0.28 correction-memory — fetch the corrections applicable to a task
585
- * shape. GETs `/api/memory/corrections`; returns `[]` when none have
586
- * positive overlap. pyx never auto-prepends — the agent owns inclusion.
587
- */
588
- fetchApplicableCorrections(input: {
589
- /** Omit in single-tenant deployments — reads the namespace-free scope. */
590
- namespaceId?: string;
591
- taskShape: string;
592
- project?: string;
593
- limit?: number;
594
- }): Promise<CorrectionRecord$1[]>;
595
- /**
596
- * H26 B-d — deterministic prospective due-scan: entries with
597
- * `eventTime ∈ [from, from+windowDays]` (inclusive), eventTime ascending,
598
- * no relevance ranking. `GET /api/memory/due`.
599
- */
600
- dueScan(input: {
601
- windowDays: number;
602
- from?: string;
603
- /** Omit in single-tenant deployments. */
604
- namespaceId?: string;
605
- limit?: number;
606
- }): Promise<MemoryEntry$1[]>;
607
- protected fetchApi<T>(path: string, options?: RequestInit): Promise<T>;
608
- /**
609
- * Map fetch-layer rejections into a typed `MemoryServerError` so callers
610
- * can react uniformly. AbortSignal.timeout fires a `TimeoutError`; the
611
- * caller's signal generally fires an `AbortError`. Anything else (DNS,
612
- * TCP reset, TLS) becomes a wrapped error with status 0.
613
- */
614
- private translateFetchError;
615
- /** Parse and validate a JSON API response, throwing MemoryServerError on any failure. */
616
- private parseApiResponse;
359
+ /** Confidence assessment for abstention. Present when search produces scored entries. */
360
+ confidence?: {
361
+ /** Overall confidence 0.0–1.0. */
362
+ confidence: number;
363
+ /** Whether the system recommends abstaining (confidence below threshold). */
364
+ shouldAbstain: boolean;
365
+ /** Raw signals used to compute confidence. */
366
+ signals: {
367
+ topScore: number;
368
+ scoreGap: number;
369
+ scoreStdDev: number;
370
+ resultCount: number;
371
+ aboveThresholdRatio: number;
372
+ scoreSeparation: number;
373
+ };
374
+ };
617
375
  }
618
-
619
- interface IngestionResult {
620
- filename: string;
621
- fileType: string;
622
- chunks: number;
623
- entryIds: string[];
624
- totalCharacters: number;
376
+ /** One version in a fact's history, as returned by {@link LineageResult}. */
377
+ interface LineageVersion {
378
+ entryId: string;
379
+ /** The entry content carrying this version's value. */
380
+ value: string;
381
+ eventTime?: string;
382
+ ingestTime?: string;
383
+ status: 'active' | 'superseded' | 'archived';
384
+ /** Set when this version was superseded by a newer entry. */
385
+ supersededByEntryId?: string;
625
386
  }
626
-
627
- declare const DEFAULTS: {
628
- readonly DATA_DIR: "./data";
629
- readonly VECTOR_PROVIDER: "lancedb";
630
- readonly MEMORY_SERVER_PORT: 7822;
631
- };
632
- declare const TAXONOMY_MAX_CATEGORIES = 10;
633
- declare const TAXONOMY_MAX_TOP_ENTITIES = 15;
634
- declare const TAXONOMY_MAX_SAMPLE_TOPICS = 8;
635
- declare const TAXONOMY_MAX_PROJECTS = 8;
636
- declare const MEMORY_PROJECT_LABEL_MAX_CHARS = 80;
637
-
638
- /** ISO 8601 timestamp string */
639
- type Timestamp = string;
640
- /** Unique agent identifier */
641
- type AgentId = string;
642
-
643
387
  /**
644
- * Caller identity for ReBAC authorization.
645
- *
646
- * The canonical "subject" in Zanzibar terms — passed alongside requests so the
647
- * memory layer can compute an AuthzPlan (visible namespaces + entry overrides)
648
- * before any retrieval source fans out.
649
- *
650
- * Identity comes from authenticated request context (X-Tenant-Id / auth token
651
- * claims), never from request bodies or multipart form fields. The legacy
652
- * `userId` / `teamId` / `agentId` columns on MemoryEntry remain for audit and
653
- * legacy filters but MUST NOT drive authorization decisions — they are
654
- * collision-prone aliases (a service principal sharing an ID with a human
655
- * user has no protection against confused-deputy attacks).
656
- *
657
- * Sensitivity / clearance is intentionally NOT on this object. It is a
658
- * MAC-style classification, orthogonal to RBAC, and continues to be carried
659
- * via the `X-Caller-Access-Level` header → `MemorySearchParams.maxSensitivity`.
660
- * Conflating the two couples future changes (e.g. per-namespace classification
661
- * rules) to identity propagation.
388
+ * Query for the evolution of a fact (H8 `Memory.lineage`). Provide either a
389
+ * `subject` (+ optional `relation`) for graph-backed subject/relation lineage,
390
+ * OR an `entryId` to walk the `supersededBy` chain (the only mode available
391
+ * without a graph store).
662
392
  */
663
- interface PrincipalContext {
664
- /**
665
- * Hard isolation boundary. Required even in single-tenant deployments —
666
- * single-mode passes a stable sentinel (`SINGLE_TENANT_ID`) so authz code
667
- * paths look identical regardless of mode.
668
- */
669
- tenantId: string;
670
- /**
671
- * Stable subject ID (within the tenant). For humans this is the userId;
672
- * for AI runtimes it is the agentId; for system actors it is a service
673
- * identifier. Combined with `kind`, forms the Zanzibar subject coordinate
674
- * `<kind>:<principalId>`.
675
- */
676
- principalId: string;
677
- /**
678
- * Subject namespace. Distinguishes humans from AI agents from internal
679
- * services so a userId/agentId/serviceId collision cannot grant
680
- * unintended access.
681
- * - `user`: human end user
682
- * - `agent`: AI runtime acting on a user's behalf or autonomously
683
- * - `service`: non-AI internal system (cron, ETL, admin tooling)
684
- */
685
- kind: 'user' | 'agent' | 'service';
393
+ interface LineageParams {
394
+ subject?: string;
395
+ relation?: string;
396
+ entryId?: string;
397
+ /** Current version as of this time (newest version with eventTime ≤ asOf). */
398
+ asOf?: string;
399
+ eventTimeRange?: [string, string];
400
+ /** Return only versions strictly older than the version holding this value. */
401
+ beforeValue?: string;
402
+ limit?: number;
403
+ }
404
+ interface LineageResult {
405
+ subject?: string;
406
+ relation?: string;
407
+ /** Event-time ascending (oldest → newest). */
408
+ versions: LineageVersion[];
409
+ /** Which path answered — honest provenance (graph conflict-group vs supersededBy chain). */
410
+ source: 'graph' | 'chain';
686
411
  }
687
- /** Sentinel tenant ID used in single-tenant deployments. */
688
- declare const SINGLE_TENANT_ID = "_single";
689
-
690
- declare const MemoryType: {
691
- readonly SHORT_TERM: "short-term";
692
- readonly LONG_TERM: "long-term";
693
- readonly WORKING: "working";
694
- readonly EPISODIC: "episodic";
695
- readonly SUMMARY: "summary";
696
- };
697
- type MemoryType = (typeof MemoryType)[keyof typeof MemoryType];
698
- declare const SensitivityLevel: {
699
- readonly PUBLIC: "public";
700
- readonly INTERNAL: "internal";
701
- readonly SECRET: "secret";
702
- };
703
- type SensitivityLevel = (typeof SensitivityLevel)[keyof typeof SensitivityLevel];
704
- declare const RAGStrategy: {
705
- readonly NAIVE: "naive";
706
- readonly GRAPH: "graph";
707
- readonly HYBRID: "hybrid";
708
- };
709
- type RAGStrategy = (typeof RAGStrategy)[keyof typeof RAGStrategy];
710
412
  /**
711
- * Strategy identifiers that were public in earlier versions and have been
712
- * removed. Server/SDK reject requests using these with a stable
713
- * `strategy.deprecated:<name>` error code (not the generic "invalid
714
- * strategy" message) so callers and dashboards can detect the removal
715
- * cleanly across a version bump.
716
- *
717
- * v0.26: `agentic` removed (Codex pair: silent-catch in agentic.ts
718
- * violated Production-ready; behavior subsumed by HybridRAGEngine).
413
+ * Explicit recall-usefulness signal for {@link MemorySearchParams} `reinforce`.
414
+ * `context_included` = surfaced into the working context (small η); `cited` =
415
+ * the agent actually used it in its answer (medium η); `explicit_positive` =
416
+ * user/agent marked it useful (large η). Mere top-k return is NOT a signal
417
+ * (determinism + "returned ≠ used") — only an explicit `reinforce()` call moves
418
+ * strength.
719
419
  */
720
- declare const DEPRECATED_RAG_STRATEGIES: ReadonlyMap<string, string>;
721
- declare const VectorProvider: {
722
- readonly LANCEDB: "lancedb";
723
- };
724
- type VectorProvider = (typeof VectorProvider)[keyof typeof VectorProvider];
725
- declare const EmbeddingProviderName: {
726
- readonly STUB: "stub";
727
- /** @deprecated Vestigial — pyx-memory uses internal EmbeddingGemma embeddings. */
728
- readonly ANTHROPIC: "anthropic";
729
- /** @deprecated Vestigial — pyx-memory uses internal EmbeddingGemma embeddings. */
730
- readonly OPENAI: "openai";
731
- /** In-process ONNX model (default: EmbeddingGemma-300M). */
732
- readonly LOCAL: "local";
733
- /** Remote OpenAI-compatible embedding service (pyx-cloud shared, custom, etc.). */
734
- readonly HTTP: "http";
735
- };
736
- type EmbeddingProviderName = (typeof EmbeddingProviderName)[keyof typeof EmbeddingProviderName];
737
- type GraphEnrichmentStatus = 'caller-provided' | 'extracted' | 'merged' | 'opted-out' | 'skipped-duplicate' | 'skipped-sensitive' | 'skipped-unprovisioned' | 'extracted-empty' | 'failed-graph-write' | 'failed-best-effort';
738
- interface GraphEnrichment {
739
- status: GraphEnrichmentStatus;
740
- provider?: 'http' | 'local' | 'none';
741
- reason?: string;
742
- action?: string;
420
+ type ReinforceSignal = 'context_included' | 'cited' | 'explicit_positive';
421
+ interface ReinforceParams {
422
+ entryIds: string[];
423
+ signal: ReinforceSignal;
424
+ /** When the recall happened — epoch-ms, or full ISO-8601 WITH timezone. Date-only / tz-free is rejected. Defaults to the activation clock. */
425
+ at?: string | number;
426
+ }
427
+ interface ReinforceResult {
428
+ /** Per-entry post-reinforce activation. Entries absent from the store are omitted. */
429
+ updated: Array<{
430
+ entryId: string;
431
+ strength: number;
432
+ tier: 'quick' | 'medium' | 'deep';
433
+ }>;
434
+ }
435
+ interface SourceEvidence {
436
+ /** Memory entry that produced this graph fact. */
437
+ memoryEntryId: string;
438
+ /** Data tenant of the source entry. `null` = single-tenant / legacy data. */
439
+ tenantId?: string | null;
440
+ /** Namespace of the source memory entry. `null` = legacy / tenant-root. */
441
+ namespaceId?: string | null;
442
+ /** Optional source identifier copied from the memory entry or caller. */
443
+ source?: string;
444
+ /** Optional content hash copied from the memory entry or caller. */
445
+ contentHash?: string;
446
+ /** Optional short text evidence for the graph fact. */
447
+ snippet?: string;
448
+ /** When this evidence was recorded. */
449
+ createdAt?: Timestamp;
743
450
  }
744
- /**
745
- * A caller-supplied relationship whose source or target name did not resolve to
746
- * any entity in the same store call (after name normalization), so the edge was
747
- * not written. Surfaced on the store response so the agent — not just the server
748
- * log — can see which edges to re-send.
749
- */
750
- interface DroppedGraphRelationship {
451
+ declare const StoreTarget: {
452
+ readonly SQLITE: "sqlite";
453
+ readonly VECTOR: "vector";
454
+ readonly GRAPH: "graph";
455
+ };
456
+ type StoreTarget = (typeof StoreTarget)[keyof typeof StoreTarget];
457
+ /** Agent-provided entity for graph storage. */
458
+ interface IngestEntity {
459
+ /** Entity name (e.g., "Alice", "TypeScript"). */
460
+ name: string;
461
+ /** Entity type — freeform, agent decides (e.g., "PERSON", "TOOL"). */
462
+ type: string;
463
+ /** Stable canonical identifier. Defaults to a deterministic name+type id. */
464
+ canonicalId?: string;
465
+ /** Source evidence for this graph node. Defaults to the containing memory entry. */
466
+ sourceEvidence?: SourceEvidence[];
467
+ /** Optional properties to attach to the graph node. */
468
+ properties?: Record<string, unknown>;
469
+ }
470
+ /** Agent-provided relationship for graph storage. */
471
+ interface IngestRelationship {
472
+ /** Source entity name (must match an entity in the entities array). */
751
473
  source: string;
474
+ /** Target entity name (must match an entity in the entities array). */
752
475
  target: string;
476
+ /** Relationship type — freeform, agent decides (e.g., "WORKS_AT", "USES"). */
753
477
  type: string;
478
+ /** Source evidence for this graph edge. Defaults to the containing memory entry. */
479
+ sourceEvidence?: SourceEvidence[];
480
+ /** Optional properties to attach to the graph edge. */
481
+ properties?: Record<string, unknown>;
754
482
  }
755
- type VectorStatus = 'pending' | 'stored' | 'skipped';
756
- interface MemoryEntry {
483
+ /**
484
+ * How `Memory.store()` should react when the graph write fails.
485
+ * - `throw` (default, since v0.13.0): propagate the failure so the caller
486
+ * knows the graph is incomplete. Honest contract: a graph write either
487
+ * commits or fails loudly. Silent partial-loss was the v0.12.2 bug that
488
+ * masked 91/92 dropped entities.
489
+ * - `best-effort`: swallow the error and log a warning; the entry is still
490
+ * considered ingested in SQLite/vector. Use only when you genuinely don't
491
+ * need the graph slice and a transient neo4j blip shouldn't fail ingest.
492
+ */
493
+ type GraphFailureMode = 'throw' | 'best-effort';
494
+ /** Store input: what the agent sends to Memory.store(). */
495
+ type StoreInput = Omit<MemoryEntry, 'id' | 'createdAt'> & {
496
+ id?: string;
497
+ createdAt?: string;
498
+ /** Storage targets. Default: ["sqlite", "vector"]. */
499
+ targets?: StoreTarget[];
500
+ /** Agent-provided entities for graph storage. */
501
+ entities?: IngestEntity[];
502
+ /** Agent-provided relationships for graph storage. */
503
+ relationships?: IngestRelationship[];
504
+ /** Override graph entity extraction for this store call. */
505
+ extractEntities?: boolean;
506
+ /** Graph-failure handling. Default: "throw" (loud) — see GraphFailureMode. */
507
+ graphFailureMode?: GraphFailureMode;
508
+ };
509
+ /**
510
+ * `Memory.expand()` input (eng-pull FD2): `baseEntryIds` is the caller's
511
+ * declared context in ITS order (dedupe set only; ids need not resolve);
512
+ * `anchorEntryIds` ⊆ base, in the caller's priority order.
513
+ */
514
+ type ExpandParams = {
515
+ baseEntryIds: string[];
516
+ anchorEntryIds: string[];
517
+ };
518
+ type ExpandAnchorStatus = {
757
519
  id: string;
758
- content: string;
759
- type: MemoryType;
760
- agentId?: AgentId;
520
+ status: 'expanded';
521
+ sessionId: string;
522
+ sessionOrdinal: number;
523
+ } | {
524
+ id: string;
525
+ status: 'not_expandable';
526
+ reason: 'not_found' | 'not_active' | 'no_ordinal';
527
+ };
528
+ /** `added` = full entries in admission order (±1 then ±2 per anchor, anchors in request order). */
529
+ interface ExpandResult {
530
+ added: MemoryEntry[];
531
+ anchors: ExpandAnchorStatus[];
532
+ }
533
+ interface MemoryIngestRequest {
534
+ content?: string;
535
+ type?: MemoryType;
536
+ metadata?: Record<string, unknown>;
537
+ agentId?: string;
761
538
  sessionId?: string;
762
- metadata: Record<string, unknown>;
763
- /** @deprecated Vestigial — embeddings are managed internally by the vector store. */
764
- embedding?: number[];
765
- createdAt: Timestamp;
766
- /** SHA-256 hash of content for deduplication. */
767
- contentHash?: string;
539
+ sessionOrdinal?: number;
540
+ /** Storage targets. Default: ["sqlite", "vector"]. */
541
+ targets?: StoreTarget[];
542
+ /** Agent-provided entities for graph storage. */
543
+ entities?: IngestEntity[];
544
+ /** Agent-provided relationships for graph storage. */
545
+ relationships?: IngestRelationship[];
546
+ /** Override graph entity extraction for this ingest request. */
547
+ extractEntities?: boolean;
548
+ /** Graph-failure handling. Default: "throw" (loud) — see GraphFailureMode. */
549
+ graphFailureMode?: GraphFailureMode;
768
550
  /** Importance score (1-10). */
769
551
  importance?: number;
770
- /** Number of times this entry has been accessed via search. */
771
- accessCount?: number;
772
- /** ISO timestamp of last access via search. */
773
- lastAccessed?: string;
774
- /** Parent entry ID for hierarchical storage (e.g., doc → section → chunk). */
775
- parentId?: string;
776
- /** Source identifier (e.g., filename, URL, session). */
552
+ /** Source identifier (e.g., filename, URL). */
777
553
  source?: string;
778
- /** When the event described by this memory occurred. */
554
+ /** When the event occurred (ISO timestamp). */
779
555
  eventTime?: string;
780
- /** When this entry was ingested into the system. */
781
- ingestTime?: string;
782
- /** Sensitivity classification based on content analysis. */
783
- sensitivity?: SensitivityLevel;
784
- /** Whether the content field is encrypted at rest. */
785
- encrypted?: boolean;
786
- /** Number of graph entities written by this store call. Present on store responses. */
787
- graphEntitiesWritten?: number;
788
- /** Number of graph relationships written by this store call. Present on store responses. */
789
- graphRelationshipsWritten?: number;
790
- /** Count of caller relationships dropped because an endpoint name did not match any entity in the call. Present (and >0) only when edges were dropped. */
791
- graphRelationshipsDropped?: number;
792
- /** Up to 20 of the dropped relationships (source/target/type), so the agent can re-send them. Present only when edges were dropped. */
793
- graphRelationshipsDroppedDetail?: DroppedGraphRelationship[];
794
- /** Graph extraction/enrichment outcome for this store call. Present on graph-targeted store responses. */
795
- graphEnrichment?: GraphEnrichment;
796
- /** Store response vector outcome. Pending means SQLite is durable and vector indexing is eventually consistent. */
797
- vectorStatus?: VectorStatus;
798
- /** Tenant ID for multi-tenant isolation. */
799
- tenantId?: string;
800
- /** User ID within the tenant. */
801
- userId?: string;
802
- /** Team/group ID within the tenant. */
803
- teamId?: string;
804
- /**
805
- * Namespace ID — the primary protected resource for ReBAC authorization.
806
- * `undefined` (NULL on the row) means the entry lives in the legacy
807
- * "tenant-root" bucket and is visible to anyone with tenant access (the
808
- * pre-ReBAC posture). Setting `namespaceId` opts the entry into AuthzPlan-
809
- * based filtering, where visibility is computed from `authz_tuples` for
810
- * the calling principal.
811
- */
812
- namespaceId?: string;
813
- /**
814
- * When true, consolidation leaves this entry alone — it is never archived by
815
- * decay and never merged (nor merged-into) by semantic deduplication. Use for
816
- * stable anchor entries whose ID is referenced by external systems (e.g. a
817
- * file-catalog row pointed at by another service's foreign key).
818
- */
819
- pinned?: boolean;
820
- /**
821
- * Lifecycle status (H8). Optional on write (absent means `'active'`), but
822
- * every entry READ back from the store carries it explicitly — a caller can
823
- * compare `entry.status === 'active'` without special-casing an absent field.
824
- * `'active'` is a normal retrievable entry. `'superseded'` means a newer near-duplicate
825
- * UPDATE replaced this one during consolidation. `'archived'` (1b) means decay
826
- * retired it (no successor) — kept, strength 0, `deep`-tier only. All three
827
- * are kept (history / lineage / deep recall) but `superseded`/`archived` are
828
- * excluded from default/quick/medium search. Only `forget()` and exact-byte-
829
- * duplicate collapse hard-delete. See `docs/H8-MEMORY-MODEL-DESIGN.md`.
830
- */
831
- status?: 'active' | 'superseded' | 'archived';
832
- /**
833
- * When `status==='superseded'`, the id of the newer entry that replaced this
834
- * one — the backward link used by `Memory.lineage()` chain traversal. Cleared
835
- * to NULL (never resurrected to active) if the successor is later forgotten.
836
- */
837
- supersededByEntryId?: string;
838
- /**
839
- * @internal Hosted data-plane only. SHA-256 of the canonical caller store
840
- * payload (server-stamped timestamps excluded), persisted for caller-id
841
- * stores so a re-send of the same `metadata.dbRef.revision` can be
842
- * classified as an idempotent no-op (digest match) or a
843
- * `revision_reuse_conflict` (digest mismatch). Graph entities/relationships
844
- * are part of the payload but not of the row, so the digest cannot be
845
- * recomputed from stored state.
846
- */
847
- payloadDigest?: string;
848
- }
849
- interface MemorySearchParams {
850
- query: string;
851
- type?: MemoryType;
852
- agentId?: AgentId;
853
- /** Optional caller session identifier used for in-process hygiene telemetry. */
854
- sessionId?: string;
855
- limit?: number;
856
- strategy?: RAGStrategy;
857
- /** Filter results to entries whose eventTime falls within [start, end] (ISO 8601). */
858
- eventTimeRange?: [string, string];
859
- /** Filter results to entries ingested before this cutoff (ISO 8601). Falls back to createdAt when ingestTime is null. */
860
- asOf?: string;
861
- /**
862
- * Soft recency ANCHOR (ISO 8601) — never a filter. Candidates are ranked by
863
- * proximity to this time instead of now, and conflicting assertions
864
- * re-order around it. Resolving relative-time expressions ("two months
865
- * ago", "3년 전") to an absolute timestamp is the CALLER's side of the
866
- * agentic contract — language understanding never enters the engine. Wins
867
- * over the query-text year parse (hybrid strategy).
868
- */
869
- anchorTime?: string;
870
- /**
871
- * The category the user is asking to count/list (e.g. "fitness classes",
872
- * "운동 수업", any language). Presence signals enumeration intent and supplies
873
- * the category for graph resolution; the caller (which understands the user's
874
- * language) sets it. When omitted, pyx falls back to a deterministic EN/KO
875
- * marker detector.
876
- */
877
- enumerationConcept?: string;
878
- /** Confidence threshold below which the system recommends abstention (0.0–1.0). Default: 0.3. */
879
- abstentionThreshold?: number;
880
- /**
881
- * Rerank with the cross-encoder before final truncation (hybrid strategy
882
- * only). The pipeline retrieves and dedups a deeper candidate pool (≥50),
883
- * scores it through the cross-encoder, then truncates to `limit` —
884
- * reranking after truncation cannot change top-`limit` set membership.
885
- * Forwarded by `MemoryClient.search` and the HTTP route; core enforces
886
- * hybrid-only usage.
887
- */
888
- enableRerank?: boolean;
889
- /**
890
- * Iterative multi-hop candidate generation (hybrid strategy only). After the
891
- * first retrieval pass, non-oracle bridge entities are mined from the top
892
- * seed passages, a second dense+lexical pass is seeded by those bridges, and
893
- * both passes' ranked lists are fused into a single RRF before scoring and
894
- * (optional) rerank-then-truncate. Grows the candidate pool to surface
895
- * later-hop passages the single-pass query misses. Deterministic: no
896
- * query-time LLM, fixed bridge order. Default off keeps the pipeline
897
- * byte-identical. EMBEDDED ONLY: `MemoryClient.search` rejects it (the HTTP
898
- * API does not forward it).
899
- */
900
- enableMultiHop?: boolean;
901
- /**
902
- * Explicit bridge entities for the second multi-hop pass, bypassing mining.
903
- * EVAL ONLY — used by the benchmark oracle-ceiling probe to isolate fusion
904
- * capacity from mining quality; never set on a production path. Ignored
905
- * unless `enableMultiHop` is also set.
906
- */
907
- multiHopBridges?: string[];
908
- /**
909
- * Set false for a read-only search that does NOT bump access counts /
910
- * lastAccessed on returned entries. Access feeds ranking (WEIGHT_ACCESS and
911
- * the no-eventTime recency fallback), so a measurement that searches the
912
- * store mutates what it measures — repeated benchmark runs over a persisted
913
- * index drift. Default true (access tracking is the product's usage signal).
914
- */
915
- trackAccess?: boolean;
916
- /**
917
- * Retrieval EFFORT tier (H8 slice 1b) — admits candidates by activation
918
- * strength BEFORE RRF fusion (like LLM thinking-mode depth): `quick` = the
919
- * strongest (sharpest top), `medium` = strong+mid, `deep` = everything
920
- * including cold + superseded + archived rows. **Omitted ⇒ byte-identical to
921
- * pre-1b behavior** (no activation lookup; all rows admitted, superseded/
922
- * archived hidden as in 1a). Strength rises only via `Memory.reinforce` (recall
923
- * reinforces); idle alone never revives. See `docs/H8-MEMORY-MODEL-DESIGN.md`.
924
- */
925
- effort?: 'quick' | 'medium' | 'deep';
926
- /** Maximum sensitivity level to include in results. Entries above this level are excluded. */
927
- maxSensitivity?: SensitivityLevel;
556
+ /** Optional deterministic ID for the entry (agent-provided). */
557
+ id?: string;
558
+ /** Parent entry ID for hierarchical storage (e.g., doc → section → chunk). */
559
+ parentId?: string;
560
+ /** When this entry was ingested (ISO timestamp). Default: now. */
561
+ ingestTime?: string;
928
562
  /** Tenant ID for multi-tenant isolation. */
929
563
  tenantId?: string;
930
564
  /** User ID within the tenant. */
931
565
  userId?: string;
932
566
  /** Team/group ID within the tenant. */
933
567
  teamId?: string;
934
- /**
935
- * Exact namespace requested by a trusted transport boundary. `Memory.search`
936
- * validates it against the calling principal's AuthzPlan and compiles it to
937
- * a singleton prefilter. Exact scope excludes legacy NULL rows.
938
- */
568
+ /** Namespace ID — see `MemoryEntry.namespaceId`. */
939
569
  namespaceId?: string;
940
570
  /**
941
- * AuthzPlan-derived visibility list. Populated internally by `Memory.search`
942
- * after computing the plan from the calling principal — callers should
943
- * NOT set this directly. Empty array means "no granted namespaces" (only
944
- * legacy NULL-namespace entries are visible). `undefined` skips the
945
- * filter (single-tenant / pre-ReBAC compat).
946
- *
947
- * Callers must not set this directly; use `namespaceId` for exact scope.
571
+ * Exclude this entry from consolidation (decay-archive and semantic dedup).
572
+ * See `MemoryEntry.pinned` for full semantics.
948
573
  */
949
- namespaceIds?: string[];
950
- /** Strict namespace equality compiled internally from `namespaceId`. */
951
- exactNamespaceId?: string;
574
+ pinned?: boolean;
575
+ }
576
+ /**
577
+ * Agent-recorded explicit correction ("you did X wrong; do Y instead").
578
+ * `Memory.recordCorrection` writes one pinned, sqlite-only entry; pyx does
579
+ * pure structural retrieval with zero LLM / embedding on this path. Scope is
580
+ * `(tenantId, namespaceId)` + optional `project` — NOT per-user, because a
581
+ * correction about how to do X in this project is namespace-shared. No
582
+ * `confidence` field by design: ranking is overlap-then-recency only.
583
+ */
584
+ interface CorrectionInput {
585
+ tenantId: string;
952
586
  /**
953
- * AuthzPlan-derived list of strict-mode namespaces in the caller's
954
- * tenant the principal CANNOT see (v0.17.0). Graph traversal MUST
955
- * drop edges whose `namespace_id` matches the supplied set even when
956
- * the surrounding KG node is otherwise reachable. Populated
957
- * internally by `Memory.search` from `AuthzPlan.forbiddenStrict
958
- * NamespaceIds` — callers should NOT set this directly.
587
+ * Namespace partition. Required in multi-tenant mode (the isolation
588
+ * boundary). Optional in single-tenant mode, where corrections are stored
589
+ * namespace-free (`namespace_id IS NULL`) exactly like ordinary writes.
959
590
  */
960
- forbiddenStrictNamespaceIds?: string[];
591
+ namespaceId?: string;
592
+ /** What the agent did wrong (required free text). */
593
+ whatWasWrong: string;
594
+ /** The corrective instruction (required free text) — stored as `entry.content`. */
595
+ whatToDoInstead: string;
596
+ /** Applicability context the matcher scores task shapes against (required free text). */
597
+ appliesWhen: string;
598
+ /** Optional project scope — when set, the correction applies only to that project. */
599
+ project?: string;
600
+ /** Optional task-shape hint, stored for provenance; matching uses `appliesWhen`. */
601
+ taskShape?: string;
602
+ /** Optional agent id; defaults to the Memory instance's `agentId`. */
603
+ agentId?: string;
961
604
  }
962
- interface MemorySearchResult {
963
- entries: MemoryEntry[];
964
- totalCount: number;
965
- strategy: RAGStrategy;
966
- /** Visible graph slice that supported the returned entries, when graph traversal contributed. */
967
- graph?: GraphTraversalResult;
605
+ /** Input to `Memory.fetchApplicableCorrections`. */
606
+ interface FetchCorrectionsInput {
607
+ tenantId: string;
608
+ /** Namespace partition; omit to read the namespace-free scope (single-tenant mode). */
609
+ namespaceId?: string;
610
+ /** Shape of the task about to run — scored against each correction's `appliesWhen`. */
611
+ taskShape: string;
612
+ /** Optional project filter — keeps only project-matching or project-absent rows. */
613
+ project?: string;
614
+ /** Max corrections to return. Default 5, hard cap 5. */
615
+ limit?: number;
616
+ /** Optional sensitivity cap for hosted/HTTP callers. Omitted preserves trusted in-process behavior. */
617
+ maxSensitivity?: SensitivityLevel;
618
+ }
619
+ /** Input to `Memory.dueScan` (H26 B-d — the one deterministic prospective primitive). */
620
+ interface DueScanInput {
968
621
  /**
969
- * Optional scored entries for ranked results. `score` is the fused RANK score
970
- * (RRF + recency/importance/access priors) — good for ordering, NOT a relevance
971
- * magnitude. `vectorSimilarity` is the raw dense query-similarity (LanceDB
972
- * transformed-L2, 1/(1+distance)); null when the entry has no dense signal
973
- * (FTS/graph-only). Surface vectorSimilarity, not score, as a "% match".
622
+ * Window start, ISO-8601. Defaults to the server's injected clock ("now").
623
+ * Benches and reproducible callers pass it explicitly.
974
624
  */
975
- scoredEntries?: Array<{
976
- entry: MemoryEntry;
977
- score: number;
978
- vectorSimilarity?: number | null;
979
- }>;
980
- /** Confidence assessment for abstention. Present when search produces scored entries. */
981
- confidence?: {
982
- /** Overall confidence 0.0–1.0. */
983
- confidence: number;
984
- /** Whether the system recommends abstaining (confidence below threshold). */
985
- shouldAbstain: boolean;
986
- /** Raw signals used to compute confidence. */
987
- signals: {
988
- topScore: number;
989
- scoreGap: number;
990
- scoreStdDev: number;
991
- resultCount: number;
992
- aboveThresholdRatio: number;
993
- scoreSeparation: number;
994
- };
995
- };
625
+ from?: string;
626
+ /** Window length in fixed 24-hour periods, endpoints inclusive. Integer 1..370 — out-of-range is a loud error, never a clamp. */
627
+ windowDays: number;
628
+ /** Max entries returned. Default 20, hard cap 100. */
629
+ limit?: number;
630
+ /** Tenant scope; defaults to the Memory instance's tenant. */
631
+ tenantId?: string;
632
+ /** Explicit namespace scope (tenant-root rows stay visible). Overrides principal-derived visibility. */
633
+ namespaceId?: string;
634
+ /** Optional principal for namespace visibility (AuthzPlan), like search. */
635
+ principal?: PrincipalContext;
636
+ /** Optional sensitivity cap for hosted/HTTP callers; filtered in SQL before LIMIT. */
637
+ maxSensitivity?: SensitivityLevel;
996
638
  }
997
- /** One version in a fact's history, as returned by {@link LineageResult}. */
998
- interface LineageVersion {
999
- entryId: string;
1000
- /** The entry content carrying this version's value. */
1001
- value: string;
1002
- eventTime?: string;
1003
- ingestTime?: string;
1004
- status: 'active' | 'superseded' | 'archived';
1005
- /** Set when this version was superseded by a newer entry. */
1006
- supersededByEntryId?: string;
639
+ /** One applicable correction returned by `fetchApplicableCorrections`. */
640
+ interface CorrectionRecord {
641
+ id: string;
642
+ whatWasWrong: string;
643
+ whatToDoInstead: string;
644
+ appliesWhen: string;
645
+ createdAt: string;
646
+ /** Overlap-coefficient score between the query `taskShape` and this row's `appliesWhen`. */
647
+ score: number;
1007
648
  }
1008
649
  /**
1009
- * Query for the evolution of a fact (H8 `Memory.lineage`). Provide either a
1010
- * `subject` (+ optional `relation`) for graph-backed subject/relation lineage,
1011
- * OR an `entryId` to walk the `supersededBy` chain (the only mode available
1012
- * without a graph store).
650
+ * Rolling graph-traversal telemetry (in-process, since boot). Watches the
651
+ * engine re-review triggers: depth-2 getNeighbors p95 latency / result size
652
+ * (hub explosion) and getAllEdges job duration.
1013
653
  */
1014
- interface LineageParams {
1015
- subject?: string;
1016
- relation?: string;
1017
- entryId?: string;
1018
- /** Current version as of this time (newest version with eventTime ≤ asOf). */
1019
- asOf?: string;
1020
- eventTimeRange?: [string, string];
1021
- /** Return only versions strictly older than the version holding this value. */
1022
- beforeValue?: string;
1023
- limit?: number;
1024
- }
1025
- interface LineageResult {
1026
- subject?: string;
1027
- relation?: string;
1028
- /** Event-time ascending (oldest → newest). */
1029
- versions: LineageVersion[];
1030
- /** Which path answered — honest provenance (graph conflict-group vs supersededBy chain). */
1031
- source: 'graph' | 'chain';
654
+ interface GraphTelemetrySnapshot {
655
+ /** p95 latency (ms) of getNeighbors calls with depth >= 2; null until sampled. */
656
+ neighborsDepth2P95Ms: number | null;
657
+ /** p95 result node count of getNeighbors calls with depth >= 2; null until sampled. */
658
+ neighborsDepth2ResultP95: number | null;
659
+ /** Depth >= 2 samples in the rolling window (confidence for the p95s). */
660
+ neighborsDepth2SampleCount: number;
661
+ /** Duration (ms) of the most recent getAllEdges call; null until one ran. */
662
+ allEdgesLastMs: number | null;
1032
663
  }
1033
664
  /**
1034
- * Explicit recall-usefulness signal for {@link MemorySearchParams} `reinforce`.
1035
- * `context_included` = surfaced into the working context (small η); `cited` =
1036
- * the agent actually used it in its answer (medium η); `explicit_positive` =
1037
- * user/agent marked it useful (large η). Mere top-k return is NOT a signal
1038
- * (determinism + "returned ≠ used") — only an explicit `reinforce()` call moves
1039
- * strength.
665
+ * Since-boot usage-hygiene telemetry (in-process, serializable). Tracks whether
666
+ * callers provide event-time/graph context on store, whether searches miss, how
667
+ * reinforce is used, and whether sessions search before their first store.
1040
668
  */
1041
- type ReinforceSignal = 'context_included' | 'cited' | 'explicit_positive';
1042
- interface ReinforceParams {
1043
- entryIds: string[];
1044
- signal: ReinforceSignal;
1045
- /** When the recall happened — epoch-ms, or full ISO-8601 WITH timezone. Date-only / tz-free is rejected. Defaults to the activation clock. */
1046
- at?: string | number;
669
+ interface UsageHygieneSnapshot {
670
+ /** Total Memory.store calls observed since boot. */
671
+ storesTotal: number;
672
+ /** Store calls whose input carried eventTime. */
673
+ storesWithEventTime: number;
674
+ /** Store calls whose input carried caller-supplied entities or relationships. */
675
+ storesWithGraph: number;
676
+ /** Store calls by input type; missing type is counted as "long-term". */
677
+ storesByType: Record<string, number>;
678
+ /** Total Memory.search calls observed since boot. */
679
+ searchesTotal: number;
680
+ /** Completed searches that returned zero entries. */
681
+ searchesZeroResults: number;
682
+ /** Total Memory.reinforce calls observed since boot. */
683
+ reinforceTotal: number;
684
+ /** Total get_taxonomy_state (Memory.getTaxonomyState) calls observed since boot. */
685
+ taxonomyStateReadsTotal: number;
686
+ /** Total name_cluster (Memory.nameCluster) calls observed since boot. */
687
+ nameClusterCallsTotal: number;
688
+ /** Reinforce calls by signal value. */
689
+ reinforceBySignal: Record<string, number>;
690
+ /** Sessions where at least one search happened before the first store. */
691
+ searchBeforeFirstStoreSessions: number;
692
+ /** Sessions whose first observed hygiene event was a store. */
693
+ storeFirstSessions: number;
1047
694
  }
1048
- interface ReinforceResult {
1049
- /** Per-entry post-reinforce activation. Entries absent from the store are omitted. */
1050
- updated: Array<{
1051
- entryId: string;
1052
- strength: number;
1053
- tier: 'quick' | 'medium' | 'deep';
695
+ interface MemoryStats {
696
+ totalEntries: number;
697
+ storageUsedBytes: number;
698
+ vectorCount: number;
699
+ recentAccessCount: number;
700
+ graphNodeCount?: number;
701
+ graphEdgeCount?: number;
702
+ /** Raw graph node count before tenant/ReBAC visibility filtering (raw stats mode only). */
703
+ graphRawNodeCount?: number;
704
+ /** Raw graph edge count before tenant/ReBAC visibility filtering (raw stats mode only). */
705
+ graphRawEdgeCount?: number;
706
+ /** Name of the active graph store ('neo4j', 'sqlite', or undefined if none). */
707
+ graphStore?: string;
708
+ /** Graph traversal telemetry; undefined when no graph store is active. */
709
+ graphTelemetry?: GraphTelemetrySnapshot;
710
+ /** Usage-hygiene telemetry since process boot. */
711
+ usageHygiene?: UsageHygieneSnapshot;
712
+ /** Whether the memory service is connected. False when using DisabledMemory. */
713
+ connected?: boolean;
714
+ /**
715
+ * Deferred-embed queue depth. The in-process core always reports it (0 when
716
+ * idle); absent means unknown (older server or disabled client), never 0.
717
+ */
718
+ pendingEmbeddings?: number;
719
+ }
720
+ interface MemoryInsightMetrics {
721
+ activeEntries: number;
722
+ retainedAdditions7d: number;
723
+ appliedRecalls: number;
724
+ reinforcedEntries: number;
725
+ retrievedEntries: number;
726
+ retrievals: number;
727
+ lastAppliedAt: string | null;
728
+ lastRetrievedAt: string | null;
729
+ }
730
+ interface MemoryProjectInsight extends MemoryInsightMetrics {
731
+ label: string;
732
+ }
733
+ /** Body-free, caller-visible aggregate for product status surfaces. */
734
+ interface MemoryInsights {
735
+ generatedAt: string;
736
+ scope: 'connected_memory';
737
+ coverage: {
738
+ retainedAdditions: {
739
+ state: 'measured' | 'partial';
740
+ trackingSince: string | null;
741
+ trackedEntries: number;
742
+ totalEntries: number;
743
+ reason: string | null;
744
+ };
745
+ projectLabels: {
746
+ state: 'measured';
747
+ };
748
+ retrievalUsage: {
749
+ state: 'partial';
750
+ reason: string;
751
+ };
752
+ tokenEfficiency: {
753
+ state: 'not_instrumented';
754
+ reason: string;
755
+ };
756
+ contextAccuracy: {
757
+ state: 'not_instrumented';
758
+ reason: string;
759
+ };
760
+ };
761
+ summary: {
762
+ activeEntries: number;
763
+ observedProjectLabels: number;
764
+ retainedAdditions7d: number | null;
765
+ trackedEntries: number;
766
+ appliedRecalls: number;
767
+ reinforcedEntries: number;
768
+ retrievedEntries: number;
769
+ retrievals: number;
770
+ };
771
+ projects: MemoryProjectInsight[];
772
+ other: MemoryInsightMetrics | null;
773
+ /** Most recently reinforced visible entries (≤5), labels only, never bodies. */
774
+ recentApplied?: Array<{
775
+ topic: string | null;
776
+ project: string | null;
777
+ at: string;
1054
778
  }>;
1055
779
  }
1056
- interface SourceEvidence {
1057
- /** Memory entry that produced this graph fact. */
1058
- memoryEntryId: string;
1059
- /** Data tenant of the source entry. `null` = single-tenant / legacy data. */
1060
- tenantId?: string | null;
1061
- /** Namespace of the source memory entry. `null` = legacy / tenant-root. */
1062
- namespaceId?: string | null;
1063
- /** Optional source identifier copied from the memory entry or caller. */
1064
- source?: string;
1065
- /** Optional content hash copied from the memory entry or caller. */
1066
- contentHash?: string;
1067
- /** Optional short text evidence for the graph fact. */
1068
- snippet?: string;
1069
- /** When this evidence was recorded. */
1070
- createdAt?: Timestamp;
780
+ interface GraphRepairResult {
781
+ staleEdgesDeleted: number;
782
+ staleNodeRefsRemoved: number;
783
+ orphanNodesDeleted: number;
1071
784
  }
1072
- declare const StoreTarget: {
1073
- readonly SQLITE: "sqlite";
1074
- readonly VECTOR: "vector";
1075
- readonly GRAPH: "graph";
1076
- };
1077
- type StoreTarget = (typeof StoreTarget)[keyof typeof StoreTarget];
1078
- /** Agent-provided entity for graph storage. */
1079
- interface IngestEntity {
1080
- /** Entity name (e.g., "Alice", "TypeScript"). */
785
+ interface GraphNode {
786
+ id: string;
1081
787
  name: string;
1082
- /** Entity type — freeform, agent decides (e.g., "PERSON", "TOOL"). */
1083
788
  type: string;
1084
- /** Stable canonical identifier. Defaults to a deterministic name+type id. */
1085
789
  canonicalId?: string;
1086
- /** Source evidence for this graph node. Defaults to the containing memory entry. */
1087
790
  sourceEvidence?: SourceEvidence[];
1088
- /** Optional properties to attach to the graph node. */
1089
- properties?: Record<string, unknown>;
791
+ properties: Record<string, unknown>;
792
+ memoryEntryIds: string[];
1090
793
  }
1091
- /** Agent-provided relationship for graph storage. */
1092
- interface IngestRelationship {
1093
- /** Source entity name (must match an entity in the entities array). */
1094
- source: string;
1095
- /** Target entity name (must match an entity in the entities array). */
1096
- target: string;
1097
- /** Relationship type — freeform, agent decides (e.g., "WORKS_AT", "USES"). */
794
+ interface GraphRelationship {
795
+ id: string;
796
+ sourceId: string;
797
+ targetId: string;
1098
798
  type: string;
1099
- /** Source evidence for this graph edge. Defaults to the containing memory entry. */
1100
799
  sourceEvidence?: SourceEvidence[];
1101
- /** Optional properties to attach to the graph edge. */
1102
- properties?: Record<string, unknown>;
800
+ properties: Record<string, unknown>;
801
+ memoryEntryId?: string;
802
+ /**
803
+ * Namespace_id provenance carried from the originating MemoryEntry.
804
+ * `null` (or absent) = legacy / tenant-root bucket. Foundation for the
805
+ * v0.17.0 strict traversal filter (the AuthzPlan compares this value
806
+ * edge-by-edge so KG dedupe at the node level can stay intact).
807
+ */
808
+ namespaceId?: string | null;
809
+ }
810
+ interface GraphTraversalResult {
811
+ nodes: GraphNode[];
812
+ relationships: GraphRelationship[];
813
+ paths: Array<{
814
+ nodeIds: string[];
815
+ relationshipIds: string[];
816
+ }>;
1103
817
  }
1104
818
  /**
1105
- * How `Memory.store()` should react when the graph write fails.
1106
- * - `throw` (default, since v0.13.0): propagate the failure so the caller
1107
- * knows the graph is incomplete. Honest contract: a graph write either
1108
- * commits or fails loudly. Silent partial-loss was the v0.12.2 bug that
1109
- * masked 91/92 dropped entities.
1110
- * - `best-effort`: swallow the error and log a warning; the entry is still
1111
- * considered ingested in SQLite/vector. Use only when you genuinely don't
1112
- * need the graph slice and a transient neo4j blip shouldn't fail ingest.
819
+ * Memory.lint() report shape — Karpathy-wiki Item B (v0.18.0).
820
+ * Read-only projection composed from signals every owning module
821
+ * already exposes. Lives in shared so the HTTP client can hold the
822
+ * same type as core without re-declaring it.
1113
823
  */
1114
- type GraphFailureMode = 'throw' | 'best-effort';
1115
- /** Store input: what the agent sends to Memory.store(). */
1116
- type StoreInput = Omit<MemoryEntry, 'id' | 'createdAt'> & {
1117
- id?: string;
1118
- createdAt?: string;
1119
- /** Storage targets. Default: ["sqlite", "vector"]. */
1120
- targets?: StoreTarget[];
1121
- /** Agent-provided entities for graph storage. */
1122
- entities?: IngestEntity[];
1123
- /** Agent-provided relationships for graph storage. */
1124
- relationships?: IngestRelationship[];
1125
- /** Override graph entity extraction for this store call. */
1126
- extractEntities?: boolean;
1127
- /** Graph-failure handling. Default: "throw" (loud) — see GraphFailureMode. */
1128
- graphFailureMode?: GraphFailureMode;
1129
- };
1130
- interface MemoryIngestRequest {
1131
- content?: string;
1132
- type?: MemoryType;
1133
- metadata?: Record<string, unknown>;
824
+ interface WikiLintReport {
825
+ orphans: GraphNode[];
826
+ decayCandidates: MemoryEntry[];
827
+ staleSyntheses: Array<{
828
+ entry: MemoryEntry;
829
+ reason: string;
830
+ }>;
831
+ dedupCandidates: Array<{
832
+ hash: string;
833
+ entryIds: string[];
834
+ }>;
835
+ }
836
+
837
+ /** Parameters for paginated entry listing. */
838
+ interface MemoryListParams {
839
+ /** 1-based page number. Default: 1 */
840
+ page?: number;
841
+ /** Entries per page (1–100). Default: 20 */
842
+ limit?: number;
843
+ /**
844
+ * Opaque keyset-pagination token from a previous result's `nextCursor`.
845
+ * Guarantees exactly-once traversal even while strictly-newer entries
846
+ * are being written (offset/page pagination can repeat or skip there).
847
+ * A cursor is only valid for the same filter set that produced it.
848
+ * Mutually exclusive with `page` — supplying both is an error. Not a
849
+ * snapshot: rows backdated behind the cursor position can still appear.
850
+ */
851
+ cursor?: string;
852
+ /**
853
+ * Opt-in lifecycle-status filter. Omitted preserves today's behavior:
854
+ * active, superseded, and archived entries are all returned.
855
+ */
856
+ status?: 'active' | 'superseded' | 'archived';
857
+ /** Filter by memory type. */
858
+ type?: MemoryType$1;
859
+ /** Filter by agent ID. */
860
+ agentId?: string;
861
+ /** Filter by tenant ID for multi-tenant isolation. */
862
+ tenantId?: string;
863
+ /** Exact namespace scope. Excludes legacy tenant-root entries. */
864
+ namespaceId?: string;
865
+ /**
866
+ * Calling principal. When supplied, list applies the AuthzPlan
867
+ * visibility filter so entries in forbidden namespaces never reach
868
+ * the response. Single-tenant / library-direct callers may omit it
869
+ * and get the legacy tenant-only scope.
870
+ */
871
+ principal?: PrincipalContext$1;
872
+ /** Maximum sensitivity level to include. Omitted preserves legacy behavior. */
873
+ maxSensitivity?: SensitivityLevel$1;
874
+ /**
875
+ * R1/R2 — opt-in list of `metadata._kind` values to include in the
876
+ * response. When omitted or empty, the default-set returns only entries
877
+ * with NO `_kind` system metadata (e.g. `_kind:'entity-summary'` rows
878
+ * are hidden). When supplied, the listed kinds are returned IN ADDITION
879
+ * to the default-set (additive, not replacement). See
880
+ * `docs/specs/topic-org-v025-f1-include-kinds/spec.md`.
881
+ */
882
+ includeKinds?: string[];
883
+ }
884
+ /** Result of a paginated entry listing. */
885
+ interface MemoryListResult {
886
+ entries: MemoryEntry$1[];
887
+ totalCount: number;
888
+ /** Present in page/offset mode only — a keyset traversal has no page number. */
889
+ page?: number;
890
+ limit: number;
891
+ /** Keyset token for the next page; null when this page is the last. */
892
+ nextCursor: string | null;
893
+ }
894
+ /** Filters for temporal queries (queryAsOf, queryByEventTime). */
895
+ interface TemporalQueryFilters {
896
+ type?: MemoryType$1;
1134
897
  agentId?: string;
1135
- sessionId?: string;
1136
- /** Storage targets. Default: ["sqlite", "vector"]. */
1137
- targets?: StoreTarget[];
1138
- /** Agent-provided entities for graph storage. */
1139
- entities?: IngestEntity[];
1140
- /** Agent-provided relationships for graph storage. */
1141
- relationships?: IngestRelationship[];
1142
- /** Override graph entity extraction for this ingest request. */
1143
- extractEntities?: boolean;
1144
- /** Graph-failure handling. Default: "throw" (loud) — see GraphFailureMode. */
1145
- graphFailureMode?: GraphFailureMode;
1146
- /** Importance score (1-10). */
1147
- importance?: number;
1148
- /** Source identifier (e.g., filename, URL). */
1149
898
  source?: string;
1150
- /** When the event occurred (ISO timestamp). */
1151
- eventTime?: string;
1152
- /** Optional deterministic ID for the entry (agent-provided). */
1153
- id?: string;
1154
- /** Parent entry ID for hierarchical storage (e.g., doc → section → chunk). */
1155
- parentId?: string;
1156
- /** When this entry was ingested (ISO timestamp). Default: now. */
1157
- ingestTime?: string;
1158
- /** Tenant ID for multi-tenant isolation. */
899
+ limit?: number;
900
+ /**
901
+ * Number of matching rows to skip. Offset pages can shift under concurrent
902
+ * deletion; use cursor for a deletion-stable queryAsOf walk.
903
+ */
904
+ offset?: number;
905
+ /**
906
+ * Opaque keyset token for a deletion-stable queryAsOf walk. Derive it from
907
+ * the last returned entry with `encodeListCursorToken`; mutually exclusive
908
+ * with offset.
909
+ */
910
+ cursor?: string;
911
+ /** Maximum sensitivity level to include. Omitted preserves legacy behavior. */
912
+ maxSensitivity?: SensitivityLevel$1;
913
+ }
914
+ /** Filters for the chronological feed (`log`, Karpathy `log.md` primitive). */
915
+ interface MemoryLogFilters {
916
+ /** Inclusive lower bound on `created_at` (ISO 8601). Cursor for "what's new since X". */
917
+ since?: string;
918
+ /** Maximum entries to return. The HTTP layer clamps to [1, 100]. */
919
+ limit?: number;
920
+ type?: MemoryType$1;
921
+ agentId?: string;
922
+ source?: string;
923
+ /** Maximum sensitivity level to include. Omitted preserves legacy behavior. */
924
+ maxSensitivity?: SensitivityLevel$1;
925
+ }
926
+ /** Options for scoping operations to a specific tenant. */
927
+ interface TenantScopeOptions {
1159
928
  tenantId?: string;
1160
- /** User ID within the tenant. */
1161
- userId?: string;
1162
- /** Team/group ID within the tenant. */
1163
- teamId?: string;
1164
- /** Namespace ID — see `MemoryEntry.namespaceId`. */
929
+ /** Optional strict namespace coordinate for exact get/delete operations. */
1165
930
  namespaceId?: string;
1166
931
  /**
1167
- * Exclude this entry from consolidation (decay-archive and semantic dedup).
1168
- * See `MemoryEntry.pinned` for full semantics.
932
+ * Graph count mode for stats(). Use raw on admin-health paths
933
+ * that should avoid the visible graph projection.
1169
934
  */
1170
- pinned?: boolean;
935
+ graphVisibility?: 'visible' | 'raw';
936
+ /**
937
+ * Calling principal. When supplied alongside or instead of tenantId,
938
+ * the operation applies the AuthzPlan visibility filter — get/delete
939
+ * will treat entries in forbidden namespaces as if they did not exist.
940
+ * Single-tenant / library-direct callers may omit it and get the
941
+ * legacy tenant-only scope.
942
+ */
943
+ principal?: PrincipalContext$1;
944
+ /** Maximum sensitivity level to include. Omitted preserves legacy behavior. */
945
+ maxSensitivity?: SensitivityLevel$1;
946
+ }
947
+ /** Abstract interface for memory systems (local or remote). */
948
+ interface MemoryInterface {
949
+ initialize(): Promise<void>;
950
+ store(entry: StoreInput$1): Promise<MemoryEntry$1>;
951
+ search(params: MemorySearchParams$1): Promise<MemorySearchResult$1>;
952
+ /** List entries with SQL LIMIT/OFFSET pagination. */
953
+ list(params?: MemoryListParams): Promise<MemoryListResult>;
954
+ get(id: string, options?: TenantScopeOptions): Promise<MemoryEntry$1 | null>;
955
+ delete(id: string, options?: TenantScopeOptions): Promise<boolean>;
956
+ clearSession(sessionId: string, options?: TenantScopeOptions): Promise<number>;
957
+ stats(options?: TenantScopeOptions): Promise<MemoryStats$1>;
958
+ insights(options?: TenantScopeOptions): Promise<MemoryInsights$1>;
959
+ /** Query entries as they existed at a point in time (by ingest time). */
960
+ queryAsOf(asOfDate: string, filters?: TemporalQueryFilters, options?: TenantScopeOptions): Promise<MemoryEntry$1[]>;
961
+ /** Read the time-ordered lineage of a graph fact or superseded entry chain. */
962
+ lineage(params: LineageParams$1): Promise<LineageResult$1>;
963
+ /** Reinforce memories that were actually used by the caller. */
964
+ reinforce(params: ReinforceParams$1): Promise<ReinforceResult$1>;
965
+ /** Query entries by event time range (when things actually happened). */
966
+ queryByEventTime(startTime: string, endTime: string, filters?: TemporalQueryFilters): Promise<MemoryEntry$1[]>;
967
+ shutdown(): Promise<void>;
968
+ }
969
+ /** Consolidation run result. */
970
+ interface ConsolidationRunResult {
971
+ entriesProcessed: number;
972
+ entriesMerged: number;
973
+ entriesArchived: number;
974
+ durationMs: number;
975
+ }
976
+ /** Extended interface with lifecycle operations. Non-breaking for existing consumers. */
977
+ interface ExtendedMemoryInterface extends MemoryInterface {
978
+ /** Run consolidation: score, dedup, decay, and summarize memories. */
979
+ consolidate(): Promise<ConsolidationRunResult>;
980
+ /** Soft-delete a memory with a reason (marks as archived). */
981
+ forget(id: string, reason?: string): Promise<boolean>;
982
+ /** Summarize a session's memories into a long-term entry. */
983
+ summarizeSession(sessionId: string): Promise<MemoryEntry$1 | null>;
984
+ /**
985
+ * Read-only memory-wide lint report (v0.18.0 Karpathy-wiki Item B):
986
+ * orphans, decay candidates, stale entries, dedup candidates. Pure
987
+ * projection — no writes.
988
+ */
989
+ lint(options?: {
990
+ limit?: number;
991
+ }): Promise<WikiLintReport$1>;
992
+ /** Run decay on all entries, archiving those below threshold. */
993
+ runDecay(): Promise<number>;
994
+ /** Reindex the FTS5 full-text search index. */
995
+ reindex(): Promise<void>;
996
+ /** Delete all entries matching a source, cleaning up all stores. */
997
+ deleteBySource(source: string, options?: TenantScopeOptions): Promise<number>;
998
+ /** Repair stale graph references left by older delete paths or crashed cleanup. */
999
+ repairGraph(): Promise<GraphRepairResult$1>;
1000
+ /**
1001
+ * Chronological feed of memory entries (Karpathy `log.md` primitive).
1002
+ * Cursor-based via `since` (created_at lower bound). No totalCount.
1003
+ */
1004
+ log(filters?: MemoryLogFilters): Promise<MemoryEntry$1[]>;
1005
+ /**
1006
+ * Synthesize a per-entity profile (Karpathy-wiki "wiki page" primitive).
1007
+ * LLM-driven, caller-triggered. Stores a pinned `_kind:'entity-summary'`
1008
+ * entry with `_search_visibility:'on-demand'` so it never enters the
1009
+ * default retrieval pool. Re-running replaces the prior synthesis.
1010
+ */
1011
+ summarizeEntity(name: string): Promise<MemoryEntry$1>;
1012
+ /**
1013
+ * Fetch a previously-synthesized entity profile. Returns `null` when no
1014
+ * synthesis exists yet. O(1) — the read side of the amortized pattern.
1015
+ */
1016
+ getEntitySynthesis(name: string): Promise<MemoryEntry$1 | null>;
1171
1017
  }
1018
+
1172
1019
  /**
1173
- * Agent-recorded explicit correction ("you did X wrong; do Y instead").
1174
- * `Memory.recordCorrection` writes one pinned, sqlite-only entry; pyx does
1175
- * pure structural retrieval with zero LLM / embedding on this path. Scope is
1176
- * `(tenantId, namespaceId)` + optional `project` — NOT per-user, because a
1177
- * correction about how to do X in this project is namespace-shared. No
1178
- * `confidence` field by design: ranking is overlap-then-recency only.
1020
+ * No-op {@link MemoryInterface} for hosts that run without a memory backend
1021
+ * (e.g. `MEMORY_URL` is unset). Every method returns a safe default, so the
1022
+ * rest of the system functions without branching on `memory == null`.
1023
+ *
1024
+ * Canonical single source: this lives in the SAME package as `MemoryInterface`,
1025
+ * so any method added to the interface fails THIS class's compile in the same
1026
+ * build. The null-object can never silently drift behind the contract — the
1027
+ * failure mode that left hand-rolled copies in downstream repos missing
1028
+ * `lineage`/`reinforce` after the interface grew them.
1029
+ *
1030
+ * `initialize()` emits a single `console.warn`; pass nothing else — it is a
1031
+ * pure null-object. Hosts wanting structured logging should log at the wiring
1032
+ * site where they choose `DisabledMemory` over a real client.
1179
1033
  */
1180
- interface CorrectionInput {
1181
- tenantId: string;
1034
+ declare class DisabledMemory implements MemoryInterface {
1035
+ initialize(): Promise<void>;
1036
+ store(entry: StoreInput$1): Promise<MemoryEntry$1>;
1037
+ search(): Promise<MemorySearchResult$1>;
1038
+ list(params?: MemoryListParams): Promise<MemoryListResult>;
1039
+ get(): Promise<MemoryEntry$1 | null>;
1040
+ delete(): Promise<boolean>;
1041
+ clearSession(): Promise<number>;
1042
+ stats(): Promise<MemoryStats$1>;
1043
+ insights(): Promise<MemoryInsights$1>;
1044
+ queryAsOf(): Promise<MemoryEntry$1[]>;
1045
+ lineage(): Promise<LineageResult$1>;
1046
+ reinforce(): Promise<ReinforceResult$1>;
1047
+ queryByEventTime(): Promise<MemoryEntry$1[]>;
1048
+ shutdown(): Promise<void>;
1049
+ }
1050
+
1051
+ /**
1052
+ * Callbacks for two-phase file enrichment. All callbacks are optional:
1053
+ * - Image-rich PDF + describeImage only → describes images, no entity extraction
1054
+ * - Image-rich PDF + describeImage + extractEntitiesV2 → describes + extracts
1055
+ * - Text-only file + extractEntitiesV2 only → extracts from textWindows
1056
+ * - Mixed file + both → describes images + extracts from both sources
1057
+ *
1058
+ * Without any callback, the ingest stream emits the server result with no
1059
+ * SDK-side enrichment. Server-side text/entity extraction may still run when
1060
+ * configured; image understanding still requires caller-provided
1061
+ * descriptions/hooks.
1062
+ */
1063
+ interface EnrichmentCallbacks {
1182
1064
  /**
1183
- * Namespace partition. Required in multi-tenant mode (the isolation
1184
- * boundary). Optional in single-tenant mode, where corrections are stored
1185
- * namespace-free (`namespace_id IS NULL`) exactly like ordinary writes.
1065
+ * Describe an image using LLM vision. Receives the raw image buffer and
1066
+ * metadata. Required for image-bearing files; safe to omit for text-only
1067
+ * uploads where the server emits zero images.
1186
1068
  */
1187
- namespaceId?: string;
1188
- /** What the agent did wrong (required free text). */
1189
- whatWasWrong: string;
1190
- /** The corrective instruction (required free text) — stored as `entry.content`. */
1191
- whatToDoInstead: string;
1192
- /** Applicability context the matcher scores task shapes against (required free text). */
1193
- appliesWhen: string;
1194
- /** Optional project scope — when set, the correction applies only to that project. */
1195
- project?: string;
1196
- /** Optional task-shape hint, stored for provenance; matching uses `appliesWhen`. */
1197
- taskShape?: string;
1198
- /** Optional agent id; defaults to the Memory instance's `agentId`. */
1199
- agentId?: string;
1069
+ describeImage?: (imageBuffer: ArrayBuffer, meta: ExtractedImageMeta$1) => Promise<string>;
1070
+ /**
1071
+ * Entity-extraction callback. Receives text windows and image descriptions
1072
+ * separately so callers can apply different prompts per source. Triggers
1073
+ * the `X-Pyx-Enrichment-Capabilities: text_windows_v1` negotiation header
1074
+ * on ingest.
1075
+ */
1076
+ extractEntitiesV2?: (input: {
1077
+ textWindows: string[];
1078
+ imageDescriptions: string[];
1079
+ mimeType: string;
1080
+ filename: string;
1081
+ }) => Promise<{
1082
+ entities: IngestEntity$1[];
1083
+ relationships: IngestRelationship$1[];
1084
+ }>;
1200
1085
  }
1201
- /** Input to `Memory.fetchApplicableCorrections`. */
1202
- interface FetchCorrectionsInput {
1203
- tenantId: string;
1204
- /** Namespace partition; omit to read the namespace-free scope (single-tenant mode). */
1086
+ /**
1087
+ * Options for {@link MemoryClient.ingestFileEvents}. `signal` lets
1088
+ * long-running ingests (LLM enrichment + graph writes) be cancelled cleanly.
1089
+ *
1090
+ * `namespaceId` opts the upload into ReBAC AuthzPlan visibility — the server
1091
+ * thread the namespace through parsing → enrichment → store calls so the
1092
+ * resulting catalog row and chunk entries land in the named namespace
1093
+ * (server v0.17.4+; required when `requireNamespaceForTenantWrites=true`).
1094
+ */
1095
+ interface IngestFileOptions {
1096
+ description?: string;
1097
+ enrichment?: EnrichmentCallbacks;
1098
+ signal?: AbortSignal;
1205
1099
  namespaceId?: string;
1206
- /** Shape of the task about to run — scored against each correction's `appliesWhen`. */
1207
- taskShape: string;
1208
- /** Optional project filter — keeps only project-matching or project-absent rows. */
1209
- project?: string;
1210
- /** Max corrections to return. Default 5, hard cap 5. */
1211
- limit?: number;
1212
- /** Optional sensitivity cap for hosted/HTTP callers. Omitted preserves trusted in-process behavior. */
1213
- maxSensitivity?: SensitivityLevel;
1214
- }
1215
- /** Input to `Memory.dueScan` (H26 B-d — the one deterministic prospective primitive). */
1216
- interface DueScanInput {
1217
1100
  /**
1218
- * Window start, ISO-8601. Defaults to the server's injected clock ("now").
1219
- * Benches and reproducible callers pass it explicitly.
1101
+ * Stable logical document identity used for replaceable content, image,
1102
+ * and graph projections. Requires `enrichment.extractEntitiesV2` so the
1103
+ * client can negotiate text windows and complete the stable replacement.
1220
1104
  */
1221
- from?: string;
1222
- /** Window length in fixed 24-hour periods, endpoints inclusive. Integer 1..370 — out-of-range is a loud error, never a clamp. */
1223
- windowDays: number;
1224
- /** Max entries returned. Default 20, hard cap 100. */
1225
- limit?: number;
1226
- /** Tenant scope; defaults to the Memory instance's tenant. */
1227
- tenantId?: string;
1228
- /** Explicit namespace scope (tenant-root rows stay visible). Overrides principal-derived visibility. */
1229
- namespaceId?: string;
1230
- /** Optional principal for namespace visibility (AuthzPlan), like search. */
1231
- principal?: PrincipalContext;
1232
- /** Optional sensitivity cap for hosted/HTTP callers; filtered in SQL before LIMIT. */
1233
- maxSensitivity?: SensitivityLevel;
1234
- }
1235
- /** One applicable correction returned by `fetchApplicableCorrections`. */
1236
- interface CorrectionRecord {
1237
- id: string;
1238
- whatWasWrong: string;
1239
- whatToDoInstead: string;
1240
- appliesWhen: string;
1241
- createdAt: string;
1242
- /** Overlap-coefficient score between the query `taskShape` and this row's `appliesWhen`. */
1243
- score: number;
1105
+ documentKey?: string;
1106
+ /**
1107
+ * Migration-only pinned file-ingestion catalog for this document's first
1108
+ * stable replacement. The server validates its exact scope and uses its
1109
+ * bounded provenance to detach legacy graph references. Omit this after the
1110
+ * stable anchor is established: the first pass may retire catalog-owned
1111
+ * projections, so later revisions should use `documentKey` alone.
1112
+ */
1113
+ catalogEntryId?: string;
1244
1114
  }
1245
1115
  /**
1246
- * Rolling graph-traversal telemetry (in-process, since boot). Watches the
1247
- * engine re-review triggers: depth-2 getNeighbors p95 latency / result size
1248
- * (hub explosion) and getAllEdges job duration.
1116
+ * Options for {@link MemoryClient.graphEnrichFileEvents}. `documentKey` is the
1117
+ * caller's stable logical identity for the document whose graph is being
1118
+ * rebuilt — the server derives the graph anchor id from
1119
+ * (tenant, namespace, documentKey), so repeating the same key replaces the
1120
+ * document's graph references instead of multiplying them.
1121
+ *
1122
+ * `enrichment.extractEntitiesV2` is required: graph-only re-enrichment is
1123
+ * caller-extraction by definition (there is no server-side fallback).
1249
1124
  */
1250
- interface GraphTelemetrySnapshot {
1251
- /** p95 latency (ms) of getNeighbors calls with depth >= 2; null until sampled. */
1252
- neighborsDepth2P95Ms: number | null;
1253
- /** p95 result node count of getNeighbors calls with depth >= 2; null until sampled. */
1254
- neighborsDepth2ResultP95: number | null;
1255
- /** Depth >= 2 samples in the rolling window (confidence for the p95s). */
1256
- neighborsDepth2SampleCount: number;
1257
- /** Duration (ms) of the most recent getAllEdges call; null until one ran. */
1258
- allEdgesLastMs: number | null;
1125
+ interface GraphEnrichFileOptions {
1126
+ documentKey: string;
1127
+ /**
1128
+ * Migration-only pinned file-ingestion catalog for the first stable graph
1129
+ * replacement. The server resolves it in the current tenant/namespace and
1130
+ * detaches its bounded graph references. Omit it on later revisions once
1131
+ * the `documentKey` anchor exists.
1132
+ */
1133
+ catalogEntryId?: string;
1134
+ namespaceId?: string;
1135
+ signal?: AbortSignal;
1136
+ enrichment: EnrichmentCallbacks;
1137
+ }
1138
+ interface FileDownloadOptions {
1139
+ /** Stable logical document identity used by documentKey-aware ingest. */
1140
+ documentKey?: string;
1141
+ /** Exact namespace containing the uploaded document. */
1142
+ namespaceId?: string;
1259
1143
  }
1260
1144
  /**
1261
- * Since-boot usage-hygiene telemetry (in-process, serializable). Tracks whether
1262
- * callers provide event-time/graph context on store, whether searches miss, how
1263
- * reinforce is used, and whether sessions search before their first store.
1145
+ * Caller-supplied enrichment for the per-call store path. Mirrors
1146
+ * {@link EnrichmentCallbacks} for file ingest. When supplied, the SDK invokes
1147
+ * the callback and merges the result into the payload before POSTing. Without
1148
+ * a callback, server-side text/entity extraction can run only when the server
1149
+ * has an extraction brain configured; otherwise callers must pass graph data
1150
+ * or use caller-side hooks. Images always require caller-provided
1151
+ * descriptions/hooks.
1264
1152
  */
1265
- interface UsageHygieneSnapshot {
1266
- /** Total Memory.store calls observed since boot. */
1267
- storesTotal: number;
1268
- /** Store calls whose input carried eventTime. */
1269
- storesWithEventTime: number;
1270
- /** Store calls whose input carried caller-supplied entities or relationships. */
1271
- storesWithGraph: number;
1272
- /** Store calls by input type; missing type is counted as "long-term". */
1273
- storesByType: Record<string, number>;
1274
- /** Total Memory.search calls observed since boot. */
1275
- searchesTotal: number;
1276
- /** Completed searches that returned zero entries. */
1277
- searchesZeroResults: number;
1278
- /** Total Memory.reinforce calls observed since boot. */
1279
- reinforceTotal: number;
1280
- /** Total get_taxonomy_state (Memory.getTaxonomyState) calls observed since boot. */
1281
- taxonomyStateReadsTotal: number;
1282
- /** Total name_cluster (Memory.nameCluster) calls observed since boot. */
1283
- nameClusterCallsTotal: number;
1284
- /** Reinforce calls by signal value. */
1285
- reinforceBySignal: Record<string, number>;
1286
- /** Sessions where at least one search happened before the first store. */
1287
- searchBeforeFirstStoreSessions: number;
1288
- /** Sessions whose first observed hygiene event was a store. */
1289
- storeFirstSessions: number;
1153
+ interface StoreEnrichmentCallbacks {
1154
+ /**
1155
+ * Extract entities + relationships from `content`. The caller's LLM does
1156
+ * the work; the SDK passes the result through {@link mergeExtractedEntities}
1157
+ * (caller-wins, case-insensitive) before sending to the server.
1158
+ *
1159
+ * Skipped when `entry.extractEntities === false`. When
1160
+ * `entry.extractEntities === true` but this callback is not supplied,
1161
+ * `MemoryClient.store()` forwards the hint so the server-side extraction
1162
+ * brain can run and loud-fail if it is not configured.
1163
+ */
1164
+ extractEntities?: (input: {
1165
+ content: string;
1166
+ metadata?: Record<string, unknown>;
1167
+ signal?: AbortSignal;
1168
+ }) => Promise<EntityExtractionResult$1>;
1290
1169
  }
1291
- interface MemoryStats {
1292
- totalEntries: number;
1293
- storageUsedBytes: number;
1294
- vectorCount: number;
1295
- recentAccessCount: number;
1296
- graphNodeCount?: number;
1297
- graphEdgeCount?: number;
1298
- /** Raw graph node count before tenant/ReBAC visibility filtering (raw stats mode only). */
1299
- graphRawNodeCount?: number;
1300
- /** Raw graph edge count before tenant/ReBAC visibility filtering (raw stats mode only). */
1301
- graphRawEdgeCount?: number;
1302
- /** Name of the active graph store ('neo4j', 'sqlite', or undefined if none). */
1303
- graphStore?: string;
1304
- /** Graph traversal telemetry; undefined when no graph store is active. */
1305
- graphTelemetry?: GraphTelemetrySnapshot;
1306
- /** Usage-hygiene telemetry since process boot. */
1307
- usageHygiene?: UsageHygieneSnapshot;
1308
- /** Whether the memory service is connected. False when using DisabledMemory. */
1309
- connected?: boolean;
1170
+ /** Options accepted by {@link MemoryClient.store}. */
1171
+ interface StoreOptions {
1172
+ enrichment?: StoreEnrichmentCallbacks;
1173
+ /** Propagated into the `extractEntities` callback and the underlying fetch. */
1174
+ signal?: AbortSignal;
1175
+ /** Stable logical request key. Reuse this exact value after a lost response. */
1176
+ idempotencyKey?: string;
1177
+ }
1178
+ interface RequestAuthorityOptions {
1179
+ /** Stable logical request key. Reuse this exact value after a lost response. */
1180
+ idempotencyKey?: string;
1181
+ }
1182
+ /** Error thrown by MemoryClient when the server returns a non-success response. */
1183
+ declare class MemoryServerError extends Error {
1184
+ readonly status: number;
1185
+ /** Stable machine-readable discriminator returned by the memory server. */
1186
+ readonly code?: string;
1187
+ /** Exact HTTP Retry-After value returned by the memory server. */
1188
+ readonly retryAfter?: string;
1189
+ /** Retry delay normalized to seconds when Retry-After is parseable. */
1190
+ readonly retryAfterSeconds?: number;
1191
+ constructor(message: string, status: number, code?: string, retryAfter?: string);
1192
+ /** True when the server returned HTTP 404 (not found). */
1193
+ get isNotFound(): boolean;
1194
+ }
1195
+ interface MemoryClientOptions {
1196
+ /** API key for authentication. */
1197
+ apiKey?: string;
1198
+ /** Additional headers to send with every request (e.g., X-Caller-Access-Level). */
1199
+ defaultHeaders?: Record<string, string>;
1200
+ /**
1201
+ * Default per-request timeout in milliseconds. Without this, a wedged
1202
+ * memory server (e.g. event-loop blocked by inference) makes every
1203
+ * caller hang forever — that was the Korens demo wedge in 2026-04 where
1204
+ * a 161-second pyx-memory stall propagated through the runtime to the
1205
+ * browser. Defaults to 30 s, which is high enough that normal
1206
+ * `/search` and `/stats` requests never hit it but low enough that a
1207
+ * stuck server fails loudly.
1208
+ *
1209
+ * Only applied when the caller does NOT pass their own `signal` via
1210
+ * RequestInit. Long-running operations (large `consolidate`, `reindex`,
1211
+ * file ingest with enrichment) should pass their own AbortSignal —
1212
+ * that signal fully replaces the default ceiling.
1213
+ */
1214
+ requestTimeoutMs?: number;
1215
+ }
1216
+ declare class MemoryClient implements ExtendedMemoryInterface {
1217
+ protected baseUrl: string;
1218
+ private readonly _authHeaders;
1219
+ private readonly _requestTimeoutMs;
1220
+ constructor(memoryUrl: string, apiKeyOrOptions?: string | MemoryClientOptions);
1221
+ /** Encode a path segment to prevent URL injection */
1222
+ private encodePathSegment;
1223
+ private authorityHeaders;
1224
+ private exactReadAuthority;
1225
+ initialize(): Promise<void>;
1226
+ store(entry: StoreInput$1, options?: StoreOptions): Promise<MemoryEntry$1>;
1227
+ search(params: MemorySearchParams$1, authority?: RequestAuthorityOptions & Pick<TenantScopeOptions, 'tenantId' | 'namespaceId'>): Promise<MemorySearchResult$1>;
1228
+ get(id: string, authority?: TenantScopeOptions & RequestAuthorityOptions): Promise<MemoryEntry$1 | null>;
1229
+ delete(id: string, authority?: TenantScopeOptions & RequestAuthorityOptions): Promise<boolean>;
1230
+ clearSession(sessionId: string): Promise<number>;
1231
+ stats(options?: TenantScopeOptions): Promise<MemoryStats$1>;
1232
+ insights(options?: TenantScopeOptions & RequestAuthorityOptions): Promise<MemoryInsights$1>;
1233
+ /**
1234
+ * Fetch the running server's topology snapshot (build variant, declared
1235
+ * role, embedding location, active model profile). Round-trips the
1236
+ * server's `GET /status` envelope through {@link fetchApi}, surfacing any
1237
+ * non-success response as {@link MemoryServerError}. Auth-header
1238
+ * forwarding is unchanged from other client methods even though `/status`
1239
+ * is server-side public — the server simply ignores credentials on that
1240
+ * route.
1241
+ */
1242
+ status(): Promise<Topology$1>;
1243
+ shutdown(): Promise<void>;
1244
+ list(params?: MemoryListParams, authority?: RequestAuthorityOptions & Pick<TenantScopeOptions, 'tenantId' | 'namespaceId'>): Promise<MemoryListResult>;
1245
+ /**
1246
+ * Native streaming file ingest. Yields typed {@link IngestEvent}s as the
1247
+ * server (parsing/storing) and the SDK (enrichment/result) make progress.
1248
+ *
1249
+ * Wire contract: SDK POSTs with `Accept: application/x-ndjson`; the server
1250
+ * MUST respond with NDJSON. There is no JSON fallback — older servers
1251
+ * that emit `application/json` for this endpoint are not supported, and
1252
+ * the SDK yields a terminal `error` event in that case.
1253
+ *
1254
+ * After the server's terminal `result`, the SDK runs its own enrichment
1255
+ * phase (image-describe → entity-extract → `/enrich` POST), emitting
1256
+ * progress + heartbeat events around each step, then yields the single
1257
+ * terminal `result` event with the merged SDK + server result.
1258
+ *
1259
+ * Promise-shaped consumers should iterate the returned AsyncIterable and
1260
+ * collect the terminal event; there is no separate `ingestFile()` Promise
1261
+ * method by design (one wire format, one SDK method).
1262
+ */
1263
+ ingestFileEvents(file: File, options?: IngestFileOptions): AsyncIterable<IngestEvent$1>;
1264
+ /**
1265
+ * Graph-only re-enrichment for a document whose chunks are already stored
1266
+ * and searchable but whose graph build failed. Uploads the original to
1267
+ * `/api/memory/graph/enrich/file` (prepare-only — the server performs zero
1268
+ * store/delete before the final graph write), runs the SAME enrichment
1269
+ * callback engine as {@link ingestFileEvents}, then finalizes into one
1270
+ * stable graph anchor keyed by `documentKey`. Repeating the same key
1271
+ * replaces the document's graph references idempotently.
1272
+ *
1273
+ * The terminal `result` is a {@link GraphEnrichResult} event carrying the
1274
+ * ACTUAL persisted graph counts; abort and failures yield a terminal
1275
+ * `error` event instead (the server retains the pending session for retry).
1276
+ */
1277
+ graphEnrichFileEvents(file: File, options: GraphEnrichFileOptions): AsyncIterable<GraphEnrichEvent$1>;
1278
+ /**
1279
+ * POST a multipart body to an NDJSON streaming endpoint and relay its
1280
+ * progress/heartbeat events. Returns the raw terminal `result` record, or
1281
+ * null after yielding a terminal error (transport failure, server error
1282
+ * event, non-NDJSON response, stream ending without a result). One
1283
+ * implementation for both streaming surfaces so the wire protocol cannot
1284
+ * fork.
1285
+ */
1286
+ private streamNdjsonUpload;
1287
+ /**
1288
+ * Run the SDK-side enrichment phase for an ingest result and yield the
1289
+ * single terminal {@link IngestResultEvent} at the end. Skips work cleanly
1290
+ * when the server emitted no enrichment block or the caller wired no
1291
+ * callbacks. The callback work itself lives in
1292
+ * {@link runEnrichmentCallbacks} — shared with the graph-only surface.
1293
+ */
1294
+ private completeIngestFileEvents;
1295
+ /**
1296
+ * The ONE enrichment callback engine, shared by {@link ingestFileEvents}
1297
+ * and {@link graphEnrichFileEvents}: fetches extracted images, invokes
1298
+ * `describeImage` with bounded concurrency, invokes `extractEntitiesV2`
1299
+ * exactly once, and POSTs `/files/{fileId}/enrich` — emitting progress and
1300
+ * heartbeat events around each slow step. Throws on any failure; the
1301
+ * purpose-specific wrappers translate that into their terminal error.
1302
+ *
1303
+ * Legacy ingest keeps its existing partial add-on behavior. Graph-only and
1304
+ * documentKey-aware full ingest may replace a prior graph only from a
1305
+ * complete input set (no truncated text windows or undescribed images). A
1306
+ * complete extractor result containing zero entities remains a valid clear.
1307
+ */
1308
+ private runEnrichmentCallbacks;
1309
+ /**
1310
+ * Race a Promise against a periodic heartbeat tick. Yields a heartbeat
1311
+ * IngestEvent every {@link INGEST_EVENT_HEARTBEAT_MS} until the promise
1312
+ * settles, then returns the resolved value (or rethrows). Lets callers
1313
+ * keep upstream sockets alive through long LLM/HTTP work without
1314
+ * coupling the heartbeat cadence to the work itself.
1315
+ */
1316
+ private withSdkHeartbeats;
1317
+ private normalizeActiveIngestStage;
1318
+ private fileIngestResultFromEvent;
1319
+ private ingestErrorEvent;
1310
1320
  /**
1311
- * Deferred-embed queue depth. The in-process core always reports it (0 when
1312
- * idle); absent means unknown (older server or disabled client), never 0.
1321
+ * Get the download URL for an uploaded file.
1322
+ * Returns a URL that serves the original file binary with proper Content-Type.
1313
1323
  */
1314
- pendingEmbeddings?: number;
1315
- }
1316
- interface MemoryInsightMetrics {
1317
- activeEntries: number;
1318
- retainedAdditions7d: number;
1319
- appliedRecalls: number;
1320
- reinforcedEntries: number;
1321
- retrievedEntries: number;
1322
- retrievals: number;
1323
- lastAppliedAt: string | null;
1324
- lastRetrievedAt: string | null;
1325
- }
1326
- interface MemoryProjectInsight extends MemoryInsightMetrics {
1327
- label: string;
1328
- }
1329
- /** Body-free, caller-visible aggregate for product status surfaces. */
1330
- interface MemoryInsights {
1331
- generatedAt: string;
1332
- scope: 'connected_memory';
1333
- coverage: {
1334
- retainedAdditions: {
1335
- state: 'measured' | 'partial';
1336
- trackingSince: string | null;
1337
- trackedEntries: number;
1338
- totalEntries: number;
1339
- reason: string | null;
1340
- };
1341
- projectLabels: {
1342
- state: 'measured';
1343
- };
1344
- retrievalUsage: {
1345
- state: 'partial';
1346
- reason: string;
1347
- };
1348
- tokenEfficiency: {
1349
- state: 'not_instrumented';
1350
- reason: string;
1351
- };
1352
- contextAccuracy: {
1353
- state: 'not_instrumented';
1354
- reason: string;
1324
+ getFileDownloadUrl(filename: string, options?: FileDownloadOptions): string;
1325
+ /**
1326
+ * Download an uploaded file by filename.
1327
+ * Returns the raw Response (caller handles the body — arrayBuffer, blob, stream, etc.).
1328
+ */
1329
+ downloadFile(filename: string, options?: FileDownloadOptions): Promise<Response>;
1330
+ /** @deprecated Use {@link list} instead. Kept for backwards compatibility. */
1331
+ listEntries(params?: {
1332
+ page?: number;
1333
+ limit?: number;
1334
+ }): Promise<MemoryEntry$1[]>;
1335
+ graphNodes(): Promise<GraphNode$1[]>;
1336
+ graphEdges(): Promise<{
1337
+ stats: {
1338
+ nodeCount: number;
1339
+ edgeCount: number;
1340
+ rawNodeCount?: number;
1341
+ rawEdgeCount?: number;
1355
1342
  };
1356
- };
1357
- summary: {
1358
- activeEntries: number;
1359
- observedProjectLabels: number;
1360
- retainedAdditions7d: number | null;
1361
- trackedEntries: number;
1362
- appliedRecalls: number;
1363
- reinforcedEntries: number;
1364
- retrievedEntries: number;
1365
- retrievals: number;
1366
- };
1367
- projects: MemoryProjectInsight[];
1368
- other: MemoryInsightMetrics | null;
1369
- /** Most recently reinforced visible entries (≤5), labels only, never bodies. */
1370
- recentApplied?: Array<{
1371
- topic: string | null;
1372
- project: string | null;
1373
- at: string;
1374
1343
  }>;
1375
- }
1376
- interface GraphRepairResult {
1377
- staleEdgesDeleted: number;
1378
- staleNodeRefsRemoved: number;
1379
- orphanNodesDeleted: number;
1380
- }
1381
- interface GraphNode {
1382
- id: string;
1383
- name: string;
1384
- type: string;
1385
- canonicalId?: string;
1386
- sourceEvidence?: SourceEvidence[];
1387
- properties: Record<string, unknown>;
1388
- memoryEntryIds: string[];
1389
- }
1390
- interface GraphRelationship {
1391
- id: string;
1392
- sourceId: string;
1393
- targetId: string;
1394
- type: string;
1395
- sourceEvidence?: SourceEvidence[];
1396
- properties: Record<string, unknown>;
1397
- memoryEntryId?: string;
1344
+ graphQuery(query: {
1345
+ nodeId: string;
1346
+ depth?: number;
1347
+ }): Promise<GraphTraversalResult$1>;
1348
+ consolidate(): Promise<ConsolidationRunResult>;
1349
+ forget(id: string, reason?: string): Promise<boolean>;
1350
+ summarizeSession(sessionId: string): Promise<MemoryEntry$1 | null>;
1351
+ lint(options?: {
1352
+ limit?: number;
1353
+ }): Promise<WikiLintReport$1>;
1354
+ runDecay(): Promise<number>;
1355
+ reindex(): Promise<void>;
1356
+ clearGraph(): Promise<number>;
1357
+ repairGraph(): Promise<GraphRepairResult$1>;
1358
+ deleteBySource(source: string, authority?: TenantScopeOptions): Promise<number>;
1359
+ setFolder(from: string, to: string, options?: {
1360
+ dryRun?: boolean;
1361
+ }): Promise<{
1362
+ from: string;
1363
+ to: string;
1364
+ updated: number;
1365
+ dryRun: boolean;
1366
+ }>;
1367
+ queryAsOf(asOfDate: string, filters?: TemporalQueryFilters, authority?: TenantScopeOptions): Promise<MemoryEntry$1[]>;
1368
+ lineage(params: LineageParams$1, authority?: RequestAuthorityOptions): Promise<LineageResult$1>;
1369
+ reinforce(params: ReinforceParams$1, authority?: RequestAuthorityOptions): Promise<ReinforceResult$1>;
1370
+ log(filters?: MemoryLogFilters): Promise<MemoryEntry$1[]>;
1371
+ queryByEventTime(startTime: string, endTime: string, filters?: TemporalQueryFilters): Promise<MemoryEntry$1[]>;
1372
+ summarizeEntity(name: string): Promise<MemoryEntry$1>;
1373
+ getEntitySynthesis(name: string): Promise<MemoryEntry$1 | null>;
1398
1374
  /**
1399
- * Namespace_id provenance carried from the originating MemoryEntry.
1400
- * `null` (or absent) = legacy / tenant-root bucket. Foundation for the
1401
- * v0.17.0 strict traversal filter (the AuthzPlan compares this value
1402
- * edge-by-edge so KG dedupe at the node level can stay intact).
1375
+ * v0.26 user-profile snapshot — upsert. The server derives `userId`
1376
+ * from `X-User-Id` (caller wires it via `defaultHeaders` on the
1377
+ * client constructor or per-request middleware); the body cannot
1378
+ * override it. See spec §Requirements 10.
1403
1379
  */
1404
- namespaceId?: string | null;
1405
- }
1406
- interface GraphTraversalResult {
1407
- nodes: GraphNode[];
1408
- relationships: GraphRelationship[];
1409
- paths: Array<{
1410
- nodeIds: string[];
1411
- relationshipIds: string[];
1412
- }>;
1413
- }
1414
- /**
1415
- * Memory.lint() report shape — Karpathy-wiki Item B (v0.18.0).
1416
- * Read-only projection composed from signals every owning module
1417
- * already exposes. Lives in shared so the HTTP client can hold the
1418
- * same type as core without re-declaring it.
1419
- */
1420
- interface WikiLintReport {
1421
- orphans: GraphNode[];
1422
- decayCandidates: MemoryEntry[];
1423
- staleSyntheses: Array<{
1424
- entry: MemoryEntry;
1425
- reason: string;
1380
+ upsertUserProfile(input: {
1381
+ namespaceId: string;
1382
+ content: string;
1383
+ }): Promise<{
1384
+ updatedAt: string;
1385
+ contentSize: number;
1426
1386
  }>;
1427
- dedupCandidates: Array<{
1428
- hash: string;
1429
- entryIds: string[];
1387
+ /**
1388
+ * v0.26 user-profile snapshot — fetch by namespace. Returns `null` on
1389
+ * HTTP 404 (`isNotFound`), rethrows any other non-2xx as
1390
+ * `MemoryServerError`. Mirrors `get()`'s 404-to-null pattern so callers
1391
+ * can branch on "no profile yet" without inspecting status codes.
1392
+ */
1393
+ getUserProfile(namespaceId: string): Promise<{
1394
+ content: string;
1395
+ updatedAt: string;
1396
+ contentSize: number;
1397
+ } | null>;
1398
+ /**
1399
+ * v0.28 correction-memory — record an explicit correction. POSTs to
1400
+ * `/api/memory/corrections`; tenant is header-derived (server-side), so
1401
+ * the body carries only the correction fields. Returns `{ id, createdAt }`.
1402
+ */
1403
+ recordCorrection(input: {
1404
+ /** Omit in single-tenant deployments — corrections are stored namespace-free. */
1405
+ namespaceId?: string;
1406
+ whatWasWrong: string;
1407
+ whatToDoInstead: string;
1408
+ appliesWhen: string;
1409
+ project?: string;
1410
+ taskShape?: string;
1411
+ }): Promise<{
1412
+ id: string;
1413
+ createdAt: string;
1430
1414
  }>;
1415
+ /**
1416
+ * v0.28 correction-memory — fetch the corrections applicable to a task
1417
+ * shape. GETs `/api/memory/corrections`; returns `[]` when none have
1418
+ * positive overlap. pyx never auto-prepends — the agent owns inclusion.
1419
+ */
1420
+ fetchApplicableCorrections(input: {
1421
+ /** Omit in single-tenant deployments — reads the namespace-free scope. */
1422
+ namespaceId?: string;
1423
+ taskShape: string;
1424
+ project?: string;
1425
+ limit?: number;
1426
+ }): Promise<CorrectionRecord$1[]>;
1427
+ /**
1428
+ * H26 B-d — deterministic prospective due-scan: entries with
1429
+ * `eventTime ∈ [from, from+windowDays]` (inclusive), eventTime ascending,
1430
+ * no relevance ranking. `GET /api/memory/due`.
1431
+ */
1432
+ dueScan(input: {
1433
+ windowDays: number;
1434
+ from?: string;
1435
+ /** Omit in single-tenant deployments. */
1436
+ namespaceId?: string;
1437
+ limit?: number;
1438
+ }): Promise<MemoryEntry$1[]>;
1439
+ protected fetchApi<T>(path: string, options?: RequestInit): Promise<T>;
1440
+ /**
1441
+ * Map fetch-layer rejections into a typed `MemoryServerError` so callers
1442
+ * can react uniformly. AbortSignal.timeout fires a `TimeoutError`; the
1443
+ * caller's signal generally fires an `AbortError`. Anything else (DNS,
1444
+ * TCP reset, TLS) becomes a wrapped error with status 0.
1445
+ */
1446
+ private translateFetchError;
1447
+ /** Parse and validate a JSON API response, throwing MemoryServerError on any failure. */
1448
+ private parseApiResponse;
1449
+ }
1450
+
1451
+ interface IngestionResult {
1452
+ filename: string;
1453
+ fileType: string;
1454
+ chunks: number;
1455
+ entryIds: string[];
1456
+ totalCharacters: number;
1431
1457
  }
1432
1458
 
1459
+ declare const DEFAULTS: {
1460
+ readonly DATA_DIR: "./data";
1461
+ readonly VECTOR_PROVIDER: "lancedb";
1462
+ readonly MEMORY_SERVER_PORT: 7822;
1463
+ };
1464
+ declare const TAXONOMY_MAX_CATEGORIES = 10;
1465
+ declare const TAXONOMY_MAX_TOP_ENTITIES = 15;
1466
+ declare const TAXONOMY_MAX_SAMPLE_TOPICS = 8;
1467
+ declare const TAXONOMY_MAX_PROJECTS = 8;
1468
+ declare const MEMORY_PROJECT_LABEL_MAX_CHARS = 80;
1469
+
1433
1470
  /**
1434
1471
  * Result shape returned by an LLM entity extractor — entities + relations.
1435
1472
  *
@@ -1866,6 +1903,8 @@ declare const MoveFailureReason: {
1866
1903
  readonly GRAPH_UPDATE_FAILED: "graph_update_failed";
1867
1904
  /** Compensation itself failed — manual intervention required. */
1868
1905
  readonly COMPENSATION_FAILED: "compensation_failed";
1906
+ /** Target namespace already holds the entry's (session, ordinal) coordinate; nothing moved. */
1907
+ readonly SESSION_ORDINAL_CONFLICT: "session_ordinal_conflict";
1869
1908
  };
1870
1909
  type MoveFailureReason = (typeof MoveFailureReason)[keyof typeof MoveFailureReason];
1871
1910
  /**
@@ -1893,4 +1932,4 @@ interface CreatePyxMemoryOptions {
1893
1932
  }
1894
1933
  declare function createPyxMemory(opts?: CreatePyxMemoryOptions): MemoryClient;
1895
1934
 
1896
- export { type AgentId, type ApiResponse, type ConsolidationRunResult, type CorrectionInput, type CorrectionRecord, type CreatePyxMemoryOptions, DEFAULTS, DEPRECATED_RAG_STRATEGIES, DisabledMemory, type DroppedGraphRelationship, type DueScanInput, EmbeddingProviderName, type EnrichmentCallbacks, type EnrichmentPurpose, type EntityExtractionResult, type ExtendedMemoryInterface, type FetchCorrectionsInput, type FileDownloadOptions, type GraphEnrichEvent, type GraphEnrichFileOptions, type GraphEnrichPreparedEvent, type GraphEnrichResult, type GraphEnrichResultEvent, type GraphEnrichment, type GraphEnrichmentStatus, type GraphExtractionPayload, type GraphFailureMode, type GraphNode, type GraphRelationship, type GraphRepairResult, type GraphTelemetrySnapshot, type GraphTraversalResult, type IngestEntity, type IngestErrorEvent, type IngestEvent, type IngestFileOptions, type IngestHeartbeatEvent, type IngestProgressEvent, type IngestRelationship, type IngestResultEvent, type IngestStage, type IngestionResult, type LineageParams, type LineageResult, type LineageVersion, MEMORY_PROJECT_LABEL_MAX_CHARS, MemoryClient, type MemoryClientOptions, type MemoryEntry, type MemoryIngestRequest, type MemoryInsightMetrics, type MemoryInsights, type MemoryInterface, type MemoryListParams, type MemoryListResult, type MemoryLogFilters, type MemoryProjectInsight, type MemorySearchParams, type MemorySearchResult, MemoryServerError, type MemoryStats, MemoryType, type MoveEntriesFilter, MoveFailureReason, type MoveResult, type MoveTarget, NamespaceIsolation, type PrincipalContext, RAGStrategy, type ReinforceParams, type ReinforceResult, type ReinforceSignal, SINGLE_TENANT_ID, type SecretElevationAggregate, type SecretElevationNotice, SensitivityLevel, type SourceEvidence, type StoreInput, StoreTarget, TAXONOMY_MAX_CATEGORIES, TAXONOMY_MAX_PROJECTS, TAXONOMY_MAX_SAMPLE_TOPICS, TAXONOMY_MAX_TOP_ENTITIES, type TemporalQueryFilters, type TenantScopeOptions, type Timestamp, type Topology, type TopologyExtractionProvider, type TopologyServiceVariant, type UsageHygieneSnapshot, VectorProvider, type VectorStatus, type WikiLintReport, assertGraphExtractionPayload, createPyxMemory, mergeExtractedEntities, normalizeGraphLabel, normalizeNameKey, projectSearchResponseForMcp, secretElevationAggregate, secretElevationNoticeFor, withSecretElevationNotice };
1935
+ export { type AgentId, type ApiResponse, type ConsolidationRunResult, type CorrectionInput, type CorrectionRecord, type CreatePyxMemoryOptions, DEFAULTS, DEPRECATED_RAG_STRATEGIES, DisabledMemory, type DroppedGraphRelationship, type DueScanInput, EmbeddingProviderName, type EnrichmentCallbacks, type EnrichmentPurpose, type EntityExtractionResult, type ExpandAnchorStatus, type ExpandParams, type ExpandResult, type ExtendedMemoryInterface, type FetchCorrectionsInput, type FileDownloadOptions, type GraphEnrichEvent, type GraphEnrichFileOptions, type GraphEnrichPreparedEvent, type GraphEnrichResult, type GraphEnrichResultEvent, type GraphEnrichment, type GraphEnrichmentStatus, type GraphExtractionPayload, type GraphFailureMode, type GraphNode, type GraphRelationship, type GraphRepairResult, type GraphTelemetrySnapshot, type GraphTraversalResult, type IngestEntity, type IngestErrorEvent, type IngestEvent, type IngestFileOptions, type IngestHeartbeatEvent, type IngestProgressEvent, type IngestRelationship, type IngestResultEvent, type IngestStage, type IngestionResult, type LineageParams, type LineageResult, type LineageVersion, MEMORY_PROJECT_LABEL_MAX_CHARS, MemoryClient, type MemoryClientOptions, type MemoryEntry, type MemoryIngestRequest, type MemoryInsightMetrics, type MemoryInsights, type MemoryInterface, type MemoryListParams, type MemoryListResult, type MemoryLogFilters, type MemoryProjectInsight, type MemorySearchParams, type MemorySearchResult, MemoryServerError, type MemoryStats, MemoryType, type MoveEntriesFilter, MoveFailureReason, type MoveResult, type MoveTarget, NamespaceIsolation, type PrincipalContext, RAGStrategy, type ReinforceParams, type ReinforceResult, type ReinforceSignal, SESSION_ORDINAL_MAX, SINGLE_TENANT_ID, type SecretElevationAggregate, type SecretElevationNotice, SensitivityLevel, type SourceEvidence, type StoreInput, StoreTarget, TAXONOMY_MAX_CATEGORIES, TAXONOMY_MAX_PROJECTS, TAXONOMY_MAX_SAMPLE_TOPICS, TAXONOMY_MAX_TOP_ENTITIES, type TemporalQueryFilters, type TenantScopeOptions, type Timestamp, type Topology, type TopologyExtractionProvider, type TopologyServiceVariant, type UsageHygieneSnapshot, VectorProvider, type VectorStatus, type WikiLintReport, assertGraphExtractionPayload, createPyxMemory, isSessionOrdinal, mergeExtractedEntities, normalizeGraphLabel, normalizeNameKey, projectSearchResponseForMcp, secretElevationAggregate, secretElevationNoticeFor, withSecretElevationNotice };