@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.
Files changed (167) hide show
  1. package/README.md +114 -116
  2. package/dist/ably-ai-transport.js +1743 -961
  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 +117 -39
  7. package/dist/core/agent.d.ts +29 -0
  8. package/dist/core/codec/decoder.d.ts +20 -23
  9. package/dist/core/codec/encoder.d.ts +11 -8
  10. package/dist/core/codec/index.d.ts +1 -2
  11. package/dist/core/codec/lifecycle-tracker.d.ts +10 -9
  12. package/dist/core/codec/types.d.ts +410 -101
  13. package/dist/core/transport/agent-session.d.ts +10 -0
  14. package/dist/core/transport/branch-chain.d.ts +43 -0
  15. package/dist/core/transport/client-session.d.ts +13 -0
  16. package/dist/core/transport/decode-fold.d.ts +47 -0
  17. package/dist/core/transport/headers.d.ts +97 -17
  18. package/dist/core/transport/index.d.ts +5 -3
  19. package/dist/core/transport/internal/bounded-map.d.ts +20 -0
  20. package/dist/core/transport/invocation.d.ts +74 -0
  21. package/dist/core/transport/load-conversation.d.ts +128 -0
  22. package/dist/core/transport/load-history.d.ts +39 -0
  23. package/dist/core/transport/pipe-stream.d.ts +9 -8
  24. package/dist/core/transport/run-manager.d.ts +78 -0
  25. package/dist/core/transport/tree.d.ts +435 -0
  26. package/dist/core/transport/types/agent.d.ts +353 -0
  27. package/dist/core/transport/types/client.d.ts +168 -0
  28. package/dist/core/transport/types/shared.d.ts +24 -0
  29. package/dist/core/transport/types/tree.d.ts +315 -0
  30. package/dist/core/transport/types/view.d.ts +222 -0
  31. package/dist/core/transport/types.d.ts +13 -402
  32. package/dist/core/transport/view.d.ts +354 -0
  33. package/dist/errors.d.ts +37 -9
  34. package/dist/index.d.ts +6 -6
  35. package/dist/logger.d.ts +12 -0
  36. package/dist/react/ably-ai-transport-react.js +1164 -645
  37. package/dist/react/ably-ai-transport-react.js.map +1 -1
  38. package/dist/react/ably-ai-transport-react.umd.cjs +1 -1
  39. package/dist/react/ably-ai-transport-react.umd.cjs.map +1 -1
  40. package/dist/react/contexts/client-session-context.d.ts +36 -0
  41. package/dist/react/contexts/client-session-provider.d.ts +53 -0
  42. package/dist/react/create-session-hooks.d.ts +116 -0
  43. package/dist/react/index.d.ts +16 -10
  44. package/dist/react/internal/use-resolved-session.d.ts +36 -0
  45. package/dist/react/use-ably-messages.d.ts +20 -11
  46. package/dist/react/use-client-session.d.ts +81 -0
  47. package/dist/react/use-create-view.d.ts +23 -0
  48. package/dist/react/use-tree.d.ts +35 -0
  49. package/dist/react/use-view.d.ts +110 -0
  50. package/dist/utils.d.ts +32 -23
  51. package/dist/vercel/ably-ai-transport-vercel.js +2748 -1625
  52. package/dist/vercel/ably-ai-transport-vercel.js.map +1 -1
  53. package/dist/vercel/ably-ai-transport-vercel.umd.cjs +1 -1
  54. package/dist/vercel/ably-ai-transport-vercel.umd.cjs.map +1 -1
  55. package/dist/vercel/codec/decoder.d.ts +5 -18
  56. package/dist/vercel/codec/encoder.d.ts +6 -36
  57. package/dist/vercel/codec/events.d.ts +51 -0
  58. package/dist/vercel/codec/index.d.ts +24 -12
  59. package/dist/vercel/codec/reducer.d.ts +144 -0
  60. package/dist/vercel/codec/tool-transitions.d.ts +50 -0
  61. package/dist/vercel/index.d.ts +4 -2
  62. package/dist/vercel/react/ably-ai-transport-vercel-react.js +10298 -1410
  63. package/dist/vercel/react/ably-ai-transport-vercel-react.js.map +1 -1
  64. package/dist/vercel/react/ably-ai-transport-vercel-react.umd.cjs +70 -1
  65. package/dist/vercel/react/ably-ai-transport-vercel-react.umd.cjs.map +1 -1
  66. package/dist/vercel/react/contexts/chat-transport-context.d.ts +33 -0
  67. package/dist/vercel/react/contexts/chat-transport-provider.d.ts +96 -0
  68. package/dist/vercel/react/index.d.ts +4 -0
  69. package/dist/vercel/react/use-chat-transport.d.ts +66 -21
  70. package/dist/vercel/react/use-message-sync.d.ts +31 -12
  71. package/dist/vercel/run-end-reason.d.ts +29 -0
  72. package/dist/vercel/transport/chat-transport.d.ts +71 -30
  73. package/dist/vercel/transport/index.d.ts +25 -18
  74. package/dist/vercel/transport/run-output-stream.d.ts +56 -0
  75. package/dist/version.d.ts +2 -0
  76. package/package.json +47 -34
  77. package/src/constants.ts +126 -47
  78. package/src/core/agent.ts +68 -0
  79. package/src/core/codec/decoder.ts +71 -98
  80. package/src/core/codec/encoder.ts +115 -58
  81. package/src/core/codec/index.ts +13 -6
  82. package/src/core/codec/lifecycle-tracker.ts +10 -9
  83. package/src/core/codec/types.ts +438 -106
  84. package/src/core/transport/agent-session.ts +1344 -0
  85. package/src/core/transport/branch-chain.ts +58 -0
  86. package/src/core/transport/client-session.ts +775 -0
  87. package/src/core/transport/decode-fold.ts +91 -0
  88. package/src/core/transport/headers.ts +182 -19
  89. package/src/core/transport/index.ts +29 -22
  90. package/src/core/transport/internal/bounded-map.ts +27 -0
  91. package/src/core/transport/invocation.ts +98 -0
  92. package/src/core/transport/load-conversation.ts +355 -0
  93. package/src/core/transport/load-history.ts +269 -0
  94. package/src/core/transport/pipe-stream.ts +58 -40
  95. package/src/core/transport/run-manager.ts +249 -0
  96. package/src/core/transport/tree.ts +1167 -0
  97. package/src/core/transport/types/agent.ts +407 -0
  98. package/src/core/transport/types/client.ts +211 -0
  99. package/src/core/transport/types/shared.ts +27 -0
  100. package/src/core/transport/types/tree.ts +344 -0
  101. package/src/core/transport/types/view.ts +259 -0
  102. package/src/core/transport/types.ts +13 -527
  103. package/src/core/transport/view.ts +1271 -0
  104. package/src/errors.ts +42 -9
  105. package/src/event-emitter.ts +3 -2
  106. package/src/index.ts +55 -39
  107. package/src/logger.ts +14 -1
  108. package/src/react/contexts/client-session-context.ts +41 -0
  109. package/src/react/contexts/client-session-provider.tsx +186 -0
  110. package/src/react/create-session-hooks.ts +141 -0
  111. package/src/react/index.ts +27 -10
  112. package/src/react/internal/use-resolved-session.ts +63 -0
  113. package/src/react/use-ably-messages.ts +47 -19
  114. package/src/react/use-client-session.ts +201 -0
  115. package/src/react/use-create-view.ts +72 -0
  116. package/src/react/use-tree.ts +84 -0
  117. package/src/react/use-view.ts +275 -0
  118. package/src/react/vite.config.ts +4 -1
  119. package/src/utils.ts +63 -45
  120. package/src/vercel/codec/decoder.ts +336 -255
  121. package/src/vercel/codec/encoder.ts +348 -196
  122. package/src/vercel/codec/events.ts +87 -0
  123. package/src/vercel/codec/index.ts +59 -14
  124. package/src/vercel/codec/reducer.ts +977 -0
  125. package/src/vercel/codec/tool-transitions.ts +122 -0
  126. package/src/vercel/index.ts +7 -3
  127. package/src/vercel/react/contexts/chat-transport-context.ts +41 -0
  128. package/src/vercel/react/contexts/chat-transport-provider.tsx +150 -0
  129. package/src/vercel/react/index.ts +13 -1
  130. package/src/vercel/react/use-chat-transport.ts +162 -42
  131. package/src/vercel/react/use-message-sync.ts +121 -22
  132. package/src/vercel/react/vite.config.ts +4 -2
  133. package/src/vercel/run-end-reason.ts +78 -0
  134. package/src/vercel/transport/chat-transport.ts +553 -113
  135. package/src/vercel/transport/index.ts +40 -28
  136. package/src/vercel/transport/run-output-stream.ts +170 -0
  137. package/src/version.ts +2 -0
  138. package/dist/core/transport/client-transport.d.ts +0 -10
  139. package/dist/core/transport/conversation-tree.d.ts +0 -9
  140. package/dist/core/transport/decode-history.d.ts +0 -41
  141. package/dist/core/transport/server-transport.d.ts +0 -7
  142. package/dist/core/transport/stream-router.d.ts +0 -19
  143. package/dist/core/transport/turn-manager.d.ts +0 -34
  144. package/dist/react/use-active-turns.d.ts +0 -8
  145. package/dist/react/use-client-transport.d.ts +0 -7
  146. package/dist/react/use-conversation-tree.d.ts +0 -20
  147. package/dist/react/use-edit.d.ts +0 -7
  148. package/dist/react/use-history.d.ts +0 -19
  149. package/dist/react/use-messages.d.ts +0 -7
  150. package/dist/react/use-regenerate.d.ts +0 -7
  151. package/dist/react/use-send.d.ts +0 -7
  152. package/dist/vercel/codec/accumulator.d.ts +0 -21
  153. package/src/core/transport/client-transport.ts +0 -959
  154. package/src/core/transport/conversation-tree.ts +0 -434
  155. package/src/core/transport/decode-history.ts +0 -337
  156. package/src/core/transport/server-transport.ts +0 -458
  157. package/src/core/transport/stream-router.ts +0 -118
  158. package/src/core/transport/turn-manager.ts +0 -147
  159. package/src/react/use-active-turns.ts +0 -61
  160. package/src/react/use-client-transport.ts +0 -37
  161. package/src/react/use-conversation-tree.ts +0 -71
  162. package/src/react/use-edit.ts +0 -24
  163. package/src/react/use-history.ts +0 -111
  164. package/src/react/use-messages.ts +0 -32
  165. package/src/react/use-regenerate.ts +0 -24
  166. package/src/react/use-send.ts +0 -25
  167. package/src/vercel/codec/accumulator.ts +0 -603
