experimental-a2 0.2.0 → 0.4.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 (92) hide show
  1. package/CHANGELOG.md +169 -0
  2. package/dist/ai-B4YhEnfw.d.ts +333 -0
  3. package/dist/ai-server.d.ts +48 -9
  4. package/dist/ai-server.js +121 -49
  5. package/dist/ai.d.ts +2 -303
  6. package/dist/ai.js +231 -86
  7. package/dist/cli-B3VuxoDe.js +597 -0
  8. package/dist/cli-bin.d.ts +1 -0
  9. package/dist/cli-bin.js +5 -0
  10. package/dist/cli.d.ts +19 -0
  11. package/dist/cli.js +2 -0
  12. package/dist/client-BrfDXQ8A.d.ts +155 -0
  13. package/dist/client-Bt4tAKi9.js +798 -0
  14. package/dist/client.d.ts +2 -90
  15. package/dist/client.js +1 -409
  16. package/dist/{contract-CG_adnu_.js → contract-48bUMgcL.js} +10 -2
  17. package/dist/{contract-C_3dIIEU.d.ts → contract-jIfaR085.d.ts} +62 -8
  18. package/dist/devtools-J_jZ2vQf.d.ts +151 -0
  19. package/dist/devtools-kJJaORn-.js +338 -0
  20. package/dist/devtools-server.browser.js +1 -1
  21. package/dist/devtools-server.d.ts +2 -2
  22. package/dist/devtools-server.js +224 -43
  23. package/dist/devtools.d.ts +2 -0
  24. package/dist/devtools.js +2 -0
  25. package/dist/{errors-BJRMd-h6.js → errors-BQuJpe82.js} +4 -4
  26. package/dist/{errors-xL_JTXsY.d.ts → errors-W6nwJ-fm.d.ts} +1 -1
  27. package/dist/http.d.ts +71 -13
  28. package/dist/http.js +302 -41
  29. package/dist/{idempotent-replay-BMyHrP0L.js → idempotent-replay-DuqEkYA7.js} +2 -2
  30. package/dist/index.d.ts +5 -5
  31. package/dist/index.js +2 -2
  32. package/dist/{inspection-E7qbD0Xj.js → inspection-DaxB5jM2.js} +2 -1
  33. package/dist/internal-aEotMzu_.js +209 -0
  34. package/dist/otel.d.ts +1 -1
  35. package/dist/platform-B4TnJtWu.js +32 -0
  36. package/dist/react.d.ts +37 -14
  37. package/dist/react.js +26 -15
  38. package/dist/scheduler-qstash.d.ts +78 -0
  39. package/dist/scheduler-qstash.js +499 -0
  40. package/dist/scheduler-task-BpzhPnRS.js +54 -0
  41. package/dist/{recovery-vercel.d.ts → scheduler-vercel.d.ts} +17 -24
  42. package/dist/scheduler-vercel.js +226 -0
  43. package/dist/server-CcNnFnoW.js +1405 -0
  44. package/dist/server-YtPq7hjw.d.ts +260 -0
  45. package/dist/server.d.ts +4 -155
  46. package/dist/server.js +2 -2
  47. package/dist/{log-ldf5g8Cx.d.ts → store-C3sNAaBT.d.ts} +111 -35
  48. package/dist/{log-yJbXUf72.js → store-N8PXxDAS.js} +1 -1
  49. package/dist/store-codec-DTG0Ftek.js +8 -0
  50. package/dist/store-memory.d.ts +11 -0
  51. package/dist/{log-memory.js → store-memory.js} +127 -24
  52. package/dist/{log-polling-6COoN60V.js → store-polling-DgrrAE3d.js} +7 -6
  53. package/dist/{log-postgres.d.ts → store-postgres.d.ts} +6 -6
  54. package/dist/{log-postgres.js → store-postgres.js} +158 -24
  55. package/dist/{log-redis.js → store-redis-core-DWqx3F47.js} +294 -156
  56. package/dist/store-redis-http.d.ts +21 -0
  57. package/dist/store-redis-http.js +70 -0
  58. package/dist/store-redis.d.ts +37 -0
  59. package/dist/store-redis.js +298 -0
  60. package/dist/{log-sqlite.d.ts → store-sqlite.d.ts} +6 -6
  61. package/dist/{log-sqlite.js → store-sqlite.js} +116 -22
  62. package/dist/{telemetry-Cso0qyHQ.d.ts → telemetry-BjYHTfh2.d.ts} +1 -1
  63. package/dist/testing.browser.d.ts +1 -0
  64. package/dist/testing.browser.js +4 -0
  65. package/dist/testing.d.ts +31 -0
  66. package/dist/testing.js +101 -0
  67. package/dist/wire-DCUZBUlT.js +222 -0
  68. package/docs/01-quickstart.mdx +4 -5
  69. package/docs/concepts/01-contracts.mdx +21 -17
  70. package/docs/concepts/02-handlers.mdx +7 -7
  71. package/docs/concepts/03-durability.mdx +26 -29
  72. package/docs/concepts/04-state.mdx +18 -21
  73. package/docs/guides/01-timers.mdx +154 -54
  74. package/docs/guides/02-cancellation.mdx +30 -4
  75. package/docs/guides/03-react.mdx +20 -21
  76. package/docs/guides/04-local-first.mdx +1 -1
  77. package/docs/guides/05-production.mdx +321 -60
  78. package/docs/guides/06-ai-agents.mdx +249 -49
  79. package/docs/guides/07-devtools.mdx +137 -12
  80. package/docs/guides/08-application-data.mdx +1 -1
  81. package/docs/guides/09-presence.mdx +284 -0
  82. package/docs/guides/10-transports.mdx +131 -0
  83. package/docs/index.mdx +22 -46
  84. package/docs/reference/01-api.mdx +751 -102
  85. package/docs/reference/02-errors.mdx +10 -5
  86. package/package.json +23 -6
  87. package/dist/internal-D6wNxTck.js +0 -36
  88. package/dist/log-memory.d.ts +0 -11
  89. package/dist/log-redis.d.ts +0 -31
  90. package/dist/recovery-vercel.js +0 -119
  91. package/dist/server-DJgD2YWP.js +0 -877
  92. package/dist/wire-BVsgR8o9.js +0 -62
