@usewhisper/sdk 2.2.0 → 2.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.d.mts CHANGED
@@ -179,6 +179,7 @@ declare class Whisper {
179
179
  */
180
180
  raw(): WhisperContext;
181
181
  private extractMemoryIdsFromBulkResponse;
182
+ private fallbackCaptureViaAddMemory;
182
183
  }
183
184
 
184
185
  interface AgentMiddlewareConfig extends WhisperOptions {
@@ -315,7 +316,20 @@ interface QueryResult {
315
316
  cache_hit: boolean;
316
317
  tokens_used: number;
317
318
  context_hash: string;
319
+ profile?: string;
318
320
  compression?: any;
321
+ timing?: {
322
+ cache_check_ms?: number;
323
+ embed_ms?: number;
324
+ vector_ms?: number;
325
+ fts_ms?: number;
326
+ rerank_ms?: number;
327
+ enrich_ms?: number;
328
+ pack_ms?: number;
329
+ cache_set_ms?: number;
330
+ total_ms?: number;
331
+ [key: string]: number | undefined;
332
+ };
319
333
  };
320
334
  }
321
335
  interface Project {
@@ -372,6 +386,61 @@ interface MemoryExtractionResult {
372
386
  extractionMethod: "pattern" | "inference" | "hybrid" | "skipped";
373
387
  latencyMs: number;
374
388
  }
389
+ interface MemoryLatencyBreakdown {
390
+ cache_ms: number;
391
+ embed_ms: number;
392
+ vector_ms: number;
393
+ lexical_ms: number;
394
+ merge_ms: number;
395
+ total_ms: number;
396
+ }
397
+ interface MemorySearchResponse {
398
+ results: Array<{
399
+ memory: {
400
+ id: string;
401
+ content: string;
402
+ type: string;
403
+ entities?: string[];
404
+ confidence?: number;
405
+ version?: number;
406
+ temporal?: {
407
+ document_date?: string | null;
408
+ event_date?: string | null;
409
+ valid_from?: string | null;
410
+ valid_until?: string | null;
411
+ };
412
+ };
413
+ chunk?: {
414
+ id: string;
415
+ content: string;
416
+ metadata?: Record<string, any>;
417
+ };
418
+ similarity: number;
419
+ relations?: any[];
420
+ }>;
421
+ count: number;
422
+ query: string;
423
+ trace_id?: string;
424
+ question_date?: string;
425
+ latency_ms?: number;
426
+ latency_breakdown?: MemoryLatencyBreakdown;
427
+ fallback?: "vector" | "lexical";
428
+ mode?: "fast" | "balanced" | "quality";
429
+ profile?: "fast" | "balanced" | "quality";
430
+ include_pending?: boolean;
431
+ pending_overlay_count?: number;
432
+ }
433
+ interface MemoryWriteAck {
434
+ success: boolean;
435
+ mode?: "async" | "sync";
436
+ trace_id?: string;
437
+ job_id?: string;
438
+ status_url?: string;
439
+ accepted_at?: string;
440
+ visibility_sla_ms?: number;
441
+ pending_visibility?: boolean;
442
+ [key: string]: any;
443
+ }
375
444
  type WhisperErrorCode = "INVALID_API_KEY" | "PROJECT_NOT_FOUND" | "PROJECT_AMBIGUOUS" | "RATE_LIMITED" | "TEMPORARY_UNAVAILABLE" | "NETWORK_ERROR" | "TIMEOUT" | "REQUEST_FAILED" | "MISSING_PROJECT";
376
445
  declare class WhisperError extends Error {
377
446
  code: WhisperErrorCode;
@@ -403,6 +472,7 @@ declare class WhisperContext {
403
472
  private getProjectRefCandidates;
404
473
  private withProjectRefFallback;
405
474
  private classifyError;
475
+ private isEndpointNotFoundError;
406
476
  private request;
407
477
  query(params: QueryParams): Promise<QueryResult>;
408
478
  createProject(params: {
@@ -453,6 +523,8 @@ declare class WhisperContext {
453
523
  importance?: number;
454
524
  metadata?: Record<string, any>;
455
525
  expires_in_seconds?: number;
526
+ async?: boolean;
527
+ write_mode?: "async" | "sync";
456
528
  allow_legacy_fallback?: boolean;
457
529
  }): Promise<{
458
530
  id: string;
@@ -478,6 +550,7 @@ declare class WhisperContext {
478
550
  namespace?: string;
479
551
  tags?: string[];
480
552
  async?: boolean;
553
+ write_mode?: "async" | "sync";
481
554
  webhook_url?: string;
482
555
  }): Promise<any>;
483
556
  extractMemories(params: {
@@ -513,7 +586,9 @@ declare class WhisperContext {
513
586
  agent_id?: string;
514
587
  memory_type?: "factual" | "preference" | "event" | "relationship" | "opinion" | "goal" | "instruction";
515
588
  top_k?: number;
516
- }): Promise<any>;
589
+ profile?: "fast" | "balanced" | "quality";
590
+ include_pending?: boolean;
591
+ }): Promise<MemorySearchResponse>;
517
592
  createApiKey(params: {
518
593
  name: string;
519
594
  scopes?: string[];
@@ -540,7 +615,9 @@ declare class WhisperContext {
540
615
  include_chunks?: boolean;
541
616
  include_relations?: boolean;
542
617
  fast_mode?: boolean;
543
- }): Promise<any>;
618
+ profile?: "fast" | "balanced" | "quality";
619
+ include_pending?: boolean;
620
+ }): Promise<MemorySearchResponse>;
544
621
  ingestSession(params: {
545
622
  project?: string;
546
623
  session_id: string;
@@ -550,18 +627,21 @@ declare class WhisperContext {
550
627
  content: string;
551
628
  timestamp: string;
552
629
  }>;
630
+ async?: boolean;
631
+ write_mode?: "async" | "sync";
553
632
  }): Promise<{
554
633
  success: boolean;
555
634
  memories_created: number;
556
635
  relations_created: number;
557
636
  memories_invalidated: number;
558
637
  errors?: string[];
559
- }>;
638
+ } & MemoryWriteAck>;
560
639
  getSessionMemories(params: {
561
640
  session_id: string;
562
641
  project?: string;
563
642
  limit?: number;
564
643
  since_date?: string;
644
+ include_pending?: boolean;
565
645
  }): Promise<{
566
646
  memories: any[];
567
647
  count: number;
@@ -570,6 +650,7 @@ declare class WhisperContext {
570
650
  user_id: string;
571
651
  project?: string;
572
652
  memory_types?: string;
653
+ include_pending?: boolean;
573
654
  }): Promise<{
574
655
  user_id: string;
575
656
  memories: any[];
@@ -832,15 +913,15 @@ declare class WhisperContext {
832
913
  count: number;
833
914
  latencyMs: number;
834
915
  }>;
835
- search: (params: Parameters<WhisperContext["searchMemories"]>[0]) => Promise<any>;
836
- searchSOTA: (params: Parameters<WhisperContext["searchMemoriesSOTA"]>[0]) => Promise<any>;
916
+ search: (params: Parameters<WhisperContext["searchMemories"]>[0]) => Promise<MemorySearchResponse>;
917
+ searchSOTA: (params: Parameters<WhisperContext["searchMemoriesSOTA"]>[0]) => Promise<MemorySearchResponse>;
837
918
  ingestSession: (params: Parameters<WhisperContext["ingestSession"]>[0]) => Promise<{
838
919
  success: boolean;
839
920
  memories_created: number;
840
921
  relations_created: number;
841
922
  memories_invalidated: number;
842
923
  errors?: string[];
843
- }>;
924
+ } & MemoryWriteAck>;
844
925
  getSessionMemories: (params: Parameters<WhisperContext["getSessionMemories"]>[0]) => Promise<{
845
926
  memories: any[];
846
927
  count: number;
@@ -955,4 +1036,4 @@ declare class WhisperContext {
955
1036
  };
956
1037
  }
957
1038
 
958
- export { type ExtractedMemory, type Memory, type MemoryExtractionResult, type MemoryKind, type Project, type QueryParams, type QueryResult, type Source, Whisper, WhisperAgentMiddleware, type WhisperConfig, WhisperContext, Whisper as WhisperDefault, WhisperError, type WhisperErrorCode, createAgentMiddleware, WhisperContext as default, memoryGraphToMermaid };
1039
+ export { type ExtractedMemory, type Memory, type MemoryExtractionResult, type MemoryKind, type MemoryLatencyBreakdown, type MemorySearchResponse, type MemoryWriteAck, type Project, type QueryParams, type QueryResult, type Source, Whisper, WhisperAgentMiddleware, type WhisperConfig, WhisperContext, Whisper as WhisperDefault, WhisperError, type WhisperErrorCode, createAgentMiddleware, WhisperContext as default, memoryGraphToMermaid };
package/index.d.ts CHANGED
@@ -179,6 +179,7 @@ declare class Whisper {
179
179
  */
180
180
  raw(): WhisperContext;
181
181
  private extractMemoryIdsFromBulkResponse;
182
+ private fallbackCaptureViaAddMemory;
182
183
  }
183
184
 
184
185
  interface AgentMiddlewareConfig extends WhisperOptions {
@@ -315,7 +316,20 @@ interface QueryResult {
315
316
  cache_hit: boolean;
316
317
  tokens_used: number;
317
318
  context_hash: string;
319
+ profile?: string;
318
320
  compression?: any;
321
+ timing?: {
322
+ cache_check_ms?: number;
323
+ embed_ms?: number;
324
+ vector_ms?: number;
325
+ fts_ms?: number;
326
+ rerank_ms?: number;
327
+ enrich_ms?: number;
328
+ pack_ms?: number;
329
+ cache_set_ms?: number;
330
+ total_ms?: number;
331
+ [key: string]: number | undefined;
332
+ };
319
333
  };
320
334
  }
321
335
  interface Project {
@@ -372,6 +386,61 @@ interface MemoryExtractionResult {
372
386
  extractionMethod: "pattern" | "inference" | "hybrid" | "skipped";
373
387
  latencyMs: number;
374
388
  }
389
+ interface MemoryLatencyBreakdown {
390
+ cache_ms: number;
391
+ embed_ms: number;
392
+ vector_ms: number;
393
+ lexical_ms: number;
394
+ merge_ms: number;
395
+ total_ms: number;
396
+ }
397
+ interface MemorySearchResponse {
398
+ results: Array<{
399
+ memory: {
400
+ id: string;
401
+ content: string;
402
+ type: string;
403
+ entities?: string[];
404
+ confidence?: number;
405
+ version?: number;
406
+ temporal?: {
407
+ document_date?: string | null;
408
+ event_date?: string | null;
409
+ valid_from?: string | null;
410
+ valid_until?: string | null;
411
+ };
412
+ };
413
+ chunk?: {
414
+ id: string;
415
+ content: string;
416
+ metadata?: Record<string, any>;
417
+ };
418
+ similarity: number;
419
+ relations?: any[];
420
+ }>;
421
+ count: number;
422
+ query: string;
423
+ trace_id?: string;
424
+ question_date?: string;
425
+ latency_ms?: number;
426
+ latency_breakdown?: MemoryLatencyBreakdown;
427
+ fallback?: "vector" | "lexical";
428
+ mode?: "fast" | "balanced" | "quality";
429
+ profile?: "fast" | "balanced" | "quality";
430
+ include_pending?: boolean;
431
+ pending_overlay_count?: number;
432
+ }
433
+ interface MemoryWriteAck {
434
+ success: boolean;
435
+ mode?: "async" | "sync";
436
+ trace_id?: string;
437
+ job_id?: string;
438
+ status_url?: string;
439
+ accepted_at?: string;
440
+ visibility_sla_ms?: number;
441
+ pending_visibility?: boolean;
442
+ [key: string]: any;
443
+ }
375
444
  type WhisperErrorCode = "INVALID_API_KEY" | "PROJECT_NOT_FOUND" | "PROJECT_AMBIGUOUS" | "RATE_LIMITED" | "TEMPORARY_UNAVAILABLE" | "NETWORK_ERROR" | "TIMEOUT" | "REQUEST_FAILED" | "MISSING_PROJECT";
376
445
  declare class WhisperError extends Error {
377
446
  code: WhisperErrorCode;
@@ -403,6 +472,7 @@ declare class WhisperContext {
403
472
  private getProjectRefCandidates;
404
473
  private withProjectRefFallback;
405
474
  private classifyError;
475
+ private isEndpointNotFoundError;
406
476
  private request;
407
477
  query(params: QueryParams): Promise<QueryResult>;
408
478
  createProject(params: {
@@ -453,6 +523,8 @@ declare class WhisperContext {
453
523
  importance?: number;
454
524
  metadata?: Record<string, any>;
455
525
  expires_in_seconds?: number;
526
+ async?: boolean;
527
+ write_mode?: "async" | "sync";
456
528
  allow_legacy_fallback?: boolean;
457
529
  }): Promise<{
458
530
  id: string;
@@ -478,6 +550,7 @@ declare class WhisperContext {
478
550
  namespace?: string;
479
551
  tags?: string[];
480
552
  async?: boolean;
553
+ write_mode?: "async" | "sync";
481
554
  webhook_url?: string;
482
555
  }): Promise<any>;
483
556
  extractMemories(params: {
@@ -513,7 +586,9 @@ declare class WhisperContext {
513
586
  agent_id?: string;
514
587
  memory_type?: "factual" | "preference" | "event" | "relationship" | "opinion" | "goal" | "instruction";
515
588
  top_k?: number;
516
- }): Promise<any>;
589
+ profile?: "fast" | "balanced" | "quality";
590
+ include_pending?: boolean;
591
+ }): Promise<MemorySearchResponse>;
517
592
  createApiKey(params: {
518
593
  name: string;
519
594
  scopes?: string[];
@@ -540,7 +615,9 @@ declare class WhisperContext {
540
615
  include_chunks?: boolean;
541
616
  include_relations?: boolean;
542
617
  fast_mode?: boolean;
543
- }): Promise<any>;
618
+ profile?: "fast" | "balanced" | "quality";
619
+ include_pending?: boolean;
620
+ }): Promise<MemorySearchResponse>;
544
621
  ingestSession(params: {
545
622
  project?: string;
546
623
  session_id: string;
@@ -550,18 +627,21 @@ declare class WhisperContext {
550
627
  content: string;
551
628
  timestamp: string;
552
629
  }>;
630
+ async?: boolean;
631
+ write_mode?: "async" | "sync";
553
632
  }): Promise<{
554
633
  success: boolean;
555
634
  memories_created: number;
556
635
  relations_created: number;
557
636
  memories_invalidated: number;
558
637
  errors?: string[];
559
- }>;
638
+ } & MemoryWriteAck>;
560
639
  getSessionMemories(params: {
561
640
  session_id: string;
562
641
  project?: string;
563
642
  limit?: number;
564
643
  since_date?: string;
644
+ include_pending?: boolean;
565
645
  }): Promise<{
566
646
  memories: any[];
567
647
  count: number;
@@ -570,6 +650,7 @@ declare class WhisperContext {
570
650
  user_id: string;
571
651
  project?: string;
572
652
  memory_types?: string;
653
+ include_pending?: boolean;
573
654
  }): Promise<{
574
655
  user_id: string;
575
656
  memories: any[];
@@ -832,15 +913,15 @@ declare class WhisperContext {
832
913
  count: number;
833
914
  latencyMs: number;
834
915
  }>;
835
- search: (params: Parameters<WhisperContext["searchMemories"]>[0]) => Promise<any>;
836
- searchSOTA: (params: Parameters<WhisperContext["searchMemoriesSOTA"]>[0]) => Promise<any>;
916
+ search: (params: Parameters<WhisperContext["searchMemories"]>[0]) => Promise<MemorySearchResponse>;
917
+ searchSOTA: (params: Parameters<WhisperContext["searchMemoriesSOTA"]>[0]) => Promise<MemorySearchResponse>;
837
918
  ingestSession: (params: Parameters<WhisperContext["ingestSession"]>[0]) => Promise<{
838
919
  success: boolean;
839
920
  memories_created: number;
840
921
  relations_created: number;
841
922
  memories_invalidated: number;
842
923
  errors?: string[];
843
- }>;
924
+ } & MemoryWriteAck>;
844
925
  getSessionMemories: (params: Parameters<WhisperContext["getSessionMemories"]>[0]) => Promise<{
845
926
  memories: any[];
846
927
  count: number;
@@ -955,4 +1036,4 @@ declare class WhisperContext {
955
1036
  };
956
1037
  }
957
1038
 
958
- export { type ExtractedMemory, type Memory, type MemoryExtractionResult, type MemoryKind, type Project, type QueryParams, type QueryResult, type Source, Whisper, WhisperAgentMiddleware, type WhisperConfig, WhisperContext, Whisper as WhisperDefault, WhisperError, type WhisperErrorCode, createAgentMiddleware, WhisperContext as default, memoryGraphToMermaid };
1039
+ export { type ExtractedMemory, type Memory, type MemoryExtractionResult, type MemoryKind, type MemoryLatencyBreakdown, type MemorySearchResponse, type MemoryWriteAck, type Project, type QueryParams, type QueryResult, type Source, Whisper, WhisperAgentMiddleware, type WhisperConfig, WhisperContext, Whisper as WhisperDefault, WhisperError, type WhisperErrorCode, createAgentMiddleware, WhisperContext as default, memoryGraphToMermaid };
package/index.js CHANGED
@@ -150,7 +150,7 @@ ${context}` : "",
150
150
  if (extractedMemories.length > 0) {
151
151
  const bulk = await this.client.addMemoriesBulk({
152
152
  project: options?.project ?? this.options.project,
153
- async: false,
153
+ write_mode: "async",
154
154
  memories: extractedMemories.map((m) => ({
155
155
  content: m.content,
156
156
  memory_type: m.memoryType,
@@ -218,6 +218,10 @@ ${context}` : "",
218
218
  extracted: result?.memories_created ?? 0
219
219
  };
220
220
  } catch (error) {
221
+ const fallback = await this.fallbackCaptureViaAddMemory(messages, options);
222
+ if (fallback.success) {
223
+ return fallback;
224
+ }
221
225
  console.error("[Whisper] Session capture failed:", error);
222
226
  return { success: false, extracted: 0 };
223
227
  }