@@ -0,0 +1,47 @@
1
+ import { Codec, CodecInputEvent, CodecOutputEvent, Decoder } from '../codec/types.js';
2
+ import { TreeInternal } from './tree.js';
3
+ import { RunLifecycleEvent } from './types.js';
4
+ /**
5
+ * Shared wire decode-and-apply engine.
6
+ *
7
+ * The client's live decode loop and the View's history replay both reconstruct
8
+ * the conversation Tree from the same raw Ably wire log. This module is the one
9
+ * place that classifies a wire message (run-lifecycle vs codec-decoded), parses
10
+ * or decodes it, and applies it to the Tree — so the two paths can never drift.
11
+ */
12
+ import type * as Ably from 'ably';
13
+ /**
14
+ * Apply one inbound wire message to the tree.
15
+ *
16
+ * Run-lifecycle messages are turned into a {@link RunLifecycleEvent} via
17
+ * {@link parseRunLifecycle} and applied with `applyRunLifecycle`; everything
18
+ * else is decoded with `decoder` and applied with `applyMessage`, skipping
19
+ * wire-only carriers that decode to no events and carry no run-id (the eventual
20
+ * reply run is created later by its run-start).
21
+ *
22
+ * Does NOT emit the tree's `ably-message` event — the caller owns that, because
23
+ * the live loop emits per message while history replay emits in a batch once
24
+ * the whole page is applied. Returns the parsed lifecycle event so a live
25
+ * caller can run its own side-effects (resolving a pending run-start,
26
+ * surfacing an agent error); returns `undefined` for a codec-decoded message
27
+ * or a lifecycle message that carried no run-id.
28
+ * @param tree - The tree to apply the message to.
29
+ * @param decoder - The codec decoder used for non-lifecycle messages.
30
+ * @param rawMsg - The inbound Ably wire message.
31
+ * @returns The parsed run-lifecycle event, or `undefined`.
32
+ */
33
+ export declare const applyWireMessage: <TInput extends CodecInputEvent, TOutput extends CodecOutputEvent, TProjection>(tree: TreeInternal<TInput, TOutput, TProjection>, decoder: Decoder<TInput, TOutput>, rawMsg: Ably.InboundMessage) => RunLifecycleEvent | undefined;
34
+ /**
35
+ * Decode one wire message with `decoder` and fold its events into `projection`,
36
+ * returning the updated projection. Unlike {@link applyWireMessage} this builds
37
+ * a standalone projection rather than applying to a tree — used by the agent's
38
+ * conversation reconstruction. The caller owns the decoder so its streaming
39
+ * state can span the messages of a run, and chooses the reducer routing key.
40
+ * @param codec - The codec whose inherited Reducer `fold` method folds each decoded event into the projection.
41
+ * @param decoder - The caller-owned codec decoder (reused across a run's wires).
42
+ * @param projection - The projection to fold the message's events into.
43
+ * @param rawMsg - The wire message to decode and fold.
44
+ * @param messageId - The reducer routing key (codec-message-id) for this message.
45
+ * @returns The projection after folding all of the message's decoded events.
46
+ */
47
+ export declare const foldMessageInto: <TInput extends CodecInputEvent, TOutput extends CodecOutputEvent, TProjection, TMessage>(codec: Codec<TInput, TOutput, TProjection, TMessage>, decoder: Decoder<TInput, TOutput>, projection: TProjection, rawMsg: Ably.InboundMessage, messageId: string) => TProjection;
@@ -1,26 +1,106 @@
1
- /**
2
- * Transport header builder.
3
- *
4
- * Single source of truth for which `x-ably-*` headers every transport
5
- * message carries. Used by the server transport (addMessages, streamResponse)
6
- * and will be used by the client transport (optimistic message stamping).
7
- */
1
+ import { EVENT_RUN_END, EVENT_RUN_RESUME, EVENT_RUN_START, EVENT_RUN_SUSPEND } from '../../constants.js';
2
+ import { RunEndReason, RunLifecycleEvent } from './types.js';
8
3
  /**
9
4
  * Build the standard transport header set for a message.
10
5
  * @param opts - The header values to include.
11
6
  * @param opts.role - Message role (e.g. "user", "assistant").
12
- * @param opts.turnId - Turn correlation ID.
13
- * @param opts.msgId - Message identity.
14
- * @param opts.turnClientId - ClientId of the turn initiator.
15
- * @param opts.parent - Preceding message's msg-id (for branching). Null means root.
16
- * @param opts.forkOf - Forked message's msg-id (for edit/regen).
17
- * @returns A headers record with the `x-ably-*` transport headers set.
7
+ * @param opts.runId - Run correlation ID, or `undefined` for a fresh client
8
+ * input (the agent mints run-ids, so it is not known synchronously). Omitted
9
+ * from the headers when undefined; a continuation still carries the known run-id.
10
+ * @param opts.codecMessageId - Message identity — the wire `codec-message-id` for this message.
11
+ * @param opts.runClientId - ClientId of the run initiator.
12
+ * @param opts.parent - Preceding message's codec-message-id (for branching).
13
+ * @param opts.forkOf - Forked user-prompt's codec-message-id (for edits — creates a Run-level fork sibling).
14
+ * @param opts.regenerates - Assistant codec-message-id this run regenerates. Stamps
15
+ * `msg-regenerate`. Distinct from `forkOf`: regenerate is a
16
+ * continuation of the prior run (no Run-level fork), with the message
17
+ * replacement resolved at projection extraction time.
18
+ * @param opts.invocationId - Agent-minted invocation id. Stamped by the agent on every event it publishes for the invocation (run lifecycle + outputs) so the client can observe it; not set by the client on the input.
19
+ * @param opts.inputClientId - ClientId of the input event (the `ai-input`) that
20
+ * drove the current invocation. The agent reads it from the publisher's
21
+ * Ably-level `clientId` on the matched input event and re-stamps it on its
22
+ * own publishes (run lifecycle + outputs). Differs from `runClientId` on
23
+ * continuation invocations driven by an input from a non-owner.
24
+ * @param opts.inputEventId - Per-event identifier. Set on each client-published user-prompt message; the invocation body's `inputEventIds` lists the ids the agent should look up.
25
+ * @param opts.inputCodecMessageId - The codec-message-id of the input event that
26
+ * triggered the current invocation (the one whose `event-id` matched the
27
+ * invocation's `inputEventId`). The agent re-stamps it on every event it
28
+ * publishes for the invocation (run lifecycle + outputs), mirroring
29
+ * `inputClientId`, so the client can correlate any of those events back to
30
+ * the originating input by the id it owned at send time.
31
+ * @returns A headers record with the transport headers set.
18
32
  */
