@ably/ai-transport 0.0.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +114 -116
- package/dist/ably-ai-transport.js +1743 -961
- package/dist/ably-ai-transport.js.map +1 -1
- package/dist/ably-ai-transport.umd.cjs +1 -1
- package/dist/ably-ai-transport.umd.cjs.map +1 -1
- package/dist/constants.d.ts +117 -39
- package/dist/core/agent.d.ts +29 -0
- package/dist/core/codec/decoder.d.ts +20 -23
- package/dist/core/codec/encoder.d.ts +11 -8
- package/dist/core/codec/index.d.ts +1 -2
- package/dist/core/codec/lifecycle-tracker.d.ts +10 -9
- package/dist/core/codec/types.d.ts +410 -101
- package/dist/core/transport/agent-session.d.ts +10 -0
- package/dist/core/transport/branch-chain.d.ts +43 -0
- package/dist/core/transport/client-session.d.ts +13 -0
- package/dist/core/transport/decode-fold.d.ts +47 -0
- package/dist/core/transport/headers.d.ts +97 -17
- package/dist/core/transport/index.d.ts +5 -3
- package/dist/core/transport/internal/bounded-map.d.ts +20 -0
- package/dist/core/transport/invocation.d.ts +74 -0
- package/dist/core/transport/load-conversation.d.ts +128 -0
- package/dist/core/transport/load-history.d.ts +39 -0
- package/dist/core/transport/pipe-stream.d.ts +9 -8
- package/dist/core/transport/run-manager.d.ts +78 -0
- package/dist/core/transport/tree.d.ts +435 -0
- package/dist/core/transport/types/agent.d.ts +353 -0
- package/dist/core/transport/types/client.d.ts +168 -0
- package/dist/core/transport/types/shared.d.ts +24 -0
- package/dist/core/transport/types/tree.d.ts +315 -0
- package/dist/core/transport/types/view.d.ts +222 -0
- package/dist/core/transport/types.d.ts +13 -402
- package/dist/core/transport/view.d.ts +354 -0
- package/dist/errors.d.ts +37 -9
- package/dist/index.d.ts +6 -6
- package/dist/logger.d.ts +12 -0
- package/dist/react/ably-ai-transport-react.js +1164 -645
- package/dist/react/ably-ai-transport-react.js.map +1 -1
- package/dist/react/ably-ai-transport-react.umd.cjs +1 -1
- package/dist/react/ably-ai-transport-react.umd.cjs.map +1 -1
- package/dist/react/contexts/client-session-context.d.ts +36 -0
- package/dist/react/contexts/client-session-provider.d.ts +53 -0
- package/dist/react/create-session-hooks.d.ts +116 -0
- package/dist/react/index.d.ts +16 -10
- package/dist/react/internal/use-resolved-session.d.ts +36 -0
- package/dist/react/use-ably-messages.d.ts +20 -11
- package/dist/react/use-client-session.d.ts +81 -0
- package/dist/react/use-create-view.d.ts +23 -0
- package/dist/react/use-tree.d.ts +35 -0
- package/dist/react/use-view.d.ts +110 -0
- package/dist/utils.d.ts +32 -23
- package/dist/vercel/ably-ai-transport-vercel.js +2748 -1625
- package/dist/vercel/ably-ai-transport-vercel.js.map +1 -1
- package/dist/vercel/ably-ai-transport-vercel.umd.cjs +1 -1
- package/dist/vercel/ably-ai-transport-vercel.umd.cjs.map +1 -1
- package/dist/vercel/codec/decoder.d.ts +5 -18
- package/dist/vercel/codec/encoder.d.ts +6 -36
- package/dist/vercel/codec/events.d.ts +51 -0
- package/dist/vercel/codec/index.d.ts +24 -12
- package/dist/vercel/codec/reducer.d.ts +144 -0
- package/dist/vercel/codec/tool-transitions.d.ts +50 -0
- package/dist/vercel/index.d.ts +4 -2
- package/dist/vercel/react/ably-ai-transport-vercel-react.js +10298 -1410
- package/dist/vercel/react/ably-ai-transport-vercel-react.js.map +1 -1
- package/dist/vercel/react/ably-ai-transport-vercel-react.umd.cjs +70 -1
- package/dist/vercel/react/ably-ai-transport-vercel-react.umd.cjs.map +1 -1
- package/dist/vercel/react/contexts/chat-transport-context.d.ts +33 -0
- package/dist/vercel/react/contexts/chat-transport-provider.d.ts +96 -0
- package/dist/vercel/react/index.d.ts +4 -0
- package/dist/vercel/react/use-chat-transport.d.ts +66 -21
- package/dist/vercel/react/use-message-sync.d.ts +31 -12
- package/dist/vercel/run-end-reason.d.ts +29 -0
- package/dist/vercel/transport/chat-transport.d.ts +71 -30
- package/dist/vercel/transport/index.d.ts +25 -18
- package/dist/vercel/transport/run-output-stream.d.ts +56 -0
- package/dist/version.d.ts +2 -0
- package/package.json +47 -34
- package/src/constants.ts +126 -47
- package/src/core/agent.ts +68 -0
- package/src/core/codec/decoder.ts +71 -98
- package/src/core/codec/encoder.ts +115 -58
- package/src/core/codec/index.ts +13 -6
- package/src/core/codec/lifecycle-tracker.ts +10 -9
- package/src/core/codec/types.ts +438 -106
- package/src/core/transport/agent-session.ts +1344 -0
- package/src/core/transport/branch-chain.ts +58 -0
- package/src/core/transport/client-session.ts +775 -0
- package/src/core/transport/decode-fold.ts +91 -0
- package/src/core/transport/headers.ts +182 -19
- package/src/core/transport/index.ts +29 -22
- package/src/core/transport/internal/bounded-map.ts +27 -0
- package/src/core/transport/invocation.ts +98 -0
- package/src/core/transport/load-conversation.ts +355 -0
- package/src/core/transport/load-history.ts +269 -0
- package/src/core/transport/pipe-stream.ts +58 -40
- package/src/core/transport/run-manager.ts +249 -0
- package/src/core/transport/tree.ts +1167 -0
- package/src/core/transport/types/agent.ts +407 -0
- package/src/core/transport/types/client.ts +211 -0
- package/src/core/transport/types/shared.ts +27 -0
- package/src/core/transport/types/tree.ts +344 -0
- package/src/core/transport/types/view.ts +259 -0
- package/src/core/transport/types.ts +13 -527
- package/src/core/transport/view.ts +1271 -0
- package/src/errors.ts +42 -9
- package/src/event-emitter.ts +3 -2
- package/src/index.ts +55 -39
- package/src/logger.ts +14 -1
- package/src/react/contexts/client-session-context.ts +41 -0
- package/src/react/contexts/client-session-provider.tsx +186 -0
- package/src/react/create-session-hooks.ts +141 -0
- package/src/react/index.ts +27 -10
- package/src/react/internal/use-resolved-session.ts +63 -0
- package/src/react/use-ably-messages.ts +47 -19
- package/src/react/use-client-session.ts +201 -0
- package/src/react/use-create-view.ts +72 -0
- package/src/react/use-tree.ts +84 -0
- package/src/react/use-view.ts +275 -0
- package/src/react/vite.config.ts +4 -1
- package/src/utils.ts +63 -45
- package/src/vercel/codec/decoder.ts +336 -255
- package/src/vercel/codec/encoder.ts +348 -196
- package/src/vercel/codec/events.ts +87 -0
- package/src/vercel/codec/index.ts +59 -14
- package/src/vercel/codec/reducer.ts +977 -0
- package/src/vercel/codec/tool-transitions.ts +122 -0
- package/src/vercel/index.ts +7 -3
- package/src/vercel/react/contexts/chat-transport-context.ts +41 -0
- package/src/vercel/react/contexts/chat-transport-provider.tsx +150 -0
- package/src/vercel/react/index.ts +13 -1
- package/src/vercel/react/use-chat-transport.ts +162 -42
- package/src/vercel/react/use-message-sync.ts +121 -22
- package/src/vercel/react/vite.config.ts +4 -2
- package/src/vercel/run-end-reason.ts +78 -0
- package/src/vercel/transport/chat-transport.ts +553 -113
- package/src/vercel/transport/index.ts +40 -28
- package/src/vercel/transport/run-output-stream.ts +170 -0
- package/src/version.ts +2 -0
- package/dist/core/transport/client-transport.d.ts +0 -10
- package/dist/core/transport/conversation-tree.d.ts +0 -9
- package/dist/core/transport/decode-history.d.ts +0 -41
- package/dist/core/transport/server-transport.d.ts +0 -7
- package/dist/core/transport/stream-router.d.ts +0 -19
- package/dist/core/transport/turn-manager.d.ts +0 -34
- package/dist/react/use-active-turns.d.ts +0 -8
- package/dist/react/use-client-transport.d.ts +0 -7
- package/dist/react/use-conversation-tree.d.ts +0 -20
- package/dist/react/use-edit.d.ts +0 -7
- package/dist/react/use-history.d.ts +0 -19
- package/dist/react/use-messages.d.ts +0 -7
- package/dist/react/use-regenerate.d.ts +0 -7
- package/dist/react/use-send.d.ts +0 -7
- package/dist/vercel/codec/accumulator.d.ts +0 -21
- package/src/core/transport/client-transport.ts +0 -959
- package/src/core/transport/conversation-tree.ts +0 -434
- package/src/core/transport/decode-history.ts +0 -337
- package/src/core/transport/server-transport.ts +0 -458
- package/src/core/transport/stream-router.ts +0 -118
- package/src/core/transport/turn-manager.ts +0 -147
- package/src/react/use-active-turns.ts +0 -61
- package/src/react/use-client-transport.ts +0 -37
- package/src/react/use-conversation-tree.ts +0 -71
- package/src/react/use-edit.ts +0 -24
- package/src/react/use-history.ts +0 -111
- package/src/react/use-messages.ts +0 -32
- package/src/react/use-regenerate.ts +0 -24
- package/src/react/use-send.ts +0 -25
- package/src/vercel/codec/accumulator.ts +0 -603
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Encoder core — message append lifecycle machinery.
|
|
3
3
|
*
|
|
4
|
-
* Provides Ably primitives (publish, append, close,
|
|
4
|
+
* Provides Ably primitives (publish, append, close, cancel, flush) that
|
|
5
5
|
* domain-specific encoders wire their event types to.
|
|
6
6
|
*
|
|
7
7
|
* Domain encoders call `createEncoderCore(writer, options)` and use the
|
|
@@ -11,7 +11,13 @@
|
|
|
11
11
|
|
|
12
12
|
import * as Ably from 'ably';
|
|
13
13
|
|
|
14
|
-
import {
|
|
14
|
+
import {
|
|
15
|
+
HEADER_CODEC_MESSAGE_ID,
|
|
16
|
+
HEADER_DISCRETE,
|
|
17
|
+
HEADER_STATUS,
|
|
18
|
+
HEADER_STREAM,
|
|
19
|
+
HEADER_STREAM_ID,
|
|
20
|
+
} from '../../constants.js';
|
|
15
21
|
import { ErrorCode } from '../../errors.js';
|
|
16
22
|
import type { Logger } from '../../logger.js';
|
|
17
23
|
import { mergeHeaders } from '../../utils.js';
|
|
@@ -36,8 +42,20 @@ interface StreamState {
|
|
|
36
42
|
name: string;
|
|
37
43
|
streamId: string;
|
|
38
44
|
accumulated: string;
|
|
39
|
-
|
|
40
|
-
|
|
45
|
+
/** Transport-tier headers repeated on every append (`extras.ai.transport`). */
|
|
46
|
+
persistentTransport: Record<string, string>;
|
|
47
|
+
/** Codec-tier headers repeated on every append (`extras.ai.codec`). */
|
|
48
|
+
persistentCodec: Record<string, string>;
|
|
49
|
+
cancelled: boolean;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* The SDK's `extras.ai` namespace as written to the wire: a `transport` tier
|
|
54
|
+
* (always present on SDK-published messages) and an optional `codec` tier.
|
|
55
|
+
*/
|
|
56
|
+
interface AiExtras {
|
|
57
|
+
transport: Record<string, string>;
|
|
58
|
+
codec?: Record<string, string>;
|
|
41
59
|
}
|
|
42
60
|
|
|
43
61
|
interface PendingAppend {
|
|
@@ -57,32 +75,35 @@ export interface EncoderCore {
|
|
|
57
75
|
/** Publish multiple discrete messages atomically in a single channel publish. */
|
|
58
76
|
publishDiscreteBatch(payloads: MessagePayload[], opts?: WriteOptions): Promise<Ably.PublishResult>;
|
|
59
77
|
|
|
60
|
-
/** Start a streamed message with
|
|
78
|
+
/** Start a streamed message with status:streaming. */
|
|
61
79
|
startStream(streamId: string, payload: StreamPayload, opts?: WriteOptions): Promise<void>;
|
|
62
80
|
|
|
63
81
|
/**
|
|
64
82
|
* Append data to an in-flight streamed message. Fire-and-forget: errors are
|
|
65
|
-
* collected internally and surfaced by {@link closeStream}
|
|
83
|
+
* collected internally and surfaced by {@link closeStream}, {@link cancelStream},
|
|
84
|
+
* {@link cancelAllStreams} or {@link close}.
|
|
85
|
+
* @throws {Ably.ErrorInfo} InvalidArgument if there is no active stream for `streamId` or the core is closed.
|
|
66
86
|
*/
|
|
67
87
|
appendStream(streamId: string, data: string): void;
|
|
68
88
|
|
|
69
89
|
/**
|
|
70
|
-
* Close a streamed message with
|
|
90
|
+
* Close a streamed message with status:complete. Flushes all pending
|
|
71
91
|
* appends for recovery before returning. Repeats persistent and payload headers.
|
|
92
|
+
* @throws {Ably.ErrorInfo} InvalidArgument if there is no active stream for `streamId`, or the encoder has been closed; EncoderRecoveryFailed if a failed append cannot be recovered during the flush.
|
|
72
93
|
*/
|
|
73
94
|
closeStream(streamId: string, payload: StreamPayload): Promise<void>;
|
|
74
95
|
|
|
75
96
|
/**
|
|
76
|
-
*
|
|
97
|
+
* Cancel a single in-progress stream (status:cancelled) and flush all
|
|
77
98
|
* pending appends for recovery before returning.
|
|
78
99
|
*/
|
|
79
|
-
|
|
100
|
+
cancelStream(streamId: string, opts?: WriteOptions): Promise<void>;
|
|
80
101
|
|
|
81
102
|
/**
|
|
82
|
-
*
|
|
103
|
+
* Cancel all in-progress streams (status:cancelled) and flush all
|
|
83
104
|
* pending appends for recovery before returning.
|
|
84
105
|
*/
|
|
85
|
-
|
|
106
|
+
cancelAllStreams(opts?: WriteOptions): Promise<void>;
|
|
86
107
|
|
|
87
108
|
/** Flush + clear trackers. Idempotent. */
|
|
88
109
|
close(): Promise<void>;
|
|
@@ -128,7 +149,7 @@ class DefaultEncoderCore implements EncoderCore {
|
|
|
128
149
|
async publishDiscreteBatch(payloads: MessagePayload[], opts?: WriteOptions): Promise<Ably.PublishResult> {
|
|
129
150
|
this._assertNotClosed();
|
|
130
151
|
this._logger?.trace('DefaultEncoderCore.publishDiscreteBatch();', { count: payloads.length });
|
|
131
|
-
const msgs = payloads.map((p) => this._buildDiscreteMessage(p, opts));
|
|
152
|
+
const msgs = payloads.map((p) => this._buildDiscreteMessage(p, opts, true));
|
|
132
153
|
return this._writer.publish(msgs);
|
|
133
154
|
}
|
|
134
155
|
|
|
@@ -137,16 +158,17 @@ class DefaultEncoderCore implements EncoderCore {
|
|
|
137
158
|
this._assertNotClosed();
|
|
138
159
|
this._logger?.trace('DefaultEncoderCore.startStream();', { name: payload.name, streamId });
|
|
139
160
|
|
|
140
|
-
const
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
161
|
+
const transport = this._buildTransport(payload.transportHeaders, opts);
|
|
162
|
+
transport[HEADER_STREAM] = 'true';
|
|
163
|
+
transport[HEADER_STATUS] = 'streaming';
|
|
164
|
+
transport[HEADER_STREAM_ID] = streamId;
|
|
165
|
+
const codec = payload.codecHeaders ?? {};
|
|
144
166
|
|
|
145
167
|
const clientId = this._resolveClientId(opts);
|
|
146
168
|
const msg: Ably.Message = {
|
|
147
169
|
name: payload.name,
|
|
148
170
|
data: payload.data,
|
|
149
|
-
extras: {
|
|
171
|
+
extras: { ai: this._aiExtras(transport, codec) },
|
|
150
172
|
...(clientId ? { clientId } : {}),
|
|
151
173
|
};
|
|
152
174
|
|
|
@@ -154,6 +176,7 @@ class DefaultEncoderCore implements EncoderCore {
|
|
|
154
176
|
const result = await this._writer.publish(msg);
|
|
155
177
|
const serial = result.serials[0];
|
|
156
178
|
|
|
179
|
+
// Spec: AIT-CD2a
|
|
157
180
|
if (!serial) {
|
|
158
181
|
throw new Ably.ErrorInfo(
|
|
159
182
|
`unable to start stream; no serial returned for stream '${payload.name}' (streamId: ${streamId})`,
|
|
@@ -167,8 +190,9 @@ class DefaultEncoderCore implements EncoderCore {
|
|
|
167
190
|
name: payload.name,
|
|
168
191
|
streamId,
|
|
169
192
|
accumulated: payload.data,
|
|
170
|
-
|
|
171
|
-
|
|
193
|
+
persistentTransport: transport,
|
|
194
|
+
persistentCodec: codec,
|
|
195
|
+
cancelled: false,
|
|
172
196
|
});
|
|
173
197
|
|
|
174
198
|
this._logger?.debug('DefaultEncoderCore.startStream(); stream started', {
|
|
@@ -181,6 +205,7 @@ class DefaultEncoderCore implements EncoderCore {
|
|
|
181
205
|
// Spec: AIT-CD3
|
|
182
206
|
appendStream(streamId: string, data: string): void {
|
|
183
207
|
this._assertNotClosed();
|
|
208
|
+
// Spec: AIT-CD3a
|
|
184
209
|
const tracker = this._trackers.get(streamId);
|
|
185
210
|
if (!tracker) {
|
|
186
211
|
throw new Ably.ErrorInfo(
|
|
@@ -195,7 +220,7 @@ class DefaultEncoderCore implements EncoderCore {
|
|
|
195
220
|
const appendMsg: Ably.Message = {
|
|
196
221
|
serial: tracker.serial,
|
|
197
222
|
data,
|
|
198
|
-
extras: {
|
|
223
|
+
extras: { ai: this._aiExtras({ ...tracker.persistentTransport }, { ...tracker.persistentCodec }) },
|
|
199
224
|
};
|
|
200
225
|
|
|
201
226
|
this._invokeOnMessage(appendMsg);
|
|
@@ -220,13 +245,13 @@ class DefaultEncoderCore implements EncoderCore {
|
|
|
220
245
|
// Accumulate closing data so recovery has the full content
|
|
221
246
|
tracker.accumulated += payload.data;
|
|
222
247
|
|
|
223
|
-
const
|
|
224
|
-
|
|
248
|
+
const { transport, codec } = this._buildClosing(tracker, payload);
|
|
249
|
+
transport[HEADER_STATUS] = 'complete';
|
|
225
250
|
|
|
226
251
|
const msg: Ably.Message = {
|
|
227
252
|
serial: tracker.serial,
|
|
228
253
|
data: payload.data,
|
|
229
|
-
extras: {
|
|
254
|
+
extras: { ai: this._aiExtras(transport, codec) },
|
|
230
255
|
};
|
|
231
256
|
|
|
232
257
|
this._invokeOnMessage(msg);
|
|
@@ -239,28 +264,28 @@ class DefaultEncoderCore implements EncoderCore {
|
|
|
239
264
|
}
|
|
240
265
|
|
|
241
266
|
// Spec: AIT-CD5, AIT-CD5b
|
|
242
|
-
async
|
|
267
|
+
async cancelStream(streamId: string, opts?: WriteOptions): Promise<void> {
|
|
243
268
|
this._assertNotClosed();
|
|
244
|
-
this._logger?.trace('DefaultEncoderCore.
|
|
269
|
+
this._logger?.trace('DefaultEncoderCore.cancelStream();', { streamId });
|
|
245
270
|
|
|
246
271
|
const tracker = this._trackers.get(streamId);
|
|
247
272
|
if (!tracker) {
|
|
248
273
|
throw new Ably.ErrorInfo(
|
|
249
|
-
`unable to
|
|
274
|
+
`unable to cancel stream; no active stream for streamId '${streamId}'`,
|
|
250
275
|
ErrorCode.InvalidArgument,
|
|
251
276
|
400,
|
|
252
277
|
);
|
|
253
278
|
}
|
|
254
279
|
|
|
255
|
-
tracker.
|
|
280
|
+
tracker.cancelled = true;
|
|
256
281
|
|
|
257
|
-
const
|
|
258
|
-
|
|
282
|
+
const { transport, codec } = this._buildClosing(tracker, undefined, opts);
|
|
283
|
+
transport[HEADER_STATUS] = 'cancelled';
|
|
259
284
|
|
|
260
285
|
const msg: Ably.Message = {
|
|
261
286
|
serial: tracker.serial,
|
|
262
287
|
data: '',
|
|
263
|
-
extras: {
|
|
288
|
+
extras: { ai: this._aiExtras(transport, codec) },
|
|
264
289
|
};
|
|
265
290
|
|
|
266
291
|
this._invokeOnMessage(msg);
|
|
@@ -269,24 +294,24 @@ class DefaultEncoderCore implements EncoderCore {
|
|
|
269
294
|
|
|
270
295
|
await this._flushPending();
|
|
271
296
|
|
|
272
|
-
this._logger?.debug('DefaultEncoderCore.
|
|
297
|
+
this._logger?.debug('DefaultEncoderCore.cancelStream(); stream cancelled', { streamId });
|
|
273
298
|
}
|
|
274
299
|
|
|
275
300
|
// Spec: AIT-CD5a
|
|
276
|
-
async
|
|
301
|
+
async cancelAllStreams(opts?: WriteOptions): Promise<void> {
|
|
277
302
|
this._assertNotClosed();
|
|
278
|
-
this._logger?.trace('DefaultEncoderCore.
|
|
303
|
+
this._logger?.trace('DefaultEncoderCore.cancelAllStreams();', { streamCount: this._trackers.size });
|
|
279
304
|
|
|
280
305
|
for (const tracker of this._trackers.values()) {
|
|
281
|
-
tracker.
|
|
306
|
+
tracker.cancelled = true;
|
|
282
307
|
|
|
283
|
-
const
|
|
284
|
-
|
|
308
|
+
const { transport, codec } = this._buildClosing(tracker, undefined, opts);
|
|
309
|
+
transport[HEADER_STATUS] = 'cancelled';
|
|
285
310
|
|
|
286
311
|
const msg: Ably.Message = {
|
|
287
312
|
serial: tracker.serial,
|
|
288
313
|
data: '',
|
|
289
|
-
extras: {
|
|
314
|
+
extras: { ai: this._aiExtras(transport, codec) },
|
|
290
315
|
};
|
|
291
316
|
|
|
292
317
|
this._invokeOnMessage(msg);
|
|
@@ -345,11 +370,16 @@ class DefaultEncoderCore implements EncoderCore {
|
|
|
345
370
|
const tracker = this._trackers.get(streamId);
|
|
346
371
|
if (!tracker) continue;
|
|
347
372
|
|
|
348
|
-
const recoveryStatus = tracker.
|
|
373
|
+
const recoveryStatus = tracker.cancelled ? 'cancelled' : 'complete';
|
|
349
374
|
const msg: Ably.Message = {
|
|
350
375
|
serial: tracker.serial,
|
|
351
376
|
data: tracker.accumulated,
|
|
352
|
-
extras: {
|
|
377
|
+
extras: {
|
|
378
|
+
ai: this._aiExtras(
|
|
379
|
+
{ ...tracker.persistentTransport, [HEADER_STATUS]: recoveryStatus },
|
|
380
|
+
{ ...tracker.persistentCodec },
|
|
381
|
+
),
|
|
382
|
+
},
|
|
353
383
|
};
|
|
354
384
|
|
|
355
385
|
try {
|
|
@@ -406,25 +436,53 @@ class DefaultEncoderCore implements EncoderCore {
|
|
|
406
436
|
return opts?.clientId ?? this._defaultClientId;
|
|
407
437
|
}
|
|
408
438
|
|
|
409
|
-
|
|
439
|
+
/**
|
|
440
|
+
* Build the transport-tier header record for a message: caller-configured
|
|
441
|
+
* transport headers (default extras + per-write overrides) layered with any
|
|
442
|
+
* transport headers the codec payload stamps directly, plus the message-id.
|
|
443
|
+
* @param payloadTransport - Transport headers carried on the codec payload.
|
|
444
|
+
* @param opts - Optional per-write overrides.
|
|
445
|
+
* @returns The transport-tier headers record (`extras.ai.transport`).
|
|
446
|
+
*/
|
|
447
|
+
private _buildTransport(
|
|
448
|
+
payloadTransport: Record<string, string> | undefined,
|
|
449
|
+
opts?: WriteOptions,
|
|
450
|
+
): Record<string, string> {
|
|
410
451
|
const callerHeaders = mergeHeaders(this._defaultExtras?.headers, opts?.extras?.headers);
|
|
411
|
-
const
|
|
452
|
+
const transport = { ...callerHeaders, ...payloadTransport };
|
|
412
453
|
if (opts?.messageId !== undefined) {
|
|
413
|
-
|
|
454
|
+
transport[HEADER_CODEC_MESSAGE_ID] = opts.messageId;
|
|
414
455
|
}
|
|
415
|
-
return
|
|
456
|
+
return transport;
|
|
416
457
|
}
|
|
417
458
|
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
459
|
+
/**
|
|
460
|
+
* Assemble the `extras.ai` namespace from its two tiers, omitting the codec
|
|
461
|
+
* tier when empty.
|
|
462
|
+
* @param transport - Transport-tier headers (always present on SDK messages).
|
|
463
|
+
* @param codec - Codec-tier headers; omitted from the wire when empty.
|
|
464
|
+
* @returns The `extras.ai` object.
|
|
465
|
+
*/
|
|
466
|
+
private _aiExtras(transport: Record<string, string>, codec: Record<string, string>): AiExtras {
|
|
467
|
+
return Object.keys(codec).length > 0 ? { transport, codec } : { transport };
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
private _buildDiscreteMessage(payload: MessagePayload, opts?: WriteOptions, discrete = false): Ably.Message {
|
|
471
|
+
const transport = this._buildTransport(payload.transportHeaders, opts);
|
|
472
|
+
transport[HEADER_STREAM] = 'false';
|
|
473
|
+
if (discrete) {
|
|
474
|
+
// Mark batch-published payloads as discrete message parts (from writeMessages).
|
|
475
|
+
// The decoder relies on this header to distinguish message parts from lifecycle
|
|
476
|
+
// events that also happen to be discrete (stream: false).
|
|
477
|
+
transport[HEADER_DISCRETE] = 'true';
|
|
478
|
+
}
|
|
421
479
|
const clientId = this._resolveClientId(opts);
|
|
422
480
|
|
|
423
481
|
const msg: Ably.Message = {
|
|
424
482
|
name: payload.name,
|
|
425
483
|
data: payload.data,
|
|
426
484
|
extras: {
|
|
427
|
-
|
|
485
|
+
ai: this._aiExtras(transport, payload.codecHeaders ?? {}),
|
|
428
486
|
...(payload.ephemeral ? { ephemeral: true } : {}),
|
|
429
487
|
},
|
|
430
488
|
...(clientId ? { clientId } : {}),
|
|
@@ -435,24 +493,23 @@ class DefaultEncoderCore implements EncoderCore {
|
|
|
435
493
|
}
|
|
436
494
|
|
|
437
495
|
/**
|
|
438
|
-
* Build
|
|
439
|
-
* persistent headers (Ably replaces the entire extras object on append).
|
|
496
|
+
* Build both header tiers for a closing append. Closing appends must repeat
|
|
497
|
+
* ALL persistent headers (Ably replaces the entire extras object on append).
|
|
440
498
|
* Then layer caller and codec overrides.
|
|
441
499
|
* @param tracker - The stream tracker with persistent headers.
|
|
442
|
-
* @param
|
|
500
|
+
* @param payload - The closing stream payload (codec + transport headers).
|
|
443
501
|
* @param opts - Optional per-write overrides.
|
|
444
|
-
* @returns
|
|
502
|
+
* @returns The two tiers for the closing append.
|
|
445
503
|
*/
|
|
446
|
-
private
|
|
504
|
+
private _buildClosing(
|
|
447
505
|
tracker: StreamState,
|
|
448
|
-
|
|
506
|
+
payload: StreamPayload | undefined,
|
|
449
507
|
opts?: WriteOptions,
|
|
450
|
-
): Record<string, string> {
|
|
451
|
-
const h = { ...tracker.persistentHeaders };
|
|
508
|
+
): { transport: Record<string, string>; codec: Record<string, string> } {
|
|
452
509
|
const callerHeaders = mergeHeaders(this._defaultExtras?.headers, opts?.extras?.headers);
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
return
|
|
510
|
+
const transport = { ...tracker.persistentTransport, ...callerHeaders, ...payload?.transportHeaders };
|
|
511
|
+
const codec = { ...tracker.persistentCodec, ...payload?.codecHeaders };
|
|
512
|
+
return { transport, codec };
|
|
456
513
|
}
|
|
457
514
|
}
|
|
458
515
|
|
package/src/core/codec/index.ts
CHANGED
|
@@ -1,17 +1,24 @@
|
|
|
1
|
-
export { eventOutput } from './decoder.js';
|
|
2
1
|
export type {
|
|
3
2
|
ChannelWriter,
|
|
4
3
|
Codec,
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
CodecInputEvent,
|
|
5
|
+
CodecMessage,
|
|
6
|
+
CodecOutputEvent,
|
|
7
|
+
DecodedMessage,
|
|
8
|
+
Decoder,
|
|
9
|
+
Encoder,
|
|
7
10
|
EncoderOptions,
|
|
8
11
|
Extras,
|
|
9
|
-
MessageAccumulator,
|
|
10
12
|
MessagePayload,
|
|
11
|
-
|
|
12
|
-
|
|
13
|
+
Reducer,
|
|
14
|
+
ReducerMeta,
|
|
15
|
+
Regenerate,
|
|
13
16
|
StreamPayload,
|
|
14
17
|
StreamTrackerState,
|
|
18
|
+
ToolApprovalResponse,
|
|
19
|
+
ToolResult,
|
|
20
|
+
ToolResultError,
|
|
21
|
+
UserMessage,
|
|
15
22
|
WriteOptions,
|
|
16
23
|
} from './types.js';
|
|
17
24
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Generic lifecycle tracker for codec decoders.
|
|
3
3
|
*
|
|
4
|
-
* Manages per-scope (typically per-
|
|
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.
|
|
@@ -40,15 +40,16 @@ export interface PhaseConfig<TEvent> {
|
|
|
40
40
|
* Per-scope lifecycle tracker that ensures required phases are emitted
|
|
41
41
|
* before content events, synthesizing missing ones for mid-stream joins.
|
|
42
42
|
*
|
|
43
|
-
* Scoped by an arbitrary string key (typically a
|
|
43
|
+
* Scoped by an arbitrary string key (typically a run ID). Each scope
|
|
44
44
|
* tracks independently which phases have been emitted.
|
|
45
45
|
*/
|
|
46
46
|
export interface LifecycleTracker<TEvent> {
|
|
47
47
|
/**
|
|
48
48
|
* Ensure all configured phases have been emitted for the given scope.
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
49
|
+
* Synthesizes and returns the events for any phases not yet marked as
|
|
50
|
+
* emitted, marking each as emitted so it is not synthesized again.
|
|
51
|
+
* Returns an empty array if all phases are already emitted.
|
|
52
|
+
* @param scopeId - The scope to check (e.g. run ID).
|
|
52
53
|
* @param context - Key-value pairs passed through to phase build functions.
|
|
53
54
|
* @returns Synthetic events for missing phases, in configuration order.
|
|
54
55
|
*/
|
|
@@ -57,7 +58,7 @@ export interface LifecycleTracker<TEvent> {
|
|
|
57
58
|
/**
|
|
58
59
|
* Mark a phase as emitted from the wire (not synthetic). Call this
|
|
59
60
|
* when the real event arrives so the tracker does not re-synthesize it.
|
|
60
|
-
* @param scopeId - The scope (e.g.
|
|
61
|
+
* @param scopeId - The scope (e.g. run ID).
|
|
61
62
|
* @param phaseKey - The phase key to mark.
|
|
62
63
|
*/
|
|
63
64
|
markEmitted(scopeId: string, phaseKey: string): void;
|
|
@@ -66,14 +67,14 @@ export interface LifecycleTracker<TEvent> {
|
|
|
66
67
|
* Reset a phase so it will be re-synthesized on the next
|
|
67
68
|
* {@link ensurePhases} call. Used for repeating phases (e.g. "start-step"
|
|
68
69
|
* resets after "finish-step").
|
|
69
|
-
* @param scopeId - The scope (e.g.
|
|
70
|
+
* @param scopeId - The scope (e.g. run ID).
|
|
70
71
|
* @param phaseKey - The phase key to reset.
|
|
71
72
|
*/
|
|
72
73
|
resetPhase(scopeId: string, phaseKey: string): void;
|
|
73
74
|
|
|
74
75
|
/**
|
|
75
|
-
* Remove all tracking state for a scope. Call on
|
|
76
|
-
* (finish,
|
|
76
|
+
* Remove all tracking state for a scope. Call on run completion
|
|
77
|
+
* (finish, cancel) to free memory.
|
|
77
78
|
* @param scopeId - The scope to clear.
|
|
78
79
|
*/
|
|
79
80
|
clearScope(scopeId: string): void;
|