@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,189 @@
1
+ /**
2
+ * Per-node event log.
3
+ *
4
+ * Each node retains the decoded events it was folded from, grouped by
5
+ * wire-message serial and ordered ascending by serial. The log captures
6
+ * canonical serial order regardless of delivery order, so a node's event
7
+ * sequence can be re-derived in that order even when wires arrive late
8
+ * (cross-publisher reordering) or out of order (history pages applying older
9
+ * messages after newer ones).
10
+ *
11
+ * Within one serial, deliveries are sequenced by `Message.version.serial`
12
+ * (lexicographically ordered per mutation — platform guarantee): each entry
13
+ * records the highest version decoded into it, so a delivery the entry has
14
+ * already incorporated — a whole-wire replay from a second hydration, a
15
+ * remount, or an agent re-walk — is recognised and dropped at the transport.
16
+ *
17
+ * {@link WireLog} encapsulates the entry list and all of its mutation: the
18
+ * caller hands it a wire and is told only how to fold (see {@link WireLogFold}).
19
+ */
20
+
21
+ /** One wire message in a node's event log: a serial and its decoded events. */
22
+ interface WireLogEntry<TEvent> {
23
+ /** Ably channel serial of the wire message. */
24
+ serial: string;
25
+ /**
26
+ * The wire's codec-message-id — the reducer routing key the events were
27
+ * folded alongside; undefined when the wire carried none.
28
+ */
29
+ messageId: string | undefined;
30
+ /**
31
+ * The decoded events from this wire message's deliveries, in arrival order.
32
+ * Same-serial deliveries (the create plus each append/update) extend the
33
+ * entry, so the list accumulates across deliveries.
34
+ */
35
+ events: TEvent[];
36
+ /**
37
+ * The highest `Message.version.serial` decoded into this entry. Versions
38
+ * are lexicographically comparable within one serial, so a delivery at or
39
+ * below this value is already incorporated and must not fold again. In
40
+ * practice every delivery carries a version (a never-mutated message's
41
+ * version serial equals its serial); the message serial is used as the floor
42
+ * only as a defensive fallback for the type-optional absent case.
43
+ */
44
+ decodedThrough: string;
45
+ }
46
+
47
+ /** How a {@link WireLog.record} call tells the caller to fold the wire's events. */
48
+ export type WireLogFold =
49
+ /**
50
+ * The version guard rejected a re-delivery the log already incorporated — a
51
+ * whole-wire replay, or a newer version of a non-streamed wire (an edited
52
+ * discrete). Nothing was recorded; fold nothing.
53
+ */
54
+ | 'dropped'
55
+ /**
56
+ * The events extend the log tail (in-order delivery) or landed on a swept
57
+ * log; fold them onto the node's existing projection.
58
+ */
59
+ | 'incremental'
60
+ /**
61
+ * An earlier-serial wire arrived late, so incremental folding would corrupt
62
+ * serial order; rebuild the projection from the whole log via {@link replay}.
63
+ */
64
+ | 'refold';
65
+
66
+ /**
67
+ * A node's event log: one entry per wire-message serial, kept ascending by
68
+ * serial, each accumulating that serial's decoded events in arrival order.
69
+ */
70
+ export class WireLog<TEvent> {
71
+ private readonly _entries: WireLogEntry<TEvent>[] = [];
72
+ private _swept = false;
73
+
74
+ /**
75
+ * Whether the retention sweep has dropped this log's decoded payloads. A
76
+ * swept log keeps each entry's replay key (serial + `decodedThrough`) so it
77
+ * still recognises whole-wire replays, but it can no longer be refolded.
78
+ * @returns True once {@link sweep} has run.
79
+ */
80
+ get swept(): boolean {
81
+ return this._swept;
82
+ }
83
+
84
+ /**
85
+ * Record a wire message's decoded events and report how to fold them.
86
+ *
87
+ * Events for an already-logged serial are guarded by the entry's
88
+ * `decodedThrough` version before being recorded; a new serial is inserted
89
+ * at the position that keeps the log ascending by serial (Ably serials order
90
+ * lexicographically). The version guard fires only for deliveries carrying
91
+ * an explicit `version.serial`: in-contract mutations always do, while a
92
+ * version-less delivery records unguarded (and never advances
93
+ * `decodedThrough`), matching the decoder's convention.
94
+ *
95
+ * On a swept log the payload is not retained (only the replay key is), so
96
+ * the fold is never `refold` — a genuinely-new wire there is outside the
97
+ * reorder window and folds incrementally in arrival order.
98
+ * @param serial - The Ably channel serial of the wire message.
99
+ * @param messageId - The wire's codec-message-id, or undefined.
100
+ * @param events - The decoded events to record, in arrival order.
101
+ * @param version - The delivery's `Message.version.serial`, or undefined
102
+ * when the delivery carried none (guard disabled for this delivery).
103
+ * @param streamed - Whether the delivery is part of a streamed wire; a
104
+ * guarded newer delivery for a non-streamed wire is an edited discrete and
105
+ * is dropped.
106
+ * @returns How the caller should fold the events.
107
+ */
108
+ record(
109
+ serial: string,
110
+ messageId: string | undefined,
111
+ events: TEvent[],
112
+ version: string | undefined,
113
+ streamed: boolean,
114
+ ): WireLogFold {
115
+ // A swept log retains replay keys but not payloads: record an empty event
116
+ // list so the key advances while nothing is stored. The caller folds the
117
+ // events it already holds.
118
+ const index = this._recordEntry(serial, messageId, this._swept ? [] : events, version, streamed);
119
+ if (index === undefined) return 'dropped';
120
+ if (this._swept) return 'incremental';
121
+ return index === this._entries.length - 1 ? 'incremental' : 'refold';
122
+ }
123
+
124
+ /**
125
+ * Replay every recorded event in canonical order — wire messages ascending
126
+ * by serial, events within a wire in arrival order — each with its wire's
127
+ * routing metadata, for a refold.
128
+ * @param visit - Called once per event, in canonical order.
129
+ */
130
+ replay(visit: (event: TEvent, serial: string, messageId: string | undefined) => void): void {
131
+ for (const entry of this._entries) {
132
+ for (const event of entry.events) visit(event, entry.serial, entry.messageId);
133
+ }
134
+ }
135
+
136
+ /**
137
+ * Drop the decoded payloads (the unbounded cost) but keep each entry's
138
+ * replay key, so a post-sweep whole-wire replay is still recognised and
139
+ * dropped rather than re-folded. The log becomes {@link swept}; a refold can
140
+ * no longer rebuild the dropped events, which `swept` reflects.
141
+ */
142
+ sweep(): void {
143
+ this._swept = true;
144
+ for (const entry of this._entries) entry.events.length = 0;
145
+ }
146
+
147
+ /**
148
+ * Insert or extend the entry for `serial`, guarding replays by version.
149
+ * @param serial - The Ably channel serial of the wire message.
150
+ * @param messageId - The wire's codec-message-id, or undefined.
151
+ * @param events - The decoded events to store (empty on a swept log).
152
+ * @param version - The delivery's `Message.version.serial`, or undefined.
153
+ * @param streamed - Whether the delivery is part of a streamed wire.
154
+ * @returns The index of the entry the events landed in, or `undefined` when
155
+ * the version guard dropped the delivery.
156
+ */
157
+ private _recordEntry(
158
+ serial: string,
159
+ messageId: string | undefined,
160
+ events: TEvent[],
161
+ version: string | undefined,
162
+ streamed: boolean,
163
+ ): number | undefined {
164
+ // Scan from the tail: live delivery appends at (or extends) the end, so the
165
+ // match is almost always within the last entry or two.
166
+ for (let i = this._entries.length - 1; i >= 0; i--) {
167
+ const entry = this._entries[i];
168
+ if (!entry) break; // unreachable
169
+ if (entry.serial === serial) {
170
+ // Version guard: drop a re-delivery the entry already incorporated — a
171
+ // replay (version at or below the high-water-mark) or an edit to a
172
+ // discrete (a newer version of a non-streamed wire, not propagated).
173
+ if (version !== undefined && (version <= entry.decodedThrough || !streamed)) {
174
+ return undefined;
175
+ }
176
+ entry.events.push(...events);
177
+ if (version !== undefined) entry.decodedThrough = version;
178
+ return i;
179
+ }
180
+ if (entry.serial < serial) {
181
+ this._entries.splice(i + 1, 0, { serial, messageId, events: [...events], decodedThrough: version ?? serial });
182
+ return i + 1;
183
+ }
184
+ }
185
+ // Lower than every logged serial (or the log is empty): insert at the head.
186
+ this._entries.unshift({ serial, messageId, events: [...events], decodedThrough: version ?? serial });
187
+ return 0;
188
+ }
189
+ }
package/src/errors.ts CHANGED
@@ -14,18 +14,24 @@ export enum ErrorCode {
14
14
  */
15
15
  InvalidArgument = 40003,
16
16
 
17
+ /**
18
+ * Operation not permitted with the provided capability (Ably 40160).
19
+ * Used when the Ably channel rejects a publish for a capability reason.
20
+ */
21
+ InsufficientCapability = 40160,
22
+
17
23
  // 104000 - 104999 are reserved for AI Transport SDK errors
18
24
 
19
25
  /**
20
- * Encoder recovery failed after flush — one or more updateMessage calls
26
+ * Encoder recovery failed during flush — one or more updateMessage calls
21
27
  * could not recover a failed append pipeline.
22
28
  */
23
29
  EncoderRecoveryFailed = 104000,
24
30
 
25
31
  /**
26
- * A transport-level channel subscription callback threw unexpectedly.
32
+ * A session-level channel subscription callback threw unexpectedly.
27
33
  */
28
- TransportSubscriptionError = 104001,
34
+ SessionSubscriptionError = 104001,
29
35
 
30
36
  /**
31
37
  * Cancel listener or onCancel hook threw while processing a cancel message.
@@ -33,19 +39,19 @@ export enum ErrorCode {
33
39
  CancelListenerError = 104002,
34
40
 
35
41
  /**
36
- * A publish within a turn failed (lifecycle event, message, or event).
42
+ * A publish within a run failed (lifecycle event, message, or event).
37
43
  */
38
- TurnLifecycleError = 104003,
44
+ RunLifecycleError = 104003,
39
45
 
40
46
  /**
41
- * An operation was attempted on a transport that has already been closed.
47
+ * An operation was attempted on a session that has already been closed.
42
48
  */
43
- TransportClosed = 104004,
49
+ SessionClosed = 104004,
44
50
 
45
51
  /**
46
- * The HTTP POST to the server endpoint failed (network error or non-2xx response).
52
+ * The HTTP POST to the agent endpoint failed (network error or non-2xx response).
47
53
  */
48
- TransportSendFailed = 104005,
54
+ SessionSendFailed = 104005,
49
55
 
50
56
  /**
51
57
  * The Ably channel lost message continuity — the channel entered FAILED,
@@ -66,6 +72,20 @@ export enum ErrorCode {
66
72
  * network failure) or an underlying publish failed mid-stream.
67
73
  */
68
74
  StreamError = 104008,
75
+
76
+ /**
77
+ * The agent waited for the input event(s) the invocation points at —
78
+ * across the bounded history scan and the live subscription — but
79
+ * `inputEventLookupTimeoutMs` lapsed without seeing them.
80
+ */
81
+ InputEventNotFound = 104010,
82
+
83
+ /**
84
+ * Channel history pagination failed after bounded retry — either the initial
85
+ * `channel.history()` call or a subsequent `page.next()` exhausted its
86
+ * retry budget. The original failure is preserved as `cause`.
87
+ */
88
+ HistoryFetchFailed = 104011,
69
89
  }
