veryfront 0.1.62 → 0.1.64
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/cli/templates/manifest.js +37 -37
- package/esm/deno.d.ts +3 -0
- package/esm/deno.js +6 -3
- package/esm/src/agent/composition/composition.d.ts.map +1 -1
- package/esm/src/agent/composition/composition.js +13 -3
- package/esm/src/agent/factory.d.ts.map +1 -1
- package/esm/src/agent/factory.js +3 -3
- package/esm/src/agent/middleware/security/validator.d.ts +92 -0
- package/esm/src/agent/middleware/security/validator.d.ts.map +1 -0
- package/esm/src/agent/middleware/security/validator.js +187 -0
- package/esm/src/agent/runtime/index.d.ts +3 -2
- package/esm/src/agent/runtime/index.d.ts.map +1 -1
- package/esm/src/agent/runtime/index.js +16 -8
- package/esm/src/agent/types.d.ts +4 -0
- package/esm/src/agent/types.d.ts.map +1 -1
- package/esm/src/channels/invoke.d.ts +491 -0
- package/esm/src/channels/invoke.d.ts.map +1 -0
- package/esm/src/channels/invoke.js +417 -0
- package/esm/src/embedding/embedding.js +2 -2
- 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/integrations/schema.d.ts +2 -2
- package/esm/src/oauth/handlers/init-handler.d.ts +6 -2
- package/esm/src/oauth/handlers/init-handler.d.ts.map +1 -1
- package/esm/src/oauth/handlers/init-handler.js +8 -2
- package/esm/src/platform/compat/opaque-deps.d.ts.map +1 -1
- package/esm/src/platform/compat/opaque-deps.js +10 -1
- package/esm/src/prompt/factory.d.ts.map +1 -1
- package/esm/src/prompt/factory.js +9 -1
- package/esm/src/react/components/ai/markdown.d.ts.map +1 -1
- package/esm/src/react/components/ai/markdown.js +4 -4
- package/esm/src/server/handlers/dev/framework-candidates.generated.d.ts.map +1 -1
- package/esm/src/server/handlers/dev/framework-candidates.generated.js +5 -4
- package/esm/src/server/handlers/preview/markdown-html-generator.js +1 -1
- package/esm/src/server/handlers/request/api/api-handler-wrapper.d.ts.map +1 -1
- package/esm/src/server/handlers/request/api/api-handler-wrapper.js +1 -74
- package/esm/src/server/handlers/request/api/project-discovery.d.ts +9 -0
- package/esm/src/server/handlers/request/api/project-discovery.d.ts.map +1 -0
- package/esm/src/server/handlers/request/api/project-discovery.js +74 -0
- package/esm/src/server/handlers/request/channel-assistants.handler.d.ts +11 -0
- package/esm/src/server/handlers/request/channel-assistants.handler.d.ts.map +1 -0
- package/esm/src/server/handlers/request/channel-assistants.handler.js +71 -0
- package/esm/src/server/handlers/request/channel-invoke.handler.d.ts +11 -0
- package/esm/src/server/handlers/request/channel-invoke.handler.d.ts.map +1 -0
- package/esm/src/server/handlers/request/channel-invoke.handler.js +72 -0
- package/esm/src/server/runtime-handler/index.d.ts.map +1 -1
- package/esm/src/server/runtime-handler/index.js +4 -0
- package/esm/src/transforms/md/compiler/md-compiler.d.ts.map +1 -1
- package/esm/src/transforms/md/compiler/md-compiler.js +25 -1
- package/package.json +3 -1
- package/src/cli/templates/manifest.js +37 -37
- package/src/deno.js +6 -3
- package/src/src/agent/composition/composition.ts +15 -3
- package/src/src/agent/factory.ts +19 -6
- package/src/src/agent/middleware/security/validator.ts +288 -0
- package/src/src/agent/runtime/index.ts +26 -3
- package/src/src/agent/types.ts +4 -0
- package/src/src/channels/invoke.ts +546 -0
- package/src/src/embedding/embedding.ts +2 -2
- package/src/src/integrations/endpoint-executor.ts +51 -0
- package/src/src/oauth/handlers/init-handler.ts +20 -5
- package/src/src/platform/compat/opaque-deps.ts +19 -4
- package/src/src/prompt/factory.ts +10 -1
- package/src/src/react/components/ai/markdown.tsx +5 -4
- package/src/src/server/handlers/dev/framework-candidates.generated.ts +5 -4
- package/src/src/server/handlers/preview/markdown-html-generator.ts +1 -1
- package/src/src/server/handlers/request/api/api-handler-wrapper.ts +1 -85
- package/src/src/server/handlers/request/api/project-discovery.ts +86 -0
- package/src/src/server/handlers/request/channel-assistants.handler.ts +94 -0
- package/src/src/server/handlers/request/channel-invoke.handler.ts +95 -0
- package/src/src/server/runtime-handler/index.ts +4 -0
- package/src/src/transforms/md/compiler/md-compiler.ts +27 -1
package/src/deno.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export default {
|
|
2
2
|
"name": "veryfront",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.64",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"nodeModulesDir": "auto",
|
|
6
6
|
"exclude": [
|
|
@@ -225,6 +225,8 @@ export default {
|
|
|
225
225
|
"rehype-highlight": "npm:rehype-highlight@7.0.2",
|
|
226
226
|
"rehype-starry-night": "npm:rehype-starry-night@2.2.0",
|
|
227
227
|
"rehype-slug": "npm:rehype-slug@6.0.0",
|
|
228
|
+
"rehype-raw": "npm:rehype-raw@7.0.0",
|
|
229
|
+
"rehype-sanitize": "npm:rehype-sanitize@6.0.0",
|
|
228
230
|
"rehype-stringify": "npm:rehype-stringify@10.0.1",
|
|
229
231
|
"esbuild": "npm:esbuild@0.20.2",
|
|
230
232
|
"esbuild/mod.js": "npm:esbuild@0.20.2",
|
|
@@ -263,7 +265,8 @@ export default {
|
|
|
263
265
|
"class-variance-authority": "npm:class-variance-authority@0.7.1",
|
|
264
266
|
"clsx": "npm:clsx@2.1.1",
|
|
265
267
|
"tailwind-merge": "npm:tailwind-merge@2.6.0",
|
|
266
|
-
"@kreuzberg/wasm": "npm:@kreuzberg/wasm@4.4.2"
|
|
268
|
+
"@kreuzberg/wasm": "npm:@kreuzberg/wasm@4.4.2",
|
|
269
|
+
"#kreuzberg-wasm-glue": "npm:@kreuzberg/wasm@4.4.2/dist/pkg/kreuzberg_wasm.js"
|
|
267
270
|
},
|
|
268
271
|
"compilerOptions": {
|
|
269
272
|
"jsx": "react-jsx",
|
|
@@ -291,7 +294,7 @@ export default {
|
|
|
291
294
|
"dev": "deno task generate && deno run --allow-all cli/main.ts dev",
|
|
292
295
|
"production": "deno task generate && deno run --allow-all cli/main.ts serve --mode=production",
|
|
293
296
|
"build:prepare": "deno run -A scripts/build/generate-integrations-module.ts && deno task generate && deno run -A scripts/build/prepare-framework-sources.ts",
|
|
294
|
-
"build": "deno task build:prepare && deno
|
|
297
|
+
"build": "deno task build:prepare && deno run -A scripts/build/compile-binary.ts --output ./bin/veryfront",
|
|
295
298
|
"build:npm": "deno run -A scripts/build/generate-integrations-module.ts && deno task generate && deno run -A scripts/build/build-npm-dnt.ts",
|
|
296
299
|
"release": "deno run -A scripts/release.ts",
|
|
297
300
|
"test": "deno task generate && VF_DISABLE_LRU_INTERVAL=1 SSR_TRANSFORM_PER_PROJECT_LIMIT=0 REVALIDATION_PER_PROJECT_LIMIT=0 NODE_ENV=production LOG_FORMAT=text deno test --no-check --parallel --allow-all '--ignore=tests/e2e,tests/integration/compiled-binary-e2e.test.ts' --unstable-worker-options --unstable-net",
|
|
@@ -149,9 +149,21 @@ export function getAllAgentIds(): string[] {
|
|
|
149
149
|
// Register on globalThis so compiled-binary runtime shim can delegate to the
|
|
150
150
|
// real registry. External temp-file modules can't import from the embedded
|
|
151
151
|
// binary FS, so they use globalThis bridges instead.
|
|
152
|
-
|
|
153
|
-
(
|
|
154
|
-
|
|
152
|
+
// Use Object.defineProperty to prevent accidental overwriting or enumeration.
|
|
153
|
+
for (
|
|
154
|
+
const [key, value] of Object.entries({
|
|
155
|
+
__vfGetAgent: getAgent,
|
|
156
|
+
__vfRegisterAgent: registerAgent,
|
|
157
|
+
__vfGetAllAgentIds: getAllAgentIds,
|
|
158
|
+
})
|
|
159
|
+
) {
|
|
160
|
+
Object.defineProperty(dntShim.dntGlobalThis, key, {
|
|
161
|
+
value,
|
|
162
|
+
writable: false,
|
|
163
|
+
enumerable: false,
|
|
164
|
+
configurable: false,
|
|
165
|
+
});
|
|
166
|
+
}
|
|
155
167
|
|
|
156
168
|
export function getAgentsAsTools(descriptions?: Record<string, string>): Record<string, Tool> {
|
|
157
169
|
const tools: Record<string, Tool> = {};
|
package/src/src/agent/factory.ts
CHANGED
|
@@ -160,7 +160,7 @@ export function agent(config: AgentConfig): Agent {
|
|
|
160
160
|
generate(input): Promise<AgentResponse> {
|
|
161
161
|
return withSpan(
|
|
162
162
|
"agent.factory.generate",
|
|
163
|
-
() => runtime.generate(input.input, input.context, input.model),
|
|
163
|
+
() => runtime.generate(input.input, input.context, input.model, input.maxOutputTokens),
|
|
164
164
|
{ "agent.id": id },
|
|
165
165
|
);
|
|
166
166
|
},
|
|
@@ -179,10 +179,16 @@ export function agent(config: AgentConfig): Agent {
|
|
|
179
179
|
]
|
|
180
180
|
: (input.messages ?? []);
|
|
181
181
|
|
|
182
|
-
const stream = await runtime.stream(
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
182
|
+
const stream = await runtime.stream(
|
|
183
|
+
inputMessages,
|
|
184
|
+
input.context,
|
|
185
|
+
{
|
|
186
|
+
onToolCall: input.onToolCall,
|
|
187
|
+
onChunk: input.onChunk,
|
|
188
|
+
},
|
|
189
|
+
input.model,
|
|
190
|
+
input.maxOutputTokens,
|
|
191
|
+
);
|
|
186
192
|
|
|
187
193
|
return createAgentStreamResult(stream);
|
|
188
194
|
},
|
|
@@ -198,6 +204,7 @@ export function agent(config: AgentConfig): Agent {
|
|
|
198
204
|
messages?: Message[];
|
|
199
205
|
context?: Record<string, unknown>;
|
|
200
206
|
model?: string;
|
|
207
|
+
maxOutputTokens?: number;
|
|
201
208
|
} = await request.json();
|
|
202
209
|
|
|
203
210
|
// Validate model override against allowlist when configured
|
|
@@ -216,7 +223,13 @@ export function agent(config: AgentConfig): Agent {
|
|
|
216
223
|
}
|
|
217
224
|
|
|
218
225
|
const messages = body.messages ?? [];
|
|
219
|
-
const stream = await runtime.stream(
|
|
226
|
+
const stream = await runtime.stream(
|
|
227
|
+
messages,
|
|
228
|
+
body.context,
|
|
229
|
+
undefined,
|
|
230
|
+
modelOverride,
|
|
231
|
+
body.maxOutputTokens,
|
|
232
|
+
);
|
|
220
233
|
|
|
221
234
|
return new dntShim.Response(stream, { headers: STREAMING_HEADERS });
|
|
222
235
|
},
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
import type { AgentContext, AgentResponse } from "../../types.js";
|
|
2
|
+
import { createError, toError } from "../../../errors/veryfront-error.js";
|
|
3
|
+
|
|
4
|
+
export interface SecurityConfig {
|
|
5
|
+
/** Input validation rules */
|
|
6
|
+
input?: {
|
|
7
|
+
/** Maximum input length */
|
|
8
|
+
maxLength?: number;
|
|
9
|
+
|
|
10
|
+
/** Blocked patterns (regex) */
|
|
11
|
+
blockedPatterns?: RegExp[];
|
|
12
|
+
|
|
13
|
+
/** Sanitize input */
|
|
14
|
+
sanitize?: boolean;
|
|
15
|
+
|
|
16
|
+
/** Custom validator */
|
|
17
|
+
validate?: (input: string) => boolean | Promise<boolean>;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/** Output filtering rules */
|
|
21
|
+
output?: {
|
|
22
|
+
/** Blocked patterns in output */
|
|
23
|
+
blockedPatterns?: RegExp[];
|
|
24
|
+
|
|
25
|
+
/** Filter PII (Personal Identifiable Information) */
|
|
26
|
+
filterPII?: boolean;
|
|
27
|
+
|
|
28
|
+
/** Custom filter */
|
|
29
|
+
filter?: (output: string) => string | Promise<string>;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
/** Action when violation detected */
|
|
33
|
+
onViolation?: (violation: SecurityViolation) => void;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface SecurityViolation {
|
|
37
|
+
/** Violation type */
|
|
38
|
+
type: "input" | "output";
|
|
39
|
+
|
|
40
|
+
/** Violation reason */
|
|
41
|
+
reason: string;
|
|
42
|
+
|
|
43
|
+
/** Original content */
|
|
44
|
+
content: string;
|
|
45
|
+
|
|
46
|
+
/** Matched pattern (if any) */
|
|
47
|
+
pattern?: RegExp;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Common blocked patterns
|
|
52
|
+
*/
|
|
53
|
+
export const COMMON_BLOCKED_PATTERNS = {
|
|
54
|
+
/** Prompt injection attempts */
|
|
55
|
+
promptInjection: [
|
|
56
|
+
/ignore\s+previous\s+instructions/i,
|
|
57
|
+
/ignore\s+all\s+previous\s+prompts/i,
|
|
58
|
+
/you\s+are\s+now\s+a/i,
|
|
59
|
+
/pretend\s+you\s+are/i,
|
|
60
|
+
/system:\s*/i,
|
|
61
|
+
/<\|im_start\|>/i,
|
|
62
|
+
/<\|im_end\|>/i,
|
|
63
|
+
],
|
|
64
|
+
|
|
65
|
+
/** Potential data exfiltration */
|
|
66
|
+
dataExfiltration: [
|
|
67
|
+
/password/i,
|
|
68
|
+
/api[_\s-]?key/i,
|
|
69
|
+
/secret/i,
|
|
70
|
+
/token/i,
|
|
71
|
+
/credit\s+card/i,
|
|
72
|
+
],
|
|
73
|
+
|
|
74
|
+
/** SQL injection patterns */
|
|
75
|
+
sqlInjection: [
|
|
76
|
+
/(\bUNION\b|\bSELECT\b).*\bFROM\b/i,
|
|
77
|
+
/;\s*(DROP|DELETE|UPDATE|INSERT)/i,
|
|
78
|
+
],
|
|
79
|
+
|
|
80
|
+
/** XSS patterns */
|
|
81
|
+
xss: [
|
|
82
|
+
/<script[^>]*>.*?<\/script>/gi,
|
|
83
|
+
/javascript:/i,
|
|
84
|
+
/on\w+\s*=/i, // Event handlers
|
|
85
|
+
],
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* PII patterns with replacement labels
|
|
90
|
+
*/
|
|
91
|
+
const PII_REPLACEMENTS: Array<{ pattern: RegExp; label: string }> = [
|
|
92
|
+
{ pattern: /\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b/gi, label: "[EMAIL]" },
|
|
93
|
+
{
|
|
94
|
+
pattern: /\b(\+\d{1,3}[-.\s]?)?\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}\b/g,
|
|
95
|
+
label: "[PHONE]",
|
|
96
|
+
},
|
|
97
|
+
{ pattern: /\b\d{3}-\d{2}-\d{4}\b/g, label: "[SSN]" },
|
|
98
|
+
{ pattern: /\b\d{4}[-\s]?\d{4}[-\s]?\d{4}[-\s]?\d{4}\b/g, label: "[CREDIT_CARD]" },
|
|
99
|
+
];
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Input Validator
|
|
103
|
+
*/
|
|
104
|
+
export class InputValidator {
|
|
105
|
+
private config: NonNullable<SecurityConfig["input"]>;
|
|
106
|
+
|
|
107
|
+
constructor(config?: SecurityConfig["input"]) {
|
|
108
|
+
this.config = config ?? {};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Validate input
|
|
113
|
+
*/
|
|
114
|
+
async validate(input: string): Promise<{
|
|
115
|
+
valid: boolean;
|
|
116
|
+
sanitized?: string;
|
|
117
|
+
violations: SecurityViolation[];
|
|
118
|
+
}> {
|
|
119
|
+
const violations: SecurityViolation[] = [];
|
|
120
|
+
|
|
121
|
+
const maxLength = this.config.maxLength;
|
|
122
|
+
if (maxLength != null && input.length > maxLength) {
|
|
123
|
+
violations.push({
|
|
124
|
+
type: "input",
|
|
125
|
+
reason: `Input exceeds maximum length of ${maxLength}`,
|
|
126
|
+
content: `${input.substring(0, 100)}...`,
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
for (const pattern of this.config.blockedPatterns ?? []) {
|
|
131
|
+
if (!pattern.test(input)) continue;
|
|
132
|
+
|
|
133
|
+
violations.push({
|
|
134
|
+
type: "input",
|
|
135
|
+
reason: "Input matches blocked pattern",
|
|
136
|
+
content: input,
|
|
137
|
+
pattern,
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const customValidate = this.config.validate;
|
|
142
|
+
if (customValidate) {
|
|
143
|
+
const customValid = await customValidate(input);
|
|
144
|
+
if (!customValid) {
|
|
145
|
+
violations.push({
|
|
146
|
+
type: "input",
|
|
147
|
+
reason: "Custom validation failed",
|
|
148
|
+
content: input,
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const sanitized = this.config.sanitize ? this.sanitizeInput(input) : undefined;
|
|
154
|
+
|
|
155
|
+
return {
|
|
156
|
+
valid: violations.length === 0,
|
|
157
|
+
sanitized,
|
|
158
|
+
violations,
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/** Sanitization patterns to remove harmful content */
|
|
163
|
+
private static readonly SANITIZE_PATTERNS: RegExp[] = [
|
|
164
|
+
/<script[^>]*>.*?<\/script>/gi, // Script tags
|
|
165
|
+
/on\w+\s*=\s*["'][^"']*["']/gi, // Event handlers
|
|
166
|
+
/javascript:/gi, // JavaScript protocol
|
|
167
|
+
];
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Sanitize input (remove potentially harmful content)
|
|
171
|
+
*/
|
|
172
|
+
private sanitizeInput(input: string): string {
|
|
173
|
+
return InputValidator.SANITIZE_PATTERNS.reduce(
|
|
174
|
+
(text, pattern) => text.replace(pattern, ""),
|
|
175
|
+
input,
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Output Filter
|
|
182
|
+
*/
|
|
183
|
+
export class OutputFilter {
|
|
184
|
+
private config: NonNullable<SecurityConfig["output"]>;
|
|
185
|
+
|
|
186
|
+
constructor(config?: SecurityConfig["output"]) {
|
|
187
|
+
this.config = config ?? {};
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Filter output
|
|
192
|
+
*/
|
|
193
|
+
async filter(output: string): Promise<{
|
|
194
|
+
filtered: string;
|
|
195
|
+
violations: SecurityViolation[];
|
|
196
|
+
}> {
|
|
197
|
+
const violations: SecurityViolation[] = [];
|
|
198
|
+
let filtered = output;
|
|
199
|
+
|
|
200
|
+
for (const pattern of this.config.blockedPatterns ?? []) {
|
|
201
|
+
if (!pattern.test(filtered)) continue;
|
|
202
|
+
|
|
203
|
+
violations.push({
|
|
204
|
+
type: "output",
|
|
205
|
+
reason: "Output contains blocked pattern",
|
|
206
|
+
content: filtered,
|
|
207
|
+
pattern,
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
filtered = filtered.replace(pattern, "[REDACTED]");
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
if (this.config.filterPII) {
|
|
214
|
+
filtered = this.filterPII(filtered);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
const customFilter = this.config.filter;
|
|
218
|
+
if (customFilter) {
|
|
219
|
+
filtered = await customFilter(filtered);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
return { filtered, violations };
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Filter PII from output
|
|
227
|
+
*/
|
|
228
|
+
private filterPII(output: string): string {
|
|
229
|
+
return PII_REPLACEMENTS.reduce(
|
|
230
|
+
(text, { pattern, label }) => text.replace(pattern, label),
|
|
231
|
+
output,
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Report violations to the configured handler
|
|
238
|
+
*/
|
|
239
|
+
function reportViolations(
|
|
240
|
+
violations: SecurityViolation[],
|
|
241
|
+
onViolation?: (violation: SecurityViolation) => void,
|
|
242
|
+
): void {
|
|
243
|
+
if (!onViolation) return;
|
|
244
|
+
for (const violation of violations) onViolation(violation);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Create security middleware for agents
|
|
249
|
+
*/
|
|
250
|
+
export function securityMiddleware(
|
|
251
|
+
config: SecurityConfig,
|
|
252
|
+
): (context: AgentContext, next: () => Promise<AgentResponse>) => Promise<AgentResponse> {
|
|
253
|
+
const inputValidator = new InputValidator(config.input);
|
|
254
|
+
const outputFilter = new OutputFilter(config.output);
|
|
255
|
+
|
|
256
|
+
return async (
|
|
257
|
+
context: AgentContext,
|
|
258
|
+
next: () => Promise<AgentResponse>,
|
|
259
|
+
): Promise<AgentResponse> => {
|
|
260
|
+
const inputString = typeof context.input === "string"
|
|
261
|
+
? context.input
|
|
262
|
+
: JSON.stringify(context.input);
|
|
263
|
+
const inputValidation = await inputValidator.validate(inputString);
|
|
264
|
+
|
|
265
|
+
if (!inputValidation.valid) {
|
|
266
|
+
reportViolations(inputValidation.violations, config.onViolation);
|
|
267
|
+
|
|
268
|
+
const firstViolation = inputValidation.violations[0];
|
|
269
|
+
throw toError(
|
|
270
|
+
createError({
|
|
271
|
+
type: "agent",
|
|
272
|
+
message: `Input validation failed: ${firstViolation?.reason ?? "Unknown reason"}`,
|
|
273
|
+
}),
|
|
274
|
+
);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
if (inputValidation.sanitized != null) {
|
|
278
|
+
context.input = inputValidation.sanitized;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
const result = await next();
|
|
282
|
+
|
|
283
|
+
const outputFiltering = await outputFilter.filter(result.text);
|
|
284
|
+
reportViolations(outputFiltering.violations, config.onViolation);
|
|
285
|
+
|
|
286
|
+
return { ...result, text: outputFiltering.filtered };
|
|
287
|
+
};
|
|
288
|
+
}
|
|
@@ -194,6 +194,7 @@ export class AgentRuntime {
|
|
|
194
194
|
input: string | Message[],
|
|
195
195
|
context?: Record<string, unknown>,
|
|
196
196
|
modelOverride?: string,
|
|
197
|
+
maxOutputTokensOverride?: number,
|
|
197
198
|
): Promise<AgentResponse> {
|
|
198
199
|
const requestedModel = resolveConfiguredAgentModel(modelOverride || this.config.model);
|
|
199
200
|
const resolvedModelString = maybeUpgradeLocalModel(requestedModel);
|
|
@@ -221,7 +222,13 @@ export class AgentRuntime {
|
|
|
221
222
|
const chain = new MiddlewareChain(this.config.middleware);
|
|
222
223
|
return chain.execute(
|
|
223
224
|
agentContext,
|
|
224
|
-
() =>
|
|
225
|
+
() =>
|
|
226
|
+
this.executeAgentLoop(
|
|
227
|
+
systemPrompt,
|
|
228
|
+
messages,
|
|
229
|
+
resolvedModelString,
|
|
230
|
+
maxOutputTokensOverride,
|
|
231
|
+
),
|
|
225
232
|
);
|
|
226
233
|
});
|
|
227
234
|
}
|
|
@@ -238,6 +245,7 @@ export class AgentRuntime {
|
|
|
238
245
|
onChunk?: (chunk: string) => void;
|
|
239
246
|
},
|
|
240
247
|
modelOverride?: string,
|
|
248
|
+
maxOutputTokensOverride?: number,
|
|
241
249
|
): Promise<ReadableStream<Uint8Array>> {
|
|
242
250
|
const requestedModel = resolveConfiguredAgentModel(modelOverride || this.config.model);
|
|
243
251
|
// Auto-upgrade local/* to a cloud provider when API keys are available.
|
|
@@ -300,6 +308,7 @@ export class AgentRuntime {
|
|
|
300
308
|
toolContext,
|
|
301
309
|
resolvedModelString,
|
|
302
310
|
languageModel,
|
|
311
|
+
maxOutputTokensOverride,
|
|
303
312
|
);
|
|
304
313
|
|
|
305
314
|
sendSSE(controller, encoder, { type: "text-end", id: textPartId });
|
|
@@ -325,6 +334,7 @@ export class AgentRuntime {
|
|
|
325
334
|
systemPrompt: string,
|
|
326
335
|
messages: Message[],
|
|
327
336
|
modelString?: string,
|
|
337
|
+
maxOutputTokensOverride?: number,
|
|
328
338
|
): Promise<AgentResponse> {
|
|
329
339
|
return withSpan("agent.execution_loop", async (loopSpan) => {
|
|
330
340
|
const { maxAgentSteps } = getPlatformCapabilities();
|
|
@@ -373,7 +383,7 @@ export class AgentRuntime {
|
|
|
373
383
|
system: systemPrompt,
|
|
374
384
|
messages: convertToModelMessages(currentMessages),
|
|
375
385
|
tools: convertToolsToAISDK(tools),
|
|
376
|
-
maxOutputTokens: this.
|
|
386
|
+
maxOutputTokens: this.resolveMaxOutputTokens(maxOutputTokensOverride),
|
|
377
387
|
temperature: DEFAULT_TEMPERATURE,
|
|
378
388
|
});
|
|
379
389
|
});
|
|
@@ -556,6 +566,7 @@ export class AgentRuntime {
|
|
|
556
566
|
toolContext?: Record<string, unknown>,
|
|
557
567
|
modelString?: string,
|
|
558
568
|
resolvedModel?: LanguageModel,
|
|
569
|
+
maxOutputTokensOverride?: number,
|
|
559
570
|
): Promise<AgentResponse> {
|
|
560
571
|
const { maxAgentSteps } = getPlatformCapabilities();
|
|
561
572
|
const maxSteps = this.computeMaxSteps(maxAgentSteps);
|
|
@@ -597,7 +608,7 @@ export class AgentRuntime {
|
|
|
597
608
|
system: systemPrompt,
|
|
598
609
|
messages: convertToModelMessages(currentMessages),
|
|
599
610
|
tools: convertToolsToAISDK(tools),
|
|
600
|
-
maxOutputTokens: this.
|
|
611
|
+
maxOutputTokens: this.resolveMaxOutputTokens(maxOutputTokensOverride),
|
|
601
612
|
temperature: DEFAULT_TEMPERATURE,
|
|
602
613
|
});
|
|
603
614
|
|
|
@@ -818,6 +829,18 @@ export class AgentRuntime {
|
|
|
818
829
|
return getMaxSteps(this.config.maxSteps, edgeMaxSteps, platformLimit);
|
|
819
830
|
}
|
|
820
831
|
|
|
832
|
+
private resolveMaxOutputTokens(maxOutputTokensOverride?: number): number {
|
|
833
|
+
if (
|
|
834
|
+
typeof maxOutputTokensOverride === "number" &&
|
|
835
|
+
Number.isFinite(maxOutputTokensOverride) &&
|
|
836
|
+
maxOutputTokensOverride > 0
|
|
837
|
+
) {
|
|
838
|
+
return Math.floor(maxOutputTokensOverride);
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
return this.config.memory?.maxTokens ?? DEFAULT_MAX_TOKENS;
|
|
842
|
+
}
|
|
843
|
+
|
|
821
844
|
/**
|
|
822
845
|
* Get memory instance (for advanced use cases)
|
|
823
846
|
*/
|
package/src/src/agent/types.ts
CHANGED
|
@@ -134,6 +134,8 @@ export interface Agent {
|
|
|
134
134
|
context?: Record<string, unknown>;
|
|
135
135
|
/** Override the agent's default model for this request. Must be in `allowedModels` if configured. */
|
|
136
136
|
model?: ModelString;
|
|
137
|
+
/** Override the maximum model output tokens for this request. */
|
|
138
|
+
maxOutputTokens?: number;
|
|
137
139
|
}): Promise<AgentResponse>;
|
|
138
140
|
|
|
139
141
|
stream(input: {
|
|
@@ -142,6 +144,8 @@ export interface Agent {
|
|
|
142
144
|
context?: Record<string, unknown>;
|
|
143
145
|
/** Override the agent's default model for this request. Must be in `allowedModels` if configured. */
|
|
144
146
|
model?: ModelString;
|
|
147
|
+
/** Override the maximum model output tokens for this request. */
|
|
148
|
+
maxOutputTokens?: number;
|
|
145
149
|
onToolCall?: (toolCall: ToolCall) => void;
|
|
146
150
|
onChunk?: (chunk: string) => void;
|
|
147
151
|
}): Promise<AgentStreamResult>;
|