@lumetra/engram 0.4.0 → 0.5.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 +35 -0
- package/dist/index.cjs +27 -11
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +39 -1
- package/dist/index.d.ts +39 -1
- package/dist/index.js +27 -11
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -63,6 +63,41 @@ new EngramClient({
|
|
|
63
63
|
- `deleteMemory(memoryId, bucket?)` — delete one memory. `bucket` defaults to `"default"`.
|
|
64
64
|
- `clearMemories(bucket)` — delete every memory in a bucket. **No default — explicit bucket required** (prevents accidental wipes).
|
|
65
65
|
|
|
66
|
+
### Query knobs
|
|
67
|
+
|
|
68
|
+
`query` and `queryStream` accept these tuning options (all optional):
|
|
69
|
+
|
|
70
|
+
| Field | Type | What it does |
|
|
71
|
+
|---|---|---|
|
|
72
|
+
| `maxTokens` | `number` | Cap synthesis output. Lower for agent loops / cost control. |
|
|
73
|
+
| `minSimilarityThreshold` | `number` | Drop retrieved chunks below this raw cosine similarity. Citations-grade precision. |
|
|
74
|
+
| `topKPerBucket` | `number \| Record<string,number>` | Per-bucket retrieval depth. `{ edgar_AAPL: 20, prices_AAPL: 4 }` lets you express "deep here, shallow there." |
|
|
75
|
+
| `returnFormat` | `'prose' \| 'json'` | When `'json'`, server returns JSON; result includes parsed `answer_json`. |
|
|
76
|
+
| `responseSchema` | `Record<string, unknown>` (JSON Schema) | Hint the model with a target shape. Best-effort; validate client-side for strict. |
|
|
77
|
+
|
|
78
|
+
Example:
|
|
79
|
+
|
|
80
|
+
```ts
|
|
81
|
+
const r = await engram.query("Apple's active legal proceedings", {
|
|
82
|
+
buckets: ['edgar_AAPL', 'patents_AAPL'],
|
|
83
|
+
topKPerBucket: { edgar_AAPL: 20, patents_AAPL: 5 },
|
|
84
|
+
maxTokens: 400,
|
|
85
|
+
returnFormat: 'json',
|
|
86
|
+
responseSchema: {
|
|
87
|
+
type: 'array',
|
|
88
|
+
items: {
|
|
89
|
+
properties: {
|
|
90
|
+
case_name: { type: 'string' },
|
|
91
|
+
jurisdiction: { type: 'string' },
|
|
92
|
+
status: { type: 'string' },
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
});
|
|
97
|
+
const cases = r.answer_json as Array<{case_name: string; jurisdiction: string; status: string}> | undefined;
|
|
98
|
+
for (const c of cases ?? []) console.log(c);
|
|
99
|
+
```
|
|
100
|
+
|
|
66
101
|
### Query
|
|
67
102
|
- `query(question, { buckets?, topK?, skipSynthesis?, returnExplanation? })`
|
|
68
103
|
- `buckets` fuses across multiple buckets in one call. Defaults to `["default"]`.
|
package/dist/index.cjs
CHANGED
|
@@ -18,7 +18,7 @@ var DEFAULT_TIMEOUT_MS = 3e4;
|
|
|
18
18
|
var DEFAULT_STREAM_TIMEOUT_MS = 3e5;
|
|
19
19
|
var DEFAULT_MAX_RETRIES_ON_429 = 3;
|
|
20
20
|
var RETRY_AFTER_CAP_MS = 3e4;
|
|
21
|
-
var SDK_VERSION = "0.
|
|
21
|
+
var SDK_VERSION = "0.5.0";
|
|
22
22
|
var USER_AGENT = `engram-js/${SDK_VERSION}`;
|
|
23
23
|
function parseRetryAfterMs(header, defaultBackoffMs) {
|
|
24
24
|
if (header) {
|
|
@@ -158,16 +158,24 @@ var EngramClient = class {
|
|
|
158
158
|
// ---------- Query ----------
|
|
159
159
|
async query(question, options = {}) {
|
|
160
160
|
const buckets = options.buckets ?? ["default"];
|
|
161
|
+
const opts = {
|
|
162
|
+
top_k: options.topK ?? 8,
|
|
163
|
+
return_explanation: options.returnExplanation ?? true,
|
|
164
|
+
skip_synthesis: options.skipSynthesis ?? false
|
|
165
|
+
};
|
|
166
|
+
if (options.maxTokens !== void 0) opts.max_tokens = options.maxTokens;
|
|
167
|
+
if (options.minSimilarityThreshold !== void 0) {
|
|
168
|
+
opts.min_similarity_threshold = options.minSimilarityThreshold;
|
|
169
|
+
}
|
|
170
|
+
if (options.topKPerBucket !== void 0) opts.top_k_per_bucket = options.topKPerBucket;
|
|
171
|
+
if (options.returnFormat !== void 0) opts.return_format = options.returnFormat;
|
|
172
|
+
if (options.responseSchema !== void 0) opts.response_schema = options.responseSchema;
|
|
161
173
|
return this.request("/v1/query", {
|
|
162
174
|
method: "POST",
|
|
163
175
|
body: {
|
|
164
176
|
query: question,
|
|
165
177
|
buckets,
|
|
166
|
-
options:
|
|
167
|
-
top_k: options.topK ?? 8,
|
|
168
|
-
return_explanation: options.returnExplanation ?? true,
|
|
169
|
-
skip_synthesis: options.skipSynthesis ?? false
|
|
170
|
-
}
|
|
178
|
+
options: opts
|
|
171
179
|
}
|
|
172
180
|
});
|
|
173
181
|
}
|
|
@@ -185,15 +193,23 @@ var EngramClient = class {
|
|
|
185
193
|
*/
|
|
186
194
|
queryStream(question, options = {}) {
|
|
187
195
|
const buckets = options.buckets ?? ["default"];
|
|
196
|
+
const opts = {
|
|
197
|
+
top_k: options.topK ?? 8,
|
|
198
|
+
return_explanation: options.returnExplanation ?? true,
|
|
199
|
+
skip_synthesis: options.skipSynthesis ?? false
|
|
200
|
+
};
|
|
201
|
+
if (options.maxTokens !== void 0) opts.max_tokens = options.maxTokens;
|
|
202
|
+
if (options.minSimilarityThreshold !== void 0) {
|
|
203
|
+
opts.min_similarity_threshold = options.minSimilarityThreshold;
|
|
204
|
+
}
|
|
205
|
+
if (options.topKPerBucket !== void 0) opts.top_k_per_bucket = options.topKPerBucket;
|
|
206
|
+
if (options.returnFormat !== void 0) opts.return_format = options.returnFormat;
|
|
207
|
+
if (options.responseSchema !== void 0) opts.response_schema = options.responseSchema;
|
|
188
208
|
const body = {
|
|
189
209
|
query: question,
|
|
190
210
|
buckets,
|
|
191
211
|
stream: true,
|
|
192
|
-
options:
|
|
193
|
-
top_k: options.topK ?? 8,
|
|
194
|
-
return_explanation: options.returnExplanation ?? true,
|
|
195
|
-
skip_synthesis: options.skipSynthesis ?? false
|
|
196
|
-
}
|
|
212
|
+
options: opts
|
|
197
213
|
};
|
|
198
214
|
const url = `${this.baseUrl}/v1/query`;
|
|
199
215
|
const apiKey = this.apiKey;
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +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 for buffered (non-streaming) calls.\n * Defaults to 30000 (30s).\n */\n timeoutMs?: number;\n /**\n * Timeout in milliseconds for `queryStream` calls. Streaming responses\n * can sit in the prep phase (retrieval + extractor pass) for 5–15s\n * before the first synthesis token arrives, so the buffered 30s\n * default would leave no headroom for the streamed body. Defaults to\n * 300000 (5 min). Use a higher value for very large synthesis bodies.\n */\n streamTimeoutMs?: number;\n /**\n * How many times to retry on a 429 (per-tenant concurrent-request cap).\n * Honors the server's `Retry-After` header, capped at 30s per sleep.\n * Defaults to 3. Set to 0 to disable retry and surface 429 as `EngramError`\n * on the first attempt.\n */\n maxRetriesOn429?: number;\n}\n\nexport interface Bucket {\n id: string;\n name: string;\n /**\n * Mirror of `name`. The server emits both so callers iterating both\n * `listBuckets` and `storeMemory` responses can use one field name.\n * Prefer `name` in new code.\n */\n bucket_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 type StoreStatus = 'stored' | 'merged';\n\nexport type MergeReason =\n | 'content_hash'\n | 'embedding_similarity'\n | 'conflict_keep_existing'\n | 'concurrent_insert_race';\n\nexport interface StoreMemoryResult {\n id: string;\n /**\n * Alias for `id` — older API docs / older SDKs referenced this name.\n * Always present; prefer `id` in new code.\n */\n memory_id?: string;\n bucket_name: string;\n token_count: number;\n /**\n * `\"stored\"` for fresh writes, `\"merged\"` when the server collapsed\n * this write into a pre-existing memory via dedup. Always present.\n */\n status?: StoreStatus;\n /** Present only when `status === \"merged\"`. ID of the canonical memory the write was absorbed into. */\n deduped_into?: string;\n /** Present only when `status === \"merged\"`. Similarity score in [0.0, 1.0] (1.0 for content-hash matches). */\n similarity_score?: number;\n /** Present only when `status === \"merged\"`. Reason for the merge. */\n merge_reason?: MergeReason;\n}\n\n/**\n * Dedup policy passed to `storeMemory`. The server's default (currently\n * `\"loose\"`) applies when omitted.\n *\n * - `\"off\"` — store every write as a new memory; useful for templated\n * time-series ingest where structurally similar rows carry unique\n * values and would otherwise collapse.\n * - `\"loose\"` — merge writes at similarity ≥ 0.95 (default).\n * - `\"strict\"` — only merge near-identical content (≥ 0.99).\n */\nexport type DedupPolicy = 'off' | 'loose' | 'strict';\n\nexport interface ClearMemoriesResult {\n success: boolean;\n /** Number of memories actually deleted (server-reported). */\n cleared_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 /**\n * Top-level count of retrieved memories. Equivalent to\n * `result.explanation?.retrieved_memories.length` but present even\n * when `returnExplanation` is false.\n */\n memories_found?: number;\n explanation?: QueryExplanation;\n usage?: QueryUsage;\n}\n\n/**\n * One frame yielded by {@link EngramClient.queryStream}.\n *\n * The shape is discriminated by `type`:\n * - `delta` frames carry an incremental piece of the answer in `content`.\n * - `done` carries the final usage + (optional) explanation. Emitted\n * exactly once at the end of the stream.\n */\nexport type QueryStreamEvent =\n | { type: 'delta'; content: string }\n | {\n type: 'done';\n usage?: QueryUsage;\n synthesis_usage?: unknown;\n explanation?: QueryExplanation;\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 ClearMemoriesResult,\n type DedupPolicy,\n type EngramClientOptions,\n type ListMemoriesOptions,\n type ListMemoriesResult,\n type QueryOptions,\n type QueryResult,\n type QueryStreamEvent,\n type StoreMemoryResult,\n} from './types.js';\n\nconst DEFAULT_BASE_URL = 'https://api.lumetra.io';\nconst DEFAULT_TIMEOUT_MS = 30_000;\nconst DEFAULT_STREAM_TIMEOUT_MS = 300_000;\nconst DEFAULT_MAX_RETRIES_ON_429 = 3;\n// Cap on per-attempt backoff so a misconfigured server can't force\n// callers to sleep for minutes.\nconst RETRY_AFTER_CAP_MS = 30_000;\nconst SDK_VERSION = '0.4.0';\nconst USER_AGENT = `engram-js/${SDK_VERSION}`;\n\nfunction parseRetryAfterMs(header: string | null, defaultBackoffMs: number): number {\n if (header) {\n const value = Number(header.trim());\n if (Number.isFinite(value) && value >= 0) {\n return Math.min(value * 1000, RETRY_AFTER_CAP_MS);\n }\n }\n return Math.min(defaultBackoffMs, RETRY_AFTER_CAP_MS);\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\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 private readonly streamTimeoutMs: number;\n private readonly maxRetriesOn429: 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 this.streamTimeoutMs = options.streamTimeoutMs ?? DEFAULT_STREAM_TIMEOUT_MS;\n this.maxRetriesOn429 = Math.max(0, options.maxRetriesOn429 ?? DEFAULT_MAX_RETRIES_ON_429);\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 // 429-aware retry. The Engram API enforces a per-tenant concurrent-\n // request cap and sets Retry-After on 429s; without retry handling,\n // bursty clients fail immediately under load. The body is JSON-\n // serialized once outside the loop so each attempt sends an\n // identical request.\n const requestBody = init.body !== undefined ? JSON.stringify(init.body) : undefined;\n let attemptsRemaining = this.maxRetriesOn429;\n let backoffMs = 1000;\n\n // eslint-disable-next-line no-constant-condition\n while (true) {\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 'User-Agent': USER_AGENT,\n },\n body: requestBody,\n signal: controller.signal,\n });\n } finally {\n clearTimeout(timer);\n }\n\n if (res.status === 429 && attemptsRemaining > 0) {\n // Drain the body so the connection can return to the pool.\n await res.text().catch(() => undefined);\n const delay = parseRetryAfterMs(res.headers.get('Retry-After'), backoffMs);\n await sleep(delay);\n attemptsRemaining -= 1;\n backoffMs = Math.min(backoffMs * 2, RETRY_AFTER_CAP_MS);\n continue;\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\n // ---------- Memories ----------\n\n async storeMemory(\n content: string,\n bucket: string = 'default',\n options: { dedup?: DedupPolicy } = {},\n ): Promise<StoreMemoryResult> {\n const body: Record<string, unknown> = { content };\n if (options.dedup !== undefined) body.dedup = options.dedup;\n return this.request<StoreMemoryResult>(\n `/v1/buckets/${encodeURIComponent(bucket)}/memories`,\n { method: 'POST', body },\n );\n }\n\n async storeMemories(\n contents: string[],\n bucket: string = 'default',\n ): Promise<{ memories: StoreMemoryResult[] }> {\n // Defensively unwrap: depending on server version the batch endpoint\n // returns either { memories: [...] } or a bare array. Normalize to the\n // wrapped shape so callers don't have to switch on it.\n const result = await this.request<{ memories: StoreMemoryResult[] } | StoreMemoryResult[]>(\n `/v1/buckets/${encodeURIComponent(bucket)}/memories`,\n { method: 'POST', body: { memories: contents.map((content) => ({ content })) } },\n );\n return Array.isArray(result) ? { memories: result } : result;\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<ClearMemoriesResult> {\n const res = await this.request<ClearMemoriesResult>(\n `/v1/buckets/${encodeURIComponent(bucket)}/memories`,\n { method: 'DELETE' },\n );\n // Defensive default: older servers / proxies may strip the body. The\n // contract surface is {success, cleared_count}; if the server stayed\n // silent we still return the same shape so callers can rely on it.\n return res ?? { success: true, cleared_count: 0 };\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 /**\n * Streaming variant of {@link query}. Returns an async-iterable that\n * yields {@link QueryStreamEvent} frames as the server produces them:\n *\n * for await (const ev of engram.queryStream('...')) {\n * if (ev.type === 'delta') process.stdout.write(ev.content);\n * else if (ev.type === 'done') console.log(ev.usage);\n * }\n *\n * Break out of the loop to abort the request (the underlying\n * AbortController is wired up to the fetch call).\n */\n queryStream(question: string, options: QueryOptions = {}): AsyncIterable<QueryStreamEvent> {\n const buckets = options.buckets ?? ['default'];\n const body = {\n query: question,\n buckets,\n stream: true,\n options: {\n top_k: options.topK ?? 8,\n return_explanation: options.returnExplanation ?? true,\n skip_synthesis: options.skipSynthesis ?? false,\n },\n };\n const url = `${this.baseUrl}/v1/query`;\n const apiKey = this.apiKey;\n const fetchImpl = this.fetchImpl;\n const timeoutMs = this.streamTimeoutMs;\n const maxRetriesOn429 = this.maxRetriesOn429;\n const bodyJson = JSON.stringify(body);\n\n return {\n [Symbol.asyncIterator]: () => {\n const controller = new AbortController();\n // The timeout caps total wall-clock for the stream. Set generously\n // because synthesis can run 10–25s before the first byte even with\n // streaming on slow paths; clamp to the user's configured timeout.\n const timer = setTimeout(() => controller.abort(), timeoutMs);\n\n let started = false;\n let reader: ReadableStreamDefaultReader<Uint8Array> | null = null;\n const decoder = new TextDecoder('utf-8');\n let buffer = '';\n let done = false;\n const queue: QueryStreamEvent[] = [];\n let pendingError: unknown = null;\n\n const ensureStarted = async (): Promise<void> => {\n if (started) return;\n started = true;\n // 429-aware retry at the connection-open stage only. Once\n // the response body starts flowing we can't resume mid-\n // stream safely.\n let attemptsRemaining = maxRetriesOn429;\n let backoffMs = 1000;\n // eslint-disable-next-line no-constant-condition\n while (true) {\n const res = await fetchImpl(url, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${apiKey}`,\n 'Content-Type': 'application/json',\n Accept: 'text/event-stream',\n 'User-Agent': USER_AGENT,\n },\n body: bodyJson,\n signal: controller.signal,\n });\n if (res.status === 429 && attemptsRemaining > 0) {\n await res.text().catch(() => undefined);\n const delay = parseRetryAfterMs(res.headers.get('Retry-After'), backoffMs);\n await sleep(delay);\n attemptsRemaining -= 1;\n backoffMs = Math.min(backoffMs * 2, RETRY_AFTER_CAP_MS);\n continue;\n }\n if (!res.ok) {\n const text = await res.text().catch(() => '');\n let parsed: unknown = text;\n try {\n parsed = text ? JSON.parse(text) : text;\n } catch {\n /* keep raw text */\n }\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 if (!res.body) {\n throw new EngramError('Engram API: streaming response has no body', res.status, null);\n }\n reader = res.body.getReader();\n return;\n }\n };\n\n const drainBuffer = (): void => {\n // SSE frames are separated by a blank line ('\\n\\n'). Each frame\n // is one or more 'field: value' lines. We only care about\n // 'data:' lines for this stream.\n let idx: number;\n while ((idx = buffer.indexOf('\\n\\n')) !== -1) {\n const frame = buffer.slice(0, idx);\n buffer = buffer.slice(idx + 2);\n const dataLines: string[] = [];\n for (const rawLine of frame.split('\\n')) {\n const line = rawLine.endsWith('\\r') ? rawLine.slice(0, -1) : rawLine;\n if (line.startsWith('data: ')) {\n dataLines.push(line.slice(6));\n } else if (line.startsWith('data:')) {\n dataLines.push(line.slice(5));\n }\n }\n if (dataLines.length === 0) continue;\n const payloadStr = dataLines.join('\\n');\n if (payloadStr === '[DONE]') {\n done = true;\n return;\n }\n let payload: unknown;\n try {\n payload = JSON.parse(payloadStr);\n } catch {\n // Malformed frame — skip rather than corrupt the stream.\n continue;\n }\n if (payload && typeof payload === 'object') {\n const obj = payload as Record<string, unknown>;\n if (obj.error) {\n pendingError = new EngramError(String(obj.error), 0, obj);\n done = true;\n return;\n }\n // OpenAI-style delta chunk\n const choices = obj.choices as Array<{ delta?: { content?: string } }> | undefined;\n if (Array.isArray(choices) && choices.length > 0) {\n const delta = choices[0]?.delta?.content;\n if (typeof delta === 'string' && delta.length > 0) {\n queue.push({ type: 'delta', content: delta });\n }\n continue;\n }\n // Final usage / explanation frame (no 'choices' key).\n queue.push({ type: 'done', ...(obj as Omit<Extract<QueryStreamEvent, { type: 'done' }>, 'type'>) });\n }\n }\n };\n\n return {\n next: async (): Promise<IteratorResult<QueryStreamEvent>> => {\n try {\n await ensureStarted();\n } catch (err) {\n clearTimeout(timer);\n throw err;\n }\n while (queue.length === 0 && !done) {\n if (!reader) {\n clearTimeout(timer);\n throw new EngramError('Engram API: stream reader missing', 0, null);\n }\n const chunk = await reader.read();\n if (chunk.done) {\n // Flush whatever's left in the buffer (some servers don't\n // terminate with a trailing blank line).\n if (buffer.length > 0) {\n buffer += '\\n\\n';\n drainBuffer();\n }\n done = true;\n break;\n }\n buffer += decoder.decode(chunk.value, { stream: true });\n drainBuffer();\n }\n if (queue.length > 0) {\n return { value: queue.shift() as QueryStreamEvent, done: false };\n }\n clearTimeout(timer);\n if (pendingError) throw pendingError;\n return { value: undefined as unknown as QueryStreamEvent, done: true };\n },\n return: async (): Promise<IteratorResult<QueryStreamEvent>> => {\n // Caller broke out of the for-await loop — cancel the upstream\n // request so we're not holding the connection open.\n clearTimeout(timer);\n controller.abort();\n try {\n await reader?.cancel();\n } catch {\n /* ignored */\n }\n return { value: undefined as unknown as QueryStreamEvent, done: true };\n },\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"]}
|
|
1
|
+
{"version":3,"sources":["../src/types.ts","../src/client.ts"],"names":[],"mappings":";;;AAgOO,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;;;AC5NA,IAAM,gBAAA,GAAmB,wBAAA;AACzB,IAAM,kBAAA,GAAqB,GAAA;AAC3B,IAAM,yBAAA,GAA4B,GAAA;AAClC,IAAM,0BAAA,GAA6B,CAAA;AAGnC,IAAM,kBAAA,GAAqB,GAAA;AAC3B,IAAM,WAAA,GAAc,OAAA;AACpB,IAAM,UAAA,GAAa,aAAa,WAAW,CAAA,CAAA;AAE3C,SAAS,iBAAA,CAAkB,QAAuB,gBAAA,EAAkC;AAClF,EAAA,IAAI,MAAA,EAAQ;AACV,IAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,MAAA,CAAO,IAAA,EAAM,CAAA;AAClC,IAAA,IAAI,MAAA,CAAO,QAAA,CAAS,KAAK,CAAA,IAAK,SAAS,CAAA,EAAG;AACxC,MAAA,OAAO,IAAA,CAAK,GAAA,CAAI,KAAA,GAAQ,GAAA,EAAM,kBAAkB,CAAA;AAAA,IAClD;AAAA,EACF;AACA,EAAA,OAAO,IAAA,CAAK,GAAA,CAAI,gBAAA,EAAkB,kBAAkB,CAAA;AACtD;AAEA,SAAS,MAAM,EAAA,EAA2B;AACxC,EAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,YAAY,UAAA,CAAW,OAAA,EAAS,EAAE,CAAC,CAAA;AACzD;AAEO,IAAM,eAAN,MAAmB;AAAA,EACP,MAAA;AAAA,EACA,OAAA;AAAA,EACA,SAAA;AAAA,EACA,SAAA;AAAA,EACA,eAAA;AAAA,EACA,eAAA;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;AACtC,IAAA,IAAA,CAAK,eAAA,GAAkB,QAAQ,eAAA,IAAmB,yBAAA;AAClD,IAAA,IAAA,CAAK,kBAAkB,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,OAAA,CAAQ,mBAAmB,0BAA0B,CAAA;AAExF,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;AAOA,IAAA,MAAM,WAAA,GAAc,KAAK,IAAA,KAAS,MAAA,GAAY,KAAK,SAAA,CAAU,IAAA,CAAK,IAAI,CAAA,GAAI,MAAA;AAC1E,IAAA,IAAI,oBAAoB,IAAA,CAAK,eAAA;AAC7B,IAAA,IAAI,SAAA,GAAY,GAAA;AAGhB,IAAA,OAAO,IAAA,EAAM;AACX,MAAA,MAAM,UAAA,GAAa,IAAI,eAAA,EAAgB;AACvC,MAAA,MAAM,QAAQ,UAAA,CAAW,MAAM,WAAW,KAAA,EAAM,EAAG,KAAK,SAAS,CAAA;AAEjE,MAAA,IAAI,GAAA;AACJ,MAAA,IAAI;AACF,QAAA,GAAA,GAAM,MAAM,IAAA,CAAK,SAAA,CAAU,GAAA,CAAI,UAAS,EAAG;AAAA,UACzC,QAAQ,IAAA,CAAK,MAAA;AAAA,UACb,OAAA,EAAS;AAAA,YACP,aAAA,EAAe,CAAA,OAAA,EAAU,IAAA,CAAK,MAAM,CAAA,CAAA;AAAA,YACpC,cAAA,EAAgB,kBAAA;AAAA,YAChB,YAAA,EAAc;AAAA,WAChB;AAAA,UACA,IAAA,EAAM,WAAA;AAAA,UACN,QAAQ,UAAA,CAAW;AAAA,SACpB,CAAA;AAAA,MACH,CAAA,SAAE;AACA,QAAA,YAAA,CAAa,KAAK,CAAA;AAAA,MACpB;AAEA,MAAA,IAAI,GAAA,CAAI,MAAA,KAAW,GAAA,IAAO,iBAAA,GAAoB,CAAA,EAAG;AAE/C,QAAA,MAAM,GAAA,CAAI,IAAA,EAAK,CAAE,KAAA,CAAM,MAAM,MAAS,CAAA;AACtC,QAAA,MAAM,QAAQ,iBAAA,CAAkB,GAAA,CAAI,QAAQ,GAAA,CAAI,aAAa,GAAG,SAAS,CAAA;AACzE,QAAA,MAAM,MAAM,KAAK,CAAA;AACjB,QAAA,iBAAA,IAAqB,CAAA;AACrB,QAAA,SAAA,GAAY,IAAA,CAAK,GAAA,CAAI,SAAA,GAAY,CAAA,EAAG,kBAAkB,CAAA;AACtD,QAAA;AAAA,MACF;AAEA,MAAA,MAAM,IAAA,GAAO,MAAM,GAAA,CAAI,IAAA,EAAK;AAC5B,MAAA,IAAI,MAAA,GAAkB,MAAA;AACtB,MAAA,IAAI,IAAA,EAAM;AACR,QAAA,IAAI;AACF,UAAA,MAAA,GAAS,IAAA,CAAK,MAAM,IAAI,CAAA;AAAA,QAC1B,CAAA,CAAA,MAAQ;AACN,UAAA,MAAA,GAAS,IAAA;AAAA,QACX;AAAA,MACF;AAEA,MAAA,IAAI,CAAC,IAAI,EAAA,EAAI;AACX,QAAA,MAAM,MAAA,GACJ,MAAA,IAAU,OAAO,MAAA,KAAW,QAAA,IAAY,WAAW,IAAA,IAAQ,OAAA,IAAW,MAAA,GACjE,MAAA,CAA8B,KAAA,GAC/B,MAAA;AACN,QAAA,MAAM,IAAI,WAAA;AAAA,UACR,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,UAC/F,GAAA,CAAI,MAAA;AAAA,UACJ;AAAA,SACF;AAAA,MACF;AAEA,MAAA,OAAO,MAAA;AAAA,IACT;AAAA,EACF;AAAA;AAAA,EAIA,MAAM,WAAA,CACJ,OAAA,EACA,SAAiB,SAAA,EACjB,OAAA,GAAmC,EAAC,EACR;AAC5B,IAAA,MAAM,IAAA,GAAgC,EAAE,OAAA,EAAQ;AAChD,IAAA,IAAI,OAAA,CAAQ,KAAA,KAAU,MAAA,EAAW,IAAA,CAAK,QAAQ,OAAA,CAAQ,KAAA;AACtD,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;AAAK,KACzB;AAAA,EACF;AAAA,EAEA,MAAM,aAAA,CACJ,QAAA,EACA,MAAA,GAAiB,SAAA,EAC2B;AAI5C,IAAA,MAAM,MAAA,GAAS,MAAM,IAAA,CAAK,OAAA;AAAA,MACxB,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;AACA,IAAA,OAAO,MAAM,OAAA,CAAQ,MAAM,IAAI,EAAE,QAAA,EAAU,QAAO,GAAI,MAAA;AAAA,EACxD;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,EAA8C;AAChE,IAAA,MAAM,GAAA,GAAM,MAAM,IAAA,CAAK,OAAA;AAAA,MACrB,CAAA,YAAA,EAAe,kBAAA,CAAmB,MAAM,CAAC,CAAA,SAAA,CAAA;AAAA,MACzC,EAAE,QAAQ,QAAA;AAAS,KACrB;AAIA,IAAA,OAAO,GAAA,IAAO,EAAE,OAAA,EAAS,IAAA,EAAM,eAAe,CAAA,EAAE;AAAA,EAClD;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,MAAM,IAAA,GAAgC;AAAA,MACpC,KAAA,EAAO,QAAQ,IAAA,IAAQ,CAAA;AAAA,MACvB,kBAAA,EAAoB,QAAQ,iBAAA,IAAqB,IAAA;AAAA,MACjD,cAAA,EAAgB,QAAQ,aAAA,IAAiB;AAAA,KAC3C;AACA,IAAA,IAAI,OAAA,CAAQ,SAAA,KAAc,MAAA,EAAW,IAAA,CAAK,aAAa,OAAA,CAAQ,SAAA;AAC/D,IAAA,IAAI,OAAA,CAAQ,2BAA2B,MAAA,EAAW;AAChD,MAAA,IAAA,CAAK,2BAA2B,OAAA,CAAQ,sBAAA;AAAA,IAC1C;AACA,IAAA,IAAI,OAAA,CAAQ,aAAA,KAAkB,MAAA,EAAW,IAAA,CAAK,mBAAmB,OAAA,CAAQ,aAAA;AACzE,IAAA,IAAI,OAAA,CAAQ,YAAA,KAAiB,MAAA,EAAW,IAAA,CAAK,gBAAgB,OAAA,CAAQ,YAAA;AACrE,IAAA,IAAI,OAAA,CAAQ,cAAA,KAAmB,MAAA,EAAW,IAAA,CAAK,kBAAkB,OAAA,CAAQ,cAAA;AACzE,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;AACX,KACD,CAAA;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcA,WAAA,CAAY,QAAA,EAAkB,OAAA,GAAwB,EAAC,EAAoC;AACzF,IAAA,MAAM,OAAA,GAAU,OAAA,CAAQ,OAAA,IAAW,CAAC,SAAS,CAAA;AAC7C,IAAA,MAAM,IAAA,GAAgC;AAAA,MACpC,KAAA,EAAO,QAAQ,IAAA,IAAQ,CAAA;AAAA,MACvB,kBAAA,EAAoB,QAAQ,iBAAA,IAAqB,IAAA;AAAA,MACjD,cAAA,EAAgB,QAAQ,aAAA,IAAiB;AAAA,KAC3C;AACA,IAAA,IAAI,OAAA,CAAQ,SAAA,KAAc,MAAA,EAAW,IAAA,CAAK,aAAa,OAAA,CAAQ,SAAA;AAC/D,IAAA,IAAI,OAAA,CAAQ,2BAA2B,MAAA,EAAW;AAChD,MAAA,IAAA,CAAK,2BAA2B,OAAA,CAAQ,sBAAA;AAAA,IAC1C;AACA,IAAA,IAAI,OAAA,CAAQ,aAAA,KAAkB,MAAA,EAAW,IAAA,CAAK,mBAAmB,OAAA,CAAQ,aAAA;AACzE,IAAA,IAAI,OAAA,CAAQ,YAAA,KAAiB,MAAA,EAAW,IAAA,CAAK,gBAAgB,OAAA,CAAQ,YAAA;AACrE,IAAA,IAAI,OAAA,CAAQ,cAAA,KAAmB,MAAA,EAAW,IAAA,CAAK,kBAAkB,OAAA,CAAQ,cAAA;AACzE,IAAA,MAAM,IAAA,GAAO;AAAA,MACX,KAAA,EAAO,QAAA;AAAA,MACP,OAAA;AAAA,MACA,MAAA,EAAQ,IAAA;AAAA,MACR,OAAA,EAAS;AAAA,KACX;AACA,IAAA,MAAM,GAAA,GAAM,CAAA,EAAG,IAAA,CAAK,OAAO,CAAA,SAAA,CAAA;AAC3B,IAAA,MAAM,SAAS,IAAA,CAAK,MAAA;AACpB,IAAA,MAAM,YAAY,IAAA,CAAK,SAAA;AACvB,IAAA,MAAM,YAAY,IAAA,CAAK,eAAA;AACvB,IAAA,MAAM,kBAAkB,IAAA,CAAK,eAAA;AAC7B,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,SAAA,CAAU,IAAI,CAAA;AAEpC,IAAA,OAAO;AAAA,MACL,CAAC,MAAA,CAAO,aAAa,GAAG,MAAM;AAC5B,QAAA,MAAM,UAAA,GAAa,IAAI,eAAA,EAAgB;AAIvC,QAAA,MAAM,QAAQ,UAAA,CAAW,MAAM,UAAA,CAAW,KAAA,IAAS,SAAS,CAAA;AAE5D,QAAA,IAAI,OAAA,GAAU,KAAA;AACd,QAAA,IAAI,MAAA,GAAyD,IAAA;AAC7D,QAAA,MAAM,OAAA,GAAU,IAAI,WAAA,CAAY,OAAO,CAAA;AACvC,QAAA,IAAI,MAAA,GAAS,EAAA;AACb,QAAA,IAAI,IAAA,GAAO,KAAA;AACX,QAAA,MAAM,QAA4B,EAAC;AACnC,QAAA,IAAI,YAAA,GAAwB,IAAA;AAE5B,QAAA,MAAM,gBAAgB,YAA2B;AAC/C,UAAA,IAAI,OAAA,EAAS;AACb,UAAA,OAAA,GAAU,IAAA;AAIV,UAAA,IAAI,iBAAA,GAAoB,eAAA;AACxB,UAAA,IAAI,SAAA,GAAY,GAAA;AAEhB,UAAA,OAAO,IAAA,EAAM;AACX,YAAA,MAAM,GAAA,GAAM,MAAM,SAAA,CAAU,GAAA,EAAK;AAAA,cAC/B,MAAA,EAAQ,MAAA;AAAA,cACR,OAAA,EAAS;AAAA,gBACP,aAAA,EAAe,UAAU,MAAM,CAAA,CAAA;AAAA,gBAC/B,cAAA,EAAgB,kBAAA;AAAA,gBAChB,MAAA,EAAQ,mBAAA;AAAA,gBACR,YAAA,EAAc;AAAA,eAChB;AAAA,cACA,IAAA,EAAM,QAAA;AAAA,cACN,QAAQ,UAAA,CAAW;AAAA,aACpB,CAAA;AACD,YAAA,IAAI,GAAA,CAAI,MAAA,KAAW,GAAA,IAAO,iBAAA,GAAoB,CAAA,EAAG;AAC/C,cAAA,MAAM,GAAA,CAAI,IAAA,EAAK,CAAE,KAAA,CAAM,MAAM,MAAS,CAAA;AACtC,cAAA,MAAM,QAAQ,iBAAA,CAAkB,GAAA,CAAI,QAAQ,GAAA,CAAI,aAAa,GAAG,SAAS,CAAA;AACzE,cAAA,MAAM,MAAM,KAAK,CAAA;AACjB,cAAA,iBAAA,IAAqB,CAAA;AACrB,cAAA,SAAA,GAAY,IAAA,CAAK,GAAA,CAAI,SAAA,GAAY,CAAA,EAAG,kBAAkB,CAAA;AACtD,cAAA;AAAA,YACF;AACA,YAAA,IAAI,CAAC,IAAI,EAAA,EAAI;AACX,cAAA,MAAM,OAAO,MAAM,GAAA,CAAI,MAAK,CAAE,KAAA,CAAM,MAAM,EAAE,CAAA;AAC5C,cAAA,IAAI,MAAA,GAAkB,IAAA;AACtB,cAAA,IAAI;AACF,gBAAA,MAAA,GAAS,IAAA,GAAO,IAAA,CAAK,KAAA,CAAM,IAAI,CAAA,GAAI,IAAA;AAAA,cACrC,CAAA,CAAA,MAAQ;AAAA,cAER;AACA,cAAA,MAAM,MAAA,GACJ,MAAA,IAAU,OAAO,MAAA,KAAW,QAAA,IAAY,WAAW,IAAA,IAAQ,OAAA,IAAW,MAAA,GACjE,MAAA,CAA8B,KAAA,GAC/B,MAAA;AACN,cAAA,MAAM,IAAI,WAAA;AAAA,gBACR,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,gBAC/F,GAAA,CAAI,MAAA;AAAA,gBACJ;AAAA,eACF;AAAA,YACF;AACA,YAAA,IAAI,CAAC,IAAI,IAAA,EAAM;AACb,cAAA,MAAM,IAAI,WAAA,CAAY,4CAAA,EAA8C,GAAA,CAAI,QAAQ,IAAI,CAAA;AAAA,YACtF;AACA,YAAA,MAAA,GAAS,GAAA,CAAI,KAAK,SAAA,EAAU;AAC5B,YAAA;AAAA,UACF;AAAA,QACF,CAAA;AAEA,QAAA,MAAM,cAAc,MAAY;AAI9B,UAAA,IAAI,GAAA;AACJ,UAAA,OAAA,CAAQ,GAAA,GAAM,MAAA,CAAO,OAAA,CAAQ,MAAM,OAAO,EAAA,EAAI;AAC5C,YAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,KAAA,CAAM,CAAA,EAAG,GAAG,CAAA;AACjC,YAAA,MAAA,GAAS,MAAA,CAAO,KAAA,CAAM,GAAA,GAAM,CAAC,CAAA;AAC7B,YAAA,MAAM,YAAsB,EAAC;AAC7B,YAAA,KAAA,MAAW,OAAA,IAAW,KAAA,CAAM,KAAA,CAAM,IAAI,CAAA,EAAG;AACvC,cAAA,MAAM,IAAA,GAAO,QAAQ,QAAA,CAAS,IAAI,IAAI,OAAA,CAAQ,KAAA,CAAM,CAAA,EAAG,EAAE,CAAA,GAAI,OAAA;AAC7D,cAAA,IAAI,IAAA,CAAK,UAAA,CAAW,QAAQ,CAAA,EAAG;AAC7B,gBAAA,SAAA,CAAU,IAAA,CAAK,IAAA,CAAK,KAAA,CAAM,CAAC,CAAC,CAAA;AAAA,cAC9B,CAAA,MAAA,IAAW,IAAA,CAAK,UAAA,CAAW,OAAO,CAAA,EAAG;AACnC,gBAAA,SAAA,CAAU,IAAA,CAAK,IAAA,CAAK,KAAA,CAAM,CAAC,CAAC,CAAA;AAAA,cAC9B;AAAA,YACF;AACA,YAAA,IAAI,SAAA,CAAU,WAAW,CAAA,EAAG;AAC5B,YAAA,MAAM,UAAA,GAAa,SAAA,CAAU,IAAA,CAAK,IAAI,CAAA;AACtC,YAAA,IAAI,eAAe,QAAA,EAAU;AAC3B,cAAA,IAAA,GAAO,IAAA;AACP,cAAA;AAAA,YACF;AACA,YAAA,IAAI,OAAA;AACJ,YAAA,IAAI;AACF,cAAA,OAAA,GAAU,IAAA,CAAK,MAAM,UAAU,CAAA;AAAA,YACjC,CAAA,CAAA,MAAQ;AAEN,cAAA;AAAA,YACF;AACA,YAAA,IAAI,OAAA,IAAW,OAAO,OAAA,KAAY,QAAA,EAAU;AAC1C,cAAA,MAAM,GAAA,GAAM,OAAA;AACZ,cAAA,IAAI,IAAI,KAAA,EAAO;AACb,gBAAA,YAAA,GAAe,IAAI,WAAA,CAAY,MAAA,CAAO,IAAI,KAAK,CAAA,EAAG,GAAG,GAAG,CAAA;AACxD,gBAAA,IAAA,GAAO,IAAA;AACP,gBAAA;AAAA,cACF;AAEA,cAAA,MAAM,UAAU,GAAA,CAAI,OAAA;AACpB,cAAA,IAAI,MAAM,OAAA,CAAQ,OAAO,CAAA,IAAK,OAAA,CAAQ,SAAS,CAAA,EAAG;AAChD,gBAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,CAAC,CAAA,EAAG,KAAA,EAAO,OAAA;AACjC,gBAAA,IAAI,OAAO,KAAA,KAAU,QAAA,IAAY,KAAA,CAAM,SAAS,CAAA,EAAG;AACjD,kBAAA,KAAA,CAAM,KAAK,EAAE,IAAA,EAAM,OAAA,EAAS,OAAA,EAAS,OAAO,CAAA;AAAA,gBAC9C;AACA,gBAAA;AAAA,cACF;AAEA,cAAA,KAAA,CAAM,KAAK,EAAE,IAAA,EAAM,MAAA,EAAQ,GAAI,KAAmE,CAAA;AAAA,YACpG;AAAA,UACF;AAAA,QACF,CAAA;AAEA,QAAA,OAAO;AAAA,UACL,MAAM,YAAuD;AAC3D,YAAA,IAAI;AACF,cAAA,MAAM,aAAA,EAAc;AAAA,YACtB,SAAS,GAAA,EAAK;AACZ,cAAA,YAAA,CAAa,KAAK,CAAA;AAClB,cAAA,MAAM,GAAA;AAAA,YACR;AACA,YAAA,OAAO,KAAA,CAAM,MAAA,KAAW,CAAA,IAAK,CAAC,IAAA,EAAM;AAClC,cAAA,IAAI,CAAC,MAAA,EAAQ;AACX,gBAAA,YAAA,CAAa,KAAK,CAAA;AAClB,gBAAA,MAAM,IAAI,WAAA,CAAY,mCAAA,EAAqC,CAAA,EAAG,IAAI,CAAA;AAAA,cACpE;AACA,cAAA,MAAM,KAAA,GAAQ,MAAM,MAAA,CAAO,IAAA,EAAK;AAChC,cAAA,IAAI,MAAM,IAAA,EAAM;AAGd,gBAAA,IAAI,MAAA,CAAO,SAAS,CAAA,EAAG;AACrB,kBAAA,MAAA,IAAU,MAAA;AACV,kBAAA,WAAA,EAAY;AAAA,gBACd;AACA,gBAAA,IAAA,GAAO,IAAA;AACP,gBAAA;AAAA,cACF;AACA,cAAA,MAAA,IAAU,QAAQ,MAAA,CAAO,KAAA,CAAM,OAAO,EAAE,MAAA,EAAQ,MAAM,CAAA;AACtD,cAAA,WAAA,EAAY;AAAA,YACd;AACA,YAAA,IAAI,KAAA,CAAM,SAAS,CAAA,EAAG;AACpB,cAAA,OAAO,EAAE,KAAA,EAAO,KAAA,CAAM,KAAA,EAAM,EAAuB,MAAM,KAAA,EAAM;AAAA,YACjE;AACA,YAAA,YAAA,CAAa,KAAK,CAAA;AAClB,YAAA,IAAI,cAAc,MAAM,YAAA;AACxB,YAAA,OAAO,EAAE,KAAA,EAAO,MAAA,EAA0C,IAAA,EAAM,IAAA,EAAK;AAAA,UACvE,CAAA;AAAA,UACA,QAAQ,YAAuD;AAG7D,YAAA,YAAA,CAAa,KAAK,CAAA;AAClB,YAAA,UAAA,CAAW,KAAA,EAAM;AACjB,YAAA,IAAI;AACF,cAAA,MAAM,QAAQ,MAAA,EAAO;AAAA,YACvB,CAAA,CAAA,MAAQ;AAAA,YAER;AACA,YAAA,OAAO,EAAE,KAAA,EAAO,MAAA,EAA0C,IAAA,EAAM,IAAA,EAAK;AAAA,UACvE;AAAA,SACF;AAAA,MACF;AAAA,KACF;AAAA,EACF;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.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 for buffered (non-streaming) calls.\n * Defaults to 30000 (30s).\n */\n timeoutMs?: number;\n /**\n * Timeout in milliseconds for `queryStream` calls. Streaming responses\n * can sit in the prep phase (retrieval + extractor pass) for 5–15s\n * before the first synthesis token arrives, so the buffered 30s\n * default would leave no headroom for the streamed body. Defaults to\n * 300000 (5 min). Use a higher value for very large synthesis bodies.\n */\n streamTimeoutMs?: number;\n /**\n * How many times to retry on a 429 (per-tenant concurrent-request cap).\n * Honors the server's `Retry-After` header, capped at 30s per sleep.\n * Defaults to 3. Set to 0 to disable retry and surface 429 as `EngramError`\n * on the first attempt.\n */\n maxRetriesOn429?: number;\n}\n\nexport interface Bucket {\n id: string;\n name: string;\n /**\n * Mirror of `name`. The server emits both so callers iterating both\n * `listBuckets` and `storeMemory` responses can use one field name.\n * Prefer `name` in new code.\n */\n bucket_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 type StoreStatus = 'stored' | 'merged';\n\nexport type MergeReason =\n | 'content_hash'\n | 'embedding_similarity'\n | 'conflict_keep_existing'\n | 'concurrent_insert_race';\n\nexport interface StoreMemoryResult {\n id: string;\n /**\n * Alias for `id` — older API docs / older SDKs referenced this name.\n * Always present; prefer `id` in new code.\n */\n memory_id?: string;\n bucket_name: string;\n token_count: number;\n /**\n * `\"stored\"` for fresh writes, `\"merged\"` when the server collapsed\n * this write into a pre-existing memory via dedup. Always present.\n */\n status?: StoreStatus;\n /** Present only when `status === \"merged\"`. ID of the canonical memory the write was absorbed into. */\n deduped_into?: string;\n /** Present only when `status === \"merged\"`. Similarity score in [0.0, 1.0] (1.0 for content-hash matches). */\n similarity_score?: number;\n /** Present only when `status === \"merged\"`. Reason for the merge. */\n merge_reason?: MergeReason;\n}\n\n/**\n * Dedup policy passed to `storeMemory`. The server's default (currently\n * `\"loose\"`) applies when omitted.\n *\n * - `\"off\"` — store every write as a new memory; useful for templated\n * time-series ingest where structurally similar rows carry unique\n * values and would otherwise collapse.\n * - `\"loose\"` — merge writes at similarity ≥ 0.95 (default).\n * - `\"strict\"` — only merge near-identical content (≥ 0.99).\n */\nexport type DedupPolicy = 'off' | 'loose' | 'strict';\n\nexport interface ClearMemoriesResult {\n success: boolean;\n /** Number of memories actually deleted (server-reported). */\n cleared_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 /**\n * Parsed JSON when the request set `returnFormat: 'json'`. Present\n * only on JSON queries — the parsed value (object / array / scalar)\n * on success, or `null` when the model returned malformed JSON.\n */\n answer_json?: unknown;\n /**\n * Top-level count of retrieved memories. Equivalent to\n * `result.explanation?.retrieved_memories.length` but present even\n * when `returnExplanation` is false.\n */\n memories_found?: number;\n explanation?: QueryExplanation;\n usage?: QueryUsage;\n}\n\n/**\n * One frame yielded by {@link EngramClient.queryStream}.\n *\n * The shape is discriminated by `type`:\n * - `delta` frames carry an incremental piece of the answer in `content`.\n * - `done` carries the final usage + (optional) explanation. Emitted\n * exactly once at the end of the stream.\n */\nexport type QueryStreamEvent =\n | { type: 'delta'; content: string }\n | {\n type: 'done';\n usage?: QueryUsage;\n synthesis_usage?: unknown;\n explanation?: QueryExplanation;\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 per bucket. Defaults to 8.\n * Used as the fallback K when `topKPerBucket` doesn't cover a bucket.\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 * Cap synthesis output tokens. Default is the server's (currently\n * 8192). Lower for agent loops or cost control.\n */\n maxTokens?: number;\n /**\n * Floor for retrieval scores. When set, drops retrieved chunks\n * below this raw cosine similarity — useful for citations-grade\n * output where every chunk should actually match.\n */\n minSimilarityThreshold?: number;\n /**\n * Per-bucket retrieval depth. `number` for a uniform value across\n * all buckets; an object for explicit per-bucket K (e.g.\n * `{ edgar_AAPL: 20, prices_AAPL: 4 }`). Missing buckets fall back\n * to `topK`. Lets callers express \"deep retrieval on this one,\n * shallow on the others.\"\n */\n topKPerBucket?: number | Record<string, number>;\n /**\n * `'prose'` (default) or `'json'`. When `'json'`, the server asks\n * the synthesizer for JSON output and returns the parsed value\n * under `result.answer_json` alongside the raw `result.answer`.\n */\n returnFormat?: 'prose' | 'json';\n /**\n * Optional JSON Schema describing the desired output shape. Included\n * in the prompt to guide the model. Best-effort — validate\n * client-side if you need strict enforcement.\n */\n responseSchema?: Record<string, unknown>;\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 ClearMemoriesResult,\n type DedupPolicy,\n type EngramClientOptions,\n type ListMemoriesOptions,\n type ListMemoriesResult,\n type QueryOptions,\n type QueryResult,\n type QueryStreamEvent,\n type StoreMemoryResult,\n} from './types.js';\n\nconst DEFAULT_BASE_URL = 'https://api.lumetra.io';\nconst DEFAULT_TIMEOUT_MS = 30_000;\nconst DEFAULT_STREAM_TIMEOUT_MS = 300_000;\nconst DEFAULT_MAX_RETRIES_ON_429 = 3;\n// Cap on per-attempt backoff so a misconfigured server can't force\n// callers to sleep for minutes.\nconst RETRY_AFTER_CAP_MS = 30_000;\nconst SDK_VERSION = '0.5.0';\nconst USER_AGENT = `engram-js/${SDK_VERSION}`;\n\nfunction parseRetryAfterMs(header: string | null, defaultBackoffMs: number): number {\n if (header) {\n const value = Number(header.trim());\n if (Number.isFinite(value) && value >= 0) {\n return Math.min(value * 1000, RETRY_AFTER_CAP_MS);\n }\n }\n return Math.min(defaultBackoffMs, RETRY_AFTER_CAP_MS);\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\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 private readonly streamTimeoutMs: number;\n private readonly maxRetriesOn429: 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 this.streamTimeoutMs = options.streamTimeoutMs ?? DEFAULT_STREAM_TIMEOUT_MS;\n this.maxRetriesOn429 = Math.max(0, options.maxRetriesOn429 ?? DEFAULT_MAX_RETRIES_ON_429);\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 // 429-aware retry. The Engram API enforces a per-tenant concurrent-\n // request cap and sets Retry-After on 429s; without retry handling,\n // bursty clients fail immediately under load. The body is JSON-\n // serialized once outside the loop so each attempt sends an\n // identical request.\n const requestBody = init.body !== undefined ? JSON.stringify(init.body) : undefined;\n let attemptsRemaining = this.maxRetriesOn429;\n let backoffMs = 1000;\n\n // eslint-disable-next-line no-constant-condition\n while (true) {\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 'User-Agent': USER_AGENT,\n },\n body: requestBody,\n signal: controller.signal,\n });\n } finally {\n clearTimeout(timer);\n }\n\n if (res.status === 429 && attemptsRemaining > 0) {\n // Drain the body so the connection can return to the pool.\n await res.text().catch(() => undefined);\n const delay = parseRetryAfterMs(res.headers.get('Retry-After'), backoffMs);\n await sleep(delay);\n attemptsRemaining -= 1;\n backoffMs = Math.min(backoffMs * 2, RETRY_AFTER_CAP_MS);\n continue;\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\n // ---------- Memories ----------\n\n async storeMemory(\n content: string,\n bucket: string = 'default',\n options: { dedup?: DedupPolicy } = {},\n ): Promise<StoreMemoryResult> {\n const body: Record<string, unknown> = { content };\n if (options.dedup !== undefined) body.dedup = options.dedup;\n return this.request<StoreMemoryResult>(\n `/v1/buckets/${encodeURIComponent(bucket)}/memories`,\n { method: 'POST', body },\n );\n }\n\n async storeMemories(\n contents: string[],\n bucket: string = 'default',\n ): Promise<{ memories: StoreMemoryResult[] }> {\n // Defensively unwrap: depending on server version the batch endpoint\n // returns either { memories: [...] } or a bare array. Normalize to the\n // wrapped shape so callers don't have to switch on it.\n const result = await this.request<{ memories: StoreMemoryResult[] } | StoreMemoryResult[]>(\n `/v1/buckets/${encodeURIComponent(bucket)}/memories`,\n { method: 'POST', body: { memories: contents.map((content) => ({ content })) } },\n );\n return Array.isArray(result) ? { memories: result } : result;\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<ClearMemoriesResult> {\n const res = await this.request<ClearMemoriesResult>(\n `/v1/buckets/${encodeURIComponent(bucket)}/memories`,\n { method: 'DELETE' },\n );\n // Defensive default: older servers / proxies may strip the body. The\n // contract surface is {success, cleared_count}; if the server stayed\n // silent we still return the same shape so callers can rely on it.\n return res ?? { success: true, cleared_count: 0 };\n }\n\n // ---------- Query ----------\n\n async query(question: string, options: QueryOptions = {}): Promise<QueryResult> {\n const buckets = options.buckets ?? ['default'];\n const opts: Record<string, unknown> = {\n top_k: options.topK ?? 8,\n return_explanation: options.returnExplanation ?? true,\n skip_synthesis: options.skipSynthesis ?? false,\n };\n if (options.maxTokens !== undefined) opts.max_tokens = options.maxTokens;\n if (options.minSimilarityThreshold !== undefined) {\n opts.min_similarity_threshold = options.minSimilarityThreshold;\n }\n if (options.topKPerBucket !== undefined) opts.top_k_per_bucket = options.topKPerBucket;\n if (options.returnFormat !== undefined) opts.return_format = options.returnFormat;\n if (options.responseSchema !== undefined) opts.response_schema = options.responseSchema;\n return this.request<QueryResult>('/v1/query', {\n method: 'POST',\n body: {\n query: question,\n buckets,\n options: opts,\n },\n });\n }\n\n /**\n * Streaming variant of {@link query}. Returns an async-iterable that\n * yields {@link QueryStreamEvent} frames as the server produces them:\n *\n * for await (const ev of engram.queryStream('...')) {\n * if (ev.type === 'delta') process.stdout.write(ev.content);\n * else if (ev.type === 'done') console.log(ev.usage);\n * }\n *\n * Break out of the loop to abort the request (the underlying\n * AbortController is wired up to the fetch call).\n */\n queryStream(question: string, options: QueryOptions = {}): AsyncIterable<QueryStreamEvent> {\n const buckets = options.buckets ?? ['default'];\n const opts: Record<string, unknown> = {\n top_k: options.topK ?? 8,\n return_explanation: options.returnExplanation ?? true,\n skip_synthesis: options.skipSynthesis ?? false,\n };\n if (options.maxTokens !== undefined) opts.max_tokens = options.maxTokens;\n if (options.minSimilarityThreshold !== undefined) {\n opts.min_similarity_threshold = options.minSimilarityThreshold;\n }\n if (options.topKPerBucket !== undefined) opts.top_k_per_bucket = options.topKPerBucket;\n if (options.returnFormat !== undefined) opts.return_format = options.returnFormat;\n if (options.responseSchema !== undefined) opts.response_schema = options.responseSchema;\n const body = {\n query: question,\n buckets,\n stream: true,\n options: opts,\n };\n const url = `${this.baseUrl}/v1/query`;\n const apiKey = this.apiKey;\n const fetchImpl = this.fetchImpl;\n const timeoutMs = this.streamTimeoutMs;\n const maxRetriesOn429 = this.maxRetriesOn429;\n const bodyJson = JSON.stringify(body);\n\n return {\n [Symbol.asyncIterator]: () => {\n const controller = new AbortController();\n // The timeout caps total wall-clock for the stream. Set generously\n // because synthesis can run 10–25s before the first byte even with\n // streaming on slow paths; clamp to the user's configured timeout.\n const timer = setTimeout(() => controller.abort(), timeoutMs);\n\n let started = false;\n let reader: ReadableStreamDefaultReader<Uint8Array> | null = null;\n const decoder = new TextDecoder('utf-8');\n let buffer = '';\n let done = false;\n const queue: QueryStreamEvent[] = [];\n let pendingError: unknown = null;\n\n const ensureStarted = async (): Promise<void> => {\n if (started) return;\n started = true;\n // 429-aware retry at the connection-open stage only. Once\n // the response body starts flowing we can't resume mid-\n // stream safely.\n let attemptsRemaining = maxRetriesOn429;\n let backoffMs = 1000;\n // eslint-disable-next-line no-constant-condition\n while (true) {\n const res = await fetchImpl(url, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${apiKey}`,\n 'Content-Type': 'application/json',\n Accept: 'text/event-stream',\n 'User-Agent': USER_AGENT,\n },\n body: bodyJson,\n signal: controller.signal,\n });\n if (res.status === 429 && attemptsRemaining > 0) {\n await res.text().catch(() => undefined);\n const delay = parseRetryAfterMs(res.headers.get('Retry-After'), backoffMs);\n await sleep(delay);\n attemptsRemaining -= 1;\n backoffMs = Math.min(backoffMs * 2, RETRY_AFTER_CAP_MS);\n continue;\n }\n if (!res.ok) {\n const text = await res.text().catch(() => '');\n let parsed: unknown = text;\n try {\n parsed = text ? JSON.parse(text) : text;\n } catch {\n /* keep raw text */\n }\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 if (!res.body) {\n throw new EngramError('Engram API: streaming response has no body', res.status, null);\n }\n reader = res.body.getReader();\n return;\n }\n };\n\n const drainBuffer = (): void => {\n // SSE frames are separated by a blank line ('\\n\\n'). Each frame\n // is one or more 'field: value' lines. We only care about\n // 'data:' lines for this stream.\n let idx: number;\n while ((idx = buffer.indexOf('\\n\\n')) !== -1) {\n const frame = buffer.slice(0, idx);\n buffer = buffer.slice(idx + 2);\n const dataLines: string[] = [];\n for (const rawLine of frame.split('\\n')) {\n const line = rawLine.endsWith('\\r') ? rawLine.slice(0, -1) : rawLine;\n if (line.startsWith('data: ')) {\n dataLines.push(line.slice(6));\n } else if (line.startsWith('data:')) {\n dataLines.push(line.slice(5));\n }\n }\n if (dataLines.length === 0) continue;\n const payloadStr = dataLines.join('\\n');\n if (payloadStr === '[DONE]') {\n done = true;\n return;\n }\n let payload: unknown;\n try {\n payload = JSON.parse(payloadStr);\n } catch {\n // Malformed frame — skip rather than corrupt the stream.\n continue;\n }\n if (payload && typeof payload === 'object') {\n const obj = payload as Record<string, unknown>;\n if (obj.error) {\n pendingError = new EngramError(String(obj.error), 0, obj);\n done = true;\n return;\n }\n // OpenAI-style delta chunk\n const choices = obj.choices as Array<{ delta?: { content?: string } }> | undefined;\n if (Array.isArray(choices) && choices.length > 0) {\n const delta = choices[0]?.delta?.content;\n if (typeof delta === 'string' && delta.length > 0) {\n queue.push({ type: 'delta', content: delta });\n }\n continue;\n }\n // Final usage / explanation frame (no 'choices' key).\n queue.push({ type: 'done', ...(obj as Omit<Extract<QueryStreamEvent, { type: 'done' }>, 'type'>) });\n }\n }\n };\n\n return {\n next: async (): Promise<IteratorResult<QueryStreamEvent>> => {\n try {\n await ensureStarted();\n } catch (err) {\n clearTimeout(timer);\n throw err;\n }\n while (queue.length === 0 && !done) {\n if (!reader) {\n clearTimeout(timer);\n throw new EngramError('Engram API: stream reader missing', 0, null);\n }\n const chunk = await reader.read();\n if (chunk.done) {\n // Flush whatever's left in the buffer (some servers don't\n // terminate with a trailing blank line).\n if (buffer.length > 0) {\n buffer += '\\n\\n';\n drainBuffer();\n }\n done = true;\n break;\n }\n buffer += decoder.decode(chunk.value, { stream: true });\n drainBuffer();\n }\n if (queue.length > 0) {\n return { value: queue.shift() as QueryStreamEvent, done: false };\n }\n clearTimeout(timer);\n if (pendingError) throw pendingError;\n return { value: undefined as unknown as QueryStreamEvent, done: true };\n },\n return: async (): Promise<IteratorResult<QueryStreamEvent>> => {\n // Caller broke out of the for-await loop — cancel the upstream\n // request so we're not holding the connection open.\n clearTimeout(timer);\n controller.abort();\n try {\n await reader?.cancel();\n } catch {\n /* ignored */\n }\n return { value: undefined as unknown as QueryStreamEvent, done: true };\n },\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
CHANGED
|
@@ -110,6 +110,12 @@ interface QueryUsage {
|
|
|
110
110
|
}
|
|
111
111
|
interface QueryResult {
|
|
112
112
|
answer: string;
|
|
113
|
+
/**
|
|
114
|
+
* Parsed JSON when the request set `returnFormat: 'json'`. Present
|
|
115
|
+
* only on JSON queries — the parsed value (object / array / scalar)
|
|
116
|
+
* on success, or `null` when the model returned malformed JSON.
|
|
117
|
+
*/
|
|
118
|
+
answer_json?: unknown;
|
|
113
119
|
/**
|
|
114
120
|
* Top-level count of retrieved memories. Equivalent to
|
|
115
121
|
* `result.explanation?.retrieved_memories.length` but present even
|
|
@@ -142,7 +148,8 @@ interface QueryOptions {
|
|
|
142
148
|
*/
|
|
143
149
|
buckets?: string[];
|
|
144
150
|
/**
|
|
145
|
-
* Maximum number of memories to retrieve. Defaults to 8.
|
|
151
|
+
* Maximum number of memories to retrieve per bucket. Defaults to 8.
|
|
152
|
+
* Used as the fallback K when `topKPerBucket` doesn't cover a bucket.
|
|
146
153
|
*/
|
|
147
154
|
topK?: number;
|
|
148
155
|
/**
|
|
@@ -154,6 +161,37 @@ interface QueryOptions {
|
|
|
154
161
|
* Whether to populate the `explanation` field. Defaults to true.
|
|
155
162
|
*/
|
|
156
163
|
returnExplanation?: boolean;
|
|
164
|
+
/**
|
|
165
|
+
* Cap synthesis output tokens. Default is the server's (currently
|
|
166
|
+
* 8192). Lower for agent loops or cost control.
|
|
167
|
+
*/
|
|
168
|
+
maxTokens?: number;
|
|
169
|
+
/**
|
|
170
|
+
* Floor for retrieval scores. When set, drops retrieved chunks
|
|
171
|
+
* below this raw cosine similarity — useful for citations-grade
|
|
172
|
+
* output where every chunk should actually match.
|
|
173
|
+
*/
|
|
174
|
+
minSimilarityThreshold?: number;
|
|
175
|
+
/**
|
|
176
|
+
* Per-bucket retrieval depth. `number` for a uniform value across
|
|
177
|
+
* all buckets; an object for explicit per-bucket K (e.g.
|
|
178
|
+
* `{ edgar_AAPL: 20, prices_AAPL: 4 }`). Missing buckets fall back
|
|
179
|
+
* to `topK`. Lets callers express "deep retrieval on this one,
|
|
180
|
+
* shallow on the others."
|
|
181
|
+
*/
|
|
182
|
+
topKPerBucket?: number | Record<string, number>;
|
|
183
|
+
/**
|
|
184
|
+
* `'prose'` (default) or `'json'`. When `'json'`, the server asks
|
|
185
|
+
* the synthesizer for JSON output and returns the parsed value
|
|
186
|
+
* under `result.answer_json` alongside the raw `result.answer`.
|
|
187
|
+
*/
|
|
188
|
+
returnFormat?: 'prose' | 'json';
|
|
189
|
+
/**
|
|
190
|
+
* Optional JSON Schema describing the desired output shape. Included
|
|
191
|
+
* in the prompt to guide the model. Best-effort — validate
|
|
192
|
+
* client-side if you need strict enforcement.
|
|
193
|
+
*/
|
|
194
|
+
responseSchema?: Record<string, unknown>;
|
|
157
195
|
}
|
|
158
196
|
interface ListMemoriesOptions {
|
|
159
197
|
limit?: number;
|
package/dist/index.d.ts
CHANGED
|
@@ -110,6 +110,12 @@ interface QueryUsage {
|
|
|
110
110
|
}
|
|
111
111
|
interface QueryResult {
|
|
112
112
|
answer: string;
|
|
113
|
+
/**
|
|
114
|
+
* Parsed JSON when the request set `returnFormat: 'json'`. Present
|
|
115
|
+
* only on JSON queries — the parsed value (object / array / scalar)
|
|
116
|
+
* on success, or `null` when the model returned malformed JSON.
|
|
117
|
+
*/
|
|
118
|
+
answer_json?: unknown;
|
|
113
119
|
/**
|
|
114
120
|
* Top-level count of retrieved memories. Equivalent to
|
|
115
121
|
* `result.explanation?.retrieved_memories.length` but present even
|
|
@@ -142,7 +148,8 @@ interface QueryOptions {
|
|
|
142
148
|
*/
|
|
143
149
|
buckets?: string[];
|
|
144
150
|
/**
|
|
145
|
-
* Maximum number of memories to retrieve. Defaults to 8.
|
|
151
|
+
* Maximum number of memories to retrieve per bucket. Defaults to 8.
|
|
152
|
+
* Used as the fallback K when `topKPerBucket` doesn't cover a bucket.
|
|
146
153
|
*/
|
|
147
154
|
topK?: number;
|
|
148
155
|
/**
|
|
@@ -154,6 +161,37 @@ interface QueryOptions {
|
|
|
154
161
|
* Whether to populate the `explanation` field. Defaults to true.
|
|
155
162
|
*/
|
|
156
163
|
returnExplanation?: boolean;
|
|
164
|
+
/**
|
|
165
|
+
* Cap synthesis output tokens. Default is the server's (currently
|
|
166
|
+
* 8192). Lower for agent loops or cost control.
|
|
167
|
+
*/
|
|
168
|
+
maxTokens?: number;
|
|
169
|
+
/**
|
|
170
|
+
* Floor for retrieval scores. When set, drops retrieved chunks
|
|
171
|
+
* below this raw cosine similarity — useful for citations-grade
|
|
172
|
+
* output where every chunk should actually match.
|
|
173
|
+
*/
|
|
174
|
+
minSimilarityThreshold?: number;
|
|
175
|
+
/**
|
|
176
|
+
* Per-bucket retrieval depth. `number` for a uniform value across
|
|
177
|
+
* all buckets; an object for explicit per-bucket K (e.g.
|
|
178
|
+
* `{ edgar_AAPL: 20, prices_AAPL: 4 }`). Missing buckets fall back
|
|
179
|
+
* to `topK`. Lets callers express "deep retrieval on this one,
|
|
180
|
+
* shallow on the others."
|
|
181
|
+
*/
|
|
182
|
+
topKPerBucket?: number | Record<string, number>;
|
|
183
|
+
/**
|
|
184
|
+
* `'prose'` (default) or `'json'`. When `'json'`, the server asks
|
|
185
|
+
* the synthesizer for JSON output and returns the parsed value
|
|
186
|
+
* under `result.answer_json` alongside the raw `result.answer`.
|
|
187
|
+
*/
|
|
188
|
+
returnFormat?: 'prose' | 'json';
|
|
189
|
+
/**
|
|
190
|
+
* Optional JSON Schema describing the desired output shape. Included
|
|
191
|
+
* in the prompt to guide the model. Best-effort — validate
|
|
192
|
+
* client-side if you need strict enforcement.
|
|
193
|
+
*/
|
|
194
|
+
responseSchema?: Record<string, unknown>;
|
|
157
195
|
}
|
|
158
196
|
interface ListMemoriesOptions {
|
|
159
197
|
limit?: number;
|
package/dist/index.js
CHANGED
|
@@ -16,7 +16,7 @@ var DEFAULT_TIMEOUT_MS = 3e4;
|
|
|
16
16
|
var DEFAULT_STREAM_TIMEOUT_MS = 3e5;
|
|
17
17
|
var DEFAULT_MAX_RETRIES_ON_429 = 3;
|
|
18
18
|
var RETRY_AFTER_CAP_MS = 3e4;
|
|
19
|
-
var SDK_VERSION = "0.
|
|
19
|
+
var SDK_VERSION = "0.5.0";
|
|
20
20
|
var USER_AGENT = `engram-js/${SDK_VERSION}`;
|
|
21
21
|
function parseRetryAfterMs(header, defaultBackoffMs) {
|
|
22
22
|
if (header) {
|
|
@@ -156,16 +156,24 @@ var EngramClient = class {
|
|
|
156
156
|
// ---------- Query ----------
|
|
157
157
|
async query(question, options = {}) {
|
|
158
158
|
const buckets = options.buckets ?? ["default"];
|
|
159
|
+
const opts = {
|
|
160
|
+
top_k: options.topK ?? 8,
|
|
161
|
+
return_explanation: options.returnExplanation ?? true,
|
|
162
|
+
skip_synthesis: options.skipSynthesis ?? false
|
|
163
|
+
};
|
|
164
|
+
if (options.maxTokens !== void 0) opts.max_tokens = options.maxTokens;
|
|
165
|
+
if (options.minSimilarityThreshold !== void 0) {
|
|
166
|
+
opts.min_similarity_threshold = options.minSimilarityThreshold;
|
|
167
|
+
}
|
|
168
|
+
if (options.topKPerBucket !== void 0) opts.top_k_per_bucket = options.topKPerBucket;
|
|
169
|
+
if (options.returnFormat !== void 0) opts.return_format = options.returnFormat;
|
|
170
|
+
if (options.responseSchema !== void 0) opts.response_schema = options.responseSchema;
|
|
159
171
|
return this.request("/v1/query", {
|
|
160
172
|
method: "POST",
|
|
161
173
|
body: {
|
|
162
174
|
query: question,
|
|
163
175
|
buckets,
|
|
164
|
-
options:
|
|
165
|
-
top_k: options.topK ?? 8,
|
|
166
|
-
return_explanation: options.returnExplanation ?? true,
|
|
167
|
-
skip_synthesis: options.skipSynthesis ?? false
|
|
168
|
-
}
|
|
176
|
+
options: opts
|
|
169
177
|
}
|
|
170
178
|
});
|
|
171
179
|
}
|
|
@@ -183,15 +191,23 @@ var EngramClient = class {
|
|
|
183
191
|
*/
|
|
184
192
|
queryStream(question, options = {}) {
|
|
185
193
|
const buckets = options.buckets ?? ["default"];
|
|
194
|
+
const opts = {
|
|
195
|
+
top_k: options.topK ?? 8,
|
|
196
|
+
return_explanation: options.returnExplanation ?? true,
|
|
197
|
+
skip_synthesis: options.skipSynthesis ?? false
|
|
198
|
+
};
|
|
199
|
+
if (options.maxTokens !== void 0) opts.max_tokens = options.maxTokens;
|
|
200
|
+
if (options.minSimilarityThreshold !== void 0) {
|
|
201
|
+
opts.min_similarity_threshold = options.minSimilarityThreshold;
|
|
202
|
+
}
|
|
203
|
+
if (options.topKPerBucket !== void 0) opts.top_k_per_bucket = options.topKPerBucket;
|
|
204
|
+
if (options.returnFormat !== void 0) opts.return_format = options.returnFormat;
|
|
205
|
+
if (options.responseSchema !== void 0) opts.response_schema = options.responseSchema;
|
|
186
206
|
const body = {
|
|
187
207
|
query: question,
|
|
188
208
|
buckets,
|
|
189
209
|
stream: true,
|
|
190
|
-
options:
|
|
191
|
-
top_k: options.topK ?? 8,
|
|
192
|
-
return_explanation: options.returnExplanation ?? true,
|
|
193
|
-
skip_synthesis: options.skipSynthesis ?? false
|
|
194
|
-
}
|
|
210
|
+
options: opts
|
|
195
211
|
};
|
|
196
212
|
const url = `${this.baseUrl}/v1/query`;
|
|
197
213
|
const apiKey = this.apiKey;
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/types.ts","../src/client.ts"],"names":[],"mappings":"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","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 for buffered (non-streaming) calls.\n * Defaults to 30000 (30s).\n */\n timeoutMs?: number;\n /**\n * Timeout in milliseconds for `queryStream` calls. Streaming responses\n * can sit in the prep phase (retrieval + extractor pass) for 5–15s\n * before the first synthesis token arrives, so the buffered 30s\n * default would leave no headroom for the streamed body. Defaults to\n * 300000 (5 min). Use a higher value for very large synthesis bodies.\n */\n streamTimeoutMs?: number;\n /**\n * How many times to retry on a 429 (per-tenant concurrent-request cap).\n * Honors the server's `Retry-After` header, capped at 30s per sleep.\n * Defaults to 3. Set to 0 to disable retry and surface 429 as `EngramError`\n * on the first attempt.\n */\n maxRetriesOn429?: number;\n}\n\nexport interface Bucket {\n id: string;\n name: string;\n /**\n * Mirror of `name`. The server emits both so callers iterating both\n * `listBuckets` and `storeMemory` responses can use one field name.\n * Prefer `name` in new code.\n */\n bucket_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 type StoreStatus = 'stored' | 'merged';\n\nexport type MergeReason =\n | 'content_hash'\n | 'embedding_similarity'\n | 'conflict_keep_existing'\n | 'concurrent_insert_race';\n\nexport interface StoreMemoryResult {\n id: string;\n /**\n * Alias for `id` — older API docs / older SDKs referenced this name.\n * Always present; prefer `id` in new code.\n */\n memory_id?: string;\n bucket_name: string;\n token_count: number;\n /**\n * `\"stored\"` for fresh writes, `\"merged\"` when the server collapsed\n * this write into a pre-existing memory via dedup. Always present.\n */\n status?: StoreStatus;\n /** Present only when `status === \"merged\"`. ID of the canonical memory the write was absorbed into. */\n deduped_into?: string;\n /** Present only when `status === \"merged\"`. Similarity score in [0.0, 1.0] (1.0 for content-hash matches). */\n similarity_score?: number;\n /** Present only when `status === \"merged\"`. Reason for the merge. */\n merge_reason?: MergeReason;\n}\n\n/**\n * Dedup policy passed to `storeMemory`. The server's default (currently\n * `\"loose\"`) applies when omitted.\n *\n * - `\"off\"` — store every write as a new memory; useful for templated\n * time-series ingest where structurally similar rows carry unique\n * values and would otherwise collapse.\n * - `\"loose\"` — merge writes at similarity ≥ 0.95 (default).\n * - `\"strict\"` — only merge near-identical content (≥ 0.99).\n */\nexport type DedupPolicy = 'off' | 'loose' | 'strict';\n\nexport interface ClearMemoriesResult {\n success: boolean;\n /** Number of memories actually deleted (server-reported). */\n cleared_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 /**\n * Top-level count of retrieved memories. Equivalent to\n * `result.explanation?.retrieved_memories.length` but present even\n * when `returnExplanation` is false.\n */\n memories_found?: number;\n explanation?: QueryExplanation;\n usage?: QueryUsage;\n}\n\n/**\n * One frame yielded by {@link EngramClient.queryStream}.\n *\n * The shape is discriminated by `type`:\n * - `delta` frames carry an incremental piece of the answer in `content`.\n * - `done` carries the final usage + (optional) explanation. Emitted\n * exactly once at the end of the stream.\n */\nexport type QueryStreamEvent =\n | { type: 'delta'; content: string }\n | {\n type: 'done';\n usage?: QueryUsage;\n synthesis_usage?: unknown;\n explanation?: QueryExplanation;\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 ClearMemoriesResult,\n type DedupPolicy,\n type EngramClientOptions,\n type ListMemoriesOptions,\n type ListMemoriesResult,\n type QueryOptions,\n type QueryResult,\n type QueryStreamEvent,\n type StoreMemoryResult,\n} from './types.js';\n\nconst DEFAULT_BASE_URL = 'https://api.lumetra.io';\nconst DEFAULT_TIMEOUT_MS = 30_000;\nconst DEFAULT_STREAM_TIMEOUT_MS = 300_000;\nconst DEFAULT_MAX_RETRIES_ON_429 = 3;\n// Cap on per-attempt backoff so a misconfigured server can't force\n// callers to sleep for minutes.\nconst RETRY_AFTER_CAP_MS = 30_000;\nconst SDK_VERSION = '0.4.0';\nconst USER_AGENT = `engram-js/${SDK_VERSION}`;\n\nfunction parseRetryAfterMs(header: string | null, defaultBackoffMs: number): number {\n if (header) {\n const value = Number(header.trim());\n if (Number.isFinite(value) && value >= 0) {\n return Math.min(value * 1000, RETRY_AFTER_CAP_MS);\n }\n }\n return Math.min(defaultBackoffMs, RETRY_AFTER_CAP_MS);\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\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 private readonly streamTimeoutMs: number;\n private readonly maxRetriesOn429: 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 this.streamTimeoutMs = options.streamTimeoutMs ?? DEFAULT_STREAM_TIMEOUT_MS;\n this.maxRetriesOn429 = Math.max(0, options.maxRetriesOn429 ?? DEFAULT_MAX_RETRIES_ON_429);\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 // 429-aware retry. The Engram API enforces a per-tenant concurrent-\n // request cap and sets Retry-After on 429s; without retry handling,\n // bursty clients fail immediately under load. The body is JSON-\n // serialized once outside the loop so each attempt sends an\n // identical request.\n const requestBody = init.body !== undefined ? JSON.stringify(init.body) : undefined;\n let attemptsRemaining = this.maxRetriesOn429;\n let backoffMs = 1000;\n\n // eslint-disable-next-line no-constant-condition\n while (true) {\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 'User-Agent': USER_AGENT,\n },\n body: requestBody,\n signal: controller.signal,\n });\n } finally {\n clearTimeout(timer);\n }\n\n if (res.status === 429 && attemptsRemaining > 0) {\n // Drain the body so the connection can return to the pool.\n await res.text().catch(() => undefined);\n const delay = parseRetryAfterMs(res.headers.get('Retry-After'), backoffMs);\n await sleep(delay);\n attemptsRemaining -= 1;\n backoffMs = Math.min(backoffMs * 2, RETRY_AFTER_CAP_MS);\n continue;\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\n // ---------- Memories ----------\n\n async storeMemory(\n content: string,\n bucket: string = 'default',\n options: { dedup?: DedupPolicy } = {},\n ): Promise<StoreMemoryResult> {\n const body: Record<string, unknown> = { content };\n if (options.dedup !== undefined) body.dedup = options.dedup;\n return this.request<StoreMemoryResult>(\n `/v1/buckets/${encodeURIComponent(bucket)}/memories`,\n { method: 'POST', body },\n );\n }\n\n async storeMemories(\n contents: string[],\n bucket: string = 'default',\n ): Promise<{ memories: StoreMemoryResult[] }> {\n // Defensively unwrap: depending on server version the batch endpoint\n // returns either { memories: [...] } or a bare array. Normalize to the\n // wrapped shape so callers don't have to switch on it.\n const result = await this.request<{ memories: StoreMemoryResult[] } | StoreMemoryResult[]>(\n `/v1/buckets/${encodeURIComponent(bucket)}/memories`,\n { method: 'POST', body: { memories: contents.map((content) => ({ content })) } },\n );\n return Array.isArray(result) ? { memories: result } : result;\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<ClearMemoriesResult> {\n const res = await this.request<ClearMemoriesResult>(\n `/v1/buckets/${encodeURIComponent(bucket)}/memories`,\n { method: 'DELETE' },\n );\n // Defensive default: older servers / proxies may strip the body. The\n // contract surface is {success, cleared_count}; if the server stayed\n // silent we still return the same shape so callers can rely on it.\n return res ?? { success: true, cleared_count: 0 };\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 /**\n * Streaming variant of {@link query}. Returns an async-iterable that\n * yields {@link QueryStreamEvent} frames as the server produces them:\n *\n * for await (const ev of engram.queryStream('...')) {\n * if (ev.type === 'delta') process.stdout.write(ev.content);\n * else if (ev.type === 'done') console.log(ev.usage);\n * }\n *\n * Break out of the loop to abort the request (the underlying\n * AbortController is wired up to the fetch call).\n */\n queryStream(question: string, options: QueryOptions = {}): AsyncIterable<QueryStreamEvent> {\n const buckets = options.buckets ?? ['default'];\n const body = {\n query: question,\n buckets,\n stream: true,\n options: {\n top_k: options.topK ?? 8,\n return_explanation: options.returnExplanation ?? true,\n skip_synthesis: options.skipSynthesis ?? false,\n },\n };\n const url = `${this.baseUrl}/v1/query`;\n const apiKey = this.apiKey;\n const fetchImpl = this.fetchImpl;\n const timeoutMs = this.streamTimeoutMs;\n const maxRetriesOn429 = this.maxRetriesOn429;\n const bodyJson = JSON.stringify(body);\n\n return {\n [Symbol.asyncIterator]: () => {\n const controller = new AbortController();\n // The timeout caps total wall-clock for the stream. Set generously\n // because synthesis can run 10–25s before the first byte even with\n // streaming on slow paths; clamp to the user's configured timeout.\n const timer = setTimeout(() => controller.abort(), timeoutMs);\n\n let started = false;\n let reader: ReadableStreamDefaultReader<Uint8Array> | null = null;\n const decoder = new TextDecoder('utf-8');\n let buffer = '';\n let done = false;\n const queue: QueryStreamEvent[] = [];\n let pendingError: unknown = null;\n\n const ensureStarted = async (): Promise<void> => {\n if (started) return;\n started = true;\n // 429-aware retry at the connection-open stage only. Once\n // the response body starts flowing we can't resume mid-\n // stream safely.\n let attemptsRemaining = maxRetriesOn429;\n let backoffMs = 1000;\n // eslint-disable-next-line no-constant-condition\n while (true) {\n const res = await fetchImpl(url, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${apiKey}`,\n 'Content-Type': 'application/json',\n Accept: 'text/event-stream',\n 'User-Agent': USER_AGENT,\n },\n body: bodyJson,\n signal: controller.signal,\n });\n if (res.status === 429 && attemptsRemaining > 0) {\n await res.text().catch(() => undefined);\n const delay = parseRetryAfterMs(res.headers.get('Retry-After'), backoffMs);\n await sleep(delay);\n attemptsRemaining -= 1;\n backoffMs = Math.min(backoffMs * 2, RETRY_AFTER_CAP_MS);\n continue;\n }\n if (!res.ok) {\n const text = await res.text().catch(() => '');\n let parsed: unknown = text;\n try {\n parsed = text ? JSON.parse(text) : text;\n } catch {\n /* keep raw text */\n }\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 if (!res.body) {\n throw new EngramError('Engram API: streaming response has no body', res.status, null);\n }\n reader = res.body.getReader();\n return;\n }\n };\n\n const drainBuffer = (): void => {\n // SSE frames are separated by a blank line ('\\n\\n'). Each frame\n // is one or more 'field: value' lines. We only care about\n // 'data:' lines for this stream.\n let idx: number;\n while ((idx = buffer.indexOf('\\n\\n')) !== -1) {\n const frame = buffer.slice(0, idx);\n buffer = buffer.slice(idx + 2);\n const dataLines: string[] = [];\n for (const rawLine of frame.split('\\n')) {\n const line = rawLine.endsWith('\\r') ? rawLine.slice(0, -1) : rawLine;\n if (line.startsWith('data: ')) {\n dataLines.push(line.slice(6));\n } else if (line.startsWith('data:')) {\n dataLines.push(line.slice(5));\n }\n }\n if (dataLines.length === 0) continue;\n const payloadStr = dataLines.join('\\n');\n if (payloadStr === '[DONE]') {\n done = true;\n return;\n }\n let payload: unknown;\n try {\n payload = JSON.parse(payloadStr);\n } catch {\n // Malformed frame — skip rather than corrupt the stream.\n continue;\n }\n if (payload && typeof payload === 'object') {\n const obj = payload as Record<string, unknown>;\n if (obj.error) {\n pendingError = new EngramError(String(obj.error), 0, obj);\n done = true;\n return;\n }\n // OpenAI-style delta chunk\n const choices = obj.choices as Array<{ delta?: { content?: string } }> | undefined;\n if (Array.isArray(choices) && choices.length > 0) {\n const delta = choices[0]?.delta?.content;\n if (typeof delta === 'string' && delta.length > 0) {\n queue.push({ type: 'delta', content: delta });\n }\n continue;\n }\n // Final usage / explanation frame (no 'choices' key).\n queue.push({ type: 'done', ...(obj as Omit<Extract<QueryStreamEvent, { type: 'done' }>, 'type'>) });\n }\n }\n };\n\n return {\n next: async (): Promise<IteratorResult<QueryStreamEvent>> => {\n try {\n await ensureStarted();\n } catch (err) {\n clearTimeout(timer);\n throw err;\n }\n while (queue.length === 0 && !done) {\n if (!reader) {\n clearTimeout(timer);\n throw new EngramError('Engram API: stream reader missing', 0, null);\n }\n const chunk = await reader.read();\n if (chunk.done) {\n // Flush whatever's left in the buffer (some servers don't\n // terminate with a trailing blank line).\n if (buffer.length > 0) {\n buffer += '\\n\\n';\n drainBuffer();\n }\n done = true;\n break;\n }\n buffer += decoder.decode(chunk.value, { stream: true });\n drainBuffer();\n }\n if (queue.length > 0) {\n return { value: queue.shift() as QueryStreamEvent, done: false };\n }\n clearTimeout(timer);\n if (pendingError) throw pendingError;\n return { value: undefined as unknown as QueryStreamEvent, done: true };\n },\n return: async (): Promise<IteratorResult<QueryStreamEvent>> => {\n // Caller broke out of the for-await loop — cancel the upstream\n // request so we're not holding the connection open.\n clearTimeout(timer);\n controller.abort();\n try {\n await reader?.cancel();\n } catch {\n /* ignored */\n }\n return { value: undefined as unknown as QueryStreamEvent, done: true };\n },\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"]}
|
|
1
|
+
{"version":3,"sources":["../src/types.ts","../src/client.ts"],"names":[],"mappings":"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","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 for buffered (non-streaming) calls.\n * Defaults to 30000 (30s).\n */\n timeoutMs?: number;\n /**\n * Timeout in milliseconds for `queryStream` calls. Streaming responses\n * can sit in the prep phase (retrieval + extractor pass) for 5–15s\n * before the first synthesis token arrives, so the buffered 30s\n * default would leave no headroom for the streamed body. Defaults to\n * 300000 (5 min). Use a higher value for very large synthesis bodies.\n */\n streamTimeoutMs?: number;\n /**\n * How many times to retry on a 429 (per-tenant concurrent-request cap).\n * Honors the server's `Retry-After` header, capped at 30s per sleep.\n * Defaults to 3. Set to 0 to disable retry and surface 429 as `EngramError`\n * on the first attempt.\n */\n maxRetriesOn429?: number;\n}\n\nexport interface Bucket {\n id: string;\n name: string;\n /**\n * Mirror of `name`. The server emits both so callers iterating both\n * `listBuckets` and `storeMemory` responses can use one field name.\n * Prefer `name` in new code.\n */\n bucket_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 type StoreStatus = 'stored' | 'merged';\n\nexport type MergeReason =\n | 'content_hash'\n | 'embedding_similarity'\n | 'conflict_keep_existing'\n | 'concurrent_insert_race';\n\nexport interface StoreMemoryResult {\n id: string;\n /**\n * Alias for `id` — older API docs / older SDKs referenced this name.\n * Always present; prefer `id` in new code.\n */\n memory_id?: string;\n bucket_name: string;\n token_count: number;\n /**\n * `\"stored\"` for fresh writes, `\"merged\"` when the server collapsed\n * this write into a pre-existing memory via dedup. Always present.\n */\n status?: StoreStatus;\n /** Present only when `status === \"merged\"`. ID of the canonical memory the write was absorbed into. */\n deduped_into?: string;\n /** Present only when `status === \"merged\"`. Similarity score in [0.0, 1.0] (1.0 for content-hash matches). */\n similarity_score?: number;\n /** Present only when `status === \"merged\"`. Reason for the merge. */\n merge_reason?: MergeReason;\n}\n\n/**\n * Dedup policy passed to `storeMemory`. The server's default (currently\n * `\"loose\"`) applies when omitted.\n *\n * - `\"off\"` — store every write as a new memory; useful for templated\n * time-series ingest where structurally similar rows carry unique\n * values and would otherwise collapse.\n * - `\"loose\"` — merge writes at similarity ≥ 0.95 (default).\n * - `\"strict\"` — only merge near-identical content (≥ 0.99).\n */\nexport type DedupPolicy = 'off' | 'loose' | 'strict';\n\nexport interface ClearMemoriesResult {\n success: boolean;\n /** Number of memories actually deleted (server-reported). */\n cleared_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 /**\n * Parsed JSON when the request set `returnFormat: 'json'`. Present\n * only on JSON queries — the parsed value (object / array / scalar)\n * on success, or `null` when the model returned malformed JSON.\n */\n answer_json?: unknown;\n /**\n * Top-level count of retrieved memories. Equivalent to\n * `result.explanation?.retrieved_memories.length` but present even\n * when `returnExplanation` is false.\n */\n memories_found?: number;\n explanation?: QueryExplanation;\n usage?: QueryUsage;\n}\n\n/**\n * One frame yielded by {@link EngramClient.queryStream}.\n *\n * The shape is discriminated by `type`:\n * - `delta` frames carry an incremental piece of the answer in `content`.\n * - `done` carries the final usage + (optional) explanation. Emitted\n * exactly once at the end of the stream.\n */\nexport type QueryStreamEvent =\n | { type: 'delta'; content: string }\n | {\n type: 'done';\n usage?: QueryUsage;\n synthesis_usage?: unknown;\n explanation?: QueryExplanation;\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 per bucket. Defaults to 8.\n * Used as the fallback K when `topKPerBucket` doesn't cover a bucket.\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 * Cap synthesis output tokens. Default is the server's (currently\n * 8192). Lower for agent loops or cost control.\n */\n maxTokens?: number;\n /**\n * Floor for retrieval scores. When set, drops retrieved chunks\n * below this raw cosine similarity — useful for citations-grade\n * output where every chunk should actually match.\n */\n minSimilarityThreshold?: number;\n /**\n * Per-bucket retrieval depth. `number` for a uniform value across\n * all buckets; an object for explicit per-bucket K (e.g.\n * `{ edgar_AAPL: 20, prices_AAPL: 4 }`). Missing buckets fall back\n * to `topK`. Lets callers express \"deep retrieval on this one,\n * shallow on the others.\"\n */\n topKPerBucket?: number | Record<string, number>;\n /**\n * `'prose'` (default) or `'json'`. When `'json'`, the server asks\n * the synthesizer for JSON output and returns the parsed value\n * under `result.answer_json` alongside the raw `result.answer`.\n */\n returnFormat?: 'prose' | 'json';\n /**\n * Optional JSON Schema describing the desired output shape. Included\n * in the prompt to guide the model. Best-effort — validate\n * client-side if you need strict enforcement.\n */\n responseSchema?: Record<string, unknown>;\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 ClearMemoriesResult,\n type DedupPolicy,\n type EngramClientOptions,\n type ListMemoriesOptions,\n type ListMemoriesResult,\n type QueryOptions,\n type QueryResult,\n type QueryStreamEvent,\n type StoreMemoryResult,\n} from './types.js';\n\nconst DEFAULT_BASE_URL = 'https://api.lumetra.io';\nconst DEFAULT_TIMEOUT_MS = 30_000;\nconst DEFAULT_STREAM_TIMEOUT_MS = 300_000;\nconst DEFAULT_MAX_RETRIES_ON_429 = 3;\n// Cap on per-attempt backoff so a misconfigured server can't force\n// callers to sleep for minutes.\nconst RETRY_AFTER_CAP_MS = 30_000;\nconst SDK_VERSION = '0.5.0';\nconst USER_AGENT = `engram-js/${SDK_VERSION}`;\n\nfunction parseRetryAfterMs(header: string | null, defaultBackoffMs: number): number {\n if (header) {\n const value = Number(header.trim());\n if (Number.isFinite(value) && value >= 0) {\n return Math.min(value * 1000, RETRY_AFTER_CAP_MS);\n }\n }\n return Math.min(defaultBackoffMs, RETRY_AFTER_CAP_MS);\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\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 private readonly streamTimeoutMs: number;\n private readonly maxRetriesOn429: 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 this.streamTimeoutMs = options.streamTimeoutMs ?? DEFAULT_STREAM_TIMEOUT_MS;\n this.maxRetriesOn429 = Math.max(0, options.maxRetriesOn429 ?? DEFAULT_MAX_RETRIES_ON_429);\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 // 429-aware retry. The Engram API enforces a per-tenant concurrent-\n // request cap and sets Retry-After on 429s; without retry handling,\n // bursty clients fail immediately under load. The body is JSON-\n // serialized once outside the loop so each attempt sends an\n // identical request.\n const requestBody = init.body !== undefined ? JSON.stringify(init.body) : undefined;\n let attemptsRemaining = this.maxRetriesOn429;\n let backoffMs = 1000;\n\n // eslint-disable-next-line no-constant-condition\n while (true) {\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 'User-Agent': USER_AGENT,\n },\n body: requestBody,\n signal: controller.signal,\n });\n } finally {\n clearTimeout(timer);\n }\n\n if (res.status === 429 && attemptsRemaining > 0) {\n // Drain the body so the connection can return to the pool.\n await res.text().catch(() => undefined);\n const delay = parseRetryAfterMs(res.headers.get('Retry-After'), backoffMs);\n await sleep(delay);\n attemptsRemaining -= 1;\n backoffMs = Math.min(backoffMs * 2, RETRY_AFTER_CAP_MS);\n continue;\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\n // ---------- Memories ----------\n\n async storeMemory(\n content: string,\n bucket: string = 'default',\n options: { dedup?: DedupPolicy } = {},\n ): Promise<StoreMemoryResult> {\n const body: Record<string, unknown> = { content };\n if (options.dedup !== undefined) body.dedup = options.dedup;\n return this.request<StoreMemoryResult>(\n `/v1/buckets/${encodeURIComponent(bucket)}/memories`,\n { method: 'POST', body },\n );\n }\n\n async storeMemories(\n contents: string[],\n bucket: string = 'default',\n ): Promise<{ memories: StoreMemoryResult[] }> {\n // Defensively unwrap: depending on server version the batch endpoint\n // returns either { memories: [...] } or a bare array. Normalize to the\n // wrapped shape so callers don't have to switch on it.\n const result = await this.request<{ memories: StoreMemoryResult[] } | StoreMemoryResult[]>(\n `/v1/buckets/${encodeURIComponent(bucket)}/memories`,\n { method: 'POST', body: { memories: contents.map((content) => ({ content })) } },\n );\n return Array.isArray(result) ? { memories: result } : result;\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<ClearMemoriesResult> {\n const res = await this.request<ClearMemoriesResult>(\n `/v1/buckets/${encodeURIComponent(bucket)}/memories`,\n { method: 'DELETE' },\n );\n // Defensive default: older servers / proxies may strip the body. The\n // contract surface is {success, cleared_count}; if the server stayed\n // silent we still return the same shape so callers can rely on it.\n return res ?? { success: true, cleared_count: 0 };\n }\n\n // ---------- Query ----------\n\n async query(question: string, options: QueryOptions = {}): Promise<QueryResult> {\n const buckets = options.buckets ?? ['default'];\n const opts: Record<string, unknown> = {\n top_k: options.topK ?? 8,\n return_explanation: options.returnExplanation ?? true,\n skip_synthesis: options.skipSynthesis ?? false,\n };\n if (options.maxTokens !== undefined) opts.max_tokens = options.maxTokens;\n if (options.minSimilarityThreshold !== undefined) {\n opts.min_similarity_threshold = options.minSimilarityThreshold;\n }\n if (options.topKPerBucket !== undefined) opts.top_k_per_bucket = options.topKPerBucket;\n if (options.returnFormat !== undefined) opts.return_format = options.returnFormat;\n if (options.responseSchema !== undefined) opts.response_schema = options.responseSchema;\n return this.request<QueryResult>('/v1/query', {\n method: 'POST',\n body: {\n query: question,\n buckets,\n options: opts,\n },\n });\n }\n\n /**\n * Streaming variant of {@link query}. Returns an async-iterable that\n * yields {@link QueryStreamEvent} frames as the server produces them:\n *\n * for await (const ev of engram.queryStream('...')) {\n * if (ev.type === 'delta') process.stdout.write(ev.content);\n * else if (ev.type === 'done') console.log(ev.usage);\n * }\n *\n * Break out of the loop to abort the request (the underlying\n * AbortController is wired up to the fetch call).\n */\n queryStream(question: string, options: QueryOptions = {}): AsyncIterable<QueryStreamEvent> {\n const buckets = options.buckets ?? ['default'];\n const opts: Record<string, unknown> = {\n top_k: options.topK ?? 8,\n return_explanation: options.returnExplanation ?? true,\n skip_synthesis: options.skipSynthesis ?? false,\n };\n if (options.maxTokens !== undefined) opts.max_tokens = options.maxTokens;\n if (options.minSimilarityThreshold !== undefined) {\n opts.min_similarity_threshold = options.minSimilarityThreshold;\n }\n if (options.topKPerBucket !== undefined) opts.top_k_per_bucket = options.topKPerBucket;\n if (options.returnFormat !== undefined) opts.return_format = options.returnFormat;\n if (options.responseSchema !== undefined) opts.response_schema = options.responseSchema;\n const body = {\n query: question,\n buckets,\n stream: true,\n options: opts,\n };\n const url = `${this.baseUrl}/v1/query`;\n const apiKey = this.apiKey;\n const fetchImpl = this.fetchImpl;\n const timeoutMs = this.streamTimeoutMs;\n const maxRetriesOn429 = this.maxRetriesOn429;\n const bodyJson = JSON.stringify(body);\n\n return {\n [Symbol.asyncIterator]: () => {\n const controller = new AbortController();\n // The timeout caps total wall-clock for the stream. Set generously\n // because synthesis can run 10–25s before the first byte even with\n // streaming on slow paths; clamp to the user's configured timeout.\n const timer = setTimeout(() => controller.abort(), timeoutMs);\n\n let started = false;\n let reader: ReadableStreamDefaultReader<Uint8Array> | null = null;\n const decoder = new TextDecoder('utf-8');\n let buffer = '';\n let done = false;\n const queue: QueryStreamEvent[] = [];\n let pendingError: unknown = null;\n\n const ensureStarted = async (): Promise<void> => {\n if (started) return;\n started = true;\n // 429-aware retry at the connection-open stage only. Once\n // the response body starts flowing we can't resume mid-\n // stream safely.\n let attemptsRemaining = maxRetriesOn429;\n let backoffMs = 1000;\n // eslint-disable-next-line no-constant-condition\n while (true) {\n const res = await fetchImpl(url, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${apiKey}`,\n 'Content-Type': 'application/json',\n Accept: 'text/event-stream',\n 'User-Agent': USER_AGENT,\n },\n body: bodyJson,\n signal: controller.signal,\n });\n if (res.status === 429 && attemptsRemaining > 0) {\n await res.text().catch(() => undefined);\n const delay = parseRetryAfterMs(res.headers.get('Retry-After'), backoffMs);\n await sleep(delay);\n attemptsRemaining -= 1;\n backoffMs = Math.min(backoffMs * 2, RETRY_AFTER_CAP_MS);\n continue;\n }\n if (!res.ok) {\n const text = await res.text().catch(() => '');\n let parsed: unknown = text;\n try {\n parsed = text ? JSON.parse(text) : text;\n } catch {\n /* keep raw text */\n }\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 if (!res.body) {\n throw new EngramError('Engram API: streaming response has no body', res.status, null);\n }\n reader = res.body.getReader();\n return;\n }\n };\n\n const drainBuffer = (): void => {\n // SSE frames are separated by a blank line ('\\n\\n'). Each frame\n // is one or more 'field: value' lines. We only care about\n // 'data:' lines for this stream.\n let idx: number;\n while ((idx = buffer.indexOf('\\n\\n')) !== -1) {\n const frame = buffer.slice(0, idx);\n buffer = buffer.slice(idx + 2);\n const dataLines: string[] = [];\n for (const rawLine of frame.split('\\n')) {\n const line = rawLine.endsWith('\\r') ? rawLine.slice(0, -1) : rawLine;\n if (line.startsWith('data: ')) {\n dataLines.push(line.slice(6));\n } else if (line.startsWith('data:')) {\n dataLines.push(line.slice(5));\n }\n }\n if (dataLines.length === 0) continue;\n const payloadStr = dataLines.join('\\n');\n if (payloadStr === '[DONE]') {\n done = true;\n return;\n }\n let payload: unknown;\n try {\n payload = JSON.parse(payloadStr);\n } catch {\n // Malformed frame — skip rather than corrupt the stream.\n continue;\n }\n if (payload && typeof payload === 'object') {\n const obj = payload as Record<string, unknown>;\n if (obj.error) {\n pendingError = new EngramError(String(obj.error), 0, obj);\n done = true;\n return;\n }\n // OpenAI-style delta chunk\n const choices = obj.choices as Array<{ delta?: { content?: string } }> | undefined;\n if (Array.isArray(choices) && choices.length > 0) {\n const delta = choices[0]?.delta?.content;\n if (typeof delta === 'string' && delta.length > 0) {\n queue.push({ type: 'delta', content: delta });\n }\n continue;\n }\n // Final usage / explanation frame (no 'choices' key).\n queue.push({ type: 'done', ...(obj as Omit<Extract<QueryStreamEvent, { type: 'done' }>, 'type'>) });\n }\n }\n };\n\n return {\n next: async (): Promise<IteratorResult<QueryStreamEvent>> => {\n try {\n await ensureStarted();\n } catch (err) {\n clearTimeout(timer);\n throw err;\n }\n while (queue.length === 0 && !done) {\n if (!reader) {\n clearTimeout(timer);\n throw new EngramError('Engram API: stream reader missing', 0, null);\n }\n const chunk = await reader.read();\n if (chunk.done) {\n // Flush whatever's left in the buffer (some servers don't\n // terminate with a trailing blank line).\n if (buffer.length > 0) {\n buffer += '\\n\\n';\n drainBuffer();\n }\n done = true;\n break;\n }\n buffer += decoder.decode(chunk.value, { stream: true });\n drainBuffer();\n }\n if (queue.length > 0) {\n return { value: queue.shift() as QueryStreamEvent, done: false };\n }\n clearTimeout(timer);\n if (pendingError) throw pendingError;\n return { value: undefined as unknown as QueryStreamEvent, done: true };\n },\n return: async (): Promise<IteratorResult<QueryStreamEvent>> => {\n // Caller broke out of the for-await loop — cancel the upstream\n // request so we're not holding the connection open.\n clearTimeout(timer);\n controller.abort();\n try {\n await reader?.cancel();\n } catch {\n /* ignored */\n }\n return { value: undefined as unknown as QueryStreamEvent, done: true };\n },\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"]}
|