veryfront 0.1.219 → 0.1.221

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.
@@ -0,0 +1,182 @@
1
+ import { z } from "zod";
2
+ import { formatAgUiEvent } from "../internal-agents/ag-ui-sse.js";
3
+ const AGENT_ID_PATTERN = /^[a-zA-Z0-9_-]+$/;
4
+ const MAX_TOOL_PARAMETERS_BYTES = 16_384;
5
+ const MAX_CONTEXT_ITEM_BYTES = 16_384;
6
+ const MAX_CONTEXT_TOTAL_BYTES = 65_536;
7
+ const MAX_FORWARDED_PROPS_BYTES = 65_536;
8
+ const MAX_TEXT_PART_LENGTH = 10_000;
9
+ const MAX_MESSAGES_PER_REQUEST = 100;
10
+ const encoder = new TextEncoder();
11
+ const decoder = new TextDecoder();
12
+ function isWithinJsonSizeLimit(value, maxBytes) {
13
+ try {
14
+ return encoder.encode(JSON.stringify(value)).byteLength <= maxBytes;
15
+ }
16
+ catch {
17
+ return false;
18
+ }
19
+ }
20
+ function isRecord(value) {
21
+ return typeof value === "object" && value !== null && !Array.isArray(value);
22
+ }
23
+ const AgUiRunIdSchema = z.string().min(1).max(128).regex(AGENT_ID_PATTERN);
24
+ export const AgUiInjectedToolSchema = z.object({
25
+ name: z.string().min(1).max(128),
26
+ description: z.string().max(1024).optional(),
27
+ parameters: z.record(z.string(), z.unknown()).optional().refine((value) => value === undefined || isWithinJsonSizeLimit(value, MAX_TOOL_PARAMETERS_BYTES), { message: "Tool parameters must be less than 16 KB" }),
28
+ });
29
+ export const AgUiContextItemSchema = z.discriminatedUnion("type", [
30
+ z.object({
31
+ type: z.literal("text"),
32
+ title: z.string().max(256).optional(),
33
+ text: z.string().max(MAX_CONTEXT_ITEM_BYTES),
34
+ }),
35
+ z.object({
36
+ type: z.literal("json"),
37
+ title: z.string().max(256).optional(),
38
+ data: z.record(z.string(), z.unknown()).refine((value) => isWithinJsonSizeLimit(value, MAX_CONTEXT_ITEM_BYTES), { message: "JSON context item must be less than 16 KB" }),
39
+ }),
40
+ z.object({
41
+ type: z.literal("resource"),
42
+ title: z.string().max(256).optional(),
43
+ uri: z.string().max(2048),
44
+ mimeType: z.string().max(256).optional(),
45
+ text: z.string().max(MAX_CONTEXT_ITEM_BYTES).optional(),
46
+ }),
47
+ ]);
48
+ const AgUiMessagePartSchema = z.object({ type: z.string().min(1) }).passthrough();
49
+ const AgUiMessageSchema = z.object({
50
+ id: z.string().min(1),
51
+ role: z.enum(["user", "assistant", "system", "tool"]),
52
+ parts: z.array(AgUiMessagePartSchema).default([]),
53
+ metadata: z.record(z.string(), z.unknown()).optional(),
54
+ createdAt: z.string().optional(),
55
+ });
56
+ export const AgUiRequestSchema = z.object({
57
+ threadId: z.string().uuid().optional(),
58
+ runId: AgUiRunIdSchema.optional(),
59
+ messages: z.array(AgUiMessageSchema).min(1).max(MAX_MESSAGES_PER_REQUEST),
60
+ tools: z.array(AgUiInjectedToolSchema).max(50).default([]),
61
+ context: z.array(AgUiContextItemSchema).max(10).default([]).refine((value) => isWithinJsonSizeLimit(value, MAX_CONTEXT_TOTAL_BYTES), { message: "context must be less than 64 KB total" }),
62
+ forwardedProps: z.record(z.string(), z.unknown()).optional().refine((value) => value === undefined || isWithinJsonSizeLimit(value, MAX_FORWARDED_PROPS_BYTES), { message: "forwardedProps must be less than 64 KB" }),
63
+ model: z.string().optional(),
64
+ maxOutputTokens: z.number().int().positive().optional(),
65
+ });
66
+ function normalizeToolArgs(part) {
67
+ if (isRecord(part.args))
68
+ return part.args;
69
+ if (isRecord(part.input))
70
+ return part.input;
71
+ return {};
72
+ }
73
+ function normalizeMessagePart(part) {
74
+ if (part.type === "text" && typeof part.text === "string" &&
75
+ part.text.length <= MAX_TEXT_PART_LENGTH) {
76
+ return { type: "text", text: part.text };
77
+ }
78
+ if (part.type === "tool_call" && typeof part.id === "string" && typeof part.name === "string") {
79
+ return {
80
+ type: "tool-call",
81
+ toolCallId: part.id,
82
+ toolName: part.name,
83
+ args: normalizeToolArgs(part),
84
+ };
85
+ }
86
+ if (part.type === "tool-call" &&
87
+ typeof part.toolCallId === "string" &&
88
+ typeof part.toolName === "string") {
89
+ return {
90
+ type: "tool-call",
91
+ toolCallId: part.toolCallId,
92
+ toolName: part.toolName,
93
+ args: normalizeToolArgs(part),
94
+ };
95
+ }
96
+ if (typeof part.type === "string" &&
97
+ part.type.startsWith("tool-") &&
98
+ part.type !== "tool-result" &&
99
+ typeof part.toolCallId === "string" &&
100
+ typeof part.toolName === "string") {
101
+ return {
102
+ type: part.type,
103
+ toolCallId: part.toolCallId,
104
+ toolName: part.toolName,
105
+ args: normalizeToolArgs(part),
106
+ };
107
+ }
108
+ if (part.type === "tool_result" && typeof part.tool_call_id === "string") {
109
+ return {
110
+ type: "tool-result",
111
+ toolCallId: part.tool_call_id,
112
+ toolName: typeof part.tool_name === "string" ? part.tool_name : "unknown",
113
+ result: "output" in part ? part.output : undefined,
114
+ };
115
+ }
116
+ if (part.type === "tool-result" && typeof part.toolCallId === "string") {
117
+ return {
118
+ type: "tool-result",
119
+ toolCallId: part.toolCallId,
120
+ toolName: typeof part.toolName === "string" ? part.toolName : "unknown",
121
+ result: "result" in part ? part.result : undefined,
122
+ };
123
+ }
124
+ return null;
125
+ }
126
+ export async function parseAgUiRequest(request) {
127
+ return AgUiRequestSchema.parse(await request.json());
128
+ }
129
+ export async function parseAgUiRequestOrError(request) {
130
+ try {
131
+ return await parseAgUiRequest(request);
132
+ }
133
+ catch (error) {
134
+ if (error instanceof z.ZodError) {
135
+ return Response.json({
136
+ error: "Invalid AG-UI request",
137
+ details: error.issues.map((issue) => ({
138
+ path: issue.path,
139
+ message: issue.message,
140
+ })),
141
+ }, { status: 400 });
142
+ }
143
+ if (error instanceof SyntaxError || error instanceof TypeError) {
144
+ return Response.json({
145
+ error: "Invalid AG-UI request",
146
+ details: [{ path: [], message: "Malformed JSON request body" }],
147
+ }, { status: 400 });
148
+ }
149
+ throw error;
150
+ }
151
+ }
152
+ export function normalizeAgUiMessages(messages) {
153
+ return messages.map((message) => ({
154
+ id: message.id,
155
+ role: message.role,
156
+ parts: message.parts
157
+ .map((part) => normalizeMessagePart(part))
158
+ .filter((part) => part !== null),
159
+ ...(message.createdAt ? { timestamp: Date.parse(message.createdAt) || undefined } : {}),
160
+ ...(message.metadata ? { metadata: message.metadata } : {}),
161
+ }));
162
+ }
163
+ export function createAgUiRunErrorEvent(message, code) {
164
+ return {
165
+ event: "RunError",
166
+ payload: {
167
+ message,
168
+ ...(code ? { code } : {}),
169
+ },
170
+ };
171
+ }
172
+ export function createAgUiSseErrorResponse(event, status) {
173
+ return new Response(decoder.decode(formatAgUiEvent(event.event, event.payload)), {
174
+ status,
175
+ headers: {
176
+ "Content-Type": "text/event-stream; charset=utf-8",
177
+ "Cache-Control": "no-cache, no-transform",
178
+ "Connection": "keep-alive",
179
+ "X-Accel-Buffering": "no",
180
+ },
181
+ });
182
+ }
@@ -90,6 +90,7 @@ export { mergeToolCallInput, mergeToolInputDelta, parseDataStreamSseEvents, pars
90
90
  export { expandAllowedRemoteToolNames, getProviderNativeToolNames, type ProviderNativeToolInventoryOptions, } from "./provider-native-tool-inventory.js";
91
91
  export { type AgUiDetachedStartAccepted, AgUiDetachedStartAcceptedSchema, type AgUiDetachedStartHandlerOptions, type AgUiDetachedStartRequest, AgUiDetachedStartRequestSchema, createAgUiDetachedStartHandler, } from "./ag-ui-detached-start.js";
92
92
  export { type AgUiCancelHandlerOptions, type AgUiResumeHandlerOptions, type AgUiResumeSignal, AgUiResumeSignalSchema, createAgUiCancelHandler, createAgUiResumeHandler, } from "./ag-ui-run-control.js";
93
+ export { type AgUiSseEvent, createAgUiRunErrorEvent, createAgUiSseErrorResponse, normalizeAgUiMessages, parseAgUiRequest, parseAgUiRequestOrError, } from "./ag-ui-host-support.js";
93
94
  export { type AgUiContextItem, type AgUiHandlerConfigWithAgent, type AgUiHandlerOptions, type AgUiInjectedTool, type AgUiRequest, AgUiRequestSchema, createAgUiHandler, } from "./ag-ui-handler.js";
94
95
  export { type HumanInputField, type HumanInputFieldInput, HumanInputFieldSchema, type HumanInputOption, HumanInputOptionSchema, type HumanInputPendingRequest, HumanInputPendingRequestSchema, type HumanInputRequest, type HumanInputRequestInput, HumanInputRequestSchema, type HumanInputResult, HumanInputResultSchema, HumanInputResumeError, InvalidHumanInputResultError, waitForHumanInput, type WaitForHumanInputOptions, } from "./human-input.js";
95
96
  export { type ChatHandlerBeforeStream, type ChatHandlerBeforeStreamContext, type ChatHandlerBeforeStreamResult, type ChatHandlerConfigWithAgent, type ChatHandlerMessageInput, type ChatHandlerOptions, createChatHandler, } from "./chat-handler.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/src/agent/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+EG;AACH,OAAO,yBAAyB,CAAC;AAGjC,YAAY,EACV,KAAK,EACL,WAAW,EACX,YAAY,EACZ,eAAe,EACf,aAAa,EACb,WAAW,EACX,iBAAiB,EACjB,eAAe,EACf,gBAAgB,EAChB,UAAU,EACV,YAAY,EACZ,OAAO,IAAI,YAAY,EACvB,WAAW,EACX,aAAa,EACb,WAAW,EACX,qBAAqB,EACrB,sBAAsB,EACtB,mBAAmB,EACnB,sBAAsB,EACtB,oBAAoB,EACpB,mBAAmB,EACnB,oBAAoB,EACpB,cAAc,EACd,QAAQ,EACR,YAAY,EACZ,oBAAoB,EACpB,qBAAqB,EACrB,cAAc,GACf,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEnF,OAAO,EACL,YAAY,EACZ,kBAAkB,EAClB,YAAY,EACZ,iBAAiB,EACjB,KAAK,MAAM,EACX,KAAK,iBAAiB,EACtB,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,WAAW,EACX,KAAK,iBAAiB,EACtB,aAAa,GACd,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,WAAW,EACX,cAAc,EACd,QAAQ,EACR,gBAAgB,EAChB,cAAc,EACd,aAAa,EACb,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,YAAY,GAClB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AACrC,OAAO,EACL,KAAK,sBAAsB,EAC3B,4BAA4B,EAC5B,KAAK,uBAAuB,EAC5B,6BAA6B,EAC7B,KAAK,kBAAkB,EACvB,wBAAwB,EACxB,KAAK,kBAAkB,EACvB,wBAAwB,GACzB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EACL,KAAK,uBAAuB,EAC5B,KAAK,uBAAuB,EAC5B,KAAK,8BAA8B,EACnC,KAAK,sBAAsB,EAC3B,6BAA6B,EAC7B,yBAAyB,EACzB,wCAAwC,GACzC,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,kBAAkB,EAClB,mBAAmB,EACnB,wBAAwB,EACxB,oBAAoB,EACpB,sBAAsB,EACtB,kCAAkC,GACnC,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,4BAA4B,EAC5B,0BAA0B,EAC1B,KAAK,kCAAkC,GACxC,MAAM,qCAAqC,CAAC;AAC7C,OAAO,EACL,KAAK,yBAAyB,EAC9B,+BAA+B,EAC/B,KAAK,+BAA+B,EACpC,KAAK,wBAAwB,EAC7B,8BAA8B,EAC9B,8BAA8B,GAC/B,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACL,KAAK,wBAAwB,EAC7B,KAAK,wBAAwB,EAC7B,KAAK,gBAAgB,EACrB,sBAAsB,EACtB,uBAAuB,EACvB,uBAAuB,GACxB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,KAAK,eAAe,EACpB,KAAK,0BAA0B,EAC/B,KAAK,kBAAkB,EACvB,KAAK,gBAAgB,EACrB,KAAK,WAAW,EAChB,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,KAAK,eAAe,EACpB,KAAK,oBAAoB,EACzB,qBAAqB,EACrB,KAAK,gBAAgB,EACrB,sBAAsB,EACtB,KAAK,wBAAwB,EAC7B,8BAA8B,EAC9B,KAAK,iBAAiB,EACtB,KAAK,sBAAsB,EAC3B,uBAAuB,EACvB,KAAK,gBAAgB,EACrB,sBAAsB,EACtB,qBAAqB,EACrB,4BAA4B,EAC5B,iBAAiB,EACjB,KAAK,wBAAwB,GAC9B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,KAAK,uBAAuB,EAC5B,KAAK,8BAA8B,EACnC,KAAK,6BAA6B,EAClC,KAAK,0BAA0B,EAC/B,KAAK,uBAAuB,EAC5B,KAAK,kBAAkB,EACvB,iBAAiB,GAClB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,YAAY,EACZ,qBAAqB,EACrB,iBAAiB,EACjB,iBAAiB,EACjB,uBAAuB,EACvB,KAAK,8BAA8B,EACnC,KAAK,gBAAgB,EACrB,KAAK,wBAAwB,EAC7B,iBAAiB,EACjB,mBAAmB,GACpB,MAAM,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/src/agent/index.ts"],"names":[],"mappings":"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"}
