@m6d/cortex-angular 0.1.1 → 0.2.0

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.
@@ -44,6 +44,9 @@ function checkAttachmentPolicy(contentType, sizeBytes) {
44
44
  return "size";
45
45
  return "ok";
46
46
  }
47
+ function toUiMessage(message) {
48
+ return { ...message, role: message.role === "trigger" ? "user" : message.role };
49
+ }
47
50
  var CLIENT_TOOL_ANSWERS_KEY = "clientToolAnswers";
48
51
  var TIMEZONE_HEADER = "X-Cortex-Timezone";
49
52
 
@@ -412,10 +415,6 @@ import {
412
415
  EventType
413
416
  } from "@tanstack/ai";
414
417
  import { fetchServerSentEvents } from "@tanstack/ai-client";
415
- function toUiMessage(message) {
416
- const role = message.role === "trigger" ? "user" : message.role;
417
- return { id: message.id, role, parts: message.parts };
418
- }
419
418
  function newestUnsent(messages) {
420
419
  for (let index = messages.length - 1;index >= 0; index -= 1) {
421
420
  const message = messages[index];
@@ -454,8 +453,22 @@ function clientToolAnswers(tail) {
454
453
  });
455
454
  return answers.length > 0 ? answers : null;
456
455
  }
457
- function metadataByMessageId(rows) {
458
- return new Map(rows.flatMap((row) => row.metadata ? [[row.id, row.metadata]] : []));
456
+ async function* withCommittedTranscript(stream, options, lastSent) {
457
+ for await (const chunk of stream) {
458
+ if (chunk.type !== EventType.MESSAGES_SNAPSHOT) {
459
+ yield chunk;
460
+ continue;
461
+ }
462
+ const local = options.localMessages();
463
+ const boundary = local.findIndex((message) => message.id === lastSent);
464
+ const queued = boundary === -1 ? [] : local.slice(boundary + 1).filter((message) => message.role === "user");
465
+ options.onTranscriptCarried?.(chunk.timestamp ?? Date.now());
466
+ const merged = {
467
+ ...chunk,
468
+ messages: [...chunk.messages, ...queued]
469
+ };
470
+ yield merged;
471
+ }
459
472
  }
460
473
  function createCortexConnection(options) {
461
474
  const { api, thread } = options;
@@ -464,7 +477,8 @@ function createCortexConnection(options) {
464
477
  const connect = function(messages, data, abortSignal, runContext) {
465
478
  const tail = newestUnsent(messages);
466
479
  const answers = clientToolAnswers(tail);
467
- return answers ? turn.connect([], { ...data, [CLIENT_TOOL_ANSWERS_KEY]: answers }, abortSignal, runContext) : turn.connect(tail, data, abortSignal, runContext);
480
+ const stream = answers ? turn.connect([], { ...data, [CLIENT_TOOL_ANSWERS_KEY]: answers }, abortSignal, runContext) : turn.connect(tail, data, abortSignal, runContext);
481
+ return withCommittedTranscript(stream, options, messages.at(-1)?.id);
468
482
  };
469
483
  const join = fetchServerSentEvents(() => api.resolveUrl(`/chat/${thread.id}/stream`), requestOptions);
470
484
  let replayBase = [];
@@ -476,7 +490,7 @@ function createCortexConnection(options) {
476
490
  timestamp: Date.now(),
477
491
  messages: replayBase
478
492
  };
479
- yield* join.joinRun(runId, abortSignal);
493
+ yield* withCommittedTranscript(join.joinRun(runId, abortSignal), options, replayBase.at(-1)?.id);
480
494
  },
481
495
  hydrate: async () => {
482
496
  const hydration = await hydrateThread(options);
@@ -495,19 +509,18 @@ async function hydrateThread(options) {
495
509
  try {
496
510
  const rows = await api.listMessages(thread.id);
497
511
  const messages = rows.map(toUiMessage);
498
- options.onHydrated?.(rows, messages);
512
+ options.onHydrated?.(messages);
499
513
  return { messages, activeRun, interrupts: null };
500
514
  } finally {
501
515
  options.setLoadingMessages?.(false);
502
516
  }
503
517
  }
504
518
  async function settleTurn(options) {
519
+ if (options.isStale?.() || options.isStreaming())
520
+ return;
505
521
  try {
506
522
  const rows = await options.api.listMessages(options.threadId);
507
- if (options.isStale?.())
508
- return;
509
- options.absorbMetadata(metadataByMessageId(rows));
510
- if (options.isStreaming())
523
+ if (options.isStale?.() || options.isStreaming())
511
524
  return;
512
525
  const messages = rows.map(toUiMessage);
513
526
  options.setMessages(messages);
@@ -2000,23 +2013,16 @@ function localized(value, locale) {
2000
2013
  const byLocale = value;
2001
2014
  return byLocale[locale] ?? byLocale.en ?? Object.values(byLocale)[0];
2002
2015
  }
2003
- // src/internal/client/src/format/relative-time.ts
2004
- var UNITS = [
2005
- ["year", 31536000000],
2006
- ["month", 2592000000],
2007
- ["week", 604800000],
2008
- ["day", 86400000],
2009
- ["hour", 3600000],
2010
- ["minute", 60000],
2011
- ["second", 1000]
2012
- ];
2013
- function relativeTimeLabel(iso, locale, now = Date.now()) {
2014
- const at = Date.parse(iso);
2015
- if (Number.isNaN(at))
2016
+ // src/internal/client/src/format/time-label.ts
2017
+ function timeLabel(iso, locale, now = Date.now()) {
2018
+ const at = new Date(iso);
2019
+ if (Number.isNaN(at.getTime()))
2016
2020
  return "";
2017
- const elapsed = at - now;
2018
- const [unit, ms] = UNITS.find(([, size]) => Math.abs(elapsed) >= size) ?? UNITS[UNITS.length - 1];
2019
- return new Intl.RelativeTimeFormat(locale, { numeric: "auto" }).format(Math.round(elapsed / ms), unit);
2021
+ const isToday = at.toDateString() === new Date(now).toDateString();
2022
+ return new Intl.DateTimeFormat(locale, {
2023
+ ...isToday ? {} : { dateStyle: "medium" },
2024
+ timeStyle: "short"
2025
+ }).format(at);
2020
2026
  }
2021
2027
  // src/internal/client/src/format/save-blob.ts
2022
2028
  function saveBlob(blob, name) {
@@ -2095,6 +2101,8 @@ function createTurnLifecycle(options) {
2095
2101
  let streamDropped = false;
2096
2102
  let wasAborted = false;
2097
2103
  let wasWorking = false;
2104
+ let carriedTranscript = false;
2105
+ let owedSince;
2098
2106
  const dispatched = new Set;
2099
2107
  let adoptedInFlight = 0;
2100
2108
  let adoptedDelivered = false;
@@ -2170,11 +2178,9 @@ function createTurnLifecycle(options) {
2170
2178
  return pending.length > 0;
2171
2179
  }
2172
2180
  async function settle(messages) {
2173
- if (wasAborted) {
2174
- wasAborted = false;
2175
- return;
2176
- }
2177
- if (ownsRun) {
2181
+ const aborted = wasAborted;
2182
+ wasAborted = false;
2183
+ if (!aborted && ownsRun) {
2178
2184
  if (dispatchToolCalls(messages()))
2179
2185
  return;
2180
2186
  if (streamDropped)
@@ -2182,14 +2188,29 @@ function createTurnLifecycle(options) {
2182
2188
  else
2183
2189
  options.setRunning(false);
2184
2190
  }
2191
+ if (owedSince === undefined && (carriedTranscript || aborted))
2192
+ return;
2193
+ owedSince = undefined;
2185
2194
  const transcript = await options.refreshMessages();
2186
- if (ownsRun && transcript)
2195
+ if (!aborted && ownsRun && transcript)
2187
2196
  dispatchToolCalls(transcript);
2188
2197
  }
2189
2198
  return {
2190
2199
  chunkArrived() {
2191
2200
  serverAnswered = true;
2192
2201
  },
2202
+ transcriptCarried(at) {
2203
+ carriedTranscript = true;
2204
+ if (owedSince !== undefined && owedSince <= at)
2205
+ owedSince = undefined;
2206
+ },
2207
+ transcriptUpdated(updatedAt) {
2208
+ if (!wasWorking) {
2209
+ options.refreshMessages();
2210
+ return;
2211
+ }
2212
+ owedSince = Math.max(owedSince ?? 0, Date.parse(updatedAt));
2213
+ },
2193
2214
  streamFailed() {
2194
2215
  streamDropped = true;
2195
2216
  if (serverAnswered)
@@ -2201,6 +2222,7 @@ function createTurnLifecycle(options) {
2201
2222
  if (isLoading) {
2202
2223
  wasWorking = true;
2203
2224
  streamDropped = false;
2225
+ carriedTranscript = false;
2204
2226
  return;
2205
2227
  }
2206
2228
  if (!wasWorking)
@@ -2437,7 +2459,6 @@ var CortexChatService = class CortexChatService2 {
2437
2459
  return false;
2438
2460
  return unansweredToolCalls(chat.messages()).length > 0;
2439
2461
  }, ...ngDevMode ? [{ debugName: "hasPendingToolCalls" }] : []);
2440
- messageMetadata = signal(/* @__PURE__ */ new Map, ...ngDevMode ? [{ debugName: "messageMetadata" }] : []);
2441
2462
  capabilities = signal(undefined, ...ngDevMode ? [{ debugName: "capabilities" }] : []);
2442
2463
  events = new Subject;
2443
2464
  selectedThreadSnapshot = signal(undefined, ...ngDevMode ? [{ debugName: "selectedThreadSnapshot" }] : []);
@@ -2488,7 +2509,6 @@ var CortexChatService = class CortexChatService2 {
2488
2509
  this.chatInjector = undefined;
2489
2510
  this.lifecycle = undefined;
2490
2511
  this.isLoadingMessages.set(false);
2491
- this.messageMetadata.set(/* @__PURE__ */ new Map);
2492
2512
  const previousThread = this.selectedThread();
2493
2513
  if (!previousThread && !this.chat())
2494
2514
  return;
@@ -2524,12 +2544,12 @@ var CortexChatService = class CortexChatService2 {
2524
2544
  parts: [{
2525
2545
  type: "text",
2526
2546
  content: prompt
2527
- }]
2547
+ }],
2548
+ metadata: {
2549
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
2550
+ attachments
2551
+ }
2528
2552
  };
2529
- this.setMetadata(message.id, {
2530
- createdAt: (/* @__PURE__ */ new Date()).toISOString(),
2531
- attachments
2532
- });
2533
2553
  return from(this.chat().append(message));
2534
2554
  }));
2535
2555
  }
@@ -2579,8 +2599,6 @@ var CortexChatService = class CortexChatService2 {
2579
2599
  mountChat(thread, mode) {
2580
2600
  const initialMessages = mode === "reload" ? this.chat()?.messages() : undefined;
2581
2601
  this.chatInjector?.destroy();
2582
- if (mode !== "reload")
2583
- this.messageMetadata.set(/* @__PURE__ */ new Map);
2584
2602
  const injector = createEnvironmentInjector([], this.environmentInjector, "cortex-chat");
2585
2603
  this.chatInjector = injector;
2586
2604
  this.selectedThreadSnapshot.set(thread);
@@ -2631,11 +2649,14 @@ var CortexChatService = class CortexChatService2 {
2631
2649
  api: this.api,
2632
2650
  thread,
2633
2651
  mode,
2634
- onHydrated: (rows, messages) => {
2635
- if (this.chatInjector !== injector)
2636
- return;
2637
- this.absorbMetadata(metadataByMessageId(rows));
2638
- this.lifecycle?.hydrated(messages, thread.isRunning);
2652
+ localMessages: () => this.chat()?.messages() ?? [],
2653
+ onHydrated: (messages) => {
2654
+ if (this.chatInjector === injector)
2655
+ this.lifecycle?.hydrated(messages, thread.isRunning);
2656
+ },
2657
+ onTranscriptCarried: (at) => {
2658
+ if (this.chatInjector === injector)
2659
+ this.lifecycle?.transcriptCarried(at);
2639
2660
  },
2640
2661
  setLoadingMessages: (loading) => {
2641
2662
  if (this.chatInjector === injector)
@@ -2656,18 +2677,11 @@ var CortexChatService = class CortexChatService2 {
2656
2677
  threadId,
2657
2678
  isStale: () => this.chat() !== chat,
2658
2679
  isStreaming: () => this.isAgentWorking(),
2659
- absorbMetadata: (fresh) => this.absorbMetadata(fresh),
2660
2680
  setMessages: (messages) => {
2661
2681
  chat.setMessages(messages);
2662
2682
  }
2663
2683
  });
2664
2684
  }
2665
- absorbMetadata(fresh) {
2666
- this.messageMetadata.update((previous) => new Map([...previous, ...fresh]));
2667
- }
2668
- setMetadata(messageId, metadata) {
2669
- this.messageMetadata.update((current) => new Map(current).set(messageId, metadata));
2670
- }
2671
2685
  subscribeToWsEvents() {
2672
2686
  this.wsService.events.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((event) => {
2673
2687
  this.onWsEvent(event);
@@ -2684,7 +2698,8 @@ var CortexChatService = class CortexChatService2 {
2684
2698
  this.reattach(event.payload.thread);
2685
2699
  break;
2686
2700
  case "thread:messages-updated":
2687
- this.refreshMessages(event.payload.thread.id);
2701
+ if (this.selectedThread()?.id === event.payload.thread.id)
2702
+ this.lifecycle?.transcriptUpdated(event.payload.thread.updatedAt);
2688
2703
  }
2689
2704
  }
2690
2705
  subscribeToWsConnections() {
@@ -3430,7 +3445,7 @@ var ChatLandingComponent = class ChatLandingComponent2 {
3430
3445
  this.chatService.send(suggestion.prompt).subscribe();
3431
3446
  }
3432
3447
  relativeTime(iso) {
3433
- return relativeTimeLabel(iso, this.locale());
3448
+ return timeLabel(iso, this.locale());
3434
3449
  }
3435
3450
  static ɵfac = i0.ɵɵngDeclareFactory({
3436
3451
  minVersion: "12.0.0",
@@ -8412,7 +8427,6 @@ var MessageBodyComponent = class MessageBodyComponent2 {
8412
8427
  fold = input(...ngDevMode ? [undefined, { debugName: "fold" }] : []);
8413
8428
  openRun = output();
8414
8429
  locale = inject(CORTEX_LOCALE);
8415
- revealedAt = signal(Date.now(), ...ngDevMode ? [{ debugName: "revealedAt" }] : []);
8416
8430
  isAssistant = computed(() => this.message().role === "assistant", ...ngDevMode ? [{ debugName: "isAssistant" }] : []);
8417
8431
  isUser = computed(() => this.message().role === "user", ...ngDevMode ? [{ debugName: "isUser" }] : []);
8418
8432
  streamingPartIndex = computed(() => this.isStreaming() ? this.parts().length - 1 : -1, ...ngDevMode ? [{ debugName: "streamingPartIndex" }] : []);
@@ -8433,13 +8447,10 @@ var MessageBodyComponent = class MessageBodyComponent2 {
8433
8447
  key: source.indexOf(part)
8434
8448
  }));
8435
8449
  }, ...ngDevMode ? [{ debugName: "keyedParts" }] : []);
8436
- sentAgo = computed(() => {
8450
+ sentAt = computed(() => {
8437
8451
  const at = this.createdAt();
8438
- return at ? relativeTimeLabel(at, this.locale(), this.revealedAt()) : "";
8439
- }, ...ngDevMode ? [{ debugName: "sentAgo" }] : []);
8440
- reveal() {
8441
- this.revealedAt.set(Date.now());
8442
- }
8452
+ return at ? timeLabel(at, this.locale()) : "";
8453
+ }, ...ngDevMode ? [{ debugName: "sentAt" }] : []);
8443
8454
  foldedSteps(part) {
8444
8455
  const mark = this.fold()?.get(part);
8445
8456
  if (mark?.kind !== "more")
@@ -8519,13 +8530,7 @@ var MessageBodyComponent = class MessageBodyComponent2 {
8519
8530
  }
8520
8531
  },
8521
8532
  outputs: { openRun: "openRun" },
8522
- host: {
8523
- listeners: {
8524
- mouseenter: "reveal()",
8525
- focusin: "reveal()"
8526
- },
8527
- classAttribute: "cortex-message-parts"
8528
- },
8533
+ host: { classAttribute: "cortex-message-parts" },
8529
8534
  ngImport: i0,
8530
8535
  template: `@for (drawn of keyedParts(); track drawn.key) {
8531
8536
  @let part = drawn.part;
@@ -8570,7 +8575,7 @@ var MessageBodyComponent = class MessageBodyComponent2 {
8570
8575
  <cortex-copy-button [value]="text" />
8571
8576
  }
8572
8577
  @if (createdAt(); as at) {
8573
- <time class="cortex-message-actions__time" [attr.datetime]="at">{{ sentAgo() }}</time>
8578
+ <time class="cortex-message-actions__time" [attr.datetime]="at">{{ sentAt() }}</time>
8574
8579
  }
8575
8580
  </div>
8576
8581
  </ng-template>
@@ -8671,11 +8676,7 @@ i0.ɵɵngDeclareClassMetadata({
8671
8676
  NgTemplateOutlet,
8672
8677
  TranslatePipe
8673
8678
  ],
8674
- host: {
8675
- class: "cortex-message-parts",
8676
- "(mouseenter)": "reveal()",
8677
- "(focusin)": "reveal()"
8678
- },
8679
+ host: { class: "cortex-message-parts" },
8679
8680
  template: `@for (drawn of keyedParts(); track drawn.key) {
8680
8681
  @let part = drawn.part;
8681
8682
  <cortex-message-part
@@ -8719,7 +8720,7 @@ i0.ɵɵngDeclareClassMetadata({
8719
8720
  <cortex-copy-button [value]="text" />
8720
8721
  }
8721
8722
  @if (createdAt(); as at) {
8722
- <time class="cortex-message-actions__time" [attr.datetime]="at">{{ sentAgo() }}</time>
8723
+ <time class="cortex-message-actions__time" [attr.datetime]="at">{{ sentAt() }}</time>
8723
8724
  }
8724
8725
  </div>
8725
8726
  </ng-template>
@@ -8805,7 +8806,7 @@ var TriggerBlockComponent = class TriggerBlockComponent2 {
8805
8806
  firing = input.required(...ngDevMode ? [{ debugName: "firing" }] : []);
8806
8807
  debugMode = input(false, ...ngDevMode ? [{ debugName: "debugMode" }] : []);
8807
8808
  locale = inject(CORTEX_LOCALE);
8808
- firedAgo = computed(() => relativeTimeLabel(this.firing().firedAt, this.locale()), ...ngDevMode ? [{ debugName: "firedAgo" }] : []);
8809
+ firedAgo = computed(() => timeLabel(this.firing().firedAt, this.locale()), ...ngDevMode ? [{ debugName: "firedAgo" }] : []);
8809
8810
  static ɵfac = i0.ɵɵngDeclareFactory({
8810
8811
  minVersion: "12.0.0",
8811
8812
  version: "22.2.0",
@@ -8942,7 +8943,7 @@ var MessageComponent = class MessageComponent2 {
8942
8943
  return false;
8943
8944
  return streamingMessage(this.chatService.messages())?.id === this.message().id;
8944
8945
  }, ...ngDevMode ? [{ debugName: "isStreaming" }] : []);
8945
- metadata = computed(() => this.chatService.messageMetadata().get(this.message().id), ...ngDevMode ? [{ debugName: "metadata" }] : []);
8946
+ metadata = computed(() => this.message().metadata, ...ngDevMode ? [{ debugName: "metadata" }] : []);
8946
8947
  visibleParts = computed(() => visibleMessageParts(this.message().parts, {
8947
8948
  debugMode: this.debugMode(),
8948
8949
  isStreaming: this.isStreaming(),
@@ -9401,7 +9402,7 @@ var ThreadListComponent = class ThreadListComponent2 {
9401
9402
  return count2 === 1 ? "translate_one_conversation" : "translate_n_conversations";
9402
9403
  }
9403
9404
  relativeTime(iso) {
9404
- return relativeTimeLabel(iso, this.locale());
9405
+ return timeLabel(iso, this.locale());
9405
9406
  }
9406
9407
  static ɵfac = i0.ɵɵngDeclareFactory({
9407
9408
  minVersion: "12.0.0",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@m6d/cortex-angular",
3
- "version": "0.1.1",
3
+ "version": "0.2.0",
4
4
  "description": "Reusable AI agent chat UI library for Angular",
5
5
  "license": "MIT",
6
6
  "sideEffects": false,
@@ -10,11 +10,6 @@ declare const LOCALES: readonly [
10
10
  "ar"
11
11
  ];
12
12
  export type Locale = (typeof LOCALES)[number];
13
- declare const TOOL_SURFACES: readonly [
14
- "inline",
15
- "modal"
16
- ];
17
- export type ToolSurface = (typeof TOOL_SURFACES)[number];
18
13
  declare const ATTACHMENT_STATUSES: readonly [
19
14
  "pending",
20
15
  "described",
@@ -47,32 +42,6 @@ export type ThreadSummary = {
47
42
  name: string;
48
43
  };
49
44
  };
50
- export type TokenUsage = {
51
- input: {
52
- noCache: number;
53
- cacheRead: number;
54
- cacheWrite: number;
55
- total: number;
56
- };
57
- output: {
58
- reasoning: number;
59
- text: number;
60
- total: number;
61
- };
62
- total: number;
63
- };
64
- /**
65
- * How to launch one client tool: stamped by the server, per tool name, on
66
- * the metadata of an assistant message that may carry its pending call. Kept in
67
- * the message so the binding survives server restarts while a run is parked.
68
- */
69
- export type ClientToolBinding = {
70
- toolId: string;
71
- surface: ToolSurface;
72
- embedOrigin: string;
73
- /** Variables the initiate call's input reads. */
74
- variables: string[];
75
- };
76
45
  /**
77
46
  * What the server offers this agent's clients, fetched once at widget startup.
78
47
  * The widget hides UI for anything absent; enforcement stays server-side.
@@ -86,18 +55,6 @@ export type AgentCapabilities = {
86
55
  /** Headline of the blank-chat landing per locale; "" falls back to the widget's built-in copy. */
87
56
  greeting: Greeting;
88
57
  };
89
- export type MessageMetadata = {
90
- /** ISO time the server stored the message; stamped from the row when a transcript is served. */
91
- createdAt?: string;
92
- modelId?: string;
93
- providerMetadata?: unknown;
94
- isAborted?: boolean;
95
- tokenUsage?: TokenUsage;
96
- attachments?: AttachmentSummary[];
97
- clientTools?: Record<string, ClientToolBinding>;
98
- /** Set on `trigger` messages: the firing that wrote them. */
99
- trigger?: TriggerFiringSummary;
100
- };
101
58
  /**
102
59
  * One landing-page chip: the widget shows `title` and sends `prompt` as the
103
60
  * first message when clicked. The two may be the same text.
@@ -109,12 +66,6 @@ export type Suggestion = {
109
66
  /** The runtime contract's `suggestionsSchema` and `greetingSchema` are built from these. */
110
67
  export type Suggestions = Record<Locale, Suggestion[]>;
111
68
  export type Greeting = Record<Locale, string>;
112
- export type TriggerFiringSummary = {
113
- name: string;
114
- firingId: string;
115
- firedAt: string;
116
- payload: unknown;
117
- };
118
69
  export type CortexHeaders = Record<string, string>;
119
70
  /**
120
71
  * How the widget reaches its cortex server. `baseUrl` may be a thunk so a host
@@ -287,13 +238,6 @@ declare class CortexChatService {
287
238
  * only resolves once the continuation turn ends, far too late to gate UI on.
288
239
  */
289
240
  readonly hasPendingToolCalls: import("@angular/core").Signal<boolean>;
290
- /**
291
- * The per-message facts the SDK's `UIMessage` has no room for — usage, model
292
- * id, the aborted flag, attachments. They are cortex's own envelope around the
293
- * stored parts, so they arrive with the persisted transcript rather than over
294
- * the stream, and are merged back in by message id at render time.
295
- */
296
- readonly messageMetadata: import("@angular/core").WritableSignal<ReadonlyMap<string, MessageMetadata>>;
297
241
  /** What the server offers this agent's clients; undefined until the handshake answers. */
298
242
  readonly capabilities: import("@angular/core").WritableSignal<AgentCapabilities | undefined>;
299
243
  private readonly events;
@@ -361,13 +305,6 @@ declare class CortexChatService {
361
305
  private createConnection;
362
306
  private refreshMessages;
363
307
  private readBackMessages;
364
- /**
365
- * Server rows are merged over what is held, never swapped in: the entry this
366
- * client seeded for a message it just sent must outlive a hydration or
367
- * read-back that started before the send.
368
- */
369
- private absorbMetadata;
370
- private setMetadata;
371
308
  private subscribeToWsEvents;
372
309
  /**
373
310
  * Only what these events mean for the open conversation — their list-shaped