@ably/ai-transport 0.2.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.
- package/README.md +10 -19
- package/dist/ably-ai-transport.js +1790 -1091
- 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 +2 -2
- package/dist/core/agent.d.ts +20 -5
- package/dist/core/channel-options.d.ts +57 -0
- package/dist/core/codec/codec-event.d.ts +9 -0
- package/dist/core/codec/decoder.d.ts +4 -1
- package/dist/core/codec/define-codec.d.ts +100 -0
- package/dist/core/codec/encoder.d.ts +2 -7
- package/dist/core/codec/field-bag.d.ts +85 -0
- package/dist/core/codec/fields.d.ts +141 -0
- package/dist/core/codec/index.d.ts +8 -1
- package/dist/core/codec/input-descriptor-decoder.d.ts +19 -0
- package/dist/core/codec/input-descriptor-encoder.d.ts +22 -0
- package/dist/core/codec/input-descriptors.d.ts +281 -0
- package/dist/core/codec/output-descriptor-decoder.d.ts +29 -0
- package/dist/core/codec/output-descriptor-encoder.d.ts +31 -0
- package/dist/core/codec/output-descriptors.d.ts +237 -0
- package/dist/core/codec/types.d.ts +95 -36
- package/dist/core/codec/well-known-inputs.d.ts +52 -0
- package/dist/core/transport/agent-view.d.ts +296 -0
- package/dist/core/transport/decode-fold.d.ts +40 -32
- package/dist/core/transport/headers.d.ts +30 -1
- package/dist/core/transport/index.d.ts +1 -1
- package/dist/core/transport/invocation.d.ts +1 -1
- package/dist/core/transport/load-history-pages.d.ts +71 -0
- package/dist/core/transport/load-history.d.ts +21 -16
- package/dist/core/transport/run-manager.d.ts +9 -11
- package/dist/core/transport/session-support.d.ts +55 -0
- package/dist/core/transport/tree.d.ts +165 -15
- package/dist/core/transport/types/agent.d.ts +120 -98
- package/dist/core/transport/types/client.d.ts +45 -12
- package/dist/core/transport/types/tree.d.ts +52 -10
- package/dist/core/transport/types/view.d.ts +55 -28
- package/dist/core/transport/view.d.ts +176 -58
- package/dist/core/transport/wire-log.d.ts +102 -0
- package/dist/errors.d.ts +10 -4
- package/dist/index.d.ts +6 -5
- package/dist/react/ably-ai-transport-react.js +784 -415
- 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 +2 -1
- package/dist/react/contexts/client-session-provider.d.ts +3 -0
- package/dist/react/index.d.ts +2 -1
- package/dist/react/internal/skipped-session.d.ts +8 -0
- package/dist/react/use-view.d.ts +3 -3
- package/dist/utils.d.ts +22 -54
- package/dist/vercel/ably-ai-transport-vercel.js +2297 -2026
- 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/decode-lifecycle.d.ts +9 -0
- package/dist/vercel/codec/events.d.ts +1 -2
- package/dist/vercel/codec/fields.d.ts +44 -0
- package/dist/vercel/codec/fold-content.d.ts +16 -0
- package/dist/vercel/codec/fold-data.d.ts +16 -0
- package/dist/vercel/codec/fold-input.d.ts +67 -0
- package/dist/vercel/codec/fold-lifecycle.d.ts +16 -0
- package/dist/vercel/codec/fold-text.d.ts +16 -0
- package/dist/vercel/codec/fold-tool-input.d.ts +17 -0
- package/dist/vercel/codec/fold-tool-output.d.ts +16 -0
- package/dist/vercel/codec/index.d.ts +5 -30
- package/dist/vercel/codec/inputs.d.ts +11 -0
- package/dist/vercel/codec/outputs.d.ts +11 -0
- package/dist/vercel/codec/reducer-state.d.ts +121 -0
- package/dist/vercel/codec/reducer.d.ts +20 -102
- package/dist/vercel/codec/tool-transitions.d.ts +0 -6
- package/dist/vercel/codec/wire-data.d.ts +34 -0
- package/dist/vercel/index.d.ts +1 -0
- package/dist/vercel/react/ably-ai-transport-vercel-react.js +2013 -9500
- package/dist/vercel/react/ably-ai-transport-vercel-react.js.map +1 -1
- package/dist/vercel/react/ably-ai-transport-vercel-react.umd.cjs +1 -70
- package/dist/vercel/react/ably-ai-transport-vercel-react.umd.cjs.map +1 -1
- package/dist/vercel/react/contexts/chat-transport-context.d.ts +2 -1
- package/dist/vercel/run-end-reason.d.ts +66 -11
- package/dist/vercel/tool-part.d.ts +21 -0
- package/dist/vercel/transport/chat-transport.d.ts +0 -2
- package/dist/vercel/transport/index.d.ts +1 -1
- package/dist/vercel/transport/run-output-stream.d.ts +6 -8
- package/dist/version.d.ts +1 -1
- package/package.json +2 -2
- package/src/constants.ts +2 -2
- package/src/core/agent.ts +43 -19
- package/src/core/channel-options.ts +89 -0
- package/src/core/codec/codec-event.ts +27 -0
- package/src/core/codec/decoder.ts +145 -21
- package/src/core/codec/define-codec.ts +432 -0
- package/src/core/codec/encoder.ts +13 -54
- package/src/core/codec/field-bag.ts +142 -0
- package/src/core/codec/fields.ts +193 -0
- package/src/core/codec/index.ts +43 -0
- package/src/core/codec/input-descriptor-decoder.ts +97 -0
- package/src/core/codec/input-descriptor-encoder.ts +150 -0
- package/src/core/codec/input-descriptors.ts +373 -0
- package/src/core/codec/output-descriptor-decoder.ts +139 -0
- package/src/core/codec/output-descriptor-encoder.ts +101 -0
- package/src/core/codec/output-descriptors.ts +307 -0
- package/src/core/codec/types.ts +99 -36
- package/src/core/codec/well-known-inputs.ts +96 -0
- package/src/core/transport/agent-session.ts +330 -589
- package/src/core/transport/agent-view.ts +738 -0
- package/src/core/transport/client-session.ts +74 -69
- package/src/core/transport/decode-fold.ts +57 -47
- package/src/core/transport/headers.ts +57 -4
- package/src/core/transport/index.ts +2 -1
- package/src/core/transport/invocation.ts +1 -1
- package/src/core/transport/load-history-pages.ts +220 -0
- package/src/core/transport/load-history.ts +63 -61
- package/src/core/transport/pipe-stream.ts +10 -1
- package/src/core/transport/run-manager.ts +25 -31
- package/src/core/transport/session-support.ts +96 -0
- package/src/core/transport/tree.ts +414 -47
- package/src/core/transport/types/agent.ts +129 -102
- package/src/core/transport/types/client.ts +49 -13
- package/src/core/transport/types/tree.ts +61 -12
- package/src/core/transport/types/view.ts +57 -28
- package/src/core/transport/view.ts +520 -172
- package/src/core/transport/wire-log.ts +189 -0
- package/src/errors.ts +10 -3
- package/src/index.ts +44 -11
- package/src/react/contexts/client-session-context.ts +1 -1
- package/src/react/contexts/client-session-provider.tsx +38 -2
- package/src/react/index.ts +2 -1
- package/src/react/internal/skipped-session.ts +62 -0
- package/src/react/use-client-session.ts +7 -30
- package/src/react/use-view.ts +3 -3
- package/src/utils.ts +31 -97
- package/src/vercel/codec/decode-lifecycle.ts +70 -0
- package/src/vercel/codec/events.ts +1 -3
- package/src/vercel/codec/fields.ts +58 -0
- package/src/vercel/codec/fold-content.ts +54 -0
- package/src/vercel/codec/fold-data.ts +46 -0
- package/src/vercel/codec/fold-input.ts +255 -0
- package/src/vercel/codec/fold-lifecycle.ts +85 -0
- package/src/vercel/codec/fold-text.ts +55 -0
- package/src/vercel/codec/fold-tool-input.ts +86 -0
- package/src/vercel/codec/fold-tool-output.ts +79 -0
- package/src/vercel/codec/index.ts +23 -63
- package/src/vercel/codec/inputs.ts +116 -0
- package/src/vercel/codec/outputs.ts +207 -0
- package/src/vercel/codec/reducer-state.ts +169 -0
- package/src/vercel/codec/reducer.ts +52 -838
- package/src/vercel/codec/tool-transitions.ts +1 -12
- package/src/vercel/codec/wire-data.ts +64 -0
- package/src/vercel/index.ts +1 -0
- package/src/vercel/react/contexts/chat-transport-context.ts +1 -1
- package/src/vercel/react/use-chat-transport.ts +8 -28
- package/src/vercel/react/use-message-sync.ts +5 -10
- package/src/vercel/run-end-reason.ts +95 -16
- package/src/vercel/tool-part.ts +25 -0
- package/src/vercel/transport/chat-transport.ts +10 -22
- package/src/vercel/transport/index.ts +1 -1
- package/src/vercel/transport/run-output-stream.ts +7 -8
- package/src/version.ts +1 -1
- package/dist/core/transport/branch-chain.d.ts +0 -43
- package/dist/core/transport/load-conversation.d.ts +0 -128
- package/dist/vercel/codec/decoder.d.ts +0 -9
- package/dist/vercel/codec/encoder.d.ts +0 -11
- package/src/core/transport/branch-chain.ts +0 -58
- package/src/core/transport/load-conversation.ts +0 -355
- package/src/vercel/codec/decoder.ts +0 -696
- package/src/vercel/codec/encoder.ts +0 -548
|
@@ -29,8 +29,6 @@ export interface Extras {
|
|
|
29
29
|
}
|
|
30
30
|
/** Per-write overrides for encoder operations. */
|
|
31
31
|
export interface WriteOptions {
|
|
32
|
-
/** Override the default clientId for this write. */
|
|
33
|
-
clientId?: string;
|
|
34
32
|
/** Override the default extras for this write. */
|
|
35
33
|
extras?: Extras;
|
|
36
34
|
/** Message identity for projection routing. Stamped as `codec-message-id`. */
|
|
@@ -39,7 +37,7 @@ export interface WriteOptions {
|
|
|
39
37
|
/**
|
|
40
38
|
* A codec-agnostic description of a discrete Ably message. Used on both sides:
|
|
41
39
|
* - **Encode:** the domain encoder describes what to publish; the encoder core
|
|
42
|
-
* handles header merging
|
|
40
|
+
* handles header merging and the actual publish.
|
|
43
41
|
* - **Decode:** the decoder core extracts these fields from an
|
|
44
42
|
* `Ably.InboundMessage` before calling domain hooks, keeping hooks free of
|
|
45
43
|
* Ably SDK types.
|
|
@@ -48,7 +46,7 @@ export interface WriteOptions {
|
|
|
48
46
|
* (strings, objects, etc.) — Ably handles serialization natively.
|
|
49
47
|
*/
|
|
50
48
|
export interface MessagePayload {
|
|
51
|
-
/** Ably message name (
|
|
49
|
+
/** Ably message name — the wire direction (`ai-output` / `ai-input`). */
|
|
52
50
|
name: string;
|
|
53
51
|
/** Message data. Ably handles serialization — strings, objects, and arrays are all valid. */
|
|
54
52
|
data: unknown;
|
|
@@ -69,7 +67,7 @@ export interface MessagePayload {
|
|
|
69
67
|
* concatenated for recovery and prefix-matching on the decoder.
|
|
70
68
|
*/
|
|
71
69
|
export interface StreamPayload {
|
|
72
|
-
/** Ably message name (
|
|
70
|
+
/** Ably message name — `ai-output` (only outputs stream); not the codec `kind` / stream family. */
|
|
73
71
|
name: string;
|
|
74
72
|
/** Initial or closing data for the stream. Must be a string for append/accumulate semantics. */
|
|
75
73
|
data: string;
|
|
@@ -86,7 +84,7 @@ export interface StreamPayload {
|
|
|
86
84
|
* Accumulates text across appends and tracks lifecycle (open/closed).
|
|
87
85
|
*/
|
|
88
86
|
export interface StreamTrackerState {
|
|
89
|
-
/** Ably message name (
|
|
87
|
+
/** Ably message name — `ai-output` (only outputs stream); not the codec `kind` / stream family. */
|
|
90
88
|
name: string;
|
|
91
89
|
/** Stream identifier (e.g. chunk.id for text, toolCallId for tool-input). */
|
|
92
90
|
streamId: string;
|
|
@@ -102,6 +100,16 @@ export interface StreamTrackerState {
|
|
|
102
100
|
* Initially set from the first publish, but may be replaced on update.
|
|
103
101
|
*/
|
|
104
102
|
transportHeaders: Record<string, string>;
|
|
103
|
+
/**
|
|
104
|
+
* Highest `Message.version.serial` incorporated into this tracker.
|
|
105
|
+
* Versions are lexicographically comparable within one message serial, so
|
|
106
|
+
* a delivery carrying a version at or below this value is already
|
|
107
|
+
* incorporated and decodes to nothing. Stamped at first contact (a
|
|
108
|
+
* never-mutated message's version serial equals the message serial, which
|
|
109
|
+
* is also the fallback when the version carries no serial) and advanced by
|
|
110
|
+
* each version-bearing delivery.
|
|
111
|
+
*/
|
|
112
|
+
version: string;
|
|
105
113
|
/** Whether this stream has been closed (complete or cancelled). */
|
|
106
114
|
closed: boolean;
|
|
107
115
|
}
|
|
@@ -111,9 +119,12 @@ export interface StreamTrackerState {
|
|
|
111
119
|
*/
|
|
112
120
|
export interface ReducerMeta {
|
|
113
121
|
/**
|
|
114
|
-
* Ably channel serial of the message that produced this event
|
|
115
|
-
*
|
|
116
|
-
*
|
|
122
|
+
* Ably channel serial of the wire message that produced this event, or `''`
|
|
123
|
+
* for a not-yet-sequenced optimistic (local) fold. Ordering context only:
|
|
124
|
+
* the transport invokes `fold` in canonical serial order and exactly once
|
|
125
|
+
* per event, so the reducer must not treat a same-or-lower serial as a
|
|
126
|
+
* replay to skip — ordering and dedup are the transport's job, not the
|
|
127
|
+
* reducer's.
|
|
117
128
|
*/
|
|
118
129
|
serial: string;
|
|
119
130
|
/**
|
|
@@ -129,9 +140,14 @@ export interface ReducerMeta {
|
|
|
129
140
|
* result every time — `fold` is a pure function and the reducer holds no
|
|
130
141
|
* instance state.
|
|
131
142
|
*
|
|
132
|
-
*
|
|
133
|
-
*
|
|
134
|
-
*
|
|
143
|
+
* Ordering, deduplication, and replay are the transport's responsibility, not
|
|
144
|
+
* the reducer's. The transport invokes `fold` exactly once per event, in
|
|
145
|
+
* canonical order — wire messages ascending by serial, events within a wire in
|
|
146
|
+
* decode order — refolding a node from a fresh `init` when a late wire would
|
|
147
|
+
* otherwise land out of order. The reducer therefore folds unconditionally: it
|
|
148
|
+
* must not keep a serial high-water-mark or skip "already-seen" events.
|
|
149
|
+
* Last-writer-wins for events competing over the same state falls out of fold
|
|
150
|
+
* order, since the highest-serial event folds last.
|
|
135
151
|
*
|
|
136
152
|
* Mutation: `fold` is allowed to mutate the projection passed in and return
|
|
137
153
|
* it. The caller treats the projection as single-owner and never retains a
|
|
@@ -141,26 +157,48 @@ export interface Reducer<TEvent, TProjection> {
|
|
|
141
157
|
/**
|
|
142
158
|
* Build an empty initial projection. Called once per conversation node — a
|
|
143
159
|
* Run node or a run-less input node — before any of that node's events are
|
|
144
|
-
* folded.
|
|
160
|
+
* folded, and again on every refold of that node.
|
|
145
161
|
*/
|
|
146
162
|
init(): TProjection;
|
|
147
163
|
/**
|
|
148
164
|
* Fold one TEvent into the projection and return the updated projection.
|
|
149
|
-
*
|
|
165
|
+
* Invoked exactly once per event, in canonical order; the reducer may mutate
|
|
166
|
+
* `state` in place.
|
|
150
167
|
*/
|
|
151
168
|
fold(state: TProjection, event: TEvent, meta: ReducerMeta): TProjection;
|
|
152
169
|
}
|
|
170
|
+
/**
|
|
171
|
+
* A decoded event tagged with the wire direction it arrived on. The reducer
|
|
172
|
+
* folds this union (not a bare `TInput | TOutput`) so it can dispatch on
|
|
173
|
+
* `direction` rather than inspecting the event's shape. Direction is derived
|
|
174
|
+
* once, from the Ably message name, at decode time (see `toCodecEvents`) — the
|
|
175
|
+
* authoritative signal, since a single message is either `ai-input` or
|
|
176
|
+
* `ai-output` but never both.
|
|
177
|
+
* @template TInput - The codec's input union.
|
|
178
|
+
* @template TOutput - The codec's output union.
|
|
179
|
+
*/
|
|
180
|
+
export type CodecEvent<TInput, TOutput> = {
|
|
181
|
+
/** The event arrived on the `ai-input` wire. */
|
|
182
|
+
readonly direction: 'input';
|
|
183
|
+
/** The decoded input event. */
|
|
184
|
+
readonly event: TInput;
|
|
185
|
+
} | {
|
|
186
|
+
/** The event arrived on the `ai-output` wire. */
|
|
187
|
+
readonly direction: 'output';
|
|
188
|
+
/** The decoded output event. */
|
|
189
|
+
readonly event: TOutput;
|
|
190
|
+
};
|
|
153
191
|
/** Options passed to a codec's `createEncoder` factory. */
|
|
154
192
|
export interface EncoderOptions {
|
|
155
|
-
/** Default clientId for all writes. */
|
|
156
|
-
clientId?: string;
|
|
157
193
|
/** Default extras (e.g. headers) merged into every Ably message. */
|
|
158
194
|
extras?: Extras;
|
|
159
195
|
/** Hook called before each Ably message is published. Mutate the message in place to add transport-level headers under `extras.ai`. */
|
|
160
196
|
onMessage?: (message: Ably.Message) => void;
|
|
161
197
|
/**
|
|
162
|
-
*
|
|
163
|
-
*
|
|
198
|
+
* Fallback domain message id surfaced to output escape hatches as
|
|
199
|
+
* `ctx.messageId` (e.g. the Vercel `start` hatch injects it when a chunk
|
|
200
|
+
* carries no `messageId` of its own). Unrelated to the wire
|
|
201
|
+
* codec-message-id transport header, which `WriteOptions.messageId` stamps.
|
|
164
202
|
*/
|
|
165
203
|
messageId?: string;
|
|
166
204
|
}
|
|
@@ -174,24 +212,24 @@ export interface EncoderOptions {
|
|
|
174
212
|
export interface Encoder<TInput extends CodecInputEvent, TOutput extends CodecOutputEvent> {
|
|
175
213
|
/**
|
|
176
214
|
* Encode and publish a single client input on the `ai-input` wire.
|
|
177
|
-
*
|
|
215
|
+
* Rejects if the codec cannot encode the given input
|
|
178
216
|
* variant.
|
|
179
217
|
*/
|
|
180
218
|
publishInput(input: TInput, options?: WriteOptions): Promise<void>;
|
|
181
219
|
/**
|
|
182
220
|
* Encode and publish a single agent output on the `ai-output` wire.
|
|
183
|
-
*
|
|
221
|
+
* Rejects if the codec cannot encode the given output
|
|
184
222
|
* variant.
|
|
185
223
|
*/
|
|
186
224
|
publishOutput(output: TOutput, options?: WriteOptions): Promise<void>;
|
|
187
225
|
/**
|
|
188
|
-
*
|
|
189
|
-
*
|
|
190
|
-
*
|
|
191
|
-
* closed.
|
|
192
|
-
*
|
|
226
|
+
* Close all in-progress streamed messages as cancelled (status:cancelled) and
|
|
227
|
+
* flush pending appends. Pure transport mechanics — emits no codec output.
|
|
228
|
+
* Idempotent: streams already cancelled are not re-appended. Must not be
|
|
229
|
+
* called after `close`; doing so throws because the encoder is already closed.
|
|
230
|
+
* Run termination is signalled separately by the transport `ai-run-end` event.
|
|
193
231
|
*/
|
|
194
|
-
|
|
232
|
+
cancelStreams(): Promise<void>;
|
|
195
233
|
/** Flush pending appends and release encoder resources. */
|
|
196
234
|
close(): Promise<void>;
|
|
197
235
|
}
|
|
@@ -212,6 +250,12 @@ export interface DecodedMessage<TInput extends CodecInputEvent, TOutput extends
|
|
|
212
250
|
* compaction, partial-history page boundary, rewind miss) synthesizes any
|
|
213
251
|
* missing start events before deltas reach the SDK — the reducer always
|
|
214
252
|
* sees a clean `(start, delta*, end)` sequence.
|
|
253
|
+
*
|
|
254
|
+
* Trackers are version-guarded: a delivery whose `Message.version.serial`
|
|
255
|
+
* is at or below the version already incorporated decodes to nothing. One
|
|
256
|
+
* decoder instance can therefore be shared by the live subscription and
|
|
257
|
+
* history hydration — whichever route delivers a message's content first
|
|
258
|
+
* wins, and the other route's covered deliveries are no-ops.
|
|
215
259
|
*/
|
|
216
260
|
export interface Decoder<TInput extends CodecInputEvent, TOutput extends CodecOutputEvent> {
|
|
217
261
|
/** Decode one Ably inbound message into the input/output halves. */
|
|
@@ -246,10 +290,11 @@ export interface CodecInputEvent {
|
|
|
246
290
|
* Pointer to another codec-message this input references. The semantic
|
|
247
291
|
* depends on `kind` — for `regenerate`, the assistant codec-message to
|
|
248
292
|
* regenerate; codec-specific `kind`s may give it other meanings. The
|
|
249
|
-
* input event itself does not create a fork — it requests one
|
|
293
|
+
* input event itself does not create a fork — it requests one: the
|
|
294
|
+
* transport reads `target` off the input (e.g. the client session maps a
|
|
295
|
+
* regenerate's target into its transport headers) and the fork
|
|
250
296
|
* relationship is established on the agent's response (and on
|
|
251
|
-
* `ai-run-start`)
|
|
252
|
-
* wire's `fork-of` header.
|
|
297
|
+
* `ai-run-start`).
|
|
253
298
|
*/
|
|
254
299
|
target?: string;
|
|
255
300
|
/**
|
|
@@ -300,7 +345,7 @@ export interface Regenerate extends CodecInputEvent {
|
|
|
300
345
|
* The core is domain-independent: it knows only that this input amends the
|
|
301
346
|
* assistant at `codecMessageId` and carries a codec-defined `payload`. The
|
|
302
347
|
* shape of `payload` (e.g. the tool-call id and output value) is supplied
|
|
303
|
-
* by the codec via `TPayload`
|
|
348
|
+
* by the codec via `TPayload` (e.g. a tool-call id and output value).
|
|
304
349
|
*
|
|
305
350
|
* Codecs opt in to client-side tool resolution by including this variant
|
|
306
351
|
* in their `TInput` union. Codecs whose domain model doesn't natively
|
|
@@ -322,7 +367,7 @@ export interface ToolResult<TPayload> extends CodecInputEvent {
|
|
|
322
367
|
* Well-known input variant: client-published tool result (failure). The
|
|
323
368
|
* tool ran and failed. Mutates the assistant codec-message addressed by
|
|
324
369
|
* `codecMessageId`. The failure detail (e.g. tool-call id and error text)
|
|
325
|
-
* is the codec's domain `payload
|
|
370
|
+
* is the codec's domain `payload`.
|
|
326
371
|
* @template TPayload - The codec's domain payload for a tool-result failure.
|
|
327
372
|
*/
|
|
328
373
|
export interface ToolResultError<TPayload> extends CodecInputEvent {
|
|
@@ -339,7 +384,7 @@ export interface ToolResultError<TPayload> extends CodecInputEvent {
|
|
|
339
384
|
* codec-message addressed by `codecMessageId` — flipping the targeted
|
|
340
385
|
* tool call from pending-approval to approved or denied. The decision
|
|
341
386
|
* detail (e.g. tool-call id, approved flag, reason) is the codec's domain
|
|
342
|
-
* `payload
|
|
387
|
+
* `payload`.
|
|
343
388
|
*
|
|
344
389
|
* Codecs may layer approval semantics on top of domain models that don't
|
|
345
390
|
* natively support gating tool execution behind an approval — the codec
|
|
@@ -374,6 +419,15 @@ export type ToolResultErrorPayloadOf<TInput> = TInput extends ToolResultError<in
|
|
|
374
419
|
* @template TInput - The codec's input union.
|
|
375
420
|
*/
|
|
376
421
|
export type ToolApprovalResponsePayloadOf<TInput> = TInput extends ToolApprovalResponse<infer P> ? P : never;
|
|
422
|
+
/**
|
|
423
|
+
* Extract the domain message type (`TMessage`) carried by a codec's
|
|
424
|
+
* {@link UserMessage} member from its `TInput` union, or `never` if the codec
|
|
425
|
+
* has no user-message variant. Lets the core well-known input factories type
|
|
426
|
+
* `createUserMessage` from `TInput` alone, without a separate message type
|
|
427
|
+
* parameter.
|
|
428
|
+
* @template TInput - The codec's input union.
|
|
429
|
+
*/
|
|
430
|
+
export type UserMessageOf<TInput> = TInput extends UserMessage<infer M> ? M : never;
|
|
377
431
|
/**
|
|
378
432
|
* Structural base every codec output variant must satisfy. The output
|
|
379
433
|
* counterpart of {@link CodecInputEvent}: pins a `type` discriminator so
|
|
@@ -382,9 +436,8 @@ export type ToolApprovalResponsePayloadOf<TInput> = TInput extends ToolApprovalR
|
|
|
382
436
|
* fields on outputs without a breaking generic-arity change.
|
|
383
437
|
*
|
|
384
438
|
* The `type` discriminator is required on every variant so the codec's
|
|
385
|
-
* reducer can switch on it
|
|
386
|
-
*
|
|
387
|
-
* `string` — so the Vercel codec needs no implementation changes.
|
|
439
|
+
* reducer can switch on it — any domain union whose members carry a `type`
|
|
440
|
+
* string literal satisfies it structurally.
|
|
388
441
|
*
|
|
389
442
|
* No routing fields today: outputs carry no per-event `codecMessageId` /
|
|
390
443
|
* `parent` / `forkOf` overrides. Those move onto this base when a concrete
|
|
@@ -428,7 +481,13 @@ export interface CodecMessage<TMessage> {
|
|
|
428
481
|
* - `TMessage` — the per-message shape consumed by the Tree. Returned from
|
|
429
482
|
* {@link Codec.getMessages}.
|
|
430
483
|
*/
|
|
431
|
-
export interface Codec<TInput extends CodecInputEvent, TOutput extends CodecOutputEvent, TProjection, TMessage> extends Reducer<TInput
|
|
484
|
+
export interface Codec<TInput extends CodecInputEvent, TOutput extends CodecOutputEvent, TProjection, TMessage> extends Reducer<CodecEvent<TInput, TOutput>, TProjection> {
|
|
485
|
+
/**
|
|
486
|
+
* Optional Ably-Agent identifier. When present, the agent-registration path
|
|
487
|
+
* registers it on the channel (so traffic is attributed to this codec); when
|
|
488
|
+
* absent, the codec opts out of registration. Read directly by `registerAgent`.
|
|
489
|
+
*/
|
|
490
|
+
readonly adapterTag?: string;
|
|
432
491
|
/** Create a stateful encoder bound to the given channel. */
|
|
433
492
|
createEncoder(channel: ChannelWriter, options?: EncoderOptions): Encoder<TInput, TOutput>;
|
|
434
493
|
/** Create a stateful decoder for converting Ably inbound messages into typed inputs and outputs. */
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { CodecInputEvent, Regenerate, ToolApprovalResponse, ToolApprovalResponsePayloadOf, ToolResult, ToolResultError, ToolResultErrorPayloadOf, ToolResultPayloadOf, UserMessage, UserMessageOf } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* The well-known input factory functions, payload-typed for a codec's `TInput`
|
|
4
|
+
* union. A codec spreads these into its definition rather than re-implementing
|
|
5
|
+
* the variant-wrapping boilerplate. Each factory returns the specific variant
|
|
6
|
+
* it builds — a member of the codec's `TInput` union.
|
|
7
|
+
* @template TInput - The codec's input union.
|
|
8
|
+
*/
|
|
9
|
+
export interface WellKnownInputFactories<TInput extends CodecInputEvent> {
|
|
10
|
+
/**
|
|
11
|
+
* Wrap a domain message as the codec's {@link UserMessage} variant.
|
|
12
|
+
* @param message - The message in the codec's domain representation.
|
|
13
|
+
* @returns The user-message input.
|
|
14
|
+
*/
|
|
15
|
+
createUserMessage(message: UserMessageOf<TInput>): UserMessage<UserMessageOf<TInput>>;
|
|
16
|
+
/**
|
|
17
|
+
* Build a {@link Regenerate} input.
|
|
18
|
+
* @param target - The codec-message-id of the assistant message to regenerate.
|
|
19
|
+
* @param parent - The codec-message-id of the parent user message the new assistant threads under.
|
|
20
|
+
* @returns The regenerate input.
|
|
21
|
+
*/
|
|
22
|
+
createRegenerate(target: string, parent: string): Regenerate;
|
|
23
|
+
/**
|
|
24
|
+
* Build a {@link ToolResult} input addressing an assistant codec-message.
|
|
25
|
+
* @param codecMessageId - The assistant codec-message carrying the tool call.
|
|
26
|
+
* @param payload - The codec's domain payload describing the tool result.
|
|
27
|
+
* @returns The tool-result input.
|
|
28
|
+
*/
|
|
29
|
+
createToolResult(codecMessageId: string, payload: ToolResultPayloadOf<TInput>): ToolResult<ToolResultPayloadOf<TInput>>;
|
|
30
|
+
/**
|
|
31
|
+
* Build a {@link ToolResultError} input addressing an assistant codec-message.
|
|
32
|
+
* @param codecMessageId - The assistant codec-message carrying the tool call.
|
|
33
|
+
* @param payload - The codec's domain payload describing the failure.
|
|
34
|
+
* @returns The tool-result-error input.
|
|
35
|
+
*/
|
|
36
|
+
createToolResultError(codecMessageId: string, payload: ToolResultErrorPayloadOf<TInput>): ToolResultError<ToolResultErrorPayloadOf<TInput>>;
|
|
37
|
+
/**
|
|
38
|
+
* Build a {@link ToolApprovalResponse} input addressing an assistant codec-message.
|
|
39
|
+
* @param codecMessageId - The assistant codec-message carrying the tool call.
|
|
40
|
+
* @param payload - The codec's domain payload describing the approval decision.
|
|
41
|
+
* @returns The tool-approval-response input.
|
|
42
|
+
*/
|
|
43
|
+
createToolApprovalResponse(codecMessageId: string, payload: ToolApprovalResponsePayloadOf<TInput>): ToolApprovalResponse<ToolApprovalResponsePayloadOf<TInput>>;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Build the {@link WellKnownInputFactories} for a codec's `TInput` union. The
|
|
47
|
+
* returned factories wrap domain values into the well-known input variants and
|
|
48
|
+
* are typically spread into a codec definition.
|
|
49
|
+
* @template TInput - The codec's input union.
|
|
50
|
+
* @returns The well-known input factory functions, payload-typed to `TInput`.
|
|
51
|
+
*/
|
|
52
|
+
export declare const wellKnownInputs: <TInput extends CodecInputEvent>() => WellKnownInputFactories<TInput>;
|
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
import { Logger } from '../../logger.js';
|
|
2
|
+
import { Codec, CodecInputEvent, CodecOutputEvent } from '../codec/types.js';
|
|
3
|
+
import { WireApplier } from './decode-fold.js';
|
|
4
|
+
import { TreeInternal } from './tree.js';
|
|
5
|
+
import { ConversationNode, Tree } from './types.js';
|
|
6
|
+
/**
|
|
7
|
+
* AgentView — internal, server-side message-loading + input-event lookup for
|
|
8
|
+
* AgentSession.
|
|
9
|
+
*
|
|
10
|
+
* Encapsulates everything the agent needs to read conversation state off the
|
|
11
|
+
* channel: locating the triggering input event before `run-start`
|
|
12
|
+
* ({@link AgentView.findInputEvent}), and reconstructing the ancestor chain for
|
|
13
|
+
* an LLM prompt ({@link AgentView.loadConversation} / {@link AgentView.messages}).
|
|
14
|
+
*
|
|
15
|
+
* It does NOT own the materialisation Tree — AgentSession owns the Tree and the
|
|
16
|
+
* applier (and swaps them on channel continuity loss) and injects them here as
|
|
17
|
+
* `readonly` fields, the same way ClientSession wires `DefaultView`. Because
|
|
18
|
+
* AgentSession swaps the Tree, it RECREATES the AgentView on continuity loss
|
|
19
|
+
* (a fresh instance bound to the fresh Tree/applier) rather than mutating it —
|
|
20
|
+
* so this class never needs a tree accessor or a reset hook.
|
|
21
|
+
*
|
|
22
|
+
* This is deliberately internal: it is not exported from any entry point and
|
|
23
|
+
* does NOT implement the public `View` interface (that is the client-side
|
|
24
|
+
* `DefaultView`, unrelated to this class).
|
|
25
|
+
*
|
|
26
|
+
* Both `findInputEvent` and `loadConversation` drive ONE history-walk mechanism
|
|
27
|
+
* — the single-flight chain in {@link AgentView._driveHistoryChain} — so a
|
|
28
|
+
* `start()` input scan and a concurrent `loadConversation` share folded pages
|
|
29
|
+
* instead of each scanning the channel.
|
|
30
|
+
*/
|
|
31
|
+
import * as Ably from 'ably';
|
|
32
|
+
/**
|
|
33
|
+
* Result of {@link AgentView.findInputEvent}. The lookup races the session's
|
|
34
|
+
* Tree (`findAblyMessageByEventId` pre-scan + `'ably-message'` event for live
|
|
35
|
+
* arrivals) against a bounded history scan; resolves with the matched messages
|
|
36
|
+
* sorted by Ably `serial` ascending.
|
|
37
|
+
*
|
|
38
|
+
* Run.start reads `firstHeaders` / `firstClientId` from the smallest-serial
|
|
39
|
+
* matched message to derive per-run metadata (run-id, parent, forkOf,
|
|
40
|
+
* continuation flag, publisher clientId). The Tree has already folded each
|
|
41
|
+
* message by the time the lookup resolves, so callers do NOT need to decode the
|
|
42
|
+
* raw matched messages themselves.
|
|
43
|
+
*/
|
|
44
|
+
export interface InputEventLookupResult {
|
|
45
|
+
/** Raw Ably messages matched by the lookup, sorted by serial ascending. */
|
|
46
|
+
rawMessages: Ably.InboundMessage[];
|
|
47
|
+
/** Transport headers of the smallest-serial matched message (run metadata). */
|
|
48
|
+
firstHeaders?: Record<string, string>;
|
|
49
|
+
/** Publisher's Ably channel-level `clientId` from the smallest-serial message. */
|
|
50
|
+
firstClientId?: string;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Walk parent pointers from an anchor codec-message-id back through the
|
|
54
|
+
* Tree to the conversation root, returning nodes in root-first order. When
|
|
55
|
+
* `maxRuns` is set, the walk stops before the RunNode that would exceed the
|
|
56
|
+
* bound, so the bounding run's own input node(s) are still included (input
|
|
57
|
+
* nodes never count toward the bound). The chain therefore starts with the
|
|
58
|
+
* input that triggered its oldest run, never with an assistant reply.
|
|
59
|
+
*
|
|
60
|
+
* Returns an empty array when the anchor isn't in the Tree.
|
|
61
|
+
* @param tree - The materialisation tree to walk.
|
|
62
|
+
* @param anchor - The codec-message-id to start from (typically the current run's input).
|
|
63
|
+
* @param maxRuns - Optional bound on the number of ancestor reply RunNodes in the chain.
|
|
64
|
+
* @param currentRunId - The current run's id. Its own RunNode (reachable when
|
|
65
|
+
* the anchor's wire carried the run-id) is conversation tail, not ancestor
|
|
66
|
+
* context, so it never counts toward `maxRuns`.
|
|
67
|
+
* @returns Nodes from root to anchor in chronological order.
|
|
68
|
+
*/
|
|
69
|
+
export declare const walkAncestorChain: <TOutput extends CodecOutputEvent, TProjection>(tree: Tree<TOutput, TProjection>, anchor: string | undefined, maxRuns?: number, currentRunId?: string) => readonly ConversationNode<TProjection>[];
|
|
70
|
+
/**
|
|
71
|
+
* Constructor dependencies for {@link AgentView}, injected by AgentSession.
|
|
72
|
+
*
|
|
73
|
+
* AgentView holds `tree` + `applier` directly (like `DefaultView`). AgentSession
|
|
74
|
+
* owns them and, because it SWAPS the Tree on continuity loss, recreates the
|
|
75
|
+
* AgentView with the fresh Tree/applier rather than mutating them in place.
|
|
76
|
+
*/
|
|
77
|
+
export interface AgentViewOptions<TInput extends CodecInputEvent, TOutput extends CodecOutputEvent, TProjection, TMessage> {
|
|
78
|
+
/** The session's materialisation Tree (read for walks; folded into by history). */
|
|
79
|
+
tree: TreeInternal<TInput, TOutput, TProjection>;
|
|
80
|
+
/** The Ably channel to read history from. */
|
|
81
|
+
channel: Ably.RealtimeChannel;
|
|
82
|
+
/** Codec used to project per-node messages. */
|
|
83
|
+
codec: Codec<TInput, TOutput, TProjection, TMessage>;
|
|
84
|
+
/** The Tree's decode-and-apply engine; history pages fold through it. */
|
|
85
|
+
applier: WireApplier;
|
|
86
|
+
/** Logger for diagnostic output. */
|
|
87
|
+
logger?: Logger;
|
|
88
|
+
/**
|
|
89
|
+
* Age bound for the input-event scan: the scan gives up paging once it
|
|
90
|
+
* crosses `Date.now() - inputEventLookbackMs`. Applied only to
|
|
91
|
+
* `findInputEvent`, never to the ancestor-hydration walk.
|
|
92
|
+
*/
|
|
93
|
+
inputEventLookbackMs: number;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Internal server-side view: input-event lookup + conversation loading over the
|
|
97
|
+
* session Tree. See the file header for the ownership boundary.
|
|
98
|
+
*/
|
|
99
|
+
export declare class AgentView<TInput extends CodecInputEvent, TOutput extends CodecOutputEvent, TProjection, TMessage> {
|
|
100
|
+
private readonly _tree;
|
|
101
|
+
private readonly _channel;
|
|
102
|
+
private readonly _codec;
|
|
103
|
+
private readonly _applier;
|
|
104
|
+
private readonly _logger?;
|
|
105
|
+
private readonly _inputEventLookbackMs;
|
|
106
|
+
/**
|
|
107
|
+
* Tail of the single-flight history-hydration chain. Each walk links behind
|
|
108
|
+
* the current tail and becomes the new tail, so concurrent calls serialise
|
|
109
|
+
* and share each other's folded pages instead of each scanning the channel.
|
|
110
|
+
* A link never rejects (it records its error locally), so a follower awaiting
|
|
111
|
+
* the tail is isolated from a prior link's failure.
|
|
112
|
+
*/
|
|
113
|
+
private _hydrationMutex;
|
|
114
|
+
/**
|
|
115
|
+
* Shared history-walk cursor for this AgentView's attach epoch — ONE backward
|
|
116
|
+
* `untilAttach` pagination that both `findInputEvent` and `loadConversation`
|
|
117
|
+
* advance. `findInputEvent` pages it until the trigger is found (or its
|
|
118
|
+
* lookback give-up point) and pauses; `loadConversation` resumes from that
|
|
119
|
+
* position instead of re-paging from newest, so the channel is walked once.
|
|
120
|
+
* Created lazily on first use (no per-caller signal, so it outlives any one
|
|
121
|
+
* caller; no lookback, so it can reach attach). The single-flight chain
|
|
122
|
+
* (`_hydrationMutex`) serialises access so it is never paged concurrently. A
|
|
123
|
+
* continuity-loss swap recreates the whole AgentView, so there is no in-place
|
|
124
|
+
* reset.
|
|
125
|
+
*/
|
|
126
|
+
private _cursor;
|
|
127
|
+
/**
|
|
128
|
+
* True once the shared cursor reached attach (channel exhausted). Because the
|
|
129
|
+
* cursor carries no lookback, its exhaustion is always genuine (never a
|
|
130
|
+
* lookback boundary), so either caller may record it; a lookback-bounded
|
|
131
|
+
* `findInputEvent` scan stops via an early `break` that leaves the cursor
|
|
132
|
+
* non-exhausted, so it never sets this.
|
|
133
|
+
*/
|
|
134
|
+
private _historyExhausted;
|
|
135
|
+
constructor(options: AgentViewOptions<TInput, TOutput, TProjection, TMessage>);
|
|
136
|
+
/**
|
|
137
|
+
* Fold a single wire message into the Tree: decode-and-apply via the applier,
|
|
138
|
+
* then notify Tree subscribers and populate the event-id index. Mirrors
|
|
139
|
+
* AgentSession's live `_foldWire`; history pages fold through this.
|
|
140
|
+
* @param wire - The inbound Ably message to fold.
|
|
141
|
+
*/
|
|
142
|
+
private _foldWire;
|
|
143
|
+
/**
|
|
144
|
+
* Find every message whose `event-id` matches one of `expectedEventIds`,
|
|
145
|
+
* racing three sources:
|
|
146
|
+
*
|
|
147
|
+
* 1. A pre-scan of the Tree via `findAblyMessageByEventId` for messages already
|
|
148
|
+
* folded into it from prior live arrivals.
|
|
149
|
+
* 2. A live listener on the Tree's `ably-message` event for new arrivals
|
|
150
|
+
* during the call.
|
|
151
|
+
* 3. The shared history walk (lookback-bounded) — pages fold into the Tree
|
|
152
|
+
* and surface through the same `ably-message` event.
|
|
153
|
+
*
|
|
154
|
+
* Resolves when every expected event-id has been matched. Per-id race
|
|
155
|
+
* resolution — whichever source surfaces a matched message first wins
|
|
156
|
+
* (dedup by serial). On timeout: cancels the in-flight history scan and
|
|
157
|
+
* rejects with `InputEventNotFound`, wrapping any history-scan failure as
|
|
158
|
+
* `cause` so a broken history fetch isn't masked behind the timeout. On
|
|
159
|
+
* signal abort: rejects with `InvalidArgument`.
|
|
160
|
+
*
|
|
161
|
+
* `firstHeaders` and `firstClientId` are read from the matched message with
|
|
162
|
+
* the smallest serial (`compareBySerial`), giving stable run-level
|
|
163
|
+
* metadata regardless of arrival ordering across sources.
|
|
164
|
+
* @param opts - Lookup parameters.
|
|
165
|
+
* @param opts.invocationId - The invocation id this lookup is for (logging / error messages).
|
|
166
|
+
* @param opts.runId - The run id this lookup is for (logging / error messages).
|
|
167
|
+
* @param opts.expectedEventIds - The set of `event-id`s the lookup must observe before resolving.
|
|
168
|
+
* @param opts.timeoutMs - Maximum total wait across live + history sources.
|
|
169
|
+
* @param opts.signal - AbortSignal that aborts the lookup if the run is cancelled.
|
|
170
|
+
* @returns Raw matched Ably messages sorted by serial ascending, plus the
|
|
171
|
+
* smallest-serial message's headers and clientId for downstream metadata.
|
|
172
|
+
*/
|
|
173
|
+
findInputEvent(opts: {
|
|
174
|
+
invocationId: string;
|
|
175
|
+
runId: string;
|
|
176
|
+
expectedEventIds: readonly string[];
|
|
177
|
+
timeoutMs: number;
|
|
178
|
+
signal: AbortSignal;
|
|
179
|
+
}): Promise<InputEventLookupResult>;
|
|
180
|
+
/**
|
|
181
|
+
* Reconstruct the conversation by walking the parent chain from the run's
|
|
182
|
+
* input node back to the conversation root, reading already-folded
|
|
183
|
+
* projections off the Tree's nodes.
|
|
184
|
+
*
|
|
185
|
+
* Hydrates the Tree as needed via the shared history walk
|
|
186
|
+
* ({@link AgentView._hydrateAncestors}), then concatenates
|
|
187
|
+
* `codec.getMessages(node.projection)` per node (root first) and appends the
|
|
188
|
+
* current run's projection at the tail.
|
|
189
|
+
* @param runId - The current run's id (for the tail run's projection lookup).
|
|
190
|
+
* @param assistantParentFallback - The current run's input node codec-message-id.
|
|
191
|
+
* @param signal - AbortSignal; rejects with InvalidArgument when aborted.
|
|
192
|
+
* @param maxRuns - Optional bound on the parent walk; counts reply RunNodes.
|
|
193
|
+
* @param runIdAdopted - True when the run-id came from outside (runtime
|
|
194
|
+
* override or continuation), so its node may exist in channel history;
|
|
195
|
+
* false for agent-minted ids, whose run-start only ever arrives via the
|
|
196
|
+
* live echo.
|
|
197
|
+
* @param regenerateTarget - The codec-message-id being regenerated, or
|
|
198
|
+
* undefined; the run that owns it is flattened only up to that message so
|
|
199
|
+
* the reconstructed history stops before the assistant message being
|
|
200
|
+
* replaced (which the model would otherwise reject).
|
|
201
|
+
* @returns The branch's messages (root-first) and the current run's projection.
|
|
202
|
+
*/
|
|
203
|
+
loadConversation(runId: string, assistantParentFallback: string | undefined, signal: AbortSignal, maxRuns: number | undefined, runIdAdopted: boolean, regenerateTarget?: string): Promise<{
|
|
204
|
+
messages: TMessage[];
|
|
205
|
+
projection: TProjection;
|
|
206
|
+
}>;
|
|
207
|
+
/**
|
|
208
|
+
* Walk the parent chain from `anchor` over the current Tree and concatenate
|
|
209
|
+
* each node's projected messages (root-first), then append the current run's
|
|
210
|
+
* own messages when its RunNode isn't already on the chain. Shared by
|
|
211
|
+
* {@link AgentView.loadConversation} and {@link AgentView.messages}. Pure read
|
|
212
|
+
* over whatever is currently folded — no fetching.
|
|
213
|
+
* @param runId - The current run's id (for the tail run's projection lookup).
|
|
214
|
+
* @param anchor - The current run's input node codec-message-id.
|
|
215
|
+
* @param maxRuns - Optional bound on the ancestor walk (counts reply runs).
|
|
216
|
+
* @param regenerateTarget - The codec-message-id being regenerated; when set,
|
|
217
|
+
* the walk stops before that message (a regenerate of a non-head message
|
|
218
|
+
* anchors at the target's predecessor, so flattening its run whole would
|
|
219
|
+
* re-emit the target and end the history on the message being replaced).
|
|
220
|
+
* @returns The conversation messages (root-first) and the current run's
|
|
221
|
+
* projection (the codec's empty init when the run has no node yet).
|
|
222
|
+
*/
|
|
223
|
+
private _collectConversation;
|
|
224
|
+
/**
|
|
225
|
+
* Synchronous live read of the conversation messages for `Run.messages`:
|
|
226
|
+
* walk the parent chain from `anchor` (no `maxRuns` bound), concatenate each
|
|
227
|
+
* ancestor's projection, then append the current run's messages if its node
|
|
228
|
+
* isn't already on the chain. No I/O — reflects whatever is currently folded.
|
|
229
|
+
* @param runId - The current run's id (for the tail run's projection lookup).
|
|
230
|
+
* @param anchor - The current run's input node codec-message-id (assistantParentFallback).
|
|
231
|
+
* @param regenerateTarget - The codec-message-id being regenerated; when set,
|
|
232
|
+
* the walk stops before it (see {@link AgentView._collectConversation}).
|
|
233
|
+
* @returns The conversation messages, root-first.
|
|
234
|
+
*/
|
|
235
|
+
messages(runId: string, anchor: string | undefined, regenerateTarget?: string): TMessage[];
|
|
236
|
+
/**
|
|
237
|
+
* Single-flight chain entry shared by `findInputEvent` and `loadConversation`.
|
|
238
|
+
* Serialises behind any in-flight walk so the shared cursor is advanced by one
|
|
239
|
+
* caller at a time (never paged concurrently), then runs one
|
|
240
|
+
* {@link AgentView._walkSharedHistory}. A link never rejects (it records its
|
|
241
|
+
* error locally), so a follower awaiting the chain tail is isolated from a
|
|
242
|
+
* prior link's failure; this method rethrows the wrapped error from its own
|
|
243
|
+
* frame after awaiting.
|
|
244
|
+
*
|
|
245
|
+
* Returns `exhausted` but never records `_historyExhausted`; the caller records
|
|
246
|
+
* it (both callers may, since the shared cursor's exhaustion is always genuine
|
|
247
|
+
* — see {@link AgentView._historyExhausted}).
|
|
248
|
+
* @param shouldStop - Polled before each page; true pauses this walk.
|
|
249
|
+
* @param signal - Per-call abort signal (checked between pages).
|
|
250
|
+
* @param lookbackMs - Optional give-up bound for the input scan (early break).
|
|
251
|
+
* @param operationLabel - Verb for the wrapped error message.
|
|
252
|
+
* @returns `{ exhausted }` — true only when the shared cursor reached attach.
|
|
253
|
+
*/
|
|
254
|
+
private _driveHistoryChain;
|
|
255
|
+
/**
|
|
256
|
+
* Advance the SHARED history cursor (lazily opening it once per attach epoch)
|
|
257
|
+
* and fold each page into the session Tree via the injected `fold`, stopping
|
|
258
|
+
* when `shouldStop()` returns true, the channel is exhausted, the signal
|
|
259
|
+
* aborts, a continuity-loss Tree swap abandons the walk, or — when `lookbackMs`
|
|
260
|
+
* is given — the walk pages past the lookback window. The cursor is NOT closed
|
|
261
|
+
* on stop: it stays paused at its current position so a later caller resumes
|
|
262
|
+
* from there rather than re-paging from newest. Throws (caller-wrapped) on a
|
|
263
|
+
* fetch failure after `loadHistoryPages`' per-page retries.
|
|
264
|
+
* @param shouldStop - Polled before each page; true pauses the walk.
|
|
265
|
+
* @param signal - Per-call abort signal (checked between pages; the shared cursor carries none).
|
|
266
|
+
* @param lookbackMs - Optional give-up bound: stop paging once a page's oldest
|
|
267
|
+
* message predates `Date.now() - lookbackMs`. An early `break`, NOT a cursor
|
|
268
|
+
* bound, so the cursor stays resumable and exhaustion is never reported here.
|
|
269
|
+
* @returns True only when the cursor genuinely reached attach — NOT when
|
|
270
|
+
* paused by the predicate / lookback, a Tree swap, or signal abort.
|
|
271
|
+
*/
|
|
272
|
+
private _walkSharedHistory;
|
|
273
|
+
/**
|
|
274
|
+
* Populate the Tree with enough ancestor coverage to walk from `anchor` to
|
|
275
|
+
* root (or `maxRuns` reply runs back) by driving the shared history walk.
|
|
276
|
+
* Records `_historyExhausted` only when a FULL (no-lookback) walk genuinely
|
|
277
|
+
* exhausts the channel.
|
|
278
|
+
* @param runId - The current run's id (when adopted, its node must be present in the Tree before the walk is complete).
|
|
279
|
+
* @param anchor - The input codec-message-id to walk from. Undefined means no walk is needed (current run only).
|
|
280
|
+
* @param signal - AbortSignal.
|
|
281
|
+
* @param maxRuns - Optional bound on the ancestor walk.
|
|
282
|
+
* @param runIdAdopted - Whether the run-id came from outside (override or continuation) and so may name a run present in channel history.
|
|
283
|
+
* @throws {Ably.ErrorInfo} `InvalidArgument` when `signal` aborts;
|
|
284
|
+
* `HistoryFetchFailed` — or the underlying Ably code when the failure
|
|
285
|
+
* carried one — (original as `cause`) when this caller's own history
|
|
286
|
+
* fetch fails after retries.
|
|
287
|
+
*/
|
|
288
|
+
private _hydrateAncestors;
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Create an {@link AgentView}. Factory entry point mirroring `createTree`;
|
|
292
|
+
* AgentSession never calls `new AgentView` directly.
|
|
293
|
+
* @param options - Injected dependencies.
|
|
294
|
+
* @returns A new AgentView.
|
|
295
|
+
*/
|
|
296
|
+
export declare const createAgentView: <TInput extends CodecInputEvent, TOutput extends CodecOutputEvent, TProjection, TMessage>(options: AgentViewOptions<TInput, TOutput, TProjection, TMessage>) => AgentView<TInput, TOutput, TProjection, TMessage>;
|