@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,141 @@
1
+ /**
2
+ * Typed header-field bindings.
3
+ *
4
+ * A {@link HeaderField} binds a codec header key to its value type **once**,
5
+ * and exposes a symmetric {@link HeaderField.read | read} / {@link
6
+ * HeaderField.write | write} pair over a raw `Record<string, string>` headers
7
+ * record. Because a single binding drives both the encode and decode side, the
8
+ * header key and its value type stay in lockstep across directions — a key
9
+ * cannot be misspelled on one side and silently read as absent on the other.
10
+ *
11
+ * This is deliberately **not** a schema library: it is a thin bidirectional
12
+ * string (de)serializer over the headers record. The SDK ships no hard runtime
13
+ * dependencies, and a schema approach would force re-declaring peer-SDK-owned
14
+ * types. The four constructors cover every header value shape the codecs use:
15
+ *
16
+ * - {@link strField} — string values, optional default.
17
+ * - {@link boolField} — `"true"`/`"false"` booleans, optional default.
18
+ * - {@link jsonField} — JSON-serialized structured values.
19
+ * - {@link enumField} — string values validated against an allow-list with a
20
+ * fallback (e.g. a finish reason).
21
+ *
22
+ * Passing a default to `strField`/`boolField` makes the field **total**: its
23
+ * `read` returns `V` rather than `V | undefined`, for required headers that
24
+ * should always decode to a concrete value.
25
+ */
26
+ /**
27
+ * A header key bound to its value type, with symmetric read/write over a raw
28
+ * headers record. Created via {@link strField}, {@link boolField}, {@link
29
+ * jsonField}, or {@link enumField}.
30
+ *
31
+ * The `key` plays a dual role in descriptor `fields` tables: it is the wire
32
+ * header key AND the property name the drivers read off the source object on
33
+ * encode and write back into the rebuilt object on decode. {@link FieldFor}
34
+ * enforces this — a declared field's key must name a real property of the
35
+ * member it lenses onto.
36
+ * @template V - The decoded value type this field reads and writes.
37
+ * @template K - The header key literal (preserved so {@link FieldFor} can match it against the member's property names).
38
+ */
39
+ export interface HeaderField<V, K extends string = string> {
40
+ /** The raw header key this field reads from and writes to — also the source/rebuilt property name in descriptor tables. */
41
+ readonly key: K;
42
+ /**
43
+ * Read and decode this field's value from a headers record.
44
+ * @param headers - The raw codec headers record to read from.
45
+ * @returns The decoded value. For defaulted/validated fields this is total
46
+ * (the default/fallback is returned when the header is absent or invalid);
47
+ * otherwise `undefined` when the header is absent.
48
+ */
49
+ read(headers: Record<string, string>): V;
50
+ /**
51
+ * Encode and write this field's value into a headers record, mutating it in
52
+ * place. `undefined` (and `null`, for JSON values), and values whose runtime
53
+ * type doesn't match the field, are skipped — the key is left unset rather
54
+ * than written. The parameter is `unknown` (not `V`) so a field keeps `V` in
55
+ * a single covariant position (`read`); this lets heterogeneous fields share a
56
+ * `HeaderField<unknown>[]` array, which the descriptor drivers rely on. At a
57
+ * typed call site the caller still passes a `V`.
58
+ * @param headers - The headers record to mutate.
59
+ * @param value - The value to encode and set.
60
+ */
61
+ write(headers: Record<string, string>, value: unknown): void;
62
+ }
63
+ /**
64
+ * Symmetric codec for a descriptor's wire `data`. Many wire payloads are object
65
+ * envelopes a decode reads several chunk props out of (e.g. `{ errorText, input }`),
66
+ * so a single field can't model them. `encode` produces the wire data from the
67
+ * chunk; `decode` returns the chunk props the envelope contributes, merged into
68
+ * the rebuilt chunk by the driver.
69
+ * @template C - The narrowed chunk member.
70
+ */
71
+ export interface DataCodec<C> {
72
+ /** Produce the wire `data` from the chunk. */
73
+ encode: (chunk: C) => unknown;
74
+ /**
75
+ * Extract the chunk props this envelope contributes from the wire `data`.
76
+ * Undefined-valued props are stripped when the driver rebuilds the object —
77
+ * every rebuild seam (output chunk, input payload, batch part) applies the
78
+ * same rule, since absent and undefined are indistinguishable on the wire.
79
+ */
80
+ decode: (data: unknown) => Partial<C>;
81
+ }
82
+ /**
83
+ * The header fields a descriptor may declare against member `C`. For each
84
+ * string-keyed property of `C`, a field is acceptable when its key IS that
85
+ * property name and its value type can hold the property. A mistyped key or a
86
+ * wrong-typed field (e.g. a `boolField` on a string property) is a compile
87
+ * error instead of a silently absent header.
88
+ * @template C - The member (chunk, payload, or part) the fields lens onto.
89
+ */
90
+ export type FieldFor<C> = {
91
+ [K in keyof C & string]-?: HeaderField<C[K] | undefined, K>;
92
+ }[keyof C & string];
93
+ /**
94
+ * Bind a string-valued header field.
95
+ * @param key - The header key (and source property name in descriptor tables).
96
+ * @returns A field whose `read` yields `string | undefined` (absent → `undefined`).
97
+ */
98
+ export declare function strField<K extends string>(key: K): HeaderField<string | undefined, K>;
99
+ /**
100
+ * Bind a string-valued header field with a default, making it total.
101
+ * @param key - The header key (and source property name in descriptor tables).
102
+ * @param fallback - Value returned by `read` when the header is absent.
103
+ * @returns A field whose `read` yields `string` (absent → `fallback`).
104
+ */
105
+ export declare function strField<K extends string>(key: K, fallback: string): HeaderField<string, K>;
106
+ /**
107
+ * Bind a boolean-valued header field, serialized as `"true"`/`"false"`.
108
+ * @param key - The header key (and source property name in descriptor tables).
109
+ * @returns A field whose `read` yields `boolean | undefined` (absent → `undefined`).
110
+ */
111
+ export declare function boolField<K extends string>(key: K): HeaderField<boolean | undefined, K>;
112
+ /**
113
+ * Bind a boolean-valued header field with a default, making it total.
114
+ * @param key - The header key (and source property name in descriptor tables).
115
+ * @param fallback - Value returned by `read` when the header is absent.
116
+ * @returns A field whose `read` yields `boolean` (absent → `fallback`).
117
+ */
118
+ export declare function boolField<K extends string>(key: K, fallback: boolean): HeaderField<boolean, K>;
119
+ /**
120
+ * Bind a JSON-serialized header field. The value is written with
121
+ * `JSON.stringify` and read back with `JSON.parse`; malformed JSON reads as
122
+ * `undefined`. The decoded shape is a trust boundary — the caller asserts it
123
+ * via the `V` type parameter.
124
+ * @template V - The expected decoded shape of the JSON value.
125
+ * @template K - The header key literal. Inferred when `V` is omitted; pass it explicitly alongside `V` when the field participates in a typed descriptor `fields` table.
126
+ * @param key - The header key (and source property name in descriptor tables).
127
+ * @returns A field whose `read` yields `V | undefined` (absent or malformed → `undefined`).
128
+ */
129
+ export declare const jsonField: <V, K extends string = string>(key: K) => HeaderField<V | undefined, K>;
130
+ /**
131
+ * Bind a string-valued header field validated against a fixed allow-list,
132
+ * falling back to a given value when the header is absent or unrecognized. Use
133
+ * for headers with a small closed set of valid values (e.g. a finish reason).
134
+ * @template T - The union of allowed string literals, inferred from `allowed`.
135
+ * @template K - The header key literal, inferred from `key`.
136
+ * @param key - The header key (and source property name in descriptor tables).
137
+ * @param allowed - The exhaustive list of valid values.
138
+ * @param fallback - Value returned by `read` when the header is absent or not in `allowed`.
139
+ * @returns A total field whose `read` yields one of the allowed literals.
140
+ */
141
+ export declare const enumField: <const T extends string, K extends string>(key: K, allowed: readonly T[], fallback: NoInfer<T>) => HeaderField<T, K>;
@@ -1,8 +1,14 @@
1
- export { eventOutput } from './decoder.js';
2
- export type { ChannelWriter, Codec, DecoderOutput, DiscreteEncoder, EncoderOptions, Extras, MessageAccumulator, MessagePayload, StreamDecoder, StreamEncoder, StreamPayload, StreamTrackerState, WriteOptions, } from './types.js';
1
+ export type { ChannelWriter, Codec, CodecEvent, CodecInputEvent, CodecMessage, CodecOutputEvent, DecodedMessage, Decoder, Encoder, EncoderOptions, Extras, MessagePayload, Reducer, ReducerMeta, Regenerate, StreamPayload, StreamTrackerState, ToolApprovalResponse, ToolResult, ToolResultError, UserMessage, WriteOptions, } from './types.js';
3
2
  export type { EncoderCore, EncoderCoreOptions } from './encoder.js';
