@maximem/synap-js-sdk 0.5.2 → 0.5.6

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/dist/index.js CHANGED
@@ -49,6 +49,7 @@ var ENDPOINTS = {
49
49
  memories_get: { method: "GET", path: "/api/v1/memories/{memory_id}", idempotent: true },
50
50
  memories_update: { method: "PATCH", path: "/api/v1/memories/{memory_id}", idempotent: false },
51
51
  memories_delete: { method: "DELETE", path: "/api/v1/memories/{memory_id}", idempotent: true },
52
+ memories_forget: { method: "POST", path: "/api/v1/memories/forget", idempotent: false },
52
53
  context_fetch_user: { method: "POST", path: "/v1/context/user/fetch", idempotent: true },
53
54
  context_fetch_customer: { method: "POST", path: "/v1/context/customer/fetch", idempotent: true },
54
55
  context_fetch_client: { method: "POST", path: "/v1/context/client/fetch", idempotent: true },
@@ -536,6 +537,8 @@ function buildFetchRequest(scope, options) {
536
537
  const searchQuery = opt(options, "search_query", "searchQuery");
537
538
  const maxResults = opt(options, "max_results", "maxResults") ?? 10;
538
539
  const precisionLevel = opt(options, "precision_level", "precisionLevel") ?? "high";
540
+ const queryDate = opt(options, "query_date", "queryDate");
541
+ const perQuery = opt(options, "max_results_per_query", "maxResultsPerQuery");
539
542
  const mode = options.mode ?? "fast";
540
543
  if (searchQuery !== void 0 && !Array.isArray(searchQuery)) {
541
544
  throw new InvalidInputError("search_query must be an array when provided");
@@ -551,6 +554,8 @@ function buildFetchRequest(scope, options) {
551
554
  mode
552
555
  };
553
556
  if (precisionLevel !== "high") body["precision_level"] = precisionLevel;
557
+ if (queryDate) body["query_date"] = queryDate;
558
+ if (perQuery) body["max_results_per_query"] = perQuery;
554
559
  if (options.include_conversation_context === false) {
555
560
  body["include_conversation_context"] = false;
556
561
  }
@@ -626,6 +631,10 @@ function pick(...values) {
626
631
  return pickDefined(...values);
627
632
  }
628
633
  var obj = (v) => v ?? {};
634
+ function matchedQueries(item = {}) {
635
+ const raw = item["matchedQueries"] ?? item.matched_queries;
636
+ return Array.isArray(raw) ? raw : [];
637
+ }
629
638
  function normalizeTemporalFields(item = {}) {
630
639
  return {
631
640
  eventDate: pick(item["eventDate"], item.event_date, null),
@@ -642,7 +651,8 @@ function normalizeFact(item = {}) {
642
651
  source: item.source || "",
643
652
  extractedAt: pick(item["extractedAt"], item.extracted_at, null),
644
653
  metadata: obj(item.metadata),
645
- ...normalizeTemporalFields(item)
654
+ ...normalizeTemporalFields(item),
655
+ matchedQueries: matchedQueries(item)
646
656
  };
647
657
  }
648
658
  function normalizePreference(item = {}) {
@@ -654,7 +664,8 @@ function normalizePreference(item = {}) {
654
664
  source: item.source || "",
655
665
  extractedAt: pick(item["extractedAt"], item.extracted_at, null),
656
666
  metadata: obj(item.metadata),
657
- ...normalizeTemporalFields(item)
667
+ ...normalizeTemporalFields(item),
668
+ matchedQueries: matchedQueries(item)
658
669
  };
659
670
  }
660
671
  function normalizeEpisode(item = {}) {
@@ -665,7 +676,8 @@ function normalizeEpisode(item = {}) {
665
676
  significance: pick(item["significance"], item.confidence, 0),
666
677
  participants: item["participants"] || [],
667
678
  metadata: obj(item.metadata),
668
- ...normalizeTemporalFields(item)
679
+ ...normalizeTemporalFields(item),
680
+ matchedQueries: matchedQueries(item)
669
681
  };
670
682
  }
671
683
  function normalizeEmotion(item = {}) {
@@ -676,7 +688,8 @@ function normalizeEmotion(item = {}) {
676
688
  detectedAt: pick(item["detectedAt"], item["detected_at"], null),
677
689
  context: item["context"] || "",
678
690
  metadata: obj(item.metadata),
679
- ...normalizeTemporalFields(item)
691
+ ...normalizeTemporalFields(item),
692
+ matchedQueries: matchedQueries(item)
680
693
  };
681
694
  }
682
695
  function normalizeTemporalEvent(item = {}) {
@@ -690,7 +703,8 @@ function normalizeTemporalEvent(item = {}) {
690
703
  confidence: pick(item.confidence, 0),
691
704
  source: item.source || "",
692
705
  extractedAt: pick(item["extractedAt"], item.extracted_at, null),
693
- metadata: obj(item.metadata)
706
+ metadata: obj(item.metadata),
707
+ matchedQueries: matchedQueries(item)
694
708
  };
695
709
  }
696
710
  function normalizeContextMetadata(metadata = {}) {
@@ -864,8 +878,33 @@ function buildCreateBody(options) {
864
878
  metadata: options.metadata ?? {}
865
879
  };
866
880
  }
881
+ var FORGET_MODES = ["preview", "direct"];
882
+ var FORGET_DESCRIPTION_MIN = 3;
883
+ var FORGET_DESCRIPTION_MAX = 500;
884
+ function buildForgetBody(options) {
885
+ const description = options.description;
886
+ if (typeof description !== "string" || description.length < FORGET_DESCRIPTION_MIN || description.length > FORGET_DESCRIPTION_MAX) {
887
+ throw new InvalidInputError(
888
+ `description must be between ${FORGET_DESCRIPTION_MIN} and ${FORGET_DESCRIPTION_MAX} characters`
889
+ );
890
+ }
891
+ const mode = options.mode ?? "preview";
892
+ if (!FORGET_MODES.includes(mode)) {
893
+ throw new InvalidInputError(
894
+ `Invalid mode '${mode}'. Expected one of: ${FORGET_MODES.join(", ")}`
895
+ );
896
+ }
897
+ const o2 = options;
898
+ return {
899
+ description,
900
+ user_id: either(o2, "user_id", "userId") ?? null,
901
+ customer_id: either(o2, "customer_id", "customerId") ?? null,
902
+ scope: options.scope ?? null,
903
+ mode
904
+ };
905
+ }
867
906
  var TERMINAL_STATUSES = /* @__PURE__ */ new Set(["completed", "failed", "error", "cancelled"]);
868
- function createMemoriesInterface(transport) {
907
+ function createMemoriesInterface(transport, onForgotten) {
869
908
  return {
870
909
  async create(options) {
871
910
  const o2 = options;
@@ -951,6 +990,23 @@ function createMemoriesInterface(transport) {
951
990
  }
952
991
  return transport.request("memories_delete", { pathParams: { memory_id: memoryId } });
953
992
  },
993
+ async forget(options) {
994
+ const o2 = options;
995
+ transport.checkCustomerId(o2["customer_id"] ?? o2["customerId"], "memories.forget");
996
+ const body = buildForgetBody(options);
997
+ const result = await transport.request("memories_forget", { body });
998
+ const removed = !!result?.deleted_ids?.length || result?.status === "deleted" || result?.status === "partial";
999
+ if (removed && onForgotten) {
1000
+ try {
1001
+ onForgotten({
1002
+ userId: body["user_id"] ?? null,
1003
+ customerId: body["customer_id"] ?? null
1004
+ });
1005
+ } catch {
1006
+ }
1007
+ }
1008
+ return result;
1009
+ },
954
1010
  async status(ingestionId) {
955
1011
  if (!ingestionId) throw new InvalidInputError("ingestion_id is required");
956
1012
  return transport.request("memories_status", {
@@ -1391,7 +1447,22 @@ var KNOWN_EVENT_TYPES = /* @__PURE__ */ new Set([
1391
1447
  ]);
1392
1448
  function toolResultJson(result) {
1393
1449
  if (result === void 0 || result === null) return "";
1394
- return typeof result === "string" ? result : JSON.stringify(result);
1450
+ return typeof result === "string" ? result : jsonOrText(result);
1451
+ }
1452
+ function jsonOrText(value) {
1453
+ try {
1454
+ const out = JSON.stringify(
1455
+ value,
1456
+ (_k, v) => typeof v === "bigint" ? String(v) : v
1457
+ );
1458
+ return out === void 0 ? String(value) : out;
1459
+ } catch {
1460
+ try {
1461
+ return String(value);
1462
+ } catch {
1463
+ return "";
1464
+ }
1465
+ }
1395
1466
  }
1396
1467
  function createInstanceNamespace(credentials, cache, onTurn) {
1397
1468
  let client = null;
@@ -1440,7 +1511,7 @@ function createInstanceNamespace(credentials, cache, onTurn) {
1440
1511
  if (client !== null) {
1441
1512
  throw new ListeningAlreadyActiveError("Listening is already active on this instance");
1442
1513
  }
1443
- const { GrpcStreamClient } = await import("./stream-client-5CGJNTH4.js");
1514
+ const { GrpcStreamClient } = await import("./stream-client-Y5NFAMIH.js");
1444
1515
  const onContext = options.on_context ?? options.onContext;
1445
1516
  const onDisconnect = options.on_disconnect ?? options.onDisconnect;
1446
1517
  const onReconnect = options.on_reconnect ?? options.onReconnect;
@@ -1538,7 +1609,7 @@ function createInstanceNamespace(credentials, cache, onTurn) {
1538
1609
  // Python serialises tool_args with json.dumps into tool_args_json.
1539
1610
  tool_args_json: (() => {
1540
1611
  const a = options.tool_args ?? options.toolArgs;
1541
- return a === void 0 ? "" : JSON.stringify(a);
1612
+ return a === void 0 ? "" : jsonOrText(a);
1542
1613
  })(),
1543
1614
  tool_result_json: toolResultJson(options.tool_result ?? options.toolResult),
1544
1615
  tool_call_id: options.tool_call_id ?? options.toolCallId ?? "",
@@ -1612,7 +1683,7 @@ function createInstanceNamespace(credentials, cache, onTurn) {
1612
1683
  }
1613
1684
 
1614
1685
  // src/version.ts
1615
- var SDK_VERSION = "0.5.2";
1686
+ var SDK_VERSION = "0.5.6";
1616
1687
 
1617
1688
  // src/registry.ts
1618
1689
  var instances = /* @__PURE__ */ new Map();
@@ -2115,6 +2186,10 @@ function tryServeFromCache(cache, scope, params, maxItems) {
2115
2186
  return { response: null, hit: null };
2116
2187
  }
2117
2188
  }
2189
+ function distinctQueryCount(searchQuery) {
2190
+ if (!Array.isArray(searchQuery)) return 0;
2191
+ return new Set(searchQuery.filter((q) => typeof q === "string" && q.length > 0)).size;
2192
+ }
2118
2193
 
2119
2194
  // src/context/assembled.ts
2120
2195
  var COLLECTIONS2 = ["facts", "preferences", "episodes", "emotions", "temporal_events"];
@@ -2611,6 +2686,8 @@ var SynapClient = class {
2611
2686
  this.#fetchHooks = {
2612
2687
  beforeFetch: (scope, options2) => {
2613
2688
  const o2 = options2;
2689
+ if (o2["query_date"] ?? o2["queryDate"]) return null;
2690
+ if (o2["max_results_per_query"] ?? o2["maxResultsPerQuery"]) return null;
2614
2691
  const attempt = tryServeFromCache(
2615
2692
  this.#anticipationCache,
2616
2693
  scope,
@@ -2681,7 +2758,11 @@ var SynapClient = class {
2681
2758
  compacted: (conversationId, format) => this.#localCompacted(conversationId, format)
2682
2759
  }
2683
2760
  );
2684
- this.memories = createMemoriesInterface(this.#transport);
2761
+ this.memories = createMemoriesInterface(this.#transport, ({ userId, customerId }) => {
2762
+ for (const id of /* @__PURE__ */ new Set([userId, customerId])) {
2763
+ if (id) this.#anticipationCache.dropEntity(id);
2764
+ }
2765
+ });
2685
2766
  this.credits = createCreditsNamespace(this.#transport);
2686
2767
  this.cache = createCacheNamespace(this.#anticipationCache);
2687
2768
  this.instance = createInstanceNamespace(
@@ -2879,6 +2960,8 @@ var SynapClient = class {
2879
2960
  types,
2880
2961
  mode = "fast",
2881
2962
  precision_level: precisionLevel = "high",
2963
+ query_date: queryDate,
2964
+ max_results_per_query: maxResultsPerQuery,
2882
2965
  include_conversation_context: includeConversationContext = true,
2883
2966
  scopes,
2884
2967
  include_scope_labels: includeScopeLabels = false,
@@ -2893,7 +2976,12 @@ var SynapClient = class {
2893
2976
  max_results: maxResults,
2894
2977
  types,
2895
2978
  mode,
2896
- precision_level: precisionLevel
2979
+ precision_level: precisionLevel,
2980
+ // In `shared` so it reaches all four branches at once. The Python edit
2981
+ // threaded three call sites by hand and missed the client branch, which
2982
+ // sits one indent deeper; spreading removes that whole class of miss.
2983
+ query_date: queryDate,
2984
+ max_results_per_query: maxResultsPerQuery
2897
2985
  };
2898
2986
  const labels = [];
2899
2987
  const tasks = [];
@@ -3003,7 +3091,12 @@ var SynapClient = class {
3003
3091
  served_item_ids: served.servedItemIds,
3004
3092
  scope,
3005
3093
  source_bundle_ids: served.bundleId ? [served.bundleId] : [],
3006
- timestamp_ms: Date.now()
3094
+ timestamp_ms: Date.now(),
3095
+ // How many distinct search queries the fetch carried. A hit never
3096
+ // reaches the fetch route, so this event is how the server learns it
3097
+ // happened and what it is charged by. The count only: this event must
3098
+ // not carry the caller's words.
3099
+ query_count: distinctQueryCount(options["search_query"] ?? options["searchQuery"])
3007
3100
  });
3008
3101
  } catch {
3009
3102
  }
@@ -3142,6 +3235,7 @@ export {
3142
3235
  DEFAULT_TIMEOUTS,
3143
3236
  DOCUMENT_TYPES,
3144
3237
  ENDPOINTS,
3238
+ FORGET_MODES,
3145
3239
  HttpTransport,
3146
3240
  INGEST_MODES,
3147
3241
  ITEM_COLLECTIONS,