@maximem/synap-js-sdk 0.4.7 → 0.5.1

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.
Files changed (50) hide show
  1. package/dist/anticipation-cache-LRE3TLK4.cjs +14 -0
  2. package/dist/anticipation-cache-LRE3TLK4.cjs.map +1 -0
  3. package/dist/anticipation-cache-WLU4NMD5.js +14 -0
  4. package/dist/{chunk-ZU6ZC4SU.js → chunk-ASM2OIIG.js} +305 -7
  5. package/dist/chunk-ASM2OIIG.js.map +1 -0
  6. package/dist/{chunk-OCMM2Z5P.js → chunk-BWMPKLFG.js} +40 -2
  7. package/dist/chunk-BWMPKLFG.js.map +1 -0
  8. package/dist/{chunk-3JSE64GW.cjs → chunk-IA2N5NUY.cjs} +315 -17
  9. package/dist/chunk-IA2N5NUY.cjs.map +1 -0
  10. package/dist/{chunk-6LDUDKHS.js → chunk-ODVOQOSO.js} +124 -8
  11. package/dist/chunk-ODVOQOSO.js.map +1 -0
  12. package/dist/{chunk-2TVL5IPQ.cjs → chunk-T372OL3Q.cjs} +41 -3
  13. package/dist/chunk-T372OL3Q.cjs.map +1 -0
  14. package/dist/{chunk-RB57I2IQ.cjs → chunk-T6U5PVAD.cjs} +125 -9
  15. package/dist/chunk-T6U5PVAD.cjs.map +1 -0
  16. package/dist/chunk-ZKOJDUN4.cjs.map +1 -1
  17. package/dist/env-55ULHNJZ.cjs.map +1 -1
  18. package/dist/errors-Bl3vY1eb.d.cts +382 -0
  19. package/dist/errors-Bl3vY1eb.d.ts +382 -0
  20. package/dist/grpc/index.cjs +8 -8
  21. package/dist/grpc/index.cjs.map +1 -1
  22. package/dist/grpc/index.d.cts +44 -4
  23. package/dist/grpc/index.d.ts +44 -4
  24. package/dist/grpc/index.js +6 -6
  25. package/dist/index.cjs +301 -173
  26. package/dist/index.cjs.map +1 -1
  27. package/dist/index.d.cts +102 -146
  28. package/dist/index.d.ts +102 -146
  29. package/dist/index.js +192 -64
  30. package/dist/index.js.map +1 -1
  31. package/dist/stream-client-6OWRYOA4.js +16 -0
  32. package/dist/stream-client-Y5JGSF2R.cjs +16 -0
  33. package/dist/stream-client-Y5JGSF2R.cjs.map +1 -0
  34. package/package.json +6 -1
  35. package/dist/anticipation-cache-ARYEEKMU.cjs +0 -10
  36. package/dist/anticipation-cache-ARYEEKMU.cjs.map +0 -1
  37. package/dist/anticipation-cache-BMVF5sXb.d.cts +0 -190
  38. package/dist/anticipation-cache-BMVF5sXb.d.ts +0 -190
  39. package/dist/anticipation-cache-H7HEVWQC.js +0 -10
  40. package/dist/chunk-2TVL5IPQ.cjs.map +0 -1
  41. package/dist/chunk-3JSE64GW.cjs.map +0 -1
  42. package/dist/chunk-6LDUDKHS.js.map +0 -1
  43. package/dist/chunk-OCMM2Z5P.js.map +0 -1
  44. package/dist/chunk-RB57I2IQ.cjs.map +0 -1
  45. package/dist/chunk-ZU6ZC4SU.js.map +0 -1
  46. package/dist/stream-client-6V4FGKZ3.js +0 -7
  47. package/dist/stream-client-PRTOH62B.cjs +0 -7
  48. package/dist/stream-client-PRTOH62B.cjs.map +0 -1
  49. /package/dist/{anticipation-cache-H7HEVWQC.js.map → anticipation-cache-WLU4NMD5.js.map} +0 -0
  50. /package/dist/{stream-client-6V4FGKZ3.js.map → stream-client-6OWRYOA4.js.map} +0 -0
