@ably/ai-transport 0.1.0 → 0.3.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.
Files changed (221) hide show
  1. package/README.md +93 -111
  2. package/dist/ably-ai-transport.js +2401 -1387
  3. package/dist/ably-ai-transport.js.map +1 -1
  4. package/dist/ably-ai-transport.umd.cjs +1 -1
  5. package/dist/ably-ai-transport.umd.cjs.map +1 -1
  6. package/dist/constants.d.ts +116 -42
  7. package/dist/core/agent.d.ts +44 -0
  8. package/dist/core/channel-options.d.ts +57 -0
  9. package/dist/core/codec/codec-event.d.ts +9 -0
  10. package/dist/core/codec/decoder.d.ts +24 -24
  11. package/dist/core/codec/define-codec.d.ts +100 -0
  12. package/dist/core/codec/encoder.d.ts +10 -12
  13. package/dist/core/codec/field-bag.d.ts +85 -0
  14. package/dist/core/codec/fields.d.ts +141 -0
  15. package/dist/core/codec/index.d.ts +8 -2
  16. package/dist/core/codec/input-descriptor-decoder.d.ts +19 -0
  17. package/dist/core/codec/input-descriptor-encoder.d.ts +22 -0
  18. package/dist/core/codec/input-descriptors.d.ts +281 -0
  19. package/dist/core/codec/lifecycle-tracker.d.ts +10 -9
  20. package/dist/core/codec/output-descriptor-decoder.d.ts +29 -0
  21. package/dist/core/codec/output-descriptor-encoder.d.ts +31 -0
  22. package/dist/core/codec/output-descriptors.d.ts +237 -0
  23. package/dist/core/codec/types.d.ts +470 -119
  24. package/dist/core/codec/well-known-inputs.d.ts +52 -0
  25. package/dist/core/transport/agent-session.d.ts +10 -0
  26. package/dist/core/transport/agent-view.d.ts +296 -0
  27. package/dist/core/transport/client-session.d.ts +13 -0
  28. package/dist/core/transport/decode-fold.d.ts +55 -0
  29. package/dist/core/transport/headers.d.ts +121 -14
  30. package/dist/core/transport/index.d.ts +5 -6
  31. package/dist/core/transport/internal/bounded-map.d.ts +20 -0
  32. package/dist/core/transport/invocation.d.ts +74 -0
  33. package/dist/core/transport/load-history-pages.d.ts +71 -0
  34. package/dist/core/transport/load-history.d.ts +44 -0
  35. package/dist/core/transport/pipe-stream.d.ts +9 -9
  36. package/dist/core/transport/run-manager.d.ts +76 -0
  37. package/dist/core/transport/session-support.d.ts +55 -0
  38. package/dist/core/transport/tree.d.ts +523 -109
  39. package/dist/core/transport/types/agent.d.ts +375 -0
  40. package/dist/core/transport/types/client.d.ts +201 -0
  41. package/dist/core/transport/types/shared.d.ts +24 -0
  42. package/dist/core/transport/types/tree.d.ts +357 -0
  43. package/dist/core/transport/types/view.d.ts +249 -0
  44. package/dist/core/transport/types.d.ts +13 -553
  45. package/dist/core/transport/view.d.ts +390 -84
  46. package/dist/core/transport/wire-log.d.ts +102 -0
  47. package/dist/errors.d.ts +27 -10
  48. package/dist/index.d.ts +8 -9
  49. package/dist/logger.d.ts +12 -0
  50. package/dist/react/ably-ai-transport-react.js +1365 -1010
  51. package/dist/react/ably-ai-transport-react.js.map +1 -1
  52. package/dist/react/ably-ai-transport-react.umd.cjs +1 -1
  53. package/dist/react/ably-ai-transport-react.umd.cjs.map +1 -1
  54. package/dist/react/contexts/client-session-context.d.ts +37 -0
  55. package/dist/react/contexts/client-session-provider.d.ts +56 -0
  56. package/dist/react/create-session-hooks.d.ts +116 -0
  57. package/dist/react/index.d.ts +13 -12
  58. package/dist/react/internal/skipped-session.d.ts +8 -0
  59. package/dist/react/internal/use-resolved-session.d.ts +36 -0
  60. package/dist/react/use-ably-messages.d.ts +17 -14
  61. package/dist/react/use-client-session.d.ts +81 -0
  62. package/dist/react/use-create-view.d.ts +14 -13
  63. package/dist/react/use-tree.d.ts +30 -15
  64. package/dist/react/use-view.d.ts +81 -50
  65. package/dist/utils.d.ts +48 -71
  66. package/dist/vercel/ably-ai-transport-vercel.js +3257 -2499
  67. package/dist/vercel/ably-ai-transport-vercel.js.map +1 -1
  68. package/dist/vercel/ably-ai-transport-vercel.umd.cjs +1 -1
  69. package/dist/vercel/ably-ai-transport-vercel.umd.cjs.map +1 -1
  70. package/dist/vercel/codec/decode-lifecycle.d.ts +9 -0
  71. package/dist/vercel/codec/events.d.ts +50 -0
  72. package/dist/vercel/codec/fields.d.ts +44 -0
  73. package/dist/vercel/codec/fold-content.d.ts +16 -0
  74. package/dist/vercel/codec/fold-data.d.ts +16 -0
  75. package/dist/vercel/codec/fold-input.d.ts +67 -0
  76. package/dist/vercel/codec/fold-lifecycle.d.ts +16 -0
  77. package/dist/vercel/codec/fold-text.d.ts +16 -0
  78. package/dist/vercel/codec/fold-tool-input.d.ts +17 -0
  79. package/dist/vercel/codec/fold-tool-output.d.ts +16 -0
  80. package/dist/vercel/codec/index.d.ts +7 -20
  81. package/dist/vercel/codec/inputs.d.ts +11 -0
  82. package/dist/vercel/codec/outputs.d.ts +11 -0
  83. package/dist/vercel/codec/reducer-state.d.ts +121 -0
  84. package/dist/vercel/codec/reducer.d.ts +62 -0
  85. package/dist/vercel/codec/tool-transitions.d.ts +2 -8
  86. package/dist/vercel/codec/wire-data.d.ts +34 -0
  87. package/dist/vercel/index.d.ts +5 -5
  88. package/dist/vercel/react/ably-ai-transport-vercel-react.js +2859 -9705
  89. package/dist/vercel/react/ably-ai-transport-vercel-react.js.map +1 -1
  90. package/dist/vercel/react/ably-ai-transport-vercel-react.umd.cjs +1 -45
  91. package/dist/vercel/react/ably-ai-transport-vercel-react.umd.cjs.map +1 -1
  92. package/dist/vercel/react/contexts/chat-transport-context.d.ts +9 -7
  93. package/dist/vercel/react/contexts/chat-transport-provider.d.ts +53 -41
  94. package/dist/vercel/react/index.d.ts +1 -2
  95. package/dist/vercel/react/use-chat-transport.d.ts +30 -26
  96. package/dist/vercel/react/use-message-sync.d.ts +17 -30
  97. package/dist/vercel/run-end-reason.d.ts +84 -0
  98. package/dist/vercel/tool-part.d.ts +21 -0
  99. package/dist/vercel/transport/chat-transport.d.ts +41 -24
  100. package/dist/vercel/transport/index.d.ts +24 -20
  101. package/dist/vercel/transport/run-output-stream.d.ts +54 -0
  102. package/dist/version.d.ts +2 -0
  103. package/package.json +31 -24
  104. package/src/constants.ts +124 -51
  105. package/src/core/agent.ts +92 -0
  106. package/src/core/channel-options.ts +89 -0
  107. package/src/core/codec/codec-event.ts +27 -0
  108. package/src/core/codec/decoder.ts +202 -105
  109. package/src/core/codec/define-codec.ts +432 -0
  110. package/src/core/codec/encoder.ts +114 -107
  111. package/src/core/codec/field-bag.ts +142 -0
  112. package/src/core/codec/fields.ts +193 -0
  113. package/src/core/codec/index.ts +56 -6
  114. package/src/core/codec/input-descriptor-decoder.ts +97 -0
  115. package/src/core/codec/input-descriptor-encoder.ts +150 -0
  116. package/src/core/codec/input-descriptors.ts +373 -0
  117. package/src/core/codec/lifecycle-tracker.ts +10 -9
  118. package/src/core/codec/output-descriptor-decoder.ts +139 -0
  119. package/src/core/codec/output-descriptor-encoder.ts +101 -0
  120. package/src/core/codec/output-descriptors.ts +307 -0
  121. package/src/core/codec/types.ts +505 -126
  122. package/src/core/codec/well-known-inputs.ts +96 -0
  123. package/src/core/transport/agent-session.ts +1085 -0
  124. package/src/core/transport/agent-view.ts +738 -0
  125. package/src/core/transport/client-session.ts +780 -0
  126. package/src/core/transport/decode-fold.ts +101 -0
  127. package/src/core/transport/headers.ts +234 -22
  128. package/src/core/transport/index.ts +27 -27
  129. package/src/core/transport/internal/bounded-map.ts +27 -0
  130. package/src/core/transport/invocation.ts +98 -0
  131. package/src/core/transport/load-history-pages.ts +220 -0
  132. package/src/core/transport/load-history.ts +271 -0
  133. package/src/core/transport/pipe-stream.ts +63 -39
  134. package/src/core/transport/run-manager.ts +243 -0
  135. package/src/core/transport/session-support.ts +96 -0
  136. package/src/core/transport/tree.ts +1293 -308
  137. package/src/core/transport/types/agent.ts +434 -0
  138. package/src/core/transport/types/client.ts +247 -0
  139. package/src/core/transport/types/shared.ts +27 -0
  140. package/src/core/transport/types/tree.ts +393 -0
  141. package/src/core/transport/types/view.ts +288 -0
  142. package/src/core/transport/types.ts +13 -706
  143. package/src/core/transport/view.ts +1229 -450
  144. package/src/core/transport/wire-log.ts +189 -0
  145. package/src/errors.ts +29 -9
  146. package/src/event-emitter.ts +3 -2
  147. package/src/index.ts +86 -42
  148. package/src/logger.ts +14 -1
  149. package/src/react/contexts/client-session-context.ts +41 -0
  150. package/src/react/contexts/client-session-provider.tsx +222 -0
  151. package/src/react/create-session-hooks.ts +141 -0
  152. package/src/react/index.ts +24 -13
  153. package/src/react/internal/skipped-session.ts +62 -0
  154. package/src/react/internal/use-resolved-session.ts +63 -0
  155. package/src/react/use-ably-messages.ts +32 -22
  156. package/src/react/use-client-session.ts +178 -0
  157. package/src/react/use-create-view.ts +33 -29
  158. package/src/react/use-tree.ts +61 -30
  159. package/src/react/use-view.ts +138 -96
  160. package/src/utils.ts +83 -131
  161. package/src/vercel/codec/decode-lifecycle.ts +70 -0
  162. package/src/vercel/codec/events.ts +85 -0
  163. package/src/vercel/codec/fields.ts +58 -0
  164. package/src/vercel/codec/fold-content.ts +54 -0
  165. package/src/vercel/codec/fold-data.ts +46 -0
  166. package/src/vercel/codec/fold-input.ts +255 -0
  167. package/src/vercel/codec/fold-lifecycle.ts +85 -0
  168. package/src/vercel/codec/fold-text.ts +55 -0
  169. package/src/vercel/codec/fold-tool-input.ts +86 -0
  170. package/src/vercel/codec/fold-tool-output.ts +79 -0
  171. package/src/vercel/codec/index.ts +28 -21
  172. package/src/vercel/codec/inputs.ts +116 -0
  173. package/src/vercel/codec/outputs.ts +207 -0
  174. package/src/vercel/codec/reducer-state.ts +169 -0
  175. package/src/vercel/codec/reducer.ts +191 -0
  176. package/src/vercel/codec/tool-transitions.ts +3 -14
  177. package/src/vercel/codec/wire-data.ts +64 -0
  178. package/src/vercel/index.ts +7 -19
  179. package/src/vercel/react/contexts/chat-transport-context.ts +8 -7
  180. package/src/vercel/react/contexts/chat-transport-provider.tsx +87 -59
  181. package/src/vercel/react/index.ts +3 -5
  182. package/src/vercel/react/use-chat-transport.ts +44 -66
  183. package/src/vercel/react/use-message-sync.ts +75 -39
  184. package/src/vercel/run-end-reason.ts +157 -0
  185. package/src/vercel/tool-part.ts +25 -0
  186. package/src/vercel/transport/chat-transport.ts +380 -98
  187. package/src/vercel/transport/index.ts +38 -37
  188. package/src/vercel/transport/run-output-stream.ts +169 -0
  189. package/src/version.ts +2 -0
  190. package/dist/core/transport/client-transport.d.ts +0 -10
  191. package/dist/core/transport/decode-history.d.ts +0 -43
  192. package/dist/core/transport/server-transport.d.ts +0 -7
  193. package/dist/core/transport/stream-router.d.ts +0 -29
  194. package/dist/core/transport/turn-manager.d.ts +0 -37
  195. package/dist/react/contexts/transport-context.d.ts +0 -31
  196. package/dist/react/contexts/transport-provider.d.ts +0 -49
  197. package/dist/react/create-transport-hooks.d.ts +0 -124
  198. package/dist/react/use-active-turns.d.ts +0 -12
  199. package/dist/react/use-client-transport.d.ts +0 -80
  200. package/dist/vercel/codec/accumulator.d.ts +0 -21
  201. package/dist/vercel/codec/decoder.d.ts +0 -22
  202. package/dist/vercel/codec/encoder.d.ts +0 -41
  203. package/dist/vercel/react/use-staged-add-tool-approval-response.d.ts +0 -30
  204. package/dist/vercel/tool-approvals.d.ts +0 -124
  205. package/dist/vercel/tool-events.d.ts +0 -26
  206. package/src/core/transport/client-transport.ts +0 -977
  207. package/src/core/transport/decode-history.ts +0 -485
  208. package/src/core/transport/server-transport.ts +0 -612
  209. package/src/core/transport/stream-router.ts +0 -136
  210. package/src/core/transport/turn-manager.ts +0 -165
  211. package/src/react/contexts/transport-context.ts +0 -37
  212. package/src/react/contexts/transport-provider.tsx +0 -164
  213. package/src/react/create-transport-hooks.ts +0 -144
  214. package/src/react/use-active-turns.ts +0 -72
  215. package/src/react/use-client-transport.ts +0 -197
  216. package/src/vercel/codec/accumulator.ts +0 -588
  217. package/src/vercel/codec/decoder.ts +0 -618
  218. package/src/vercel/codec/encoder.ts +0 -410
  219. package/src/vercel/react/use-staged-add-tool-approval-response.ts +0 -87
  220. package/src/vercel/tool-approvals.ts +0 -380
  221. package/src/vercel/tool-events.ts +0 -53
