@hilbras/remembra 0.1.0 → 0.3.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/CHANGELOG.md CHANGED
@@ -3,6 +3,37 @@
3
3
  All notable changes to Remembra will be documented in this file.
4
4
  Format follows [Keep a Changelog](https://keepachangelog.com/).
5
5
 
6
+ ## [0.3.0] — 2026-09-23
7
+
8
+ ### Added
9
+ - **Session digest**: `memory_digest` tool + `POST /memories/digest` — LLM extracts
10
+ facts/decisions/roles/history from a transcript and stores them.
11
+ - **Pluggable LLM provider**: `REMEMBRA_LLM=openai|anthropic|ollama` (+ `REMEMBRA_LLM_MODEL`).
12
+ - **Pluggable embeddings**: `REMEMBRA_EMBEDDINGS=openai|ollama|none` (default `none`).
13
+ - **Semantic search**: cosine similarity becomes the primary ranking signal when enabled;
14
+ vectors cached in memory frontmatter (computed once on write).
15
+ - Scope and role rules remain hard gates in both ranking modes.
16
+ - Keyword fallback: memories without vectors, and any embedding API failure, degrade
17
+ gracefully to keyword scoring (writes never blocked by embedding errors).
18
+ - Exact-match dedup in digest (type + scope + normalized content) — digests are idempotent.
19
+ - `docs/providers.md` — configuration guide for digest + embeddings.
20
+ - 18 new tests (digest, embeddings, retrieval modes, LLM output parsing).
21
+
22
+ ### Changed
23
+ - `MemoryService` now accepts optional injected deps (embed/extract) for testing.
24
+
25
+ ## [0.2.0] — 2026-09-23
26
+
27
+ ### Added
28
+ - HTTP API mode: `remembra --http [--port N]` — same handlers as the MCP tools.
29
+ - Routes: `GET /health`, `POST /memories`, `GET /memories/search`, `GET /memories`,
30
+ `DELETE /memories/:id`.
31
+ - API-key auth via `REMEMBRA_API_KEY` (`x-api-key` header or `Authorization: Bearer`).
32
+ - `REMEMBRA_PORT` env var as default port.
33
+ - Shared `MemoryService` core used by both MCP and HTTP transports.
34
+ - ChatGPT setup guide with full Custom GPT OpenAPI action schema (`docs/chatgpt.md`).
35
+ - HTTP and service test suites.
36
+
6
37
  ## [0.1.0] — 2026-09-23
7
38
 
8
39
  ### Added
package/README.md CHANGED
@@ -16,7 +16,7 @@ One memory server, many clients:
16
16
  | Claude Code | MCP (stdio) |
17
17
  | Cline | MCP (stdio) |
18
18
  | Kimi Code | MCP (stdio) |
19
- | ChatGPT | HTTP API + Custom GPT action *(v1.5)* |
19
+ | ChatGPT | HTTP API + Custom GPT action |
20
20
 
21
21
  ## The problem
22
22
 
@@ -73,11 +73,34 @@ claude mcp add remembra -- remembra
73
73
 
74
74
  More clients (Cline, Kimi Code) in **[docs/clients.md](docs/clients.md)**.
75
75
 
76
+ ### ChatGPT (HTTP mode)
77
+
78
+ ```bash
79
+ REMEMBRA_API_KEY="your-secret" remembra --http --port 8787
80
+ ```
81
+
82
+ Then wire a Custom GPT to the API — full walkthrough in **[docs/chatgpt.md](docs/chatgpt.md)**.
83
+
84
+ ### HTTP API
85
+
86
+ | Method | Route | Purpose |
87
+ |--------|-------|---------|
88
+ | GET | `/health` | Liveness (no auth) |
89
+ | POST | `/memories` | Store a memory |
90
+ | GET | `/memories/search?query=&scope=` | Search |
91
+ | GET | `/memories?scope=&type=` | List |
92
+ | POST | `/memories/digest` | LLM extract + store from a transcript |
93
+ | DELETE | `/memories/:id` | Forget |
94
+
95
+ All routes except `/health` require `x-api-key` (or `Authorization: Bearer`) when
96
+ `REMEMBRA_API_KEY` is set.
97
+
76
98
  ## Tools
77
99
 
78
100
  | Tool | Purpose |
79
101
  |------|---------|
80
102
  | `memory_store` | Save a fact / decision / role / history |
103
+ | `memory_digest` | Extract + store memories from a transcript (LLM) |
81
104
  | `memory_search` | Retrieve relevant memories (pass `scope` = current project) |
82
105
  | `memory_list` | Browse stored memories |
83
106
  | `memory_forget` | Delete by id |
@@ -91,6 +114,8 @@ Full reference: **[docs/tools.md](docs/tools.md)**
91
114
  | [Memory model](docs/memory-model.md) | Types, scopes, ranking, storage format |
92
115
  | [Tool reference](docs/tools.md) | Every MCP tool with arguments |
93
116
  | [Client setup](docs/clients.md) | Config for each supported tool |
117
+ | [ChatGPT setup](docs/chatgpt.md) | HTTP API + Custom GPT walkthrough |
118
+ | [AI providers](docs/providers.md) | Digest LLM + embeddings configuration |
94
119
  | [Contributing](CONTRIBUTING.md) | Dev workflow and guidelines |
95
120
  | [Changelog](CHANGELOG.md) | Release history |
96
121
 
@@ -119,9 +144,9 @@ npm test # run tests
119
144
 
120
145
  ## Roadmap
121
146
 
122
- - **v1** *(current)* — MCP server for coding tools, file storage, layered retrieval
123
- - **v1.5** — HTTP API + ChatGPT Custom GPT action
124
- - **v2** — automatic session-digest extraction, embeddings behind `memory_search`
147
+ - **v1** — MCP server for coding tools, file storage, layered retrieval
148
+ - **v1.5** — HTTP API + ChatGPT Custom GPT action
149
+ - **v2** *(current)* — automatic session-digest extraction, embeddings behind `memory_search`
125
150
  - **v3** — SQLite for scale, duplicate merging, memory decay
126
151
 
127
152
  ## License
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Pluggable embedding provider (v2).
3
+ *
4
+ * Config: REMEMBRA_EMBEDDINGS=openai|ollama|none (default: none → keyword-only, v1 behavior)
5
+ * Keys: OPENAI_API_KEY / OLLAMA_HOST (default localhost:11434)
6
+ *
7
+ * Vectors are computed once on write and cached in the memory file's frontmatter.
8
+ */
9
+ export type EmbeddingProvider = "openai" | "ollama" | "none";
10
+ export declare function resolveEmbeddingProvider(): EmbeddingProvider;
11
+ export declare function embedText(text: string, provider?: EmbeddingProvider): Promise<number[]>;
12
+ export declare function cosine(a: number[], b: number[]): number;
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Pluggable embedding provider (v2).
3
+ *
4
+ * Config: REMEMBRA_EMBEDDINGS=openai|ollama|none (default: none → keyword-only, v1 behavior)
5
+ * Keys: OPENAI_API_KEY / OLLAMA_HOST (default localhost:11434)
6
+ *
7
+ * Vectors are computed once on write and cached in the memory file's frontmatter.
8
+ */
9
+ export function resolveEmbeddingProvider() {
10
+ const v = (process.env.REMEMBRA_EMBEDDINGS ?? "none").toLowerCase();
11
+ if (v === "openai" || v === "ollama" || v === "none")
12
+ return v;
13
+ throw new Error(`Invalid REMEMBRA_EMBEDDINGS "${v}" — expected openai|ollama|none`);
14
+ }
15
+ export async function embedText(text, provider = resolveEmbeddingProvider()) {
16
+ if (provider === "none")
17
+ throw new Error("embeddings disabled (REMEMBRA_EMBEDDINGS=none)");
18
+ if (provider === "openai") {
19
+ const key = process.env.OPENAI_API_KEY;
20
+ if (!key)
21
+ throw new Error("REMEMBRA_EMBEDDINGS=openai requires OPENAI_API_KEY");
22
+ const res = await fetch("https://api.openai.com/v1/embeddings", {
23
+ method: "POST",
24
+ headers: { authorization: `Bearer ${key}`, "content-type": "application/json" },
25
+ body: JSON.stringify({
26
+ model: process.env.REMEMBRA_EMBEDDING_MODEL ?? "text-embedding-3-small",
27
+ input: text,
28
+ }),
29
+ });
30
+ if (!res.ok)
31
+ throw new Error(`OpenAI embeddings failed: ${res.status}`);
32
+ const data = (await res.json());
33
+ return data.data[0].embedding;
34
+ }
35
+ // ollama
36
+ const host = process.env.OLLAMA_HOST ?? "http://localhost:11434";
37
+ const res = await fetch(`${host}/api/embeddings`, {
38
+ method: "POST",
39
+ headers: { "content-type": "application/json" },
40
+ body: JSON.stringify({
41
+ model: process.env.REMEMBRA_EMBEDDING_MODEL ?? "nomic-embed-text",
42
+ prompt: text,
43
+ }),
44
+ });
45
+ if (!res.ok)
46
+ throw new Error(`Ollama embeddings failed: ${res.status}`);
47
+ const data = (await res.json());
48
+ return data.embedding;
49
+ }
50
+ export function cosine(a, b) {
51
+ if (a.length === 0 || a.length !== b.length)
52
+ return 0;
53
+ let dot = 0;
54
+ let na = 0;
55
+ let nb = 0;
56
+ for (let i = 0; i < a.length; i++) {
57
+ dot += a[i] * b[i];
58
+ na += a[i] * a[i];
59
+ nb += b[i] * b[i];
60
+ }
61
+ if (na === 0 || nb === 0)
62
+ return 0;
63
+ return dot / (Math.sqrt(na) * Math.sqrt(nb));
64
+ }
65
+ //# sourceMappingURL=embeddings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"embeddings.js","sourceRoot":"","sources":["../src/embeddings.ts"],"names":[],"mappings":"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"}
package/dist/http.d.ts ADDED
@@ -0,0 +1,19 @@
1
+ import http from "node:http";
2
+ import { MemoryService } from "./service.js";
3
+ interface HttpOptions {
4
+ port?: number;
5
+ /** If set, all endpoints except GET /health require `x-api-key` or `Authorization: Bearer`. */
6
+ apiKey?: string;
7
+ }
8
+ /**
9
+ * Minimal HTTP API over the same handlers the MCP tools use.
10
+ *
11
+ * Routes:
12
+ * GET /health → liveness (no auth)
13
+ * POST /memories → store a memory
14
+ * GET /memories/search → ?query=&scope=&type=&limit=
15
+ * GET /memories → ?scope=&type=
16
+ * DELETE /memories/:id → forget
17
+ */
18
+ export declare function createHttpServer(service: MemoryService, opts?: HttpOptions): http.Server;
19
+ export {};
package/dist/http.js ADDED
@@ -0,0 +1,114 @@
1
+ import http from "node:http";
2
+ /**
3
+ * Minimal HTTP API over the same handlers the MCP tools use.
4
+ *
5
+ * Routes:
6
+ * GET /health → liveness (no auth)
7
+ * POST /memories → store a memory
8
+ * GET /memories/search → ?query=&scope=&type=&limit=
9
+ * GET /memories → ?scope=&type=
10
+ * DELETE /memories/:id → forget
11
+ */
12
+ export function createHttpServer(service, opts = {}) {
13
+ const server = http.createServer(async (req, res) => {
14
+ try {
15
+ const url = new URL(req.url ?? "/", "http://localhost");
16
+ const path = url.pathname.replace(/\/+$/, "") || "/";
17
+ if (path === "/health") {
18
+ return send(res, 200, { status: "ok" });
19
+ }
20
+ if (opts.apiKey && !authorized(req, opts.apiKey)) {
21
+ return send(res, 401, { error: "Unauthorized: missing or invalid API key" });
22
+ }
23
+ // POST /memories/digest — must be checked before /memories/:id DELETE patterns
24
+ if (req.method === "POST" && path === "/memories/digest") {
25
+ const body = await readBody(req);
26
+ if (typeof body.transcript !== "string" || !body.transcript.trim()) {
27
+ return send(res, 400, { error: "Body must include a non-empty `transcript` string" });
28
+ }
29
+ const result = await service.digest({
30
+ transcript: body.transcript,
31
+ scope: body.scope,
32
+ source: body.source,
33
+ });
34
+ return send(res, 200, result);
35
+ }
36
+ // POST /memories
37
+ if (req.method === "POST" && path === "/memories") {
38
+ const body = await readBody(req);
39
+ const result = await service.store(body);
40
+ return send(res, 201, result);
41
+ }
42
+ // GET /memories/search
43
+ if (req.method === "GET" && path === "/memories/search") {
44
+ const result = await service.search({
45
+ query: url.searchParams.get("query") ?? url.searchParams.get("q") ?? undefined,
46
+ scope: url.searchParams.get("scope") ?? undefined,
47
+ type: url.searchParams.get("type") ?? undefined,
48
+ limit: url.searchParams.get("limit") ? Number(url.searchParams.get("limit")) : undefined,
49
+ });
50
+ return send(res, 200, result);
51
+ }
52
+ // GET /memories
53
+ if (req.method === "GET" && path === "/memories") {
54
+ const result = await service.list({
55
+ scope: url.searchParams.get("scope") ?? undefined,
56
+ type: url.searchParams.get("type") ?? undefined,
57
+ });
58
+ return send(res, 200, result);
59
+ }
60
+ // DELETE /memories/:id
61
+ const del = path.match(/^\/memories\/([^/]+)$/);
62
+ if (req.method === "DELETE" && del) {
63
+ const result = await service.forget(decodeURIComponent(del[1]));
64
+ return send(res, result.ok ? 200 : 404, result);
65
+ }
66
+ send(res, 404, { error: `No route: ${req.method} ${path}` });
67
+ }
68
+ catch (err) {
69
+ const name = err.name;
70
+ const isClientError = name === "ZodError" || name === "BadRequestError";
71
+ send(res, isClientError ? 400 : 500, {
72
+ error: err instanceof Error ? err.message : String(err),
73
+ });
74
+ }
75
+ });
76
+ const port = opts.port ?? Number(process.env.REMEMBRA_PORT ?? 8787);
77
+ server.listen(port, () => {
78
+ console.error(`Remembra HTTP API listening on :${port}${opts.apiKey ? " (auth required)" : " (no auth!)"}`);
79
+ });
80
+ return server;
81
+ }
82
+ function authorized(req, key) {
83
+ const header = req.headers["x-api-key"];
84
+ const auth = req.headers.authorization;
85
+ const provided = (typeof header === "string" ? header : undefined) ??
86
+ (auth?.startsWith("Bearer ") ? auth.slice(7) : undefined);
87
+ return provided === key;
88
+ }
89
+ function send(res, status, body) {
90
+ const data = JSON.stringify(body, null, 2);
91
+ res.writeHead(status, { "content-type": "application/json; charset=utf-8" });
92
+ res.end(data);
93
+ }
94
+ function readBody(req) {
95
+ return new Promise((resolve, reject) => {
96
+ let chunks = [];
97
+ req.on("data", (c) => chunks.push(c));
98
+ req.on("end", () => {
99
+ const raw = Buffer.concat(chunks).toString("utf8");
100
+ if (!raw)
101
+ return resolve({});
102
+ try {
103
+ resolve(JSON.parse(raw));
104
+ }
105
+ catch {
106
+ const e = new Error("Invalid JSON body");
107
+ e.name = "BadRequestError";
108
+ reject(e);
109
+ }
110
+ });
111
+ req.on("error", reject);
112
+ });
113
+ }
114
+ //# sourceMappingURL=http.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.js","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -3,80 +3,103 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
3
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
4
  import { z } from "zod";
5
5
  import { MemoryStore } from "./store.js";
6
- import { search } from "./retrieval.js";
7
- import { StoreInput } from "./types.js";
6
+ import { MemoryService } from "./service.js";
7
+ import { createHttpServer } from "./http.js";
8
8
  const store = new MemoryStore(MemoryStore.defaultRoot());
9
- const server = new McpServer({ name: "remembra", version: "0.1.0" });
10
- server.registerTool("memory_store", {
11
- title: "Store a memory",
12
- description: "Persist a fact, decision, role or history entry so it survives context window resets. " +
13
- "Use type 'fact' for stable knowledge, 'decision' for choices already made, " +
14
- "'role' for standing instructions/roles, 'history' for condensed chronology of past work.",
15
- inputSchema: {
16
- type: z.enum(["fact", "decision", "role", "history"]),
17
- content: z.string().describe("The memory itself, written as a standalone statement"),
18
- scope: z
19
- .string()
20
- .optional()
21
- .describe("'global' for always-relevant memories, or a project path/id for project-scoped ones"),
22
- tags: z.array(z.string()).optional(),
23
- importance: z.number().int().min(1).max(5).optional().describe("1=minor, 5=critical (default 3)"),
24
- source: z.string().optional().describe("Originating session or client"),
25
- },
26
- }, async ({ type, content, scope, tags, importance, source }) => {
27
- const memory = await store.store(StoreInput.parse({ type, content, scope, tags, importance, source }));
28
- return { content: [{ type: "text", text: `Stored ${memory.type} memory ${memory.id} (scope: ${memory.scope})` }] };
29
- });
30
- server.registerTool("memory_search", {
31
- title: "Search memories",
32
- description: "Retrieve relevant memories from external storage. Call this at the start of a session " +
33
- "(or whenever prior context might exist) to recover facts, decisions, roles and history.",
34
- inputSchema: {
35
- query: z.string().optional().describe("Keywords to match (omit to get a scope/recency-ranked list)"),
36
- scope: z.string().optional().describe("Current project path or workspace id to filter by"),
37
- type: z.enum(["fact", "decision", "role", "history"]).optional(),
38
- limit: z.number().int().min(1).max(50).optional(),
39
- },
40
- }, async ({ query, scope, type, limit }) => {
41
- const results = search(await store.all(), { query, scope, type, limit });
42
- const text = results.length === 0
43
- ? "No matching memories."
44
- : results
45
- .map((m) => `[${m.id}] ${m.type.toUpperCase()} (scope: ${m.scope}, importance: ${m.importance}, ${m.updatedAt.slice(0, 10)})\n${m.content}`)
46
- .join("\n\n");
47
- return { content: [{ type: "text", text }] };
48
- });
49
- server.registerTool("memory_list", {
50
- title: "List memories",
51
- description: "List stored memories, optionally filtered by scope or type.",
52
- inputSchema: {
53
- scope: z.string().optional(),
54
- type: z.enum(["fact", "decision", "role", "history"]).optional(),
55
- },
56
- }, async ({ scope, type }) => {
57
- let memories = await store.all();
58
- if (scope)
59
- memories = memories.filter((m) => m.scope === scope || m.scope === "global");
60
- if (type)
61
- memories = memories.filter((m) => m.type === type);
62
- memories.sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
63
- const text = memories.length === 0
64
- ? "No memories stored yet."
65
- : memories.map((m) => `[${m.id}] ${m.type} (${m.scope}): ${m.content.split("\n")[0]}`).join("\n");
66
- return { content: [{ type: "text", text }] };
67
- });
68
- server.registerTool("memory_forget", {
69
- title: "Delete a memory",
70
- description: "Permanently delete a memory by its id.",
71
- inputSchema: { id: z.string() },
72
- }, async ({ id }) => {
73
- const ok = await store.forget(id);
74
- return {
75
- content: [{ type: "text", text: ok ? `Deleted memory ${id}.` : `No memory with id ${id}.` }],
76
- isError: !ok,
77
- };
78
- });
79
- const transport = new StdioServerTransport();
80
- await server.connect(transport);
81
- console.error(`Remembra memory server running (root: ${MemoryStore.defaultRoot()})`);
9
+ const service = new MemoryService(store);
10
+ const httpFlag = process.argv.includes("--http");
11
+ const portArg = process.argv.indexOf("--port");
12
+ const port = portArg !== -1 ? Number(process.argv[portArg + 1]) : undefined;
13
+ if (httpFlag) {
14
+ // HTTP mode: long-running API for non-MCP clients (ChatGPT, scripts, ...).
15
+ createHttpServer(service, {
16
+ port,
17
+ apiKey: process.env.REMEMBRA_API_KEY,
18
+ });
19
+ }
20
+ else {
21
+ // MCP mode (default): stdio transport launched by an MCP client.
22
+ await startMcp();
23
+ }
24
+ async function startMcp() {
25
+ const server = new McpServer({ name: "remembra", version: "0.3.0" });
26
+ server.registerTool("memory_store", {
27
+ title: "Store a memory",
28
+ description: "Persist a fact, decision, role or history entry so it survives context window resets. " +
29
+ "Use type 'fact' for stable knowledge, 'decision' for choices already made, " +
30
+ "'role' for standing instructions/roles, 'history' for condensed chronology of past work.",
31
+ inputSchema: {
32
+ type: z.enum(["fact", "decision", "role", "history"]),
33
+ content: z.string().describe("The memory itself, written as a standalone statement"),
34
+ scope: z
35
+ .string()
36
+ .optional()
37
+ .describe("'global' for always-relevant memories, or a project path/id for project-scoped ones"),
38
+ tags: z.array(z.string()).optional(),
39
+ importance: z.number().int().min(1).max(5).optional().describe("1=minor, 5=critical (default 3)"),
40
+ source: z.string().optional().describe("Originating session or client"),
41
+ },
42
+ }, async (args) => {
43
+ const result = await service.store(args);
44
+ return { content: [{ type: "text", text: result.message }] };
45
+ });
46
+ server.registerTool("memory_digest", {
47
+ title: "Digest a session",
48
+ description: "Extract facts, decisions, roles and history from a conversation transcript and store " +
49
+ "them automatically (exact duplicates are skipped). Call at the end of a session with " +
50
+ "the transcript or a detailed summary of it. Requires REMEMBRA_LLM + an API key.",
51
+ inputSchema: {
52
+ transcript: z
53
+ .string()
54
+ .describe("Conversation transcript or a detailed summary of the session"),
55
+ scope: z.string().optional().describe("Scope for extracted memories (default: global)"),
56
+ source: z.string().optional().describe("Originating session/client"),
57
+ },
58
+ }, async ({ transcript, scope, source }) => {
59
+ const result = await service.digest({ transcript, scope, source });
60
+ const text = `Digest complete: ${result.extracted} extracted, ${result.stored.length} stored, ` +
61
+ `${result.skippedDuplicates} duplicates skipped.` +
62
+ (result.ids.length ? `\nStored ids: ${result.ids.join(", ")}` : "");
63
+ return { content: [{ type: "text", text }] };
64
+ });
65
+ server.registerTool("memory_search", {
66
+ title: "Search memories",
67
+ description: "Retrieve relevant memories from external storage. Call this at the start of a session " +
68
+ "(or whenever prior context might exist) to recover facts, decisions, roles and history.",
69
+ inputSchema: {
70
+ query: z.string().optional().describe("Keywords to match (omit to get a scope/recency-ranked list)"),
71
+ scope: z.string().optional().describe("Current project path or workspace id to filter by"),
72
+ type: z.enum(["fact", "decision", "role", "history"]).optional(),
73
+ limit: z.number().int().min(1).max(50).optional(),
74
+ },
75
+ }, async (args) => {
76
+ const result = await service.search(args);
77
+ return { content: [{ type: "text", text: result.text }] };
78
+ });
79
+ server.registerTool("memory_list", {
80
+ title: "List memories",
81
+ description: "List stored memories, optionally filtered by scope or type.",
82
+ inputSchema: {
83
+ scope: z.string().optional(),
84
+ type: z.enum(["fact", "decision", "role", "history"]).optional(),
85
+ },
86
+ }, async (args) => {
87
+ const result = await service.list(args);
88
+ return { content: [{ type: "text", text: result.text }] };
89
+ });
90
+ server.registerTool("memory_forget", {
91
+ title: "Delete a memory",
92
+ description: "Permanently delete a memory by its id.",
93
+ inputSchema: { id: z.string() },
94
+ }, async ({ id }) => {
95
+ const result = await service.forget(id);
96
+ return {
97
+ content: [{ type: "text", text: result.text }],
98
+ isError: !result.ok,
99
+ };
100
+ });
101
+ const transport = new StdioServerTransport();
102
+ await server.connect(transport);
103
+ console.error(`Remembra MCP server running (root: ${MemoryStore.defaultRoot()})`);
104
+ }
82
105
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/llm.d.ts ADDED
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Pluggable LLM provider for session-digest extraction (v2).
3
+ *
4
+ * Config: REMEMBRA_LLM=openai|anthropic|ollama (default: openai)
5
+ * Keys: OPENAI_API_KEY / ANTHROPIC_API_KEY / OLLAMA_HOST (default localhost:11434)
6
+ *
7
+ * No SDK dependencies — plain fetch against each provider's HTTP API.
8
+ */
9
+ export type LlmProvider = "openai" | "anthropic" | "ollama";
10
+ export interface ExtractedMemory {
11
+ type: "fact" | "decision" | "role" | "history";
12
+ content: string;
13
+ tags: string[];
14
+ importance: number;
15
+ /** Optional scope override; falls back to the digest call's scope. */
16
+ scope?: string;
17
+ }
18
+ export declare function resolveLlmProvider(): LlmProvider;
19
+ export declare function extractMemories(transcript: string, provider?: LlmProvider): Promise<ExtractedMemory[]>;
20
+ /** Parse the model's reply into extracted memories, tolerating code fences. */
21
+ export declare function parseExtraction(raw: string): ExtractedMemory[];