@@ -275,6 +279,28 @@ User: ${params.userMessage}` : params.userMessage;
275
279
  }
276
280
  return Array.from(new Set(ids));
277
281
  }
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 };
286
+ }
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 {
300
+ }
301
+ }
302
+ return { success: extracted > 0, extracted };
303
+ }
278
304
  };
279
305
  var whisper_agent_default = Whisper;
280
306
 
@@ -416,6 +442,10 @@ function normalizeEndpoint(endpoint) {
416
442
  }
417
443
  return withLeadingSlash;
418
444
  }
445
+ function isProjectNotFoundMessage(message) {
446
+ const normalized = message.toLowerCase();
447
+ return normalized.includes("project not found") || normalized.includes("no project found") || normalized.includes("project does not exist");
448
+ }
419
449
  var WhisperContext = class _WhisperContext {
420
450
  apiKey;
421
451
  baseUrl;
@@ -522,9 +552,17 @@ var WhisperContext = class _WhisperContext {
522
552
  return Array.from(candidates).filter(Boolean);
523
553
  }
524
554
  async withProjectRefFallback(projectRef, execute) {
555
+ try {
556
+ return await execute(projectRef);
557
+ } catch (error) {
558
+ if (!(error instanceof WhisperError) || error.code !== "PROJECT_NOT_FOUND") {
559
+ throw error;
560
+ }
561
+ }
525
562
  const refs = await this.getProjectRefCandidates(projectRef);
526
563
  let lastError;
527
564
  for (const ref of refs) {
565
+ if (ref === projectRef) continue;
528
566
  try {
529
567
  return await execute(ref);
530
568
  } catch (error) {
@@ -547,7 +585,7 @@ var WhisperContext = class _WhisperContext {
547
585
  if (status === 401 || /api key|unauthorized|forbidden/i.test(message)) {
548
586
  return { code: "INVALID_API_KEY", retryable: false };
549
587
  }
550
- if (status === 404 || /project not found/i.test(message)) {
588
+ if (status === 404 && isProjectNotFoundMessage(message)) {
551
589
  return { code: "PROJECT_NOT_FOUND", retryable: false };
552
590
  }
553
591
  if (status === 408) {
@@ -561,6 +599,16 @@ var WhisperContext = class _WhisperContext {
561
599
  }
562
600
  return { code: "REQUEST_FAILED", retryable: false };
563
601
  }
602
+ isEndpointNotFoundError(error) {
603
+ if (!(error instanceof WhisperError)) {
604
+ return false;
605
+ }
606
+ if (error.status !== 404) {
607
+ return false;
608
+ }
609
+ const message = (error.message || "").toLowerCase();
610
+ return !isProjectNotFoundMessage(message);
611
+ }
564
612
  async request(endpoint, options = {}) {
565
613
  const maxAttempts = Math.max(1, this.retryConfig.maxAttempts);
566
614
  const normalizedEndpoint = normalizeEndpoint(endpoint);
@@ -594,7 +642,11 @@ var WhisperContext = class _WhisperContext {
594
642
  } catch {
595
643
  payload = await response.text().catch(() => "");
596
644
  }
597
- const message = typeof payload === "string" ? payload : payload?.error || payload?.message || `HTTP ${response.status}: ${response.statusText}`;
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
+ }
598
650
  const { code, retryable } = this.classifyError(response.status, message);
599
651
  const err = new WhisperError({
600
652
  code,
@@ -737,13 +789,18 @@ var WhisperContext = class _WhisperContext {
737
789
  session_id: params.session_id,
738
790
  agent_id: params.agent_id,
739
791
  importance: params.importance,
740
- metadata: params.metadata
792
+ metadata: params.metadata,
793
+ async: params.async,
794
+ write_mode: params.write_mode
741
795
  })
742
796
  });
743
- const id2 = direct?.memory?.id || direct?.id || direct?.memory_id;
797
+ const id2 = direct?.memory?.id || direct?.id || direct?.memory_id || direct?.job_id;
744
798
  if (id2) {
745
799
  return { id: id2, success: true, path: "sota", fallback_used: false };
746
800
  }
801
+ if (direct?.success === true) {
802
+ return { id: "", success: true, path: "sota", fallback_used: false };
803
+ }
747
804
  } catch (error) {
748
805
  if (params.allow_legacy_fallback === false) {
749
806
  throw error;
@@ -775,10 +832,40 @@ var WhisperContext = class _WhisperContext {
775
832
  }
776
833
  async addMemoriesBulk(params) {
777
834
  const projectRef = this.getRequiredProject(params.project);
778
- return this.withProjectRefFallback(projectRef, (project) => this.request("/v1/memory/bulk", {
779
- method: "POST",
780
- body: JSON.stringify({ ...params, project })
781
- }));
835
+ return this.withProjectRefFallback(projectRef, async (project) => {
836
+ try {
837
+ return await this.request("/v1/memory/bulk", {
838
+ method: "POST",
839
+ body: JSON.stringify({ ...params, project })
840
+ });
841
+ } catch (error) {
842
+ if (!this.isEndpointNotFoundError(error)) {
843
+ throw error;
844
+ }
845
+ const created = await Promise.all(
846
+ params.memories.map(
847
+ (memory) => this.addMemory({
848
+ project,
849
+ content: memory.content,
850
+ memory_type: memory.memory_type,
851
+ user_id: memory.user_id,
852
+ session_id: memory.session_id,
853
+ agent_id: memory.agent_id,
854
+ importance: memory.importance,
855
+ metadata: memory.metadata,
856
+ allow_legacy_fallback: true
857
+ })
858
+ )
859
+ );
860
+ return {
861
+ success: true,
862
+ created: created.length,
863
+ memories: created,
864
+ path: "legacy",
865
+ fallback_used: true
866
+ };
867
+ }
868
+ });
782
869
  }
783
870
  async extractMemories(params) {
784
871
  const projectRef = this.getRequiredProject(params.project);
@@ -803,17 +890,48 @@ var WhisperContext = class _WhisperContext {
803
890
  }
804
891
  async searchMemories(params) {
805
892
  const projectRef = this.getRequiredProject(params.project);
806
- return this.withProjectRefFallback(projectRef, (project) => this.request("/v1/memory/search", {
807
- method: "POST",
808
- body: JSON.stringify({
809
- query: params.query,
810
- project,
811
- user_id: params.user_id,
812
- session_id: params.session_id,
813
- memory_types: params.memory_type ? [params.memory_type] : void 0,
814
- top_k: params.top_k || 10
815
- })
816
- }));
893
+ return this.withProjectRefFallback(projectRef, async (project) => {
894
+ try {
895
+ return await this.request("/v1/memory/search", {
896
+ method: "POST",
897
+ body: JSON.stringify({
898
+ query: params.query,
899
+ project,
900
+ user_id: params.user_id,
901
+ session_id: params.session_id,
902
+ memory_types: params.memory_type ? [params.memory_type] : void 0,
903
+ top_k: params.top_k || 10,
904
+ profile: params.profile,
905
+ include_pending: params.include_pending
906
+ })
907
+ });
908
+ } catch (error) {
909
+ if (!this.isEndpointNotFoundError(error)) {
910
+ throw error;
911
+ }
912
+ const legacyTypeMap = {
913
+ factual: "factual",
914
+ preference: "semantic",
915
+ event: "episodic",
916
+ relationship: "semantic",
917
+ opinion: "semantic",
918
+ goal: "semantic",
919
+ instruction: "procedural"
920
+ };
921
+ return this.request("/v1/memories/search", {
922
+ method: "POST",
923
+ body: JSON.stringify({
924
+ query: params.query,
925
+ project,
926
+ user_id: params.user_id,
927
+ session_id: params.session_id,
928
+ agent_id: params.agent_id,
929
+ memory_type: params.memory_type ? legacyTypeMap[params.memory_type] : void 0,
930
+ top_k: params.top_k || 10
931
+ })
932
+ });
933
+ }
934
+ });
817
935
  }
818
936
  async createApiKey(params) {
819
937
  return this.request("/v1/keys", {
@@ -829,10 +947,29 @@ var WhisperContext = class _WhisperContext {
829
947
  }
830
948
  async searchMemoriesSOTA(params) {
831
949
  const projectRef = this.getRequiredProject(params.project);
832
- return this.withProjectRefFallback(projectRef, (project) => this.request("/v1/memory/search", {
833
- method: "POST",
834
- body: JSON.stringify({ ...params, project })
835
- }));
950
+ return this.withProjectRefFallback(projectRef, async (project) => {
951
+ try {
952
+ return await this.request("/v1/memory/search", {
953
+ method: "POST",
954
+ body: JSON.stringify({ ...params, project })
955
+ });
956
+ } catch (error) {
957
+ if (!this.isEndpointNotFoundError(error)) {
958
+ throw error;
959
+ }
960
+ const firstType = params.memory_types?.[0];
961
+ return this.searchMemories({
962
+ project,
963
+ query: params.query,
964
+ user_id: params.user_id,
965
+ session_id: params.session_id,
966
+ memory_type: firstType,
967
+ top_k: params.top_k,
968
+ profile: params.profile,
969
+ include_pending: params.include_pending
970
+ });
971
+ }
972
+ });
836
973
  }
837
974
  async ingestSession(params) {
838
975
  const projectRef = this.getRequiredProject(params.project);
@@ -842,33 +979,92 @@ var WhisperContext = class _WhisperContext {
842
979
  }));
843
980
  }
844
981
  async getSessionMemories(params) {
845
- const project = await this.resolveProjectId(this.getRequiredProject(params.project));
846
- const query = new URLSearchParams({
847
- project,
848
- ...params.limit && { limit: params.limit.toString() },
849
- ...params.since_date && { since_date: params.since_date }
982
+ const projectRef = this.getRequiredProject(params.project);
983
+ return this.withProjectRefFallback(projectRef, async (project) => {
984
+ const query = new URLSearchParams({
985
+ project,
986
+ ...params.limit && { limit: params.limit.toString() },
987
+ ...params.since_date && { since_date: params.since_date },
988
+ ...params.include_pending !== void 0 && { include_pending: String(params.include_pending) }
989
+ });
990
+ try {
991
+ return await this.request(`/v1/memory/session/${params.session_id}?${query}`);
992
+ } catch (error) {
993
+ if (!this.isEndpointNotFoundError(error)) {
994
+ throw error;
995
+ }
996
+ return { memories: [], count: 0 };
997
+ }
850
998
  });
851
- return this.request(`/v1/memory/session/${params.session_id}?${query}`);
852
999
  }
853
1000
  async getUserProfile(params) {
854
- const project = await this.resolveProjectId(this.getRequiredProject(params.project));
855
- const query = new URLSearchParams({
856
- project,
857
- ...params.memory_types && { memory_types: params.memory_types }
1001
+ const projectRef = this.getRequiredProject(params.project);
1002
+ return this.withProjectRefFallback(projectRef, async (project) => {
1003
+ const query = new URLSearchParams({
1004
+ project,
1005
+ ...params.memory_types && { memory_types: params.memory_types },
1006
+ ...params.include_pending !== void 0 && { include_pending: String(params.include_pending) }
1007
+ });
1008
+ try {
1009
+ return await this.request(`/v1/memory/profile/${params.user_id}?${query}`);
1010
+ } catch (error) {
1011
+ if (!this.isEndpointNotFoundError(error)) {
1012
+ throw error;
1013
+ }
1014
+ const legacyQuery = new URLSearchParams({
1015
+ project,
1016
+ user_id: params.user_id,
1017
+ limit: "200"
1018
+ });
1019
+ const legacy = await this.request(`/v1/memories?${legacyQuery}`);
1020
+ const memories = Array.isArray(legacy?.memories) ? legacy.memories : [];
1021
+ return {
1022
+ user_id: params.user_id,
1023
+ memories,
1024
+ count: memories.length
1025
+ };
1026
+ }
858
1027
  });
859
- return this.request(`/v1/memory/profile/${params.user_id}?${query}`);
860
1028
  }
861
1029
  async getMemoryVersions(memoryId) {
862
1030
  return this.request(`/v1/memory/${memoryId}/versions`);
863
1031
  }
864
1032
  async updateMemory(memoryId, params) {
865
- return this.request(`/v1/memory/${memoryId}`, {
866
- method: "PUT",
867
- body: JSON.stringify(params)
868
- });
1033
+ try {
1034
+ return await this.request(`/v1/memory/${memoryId}`, {
1035
+ method: "PUT",
1036
+ body: JSON.stringify(params)
1037
+ });
1038
+ } catch (error) {
1039
+ if (!this.isEndpointNotFoundError(error)) {
1040
+ throw error;
1041
+ }
1042
+ const legacy = await this.request(`/v1/memories/${memoryId}`, {
1043
+ method: "PUT",
1044
+ body: JSON.stringify({
1045
+ content: params.content
1046
+ })
1047
+ });
1048
+ return {
1049
+ success: true,
1050
+ new_memory_id: legacy?.id || memoryId,
1051
+ old_memory_id: memoryId
1052
+ };
1053
+ }
869
1054
  }
870
1055
  async deleteMemory(memoryId) {
871
- return this.request(`/v1/memory/${memoryId}`, { method: "DELETE" });
1056
+ try {
1057
+ return await this.request(`/v1/memory/${memoryId}`, { method: "DELETE" });
1058
+ } catch (error) {
1059
+ if (!this.isEndpointNotFoundError(error)) {
1060
+ throw error;
1061
+ }
1062
+ await this.request(`/v1/memories/${memoryId}`, { method: "DELETE" });
1063
+ return {
1064
+ success: true,
1065
+ deleted: memoryId
1066
+ };
1067
+ }
872
1068
  }
873
1069
  async getMemoryRelations(memoryId) {
874
1070
  return this.request(`/v1/memory/${memoryId}/relations`);
package/index.mjs CHANGED
@@ -117,7 +117,7 @@ ${context}` : "",
117
117
  if (extractedMemories.length > 0) {
118
118
  const bulk = await this.client.addMemoriesBulk({
119
119
  project: options?.project ?? this.options.project,
120
- async: false,
120
+ write_mode: "async",
121
121
  memories: extractedMemories.map((m) => ({
122
122
  content: m.content,
123
123
  memory_type: m.memoryType,
@@ -185,6 +185,10 @@ ${context}` : "",
185
185
  extracted: result?.memories_created ?? 0
186
186
  };
187
187
  } catch (error) {
188
+ const fallback = await this.fallbackCaptureViaAddMemory(messages, options);
189
+ if (fallback.success) {
190
+ return fallback;
191
+ }
188
192
  console.error("[Whisper] Session capture failed:", error);
189
193
  return { success: false, extracted: 0 };
190
194
  }
@@ -242,6 +246,28 @@ User: ${params.userMessage}` : params.userMessage;
242
246
  }
243
247
  return Array.from(new Set(ids));
244
248
  }
249
+ async fallbackCaptureViaAddMemory(messages, options) {
250
+ const userMessages = messages.filter((m) => m.role === "user").map((m) => (m.content || "").trim()).filter((content) => content.length >= 5).slice(-2);
251
+ if (userMessages.length === 0) {
252
+ return { success: false, extracted: 0 };
253
+ }
254
+ let extracted = 0;
255
+ for (const content of userMessages) {
256
+ try {
257
+ await this.client.addMemory({
258
+ project: options?.project ?? this.options.project,
259
+ content,
260
+ memory_type: "factual",
261
+ user_id: options?.userId ?? this.userId,
262
+ session_id: options?.sessionId ?? this.sessionId,
263
+ allow_legacy_fallback: true
264
+ });
265
+ extracted += 1;
266
+ } catch {
267
+ }
268
+ }
269
+ return { success: extracted > 0, extracted };
270
+ }
245
271
  };
246
272
  var whisper_agent_default = Whisper;
247
273
 
@@ -383,6 +409,10 @@ function normalizeEndpoint(endpoint) {
383
409
  }
384
410
  return withLeadingSlash;
385
411
  }
412
+ function isProjectNotFoundMessage(message) {
413
+ const normalized = message.toLowerCase();
414
+ return normalized.includes("project not found") || normalized.includes("no project found") || normalized.includes("project does not exist");
415
+ }
386
416
  var WhisperContext = class _WhisperContext {
387
417
  apiKey;
388
418
  baseUrl;
@@ -489,9 +519,17 @@ var WhisperContext = class _WhisperContext {
489
519
  return Array.from(candidates).filter(Boolean);
490
520
  }
491
521
  async withProjectRefFallback(projectRef, execute) {
522
+ try {
523
+ return await execute(projectRef);
524
+ } catch (error) {
525
+ if (!(error instanceof WhisperError) || error.code !== "PROJECT_NOT_FOUND") {
526
+ throw error;
527
+ }
528
+ }
492
529
  const refs = await this.getProjectRefCandidates(projectRef);
493
530
  let lastError;
494
531
  for (const ref of refs) {
532
+ if (ref === projectRef) continue;
495
533
  try {
496
534
  return await execute(ref);
497
535
  } catch (error) {
@@ -514,7 +552,7 @@ var WhisperContext = class _WhisperContext {
514
552
  if (status === 401 || /api key|unauthorized|forbidden/i.test(message)) {
515
553
  return { code: "INVALID_API_KEY", retryable: false };
516
554
  }
517
- if (status === 404 || /project not found/i.test(message)) {
555
+ if (status === 404 && isProjectNotFoundMessage(message)) {
518
556
  return { code: "PROJECT_NOT_FOUND", retryable: false };
519
557
  }
520
558
  if (status === 408) {
@@ -528,6 +566,16 @@ var WhisperContext = class _WhisperContext {
528
566
  }
529
567
  return { code: "REQUEST_FAILED", retryable: false };
530
568
  }
569
+ isEndpointNotFoundError(error) {
570
+ if (!(error instanceof WhisperError)) {
571
+ return false;
572
+ }
573
+ if (error.status !== 404) {
574
+ return false;
575
+ }
576
+ const message = (error.message || "").toLowerCase();
577
+ return !isProjectNotFoundMessage(message);
578
+ }
531
579
  async request(endpoint, options = {}) {
532
580
  const maxAttempts = Math.max(1, this.retryConfig.maxAttempts);
533
581
  const normalizedEndpoint = normalizeEndpoint(endpoint);
@@ -561,7 +609,11 @@ var WhisperContext = class _WhisperContext {
561
609
  } catch {
562
610
  payload = await response.text().catch(() => "");
563
611
  }
564
- const message = typeof payload === "string" ? payload : payload?.error || payload?.message || `HTTP ${response.status}: ${response.statusText}`;
612
+ let message = typeof payload === "string" ? payload : payload?.error || payload?.message || `HTTP ${response.status}: ${response.statusText}`;
613
+ if (response.status === 404 && !isProjectNotFoundMessage(message)) {
614
+ const endpointHint = `${this.baseUrl}${normalizedEndpoint}`;
615
+ message = `Endpoint not found at ${endpointHint}. This deployment may not support this API route.`;
616
+ }
565
617
  const { code, retryable } = this.classifyError(response.status, message);
566
618
  const err = new WhisperError({
567
619
  code,
@@ -704,13 +756,18 @@ var WhisperContext = class _WhisperContext {
704
756
  session_id: params.session_id,
705
757
  agent_id: params.agent_id,
706
758
  importance: params.importance,
707
- metadata: params.metadata
759
+ metadata: params.metadata,
760
+ async: params.async,
761
+ write_mode: params.write_mode
708
762
  })
709
763
  });
710
- const id2 = direct?.memory?.id || direct?.id || direct?.memory_id;
764
+ const id2 = direct?.memory?.id || direct?.id || direct?.memory_id || direct?.job_id;
711
765
  if (id2) {
712
766
  return { id: id2, success: true, path: "sota", fallback_used: false };
713
767
  }
768
+ if (direct?.success === true) {
769
+ return { id: "", success: true, path: "sota", fallback_used: false };
770
+ }
714
771
  } catch (error) {
715
772
  if (params.allow_legacy_fallback === false) {
716
773
  throw error;
@@ -742,10 +799,40 @@ var WhisperContext = class _WhisperContext {
742
799
  }
743
800
  async addMemoriesBulk(params) {
744
801
  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
- }));
802
+ return this.withProjectRefFallback(projectRef, async (project) => {
803
+ try {
804
+ return await this.request("/v1/memory/bulk", {
805
+ method: "POST",
806
+ body: JSON.stringify({ ...params, project })
807
+ });
808
+ } catch (error) {
809
+ if (!this.isEndpointNotFoundError(error)) {
810
+ throw error;
811
+ }
812
+ const created = await Promise.all(
813
+ params.memories.map(
814
+ (memory) => this.addMemory({
815
+ project,
816
+ content: memory.content,
817
+ memory_type: memory.memory_type,
818
+ user_id: memory.user_id,
819
+ session_id: memory.session_id,
820
+ agent_id: memory.agent_id,
821
+ importance: memory.importance,
822
+ metadata: memory.metadata,
823
+ allow_legacy_fallback: true
824
+ })
825
+ )
826
+ );
827
+ return {
828
+ success: true,
829
+ created: created.length,
830
+ memories: created,
831
+ path: "legacy",
832
+ fallback_used: true
833
+ };
834
+ }
835
+ });
749
836
  }
750
837
  async extractMemories(params) {
751
838
  const projectRef = this.getRequiredProject(params.project);
@@ -770,17 +857,48 @@ var WhisperContext = class _WhisperContext {
770
857
  }
771
858
  async searchMemories(params) {
772
859
  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
- }));
860
+ return this.withProjectRefFallback(projectRef, async (project) => {
861
+ try {
862
+ return await this.request("/v1/memory/search", {
863
+ method: "POST",
864
+ body: JSON.stringify({
865
+ query: params.query,
866
+ project,
867
+ user_id: params.user_id,
868
+ session_id: params.session_id,
869
+ memory_types: params.memory_type ? [params.memory_type] : void 0,
870
+ top_k: params.top_k || 10,
871
+ profile: params.profile,
872
+ include_pending: params.include_pending
873
+ })
874
+ });
875
+ } catch (error) {
876
+ if (!this.isEndpointNotFoundError(error)) {
877
+ throw error;
878
+ }
879
+ const legacyTypeMap = {
880
+ factual: "factual",
881
+ preference: "semantic",
882
+ event: "episodic",
883
+ relationship: "semantic",
884
+ opinion: "semantic",
885
+ goal: "semantic",
886
+ instruction: "procedural"
887
+ };
888
+ return this.request("/v1/memories/search", {
889
+ method: "POST",
890
+ body: JSON.stringify({
891
+ query: params.query,
892
+ project,
893
+ user_id: params.user_id,
894
+ session_id: params.session_id,
895
+ agent_id: params.agent_id,
896
+ memory_type: params.memory_type ? legacyTypeMap[params.memory_type] : void 0,
897
+ top_k: params.top_k || 10
898
+ })
899
+ });
900
+ }
901
+ });
784
902
  }
785
903
  async createApiKey(params) {
786
904
  return this.request("/v1/keys", {
@@ -796,10 +914,29 @@ var WhisperContext = class _WhisperContext {
796
914
  }
797
915
  async searchMemoriesSOTA(params) {
798
916
  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
- }));
917
+ return this.withProjectRefFallback(projectRef, async (project) => {
918
+ try {
919
+ return await this.request("/v1/memory/search", {
920
+ method: "POST",
921
+ body: JSON.stringify({ ...params, project })
922
+ });
923
+ } catch (error) {
924
+ if (!this.isEndpointNotFoundError(error)) {
925
+ throw error;
926
+ }
927
+ const firstType = params.memory_types?.[0];
928
+ return this.searchMemories({
929
+ project,
930
+ query: params.query,
931
+ user_id: params.user_id,
932
+ session_id: params.session_id,
933
+ memory_type: firstType,
934
+ top_k: params.top_k,
935
+ profile: params.profile,
936
+ include_pending: params.include_pending
937
+ });
938
+ }
939
+ });
803
940
  }
804
941
  async ingestSession(params) {
805
942
  const projectRef = this.getRequiredProject(params.project);
@@ -809,33 +946,92 @@ var WhisperContext = class _WhisperContext {
809
946
  }));
810
947
  }
811
948
  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 }
949
+ const projectRef = this.getRequiredProject(params.project);
950
+ return this.withProjectRefFallback(projectRef, async (project) => {
951
+ const query = new URLSearchParams({
952
+ project,
953
+ ...params.limit && { limit: params.limit.toString() },
954
+ ...params.since_date && { since_date: params.since_date },
955
+ ...params.include_pending !== void 0 && { include_pending: String(params.include_pending) }
956
+ });
957
+ try {
958
+ return await this.request(`/v1/memory/session/${params.session_id}?${query}`);
959
+ } catch (error) {
960
+ if (!this.isEndpointNotFoundError(error)) {
961
+ throw error;
962
+ }
963
+ return { memories: [], count: 0 };
964
+ }
817
965
  });
818
- return this.request(`/v1/memory/session/${params.session_id}?${query}`);
819
966
  }
