@maximem/synap-js-sdk 0.5.9 → 0.5.10

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.
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/anish/maximemai/maximem_synap/synap/sdk/js/dist/grpc/index.cjs","../../src/grpc/index.ts"],"names":[],"mappings":"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","file":"/Users/anish/maximemai/maximem_synap/synap/sdk/js/dist/grpc/index.cjs","sourcesContent":[null,"/**\n * gRPC anticipation stream: availability and loading.\n *\n * This is a SUBPATH export (`@maximem/synap-js-sdk/grpc`) and is never\n * imported by the main entry point. Three reasons, all of which have bitten\n * someone already:\n *\n * 1. `@grpc/grpc-js` plus its protos is roughly 5MB. HTTP-only and Edge users\n * should not pay for it (gotcha G-Q).\n * 2. grpc-js is built on `node:http2`, `node:net` and `node:tls`. Merely\n * importing it on Edge or Workers fails the *build*, not the call. Keeping\n * it behind a subpath plus a lazy `import()` means importing the SDK on\n * Edge stays safe.\n * 3. It is an `optionalDependency`, so it may legitimately be absent.\n *\n * ## Proto loading\n *\n * The stream is live. The proto ships as an INLINED JSON descriptor\n * (./descriptor.ts) loaded through `proto-loader.fromJSON`, not through\n * `loadSync(path)`. proto-loader's file-based path reads the `.proto` off disk\n * at runtime, which breaks under webpack/turbopack bundling and Vercel's `nft`\n * file tracing: at deploy time rather than at test time (gotcha G-P). Inlining\n * gets the same result as ts-proto codegen without a codegen toolchain.\n */\n\nimport { ListeningNotActiveError } from '../errors.js';\nexport { GrpcStreamClient } from './stream-client.js';\nexport type {\n StreamState, StreamCredentials, StreamClientOptions, ConversationEventInput,\n} from './stream-client.js';\nexport { PROTO_SHA } from './descriptor.js';\n\nexport type GrpcAvailability =\n | { available: true }\n | { available: false; reason: 'not-node' | 'module-missing'; detail: string };\n\n/**\n * Whether a gRPC stream could run here.\n *\n * Deliberately does not throw: callers use this to decide whether to offer the\n * stream at all, and a hard failure at that point is unhelpful.\n */\nexport async function checkGrpcAvailability(): Promise<GrpcAvailability> {\n const isNode =\n typeof process !== 'undefined' &&\n process.versions?.node !== undefined &&\n typeof (globalThis as { EdgeRuntime?: unknown }).EdgeRuntime === 'undefined';\n\n if (!isNode) {\n return {\n available: false,\n reason: 'not-node',\n detail:\n 'gRPC needs raw TCP and node:http2, which Edge runtimes and Workers do ' +\n 'not provide. HTTP context fetching works normally here; only the ' +\n 'anticipation stream is unavailable. Reaching Edge would require a ' +\n 'gRPC-Web or Connect endpoint on the server, which does not exist yet.',\n };\n }\n\n try {\n await import(/* @vite-ignore */ '@grpc/grpc-js');\n return { available: true };\n } catch (error) {\n return {\n available: false,\n reason: 'module-missing',\n detail:\n '@grpc/grpc-js is an optional dependency and is not installed. Run ' +\n '`npm install @grpc/grpc-js` to enable the anticipation stream. ' +\n `(${(error as Error)?.message ?? String(error)})`,\n };\n }\n}\n\nexport interface ListenOptions {\n conversationId: string;\n userId?: string;\n customerId?: string;\n onBundle?: (bundle: unknown) => void;\n}\n\nexport interface ListeningSession {\n stop(): Promise<void>;\n readonly active: boolean;\n}\n\n/**\n * Start the anticipation stream directly, without a SynapClient.\n *\n * Most callers want `client.instance.listen()` instead, which shares the\n * client's credentials and anticipation cache. This exists for the case where\n * only the stream is wanted.\n *\n * **Opt-in, and off by default.** The removed wrapper called `listen()`\n * unconditionally during init, so every user had a stream whether they asked\n * for one or not. Making it opt-in is the right default, but it is not a\n * neutral change: fewer streams means fewer anticipation hits and therefore\n * MORE billed cloud fetches for existing users. That has to be announced\n * rather than discovered (gotcha G-Y).\n */\nexport async function listen(\n options: ListenOptions & {\n apiKey?: string;\n clientId?: string;\n instanceId?: string;\n host?: string;\n port?: number;\n useTls?: boolean;\n },\n): Promise<ListeningSession> {\n if (!options.conversationId) {\n // conversation_id is not a scope tier, but the stream genuinely requires\n // one: it is what the server keys the anticipation session on.\n throw new ListeningNotActiveError('conversation_id is required to start a listening stream');\n }\n\n const availability = await checkGrpcAvailability();\n if (!availability.available) {\n throw new ListeningNotActiveError(availability.detail);\n }\n\n const [{ GrpcStreamClient: StreamClient }, { AnticipationCache }, { getEnv }] = await Promise.all([\n import('./stream-client.js'),\n import('../context/anticipation-cache.js'),\n import('../util/env.js'),\n ]);\n\n const apiKey = options.apiKey ?? getEnv('SYNAP_API_KEY') ?? '';\n if (apiKey === '') {\n throw new ListeningNotActiveError(\n 'No Synap API key found. Set SYNAP_API_KEY or pass apiKey.',\n );\n }\n\n const cache = new AnticipationCache();\n const client = new StreamClient(\n {\n apiKey,\n clientId: options.clientId ?? getEnv('SYNAP_CLIENT_ID') ?? '',\n instanceId: options.instanceId ?? getEnv('SYNAP_INSTANCE_ID') ?? '',\n },\n cache,\n {\n ...(options.host !== undefined ? { host: options.host } : {}),\n ...(options.port !== undefined ? { port: options.port } : {}),\n ...(options.useTls !== undefined ? { useTls: options.useTls } : {}),\n ...(options.onBundle !== undefined ? { onContext: options.onBundle } : {}),\n },\n );\n await client.connect();\n client.sendSessionControl({\n action: 'start',\n conversation_id: options.conversationId,\n ...(options.userId !== undefined ? { user_id: options.userId } : {}),\n ...(options.customerId !== undefined ? { customer_id: options.customerId } : {}),\n });\n\n return {\n stop: () => client.disconnect(),\n get active() { return client.isConnected; },\n };\n}\n"]}
1
+ {"version":3,"sources":["/Users/anish/maximemai/maximem_synap-js-parity/synap/sdk/js/dist/grpc/index.cjs","../../src/grpc/index.ts"],"names":[],"mappings":"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","file":"/Users/anish/maximemai/maximem_synap-js-parity/synap/sdk/js/dist/grpc/index.cjs","sourcesContent":[null,"/**\n * gRPC anticipation stream: availability and loading.\n *\n * This is a SUBPATH export (`@maximem/synap-js-sdk/grpc`) and is never\n * imported by the main entry point. Three reasons, all of which have bitten\n * someone already:\n *\n * 1. `@grpc/grpc-js` plus its protos is roughly 5MB. HTTP-only and Edge users\n * should not pay for it (gotcha G-Q).\n * 2. grpc-js is built on `node:http2`, `node:net` and `node:tls`. Merely\n * importing it on Edge or Workers fails the *build*, not the call. Keeping\n * it behind a subpath plus a lazy `import()` means importing the SDK on\n * Edge stays safe.\n * 3. It is an `optionalDependency`, so it may legitimately be absent.\n *\n * ## Proto loading\n *\n * The stream is live. The proto ships as an INLINED JSON descriptor\n * (./descriptor.ts) loaded through `proto-loader.fromJSON`, not through\n * `loadSync(path)`. proto-loader's file-based path reads the `.proto` off disk\n * at runtime, which breaks under webpack/turbopack bundling and Vercel's `nft`\n * file tracing: at deploy time rather than at test time (gotcha G-P). Inlining\n * gets the same result as ts-proto codegen without a codegen toolchain.\n */\n\nimport { ListeningNotActiveError } from '../errors.js';\nexport { GrpcStreamClient } from './stream-client.js';\nexport type {\n StreamState, StreamCredentials, StreamClientOptions, ConversationEventInput,\n} from './stream-client.js';\nexport { PROTO_SHA } from './descriptor.js';\n\nexport type GrpcAvailability =\n | { available: true }\n | { available: false; reason: 'not-node' | 'module-missing'; detail: string };\n\n/**\n * Whether a gRPC stream could run here.\n *\n * Deliberately does not throw: callers use this to decide whether to offer the\n * stream at all, and a hard failure at that point is unhelpful.\n */\nexport async function checkGrpcAvailability(): Promise<GrpcAvailability> {\n const isNode =\n typeof process !== 'undefined' &&\n process.versions?.node !== undefined &&\n typeof (globalThis as { EdgeRuntime?: unknown }).EdgeRuntime === 'undefined';\n\n if (!isNode) {\n return {\n available: false,\n reason: 'not-node',\n detail:\n 'gRPC needs raw TCP and node:http2, which Edge runtimes and Workers do ' +\n 'not provide. HTTP context fetching works normally here; only the ' +\n 'anticipation stream is unavailable. Reaching Edge would require a ' +\n 'gRPC-Web or Connect endpoint on the server, which does not exist yet.',\n };\n }\n\n try {\n await import(/* @vite-ignore */ '@grpc/grpc-js');\n return { available: true };\n } catch (error) {\n return {\n available: false,\n reason: 'module-missing',\n detail:\n '@grpc/grpc-js is an optional dependency and is not installed. Run ' +\n '`npm install @grpc/grpc-js` to enable the anticipation stream. ' +\n `(${(error as Error)?.message ?? String(error)})`,\n };\n }\n}\n\nexport interface ListenOptions {\n conversationId: string;\n userId?: string;\n customerId?: string;\n onBundle?: (bundle: unknown) => void;\n}\n\nexport interface ListeningSession {\n stop(): Promise<void>;\n readonly active: boolean;\n}\n\n/**\n * Start the anticipation stream directly, without a SynapClient.\n *\n * Most callers want `client.instance.listen()` instead, which shares the\n * client's credentials and anticipation cache. This exists for the case where\n * only the stream is wanted.\n *\n * **Opt-in, and off by default.** The removed wrapper called `listen()`\n * unconditionally during init, so every user had a stream whether they asked\n * for one or not. Making it opt-in is the right default, but it is not a\n * neutral change: fewer streams means fewer anticipation hits and therefore\n * MORE billed cloud fetches for existing users. That has to be announced\n * rather than discovered (gotcha G-Y).\n */\nexport async function listen(\n options: ListenOptions & {\n apiKey?: string;\n clientId?: string;\n instanceId?: string;\n host?: string;\n port?: number;\n useTls?: boolean;\n },\n): Promise<ListeningSession> {\n if (!options.conversationId) {\n // conversation_id is not a scope tier, but the stream genuinely requires\n // one: it is what the server keys the anticipation session on.\n throw new ListeningNotActiveError('conversation_id is required to start a listening stream');\n }\n\n const availability = await checkGrpcAvailability();\n if (!availability.available) {\n throw new ListeningNotActiveError(availability.detail);\n }\n\n const [{ GrpcStreamClient: StreamClient }, { AnticipationCache }, { getEnv }] = await Promise.all([\n import('./stream-client.js'),\n import('../context/anticipation-cache.js'),\n import('../util/env.js'),\n ]);\n\n const apiKey = options.apiKey ?? getEnv('SYNAP_API_KEY') ?? '';\n if (apiKey === '') {\n throw new ListeningNotActiveError(\n 'No Synap API key found. Set SYNAP_API_KEY or pass apiKey.',\n );\n }\n\n const cache = new AnticipationCache();\n const client = new StreamClient(\n {\n apiKey,\n clientId: options.clientId ?? getEnv('SYNAP_CLIENT_ID') ?? '',\n instanceId: options.instanceId ?? getEnv('SYNAP_INSTANCE_ID') ?? '',\n },\n cache,\n {\n ...(options.host !== undefined ? { host: options.host } : {}),\n ...(options.port !== undefined ? { port: options.port } : {}),\n ...(options.useTls !== undefined ? { useTls: options.useTls } : {}),\n ...(options.onBundle !== undefined ? { onContext: options.onBundle } : {}),\n },\n );\n await client.connect();\n client.sendSessionControl({\n action: 'start',\n conversation_id: options.conversationId,\n ...(options.userId !== undefined ? { user_id: options.userId } : {}),\n ...(options.customerId !== undefined ? { customer_id: options.customerId } : {}),\n });\n\n return {\n stop: () => client.disconnect(),\n get active() { return client.isConnected; },\n };\n}\n"]}
package/dist/index.cjs CHANGED
@@ -219,7 +219,7 @@ var HttpTransport = (_class2 = class {
219
219
 
220
220
 
221
221
  __init2() {this.closed = false}
222
- constructor(options) {;_class2.prototype.__init2.call(this);_class2.prototype.__init3.call(this);
222
+ constructor(options) {;_class2.prototype.__init2.call(this);_class2.prototype.__init3.call(this);_class2.prototype.__init4.call(this);
223
223
  this.#credentials = options.credentials;
224
224
  this.baseUrl = (_nullishCoalesce(options.baseUrl, () => ( DEFAULT_BASE_URL))).replace(/\/+$/, "");
225
225
  this.timeouts = { ...DEFAULT_TIMEOUTS, ...options.timeouts };
@@ -267,6 +267,17 @@ var HttpTransport = (_class2 = class {
267
267
  * deployment older than the field, and must mean "enforce nothing".
268
268
  */
269
269
  __init3() {this.userContextIsolation = void 0}
270
+ /**
271
+ * Set by the client to its identity resolution (`initialize()`'s whoami).
272
+ * Python refuses every call before `initialize()`; here the first request
273
+ * runs it instead, so a caller who skips it gets the same identity-dependent
274
+ * behaviour (client-scope cache hits, the B2C check) rather than an error.
275
+ */
276
+ __init4() {this.identityResolver = void 0}
277
+ /** Resolve identity once, before the first request. Never throws. */
278
+ async ready() {
279
+ if (this.identityResolver !== void 0) await this.identityResolver();
280
+ }
270
281
  /** Refuse a customer_id on a B2C instance, at the call site. */
271
282
  checkCustomerId(customerId, where) {
272
283
  checkCustomerId(
@@ -298,6 +309,7 @@ var HttpTransport = (_class2 = class {
298
309
  const spec = ENDPOINTS[name];
299
310
  const correlationId = _nullishCoalesce(options.correlationId, () => ( _chunkT372OL3Qcjs.newCorrelationId.call(void 0, )));
300
311
  const idempotent = _nullishCoalesce(options.idempotent, () => ( spec.idempotent));
312
+ if (name !== "whoami") await this.ready();
301
313
  let attempt = 0;
302
314
  let last = null;
303
315
  while (attempt < this.retryPolicy.maxAttempts) {
@@ -619,11 +631,10 @@ function buildFetchRequest(scope, options) {
619
631
  const conversationId = opt(options, "conversation_id", "conversationId");
620
632
  const searchQuery = opt(options, "search_query", "searchQuery");
621
633
  const maxResults = _nullishCoalesce(opt(options, "max_results", "maxResults"), () => ( 10));
622
- const precisionLevel = _nullishCoalesce(opt(options, "precision_level", "precisionLevel"), () => ( "high"));
623
634
  const queryDate = opt(options, "query_date", "queryDate");
624
635
  const perQuery = opt(options, "max_results_per_query", "maxResultsPerQuery");
625
636
  const responseShape = responseShapeOf(options);
626
- const mode = _nullishCoalesce(options.mode, () => ( "fast"));
637
+ const { mode, precisionLevel } = retrievalOptionsOf(options);
627
638
  if (searchQuery !== void 0 && !Array.isArray(searchQuery)) {
628
639
  throw new (0, _chunkT372OL3Qcjs.InvalidInputError)("search_query must be an array when provided");
629
640
  }
@@ -644,13 +655,15 @@ function buildFetchRequest(scope, options) {
644
655
  if (options.include_conversation_context === false) {
645
656
  body["include_conversation_context"] = false;
646
657
  }
658
+ const scopePath = opt(options, "scope_path", "scopePath");
659
+ if (scopePath !== void 0 && scopePath !== null && Object.keys(scopePath).length > 0) {
660
+ body["scope"] = scopePath;
661
+ }
647
662
  switch (scope) {
648
663
  case "user":
649
664
  {
650
665
  if (!userId) throw new (0, _chunkT372OL3Qcjs.InvalidInputError)("user_id is required");
651
666
  body["user_id"] = userId;
652
- const scopePath = opt(options, "scope_path", "scopePath");
653
- if (scopePath !== void 0) body["scope"] = scopePath;
654
667
  const contextMode = _nullishCoalesce(opt(options, "context_mode", "contextMode"), () => ( "in-conversation"));
655
668
  if (!VALID_CONTEXT_MODES.includes(contextMode)) {
656
669
  throw new (0, _chunkT372OL3Qcjs.InvalidInputError)(
@@ -697,19 +710,38 @@ function responseShapeOf(options) {
697
710
  }
698
711
  return shape;
699
712
  }
713
+ var VALID_MODES = ["fast", "accurate"];
714
+ var VALID_PRECISION = ["high", "medium"];
715
+ function retrievalOptionsOf(options) {
716
+ const mode = _nullishCoalesce(options.mode, () => ( "fast"));
717
+ if (!VALID_MODES.includes(mode)) {
718
+ throw new (0, _chunkT372OL3Qcjs.InvalidInputError)(
719
+ `Invalid mode '${mode}'. Must be one of: ${VALID_MODES.join(", ")}`
720
+ );
721
+ }
722
+ const precisionLevel = _nullishCoalesce(opt(options, "precision_level", "precisionLevel"), () => ( "high"));
723
+ if (!VALID_PRECISION.includes(precisionLevel)) {
724
+ throw new (0, _chunkT372OL3Qcjs.InvalidInputError)(
725
+ `Invalid precision_level '${precisionLevel}'. Must be one of: ${VALID_PRECISION.join(", ")}`
726
+ );
727
+ }
728
+ return { mode, precisionLevel };
729
+ }
700
730
  async function fetchContext(transport, scope, options = {}, hooks = {}) {
701
731
  const startedAt = Date.now();
732
+ await _optionalChain([transport, 'access', _25 => _25.ready, 'optionalCall', _26 => _26()]);
702
733
  transport.checkCustomerId(
703
734
  opt(options, "customer_id", "customerId"),
704
735
  `${scope}.context.fetch`
705
736
  );
706
737
  const responseShape = responseShapeOf(options);
738
+ retrievalOptionsOf(options);
707
739
  const network = async () => {
708
740
  const { endpoint, body } = buildFetchRequest(scope, options);
709
741
  const result = await transport.request(endpoint, { body });
710
- return applyResponseShape(_nullishCoalesce(_optionalChain([result, 'optionalAccess', _25 => _25["context"]]), () => ( {})), responseShape);
742
+ return applyResponseShape(_nullishCoalesce(_optionalChain([result, 'optionalAccess', _27 => _27["context"]]), () => ( {})), responseShape);
711
743
  };
712
- const anticipated = await _asyncNullishCoalesce(await _optionalChain([hooks, 'access', _26 => _26.beforeFetch, 'optionalCall', _27 => _27(scope, options)]), async () => ( null));
744
+ const anticipated = await _asyncNullishCoalesce(await _optionalChain([hooks, 'access', _28 => _28.beforeFetch, 'optionalCall', _29 => _29(scope, options)]), async () => ( null));
713
745
  if (anticipated !== null && anticipated.borderline) {
714
746
  const pending = network();
715
747
  pending.catch(() => void 0);
@@ -720,17 +752,17 @@ async function fetchContext(transport, scope, options = {}, hooks = {}) {
720
752
  const won = await Promise.race([pending.then((r) => r, () => null), late]);
721
753
  if (timer !== void 0) clearTimeout(timer);
722
754
  if (won !== null) {
723
- _optionalChain([hooks, 'access', _28 => _28.onAssembled, 'optionalCall', _29 => _29(scope, options, won, startedAt)]);
755
+ _optionalChain([hooks, 'access', _30 => _30.onAssembled, 'optionalCall', _31 => _31(scope, options, won, startedAt)]);
724
756
  return won;
725
757
  }
726
758
  }
727
759
  if (anticipated !== null) {
728
- _optionalChain([hooks, 'access', _30 => _30.onServedFromCache, 'optionalCall', _31 => _31(scope, options, anticipated)]);
729
- _optionalChain([hooks, 'access', _32 => _32.onAssembled, 'optionalCall', _33 => _33(scope, options, anticipated.response, startedAt)]);
760
+ _optionalChain([hooks, 'access', _32 => _32.onServedFromCache, 'optionalCall', _33 => _33(scope, options, anticipated)]);
761
+ _optionalChain([hooks, 'access', _34 => _34.onAssembled, 'optionalCall', _35 => _35(scope, options, anticipated.response, startedAt)]);
730
762
  return applyResponseShape(anticipated.response, responseShape);
731
763
  }
732
764
  const response = await network();
733
- _optionalChain([hooks, 'access', _34 => _34.onAssembled, 'optionalCall', _35 => _35(scope, options, response, startedAt)]);
765
+ _optionalChain([hooks, 'access', _36 => _36.onAssembled, 'optionalCall', _37 => _37(scope, options, response, startedAt)]);
734
766
  return response;
735
767
  }
736
768
 
@@ -1133,7 +1165,7 @@ function createMemoriesInterface(transport, onForgotten) {
1133
1165
  transport.checkCustomerId(_nullishCoalesce(o2["customer_id"], () => ( o2["customerId"])), "memories.forget");
1134
1166
  const body = buildForgetBody(options);
1135
1167
  const result = await transport.request("memories_forget", { body });
1136
- const removed = !!_optionalChain([result, 'optionalAccess', _36 => _36.deleted_ids, 'optionalAccess', _37 => _37.length]) || _optionalChain([result, 'optionalAccess', _38 => _38.status]) === "deleted" || _optionalChain([result, 'optionalAccess', _39 => _39.status]) === "partial";
1168
+ const removed = !!_optionalChain([result, 'optionalAccess', _38 => _38.deleted_ids, 'optionalAccess', _39 => _39.length]) || _optionalChain([result, 'optionalAccess', _40 => _40.status]) === "deleted" || _optionalChain([result, 'optionalAccess', _41 => _41.status]) === "partial";
1137
1169
  if (removed && onForgotten) {
1138
1170
  try {
1139
1171
  onForgotten({
@@ -1173,14 +1205,14 @@ function sleep2(ms, signal) {
1173
1205
  if (ms <= 0) return Promise.resolve();
1174
1206
  return new Promise((resolve, reject) => {
1175
1207
  const timer = setTimeout(() => {
1176
- _optionalChain([signal, 'optionalAccess', _40 => _40.removeEventListener, 'call', _41 => _41("abort", onAbort)]);
1208
+ _optionalChain([signal, 'optionalAccess', _42 => _42.removeEventListener, 'call', _43 => _43("abort", onAbort)]);
1177
1209
  resolve();
1178
1210
  }, ms);
1179
1211
  function onAbort() {
1180
1212
  clearTimeout(timer);
1181
- reject(_nullishCoalesce(_optionalChain([signal, 'optionalAccess', _42 => _42.reason]), () => ( new Error("Aborted"))));
1213
+ reject(_nullishCoalesce(_optionalChain([signal, 'optionalAccess', _44 => _44.reason]), () => ( new Error("Aborted"))));
1182
1214
  }
1183
- _optionalChain([signal, 'optionalAccess', _43 => _43.addEventListener, 'call', _44 => _44("abort", onAbort, { once: true })]);
1215
+ _optionalChain([signal, 'optionalAccess', _45 => _45.addEventListener, 'call', _46 => _46("abort", onAbort, { once: true })]);
1184
1216
  });
1185
1217
  }
1186
1218
 
@@ -1353,7 +1385,7 @@ function storedBatchRows(bodies, result) {
1353
1385
  const r = _nullishCoalesce(result, () => ( {}));
1354
1386
  const results = Array.isArray(r["results"]) ? r["results"] : [];
1355
1387
  const errors = Array.isArray(r["errors"]) ? r["errors"] : [];
1356
- const failed = new Set(errors.map((e) => _optionalChain([e, 'optionalAccess', _45 => _45["index"]])));
1388
+ const failed = new Set(errors.map((e) => _optionalChain([e, 'optionalAccess', _47 => _47["index"]])));
1357
1389
  const stored = bodies.filter((_, index) => !failed.has(index));
1358
1390
  if (stored.length !== results.length) return [];
1359
1391
  const pairs = [];
@@ -1499,8 +1531,8 @@ function createConversationNamespace(transport, subscribers = new CompactionSubs
1499
1531
  pathParams: { conversation_id: id },
1500
1532
  query: { style: _nullishCoalesce(options.style, () => ( "structured")) }
1501
1533
  });
1502
- const response = _nullishCoalesce(_nullishCoalesce(_optionalChain([result, 'optionalAccess', _46 => _46["context_for_prompt"]]), () => ( result)), () => ( {}));
1503
- _optionalChain([localShortTerm, 'access', _47 => _47.reseed, 'optionalCall', _48 => _48(id, response)]);
1534
+ const response = _nullishCoalesce(_nullishCoalesce(_optionalChain([result, 'optionalAccess', _48 => _48["context_for_prompt"]]), () => ( result)), () => ( {}));
1535
+ _optionalChain([localShortTerm, 'access', _49 => _49.reseed, 'optionalCall', _50 => _50(id, response)]);
1504
1536
  return withHistory(response);
1505
1537
  },
1506
1538
  async compact(options) {
@@ -1693,8 +1725,8 @@ function createInstanceNamespace(credentials, cache, onTurn, agentModel = () =>
1693
1725
  let onConversationState = null;
1694
1726
  const internals = {
1695
1727
  onCompactionUpdate(conversationId, bundle) {
1696
- _optionalChain([applyCompaction, 'optionalCall', _49 => _49(bundle)]);
1697
- _optionalChain([dispatchCompaction, 'optionalCall', _50 => _50(conversationId, bundle)]);
1728
+ _optionalChain([applyCompaction, 'optionalCall', _51 => _51(bundle)]);
1729
+ _optionalChain([dispatchCompaction, 'optionalCall', _52 => _52(conversationId, bundle)]);
1698
1730
  },
1699
1731
  setCompactionApplier(apply) {
1700
1732
  applyCompaction = apply;
@@ -1706,10 +1738,10 @@ function createInstanceNamespace(credentials, cache, onTurn, agentModel = () =>
1706
1738
  onConversationState = handle;
1707
1739
  },
1708
1740
  sendContextUsed(event) {
1709
- _optionalChain([client, 'optionalAccess', _51 => _51.sendContextUsed, 'call', _52 => _52(event)]);
1741
+ _optionalChain([client, 'optionalAccess', _53 => _53.sendContextUsed, 'call', _54 => _54(event)]);
1710
1742
  },
1711
1743
  sendContextAssembled(event) {
1712
- _optionalChain([client, 'optionalAccess', _53 => _53.sendContextAssembled, 'call', _54 => _54(event)]);
1744
+ _optionalChain([client, 'optionalAccess', _55 => _55.sendContextAssembled, 'call', _56 => _56(event)]);
1713
1745
  },
1714
1746
  setCompactionDispatcher(dispatch) {
1715
1747
  dispatchCompaction = dispatch;
@@ -1740,7 +1772,7 @@ function createInstanceNamespace(credentials, cache, onTurn, agentModel = () =>
1740
1772
  throw new (0, _chunkT372OL3Qcjs.ListeningAlreadyActiveError)("Listening is already active on this instance");
1741
1773
  }
1742
1774
  try {
1743
- _optionalChain([onListen, 'optionalCall', _55 => _55()]);
1775
+ _optionalChain([onListen, 'optionalCall', _57 => _57()]);
1744
1776
  } catch (e10) {
1745
1777
  }
1746
1778
  const { GrpcStreamClient } = await Promise.resolve().then(() => _interopRequireWildcard(require("./stream-client-L6OQPZN7.cjs")));
@@ -1758,17 +1790,17 @@ function createInstanceNamespace(credentials, cache, onTurn, agentModel = () =>
1758
1790
  internals.onCompactionUpdate(conversationId, bundle);
1759
1791
  },
1760
1792
  onConversationState: (conversationId, messageCount) => {
1761
- _optionalChain([onConversationState, 'optionalCall', _56 => _56(conversationId, messageCount)]);
1793
+ _optionalChain([onConversationState, 'optionalCall', _58 => _58(conversationId, messageCount)]);
1762
1794
  },
1763
1795
  onStateChange: (state) => {
1764
1796
  if (state !== "connected") openSessions.clear();
1765
1797
  if (state === "reconnecting") {
1766
1798
  reconnectAttempts += 1;
1767
- _optionalChain([onReconnect, 'optionalCall', _57 => _57(reconnectAttempts)]);
1799
+ _optionalChain([onReconnect, 'optionalCall', _59 => _59(reconnectAttempts)]);
1768
1800
  } else if (state === "disconnected") {
1769
- const stopped = _nullishCoalesce(_optionalChain([stream, 'optionalAccess', _58 => _58.lastError]), () => ( null));
1801
+ const stopped = _nullishCoalesce(_optionalChain([stream, 'optionalAccess', _60 => _60.lastError]), () => ( null));
1770
1802
  const reason = stopped === null ? "stream disconnected" : `credit_stop:${_nullishCoalesce(stopped.reason, () => ( "unknown"))}`;
1771
- _optionalChain([onDisconnect, 'optionalCall', _59 => _59(reason)]);
1803
+ _optionalChain([onDisconnect, 'optionalCall', _61 => _61(reason)]);
1772
1804
  }
1773
1805
  }
1774
1806
  });
@@ -1778,7 +1810,7 @@ function createInstanceNamespace(credentials, cache, onTurn, agentModel = () =>
1778
1810
  } catch (error) {
1779
1811
  if (error instanceof _chunkT372OL3Qcjs.SynapError) throw error;
1780
1812
  throw new (0, _chunkT372OL3Qcjs.SynapError)(
1781
- `Could not open the Synap anticipation stream: ${_nullishCoalesce(_optionalChain([error, 'optionalAccess', _60 => _60.message]), () => ( String(error)))}`,
1813
+ `Could not open the Synap anticipation stream: ${_nullishCoalesce(_optionalChain([error, 'optionalAccess', _62 => _62.message]), () => ( String(error)))}`,
1782
1814
  { cause: error }
1783
1815
  );
1784
1816
  }
@@ -1824,7 +1856,7 @@ function createInstanceNamespace(credentials, cache, onTurn, agentModel = () =>
1824
1856
  _nullishCoalesce(_nullishCoalesce(options.customer_id, () => ( options.customerId)), () => ( ""))
1825
1857
  );
1826
1858
  if (eventType === "user_message" || eventType === "assistant_message") {
1827
- _optionalChain([onTurn, 'optionalCall', _61 => _61({
1859
+ _optionalChain([onTurn, 'optionalCall', _63 => _63({
1828
1860
  conversationId,
1829
1861
  role: _nullishCoalesce(options.role, () => ( "user")),
1830
1862
  content: options.content
@@ -1870,7 +1902,7 @@ function createInstanceNamespace(credentials, cache, onTurn, agentModel = () =>
1870
1902
  async record_tool_result(options) {
1871
1903
  const conversationId = _nullishCoalesce(_nullishCoalesce(options.conversation_id, () => ( options.conversationId)), () => ( ""));
1872
1904
  if (conversationId) {
1873
- _optionalChain([onToolResult, 'optionalCall', _62 => _62({ conversationId, result: options.result, toolName: _nullishCoalesce(_nullishCoalesce(options.tool_name, () => ( options.toolName)), () => ( "")) })]);
1905
+ _optionalChain([onToolResult, 'optionalCall', _64 => _64({ conversationId, result: options.result, toolName: _nullishCoalesce(_nullishCoalesce(options.tool_name, () => ( options.toolName)), () => ( "")) })]);
1874
1906
  }
1875
1907
  await namespace.send_message({
1876
1908
  content: "",
@@ -1922,7 +1954,7 @@ function createInstanceNamespace(credentials, cache, onTurn, agentModel = () =>
1922
1954
  }
1923
1955
 
1924
1956
  // src/version.ts
1925
- var SDK_VERSION = "0.5.9";
1957
+ var SDK_VERSION = "0.5.10";
1926
1958
 
1927
1959
  // src/registry.ts
1928
1960
  var instances = /* @__PURE__ */ new Map();
@@ -2269,13 +2301,13 @@ function bytesOf(text) {
2269
2301
  }
2270
2302
  var TurnStore = (_class3 = class {
2271
2303
 
2272
- __init4() {this.onDisk = false}
2304
+ __init5() {this.onDisk = false}
2273
2305
  #now;
2274
2306
  #seq = 0;
2275
2307
  #writes = 0;
2276
2308
  #conversations = /* @__PURE__ */ new Map();
2277
2309
  #vectors = /* @__PURE__ */ new Map();
2278
- constructor(options = {}) {;_class3.prototype.__init4.call(this);
2310
+ constructor(options = {}) {;_class3.prototype.__init5.call(this);
2279
2311
  this.limits = _nullishCoalesce(options.limits, () => ( { ..._chunkICUFS3B5cjs.HISTORY_SEARCH.store_limits }));
2280
2312
  this.#now = _nullishCoalesce(options.now, () => ( (() => Date.now() / 1e3)));
2281
2313
  }
@@ -2390,7 +2422,7 @@ var TurnStore = (_class3 = class {
2390
2422
  }
2391
2423
  /** Turns the server also holds: archived tool results are local only. Python: `count`. */
2392
2424
  count(conversationId) {
2393
- return (_nullishCoalesce(_optionalChain([this, 'access', _63 => _63.#conversations, 'access', _64 => _64.get, 'call', _65 => _65(conversationId), 'optionalAccess', _66 => _66.turns]), () => ( []))).filter((t) => t.role !== "tool").length;
2425
+ return (_nullishCoalesce(_optionalChain([this, 'access', _65 => _65.#conversations, 'access', _66 => _66.get, 'call', _67 => _67(conversationId), 'optionalAccess', _68 => _68.turns]), () => ( []))).filter((t) => t.role !== "tool").length;
2394
2426
  }
2395
2427
  sizeBytes() {
2396
2428
  let n2 = 0;
@@ -2569,7 +2601,7 @@ function askedKinds(query) {
2569
2601
  }
2570
2602
  function asksHowItStarted(query) {
2571
2603
  const spec = _chunkICUFS3B5cjs.HISTORY_SEARCH.early_query;
2572
- if (!_optionalChain([spec, 'optionalAccess', _67 => _67.pattern])) return false;
2604
+ if (!_optionalChain([spec, 'optionalAccess', _69 => _69.pattern])) return false;
2573
2605
  return new RegExp(spec.pattern, (_nullishCoalesce(spec.flags, () => ( ""))).includes("i") ? "i" : "").test(_nullishCoalesce(query, () => ( "")));
2574
2606
  }
2575
2607
  async function searchTurns(turns, query, options = {}) {
@@ -3648,6 +3680,7 @@ var SynapClient = (_class4 = class _SynapClient {
3648
3680
 
3649
3681
  #closed = false;
3650
3682
  #initialized = false;
3683
+ #identity;
3651
3684
  #registryKeys;
3652
3685
  #compactionSubscribers;
3653
3686
  #shortTerm;
@@ -3698,6 +3731,7 @@ var SynapClient = (_class4 = class _SynapClient {
3698
3731
  userAgent: `@maximem/synap-js-sdk/${SDK_VERSION}`
3699
3732
  });
3700
3733
  if (options.heartbeat) this.#transport.startHeartbeat();
3734
+ this.#transport.identityResolver = () => this.#resolveIdentity();
3701
3735
  this.#anticipationCache = new (0, _chunkICUFS3B5cjs.AnticipationCache)();
3702
3736
  this.#fetchHooks = {
3703
3737
  beforeFetch: async (scope, options2) => {
@@ -3757,7 +3791,7 @@ var SynapClient = (_class4 = class _SynapClient {
3757
3791
  this.#localEncoder = _nullishCoalesce(_nullishCoalesce(options.history_search_encoder, () => ( options.historySearchEncoder)), () => ( null));
3758
3792
  const modelOption = options.history_search_model !== void 0 ? options.history_search_model : options.historySearchModel;
3759
3793
  this.#localModelName = modelOption === void 0 ? "auto" : modelOption;
3760
- if (_optionalChain([this, 'access', _68 => _68.#localEncoder, 'optionalAccess', _69 => _69.model]) === _chunkICUFS3B5cjs.SEMANTIC_MATCH.model) this.#anticipationCache.setEncoder(this.#localEncoder);
3794
+ if (_optionalChain([this, 'access', _70 => _70.#localEncoder, 'optionalAccess', _71 => _71.model]) === _chunkICUFS3B5cjs.SEMANTIC_MATCH.model) this.#anticipationCache.setEncoder(this.#localEncoder);
3761
3795
  this.#turns = new TurnCounter();
3762
3796
  this.conversation = createConversationNamespace(
3763
3797
  this.#transport,
@@ -3903,19 +3937,30 @@ var SynapClient = (_class4 = class _SynapClient {
3903
3937
  /**
3904
3938
  * Resolve `client_id` and `instance_id` from the API key.
3905
3939
  *
3906
- * Mirrors Python's `initialize()`. Calling it is optional here (unlike
3907
- * Python, which raises "SDK not initialized" from `_ensure_initialized`)
3908
- * because every HTTP route authenticates on the API key alone. It matters
3909
- * for the anticipation cache: a bundle shared at client scope is filtered on
3910
- * `client_id`, and an empty one fails that filter for every bundle. That was
3911
- * a silent cache-scope bug in Python before whoami bootstrapping existed.
3940
+ * Mirrors Python's `initialize()`. Python raises "SDK not initialized" on
3941
+ * any call made before it; here the first request runs the same resolution
3942
+ * instead (`identityResolver` on the transport), so skipping this call costs
3943
+ * nothing and breaks no existing caller. It matters for the anticipation
3944
+ * cache: a bundle shared at client scope is filtered on `client_id`, and an
3945
+ * empty one fails that filter for every bundle.
3946
+ *
3947
+ * Calling it explicitly still locks `configure()`, as in Python. Resolving
3948
+ * on first use does not, because a caller who never called it could always
3949
+ * configure after a request, and that keeps working.
3912
3950
  *
3913
3951
  * Best-effort and idempotent. A whoami failure leaves whatever the
3914
3952
  * constructor resolved and is not fatal.
3915
3953
  */
3916
3954
  async initialize() {
3917
- if (this.#initialized) return;
3918
3955
  this.#initialized = true;
3956
+ await this.#resolveIdentity();
3957
+ }
3958
+ /** Runs whoami at most once, however many calls arrive together. */
3959
+ #resolveIdentity() {
3960
+ this.#identity ??= this.#whoami();
3961
+ return this.#identity;
3962
+ }
3963
+ async #whoami() {
3919
3964
  const credentials = this.#transport.currentCredentials();
3920
3965
  if (credentials.clientId !== "" && credentials.instanceId !== "") return;
3921
3966
  try {
@@ -4236,14 +4281,14 @@ var SynapClient = (_class4 = class _SynapClient {
4236
4281
  }))
4237
4282
  );
4238
4283
  const entry = this.#shortTerm.get(conversationId);
4239
- const total = Math.max(Number(_nullishCoalesce(r["total_message_count"], () => ( 0))) || 0, Number(_nullishCoalesce(_optionalChain([entry, 'optionalAccess', _70 => _70.serverMessageCount]), () => ( 0))) || 0);
4284
+ const total = Math.max(Number(_nullishCoalesce(r["total_message_count"], () => ( 0))) || 0, Number(_nullishCoalesce(_optionalChain([entry, 'optionalAccess', _72 => _72.serverMessageCount]), () => ( 0))) || 0);
4240
4285
  this.#maybeBackfillTurns(conversationId, total);
4241
4286
  if (!r["context_block"]) return response;
4242
4287
  const turns = store.turns(conversationId);
4243
4288
  let q = query;
4244
4289
  if (!q) {
4245
4290
  const latest = [...recent].reverse().find((m) => m["role"] === "user");
4246
- q = latest ? String(_nullishCoalesce(latest["content"], () => ( ""))) : _nullishCoalesce(_optionalChain([[...turns], 'access', _71 => _71.reverse, 'call', _72 => _72(), 'access', _73 => _73.find, 'call', _74 => _74((t) => t.role === "user"), 'optionalAccess', _75 => _75.content]), () => ( ""));
4291
+ q = latest ? String(_nullishCoalesce(latest["content"], () => ( ""))) : _nullishCoalesce(_optionalChain([[...turns], 'access', _73 => _73.reverse, 'call', _74 => _74(), 'access', _75 => _75.find, 'call', _76 => _76((t) => t.role === "user"), 'optionalAccess', _77 => _77.content]), () => ( ""));
4247
4292
  }
4248
4293
  if (!q) return response;
4249
4294
  const exclude = /* @__PURE__ */ new Set();
@@ -4387,7 +4432,7 @@ function pick3(o2, snake, camel) {
4387
4432
  function resolveBaseUrl(options) {
4388
4433
  const explicit = _nullishCoalesce(options.baseUrl, () => ( options.api_base_url));
4389
4434
  if (explicit !== void 0) return explicit;
4390
- const fromEnv = _optionalChain([_chunkZKOJDUN4cjs.getEnv.call(void 0, "SYNAP_BASE_URL"), 'optionalAccess', _76 => _76.trim, 'call', _77 => _77()]);
4435
+ const fromEnv = _optionalChain([_chunkZKOJDUN4cjs.getEnv.call(void 0, "SYNAP_BASE_URL"), 'optionalAccess', _78 => _78.trim, 'call', _79 => _79()]);
4391
4436
  return fromEnv !== void 0 && fromEnv !== "" ? fromEnv : void 0;
4392
4437
  }
4393
4438
  function resolveCredentials(options) {