@vinaverse/client 0.1.0-alpha.12 → 0.1.0-alpha.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.
Files changed (47) hide show
  1. package/dist/agent/index.cjs +146 -15
  2. package/dist/agent/index.cjs.map +1 -1
  3. package/dist/agent/index.d.cts +3 -3
  4. package/dist/agent/index.d.ts +3 -3
  5. package/dist/agent/index.js +3 -3
  6. package/dist/backend/index.cjs +3 -0
  7. package/dist/backend/index.cjs.map +1 -1
  8. package/dist/backend/index.d.cts +3 -3
  9. package/dist/backend/index.d.ts +3 -3
  10. package/dist/backend/index.js +6 -3
  11. package/dist/backend/index.js.map +1 -1
  12. package/dist/{chunk-46D3FSLU.js → chunk-5HKZB2CJ.js} +14 -6
  13. package/dist/chunk-5HKZB2CJ.js.map +1 -0
  14. package/dist/{chunk-GWLLUOFY.js → chunk-LAB2FPXF.js} +31 -8
  15. package/dist/chunk-LAB2FPXF.js.map +1 -0
  16. package/dist/{chunk-5THD6XC7.js → chunk-WOMAGTI5.js} +108 -11
  17. package/dist/chunk-WOMAGTI5.js.map +1 -0
  18. package/dist/conversation/index.cjs +40 -9
  19. package/dist/conversation/index.cjs.map +1 -1
  20. package/dist/conversation/index.d.cts +4 -4
  21. package/dist/conversation/index.d.ts +4 -4
  22. package/dist/conversation/index.js +3 -3
  23. package/dist/history/index.cjs +7 -1
  24. package/dist/history/index.cjs.map +1 -1
  25. package/dist/history/index.d.cts +10 -4
  26. package/dist/history/index.d.ts +10 -4
  27. package/dist/history/index.js +10 -5
  28. package/dist/history/index.js.map +1 -1
  29. package/dist/index.cjs +29 -6
  30. package/dist/index.cjs.map +1 -1
  31. package/dist/index.d.cts +1 -1
  32. package/dist/index.d.ts +1 -1
  33. package/dist/index.js +1 -1
  34. package/dist/{runtime-CZyVCueC.d.ts → runtime-44JlV32O.d.ts} +91 -13
  35. package/dist/{runtime-BR2lS_Vg.d.cts → runtime-DWiB-XHX.d.cts} +91 -13
  36. package/dist/{session-D0ijOQX3.d.cts → session-lPGrKdhf.d.cts} +5 -0
  37. package/dist/{session-D0ijOQX3.d.ts → session-lPGrKdhf.d.ts} +5 -0
  38. package/dist/{store-CGRSxVcL.d.ts → store-Cjw9YmXA.d.ts} +6 -1
  39. package/dist/{store-CxoHwd64.d.cts → store-D-an5vch.d.cts} +6 -1
  40. package/dist/testing/index.cjs.map +1 -1
  41. package/dist/testing/index.d.cts +3 -3
  42. package/dist/testing/index.d.ts +3 -3
  43. package/dist/testing/index.js +3 -3
  44. package/package.json +2 -2
  45. package/dist/chunk-46D3FSLU.js.map +0 -1
  46. package/dist/chunk-5THD6XC7.js.map +0 -1
  47. package/dist/chunk-GWLLUOFY.js.map +0 -1
@@ -19,7 +19,8 @@ var CARD_KINDS = {
19
19
  question: true,
20
20
  proposal: true,
21
21
  next_step: true,
22
- links: true
22
+ links: true,
23
+ anchor: true
23
24
  };
