@lumetra/engram 0.4.0 → 0.5.1

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 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.4.0";
21
+ var SDK_VERSION = "0.5.1";
22
22
  var USER_AGENT = `engram-js/${SDK_VERSION}`;
23
23
  function parseRetryAfterMs(header, defaultBackoffMs) {
24
24
  if (header) {
@@ -158,16 +158,27 @@ 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.minWeightedScore !== void 0) {
171
+ opts.min_weighted_score = options.minWeightedScore;
172
+ }
173
+ if (options.topKPerBucket !== void 0) opts.top_k_per_bucket = options.topKPerBucket;
174
+ if (options.returnFormat !== void 0) opts.return_format = options.returnFormat;
175
+ if (options.responseSchema !== void 0) opts.response_schema = options.responseSchema;
161
176
  return this.request("/v1/query", {
162
177
  method: "POST",
163
178
  body: {
164
179
  query: question,
165
180
  buckets,
166
- options: {
167
- top_k: options.topK ?? 8,
168
- return_explanation: options.returnExplanation ?? true,
169
- skip_synthesis: options.skipSynthesis ?? false
170
- }
181
+ options: opts
171
182
  }
172
183
  });
173
184
  }
@@ -185,15 +196,26 @@ var EngramClient = class {
185
196
  */
186
197
  queryStream(question, options = {}) {
187
198
  const buckets = options.buckets ?? ["default"];
199
+ const opts = {
200
+ top_k: options.topK ?? 8,
201
+ return_explanation: options.returnExplanation ?? true,
202
+ skip_synthesis: options.skipSynthesis ?? false
203
+ };
204
+ if (options.maxTokens !== void 0) opts.max_tokens = options.maxTokens;
205
+ if (options.minSimilarityThreshold !== void 0) {
206
+ opts.min_similarity_threshold = options.minSimilarityThreshold;
207
+ }
208
+ if (options.minWeightedScore !== void 0) {
209
+ opts.min_weighted_score = options.minWeightedScore;
210
+ }
211
+ if (options.topKPerBucket !== void 0) opts.top_k_per_bucket = options.topKPerBucket;
212
+ if (options.returnFormat !== void 0) opts.return_format = options.returnFormat;
213
+ if (options.responseSchema !== void 0) opts.response_schema = options.responseSchema;
188
214
  const body = {
189
215
  query: question,
190
216
  buckets,
191
217
  stream: true,
192
- options: {
193
- top_k: options.topK ?? 8,
194
- return_explanation: options.returnExplanation ?? true,
195
- skip_synthesis: options.skipSynthesis ?? false
196
- }
218
+ options: opts
197
219
  };
198
220
  const url = `${this.baseUrl}/v1/query`;
199
221
  const apiKey = this.apiKey;
@@ -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":"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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 * 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 * Drop retrieved chunks whose **raw cosine similarity** (the\n * underlying embedding score) is below this. Acts as a floor over\n * the server's adaptive threshold. Useful when you specifically\n * want a precision floor on the embedding signal.\n */\n minSimilarityThreshold?: number;\n /**\n * Drop retrieved chunks whose **weighted_score** (the post-RRF\n * score surfaced in `explanation.retrieved_memories`) is below\n * this. This is the score you see in responses — most callers\n * want this rather than `minSimilarityThreshold` because the\n * scales match.\n */\n minWeightedScore?: 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.1';\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.minWeightedScore !== undefined) {\n opts.min_weighted_score = options.minWeightedScore;\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.minWeightedScore !== undefined) {\n opts.min_weighted_score = options.minWeightedScore;\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,46 @@ 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
+ * Drop retrieved chunks whose **raw cosine similarity** (the
171
+ * underlying embedding score) is below this. Acts as a floor over
172
+ * the server's adaptive threshold. Useful when you specifically
173
+ * want a precision floor on the embedding signal.
174
+ */
175
+ minSimilarityThreshold?: number;
176
+ /**
177
+ * Drop retrieved chunks whose **weighted_score** (the post-RRF
178
+ * score surfaced in `explanation.retrieved_memories`) is below
179
+ * this. This is the score you see in responses — most callers
180
+ * want this rather than `minSimilarityThreshold` because the
181
+ * scales match.
182
+ */
183
+ minWeightedScore?: number;
184
+ /**
185
+ * Per-bucket retrieval depth. `number` for a uniform value across
186
+ * all buckets; an object for explicit per-bucket K (e.g.
187
+ * `{ edgar_AAPL: 20, prices_AAPL: 4 }`). Missing buckets fall back
188
+ * to `topK`. Lets callers express "deep retrieval on this one,
189
+ * shallow on the others."
190
+ */
191
+ topKPerBucket?: number | Record<string, number>;
192
+ /**
193
+ * `'prose'` (default) or `'json'`. When `'json'`, the server asks
194
+ * the synthesizer for JSON output and returns the parsed value
195
+ * under `result.answer_json` alongside the raw `result.answer`.
196
+ */
197
+ returnFormat?: 'prose' | 'json';
198
+ /**
199
+ * Optional JSON Schema describing the desired output shape. Included
200
+ * in the prompt to guide the model. Best-effort — validate
201
+ * client-side if you need strict enforcement.
202
+ */
203
+ responseSchema?: Record<string, unknown>;
157
204
  }
158
205
  interface ListMemoriesOptions {
159
206
  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,46 @@ 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
+ * Drop retrieved chunks whose **raw cosine similarity** (the
171
+ * underlying embedding score) is below this. Acts as a floor over
172
+ * the server's adaptive threshold. Useful when you specifically
173
+ * want a precision floor on the embedding signal.
174
+ */
175
+ minSimilarityThreshold?: number;
176
+ /**
177
+ * Drop retrieved chunks whose **weighted_score** (the post-RRF
178
+ * score surfaced in `explanation.retrieved_memories`) is below
179
+ * this. This is the score you see in responses — most callers
180
+ * want this rather than `minSimilarityThreshold` because the
181
+ * scales match.
182
+ */
183
+ minWeightedScore?: number;
184
+ /**
185
+ * Per-bucket retrieval depth. `number` for a uniform value across
186
+ * all buckets; an object for explicit per-bucket K (e.g.
187
+ * `{ edgar_AAPL: 20, prices_AAPL: 4 }`). Missing buckets fall back
188
+ * to `topK`. Lets callers express "deep retrieval on this one,
189
+ * shallow on the others."
190
+ */
191
+ topKPerBucket?: number | Record<string, number>;
192
+ /**
193
+ * `'prose'` (default) or `'json'`. When `'json'`, the server asks
194
+ * the synthesizer for JSON output and returns the parsed value
195
+ * under `result.answer_json` alongside the raw `result.answer`.
196
+ */
197
+ returnFormat?: 'prose' | 'json';
198
+ /**
199
+ * Optional JSON Schema describing the desired output shape. Included
200
+ * in the prompt to guide the model. Best-effort — validate
201
+ * client-side if you need strict enforcement.
202
+ */
203
+ responseSchema?: Record<string, unknown>;
157
204
  }
158
205
  interface ListMemoriesOptions {
159
206
  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.4.0";
19
+ var SDK_VERSION = "0.5.1";
20
20
  var USER_AGENT = `engram-js/${SDK_VERSION}`;
21
21
  function parseRetryAfterMs(header, defaultBackoffMs) {
22
22
  if (header) {
@@ -156,16 +156,27 @@ 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.minWeightedScore !== void 0) {
169
+ opts.min_weighted_score = options.minWeightedScore;
170
+ }
171
+ if (options.topKPerBucket !== void 0) opts.top_k_per_bucket = options.topKPerBucket;
172
+ if (options.returnFormat !== void 0) opts.return_format = options.returnFormat;
173
+ if (options.responseSchema !== void 0) opts.response_schema = options.responseSchema;
159
174
  return this.request("/v1/query", {
160
175
  method: "POST",
161
176
  body: {
162
177
  query: question,
163
178
  buckets,
164
- options: {
165
- top_k: options.topK ?? 8,
166
- return_explanation: options.returnExplanation ?? true,
167
- skip_synthesis: options.skipSynthesis ?? false
168
- }
179
+ options: opts
169
180
  }
170
181
  });
171
182
  }
@@ -183,15 +194,26 @@ var EngramClient = class {
183
194
  */
184
195
  queryStream(question, options = {}) {
185
196
  const buckets = options.buckets ?? ["default"];
197
+ const opts = {
198
+ top_k: options.topK ?? 8,
199
+ return_explanation: options.returnExplanation ?? true,
200
+ skip_synthesis: options.skipSynthesis ?? false
201
+ };
202
+ if (options.maxTokens !== void 0) opts.max_tokens = options.maxTokens;
203
+ if (options.minSimilarityThreshold !== void 0) {
204
+ opts.min_similarity_threshold = options.minSimilarityThreshold;
205
+ }
206
+ if (options.minWeightedScore !== void 0) {
207
+ opts.min_weighted_score = options.minWeightedScore;
208
+ }
209
+ if (options.topKPerBucket !== void 0) opts.top_k_per_bucket = options.topKPerBucket;
210
+ if (options.returnFormat !== void 0) opts.return_format = options.returnFormat;
211
+ if (options.responseSchema !== void 0) opts.response_schema = options.responseSchema;
186
212
  const body = {
187
213
  query: question,
188
214
  buckets,
189
215
  stream: true,
190
- options: {
191
- top_k: options.topK ?? 8,
192
- return_explanation: options.returnExplanation ?? true,
193
- skip_synthesis: options.skipSynthesis ?? false
194
- }
216
+ options: opts
195
217
  };
196
218
  const url = `${this.baseUrl}/v1/query`;
197
219
  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":";AAyOO,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;;;ACrOA,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,qBAAqB,MAAA,EAAW;AAC1C,MAAA,IAAA,CAAK,qBAAqB,OAAA,CAAQ,gBAAA;AAAA,IACpC;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,qBAAqB,MAAA,EAAW;AAC1C,MAAA,IAAA,CAAK,qBAAqB,OAAA,CAAQ,gBAAA;AAAA,IACpC;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.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 * Drop retrieved chunks whose **raw cosine similarity** (the\n * underlying embedding score) is below this. Acts as a floor over\n * the server's adaptive threshold. Useful when you specifically\n * want a precision floor on the embedding signal.\n */\n minSimilarityThreshold?: number;\n /**\n * Drop retrieved chunks whose **weighted_score** (the post-RRF\n * score surfaced in `explanation.retrieved_memories`) is below\n * this. This is the score you see in responses — most callers\n * want this rather than `minSimilarityThreshold` because the\n * scales match.\n */\n minWeightedScore?: 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.1';\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.minWeightedScore !== undefined) {\n opts.min_weighted_score = options.minWeightedScore;\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.minWeightedScore !== undefined) {\n opts.min_weighted_score = options.minWeightedScore;\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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lumetra/engram",
3
- "version": "0.4.0",
3
+ "version": "0.5.1",
4
4
  "description": "Official TypeScript client for Engram — durable, explainable memory for AI agents.",
5
5
  "keywords": [
6
6
  "engram",