@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
@@ -0,0 +1,27 @@
1
+ /** Types shared across the client, agent, tree, and view layers. */
2
+
3
+ import type * as Ably from 'ably';
4
+
5
+ /**
6
+ * Why a run ended.
7
+ *
8
+ * A run-end is terminal — a run that merely pauses awaiting input publishes
9
+ * `ai-run-suspend` instead (see {@link Run.suspend}).
10
+ *
11
+ * - `complete` — the run finished naturally.
12
+ * - `cancelled` — the run was cancelled by a client.
13
+ * - `error` — the run errored.
14
+ */
15
+ export type RunEndReason = 'complete' | 'cancelled' | 'error';
16
+
17
+ /**
18
+ * Passed to a run's `onCancel` hook for authorization decisions.
19
+ * The hook inspects the incoming cancel message and decides whether to
20
+ * allow the targeted run to be cancelled.
21
+ */
22
+ export interface CancelRequest {
23
+ /** The raw Ably message that carried the cancel signal. */
24
+ message: Ably.InboundMessage;
25
+ /** The runId being cancelled. */
26
+ runId: string;
27
+ }
@@ -0,0 +1,393 @@
1
+ /** Conversation-tree types: nodes, the run-lifecycle event, output events, and the Tree contract. */
2
+
3
+ import type * as Ably from 'ably';
4
+
5
+ import type { CodecOutputEvent } from '../../codec/types.js';
6
+ import type { RunEndReason } from './shared.js';
7
+
8
+ // ---------------------------------------------------------------------------
9
+ // Run lifecycle events
10
+ // ---------------------------------------------------------------------------
11
+
12
+ /**
13
+ * Fields common to every {@link RunLifecycleEvent} arm.
14
+ */
15
+ interface RunLifecycleBase {
16
+ /** The run-id this lifecycle event concerns. */
17
+ runId: string;
18
+ /** The owning client's identity (Ably publisher `clientId`). */
19
+ clientId: string;
20
+ /**
21
+ * The invocation-id this lifecycle event was published under (wire
22
+ * `invocation-id`). Lets consumers correlate the run's lifecycle back to the
23
+ * invocation that drove it; on a run-start the Tree records it on the RunNode
24
+ * at first creation so an optimistic Run exposes the invocation synchronously.
25
+ * Empty string if the wire didn't carry an invocation-id.
26
+ */
27
+ invocationId: string;
28
+ /**
29
+ * Ably server timestamp (epoch ms) of the lifecycle message; absent for an
30
+ * optimistic local event. Advances the Tree's event-log retention clock and
31
+ * the target run's last-activity time.
32
+ */
33
+ timestamp?: number;
34
+ }
35
+
36
+ /**
37
+ * A structured event describing a run starting, suspending, resuming, or
38
+ * ending. The `type` discriminator (`start` / `suspend` / `resume` / `end`) is
39
+ * the in-memory domain vocabulary and is intentionally distinct from the wire
40
+ * message names (`ai-run-start` / `ai-run-suspend` / `ai-run-resume` /
41
+ * `ai-run-end`) those events are decoded from.
42
+ */
43
+ export type RunLifecycleEvent =
44
+ | (RunLifecycleBase & {
45
+ type: 'start';
46
+ /**
47
+ * Ably channel serial of the run-start message, or `undefined` for an
48
+ * optimistic local event (no serial assigned yet). The Tree reads it to
49
+ * promote the Run's startSerial.
50
+ */
51
+ serial: string | undefined;
52
+ /** The codec-message-id of the parent message, if known. Omitted for root runs. */
53
+ parent?: string;
54
+ /**
55
+ * The codec-message-id of the user prompt being forked, when the run is an
56
+ * edit. Carried verbatim from the `fork-of` wire header.
57
+ */
58
+ forkOf?: string;
59
+ /**
60
+ * The codec-message-id of the assistant message this run regenerates, when
61
+ * the run is a regenerate continuation. Carried verbatim from the
62
+ * `msg-regenerate` wire header. The Tree treats regenerates
63
+ * as continuations (no `forkOf` at the Run level) — the View
64
+ * realises the replacement when materialising messages.
65
+ */
66
+ regenerates?: string;
67
+ })
68
+ | (RunLifecycleBase & {
69
+ type: 'suspend';
70
+ /**
71
+ * Ably channel serial of the run-suspend message, or `undefined` for an
72
+ * optimistic local event. The Tree reads it to set the Run's endSerial
73
+ * (a suspended run carries the serial at which it paused).
74
+ */
75
+ serial: string | undefined;
76
+ })
77
+ | (RunLifecycleBase & {
78
+ type: 'resume';
79
+ /**
80
+ * Ably channel serial of the run-resume message, or `undefined` for an
81
+ * optimistic local event. A resume re-enters an existing run; it does not
82
+ * promote the Run's startSerial (the original run-start owns that).
83
+ */
84
+ serial: string | undefined;
85
+ })
86
+ | (RunLifecycleBase & {
87
+ type: 'end';
88
+ /**
89
+ * Ably channel serial of the run-end message, or `undefined` for an
90
+ * optimistic local event. The Tree reads it to set the Run's endSerial.
91
+ */
92
+ serial: string | undefined;
93
+ } & (
94
+ | {
95
+ /** Why the run ended — any terminal reason other than `'error'`. */
96
+ reason: Exclude<RunEndReason, 'error'>;
97
+ }
98
+ | {
99
+ /** The run ended in error. */
100
+ reason: 'error';
101
+ /**
102
+ * Terminal error detail, reconstructed from the run-end's
103
+ * `error-code` / `error-message` headers (or a generic fallback
104
+ * when the run ended in error without detail). The Tree records it
105
+ * on the RunNode and exposes it via `RunInfo.error`.
106
+ */
107
+ error: Ably.ErrorInfo;
108
+ }
109
+ ));
110
+
111
+ // ---------------------------------------------------------------------------
112
+ // Conversation tree (branching history)
113
+ // ---------------------------------------------------------------------------
114
+
115
+ /** A node in the conversation tree, representing a single domain message. */
116
+ export interface MessageNode<TMessage> {
117
+ /** Discriminator — identifies this as a message node. */
118
+ kind: 'message';
119
+ /** The domain message. */
120
+ message: TMessage;
121
+ /** The codec-message-id of this node — primary key in the tree. */
122
+ codecMessageId: string;
123
+ /** Parent node's codec-message-id (parent), or undefined for root messages. */
124
+ parentId: string | undefined;
125
+ /** The codec-message-id this node forks from (fork-of), or undefined if first version. */
126
+ forkOf: string | undefined;
127
+ /** The transport-tier headers (`extras.ai.transport`) for this message: the run/stream/identity/branching headers set and read by the transport layer. Codec-tier headers (`extras.ai.codec`) are not included. */
128
+ headers: Record<string, string>;
129
+ /**
130
+ * Ably serial for this message. Lexicographically comparable for total order.
131
+ * Used to sort siblings deterministically regardless of delivery/history order.
132
+ * Absent for optimistic messages (set when the server relay arrives).
133
+ */
134
+ serial: string | undefined;
135
+ }
136
+
137
+ /**
138
+ * A Run's lifecycle state, modelled as one discriminated value so the terminal
139
+ * `error` is carried exactly when `status` is `'error'`. A RunNode is mutated
140
+ * in place, so status and its dependent error move together — transitions
141
+ * reassign `node.state` wholesale rather than setting fields individually.
142
+ */
143
+ export type RunNodeState =
144
+ | {
145
+ /** `'active'` (streaming), `'suspended'` (paused), or a non-error terminal reason. */
146
+ status: 'active' | 'suspended' | Exclude<RunEndReason, 'error'>;
147
+ }
148
+ | {
149
+ /** Terminal error status. */
150
+ status: 'error';
151
+ /**
152
+ * The run-end's stamped error (or a generic fallback). Exposed to
153
+ * consumers via `RunInfo.error`.
154
+ */
155
+ error: Ably.ErrorInfo;
156
+ };
157
+
158
+ /**
159
+ * A node in the conversation tree, representing a single Run.
160
+ *
161
+ * A RunNode is keyed by its agent-minted `runId`. Each RunNode owns a per-Run
162
+ * codec {@link TProjection} folded from every event published under that
163
+ * run-id; the SDK extracts the per-message list via {@link Codec.getMessages}
164
+ * when it needs to render messages for that Run.
165
+ *
166
+ * A regenerate is a sibling reply run: it shares its input-node parent
167
+ * ({@link parentCodecMessageId}) with the original reply, so same-parent reply
168
+ * runs form the regenerate group with no `forkOf` involved. (Editing a prompt
169
+ * instead produces a sibling {@link InputNode} via that node's `forkOf`.)
170
+ */
171
+ export interface RunNode<TProjection> {
172
+ /** Discriminator — identifies this as a reply-run node within {@link ConversationNode}. */
173
+ kind: 'run';
174
+ /** The run-id of this Run — primary key in the tree. */
175
+ runId: string;
176
+ /**
177
+ * The codec-message-id this Run is rooted at — the `parent` header of the
178
+ * first observed message (or the run-start lifecycle event's `parent`
179
+ * field). This is the run's input node's codec-message-id: the user prompt
180
+ * the agent replied to. The Tree uses it for kind-blind reachability and to
181
+ * build the input→reply edge. `undefined` for the root Run.
182
+ */
183
+ parentCodecMessageId: string | undefined;
184
+ /**
185
+ * The node key of the node this Run replaces, or `undefined` if this Run is
186
+ * not a fork. Populated when the wire's `fork-of` header points at a
187
+ * codec-message-id that has been observed; the Tree resolves it through the
188
+ * codec-message-id → node-key index. Reply-run regenerate siblings do not
189
+ * use this (they group by shared parent) — it carries an explicit fork link
190
+ * when the wire stamps one.
191
+ */
192
+ forkOf: string | undefined;
193
+ /**
194
+ * The codec-message-id this Run regenerates, or `undefined` for non-regenerate
195
+ * Runs. Populated from the wire's `msg-regenerate` header (and the lifecycle
196
+ * event's `regenerates` field) verbatim — the Tree does not resolve it to a
197
+ * node key because the anchor is a message position, not a node.
198
+ *
199
+ * A regenerate run parents at the SAME input node as the reply it
200
+ * regenerates, so it joins that input's reply runs as a same-parent sibling;
201
+ * the message named by `regeneratesCodecMessageId` is replaced by this Run's
202
+ * content when the View materialises the chain into messages (Spec: AIT-CT13d).
203
+ */
204
+ regeneratesCodecMessageId: string | undefined;
205
+ /**
206
+ * Identity of the Ably client that started this Run, sourced from the
207
+ * `run-client-id` wire header (or the run-start lifecycle event's
208
+ * `clientId` field). Set once at Run creation and never updated; persists
209
+ * through the Run's lifecycle, including after `run-end`. Empty string if
210
+ * the wire didn't carry a client id.
211
+ */
212
+ clientId: string;
213
+ /**
214
+ * Run lifecycle state — see {@link RunNodeState}. `'active'` until a terminal
215
+ * event; `'suspended'` while paused (a continuation re-activates it);
216
+ * otherwise the run-end reason, carrying `error` when that reason is
217
+ * `'error'`.
218
+ */
219
+ state: RunNodeState;
220
+ /** Per-Run codec projection. Folded by the Tree from every event published under this run-id. */
221
+ projection: TProjection;
222
+ /**
223
+ * The agent-minted invocationId observed for this Run (wire `invocation-id`).
224
+ * The agent mints it, so an optimistic Run starts with an empty id; it is
225
+ * adopted from the agent's `ai-run-start` (or set at creation when the Run is
226
+ * first seen from a wire event carrying one) and never reassigned thereafter.
227
+ * Empty string until run-start arrives, or if the wire didn't carry an
228
+ * invocation-id.
229
+ */
230
+ invocationId: string;
231
+ /** Ably serial of the first observed message tagged with this run-id. Absent for optimistic Runs. */
232
+ startSerial: string | undefined;
233
+ /** Ably serial of the run-end lifecycle event, if observed. */
234
+ endSerial: string | undefined;
235
+ }
236
+
237
+ /**
238
+ * A node in the conversation tree, representing a single user input (prompt).
239
+ *
240
+ * An input node owns the user's prompt for one turn. It is keyed by the
241
+ * client-owned `codec-message-id` and never carries a run-id — the agent mints
242
+ * the run-id for the reply, which becomes a separate {@link RunNode} parented to
243
+ * this input node. An edit of a prompt is a sibling input node (via `forkOf`).
244
+ *
245
+ * Like a {@link RunNode}, it carries its own per-input codec {@link TProjection}
246
+ * folded from the input event(s) published under its codec-message-id; the SDK
247
+ * extracts the per-message list via {@link Codec.getMessages} when rendering.
248
+ */
249
+ export interface InputNode<TProjection> {
250
+ /** Discriminator — identifies this as an input node within {@link ConversationNode}. */
251
+ kind: 'input';
252
+ /** The codec-message-id of this input — primary key in the tree. */
253
+ codecMessageId: string;
254
+ /**
255
+ * The codec-message-id of the node this input hangs off (its structural
256
+ * parent — the immediately preceding reply run on this chain), or `undefined`
257
+ * for the first input in a conversation. Used for kind-blind tree
258
+ * reachability alongside {@link RunNode.parentCodecMessageId}.
259
+ */
260
+ parentCodecMessageId: string | undefined;
261
+ /**
262
+ * The codec-message-id this input forks from when it is an edit of an earlier
263
+ * prompt, or `undefined` if it is the first version. Sibling input nodes
264
+ * (alternate prompts) share the same `forkOf` anchor.
265
+ */
266
+ forkOf: string | undefined;
267
+ /** Per-input codec projection. Folded by the Tree from every input event published under this codec-message-id. */
268
+ projection: TProjection;
269
+ /** Ably serial of the first observed message for this input. Absent for optimistic (locally-created) inputs. */
270
+ serial: string | undefined;
271
+ }
272
+
273
+ /**
274
+ * A node in the conversation tree: either a user {@link InputNode} or an agent
275
+ * {@link RunNode}. Narrow on `kind` (`'input'` vs `'run'`) before reading
276
+ * kind-specific fields.
277
+ */
278
+ export type ConversationNode<TProjection> = InputNode<TProjection> | RunNode<TProjection>;
279
+
280
+ /**
281
+ * Payload of the Tree's `output` event: the decoded agent outputs folded
282
+ * for a Run from a single inbound message, carrying the routing metadata a
283
+ * consumer needs to attribute or stream them.
284
+ */
285
+ export interface OutputEvent<TOutput extends CodecOutputEvent> {
286
+ /**
287
+ * The runId the outputs were folded into, or `undefined` when the fold was
288
+ * into a user input node (which carries no run-id — the agent mints run-ids).
289
+ * An input fold always has empty {@link events}; consumers route by
290
+ * {@link inputCodecMessageId}, not this.
291
+ */
292
+ runId: string | undefined;
293
+ /**
294
+ * The codec-message-id of the input event that triggered this run — the
295
+ * agent's `input-codec-message-id` header. This is the stable key the client
296
+ * owns from send time (before the agent mints the runId), so the output
297
+ * stream can attribute outputs to the request that produced them. Distinct
298
+ * from {@link runId}: causal (which input produced these outputs) rather than
299
+ * the run's own identity. `undefined` when the carrying message had no such
300
+ * header — e.g. a purely-optimistic local fold with no wire echo yet.
301
+ */
302
+ inputCodecMessageId: string | undefined;
303
+ /**
304
+ * The `codec-message-id` the outputs were published under, or `undefined`
305
+ * when the message carried none.
306
+ */
307
+ codecMessageId: string | undefined;
308
+ /**
309
+ * Ably channel serial of the message that carried the outputs, or
310
+ * `undefined` for an optimistic local fold (no serial assigned yet).
311
+ */
312
+ serial: string | undefined;
313
+ /**
314
+ * The decoded agent outputs from this message, in wire order. Empty when
315
+ * the folded message carried only inputs (e.g. an optimistic user
316
+ * message); the event still fires so consumers can observe that the Run's
317
+ * projection changed.
318
+ */
319
+ events: TOutput[];
320
+ }
321
+
322
+ /**
323
+ * Materializes a branching conversation tree from a flat oplog of Ably
324
+ * messages. Each turn is two nodes: a user {@link InputNode} keyed by its
325
+ * client-owned codec-message-id and an agent {@link RunNode} keyed by the
326
+ * agent-minted run-id, parented to the input node.
327
+ *
328
+ * The Tree owns the complete conversation state across every observed node.
329
+ * Each node holds a per-node codec {@link TProjection} which the Tree folds
330
+ * from inbound events. The View walks the parent chain to extract a flat
331
+ * message list for rendering.
332
+ */
333
+ export interface Tree<TOutput extends CodecOutputEvent, TProjection> {
334
+ /** Get a Run by runId, or undefined if not found. */
335
+ getRunNode(runId: string): RunNode<TProjection> | undefined;
336
+
337
+ /**
338
+ * Get the node that owns a given codec-message-id (via the Tree's
339
+ * codecMessageId index), or undefined if the codec-message-id hasn't been
340
+ * observed. The result is a {@link ConversationNode} union: narrow on `kind`
341
+ * (`'input'` vs `'run'`) before reading kind-specific fields.
342
+ */
343
+ getNodeByCodecMessageId(codecMessageId: string): ConversationNode<TProjection> | undefined;
344
+
345
+ /**
346
+ * Get the sibling group (both kinds) the node keyed by `key` belongs to:
347
+ * edit versions for an input node (forkOf-linked, same parent), regenerate
348
+ * runs for a reply run (same input-node parent). Ordered oldest-first by
349
+ * serial; a single-element array when the node has no siblings. Empty when
350
+ * `key` is unknown. Narrow each node on `kind` before reading kind-specific
351
+ * fields.
352
+ * @param key - The node key ({@link RunNode.runId} or {@link InputNode.codecMessageId}).
353
+ * @returns The ordered sibling nodes.
354
+ */
355
+ getSiblingNodes(key: string): ConversationNode<TProjection>[];
356
+
357
+ /**
358
+ * Look up the raw Ably message that carried the given `event-id` header,
359
+ * if the Tree has observed it. Populated incrementally as messages arrive
360
+ * through the Tree's `ably-message` channel; not bounded except by the
361
+ * Tree's lifetime. Used by the agent's input-event lookup to find a
362
+ * triggering input message by id without scanning a separate buffer.
363
+ * @param eventId - The `event-id` header value to look up.
364
+ * @returns The matching raw Ably message, or undefined when the Tree has
365
+ * not observed an event with that id.
366
+ */
367
+ findAblyMessageByEventId(eventId: string): Ably.InboundMessage | undefined;
368
+
369
+ // --- Events ---
370
+
371
+ /**
372
+ * Subscribe to tree structural changes (Run insert, delete, sort-reorder,
373
+ * startSerial promotion, run-start metadata backfill). Does NOT fire on
374
+ * content-only folds (streaming chunks) or on run-end status changes —
375
+ * those flow through `output` and `run` respectively.
376
+ */
377
+ on(event: 'update', handler: () => void): () => void;
378
+
379
+ /** Subscribe to raw Ably messages arriving on the channel. */
380
+ on(event: 'ably-message', handler: (msg: Ably.InboundMessage) => void): () => void;
381
+
382
+ /** Subscribe to run lifecycle events (start, suspend, resume, and end). */
383
+ on(event: 'run', handler: (event: RunLifecycleEvent) => void): () => void;
384
+
385
+ /**
386
+ * Subscribe to decoded agent outputs as they are folded into a Run.
387
+ * Fires once per inbound message after its fold, carrying the message's
388
+ * output events plus routing metadata (runId, codec-message-id, serial).
389
+ * Fires with an empty `events` array for inputs-only folds so it can also
390
+ * serve as a projection-changed signal.
391
+ */
392
+ on(event: 'output', handler: (event: OutputEvent<TOutput>) => void): () => void;
393
+ }