package/dist/index.js CHANGED
@@ -1,3 +1,17 @@
1
+ import {
2
+ ANY_SCOPE,
3
+ AnticipationCache,
4
+ BM25,
5
+ CONTRACT,
6
+ THRESHOLDS,
7
+ isRecallQuery,
8
+ rungKey,
9
+ stem,
10
+ tokenize
11
+ } from "./chunk-ODVOQOSO.js";
12
+ import {
13
+ getEnv
14
+ } from "./chunk-QBCVMPGK.js";
1
15
  import {
2
16
  AgentUnavailableError,
3
17
  AuthenticationError,
@@ -21,38 +35,9 @@ import {
21
35
  SynapTransientError,
22
36
  TranscriptConflictError,
23
37
  TransientError,
24
- isSynapError
25
- } from "./chunk-OCMM2Z5P.js";
26
- import {
27
- ANY_SCOPE,
28
- AnticipationCache,
29
- BM25,
30
- CONTRACT,
31
- THRESHOLDS,
32
- isRecallQuery,
33
- stem,
34
- tokenize
35
- } from "./chunk-6LDUDKHS.js";
36
- import {
37
- getEnv
38
- } from "./chunk-QBCVMPGK.js";
39
-
40
- // src/util/correlation.ts
41
- function newCorrelationId() {
42
- const c = globalThis.crypto;
43
- if (typeof c?.randomUUID === "function") return c.randomUUID();
44
- if (typeof c?.getRandomValues === "function") {
45
- const b = c.getRandomValues(new Uint8Array(16));
46
- b[6] = (b[6] ?? 0) & 15 | 64;
47
- b[8] = (b[8] ?? 0) & 63 | 128;
48
- const h = Array.from(b, (x) => x.toString(16).padStart(2, "0")).join("");
49
- return `${h.slice(0, 8)}-${h.slice(8, 12)}-${h.slice(12, 16)}-${h.slice(16, 20)}-${h.slice(20)}`;
50
- }
51
- return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (ch) => {
52
- const r = Math.random() * 16 | 0;
53
- return (ch === "x" ? r : r & 3 | 8).toString(16);
54
- });
55
- }
38
+ isSynapError,
39
+ newCorrelationId
40
+ } from "./chunk-BWMPKLFG.js";
56
41
 
57
42
  // src/transport/endpoints.ts
58
43
  var ENDPOINTS = {
@@ -422,6 +407,16 @@ function toTransportError(error, correlationId) {
422
407
  { correlationId, cause: error }
423
408
  );
424
409
  }
