@maximem/synap-js-sdk 0.5.10 → 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
@@ -1,5 +1,5 @@
1
- import { E as Encoder, a as AnticipationCacheSnapshot } from './errors-Bdayqlzy.cjs';
2
- export { b as ANY_SCOPE, c as AgentUnavailableError, A as AnticipationCache, d as AnticipationCacheOptions, e as AuthenticationError, B as BundleItem, C as ConflictError, f as ConnectionError, g as ContextBundle, h as ContextNotFoundError, i as ExitReason, I as InsufficientCreditsError, j as InvalidConversationIdError, k as InvalidInputError, l as InvalidInstanceIdError, L as ListeningAlreadyActiveError, m as ListeningNotActiveError, n as LookupParams, o as LookupResult, p as LookupTelemetry, N as NetworkTimeoutError, P as PermanentError, R as RateLimitError, q as SDKError, r as ServiceUnavailableError, s as SessionExpiredError, t as SnapshotBundle, u as SnapshotItemPreview, v as SnapshotItemRecord, S as SynapError, w as SynapErrorCode, x as SynapErrorOptions, y as SynapPermanentError, z as SynapTransientError, T as TranscriptConflictError, D as TransientError, F as isSynapError } from './errors-Bdayqlzy.cjs';
1
+ import { E as Encoder, a as AnticipationCacheSnapshot } from './errors-BvUA5EW8.cjs';
2
+ export { b as ANY_SCOPE, c as AgentUnavailableError, A as AnticipationCache, d as AnticipationCacheOptions, e as AuthenticationError, B as BundleItem, C as ConflictError, f as ConnectionError, g as ContextBundle, h as ContextNotFoundError, i as CustomerIdNotAcceptedError, j as ExitReason, I as InsufficientCreditsError, k as InvalidConversationIdError, l as InvalidInputError, m as InvalidInstanceIdError, L as ListeningAlreadyActiveError, n as ListeningNotActiveError, o as LookupParams, p as LookupResult, q as LookupTelemetry, N as NetworkTimeoutError, P as PermanentError, R as RateLimitError, r as SDKError, s as ServiceUnavailableError, t as SessionExpiredError, u as SnapshotBundle, v as SnapshotItemPreview, w as SnapshotItemRecord, S as SynapError, x as SynapErrorCode, y as SynapErrorOptions, z as SynapPermanentError, D as SynapTransientError, T as TranscriptConflictError, F as TransientError, G as isSynapError } from './errors-BvUA5EW8.cjs';
3
3
 
4
4
  /**
5
5
  * AUTOGENERATED FROM synap/sdk/CONTRACT/endpoints.yaml -- DO NOT EDIT.
@@ -335,8 +335,12 @@ declare class HttpTransport {
335
335
  identityResolver: (() => Promise<void>) | undefined;
336
336
  /** Resolve identity once, before the first request. Never throws. */
337
337
  ready(): Promise<void>;
338
- /** Refuse a customer_id on a B2C instance, at the call site. */
339
- checkCustomerId(customerId: unknown, where: string): void;
338
+ /**
339
+ * Refuse a customer_id on a B2C instance, at the call site. Resolves identity
340
+ * first: the isolation comes from whoami, so on the first call of a client
341
+ * that skipped initialize() the check would otherwise see nothing and pass.
342
+ */
343
+ checkCustomerId(customerId: unknown, where: string): Promise<void>;
340
344
  setTimeouts(timeouts: Partial<TimeoutConfig>): void;
341
345
  /**
342
346
  * `null` DISABLES retries, matching Python.
@@ -1869,7 +1873,7 @@ declare class SynapClient {
1869
1873
  * build when the two disagree, which is the only thing that makes a manual
1870
1874
  * publish safe.
1871
1875
  */
1872
- declare const SDK_VERSION = "0.5.10";
1876
+ declare const SDK_VERSION = "0.5.12";
1873
1877
 