19
33
  export declare const buildTransportHeaders: (opts: {
20
34
  role: string;
21
- turnId: string;
22
- msgId: string;
23
- turnClientId?: string;
24
- parent?: string | null;
35
+ runId?: string;
36
+ codecMessageId: string;
37
+ runClientId?: string;
38
+ parent?: string;
25
39
  forkOf?: string;
40
+ regenerates?: string;
41
+ invocationId?: string;
42
+ inputClientId?: string;
43
+ inputCodecMessageId?: string;
44
+ inputEventId?: string;
26
45
  }) => Record<string, string>;
46
+ /**
47
+ * Build the transport header set for a run-lifecycle event (run-start,
48
+ * run-resume, run-suspend, run-end). Single source of truth for lifecycle
49
+ * header stamping, mirroring {@link buildTransportHeaders} for the
50
+ * message-carrier path. Every field except `runId`/`runClientId` is optional
51
+ * and omitted when not provided.
52
+ *
53
+ * A resume suppresses the structural `parent` / `forkOf` / `regenerates`
54
+ * headers — the caller passes them only for a fresh run-start. `reason` is
55
+ * stamped only on run-end.
56
+ * @param opts - The lifecycle header values to include.
57
+ * @param opts.runId - The run's id.
58
+ * @param opts.runClientId - ClientId of the run initiator (empty string when unknown).
59
+ * @param opts.parent - Structural parent codec-message-id (fresh run-start only).
60
+ * @param opts.forkOf - Forked user-prompt codec-message-id (fresh run-start only).
61
+ * @param opts.regenerates - Regenerated assistant codec-message-id (fresh run-start only).
62
+ * @param opts.invocationId - Agent-minted invocation id; carried on every lifecycle event.
63
+ * @param opts.inputClientId - ClientId of the triggering input event.
64
+ * @param opts.inputCodecMessageId - Codec-message-id of the triggering input event.
65
+ * @param opts.reason - Terminal reason; stamped on run-end only.
66
+ * @returns A headers record with the lifecycle headers set.
67
+ */
68
+ export declare const buildLifecycleHeaders: (opts: {
69
+ runId: string;
70
+ runClientId: string;
71
+ parent?: string;
72
+ forkOf?: string;
73
+ regenerates?: string;
74
+ invocationId?: string;
75
+ inputClientId?: string;
76
+ inputCodecMessageId?: string;
77
+ reason?: RunEndReason;
78
+ }) => Record<string, string>;
79
+ /** The four run-lifecycle Ably message names. */
80
+ type RunLifecycleName = typeof EVENT_RUN_START | typeof EVENT_RUN_SUSPEND | typeof EVENT_RUN_RESUME | typeof EVENT_RUN_END;
81
+ /**
82
+ * Whether an Ably message `name` is one of the run-lifecycle event names
83
+ * (run-start / run-suspend / run-resume / run-end). Single source of truth for
84
+ * the classification both decode loops and the agent's history scan use to
85
+ * route lifecycle wires away from the codec decoder. Narrows `name` to a
86
+ * lifecycle name so callers can pass it straight to {@link parseRunLifecycle}.
87
+ * @param name - The inbound Ably message `name`, or undefined.
88
+ * @returns True when `name` is a run-lifecycle event name.
89
+ */
90
+ export declare const isRunLifecycleName: (name: string | undefined) => name is RunLifecycleName;
91
+ /**
92
+ * Parse an inbound run-lifecycle Ably message into a {@link RunLifecycleEvent}.
93
+ *
94
+ * Single source of truth for turning the wire run-lifecycle message `name`,
95
+ * transport headers, and channel serial into the structured lifecycle event
96
+ * the Tree consumes. Used by the client decode loop (live) and the View's
97
+ * history replay so both build the event identically.
98
+ * @param name - The inbound Ably message `name`.
99
+ * @param headers - Transport headers from the inbound Ably message.
100
+ * @param serial - Ably channel serial of the message, or `undefined` for an
101
+ * optimistic local event. Stamped onto the returned event.
102
+ * @returns The lifecycle event, or `undefined` when `name` is not a
103
+ * run-lifecycle event name or the message carries no `run-id`.
104
+ */
105
+ export declare const parseRunLifecycle: (name: string, headers: Record<string, string>, serial: string | undefined) => RunLifecycleEvent | undefined;
106
+ export {};
@@ -1,4 +1,6 @@
1
- export type { ActiveTurn, AddMessageOptions, AddMessagesResult, CancelFilter, CancelRequest, ClientTransport, ClientTransportOptions, CloseOptions, ConversationNode, ConversationTree, LoadHistoryOptions, MessageWithHeaders, NewTurnOptions, PaginatedMessages, SendOptions, ServerTransport, ServerTransportOptions, StreamResponseOptions, StreamResult, Turn, TurnEndReason, TurnLifecycleEvent, } from './types.js';
2
- export { createServerTransport } from './server-transport.js';
3
- export { createClientTransport } from './client-transport.js';
1
+ export type { ActiveRun, AgentSession, AgentSessionOptions, BranchSelection, CancelRequest, ClientSession, ClientSessionOptions, ConversationNode, EventsNode, InputNode, LoadConversationOptions, MessageNode, OutputEvent, PipeOptions, Run, RunEndReason, RunInfo, RunLifecycleEvent, RunNode, RunRuntime, RunView, SendOptions, StreamResult, Tree, View, } from './types.js';
2
+ export type { InvocationData } from './invocation.js';
3
+ export { Invocation } from './invocation.js';
4
+ export { createAgentSession } from './agent-session.js';
5
+ export { createClientSession } from './client-session.js';
4
6
  export { buildTransportHeaders } from './headers.js';
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Helpers for FIFO-bounded `Map`s — Maps used as capacity-limited buffers that
3
+ * must evict their oldest entry when full.
4
+ */
5
+ /**
6
+ * Make room for a new key in a FIFO-bounded map: if `map` is at (or over)
7
+ * `limit` and does not already contain `key`, evict the oldest entry (insertion
8
+ * order) and return its key so the caller can log the eviction. Returns
9
+ * `undefined` when nothing was evicted (the key already exists, the map is
10
+ * below the limit, or it is empty).
11
+ *
12
+ * The caller performs the actual set/append afterwards — this only frees a
13
+ * slot — so it works for maps whose values are replaced and for maps whose
14
+ * values are appended-to lists.
15
+ * @param map - The bounded map to evict from.
16
+ * @param key - The key about to be added; an existing key never evicts.
17
+ * @param limit - The maximum number of entries the map may hold.
18
+ * @returns The evicted key, or `undefined` if nothing was evicted.
19
+ */
20
+ export declare const evictOldestIfFull: <K, V>(map: Map<K, V>, key: K, limit: number) => K | undefined;
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Invocation — value object wrapping the JSON body that a client sends to
3
+ * an agent's HTTP endpoint to start a run.
4
+ *
5
+ * The data shape is the wire contract; the {@link Invocation} class is a
6
+ * runtime view of that data with the same fields. {@link Invocation.fromJSON}
7
+ * is the entry point used by agent handlers:
8
+ *
9
+ * ```ts
10
+ * const data = (await req.json()) as InvocationData;
11
+ * const invocation = Invocation.fromJSON(data);
12
+ * const run = session.createRun(invocation, { signal: req.signal });
13
+ * await run.start();
14
+ * await run.loadProjection(); // fetch run projection from the channel
15
+ * const messages = run.messages;
16
+ * ```
17
+ *
18
+ * The body carries only what the agent needs out-of-band before the channel
19
+ * is observable: the session/channel name and the `inputEventId` that triggered
20
+ * the invocation. The agent mints the `invocationId` itself (one per HTTP
21
+ * request) and returns it on the HTTP response, so it is not a body field. Run
22
+ * identity also lives on the channel: the agent mints the `runId` for a fresh
23
+ * run and reads the existing `runId` off the triggering input event for a
24
+ * continuation — so the body carries no run-id either. Per-message metadata —
25
+ * `clientId`, `parent`, `forkOf`, continuation status — likewise lives on the
26
+ * channel and is resolved by the agent from the triggering input event, not
27
+ * from the body. The `inputClientId` the agent re-stamps on its own publishes
28
+ * comes from the publisher's Ably `clientId` on the matched input event, not
29
+ * from a body field.
30
+ */
31
+ /**
32
+ * Wire shape of a single invocation — the JSON body sent from the client
33
+ * transport's HTTP POST to the agent endpoint.
34
+ */
35
+ export interface InvocationData {
36
+ /**
37
+ * Identifier for the specific input event on the channel that triggered
38
+ * this invocation. The agent locates the event via the `event-id`
39
+ * header. Its wire headers carry the run-id for a continuation (absent for
40
+ * a fresh run), so run identity is resolved from the channel, not the body.
41
+ */
42
+ inputEventId: string;
43
+ /** Logical name of the session (chat) — used as the Ably channel name. */
44
+ sessionName: string;
45
+ }
46
+ /**
47
+ * Runtime view of an {@link InvocationData}. Constructed via
48
+ * {@link Invocation.fromJSON}. Read-only; carries no behaviour beyond
49
+ * exposing its fields.
50
+ */
51
+ export declare class Invocation {
52
+ /**
53
+ * Identifier for the specific input event on the channel that triggered
54
+ * this invocation. Run identity is resolved from that event's wire headers
55
+ * (or minted), not from the body.
56
+ */
57
+ readonly inputEventId: string;
58
+ /** Logical name of the session (chat). Used as the Ably channel name. */
59
+ readonly sessionName: string;
60
+ private constructor();
61
+ /**
62
+ * Build an Invocation from its JSON wire shape.
63
+ * @param data - Parsed JSON body matching {@link InvocationData}.
64
+ * @returns A new Invocation exposing the same fields.
65
+ */
66
+ static fromJSON(data: InvocationData): Invocation;
67
+ /**
68
+ * Serialise this invocation to its JSON wire shape — the body a client
69
+ * POSTs to the agent's endpoint to wake a run. Round-trips through
70
+ * {@link Invocation.fromJSON}.
71
+ * @returns The {@link InvocationData} carrying this invocation's identity.
72
+ */
73
+ toJSON(): InvocationData;
74
+ }
@@ -0,0 +1,128 @@
1
+ import { Logger } from '../../logger.js';
2
+ import { Codec, CodecInputEvent, CodecOutputEvent } from '../codec/types.js';
3
+ /**
4
+ * Agent-side conversation reconstruction from the channel wire log.
5
+ *
6
+ * When an agent wakes (or resumes) it has no in-memory tree — it rebuilds the
7
+ * state it needs by paging channel history and folding the wires through the
8
+ * codec. Two entry points:
9
+ *
10
+ * - {@link loadRunProjection} — fold a single run's wires into one projection
11
+ * (used to resume a suspended run with its client tool-output amends).
12
+ * - {@link loadConversation} — walk the structural parent chain from the
13
+ * current run's input node to the root and fold each node, producing the full
14
+ * multi-turn message history along the taken branch.
15
+ *
16
+ * Both reuse {@link foldMessageInto} (the shared per-message fold primitive) and
17
+ * {@link buildBranchChain} (the shared parent-chain walk), so the agent's
18
+ * reconstruction can't drift from the client/View decode paths.
19
+ */
20
+ import * as Ably from 'ably';
21
+ /**
22
+ * Merge messages observed live (e.g. by the input-event lookup) into a set of
23
+ * collected history messages, dedup by serial, and sort chronologically.
24
+ *
25
+ * History messages take priority in deduplication (history serial wins if the
26
+ * same message appears in both). Messages without a serial are dropped because
27
+ * they cannot be reliably ordered.
28
+ * @param collected - Raw messages from channel.history (any order).
29
+ * @param live - Messages observed live (e.g. by the input-event lookup); may be undefined.
30
+ * @returns Deduplicated, chronologically sorted messages.
31
+ */
32
+ export declare const withLiveMessages: (collected: readonly Ably.InboundMessage[], live?: readonly Ably.InboundMessage[]) => Ably.InboundMessage[];
33
+ /**
34
+ * Fold a pre-sorted array of wire messages for a single run into a projection.
35
+ *
36
+ * Skips lifecycle events (they carry no codec content) and stops before the
37
+ * message whose `codec-message-id` equals `truncateAt` (exclusive — that
38
+ * message is not folded). Used by both {@link loadRunProjection} (no
39
+ * truncation) and {@link loadConversation} (per-ancestor folding).
40
+ * @param codec - Codec used to decode and fold events.
41
+ * @param sortedMessages - Chronologically ordered wire messages (all runs).
42
+ * @param runId - Only messages stamped with this run-id are folded.
43
+ * @param truncateAt - Stop before this codec-message-id; omit to fold all messages.
44
+ * @returns The projection and the count of messages that were folded.
45
+ */
46
+ export declare const foldRunMessages: <TInput extends CodecInputEvent, TOutput extends CodecOutputEvent, TProjection, TMessage>(codec: Codec<TInput, TOutput, TProjection, TMessage>, sortedMessages: readonly Ably.InboundMessage[], runId: string, truncateAt?: string) => {
47
+ projection: TProjection;
48
+ folded: number;
49
+ };
50
+ /**
51
+ * Fold a single run-less INPUT node's events into a fresh projection: every
52
+ * wire stamped with `codecMessageId` and NO run-id (the user prompt the client
53
+ * published before the agent minted a run-id). The two-node analogue of
54
+ * {@link foldRunMessages} for the user-input side of the conversation chain.
55
+ * @param codec - Codec used to decode and fold events.
56
+ * @param sortedMessages - Chronologically ordered wire messages (all runs).
57
+ * @param codecMessageId - The input node's codec-message-id.
58
+ * @returns The folded projection for that input node.
59
+ */
60
+ export declare const foldInputMessages: <TInput extends CodecInputEvent, TOutput extends CodecOutputEvent, TProjection, TMessage>(codec: Codec<TInput, TOutput, TProjection, TMessage>, sortedMessages: readonly Ably.InboundMessage[], codecMessageId: string) => TProjection;
61
+ /**
62
+ * Fetch all messages on the channel that belong to `runId`, decode them
63
+ * through the codec, and fold them into a single projection. Used by the agent
64
+ * to reconstruct a run's full state — including client-published tool-output
65
+ * amends — when resuming a suspended run in a fresh agent session.
66
+ *
67
+ * Doesn't require channel rewind: an explicit `channel.history()` call returns
68
+ * the same data even if the channel is already attached from a prior session.
69
+ * @param opts - Load parameters.
70
+ * @param opts.channel - The Ably channel to read history from.
71
+ * @param opts.codec - Codec used to decode and fold events.
72
+ * @param opts.runId - Run identifier whose events should be folded.
73
+ * @param opts.signal - AbortSignal checked once at entry: if already aborted the call throws immediately and no history is fetched. It does not interrupt an in-flight load.
74
+ * @param opts.logger - Optional logger for diagnostic output.
75
+ * @param opts.liveMessages - Raw Ably messages already observed live (e.g. by
76
+ * the input-event lookup). Folded alongside the history fetch so just-published
77
+ * client wires don't depend on Ably's history-indexing window.
78
+ * @returns The projection produced by folding all run events in serial order.
79
+ * @throws {Ably.ErrorInfo} with code ErrorCode.InvalidArgument if `signal` is already aborted at entry (the run was cancelled before loading began).
80
+ */
81
+ export declare const loadRunProjection: <TInput extends CodecInputEvent, TOutput extends CodecOutputEvent, TProjection, TMessage>(opts: {
82
+ channel: Ably.RealtimeChannel;
83
+ codec: Codec<TInput, TOutput, TProjection, TMessage>;
84
+ runId: string;
85
+ signal: AbortSignal;
86
+ logger: Logger | undefined;
87
+ liveMessages?: readonly Ably.InboundMessage[];
88
+ }) => Promise<TProjection>;
89
+ /**
90
+ * Reconstruct the full multi-turn conversation history along the branch the
91
+ * current run sits on.
92
+ *
93
+ * Pages channel history (merging live lookup messages), indexes each
94
+ * codec-message-id's structural parent and run-id with sticky identity (the
95
+ * first wire wins; later amends can't poison it), backfills a reply run's
96
+ * parent from its `ai-run-start` when the output wire wasn't indexed, then
97
+ * walks the structural parent chain from the current run's input node
98
+ * (`assistantParentFallback`) to the root and folds each node in chain order.
99
+ * The current run is folded once, wholesale, at the tail.
100
+ * @param opts - Reconstruction parameters.
101
+ * @param opts.channel - The Ably channel to read history from.
102
+ * @param opts.codec - Codec used to decode and fold events.
103
+ * @param opts.runId - The current run's id.
104
+ * @param opts.signal - AbortSignal checked once at entry; if already aborted the call throws before any history is fetched. It does not interrupt an in-flight load.
105
+ * @param opts.logger - Optional logger for diagnostic output.
106
+ * @param opts.liveMessages - Wires already observed live, merged into history.
107
+ * @param opts.assistantParentFallback - The current run's input node
108
+ * (codec-message-id) — the anchor the parent-chain walk starts from. When
109
+ * undefined, only the current run is folded.
110
+ * @param opts.pageLimit - Messages requested per history page.
111
+ * @param opts.maxMessages - Stop paging once this many messages are collected.
112
+ * @returns The branch's messages (root-first) and the current run's projection.
113
+ * @throws {Ably.ErrorInfo} with code ErrorCode.InvalidArgument when `signal` is already aborted at entry.
114
+ */
115
+ export declare const loadConversation: <TInput extends CodecInputEvent, TOutput extends CodecOutputEvent, TProjection, TMessage>(opts: {
116
+ channel: Ably.RealtimeChannel;
117
+ codec: Codec<TInput, TOutput, TProjection, TMessage>;
118
+ runId: string;
119
+ signal: AbortSignal;
120
+ logger: Logger | undefined;
121
+ liveMessages: readonly Ably.InboundMessage[] | undefined;
122
+ assistantParentFallback: string | undefined;
123
+ pageLimit: number;
124
+ maxMessages: number;
125
+ }) => Promise<{
126
+ messages: TMessage[];
127
+ projection: TProjection;
128
+ }>;
@@ -0,0 +1,39 @@
1
+ import { Logger } from '../../logger.js';
2
+ import { HistoryPage, LoadHistoryOptions } from './types.js';
3
+ /**
4
+ * loadHistory — load conversation history from an Ably channel and return
5
+ * the raw wire messages as a paginated HistoryPage result.
6
+ *
7
+ * This does NOT decode: it pages back through Ably history until `limit`
8
+ * complete messages are present, then hands the raw Ably messages
9
+ * (oldest-first) to the caller. The View re-decodes them into the Tree
10
+ * itself, so load-history only needs a cheap, header-based completion
11
+ * counter to decide when to stop paging — the decoder never runs here.
12
+ *
13
+ * The `limit` option controls the number of complete **messages** per page,
14
+ * not the number of Ably wire messages fetched. A message is complete when
15
+ * its terminal wire signal — `status: "complete"` / `"cancelled"`, or a
16
+ * `discrete` create — has been seen. Runs that span a
17
+ * page boundary are handled by the counter requiring both a start and a
18
+ * terminal signal before counting a message complete.
19
+ *
20
+ * Because Ably history returns newest-first, each page's `rawMessages` are
21
+ * reversed to chronological (oldest-first) so the caller can fold them in
22
+ * order.
23
+ */
24
+ import type * as Ably from 'ably';
25
+ /**
26
+ * Load conversation history from a channel and return the raw wire messages.
27
+ *
28
+ * Attaches the channel if not already attached, then calls
29
+ * `channel.history({ untilAttach: true })` to guarantee no gap between
30
+ * historical and live messages. The attach is idempotent.
31
+ *
32
+ * The `limit` option controls the number of complete messages
33
+ * returned per page, not the number of Ably wire messages fetched.
34
+ * @param channel - The Ably channel to load history from.
35
+ * @param options - Pagination options.
36
+ * @param logger - Logger for diagnostic output.
37
+ * @returns The first page of raw history messages.
38
+ */
39
+ export declare const loadHistory: (channel: Ably.RealtimeChannel, options: LoadHistoryOptions | undefined, logger: Logger) => Promise<HistoryPage>;
@@ -1,16 +1,17 @@
1
1
  import { Logger } from '../../logger.js';
