@ably/ai-transport 0.1.0 → 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.
Files changed (163) hide show
  1. package/README.md +91 -100
  2. package/dist/ably-ai-transport.js +1553 -1238
  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 +29 -0
  8. package/dist/core/codec/decoder.d.ts +20 -23
  9. package/dist/core/codec/encoder.d.ts +11 -8
  10. package/dist/core/codec/index.d.ts +1 -2
  11. package/dist/core/codec/lifecycle-tracker.d.ts +10 -9
  12. package/dist/core/codec/types.d.ts +407 -115
  13. package/dist/core/transport/agent-session.d.ts +10 -0
  14. package/dist/core/transport/branch-chain.d.ts +43 -0
  15. package/dist/core/transport/client-session.d.ts +13 -0
  16. package/dist/core/transport/decode-fold.d.ts +47 -0
  17. package/dist/core/transport/headers.d.ts +96 -18
  18. package/dist/core/transport/index.d.ts +5 -6
  19. package/dist/core/transport/internal/bounded-map.d.ts +20 -0
  20. package/dist/core/transport/invocation.d.ts +74 -0
  21. package/dist/core/transport/load-conversation.d.ts +128 -0
  22. package/dist/core/transport/load-history.d.ts +39 -0
  23. package/dist/core/transport/pipe-stream.d.ts +9 -9
  24. package/dist/core/transport/run-manager.d.ts +78 -0
  25. package/dist/core/transport/tree.d.ts +373 -109
  26. package/dist/core/transport/types/agent.d.ts +353 -0
  27. package/dist/core/transport/types/client.d.ts +168 -0
  28. package/dist/core/transport/types/shared.d.ts +24 -0
  29. package/dist/core/transport/types/tree.d.ts +315 -0
  30. package/dist/core/transport/types/view.d.ts +222 -0
  31. package/dist/core/transport/types.d.ts +13 -553
  32. package/dist/core/transport/view.d.ts +272 -84
  33. package/dist/errors.d.ts +21 -10
  34. package/dist/index.d.ts +6 -8
  35. package/dist/logger.d.ts +12 -0
  36. package/dist/react/ably-ai-transport-react.js +976 -990
  37. package/dist/react/ably-ai-transport-react.js.map +1 -1
  38. package/dist/react/ably-ai-transport-react.umd.cjs +1 -1
  39. package/dist/react/ably-ai-transport-react.umd.cjs.map +1 -1
  40. package/dist/react/contexts/client-session-context.d.ts +36 -0
  41. package/dist/react/contexts/client-session-provider.d.ts +53 -0
  42. package/dist/react/create-session-hooks.d.ts +116 -0
  43. package/dist/react/index.d.ts +12 -12
  44. package/dist/react/internal/use-resolved-session.d.ts +36 -0
  45. package/dist/react/use-ably-messages.d.ts +17 -14
  46. package/dist/react/use-client-session.d.ts +81 -0
  47. package/dist/react/use-create-view.d.ts +14 -13
  48. package/dist/react/use-tree.d.ts +30 -15
  49. package/dist/react/use-view.d.ts +82 -51
  50. package/dist/utils.d.ts +32 -23
  51. package/dist/vercel/ably-ai-transport-vercel.js +2573 -2086
  52. package/dist/vercel/ably-ai-transport-vercel.js.map +1 -1
  53. package/dist/vercel/ably-ai-transport-vercel.umd.cjs +1 -1
  54. package/dist/vercel/ably-ai-transport-vercel.umd.cjs.map +1 -1
  55. package/dist/vercel/codec/decoder.d.ts +5 -18
  56. package/dist/vercel/codec/encoder.d.ts +6 -36
  57. package/dist/vercel/codec/events.d.ts +51 -0
  58. package/dist/vercel/codec/index.d.ts +24 -12
  59. package/dist/vercel/codec/reducer.d.ts +144 -0
  60. package/dist/vercel/codec/tool-transitions.d.ts +2 -2
  61. package/dist/vercel/index.d.ts +4 -5
  62. package/dist/vercel/react/ably-ai-transport-vercel-react.js +3907 -3266
  63. package/dist/vercel/react/ably-ai-transport-vercel-react.js.map +1 -1
  64. package/dist/vercel/react/ably-ai-transport-vercel-react.umd.cjs +33 -8
  65. package/dist/vercel/react/ably-ai-transport-vercel-react.umd.cjs.map +1 -1
  66. package/dist/vercel/react/contexts/chat-transport-context.d.ts +7 -6
  67. package/dist/vercel/react/contexts/chat-transport-provider.d.ts +53 -41
  68. package/dist/vercel/react/index.d.ts +1 -2
  69. package/dist/vercel/react/use-chat-transport.d.ts +30 -26
  70. package/dist/vercel/react/use-message-sync.d.ts +17 -30
  71. package/dist/vercel/run-end-reason.d.ts +29 -0
  72. package/dist/vercel/transport/chat-transport.d.ts +43 -24
  73. package/dist/vercel/transport/index.d.ts +25 -21
  74. package/dist/vercel/transport/run-output-stream.d.ts +56 -0
  75. package/dist/version.d.ts +2 -0
  76. package/package.json +30 -23
  77. package/src/constants.ts +124 -51
  78. package/src/core/agent.ts +68 -0
  79. package/src/core/codec/decoder.ts +71 -98
  80. package/src/core/codec/encoder.ts +113 -65
  81. package/src/core/codec/index.ts +13 -6
  82. package/src/core/codec/lifecycle-tracker.ts +10 -9
  83. package/src/core/codec/types.ts +436 -120
  84. package/src/core/transport/agent-session.ts +1344 -0
  85. package/src/core/transport/branch-chain.ts +58 -0
  86. package/src/core/transport/client-session.ts +775 -0
  87. package/src/core/transport/decode-fold.ts +91 -0
  88. package/src/core/transport/headers.ts +181 -22
  89. package/src/core/transport/index.ts +25 -26
  90. package/src/core/transport/internal/bounded-map.ts +27 -0
  91. package/src/core/transport/invocation.ts +98 -0
  92. package/src/core/transport/load-conversation.ts +355 -0
  93. package/src/core/transport/load-history.ts +269 -0
  94. package/src/core/transport/pipe-stream.ts +54 -39
  95. package/src/core/transport/run-manager.ts +249 -0
  96. package/src/core/transport/tree.ts +926 -308
  97. package/src/core/transport/types/agent.ts +407 -0
  98. package/src/core/transport/types/client.ts +211 -0
  99. package/src/core/transport/types/shared.ts +27 -0
  100. package/src/core/transport/types/tree.ts +344 -0
  101. package/src/core/transport/types/view.ts +259 -0
  102. package/src/core/transport/types.ts +13 -706
  103. package/src/core/transport/view.ts +864 -433
  104. package/src/errors.ts +22 -9
  105. package/src/event-emitter.ts +3 -2
  106. package/src/index.ts +52 -41
  107. package/src/logger.ts +14 -1
  108. package/src/react/contexts/client-session-context.ts +41 -0
  109. package/src/react/contexts/client-session-provider.tsx +186 -0
  110. package/src/react/create-session-hooks.ts +141 -0
  111. package/src/react/index.ts +23 -13
  112. package/src/react/internal/use-resolved-session.ts +63 -0
  113. package/src/react/use-ably-messages.ts +32 -22
  114. package/src/react/use-client-session.ts +201 -0
  115. package/src/react/use-create-view.ts +33 -29
  116. package/src/react/use-tree.ts +61 -30
  117. package/src/react/use-view.ts +139 -97
  118. package/src/utils.ts +63 -45
  119. package/src/vercel/codec/decoder.ts +336 -258
  120. package/src/vercel/codec/encoder.ts +343 -205
  121. package/src/vercel/codec/events.ts +87 -0
  122. package/src/vercel/codec/index.ts +60 -13
  123. package/src/vercel/codec/reducer.ts +977 -0
  124. package/src/vercel/codec/tool-transitions.ts +2 -2
  125. package/src/vercel/index.ts +6 -19
  126. package/src/vercel/react/contexts/chat-transport-context.ts +7 -6
  127. package/src/vercel/react/contexts/chat-transport-provider.tsx +87 -59
  128. package/src/vercel/react/index.ts +3 -5
  129. package/src/vercel/react/use-chat-transport.ts +47 -49
  130. package/src/vercel/react/use-message-sync.ts +80 -39
  131. package/src/vercel/run-end-reason.ts +78 -0
  132. package/src/vercel/transport/chat-transport.ts +392 -98
  133. package/src/vercel/transport/index.ts +39 -38
  134. package/src/vercel/transport/run-output-stream.ts +170 -0
  135. package/src/version.ts +2 -0
  136. package/dist/core/transport/client-transport.d.ts +0 -10
  137. package/dist/core/transport/decode-history.d.ts +0 -43
  138. package/dist/core/transport/server-transport.d.ts +0 -7
  139. package/dist/core/transport/stream-router.d.ts +0 -29
  140. package/dist/core/transport/turn-manager.d.ts +0 -37
  141. package/dist/react/contexts/transport-context.d.ts +0 -31
  142. package/dist/react/contexts/transport-provider.d.ts +0 -49
  143. package/dist/react/create-transport-hooks.d.ts +0 -124
  144. package/dist/react/use-active-turns.d.ts +0 -12
  145. package/dist/react/use-client-transport.d.ts +0 -80
  146. package/dist/vercel/codec/accumulator.d.ts +0 -21
  147. package/dist/vercel/react/use-staged-add-tool-approval-response.d.ts +0 -30
  148. package/dist/vercel/tool-approvals.d.ts +0 -124
  149. package/dist/vercel/tool-events.d.ts +0 -26
  150. package/src/core/transport/client-transport.ts +0 -977
  151. package/src/core/transport/decode-history.ts +0 -485
  152. package/src/core/transport/server-transport.ts +0 -612
  153. package/src/core/transport/stream-router.ts +0 -136
  154. package/src/core/transport/turn-manager.ts +0 -165
  155. package/src/react/contexts/transport-context.ts +0 -37
  156. package/src/react/contexts/transport-provider.tsx +0 -164
  157. package/src/react/create-transport-hooks.ts +0 -144
  158. package/src/react/use-active-turns.ts +0 -72
  159. package/src/react/use-client-transport.ts +0 -197
  160. package/src/vercel/codec/accumulator.ts +0 -588
  161. package/src/vercel/react/use-staged-add-tool-approval-response.ts +0 -87
  162. package/src/vercel/tool-approvals.ts +0 -380
  163. package/src/vercel/tool-events.ts +0 -53
