qlogicagent 2.19.12 → 2.19.14

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.
Files changed (31) hide show
  1. package/dist/agent.js +26 -25
  2. package/dist/cli.js +1 -1
  3. package/dist/host-contract.js +1 -1
  4. package/dist/index.js +364 -360
  5. package/dist/orchestration.js +7 -7
  6. package/dist/project-memory-host.js +10 -10
  7. package/dist/protocol.js +1 -1
  8. package/dist/types/cli/handlers/memory-handler.d.ts +4 -35
  9. package/dist/types/cli/rpc-registry.d.ts +4 -4
  10. package/dist/types/cli/task-distillation-coordinator.d.ts +48 -11
  11. package/dist/types/contracts/error-category.d.ts +11 -0
  12. package/dist/types/contracts/hooks.d.ts +2 -0
  13. package/dist/types/host-contract/index.d.ts +3 -3
  14. package/dist/types/orchestration/error-handling/error-classification.d.ts +2 -2
  15. package/dist/types/runtime/execution/dream-agent.d.ts +11 -1
  16. package/dist/types/runtime/hooks/memory-hooks.d.ts +10 -3
  17. package/dist/types/runtime/infra/llmrouter-managed-inference.d.ts +1 -1
  18. package/dist/types/runtime/memory/find-relevant-memories.d.ts +0 -44
  19. package/dist/types/runtime/ports/memory-provider.d.ts +15 -2
  20. package/dist/types/skills/memory/host-memory-provider.d.ts +43 -0
  21. package/dist/types/skills/memory/task-distillation.d.ts +29 -19
  22. package/package.json +2 -2
  23. package/dist/types/runtime/infra/codex-llmrouter-compat-proxy.d.ts +0 -4
  24. package/dist/types/skills/memory/local-store-records.d.ts +0 -206
  25. package/dist/types/skills/memory/local-store.d.ts +0 -376
  26. package/dist/types/skills/memory/memory-attachment-store.d.ts +0 -62
  27. package/dist/types/skills/memory/memory-consolidation.d.ts +0 -64
  28. package/dist/types/skills/memory/memory-db-path.d.ts +0 -13
  29. package/dist/types/skills/memory/proposal-consumer.d.ts +0 -51
  30. package/dist/types/skills/memory/sqlite-memory-mappers.d.ts +0 -7
  31. package/dist/types/skills/memory/sqlite-memory-schema.d.ts +0 -11