1874
1878
  /**
1875
1879
  * `response_shape: "ranked"`: one list in the order the server ranked it.
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { E as Encoder, a as AnticipationCacheSnapshot } from './errors-Bdayqlzy.js';
2
- export { b as ANY_SCOPE, c as AgentUnavailableError, A as AnticipationCache, d as AnticipationCacheOptions, e as AuthenticationError, B as BundleItem, C as ConflictError, f as ConnectionError, g as ContextBundle, h as ContextNotFoundError, i as ExitReason, I as InsufficientCreditsError, j as InvalidConversationIdError, k as InvalidInputError, l as InvalidInstanceIdError, L as ListeningAlreadyActiveError, m as ListeningNotActiveError, n as LookupParams, o as LookupResult, p as LookupTelemetry, N as NetworkTimeoutError, P as PermanentError, R as RateLimitError, q as SDKError, r as ServiceUnavailableError, s as SessionExpiredError, t as SnapshotBundle, u as SnapshotItemPreview, v as SnapshotItemRecord, S as SynapError, w as SynapErrorCode, x as SynapErrorOptions, y as SynapPermanentError, z as SynapTransientError, T as TranscriptConflictError, D as TransientError, F as isSynapError } from './errors-Bdayqlzy.js';
1
+ import { E as Encoder, a as AnticipationCacheSnapshot } from './errors-BvUA5EW8.js';
2
+ export { b as ANY_SCOPE, c as AgentUnavailableError, A as AnticipationCache, d as AnticipationCacheOptions, e as AuthenticationError, B as BundleItem, C as ConflictError, f as ConnectionError, g as ContextBundle, h as ContextNotFoundError, i as CustomerIdNotAcceptedError, j as ExitReason, I as InsufficientCreditsError, k as InvalidConversationIdError, l as InvalidInputError, m as InvalidInstanceIdError, L as ListeningAlreadyActiveError, n as ListeningNotActiveError, o as LookupParams, p as LookupResult, q as LookupTelemetry, N as NetworkTimeoutError, P as PermanentError, R as RateLimitError, r as SDKError, s as ServiceUnavailableError, t as SessionExpiredError, u as SnapshotBundle, v as SnapshotItemPreview, w as SnapshotItemRecord, S as SynapError, x as SynapErrorCode, y as SynapErrorOptions, z as SynapPermanentError, D as SynapTransientError, T as TranscriptConflictError, F as TransientError, G as isSynapError } from './errors-BvUA5EW8.js';
3
3
 
4
4
  /**
5
5
  * AUTOGENERATED FROM synap/sdk/CONTRACT/endpoints.yaml -- DO NOT EDIT.
@@ -335,8 +335,12 @@ declare class HttpTransport {
335
335
  identityResolver: (() => Promise<void>) | undefined;
336
336
  /** Resolve identity once, before the first request. Never throws. */
337
337
  ready(): Promise<void>;
338
- /** Refuse a customer_id on a B2C instance, at the call site. */
339
- checkCustomerId(customerId: unknown, where: string): void;
338
+ /**
339
+ * Refuse a customer_id on a B2C instance, at the call site. Resolves identity
340
+ * first: the isolation comes from whoami, so on the first call of a client
341
+ * that skipped initialize() the check would otherwise see nothing and pass.
342
+ */
343
+ checkCustomerId(customerId: unknown, where: string): Promise<void>;
340
344
  setTimeouts(timeouts: Partial<TimeoutConfig>): void;
341
345
  /**
342
346
  * `null` DISABLES retries, matching Python.
@@ -1869,7 +1873,7 @@ declare class SynapClient {
1869
1873
  * build when the two disagree, which is the only thing that makes a manual
1870
1874
  * publish safe.
1871
1875
  */
1872
- declare const SDK_VERSION = "0.5.10";
1876
+ declare const SDK_VERSION = "0.5.12";
1873
1877
 