24
25
  function isKnownCard(card) {
25
26
  return Object.hasOwn(CARD_KINDS, card.kind);
@@ -129,6 +130,11 @@ var RECONNECTABLE = /* @__PURE__ */ new Set(["server_restart"]);
129
130
  var NEW_SESSION = /* @__PURE__ */ new Set(["idle", "expired", "limit_reached"]);
130
131
  var str = (v) => typeof v === "string" ? v : void 0;
131
132
  var ConversationEngine = class {
133
+ /** `now`: the clock a message is stamped by when the server gives no time. */
134
+ constructor(now = Date.now) {
135
+ this.now = now;
136
+ }
137
+ now;
132
138
  sessionId = null;
133
139
  conversationId = null;
134
140
  connection = null;
@@ -317,7 +323,14 @@ var ConversationEngine = class {
317
323
  case "message.staff": {
318
324
  const id = str(event.message_id);
319
325
  if (id !== void 0)
320
- this.say("staff", str(event.text) ?? "", `s:${id}`);
326
+ this.say(
327
+ "staff",
328
+ str(event.text) ?? "",
329
+ `s:${id}`,
330
+ {},
331
+ void 0,
332
+ str(event.at)
333
+ );
321
334
  return;
322
335
  }
323
336
  case "input.received": {
@@ -399,7 +412,9 @@ var ConversationEngine = class {
399
412
  role,
400
413
  str(item.text) ?? "",
401
414
  transcriptKey(role, str(item.id), str(item.at)),
402
- item.interrupted === true ? { partial: "interrupted" } : {}
415
+ item.interrupted === true ? { partial: "interrupted" } : {},
416
+ void 0,
417
+ str(item.at)
403
418
  );
404
419
  }
405
420
  }
@@ -444,7 +459,8 @@ var ConversationEngine = class {
444
459
  text2,
445
460
  key,
446
461
  partial ? { partial } : {},
447
- at
462
+ at,
463
+ str(item.at)
448
464
  );
449
465
  else
450
466
  this.messages = this.messages.map((m) => {
@@ -572,9 +588,16 @@ var ConversationEngine = class {
572
588
  this.unqueue(id);
573
589
  }
574
590
  /** Adds a message once: a key already held (a frame seen twice) changes nothing. */
575
- say(role, text2, key, extra = {}, seq) {
591
+ say(role, text2, key, extra = {}, seq, at) {
576
592
  if (this.messages.some((m) => m.key === key)) return;
577
- this.messages.push({ role, text: text2, key, seq: seq ?? this.seq++, ...extra });
593
+ this.messages.push({
594
+ role,
595
+ text: text2,
596
+ key,
597
+ seq: seq ?? this.seq++,
598
+ ...extra,
599
+ at: at || new Date(this.now()).toISOString()
600
+ });
578
601
  }
579
602
  /** The turn's streamed text, kept as the agent's message when the turn ends without its `message.completed`. */
580
603
  cutOff(partial) {
@@ -1547,6 +1570,7 @@ function buildTimeline(input, previous) {
1547
1570
  role: "person",
1548
1571
  text: sent.text,
1549
1572
  state: pending,
1573
+ at: sent.at,
1550
1574
  ...pending === "not_sent" ? {
1551
1575
  rejection: rejection ?? {
1552
1576
  code: state.refused[id] ?? "",
@@ -1598,7 +1622,8 @@ function messageItem(m) {
1598
1622
  text: m.text,
1599
1623
  state: m.received ? "delivered" : "sent",
1600
1624
  ...m.partial ? { partial: m.partial } : {},
1601
- ...m.refusal ? { refusal: true } : {}
1625
+ ...m.refusal ? { refusal: true } : {},
1626
+ at: m.at
1602
1627
  };
1603
1628
  }
1604
1629
  function equal(a, b) {
@@ -1632,7 +1657,9 @@ var OUTCOMES2 = /* @__PURE__ */ new Set([
1632
1657
  ]);
1633
1658
  var ConversationStore = class {
1634
1659
  options;
1635
- engine = new ConversationEngine();
1660
+ engine = new ConversationEngine(
1661
+ () => this.options.clock?.now() ?? Date.now()
1662
+ );
1636
1663
  session = null;
1637
1664
  info = null;
1638
1665
  getting = null;
@@ -1815,7 +1842,11 @@ var ConversationStore = class {
1815
1842
  if ([...text2].length > MAX_TEXT)
1816
1843
  throw new RangeError(`A message is at most ${MAX_TEXT} characters.`);
1817
1844
  const id = (this.options.createId ?? randomId)();
1818
- this.sent.set(id, { text: text2, order: lastOrder(this.engine.state()) + 0.5 });
1845
+ this.sent.set(id, {
1846
+ text: text2,
1847
+ order: lastOrder(this.engine.state()) + 0.5,
1848
+ at: new Date(this.options.clock?.now() ?? Date.now()).toISOString()
1849
+ });
1819
1850
  this.tellActivity({ type: "message_sent", id });
1820
1851
  if (!this.session) {
1821
1852
  this.early.set(id, text2);
@@ -2456,6 +2487,65 @@ function shallowEqual(a, b) {
2456
2487
  }
2457
2488
 
2458
2489
  // src/agent/runtime.ts
2490
+ var ANCHOR_TYPES = /* @__PURE__ */ new Set([
2491
+ "booking",
2492
+ "rental",
2493
+ "professional",
2494
+ "workspace",
2495
+ "service",
2496
+ "class",
2497
+ "policy"
2498
+ ]);
2499
+ function anchorRef(type, id) {
2500
+ return ANCHOR_TYPES.has(type) && /^[A-Za-z0-9][A-Za-z0-9_.:-]{0,127}$/.test(id) ? { type, id } : null;
2501
+ }
2502
+ var JOINS = [
2503
+ 768,
2504
+ 879,
2505
+ 6832,
2506
+ 6911,
2507
+ 7616,
2508
+ 7679,
2509
+ 8400,
2510
+ 8447,
2511
+ 65056,
2512
+ 65071,
2513
+ 8205,
2514
+ 8205,
2515
+ 65038,
2516
+ 65039,
2517
+ 127995,
2518
+ 127999
2519
+ ];
2520
+ var joins = (point) => {
2521
+ const c = point?.codePointAt(0) ?? -1;
2522
+ for (let i = 0; i < JOINS.length; i += 2)
2523
+ if (c >= JOINS[i] && c <= JOINS[i + 1]) return true;
2524
+ return false;
2525
+ };
2526
+ function entryLabel(label) {
2527
+ let out = "";
2528
+ let size = 0;
2529
+ const points = Array.from(label.trim());
2530
+ for (let i = 0; i < points.length; ) {
2531
+ let end = i + 1;
2532
+ while (end < points.length && (joins(points[end]) || points[end - 1] === "\u200D"))
2533
+ end++;
2534
+ if (size + end - i > 60) break;
2535
+ out += points.slice(i, end).join("");
2536
+ size += end - i;
2537
+ i = end;
2538
+ }
2539
+ return out || void 0;
2540
+ }
2541
+ function askAboutKey(key, place) {
2542
+ return { ...key, thread: `ask:${place.entity.type}:${place.entity.id}` };
2543
+ }
2544
+ function entryOf(entry) {
2545
+ if (!/^[a-z][a-z0-9_]{0,31}$/.test(entry.point)) return null;
2546
+ const label = entry.label === void 0 ? void 0 : entryLabel(entry.label);
2547
+ return label ? { point: entry.point, label } : { point: entry.point };
2548
+ }
2459
2549
  var AgentRefusal = class extends Error {
2460
2550
  constructor(kind, options = {}) {
2461
2551
  super(
@@ -2609,6 +2699,7 @@ function createAgentRuntime(options) {
2609
2699
  };
2610
2700
  const clock = options.clock ?? SYSTEM_CLOCK;
2611
2701
  const keepAlive = options.keepAlive ?? "session";
2702
+ const graceMs = options.graceMs ?? 6e4;
2612
2703
  const staleMs = options.statusStaleMs ?? 5 * 6e4;
2613
2704
  const insecure = options.insecureAddresses ?? {};
2614
2705
  warnInsecure(insecure, options.onWarning ?? ((m) => console.warn(m)));
@@ -2628,6 +2719,7 @@ function createAgentRuntime(options) {
2628
2719
  changed();
2629
2720
  };
2630
2721
  let sessionName = null;
2722
+ const names = /* @__PURE__ */ new Map();
2631
2723
  let generation = 0;
2632
2724
  const keyOf = (key) => agentKey(key, options.agent ?? null);
2633
2725
  const prefix = options.conversation?.persistenceKey ?? "vinaverse.agent";
@@ -2710,6 +2802,7 @@ function createAgentRuntime(options) {
2710
2802
  if (!entry) return;
2711
2803
  live.delete(k);
2712
2804
  clearTimeout(entry.timer);
2805
+ clearTimeout(entry.grace);
2713
2806
  entry.store.dispose();
2714
2807
  emit({ type: "conversation_ended", key: k });
2715
2808
  changed();
@@ -2735,7 +2828,9 @@ function createAgentRuntime(options) {
2735
2828
  agent: options.agent ?? null,
2736
2829
  place: entry.place,
2737
2830
  placeRevision: ++entry.revision,
2738
- entryPoint: entry.entryPoint
2831
+ entryPoint: entry.entryPoint,
2832
+ ...options.sendAnchor && entry.anchor ? { anchor: entry.anchor } : {},
2833
+ ...options.sendAnchor && entry.via ? { entry: entry.via } : {}
2739
2834
  };
2740
2835
  const { conversationId, openId, place: told } = asked;
2741
2836
  let session;
@@ -2762,6 +2857,7 @@ function createAgentRuntime(options) {
2762
2857
  const unsettled = reason === "unknown_open" ? String(field(error, "openId") ?? openId) : null;
2763
2858
  update(entry, { failure, reason, code, openId: unsettled });
2764
2859
  emit({ type: "session_failed", key: entry.key, failure, reason });
2860
+ if (entry.shown === 0) end(entry.key);
2765
2861
  }
2766
2862
  throw error;
2767
2863
  }
@@ -2771,8 +2867,9 @@ function createAgentRuntime(options) {
2771
2867
  if (session.conversation_id)
2772
2868
  current.set(entry.key, session.conversation_id);
2773
2869
  const name = session.agent?.display_name?.trim();
2774
- if (name && name !== sessionName) {
2870
+ if (name && (name !== sessionName || names.get(key.mode) !== name)) {
2775
2871
  sessionName = name;
2872
+ names.set(key.mode, name);
2776
2873
  changed();
2777
2874
  }
2778
2875
  update(entry, {
@@ -2790,6 +2887,14 @@ function createAgentRuntime(options) {
2790
2887
  sessionId: session.id,
2791
2888
  ...entry.entryPoint ? { from: entry.entryPoint } : {}
2792
2889
  });
2890
+ if (entry.shown === 0) {
2891
+ if (entry.expiresAt === null || over(entry)) {
2892
+ end(entry.key);
2893
+ return session;
2894
+ }
2895
+ expireLater(entry);
2896
+ }
2897
+ if (!samePlace(told, entry.place)) tell(entry, {});
2793
2898
  return session;
2794
2899
  }
2795
2900
  const kept = (k) => `${prefix}.${k}`;
@@ -2804,6 +2909,7 @@ function createAgentRuntime(options) {
2804
2909
  live.clear();
2805
2910
  current.clear();
2806
2911
  sessionName = null;
2912
+ names.clear();
2807
2913
  status = null;
2808
2914
  reading = null;
2809
2915
  statusState = NO_STATUS;
@@ -2912,17 +3018,28 @@ function createAgentRuntime(options) {
2912
3018
  telling: false,
2913
3019
  queued: false,
2914
3020
  entryPoint: null,
3021
+ anchor: null,
3022
+ via: null,
2915
3023
  expiresAt: null,
2916
3024
  shown: 0,
2917
3025
  started: false,
2918
3026
  suspended: false,
2919
3027
  sentOnce: /* @__PURE__ */ new Set(),
2920
3028
  timer: void 0,
3029
+ grace: void 0,
2921
3030
  turns: /* @__PURE__ */ new Map(),
2922
3031
  failedOpen: void 0
2923
3032
  };
2924
3033
  return entry;
2925
3034
  }
3035
+ const suspend = (entry) => {
3036
+ clearTimeout(entry.grace);
3037
+ entry.grace = void 0;
3038
+ if (entry.shown > 0 || entry.suspended || live.get(entry.key) !== entry)
3039
+ return;
3040
+ entry.suspended = true;
3041
+ entry.store.setForeground(false);
3042
+ };
2926
3043
  const over = (entry) => entry.expiresAt !== null && entry.expiresAt <= clock.now();
2927
3044
  const expireLater = (entry) => {
2928
3045
  clearTimeout(entry.timer);
@@ -2940,6 +3057,9 @@ function createAgentRuntime(options) {
2940
3057
  const tell = (entry, at) => {
2941
3058
  if (at.place !== void 0) entry.place = at.place;
2942
3059
  if (at.entryPoint !== void 0) entry.entryPoint = at.entryPoint;
3060
+ if (at.anchor !== void 0)
3061
+ entry.anchor = at.anchor && anchorRef(at.anchor.type, at.anchor.id);
3062
+ if (at.entry !== void 0) entry.via = at.entry && entryOf(at.entry);
2943
3063
  const sessionId = entry.state.sessionId;
2944
3064
  const moved = sessionId !== null && !samePlace(entry.told, entry.place);
2945
3065
  update(entry, { moved });
@@ -3012,6 +3132,8 @@ function createAgentRuntime(options) {
3012
3132
  entry.shown++;
3013
3133
  clearTimeout(entry.timer);
3014
3134
  entry.timer = void 0;
3135
+ clearTimeout(entry.grace);
3136
+ entry.grace = void 0;
3015
3137
  if (entry.suspended) {
3016
3138
  entry.suspended = false;
3017
3139
  entry.store.setForeground(true);
@@ -3027,12 +3149,15 @@ function createAgentRuntime(options) {
3027
3149
  released = true;
3028
3150
  entry.shown--;
3029
3151
  if (entry.shown > 0 || live.get(entry.key) !== entry) return;
3030
- if (keepAlive === "view" || NOT_KEPT.has(entry.store.getSnapshot().status) || entry.expiresAt === null || over(entry)) {
3152
+ const status2 = entry.store.getSnapshot().status;
3153
+ const opening = status2 === "starting" && keepAlive !== "view";
3154
+ if (!opening && (keepAlive === "view" || NOT_KEPT.has(status2) || entry.expiresAt === null || over(entry))) {
3031
3155
  end(entry.key);
3032
3156
  return;
3033
3157
  }
3034
- entry.suspended = true;
3035
- entry.store.setForeground(false);
3158
+ if (graceMs > 0)
3159
+ entry.grace = setTimeout(() => suspend(entry), graceMs);
3160
+ else suspend(entry);
3036
3161
  expireLater(entry);
3037
3162
  };
3038
3163
  },
@@ -3102,6 +3227,9 @@ function createAgentRuntime(options) {
3102
3227
  forget(key) {
3103
3228
  forget(keyOf(key));
3104
3229
  },
3230
+ background() {
3231
+ for (const entry of live.values()) if (entry.grace) suspend(entry);
3232
+ },
3105
3233
  sweep() {
3106
3234
  for (const entry of [...live.values()])
3107
3235
  if (entry.shown === 0 && over(entry)) end(entry.key);
@@ -3160,7 +3288,7 @@ function createAgentRuntime(options) {
3160
3288
  getStatusState: () => statusState,
3161
3289
  backend,
3162
3290
  epoch: () => generation,
3163
- getName: () => sessionName ?? status?.value.displayName ?? null,
3291
+ getName: (mode) => (mode === void 0 ? sessionName : names.get(mode)) ?? status?.value.displayName ?? null,
3164
3292
  subscribe(listener) {
3165
3293
  listeners.add(listener);
3166
3294
  return () => listeners.delete(listener);
@@ -3344,7 +3472,10 @@ async function retrying(run, policy, signal, onRetry) {
3344
3472
 
3345
3473
  exports.AgentRefusal = AgentRefusal;
3346
3474
  exports.agentKey = agentKey;
3475
+ exports.anchorRef = anchorRef;
3476
+ exports.askAboutKey = askAboutKey;
3347
3477
  exports.createAgentRuntime = createAgentRuntime;
3478
+ exports.entryLabel = entryLabel;
3348
3479
  exports.greetedKey = greetedKey;
3349
3480
  exports.hashKey = hashKey;
3350
3481
  exports.isRefusal = isRefusal;