@@ -1,206 +0,0 @@
1
- /** Lightweight attachment reference carried on records / atlas wire (no bytes, no extractedText). */
2
- export interface MemoryAttachmentRef {
3
- id: string;
4
- kind: string;
5
- filename: string;
6
- mimeType: string;
7
- size: number;
8
- url: string;
9
- }
10
- export interface MemoryRecord {
11
- id: string;
12
- text: string;
13
- userId: string;
14
- category: string;
15
- importance: number;
16
- confidence: number;
17
- source: string;
18
- sessionId: string;
19
- eventDate: string;
20
- tags: string[];
21
- embedding: Float32Array | null;
22
- createdAt: number;
23
- updatedAt: number;
24
- accessCount: number;
25
- lastAccessedAt: number;
26
- isArchived: boolean;
27
- /** Lightweight attachment refs (populated by the provider for atlas/detail). */
28
- attachments?: MemoryAttachmentRef[];
29
- }
30
- export interface MemoryInsertInput {
31
- text: string;
32
- userId: string;
33
- category?: string;
34
- importance?: number;
35
- confidence?: number;
36
- source?: string;
37
- sessionId?: string;
38
- eventDate?: string;
39
- tags?: string[];
40
- embedding?: Float32Array;
41
- /** Provenance of `embedding` (model id). Vectors from different models are not
42
- * comparable; search skips rows whose model/dims mismatch the query's. */
43
- embeddingModel?: string;
44
- }
45
- export interface MemoryUpdateInput {
46
- text?: string;
47
- category?: string;
48
- importance?: number;
49
- source?: string;
50
- eventDate?: string;
51
- tags?: string[];
52
- embedding?: Float32Array | null;
53
- /** Provenance of the replacement embedding (see MemoryInsertInput). */
54
- embeddingModel?: string;
55
- }
56
- export interface MemorySearchHit {
57
- id: string;
58
- text: string;
59
- score: number;
60
- category: string;
61
- importance: number;
62
- metadata: Record<string, unknown>;
63
- }
64
- export interface MemoryAtlasBucket {
65
- id: string;
66
- startAt: number;
67
- endAt: number;
68
- count: number;
69
- avgImportance: number;
70
- avgConfidence: number;
71
- topCategory: string;
72
- }
73
- export interface MemoryAtlasCluster {
74
- id: string;
75
- label: string;
76
- kind: "source" | "category" | "tag";
77
- count: number;
78
- startAt: number;
79
- endAt: number;
80
- avgImportance: number;
81
- avgConfidence: number;
82
- topCategory: string;
83
- }
84
- export interface MemoryAtlasWindowCursor {
85
- startAt: number;
86
- endAt: number;
87
- centerAt: number;
88
- pageSize: number;
89
- hasBefore: boolean;
90
- hasAfter: boolean;
91
- }
92
- export interface MemoryAtlasResult {
93
- totalCount: number;
94
- records: MemoryRecord[];
95
- buckets: MemoryAtlasBucket[];
96
- clusters: MemoryAtlasCluster[];
97
- windowCursor: MemoryAtlasWindowCursor | null;
98
- timeRange: {
99
- startAt: number;
100
- endAt: number;
101
- } | null;
102
- }
103
- export type MemorySourceKind = "manual" | "explicit" | "document" | "image" | "video" | "auto" | "turn" | "dream" | "agent" | "feedback";
104
- export type MemoryClaimStatus = "active" | "superseded" | "conflicted" | "archived" | "pending_confirmation";
105
- export type MemoryProposalStatus = "pending" | "accepted" | "merged" | "conflicted" | "rejected" | "expired";
106
- export interface MemoryObservationInput {
107
- userId: string;
108
- text: string;
109
- source: string;
110
- sourcePriority: number;
111
- sessionId?: string;
112
- evidenceType?: string;
113
- payload?: Record<string, unknown>;
114
- }
115
- export interface MemoryObservationRecord extends Required<Omit<MemoryObservationInput, "payload" | "sessionId" | "evidenceType">> {
116
- id: string;
117
- sessionId: string;
118
- evidenceType: string;
119
- payload: Record<string, unknown>;
120
- createdAt: number;
121
- }
122
- export interface MemoryProposalInput {
123
- userId: string;
124
- observationIds: string[];
125
- text: string;
126
- category: string;
127
- importance: number;
128
- confidence: number;
129
- source: string;
130
- sourcePriority: number;
131
- entity: string;
132
- predicate: string;
133
- value: Record<string, unknown>;
134
- validTime?: string;
135
- tags?: string[];
136
- status?: MemoryProposalStatus;
137
- relatedClaimIds?: string[];
138
- /**
139
- * Crash-safe dedup key for evidence-bearing sources (feedback distillation — §10). When set,
140
- * proposeExtracted skips inserting a duplicate proposal for the same key. Left undefined by all
141
- * existing callers (LLM extraction / dream / manual), so their behaviour is unchanged.
142
- */
143
- idempotencyKey?: string;
144
- }
145
- export interface MemoryProposalRecord extends Omit<MemoryProposalInput, "value" | "validTime" | "tags" | "status" | "relatedClaimIds"> {
146
- id: string;
147
- value: Record<string, unknown>;
148
- validTime: string;
149
- tags: string[];
150
- status: MemoryProposalStatus;
151
- relatedClaimIds: string[];
152
- createdAt: number;
153
- updatedAt: number;
154
- }
155
- export interface MemoryClaimInput {
156
- userId: string;
157
- memoryId?: string;
158
- entity: string;
159
- predicate: string;
160
- value: Record<string, unknown>;
161
- text: string;
162
- category: string;
163
- importance: number;
164
- confidence: number;
165
- source: string;
166
- sourcePriority: number;
167
- status: MemoryClaimStatus;
168
- validTime?: string;
169
- evidenceIds: string[];
170
- supersedesClaimId?: string;
171
- conflictGroupId?: string;
172
- }
173
- export interface MemoryClaimRecord extends Omit<MemoryClaimInput, "memoryId" | "value" | "validTime" | "supersedesClaimId" | "conflictGroupId"> {
174
- id: string;
175
- memoryId: string;
176
- value: Record<string, unknown>;
177
- validTime: string;
178
- supersedesClaimId: string;
179
- conflictGroupId: string;
180
- createdAt: number;
181
- updatedAt: number;
182
- }
183
- export interface MemoryConflictRecord {
184
- id: string;
185
- userId: string;
186
- claimAId: string;
187
- claimBId: string;
188
- reason: string;
189
- status: "open" | "resolved" | "dismissed";
190
- createdAt: number;
191
- updatedAt: number;
192
- }
193
- export interface SqliteDatabase {
194
- exec(sql: string): void;
195
- prepare(sql: string): SqliteStatement;
196
- pragma(pragma: string): unknown;
197
- close(): void;
198
- }
199
- export interface SqliteStatement {
200
- run(...params: unknown[]): {
201
- changes: number;
202
- lastInsertRowid: number | bigint;
203
- };
204
- get(...params: unknown[]): unknown;
205
- all(...params: unknown[]): unknown[];
206
- }
@@ -1,376 +0,0 @@
1
- /**
2
- * Local Memory Store - SQLite-backed persistence for qmemory.
3
- *
4
- * Ported from Python qmemory's memory_store.py + db.py.
5
- * Uses better-sqlite3 for synchronous, fast, single-file persistence.
6
- *
7
- * Storage location:
8
- * ~/.qlogicagent/profiles/<owner_user_id>/memory/memories.db
9
- *
10
- * Schema:
11
- * - memories: core fact storage with optional embedding blob
12
- * - memories_fts: FTS5 full-text index for keyword search
13
- * - profiles: user profile KV (future)
14
- */
15
- import type { MemoryAtlasResult, MemoryClaimInput, MemoryClaimRecord, MemoryClaimStatus, MemoryConflictRecord, MemoryInsertInput, MemoryObservationInput, MemoryProposalInput, MemoryProposalRecord, MemoryProposalStatus, MemoryRecord, MemorySearchHit, MemoryUpdateInput, SqliteDatabase } from "./local-store-records.js";
16
- export { resolveMemoryDbPath } from "./memory-db-path.js";
17
- export type { MemoryAtlasBucket, MemoryAtlasCluster, MemoryAtlasResult, MemoryAtlasWindowCursor, MemoryAttachmentRef, MemoryClaimInput, MemoryClaimRecord, MemoryClaimStatus, MemoryConflictRecord, MemoryInsertInput, MemoryObservationInput, MemoryObservationRecord, MemoryProposalInput, MemoryProposalRecord, MemoryProposalStatus, MemoryRecord, MemorySearchHit, MemorySourceKind, MemoryUpdateInput, SqliteDatabase, SqliteStatement, } from "./local-store-records.js";
18
- /** Full attachment index row (DB-backed; file bytes live on disk under the attachments dir). */
19
- export interface MemoryAttachmentRow {
20
- id: string;
21
- memoryId: string;
22
- userId: string;
23
- kind: string;
24
- filename: string;
25
- mimeType: string;
26
- size: number;
27
- relPath: string;
28
- extractedText: string;
29
- createdAt: number;
30
- }
31
- export interface MemoryAttachmentInsert {
32
- id: string;
33
- userId: string;
34
- kind: string;
35
- filename: string;
36
- mimeType: string;
37
- size: number;
38
- relPath: string;
39
- extractedText?: string;
40
- memoryId?: string;
41
- }
42
- export declare class LocalMemoryStore {
43
- private db;
44
- /** Stamped onto rows whose embedding arrives without explicit provenance
45
- * (the consolidation pipeline passes bare vectors). Set by the provider. */
46
- private defaultEmbeddingModel;
47
- constructor(db: SqliteDatabase);
48
- setDefaultEmbeddingModel(model: string): void;
49
- private initSchema;
50
- /**
51
- * Insert a new memory record. Returns the generated ID.
52
- */
53
- insert(input: MemoryInsertInput): string;
54
- /**
55
- * Full-text search using FTS5. Returns ranked results.
56
- */
57
- searchFts(query: string, userId: string, limit?: number): MemorySearchHit[];
58
- /** One-shot flag: embedding provenance mismatches are traced once per store instance. */
59
- private embeddingMismatchLogged;
60
- /**
61
- * Vector similarity search using pre-computed embeddings.
62
- * Performs brute-force cosine similarity (efficient for <100k records per user).
63
- *
64
- * Rows whose embedding provenance (dims, and model when both sides are known)
65
- * differs from the query's are SKIPPED, not scored: cosine between vectors of
66
- * different models/dims is numeric noise, and truncated dot products silently
67
- * corrupt ranking. Legacy rows (no provenance columns) are accepted when their
68
- * dimension happens to match — dropping them all would blank historical recall.
69
- */
70
- searchVector(queryEmbedding: Float32Array, userId: string, limit?: number, minScore?: number, expectedModel?: string): MemorySearchHit[];
71
- /**
72
- * Hybrid search: FTS5 + vector similarity, fused by rank-tempered RRF.
73
- *
74
- * Two currencies, each carrying signal the other cannot:
75
- * - channel scores (0-1, isomorphic across FTS/vector) carry MAGNITUDE —
76
- * an exact lexical hit must beat weak-consensus noise, which pure rank
77
- * fusion cannot guarantee (rank ignores how strong a match is);
78
- * - reciprocal ranks carry CONSENSUS and are scale-invariant — as the
79
- * store grows, BM25 inflates until squashed top scores compress to
80
- * near-ties and the two channels' score distributions drift apart;
81
- * ranks keep differentiating where magnitudes saturate.
82
- * fused = (1-w)*magnitude + w*rrfNorm keeps both properties. Magnitude of a
83
- * dual hit is the stronger channel plus a fraction of the weaker (consensus
84
- * also rewarded in score space); rrfNorm is the reciprocal-rank sum
85
- * normalized so a dual #1 hit = 1.0. FTS ranks follow BM25 order, vector
86
- * ranks follow the blended channel order — each channel's own relevance
87
- * ordering. Rows found by FTS only (e.g. no embedding) compete in the same
88
- * fused domain and remain reachable, not buried.
89
- */
90
- searchHybrid(query: string, queryEmbedding: Float32Array | null, userId: string, limit?: number, expectedModel?: string): MemorySearchHit[];
91
- /**
92
- * Get all memories for a user (paginated).
93
- */
94
- listByUser(userId: string, page?: number, pageSize?: number, activeOnly?: boolean): MemoryRecord[];
95
- /**
96
- * All active memories carrying a tag (LIKE match on the quoted JSON-array
97
- * element). Tag consumers (resident refresh / onboarding replace-purge) need
98
- * the COMPLETE tag set regardless of age — the windowed atlas read silently
99
- * truncated them once history outgrew one page/time window. No LIMIT by
100
- * design: a capped "complete" read is the same bug at a higher threshold
101
- * (a purge that misses rows resurrects stale memories). Tag sets are small
102
- * (one origin/resident group), and this is not a hot path.
103
- */
104
- listByTag(userId: string, tag: string): MemoryRecord[];
105
- /**
106
- * Return a windowed atlas payload for large-history visualization.
107
- *
108
- * `records` are only the interactive window. `buckets` and `clusters` summarize
109
- * the whole history so the UI can render distant history as star dust /
110
- * aggregate galaxies without loading every memory as an interactive object.
111
- */
112
- getAtlas(userId: string, options?: {
113
- pageSize?: number;
114
- windowStartAt?: number;
115
- windowEndAt?: number;
116
- windowCenterAt?: number;
117
- bucketCount?: number;
118
- clusterLimit?: number;
119
- activeOnly?: boolean;
120
- }): MemoryAtlasResult;
121
- private getAtlasBuckets;
122
- private getAtlasClusters;
123
- /**
124
- * Get a single memory by ID.
125
- */
126
- getById(id: string): MemoryRecord | null;
127
- /**
128
- * Update memory text and bump updatedAt.
129
- */
130
- updateText(id: string, text: string, embedding?: Float32Array, embeddingModel?: string): boolean;
131
- /**
132
- * Update editable memory fields and bump updatedAt.
133
- */
134
- update(id: string, input: MemoryUpdateInput): boolean;
135
- /**
136
- * Delete a memory by ID.
137
- */
138
- delete(id: string): boolean;
139
- /**
140
- * Archive a memory (soft-delete: set is_archived=1).
141
- * Used by dedup gate when a similar but newer memory supersedes an older one.
142
- */
143
- archive(id: string): boolean;
144
- /** V3 demote(降格)恢复:archived procedure 回归召回池,与 archive 成对。 */
145
- unarchive(id: string): boolean;
146
- /**
147
- * Temporal expiry: archive event/plan memories whose event_date has passed
148
- * beyond a grace period (e.g., "meeting tomorrow" 3 days after it happened).
149
- */
150
- decayTemporalExpiry(userId: string, graceDays?: number): number;
151
- /**
152
- * Staleness decay: reduce importance of memories not accessed in a long time.
153
- * Memories accessed recently retain their importance; stale ones degrade.
154
- */
155
- decayStaleness(userId: string, staleDays?: number, decayFactor?: number): number;
156
- /**
157
- * Noise archival: archive low-importance memories that never got accessed.
158
- * Memories written by the agent but never recalled are likely noise.
159
- */
160
- decayNoiseArchival(userId: string, minAgeDays?: number, maxImportance?: number): number;
161
- /**
162
- * Observation retention: memory_observations is an append-only audit trail
163
- * (every propose/commit writes one) with NO reader of its own — without a
164
- * retention window it grows forever, the same disease the proposals table
165
- * had before the consumer existed. Delete rows older than the window that
166
- * are NOT referenced by any claim's evidence_ids or proposal's
167
- * observation_ids (referenced rows are live audit evidence and stay).
168
- */
169
- decayObservations(userId: string, retentionDays?: number): number;
170
- /**
171
- * Resolved-proposal retention: terminal rows (accepted/merged/rejected/
172
- * expired) are processing history, not memory — past the window they only
173
- * grow the table. Rows carrying an idempotency_key are KEPT FOREVER: they
174
- * are the crash-safe ledger that stops feedback distillation from
175
- * re-proposing the same evidence cluster (deleting them would re-open the
176
- * exact duplicate-write hole the key exists to close). Pending rows are
177
- * never touched here — the consumer owns their TTL (status=expired).
178
- */
179
- decayResolvedProposals(userId: string, retentionDays?: number): number;
180
- /**
181
- * Run all decay strategies. Returns total affected count.
182
- */
183
- runFullDecay(userId: string, options?: {
184
- temporalGraceDays?: number;
185
- staleDays?: number;
186
- staleDecayFactor?: number;
187
- noiseMinAgeDays?: number;
188
- noiseMaxImportance?: number;
189
- }): {
190
- temporal: number;
191
- stale: number;
192
- noise: number;
193
- total: number;
194
- };
195
- /**
196
- * Apply feedback signal to a memory, adjusting importance accordingly.
197
- *
198
- * Signals:
199
- * - "useful" boosts importance by +0.15 (capped at 1.0)
200
- * - "irrelevant" reduces importance by -0.2
201
- * - "outdated" archives immediately
202
- * - "wrong" deletes immediately
203
- */
204
- applyFeedback(memoryId: string, signal: "useful" | "irrelevant" | "outdated" | "wrong"): boolean;
205
- /**
206
- * Get a profile value for a user.
207
- */
208
- getProfile(userId: string, key: string): string | null;
209
- /**
210
- * Set a profile value (upsert).
211
- */
212
- setProfile(userId: string, key: string, value: string): void;
213
- /**
214
- * Get all profile entries for a user.
215
- */
216
- getAllProfiles(userId: string): Record<string, string>;
217
- /**
218
- * Delete a profile entry.
219
- */
220
- deleteProfile(userId: string, key: string): boolean;
221
- private profileTableCreated;
222
- private ensureProfileTable;
223
- /**
224
- * Retrieve memories within a time range, grouped by day.
225
- * Used for "what happened last week" type queries and dream synthesis.
226
- */
227
- getTemporalSlice(userId: string, startMs: number, endMs: number, options?: {
228
- category?: string;
229
- limit?: number;
230
- }): Array<{
231
- date: string;
232
- memories: Array<{
233
- id: string;
234
- text: string;
235
- category: string;
236
- importance: number;
237
- }>;
238
- }>;
239
- /**
240
- * Get memory activity summary over recent N days.
241
- * Returns daily counts and high-importance entries used by temporal synthesis.
242
- */
243
- getActivitySummary(userId: string, days?: number): {
244
- dailyCounts: Array<{
245
- date: string;
246
- count: number;
247
- }>;
248
- highlights: Array<{
249
- id: string;
250
- text: string;
251
- category: string;
252
- importance: number;
253
- date: string;
254
- }>;
255
- };
256
- /**
257
- * Record an access (for importance/relevance boosting).
258
- */
259
- recordAccess(id: string): void;
260
- /** Total active memory rows across ALL users (health reporting). */
261
- countAll(): number;
262
- /**
263
- * Get total memory count for a user.
264
- */
265
- count(userId: string, activeOnly?: boolean): number;
266
- /**
267
- * Delete ALL long-term memory state for a user — every table, not just
268
- * `memories`. Claims carry entity/predicate/value facts in clear text and
269
- * observations carry raw conversation excerpts; leaving them behind after a
270
- * "clear my memory" is a broken privacy promise, not a smaller reset.
271
- *
272
- * Returns the attachment rel_paths so the caller can delete the on-disk
273
- * files (the store only owns the index rows).
274
- */
275
- resetUser(userId: string): {
276
- memories: number;
277
- observations: number;
278
- proposals: number;
279
- claims: number;
280
- conflicts: number;
281
- profiles: number;
282
- attachmentRelPaths: string[];
283
- };
284
- /**
285
- * Run SQLite VACUUM to reclaim space after deletions/archival.
286
- * Should be called periodically (e.g. after decay cycles).
287
- */
288
- vacuum(): void;
289
- /**
290
- * Get database size info for capacity monitoring.
291
- */
292
- getStorageStats(): {
293
- pageCount: number;
294
- pageSize: number;
295
- totalBytes: number;
296
- freePages: number;
297
- };
298
- /**
299
- * List the oldest archived memories for cold-storage export. Read-only:
300
- * purging is a SEPARATE step (purgeMemoriesByIds) the caller performs only
301
- * after the export has durably landed on disk. The old fused
302
- * export-then-delete shape destroyed data whenever the caller dropped the
303
- * return value.
304
- */
305
- listArchivedForExport(userId: string, maxExport?: number): Array<{
306
- id: string;
307
- text: string;
308
- category: string;
309
- importance: number;
310
- createdAt: number;
311
- archivedAt: number;
312
- tags: string[];
313
- }>;
314
- /** Physically delete memory rows by id (post-export purge step). */
315
- purgeMemoriesByIds(ids: string[]): number;
316
- /**
317
- * Enforce capacity limit: if active memories exceed maxCount,
318
- * archive the oldest lowest-importance ones.
319
- */
320
- enforceCapacityLimit(userId: string, maxCount?: number): number;
321
- insertObservation(input: MemoryObservationInput): string;
322
- insertProposal(input: MemoryProposalInput): string;
323
- /**
324
- * Look up an existing proposal by its idempotency key (feedback distillation — §10). Returns the
325
- * proposal id if one already exists for this user + key, else null, letting proposeExtracted skip
326
- * a duplicate crash-safely (the key survives a worker restart mid-sweep).
327
- */
328
- findProposalByIdempotencyKey(userId: string, idempotencyKey: string): string | null;
329
- /**
330
- * List proposals by status (oldest first) — the read side of the proposal
331
- * consumer. Pending proposals from implicit-extract / feedback / dream used
332
- * to have NO reader at all: they accumulated forever and never became
333
- * searchable memories.
334
- */
335
- listProposalsByStatus(userId: string, status: MemoryProposalStatus, limit?: number): MemoryProposalRecord[];
336
- /** Bulk status transition for the proposal consumer (corroborated / expired). */
337
- markProposalsStatus(ids: string[], status: MemoryProposalStatus): number;
338
- updateProposalStatus(id: string, status: MemoryProposalStatus, relatedClaimIds?: string[]): boolean;
339
- insertClaim(input: MemoryClaimInput): string;
340
- listClaims(userId: string, statuses?: MemoryClaimStatus[]): MemoryClaimRecord[];
341
- findClaimsByFact(userId: string, entity: string, predicate: string, validTime?: string): MemoryClaimRecord[];
342
- mergeClaimEvidence(id: string, evidenceIds: string[], confidence: number, importance: number): boolean;
343
- updateClaimsByMemoryId(memoryId: string, status: MemoryClaimStatus): number;
344
- insertConflict(input: {
345
- userId: string;
346
- claimAId: string;
347
- claimBId: string;
348
- reason: string;
349
- }): string;
350
- listConflicts(userId: string): MemoryConflictRecord[];
351
- getClaimById(id: string): MemoryClaimRecord | undefined;
352
- setClaimStatus(id: string, status: MemoryClaimStatus): boolean;
353
- /** Mark a conflict resolved (the resolver has already updated the claims). */
354
- setConflictStatus(id: string, status: "open" | "resolved" | "dismissed"): boolean;
355
- /** Open conflicts only (the ones needing resolution). */
356
- listOpenConflicts(userId: string): MemoryConflictRecord[];
357
- /**
358
- * Promote pending_confirmation claims that have accumulated enough independent
359
- * evidence to become active. Returns the number promoted.
360
- */
361
- promotePendingClaims(userId: string, minEvidence: number): number;
362
- insertAttachment(input: MemoryAttachmentInsert): void;
363
- getAttachmentById(id: string): MemoryAttachmentRow | null;
364
- listAttachmentsByMemoryId(memoryId: string): MemoryAttachmentRow[];
365
- /** Batch-load attachments for many memories (for atlas windows). */
366
- listAttachmentsByMemoryIds(memoryIds: string[]): Map<string, MemoryAttachmentRow[]>;
367
- /** Link orphan/owned attachments to a committed memory. Returns linked count. */
368
- linkAttachments(memoryId: string, attachmentIds: string[], userId: string): number;
369
- setAttachmentExtractedText(id: string, text: string): boolean;
370
- /** Delete attachment index rows for a memory; returns their rel paths for file cleanup. */
371
- deleteAttachmentsByMemoryId(memoryId: string): string[];
372
- /** Orphan attachments (uploaded but never saved to a memory) older than cutoff. */
373
- listOrphanAttachments(cutoff: number): MemoryAttachmentRow[];
374
- deleteAttachmentById(id: string): void;
375
- close(): void;
376
- }
@@ -1,62 +0,0 @@
1
- /**
2
- * MemoryAttachmentStore — persistent attachment storage for long-term memory.
3
- *
4
- * Files live beside the memory DB, with no expiry:
5
- * ~/.qlogicagent/profiles/<owner>/memory/attachments/<id><ext>
6
- * The DB (`memory_attachments` table, via LocalMemoryStore) is the index;
7
- * this class owns the on-disk bytes + ties index rows to files.
8
- *
9
- * Lifecycle: an attachment is `adopt`ed at upload time (orphan, memory_id=''),
10
- * then `link`ed to a memory at commit; on memory delete the files+rows are
11
- * removed; long-orphaned uploads are purged.
12
- */
13
- import type { LocalMemoryStore, MemoryAttachmentRef, MemoryAttachmentRow } from "./local-store.js";
14
- export declare const MAX_ATTACHMENT_BYTES: number;
15
- export type AttachmentKind = "image" | "audio" | "video" | "doc" | "file";
16
- export declare function attachmentKindFromMime(mimeType: string, filename?: string): AttachmentKind;
17
- export interface AdoptedAttachment {
18
- id: string;
19
- kind: AttachmentKind;
20
- filename: string;
21
- mimeType: string;
22
- size: number;
23
- url: string;
24
- }
25
- export interface AdoptInput {
26
- /** Raw bytes (preferred). */
27
- data?: Buffer;
28
- /** Or a URL the store fetches (e.g. the gateway's temp MediaStore url). */
29
- sourceUrl?: string;
30
- filename: string;
31
- mimeType: string;
32
- userId: string;
33
- }
34
- export declare class MemoryAttachmentStore {
35
- private readonly store;
36
- private readonly dir;
37
- constructor(store: LocalMemoryStore, dir: string);
38
- urlFor(id: string): string;
39
- toRef(row: MemoryAttachmentRow): MemoryAttachmentRef;
40
- /** Persist an uploaded file + create an orphan index row (memory_id=''). */
41
- adopt(input: AdoptInput): Promise<AdoptedAttachment>;
42
- /** Read an attachment's bytes + mime (for multimodal understanding). */
43
- readBytes(id: string): Promise<{
44
- bytes: Buffer;
45
- mimeType: string;
46
- } | null>;
47
- /** Resolve an attachment to an absolute on-disk path (for serving). Guards traversal. */
48
- locate(id: string): Promise<{
49
- absPath: string;
50
- mimeType: string;
51
- filename: string;
52
- } | null>;
53
- link(memoryId: string, attachmentIds: string[], userId: string): number;
54
- setExtractedText(id: string, text: string): void;
55
- refsForMemory(memoryId: string): MemoryAttachmentRef[];
56
- /** Map of memoryId → refs, for atlas windows. */
57
- refsForMemories(memoryIds: string[]): Map<string, MemoryAttachmentRef[]>;
58
- /** Remove all files + index rows for a deleted memory. */
59
- removeByMemoryId(memoryId: string): Promise<void>;
60
- /** Purge uploads that were never linked to a saved memory. */
61
- purgeOrphans(olderThanMs?: number): Promise<void>;
62
- }