@@ -1,46 +1,59 @@
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
3
  import { TreeInternal } from './tree.js';
4
- import { ActiveTurn, EventsNode, MessageNode, SendOptions, TurnLifecycleEvent, View } from './types.js';
4
+ import { ActiveRun, BranchSelection, RunInfo, RunLifecycleEvent, SendOptions, View } from './types.js';
5
5
  /**
6
6
  * DefaultView — a paginated, branch-aware projection over the Tree.
7
7
  *
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()`.
8
+ * Wraps a Tree (RunNode-keyed) and manages a pagination window that controls
9
+ * which Runs are visible to the UI. New live Runs appear immediately; older
10
+ * Runs are revealed progressively via `loadOlder()`.
11
+ *
12
+ * `getMessages()` reads the Tree's visible node chain (input nodes + reply
13
+ * runs, with sibling selection applied) and concatenates each node's
14
+ * `codec.getMessages(node.projection)` to produce the flat
15
+ * `CodecMessage<TMessage>[]` the UI renders.
11
16
  *
12
17
  * Each View owns its own branch selection state and pagination window,
13
18
  * allowing multiple independent Views over the same Tree.
14
19
  *
15
20
  * Events are scoped to the visible window — 'update' only fires when the
16
21
  * visible output changes, 'ably-message' only for messages corresponding to
17
- * visible nodes, and 'turn' only for turns with visible messages.
22
+ * visible Runs, and 'run' only for runs with visible content.
18
23
  */
