experimental-a2 0.17.0 → 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 +21 -0
- package/README.md +1 -1
- package/dist/{actor-DBbe5xeE.d.ts → actor-Bjce9_5U.d.ts} +5 -5
- package/dist/{actor-DBbe5xeE.d.ts.map → actor-Bjce9_5U.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-UrWfKeuv.js → ai-BpOGm-zB.js} +2 -2
- package/dist/{ai-UrWfKeuv.js.map → ai-BpOGm-zB.js.map} +1 -1
- package/dist/{ai-vpGtcaCB.d.ts → ai-DrUaMyRt.d.ts} +3 -3
- package/dist/{ai-vpGtcaCB.d.ts.map → ai-DrUaMyRt.d.ts.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 +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 +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 +106 -37
- package/dist/ai-server.js.map +1 -1
- 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-BReKqwZC.js} +3 -3
- package/dist/{client-COaiaDub.js.map → client-BReKqwZC.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-B2T3U4Rq.js} +8 -2
- package/dist/internal-B2T3U4Rq.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 +2 -2
- package/dist/scheduler-vercel.d.ts +2 -2
- package/dist/scheduler-vercel.js +2 -2
- package/dist/{server-Rj64fNvX.js → server-Dw_k_7kO.js} +93 -60
- package/dist/server-Dw_k_7kO.js.map +1 -0
- package/dist/{server-CGM8WzRG.d.ts → server-En7cbi3v.d.ts} +36 -7
- package/dist/server-En7cbi3v.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-Bo-XTFEy.d.ts} +2 -2
- package/dist/session-clear-Bo-XTFEy.d.ts.map +1 -0
- package/dist/{store-Gpkq7WBo.d.ts → store-Djdv0bnZ.d.ts} +31 -2
- 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.js +32 -6
- package/dist/store-memory.js.map +1 -1
- package/dist/{store-polling-4_y8lETm.js → store-polling-B5FcwJfo.js} +2 -2
- package/dist/{store-polling-4_y8lETm.js.map → store-polling-B5FcwJfo.js.map} +1 -1
- package/dist/store-postgres.d.ts +1 -1
- package/dist/store-postgres.js +54 -3
- package/dist/store-postgres.js.map +1 -1
- package/dist/{store-presence-polling-Q1C-k2dd.js → store-presence-polling-BAwS8RWn.js} +3 -3
- package/dist/{store-presence-polling-Q1C-k2dd.js.map → store-presence-polling-BAwS8RWn.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-BRITti_o.js} +187 -68
- package/dist/store-redis-notify-BRITti_o.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 +32 -2
- 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-rSUglYo8.js} +2 -2
- package/dist/{wire-DjfHOvdW.js.map → wire-rSUglYo8.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 +108 -144
- 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 +1 -1
- package/examples/playground/app/a0/[appId]/page.tsx +11 -6
- 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/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 +100 -45
- 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 +261 -87
- 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-model-metadata.ts +11 -6
- package/src/ai-pi.browser.ts +5 -0
- package/src/ai-pi.ts +1263 -0
- package/src/ai-sdk-step.ts +2 -2
- package/src/ai-server.ts +3 -1
- package/src/internal.ts +7 -0
- package/src/libfx.d.ts +34 -0
- package/src/reducer.ts +1 -1
- package/src/server.ts +177 -19
- package/src/store-memory.ts +42 -7
- package/src/store-postgres.ts +80 -0
- package/src/store-redis-core.ts +210 -79
- package/src/store-redis-notify.ts +2 -0
- package/src/store-sqlite.ts +60 -0
- package/src/store.ts +33 -0
- 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)
|
|
@@ -877,7 +935,8 @@ const lifecycleEvents = async <
|
|
|
877
935
|
pending: PendingToolCall[]
|
|
878
936
|
tools: T
|
|
879
937
|
generation: AgentGenerationSettings<T>
|
|
880
|
-
|
|
938
|
+
/** A harness's tool calls run without approval. */
|
|
939
|
+
approvals?: boolean
|
|
881
940
|
}): Promise<{ events: AppendInput<D>[]; pending: PendingToolCall[] }> => {
|
|
882
941
|
const result: AppendInput<D>[] = []
|
|
883
942
|
const pending = [...options.pending]
|
|
@@ -927,11 +986,14 @@ const lifecycleEvents = async <
|
|
|
927
986
|
...(chunk.title === undefined ? {} : { title: chunk.title }),
|
|
928
987
|
}
|
|
929
988
|
take(payload.toolCallId)
|
|
930
|
-
const classification =
|
|
931
|
-
options.
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
989
|
+
const classification =
|
|
990
|
+
options.approvals === false
|
|
991
|
+
? 'automatic'
|
|
992
|
+
: approvalClassification(
|
|
993
|
+
options.tools,
|
|
994
|
+
options.generation,
|
|
995
|
+
chunk.toolName,
|
|
996
|
+
)
|
|
935
997
|
if (classification === 'automatic') {
|
|
936
998
|
result.push(await toolCalledEvent<D>(payload))
|
|
937
999
|
} else {
|
|
@@ -1142,6 +1204,26 @@ const validateCompaction = <
|
|
|
1142
1204
|
return compaction
|
|
1143
1205
|
}
|
|
1144
1206
|
|
|
1207
|
+
// Options of the AI SDK harness, which live in it, not on agent().
|
|
1208
|
+
const AI_SDK_HARNESS_OPTIONS = [
|
|
1209
|
+
'generation',
|
|
1210
|
+
'generate',
|
|
1211
|
+
'compaction',
|
|
1212
|
+
'messageMetadata',
|
|
1213
|
+
] as const
|
|
1214
|
+
|
|
1215
|
+
const assertNoLoopOptions = (options: { harness?: { type: string } }): void => {
|
|
1216
|
+
const harness = options.harness?.type ?? 'ai-sdk'
|
|
1217
|
+
for (const key of AI_SDK_HARNESS_OPTIONS) {
|
|
1218
|
+
if (!Object.hasOwn(options, key)) continue
|
|
1219
|
+
throw new TypeError(
|
|
1220
|
+
harness === 'ai-sdk'
|
|
1221
|
+
? `${key} belongs to the harness: agent({ harness: { type: 'ai-sdk', ${key} } })`
|
|
1222
|
+
: `${key} is an option of the AI SDK harness; ${harness}() runs its own loop`,
|
|
1223
|
+
)
|
|
1224
|
+
}
|
|
1225
|
+
}
|
|
1226
|
+
|
|
1145
1227
|
export function createHandlers<
|
|
1146
1228
|
M extends UIMessage,
|
|
1147
1229
|
D extends AIEventDefs<M> & EventDefs,
|
|
@@ -1175,22 +1257,63 @@ export function createHandlers<
|
|
|
1175
1257
|
throw new TypeError('maxSteps must be a positive integer or Infinity')
|
|
1176
1258
|
}
|
|
1177
1259
|
|
|
1260
|
+
assertNoLoopOptions(options)
|
|
1261
|
+
const configured = options.harness
|
|
1262
|
+
const loop: Omit<AISDKHarness<M, D, T, X>, 'type'> = configured?.type ===
|
|
1263
|
+
'ai-sdk'
|
|
1264
|
+
? configured
|
|
1265
|
+
: {}
|
|
1266
|
+
const harness: HarnessDriver | undefined =
|
|
1267
|
+
configured === undefined || configured.type === 'ai-sdk'
|
|
1268
|
+
? undefined
|
|
1269
|
+
: harnessDriver(configured)
|
|
1270
|
+
const states = options.harnessStates ?? harnessStates()
|
|
1271
|
+
if (harness !== undefined) {
|
|
1272
|
+
for (const [name, tool] of Object.entries(options.tools ?? {})) {
|
|
1273
|
+
const needsApproval = (tool as { needsApproval?: unknown }).needsApproval
|
|
1274
|
+
if (needsApproval !== undefined && needsApproval !== false)
|
|
1275
|
+
throw new TypeError(
|
|
1276
|
+
`a harness runs tools without approval; '${name}' sets needsApproval`,
|
|
1277
|
+
)
|
|
1278
|
+
}
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1178
1281
|
const configuredCompaction =
|
|
1179
|
-
|
|
1282
|
+
loop.compaction ??
|
|
1283
|
+
(loop.generate === undefined && harness === undefined ? {} : false)
|
|
1180
1284
|
const staticCompaction =
|
|
1181
1285
|
typeof configuredCompaction === 'function'
|
|
1182
1286
|
? undefined
|
|
1183
1287
|
: validateCompaction({
|
|
1184
1288
|
compaction: configuredCompaction,
|
|
1185
|
-
explicit:
|
|
1289
|
+
explicit: loop.compaction !== undefined,
|
|
1186
1290
|
generation:
|
|
1187
|
-
typeof
|
|
1188
|
-
? undefined
|
|
1189
|
-
: options.generation,
|
|
1291
|
+
typeof loop.generation === 'function' ? undefined : loop.generation,
|
|
1190
1292
|
tools: options.tools,
|
|
1191
1293
|
})
|
|
1192
1294
|
|
|
1193
|
-
|
|
1295
|
+
// The harness's own tools come first, so an agent tool with a name replaces them.
|
|
1296
|
+
const tools = (
|
|
1297
|
+
harness === undefined
|
|
1298
|
+
? (options.tools ?? {})
|
|
1299
|
+
: { ...harness.tools, ...options.tools }
|
|
1300
|
+
) as T
|
|
1301
|
+
const toolRecovery: Readonly<Record<string, ToolRecovery | undefined>> =
|
|
1302
|
+
options.toolRecovery ?? {}
|
|
1303
|
+
for (const [name, recovery] of Object.entries(toolRecovery)) {
|
|
1304
|
+
if (!Object.hasOwn(tools, name))
|
|
1305
|
+
throw new TypeError(
|
|
1306
|
+
`toolRecovery names '${name}', which is not one of the agent's tools`,
|
|
1307
|
+
)
|
|
1308
|
+
if (typeof (tools[name] as RuntimeTool).execute !== 'function')
|
|
1309
|
+
throw new TypeError(
|
|
1310
|
+
`toolRecovery names '${name}', which has no execute function`,
|
|
1311
|
+
)
|
|
1312
|
+
if (recovery !== 'rerun' && recovery !== 'report')
|
|
1313
|
+
throw new TypeError(
|
|
1314
|
+
`toolRecovery for '${name}' must be 'rerun' or 'report'`,
|
|
1315
|
+
)
|
|
1316
|
+
}
|
|
1194
1317
|
const telemetry = options.telemetry ?? CONSOLE_TELEMETRY
|
|
1195
1318
|
const maxSteps = options.maxSteps ?? Number.POSITIVE_INFINITY
|
|
1196
1319
|
const control = createControlRuntime({
|
|
@@ -1250,6 +1373,7 @@ export function createHandlers<
|
|
|
1250
1373
|
toolCallId: string
|
|
1251
1374
|
messages: ModelMessage[]
|
|
1252
1375
|
abortSignal?: AbortSignal
|
|
1376
|
+
experimental_sandbox?: Experimental_SandboxSession
|
|
1253
1377
|
},
|
|
1254
1378
|
) => unknown
|
|
1255
1379
|
}
|
|
@@ -1366,6 +1490,7 @@ export function createHandlers<
|
|
|
1366
1490
|
call: ToolCalledPayload,
|
|
1367
1491
|
execute: NonNullable<RuntimeTool['execute']>,
|
|
1368
1492
|
messages: ModelMessage[],
|
|
1493
|
+
sandbox: Experimental_SandboxSession | undefined,
|
|
1369
1494
|
): Promise<AppendInput<D> | void> => {
|
|
1370
1495
|
let output: unknown
|
|
1371
1496
|
try {
|
|
@@ -1373,6 +1498,7 @@ export function createHandlers<
|
|
|
1373
1498
|
toolCallId: call.toolCallId,
|
|
1374
1499
|
messages,
|
|
1375
1500
|
abortSignal: ctx.signal,
|
|
1501
|
+
...(sandbox === undefined ? {} : { experimental_sandbox: sandbox }),
|
|
1376
1502
|
})
|
|
1377
1503
|
} catch (error) {
|
|
1378
1504
|
return toolExecutionFailure(ctx, call, error)
|
|
@@ -1449,7 +1575,25 @@ export function createHandlers<
|
|
|
1449
1575
|
error: `Tool '${call.toolName}' has no server executor`,
|
|
1450
1576
|
})
|
|
1451
1577
|
}
|
|
1578
|
+
const report = toolRecovery[call.toolName] === 'report'
|
|
1579
|
+
const interrupted = () =>
|
|
1580
|
+
resultEvent(call, `${ctx.event.id}:execution:error`, {
|
|
1581
|
+
error: `Tool '${call.toolName}' was interrupted and may have partly run.`,
|
|
1582
|
+
})
|
|
1583
|
+
// A thrown failure never follows `execute` for a reported tool (see
|
|
1584
|
+
// below), so only a lapsed attempt may have reached it.
|
|
1585
|
+
if (report && ctx.attempt > 1 && !failedPreviousAttempt.has(ctx))
|
|
1586
|
+
return interrupted()
|
|
1452
1587
|
const messages = await promptMessages(input)
|
|
1588
|
+
// A sandbox that fails to resolve fails the attempt, which A2 retries;
|
|
1589
|
+
// it is not the tool's failure to report to the model.
|
|
1590
|
+
const sandbox =
|
|
1591
|
+
harness?.sandbox === undefined
|
|
1592
|
+
? undefined
|
|
1593
|
+
: await resolve(harness.sandbox, {
|
|
1594
|
+
session: { id: ctx.session.id },
|
|
1595
|
+
signal: ctx.signal,
|
|
1596
|
+
})
|
|
1453
1597
|
if (checkAbort(ctx.signal)) return
|
|
1454
1598
|
const scope: AmbientToolScope = {
|
|
1455
1599
|
contract: options.contract,
|
|
@@ -1457,9 +1601,19 @@ export function createHandlers<
|
|
|
1457
1601
|
}
|
|
1458
1602
|
// Async iteration resumes in the caller's context, so the whole
|
|
1459
1603
|
// execution, not just the execute call, runs inside the scope.
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1604
|
+
const run = () =>
|
|
1605
|
+
toolScopeStorage.run(scope, () =>
|
|
1606
|
+
runToolExecution(ctx, call, execute, messages, sandbox),
|
|
1607
|
+
)
|
|
1608
|
+
if (!report) return run()
|
|
1609
|
+
try {
|
|
1610
|
+
// Undefined means a user cancellation after `execute` started.
|
|
1611
|
+
return (await run()) ?? (await interrupted())
|
|
1612
|
+
} catch {
|
|
1613
|
+
// A lapsed claim surrenders; the next attempt reports the call.
|
|
1614
|
+
checkAbort(ctx.signal)
|
|
1615
|
+
return interrupted()
|
|
1616
|
+
}
|
|
1463
1617
|
}
|
|
1464
1618
|
|
|
1465
1619
|
const handleToolExecution = async (
|
|
@@ -1632,19 +1786,17 @@ export function createHandlers<
|
|
|
1632
1786
|
} as AppendInput<D>)
|
|
1633
1787
|
return events
|
|
1634
1788
|
}
|
|
1635
|
-
const startedPayload = (
|
|
1636
|
-
model?: LanguageModel,
|
|
1637
|
-
): GenerationStartedPayload => ({
|
|
1789
|
+
const startedPayload = (model?: string): GenerationStartedPayload => ({
|
|
1638
1790
|
requestId,
|
|
1639
1791
|
messageId: request.messageId,
|
|
1640
1792
|
generationId,
|
|
1641
1793
|
responseMessageId,
|
|
1642
1794
|
attempt,
|
|
1643
|
-
...(model === undefined ? {} : { model
|
|
1795
|
+
...(model === undefined ? {} : { model }),
|
|
1644
1796
|
promptThroughIndex: snapshot.index,
|
|
1645
1797
|
})
|
|
1646
1798
|
|
|
1647
|
-
let resolvedModel:
|
|
1799
|
+
let resolvedModel: string | undefined
|
|
1648
1800
|
let resolving = true
|
|
1649
1801
|
let generationStarted = false
|
|
1650
1802
|
try {
|
|
@@ -1653,15 +1805,10 @@ export function createHandlers<
|
|
|
1653
1805
|
throw new TypeError('the model resolver returned undefined')
|
|
1654
1806
|
}
|
|
1655
1807
|
const settings: ModelSettings =
|
|
1656
|
-
typeof choice === 'string'
|
|
1657
|
-
? { model: choice }
|
|
1658
|
-
: choice
|
|
1808
|
+
typeof choice === 'string' ? { model: choice } : choice
|
|
1659
1809
|
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')
|
|
1810
|
+
if (typeof model !== 'string' || model === '')
|
|
1811
|
+
throw new TypeError('the model must be an AI Gateway model ID')
|
|
1665
1812
|
resolvedModel = model
|
|
1666
1813
|
if (checkAbort(ctx.signal)) return
|
|
1667
1814
|
const resolvedInstructions =
|
|
@@ -1670,7 +1817,7 @@ export function createHandlers<
|
|
|
1670
1817
|
: await resolve(options.instructions, resolverContext)
|
|
1671
1818
|
if (checkAbort(ctx.signal)) return
|
|
1672
1819
|
const resolvedGeneration: AgentGenerationSettings<T> = await resolve(
|
|
1673
|
-
|
|
1820
|
+
loop.generation ?? {},
|
|
1674
1821
|
resolverContext,
|
|
1675
1822
|
)
|
|
1676
1823
|
if (checkAbort(ctx.signal)) return
|
|
@@ -1686,13 +1833,13 @@ export function createHandlers<
|
|
|
1686
1833
|
})
|
|
1687
1834
|
const compaction =
|
|
1688
1835
|
typeof configuredCompaction === 'function' ||
|
|
1689
|
-
typeof
|
|
1836
|
+
typeof loop.generation === 'function'
|
|
1690
1837
|
? validateCompaction({
|
|
1691
1838
|
compaction:
|
|
1692
1839
|
typeof configuredCompaction === 'function'
|
|
1693
1840
|
? await resolve(configuredCompaction, resolverContext)
|
|
1694
1841
|
: staticCompaction!,
|
|
1695
|
-
explicit:
|
|
1842
|
+
explicit: loop.compaction !== undefined,
|
|
1696
1843
|
generation,
|
|
1697
1844
|
tools: options.tools,
|
|
1698
1845
|
})
|
|
@@ -1802,7 +1949,7 @@ export function createHandlers<
|
|
|
1802
1949
|
})
|
|
1803
1950
|
const inputTokens = measuredInputTokens({
|
|
1804
1951
|
estimate: inputTokenEstimate,
|
|
1805
|
-
model:
|
|
1952
|
+
model: resolvedModel,
|
|
1806
1953
|
calibration: coordinatorState.calibration,
|
|
1807
1954
|
})
|
|
1808
1955
|
const threshold =
|
|
@@ -1988,15 +2135,40 @@ export function createHandlers<
|
|
|
1988
2135
|
messages: generationMessages,
|
|
1989
2136
|
modelMessages,
|
|
1990
2137
|
}
|
|
1991
|
-
const custom = options.generate !== undefined
|
|
1992
2138
|
const source =
|
|
1993
|
-
|
|
1994
|
-
? await
|
|
2139
|
+
harness !== undefined
|
|
2140
|
+
? await harness.step({
|
|
1995
2141
|
agentName: options.contract.name,
|
|
1996
|
-
|
|
1997
|
-
|
|
2142
|
+
sessionId: ctx.event.sessionId,
|
|
2143
|
+
requestIndex: ctx.event.index,
|
|
2144
|
+
generationId,
|
|
2145
|
+
responseMessageId,
|
|
2146
|
+
throughIndex: snapshot.index,
|
|
2147
|
+
messages: generationMessages,
|
|
2148
|
+
model,
|
|
2149
|
+
...(settings.reasoning === undefined
|
|
2150
|
+
? {}
|
|
2151
|
+
: { reasoning: settings.reasoning }),
|
|
2152
|
+
...(settings.speed === undefined
|
|
2153
|
+
? {}
|
|
2154
|
+
: { speed: settings.speed }),
|
|
2155
|
+
instructions: instructionTexts(resolvedInstructions),
|
|
2156
|
+
tools,
|
|
2157
|
+
log: harnessLog({
|
|
2158
|
+
states,
|
|
2159
|
+
session: ctx.session as Parameters<
|
|
2160
|
+
typeof harnessLog
|
|
2161
|
+
>[0]['session'],
|
|
2162
|
+
}),
|
|
2163
|
+
signal: ctx.signal,
|
|
1998
2164
|
})
|
|
1999
|
-
:
|
|
2165
|
+
: loop.generate === undefined
|
|
2166
|
+
? await generateWithAISDK({
|
|
2167
|
+
agentName: options.contract.name,
|
|
2168
|
+
context: generateContext,
|
|
2169
|
+
messageMetadata: loop.messageMetadata,
|
|
2170
|
+
})
|
|
2171
|
+
: { stream: await loop.generate(generateContext) }
|
|
2000
2172
|
const updates = consumeGeneration({
|
|
2001
2173
|
source,
|
|
2002
2174
|
...(options.progress === undefined
|
|
@@ -2025,7 +2197,7 @@ export function createHandlers<
|
|
|
2025
2197
|
pending: pendingToolCalls,
|
|
2026
2198
|
tools,
|
|
2027
2199
|
generation,
|
|
2028
|
-
|
|
2200
|
+
approvals: harness === undefined,
|
|
2029
2201
|
})
|
|
2030
2202
|
pendingToolCalls = lifecycle.pending
|
|
2031
2203
|
await control.append({
|
|
@@ -2064,7 +2236,7 @@ export function createHandlers<
|
|
|
2064
2236
|
id: await aiEventId('a2.ai.completed', generationId),
|
|
2065
2237
|
payload: completed,
|
|
2066
2238
|
} as AppendInput<D>
|
|
2067
|
-
const unresolved =
|
|
2239
|
+
const unresolved = loop.generate
|
|
2068
2240
|
? pendingToolCalls.filter(
|
|
2069
2241
|
(pending) => pending.classification !== 'automatic',
|
|
2070
2242
|
)
|
|
@@ -2079,7 +2251,7 @@ export function createHandlers<
|
|
|
2079
2251
|
.filter(
|
|
2080
2252
|
(pending) =>
|
|
2081
2253
|
pending.classification === 'automatic' ||
|
|
2082
|
-
(
|
|
2254
|
+
(loop.generate === undefined &&
|
|
2083
2255
|
pending.classification === 'unknown'),
|
|
2084
2256
|
)
|
|
2085
2257
|
.map((pending) => toolCalledEvent<D>(pending.call)),
|
|
@@ -2255,8 +2427,9 @@ export function agent<
|
|
|
2255
2427
|
T extends ToolSet = ToolSet,
|
|
2256
2428
|
M extends UIMessage = UIMessage,
|
|
2257
2429
|
E extends EventDefs = Record<never, never>,
|
|
2430
|
+
H extends string = never,
|
|
2258
2431
|
>(
|
|
2259
|
-
options: AgentOptions<M, E, T>,
|
|
2432
|
+
options: AgentOptions<M, E, T, H>,
|
|
2260
2433
|
): Agent<AIEventDefs<M> & E, AIState<M>, typeof AI_STATE_REDUCER>
|
|
2261
2434
|
export function agent<
|
|
2262
2435
|
D extends AIEventDefs<AIMessageOf<D>> & EventDefs,
|
|
@@ -2264,22 +2437,22 @@ export function agent<
|
|
|
2264
2437
|
T extends ToolSet = ToolSet,
|
|
2265
2438
|
Name extends string = string,
|
|
2266
2439
|
X extends object = Record<never, never>,
|
|
2267
|
-
|
|
2440
|
+
H extends string = never,
|
|
2441
|
+
>(options: AgentFromContractOptions<D, S, T, Name, X, H>): Agent<D, S, Name>
|
|
2268
2442
|
export function agent(
|
|
2269
2443
|
options:
|
|
2270
2444
|
| AgentOptions<UIMessage, EventDefs, ToolSet>
|
|
2271
2445
|
| AgentFromContractOptions<AIEventDefs & EventDefs, AIState, ToolSet>,
|
|
2272
2446
|
): Agent<AIEventDefs & EventDefs, AIState> {
|
|
2273
2447
|
type D = AIEventDefs & EventDefs
|
|
2448
|
+
assertNoLoopOptions(options)
|
|
2274
2449
|
const {
|
|
2275
2450
|
model,
|
|
2276
2451
|
tools,
|
|
2277
2452
|
instructions,
|
|
2278
|
-
generation,
|
|
2279
2453
|
maxSteps,
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
compaction,
|
|
2454
|
+
harness,
|
|
2455
|
+
toolRecovery,
|
|
2283
2456
|
progress,
|
|
2284
2457
|
toolLane,
|
|
2285
2458
|
handlers,
|
|
@@ -2307,22 +2480,22 @@ export function agent(
|
|
|
2307
2480
|
})
|
|
2308
2481
|
serverOptions = remaining
|
|
2309
2482
|
}
|
|
2483
|
+
const states = harnessStates()
|
|
2310
2484
|
const builtIns = createHandlers<UIMessage, D>({
|
|
2311
2485
|
contract,
|
|
2312
2486
|
model,
|
|
2487
|
+
harnessStates: states,
|
|
2313
2488
|
...(serverOptions.telemetry === undefined
|
|
2314
2489
|
? {}
|
|
2315
2490
|
: { telemetry: serverOptions.telemetry }),
|
|
2316
2491
|
...(tools === undefined ? {} : { tools }),
|
|
2317
2492
|
...(instructions === undefined ? {} : { instructions }),
|
|
2318
|
-
...(generation === undefined ? {} : { generation }),
|
|
2319
2493
|
...(maxSteps === undefined ? {} : { maxSteps }),
|
|
2320
|
-
...(
|
|
2321
|
-
...(
|
|
2322
|
-
...(compaction === undefined ? {} : { compaction }),
|
|
2494
|
+
...(harness === undefined ? {} : { harness }),
|
|
2495
|
+
...(toolRecovery === undefined ? {} : { toolRecovery }),
|
|
2323
2496
|
...(progress === undefined ? {} : { progress }),
|
|
2324
2497
|
...(toolLane === undefined ? {} : { toolLane }),
|
|
2325
|
-
})
|
|
2498
|
+
} as HandlersOptions<UIMessage, D>)
|
|
2326
2499
|
for (const type of Object.keys(handlers ?? {})) {
|
|
2327
2500
|
if (Object.hasOwn(builtIns, type))
|
|
2328
2501
|
throw new TypeError(`agent handles '${type}' itself`)
|
|
@@ -2332,6 +2505,7 @@ export function agent(
|
|
|
2332
2505
|
contract,
|
|
2333
2506
|
handlers: { ...builtIns, ...handlers },
|
|
2334
2507
|
})
|
|
2508
|
+
registerHarnessStates(server, states)
|
|
2335
2509
|
const applicationEvents = 'contract' in rest
|
|
2336
2510
|
setServerFetchHooks(server, {
|
|
2337
2511
|
validateIngress: (context) =>
|
|
@@ -2340,4 +2514,4 @@ export function agent(
|
|
|
2340
2514
|
return server
|
|
2341
2515
|
}
|
|
2342
2516
|
|
|
2343
|
-
export type { Instructions,
|
|
2517
|
+
export type { Instructions, ToolSet }
|