@usewhisper/sdk 2.1.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.
Files changed (5) hide show
  1. package/index.d.mts +124 -7
  2. package/index.d.ts +124 -7
  3. package/index.js +287 -42
  4. package/index.mjs +285 -41
  5. package/package.json +1 -1
package/index.js CHANGED
@@ -26,7 +26,8 @@ __export(index_exports, {
26
26
  WhisperDefault: () => whisper_agent_default,
27
27
  WhisperError: () => WhisperError,
28
28
  createAgentMiddleware: () => createAgentMiddleware,
29
- default: () => index_default
29
+ default: () => index_default,
30
+ memoryGraphToMermaid: () => memoryGraphToMermaid
30
31
  });
31
32
  module.exports = __toCommonJS(index_exports);
32
33
 
@@ -149,7 +150,7 @@ ${context}` : "",
149
150
  if (extractedMemories.length > 0) {
150
151
  const bulk = await this.client.addMemoriesBulk({
151
152
  project: options?.project ?? this.options.project,
152
- async: false,
153
+ write_mode: "async",
153
154
  memories: extractedMemories.map((m) => ({
154
155
  content: m.content,
155
156
  memory_type: m.memoryType,
@@ -217,6 +218,10 @@ ${context}` : "",
217
218
  extracted: result?.memories_created ?? 0
218
219
  };
219
220
  } catch (error) {
221
+ const fallback = await this.fallbackCaptureViaAddMemory(messages, options);
222
+ if (fallback.success) {
223
+ return fallback;
224
+ }
220
225
  console.error("[Whisper] Session capture failed:", error);
221
226
  return { success: false, extracted: 0 };
222
227
  }
@@ -274,6 +279,28 @@ User: ${params.userMessage}` : params.userMessage;
274
279
  }
275
280
  return Array.from(new Set(ids));
276
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
+ }
277
304
  };
278
305
  var whisper_agent_default = Whisper;
279
306
 
@@ -346,6 +373,31 @@ function createAgentMiddleware(config) {
346
373
  return new WhisperAgentMiddleware(config);
347
374
  }
348
375
 
376
+ // ../src/sdk/graph-utils.ts
377
+ function sanitizeId(id) {
378
+ return `n_${id.replace(/[^a-zA-Z0-9_]/g, "_")}`;
379
+ }
380
+ function shortLabel(input, max = 48) {
381
+ const text = (input || "").replace(/\s+/g, " ").trim();
382
+ if (text.length <= max) return text;
383
+ return `${text.slice(0, max - 3)}...`;
384
+ }
385
+ function memoryGraphToMermaid(graph) {
386
+ const lines = ["flowchart LR"];
387
+ for (const node of graph.nodes || []) {
388
+ const sid = sanitizeId(node.id);
389
+ const label = shortLabel(node.label || node.id);
390
+ lines.push(` ${sid}["${label.replace(/"/g, '\\"')}"]`);
391
+ }
392
+ for (const edge of graph.edges || []) {
393
+ const s = sanitizeId(edge.source);
394
+ const t = sanitizeId(edge.target);
395
+ const rel = shortLabel(edge.type || "rel", 18).replace(/"/g, '\\"');
396
+ lines.push(` ${s} -->|${rel}| ${t}`);
397
+ }
398
+ return lines.join("\n");
399
+ }
400
+
349
401
  // ../src/sdk/index.ts
350
402
  var WhisperError = class extends Error {
351
403
  code;
@@ -390,6 +442,10 @@ function normalizeEndpoint(endpoint) {
390
442
  }
391
443
  return withLeadingSlash;
392
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
+ }
393
449
  var WhisperContext = class _WhisperContext {
394
450
  apiKey;
395
451
  baseUrl;
@@ -496,9 +552,17 @@ var WhisperContext = class _WhisperContext {
496
552
  return Array.from(candidates).filter(Boolean);
497
553
  }
498
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
+ }
499
562
  const refs = await this.getProjectRefCandidates(projectRef);
500
563
  let lastError;
