hoomanjs 1.0.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.
Files changed (96) hide show
  1. package/.github/screenshot.png +0 -0
  2. package/.github/workflows/build-publish.yml +49 -0
  3. package/LICENSE +21 -0
  4. package/README.md +399 -0
  5. package/docker-compose.yml +13 -0
  6. package/package.json +78 -0
  7. package/src/acp/acp-agent.ts +803 -0
  8. package/src/acp/approvals.ts +147 -0
  9. package/src/acp/index.ts +1 -0
  10. package/src/acp/meta/system-prompt.ts +44 -0
  11. package/src/acp/meta/user-id.ts +44 -0
  12. package/src/acp/prompt-invoke.ts +149 -0
  13. package/src/acp/sessions/config-options.ts +56 -0
  14. package/src/acp/sessions/replay.ts +131 -0
  15. package/src/acp/sessions/store.ts +158 -0
  16. package/src/acp/sessions/title.ts +22 -0
  17. package/src/acp/utils/paths.ts +5 -0
  18. package/src/acp/utils/tool-kind.ts +38 -0
  19. package/src/acp/utils/tool-locations.ts +46 -0
  20. package/src/acp/utils/tool-result-content.ts +27 -0
  21. package/src/chat/app.tsx +428 -0
  22. package/src/chat/approvals.ts +96 -0
  23. package/src/chat/components/ApprovalPrompt.tsx +25 -0
  24. package/src/chat/components/ChatMessage.tsx +47 -0
  25. package/src/chat/components/Composer.tsx +39 -0
  26. package/src/chat/components/EmptyChatBanner.tsx +26 -0
  27. package/src/chat/components/ReasoningStrip.tsx +30 -0
  28. package/src/chat/components/Spinner.tsx +34 -0
  29. package/src/chat/components/StatusBar.tsx +65 -0
  30. package/src/chat/components/ThinkingStatus.tsx +128 -0
  31. package/src/chat/components/ToolEvent.tsx +34 -0
  32. package/src/chat/components/Transcript.tsx +34 -0
  33. package/src/chat/components/ascii-logo.ts +11 -0
  34. package/src/chat/components/shared.ts +70 -0
  35. package/src/chat/index.tsx +42 -0
  36. package/src/chat/types.ts +21 -0
  37. package/src/cli.ts +146 -0
  38. package/src/configure/app.tsx +911 -0
  39. package/src/configure/components/BusyScreen.tsx +22 -0
  40. package/src/configure/components/HomeScreen.tsx +43 -0
  41. package/src/configure/components/MenuScreen.tsx +44 -0
  42. package/src/configure/components/PromptForm.tsx +40 -0
  43. package/src/configure/components/SelectMenuItem.tsx +30 -0
  44. package/src/configure/index.tsx +43 -0
  45. package/src/configure/open-in-editor.ts +133 -0
  46. package/src/configure/types.ts +45 -0
  47. package/src/configure/utils.ts +113 -0
  48. package/src/core/agent/index.ts +76 -0
  49. package/src/core/config.ts +157 -0
  50. package/src/core/index.ts +54 -0
  51. package/src/core/mcp/config.ts +80 -0
  52. package/src/core/mcp/index.ts +13 -0
  53. package/src/core/mcp/manager.ts +109 -0
  54. package/src/core/mcp/prefixed-mcp-tool.ts +45 -0
  55. package/src/core/mcp/tools.ts +92 -0
  56. package/src/core/mcp/types.ts +37 -0
  57. package/src/core/memory/index.ts +17 -0
  58. package/src/core/memory/ltm/embed.ts +67 -0
  59. package/src/core/memory/ltm/index.ts +18 -0
  60. package/src/core/memory/ltm/store.ts +376 -0
  61. package/src/core/memory/ltm/tools.ts +146 -0
  62. package/src/core/memory/ltm/types.ts +111 -0
  63. package/src/core/memory/ltm/utils.ts +218 -0
  64. package/src/core/memory/stm/index.ts +17 -0
  65. package/src/core/models/anthropic.ts +53 -0
  66. package/src/core/models/bedrock.ts +54 -0
  67. package/src/core/models/google.ts +51 -0
  68. package/src/core/models/index.ts +16 -0
  69. package/src/core/models/ollama/index.ts +13 -0
  70. package/src/core/models/ollama/strands-ollama.ts +439 -0
  71. package/src/core/models/openai.ts +12 -0
  72. package/src/core/prompts/index.ts +23 -0
  73. package/src/core/prompts/skills.ts +66 -0
  74. package/src/core/prompts/static/fetch.md +33 -0
  75. package/src/core/prompts/static/filesystem.md +38 -0
  76. package/src/core/prompts/static/identity.md +22 -0
  77. package/src/core/prompts/static/ltm.md +39 -0
  78. package/src/core/prompts/static/memory.md +39 -0
  79. package/src/core/prompts/static/shell.md +34 -0
  80. package/src/core/prompts/static/skills.md +19 -0
  81. package/src/core/prompts/static/thinking.md +27 -0
  82. package/src/core/prompts/system.ts +109 -0
  83. package/src/core/skills/index.ts +2 -0
  84. package/src/core/skills/registry.ts +239 -0
  85. package/src/core/skills/tools.ts +80 -0
  86. package/src/core/toolkit.ts +13 -0
  87. package/src/core/tools/fetch.ts +288 -0
  88. package/src/core/tools/filesystem.ts +747 -0
  89. package/src/core/tools/index.ts +5 -0
  90. package/src/core/tools/shell.ts +426 -0
  91. package/src/core/tools/thinking.ts +184 -0
  92. package/src/core/tools/time.ts +121 -0
  93. package/src/core/utils/cwd-context.ts +11 -0
  94. package/src/core/utils/paths.ts +28 -0
  95. package/src/exec/approvals.ts +85 -0
  96. package/tsconfig.json +30 -0
