veryfront 0.1.144 → 0.1.145
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/esm/deno.js +1 -1
- package/esm/src/agent/ag-ui-handler.d.ts +77 -0
- package/esm/src/agent/ag-ui-handler.d.ts.map +1 -0
- package/esm/src/agent/ag-ui-handler.js +331 -0
- package/esm/src/agent/index.d.ts +2 -1
- package/esm/src/agent/index.d.ts.map +1 -1
- package/esm/src/agent/index.js +2 -1
- package/esm/src/agent/runtime/index.d.ts +2 -0
- package/esm/src/agent/runtime/index.d.ts.map +1 -1
- package/esm/src/agent/runtime/index.js +15 -7
- package/esm/src/agent/runtime/resume-session.d.ts +61 -0
- package/esm/src/agent/runtime/resume-session.d.ts.map +1 -0
- package/esm/src/agent/runtime/resume-session.js +232 -0
- package/esm/src/agent/runtime/tool-helpers.d.ts +4 -2
- package/esm/src/agent/runtime/tool-helpers.d.ts.map +1 -1
- package/esm/src/agent/runtime/tool-helpers.js +57 -4
- package/esm/src/agent/types.d.ts +2 -1
- package/esm/src/agent/types.d.ts.map +1 -1
- package/esm/src/internal-agents/session-manager.d.ts +8 -24
- package/esm/src/internal-agents/session-manager.d.ts.map +1 -1
- package/esm/src/internal-agents/session-manager.js +55 -178
- package/esm/src/mcp/index.d.ts +2 -0
- package/esm/src/mcp/index.d.ts.map +1 -1
- package/esm/src/mcp/index.js +2 -0
- package/esm/src/mcp/server.d.ts +1 -0
- package/esm/src/mcp/server.d.ts.map +1 -1
- package/esm/src/mcp/server.js +47 -8
- package/esm/src/mcp/session.d.ts +9 -0
- package/esm/src/mcp/session.d.ts.map +1 -0
- package/esm/src/mcp/session.js +25 -0
- package/esm/src/mcp/sse.d.ts +8 -0
- package/esm/src/mcp/sse.d.ts.map +1 -0
- package/esm/src/mcp/sse.js +17 -0
- package/esm/src/platform/cloud/resolver.d.ts.map +1 -1
- package/esm/src/platform/cloud/resolver.js +13 -3
- package/esm/src/provider/index.d.ts +2 -0
- package/esm/src/provider/index.d.ts.map +1 -1
- package/esm/src/provider/index.js +1 -0
- package/esm/src/provider/veryfront-cloud/context.d.ts +10 -0
- package/esm/src/provider/veryfront-cloud/context.d.ts.map +1 -0
- package/esm/src/provider/veryfront-cloud/context.js +11 -0
- package/esm/src/tool/index.d.ts +3 -1
- package/esm/src/tool/index.d.ts.map +1 -1
- package/esm/src/tool/index.js +1 -0
- package/esm/src/tool/remote-mcp.d.ts +14 -0
- package/esm/src/tool/remote-mcp.d.ts.map +1 -0
- package/esm/src/tool/remote-mcp.js +176 -0
- package/esm/src/tool/types.d.ts +12 -0
- package/esm/src/tool/types.d.ts.map +1 -1
- package/esm/src/utils/version-constant.d.ts +1 -1
- package/esm/src/utils/version-constant.js +1 -1
- package/package.json +1 -1
- package/src/deno.js +1 -1
- package/src/src/agent/ag-ui-handler.ts +451 -0
- package/src/src/agent/index.ts +21 -1
- package/src/src/agent/runtime/index.ts +28 -3
- package/src/src/agent/runtime/resume-session.ts +319 -0
- package/src/src/agent/runtime/tool-helpers.ts +89 -6
- package/src/src/agent/types.ts +2 -1
- package/src/src/internal-agents/session-manager.ts +69 -243
- package/src/src/mcp/index.ts +3 -0
- package/src/src/mcp/server.ts +54 -9
- package/src/src/mcp/session.ts +31 -0
- package/src/src/mcp/sse.ts +19 -0
- package/src/src/platform/cloud/resolver.ts +15 -3
- package/src/src/provider/index.ts +5 -0
- package/src/src/provider/veryfront-cloud/context.ts +28 -0
- package/src/src/tool/index.ts +9 -1
- package/src/src/tool/remote-mcp.ts +261 -0
- package/src/src/tool/types.ts +17 -0
- package/src/src/utils/version-constant.ts +1 -1
|
@@ -0,0 +1,451 @@
|
|
|
1
|
+
import * as dntShim from "../../_dnt.shims.js";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { getAgent } from "./composition/index.js";
|
|
4
|
+
import type { Agent, Message } from "./types.js";
|
|
5
|
+
import { INVALID_ARGUMENT } from "../errors/index.js";
|
|
6
|
+
import {
|
|
7
|
+
createStreamTransformState,
|
|
8
|
+
finalizeRunEvents,
|
|
9
|
+
formatAgUiEvent,
|
|
10
|
+
mapRuntimeEventToAgUi,
|
|
11
|
+
parseSseJsonEvents,
|
|
12
|
+
} from "../internal-agents/ag-ui-sse.js";
|
|
13
|
+
|
|
14
|
+
const AGENT_ID_PATTERN = /^[a-zA-Z0-9_-]+$/;
|
|
15
|
+
const MAX_TOOL_PARAMETERS_BYTES = 16_384;
|
|
16
|
+
const MAX_CONTEXT_ITEM_BYTES = 16_384;
|
|
17
|
+
const MAX_CONTEXT_TOTAL_BYTES = 65_536;
|
|
18
|
+
const MAX_FORWARDED_PROPS_BYTES = 65_536;
|
|
19
|
+
const MAX_TEXT_PART_LENGTH = 10_000;
|
|
20
|
+
const MAX_MESSAGES_PER_REQUEST = 100;
|
|
21
|
+
|
|
22
|
+
const encoder = new TextEncoder();
|
|
23
|
+
|
|
24
|
+
const AG_UI_HEADERS: Record<string, string> = {
|
|
25
|
+
"Content-Type": "text/event-stream",
|
|
26
|
+
"Cache-Control": "no-cache",
|
|
27
|
+
Connection: "keep-alive",
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
function isWithinJsonSizeLimit(value: unknown, maxBytes: number): boolean {
|
|
31
|
+
try {
|
|
32
|
+
return encoder.encode(JSON.stringify(value)).byteLength <= maxBytes;
|
|
33
|
+
} catch {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const AgUiRunIdSchema = z.string().min(1).max(128).regex(AGENT_ID_PATTERN);
|
|
39
|
+
|
|
40
|
+
const AgUiInjectedToolSchema = z.object({
|
|
41
|
+
name: z.string().min(1).max(128),
|
|
42
|
+
description: z.string().max(1024).optional(),
|
|
43
|
+
parameters: z.record(z.string(), z.unknown()).optional().refine(
|
|
44
|
+
(value) => value === undefined || isWithinJsonSizeLimit(value, MAX_TOOL_PARAMETERS_BYTES),
|
|
45
|
+
{ message: "Tool parameters must be less than 16 KB" },
|
|
46
|
+
),
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
const AgUiContextItemSchema = z.discriminatedUnion("type", [
|
|
50
|
+
z.object({
|
|
51
|
+
type: z.literal("text"),
|
|
52
|
+
title: z.string().max(256).optional(),
|
|
53
|
+
text: z.string().max(MAX_CONTEXT_ITEM_BYTES),
|
|
54
|
+
}),
|
|
55
|
+
z.object({
|
|
56
|
+
type: z.literal("json"),
|
|
57
|
+
title: z.string().max(256).optional(),
|
|
58
|
+
data: z.record(z.string(), z.unknown()).refine(
|
|
59
|
+
(value) => isWithinJsonSizeLimit(value, MAX_CONTEXT_ITEM_BYTES),
|
|
60
|
+
{ message: "JSON context item must be less than 16 KB" },
|
|
61
|
+
),
|
|
62
|
+
}),
|
|
63
|
+
z.object({
|
|
64
|
+
type: z.literal("resource"),
|
|
65
|
+
title: z.string().max(256).optional(),
|
|
66
|
+
uri: z.string().max(2048),
|
|
67
|
+
mimeType: z.string().max(256).optional(),
|
|
68
|
+
text: z.string().max(MAX_CONTEXT_ITEM_BYTES).optional(),
|
|
69
|
+
}),
|
|
70
|
+
]);
|
|
71
|
+
|
|
72
|
+
const AgUiMessagePartSchema = z.object({ type: z.string().min(1) }).passthrough();
|
|
73
|
+
|
|
74
|
+
const AgUiMessageSchema = z.object({
|
|
75
|
+
id: z.string().min(1),
|
|
76
|
+
role: z.enum(["user", "assistant", "system", "tool"]),
|
|
77
|
+
parts: z.array(AgUiMessagePartSchema).default([]),
|
|
78
|
+
metadata: z.record(z.string(), z.unknown()).optional(),
|
|
79
|
+
createdAt: z.string().optional(),
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
export const AgUiRequestSchema = z.object({
|
|
83
|
+
threadId: z.string().uuid().optional(),
|
|
84
|
+
runId: AgUiRunIdSchema.optional(),
|
|
85
|
+
messages: z.array(AgUiMessageSchema).min(1).max(MAX_MESSAGES_PER_REQUEST),
|
|
86
|
+
tools: z.array(AgUiInjectedToolSchema).max(50).default([]),
|
|
87
|
+
context: z.array(AgUiContextItemSchema).max(10).default([]).refine(
|
|
88
|
+
(value) => isWithinJsonSizeLimit(value, MAX_CONTEXT_TOTAL_BYTES),
|
|
89
|
+
{ message: "context must be less than 64 KB total" },
|
|
90
|
+
),
|
|
91
|
+
forwardedProps: z.record(z.string(), z.unknown()).optional().refine(
|
|
92
|
+
(value) => value === undefined || isWithinJsonSizeLimit(value, MAX_FORWARDED_PROPS_BYTES),
|
|
93
|
+
{ message: "forwardedProps must be less than 64 KB" },
|
|
94
|
+
),
|
|
95
|
+
model: z.string().optional(),
|
|
96
|
+
maxOutputTokens: z.number().int().positive().optional(),
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
export type AgUiInjectedTool = z.infer<typeof AgUiInjectedToolSchema>;
|
|
100
|
+
export type AgUiContextItem = z.infer<typeof AgUiContextItemSchema>;
|
|
101
|
+
export type AgUiRequest = z.infer<typeof AgUiRequestSchema>;
|
|
102
|
+
|
|
103
|
+
type AgUiRuntimePart = Record<string, unknown> & { type: string };
|
|
104
|
+
|
|
105
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
106
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function normalizeToolArgs(part: Record<string, unknown>): Record<string, unknown> {
|
|
110
|
+
if (isRecord(part.args)) return part.args;
|
|
111
|
+
if (isRecord(part.input)) return part.input;
|
|
112
|
+
return {};
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function normalizeMessagePart(part: Record<string, unknown>): Message["parts"][number] | null {
|
|
116
|
+
if (
|
|
117
|
+
part.type === "text" && typeof part.text === "string" &&
|
|
118
|
+
part.text.length <= MAX_TEXT_PART_LENGTH
|
|
119
|
+
) {
|
|
120
|
+
return { type: "text", text: part.text };
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (part.type === "tool_call" && typeof part.id === "string" && typeof part.name === "string") {
|
|
124
|
+
return {
|
|
125
|
+
type: "tool-call",
|
|
126
|
+
toolCallId: part.id,
|
|
127
|
+
toolName: part.name,
|
|
128
|
+
args: normalizeToolArgs(part),
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (
|
|
133
|
+
part.type === "tool-call" &&
|
|
134
|
+
typeof part.toolCallId === "string" &&
|
|
135
|
+
typeof part.toolName === "string"
|
|
136
|
+
) {
|
|
137
|
+
return {
|
|
138
|
+
type: "tool-call",
|
|
139
|
+
toolCallId: part.toolCallId,
|
|
140
|
+
toolName: part.toolName,
|
|
141
|
+
args: normalizeToolArgs(part),
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (
|
|
146
|
+
typeof part.type === "string" &&
|
|
147
|
+
part.type.startsWith("tool-") &&
|
|
148
|
+
part.type !== "tool-result" &&
|
|
149
|
+
typeof part.toolCallId === "string" &&
|
|
150
|
+
typeof part.toolName === "string"
|
|
151
|
+
) {
|
|
152
|
+
return {
|
|
153
|
+
type: part.type,
|
|
154
|
+
toolCallId: part.toolCallId,
|
|
155
|
+
toolName: part.toolName,
|
|
156
|
+
args: normalizeToolArgs(part),
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (part.type === "tool_result" && typeof part.tool_call_id === "string") {
|
|
161
|
+
return {
|
|
162
|
+
type: "tool-result",
|
|
163
|
+
toolCallId: part.tool_call_id,
|
|
164
|
+
toolName: typeof part.tool_name === "string" ? part.tool_name : "unknown",
|
|
165
|
+
result: "output" in part ? part.output : undefined,
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (part.type === "tool-result" && typeof part.toolCallId === "string") {
|
|
170
|
+
return {
|
|
171
|
+
type: "tool-result",
|
|
172
|
+
toolCallId: part.toolCallId,
|
|
173
|
+
toolName: typeof part.toolName === "string" ? part.toolName : "unknown",
|
|
174
|
+
result: "result" in part ? part.result : undefined,
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
return null;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function normalizeMessages(messages: AgUiRequest["messages"]): Message[] {
|
|
182
|
+
return messages.map((message) => ({
|
|
183
|
+
id: message.id,
|
|
184
|
+
role: message.role,
|
|
185
|
+
parts: message.parts
|
|
186
|
+
.map((part) => normalizeMessagePart(part))
|
|
187
|
+
.filter((part): part is Message["parts"][number] => part !== null),
|
|
188
|
+
...(message.createdAt ? { timestamp: Date.parse(message.createdAt) || undefined } : {}),
|
|
189
|
+
...(message.metadata ? { metadata: message.metadata } : {}),
|
|
190
|
+
}));
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function isRequest(obj: unknown): obj is dntShim.Request {
|
|
194
|
+
return (
|
|
195
|
+
typeof obj === "object" &&
|
|
196
|
+
obj !== null &&
|
|
197
|
+
"json" in obj &&
|
|
198
|
+
typeof obj.json === "function" &&
|
|
199
|
+
"url" in obj &&
|
|
200
|
+
typeof obj.url === "string" &&
|
|
201
|
+
"method" in obj &&
|
|
202
|
+
typeof obj.method === "string"
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function extractRequest(requestOrCtx: unknown): dntShim.Request {
|
|
207
|
+
if (isRequest(requestOrCtx)) return requestOrCtx;
|
|
208
|
+
|
|
209
|
+
if (typeof requestOrCtx === "object" && requestOrCtx !== null && "request" in requestOrCtx) {
|
|
210
|
+
const candidate = (requestOrCtx as Record<string, unknown>).request;
|
|
211
|
+
if (isRequest(candidate)) return candidate;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
throw INVALID_ARGUMENT.create({
|
|
215
|
+
detail: "Invalid handler argument: expected Request or APIContext",
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function generateRunId(): string {
|
|
220
|
+
return `run_${dntShim.crypto.randomUUID().replaceAll("-", "")}`;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function buildStreamContext(
|
|
224
|
+
request: AgUiRequest,
|
|
225
|
+
baseContext: Record<string, unknown>,
|
|
226
|
+
threadId: string,
|
|
227
|
+
runId: string,
|
|
228
|
+
): Record<string, unknown> {
|
|
229
|
+
return {
|
|
230
|
+
...baseContext,
|
|
231
|
+
threadId,
|
|
232
|
+
runId,
|
|
233
|
+
agUi: {
|
|
234
|
+
context: request.context,
|
|
235
|
+
forwardedProps: request.forwardedProps,
|
|
236
|
+
},
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
function closeController(controller: ReadableStreamDefaultController<Uint8Array>): void {
|
|
241
|
+
try {
|
|
242
|
+
controller.close();
|
|
243
|
+
} catch {
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
function enqueueEvent(
|
|
249
|
+
controller: ReadableStreamDefaultController<Uint8Array>,
|
|
250
|
+
event: string,
|
|
251
|
+
payload: Record<string, unknown>,
|
|
252
|
+
): boolean {
|
|
253
|
+
try {
|
|
254
|
+
controller.enqueue(formatAgUiEvent(event, payload));
|
|
255
|
+
return true;
|
|
256
|
+
} catch {
|
|
257
|
+
return false;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
async function createAgUiStreamResponse(
|
|
262
|
+
agent: Agent,
|
|
263
|
+
request: AgUiRequest,
|
|
264
|
+
baseContext: Record<string, unknown>,
|
|
265
|
+
): Promise<dntShim.Response> {
|
|
266
|
+
const threadId = request.threadId ?? dntShim.crypto.randomUUID();
|
|
267
|
+
const runId = request.runId ?? generateRunId();
|
|
268
|
+
|
|
269
|
+
await agent.clearMemory();
|
|
270
|
+
|
|
271
|
+
const result = await agent.stream({
|
|
272
|
+
messages: normalizeMessages(request.messages),
|
|
273
|
+
context: buildStreamContext(request, baseContext, threadId, runId),
|
|
274
|
+
...(request.model ? { model: request.model } : {}),
|
|
275
|
+
...(request.maxOutputTokens ? { maxOutputTokens: request.maxOutputTokens } : {}),
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
const upstream = result.toDataStreamResponse();
|
|
279
|
+
const upstreamBody = upstream.body;
|
|
280
|
+
|
|
281
|
+
const stream = new ReadableStream<Uint8Array>({
|
|
282
|
+
start: async (controller) => {
|
|
283
|
+
const state = createStreamTransformState();
|
|
284
|
+
let reader: ReadableStreamDefaultReader<Uint8Array> | null = null;
|
|
285
|
+
let remainder = "";
|
|
286
|
+
const decoder = new TextDecoder();
|
|
287
|
+
|
|
288
|
+
if (!enqueueEvent(controller, "RunStarted", { runId, threadId, agentId: agent.id })) {
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
try {
|
|
293
|
+
if (!upstreamBody) {
|
|
294
|
+
for (const event of finalizeRunEvents(state, null)) {
|
|
295
|
+
if (!enqueueEvent(controller, event.event, event.payload)) {
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
closeController(controller);
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
reader = upstreamBody.getReader();
|
|
304
|
+
|
|
305
|
+
while (true) {
|
|
306
|
+
const { done, value } = await reader.read();
|
|
307
|
+
if (done) break;
|
|
308
|
+
|
|
309
|
+
remainder += decoder.decode(value, { stream: true });
|
|
310
|
+
const parsed = parseSseJsonEvents(remainder);
|
|
311
|
+
remainder = parsed.remainder;
|
|
312
|
+
|
|
313
|
+
for (const event of parsed.events as AgUiRuntimePart[]) {
|
|
314
|
+
for (const mapped of mapRuntimeEventToAgUi(state, event)) {
|
|
315
|
+
if (!enqueueEvent(controller, mapped.event, mapped.payload)) {
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
remainder += decoder.decode();
|
|
323
|
+
const parsed = parseSseJsonEvents(remainder);
|
|
324
|
+
for (const event of parsed.events as AgUiRuntimePart[]) {
|
|
325
|
+
for (const mapped of mapRuntimeEventToAgUi(state, event)) {
|
|
326
|
+
if (!enqueueEvent(controller, mapped.event, mapped.payload)) {
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
for (const event of finalizeRunEvents(state, null)) {
|
|
333
|
+
if (!enqueueEvent(controller, event.event, event.payload)) {
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
} catch (error) {
|
|
338
|
+
enqueueEvent(controller, "RunError", {
|
|
339
|
+
message: error instanceof Error ? error.message : "Agent run failed",
|
|
340
|
+
});
|
|
341
|
+
} finally {
|
|
342
|
+
await reader?.cancel().catch(() => undefined);
|
|
343
|
+
closeController(controller);
|
|
344
|
+
}
|
|
345
|
+
},
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
return new dntShim.Response(stream, {
|
|
349
|
+
status: upstream.status,
|
|
350
|
+
statusText: upstream.statusText,
|
|
351
|
+
headers: { ...AG_UI_HEADERS },
|
|
352
|
+
});
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
export interface AgUiHandlerOptions {
|
|
356
|
+
context?:
|
|
357
|
+
| Record<string, unknown>
|
|
358
|
+
| ((request: dntShim.Request) => Record<string, unknown> | Promise<Record<string, unknown>>);
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
export interface AgUiHandlerConfigWithAgent extends AgUiHandlerOptions {
|
|
362
|
+
agent: Agent;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
function mergeConfig(
|
|
366
|
+
config: AgUiHandlerConfigWithAgent,
|
|
367
|
+
options?: AgUiHandlerOptions,
|
|
368
|
+
): AgUiHandlerConfigWithAgent {
|
|
369
|
+
if (!options) return config;
|
|
370
|
+
return { ...options, ...config };
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
export function createAgUiHandler(
|
|
374
|
+
agentId: string,
|
|
375
|
+
options?: AgUiHandlerOptions,
|
|
376
|
+
): (requestOrCtx: unknown) => Promise<dntShim.Response>;
|
|
377
|
+
export function createAgUiHandler(
|
|
378
|
+
config: AgUiHandlerConfigWithAgent,
|
|
379
|
+
options?: AgUiHandlerOptions,
|
|
380
|
+
): (requestOrCtx: unknown) => Promise<dntShim.Response>;
|
|
381
|
+
export function createAgUiHandler(
|
|
382
|
+
agentIdOrConfig: string | AgUiHandlerConfigWithAgent,
|
|
383
|
+
options?: AgUiHandlerOptions,
|
|
384
|
+
) {
|
|
385
|
+
return async function POST(requestOrCtx: unknown): Promise<dntShim.Response> {
|
|
386
|
+
const request = extractRequest(requestOrCtx);
|
|
387
|
+
|
|
388
|
+
let agent: Agent | undefined;
|
|
389
|
+
|
|
390
|
+
if (
|
|
391
|
+
typeof agentIdOrConfig === "object" &&
|
|
392
|
+
agentIdOrConfig !== null &&
|
|
393
|
+
"agent" in agentIdOrConfig
|
|
394
|
+
) {
|
|
395
|
+
const config = mergeConfig(agentIdOrConfig, options);
|
|
396
|
+
agent = config.agent;
|
|
397
|
+
options = config;
|
|
398
|
+
} else {
|
|
399
|
+
const agentId = agentIdOrConfig as string;
|
|
400
|
+
try {
|
|
401
|
+
agent = getAgent(agentId);
|
|
402
|
+
} catch {
|
|
403
|
+
return dntShim.Response.json({ error: "Agent not found" }, { status: 404 });
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
if (!agent) {
|
|
408
|
+
return dntShim.Response.json({ error: "Agent not found" }, { status: 404 });
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
try {
|
|
412
|
+
const parsed = AgUiRequestSchema.parse(await request.json());
|
|
413
|
+
|
|
414
|
+
if (parsed.tools.length > 0) {
|
|
415
|
+
return dntShim.Response.json(
|
|
416
|
+
{
|
|
417
|
+
error:
|
|
418
|
+
"Injected AG-UI tools are not supported by createAgUiHandler yet. Use package-level wait/resume runtime primitives instead.",
|
|
419
|
+
},
|
|
420
|
+
{ status: 501 },
|
|
421
|
+
);
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
const context = typeof options?.context === "function"
|
|
425
|
+
? await options.context(request)
|
|
426
|
+
: options?.context ?? {};
|
|
427
|
+
|
|
428
|
+
return await createAgUiStreamResponse(agent, parsed, context);
|
|
429
|
+
} catch (error) {
|
|
430
|
+
if (error instanceof z.ZodError) {
|
|
431
|
+
return dntShim.Response.json(
|
|
432
|
+
{
|
|
433
|
+
error: "Invalid AG-UI request",
|
|
434
|
+
details: error.issues.map((issue) => ({
|
|
435
|
+
path: issue.path,
|
|
436
|
+
message: issue.message,
|
|
437
|
+
})),
|
|
438
|
+
},
|
|
439
|
+
{ status: 400 },
|
|
440
|
+
);
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
return dntShim.Response.json(
|
|
444
|
+
{
|
|
445
|
+
error: error instanceof Error ? error.message : "Internal server error",
|
|
446
|
+
},
|
|
447
|
+
{ status: 500 },
|
|
448
|
+
);
|
|
449
|
+
}
|
|
450
|
+
};
|
|
451
|
+
}
|
package/src/src/agent/index.ts
CHANGED
|
@@ -135,6 +135,15 @@ export {
|
|
|
135
135
|
} from "./composition/index.js";
|
|
136
136
|
|
|
137
137
|
export { agent } from "./factory.js";
|
|
138
|
+
export {
|
|
139
|
+
type AgUiContextItem,
|
|
140
|
+
type AgUiHandlerConfigWithAgent,
|
|
141
|
+
type AgUiHandlerOptions,
|
|
142
|
+
type AgUiInjectedTool,
|
|
143
|
+
type AgUiRequest,
|
|
144
|
+
AgUiRequestSchema,
|
|
145
|
+
createAgUiHandler,
|
|
146
|
+
} from "./ag-ui-handler.js";
|
|
138
147
|
export {
|
|
139
148
|
type ChatHandlerBeforeStream,
|
|
140
149
|
type ChatHandlerBeforeStreamContext,
|
|
@@ -144,4 +153,15 @@ export {
|
|
|
144
153
|
type ChatHandlerOptions,
|
|
145
154
|
createChatHandler,
|
|
146
155
|
} from "./chat-handler.js";
|
|
147
|
-
export {
|
|
156
|
+
export {
|
|
157
|
+
AgentRuntime,
|
|
158
|
+
RunAlreadyExistsError,
|
|
159
|
+
RunCancelledError,
|
|
160
|
+
RunNotActiveError,
|
|
161
|
+
RunResumeSessionManager,
|
|
162
|
+
type RunResumeSessionManagerOptions,
|
|
163
|
+
type RunSessionStatus,
|
|
164
|
+
type SubmitResumeValueOutcome,
|
|
165
|
+
WaitConflictError,
|
|
166
|
+
WaitNotPendingError,
|
|
167
|
+
} from "./runtime/index.js";
|
|
@@ -39,9 +39,23 @@ import { MiddlewareChain } from "../middleware/chain.js";
|
|
|
39
39
|
import { generateText, type LanguageModel, streamText } from "ai";
|
|
40
40
|
import { AGENT_DEFAULTS } from "../ai-defaults.js";
|
|
41
41
|
import { tryGetCacheKeyContext } from "../../cache/cache-key-builder.js";
|
|
42
|
+
import type { ToolExecutionContext } from "../../tool/index.js";
|
|
42
43
|
|
|
43
44
|
// Re-export from submodules
|
|
44
45
|
export { closeSSEStream, generateMessageId, sendSSE } from "./sse-utils.js";
|
|
46
|
+
export {
|
|
47
|
+
RunAlreadyExistsError,
|
|
48
|
+
RunCancelledError,
|
|
49
|
+
RunNotActiveError,
|
|
50
|
+
RunResumeSessionManager,
|
|
51
|
+
WaitConflictError,
|
|
52
|
+
WaitNotPendingError,
|
|
53
|
+
} from "./resume-session.js";
|
|
54
|
+
export type {
|
|
55
|
+
RunResumeSessionManagerOptions,
|
|
56
|
+
RunSessionStatus,
|
|
57
|
+
SubmitResumeValueOutcome,
|
|
58
|
+
} from "./resume-session.js";
|
|
45
59
|
export {
|
|
46
60
|
executeConfiguredTool,
|
|
47
61
|
getAvailableTools,
|
|
@@ -279,6 +293,11 @@ export class AgentRuntime {
|
|
|
279
293
|
this.executeAgentLoop(
|
|
280
294
|
systemPrompt,
|
|
281
295
|
messages,
|
|
296
|
+
{
|
|
297
|
+
agentId: this.id,
|
|
298
|
+
projectId: tryGetCacheKeyContext()?.projectId,
|
|
299
|
+
...context,
|
|
300
|
+
},
|
|
282
301
|
resolvedModelString,
|
|
283
302
|
maxOutputTokensOverride,
|
|
284
303
|
),
|
|
@@ -425,6 +444,7 @@ export class AgentRuntime {
|
|
|
425
444
|
private async executeAgentLoop(
|
|
426
445
|
systemPrompt: string,
|
|
427
446
|
messages: Message[],
|
|
447
|
+
toolContext?: ToolExecutionContext,
|
|
428
448
|
modelString?: string,
|
|
429
449
|
maxOutputTokensOverride?: number,
|
|
430
450
|
): Promise<AgentResponse> {
|
|
@@ -460,6 +480,8 @@ export class AgentRuntime {
|
|
|
460
480
|
let tools = isLocal ? [] : await getAvailableTools(this.config.tools, {
|
|
461
481
|
includeSkillTools: Boolean(this.config.skills),
|
|
462
482
|
allowedRemoteToolNames,
|
|
483
|
+
remoteToolSources: this.config.remoteTools,
|
|
484
|
+
remoteToolContext: toolContext,
|
|
463
485
|
});
|
|
464
486
|
|
|
465
487
|
// Layer 1: Filter tools based on active skill policy (planning-time)
|
|
@@ -583,11 +605,12 @@ export class AgentRuntime {
|
|
|
583
605
|
toolCall.args,
|
|
584
606
|
this.config.tools,
|
|
585
607
|
{
|
|
586
|
-
agentId: this.id,
|
|
587
608
|
toolCallId: tc.toolCallId,
|
|
588
|
-
|
|
609
|
+
...toolContext,
|
|
610
|
+
projectId: cacheCtx?.projectId ?? toolContext?.projectId,
|
|
589
611
|
},
|
|
590
612
|
allowedRemoteToolNames,
|
|
613
|
+
this.config.remoteTools,
|
|
591
614
|
);
|
|
592
615
|
|
|
593
616
|
toolCall.status = "completed";
|
|
@@ -712,6 +735,8 @@ export class AgentRuntime {
|
|
|
712
735
|
let tools = isLocalStreaming ? [] : await getAvailableTools(this.config.tools, {
|
|
713
736
|
includeSkillTools: Boolean(this.config.skills),
|
|
714
737
|
allowedRemoteToolNames,
|
|
738
|
+
remoteToolSources: this.config.remoteTools,
|
|
739
|
+
remoteToolContext: toolContext,
|
|
715
740
|
});
|
|
716
741
|
|
|
717
742
|
// Layer 1: Filter tools based on active skill policy (planning-time)
|
|
@@ -873,11 +898,11 @@ export class AgentRuntime {
|
|
|
873
898
|
toolCall.args,
|
|
874
899
|
this.config.tools,
|
|
875
900
|
{
|
|
876
|
-
agentId: this.id,
|
|
877
901
|
toolCallId: tc.id,
|
|
878
902
|
...toolContext,
|
|
879
903
|
},
|
|
880
904
|
allowedRemoteToolNames,
|
|
905
|
+
this.config.remoteTools,
|
|
881
906
|
);
|
|
882
907
|
throwIfAborted(abortSignal);
|
|
883
908
|
|