package/CHANGELOG.md CHANGED
@@ -1,5 +1,174 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.4.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 0640425: Replace the A2 `tool()` wrapper with ambient handler context for plain AI SDK
8
+ tools. Tools are now ordinary `tool()` definitions from `ai`; inside a local
9
+ `execute`, `handlerContext(agent)` from `experimental-a2/ai` returns the
10
+ durable `AgentToolContext` (verified against the executing server's contract),
11
+ and `runWithHandlerContext(ctx, fn)` from `experimental-a2/ai/server` makes
12
+ tools directly testable. `tool()`, `AgentToolOptions`, and the agent-binding
13
+ construction checks are removed, and the model-phase option bans are lifted:
14
+ `contextSchema`, dynamic `description`, `needsApproval` predicates, input
15
+ lifecycle callbacks, and generation `toolsContext` now pass through to the AI
16
+ SDK untouched. Approval predicates are re-evaluated on recovery for the same
17
+ durable tool call, so they must be deterministic over the tool input.
18
+ - d0c5323: Add a typed `messageMetadata` mapper to the default AI SDK generator so
19
+ assistant stream metadata, including final usage, can be durably projected.
20
+ - 870dbd5: Add agent-bound `tool()` definitions whose local executors receive the current
21
+ durable A2 handler context. The playground agent now demonstrates the API by
22
+ scheduling reminders that return as new user messages.
23
+ - 4c11535: Add indexed `gte` and `lte` history ranges and rename the exclusive stream
24
+ cursor from `startAt` to `startAfter`.
25
+ - 0c3d861: Rename the configured storage and delivery primitives across the public API.
26
+ `log` is now `store`, `recovery` is now `scheduler`, built-in adapter entry
27
+ points move to `experimental-a2/store-*` and
28
+ `experimental-a2/scheduler-vercel`, and the corresponding public types and
29
+ error codes use `Store` and `Scheduler` names. This is a breaking rename with
30
+ no persisted storage or queue-message format change.
31
+ - 2a1743a: Add versioned Devtools captures, the `a2 devtools` read-only CLI, offline reducer replay helpers, conservative authorization that opens without a callback only when `NODE_ENV` is exactly `development`, and fixed-frontier pagination that keeps Redis reads, reducer state, session summaries, detail, and exports complete beyond provider range limits.
32
+ - 589c361: Fence the public AI projection against stale lifecycle events after generation
33
+ failure, interruption, and attempt supersession. Interrupted responses now keep
34
+ only the exact visible frontier across post-step tool, approval, and
35
+ application-input barriers and across failure races, preserve terminal tool
36
+ results, restore the committed message and compaction base for retries, and
37
+ clear failed pending inputs without allowing delayed events to corrupt a later
38
+ model step.
39
+ Clients identify a requested response with its active `requestId` and a
40
+ started response with its exact `generationId`. A request-owned interruption
41
+ remains valid if that same request starts before the interruption commits.
42
+ The response message and owner IDs must identify the same work.
43
+ `AIState` exposes optional terminal request and generation ownership maps. The
44
+ built-in public and coordinator reducers use new versioned names so stored
45
+ snapshots refold under these semantics.
46
+ - 75bf51a: Fence handler appends by attempt currency and abort superseded runs. A
47
+ `ctx.session.append` from an attempt a recovery claim has replaced now
48
+ rejects with `SUPERSEDED_ATTEMPT` instead of landing stale events —
49
+ atomically, in the store's append operation — while exact retries of
50
+ already-committed batches still replay idempotently. `ctx.signal` is now
51
+ live for every handler and aborts with a `SUPERSEDED_ATTEMPT` reason when
52
+ the claim heartbeat learns a newer attempt owns the event; `abortOn`
53
+ remains the additional user-cancellation source. Custom store adapters:
54
+ `append` must implement the fence, and `renewClaims` now takes
55
+ `{ index, attempt }` pairs and returns `{ renewed, superseded }`.
56
+ - 22534c2: Self-fence at local lease lapse and retry failed renewals promptly. A
57
+ handler whose claim lapses without renewal now gets its `ctx.signal`
58
+ aborted with a `CLAIM_EXPIRED` reason, decided by the local clock with
59
+ zero I/O — so it fires during store outages and in the first tick after
60
+ an event-loop stall, before any round trip could report back. A failed
61
+ heartbeat renewal retries after a short jittered delay while the lease
62
+ can still be saved instead of waiting out the next scheduled beat. A
63
+ lapsed-but-unsuperseded attempt that returns normally still completes;
64
+ proven supersession remains what releases the drain.
65
+ - a7a3818: Add passive user messages with `inputs.message(message, { generate: false })`
66
+ and make `inputs.seed()` record context without scheduling a user turn.
67
+ Passive user messages join the prompt when a later generating message advances
68
+ the ordered conversation frontier.
69
+ - f84cbe8: Presence: the ephemeral plane. Contracts grow an optional `presence`
70
+ field-schema map; sessions gain `setPresence(patch)`, `presence()`, and
71
+ `stream({ presence: true })` (one snapshot frame, then live patches
72
+ interleaved with events); `useSession` gains `presence`/`setPresence`,
73
+ typed from the contract with no type arguments and existing only on
74
+ presence-declaring contracts. Per-participant state replicates
75
+ last-writer-wins per field, stamped with the sender's stream frontier
76
+ (`seen`), and never touches the log: no index, no history, no folds, no
77
+ scheduler arm, no browser cache. Backed by an optional `A2Store.presence`
78
+ capability: push tier on `store-redis` (pub/sub beside the notify
79
+ channel) and `store-memory`; degraded poll-merge tier on `store-postgres`,
80
+ `store-sqlite`, and `store-redis-http`. `parsePushBody` accepts a branded
81
+ `presence` sibling (presence-only pushes valid); `sseResponse` rides it
82
+ as named SSE frames old clients skip. New error codes:
83
+ `UNKNOWN_PRESENCE_FIELD`, `PRESENCE_NOT_SUPPORTED`. Also fixes a latent
84
+ `store-redis` subscriber-handshake race (channel commands could beat the
85
+ ready check).
86
+ - 817d636: Make `qstash()` zero-config in local Node.js development by inferring its
87
+ conventional localhost callback and enabling the QStash SDK development server.
88
+ Infer Vercel production and preview callbacks, and disable SDK development mode
89
+ in production. For inferred previews, opportunistically forward a fresh-enough
90
+ invocation identity for Vercel Trusted Sources and request redaction from the
91
+ QStash dashboard and API.
92
+ Allow static callback headers with automatic provider redaction, or a configured
93
+ QStash publishing client while A2 keeps the default signature receiver.
94
+ Require `@upstash/qstash` 2.11.0 or newer so both redaction and zero-config local
95
+ development are enforced by the peer range.
96
+ - 1d0aa9c: Add first-party delayed events with `session.schedule()`. Configured scheduler
97
+ adapters now deliver both recovery watchdogs and named, typed timer events.
98
+ Scheduler routes use `schedulerHandler(...)`, which rejects mismatched adapter
99
+ wiring before accepting deliveries.
100
+ - ac007ed: Drop the pre-versioning kindless drain envelope: scheduler routes now accept
101
+ only the versioned task union, and `dueAt` is required on `SchedulerDrainTask`.
102
+ The `DrainMessage` type exports and the `delaySeconds` fallback options are
103
+ removed from both scheduler adapters (`vercelQueues` keeps its documented
104
+ unsettled-redelivery backoff with a fixed base). In-flight kindless watchdogs
105
+ from earlier versions are rejected at delivery; affected sessions heal on
106
+ their next append or explicit drain.
107
+ - d3b3f8d: Remove the default agent response step limit. Set `maxSteps` to a positive
108
+ integer when a response needs an explicit bound.
109
+ - c446705: Add `experimental-a2/scheduler-qstash`, a QStash-backed scheduler adapter with
110
+ authenticated callback delivery, delayed watchdogs, and deterministic publish
111
+ deduplication.
112
+ - 62018f1: Transports: the `ws` wire. `createClient`'s `api` becomes the
113
+ documented `ClientApi` union — a string (one route: GET SSE + POST
114
+ push), `{ type: 'http', push, stream }` (split routes for per-route
115
+ duration limits), or `{ type: 'ws', url }` (one WebSocket, both
116
+ directions: the stream down, pushes and presence up, each presence
117
+ send a socket frame instead of a route invocation). Everything above
118
+ the wire seam — optimistic pushes with ack and `confirmed`,
119
+ frontier-resumed reads, reconnect with backoff, the stall watchdog,
120
+ the presence throttle and re-send — is transport-agnostic and behaves
121
+ identically on every wire. `experimental-a2/http` gains
122
+ `sessionSocket(session, socket, { startAfter?, presence?, deadline? })`,
123
+ which speaks the frame protocol (event / presence / presence-snapshot
124
+ / ack / ping down; push / presence up) against any structurally
125
+ `ws`-shaped socket and validates pushes exactly as `parsePushBody`
126
+ does — same brands, same per-plane `validatePush` calls; the platform
127
+ upgrade API stays out of the library. `createClient` gains a
128
+ `webSocket` injectable mirroring `fetch`. In-flight pushes that lose
129
+ their socket reject retryably as `STORE_UNAVAILABLE`; client-generated
130
+ event ids make retries idempotent.
131
+
132
+ ### Patch Changes
133
+
134
+ - 0664146: Harden the lease machinery against three adversarial-review findings. A
135
+ drain that re-claims its own lapsed event now fences the old attempt's
136
+ slot before the new one takes it, and continuations are
137
+ identity-guarded, so a settling zombie can no longer orphan the live
138
+ attempt from heartbeat coverage. A handler throw that is the signal's
139
+ own abort reason (object identity, never an error code) surrenders the
140
+ attempt — no completion, no failure budget — which makes passing
141
+ `ctx.signal` to `fetch` the correct default wiring; every other throw,
142
+ including store fence rejections, is adjudicated by the already-fenced
143
+ `failAttempt` instead of an in-process error-code check. The postgres
144
+ and sqlite `renewClaims` now require the listed attempt to match, so a
145
+ stale heartbeat can never extend or mask a successor's claim (the
146
+ conformance kit pins same-holder supersession on every backend). The
147
+ `a2.event` telemetry outcome set gains `surrendered`.
148
+ - a80ec55: Preserve invocation order when one session client makes overlapping
149
+ optimistic pushes.
150
+ - ae1fab7: Close SSE responses cleanly one second before an ambient Vercel invocation
151
+ deadline so clients reconnect from their last frontier without a
152
+ platform-timeout failure.
153
+ - 2181989: Pin Vercel Queue recovery and scheduled appends to their publishing deployment
154
+ by default, with an explicit `scheduledAppends: 'deploymentless'` opt-out for
155
+ applications that maintain cross-deployment timer compatibility.
156
+ - ef9b60e: Harden scheduler delivery across provider limits, deployment rollouts, retries,
157
+ and AI tool approval contexts.
158
+
159
+ ## 0.3.0
160
+
161
+ ### Minor Changes
162
+
163
+ - c2d7f17: Rework `experimental-a2/log-redis` streaming to notify + catch-up: writes to
164
+ watched sessions publish a disposable wake-up, one shared subscriber
165
+ connection per process serves every local feed, and a safety re-read heals
166
+ lost notifications — connections scale with processes, not concurrent
167
+ viewers. Add `experimental-a2/log-redis-http`: the same Redis Streams log
168
+ over a provider REST API (Upstash), connectionless, streaming via the shared
169
+ adaptive poll loop. Breaking for injected clients: `RedisConnection` gains
170
+ `on('message')` (`ioredis` already satisfies it).
171
+
3
172
  ## 0.2.0