@@ -1,161 +1,466 @@
1
1
  import { Logger } from '../../logger.js';
2
- import { Codec } from '../codec/types.js';
2
+ import { Codec, CodecInputEvent, CodecMessage, CodecOutputEvent } from '../codec/types.js';
3
+ import { WireApplier } from './decode-fold.js';
3
4
  import { TreeInternal } from './tree.js';
4
- import { ActiveTurn, EventsNode, MessageNode, SendOptions, TurnLifecycleEvent, View } from './types.js';
5
+ import { ActiveRun, BranchSelection, RunInfo, RunLifecycleEvent, SendOptions, View } from './types.js';
5
6
  /**
6
7
  * DefaultView — a paginated, branch-aware projection over the Tree.
7
8
  *
8
- * Wraps a Tree and manages a pagination window that controls which nodes
9
- * are visible to the UI. New live messages appear immediately; older messages
10
- * are revealed progressively via `loadOlder()`.
9
+ * Wraps a Tree (RunNode-keyed) and manages a pagination window that controls
10
+ * which Runs are visible to the UI. New live Runs appear immediately; older
11
+ * Runs are revealed progressively via `loadOlder()`.
12
+ *
13
+ * `getMessages()` reads the Tree's visible node chain (input nodes + reply
14
+ * runs, with sibling selection applied) and concatenates each node's
15
+ * `codec.getMessages(node.projection)` to produce the flat
16
+ * `CodecMessage<TMessage>[]` the UI renders.
11
17
  *
12
18
  * Each View owns its own branch selection state and pagination window,
13
19
  * allowing multiple independent Views over the same Tree.
14
20
  *
15
21
  * Events are scoped to the visible window — 'update' only fires when the
16
22
  * visible output changes, 'ably-message' only for messages corresponding to
17
- * visible nodes, and 'turn' only for turns with visible messages.
23
+ * visible Runs, and 'run' only for runs with visible content.
18
24
  */
