@maximem/synap-js-sdk 0.5.11 → 0.5.13

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.cjs CHANGED
@@ -408,22 +408,40 @@ function isOutcomeUnknown(error) {
408
408
  if (error instanceof _chunkUXNVTP4Dcjs.ConflictError) return false;
409
409
  if (error instanceof _chunkUXNVTP4Dcjs.InsufficientCreditsError) return false;
410
410
  if (error instanceof _chunkUXNVTP4Dcjs.ContextNotFoundError) return false;
411
- if (error instanceof _chunkUXNVTP4Dcjs.NetworkTimeoutError) return true;
412
411
  if (isConnectionRefusal(error)) return false;
412
+ if (error instanceof _chunkUXNVTP4Dcjs.NetworkTimeoutError) return true;
413
413
  return true;
414
414
  }
415
+ var CONNECTION_REFUSAL_CODES = /* @__PURE__ */ new Set([
416
+ "ECONNREFUSED",
417
+ "ENOTFOUND",
418
+ "EAI_AGAIN",
419
+ "ECONNRESET",
420
+ "EHOSTUNREACH"
421
+ ]);
415
422
  function isConnectionRefusal(error) {
416
- const code = _nullishCoalesce(_optionalChain([error, 'optionalAccess', _10 => _10.cause, 'optionalAccess', _11 => _11.code]), () => ( _optionalChain([error, 'optionalAccess', _12 => _12.code])));
417
- return code === "ECONNREFUSED" || code === "ENOTFOUND" || code === "EAI_AGAIN" || code === "ECONNRESET" || code === "EHOSTUNREACH";
423
+ let cur = error;
424
+ for (let depth = 0; depth < 4 && cur !== null && typeof cur === "object"; depth += 1) {
425
+ const code = cur.code;
426
+ if (typeof code === "string" && CONNECTION_REFUSAL_CODES.has(code)) return true;
427
+ cur = cur.cause;
428
+ }
429
+ return false;
418
430
  }
419
431
  function toTransportError(error, correlationId) {
420
432
  if (error instanceof _chunkUXNVTP4Dcjs.SynapError) return error;
421
- const name = _optionalChain([error, 'optionalAccess', _13 => _13.name]);
433
+ const name = _optionalChain([error, 'optionalAccess', _10 => _10.name]);
422
434
  if (name === "AbortError" || name === "TimeoutError") {
423
435
  return new (0, _chunkUXNVTP4Dcjs.NetworkTimeoutError)("Request timed out", { correlationId, cause: error });
424
436
  }
437
+ if (isConnectionRefusal(error)) {
438
+ return new (0, _chunkUXNVTP4Dcjs.NetworkTimeoutError)(
439
+ `Connection failed: ${_nullishCoalesce(_optionalChain([error, 'optionalAccess', _11 => _11.message]), () => ( String(error)))}`,
440
+ { correlationId, cause: error }
441
+ );
442
+ }
425
443
  return new (0, _chunkUXNVTP4Dcjs.ServiceUnavailableError)(
426
- `Network request failed: ${_nullishCoalesce(_optionalChain([error, 'optionalAccess', _14 => _14.message]), () => ( String(error)))}`,
444
+ `Network request failed: ${_nullishCoalesce(_optionalChain([error, 'optionalAccess', _12 => _12.message]), () => ( String(error)))}`,
427
445
  { correlationId, cause: error }
428
446
  );
429
447
  }
@@ -504,11 +522,11 @@ function stringOrNull(v) {
504
522
  }