4
173
 
5
174
  ### Minor Changes
@@ -0,0 +1,333 @@
1
+ import { a as EventDefs, h as StandardSchemaV1, n as Contract, p as Reducer, t as AppendInput } from "./contract-jIfaR085.js";
2
+ import { s as HandlerContext } from "./server-YtPq7hjw.js";
3
+ import { FinishReason, JSONValue, LanguageModelUsage, UIMessage as UIMessage$1, UIMessageChunk as UIMessageChunk$1 } from "ai";
4
+ //#region src/ai.d.ts
5
+ type AgentStatus = "idle" | "generating" | "waiting" | "failed" | "closed";
6
+ type GenerationReason = "message" | "tool" | "input" | "retry";
7
+ type SessionCreatedPayload = {
8
+ metadata?: JSONValue;
9
+ };
10
+ type SessionClosedPayload = {
11
+ reason?: string;
12
+ };
13
+ type MessageCreatedPayload<M extends UIMessage$1> = {
14
+ message: M;
15
+ /** For user messages, false records passive context. Omission or true schedules. */
16
+ generate?: boolean;
17
+ };
18
+ type MessageCompletedPayload = {
19
+ messageId: string;
20
+ };
21
+ type MessageInterruption = {
22
+ messageId: string;
23
+ reason?: string;
24
+ /** Last confirmed event-log index visible to the interrupter. */
25
+ lastSeenIndex?: number;
26
+ };
27
+ type MessageInterruptedPayload = MessageInterruption & ({
28
+ generationId: string;
29
+ requestId?: never;
30
+ } | {
31
+ requestId: string;
32
+ generationId?: never;
33
+ });
34
+ type GenerationRequestedPayload = {
35
+ messageId: string;
36
+ reason: GenerationReason;
37
+ responseMessageId?: string;
38
+ };
39
+ type RetryGenerationOptions = {
40
+ messageId: string;
41
+ responseMessageId: string;
42
+ retryId: string;
43
+ };
44
+ type RetryRequestedPayload = RetryGenerationOptions;
45
+ type GenerationStartedPayload = {
46
+ requestId: string;
47
+ messageId: string;
48
+ generationId: string;
49
+ responseMessageId: string;
50
+ attempt: number;
51
+ model: string;
52
+ };
53
+ type GenerationProgressPayload = {
54
+ requestId: string;
55
+ messageId: string;
56
+ generationId: string;
57
+ responseMessageId: string;
58
+ sequence: number;
59
+ chunks: UIMessageChunk$1[];
60
+ };
61
+ type GenerationCompletedPayload = {
62
+ requestId: string;
63
+ messageId: string;
64
+ generationId: string;
65
+ responseMessageId: string;
66
+ finishReason?: FinishReason;
67
+ usage?: LanguageModelUsage;
68
+ };
69
+ type GenerationFailedPayload = {
70
+ requestId: string;
71
+ messageId: string;
72
+ generationId: string;
73
+ responseMessageId: string;
74
+ error: string;
75
+ /** True when a later attempt replaced an incomplete attempt. */
76
+ superseded?: boolean;
77
+ stepLimit?: boolean;
78
+ };
79
+ type ToolCalledPayload = {
80
+ requestId: string;
81
+ messageId: string;
82
+ generationId: string;
83
+ toolCallId: string;
84
+ toolName: string;
85
+ input: unknown;
86
+ dynamic?: boolean;
87
+ providerExecuted?: boolean;
88
+ supportsDeferredResults?: boolean;
89
+ providerMetadata?: unknown;
90
+ toolMetadata?: unknown;
91
+ title?: string;
92
+ };
93
+ type ToolResultPayload = {
94
+ requestId: string;
95
+ messageId: string;
96
+ generationId: string;
97
+ toolCallId: string;
98
+ toolName?: string;
99
+ input?: unknown;
100
+ rawInput?: unknown;
101
+ output?: unknown;
102
+ error?: string;
103
+ denied?: boolean;
104
+ preliminary?: boolean;
105
+ phase?: "input" | "execution";
106
+ dynamic?: boolean;
107
+ providerExecuted?: boolean;
108
+ providerMetadata?: unknown;
109
+ toolMetadata?: unknown;
110
+ };
111
+ type ApprovalRequestedPayload = {
112
+ messageId: string;
113
+ generationId: string;
114
+ approvalId: string;
115
+ toolCallId: string;
116
+ isAutomatic?: boolean;
117
+ signature?: string;
118
+ };
119
+ type ApprovalRespondedPayload = {
120
+ messageId: string;
121
+ generationId: string;
122
+ approvalId: string;
123
+ approved: boolean;
124
+ reason?: string;
125
+ };
126
+ type InputRequestedPayload = {
127
+ messageId: string;
128
+ generationId: string;
129
+ inputId: string;
130
+ name: string;
131
+ question?: JSONValue;
132
+ };
133
+ type InputRespondedPayload = {
134
+ messageId: string;
135
+ generationId: string;
136
+ inputId: string;
137
+ name: string;
138
+ value: JSONValue;
139
+ };
140
+ type CompactionRequestedPayload = {
141
+ generationId: string;
142
+ throughMessageId: string;
143
+ };
144
+ type CompactionCompletedPayload<M extends UIMessage$1> = {
145
+ generationId: string;
146
+ throughMessageId: string;
147
+ messages: M[];
148
+ retainedMessageIds?: string[];
149
+ };
150
+ type AIEventDefs<M extends UIMessage$1 = UIMessage$1> = {
151
+ "ai.session.created": StandardSchemaV1<SessionCreatedPayload>;
152
+ "ai.session.closed": StandardSchemaV1<SessionClosedPayload>;
153
+ "ai.message.created": StandardSchemaV1<MessageCreatedPayload<M>>;
154
+ "ai.message.completed": StandardSchemaV1<MessageCompletedPayload>;
155
+ "ai.message.interrupted": StandardSchemaV1<MessageInterruptedPayload>;
156
+ "ai.generation.requested": StandardSchemaV1<GenerationRequestedPayload>;
157
+ "ai.retry.requested": StandardSchemaV1<RetryRequestedPayload>;
158
+ "ai.generation.started": StandardSchemaV1<GenerationStartedPayload>;
159
+ "ai.generation.progress": StandardSchemaV1<GenerationProgressPayload>;
160
+ "ai.generation.completed": StandardSchemaV1<GenerationCompletedPayload>;
161
+ "ai.generation.failed": StandardSchemaV1<GenerationFailedPayload>;
162
+ "ai.tool.called": StandardSchemaV1<ToolCalledPayload>;
163
+ "ai.tool.result": StandardSchemaV1<ToolResultPayload>;
164
+ "ai.approval.requested": StandardSchemaV1<ApprovalRequestedPayload>;
165
+ "ai.approval.responded": StandardSchemaV1<ApprovalRespondedPayload>;
166
+ "ai.input.requested": StandardSchemaV1<InputRequestedPayload>;
167
+ "ai.input.responded": StandardSchemaV1<InputRespondedPayload>;
168
+ "ai.compaction.requested": StandardSchemaV1<CompactionRequestedPayload>;
169
+ "ai.compaction.completed": StandardSchemaV1<CompactionCompletedPayload<M>>;
170
+ };
171
+ type ActiveGeneration = GenerationStartedPayload;
172
+ type ActiveGenerationProjection<M extends UIMessage$1 = UIMessage$1> = {
173
+ generationId: string;
174
+ responseMessageId: string;
175
+ /** Log index of the completed model step while its response remains interruptible. */
176
+ completionIndex?: number;
177
+ baseMessage?: M;
178
+ baseCompaction?: CompactionState<M> | null;
179
+ batches: Array<{
180
+ index: number;
181
+ chunks: UIMessageChunk$1[];
182
+ }>;
183
+ baseTools: ToolActivity[];
184
+ toolEvents: Array<{
185
+ index: number;
186
+ type: "ai.tool.called";
187
+ payload: ToolCalledPayload;
188
+ } | {
189
+ index: number;
190
+ type: "ai.tool.result";
191
+ payload: ToolResultPayload;
192
+ }>;
193
+ approvalEvents: Array<{
194
+ index: number;
195
+ type: "ai.approval.requested";
196
+ payload: ApprovalRequestedPayload;
197
+ } | {
198
+ index: number;
199
+ type: "ai.approval.responded";
200
+ payload: ApprovalRespondedPayload;
201
+ }>;
202
+ };
203
+ type PendingApproval = ApprovalRequestedPayload;
204
+ type PendingInput = InputRequestedPayload;
205
+ type ToolActivity = {
206
+ requestId: string;
207
+ messageId: string;
208
+ generationId: string;
209
+ toolCallId: string;
210
+ toolName?: string;
211
+ input?: unknown;
212
+ rawInput?: unknown;
213
+ output?: unknown;
214
+ error?: string;
215
+ preliminary?: boolean;
216
+ phase?: "input" | "execution";
217
+ dynamic?: boolean;
218
+ providerExecuted?: boolean;
219
+ callProviderMetadata?: unknown;
220
+ resultProviderMetadata?: unknown;
221
+ toolMetadata?: unknown;
222
+ title?: string;
223
+ status: "running" | "completed" | "failed" | "denied";
224
+ };
225
+ type CompactionState<M extends UIMessage$1> = {
226
+ status: "running" | "completed";
227
+ generationId: string;
228
+ throughMessageId: string;
229
+ messages?: M[];
230
+ retainedMessageIds?: string[];
231
+ };
232
+ type GenerationUsage = {
233
+ generationId: string;
234
+ usage: LanguageModelUsage;
235
+ };
236
+ type AIState<M extends UIMessage$1 = UIMessage$1> = {
237
+ session: {
238
+ created: boolean;
239
+ metadata?: JSONValue;
240
+ };
241
+ messages: M[];
242
+ status: AgentStatus;
243
+ activeGeneration: ActiveGeneration | null;
244
+ activeRequestId: string | null;
245
+ activeResponseMessageId: string | null;
246
+ activeProjection: ActiveGenerationProjection<M> | null;
247
+ responseGenerationIds: Record<string, string>;
248
+ terminalRequestIds?: Record<string, true>;
249
+ terminalGenerations?: Record<string, "completed" | "failed" | "interrupted" | "superseded">;
250
+ pendingApprovals: PendingApproval[];
251
+ pendingInputs: PendingInput[];
252
+ tools: ToolActivity[];
253
+ compaction: CompactionState<M> | null;
254
+ usage: GenerationUsage[];
255
+ error: string | null;
256
+ };
257
+ type AgentDefinition<M extends UIMessage$1 = UIMessage$1, D extends EventDefs = AIEventDefs<M>> = {
258
+ readonly contract: Contract<D>;
259
+ readonly reducer: Reducer<D, AIState<M>>;
260
+ };
261
+ type AgentToolEventDefs = EventDefs & Pick<AIEventDefs, "ai.tool.called" | "ai.approval.responded">;
262
+ /** The durable handler context supplied when A2 executes a local AI tool. */
263
+ type AgentToolContext<D extends AgentToolEventDefs> = HandlerContext<D, "ai.tool.called"> | HandlerContext<D, "ai.approval.responded">;
264
+ type AgentOptions<M extends UIMessage$1, E extends EventDefs> = {
265
+ name: string;
266
+ events?: E;
267
+ /** Optional stricter schema for custom UIMessage metadata/data/tool types. */
268
+ messageSchema?: StandardSchemaV1<M>;
269
+ /** Snapshot identity. Bump when application-level projection semantics change. */
270
+ reducerName?: string;
271
+ };
272
+ type AIMessageFrom<D extends EventDefs> = D extends Record<"ai.message.created", infer S extends StandardSchemaV1> ? StandardSchemaV1.InferOutput<S> extends MessageCreatedPayload<infer M extends UIMessage$1> ? M : UIMessage$1 : UIMessage$1;
273
+ declare function createEvents<M extends UIMessage$1 = UIMessage$1>(options?: {
274
+ messageSchema?: StandardSchemaV1<M>;
275
+ }): AIEventDefs<M>;
276
+ declare const events: AIEventDefs<UIMessage$1>;
277
+ /** Pure projection of the built-in AI protocol. Unknown extension events are ignored. */
278
+ declare function reduceAIState<M extends UIMessage$1>(state: AIState<M>, event: {
279
+ type: string;
280
+ payload: unknown;
281
+ index: number;
282
+ id?: string;
283
+ }): AIState<M>;
284
+ /** Derive AI SDK UI messages directly from an A2 event history. */
285
+ declare function deriveUIMessages<M extends UIMessage$1 = UIMessage$1>(history: readonly {
286
+ type: string;
287
+ payload: unknown;
288
+ index: number;
289
+ }[]): M[];
290
+ /** Build the standard AI state projection for any contract containing the protocol. */
291
+ declare function createReducer<D extends EventDefs>(options: {
292
+ contract: Contract<D>;
293
+ name?: string;
294
+ }): Reducer<D, AIState<AIMessageFrom<D>>>;
295
+ type ProtocolInput<M extends UIMessage$1, K extends keyof AIEventDefs<M> & string> = AppendInput<Pick<AIEventDefs<M>, K>>;
296
+ type AIInputs = {
297
+ /** Record a message. User messages schedule unless generate is false. */
298
+ message<M extends UIMessage$1>(message: M, options?: {
299
+ generate?: boolean;
300
+ }): ProtocolInput<M, "ai.message.created">[];
301
+ /** Record a message without requesting a generation. */
302
+ seed<M extends UIMessage$1>(message: M): ProtocolInput<M, "ai.message.created">[];
303
+ /** Answer an AI SDK tool approval. The tool barrier owns continuation. */
304
+ approval(response: ApprovalRespondedPayload): ProtocolInput<UIMessage$1, "ai.approval.responded">[];
305
+ /** Answer an application-defined input request. */
306
+ input(response: InputRespondedPayload): ProtocolInput<UIMessage$1, "ai.input.responded">[];
307
+ /** Record an application-defined request for input. */
308
+ requestInput(request: InputRequestedPayload): ProtocolInput<UIMessage$1, "ai.input.requested">[];
309
+ /** Request a fresh attempt for a failed response. */
310
+ retry(options: RetryGenerationOptions): ProtocolInput<UIMessage$1, "ai.retry.requested">[];
311
+ /** Interrupt the active response for a message. */
312
+ interrupt(interruption: MessageInterruptedPayload): ProtocolInput<UIMessage$1, "ai.message.interrupted">[];
313
+ };
314
+ /** Pure append inputs for the built-in AI protocol. */
315
+ declare const inputs: AIInputs;
316
+ /**
317
+ * Read the durable handler context ambient to the current AI tool
318
+ * execution. A2 runs each local tool's `execute` inside this scope, so
319
+ * plain AI SDK `tool()` definitions reach their `event`, `attempt`,
320
+ * `session`, and `signal` without an A2-specific wrapper. The agent (or
321
+ * contract) argument carries the event types and is verified against
322
+ * the executing server's contract.
323
+ */
324
+ declare function handlerContext<D extends AgentToolEventDefs>(agentOrContract: Contract<D> | {
325
+ readonly contract: Contract<D>;
326
+ }): AgentToolContext<D>;
327
+ /**
328
+ * Define an agent: built-in AI protocol + application events and one state
329
+ * reducer. The result is isomorphic.
330
+ */
331
+ declare function agent<M extends UIMessage$1 = UIMessage$1, E extends EventDefs = Record<never, never>>(options: AgentOptions<M, E>): AgentDefinition<M, AIEventDefs<M> & E>;
332
+ //#endregion
333
+ export { MessageInterruptedPayload as A, UIMessage$1 as B, GenerationUsage as C, LanguageModelUsage as D, JSONValue as E, SessionClosedPayload as F, deriveUIMessages as G, agent as H, SessionCreatedPayload as I, inputs as J, events as K, ToolActivity as L, PendingInput as M, RetryGenerationOptions as N, MessageCompletedPayload as O, RetryRequestedPayload as P, ToolCalledPayload as R, GenerationStartedPayload as S, InputRespondedPayload as T, createEvents as U, UIMessageChunk$1 as V, createReducer as W, reduceAIState as Y, GenerationCompletedPayload as _, ActiveGenerationProjection as a, GenerationReason as b, AgentStatus as c, ApprovalRequestedPayload as d, ApprovalRespondedPayload as f, FinishReason as g, CompactionState as h, ActiveGeneration as i, PendingApproval as j, MessageCreatedPayload as k, AgentToolContext as l, CompactionRequestedPayload as m, AIInputs as n, AgentDefinition as o, CompactionCompletedPayload as p, handlerContext as q, AIState as r, AgentOptions as s, AIEventDefs as t, AgentToolEventDefs as u, GenerationFailedPayload as v, InputRequestedPayload as w, GenerationRequestedPayload as x, GenerationProgressPayload as y, ToolResultPayload as z };
@@ -1,14 +1,40 @@
1
- import { a as EventDefs, r as ContractEvent } from "./contract-C_3dIIEU.js";
2
- import { AIEventDefs, AIState, AgentDefinition } from "./ai.js";
3
- import { A2Server, PushValidationContext, ServerOptions } from "./server.js";
4
- import { Instructions, LanguageModel, ToolSet, ToolSet as ToolSet$1, UIMessage, UIMessageChunk, streamText } from "ai";
1
+ import { a as EventDefs, r as ContractEvent } from "./contract-jIfaR085.js";
2
+ import { d as PushValidationContext, g as ServerOptions, n as A2Server } from "./server-YtPq7hjw.js";
3
+ import { l as AgentToolContext, o as AgentDefinition, r as AIState, t as AIEventDefs, u as AgentToolEventDefs } from "./ai-B4YhEnfw.js";
4
+ import { Instructions, LanguageModel, TextStreamPart, ToolSet, ToolSet as ToolSet$1, UIMessage, UIMessageChunk, streamText } from "ai";
5
5
  //#region src/ai-sdk-step.d.ts
