@usewhisper/sdk 2.2.0 → 3.0.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 (5) hide show
  1. package/index.d.mts +735 -11
  2. package/index.d.ts +735 -11
  3. package/index.js +2181 -121
  4. package/index.mjs +2165 -121
  5. package/package.json +1 -1
package/index.mjs CHANGED
@@ -1,4 +1,377 @@
1
+ // ../src/sdk/core/telemetry.ts
2
+ var DiagnosticsStore = class {
3
+ maxEntries;
4
+ records = [];
5
+ subscribers = /* @__PURE__ */ new Set();
6
+ constructor(maxEntries = 1e3) {
7
+ this.maxEntries = Math.max(1, maxEntries);
8
+ }
9
+ add(record) {
10
+ this.records.push(record);
11
+ if (this.records.length > this.maxEntries) {
12
+ this.records.splice(0, this.records.length - this.maxEntries);
13
+ }
14
+ for (const fn of this.subscribers) {
15
+ try {
16
+ fn(record);
17
+ } catch {
18
+ }
19
+ }
20
+ }
21
+ getLast(limit = 25) {
22
+ const count = Math.max(1, limit);
23
+ return this.records.slice(-count);
24
+ }
25
+ snapshot() {
26
+ const total = this.records.length;
27
+ const success = this.records.filter((r) => r.success).length;
28
+ const failure = total - success;
29
+ const duration = this.records.reduce((acc, item) => acc + item.durationMs, 0);
30
+ return {
31
+ total,
32
+ success,
33
+ failure,
34
+ avgDurationMs: total > 0 ? duration / total : 0,
35
+ lastTraceId: this.records[this.records.length - 1]?.traceId
36
+ };
37
+ }
38
+ subscribe(fn) {
39
+ this.subscribers.add(fn);
40
+ return () => {
41
+ this.subscribers.delete(fn);
42
+ };
43
+ }
44
+ };
45
+
46
+ // ../src/sdk/core/utils.ts
47
+ function normalizeBaseUrl(url) {
48
+ let normalized = url.trim().replace(/\/+$/, "");
49
+ normalized = normalized.replace(/\/api\/v1$/i, "");
50
+ normalized = normalized.replace(/\/v1$/i, "");
51
+ normalized = normalized.replace(/\/api$/i, "");
52
+ return normalized;
53
+ }
54
+ function normalizeEndpoint(endpoint) {
55
+ const withLeadingSlash = endpoint.startsWith("/") ? endpoint : `/${endpoint}`;
56
+ if (/^\/api\/v1(\/|$)/i.test(withLeadingSlash)) {
57
+ return withLeadingSlash.replace(/^\/api/i, "");
58
+ }
59
+ return withLeadingSlash;
60
+ }
61
+ function nowIso() {
62
+ return (/* @__PURE__ */ new Date()).toISOString();
63
+ }
64
+ function stableHash(input) {
65
+ let hash = 2166136261;
66
+ for (let i = 0; i < input.length; i += 1) {
67
+ hash ^= input.charCodeAt(i);
68
+ hash = Math.imul(hash, 16777619);
69
+ }
70
+ return (hash >>> 0).toString(16).padStart(8, "0");
71
+ }
72
+ function normalizeQuery(query) {
73
+ return query.trim().toLowerCase().replace(/\s+/g, " ");
74
+ }
75
+ function randomId(prefix = "id") {
76
+ return `${prefix}_${stableHash(`${Date.now()}_${Math.random()}`)}`;
77
+ }
78
+
79
+ // ../src/sdk/core/client.ts
80
+ var DEFAULT_TIMEOUTS = {
81
+ searchMs: 3e3,
82
+ writeAckMs: 2e3,
83
+ bulkMs: 1e4,
84
+ profileMs: 2500,
85
+ sessionMs: 2500
86
+ };
87
+ var DEFAULT_RETRYABLE_STATUS = [408, 429, 500, 502, 503, 504];
88
+ var DEFAULT_RETRY_ATTEMPTS = {
89
+ search: 3,
90
+ writeAck: 2,
91
+ bulk: 2,
92
+ profile: 2,
93
+ session: 2,
94
+ query: 3,
95
+ get: 2
96
+ };
97
+ function isObject(value) {
98
+ return typeof value === "object" && value !== null;
99
+ }
100
+ function toMessage(payload, status, statusText) {
101
+ if (typeof payload === "string" && payload.trim()) return payload;
102
+ if (isObject(payload)) {
103
+ const maybeError = payload.error;
104
+ const maybeMessage = payload.message;
105
+ if (typeof maybeError === "string" && maybeError.trim()) return maybeError;
106
+ if (typeof maybeMessage === "string" && maybeMessage.trim()) return maybeMessage;
107
+ if (isObject(maybeError) && typeof maybeError.message === "string") return maybeError.message;
108
+ }
109
+ return `HTTP ${status}: ${statusText}`;
110
+ }
111
+ var RuntimeClientError = class extends Error {
112
+ status;
113
+ retryable;
114
+ code;
115
+ details;
116
+ traceId;
117
+ constructor(args) {
118
+ super(args.message);
119
+ this.name = "RuntimeClientError";
120
+ this.status = args.status;
121
+ this.retryable = args.retryable;
122
+ this.code = args.code;
123
+ this.details = args.details;
124
+ this.traceId = args.traceId;
125
+ }
126
+ };
127
+ var RuntimeClient = class {
128
+ apiKey;
129
+ baseUrl;
130
+ sdkVersion;
131
+ compatMode;
132
+ retryPolicy;
133
+ timeouts;
134
+ diagnostics;
135
+ inFlight = /* @__PURE__ */ new Map();
136
+ constructor(options, diagnostics) {
137
+ if (!options.apiKey) {
138
+ throw new RuntimeClientError({
139
+ code: "INVALID_API_KEY",
140
+ message: "API key is required",
141
+ retryable: false
142
+ });
143
+ }
144
+ this.apiKey = options.apiKey;
145
+ this.baseUrl = normalizeBaseUrl(options.baseUrl || "https://context.usewhisper.dev");
146
+ this.sdkVersion = options.sdkVersion || "2.x-runtime";
147
+ this.compatMode = options.compatMode || "fallback";
148
+ this.retryPolicy = {
149
+ retryableStatusCodes: options.retryPolicy?.retryableStatusCodes || DEFAULT_RETRYABLE_STATUS,
150
+ retryOnNetworkError: options.retryPolicy?.retryOnNetworkError ?? true,
151
+ maxBackoffMs: options.retryPolicy?.maxBackoffMs ?? 1200,
152
+ baseBackoffMs: options.retryPolicy?.baseBackoffMs ?? 250,
153
+ maxAttemptsByOperation: options.retryPolicy?.maxAttemptsByOperation || {}
154
+ };
155
+ this.timeouts = {
156
+ ...DEFAULT_TIMEOUTS,
157
+ ...options.timeouts || {}
158
+ };
159
+ this.diagnostics = diagnostics || new DiagnosticsStore(1e3);
160
+ }
161
+ getDiagnosticsStore() {
162
+ return this.diagnostics;
163
+ }
164
+ getCompatMode() {
165
+ return this.compatMode;
166
+ }
167
+ timeoutFor(operation) {
168
+ switch (operation) {
169
+ case "search":
170
+ return this.timeouts.searchMs;
171
+ case "writeAck":
172
+ return this.timeouts.writeAckMs;
173
+ case "bulk":
174
+ return this.timeouts.bulkMs;
175
+ case "profile":
176
+ return this.timeouts.profileMs;
177
+ case "session":
178
+ return this.timeouts.sessionMs;
179
+ case "query":
180
+ case "get":
181
+ default:
182
+ return this.timeouts.searchMs;
183
+ }
184
+ }
185
+ maxAttemptsFor(operation) {
186
+ const override = this.retryPolicy.maxAttemptsByOperation?.[operation];
187
+ return Math.max(1, override ?? DEFAULT_RETRY_ATTEMPTS[operation]);
188
+ }
189
+ shouldRetryStatus(status) {
190
+ return status !== void 0 && this.retryPolicy.retryableStatusCodes?.includes(status) === true;
191
+ }
192
+ backoff(attempt) {
193
+ const base = this.retryPolicy.baseBackoffMs ?? 250;
194
+ const max = this.retryPolicy.maxBackoffMs ?? 1200;
195
+ const jitter = 0.8 + Math.random() * 0.4;
196
+ return Math.min(max, Math.floor(base * Math.pow(2, attempt) * jitter));
197
+ }
198
+ runtimeName() {
199
+ const maybeWindow = globalThis.window;
200
+ return maybeWindow && typeof maybeWindow === "object" ? "browser" : "node";
201
+ }
202
+ createRequestFingerprint(options) {
203
+ const normalizedEndpoint = normalizeEndpoint(options.endpoint);
204
+ const authFingerprint = stableHash(this.apiKey.replace(/^Bearer\s+/i, ""));
205
+ const payload = JSON.stringify({
206
+ method: options.method || "GET",
207
+ endpoint: normalizedEndpoint,
208
+ body: options.body || null,
209
+ extra: options.dedupeKeyExtra || "",
210
+ authFingerprint
211
+ });
212
+ return stableHash(payload);
213
+ }
214
+ async request(options) {
215
+ const dedupeKey = options.idempotent ? this.createRequestFingerprint(options) : null;
216
+ if (dedupeKey) {
217
+ const inFlight = this.inFlight.get(dedupeKey);
218
+ if (inFlight) {
219
+ const data = await inFlight;
220
+ this.diagnostics.add({
221
+ id: randomId("diag"),
222
+ startedAt: nowIso(),
223
+ endedAt: nowIso(),
224
+ traceId: data.traceId,
225
+ spanId: randomId("span"),
226
+ operation: options.operation,
227
+ method: options.method || "GET",
228
+ endpoint: normalizeEndpoint(options.endpoint),
229
+ status: data.status,
230
+ durationMs: 0,
231
+ success: true,
232
+ deduped: true
233
+ });
234
+ const cloned = {
235
+ data: data.data,
236
+ status: data.status,
237
+ traceId: data.traceId
238
+ };
239
+ return cloned;
240
+ }
241
+ }
242
+ const runner = this.performRequest(options).then((data) => {
243
+ if (dedupeKey) this.inFlight.delete(dedupeKey);
244
+ return data;
245
+ }).catch((error) => {
246
+ if (dedupeKey) this.inFlight.delete(dedupeKey);
247
+ throw error;
248
+ });
249
+ if (dedupeKey) {
250
+ this.inFlight.set(dedupeKey, runner);
251
+ }
252
+ return runner;
253
+ }
254
+ async performRequest(options) {
255
+ const method = options.method || "GET";
256
+ const normalizedEndpoint = normalizeEndpoint(options.endpoint);
257
+ const operation = options.operation;
258
+ const maxAttempts = this.maxAttemptsFor(operation);
259
+ const timeoutMs = this.timeoutFor(operation);
260
+ const traceId = options.traceId || randomId("trace");
261
+ let lastError = null;
262
+ for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
263
+ const spanId = randomId("span");
264
+ const startedAt = Date.now();
265
+ const controller = new AbortController();
266
+ const timeout = setTimeout(() => controller.abort(), timeoutMs);
267
+ try {
268
+ const response = await fetch(`${this.baseUrl}${normalizedEndpoint}`, {
269
+ method,
270
+ signal: controller.signal,
271
+ keepalive: method !== "GET",
272
+ headers: {
273
+ "Content-Type": "application/json",
274
+ Authorization: this.apiKey.startsWith("Bearer ") ? this.apiKey : `Bearer ${this.apiKey}`,
275
+ "X-API-Key": this.apiKey.replace(/^Bearer\s+/i, ""),
276
+ "x-trace-id": traceId,
277
+ "x-span-id": spanId,
278
+ "x-sdk-version": this.sdkVersion,
279
+ "x-sdk-runtime": this.runtimeName(),
280
+ ...options.headers || {}
281
+ },
282
+ body: method === "GET" || method === "DELETE" ? void 0 : JSON.stringify(options.body || {})
283
+ });
284
+ clearTimeout(timeout);
285
+ let payload = null;
286
+ try {
287
+ payload = await response.json();
288
+ } catch {
289
+ payload = await response.text().catch(() => "");
290
+ }
291
+ const durationMs = Date.now() - startedAt;
292
+ const record = {
293
+ id: randomId("diag"),
294
+ startedAt: new Date(startedAt).toISOString(),
295
+ endedAt: nowIso(),
296
+ traceId,
297
+ spanId,
298
+ operation,
299
+ method,
300
+ endpoint: normalizedEndpoint,
301
+ status: response.status,
302
+ durationMs,
303
+ success: response.ok
304
+ };
305
+ this.diagnostics.add(record);
306
+ if (response.ok) {
307
+ return {
308
+ data: payload,
309
+ status: response.status,
310
+ traceId
311
+ };
312
+ }
313
+ const message = toMessage(payload, response.status, response.statusText);
314
+ const retryable = this.shouldRetryStatus(response.status);
315
+ const error = new RuntimeClientError({
316
+ message,
317
+ status: response.status,
318
+ retryable,
319
+ code: response.status === 404 ? "NOT_FOUND" : "REQUEST_FAILED",
320
+ details: payload,
321
+ traceId
322
+ });
323
+ lastError = error;
324
+ if (!retryable || attempt === maxAttempts - 1) {
325
+ throw error;
326
+ }
327
+ } catch (error) {
328
+ clearTimeout(timeout);
329
+ const durationMs = Date.now() - startedAt;
330
+ const isAbort = isObject(error) && error.name === "AbortError";
331
+ const mapped = error instanceof RuntimeClientError ? error : new RuntimeClientError({
332
+ message: isAbort ? "Request timed out" : error instanceof Error ? error.message : "Network error",
333
+ retryable: this.retryPolicy.retryOnNetworkError ?? true,
334
+ code: isAbort ? "TIMEOUT" : "NETWORK_ERROR",
335
+ traceId
336
+ });
337
+ lastError = mapped;
338
+ this.diagnostics.add({
339
+ id: randomId("diag"),
340
+ startedAt: new Date(startedAt).toISOString(),
341
+ endedAt: nowIso(),
342
+ traceId,
343
+ spanId,
344
+ operation,
345
+ method,
346
+ endpoint: normalizedEndpoint,
347
+ durationMs,
348
+ success: false,
349
+ errorCode: mapped.code,
350
+ errorMessage: mapped.message
351
+ });
352
+ if (!mapped.retryable || attempt === maxAttempts - 1) {
353
+ throw mapped;
354
+ }
355
+ }
356
+ await new Promise((resolve) => setTimeout(resolve, this.backoff(attempt)));
357
+ }
358
+ throw lastError || new RuntimeClientError({
359
+ message: "Request failed",
360
+ retryable: false,
361
+ code: "REQUEST_FAILED"
362
+ });
363
+ }
364
+ };
365
+
1
366
  // ../src/sdk/whisper-agent.ts