4
3
  export { createEncoderCore } from './encoder.js';
5
4
  export type { DecoderCore, DecoderCoreHooks, DecoderCoreOptions } from './decoder.js';
6
5
  export { createDecoderCore } from './decoder.js';
7
6
  export type { LifecycleTracker, PhaseConfig } from './lifecycle-tracker.js';
8
7
  export { createLifecycleTracker } from './lifecycle-tracker.js';
8
+ export type { DataCodec, FieldFor, HeaderField } from './fields.js';
9
+ export { boolField, enumField, jsonField, strField } from './fields.js';
10
+ export type { WellKnownInputFactories } from './well-known-inputs.js';
11
+ export type { EscapeHatchCore, HeaderBuilder, OutputDecodeContext, OutputDescriptor, OutputEncodeHatchContext, OutputEventSpec, OutputStreamEndContext, OutputStreamSpec, } from './output-descriptors.js';
12
+ export type { BatchAssembleContext, BatchMessageHeaders, BatchSpec, InputDescriptor, InputEventSpec, PartBuilder, PartSpec, } from './input-descriptors.js';
13
+ export type { CodecReducer, DefineCodecConfig, DefinedCodec, InputBuilder, LifecycleDiscreteContext, LifecyclePolicy, OutputBuilder, } from './define-codec.js';
14
+ export { defineCodec } from './define-codec.js';
@@ -0,0 +1,19 @@
1
+ import { InputDecodeContext, InputDescriptor } from './input-descriptors.js';
2
+ /** Decodes inbound `ai-input` messages of union `U` from an input descriptor set. */
3
+ export interface InputDescriptorDecoder<U> {
4
+ /**
5
+ * Rebuild zero or more inputs from one inbound `ai-input` message.
6
+ * @param ctx - The inbound message context (codec kind, data, header tiers).
7
+ * @returns The decoded inputs (empty when no descriptor matches or the input is wire-only).
8
+ */
9
+ decode(ctx: InputDecodeContext): U[];
10
+ }
11
+ /**
12
+ * Build an input decode driver for an input descriptor set.
13
+ * @template U - The codec's input union.
14
+ * @param descriptors - The input descriptor set (events + batches).
15
+ * @returns An {@link InputDescriptorDecoder} that reconstructs inputs from the wire.
16
+ */
17
+ export declare const createInputDescriptorDecoder: <U extends {
18
+ kind: string;
19
+ }>(descriptors: readonly InputDescriptor<U>[]) => InputDescriptorDecoder<U>;
@@ -0,0 +1,22 @@
1
+ import { InputDescriptor, InputEncodeContext, InputEncoderCore } from './input-descriptors.js';
2
+ /** Encodes inputs of union `U` to channel operations via an input descriptor set. */
3
+ export interface InputDescriptorEncoder<U> {
4
+ /**
5
+ * Encode one input through its descriptor.
6
+ * @param input - The input to encode.
7
+ * @param core - The input encoder core to publish through.
8
+ * @param ctx - Per-write context (write options, carrying the codec-message-id).
9
+ * @returns A promise resolving when the publish operation completes.
10
+ */
11
+ encode(input: U, core: InputEncoderCore, ctx: InputEncodeContext): Promise<void>;
12
+ }
13
+ /**
14
+ * Build an input encode driver for an input descriptor set bound to a wire name.
15
+ * @template U - The codec's input union.
16
+ * @param descriptors - The input descriptor set (events + batches).
17
+ * @param wireName - The Ably message name for the input direction (`ai-input`).
18
+ * @returns An {@link InputDescriptorEncoder} routing each input through its descriptor.
19
+ */
20
+ export declare const createInputDescriptorEncoder: <U extends {
21
+ kind: string;
22
+ }>(descriptors: readonly InputDescriptor<U>[], wireName: string) => InputDescriptorEncoder<U>;
@@ -0,0 +1,281 @@
1
+ import { DataCodec, FieldFor, HeaderField } from './fields.js';
2
+ import { MessagePayload, WriteOptions } from './types.js';
3
+ /**
4
+ * Declarative input descriptors — the single source of truth for a codec's
5
+ * `ai-input` wire mapping, the input-side sibling of {@link import('./output-descriptors.js')}.
6
+ *
7
+ * Inputs come in two cardinalities: a single domain input ↔ one wire message
8
+ * (the `event` construct), and a single domain message ↔ many atomic wire events
9
+ * (the `batch` construct — the input sibling of the output `stream`). Both are
10
+ * declared once per codec and consumed by the generic input encode/decode
11
+ * drivers, so adding an input is one descriptor entry rather than a pair of
12
+ * hand-synchronised switch arms.
13
+ *
14
+ * Authoring is cast-free: the {@link inputBuilder} factory hands the codec a
15
+ * `{ event, batch }` pair curried on the codec's input union, so every `data` /
16
+ * `fields` / `parts` callback receives the exact narrowed member. The descriptors
17
+ * are then erased to a heterogeneous {@link InputDescriptor} via a single
18
+ * documented cast at each constructor boundary — never in author code.
19
+ */
20
+ import type * as Ably from 'ably';
21
+ /** Resolve the input union member a `kind` literal selects. */
22
+ export type ResolveInput<U extends {
23
+ kind: string;
24
+ }, K extends U['kind']> = Extract<U, {
25
+ kind: K;
26
+ }>;
27
+ /**
28
+ * The payload an input `event`'s `fields` / `data` operate on. Inputs nest their
29
+ * domain data under `payload` (the `{ kind, codecMessageId, payload }` envelope of
30
+ * the well-known input variants), so a single event's spec is authored against the
31
+ * payload, and the driver wraps/unwraps the envelope. A member with no `payload`
32
+ * (a `wireOnly` signal) resolves to `never` — such an event declares no `fields` /
33
+ * `data`, so the payload type is never used.
34
+ * @template C - The narrowed input member.
35
+ */
36
+ export type PayloadOf<C> = C extends {
37
+ payload: infer P;
38
+ } ? P : never;
39
+ /**
40
+ * Resolve the part union member a `partType` literal selects, mirroring the
41
+ * output {@link import('./output-descriptors.js').ResolveType} curry one level down.
42
+ * An exact match wins; a wildcard literal (`data-*`) resolves to the template
43
+ * member (`data-${string}`).
44
+ * @template P - The part union.
45
+ * @template T - The selected `partType` literal (or a `*-*` wildcard).
46
+ */
47
+ export type ResolvePart<P extends {
48
+ type: string;
49
+ }, T extends string> = Extract<P, {
50
+ type: T;
51
+ }> extends never ? T extends `${infer Pre}-*` ? Extract<P, {
52
+ type: `${Pre}-${string}`;
53
+ }> : never : Extract<P, {
54
+ type: T;
55
+ }>;
56
+ /**
57
+ * The encoder-core view the input encode driver receives: discrete publishes
58
+ * only — inputs never stream. The concrete {@link EncoderCore} satisfies this
59
+ * structurally.
60
+ */
61
+ export interface InputEncoderCore {
62
+ /** Publish a single discrete message. */
63
+ publishDiscrete(payload: MessagePayload, opts?: WriteOptions): Promise<Ably.PublishResult>;
64
+ /** Publish multiple discrete messages atomically (the batch fan-out). */
65
+ publishDiscreteBatch(payloads: MessagePayload[], opts?: WriteOptions): Promise<Ably.PublishResult>;
66
+ }
67
+ /** Per-write context passed to the input encode driver. */
68
+ export interface InputEncodeContext {
69
+ /** Per-write overrides (the wire codec-message-id is stamped here by the client session). */
70
+ opts: WriteOptions | undefined;
71
+ }
72
+ /** Per-message context the input decode driver receives for one inbound `ai-input` message. */
73
+ export interface InputDecodeContext {
74
+ /** The codec `kind` header value (the input descriptor's dispatch key). */
75
+ codecKind: string;
76
+ /** The inbound message data. */
77
+ data: unknown;
78
+ /** The inbound codec-tier headers. */
79
+ codecHeaders: Record<string, string>;
80
+ /** The inbound transport-tier headers (role, codec-message-id, discrete marker). */
81
+ transportHeaders: Record<string, string>;
82
+ }
83
+ /**
84
+ * The spec the input `event` construct accepts for member `C`. A member with
85
+ * no `payload` has nothing for `fields` / `data` to lens onto, so it may only
86
+ * be declared `wireOnly` or escape-hatched; the driver also rejects a
87
+ * payload-less encode at runtime.
88
+ * @template C - The narrowed input member.
89
+ */
90
+ export type InputEventSpecFor<C> = [PayloadOf<C>] extends [never] ? Pick<InputEventSpec<C>, 'wireOnly'> : InputEventSpec<C>;
91
+ /**
92
+ * A single-event input descriptor spec, narrowed to input member `C`. `fields`
93
+ * and `data` operate on the member's {@link PayloadOf payload}; the driver wraps
94
+ * the `{ kind, codecMessageId, payload }` envelope on decode and unwraps it on
95
+ * encode. A `wireOnly` event carries no payload (kind only).
96
+ * @template C - The narrowed input member.
97
+ */
98
+ export interface InputEventSpec<C> {
99
+ /**
100
+ * Declared header fields over the member's payload, written on encode and
101
+ * read on decode. Each field's key names both the wire header and the
102
+ * payload property it carries (see {@link FieldFor}). Omit for none.
103
+ */
104
+ fields?: readonly FieldFor<PayloadOf<C>>[];
105
+ /** Wire `data` codec over the payload. Omit when the input carries no data (`data: ''`). */
106
+ data?: DataCodec<PayloadOf<C>>;
107
+ /** Wire-only signal: encode stamps only the `kind` header (empty data, no fields); decode yields `[]`. */
108
+ wireOnly?: boolean;
109
+ }
110
+ /**
111
+ * A per-part wire mapping inside a {@link BatchSpec}, narrowed to part member `Q`.
112
+ * `fields` and `data` operate on the selected part; the batch driver fans the
113
+ * domain message out into one wire event per part and reassembles them in the
114
+ * reducer (merge by codec-message-id).
115
+ * @template Q - The narrowed part member.
116
+ */
117
+ export interface PartSpec<Q> {
118
+ /**
119
+ * Declared header fields for this part, written on encode and read on
120
+ * decode. Each field's key names both the wire header and the part property
121
+ * it carries (see {@link FieldFor}). Omit for none.
122
+ */
123
+ fields?: readonly FieldFor<Q>[];
124
+ /** Wire `data` codec over the part. Omit when the part carries no data. */
125
+ data?: DataCodec<Q>;
126
+ }
127
+ /**
128
+ * The curried part sub-builder a {@link BatchSpec.parts} function receives.
129
+ * Mirrors the {@link inputBuilder} `event` curry one level down — and the
130
+ * output builder's wildcard idiom: `p(partType, spec)` narrows `spec` to the
131
+ * part member the literal selects, and a `-*` literal (e.g. `data-*`) declares
132
+ * a wildcard family whose dispatch predicate is derived from the literal's
133
+ * prefix, narrowing `spec` to the template member. Both forms are cast-free in
134
+ * author code.
135
+ * @template P - The part union.
136
+ */
137
+ export type PartBuilder<P extends {
138
+ type: string;
139
+ }> = <T extends P['type'] | `${string}-*`>(partType: T, spec: PartSpec<ResolvePart<P, T>>) => PartDescriptor;
140
+ /**
141
+ * Per-message wire headers a {@link BatchSpec.messageHeaders} stamps on every
142
+ * part of one batch. These carry metadata that belongs to the whole message
143
+ * rather than an individual part (e.g. the message id as a codec header, the
144
+ * sender role as a transport header), so the decode side can reconstruct the
145
+ * shared message envelope from any single part. Both tiers are optional.
146
+ */
147
+ export interface BatchMessageHeaders {
148
+ /** Codec-tier headers stamped on every part (e.g. a per-message id). */
149
+ codecHeaders?: Record<string, string>;
150
+ /** Transport-tier headers stamped on every part (e.g. the sender role). */
151
+ transportHeaders?: Record<string, string>;
152
+ }
153
+ /**
154
+ * The context a {@link BatchSpec.assemble} receives alongside one decoded part:
155
+ * the inbound header tiers of the wire event the part was decoded from. A batch
156
+ * fans out into N independent wire events, so each part arrives carrying the
157
+ * shared per-message headers ({@link BatchMessageHeaders}); `assemble` reads them
158
+ * to rebuild the message envelope (id, role, …) around its one part.
159
+ */
160
+ export interface BatchAssembleContext {
161
+ /** The inbound codec-tier headers (carries the per-message codec headers). */
162
+ codecHeaders: Record<string, string>;
163
+ /** The inbound transport-tier headers (carries the per-message transport headers). */
164
+ transportHeaders: Record<string, string>;
165
+ }
166
+ /**
167
+ * A multi-part input descriptor spec: one domain message decomposed into many
168
+ * atomic wire events sharing the input member's `kind` and codec-message-id, each
169
+ * carrying a `partType` sub-discriminator. The part union `P` is inferred from
170
+ * `explode`'s return type and threaded into `parts`'s curried `p` and `assemble`,
171
+ * so all three are cast-free in author code.
172
+ * @template C - The narrowed input member (the message-bearing input).
173
+ * @template P - The part union the message explodes into.
174
+ */
175
+ export interface BatchSpec<C, P extends {
176
+ type: string;
177
+ }> {
178
+ /** ENCODE: decompose the domain message into its parts. */
179
+ explode: (input: C) => readonly P[];
180
+ /** The `partType` sub-discriminator read off each part on encode. */
181
+ partTypeOf: (part: P) => string;
182
+ /** Declarative per-part wire mapping (a sub-table built via the curried `p`). */
183
+ parts: (p: PartBuilder<P>) => readonly PartDescriptor[];
184
+ /**
185
+ * ENCODE: per-message headers stamped on every part (the driver merges them
186
+ * onto each part's headers, including the ≥1-event fallback). Use for metadata
187
+ * shared by the whole message — e.g. a message-id codec header and a role
188
+ * transport header. Omit when parts carry no shared per-message metadata.
189
+ */
190
+ messageHeaders?: (input: C) => BatchMessageHeaders;
191
+ /**
192
+ * DECODE: shape one decoded wire part into a one-part input (the reducer merges
193
+ * parts by codec-message-id). `ctx` exposes the inbound header tiers so the
194
+ * shared per-message metadata stamped by `messageHeaders` can be read back.
195
+ * The driver stamps only `kind`; the per-message identity rides the
196
+ * transport header and is recovered through `ctx` when needed.
197
+ */
198
+ assemble: (part: P, ctx: BatchAssembleContext) => Omit<C, 'kind'>;
199
+ }
200
+ /** A single-event input descriptor erased to the codec's input union `U`. */
201
+ export interface InputEventDescriptor {
202
+ /** Discriminator. */
203
+ construct: 'event';
204
+ /** The wire `kind` this input dispatches on. */
205
+ kind: string;
206
+ /** Declared header fields (read/written against the member's payload). */
207
+ fields: readonly HeaderField<unknown>[];
208
+ /** Wire `data` codec, if any. */
209
+ data?: DataCodec<unknown>;
210
+ /** Wire-only signal flag. */
211
+ wireOnly: boolean;
212
+ }
213
+ /** An erased per-part wire mapping within a {@link BatchDescriptor}. */
214
+ export interface PartDescriptor {
215
+ /** The exact `partType` this part encodes as (the wildcard sentinel for a family). */
216
+ partType: string;
217
+ /** Decode-dispatch predicate for a wildcard part; absent for an exact part. */
218
+ match?: (partType: string) => boolean;
219
+ /** Declared header fields for this part. */
220
+ fields: readonly HeaderField<unknown>[];
221
+ /** Wire `data` codec over the part, if any. */
222
+ data?: DataCodec<unknown>;
223
+ }
224
+ /** A multi-part (batch) input descriptor erased to the codec's input union `U`. */
225
+ export interface BatchDescriptor<U> {
226
+ /** Discriminator. */
227
+ construct: 'batch';
228
+ /** The wire `kind` every part of this batch shares. */
229
+ kind: string;
230
+ /** Decompose the domain input into its parts. */
231
+ explode: (input: U) => readonly unknown[];
232
+ /** Read the `partType` sub-discriminator off a part. */
233
+ partTypeOf: (part: unknown) => string;
234
+ /** The per-part wire mappings. */
235
+ parts: readonly PartDescriptor[];
236
+ /** Build the per-message headers stamped on every part, if any. */
237
+ messageHeaders?: (input: U) => BatchMessageHeaders;
238
+ /** Shape one decoded part into a one-part input (sans the driver-stamped `kind`). */
239
+ assemble: (part: unknown, ctx: BatchAssembleContext) => Omit<U, 'kind'>;
240
+ }
241
+ /** An erased input descriptor — a single event or a multi-part batch. */
242
+ export type InputDescriptor<U> = InputEventDescriptor | BatchDescriptor<U>;
243
+ /**
244
+ * The direction-scoped input builder `defineCodec` injects into the `input`
245
+ * config function — `event` and `batch`, both curried on the codec's input union
246
+ * so author entries narrow cast-free.
247
+ * @template U - The codec's input union.
248
+ */
249
+ export interface InputBuilder<U extends {
250
+ kind: string;
251
+ }> {
252
+ /**
253
+ * Declare a single-event input. Narrows `spec` to the member `kind` selects;
254
+ * `fields` / `data` operate on that member's payload.
255
+ * @param kind - The input member's `kind` literal (the wire dispatch key).
256
+ * @param spec - The narrowed input spec. Omit for a bare-`kind` input.
257
+ * @returns An erased {@link InputDescriptor}.
258
+ */
259
+ event: <K extends U['kind']>(kind: K, spec?: InputEventSpecFor<ResolveInput<U, K>>) => InputDescriptor<U>;
260
+ /**
261
+ * Declare a multi-part (batch) input. Narrows the spec to the message-bearing
262
+ * member `kind` selects; `explode`'s return type fixes the part union `P`, which
263
+ * threads into `parts`'s curried `p` and `assemble` cast-free.
264
+ * @param kind - The input member's `kind` literal (the shared wire dispatch key).
265
+ * @param spec - The narrowed batch spec.
266
+ * @returns An erased {@link InputDescriptor}.
267
+ */
268
+ batch: <K extends U['kind'], P extends {
269
+ type: string;
270
+ }>(kind: K, spec: BatchSpec<ResolveInput<U, K>, P>) => InputDescriptor<U>;
271
+ }
272
+ /**
273
+ * Build the curried `{ event, batch }` input builder for a codec's input union.
274
+ * `defineCodec` calls this once and hands the result to the `input` config
275
+ * function; mirrors the output side's {@link import('./output-descriptors.js').outputBuilder}.
276
+ * @template U - The codec's input union.
277
+ * @returns The direction-scoped {@link InputBuilder}.
278
+ */
279
+ export declare const inputBuilder: <U extends {
280
+ kind: string;
281
+ }>() => InputBuilder<U>;
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Generic lifecycle tracker for codec decoders.
3
3
  *