6
6
  type StreamTextOptions<T extends ToolSet$1> = Parameters<typeof streamText<T>>[0];
7
7
  type ModelStepTimeout<T extends ToolSet$1> = number | Omit<Exclude<StreamTextOptions<T>["timeout"], number | undefined>, "toolMs" | "tools">;
8
- type ControlledStreamTextSetting = "_internal" | "abortSignal" | "instructions" | "messages" | "model" | "onToolExecutionEnd" | "onToolExecutionStart" | "experimental_onToolCallFinish" | "experimental_onToolCallStart" | "experimental_sandbox" | "experimental_toolCallers" | "experimental_toolApprovalSecret" | "prompt" | "prepareStep" | "stopWhen" | "system" | "tools" | "toolsContext";
8
+ type ControlledStreamTextSetting = "_internal" | "abortSignal" | "instructions" | "messages" | "model" | "onToolExecutionEnd" | "onToolExecutionStart" | "experimental_onToolCallFinish" | "experimental_onToolCallStart" | "experimental_sandbox" | "experimental_toolCallers" | "experimental_toolApprovalSecret" | "prompt" | "prepareStep" | "stopWhen" | "system" | "tools";
9
+ type RetypedStreamTextSetting = "experimental_onStart" | "experimental_onStepStart" | "experimental_repairToolCall" | "experimental_transform" | "onStart" | "onStepStart" | "repairToolCall";
10
+ type ModelFacingTools<T extends ToolSet$1> = { readonly [K in keyof T]: Omit<T[K], "execute">; };
11
+ type SettingEvent<T extends ToolSet$1, K extends keyof StreamTextOptions<T>> = NonNullable<StreamTextOptions<T>[K]> extends ((event: infer EVENT) => unknown) ? EVENT : never;
12
+ type ModelPhaseStartEvent<T extends ToolSet$1> = Omit<SettingEvent<T, "onStart">, "tools"> & {
13
+ readonly tools: ModelFacingTools<T> | undefined;
14
+ };
15
+ type ModelPhaseStepStartEvent<T extends ToolSet$1> = Omit<SettingEvent<T, "onStepStart">, "tools"> & {
16
+ readonly tools: ModelFacingTools<T> | undefined;
17
+ };
18
+ type ModelPhaseCallback<EVENT> = (event: EVENT) => void | PromiseLike<void>;
19
+ type StreamTextRepairToolCall<T extends ToolSet$1> = NonNullable<StreamTextOptions<T>["repairToolCall"]>;
20
+ type ModelPhaseRepairToolCall<T extends ToolSet$1> = (options: Omit<Parameters<StreamTextRepairToolCall<T>>[0], "tools"> & {
21
+ tools: ModelFacingTools<T>;
22
+ }) => ReturnType<StreamTextRepairToolCall<T>>;
23
+ type StreamTextTransformSetting<T extends ToolSet$1> = NonNullable<StreamTextOptions<T>["experimental_transform"]>;
24
+ type StreamTextTransform<T extends ToolSet$1> = Extract<StreamTextTransformSetting<T>, (...args: never[]) => unknown>;
25
+ type ModelPhaseTransform<T extends ToolSet$1> = (options: Omit<Parameters<StreamTextTransform<T>>[0], "tools"> & {
26
+ tools: ModelFacingTools<T>;
27
+ }) => ReturnType<StreamTextTransform<T>>;
9
28
  /** AI SDK streamText settings that remain meaningful for one durable step. */