501
564
  for (const ref of refs) {
565
+ if (ref === projectRef) continue;
502
566
  try {
503
567
  return await execute(ref);
504
568
  } catch (error) {
@@ -521,7 +585,7 @@ var WhisperContext = class _WhisperContext {
521
585
  if (status === 401 || /api key|unauthorized|forbidden/i.test(message)) {
522
586
  return { code: "INVALID_API_KEY", retryable: false };
523
587
  }
524
- if (status === 404 || /project not found/i.test(message)) {
588
+ if (status === 404 && isProjectNotFoundMessage(message)) {
525
589
  return { code: "PROJECT_NOT_FOUND", retryable: false };
526
590
  }
527
591
  if (status === 408) {
@@ -535,6 +599,16 @@ var WhisperContext = class _WhisperContext {
535
599
  }
536
600
  return { code: "REQUEST_FAILED", retryable: false };
537
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
+ }
538
612
  async request(endpoint, options = {}) {
539
613
  const maxAttempts = Math.max(1, this.retryConfig.maxAttempts);
540
614
  const normalizedEndpoint = normalizeEndpoint(endpoint);
@@ -568,7 +642,11 @@ var WhisperContext = class _WhisperContext {
568
642
  } catch {
569
643
  payload = await response.text().catch(() => "");
570
644
  }
571
- 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
+ }
572
650
  const { code, retryable } = this.classifyError(response.status, message);
573
651
  const err = new WhisperError({
574
652
  code,
@@ -711,13 +789,18 @@ var WhisperContext = class _WhisperContext {
711
789
  session_id: params.session_id,
712
790
  agent_id: params.agent_id,
713
791
  importance: params.importance,
714
- metadata: params.metadata
792
+ metadata: params.metadata,
793
+ async: params.async,
794
+ write_mode: params.write_mode
715
795
  })
716
796
  });
717
- const id2 = direct?.memory?.id || direct?.id || direct?.memory_id;
797
+ const id2 = direct?.memory?.id || direct?.id || direct?.memory_id || direct?.job_id;
718
798
  if (id2) {
719
799
  return { id: id2, success: true, path: "sota", fallback_used: false };
720
800
  }
801
+ if (direct?.success === true) {
802
+ return { id: "", success: true, path: "sota", fallback_used: false };
803
+ }
721
804
  } catch (error) {
722
805
  if (params.allow_legacy_fallback === false) {
723
806
  throw error;
@@ -749,10 +832,40 @@ var WhisperContext = class _WhisperContext {
749
832
  }
750
833
  async addMemoriesBulk(params) {
751
834
  const projectRef = this.getRequiredProject(params.project);
752
- return this.withProjectRefFallback(projectRef, (project) => this.request("/v1/memory/bulk", {
753
- method: "POST",
754
- body: JSON.stringify({ ...params, project })
755
- }));
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
+ });
756
869
  }
757
870
  async extractMemories(params) {
758
871
  const projectRef = this.getRequiredProject(params.project);
@@ -777,17 +890,48 @@ var WhisperContext = class _WhisperContext {
777
890
  }
778
891
  async searchMemories(params) {
779
892
  const projectRef = this.getRequiredProject(params.project);
780
- return this.withProjectRefFallback(projectRef, (project) => this.request("/v1/memory/search", {
781
- method: "POST",
782
- body: JSON.stringify({
783
- query: params.query,
784
- project,
785
- user_id: params.user_id,
786
- session_id: params.session_id,
787
- memory_types: params.memory_type ? [params.memory_type] : void 0,
788
- top_k: params.top_k || 10
789
- })
790
- }));
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
+ });
791
935
  }
792
936
  async createApiKey(params) {
793
937
  return this.request("/v1/keys", {
@@ -803,10 +947,29 @@ var WhisperContext = class _WhisperContext {
803
947
  }
804
948
  async searchMemoriesSOTA(params) {
805
949
  const projectRef = this.getRequiredProject(params.project);
806
- return this.withProjectRefFallback(projectRef, (project) => this.request("/v1/memory/search", {
807
- method: "POST",
808
- body: JSON.stringify({ ...params, project })
809
- }));
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
+ });
810
973
  }
811
974
  async ingestSession(params) {
812
975
  const projectRef = this.getRequiredProject(params.project);
@@ -816,37 +979,116 @@ var WhisperContext = class _WhisperContext {
816
979
  }));
817
980
  }