410
+ var CREDIT_ERRORS = /* @__PURE__ */ new Set(["insufficient_credits", "trial_limit_reached"]);
411
+ function creditPayload(parsed, detailObject) {
412
+ return detailObject ?? parsed;
413
+ }
414
+ function creditReason(payload) {
415
+ const reason = stringOrNull(payload["reason"]);
416
+ if (reason !== null) return reason;
417
+ const error = stringOrNull(payload["error"]);
418
+ return error !== null && CREDIT_ERRORS.has(error) ? error : null;
419
+ }
425
420
  async function toHttpError(response, correlationId) {
426
421
  const body = await response.text().catch(() => "");
427
422
  let parsed = {};
@@ -443,14 +438,18 @@ async function toHttpError(response, correlationId) {
443
438
  return new AuthenticationError(message, opts);
444
439
  case 404:
445
440
  return new ContextNotFoundError(message, opts);
446
- case 402:
441
+ case 402: {
442
+ const credit = creditPayload(parsed, detailObject);
447
443
  return new InsufficientCreditsError(message, {
448
444
  ...opts,
449
- balanceCredits: numberOrNull(parsed["balance_credits"]),
450
- requiredCredits: numberOrNull(parsed["minimum_required_credits"]) ?? numberOrNull(parsed["required_credits"]),
451
- recoveryUrl: stringOrNull(parsed["recovery_url"]),
452
- redeemUrl: stringOrNull(parsed["redeem_url"])
445
+ balanceCredits: numberOrNull(credit["balance_credits"]),
446
+ requiredCredits: numberOrNull(credit["minimum_required_credits"]) ?? numberOrNull(credit["required_credits"]),
447
+ recoveryUrl: stringOrNull(credit["recovery_url"]),
448
+ redeemUrl: stringOrNull(credit["redeem_url"]),
449
+ reason: creditReason(credit),
450
+ manageUrl: stringOrNull(credit["manage_url"])
453
451
  });
452
+ }
454
453
  case 409:
455
454
  if (detailObject !== null && detailObject["code"] === "transcript_conflict") {
456
455
  return new TranscriptConflictError(message, opts);
@@ -459,9 +458,13 @@ async function toHttpError(response, correlationId) {
459
458
  case 429: {
460
459
  const header = response.headers.get("retry-after");
461
460
  const retryAfter = header !== null && header.trim() !== "" ? Number(header) : null;
461
+ const credit = creditPayload(parsed, detailObject);
462
462
  return new RateLimitError(message, {
463
463
  ...opts,
464
- retryAfterSeconds: retryAfter !== null && Number.isFinite(retryAfter) ? retryAfter : null
464
+ retryAfterSeconds: retryAfter !== null && Number.isFinite(retryAfter) ? retryAfter : null,
465
+ reason: creditReason(credit),
466
+ upgradeUrl: stringOrNull(credit["upgrade_url"]),
467
+ manageUrl: stringOrNull(credit["manage_url"])
465
468
  });
466
469
  }
467
470
  case 503:
@@ -1046,6 +1049,8 @@ function buildRecordMessageBody(options) {
1046
1049
  };
1047
1050
  const sessionId = either2(o2, "session_id", "sessionId");
1048
1051
  if (sessionId !== void 0) body["session_id"] = sessionId;
1052
+ const scopePath = either2(o2, "scope_path", "scopePath");
1053
+ if (scopePath !== void 0) body["scope"] = scopePath;
1049
1054
  return body;
1050
1055
  }
1051
1056
  function buildIngestTranscriptBody(options) {
@@ -1072,6 +1077,8 @@ function buildIngestTranscriptBody(options) {
1072
1077
  if (options.metadata !== void 0) body["metadata"] = options.metadata;
1073
1078
  if (startedAt !== void 0) body["started_at"] = startedAt;
1074
1079
  if (endedAt !== void 0) body["ended_at"] = endedAt;
1080
+ const scopePath = either2(o2, "scope_path", "scopePath");
1081
+ if (scopePath !== void 0) body["scope"] = scopePath;
1075
1082
  return body;
1076
1083
  }
1077
1084
  function buildCompactBody(options) {
@@ -1205,7 +1212,8 @@ function createConversationNamespace(transport, subscribers = new CompactionSubs
1205
1212
  onFetched(
1206
1213
  response,
1207
1214
  id,
1208
- options.user_id ?? options.userId
1215
+ options.user_id ?? options.userId,
1216
+ options.scope_path ?? options.scopePath
1209
1217
  );
1210
1218
  return response;
1211
1219
  },
@@ -1370,8 +1378,24 @@ function thinkingMetadata(options) {
1370
1378
  }
1371
1379
  return md;
1372
1380
  }
1381
+ var KNOWN_EVENT_TYPES = /* @__PURE__ */ new Set([
1382
+ "user_message",
1383
+ "assistant_message",
1384
+ "tool_call",
1385
+ "tool_result",
1386
+ "agent_thinking",
1387
+ "context_request",
1388
+ "context_fetch",
1389
+ "session_start",
1390
+ "session_end"
1391
+ ]);
1392
+ function toolResultJson(result) {
1393
+ if (result === void 0 || result === null) return "";
1394
+ return typeof result === "string" ? result : JSON.stringify(result);
1395
+ }
1373
1396
  function createInstanceNamespace(credentials, cache, onTurn) {
1374
1397
  let client = null;
1398
+ const openSessions = /* @__PURE__ */ new Map();
1375
1399
  let dispatchCompaction = null;
1376
1400
  let applyCompaction = null;
1377
1401
  const internals = {
@@ -1395,16 +1419,33 @@ function createInstanceNamespace(credentials, cache, onTurn) {
1395
1419
  return client !== null && client.isConnected;
1396
1420
  }
1397
1421
  };
1422
+ function ensureSession(conversationId, userId, customerId) {
1423
+ if (!conversationId || !userId || client === null) return;
1424
+ if (openSessions.has(conversationId)) return;
1425
+ const sessionId = newCorrelationId();
1426
+ try {
1427
+ client.sendSessionControl({
1428
+ action: "start",
1429
+ session_id: sessionId,
1430
+ conversation_id: conversationId,
1431
+ ...userId ? { user_id: userId } : {},
1432
+ ...customerId ? { customer_id: customerId } : {}
1433
+ });
1434
+ openSessions.set(conversationId, sessionId);
1435
+ } catch {
1436
+ }
1437
+ }
1398
1438
  const namespace = {
1399
1439
  async listen(options = {}) {
1400
1440
  if (client !== null) {
1401
1441
  throw new ListeningAlreadyActiveError("Listening is already active on this instance");
1402
1442
  }
1403
- const { GrpcStreamClient } = await import("./stream-client-6V4FGKZ3.js");
1443
+ const { GrpcStreamClient } = await import("./stream-client-6OWRYOA4.js");
1404
1444
  const onContext = options.on_context ?? options.onContext;
1405
1445
  const onDisconnect = options.on_disconnect ?? options.onDisconnect;
1406
1446
  const onReconnect = options.on_reconnect ?? options.onReconnect;
1407
1447
  let reconnectAttempts = 0;
1448
+ let stream = null;
1408
1449
  const created = new GrpcStreamClient(credentials(), cache, {
1409
1450
  host: options.host ?? getEnv("SYNAP_GRPC_HOST") ?? DEFAULT_GRPC_HOST,
1410
1451
  port: options.port ?? envPort() ?? DEFAULT_GRPC_PORT,
@@ -1414,14 +1455,18 @@ function createInstanceNamespace(credentials, cache, onTurn) {
1414
1455
  internals.onCompactionUpdate(conversationId, bundle);
1415
1456
  },
1416
1457
  onStateChange: (state) => {
1458
+ if (state !== "connected") openSessions.clear();
1417
1459
  if (state === "reconnecting") {
1418
1460
  reconnectAttempts += 1;
1419
1461
  onReconnect?.(reconnectAttempts);
1420
1462
  } else if (state === "disconnected") {
1421
- onDisconnect?.("stream disconnected");
1463
+ const stopped = stream?.lastError ?? null;
1464
+ const reason = stopped === null ? "stream disconnected" : `credit_stop:${stopped.reason ?? "unknown"}`;
1465
+ onDisconnect?.(reason);
1422
1466
  }
1423
1467
  }
1424
1468
  });
1469
+ stream = created;
1425
1470
  try {
1426
1471
  await created.connect();
1427
1472
  } catch (error) {
@@ -1435,29 +1480,58 @@ function createInstanceNamespace(credentials, cache, onTurn) {
1435
1480
  },
1436
1481
  async stop_listening() {
1437
1482
  if (client === null) return;
1483
+ for (const conversationId of [...openSessions.keys()]) {
1484
+ await namespace.end_session(conversationId);
1485
+ }
1438
1486
  const active = client;
1439
1487
  client = null;
1440
1488
  await active.disconnect();
1441
1489
  },
1490
+ async end_session(conversationId) {
1491
+ const sessionId = openSessions.get(conversationId);
1492
+ if (sessionId === void 0 || client === null) return;
1493
+ openSessions.delete(conversationId);
1494
+ try {
1495
+ client.sendSessionControl({
1496
+ action: "end",
1497
+ session_id: sessionId,
1498
+ conversation_id: conversationId
1499
+ });
1500
+ } catch {
1501
+ }
1502
+ },
1442
1503
  async send_message(options) {
1443
1504
  if (client === null) throw new ListeningNotActiveError("Listening is not active");
1444
1505
  if (options.content === void 0) {
1445
1506
  throw new ListeningNotActiveError("content is required");
1446
1507
  }
1508
+ const eventType = options.event_type ?? options.eventType ?? "user_message";
1509
+ if (!KNOWN_EVENT_TYPES.has(eventType)) {
1510
+ throw new SynapError(
1511
+ `unknown event_type '${eventType}'. Expected one of: ` + [...KNOWN_EVENT_TYPES].sort().join(", ")
1512
+ );
1513
+ }
1447
1514
  const conversationId = options.conversation_id ?? options.conversationId ?? "";
1448
- onTurn?.({
1515
+ ensureSession(
1449
1516
  conversationId,
1450
- role: options.role ?? "user",
1451
- content: options.content
1452
- });
1517
+ options.user_id ?? options.userId ?? "",
1518
+ options.customer_id ?? options.customerId ?? ""
1519
+ );
1520
+ if (eventType === "user_message" || eventType === "assistant_message") {
1521
+ onTurn?.({
1522
+ conversationId,
1523
+ role: options.role ?? "user",
1524
+ content: options.content
1525
+ });
1526
+ }
1453
1527
  client.sendConversationEvent({
1454
- event_type: options.event_type ?? options.eventType ?? "user_message",
1528
+ event_type: eventType,
1455
1529
  content: options.content,
1456
1530
  role: options.role ?? "user",
1457
1531
  conversation_id: options.conversation_id ?? options.conversationId ?? "",
1458
1532
  user_id: options.user_id ?? options.userId ?? "",
1459
1533
  customer_id: options.customer_id ?? options.customerId ?? "",
1460
- session_id: options.session_id ?? options.sessionId ?? "",
1534
+ session_id: options.session_id ?? options.sessionId ?? openSessions.get(conversationId) ?? "",
1461
1535
  metadata: options.metadata ?? {},
1462
1536
  timestamp_ms: Date.now(),
1463
1537
  tool_name: options.tool_name ?? options.toolName ?? "",
@@ -1466,17 +1540,61 @@ function createInstanceNamespace(credentials, cache, onTurn) {
1466
1540
  const a = options.tool_args ?? options.toolArgs;
1467
1541
  return a === void 0 ? "" : JSON.stringify(a);
1468
1542
  })(),
1543
+ tool_result_json: toolResultJson(options.tool_result ?? options.toolResult),
1544
+ tool_call_id: options.tool_call_id ?? options.toolCallId ?? "",
1469
1545
  search_queries: options.search_queries ?? options.searchQueries ?? [],
1470
1546
  context_types: options.context_types ?? options.contextTypes ?? []
1471
1547
  });
1472
1548
  },
1549
+ async record_tool_call(options) {
1550
+ await namespace.send_message({
1551
+ content: "",
1552
+ role: "assistant",
1553
+ event_type: "tool_call",
1554
+ tool_name: options.tool_name ?? options.toolName ?? "",
1555
+ ...options.tool_args ?? options.toolArgs ? { tool_args: options.tool_args ?? options.toolArgs } : {},
1556
+ tool_call_id: options.tool_call_id ?? options.toolCallId ?? "",
1557
+ conversation_id: options.conversation_id ?? options.conversationId ?? "",
1558
+ user_id: options.user_id ?? options.userId ?? "",
1559
+ customer_id: options.customer_id ?? options.customerId ?? "",
1560
+ session_id: options.session_id ?? options.sessionId ?? "",
1561
+ metadata: options.metadata ?? {}
1562
+ });
1563
+ },
1564
+ async record_tool_result(options) {
1565
+ await namespace.send_message({
1566
+ content: "",
1567
+ role: "tool",
1568
+ event_type: "tool_result",
1569
+ tool_result: options.result,
1570
+ tool_name: options.tool_name ?? options.toolName ?? "",
1571
+ tool_call_id: options.tool_call_id ?? options.toolCallId ?? "",
1572
+ conversation_id: options.conversation_id ?? options.conversationId ?? "",
1573
+ user_id: options.user_id ?? options.userId ?? "",
1574
+ customer_id: options.customer_id ?? options.customerId ?? "",
1575
+ session_id: options.session_id ?? options.sessionId ?? "",
1576
+ metadata: options.metadata ?? {}
1577
+ });
1578
+ },
1473
1579
  async record_thinking(options) {
1474
1580
  if (client === null) throw new ListeningNotActiveError("Listening is not active");
1581
+ const conversationId = options.conversation_id ?? options.conversationId ?? "";
1582
+ ensureSession(
1583
+ conversationId,
1584
+ options.user_id ?? options.userId ?? "",
1585
+ options.customer_id ?? options.customerId ?? ""
1586
+ );
1475
1587
  client.sendConversationEvent({
1476
1588
  // Python emits reasoning as an `agent_thinking` conversation event.
1477
1589
  event_type: "agent_thinking",
1478
1590
  content: options.content,
1479
- role: "assistant",
1591
+ // Deliberately no role. A thought is not the assistant's reply, and
1592
+ // this went out as 'assistant' from the day it shipped: the server
1593
+ // checked role before event_type, so every reasoning step any client
1594
+ // sent was filed as the final answer and the reasoning path never ran.
1595
+ // Sending no role is correct against both the fixed server and one that
1596
+ // has not been updated yet.
1597
+ role: "",
1480
1598
  conversation_id: options.conversation_id ?? options.conversationId ?? "",
1481
1599
  user_id: options.user_id ?? options.userId ?? "",
1482
1600
  customer_id: options.customer_id ?? options.customerId ?? "",
@@ -1494,7 +1612,7 @@ function createInstanceNamespace(credentials, cache, onTurn) {
1494
1612
  }
1495
1613
 
1496
1614
  // src/version.ts
1497
- var SDK_VERSION = "1.0.0-beta.0";
1615
+ var SDK_VERSION = "0.5.1";
1498
1616
 
1499
1617
  // src/registry.ts
1500
1618
  var instances = /* @__PURE__ */ new Map();
@@ -1683,7 +1801,7 @@ function budgetRecentTurns(turns) {
1683
1801
  return windowed;
1684
1802
  }
1685
1803
  function overlayLocalRecentTurns(response, store, conversationId, configured) {
1686
- if (conversationId === void 0 || conversationId === "") return;
1804
+ if (conversationId === void 0 || conversationId === null || conversationId === "") return;
1687
1805
  try {
1688
1806
  const entry = store.get(conversationId);
1689
1807
  if (entry === null) return;
@@ -1944,16 +2062,16 @@ function mergeUserSummary(response, bundle) {
1944
2062
 
1945
2063
  // src/context/anticipated.ts
1946
2064
  function scopeLookupParams(scope, params) {
1947
- const { searchQuery, entityId, customerId, clientId, conversationId } = params;
2065
+ const { searchQuery, entityId, customerId, clientId, conversationId, scopeRung } = params;
1948
2066
  switch (scope) {
1949
2067
  case "conversation":
1950
- return { searchQuery, entityId, customerId, clientId, conversationId };
2068
+ return { searchQuery, entityId, customerId, clientId, conversationId, scopeRung };
1951
2069
  case "user":
1952
- return { searchQuery, entityId, customerId, clientId };
2070
+ return { searchQuery, entityId, customerId, clientId, scopeRung };
1953
2071
  case "customer":
1954
- return { searchQuery, entityId: null, customerId, clientId };
2072
+ return { searchQuery, entityId: null, customerId, clientId, scopeRung };
1955
2073
  case "client":
1956
- return { searchQuery, entityId: null, customerId: null, clientId };
2074
+ return { searchQuery, entityId: null, customerId: null, clientId, scopeRung };
1957
2075
  }
1958
2076
  }
1959
2077
  function buildAnticipationResponse(hit) {
@@ -1988,6 +2106,7 @@ function tryServeFromCache(cache, scope, params, maxItems) {
1988
2106
  customerId: scoped.customerId ?? null,
1989
2107
  clientId: scoped.clientId ?? null,
1990
2108
  conversationId: scoped.conversationId ?? null,
2109
+ scopeRung: scoped.scopeRung ?? null,
1991
2110
  maxItems
1992
2111
  });
1993
2112
  if (hit === null) return { response: null, hit: null };
@@ -2500,7 +2619,15 @@ var SynapClient = class {
2500
2619
  entityId: o2["user_id"] ?? o2["userId"],
2501
2620
  customerId: o2["customer_id"] ?? o2["customerId"],
2502
2621
  clientId: this.#transport.currentCredentials().clientId || null,
2503
- conversationId: o2["conversation_id"] ?? o2["conversationId"]
2622
+ conversationId: o2["conversation_id"] ?? o2["conversationId"],
2623
+ // The rung this read is addressed to, in the same words the server
2624
+ // stamped on the bundles it pushed. Without it the cache matched
2625
+ // on entity and conversation alone, so a bundle prefetched for one
2626
+ // rung answered a caller standing at another, entirely inside this
2627
+ // process and invisible to every server log.
2628
+ scopeRung: rungKey(
2629
+ o2["scope_path"] ?? o2["scopePath"]
2630
+ )
2504
2631
  },
2505
2632
  Number(o2["max_results"] ?? o2["maxResults"] ?? 10)
2506
2633
  );
@@ -2545,9 +2672,9 @@ var SynapClient = class {
2545
2672
  ({ conversationId, role, content, timestamp }) => {
2546
2673
  this.#shortTerm.appendTurn(conversationId, role, content, timestamp);
2547
2674
  },
2548
- (response, conversationId, userId) => {
2675
+ (response, conversationId, userId, scopePath) => {
2549
2676
  overlayLocalRecentTurns(response, this.#shortTerm, conversationId, this.#stVerbatimOverlay);
2550
- this.#injectUserSummary(response, conversationId, userId);
2677
+ this.#injectUserSummary(response, conversationId, userId, rungKey(scopePath));
2551
2678
  },
2552
2679
  {
2553
2680
  prompt: (conversationId, style) => this.#localPrompt(conversationId, style),
@@ -2770,7 +2897,8 @@ var SynapClient = class {
2770
2897
  };
2771
2898
  const labels = [];
2772
2899
  const tasks = [];
2773
- if (conversationId !== void 0 && conversationId !== "" && wants("conversation")) {
2900
+ const present = (v) => v !== void 0 && v !== null && v !== "";
2901
+ if (present(conversationId) && wants("conversation")) {
2774
2902
  labels.push("conversation");
2775
2903
  tasks.push(this.conversation.context.fetch({
2776
2904
  conversation_id: conversationId,
@@ -2779,7 +2907,7 @@ var SynapClient = class {
2779
2907
  customer_id: customerId
2780
2908
  }));
2781
2909
  }
2782
- if (userId !== void 0 && userId !== "" && wants("user")) {
2910
+ if (present(userId) && wants("user")) {
2783
2911
  labels.push("user");
2784
2912
  tasks.push(this.user.context.fetch({
2785
2913
  user_id: userId,
@@ -2791,7 +2919,7 @@ var SynapClient = class {
2791
2919
  last_n_conversations: lastNConversations
2792
2920
  }));
2793
2921
  }
2794
- if (customerId !== void 0 && customerId !== "" && wants("customer")) {
2922
+ if (present(customerId) && wants("customer")) {
2795
2923
  labels.push("customer");
2796
2924
  tasks.push(this.customer.context.fetch({
2797
2925
  customer_id: customerId,
@@ -2825,7 +2953,7 @@ var SynapClient = class {
2825
2953
  for (const [, response] of successful) {
2826
2954
  overlayLocalRecentTurns(response, this.#shortTerm, conversationId, this.#stVerbatimOverlay);
2827
2955
  }
2828
- if (includeConversationContext && conversationId !== void 0 && conversationId !== "") {
2956
+ if (includeConversationContext && present(conversationId)) {
2829
2957
  try {
2830
2958
  merged.conversation_context = await this.conversation.context.get_context_for_prompt({
2831
2959
  conversation_id: conversationId
@@ -2912,11 +3040,11 @@ var SynapClient = class {
2912
3040
  * cannot be scoped, and an unscoped lookup is how user A's summary ends up in
2913
3041
  * user B's response.
2914
3042
  */
2915
- #injectUserSummary(response, conversationId, userId) {
3043
+ #injectUserSummary(response, conversationId, userId, scopeRung) {
2916
3044
  this.#turns.increment(conversationId);
2917
3045
  if (userId === void 0 || userId === "") return;
2918
3046
  if (!this.#turns.shouldInject(conversationId)) return;
2919
- const summary = this.#anticipationCache.lookupUserSummary(userId);
3047
+ const summary = this.#anticipationCache.lookupUserSummary(userId, scopeRung);
2920
3048
  if (summary === null) return;
2921
3049
  mergeUserSummary(response, summary);
2922
3050
  }