70
90
 
71
91
  /**
@@ -76,8 +76,9 @@ const toAblyLogger = (logger: Logger): unknown => ({
76
76
  });
77
77
 
78
78
  // CAST: Access Ably's internal EventEmitter constructor. Not publicly exported
79
- // but available to other Ably SDKs. The logger parameter ensures listener
80
- // exceptions are caught and logged rather than crashing.
79
+ // but available to other Ably SDKs. Ably always catches listener exceptions
80
+ // internally; the logger parameter ensures those caught exceptions are logged
81
+ // rather than silently swallowed.
81
82
  const InternalEventEmitter: new <EventsMap>(logger: unknown) => InterfaceEventEmitter<EventsMap> = (
82
83
  Ably.Realtime as unknown as { EventEmitter: new <EventsMap>(logger: unknown) => InterfaceEventEmitter<EventsMap> }
83
84
  ).EventEmitter;
package/src/index.ts CHANGED
@@ -1,87 +1,131 @@
1
1
  // Core transport
2
2
  export type {
3
- ActiveTurn,
4
- AddMessageOptions,
5
- AddMessagesResult,
6
- CancelFilter,
3
+ ActiveRun,
4
+ AgentSession,
5
+ AgentSessionOptions,
6
+ BranchSelection,
7
7
  CancelRequest,
8
- ClientTransport,
9
- ClientTransportOptions,
10
- CloseOptions,
11
- EventsNode,
8
+ ClientSession,
9
+ ClientSessionOptions,
10
+ ConversationNode,
11
+ InputNode,
12
+ InvocationData,
13
+ LoadConversationOptions,
12
14
  MessageNode,
13
- NewTurnOptions,
15
+ OutputEvent,
16
+ PipeOptions,
17
+ Run,
18
+ RunEndParams,
19
+ RunEndReason,
20
+ RunInfo,
21
+ RunLifecycleEvent,
22
+ RunNode,
23
+ RunNodeState,
24
+ RunRuntime,
25
+ RunView,
14
26
  SendOptions,
15
- ServerTransport,
16
- ServerTransportOptions,
17
- StreamResponseOptions,
18
27
  StreamResult,
19
28
  Tree,
20
- Turn,
21
- TurnEndReason,
22
- TurnLifecycleEvent,
23
29
  View,
24
30
  } from './core/transport/index.js';
31
+ export { buildTransportHeaders, createAgentSession, createClientSession, Invocation } from './core/transport/index.js';
25
32
 
26
- // Deprecated aliases — intentional re-export of deprecated types for backwards compatibility.
27
- // eslint-disable-next-line @typescript-eslint/no-deprecated
28
- export type { EventNode } from './core/transport/index.js';
29
- // eslint-disable-next-line @typescript-eslint/no-deprecated
30
- export type { TreeNode } from './core/transport/index.js';
31
- export { buildTransportHeaders, createClientTransport, createServerTransport } from './core/transport/index.js';
33
+ // Channel modes
34
+ export { OBJECT_MODES } from './core/channel-options.js';
32
35
 
33
36
  // Core codec
34
37
  export type {
38
+ BatchAssembleContext,
39
+ BatchMessageHeaders,
40
+ BatchSpec,
35
41
  ChannelWriter,
36
42
  Codec,
43
+ CodecEvent,
44
+ CodecInputEvent,
45
+ CodecMessage,
46
+ CodecOutputEvent,
47
+ CodecReducer,
48
+ DataCodec,
49
+ DecodedMessage,
50
+ Decoder,
37
51
  DecoderCore,
38
52
  DecoderCoreHooks,
39
53
  DecoderCoreOptions,
40
- DecoderOutput,
41
- DiscreteEncoder,
54
+ DefineCodecConfig,
55
+ DefinedCodec,
56
+ Encoder,
42
57
  EncoderCore,
43
58
  EncoderCoreOptions,
44
59
  EncoderOptions,
60
+ EscapeHatchCore,
45
61
  Extras,
62
+ FieldFor,
63
+ HeaderBuilder,
64
+ HeaderField,
65
+ InputBuilder,
66
+ InputDescriptor,
67
+ InputEventSpec,
68
+ LifecycleDiscreteContext,
69
+ LifecyclePolicy,
46
70
  LifecycleTracker,
47
- MessageAccumulator,
48
71
  MessagePayload,
72
+ OutputBuilder,
73
+ OutputDecodeContext,
74
+ OutputDescriptor,
75
+ OutputEncodeHatchContext,
76
+ OutputEventSpec,
77
+ OutputStreamEndContext,
78
+ OutputStreamSpec,
79
+ PartBuilder,
80
+ PartSpec,
49
81
  PhaseConfig,
50
- StreamDecoder,
51
- StreamEncoder,
82
+ Reducer,
83
+ ReducerMeta,
84
+ Regenerate,
52
85
  StreamPayload,
53
86
  StreamTrackerState,
87
+ ToolApprovalResponse,
88
+ ToolResult,
89
+ ToolResultError,
90
+ UserMessage,
91
+ WellKnownInputFactories,
54
92
  WriteOptions,
55
93
  } from './core/codec/index.js';
56
- export { createDecoderCore, createEncoderCore, createLifecycleTracker, eventOutput } from './core/codec/index.js';
94
+ export {
95
+ boolField,
96
+ createDecoderCore,
97
+ createEncoderCore,
98
+ createLifecycleTracker,
99
+ defineCodec,
100
+ enumField,
101
+ jsonField,
102
+ strField,
103
+ } from './core/codec/index.js';
57
104
 
58
105
  // Constants
59
106
  export {
60
- DOMAIN_HEADER_PREFIX,
61
- EVENT_ABORT,
62
107
  EVENT_CANCEL,
63
- EVENT_ERROR,
64
- EVENT_TURN_END,
65
- EVENT_TURN_START,
66
- HEADER_CANCEL_ALL,
67
- HEADER_CANCEL_CLIENT_ID,
68
- HEADER_CANCEL_OWN,
69
- HEADER_CANCEL_TURN_ID,
108
+ EVENT_RUN_END,
109
+ EVENT_RUN_START,
110
+ HEADER_CODEC_MESSAGE_ID,
111
+ HEADER_ERROR_CODE,
112
+ HEADER_ERROR_MESSAGE,
70
113
  HEADER_FORK_OF,
71
- HEADER_MSG_ID,
114
+ HEADER_INPUT_CLIENT_ID,
115
+ HEADER_MSG_REGENERATE,
72
116
  HEADER_PARENT,
73
117
  HEADER_ROLE,
118
+ HEADER_RUN_CLIENT_ID,
119
+ HEADER_RUN_ID,
120
+ HEADER_RUN_REASON,
74
121
  HEADER_STATUS,
75
122
  HEADER_STREAM,
76
123
  HEADER_STREAM_ID,
77
- HEADER_TURN_CLIENT_ID,
78
- HEADER_TURN_ID,
79
- HEADER_TURN_REASON,
80
124
  } from './constants.js';
81
125
 
82
126
  // Utilities
83
- export type { DomainHeaderReader, DomainHeaderWriter, Stripped } from './utils.js';
84
- export { getHeaders, headerReader, headerWriter, mergeHeaders, stripUndefined } from './utils.js';
127
+ export type { Stripped } from './utils.js';
128
+ export { getCodecHeaders, getTransportHeaders, mergeHeaders, stripUndefined } from './utils.js';
85
129
 
86
130
  // Event emitter
87
131
  export { EventEmitter } from './event-emitter.js';
package/src/logger.ts CHANGED
@@ -143,10 +143,22 @@ export const consoleLogger = (message: string, level: LogLevel, context?: LogCon
143
143
  * Options for creating a logger.
144
144
  */