19
24
  import * as Ably from 'ably';
20
25
  /**
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.
26
+ * Internal delegate function provided by the session for executing sends.
27
+ * The View pre-computes the visible branch's flat message list and the
28
+ * codec-message-id of its tail (for auto-parent routing) before calling
29
+ * the delegate, so the delegate has no back-reference to the View.
30
+ *
31
+ * Each TInput carries its own routing metadata (`parent` / `target` /
32
+ * `codecMessageId`) via the {@link CodecInputEvent} base; the delegate
33
+ * reads those fields directly without runtime classification.
34
+ *
35
+ * `parentCodecMessageId` is the codec-message-id of the last message in
36
+ * the visible branch (extracted from the tail Run's projection per codec
37
+ * convention), or `undefined` for an empty conversation. The session
38
+ * uses it as the auto-parent for fresh user messages.
26
39
  */
27
- export type SendDelegate<TEvent, TMessage> = (input: TMessage | TMessage[], options: SendOptions | undefined, history: MessageNode<TMessage>[], eventNodes?: EventsNode<TEvent>[]) => Promise<ActiveTurn<TEvent>>;
40
+ export type SendDelegate<TInput extends CodecInputEvent> = (input: TInput[], options: SendOptions | undefined, parentCodecMessageId: string | undefined) => Promise<ActiveRun>;
28
41
  /** Options for creating a View. */
