@lumetra/engram 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/LICENSE +21 -0
- package/README.md +106 -0
- package/dist/index.cjs +171 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +122 -0
- package/dist/index.d.ts +122 -0
- package/dist/index.js +168 -0
- package/dist/index.js.map +1 -0
- package/package.json +61 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Lumetra
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# @lumetra/engram
|
|
2
|
+
|
|
3
|
+
Official TypeScript client for [Engram](https://lumetra.io) — durable, explainable memory for AI agents.
|
|
4
|
+
|
|
5
|
+
- Zero runtime dependencies (uses built-in `fetch`).
|
|
6
|
+
- ESM + CommonJS, full `.d.ts` typings.
|
|
7
|
+
- Node 18+, Bun, Deno, edge runtimes.
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install @lumetra/engram
|
|
13
|
+
# or
|
|
14
|
+
yarn add @lumetra/engram
|
|
15
|
+
# or
|
|
16
|
+
pnpm add @lumetra/engram
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Quickstart
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
import { EngramClient } from '@lumetra/engram';
|
|
23
|
+
|
|
24
|
+
const engram = new EngramClient({
|
|
25
|
+
apiKey: process.env.ENGRAM_API_KEY, // or set ENGRAM_API_KEY and omit
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
// Store a fact
|
|
29
|
+
await engram.storeMemory('User prefers dark mode.', 'user-123');
|
|
30
|
+
|
|
31
|
+
// Recall — returns a synthesized answer plus the memories that contributed
|
|
32
|
+
const result = await engram.query('What are this user\'s UI preferences?', {
|
|
33
|
+
buckets: ['user-123'],
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
console.log(result.answer);
|
|
37
|
+
console.log(result.explanation?.retrieved_memories);
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Configuration
|
|
41
|
+
|
|
42
|
+
```ts
|
|
43
|
+
new EngramClient({
|
|
44
|
+
apiKey: 'eng_live_...', // or ENGRAM_API_KEY env var
|
|
45
|
+
baseUrl: 'https://api.lumetra.io', // or ENGRAM_BASE_URL env var
|
|
46
|
+
timeoutMs: 30_000, // optional, default 30s
|
|
47
|
+
fetch: customFetch, // optional, defaults to globalThis.fetch
|
|
48
|
+
});
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
> **BYOK reminder.** Engram is bring-your-own-key end-to-end. Configure an OpenAI / Anthropic / Groq / Together / Fireworks key on the [Lumetra portal](https://lumetra.io/models) before your first call, or `storeMemory` / `query` will return HTTP 412.
|
|
52
|
+
|
|
53
|
+
## API surface
|
|
54
|
+
|
|
55
|
+
### Memories
|
|
56
|
+
- `storeMemory(content, bucket?)` — store a single fact
|
|
57
|
+
- `storeMemories(contents[], bucket?)` — batched store
|
|
58
|
+
- `listMemories(bucket?, { limit?, offset? })` — paginated list
|
|
59
|
+
- `deleteMemory(memoryId, bucket?)` — delete one memory
|
|
60
|
+
- `clearMemories(bucket)` — delete every memory in a bucket
|
|
61
|
+
|
|
62
|
+
### Query
|
|
63
|
+
- `query(question, { buckets?, topK?, skipSynthesis?, returnExplanation? })`
|
|
64
|
+
- `buckets` fuses across multiple buckets in one call
|
|
65
|
+
- `skipSynthesis: true` returns retrieval-only — no server-side LLM call
|
|
66
|
+
- response shape: `{ answer, explanation: { retrieved_memories, profile, graph_facts }, usage }`
|
|
67
|
+
|
|
68
|
+
### Buckets
|
|
69
|
+
- `listBuckets()` — all buckets in your tenant
|
|
70
|
+
- `createBucket(name, description?)`
|
|
71
|
+
- `deleteBucket(bucket)`
|
|
72
|
+
|
|
73
|
+
### Profile
|
|
74
|
+
- `getProfile(bucket?)` — the canonical profile prepended to recall
|
|
75
|
+
- `regenerateProfile(bucket?)` — rebuild from current memories
|
|
76
|
+
|
|
77
|
+
### Errors
|
|
78
|
+
|
|
79
|
+
All HTTP failures throw `EngramError`:
|
|
80
|
+
|
|
81
|
+
```ts
|
|
82
|
+
import { EngramError } from '@lumetra/engram';
|
|
83
|
+
|
|
84
|
+
try {
|
|
85
|
+
await engram.storeMemory('...');
|
|
86
|
+
} catch (err) {
|
|
87
|
+
if (err instanceof EngramError) {
|
|
88
|
+
console.error(err.status, err.body);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Development
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
npm install
|
|
97
|
+
npm run typecheck
|
|
98
|
+
npm run build # emits dist/
|
|
99
|
+
npm run dev # watch mode
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
`npm run prepublishOnly` runs typecheck + clean build automatically when publishing.
|
|
103
|
+
|
|
104
|
+
## License
|
|
105
|
+
|
|
106
|
+
[MIT](LICENSE) — Copyright (c) 2026 Lumetra.
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// src/types.ts
|
|
4
|
+
var EngramError = class extends Error {
|
|
5
|
+
name = "EngramError";
|
|
6
|
+
status;
|
|
7
|
+
body;
|
|
8
|
+
constructor(message, status, body) {
|
|
9
|
+
super(message);
|
|
10
|
+
this.status = status;
|
|
11
|
+
this.body = body;
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
// src/client.ts
|
|
16
|
+
var DEFAULT_BASE_URL = "https://api.lumetra.io";
|
|
17
|
+
var DEFAULT_TIMEOUT_MS = 3e4;
|
|
18
|
+
var EngramClient = class {
|
|
19
|
+
apiKey;
|
|
20
|
+
baseUrl;
|
|
21
|
+
fetchImpl;
|
|
22
|
+
timeoutMs;
|
|
23
|
+
constructor(options = {}) {
|
|
24
|
+
const apiKey = options.apiKey ?? (typeof process !== "undefined" ? process.env?.ENGRAM_API_KEY : void 0) ?? "";
|
|
25
|
+
if (!apiKey) {
|
|
26
|
+
throw new Error(
|
|
27
|
+
"EngramClient: apiKey is required. Pass it explicitly or set ENGRAM_API_KEY in your environment."
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
const baseUrl = options.baseUrl ?? (typeof process !== "undefined" ? process.env?.ENGRAM_BASE_URL : void 0) ?? DEFAULT_BASE_URL;
|
|
31
|
+
this.apiKey = apiKey;
|
|
32
|
+
this.baseUrl = baseUrl.replace(/\/+$/, "");
|
|
33
|
+
this.fetchImpl = options.fetch ?? globalThis.fetch;
|
|
34
|
+
this.timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
35
|
+
if (typeof this.fetchImpl !== "function") {
|
|
36
|
+
throw new Error(
|
|
37
|
+
"EngramClient: no fetch implementation available. Use Node 18+, or pass options.fetch."
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
async request(path, init = {
|
|
42
|
+
method: "GET"
|
|
43
|
+
}) {
|
|
44
|
+
const url = new URL(`${this.baseUrl}${path}`);
|
|
45
|
+
if (init.query) {
|
|
46
|
+
for (const [k, v] of Object.entries(init.query)) {
|
|
47
|
+
if (v !== void 0) url.searchParams.set(k, String(v));
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
const controller = new AbortController();
|
|
51
|
+
const timer = setTimeout(() => controller.abort(), this.timeoutMs);
|
|
52
|
+
let res;
|
|
53
|
+
try {
|
|
54
|
+
res = await this.fetchImpl(url.toString(), {
|
|
55
|
+
method: init.method,
|
|
56
|
+
headers: {
|
|
57
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
58
|
+
"Content-Type": "application/json"
|
|
59
|
+
},
|
|
60
|
+
body: init.body !== void 0 ? JSON.stringify(init.body) : void 0,
|
|
61
|
+
signal: controller.signal
|
|
62
|
+
});
|
|
63
|
+
} finally {
|
|
64
|
+
clearTimeout(timer);
|
|
65
|
+
}
|
|
66
|
+
const text = await res.text();
|
|
67
|
+
let parsed = void 0;
|
|
68
|
+
if (text) {
|
|
69
|
+
try {
|
|
70
|
+
parsed = JSON.parse(text);
|
|
71
|
+
} catch {
|
|
72
|
+
parsed = text;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
if (!res.ok) {
|
|
76
|
+
const detail = parsed && typeof parsed === "object" && parsed !== null && "error" in parsed ? parsed.error : parsed;
|
|
77
|
+
throw new EngramError(
|
|
78
|
+
`Engram API ${res.status}: ${typeof detail === "string" ? detail : JSON.stringify(detail ?? "")}`,
|
|
79
|
+
res.status,
|
|
80
|
+
parsed
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
return parsed;
|
|
84
|
+
}
|
|
85
|
+
// ---------- Memories ----------
|
|
86
|
+
async storeMemory(content, bucket = "default") {
|
|
87
|
+
return this.request(
|
|
88
|
+
`/v1/buckets/${encodeURIComponent(bucket)}/memories`,
|
|
89
|
+
{ method: "POST", body: { content } }
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
async storeMemories(contents, bucket = "default") {
|
|
93
|
+
return this.request(
|
|
94
|
+
`/v1/buckets/${encodeURIComponent(bucket)}/memories`,
|
|
95
|
+
{ method: "POST", body: { memories: contents.map((content) => ({ content })) } }
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
async listMemories(bucket = "default", options = {}) {
|
|
99
|
+
return this.request(
|
|
100
|
+
`/v1/buckets/${encodeURIComponent(bucket)}/memories`,
|
|
101
|
+
{
|
|
102
|
+
method: "GET",
|
|
103
|
+
query: { limit: options.limit ?? 20, offset: options.offset ?? 0 }
|
|
104
|
+
}
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
async deleteMemory(memoryId, bucket = "default") {
|
|
108
|
+
await this.request(
|
|
109
|
+
`/v1/buckets/${encodeURIComponent(bucket)}/memories/${encodeURIComponent(memoryId)}`,
|
|
110
|
+
{ method: "DELETE" }
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
async clearMemories(bucket) {
|
|
114
|
+
await this.request(
|
|
115
|
+
`/v1/buckets/${encodeURIComponent(bucket)}/memories`,
|
|
116
|
+
{ method: "DELETE" }
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
// ---------- Query ----------
|
|
120
|
+
async query(question, options = {}) {
|
|
121
|
+
const buckets = options.buckets ?? ["default"];
|
|
122
|
+
return this.request("/v1/query", {
|
|
123
|
+
method: "POST",
|
|
124
|
+
body: {
|
|
125
|
+
query: question,
|
|
126
|
+
buckets,
|
|
127
|
+
options: {
|
|
128
|
+
top_k: options.topK ?? 8,
|
|
129
|
+
return_explanation: options.returnExplanation ?? true,
|
|
130
|
+
skip_synthesis: options.skipSynthesis ?? false
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
// ---------- Buckets ----------
|
|
136
|
+
async listBuckets() {
|
|
137
|
+
const result = await this.request(`/v1/buckets`, {
|
|
138
|
+
method: "GET"
|
|
139
|
+
});
|
|
140
|
+
return Array.isArray(result) ? result : result.buckets;
|
|
141
|
+
}
|
|
142
|
+
async createBucket(name, description) {
|
|
143
|
+
return this.request("/v1/buckets", {
|
|
144
|
+
method: "POST",
|
|
145
|
+
body: { name, description }
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
async deleteBucket(bucket) {
|
|
149
|
+
await this.request(`/v1/buckets/${encodeURIComponent(bucket)}`, {
|
|
150
|
+
method: "DELETE"
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
// ---------- Profile ----------
|
|
154
|
+
async getProfile(bucket = "default") {
|
|
155
|
+
return this.request(
|
|
156
|
+
`/v1/buckets/${encodeURIComponent(bucket)}/profile`,
|
|
157
|
+
{ method: "GET" }
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
async regenerateProfile(bucket = "default") {
|
|
161
|
+
return this.request(
|
|
162
|
+
`/v1/buckets/${encodeURIComponent(bucket)}/profile/regenerate`,
|
|
163
|
+
{ method: "POST" }
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
exports.EngramClient = EngramClient;
|
|
169
|
+
exports.EngramError = EngramError;
|
|
170
|
+
//# sourceMappingURL=index.cjs.map
|
|
171
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/types.ts","../src/client.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["export interface EngramClientOptions {\n /**\n * Engram API key. Looks like `eng_live_...`. Defaults to `process.env.ENGRAM_API_KEY`.\n */\n apiKey?: string;\n /**\n * API base URL. Defaults to `process.env.ENGRAM_BASE_URL` or `https://api.lumetra.io`.\n */\n baseUrl?: string;\n /**\n * Custom fetch implementation. Defaults to the global `fetch`.\n * Useful for proxying, retry middleware, or non-Node runtimes.\n */\n fetch?: typeof fetch;\n /**\n * Request timeout in milliseconds. Defaults to 30000 (30s).\n */\n timeoutMs?: number;\n}\n\nexport interface Bucket {\n id: string;\n name: string;\n description?: string | null;\n created_at: string;\n memory_count?: number;\n}\n\nexport interface Memory {\n id: string;\n content: string;\n bucket_name?: string;\n created_at?: string;\n token_count?: number;\n}\n\nexport interface StoreMemoryResult {\n id: string;\n bucket_name: string;\n token_count: number;\n}\n\nexport interface RetrievedMemory {\n id?: string;\n content: string;\n score?: number;\n bucket?: string;\n}\n\nexport interface QueryExplanation {\n retrieved_memories?: RetrievedMemory[];\n profile?: string | null;\n graph_facts?: string[];\n}\n\nexport interface QueryUsage {\n prompt_tokens?: number;\n completion_tokens?: number;\n total_tokens?: number;\n}\n\nexport interface QueryResult {\n answer: string;\n explanation?: QueryExplanation;\n usage?: QueryUsage;\n}\n\nexport interface QueryOptions {\n /**\n * Buckets to fuse across. Defaults to `['default']`.\n */\n buckets?: string[];\n /**\n * Maximum number of memories to retrieve. Defaults to 8.\n */\n topK?: number;\n /**\n * If true, server skips the synthesis LLM call and returns retrieval-only.\n * `answer` will be an empty string in that case. Defaults to false.\n */\n skipSynthesis?: boolean;\n /**\n * Whether to populate the `explanation` field. Defaults to true.\n */\n returnExplanation?: boolean;\n}\n\nexport interface ListMemoriesOptions {\n limit?: number;\n offset?: number;\n}\n\nexport interface ListMemoriesResult {\n memories: Memory[];\n total: number;\n limit: number;\n offset: number;\n}\n\nexport class EngramError extends Error {\n override readonly name = 'EngramError';\n readonly status: number;\n readonly body: unknown;\n\n constructor(message: string, status: number, body: unknown) {\n super(message);\n this.status = status;\n this.body = body;\n }\n}\n","import {\n EngramError,\n type Bucket,\n type EngramClientOptions,\n type ListMemoriesOptions,\n type ListMemoriesResult,\n type QueryOptions,\n type QueryResult,\n type StoreMemoryResult,\n} from './types.js';\n\nconst DEFAULT_BASE_URL = 'https://api.lumetra.io';\nconst DEFAULT_TIMEOUT_MS = 30_000;\n\nexport class EngramClient {\n private readonly apiKey: string;\n private readonly baseUrl: string;\n private readonly fetchImpl: typeof fetch;\n private readonly timeoutMs: number;\n\n constructor(options: EngramClientOptions = {}) {\n const apiKey =\n options.apiKey ??\n (typeof process !== 'undefined' ? process.env?.ENGRAM_API_KEY : undefined) ??\n '';\n if (!apiKey) {\n throw new Error(\n 'EngramClient: apiKey is required. Pass it explicitly or set ENGRAM_API_KEY in your environment.',\n );\n }\n const baseUrl =\n options.baseUrl ??\n (typeof process !== 'undefined' ? process.env?.ENGRAM_BASE_URL : undefined) ??\n DEFAULT_BASE_URL;\n\n this.apiKey = apiKey;\n this.baseUrl = baseUrl.replace(/\\/+$/, '');\n this.fetchImpl = options.fetch ?? globalThis.fetch;\n this.timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n\n if (typeof this.fetchImpl !== 'function') {\n throw new Error(\n 'EngramClient: no fetch implementation available. Use Node 18+, or pass options.fetch.',\n );\n }\n }\n\n private async request<T>(\n path: string,\n init: { method: string; body?: unknown; query?: Record<string, string | number | undefined> } = {\n method: 'GET',\n },\n ): Promise<T> {\n const url = new URL(`${this.baseUrl}${path}`);\n if (init.query) {\n for (const [k, v] of Object.entries(init.query)) {\n if (v !== undefined) url.searchParams.set(k, String(v));\n }\n }\n\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.timeoutMs);\n\n let res: Response;\n try {\n res = await this.fetchImpl(url.toString(), {\n method: init.method,\n headers: {\n Authorization: `Bearer ${this.apiKey}`,\n 'Content-Type': 'application/json',\n },\n body: init.body !== undefined ? JSON.stringify(init.body) : undefined,\n signal: controller.signal,\n });\n } finally {\n clearTimeout(timer);\n }\n\n const text = await res.text();\n let parsed: unknown = undefined;\n if (text) {\n try {\n parsed = JSON.parse(text);\n } catch {\n parsed = text;\n }\n }\n\n if (!res.ok) {\n const detail =\n parsed && typeof parsed === 'object' && parsed !== null && 'error' in parsed\n ? (parsed as { error: unknown }).error\n : parsed;\n throw new EngramError(\n `Engram API ${res.status}: ${typeof detail === 'string' ? detail : JSON.stringify(detail ?? '')}`,\n res.status,\n parsed,\n );\n }\n\n return parsed as T;\n }\n\n // ---------- Memories ----------\n\n async storeMemory(content: string, bucket: string = 'default'): Promise<StoreMemoryResult> {\n return this.request<StoreMemoryResult>(\n `/v1/buckets/${encodeURIComponent(bucket)}/memories`,\n { method: 'POST', body: { content } },\n );\n }\n\n async storeMemories(\n contents: string[],\n bucket: string = 'default',\n ): Promise<{ memories: StoreMemoryResult[] }> {\n return this.request<{ memories: StoreMemoryResult[] }>(\n `/v1/buckets/${encodeURIComponent(bucket)}/memories`,\n { method: 'POST', body: { memories: contents.map((content) => ({ content })) } },\n );\n }\n\n async listMemories(\n bucket: string = 'default',\n options: ListMemoriesOptions = {},\n ): Promise<ListMemoriesResult> {\n return this.request<ListMemoriesResult>(\n `/v1/buckets/${encodeURIComponent(bucket)}/memories`,\n {\n method: 'GET',\n query: { limit: options.limit ?? 20, offset: options.offset ?? 0 },\n },\n );\n }\n\n async deleteMemory(memoryId: string, bucket: string = 'default'): Promise<void> {\n await this.request<unknown>(\n `/v1/buckets/${encodeURIComponent(bucket)}/memories/${encodeURIComponent(memoryId)}`,\n { method: 'DELETE' },\n );\n }\n\n async clearMemories(bucket: string): Promise<void> {\n await this.request<unknown>(\n `/v1/buckets/${encodeURIComponent(bucket)}/memories`,\n { method: 'DELETE' },\n );\n }\n\n // ---------- Query ----------\n\n async query(question: string, options: QueryOptions = {}): Promise<QueryResult> {\n const buckets = options.buckets ?? ['default'];\n return this.request<QueryResult>('/v1/query', {\n method: 'POST',\n body: {\n query: question,\n buckets,\n options: {\n top_k: options.topK ?? 8,\n return_explanation: options.returnExplanation ?? true,\n skip_synthesis: options.skipSynthesis ?? false,\n },\n },\n });\n }\n\n // ---------- Buckets ----------\n\n async listBuckets(): Promise<Bucket[]> {\n const result = await this.request<{ buckets: Bucket[] } | Bucket[]>(`/v1/buckets`, {\n method: 'GET',\n });\n return Array.isArray(result) ? result : result.buckets;\n }\n\n async createBucket(name: string, description?: string): Promise<Bucket> {\n return this.request<Bucket>('/v1/buckets', {\n method: 'POST',\n body: { name, description },\n });\n }\n\n async deleteBucket(bucket: string): Promise<void> {\n await this.request<unknown>(`/v1/buckets/${encodeURIComponent(bucket)}`, {\n method: 'DELETE',\n });\n }\n\n // ---------- Profile ----------\n\n async getProfile(bucket: string = 'default'): Promise<{ profile: string | null }> {\n return this.request<{ profile: string | null }>(\n `/v1/buckets/${encodeURIComponent(bucket)}/profile`,\n { method: 'GET' },\n );\n }\n\n async regenerateProfile(bucket: string = 'default'): Promise<{ profile: string | null }> {\n return this.request<{ profile: string | null }>(\n `/v1/buckets/${encodeURIComponent(bucket)}/profile/regenerate`,\n { method: 'POST' },\n );\n }\n}\n"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
interface EngramClientOptions {
|
|
2
|
+
/**
|
|
3
|
+
* Engram API key. Looks like `eng_live_...`. Defaults to `process.env.ENGRAM_API_KEY`.
|
|
4
|
+
*/
|
|
5
|
+
apiKey?: string;
|
|
6
|
+
/**
|
|
7
|
+
* API base URL. Defaults to `process.env.ENGRAM_BASE_URL` or `https://api.lumetra.io`.
|
|
8
|
+
*/
|
|
9
|
+
baseUrl?: string;
|
|
10
|
+
/**
|
|
11
|
+
* Custom fetch implementation. Defaults to the global `fetch`.
|
|
12
|
+
* Useful for proxying, retry middleware, or non-Node runtimes.
|
|
13
|
+
*/
|
|
14
|
+
fetch?: typeof fetch;
|
|
15
|
+
/**
|
|
16
|
+
* Request timeout in milliseconds. Defaults to 30000 (30s).
|
|
17
|
+
*/
|
|
18
|
+
timeoutMs?: number;
|
|
19
|
+
}
|
|
20
|
+
interface Bucket {
|
|
21
|
+
id: string;
|
|
22
|
+
name: string;
|
|
23
|
+
description?: string | null;
|
|
24
|
+
created_at: string;
|
|
25
|
+
memory_count?: number;
|
|
26
|
+
}
|
|
27
|
+
interface Memory {
|
|
28
|
+
id: string;
|
|
29
|
+
content: string;
|
|
30
|
+
bucket_name?: string;
|
|
31
|
+
created_at?: string;
|
|
32
|
+
token_count?: number;
|
|
33
|
+
}
|
|
34
|
+
interface StoreMemoryResult {
|
|
35
|
+
id: string;
|
|
36
|
+
bucket_name: string;
|
|
37
|
+
token_count: number;
|
|
38
|
+
}
|
|
39
|
+
interface RetrievedMemory {
|
|
40
|
+
id?: string;
|
|
41
|
+
content: string;
|
|
42
|
+
score?: number;
|
|
43
|
+
bucket?: string;
|
|
44
|
+
}
|
|
45
|
+
interface QueryExplanation {
|
|
46
|
+
retrieved_memories?: RetrievedMemory[];
|
|
47
|
+
profile?: string | null;
|
|
48
|
+
graph_facts?: string[];
|
|
49
|
+
}
|
|
50
|
+
interface QueryUsage {
|
|
51
|
+
prompt_tokens?: number;
|
|
52
|
+
completion_tokens?: number;
|
|
53
|
+
total_tokens?: number;
|
|
54
|
+
}
|
|
55
|
+
interface QueryResult {
|
|
56
|
+
answer: string;
|
|
57
|
+
explanation?: QueryExplanation;
|
|
58
|
+
usage?: QueryUsage;
|
|
59
|
+
}
|
|
60
|
+
interface QueryOptions {
|
|
61
|
+
/**
|
|
62
|
+
* Buckets to fuse across. Defaults to `['default']`.
|
|
63
|
+
*/
|
|
64
|
+
buckets?: string[];
|
|
65
|
+
/**
|
|
66
|
+
* Maximum number of memories to retrieve. Defaults to 8.
|
|
67
|
+
*/
|
|
68
|
+
topK?: number;
|
|
69
|
+
/**
|
|
70
|
+
* If true, server skips the synthesis LLM call and returns retrieval-only.
|
|
71
|
+
* `answer` will be an empty string in that case. Defaults to false.
|
|
72
|
+
*/
|
|
73
|
+
skipSynthesis?: boolean;
|
|
74
|
+
/**
|
|
75
|
+
* Whether to populate the `explanation` field. Defaults to true.
|
|
76
|
+
*/
|
|
77
|
+
returnExplanation?: boolean;
|
|
78
|
+
}
|
|
79
|
+
interface ListMemoriesOptions {
|
|
80
|
+
limit?: number;
|
|
81
|
+
offset?: number;
|
|
82
|
+
}
|
|
83
|
+
interface ListMemoriesResult {
|
|
84
|
+
memories: Memory[];
|
|
85
|
+
total: number;
|
|
86
|
+
limit: number;
|
|
87
|
+
offset: number;
|
|
88
|
+
}
|
|
89
|
+
declare class EngramError extends Error {
|
|
90
|
+
readonly name = "EngramError";
|
|
91
|
+
readonly status: number;
|
|
92
|
+
readonly body: unknown;
|
|
93
|
+
constructor(message: string, status: number, body: unknown);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
declare class EngramClient {
|
|
97
|
+
private readonly apiKey;
|
|
98
|
+
private readonly baseUrl;
|
|
99
|
+
private readonly fetchImpl;
|
|
100
|
+
private readonly timeoutMs;
|
|
101
|
+
constructor(options?: EngramClientOptions);
|
|
102
|
+
private request;
|
|
103
|
+
storeMemory(content: string, bucket?: string): Promise<StoreMemoryResult>;
|
|
104
|
+
storeMemories(contents: string[], bucket?: string): Promise<{
|
|
105
|
+
memories: StoreMemoryResult[];
|
|
106
|
+
}>;
|
|
107
|
+
listMemories(bucket?: string, options?: ListMemoriesOptions): Promise<ListMemoriesResult>;
|
|
108
|
+
deleteMemory(memoryId: string, bucket?: string): Promise<void>;
|
|
109
|
+
clearMemories(bucket: string): Promise<void>;
|
|
110
|
+
query(question: string, options?: QueryOptions): Promise<QueryResult>;
|
|
111
|
+
listBuckets(): Promise<Bucket[]>;
|
|
112
|
+
createBucket(name: string, description?: string): Promise<Bucket>;
|
|
113
|
+
deleteBucket(bucket: string): Promise<void>;
|
|
114
|
+
getProfile(bucket?: string): Promise<{
|
|
115
|
+
profile: string | null;
|
|
116
|
+
}>;
|
|
117
|
+
regenerateProfile(bucket?: string): Promise<{
|
|
118
|
+
profile: string | null;
|
|
119
|
+
}>;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export { type Bucket, EngramClient, type EngramClientOptions, EngramError, type ListMemoriesOptions, type ListMemoriesResult, type Memory, type QueryExplanation, type QueryOptions, type QueryResult, type QueryUsage, type RetrievedMemory, type StoreMemoryResult };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
interface EngramClientOptions {
|
|
2
|
+
/**
|
|
3
|
+
* Engram API key. Looks like `eng_live_...`. Defaults to `process.env.ENGRAM_API_KEY`.
|
|
4
|
+
*/
|
|
5
|
+
apiKey?: string;
|
|
6
|
+
/**
|
|
7
|
+
* API base URL. Defaults to `process.env.ENGRAM_BASE_URL` or `https://api.lumetra.io`.
|
|
8
|
+
*/
|
|
9
|
+
baseUrl?: string;
|
|
10
|
+
/**
|
|
11
|
+
* Custom fetch implementation. Defaults to the global `fetch`.
|
|
12
|
+
* Useful for proxying, retry middleware, or non-Node runtimes.
|
|
13
|
+
*/
|
|
14
|
+
fetch?: typeof fetch;
|
|
15
|
+
/**
|
|
16
|
+
* Request timeout in milliseconds. Defaults to 30000 (30s).
|
|
17
|
+
*/
|
|
18
|
+
timeoutMs?: number;
|
|
19
|
+
}
|
|
20
|
+
interface Bucket {
|
|
21
|
+
id: string;
|
|
22
|
+
name: string;
|
|
23
|
+
description?: string | null;
|
|
24
|
+
created_at: string;
|
|
25
|
+
memory_count?: number;
|
|
26
|
+
}
|
|
27
|
+
interface Memory {
|
|
28
|
+
id: string;
|
|
29
|
+
content: string;
|
|
30
|
+
bucket_name?: string;
|
|
31
|
+
created_at?: string;
|
|
32
|
+
token_count?: number;
|
|
33
|
+
}
|
|
34
|
+
interface StoreMemoryResult {
|
|
35
|
+
id: string;
|
|
36
|
+
bucket_name: string;
|
|
37
|
+
token_count: number;
|
|
38
|
+
}
|
|
39
|
+
interface RetrievedMemory {
|
|
40
|
+
id?: string;
|
|
41
|
+
content: string;
|
|
42
|
+
score?: number;
|
|
43
|
+
bucket?: string;
|
|
44
|
+
}
|
|
45
|
+
interface QueryExplanation {
|
|
46
|
+
retrieved_memories?: RetrievedMemory[];
|
|
47
|
+
profile?: string | null;
|
|
48
|
+
graph_facts?: string[];
|
|
49
|
+
}
|
|
50
|
+
interface QueryUsage {
|
|
51
|
+
prompt_tokens?: number;
|
|
52
|
+
completion_tokens?: number;
|
|
53
|
+
total_tokens?: number;
|
|
54
|
+
}
|
|
55
|
+
interface QueryResult {
|
|
56
|
+
answer: string;
|
|
57
|
+
explanation?: QueryExplanation;
|
|
58
|
+
usage?: QueryUsage;
|
|
59
|
+
}
|
|
60
|
+
interface QueryOptions {
|
|
61
|
+
/**
|
|
62
|
+
* Buckets to fuse across. Defaults to `['default']`.
|
|
63
|
+
*/
|
|
64
|
+
buckets?: string[];
|
|
65
|
+
/**
|
|
66
|
+
* Maximum number of memories to retrieve. Defaults to 8.
|
|
67
|
+
*/
|
|
68
|
+
topK?: number;
|
|
69
|
+
/**
|
|
70
|
+
* If true, server skips the synthesis LLM call and returns retrieval-only.
|
|
71
|
+
* `answer` will be an empty string in that case. Defaults to false.
|
|
72
|
+
*/
|
|
73
|
+
skipSynthesis?: boolean;
|
|
74
|
+
/**
|
|
75
|
+
* Whether to populate the `explanation` field. Defaults to true.
|
|
76
|
+
*/
|
|
77
|
+
returnExplanation?: boolean;
|
|
78
|
+
}
|
|
79
|
+
interface ListMemoriesOptions {
|
|
80
|
+
limit?: number;
|
|
81
|
+
offset?: number;
|
|
82
|
+
}
|
|
83
|
+
interface ListMemoriesResult {
|
|
84
|
+
memories: Memory[];
|
|
85
|
+
total: number;
|
|
86
|
+
limit: number;
|
|
87
|
+
offset: number;
|
|
88
|
+
}
|
|
89
|
+
declare class EngramError extends Error {
|
|
90
|
+
readonly name = "EngramError";
|
|
91
|
+
readonly status: number;
|
|
92
|
+
readonly body: unknown;
|
|
93
|
+
constructor(message: string, status: number, body: unknown);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
declare class EngramClient {
|
|
97
|
+
private readonly apiKey;
|
|
98
|
+
private readonly baseUrl;
|
|
99
|
+
private readonly fetchImpl;
|
|
100
|
+
private readonly timeoutMs;
|
|
101
|
+
constructor(options?: EngramClientOptions);
|
|
102
|
+
private request;
|
|
103
|
+
storeMemory(content: string, bucket?: string): Promise<StoreMemoryResult>;
|
|
104
|
+
storeMemories(contents: string[], bucket?: string): Promise<{
|
|
105
|
+
memories: StoreMemoryResult[];
|
|
106
|
+
}>;
|
|
107
|
+
listMemories(bucket?: string, options?: ListMemoriesOptions): Promise<ListMemoriesResult>;
|
|
108
|
+
deleteMemory(memoryId: string, bucket?: string): Promise<void>;
|
|
109
|
+
clearMemories(bucket: string): Promise<void>;
|
|
110
|
+
query(question: string, options?: QueryOptions): Promise<QueryResult>;
|
|
111
|
+
listBuckets(): Promise<Bucket[]>;
|
|
112
|
+
createBucket(name: string, description?: string): Promise<Bucket>;
|
|
113
|
+
deleteBucket(bucket: string): Promise<void>;
|
|
114
|
+
getProfile(bucket?: string): Promise<{
|
|
115
|
+
profile: string | null;
|
|
116
|
+
}>;
|
|
117
|
+
regenerateProfile(bucket?: string): Promise<{
|
|
118
|
+
profile: string | null;
|
|
119
|
+
}>;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export { type Bucket, EngramClient, type EngramClientOptions, EngramError, type ListMemoriesOptions, type ListMemoriesResult, type Memory, type QueryExplanation, type QueryOptions, type QueryResult, type QueryUsage, type RetrievedMemory, type StoreMemoryResult };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
// src/types.ts
|
|
2
|
+
var EngramError = class extends Error {
|
|
3
|
+
name = "EngramError";
|
|
4
|
+
status;
|
|
5
|
+
body;
|
|
6
|
+
constructor(message, status, body) {
|
|
7
|
+
super(message);
|
|
8
|
+
this.status = status;
|
|
9
|
+
this.body = body;
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
// src/client.ts
|
|
14
|
+
var DEFAULT_BASE_URL = "https://api.lumetra.io";
|
|
15
|
+
var DEFAULT_TIMEOUT_MS = 3e4;
|
|
16
|
+
var EngramClient = class {
|
|
17
|
+
apiKey;
|
|
18
|
+
baseUrl;
|
|
19
|
+
fetchImpl;
|
|
20
|
+
timeoutMs;
|
|
21
|
+
constructor(options = {}) {
|
|
22
|
+
const apiKey = options.apiKey ?? (typeof process !== "undefined" ? process.env?.ENGRAM_API_KEY : void 0) ?? "";
|
|
23
|
+
if (!apiKey) {
|
|
24
|
+
throw new Error(
|
|
25
|
+
"EngramClient: apiKey is required. Pass it explicitly or set ENGRAM_API_KEY in your environment."
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
const baseUrl = options.baseUrl ?? (typeof process !== "undefined" ? process.env?.ENGRAM_BASE_URL : void 0) ?? DEFAULT_BASE_URL;
|
|
29
|
+
this.apiKey = apiKey;
|
|
30
|
+
this.baseUrl = baseUrl.replace(/\/+$/, "");
|
|
31
|
+
this.fetchImpl = options.fetch ?? globalThis.fetch;
|
|
32
|
+
this.timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
33
|
+
if (typeof this.fetchImpl !== "function") {
|
|
34
|
+
throw new Error(
|
|
35
|
+
"EngramClient: no fetch implementation available. Use Node 18+, or pass options.fetch."
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
async request(path, init = {
|
|
40
|
+
method: "GET"
|
|
41
|
+
}) {
|
|
42
|
+
const url = new URL(`${this.baseUrl}${path}`);
|
|
43
|
+
if (init.query) {
|
|
44
|
+
for (const [k, v] of Object.entries(init.query)) {
|
|
45
|
+
if (v !== void 0) url.searchParams.set(k, String(v));
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
const controller = new AbortController();
|
|
49
|
+
const timer = setTimeout(() => controller.abort(), this.timeoutMs);
|
|
50
|
+
let res;
|
|
51
|
+
try {
|
|
52
|
+
res = await this.fetchImpl(url.toString(), {
|
|
53
|
+
method: init.method,
|
|
54
|
+
headers: {
|
|
55
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
56
|
+
"Content-Type": "application/json"
|
|
57
|
+
},
|
|
58
|
+
body: init.body !== void 0 ? JSON.stringify(init.body) : void 0,
|
|
59
|
+
signal: controller.signal
|
|
60
|
+
});
|
|
61
|
+
} finally {
|
|
62
|
+
clearTimeout(timer);
|
|
63
|
+
}
|
|
64
|
+
const text = await res.text();
|
|
65
|
+
let parsed = void 0;
|
|
66
|
+
if (text) {
|
|
67
|
+
try {
|
|
68
|
+
parsed = JSON.parse(text);
|
|
69
|
+
} catch {
|
|
70
|
+
parsed = text;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if (!res.ok) {
|
|
74
|
+
const detail = parsed && typeof parsed === "object" && parsed !== null && "error" in parsed ? parsed.error : parsed;
|
|
75
|
+
throw new EngramError(
|
|
76
|
+
`Engram API ${res.status}: ${typeof detail === "string" ? detail : JSON.stringify(detail ?? "")}`,
|
|
77
|
+
res.status,
|
|
78
|
+
parsed
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
return parsed;
|
|
82
|
+
}
|
|
83
|
+
// ---------- Memories ----------
|
|
84
|
+
async storeMemory(content, bucket = "default") {
|
|
85
|
+
return this.request(
|
|
86
|
+
`/v1/buckets/${encodeURIComponent(bucket)}/memories`,
|
|
87
|
+
{ method: "POST", body: { content } }
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
async storeMemories(contents, bucket = "default") {
|
|
91
|
+
return this.request(
|
|
92
|
+
`/v1/buckets/${encodeURIComponent(bucket)}/memories`,
|
|
93
|
+
{ method: "POST", body: { memories: contents.map((content) => ({ content })) } }
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
async listMemories(bucket = "default", options = {}) {
|
|
97
|
+
return this.request(
|
|
98
|
+
`/v1/buckets/${encodeURIComponent(bucket)}/memories`,
|
|
99
|
+
{
|
|
100
|
+
method: "GET",
|
|
101
|
+
query: { limit: options.limit ?? 20, offset: options.offset ?? 0 }
|
|
102
|
+
}
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
async deleteMemory(memoryId, bucket = "default") {
|
|
106
|
+
await this.request(
|
|
107
|
+
`/v1/buckets/${encodeURIComponent(bucket)}/memories/${encodeURIComponent(memoryId)}`,
|
|
108
|
+
{ method: "DELETE" }
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
async clearMemories(bucket) {
|
|
112
|
+
await this.request(
|
|
113
|
+
`/v1/buckets/${encodeURIComponent(bucket)}/memories`,
|
|
114
|
+
{ method: "DELETE" }
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
// ---------- Query ----------
|
|
118
|
+
async query(question, options = {}) {
|
|
119
|
+
const buckets = options.buckets ?? ["default"];
|
|
120
|
+
return this.request("/v1/query", {
|
|
121
|
+
method: "POST",
|
|
122
|
+
body: {
|
|
123
|
+
query: question,
|
|
124
|
+
buckets,
|
|
125
|
+
options: {
|
|
126
|
+
top_k: options.topK ?? 8,
|
|
127
|
+
return_explanation: options.returnExplanation ?? true,
|
|
128
|
+
skip_synthesis: options.skipSynthesis ?? false
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
// ---------- Buckets ----------
|
|
134
|
+
async listBuckets() {
|
|
135
|
+
const result = await this.request(`/v1/buckets`, {
|
|
136
|
+
method: "GET"
|
|
137
|
+
});
|
|
138
|
+
return Array.isArray(result) ? result : result.buckets;
|
|
139
|
+
}
|
|
140
|
+
async createBucket(name, description) {
|
|
141
|
+
return this.request("/v1/buckets", {
|
|
142
|
+
method: "POST",
|
|
143
|
+
body: { name, description }
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
async deleteBucket(bucket) {
|
|
147
|
+
await this.request(`/v1/buckets/${encodeURIComponent(bucket)}`, {
|
|
148
|
+
method: "DELETE"
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
// ---------- Profile ----------
|
|
152
|
+
async getProfile(bucket = "default") {
|
|
153
|
+
return this.request(
|
|
154
|
+
`/v1/buckets/${encodeURIComponent(bucket)}/profile`,
|
|
155
|
+
{ method: "GET" }
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
async regenerateProfile(bucket = "default") {
|
|
159
|
+
return this.request(
|
|
160
|
+
`/v1/buckets/${encodeURIComponent(bucket)}/profile/regenerate`,
|
|
161
|
+
{ method: "POST" }
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
export { EngramClient, EngramError };
|
|
167
|
+
//# sourceMappingURL=index.js.map
|
|
168
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/types.ts","../src/client.ts"],"names":[],"mappings":";AAmGO,IAAM,WAAA,GAAN,cAA0B,KAAA,CAAM;AAAA,EACnB,IAAA,GAAO,aAAA;AAAA,EAChB,MAAA;AAAA,EACA,IAAA;AAAA,EAET,WAAA,CAAY,OAAA,EAAiB,MAAA,EAAgB,IAAA,EAAe;AAC1D,IAAA,KAAA,CAAM,OAAO,CAAA;AACb,IAAA,IAAA,CAAK,MAAA,GAAS,MAAA;AACd,IAAA,IAAA,CAAK,IAAA,GAAO,IAAA;AAAA,EACd;AACF;;;AClGA,IAAM,gBAAA,GAAmB,wBAAA;AACzB,IAAM,kBAAA,GAAqB,GAAA;AAEpB,IAAM,eAAN,MAAmB;AAAA,EACP,MAAA;AAAA,EACA,OAAA;AAAA,EACA,SAAA;AAAA,EACA,SAAA;AAAA,EAEjB,WAAA,CAAY,OAAA,GAA+B,EAAC,EAAG;AAC7C,IAAA,MAAM,MAAA,GACJ,QAAQ,MAAA,KACP,OAAO,YAAY,WAAA,GAAc,OAAA,CAAQ,GAAA,EAAK,cAAA,GAAiB,MAAA,CAAA,IAChE,EAAA;AACF,IAAA,IAAI,CAAC,MAAA,EAAQ;AACX,MAAA,MAAM,IAAI,KAAA;AAAA,QACR;AAAA,OACF;AAAA,IACF;AACA,IAAA,MAAM,OAAA,GACJ,QAAQ,OAAA,KACP,OAAO,YAAY,WAAA,GAAc,OAAA,CAAQ,GAAA,EAAK,eAAA,GAAkB,MAAA,CAAA,IACjE,gBAAA;AAEF,IAAA,IAAA,CAAK,MAAA,GAAS,MAAA;AACd,IAAA,IAAA,CAAK,OAAA,GAAU,OAAA,CAAQ,OAAA,CAAQ,MAAA,EAAQ,EAAE,CAAA;AACzC,IAAA,IAAA,CAAK,SAAA,GAAY,OAAA,CAAQ,KAAA,IAAS,UAAA,CAAW,KAAA;AAC7C,IAAA,IAAA,CAAK,SAAA,GAAY,QAAQ,SAAA,IAAa,kBAAA;AAEtC,IAAA,IAAI,OAAO,IAAA,CAAK,SAAA,KAAc,UAAA,EAAY;AACxC,MAAA,MAAM,IAAI,KAAA;AAAA,QACR;AAAA,OACF;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAc,OAAA,CACZ,IAAA,EACA,IAAA,GAAgG;AAAA,IAC9F,MAAA,EAAQ;AAAA,GACV,EACY;AACZ,IAAA,MAAM,GAAA,GAAM,IAAI,GAAA,CAAI,CAAA,EAAG,KAAK,OAAO,CAAA,EAAG,IAAI,CAAA,CAAE,CAAA;AAC5C,IAAA,IAAI,KAAK,KAAA,EAAO;AACd,MAAA,KAAA,MAAW,CAAC,GAAG,CAAC,CAAA,IAAK,OAAO,OAAA,CAAQ,IAAA,CAAK,KAAK,CAAA,EAAG;AAC/C,QAAA,IAAI,CAAA,KAAM,QAAW,GAAA,CAAI,YAAA,CAAa,IAAI,CAAA,EAAG,MAAA,CAAO,CAAC,CAAC,CAAA;AAAA,MACxD;AAAA,IACF;AAEA,IAAA,MAAM,UAAA,GAAa,IAAI,eAAA,EAAgB;AACvC,IAAA,MAAM,QAAQ,UAAA,CAAW,MAAM,WAAW,KAAA,EAAM,EAAG,KAAK,SAAS,CAAA;AAEjE,IAAA,IAAI,GAAA;AACJ,IAAA,IAAI;AACF,MAAA,GAAA,GAAM,MAAM,IAAA,CAAK,SAAA,CAAU,GAAA,CAAI,UAAS,EAAG;AAAA,QACzC,QAAQ,IAAA,CAAK,MAAA;AAAA,QACb,OAAA,EAAS;AAAA,UACP,aAAA,EAAe,CAAA,OAAA,EAAU,IAAA,CAAK,MAAM,CAAA,CAAA;AAAA,UACpC,cAAA,EAAgB;AAAA,SAClB;AAAA,QACA,IAAA,EAAM,KAAK,IAAA,KAAS,KAAA,CAAA,GAAY,KAAK,SAAA,CAAU,IAAA,CAAK,IAAI,CAAA,GAAI,KAAA,CAAA;AAAA,QAC5D,QAAQ,UAAA,CAAW;AAAA,OACpB,CAAA;AAAA,IACH,CAAA,SAAE;AACA,MAAA,YAAA,CAAa,KAAK,CAAA;AAAA,IACpB;AAEA,IAAA,MAAM,IAAA,GAAO,MAAM,GAAA,CAAI,IAAA,EAAK;AAC5B,IAAA,IAAI,MAAA,GAAkB,MAAA;AACtB,IAAA,IAAI,IAAA,EAAM;AACR,MAAA,IAAI;AACF,QAAA,MAAA,GAAS,IAAA,CAAK,MAAM,IAAI,CAAA;AAAA,MAC1B,CAAA,CAAA,MAAQ;AACN,QAAA,MAAA,GAAS,IAAA;AAAA,MACX;AAAA,IACF;AAEA,IAAA,IAAI,CAAC,IAAI,EAAA,EAAI;AACX,MAAA,MAAM,MAAA,GACJ,MAAA,IAAU,OAAO,MAAA,KAAW,QAAA,IAAY,WAAW,IAAA,IAAQ,OAAA,IAAW,MAAA,GACjE,MAAA,CAA8B,KAAA,GAC/B,MAAA;AACN,MAAA,MAAM,IAAI,WAAA;AAAA,QACR,CAAA,WAAA,EAAc,GAAA,CAAI,MAAM,CAAA,EAAA,EAAK,OAAO,MAAA,KAAW,QAAA,GAAW,MAAA,GAAS,IAAA,CAAK,SAAA,CAAU,MAAA,IAAU,EAAE,CAAC,CAAA,CAAA;AAAA,QAC/F,GAAA,CAAI,MAAA;AAAA,QACJ;AAAA,OACF;AAAA,IACF;AAEA,IAAA,OAAO,MAAA;AAAA,EACT;AAAA;AAAA,EAIA,MAAM,WAAA,CAAY,OAAA,EAAiB,MAAA,GAAiB,SAAA,EAAuC;AACzF,IAAA,OAAO,IAAA,CAAK,OAAA;AAAA,MACV,CAAA,YAAA,EAAe,kBAAA,CAAmB,MAAM,CAAC,CAAA,SAAA,CAAA;AAAA,MACzC,EAAE,MAAA,EAAQ,MAAA,EAAQ,IAAA,EAAM,EAAE,SAAQ;AAAE,KACtC;AAAA,EACF;AAAA,EAEA,MAAM,aAAA,CACJ,QAAA,EACA,MAAA,GAAiB,SAAA,EAC2B;AAC5C,IAAA,OAAO,IAAA,CAAK,OAAA;AAAA,MACV,CAAA,YAAA,EAAe,kBAAA,CAAmB,MAAM,CAAC,CAAA,SAAA,CAAA;AAAA,MACzC,EAAE,MAAA,EAAQ,MAAA,EAAQ,IAAA,EAAM,EAAE,QAAA,EAAU,QAAA,CAAS,GAAA,CAAI,CAAC,OAAA,MAAa,EAAE,OAAA,EAAQ,CAAE,GAAE;AAAE,KACjF;AAAA,EACF;AAAA,EAEA,MAAM,YAAA,CACJ,MAAA,GAAiB,SAAA,EACjB,OAAA,GAA+B,EAAC,EACH;AAC7B,IAAA,OAAO,IAAA,CAAK,OAAA;AAAA,MACV,CAAA,YAAA,EAAe,kBAAA,CAAmB,MAAM,CAAC,CAAA,SAAA,CAAA;AAAA,MACzC;AAAA,QACE,MAAA,EAAQ,KAAA;AAAA,QACR,KAAA,EAAO,EAAE,KAAA,EAAO,OAAA,CAAQ,SAAS,EAAA,EAAI,MAAA,EAAQ,OAAA,CAAQ,MAAA,IAAU,CAAA;AAAE;AACnE,KACF;AAAA,EACF;AAAA,EAEA,MAAM,YAAA,CAAa,QAAA,EAAkB,MAAA,GAAiB,SAAA,EAA0B;AAC9E,IAAA,MAAM,IAAA,CAAK,OAAA;AAAA,MACT,eAAe,kBAAA,CAAmB,MAAM,CAAC,CAAA,UAAA,EAAa,kBAAA,CAAmB,QAAQ,CAAC,CAAA,CAAA;AAAA,MAClF,EAAE,QAAQ,QAAA;AAAS,KACrB;AAAA,EACF;AAAA,EAEA,MAAM,cAAc,MAAA,EAA+B;AACjD,IAAA,MAAM,IAAA,CAAK,OAAA;AAAA,MACT,CAAA,YAAA,EAAe,kBAAA,CAAmB,MAAM,CAAC,CAAA,SAAA,CAAA;AAAA,MACzC,EAAE,QAAQ,QAAA;AAAS,KACrB;AAAA,EACF;AAAA;AAAA,EAIA,MAAM,KAAA,CAAM,QAAA,EAAkB,OAAA,GAAwB,EAAC,EAAyB;AAC9E,IAAA,MAAM,OAAA,GAAU,OAAA,CAAQ,OAAA,IAAW,CAAC,SAAS,CAAA;AAC7C,IAAA,OAAO,IAAA,CAAK,QAAqB,WAAA,EAAa;AAAA,MAC5C,MAAA,EAAQ,MAAA;AAAA,MACR,IAAA,EAAM;AAAA,QACJ,KAAA,EAAO,QAAA;AAAA,QACP,OAAA;AAAA,QACA,OAAA,EAAS;AAAA,UACP,KAAA,EAAO,QAAQ,IAAA,IAAQ,CAAA;AAAA,UACvB,kBAAA,EAAoB,QAAQ,iBAAA,IAAqB,IAAA;AAAA,UACjD,cAAA,EAAgB,QAAQ,aAAA,IAAiB;AAAA;AAC3C;AACF,KACD,CAAA;AAAA,EACH;AAAA;AAAA,EAIA,MAAM,WAAA,GAAiC;AACrC,IAAA,MAAM,MAAA,GAAS,MAAM,IAAA,CAAK,OAAA,CAA0C,CAAA,WAAA,CAAA,EAAe;AAAA,MACjF,MAAA,EAAQ;AAAA,KACT,CAAA;AACD,IAAA,OAAO,KAAA,CAAM,OAAA,CAAQ,MAAM,CAAA,GAAI,SAAS,MAAA,CAAO,OAAA;AAAA,EACjD;AAAA,EAEA,MAAM,YAAA,CAAa,IAAA,EAAc,WAAA,EAAuC;AACtE,IAAA,OAAO,IAAA,CAAK,QAAgB,aAAA,EAAe;AAAA,MACzC,MAAA,EAAQ,MAAA;AAAA,MACR,IAAA,EAAM,EAAE,IAAA,EAAM,WAAA;AAAY,KAC3B,CAAA;AAAA,EACH;AAAA,EAEA,MAAM,aAAa,MAAA,EAA+B;AAChD,IAAA,MAAM,KAAK,OAAA,CAAiB,CAAA,YAAA,EAAe,kBAAA,CAAmB,MAAM,CAAC,CAAA,CAAA,EAAI;AAAA,MACvE,MAAA,EAAQ;AAAA,KACT,CAAA;AAAA,EACH;AAAA;AAAA,EAIA,MAAM,UAAA,CAAW,MAAA,GAAiB,SAAA,EAAgD;AAChF,IAAA,OAAO,IAAA,CAAK,OAAA;AAAA,MACV,CAAA,YAAA,EAAe,kBAAA,CAAmB,MAAM,CAAC,CAAA,QAAA,CAAA;AAAA,MACzC,EAAE,QAAQ,KAAA;AAAM,KAClB;AAAA,EACF;AAAA,EAEA,MAAM,iBAAA,CAAkB,MAAA,GAAiB,SAAA,EAAgD;AACvF,IAAA,OAAO,IAAA,CAAK,OAAA;AAAA,MACV,CAAA,YAAA,EAAe,kBAAA,CAAmB,MAAM,CAAC,CAAA,mBAAA,CAAA;AAAA,MACzC,EAAE,QAAQ,MAAA;AAAO,KACnB;AAAA,EACF;AACF","file":"index.js","sourcesContent":["export interface EngramClientOptions {\n /**\n * Engram API key. Looks like `eng_live_...`. Defaults to `process.env.ENGRAM_API_KEY`.\n */\n apiKey?: string;\n /**\n * API base URL. Defaults to `process.env.ENGRAM_BASE_URL` or `https://api.lumetra.io`.\n */\n baseUrl?: string;\n /**\n * Custom fetch implementation. Defaults to the global `fetch`.\n * Useful for proxying, retry middleware, or non-Node runtimes.\n */\n fetch?: typeof fetch;\n /**\n * Request timeout in milliseconds. Defaults to 30000 (30s).\n */\n timeoutMs?: number;\n}\n\nexport interface Bucket {\n id: string;\n name: string;\n description?: string | null;\n created_at: string;\n memory_count?: number;\n}\n\nexport interface Memory {\n id: string;\n content: string;\n bucket_name?: string;\n created_at?: string;\n token_count?: number;\n}\n\nexport interface StoreMemoryResult {\n id: string;\n bucket_name: string;\n token_count: number;\n}\n\nexport interface RetrievedMemory {\n id?: string;\n content: string;\n score?: number;\n bucket?: string;\n}\n\nexport interface QueryExplanation {\n retrieved_memories?: RetrievedMemory[];\n profile?: string | null;\n graph_facts?: string[];\n}\n\nexport interface QueryUsage {\n prompt_tokens?: number;\n completion_tokens?: number;\n total_tokens?: number;\n}\n\nexport interface QueryResult {\n answer: string;\n explanation?: QueryExplanation;\n usage?: QueryUsage;\n}\n\nexport interface QueryOptions {\n /**\n * Buckets to fuse across. Defaults to `['default']`.\n */\n buckets?: string[];\n /**\n * Maximum number of memories to retrieve. Defaults to 8.\n */\n topK?: number;\n /**\n * If true, server skips the synthesis LLM call and returns retrieval-only.\n * `answer` will be an empty string in that case. Defaults to false.\n */\n skipSynthesis?: boolean;\n /**\n * Whether to populate the `explanation` field. Defaults to true.\n */\n returnExplanation?: boolean;\n}\n\nexport interface ListMemoriesOptions {\n limit?: number;\n offset?: number;\n}\n\nexport interface ListMemoriesResult {\n memories: Memory[];\n total: number;\n limit: number;\n offset: number;\n}\n\nexport class EngramError extends Error {\n override readonly name = 'EngramError';\n readonly status: number;\n readonly body: unknown;\n\n constructor(message: string, status: number, body: unknown) {\n super(message);\n this.status = status;\n this.body = body;\n }\n}\n","import {\n EngramError,\n type Bucket,\n type EngramClientOptions,\n type ListMemoriesOptions,\n type ListMemoriesResult,\n type QueryOptions,\n type QueryResult,\n type StoreMemoryResult,\n} from './types.js';\n\nconst DEFAULT_BASE_URL = 'https://api.lumetra.io';\nconst DEFAULT_TIMEOUT_MS = 30_000;\n\nexport class EngramClient {\n private readonly apiKey: string;\n private readonly baseUrl: string;\n private readonly fetchImpl: typeof fetch;\n private readonly timeoutMs: number;\n\n constructor(options: EngramClientOptions = {}) {\n const apiKey =\n options.apiKey ??\n (typeof process !== 'undefined' ? process.env?.ENGRAM_API_KEY : undefined) ??\n '';\n if (!apiKey) {\n throw new Error(\n 'EngramClient: apiKey is required. Pass it explicitly or set ENGRAM_API_KEY in your environment.',\n );\n }\n const baseUrl =\n options.baseUrl ??\n (typeof process !== 'undefined' ? process.env?.ENGRAM_BASE_URL : undefined) ??\n DEFAULT_BASE_URL;\n\n this.apiKey = apiKey;\n this.baseUrl = baseUrl.replace(/\\/+$/, '');\n this.fetchImpl = options.fetch ?? globalThis.fetch;\n this.timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n\n if (typeof this.fetchImpl !== 'function') {\n throw new Error(\n 'EngramClient: no fetch implementation available. Use Node 18+, or pass options.fetch.',\n );\n }\n }\n\n private async request<T>(\n path: string,\n init: { method: string; body?: unknown; query?: Record<string, string | number | undefined> } = {\n method: 'GET',\n },\n ): Promise<T> {\n const url = new URL(`${this.baseUrl}${path}`);\n if (init.query) {\n for (const [k, v] of Object.entries(init.query)) {\n if (v !== undefined) url.searchParams.set(k, String(v));\n }\n }\n\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.timeoutMs);\n\n let res: Response;\n try {\n res = await this.fetchImpl(url.toString(), {\n method: init.method,\n headers: {\n Authorization: `Bearer ${this.apiKey}`,\n 'Content-Type': 'application/json',\n },\n body: init.body !== undefined ? JSON.stringify(init.body) : undefined,\n signal: controller.signal,\n });\n } finally {\n clearTimeout(timer);\n }\n\n const text = await res.text();\n let parsed: unknown = undefined;\n if (text) {\n try {\n parsed = JSON.parse(text);\n } catch {\n parsed = text;\n }\n }\n\n if (!res.ok) {\n const detail =\n parsed && typeof parsed === 'object' && parsed !== null && 'error' in parsed\n ? (parsed as { error: unknown }).error\n : parsed;\n throw new EngramError(\n `Engram API ${res.status}: ${typeof detail === 'string' ? detail : JSON.stringify(detail ?? '')}`,\n res.status,\n parsed,\n );\n }\n\n return parsed as T;\n }\n\n // ---------- Memories ----------\n\n async storeMemory(content: string, bucket: string = 'default'): Promise<StoreMemoryResult> {\n return this.request<StoreMemoryResult>(\n `/v1/buckets/${encodeURIComponent(bucket)}/memories`,\n { method: 'POST', body: { content } },\n );\n }\n\n async storeMemories(\n contents: string[],\n bucket: string = 'default',\n ): Promise<{ memories: StoreMemoryResult[] }> {\n return this.request<{ memories: StoreMemoryResult[] }>(\n `/v1/buckets/${encodeURIComponent(bucket)}/memories`,\n { method: 'POST', body: { memories: contents.map((content) => ({ content })) } },\n );\n }\n\n async listMemories(\n bucket: string = 'default',\n options: ListMemoriesOptions = {},\n ): Promise<ListMemoriesResult> {\n return this.request<ListMemoriesResult>(\n `/v1/buckets/${encodeURIComponent(bucket)}/memories`,\n {\n method: 'GET',\n query: { limit: options.limit ?? 20, offset: options.offset ?? 0 },\n },\n );\n }\n\n async deleteMemory(memoryId: string, bucket: string = 'default'): Promise<void> {\n await this.request<unknown>(\n `/v1/buckets/${encodeURIComponent(bucket)}/memories/${encodeURIComponent(memoryId)}`,\n { method: 'DELETE' },\n );\n }\n\n async clearMemories(bucket: string): Promise<void> {\n await this.request<unknown>(\n `/v1/buckets/${encodeURIComponent(bucket)}/memories`,\n { method: 'DELETE' },\n );\n }\n\n // ---------- Query ----------\n\n async query(question: string, options: QueryOptions = {}): Promise<QueryResult> {\n const buckets = options.buckets ?? ['default'];\n return this.request<QueryResult>('/v1/query', {\n method: 'POST',\n body: {\n query: question,\n buckets,\n options: {\n top_k: options.topK ?? 8,\n return_explanation: options.returnExplanation ?? true,\n skip_synthesis: options.skipSynthesis ?? false,\n },\n },\n });\n }\n\n // ---------- Buckets ----------\n\n async listBuckets(): Promise<Bucket[]> {\n const result = await this.request<{ buckets: Bucket[] } | Bucket[]>(`/v1/buckets`, {\n method: 'GET',\n });\n return Array.isArray(result) ? result : result.buckets;\n }\n\n async createBucket(name: string, description?: string): Promise<Bucket> {\n return this.request<Bucket>('/v1/buckets', {\n method: 'POST',\n body: { name, description },\n });\n }\n\n async deleteBucket(bucket: string): Promise<void> {\n await this.request<unknown>(`/v1/buckets/${encodeURIComponent(bucket)}`, {\n method: 'DELETE',\n });\n }\n\n // ---------- Profile ----------\n\n async getProfile(bucket: string = 'default'): Promise<{ profile: string | null }> {\n return this.request<{ profile: string | null }>(\n `/v1/buckets/${encodeURIComponent(bucket)}/profile`,\n { method: 'GET' },\n );\n }\n\n async regenerateProfile(bucket: string = 'default'): Promise<{ profile: string | null }> {\n return this.request<{ profile: string | null }>(\n `/v1/buckets/${encodeURIComponent(bucket)}/profile/regenerate`,\n { method: 'POST' },\n );\n }\n}\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@lumetra/engram",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Official TypeScript client for Engram — durable, explainable memory for AI agents.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"engram",
|
|
7
|
+
"lumetra",
|
|
8
|
+
"memory",
|
|
9
|
+
"ai",
|
|
10
|
+
"agents",
|
|
11
|
+
"llm",
|
|
12
|
+
"mcp",
|
|
13
|
+
"rag"
|
|
14
|
+
],
|
|
15
|
+
"license": "MIT",
|
|
16
|
+
"author": "Lumetra <hi@lumetra.io>",
|
|
17
|
+
"homepage": "https://lumetra.io",
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "git+https://github.com/lumetra-io/engram-js.git"
|
|
21
|
+
},
|
|
22
|
+
"bugs": {
|
|
23
|
+
"url": "https://github.com/lumetra-io/engram-js/issues"
|
|
24
|
+
},
|
|
25
|
+
"type": "module",
|
|
26
|
+
"main": "./dist/index.cjs",
|
|
27
|
+
"module": "./dist/index.js",
|
|
28
|
+
"types": "./dist/index.d.ts",
|
|
29
|
+
"exports": {
|
|
30
|
+
".": {
|
|
31
|
+
"types": "./dist/index.d.ts",
|
|
32
|
+
"import": "./dist/index.js",
|
|
33
|
+
"require": "./dist/index.cjs"
|
|
34
|
+
},
|
|
35
|
+
"./package.json": "./package.json"
|
|
36
|
+
},
|
|
37
|
+
"files": [
|
|
38
|
+
"dist",
|
|
39
|
+
"README.md",
|
|
40
|
+
"LICENSE"
|
|
41
|
+
],
|
|
42
|
+
"sideEffects": false,
|
|
43
|
+
"engines": {
|
|
44
|
+
"node": ">=18"
|
|
45
|
+
},
|
|
46
|
+
"scripts": {
|
|
47
|
+
"build": "tsup",
|
|
48
|
+
"dev": "tsup --watch",
|
|
49
|
+
"typecheck": "tsc --noEmit",
|
|
50
|
+
"clean": "rm -rf dist",
|
|
51
|
+
"prepublishOnly": "npm run clean && npm run typecheck && npm run build"
|
|
52
|
+
},
|
|
53
|
+
"devDependencies": {
|
|
54
|
+
"@types/node": "^20.11.0",
|
|
55
|
+
"tsup": "^8.0.0",
|
|
56
|
+
"typescript": "^5.4.0"
|
|
57
|
+
},
|
|
58
|
+
"publishConfig": {
|
|
59
|
+
"access": "public"
|
|
60
|
+
}
|
|
61
|
+
}
|