getmnemo 0.1.3 → 0.2.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/README.md +74 -14
- package/dist/index.cjs +77 -21
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +132 -30
- package/dist/index.d.ts +132 -30
- package/dist/index.js +77 -21
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -6,7 +6,9 @@ Official TypeScript / JavaScript SDK for [Mnemo Memory](https://mnemohq.com) —
|
|
|
6
6
|
npm install getmnemo
|
|
7
7
|
```
|
|
8
8
|
|
|
9
|
-
Zero runtime dependencies. Works in Node 18+, Bun, Deno, Cloudflare Workers, and any other modern server or edge JS runtime with `fetch`.
|
|
9
|
+
Zero runtime dependencies. Works in Node 18+, Bun, Deno, Cloudflare Workers, and any other modern server or edge JS runtime with `fetch`.
|
|
10
|
+
|
|
11
|
+
A default `apiKey` is **full-access** — keep it server-side. Scoped keys **do** exist: the key-mint dialog lets you grant `read` / `write` / `delete` / `billing` scopes individually. For browser or client-exposed contexts, mint a **scoped read-only key** (or proxy through a server route) rather than shipping a full-access key.
|
|
10
12
|
|
|
11
13
|
## Quickstart
|
|
12
14
|
|
|
@@ -18,25 +20,59 @@ const memory = new Mnemo({
|
|
|
18
20
|
workspaceId: process.env.GETMNEMO_WORKSPACE_ID!,
|
|
19
21
|
})
|
|
20
22
|
|
|
21
|
-
// Store an atomic fact
|
|
22
|
-
await memory.add({
|
|
23
|
+
// Store an atomic fact, scoped to a container (e.g. a user)
|
|
24
|
+
await memory.add({
|
|
25
|
+
content: 'User prefers Japanese short-grain rice for onigiri.',
|
|
26
|
+
containerTag: 'user:jane',
|
|
27
|
+
})
|
|
23
28
|
|
|
24
|
-
// Retrieve relevant facts
|
|
25
|
-
const {
|
|
26
|
-
|
|
29
|
+
// Retrieve relevant facts from the same container
|
|
30
|
+
const { results } = await memory.search({
|
|
31
|
+
q: 'what kind of rice does the user like?',
|
|
32
|
+
containerTag: 'user:jane',
|
|
33
|
+
})
|
|
34
|
+
for (const hit of results) {
|
|
27
35
|
console.log(hit.score.toFixed(2), hit.content)
|
|
28
36
|
}
|
|
29
37
|
```
|
|
30
38
|
|
|
39
|
+
## Containers
|
|
40
|
+
|
|
41
|
+
Memories live in **containers**. Identify a container two ways:
|
|
42
|
+
|
|
43
|
+
- `containerTag` — a string like `"user:jane"` (the simplest, recommended form)
|
|
44
|
+
- `scope` — the structured equivalent `{ type: 'user', id: 'jane' }`
|
|
45
|
+
|
|
46
|
+
`add` and `search` require a container. Set one per call, or set `defaultContainerTag`
|
|
47
|
+
on the client once so every call falls back to it:
|
|
48
|
+
|
|
49
|
+
```ts
|
|
50
|
+
const memory = new Mnemo({
|
|
51
|
+
apiKey: process.env.GETMNEMO_API_KEY!,
|
|
52
|
+
workspaceId: process.env.GETMNEMO_WORKSPACE_ID!,
|
|
53
|
+
defaultContainerTag: 'user:jane',
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
await memory.add({ content: 'Likes onigiri.' }) // uses user:jane
|
|
57
|
+
await memory.search({ q: 'food preferences?' }) // uses user:jane
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
If neither a per-call container nor a default is set, `add`/`search` throw before
|
|
61
|
+
hitting the network.
|
|
62
|
+
|
|
31
63
|
## API surface
|
|
32
64
|
|
|
33
65
|
| Method | Purpose |
|
|
34
66
|
|---|---|
|
|
35
|
-
| `search({
|
|
36
|
-
| `add({ content,
|
|
37
|
-
| `update(
|
|
38
|
-
| `
|
|
39
|
-
| `
|
|
67
|
+
| `search({ q, containerTag?, scope?, limit?, searchMode? })` | Hybrid retrieval. Returns `SearchResponse`. |
|
|
68
|
+
| `add({ content, containerTag?, scope?, metadata? })` | Store an atomic fact. Returns `AddResponse`. |
|
|
69
|
+
| `update(memoryId, { content?, memoryType?, metadata?, source? })` | Patch an existing memory. |
|
|
70
|
+
| `get(memoryId)` | Fetch a single memory. |
|
|
71
|
+
| `delete(memoryId)` | Remove a memory. |
|
|
72
|
+
| `list({ containerTag?, limit?, cursor?, scopeType?, scopeId? })` | Cursor-paginated list. |
|
|
73
|
+
|
|
74
|
+
> Response types (`SearchResponse`, `AddResponse`, `Memory`, …) are **provisional** —
|
|
75
|
+
> reconstructed from observed live payloads pending a fully-annotated API spec.
|
|
40
76
|
|
|
41
77
|
## Errors
|
|
42
78
|
|
|
@@ -46,7 +82,7 @@ All HTTP failures throw `MnemoHTTPError` with `.status` and `.body`. Aborted req
|
|
|
46
82
|
import { Mnemo, MnemoHTTPError } from 'getmnemo'
|
|
47
83
|
|
|
48
84
|
try {
|
|
49
|
-
await memory.search({
|
|
85
|
+
await memory.search({ q: 'rice', containerTag: 'user:jane' })
|
|
50
86
|
} catch (err) {
|
|
51
87
|
if (err instanceof MnemoHTTPError && err.status === 401) {
|
|
52
88
|
console.error('API key rejected:', err.body)
|
|
@@ -61,8 +97,8 @@ try {
|
|
|
61
97
|
| Option | Default | Notes |
|
|
62
98
|
|---|---|---|
|
|
63
99
|
| `apiKey` | (required) | from <https://app.mnemohq.com/settings/api-keys> |
|
|
64
|
-
| `workspaceId` | (required) |
|
|
65
|
-
| `
|
|
100
|
+
| `workspaceId` | (required) | sent as the `x-workspace-id` header |
|
|
101
|
+
| `defaultContainerTag` | none | fallback container for `add`/`search` |
|
|
66
102
|
| `baseUrl` | `https://api.mnemohq.com` | override for self-hosted |
|
|
67
103
|
| `timeoutMs` | `30000` | per-request abort timeout |
|
|
68
104
|
| `fetch` | global `fetch` | inject for testing or proxying |
|
|
@@ -75,6 +111,30 @@ npm test
|
|
|
75
111
|
npm run build
|
|
76
112
|
```
|
|
77
113
|
|
|
114
|
+
## CI smoke gate
|
|
115
|
+
|
|
116
|
+
The publish workflow (`.github/workflows/publish.yml`) will **not** publish to
|
|
117
|
+
npm unless a real production round-trip passes first. A `smoke` job runs on the
|
|
118
|
+
same `v*` tag trigger and the `publish` job depends on it via `needs: smoke`, so
|
|
119
|
+
a failed smoke blocks the release.
|
|
120
|
+
|
|
121
|
+
`npm run smoke` (`scripts/prod-smoke.mjs`) writes a memory to container **A** and
|
|
122
|
+
another to container **B** against prod, confirms the add/search round-trip via
|
|
123
|
+
`response.results`, then asserts **tenant isolation**: a search scoped to B must
|
|
124
|
+
not return A's memory, and vice versa. A leak exits non-zero with a loud
|
|
125
|
+
`TENANT ISOLATION FAILURE` — treat that as a production security finding, not a
|
|
126
|
+
flaky test. Created memories are deleted on cleanup (cleanup failure only warns).
|
|
127
|
+
|
|
128
|
+
It needs three secrets, which **must be ORG-level (no repo-level twin)** — a
|
|
129
|
+
repo-level twin shadows the org secret, which is exactly the failure mode that
|
|
130
|
+
broke an earlier publish:
|
|
131
|
+
|
|
132
|
+
| Secret | Purpose |
|
|
133
|
+
|---|---|
|
|
134
|
+
| `MNEMO_API_KEY` | Scoped test key. **Needs `delete` scope** so the smoke can clean up the memories it creates (plus `write` + `search`). |
|
|
135
|
+
| `MNEMO_WORKSPACE_ID` | Throwaway test workspace id. |
|
|
136
|
+
| `MNEMO_TEST_CONTAINER` | Base `containerTag` (e.g. `ci-smoke`); the script derives unique per-run A/B containers from it. |
|
|
137
|
+
|
|
78
138
|
## License
|
|
79
139
|
|
|
80
140
|
MIT
|
package/dist/index.cjs
CHANGED
|
@@ -30,7 +30,8 @@ var MnemoTimeoutError = class extends MnemoError {
|
|
|
30
30
|
// src/client.ts
|
|
31
31
|
var DEFAULT_BASE_URL = "https://api.mnemohq.com";
|
|
32
32
|
var DEFAULT_TIMEOUT_MS = 3e4;
|
|
33
|
-
var SDK_VERSION = "0.
|
|
33
|
+
var SDK_VERSION = "0.2.0";
|
|
34
|
+
var DEFAULT_SEARCH_LIMIT = 8;
|
|
34
35
|
var USER_AGENT = `getmnemo/${SDK_VERSION}`;
|
|
35
36
|
var DEFAULT_MAX_RETRIES = 3;
|
|
36
37
|
var RETRY_BASE_DELAY_MS = 200;
|
|
@@ -73,7 +74,7 @@ var Mnemo = class {
|
|
|
73
74
|
#fetch;
|
|
74
75
|
#timeoutMs;
|
|
75
76
|
#maxRetries;
|
|
76
|
-
#
|
|
77
|
+
#defaultContainerTag;
|
|
77
78
|
constructor(cfg) {
|
|
78
79
|
if (!cfg.apiKey) throw new Error("Mnemo: apiKey is required");
|
|
79
80
|
if (!cfg.workspaceId) throw new Error("Mnemo: workspaceId is required");
|
|
@@ -88,49 +89,104 @@ var Mnemo = class {
|
|
|
88
89
|
} else {
|
|
89
90
|
this.#headers["user-agent"] = USER_AGENT;
|
|
90
91
|
}
|
|
91
|
-
|
|
92
|
-
this.#defaultActorId = cfg.actorId;
|
|
92
|
+
this.#defaultContainerTag = cfg.defaultContainerTag;
|
|
93
93
|
this.#fetch = cfg.fetch ?? fetch;
|
|
94
94
|
this.#timeoutMs = cfg.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
95
95
|
this.#maxRetries = Math.max(0, cfg.maxRetries ?? DEFAULT_MAX_RETRIES);
|
|
96
96
|
}
|
|
97
|
+
/**
|
|
98
|
+
* Resolve the container for a call into the request fields the API expects.
|
|
99
|
+
* A structured `scope` wins over a `containerTag` string; both fall back to
|
|
100
|
+
* the constructor's `defaultContainerTag`. Throws if none is available.
|
|
101
|
+
*/
|
|
102
|
+
#resolveContainer(method, input) {
|
|
103
|
+
if (input.scope) return { scope: input.scope };
|
|
104
|
+
const tag = input.containerTag ?? this.#defaultContainerTag;
|
|
105
|
+
if (tag) return { containerTag: tag };
|
|
106
|
+
throw new Error(
|
|
107
|
+
`Mnemo.${method}: a container is required \u2014 pass containerTag (e.g. "user:jane") or scope ({ type, id }) per call, or set defaultContainerTag on the client.`
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Hybrid retrieval. Requires a container — pass `containerTag` (e.g.
|
|
112
|
+
* `"user:jane"`) or `scope`, or set `defaultContainerTag` on the client.
|
|
113
|
+
*
|
|
114
|
+
* Sends `POST /v1/search` with body `{ q, limit, containerTag|scope }`.
|
|
115
|
+
*/
|
|
97
116
|
async search(input) {
|
|
117
|
+
const container = this.#resolveContainer("search", input);
|
|
98
118
|
return this.#request("POST", "/v1/search", {
|
|
99
|
-
|
|
100
|
-
limit: input.limit ??
|
|
101
|
-
...input.
|
|
119
|
+
q: input.q,
|
|
120
|
+
limit: input.limit ?? DEFAULT_SEARCH_LIMIT,
|
|
121
|
+
...input.searchMode !== void 0 ? { searchMode: input.searchMode } : {},
|
|
122
|
+
...container
|
|
102
123
|
});
|
|
103
124
|
}
|
|
125
|
+
/**
|
|
126
|
+
* Store an atomic fact. Requires a container — pass `containerTag` (e.g.
|
|
127
|
+
* `"user:jane"`) or `scope`, or set `defaultContainerTag` on the client.
|
|
128
|
+
*
|
|
129
|
+
* Sends `POST /v1/memories` with body
|
|
130
|
+
* `{ items: [{ content, metadata? }], containerTag|scope }`.
|
|
131
|
+
*/
|
|
104
132
|
async add(input) {
|
|
133
|
+
const container = this.#resolveContainer("add", input);
|
|
105
134
|
return this.#request("POST", "/v1/memories", {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
135
|
+
items: [
|
|
136
|
+
{
|
|
137
|
+
content: input.content,
|
|
138
|
+
...input.metadata !== void 0 ? { metadata: input.metadata } : {}
|
|
139
|
+
}
|
|
140
|
+
],
|
|
141
|
+
...container
|
|
109
142
|
});
|
|
110
143
|
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
144
|
+
/**
|
|
145
|
+
* Patch an existing memory by id.
|
|
146
|
+
* Sends `PATCH /v1/memories/{memoryId}` with body `UpdateMemoryDto`
|
|
147
|
+
* `{ content?, memoryType?, metadata?, source? }` (none required).
|
|
148
|
+
*/
|
|
149
|
+
async update(memoryId, input) {
|
|
150
|
+
if (input.content === void 0 && input.memoryType === void 0 && input.metadata === void 0 && input.source === void 0) {
|
|
151
|
+
throw new Error(
|
|
152
|
+
"Mnemo.update: at least one of content/memoryType/metadata/source must be provided"
|
|
153
|
+
);
|
|
114
154
|
}
|
|
115
|
-
return this.#request(
|
|
155
|
+
return this.#request(
|
|
156
|
+
"PATCH",
|
|
157
|
+
`/v1/memories/${encodeURIComponent(memoryId)}`,
|
|
158
|
+
input
|
|
159
|
+
);
|
|
116
160
|
}
|
|
117
|
-
|
|
118
|
-
|
|
161
|
+
/** Fetch a single memory by id. Sends `GET /v1/memories/{memoryId}`. */
|
|
162
|
+
async get(memoryId) {
|
|
163
|
+
return this.#request("GET", `/v1/memories/${encodeURIComponent(memoryId)}`);
|
|
119
164
|
}
|
|
120
|
-
|
|
121
|
-
|
|
165
|
+
/** Remove a memory by id. Sends `DELETE /v1/memories/{memoryId}`. */
|
|
166
|
+
async delete(memoryId) {
|
|
167
|
+
await this.#request(
|
|
168
|
+
"DELETE",
|
|
169
|
+
`/v1/memories/${encodeURIComponent(memoryId)}`
|
|
170
|
+
);
|
|
122
171
|
}
|
|
172
|
+
/**
|
|
173
|
+
* Cursor-paginated list of memories, optionally filtered by container.
|
|
174
|
+
* Sends `GET /v1/memories` with query
|
|
175
|
+
* `limit?, cursor?, scopeType?, scopeId?, containerTag?`.
|
|
176
|
+
*/
|
|
123
177
|
async list(input) {
|
|
124
178
|
const params = new URLSearchParams();
|
|
125
179
|
if (input?.limit !== void 0) params.set("limit", String(input.limit));
|
|
126
180
|
if (input?.cursor !== void 0) params.set("cursor", input.cursor);
|
|
127
|
-
if (input?.
|
|
181
|
+
if (input?.scopeType !== void 0) params.set("scopeType", input.scopeType);
|
|
182
|
+
if (input?.scopeId !== void 0) params.set("scopeId", input.scopeId);
|
|
183
|
+
if (input?.containerTag !== void 0) params.set("containerTag", input.containerTag);
|
|
128
184
|
const qs = params.toString();
|
|
129
185
|
return this.#request("GET", `/v1/memories${qs ? `?${qs}` : ""}`);
|
|
130
186
|
}
|
|
131
187
|
/** Echoed back for debugging — never sent to the wire. */
|
|
132
|
-
get
|
|
133
|
-
return this.#
|
|
188
|
+
get defaultContainerTag() {
|
|
189
|
+
return this.#defaultContainerTag;
|
|
134
190
|
}
|
|
135
191
|
async #request(method, path, body) {
|
|
136
192
|
const serializedBody = body === void 0 ? void 0 : JSON.stringify(body);
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/errors.ts","../src/client.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["export class MnemoError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'MnemoError'\n Object.setPrototypeOf(this, new.target.prototype)\n }\n}\n\nexport class MnemoHTTPError extends MnemoError {\n constructor(\n message: string,\n readonly status: number,\n readonly body?: unknown,\n ) {\n super(`[${status}] ${message}`)\n this.name = 'MnemoHTTPError'\n Object.setPrototypeOf(this, new.target.prototype)\n }\n}\n\nexport class MnemoTimeoutError extends MnemoError {\n constructor(timeoutMs: number) {\n super(`Request timed out after ${timeoutMs}ms`)\n this.name = 'MnemoTimeoutError'\n Object.setPrototypeOf(this, new.target.prototype)\n }\n}\n","/**\n * Mnemo Memory client.\n *\n * Zero runtime dependencies — uses the global `fetch` (Node 18+, Bun, browsers,\n * Cloudflare Workers, Deno, etc).\n *\n * @example\n * ```ts\n * import { Mnemo } from 'getmnemo'\n *\n * const memory = new Mnemo({\n * apiKey: process.env.GETMNEMO_API_KEY!,\n * workspaceId: process.env.GETMNEMO_WORKSPACE_ID!,\n * })\n *\n * await memory.add({ content: 'User prefers Japanese rice.' })\n * const { hits } = await memory.search({ query: 'what rice does the user like?' })\n * ```\n */\n\nimport { MnemoHTTPError, MnemoTimeoutError } from './errors.js'\nimport type {\n ClientConfig,\n Memory,\n PaginatedMemories,\n SearchResponse,\n} from './types.js'\n\nconst DEFAULT_BASE_URL = 'https://api.mnemohq.com'\nconst DEFAULT_TIMEOUT_MS = 30_000\nconst SDK_VERSION = '0.1.0'\nconst USER_AGENT = `getmnemo/${SDK_VERSION}`\nconst DEFAULT_MAX_RETRIES = 3\nconst RETRY_BASE_DELAY_MS = 200\nconst RETRY_MAX_DELAY_MS = 5_000\n\n// Browsers reject `user-agent` as a forbidden header — setting it via fetch\n// throws or warns. Detect a browser-like environment so we can skip it there.\nconst IS_BROWSER_LIKE =\n typeof globalThis !== 'undefined' &&\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n typeof (globalThis as any).window !== 'undefined' &&\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n typeof (globalThis as any).document !== 'undefined'\n\nfunction retryDelayMs(attempt: number): number {\n const capped = Math.min(RETRY_BASE_DELAY_MS * 2 ** attempt, RETRY_MAX_DELAY_MS)\n // Full jitter.\n return Math.floor(Math.random() * capped)\n}\n\nfunction isRetryableStatus(status: number): boolean {\n // 501 Not Implemented is a permanent failure — retrying just wastes round-trips.\n if (status === 501) return false\n return status === 429 || (status >= 500 && status < 600)\n}\n\nfunction parseRetryAfterMs(headerValue: string | null): number | null {\n if (!headerValue) return null\n const trimmed = headerValue.trim()\n // Delta-seconds form.\n const seconds = Number(trimmed)\n if (Number.isFinite(seconds) && seconds >= 0) {\n return Math.min(seconds * 1000, RETRY_MAX_DELAY_MS)\n }\n // HTTP-date form.\n const epoch = Date.parse(trimmed)\n if (!Number.isNaN(epoch)) {\n const delta = epoch - Date.now()\n return Math.max(0, Math.min(delta, RETRY_MAX_DELAY_MS))\n }\n return null\n}\n\nfunction delayForResponse(res: Response, attempt: number): number {\n const hint = parseRetryAfterMs(res.headers.get('retry-after'))\n return hint !== null ? hint : retryDelayMs(attempt)\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms))\n}\n\nexport class Mnemo {\n readonly #baseUrl: string\n readonly #headers: Record<string, string>\n readonly #fetch: typeof fetch\n readonly #timeoutMs: number\n readonly #maxRetries: number\n readonly #defaultActorId: string | undefined\n\n constructor(cfg: ClientConfig) {\n if (!cfg.apiKey) throw new Error('Mnemo: apiKey is required')\n if (!cfg.workspaceId) throw new Error('Mnemo: workspaceId is required')\n this.#baseUrl = (cfg.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/$/, '')\n this.#headers = {\n authorization: `Bearer ${cfg.apiKey}`,\n 'x-workspace-id': cfg.workspaceId,\n 'content-type': 'application/json',\n }\n // `user-agent` is on the forbidden header list in browsers — setting it\n // via fetch is silently dropped or throws. Send `x-getmnemo-client` as\n // an SDK identifier in browsers, and the standard User-Agent on Node.\n if (IS_BROWSER_LIKE) {\n this.#headers['x-getmnemo-client'] = USER_AGENT\n } else {\n this.#headers['user-agent'] = USER_AGENT\n }\n if (cfg.actorId) this.#headers['x-actor-id'] = cfg.actorId\n this.#defaultActorId = cfg.actorId\n this.#fetch = cfg.fetch ?? fetch\n this.#timeoutMs = cfg.timeoutMs ?? DEFAULT_TIMEOUT_MS\n this.#maxRetries = Math.max(0, cfg.maxRetries ?? DEFAULT_MAX_RETRIES)\n }\n\n async search(input: {\n query: string\n limit?: number\n actorId?: string\n }): Promise<SearchResponse> {\n return this.#request<SearchResponse>('POST', '/v1/search', {\n query: input.query,\n limit: input.limit ?? 8,\n ...(input.actorId !== undefined ? { actorId: input.actorId } : {}),\n })\n }\n\n async add(input: {\n content: string\n metadata?: Record<string, unknown>\n actorId?: string\n }): Promise<Memory> {\n return this.#request<Memory>('POST', '/v1/memories', {\n content: input.content,\n ...(input.metadata !== undefined ? { metadata: input.metadata } : {}),\n ...(input.actorId !== undefined ? { actorId: input.actorId } : {}),\n })\n }\n\n async update(\n id: string,\n input: { content?: string; metadata?: Record<string, unknown> },\n ): Promise<Memory> {\n if (input.content === undefined && input.metadata === undefined) {\n throw new Error('Mnemo.update: at least one of content/metadata must be provided')\n }\n return this.#request<Memory>('PATCH', `/v1/memories/${encodeURIComponent(id)}`, input)\n }\n\n async get(id: string): Promise<Memory> {\n return this.#request<Memory>('GET', `/v1/memories/${encodeURIComponent(id)}`)\n }\n\n async delete(id: string): Promise<void> {\n await this.#request<unknown>('DELETE', `/v1/memories/${encodeURIComponent(id)}`)\n }\n\n async list(input?: {\n limit?: number\n cursor?: string\n actorId?: string\n }): Promise<PaginatedMemories> {\n const params = new URLSearchParams()\n if (input?.limit !== undefined) params.set('limit', String(input.limit))\n if (input?.cursor !== undefined) params.set('cursor', input.cursor)\n if (input?.actorId !== undefined) params.set('actorId', input.actorId)\n const qs = params.toString()\n return this.#request<PaginatedMemories>('GET', `/v1/memories${qs ? `?${qs}` : ''}`)\n }\n\n /** Echoed back for debugging — never sent to the wire. */\n get defaultActorId(): string | undefined {\n return this.#defaultActorId\n }\n\n async #request<T>(method: string, path: string, body?: unknown): Promise<T> {\n const serializedBody = body === undefined ? undefined : JSON.stringify(body)\n let lastErr: unknown\n for (let attempt = 0; attempt <= this.#maxRetries; attempt++) {\n const ctrl = new AbortController()\n const timer = setTimeout(() => ctrl.abort(), this.#timeoutMs)\n try {\n const res = await this.#fetch(`${this.#baseUrl}${path}`, {\n method,\n headers: { ...this.#headers },\n body: serializedBody,\n signal: ctrl.signal,\n })\n if (isRetryableStatus(res.status) && attempt < this.#maxRetries) {\n // Capture Retry-After before draining; some runtimes invalidate\n // headers once the body is consumed.\n const wait = delayForResponse(res, attempt)\n // Drain body so the underlying connection can be reused.\n await res.text().catch(() => undefined)\n await sleep(wait)\n continue\n }\n const text = await res.text()\n const parsed: unknown = text ? safeJson(text) : undefined\n if (!res.ok) {\n const message =\n (parsed && typeof parsed === 'object' && 'message' in parsed\n ? String((parsed as { message: unknown }).message)\n : null) ?? `HTTP ${res.status} ${res.statusText}`\n throw new MnemoHTTPError(message, res.status, parsed)\n }\n return parsed as T\n } catch (err) {\n if (err instanceof Error && err.name === 'AbortError') {\n throw new MnemoTimeoutError(this.#timeoutMs)\n }\n if (err instanceof MnemoHTTPError) throw err\n lastErr = err\n if (attempt < this.#maxRetries) {\n await sleep(retryDelayMs(attempt))\n continue\n }\n throw err\n } finally {\n clearTimeout(timer)\n }\n }\n throw lastErr ?? new Error('Mnemo: request failed')\n }\n}\n\nfunction safeJson(s: string): unknown {\n try {\n return JSON.parse(s)\n } catch {\n return s\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/client.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["export class MnemoError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'MnemoError'\n Object.setPrototypeOf(this, new.target.prototype)\n }\n}\n\nexport class MnemoHTTPError extends MnemoError {\n constructor(\n message: string,\n readonly status: number,\n readonly body?: unknown,\n ) {\n super(`[${status}] ${message}`)\n this.name = 'MnemoHTTPError'\n Object.setPrototypeOf(this, new.target.prototype)\n }\n}\n\nexport class MnemoTimeoutError extends MnemoError {\n constructor(timeoutMs: number) {\n super(`Request timed out after ${timeoutMs}ms`)\n this.name = 'MnemoTimeoutError'\n Object.setPrototypeOf(this, new.target.prototype)\n }\n}\n","/**\n * Mnemo Memory client.\n *\n * Zero runtime dependencies — uses the global `fetch` (Node 18+, Bun, browsers,\n * Cloudflare Workers, Deno, etc).\n *\n * @example\n * ```ts\n * import { Mnemo } from 'getmnemo'\n *\n * const memory = new Mnemo({\n * apiKey: process.env.GETMNEMO_API_KEY!,\n * workspaceId: process.env.GETMNEMO_WORKSPACE_ID!,\n * })\n *\n * await memory.add({ content: 'User prefers Japanese rice.', containerTag: 'user:jane' })\n * const { results } = await memory.search({ q: 'what rice does the user like?', containerTag: 'user:jane' })\n * ```\n */\n\nimport { MnemoHTTPError, MnemoTimeoutError } from './errors.js'\nimport type {\n AddResponse,\n ClientConfig,\n Memory,\n PaginatedMemories,\n Scope,\n SearchResponse,\n} from './types.js'\n\nconst DEFAULT_BASE_URL = 'https://api.mnemohq.com'\nconst DEFAULT_TIMEOUT_MS = 30_000\nconst SDK_VERSION = '0.2.0'\nconst DEFAULT_SEARCH_LIMIT = 8\nconst USER_AGENT = `getmnemo/${SDK_VERSION}`\nconst DEFAULT_MAX_RETRIES = 3\nconst RETRY_BASE_DELAY_MS = 200\nconst RETRY_MAX_DELAY_MS = 5_000\n\n// Browsers reject `user-agent` as a forbidden header — setting it via fetch\n// throws or warns. Detect a browser-like environment so we can skip it there.\nconst IS_BROWSER_LIKE =\n typeof globalThis !== 'undefined' &&\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n typeof (globalThis as any).window !== 'undefined' &&\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n typeof (globalThis as any).document !== 'undefined'\n\nfunction retryDelayMs(attempt: number): number {\n const capped = Math.min(RETRY_BASE_DELAY_MS * 2 ** attempt, RETRY_MAX_DELAY_MS)\n // Full jitter.\n return Math.floor(Math.random() * capped)\n}\n\nfunction isRetryableStatus(status: number): boolean {\n // 501 Not Implemented is a permanent failure — retrying just wastes round-trips.\n if (status === 501) return false\n return status === 429 || (status >= 500 && status < 600)\n}\n\nfunction parseRetryAfterMs(headerValue: string | null): number | null {\n if (!headerValue) return null\n const trimmed = headerValue.trim()\n // Delta-seconds form.\n const seconds = Number(trimmed)\n if (Number.isFinite(seconds) && seconds >= 0) {\n return Math.min(seconds * 1000, RETRY_MAX_DELAY_MS)\n }\n // HTTP-date form.\n const epoch = Date.parse(trimmed)\n if (!Number.isNaN(epoch)) {\n const delta = epoch - Date.now()\n return Math.max(0, Math.min(delta, RETRY_MAX_DELAY_MS))\n }\n return null\n}\n\nfunction delayForResponse(res: Response, attempt: number): number {\n const hint = parseRetryAfterMs(res.headers.get('retry-after'))\n return hint !== null ? hint : retryDelayMs(attempt)\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms))\n}\n\nexport class Mnemo {\n readonly #baseUrl: string\n readonly #headers: Record<string, string>\n readonly #fetch: typeof fetch\n readonly #timeoutMs: number\n readonly #maxRetries: number\n readonly #defaultContainerTag: string | undefined\n\n constructor(cfg: ClientConfig) {\n if (!cfg.apiKey) throw new Error('Mnemo: apiKey is required')\n if (!cfg.workspaceId) throw new Error('Mnemo: workspaceId is required')\n this.#baseUrl = (cfg.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/$/, '')\n this.#headers = {\n authorization: `Bearer ${cfg.apiKey}`,\n 'x-workspace-id': cfg.workspaceId,\n 'content-type': 'application/json',\n }\n // `user-agent` is on the forbidden header list in browsers — setting it\n // via fetch is silently dropped or throws. Send `x-getmnemo-client` as\n // an SDK identifier in browsers, and the standard User-Agent on Node.\n if (IS_BROWSER_LIKE) {\n this.#headers['x-getmnemo-client'] = USER_AGENT\n } else {\n this.#headers['user-agent'] = USER_AGENT\n }\n this.#defaultContainerTag = cfg.defaultContainerTag\n this.#fetch = cfg.fetch ?? fetch\n this.#timeoutMs = cfg.timeoutMs ?? DEFAULT_TIMEOUT_MS\n this.#maxRetries = Math.max(0, cfg.maxRetries ?? DEFAULT_MAX_RETRIES)\n }\n\n /**\n * Resolve the container for a call into the request fields the API expects.\n * A structured `scope` wins over a `containerTag` string; both fall back to\n * the constructor's `defaultContainerTag`. Throws if none is available.\n */\n #resolveContainer(\n method: 'add' | 'search',\n input: { containerTag?: string; scope?: Scope },\n ): { containerTag: string } | { scope: Scope } {\n if (input.scope) return { scope: input.scope }\n const tag = input.containerTag ?? this.#defaultContainerTag\n if (tag) return { containerTag: tag }\n throw new Error(\n `Mnemo.${method}: a container is required — pass containerTag (e.g. \"user:jane\") ` +\n 'or scope ({ type, id }) per call, or set defaultContainerTag on the client.',\n )\n }\n\n /**\n * Hybrid retrieval. Requires a container — pass `containerTag` (e.g.\n * `\"user:jane\"`) or `scope`, or set `defaultContainerTag` on the client.\n *\n * Sends `POST /v1/search` with body `{ q, limit, containerTag|scope }`.\n */\n async search(input: {\n q: string\n containerTag?: string\n scope?: Scope\n limit?: number\n searchMode?: string\n }): Promise<SearchResponse> {\n const container = this.#resolveContainer('search', input)\n return this.#request<SearchResponse>('POST', '/v1/search', {\n q: input.q,\n limit: input.limit ?? DEFAULT_SEARCH_LIMIT,\n ...(input.searchMode !== undefined ? { searchMode: input.searchMode } : {}),\n ...container,\n })\n }\n\n /**\n * Store an atomic fact. Requires a container — pass `containerTag` (e.g.\n * `\"user:jane\"`) or `scope`, or set `defaultContainerTag` on the client.\n *\n * Sends `POST /v1/memories` with body\n * `{ items: [{ content, metadata? }], containerTag|scope }`.\n */\n async add(input: {\n content: string\n containerTag?: string\n scope?: Scope\n metadata?: Record<string, unknown>\n }): Promise<AddResponse> {\n const container = this.#resolveContainer('add', input)\n return this.#request<AddResponse>('POST', '/v1/memories', {\n items: [\n {\n content: input.content,\n ...(input.metadata !== undefined ? { metadata: input.metadata } : {}),\n },\n ],\n ...container,\n })\n }\n\n /**\n * Patch an existing memory by id.\n * Sends `PATCH /v1/memories/{memoryId}` with body `UpdateMemoryDto`\n * `{ content?, memoryType?, metadata?, source? }` (none required).\n */\n async update(\n memoryId: string,\n input: {\n content?: string\n memoryType?: string\n metadata?: Record<string, unknown>\n source?: string\n },\n ): Promise<Memory> {\n if (\n input.content === undefined &&\n input.memoryType === undefined &&\n input.metadata === undefined &&\n input.source === undefined\n ) {\n throw new Error(\n 'Mnemo.update: at least one of content/memoryType/metadata/source must be provided',\n )\n }\n return this.#request<Memory>(\n 'PATCH',\n `/v1/memories/${encodeURIComponent(memoryId)}`,\n input,\n )\n }\n\n /** Fetch a single memory by id. Sends `GET /v1/memories/{memoryId}`. */\n async get(memoryId: string): Promise<Memory> {\n return this.#request<Memory>('GET', `/v1/memories/${encodeURIComponent(memoryId)}`)\n }\n\n /** Remove a memory by id. Sends `DELETE /v1/memories/{memoryId}`. */\n async delete(memoryId: string): Promise<void> {\n await this.#request<unknown>(\n 'DELETE',\n `/v1/memories/${encodeURIComponent(memoryId)}`,\n )\n }\n\n /**\n * Cursor-paginated list of memories, optionally filtered by container.\n * Sends `GET /v1/memories` with query\n * `limit?, cursor?, scopeType?, scopeId?, containerTag?`.\n */\n async list(input?: {\n containerTag?: string\n limit?: number\n cursor?: string\n scopeType?: string\n scopeId?: string\n }): Promise<PaginatedMemories> {\n const params = new URLSearchParams()\n if (input?.limit !== undefined) params.set('limit', String(input.limit))\n if (input?.cursor !== undefined) params.set('cursor', input.cursor)\n if (input?.scopeType !== undefined) params.set('scopeType', input.scopeType)\n if (input?.scopeId !== undefined) params.set('scopeId', input.scopeId)\n if (input?.containerTag !== undefined) params.set('containerTag', input.containerTag)\n const qs = params.toString()\n return this.#request<PaginatedMemories>('GET', `/v1/memories${qs ? `?${qs}` : ''}`)\n }\n\n /** Echoed back for debugging — never sent to the wire. */\n get defaultContainerTag(): string | undefined {\n return this.#defaultContainerTag\n }\n\n async #request<T>(method: string, path: string, body?: unknown): Promise<T> {\n const serializedBody = body === undefined ? undefined : JSON.stringify(body)\n let lastErr: unknown\n for (let attempt = 0; attempt <= this.#maxRetries; attempt++) {\n const ctrl = new AbortController()\n const timer = setTimeout(() => ctrl.abort(), this.#timeoutMs)\n try {\n const res = await this.#fetch(`${this.#baseUrl}${path}`, {\n method,\n headers: { ...this.#headers },\n body: serializedBody,\n signal: ctrl.signal,\n })\n if (isRetryableStatus(res.status) && attempt < this.#maxRetries) {\n // Capture Retry-After before draining; some runtimes invalidate\n // headers once the body is consumed.\n const wait = delayForResponse(res, attempt)\n // Drain body so the underlying connection can be reused.\n await res.text().catch(() => undefined)\n await sleep(wait)\n continue\n }\n const text = await res.text()\n const parsed: unknown = text ? safeJson(text) : undefined\n if (!res.ok) {\n const message =\n (parsed && typeof parsed === 'object' && 'message' in parsed\n ? String((parsed as { message: unknown }).message)\n : null) ?? `HTTP ${res.status} ${res.statusText}`\n throw new MnemoHTTPError(message, res.status, parsed)\n }\n return parsed as T\n } catch (err) {\n if (err instanceof Error && err.name === 'AbortError') {\n throw new MnemoTimeoutError(this.#timeoutMs)\n }\n if (err instanceof MnemoHTTPError) throw err\n lastErr = err\n if (attempt < this.#maxRetries) {\n await sleep(retryDelayMs(attempt))\n continue\n }\n throw err\n } finally {\n clearTimeout(timer)\n }\n }\n throw lastErr ?? new Error('Mnemo: request failed')\n }\n}\n\nfunction safeJson(s: string): unknown {\n try {\n return JSON.parse(s)\n } catch {\n return s\n }\n}\n"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,46 +1,116 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Public types for the Mnemo SDK.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* Request types are derived from the OpenAPI spec at
|
|
5
|
+
* `https://api.mnemohq.com/openapi.json` ("Mnemo API" v0.2.0).
|
|
6
|
+
*
|
|
7
|
+
* Response types are confirmed against real prod payloads captured 2026-06-16
|
|
8
|
+
* (the spec does NOT annotate response schemas — every memories/search op
|
|
9
|
+
* returns `{}` — so these shapes were finalized from live responses).
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Structured container scope. The alternative to the `containerTag` string —
|
|
13
|
+
* e.g. `{ type: 'user', id: 'jane' }` is equivalent to `containerTag: 'user:jane'`.
|
|
14
|
+
*/
|
|
15
|
+
type Scope = {
|
|
16
|
+
type: string;
|
|
17
|
+
id: string;
|
|
18
|
+
};
|
|
19
|
+
/** The container a memory belongs to. */
|
|
20
|
+
type Container = {
|
|
21
|
+
id: string;
|
|
22
|
+
tag: string;
|
|
23
|
+
containerType: string;
|
|
24
|
+
displayName: string;
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* A single memory as returned by `get`/`update`, and the per-item shape inside
|
|
28
|
+
* `list` and `add` responses.
|
|
7
29
|
*/
|
|
8
30
|
type Memory = {
|
|
9
31
|
id: string;
|
|
32
|
+
scope: Scope;
|
|
33
|
+
scopeKey: string;
|
|
34
|
+
container: Container;
|
|
10
35
|
content: string;
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
36
|
+
contentHash: string;
|
|
37
|
+
idempotencyKey: string | null;
|
|
38
|
+
memoryType: string;
|
|
39
|
+
metadata: Record<string, unknown> | null;
|
|
40
|
+
source: unknown | null;
|
|
41
|
+
sourceDocumentId: string | null;
|
|
42
|
+
eventId: string | null;
|
|
43
|
+
deletedAt: string | null;
|
|
14
44
|
createdAt: string;
|
|
15
45
|
updatedAt: string;
|
|
16
46
|
};
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
47
|
+
/**
|
|
48
|
+
* One stored item in an `add` response. Same fields as a `Memory`.
|
|
49
|
+
*/
|
|
50
|
+
type AddedItem = Memory;
|
|
51
|
+
/** Response shape of `add()`. */
|
|
52
|
+
type AddResponse = {
|
|
53
|
+
scopeKey: string;
|
|
54
|
+
scope: Scope;
|
|
55
|
+
items: AddedItem[];
|
|
20
56
|
};
|
|
57
|
+
/** One retrieval hit in a `search` response. */
|
|
21
58
|
type SearchHit = {
|
|
59
|
+
resultType: string;
|
|
22
60
|
memoryId: string;
|
|
61
|
+
scopeKey: string;
|
|
23
62
|
content: string;
|
|
63
|
+
metadata: Record<string, unknown> | null;
|
|
64
|
+
memoryType: string;
|
|
65
|
+
polarity: string;
|
|
24
66
|
score: number;
|
|
25
|
-
|
|
26
|
-
|
|
67
|
+
createdAt: string;
|
|
68
|
+
updatedAt: string;
|
|
27
69
|
};
|
|
70
|
+
/** Per-stage timing breakdown returned by `search`. */
|
|
71
|
+
type SearchLatency = {
|
|
72
|
+
parallelMs: number;
|
|
73
|
+
strategyMs: number;
|
|
74
|
+
fusionMs: number;
|
|
75
|
+
rerankerMs: number;
|
|
76
|
+
totalMs: number;
|
|
77
|
+
};
|
|
78
|
+
/**
|
|
79
|
+
* Response shape of `search()`. The primary results live in `results`; the
|
|
80
|
+
* `positivePreferences` and `hardConstraints` arrays carry the same `SearchHit`
|
|
81
|
+
* shape, alongside retrieval metadata.
|
|
82
|
+
*/
|
|
28
83
|
type SearchResponse = {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
84
|
+
results: SearchHit[];
|
|
85
|
+
positivePreferences: SearchHit[];
|
|
86
|
+
hardConstraints: SearchHit[];
|
|
87
|
+
searchMode: string;
|
|
88
|
+
queryIntent: string;
|
|
89
|
+
queryIntentConfidence: number;
|
|
90
|
+
abstained: boolean;
|
|
91
|
+
reranked: boolean;
|
|
92
|
+
rawBestVectorSim: number;
|
|
93
|
+
latency: SearchLatency;
|
|
32
94
|
};
|
|
95
|
+
/** Cursor-paginated list of memories. */
|
|
33
96
|
type PaginatedMemories = {
|
|
34
97
|
items: Memory[];
|
|
35
98
|
nextCursor: string | null;
|
|
36
99
|
};
|
|
37
100
|
type ClientConfig = {
|
|
38
|
-
/**
|
|
101
|
+
/**
|
|
102
|
+
* Required. Full-access by default — keep server-side. For client-exposed
|
|
103
|
+
* contexts, mint a scoped read-only key. Get one at
|
|
104
|
+
* https://app.mnemohq.com/settings/api-keys.
|
|
105
|
+
*/
|
|
39
106
|
apiKey: string;
|
|
40
|
-
/** Required. Workspace ID
|
|
107
|
+
/** Required. Workspace ID — sent as the `x-workspace-id` header on every call. */
|
|
41
108
|
workspaceId: string;
|
|
42
|
-
/**
|
|
43
|
-
|
|
109
|
+
/**
|
|
110
|
+
* Optional default container tag (e.g. `"user:jane"`). When set, `add` and
|
|
111
|
+
* `search` fall back to it if no per-call `containerTag`/`scope` is given.
|
|
112
|
+
*/
|
|
113
|
+
defaultContainerTag?: string;
|
|
44
114
|
/** Defaults to https://api.mnemohq.com. */
|
|
45
115
|
baseUrl?: string;
|
|
46
116
|
/** Per-request timeout in ms (default 30s). */
|
|
@@ -66,37 +136,69 @@ type ClientConfig = {
|
|
|
66
136
|
* workspaceId: process.env.GETMNEMO_WORKSPACE_ID!,
|
|
67
137
|
* })
|
|
68
138
|
*
|
|
69
|
-
* await memory.add({ content: 'User prefers Japanese rice.' })
|
|
70
|
-
* const {
|
|
139
|
+
* await memory.add({ content: 'User prefers Japanese rice.', containerTag: 'user:jane' })
|
|
140
|
+
* const { results } = await memory.search({ q: 'what rice does the user like?', containerTag: 'user:jane' })
|
|
71
141
|
* ```
|
|
72
142
|
*/
|
|
73
143
|
|
|
74
144
|
declare class Mnemo {
|
|
75
145
|
#private;
|
|
76
146
|
constructor(cfg: ClientConfig);
|
|
147
|
+
/**
|
|
148
|
+
* Hybrid retrieval. Requires a container — pass `containerTag` (e.g.
|
|
149
|
+
* `"user:jane"`) or `scope`, or set `defaultContainerTag` on the client.
|
|
150
|
+
*
|
|
151
|
+
* Sends `POST /v1/search` with body `{ q, limit, containerTag|scope }`.
|
|
152
|
+
*/
|
|
77
153
|
search(input: {
|
|
78
|
-
|
|
154
|
+
q: string;
|
|
155
|
+
containerTag?: string;
|
|
156
|
+
scope?: Scope;
|
|
79
157
|
limit?: number;
|
|
80
|
-
|
|
158
|
+
searchMode?: string;
|
|
81
159
|
}): Promise<SearchResponse>;
|
|
160
|
+
/**
|
|
161
|
+
* Store an atomic fact. Requires a container — pass `containerTag` (e.g.
|
|
162
|
+
* `"user:jane"`) or `scope`, or set `defaultContainerTag` on the client.
|
|
163
|
+
*
|
|
164
|
+
* Sends `POST /v1/memories` with body
|
|
165
|
+
* `{ items: [{ content, metadata? }], containerTag|scope }`.
|
|
166
|
+
*/
|
|
82
167
|
add(input: {
|
|
83
168
|
content: string;
|
|
169
|
+
containerTag?: string;
|
|
170
|
+
scope?: Scope;
|
|
84
171
|
metadata?: Record<string, unknown>;
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
172
|
+
}): Promise<AddResponse>;
|
|
173
|
+
/**
|
|
174
|
+
* Patch an existing memory by id.
|
|
175
|
+
* Sends `PATCH /v1/memories/{memoryId}` with body `UpdateMemoryDto`
|
|
176
|
+
* `{ content?, memoryType?, metadata?, source? }` (none required).
|
|
177
|
+
*/
|
|
178
|
+
update(memoryId: string, input: {
|
|
88
179
|
content?: string;
|
|
180
|
+
memoryType?: string;
|
|
89
181
|
metadata?: Record<string, unknown>;
|
|
182
|
+
source?: string;
|
|
90
183
|
}): Promise<Memory>;
|
|
91
|
-
|
|
92
|
-
|
|
184
|
+
/** Fetch a single memory by id. Sends `GET /v1/memories/{memoryId}`. */
|
|
185
|
+
get(memoryId: string): Promise<Memory>;
|
|
186
|
+
/** Remove a memory by id. Sends `DELETE /v1/memories/{memoryId}`. */
|
|
187
|
+
delete(memoryId: string): Promise<void>;
|
|
188
|
+
/**
|
|
189
|
+
* Cursor-paginated list of memories, optionally filtered by container.
|
|
190
|
+
* Sends `GET /v1/memories` with query
|
|
191
|
+
* `limit?, cursor?, scopeType?, scopeId?, containerTag?`.
|
|
192
|
+
*/
|
|
93
193
|
list(input?: {
|
|
194
|
+
containerTag?: string;
|
|
94
195
|
limit?: number;
|
|
95
196
|
cursor?: string;
|
|
96
|
-
|
|
197
|
+
scopeType?: string;
|
|
198
|
+
scopeId?: string;
|
|
97
199
|
}): Promise<PaginatedMemories>;
|
|
98
200
|
/** Echoed back for debugging — never sent to the wire. */
|
|
99
|
-
get
|
|
201
|
+
get defaultContainerTag(): string | undefined;
|
|
100
202
|
}
|
|
101
203
|
|
|
102
204
|
declare class MnemoError extends Error {
|
|
@@ -111,4 +213,4 @@ declare class MnemoTimeoutError extends MnemoError {
|
|
|
111
213
|
constructor(timeoutMs: number);
|
|
112
214
|
}
|
|
113
215
|
|
|
114
|
-
export { type ClientConfig, type Memory, Mnemo, MnemoError, MnemoHTTPError, MnemoTimeoutError, type PaginatedMemories, type
|
|
216
|
+
export { type AddResponse, type AddedItem, type ClientConfig, type Container, type Memory, Mnemo, MnemoError, MnemoHTTPError, MnemoTimeoutError, type PaginatedMemories, type Scope, type SearchHit, type SearchResponse };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,46 +1,116 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Public types for the Mnemo SDK.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* Request types are derived from the OpenAPI spec at
|
|
5
|
+
* `https://api.mnemohq.com/openapi.json` ("Mnemo API" v0.2.0).
|
|
6
|
+
*
|
|
7
|
+
* Response types are confirmed against real prod payloads captured 2026-06-16
|
|
8
|
+
* (the spec does NOT annotate response schemas — every memories/search op
|
|
9
|
+
* returns `{}` — so these shapes were finalized from live responses).
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Structured container scope. The alternative to the `containerTag` string —
|
|
13
|
+
* e.g. `{ type: 'user', id: 'jane' }` is equivalent to `containerTag: 'user:jane'`.
|
|
14
|
+
*/
|
|
15
|
+
type Scope = {
|
|
16
|
+
type: string;
|
|
17
|
+
id: string;
|
|
18
|
+
};
|
|
19
|
+
/** The container a memory belongs to. */
|
|
20
|
+
type Container = {
|
|
21
|
+
id: string;
|
|
22
|
+
tag: string;
|
|
23
|
+
containerType: string;
|
|
24
|
+
displayName: string;
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* A single memory as returned by `get`/`update`, and the per-item shape inside
|
|
28
|
+
* `list` and `add` responses.
|
|
7
29
|
*/
|
|
8
30
|
type Memory = {
|
|
9
31
|
id: string;
|
|
32
|
+
scope: Scope;
|
|
33
|
+
scopeKey: string;
|
|
34
|
+
container: Container;
|
|
10
35
|
content: string;
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
36
|
+
contentHash: string;
|
|
37
|
+
idempotencyKey: string | null;
|
|
38
|
+
memoryType: string;
|
|
39
|
+
metadata: Record<string, unknown> | null;
|
|
40
|
+
source: unknown | null;
|
|
41
|
+
sourceDocumentId: string | null;
|
|
42
|
+
eventId: string | null;
|
|
43
|
+
deletedAt: string | null;
|
|
14
44
|
createdAt: string;
|
|
15
45
|
updatedAt: string;
|
|
16
46
|
};
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
47
|
+
/**
|
|
48
|
+
* One stored item in an `add` response. Same fields as a `Memory`.
|
|
49
|
+
*/
|
|
50
|
+
type AddedItem = Memory;
|
|
51
|
+
/** Response shape of `add()`. */
|
|
52
|
+
type AddResponse = {
|
|
53
|
+
scopeKey: string;
|
|
54
|
+
scope: Scope;
|
|
55
|
+
items: AddedItem[];
|
|
20
56
|
};
|
|
57
|
+
/** One retrieval hit in a `search` response. */
|
|
21
58
|
type SearchHit = {
|
|
59
|
+
resultType: string;
|
|
22
60
|
memoryId: string;
|
|
61
|
+
scopeKey: string;
|
|
23
62
|
content: string;
|
|
63
|
+
metadata: Record<string, unknown> | null;
|
|
64
|
+
memoryType: string;
|
|
65
|
+
polarity: string;
|
|
24
66
|
score: number;
|
|
25
|
-
|
|
26
|
-
|
|
67
|
+
createdAt: string;
|
|
68
|
+
updatedAt: string;
|
|
27
69
|
};
|
|
70
|
+
/** Per-stage timing breakdown returned by `search`. */
|
|
71
|
+
type SearchLatency = {
|
|
72
|
+
parallelMs: number;
|
|
73
|
+
strategyMs: number;
|
|
74
|
+
fusionMs: number;
|
|
75
|
+
rerankerMs: number;
|
|
76
|
+
totalMs: number;
|
|
77
|
+
};
|
|
78
|
+
/**
|
|
79
|
+
* Response shape of `search()`. The primary results live in `results`; the
|
|
80
|
+
* `positivePreferences` and `hardConstraints` arrays carry the same `SearchHit`
|
|
81
|
+
* shape, alongside retrieval metadata.
|
|
82
|
+
*/
|
|
28
83
|
type SearchResponse = {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
84
|
+
results: SearchHit[];
|
|
85
|
+
positivePreferences: SearchHit[];
|
|
86
|
+
hardConstraints: SearchHit[];
|
|
87
|
+
searchMode: string;
|
|
88
|
+
queryIntent: string;
|
|
89
|
+
queryIntentConfidence: number;
|
|
90
|
+
abstained: boolean;
|
|
91
|
+
reranked: boolean;
|
|
92
|
+
rawBestVectorSim: number;
|
|
93
|
+
latency: SearchLatency;
|
|
32
94
|
};
|
|
95
|
+
/** Cursor-paginated list of memories. */
|
|
33
96
|
type PaginatedMemories = {
|
|
34
97
|
items: Memory[];
|
|
35
98
|
nextCursor: string | null;
|
|
36
99
|
};
|
|
37
100
|
type ClientConfig = {
|
|
38
|
-
/**
|
|
101
|
+
/**
|
|
102
|
+
* Required. Full-access by default — keep server-side. For client-exposed
|
|
103
|
+
* contexts, mint a scoped read-only key. Get one at
|
|
104
|
+
* https://app.mnemohq.com/settings/api-keys.
|
|
105
|
+
*/
|
|
39
106
|
apiKey: string;
|
|
40
|
-
/** Required. Workspace ID
|
|
107
|
+
/** Required. Workspace ID — sent as the `x-workspace-id` header on every call. */
|
|
41
108
|
workspaceId: string;
|
|
42
|
-
/**
|
|
43
|
-
|
|
109
|
+
/**
|
|
110
|
+
* Optional default container tag (e.g. `"user:jane"`). When set, `add` and
|
|
111
|
+
* `search` fall back to it if no per-call `containerTag`/`scope` is given.
|
|
112
|
+
*/
|
|
113
|
+
defaultContainerTag?: string;
|
|
44
114
|
/** Defaults to https://api.mnemohq.com. */
|
|
45
115
|
baseUrl?: string;
|
|
46
116
|
/** Per-request timeout in ms (default 30s). */
|
|
@@ -66,37 +136,69 @@ type ClientConfig = {
|
|
|
66
136
|
* workspaceId: process.env.GETMNEMO_WORKSPACE_ID!,
|
|
67
137
|
* })
|
|
68
138
|
*
|
|
69
|
-
* await memory.add({ content: 'User prefers Japanese rice.' })
|
|
70
|
-
* const {
|
|
139
|
+
* await memory.add({ content: 'User prefers Japanese rice.', containerTag: 'user:jane' })
|
|
140
|
+
* const { results } = await memory.search({ q: 'what rice does the user like?', containerTag: 'user:jane' })
|
|
71
141
|
* ```
|
|
72
142
|
*/
|
|
73
143
|
|
|
74
144
|
declare class Mnemo {
|
|
75
145
|
#private;
|
|
76
146
|
constructor(cfg: ClientConfig);
|
|
147
|
+
/**
|
|
148
|
+
* Hybrid retrieval. Requires a container — pass `containerTag` (e.g.
|
|
149
|
+
* `"user:jane"`) or `scope`, or set `defaultContainerTag` on the client.
|
|
150
|
+
*
|
|
151
|
+
* Sends `POST /v1/search` with body `{ q, limit, containerTag|scope }`.
|
|
152
|
+
*/
|
|
77
153
|
search(input: {
|
|
78
|
-
|
|
154
|
+
q: string;
|
|
155
|
+
containerTag?: string;
|
|
156
|
+
scope?: Scope;
|
|
79
157
|
limit?: number;
|
|
80
|
-
|
|
158
|
+
searchMode?: string;
|
|
81
159
|
}): Promise<SearchResponse>;
|
|
160
|
+
/**
|
|
161
|
+
* Store an atomic fact. Requires a container — pass `containerTag` (e.g.
|
|
162
|
+
* `"user:jane"`) or `scope`, or set `defaultContainerTag` on the client.
|
|
163
|
+
*
|
|
164
|
+
* Sends `POST /v1/memories` with body
|
|
165
|
+
* `{ items: [{ content, metadata? }], containerTag|scope }`.
|
|
166
|
+
*/
|
|
82
167
|
add(input: {
|
|
83
168
|
content: string;
|
|
169
|
+
containerTag?: string;
|
|
170
|
+
scope?: Scope;
|
|
84
171
|
metadata?: Record<string, unknown>;
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
172
|
+
}): Promise<AddResponse>;
|
|
173
|
+
/**
|
|
174
|
+
* Patch an existing memory by id.
|
|
175
|
+
* Sends `PATCH /v1/memories/{memoryId}` with body `UpdateMemoryDto`
|
|
176
|
+
* `{ content?, memoryType?, metadata?, source? }` (none required).
|
|
177
|
+
*/
|
|
178
|
+
update(memoryId: string, input: {
|
|
88
179
|
content?: string;
|
|
180
|
+
memoryType?: string;
|
|
89
181
|
metadata?: Record<string, unknown>;
|
|
182
|
+
source?: string;
|
|
90
183
|
}): Promise<Memory>;
|
|
91
|
-
|
|
92
|
-
|
|
184
|
+
/** Fetch a single memory by id. Sends `GET /v1/memories/{memoryId}`. */
|
|
185
|
+
get(memoryId: string): Promise<Memory>;
|
|
186
|
+
/** Remove a memory by id. Sends `DELETE /v1/memories/{memoryId}`. */
|
|
187
|
+
delete(memoryId: string): Promise<void>;
|
|
188
|
+
/**
|
|
189
|
+
* Cursor-paginated list of memories, optionally filtered by container.
|
|
190
|
+
* Sends `GET /v1/memories` with query
|
|
191
|
+
* `limit?, cursor?, scopeType?, scopeId?, containerTag?`.
|
|
192
|
+
*/
|
|
93
193
|
list(input?: {
|
|
194
|
+
containerTag?: string;
|
|
94
195
|
limit?: number;
|
|
95
196
|
cursor?: string;
|
|
96
|
-
|
|
197
|
+
scopeType?: string;
|
|
198
|
+
scopeId?: string;
|
|
97
199
|
}): Promise<PaginatedMemories>;
|
|
98
200
|
/** Echoed back for debugging — never sent to the wire. */
|
|
99
|
-
get
|
|
201
|
+
get defaultContainerTag(): string | undefined;
|
|
100
202
|
}
|
|
101
203
|
|
|
102
204
|
declare class MnemoError extends Error {
|
|
@@ -111,4 +213,4 @@ declare class MnemoTimeoutError extends MnemoError {
|
|
|
111
213
|
constructor(timeoutMs: number);
|
|
112
214
|
}
|
|
113
215
|
|
|
114
|
-
export { type ClientConfig, type Memory, Mnemo, MnemoError, MnemoHTTPError, MnemoTimeoutError, type PaginatedMemories, type
|
|
216
|
+
export { type AddResponse, type AddedItem, type ClientConfig, type Container, type Memory, Mnemo, MnemoError, MnemoHTTPError, MnemoTimeoutError, type PaginatedMemories, type Scope, type SearchHit, type SearchResponse };
|
package/dist/index.js
CHANGED
|
@@ -28,7 +28,8 @@ var MnemoTimeoutError = class extends MnemoError {
|
|
|
28
28
|
// src/client.ts
|
|
29
29
|
var DEFAULT_BASE_URL = "https://api.mnemohq.com";
|
|
30
30
|
var DEFAULT_TIMEOUT_MS = 3e4;
|
|
31
|
-
var SDK_VERSION = "0.
|
|
31
|
+
var SDK_VERSION = "0.2.0";
|
|
32
|
+
var DEFAULT_SEARCH_LIMIT = 8;
|
|
32
33
|
var USER_AGENT = `getmnemo/${SDK_VERSION}`;
|
|
33
34
|
var DEFAULT_MAX_RETRIES = 3;
|
|
34
35
|
var RETRY_BASE_DELAY_MS = 200;
|
|
@@ -71,7 +72,7 @@ var Mnemo = class {
|
|
|
71
72
|
#fetch;
|
|
72
73
|
#timeoutMs;
|
|
73
74
|
#maxRetries;
|
|
74
|
-
#
|
|
75
|
+
#defaultContainerTag;
|
|
75
76
|
constructor(cfg) {
|
|
76
77
|
if (!cfg.apiKey) throw new Error("Mnemo: apiKey is required");
|
|
77
78
|
if (!cfg.workspaceId) throw new Error("Mnemo: workspaceId is required");
|
|
@@ -86,49 +87,104 @@ var Mnemo = class {
|
|
|
86
87
|
} else {
|
|
87
88
|
this.#headers["user-agent"] = USER_AGENT;
|
|
88
89
|
}
|
|
89
|
-
|
|
90
|
-
this.#defaultActorId = cfg.actorId;
|
|
90
|
+
this.#defaultContainerTag = cfg.defaultContainerTag;
|
|
91
91
|
this.#fetch = cfg.fetch ?? fetch;
|
|
92
92
|
this.#timeoutMs = cfg.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
93
93
|
this.#maxRetries = Math.max(0, cfg.maxRetries ?? DEFAULT_MAX_RETRIES);
|
|
94
94
|
}
|
|
95
|
+
/**
|
|
96
|
+
* Resolve the container for a call into the request fields the API expects.
|
|
97
|
+
* A structured `scope` wins over a `containerTag` string; both fall back to
|
|
98
|
+
* the constructor's `defaultContainerTag`. Throws if none is available.
|
|
99
|
+
*/
|
|
100
|
+
#resolveContainer(method, input) {
|
|
101
|
+
if (input.scope) return { scope: input.scope };
|
|
102
|
+
const tag = input.containerTag ?? this.#defaultContainerTag;
|
|
103
|
+
if (tag) return { containerTag: tag };
|
|
104
|
+
throw new Error(
|
|
105
|
+
`Mnemo.${method}: a container is required \u2014 pass containerTag (e.g. "user:jane") or scope ({ type, id }) per call, or set defaultContainerTag on the client.`
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Hybrid retrieval. Requires a container — pass `containerTag` (e.g.
|
|
110
|
+
* `"user:jane"`) or `scope`, or set `defaultContainerTag` on the client.
|
|
111
|
+
*
|
|
112
|
+
* Sends `POST /v1/search` with body `{ q, limit, containerTag|scope }`.
|
|
113
|
+
*/
|
|
95
114
|
async search(input) {
|
|
115
|
+
const container = this.#resolveContainer("search", input);
|
|
96
116
|
return this.#request("POST", "/v1/search", {
|
|
97
|
-
|
|
98
|
-
limit: input.limit ??
|
|
99
|
-
...input.
|
|
117
|
+
q: input.q,
|
|
118
|
+
limit: input.limit ?? DEFAULT_SEARCH_LIMIT,
|
|
119
|
+
...input.searchMode !== void 0 ? { searchMode: input.searchMode } : {},
|
|
120
|
+
...container
|
|
100
121
|
});
|
|
101
122
|
}
|
|
123
|
+
/**
|
|
124
|
+
* Store an atomic fact. Requires a container — pass `containerTag` (e.g.
|
|
125
|
+
* `"user:jane"`) or `scope`, or set `defaultContainerTag` on the client.
|
|
126
|
+
*
|
|
127
|
+
* Sends `POST /v1/memories` with body
|
|
128
|
+
* `{ items: [{ content, metadata? }], containerTag|scope }`.
|
|
129
|
+
*/
|
|
102
130
|
async add(input) {
|
|
131
|
+
const container = this.#resolveContainer("add", input);
|
|
103
132
|
return this.#request("POST", "/v1/memories", {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
133
|
+
items: [
|
|
134
|
+
{
|
|
135
|
+
content: input.content,
|
|
136
|
+
...input.metadata !== void 0 ? { metadata: input.metadata } : {}
|
|
137
|
+
}
|
|
138
|
+
],
|
|
139
|
+
...container
|
|
107
140
|
});
|
|
108
141
|
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
142
|
+
/**
|
|
143
|
+
* Patch an existing memory by id.
|
|
144
|
+
* Sends `PATCH /v1/memories/{memoryId}` with body `UpdateMemoryDto`
|
|
145
|
+
* `{ content?, memoryType?, metadata?, source? }` (none required).
|
|
146
|
+
*/
|
|
147
|
+
async update(memoryId, input) {
|
|
148
|
+
if (input.content === void 0 && input.memoryType === void 0 && input.metadata === void 0 && input.source === void 0) {
|
|
149
|
+
throw new Error(
|
|
150
|
+
"Mnemo.update: at least one of content/memoryType/metadata/source must be provided"
|
|
151
|
+
);
|
|
112
152
|
}
|
|
113
|
-
return this.#request(
|
|
153
|
+
return this.#request(
|
|
154
|
+
"PATCH",
|
|
155
|
+
`/v1/memories/${encodeURIComponent(memoryId)}`,
|
|
156
|
+
input
|
|
157
|
+
);
|
|
114
158
|
}
|
|
115
|
-
|
|
116
|
-
|
|
159
|
+
/** Fetch a single memory by id. Sends `GET /v1/memories/{memoryId}`. */
|
|
160
|
+
async get(memoryId) {
|
|
161
|
+
return this.#request("GET", `/v1/memories/${encodeURIComponent(memoryId)}`);
|
|
117
162
|
}
|
|
118
|
-
|
|
119
|
-
|
|
163
|
+
/** Remove a memory by id. Sends `DELETE /v1/memories/{memoryId}`. */
|
|
164
|
+
async delete(memoryId) {
|
|
165
|
+
await this.#request(
|
|
166
|
+
"DELETE",
|
|
167
|
+
`/v1/memories/${encodeURIComponent(memoryId)}`
|
|
168
|
+
);
|
|
120
169
|
}
|
|
170
|
+
/**
|
|
171
|
+
* Cursor-paginated list of memories, optionally filtered by container.
|
|
172
|
+
* Sends `GET /v1/memories` with query
|
|
173
|
+
* `limit?, cursor?, scopeType?, scopeId?, containerTag?`.
|
|
174
|
+
*/
|
|
121
175
|
async list(input) {
|
|
122
176
|
const params = new URLSearchParams();
|
|
123
177
|
if (input?.limit !== void 0) params.set("limit", String(input.limit));
|
|
124
178
|
if (input?.cursor !== void 0) params.set("cursor", input.cursor);
|
|
125
|
-
if (input?.
|
|
179
|
+
if (input?.scopeType !== void 0) params.set("scopeType", input.scopeType);
|
|
180
|
+
if (input?.scopeId !== void 0) params.set("scopeId", input.scopeId);
|
|
181
|
+
if (input?.containerTag !== void 0) params.set("containerTag", input.containerTag);
|
|
126
182
|
const qs = params.toString();
|
|
127
183
|
return this.#request("GET", `/v1/memories${qs ? `?${qs}` : ""}`);
|
|
128
184
|
}
|
|
129
185
|
/** Echoed back for debugging — never sent to the wire. */
|
|
130
|
-
get
|
|
131
|
-
return this.#
|
|
186
|
+
get defaultContainerTag() {
|
|
187
|
+
return this.#defaultContainerTag;
|
|
132
188
|
}
|
|
133
189
|
async #request(method, path, body) {
|
|
134
190
|
const serializedBody = body === void 0 ? void 0 : JSON.stringify(body);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/errors.ts","../src/client.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["export class MnemoError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'MnemoError'\n Object.setPrototypeOf(this, new.target.prototype)\n }\n}\n\nexport class MnemoHTTPError extends MnemoError {\n constructor(\n message: string,\n readonly status: number,\n readonly body?: unknown,\n ) {\n super(`[${status}] ${message}`)\n this.name = 'MnemoHTTPError'\n Object.setPrototypeOf(this, new.target.prototype)\n }\n}\n\nexport class MnemoTimeoutError extends MnemoError {\n constructor(timeoutMs: number) {\n super(`Request timed out after ${timeoutMs}ms`)\n this.name = 'MnemoTimeoutError'\n Object.setPrototypeOf(this, new.target.prototype)\n }\n}\n","/**\n * Mnemo Memory client.\n *\n * Zero runtime dependencies — uses the global `fetch` (Node 18+, Bun, browsers,\n * Cloudflare Workers, Deno, etc).\n *\n * @example\n * ```ts\n * import { Mnemo } from 'getmnemo'\n *\n * const memory = new Mnemo({\n * apiKey: process.env.GETMNEMO_API_KEY!,\n * workspaceId: process.env.GETMNEMO_WORKSPACE_ID!,\n * })\n *\n * await memory.add({ content: 'User prefers Japanese rice.' })\n * const { hits } = await memory.search({ query: 'what rice does the user like?' })\n * ```\n */\n\nimport { MnemoHTTPError, MnemoTimeoutError } from './errors.js'\nimport type {\n ClientConfig,\n Memory,\n PaginatedMemories,\n SearchResponse,\n} from './types.js'\n\nconst DEFAULT_BASE_URL = 'https://api.mnemohq.com'\nconst DEFAULT_TIMEOUT_MS = 30_000\nconst SDK_VERSION = '0.1.0'\nconst USER_AGENT = `getmnemo/${SDK_VERSION}`\nconst DEFAULT_MAX_RETRIES = 3\nconst RETRY_BASE_DELAY_MS = 200\nconst RETRY_MAX_DELAY_MS = 5_000\n\n// Browsers reject `user-agent` as a forbidden header — setting it via fetch\n// throws or warns. Detect a browser-like environment so we can skip it there.\nconst IS_BROWSER_LIKE =\n typeof globalThis !== 'undefined' &&\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n typeof (globalThis as any).window !== 'undefined' &&\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n typeof (globalThis as any).document !== 'undefined'\n\nfunction retryDelayMs(attempt: number): number {\n const capped = Math.min(RETRY_BASE_DELAY_MS * 2 ** attempt, RETRY_MAX_DELAY_MS)\n // Full jitter.\n return Math.floor(Math.random() * capped)\n}\n\nfunction isRetryableStatus(status: number): boolean {\n // 501 Not Implemented is a permanent failure — retrying just wastes round-trips.\n if (status === 501) return false\n return status === 429 || (status >= 500 && status < 600)\n}\n\nfunction parseRetryAfterMs(headerValue: string | null): number | null {\n if (!headerValue) return null\n const trimmed = headerValue.trim()\n // Delta-seconds form.\n const seconds = Number(trimmed)\n if (Number.isFinite(seconds) && seconds >= 0) {\n return Math.min(seconds * 1000, RETRY_MAX_DELAY_MS)\n }\n // HTTP-date form.\n const epoch = Date.parse(trimmed)\n if (!Number.isNaN(epoch)) {\n const delta = epoch - Date.now()\n return Math.max(0, Math.min(delta, RETRY_MAX_DELAY_MS))\n }\n return null\n}\n\nfunction delayForResponse(res: Response, attempt: number): number {\n const hint = parseRetryAfterMs(res.headers.get('retry-after'))\n return hint !== null ? hint : retryDelayMs(attempt)\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms))\n}\n\nexport class Mnemo {\n readonly #baseUrl: string\n readonly #headers: Record<string, string>\n readonly #fetch: typeof fetch\n readonly #timeoutMs: number\n readonly #maxRetries: number\n readonly #defaultActorId: string | undefined\n\n constructor(cfg: ClientConfig) {\n if (!cfg.apiKey) throw new Error('Mnemo: apiKey is required')\n if (!cfg.workspaceId) throw new Error('Mnemo: workspaceId is required')\n this.#baseUrl = (cfg.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/$/, '')\n this.#headers = {\n authorization: `Bearer ${cfg.apiKey}`,\n 'x-workspace-id': cfg.workspaceId,\n 'content-type': 'application/json',\n }\n // `user-agent` is on the forbidden header list in browsers — setting it\n // via fetch is silently dropped or throws. Send `x-getmnemo-client` as\n // an SDK identifier in browsers, and the standard User-Agent on Node.\n if (IS_BROWSER_LIKE) {\n this.#headers['x-getmnemo-client'] = USER_AGENT\n } else {\n this.#headers['user-agent'] = USER_AGENT\n }\n if (cfg.actorId) this.#headers['x-actor-id'] = cfg.actorId\n this.#defaultActorId = cfg.actorId\n this.#fetch = cfg.fetch ?? fetch\n this.#timeoutMs = cfg.timeoutMs ?? DEFAULT_TIMEOUT_MS\n this.#maxRetries = Math.max(0, cfg.maxRetries ?? DEFAULT_MAX_RETRIES)\n }\n\n async search(input: {\n query: string\n limit?: number\n actorId?: string\n }): Promise<SearchResponse> {\n return this.#request<SearchResponse>('POST', '/v1/search', {\n query: input.query,\n limit: input.limit ?? 8,\n ...(input.actorId !== undefined ? { actorId: input.actorId } : {}),\n })\n }\n\n async add(input: {\n content: string\n metadata?: Record<string, unknown>\n actorId?: string\n }): Promise<Memory> {\n return this.#request<Memory>('POST', '/v1/memories', {\n content: input.content,\n ...(input.metadata !== undefined ? { metadata: input.metadata } : {}),\n ...(input.actorId !== undefined ? { actorId: input.actorId } : {}),\n })\n }\n\n async update(\n id: string,\n input: { content?: string; metadata?: Record<string, unknown> },\n ): Promise<Memory> {\n if (input.content === undefined && input.metadata === undefined) {\n throw new Error('Mnemo.update: at least one of content/metadata must be provided')\n }\n return this.#request<Memory>('PATCH', `/v1/memories/${encodeURIComponent(id)}`, input)\n }\n\n async get(id: string): Promise<Memory> {\n return this.#request<Memory>('GET', `/v1/memories/${encodeURIComponent(id)}`)\n }\n\n async delete(id: string): Promise<void> {\n await this.#request<unknown>('DELETE', `/v1/memories/${encodeURIComponent(id)}`)\n }\n\n async list(input?: {\n limit?: number\n cursor?: string\n actorId?: string\n }): Promise<PaginatedMemories> {\n const params = new URLSearchParams()\n if (input?.limit !== undefined) params.set('limit', String(input.limit))\n if (input?.cursor !== undefined) params.set('cursor', input.cursor)\n if (input?.actorId !== undefined) params.set('actorId', input.actorId)\n const qs = params.toString()\n return this.#request<PaginatedMemories>('GET', `/v1/memories${qs ? `?${qs}` : ''}`)\n }\n\n /** Echoed back for debugging — never sent to the wire. */\n get defaultActorId(): string | undefined {\n return this.#defaultActorId\n }\n\n async #request<T>(method: string, path: string, body?: unknown): Promise<T> {\n const serializedBody = body === undefined ? undefined : JSON.stringify(body)\n let lastErr: unknown\n for (let attempt = 0; attempt <= this.#maxRetries; attempt++) {\n const ctrl = new AbortController()\n const timer = setTimeout(() => ctrl.abort(), this.#timeoutMs)\n try {\n const res = await this.#fetch(`${this.#baseUrl}${path}`, {\n method,\n headers: { ...this.#headers },\n body: serializedBody,\n signal: ctrl.signal,\n })\n if (isRetryableStatus(res.status) && attempt < this.#maxRetries) {\n // Capture Retry-After before draining; some runtimes invalidate\n // headers once the body is consumed.\n const wait = delayForResponse(res, attempt)\n // Drain body so the underlying connection can be reused.\n await res.text().catch(() => undefined)\n await sleep(wait)\n continue\n }\n const text = await res.text()\n const parsed: unknown = text ? safeJson(text) : undefined\n if (!res.ok) {\n const message =\n (parsed && typeof parsed === 'object' && 'message' in parsed\n ? String((parsed as { message: unknown }).message)\n : null) ?? `HTTP ${res.status} ${res.statusText}`\n throw new MnemoHTTPError(message, res.status, parsed)\n }\n return parsed as T\n } catch (err) {\n if (err instanceof Error && err.name === 'AbortError') {\n throw new MnemoTimeoutError(this.#timeoutMs)\n }\n if (err instanceof MnemoHTTPError) throw err\n lastErr = err\n if (attempt < this.#maxRetries) {\n await sleep(retryDelayMs(attempt))\n continue\n }\n throw err\n } finally {\n clearTimeout(timer)\n }\n }\n throw lastErr ?? new Error('Mnemo: request failed')\n }\n}\n\nfunction safeJson(s: string): unknown {\n try {\n return JSON.parse(s)\n } catch {\n return s\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/client.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["export class MnemoError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'MnemoError'\n Object.setPrototypeOf(this, new.target.prototype)\n }\n}\n\nexport class MnemoHTTPError extends MnemoError {\n constructor(\n message: string,\n readonly status: number,\n readonly body?: unknown,\n ) {\n super(`[${status}] ${message}`)\n this.name = 'MnemoHTTPError'\n Object.setPrototypeOf(this, new.target.prototype)\n }\n}\n\nexport class MnemoTimeoutError extends MnemoError {\n constructor(timeoutMs: number) {\n super(`Request timed out after ${timeoutMs}ms`)\n this.name = 'MnemoTimeoutError'\n Object.setPrototypeOf(this, new.target.prototype)\n }\n}\n","/**\n * Mnemo Memory client.\n *\n * Zero runtime dependencies — uses the global `fetch` (Node 18+, Bun, browsers,\n * Cloudflare Workers, Deno, etc).\n *\n * @example\n * ```ts\n * import { Mnemo } from 'getmnemo'\n *\n * const memory = new Mnemo({\n * apiKey: process.env.GETMNEMO_API_KEY!,\n * workspaceId: process.env.GETMNEMO_WORKSPACE_ID!,\n * })\n *\n * await memory.add({ content: 'User prefers Japanese rice.', containerTag: 'user:jane' })\n * const { results } = await memory.search({ q: 'what rice does the user like?', containerTag: 'user:jane' })\n * ```\n */\n\nimport { MnemoHTTPError, MnemoTimeoutError } from './errors.js'\nimport type {\n AddResponse,\n ClientConfig,\n Memory,\n PaginatedMemories,\n Scope,\n SearchResponse,\n} from './types.js'\n\nconst DEFAULT_BASE_URL = 'https://api.mnemohq.com'\nconst DEFAULT_TIMEOUT_MS = 30_000\nconst SDK_VERSION = '0.2.0'\nconst DEFAULT_SEARCH_LIMIT = 8\nconst USER_AGENT = `getmnemo/${SDK_VERSION}`\nconst DEFAULT_MAX_RETRIES = 3\nconst RETRY_BASE_DELAY_MS = 200\nconst RETRY_MAX_DELAY_MS = 5_000\n\n// Browsers reject `user-agent` as a forbidden header — setting it via fetch\n// throws or warns. Detect a browser-like environment so we can skip it there.\nconst IS_BROWSER_LIKE =\n typeof globalThis !== 'undefined' &&\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n typeof (globalThis as any).window !== 'undefined' &&\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n typeof (globalThis as any).document !== 'undefined'\n\nfunction retryDelayMs(attempt: number): number {\n const capped = Math.min(RETRY_BASE_DELAY_MS * 2 ** attempt, RETRY_MAX_DELAY_MS)\n // Full jitter.\n return Math.floor(Math.random() * capped)\n}\n\nfunction isRetryableStatus(status: number): boolean {\n // 501 Not Implemented is a permanent failure — retrying just wastes round-trips.\n if (status === 501) return false\n return status === 429 || (status >= 500 && status < 600)\n}\n\nfunction parseRetryAfterMs(headerValue: string | null): number | null {\n if (!headerValue) return null\n const trimmed = headerValue.trim()\n // Delta-seconds form.\n const seconds = Number(trimmed)\n if (Number.isFinite(seconds) && seconds >= 0) {\n return Math.min(seconds * 1000, RETRY_MAX_DELAY_MS)\n }\n // HTTP-date form.\n const epoch = Date.parse(trimmed)\n if (!Number.isNaN(epoch)) {\n const delta = epoch - Date.now()\n return Math.max(0, Math.min(delta, RETRY_MAX_DELAY_MS))\n }\n return null\n}\n\nfunction delayForResponse(res: Response, attempt: number): number {\n const hint = parseRetryAfterMs(res.headers.get('retry-after'))\n return hint !== null ? hint : retryDelayMs(attempt)\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms))\n}\n\nexport class Mnemo {\n readonly #baseUrl: string\n readonly #headers: Record<string, string>\n readonly #fetch: typeof fetch\n readonly #timeoutMs: number\n readonly #maxRetries: number\n readonly #defaultContainerTag: string | undefined\n\n constructor(cfg: ClientConfig) {\n if (!cfg.apiKey) throw new Error('Mnemo: apiKey is required')\n if (!cfg.workspaceId) throw new Error('Mnemo: workspaceId is required')\n this.#baseUrl = (cfg.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/$/, '')\n this.#headers = {\n authorization: `Bearer ${cfg.apiKey}`,\n 'x-workspace-id': cfg.workspaceId,\n 'content-type': 'application/json',\n }\n // `user-agent` is on the forbidden header list in browsers — setting it\n // via fetch is silently dropped or throws. Send `x-getmnemo-client` as\n // an SDK identifier in browsers, and the standard User-Agent on Node.\n if (IS_BROWSER_LIKE) {\n this.#headers['x-getmnemo-client'] = USER_AGENT\n } else {\n this.#headers['user-agent'] = USER_AGENT\n }\n this.#defaultContainerTag = cfg.defaultContainerTag\n this.#fetch = cfg.fetch ?? fetch\n this.#timeoutMs = cfg.timeoutMs ?? DEFAULT_TIMEOUT_MS\n this.#maxRetries = Math.max(0, cfg.maxRetries ?? DEFAULT_MAX_RETRIES)\n }\n\n /**\n * Resolve the container for a call into the request fields the API expects.\n * A structured `scope` wins over a `containerTag` string; both fall back to\n * the constructor's `defaultContainerTag`. Throws if none is available.\n */\n #resolveContainer(\n method: 'add' | 'search',\n input: { containerTag?: string; scope?: Scope },\n ): { containerTag: string } | { scope: Scope } {\n if (input.scope) return { scope: input.scope }\n const tag = input.containerTag ?? this.#defaultContainerTag\n if (tag) return { containerTag: tag }\n throw new Error(\n `Mnemo.${method}: a container is required — pass containerTag (e.g. \"user:jane\") ` +\n 'or scope ({ type, id }) per call, or set defaultContainerTag on the client.',\n )\n }\n\n /**\n * Hybrid retrieval. Requires a container — pass `containerTag` (e.g.\n * `\"user:jane\"`) or `scope`, or set `defaultContainerTag` on the client.\n *\n * Sends `POST /v1/search` with body `{ q, limit, containerTag|scope }`.\n */\n async search(input: {\n q: string\n containerTag?: string\n scope?: Scope\n limit?: number\n searchMode?: string\n }): Promise<SearchResponse> {\n const container = this.#resolveContainer('search', input)\n return this.#request<SearchResponse>('POST', '/v1/search', {\n q: input.q,\n limit: input.limit ?? DEFAULT_SEARCH_LIMIT,\n ...(input.searchMode !== undefined ? { searchMode: input.searchMode } : {}),\n ...container,\n })\n }\n\n /**\n * Store an atomic fact. Requires a container — pass `containerTag` (e.g.\n * `\"user:jane\"`) or `scope`, or set `defaultContainerTag` on the client.\n *\n * Sends `POST /v1/memories` with body\n * `{ items: [{ content, metadata? }], containerTag|scope }`.\n */\n async add(input: {\n content: string\n containerTag?: string\n scope?: Scope\n metadata?: Record<string, unknown>\n }): Promise<AddResponse> {\n const container = this.#resolveContainer('add', input)\n return this.#request<AddResponse>('POST', '/v1/memories', {\n items: [\n {\n content: input.content,\n ...(input.metadata !== undefined ? { metadata: input.metadata } : {}),\n },\n ],\n ...container,\n })\n }\n\n /**\n * Patch an existing memory by id.\n * Sends `PATCH /v1/memories/{memoryId}` with body `UpdateMemoryDto`\n * `{ content?, memoryType?, metadata?, source? }` (none required).\n */\n async update(\n memoryId: string,\n input: {\n content?: string\n memoryType?: string\n metadata?: Record<string, unknown>\n source?: string\n },\n ): Promise<Memory> {\n if (\n input.content === undefined &&\n input.memoryType === undefined &&\n input.metadata === undefined &&\n input.source === undefined\n ) {\n throw new Error(\n 'Mnemo.update: at least one of content/memoryType/metadata/source must be provided',\n )\n }\n return this.#request<Memory>(\n 'PATCH',\n `/v1/memories/${encodeURIComponent(memoryId)}`,\n input,\n )\n }\n\n /** Fetch a single memory by id. Sends `GET /v1/memories/{memoryId}`. */\n async get(memoryId: string): Promise<Memory> {\n return this.#request<Memory>('GET', `/v1/memories/${encodeURIComponent(memoryId)}`)\n }\n\n /** Remove a memory by id. Sends `DELETE /v1/memories/{memoryId}`. */\n async delete(memoryId: string): Promise<void> {\n await this.#request<unknown>(\n 'DELETE',\n `/v1/memories/${encodeURIComponent(memoryId)}`,\n )\n }\n\n /**\n * Cursor-paginated list of memories, optionally filtered by container.\n * Sends `GET /v1/memories` with query\n * `limit?, cursor?, scopeType?, scopeId?, containerTag?`.\n */\n async list(input?: {\n containerTag?: string\n limit?: number\n cursor?: string\n scopeType?: string\n scopeId?: string\n }): Promise<PaginatedMemories> {\n const params = new URLSearchParams()\n if (input?.limit !== undefined) params.set('limit', String(input.limit))\n if (input?.cursor !== undefined) params.set('cursor', input.cursor)\n if (input?.scopeType !== undefined) params.set('scopeType', input.scopeType)\n if (input?.scopeId !== undefined) params.set('scopeId', input.scopeId)\n if (input?.containerTag !== undefined) params.set('containerTag', input.containerTag)\n const qs = params.toString()\n return this.#request<PaginatedMemories>('GET', `/v1/memories${qs ? `?${qs}` : ''}`)\n }\n\n /** Echoed back for debugging — never sent to the wire. */\n get defaultContainerTag(): string | undefined {\n return this.#defaultContainerTag\n }\n\n async #request<T>(method: string, path: string, body?: unknown): Promise<T> {\n const serializedBody = body === undefined ? undefined : JSON.stringify(body)\n let lastErr: unknown\n for (let attempt = 0; attempt <= this.#maxRetries; attempt++) {\n const ctrl = new AbortController()\n const timer = setTimeout(() => ctrl.abort(), this.#timeoutMs)\n try {\n const res = await this.#fetch(`${this.#baseUrl}${path}`, {\n method,\n headers: { ...this.#headers },\n body: serializedBody,\n signal: ctrl.signal,\n })\n if (isRetryableStatus(res.status) && attempt < this.#maxRetries) {\n // Capture Retry-After before draining; some runtimes invalidate\n // headers once the body is consumed.\n const wait = delayForResponse(res, attempt)\n // Drain body so the underlying connection can be reused.\n await res.text().catch(() => undefined)\n await sleep(wait)\n continue\n }\n const text = await res.text()\n const parsed: unknown = text ? safeJson(text) : undefined\n if (!res.ok) {\n const message =\n (parsed && typeof parsed === 'object' && 'message' in parsed\n ? String((parsed as { message: unknown }).message)\n : null) ?? `HTTP ${res.status} ${res.statusText}`\n throw new MnemoHTTPError(message, res.status, parsed)\n }\n return parsed as T\n } catch (err) {\n if (err instanceof Error && err.name === 'AbortError') {\n throw new MnemoTimeoutError(this.#timeoutMs)\n }\n if (err instanceof MnemoHTTPError) throw err\n lastErr = err\n if (attempt < this.#maxRetries) {\n await sleep(retryDelayMs(attempt))\n continue\n }\n throw err\n } finally {\n clearTimeout(timer)\n }\n }\n throw lastErr ?? new Error('Mnemo: request failed')\n }\n}\n\nfunction safeJson(s: string): unknown {\n try {\n return JSON.parse(s)\n } catch {\n return s\n }\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "getmnemo",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Official TypeScript / JavaScript SDK for Mnemo Memory — long-term memory infrastructure for AI agents.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -28,7 +28,8 @@
|
|
|
28
28
|
"lint": "eslint src",
|
|
29
29
|
"typecheck": "tsc --noEmit",
|
|
30
30
|
"test": "vitest run",
|
|
31
|
-
"test:watch": "vitest"
|
|
31
|
+
"test:watch": "vitest",
|
|
32
|
+
"smoke": "node scripts/prod-smoke.mjs"
|
|
32
33
|
},
|
|
33
34
|
"keywords": [
|
|
34
35
|
"mnemo",
|