820
967
  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 }
968
+ const projectRef = this.getRequiredProject(params.project);
969
+ return this.withProjectRefFallback(projectRef, async (project) => {
970
+ const query = new URLSearchParams({
971
+ project,
972
+ ...params.memory_types && { memory_types: params.memory_types },
973
+ ...params.include_pending !== void 0 && { include_pending: String(params.include_pending) }
974
+ });
975
+ try {
976
+ return await this.request(`/v1/memory/profile/${params.user_id}?${query}`);
977
+ } catch (error) {
978
+ if (!this.isEndpointNotFoundError(error)) {
979
+ throw error;
980
+ }
981
+ const legacyQuery = new URLSearchParams({
982
+ project,
983
+ user_id: params.user_id,
984
+ limit: "200"
985
+ });
986
+ const legacy = await this.request(`/v1/memories?${legacyQuery}`);
987
+ const memories = Array.isArray(legacy?.memories) ? legacy.memories : [];
988
+ return {
989
+ user_id: params.user_id,
990
+ memories,
991
+ count: memories.length
992
+ };
993
+ }
825
994
  });
826
- return this.request(`/v1/memory/profile/${params.user_id}?${query}`);
827
995
  }
828
996
  async getMemoryVersions(memoryId) {
829
997
  return this.request(`/v1/memory/${memoryId}/versions`);
830
998
  }