19
25
  import * as Ably from 'ably';
20
26
  /**
21
- * Internal delegate function provided by the transport for executing sends.
22
- * The View pre-computes the visible branch history and passes it directly,
23
- * so the delegate has no back-reference to the View.
24
- * When `eventNodes` is provided, the transport includes them in the POST body
25
- * for the server to publish as cross-turn events.
27
+ * Internal delegate function provided by the session for executing sends.
28
+ * The View pre-computes the visible branch's flat message list and the
29
+ * codec-message-id of its tail (for auto-parent routing) before calling
30
+ * the delegate, so the delegate has no back-reference to the View.
31
+ *
32
+ * Each TInput carries its own routing metadata (`parent` / `target` /
33
+ * `codecMessageId`) via the {@link CodecInputEvent} base; the delegate
34
+ * reads those fields directly without runtime classification.
35
+ *
36
+ * `parentCodecMessageId` is the codec-message-id of the last message in
37
+ * the visible branch (extracted from the tail Run's projection per codec
38
+ * convention), or `undefined` for an empty conversation. The session
39
+ * uses it as the auto-parent for fresh user messages.
26
40
  */
27
- export type SendDelegate<TEvent, TMessage> = (input: TMessage | TMessage[], options: SendOptions | undefined, history: MessageNode<TMessage>[], eventNodes?: EventsNode<TEvent>[]) => Promise<ActiveTurn<TEvent>>;
41
+ export type SendDelegate<TInput extends CodecInputEvent> = (input: TInput[], options: SendOptions | undefined, parentCodecMessageId: string | undefined) => Promise<ActiveRun>;
28
42
  /** Options for creating a View. */