10
- type AISDKStepSettings<T extends ToolSet$1> = Partial<Omit<StreamTextOptions<T>, ControlledStreamTextSetting | "timeout">> & {
29
+ type AISDKStepSettings<T extends ToolSet$1> = Partial<Omit<StreamTextOptions<T>, ControlledStreamTextSetting | RetypedStreamTextSetting | "timeout">> & {
11
30
  timeout?: ModelStepTimeout<T>;
31
+ onStart?: ModelPhaseCallback<ModelPhaseStartEvent<T>>;
32
+ experimental_onStart?: ModelPhaseCallback<ModelPhaseStartEvent<T>>;
33
+ onStepStart?: ModelPhaseCallback<ModelPhaseStepStartEvent<T>>;
34
+ experimental_onStepStart?: ModelPhaseCallback<ModelPhaseStepStartEvent<T>>;
35
+ repairToolCall?: ModelPhaseRepairToolCall<T>;
36
+ experimental_repairToolCall?: ModelPhaseRepairToolCall<T>;
37
+ experimental_transform?: ModelPhaseTransform<T> | Array<ModelPhaseTransform<T>>;
12
38
  };
13
39
  //#endregion
14
40
  //#region src/ai-server.d.ts
@@ -28,6 +54,10 @@ type AgentGenerateContext<M extends UIMessage, D extends AIEventDefs<M> & EventD
28
54
  generation: AgentGenerationSettings<T>;
29
55
  };
