experimental-a2 0.17.0 → 0.18.1
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 +32 -0
- package/README.md +1 -1
- package/dist/{actor-DBbe5xeE.d.ts → actor-C7b-1arn.d.ts} +5 -5
- package/dist/{actor-DBbe5xeE.d.ts.map → actor-C7b-1arn.d.ts.map} +1 -1
- package/dist/actor-client.d.ts +1 -1
- package/dist/actor-react.d.ts +3 -3
- package/dist/actor-react.js +1 -1
- package/dist/actor.d.ts +1 -1
- package/dist/actor.js +2 -2
- package/dist/{ai-vpGtcaCB.d.ts → ai-BMLlI2Ff.d.ts} +3 -3
- package/dist/{ai-vpGtcaCB.d.ts.map → ai-BMLlI2Ff.d.ts.map} +1 -1
- package/dist/{ai-UrWfKeuv.js → ai-D6mGlO8j.js} +2 -2
- package/dist/{ai-UrWfKeuv.js.map → ai-D6mGlO8j.js.map} +1 -1
- package/dist/ai-client.d.ts +2 -2
- package/dist/ai-client.js +2 -2
- 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 +692 -0
- package/dist/ai-fx.js.map +1 -0
- package/dist/ai-harness-B2suP2Qh.d.ts +26 -0
- package/dist/ai-harness-B2suP2Qh.d.ts.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-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 +950 -0
- package/dist/ai-pi.js.map +1 -0
- package/dist/ai-react.d.ts +5 -5
- package/dist/ai-react.js +2 -2
- package/dist/ai-server.d.ts +47 -25
- package/dist/ai-server.d.ts.map +1 -1
- package/dist/ai-server.js +113 -40
- package/dist/ai-server.js.map +1 -1
- package/dist/ai-tool-input-DmSqMUQi.js +40 -0
- package/dist/ai-tool-input-DmSqMUQi.js.map +1 -0
- package/dist/ai.d.ts +1 -1
- package/dist/ai.js +1 -1
- package/dist/bounded-cache-CPHWF-8h.js +41 -0
- package/dist/bounded-cache-CPHWF-8h.js.map +1 -0
- package/dist/{client-COaiaDub.js → client-BhHLoNKF.js} +3 -3
- package/dist/{client-COaiaDub.js.map → client-BhHLoNKF.js.map} +1 -1
- package/dist/{client-qRnRUzBS.d.ts → client-h_DKFAjj.d.ts} +3 -3
- package/dist/{client-qRnRUzBS.d.ts.map → client-h_DKFAjj.d.ts.map} +1 -1
- package/dist/client.d.ts +3 -3
- package/dist/client.js +1 -1
- package/dist/index.d.ts +5 -5
- package/dist/{initial-snapshot-BrLso5x_.d.ts → initial-snapshot-Bx-c0pDP.d.ts} +2 -2
- package/dist/{initial-snapshot-BrLso5x_.d.ts.map → initial-snapshot-Bx-c0pDP.d.ts.map} +1 -1
- package/dist/{internal-CbVvEwad.js → internal-CscSY7K_.js} +11 -3
- package/dist/internal-CscSY7K_.js.map +1 -0
- package/dist/otel.d.ts +1 -1
- package/dist/{react-BbJ-g6Uu.d.ts → react-BBXgHWFc.d.ts} +4 -4
- package/dist/{react-BbJ-g6Uu.d.ts.map → react-BBXgHWFc.d.ts.map} +1 -1
- package/dist/react.d.ts +1 -1
- package/dist/react.js +1 -1
- package/dist/reducer-BAXc8JyF.js.map +1 -1
- package/dist/{reducer-BYu6DT7h.d.ts → reducer-CqA59Q6U.d.ts} +2 -2
- package/dist/{reducer-BYu6DT7h.d.ts.map → reducer-CqA59Q6U.d.ts.map} +1 -1
- package/dist/scheduler-qstash.d.ts +2 -2
- package/dist/scheduler-qstash.js +3 -3
- package/dist/scheduler-qstash.js.map +1 -1
- package/dist/scheduler-vercel.d.ts +7 -7
- package/dist/scheduler-vercel.d.ts.map +1 -1
- package/dist/scheduler-vercel.js +9 -10
- package/dist/scheduler-vercel.js.map +1 -1
- package/dist/{server-Rj64fNvX.js → server-D-Y4pqwu.js} +126 -67
- package/dist/server-D-Y4pqwu.js.map +1 -0
- package/dist/{server-CGM8WzRG.d.ts → server-DYAATFuT.d.ts} +42 -7
- package/dist/server-DYAATFuT.d.ts.map +1 -0
- package/dist/server.d.ts +4 -4
- package/dist/server.js +1 -1
- package/dist/{session-clear-Dshpuhff.d.ts → session-clear-C-QwTXV1.d.ts} +2 -2
- package/dist/session-clear-C-QwTXV1.d.ts.map +1 -0
- package/dist/{store-Gpkq7WBo.d.ts → store-CyLUy86v.d.ts} +53 -5
- package/dist/store-CyLUy86v.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.js +56 -11
- package/dist/store-memory.js.map +1 -1
- package/dist/{store-polling-4_y8lETm.js → store-polling-7WJV0YWP.js} +2 -2
- package/dist/{store-polling-4_y8lETm.js.map → store-polling-7WJV0YWP.js.map} +1 -1
- package/dist/store-postgres.d.ts +1 -1
- package/dist/store-postgres.d.ts.map +1 -1
- package/dist/store-postgres.js +106 -25
- package/dist/store-postgres.js.map +1 -1
- package/dist/{store-presence-polling-Q1C-k2dd.js → store-presence-polling-B1ixeqIS.js} +3 -3
- package/dist/{store-presence-polling-Q1C-k2dd.js.map → store-presence-polling-B1ixeqIS.js.map} +1 -1
- package/dist/store-redis-http.d.ts +1 -1
- package/dist/store-redis-http.js +3 -3
- package/dist/{store-redis-notify-tqWNnMRu.js → store-redis-notify-CM0AfLY0.js} +271 -101
- package/dist/store-redis-notify-CM0AfLY0.js.map +1 -0
- package/dist/store-redis.d.ts +1 -1
- package/dist/store-redis.js +1 -1
- package/dist/store-sqlite.d.ts +1 -1
- package/dist/store-sqlite.js +66 -21
- package/dist/store-sqlite.js.map +1 -1
- package/dist/{telemetry-cZH-cibj.d.ts → telemetry-Cyfqo6Qt.d.ts} +2 -2
- package/dist/telemetry-Cyfqo6Qt.d.ts.map +1 -0
- package/dist/{wire-DjfHOvdW.js → wire-BKxH1vbP.js} +2 -2
- package/dist/{wire-DjfHOvdW.js.map → wire-BKxH1vbP.js.map} +1 -1
- package/docs/01-quickstart.mdx +49 -83
- package/docs/{guides/07-examples.mdx → 02-examples.mdx} +10 -20
- package/docs/actors/01-introduction.mdx +48 -86
- package/docs/actors/02-concurrency.mdx +43 -70
- package/docs/actors/03-timers.mdx +28 -42
- package/docs/actors/04-routes.mdx +110 -150
- 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 +109 -145
- package/docs/reference/01-core.mdx +139 -0
- package/docs/reference/02-server.mdx +860 -0
- package/docs/reference/03-client.mdx +301 -0
- package/docs/reference/04-ai.mdx +731 -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 +142 -0
- package/docs/server/04-routes.mdx +243 -0
- package/docs/server/05-production.mdx +323 -0
- package/docs/server/06-guarantees.mdx +132 -0
- package/examples/playground/DEPLOY.md +3 -5
- package/examples/playground/app/a0/[appId]/page.tsx +12 -13
- package/examples/playground/app/a0/app-list.tsx +9 -2
- package/examples/playground/app/a0/app-view.tsx +9 -1
- package/examples/playground/app/a0/apps/[appId]/route.ts +10 -5
- package/examples/playground/app/a0/apps.test.ts +12 -0
- package/examples/playground/app/a0/apps.ts +22 -7
- package/examples/playground/app/a0/chat.tsx +47 -1
- package/examples/playground/app/a0/devtools.tsx +2 -8
- 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/model.test.ts +18 -1
- package/examples/playground/app/a0/model.ts +47 -10
- 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/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/sandbox-log.ts +10 -4
- package/examples/playground/app/a0/sandbox-session.ts +152 -0
- package/examples/playground/app/a0/scheduler/route.ts +2 -2
- package/examples/playground/app/a0/server.ts +98 -54
- package/examples/playground/app/a0/session.ts +17 -5
- package/examples/playground/app/a0/shell.tsx +11 -3
- package/examples/playground/app/agent/ingress.test.ts +6 -3
- package/examples/playground/app/agent/server.ts +9 -6
- package/examples/playground/app/agent/telemetry.test.ts +71 -50
- package/examples/playground/app/canvas/[canvasId]/canvas-client.tsx +1 -1
- package/examples/playground/app/chat/server.test.ts +30 -26
- package/examples/playground/app/chat/server.ts +46 -46
- package/examples/playground/next.config.ts +17 -5
- package/examples/playground/package.json +4 -1
- package/examples/playground/vercel.json +18 -0
- package/package.json +27 -3
- package/src/ai-agent.ts +271 -90
- package/src/ai-fx.browser.ts +5 -0
- package/src/ai-fx.ts +912 -0
- package/src/ai-harness.ts +518 -0
- package/src/ai-model-metadata.ts +11 -6
- package/src/ai-pi.browser.ts +5 -0
- package/src/ai-pi.ts +1322 -0
- package/src/ai-sdk-step.ts +2 -2
- package/src/ai-server.ts +3 -1
- package/src/ai-tool-input.ts +45 -0
- package/src/internal.ts +13 -0
- package/src/libfx.d.ts +34 -0
- package/src/reducer.ts +1 -1
- package/src/scheduler-qstash.ts +5 -5
- package/src/scheduler-vercel.ts +14 -15
- package/src/server.ts +233 -29
- package/src/store-memory.ts +92 -16
- package/src/store-postgres.ts +156 -25
- package/src/store-redis-core.ts +322 -110
- package/src/store-redis-notify.ts +2 -0
- package/src/store-sqlite.ts +121 -28
- package/src/store.ts +55 -3
- package/src/telemetry.ts +1 -0
- package/dist/internal-CbVvEwad.js.map +0 -1
- package/dist/server-CGM8WzRG.d.ts.map +0 -1
- package/dist/server-Rj64fNvX.js.map +0 -1
- package/dist/session-clear-Dshpuhff.d.ts.map +0 -1
- package/dist/store-Gpkq7WBo.d.ts.map +0 -1
- package/dist/store-redis-notify-tqWNnMRu.js.map +0 -1
- package/dist/telemetry-cZH-cibj.d.ts.map +0 -1
- package/docs/concepts/01-contracts.mdx +0 -237
- 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 -193
- package/docs/guides/02-cancellation.mdx +0 -161
- package/docs/guides/03-react.mdx +0 -324
- package/docs/guides/04-local-first.mdx +0 -47
- package/docs/guides/05-production.mdx +0 -534
- package/docs/guides/06-ai-agents.mdx +0 -1408
- package/docs/guides/08-application-data.mdx +0 -113
- package/docs/guides/09-presence.mdx +0 -262
- package/docs/guides/10-transports.mdx +0 -221
- package/docs/reference/01-api.mdx +0 -2358
- package/docs/reference/02-errors.mdx +0 -150
- /package/docs/{concepts → contract}/meta.ts +0 -0
- /package/docs/{guides → server}/meta.ts +0 -0
package/src/ai-agent.ts
CHANGED
|
@@ -23,9 +23,9 @@ import { AsyncLocalStorage } from 'node:async_hooks'
|
|
|
23
23
|
import { createHash } from 'node:crypto'
|
|
24
24
|
import { convertToModelMessages, isToolUIPart } from 'ai'
|
|
25
25
|
import type {
|
|
26
|
+
Experimental_SandboxSession,
|
|
26
27
|
FinishReason,
|
|
27
28
|
Instructions,
|
|
28
|
-
LanguageModel,
|
|
29
29
|
LanguageModelUsage,
|
|
30
30
|
ModelMessage,
|
|
31
31
|
TextStreamPart,
|
|
@@ -34,6 +34,15 @@ import type {
|
|
|
34
34
|
UIMessageChunk,
|
|
35
35
|
} from 'ai'
|
|
36
36
|
import { generateAISDKStep, type AISDKStepSettings } from './ai-sdk-step.ts'
|
|
37
|
+
import {
|
|
38
|
+
harnessDriver,
|
|
39
|
+
harnessLog,
|
|
40
|
+
harnessStates,
|
|
41
|
+
registerHarnessStates,
|
|
42
|
+
type Harness,
|
|
43
|
+
type HarnessDriver,
|
|
44
|
+
type HarnessStates,
|
|
45
|
+
} from './ai-harness.ts'
|
|
37
46
|
import { gatewayModelId, readModelLimits } from './ai-model-metadata.ts'
|
|
38
47
|
import { estimateInputTokens, measuredInputTokens } from './ai-input-tokens.ts'
|
|
39
48
|
import { AI_STATE_REDUCER, agentContract, events as aiEvents } from './ai.ts'
|
|
@@ -66,6 +75,7 @@ import type {
|
|
|
66
75
|
import { A2Error } from './errors.ts'
|
|
67
76
|
import {
|
|
68
77
|
consumeSchedulerSendFailure,
|
|
78
|
+
failedPreviousAttempt,
|
|
69
79
|
installAmbientToolScopeStorage,
|
|
70
80
|
type AmbientToolScope,
|
|
71
81
|
} from './internal.ts'
|
|
@@ -141,7 +151,8 @@ export type AgentGenerateContext<
|
|
|
141
151
|
> = AgentResolverContext<M, D, X> & {
|
|
142
152
|
generationId: string
|
|
143
153
|
modelMessages: ModelMessage[]
|
|
144
|
-
model
|
|
154
|
+
/** The resolved AI Gateway model ID. */
|
|
155
|
+
model: string
|
|
145
156
|
tools: T
|
|
146
157
|
instructions?: Instructions
|
|
147
158
|
generation: AgentGenerationSettings<T>
|
|
@@ -188,7 +199,8 @@ export type Resolvable<T, C> = T | ((context: C) => T | Promise<T>)
|
|
|
188
199
|
|
|
189
200
|
/** A model with its reasoning level and speed, chosen together. */
|
|
190
201
|
export type ModelSettings = {
|
|
191
|
-
model
|
|
202
|
+
/** An AI Gateway model ID, such as `'anthropic/claude-sonnet-5.5'`. */
|
|
203
|
+
model: string
|
|
192
204
|
/** Overrides `generation.reasoning`. */
|
|
193
205
|
reasoning?: ReasoningLevel
|
|
194
206
|
/** `fast` prefers AI Gateway's faster tier when the model offers one. */
|
|
@@ -235,36 +247,29 @@ export type HandlersOptions<
|
|
|
235
247
|
> = AgentModelOptions<M, D, T, X> & {
|
|
236
248
|
contract: Contract<D, Record<never, never>, unknown>
|
|
237
249
|
telemetry?: A2Telemetry
|
|
250
|
+
/** Where harness steps keep their saved states; one per agent. */
|
|
251
|
+
harnessStates?: HarnessStates
|
|
238
252
|
}
|
|
239
253
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
254
|
+
/** What a tool call does when a crash or a cancellation may have cut it short. */
|
|
255
|
+
export type ToolRecovery = 'rerun' | 'report'
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* The AI SDK harness, the default: one AI SDK `streamText()` step per
|
|
259
|
+
* durable generation, with A2 running tools, approvals, and compaction.
|
|
260
|
+
*/
|
|
261
|
+
export type AISDKHarness<
|
|
262
|
+
M extends UIMessage = UIMessage,
|
|
263
|
+
D extends AIEventDefs<M> & EventDefs = AIEventDefs<M> & EventDefs,
|
|
243
264
|
T extends ToolSet = ToolSet,
|
|
244
265
|
X extends object = Record<never, never>,
|
|
245
266
|
> = {
|
|
246
|
-
|
|
247
|
-
* AI SDK model string or provider model, or `ModelSettings` to choose its
|
|
248
|
-
* reasoning level and speed with it, optionally resolved per generation.
|
|
249
|
-
*/
|
|
250
|
-
model: Resolvable<
|
|
251
|
-
LanguageModel | ModelSettings,
|
|
252
|
-
AgentResolverContext<M, D, X>
|
|
253
|
-
>
|
|
254
|
-
tools?: T
|
|
255
|
-
instructions?: Resolvable<
|
|
256
|
-
Instructions | undefined,
|
|
257
|
-
AgentResolverContext<M, D, X>
|
|
258
|
-
>
|
|
267
|
+
type: 'ai-sdk'
|
|
259
268
|
/** Settings for each one-step AI SDK streamText call, resolved per generation. */
|
|
260
269
|
generation?: Resolvable<
|
|
261
270
|
AgentGenerationSettings<T>,
|
|
262
271
|
AgentResolverContext<M, D, X>
|
|
263
272
|
>
|
|
264
|
-
/**
|
|
265
|
-
* Maximum model steps in one assistant response. Defaults to Infinity.
|
|
266
|
-
*/
|
|
267
|
-
maxSteps?: number
|
|
268
273
|
/** Map default AI SDK stream parts to typed assistant message metadata. */
|
|
269
274
|
messageMetadata?: AgentMessageMetadata<M, D, T, X>
|
|
270
275
|
/**
|
|
@@ -276,6 +281,53 @@ export type AgentModelOptions<
|
|
|
276
281
|
CompactionOptions<M, D, X>,
|
|
277
282
|
AgentResolverContext<M, D, X>
|
|
278
283
|
>
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
type AgentLoopOptions<
|
|
287
|
+
M extends UIMessage,
|
|
288
|
+
D extends AIEventDefs<M> & EventDefs,
|
|
289
|
+
T extends ToolSet,
|
|
290
|
+
X extends object,
|
|
291
|
+
H extends string,
|
|
292
|
+
> =
|
|
293
|
+
| {
|
|
294
|
+
/** The agent's loop: the AI SDK's (the default), or `fx()` or `pi()`. */
|
|
295
|
+
harness?: AISDKHarness<M, D, T, X>
|
|
296
|
+
/** Per tool name: rerun an interrupted call (the default) or report it to the model. */
|
|
297
|
+
toolRecovery?: Readonly<
|
|
298
|
+
Partial<Record<NoInfer<keyof T & string>, ToolRecovery>>
|
|
299
|
+
>
|
|
300
|
+
}
|
|
301
|
+
| {
|
|
302
|
+
harness: Harness<'fx' | 'pi', H>
|
|
303
|
+
/** Per tool name, the harness's own tools included: rerun an interrupted call (the default) or report it. */
|
|
304
|
+
toolRecovery?: Readonly<
|
|
305
|
+
Partial<Record<NoInfer<(keyof T & string) | H>, ToolRecovery>>
|
|
306
|
+
>
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
export type AgentModelOptions<
|
|
310
|
+
M extends UIMessage,
|
|
311
|
+
D extends AIEventDefs<M> & EventDefs,
|
|
312
|
+
T extends ToolSet = ToolSet,
|
|
313
|
+
X extends object = Record<never, never>,
|
|
314
|
+
/** The tool names a harness from `fx()` or `pi()` brings. */
|
|
315
|
+
H extends string = string,
|
|
316
|
+
> = {
|
|
317
|
+
/**
|
|
318
|
+
* An AI Gateway model ID, or `ModelSettings` to choose its reasoning level
|
|
319
|
+
* and speed with it, optionally resolved per generation.
|
|
320
|
+
*/
|
|
321
|
+
model: Resolvable<string | ModelSettings, AgentResolverContext<M, D, X>>
|
|
322
|
+
tools?: T
|
|
323
|
+
instructions?: Resolvable<
|
|
324
|
+
Instructions | undefined,
|
|
325
|
+
AgentResolverContext<M, D, X>
|
|
326
|
+
>
|
|
327
|
+
/**
|
|
328
|
+
* Maximum model steps in one assistant response. Defaults to Infinity.
|
|
329
|
+
*/
|
|
330
|
+
maxSteps?: number
|
|
279
331
|
/** Progress is durably flushed at either limit, whichever is reached first. */
|
|
280
332
|
progress?: { maxChunks?: number; maxDelayMs?: number }
|
|
281
333
|
/**
|
|
@@ -283,7 +335,7 @@ export type AgentModelOptions<
|
|
|
283
335
|
* independent tools run concurrently.
|
|
284
336
|
*/
|
|
285
337
|
toolLane?: string
|
|
286
|
-
}
|
|
338
|
+
} & AgentLoopOptions<M, D, T, X, H>
|
|
287
339
|
|
|
288
340
|
type AgentServerOptions<
|
|
289
341
|
M extends UIMessage,
|
|
@@ -291,7 +343,8 @@ type AgentServerOptions<
|
|
|
291
343
|
S,
|
|
292
344
|
T extends ToolSet,
|
|
293
345
|
X extends object = Record<never, never>,
|
|
294
|
-
|
|
346
|
+
H extends string = string,
|
|
347
|
+
> = AgentModelOptions<M, D, T, X, H> &
|
|
295
348
|
Omit<
|
|
296
349
|
ServerOptions<D, Record<never, never>, Reducer<D, S>>,
|
|
297
350
|
'contract' | 'handlers'
|
|
@@ -304,11 +357,14 @@ export type AgentOptions<
|
|
|
304
357
|
M extends UIMessage,
|
|
305
358
|
E extends EventDefs,
|
|
306
359
|
T extends ToolSet,
|
|
360
|
+
H extends string = string,
|
|
307
361
|
> = AgentServerOptions<
|
|
308
362
|
NoInfer<M>,
|
|
309
363
|
AIEventDefs<NoInfer<M>> & E,
|
|
310
364
|
AIState<NoInfer<M>>,
|
|
311
|
-
T
|
|
365
|
+
T,
|
|
366
|
+
Record<never, never>,
|
|
367
|
+
H
|
|
312
368
|
> & {
|
|
313
369
|
/** Identity: prefixes storage keys and queue messages. */
|
|
314
370
|
name: string
|
|
@@ -327,7 +383,8 @@ export type AgentFromContractOptions<
|
|
|
327
383
|
T extends ToolSet,
|
|
328
384
|
Name extends string = string,
|
|
329
385
|
X extends object = Record<never, never>,
|
|
330
|
-
|
|
386
|
+
H extends string = string,
|
|
387
|
+
> = AgentServerOptions<AIMessageOf<D>, D, S, T, X, H> & {
|
|
331
388
|
/**
|
|
332
389
|
* A shared `agentContract()`. Its application state reaches every resolver
|
|
333
390
|
* as `state`; a fully custom contract is core A2, served by `createServer()`.
|
|
@@ -407,13 +464,14 @@ const withModelSettings = <T extends ToolSet>(options: {
|
|
|
407
464
|
}
|
|
408
465
|
}
|
|
409
466
|
|
|
410
|
-
const
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
467
|
+
const instructionTexts = (instructions: Instructions | undefined): string[] =>
|
|
468
|
+
instructions === undefined
|
|
469
|
+
? []
|
|
470
|
+
: typeof instructions === 'string'
|
|
471
|
+
? [instructions]
|
|
472
|
+
: (Array.isArray(instructions) ? instructions : [instructions]).map(
|
|
473
|
+
(message) => message.content,
|
|
474
|
+
)
|
|
417
475
|
|
|
418
476
|
const errorMessage = (error: unknown): string =>
|
|
419
477
|
error instanceof Error ? error.message : String(error)
|
|
@@ -622,7 +680,15 @@ async function* consumeGeneration(options: {
|
|
|
622
680
|
chunks: mergeDeltas(pending.splice(0)),
|
|
623
681
|
})
|
|
624
682
|
const reader = options.source.stream.getReader()
|
|
625
|
-
|
|
683
|
+
// The next read starts before a batch is yielded, and the consumer may
|
|
684
|
+
// take a while to ask again: a stream that fails meanwhile must not leave
|
|
685
|
+
// that read rejected with no handler, which ends the process.
|
|
686
|
+
const readAhead = (): Promise<StreamRead<UIMessageChunk>> => {
|
|
687
|
+
const read = reader.read()
|
|
688
|
+
read.catch(() => {})
|
|
689
|
+
return read
|
|
690
|
+
}
|
|
691
|
+
let pendingChunk = readAhead()
|
|
626
692
|
try {
|
|
627
693
|
for (;;) {
|
|
628
694
|
let result: StreamRead<UIMessageChunk>
|
|
@@ -643,7 +709,7 @@ async function* consumeGeneration(options: {
|
|
|
643
709
|
pending.push(chunk)
|
|
644
710
|
if (chunk.type === 'finish') streamedFinishReason = chunk.finishReason
|
|
645
711
|
if (chunk.type === 'error') streamedError = chunk.errorText
|
|
646
|
-
pendingChunk =
|
|
712
|
+
pendingChunk = readAhead()
|
|
647
713
|
|
|
648
714
|
if (pending.length >= maxChunks || isBoundaryChunk(pending.at(-1))) {
|
|
649
715
|
yield batch()
|
|
@@ -654,7 +720,6 @@ async function* consumeGeneration(options: {
|
|
|
654
720
|
if (pending.length > 0) yield batch()
|
|
655
721
|
throw error
|
|
656
722
|
} finally {
|
|
657
|
-
void pendingChunk.catch(() => {})
|
|
658
723
|
try {
|
|
659
724
|
await reader.cancel()
|
|
660
725
|
} catch {
|
|
@@ -877,7 +942,8 @@ const lifecycleEvents = async <
|
|
|
877
942
|
pending: PendingToolCall[]
|
|
878
943
|
tools: T
|
|
879
944
|
generation: AgentGenerationSettings<T>
|
|
880
|
-
|
|
945
|
+
/** A harness's tool calls run without approval. */
|
|
946
|
+
approvals?: boolean
|
|
881
947
|
}): Promise<{ events: AppendInput<D>[]; pending: PendingToolCall[] }> => {
|
|
882
948
|
const result: AppendInput<D>[] = []
|
|
883
949
|
const pending = [...options.pending]
|
|
@@ -927,11 +993,14 @@ const lifecycleEvents = async <
|
|
|
927
993
|
...(chunk.title === undefined ? {} : { title: chunk.title }),
|
|
928
994
|
}
|
|
929
995
|
take(payload.toolCallId)
|
|
930
|
-
const classification =
|
|
931
|
-
options.
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
996
|
+
const classification =
|
|
997
|
+
options.approvals === false
|
|
998
|
+
? 'automatic'
|
|
999
|
+
: approvalClassification(
|
|
1000
|
+
options.tools,
|
|
1001
|
+
options.generation,
|
|
1002
|
+
chunk.toolName,
|
|
1003
|
+
)
|
|
935
1004
|
if (classification === 'automatic') {
|
|
936
1005
|
result.push(await toolCalledEvent<D>(payload))
|
|
937
1006
|
} else {
|
|
@@ -1142,6 +1211,26 @@ const validateCompaction = <
|
|
|
1142
1211
|
return compaction
|
|
1143
1212
|
}
|
|
1144
1213
|
|
|
1214
|
+
// Options of the AI SDK harness, which live in it, not on agent().
|
|
1215
|
+
const AI_SDK_HARNESS_OPTIONS = [
|
|
1216
|
+
'generation',
|
|
1217
|
+
'generate',
|
|
1218
|
+
'compaction',
|
|
1219
|
+
'messageMetadata',
|
|
1220
|
+
] as const
|
|
1221
|
+
|
|
1222
|
+
const assertNoLoopOptions = (options: { harness?: { type: string } }): void => {
|
|
1223
|
+
const harness = options.harness?.type ?? 'ai-sdk'
|
|
1224
|
+
for (const key of AI_SDK_HARNESS_OPTIONS) {
|
|
1225
|
+
if (!Object.hasOwn(options, key)) continue
|
|
1226
|
+
throw new TypeError(
|
|
1227
|
+
harness === 'ai-sdk'
|
|
1228
|
+
? `${key} belongs to the harness: agent({ harness: { type: 'ai-sdk', ${key} } })`
|
|
1229
|
+
: `${key} is an option of the AI SDK harness; ${harness}() runs its own loop`,
|
|
1230
|
+
)
|
|
1231
|
+
}
|
|
1232
|
+
}
|
|
1233
|
+
|
|
1145
1234
|
export function createHandlers<
|
|
1146
1235
|
M extends UIMessage,
|
|
1147
1236
|
D extends AIEventDefs<M> & EventDefs,
|
|
@@ -1175,22 +1264,63 @@ export function createHandlers<
|
|
|
1175
1264
|
throw new TypeError('maxSteps must be a positive integer or Infinity')
|
|
1176
1265
|
}
|
|
1177
1266
|
|
|
1267
|
+
assertNoLoopOptions(options)
|
|
1268
|
+
const configured = options.harness
|
|
1269
|
+
const loop: Omit<AISDKHarness<M, D, T, X>, 'type'> = configured?.type ===
|
|
1270
|
+
'ai-sdk'
|
|
1271
|
+
? configured
|
|
1272
|
+
: {}
|
|
1273
|
+
const harness: HarnessDriver | undefined =
|
|
1274
|
+
configured === undefined || configured.type === 'ai-sdk'
|
|
1275
|
+
? undefined
|
|
1276
|
+
: harnessDriver(configured)
|
|
1277
|
+
const states = options.harnessStates ?? harnessStates()
|
|
1278
|
+
if (harness !== undefined) {
|
|
1279
|
+
for (const [name, tool] of Object.entries(options.tools ?? {})) {
|
|
1280
|
+
const needsApproval = (tool as { needsApproval?: unknown }).needsApproval
|
|
1281
|
+
if (needsApproval !== undefined && needsApproval !== false)
|
|
1282
|
+
throw new TypeError(
|
|
1283
|
+
`a harness runs tools without approval; '${name}' sets needsApproval`,
|
|
1284
|
+
)
|
|
1285
|
+
}
|
|
1286
|
+
}
|
|
1287
|
+
|
|
1178
1288
|
const configuredCompaction =
|
|
1179
|
-
|
|
1289
|
+
loop.compaction ??
|
|
1290
|
+
(loop.generate === undefined && harness === undefined ? {} : false)
|
|
1180
1291
|
const staticCompaction =
|
|
1181
1292
|
typeof configuredCompaction === 'function'
|
|
1182
1293
|
? undefined
|
|
1183
1294
|
: validateCompaction({
|
|
1184
1295
|
compaction: configuredCompaction,
|
|
1185
|
-
explicit:
|
|
1296
|
+
explicit: loop.compaction !== undefined,
|
|
1186
1297
|
generation:
|
|
1187
|
-
typeof
|
|
1188
|
-
? undefined
|
|
1189
|
-
: options.generation,
|
|
1298
|
+
typeof loop.generation === 'function' ? undefined : loop.generation,
|
|
1190
1299
|
tools: options.tools,
|
|
1191
1300
|
})
|
|
1192
1301
|
|
|
1193
|
-
|
|
1302
|
+
// The harness's own tools come first, so an agent tool with a name replaces them.
|
|
1303
|
+
const tools = (
|
|
1304
|
+
harness === undefined
|
|
1305
|
+
? (options.tools ?? {})
|
|
1306
|
+
: { ...harness.tools, ...options.tools }
|
|
1307
|
+
) as T
|
|
1308
|
+
const toolRecovery: Readonly<Record<string, ToolRecovery | undefined>> =
|
|
1309
|
+
options.toolRecovery ?? {}
|
|
1310
|
+
for (const [name, recovery] of Object.entries(toolRecovery)) {
|
|
1311
|
+
if (!Object.hasOwn(tools, name))
|
|
1312
|
+
throw new TypeError(
|
|
1313
|
+
`toolRecovery names '${name}', which is not one of the agent's tools`,
|
|
1314
|
+
)
|
|
1315
|
+
if (typeof (tools[name] as RuntimeTool).execute !== 'function')
|
|
1316
|
+
throw new TypeError(
|
|
1317
|
+
`toolRecovery names '${name}', which has no execute function`,
|
|
1318
|
+
)
|
|
1319
|
+
if (recovery !== 'rerun' && recovery !== 'report')
|
|
1320
|
+
throw new TypeError(
|
|
1321
|
+
`toolRecovery for '${name}' must be 'rerun' or 'report'`,
|
|
1322
|
+
)
|
|
1323
|
+
}
|
|
1194
1324
|
const telemetry = options.telemetry ?? CONSOLE_TELEMETRY
|
|
1195
1325
|
const maxSteps = options.maxSteps ?? Number.POSITIVE_INFINITY
|
|
1196
1326
|
const control = createControlRuntime({
|
|
@@ -1250,6 +1380,7 @@ export function createHandlers<
|
|
|
1250
1380
|
toolCallId: string
|
|
1251
1381
|
messages: ModelMessage[]
|
|
1252
1382
|
abortSignal?: AbortSignal
|
|
1383
|
+
experimental_sandbox?: Experimental_SandboxSession
|
|
1253
1384
|
},
|
|
1254
1385
|
) => unknown
|
|
1255
1386
|
}
|
|
@@ -1366,6 +1497,7 @@ export function createHandlers<
|
|
|
1366
1497
|
call: ToolCalledPayload,
|
|
1367
1498
|
execute: NonNullable<RuntimeTool['execute']>,
|
|
1368
1499
|
messages: ModelMessage[],
|
|
1500
|
+
sandbox: Experimental_SandboxSession | undefined,
|
|
1369
1501
|
): Promise<AppendInput<D> | void> => {
|
|
1370
1502
|
let output: unknown
|
|
1371
1503
|
try {
|
|
@@ -1373,6 +1505,7 @@ export function createHandlers<
|
|
|
1373
1505
|
toolCallId: call.toolCallId,
|
|
1374
1506
|
messages,
|
|
1375
1507
|
abortSignal: ctx.signal,
|
|
1508
|
+
...(sandbox === undefined ? {} : { experimental_sandbox: sandbox }),
|
|
1376
1509
|
})
|
|
1377
1510
|
} catch (error) {
|
|
1378
1511
|
return toolExecutionFailure(ctx, call, error)
|
|
@@ -1449,7 +1582,25 @@ export function createHandlers<
|
|
|
1449
1582
|
error: `Tool '${call.toolName}' has no server executor`,
|
|
1450
1583
|
})
|
|
1451
1584
|
}
|
|
1585
|
+
const report = toolRecovery[call.toolName] === 'report'
|
|
1586
|
+
const interrupted = () =>
|
|
1587
|
+
resultEvent(call, `${ctx.event.id}:execution:error`, {
|
|
1588
|
+
error: `Tool '${call.toolName}' was interrupted and may have partly run.`,
|
|
1589
|
+
})
|
|
1590
|
+
// A thrown failure never follows `execute` for a reported tool (see
|
|
1591
|
+
// below), so only a lapsed attempt may have reached it.
|
|
1592
|
+
if (report && ctx.attempt > 1 && !failedPreviousAttempt.has(ctx))
|
|
1593
|
+
return interrupted()
|
|
1452
1594
|
const messages = await promptMessages(input)
|
|
1595
|
+
// A sandbox that fails to resolve fails the attempt, which A2 retries;
|
|
1596
|
+
// it is not the tool's failure to report to the model.
|
|
1597
|
+
const sandbox =
|
|
1598
|
+
harness?.sandbox === undefined
|
|
1599
|
+
? undefined
|
|
1600
|
+
: await resolve(harness.sandbox, {
|
|
1601
|
+
session: { id: ctx.session.id },
|
|
1602
|
+
signal: ctx.signal,
|
|
1603
|
+
})
|
|
1453
1604
|
if (checkAbort(ctx.signal)) return
|
|
1454
1605
|
const scope: AmbientToolScope = {
|
|
1455
1606
|
contract: options.contract,
|
|
@@ -1457,9 +1608,19 @@ export function createHandlers<
|
|
|
1457
1608
|
}
|
|
1458
1609
|
// Async iteration resumes in the caller's context, so the whole
|
|
1459
1610
|
// execution, not just the execute call, runs inside the scope.
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1611
|
+
const run = () =>
|
|
1612
|
+
toolScopeStorage.run(scope, () =>
|
|
1613
|
+
runToolExecution(ctx, call, execute, messages, sandbox),
|
|
1614
|
+
)
|
|
1615
|
+
if (!report) return run()
|
|
1616
|
+
try {
|
|
1617
|
+
// Undefined means a user cancellation after `execute` started.
|
|
1618
|
+
return (await run()) ?? (await interrupted())
|
|
1619
|
+
} catch {
|
|
1620
|
+
// A lapsed claim surrenders; the next attempt reports the call.
|
|
1621
|
+
checkAbort(ctx.signal)
|
|
1622
|
+
return interrupted()
|
|
1623
|
+
}
|
|
1463
1624
|
}
|
|
1464
1625
|
|
|
1465
1626
|
const handleToolExecution = async (
|
|
@@ -1632,19 +1793,17 @@ export function createHandlers<
|
|
|
1632
1793
|
} as AppendInput<D>)
|
|
1633
1794
|
return events
|
|
1634
1795
|
}
|
|
1635
|
-
const startedPayload = (
|
|
1636
|
-
model?: LanguageModel,
|
|
1637
|
-
): GenerationStartedPayload => ({
|
|
1796
|
+
const startedPayload = (model?: string): GenerationStartedPayload => ({
|
|
1638
1797
|
requestId,
|
|
1639
1798
|
messageId: request.messageId,
|
|
1640
1799
|
generationId,
|
|
1641
1800
|
responseMessageId,
|
|
1642
1801
|
attempt,
|
|
1643
|
-
...(model === undefined ? {} : { model
|
|
1802
|
+
...(model === undefined ? {} : { model }),
|
|
1644
1803
|
promptThroughIndex: snapshot.index,
|
|
1645
1804
|
})
|
|
1646
1805
|
|
|
1647
|
-
let resolvedModel:
|
|
1806
|
+
let resolvedModel: string | undefined
|
|
1648
1807
|
let resolving = true
|
|
1649
1808
|
let generationStarted = false
|
|
1650
1809
|
try {
|
|
@@ -1653,15 +1812,10 @@ export function createHandlers<
|
|
|
1653
1812
|
throw new TypeError('the model resolver returned undefined')
|
|
1654
1813
|
}
|
|
1655
1814
|
const settings: ModelSettings =
|
|
1656
|
-
typeof choice === 'string'
|
|
1657
|
-
? { model: choice }
|
|
1658
|
-
: choice
|
|
1815
|
+
typeof choice === 'string' ? { model: choice } : choice
|
|
1659
1816
|
const model = settings.model
|
|
1660
|
-
if (
|
|
1661
|
-
|
|
1662
|
-
(typeof model !== 'object' || model === null)
|
|
1663
|
-
)
|
|
1664
|
-
throw new TypeError('the model resolver must return a model')
|
|
1817
|
+
if (typeof model !== 'string' || model === '')
|
|
1818
|
+
throw new TypeError('the model must be an AI Gateway model ID')
|
|
1665
1819
|
resolvedModel = model
|
|
1666
1820
|
if (checkAbort(ctx.signal)) return
|
|
1667
1821
|
const resolvedInstructions =
|
|
@@ -1670,7 +1824,7 @@ export function createHandlers<
|
|
|
1670
1824
|
: await resolve(options.instructions, resolverContext)
|
|
1671
1825
|
if (checkAbort(ctx.signal)) return
|
|
1672
1826
|
const resolvedGeneration: AgentGenerationSettings<T> = await resolve(
|
|
1673
|
-
|
|
1827
|
+
loop.generation ?? {},
|
|
1674
1828
|
resolverContext,
|
|
1675
1829
|
)
|
|
1676
1830
|
if (checkAbort(ctx.signal)) return
|
|
@@ -1686,13 +1840,13 @@ export function createHandlers<
|
|
|
1686
1840
|
})
|
|
1687
1841
|
const compaction =
|
|
1688
1842
|
typeof configuredCompaction === 'function' ||
|
|
1689
|
-
typeof
|
|
1843
|
+
typeof loop.generation === 'function'
|
|
1690
1844
|
? validateCompaction({
|
|
1691
1845
|
compaction:
|
|
1692
1846
|
typeof configuredCompaction === 'function'
|
|
1693
1847
|
? await resolve(configuredCompaction, resolverContext)
|
|
1694
1848
|
: staticCompaction!,
|
|
1695
|
-
explicit:
|
|
1849
|
+
explicit: loop.compaction !== undefined,
|
|
1696
1850
|
generation,
|
|
1697
1851
|
tools: options.tools,
|
|
1698
1852
|
})
|
|
@@ -1802,7 +1956,7 @@ export function createHandlers<
|
|
|
1802
1956
|
})
|
|
1803
1957
|
const inputTokens = measuredInputTokens({
|
|
1804
1958
|
estimate: inputTokenEstimate,
|
|
1805
|
-
model:
|
|
1959
|
+
model: resolvedModel,
|
|
1806
1960
|
calibration: coordinatorState.calibration,
|
|
1807
1961
|
})
|
|
1808
1962
|
const threshold =
|
|
@@ -1988,15 +2142,40 @@ export function createHandlers<
|
|
|
1988
2142
|
messages: generationMessages,
|
|
1989
2143
|
modelMessages,
|
|
1990
2144
|
}
|
|
1991
|
-
const custom = options.generate !== undefined
|
|
1992
2145
|
const source =
|
|
1993
|
-
|
|
1994
|
-
? await
|
|
2146
|
+
harness !== undefined
|
|
2147
|
+
? await harness.step({
|
|
1995
2148
|
agentName: options.contract.name,
|
|
1996
|
-
|
|
1997
|
-
|
|
2149
|
+
sessionId: ctx.event.sessionId,
|
|
2150
|
+
requestIndex: ctx.event.index,
|
|
2151
|
+
generationId,
|
|
2152
|
+
responseMessageId,
|
|
2153
|
+
throughIndex: snapshot.index,
|
|
2154
|
+
messages: generationMessages,
|
|
2155
|
+
model,
|
|
2156
|
+
...(settings.reasoning === undefined
|
|
2157
|
+
? {}
|
|
2158
|
+
: { reasoning: settings.reasoning }),
|
|
2159
|
+
...(settings.speed === undefined
|
|
2160
|
+
? {}
|
|
2161
|
+
: { speed: settings.speed }),
|
|
2162
|
+
instructions: instructionTexts(resolvedInstructions),
|
|
2163
|
+
tools,
|
|
2164
|
+
log: harnessLog({
|
|
2165
|
+
states,
|
|
2166
|
+
session: ctx.session as Parameters<
|
|
2167
|
+
typeof harnessLog
|
|
2168
|
+
>[0]['session'],
|
|
2169
|
+
}),
|
|
2170
|
+
signal: ctx.signal,
|
|
1998
2171
|
})
|
|
1999
|
-
:
|
|
2172
|
+
: loop.generate === undefined
|
|
2173
|
+
? await generateWithAISDK({
|
|
2174
|
+
agentName: options.contract.name,
|
|
2175
|
+
context: generateContext,
|
|
2176
|
+
messageMetadata: loop.messageMetadata,
|
|
2177
|
+
})
|
|
2178
|
+
: { stream: await loop.generate(generateContext) }
|
|
2000
2179
|
const updates = consumeGeneration({
|
|
2001
2180
|
source,
|
|
2002
2181
|
...(options.progress === undefined
|
|
@@ -2025,7 +2204,7 @@ export function createHandlers<
|
|
|
2025
2204
|
pending: pendingToolCalls,
|
|
2026
2205
|
tools,
|
|
2027
2206
|
generation,
|
|
2028
|
-
|
|
2207
|
+
approvals: harness === undefined,
|
|
2029
2208
|
})
|
|
2030
2209
|
pendingToolCalls = lifecycle.pending
|
|
2031
2210
|
await control.append({
|
|
@@ -2064,7 +2243,7 @@ export function createHandlers<
|
|
|
2064
2243
|
id: await aiEventId('a2.ai.completed', generationId),
|
|
2065
2244
|
payload: completed,
|
|
2066
2245
|
} as AppendInput<D>
|
|
2067
|
-
const unresolved =
|
|
2246
|
+
const unresolved = loop.generate
|
|
2068
2247
|
? pendingToolCalls.filter(
|
|
2069
2248
|
(pending) => pending.classification !== 'automatic',
|
|
2070
2249
|
)
|
|
@@ -2079,7 +2258,7 @@ export function createHandlers<
|
|
|
2079
2258
|
.filter(
|
|
2080
2259
|
(pending) =>
|
|
2081
2260
|
pending.classification === 'automatic' ||
|
|
2082
|
-
(
|
|
2261
|
+
(loop.generate === undefined &&
|
|
2083
2262
|
pending.classification === 'unknown'),
|
|
2084
2263
|
)
|
|
2085
2264
|
.map((pending) => toolCalledEvent<D>(pending.call)),
|
|
@@ -2255,8 +2434,9 @@ export function agent<
|
|
|
2255
2434
|
T extends ToolSet = ToolSet,
|
|
2256
2435
|
M extends UIMessage = UIMessage,
|
|
2257
2436
|
E extends EventDefs = Record<never, never>,
|
|
2437
|
+
H extends string = never,
|
|
2258
2438
|
>(
|
|
2259
|
-
options: AgentOptions<M, E, T>,
|
|
2439
|
+
options: AgentOptions<M, E, T, H>,
|
|
2260
2440
|
): Agent<AIEventDefs<M> & E, AIState<M>, typeof AI_STATE_REDUCER>
|
|
2261
2441
|
export function agent<
|
|
2262
2442
|
D extends AIEventDefs<AIMessageOf<D>> & EventDefs,
|
|
@@ -2264,22 +2444,22 @@ export function agent<
|
|
|
2264
2444
|
T extends ToolSet = ToolSet,
|
|
2265
2445
|
Name extends string = string,
|
|
2266
2446
|
X extends object = Record<never, never>,
|
|
2267
|
-
|
|
2447
|
+
H extends string = never,
|
|
2448
|
+
>(options: AgentFromContractOptions<D, S, T, Name, X, H>): Agent<D, S, Name>
|
|
2268
2449
|
export function agent(
|
|
2269
2450
|
options:
|
|
2270
2451
|
| AgentOptions<UIMessage, EventDefs, ToolSet>
|
|
2271
2452
|
| AgentFromContractOptions<AIEventDefs & EventDefs, AIState, ToolSet>,
|
|
2272
2453
|
): Agent<AIEventDefs & EventDefs, AIState> {
|
|
2273
2454
|
type D = AIEventDefs & EventDefs
|
|
2455
|
+
assertNoLoopOptions(options)
|
|
2274
2456
|
const {
|
|
2275
2457
|
model,
|
|
2276
2458
|
tools,
|
|
2277
2459
|
instructions,
|
|
2278
|
-
generation,
|
|
2279
2460
|
maxSteps,
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
compaction,
|
|
2461
|
+
harness,
|
|
2462
|
+
toolRecovery,
|
|
2283
2463
|
progress,
|
|
2284
2464
|
toolLane,
|
|
2285
2465
|
handlers,
|
|
@@ -2307,22 +2487,22 @@ export function agent(
|
|
|
2307
2487
|
})
|
|
2308
2488
|
serverOptions = remaining
|
|
2309
2489
|
}
|
|
2490
|
+
const states = harnessStates()
|
|
2310
2491
|
const builtIns = createHandlers<UIMessage, D>({
|
|
2311
2492
|
contract,
|
|
2312
2493
|
model,
|
|
2494
|
+
harnessStates: states,
|
|
2313
2495
|
...(serverOptions.telemetry === undefined
|
|
2314
2496
|
? {}
|
|
2315
2497
|
: { telemetry: serverOptions.telemetry }),
|
|
2316
2498
|
...(tools === undefined ? {} : { tools }),
|
|
2317
2499
|
...(instructions === undefined ? {} : { instructions }),
|
|
2318
|
-
...(generation === undefined ? {} : { generation }),
|
|
2319
2500
|
...(maxSteps === undefined ? {} : { maxSteps }),
|
|
2320
|
-
...(
|
|
2321
|
-
...(
|
|
2322
|
-
...(compaction === undefined ? {} : { compaction }),
|
|
2501
|
+
...(harness === undefined ? {} : { harness }),
|
|
2502
|
+
...(toolRecovery === undefined ? {} : { toolRecovery }),
|
|
2323
2503
|
...(progress === undefined ? {} : { progress }),
|
|
2324
2504
|
...(toolLane === undefined ? {} : { toolLane }),
|
|
2325
|
-
})
|
|
2505
|
+
} as HandlersOptions<UIMessage, D>)
|
|
2326
2506
|
for (const type of Object.keys(handlers ?? {})) {
|
|
2327
2507
|
if (Object.hasOwn(builtIns, type))
|
|
2328
2508
|
throw new TypeError(`agent handles '${type}' itself`)
|
|
@@ -2332,6 +2512,7 @@ export function agent(
|
|
|
2332
2512
|
contract,
|
|
2333
2513
|
handlers: { ...builtIns, ...handlers },
|
|
2334
2514
|
})
|
|
2515
|
+
registerHarnessStates(server, states)
|
|
2335
2516
|
const applicationEvents = 'contract' in rest
|
|
2336
2517
|
setServerFetchHooks(server, {
|
|
2337
2518
|
validateIngress: (context) =>
|
|
@@ -2340,4 +2521,4 @@ export function agent(
|
|
|
2340
2521
|
return server
|
|
2341
2522
|
}
|
|
2342
2523
|
|
|
2343
|
-
export type { Instructions,
|
|
2524
|
+
export type { Instructions, ToolSet }
|