2
- import { StreamEncoder } from '../codec/types.js';
2
+ import { CodecInputEvent, CodecOutputEvent, Encoder, WriteOptions } from '../codec/types.js';
3
3
  import { StreamResult } from './types.js';
4
4
  /**
5
- * Pipe an event stream through an encoder to the channel.
5
+ * Pipe an output stream through an encoder to the channel.
6
6
  *
7
7
  * Returns when the stream completes, is cancelled (via signal), or errors.
8
8
  * The `reason` field of the result indicates which case occurred.
9
- * @param stream - The event stream to read from.
10
- * @param encoder - The streaming encoder to write events through.
11
- * @param signal - Abort signal to monitor for cancellation.
12
- * @param onAbort - Optional callback invoked when the stream is cancelled, before the stream ends.
9
+ * @param stream - The output stream to read from.
10
+ * @param encoder - The encoder to publish outputs through.
11
+ * @param signal - AbortSignal to monitor for cancellation.
12
+ * @param onCancelled - Optional callback invoked when the stream is cancelled, before the stream ends.
13
+ * @param resolveWriteOptions - Optional per-output hook returning {@link WriteOptions} overrides to pass to `encoder.publishOutput`.
13
14
  * @param logger - Optional logger for diagnostic output.
14
- * @returns The reason the pipe ended.
15
+ * @returns A {@link StreamResult}: `reason` is why the pipe ended, and `error` holds the caught error when `reason` is `'error'`.
15
16
  */
