@usewhisper/sdk 2.2.1 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (6) hide show
  1. package/README.md +2 -2
  2. package/index.d.mts +753 -5
  3. package/index.d.ts +753 -5
  4. package/index.js +2126 -148
  5. package/index.mjs +2110 -148
  6. package/package.json +2 -1
package/index.js CHANGED
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
+ var __create = Object.create;
2
3
  var __defProp = Object.defineProperty;
3
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
5
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
8
  var __export = (target, all) => {
7
9
  for (var name in all)
@@ -15,23 +17,424 @@ var __copyProps = (to, from, except, desc) => {
15
17
  }
16
18
  return to;
17
19
  };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
18
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
29
 
20
30
  // ../src/sdk/index.ts
21
31
  var index_exports = {};
22
32
  __export(index_exports, {
33
+ LangChainMemoryAdapter: () => LangChainMemoryAdapter,
34
+ LangGraphCheckpointAdapter: () => LangGraphCheckpointAdapter,
23
35
  Whisper: () => Whisper,
24
36
  WhisperAgentMiddleware: () => WhisperAgentMiddleware,
37
+ WhisperClient: () => WhisperClient,
25
38
  WhisperContext: () => WhisperContext,
26
39
  WhisperDefault: () => whisper_agent_default,
27
40
  WhisperError: () => WhisperError,
41
+ WhisperRuntimeClient: () => whisper_default,
28
42
  createAgentMiddleware: () => createAgentMiddleware,
43
+ createLangChainMemoryAdapter: () => createLangChainMemoryAdapter,
44
+ createLangGraphCheckpointAdapter: () => createLangGraphCheckpointAdapter,
29
45
  default: () => index_default,
30
46
  memoryGraphToMermaid: () => memoryGraphToMermaid
31
47
  });
32
48
  module.exports = __toCommonJS(index_exports);
33
49
 
50
+ // ../src/sdk/core/telemetry.ts
51
+ var DiagnosticsStore = class {
52
+ maxEntries;
53
+ records = [];
54
+ subscribers = /* @__PURE__ */ new Set();
55
+ constructor(maxEntries = 1e3) {
56
+ this.maxEntries = Math.max(1, maxEntries);
57
+ }
58
+ add(record) {
59
+ this.records.push(record);
60
+ if (this.records.length > this.maxEntries) {
61
+ this.records.splice(0, this.records.length - this.maxEntries);
62
+ }
63
+ for (const fn of this.subscribers) {
64
+ try {
65
+ fn(record);
66
+ } catch {
67
+ }
68
+ }
69
+ }
70
+ getLast(limit = 25) {
71
+ const count = Math.max(1, limit);
72
+ return this.records.slice(-count);
73
+ }
74
+ snapshot() {
75
+ const total = this.records.length;
76
+ const success = this.records.filter((r) => r.success).length;
77
+ const failure = total - success;
78
+ const duration = this.records.reduce((acc, item) => acc + item.durationMs, 0);
79
+ return {
80
+ total,
81
+ success,
82
+ failure,
83
+ avgDurationMs: total > 0 ? duration / total : 0,
84
+ lastTraceId: this.records[this.records.length - 1]?.traceId
85
+ };
86
+ }
87
+ subscribe(fn) {
88
+ this.subscribers.add(fn);
89
+ return () => {
90
+ this.subscribers.delete(fn);
91
+ };
92
+ }
93
+ };
94
+
95
+ // ../src/sdk/core/utils.ts
96
+ function normalizeBaseUrl(url) {
97
+ let normalized = url.trim().replace(/\/+$/, "");
98
+ normalized = normalized.replace(/\/api\/v1$/i, "");
99
+ normalized = normalized.replace(/\/v1$/i, "");
100
+ normalized = normalized.replace(/\/api$/i, "");
101
+ return normalized;
102
+ }
103
+ function normalizeEndpoint(endpoint) {
104
+ const withLeadingSlash = endpoint.startsWith("/") ? endpoint : `/${endpoint}`;
105
+ if (/^\/api\/v1(\/|$)/i.test(withLeadingSlash)) {
106
+ return withLeadingSlash.replace(/^\/api/i, "");
107
+ }
108
+ return withLeadingSlash;
109
+ }
110
+ function nowIso() {
111
+ return (/* @__PURE__ */ new Date()).toISOString();
112
+ }
113
+ function stableHash(input) {
114
+ let hash = 2166136261;
115
+ for (let i = 0; i < input.length; i += 1) {
116
+ hash ^= input.charCodeAt(i);
117
+ hash = Math.imul(hash, 16777619);
118
+ }
119
+ return (hash >>> 0).toString(16).padStart(8, "0");
120
+ }
121
+ function normalizeQuery(query) {
122
+ return query.trim().toLowerCase().replace(/\s+/g, " ");
123
+ }
124
+ function randomId(prefix = "id") {
125
+ return `${prefix}_${stableHash(`${Date.now()}_${Math.random()}`)}`;
126
+ }
127
+
128
+ // ../src/sdk/core/client.ts
129
+ var DEFAULT_TIMEOUTS = {
130
+ searchMs: 3e3,
131
+ writeAckMs: 2e3,
132
+ bulkMs: 1e4,
133
+ profileMs: 2500,
134
+ sessionMs: 2500
135
+ };
136
+ var DEFAULT_RETRYABLE_STATUS = [408, 429, 500, 502, 503, 504];
137
+ var DEFAULT_API_KEY_ONLY_PREFIXES = ["/v1/memory", "/v1/context/query"];
138
+ var DEFAULT_RETRY_ATTEMPTS = {
139
+ search: 3,
140
+ writeAck: 2,
141
+ bulk: 2,
142
+ profile: 2,
143
+ session: 2,
144
+ query: 3,
145
+ get: 2
146
+ };
147
+ function isObject(value) {
148
+ return typeof value === "object" && value !== null;
149
+ }
150
+ function toMessage(payload, status, statusText) {
151
+ if (typeof payload === "string" && payload.trim()) return payload;
152
+ if (isObject(payload)) {
153
+ const maybeError = payload.error;
154
+ const maybeMessage = payload.message;
155
+ if (typeof maybeError === "string" && maybeError.trim()) return maybeError;
156
+ if (typeof maybeMessage === "string" && maybeMessage.trim()) return maybeMessage;
157
+ if (isObject(maybeError) && typeof maybeError.message === "string") return maybeError.message;
158
+ }
159
+ return `HTTP ${status}: ${statusText}`;
160
+ }
161
+ var RuntimeClientError = class extends Error {
162
+ status;
163
+ retryable;
164
+ code;
165
+ details;
166
+ traceId;
167
+ constructor(args) {
168
+ super(args.message);
169
+ this.name = "RuntimeClientError";
170
+ this.status = args.status;
171
+ this.retryable = args.retryable;
172
+ this.code = args.code;
173
+ this.details = args.details;
174
+ this.traceId = args.traceId;
175
+ }
176
+ };
177
+ var RuntimeClient = class {
178
+ apiKey;
179
+ baseUrl;
180
+ sdkVersion;
181
+ compatMode;
182
+ retryPolicy;
183
+ timeouts;
184
+ diagnostics;
185
+ inFlight = /* @__PURE__ */ new Map();
186
+ sendApiKeyHeader;
187
+ constructor(options, diagnostics) {
188
+ if (!options.apiKey) {
189
+ throw new RuntimeClientError({
190
+ code: "INVALID_API_KEY",
191
+ message: "API key is required",
192
+ retryable: false
193
+ });
194
+ }
195
+ this.apiKey = options.apiKey;
196
+ this.baseUrl = normalizeBaseUrl(options.baseUrl || "https://context.usewhisper.dev");
197
+ this.sdkVersion = options.sdkVersion || "2.x-runtime";
198
+ this.compatMode = options.compatMode || "fallback";
199
+ this.retryPolicy = {
200
+ retryableStatusCodes: options.retryPolicy?.retryableStatusCodes || DEFAULT_RETRYABLE_STATUS,
201
+ retryOnNetworkError: options.retryPolicy?.retryOnNetworkError ?? true,
202
+ maxBackoffMs: options.retryPolicy?.maxBackoffMs ?? 1200,
203
+ baseBackoffMs: options.retryPolicy?.baseBackoffMs ?? 250,
204
+ maxAttemptsByOperation: options.retryPolicy?.maxAttemptsByOperation || {}
205
+ };
206
+ this.timeouts = {
207
+ ...DEFAULT_TIMEOUTS,
208
+ ...options.timeouts || {}
209
+ };
210
+ this.sendApiKeyHeader = process.env.WHISPER_SEND_X_API_KEY === "1";
211
+ this.diagnostics = diagnostics || new DiagnosticsStore(1e3);
212
+ }
213
+ getDiagnosticsStore() {
214
+ return this.diagnostics;
215
+ }
216
+ getCompatMode() {
217
+ return this.compatMode;
218
+ }
219
+ timeoutFor(operation) {
220
+ switch (operation) {
221
+ case "search":
222
+ return this.timeouts.searchMs;
223
+ case "writeAck":
224
+ return this.timeouts.writeAckMs;
225
+ case "bulk":
226
+ return this.timeouts.bulkMs;
227
+ case "profile":
228
+ return this.timeouts.profileMs;
229
+ case "session":
230
+ return this.timeouts.sessionMs;
231
+ case "query":
232
+ case "get":
233
+ default:
234
+ return this.timeouts.searchMs;
235
+ }
236
+ }
237
+ maxAttemptsFor(operation) {
238
+ const override = this.retryPolicy.maxAttemptsByOperation?.[operation];
239
+ return Math.max(1, override ?? DEFAULT_RETRY_ATTEMPTS[operation]);
240
+ }
241
+ shouldRetryStatus(status) {
242
+ return status !== void 0 && this.retryPolicy.retryableStatusCodes?.includes(status) === true;
243
+ }
244
+ backoff(attempt) {
245
+ const base = this.retryPolicy.baseBackoffMs ?? 250;
246
+ const max = this.retryPolicy.maxBackoffMs ?? 1200;
247
+ const jitter = 0.8 + Math.random() * 0.4;
248
+ return Math.min(max, Math.floor(base * Math.pow(2, attempt) * jitter));
249
+ }
250
+ runtimeName() {
251
+ const maybeWindow = globalThis.window;
252
+ return maybeWindow && typeof maybeWindow === "object" ? "browser" : "node";
253
+ }
254
+ apiKeyOnlyPrefixes() {
255
+ const raw = process.env.WHISPER_API_KEY_ONLY_PREFIXES;
256
+ if (!raw || !raw.trim()) return DEFAULT_API_KEY_ONLY_PREFIXES;
257
+ return raw.split(",").map((p) => p.trim()).filter((p) => p.length > 0);
258
+ }
259
+ shouldAttachApiKeyHeader(endpoint) {
260
+ if (this.sendApiKeyHeader) return true;
261
+ const prefixes = this.apiKeyOnlyPrefixes();
262
+ return prefixes.some((prefix) => endpoint === prefix || endpoint.startsWith(`${prefix}/`));
263
+ }
264
+ createRequestFingerprint(options) {
265
+ const normalizedEndpoint = normalizeEndpoint(options.endpoint);
266
+ const authFingerprint = stableHash(this.apiKey.replace(/^Bearer\s+/i, ""));
267
+ const payload = JSON.stringify({
268
+ method: options.method || "GET",
269
+ endpoint: normalizedEndpoint,
270
+ body: options.body || null,
271
+ extra: options.dedupeKeyExtra || "",
272
+ authFingerprint
273
+ });
274
+ return stableHash(payload);
275
+ }
276
+ async request(options) {
277
+ const dedupeKey = options.idempotent ? this.createRequestFingerprint(options) : null;
278
+ if (dedupeKey) {
279
+ const inFlight = this.inFlight.get(dedupeKey);
280
+ if (inFlight) {
281
+ const data = await inFlight;
282
+ this.diagnostics.add({
283
+ id: randomId("diag"),
284
+ startedAt: nowIso(),
285
+ endedAt: nowIso(),
286
+ traceId: data.traceId,
287
+ spanId: randomId("span"),
288
+ operation: options.operation,
289
+ method: options.method || "GET",
290
+ endpoint: normalizeEndpoint(options.endpoint),
291
+ status: data.status,
292
+ durationMs: 0,
293
+ success: true,
294
+ deduped: true
295
+ });
296
+ const cloned = {
297
+ data: data.data,
298
+ status: data.status,
299
+ traceId: data.traceId
300
+ };
301
+ return cloned;
302
+ }
303
+ }
304
+ const runner = this.performRequest(options).then((data) => {
305
+ if (dedupeKey) this.inFlight.delete(dedupeKey);
306
+ return data;
307
+ }).catch((error) => {
308
+ if (dedupeKey) this.inFlight.delete(dedupeKey);
309
+ throw error;
310
+ });
311
+ if (dedupeKey) {
312
+ this.inFlight.set(dedupeKey, runner);
313
+ }
314
+ return runner;
315
+ }
316
+ async performRequest(options) {
317
+ const method = options.method || "GET";
318
+ const normalizedEndpoint = normalizeEndpoint(options.endpoint);
319
+ const operation = options.operation;
320
+ const maxAttempts = this.maxAttemptsFor(operation);
321
+ const timeoutMs = this.timeoutFor(operation);
322
+ const traceId = options.traceId || randomId("trace");
323
+ let lastError = null;
324
+ for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
325
+ const spanId = randomId("span");
326
+ const startedAt = Date.now();
327
+ const controller = new AbortController();
328
+ const timeout = setTimeout(() => controller.abort(), timeoutMs);
329
+ try {
330
+ const attachApiKeyHeader = this.shouldAttachApiKeyHeader(normalizedEndpoint);
331
+ const response = await fetch(`${this.baseUrl}${normalizedEndpoint}`, {
332
+ method,
333
+ signal: controller.signal,
334
+ keepalive: method !== "GET",
335
+ headers: {
336
+ "Content-Type": "application/json",
337
+ Authorization: this.apiKey.startsWith("Bearer ") ? this.apiKey : `Bearer ${this.apiKey}`,
338
+ ...attachApiKeyHeader ? { "X-API-Key": this.apiKey.replace(/^Bearer\s+/i, "") } : {},
339
+ "x-trace-id": traceId,
340
+ "x-span-id": spanId,
341
+ "x-sdk-version": this.sdkVersion,
342
+ "x-sdk-runtime": this.runtimeName(),
343
+ ...options.headers || {}
344
+ },
345
+ body: method === "GET" || method === "DELETE" ? void 0 : JSON.stringify(options.body || {})
346
+ });
347
+ clearTimeout(timeout);
348
+ let payload = null;
349
+ try {
350
+ payload = await response.json();
351
+ } catch {
352
+ payload = await response.text().catch(() => "");
353
+ }
354
+ const durationMs = Date.now() - startedAt;
355
+ const record = {
356
+ id: randomId("diag"),
357
+ startedAt: new Date(startedAt).toISOString(),
358
+ endedAt: nowIso(),
359
+ traceId,
360
+ spanId,
361
+ operation,
362
+ method,
363
+ endpoint: normalizedEndpoint,
364
+ status: response.status,
365
+ durationMs,
366
+ success: response.ok
367
+ };
368
+ this.diagnostics.add(record);
369
+ if (response.ok) {
370
+ return {
371
+ data: payload,
372
+ status: response.status,
373
+ traceId
374
+ };
375
+ }
376
+ const message = toMessage(payload, response.status, response.statusText);
377
+ const retryable = this.shouldRetryStatus(response.status);
378
+ const error = new RuntimeClientError({
379
+ message,
380
+ status: response.status,
381
+ retryable,
382
+ code: response.status === 404 ? "NOT_FOUND" : "REQUEST_FAILED",
383
+ details: payload,
384
+ traceId
385
+ });
386
+ lastError = error;
387
+ if (!retryable || attempt === maxAttempts - 1) {
388
+ throw error;
389
+ }
390
+ } catch (error) {
391
+ clearTimeout(timeout);
392
+ const durationMs = Date.now() - startedAt;
393
+ const isAbort = isObject(error) && error.name === "AbortError";
394
+ const mapped = error instanceof RuntimeClientError ? error : new RuntimeClientError({
395
+ message: isAbort ? "Request timed out" : error instanceof Error ? error.message : "Network error",
396
+ retryable: this.retryPolicy.retryOnNetworkError ?? true,
397
+ code: isAbort ? "TIMEOUT" : "NETWORK_ERROR",
398
+ traceId
399
+ });
400
+ lastError = mapped;
401
+ this.diagnostics.add({
402
+ id: randomId("diag"),
403
+ startedAt: new Date(startedAt).toISOString(),
404
+ endedAt: nowIso(),
405
+ traceId,
406
+ spanId,
407
+ operation,
408
+ method,
409
+ endpoint: normalizedEndpoint,
410
+ durationMs,
411
+ success: false,
412
+ errorCode: mapped.code,
413
+ errorMessage: mapped.message
414
+ });
415
+ if (!mapped.retryable || attempt === maxAttempts - 1) {
416
+ throw mapped;
417
+ }
418
+ }
419
+ await new Promise((resolve) => setTimeout(resolve, this.backoff(attempt)));
420
+ }
421
+ throw lastError || new RuntimeClientError({
422
+ message: "Request failed",
423
+ retryable: false,
424
+ code: "REQUEST_FAILED"
425
+ });
426
+ }
427
+ };
428
+
34
429
  // ../src/sdk/whisper-agent.ts