@@ -89,6 +89,7 @@ export { mergeToolCallInput, mergeToolInputDelta, parseDataStreamSseEvents, pars
89
89
  export { expandAllowedRemoteToolNames, getProviderNativeToolNames, } from "./provider-native-tool-inventory.js";
90
90
  export { AgUiDetachedStartAcceptedSchema, AgUiDetachedStartRequestSchema, createAgUiDetachedStartHandler, } from "./ag-ui-detached-start.js";
91
91
  export { AgUiResumeSignalSchema, createAgUiCancelHandler, createAgUiResumeHandler, } from "./ag-ui-run-control.js";
92
+ export { createAgUiRunErrorEvent, createAgUiSseErrorResponse, normalizeAgUiMessages, parseAgUiRequest, parseAgUiRequestOrError, } from "./ag-ui-host-support.js";
92
93
  export { AgUiRequestSchema, createAgUiHandler, } from "./ag-ui-handler.js";
93
94
  export { HumanInputFieldSchema, HumanInputOptionSchema, HumanInputPendingRequestSchema, HumanInputRequestSchema, HumanInputResultSchema, HumanInputResumeError, InvalidHumanInputResultError, waitForHumanInput, } from "./human-input.js";
94
95
  export { createChatHandler, } from "./chat-handler.js";
@@ -1,2 +1,2 @@
1
- export declare const VERSION = "0.1.219";
1
+ export declare const VERSION = "0.1.221";
2
2
  //# sourceMappingURL=version-constant.d.ts.map
@@ -1,3 +1,3 @@
1
1
  // Keep in sync with deno.json version.
2
2
  // scripts/release.ts updates this constant during releases.
3
- export const VERSION = "0.1.219";
3
+ export const VERSION = "0.1.221";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "veryfront",
3
- "version": "0.1.219",
3
+ "version": "0.1.221",
4
4
  "description": "The simplest way to build AI-powered apps",
5
5
  "keywords": [
6
6
  "react",
package/src/deno.js CHANGED
@@ -1,6 +1,6 @@
1
1
  export default {
2
2
  "name": "veryfront",
3
- "version": "0.1.219",
3
+ "version": "0.1.221",
4
4
  "license": "Apache-2.0",
5
5
  "nodeModulesDir": "auto",
6
6
  "workspace": [
@@ -3,18 +3,20 @@ import { INVALID_ARGUMENT } from "../errors/index.js";
3
3
  import { SKILL_TOOL_IDS } from "../skill/types.js";
4
4
  import { type Tool, toolRegistry } from "../tool/index.js";
5
5
  import { streamDataStreamEvents } from "./data-stream.js";
6
- import { type AgUiInjectedTool, type AgUiRequest, AgUiRequestSchema } from "./ag-ui-handler.js";
6
+ import {
7
+ type AgUiInjectedTool,
8
+ AgUiRequestSchema,
9
+ normalizeAgUiMessages,
10
+ } from "./ag-ui-host-support.js";
7
11
  import {
8
12
  AgentRuntime,
9
13
  RunAlreadyExistsError,
10
14
  type RunResumeSessionManager,
11
15
  } from "./runtime/index.js";
12
- import type { Agent, Message } from "./types.js";
16
+ import type { Agent } from "./types.js";
13
17
 
14
18
  const AGENT_ID_PATTERN = /^[a-zA-Z0-9_-]+$/;
15
19
  const AG_UI_DETACHED_RUN_ID_SCHEMA = z.string().min(1).max(128).regex(AGENT_ID_PATTERN);
16
- const MAX_TEXT_PART_LENGTH = 10_000;
17
-
18
20
  type AgUiResumeValue = {
19
21
  result: unknown;
20
22
  isError: boolean;
@@ -26,94 +28,6 @@ type AgUiContextValue =
26
28
 
27
29
  type AgUiRuntimePart = Record<string, unknown> & { type: string };
28
30
 
29
- function isRecord(value: unknown): value is Record<string, unknown> {
30
- return typeof value === "object" && value !== null && !Array.isArray(value);
31
- }
32
-
33
- function normalizeToolArgs(part: Record<string, unknown>): Record<string, unknown> {
34
- if (isRecord(part.args)) return part.args;
35
- if (isRecord(part.input)) return part.input;
36
- return {};
37
- }
38
-
39
- function normalizeMessagePart(part: Record<string, unknown>): Message["parts"][number] | null {
40
- if (
41
- part.type === "text" && typeof part.text === "string" &&
42
- part.text.length <= MAX_TEXT_PART_LENGTH
43
- ) {
44
- return { type: "text", text: part.text };
45
- }
46
-
47
- if (part.type === "tool_call" && typeof part.id === "string" && typeof part.name === "string") {
48
- return {
49
- type: "tool-call",
50
- toolCallId: part.id,
51
- toolName: part.name,
52
- args: normalizeToolArgs(part),
53
- };
54
- }
55
-
56
- if (
57
- part.type === "tool-call" &&
58
- typeof part.toolCallId === "string" &&
59
- typeof part.toolName === "string"
60
- ) {
61
- return {
62
- type: "tool-call",
63
- toolCallId: part.toolCallId,
64
- toolName: part.toolName,
65
- args: normalizeToolArgs(part),
66
- };
67
- }
68
-
69
- if (
70
- typeof part.type === "string" &&
71
- part.type.startsWith("tool-") &&
72
- part.type !== "tool-result" &&
73
- typeof part.toolCallId === "string" &&
74
- typeof part.toolName === "string"
75
- ) {
76
- return {
77
- type: part.type,
78
- toolCallId: part.toolCallId,
79
- toolName: part.toolName,
80
- args: normalizeToolArgs(part),
81
- };
82
- }
83
-
84
- if (part.type === "tool_result" && typeof part.tool_call_id === "string") {
85
- return {
86
- type: "tool-result",
87
- toolCallId: part.tool_call_id,
88
- toolName: typeof part.tool_name === "string" ? part.tool_name : "unknown",
89
- result: "output" in part ? part.output : undefined,
90
- };
91
- }
92
-
93
- if (part.type === "tool-result" && typeof part.toolCallId === "string") {
94
- return {
95
- type: "tool-result",
96
- toolCallId: part.toolCallId,
97
- toolName: typeof part.toolName === "string" ? part.toolName : "unknown",
98
- result: "result" in part ? part.result : undefined,
99
- };
100
- }
101
-
102
- return null;
103
- }
104
-
105
- function normalizeMessages(messages: AgUiRequest["messages"]): Message[] {
106
- return messages.map((message) => ({
107
- id: message.id,
108
- role: message.role,
109
- parts: message.parts
110
- .map((part) => normalizeMessagePart(part))
111
- .filter((part): part is Message["parts"][number] => part !== null),
112
- ...(message.createdAt ? { timestamp: Date.parse(message.createdAt) || undefined } : {}),
113
- ...(message.metadata ? { metadata: message.metadata } : {}),
114
- }));
115
- }
116
-
117
31
  function isRequest(obj: unknown): obj is Request {
118
32
  return (
119
33
  typeof obj === "object" &&
@@ -267,10 +181,22 @@ export const AgUiDetachedStartAcceptedSchema = z.object({
267
181
  export type AgUiDetachedStartRequest = z.infer<typeof AgUiDetachedStartRequestSchema>;
268
182
  export type AgUiDetachedStartAccepted = z.infer<typeof AgUiDetachedStartAcceptedSchema>;
269
183
 
270
- export interface AgUiDetachedStartHandlerOptions {
271
- agent: Agent;
184
+ interface AgUiDetachedStartExecutionInput {
185
+ request: AgUiDetachedStartRequest;
186
+ requestOrCtx: unknown;
187
+ rawRequest: Request;
188
+ context: Record<string, unknown>;
189
+ abortSignal: AbortSignal;
190
+ }
191
+
192
+ type AgUiDetachedExecutionStarter = (
193
+ input: AgUiDetachedStartExecutionInput,
194
+ ) => Promise<void> | void;
195
+
196
+ interface AgUiDetachedStartHandlerOptionsBase {
272
197
  sessionManager: RunResumeSessionManager<AgUiResumeValue>;
273
198
  context?: AgUiContextValue;
199
+ startDetachedExecution?: AgUiDetachedExecutionStarter;
274
200
  onAccepted?: (input: {
275
201
  request: AgUiDetachedStartRequest;
276
202
  runId: string;
@@ -285,9 +211,46 @@ export interface AgUiDetachedStartHandlerOptions {
285
211
  onError?: (input: { runId: string; threadId: string; error: unknown }) => Promise<void> | void;
286
212
  }
287
213
 
214
+ export type AgUiDetachedStartHandlerOptions =
215
+ | (AgUiDetachedStartHandlerOptionsBase & { agent: Agent })
216
+ | (AgUiDetachedStartHandlerOptionsBase & {
217
+ agent?: undefined;
218
+ startDetachedExecution: AgUiDetachedExecutionStarter;
219
+ });
220
+
221
+ async function startDefaultDetachedExecution(input: {
222
+ agent: Agent;
223
+ request: AgUiDetachedStartRequest;
224
+ context: Record<string, unknown>;
225
+ abortSignal: AbortSignal;
226
+ sessionManager: RunResumeSessionManager<AgUiResumeValue>;
227
+ }): Promise<void> {
228
+ const runtime = new AgentRuntime(input.agent.id, {
229
+ ...input.agent.config,
230
+ tools: buildMergedTools(input.agent, input.request, input.sessionManager),
231
+ });
232
+
233
+ const runtimeStream = await runtime.stream(
234
+ normalizeAgUiMessages(input.request.messages),
235
+ buildStreamContext(input.request, input.context, input.request.threadId, input.request.runId),
236
+ undefined,
237
+ input.request.model,
238
+ input.request.maxOutputTokens,
239
+ input.abortSignal,
240
+ );
241
+
242
+ await drainRuntimeStream(runtimeStream);
243
+ }
244
+
288
245
  export function createAgUiDetachedStartHandler(
289
246
  options: AgUiDetachedStartHandlerOptions,
290
247
  ): (requestOrCtx: unknown) => Promise<Response> {
248
+ if (!options.agent && !options.startDetachedExecution) {
249
+ throw new Error(
250
+ "Detached AG-UI start requires either an agent or startDetachedExecution handler.",
251
+ );
252
+ }
253
+
291
254
  return async function POST(requestOrCtx: unknown): Promise<Response> {
292
255
  const request = extractRequest(requestOrCtx);
293
256
 
@@ -301,20 +264,6 @@ export function createAgUiDetachedStartHandler(
301
264
  threadId: parsed.threadId,
302
265
  });
303
266
 
304
- const runtime = new AgentRuntime(options.agent.id, {
305
- ...options.agent.config,
306
- tools: buildMergedTools(options.agent, parsed, options.sessionManager),
307
- });
308
-
309
- const runtimeStream = await runtime.stream(
310
- normalizeMessages(parsed.messages),
311
- buildStreamContext(parsed, context, parsed.threadId, parsed.runId),
312
- undefined,
313
- parsed.model,
314
- parsed.maxOutputTokens,
315
- abortSignal,
316
- );
317
-
318
267
  await options.onAccepted?.({
319
268
  request: parsed,
320
269
  runId: parsed.runId,
@@ -323,7 +272,28 @@ export function createAgUiDetachedStartHandler(
323
272
 
324
273
  const detachedTask = (async () => {
325
274
  try {
326
- await drainRuntimeStream(runtimeStream);
275
+ if (options.startDetachedExecution) {
276
+ await options.startDetachedExecution({
277
+ request: parsed,
278
+ requestOrCtx,
279
+ rawRequest: request,
280
+ context,
281
+ abortSignal,
282
+ });
283
+ } else if (options.agent) {
284
+ await startDefaultDetachedExecution({
285
+ agent: options.agent,
286
+ request: parsed,
287
+ context,
288
+ abortSignal,
289
+ sessionManager: options.sessionManager,
290
+ });
291
+ } else {
292
+ throw new Error(
293
+ "Detached AG-UI start configuration became invalid during execution.",
294
+ );
295
+ }
296
+
327
297
  options.sessionManager.completeRun(parsed.runId);
328
298
  await options.onFinish?.({
329
299
  runId: parsed.runId,