@theokit/memory-supermemory 0.1.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 ADDED
@@ -0,0 +1,32 @@
1
+ # Changelog
2
+
3
+ ## 2.0.0
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies
8
+ - @theokit/sdk@1.3.0
9
+
10
+ ## 1.0.0
11
+
12
+ ### Patch Changes
13
+
14
+ - Updated dependencies
15
+ - @theokit/sdk@1.2.0
16
+
17
+ ## 0.1.0
18
+
19
+ ### Added
20
+
21
+ - Initial release. Implements the `MemoryAdapter` contract (ADR D141) over
22
+ the `supermemory@^4.21.0` SDK. Exposes:
23
+ - `supermemoryMemory(options)` plugin factory.
24
+ - `MemoryAdapter.write` → `documents.add` with translated containerTags.
25
+ - `MemoryAdapter.recall` → `search.memories` with rerank=true.
26
+ - `MemoryAdapter.delete` → `documents.delete` with EC-B prefix validation.
27
+ - LLM-callable tool schemas (`memory_write`, `memory_recall`).
28
+ - EC-C identifier sanitizer (`^[a-zA-Z0-9_-]+$`) for every containerTag
29
+ component — prevents silent cross-bucket leak from `:`/whitespace in
30
+ userId/agentId/tenantId/tags.
31
+ - Typed error translation: 401/403 → `auth_failed`, 429 → `rate_limited`,
32
+ 404 → `not_found`, network → `network`.
package/README.md ADDED
@@ -0,0 +1,82 @@
1
+ # @theokit/memory-supermemory
2
+
3
+ Supermemory memory adapter for [`@theokit/sdk`](../sdk).
4
+
5
+ Wraps [`supermemory@^4`](https://www.npmjs.com/package/supermemory) (zero-dep,
6
+ MIT-licensed, native fetch) with the `MemoryAdapter` contract from ADR D141.
7
+
8
+ ## Install
9
+
10
+ ```bash
11
+ pnpm add @theokit/memory-supermemory supermemory
12
+ ```
13
+
14
+ ## Usage
15
+
16
+ ```ts
17
+ import { Agent } from "@theokit/sdk";
18
+ import { supermemoryMemory } from "@theokit/memory-supermemory";
19
+
20
+ const agent = await Agent.create({
21
+ apiKey: process.env.OPENROUTER_API_KEY,
22
+ model: { id: "openai/gpt-4o-mini" },
23
+ local: {},
24
+ plugins: [supermemoryMemory({ apiKey: process.env.SUPERMEMORY_API_KEY! })],
25
+ memoryContext: { userId: "demo" },
26
+ });
27
+
28
+ // Direct API
29
+ await agent.memory.write("User likes Brazilian jazz", { userId: "demo" });
30
+ const facts = await agent.memory.recall("music preferences", { userId: "demo" });
31
+
32
+ // LLM-driven via tool schemas (registered automatically when toolSchemas: true)
33
+ await agent.send("What music does the user enjoy?");
34
+ ```
35
+
36
+ ## Options
37
+
38
+ | Field | Type | Default | Description |
39
+ |---|---|---|---|
40
+ | `apiKey` | `string` | — | Supermemory API key. Required. |
41
+ | `baseUrl` | `string` | Supermemory cloud | Override for self-hosted deployments. |
42
+ | `containerTagPrefix` | `string` | `"theokit"` | Prefix for every container tag. Useful for test isolation. |
43
+
44
+ ## Container tag scheme
45
+
46
+ Every memory write is tagged with:
47
+
48
+ - `${prefix}:user:${userId}` (always)
49
+ - `${prefix}:agent:${agentId}` (when set)
50
+ - `${prefix}:tenant:${tenantId}` (when set)
51
+ - `${prefix}:tag:${tag}` (one per entry in `ctx.tags`)
52
+
53
+ Each component is sanitized against `^[a-zA-Z0-9_-]+$` (EC-C) — values
54
+ containing `:` or whitespace throw `MemoryAdapterError(code: "invalid_input")`
55
+ at the boundary, before any HTTP call.
56
+
57
+ ## Multi-tenant accumulation (EC-S)
58
+
59
+ Calling `agent.memory.write` writes durable data to Supermemory tied to
60
+ the supplied `userId`. In bot/CI scenarios where the same `userId` is
61
+ reused across runs, set a unique `containerTagPrefix` per test:
62
+
63
+ ```ts
64
+ supermemoryMemory({
65
+ apiKey,
66
+ containerTagPrefix: `theokit-test-${Date.now()}`,
67
+ })
68
+ ```
69
+
70
+ ## Failure modes
71
+
72
+ | HTTP status | Maps to | `isRetryable` |
73
+ |---|---|---|
74
+ | 401 / 403 | `MemoryAdapterError(code: "auth_failed")` | false |
75
+ | 429 | `MemoryAdapterError(code: "rate_limited")` | true |
76
+ | 404 | `MemoryAdapterError(code: "not_found")` | false |
77
+ | Network/timeout | `MemoryAdapterError(code: "network")` | true |
78
+ | Other | `MemoryAdapterError(code: "unknown")` | false |
79
+
80
+ ## License
81
+
82
+ Apache-2.0. See [LICENSE](./LICENSE).
package/dist/index.cjs ADDED
@@ -0,0 +1,251 @@
1
+ 'use strict';
2
+
3
+ var sdk = require('@theokit/sdk');
4
+ var SupermemoryClient = require('supermemory');
5
+
6
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
7
+
8
+ var SupermemoryClient__default = /*#__PURE__*/_interopDefault(SupermemoryClient);
9
+
10
+ // src/index.ts
11
+ var SAFE_IDENT = /^[a-zA-Z0-9_-]+$/;
12
+ var ADAPTER_ID = "supermemory";
13
+ function sanitizeIdentifier(value, fieldName) {
14
+ if (typeof value !== "string" || value.length === 0) {
15
+ throw new sdk.MemoryAdapterError(`Supermemory adapter: ${fieldName} must be a non-empty string`, {
16
+ adapterId: ADAPTER_ID,
17
+ code: "invalid_input"
18
+ });
19
+ }
20
+ if (!SAFE_IDENT.test(value)) {
21
+ throw new sdk.MemoryAdapterError(
22
+ `Supermemory adapter: ${fieldName} "${value}" contains invalid characters (allowed: a-zA-Z0-9_-)`,
23
+ { adapterId: ADAPTER_ID, code: "invalid_input" }
24
+ );
25
+ }
26
+ return value;
27
+ }
28
+ function buildContainerTags(ctx, prefix) {
29
+ const safePrefix = sanitizeIdentifier(prefix, "prefix");
30
+ const tags = [`${safePrefix}:user:${sanitizeIdentifier(ctx.userId, "userId")}`];
31
+ if (ctx.agentId !== void 0) {
32
+ tags.push(`${safePrefix}:agent:${sanitizeIdentifier(ctx.agentId, "agentId")}`);
33
+ }
34
+ if (ctx.tenantId !== void 0) {
35
+ tags.push(`${safePrefix}:tenant:${sanitizeIdentifier(ctx.tenantId, "tenantId")}`);
36
+ }
37
+ if (ctx.tags !== void 0) {
38
+ for (const t of ctx.tags) {
39
+ tags.push(`${safePrefix}:tag:${sanitizeIdentifier(t, "tag")}`);
40
+ }
41
+ }
42
+ return tags;
43
+ }
44
+ function primaryContainerTag(ctx, prefix) {
45
+ const safePrefix = sanitizeIdentifier(prefix, "prefix");
46
+ return `${safePrefix}:user:${sanitizeIdentifier(ctx.userId, "userId")}`;
47
+ }
48
+
49
+ // src/adapter.ts
50
+ var ADAPTER_ID2 = "supermemory";
51
+ var CAPS = {
52
+ history: false,
53
+ sessions: false,
54
+ tenancy: true,
55
+ reasoning: false,
56
+ toolSchemas: true,
57
+ prefetch: false
58
+ };
59
+ var SupermemoryAdapter = class {
60
+ id = ADAPTER_ID2;
61
+ capabilities = CAPS;
62
+ #opts;
63
+ #client;
64
+ constructor(opts) {
65
+ this.#opts = opts;
66
+ }
67
+ isAvailable() {
68
+ return typeof this.#opts.apiKey === "string" && this.#opts.apiKey.length > 0;
69
+ }
70
+ async initialize() {
71
+ }
72
+ async write(content, ctx) {
73
+ const text = this.#renderContent(content);
74
+ if (text.length === 0) {
75
+ throw new sdk.MemoryAdapterError("write: empty content", {
76
+ adapterId: ADAPTER_ID2,
77
+ code: "invalid_input"
78
+ });
79
+ }
80
+ const containerTags = buildContainerTags(ctx, this.#prefix());
81
+ try {
82
+ const resp = await this.#sdk().documents.add({
83
+ content: text,
84
+ containerTags,
85
+ ...ctx.metadata !== void 0 ? { metadata: ctx.metadata } : {}
86
+ });
87
+ return sdk.mkMemoryId(ADAPTER_ID2, resp.id);
88
+ } catch (err) {
89
+ throw this.#translateError(err, "write");
90
+ }
91
+ }
92
+ async recall(query, ctx, k = 10) {
93
+ if (k <= 0) return [];
94
+ const containerTag = primaryContainerTag(ctx, this.#prefix());
95
+ try {
96
+ const resp = await this.#sdk().search.memories({
97
+ q: query,
98
+ containerTag,
99
+ limit: k,
100
+ rerank: true
101
+ });
102
+ const results = resp.results ?? [];
103
+ return results.map(this.#mapResult);
104
+ } catch (err) {
105
+ throw this.#translateError(err, "recall");
106
+ }
107
+ }
108
+ async delete(id) {
109
+ const rawId = sdk.extractRawId(id, ADAPTER_ID2);
110
+ try {
111
+ await this.#sdk().documents.delete(rawId);
112
+ } catch (err) {
113
+ throw this.#translateError(err, "delete");
114
+ }
115
+ }
116
+ getToolSchemas() {
117
+ return [
118
+ {
119
+ name: "memory_write",
120
+ description: "Persist a fact about the user or context to Supermemory long-term memory. Returns the stored memory ID.",
121
+ parameters: {
122
+ type: "object",
123
+ properties: {
124
+ content: { type: "string", description: "Fact text to persist verbatim." }
125
+ },
126
+ required: ["content"]
127
+ }
128
+ },
129
+ {
130
+ name: "memory_recall",
131
+ description: "Retrieve up to k semantically relevant facts from Supermemory long-term memory. Returns an array of {id, content, score, createdAt} objects.",
132
+ parameters: {
133
+ type: "object",
134
+ properties: {
135
+ query: { type: "string", description: "Free-text query to search memory." },
136
+ k: {
137
+ type: "integer",
138
+ minimum: 1,
139
+ maximum: 50,
140
+ description: "Max results (default 10)."
141
+ }
142
+ },
143
+ required: ["query"]
144
+ }
145
+ }
146
+ ];
147
+ }
148
+ async handleToolCall(name, args, ctx) {
149
+ if (name === "memory_write") {
150
+ const content = String(args.content ?? "");
151
+ const id = await this.write(content, ctx);
152
+ return JSON.stringify({ ok: true, id });
153
+ }
154
+ if (name === "memory_recall") {
155
+ const query = String(args.query ?? "");
156
+ const k = typeof args.k === "number" ? args.k : 10;
157
+ const facts = await this.recall(query, ctx, k);
158
+ return JSON.stringify({ ok: true, facts });
159
+ }
160
+ throw new sdk.MemoryAdapterError(`Unknown tool name: ${name}`, {
161
+ adapterId: ADAPTER_ID2,
162
+ code: "invalid_input"
163
+ });
164
+ }
165
+ async shutdown() {
166
+ this.#client = void 0;
167
+ }
168
+ // ── helpers ────────────────────────────────────────────────────────
169
+ #prefix() {
170
+ return this.#opts.containerTagPrefix ?? "theokit";
171
+ }
172
+ #renderContent(content) {
173
+ if (typeof content === "string") return content.trim();
174
+ return content.map((m) => `${m.role}: ${m.content}`).join("\n").trim();
175
+ }
176
+ #mapResult = (r) => {
177
+ const obj = r ?? {};
178
+ const memory = obj.memory ?? obj;
179
+ const rawId = String(memory.id ?? obj.id ?? "");
180
+ const content = String(memory.content ?? memory.text ?? obj.content ?? "");
181
+ const score = typeof obj.score === "number" ? obj.score : void 0;
182
+ const createdAt = typeof memory.createdAt === "string" ? memory.createdAt : void 0;
183
+ return {
184
+ id: sdk.mkMemoryId(ADAPTER_ID2, rawId),
185
+ content,
186
+ ...score !== void 0 ? { score } : {},
187
+ ...createdAt !== void 0 ? { createdAt } : {}
188
+ };
189
+ };
190
+ #sdk() {
191
+ if (this.#client === void 0) {
192
+ this.#client = new SupermemoryClient__default.default({
193
+ apiKey: this.#opts.apiKey,
194
+ ...this.#opts.baseUrl !== void 0 ? { baseURL: this.#opts.baseUrl } : {}
195
+ });
196
+ }
197
+ return this.#client;
198
+ }
199
+ #translateError(err, op) {
200
+ if (err instanceof sdk.MemoryAdapterError) return err;
201
+ const status = err?.status ?? err?.statusCode;
202
+ const message = err?.message ?? String(err);
203
+ if (status === 401 || status === 403) {
204
+ return new sdk.MemoryAdapterError(`Supermemory auth failed (${op}): ${message}`, {
205
+ adapterId: ADAPTER_ID2,
206
+ code: "auth_failed",
207
+ cause: err
208
+ });
209
+ }
210
+ if (status === 429) {
211
+ return new sdk.MemoryAdapterError(`Supermemory rate limited (${op}): ${message}`, {
212
+ adapterId: ADAPTER_ID2,
213
+ code: "rate_limited",
214
+ cause: err
215
+ });
216
+ }
217
+ if (status === 404) {
218
+ return new sdk.MemoryAdapterError(`Supermemory not found (${op}): ${message}`, {
219
+ adapterId: ADAPTER_ID2,
220
+ code: "not_found",
221
+ cause: err
222
+ });
223
+ }
224
+ if (status === void 0 && message.toLowerCase().includes("network")) {
225
+ return new sdk.MemoryAdapterError(`Supermemory network error (${op}): ${message}`, {
226
+ adapterId: ADAPTER_ID2,
227
+ code: "network",
228
+ cause: err
229
+ });
230
+ }
231
+ return new sdk.MemoryAdapterError(`Supermemory error (${op}): ${message}`, {
232
+ adapterId: ADAPTER_ID2,
233
+ code: "unknown",
234
+ cause: err
235
+ });
236
+ }
237
+ };
238
+
239
+ // src/index.ts
240
+ function supermemoryMemory(options) {
241
+ return sdk.definePlugin({
242
+ name: "@theokit/memory-supermemory",
243
+ version: "0.1.0",
244
+ kind: "memory",
245
+ createProvider: () => new SupermemoryAdapter(options)
246
+ });
247
+ }
248
+
249
+ exports.supermemoryMemory = supermemoryMemory;
250
+ //# sourceMappingURL=index.cjs.map
251
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/translate.ts","../src/adapter.ts","../src/index.ts"],"names":["MemoryAdapterError","ADAPTER_ID","mkMemoryId","extractRawId","SupermemoryClient","definePlugin"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * `MemoryContext` → Supermemory containerTags translation (T3.2).\n *\n * EC-C fix: every component runs through a strict identifier sanitizer\n * (regex `^[a-zA-Z0-9_-]+$`) before being joined with `:`. Rejects with\n * `MemoryAdapterError(code: \"invalid_input\")` on invalid input, so a\n * value like `userId: \"user:123\"` cannot silently land in a different\n * bucket via tag mis-parsing.\n *\n * @internal\n */\n\nimport type { MemoryContext } from \"@theokit/sdk\";\nimport { MemoryAdapterError } from \"@theokit/sdk\";\n\nconst SAFE_IDENT = /^[a-zA-Z0-9_-]+$/;\nconst ADAPTER_ID = \"supermemory\";\n\nexport function sanitizeIdentifier(value: string, fieldName: string): string {\n if (typeof value !== \"string\" || value.length === 0) {\n throw new MemoryAdapterError(`Supermemory adapter: ${fieldName} must be a non-empty string`, {\n adapterId: ADAPTER_ID,\n code: \"invalid_input\",\n });\n }\n if (!SAFE_IDENT.test(value)) {\n throw new MemoryAdapterError(\n `Supermemory adapter: ${fieldName} \"${value}\" contains invalid characters (allowed: a-zA-Z0-9_-)`,\n { adapterId: ADAPTER_ID, code: \"invalid_input\" },\n );\n }\n return value;\n}\n\n/**\n * Build the array of containerTags for `documents.add`. Each component\n * is sanitized; collisions across tag namespaces (user/agent/tenant/tag)\n * are intentional — Supermemory treats containerTags as a set.\n *\n * @internal\n */\nexport function buildContainerTags(ctx: MemoryContext, prefix: string): string[] {\n const safePrefix = sanitizeIdentifier(prefix, \"prefix\");\n const tags: string[] = [`${safePrefix}:user:${sanitizeIdentifier(ctx.userId, \"userId\")}`];\n if (ctx.agentId !== undefined) {\n tags.push(`${safePrefix}:agent:${sanitizeIdentifier(ctx.agentId, \"agentId\")}`);\n }\n if (ctx.tenantId !== undefined) {\n tags.push(`${safePrefix}:tenant:${sanitizeIdentifier(ctx.tenantId, \"tenantId\")}`);\n }\n if (ctx.tags !== undefined) {\n for (const t of ctx.tags) {\n tags.push(`${safePrefix}:tag:${sanitizeIdentifier(t, \"tag\")}`);\n }\n }\n return tags;\n}\n\n/**\n * Pick the primary containerTag for `search.memories` (which takes a\n * single string, not an array). The user tag is canonical.\n *\n * @internal\n */\nexport function primaryContainerTag(ctx: MemoryContext, prefix: string): string {\n const safePrefix = sanitizeIdentifier(prefix, \"prefix\");\n return `${safePrefix}:user:${sanitizeIdentifier(ctx.userId, \"userId\")}`;\n}\n","/**\n * SupermemoryAdapter — `@theokit-memory-supermemory` core (T3.2, ADR D141).\n *\n * Wraps `supermemory` SDK v4. Implements `MemoryAdapter` so the SDK's\n * `pre_user_send` / `post_assistant_reply` hooks (D145) and\n * `agent.memory.*` direct API (D142) work end-to-end against Supermemory's\n * managed memory + RAG service.\n *\n * @public\n */\n\nimport {\n extractRawId,\n type MemoryAdapter,\n type MemoryAdapterCapabilities,\n MemoryAdapterError,\n type MemoryContext,\n type MemoryFact,\n type MemoryId,\n type MemoryToolSchema,\n type MemoryTurnMessage,\n mkMemoryId,\n} from \"@theokit/sdk\";\nimport type Supermemory from \"supermemory\";\nimport SupermemoryClient from \"supermemory\";\n\nimport { buildContainerTags, primaryContainerTag } from \"./translate.js\";\n\n/** Configuration accepted by the `supermemoryMemory(...)` factory. @public */\nexport interface SupermemoryAdapterOptions {\n /** Supermemory API key. Falls back to `SUPERMEMORY_API_KEY`. */\n apiKey: string;\n /** Base URL override for self-hosted Supermemory deployments. */\n baseUrl?: string;\n /** Prefix for every containerTag (default `\"theokit\"`). Useful for test isolation (EC-S). */\n containerTagPrefix?: string;\n}\n\nconst ADAPTER_ID = \"supermemory\";\n\nconst CAPS: MemoryAdapterCapabilities = {\n history: false,\n sessions: false,\n tenancy: true,\n reasoning: false,\n toolSchemas: true,\n prefetch: false,\n};\n\n/**\n * SDK-internal adapter class. Construct via `supermemoryMemory(...)`\n * factory from `./index.ts`, not directly.\n *\n * @internal\n */\nexport class SupermemoryAdapter implements MemoryAdapter {\n readonly id = ADAPTER_ID;\n readonly capabilities = CAPS;\n readonly #opts: SupermemoryAdapterOptions;\n #client?: Supermemory;\n\n constructor(opts: SupermemoryAdapterOptions) {\n this.#opts = opts;\n }\n\n isAvailable(): boolean {\n return typeof this.#opts.apiKey === \"string\" && this.#opts.apiKey.length > 0;\n }\n\n async initialize(): Promise<void> {\n // Lazy: defer the actual client construction until first call.\n // initialize() is idempotent — see EC-3 / EC-I.\n }\n\n async write(content: string | MemoryTurnMessage[], ctx: MemoryContext): Promise<MemoryId> {\n const text = this.#renderContent(content);\n if (text.length === 0) {\n throw new MemoryAdapterError(\"write: empty content\", {\n adapterId: ADAPTER_ID,\n code: \"invalid_input\",\n });\n }\n const containerTags = buildContainerTags(ctx, this.#prefix());\n try {\n const resp = await this.#sdk().documents.add({\n content: text,\n containerTags,\n ...(ctx.metadata !== undefined ? { metadata: ctx.metadata as Record<string, string> } : {}),\n });\n return mkMemoryId(ADAPTER_ID, resp.id);\n } catch (err) {\n throw this.#translateError(err, \"write\");\n }\n }\n\n async recall(query: string, ctx: MemoryContext, k = 10): Promise<MemoryFact[]> {\n if (k <= 0) return [];\n const containerTag = primaryContainerTag(ctx, this.#prefix());\n try {\n const resp = await this.#sdk().search.memories({\n q: query,\n containerTag,\n limit: k,\n rerank: true,\n });\n const results = resp.results ?? [];\n return results.map(this.#mapResult);\n } catch (err) {\n throw this.#translateError(err, \"recall\");\n }\n }\n\n async delete(id: MemoryId): Promise<void> {\n const rawId = extractRawId(id, ADAPTER_ID);\n try {\n await this.#sdk().documents.delete(rawId);\n } catch (err) {\n throw this.#translateError(err, \"delete\");\n }\n }\n\n getToolSchemas(): MemoryToolSchema[] {\n return [\n {\n name: \"memory_write\",\n description:\n \"Persist a fact about the user or context to Supermemory long-term memory. \" +\n \"Returns the stored memory ID.\",\n parameters: {\n type: \"object\",\n properties: {\n content: { type: \"string\", description: \"Fact text to persist verbatim.\" },\n },\n required: [\"content\"],\n },\n },\n {\n name: \"memory_recall\",\n description:\n \"Retrieve up to k semantically relevant facts from Supermemory long-term memory. \" +\n \"Returns an array of {id, content, score, createdAt} objects.\",\n parameters: {\n type: \"object\",\n properties: {\n query: { type: \"string\", description: \"Free-text query to search memory.\" },\n k: {\n type: \"integer\",\n minimum: 1,\n maximum: 50,\n description: \"Max results (default 10).\",\n },\n },\n required: [\"query\"],\n },\n },\n ];\n }\n\n async handleToolCall(\n name: string,\n args: Record<string, unknown>,\n ctx: MemoryContext,\n ): Promise<string> {\n if (name === \"memory_write\") {\n const content = String(args.content ?? \"\");\n const id = await this.write(content, ctx);\n return JSON.stringify({ ok: true, id });\n }\n if (name === \"memory_recall\") {\n const query = String(args.query ?? \"\");\n const k = typeof args.k === \"number\" ? args.k : 10;\n const facts = await this.recall(query, ctx, k);\n return JSON.stringify({ ok: true, facts });\n }\n throw new MemoryAdapterError(`Unknown tool name: ${name}`, {\n adapterId: ADAPTER_ID,\n code: \"invalid_input\",\n });\n }\n\n async shutdown(): Promise<void> {\n this.#client = undefined;\n }\n\n // ── helpers ────────────────────────────────────────────────────────\n\n #prefix(): string {\n return this.#opts.containerTagPrefix ?? \"theokit\";\n }\n\n #renderContent(content: string | MemoryTurnMessage[]): string {\n if (typeof content === \"string\") return content.trim();\n return content\n .map((m) => `${m.role}: ${m.content}`)\n .join(\"\\n\")\n .trim();\n }\n\n #mapResult = (r: unknown): MemoryFact => {\n const obj = (r as Record<string, unknown>) ?? {};\n // SDK shape: { memory?: { id, content, ... }, score, ... } or chunk shape.\n const memory = (obj.memory as Record<string, unknown> | undefined) ?? obj;\n const rawId = String(memory.id ?? obj.id ?? \"\");\n const content = String(memory.content ?? memory.text ?? obj.content ?? \"\");\n const score = typeof obj.score === \"number\" ? obj.score : undefined;\n const createdAt = typeof memory.createdAt === \"string\" ? memory.createdAt : undefined;\n return {\n id: mkMemoryId(ADAPTER_ID, rawId),\n content,\n ...(score !== undefined ? { score } : {}),\n ...(createdAt !== undefined ? { createdAt } : {}),\n };\n };\n\n #sdk(): Supermemory {\n if (this.#client === undefined) {\n this.#client = new SupermemoryClient({\n apiKey: this.#opts.apiKey,\n ...(this.#opts.baseUrl !== undefined ? { baseURL: this.#opts.baseUrl } : {}),\n });\n }\n return this.#client;\n }\n\n #translateError(err: unknown, op: string): MemoryAdapterError {\n if (err instanceof MemoryAdapterError) return err;\n const status =\n (err as { status?: number; statusCode?: number })?.status ??\n (err as { statusCode?: number })?.statusCode;\n const message = (err as Error)?.message ?? String(err);\n if (status === 401 || status === 403) {\n return new MemoryAdapterError(`Supermemory auth failed (${op}): ${message}`, {\n adapterId: ADAPTER_ID,\n code: \"auth_failed\",\n cause: err,\n });\n }\n if (status === 429) {\n return new MemoryAdapterError(`Supermemory rate limited (${op}): ${message}`, {\n adapterId: ADAPTER_ID,\n code: \"rate_limited\",\n cause: err,\n });\n }\n if (status === 404) {\n return new MemoryAdapterError(`Supermemory not found (${op}): ${message}`, {\n adapterId: ADAPTER_ID,\n code: \"not_found\",\n cause: err,\n });\n }\n if (status === undefined && message.toLowerCase().includes(\"network\")) {\n return new MemoryAdapterError(`Supermemory network error (${op}): ${message}`, {\n adapterId: ADAPTER_ID,\n code: \"network\",\n cause: err,\n });\n }\n return new MemoryAdapterError(`Supermemory error (${op}): ${message}`, {\n adapterId: ADAPTER_ID,\n code: \"unknown\",\n cause: err,\n });\n }\n}\n","/**\n * `@theokit/memory-supermemory` — Supermemory memory adapter for @theokit/sdk.\n *\n * Usage:\n *\n * ```ts\n * import { Agent } from \"@theokit/sdk\";\n * import { supermemoryMemory } from \"@theokit/memory-supermemory\";\n *\n * const agent = await Agent.create({\n * apiKey: process.env.OPENROUTER_API_KEY,\n * model: { id: \"openai/gpt-4o-mini\" },\n * local: {},\n * plugins: [supermemoryMemory({ apiKey: process.env.SUPERMEMORY_API_KEY! })],\n * memoryContext: { userId: \"demo\" },\n * });\n *\n * await agent.memory.write(\"User likes Brazilian jazz\", { userId: \"demo\" });\n * const facts = await agent.memory.recall(\"music preferences\", { userId: \"demo\" });\n * ```\n *\n * @public\n */\n\nimport type { Plugin } from \"@theokit/sdk\";\nimport { definePlugin } from \"@theokit/sdk\";\n\nimport { SupermemoryAdapter, type SupermemoryAdapterOptions } from \"./adapter.js\";\n\nexport type { SupermemoryAdapterOptions } from \"./adapter.js\";\n\n/**\n * Build a `Plugin { kind: \"memory\" }` ready to pass to\n * `Agent.create({ plugins: [...] })`.\n *\n * @public\n */\nexport function supermemoryMemory(options: SupermemoryAdapterOptions): Plugin {\n return definePlugin({\n name: \"@theokit/memory-supermemory\",\n version: \"0.1.0\",\n kind: \"memory\",\n createProvider: () => new SupermemoryAdapter(options),\n });\n}\n"]}
@@ -0,0 +1,55 @@
1
+ import { Plugin } from '@theokit/sdk';
2
+
3
+ /**
4
+ * SupermemoryAdapter — `@theokit-memory-supermemory` core (T3.2, ADR D141).
5
+ *
6
+ * Wraps `supermemory` SDK v4. Implements `MemoryAdapter` so the SDK's
7
+ * `pre_user_send` / `post_assistant_reply` hooks (D145) and
8
+ * `agent.memory.*` direct API (D142) work end-to-end against Supermemory's
9
+ * managed memory + RAG service.
10
+ *
11
+ * @public
12
+ */
13
+ /** Configuration accepted by the `supermemoryMemory(...)` factory. @public */
14
+ interface SupermemoryAdapterOptions {
15
+ /** Supermemory API key. Falls back to `SUPERMEMORY_API_KEY`. */
16
+ apiKey: string;
17
+ /** Base URL override for self-hosted Supermemory deployments. */
18
+ baseUrl?: string;
19
+ /** Prefix for every containerTag (default `"theokit"`). Useful for test isolation (EC-S). */
20
+ containerTagPrefix?: string;
21
+ }
22
+
23
+ /**
24
+ * `@theokit/memory-supermemory` — Supermemory memory adapter for @theokit/sdk.
25
+ *
26
+ * Usage:
27
+ *
28
+ * ```ts
29
+ * import { Agent } from "@theokit/sdk";
30
+ * import { supermemoryMemory } from "@theokit/memory-supermemory";
31
+ *
32
+ * const agent = await Agent.create({
33
+ * apiKey: process.env.OPENROUTER_API_KEY,
34
+ * model: { id: "openai/gpt-4o-mini" },
35
+ * local: {},
36
+ * plugins: [supermemoryMemory({ apiKey: process.env.SUPERMEMORY_API_KEY! })],
37
+ * memoryContext: { userId: "demo" },
38
+ * });
39
+ *
40
+ * await agent.memory.write("User likes Brazilian jazz", { userId: "demo" });
41
+ * const facts = await agent.memory.recall("music preferences", { userId: "demo" });
42
+ * ```
43
+ *
44
+ * @public
45
+ */
46
+
47
+ /**
48
+ * Build a `Plugin { kind: "memory" }` ready to pass to
49
+ * `Agent.create({ plugins: [...] })`.
50
+ *
51
+ * @public
52
+ */
53
+ declare function supermemoryMemory(options: SupermemoryAdapterOptions): Plugin;
54
+
55
+ export { type SupermemoryAdapterOptions, supermemoryMemory };
@@ -0,0 +1,55 @@
1
+ import { Plugin } from '@theokit/sdk';
2
+
3
+ /**
4
+ * SupermemoryAdapter — `@theokit-memory-supermemory` core (T3.2, ADR D141).
5
+ *
6
+ * Wraps `supermemory` SDK v4. Implements `MemoryAdapter` so the SDK's
7
+ * `pre_user_send` / `post_assistant_reply` hooks (D145) and
8
+ * `agent.memory.*` direct API (D142) work end-to-end against Supermemory's
9
+ * managed memory + RAG service.
10
+ *
11
+ * @public
12
+ */
13
+ /** Configuration accepted by the `supermemoryMemory(...)` factory. @public */
14
+ interface SupermemoryAdapterOptions {
15
+ /** Supermemory API key. Falls back to `SUPERMEMORY_API_KEY`. */
16
+ apiKey: string;
17
+ /** Base URL override for self-hosted Supermemory deployments. */
18
+ baseUrl?: string;
19
+ /** Prefix for every containerTag (default `"theokit"`). Useful for test isolation (EC-S). */
20
+ containerTagPrefix?: string;
21
+ }
22
+
23
+ /**
24
+ * `@theokit/memory-supermemory` — Supermemory memory adapter for @theokit/sdk.
25
+ *
26
+ * Usage:
27
+ *
28
+ * ```ts
29
+ * import { Agent } from "@theokit/sdk";
30
+ * import { supermemoryMemory } from "@theokit/memory-supermemory";
31
+ *
32
+ * const agent = await Agent.create({
33
+ * apiKey: process.env.OPENROUTER_API_KEY,
34
+ * model: { id: "openai/gpt-4o-mini" },
35
+ * local: {},
36
+ * plugins: [supermemoryMemory({ apiKey: process.env.SUPERMEMORY_API_KEY! })],
37
+ * memoryContext: { userId: "demo" },
38
+ * });
39
+ *
40
+ * await agent.memory.write("User likes Brazilian jazz", { userId: "demo" });
41
+ * const facts = await agent.memory.recall("music preferences", { userId: "demo" });
42
+ * ```
43
+ *
44
+ * @public
45
+ */
46
+
47
+ /**
48
+ * Build a `Plugin { kind: "memory" }` ready to pass to
49
+ * `Agent.create({ plugins: [...] })`.
50
+ *
51
+ * @public
52
+ */
53
+ declare function supermemoryMemory(options: SupermemoryAdapterOptions): Plugin;
54
+
55
+ export { type SupermemoryAdapterOptions, supermemoryMemory };
package/dist/index.js ADDED
@@ -0,0 +1,245 @@
1
+ import { definePlugin, MemoryAdapterError, mkMemoryId, extractRawId } from '@theokit/sdk';
2
+ import SupermemoryClient from 'supermemory';
3
+
4
+ // src/index.ts
5
+ var SAFE_IDENT = /^[a-zA-Z0-9_-]+$/;
6
+ var ADAPTER_ID = "supermemory";
7
+ function sanitizeIdentifier(value, fieldName) {
8
+ if (typeof value !== "string" || value.length === 0) {
9
+ throw new MemoryAdapterError(`Supermemory adapter: ${fieldName} must be a non-empty string`, {
10
+ adapterId: ADAPTER_ID,
11
+ code: "invalid_input"
12
+ });
13
+ }
14
+ if (!SAFE_IDENT.test(value)) {
15
+ throw new MemoryAdapterError(
16
+ `Supermemory adapter: ${fieldName} "${value}" contains invalid characters (allowed: a-zA-Z0-9_-)`,
17
+ { adapterId: ADAPTER_ID, code: "invalid_input" }
18
+ );
19
+ }
20
+ return value;
21
+ }
22
+ function buildContainerTags(ctx, prefix) {
23
+ const safePrefix = sanitizeIdentifier(prefix, "prefix");
24
+ const tags = [`${safePrefix}:user:${sanitizeIdentifier(ctx.userId, "userId")}`];
25
+ if (ctx.agentId !== void 0) {
26
+ tags.push(`${safePrefix}:agent:${sanitizeIdentifier(ctx.agentId, "agentId")}`);
27
+ }
28
+ if (ctx.tenantId !== void 0) {
29
+ tags.push(`${safePrefix}:tenant:${sanitizeIdentifier(ctx.tenantId, "tenantId")}`);
30
+ }
31
+ if (ctx.tags !== void 0) {
32
+ for (const t of ctx.tags) {
33
+ tags.push(`${safePrefix}:tag:${sanitizeIdentifier(t, "tag")}`);
34
+ }
35
+ }
36
+ return tags;
37
+ }
38
+ function primaryContainerTag(ctx, prefix) {
39
+ const safePrefix = sanitizeIdentifier(prefix, "prefix");
40
+ return `${safePrefix}:user:${sanitizeIdentifier(ctx.userId, "userId")}`;
41
+ }
42
+
43
+ // src/adapter.ts
44
+ var ADAPTER_ID2 = "supermemory";
45
+ var CAPS = {
46
+ history: false,
47
+ sessions: false,
48
+ tenancy: true,
49
+ reasoning: false,
50
+ toolSchemas: true,
51
+ prefetch: false
52
+ };
53
+ var SupermemoryAdapter = class {
54
+ id = ADAPTER_ID2;
55
+ capabilities = CAPS;
56
+ #opts;
57
+ #client;
58
+ constructor(opts) {
59
+ this.#opts = opts;
60
+ }
61
+ isAvailable() {
62
+ return typeof this.#opts.apiKey === "string" && this.#opts.apiKey.length > 0;
63
+ }
64
+ async initialize() {
65
+ }
66
+ async write(content, ctx) {
67
+ const text = this.#renderContent(content);
68
+ if (text.length === 0) {
69
+ throw new MemoryAdapterError("write: empty content", {
70
+ adapterId: ADAPTER_ID2,
71
+ code: "invalid_input"
72
+ });
73
+ }
74
+ const containerTags = buildContainerTags(ctx, this.#prefix());
75
+ try {
76
+ const resp = await this.#sdk().documents.add({
77
+ content: text,
78
+ containerTags,
79
+ ...ctx.metadata !== void 0 ? { metadata: ctx.metadata } : {}
80
+ });
81
+ return mkMemoryId(ADAPTER_ID2, resp.id);
82
+ } catch (err) {
83
+ throw this.#translateError(err, "write");
84
+ }
85
+ }
86
+ async recall(query, ctx, k = 10) {
87
+ if (k <= 0) return [];
88
+ const containerTag = primaryContainerTag(ctx, this.#prefix());
89
+ try {
90
+ const resp = await this.#sdk().search.memories({
91
+ q: query,
92
+ containerTag,
93
+ limit: k,
94
+ rerank: true
95
+ });
96
+ const results = resp.results ?? [];
97
+ return results.map(this.#mapResult);
98
+ } catch (err) {
99
+ throw this.#translateError(err, "recall");
100
+ }
101
+ }
102
+ async delete(id) {
103
+ const rawId = extractRawId(id, ADAPTER_ID2);
104
+ try {
105
+ await this.#sdk().documents.delete(rawId);
106
+ } catch (err) {
107
+ throw this.#translateError(err, "delete");
108
+ }
109
+ }
110
+ getToolSchemas() {
111
+ return [
112
+ {
113
+ name: "memory_write",
114
+ description: "Persist a fact about the user or context to Supermemory long-term memory. Returns the stored memory ID.",
115
+ parameters: {
116
+ type: "object",
117
+ properties: {
118
+ content: { type: "string", description: "Fact text to persist verbatim." }
119
+ },
120
+ required: ["content"]
121
+ }
122
+ },
123
+ {
124
+ name: "memory_recall",
125
+ description: "Retrieve up to k semantically relevant facts from Supermemory long-term memory. Returns an array of {id, content, score, createdAt} objects.",
126
+ parameters: {
127
+ type: "object",
128
+ properties: {
129
+ query: { type: "string", description: "Free-text query to search memory." },
130
+ k: {
131
+ type: "integer",
132
+ minimum: 1,
133
+ maximum: 50,
134
+ description: "Max results (default 10)."
135
+ }
136
+ },
137
+ required: ["query"]
138
+ }
139
+ }
140
+ ];
141
+ }
142
+ async handleToolCall(name, args, ctx) {
143
+ if (name === "memory_write") {
144
+ const content = String(args.content ?? "");
145
+ const id = await this.write(content, ctx);
146
+ return JSON.stringify({ ok: true, id });
147
+ }
148
+ if (name === "memory_recall") {
149
+ const query = String(args.query ?? "");
150
+ const k = typeof args.k === "number" ? args.k : 10;
151
+ const facts = await this.recall(query, ctx, k);
152
+ return JSON.stringify({ ok: true, facts });
153
+ }
154
+ throw new MemoryAdapterError(`Unknown tool name: ${name}`, {
155
+ adapterId: ADAPTER_ID2,
156
+ code: "invalid_input"
157
+ });
158
+ }
159
+ async shutdown() {
160
+ this.#client = void 0;
161
+ }
162
+ // ── helpers ────────────────────────────────────────────────────────
163
+ #prefix() {
164
+ return this.#opts.containerTagPrefix ?? "theokit";
165
+ }
166
+ #renderContent(content) {
167
+ if (typeof content === "string") return content.trim();
168
+ return content.map((m) => `${m.role}: ${m.content}`).join("\n").trim();
169
+ }
170
+ #mapResult = (r) => {
171
+ const obj = r ?? {};
172
+ const memory = obj.memory ?? obj;
173
+ const rawId = String(memory.id ?? obj.id ?? "");
174
+ const content = String(memory.content ?? memory.text ?? obj.content ?? "");
175
+ const score = typeof obj.score === "number" ? obj.score : void 0;
176
+ const createdAt = typeof memory.createdAt === "string" ? memory.createdAt : void 0;
177
+ return {
178
+ id: mkMemoryId(ADAPTER_ID2, rawId),
179
+ content,
180
+ ...score !== void 0 ? { score } : {},
181
+ ...createdAt !== void 0 ? { createdAt } : {}
182
+ };
183
+ };
184
+ #sdk() {
185
+ if (this.#client === void 0) {
186
+ this.#client = new SupermemoryClient({
187
+ apiKey: this.#opts.apiKey,
188
+ ...this.#opts.baseUrl !== void 0 ? { baseURL: this.#opts.baseUrl } : {}
189
+ });
190
+ }
191
+ return this.#client;
192
+ }
193
+ #translateError(err, op) {
194
+ if (err instanceof MemoryAdapterError) return err;
195
+ const status = err?.status ?? err?.statusCode;
196
+ const message = err?.message ?? String(err);
197
+ if (status === 401 || status === 403) {
198
+ return new MemoryAdapterError(`Supermemory auth failed (${op}): ${message}`, {
199
+ adapterId: ADAPTER_ID2,
200
+ code: "auth_failed",
201
+ cause: err
202
+ });
203
+ }
204
+ if (status === 429) {
205
+ return new MemoryAdapterError(`Supermemory rate limited (${op}): ${message}`, {
206
+ adapterId: ADAPTER_ID2,
207
+ code: "rate_limited",
208
+ cause: err
209
+ });
210
+ }
211
+ if (status === 404) {
212
+ return new MemoryAdapterError(`Supermemory not found (${op}): ${message}`, {
213
+ adapterId: ADAPTER_ID2,
214
+ code: "not_found",
215
+ cause: err
216
+ });
217
+ }
218
+ if (status === void 0 && message.toLowerCase().includes("network")) {
219
+ return new MemoryAdapterError(`Supermemory network error (${op}): ${message}`, {
220
+ adapterId: ADAPTER_ID2,
221
+ code: "network",
222
+ cause: err
223
+ });
224
+ }
225
+ return new MemoryAdapterError(`Supermemory error (${op}): ${message}`, {
226
+ adapterId: ADAPTER_ID2,
227
+ code: "unknown",
228
+ cause: err
229
+ });
230
+ }
231
+ };
232
+
233
+ // src/index.ts
234
+ function supermemoryMemory(options) {
235
+ return definePlugin({
236
+ name: "@theokit/memory-supermemory",
237
+ version: "0.1.0",
238
+ kind: "memory",
239
+ createProvider: () => new SupermemoryAdapter(options)
240
+ });
241
+ }
242
+
243
+ export { supermemoryMemory };
244
+ //# sourceMappingURL=index.js.map
245
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/translate.ts","../src/adapter.ts","../src/index.ts"],"names":["ADAPTER_ID","MemoryAdapterError"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * `MemoryContext` → Supermemory containerTags translation (T3.2).\n *\n * EC-C fix: every component runs through a strict identifier sanitizer\n * (regex `^[a-zA-Z0-9_-]+$`) before being joined with `:`. Rejects with\n * `MemoryAdapterError(code: \"invalid_input\")` on invalid input, so a\n * value like `userId: \"user:123\"` cannot silently land in a different\n * bucket via tag mis-parsing.\n *\n * @internal\n */\n\nimport type { MemoryContext } from \"@theokit/sdk\";\nimport { MemoryAdapterError } from \"@theokit/sdk\";\n\nconst SAFE_IDENT = /^[a-zA-Z0-9_-]+$/;\nconst ADAPTER_ID = \"supermemory\";\n\nexport function sanitizeIdentifier(value: string, fieldName: string): string {\n if (typeof value !== \"string\" || value.length === 0) {\n throw new MemoryAdapterError(`Supermemory adapter: ${fieldName} must be a non-empty string`, {\n adapterId: ADAPTER_ID,\n code: \"invalid_input\",\n });\n }\n if (!SAFE_IDENT.test(value)) {\n throw new MemoryAdapterError(\n `Supermemory adapter: ${fieldName} \"${value}\" contains invalid characters (allowed: a-zA-Z0-9_-)`,\n { adapterId: ADAPTER_ID, code: \"invalid_input\" },\n );\n }\n return value;\n}\n\n/**\n * Build the array of containerTags for `documents.add`. Each component\n * is sanitized; collisions across tag namespaces (user/agent/tenant/tag)\n * are intentional — Supermemory treats containerTags as a set.\n *\n * @internal\n */\nexport function buildContainerTags(ctx: MemoryContext, prefix: string): string[] {\n const safePrefix = sanitizeIdentifier(prefix, \"prefix\");\n const tags: string[] = [`${safePrefix}:user:${sanitizeIdentifier(ctx.userId, \"userId\")}`];\n if (ctx.agentId !== undefined) {\n tags.push(`${safePrefix}:agent:${sanitizeIdentifier(ctx.agentId, \"agentId\")}`);\n }\n if (ctx.tenantId !== undefined) {\n tags.push(`${safePrefix}:tenant:${sanitizeIdentifier(ctx.tenantId, \"tenantId\")}`);\n }\n if (ctx.tags !== undefined) {\n for (const t of ctx.tags) {\n tags.push(`${safePrefix}:tag:${sanitizeIdentifier(t, \"tag\")}`);\n }\n }\n return tags;\n}\n\n/**\n * Pick the primary containerTag for `search.memories` (which takes a\n * single string, not an array). The user tag is canonical.\n *\n * @internal\n */\nexport function primaryContainerTag(ctx: MemoryContext, prefix: string): string {\n const safePrefix = sanitizeIdentifier(prefix, \"prefix\");\n return `${safePrefix}:user:${sanitizeIdentifier(ctx.userId, \"userId\")}`;\n}\n","/**\n * SupermemoryAdapter — `@theokit-memory-supermemory` core (T3.2, ADR D141).\n *\n * Wraps `supermemory` SDK v4. Implements `MemoryAdapter` so the SDK's\n * `pre_user_send` / `post_assistant_reply` hooks (D145) and\n * `agent.memory.*` direct API (D142) work end-to-end against Supermemory's\n * managed memory + RAG service.\n *\n * @public\n */\n\nimport {\n extractRawId,\n type MemoryAdapter,\n type MemoryAdapterCapabilities,\n MemoryAdapterError,\n type MemoryContext,\n type MemoryFact,\n type MemoryId,\n type MemoryToolSchema,\n type MemoryTurnMessage,\n mkMemoryId,\n} from \"@theokit/sdk\";\nimport type Supermemory from \"supermemory\";\nimport SupermemoryClient from \"supermemory\";\n\nimport { buildContainerTags, primaryContainerTag } from \"./translate.js\";\n\n/** Configuration accepted by the `supermemoryMemory(...)` factory. @public */\nexport interface SupermemoryAdapterOptions {\n /** Supermemory API key. Falls back to `SUPERMEMORY_API_KEY`. */\n apiKey: string;\n /** Base URL override for self-hosted Supermemory deployments. */\n baseUrl?: string;\n /** Prefix for every containerTag (default `\"theokit\"`). Useful for test isolation (EC-S). */\n containerTagPrefix?: string;\n}\n\nconst ADAPTER_ID = \"supermemory\";\n\nconst CAPS: MemoryAdapterCapabilities = {\n history: false,\n sessions: false,\n tenancy: true,\n reasoning: false,\n toolSchemas: true,\n prefetch: false,\n};\n\n/**\n * SDK-internal adapter class. Construct via `supermemoryMemory(...)`\n * factory from `./index.ts`, not directly.\n *\n * @internal\n */\nexport class SupermemoryAdapter implements MemoryAdapter {\n readonly id = ADAPTER_ID;\n readonly capabilities = CAPS;\n readonly #opts: SupermemoryAdapterOptions;\n #client?: Supermemory;\n\n constructor(opts: SupermemoryAdapterOptions) {\n this.#opts = opts;\n }\n\n isAvailable(): boolean {\n return typeof this.#opts.apiKey === \"string\" && this.#opts.apiKey.length > 0;\n }\n\n async initialize(): Promise<void> {\n // Lazy: defer the actual client construction until first call.\n // initialize() is idempotent — see EC-3 / EC-I.\n }\n\n async write(content: string | MemoryTurnMessage[], ctx: MemoryContext): Promise<MemoryId> {\n const text = this.#renderContent(content);\n if (text.length === 0) {\n throw new MemoryAdapterError(\"write: empty content\", {\n adapterId: ADAPTER_ID,\n code: \"invalid_input\",\n });\n }\n const containerTags = buildContainerTags(ctx, this.#prefix());\n try {\n const resp = await this.#sdk().documents.add({\n content: text,\n containerTags,\n ...(ctx.metadata !== undefined ? { metadata: ctx.metadata as Record<string, string> } : {}),\n });\n return mkMemoryId(ADAPTER_ID, resp.id);\n } catch (err) {\n throw this.#translateError(err, \"write\");\n }\n }\n\n async recall(query: string, ctx: MemoryContext, k = 10): Promise<MemoryFact[]> {\n if (k <= 0) return [];\n const containerTag = primaryContainerTag(ctx, this.#prefix());\n try {\n const resp = await this.#sdk().search.memories({\n q: query,\n containerTag,\n limit: k,\n rerank: true,\n });\n const results = resp.results ?? [];\n return results.map(this.#mapResult);\n } catch (err) {\n throw this.#translateError(err, \"recall\");\n }\n }\n\n async delete(id: MemoryId): Promise<void> {\n const rawId = extractRawId(id, ADAPTER_ID);\n try {\n await this.#sdk().documents.delete(rawId);\n } catch (err) {\n throw this.#translateError(err, \"delete\");\n }\n }\n\n getToolSchemas(): MemoryToolSchema[] {\n return [\n {\n name: \"memory_write\",\n description:\n \"Persist a fact about the user or context to Supermemory long-term memory. \" +\n \"Returns the stored memory ID.\",\n parameters: {\n type: \"object\",\n properties: {\n content: { type: \"string\", description: \"Fact text to persist verbatim.\" },\n },\n required: [\"content\"],\n },\n },\n {\n name: \"memory_recall\",\n description:\n \"Retrieve up to k semantically relevant facts from Supermemory long-term memory. \" +\n \"Returns an array of {id, content, score, createdAt} objects.\",\n parameters: {\n type: \"object\",\n properties: {\n query: { type: \"string\", description: \"Free-text query to search memory.\" },\n k: {\n type: \"integer\",\n minimum: 1,\n maximum: 50,\n description: \"Max results (default 10).\",\n },\n },\n required: [\"query\"],\n },\n },\n ];\n }\n\n async handleToolCall(\n name: string,\n args: Record<string, unknown>,\n ctx: MemoryContext,\n ): Promise<string> {\n if (name === \"memory_write\") {\n const content = String(args.content ?? \"\");\n const id = await this.write(content, ctx);\n return JSON.stringify({ ok: true, id });\n }\n if (name === \"memory_recall\") {\n const query = String(args.query ?? \"\");\n const k = typeof args.k === \"number\" ? args.k : 10;\n const facts = await this.recall(query, ctx, k);\n return JSON.stringify({ ok: true, facts });\n }\n throw new MemoryAdapterError(`Unknown tool name: ${name}`, {\n adapterId: ADAPTER_ID,\n code: \"invalid_input\",\n });\n }\n\n async shutdown(): Promise<void> {\n this.#client = undefined;\n }\n\n // ── helpers ────────────────────────────────────────────────────────\n\n #prefix(): string {\n return this.#opts.containerTagPrefix ?? \"theokit\";\n }\n\n #renderContent(content: string | MemoryTurnMessage[]): string {\n if (typeof content === \"string\") return content.trim();\n return content\n .map((m) => `${m.role}: ${m.content}`)\n .join(\"\\n\")\n .trim();\n }\n\n #mapResult = (r: unknown): MemoryFact => {\n const obj = (r as Record<string, unknown>) ?? {};\n // SDK shape: { memory?: { id, content, ... }, score, ... } or chunk shape.\n const memory = (obj.memory as Record<string, unknown> | undefined) ?? obj;\n const rawId = String(memory.id ?? obj.id ?? \"\");\n const content = String(memory.content ?? memory.text ?? obj.content ?? \"\");\n const score = typeof obj.score === \"number\" ? obj.score : undefined;\n const createdAt = typeof memory.createdAt === \"string\" ? memory.createdAt : undefined;\n return {\n id: mkMemoryId(ADAPTER_ID, rawId),\n content,\n ...(score !== undefined ? { score } : {}),\n ...(createdAt !== undefined ? { createdAt } : {}),\n };\n };\n\n #sdk(): Supermemory {\n if (this.#client === undefined) {\n this.#client = new SupermemoryClient({\n apiKey: this.#opts.apiKey,\n ...(this.#opts.baseUrl !== undefined ? { baseURL: this.#opts.baseUrl } : {}),\n });\n }\n return this.#client;\n }\n\n #translateError(err: unknown, op: string): MemoryAdapterError {\n if (err instanceof MemoryAdapterError) return err;\n const status =\n (err as { status?: number; statusCode?: number })?.status ??\n (err as { statusCode?: number })?.statusCode;\n const message = (err as Error)?.message ?? String(err);\n if (status === 401 || status === 403) {\n return new MemoryAdapterError(`Supermemory auth failed (${op}): ${message}`, {\n adapterId: ADAPTER_ID,\n code: \"auth_failed\",\n cause: err,\n });\n }\n if (status === 429) {\n return new MemoryAdapterError(`Supermemory rate limited (${op}): ${message}`, {\n adapterId: ADAPTER_ID,\n code: \"rate_limited\",\n cause: err,\n });\n }\n if (status === 404) {\n return new MemoryAdapterError(`Supermemory not found (${op}): ${message}`, {\n adapterId: ADAPTER_ID,\n code: \"not_found\",\n cause: err,\n });\n }\n if (status === undefined && message.toLowerCase().includes(\"network\")) {\n return new MemoryAdapterError(`Supermemory network error (${op}): ${message}`, {\n adapterId: ADAPTER_ID,\n code: \"network\",\n cause: err,\n });\n }\n return new MemoryAdapterError(`Supermemory error (${op}): ${message}`, {\n adapterId: ADAPTER_ID,\n code: \"unknown\",\n cause: err,\n });\n }\n}\n","/**\n * `@theokit/memory-supermemory` — Supermemory memory adapter for @theokit/sdk.\n *\n * Usage:\n *\n * ```ts\n * import { Agent } from \"@theokit/sdk\";\n * import { supermemoryMemory } from \"@theokit/memory-supermemory\";\n *\n * const agent = await Agent.create({\n * apiKey: process.env.OPENROUTER_API_KEY,\n * model: { id: \"openai/gpt-4o-mini\" },\n * local: {},\n * plugins: [supermemoryMemory({ apiKey: process.env.SUPERMEMORY_API_KEY! })],\n * memoryContext: { userId: \"demo\" },\n * });\n *\n * await agent.memory.write(\"User likes Brazilian jazz\", { userId: \"demo\" });\n * const facts = await agent.memory.recall(\"music preferences\", { userId: \"demo\" });\n * ```\n *\n * @public\n */\n\nimport type { Plugin } from \"@theokit/sdk\";\nimport { definePlugin } from \"@theokit/sdk\";\n\nimport { SupermemoryAdapter, type SupermemoryAdapterOptions } from \"./adapter.js\";\n\nexport type { SupermemoryAdapterOptions } from \"./adapter.js\";\n\n/**\n * Build a `Plugin { kind: \"memory\" }` ready to pass to\n * `Agent.create({ plugins: [...] })`.\n *\n * @public\n */\nexport function supermemoryMemory(options: SupermemoryAdapterOptions): Plugin {\n return definePlugin({\n name: \"@theokit/memory-supermemory\",\n version: \"0.1.0\",\n kind: \"memory\",\n createProvider: () => new SupermemoryAdapter(options),\n });\n}\n"]}
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "@theokit/memory-supermemory",
3
+ "version": "0.1.0",
4
+ "description": "Supermemory memory adapter for @theokit/sdk — wraps supermemory@^4 with the MemoryAdapter contract (ADR D141).",
5
+ "license": "Apache-2.0",
6
+ "type": "module",
7
+ "engines": {
8
+ "node": ">=22.12.0"
9
+ },
10
+ "main": "./dist/index.cjs",
11
+ "module": "./dist/index.js",
12
+ "types": "./dist/index.d.ts",
13
+ "exports": {
14
+ ".": {
15
+ "import": {
16
+ "types": "./dist/index.d.ts",
17
+ "default": "./dist/index.js"
18
+ },
19
+ "require": {
20
+ "types": "./dist/index.d.cts",
21
+ "default": "./dist/index.cjs"
22
+ }
23
+ }
24
+ },
25
+ "files": [
26
+ "dist",
27
+ "README.md",
28
+ "LICENSE",
29
+ "CHANGELOG.md"
30
+ ],
31
+ "scripts": {
32
+ "build": "tsup",
33
+ "typecheck": "tsc --noEmit",
34
+ "test": "vitest run"
35
+ },
36
+ "peerDependencies": {
37
+ "@theokit/sdk": "workspace:^",
38
+ "supermemory": "^4.21.0"
39
+ },
40
+ "devDependencies": {
41
+ "@theokit/sdk": "workspace:*",
42
+ "supermemory": "^4.21.1",
43
+ "tsup": "^8.5.0",
44
+ "typescript": "^5.8.0",
45
+ "vitest": "^3.0.0"
46
+ }
47
+ }