4
- * Manages per-scope (typically per-turn) tracking of lifecycle phases that
4
+ * Manages per-scope (typically per-run) tracking of lifecycle phases that
5
5
  * must be emitted before content events. When a phase has not been emitted
6
6
  * (e.g. mid-stream join), the tracker synthesizes the missing events using
7
7
  * codec-provided build functions.
@@ -30,15 +30,16 @@ export interface PhaseConfig<TEvent> {
30
30
  * Per-scope lifecycle tracker that ensures required phases are emitted
31
31
  * before content events, synthesizing missing ones for mid-stream joins.
32
32
  *
33
- * Scoped by an arbitrary string key (typically a turn ID). Each scope
33
+ * Scoped by an arbitrary string key (typically a run ID). Each scope
34
34
  * tracks independently which phases have been emitted.
35
35
  */
36
36
  export interface LifecycleTracker<TEvent> {
37
37
  /**
38
38
  * Ensure all configured phases have been emitted for the given scope.
39
- * Returns synthetic events for any phases not yet marked as emitted,
40
- * then marks them. Returns an empty array if all phases are current.
41
- * @param scopeId - The scope to check (e.g. turn ID).
39
+ * Synthesizes and returns the events for any phases not yet marked as
40
+ * emitted, marking each as emitted so it is not synthesized again.
41
+ * Returns an empty array if all phases are already emitted.
42
+ * @param scopeId - The scope to check (e.g. run ID).
42
43
  * @param context - Key-value pairs passed through to phase build functions.
43
44
  * @returns Synthetic events for missing phases, in configuration order.
44
45
  */
@@ -46,7 +47,7 @@ export interface LifecycleTracker<TEvent> {
46
47
  /**
47
48
  * Mark a phase as emitted from the wire (not synthetic). Call this
48
49
  * when the real event arrives so the tracker does not re-synthesize it.
49
- * @param scopeId - The scope (e.g. turn ID).
50
+ * @param scopeId - The scope (e.g. run ID).
50
51
  * @param phaseKey - The phase key to mark.
51
52
  */
52
53
  markEmitted(scopeId: string, phaseKey: string): void;
@@ -54,13 +55,13 @@ export interface LifecycleTracker<TEvent> {
54
55
  * Reset a phase so it will be re-synthesized on the next
55
56
  * {@link ensurePhases} call. Used for repeating phases (e.g. "start-step"
56
57
  * resets after "finish-step").
57
- * @param scopeId - The scope (e.g. turn ID).
58
+ * @param scopeId - The scope (e.g. run ID).
58
59
  * @param phaseKey - The phase key to reset.
59
60
  */
60
61
  resetPhase(scopeId: string, phaseKey: string): void;
61
62
  /**
62
- * Remove all tracking state for a scope. Call on turn completion
63
- * (finish, abort) to free memory.
63
+ * Remove all tracking state for a scope. Call on run completion
64
+ * (finish, cancel) to free memory.
64
65
  * @param scopeId - The scope to clear.
65
66
  */
66
67
  clearScope(scopeId: string): void;
@@ -0,0 +1,29 @@
1
+ import { OutputDescriptor } from './output-descriptors.js';
2
+ import { StreamTrackerState } from './types.js';
3
+ /** Decodes wire messages of union `U` from a descriptor set. */
4
+ export interface OutputDescriptorDecoder<U> {
5
+ /** Rebuild the chunk(s) emitted when a stream starts. */
6
+ buildStart(tracker: StreamTrackerState): U[];
7
+ /** Rebuild the chunk(s) for a stream delta. */
8
+ buildDelta(tracker: StreamTrackerState, delta: string): U[];
9
+ /** Rebuild the chunk(s) emitted when a stream completes. */
10
+ buildEnd(tracker: StreamTrackerState, closingCodecHeaders: Record<string, string>): U[];
11
+ /**
12
+ * Decode a discrete message by its codec `kind`.
13
+ * @param codecKind - The codec `kind` header value (the dispatch key).
14
+ * @param codecHeaders - The inbound codec-tier headers.
15
+ * @param transportHeaders - The inbound transport-tier headers.
16
+ * @param data - The inbound message data.
17
+ * @returns The decoded events (empty if no descriptor matches).
18
+ */
19
+ decodeDiscrete(codecKind: string, codecHeaders: Record<string, string>, transportHeaders: Record<string, string>, data: unknown): U[];
20
+ }
21
+ /**
22
+ * Build an output decode driver for a descriptor set.
23
+ * @template U - The codec's event union.
24
+ * @param descriptors - The descriptor set (events + streamed families).
25
+ * @returns An {@link OutputDescriptorDecoder} that reconstructs events from the wire.
26
+ */
27
+ export declare const createOutputDescriptorDecoder: <U extends {
28
+ type: string;
29
+ }>(descriptors: readonly OutputDescriptor<U>[]) => OutputDescriptorDecoder<U>;
@@ -0,0 +1,31 @@
1
+ import { EncoderCore } from './encoder.js';
2
+ import { OutputDescriptor } from './output-descriptors.js';
3
+ import { WriteOptions } from './types.js';
4
+ /** Per-write output encode context threaded from the encoder. */
5
+ export interface OutputEncodeContext {
6
+ /** The encoder's configured fallback message id, if any. */
7
+ messageId: string | undefined;
8
+ /** Per-write overrides. */
9
+ opts: WriteOptions | undefined;
10
+ }
11
+ /** Encodes events of union `U` to channel operations via a descriptor set. */
12
+ export interface OutputDescriptorEncoder<U> {
13
+ /**
14
+ * Encode one event through its descriptor.
15
+ * @param chunk - The event to encode.
16
+ * @param core - The encoder core to publish/stream through.
17
+ * @param ctx - Per-write context (fallback message id, write options).
18
+ * @returns A promise resolving when the publish/stream operation completes.
19
+ */
20
+ encode(chunk: U, core: EncoderCore, ctx: OutputEncodeContext): Promise<void>;
21
+ }
22
+ /**
23
+ * Build an output encode driver for a descriptor set bound to a wire message name.
24
+ * @template U - The codec's event union.
25
+ * @param descriptors - The descriptor set (events + streamed families).
26
+ * @param wireName - The Ably message name for this direction (`ai-output` / `ai-input`).
27
+ * @returns An {@link OutputDescriptorEncoder} routing each event through its descriptor.
28
+ */
29
+ export declare const createOutputDescriptorEncoder: <U extends {
30
+ type: string;
31
+ }>(descriptors: readonly OutputDescriptor<U>[], wireName: string) => OutputDescriptorEncoder<U>;