29
- export interface ViewOptions<TEvent, TMessage> {
43
+ interface ViewOptions<TInput extends CodecInputEvent, TOutput extends CodecOutputEvent, TProjection, TMessage> {
30
44
  /** The tree to project. */
31
- tree: TreeInternal<TMessage>;
45
+ tree: TreeInternal<TInput, TOutput, TProjection>;
32
46
  /** The Ably channel to load history from. */
33
47
  channel: Ably.RealtimeChannel;
34
- /** The codec for decoding history messages. */
35
- codec: Codec<TEvent, TMessage>;
36
- /** Delegate for executing sends through the transport. */
37
- sendDelegate: SendDelegate<TEvent, TMessage>;
48
+ /** The codec used to project messages and mint regenerate inputs. */
49
+ codec: Codec<TInput, TOutput, TProjection, TMessage>;
50
+ /**
51
+ * The Tree's single decode-and-apply engine, owned by the session and
52
+ * shared with the live decode loop. History replay feeds pages through it
53
+ * so the one decoder instance sees every route into the Tree.
54
+ */
55
+ applier: WireApplier;
56
+ /** Delegate for executing sends through the session. */
57
+ sendDelegate: SendDelegate<TInput>;
38
58
  /** Logger for diagnostic output. */
39
59
  logger: Logger;
40
60
  /** Called when the view is closed, allowing the owner to clean up references. */
41
61
  onClose?: () => void;
42
62
  }
43
- export declare class DefaultView<TEvent, TMessage> implements View<TEvent, TMessage> {
63
+ export declare class DefaultView<TInput extends CodecInputEvent, TOutput extends CodecOutputEvent, TProjection, TMessage> implements View<TInput, TMessage> {
44
64
  private readonly _tree;
45
65
  private readonly _channel;
46
66
  private readonly _codec;
67
+ private readonly _applier;
47
68
  private readonly _sendDelegate;
48
69
  private readonly _logger;
49
70
  private readonly _emitter;
50
71
  private readonly _onClose?;
51
72
  /**
52
- * View-local branch selections: group root msgId → selection intent.
73
+ * View-local branch selections: group-root runId → selection intent.
53
74
  * Fork points not present here default to the latest sibling.
54
- * Replaces the previous numeric-index _selections and _pendingForkSelections
55
- * with a single tagged-union map that carries the selected msgId (not index)
56
- * and the reason for the selection.
57
75
  */
58
76
  private readonly _branchSelections;
59
- /** Spec: AIT-CT11c — msg-ids loaded from history but not yet revealed to the UI. */
60
- private readonly _withheldMsgIds;
61
- /** Snapshot of visible msgIds — used to detect structural changes and for selection pinning. */
62
- private _lastVisibleIds;
63
- /** Snapshot of visible message references used to detect in-place content updates (streaming). */
64
- private _lastVisibleMessages;
65
- /** Cached set of turn IDs present on the visible branch avoids recomputing flattenNodes() on turn events. */
66
- private _lastVisibleTurnIds;
77
+ /**
78
+ * View-local regenerate-group selections: anchor codec-message-id (the assistant
79
+ * codec-message-id being regenerated) selection intent. Distinct from
80
+ * {@link _branchSelections} because a regenerate group is a set of
81
+ * same-parent reply runsmessage-level alternatives at a single
82
+ * conversation slot, not edit forks of the prompt. Groups not present here default to the latest
83
+ * member (the most recent regenerator, or the original if no regen has
84
+ * landed).
85
+ */
86
+ private readonly _regenSelections;
87
+ /**
88
+ * Non-head regenerate selections, keyed by the regenerate target's
89
+ * codec-message-id. Separate from {@link _regenSelections} because a non-head
90
+ * regenerator parents inside the owner run rather than as a same-parent
91
+ * sibling, so it lives outside the Tree's `visibleNodes` selection space and
92
+ * is resolved at extraction (see `_extractMessages`). Value is the selected
93
+ * member's nodeKey (the owner run id, or a regenerator run id); absent groups
94
+ * default to the newest regenerator.
95
+ */
96
+ private readonly _nonHeadRegenSelections;
97
+ /** Spec: AIT-CT11c — runIds loaded from history but not yet revealed to the UI. */
98
+ private readonly _withheldRunIds;
99
+ /** Snapshot of visible node keys — used to detect structural changes and for selection pinning. */
100
+ private _lastVisibleNodeKeys;
101
+ /**
102
+ * Snapshot of visible projection references — used to detect in-place
103
+ * projection updates (streaming). One entry per visible Run.
104
+ */
105
+ private _lastVisibleProjections;
106
+ /**
107
+ * Snapshot of the visible flat message chain with codec-message-ids —
108
+ * exposed verbatim via `getMessages()` and the internal correlation
109
+ * source for parent/branch routing.
110
+ */
111
+ private _lastVisibleMessagePairs;
112
+ /** Cached visible node-key Set — for O(1) lookup in event scoping. */
113
+ private _lastVisibleNodeKeySet;
67
114
  /** Whether there are more history pages to fetch from the channel. */
68
115
  private _hasMoreHistory;
69
116
  /** Internal state for continuing history pagination. */
70
117
  private _lastHistoryPage;
71
- /** Buffer of withheld nodes, drained newest-first by successive loadOlder() calls. */
118
+ /** Buffer of withheld nodes (input + reply), drained newest-first by successive loadOlder() calls. */
72
119
  private readonly _withheldBuffer;
120
+ /**
121
+ * Message-level trim on top of the run-level pagination window. Runs are
122
+ * revealed whole (via `_withheldRunIds`/`_withheldBuffer`), so a `loadOlder`
123
+ * may surface more messages than asked; this is the count of OLDEST messages
124
+ * of the visible node chain to hide from `getMessages()` so a page lands on
125
+ * exactly `limit` messages. The boundary run still appears in `runs()` (it's
126
+ * a revealed node); only its oldest messages are trimmed from the flat list.
127
+ * Live messages append at the newest end and are never trimmed.
128
+ */
129
+ private _hiddenMessageCount;
73
130
  /** Unsubscribe functions for tree event subscriptions. */
74
131
  private readonly _unsubs;
75
132
  /**
76
- * Cached result of the last flattenNodes computation. Public `flattenNodes()`
77
- * returns this in O(1); internal callers use `_computeFlatNodes()` when a
78
- * fresh tree walk is needed (structural changes, selection changes, history reveal).
133
+ * Cached result of the last flat-nodes computation. Drives the visible
134
+ * message snapshot exposed via `getMessages()`; refreshed by
135
+ * `_computeFlatNodes()` on structural changes, selection changes,
136
+ * and history reveal.
79
137
  */
80
138
  private _cachedNodes;
81
- /** Last seen tree structural version - used to distinguish content-only from structural updates. */
82
- private _lastStructuralVersion;
83
139
  private _loadingOlder;
84
140
  private _processingHistory;
85
141
  private _closed;
86
- constructor(options: ViewOptions<TEvent, TMessage>);
87
- getMessages(): TMessage[];
88
- flattenNodes(): MessageNode<TMessage>[];
142
+ constructor(options: ViewOptions<TInput, TOutput, TProjection, TMessage>);
143
+ /**
144
+ * Handle decoded outputs folded into a Run (streaming delta). If the run
145
+ * is on the visible chain, recompute the flat message list and emit
146
+ * `update`.
147
+ * @param event - The output event from the Tree.
148
+ */
149
+ private _onTreeOutput;
150
+ getMessages(): CodecMessage<TMessage>[];
151
+ runs(): RunInfo[];
89
152
  /**
90
- * Walk the tree and compute a fresh visible node list, applying branch
91
- * selections and withheld-message filtering. Use this instead of the
92
- * public `flattenNodes()` when the cache may be stale (structural
93
- * changes, selection changes, history reveal).
94
- * @returns A fresh array of visible nodes.
153
+ * Compute the fresh visible node chain. The Tree's `visibleNodes` already
154
+ * applies kind-blind reachability and sibling selection (edit versions /
155
+ * regenerate runs collapse to the selected member), so the View only layers
156
+ * its pagination window on top: drop nodes whose key is currently withheld.
157
+ * @returns A fresh array of visible nodes (inputs + reply runs).
95
158
  */
96
159
  private _computeFlatNodes;
160
+ /**
161
+ * Recompute the visible node chain, refresh the cache + snapshot, and emit
162
+ * `update` unconditionally. Use after a mutation that always changes the
163
+ * visible output (e.g. an explicit selection or a withheld-batch reveal).
164
+ */
165
+ private _recomputeAndEmit;
166
+ /**
167
+ * Recompute the visible node chain and, only if it differs from the current
168
+ * snapshot, refresh the cache + snapshot and emit `update`. Use after a
169
+ * mutation that may or may not move the visible window (e.g. a structural
170
+ * tree update, or a deferred regenerate promotion that may already match).
171
+ */
172
+ private _recomputeAndEmitIfChanged;
173
+ /**
174
+ * Resolve the reply Run that owns a codec-message-id, narrowing the Tree's
175
+ * node union to a {@link RunNode}. A user-input codec-message-id resolves to
176
+ * an input node and yields `undefined` here — callers that must handle input
177
+ * nodes use {@link _tree.getNodeByCodecMessageId} directly.
178
+ * @param codecMessageId - The codec-message-id to resolve.
179
+ * @returns The owning RunNode, or undefined if absent or not a reply Run.
180
+ */
181
+ private _runByCodecMessageId;
182
+ /**
183
+ * The regenerator runs that replaced a non-head message of a reply run. They
184
+ * file under the target's predecessor (not the owner run's input node), so the
185
+ * Tree's `visibleNodes` cannot collapse them into the owner's slot; this
186
+ * surfaces them for the View to resolve and render. Head-message (index 0)
187
+ * regenerates are excluded - those are whole-reply sibling runs the Tree
188
+ * already groups.
189
+ * @param targetCodecMessageId - The regenerate target's (non-head) message id.
190
+ * @param predecessorCodecMessageId - The codec-message-id immediately before it in the owner run.
191
+ * @returns The regenerator runs in startSerial order (oldest first).
192
+ */
193
+ private _nonHeadRegenerators;
194
+ /**
195
+ * Resolve the selected member of a non-head regenerate group anchored at
196
+ * `targetCodecMessageId`. Members are the owner run `O` (memberNodeKey =
197
+ * `ownerRunId`, the regenerate target in place) followed by each regenerator
198
+ * run. Honours an explicit {@link _nonHeadRegenSelections} entry, else
199
+ * defaults to the latest member (newest regenerator), mirroring the
200
+ * whole-reply regenerate default.
201
+ * @param targetCodecMessageId - The regenerate target's message id (the group anchor).
202
+ * @param ownerRunId - The runId of the run that owns the regenerate target.
203
+ * @param regenerators - The regenerator runs (oldest first) from `_nonHeadRegenerators`.
204
+ * @returns The selected member's node key (`ownerRunId` or a regenerator runId).
205
+ */
206
+ private _selectedNonHeadMember;
207
+ /**
208
+ * Flatten visible nodes to messages, collapsing a non-head regenerate into the
209
+ * slot it replaces: while emitting a reply run, at each non-head message that
210
+ * has a selected regenerator, drop that message and the run's tail and emit the
211
+ * selected regenerator instead (recursive for regen-of-regen). Whole-reply
212
+ * regenerates need nothing here - visibleNodes already picks the sibling.
213
+ * @param nodes - Visible nodes (inputs + reply runs), chronological.
214
+ * @returns The flat message list, each paired with its codec-message-id.
215
+ */
216
+ private _extractMessages;
217
+ /**
218
+ * Emit one visible node's messages into `out`, applying non-head regenerate
219
+ * substitution for a reply run (see `_extractMessages`). Input nodes and runs
220
+ * with no non-head regenerators emit their projection verbatim.
221
+ * @param node - The node to emit.
222
+ * @param out - The accumulating flat message list (mutated in place).
223
+ * @param consumedRunIds - Set of regenerator runIds already emitted via substitution (mutated in place).
224
+ */
225
+ private _emitNodeMessages;
97
226
  hasOlder(): boolean;
227
+ /**
228
+ * Reveal `limit` more older codecMessages in this view — fewer only when
229
+ * channel history is exhausted.
230
+ *
231
+ * Internally runs are revealed WHOLE (run-granular withholding), counting
232
+ * codecMessages to decide how many runs to bring in, then the flat list
233
+ * returned by {@link getMessages} is trimmed to exactly `limit` more
234
+ * messages. So a run straddling the boundary still appears in {@link runs}
235
+ * (it's a revealed node) while only its newest messages show in
236
+ * `getMessages`. Live messages append at the newest end and are never
237
+ * trimmed.
238
+ * @param limit - Number of older codecMessages to reveal. Defaults to 10.
239
+ */
98
240
  loadOlder(limit?: number): Promise<void>;
99
- select(msgId: string, index: number): void;
100
- getSelectedIndex(msgId: string): number;
101
- getSiblings(msgId: string): TMessage[];
102
- hasSiblings(msgId: string): boolean;
103
- getNode(msgId: string): MessageNode<TMessage> | undefined;
104
- send(input: TMessage | TMessage[], options?: SendOptions): Promise<ActiveTurn<TEvent>>;
105
- regenerate(messageId: string, options?: SendOptions): Promise<ActiveTurn<TEvent>>;
106
- edit(messageId: string, newMessages: TMessage | TMessage[], options?: SendOptions): Promise<ActiveTurn<TEvent>>;
107
- update(msgId: string, events: TEvent[], options?: SendOptions): Promise<ActiveTurn<TEvent>>;
108
- private _getHistoryBefore;
109
- getActiveTurnIds(): Map<string, Set<string>>;
110
- on(event: 'update', handler: () => void): () => void;
111
- on(event: 'ably-message', handler: (msg: Ably.InboundMessage) => void): () => void;
112
- on(event: 'turn', handler: (event: TurnLifecycleEvent) => void): () => void;
113
241
  /**
114
- * Tear down the view unsubscribe from tree events.
242
+ * Fetch older channel history covering at least `target` more codecMessages,
243
+ * buffering the older nodes and revealing whole runs. The withheld buffer is
244
+ * assumed already drained by the caller. Loads the first page when no history
245
+ * has been fetched yet, otherwise advances to the next older page; the
246
+ * page-walk inside {@link _revealFromPage} loops until `target` messages are
247
+ * covered or history runs out. No-op (leaving `_hasMoreHistory` false) once
248
+ * channel history is exhausted.
249
+ * @param target - Minimum additional codecMessages this fetch aims to cover.
115
250
  */
251
+ private _fetchOlder;
252
+ /**
253
+ * Find the index in `nodes` (chronological, oldest-first) at which the newest
254
+ * whole runs covering at least `target` codecMessages begin. Walks newest-first
255
+ * summing each node's `codec.getMessages(projection)` count; once the running
256
+ * total reaches `target`, the current node (and everything newer) is the
257
+ * revealed batch — so whole runs are revealed and the batch may overshoot
258
+ * `target` (the caller trims). Returns `0` when the nodes hold fewer than
259
+ * `target` messages — reveal everything.
260
+ *
261
+ * Shared by the buffer-drain and history-fetch reveal paths so they agree on
262
+ * "covering `target` messages".
263
+ * @param nodes - Candidate nodes, oldest-first.
264
+ * @param target - Minimum codecMessages the revealed batch must cover.
265
+ * @returns The split index; `nodes[splitIdx..]` is the revealed batch.
266
+ */
267
+ private _messageTailSplitIndex;
268
+ runOf(codecMessageId: string): RunInfo | undefined;
269
+ /**
270
+ * Resolve the reply run currently selected for an input node, honouring the
271
+ * View's regenerate selection. Falls back to the latest reply run when no
272
+ * selection has been recorded; undefined when no reply run has started.
273
+ * @param inputCodecMessageId - The input node's codec-message-id.
274
+ * @returns The selected reply RunNode, or undefined.
275
+ */
276
+ private _selectedReplyRun;
277
+ run(runId: string): RunInfo | undefined;
278
+ branchSelection(codecMessageId: string): BranchSelection<TMessage>;
279
+ selectSibling(codecMessageId: string, index: number): void;
280
+ /**
281
+ * Resolve the currently selected sibling's index inside a branch group.
282
+ * Pending selections fall back to the latest sibling. The caller clamps
283
+ * the returned index against any post-extraction filtering.
284
+ * @param branch - Resolved branch-point descriptor from `_resolveMessageBranchPoint`.
285
+ * @returns The selected sibling's index within `branch.siblings`.
286
+ */
287
+ private _resolveSelectedIndex;
288
+ /**
289
+ * Resolve the branch point anchored at `codecMessageId`, if any, returning the
290
+ * group `kind` + members + groupRoot so the caller routes to the correct
291
+ * selection map directly (not via a runId dispatch that would mis-route when
292
+ * the owning Run is in both a fork-of and a regen group).
293
+ * @param codecMessageId - The codec-message-id to look up.
294
+ * @returns The resolved branch point, or undefined when `codecMessageId`
295
+ * anchors no group.
296
+ */
297
+ private _resolveMessageBranchPoint;
298
+ /**
299
+ * Resolve a non-head regenerate branch point from a reply-run message, if any.
300
+ * `codecMessageId` is either (a) a non-head message `M` of its owner run with
301
+ * regenerators, or (b) a regenerator run's head; both resolve to the same group
302
+ * anchored at `M` (key matching {@link _nonHeadRegenSelections}).
303
+ * @param node - The reply run owning `codecMessageId`.
304
+ * @param ownMessages - That run's projected messages (already extracted).
305
+ * @param codecMessageId - The slot's codec-message-id (an `M`, or a regenerator head).
306
+ * @returns The non-head branch point, or undefined when `codecMessageId` anchors none.
307
+ */
308
+ private _resolveNonHeadBranchPoint;
309
+ /**
310
+ * Build the {@link MessageBranchPoint} for a non-head regenerate group, or
311
+ * undefined when the anchor has no regenerators. The owner member's
312
+ * representative is the anchor message (the regenerate target); each
313
+ * regenerator's is its head message.
314
+ * @param anchorCodecMessageId - The regenerate target's (non-head) message id.
315
+ * @param ownerRunId - The runId owning the regenerate target.
316
+ * @param predecessorCodecMessageId - The codec-message-id immediately before the anchor in the owner run.
317
+ * @returns The non-head branch point, or undefined when there are no regenerators.
318
+ */
319
+ private _buildNonHeadGroup;
320
+ /**
321
+ * Project nodes to {@link BranchMember}s for fork-of / whole-reply regen
322
+ * groups, where each member's branch-arrow representative is its own head
323
+ * message and its memberNodeKey is its node key.
324
+ * @param nodes - The sibling nodes.
325
+ * @returns One member per node that has a head message.
326
+ */
327
+ private _nodeHeadMembers;
328
+ send(input: TInput | TInput[], options?: SendOptions): Promise<ActiveRun>;
329
+ /**
330
+ * Auto-select / pin branch selections after a forking send.
331
+ * @param result - The ActiveRun returned by the delegate.
332
+ * @param options - The SendOptions passed by the caller.
333
+ */
334
+ private _applyForkAutoSelect;
335
+ /**
336
+ * Auto-select / pin the regenerate group anchored at `anchorCodecMessageId` so
337
+ * the new Run's content appears as soon as the agent's run-start lands.
338
+ *
339
+ * `View.regenerate()` calls this with the assistant codec-message-id being
340
+ * regenerated. The Run doesn't exist yet on the channel (the regenerate
341
+ * wire is wire-only); the selection is recorded as `pending` and
342
+ * promoted to `auto` by `_pinRegenSelections` once the corresponding
343
+ * Run is created in the tree.
344
+ * @param result - The ActiveRun returned by the delegate (run-id is the new regenerator's).
345
+ * @param anchorCodecMessageId - The codec-message-id of the assistant being regenerated.
346
+ */
347
+ private _applyRegenerateAutoSelect;
348
+ regenerate(messageId: string, options?: SendOptions): Promise<ActiveRun>;
349
+ edit(messageId: string, inputs: TInput | TInput[], options?: SendOptions): Promise<ActiveRun>;
350
+ /**
351
+ * Find the codec-message-id of the message immediately preceding `targetMsgId` in
352
+ * the visible conversation.
353
+ *
354
+ * Consults the View's visible message chain first so message-level
355
+ * replacements (regenerate) are respected: regenerating an
356
+ * already-regenerated assistant lands the predecessor on the user
357
+ * prompt the regen is responding to, NOT on the hidden original
358
+ * assistant that occupies the same conversation slot. Falls back to a
359
+ * projection-walk for the rare case where `targetMsgId` isn't on the
360
+ * visible chain (e.g. caller is operating on a Run that's selection-
361
+ * hidden by the current branch).
362
+ * @param targetNode - The node (input node or reply run) that owns `targetMsgId`.
363
+ * @param targetMsgId - The codec-message-id to find the parent of.
364
+ * @returns The parent codec-message-id, or undefined if no predecessor exists.
365
+ */
366
+ private _findParentMsgId;
367
+ on(event: 'update', handler: () => void): () => void;
368
+ on(event: 'ably-message', handler: (msg: Ably.InboundMessage) => void): () => void;
369
+ on(event: 'run', handler: (event: RunLifecycleEvent) => void): () => void;
116
370
  close(): void;
117
371
  private _loadFirstPage;
118
- private _loadAndReveal;
372
+ /**
373
+ * Walk channel history from `page` until the newly-observed nodes hold at
374
+ * least `target` codecMessages (or the channel is exhausted), then reveal the
375
+ * newest whole runs covering `target` and withhold the rest. Snapshots the
376
+ * already-visible nodes up front so only newly-observed nodes count toward
377
+ * `target`. No-op if the view closed during the page walk.
378
+ * @param page - The decoded history page to start from.
379
+ * @param target - Minimum codecMessages to reveal in this batch.
380
+ */
381
+ private _revealFromPage;
382
+ /**
383
+ * Reveal the newest whole runs covering `target` codecMessages from
384
+ * `newVisible` and withhold the rest so subsequent `loadOlder` calls can
385
+ * drain them. Reveal granularity is the whole run; the caller trims the flat
386
+ * message list (via `_hiddenMessageCount`) to make the visible message count
387
+ * exact. Called by {@link _revealFromPage}.
388
+ * @param newVisible - Newly observed nodes (inputs + reply runs) from the history fetch, chronological.
389
+ * @param target - Minimum codecMessages the revealed batch must cover.
390
+ */
391
+ private _splitReveal;
392
+ /**
393
+ * Replay a history page's raw messages into the Tree through the Tree's
394
+ * single decode-and-apply engine — the same applier (and decoder instance)
395
+ * the client's live loop uses, so history replay can't drift from it. The
396
+ * shared decoder's version-guarded trackers make the overlap between the
397
+ * two routes safe: an in-flight stream that spans the attach boundary is
398
+ * continued rather than re-started, and content the live route already
399
+ * incorporated decodes to nothing.
400
+ * @param page - The history page returned by `loadHistory`.
401
+ */
119
402
  private _processHistoryPage;
120
403
  private _loadUntilVisible;
121
404
  private _releaseWithheld;
122
405
  private _updateVisibleSnapshot;
123
406
  private _onTreeUpdate;
124
407
  /**
125
- * Build a resolved selections map from `_branchSelections` for passing
126
- * to `tree.flattenNodes()`. Pending entries (no sibling yet) are omitted,
127
- * causing the tree to use the default (latest sibling).
128
- * @returns Resolved map of groupRoot selectedMsgId.
408
+ * Build the unified selection map the Tree's `visibleNodes` consumes:
409
+ * `groupRootKey -> selectedKey`, covering both edit forks (input-node groups,
410
+ * keyed by the input group root) and regenerate groups (reply-run groups,
411
+ * keyed by the original reply's group root). Pending entries (no chosen
412
+ * member yet) are omitted so the Tree falls back to the latest sibling.
413
+ * @returns The merged group-root → selected-key map.
129
414
  */
130
415
  private _resolveSelections;
131
416
  /**
132
- * For each previously-visible message that now has siblings but no
133
- * explicit selection, pin the selection to that message's msgId.
134
- * This preserves the current branch when new forks appear from
135
- * other views or external sources.
417
+ * The Tree's visible node chain under this view's current selections — the
418
+ * reachable, sibling-resolved nodes before the View's pagination window is
419
+ * applied.
420
+ * @returns The selection-resolved visible node chain.
421
+ */
422
+ private _treeVisibleNodes;
423
+ /**
424
+ * For each previously-visible Run that now has siblings but no explicit
425
+ * selection, pin the selection to that Run's runId. This preserves the
426
+ * current branch when new forks appear from other views or external
427
+ * sources.
136
428
  *
137
429
  * Exception: if the fork was initiated by this view (tracked as a
138
- * `pending` BranchSelection), select the newest sibling instead of
139
- * pinning the old one. This handles regenerate, where no optimistic
140
- * insert was possible at send time.
430
+ * `pending` BranchSelection), select the newest sibling (the awaited Run)
431
+ * instead of pinning the old one.
141
432
  */
142
433
  private _pinBranchSelections;
143
434
  /**
144
- * Resolve pending selections that are no longer on the visible branch.
145
- * `_pinBranchSelections` only checks visible nodes, so if the user navigated
146
- * away before the server response arrived, the pending entry would linger.
147
- * This pass checks all pending entries against the tree directly.
435
+ * Roll `pending` and `auto` regenerate selections forward to the newest
436
+ * group member. A regenerate slot defaults to the latest member, so each
437
+ * new regenerator (this view's awaited run, or an external one) auto-rolls
438
+ * the slot forward UNLESS the user explicitly selected an earlier member
439
+ * (`user`), which pins and is left untouched. The agent mints the run-id, so
440
+ * we can't match the awaited run by id — once the group grows we adopt the
441
+ * newest as the selected member.
442
+ */
443
+ private _resolvePendingRegenSelections;
444
+ /**
445
+ * Roll `pending` and `auto` non-head regenerate selections forward to the
446
+ * newest regenerator of their anchor message. Mirrors
447
+ * {@link _resolvePendingRegenSelections} for the non-head group, which lives in
448
+ * a separate selection map (anchored by the regenerate target rather than a
449
+ * sibling-group root): a `user` selection pins and is left untouched; a
450
+ * `pending`/`auto` slot adopts the newest regenerator once one lands. The
451
+ * anchor's predecessor — the key the regenerators file under — is recovered
452
+ * from the owning run's projection.
148
453
  */
149
- private _resolvePendingSelections;
454
+ private _resolvePendingNonHeadRegenSelections;
150
455
  private _onTreeAblyMessage;
151
- private _onTreeTurn;
456
+ private _onTreeRun;
152
457
  /**
153
- * Predict whether a turn-start's messages will be visible on this view's branch
154
- * using the parent/forkOf metadata from the event.
155
- * @param event - The turn-start lifecycle event with optional branch metadata.
156
- * @returns True if the turn's messages are expected to be visible on this view's branch.
458
+ * Predict whether a run-start's messages will be visible on this view's
459
+ * branch using the parent/forkOf metadata from the event.
460
+ * @param event - The run-start lifecycle event.
461
+ * @returns True if the run is expected to be visible on this view's branch.
157
462
  */
158
- private _isTurnStartVisible;
463
+ private _isRunStartVisible;
159
464
  private _visibleChanged;
160
465
  }
161
466
  /**
@@ -163,4 +468,5 @@ export declare class DefaultView<TEvent, TMessage> implements View<TEvent, TMess
163
468
  * @param options - The tree, channel, codec, and logger to use.
164
469
  * @returns A new {@link DefaultView} instance.
165
470
  */
166
- export declare const createView: <TEvent, TMessage>(options: ViewOptions<TEvent, TMessage>) => DefaultView<TEvent, TMessage>;
471
+ export declare const createView: <TInput extends CodecInputEvent, TOutput extends CodecOutputEvent, TProjection, TMessage>(options: ViewOptions<TInput, TOutput, TProjection, TMessage>) => DefaultView<TInput, TOutput, TProjection, TMessage>;
472
+ export {};