30
56
  type AgentGenerate<M extends UIMessage, D extends AIEventDefs<M> & EventDefs, T extends ToolSet> = (context: AgentGenerateContext<M, D, T>) => ReadableStream<UIMessageChunk> | Promise<ReadableStream<UIMessageChunk>>;
57
+ type UIMessageMetadata<M extends UIMessage> = M extends UIMessage<infer Metadata> ? Metadata : unknown;
58
+ type AgentMessageMetadata<M extends UIMessage, D extends AIEventDefs<M> & EventDefs, T extends ToolSet> = (context: AgentGenerateContext<M, D, T> & {
59
+ part: TextStreamPart<T>;
60
+ }) => UIMessageMetadata<M> | undefined;
31
61
  type AgentResolverContext<M extends UIMessage, D extends AIEventDefs<M> & EventDefs> = {
32
62
  event: ContractEvent<D, "ai.generation.requested">;
33
63
  state: AIState<M>;
@@ -52,9 +82,16 @@ type CreateHandlersOptions<M extends UIMessage, D extends AIEventDefs<M> & Event
52
82
  instructions?: Resolvable<Instructions | undefined, AgentResolverContext<M, D>>;
53
83
  /** Settings for each one-step AI SDK streamText call. */
54
84
  generation?: AgentGenerationSettings<T>;
55
- /** Maximum model steps in one assistant response. Defaults to 20. */
85
+ /**
86
+ * Maximum model steps in one assistant response. Defaults to Infinity.
87
+ */
56
88
  maxSteps?: number;
57
- /** Replace model generation with an AI SDK UI message chunk stream. */
89
+ /** Map default AI SDK stream parts to typed assistant message metadata. */
90
+ messageMetadata?: AgentMessageMetadata<M, D, T>;
91
+ /**
92
+ * Replace model generation with an AI SDK UI message chunk stream.
93
+ * The custom stream owns its metadata chunks.
94
+ */
58
95
  generate?: AgentGenerate<M, D, T>;
59
96
  compaction?: CompactionPolicy<M, D>;
60
97
  /** Progress is durably flushed at either limit, whichever is reached first. */
@@ -66,6 +103,8 @@ type CreateHandlersOptions<M extends UIMessage, D extends AIEventDefs<M> & Event
66
103
  type CreateAgentServerOptions<M extends UIMessage, D extends AIEventDefs<M> & EventDefs, T extends ToolSet = ToolSet> = CreateHandlersOptions<M, D, T> & Omit<ServerOptions<D>, "contract" | "handlers" | "validatePush"> & {
67
104
  handlers?: ServerOptions<D>["handlers"];
68
105
  };
106
+ /** Run `fn` with `ctx` as the ambient tool handler context, for direct tool tests. */
107
+ declare function runWithHandlerContext<D extends AgentToolEventDefs, R>(ctx: AgentToolContext<D>, fn: () => R): R;
69
108
  /**
70
109
  * Build the ordinary A2 handler table for the built-in agent protocol.
71
110
  * Application handlers can be spread beside this table.
@@ -74,4 +113,4 @@ declare function createHandlers<M extends UIMessage, D extends AIEventDefs<M> &
74
113
  /** Assemble an A2 server with the built-in agent handlers and app extensions. */
75
114
  declare function createAgentServer<M extends UIMessage, D extends AIEventDefs<M> & EventDefs, T extends ToolSet = ToolSet>(options: CreateAgentServerOptions<M, D, T>): A2Server<D>;
76
115
  //#endregion
77
- export { AgentGenerate, AgentGenerateContext, AgentGenerationSettings, AgentResolverContext, CompactionPolicy, CreateAgentServerOptions, CreateHandlersOptions, type Instructions, type LanguageModel, Resolvable, type ToolSet, createAgentServer, createHandlers, validateAgentPush };
116
+ export { AgentGenerate, AgentGenerateContext, AgentGenerationSettings, AgentMessageMetadata, AgentResolverContext, CompactionPolicy, CreateAgentServerOptions, CreateHandlersOptions, type Instructions, type LanguageModel, Resolvable, type ToolSet, createAgentServer, createHandlers, runWithHandlerContext, validateAgentPush };