430
+ var DEPRECATION_WARNINGS = /* @__PURE__ */ new Set();
431
+ function warnDeprecatedOnce(key, message) {
432
+ if (DEPRECATION_WARNINGS.has(key)) return;
433
+ DEPRECATION_WARNINGS.add(key);
434
+ if (typeof console !== "undefined" && typeof console.warn === "function") {
435
+ console.warn(message);
436
+ }
437
+ }
35
438
  var Whisper = class {
36
439
  client;
37
440
  options;
@@ -49,6 +452,10 @@ var Whisper = class {
49
452
  if (options.timeoutMs) clientConfig.timeoutMs = options.timeoutMs;
50
453
  if (options.retry) clientConfig.retry = options.retry;
51
454
  this.client = new WhisperContext(clientConfig);
455
+ warnDeprecatedOnce(
456
+ "whisper_agent_wrapper",
457
+ "[Whisper SDK] Whisper wrapper is supported for v2 compatibility. Prefer WhisperClient for new integrations."
458
+ );
52
459
  const finalRetry = options.retry || { maxAttempts: 3, baseDelayMs: 250, maxDelayMs: 2e3 };
53
460
  this.options = {
54
461
  apiKey: options.apiKey,
@@ -226,83 +633,1163 @@ ${context}` : "",
226
633
  return { success: false, extracted: 0 };
227
634
  }
228
635
  }
229
- /**
230
- * Run a full agent turn with automatic memory read (before) + write (after).
231
- */
232
- async runTurn(params) {
233
- const contextResult = await this.getContext(params.userMessage, {
636
+ /**
637
+ * Run a full agent turn with automatic memory read (before) + write (after).
638
+ */
639
+ async runTurn(params) {
640
+ const contextResult = await this.getContext(params.userMessage, {
641
+ userId: params.userId,
642
+ sessionId: params.sessionId,
643
+ project: params.project,
644
+ limit: params.limit
645
+ });
646
+ const prompt = contextResult.context ? `${contextResult.context}
647
+
648
+ User: ${params.userMessage}` : params.userMessage;
649
+ const response = await params.generate(prompt);
650
+ const captureResult = await this.captureSession(
651
+ [
652
+ { role: "user", content: params.userMessage },
653
+ { role: "assistant", content: response }
654
+ ],
655
+ {
656
+ userId: params.userId,
657
+ sessionId: params.sessionId,
658
+ project: params.project
659
+ }
660
+ );
661
+ return {
662
+ response,
663
+ context: contextResult.context,
664
+ count: contextResult.count,
665
+ extracted: captureResult.extracted
666
+ };
667
+ }
668
+ /**
669
+ * Direct access to WhisperContext for advanced usage
670
+ */
671
+ raw() {
672
+ return this.client;
673
+ }
674
+ extractMemoryIdsFromBulkResponse(bulkResponse) {
675
+ const ids = [];
676
+ if (Array.isArray(bulkResponse?.memories)) {
677
+ for (const memory of bulkResponse.memories) {
678
+ if (memory?.id) ids.push(memory.id);
679
+ }
680
+ }
681
+ if (bulkResponse?.memory?.id) {
682
+ ids.push(bulkResponse.memory.id);
683
+ }
684
+ if (bulkResponse?.id) {
685
+ ids.push(bulkResponse.id);
686
+ }
687
+ return Array.from(new Set(ids));
688
+ }
689
+ async fallbackCaptureViaAddMemory(messages, options) {
690
+ const userMessages = messages.filter((m) => m.role === "user").map((m) => (m.content || "").trim()).filter((content) => content.length >= 5).slice(-2);
691
+ if (userMessages.length === 0) {
692
+ return { success: false, extracted: 0 };
693
+ }
694
+ let extracted = 0;
695
+ for (const content of userMessages) {
696
+ try {
697
+ await this.client.addMemory({
698
+ project: options?.project ?? this.options.project,
699
+ content,
700
+ memory_type: "factual",
701
+ user_id: options?.userId ?? this.userId,
702
+ session_id: options?.sessionId ?? this.sessionId,
703
+ allow_legacy_fallback: true
704
+ });
705
+ extracted += 1;
706
+ } catch {
707
+ }
708
+ }
709
+ return { success: extracted > 0, extracted };
710
+ }
711
+ };
712
+ var whisper_agent_default = Whisper;
713
+
714
+ // ../src/sdk/core/cache.ts
715
+ var SearchResponseCache = class {
716
+ ttlMs;
717
+ capacity;
718
+ byKey = /* @__PURE__ */ new Map();
719
+ scopeIndex = /* @__PURE__ */ new Map();
720
+ constructor(ttlMs = 7e3, capacity = 500) {
721
+ this.ttlMs = Math.max(1e3, ttlMs);
722
+ this.capacity = Math.max(10, capacity);
723
+ }
724
+ makeScopeKey(project, userId, sessionId) {
725
+ return `${project}:${userId || "_"}:${sessionId || "_"}`;
726
+ }
727
+ makeKey(input) {
728
+ const normalized = {
729
+ project: input.project,
730
+ userId: input.userId || "",
731
+ sessionId: input.sessionId || "",
732
+ query: normalizeQuery(input.query),
733
+ topK: input.topK,
734
+ profile: input.profile,
735
+ includePending: input.includePending
736
+ };
737
+ return `search:${stableHash(JSON.stringify(normalized))}`;
738
+ }
739
+ get(key) {
740
+ const found = this.byKey.get(key);
741
+ if (!found) return null;
742
+ if (found.expiresAt <= Date.now()) {
743
+ this.deleteByKey(key);
744
+ return null;
745
+ }
746
+ found.touchedAt = Date.now();
747
+ return found.value;
748
+ }
749
+ set(key, scopeKey, value) {
750
+ this.byKey.set(key, {
751
+ value,
752
+ scopeKey,
753
+ touchedAt: Date.now(),
754
+ expiresAt: Date.now() + this.ttlMs
755
+ });
756
+ if (!this.scopeIndex.has(scopeKey)) {
757
+ this.scopeIndex.set(scopeKey, /* @__PURE__ */ new Set());
758
+ }
759
+ this.scopeIndex.get(scopeKey).add(key);
760
+ this.evictIfNeeded();
761
+ }
762
+ invalidateScope(scopeKey) {
763
+ const keys = this.scopeIndex.get(scopeKey);
764
+ if (!keys || keys.size === 0) {
765
+ return 0;
766
+ }
767
+ const toDelete = Array.from(keys);
768
+ for (const key of toDelete) {
769
+ this.deleteByKey(key);
770
+ }
771
+ this.scopeIndex.delete(scopeKey);
772
+ return toDelete.length;
773
+ }
774
+ evictIfNeeded() {
775
+ if (this.byKey.size <= this.capacity) return;
776
+ const ordered = Array.from(this.byKey.entries()).sort((a, b) => a[1].touchedAt - b[1].touchedAt);
777
+ const removeCount = this.byKey.size - this.capacity;
778
+ for (let i = 0; i < removeCount; i += 1) {
779
+ this.deleteByKey(ordered[i][0]);
780
+ }
781
+ }
782
+ deleteByKey(key) {
783
+ const found = this.byKey.get(key);
784
+ if (!found) return;
785
+ this.byKey.delete(key);
786
+ const scopeKeys = this.scopeIndex.get(found.scopeKey);
787
+ if (!scopeKeys) return;
788
+ scopeKeys.delete(key);
789
+ if (scopeKeys.size === 0) {
790
+ this.scopeIndex.delete(found.scopeKey);
791
+ }
792
+ }
793
+ };
794
+
795
+ // ../src/sdk/core/queue.ts
796
+ var InMemoryQueueStore = class {
797
+ items = [];
798
+ async load() {
799
+ return [...this.items];
800
+ }
801
+ async save(items) {
802
+ this.items = [...items];
803
+ }
804
+ };
805
+ var WriteQueue = class {
806
+ flushHandler;
807
+ store;
808
+ maxBatchSize;
809
+ flushIntervalMs;
810
+ maxAttempts;
811
+ queue = [];
812
+ flushTimer = null;
813
+ flushing = false;
814
+ lastFlushAt;
815
+ lastFlushCount = 0;
816
+ constructor(args) {
817
+ this.flushHandler = args.flushHandler;
818
+ this.store = args.store || new InMemoryQueueStore();
819
+ this.maxBatchSize = Math.max(1, args.maxBatchSize ?? 50);
820
+ this.flushIntervalMs = Math.max(10, args.flushIntervalMs ?? 100);
821
+ this.maxAttempts = Math.max(1, args.maxAttempts ?? 2);
822
+ }
823
+ async start() {
824
+ const pending = await this.store.load();
825
+ if (pending.length > 0) {
826
+ this.queue.push(...pending);
827
+ }
828
+ if (!this.flushTimer) {
829
+ this.flushTimer = setInterval(() => {
830
+ void this.flush();
831
+ }, this.flushIntervalMs);
832
+ const timer = this.flushTimer;
833
+ if (typeof timer.unref === "function") {
834
+ timer.unref();
835
+ }
836
+ }
837
+ this.bindProcessHooks();
838
+ }
839
+ async stop() {
840
+ if (this.flushTimer) {
841
+ clearInterval(this.flushTimer);
842
+ this.flushTimer = null;
843
+ }
844
+ await this.flush();
845
+ }
846
+ status() {
847
+ return {
848
+ queued: this.queue.length,
849
+ flushing: this.flushing,
850
+ lastFlushAt: this.lastFlushAt,
851
+ lastFlushCount: this.lastFlushCount
852
+ };
853
+ }
854
+ async enqueue(input) {
855
+ const eventId = input.eventId || this.makeEventId(input);
856
+ const item = {
857
+ ...input,
858
+ eventId,
859
+ createdAt: nowIso()
860
+ };
861
+ this.queue.push(item);
862
+ await this.store.save(this.queue);
863
+ if (this.queue.length >= this.maxBatchSize) {
864
+ void this.flush();
865
+ }
866
+ return item;
867
+ }
868
+ async flush() {
869
+ if (this.flushing || this.queue.length === 0) return;
870
+ this.flushing = true;
871
+ try {
872
+ while (this.queue.length > 0) {
873
+ const batch = this.queue.slice(0, this.maxBatchSize);
874
+ let done = false;
875
+ let error = null;
876
+ for (let attempt = 0; attempt < this.maxAttempts; attempt += 1) {
877
+ try {
878
+ await this.flushHandler(batch);
879
+ done = true;
880
+ break;
881
+ } catch (err) {
882
+ error = err;
883
+ await new Promise((resolve) => setTimeout(resolve, (attempt + 1) * 180));
884
+ }
885
+ }
886
+ if (!done) {
887
+ throw error instanceof Error ? error : new Error("Queue flush failed");
888
+ }
889
+ this.queue.splice(0, batch.length);
890
+ this.lastFlushAt = nowIso();
891
+ this.lastFlushCount = batch.length;
892
+ await this.store.save(this.queue);
893
+ }
894
+ } finally {
895
+ this.flushing = false;
896
+ }
897
+ }
898
+ makeEventId(input) {
899
+ const source = JSON.stringify({
900
+ project: input.project,
901
+ userId: input.userId || "",
902
+ sessionId: input.sessionId || "",
903
+ payload: input.payload
904
+ });
905
+ return `evt_${stableHash(source)}`;
906
+ }
907
+ bindProcessHooks() {
908
+ if (typeof process === "undefined") return;
909
+ const proc = process;
910
+ const flushOnExit = () => {
911
+ void this.flush();
912
+ };
913
+ proc.once("beforeExit", flushOnExit);
914
+ proc.once("SIGINT", flushOnExit);
915
+ proc.once("SIGTERM", flushOnExit);
916
+ }
917
+ };
918
+ function createStorageQueueStore(key = "whisper_sdk_queue") {
919
+ const getStorage = () => {
920
+ const maybeStorage = globalThis.localStorage;
921
+ if (!maybeStorage || typeof maybeStorage !== "object") return null;
922
+ const candidate = maybeStorage;
923
+ if (typeof candidate.getItem !== "function" || typeof candidate.setItem !== "function") {
924
+ return null;
925
+ }
926
+ return {
927
+ getItem: candidate.getItem,
928
+ setItem: candidate.setItem
929
+ };
930
+ };
931
+ return {
932
+ async load() {
933
+ const storage = getStorage();
934
+ if (!storage) return [];
935
+ const raw = storage.getItem(key);
936
+ if (!raw) return [];
937
+ try {
938
+ const parsed = JSON.parse(raw);
939
+ return Array.isArray(parsed) ? parsed : [];
940
+ } catch {
941
+ return [];
942
+ }
943
+ },
944
+ async save(items) {
945
+ const storage = getStorage();
946
+ if (!storage) return;
947
+ storage.setItem(key, JSON.stringify(items));
948
+ }
949
+ };
950
+ }
951
+ function createFileQueueStore(filePath) {
952
+ return {
953
+ async load() {
954
+ if (typeof process === "undefined") return [];
955
+ const fs = await import("fs/promises");
956
+ try {
957
+ const raw = await fs.readFile(filePath, "utf8");
958
+ const parsed = JSON.parse(raw);
959
+ return Array.isArray(parsed) ? parsed : [];
960
+ } catch (error) {
961
+ const nodeError = error;
962
+ if (nodeError?.code === "ENOENT") {
963
+ return [];
964
+ }
965
+ return [];
966
+ }
967
+ },
968
+ async save(items) {
969
+ if (typeof process === "undefined") return;
970
+ const fs = await import("fs/promises");
971
+ const path = await import("path");
972
+ const dir = path.dirname(filePath);
973
+ await fs.mkdir(dir, { recursive: true });
974
+ await fs.writeFile(filePath, JSON.stringify(items), "utf8");
975
+ }
976
+ };
977
+ }
978
+
979
+ // ../src/sdk/modules/memory.ts
980
+ function isEndpointNotFound(error) {
981
+ return error instanceof RuntimeClientError && error.status === 404;
982
+ }
983
+ function toSotaType(memoryType) {
984
+ if (!memoryType) return void 0;
985
+ switch (memoryType) {
986
+ case "episodic":
987
+ return "event";
988
+ case "semantic":
989
+ return "factual";
990
+ case "procedural":
991
+ return "instruction";
992
+ default:
993
+ return memoryType;
994
+ }
995
+ }
996
+ function toLegacyType(memoryType) {
997
+ if (!memoryType) return void 0;
998
+ switch (memoryType) {
999
+ case "event":
1000
+ return "episodic";
1001
+ case "instruction":
1002
+ return "procedural";
1003
+ case "preference":
1004
+ case "relationship":
1005
+ case "opinion":
1006
+ case "goal":
1007
+ return "semantic";
1008
+ default:
1009
+ return memoryType;
1010
+ }
1011
+ }
1012
+ var MemoryModule = class {
1013
+ constructor(client, cache, queue, options = {}) {
1014
+ this.client = client;
1015
+ this.cache = cache;
1016
+ this.queue = queue;
1017
+ this.options = options;
1018
+ }
1019
+ resolveProject(project) {
1020
+ const value = project || this.options.defaultProject;
1021
+ if (!value) {
1022
+ throw new RuntimeClientError({
1023
+ code: "MISSING_PROJECT",
1024
+ message: "Project is required",
1025
+ retryable: false
1026
+ });
1027
+ }
1028
+ return value;
1029
+ }
1030
+ invalidate(project, userId, sessionId) {
1031
+ if (this.options.cacheEnabled === false) {
1032
+ return;
1033
+ }
1034
+ const scope = this.cache.makeScopeKey(project, userId, sessionId);
1035
+ this.cache.invalidateScope(scope);
1036
+ }
1037
+ async add(params) {
1038
+ const project = this.resolveProject(params.project);
1039
+ const queueEnabled = this.options.queueEnabled !== false;
1040
+ const useQueue = queueEnabled && params.write_mode !== "sync" && params.async !== false;
1041
+ if (useQueue) {
1042
+ const queued = await this.queue.enqueue({
1043
+ project,
1044
+ userId: params.user_id,
1045
+ sessionId: params.session_id,
1046
+ payload: {
1047
+ content: params.content,
1048
+ memory_type: toSotaType(params.memory_type),
1049
+ user_id: params.user_id,
1050
+ session_id: params.session_id,
1051
+ agent_id: params.agent_id,
1052
+ importance: params.importance,
1053
+ confidence: params.confidence,
1054
+ metadata: params.metadata,
1055
+ document_date: params.document_date,
1056
+ event_date: params.event_date
1057
+ }
1058
+ });
1059
+ this.invalidate(project, params.user_id, params.session_id);
1060
+ return {
1061
+ success: true,
1062
+ mode: "async",
1063
+ queued: true,
1064
+ event_id: queued.eventId,
1065
+ accepted_at: queued.createdAt
1066
+ };
1067
+ }
1068
+ try {
1069
+ const response = await this.client.request({
1070
+ endpoint: "/v1/memory",
1071
+ method: "POST",
1072
+ operation: "writeAck",
1073
+ body: {
1074
+ project,
1075
+ content: params.content,
1076
+ memory_type: toSotaType(params.memory_type),
1077
+ user_id: params.user_id,
1078
+ session_id: params.session_id,
1079
+ agent_id: params.agent_id,
1080
+ importance: params.importance,
1081
+ confidence: params.confidence,
1082
+ metadata: params.metadata,
1083
+ document_date: params.document_date,
1084
+ event_date: params.event_date,
1085
+ write_mode: "sync"
1086
+ }
1087
+ });
1088
+ this.invalidate(project, params.user_id, params.session_id);
1089
+ return {
1090
+ success: true,
1091
+ mode: "sync",
1092
+ trace_id: response.traceId
1093
+ };
1094
+ } catch (error) {
1095
+ if (this.client.getCompatMode() !== "fallback" || !isEndpointNotFound(error)) {
1096
+ throw error;
1097
+ }
1098
+ await this.client.request({
1099
+ endpoint: "/v1/memories",
1100
+ method: "POST",
1101
+ operation: "writeAck",
1102
+ body: {
1103
+ project,
1104
+ content: params.content,
1105
+ memory_type: toLegacyType(params.memory_type),
1106
+ user_id: params.user_id,
1107
+ session_id: params.session_id,
1108
+ agent_id: params.agent_id,
1109
+ importance: params.importance,
1110
+ metadata: params.metadata
1111
+ }
1112
+ });
1113
+ this.invalidate(project, params.user_id, params.session_id);
1114
+ return {
1115
+ success: true,
1116
+ mode: "sync"
1117
+ };
1118
+ }
1119
+ }
1120
+ async addBulk(params) {
1121
+ const project = this.resolveProject(params.project);
1122
+ if (!Array.isArray(params.memories) || params.memories.length === 0) {
1123
+ throw new RuntimeClientError({
1124
+ code: "VALIDATION_ERROR",
1125
+ message: "memories is required",
1126
+ retryable: false
1127
+ });
1128
+ }
1129
+ const queueEnabled = this.options.queueEnabled !== false;
1130
+ const useQueue = queueEnabled && params.write_mode !== "sync" && params.async !== false;
1131
+ if (useQueue) {
1132
+ const queued = await Promise.all(
1133
+ params.memories.map(
1134
+ (memory) => this.queue.enqueue({
1135
+ project,
1136
+ userId: memory.user_id,
1137
+ sessionId: memory.session_id,
1138
+ payload: {
1139
+ content: memory.content,
1140
+ memory_type: toSotaType(memory.memory_type),
1141
+ user_id: memory.user_id,
1142
+ session_id: memory.session_id,
1143
+ agent_id: memory.agent_id,
1144
+ importance: memory.importance,
1145
+ confidence: memory.confidence,
1146
+ metadata: memory.metadata,
1147
+ document_date: memory.document_date,
1148
+ event_date: memory.event_date
1149
+ }
1150
+ })
1151
+ )
1152
+ );
1153
+ for (const memory of params.memories) {
1154
+ this.invalidate(project, memory.user_id, memory.session_id);
1155
+ }
1156
+ return {
1157
+ success: true,
1158
+ mode: "async",
1159
+ queued: true,
1160
+ created: queued.length
1161
+ };
1162
+ }
1163
+ try {
1164
+ const response = await this.client.request({
1165
+ endpoint: "/v1/memory/bulk",
1166
+ method: "POST",
1167
+ operation: "bulk",
1168
+ body: {
1169
+ project,
1170
+ memories: params.memories.map((memory) => ({
1171
+ ...memory,
1172
+ memory_type: toSotaType(memory.memory_type)
1173
+ })),
1174
+ write_mode: "sync"
1175
+ }
1176
+ });
1177
+ for (const memory of params.memories) {
1178
+ this.invalidate(project, memory.user_id, memory.session_id);
1179
+ }
1180
+ return {
1181
+ success: true,
1182
+ mode: "sync",
1183
+ trace_id: response.traceId
1184
+ };
1185
+ } catch (error) {
1186
+ if (this.client.getCompatMode() !== "fallback" || !isEndpointNotFound(error)) {
1187
+ throw error;
1188
+ }
1189
+ await Promise.all(
1190
+ params.memories.map(
1191
+ (memory) => this.add({
1192
+ project,
1193
+ ...memory,
1194
+ write_mode: "sync"
1195
+ })
1196
+ )
1197
+ );
1198
+ return {
1199
+ success: true,
1200
+ mode: "sync"
1201
+ };
1202
+ }
1203
+ }
1204
+ async search(params) {
1205
+ const project = this.resolveProject(params.project);
1206
+ const topK = params.top_k || 10;
1207
+ const profile = params.profile || "fast";
1208
+ const includePending = params.include_pending !== false;
1209
+ const cacheKey = this.cache.makeKey({
1210
+ project,
1211
+ userId: params.user_id,
1212
+ sessionId: params.session_id,
1213
+ query: params.query,
1214
+ topK,
1215
+ profile,
1216
+ includePending
1217
+ });
1218
+ if (this.options.cacheEnabled !== false) {
1219
+ const cached = this.cache.get(cacheKey);
1220
+ if (cached) {
1221
+ return {
1222
+ ...cached,
1223
+ cache_hit: true
1224
+ };
1225
+ }
1226
+ }
1227
+ try {
1228
+ const response = await this.client.request({
1229
+ endpoint: "/v1/memory/search",
1230
+ method: "POST",
1231
+ operation: "search",
1232
+ idempotent: true,
1233
+ body: {
1234
+ project,
1235
+ query: params.query,
1236
+ user_id: params.user_id,
1237
+ session_id: params.session_id,
1238
+ top_k: topK,
1239
+ profile,
1240
+ include_pending: includePending,
1241
+ memory_types: params.memory_type ? [toSotaType(params.memory_type)] : void 0
1242
+ }
1243
+ });
1244
+ const data = {
1245
+ ...response.data || {},
1246
+ cache_hit: false
1247
+ };
1248
+ if (this.options.cacheEnabled !== false) {
1249
+ const scope = this.cache.makeScopeKey(project, params.user_id, params.session_id);
1250
+ this.cache.set(cacheKey, scope, data);
1251
+ }
1252
+ return data;
1253
+ } catch (error) {
1254
+ if (this.client.getCompatMode() !== "fallback" || !isEndpointNotFound(error)) {
1255
+ throw error;
1256
+ }
1257
+ const legacy = await this.client.request({
1258
+ endpoint: "/v1/memories/search",
1259
+ method: "POST",
1260
+ operation: "search",
1261
+ idempotent: true,
1262
+ body: {
1263
+ project,
1264
+ query: params.query,
1265
+ user_id: params.user_id,
1266
+ session_id: params.session_id,
1267
+ top_k: topK,
1268
+ memory_type: toLegacyType(params.memory_type)
1269
+ }
1270
+ });
1271
+ const data = {
1272
+ ...legacy.data || {},
1273
+ cache_hit: false
1274
+ };
1275
+ if (this.options.cacheEnabled !== false) {
1276
+ const scope = this.cache.makeScopeKey(project, params.user_id, params.session_id);
1277
+ this.cache.set(cacheKey, scope, data);
1278
+ }
1279
+ return data;
1280
+ }
1281
+ }
1282
+ async getUserProfile(params) {
1283
+ const project = this.resolveProject(params.project);
1284
+ const query = new URLSearchParams({
1285
+ project,
1286
+ ...params.include_pending !== void 0 ? { include_pending: String(params.include_pending) } : {},
1287
+ ...params.memory_types ? { memory_types: params.memory_types } : {}
1288
+ });
1289
+ try {
1290
+ const response = await this.client.request({
1291
+ endpoint: `/v1/memory/profile/${params.user_id}?${query}`,
1292
+ method: "GET",
1293
+ operation: "profile",
1294
+ idempotent: true
1295
+ });
1296
+ return response.data;
1297
+ } catch (error) {
1298
+ if (this.client.getCompatMode() !== "fallback" || !isEndpointNotFound(error)) {
1299
+ throw error;
1300
+ }
1301
+ const legacyQuery = new URLSearchParams({
1302
+ project,
1303
+ user_id: params.user_id,
1304
+ limit: "200"
1305
+ });
1306
+ const legacy = await this.client.request({
1307
+ endpoint: `/v1/memories?${legacyQuery}`,
1308
+ method: "GET",
1309
+ operation: "profile",
1310
+ idempotent: true
1311
+ });
1312
+ const memories = Array.isArray(legacy.data?.memories) ? legacy.data.memories : [];
1313
+ return {
1314
+ user_id: params.user_id,
1315
+ memories,
1316
+ count: memories.length
1317
+ };
1318
+ }
1319
+ }
1320
+ async getSessionMemories(params) {
1321
+ const project = this.resolveProject(params.project);
1322
+ const query = new URLSearchParams({
1323
+ project,
1324
+ ...params.limit ? { limit: String(params.limit) } : {},
1325
+ ...params.include_pending !== void 0 ? { include_pending: String(params.include_pending) } : {}
1326
+ });
1327
+ const response = await this.client.request({
1328
+ endpoint: `/v1/memory/session/${params.session_id}?${query}`,
1329
+ method: "GET",
1330
+ operation: "profile",
1331
+ idempotent: true
1332
+ });
1333
+ return response.data;
1334
+ }
1335
+ async get(memoryId) {
1336
+ try {
1337
+ const response = await this.client.request({
1338
+ endpoint: `/v1/memory/${memoryId}`,
1339
+ method: "GET",
1340
+ operation: "get",
1341
+ idempotent: true
1342
+ });
1343
+ return response.data;
1344
+ } catch (error) {
1345
+ if (this.client.getCompatMode() !== "fallback" || !isEndpointNotFound(error)) {
1346
+ throw error;
1347
+ }
1348
+ const legacy = await this.client.request({
1349
+ endpoint: `/v1/memories/${memoryId}`,
1350
+ method: "GET",
1351
+ operation: "get",
1352
+ idempotent: true
1353
+ });
1354
+ return legacy.data;
1355
+ }
1356
+ }
1357
+ async update(memoryId, params) {
1358
+ try {
1359
+ await this.client.request({
1360
+ endpoint: `/v1/memory/${memoryId}`,
1361
+ method: "PUT",
1362
+ operation: "writeAck",
1363
+ body: params
1364
+ });
1365
+ return { success: true };
1366
+ } catch (error) {
1367
+ if (this.client.getCompatMode() !== "fallback" || !isEndpointNotFound(error)) {
1368
+ throw error;
1369
+ }
1370
+ await this.client.request({
1371
+ endpoint: `/v1/memories/${memoryId}`,
1372
+ method: "PUT",
1373
+ operation: "writeAck",
1374
+ body: { content: params.content }
1375
+ });
1376
+ return { success: true };
1377
+ }
1378
+ }
1379
+ async delete(memoryId) {
1380
+ try {
1381
+ await this.client.request({
1382
+ endpoint: `/v1/memory/${memoryId}`,
1383
+ method: "DELETE",
1384
+ operation: "writeAck"
1385
+ });
1386
+ return { success: true, deleted: memoryId };
1387
+ } catch (error) {
1388
+ if (this.client.getCompatMode() !== "fallback" || !isEndpointNotFound(error)) {
1389
+ throw error;
1390
+ }
1391
+ await this.client.request({
1392
+ endpoint: `/v1/memories/${memoryId}`,
1393
+ method: "DELETE",
1394
+ operation: "writeAck"
1395
+ });
1396
+ return { success: true, deleted: memoryId };
1397
+ }
1398
+ }
1399
+ async flag(params) {
1400
+ try {
1401
+ await this.client.request({
1402
+ endpoint: `/v1/memory/${params.memoryId}/flag`,
1403
+ method: "POST",
1404
+ operation: "writeAck",
1405
+ body: {
1406
+ reason: params.reason,
1407
+ severity: params.severity || "medium"
1408
+ }
1409
+ });
1410
+ return { success: true };
1411
+ } catch (error) {
1412
+ if (this.client.getCompatMode() !== "fallback" || !isEndpointNotFound(error)) {
1413
+ throw error;
1414
+ }
1415
+ await this.client.request({
1416
+ endpoint: `/v1/memory/${params.memoryId}`,
1417
+ method: "PUT",
1418
+ operation: "writeAck",
1419
+ body: {
1420
+ content: `[FLAGGED:${params.severity || "medium"}] ${params.reason}`
1421
+ }
1422
+ });
1423
+ return { success: true };
1424
+ }
1425
+ }
1426
+ };
1427
+
1428
+ // ../src/sdk/modules/session.ts
1429
+ function randomSessionId() {
1430
+ return `sess_${stableHash(`${Date.now()}_${Math.random()}`)}`;
1431
+ }
1432
+ function assertTransition(current, next) {
1433
+ const allowed = {
1434
+ created: ["active", "ended", "archived"],
1435
+ active: ["suspended", "ended", "archived"],
1436
+ suspended: ["resumed", "ended", "archived"],
1437
+ resumed: ["suspended", "ended", "archived"],
1438
+ ended: ["archived"],
1439
+ archived: []
1440
+ };
1441
+ if (!allowed[current].includes(next)) {
1442
+ throw new RuntimeClientError({
1443
+ code: "INVALID_SESSION_STATE",
1444
+ message: `Invalid session transition ${current} -> ${next}`,
1445
+ retryable: false
1446
+ });
1447
+ }
1448
+ }
1449
+ var SessionModule = class {
1450
+ constructor(memory, defaultProject) {
1451
+ this.memory = memory;
1452
+ this.defaultProject = defaultProject;
1453
+ }
1454
+ sessions = /* @__PURE__ */ new Map();
1455
+ resolveProject(project) {
1456
+ const value = project || this.defaultProject;
1457
+ if (!value) {
1458
+ throw new RuntimeClientError({
1459
+ code: "MISSING_PROJECT",
1460
+ message: "Project is required",
1461
+ retryable: false
1462
+ });
1463
+ }
1464
+ return value;
1465
+ }
1466
+ ensure(sessionId) {
1467
+ const found = this.sessions.get(sessionId);
1468
+ if (!found) {
1469
+ throw new RuntimeClientError({
1470
+ code: "SESSION_NOT_FOUND",
1471
+ message: `Unknown session ${sessionId}`,
1472
+ retryable: false
1473
+ });
1474
+ }
1475
+ return found;
1476
+ }
1477
+ async start(params) {
1478
+ const project = this.resolveProject(params.project);
1479
+ const sessionId = params.sessionId || randomSessionId();
1480
+ const now = nowIso();
1481
+ const record = {
1482
+ sessionId,
1483
+ project,
234
1484
  userId: params.userId,
235
- sessionId: params.sessionId,
236
- project: params.project,
237
- limit: params.limit
1485
+ state: "active",
1486
+ sequence: 0,
1487
+ metadata: params.metadata,
1488
+ createdAt: now,
1489
+ updatedAt: now
1490
+ };
1491
+ this.sessions.set(sessionId, record);
1492
+ return {
1493
+ sessionId,
1494
+ state: record.state,
1495
+ createdAt: now
1496
+ };
1497
+ }
1498
+ async event(params) {
1499
+ const session = this.ensure(params.sessionId);
1500
+ if (session.state !== "active" && session.state !== "resumed") {
1501
+ throw new RuntimeClientError({
1502
+ code: "INVALID_SESSION_STATE",
1503
+ message: `Cannot append event in ${session.state} state`,
1504
+ retryable: false
1505
+ });
1506
+ }
1507
+ session.sequence += 1;
1508
+ session.updatedAt = nowIso();
1509
+ const eventId = `evt_${stableHash(JSON.stringify({
1510
+ sessionId: session.sessionId,
1511
+ seq: session.sequence,
1512
+ type: params.type,
1513
+ content: params.content,
1514
+ parent: params.parentEventId || ""
1515
+ }))}`;
1516
+ await this.memory.add({
1517
+ project: session.project,
1518
+ content: `${params.type}: ${params.content}`,
1519
+ memory_type: "event",
1520
+ user_id: session.userId,
1521
+ session_id: session.sessionId,
1522
+ metadata: {
1523
+ session_event: true,
1524
+ event_id: eventId,
1525
+ sequence: session.sequence,
1526
+ parent_event_id: params.parentEventId,
1527
+ ...session.metadata,
1528
+ ...params.metadata || {}
1529
+ },
1530
+ write_mode: "async"
238
1531
  });
239
- const prompt = contextResult.context ? `${contextResult.context}
240
-
241
- User: ${params.userMessage}` : params.userMessage;
242
- const response = await params.generate(prompt);
243
- const captureResult = await this.captureSession(
244
- [
245
- { role: "user", content: params.userMessage },
246
- { role: "assistant", content: response }
247
- ],
248
- {
249
- userId: params.userId,
250
- sessionId: params.sessionId,
251
- project: params.project
252
- }
253
- );
254
1532
  return {
255
- response,
256
- context: contextResult.context,
257
- count: contextResult.count,
258
- extracted: captureResult.extracted
1533
+ success: true,
1534
+ eventId,
1535
+ sequence: session.sequence
259
1536
  };
260
1537
  }
261
- /**
262
- * Direct access to WhisperContext for advanced usage
263
- */
264
- raw() {
265
- return this.client;
1538
+ async suspend(params) {
1539
+ const session = this.ensure(params.sessionId);
1540
+ assertTransition(session.state, "suspended");
1541
+ session.state = "suspended";
1542
+ session.updatedAt = nowIso();
1543
+ return { sessionId: session.sessionId, state: session.state };
1544
+ }
1545
+ async resume(params) {
1546
+ const session = this.ensure(params.sessionId);
1547
+ const target = session.state === "suspended" ? "resumed" : "active";
1548
+ assertTransition(session.state, target);
1549
+ session.state = target;
1550
+ session.updatedAt = nowIso();
1551
+ return { sessionId: session.sessionId, state: session.state };
1552
+ }
1553
+ async end(params) {
1554
+ const session = this.ensure(params.sessionId);
1555
+ assertTransition(session.state, "ended");
1556
+ session.state = "ended";
1557
+ session.updatedAt = nowIso();
1558
+ return { sessionId: session.sessionId, state: session.state };
1559
+ }
1560
+ async archive(params) {
1561
+ const session = this.ensure(params.sessionId);
1562
+ assertTransition(session.state, "archived");
1563
+ session.state = "archived";
1564
+ session.updatedAt = nowIso();
1565
+ return { sessionId: session.sessionId, state: session.state };
266
1566
  }
267
- extractMemoryIdsFromBulkResponse(bulkResponse) {
268
- const ids = [];
269
- if (Array.isArray(bulkResponse?.memories)) {
270
- for (const memory of bulkResponse.memories) {
271
- if (memory?.id) ids.push(memory.id);
272
- }
273
- }
274
- if (bulkResponse?.memory?.id) {
275
- ids.push(bulkResponse.memory.id);
276
- }
277
- if (bulkResponse?.id) {
278
- ids.push(bulkResponse.id);
279
- }
280
- return Array.from(new Set(ids));
1567
+ };
1568
+
1569
+ // ../src/sdk/modules/profile.ts
1570
+ var ProfileModule = class {
1571
+ constructor(memory) {
1572
+ this.memory = memory;
281
1573
  }
282
- async fallbackCaptureViaAddMemory(messages, options) {
283
- const userMessages = messages.filter((m) => m.role === "user").map((m) => (m.content || "").trim()).filter((content) => content.length >= 5).slice(-2);
284
- if (userMessages.length === 0) {
285
- return { success: false, extracted: 0 };
1574
+ async getUserProfile(params) {
1575
+ return this.memory.getUserProfile(params);
1576
+ }
1577
+ async getSessionMemories(params) {
1578
+ return this.memory.getSessionMemories(params);
1579
+ }
1580
+ };
1581
+
1582
+ // ../src/sdk/modules/analytics.ts
1583
+ var AnalyticsModule = class {
1584
+ constructor(diagnostics, queue) {
1585
+ this.diagnostics = diagnostics;
1586
+ this.queue = queue;
1587
+ }
1588
+ diagnosticsSnapshot() {
1589
+ return this.diagnostics.snapshot();
1590
+ }
1591
+ queueStatus() {
1592
+ return this.queue.status();
1593
+ }
1594
+ };
1595
+
1596
+ // ../src/sdk/whisper.ts
1597
+ var WhisperClient = class _WhisperClient {
1598
+ constructor(config) {
1599
+ this.config = config;
1600
+ this.diagnosticsStore = new DiagnosticsStore(config.telemetry?.maxEntries || 1e3);
1601
+ this.runtimeClient = new RuntimeClient(
1602
+ {
1603
+ apiKey: config.apiKey,
1604
+ baseUrl: config.baseUrl,
1605
+ compatMode: config.compatMode || "fallback",
1606
+ timeouts: config.timeouts,
1607
+ retryPolicy: config.retryPolicy
1608
+ },
1609
+ this.diagnosticsStore
1610
+ );
1611
+ this.searchCache = new SearchResponseCache(
1612
+ config.cache?.ttlMs ?? 7e3,
1613
+ config.cache?.capacity ?? 500
1614
+ );
1615
+ const queueStore = config.queue?.persistence === "storage" ? createStorageQueueStore() : config.queue?.persistence === "file" && config.queue.filePath ? createFileQueueStore(config.queue.filePath) : new InMemoryQueueStore();
1616
+ this.writeQueue = new WriteQueue({
1617
+ store: queueStore,
1618
+ maxBatchSize: config.queue?.maxBatchSize ?? 50,
1619
+ flushIntervalMs: config.queue?.flushIntervalMs ?? 100,
1620
+ maxAttempts: config.queue?.maxAttempts ?? 2,
1621
+ flushHandler: async (items) => {
1622
+ if (items.length === 0) return;
1623
+ const project = items[0].project;
1624
+ const memories = items.map((item) => ({
1625
+ ...item.payload,
1626
+ user_id: item.payload.user_id ?? item.userId,
1627
+ session_id: item.payload.session_id ?? item.sessionId,
1628
+ metadata: {
1629
+ ...item.payload.metadata || {},
1630
+ event_id: item.eventId,
1631
+ queued_at: item.createdAt
1632
+ }
1633
+ }));
1634
+ try {
1635
+ await this.runtimeClient.request({
1636
+ endpoint: "/v1/memory/bulk",
1637
+ method: "POST",
1638
+ operation: "bulk",
1639
+ body: {
1640
+ project,
1641
+ write_mode: "async",
1642
+ memories
1643
+ }
1644
+ });
1645
+ } catch (error) {
1646
+ if (this.runtimeClient.getCompatMode() !== "fallback" || !(error instanceof RuntimeClientError) || error.status !== 404) {
1647
+ throw error;
1648
+ }
1649
+ await Promise.all(
1650
+ memories.map(async (memory) => {
1651
+ try {
1652
+ await this.runtimeClient.request({
1653
+ endpoint: "/v1/memory",
1654
+ method: "POST",
1655
+ operation: "writeAck",
1656
+ body: {
1657
+ project,
1658
+ ...memory,
1659
+ write_mode: "sync"
1660
+ }
1661
+ });
1662
+ } catch (fallbackError) {
1663
+ if (this.runtimeClient.getCompatMode() !== "fallback" || !(fallbackError instanceof RuntimeClientError) || fallbackError.status !== 404) {
1664
+ throw fallbackError;
1665
+ }
1666
+ await this.runtimeClient.request({
1667
+ endpoint: "/v1/memories",
1668
+ method: "POST",
1669
+ operation: "writeAck",
1670
+ body: {
1671
+ project,
1672
+ ...memory,
1673
+ memory_type: memory.memory_type === "event" ? "episodic" : memory.memory_type
1674
+ }
1675
+ });
1676
+ }
1677
+ })
1678
+ );
1679
+ }
1680
+ }
1681
+ });
1682
+ if (config.queue?.enabled !== false) {
1683
+ void this.writeQueue.start();
286
1684
  }
287
- let extracted = 0;
288
- for (const content of userMessages) {
289
- try {
290
- await this.client.addMemory({
291
- project: options?.project ?? this.options.project,
292
- content,
293
- memory_type: "factual",
294
- user_id: options?.userId ?? this.userId,
295
- session_id: options?.sessionId ?? this.sessionId,
296
- allow_legacy_fallback: true
297
- });
298
- extracted += 1;
299
- } catch {
1685
+ this.memoryModule = new MemoryModule(
1686
+ this.runtimeClient,
1687
+ this.searchCache,
1688
+ this.writeQueue,
1689
+ {
1690
+ defaultProject: config.project,
1691
+ cacheEnabled: config.cache?.enabled !== false,
1692
+ queueEnabled: config.queue?.enabled !== false
300
1693
  }
1694
+ );
1695
+ this.sessionModule = new SessionModule(this.memoryModule, config.project);
1696
+ this.profileModule = new ProfileModule(this.memoryModule);
1697
+ this.analyticsModule = new AnalyticsModule(this.diagnosticsStore, this.writeQueue);
1698
+ this.diagnostics = {
1699
+ getLast: (limit) => this.diagnosticsStore.getLast(limit),
1700
+ subscribe: (fn) => this.diagnosticsStore.subscribe(fn),
1701
+ snapshot: () => this.diagnosticsStore.snapshot()
1702
+ };
1703
+ this.queue = {
1704
+ flush: () => this.writeQueue.flush(),
1705
+ status: () => this.writeQueue.status()
1706
+ };
1707
+ this.memory = {
1708
+ add: (params) => this.memoryModule.add(params),
1709
+ addBulk: (params) => this.memoryModule.addBulk(params),
1710
+ search: (params) => this.memoryModule.search(params),
1711
+ get: (memoryId) => this.memoryModule.get(memoryId),
1712
+ getUserProfile: (params) => this.memoryModule.getUserProfile(params),
1713
+ getSessionMemories: (params) => this.memoryModule.getSessionMemories(params),
1714
+ update: (memoryId, params) => this.memoryModule.update(memoryId, params),
1715
+ delete: (memoryId) => this.memoryModule.delete(memoryId),
1716
+ flag: (params) => this.memoryModule.flag(params)
1717
+ };
1718
+ this.session = {
1719
+ start: (params) => this.sessionModule.start(params),
1720
+ event: (params) => this.sessionModule.event(params),
1721
+ suspend: (params) => this.sessionModule.suspend(params),
1722
+ resume: (params) => this.sessionModule.resume(params),
1723
+ end: (params) => this.sessionModule.end(params)
1724
+ };
1725
+ this.profile = {
1726
+ getUserProfile: (params) => this.profileModule.getUserProfile(params),
1727
+ getSessionMemories: (params) => this.profileModule.getSessionMemories(params)
1728
+ };
1729
+ this.analytics = {
1730
+ diagnosticsSnapshot: () => this.analyticsModule.diagnosticsSnapshot(),
1731
+ queueStatus: () => this.analyticsModule.queueStatus()
1732
+ };
1733
+ }
1734
+ diagnostics;
1735
+ queue;
1736
+ memory;
1737
+ session;
1738
+ profile;
1739
+ analytics;
1740
+ runtimeClient;
1741
+ diagnosticsStore;
1742
+ searchCache;
1743
+ writeQueue;
1744
+ memoryModule;
1745
+ sessionModule;
1746
+ profileModule;
1747
+ analyticsModule;
1748
+ static fromEnv(overrides = {}) {
1749
+ const env = typeof process !== "undefined" ? process.env : {};
1750
+ const apiKey = overrides.apiKey || env.WHISPER_API_KEY || env.USEWHISPER_API_KEY || env.API_KEY;
1751
+ if (!apiKey) {
1752
+ throw new Error("Missing API key. Set WHISPER_API_KEY / USEWHISPER_API_KEY / API_KEY.");
301
1753
  }
302
- return { success: extracted > 0, extracted };
1754
+ return new _WhisperClient({
1755
+ apiKey,
1756
+ baseUrl: overrides.baseUrl || env.WHISPER_BASE_URL || env.API_BASE_URL || "https://context.usewhisper.dev",
1757
+ project: overrides.project || env.WHISPER_PROJECT || env.PROJECT,
1758
+ ...overrides
1759
+ });
1760
+ }
1761
+ withRunContext(context) {
1762
+ const base = this;
1763
+ return {
1764
+ memory: {
1765
+ add: (params) => base.memory.add({
1766
+ ...params,
1767
+ project: params.project || context.project || base.config.project,
1768
+ user_id: params.user_id || context.userId,
1769
+ session_id: params.session_id || context.sessionId
1770
+ }),
1771
+ search: (params) => base.memory.search({
1772
+ ...params,
1773
+ project: params.project || context.project || base.config.project,
1774
+ user_id: params.user_id || context.userId,
1775
+ session_id: params.session_id || context.sessionId
1776
+ })
1777
+ },
1778
+ session: {
1779
+ event: (params) => base.session.event({
1780
+ ...params,
1781
+ sessionId: params.sessionId || context.sessionId || ""
1782
+ })
1783
+ },
1784
+ queue: base.queue,
1785
+ diagnostics: base.diagnostics
1786
+ };
1787
+ }
1788
+ async shutdown() {
1789
+ await this.writeQueue.stop();
303
1790
  }
304
1791
  };
305
- var whisper_agent_default = Whisper;
1792
+ var whisper_default = WhisperClient;
306
1793
 
307
1794
  // ../src/sdk/middleware.ts
308
1795
  var WhisperAgentMiddleware = class {
@@ -373,14 +1860,409 @@ function createAgentMiddleware(config) {
373
1860
  return new WhisperAgentMiddleware(config);
374
1861
  }
375
1862
 
1863
+ // ../src/sdk/adapters/langchain.ts
1864
+ var LangChainMemoryAdapter = class {
1865
+ constructor(client, options) {
1866
+ this.client = client;
1867
+ this.options = options;
1868
+ this.memoryKey = options.memoryKey || "history";
1869
+ this.memoryKeys = [this.memoryKey];
1870
+ }
1871
+ memoryKeys;
1872
+ memoryKey;
1873
+ async loadMemoryVariables(_inputValues) {
1874
+ const response = await this.client.memory.search({
1875
+ project: this.options.project,
1876
+ query: "recent context",
1877
+ user_id: this.options.userId,
1878
+ session_id: this.options.sessionId,
1879
+ top_k: this.options.topK || 10,
1880
+ profile: this.options.profile || "fast",
1881
+ include_pending: true
1882
+ });
1883
+ const content = (response.results || []).map((row) => row.memory?.content || "").filter(Boolean).join("\n");
1884
+ return {
1885
+ [this.memoryKey]: content
1886
+ };
1887
+ }
1888
+ async saveContext(inputValues, outputValues) {
1889
+ const userInput = typeof inputValues.input === "string" ? inputValues.input : JSON.stringify(inputValues);
1890
+ const output = typeof outputValues.output === "string" ? outputValues.output : JSON.stringify(outputValues);
1891
+ await this.client.memory.addBulk({
1892
+ project: this.options.project,
1893
+ write_mode: "async",
1894
+ memories: [
1895
+ {
1896
+ content: `user: ${userInput}`,
1897
+ memory_type: "event",
1898
+ user_id: this.options.userId,
1899
+ session_id: this.options.sessionId
1900
+ },
1901
+ {
1902
+ content: `assistant: ${output}`,
1903
+ memory_type: "event",
1904
+ user_id: this.options.userId,
1905
+ session_id: this.options.sessionId
1906
+ }
1907
+ ]
1908
+ });
1909
+ }
1910
+ async clear() {
1911
+ const profile = await this.client.memory.getUserProfile({
1912
+ project: this.options.project,
1913
+ user_id: this.options.userId
1914
+ });
1915
+ await Promise.all(
1916
+ (profile.memories || []).map((memory) => String(memory.id || "")).filter(Boolean).map((id) => this.client.memory.delete(id))
1917
+ );
1918
+ }
1919
+ };
1920
+ function createLangChainMemoryAdapter(client, options) {
1921
+ return new LangChainMemoryAdapter(client, options);
1922
+ }
1923
+
1924
+ // ../src/sdk/adapters/langgraph.ts
1925
+ function asRecord(value) {
1926
+ return value && typeof value === "object" ? value : {};
1927
+ }
1928
+ function text(value) {
1929
+ return typeof value === "string" && value.trim() ? value : void 0;
1930
+ }
1931
+ function isTupleLike(value) {
1932
+ if (!value || typeof value !== "object") return false;
1933
+ const tuple = value;
1934
+ const config = asRecord(tuple.config);
1935
+ const configurable = asRecord(config.configurable);
1936
+ return Boolean(
1937
+ typeof configurable.thread_id === "string" && tuple.checkpoint && typeof tuple.checkpoint === "object"
1938
+ );
1939
+ }
1940
+ function tupleTimestamp(tuple, fallback) {
1941
+ const checkpoint = asRecord(tuple.checkpoint);
1942
+ const metadata = asRecord(tuple.metadata);
1943
+ const sources = [
1944
+ checkpoint.updatedAt,
1945
+ checkpoint.updated_at,
1946
+ checkpoint.ts,
1947
+ checkpoint.timestamp,
1948
+ metadata.updatedAt,
1949
+ metadata.updated_at,
1950
+ metadata.ts,
1951
+ metadata.timestamp,
1952
+ fallback
1953
+ ];
1954
+ for (const source of sources) {
1955
+ const parsed = source ? new Date(String(source)).getTime() : Number.NaN;
1956
+ if (!Number.isNaN(parsed) && parsed > 0) return parsed;
1957
+ }
1958
+ return 0;
1959
+ }
1960
+ function metadataMatches(target, filter) {
1961
+ if (!filter || Object.keys(filter).length === 0) return true;
1962
+ const value = target || {};
1963
+ return Object.entries(filter).every(([key, expected]) => {
1964
+ if (!(key in value)) return false;
1965
+ return JSON.stringify(value[key]) === JSON.stringify(expected);
1966
+ });
1967
+ }
1968
+ var LangGraphCheckpointAdapter = class {
1969
+ constructor(client, options = {}) {
1970
+ this.client = client;
1971
+ this.options = options;
1972
+ }
1973
+ localByKey = /* @__PURE__ */ new Map();
1974
+ localByThread = /* @__PURE__ */ new Map();
1975
+ options;
1976
+ getUserId(threadId) {
1977
+ const prefix = this.options.userIdPrefix || "langgraph-thread";
1978
+ return `${prefix}:${threadId}`;
1979
+ }
1980
+ resolveCheckpointNs(config) {
1981
+ return config.configurable.checkpoint_ns || this.options.defaultCheckpointNs || "default";
1982
+ }
1983
+ makeLocalKey(threadId, checkpointNs, checkpointId) {
1984
+ return `${threadId}:${checkpointNs}:${checkpointId}`;
1985
+ }
1986
+ normalizeTuple(tuple) {
1987
+ const config = asRecord(tuple.config);
1988
+ const configurable = asRecord(config.configurable);
1989
+ const threadId = text(configurable.thread_id) || "";
1990
+ const checkpointNs = text(configurable.checkpoint_ns) || this.options.defaultCheckpointNs || "default";
1991
+ const checkpointId = text(configurable.checkpoint_id) || "";
1992
+ return {
1993
+ config: {
1994
+ configurable: {
1995
+ thread_id: threadId,
1996
+ checkpoint_ns: checkpointNs,
1997
+ checkpoint_id: checkpointId || void 0
1998
+ }
1999
+ },
2000
+ checkpoint: asRecord(tuple.checkpoint),
2001
+ metadata: asRecord(tuple.metadata),
2002
+ parent_config: tuple.parent_config ? {
2003
+ configurable: {
2004
+ thread_id: text(tuple.parent_config.configurable.thread_id) || "",
2005
+ checkpoint_ns: text(tuple.parent_config.configurable.checkpoint_ns) || checkpointNs,
2006
+ checkpoint_id: text(tuple.parent_config.configurable.checkpoint_id)
2007
+ }
2008
+ } : null
2009
+ };
2010
+ }
2011
+ parseCheckpointTupleFromRow(row) {
2012
+ const rowMetadata = asRecord(row.metadata);
2013
+ const marker = rowMetadata.langgraph_checkpoint === true;
2014
+ const rawContent = text(row.content) || "";
2015
+ if (!rawContent) return null;
2016
+ try {
2017
+ const parsed = JSON.parse(rawContent);
2018
+ let tuple = null;
2019
+ if (isTupleLike(parsed)) {
2020
+ tuple = this.normalizeTuple(parsed);
2021
+ } else {
2022
+ const wrapped = asRecord(parsed);
2023
+ if (isTupleLike(wrapped.tuple)) {
2024
+ tuple = this.normalizeTuple(wrapped.tuple);
2025
+ }
2026
+ }
2027
+ if (!tuple) return null;
2028
+ const config = tuple.config.configurable;
2029
+ if (!config.thread_id) return null;
2030
+ if (!config.checkpoint_id) return null;
2031
+ if (!marker && rowMetadata.checkpoint_id !== config.checkpoint_id) {
2032
+ return null;
2033
+ }
2034
+ return {
2035
+ tuple,
2036
+ memoryId: text(row.id),
2037
+ createdAt: text(row.createdAt) || text(row.created_at),
2038
+ updatedAt: text(row.updatedAt) || text(row.updated_at)
2039
+ };
2040
+ } catch {
2041
+ return null;
2042
+ }
2043
+ }
2044
+ upsertLocal(record) {
2045
+ const cfg = record.tuple.config.configurable;
2046
+ const key = this.makeLocalKey(cfg.thread_id, cfg.checkpoint_ns || "default", cfg.checkpoint_id || "");
2047
+ this.localByKey.set(key, record);
2048
+ if (!this.localByThread.has(cfg.thread_id)) {
2049
+ this.localByThread.set(cfg.thread_id, /* @__PURE__ */ new Set());
2050
+ }
2051
+ this.localByThread.get(cfg.thread_id).add(key);
2052
+ }
2053
+ mergeWithLocal(records, threadId) {
2054
+ const merged = /* @__PURE__ */ new Map();
2055
+ for (const record of records) {
2056
+ const cfg = record.tuple.config.configurable;
2057
+ const key = this.makeLocalKey(cfg.thread_id, cfg.checkpoint_ns || "default", cfg.checkpoint_id || "");
2058
+ merged.set(key, record);
2059
+ }
2060
+ const localKeys = this.localByThread.get(threadId);
2061
+ if (localKeys) {
2062
+ for (const key of localKeys) {
2063
+ const local = this.localByKey.get(key);
2064
+ if (local) {
2065
+ merged.set(key, local);
2066
+ }
2067
+ }
2068
+ }
2069
+ return Array.from(merged.values());
2070
+ }
2071
+ applyListFilters(records, options) {
2072
+ let filtered = records;
2073
+ if (options?.filter?.checkpointNs) {
2074
+ filtered = filtered.filter(
2075
+ (record) => (record.tuple.config.configurable.checkpoint_ns || "default") === options.filter.checkpointNs
2076
+ );
2077
+ }
2078
+ if (options?.filter?.metadata) {
2079
+ filtered = filtered.filter((record) => metadataMatches(record.tuple.metadata, options.filter.metadata));
2080
+ }
2081
+ if (options?.before?.checkpointId) {
2082
+ const beforeId = options.before.checkpointId;
2083
+ filtered = filtered.filter(
2084
+ (record) => record.tuple.config.configurable.checkpoint_id !== beforeId
2085
+ );
2086
+ }
2087
+ if (options?.before?.updatedAt) {
2088
+ const cutoff = new Date(options.before.updatedAt).getTime();
2089
+ if (!Number.isNaN(cutoff)) {
2090
+ filtered = filtered.filter((record) => {
2091
+ const value = tupleTimestamp(record.tuple, record.updatedAt || record.createdAt);
2092
+ return value < cutoff;
2093
+ });
2094
+ }
2095
+ }
2096
+ const direction = options?.sort || "desc";
2097
+ filtered.sort((a, b) => {
2098
+ const ta = tupleTimestamp(a.tuple, a.updatedAt || a.createdAt);
2099
+ const tb = tupleTimestamp(b.tuple, b.updatedAt || b.createdAt);
2100
+ return direction === "asc" ? ta - tb : tb - ta;
2101
+ });
2102
+ if (options?.limit && options.limit > 0) {
2103
+ return filtered.slice(0, options.limit);
2104
+ }
2105
+ return filtered;
2106
+ }
2107
+ async fetchThreadRecords(threadId) {
2108
+ const profile = await this.client.memory.getUserProfile({
2109
+ project: this.options.project,
2110
+ user_id: this.getUserId(threadId),
2111
+ include_pending: true
2112
+ });
2113
+ const parsed = (profile.memories || []).map((row) => this.parseCheckpointTupleFromRow(row)).filter((value) => value !== null).filter((record) => record.tuple.config.configurable.thread_id === threadId);
2114
+ const merged = this.mergeWithLocal(parsed, threadId);
2115
+ for (const record of merged) {
2116
+ this.upsertLocal(record);
2117
+ }
2118
+ return merged;
2119
+ }
2120
+ async get(config) {
2121
+ const threadId = config.configurable.thread_id;
2122
+ const checkpointNs = this.resolveCheckpointNs(config);
2123
+ const checkpointId = config.configurable.checkpoint_id;
2124
+ if (checkpointId) {
2125
+ const local = this.localByKey.get(this.makeLocalKey(threadId, checkpointNs, checkpointId));
2126
+ if (local) return local.tuple;
2127
+ }
2128
+ const records = await this.fetchThreadRecords(threadId);
2129
+ const scoped = records.filter((record) => {
2130
+ const cfg = record.tuple.config.configurable;
2131
+ if ((cfg.checkpoint_ns || "default") !== checkpointNs) return false;
2132
+ if (!checkpointId) return true;
2133
+ return cfg.checkpoint_id === checkpointId;
2134
+ });
2135
+ if (scoped.length === 0) return void 0;
2136
+ scoped.sort((a, b) => {
2137
+ const ta = tupleTimestamp(a.tuple, a.updatedAt || a.createdAt);
2138
+ const tb = tupleTimestamp(b.tuple, b.updatedAt || b.createdAt);
2139
+ return tb - ta;
2140
+ });
2141
+ return scoped[0].tuple;
2142
+ }
2143
+ async put(config, checkpoint, metadata, parentConfig) {
2144
+ const threadId = config.configurable.thread_id;
2145
+ const checkpointNs = this.resolveCheckpointNs(config);
2146
+ const checkpointId = config.configurable.checkpoint_id || text(checkpoint.id) || `cp_${stableHash(JSON.stringify({
2147
+ threadId,
2148
+ checkpointNs,
2149
+ checkpoint,
2150
+ metadata: metadata || {},
2151
+ parentConfig: parentConfig || null
2152
+ }))}`;
2153
+ const tuple = this.normalizeTuple({
2154
+ config: {
2155
+ configurable: {
2156
+ thread_id: threadId,
2157
+ checkpoint_ns: checkpointNs,
2158
+ checkpoint_id: checkpointId
2159
+ }
2160
+ },
2161
+ checkpoint: {
2162
+ ...checkpoint,
2163
+ id: checkpointId
2164
+ },
2165
+ metadata: {
2166
+ ...metadata || {},
2167
+ checkpoint_ns: checkpointNs,
2168
+ written_at: nowIso()
2169
+ },
2170
+ parent_config: parentConfig ? this.normalizeTuple({
2171
+ config: parentConfig,
2172
+ checkpoint: {},
2173
+ metadata: {},
2174
+ parent_config: null
2175
+ }).config : null
2176
+ });
2177
+ const record = { tuple, updatedAt: nowIso() };
2178
+ this.upsertLocal(record);
2179
+ await this.client.memory.add({
2180
+ project: this.options.project,
2181
+ user_id: this.getUserId(threadId),
2182
+ session_id: threadId,
2183
+ memory_type: "event",
2184
+ write_mode: "async",
2185
+ content: JSON.stringify(tuple),
2186
+ metadata: {
2187
+ langgraph_checkpoint: true,
2188
+ thread_id: threadId,
2189
+ checkpoint_ns: checkpointNs,
2190
+ checkpoint_id: checkpointId,
2191
+ parent_checkpoint_id: parentConfig?.configurable.checkpoint_id
2192
+ }
2193
+ });
2194
+ return tuple.config;
2195
+ }
2196
+ async list(config, options) {
2197
+ const threadId = config.configurable.thread_id;
2198
+ const checkpointNs = this.resolveCheckpointNs(config);
2199
+ const records = await this.fetchThreadRecords(threadId);
2200
+ const scoped = records.filter(
2201
+ (record) => (record.tuple.config.configurable.checkpoint_ns || "default") === checkpointNs
2202
+ );
2203
+ return this.applyListFilters(scoped, options).map((record) => record.tuple);
2204
+ }
2205
+ async search(params) {
2206
+ const includePending = params.includePending !== false;
2207
+ const profile = params.profile || "fast";
2208
+ const checkpointNs = params.checkpointNs || this.options.defaultCheckpointNs || "default";
2209
+ const response = await this.client.memory.search({
2210
+ project: this.options.project,
2211
+ query: params.query,
2212
+ user_id: this.getUserId(params.threadId),
2213
+ session_id: params.threadId,
2214
+ top_k: params.topK || 10,
2215
+ include_pending: includePending,
2216
+ profile
2217
+ });
2218
+ const serverHits = (response.results || []).map((row) => {
2219
+ const content = text(row.memory?.content);
2220
+ if (!content) return null;
2221
+ try {
2222
+ const parsed = JSON.parse(content);
2223
+ if (!isTupleLike(parsed)) return null;
2224
+ const tuple = this.normalizeTuple(parsed);
2225
+ const ns = tuple.config.configurable.checkpoint_ns || "default";
2226
+ if (tuple.config.configurable.thread_id !== params.threadId) return null;
2227
+ if (ns !== checkpointNs) return null;
2228
+ return { tuple, score: row.similarity || 0 };
2229
+ } catch {
2230
+ return null;
2231
+ }
2232
+ }).filter((value) => value !== null);
2233
+ const merged = /* @__PURE__ */ new Map();
2234
+ for (const hit of serverHits) {
2235
+ const cfg = hit.tuple.config.configurable;
2236
+ const key = this.makeLocalKey(cfg.thread_id, cfg.checkpoint_ns || "default", cfg.checkpoint_id || "");
2237
+ merged.set(key, hit);
2238
+ }
2239
+ const localKeys = this.localByThread.get(params.threadId);
2240
+ if (localKeys && includePending) {
2241
+ for (const key of localKeys) {
2242
+ const local = this.localByKey.get(key);
2243
+ if (!local) continue;
2244
+ const cfg = local.tuple.config.configurable;
2245
+ if ((cfg.checkpoint_ns || "default") !== checkpointNs) continue;
2246
+ if (!merged.has(key)) {
2247
+ merged.set(key, { tuple: local.tuple, score: 0 });
2248
+ }
2249
+ }
2250
+ }
2251
+ return Array.from(merged.values()).sort((a, b) => b.score - a.score).map((row) => row.tuple).slice(0, params.topK || 10);
2252
+ }
2253
+ };
2254
+ function createLangGraphCheckpointAdapter(client, options = {}) {
2255
+ return new LangGraphCheckpointAdapter(client, options);
2256
+ }
2257
+
376
2258
  // ../src/sdk/graph-utils.ts
377
2259
  function sanitizeId(id) {
378
2260
  return `n_${id.replace(/[^a-zA-Z0-9_]/g, "_")}`;
379
2261
  }
380
2262
  function shortLabel(input, max = 48) {
381
- const text = (input || "").replace(/\s+/g, " ").trim();
382
- if (text.length <= max) return text;
383
- return `${text.slice(0, max - 3)}...`;
2263
+ const text2 = (input || "").replace(/\s+/g, " ").trim();
2264
+ if (text2.length <= max) return text2;
2265
+ return `${text2.slice(0, max - 3)}...`;
384
2266
  }
385
2267
  function memoryGraphToMermaid(graph) {
386
2268
  const lines = ["flowchart LR"];
@@ -418,24 +2300,25 @@ var DEFAULT_BASE_DELAY_MS = 250;
418
2300
  var DEFAULT_MAX_DELAY_MS = 2e3;
419
2301
  var DEFAULT_TIMEOUT_MS = 15e3;
420
2302
  var PROJECT_CACHE_TTL_MS = 3e4;
421
- function sleep(ms) {
422
- return new Promise((resolve) => setTimeout(resolve, ms));
423
- }
424
- function getBackoffDelay(attempt, base, max) {
425
- const jitter = 0.8 + Math.random() * 0.4;
426
- return Math.min(max, Math.floor(base * Math.pow(2, attempt) * jitter));
2303
+ var DEPRECATION_WARNINGS2 = /* @__PURE__ */ new Set();
2304
+ function warnDeprecatedOnce2(key, message) {
2305
+ if (DEPRECATION_WARNINGS2.has(key)) return;
2306
+ DEPRECATION_WARNINGS2.add(key);
2307
+ if (typeof console !== "undefined" && typeof console.warn === "function") {
2308
+ console.warn(message);
2309
+ }
427
2310
  }
428
2311
  function isLikelyProjectId(projectRef) {
429
2312
  return /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(projectRef);
430
2313
  }
431
- function normalizeBaseUrl(url) {
2314
+ function normalizeBaseUrl2(url) {
432
2315
  let normalized = url.trim().replace(/\/+$/, "");
433
2316
  normalized = normalized.replace(/\/api\/v1$/i, "");
434
2317
  normalized = normalized.replace(/\/v1$/i, "");
435
2318
  normalized = normalized.replace(/\/api$/i, "");
436
2319
  return normalized;
437
2320
  }
438
- function normalizeEndpoint(endpoint) {
2321
+ function normalizeEndpoint2(endpoint) {
439
2322
  const withLeadingSlash = endpoint.startsWith("/") ? endpoint : `/${endpoint}`;
440
2323
  if (/^\/api\/v1(\/|$)/i.test(withLeadingSlash)) {
441
2324
  return withLeadingSlash.replace(/^\/api/i, "");
@@ -452,6 +2335,7 @@ var WhisperContext = class _WhisperContext {
452
2335
  defaultProject;
453
2336
  timeoutMs;
454
2337
  retryConfig;
2338
+ runtimeClient;
455
2339
  projectRefToId = /* @__PURE__ */ new Map();
456
2340
  projectCache = [];
457
2341
  projectCacheExpiresAt = 0;
@@ -463,7 +2347,7 @@ var WhisperContext = class _WhisperContext {
463
2347
  });
464
2348
  }
465
2349
  this.apiKey = config.apiKey;
466
- this.baseUrl = normalizeBaseUrl(config.baseUrl || "https://context.usewhisper.dev");
2350
+ this.baseUrl = normalizeBaseUrl2(config.baseUrl || "https://context.usewhisper.dev");
467
2351
  this.defaultProject = config.project;
468
2352
  this.timeoutMs = config.timeoutMs ?? DEFAULT_TIMEOUT_MS;
469
2353
  this.retryConfig = {
@@ -471,6 +2355,35 @@ var WhisperContext = class _WhisperContext {
471
2355
  baseDelayMs: config.retry?.baseDelayMs ?? DEFAULT_BASE_DELAY_MS,
472
2356
  maxDelayMs: config.retry?.maxDelayMs ?? DEFAULT_MAX_DELAY_MS
473
2357
  };
2358
+ this.runtimeClient = new RuntimeClient({
2359
+ apiKey: this.apiKey,
2360
+ baseUrl: this.baseUrl,
2361
+ compatMode: "fallback",
2362
+ timeouts: {
2363
+ searchMs: this.timeoutMs,
2364
+ writeAckMs: this.timeoutMs,
2365
+ bulkMs: Math.max(this.timeoutMs, 1e4),
2366
+ profileMs: this.timeoutMs,
2367
+ sessionMs: this.timeoutMs
2368
+ },
2369
+ retryPolicy: {
2370
+ baseBackoffMs: this.retryConfig.baseDelayMs,
2371
+ maxBackoffMs: this.retryConfig.maxDelayMs,
2372
+ maxAttemptsByOperation: {
2373
+ search: this.retryConfig.maxAttempts,
2374
+ writeAck: this.retryConfig.maxAttempts,
2375
+ bulk: this.retryConfig.maxAttempts,
2376
+ profile: this.retryConfig.maxAttempts,
2377
+ session: this.retryConfig.maxAttempts,
2378
+ query: this.retryConfig.maxAttempts,
2379
+ get: this.retryConfig.maxAttempts
2380
+ }
2381
+ }
2382
+ });
2383
+ warnDeprecatedOnce2(
2384
+ "whisper_context_class",
2385
+ "[Whisper SDK] WhisperContext is deprecated in v3 and scheduled for removal in v4. Prefer WhisperClient for runtime features and future contract compatibility."
2386
+ );
474
2387
  }
475
2388
  withProject(project) {
476
2389
  return new _WhisperContext({
@@ -609,76 +2522,58 @@ var WhisperContext = class _WhisperContext {
609
2522
  const message = (error.message || "").toLowerCase();
610
2523
  return !isProjectNotFoundMessage(message);
611
2524
  }
2525
+ inferOperation(endpoint, method) {
2526
+ const normalized = normalizeEndpoint2(endpoint).toLowerCase();
2527
+ if (normalized.includes("/memory/search")) return "search";
2528
+ if (normalized.includes("/memory/bulk")) return "bulk";
2529
+ if (normalized.includes("/memory/profile") || normalized.includes("/memory/session")) return "profile";
2530
+ if (normalized.includes("/memory/ingest/session")) return "session";
2531
+ if (normalized.includes("/context/query")) return "query";
2532
+ if (method === "GET") return "get";
2533
+ return "writeAck";
2534
+ }
612
2535
  async request(endpoint, options = {}) {
613
- const maxAttempts = Math.max(1, this.retryConfig.maxAttempts);
614
- const normalizedEndpoint = normalizeEndpoint(endpoint);
615
- let lastError;
616
- for (let attempt = 0; attempt < maxAttempts; attempt++) {
617
- const controller = new AbortController();
618
- const timeout = setTimeout(() => controller.abort(), this.timeoutMs);
2536
+ const method = String(options.method || "GET").toUpperCase();
2537
+ const normalizedEndpoint = normalizeEndpoint2(endpoint);
2538
+ const operation = this.inferOperation(normalizedEndpoint, method);
2539
+ let body;
2540
+ if (typeof options.body === "string") {
619
2541
  try {
620
- const headers = {
621
- "Content-Type": "application/json",
622
- ...options.headers
623
- };
624
- const hasAuthHeader = Object.keys(headers).some((k) => k.toLowerCase() === "authorization");
625
- const hasApiKeyHeader = Object.keys(headers).some((k) => k.toLowerCase() === "x-api-key");
626
- if (!hasAuthHeader) {
627
- headers.Authorization = `Bearer ${this.apiKey}`;
628
- }
629
- if (!hasApiKeyHeader) {
630
- headers["X-API-Key"] = this.apiKey;
631
- }
632
- const response = await fetch(`${this.baseUrl}${normalizedEndpoint}`, {
633
- ...options,
634
- signal: controller.signal,
635
- headers
636
- });
637
- clearTimeout(timeout);
638
- if (!response.ok) {
639
- let payload = null;
640
- try {
641
- payload = await response.json();
642
- } catch {
643
- payload = await response.text().catch(() => "");
644
- }
645
- let message = typeof payload === "string" ? payload : payload?.error || payload?.message || `HTTP ${response.status}: ${response.statusText}`;
646
- if (response.status === 404 && !isProjectNotFoundMessage(message)) {
647
- const endpointHint = `${this.baseUrl}${normalizedEndpoint}`;
648
- message = `Endpoint not found at ${endpointHint}. This deployment may not support this API route.`;
649
- }
650
- const { code, retryable } = this.classifyError(response.status, message);
651
- const err = new WhisperError({
652
- code,
653
- message,
654
- status: response.status,
655
- retryable,
656
- details: payload
657
- });
658
- if (!retryable || attempt === maxAttempts - 1) {
659
- throw err;
660
- }
661
- await sleep(getBackoffDelay(attempt, this.retryConfig.baseDelayMs, this.retryConfig.maxDelayMs));
662
- continue;
663
- }
664
- return response.json();
665
- } catch (error) {
666
- clearTimeout(timeout);
667
- const isAbort = error?.name === "AbortError";
668
- const mapped = error instanceof WhisperError ? error : new WhisperError({
669
- code: isAbort ? "TIMEOUT" : "NETWORK_ERROR",
670
- message: isAbort ? "Request timed out" : error?.message || "Network request failed",
671
- retryable: true,
672
- details: error
673
- });
674
- lastError = mapped;
675
- if (!mapped.retryable || attempt === maxAttempts - 1) {
676
- throw mapped;
677
- }
678
- await sleep(getBackoffDelay(attempt, this.retryConfig.baseDelayMs, this.retryConfig.maxDelayMs));
2542
+ body = JSON.parse(options.body);
2543
+ } catch {
2544
+ body = void 0;
2545
+ }
2546
+ } else if (options.body && typeof options.body === "object" && !ArrayBuffer.isView(options.body) && !(options.body instanceof ArrayBuffer) && !(options.body instanceof FormData) && !(options.body instanceof URLSearchParams) && !(options.body instanceof Blob) && !(options.body instanceof ReadableStream)) {
2547
+ body = options.body;
2548
+ }
2549
+ try {
2550
+ const response = await this.runtimeClient.request({
2551
+ endpoint: normalizedEndpoint,
2552
+ method,
2553
+ operation,
2554
+ idempotent: method === "GET" || method === "POST" && (operation === "search" || operation === "query" || operation === "profile"),
2555
+ body,
2556
+ headers: options.headers || {}
2557
+ });
2558
+ return response.data;
2559
+ } catch (error) {
2560
+ if (!(error instanceof RuntimeClientError)) {
2561
+ throw error;
679
2562
  }
2563
+ let message = error.message;
2564
+ if (error.status === 404 && !isProjectNotFoundMessage(message)) {
2565
+ const endpointHint = `${this.baseUrl}${normalizedEndpoint}`;
2566
+ message = `Endpoint not found at ${endpointHint}. This deployment may not support this API route.`;
2567
+ }
2568
+ const { code, retryable } = this.classifyError(error.status, message);
2569
+ throw new WhisperError({
2570
+ code,
2571
+ message,
2572
+ status: error.status,
2573
+ retryable,
2574
+ details: error.details
2575
+ });
680
2576
  }
681
- throw lastError instanceof Error ? lastError : new WhisperError({ code: "REQUEST_FAILED", message: "Request failed" });
682
2577
  }
683
2578
  async query(params) {
684
2579
  const projectRef = this.getRequiredProject(params.project);
@@ -731,6 +2626,69 @@ var WhisperContext = class _WhisperContext {
731
2626
  async syncSource(sourceId) {
732
2627
  return this.request(`/v1/sources/${sourceId}/sync`, { method: "POST" });
733
2628
  }
2629
+ async addSourceByType(projectId, params) {
2630
+ const resolvedProjectId = await this.resolveProjectId(projectId);
2631
+ return this.request(`/v1/projects/${resolvedProjectId}/add_source`, {
2632
+ method: "POST",
2633
+ body: JSON.stringify(params)
2634
+ });
2635
+ }
2636
+ async getSourceStatus(sourceId) {
2637
+ return this.request(`/v1/sources/${sourceId}/status`, { method: "GET" });
2638
+ }
2639
+ async createCanonicalSource(project, params) {
2640
+ const connector_type = params.type === "github" ? "github" : params.type === "web" ? "website" : params.type === "pdf" ? "pdf" : params.type === "local" ? "local-folder" : "slack";
2641
+ const config = {};
2642
+ if (params.type === "github") {
2643
+ if (!params.owner || !params.repo) throw new WhisperError({ code: "REQUEST_FAILED", message: "github source requires owner and repo" });
2644
+ config.owner = params.owner;
2645
+ config.repo = params.repo;
2646
+ if (params.branch) config.branch = params.branch;
2647
+ if (params.paths) config.paths = params.paths;
2648
+ } else if (params.type === "web") {
2649
+ if (!params.url) throw new WhisperError({ code: "REQUEST_FAILED", message: "web source requires url" });
2650
+ config.url = params.url;
2651
+ if (params.crawl_depth !== void 0) config.crawl_depth = params.crawl_depth;
2652
+ if (params.include_paths) config.include_paths = params.include_paths;
2653
+ if (params.exclude_paths) config.exclude_paths = params.exclude_paths;
2654
+ } else if (params.type === "pdf") {
2655
+ if (!params.url && !params.file_path) throw new WhisperError({ code: "REQUEST_FAILED", message: "pdf source requires url or file_path" });
2656
+ if (params.url) config.url = params.url;
2657
+ if (params.file_path) config.file_path = params.file_path;
2658
+ } else if (params.type === "local") {
2659
+ if (!params.path) throw new WhisperError({ code: "REQUEST_FAILED", message: "local source requires path" });
2660
+ config.path = params.path;
2661
+ if (params.glob) config.glob = params.glob;
2662
+ if (params.max_files !== void 0) config.max_files = params.max_files;
2663
+ } else {
2664
+ config.channel_ids = params.channel_ids || [];
2665
+ if (params.since) config.since = params.since;
2666
+ if (params.workspace_id) config.workspace_id = params.workspace_id;
2667
+ if (params.token) config.token = params.token;
2668
+ if (params.auth_ref) config.auth_ref = params.auth_ref;
2669
+ }
2670
+ if (params.metadata) config.metadata = params.metadata;
2671
+ config.auto_index = params.auto_index ?? true;
2672
+ const created = await this.addSource(project, {
2673
+ name: params.name || `${params.type}-source-${Date.now()}`,
2674
+ connector_type,
2675
+ config
2676
+ });
2677
+ let status = "queued";
2678
+ let jobId = null;
2679
+ if (params.auto_index ?? true) {
2680
+ const syncRes = await this.syncSource(created.id);
2681
+ status = "indexing";
2682
+ jobId = String(syncRes?.id || syncRes?.job_id || "");
2683
+ }
2684
+ return {
2685
+ source_id: created.id,
2686
+ status,
2687
+ job_id: jobId,
2688
+ index_started: params.auto_index ?? true,
2689
+ warnings: []
2690
+ };
2691
+ }
734
2692
  async ingest(projectId, documents) {
735
2693
  const resolvedProjectId = await this.resolveProjectId(projectId);
736
2694
  return this.request(`/v1/projects/${resolvedProjectId}/ingest`, {
@@ -751,7 +2709,7 @@ var WhisperContext = class _WhisperContext {
751
2709
  async addMemory(params) {
752
2710
  const projectRef = this.getRequiredProject(params.project);
753
2711
  return this.withProjectRefFallback(projectRef, async (project) => {
754
- const toSotaType = (memoryType) => {
2712
+ const toSotaType2 = (memoryType) => {
755
2713
  switch (memoryType) {
756
2714
  case "episodic":
757
2715
  return "event";
@@ -763,7 +2721,7 @@ var WhisperContext = class _WhisperContext {
763
2721
  return memoryType;
764
2722
  }
765
2723
  };
766
- const toLegacyType = (memoryType) => {
2724
+ const toLegacyType2 = (memoryType) => {
767
2725
  switch (memoryType) {
768
2726
  case "event":
769
2727
  return "episodic";
@@ -784,7 +2742,7 @@ var WhisperContext = class _WhisperContext {
784
2742
  body: JSON.stringify({
785
2743
  project,
786
2744
  content: params.content,
787
- memory_type: toSotaType(params.memory_type),
2745
+ memory_type: toSotaType2(params.memory_type),
788
2746
  user_id: params.user_id,
789
2747
  session_id: params.session_id,
790
2748
  agent_id: params.agent_id,
@@ -811,7 +2769,7 @@ var WhisperContext = class _WhisperContext {
811
2769
  body: JSON.stringify({
812
2770
  project,
813
2771
  content: params.content,
814
- memory_type: toLegacyType(params.memory_type),
2772
+ memory_type: toLegacyType2(params.memory_type),
815
2773
  user_id: params.user_id,
816
2774
  session_id: params.session_id,
817
2775
  agent_id: params.agent_id,
@@ -1026,6 +2984,16 @@ var WhisperContext = class _WhisperContext {
1026
2984
  }
1027
2985
  });
1028
2986
  }
2987
+ async getMemory(memoryId) {
2988
+ try {
2989
+ return await this.request(`/v1/memory/${memoryId}`);
2990
+ } catch (error) {
2991
+ if (!this.isEndpointNotFoundError(error)) {
2992
+ throw error;
2993
+ }
2994
+ return this.request(`/v1/memories/${memoryId}`);
2995
+ }
2996
+ }
1029
2997
  async getMemoryVersions(memoryId) {
1030
2998
  return this.request(`/v1/memory/${memoryId}/versions`);
1031
2999
  }
@@ -1208,8 +3176,11 @@ var WhisperContext = class _WhisperContext {
1208
3176
  };
1209
3177
  sources = {
1210
3178
  add: (projectId, params) => this.addSource(projectId, params),
3179
+ addSource: (projectId, params) => this.addSourceByType(projectId, params),
1211
3180
  sync: (sourceId) => this.syncSource(sourceId),
1212
- syncSource: (sourceId) => this.syncSource(sourceId)
3181
+ syncSource: (sourceId) => this.syncSource(sourceId),
3182
+ status: (sourceId) => this.getSourceStatus(sourceId),
3183
+ getStatus: (sourceId) => this.getSourceStatus(sourceId)
1213
3184
  };
1214
3185
  memory = {
1215
3186
  add: (params) => this.addMemory(params),
@@ -1221,6 +3192,7 @@ var WhisperContext = class _WhisperContext {
1221
3192
  ingestSession: (params) => this.ingestSession(params),
1222
3193
  getSessionMemories: (params) => this.getSessionMemories(params),
1223
3194
  getUserProfile: (params) => this.getUserProfile(params),
3195
+ get: (memoryId) => this.getMemory(memoryId),
1224
3196
  getVersions: (memoryId) => this.getMemoryVersions(memoryId),
1225
3197
  update: (memoryId, params) => this.updateMemory(memoryId, params),
1226
3198
  delete: (memoryId) => this.deleteMemory(memoryId),
@@ -1256,11 +3228,17 @@ var WhisperContext = class _WhisperContext {
1256
3228
  var index_default = WhisperContext;
1257
3229
  // Annotate the CommonJS export names for ESM import in node:
1258
3230
  0 && (module.exports = {
3231
+ LangChainMemoryAdapter,
3232
+ LangGraphCheckpointAdapter,
1259
3233
  Whisper,
1260
3234
  WhisperAgentMiddleware,
3235
+ WhisperClient,
1261
3236
  WhisperContext,
1262
3237
  WhisperDefault,
1263
3238
  WhisperError,
3239
+ WhisperRuntimeClient,
1264
3240
  createAgentMiddleware,
3241
+ createLangChainMemoryAdapter,
3242
+ createLangGraphCheckpointAdapter,
1265
3243
  memoryGraphToMermaid
1266
3244
  });