@1mbrain/sdk 0.1.1 → 0.1.3

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.
@@ -0,0 +1,429 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/hermes.ts
21
+ var hermes_exports = {};
22
+ __export(hermes_exports, {
23
+ HermesMemoryAdapter: () => HermesMemoryAdapter
24
+ });
25
+ module.exports = __toCommonJS(hermes_exports);
26
+
27
+ // src/index.ts
28
+ var OneMBrainError = class extends Error {
29
+ constructor(message, status, details) {
30
+ super(message);
31
+ this.status = status;
32
+ this.details = details;
33
+ this.name = "OneMBrainError";
34
+ }
35
+ status;
36
+ details;
37
+ };
38
+ var OneMBrainClient = class {
39
+ apiUrl;
40
+ apiKey;
41
+ agentId;
42
+ fetchFn;
43
+ constructor(config) {
44
+ if (!config.apiUrl) {
45
+ throw new Error("apiUrl is required");
46
+ }
47
+ if (!config.apiKey) {
48
+ throw new Error("apiKey is required");
49
+ }
50
+ this.apiUrl = config.apiUrl.replace(/\/+$/, "");
51
+ this.apiKey = config.apiKey;
52
+ this.agentId = config.agentId;
53
+ this.fetchFn = config.fetch ?? fetch;
54
+ }
55
+ async remember(input) {
56
+ const agentId = this.resolveAgentId(input.agentId);
57
+ const envelope = await this.request("/v1/memories", {
58
+ method: "POST",
59
+ agentId,
60
+ body: {
61
+ ...input,
62
+ agentId
63
+ }
64
+ });
65
+ return deserializeMemory(envelope.data);
66
+ }
67
+ async recall(input) {
68
+ const agentId = this.resolveAgentId(input.agentId);
69
+ const params = toSearchParams({
70
+ ...input,
71
+ agentId,
72
+ q: input.query,
73
+ query: void 0
74
+ });
75
+ const envelope = await this.request(
76
+ `/v1/memories/search?${params.toString()}`,
77
+ {
78
+ method: "GET",
79
+ agentId
80
+ }
81
+ );
82
+ const results = envelope.data.map((result) => ({
83
+ ...result,
84
+ memory: deserializeMemory(result.memory)
85
+ }));
86
+ if (envelope.meta) {
87
+ results.confidence = envelope.meta.confidence;
88
+ results.reason = envelope.meta.reason;
89
+ }
90
+ return results;
91
+ }
92
+ async forget(id, options = {}) {
93
+ const envelope = await this.request(`/v1/memories/${id}`, {
94
+ method: "DELETE",
95
+ agentId: this.resolveAgentId(options.agentId)
96
+ });
97
+ return envelope.success;
98
+ }
99
+ async associate(sourceId, input) {
100
+ const envelope = await this.request(
101
+ `/v1/memories/${sourceId}/associate`,
102
+ {
103
+ method: "POST",
104
+ agentId: this.resolveAgentId(input.agentId),
105
+ body: {
106
+ targetId: input.targetId,
107
+ strength: input.strength,
108
+ origin: input.origin,
109
+ relationType: input.relationType
110
+ }
111
+ }
112
+ );
113
+ return envelope.success;
114
+ }
115
+ /**
116
+ * Ingest a web page URL into memory.
117
+ *
118
+ * The server-side pipeline will:
119
+ * 1. Fetch the page HTML
120
+ * 2. Extract main content → Markdown
121
+ * 3. Chunk and extract factual claims via LLM
122
+ * 4. Store facts as memories (type, importance, metadata auto-set)
123
+ *
124
+ * Works from any gateway: Telegram, Discord, browser extension, CLI.
125
+ *
126
+ * @param url - The URL to ingest
127
+ * @param options - Optional overrides (agentId, confidenceThreshold, etc.)
128
+ */
129
+ async ingestUrl(url, options = {}) {
130
+ const agentId = this.resolveAgentId(options.agentId);
131
+ const envelope = await this.request("/v1/ingest/url", {
132
+ method: "POST",
133
+ agentId,
134
+ body: {
135
+ url,
136
+ agentId,
137
+ confidenceThreshold: options.confidenceThreshold,
138
+ maxChunkChars: options.maxChunkChars,
139
+ deduplicate: options.deduplicate
140
+ }
141
+ });
142
+ return envelope.data;
143
+ }
144
+ async consolidate(options = {}) {
145
+ const agentId = this.resolveAgentId(options.agentId);
146
+ const envelope = await this.request("/v1/consolidate", {
147
+ method: "POST",
148
+ agentId,
149
+ body: {
150
+ agentId,
151
+ dryRun: options.dryRun,
152
+ clusterStrategy: options.clusterStrategy
153
+ }
154
+ });
155
+ return envelope.data;
156
+ }
157
+ resolveAgentId(agentId) {
158
+ const resolved = agentId ?? this.agentId;
159
+ if (!resolved) {
160
+ throw new Error("agentId is required");
161
+ }
162
+ return resolved;
163
+ }
164
+ async request(path, options) {
165
+ const response = await this.fetchFn(`${this.apiUrl}${path}`, {
166
+ method: options.method,
167
+ headers: {
168
+ "content-type": "application/json",
169
+ "x-api-key": this.apiKey,
170
+ "x-agent-id": options.agentId
171
+ },
172
+ body: options.body === void 0 ? void 0 : JSON.stringify(options.body)
173
+ });
174
+ const payload = await readJson(response);
175
+ if (!response.ok) {
176
+ throw new OneMBrainError(
177
+ extractErrorMessage(payload, response.statusText),
178
+ response.status,
179
+ payload
180
+ );
181
+ }
182
+ return payload;
183
+ }
184
+ };
185
+ function deserializeMemory(memory) {
186
+ return {
187
+ ...memory,
188
+ createdAt: new Date(memory.createdAt),
189
+ lastAccessedAt: new Date(memory.lastAccessedAt)
190
+ };
191
+ }
192
+ function toSearchParams(input) {
193
+ const params = new URLSearchParams();
194
+ for (const [key, value] of Object.entries(input)) {
195
+ if (value === void 0 || value === null) {
196
+ continue;
197
+ }
198
+ if (Array.isArray(value)) {
199
+ params.set(key, value.join(","));
200
+ continue;
201
+ }
202
+ params.set(key, String(value));
203
+ }
204
+ return params;
205
+ }
206
+ async function readJson(response) {
207
+ const text = await response.text();
208
+ return text ? JSON.parse(text) : {};
209
+ }
210
+ function extractErrorMessage(payload, fallback) {
211
+ if (payload && typeof payload === "object" && "error" in payload) {
212
+ return String(payload.error);
213
+ }
214
+ if (payload && typeof payload === "object" && "message" in payload) {
215
+ return String(payload.message);
216
+ }
217
+ return fallback || "1MBrain request failed";
218
+ }
219
+
220
+ // src/hermes.ts
221
+ var HermesMemoryAdapter = class {
222
+ client;
223
+ defaultImportance;
224
+ agentId;
225
+ constructor(config) {
226
+ this.client = new OneMBrainClient({
227
+ apiUrl: config.apiUrl,
228
+ apiKey: config.apiKey,
229
+ agentId: config.agentId,
230
+ fetch: config.fetch
231
+ });
232
+ this.defaultImportance = config.defaultImportance ?? 0.6;
233
+ this.agentId = config.agentId;
234
+ }
235
+ // ------------------------------------------------------------------
236
+ // Specialised remember helpers
237
+ // ------------------------------------------------------------------
238
+ /**
239
+ * Store a conversation turn as an episodic memory.
240
+ * The content is formatted as a Q&A pair for rich recall later.
241
+ */
242
+ async rememberTurn(turn, agentId) {
243
+ const content = turn.assistantReply ? `User: ${turn.userMessage}
244
+ Hermes: ${turn.assistantReply}` : `User: ${turn.userMessage}`;
245
+ const tags = ["episodic", "conversation-turn", ...turn.topics ?? []];
246
+ if (turn.sessionId) tags.push(`session:${turn.sessionId}`);
247
+ return this.client.remember({
248
+ content,
249
+ type: "episodic",
250
+ importance: this.defaultImportance,
251
+ tags,
252
+ agentId
253
+ });
254
+ }
255
+ /**
256
+ * Store a durable user preference as a semantic memory.
257
+ * Semantic memories don't decay as fast and are weighted higher on recall.
258
+ */
259
+ async rememberPreference(key, value, agentId) {
260
+ return this.client.remember({
261
+ content: `User preference \u2014 ${key}: ${value}`,
262
+ type: "semantic",
263
+ importance: 0.85,
264
+ tags: ["semantic", "preference", `pref:${key}`],
265
+ agentId
266
+ });
267
+ }
268
+ /**
269
+ * Store a learned behavioural pattern or workflow as a procedural memory.
270
+ * Procedural memories carry high importance by default.
271
+ */
272
+ async rememberProcedure(name, pattern, agentId) {
273
+ return this.client.remember({
274
+ content: `Procedure \u2014 ${name}: ${pattern}`,
275
+ type: "procedural",
276
+ importance: 0.9,
277
+ tags: ["procedural", "workflow", `proc:${name}`],
278
+ agentId
279
+ });
280
+ }
281
+ /**
282
+ * General-purpose remember — uses sensible Hermes defaults.
283
+ * Delegates directly to the underlying SDK client.
284
+ */
285
+ async remember(content, options = {}) {
286
+ return this.client.remember({
287
+ content,
288
+ type: options.type ?? "episodic",
289
+ importance: options.importance ?? this.defaultImportance,
290
+ tags: ["source:hermes", ...options.tags ?? []],
291
+ agentId: options.agentId
292
+ });
293
+ }
294
+ // ------------------------------------------------------------------
295
+ // Recall
296
+ // ------------------------------------------------------------------
297
+ /**
298
+ * Recall memories relevant to the given query.
299
+ * Automatically uses spreading activation (2 hops) for richer results.
300
+ */
301
+ async recall(query, options = {}) {
302
+ return this.client.recall({
303
+ query,
304
+ limit: options.limit ?? 8,
305
+ type: options.type,
306
+ maxHops: options.maxHops ?? 2,
307
+ agentId: options.agentId
308
+ });
309
+ }
310
+ /**
311
+ * Recall only episodic memories (conversation history).
312
+ */
313
+ async recallHistory(query, limit = 5, agentId) {
314
+ return this.recall(query, { type: "episodic", limit, agentId });
315
+ }
316
+ /**
317
+ * Recall only semantic memories (facts & preferences).
318
+ */
319
+ async recallFacts(query, limit = 5, agentId) {
320
+ return this.recall(query, { type: "semantic", limit, agentId });
321
+ }
322
+ /**
323
+ * Recall only procedural memories (learned workflows).
324
+ */
325
+ async recallProcedures(query, limit = 5, agentId) {
326
+ return this.recall(query, { type: "procedural", limit, agentId });
327
+ }
328
+ // ------------------------------------------------------------------
329
+ // Forget
330
+ // ------------------------------------------------------------------
331
+ /** Hard-delete a memory by ID. */
332
+ async forget(memoryId, agentId) {
333
+ return this.client.forget(memoryId, { agentId });
334
+ }
335
+ // ------------------------------------------------------------------
336
+ // Associate
337
+ // ------------------------------------------------------------------
338
+ /** Create an explicit association between two memories. */
339
+ async associate(sourceId, targetId, strength = 0.5, agentId, relationType = "relates_to") {
340
+ return this.client.associate(sourceId, { targetId, strength, origin: "explicit", agentId, relationType });
341
+ }
342
+ // ------------------------------------------------------------------
343
+ // Context builder (for injecting memory into LLM prompts)
344
+ // ------------------------------------------------------------------
345
+ /**
346
+ * Build a formatted memory context block for injection into an LLM system prompt.
347
+ *
348
+ * Returns a markdown-formatted string listing the most relevant memories
349
+ * so Hermes can surface them to the model without manual formatting.
350
+ *
351
+ * @example
352
+ * const ctx = await memory.buildContext('user preferences');
353
+ * systemPrompt = `${baseSystemPrompt}\n\n${ctx}`;
354
+ */
355
+ async buildContext(query, limit = 6, agentId) {
356
+ const results = await this.recall(query, { limit, agentId });
357
+ if (results.length === 0) return "";
358
+ if (results.confidence === "low") {
359
+ return "I don't have information about that in my memory.";
360
+ }
361
+ const lines = ["## Relevant Memories", ""];
362
+ for (const { memory, score } of results) {
363
+ const typeLabel = memory.type.charAt(0).toUpperCase() + memory.type.slice(1);
364
+ lines.push(`- [${typeLabel}] (relevance: ${score.toFixed(2)}) ${memory.content}`);
365
+ }
366
+ return lines.join("\n");
367
+ }
368
+ // ------------------------------------------------------------------
369
+ // Web Page Ingestion (Phase 6)
370
+ // ------------------------------------------------------------------
371
+ /**
372
+ * Ingest a web page URL and store its factual content as memories.
373
+ *
374
+ * The server-side pipeline automatically:
375
+ * 1. Fetches the URL
376
+ * 2. Converts HTML → Markdown (noise stripped)
377
+ * 3. Chunks the content
378
+ * 4. Extracts factual claims via LLM (using your configured provider)
379
+ * 5. Stores facts with type/importance/metadata auto-set
380
+ * 6. Deduplicates (won't re-ingest the same page content twice)
381
+ *
382
+ * Works from any gateway: Telegram, Discord, browser extension, CLI.
383
+ *
384
+ * @example
385
+ * // Telegram bot handler
386
+ * if (message.startsWith('/learn ')) {
387
+ * const url = message.slice(7).trim();
388
+ * const result = await memory.learnFromUrl(url);
389
+ * return `✅ Learned ${result.storedCount} facts from "${result.title}"`;
390
+ * }
391
+ */
392
+ async learnFromUrl(url, options = {}) {
393
+ const agentId = options.agentId ?? this.agentId;
394
+ const result = await this.client.ingestUrl(url, {
395
+ agentId,
396
+ confidenceThreshold: options.confidenceThreshold,
397
+ maxChunkChars: options.maxChunkChars,
398
+ deduplicate: options.deduplicate
399
+ });
400
+ return {
401
+ ok: true,
402
+ title: result.title,
403
+ url: result.url,
404
+ storedCount: result.storedCount,
405
+ deduplicated: result.deduplicated,
406
+ memoryIds: result.memoryIds
407
+ };
408
+ }
409
+ /**
410
+ * Recall memories that were ingested from a specific source domain or URL pattern.
411
+ *
412
+ * Uses the `domain:` tag automatically added during ingestion.
413
+ *
414
+ * @example
415
+ * const newsFromKompas = await memory.recallFromSource('kompas.com', 'AI regulation');
416
+ */
417
+ async recallFromSource(domain, query, limit = 8, agentId) {
418
+ return this.recall(query, {
419
+ limit,
420
+ agentId,
421
+ tags: [`domain:${domain}`]
422
+ });
423
+ }
424
+ };
425
+ // Annotate the CommonJS export names for ESM import in node:
426
+ 0 && (module.exports = {
427
+ HermesMemoryAdapter
428
+ });
429
+ //# sourceMappingURL=hermes.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/hermes.ts","../src/index.ts"],"sourcesContent":["/**\n * @1mbrain/hermes-adapter\n *\n * NOTE: This is an optional convenience wrapper tailored specifically for the Hermes \n * agent framework. It serves as a reference/blueprint. For other frameworks or gateways, \n * use the generic `OneMBrainClient` directly from '@1mbrain/sdk'.\n *\n * Hermes context objects are automatically mapped to the correct 1MBrain memory type, \n * importance score, and metadata tags, so you never have to think about them in your \n * agent code.\n *\n * Quick start:\n *\n * ```ts\n * import { HermesMemoryAdapter } from '@1mbrain/sdk/hermes';\n *\n * const memory = new HermesMemoryAdapter({\n * apiUrl: process.env.ONEMILLION_API_URL!,\n * apiKey: process.env.ONEMILLION_API_KEY!,\n * agentId: 'hermes-agent-1', // your instance name/namespace\n * defaultImportance: 0.6,\n * });\n *\n * // Store an episodic memory from a conversation turn\n * await memory.rememberTurn({\n * userMessage: \"What is VibeAman pricing?\",\n * assistantReply: \"VibeAman starts at Rp 150k/month.\",\n * });\n *\n * // Store a persistent user preference\n * await memory.rememberPreference('preferred_language', 'Bahasa Indonesia');\n *\n * // Store a procedural pattern\n * await memory.rememberProcedure('push_to_github', 'Create PRD → push markdown deliverable');\n *\n * // Recall with automatic context enrichment\n * const results = await memory.recall('pricing');\n * ```\n */\n\nimport { OneMBrainClient } from './index.js';\nimport type { AssociateInput, Memory, SearchResult } from './index.js';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface HermesMemoryAdapterConfig {\n apiUrl: string;\n apiKey: string;\n agentId?: string;\n /** Default importance score for new memories (0–1). Defaults to 0.6. */\n defaultImportance?: number;\n /** Custom fetch implementation (useful in Cloudflare Workers / Edge). */\n fetch?: typeof fetch;\n}\n\nexport interface HermesTurn {\n /** The raw user message from the current conversation turn. */\n userMessage: string;\n /** The assistant reply that was generated for this turn. */\n assistantReply?: string;\n /** Optional topic tags to attach to this episodic memory. */\n topics?: string[];\n /** Optional conversation / session ID for grouping. */\n sessionId?: string;\n}\n\nexport interface HermesRecallOptions {\n /** Maximum number of results (default: 8). */\n limit?: number;\n /**\n * Restrict recall to a specific memory type.\n * When omitted, all types are searched.\n */\n type?: 'episodic' | 'semantic' | 'procedural' | 'entity' | 'warning';\n /** Filter by tags. */\n tags?: string[];\n /** Number of graph hops for spreading activation (default: 2). */\n maxHops?: number;\n /**\n * If provided, override the default agentId for this call.\n * Useful when querying another Hermes instance's memory.\n */\n agentId?: string;\n}\n\n// ---------------------------------------------------------------------------\n// Adapter\n// ---------------------------------------------------------------------------\n\nexport class HermesMemoryAdapter {\n private readonly client: OneMBrainClient;\n private readonly defaultImportance: number;\n private readonly agentId?: string;\n\n constructor(config: HermesMemoryAdapterConfig) {\n this.client = new OneMBrainClient({\n apiUrl: config.apiUrl,\n apiKey: config.apiKey,\n agentId: config.agentId,\n fetch: config.fetch,\n });\n this.defaultImportance = config.defaultImportance ?? 0.6;\n this.agentId = config.agentId;\n }\n\n // ------------------------------------------------------------------\n // Specialised remember helpers\n // ------------------------------------------------------------------\n\n /**\n * Store a conversation turn as an episodic memory.\n * The content is formatted as a Q&A pair for rich recall later.\n */\n async rememberTurn(turn: HermesTurn, agentId?: string): Promise<Memory> {\n const content = turn.assistantReply\n ? `User: ${turn.userMessage}\\nHermes: ${turn.assistantReply}`\n : `User: ${turn.userMessage}`;\n\n const tags = ['episodic', 'conversation-turn', ...(turn.topics ?? [])];\n if (turn.sessionId) tags.push(`session:${turn.sessionId}`);\n\n return this.client.remember({\n content,\n type: 'episodic',\n importance: this.defaultImportance,\n tags,\n agentId,\n });\n }\n\n /**\n * Store a durable user preference as a semantic memory.\n * Semantic memories don't decay as fast and are weighted higher on recall.\n */\n async rememberPreference(key: string, value: string, agentId?: string): Promise<Memory> {\n return this.client.remember({\n content: `User preference — ${key}: ${value}`,\n type: 'semantic',\n importance: 0.85,\n tags: ['semantic', 'preference', `pref:${key}`],\n agentId,\n });\n }\n\n /**\n * Store a learned behavioural pattern or workflow as a procedural memory.\n * Procedural memories carry high importance by default.\n */\n async rememberProcedure(name: string, pattern: string, agentId?: string): Promise<Memory> {\n return this.client.remember({\n content: `Procedure — ${name}: ${pattern}`,\n type: 'procedural',\n importance: 0.9,\n tags: ['procedural', 'workflow', `proc:${name}`],\n agentId,\n });\n }\n\n /**\n * General-purpose remember — uses sensible Hermes defaults.\n * Delegates directly to the underlying SDK client.\n */\n async remember(\n content: string,\n options: {\n type?: 'episodic' | 'semantic' | 'procedural';\n importance?: number;\n tags?: string[];\n agentId?: string;\n } = {},\n ): Promise<Memory> {\n return this.client.remember({\n content,\n type: options.type ?? 'episodic',\n importance: options.importance ?? this.defaultImportance,\n tags: ['source:hermes', ...(options.tags ?? [])],\n agentId: options.agentId,\n });\n }\n\n // ------------------------------------------------------------------\n // Recall\n // ------------------------------------------------------------------\n\n /**\n * Recall memories relevant to the given query.\n * Automatically uses spreading activation (2 hops) for richer results.\n */\n async recall(query: string, options: HermesRecallOptions = {}): Promise<SearchResult[]> {\n return this.client.recall({\n query,\n limit: options.limit ?? 8,\n type: options.type,\n maxHops: options.maxHops ?? 2,\n agentId: options.agentId,\n });\n }\n\n /**\n * Recall only episodic memories (conversation history).\n */\n async recallHistory(query: string, limit = 5, agentId?: string): Promise<SearchResult[]> {\n return this.recall(query, { type: 'episodic', limit, agentId });\n }\n\n /**\n * Recall only semantic memories (facts & preferences).\n */\n async recallFacts(query: string, limit = 5, agentId?: string): Promise<SearchResult[]> {\n return this.recall(query, { type: 'semantic', limit, agentId });\n }\n\n /**\n * Recall only procedural memories (learned workflows).\n */\n async recallProcedures(query: string, limit = 5, agentId?: string): Promise<SearchResult[]> {\n return this.recall(query, { type: 'procedural', limit, agentId });\n }\n\n // ------------------------------------------------------------------\n // Forget\n // ------------------------------------------------------------------\n\n /** Hard-delete a memory by ID. */\n async forget(memoryId: string, agentId?: string): Promise<boolean> {\n return this.client.forget(memoryId, { agentId });\n }\n\n // ------------------------------------------------------------------\n // Associate\n // ------------------------------------------------------------------\n\n /** Create an explicit association between two memories. */\n async associate(\n sourceId: string,\n targetId: string,\n strength = 0.5,\n agentId?: string,\n relationType: AssociateInput['relationType'] = 'relates_to',\n ): Promise<boolean> {\n return this.client.associate(sourceId, { targetId, strength, origin: 'explicit', agentId, relationType });\n }\n\n // ------------------------------------------------------------------\n // Context builder (for injecting memory into LLM prompts)\n // ------------------------------------------------------------------\n\n /**\n * Build a formatted memory context block for injection into an LLM system prompt.\n *\n * Returns a markdown-formatted string listing the most relevant memories\n * so Hermes can surface them to the model without manual formatting.\n *\n * @example\n * const ctx = await memory.buildContext('user preferences');\n * systemPrompt = `${baseSystemPrompt}\\n\\n${ctx}`;\n */\n async buildContext(query: string, limit = 6, agentId?: string): Promise<string> {\n const results = await this.recall(query, { limit, agentId });\n if (results.length === 0) return '';\n \n // R5.2 Explicit \"No Evidence\" Signal\n if ((results as any).confidence === 'low') {\n return \"I don't have information about that in my memory.\";\n }\n\n const lines: string[] = ['## Relevant Memories', ''];\n for (const { memory, score } of results) {\n const typeLabel = memory.type.charAt(0).toUpperCase() + memory.type.slice(1);\n lines.push(`- [${typeLabel}] (relevance: ${score.toFixed(2)}) ${memory.content}`);\n }\n\n return lines.join('\\n');\n }\n\n // ------------------------------------------------------------------\n // Web Page Ingestion (Phase 6)\n // ------------------------------------------------------------------\n\n\n /**\n * Ingest a web page URL and store its factual content as memories.\n *\n * The server-side pipeline automatically:\n * 1. Fetches the URL\n * 2. Converts HTML → Markdown (noise stripped)\n * 3. Chunks the content\n * 4. Extracts factual claims via LLM (using your configured provider)\n * 5. Stores facts with type/importance/metadata auto-set\n * 6. Deduplicates (won't re-ingest the same page content twice)\n *\n * Works from any gateway: Telegram, Discord, browser extension, CLI.\n *\n * @example\n * // Telegram bot handler\n * if (message.startsWith('/learn ')) {\n * const url = message.slice(7).trim();\n * const result = await memory.learnFromUrl(url);\n * return `✅ Learned ${result.storedCount} facts from \"${result.title}\"`;\n * }\n */\n async learnFromUrl(\n url: string,\n options: {\n agentId?: string;\n confidenceThreshold?: number;\n maxChunkChars?: number;\n deduplicate?: boolean;\n } = {},\n ): Promise<{\n ok: boolean;\n title: string;\n url: string;\n storedCount: number;\n deduplicated: boolean;\n memoryIds: string[];\n error?: string;\n }> {\n const agentId = options.agentId ?? this.agentId;\n const result = await this.client.ingestUrl(url, {\n agentId,\n confidenceThreshold: options.confidenceThreshold,\n maxChunkChars: options.maxChunkChars,\n deduplicate: options.deduplicate,\n });\n\n return {\n ok: true,\n title: result.title,\n url: result.url,\n storedCount: result.storedCount,\n deduplicated: result.deduplicated,\n memoryIds: result.memoryIds,\n };\n }\n\n /**\n * Recall memories that were ingested from a specific source domain or URL pattern.\n *\n * Uses the `domain:` tag automatically added during ingestion.\n *\n * @example\n * const newsFromKompas = await memory.recallFromSource('kompas.com', 'AI regulation');\n */\n async recallFromSource(\n domain: string,\n query: string,\n limit = 8,\n agentId?: string,\n ): Promise<SearchResult[]> {\n return this.recall(query, {\n limit,\n agentId,\n tags: [`domain:${domain}`],\n });\n }\n}\n","import type {\n CreateAssociationInput,\n CreateMemoryInput,\n Memory,\n SearchMemoryInput,\n SearchResult,\n} from '@1mbrain/core';\n\nexport interface OneMBrainClientConfig {\n apiUrl: string;\n apiKey: string;\n agentId?: string;\n fetch?: typeof fetch;\n}\n\nexport type RememberInput = Omit<CreateMemoryInput, 'agentId'> & {\n agentId?: string;\n};\n\nexport type RecallInput = Omit<SearchMemoryInput, 'agentId'> & {\n agentId?: string;\n};\n\nexport type AssociateInput = Omit<CreateAssociationInput, 'sourceId' | 'agentId'> & {\n agentId?: string;\n};\n\nexport interface IngestUrlOptions {\n agentId?: string;\n confidenceThreshold?: number;\n maxChunkChars?: number;\n deduplicate?: boolean;\n}\n\nexport interface IngestResult {\n title: string;\n url: string;\n sourceHash: string;\n chunkCount: number;\n extractedCount: number;\n storedCount: number;\n skippedCount: number;\n errorCount: number;\n deduplicated: boolean;\n memoryIds: string[];\n}\n\nexport interface ConsolidateOptions {\n agentId?: string;\n dryRun?: boolean;\n clusterStrategy?: 'tags' | 'graph' | 'hybrid';\n}\n\nexport interface ConsolidationResult {\n agentId: string;\n triggerReason: 'sleep-cycle' | 'threshold';\n dryRun: boolean;\n storedCount: number;\n archivedCount: number;\n clustersProcessed: number;\n skipped: {\n noCandidates: number;\n tooSmallClusters: number;\n summarizationFailed: number;\n dryRun: number;\n };\n errors: string[];\n summaryIds: string[];\n}\n\nexport interface ApiEnvelope<T> {\n success: boolean;\n data: T;\n meta?: Record<string, unknown>;\n message?: string;\n}\n\nexport class OneMBrainError extends Error {\n constructor(\n message: string,\n readonly status: number,\n readonly details?: unknown,\n ) {\n super(message);\n this.name = 'OneMBrainError';\n }\n}\n\nexport class OneMBrainClient {\n private readonly apiUrl: string;\n private readonly apiKey: string;\n private readonly agentId?: string;\n private readonly fetchFn: typeof fetch;\n\n constructor(config: OneMBrainClientConfig) {\n if (!config.apiUrl) {\n throw new Error('apiUrl is required');\n }\n\n if (!config.apiKey) {\n throw new Error('apiKey is required');\n }\n\n this.apiUrl = config.apiUrl.replace(/\\/+$/, '');\n this.apiKey = config.apiKey;\n this.agentId = config.agentId;\n this.fetchFn = config.fetch ?? fetch;\n }\n\n async remember(input: RememberInput): Promise<Memory> {\n const agentId = this.resolveAgentId(input.agentId);\n const envelope = await this.request<ApiEnvelope<SerializedMemory>>('/v1/memories', {\n method: 'POST',\n agentId,\n body: {\n ...input,\n agentId,\n },\n });\n\n return deserializeMemory(envelope.data);\n }\n\n async recall(input: RecallInput): Promise<SearchResult[]> {\n const agentId = this.resolveAgentId(input.agentId);\n const params = toSearchParams({\n ...input,\n agentId,\n q: input.query,\n query: undefined,\n });\n const envelope = await this.request<ApiEnvelope<SerializedSearchResult[]>>(\n `/v1/memories/search?${params.toString()}`,\n {\n method: 'GET',\n agentId,\n },\n );\n\n const results = envelope.data.map((result) => ({\n ...result,\n memory: deserializeMemory(result.memory),\n })) as SearchResult[] & { confidence?: string; reason?: string };\n\n if (envelope.meta) {\n results.confidence = envelope.meta.confidence as string | undefined;\n results.reason = envelope.meta.reason as string | undefined;\n }\n\n return results;\n }\n\n async forget(id: string, options: { agentId?: string } = {}): Promise<boolean> {\n const envelope = await this.request<ApiEnvelope<unknown>>(`/v1/memories/${id}`, {\n method: 'DELETE',\n agentId: this.resolveAgentId(options.agentId),\n });\n\n return envelope.success;\n }\n\n async associate(sourceId: string, input: AssociateInput): Promise<boolean> {\n const envelope = await this.request<ApiEnvelope<unknown>>(\n `/v1/memories/${sourceId}/associate`,\n {\n method: 'POST',\n agentId: this.resolveAgentId(input.agentId),\n body: {\n targetId: input.targetId,\n strength: input.strength,\n origin: input.origin,\n relationType: input.relationType,\n },\n },\n );\n\n return envelope.success;\n }\n\n /**\n * Ingest a web page URL into memory.\n *\n * The server-side pipeline will:\n * 1. Fetch the page HTML\n * 2. Extract main content → Markdown\n * 3. Chunk and extract factual claims via LLM\n * 4. Store facts as memories (type, importance, metadata auto-set)\n *\n * Works from any gateway: Telegram, Discord, browser extension, CLI.\n *\n * @param url - The URL to ingest\n * @param options - Optional overrides (agentId, confidenceThreshold, etc.)\n */\n async ingestUrl(url: string, options: IngestUrlOptions = {}): Promise<IngestResult> {\n const agentId = this.resolveAgentId(options.agentId);\n const envelope = await this.request<ApiEnvelope<IngestResult>>('/v1/ingest/url', {\n method: 'POST',\n agentId,\n body: {\n url,\n agentId,\n confidenceThreshold: options.confidenceThreshold,\n maxChunkChars: options.maxChunkChars,\n deduplicate: options.deduplicate,\n },\n });\n\n return envelope.data;\n }\n\n async consolidate(options: ConsolidateOptions = {}): Promise<ConsolidationResult> {\n const agentId = this.resolveAgentId(options.agentId);\n const envelope = await this.request<ApiEnvelope<ConsolidationResult>>('/v1/consolidate', {\n method: 'POST',\n agentId,\n body: {\n agentId,\n dryRun: options.dryRun,\n clusterStrategy: options.clusterStrategy,\n },\n });\n\n return envelope.data;\n }\n\n private resolveAgentId(agentId?: string): string {\n const resolved = agentId ?? this.agentId;\n\n if (!resolved) {\n throw new Error('agentId is required');\n }\n\n return resolved;\n }\n\n private async request<T>(\n path: string,\n options: {\n method: 'GET' | 'POST' | 'DELETE';\n agentId: string;\n body?: unknown;\n },\n ): Promise<T> {\n const response = await this.fetchFn(`${this.apiUrl}${path}`, {\n method: options.method,\n headers: {\n 'content-type': 'application/json',\n 'x-api-key': this.apiKey,\n 'x-agent-id': options.agentId,\n },\n body: options.body === undefined ? undefined : JSON.stringify(options.body),\n });\n\n const payload = await readJson(response);\n\n if (!response.ok) {\n throw new OneMBrainError(\n extractErrorMessage(payload, response.statusText),\n response.status,\n payload,\n );\n }\n\n return payload as T;\n }\n}\n\ntype SerializedMemory = Omit<Memory, 'createdAt' | 'lastAccessedAt'> & {\n createdAt: string;\n lastAccessedAt: string;\n};\n\ntype SerializedSearchResult = Omit<SearchResult, 'memory'> & {\n memory: SerializedMemory;\n};\n\nfunction deserializeMemory(memory: SerializedMemory): Memory {\n return {\n ...memory,\n createdAt: new Date(memory.createdAt),\n lastAccessedAt: new Date(memory.lastAccessedAt),\n };\n}\n\nfunction toSearchParams(input: Record<string, unknown>): URLSearchParams {\n const params = new URLSearchParams();\n\n for (const [key, value] of Object.entries(input)) {\n if (value === undefined || value === null) {\n continue;\n }\n\n if (Array.isArray(value)) {\n params.set(key, value.join(','));\n continue;\n }\n\n params.set(key, String(value));\n }\n\n return params;\n}\n\nasync function readJson(response: Response): Promise<unknown> {\n const text = await response.text();\n return text ? JSON.parse(text) : {};\n}\n\nfunction extractErrorMessage(payload: unknown, fallback: string): string {\n if (payload && typeof payload === 'object' && 'error' in payload) {\n return String((payload as { error: unknown }).error);\n }\n\n if (payload && typeof payload === 'object' && 'message' in payload) {\n return String((payload as { message: unknown }).message);\n }\n\n return fallback || '1MBrain request failed';\n}\n\nexport type { Memory, SearchResult };\nexport { AGENT_SYSTEM_PROMPT } from './prompts.js';\n"],"mappings":"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","names":[]}