505
523
  function withTimeout(ms, external) {
506
524
  const controller = new AbortController();
507
- const onExternalAbort = () => controller.abort(_optionalChain([external, 'optionalAccess', _15 => _15.reason]));
525
+ const onExternalAbort = () => controller.abort(_optionalChain([external, 'optionalAccess', _13 => _13.reason]));
508
526
  const timer = setTimeout(() => {
509
527
  controller.abort(new (0, _chunkUXNVTP4Dcjs.NetworkTimeoutError)(`Timed out after ${ms}ms`));
510
528
  }, ms);
511
- _optionalChain([timer, 'access', _16 => _16.unref, 'optionalCall', _17 => _17()]);
529
+ _optionalChain([timer, 'access', _14 => _14.unref, 'optionalCall', _15 => _15()]);
512
530
  if (external) {
513
531
  if (external.aborted) onExternalAbort();
514
532
  else external.addEventListener("abort", onExternalAbort, { once: true });
@@ -517,7 +535,7 @@ function withTimeout(ms, external) {
517
535
  signal: controller.signal,
518
536
  dispose() {
519
537
  clearTimeout(timer);
520
- _optionalChain([external, 'optionalAccess', _18 => _18.removeEventListener, 'call', _19 => _19("abort", onExternalAbort)]);
538
+ _optionalChain([external, 'optionalAccess', _16 => _16.removeEventListener, 'call', _17 => _17("abort", onExternalAbort)]);
521
539
  }
522
540
  };
523
541
  }
@@ -525,14 +543,14 @@ function sleep(ms, signal) {
525
543
  if (ms <= 0) return Promise.resolve();
526
544
  return new Promise((resolve, reject) => {
527
545
  const timer = setTimeout(() => {
528
- _optionalChain([signal, 'optionalAccess', _20 => _20.removeEventListener, 'call', _21 => _21("abort", onAbort)]);
546
+ _optionalChain([signal, 'optionalAccess', _18 => _18.removeEventListener, 'call', _19 => _19("abort", onAbort)]);
529
547
  resolve();
530
548
  }, ms);
531
549
  function onAbort() {
532
550
  clearTimeout(timer);
533
- reject(_nullishCoalesce(_optionalChain([signal, 'optionalAccess', _22 => _22.reason]), () => ( new Error("Aborted"))));
551
+ reject(_nullishCoalesce(_optionalChain([signal, 'optionalAccess', _20 => _20.reason]), () => ( new Error("Aborted"))));
534
552
  }
535
- _optionalChain([signal, 'optionalAccess', _23 => _23.addEventListener, 'call', _24 => _24("abort", onAbort, { once: true })]);
553
+ _optionalChain([signal, 'optionalAccess', _21 => _21.addEventListener, 'call', _22 => _22("abort", onAbort, { once: true })]);
536
554
  });
537
555
  }
538
556
 
@@ -639,6 +657,7 @@ function buildFetchRequest(scope, options) {
639
657
  const perQuery = opt(options, "max_results_per_query", "maxResultsPerQuery");
640
658
  const responseShape = responseShapeOf(options);
641
659
  const { mode, precisionLevel } = retrievalOptionsOf(options);
660
+ const { contextMode, lastN } = scopeOptionsOf(scope, options);
642
661
  if (searchQuery !== void 0 && !Array.isArray(searchQuery)) {
643
662
  throw new (0, _chunkUXNVTP4Dcjs.InvalidInputError)("search_query must be an array when provided");
644
663
  }
@@ -666,21 +685,7 @@ function buildFetchRequest(scope, options) {
666
685
  switch (scope) {
667
686
  case "user":
668
687
  {
669
- if (!userId) throw new (0, _chunkUXNVTP4Dcjs.InvalidInputError)("user_id is required");
670
688
  body["user_id"] = userId;
671
- const contextMode = _nullishCoalesce(opt(options, "context_mode", "contextMode"), () => ( "in-conversation"));
672
- if (!VALID_CONTEXT_MODES.includes(contextMode)) {
673
- throw new (0, _chunkUXNVTP4Dcjs.InvalidInputError)(
674
- `Invalid context_mode '${contextMode}'. Must be one of: ${VALID_CONTEXT_MODES.join(", ")}`
675
- );
676
- }
677
- const lastN = _nullishCoalesce(opt(options, "last_n_conversations", "lastNConversations"), () => ( 1));
678
- if (!Number.isInteger(lastN)) {
679
- throw new (0, _chunkUXNVTP4Dcjs.InvalidInputError)("last_n_conversations must be an integer");
680
- }
681
- if (lastN < 0 || lastN > 20) {
682
- throw new (0, _chunkUXNVTP4Dcjs.InvalidInputError)("last_n_conversations must be between 0 and 20");
683
- }
684
689
  if (contextMode === "conversation-summary") {
685
690
  body["context_mode"] = contextMode;
686
691
  body["include_profile"] = _nullishCoalesce(opt(options, "include_profile", "includeProfile"), () => ( true));
@@ -691,11 +696,9 @@ function buildFetchRequest(scope, options) {
691
696
  }
692
697
  break;
693
698
  case "customer":
694
- if (!customerId) throw new (0, _chunkUXNVTP4Dcjs.InvalidInputError)("customer_id is required");
695
699
  body["customer_id"] = customerId;
696
700
  break;
697
701
  case "conversation":
698
- if (!conversationId) throw new (0, _chunkUXNVTP4Dcjs.InvalidInputError)("conversation_id is required");
699
702
  if (userId !== void 0) body["user_id"] = userId;
700
703
  if (customerId !== void 0) body["customer_id"] = customerId;
701
704
  break;
@@ -714,6 +717,33 @@ function responseShapeOf(options) {
714
717
  }
715
718
  return shape;
716
719
  }
720
+ var REQUIRED_ID = {
721
+ user: ["user_id", "userId"],
722
+ customer: ["customer_id", "customerId"],
723
+ conversation: ["conversation_id", "conversationId"],
724
+ client: null
725
+ };
726
+ function scopeOptionsOf(scope, options) {
727
+ const required = REQUIRED_ID[scope];
728
+ if (required !== null && !opt(options, required[0], required[1])) {
729
+ throw new (0, _chunkUXNVTP4Dcjs.InvalidInputError)(`${required[0]} is required`);
730
+ }
731
+ const contextMode = _nullishCoalesce(opt(options, "context_mode", "contextMode"), () => ( "in-conversation"));
732
+ const lastN = _nullishCoalesce(opt(options, "last_n_conversations", "lastNConversations"), () => ( 1));
733
+ if (scope !== "user") return { contextMode, lastN };
734
+ if (!VALID_CONTEXT_MODES.includes(contextMode)) {
735
+ throw new (0, _chunkUXNVTP4Dcjs.InvalidInputError)(
736
+ `Invalid context_mode '${contextMode}'. Must be one of: ${VALID_CONTEXT_MODES.join(", ")}`
737
+ );
738
+ }
739
+ if (!Number.isInteger(lastN)) {
740
+ throw new (0, _chunkUXNVTP4Dcjs.InvalidInputError)("last_n_conversations must be an integer");
741
+ }
742
+ if (lastN < 0 || lastN > 20) {
743
+ throw new (0, _chunkUXNVTP4Dcjs.InvalidInputError)("last_n_conversations must be between 0 and 20");
744
+ }
745
+ return { contextMode, lastN };
746
+ }
717
747
  var VALID_MODES = ["fast", "accurate"];
718
748
  var VALID_PRECISION = ["high", "medium"];
719
749
  function retrievalOptionsOf(options) {
@@ -733,19 +763,30 @@ function retrievalOptionsOf(options) {
733
763
  }
734
764
  async function fetchContext(transport, scope, options = {}, hooks = {}) {
735
765
  const startedAt = Date.now();
736
- await _optionalChain([transport, 'access', _25 => _25.ready, 'optionalCall', _26 => _26()]);
766
+ await _optionalChain([transport, 'access', _23 => _23.ready, 'optionalCall', _24 => _24()]);
737
767
  await transport.checkCustomerId(
738
768
  opt(options, "customer_id", "customerId"),
739
769
  `${scope}.context.fetch`
740
770
  );
741
771
  const responseShape = responseShapeOf(options);
742
772
  retrievalOptionsOf(options);
773
+ const { contextMode } = scopeOptionsOf(scope, options);
774
+ const summaryMode = scope === "user" && contextMode === "conversation-summary";
775
+ const finish = (response2) => {
776
+ _optionalChain([hooks, 'access', _25 => _25.onResponse, 'optionalCall', _26 => _26(scope, options, response2)]);
777
+ return response2;
778
+ };
779
+ const conversationId = opt(options, "conversation_id", "conversationId");
780
+ const skipServerSt = conversationId ? _optionalChain([hooks, 'access', _27 => _27.skipServerShortTerm, 'optionalCall', _28 => _28(conversationId)]) === true : false;
743
781
  const network = async () => {
744
- const { endpoint, body } = buildFetchRequest(scope, options);
782
+ const { endpoint, body } = buildFetchRequest(
783
+ scope,
784
+ skipServerSt ? { ...options, include_conversation_context: false } : options
785
+ );
745
786
  const result = await transport.request(endpoint, { body });
746
- return applyResponseShape(_nullishCoalesce(_optionalChain([result, 'optionalAccess', _27 => _27["context"]]), () => ( {})), responseShape);
787
+ return applyResponseShape(_nullishCoalesce(_optionalChain([result, 'optionalAccess', _29 => _29["context"]]), () => ( {})), responseShape);
747
788
  };
748
- const anticipated = await _asyncNullishCoalesce(await _optionalChain([hooks, 'access', _28 => _28.beforeFetch, 'optionalCall', _29 => _29(scope, options)]), async () => ( null));
789
+ const anticipated = summaryMode ? null : await _asyncNullishCoalesce(await _optionalChain([hooks, 'access', _30 => _30.beforeFetch, 'optionalCall', _31 => _31(scope, options)]), async () => ( null));
749
790
  if (anticipated !== null && anticipated.borderline) {
750
791
  const pending = network();
751
792
  pending.catch(() => void 0);
@@ -756,18 +797,18 @@ async function fetchContext(transport, scope, options = {}, hooks = {}) {
756
797
  const won = await Promise.race([pending.then((r) => r, () => null), late]);
757
798
  if (timer !== void 0) clearTimeout(timer);
758
799
  if (won !== null) {
759
- _optionalChain([hooks, 'access', _30 => _30.onAssembled, 'optionalCall', _31 => _31(scope, options, won, startedAt)]);
760
- return won;
800
+ _optionalChain([hooks, 'access', _32 => _32.onAssembled, 'optionalCall', _33 => _33(scope, options, won, startedAt)]);
801
+ return finish(won);
761
802
  }
762
803
  }
763
804
  if (anticipated !== null) {
764
- _optionalChain([hooks, 'access', _32 => _32.onServedFromCache, 'optionalCall', _33 => _33(scope, options, anticipated)]);
765
- _optionalChain([hooks, 'access', _34 => _34.onAssembled, 'optionalCall', _35 => _35(scope, options, anticipated.response, startedAt)]);
766
- return applyResponseShape(anticipated.response, responseShape);
805
+ _optionalChain([hooks, 'access', _34 => _34.onServedFromCache, 'optionalCall', _35 => _35(scope, options, anticipated)]);
806
+ _optionalChain([hooks, 'access', _36 => _36.onAssembled, 'optionalCall', _37 => _37(scope, options, anticipated.response, startedAt)]);
807
+ return finish(applyResponseShape(anticipated.response, responseShape));
767
808
  }
768
809
  const response = await network();
769
- _optionalChain([hooks, 'access', _36 => _36.onAssembled, 'optionalCall', _37 => _37(scope, options, response, startedAt)]);
770
- return response;
810
+ _optionalChain([hooks, 'access', _38 => _38.onAssembled, 'optionalCall', _39 => _39(scope, options, response, startedAt)]);
811
+ return finish(response);
771
812
  }
772
813
 
773
814
  // src/context/normalize.ts
@@ -1169,7 +1210,7 @@ function createMemoriesInterface(transport, onForgotten) {
1169
1210
  await transport.checkCustomerId(_nullishCoalesce(o2["customer_id"], () => ( o2["customerId"])), "memories.forget");
1170
1211
  const body = buildForgetBody(options);
1171
1212
  const result = await transport.request("memories_forget", { body });
1172
- 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";
1213
+ const removed = !!_optionalChain([result, 'optionalAccess', _40 => _40.deleted_ids, 'optionalAccess', _41 => _41.length]) || _optionalChain([result, 'optionalAccess', _42 => _42.status]) === "deleted" || _optionalChain([result, 'optionalAccess', _43 => _43.status]) === "partial";
1173
1214
  if (removed && onForgotten) {
1174
1215
  try {
1175
1216
  onForgotten({
@@ -1209,14 +1250,14 @@ function sleep2(ms, signal) {
1209
1250
  if (ms <= 0) return Promise.resolve();
1210
1251
  return new Promise((resolve, reject) => {
1211
1252
  const timer = setTimeout(() => {
1212
- _optionalChain([signal, 'optionalAccess', _42 => _42.removeEventListener, 'call', _43 => _43("abort", onAbort)]);
1253
+ _optionalChain([signal, 'optionalAccess', _44 => _44.removeEventListener, 'call', _45 => _45("abort", onAbort)]);
1213
1254
  resolve();
1214
1255
  }, ms);
1215
1256
  function onAbort() {
1216
1257
  clearTimeout(timer);
1217
- reject(_nullishCoalesce(_optionalChain([signal, 'optionalAccess', _44 => _44.reason]), () => ( new Error("Aborted"))));
1258
+ reject(_nullishCoalesce(_optionalChain([signal, 'optionalAccess', _46 => _46.reason]), () => ( new Error("Aborted"))));
1218
1259
  }
1219
- _optionalChain([signal, 'optionalAccess', _45 => _45.addEventListener, 'call', _46 => _46("abort", onAbort, { once: true })]);
1260
+ _optionalChain([signal, 'optionalAccess', _47 => _47.addEventListener, 'call', _48 => _48("abort", onAbort, { once: true })]);
1220
1261
  });
1221
1262
  }
1222
1263
 
@@ -1389,7 +1430,7 @@ function storedBatchRows(bodies, result) {
1389
1430
  const r = _nullishCoalesce(result, () => ( {}));
1390
1431
  const results = Array.isArray(r["results"]) ? r["results"] : [];
1391
1432
  const errors = Array.isArray(r["errors"]) ? r["errors"] : [];
1392
- const failed = new Set(errors.map((e) => _optionalChain([e, 'optionalAccess', _47 => _47["index"]])));
1433
+ const failed = new Set(errors.map((e) => _optionalChain([e, 'optionalAccess', _49 => _49["index"]])));
1393
1434
  const stored = bodies.filter((_, index) => !failed.has(index));
1394
1435
  if (stored.length !== results.length) return [];
1395
1436
  const pairs = [];
@@ -1402,7 +1443,7 @@ function storedBatchRows(bodies, result) {
1402
1443
  function createConversationNamespace(transport, subscribers = new CompactionSubscribers(), onWrite = () => {
1403
1444
  }, onTurn = () => {
1404
1445
  }, onFetched = () => {
1405
- }, localShortTerm = { prompt: () => null, compacted: () => null }, agentModel = () => ({})) {
1446
+ }, localShortTerm = { prompt: () => null, compacted: () => null }, agentModel = () => ({}), fetchHooks = {}) {
1406
1447
  const writesInFlight = /* @__PURE__ */ new Map();
1407
1448
  const withTurnModel = (body, options) => {
1408
1449
  const metadata = withAgentModel(
@@ -1509,7 +1550,7 @@ function createConversationNamespace(transport, subscribers = new CompactionSubs
1509
1550
  async fetch(options = {}) {
1510
1551
  const id = _nullishCoalesce(options.conversation_id, () => ( options.conversationId));
1511
1552
  validateConversationId(id);
1512
- const response = await fetchContext(transport, "conversation", options);
1553
+ const response = await fetchContext(transport, "conversation", options, fetchHooks);
1513
1554
  onFetched(
1514
1555
  response,
1515
1556
  id,
@@ -1535,8 +1576,8 @@ function createConversationNamespace(transport, subscribers = new CompactionSubs
1535
1576
  pathParams: { conversation_id: id },
1536
1577
  query: { style: _nullishCoalesce(options.style, () => ( "structured")) }
1537
1578
  });
1538
- const response = _nullishCoalesce(_nullishCoalesce(_optionalChain([result, 'optionalAccess', _48 => _48["context_for_prompt"]]), () => ( result)), () => ( {}));
1539
- _optionalChain([localShortTerm, 'access', _49 => _49.reseed, 'optionalCall', _50 => _50(id, response)]);
1579
+ const response = _nullishCoalesce(_nullishCoalesce(_optionalChain([result, 'optionalAccess', _50 => _50["context_for_prompt"]]), () => ( result)), () => ( {}));
1580
+ _optionalChain([localShortTerm, 'access', _51 => _51.reseed, 'optionalCall', _52 => _52(id, response)]);
1540
1581
  return withHistory(response);
1541
1582
  },
1542
1583
  async compact(options) {
@@ -1729,8 +1770,8 @@ function createInstanceNamespace(credentials, cache, onTurn, agentModel = () =>
1729
1770
  let onConversationState = null;
1730
1771
  const internals = {
1731
1772
  onCompactionUpdate(conversationId, bundle) {
1732
- _optionalChain([applyCompaction, 'optionalCall', _51 => _51(bundle)]);
1733
- _optionalChain([dispatchCompaction, 'optionalCall', _52 => _52(conversationId, bundle)]);
1773
+ _optionalChain([applyCompaction, 'optionalCall', _53 => _53(bundle)]);
1774
+ _optionalChain([dispatchCompaction, 'optionalCall', _54 => _54(conversationId, bundle)]);
1734
1775
  },
1735
1776
  setCompactionApplier(apply) {
1736
1777
  applyCompaction = apply;
@@ -1742,10 +1783,10 @@ function createInstanceNamespace(credentials, cache, onTurn, agentModel = () =>
1742
1783
  onConversationState = handle;
1743
1784
  },
1744
1785
  sendContextUsed(event) {
1745
- _optionalChain([client, 'optionalAccess', _53 => _53.sendContextUsed, 'call', _54 => _54(event)]);
1786
+ _optionalChain([client, 'optionalAccess', _55 => _55.sendContextUsed, 'call', _56 => _56(event)]);
1746
1787
  },
1747
1788
  sendContextAssembled(event) {
1748
- _optionalChain([client, 'optionalAccess', _55 => _55.sendContextAssembled, 'call', _56 => _56(event)]);
1789
+ _optionalChain([client, 'optionalAccess', _57 => _57.sendContextAssembled, 'call', _58 => _58(event)]);
1749
1790
  },
1750
1791
  setCompactionDispatcher(dispatch) {
1751
1792
  dispatchCompaction = dispatch;
@@ -1776,7 +1817,7 @@ function createInstanceNamespace(credentials, cache, onTurn, agentModel = () =>
1776
1817
  throw new (0, _chunkUXNVTP4Dcjs.ListeningAlreadyActiveError)("Listening is already active on this instance");
1777
1818
  }
1778
1819
  try {
1779
- _optionalChain([onListen, 'optionalCall', _57 => _57()]);
1820
+ _optionalChain([onListen, 'optionalCall', _59 => _59()]);
1780
1821
  } catch (e10) {
1781
1822
  }
1782
1823
  const { GrpcStreamClient } = await Promise.resolve().then(() => _interopRequireWildcard(require("./stream-client-5GYUWETN.cjs")));
@@ -1794,17 +1835,17 @@ function createInstanceNamespace(credentials, cache, onTurn, agentModel = () =>
1794
1835
  internals.onCompactionUpdate(conversationId, bundle);
1795
1836
  },
1796
1837
  onConversationState: (conversationId, messageCount) => {
1797
- _optionalChain([onConversationState, 'optionalCall', _58 => _58(conversationId, messageCount)]);
1838
+ _optionalChain([onConversationState, 'optionalCall', _60 => _60(conversationId, messageCount)]);
1798
1839
  },
1799
1840
  onStateChange: (state) => {
1800
1841
  if (state !== "connected") openSessions.clear();
1801
1842
  if (state === "reconnecting") {
1802
1843
  reconnectAttempts += 1;
1803
- _optionalChain([onReconnect, 'optionalCall', _59 => _59(reconnectAttempts)]);
1844
+ _optionalChain([onReconnect, 'optionalCall', _61 => _61(reconnectAttempts)]);
1804
1845
  } else if (state === "disconnected") {
1805
- const stopped = _nullishCoalesce(_optionalChain([stream, 'optionalAccess', _60 => _60.lastError]), () => ( null));
1846
+ const stopped = _nullishCoalesce(_optionalChain([stream, 'optionalAccess', _62 => _62.lastError]), () => ( null));
1806
1847
  const reason = stopped === null ? "stream disconnected" : `credit_stop:${_nullishCoalesce(stopped.reason, () => ( "unknown"))}`;
1807
- _optionalChain([onDisconnect, 'optionalCall', _61 => _61(reason)]);
1848
+ _optionalChain([onDisconnect, 'optionalCall', _63 => _63(reason)]);
1808
1849
  }
1809
1850
  }
1810
1851
  });
@@ -1814,7 +1855,7 @@ function createInstanceNamespace(credentials, cache, onTurn, agentModel = () =>
1814
1855
  } catch (error) {
1815
1856
  if (error instanceof _chunkUXNVTP4Dcjs.SynapError) throw error;
1816
1857
  throw new (0, _chunkUXNVTP4Dcjs.SynapError)(
1817
- `Could not open the Synap anticipation stream: ${_nullishCoalesce(_optionalChain([error, 'optionalAccess', _62 => _62.message]), () => ( String(error)))}`,
1858
+ `Could not open the Synap anticipation stream: ${_nullishCoalesce(_optionalChain([error, 'optionalAccess', _64 => _64.message]), () => ( String(error)))}`,
1818
1859
  { cause: error }
1819
1860
  );
1820
1861
  }
@@ -1860,7 +1901,7 @@ function createInstanceNamespace(credentials, cache, onTurn, agentModel = () =>
1860
1901
  _nullishCoalesce(_nullishCoalesce(options.customer_id, () => ( options.customerId)), () => ( ""))
1861
1902
  );
1862
1903
  if (eventType === "user_message" || eventType === "assistant_message") {
1863
- _optionalChain([onTurn, 'optionalCall', _63 => _63({
1904
+ _optionalChain([onTurn, 'optionalCall', _65 => _65({
1864
1905
  conversationId,
1865
1906
  role: _nullishCoalesce(options.role, () => ( "user")),
1866
1907
  content: options.content
@@ -1906,7 +1947,7 @@ function createInstanceNamespace(credentials, cache, onTurn, agentModel = () =>
1906
1947
  async record_tool_result(options) {
1907
1948
  const conversationId = _nullishCoalesce(_nullishCoalesce(options.conversation_id, () => ( options.conversationId)), () => ( ""));
1908
1949
  if (conversationId) {
1909
- _optionalChain([onToolResult, 'optionalCall', _64 => _64({ conversationId, result: options.result, toolName: _nullishCoalesce(_nullishCoalesce(options.tool_name, () => ( options.toolName)), () => ( "")) })]);
1950
+ _optionalChain([onToolResult, 'optionalCall', _66 => _66({ conversationId, result: options.result, toolName: _nullishCoalesce(_nullishCoalesce(options.tool_name, () => ( options.toolName)), () => ( "")) })]);
1910
1951
  }
1911
1952
  await namespace.send_message({
1912
1953
  content: "",
@@ -1958,7 +1999,7 @@ function createInstanceNamespace(credentials, cache, onTurn, agentModel = () =>
1958
1999
  }
1959
2000
 
1960
2001
  // src/version.ts
1961
- var SDK_VERSION = "0.5.11";
2002
+ var SDK_VERSION = "0.5.13";
1962
2003
 
1963
2004
  // src/registry.ts
1964
2005
  var instances = /* @__PURE__ */ new Map();
@@ -2426,7 +2467,7 @@ var TurnStore = (_class3 = class {
2426
2467
  }
2427
2468
  /** Turns the server also holds: archived tool results are local only. Python: `count`. */
2428
2469
  count(conversationId) {
2429
- 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;
2470
+ return (_nullishCoalesce(_optionalChain([this, 'access', _67 => _67.#conversations, 'access', _68 => _68.get, 'call', _69 => _69(conversationId), 'optionalAccess', _70 => _70.turns]), () => ( []))).filter((t) => t.role !== "tool").length;
2430
2471
  }
2431
2472
  sizeBytes() {
2432
2473
  let n2 = 0;
@@ -2605,7 +2646,7 @@ function askedKinds(query) {
2605
2646
  }
2606
2647
  function asksHowItStarted(query) {
2607
2648
  const spec = _chunkICUFS3B5cjs.HISTORY_SEARCH.early_query;
2608
- if (!_optionalChain([spec, 'optionalAccess', _69 => _69.pattern])) return false;
2649
+ if (!_optionalChain([spec, 'optionalAccess', _71 => _71.pattern])) return false;
2609
2650
  return new RegExp(spec.pattern, (_nullishCoalesce(spec.flags, () => ( ""))).includes("i") ? "i" : "").test(_nullishCoalesce(query, () => ( "")));
2610
2651
  }
2611
2652
  async function searchTurns(turns, query, options = {}) {
@@ -3776,6 +3817,29 @@ var SynapClient = (_class4 = class _SynapClient {
3776
3817
  },
3777
3818
  onServedFromCache: (_scope, options2, served) => {
3778
3819
  this.#emitContextUsed(options2, _scope, served);
3820
+ },
3821
+ // The periodic user-summary splice, as Python runs it at the end of the
3822
+ // user, customer and client fetches (the conversation fetch does its own
3823
+ // through `onFetched`). Until 0.5.12 only the conversation fetch had it,
3824
+ // so the same usage gave the model different context in JS.
3825
+ // Python's `_should_skip_server_st`: when this process already holds the
3826
+ // conversation's compaction and every turn after it, the server is told
3827
+ // not to assemble them again.
3828
+ skipServerShortTerm: (conversationId) => {
3829
+ if (!this.#isStAuthoritative()) return false;
3830
+ const entry = this.#shortTerm.get(conversationId);
3831
+ return entry !== null && entry.compactionId !== null && isComplete(entry);
3832
+ },
3833
+ onResponse: (scope, options2, response) => {
3834
+ if (scope === "conversation") return;
3835
+ const o2 = options2;
3836
+ const owner = scope === "user" ? _nullishCoalesce(o2["user_id"], () => ( o2["userId"])) : scope === "customer" ? _nullishCoalesce(o2["customer_id"], () => ( o2["customerId"])) : "_client";
3837
+ this.#injectUserSummary(
3838
+ response,
3839
+ _nullishCoalesce(o2["conversation_id"], () => ( o2["conversationId"])),
3840
+ owner,
3841
+ _chunkICUFS3B5cjs.rungKey.call(void 0, _nullishCoalesce(o2["scope_path"], () => ( o2["scopePath"])))
3842
+ );
3779
3843
  }
3780
3844
  };
3781
3845
  this.user = createUserNamespace(this.#transport, this.#fetchHooks);
@@ -3795,7 +3859,7 @@ var SynapClient = (_class4 = class _SynapClient {
3795
3859
  this.#localEncoder = _nullishCoalesce(_nullishCoalesce(options.history_search_encoder, () => ( options.historySearchEncoder)), () => ( null));
3796
3860
  const modelOption = options.history_search_model !== void 0 ? options.history_search_model : options.historySearchModel;
3797
3861
  this.#localModelName = modelOption === void 0 ? "auto" : modelOption;
3798
- if (_optionalChain([this, 'access', _70 => _70.#localEncoder, 'optionalAccess', _71 => _71.model]) === _chunkICUFS3B5cjs.SEMANTIC_MATCH.model) this.#anticipationCache.setEncoder(this.#localEncoder);
3862
+ if (_optionalChain([this, 'access', _72 => _72.#localEncoder, 'optionalAccess', _73 => _73.model]) === _chunkICUFS3B5cjs.SEMANTIC_MATCH.model) this.#anticipationCache.setEncoder(this.#localEncoder);
3799
3863
  this.#turns = new TurnCounter();
3800
3864
  this.conversation = createConversationNamespace(
3801
3865
  this.#transport,
@@ -3829,7 +3893,12 @@ var SynapClient = (_class4 = class _SynapClient {
3829
3893
  reseed: (conversationId, response) => this.#reseedShortTerm(conversationId, response),
3830
3894
  historyExcerpts: (conversationId, response, query) => this.#withHistoryExcerpts(conversationId, response, query)
3831
3895
  },
3832
- () => this.#agentModel
3896
+ () => this.#agentModel,
3897
+ // The same hooks as the other three scopes: the anticipation cache first,
3898
+ // as Python's conversation fetch does, and the audit events. Until 0.5.13
3899
+ // the conversation fetch was built without them, so every JS conversation
3900
+ // fetch was a billed round trip, including ones the stream had answered.
3901
+ this.#fetchHooks
3833
3902
  );
3834
3903
  this.memories = createMemoriesInterface(this.#transport, ({ userId, customerId }) => {
3835
3904
  for (const id of /* @__PURE__ */ new Set([userId, customerId])) {
@@ -4286,14 +4355,14 @@ var SynapClient = (_class4 = class _SynapClient {
4286
4355
  }))
4287
4356
  );
4288
4357
  const entry = this.#shortTerm.get(conversationId);
4289
- const total = Math.max(Number(_nullishCoalesce(r["total_message_count"], () => ( 0))) || 0, Number(_nullishCoalesce(_optionalChain([entry, 'optionalAccess', _72 => _72.serverMessageCount]), () => ( 0))) || 0);
4358
+ const total = Math.max(Number(_nullishCoalesce(r["total_message_count"], () => ( 0))) || 0, Number(_nullishCoalesce(_optionalChain([entry, 'optionalAccess', _74 => _74.serverMessageCount]), () => ( 0))) || 0);
4290
4359
  this.#maybeBackfillTurns(conversationId, total);
4291
4360
  if (!r["context_block"]) return response;
4292
4361
  const turns = store.turns(conversationId);
4293
4362
  let q = query;
4294
4363
  if (!q) {
4295
4364
  const latest = [...recent].reverse().find((m) => m["role"] === "user");
4296
- 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]), () => ( ""));
4365
+ q = latest ? String(_nullishCoalesce(latest["content"], () => ( ""))) : _nullishCoalesce(_optionalChain([[...turns], 'access', _75 => _75.reverse, 'call', _76 => _76(), 'access', _77 => _77.find, 'call', _78 => _78((t) => t.role === "user"), 'optionalAccess', _79 => _79.content]), () => ( ""));
4297
4366
  }
4298
4367
  if (!q) return response;
4299
4368
  const exclude = /* @__PURE__ */ new Set();
@@ -4437,13 +4506,13 @@ function pick3(o2, snake, camel) {
4437
4506
  function resolveBaseUrl(options) {
4438
4507
  const explicit = _nullishCoalesce(options.baseUrl, () => ( options.api_base_url));
4439
4508
  if (explicit !== void 0) return explicit;
4440
- const fromEnv = _optionalChain([_chunkZKOJDUN4cjs.getEnv.call(void 0, "SYNAP_BASE_URL"), 'optionalAccess', _78 => _78.trim, 'call', _79 => _79()]);
4509
+ const fromEnv = _optionalChain([_chunkZKOJDUN4cjs.getEnv.call(void 0, "SYNAP_BASE_URL"), 'optionalAccess', _80 => _80.trim, 'call', _81 => _81()]);
4441
4510
  return fromEnv !== void 0 && fromEnv !== "" ? fromEnv : void 0;
4442
4511
  }
4443
4512
  function resolveCredentials(options) {
4444
4513
  const apiKey = _nullishCoalesce(options.apiKey, () => ( _chunkZKOJDUN4cjs.getEnv.call(void 0, "SYNAP_API_KEY")));
4445
4514
  if (!apiKey) {
4446
- throw new (0, _chunkUXNVTP4Dcjs.InvalidInputError)(
4515
+ throw new (0, _chunkUXNVTP4Dcjs.AuthenticationError)(
4447
4516
  "No Synap API key found. Set SYNAP_API_KEY in your environment, or pass apiKey to the SynapClient constructor."
4448
4517
  );
4449
4518
  }