experimental-a2 0.16.1 → 0.18.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/CHANGELOG.md +373 -0
- package/README.md +1 -1
- package/dist/{actor-ohPC-81x.d.ts → actor-Bjce9_5U.d.ts} +21 -11
- package/dist/actor-Bjce9_5U.d.ts.map +1 -0
- package/dist/actor-client.d.ts +2 -5
- package/dist/actor-client.d.ts.map +1 -1
- package/dist/actor-client.js +13 -4
- package/dist/actor-client.js.map +1 -1
- package/dist/actor-react.d.ts +5 -3
- package/dist/actor-react.d.ts.map +1 -1
- package/dist/actor-react.js +20 -10
- package/dist/actor-react.js.map +1 -1
- package/dist/{actor-shared-B5tJfzt-.js → actor-shared-t7w8xIKP.js} +12 -7
- package/dist/actor-shared-t7w8xIKP.js.map +1 -0
- package/dist/actor.d.ts +1 -1
- package/dist/actor.js +42 -23
- package/dist/actor.js.map +1 -1
- package/dist/{ai-DgOBltJ_.js → ai-BpOGm-zB.js} +621 -216
- package/dist/ai-BpOGm-zB.js.map +1 -0
- package/dist/{ai-CrEf6p_W.d.ts → ai-DrUaMyRt.d.ts} +114 -100
- package/dist/ai-DrUaMyRt.d.ts.map +1 -0
- package/dist/ai-client.d.ts +27 -0
- package/dist/ai-client.d.ts.map +1 -0
- package/dist/ai-client.js +29 -0
- package/dist/ai-client.js.map +1 -0
- package/dist/ai-fx.browser.d.ts +1 -0
- package/dist/ai-fx.browser.js +6 -0
- package/dist/ai-fx.browser.js.map +1 -0
- package/dist/ai-fx.d.ts +10 -0
- package/dist/ai-fx.d.ts.map +1 -0
- package/dist/ai-fx.js +634 -0
- package/dist/ai-fx.js.map +1 -0
- package/dist/ai-harness-BuLh_EYi.js +273 -0
- package/dist/ai-harness-BuLh_EYi.js.map +1 -0
- package/dist/ai-harness-DvsPeJeB.d.ts +26 -0
- package/dist/ai-harness-DvsPeJeB.d.ts.map +1 -0
- package/dist/ai-pi.browser.d.ts +1 -0
- package/dist/ai-pi.browser.js +6 -0
- package/dist/ai-pi.browser.js.map +1 -0
- package/dist/ai-pi.d.ts +17 -0
- package/dist/ai-pi.d.ts.map +1 -0
- package/dist/ai-pi.js +904 -0
- package/dist/ai-pi.js.map +1 -0
- package/dist/ai-react.d.ts +96 -0
- package/dist/ai-react.d.ts.map +1 -0
- package/dist/ai-react.js +142 -0
- package/dist/ai-react.js.map +1 -0
- package/dist/ai-server.browser.js +2 -2
- package/dist/ai-server.browser.js.map +1 -1
- package/dist/ai-server.d.ts +109 -43
- package/dist/ai-server.d.ts.map +1 -1
- package/dist/ai-server.js +526 -283
- package/dist/ai-server.js.map +1 -1
- package/dist/ai.d.ts +2 -2
- package/dist/ai.js +2 -2
- package/dist/bounded-cache-CPHWF-8h.js +41 -0
- package/dist/bounded-cache-CPHWF-8h.js.map +1 -0
- package/dist/{client-BYzHjkwU.js → client-BReKqwZC.js} +447 -80
- package/dist/client-BReKqwZC.js.map +1 -0
- package/dist/{client-CzyacQpJ.d.ts → client-h_DKFAjj.d.ts} +14 -13
- package/dist/client-h_DKFAjj.d.ts.map +1 -0
- package/dist/client.d.ts +4 -2
- package/dist/client.js +1 -1
- package/dist/{contract-CKRg_E4q.js → contract-BYKASlCV.js} +12 -21
- package/dist/contract-BYKASlCV.js.map +1 -0
- package/dist/{idempotent-replay-DVOlyYbx.js → idempotent-replay-JdgMQRRm.js} +2 -2
- package/dist/{idempotent-replay-DVOlyYbx.js.map → idempotent-replay-JdgMQRRm.js.map} +1 -1
- package/dist/index.d.ts +6 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -3
- package/dist/{errors-DvhSXnxk.d.ts → initial-snapshot-Bx-c0pDP.d.ts} +7 -3
- package/dist/initial-snapshot-Bx-c0pDP.d.ts.map +1 -0
- package/dist/{internal-Dq2qYxou.js → internal-B2T3U4Rq.js} +29 -2
- package/dist/internal-B2T3U4Rq.js.map +1 -0
- package/dist/otel.d.ts +1 -1
- package/dist/react-BBXgHWFc.d.ts +86 -0
- package/dist/react-BBXgHWFc.d.ts.map +1 -0
- package/dist/react.d.ts +2 -122
- package/dist/react.js +107 -100
- package/dist/react.js.map +1 -1
- package/dist/reducer-BAXc8JyF.js +87 -0
- package/dist/reducer-BAXc8JyF.js.map +1 -0
- package/dist/{reducer-otzHjuJj.d.ts → reducer-CqA59Q6U.d.ts} +46 -30
- package/dist/reducer-CqA59Q6U.d.ts.map +1 -0
- package/dist/reducer-runtime-DQwz_J59.js +28 -0
- package/dist/reducer-runtime-DQwz_J59.js.map +1 -0
- package/dist/scheduler-qstash.d.ts +3 -3
- package/dist/scheduler-qstash.d.ts.map +1 -1
- package/dist/scheduler-qstash.js +33 -10
- package/dist/scheduler-qstash.js.map +1 -1
- package/dist/{scheduler-task-BpzhPnRS.js → scheduler-task-X1SToDjP.js} +18 -3
- package/dist/scheduler-task-X1SToDjP.js.map +1 -0
- package/dist/scheduler-vercel.d.ts +4 -9
- package/dist/scheduler-vercel.d.ts.map +1 -1
- package/dist/scheduler-vercel.js +25 -44
- package/dist/scheduler-vercel.js.map +1 -1
- package/dist/{server-BD5ckxZb.js → server-Dw_k_7kO.js} +904 -219
- package/dist/server-Dw_k_7kO.js.map +1 -0
- package/dist/{server-DbD7IJVK.d.ts → server-En7cbi3v.d.ts} +116 -26
- package/dist/server-En7cbi3v.d.ts.map +1 -0
- package/dist/server.d.ts +4 -4
- package/dist/server.js +2 -2
- package/dist/session-clear-Bo-XTFEy.d.ts +12 -0
- package/dist/session-clear-Bo-XTFEy.d.ts.map +1 -0
- package/dist/{errors-DCk6ch5n.js → session-clear-DGI4jTQ5.js} +17 -2
- package/dist/session-clear-DGI4jTQ5.js.map +1 -0
- package/dist/{store-DyZM6fS5.d.ts → store-Djdv0bnZ.d.ts} +73 -3
- package/dist/store-Djdv0bnZ.d.ts.map +1 -0
- package/dist/store-N8PXxDAS.js.map +1 -1
- package/dist/store-memory.d.ts +1 -1
- package/dist/store-memory.d.ts.map +1 -1
- package/dist/store-memory.js +205 -66
- package/dist/store-memory.js.map +1 -1
- package/dist/{store-polling-CmxUbV93.js → store-polling-B5FcwJfo.js} +21 -4
- package/dist/store-polling-B5FcwJfo.js.map +1 -0
- package/dist/store-postgres.d.ts +1 -1
- package/dist/store-postgres.d.ts.map +1 -1
- package/dist/store-postgres.js +450 -108
- package/dist/store-postgres.js.map +1 -1
- package/dist/{store-presence-polling-C7-XZyW9.js → store-presence-polling-BAwS8RWn.js} +3 -3
- package/dist/{store-presence-polling-C7-XZyW9.js.map → store-presence-polling-BAwS8RWn.js.map} +1 -1
- package/dist/store-redis-http.d.ts +1 -1
- package/dist/store-redis-http.d.ts.map +1 -1
- package/dist/store-redis-http.js +293 -11
- package/dist/store-redis-http.js.map +1 -1
- package/dist/store-redis-notify-BRITti_o.js +2493 -0
- package/dist/store-redis-notify-BRITti_o.js.map +1 -0
- package/dist/store-redis.d.ts +1 -1
- package/dist/store-redis.d.ts.map +1 -1
- package/dist/store-redis.js +11 -11
- package/dist/store-redis.js.map +1 -1
- package/dist/store-sqlite.d.ts +1 -1
- package/dist/store-sqlite.d.ts.map +1 -1
- package/dist/store-sqlite.js +197 -33
- package/dist/store-sqlite.js.map +1 -1
- package/dist/stream-buffer-Cx7AAPGq.js +23 -0
- package/dist/stream-buffer-Cx7AAPGq.js.map +1 -0
- package/dist/{telemetry-B5jzpy6y.d.ts → telemetry-Cyfqo6Qt.d.ts} +2 -2
- package/dist/telemetry-Cyfqo6Qt.d.ts.map +1 -0
- package/dist/{wire-BO5wWCb1.js → wire-rSUglYo8.js} +132 -10
- package/dist/wire-rSUglYo8.js.map +1 -0
- package/docs/01-quickstart.mdx +50 -84
- package/docs/{guides/07-examples.mdx → 02-examples.mdx} +10 -20
- package/docs/actors/01-introduction.mdx +48 -82
- package/docs/actors/02-concurrency.mdx +43 -70
- package/docs/actors/03-timers.mdx +28 -42
- package/docs/actors/04-routes.mdx +110 -137
- package/docs/actors/meta.ts +1 -1
- package/docs/agents/01-introduction.mdx +257 -0
- package/docs/agents/02-tools.mdx +247 -0
- package/docs/agents/03-conversations.mdx +538 -0
- package/docs/agents/04-harnesses.mdx +136 -0
- package/docs/agents/meta.ts +1 -0
- package/docs/client/01-react.mdx +294 -0
- package/docs/client/02-transports.mdx +86 -0
- package/docs/client/03-presence.mdx +224 -0
- package/docs/client/meta.ts +1 -0
- package/docs/contract/01-events.mdx +57 -0
- package/docs/contract/02-state.mdx +142 -0
- package/docs/contract/03-sessions.mdx +175 -0
- package/docs/index.mdx +112 -156
- package/docs/reference/01-core.mdx +139 -0
- package/docs/reference/02-server.mdx +855 -0
- package/docs/reference/03-client.mdx +301 -0
- package/docs/reference/04-ai.mdx +722 -0
- package/docs/reference/05-adapters.mdx +351 -0
- package/docs/reference/06-errors.mdx +138 -0
- package/docs/reference/meta.ts +1 -1
- package/docs/server/01-handlers.mdx +200 -0
- package/docs/server/02-timers.mdx +130 -0
- package/docs/server/03-cancellation.mdx +141 -0
- package/docs/server/04-routes.mdx +243 -0
- package/docs/server/05-production.mdx +322 -0
- package/docs/server/06-guarantees.mdx +123 -0
- package/examples/playground/DEPLOY.md +53 -7
- package/examples/playground/app/a0/[appId]/loading.tsx +16 -0
- package/examples/playground/app/a0/[appId]/page.tsx +53 -0
- package/examples/playground/app/a0/a0.css +818 -0
- package/examples/playground/app/a0/app-list.tsx +218 -0
- package/examples/playground/app/a0/app-view.tsx +63 -0
- package/examples/playground/app/a0/apps/[appId]/preview/route.ts +27 -0
- package/examples/playground/app/a0/apps/[appId]/route.ts +28 -0
- package/examples/playground/app/a0/apps.test.ts +128 -0
- package/examples/playground/app/a0/apps.ts +102 -0
- package/examples/playground/app/a0/chat.tsx +410 -0
- package/examples/playground/app/a0/columns.tsx +109 -0
- package/examples/playground/app/a0/context-menu.tsx +116 -0
- package/examples/playground/app/a0/cookies.ts +46 -0
- package/examples/playground/app/a0/crash-on-request.ts +72 -0
- package/examples/playground/app/a0/crashes/route.ts +3 -0
- package/examples/playground/app/a0/crashes.test.ts +33 -0
- package/examples/playground/app/a0/crashes.ts +28 -0
- package/examples/playground/app/a0/devtools.tsx +164 -0
- package/examples/playground/app/a0/events/route.ts +6 -0
- package/examples/playground/app/a0/flags.ts +30 -0
- package/examples/playground/app/a0/fx/events/route.ts +9 -0
- package/examples/playground/app/a0/fx/scheduler/route.ts +7 -0
- package/examples/playground/app/a0/fx/short/events/route.ts +11 -0
- package/examples/playground/app/a0/layout.tsx +38 -0
- package/examples/playground/app/a0/list/route.ts +10 -0
- package/examples/playground/app/a0/model.test.ts +73 -0
- package/examples/playground/app/a0/model.ts +95 -0
- package/examples/playground/app/a0/no-photon.cjs +4 -0
- package/examples/playground/app/a0/no-quickjs.cjs +3 -0
- package/examples/playground/app/a0/page.tsx +14 -0
- package/examples/playground/app/a0/pi/events/route.ts +9 -0
- package/examples/playground/app/a0/pi/scheduler/route.ts +7 -0
- package/examples/playground/app/a0/pi/short/events/route.ts +11 -0
- package/examples/playground/app/a0/preview-pane.tsx +145 -0
- package/examples/playground/app/a0/preview.test.ts +53 -0
- package/examples/playground/app/a0/preview.ts +26 -0
- package/examples/playground/app/a0/sandbox-log.ts +75 -0
- package/examples/playground/app/a0/sandbox-session.ts +152 -0
- package/examples/playground/app/a0/sandbox.ts +191 -0
- package/examples/playground/app/a0/sandboxes/scheduler/route.ts +6 -0
- package/examples/playground/app/a0/scheduler/route.ts +7 -0
- package/examples/playground/app/a0/server.ts +213 -0
- package/examples/playground/app/a0/session.ts +59 -0
- package/examples/playground/app/a0/shell.tsx +158 -0
- package/examples/playground/app/a0/short/events/route.ts +9 -0
- package/examples/playground/app/a0/splitter.tsx +120 -0
- package/examples/playground/app/agent/[agentId]/agent-client.tsx +144 -174
- package/examples/playground/app/agent/[agentId]/command-receipt.test.tsx +65 -0
- package/examples/playground/app/agent/[agentId]/command-receipt.tsx +27 -0
- package/examples/playground/app/agent/[agentId]/compaction-event.tsx +25 -24
- package/examples/playground/app/agent/[agentId]/compaction-panel.test.tsx +119 -0
- package/examples/playground/app/agent/[agentId]/compaction-panel.tsx +208 -165
- package/examples/playground/app/agent/[agentId]/page.tsx +2 -16
- package/examples/playground/app/agent/events/route.ts +5 -2
- package/examples/playground/app/agent/ingress.test.ts +101 -0
- package/examples/playground/app/agent/model-input.test.tsx +58 -0
- package/examples/playground/app/agent/model-input.tsx +115 -0
- package/examples/playground/app/agent/model.test.ts +73 -0
- package/examples/playground/app/agent/model.ts +58 -26
- package/examples/playground/app/agent/new-agent-session.tsx +37 -19
- package/examples/playground/app/agent/page.tsx +4 -4
- package/examples/playground/app/agent/server.ts +19 -15
- package/examples/playground/app/agent/session.ts +5 -6
- package/examples/playground/app/agent/telemetry.test.ts +189 -0
- package/examples/playground/app/agent/telemetry.ts +30 -0
- package/examples/playground/app/agent/trace.test.ts +23 -0
- package/examples/playground/app/agent/trace.ts +18 -0
- package/examples/playground/app/canvas/[canvasId]/canvas-client.tsx +12 -12
- package/examples/playground/app/canvas/[canvasId]/page.tsx +1 -2
- package/examples/playground/app/canvas/[canvasId]/session.ts +2 -2
- package/examples/playground/app/canvas/model.ts +53 -53
- package/examples/playground/app/chat/[chatId]/agent-state.test.ts +176 -0
- package/examples/playground/app/chat/[chatId]/agent-stream-drawer.tsx +16 -1
- package/examples/playground/app/chat/[chatId]/chat-client.tsx +55 -77
- package/examples/playground/app/chat/[chatId]/chat-view.ts +37 -3
- package/examples/playground/app/chat/[chatId]/page.tsx +7 -15
- package/examples/playground/app/chat/[chatId]/session.ts +2 -19
- package/examples/playground/app/chat/agent/route.ts +9 -0
- package/examples/playground/app/chat/model.test.ts +46 -119
- package/examples/playground/app/chat/model.ts +82 -128
- package/examples/playground/app/chat/scheduler/route.ts +2 -2
- package/examples/playground/app/chat/server.test.ts +112 -0
- package/examples/playground/app/chat/server.ts +113 -117
- package/examples/playground/app/components/activity-feed.tsx +30 -1
- package/examples/playground/app/components/activity-history.test.tsx +35 -0
- package/examples/playground/app/components/demo-icons.tsx +89 -0
- package/examples/playground/app/components/demos.tsx +33 -0
- package/examples/playground/app/components/fast-link.test.tsx +58 -0
- package/examples/playground/app/components/fast-link.tsx +55 -0
- package/examples/playground/app/components/site-header.tsx +96 -0
- package/examples/playground/app/counter/counter-client.tsx +3 -3
- package/examples/playground/app/counter/model.test.ts +3 -3
- package/examples/playground/app/counter/model.ts +11 -21
- package/examples/playground/app/counter/page.tsx +2 -15
- package/examples/playground/app/counter/session.ts +2 -2
- package/examples/playground/app/documents/[documentId]/code-editor.tsx +12 -1
- package/examples/playground/app/documents/[documentId]/document-client.tsx +10 -11
- package/examples/playground/app/documents/[documentId]/page.tsx +1 -2
- package/examples/playground/app/documents/[documentId]/session.ts +2 -2
- package/examples/playground/app/documents/model.ts +27 -27
- package/examples/playground/app/globals.css +420 -207
- package/examples/playground/app/initial-state.test.tsx +54 -0
- package/examples/playground/app/layout.tsx +7 -23
- package/examples/playground/app/orders/[orderId]/page.tsx +1 -2
- package/examples/playground/app/orders/[orderId]/session.ts +2 -2
- package/examples/playground/app/orders/model.ts +49 -49
- package/examples/playground/app/page.tsx +13 -102
- package/examples/playground/app/recovery/[recoveryId]/page.tsx +1 -2
- package/examples/playground/app/recovery/[recoveryId]/session.ts +2 -2
- package/examples/playground/app/recovery/model.ts +30 -30
- package/examples/playground/instrumentation.ts +5 -0
- package/examples/playground/next.config.ts +17 -5
- package/examples/playground/package.json +13 -2
- package/examples/playground/scripts/a0-template.ts +77 -0
- package/examples/playground/vercel.json +36 -0
- package/package.json +29 -3
- package/src/actor-client.ts +16 -4
- package/src/actor-react.ts +25 -11
- package/src/actor-shared.ts +21 -6
- package/src/actor.ts +76 -31
- package/src/ai-agent-actions.ts +219 -0
- package/src/ai-agent.ts +2517 -0
- package/src/ai-app-state.ts +91 -0
- package/src/ai-client-state.ts +6 -3
- package/src/ai-client.ts +62 -0
- package/src/ai-context-schema.ts +25 -5
- package/src/ai-context.ts +90 -40
- package/src/ai-control-server.ts +92 -72
- package/src/ai-coordinator.ts +23 -22
- package/src/ai-fx.browser.ts +5 -0
- package/src/ai-fx.ts +833 -0
- package/src/ai-harness.ts +518 -0
- package/src/ai-message-base.ts +209 -0
- package/src/ai-message-projection.ts +262 -64
- package/src/ai-model-metadata.ts +11 -6
- package/src/ai-pi.browser.ts +5 -0
- package/src/ai-pi.ts +1263 -0
- package/src/ai-progress-batches.ts +26 -0
- package/src/ai-projector.ts +95 -14
- package/src/ai-react.ts +146 -0
- package/src/ai-sdk-step.ts +2 -2
- package/src/ai-server.browser.ts +2 -2
- package/src/ai-server.ts +23 -1965
- package/src/ai-stored-state.ts +48 -163
- package/src/ai.ts +339 -155
- package/src/bootstrap-stream.ts +72 -0
- package/src/bounded-cache.ts +55 -0
- package/src/client-render-session.ts +49 -0
- package/src/client.ts +688 -151
- package/src/contract.ts +92 -42
- package/src/deterministic-id.ts +37 -0
- package/src/equal-json.ts +32 -0
- package/src/errors.ts +13 -1
- package/src/index.ts +5 -1
- package/src/initial-snapshot.ts +39 -0
- package/src/internal.ts +52 -0
- package/src/libfx.d.ts +34 -0
- package/src/postgres-notification-scope.ts +14 -3
- package/src/react.ts +171 -206
- package/src/redis-http-reply.ts +256 -0
- package/src/redis-http-stream.ts +73 -0
- package/src/redis-http-subscriptions.ts +13 -5
- package/src/reducer-runtime.ts +52 -0
- package/src/reducer.ts +93 -11
- package/src/scheduler-qstash.ts +49 -20
- package/src/scheduler-task.ts +34 -2
- package/src/scheduler-vercel.ts +32 -84
- package/src/server-fetch.ts +139 -35
- package/src/server.ts +1133 -255
- package/src/session-clear.ts +23 -0
- package/src/session-socket.ts +154 -49
- package/src/sse.ts +71 -4
- package/src/store-memory.ts +252 -75
- package/src/store-polling.ts +18 -4
- package/src/store-postgres.ts +541 -114
- package/src/store-redis-core.ts +1450 -493
- package/src/store-redis-http.ts +18 -2
- package/src/store-redis-notify.ts +262 -85
- package/src/store-redis.ts +19 -9
- package/src/store-sqlite.ts +319 -45
- package/src/store.ts +79 -1
- package/src/stream-buffer.ts +43 -0
- package/src/telemetry.ts +14 -1
- package/src/wire.ts +241 -13
- package/dist/actor-ohPC-81x.d.ts.map +0 -1
- package/dist/actor-shared-B5tJfzt-.js.map +0 -1
- package/dist/ai-CrEf6p_W.d.ts.map +0 -1
- package/dist/ai-DgOBltJ_.js.map +0 -1
- package/dist/client-BYzHjkwU.js.map +0 -1
- package/dist/client-CzyacQpJ.d.ts.map +0 -1
- package/dist/contract-CKRg_E4q.js.map +0 -1
- package/dist/errors-DCk6ch5n.js.map +0 -1
- package/dist/errors-DvhSXnxk.d.ts.map +0 -1
- package/dist/internal-Dq2qYxou.js.map +0 -1
- package/dist/react.d.ts.map +0 -1
- package/dist/reducer-DEMjEY_O.js +0 -29
- package/dist/reducer-DEMjEY_O.js.map +0 -1
- package/dist/reducer-otzHjuJj.d.ts.map +0 -1
- package/dist/scheduler-task-BpzhPnRS.js.map +0 -1
- package/dist/server-BD5ckxZb.js.map +0 -1
- package/dist/server-DbD7IJVK.d.ts.map +0 -1
- package/dist/store-DyZM6fS5.d.ts.map +0 -1
- package/dist/store-polling-CmxUbV93.js.map +0 -1
- package/dist/store-redis-notify-BVLUfI3j.js +0 -1583
- package/dist/store-redis-notify-BVLUfI3j.js.map +0 -1
- package/dist/telemetry-B5jzpy6y.d.ts.map +0 -1
- package/dist/validate-XKT4FSNn.js +0 -30
- package/dist/validate-XKT4FSNn.js.map +0 -1
- package/dist/wire-BO5wWCb1.js.map +0 -1
- package/docs/concepts/01-contracts.mdx +0 -142
- package/docs/concepts/02-handlers.mdx +0 -284
- package/docs/concepts/03-durability.mdx +0 -314
- package/docs/concepts/04-state.mdx +0 -209
- package/docs/guides/01-timers.mdx +0 -185
- package/docs/guides/02-cancellation.mdx +0 -161
- package/docs/guides/03-react.mdx +0 -384
- package/docs/guides/04-local-first.mdx +0 -88
- package/docs/guides/05-production.mdx +0 -521
- package/docs/guides/06-ai-agents.mdx +0 -1318
- package/docs/guides/08-application-data.mdx +0 -113
- package/docs/guides/09-presence.mdx +0 -266
- package/docs/guides/10-transports.mdx +0 -221
- package/docs/reference/01-api.mdx +0 -1896
- package/docs/reference/02-errors.mdx +0 -149
- package/examples/playground/app/agent/[agentId]/compaction/route.ts +0 -14
- package/examples/playground/app/agent/compaction-settings.test.ts +0 -144
- package/examples/playground/app/agent/compaction-settings.ts +0 -49
- package/examples/playground/app/agent/compaction-timeline.test.ts +0 -377
- package/examples/playground/app/agent/compaction-timeline.ts +0 -208
- /package/docs/{concepts → contract}/meta.ts +0 -0
- /package/docs/{guides → server}/meta.ts +0 -0
|
@@ -0,0 +1,722 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: AI
|
|
3
|
+
description: "`experimental-a2/ai`, `experimental-a2/ai/server`, `experimental-a2/ai/client`, and `experimental-a2/ai/react`."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
## `experimental-a2/ai`
|
|
7
|
+
|
|
8
|
+
The isomorphic AI protocol: event schemas, the `AIState` reducer, pure input
|
|
9
|
+
builders, and `agentContract()` for extending both. Its peer dependency, AI SDK
|
|
10
|
+
v7, is used as types only here. See [Agents](/agents/introduction) for the
|
|
11
|
+
protocol and complete examples.
|
|
12
|
+
|
|
13
|
+
### `agentContract(options)`
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
agentContract<M extends UIMessage = UIMessage>(options: {
|
|
17
|
+
name: string
|
|
18
|
+
events?: Record<string, StandardSchemaV1>
|
|
19
|
+
messageSchema?: StandardSchemaV1<M>
|
|
20
|
+
reducer?: {
|
|
21
|
+
name: string // snapshot identity: rename it when fold changes
|
|
22
|
+
initialState: X // its keys may not shadow AIState's
|
|
23
|
+
fold: (state: X, event: ContractEvent) => X
|
|
24
|
+
}
|
|
25
|
+
}): Contract<Events, {}, AgentReducer<M, Events, X>>
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
A core contract with the built-in AI protocol plus `events`; the session's
|
|
29
|
+
state is `AIState<M> & X`. Share it when a client needs application events or
|
|
30
|
+
state: serve it with `agent({ contract })` and use it with
|
|
31
|
+
[`useAgent({ api, id, contract })`](#useagentoptions). Otherwise
|
|
32
|
+
`agent({ name })` builds one on the server.
|
|
33
|
+
|
|
34
|
+
- `events` cannot replace built-in event names.
|
|
35
|
+
- `messageSchema` validates a narrower `UIMessage` in message payloads; without
|
|
36
|
+
it, the type argument types messages.
|
|
37
|
+
- `reducer.fold` sees `X` and every event, never the transcript, and runs after
|
|
38
|
+
the AI fold on the server and in every client, so optimistic display carries
|
|
39
|
+
through.
|
|
40
|
+
- An `initialState` key that `AIState` also has throws a `TypeError` and fails
|
|
41
|
+
to typecheck.
|
|
42
|
+
- The reducer name is `AI_STATE_REDUCER` (`a2.ai.state.v26`) without
|
|
43
|
+
`reducer`, else `${reducer.name}+a2.ai.state.v26`, so checkpoints advance when
|
|
44
|
+
either fold changes. `AgentReducer` types that name (so
|
|
45
|
+
[`createAgentClient()`](#createagentclientoptions) accepts a plain
|
|
46
|
+
`agentContract()`) and carries `X` to `agent()`'s resolvers.
|
|
47
|
+
|
|
48
|
+
See [Add your own events and state](/agents/conversations#add-your-own-events-and-state).
|
|
49
|
+
|
|
50
|
+
### `TranscriptMessage<M>`
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
type TranscriptMessage<M extends UIMessage> = Omit<M, 'parts'> & {
|
|
54
|
+
parts: Array<M['parts'][number] | CompactionPart>
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
The message type of `AIState<M>['messages']` and `deriveUIMessages()`: `M` plus
|
|
59
|
+
the [compaction part](#iscompactionpartpart), so `isCompactionPart()` narrows
|
|
60
|
+
even when `M` declares its own data parts.
|
|
61
|
+
|
|
62
|
+
### `AIMessageOf<Events>`
|
|
63
|
+
|
|
64
|
+
The `UIMessage` type a contract's `ai.message.created` schema carries, such as
|
|
65
|
+
`AIMessageOf<typeof contract.events>`; `UIMessage` otherwise. `agent()` types
|
|
66
|
+
messages with it.
|
|
67
|
+
|
|
68
|
+
### `handlerContext(contract?)`
|
|
69
|
+
|
|
70
|
+
Returns the current tool execution's durable handler context, an
|
|
71
|
+
`AgentToolContext<D>` with `event`, `attempt`, `session`, and `signal`.
|
|
72
|
+
|
|
73
|
+
- Tools are plain AI SDK `tool()` definitions, passed through uninterpreted;
|
|
74
|
+
each local `execute` runs inside the ambient scope. Call it anywhere below
|
|
75
|
+
`execute`, including awaited helpers and async iteration; elsewhere it throws
|
|
76
|
+
a `TypeError`.
|
|
77
|
+
- Typed for the built-in protocol by default. Pass the shared `agentContract()`
|
|
78
|
+
to type application events; a mismatch with the executing agent throws a
|
|
79
|
+
`TypeError`.
|
|
80
|
+
- `event` is the `ai.tool.execution.requested` work event, whose payload holds
|
|
81
|
+
the admitted `call`, `generation`, `turnId`, and execution `version`.
|
|
82
|
+
`ctx.session.schedule()` uses the executing agent's scheduler.
|
|
83
|
+
- Built per attempt, never persisted, never sent to the model or a
|
|
84
|
+
provider-executed tool; each retry gets a fresh one.
|
|
85
|
+
- Model-phase tool options (`contextSchema`, dynamic descriptions,
|
|
86
|
+
`needsApproval` predicates, input lifecycle callbacks) pass through untouched,
|
|
87
|
+
durable execution passes no AI SDK `context` option, and model-phase hooks see
|
|
88
|
+
tools without local `execute`.
|
|
89
|
+
- `needsApproval` and `generation.toolApproval` predicates are re-evaluated on
|
|
90
|
+
recovery for the same durable call: keep them deterministic over the input.
|
|
91
|
+
|
|
92
|
+
See [Tools and approvals](/agents/tools).
|
|
93
|
+
|
|
94
|
+
### `inputs`
|
|
95
|
+
|
|
96
|
+
Pure typed builders of `ai.control.requested` commands, for `append()` and
|
|
97
|
+
`push()`. The `useAgent()` actions build the browser ones.
|
|
98
|
+
|
|
99
|
+
| Input | Events |
|
|
100
|
+
| --- | --- |
|
|
101
|
+
| `inputs.message(message, { generate? })` | queues input; `generate: false` records passive context at admission |
|
|
102
|
+
| `inputs.seed(message)` | queues passive context; non-user roles require a trusted append |
|
|
103
|
+
| `inputs.approval(response)` | answers a pending tool approval |
|
|
104
|
+
| `inputs.input(response)` | answers a pending application input |
|
|
105
|
+
| `inputs.requestInput(request)` | requests application input from trusted server code |
|
|
106
|
+
| `inputs.retry(options)` | retries a failed response |
|
|
107
|
+
| `inputs.stop({ turnId, lastSeenIndex? })` | ends the observed turn and advances when admission is open |
|
|
108
|
+
| `inputs.steer({ turnId, message, lastSeenIndex? })` | puts the new input first for a handoff after the observed turn's current step |
|
|
109
|
+
| `inputs.queue.edit({ message })` | changes a pending input; its ID stays fixed |
|
|
110
|
+
| `inputs.queue.move({ inputId, beforeId })` | moves pending input before an ID; `null` means the end |
|
|
111
|
+
| `inputs.queue.remove({ inputId })` | removes pending input; its submission stays in the log |
|
|
112
|
+
| `inputs.queue.sendNow({ inputId, turnId, lastSeenIndex? })` | promotes an existing queued input for a handoff after the current step; preserves pause |
|
|
113
|
+
| `inputs.pause({ when: 'now' \| 'after-turn' })` | pauses execution now or inbox admission after the turn |
|
|
114
|
+
| `inputs.resume()` | resumes retained work, then inbox admission |
|
|
115
|
+
| `inputs.toolResult(result)` | records a deferred provider-executed tool result from trusted server code |
|
|
116
|
+
| `inputs.interrupt(options)` | interrupts a specific generation/request owner |
|
|
117
|
+
|
|
118
|
+
- **Receipts.** A push confirms persistence; `ai.control.decided` confirms
|
|
119
|
+
application with `{ commandId, outcome, reason? }` on the existing stream.
|
|
120
|
+
`outcome` is `applied` or `rejected`; reasons include `not-pending`,
|
|
121
|
+
`role-mismatch`, `stale-turn`, `not-found`, `not-user-input`, and `closed`.
|
|
122
|
+
`state.receipt` holds the latest user receipt.
|
|
123
|
+
- **Trust.** Browser ingress accepts user messages, approval and input
|
|
124
|
+
responses, interruptions, and explicit retries. `inputs.requestInput()`,
|
|
125
|
+
`inputs.toolResult()`, and non-user `inputs.seed()` messages are trusted
|
|
126
|
+
server appends; only built-in handlers append generation requests and AI
|
|
127
|
+
lifecycle events. No builder covers session lifecycle: append
|
|
128
|
+
`ai.session.created` and `ai.session.closed` from trusted server code.
|
|
129
|
+
- **IDs.** Message, seed, and steer commands use the input message ID as their
|
|
130
|
+
event ID, and must. Approval, input-response, and retry builders use stable
|
|
131
|
+
interaction IDs; other commands use the ID `push()` or `append()` assigns,
|
|
132
|
+
kept across transport retries. Caller IDs are nonempty, never start with the
|
|
133
|
+
reserved `a2.ai:`, and are unique across the store; identical events replay
|
|
134
|
+
and conflicting reuse rejects before append. A2's own IDs are opaque,
|
|
135
|
+
fixed-length, deterministic `a2.ai:` values; an assistant message's ID is its
|
|
136
|
+
initial model-request event's ID.
|
|
137
|
+
- **Passive input.** `generate: false` is valid browser input: it admits the
|
|
138
|
+
user message to `AIState.messages` without a turn. The next generating user
|
|
139
|
+
message includes the passive ones before it; later ones wait. `inputs.seed()`
|
|
140
|
+
sets the same flag. Trusted assistant and system seeds are context, not queue
|
|
141
|
+
cutpoints, and never scheduled, whatever `generate` says. Model output is
|
|
142
|
+
generation progress, not `ai.message.created`, so a response never starts a
|
|
143
|
+
turn.
|
|
144
|
+
- **Queue.** Edits are last-write-wins in log order, keep identity and role,
|
|
145
|
+
and need no confirmation between edits; after admission they return
|
|
146
|
+
`not-pending`. Removal keeps the submission in the log, so replay cannot
|
|
147
|
+
recreate it.
|
|
148
|
+
- **Steer and Send now.** Steering prioritizes new input even after the
|
|
149
|
+
observed turn ends; a matching active turn yields after its current model
|
|
150
|
+
response and tool batch settle, including authorized deferred provider
|
|
151
|
+
results (unanswered approval and input waits can close; a denied approval
|
|
152
|
+
never blocks the handoff); otherwise it starts when idle or waits first
|
|
153
|
+
behind a different active turn. Both the reprioritization and the later
|
|
154
|
+
handoff commit atomically. Send now keeps the queued input's ID and content,
|
|
155
|
+
needs an observed `turnId` (`null` when idle), accepts only user-role input,
|
|
156
|
+
and promotes passive input; missing targets and stale turns reject before the
|
|
157
|
+
queue changes. Neither resumes a pause or cuts output at `lastSeenIndex`.
|
|
158
|
+
- **Resume** uses a fresh model request and execution version. Tools without a
|
|
159
|
+
terminal outcome can rerun; key external effects on their stable
|
|
160
|
+
`toolCallId`.
|
|
161
|
+
- **Approvals and input.** Request and response payloads carry the active
|
|
162
|
+
`requestId` and `generationId`, copied from the pending request, so a late
|
|
163
|
+
response cannot satisfy a newer step.
|
|
164
|
+
- **Retry.** `ai.retry.requested` carries `{ messageId, responseMessageId,
|
|
165
|
+
retryId }` (one `retryId` per user action) and becomes an
|
|
166
|
+
`ai.generation.requested` with reason `retry`. It reruns the failed model
|
|
167
|
+
call, keeping earlier completed steps, their tool results, and committed
|
|
168
|
+
compactions, and drops the failed call's uncommitted step. Forks and
|
|
169
|
+
edit-and-resend are application-owned.
|
|
170
|
+
- **Generation events.** `ai.generation.requested` requires
|
|
171
|
+
`responseMessageId`, plus `sourceGenerationId` for a tool continuation.
|
|
172
|
+
`ai.generation.failed` sets `stepLimit: true` when `maxSteps` rejects a
|
|
173
|
+
continuation.
|
|
174
|
+
- **Interruption.** `ai.message.interrupted` is `{ messageId, requestId,
|
|
175
|
+
reason?, lastSeenIndex? }` or `{ messageId, generationId, reason?,
|
|
176
|
+
lastSeenIndex? }`: copy `activeRequestId` before the generation starts,
|
|
177
|
+
`activeGeneration.generationId` after. A request-owned interruption survives
|
|
178
|
+
that request starting first. An older or mismatched message/owner pair is a
|
|
179
|
+
no-op. An accepted one fences its owner for good: later events stay in raw
|
|
180
|
+
history but cannot alter `AIState`, satisfy pending work, or reactivate the
|
|
181
|
+
response. Tool results completed at or before `lastSeenIndex` stay
|
|
182
|
+
completed; a final tool result racing a generation failure wins in either
|
|
183
|
+
order, and the generation stays failed. Interruption and failure drop
|
|
184
|
+
`input-streaming` tool drafts from the projection and later prompts (raw
|
|
185
|
+
progress stays); other tool parts keep their terminal handling.
|
|
186
|
+
|
|
187
|
+
See [Inbox and turn controls](/agents/conversations#inbox-and-turn-controls)
|
|
188
|
+
and [Interrupt and retry](/agents/tools#interrupt-and-retry).
|
|
189
|
+
|
|
190
|
+
### `reasoningLevels`
|
|
191
|
+
|
|
192
|
+
```ts
|
|
193
|
+
type ReasoningLevel = 'provider-default' | 'none' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh'
|
|
194
|
+
const reasoningLevels: readonly ReasoningLevel[]
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
Every `ReasoningLevel`, in order, for pickers. A `model` option returns one in
|
|
198
|
+
[`ModelSettings`](#modelsettings).
|
|
199
|
+
|
|
200
|
+
### `isCompactionPart(part)`
|
|
201
|
+
|
|
202
|
+
```ts
|
|
203
|
+
isCompactionPart(part: { type: string }): part is CompactionPart
|
|
204
|
+
|
|
205
|
+
type CompactionPart = {
|
|
206
|
+
type: 'data-a2-compaction'
|
|
207
|
+
id: string // the compacting generation's ID
|
|
208
|
+
data: {
|
|
209
|
+
status: 'running' | 'completed' | 'failed' | 'interrupted'
|
|
210
|
+
inputTokens?: number
|
|
211
|
+
thresholdTokens?: number
|
|
212
|
+
summary?: string
|
|
213
|
+
usage?: LanguageModelUsage
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
The transcript part that marks a compaction.
|
|
219
|
+
|
|
220
|
+
- Folding `ai.compaction.requested` appends it to the active response before
|
|
221
|
+
the step it compacts for (or opens the response with it). It counts toward
|
|
222
|
+
that step's recovery base, so Stop cutoffs, failures, and retries keep it.
|
|
223
|
+
- `ai.compaction.completed` settles it in place with `summary` and `usage`. If
|
|
224
|
+
its generation ends first: `interrupted` (Stop, Pause now, session close) or
|
|
225
|
+
`failed`. A pending Stop previews `interrupted` on the client.
|
|
226
|
+
- A superseded worker attempt's part is removed; the replacement compacts again
|
|
227
|
+
if needed.
|
|
228
|
+
- `convertToModelMessages()` skips data parts by default; model context never
|
|
229
|
+
contains it.
|
|
230
|
+
|
|
231
|
+
See [Show compaction in the conversation](/agents/conversations#show-compaction-in-the-conversation).
|
|
232
|
+
|
|
233
|
+
### `events` and `createEvents(options?)`
|
|
234
|
+
|
|
235
|
+
The built-in Standard Schema definitions, both isomorphic: `events` for the
|
|
236
|
+
default AI SDK `UIMessage`, `createEvents({ messageSchema })` for a more
|
|
237
|
+
specific message type.
|
|
238
|
+
|
|
239
|
+
### Optimistic AI client state
|
|
240
|
+
|
|
241
|
+
Every client folding an AI reducer (`agentContract({ reducer })` included)
|
|
242
|
+
shows pending send, edit, move, remove, Send now, steer, pause, resume, and
|
|
243
|
+
Stop commands in `state.messages`, `state.inbox`, and `state.starting`, with no
|
|
244
|
+
extra I/O or raw-history reads.
|
|
245
|
+
|
|
246
|
+
- An idle, unpaused send joins the conversation immediately with
|
|
247
|
+
`starting: true` (a speculative turn, not model execution); other sends
|
|
248
|
+
queue. Turn identities come only from accepted decisions; confirmed turns
|
|
249
|
+
win.
|
|
250
|
+
- Steer, and Send now against an active turn, show in `state.messages` after
|
|
251
|
+
the current response, not the inbox, until admission; they stay out of the
|
|
252
|
+
prompt. Several steering inputs show in admission order, most recent first,
|
|
253
|
+
and the display survives receipt and hydration, including while paused.
|
|
254
|
+
- A pending Stop clears the displayed `state.active`, generation, and pending
|
|
255
|
+
approvals and inputs, previews an idle status (paused when the inbox is), and
|
|
256
|
+
freezes the retained projection at `lastSeenIndex`, until its decision; a
|
|
257
|
+
rejection restores them.
|
|
258
|
+
- Later local edits stay visible through earlier receipts. Pending commands
|
|
259
|
+
retire on their `ai.control.decided` receipt or session close; failed pushes
|
|
260
|
+
roll back.
|
|
261
|
+
- Server reads and folds hold confirmed entries only (`starting: false`).
|
|
262
|
+
Custom reducers that call `reduceAIState()` or nest the AI fold don't get
|
|
263
|
+
this display.
|
|
264
|
+
|
|
265
|
+
See [Optimistic conversation display](/agents/conversations#optimistic-conversation-display).
|
|
266
|
+
|
|
267
|
+
### `AIState`
|
|
268
|
+
|
|
269
|
+
The type of the AI reducer's `initialState` and `fold`, server
|
|
270
|
+
`session.state()`, and client snapshots. Hydrate with state and its log index
|
|
271
|
+
together, so seen history never folds twice. The AI fold ignores application
|
|
272
|
+
events. Encoding is internal; no event or tool payload is truncated.
|
|
273
|
+
|
|
274
|
+
| Field | What it holds |
|
|
275
|
+
| --- | --- |
|
|
276
|
+
| `messages` | [`TranscriptMessage<M>`](#transcriptmessagem) values; server-side, without pending inputs |
|
|
277
|
+
| `inbox` | `{ paused, items }`; items are `{ id, message, generate, afterStepOf? }`, where `afterStepOf` is an observed steering turn that hands off after its current step (removal cancels it, admission consumes it) |
|
|
278
|
+
| `active` | `null` or `{ turnId, input, phase }`; admission freezes `input` |
|
|
279
|
+
| `status` | generation status |
|
|
280
|
+
| `starting` | a speculative optimistic turn |
|
|
281
|
+
| `receipt` | the latest user command receipt |
|
|
282
|
+
| `pendingQueueCommands` | the unresolved queue commands, for the optimistic display |
|
|
283
|
+
| `session` | session lifecycle |
|
|
284
|
+
| `pendingApprovals`, `pendingInputs` | pending tool approvals and application input |
|
|
285
|
+
| `tools` | tool activity, identity and status only; payloads live in message parts |
|
|
286
|
+
| `compaction` | the current or latest compaction |
|
|
287
|
+
| `modelMetadata` | each model's pending, resolved, or unavailable limits |
|
|
288
|
+
| `usage`, `error` | usage per generation; the last error |
|
|
289
|
+
| `activeGeneration` | the started generation |
|
|
290
|
+
| `activeRequestId` | the server-authorized generation request; fences delayed requests before start |
|
|
291
|
+
| `activeRequestReason`, `activeRequestSourceGenerationId` | that request's reason and source generation |
|
|
292
|
+
| `activeResponseMessageId` | the requested response, until `activeGeneration` exists |
|
|
293
|
+
| `activeProjection` | the indexed generation frontier, for exact interruption cutoffs |
|
|
294
|
+
| `responseOwners` | `Record<string, { generationId: string; requestId: string; attempt: number }>`: each response's latest owner, so a superseded owner's late events change nothing |
|
|
295
|
+
| `terminalRequestIds`, `terminalGenerations` | optional `Record<string, true>` and `Record<string, 'completed' \| 'failed' \| 'interrupted' \| 'superseded'>` fences, kept across snapshots and recovery |
|
|
296
|
+
|
|
297
|
+
- The `paused` status and the `pausing` and `paused` phases mean retained work.
|
|
298
|
+
- `activeProjection` lives from generation start until the response completes,
|
|
299
|
+
is interrupted or superseded, or a retry or later generation replaces it,
|
|
300
|
+
including while a step waits on tool, approval, or input barriers, while
|
|
301
|
+
paused, and while a failed generation awaits retry or interruption. Ordered
|
|
302
|
+
progress applies only new chunks. It is plain JSON, so checkpoints serialize
|
|
303
|
+
and clone, but their size grows with retained progress.
|
|
304
|
+
- `input-streaming` tool parts carry best-effort partial JSON for display until
|
|
305
|
+
the completed input arrives; it never authorizes execution or changes
|
|
306
|
+
interruption.
|
|
307
|
+
|
|
308
|
+
See [What happens after a send](/agents/introduction#what-happens-after-a-send).
|
|
309
|
+
|
|
310
|
+
### `deriveUIMessages(history)` and `reduceAIState(state, event)`
|
|
311
|
+
|
|
312
|
+
`deriveUIMessages()` folds a raw event history into `TranscriptMessage<M>[]`.
|
|
313
|
+
`reduceAIState()` is the event-at-a-time form the standard reducer uses. Both
|
|
314
|
+
project the same chunk-only protocol synchronously.
|
|
315
|
+
|
|
316
|
+
## `experimental-a2/ai/server`
|
|
317
|
+
|
|
318
|
+
### `agent(options)`
|
|
319
|
+
|
|
320
|
+
```ts
|
|
321
|
+
agent({
|
|
322
|
+
name: string, // or contract: agentContract(...), never both
|
|
323
|
+
events?, messageSchema?, // with name: server-only application events
|
|
324
|
+
model: string | ModelSettings | (context => string | ModelSettings), // an AI Gateway model ID
|
|
325
|
+
tools?,
|
|
326
|
+
instructions?,
|
|
327
|
+
maxSteps?,
|
|
328
|
+
harness?: // the agent's loop; defaults to { type: 'ai-sdk' }
|
|
329
|
+
| { type: 'ai-sdk', generation?, generate?, compaction?, messageMetadata? }
|
|
330
|
+
| Harness, // fx() or pi()
|
|
331
|
+
progress?,
|
|
332
|
+
toolLane?: string, // run local tool executions one at a time on this lane
|
|
333
|
+
toolRecovery?: { [tool]?: ToolRecovery }, // 'rerun' (default) | 'report'
|
|
334
|
+
handlers?, // application event handlers
|
|
335
|
+
store?, scheduler?, telemetry?,
|
|
336
|
+
}): Agent<Events, State, Name> // an A2Server
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
Serves an agent as one ordinary A2 server, returning an `A2Server` (`fetch`,
|
|
340
|
+
`session(id)`, `drain()`, `contract`). Server-only: the browser gets a throwing
|
|
341
|
+
stub.
|
|
342
|
+
|
|
343
|
+
| Option | What it does |
|
|
344
|
+
| --- | --- |
|
|
345
|
+
| `name` | the built-in protocol, with optional server-only `events` and `messageSchema` |
|
|
346
|
+
| `contract` | a shared `agentContract()`, when clients fold application state |
|
|
347
|
+
| `model` | an AI Gateway model ID, or [`ModelSettings`](#modelsettings) with one, under every harness; a value or per-generation async resolver |
|
|
348
|
+
| `tools` | AI SDK `tool()` definitions; local tools read context with [`handlerContext()`](#handlercontextcontract) |
|
|
349
|
+
| `instructions` | a value or per-generation async resolver |
|
|
350
|
+
| `maxSteps` | a positive integer capping one complete assistant response, under every harness; no limit by default |
|
|
351
|
+
| `harness` | the agent's loop: `{ type: 'ai-sdk', … }` (`AISDKHarness`, the default), [`fx()`](#fx), or [`pi()`](#pisandbox) |
|
|
352
|
+
| `harness.generation` | per-step settings, or a resolver |
|
|
353
|
+
| `harness.messageMetadata` | maps default stream parts to message metadata |
|
|
354
|
+
| `harness.generate` | replaces the default model step |
|
|
355
|
+
| `harness.compaction` | automatic for supported Gateway requests by default |
|
|
356
|
+
| `progress` | durable batching: `maxChunks` (128), `maxDelayMs` (0) |
|
|
357
|
+
| `toolLane` | one lane for every local tool execution, one at a time in admission order; model steps keep their own lane |
|
|
358
|
+
| `toolRecovery` | `'rerun'` (default) or `'report'` per tool, the harness's own tools included |
|
|
359
|
+
| `handlers` | application event handlers; naming an event the agent handles throws a `TypeError` |
|
|
360
|
+
| `store`, `scheduler`, `telemetry` | as for any A2 server; `telemetry` covers Core and AI in one trace ([span catalogue](/reference/adapters#the-span-catalogue)) |
|
|
361
|
+
|
|
362
|
+
**Contracts.** A contract not built by `agentContract()` throws a `TypeError`
|
|
363
|
+
and fails to typecheck (serve custom contracts with `createServer()`). Messages
|
|
364
|
+
are typed through [`AIMessageOf`](#aimessageofevents). `typeof` the agent types
|
|
365
|
+
`useAgent()` and `createAgentClient()` through a type-only import; `Name`, its
|
|
366
|
+
reducer name, decides whether the contract-free client accepts it.
|
|
367
|
+
|
|
368
|
+
**AI Gateway.** For Gateway models, A2 merges `caching: 'auto'` into
|
|
369
|
+
`generation.providerOptions.gateway`, and automatic compaction uses the same
|
|
370
|
+
default; your values take precedence and other options are kept. A custom
|
|
371
|
+
`generate` receives your original settings and owns its caching. Gateway calls
|
|
372
|
+
also send an `x-session-affinity` header, stable for the session and free of
|
|
373
|
+
the raw session ID, so supporting providers can reuse their cache; it selects
|
|
374
|
+
no provider and guarantees no hit. Override or suppress it (`undefined`) in
|
|
375
|
+
`generation.headers`, in any casing, not on the model: A2's per-call default
|
|
376
|
+
overrides model headers. See
|
|
377
|
+
[Gateway automatic caching](https://vercel.com/docs/ai-gateway/models-and-providers/automatic-caching).
|
|
378
|
+
|
|
379
|
+
**`harness`** is the agent's loop. `{ type: 'ai-sdk' }` (`AISDKHarness`), the
|
|
380
|
+
default, runs one AI SDK `streamText()` step per durable generation, with the
|
|
381
|
+
`generation`, `messageMetadata`, `generate`, and `compaction` options below.
|
|
382
|
+
[`fx()`](#fx) and [`pi()`](#pisandbox) run a coding agent's own loop instead.
|
|
383
|
+
The four options exist only in `{ type: 'ai-sdk' }`; passing one to `agent()`
|
|
384
|
+
itself throws a `TypeError` naming where it belongs.
|
|
385
|
+
|
|
386
|
+
**`fetch`** accepts reads and pushes of `ai.control.requested`, except the
|
|
387
|
+
server-authored `request-input` and `tool-result`, with `send`, `edit`, and
|
|
388
|
+
`steer` limited to user messages. With `contract` it also accepts the
|
|
389
|
+
contract's events; `events` given with `name` stay server-only. Other pushed
|
|
390
|
+
events answer `400`. `fetch(request, { authorize })` adds per-operation policy.
|
|
391
|
+
|
|
392
|
+
**Model steps.** Under `{ type: 'ai-sdk' }`, each durable generation runs one AI
|
|
393
|
+
SDK `streamText()` step, whose chunks A2 persists once in durable progress
|
|
394
|
+
batches. It passes the model ID to the AI SDK, which resolves it through its
|
|
395
|
+
global provider, AI Gateway unless replaced. Generation requests
|
|
396
|
+
share one durable lane, so a session's model calls never overlap, and a later
|
|
397
|
+
user message waits until the active response and its tool loop reach a terminal
|
|
398
|
+
event (a failed response, until retried or interrupted). A `model`,
|
|
399
|
+
`instructions`, or `generation` resolver that throws or returns an invalid
|
|
400
|
+
value fails the turn once, like a provider error, without retrying; that
|
|
401
|
+
attempt's `ai.generation.started` omits `model` if it never resolved, and
|
|
402
|
+
`retry()` runs the step again. Store failures (`A2Error`) still retry durably.
|
|
403
|
+
See [What happens after a send](/agents/introduction#what-happens-after-a-send).
|
|
404
|
+
|
|
405
|
+
**Resolver context.** `model`, `instructions`, and `generation` resolvers get
|
|
406
|
+
`{ event, messages, state, session, signal }`, where `state` is the
|
|
407
|
+
application state (`{}` without a contract `reducer`) at the captured
|
|
408
|
+
snapshot, read for free from the model-context checkpoint. Compaction,
|
|
409
|
+
`messageMetadata`, and `generate` callbacks also get `modelMessages`, the
|
|
410
|
+
model-ready prompt with committed summaries. No context exposes raw history or
|
|
411
|
+
an `execution` argument. `context.session.state(reducer)` reads at the captured
|
|
412
|
+
prompt frontier by default; `context.session.state()` returns `AIState` with
|
|
413
|
+
its log index.
|
|
414
|
+
|
|
415
|
+
**`harness.generation`** holds per-step settings such as `temperature`,
|
|
416
|
+
`maxOutputTokens`, `topP`, provider options, and tool approval policy, as the
|
|
417
|
+
provider supports them. It excludes `stopWhen`, tool execution callbacks, tool
|
|
418
|
+
callers, sandbox execution, and the tool approval secret; everything else,
|
|
419
|
+
`toolsContext` included, reaches the AI SDK untouched. Model-step timeouts work;
|
|
420
|
+
tool-execution timeouts don't. A resolver returns `AgentGenerationSettings` (or
|
|
421
|
+
a promise) once per attempt, before compaction and model dispatch, and also
|
|
422
|
+
governs tool approvals and automatic-compaction compatibility. Static settings
|
|
423
|
+
are validated at construction, resolved ones before use; failures and
|
|
424
|
+
cancellation follow model resolution.
|
|
425
|
+
|
|
426
|
+
**`harness.messageMetadata(context)`** synchronously maps each default stream part to
|
|
427
|
+
your `UIMessage` metadata type. It gets the `generate` context plus the
|
|
428
|
+
`TextStreamPart` as `part`; its `generation` includes A2's Gateway defaults.
|
|
429
|
+
Metadata for `start` and `finish` parts is recorded with progress and
|
|
430
|
+
shallow-merged onto the assistant message (use `finish`'s `totalUsage` for
|
|
431
|
+
final usage). A custom `generate` skips it. See
|
|
432
|
+
[Store assistant metadata](/agents/conversations#store-assistant-metadata).
|
|
433
|
+
|
|
434
|
+
**`harness.generate(context)`** gets the resolver context plus the step's
|
|
435
|
+
`generationId`, `modelMessages`, and the resolved `model`, `instructions`,
|
|
436
|
+
`tools`, and `generation`; `messages` and `modelMessages` reflect this step's
|
|
437
|
+
compaction. It returns exactly one model step as a
|
|
438
|
+
`ReadableStream<UIMessageChunk>` writing message
|
|
439
|
+
`event.payload.responseMessageId`; A2 keeps tool execution, continuation, and
|
|
440
|
+
the durable lifecycle. See
|
|
441
|
+
[Replace generation, not durability](/agents/conversations#replace-generation-not-durability).
|
|
442
|
+
|
|
443
|
+
**Tools.** Independent authorized tool handlers run concurrently with no
|
|
444
|
+
fixed limit. Results and generation completion arrive in either order; a
|
|
445
|
+
continuation needs the closed step and every required terminal result.
|
|
446
|
+
Single-owner terminal events commit atomically with the parent handler's
|
|
447
|
+
completion and carry its durable cause; many-owner joins and preliminary
|
|
448
|
+
outputs append immediately and idempotently. Provider calls and external side
|
|
449
|
+
effects are at least once: give them their own idempotency. An approved
|
|
450
|
+
provider-executed call can satisfy the join from its approval response, and a
|
|
451
|
+
provider tool with declared deferred-result support waits for its provider
|
|
452
|
+
result, which trusted server code submits with
|
|
453
|
+
[`inputs.toolResult(result)`](#inputs); the controller checks it against the
|
|
454
|
+
admitted call (`fetch` rejects it from browsers).
|
|
455
|
+
|
|
456
|
+
**`toolRecovery`**
|
|
457
|
+
|
|
458
|
+
- `'report'` skips `execute` when the previous attempt lapsed (its claim
|
|
459
|
+
expired after a crash, timeout, or frozen process), recording an error result
|
|
460
|
+
saying the call was interrupted and may have partly run; the model continues
|
|
461
|
+
from it. A2 can't tell whether the lapsed attempt reached the tool, so a call
|
|
462
|
+
that never started is reported too.
|
|
463
|
+
- Once `execute` has started, a cancelling Stop or Pause now, or a failure A2
|
|
464
|
+
would otherwise retry (such as a transient scheduler send failure), records
|
|
465
|
+
the same result; resuming after Pause now doesn't rerun the call.
|
|
466
|
+
- These still retry and run the tool: an attempt that failed with an error
|
|
467
|
+
before `execute` (such as a failed store read), and a failure inside A2 while
|
|
468
|
+
or just after the tool runs (its abort subscription, its result validation).
|
|
469
|
+
- An unknown tool name, a tool without `execute`, or another value throws a
|
|
470
|
+
`TypeError` at construction.
|
|
471
|
+
|
|
472
|
+
See [Delivery semantics](/agents/conversations#delivery-semantics).
|
|
473
|
+
|
|
474
|
+
**`harness.compaction`**
|
|
475
|
+
|
|
476
|
+
| Value | Behavior |
|
|
477
|
+
| --- | --- |
|
|
478
|
+
| omitted | automatic for supported Gateway requests |
|
|
479
|
+
| `false` | no compaction and no model metadata discovery |
|
|
480
|
+
| `{ thresholdTokens?, instructions? }` | tunes automatic compaction. `thresholdTokens`: a positive safe integer. `instructions`: added to A2's summary prompt; the agent's instructions stay |
|
|
481
|
+
| `{ shouldCompact(context), compact(context) }` | a custom policy |
|
|
482
|
+
| `(context: AgentResolverContext) => CompactionOptions \| Promise<CompactionOptions>` | resolves once per generation to a valid policy or `false`; can await `context.session.state(reducer)` |
|
|
483
|
+
|
|
484
|
+
- Static options are validated at construction, resolved ones before their
|
|
485
|
+
generation; each session uses its own value.
|
|
486
|
+
- Discovery: without an explicit threshold, the first generation batches a
|
|
487
|
+
metadata request into its start write, and an independent handler records the
|
|
488
|
+
model's limits from the public Gateway catalog in `state.modelMetadata`
|
|
489
|
+
without delaying dispatch (shared one-hour cache, five-second timeout; no new
|
|
490
|
+
request per turn, even after exhausted retries). The default threshold is 75%
|
|
491
|
+
of the context window, lowered for a larger output allowance. While it is
|
|
492
|
+
unknown, the first request proceeds and context-limit errors fail normally.
|
|
493
|
+
- Direct or custom providers, fallback model lists, and custom generators need
|
|
494
|
+
explicit configuration. Provider-executed tools, structured output, and
|
|
495
|
+
forced tool choices skip implicit compaction and reject explicit automatic
|
|
496
|
+
policies.
|
|
497
|
+
- The estimate is serialized bytes of messages, tools, and instructions,
|
|
498
|
+
excluding message and part provider options (they still reach the model
|
|
499
|
+
unchanged); not a tokenizer. A preceding same-model completion calibrates it
|
|
500
|
+
to reported input usage until a smaller prompt, retry, compaction, or model
|
|
501
|
+
change.
|
|
502
|
+
- Completed generations record `inputTokenEstimate`. Automatic
|
|
503
|
+
`ai.compaction.requested` events also record the pre-compaction
|
|
504
|
+
`inputTokenEstimate`, the calibrated `inputTokens`, and `thresholdTokens`
|
|
505
|
+
(custom policies omit them), at no extra model call or round trip.
|
|
506
|
+
- The built-in summary is one extra model request that keeps the request prefix
|
|
507
|
+
for caching and runs no application callbacks, transforms, or tool hooks.
|
|
508
|
+
A2 stores built-in summaries apart from your typed messages, so a summary
|
|
509
|
+
needs no message metadata and need not match `messageSchema`.
|
|
510
|
+
`state.messages` stays intact, marked with a
|
|
511
|
+
[`data-a2-compaction` part](#iscompactionpartpart);
|
|
512
|
+
`state.compaction?.status === 'running'` shows activity.
|
|
513
|
+
- Successful compaction is permanent across failure, interruption, retry, and
|
|
514
|
+
recovery. It defers while tool exchanges or A2-owned tool work are unsettled
|
|
515
|
+
(one coordinator state read per candidate), and while dead-lettered tool
|
|
516
|
+
work awaits repair and settlement or session close.
|
|
517
|
+
|
|
518
|
+
See [Compact long conversations](/agents/conversations#compact-long-conversations).
|
|
519
|
+
|
|
520
|
+
**Harnesses.** Under `fx()` and `pi()`, each model call the harness makes is one
|
|
521
|
+
durable step of the response, with the same events, progress, steering,
|
|
522
|
+
interruption, `maxSteps`, and recovery as any step. Tool calls it makes become
|
|
523
|
+
ordinary A2 tool calls, executed by A2's tool handlers, and `toolRecovery` may
|
|
524
|
+
name the harness's own tools, such as Pi's `bash`. `model` is resolved per step
|
|
525
|
+
as for any agent. `instructions` and `tools` reach the harness; how they
|
|
526
|
+
combine with its own prompt and tools depends on the harness. Tool approval
|
|
527
|
+
policy lives in `harness.generation`, so a harness agent's tools run without
|
|
528
|
+
approval, and a tool that sets `needsApproval` is rejected.
|
|
529
|
+
|
|
530
|
+
A harness resumes after a crash at the interrupted step. Finished model calls
|
|
531
|
+
are not made again and finished tool calls do not run again. A2 rebuilds the
|
|
532
|
+
harness for each step from the log, and stores nothing outside it. Each agent
|
|
533
|
+
keeps, in its process's memory, the harness's state at the end of the last
|
|
534
|
+
response it ran there, FX's checkpoint or Pi's session, so a warm process reads
|
|
535
|
+
and replays only the log since; a cold one reads and replays the session from
|
|
536
|
+
its start. A saved state counts only once the step that wrote it is committed,
|
|
537
|
+
so a stale or unusable one costs a longer rebuild, never correctness. See
|
|
538
|
+
[Harnesses](/agents/harnesses).
|
|
539
|
+
|
|
540
|
+
**`progress`.** A batch is written as soon as the previous write finishes;
|
|
541
|
+
chunks arriving mid-write share the next batch, up to `maxChunks` (128).
|
|
542
|
+
`maxDelayMs` (default 0) lets a batch collect that long after the previous
|
|
543
|
+
write; boundary chunks and `maxChunks` write sooner. Raising it trades token
|
|
544
|
+
latency for fewer progress events.
|
|
545
|
+
|
|
546
|
+
### `ModelSettings`
|
|
547
|
+
|
|
548
|
+
```ts
|
|
549
|
+
type ModelSettings = {
|
|
550
|
+
model: string // an AI Gateway model ID
|
|
551
|
+
reasoning?: ReasoningLevel
|
|
552
|
+
speed?: 'fast' | 'standard'
|
|
553
|
+
}
|
|
554
|
+
```
|
|
555
|
+
|
|
556
|
+
A model with its reasoning level and speed, returned by a `model` option or
|
|
557
|
+
resolver. `reasoning` becomes the AI SDK `reasoning` call option
|
|
558
|
+
([`reasoningLevels`](#reasoninglevels)), FX's effort, or Pi's thinking level. `speed: 'fast'` sets
|
|
559
|
+
`providerOptions.gateway.speed` to prefer AI Gateway's faster tier when the
|
|
560
|
+
model has one; `'standard'` removes a configured speed. Both override the same
|
|
561
|
+
settings in `generation`. See [Choose the model](/agents/introduction#choose-the-model).
|
|
562
|
+
|
|
563
|
+
### `runWithHandlerContext(ctx, fn)`
|
|
564
|
+
|
|
565
|
+
The test seam for context-reading tools: runs `fn` with `ctx` as the ambient
|
|
566
|
+
handler context, so tests can call `execute` directly. Inside `fn`,
|
|
567
|
+
`handlerContext()` returns `ctx`, with or without a contract argument.
|
|
568
|
+
|
|
569
|
+
## `experimental-a2/ai/fx`
|
|
570
|
+
|
|
571
|
+
### `fx()`
|
|
572
|
+
|
|
573
|
+
```ts
|
|
574
|
+
fx(): Harness<'fx'>
|
|
575
|
+
```
|
|
576
|
+
|
|
577
|
+
The [FX](https://fx.sh) harness for `agent({ harness })`, running FX's kernel
|
|
578
|
+
from `libfx` (an optional peer dependency) in the server process. FX adds no
|
|
579
|
+
system prompt and brings no tools: `instructions` is the whole system prompt
|
|
580
|
+
and the agent's `tools` are all FX can call. `reasoning` becomes FX's effort and
|
|
581
|
+
`speed: 'fast'` its fast tier. FX compacts its own context; a compaction
|
|
582
|
+
appears in the transcript as a `data-a2-compaction` part with its summary.
|
|
583
|
+
|
|
584
|
+
Every model call FX makes goes through A2, which records it as a step. To
|
|
585
|
+
continue a response, A2 restores FX's latest checkpoint and replays the
|
|
586
|
+
response so far from the log: recorded model responses and tool results answer
|
|
587
|
+
the kernel without network calls or tool runs, then FX makes its next model
|
|
588
|
+
call. Replay grows with the response, roughly 0.1 to 0.5 seconds for one of 80
|
|
589
|
+
to 200 tool calls. FX checkpoints hold at most 4 MiB of conversation; past that,
|
|
590
|
+
A2 replays from an earlier checkpoint.
|
|
591
|
+
|
|
592
|
+
Credentials come from `AI_GATEWAY_API_KEY`, or Vercel's OIDC token on Vercel.
|
|
593
|
+
This entry point is server-only.
|
|
594
|
+
|
|
595
|
+
## `experimental-a2/ai/pi`
|
|
596
|
+
|
|
597
|
+
### `pi({ sandbox })`
|
|
598
|
+
|
|
599
|
+
```ts
|
|
600
|
+
pi({
|
|
601
|
+
sandbox: ({ session, signal }) => SandboxSession | Promise<SandboxSession>,
|
|
602
|
+
}): Harness<'pi'>
|
|
603
|
+
```
|
|
604
|
+
|
|
605
|
+
The [Pi](https://pi.dev) harness for `agent({ harness })`, running Pi's own
|
|
606
|
+
agent session from `@earendil-works/pi-coding-agent` (with
|
|
607
|
+
`@earendil-works/pi-ai`, both optional peer dependencies). Pi brings its system
|
|
608
|
+
prompt and its `read`, `write`, `edit`, and `bash` tools, which run in the
|
|
609
|
+
session's sandbox. `instructions` is added to Pi's prompt. The agent's `tools`
|
|
610
|
+
are added to Pi's; a tool with one of their names replaces Pi's. `reasoning`
|
|
611
|
+
becomes Pi's thinking level, and `model` is one of the Gateway models Pi's
|
|
612
|
+
catalog lists. Pi works in the sandbox's working directory; its `bash` runs
|
|
613
|
+
with the sandbox's environment, never the server's. Pi compacts its own
|
|
614
|
+
context; a compaction appears in the transcript as a `data-a2-compaction` part
|
|
615
|
+
with its summary.
|
|
616
|
+
|
|
617
|
+
- `sandbox` (`HarnessSandbox`, given a `HarnessSandboxContext`) resolves the
|
|
618
|
+
session's AI SDK sandbox session (`Experimental_SandboxSession` from `ai`).
|
|
619
|
+
It runs for each local tool execution, whose `execute` receives the sandbox
|
|
620
|
+
as `experimental_sandbox`, Pi's tools and the agent's alike, and for a step
|
|
621
|
+
until Pi's session records the sandbox's working directory.
|
|
622
|
+
- It must return the same sandbox for a session every time, and concurrent tool
|
|
623
|
+
calls call it concurrently. A resolver failure fails that attempt, which A2
|
|
624
|
+
retries. A2 never closes the sandbox. `pi()` without a `sandbox` function
|
|
625
|
+
throws a `TypeError`.
|
|
626
|
+
- For each step, A2 restores Pi's session from the end of the last response,
|
|
627
|
+
replays the response so far from the log, and lets Pi make its next model
|
|
628
|
+
call. Pi's tool calls are ordinary A2 tool calls: A2 runs Pi's real tool
|
|
629
|
+
implementations against the sandbox and records their results.
|
|
630
|
+
- Pi's tools move at most 4 MiB from the sandbox to your server per file read
|
|
631
|
+
or command. A larger file fails `read` or `edit`, and a command whose output
|
|
632
|
+
passes 4 MiB is stopped and fails `bash`; both errors tell the model to read
|
|
633
|
+
in parts. Files arrive through the sandbox's `readFile`, so implement it as a
|
|
634
|
+
stream for the limit to bound the download too.
|
|
635
|
+
|
|
636
|
+
`pi()` takes `PiOptions`. Credentials come from `AI_GATEWAY_API_KEY`, or
|
|
637
|
+
Vercel's OIDC token on Vercel. This entry point is server-only.
|
|
638
|
+
|
|
639
|
+
## `experimental-a2/ai/client`
|
|
640
|
+
|
|
641
|
+
### `createAgentClient(options)`
|
|
642
|
+
|
|
643
|
+
```ts
|
|
644
|
+
createAgentClient<typeof agent>(options: {
|
|
645
|
+
api: ClientApi
|
|
646
|
+
gcTime?: number
|
|
647
|
+
participant?: string
|
|
648
|
+
reconnect?, fetch?, webSocket?, // as createClient
|
|
649
|
+
}): AgentClient // an A2Client over the built-in AI protocol
|
|
650
|
+
```
|
|
651
|
+
|
|
652
|
+
A contract-free client for an `agent()` route, typed by a type-only import of
|
|
653
|
+
the server module. It pushes the built-in AI controls only.
|
|
654
|
+
|
|
655
|
+
- Accepts only agents whose reducer has the built-in name
|
|
656
|
+
(`typeof AI_STATE_REDUCER`): `agent({ name })`, or `agent({ contract })` with
|
|
657
|
+
an `agentContract()` without `reducer`. Extended contracts use
|
|
658
|
+
`createClient({ contract })`, so the client folds the same state.
|
|
659
|
+
- Use it for pushes outside React, such as a first message before navigating,
|
|
660
|
+
and pass it to `useAgent({ client })` to share its sessions.
|
|
661
|
+
|
|
662
|
+
See [Start a session from another page](/agents/introduction#start-a-session-from-another-page).
|
|
663
|
+
|
|
664
|
+
## `experimental-a2/ai/react`
|
|
665
|
+
|
|
666
|
+
### `useAgent(options)`
|
|
667
|
+
|
|
668
|
+
```ts
|
|
669
|
+
useAgent<typeof agent>(options: {
|
|
670
|
+
id: string
|
|
671
|
+
initial?: InitialSnapshot<AIState>
|
|
672
|
+
participant?: string
|
|
673
|
+
} & ({ api: string } | { client: AgentClient })): UseAgentResult
|
|
674
|
+
|
|
675
|
+
useAgent(options: {
|
|
676
|
+
id: string
|
|
677
|
+
initial?: InitialSnapshot<State>
|
|
678
|
+
participant?: string
|
|
679
|
+
} & (
|
|
680
|
+
| { api: string; contract: Contract } // a shared agentContract(), imported for real
|
|
681
|
+
| { client: A2Client } // createClient({ contract, api })
|
|
682
|
+
)): UseAgentResult
|
|
683
|
+
```
|
|
684
|
+
|
|
685
|
+
One agent session in React: its live optimistic `AIState` and actions that
|
|
686
|
+
fill in protocol identities.
|
|
687
|
+
|
|
688
|
+
- `api`: one shared client per route for the page's lifetime, reading
|
|
689
|
+
`globalThis.fetch` per request. `client`: yours, for a custom `fetch`,
|
|
690
|
+
headers, or `gcTime`. Both accept only built-in-name agents.
|
|
691
|
+
- `contract`: also folds its application state, one client per contract and
|
|
692
|
+
route; `state` is `AIState & X` and `push` accepts its events. Pass
|
|
693
|
+
`createClient({ contract, api })` as `client` to share it outside React.
|
|
694
|
+
- Contracts not built by `agentContract()` use core `useSession()` and
|
|
695
|
+
`inputs`.
|
|
696
|
+
- Keep one options form per call site, unchanged between renders.
|
|
697
|
+
|
|
698
|
+
The result is the session result (`state`, `index`, `connection`, `push`,
|
|
699
|
+
`events`, `hydrated`, `reconnect`, `loadHistory`, `history`) plus:
|
|
700
|
+
|
|
701
|
+
| Member | Does |
|
|
702
|
+
| --- | --- |
|
|
703
|
+
| `messages` | `state.messages` |
|
|
704
|
+
| `status` | `state.status` |
|
|
705
|
+
| `indicator` | `'starting'` for an optimistic turn awaiting acceptance, `'compacting'` while a summary runs, `'thinking'` while the current step has no visible part (reasoning and step boundaries don't count), else `null` |
|
|
706
|
+
| `sendMessage(message, { generate? })` | queues a string (one text part) or a `UIMessage` |
|
|
707
|
+
| `steer(message)` | steers the active turn after its current step, or sends when idle |
|
|
708
|
+
| `stop()` | stops the active turn at the rendered frontier |
|
|
709
|
+
| `approve(approval)`, `deny(approval, { reason? })` | answers a pending approval |
|
|
710
|
+
| `respond(input, value)` | answers a pending application input |
|
|
711
|
+
| `retry()` | retries the failed response with a fresh `retryId` |
|
|
712
|
+
| `pause({ when })`, `resume()` | pauses and resumes |
|
|
713
|
+
| `queue.edit(message)`, `queue.move({ inputId, beforeId })`, `queue.remove(inputId)`, `queue.sendNow(inputId)` | edits the inbox |
|
|
714
|
+
|
|
715
|
+
Every action returns a `PushResult`, like `push()`: it resolves to the
|
|
716
|
+
persisted command events (each `id` is its receipt's `commandId`), rejects
|
|
717
|
+
when the push fails, and its `.confirmed` resolves when the stream delivers
|
|
718
|
+
them back. Actions read identities from the render that created them, so
|
|
719
|
+
`stop()` and `queue.sendNow()` carry the frontier the user saw. An action with
|
|
720
|
+
nothing to address (`stop()` with no active turn, `retry()` with no failed
|
|
721
|
+
one) resolves to an empty array. Actions are rebuilt every render; their
|
|
722
|
+
identity is not stable.
|