1874
1878
  /**
1875
1879
  * `response_shape: "ranked"`: one list in the order the server ranked it.
package/dist/index.js CHANGED
@@ -20,6 +20,7 @@ import {
20
20
  ConflictError,
21
21
  ConnectionError,
22
22
  ContextNotFoundError,
23
+ CustomerIdNotAcceptedError,
23
24
  InsufficientCreditsError,
24
25
  InvalidConversationIdError,
25
26
  InvalidInputError,
@@ -39,7 +40,7 @@ import {
39
40
  TransientError,
40
41
  isSynapError,
41
42
  newCorrelationId
42
- } from "./chunk-BWMPKLFG.js";
43
+ } from "./chunk-4GE7SORD.js";
43
44
 
44
45
  // src/transport/endpoints.ts
45
46
  var ENDPOINTS = {
@@ -194,9 +195,7 @@ var B2C_ISOLATION = "equals_customer";
194
195
  function checkCustomerId(isolation, customerId, where, instanceId) {
195
196
  if (customerId === void 0 || customerId === null || customerId === "") return;
196
197
  if (isolation !== B2C_ISOLATION) return;
197
- throw new InvalidInputError(
198
- `${where}: customer_id is not accepted on this instance${instanceId ? ` (${instanceId})` : ""}, which is B2C (user_context_isolation='${B2C_ISOLATION}'). Send user_id only; it is the whole identity, and the server files and reads your data under it. Received customer_id=${JSON.stringify(customerId)}.`
199
- );
198
+ throw new CustomerIdNotAcceptedError(where, String(customerId), instanceId);
200
199
  }
201
200
 
202
201
  // src/transport/http.ts
@@ -278,8 +277,13 @@ var HttpTransport = class {
278
277
  async ready() {
279
278
  if (this.identityResolver !== void 0) await this.identityResolver();
280
279
  }
281
- /** Refuse a customer_id on a B2C instance, at the call site. */
282
- checkCustomerId(customerId, where) {
280
+ /**
281
+ * Refuse a customer_id on a B2C instance, at the call site. Resolves identity
282
+ * first: the isolation comes from whoami, so on the first call of a client
283
+ * that skipped initialize() the check would otherwise see nothing and pass.
284
+ */
285
+ async checkCustomerId(customerId, where) {
286
+ await this.ready();
283
287
  checkCustomerId(
284
288
  this.userContextIsolation,
285
289
  customerId,
@@ -635,6 +639,7 @@ function buildFetchRequest(scope, options) {
635
639
  const perQuery = opt(options, "max_results_per_query", "maxResultsPerQuery");
636
640
  const responseShape = responseShapeOf(options);
637
641
  const { mode, precisionLevel } = retrievalOptionsOf(options);
642
+ const { contextMode, lastN } = scopeOptionsOf(scope, options);
638
643
  if (searchQuery !== void 0 && !Array.isArray(searchQuery)) {
639
644
  throw new InvalidInputError("search_query must be an array when provided");
640
645
  }
@@ -662,21 +667,7 @@ function buildFetchRequest(scope, options) {
662
667
  switch (scope) {
663
668
  case "user":
664
669
  {
665
- if (!userId) throw new InvalidInputError("user_id is required");
666
670
  body["user_id"] = userId;
667
- const contextMode = opt(options, "context_mode", "contextMode") ?? "in-conversation";
668
- if (!VALID_CONTEXT_MODES.includes(contextMode)) {
669
- throw new InvalidInputError(
670
- `Invalid context_mode '${contextMode}'. Must be one of: ${VALID_CONTEXT_MODES.join(", ")}`
671
- );
672
- }
673
- const lastN = opt(options, "last_n_conversations", "lastNConversations") ?? 1;
674
- if (!Number.isInteger(lastN)) {
675
- throw new InvalidInputError("last_n_conversations must be an integer");
676
- }
677
- if (lastN < 0 || lastN > 20) {
678
- throw new InvalidInputError("last_n_conversations must be between 0 and 20");
679
- }
680
671
  if (contextMode === "conversation-summary") {
681
672
  body["context_mode"] = contextMode;
682
673
  body["include_profile"] = opt(options, "include_profile", "includeProfile") ?? true;
@@ -687,11 +678,9 @@ function buildFetchRequest(scope, options) {
687
678
  }
688
679
  break;
689
680
  case "customer":
690
- if (!customerId) throw new InvalidInputError("customer_id is required");
691
681
  body["customer_id"] = customerId;
692
682
  break;
693
683
  case "conversation":
694
- if (!conversationId) throw new InvalidInputError("conversation_id is required");
695
684
  if (userId !== void 0) body["user_id"] = userId;
696
685
  if (customerId !== void 0) body["customer_id"] = customerId;
697
686
  break;
@@ -710,6 +699,33 @@ function responseShapeOf(options) {
710
699
  }
711
700
  return shape;
712
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
+ }
713
729
  var VALID_MODES = ["fast", "accurate"];
714
730
  var VALID_PRECISION = ["high", "medium"];
715
731
  function retrievalOptionsOf(options) {
@@ -730,18 +746,24 @@ function retrievalOptionsOf(options) {
730
746
  async function fetchContext(transport, scope, options = {}, hooks = {}) {
731
747
  const startedAt = Date.now();
732
748
  await transport.ready?.();
733
- transport.checkCustomerId(
749
+ await transport.checkCustomerId(
734
750
  opt(options, "customer_id", "customerId"),
735
751
  `${scope}.context.fetch`
736
752
  );
737
753
  const responseShape = responseShapeOf(options);
738
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
+ };
739
761
  const network = async () => {
740
762
  const { endpoint, body } = buildFetchRequest(scope, options);
741
763
  const result = await transport.request(endpoint, { body });
742
764
  return applyResponseShape(result?.["context"] ?? {}, responseShape);
743
765
  };
744
- const anticipated = await hooks.beforeFetch?.(scope, options) ?? null;
766
+ const anticipated = summaryMode ? null : await hooks.beforeFetch?.(scope, options) ?? null;
745
767
  if (anticipated !== null && anticipated.borderline) {
746
768
  const pending = network();
747
769
  pending.catch(() => void 0);
@@ -753,17 +775,17 @@ async function fetchContext(transport, scope, options = {}, hooks = {}) {
753
775
  if (timer !== void 0) clearTimeout(timer);
754
776
  if (won !== null) {
755
777
  hooks.onAssembled?.(scope, options, won, startedAt);
756
- return won;
778
+ return finish(won);
757
779
  }
758
780
  }
759
781
  if (anticipated !== null) {
760
782
  hooks.onServedFromCache?.(scope, options, anticipated);
761
783
  hooks.onAssembled?.(scope, options, anticipated.response, startedAt);
762
- return applyResponseShape(anticipated.response, responseShape);
784
+ return finish(applyResponseShape(anticipated.response, responseShape));
763
785
  }
764
786
  const response = await network();
765
787
  hooks.onAssembled?.(scope, options, response, startedAt);
766
- return response;
788
+ return finish(response);
767
789
  }
768
790
 
769
791
  // src/context/normalize.ts
@@ -1078,7 +1100,7 @@ function createMemoriesInterface(transport, onForgotten) {
1078
1100
  return {
1079
1101
  async create(options) {
1080
1102
  const o2 = options;
1081
- transport.checkCustomerId(o2["customer_id"] ?? o2["customerId"], "memories.create");
1103
+ await transport.checkCustomerId(o2["customer_id"] ?? o2["customerId"], "memories.create");
1082
1104
  return transport.request("memories_create", { body: buildCreateBody(options) });
1083
1105
  },
1084
1106
  async batch_create(options) {
@@ -1095,7 +1117,7 @@ function createMemoriesInterface(transport, onForgotten) {
1095
1117
  const userId = options.user_id ?? options.userId;
1096
1118
  const customerId = options.customer_id ?? options.customerId;
1097
1119
  if (!userId) throw new InvalidInputError("user_id is required");
1098
- transport.checkCustomerId(customerId, "memories.create_from_file");
1120
+ await transport.checkCustomerId(customerId, "memories.create_from_file");
1099
1121
  const filePath = options.file_path ?? options.filePath;
1100
1122
  const sources = [filePath, options.file, options.text].filter((v) => v !== void 0);
1101
1123
  if (sources.length === 0) {
@@ -1162,7 +1184,7 @@ function createMemoriesInterface(transport, onForgotten) {
1162
1184
  },
1163
1185
  async forget(options) {
1164
1186
  const o2 = options;
1165
- transport.checkCustomerId(o2["customer_id"] ?? o2["customerId"], "memories.forget");
1187
+ await transport.checkCustomerId(o2["customer_id"] ?? o2["customerId"], "memories.forget");
1166
1188
  const body = buildForgetBody(options);
1167
1189
  const result = await transport.request("memories_forget", { body });
1168
1190
  const removed = !!result?.deleted_ids?.length || result?.status === "deleted" || result?.status === "partial";
@@ -1433,7 +1455,7 @@ function createConversationNamespace(transport, subscribers = new CompactionSubs
1433
1455
  };
1434
1456
  return {
1435
1457
  async record_message(options) {
1436
- transport.checkCustomerId(
1458
+ await transport.checkCustomerId(
1437
1459
  options["customer_id"] ?? options["customerId"],
1438
1460
  "conversation.record_message"
1439
1461
  );
@@ -1465,7 +1487,7 @@ function createConversationNamespace(transport, subscribers = new CompactionSubs
1465
1487
  }
1466
1488
  for (const m of messages) {
1467
1489
  const mo = m;
1468
- transport.checkCustomerId(
1490
+ await transport.checkCustomerId(
1469
1491
  mo["customer_id"] ?? mo["customerId"],
1470
1492
  "conversation.record_messages_batch"
1471
1493
  );
@@ -1775,7 +1797,7 @@ function createInstanceNamespace(credentials, cache, onTurn, agentModel = () =>
1775
1797
  onListen?.();
1776
1798
  } catch {
1777
1799
  }
1778
- const { GrpcStreamClient } = await import("./stream-client-3WHXGW4U.js");
1800
+ const { GrpcStreamClient } = await import("./stream-client-ZBCKRU7S.js");
1779
1801
  const onContext = options.on_context ?? options.onContext;
1780
1802
  const onDisconnect = options.on_disconnect ?? options.onDisconnect;
1781
1803
  const onReconnect = options.on_reconnect ?? options.onReconnect;
@@ -1954,7 +1976,7 @@ function createInstanceNamespace(credentials, cache, onTurn, agentModel = () =>
1954
1976
  }
1955
1977
 
1956
1978
  // src/version.ts
1957
- var SDK_VERSION = "0.5.10";
1979
+ var SDK_VERSION = "0.5.12";
1958
1980
 
1959
1981
  // src/registry.ts
1960
1982
  var instances = /* @__PURE__ */ new Map();
@@ -3772,6 +3794,21 @@ var SynapClient = class _SynapClient {
3772
3794
  },
3773
3795
  onServedFromCache: (_scope, options2, served) => {
3774
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
+ );
3775
3812
  }
3776
3813
  };
3777
3814
  this.user = createUserNamespace(this.#transport, this.#fetchHooks);
@@ -4064,6 +4101,7 @@ var SynapClient = class _SynapClient {
4064
4101
  last_n_conversations: lastNConversations = 1,
4065
4102
  response_shape: responseShape = "by_type"
4066
4103
  } = options;
4104
+ await this.#transport.checkCustomerId(customerId, "sdk.fetch");
4067
4105
  validateConversationId(conversationId);
4068
4106
  responseShapeOf({ response_shape: responseShape });
4069
4107
  const wants = (scope) => scopes === void 0 || scopes.includes(scope);
@@ -4459,6 +4497,7 @@ export {
4459
4497
  ConflictError,
4460
4498
  ConnectionError,
4461
4499
  ContextNotFoundError,
4500
+ CustomerIdNotAcceptedError,
4462
4501
  DEFAULT_BASE_URL,
4463
4502
  DEFAULT_DOCUMENT_TYPE,
4464
4503
  DEFAULT_INGEST_MODE,