@maximem/synap-js-sdk 0.5.11 → 0.5.12

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.d.cts CHANGED
@@ -1873,7 +1873,7 @@ declare class SynapClient {
1873
1873
  * build when the two disagree, which is the only thing that makes a manual
1874
1874
  * publish safe.
1875
1875
  */
1876
- declare const SDK_VERSION = "0.5.11";
1876
+ declare const SDK_VERSION = "0.5.12";
1877
1877
 
1878
1878
  /**
1879
1879
  * `response_shape: "ranked"`: one list in the order the server ranked it.
package/dist/index.d.ts CHANGED
@@ -1873,7 +1873,7 @@ declare class SynapClient {
1873
1873
  * build when the two disagree, which is the only thing that makes a manual
1874
1874
  * publish safe.
1875
1875
  */
1876
- declare const SDK_VERSION = "0.5.11";
1876
+ declare const SDK_VERSION = "0.5.12";
1877
1877
 
1878
1878
  /**
1879
1879
  * `response_shape: "ranked"`: one list in the order the server ranked it.
package/dist/index.js CHANGED
@@ -639,6 +639,7 @@ function buildFetchRequest(scope, options) {
639
639
  const perQuery = opt(options, "max_results_per_query", "maxResultsPerQuery");
640
640
  const responseShape = responseShapeOf(options);
641
641
  const { mode, precisionLevel } = retrievalOptionsOf(options);
642
+ const { contextMode, lastN } = scopeOptionsOf(scope, options);
642
643
  if (searchQuery !== void 0 && !Array.isArray(searchQuery)) {
643
644
  throw new InvalidInputError("search_query must be an array when provided");
644
645
  }
@@ -666,21 +667,7 @@ function buildFetchRequest(scope, options) {
666
667
  switch (scope) {
667
668
  case "user":
668
669
  {
669
- if (!userId) throw new InvalidInputError("user_id is required");
670
670
  body["user_id"] = userId;
671
- const contextMode = opt(options, "context_mode", "contextMode") ?? "in-conversation";
672
- if (!VALID_CONTEXT_MODES.includes(contextMode)) {
673
- throw new InvalidInputError(
674
- `Invalid context_mode '${contextMode}'. Must be one of: ${VALID_CONTEXT_MODES.join(", ")}`
675
- );
676
- }
677
- const lastN = opt(options, "last_n_conversations", "lastNConversations") ?? 1;
678
- if (!Number.isInteger(lastN)) {
679
- throw new InvalidInputError("last_n_conversations must be an integer");
680
- }
681
- if (lastN < 0 || lastN > 20) {
682
- throw new InvalidInputError("last_n_conversations must be between 0 and 20");
683
- }
684
671
  if (contextMode === "conversation-summary") {
685
672
  body["context_mode"] = contextMode;
686
673
  body["include_profile"] = opt(options, "include_profile", "includeProfile") ?? true;
@@ -691,11 +678,9 @@ function buildFetchRequest(scope, options) {
691
678
  }
692
679
  break;
693
680
  case "customer":
694
- if (!customerId) throw new InvalidInputError("customer_id is required");
695
681
  body["customer_id"] = customerId;
696
682
  break;
697
683
  case "conversation":
698
- if (!conversationId) throw new InvalidInputError("conversation_id is required");
699
684
  if (userId !== void 0) body["user_id"] = userId;
700
685
  if (customerId !== void 0) body["customer_id"] = customerId;
701
686
  break;
@@ -714,6 +699,33 @@ function responseShapeOf(options) {
714
699
  }
715
700
  return shape;
716
701
  }
702
+ var REQUIRED_ID = {
703
+ user: ["user_id", "userId"],
704
+ customer: ["customer_id", "customerId"],
705
+ conversation: ["conversation_id", "conversationId"],
706
+ client: null
707
+ };
708
+ function scopeOptionsOf(scope, options) {
709
+ const required = REQUIRED_ID[scope];
710
+ if (required !== null && !opt(options, required[0], required[1])) {
711
+ throw new InvalidInputError(`${required[0]} is required`);
712
+ }
713
+ const contextMode = opt(options, "context_mode", "contextMode") ?? "in-conversation";
714
+ const lastN = opt(options, "last_n_conversations", "lastNConversations") ?? 1;
715
+ if (scope !== "user") return { contextMode, lastN };
716
+ if (!VALID_CONTEXT_MODES.includes(contextMode)) {
717
+ throw new InvalidInputError(
718
+ `Invalid context_mode '${contextMode}'. Must be one of: ${VALID_CONTEXT_MODES.join(", ")}`
719
+ );
720
+ }
721
+ if (!Number.isInteger(lastN)) {
722
+ throw new InvalidInputError("last_n_conversations must be an integer");
723
+ }
724
+ if (lastN < 0 || lastN > 20) {
725
+ throw new InvalidInputError("last_n_conversations must be between 0 and 20");
726
+ }
727
+ return { contextMode, lastN };
728
+ }
717
729
  var VALID_MODES = ["fast", "accurate"];
718
730
  var VALID_PRECISION = ["high", "medium"];
719
731
  function retrievalOptionsOf(options) {
@@ -740,12 +752,18 @@ async function fetchContext(transport, scope, options = {}, hooks = {}) {
740
752
  );
741
753
  const responseShape = responseShapeOf(options);
742
754
  retrievalOptionsOf(options);
755
+ const { contextMode } = scopeOptionsOf(scope, options);
756
+ const summaryMode = scope === "user" && contextMode === "conversation-summary";
757
+ const finish = (response2) => {
758
+ hooks.onResponse?.(scope, options, response2);
759
+ return response2;
760
+ };
743
761
  const network = async () => {
744
762
  const { endpoint, body } = buildFetchRequest(scope, options);
745
763
  const result = await transport.request(endpoint, { body });
746
764
  return applyResponseShape(result?.["context"] ?? {}, responseShape);
747
765
  };
748
- const anticipated = await hooks.beforeFetch?.(scope, options) ?? null;
766
+ const anticipated = summaryMode ? null : await hooks.beforeFetch?.(scope, options) ?? null;
749
767
  if (anticipated !== null && anticipated.borderline) {
750
768
  const pending = network();
751
769
  pending.catch(() => void 0);
@@ -757,17 +775,17 @@ async function fetchContext(transport, scope, options = {}, hooks = {}) {
757
775
  if (timer !== void 0) clearTimeout(timer);
758
776
  if (won !== null) {
759
777
  hooks.onAssembled?.(scope, options, won, startedAt);
760
- return won;
778
+ return finish(won);
761
779
  }
762
780
  }
763
781
  if (anticipated !== null) {
764
782
  hooks.onServedFromCache?.(scope, options, anticipated);
765
783
  hooks.onAssembled?.(scope, options, anticipated.response, startedAt);
766
- return applyResponseShape(anticipated.response, responseShape);
784
+ return finish(applyResponseShape(anticipated.response, responseShape));
767
785
  }
768
786
  const response = await network();
769
787
  hooks.onAssembled?.(scope, options, response, startedAt);
770
- return response;
788
+ return finish(response);
771
789
  }
772
790
 
773
791
  // src/context/normalize.ts
@@ -1958,7 +1976,7 @@ function createInstanceNamespace(credentials, cache, onTurn, agentModel = () =>
1958
1976
  }
1959
1977
 
1960
1978
  // src/version.ts
1961
- var SDK_VERSION = "0.5.11";
1979
+ var SDK_VERSION = "0.5.12";
1962
1980
 
1963
1981
  // src/registry.ts
1964
1982
  var instances = /* @__PURE__ */ new Map();
@@ -3776,6 +3794,21 @@ var SynapClient = class _SynapClient {
3776
3794
  },
3777
3795
  onServedFromCache: (_scope, options2, served) => {
3778
3796
  this.#emitContextUsed(options2, _scope, served);
3797
+ },
3798
+ // The periodic user-summary splice, as Python runs it at the end of the
3799
+ // user, customer and client fetches (the conversation fetch does its own
3800
+ // through `onFetched`). Until 0.5.12 only the conversation fetch had it,
3801
+ // so the same usage gave the model different context in JS.
3802
+ onResponse: (scope, options2, response) => {
3803
+ if (scope === "conversation") return;
3804
+ const o2 = options2;
3805
+ const owner = scope === "user" ? o2["user_id"] ?? o2["userId"] : scope === "customer" ? o2["customer_id"] ?? o2["customerId"] : "_client";
3806
+ this.#injectUserSummary(
3807
+ response,
3808
+ o2["conversation_id"] ?? o2["conversationId"],
3809
+ owner,
3810
+ rungKey(o2["scope_path"] ?? o2["scopePath"])
3811
+ );
3779
3812
  }
3780
3813
  };
3781
3814
  this.user = createUserNamespace(this.#transport, this.#fetchHooks);