818
981
  async getSessionMemories(params) {
819
- const project = await this.resolveProjectId(this.getRequiredProject(params.project));
820
- const query = new URLSearchParams({
821
- project,
822
- ...params.limit && { limit: params.limit.toString() },
823
- ...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
+ }
824
998
  });
825
- return this.request(`/v1/memory/session/${params.session_id}?${query}`);
826
999
  }
827
1000
  async getUserProfile(params) {
828
- const project = await this.resolveProjectId(this.getRequiredProject(params.project));
829
- const query = new URLSearchParams({
830
- project,
831
- ...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
+ }
832
1027
  });
833
- return this.request(`/v1/memory/profile/${params.user_id}?${query}`);
834
1028
  }
835
1029
  async getMemoryVersions(memoryId) {
836
1030
  return this.request(`/v1/memory/${memoryId}/versions`);
837
1031
  }
838
1032
  async updateMemory(memoryId, params) {
839
- return this.request(`/v1/memory/${memoryId}`, {
840
- method: "PUT",
841
- body: JSON.stringify(params)
842
- });
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
+ }
843
1054
  }
844
1055
  async deleteMemory(memoryId) {
845
- 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
+ }
846
1068
  }
847
1069
  async getMemoryRelations(memoryId) {
848
1070
  return this.request(`/v1/memory/${memoryId}/relations`);
849
1071
  }
1072
+ async getMemoryGraph(params) {
1073
+ const project = await this.resolveProjectId(this.getRequiredProject(params.project));
1074
+ const query = new URLSearchParams({
1075
+ project,
1076
+ ...params.user_id && { user_id: params.user_id },
1077
+ ...params.session_id && { session_id: params.session_id },
1078
+ ...params.include_inactive !== void 0 && { include_inactive: String(params.include_inactive) },
1079
+ ...params.limit !== void 0 && { limit: String(params.limit) }
1080
+ });
1081
+ return this.request(`/v1/memory/graph?${query}`);
1082
+ }
1083
+ async getConversationGraph(params) {
1084
+ const project = await this.resolveProjectId(this.getRequiredProject(params.project));
1085
+ const query = new URLSearchParams({
1086
+ project,
1087
+ ...params.include_inactive !== void 0 && { include_inactive: String(params.include_inactive) },
1088
+ ...params.limit !== void 0 && { limit: String(params.limit) }
1089
+ });
1090
+ return this.request(`/v1/memory/graph/conversation/${params.session_id}?${query}`);
1091
+ }
850
1092
  async oracleSearch(params) {
851
1093
  const project = await this.resolveProjectId(this.getRequiredProject(params.project));
852
1094
  return this.request("/v1/oracle/search", {
@@ -983,6 +1225,8 @@ var WhisperContext = class _WhisperContext {
983
1225
  update: (memoryId, params) => this.updateMemory(memoryId, params),
984
1226
  delete: (memoryId) => this.deleteMemory(memoryId),
985
1227
  getRelations: (memoryId) => this.getMemoryRelations(memoryId),
1228
+ getGraph: (params) => this.getMemoryGraph(params),
1229
+ getConversationGraph: (params) => this.getConversationGraph(params),
986
1230
  consolidate: (params) => this.consolidateMemories(params),
987
1231
  updateDecay: (params) => this.updateImportanceDecay(params),
988
1232
  getImportanceStats: (project) => this.getImportanceStats(project)
@@ -1017,5 +1261,6 @@ var index_default = WhisperContext;
1017
1261
  WhisperContext,
1018
1262
  WhisperDefault,
1019
1263
  WhisperError,
1020
- createAgentMiddleware
1264
+ createAgentMiddleware,
1265
+ memoryGraphToMermaid
1021
1266
  });