145
145
  export interface LoggerOptions {
146
+ /**
147
+ * The handler that receives formatted log messages. Defaults to {@link consoleLogger} when omitted.
148
+ */
146
149
  logHandler?: LogHandler;
150
+ /**
151
+ * The minimum level to emit; messages below this level are suppressed. Must be a valid {@link LogLevel}, otherwise logger creation throws.
152
+ */
147
153
  logLevel: LogLevel;
148
154
  }
149
155
 
156
+ /**
157
+ * Creates a {@link Logger} from the given options.
158
+ * @param options The handler and minimum level for the logger.
159
+ * @returns A logger that filters by level and delegates to the handler.
160
+ * @throws {@link Ably.ErrorInfo} with {@link ErrorCode.InvalidArgument} if `options.logLevel` is not a recognised {@link LogLevel}.
161
+ */
150
162
  export const makeLogger = (options: LoggerOptions): Logger => {
151
163
  const logHandler = options.logHandler ?? consoleLogger;
152
164
 
@@ -218,7 +230,8 @@ class DefaultLogger implements Logger {
218
230
  }
219
231
 
220
232
  withContext(context: LogContext): Logger {
221
- // Get the original log level by finding the key in logLevelNumberMap that matches this._levelNumber
233
+ // Get the original log level by finding the key in logLevelNumberMap that matches this._levelNumber.
234
+ // The Error fallback is defensive and unreachable in practice: _levelNumber always originates from the map.
222
235
  const originalLevel =
223
236
  [...logLevelNumberMap.entries()].find(([, value]) => value === this._levelNumber)?.[0] ?? LogLevel.Error;
224
237
 
@@ -0,0 +1,41 @@
1
+ import type * as Ably from 'ably';
2
+ import { createContext } from 'react';
3
+
4
+ import type { CodecInputEvent, CodecOutputEvent } from '../../core/codec/types.js';
5
+ import type { ClientSession } from '../../core/transport/types.js';
6
+
7
+ /**
8
+ * A single entry in the client-session registry, holding the session and any
9
+ * error that occurred during its construction.
10
+ *
11
+ * `session` is `undefined` when construction failed.
12
+ * `sessionError` is set when `createClientSession` threw during provider render.
13
+ */
14
+ export interface ClientSessionSlot {
15
+ /** The constructed session, or `undefined` if construction failed. */
16
+ session: ClientSession<CodecInputEvent, CodecOutputEvent, unknown, unknown> | undefined;
17
+ /** Construction error from `createClientSession`, or `undefined` on success. */
18
+ sessionError?: Ably.ErrorInfo | undefined;
19
+ }
20
+
21
+ /**
22
+ * The shape of the {@link ClientSessionContext} value.
23
+ *
24
+ * `nearest` is the slot from the innermost enclosing {@link ClientSessionProvider}.
25
+ * `providers` is the full registry of all enclosing providers, keyed by channelName.
26
+ */
27
+ interface ClientSessionContextValue {
28
+ /** The innermost {@link ClientSessionProvider}'s slot. `undefined` when no provider is present. */
29
+ nearest: ClientSessionSlot | undefined;
30
+ /** All registered session slots from enclosing providers, keyed by channelName. */
31
+ providers: Readonly<Record<string, ClientSessionSlot>>;
32
+ }
33
+
34
+ /**
35
+ * Unified client-session context.
36
+ *
37
+ * Holds the nearest client-session slot and the full registry of all registered
38
+ * slots keyed by channelName. Populated by {@link ClientSessionProvider};
39
+ * read by {@link useClientSession} and internal hooks.
40
+ */
41
+ export const ClientSessionContext = createContext<ClientSessionContextValue>({ nearest: undefined, providers: {} });