831
999
  async updateMemory(memoryId, params) {
832
- return this.request(`/v1/memory/${memoryId}`, {
833
- method: "PUT",
834
- body: JSON.stringify(params)
835
- });
1000
+ try {
1001
+ return await this.request(`/v1/memory/${memoryId}`, {
1002
+ method: "PUT",
1003
+ body: JSON.stringify(params)
1004
+ });
1005
+ } catch (error) {
1006
+ if (!this.isEndpointNotFoundError(error)) {
1007
+ throw error;
1008
+ }
1009
+ const legacy = await this.request(`/v1/memories/${memoryId}`, {
1010
+ method: "PUT",
1011
+ body: JSON.stringify({
1012
+ content: params.content
1013
+ })
1014
+ });
1015
+ return {
1016
+ success: true,
1017
+ new_memory_id: legacy?.id || memoryId,
1018
+ old_memory_id: memoryId
1019
+ };
1020
+ }
836
1021
  }
837
1022
  async deleteMemory(memoryId) {
838
- return this.request(`/v1/memory/${memoryId}`, { method: "DELETE" });
1023
+ try {
1024
+ return await this.request(`/v1/memory/${memoryId}`, { method: "DELETE" });
1025
+ } catch (error) {
1026
+ if (!this.isEndpointNotFoundError(error)) {
1027
+ throw error;
1028
+ }
1029
+ await this.request(`/v1/memories/${memoryId}`, { method: "DELETE" });
1030
+ return {
1031
+ success: true,
1032
+ deleted: memoryId
1033
+ };
1034
+ }
839
1035
  }
840
1036
  async getMemoryRelations(memoryId) {
841
1037
  return this.request(`/v1/memory/${memoryId}/relations`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@usewhisper/sdk",
3
- "version": "2.2.0",
3
+ "version": "2.2.1",
4
4
  "scripts": {
5
5
  "build": "tsup ../src/sdk/index.ts --format esm,cjs --dts --out-dir .",
6
6
  "prepublishOnly": "npm run build"