16
- export declare const pipeStream: <TEvent, TMessage>(stream: ReadableStream<TEvent>, encoder: StreamEncoder<TEvent, TMessage>, signal: AbortSignal | undefined, onAbort?: (write: (event: TEvent) => Promise<void>) => void | Promise<void>, logger?: Logger) => Promise<StreamResult>;
17
+ export declare const pipeStream: <TInput extends CodecInputEvent, TOutput extends CodecOutputEvent>(stream: ReadableStream<TOutput>, encoder: Encoder<TInput, TOutput>, signal: AbortSignal | undefined, onCancelled?: (write: (output: TOutput) => Promise<void>) => void | Promise<void>, resolveWriteOptions?: (output: TOutput) => WriteOptions | undefined, logger?: Logger) => Promise<StreamResult>;
@@ -0,0 +1,78 @@
1
+ import { Logger } from '../../logger.js';
2
+ import { RunEndReason } from './types.js';
3
+ /**
4
+ * Server-side run state management and lifecycle event publishing.
5
+ *
6
+ * Owns the authoritative run lifecycle. Tracks active runs with their
7
+ * AbortControllers and clientIds. Publishes run-start, run-resume, run-suspend, and
8
+ * run-end events on the Ably channel so all clients can react to run
9
+ * state changes.
10
+ */
11
+ import type * as Ably from 'ably';
12
+ /**
13
+ * Per-invocation metadata carried on a run's opening lifecycle event. A
14
+ * continuation (re-entering an existing run) sets `continuation` and omits the
15
+ * structural `parent` / `forkOf` / `regenerates` fields.
16
+ */
17
+ export interface StartRunMetadata {
18
+ /** Structural parent codec-message-id (fresh run-start only). */
19
+ parent?: string;
20
+ /** Forked user-prompt codec-message-id for an edit (fresh run-start only). */
21
+ forkOf?: string;
22
+ /** Regenerated assistant codec-message-id (fresh run-start only). */
23
+ regenerates?: string;
24
+ /** Agent-minted invocation id, carried on the lifecycle event. */
25
+ invocationId?: string;
26
+ /** ClientId of the triggering input event. */
27
+ inputClientId?: string;
28
+ /** Codec-message-id of the triggering input event. */
29
+ inputCodecMessageId?: string;
30
+ /** When true, publish `ai-run-resume` (re-entry) instead of `ai-run-start`. */
31
+ continuation?: boolean;
32
+ }
33
+ /** Manages active runs and publishes run lifecycle events on the channel. */
34
+ export interface RunManager {
35
+ /**
36
+ * Register a run and publish its opening lifecycle event. Publishes
37
+ * `ai-run-start` for a fresh run, or `ai-run-resume` when `metadata.continuation`
38
+ * is set (a subsequent invocation re-entering an existing run). A resume omits
39
+ * the structural `parent` / `forkOf` / `regenerates` headers — the original
40
+ * run-start owns the run's structure. Returns the run's AbortSignal.
41
+ */
42
+ startRun(runId: string, clientId?: string, controller?: AbortController, metadata?: StartRunMetadata): Promise<AbortSignal>;
43
+ /**
44
+ * Suspend a run. Publishes run-suspend on the channel and drops the run's
45
+ * active-run entry — the agent process terminates on suspend, so there is no
46
+ * live AbortController to retain. A cancel arriving during suspension is a
47
+ * no-op; the resuming invocation re-registers the run via {@link startRun}.
48
+ * Carries the same per-invocation attribution as {@link endRun}
49
+ * (`inputClientId`, `inputCodecMessageId`), since a suspend is the terminal
50
+ * event of the suspending invocation just as run-end is of an ending one.
51
+ */
52
+ suspendRun(runId: string, invocationId?: string, inputClientId?: string, inputCodecMessageId?: string): Promise<void>;
53
+ /**
54
+ * End a run. Publishes run-end on the channel (stamping `reason` as the
55
+ * run-reason header) and drops the run's active-run entry. Carries the same
56
+ * per-invocation attribution as {@link suspendRun} (`invocationId`,
57
+ * `inputClientId`, `inputCodecMessageId`), since run-end is the terminal event
58
+ * of the ending invocation.
59
+ */
60
+ endRun(runId: string, reason: RunEndReason, invocationId?: string, inputClientId?: string, inputCodecMessageId?: string): Promise<void>;
61
+ /** Get the AbortSignal for a run. */
62
+ getSignal(runId: string): AbortSignal | undefined;
63
+ /** Get the clientId that owns a run. */
64
+ getClientId(runId: string): string | undefined;
65
+ /** Fire the AbortSignal for a run to cancel any in-flight work. */
66
+ cancel(runId: string): void;
67
+ /** Get all active run IDs. */
68
+ getActiveRunIds(): string[];
69
+ /** Cancel all active runs and clear state. */
70
+ close(): void;
71
+ }
72
+ /**
73
+ * Create a run manager bound to the given channel.
74
+ * @param channel - The Ably channel to publish lifecycle events on.
75
+ * @param logger - Optional logger for diagnostic output.
76
+ * @returns A new {@link RunManager} instance.
77
+ */
78
+ export declare const createRunManager: (channel: Ably.RealtimeChannel, logger?: Logger) => RunManager;