367
+ var DEPRECATION_WARNINGS = /* @__PURE__ */ new Set();
368
+ function warnDeprecatedOnce(key, message) {
369
+ if (DEPRECATION_WARNINGS.has(key)) return;
370
+ DEPRECATION_WARNINGS.add(key);
371
+ if (typeof console !== "undefined" && typeof console.warn === "function") {
372
+ console.warn(message);
373
+ }
374
+ }
2
375
  var Whisper = class {
3
376
  client;
4
377
  options;
@@ -16,6 +389,10 @@ var Whisper = class {
16
389
  if (options.timeoutMs) clientConfig.timeoutMs = options.timeoutMs;
17
390
  if (options.retry) clientConfig.retry = options.retry;
18
391
  this.client = new WhisperContext(clientConfig);
392
+ warnDeprecatedOnce(
393
+ "whisper_agent_wrapper",
394
+ "[Whisper SDK] Whisper wrapper is supported for v2 compatibility. Prefer WhisperClient for new integrations."
395
+ );
19
396
  const finalRetry = options.retry || { maxAttempts: 3, baseDelayMs: 250, maxDelayMs: 2e3 };
20
397
  this.options = {
21
398
  apiKey: options.apiKey,
@@ -117,7 +494,7 @@ ${context}` : "",
117
494
  if (extractedMemories.length > 0) {
118
495
  const bulk = await this.client.addMemoriesBulk({
119
496
  project: options?.project ?? this.options.project,
120
- async: false,
497
+ write_mode: "async",
121
498
  memories: extractedMemories.map((m) => ({
122
499
  content: m.content,
123
500
  memory_type: m.memoryType,
@@ -185,6 +562,10 @@ ${context}` : "",
185
562
  extracted: result?.memories_created ?? 0
186
563
  };
187
564
  } catch (error) {
565
+ const fallback = await this.fallbackCaptureViaAddMemory(messages, options);
566
+ if (fallback.success) {
567
+ return fallback;
568
+ }
188
569
  console.error("[Whisper] Session capture failed:", error);
189
570
  return { success: false, extracted: 0 };
190
571
  }
@@ -237,13 +618,1092 @@ User: ${params.userMessage}` : params.userMessage;
237
618
  if (bulkResponse?.memory?.id) {
238
619
  ids.push(bulkResponse.memory.id);
239
620
  }
240
- if (bulkResponse?.id) {
241
- ids.push(bulkResponse.id);
621
+ if (bulkResponse?.id) {
622
+ ids.push(bulkResponse.id);
623
+ }
624
+ return Array.from(new Set(ids));
625
+ }
626
+ async fallbackCaptureViaAddMemory(messages, options) {
627
+ const userMessages = messages.filter((m) => m.role === "user").map((m) => (m.content || "").trim()).filter((content) => content.length >= 5).slice(-2);
628
+ if (userMessages.length === 0) {
629
+ return { success: false, extracted: 0 };
630
+ }
631
+ let extracted = 0;
632
+ for (const content of userMessages) {
633
+ try {
634
+ await this.client.addMemory({
635
+ project: options?.project ?? this.options.project,
636
+ content,
637
+ memory_type: "factual",
638
+ user_id: options?.userId ?? this.userId,
639
+ session_id: options?.sessionId ?? this.sessionId,
640
+ allow_legacy_fallback: true
641
+ });
642
+ extracted += 1;
643
+ } catch {
644
+ }
645
+ }
646
+ return { success: extracted > 0, extracted };
647
+ }
648
+ };
649
+ var whisper_agent_default = Whisper;
650
+
651
+ // ../src/sdk/core/cache.ts
652
+ var SearchResponseCache = class {
653
+ ttlMs;
654
+ capacity;
655
+ byKey = /* @__PURE__ */ new Map();
656
+ scopeIndex = /* @__PURE__ */ new Map();
657
+ constructor(ttlMs = 7e3, capacity = 500) {
658
+ this.ttlMs = Math.max(1e3, ttlMs);
659
+ this.capacity = Math.max(10, capacity);
660
+ }
661
+ makeScopeKey(project, userId, sessionId) {
662
+ return `${project}:${userId || "_"}:${sessionId || "_"}`;
663
+ }
664
+ makeKey(input) {
665
+ const normalized = {
666
+ project: input.project,
667
+ userId: input.userId || "",
668
+ sessionId: input.sessionId || "",
669
+ query: normalizeQuery(input.query),
670
+ topK: input.topK,
671
+ profile: input.profile,
672
+ includePending: input.includePending
673
+ };
674
+ return `search:${stableHash(JSON.stringify(normalized))}`;
675
+ }
676
+ get(key) {
677
+ const found = this.byKey.get(key);
678
+ if (!found) return null;
679
+ if (found.expiresAt <= Date.now()) {
680
+ this.deleteByKey(key);
681
+ return null;
682
+ }
683
+ found.touchedAt = Date.now();
684
+ return found.value;
685
+ }
686
+ set(key, scopeKey, value) {
687
+ this.byKey.set(key, {
688
+ value,
689
+ scopeKey,
690
+ touchedAt: Date.now(),
691
+ expiresAt: Date.now() + this.ttlMs
692
+ });
693
+ if (!this.scopeIndex.has(scopeKey)) {
694
+ this.scopeIndex.set(scopeKey, /* @__PURE__ */ new Set());
695
+ }
696
+ this.scopeIndex.get(scopeKey).add(key);
697
+ this.evictIfNeeded();
698
+ }
699
+ invalidateScope(scopeKey) {
700
+ const keys = this.scopeIndex.get(scopeKey);
701
+ if (!keys || keys.size === 0) {
702
+ return 0;
703
+ }
704
+ const toDelete = Array.from(keys);
705
+ for (const key of toDelete) {
706
+ this.deleteByKey(key);
707
+ }
708
+ this.scopeIndex.delete(scopeKey);
709
+ return toDelete.length;
710
+ }
711
+ evictIfNeeded() {
712
+ if (this.byKey.size <= this.capacity) return;
713
+ const ordered = Array.from(this.byKey.entries()).sort((a, b) => a[1].touchedAt - b[1].touchedAt);
714
+ const removeCount = this.byKey.size - this.capacity;
715
+ for (let i = 0; i < removeCount; i += 1) {
716
+ this.deleteByKey(ordered[i][0]);
717
+ }
718
+ }
719
+ deleteByKey(key) {
720
+ const found = this.byKey.get(key);
721
+ if (!found) return;
722
+ this.byKey.delete(key);
723
+ const scopeKeys = this.scopeIndex.get(found.scopeKey);
724
+ if (!scopeKeys) return;
725
+ scopeKeys.delete(key);
726
+ if (scopeKeys.size === 0) {
727
+ this.scopeIndex.delete(found.scopeKey);
728
+ }
729
+ }
730
+ };
731
+
732
+ // ../src/sdk/core/queue.ts
733
+ var InMemoryQueueStore = class {
734
+ items = [];
735
+ async load() {
736
+ return [...this.items];
737
+ }
738
+ async save(items) {
739
+ this.items = [...items];
740
+ }
741
+ };
742
+ var WriteQueue = class {
743
+ flushHandler;
744
+ store;
745
+ maxBatchSize;
746
+ flushIntervalMs;
747
+ maxAttempts;
748
+ queue = [];
749
+ flushTimer = null;
750
+ flushing = false;
751
+ lastFlushAt;
752
+ lastFlushCount = 0;
753
+ constructor(args) {
754
+ this.flushHandler = args.flushHandler;
755
+ this.store = args.store || new InMemoryQueueStore();
756
+ this.maxBatchSize = Math.max(1, args.maxBatchSize ?? 50);
757
+ this.flushIntervalMs = Math.max(10, args.flushIntervalMs ?? 100);
758
+ this.maxAttempts = Math.max(1, args.maxAttempts ?? 2);
759
+ }
760
+ async start() {
761
+ const pending = await this.store.load();
762
+ if (pending.length > 0) {
763
+ this.queue.push(...pending);
764
+ }
765
+ if (!this.flushTimer) {
766
+ this.flushTimer = setInterval(() => {
767
+ void this.flush();
768
+ }, this.flushIntervalMs);
769
+ const timer = this.flushTimer;
770
+ if (typeof timer.unref === "function") {
771
+ timer.unref();
772
+ }
773
+ }
774
+ this.bindProcessHooks();
775
+ }
776
+ async stop() {
777
+ if (this.flushTimer) {
778
+ clearInterval(this.flushTimer);
779
+ this.flushTimer = null;
780
+ }
781
+ await this.flush();
782
+ }
783
+ status() {
784
+ return {
785
+ queued: this.queue.length,
786
+ flushing: this.flushing,
787
+ lastFlushAt: this.lastFlushAt,
788
+ lastFlushCount: this.lastFlushCount
789
+ };
790
+ }
791
+ async enqueue(input) {
792
+ const eventId = input.eventId || this.makeEventId(input);
793
+ const item = {
794
+ ...input,
795
+ eventId,
796
+ createdAt: nowIso()
797
+ };
798
+ this.queue.push(item);
799
+ await this.store.save(this.queue);
800
+ if (this.queue.length >= this.maxBatchSize) {
801
+ void this.flush();
802
+ }
803
+ return item;
804
+ }
805
+ async flush() {
806
+ if (this.flushing || this.queue.length === 0) return;
807
+ this.flushing = true;
808
+ try {
809
+ while (this.queue.length > 0) {
810
+ const batch = this.queue.slice(0, this.maxBatchSize);
811
+ let done = false;
812
+ let error = null;
813
+ for (let attempt = 0; attempt < this.maxAttempts; attempt += 1) {
814
+ try {
815
+ await this.flushHandler(batch);
816
+ done = true;
817
+ break;
818
+ } catch (err) {
819
+ error = err;
820
+ await new Promise((resolve) => setTimeout(resolve, (attempt + 1) * 180));
821
+ }
822
+ }
823
+ if (!done) {
824
+ throw error instanceof Error ? error : new Error("Queue flush failed");
825
+ }
826
+ this.queue.splice(0, batch.length);
827
+ this.lastFlushAt = nowIso();
828
+ this.lastFlushCount = batch.length;
829
+ await this.store.save(this.queue);
830
+ }
831
+ } finally {
832
+ this.flushing = false;
833
+ }
834
+ }
835
+ makeEventId(input) {
836
+ const source = JSON.stringify({
837
+ project: input.project,
838
+ userId: input.userId || "",
839
+ sessionId: input.sessionId || "",
840
+ payload: input.payload
841
+ });
842
+ return `evt_${stableHash(source)}`;
843
+ }
844
+ bindProcessHooks() {
845
+ if (typeof process === "undefined") return;
846
+ const proc = process;
847
+ const flushOnExit = () => {
848
+ void this.flush();
849
+ };
850
+ proc.once("beforeExit", flushOnExit);
851
+ proc.once("SIGINT", flushOnExit);
852
+ proc.once("SIGTERM", flushOnExit);
853
+ }
854
+ };
855
+ function createStorageQueueStore(key = "whisper_sdk_queue") {
856
+ const getStorage = () => {
857
+ const maybeStorage = globalThis.localStorage;
858
+ if (!maybeStorage || typeof maybeStorage !== "object") return null;
859
+ const candidate = maybeStorage;
860
+ if (typeof candidate.getItem !== "function" || typeof candidate.setItem !== "function") {
861
+ return null;
862
+ }
863
+ return {
864
+ getItem: candidate.getItem,
865
+ setItem: candidate.setItem
866
+ };
867
+ };
868
+ return {
869
+ async load() {
870
+ const storage = getStorage();
871
+ if (!storage) return [];
872
+ const raw = storage.getItem(key);
873
+ if (!raw) return [];
874
+ try {
875
+ const parsed = JSON.parse(raw);
876
+ return Array.isArray(parsed) ? parsed : [];
877
+ } catch {
878
+ return [];
879
+ }
880
+ },
881
+ async save(items) {
882
+ const storage = getStorage();
883
+ if (!storage) return;
884
+ storage.setItem(key, JSON.stringify(items));
885
+ }
886
+ };
887
+ }
888
+ function createFileQueueStore(filePath) {
889
+ return {
890
+ async load() {
891
+ if (typeof process === "undefined") return [];
892
+ const fs = await import("fs/promises");
893
+ try {
894
+ const raw = await fs.readFile(filePath, "utf8");
895
+ const parsed = JSON.parse(raw);
896
+ return Array.isArray(parsed) ? parsed : [];
897
+ } catch (error) {
898
+ const nodeError = error;
899
+ if (nodeError?.code === "ENOENT") {
900
+ return [];
901
+ }
902
+ return [];
903
+ }
904
+ },
905
+ async save(items) {
906
+ if (typeof process === "undefined") return;
907
+ const fs = await import("fs/promises");
908
+ const path = await import("path");
909
+ const dir = path.dirname(filePath);
910
+ await fs.mkdir(dir, { recursive: true });
911
+ await fs.writeFile(filePath, JSON.stringify(items), "utf8");
912
+ }
913
+ };
914
+ }
915
+
916
+ // ../src/sdk/modules/memory.ts
917
+ function isEndpointNotFound(error) {
918
+ return error instanceof RuntimeClientError && error.status === 404;
919
+ }
920
+ function toSotaType(memoryType) {
921
+ if (!memoryType) return void 0;
922
+ switch (memoryType) {
923
+ case "episodic":
924
+ return "event";
925
+ case "semantic":
926
+ return "factual";
927
+ case "procedural":
928
+ return "instruction";
929
+ default:
930
+ return memoryType;
931
+ }
932
+ }
933
+ function toLegacyType(memoryType) {
934
+ if (!memoryType) return void 0;
935
+ switch (memoryType) {
936
+ case "event":
937
+ return "episodic";
938
+ case "instruction":
939
+ return "procedural";
940
+ case "preference":
941
+ case "relationship":
942
+ case "opinion":
943
+ case "goal":
944
+ return "semantic";
945
+ default:
946
+ return memoryType;
947
+ }
948
+ }
949
+ var MemoryModule = class {
950
+ constructor(client, cache, queue, options = {}) {
951
+ this.client = client;
952
+ this.cache = cache;
953
+ this.queue = queue;
954
+ this.options = options;
955
+ }
956
+ resolveProject(project) {
957
+ const value = project || this.options.defaultProject;
958
+ if (!value) {
959
+ throw new RuntimeClientError({
960
+ code: "MISSING_PROJECT",
961
+ message: "Project is required",
962
+ retryable: false
963
+ });
964
+ }
965
+ return value;
966
+ }
967
+ invalidate(project, userId, sessionId) {
968
+ if (this.options.cacheEnabled === false) {
969
+ return;
970
+ }
971
+ const scope = this.cache.makeScopeKey(project, userId, sessionId);
972
+ this.cache.invalidateScope(scope);
973
+ }
974
+ async add(params) {
975
+ const project = this.resolveProject(params.project);
976
+ const queueEnabled = this.options.queueEnabled !== false;
977
+ const useQueue = queueEnabled && params.write_mode !== "sync" && params.async !== false;
978
+ if (useQueue) {
979
+ const queued = await this.queue.enqueue({
980
+ project,
981
+ userId: params.user_id,
982
+ sessionId: params.session_id,
983
+ payload: {
984
+ content: params.content,
985
+ memory_type: toSotaType(params.memory_type),
986
+ user_id: params.user_id,
987
+ session_id: params.session_id,
988
+ agent_id: params.agent_id,
989
+ importance: params.importance,
990
+ confidence: params.confidence,
991
+ metadata: params.metadata,
992
+ document_date: params.document_date,
993
+ event_date: params.event_date
994
+ }
995
+ });
996
+ this.invalidate(project, params.user_id, params.session_id);
997
+ return {
998
+ success: true,
999
+ mode: "async",
1000
+ queued: true,
1001
+ event_id: queued.eventId,
1002
+ accepted_at: queued.createdAt
1003
+ };
1004
+ }
1005
+ try {
1006
+ const response = await this.client.request({
1007
+ endpoint: "/v1/memory",
1008
+ method: "POST",
1009
+ operation: "writeAck",
1010
+ body: {
1011
+ project,
1012
+ content: params.content,
1013
+ memory_type: toSotaType(params.memory_type),
1014
+ user_id: params.user_id,
1015
+ session_id: params.session_id,
1016
+ agent_id: params.agent_id,
1017
+ importance: params.importance,
1018
+ confidence: params.confidence,
1019
+ metadata: params.metadata,
1020
+ document_date: params.document_date,
1021
+ event_date: params.event_date,
1022
+ write_mode: "sync"
1023
+ }
1024
+ });
1025
+ this.invalidate(project, params.user_id, params.session_id);
1026
+ return {
1027
+ success: true,
1028
+ mode: "sync",
1029
+ trace_id: response.traceId
1030
+ };
1031
+ } catch (error) {
1032
+ if (this.client.getCompatMode() !== "fallback" || !isEndpointNotFound(error)) {
1033
+ throw error;
1034
+ }
1035
+ await this.client.request({
1036
+ endpoint: "/v1/memories",
1037
+ method: "POST",
1038
+ operation: "writeAck",
1039
+ body: {
1040
+ project,
1041
+ content: params.content,
1042
+ memory_type: toLegacyType(params.memory_type),
1043
+ user_id: params.user_id,
1044
+ session_id: params.session_id,
1045
+ agent_id: params.agent_id,
1046
+ importance: params.importance,
1047
+ metadata: params.metadata
1048
+ }
1049
+ });
1050
+ this.invalidate(project, params.user_id, params.session_id);
1051
+ return {
1052
+ success: true,
1053
+ mode: "sync"
1054
+ };
1055
+ }
1056
+ }
1057
+ async addBulk(params) {
1058
+ const project = this.resolveProject(params.project);
1059
+ if (!Array.isArray(params.memories) || params.memories.length === 0) {
1060
+ throw new RuntimeClientError({
1061
+ code: "VALIDATION_ERROR",
1062
+ message: "memories is required",
1063
+ retryable: false
1064
+ });
1065
+ }
1066
+ const queueEnabled = this.options.queueEnabled !== false;
1067
+ const useQueue = queueEnabled && params.write_mode !== "sync" && params.async !== false;
1068
+ if (useQueue) {
1069
+ const queued = await Promise.all(
1070
+ params.memories.map(
1071
+ (memory) => this.queue.enqueue({
1072
+ project,
1073
+ userId: memory.user_id,
1074
+ sessionId: memory.session_id,
1075
+ payload: {
1076
+ content: memory.content,
1077
+ memory_type: toSotaType(memory.memory_type),
1078
+ user_id: memory.user_id,
1079
+ session_id: memory.session_id,
1080
+ agent_id: memory.agent_id,
1081
+ importance: memory.importance,
1082
+ confidence: memory.confidence,
1083
+ metadata: memory.metadata,
1084
+ document_date: memory.document_date,
1085
+ event_date: memory.event_date
1086
+ }
1087
+ })
1088
+ )
1089
+ );
1090
+ for (const memory of params.memories) {
1091
+ this.invalidate(project, memory.user_id, memory.session_id);
1092
+ }
1093
+ return {
1094
+ success: true,
1095
+ mode: "async",
1096
+ queued: true,
1097
+ created: queued.length
1098
+ };
1099
+ }
1100
+ try {
1101
+ const response = await this.client.request({
1102
+ endpoint: "/v1/memory/bulk",
1103
+ method: "POST",
1104
+ operation: "bulk",
1105
+ body: {
1106
+ project,
1107
+ memories: params.memories.map((memory) => ({
1108
+ ...memory,
1109
+ memory_type: toSotaType(memory.memory_type)
1110
+ })),
1111
+ write_mode: "sync"
1112
+ }
1113
+ });
1114
+ for (const memory of params.memories) {
1115
+ this.invalidate(project, memory.user_id, memory.session_id);
1116
+ }
1117
+ return {
1118
+ success: true,
1119
+ mode: "sync",
1120
+ trace_id: response.traceId
1121
+ };
1122
+ } catch (error) {
1123
+ if (this.client.getCompatMode() !== "fallback" || !isEndpointNotFound(error)) {
1124
+ throw error;
1125
+ }
1126
+ await Promise.all(
1127
+ params.memories.map(
1128
+ (memory) => this.add({
1129
+ project,
1130
+ ...memory,
1131
+ write_mode: "sync"
1132
+ })
1133
+ )
1134
+ );
1135
+ return {
1136
+ success: true,
1137
+ mode: "sync"
1138
+ };
1139
+ }
1140
+ }
1141
+ async search(params) {
1142
+ const project = this.resolveProject(params.project);
1143
+ const topK = params.top_k || 10;
1144
+ const profile = params.profile || "fast";
1145
+ const includePending = params.include_pending !== false;
1146
+ const cacheKey = this.cache.makeKey({
1147
+ project,
1148
+ userId: params.user_id,
1149
+ sessionId: params.session_id,
1150
+ query: params.query,
1151
+ topK,
1152
+ profile,
1153
+ includePending
1154
+ });
1155
+ if (this.options.cacheEnabled !== false) {
1156
+ const cached = this.cache.get(cacheKey);
1157
+ if (cached) {
1158
+ return {
1159
+ ...cached,
1160
+ cache_hit: true
1161
+ };
1162
+ }
1163
+ }
1164
+ try {
1165
+ const response = await this.client.request({
1166
+ endpoint: "/v1/memory/search",
1167
+ method: "POST",
1168
+ operation: "search",
1169
+ idempotent: true,
1170
+ body: {
1171
+ project,
1172
+ query: params.query,
1173
+ user_id: params.user_id,
1174
+ session_id: params.session_id,
1175
+ top_k: topK,
1176
+ profile,
1177
+ include_pending: includePending,
1178
+ memory_types: params.memory_type ? [toSotaType(params.memory_type)] : void 0
1179
+ }
1180
+ });
1181
+ const data = {
1182
+ ...response.data || {},
1183
+ cache_hit: false
1184
+ };
1185
+ if (this.options.cacheEnabled !== false) {
1186
+ const scope = this.cache.makeScopeKey(project, params.user_id, params.session_id);
1187
+ this.cache.set(cacheKey, scope, data);
1188
+ }
1189
+ return data;
1190
+ } catch (error) {
1191
+ if (this.client.getCompatMode() !== "fallback" || !isEndpointNotFound(error)) {
1192
+ throw error;
1193
+ }
1194
+ const legacy = await this.client.request({
1195
+ endpoint: "/v1/memories/search",
1196
+ method: "POST",
1197
+ operation: "search",
1198
+ idempotent: true,
1199
+ body: {
1200
+ project,
1201
+ query: params.query,
1202
+ user_id: params.user_id,
1203
+ session_id: params.session_id,
1204
+ top_k: topK,
1205
+ memory_type: toLegacyType(params.memory_type)
1206
+ }
1207
+ });
1208
+ const data = {
1209
+ ...legacy.data || {},
1210
+ cache_hit: false
1211
+ };
1212
+ if (this.options.cacheEnabled !== false) {
1213
+ const scope = this.cache.makeScopeKey(project, params.user_id, params.session_id);
1214
+ this.cache.set(cacheKey, scope, data);
1215
+ }
1216
+ return data;
1217
+ }
1218
+ }
1219
+ async getUserProfile(params) {
1220
+ const project = this.resolveProject(params.project);
1221
+ const query = new URLSearchParams({
1222
+ project,
1223
+ ...params.include_pending !== void 0 ? { include_pending: String(params.include_pending) } : {},
1224
+ ...params.memory_types ? { memory_types: params.memory_types } : {}
1225
+ });
1226
+ try {
1227
+ const response = await this.client.request({
1228
+ endpoint: `/v1/memory/profile/${params.user_id}?${query}`,
1229
+ method: "GET",
1230
+ operation: "profile",
1231
+ idempotent: true
1232
+ });
1233
+ return response.data;
1234
+ } catch (error) {
1235
+ if (this.client.getCompatMode() !== "fallback" || !isEndpointNotFound(error)) {
1236
+ throw error;
1237
+ }
1238
+ const legacyQuery = new URLSearchParams({
1239
+ project,
1240
+ user_id: params.user_id,
1241
+ limit: "200"
1242
+ });
1243
+ const legacy = await this.client.request({
1244
+ endpoint: `/v1/memories?${legacyQuery}`,
1245
+ method: "GET",
1246
+ operation: "profile",
1247
+ idempotent: true
1248
+ });
1249
+ const memories = Array.isArray(legacy.data?.memories) ? legacy.data.memories : [];
1250
+ return {
1251
+ user_id: params.user_id,
1252
+ memories,
1253
+ count: memories.length
1254
+ };
1255
+ }
1256
+ }
1257
+ async getSessionMemories(params) {
1258
+ const project = this.resolveProject(params.project);
1259
+ const query = new URLSearchParams({
1260
+ project,
1261
+ ...params.limit ? { limit: String(params.limit) } : {},
1262
+ ...params.include_pending !== void 0 ? { include_pending: String(params.include_pending) } : {}
1263
+ });
1264
+ const response = await this.client.request({
1265
+ endpoint: `/v1/memory/session/${params.session_id}?${query}`,
1266
+ method: "GET",
1267
+ operation: "profile",
1268
+ idempotent: true
1269
+ });
1270
+ return response.data;
1271
+ }
1272
+ async update(memoryId, params) {
1273
+ try {
1274
+ await this.client.request({
1275
+ endpoint: `/v1/memory/${memoryId}`,
1276
+ method: "PUT",
1277
+ operation: "writeAck",
1278
+ body: params
1279
+ });
1280
+ return { success: true };
1281
+ } catch (error) {
1282
+ if (this.client.getCompatMode() !== "fallback" || !isEndpointNotFound(error)) {
1283
+ throw error;
1284
+ }
1285
+ await this.client.request({
1286
+ endpoint: `/v1/memories/${memoryId}`,
1287
+ method: "PUT",
1288
+ operation: "writeAck",
1289
+ body: { content: params.content }
1290
+ });
1291
+ return { success: true };
1292
+ }
1293
+ }
1294
+ async delete(memoryId) {
1295
+ try {
1296
+ await this.client.request({
1297
+ endpoint: `/v1/memory/${memoryId}`,
1298
+ method: "DELETE",
1299
+ operation: "writeAck"
1300
+ });
1301
+ return { success: true, deleted: memoryId };
1302
+ } catch (error) {
1303
+ if (this.client.getCompatMode() !== "fallback" || !isEndpointNotFound(error)) {
1304
+ throw error;
1305
+ }
1306
+ await this.client.request({
1307
+ endpoint: `/v1/memories/${memoryId}`,
1308
+ method: "DELETE",
1309
+ operation: "writeAck"
1310
+ });
1311
+ return { success: true, deleted: memoryId };
1312
+ }
1313
+ }
1314
+ async flag(params) {
1315
+ try {
1316
+ await this.client.request({
1317
+ endpoint: `/v1/memory/${params.memoryId}/flag`,
1318
+ method: "POST",
1319
+ operation: "writeAck",
1320
+ body: {
1321
+ reason: params.reason,
1322
+ severity: params.severity || "medium"
1323
+ }
1324
+ });
1325
+ return { success: true };
1326
+ } catch (error) {
1327
+ if (this.client.getCompatMode() !== "fallback" || !isEndpointNotFound(error)) {
1328
+ throw error;
1329
+ }
1330
+ await this.client.request({
1331
+ endpoint: `/v1/memory/${params.memoryId}`,
1332
+ method: "PUT",
1333
+ operation: "writeAck",
1334
+ body: {
1335
+ content: `[FLAGGED:${params.severity || "medium"}] ${params.reason}`
1336
+ }
1337
+ });
1338
+ return { success: true };
1339
+ }
1340
+ }
1341
+ };
1342
+
1343
+ // ../src/sdk/modules/session.ts
1344
+ function randomSessionId() {
1345
+ return `sess_${stableHash(`${Date.now()}_${Math.random()}`)}`;
1346
+ }
1347
+ function assertTransition(current, next) {
1348
+ const allowed = {
1349
+ created: ["active", "ended", "archived"],
1350
+ active: ["suspended", "ended", "archived"],
1351
+ suspended: ["resumed", "ended", "archived"],
1352
+ resumed: ["suspended", "ended", "archived"],
1353
+ ended: ["archived"],
1354
+ archived: []
1355
+ };
1356
+ if (!allowed[current].includes(next)) {
1357
+ throw new RuntimeClientError({
1358
+ code: "INVALID_SESSION_STATE",
1359
+ message: `Invalid session transition ${current} -> ${next}`,
1360
+ retryable: false
1361
+ });
1362
+ }
1363
+ }
1364
+ var SessionModule = class {
1365
+ constructor(memory, defaultProject) {
1366
+ this.memory = memory;
1367
+ this.defaultProject = defaultProject;
1368
+ }
1369
+ sessions = /* @__PURE__ */ new Map();
1370
+ resolveProject(project) {
1371
+ const value = project || this.defaultProject;
1372
+ if (!value) {
1373
+ throw new RuntimeClientError({
1374
+ code: "MISSING_PROJECT",
1375
+ message: "Project is required",
1376
+ retryable: false
1377
+ });
1378
+ }
1379
+ return value;
1380
+ }
1381
+ ensure(sessionId) {
1382
+ const found = this.sessions.get(sessionId);
1383
+ if (!found) {
1384
+ throw new RuntimeClientError({
1385
+ code: "SESSION_NOT_FOUND",
1386
+ message: `Unknown session ${sessionId}`,
1387
+ retryable: false
1388
+ });
1389
+ }
1390
+ return found;
1391
+ }
1392
+ async start(params) {
1393
+ const project = this.resolveProject(params.project);
1394
+ const sessionId = params.sessionId || randomSessionId();
1395
+ const now = nowIso();
1396
+ const record = {
1397
+ sessionId,
1398
+ project,
1399
+ userId: params.userId,
1400
+ state: "active",
1401
+ sequence: 0,
1402
+ metadata: params.metadata,
1403
+ createdAt: now,
1404
+ updatedAt: now
1405
+ };
1406
+ this.sessions.set(sessionId, record);
1407
+ return {
1408
+ sessionId,
1409
+ state: record.state,
1410
+ createdAt: now
1411
+ };
1412
+ }
1413
+ async event(params) {
1414
+ const session = this.ensure(params.sessionId);
1415
+ if (session.state !== "active" && session.state !== "resumed") {
1416
+ throw new RuntimeClientError({
1417
+ code: "INVALID_SESSION_STATE",
1418
+ message: `Cannot append event in ${session.state} state`,
1419
+ retryable: false
1420
+ });
1421
+ }
1422
+ session.sequence += 1;
1423
+ session.updatedAt = nowIso();
1424
+ const eventId = `evt_${stableHash(JSON.stringify({
1425
+ sessionId: session.sessionId,
1426
+ seq: session.sequence,
1427
+ type: params.type,
1428
+ content: params.content,
1429
+ parent: params.parentEventId || ""
1430
+ }))}`;
1431
+ await this.memory.add({
1432
+ project: session.project,
1433
+ content: `${params.type}: ${params.content}`,
1434
+ memory_type: "event",
1435
+ user_id: session.userId,
1436
+ session_id: session.sessionId,
1437
+ metadata: {
1438
+ session_event: true,
1439
+ event_id: eventId,
1440
+ sequence: session.sequence,
1441
+ parent_event_id: params.parentEventId,
1442
+ ...session.metadata,
1443
+ ...params.metadata || {}
1444
+ },
1445
+ write_mode: "async"
1446
+ });
1447
+ return {
1448
+ success: true,
1449
+ eventId,
1450
+ sequence: session.sequence
1451
+ };
1452
+ }
1453
+ async suspend(params) {
1454
+ const session = this.ensure(params.sessionId);
1455
+ assertTransition(session.state, "suspended");
1456
+ session.state = "suspended";
1457
+ session.updatedAt = nowIso();
1458
+ return { sessionId: session.sessionId, state: session.state };
1459
+ }
1460
+ async resume(params) {
1461
+ const session = this.ensure(params.sessionId);
1462
+ const target = session.state === "suspended" ? "resumed" : "active";
1463
+ assertTransition(session.state, target);
1464
+ session.state = target;
1465
+ session.updatedAt = nowIso();
1466
+ return { sessionId: session.sessionId, state: session.state };
1467
+ }
1468
+ async end(params) {
1469
+ const session = this.ensure(params.sessionId);
1470
+ assertTransition(session.state, "ended");
1471
+ session.state = "ended";
1472
+ session.updatedAt = nowIso();
1473
+ return { sessionId: session.sessionId, state: session.state };
1474
+ }
1475
+ async archive(params) {
1476
+ const session = this.ensure(params.sessionId);
1477
+ assertTransition(session.state, "archived");
1478
+ session.state = "archived";
1479
+ session.updatedAt = nowIso();
1480
+ return { sessionId: session.sessionId, state: session.state };
1481
+ }
1482
+ };
1483
+
1484
+ // ../src/sdk/modules/profile.ts
1485
+ var ProfileModule = class {
1486
+ constructor(memory) {
1487
+ this.memory = memory;
1488
+ }
1489
+ async getUserProfile(params) {
1490
+ return this.memory.getUserProfile(params);
1491
+ }
1492
+ async getSessionMemories(params) {
1493
+ return this.memory.getSessionMemories(params);
1494
+ }
1495
+ };
1496
+
1497
+ // ../src/sdk/modules/analytics.ts
1498
+ var AnalyticsModule = class {
1499
+ constructor(diagnostics, queue) {
1500
+ this.diagnostics = diagnostics;
1501
+ this.queue = queue;
1502
+ }
1503
+ diagnosticsSnapshot() {
1504
+ return this.diagnostics.snapshot();
1505
+ }
1506
+ queueStatus() {
1507
+ return this.queue.status();
1508
+ }
1509
+ };
1510
+
1511
+ // ../src/sdk/whisper.ts
1512
+ var WhisperClient = class _WhisperClient {
1513
+ constructor(config) {
1514
+ this.config = config;
1515
+ this.diagnosticsStore = new DiagnosticsStore(config.telemetry?.maxEntries || 1e3);
1516
+ this.runtimeClient = new RuntimeClient(
1517
+ {
1518
+ apiKey: config.apiKey,
1519
+ baseUrl: config.baseUrl,
1520
+ compatMode: config.compatMode || "fallback",
1521
+ timeouts: config.timeouts,
1522
+ retryPolicy: config.retryPolicy
1523
+ },
1524
+ this.diagnosticsStore
1525
+ );
1526
+ this.searchCache = new SearchResponseCache(
1527
+ config.cache?.ttlMs ?? 7e3,
1528
+ config.cache?.capacity ?? 500
1529
+ );
1530
+ const queueStore = config.queue?.persistence === "storage" ? createStorageQueueStore() : config.queue?.persistence === "file" && config.queue.filePath ? createFileQueueStore(config.queue.filePath) : new InMemoryQueueStore();
1531
+ this.writeQueue = new WriteQueue({
1532
+ store: queueStore,
1533
+ maxBatchSize: config.queue?.maxBatchSize ?? 50,
1534
+ flushIntervalMs: config.queue?.flushIntervalMs ?? 100,
1535
+ maxAttempts: config.queue?.maxAttempts ?? 2,
1536
+ flushHandler: async (items) => {
1537
+ if (items.length === 0) return;
1538
+ const project = items[0].project;
1539
+ const memories = items.map((item) => ({
1540
+ ...item.payload,
1541
+ user_id: item.payload.user_id ?? item.userId,
1542
+ session_id: item.payload.session_id ?? item.sessionId,
1543
+ metadata: {
1544
+ ...item.payload.metadata || {},
1545
+ event_id: item.eventId,
1546
+ queued_at: item.createdAt
1547
+ }
1548
+ }));
1549
+ try {
1550
+ await this.runtimeClient.request({
1551
+ endpoint: "/v1/memory/bulk",
1552
+ method: "POST",
1553
+ operation: "bulk",
1554
+ body: {
1555
+ project,
1556
+ write_mode: "async",
1557
+ memories
1558
+ }
1559
+ });
1560
+ } catch (error) {
1561
+ if (this.runtimeClient.getCompatMode() !== "fallback" || !(error instanceof RuntimeClientError) || error.status !== 404) {
1562
+ throw error;
1563
+ }
1564
+ await Promise.all(
1565
+ memories.map(async (memory) => {
1566
+ try {
1567
+ await this.runtimeClient.request({
1568
+ endpoint: "/v1/memory",
1569
+ method: "POST",
1570
+ operation: "writeAck",
1571
+ body: {
1572
+ project,
1573
+ ...memory,
1574
+ write_mode: "sync"
1575
+ }
1576
+ });
1577
+ } catch (fallbackError) {
1578
+ if (this.runtimeClient.getCompatMode() !== "fallback" || !(fallbackError instanceof RuntimeClientError) || fallbackError.status !== 404) {
1579
+ throw fallbackError;
1580
+ }
1581
+ await this.runtimeClient.request({
1582
+ endpoint: "/v1/memories",
1583
+ method: "POST",
1584
+ operation: "writeAck",
1585
+ body: {
1586
+ project,
1587
+ ...memory,
1588
+ memory_type: memory.memory_type === "event" ? "episodic" : memory.memory_type
1589
+ }
1590
+ });
1591
+ }
1592
+ })
1593
+ );
1594
+ }
1595
+ }
1596
+ });
1597
+ if (config.queue?.enabled !== false) {
1598
+ void this.writeQueue.start();
1599
+ }
1600
+ this.memoryModule = new MemoryModule(
1601
+ this.runtimeClient,
1602
+ this.searchCache,
1603
+ this.writeQueue,
1604
+ {
1605
+ defaultProject: config.project,
1606
+ cacheEnabled: config.cache?.enabled !== false,
1607
+ queueEnabled: config.queue?.enabled !== false
1608
+ }
1609
+ );
1610
+ this.sessionModule = new SessionModule(this.memoryModule, config.project);
1611
+ this.profileModule = new ProfileModule(this.memoryModule);
1612
+ this.analyticsModule = new AnalyticsModule(this.diagnosticsStore, this.writeQueue);
1613
+ this.diagnostics = {
1614
+ getLast: (limit) => this.diagnosticsStore.getLast(limit),
1615
+ subscribe: (fn) => this.diagnosticsStore.subscribe(fn),
1616
+ snapshot: () => this.diagnosticsStore.snapshot()
1617
+ };
1618
+ this.queue = {
1619
+ flush: () => this.writeQueue.flush(),
1620
+ status: () => this.writeQueue.status()
1621
+ };
1622
+ this.memory = {
1623
+ add: (params) => this.memoryModule.add(params),
1624
+ addBulk: (params) => this.memoryModule.addBulk(params),
1625
+ search: (params) => this.memoryModule.search(params),
1626
+ getUserProfile: (params) => this.memoryModule.getUserProfile(params),
1627
+ getSessionMemories: (params) => this.memoryModule.getSessionMemories(params),
1628
+ update: (memoryId, params) => this.memoryModule.update(memoryId, params),
1629
+ delete: (memoryId) => this.memoryModule.delete(memoryId),
1630
+ flag: (params) => this.memoryModule.flag(params)
1631
+ };
1632
+ this.session = {
1633
+ start: (params) => this.sessionModule.start(params),
1634
+ event: (params) => this.sessionModule.event(params),
1635
+ suspend: (params) => this.sessionModule.suspend(params),
1636
+ resume: (params) => this.sessionModule.resume(params),
1637
+ end: (params) => this.sessionModule.end(params)
1638
+ };
1639
+ this.profile = {
1640
+ getUserProfile: (params) => this.profileModule.getUserProfile(params),
1641
+ getSessionMemories: (params) => this.profileModule.getSessionMemories(params)
1642
+ };
1643
+ this.analytics = {
1644
+ diagnosticsSnapshot: () => this.analyticsModule.diagnosticsSnapshot(),
1645
+ queueStatus: () => this.analyticsModule.queueStatus()
1646
+ };
1647
+ }
1648
+ diagnostics;
1649
+ queue;
1650
+ memory;
1651
+ session;
1652
+ profile;
1653
+ analytics;
1654
+ runtimeClient;
1655
+ diagnosticsStore;
1656
+ searchCache;
1657
+ writeQueue;
1658
+ memoryModule;
1659
+ sessionModule;
1660
+ profileModule;
1661
+ analyticsModule;
1662
+ static fromEnv(overrides = {}) {
1663
+ const env = typeof process !== "undefined" ? process.env : {};
1664
+ const apiKey = overrides.apiKey || env.WHISPER_API_KEY || env.USEWHISPER_API_KEY || env.API_KEY;
1665
+ if (!apiKey) {
1666
+ throw new Error("Missing API key. Set WHISPER_API_KEY / USEWHISPER_API_KEY / API_KEY.");
242
1667
  }
243
- return Array.from(new Set(ids));
1668
+ return new _WhisperClient({
1669
+ apiKey,
1670
+ baseUrl: overrides.baseUrl || env.WHISPER_BASE_URL || env.API_BASE_URL || "https://context.usewhisper.dev",
1671
+ project: overrides.project || env.WHISPER_PROJECT || env.PROJECT,
1672
+ ...overrides
1673
+ });
1674
+ }
1675
+ withRunContext(context) {
1676
+ const base = this;
1677
+ return {
1678
+ memory: {
1679
+ add: (params) => base.memory.add({
1680
+ ...params,
1681
+ project: params.project || context.project || base.config.project,
1682
+ user_id: params.user_id || context.userId,
1683
+ session_id: params.session_id || context.sessionId
1684
+ }),
1685
+ search: (params) => base.memory.search({
1686
+ ...params,
1687
+ project: params.project || context.project || base.config.project,
1688
+ user_id: params.user_id || context.userId,
1689
+ session_id: params.session_id || context.sessionId
1690
+ })
1691
+ },
1692
+ session: {
1693
+ event: (params) => base.session.event({
1694
+ ...params,
1695
+ sessionId: params.sessionId || context.sessionId || ""
1696
+ })
1697
+ },
1698
+ queue: base.queue,
1699
+ diagnostics: base.diagnostics
1700
+ };
1701
+ }
1702
+ async shutdown() {
1703
+ await this.writeQueue.stop();
244
1704
  }
245
1705
  };
246
- var whisper_agent_default = Whisper;
1706
+ var whisper_default = WhisperClient;
247
1707
 
248
1708
  // ../src/sdk/middleware.ts
249
1709
  var WhisperAgentMiddleware = class {
@@ -314,14 +1774,409 @@ function createAgentMiddleware(config) {
314
1774
  return new WhisperAgentMiddleware(config);
315
1775
  }
316
1776
 
1777
+ // ../src/sdk/adapters/langchain.ts
1778
+ var LangChainMemoryAdapter = class {
1779
+ constructor(client, options) {
1780
+ this.client = client;
1781
+ this.options = options;
1782
+ this.memoryKey = options.memoryKey || "history";
1783
+ this.memoryKeys = [this.memoryKey];
1784
+ }
1785
+ memoryKeys;
1786
+ memoryKey;
1787
+ async loadMemoryVariables(_inputValues) {
1788
+ const response = await this.client.memory.search({
1789
+ project: this.options.project,
1790
+ query: "recent context",
1791
+ user_id: this.options.userId,
1792
+ session_id: this.options.sessionId,
1793
+ top_k: this.options.topK || 10,
1794
+ profile: this.options.profile || "fast",
1795
+ include_pending: true
1796
+ });
1797
+ const content = (response.results || []).map((row) => row.memory?.content || "").filter(Boolean).join("\n");
1798
+ return {
1799
+ [this.memoryKey]: content
1800
+ };
1801
+ }
1802
+ async saveContext(inputValues, outputValues) {
1803
+ const userInput = typeof inputValues.input === "string" ? inputValues.input : JSON.stringify(inputValues);
1804
+ const output = typeof outputValues.output === "string" ? outputValues.output : JSON.stringify(outputValues);
1805
+ await this.client.memory.addBulk({
1806
+ project: this.options.project,
1807
+ write_mode: "async",
1808
+ memories: [
1809
+ {
1810
+ content: `user: ${userInput}`,
1811
+ memory_type: "event",
1812
+ user_id: this.options.userId,
1813
+ session_id: this.options.sessionId
1814
+ },
1815
+ {
1816
+ content: `assistant: ${output}`,
1817
+ memory_type: "event",
1818
+ user_id: this.options.userId,
1819
+ session_id: this.options.sessionId
1820
+ }
1821
+ ]
1822
+ });
1823
+ }
1824
+ async clear() {
1825
+ const profile = await this.client.memory.getUserProfile({
1826
+ project: this.options.project,
1827
+ user_id: this.options.userId
1828
+ });
1829
+ await Promise.all(
1830
+ (profile.memories || []).map((memory) => String(memory.id || "")).filter(Boolean).map((id) => this.client.memory.delete(id))
1831
+ );
1832
+ }
1833
+ };
1834
+ function createLangChainMemoryAdapter(client, options) {
1835
+ return new LangChainMemoryAdapter(client, options);
1836
+ }
1837
+
1838
+ // ../src/sdk/adapters/langgraph.ts
1839
+ function asRecord(value) {
1840
+ return value && typeof value === "object" ? value : {};
1841
+ }
1842
+ function text(value) {
1843
+ return typeof value === "string" && value.trim() ? value : void 0;
1844
+ }
1845
+ function isTupleLike(value) {
1846
+ if (!value || typeof value !== "object") return false;
1847
+ const tuple = value;
1848
+ const config = asRecord(tuple.config);
1849
+ const configurable = asRecord(config.configurable);
1850
+ return Boolean(
1851
+ typeof configurable.thread_id === "string" && tuple.checkpoint && typeof tuple.checkpoint === "object"
1852
+ );
1853
+ }
1854
+ function tupleTimestamp(tuple, fallback) {
1855
+ const checkpoint = asRecord(tuple.checkpoint);
1856
+ const metadata = asRecord(tuple.metadata);
1857
+ const sources = [
1858
+ checkpoint.updatedAt,
1859
+ checkpoint.updated_at,
1860
+ checkpoint.ts,
1861
+ checkpoint.timestamp,
1862
+ metadata.updatedAt,
1863
+ metadata.updated_at,
1864
+ metadata.ts,
1865
+ metadata.timestamp,
1866
+ fallback
1867
+ ];
1868
+ for (const source of sources) {
1869
+ const parsed = source ? new Date(String(source)).getTime() : Number.NaN;
1870
+ if (!Number.isNaN(parsed) && parsed > 0) return parsed;
1871
+ }
1872
+ return 0;
1873
+ }
1874
+ function metadataMatches(target, filter) {
1875
+ if (!filter || Object.keys(filter).length === 0) return true;
1876
+ const value = target || {};
1877
+ return Object.entries(filter).every(([key, expected]) => {
1878
+ if (!(key in value)) return false;
1879
+ return JSON.stringify(value[key]) === JSON.stringify(expected);
1880
+ });
1881
+ }
1882
+ var LangGraphCheckpointAdapter = class {
1883
+ constructor(client, options = {}) {
1884
+ this.client = client;
1885
+ this.options = options;
1886
+ }
1887
+ localByKey = /* @__PURE__ */ new Map();
1888
+ localByThread = /* @__PURE__ */ new Map();
1889
+ options;
1890
+ getUserId(threadId) {
1891
+ const prefix = this.options.userIdPrefix || "langgraph-thread";
1892
+ return `${prefix}:${threadId}`;
1893
+ }
1894
+ resolveCheckpointNs(config) {
1895
+ return config.configurable.checkpoint_ns || this.options.defaultCheckpointNs || "default";
1896
+ }
1897
+ makeLocalKey(threadId, checkpointNs, checkpointId) {
1898
+ return `${threadId}:${checkpointNs}:${checkpointId}`;
1899
+ }
1900
+ normalizeTuple(tuple) {
1901
+ const config = asRecord(tuple.config);
1902
+ const configurable = asRecord(config.configurable);
1903
+ const threadId = text(configurable.thread_id) || "";
1904
+ const checkpointNs = text(configurable.checkpoint_ns) || this.options.defaultCheckpointNs || "default";
1905
+ const checkpointId = text(configurable.checkpoint_id) || "";
1906
+ return {
1907
+ config: {
1908
+ configurable: {
1909
+ thread_id: threadId,
1910
+ checkpoint_ns: checkpointNs,
1911
+ checkpoint_id: checkpointId || void 0
1912
+ }
1913
+ },
1914
+ checkpoint: asRecord(tuple.checkpoint),
1915
+ metadata: asRecord(tuple.metadata),
1916
+ parent_config: tuple.parent_config ? {
1917
+ configurable: {
1918
+ thread_id: text(tuple.parent_config.configurable.thread_id) || "",
1919
+ checkpoint_ns: text(tuple.parent_config.configurable.checkpoint_ns) || checkpointNs,
1920
+ checkpoint_id: text(tuple.parent_config.configurable.checkpoint_id)
1921
+ }
1922
+ } : null
1923
+ };
1924
+ }
1925
+ parseCheckpointTupleFromRow(row) {
1926
+ const rowMetadata = asRecord(row.metadata);
1927
+ const marker = rowMetadata.langgraph_checkpoint === true;
1928
+ const rawContent = text(row.content) || "";
1929
+ if (!rawContent) return null;
1930
+ try {
1931
+ const parsed = JSON.parse(rawContent);
1932
+ let tuple = null;
1933
+ if (isTupleLike(parsed)) {
1934
+ tuple = this.normalizeTuple(parsed);
1935
+ } else {
1936
+ const wrapped = asRecord(parsed);
1937
+ if (isTupleLike(wrapped.tuple)) {
1938
+ tuple = this.normalizeTuple(wrapped.tuple);
1939
+ }
1940
+ }
1941
+ if (!tuple) return null;
1942
+ const config = tuple.config.configurable;
1943
+ if (!config.thread_id) return null;
1944
+ if (!config.checkpoint_id) return null;
1945
+ if (!marker && rowMetadata.checkpoint_id !== config.checkpoint_id) {
1946
+ return null;
1947
+ }
1948
+ return {
1949
+ tuple,
1950
+ memoryId: text(row.id),
1951
+ createdAt: text(row.createdAt) || text(row.created_at),
1952
+ updatedAt: text(row.updatedAt) || text(row.updated_at)
1953
+ };
1954
+ } catch {
1955
+ return null;
1956
+ }
1957
+ }
1958
+ upsertLocal(record) {
1959
+ const cfg = record.tuple.config.configurable;
1960
+ const key = this.makeLocalKey(cfg.thread_id, cfg.checkpoint_ns || "default", cfg.checkpoint_id || "");
1961
+ this.localByKey.set(key, record);
1962
+ if (!this.localByThread.has(cfg.thread_id)) {
1963
+ this.localByThread.set(cfg.thread_id, /* @__PURE__ */ new Set());
1964
+ }
1965
+ this.localByThread.get(cfg.thread_id).add(key);
1966
+ }
1967
+ mergeWithLocal(records, threadId) {
1968
+ const merged = /* @__PURE__ */ new Map();
1969
+ for (const record of records) {
1970
+ const cfg = record.tuple.config.configurable;
1971
+ const key = this.makeLocalKey(cfg.thread_id, cfg.checkpoint_ns || "default", cfg.checkpoint_id || "");
1972
+ merged.set(key, record);
1973
+ }
1974
+ const localKeys = this.localByThread.get(threadId);
1975
+ if (localKeys) {
1976
+ for (const key of localKeys) {
1977
+ const local = this.localByKey.get(key);
1978
+ if (local) {
1979
+ merged.set(key, local);
1980
+ }
1981
+ }
1982
+ }
1983
+ return Array.from(merged.values());
1984
+ }
1985
+ applyListFilters(records, options) {
1986
+ let filtered = records;
1987
+ if (options?.filter?.checkpointNs) {
1988
+ filtered = filtered.filter(
1989
+ (record) => (record.tuple.config.configurable.checkpoint_ns || "default") === options.filter.checkpointNs
1990
+ );
1991
+ }
1992
+ if (options?.filter?.metadata) {
1993
+ filtered = filtered.filter((record) => metadataMatches(record.tuple.metadata, options.filter.metadata));
1994
+ }
1995
+ if (options?.before?.checkpointId) {
1996
+ const beforeId = options.before.checkpointId;
1997
+ filtered = filtered.filter(
1998
+ (record) => record.tuple.config.configurable.checkpoint_id !== beforeId
1999
+ );
2000
+ }
2001
+ if (options?.before?.updatedAt) {
2002
+ const cutoff = new Date(options.before.updatedAt).getTime();
2003
+ if (!Number.isNaN(cutoff)) {
2004
+ filtered = filtered.filter((record) => {
2005
+ const value = tupleTimestamp(record.tuple, record.updatedAt || record.createdAt);
2006
+ return value < cutoff;
2007
+ });
2008
+ }
2009
+ }
2010
+ const direction = options?.sort || "desc";
2011
+ filtered.sort((a, b) => {
2012
+ const ta = tupleTimestamp(a.tuple, a.updatedAt || a.createdAt);
2013
+ const tb = tupleTimestamp(b.tuple, b.updatedAt || b.createdAt);
2014
+ return direction === "asc" ? ta - tb : tb - ta;
2015
+ });
2016
+ if (options?.limit && options.limit > 0) {
2017
+ return filtered.slice(0, options.limit);
2018
+ }
2019
+ return filtered;
2020
+ }
2021
+ async fetchThreadRecords(threadId) {
2022
+ const profile = await this.client.memory.getUserProfile({
2023
+ project: this.options.project,
2024
+ user_id: this.getUserId(threadId),
2025
+ include_pending: true
2026
+ });
2027
+ const parsed = (profile.memories || []).map((row) => this.parseCheckpointTupleFromRow(row)).filter((value) => value !== null).filter((record) => record.tuple.config.configurable.thread_id === threadId);
2028
+ const merged = this.mergeWithLocal(parsed, threadId);
2029
+ for (const record of merged) {
2030
+ this.upsertLocal(record);
2031
+ }
2032
+ return merged;
2033
+ }
2034
+ async get(config) {
2035
+ const threadId = config.configurable.thread_id;
2036
+ const checkpointNs = this.resolveCheckpointNs(config);
2037
+ const checkpointId = config.configurable.checkpoint_id;
2038
+ if (checkpointId) {
2039
+ const local = this.localByKey.get(this.makeLocalKey(threadId, checkpointNs, checkpointId));
2040
+ if (local) return local.tuple;
2041
+ }
2042
+ const records = await this.fetchThreadRecords(threadId);
2043
+ const scoped = records.filter((record) => {
2044
+ const cfg = record.tuple.config.configurable;
2045
+ if ((cfg.checkpoint_ns || "default") !== checkpointNs) return false;
2046
+ if (!checkpointId) return true;
2047
+ return cfg.checkpoint_id === checkpointId;
2048
+ });
2049
+ if (scoped.length === 0) return void 0;
2050
+ scoped.sort((a, b) => {
2051
+ const ta = tupleTimestamp(a.tuple, a.updatedAt || a.createdAt);
2052
+ const tb = tupleTimestamp(b.tuple, b.updatedAt || b.createdAt);
2053
+ return tb - ta;
2054
+ });
2055
+ return scoped[0].tuple;
2056
+ }
2057
+ async put(config, checkpoint, metadata, parentConfig) {
2058
+ const threadId = config.configurable.thread_id;
2059
+ const checkpointNs = this.resolveCheckpointNs(config);
2060
+ const checkpointId = config.configurable.checkpoint_id || text(checkpoint.id) || `cp_${stableHash(JSON.stringify({
2061
+ threadId,
2062
+ checkpointNs,
2063
+ checkpoint,
2064
+ metadata: metadata || {},
2065
+ parentConfig: parentConfig || null
2066
+ }))}`;
2067
+ const tuple = this.normalizeTuple({
2068
+ config: {
2069
+ configurable: {
2070
+ thread_id: threadId,
2071
+ checkpoint_ns: checkpointNs,
2072
+ checkpoint_id: checkpointId
2073
+ }
2074
+ },
2075
+ checkpoint: {
2076
+ ...checkpoint,
2077
+ id: checkpointId
2078
+ },
2079
+ metadata: {
2080
+ ...metadata || {},
2081
+ checkpoint_ns: checkpointNs,
2082
+ written_at: nowIso()
2083
+ },
2084
+ parent_config: parentConfig ? this.normalizeTuple({
2085
+ config: parentConfig,
2086
+ checkpoint: {},
2087
+ metadata: {},
2088
+ parent_config: null
2089
+ }).config : null
2090
+ });
2091
+ const record = { tuple, updatedAt: nowIso() };
2092
+ this.upsertLocal(record);
2093
+ await this.client.memory.add({
2094
+ project: this.options.project,
2095
+ user_id: this.getUserId(threadId),
2096
+ session_id: threadId,
2097
+ memory_type: "event",
2098
+ write_mode: "async",
2099
+ content: JSON.stringify(tuple),
2100
+ metadata: {
2101
+ langgraph_checkpoint: true,
2102
+ thread_id: threadId,
2103
+ checkpoint_ns: checkpointNs,
2104
+ checkpoint_id: checkpointId,
2105
+ parent_checkpoint_id: parentConfig?.configurable.checkpoint_id
2106
+ }
2107
+ });
2108
+ return tuple.config;
2109
+ }
2110
+ async list(config, options) {
2111
+ const threadId = config.configurable.thread_id;
2112
+ const checkpointNs = this.resolveCheckpointNs(config);
2113
+ const records = await this.fetchThreadRecords(threadId);
2114
+ const scoped = records.filter(
2115
+ (record) => (record.tuple.config.configurable.checkpoint_ns || "default") === checkpointNs
2116
+ );
2117
+ return this.applyListFilters(scoped, options).map((record) => record.tuple);
2118
+ }
2119
+ async search(params) {
2120
+ const includePending = params.includePending !== false;
2121
+ const profile = params.profile || "fast";
2122
+ const checkpointNs = params.checkpointNs || this.options.defaultCheckpointNs || "default";
2123
+ const response = await this.client.memory.search({
2124
+ project: this.options.project,
2125
+ query: params.query,
2126
+ user_id: this.getUserId(params.threadId),
2127
+ session_id: params.threadId,
2128
+ top_k: params.topK || 10,
2129
+ include_pending: includePending,
2130
+ profile
2131
+ });
2132
+ const serverHits = (response.results || []).map((row) => {
2133
+ const content = text(row.memory?.content);
2134
+ if (!content) return null;
2135
+ try {
2136
+ const parsed = JSON.parse(content);
2137
+ if (!isTupleLike(parsed)) return null;
2138
+ const tuple = this.normalizeTuple(parsed);
2139
+ const ns = tuple.config.configurable.checkpoint_ns || "default";
2140
+ if (tuple.config.configurable.thread_id !== params.threadId) return null;
2141
+ if (ns !== checkpointNs) return null;
2142
+ return { tuple, score: row.similarity || 0 };
2143
+ } catch {
2144
+ return null;
2145
+ }
2146
+ }).filter((value) => value !== null);
2147
+ const merged = /* @__PURE__ */ new Map();
2148
+ for (const hit of serverHits) {
2149
+ const cfg = hit.tuple.config.configurable;
2150
+ const key = this.makeLocalKey(cfg.thread_id, cfg.checkpoint_ns || "default", cfg.checkpoint_id || "");
2151
+ merged.set(key, hit);
2152
+ }
2153
+ const localKeys = this.localByThread.get(params.threadId);
2154
+ if (localKeys && includePending) {
2155
+ for (const key of localKeys) {
2156
+ const local = this.localByKey.get(key);
2157
+ if (!local) continue;
2158
+ const cfg = local.tuple.config.configurable;
2159
+ if ((cfg.checkpoint_ns || "default") !== checkpointNs) continue;
2160
+ if (!merged.has(key)) {
2161
+ merged.set(key, { tuple: local.tuple, score: 0 });
2162
+ }
2163
+ }
2164
+ }
2165
+ return Array.from(merged.values()).sort((a, b) => b.score - a.score).map((row) => row.tuple).slice(0, params.topK || 10);
2166
+ }
2167
+ };
2168
+ function createLangGraphCheckpointAdapter(client, options = {}) {
2169
+ return new LangGraphCheckpointAdapter(client, options);
2170
+ }
2171
+
317
2172
  // ../src/sdk/graph-utils.ts
318
2173
  function sanitizeId(id) {
319
2174
  return `n_${id.replace(/[^a-zA-Z0-9_]/g, "_")}`;
320
2175
  }
321
2176
  function shortLabel(input, max = 48) {
322
- const text = (input || "").replace(/\s+/g, " ").trim();
323
- if (text.length <= max) return text;
324
- return `${text.slice(0, max - 3)}...`;
2177
+ const text2 = (input || "").replace(/\s+/g, " ").trim();
2178
+ if (text2.length <= max) return text2;
2179
+ return `${text2.slice(0, max - 3)}...`;
325
2180
  }
326
2181
  function memoryGraphToMermaid(graph) {
327
2182
  const lines = ["flowchart LR"];
@@ -359,36 +2214,42 @@ var DEFAULT_BASE_DELAY_MS = 250;
359
2214
  var DEFAULT_MAX_DELAY_MS = 2e3;
360
2215
  var DEFAULT_TIMEOUT_MS = 15e3;
361
2216
  var PROJECT_CACHE_TTL_MS = 3e4;
362
- function sleep(ms) {
363
- return new Promise((resolve) => setTimeout(resolve, ms));
364
- }
365
- function getBackoffDelay(attempt, base, max) {
366
- const jitter = 0.8 + Math.random() * 0.4;
367
- return Math.min(max, Math.floor(base * Math.pow(2, attempt) * jitter));
2217
+ var DEPRECATION_WARNINGS2 = /* @__PURE__ */ new Set();
2218
+ function warnDeprecatedOnce2(key, message) {
2219
+ if (DEPRECATION_WARNINGS2.has(key)) return;
2220
+ DEPRECATION_WARNINGS2.add(key);
2221
+ if (typeof console !== "undefined" && typeof console.warn === "function") {
2222
+ console.warn(message);
2223
+ }
368
2224
  }
369
2225
  function isLikelyProjectId(projectRef) {
370
2226
  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);
371
2227
  }
372
- function normalizeBaseUrl(url) {
2228
+ function normalizeBaseUrl2(url) {
373
2229
  let normalized = url.trim().replace(/\/+$/, "");
374
2230
  normalized = normalized.replace(/\/api\/v1$/i, "");
375
2231
  normalized = normalized.replace(/\/v1$/i, "");
376
2232
  normalized = normalized.replace(/\/api$/i, "");
377
2233
  return normalized;
378
2234
  }
379
- function normalizeEndpoint(endpoint) {
2235
+ function normalizeEndpoint2(endpoint) {
380
2236
  const withLeadingSlash = endpoint.startsWith("/") ? endpoint : `/${endpoint}`;
381
2237
  if (/^\/api\/v1(\/|$)/i.test(withLeadingSlash)) {
382
2238
  return withLeadingSlash.replace(/^\/api/i, "");
383
2239
  }
384
2240
  return withLeadingSlash;
385
2241
  }
2242
+ function isProjectNotFoundMessage(message) {
2243
+ const normalized = message.toLowerCase();
2244
+ return normalized.includes("project not found") || normalized.includes("no project found") || normalized.includes("project does not exist");
2245
+ }
386
2246
  var WhisperContext = class _WhisperContext {
387
2247
  apiKey;
388
2248
  baseUrl;
389
2249
  defaultProject;
390
2250
  timeoutMs;
391
2251
  retryConfig;
2252
+ runtimeClient;
392
2253
  projectRefToId = /* @__PURE__ */ new Map();
393
2254
  projectCache = [];
394
2255
  projectCacheExpiresAt = 0;
@@ -400,7 +2261,7 @@ var WhisperContext = class _WhisperContext {
400
2261
  });
401
2262
  }
402
2263
  this.apiKey = config.apiKey;
403
- this.baseUrl = normalizeBaseUrl(config.baseUrl || "https://context.usewhisper.dev");
2264
+ this.baseUrl = normalizeBaseUrl2(config.baseUrl || "https://context.usewhisper.dev");
404
2265
  this.defaultProject = config.project;
405
2266
  this.timeoutMs = config.timeoutMs ?? DEFAULT_TIMEOUT_MS;
406
2267
  this.retryConfig = {
@@ -408,6 +2269,35 @@ var WhisperContext = class _WhisperContext {
408
2269
  baseDelayMs: config.retry?.baseDelayMs ?? DEFAULT_BASE_DELAY_MS,
409
2270
  maxDelayMs: config.retry?.maxDelayMs ?? DEFAULT_MAX_DELAY_MS
410
2271
  };
2272
+ this.runtimeClient = new RuntimeClient({
2273
+ apiKey: this.apiKey,
2274
+ baseUrl: this.baseUrl,
2275
+ compatMode: "fallback",
2276
+ timeouts: {
2277
+ searchMs: this.timeoutMs,
2278
+ writeAckMs: this.timeoutMs,
2279
+ bulkMs: Math.max(this.timeoutMs, 1e4),
2280
+ profileMs: this.timeoutMs,
2281
+ sessionMs: this.timeoutMs
2282
+ },
2283
+ retryPolicy: {
2284
+ baseBackoffMs: this.retryConfig.baseDelayMs,
2285
+ maxBackoffMs: this.retryConfig.maxDelayMs,
2286
+ maxAttemptsByOperation: {
2287
+ search: this.retryConfig.maxAttempts,
2288
+ writeAck: this.retryConfig.maxAttempts,
2289
+ bulk: this.retryConfig.maxAttempts,
2290
+ profile: this.retryConfig.maxAttempts,
2291
+ session: this.retryConfig.maxAttempts,
2292
+ query: this.retryConfig.maxAttempts,
2293
+ get: this.retryConfig.maxAttempts
2294
+ }
2295
+ }
2296
+ });
2297
+ warnDeprecatedOnce2(
2298
+ "whisper_context_class",
2299
+ "[Whisper SDK] WhisperContext remains supported in v2 but is legacy. Prefer WhisperClient for runtime features (queue/cache/session/diagnostics)."
2300
+ );
411
2301
  }
412
2302
  withProject(project) {
413
2303
  return new _WhisperContext({
@@ -489,9 +2379,17 @@ var WhisperContext = class _WhisperContext {
489
2379
  return Array.from(candidates).filter(Boolean);
490
2380
  }
491
2381
  async withProjectRefFallback(projectRef, execute) {
2382
+ try {
2383
+ return await execute(projectRef);
2384
+ } catch (error) {
2385
+ if (!(error instanceof WhisperError) || error.code !== "PROJECT_NOT_FOUND") {
2386
+ throw error;
2387
+ }
2388
+ }
492
2389
  const refs = await this.getProjectRefCandidates(projectRef);
493
2390
  let lastError;
494
2391
  for (const ref of refs) {
2392
+ if (ref === projectRef) continue;
495
2393
  try {
496
2394
  return await execute(ref);
497
2395
  } catch (error) {
@@ -514,7 +2412,7 @@ var WhisperContext = class _WhisperContext {
514
2412
  if (status === 401 || /api key|unauthorized|forbidden/i.test(message)) {
515
2413
  return { code: "INVALID_API_KEY", retryable: false };
516
2414
  }
517
- if (status === 404 || /project not found/i.test(message)) {
2415
+ if (status === 404 && isProjectNotFoundMessage(message)) {
518
2416
  return { code: "PROJECT_NOT_FOUND", retryable: false };
519
2417
  }
520
2418
  if (status === 408) {
@@ -528,72 +2426,68 @@ var WhisperContext = class _WhisperContext {
528
2426
  }
529
2427
  return { code: "REQUEST_FAILED", retryable: false };
530
2428
  }
2429
+ isEndpointNotFoundError(error) {
2430
+ if (!(error instanceof WhisperError)) {
2431
+ return false;
2432
+ }
2433
+ if (error.status !== 404) {
2434
+ return false;
2435
+ }
2436
+ const message = (error.message || "").toLowerCase();
2437
+ return !isProjectNotFoundMessage(message);
2438
+ }
2439
+ inferOperation(endpoint, method) {
2440
+ const normalized = normalizeEndpoint2(endpoint).toLowerCase();
2441
+ if (normalized.includes("/memory/search")) return "search";
2442
+ if (normalized.includes("/memory/bulk")) return "bulk";
2443
+ if (normalized.includes("/memory/profile") || normalized.includes("/memory/session")) return "profile";
2444
+ if (normalized.includes("/memory/ingest/session")) return "session";
2445
+ if (normalized.includes("/context/query")) return "query";
2446
+ if (method === "GET") return "get";
2447
+ return "writeAck";
2448
+ }
531
2449
  async request(endpoint, options = {}) {
532
- const maxAttempts = Math.max(1, this.retryConfig.maxAttempts);
533
- const normalizedEndpoint = normalizeEndpoint(endpoint);
534
- let lastError;
535
- for (let attempt = 0; attempt < maxAttempts; attempt++) {
536
- const controller = new AbortController();
537
- const timeout = setTimeout(() => controller.abort(), this.timeoutMs);
2450
+ const method = String(options.method || "GET").toUpperCase();
2451
+ const normalizedEndpoint = normalizeEndpoint2(endpoint);
2452
+ const operation = this.inferOperation(normalizedEndpoint, method);
2453
+ let body;
2454
+ if (typeof options.body === "string") {
538
2455
  try {
539
- const headers = {
540
- "Content-Type": "application/json",
541
- ...options.headers
542
- };
543
- const hasAuthHeader = Object.keys(headers).some((k) => k.toLowerCase() === "authorization");
544
- const hasApiKeyHeader = Object.keys(headers).some((k) => k.toLowerCase() === "x-api-key");
545
- if (!hasAuthHeader) {
546
- headers.Authorization = `Bearer ${this.apiKey}`;
547
- }
548
- if (!hasApiKeyHeader) {
549
- headers["X-API-Key"] = this.apiKey;
550
- }
551
- const response = await fetch(`${this.baseUrl}${normalizedEndpoint}`, {
552
- ...options,
553
- signal: controller.signal,
554
- headers
555
- });
556
- clearTimeout(timeout);
557
- if (!response.ok) {
558
- let payload = null;
559
- try {
560
- payload = await response.json();
561
- } catch {
562
- payload = await response.text().catch(() => "");
563
- }
564
- const message = typeof payload === "string" ? payload : payload?.error || payload?.message || `HTTP ${response.status}: ${response.statusText}`;
565
- const { code, retryable } = this.classifyError(response.status, message);
566
- const err = new WhisperError({
567
- code,
568
- message,
569
- status: response.status,
570
- retryable,
571
- details: payload
572
- });
573
- if (!retryable || attempt === maxAttempts - 1) {
574
- throw err;
575
- }
576
- await sleep(getBackoffDelay(attempt, this.retryConfig.baseDelayMs, this.retryConfig.maxDelayMs));
577
- continue;
578
- }
579
- return response.json();
580
- } catch (error) {
581
- clearTimeout(timeout);
582
- const isAbort = error?.name === "AbortError";
583
- const mapped = error instanceof WhisperError ? error : new WhisperError({
584
- code: isAbort ? "TIMEOUT" : "NETWORK_ERROR",
585
- message: isAbort ? "Request timed out" : error?.message || "Network request failed",
586
- retryable: true,
587
- details: error
588
- });
589
- lastError = mapped;
590
- if (!mapped.retryable || attempt === maxAttempts - 1) {
591
- throw mapped;
592
- }
593
- await sleep(getBackoffDelay(attempt, this.retryConfig.baseDelayMs, this.retryConfig.maxDelayMs));
2456
+ body = JSON.parse(options.body);
2457
+ } catch {
2458
+ body = void 0;
594
2459
  }
2460
+ } 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)) {
2461
+ body = options.body;
2462
+ }
2463
+ try {
2464
+ const response = await this.runtimeClient.request({
2465
+ endpoint: normalizedEndpoint,
2466
+ method,
2467
+ operation,
2468
+ idempotent: method === "GET" || method === "POST" && (operation === "search" || operation === "query" || operation === "profile"),
2469
+ body,
2470
+ headers: options.headers || {}
2471
+ });
2472
+ return response.data;
2473
+ } catch (error) {
2474
+ if (!(error instanceof RuntimeClientError)) {
2475
+ throw error;
2476
+ }
2477
+ let message = error.message;
2478
+ if (error.status === 404 && !isProjectNotFoundMessage(message)) {
2479
+ const endpointHint = `${this.baseUrl}${normalizedEndpoint}`;
2480
+ message = `Endpoint not found at ${endpointHint}. This deployment may not support this API route.`;
2481
+ }
2482
+ const { code, retryable } = this.classifyError(error.status, message);
2483
+ throw new WhisperError({
2484
+ code,
2485
+ message,
2486
+ status: error.status,
2487
+ retryable,
2488
+ details: error.details
2489
+ });
595
2490
  }
596
- throw lastError instanceof Error ? lastError : new WhisperError({ code: "REQUEST_FAILED", message: "Request failed" });
597
2491
  }
598
2492
  async query(params) {
599
2493
  const projectRef = this.getRequiredProject(params.project);
@@ -666,7 +2560,7 @@ var WhisperContext = class _WhisperContext {
666
2560
  async addMemory(params) {
667
2561
  const projectRef = this.getRequiredProject(params.project);
668
2562
  return this.withProjectRefFallback(projectRef, async (project) => {
669
- const toSotaType = (memoryType) => {
2563
+ const toSotaType2 = (memoryType) => {
670
2564
  switch (memoryType) {
671
2565
  case "episodic":
672
2566
  return "event";
@@ -678,7 +2572,7 @@ var WhisperContext = class _WhisperContext {
678
2572
  return memoryType;
679
2573
  }
680
2574
  };
681
- const toLegacyType = (memoryType) => {
2575
+ const toLegacyType2 = (memoryType) => {
682
2576
  switch (memoryType) {
683
2577
  case "event":
684
2578
  return "episodic";
@@ -699,18 +2593,23 @@ var WhisperContext = class _WhisperContext {
699
2593
  body: JSON.stringify({
700
2594
  project,
701
2595
  content: params.content,
702
- memory_type: toSotaType(params.memory_type),
2596
+ memory_type: toSotaType2(params.memory_type),
703
2597
  user_id: params.user_id,
704
2598
  session_id: params.session_id,
705
2599
  agent_id: params.agent_id,
706
2600
  importance: params.importance,
707
- metadata: params.metadata
2601
+ metadata: params.metadata,
2602
+ async: params.async,
2603
+ write_mode: params.write_mode
708
2604
  })
709
2605
  });
710
- const id2 = direct?.memory?.id || direct?.id || direct?.memory_id;
2606
+ const id2 = direct?.memory?.id || direct?.id || direct?.memory_id || direct?.job_id;
711
2607
  if (id2) {
712
2608
  return { id: id2, success: true, path: "sota", fallback_used: false };
713
2609
  }
2610
+ if (direct?.success === true) {
2611
+ return { id: "", success: true, path: "sota", fallback_used: false };
2612
+ }
714
2613
  } catch (error) {
715
2614
  if (params.allow_legacy_fallback === false) {
716
2615
  throw error;
@@ -721,7 +2620,7 @@ var WhisperContext = class _WhisperContext {
721
2620
  body: JSON.stringify({
722
2621
  project,
723
2622
  content: params.content,
724
- memory_type: toLegacyType(params.memory_type),
2623
+ memory_type: toLegacyType2(params.memory_type),
725
2624
  user_id: params.user_id,
726
2625
  session_id: params.session_id,
727
2626
  agent_id: params.agent_id,
@@ -742,10 +2641,40 @@ var WhisperContext = class _WhisperContext {
742
2641
  }
743
2642
  async addMemoriesBulk(params) {
744
2643
  const projectRef = this.getRequiredProject(params.project);
745
- return this.withProjectRefFallback(projectRef, (project) => this.request("/v1/memory/bulk", {
746
- method: "POST",
747
- body: JSON.stringify({ ...params, project })
748
- }));
2644
+ return this.withProjectRefFallback(projectRef, async (project) => {
2645
+ try {
2646
+ return await this.request("/v1/memory/bulk", {
2647
+ method: "POST",
2648
+ body: JSON.stringify({ ...params, project })
2649
+ });
2650
+ } catch (error) {
2651
+ if (!this.isEndpointNotFoundError(error)) {
2652
+ throw error;
2653
+ }
2654
+ const created = await Promise.all(
2655
+ params.memories.map(
2656
+ (memory) => this.addMemory({
2657
+ project,
2658
+ content: memory.content,
2659
+ memory_type: memory.memory_type,
2660
+ user_id: memory.user_id,
2661
+ session_id: memory.session_id,
2662
+ agent_id: memory.agent_id,
2663
+ importance: memory.importance,
2664
+ metadata: memory.metadata,
2665
+ allow_legacy_fallback: true
2666
+ })
2667
+ )
2668
+ );
2669
+ return {
2670
+ success: true,
2671
+ created: created.length,
2672
+ memories: created,
2673
+ path: "legacy",
2674
+ fallback_used: true
2675
+ };
2676
+ }
2677
+ });
749
2678
  }
750
2679
  async extractMemories(params) {
751
2680
  const projectRef = this.getRequiredProject(params.project);
@@ -770,17 +2699,48 @@ var WhisperContext = class _WhisperContext {
770
2699
  }
771
2700
  async searchMemories(params) {
772
2701
  const projectRef = this.getRequiredProject(params.project);
773
- return this.withProjectRefFallback(projectRef, (project) => this.request("/v1/memory/search", {
774
- method: "POST",
775
- body: JSON.stringify({
776
- query: params.query,
777
- project,
778
- user_id: params.user_id,
779
- session_id: params.session_id,
780
- memory_types: params.memory_type ? [params.memory_type] : void 0,
781
- top_k: params.top_k || 10
782
- })
783
- }));
2702
+ return this.withProjectRefFallback(projectRef, async (project) => {
2703
+ try {
2704
+ return await this.request("/v1/memory/search", {
2705
+ method: "POST",
2706
+ body: JSON.stringify({
2707
+ query: params.query,
2708
+ project,
2709
+ user_id: params.user_id,
2710
+ session_id: params.session_id,
2711
+ memory_types: params.memory_type ? [params.memory_type] : void 0,
2712
+ top_k: params.top_k || 10,
2713
+ profile: params.profile,
2714
+ include_pending: params.include_pending
2715
+ })
2716
+ });
2717
+ } catch (error) {
2718
+ if (!this.isEndpointNotFoundError(error)) {
2719
+ throw error;
2720
+ }
2721
+ const legacyTypeMap = {
2722
+ factual: "factual",
2723
+ preference: "semantic",
2724
+ event: "episodic",
2725
+ relationship: "semantic",
2726
+ opinion: "semantic",
2727
+ goal: "semantic",
2728
+ instruction: "procedural"
2729
+ };
2730
+ return this.request("/v1/memories/search", {
2731
+ method: "POST",
2732
+ body: JSON.stringify({
2733
+ query: params.query,
2734
+ project,
2735
+ user_id: params.user_id,
2736
+ session_id: params.session_id,
2737
+ agent_id: params.agent_id,
2738
+ memory_type: params.memory_type ? legacyTypeMap[params.memory_type] : void 0,
2739
+ top_k: params.top_k || 10
2740
+ })
2741
+ });
2742
+ }
2743
+ });
784
2744
  }
785
2745
  async createApiKey(params) {
786
2746
  return this.request("/v1/keys", {
@@ -796,10 +2756,29 @@ var WhisperContext = class _WhisperContext {
796
2756
  }
797
2757
  async searchMemoriesSOTA(params) {
798
2758
  const projectRef = this.getRequiredProject(params.project);
799
- return this.withProjectRefFallback(projectRef, (project) => this.request("/v1/memory/search", {
800
- method: "POST",
801
- body: JSON.stringify({ ...params, project })
802
- }));
2759
+ return this.withProjectRefFallback(projectRef, async (project) => {
2760
+ try {
2761
+ return await this.request("/v1/memory/search", {
2762
+ method: "POST",
2763
+ body: JSON.stringify({ ...params, project })
2764
+ });
2765
+ } catch (error) {
2766
+ if (!this.isEndpointNotFoundError(error)) {
2767
+ throw error;
2768
+ }
2769
+ const firstType = params.memory_types?.[0];
2770
+ return this.searchMemories({
2771
+ project,
2772
+ query: params.query,
2773
+ user_id: params.user_id,
2774
+ session_id: params.session_id,
2775
+ memory_type: firstType,
2776
+ top_k: params.top_k,
2777
+ profile: params.profile,
2778
+ include_pending: params.include_pending
2779
+ });
2780
+ }
2781
+ });
803
2782
  }
804
2783
  async ingestSession(params) {
805
2784
  const projectRef = this.getRequiredProject(params.project);
@@ -809,33 +2788,92 @@ var WhisperContext = class _WhisperContext {
809
2788
  }));
810
2789
  }
811
2790
  async getSessionMemories(params) {
812
- const project = await this.resolveProjectId(this.getRequiredProject(params.project));
813
- const query = new URLSearchParams({
814
- project,
815
- ...params.limit && { limit: params.limit.toString() },
816
- ...params.since_date && { since_date: params.since_date }
2791
+ const projectRef = this.getRequiredProject(params.project);
2792
+ return this.withProjectRefFallback(projectRef, async (project) => {
2793
+ const query = new URLSearchParams({
2794
+ project,
2795
+ ...params.limit && { limit: params.limit.toString() },
2796
+ ...params.since_date && { since_date: params.since_date },
2797
+ ...params.include_pending !== void 0 && { include_pending: String(params.include_pending) }
2798
+ });
2799
+ try {
2800
+ return await this.request(`/v1/memory/session/${params.session_id}?${query}`);
2801
+ } catch (error) {
2802
+ if (!this.isEndpointNotFoundError(error)) {
2803
+ throw error;
2804
+ }
2805
+ return { memories: [], count: 0 };
2806
+ }
817
2807
  });
818
- return this.request(`/v1/memory/session/${params.session_id}?${query}`);
819
2808
  }
820
2809
  async getUserProfile(params) {
821
- const project = await this.resolveProjectId(this.getRequiredProject(params.project));
822
- const query = new URLSearchParams({
823
- project,
824
- ...params.memory_types && { memory_types: params.memory_types }
2810
+ const projectRef = this.getRequiredProject(params.project);
2811
+ return this.withProjectRefFallback(projectRef, async (project) => {
2812
+ const query = new URLSearchParams({
2813
+ project,
2814
+ ...params.memory_types && { memory_types: params.memory_types },
2815
+ ...params.include_pending !== void 0 && { include_pending: String(params.include_pending) }
2816
+ });
2817
+ try {
2818
+ return await this.request(`/v1/memory/profile/${params.user_id}?${query}`);
2819
+ } catch (error) {
2820
+ if (!this.isEndpointNotFoundError(error)) {
2821
+ throw error;
2822
+ }
2823
+ const legacyQuery = new URLSearchParams({
2824
+ project,
2825
+ user_id: params.user_id,
2826
+ limit: "200"
2827
+ });
2828
+ const legacy = await this.request(`/v1/memories?${legacyQuery}`);
2829
+ const memories = Array.isArray(legacy?.memories) ? legacy.memories : [];
2830
+ return {
2831
+ user_id: params.user_id,
2832
+ memories,
2833
+ count: memories.length
2834
+ };
2835
+ }
825
2836
  });
826
- return this.request(`/v1/memory/profile/${params.user_id}?${query}`);
827
2837
  }
828
2838
  async getMemoryVersions(memoryId) {
829
2839
  return this.request(`/v1/memory/${memoryId}/versions`);
830
2840
  }
831
2841
  async updateMemory(memoryId, params) {
832
- return this.request(`/v1/memory/${memoryId}`, {
833
- method: "PUT",
834
- body: JSON.stringify(params)
835
- });
2842
+ try {
2843
+ return await this.request(`/v1/memory/${memoryId}`, {
2844
+ method: "PUT",
2845
+ body: JSON.stringify(params)
2846
+ });
2847
+ } catch (error) {
2848
+ if (!this.isEndpointNotFoundError(error)) {
2849
+ throw error;
2850
+ }
2851
+ const legacy = await this.request(`/v1/memories/${memoryId}`, {
2852
+ method: "PUT",
2853
+ body: JSON.stringify({
2854
+ content: params.content
2855
+ })
2856
+ });
2857
+ return {
2858
+ success: true,
2859
+ new_memory_id: legacy?.id || memoryId,
2860
+ old_memory_id: memoryId
2861
+ };
2862
+ }
836
2863
  }
837
2864
  async deleteMemory(memoryId) {
838
- return this.request(`/v1/memory/${memoryId}`, { method: "DELETE" });
2865
+ try {
2866
+ return await this.request(`/v1/memory/${memoryId}`, { method: "DELETE" });
2867
+ } catch (error) {
2868
+ if (!this.isEndpointNotFoundError(error)) {
2869
+ throw error;
2870
+ }
2871
+ await this.request(`/v1/memories/${memoryId}`, { method: "DELETE" });
2872
+ return {
2873
+ success: true,
2874
+ deleted: memoryId
2875
+ };
2876
+ }
839
2877
  }
840
2878
  async getMemoryRelations(memoryId) {
841
2879
  return this.request(`/v1/memory/${memoryId}/relations`);
@@ -1026,12 +3064,18 @@ var WhisperContext = class _WhisperContext {
1026
3064
  };
1027
3065
  var index_default = WhisperContext;
1028
3066
  export {
3067
+ LangChainMemoryAdapter,
3068
+ LangGraphCheckpointAdapter,
1029
3069
  Whisper,
1030
3070
  WhisperAgentMiddleware,
3071
+ WhisperClient,
1031
3072
  WhisperContext,
1032
3073
  whisper_agent_default as WhisperDefault,
1033
3074
  WhisperError,
3075
+ whisper_default as WhisperRuntimeClient,
1034
3076
  createAgentMiddleware,
3077
+ createLangChainMemoryAdapter,
3078
+ createLangGraphCheckpointAdapter,
1035
3079
  index_default as default,
1036
3080
  memoryGraphToMermaid
1037
3081
  };