veryfront 0.1.63 → 0.1.65
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/runtime/index.d.ts +1 -0
- package/esm/src/agent/runtime/index.d.ts.map +1 -1
- package/esm/src/agent/runtime/index.js +10 -2
- package/esm/src/channels/control-plane.d.ts +259 -0
- package/esm/src/channels/control-plane.d.ts.map +1 -0
- package/esm/src/channels/control-plane.js +212 -0
- package/esm/src/channels/invoke.d.ts +71 -44
- package/esm/src/channels/invoke.d.ts.map +1 -1
- package/esm/src/channels/invoke.js +33 -114
- package/esm/src/integrations/endpoint-executor.d.ts +1 -0
- package/esm/src/integrations/endpoint-executor.d.ts.map +1 -1
- package/esm/src/integrations/endpoint-executor.js +44 -0
- package/esm/src/internal-agents/ag-ui-sse.d.ts +35 -0
- package/esm/src/internal-agents/ag-ui-sse.d.ts.map +1 -0
- package/esm/src/internal-agents/ag-ui-sse.js +263 -0
- package/esm/src/internal-agents/control-plane-auth.d.ts +20 -0
- package/esm/src/internal-agents/control-plane-auth.d.ts.map +1 -0
- package/esm/src/internal-agents/control-plane-auth.js +56 -0
- package/esm/src/internal-agents/request-body.d.ts +9 -0
- package/esm/src/internal-agents/request-body.d.ts.map +1 -0
- package/esm/src/internal-agents/request-body.js +28 -0
- package/esm/src/internal-agents/run-stream.d.ts +14 -0
- package/esm/src/internal-agents/run-stream.d.ts.map +1 -0
- package/esm/src/internal-agents/run-stream.js +259 -0
- package/esm/src/internal-agents/schema.d.ts +268 -0
- package/esm/src/internal-agents/schema.d.ts.map +1 -0
- package/esm/src/internal-agents/schema.js +71 -0
- package/esm/src/internal-agents/session-manager.d.ts +63 -0
- package/esm/src/internal-agents/session-manager.d.ts.map +1 -0
- package/esm/src/internal-agents/session-manager.js +258 -0
- package/esm/src/platform/adapters/runtime/deno/adapter.d.ts.map +1 -1
- package/esm/src/platform/adapters/runtime/deno/adapter.js +4 -13
- package/esm/src/platform/compat/process.d.ts.map +1 -1
- package/esm/src/platform/compat/process.js +42 -5
- package/esm/src/server/handlers/request/agent-run-cancel.handler.d.ts +11 -0
- package/esm/src/server/handlers/request/agent-run-cancel.handler.d.ts.map +1 -0
- package/esm/src/server/handlers/request/agent-run-cancel.handler.js +62 -0
- package/esm/src/server/handlers/request/agent-run-resume.handler.d.ts +11 -0
- package/esm/src/server/handlers/request/agent-run-resume.handler.d.ts.map +1 -0
- package/esm/src/server/handlers/request/agent-run-resume.handler.js +77 -0
- package/esm/src/server/handlers/request/agent-stream.handler.d.ts +14 -0
- package/esm/src/server/handlers/request/agent-stream.handler.d.ts.map +1 -0
- package/esm/src/server/handlers/request/agent-stream.handler.js +86 -0
- package/esm/src/server/handlers/request/internal-agents-list.handler.d.ts +11 -0
- package/esm/src/server/handlers/request/internal-agents-list.handler.d.ts.map +1 -0
- package/esm/src/server/handlers/request/internal-agents-list.handler.js +73 -0
- package/esm/src/server/runtime-handler/index.d.ts.map +1 -1
- package/esm/src/server/runtime-handler/index.js +8 -0
- package/package.json +1 -1
- package/src/deno.js +1 -1
- package/src/src/agent/runtime/index.ts +12 -2
- package/src/src/channels/control-plane.ts +332 -0
- package/src/src/channels/invoke.ts +44 -164
- package/src/src/integrations/endpoint-executor.ts +51 -0
- package/src/src/internal-agents/ag-ui-sse.ts +327 -0
- package/src/src/internal-agents/control-plane-auth.ts +82 -0
- package/src/src/internal-agents/request-body.ts +42 -0
- package/src/src/internal-agents/run-stream.ts +354 -0
- package/src/src/internal-agents/schema.ts +102 -0
- package/src/src/internal-agents/session-manager.ts +358 -0
- package/src/src/platform/adapters/runtime/deno/adapter.ts +9 -11
- package/src/src/platform/compat/process.ts +56 -3
- package/src/src/server/handlers/request/agent-run-cancel.handler.ts +86 -0
- package/src/src/server/handlers/request/agent-run-resume.handler.ts +108 -0
- package/src/src/server/handlers/request/agent-stream.handler.ts +125 -0
- package/src/src/server/handlers/request/internal-agents-list.handler.ts +100 -0
- package/src/src/server/runtime-handler/index.ts +8 -0
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
import * as dntShim from "../../_dnt.shims.js";
|
|
2
|
+
import { serverLogger } from "../utils/index.js";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
const encoder = new TextEncoder();
|
|
5
|
+
const logger = serverLogger.component("internal-agents-ag-ui-sse");
|
|
6
|
+
export function createStreamTransformState() {
|
|
7
|
+
return {
|
|
8
|
+
messageId: null,
|
|
9
|
+
textOpen: false,
|
|
10
|
+
stepIndex: 0,
|
|
11
|
+
sawTerminalError: false,
|
|
12
|
+
metadata: {},
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
const agUiEventPayloadSchemas = {
|
|
16
|
+
RunStarted: z.object({
|
|
17
|
+
runId: z.string().min(1),
|
|
18
|
+
threadId: z.string().min(1),
|
|
19
|
+
agentId: z.string().min(1),
|
|
20
|
+
}),
|
|
21
|
+
TextMessageStart: z.object({
|
|
22
|
+
messageId: z.string().min(1),
|
|
23
|
+
role: z.literal("assistant"),
|
|
24
|
+
}),
|
|
25
|
+
TextMessageContent: z.object({
|
|
26
|
+
messageId: z.string().min(1),
|
|
27
|
+
delta: z.string(),
|
|
28
|
+
}),
|
|
29
|
+
TextMessageEnd: z.object({
|
|
30
|
+
messageId: z.string().min(1),
|
|
31
|
+
}),
|
|
32
|
+
ToolCallStart: z.object({
|
|
33
|
+
toolCallId: z.string().min(1),
|
|
34
|
+
toolCallName: z.string().min(1),
|
|
35
|
+
}),
|
|
36
|
+
ToolCallArgs: z.object({
|
|
37
|
+
toolCallId: z.string().min(1),
|
|
38
|
+
delta: z.string(),
|
|
39
|
+
}),
|
|
40
|
+
ToolCallEnd: z.object({
|
|
41
|
+
toolCallId: z.string().min(1),
|
|
42
|
+
}),
|
|
43
|
+
ToolCallResult: z.object({
|
|
44
|
+
toolCallId: z.string().min(1),
|
|
45
|
+
result: z.unknown(),
|
|
46
|
+
isError: z.boolean().optional(),
|
|
47
|
+
}),
|
|
48
|
+
StepStarted: z.object({
|
|
49
|
+
stepIndex: z.number().int().positive(),
|
|
50
|
+
}),
|
|
51
|
+
StepFinished: z.object({
|
|
52
|
+
stepIndex: z.number().int().positive(),
|
|
53
|
+
}),
|
|
54
|
+
RunError: z.object({
|
|
55
|
+
code: z.string().min(1).optional(),
|
|
56
|
+
message: z.string().min(1),
|
|
57
|
+
}),
|
|
58
|
+
RunFinished: z.object({
|
|
59
|
+
metadata: z.object({
|
|
60
|
+
provider: z.string().optional(),
|
|
61
|
+
model: z.string().optional(),
|
|
62
|
+
inputTokens: z.number().int().nonnegative().optional(),
|
|
63
|
+
outputTokens: z.number().int().nonnegative().optional(),
|
|
64
|
+
totalTokens: z.number().int().nonnegative().optional(),
|
|
65
|
+
finishReason: z.string().optional(),
|
|
66
|
+
}),
|
|
67
|
+
}),
|
|
68
|
+
};
|
|
69
|
+
export function formatAgUiEvent(event, payload) {
|
|
70
|
+
const schema = agUiEventPayloadSchemas[event];
|
|
71
|
+
const validatedPayload = schema ? schema.parse(payload) : payload;
|
|
72
|
+
return encoder.encode(`event: ${event}\ndata: ${JSON.stringify(validatedPayload)}\n\n`);
|
|
73
|
+
}
|
|
74
|
+
export function parseSseJsonEvents(chunk) {
|
|
75
|
+
const blocks = chunk.split("\n\n");
|
|
76
|
+
const remainder = blocks.pop() ?? "";
|
|
77
|
+
const events = blocks.flatMap((block) => {
|
|
78
|
+
const dataLines = block.split("\n")
|
|
79
|
+
.filter((line) => line.startsWith("data:"))
|
|
80
|
+
.map((line) => line.slice(5).trimStart());
|
|
81
|
+
if (!dataLines.length) {
|
|
82
|
+
return [];
|
|
83
|
+
}
|
|
84
|
+
try {
|
|
85
|
+
const payload = JSON.parse(dataLines.join("\n"));
|
|
86
|
+
return [payload];
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
logger.warn("Skipping malformed runtime SSE event payload", {
|
|
90
|
+
error,
|
|
91
|
+
dataLength: dataLines.join("\n").length,
|
|
92
|
+
});
|
|
93
|
+
return [];
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
return { events, remainder };
|
|
97
|
+
}
|
|
98
|
+
function getMessageId(state, event) {
|
|
99
|
+
if (typeof event.messageId === "string") {
|
|
100
|
+
state.messageId = event.messageId;
|
|
101
|
+
return event.messageId;
|
|
102
|
+
}
|
|
103
|
+
if (!state.messageId && typeof event.id === "string") {
|
|
104
|
+
state.messageId = event.id;
|
|
105
|
+
}
|
|
106
|
+
if (!state.messageId) {
|
|
107
|
+
state.messageId = dntShim.crypto.randomUUID();
|
|
108
|
+
}
|
|
109
|
+
return state.messageId;
|
|
110
|
+
}
|
|
111
|
+
function applyDataMetadata(state, event) {
|
|
112
|
+
const data = event.data && typeof event.data === "object" && !Array.isArray(event.data)
|
|
113
|
+
? event.data
|
|
114
|
+
: event;
|
|
115
|
+
if (typeof data.model === "string") {
|
|
116
|
+
state.metadata.model = data.model;
|
|
117
|
+
const provider = data.model.split("/")[0];
|
|
118
|
+
if (provider) {
|
|
119
|
+
state.metadata.provider = provider;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
function applyResponseMetadata(state, response) {
|
|
124
|
+
if (!response)
|
|
125
|
+
return;
|
|
126
|
+
if (response.usage) {
|
|
127
|
+
state.metadata.inputTokens = response.usage.promptTokens;
|
|
128
|
+
state.metadata.outputTokens = response.usage.completionTokens;
|
|
129
|
+
state.metadata.totalTokens = response.usage.totalTokens;
|
|
130
|
+
}
|
|
131
|
+
const finishReason = response.metadata && typeof response.metadata === "object"
|
|
132
|
+
? response.metadata.finishReason
|
|
133
|
+
: undefined;
|
|
134
|
+
if (typeof finishReason === "string") {
|
|
135
|
+
state.metadata.finishReason = finishReason;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
export function mapRuntimeEventToAgUi(state, event) {
|
|
139
|
+
switch (event.type) {
|
|
140
|
+
case "message-start":
|
|
141
|
+
getMessageId(state, event);
|
|
142
|
+
return [];
|
|
143
|
+
case "text-start": {
|
|
144
|
+
if (state.textOpen)
|
|
145
|
+
return [];
|
|
146
|
+
const messageId = getMessageId(state, event);
|
|
147
|
+
state.textOpen = true;
|
|
148
|
+
return [{
|
|
149
|
+
event: "TextMessageStart",
|
|
150
|
+
payload: { messageId, role: "assistant" },
|
|
151
|
+
}];
|
|
152
|
+
}
|
|
153
|
+
case "text-delta": {
|
|
154
|
+
const messageId = getMessageId(state, event);
|
|
155
|
+
if (!state.textOpen) {
|
|
156
|
+
state.textOpen = true;
|
|
157
|
+
return [
|
|
158
|
+
{ event: "TextMessageStart", payload: { messageId, role: "assistant" } },
|
|
159
|
+
{
|
|
160
|
+
event: "TextMessageContent",
|
|
161
|
+
payload: { messageId, delta: typeof event.delta === "string" ? event.delta : "" },
|
|
162
|
+
},
|
|
163
|
+
];
|
|
164
|
+
}
|
|
165
|
+
return [{
|
|
166
|
+
event: "TextMessageContent",
|
|
167
|
+
payload: { messageId, delta: typeof event.delta === "string" ? event.delta : "" },
|
|
168
|
+
}];
|
|
169
|
+
}
|
|
170
|
+
case "text-end": {
|
|
171
|
+
if (!state.textOpen)
|
|
172
|
+
return [];
|
|
173
|
+
state.textOpen = false;
|
|
174
|
+
return [{
|
|
175
|
+
event: "TextMessageEnd",
|
|
176
|
+
payload: { messageId: getMessageId(state, event) },
|
|
177
|
+
}];
|
|
178
|
+
}
|
|
179
|
+
case "tool-input-start":
|
|
180
|
+
return [{
|
|
181
|
+
event: "ToolCallStart",
|
|
182
|
+
payload: {
|
|
183
|
+
toolCallId: event.toolCallId,
|
|
184
|
+
toolCallName: event.toolName,
|
|
185
|
+
},
|
|
186
|
+
}];
|
|
187
|
+
case "tool-input-delta":
|
|
188
|
+
return [{
|
|
189
|
+
event: "ToolCallArgs",
|
|
190
|
+
payload: {
|
|
191
|
+
toolCallId: event.toolCallId,
|
|
192
|
+
delta: typeof event.inputTextDelta === "string" ? event.inputTextDelta : "",
|
|
193
|
+
},
|
|
194
|
+
}];
|
|
195
|
+
case "tool-input-available":
|
|
196
|
+
return [{
|
|
197
|
+
event: "ToolCallEnd",
|
|
198
|
+
payload: { toolCallId: event.toolCallId },
|
|
199
|
+
}];
|
|
200
|
+
case "tool-output-available":
|
|
201
|
+
return [{
|
|
202
|
+
event: "ToolCallResult",
|
|
203
|
+
payload: {
|
|
204
|
+
toolCallId: event.toolCallId,
|
|
205
|
+
result: event.output,
|
|
206
|
+
},
|
|
207
|
+
}];
|
|
208
|
+
case "tool-output-error":
|
|
209
|
+
return [{
|
|
210
|
+
event: "ToolCallResult",
|
|
211
|
+
payload: {
|
|
212
|
+
toolCallId: event.toolCallId,
|
|
213
|
+
result: { error: event.errorText },
|
|
214
|
+
isError: true,
|
|
215
|
+
},
|
|
216
|
+
}];
|
|
217
|
+
case "step-start":
|
|
218
|
+
state.stepIndex += 1;
|
|
219
|
+
return [{
|
|
220
|
+
event: "StepStarted",
|
|
221
|
+
payload: { stepIndex: state.stepIndex },
|
|
222
|
+
}];
|
|
223
|
+
case "step-end":
|
|
224
|
+
return [{
|
|
225
|
+
event: "StepFinished",
|
|
226
|
+
payload: { stepIndex: state.stepIndex },
|
|
227
|
+
}];
|
|
228
|
+
case "data":
|
|
229
|
+
applyDataMetadata(state, event);
|
|
230
|
+
return [];
|
|
231
|
+
case "error":
|
|
232
|
+
state.sawTerminalError = true;
|
|
233
|
+
return [{
|
|
234
|
+
event: "RunError",
|
|
235
|
+
payload: {
|
|
236
|
+
message: typeof event.error === "string" ? event.error : "Agent run failed",
|
|
237
|
+
},
|
|
238
|
+
}];
|
|
239
|
+
default:
|
|
240
|
+
return [];
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
export function finalizeRunEvents(state, response) {
|
|
244
|
+
applyResponseMetadata(state, response);
|
|
245
|
+
if (state.sawTerminalError) {
|
|
246
|
+
return [];
|
|
247
|
+
}
|
|
248
|
+
const events = [];
|
|
249
|
+
if (state.textOpen) {
|
|
250
|
+
state.textOpen = false;
|
|
251
|
+
events.push({
|
|
252
|
+
event: "TextMessageEnd",
|
|
253
|
+
payload: { messageId: getMessageId(state, { type: "text-end" }) },
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
events.push({
|
|
257
|
+
event: "RunFinished",
|
|
258
|
+
payload: {
|
|
259
|
+
metadata: state.metadata,
|
|
260
|
+
},
|
|
261
|
+
});
|
|
262
|
+
return events;
|
|
263
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import * as dntShim from "../../_dnt.shims.js";
|
|
2
|
+
import type { HandlerContext } from "../types/index.js";
|
|
3
|
+
export declare class ControlPlaneRequestError extends Error {
|
|
4
|
+
readonly status: number;
|
|
5
|
+
constructor(status: number, message: string);
|
|
6
|
+
}
|
|
7
|
+
export declare function verifyControlPlaneRequest(req: dntShim.Request, ctx: HandlerContext, rawBody: string, options?: {
|
|
8
|
+
expectedSubject?: string;
|
|
9
|
+
expectedSurface?: "studio" | "channels" | "a2a" | "mcp";
|
|
10
|
+
}): Promise<{
|
|
11
|
+
project_id: string;
|
|
12
|
+
sub: string;
|
|
13
|
+
surface: "mcp" | "studio" | "channels" | "a2a";
|
|
14
|
+
iss: string;
|
|
15
|
+
aud: string;
|
|
16
|
+
iat: number;
|
|
17
|
+
exp: number;
|
|
18
|
+
request_hash: string;
|
|
19
|
+
}>;
|
|
20
|
+
//# sourceMappingURL=control-plane-auth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"control-plane-auth.d.ts","sourceRoot":"","sources":["../../../src/src/internal-agents/control-plane-auth.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,qBAAqB,CAAC;AAE/C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAQxD,qBAAa,wBAAyB,SAAQ,KAAK;IACjD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;gBAEZ,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;CAK5C;AAED,wBAAsB,yBAAyB,CAC7C,GAAG,EAAE,OAAO,CAAC,OAAO,EACpB,GAAG,EAAE,cAAc,EACnB,OAAO,EAAE,MAAM,EACf,OAAO,GAAE;IACP,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,eAAe,CAAC,EAAE,QAAQ,GAAG,UAAU,GAAG,KAAK,GAAG,KAAK,CAAC;CACpD;;;;;;;;;GAsDP"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { verifyControlPlaneJws } from "../channels/control-plane.js";
|
|
2
|
+
import { serverLogger } from "../utils/index.js";
|
|
3
|
+
import { HTTP_INTERNAL_SERVER_ERROR } from "../utils/constants/index.js";
|
|
4
|
+
const CONTROL_PLANE_JWS_HEADER = "x-veryfront-control-plane-jws";
|
|
5
|
+
const MAX_CONTROL_PLANE_SIGNATURE_AGE_SECONDS = 60;
|
|
6
|
+
const logger = serverLogger.component("internal-agents-auth");
|
|
7
|
+
export class ControlPlaneRequestError extends Error {
|
|
8
|
+
status;
|
|
9
|
+
constructor(status, message) {
|
|
10
|
+
super(message);
|
|
11
|
+
this.status = status;
|
|
12
|
+
this.name = "ControlPlaneRequestError";
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
export async function verifyControlPlaneRequest(req, ctx, rawBody, options = {}) {
|
|
16
|
+
const publicKeyPem = ctx.adapter.env.get("CHANNEL_DISPATCH_SIGNING_PUBLIC_KEY");
|
|
17
|
+
if (!publicKeyPem) {
|
|
18
|
+
throw new ControlPlaneRequestError(HTTP_INTERNAL_SERVER_ERROR, "Control-plane verification is not configured");
|
|
19
|
+
}
|
|
20
|
+
const projectSlug = ctx.projectSlug;
|
|
21
|
+
if (!projectSlug) {
|
|
22
|
+
throw new ControlPlaneRequestError(400, "Project context is unavailable");
|
|
23
|
+
}
|
|
24
|
+
const controlPlaneJws = req.headers.get(CONTROL_PLANE_JWS_HEADER);
|
|
25
|
+
if (!controlPlaneJws) {
|
|
26
|
+
throw new ControlPlaneRequestError(401, "Missing control-plane signature");
|
|
27
|
+
}
|
|
28
|
+
try {
|
|
29
|
+
return await verifyControlPlaneJws(controlPlaneJws, rawBody, {
|
|
30
|
+
audience: projectSlug,
|
|
31
|
+
expectedProjectId: ctx.projectId,
|
|
32
|
+
expectedSubject: options.expectedSubject,
|
|
33
|
+
expectedSurface: options.expectedSurface,
|
|
34
|
+
publicKeyPem,
|
|
35
|
+
maxAgeSeconds: MAX_CONTROL_PLANE_SIGNATURE_AGE_SECONDS,
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
const isAuthError = error instanceof Error && (error.message.includes("Control-plane") ||
|
|
40
|
+
error.message.includes("Unsupported"));
|
|
41
|
+
if (isAuthError) {
|
|
42
|
+
logger.warn("Invalid control-plane signature", {
|
|
43
|
+
error,
|
|
44
|
+
projectSlug,
|
|
45
|
+
expectedSubject: options.expectedSubject,
|
|
46
|
+
expectedSurface: options.expectedSurface,
|
|
47
|
+
});
|
|
48
|
+
throw new ControlPlaneRequestError(401, "Invalid control-plane signature");
|
|
49
|
+
}
|
|
50
|
+
logger.error("Unexpected error during control-plane verification", {
|
|
51
|
+
error,
|
|
52
|
+
projectSlug,
|
|
53
|
+
});
|
|
54
|
+
throw new ControlPlaneRequestError(HTTP_INTERNAL_SERVER_ERROR, "Internal error during request verification");
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import * as dntShim from "../../_dnt.shims.js";
|
|
2
|
+
export declare const INTERNAL_AGENT_STREAM_MAX_BODY_BYTES: number;
|
|
3
|
+
export declare const INTERNAL_AGENT_CONTROL_PLANE_MAX_BODY_BYTES: number;
|
|
4
|
+
export declare class InternalAgentRequestBodyTooLargeError extends Error {
|
|
5
|
+
readonly status = 413;
|
|
6
|
+
constructor(message?: string);
|
|
7
|
+
}
|
|
8
|
+
export declare function readInternalAgentRequestBody(request: dntShim.Request, maxBodyBytes?: number): Promise<string>;
|
|
9
|
+
//# sourceMappingURL=request-body.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request-body.d.ts","sourceRoot":"","sources":["../../../src/src/internal-agents/request-body.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,qBAAqB,CAAC;AAQ/C,eAAO,MAAM,oCAAoC,QAA8B,CAAC;AAChF,eAAO,MAAM,2CAA2C,QAAa,CAAC;AAEtE,qBAAa,qCAAsC,SAAQ,KAAK;IAC9D,QAAQ,CAAC,MAAM,OAA0B;gBAE7B,OAAO,SAAsB;CAI1C;AAED,wBAAsB,4BAA4B,CAChD,OAAO,EAAE,OAAO,CAAC,OAAO,EACxB,YAAY,SAAuC,GAClD,OAAO,CAAC,MAAM,CAAC,CAkBjB"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { VeryfrontError } from "../errors/types.js";
|
|
2
|
+
import { readBodyWithLimit } from "../security/index.js";
|
|
3
|
+
import { DEFAULT_MAX_BODY_SIZE_BYTES, HTTP_PAYLOAD_TOO_LARGE, } from "../utils/constants/index.js";
|
|
4
|
+
export const INTERNAL_AGENT_STREAM_MAX_BODY_BYTES = DEFAULT_MAX_BODY_SIZE_BYTES;
|
|
5
|
+
export const INTERNAL_AGENT_CONTROL_PLANE_MAX_BODY_BYTES = 128 * 1024;
|
|
6
|
+
export class InternalAgentRequestBodyTooLargeError extends Error {
|
|
7
|
+
status = HTTP_PAYLOAD_TOO_LARGE;
|
|
8
|
+
constructor(message = "Payload too large") {
|
|
9
|
+
super(message);
|
|
10
|
+
this.name = "InternalAgentRequestBodyTooLargeError";
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export async function readInternalAgentRequestBody(request, maxBodyBytes = INTERNAL_AGENT_STREAM_MAX_BODY_BYTES) {
|
|
14
|
+
if (!request.body) {
|
|
15
|
+
return "";
|
|
16
|
+
}
|
|
17
|
+
try {
|
|
18
|
+
return await readBodyWithLimit(request, maxBodyBytes);
|
|
19
|
+
}
|
|
20
|
+
catch (error) {
|
|
21
|
+
if (error instanceof VeryfrontError &&
|
|
22
|
+
error.slug === "input-validation-failed" &&
|
|
23
|
+
error.detail === "Request body exceeds size limit") {
|
|
24
|
+
throw new InternalAgentRequestBodyTooLargeError();
|
|
25
|
+
}
|
|
26
|
+
throw error;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import * as dntShim from "../../_dnt.shims.js";
|
|
2
|
+
import { type Agent, type AgentMessage as Message, type AgentResponse } from "../agent/index.js";
|
|
3
|
+
import { type AgentRunSessionManager } from "./session-manager.js";
|
|
4
|
+
import type { RuntimeRunAgentInput } from "./schema.js";
|
|
5
|
+
export interface RuntimeAgentStreamExecutionDeps {
|
|
6
|
+
sessionManager: AgentRunSessionManager;
|
|
7
|
+
createRuntime?: (agent: Agent, mergedTools: Agent["config"]["tools"]) => {
|
|
8
|
+
stream: (messages: Message[], context?: Record<string, unknown>, callbacks?: {
|
|
9
|
+
onFinish?: (response: AgentResponse) => void;
|
|
10
|
+
}) => Promise<ReadableStream<Uint8Array>>;
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
export declare function createRuntimeAgentStreamResponse(input: RuntimeRunAgentInput, agent: Agent, deps: RuntimeAgentStreamExecutionDeps): Promise<dntShim.Response>;
|
|
14
|
+
//# sourceMappingURL=run-stream.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-stream.d.ts","sourceRoot":"","sources":["../../../src/src/internal-agents/run-stream.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,qBAAqB,CAAC;AAC/C,OAAO,EACL,KAAK,KAAK,EACV,KAAK,YAAY,IAAI,OAAO,EAC5B,KAAK,aAAa,EAEnB,MAAM,mBAAmB,CAAC;AAW3B,OAAO,EAA0B,KAAK,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC3F,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAIxD,MAAM,WAAW,+BAA+B;IAC9C,cAAc,EAAE,sBAAsB,CAAC;IACvC,aAAa,CAAC,EAAE,CACd,KAAK,EAAE,KAAK,EACZ,WAAW,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,KAClC;QACH,MAAM,EAAE,CACN,QAAQ,EAAE,OAAO,EAAE,EACnB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjC,SAAS,CAAC,EAAE;YACV,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,aAAa,KAAK,IAAI,CAAC;SAC9C,KACE,OAAO,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC,CAAC;KAC1C,CAAC;CACH;AAsKD,wBAAsB,gCAAgC,CACpD,KAAK,EAAE,oBAAoB,EAC3B,KAAK,EAAE,KAAK,EACZ,IAAI,EAAE,+BAA+B,GACpC,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CAmJ3B"}
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
import * as dntShim from "../../_dnt.shims.js";
|
|
2
|
+
import { AgentRuntime, } from "../agent/index.js";
|
|
3
|
+
import { SKILL_TOOL_IDS } from "../skill/types.js";
|
|
4
|
+
import { toolRegistry } from "../tool/index.js";
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
import { createStreamTransformState, finalizeRunEvents, formatAgUiEvent, mapRuntimeEventToAgUi, parseSseJsonEvents, } from "./ag-ui-sse.js";
|
|
7
|
+
import { AgentRunCancelledError } from "./session-manager.js";
|
|
8
|
+
const anyObjectSchema = z.record(z.unknown());
|
|
9
|
+
function createInjectedStudioTool(runId, toolName, description, parameters, sessionManager) {
|
|
10
|
+
return {
|
|
11
|
+
id: toolName,
|
|
12
|
+
type: "function",
|
|
13
|
+
description: description ?? toolName,
|
|
14
|
+
inputSchema: anyObjectSchema,
|
|
15
|
+
inputSchemaJson: (parameters ??
|
|
16
|
+
{ type: "object", properties: {}, additionalProperties: true }),
|
|
17
|
+
execute: async (_input, context) => {
|
|
18
|
+
const toolCallId = typeof context?.toolCallId === "string" ? context.toolCallId : null;
|
|
19
|
+
if (!toolCallId) {
|
|
20
|
+
throw new Error(`Missing toolCallId for injected tool "${toolName}"`);
|
|
21
|
+
}
|
|
22
|
+
const waitResult = await sessionManager.waitForToolResult(runId, toolCallId);
|
|
23
|
+
if (waitResult.isError) {
|
|
24
|
+
throw new Error(typeof waitResult.result === "string"
|
|
25
|
+
? waitResult.result
|
|
26
|
+
: JSON.stringify(waitResult.result));
|
|
27
|
+
}
|
|
28
|
+
return waitResult.result;
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
function buildMergedTools(agent, input, sessionManager) {
|
|
33
|
+
const injectedTools = Object.fromEntries(input.tools.map((tool) => [
|
|
34
|
+
tool.name,
|
|
35
|
+
createInjectedStudioTool(input.runId, tool.name, tool.description, tool.parameters, sessionManager),
|
|
36
|
+
]));
|
|
37
|
+
if (!agent.config.tools) {
|
|
38
|
+
return Object.keys(injectedTools).length ? injectedTools : undefined;
|
|
39
|
+
}
|
|
40
|
+
if (agent.config.tools === true) {
|
|
41
|
+
const merged = {};
|
|
42
|
+
for (const [toolId] of toolRegistry.getAll()) {
|
|
43
|
+
if (!agent.config.skills && SKILL_TOOL_IDS.has(toolId)) {
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
merged[toolId] = true;
|
|
47
|
+
}
|
|
48
|
+
return { ...merged, ...injectedTools };
|
|
49
|
+
}
|
|
50
|
+
return { ...agent.config.tools, ...injectedTools };
|
|
51
|
+
}
|
|
52
|
+
function isRecord(value) {
|
|
53
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
54
|
+
}
|
|
55
|
+
function normalizeToolArgs(part) {
|
|
56
|
+
if (isRecord(part.args)) {
|
|
57
|
+
return part.args;
|
|
58
|
+
}
|
|
59
|
+
if (isRecord(part.input)) {
|
|
60
|
+
return part.input;
|
|
61
|
+
}
|
|
62
|
+
return {};
|
|
63
|
+
}
|
|
64
|
+
function normalizeMessagePart(part) {
|
|
65
|
+
if (part.type === "text" && typeof part.text === "string") {
|
|
66
|
+
return { type: "text", text: part.text };
|
|
67
|
+
}
|
|
68
|
+
if (part.type === "tool_call" &&
|
|
69
|
+
typeof part.id === "string" &&
|
|
70
|
+
typeof part.name === "string") {
|
|
71
|
+
return {
|
|
72
|
+
type: "tool-call",
|
|
73
|
+
toolCallId: part.id,
|
|
74
|
+
toolName: part.name,
|
|
75
|
+
args: normalizeToolArgs(part),
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
if (part.type === "tool-call" &&
|
|
79
|
+
typeof part.toolCallId === "string" &&
|
|
80
|
+
typeof part.toolName === "string") {
|
|
81
|
+
return {
|
|
82
|
+
type: "tool-call",
|
|
83
|
+
toolCallId: part.toolCallId,
|
|
84
|
+
toolName: part.toolName,
|
|
85
|
+
args: normalizeToolArgs(part),
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
if (typeof part.type === "string" &&
|
|
89
|
+
part.type.startsWith("tool-") &&
|
|
90
|
+
part.type !== "tool-result" &&
|
|
91
|
+
typeof part.toolCallId === "string" &&
|
|
92
|
+
typeof part.toolName === "string") {
|
|
93
|
+
return {
|
|
94
|
+
type: part.type,
|
|
95
|
+
toolCallId: part.toolCallId,
|
|
96
|
+
toolName: part.toolName,
|
|
97
|
+
args: normalizeToolArgs(part),
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
if (part.type === "tool_result" && typeof part.tool_call_id === "string") {
|
|
101
|
+
return {
|
|
102
|
+
type: "tool-result",
|
|
103
|
+
toolCallId: part.tool_call_id,
|
|
104
|
+
toolName: typeof part.tool_name === "string" ? part.tool_name : "unknown",
|
|
105
|
+
result: "output" in part ? part.output : undefined,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
if (part.type === "tool-result" && typeof part.toolCallId === "string") {
|
|
109
|
+
return {
|
|
110
|
+
type: "tool-result",
|
|
111
|
+
toolCallId: part.toolCallId,
|
|
112
|
+
toolName: typeof part.toolName === "string" ? part.toolName : "unknown",
|
|
113
|
+
result: "result" in part ? part.result : undefined,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
118
|
+
function normalizeRuntimeMessages(messages) {
|
|
119
|
+
return messages.map((message) => ({
|
|
120
|
+
id: message.id,
|
|
121
|
+
role: message.role,
|
|
122
|
+
parts: message.parts
|
|
123
|
+
.map((part) => isRecord(part) ? normalizeMessagePart(part) : null)
|
|
124
|
+
.filter((part) => part !== null),
|
|
125
|
+
...(message.createdAt ? { timestamp: Date.parse(message.createdAt) || undefined } : {}),
|
|
126
|
+
...(message.metadata ? { metadata: message.metadata } : {}),
|
|
127
|
+
}));
|
|
128
|
+
}
|
|
129
|
+
export async function createRuntimeAgentStreamResponse(input, agent, deps) {
|
|
130
|
+
const abortSignal = deps.sessionManager.startRun({
|
|
131
|
+
runId: input.runId,
|
|
132
|
+
threadId: input.threadId,
|
|
133
|
+
});
|
|
134
|
+
const mergedTools = buildMergedTools(agent, input, deps.sessionManager);
|
|
135
|
+
const runtime = deps.createRuntime?.(agent, mergedTools) ?? new AgentRuntime(agent.id, {
|
|
136
|
+
...agent.config,
|
|
137
|
+
tools: mergedTools,
|
|
138
|
+
});
|
|
139
|
+
let completedResponse = null;
|
|
140
|
+
const runtimeMessages = normalizeRuntimeMessages(input.messages);
|
|
141
|
+
let runtimeStream;
|
|
142
|
+
let clientAttached = true;
|
|
143
|
+
try {
|
|
144
|
+
runtimeStream = await runtime.stream(runtimeMessages, {
|
|
145
|
+
threadId: input.threadId,
|
|
146
|
+
runId: input.runId,
|
|
147
|
+
context: input.context,
|
|
148
|
+
forwardedProps: input.forwardedProps,
|
|
149
|
+
}, {
|
|
150
|
+
onFinish: (response) => {
|
|
151
|
+
completedResponse = response;
|
|
152
|
+
},
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
catch (error) {
|
|
156
|
+
deps.sessionManager.failRun(input.runId);
|
|
157
|
+
throw error;
|
|
158
|
+
}
|
|
159
|
+
const response = new ReadableStream({
|
|
160
|
+
start: async (controller) => {
|
|
161
|
+
const state = createStreamTransformState();
|
|
162
|
+
const reader = runtimeStream.getReader();
|
|
163
|
+
const decoder = new TextDecoder();
|
|
164
|
+
let remainder = "";
|
|
165
|
+
let aborted = false;
|
|
166
|
+
const enqueueIfAttached = (event, payload) => {
|
|
167
|
+
const encodedEvent = formatAgUiEvent(event, payload);
|
|
168
|
+
if (!clientAttached) {
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
try {
|
|
172
|
+
controller.enqueue(encodedEvent);
|
|
173
|
+
}
|
|
174
|
+
catch {
|
|
175
|
+
clientAttached = false;
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
const throwIfAborted = () => {
|
|
179
|
+
if (aborted || abortSignal.aborted) {
|
|
180
|
+
throw new AgentRunCancelledError();
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
const abortHandler = () => {
|
|
184
|
+
aborted = true;
|
|
185
|
+
reader.cancel(new AgentRunCancelledError()).catch(() => { });
|
|
186
|
+
};
|
|
187
|
+
abortSignal.addEventListener("abort", abortHandler, { once: true });
|
|
188
|
+
enqueueIfAttached("RunStarted", {
|
|
189
|
+
runId: input.runId,
|
|
190
|
+
threadId: input.threadId,
|
|
191
|
+
agentId: input.agentId,
|
|
192
|
+
});
|
|
193
|
+
try {
|
|
194
|
+
while (true) {
|
|
195
|
+
throwIfAborted();
|
|
196
|
+
const { done, value } = await reader.read();
|
|
197
|
+
throwIfAborted();
|
|
198
|
+
if (done) {
|
|
199
|
+
break;
|
|
200
|
+
}
|
|
201
|
+
remainder += decoder.decode(value, { stream: true });
|
|
202
|
+
const parsed = parseSseJsonEvents(remainder);
|
|
203
|
+
remainder = parsed.remainder;
|
|
204
|
+
for (const event of parsed.events) {
|
|
205
|
+
for (const mappedEvent of mapRuntimeEventToAgUi(state, event)) {
|
|
206
|
+
enqueueIfAttached(mappedEvent.event, mappedEvent.payload);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
throwIfAborted();
|
|
211
|
+
const trailingEvents = parseSseJsonEvents(`${remainder}\n\n`);
|
|
212
|
+
for (const event of trailingEvents.events) {
|
|
213
|
+
for (const mappedEvent of mapRuntimeEventToAgUi(state, event)) {
|
|
214
|
+
enqueueIfAttached(mappedEvent.event, mappedEvent.payload);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
throwIfAborted();
|
|
218
|
+
for (const mappedEvent of finalizeRunEvents(state, completedResponse)) {
|
|
219
|
+
enqueueIfAttached(mappedEvent.event, mappedEvent.payload);
|
|
220
|
+
}
|
|
221
|
+
deps.sessionManager.completeRun(input.runId);
|
|
222
|
+
}
|
|
223
|
+
catch (error) {
|
|
224
|
+
if (error instanceof AgentRunCancelledError) {
|
|
225
|
+
deps.sessionManager.cancelRun(input.runId);
|
|
226
|
+
enqueueIfAttached("RunError", {
|
|
227
|
+
code: "CANCELLED",
|
|
228
|
+
message: error.message,
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
else {
|
|
232
|
+
deps.sessionManager.failRun(input.runId);
|
|
233
|
+
enqueueIfAttached("RunError", {
|
|
234
|
+
code: "RUNTIME_ERROR",
|
|
235
|
+
message: error instanceof Error ? error.message : String(error),
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
finally {
|
|
240
|
+
abortSignal.removeEventListener("abort", abortHandler);
|
|
241
|
+
if (clientAttached) {
|
|
242
|
+
controller.close();
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
},
|
|
246
|
+
cancel() {
|
|
247
|
+
clientAttached = false;
|
|
248
|
+
return Promise.resolve();
|
|
249
|
+
},
|
|
250
|
+
});
|
|
251
|
+
return new dntShim.Response(response, {
|
|
252
|
+
status: 200,
|
|
253
|
+
headers: {
|
|
254
|
+
"Content-Type": "text/event-stream",
|
|
255
|
+
"Cache-Control": "no-cache",
|
|
256
|
+
Connection: "keep-alive",
|
|
257
|
+
},
|
|
258
|
+
});
|
|
259
|
+
}
|