@@ -0,0 +1,376 @@
1
+ import { ChromaClient } from "chromadb";
2
+ import type { QueryRowResult } from "chromadb";
3
+ import { HFEmbedding } from "./embed.ts";
4
+ import type {
5
+ ArchiveMemoryInput,
6
+ LongTermMemoryOptions,
7
+ LongTermMemoryScope,
8
+ Memory,
9
+ SearchMemoryInput,
10
+ SearchMemoryResult,
11
+ StoreMemoryInput,
12
+ StoreMemoryResult,
13
+ UpdateMemoryInput,
14
+ } from "./types.ts";
15
+ import type { Config } from "../../config.ts";
16
+ import {
17
+ DEFAULT_DEDUPE_THRESHOLD,
18
+ DEFAULT_HALF_LIFE_MS,
19
+ DEFAULT_REINFORCEMENT_STEP,
20
+ type ChromaMemoryMetadata,
21
+ buildWhere,
22
+ chromaClientArgsFromUrl,
23
+ clampSearchLimit,
24
+ clampUnitInterval,
25
+ getEffectiveStrength,
26
+ similarity,
27
+ toChromaMetadata,
28
+ toMemory,
29
+ } from "./utils.ts";
30
+
31
+ type Collection = Awaited<ReturnType<ChromaClient["getOrCreateCollection"]>>;
32
+
33
+ export class LongTermMemoryStore {
34
+ private readonly client: ChromaClient;
35
+ private collectionPromise: Promise<Collection> | null = null;
36
+
37
+ public constructor(
38
+ private readonly config: Config,
39
+ private readonly options: LongTermMemoryOptions = {},
40
+ ) {
41
+ this.client = new ChromaClient({
42
+ ...chromaClientArgsFromUrl(config.ltm.chroma.url),
43
+ });
44
+ }
45
+
46
+ private async collection(): Promise<Collection> {
47
+ if (!this.collectionPromise) {
48
+ this.collectionPromise = this.client.getOrCreateCollection({
49
+ name: this.config.ltm.chroma.collection.memory,
50
+ embeddingFunction: new HFEmbedding(),
51
+ });
52
+ }
53
+ return this.collectionPromise;
54
+ }
55
+
56
+ public async count(scope?: LongTermMemoryScope): Promise<number> {
57
+ const collection = await this.collection();
58
+ if (!scope) {
59
+ return collection.count();
60
+ }
61
+ const result = await collection.get({
62
+ where: buildWhere(scope, { includeArchived: true }),
63
+ include: [],
64
+ });
65
+ return result.ids.length;
66
+ }
67
+
68
+ public async get(id: string): Promise<Memory | null> {
69
+ const collection = await this.collection();
70
+ const result = await collection.get<ChromaMemoryMetadata>({
71
+ ids: [id],
72
+ include: ["documents", "metadatas"],
73
+ });
74
+ const content = result.documents[0];
75
+ const metadata = result.metadatas[0];
76
+ if (!content) {
77
+ return null;
78
+ }
79
+ return toMemory(id, content, metadata);
80
+ }
81
+
82
+ public async search(input: SearchMemoryInput): Promise<SearchMemoryResult[]> {
83
+ const collection = await this.collection();
84
+ const result = await collection.query<ChromaMemoryMetadata>({
85
+ queryTexts: [input.query],
86
+ nResults: clampSearchLimit(input.limit),
87
+ where: buildWhere(input.scope, {
88
+ includeArchived: input.includeArchived,
89
+ types: input.types,
90
+ }),
91
+ include: ["documents", "metadatas", "distances"],
92
+ });
93
+
94
+ const rows = (result.rows()[0] ??
95
+ []) as QueryRowResult<ChromaMemoryMetadata>[];
96
+ const memories = rows
97
+ .filter(
98
+ (
99
+ row: QueryRowResult<ChromaMemoryMetadata>,
100
+ ): row is QueryRowResult<ChromaMemoryMetadata> & {
101
+ document: string;
102
+ metadata: ChromaMemoryMetadata;
103
+ } => typeof row.document === "string" && !!row.metadata,
104
+ )
105
+ .map(
106
+ (
107
+ row: QueryRowResult<ChromaMemoryMetadata> & {
108
+ document: string;
109
+ metadata: ChromaMemoryMetadata;
110
+ },
111
+ ) => {
112
+ const memory = toMemory(row.id, row.document, row.metadata);
113
+ return {
114
+ ...memory,
115
+ distance: row.distance,
116
+ effectiveStrength: getEffectiveStrength(
117
+ memory.metadata,
118
+ this.options.halfLifeMs ?? DEFAULT_HALF_LIFE_MS,
119
+ ),
120
+ } satisfies SearchMemoryResult;
121
+ },
122
+ );
123
+
124
+ if (input.reinforce !== false && memories.length > 0) {
125
+ await Promise.all(
126
+ memories.map((memory: SearchMemoryResult) => this.reinforce(memory)),
127
+ );
128
+ }
129
+
130
+ return memories;
131
+ }
132
+
133
+ public async store(
134
+ input: StoreMemoryInput,
135
+ scope: LongTermMemoryScope,
136
+ ): Promise<StoreMemoryResult> {
137
+ const collection = await this.collection();
138
+ const content = input.content.trim();
139
+ if (!content) {
140
+ throw new Error("Long-term memory content cannot be empty");
141
+ }
142
+
143
+ if (input.dedupe !== false) {
144
+ const duplicate = await this.findDuplicate(content, scope);
145
+ if (duplicate) {
146
+ const merged = await this.mergeDuplicate(duplicate, input);
147
+ return {
148
+ id: merged.id,
149
+ merged: true,
150
+ memory: merged,
151
+ };
152
+ }
153
+ }
154
+
155
+ const now = Date.now();
156
+ const memory: Memory = {
157
+ id: crypto.randomUUID(),
158
+ userId: scope.userId,
159
+ type: input.type,
160
+ status: "active",
161
+ content,
162
+ metadata: {
163
+ createdAt: now,
164
+ updatedAt: now,
165
+ importance: clampUnitInterval(input.importance ?? 0.7, 0.7),
166
+ strength: 0.5,
167
+ accessCount: 0,
168
+ version: 1,
169
+ source: input.source ?? "assistant",
170
+ confidence:
171
+ input.confidence == null
172
+ ? undefined
173
+ : clampUnitInterval(input.confidence, 1),
174
+ tags: input.tags,
175
+ entities: input.entities,
176
+ relatedTo: input.relatedTo,
177
+ },
178
+ };
179
+
180
+ await collection.add({
181
+ ids: [memory.id],
182
+ documents: [memory.content],
183
+ metadatas: [toChromaMetadata(memory)],
184
+ });
185
+
186
+ return {
187
+ id: memory.id,
188
+ merged: false,
189
+ memory,
190
+ };
191
+ }
192
+
193
+ public async update(input: UpdateMemoryInput): Promise<Memory> {
194
+ const existing = await this.get(input.id);
195
+ if (!existing) {
196
+ throw new Error(`Memory not found: ${input.id}`);
197
+ }
198
+ const content = input.content.trim();
199
+ if (!content) {
200
+ throw new Error("Long-term memory content cannot be empty");
201
+ }
202
+
203
+ const next: Memory = {
204
+ ...existing,
205
+ type: input.type ?? existing.type,
206
+ status: input.status ?? existing.status,
207
+ content,
208
+ metadata: {
209
+ ...existing.metadata,
210
+ updatedAt: Date.now(),
211
+ version: existing.metadata.version + 1,
212
+ importance:
213
+ input.importance == null
214
+ ? existing.metadata.importance
215
+ : clampUnitInterval(input.importance, existing.metadata.importance),
216
+ confidence:
217
+ input.confidence == null
218
+ ? existing.metadata.confidence
219
+ : clampUnitInterval(
220
+ input.confidence,
221
+ existing.metadata.confidence ?? 1,
222
+ ),
223
+ tags: input.tags ?? existing.metadata.tags,
224
+ entities: input.entities ?? existing.metadata.entities,
225
+ relatedTo: input.relatedTo ?? existing.metadata.relatedTo,
226
+ supersededBy: input.supersededBy ?? existing.metadata.supersededBy,
227
+ },
228
+ };
229
+
230
+ const collection = await this.collection();
231
+ await collection.update({
232
+ ids: [next.id],
233
+ documents: [next.content],
234
+ metadatas: [toChromaMetadata(next)],
235
+ });
236
+
237
+ return next;
238
+ }
239
+
240
+ public async archive(input: ArchiveMemoryInput): Promise<Memory> {
241
+ const existing = await this.get(input.id);
242
+ if (!existing) {
243
+ throw new Error(`Memory not found: ${input.id}`);
244
+ }
245
+
246
+ const archived: Memory = {
247
+ ...existing,
248
+ status: input.status ?? "archived",
249
+ metadata: {
250
+ ...existing.metadata,
251
+ updatedAt: Date.now(),
252
+ version: existing.metadata.version + 1,
253
+ supersededBy: input.supersededBy ?? existing.metadata.supersededBy,
254
+ },
255
+ };
256
+
257
+ const collection = await this.collection();
258
+ await collection.update({
259
+ ids: [archived.id],
260
+ documents: [archived.content],
261
+ metadatas: [toChromaMetadata(archived)],
262
+ });
263
+
264
+ return archived;
265
+ }
266
+
267
+ private async reinforce(memory: Memory): Promise<void> {
268
+ const updated: Memory = {
269
+ ...memory,
270
+ metadata: {
271
+ ...memory.metadata,
272
+ strength:
273
+ memory.metadata.strength +
274
+ (this.options.reinforcementStep ?? DEFAULT_REINFORCEMENT_STEP),
275
+ lastAccessedAt: Date.now(),
276
+ accessCount: memory.metadata.accessCount + 1,
277
+ },
278
+ };
279
+
280
+ const collection = await this.collection();
281
+ await collection.update({
282
+ ids: [updated.id],
283
+ documents: [updated.content],
284
+ metadatas: [toChromaMetadata(updated)],
285
+ });
286
+ }
287
+
288
+ private async findDuplicate(
289
+ content: string,
290
+ scope: LongTermMemoryScope,
291
+ ): Promise<Memory | null> {
292
+ const collection = await this.collection();
293
+ const result = await collection.query<ChromaMemoryMetadata>({
294
+ queryTexts: [content],
295
+ nResults: 3,
296
+ where: buildWhere(scope, { status: "active" }),
297
+ include: ["documents", "metadatas"],
298
+ });
299
+
300
+ const rows = result.rows()[0] ?? [];
301
+ for (const row of rows) {
302
+ if (!row.document || !row.metadata) {
303
+ continue;
304
+ }
305
+ if (
306
+ similarity(row.document, content) >=
307
+ (this.options.dedupeThreshold ?? DEFAULT_DEDUPE_THRESHOLD)
308
+ ) {
309
+ return toMemory(row.id, row.document, row.metadata);
310
+ }
311
+ }
312
+ return null;
313
+ }
314
+
315
+ private async mergeDuplicate(
316
+ existing: Memory,
317
+ incoming: StoreMemoryInput,
318
+ ): Promise<Memory> {
319
+ const mergedTags = new Set([
320
+ ...(existing.metadata.tags ?? []),
321
+ ...(incoming.tags ?? []),
322
+ ]);
323
+ const mergedEntities = new Set([
324
+ ...(existing.metadata.entities ?? []),
325
+ ...(incoming.entities ?? []),
326
+ ]);
327
+ const mergedRelated = new Set([
328
+ ...(existing.metadata.relatedTo ?? []),
329
+ ...(incoming.relatedTo ?? []),
330
+ ]);
331
+
332
+ const updated: Memory = {
333
+ ...existing,
334
+ metadata: {
335
+ ...existing.metadata,
336
+ updatedAt: Date.now(),
337
+ lastAccessedAt: Date.now(),
338
+ accessCount: existing.metadata.accessCount + 1,
339
+ version: existing.metadata.version + 1,
340
+ strength:
341
+ existing.metadata.strength +
342
+ (this.options.reinforcementStep ?? DEFAULT_REINFORCEMENT_STEP),
343
+ importance: Math.max(
344
+ existing.metadata.importance,
345
+ clampUnitInterval(incoming.importance ?? 0.7, 0.7),
346
+ ),
347
+ confidence:
348
+ incoming.confidence == null
349
+ ? existing.metadata.confidence
350
+ : Math.max(
351
+ existing.metadata.confidence ?? 0,
352
+ clampUnitInterval(incoming.confidence, 1),
353
+ ),
354
+ tags: mergedTags.size > 0 ? [...mergedTags] : undefined,
355
+ entities: mergedEntities.size > 0 ? [...mergedEntities] : undefined,
356
+ relatedTo: mergedRelated.size > 0 ? [...mergedRelated] : undefined,
357
+ },
358
+ };
359
+
360
+ const collection = await this.collection();
361
+ await collection.update({
362
+ ids: [updated.id],
363
+ documents: [updated.content],
364
+ metadatas: [toChromaMetadata(updated)],
365
+ });
366
+
367
+ return updated;
368
+ }
369
+ }
370
+
371
+ export function create(
372
+ config: Config,
373
+ options?: LongTermMemoryOptions,
374
+ ): LongTermMemoryStore {
375
+ return new LongTermMemoryStore(config, options);
376
+ }
@@ -0,0 +1,146 @@
1
+ import { tool } from "@strands-agents/sdk";
2
+ import type { JSONValue, ToolContext } from "@strands-agents/sdk";
3
+ import { z } from "zod";
4
+ import type { LongTermMemoryStore } from "./store.ts";
5
+ import type { LongTermMemoryScope, MemoryType } from "./types.ts";
6
+
7
+ const StoreTypes: [MemoryType, ...MemoryType[]] = [
8
+ "fact",
9
+ "preference",
10
+ "task",
11
+ ];
12
+ const SearchTypes: [MemoryType, ...MemoryType[]] = [
13
+ "fact",
14
+ "preference",
15
+ "task",
16
+ "episodic",
17
+ "semantic",
18
+ ];
19
+
20
+ function toJsonValue(value: unknown): JSONValue {
21
+ return JSON.parse(JSON.stringify(value)) as JSONValue;
22
+ }
23
+
24
+ function resolveScope(context?: ToolContext): LongTermMemoryScope {
25
+ const userId = context?.agent.appState.get("userId");
26
+ if (typeof userId !== "string" || userId.trim().length === 0) {
27
+ throw new Error(
28
+ "Long-term memory tools require `userId` in agent appState.",
29
+ );
30
+ }
31
+
32
+ return { userId };
33
+ }
34
+
35
+ export function create(ltm: LongTermMemoryStore) {
36
+ return [
37
+ tool({
38
+ name: "store_memory",
39
+ description:
40
+ "Store important long-term memory. Only use for reusable facts, preferences, or tasks.",
41
+ inputSchema: z.object({
42
+ content: z.string().min(1).describe("Compressed memory content"),
43
+ type: z.enum(StoreTypes),
44
+ importance: z.number().min(0).max(1).optional(),
45
+ tags: z.array(z.string()).optional(),
46
+ entities: z.array(z.string()).optional(),
47
+ }),
48
+ callback: async (input, context?: ToolContext) => {
49
+ const scope = resolveScope(context);
50
+ const result = await ltm.store(
51
+ {
52
+ content: input.content,
53
+ type: input.type,
54
+ importance: input.importance,
55
+ tags: input.tags,
56
+ entities: input.entities,
57
+ dedupe: true,
58
+ },
59
+ scope,
60
+ );
61
+
62
+ return toJsonValue({
63
+ id: result.id,
64
+ merged: result.merged,
65
+ memory: result.memory,
66
+ });
67
+ },
68
+ }),
69
+ tool({
70
+ name: "search_memory",
71
+ description:
72
+ "Search relevant past memory for context. Use only if additional context is needed.",
73
+ inputSchema: z.object({
74
+ query: z.string().min(1).describe("What to search for"),
75
+ types: z.array(z.enum(SearchTypes)).optional(),
76
+ k: z
77
+ .number()
78
+ .int()
79
+ .min(1)
80
+ .max(20)
81
+ .optional()
82
+ .describe("Number of results (default 5, max 20)"),
83
+ }),
84
+ callback: async (input, context?: ToolContext) => {
85
+ const scope = resolveScope(context);
86
+ const memories = await ltm.search({
87
+ query: input.query,
88
+ scope,
89
+ types: input.types,
90
+ limit: input.k,
91
+ reinforce: true,
92
+ });
93
+
94
+ return toJsonValue({
95
+ count: memories.length,
96
+ memories,
97
+ });
98
+ },
99
+ }),
100
+ tool({
101
+ name: "update_memory",
102
+ description:
103
+ "Update or correct an existing memory. Prefer this over deleting.",
104
+ inputSchema: z.object({
105
+ id: z.string().min(1),
106
+ content: z.string().min(1),
107
+ tags: z.array(z.string()).optional(),
108
+ entities: z.array(z.string()).optional(),
109
+ }),
110
+ callback: async (input) => {
111
+ const memory = await ltm.update({
112
+ id: input.id,
113
+ content: input.content,
114
+ tags: input.tags,
115
+ entities: input.entities,
116
+ });
117
+
118
+ return toJsonValue({
119
+ id: memory.id,
120
+ memory,
121
+ });
122
+ },
123
+ }),
124
+ tool({
125
+ name: "archive_memory",
126
+ description: "Mark memory as no longer relevant without deleting it.",
127
+ inputSchema: z.object({
128
+ id: z.string().min(1),
129
+ reason: z.string().optional(),
130
+ }),
131
+ callback: async (input) => {
132
+ const memory = await ltm.archive({
133
+ id: input.id,
134
+ status: "archived",
135
+ });
136
+
137
+ return toJsonValue({
138
+ id: memory.id,
139
+ status: memory.status,
140
+ reason: input.reason ?? null,
141
+ memory,
142
+ });
143
+ },
144
+ }),
145
+ ];
146
+ }
@@ -0,0 +1,111 @@
1
+ export type MemoryStatus = "active" | "archived" | "superseded" | "deleted";
2
+
3
+ export type MemoryType =
4
+ | "fact"
5
+ | "preference"
6
+ | "task"
7
+ | "episodic"
8
+ | "semantic";
9
+
10
+ export interface Memory {
11
+ id: string;
12
+
13
+ // multi-tenant partitioning
14
+ userId: string;
15
+
16
+ type: MemoryType;
17
+ status: MemoryStatus;
18
+
19
+ content: string; // human-readable
20
+ embedding?: number[]; // optional (store-level)
21
+
22
+ metadata: {
23
+ // timestamps
24
+ createdAt: number;
25
+ updatedAt?: number;
26
+ lastAccessedAt?: number;
27
+
28
+ // scoring
29
+ importance: number; // write-time signal (0–1)
30
+ strength: number; // dynamic reinforcement (0–∞)
31
+ confidence?: number; // extraction confidence
32
+
33
+ // lifecycle
34
+ accessCount: number;
35
+ version: number;
36
+
37
+ // provenance
38
+ source: "user" | "assistant" | "system" | "inferred";
39
+
40
+ // structure
41
+ tags?: string[];
42
+ entities?: string[];
43
+
44
+ // relationships
45
+ supersededBy?: string; // memory id
46
+ relatedTo?: string[]; // graph-lite
47
+ };
48
+ }
49
+
50
+ export type MemorySource = Memory["metadata"]["source"];
51
+
52
+ export interface LongTermMemoryScope {
53
+ userId: string;
54
+ }
55
+
56
+ export interface LongTermMemoryOptions {
57
+ halfLifeMs?: number;
58
+ reinforcementStep?: number;
59
+ dedupeThreshold?: number;
60
+ }
61
+
62
+ export interface StoreMemoryInput {
63
+ content: string;
64
+ type: MemoryType;
65
+ importance?: number;
66
+ confidence?: number;
67
+ tags?: string[];
68
+ entities?: string[];
69
+ relatedTo?: string[];
70
+ source?: MemorySource;
71
+ dedupe?: boolean;
72
+ }
73
+
74
+ export interface SearchMemoryInput {
75
+ query: string;
76
+ scope: LongTermMemoryScope;
77
+ types?: MemoryType[];
78
+ limit?: number;
79
+ includeArchived?: boolean;
80
+ reinforce?: boolean;
81
+ }
82
+
83
+ export interface SearchMemoryResult extends Memory {
84
+ distance?: number | null;
85
+ effectiveStrength: number;
86
+ }
87
+
88
+ export interface UpdateMemoryInput {
89
+ id: string;
90
+ content: string;
91
+ type?: MemoryType;
92
+ status?: MemoryStatus;
93
+ importance?: number;
94
+ confidence?: number;
95
+ tags?: string[];
96
+ entities?: string[];
97
+ relatedTo?: string[];
98
+ supersededBy?: string;
99
+ }
100
+
101
+ export interface ArchiveMemoryInput {
102
+ id: string;
103
+ status?: Extract<MemoryStatus, "archived" | "superseded" | "deleted">;
104
+ supersededBy?: string;
105
+ }
106
+
107
+ export interface StoreMemoryResult {
108
+ id: string;
109
+ merged: boolean;
110
+ memory: Memory;
111
+ }