29
- export interface ViewOptions<TEvent, TMessage> {
42
+ export interface ViewOptions<TInput extends CodecInputEvent, TOutput extends CodecOutputEvent, TProjection, TMessage> {
30
43
  /** The tree to project. */
31
- tree: TreeInternal<TMessage>;
44
+ tree: TreeInternal<TInput, TOutput, TProjection>;
32
45
  /** The Ably channel to load history from. */
33
46
  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>;
47
+ /** The codec used to project messages, mint regenerate inputs, and decode history. */
48
+ codec: Codec<TInput, TOutput, TProjection, TMessage>;
49
+ /** Delegate for executing sends through the session. */
50
+ sendDelegate: SendDelegate<TInput>;
38
51
  /** Logger for diagnostic output. */
39
52
  logger: Logger;
40
53
  /** Called when the view is closed, allowing the owner to clean up references. */
41
54
  onClose?: () => void;
42
55
  }
43
- export declare class DefaultView<TEvent, TMessage> implements View<TEvent, TMessage> {
56
+ export declare class DefaultView<TInput extends CodecInputEvent, TOutput extends CodecOutputEvent, TProjection, TMessage> implements View<TInput, TMessage> {
44
57
  private readonly _tree;
45
58
  private readonly _channel;
46
59
  private readonly _codec;
@@ -49,113 +62,288 @@ export declare class DefaultView<TEvent, TMessage> implements View<TEvent, TMess
49
62
  private readonly _emitter;
50
63
  private readonly _onClose?;
51
64
  /**
52
- * View-local branch selections: group root msgId → selection intent.
65
+ * View-local branch selections: group-root runId → selection intent.
53
66
  * 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
67
  */
58
68
  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;
69
+ /**
70
+ * View-local regenerate-group selections: anchor codec-message-id (the assistant
71
+ * codec-message-id being regenerated) selection intent. Distinct from
72
+ * {@link _branchSelections} because a regenerate group is a set of
73
+ * same-parent reply runsmessage-level alternatives at a single
74
+ * conversation slot, not edit forks of the prompt. Groups not present here default to the latest
75
+ * member (the most recent regenerator, or the original if no regen has
76
+ * landed).
77
+ */
78
+ private readonly _regenSelections;
79
+ /** Spec: AIT-CT11c — runIds loaded from history but not yet revealed to the UI. */
80
+ private readonly _withheldRunIds;
81
+ /** Snapshot of visible node keys — used to detect structural changes and for selection pinning. */
82
+ private _lastVisibleNodeKeys;
83
+ /**
84
+ * Snapshot of visible projection references — used to detect in-place
85
+ * projection updates (streaming). One entry per visible Run.
86
+ */
87
+ private _lastVisibleProjections;
88
+ /**
89
+ * Snapshot of the visible flat message chain with codec-message-ids —
90
+ * exposed verbatim via `getMessages()` and the internal correlation
91
+ * source for parent/branch routing.
92
+ */
93
+ private _lastVisibleMessagePairs;
94
+ /** Cached visible node-key Set — for O(1) lookup in event scoping. */
95
+ private _lastVisibleNodeKeySet;
67
96
  /** Whether there are more history pages to fetch from the channel. */
68
97
  private _hasMoreHistory;
69
98
  /** Internal state for continuing history pagination. */
70
99
  private _lastHistoryPage;
71
- /** Buffer of withheld nodes, drained newest-first by successive loadOlder() calls. */
100
+ /** Buffer of withheld nodes (input + reply), drained newest-first by successive loadOlder() calls. */
72
101
  private readonly _withheldBuffer;
73
102
  /** Unsubscribe functions for tree event subscriptions. */
74
103
  private readonly _unsubs;
75
104
  /**
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).
105
+ * Cached result of the last flat-nodes computation. Drives the visible
106
+ * message snapshot exposed via `getMessages()`; refreshed by
107
+ * `_computeFlatNodes()` on structural changes, selection changes,
108
+ * and history reveal.
79
109
  */
80
110
  private _cachedNodes;
81
- /** Last seen tree structural version - used to distinguish content-only from structural updates. */
82
- private _lastStructuralVersion;
83
111
  private _loadingOlder;
84
112
  private _processingHistory;
85
113
  private _closed;
86
- constructor(options: ViewOptions<TEvent, TMessage>);
87
- getMessages(): TMessage[];
88
- flattenNodes(): MessageNode<TMessage>[];
114
+ constructor(options: ViewOptions<TInput, TOutput, TProjection, TMessage>);
115
+ /**
116
+ * Handle decoded outputs folded into a Run (streaming delta). If the run
117
+ * is on the visible chain, recompute the flat message list and emit
118
+ * `update`.
119
+ * @param event - The output event from the Tree.
120
+ */
121
+ private _onTreeOutput;
122
+ getMessages(): CodecMessage<TMessage>[];
123
+ runs(): RunInfo[];
89
124
  /**
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.
125
+ * Compute the fresh visible node chain. The Tree's `visibleNodes` already
126
+ * applies kind-blind reachability and sibling selection (edit versions /
127
+ * regenerate runs collapse to the selected member), so the View only layers
128
+ * its pagination window on top: drop nodes whose key is currently withheld.
129
+ * @returns A fresh array of visible nodes (inputs + reply runs).
95
130
  */
96
131
  private _computeFlatNodes;
132
+ /**
133
+ * Recompute the visible node chain, refresh the cache + snapshot, and emit
134
+ * `update` unconditionally. Use after a mutation that always changes the
135
+ * visible output (e.g. an explicit selection or a withheld-batch reveal).
136
+ */
137
+ private _recomputeAndEmit;
138
+ /**
139
+ * Recompute the visible node chain and, only if it differs from the current
140
+ * snapshot, refresh the cache + snapshot and emit `update`. Use after a
141
+ * mutation that may or may not move the visible window (e.g. a structural
142
+ * tree update, or a deferred regenerate promotion that may already match).
143
+ */
144
+ private _recomputeAndEmitIfChanged;
145
+ /**
146
+ * Resolve the reply Run that owns a codec-message-id, narrowing the Tree's
147
+ * node union to a {@link RunNode}. A user-input codec-message-id resolves to
148
+ * an input node and yields `undefined` here — callers that must handle input
149
+ * nodes use {@link _tree.getNodeByCodecMessageId} directly.
150
+ * @param codecMessageId - The codec-message-id to resolve.
151
+ * @returns The owning RunNode, or undefined if absent or not a reply Run.
152
+ */
153
+ private _runByCodecMessageId;
154
+ /**
155
+ * Extract the flat TMessage[] from a visible node chain.
156
+ *
157
+ * In the two-node model the Tree's `visibleNodes` has already selected one
158
+ * member per sibling group (the chosen edit version, the chosen regenerate
159
+ * run), so a regenerate is just a sibling reply run that appears in place of
160
+ * the original. Each visible node contributes its own messages in projection
161
+ * order; the flat list is their concatenation.
162
+ *
163
+ * Deferred caveat: a mid-reply regenerate that replaces a non-head message
164
+ * inside a multi-message reply run is not expressible as a sibling run in
165
+ * this model and is not handled here (see the `regenerate-of-multi-message`
166
+ * golden test).
167
+ * @param nodes - The visible nodes (inputs + reply runs) in chronological order.
168
+ * @returns The flat message list, each message paired with its codec-message-id.
169
+ */
170
+ private _extractMessages;
97
171
  hasOlder(): boolean;
172
+ /**
173
+ * Reveal up to `limit` older Runs in this view.
174
+ *
175
+ * The pagination unit is the **Run**, not the message. A single Run
176
+ * typically materialises into multiple messages (e.g. user + assistant
177
+ * pair) so revealing `limit` Runs may add several messages to the flat
178
+ * list returned by {@link getMessages}. Channel pages don't align to
179
+ * Run boundaries, so {@link _loadUntilVisible} keeps fetching channel
180
+ * pages until at least `limit` Runs are buffered (or the channel is
181
+ * exhausted).
182
+ * @param limit - Maximum number of older Runs to reveal. Defaults to 100.
183
+ */
98
184
  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;
185
+ runOf(codecMessageId: string): RunInfo | undefined;
186
+ /**
187
+ * Resolve the reply run currently selected for an input node, honouring the
188
+ * View's regenerate selection. Falls back to the latest reply run when no
189
+ * selection has been recorded; undefined when no reply run has started.
190
+ * @param inputCodecMessageId - The input node's codec-message-id.
191
+ * @returns The selected reply RunNode, or undefined.
192
+ */
193
+ private _selectedReplyRun;
194
+ run(runId: string): RunInfo | undefined;
195
+ branchSelection(codecMessageId: string): BranchSelection<TMessage>;
196
+ selectSibling(codecMessageId: string, index: number): void;
113
197
  /**
114
- * Tear down the view unsubscribe from tree events.
198
+ * Resolve the currently selected sibling's index inside a branch group.
199
+ * Pending selections fall back to the latest sibling. The caller clamps
200
+ * the returned index against any post-extraction filtering.
201
+ * @param branch - Resolved branch-point descriptor from `_resolveMessageBranchPoint`.
202
+ * @returns The selected sibling's index within `branch.siblings`.
203
+ */
204
+ private _resolveSelectedIndex;
205
+ /**
206
+ * Resolve the branch point anchored at `codecMessageId`, if any.
207
+ *
208
+ * Returns the resolved group `kind` along with the sibling list so the
209
+ * caller can update the correct selection map without re-entering the
210
+ * runId-based `select()` dispatch (which biases to fork-of first and
211
+ * would mis-route a regen-anchor codec-message-id when the owning Run is in
212
+ * BOTH groups — e.g. R1 owns both a user prompt that got edited and
213
+ * an assistant that got regenerated).
214
+ *
215
+ * Two anchor cases:
216
+ * - **fork-of** — `codecMessageId` is the first message of a Run in a fork-of
217
+ * sibling group (edit-style branch point anchored at the user prompt).
218
+ * - **regen** — `codecMessageId` is the regen-anchor itself (in the owner Run)
219
+ * or content of a regenerator Run (regen-style branch point anchored
220
+ * at the assistant slot).
221
+ * @param codecMessageId - The codec-message-id to look up.
222
+ * @returns The kind + sibling list + group key (runId for fork-of,
223
+ * anchor codec-message-id for regen), or undefined when `codecMessageId` is not an
224
+ * anchor in either group type.
115
225
  */
226
+ private _resolveMessageBranchPoint;
227
+ send(input: TInput | TInput[], options?: SendOptions): Promise<ActiveRun>;
228
+ /**
229
+ * Auto-select / pin branch selections after a forking send.
230
+ * @param result - The ActiveRun returned by the delegate.
231
+ * @param options - The SendOptions passed by the caller.
232
+ */
233
+ private _applyForkAutoSelect;
234
+ /**
235
+ * Auto-select / pin the regenerate group anchored at `anchorCodecMessageId` so
236
+ * the new Run's content appears as soon as the agent's run-start lands.
237
+ *
238
+ * `View.regenerate()` calls this with the assistant codec-message-id being
239
+ * regenerated. The Run doesn't exist yet on the channel (the regenerate
240
+ * wire is wire-only); the selection is recorded as `pending` and
241
+ * promoted to `auto` by `_pinRegenSelections` once the corresponding
242
+ * Run is created in the tree.
243
+ * @param result - The ActiveRun returned by the delegate (run-id is the new regenerator's).
244
+ * @param anchorCodecMessageId - The codec-message-id of the assistant being regenerated.
245
+ */
246
+ private _applyRegenerateAutoSelect;
247
+ regenerate(messageId: string, options?: SendOptions): Promise<ActiveRun>;
248
+ edit(messageId: string, inputs: TInput | TInput[], options?: SendOptions): Promise<ActiveRun>;
249
+ /**
250
+ * Find the codec-message-id of the message immediately preceding `targetMsgId` in
251
+ * the visible conversation.
252
+ *
253
+ * Consults the View's visible message chain first so message-level
254
+ * replacements (regenerate) are respected: regenerating an
255
+ * already-regenerated assistant lands the predecessor on the user
256
+ * prompt the regen is responding to, NOT on the hidden original
257
+ * assistant that occupies the same conversation slot. Falls back to a
258
+ * projection-walk for the rare case where `targetMsgId` isn't on the
259
+ * visible chain (e.g. caller is operating on a Run that's selection-
260
+ * hidden by the current branch).
261
+ * @param targetNode - The node (input node or reply run) that owns `targetMsgId`.
262
+ * @param targetMsgId - The codec-message-id to find the parent of.
263
+ * @returns The parent codec-message-id, or undefined if no predecessor exists.
264
+ */
265
+ private _findParentMsgId;
266
+ on(event: 'update', handler: () => void): () => void;
267
+ on(event: 'ably-message', handler: (msg: Ably.InboundMessage) => void): () => void;
268
+ on(event: 'run', handler: (event: RunLifecycleEvent) => void): () => void;
116
269
  close(): void;
117
270
  private _loadFirstPage;
118
- private _loadAndReveal;
271
+ /**
272
+ * Walk channel history from `page` until at least `limit` new Runs are
273
+ * observed (or the channel is exhausted), then reveal the newest batch and
274
+ * withhold the rest. Snapshots the already-visible nodes up front so only
275
+ * newly-observed Runs count toward `limit`. No-op if the view closed during
276
+ * the page walk.
277
+ * @param page - The decoded history page to start from.
278
+ * @param limit - Max Runs to reveal in this batch.
279
+ */
280
+ private _revealFromPage;
281
+ /**
282
+ * Reveal the newest `limit` Runs from `newVisible` and withhold the rest
283
+ * so subsequent `loadOlder` calls can drain them. Called by
284
+ * {@link _revealFromPage} to enforce the Run-unit pagination contract.
285
+ * @param newVisible - Newly observed Runs from the history fetch.
286
+ * @param limit - Max Runs to reveal in this batch.
287
+ */
288
+ private _splitReveal;
289
+ /**
290
+ * Replay a history page's raw messages into the Tree. Dispatches by Ably
291
+ * message name to run-lifecycle vs. regular wire messages, mirroring the
292
+ * live `client-session._handleMessage` decode loop. Uses a fresh decoder
293
+ * since the session's live decoder maintains its own stream-tracker state.
294
+ * @param page - The history page returned by `loadHistory`.
295
+ */
119
296
  private _processHistoryPage;
120
297
  private _loadUntilVisible;
121
298
  private _releaseWithheld;
122
299
  private _updateVisibleSnapshot;
123
300
  private _onTreeUpdate;
124
301
  /**
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.
302
+ * Build the unified selection map the Tree's `visibleNodes` consumes:
303
+ * `groupRootKey -> selectedKey`, covering both edit forks (input-node groups,
304
+ * keyed by the input group root) and regenerate groups (reply-run groups,
305
+ * keyed by the original reply's group root). Pending entries (no chosen
306
+ * member yet) are omitted so the Tree falls back to the latest sibling.
307
+ * @returns The merged group-root → selected-key map.
129
308
  */
130
309
  private _resolveSelections;
131
310
  /**
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.
311
+ * The Tree's visible node chain under this view's current selections — the
312
+ * reachable, sibling-resolved nodes before the View's pagination window is
313
+ * applied.
314
+ * @returns The selection-resolved visible node chain.
315
+ */
316
+ private _treeVisibleNodes;
317
+ /**
318
+ * For each previously-visible Run that now has siblings but no explicit
319
+ * selection, pin the selection to that Run's runId. This preserves the
320
+ * current branch when new forks appear from other views or external
321
+ * sources.
136
322
  *
137
323
  * 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.
324
+ * `pending` BranchSelection), select the newest sibling (the awaited Run)
325
+ * instead of pinning the old one.
141
326
  */
142
327
  private _pinBranchSelections;
143
328
  /**
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.
329
+ * Roll `pending` and `auto` regenerate selections forward to the newest
330
+ * group member. A regenerate slot defaults to the latest member, so each
331
+ * new regenerator (this view's awaited run, or an external one) auto-rolls
332
+ * the slot forward UNLESS the user explicitly selected an earlier member
333
+ * (`user`), which pins and is left untouched. The agent mints the run-id, so
334
+ * we can't match the awaited run by id — once the group grows we adopt the
335
+ * newest as the selected member.
148
336
  */
149
- private _resolvePendingSelections;
337
+ private _resolvePendingRegenSelections;
150
338
  private _onTreeAblyMessage;
151
- private _onTreeTurn;
339
+ private _onTreeRun;
152
340
  /**
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.
341
+ * Predict whether a run-start's messages will be visible on this view's
342
+ * branch using the parent/forkOf metadata from the event.
343
+ * @param event - The run-start lifecycle event.
344
+ * @returns True if the run is expected to be visible on this view's branch.
157
345
  */
158
- private _isTurnStartVisible;
346
+ private _isRunStartVisible;
159
347
  private _visibleChanged;
160
348
  }
161
349
  /**
@@ -163,4 +351,4 @@ export declare class DefaultView<TEvent, TMessage> implements View<TEvent, TMess
163
351
  * @param options - The tree, channel, codec, and logger to use.
164
352
  * @returns A new {@link DefaultView} instance.
165
353
  */
166
- export declare const createView: <TEvent, TMessage>(options: ViewOptions<TEvent, TMessage>) => DefaultView<TEvent, TMessage>;
354
+ export declare const createView: <TInput extends CodecInputEvent, TOutput extends CodecOutputEvent, TProjection, TMessage>(options: ViewOptions<TInput, TOutput, TProjection, TMessage>) => DefaultView<TInput, TOutput, TProjection, TMessage>;
package/dist/errors.d.ts CHANGED
@@ -12,30 +12,35 @@ export declare enum ErrorCode {
12
12
  */
13
13
  InvalidArgument = 40003,
14
14
  /**
15
- * Encoder recovery failed after flush one or more updateMessage calls
15
+ * Operation not permitted with the provided capability (Ably 40160).
16
+ * Used when the Ably channel rejects a publish for a capability reason.
17
+ */
18
+ InsufficientCapability = 40160,
19
+ /**
20
+ * Encoder recovery failed during flush — one or more updateMessage calls
16
21
  * could not recover a failed append pipeline.
17
22
  */
18
23
  EncoderRecoveryFailed = 104000,
19
24
  /**
20
- * A transport-level channel subscription callback threw unexpectedly.
25
+ * A session-level channel subscription callback threw unexpectedly.
21
26
  */
22
- TransportSubscriptionError = 104001,
27
+ SessionSubscriptionError = 104001,
23
28
  /**
24
29
  * Cancel listener or onCancel hook threw while processing a cancel message.
25
30
  */
26
31
  CancelListenerError = 104002,
27
32
  /**
28
- * A publish within a turn failed (lifecycle event, message, or event).
33
+ * A publish within a run failed (lifecycle event, message, or event).
29
34
  */
30
- TurnLifecycleError = 104003,
35
+ RunLifecycleError = 104003,
31
36
  /**
32
- * An operation was attempted on a transport that has already been closed.
37
+ * An operation was attempted on a session that has already been closed.
33
38
  */
34
- TransportClosed = 104004,
39
+ SessionClosed = 104004,
35
40
  /**
36
- * The HTTP POST to the server endpoint failed (network error or non-2xx response).
41
+ * The HTTP POST to the agent endpoint failed (network error or non-2xx response).
37
42
  */
38
- TransportSendFailed = 104005,
43
+ SessionSendFailed = 104005,
39
44
  /**
40
45
  * The Ably channel lost message continuity — the channel entered FAILED,
41
46
  * SUSPENDED, or DETACHED, or re-attached with `resumed: false`. Active
@@ -52,7 +57,13 @@ export declare enum ErrorCode {
52
57
  * the source event stream threw (e.g. LLM provider rate limit, model error,
53
58
  * network failure) or an underlying publish failed mid-stream.
54
59
  */
55
- StreamError = 104008
60
+ StreamError = 104008,
61
+ /**
62
+ * The agent attached to the channel and waited for the input event(s) the
63
+ * invocation points at (rewind + live wait) but `inputEventLookupTimeoutMs`
64
+ * lapsed without seeing them.
65
+ */
66
+ InputEventNotFound = 104010
56
67
  }
57
68
  /**
58
69
  * Returns true if the {@link Ably.ErrorInfo} code matches the provided ErrorCode value.
package/dist/index.d.ts CHANGED
@@ -1,12 +1,10 @@
1
- export type { ActiveTurn, AddMessageOptions, AddMessagesResult, CancelFilter, CancelRequest, ClientTransport, ClientTransportOptions, CloseOptions, EventsNode, MessageNode, NewTurnOptions, SendOptions, ServerTransport, ServerTransportOptions, StreamResponseOptions, StreamResult, Tree, Turn, TurnEndReason, TurnLifecycleEvent, View, } from './core/transport/index.js';
2
- export type { EventNode } from './core/transport/index.js';
3
- export type { TreeNode } from './core/transport/index.js';
4
- export { buildTransportHeaders, createClientTransport, createServerTransport } from './core/transport/index.js';
5
- export type { ChannelWriter, Codec, DecoderCore, DecoderCoreHooks, DecoderCoreOptions, DecoderOutput, DiscreteEncoder, EncoderCore, EncoderCoreOptions, EncoderOptions, Extras, LifecycleTracker, MessageAccumulator, MessagePayload, PhaseConfig, StreamDecoder, StreamEncoder, StreamPayload, StreamTrackerState, WriteOptions, } from './core/codec/index.js';
6
- export { createDecoderCore, createEncoderCore, createLifecycleTracker, eventOutput } from './core/codec/index.js';
7
- export { DOMAIN_HEADER_PREFIX, EVENT_ABORT, EVENT_CANCEL, EVENT_ERROR, EVENT_TURN_END, EVENT_TURN_START, HEADER_CANCEL_ALL, HEADER_CANCEL_CLIENT_ID, HEADER_CANCEL_OWN, HEADER_CANCEL_TURN_ID, HEADER_FORK_OF, HEADER_MSG_ID, HEADER_PARENT, HEADER_ROLE, HEADER_STATUS, HEADER_STREAM, HEADER_STREAM_ID, HEADER_TURN_CLIENT_ID, HEADER_TURN_ID, HEADER_TURN_REASON, } from './constants.js';
1
+ export type { ActiveRun, AgentSession, AgentSessionOptions, BranchSelection, CancelRequest, ClientSession, ClientSessionOptions, ConversationNode, EventsNode, InputNode, InvocationData, LoadConversationOptions, MessageNode, OutputEvent, PipeOptions, Run, RunEndReason, RunInfo, RunLifecycleEvent, RunNode, RunRuntime, RunView, SendOptions, StreamResult, Tree, View, } from './core/transport/index.js';
2
+ export { buildTransportHeaders, createAgentSession, createClientSession, Invocation } from './core/transport/index.js';
3
+ export type { ChannelWriter, Codec, CodecInputEvent, CodecMessage, CodecOutputEvent, DecodedMessage, Decoder, DecoderCore, DecoderCoreHooks, DecoderCoreOptions, Encoder, EncoderCore, EncoderCoreOptions, EncoderOptions, Extras, LifecycleTracker, MessagePayload, PhaseConfig, Reducer, ReducerMeta, Regenerate, StreamPayload, StreamTrackerState, ToolApprovalResponse, ToolResult, ToolResultError, UserMessage, WriteOptions, } from './core/codec/index.js';
4
+ export { createDecoderCore, createEncoderCore, createLifecycleTracker } from './core/codec/index.js';
5
+ export { EVENT_CANCEL, EVENT_RUN_END, EVENT_RUN_START, HEADER_CODEC_MESSAGE_ID, HEADER_ERROR_CODE, HEADER_ERROR_MESSAGE, HEADER_FORK_OF, HEADER_INPUT_CLIENT_ID, HEADER_MSG_REGENERATE, HEADER_PARENT, HEADER_ROLE, HEADER_RUN_CLIENT_ID, HEADER_RUN_ID, HEADER_RUN_REASON, HEADER_STATUS, HEADER_STREAM, HEADER_STREAM_ID, } from './constants.js';
8
6
  export type { DomainHeaderReader, DomainHeaderWriter, Stripped } from './utils.js';
9
- export { getHeaders, headerReader, headerWriter, mergeHeaders, stripUndefined } from './utils.js';
7
+ export { getCodecHeaders, getTransportHeaders, headerReader, headerWriter, mergeHeaders, stripUndefined, } from './utils.js';
10
8
  export { EventEmitter } from './event-emitter.js';
11
9
  export { ErrorCode, errorInfoIs } from './errors.js';
12
10
  export type { LogContext, Logger, LoggerOptions, LogHandler } from './logger.js';
package/dist/logger.d.ts CHANGED
@@ -97,7 +97,19 @@ export declare const consoleLogger: (message: string, level: LogLevel, context?:
97
97
  * Options for creating a logger.
98
98
  */
99
99
  export interface LoggerOptions {
100
+ /**
101
+ * The handler that receives formatted log messages. Defaults to {@link consoleLogger} when omitted.
102
+ */
100
103
  logHandler?: LogHandler;
104
+ /**
105
+ * The minimum level to emit; messages below this level are suppressed. Must be a valid {@link LogLevel}, otherwise logger creation throws.
106
+ */
101
107
  logLevel: LogLevel;
102
108
  }
109
+ /**
110
+ * Creates a {@link Logger} from the given options.
111
+ * @param options The handler and minimum level for the logger.
112
+ * @returns A logger that filters by level and delegates to the handler.
113
+ * @throws {@link Ably.ErrorInfo} with {@link ErrorCode.InvalidArgument} if `options.logLevel` is not a recognised {@link LogLevel}.
114
+ */
103
115
  export declare const makeLogger: (options: LoggerOptions) => Logger;