veryfront 0.1.131 → 0.1.132
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/_dnt.polyfills.d.ts +11 -0
- package/esm/_dnt.polyfills.d.ts.map +1 -1
- package/esm/_dnt.polyfills.js +14 -0
- package/esm/deno.js +1 -1
- package/esm/src/agent/runtime/index.d.ts.map +1 -1
- package/esm/src/agent/runtime/index.js +17 -2
- package/esm/src/agent/runtime/tool-helpers.d.ts +2 -1
- package/esm/src/agent/runtime/tool-helpers.d.ts.map +1 -1
- package/esm/src/agent/runtime/tool-helpers.js +6 -3
- package/esm/src/html/html-injection.d.ts.map +1 -1
- package/esm/src/html/html-injection.js +6 -5
- package/esm/src/html/nonce-injection.d.ts +2 -0
- package/esm/src/html/nonce-injection.d.ts.map +1 -0
- package/esm/src/html/nonce-injection.js +104 -0
- package/esm/src/internal-agents/run-stream.d.ts.map +1 -1
- package/esm/src/internal-agents/run-stream.js +26 -4
- package/esm/src/rendering/orchestrator/html.d.ts.map +1 -1
- package/esm/src/rendering/orchestrator/html.js +3 -89
- package/esm/src/rendering/script-page-handling.js +1 -0
- package/esm/src/server/handlers/request/static.handler.d.ts.map +1 -1
- package/esm/src/server/handlers/request/static.handler.js +18 -10
- 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/_dnt.polyfills.ts +27 -0
- package/src/deno.js +1 -1
- package/src/src/agent/runtime/index.ts +22 -0
- package/src/src/agent/runtime/tool-helpers.ts +15 -3
- package/src/src/html/html-injection.ts +9 -5
- package/src/src/html/nonce-injection.ts +129 -0
- package/src/src/internal-agents/run-stream.ts +35 -4
- package/src/src/rendering/orchestrator/html.ts +3 -105
- package/src/src/rendering/script-page-handling.ts +1 -0
- package/src/src/server/handlers/request/static.handler.ts +22 -10
- package/src/src/utils/version-constant.ts +1 -1
package/esm/_dnt.polyfills.d.ts
CHANGED
|
@@ -159,6 +159,17 @@ declare global {
|
|
|
159
159
|
}
|
|
160
160
|
}
|
|
161
161
|
export {};
|
|
162
|
+
declare global {
|
|
163
|
+
interface Object {
|
|
164
|
+
/**
|
|
165
|
+
* Determines whether an object has a property with the specified name.
|
|
166
|
+
* @param o An object.
|
|
167
|
+
* @param v A property name.
|
|
168
|
+
*/
|
|
169
|
+
hasOwn(o: object, v: PropertyKey): boolean;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
export {};
|
|
162
173
|
declare global {
|
|
163
174
|
interface PromiseConstructor {
|
|
164
175
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_dnt.polyfills.d.ts","sourceRoot":"","sources":["../src/_dnt.polyfills.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"_dnt.polyfills.d.ts","sourceRoot":"","sources":["../src/_dnt.polyfills.ts"],"names":[],"mappings":"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"}
|
package/esm/_dnt.polyfills.js
CHANGED
|
@@ -270,6 +270,20 @@ if (!Uint8Array.prototype.findLast) {
|
|
|
270
270
|
return findLast(this, callbackfn, that);
|
|
271
271
|
};
|
|
272
272
|
}
|
|
273
|
+
// https://github.com/tc39/proposal-accessible-object-hasownproperty/blob/main/polyfill.js
|
|
274
|
+
if (!Object.hasOwn) {
|
|
275
|
+
Object.defineProperty(Object, "hasOwn", {
|
|
276
|
+
value: function (object, property) {
|
|
277
|
+
if (object == null) {
|
|
278
|
+
throw new TypeError("Cannot convert undefined or null to object");
|
|
279
|
+
}
|
|
280
|
+
return Object.prototype.hasOwnProperty.call(Object(object), property);
|
|
281
|
+
},
|
|
282
|
+
configurable: true,
|
|
283
|
+
enumerable: false,
|
|
284
|
+
writable: true,
|
|
285
|
+
});
|
|
286
|
+
}
|
|
273
287
|
// https://github.com/tc39/proposal-promise-with-resolvers/blob/3a78801e073e99217dbeb2c43ba7212f3bdc8b83/polyfills.js#L1C1-L9C2
|
|
274
288
|
if (Promise.withResolvers === undefined) {
|
|
275
289
|
Promise.withResolvers = () => {
|
package/esm/deno.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/src/agent/runtime/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EACL,KAAK,WAAW,EAEhB,KAAK,aAAa,EAGlB,KAAK,OAAO,EAEZ,KAAK,QAAQ,EACd,MAAM,aAAa,CAAC;AAIrB,OAAO,EAAgB,KAAK,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAgB/D,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAC5E,OAAO,EACL,qBAAqB,EACrB,iBAAiB,EACjB,aAAa,EACb,aAAa,GACd,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACzE,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAChF,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAC1E,YAAY,EAAE,iBAAiB,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAClG,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EAClB,mBAAmB,EACnB,sBAAsB,GACvB,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/src/agent/runtime/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EACL,KAAK,WAAW,EAEhB,KAAK,aAAa,EAGlB,KAAK,OAAO,EAEZ,KAAK,QAAQ,EACd,MAAM,aAAa,CAAC;AAIrB,OAAO,EAAgB,KAAK,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAgB/D,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAC5E,OAAO,EACL,qBAAqB,EACrB,iBAAiB,EACjB,aAAa,EACb,aAAa,GACd,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACzE,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAChF,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAC1E,YAAY,EAAE,iBAAiB,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAClG,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EAClB,mBAAmB,EACnB,sBAAsB,GACvB,MAAM,gBAAgB,CAAC;AAuDxB;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,EAAE,GAAG,SAAS,CA6BxE;AAED,gEAAgE;AAChE,KAAK,iBAAiB,GAClB;IAAE,OAAO,EAAE,IAAI,CAAA;CAAE,GACjB;IAAE,OAAO,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtC;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,MAAM,EAChB,iBAAiB,EAAE,MAAM,EAAE,GAAG,SAAS,EACvC,kBAAkB,EAAE,OAAO,GAC1B,iBAAiB,CAiBnB;AA0BD,qBAAa,YAAY;IACvB,OAAO,CAAC,EAAE,CAAS;IACnB,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,MAAM,CAAuB;gBAEzB,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW;IAS3C;;OAEG;IACG,QAAQ,CACZ,KAAK,EAAE,MAAM,GAAG,OAAO,EAAE,EACzB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjC,aAAa,CAAC,EAAE,MAAM,EACtB,uBAAuB,CAAC,EAAE,MAAM,GAC/B,OAAO,CAAC,aAAa,CAAC;IA2CzB;;;OAGG;IACG,MAAM,CACV,QAAQ,EAAE,OAAO,EAAE,EACnB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjC,SAAS,CAAC,EAAE;QACV,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,KAAK,IAAI,CAAC;QAC1C,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;QAClC,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,aAAa,KAAK,IAAI,CAAC;KAC9C,EACD,aAAa,CAAC,EAAE,MAAM,EACtB,uBAAuB,CAAC,EAAE,MAAM,EAChC,WAAW,CAAC,EAAE,WAAW,GACxB,OAAO,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC;IAsHtC;;OAEG;YACW,gBAAgB;IAuO9B;;;;OAIG;YACW,yBAAyB;IA8OvC;;OAEG;YACW,eAAe;IAqC7B;;OAEG;YACW,mBAAmB;IAOjC;;OAEG;IACH,OAAO,CAAC,eAAe;IAKvB,OAAO,CAAC,sBAAsB;IAY9B;;OAEG;IACH,SAAS,IAAI,MAAM,CAAC,OAAO,CAAC;IAI5B;;OAEG;IACG,cAAc,IAAI,OAAO,CAAC;QAC9B,aAAa,EAAE,MAAM,CAAC;QACtB,eAAe,EAAE,MAAM,CAAC;QACxB,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;IAIF;;OAEG;IACG,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;CAGnC"}
|
|
@@ -117,6 +117,17 @@ function isLocalModel(model) {
|
|
|
117
117
|
m.provider === "local" ||
|
|
118
118
|
(typeof m.modelId === "string" && m.modelId.startsWith("local/"));
|
|
119
119
|
}
|
|
120
|
+
function getRuntimeAllowedRemoteTools(config) {
|
|
121
|
+
const configWithRuntimeFilters = config;
|
|
122
|
+
if (!Object.hasOwn(configWithRuntimeFilters, "__vfAllowedRemoteTools")) {
|
|
123
|
+
return undefined;
|
|
124
|
+
}
|
|
125
|
+
const raw = configWithRuntimeFilters.__vfAllowedRemoteTools;
|
|
126
|
+
if (!Array.isArray(raw)) {
|
|
127
|
+
return [];
|
|
128
|
+
}
|
|
129
|
+
return raw.every((toolName) => typeof toolName === "string") ? raw : [];
|
|
130
|
+
}
|
|
120
131
|
export class AgentRuntime {
|
|
121
132
|
id;
|
|
122
133
|
config;
|
|
@@ -281,11 +292,13 @@ export class AgentRuntime {
|
|
|
281
292
|
}
|
|
282
293
|
// Request-scoped skill policy (not class-level mutable state)
|
|
283
294
|
let activeSkillPolicy;
|
|
295
|
+
const allowedRemoteToolNames = getRuntimeAllowedRemoteTools(this.config);
|
|
284
296
|
for (let step = 0; step < maxSteps; step++) {
|
|
285
297
|
this.status = "thinking";
|
|
286
298
|
addSpanEvent(loopSpan, "step_start", { step });
|
|
287
299
|
let tools = isLocal ? [] : await getAvailableTools(this.config.tools, {
|
|
288
300
|
includeSkillTools: Boolean(this.config.skills),
|
|
301
|
+
allowedRemoteToolNames,
|
|
289
302
|
});
|
|
290
303
|
// Layer 1: Filter tools based on active skill policy (planning-time)
|
|
291
304
|
if (activeSkillPolicy) {
|
|
@@ -387,7 +400,7 @@ export class AgentRuntime {
|
|
|
387
400
|
agentId: this.id,
|
|
388
401
|
toolCallId: tc.toolCallId,
|
|
389
402
|
projectId: cacheCtx?.projectId,
|
|
390
|
-
});
|
|
403
|
+
}, allowedRemoteToolNames);
|
|
391
404
|
toolCall.status = "completed";
|
|
392
405
|
toolCall.result = result;
|
|
393
406
|
toolCall.executionTime = Date.now() - startTime;
|
|
@@ -473,11 +486,13 @@ export class AgentRuntime {
|
|
|
473
486
|
// Request-scoped skill policy (not class-level mutable state)
|
|
474
487
|
let activeSkillPolicy;
|
|
475
488
|
let finalFinishReason;
|
|
489
|
+
const allowedRemoteToolNames = getRuntimeAllowedRemoteTools(this.config);
|
|
476
490
|
for (let step = 0; step < maxSteps; step++) {
|
|
477
491
|
throwIfAborted(abortSignal);
|
|
478
492
|
sendSSE(controller, encoder, { type: "step-start" });
|
|
479
493
|
let tools = isLocalStreaming ? [] : await getAvailableTools(this.config.tools, {
|
|
480
494
|
includeSkillTools: Boolean(this.config.skills),
|
|
495
|
+
allowedRemoteToolNames,
|
|
481
496
|
});
|
|
482
497
|
// Layer 1: Filter tools based on active skill policy (planning-time)
|
|
483
498
|
if (activeSkillPolicy) {
|
|
@@ -566,7 +581,7 @@ export class AgentRuntime {
|
|
|
566
581
|
agentId: this.id,
|
|
567
582
|
toolCallId: tc.id,
|
|
568
583
|
...toolContext,
|
|
569
|
-
});
|
|
584
|
+
}, allowedRemoteToolNames);
|
|
570
585
|
throwIfAborted(abortSignal);
|
|
571
586
|
toolCall.status = "completed";
|
|
572
587
|
toolCall.result = result;
|
|
@@ -28,7 +28,7 @@ export declare function isDynamicTool(name: string): boolean;
|
|
|
28
28
|
*/
|
|
29
29
|
export type ToolConfigEntry = Tool<any, any> | boolean;
|
|
30
30
|
export declare function resolveConfiguredTool(toolsConfig: true | Record<string, ToolConfigEntry> | undefined, toolName: string): Tool | null;
|
|
31
|
-
export declare function executeConfiguredTool(toolName: string, input: Record<string, unknown>, toolsConfig: true | Record<string, ToolConfigEntry> | undefined, context?: ToolExecutionContext): Promise<unknown>;
|
|
31
|
+
export declare function executeConfiguredTool(toolName: string, input: Record<string, unknown>, toolsConfig: true | Record<string, ToolConfigEntry> | undefined, context?: ToolExecutionContext, allowedRemoteToolNames?: string[]): Promise<unknown>;
|
|
32
32
|
/**
|
|
33
33
|
* Get available tools based on agent configuration.
|
|
34
34
|
* When tools === true, loads all tools from registry.
|
|
@@ -40,5 +40,6 @@ export declare function executeConfiguredTool(toolName: string, input: Record<st
|
|
|
40
40
|
export declare function getAvailableTools(toolsConfig: true | Record<string, ToolConfigEntry> | undefined, options?: {
|
|
41
41
|
includeSkillTools?: boolean;
|
|
42
42
|
includeIntegrationTools?: boolean;
|
|
43
|
+
allowedRemoteToolNames?: string[];
|
|
43
44
|
}): Promise<ToolDefinition[]>;
|
|
44
45
|
//# sourceMappingURL=tool-helpers.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool-helpers.d.ts","sourceRoot":"","sources":["../../../../src/src/agent/runtime/tool-helpers.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAYtF;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACxC,cAAc,CAuBhB;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEnD;AAED;;;GAGG;AAEH,MAAM,MAAM,eAAe,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,OAAO,CAAC;AAEvD,wBAAgB,qBAAqB,CACnC,WAAW,EAAE,IAAI,GAAG,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,GAAG,SAAS,EAC/D,QAAQ,EAAE,MAAM,GACf,IAAI,GAAG,IAAI,CAmBb;AAED,wBAAsB,qBAAqB,CACzC,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,WAAW,EAAE,IAAI,GAAG,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,GAAG,SAAS,EAC/D,OAAO,CAAC,EAAE,oBAAoB,
|
|
1
|
+
{"version":3,"file":"tool-helpers.d.ts","sourceRoot":"","sources":["../../../../src/src/agent/runtime/tool-helpers.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAYtF;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACxC,cAAc,CAuBhB;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEnD;AAED;;;GAGG;AAEH,MAAM,MAAM,eAAe,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,OAAO,CAAC;AAEvD,wBAAgB,qBAAqB,CACnC,WAAW,EAAE,IAAI,GAAG,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,GAAG,SAAS,EAC/D,QAAQ,EAAE,MAAM,GACf,IAAI,GAAG,IAAI,CAmBb;AAED,wBAAsB,qBAAqB,CACzC,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,WAAW,EAAE,IAAI,GAAG,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,GAAG,SAAS,EAC/D,OAAO,CAAC,EAAE,oBAAoB,EAC9B,sBAAsB,CAAC,EAAE,MAAM,EAAE,GAChC,OAAO,CAAC,OAAO,CAAC,CAyBlB;AAoBD;;;;;;;GAOG;AACH,wBAAsB,iBAAiB,CACrC,WAAW,EAAE,IAAI,GAAG,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,GAAG,SAAS,EAC/D,OAAO,CAAC,EAAE;IACR,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,sBAAsB,CAAC,EAAE,MAAM,EAAE,CAAC;CACnC,GACA,OAAO,CAAC,cAAc,EAAE,CAAC,CA4E3B"}
|
|
@@ -59,7 +59,7 @@ export function resolveConfiguredTool(toolsConfig, toolName) {
|
|
|
59
59
|
}
|
|
60
60
|
return null;
|
|
61
61
|
}
|
|
62
|
-
export async function executeConfiguredTool(toolName, input, toolsConfig, context) {
|
|
62
|
+
export async function executeConfiguredTool(toolName, input, toolsConfig, context, allowedRemoteToolNames) {
|
|
63
63
|
const configuredTool = resolveConfiguredTool(toolsConfig, toolName);
|
|
64
64
|
if (configuredTool) {
|
|
65
65
|
return await configuredTool.execute(input, context);
|
|
@@ -71,6 +71,9 @@ export async function executeConfiguredTool(toolName, input, toolsConfig, contex
|
|
|
71
71
|
}
|
|
72
72
|
// Fall back to remote execution for integration tools (e.g., github:list-repos)
|
|
73
73
|
if (isRemoteIntegrationTool(toolName)) {
|
|
74
|
+
if (allowedRemoteToolNames && !allowedRemoteToolNames.includes(toolName)) {
|
|
75
|
+
throw new Error(`Tool "${toolName}" is not allowed for this run`);
|
|
76
|
+
}
|
|
74
77
|
return await executeRemoteIntegrationTool(toolName, input, context?.endUserId);
|
|
75
78
|
}
|
|
76
79
|
return await executeTool(toolName, input, context);
|
|
@@ -113,7 +116,7 @@ export async function getAvailableTools(toolsConfig, options) {
|
|
|
113
116
|
if (options?.includeIntegrationTools !== false) {
|
|
114
117
|
try {
|
|
115
118
|
const { getRemoteIntegrationToolDefinitions } = await import("../../integrations/remote-tools.js");
|
|
116
|
-
const remoteDefs = await getRemoteIntegrationToolDefinitions();
|
|
119
|
+
const remoteDefs = (await getRemoteIntegrationToolDefinitions()).filter((def) => !options?.allowedRemoteToolNames || options.allowedRemoteToolNames.includes(def.name));
|
|
117
120
|
for (const def of remoteDefs) {
|
|
118
121
|
logToolDefinition(def.name, def);
|
|
119
122
|
}
|
|
@@ -143,7 +146,7 @@ export async function getAvailableTools(toolsConfig, options) {
|
|
|
143
146
|
if (options?.includeIntegrationTools !== false) {
|
|
144
147
|
try {
|
|
145
148
|
const { getRemoteIntegrationToolDefinitions } = await import("../../integrations/remote-tools.js");
|
|
146
|
-
const remoteDefs = await getRemoteIntegrationToolDefinitions();
|
|
149
|
+
const remoteDefs = (await getRemoteIntegrationToolDefinitions()).filter((def) => !options?.allowedRemoteToolNames || options.allowedRemoteToolNames.includes(def.name));
|
|
147
150
|
for (const def of remoteDefs) {
|
|
148
151
|
// Skip if already present (e.g., explicitly configured by name)
|
|
149
152
|
if (!tools.some((t) => t.name === def.name)) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"html-injection.d.ts","sourceRoot":"","sources":["../../../src/src/html/html-injection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAkB/D,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,sEAAsE;IACtE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,2EAA2E;IAC3E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kDAAkD;IAClD,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,gDAAgD;IAChD,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,0CAA0C;IAC1C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uCAAuC;IACvC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gBAAgB;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,4DAA4D;IAC5D,WAAW,CAAC,EAAE,SAAS,GAAG,YAAY,CAAC;IACvC,+DAA+D;IAC/D,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,8DAA8D;IAC9D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,6DAA6D;IAC7D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iFAAiF;IACjF,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAgBD,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,YAAY,EACtB,OAAO,EAAE,wBAAwB,GAChC,MAAM,
|
|
1
|
+
{"version":3,"file":"html-injection.d.ts","sourceRoot":"","sources":["../../../src/src/html/html-injection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAkB/D,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,sEAAsE;IACtE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,2EAA2E;IAC3E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kDAAkD;IAClD,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,gDAAgD;IAChD,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,0CAA0C;IAC1C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uCAAuC;IACvC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gBAAgB;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,4DAA4D;IAC5D,WAAW,CAAC,EAAE,SAAS,GAAG,YAAY,CAAC;IACvC,+DAA+D;IAC/D,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,8DAA8D;IAC9D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,6DAA6D;IAC7D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iFAAiF;IACjF,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAgBD,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,YAAY,EACtB,OAAO,EAAE,wBAAwB,GAChC,MAAM,CAmGR"}
|
|
@@ -54,23 +54,24 @@ export function injectHTMLContent(template, content, metadata, options) {
|
|
|
54
54
|
environment: options.environment,
|
|
55
55
|
}),
|
|
56
56
|
});
|
|
57
|
-
const
|
|
57
|
+
const nonceAttr = buildNonceAttribute(options.nonce);
|
|
58
|
+
const hydrationScript = `<script id="veryfront-hydration-data" type="application/json"${nonceAttr}>${hydrationData}</script>`;
|
|
58
59
|
html = html.replace(/<\/body>/i, `${hydrationScript}</body>`);
|
|
59
60
|
}
|
|
60
61
|
if (options.mode === "development") {
|
|
61
62
|
const hasDevScriptsPlaceholder = /{{\s*devScripts\s*}}/i.test(html);
|
|
62
63
|
if (hasDevScriptsPlaceholder) {
|
|
63
|
-
html = html.replace(/{{\s*devScripts\s*}}/gi, getDevScripts());
|
|
64
|
+
html = html.replace(/{{\s*devScripts\s*}}/gi, getDevScripts(options.devPort, options.nonce));
|
|
64
65
|
}
|
|
65
|
-
html = html.replace(/{{\s*devStyles\s*}}/gi, getDevStyles());
|
|
66
|
+
html = html.replace(/{{\s*devStyles\s*}}/gi, getDevStyles(options.nonce));
|
|
66
67
|
if (!hasDevScriptsPlaceholder && hasBodyClose) {
|
|
67
|
-
html = html.replace(/<\/body>/i, `${getDevStyles()}${getDevScripts()}</body>`);
|
|
68
|
+
html = html.replace(/<\/body>/i, `${getDevStyles(options.nonce)}${getDevScripts(options.devPort, options.nonce)}</body>`);
|
|
68
69
|
}
|
|
69
70
|
}
|
|
70
71
|
else {
|
|
71
72
|
html = html.replace(/{{\s*devScripts\s*}}/gi, "");
|
|
72
73
|
html = html.replace(/{{\s*devStyles\s*}}/gi, "");
|
|
73
|
-
const prodScripts = getProdScripts(options.slug);
|
|
74
|
+
const prodScripts = getProdScripts(options.slug, options.nonce);
|
|
74
75
|
const hasProdScriptsPlaceholder = /{{\s*prodScripts\s*}}/i.test(html);
|
|
75
76
|
if (hasProdScriptsPlaceholder) {
|
|
76
77
|
html = html.replace(/{{\s*prodScripts\s*}}/gi, prodScripts);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nonce-injection.d.ts","sourceRoot":"","sources":["../../../src/src/html/nonce-injection.ts"],"names":[],"mappings":"AAmEA,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CA6DvE"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { escapeHtml } from "../utils/html-escape.js";
|
|
2
|
+
function findTagEnd(html, start) {
|
|
3
|
+
let activeQuote = null;
|
|
4
|
+
for (let index = start + 1; index < html.length; index++) {
|
|
5
|
+
const char = html[index];
|
|
6
|
+
if (activeQuote) {
|
|
7
|
+
if (char === activeQuote)
|
|
8
|
+
activeQuote = null;
|
|
9
|
+
continue;
|
|
10
|
+
}
|
|
11
|
+
if (char === '"' || char === "'") {
|
|
12
|
+
activeQuote = char;
|
|
13
|
+
continue;
|
|
14
|
+
}
|
|
15
|
+
if (char === ">")
|
|
16
|
+
return index;
|
|
17
|
+
}
|
|
18
|
+
return -1;
|
|
19
|
+
}
|
|
20
|
+
function getOpeningTagName(tag) {
|
|
21
|
+
const match = /^<\s*([a-zA-Z][\w:-]*)/u.exec(tag);
|
|
22
|
+
const tagName = match?.[1]?.toLowerCase();
|
|
23
|
+
if (tagName === "script" || tagName === "style")
|
|
24
|
+
return tagName;
|
|
25
|
+
return undefined;
|
|
26
|
+
}
|
|
27
|
+
function isTagBoundary(char) {
|
|
28
|
+
return char === undefined || /\s|\/|>/u.test(char);
|
|
29
|
+
}
|
|
30
|
+
function findRawTextClosingTagStart(lowerHtml, tagName, fromIndex) {
|
|
31
|
+
const needle = `</${tagName}`;
|
|
32
|
+
let searchIndex = fromIndex;
|
|
33
|
+
while (searchIndex < lowerHtml.length) {
|
|
34
|
+
const closingIndex = lowerHtml.indexOf(needle, searchIndex);
|
|
35
|
+
if (closingIndex === -1)
|
|
36
|
+
return -1;
|
|
37
|
+
if (isTagBoundary(lowerHtml[closingIndex + needle.length])) {
|
|
38
|
+
return closingIndex;
|
|
39
|
+
}
|
|
40
|
+
searchIndex = closingIndex + needle.length;
|
|
41
|
+
}
|
|
42
|
+
return -1;
|
|
43
|
+
}
|
|
44
|
+
function injectNonceIntoOpeningTag(tag, escapedNonce) {
|
|
45
|
+
if (/(?:\s|<)nonce\s*=/iu.test(tag))
|
|
46
|
+
return tag;
|
|
47
|
+
const closeIndex = tag.lastIndexOf(">");
|
|
48
|
+
if (closeIndex === -1)
|
|
49
|
+
return tag;
|
|
50
|
+
const insertAt = /\/\s*>$/u.test(tag) ? closeIndex - 1 : closeIndex;
|
|
51
|
+
return `${tag.slice(0, insertAt)} nonce="${escapedNonce}"${tag.slice(insertAt)}`;
|
|
52
|
+
}
|
|
53
|
+
export function addNonceToHtmlTags(html, nonce) {
|
|
54
|
+
if (!nonce)
|
|
55
|
+
return html;
|
|
56
|
+
const escapedNonce = escapeHtml(nonce);
|
|
57
|
+
const lowerHtml = html.toLowerCase();
|
|
58
|
+
let result = "";
|
|
59
|
+
let index = 0;
|
|
60
|
+
let rawTextTag = null;
|
|
61
|
+
while (index < html.length) {
|
|
62
|
+
if (rawTextTag) {
|
|
63
|
+
const closingIndex = findRawTextClosingTagStart(lowerHtml, rawTextTag, index);
|
|
64
|
+
if (closingIndex === -1) {
|
|
65
|
+
result += html.slice(index);
|
|
66
|
+
break;
|
|
67
|
+
}
|
|
68
|
+
result += html.slice(index, closingIndex);
|
|
69
|
+
index = closingIndex;
|
|
70
|
+
rawTextTag = null;
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
if (html.startsWith("<!--", index)) {
|
|
74
|
+
const commentEnd = html.indexOf("-->", index + 4);
|
|
75
|
+
const endIndex = commentEnd === -1 ? html.length : commentEnd + 3;
|
|
76
|
+
result += html.slice(index, endIndex);
|
|
77
|
+
index = endIndex;
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
if (html[index] !== "<") {
|
|
81
|
+
result += html[index];
|
|
82
|
+
index++;
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
const tagEnd = findTagEnd(html, index);
|
|
86
|
+
if (tagEnd === -1) {
|
|
87
|
+
result += html.slice(index);
|
|
88
|
+
break;
|
|
89
|
+
}
|
|
90
|
+
const tag = html.slice(index, tagEnd + 1);
|
|
91
|
+
const tagName = getOpeningTagName(tag);
|
|
92
|
+
if (!tagName) {
|
|
93
|
+
result += tag;
|
|
94
|
+
index = tagEnd + 1;
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
result += injectNonceIntoOpeningTag(tag, escapedNonce);
|
|
98
|
+
index = tagEnd + 1;
|
|
99
|
+
if (!/\/\s*>$/u.test(tag)) {
|
|
100
|
+
rawTextTag = tagName;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return result;
|
|
104
|
+
}
|
|
@@ -1 +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;
|
|
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;AAUxD,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,EACD,aAAa,CAAC,EAAE,MAAM,EACtB,uBAAuB,CAAC,EAAE,MAAM,EAChC,WAAW,CAAC,EAAE,WAAW,KACtB,OAAO,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC,CAAC;KAC1C,CAAC;CACH;AAsLD,wBAAsB,gCAAgC,CACpD,KAAK,EAAE,oBAAoB,EAC3B,KAAK,EAAE,KAAK,EACZ,IAAI,EAAE,+BAA+B,GACpC,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CA+J3B"}
|
|
@@ -126,16 +126,38 @@ function normalizeRuntimeMessages(messages) {
|
|
|
126
126
|
...(message.metadata ? { metadata: message.metadata } : {}),
|
|
127
127
|
}));
|
|
128
128
|
}
|
|
129
|
+
function getAllowedRemoteToolNames(forwardedProps) {
|
|
130
|
+
const runtimeOverrides = isRecord(forwardedProps?.runtimeOverrides)
|
|
131
|
+
? forwardedProps.runtimeOverrides
|
|
132
|
+
: null;
|
|
133
|
+
if (!runtimeOverrides || !Object.hasOwn(runtimeOverrides, "allowedTools")) {
|
|
134
|
+
return undefined;
|
|
135
|
+
}
|
|
136
|
+
const allowedTools = runtimeOverrides.allowedTools;
|
|
137
|
+
if (!Array.isArray(allowedTools)) {
|
|
138
|
+
return [];
|
|
139
|
+
}
|
|
140
|
+
return allowedTools.every((toolName) => typeof toolName === "string") ? allowedTools : [];
|
|
141
|
+
}
|
|
129
142
|
export async function createRuntimeAgentStreamResponse(input, agent, deps) {
|
|
130
143
|
const abortSignal = deps.sessionManager.startRun({
|
|
131
144
|
runId: input.runId,
|
|
132
145
|
threadId: input.threadId,
|
|
133
146
|
});
|
|
134
147
|
const mergedTools = buildMergedTools(agent, input, deps.sessionManager);
|
|
135
|
-
const
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
148
|
+
const allowedRemoteToolNames = getAllowedRemoteToolNames(input.forwardedProps);
|
|
149
|
+
const runtimeAgent = {
|
|
150
|
+
...agent,
|
|
151
|
+
config: {
|
|
152
|
+
...agent.config,
|
|
153
|
+
tools: mergedTools,
|
|
154
|
+
...(allowedRemoteToolNames !== undefined
|
|
155
|
+
? { __vfAllowedRemoteTools: allowedRemoteToolNames }
|
|
156
|
+
: {}),
|
|
157
|
+
},
|
|
158
|
+
};
|
|
159
|
+
const runtime = deps.createRuntime?.(runtimeAgent, mergedTools) ??
|
|
160
|
+
new AgentRuntime(runtimeAgent.id, runtimeAgent.config);
|
|
139
161
|
let completedResponse = null;
|
|
140
162
|
const runtimeMessages = normalizeRuntimeMessages(input.messages);
|
|
141
163
|
let runtimeStream;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"html.d.ts","sourceRoot":"","sources":["../../../../src/src/rendering/orchestrator/html.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAS7D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AACnE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AACtE,OAAO,KAAK,EACV,UAAU,EACV,UAAU,EACV,SAAS,EAET,UAAU,EACX,MAAM,sBAAsB,CAAC;AAG9B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"html.d.ts","sourceRoot":"","sources":["../../../../src/src/rendering/orchestrator/html.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAS7D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AACnE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AACtE,OAAO,KAAK,EACV,UAAU,EACV,UAAU,EACV,SAAS,EAET,UAAU,EACX,MAAM,sBAAsB,CAAC;AAG9B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAqBhD,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,cAAc,CAAC;IACxB,MAAM,EAAE,eAAe,CAAC;IACxB,IAAI,EAAE,aAAa,GAAG,YAAY,CAAC;CACpC;AAED,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,UAAU,CAAC;IACrB,UAAU,EAAE,UAAU,CAAC;IACvB,YAAY,EAAE,SAAS,GAAG,SAAS,CAAC;IACpC,aAAa,EAAE,UAAU,EAAE,CAAC;IAC5B,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC3C,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,2FAA2F;IAC3F,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAsB;gBAExB,MAAM,EAAE,mBAAmB;IAIjC,gBAAgB,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,MAAM,CAAC;IAajE,kBAAkB,CACtB,WAAW,EAAE,cAAc,EAC3B,OAAO,EAAE,IAAI,CAAC,qBAAqB,EAAE,MAAM,CAAC,GAC3C,OAAO,CAAC,cAAc,CAAC;YAgDZ,sBAAsB;YAiCtB,wBAAwB;YAmBxB,gBAAgB;YAyBhB,kBAAkB;IAwDhC,OAAO,CAAC,0BAA0B;IAsBlC,OAAO,CAAC,sBAAsB;IAgD9B,OAAO,CAAC,iBAAiB;IA4DzB,OAAO,CAAC,gBAAgB;IAQxB,OAAO,CAAC,cAAc;YAQR,eAAe;YAaf,gBAAgB;IAgF9B;;;;OAIG;YACW,gBAAgB;IA2D9B,OAAO,CAAC,wBAAwB;IAqBhC,OAAO,CAAC,qBAAqB;YAOf,6BAA6B;CAyD5C"}
|
|
@@ -2,7 +2,7 @@ import { join } from "../../platform/compat/path/index.js";
|
|
|
2
2
|
import { getExtensionName } from "../../utils/path-utils.js";
|
|
3
3
|
import { buildImportMapJson, extractHTMLMetadata, generateHTMLShellParts, injectHTMLContent, isFullHTMLDocument, } from "../../html/index.js";
|
|
4
4
|
import { DEFAULT_DASHBOARD_PORT, rendererLogger } from "../../utils/index.js";
|
|
5
|
-
import {
|
|
5
|
+
import { addNonceToHtmlTags } from "../../html/nonce-injection.js";
|
|
6
6
|
import { injectElementSelectors } from "../../studio/element-selector-injector.js";
|
|
7
7
|
import { computeSourceHash } from "../../studio/hash-utils.js";
|
|
8
8
|
import { extractRelativePath } from "../../utils/route-path-utils.js";
|
|
@@ -16,92 +16,6 @@ import { getRouteCandidates } from "./css-candidate-manifest.js";
|
|
|
16
16
|
import { resolveStyleContentVersion } from "../../html/styles-builder/content-version.js";
|
|
17
17
|
import { createStyleScopeProfile } from "../../html/styles-builder/style-scope-profile.js";
|
|
18
18
|
const logger = rendererLogger.component("html-generator");
|
|
19
|
-
function findTagEnd(html, start) {
|
|
20
|
-
let activeQuote = null;
|
|
21
|
-
for (let index = start + 1; index < html.length; index++) {
|
|
22
|
-
const char = html[index];
|
|
23
|
-
if (activeQuote) {
|
|
24
|
-
if (char === activeQuote)
|
|
25
|
-
activeQuote = null;
|
|
26
|
-
continue;
|
|
27
|
-
}
|
|
28
|
-
if (char === '"' || char === "'") {
|
|
29
|
-
activeQuote = char;
|
|
30
|
-
continue;
|
|
31
|
-
}
|
|
32
|
-
if (char === ">")
|
|
33
|
-
return index;
|
|
34
|
-
}
|
|
35
|
-
return -1;
|
|
36
|
-
}
|
|
37
|
-
function getOpeningTagName(tag) {
|
|
38
|
-
const match = /^<\s*([a-zA-Z][\w:-]*)/u.exec(tag);
|
|
39
|
-
const tagName = match?.[1]?.toLowerCase();
|
|
40
|
-
if (tagName === "script" || tagName === "style")
|
|
41
|
-
return tagName;
|
|
42
|
-
return undefined;
|
|
43
|
-
}
|
|
44
|
-
function injectNonceIntoOpeningTag(tag, escapedNonce) {
|
|
45
|
-
if (/\bnonce\s*=/iu.test(tag))
|
|
46
|
-
return tag;
|
|
47
|
-
const closeIndex = tag.lastIndexOf(">");
|
|
48
|
-
if (closeIndex === -1)
|
|
49
|
-
return tag;
|
|
50
|
-
const insertAt = /\/\s*>$/u.test(tag) ? closeIndex - 1 : closeIndex;
|
|
51
|
-
return `${tag.slice(0, insertAt)} nonce="${escapedNonce}"${tag.slice(insertAt)}`;
|
|
52
|
-
}
|
|
53
|
-
function addNonceToRenderedTags(html, nonce) {
|
|
54
|
-
if (!nonce)
|
|
55
|
-
return html;
|
|
56
|
-
const escapedNonce = escapeHtml(nonce);
|
|
57
|
-
const lowerHtml = html.toLowerCase();
|
|
58
|
-
let result = "";
|
|
59
|
-
let index = 0;
|
|
60
|
-
let rawTextTag = null;
|
|
61
|
-
while (index < html.length) {
|
|
62
|
-
if (rawTextTag) {
|
|
63
|
-
const closingIndex = lowerHtml.indexOf(`</${rawTextTag}`, index);
|
|
64
|
-
if (closingIndex === -1) {
|
|
65
|
-
result += html.slice(index);
|
|
66
|
-
break;
|
|
67
|
-
}
|
|
68
|
-
result += html.slice(index, closingIndex);
|
|
69
|
-
index = closingIndex;
|
|
70
|
-
rawTextTag = null;
|
|
71
|
-
continue;
|
|
72
|
-
}
|
|
73
|
-
if (html.startsWith("<!--", index)) {
|
|
74
|
-
const commentEnd = html.indexOf("-->", index + 4);
|
|
75
|
-
const endIndex = commentEnd === -1 ? html.length : commentEnd + 3;
|
|
76
|
-
result += html.slice(index, endIndex);
|
|
77
|
-
index = endIndex;
|
|
78
|
-
continue;
|
|
79
|
-
}
|
|
80
|
-
if (html[index] !== "<") {
|
|
81
|
-
result += html[index];
|
|
82
|
-
index++;
|
|
83
|
-
continue;
|
|
84
|
-
}
|
|
85
|
-
const tagEnd = findTagEnd(html, index);
|
|
86
|
-
if (tagEnd === -1) {
|
|
87
|
-
result += html.slice(index);
|
|
88
|
-
break;
|
|
89
|
-
}
|
|
90
|
-
const tag = html.slice(index, tagEnd + 1);
|
|
91
|
-
const tagName = getOpeningTagName(tag);
|
|
92
|
-
if (!tagName) {
|
|
93
|
-
result += tag;
|
|
94
|
-
index = tagEnd + 1;
|
|
95
|
-
continue;
|
|
96
|
-
}
|
|
97
|
-
result += injectNonceIntoOpeningTag(tag, escapedNonce);
|
|
98
|
-
index = tagEnd + 1;
|
|
99
|
-
if (!/\/\s*>$/u.test(tag)) {
|
|
100
|
-
rawTextTag = tagName;
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
return result;
|
|
104
|
-
}
|
|
105
19
|
export class HTMLGenerator {
|
|
106
20
|
config;
|
|
107
21
|
constructor(config) {
|
|
@@ -115,7 +29,7 @@ export class HTMLGenerator {
|
|
|
115
29
|
if (context.options?.studioEmbed) {
|
|
116
30
|
logger.debug("Injected element selectors for Studio");
|
|
117
31
|
}
|
|
118
|
-
return
|
|
32
|
+
return addNonceToHtmlTags(finalHtml, context.options?.nonce);
|
|
119
33
|
}
|
|
120
34
|
async generateHTMLStream(reactStream, context) {
|
|
121
35
|
const fullContext = context;
|
|
@@ -137,7 +51,7 @@ export class HTMLGenerator {
|
|
|
137
51
|
}
|
|
138
52
|
const { start, end } = await profilePhase("html.generate_shell_parts", () => this.generateShellParts(fullContext, mergedFrontmatter, htmlOptions, reactContent, projectCSSPromise));
|
|
139
53
|
const encoder = new TextEncoder();
|
|
140
|
-
const fullHtml =
|
|
54
|
+
const fullHtml = addNonceToHtmlTags(`${start}${reactContent}${end}`, context.options?.nonce);
|
|
141
55
|
return new ReadableStream({
|
|
142
56
|
start(controller) {
|
|
143
57
|
controller.enqueue(encoder.encode(fullHtml));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"static.handler.d.ts","sourceRoot":"","sources":["../../../../../src/src/server/handlers/request/static.handler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,OAAO,MAAM,2BAA2B,CAAC;AAGrD,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAmB,aAAa,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"static.handler.d.ts","sourceRoot":"","sources":["../../../../../src/src/server/handlers/request/static.handler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,OAAO,MAAM,2BAA2B,CAAC;AAGrD,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAmB,aAAa,EAAE,MAAM,aAAa,CAAC;AAgBnG,qBAAa,aAAc,SAAQ,WAAW;IAC5C,QAAQ,EAAE,eAAe,CAOvB;IAEF,OAAO,CAAC,aAAa,CAA2B;IAEhD,MAAM,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,EAAE,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;IAazE,OAAO,CAAC,cAAc;CAuEvB"}
|
|
@@ -3,6 +3,11 @@ import { hasMatchingEtag } from "../utils/etag.js";
|
|
|
3
3
|
import { HTTP_NOT_FOUND, HTTP_OK, PRIORITY_MEDIUM_STATIC, } from "../../../utils/constants/index.js";
|
|
4
4
|
import { withSpan } from "../../../observability/tracing/otlp-setup.js";
|
|
5
5
|
import { StaticFileService } from "../../services/static/index.js";
|
|
6
|
+
import { addNonceToHtmlTags } from "../../../html/nonce-injection.js";
|
|
7
|
+
import { computeEtag } from "../utils/etag.js";
|
|
8
|
+
function isHtmlResponse(contentType) {
|
|
9
|
+
return /\btext\/html\b/i.test(contentType);
|
|
10
|
+
}
|
|
6
11
|
export class StaticHandler extends BaseHandler {
|
|
7
12
|
metadata = {
|
|
8
13
|
name: "StaticHandler",
|
|
@@ -31,6 +36,8 @@ export class StaticHandler extends BaseHandler {
|
|
|
31
36
|
const isHead = method === "HEAD";
|
|
32
37
|
const isLocal = !!ctx.isLocalProject;
|
|
33
38
|
const isPreviewMode = ctx.requestContext?.mode === "preview" && !isLocal;
|
|
39
|
+
const builder = this.createResponseBuilder(ctx)
|
|
40
|
+
.withCORS(req, ctx.securityConfig?.cors);
|
|
34
41
|
const result = await this.staticService.resolveFile(pathname, {
|
|
35
42
|
projectDir: ctx.projectDir,
|
|
36
43
|
adapter: ctx.adapter,
|
|
@@ -40,24 +47,25 @@ export class StaticHandler extends BaseHandler {
|
|
|
40
47
|
if (!result) {
|
|
41
48
|
if (!this.staticService.isAssetRequest(pathname))
|
|
42
49
|
return null;
|
|
43
|
-
return
|
|
44
|
-
.withCORS(req, ctx.securityConfig?.cors)
|
|
50
|
+
return builder
|
|
45
51
|
.withSecurity(ctx.securityConfig ?? undefined, req)
|
|
46
52
|
.withCache("no-cache")
|
|
47
53
|
.withContentType("text/plain; charset=utf-8", isHead ? null : "Not Found", HTTP_NOT_FOUND);
|
|
48
54
|
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
55
|
+
const responseData = isHtmlResponse(result.contentType)
|
|
56
|
+
? new TextEncoder().encode(addNonceToHtmlTags(new TextDecoder().decode(result.data), builder.nonce))
|
|
57
|
+
: result.data;
|
|
58
|
+
const etag = computeEtag(responseData);
|
|
59
|
+
if (hasMatchingEtag(req, etag)) {
|
|
60
|
+
return builder
|
|
52
61
|
.withSecurity(ctx.securityConfig ?? undefined, req)
|
|
53
|
-
.notModified(
|
|
62
|
+
.notModified(etag);
|
|
54
63
|
}
|
|
55
|
-
const body = isHead ? null :
|
|
56
|
-
const response =
|
|
57
|
-
.withCORS(req, ctx.securityConfig?.cors)
|
|
64
|
+
const body = isHead ? null : responseData.slice();
|
|
65
|
+
const response = builder
|
|
58
66
|
.withSecurity(ctx.securityConfig ?? undefined, req)
|
|
59
67
|
.withCache(result.cacheStrategy)
|
|
60
|
-
.withETag(
|
|
68
|
+
.withETag(etag)
|
|
61
69
|
.withContentType(result.contentType, body, HTTP_OK);
|
|
62
70
|
this.logDebug(`Served static file: ${result.path}`, {
|
|
63
71
|
contentType: result.contentType,
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const VERSION = "0.1.
|
|
1
|
+
export declare const VERSION = "0.1.132";
|
|
2
2
|
//# sourceMappingURL=version-constant.d.ts.map
|
package/package.json
CHANGED
package/src/_dnt.polyfills.ts
CHANGED
|
@@ -506,6 +506,33 @@ if (!Uint8Array.prototype.findLast) {
|
|
|
506
506
|
};
|
|
507
507
|
}
|
|
508
508
|
|
|
509
|
+
export {};
|
|
510
|
+
// https://github.com/tc39/proposal-accessible-object-hasownproperty/blob/main/polyfill.js
|
|
511
|
+
if (!Object.hasOwn) {
|
|
512
|
+
Object.defineProperty(Object, "hasOwn", {
|
|
513
|
+
value: function (object: any, property: any) {
|
|
514
|
+
if (object == null) {
|
|
515
|
+
throw new TypeError("Cannot convert undefined or null to object");
|
|
516
|
+
}
|
|
517
|
+
return Object.prototype.hasOwnProperty.call(Object(object), property);
|
|
518
|
+
},
|
|
519
|
+
configurable: true,
|
|
520
|
+
enumerable: false,
|
|
521
|
+
writable: true,
|
|
522
|
+
});
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
declare global {
|
|
526
|
+
interface Object {
|
|
527
|
+
/**
|
|
528
|
+
* Determines whether an object has a property with the specified name.
|
|
529
|
+
* @param o An object.
|
|
530
|
+
* @param v A property name.
|
|
531
|
+
*/
|
|
532
|
+
hasOwn(o: object, v: PropertyKey): boolean;
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
|
|
509
536
|
export {};
|
|
510
537
|
declare global {
|
|
511
538
|
// https://github.com/denoland/deno/blob/0bfa0cc0276e94f1a308aaad5f925eaacb6e3db2/cli/tsc/dts/lib.es2021.promise.d.ts#L53
|
package/src/deno.js
CHANGED
|
@@ -77,6 +77,10 @@ import { resolveConfiguredAgentModel, resolveRuntimeModel } from "./model-resolu
|
|
|
77
77
|
const logger = serverLogger.component("agent");
|
|
78
78
|
const LOAD_SKILL_TOOL_ID = "load-skill";
|
|
79
79
|
|
|
80
|
+
type RuntimeToolFilterConfig = AgentConfig & {
|
|
81
|
+
__vfAllowedRemoteTools?: string[];
|
|
82
|
+
};
|
|
83
|
+
|
|
80
84
|
function createAbortError(reason?: unknown): Error {
|
|
81
85
|
if (reason instanceof Error) {
|
|
82
86
|
return reason;
|
|
@@ -187,6 +191,18 @@ function isLocalModel(model: LanguageModel): boolean {
|
|
|
187
191
|
(typeof m.modelId === "string" && m.modelId.startsWith("local/"));
|
|
188
192
|
}
|
|
189
193
|
|
|
194
|
+
function getRuntimeAllowedRemoteTools(config: AgentConfig): string[] | undefined {
|
|
195
|
+
const configWithRuntimeFilters = config as RuntimeToolFilterConfig;
|
|
196
|
+
if (!Object.hasOwn(configWithRuntimeFilters, "__vfAllowedRemoteTools")) {
|
|
197
|
+
return undefined;
|
|
198
|
+
}
|
|
199
|
+
const raw = configWithRuntimeFilters.__vfAllowedRemoteTools;
|
|
200
|
+
if (!Array.isArray(raw)) {
|
|
201
|
+
return [];
|
|
202
|
+
}
|
|
203
|
+
return raw.every((toolName) => typeof toolName === "string") ? raw : [];
|
|
204
|
+
}
|
|
205
|
+
|
|
190
206
|
export class AgentRuntime {
|
|
191
207
|
private id: string;
|
|
192
208
|
private config: AgentConfig;
|
|
@@ -418,6 +434,7 @@ export class AgentRuntime {
|
|
|
418
434
|
|
|
419
435
|
// Request-scoped skill policy (not class-level mutable state)
|
|
420
436
|
let activeSkillPolicy: string[] | undefined;
|
|
437
|
+
const allowedRemoteToolNames = getRuntimeAllowedRemoteTools(this.config);
|
|
421
438
|
|
|
422
439
|
for (let step = 0; step < maxSteps; step++) {
|
|
423
440
|
this.status = "thinking";
|
|
@@ -425,6 +442,7 @@ export class AgentRuntime {
|
|
|
425
442
|
|
|
426
443
|
let tools = isLocal ? [] : await getAvailableTools(this.config.tools, {
|
|
427
444
|
includeSkillTools: Boolean(this.config.skills),
|
|
445
|
+
allowedRemoteToolNames,
|
|
428
446
|
});
|
|
429
447
|
|
|
430
448
|
// Layer 1: Filter tools based on active skill policy (planning-time)
|
|
@@ -548,6 +566,7 @@ export class AgentRuntime {
|
|
|
548
566
|
toolCallId: tc.toolCallId,
|
|
549
567
|
projectId: cacheCtx?.projectId,
|
|
550
568
|
},
|
|
569
|
+
allowedRemoteToolNames,
|
|
551
570
|
);
|
|
552
571
|
|
|
553
572
|
toolCall.status = "completed";
|
|
@@ -662,6 +681,7 @@ export class AgentRuntime {
|
|
|
662
681
|
// Request-scoped skill policy (not class-level mutable state)
|
|
663
682
|
let activeSkillPolicy: string[] | undefined;
|
|
664
683
|
let finalFinishReason: string | undefined;
|
|
684
|
+
const allowedRemoteToolNames = getRuntimeAllowedRemoteTools(this.config);
|
|
665
685
|
|
|
666
686
|
for (let step = 0; step < maxSteps; step++) {
|
|
667
687
|
throwIfAborted(abortSignal);
|
|
@@ -669,6 +689,7 @@ export class AgentRuntime {
|
|
|
669
689
|
|
|
670
690
|
let tools = isLocalStreaming ? [] : await getAvailableTools(this.config.tools, {
|
|
671
691
|
includeSkillTools: Boolean(this.config.skills),
|
|
692
|
+
allowedRemoteToolNames,
|
|
672
693
|
});
|
|
673
694
|
|
|
674
695
|
// Layer 1: Filter tools based on active skill policy (planning-time)
|
|
@@ -791,6 +812,7 @@ export class AgentRuntime {
|
|
|
791
812
|
toolCallId: tc.id,
|
|
792
813
|
...toolContext,
|
|
793
814
|
},
|
|
815
|
+
allowedRemoteToolNames,
|
|
794
816
|
);
|
|
795
817
|
throwIfAborted(abortSignal);
|
|
796
818
|
|
|
@@ -100,6 +100,7 @@ export async function executeConfiguredTool(
|
|
|
100
100
|
input: Record<string, unknown>,
|
|
101
101
|
toolsConfig: true | Record<string, ToolConfigEntry> | undefined,
|
|
102
102
|
context?: ToolExecutionContext,
|
|
103
|
+
allowedRemoteToolNames?: string[],
|
|
103
104
|
): Promise<unknown> {
|
|
104
105
|
const configuredTool = resolveConfiguredTool(toolsConfig, toolName);
|
|
105
106
|
if (configuredTool) {
|
|
@@ -114,6 +115,9 @@ export async function executeConfiguredTool(
|
|
|
114
115
|
|
|
115
116
|
// Fall back to remote execution for integration tools (e.g., github:list-repos)
|
|
116
117
|
if (isRemoteIntegrationTool(toolName)) {
|
|
118
|
+
if (allowedRemoteToolNames && !allowedRemoteToolNames.includes(toolName)) {
|
|
119
|
+
throw new Error(`Tool "${toolName}" is not allowed for this run`);
|
|
120
|
+
}
|
|
117
121
|
return await executeRemoteIntegrationTool(
|
|
118
122
|
toolName,
|
|
119
123
|
input,
|
|
@@ -152,7 +156,11 @@ function addToolDefinition(
|
|
|
152
156
|
*/
|
|
153
157
|
export async function getAvailableTools(
|
|
154
158
|
toolsConfig: true | Record<string, ToolConfigEntry> | undefined,
|
|
155
|
-
options?: {
|
|
159
|
+
options?: {
|
|
160
|
+
includeSkillTools?: boolean;
|
|
161
|
+
includeIntegrationTools?: boolean;
|
|
162
|
+
allowedRemoteToolNames?: string[];
|
|
163
|
+
},
|
|
156
164
|
): Promise<ToolDefinition[]> {
|
|
157
165
|
if (!toolsConfig) return [];
|
|
158
166
|
|
|
@@ -176,7 +184,9 @@ export async function getAvailableTools(
|
|
|
176
184
|
const { getRemoteIntegrationToolDefinitions } = await import(
|
|
177
185
|
"../../integrations/remote-tools.js"
|
|
178
186
|
);
|
|
179
|
-
const remoteDefs = await getRemoteIntegrationToolDefinitions()
|
|
187
|
+
const remoteDefs = (await getRemoteIntegrationToolDefinitions()).filter((def) =>
|
|
188
|
+
!options?.allowedRemoteToolNames || options.allowedRemoteToolNames.includes(def.name)
|
|
189
|
+
);
|
|
180
190
|
for (const def of remoteDefs) {
|
|
181
191
|
logToolDefinition(def.name, def);
|
|
182
192
|
}
|
|
@@ -211,7 +221,9 @@ export async function getAvailableTools(
|
|
|
211
221
|
const { getRemoteIntegrationToolDefinitions } = await import(
|
|
212
222
|
"../../integrations/remote-tools.js"
|
|
213
223
|
);
|
|
214
|
-
const remoteDefs = await getRemoteIntegrationToolDefinitions()
|
|
224
|
+
const remoteDefs = (await getRemoteIntegrationToolDefinitions()).filter((def) =>
|
|
225
|
+
!options?.allowedRemoteToolNames || options.allowedRemoteToolNames.includes(def.name)
|
|
226
|
+
);
|
|
215
227
|
for (const def of remoteDefs) {
|
|
216
228
|
// Skip if already present (e.g., explicitly configured by name)
|
|
217
229
|
if (!tools.some((t) => t.name === def.name)) {
|
|
@@ -116,8 +116,9 @@ export function injectHTMLContent(
|
|
|
116
116
|
environment: options.environment,
|
|
117
117
|
}),
|
|
118
118
|
});
|
|
119
|
+
const nonceAttr = buildNonceAttribute(options.nonce);
|
|
119
120
|
const hydrationScript =
|
|
120
|
-
`<script id="veryfront-hydration-data" type="application/json">${hydrationData}</script>`;
|
|
121
|
+
`<script id="veryfront-hydration-data" type="application/json"${nonceAttr}>${hydrationData}</script>`;
|
|
121
122
|
html = html.replace(/<\/body>/i, `${hydrationScript}</body>`);
|
|
122
123
|
}
|
|
123
124
|
|
|
@@ -125,19 +126,22 @@ export function injectHTMLContent(
|
|
|
125
126
|
const hasDevScriptsPlaceholder = /{{\s*devScripts\s*}}/i.test(html);
|
|
126
127
|
|
|
127
128
|
if (hasDevScriptsPlaceholder) {
|
|
128
|
-
html = html.replace(/{{\s*devScripts\s*}}/gi, getDevScripts());
|
|
129
|
+
html = html.replace(/{{\s*devScripts\s*}}/gi, getDevScripts(options.devPort, options.nonce));
|
|
129
130
|
}
|
|
130
131
|
|
|
131
|
-
html = html.replace(/{{\s*devStyles\s*}}/gi, getDevStyles());
|
|
132
|
+
html = html.replace(/{{\s*devStyles\s*}}/gi, getDevStyles(options.nonce));
|
|
132
133
|
|
|
133
134
|
if (!hasDevScriptsPlaceholder && hasBodyClose) {
|
|
134
|
-
html = html.replace(
|
|
135
|
+
html = html.replace(
|
|
136
|
+
/<\/body>/i,
|
|
137
|
+
`${getDevStyles(options.nonce)}${getDevScripts(options.devPort, options.nonce)}</body>`,
|
|
138
|
+
);
|
|
135
139
|
}
|
|
136
140
|
} else {
|
|
137
141
|
html = html.replace(/{{\s*devScripts\s*}}/gi, "");
|
|
138
142
|
html = html.replace(/{{\s*devStyles\s*}}/gi, "");
|
|
139
143
|
|
|
140
|
-
const prodScripts = getProdScripts(options.slug);
|
|
144
|
+
const prodScripts = getProdScripts(options.slug, options.nonce);
|
|
141
145
|
const hasProdScriptsPlaceholder = /{{\s*prodScripts\s*}}/i.test(html);
|
|
142
146
|
|
|
143
147
|
if (hasProdScriptsPlaceholder) {
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { escapeHtml } from "../utils/html-escape.js";
|
|
2
|
+
|
|
3
|
+
function findTagEnd(html: string, start: number): number {
|
|
4
|
+
let activeQuote: '"' | "'" | null = null;
|
|
5
|
+
|
|
6
|
+
for (let index = start + 1; index < html.length; index++) {
|
|
7
|
+
const char = html[index];
|
|
8
|
+
|
|
9
|
+
if (activeQuote) {
|
|
10
|
+
if (char === activeQuote) activeQuote = null;
|
|
11
|
+
continue;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
if (char === '"' || char === "'") {
|
|
15
|
+
activeQuote = char;
|
|
16
|
+
continue;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if (char === ">") return index;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return -1;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function getOpeningTagName(tag: string): "script" | "style" | undefined {
|
|
26
|
+
const match = /^<\s*([a-zA-Z][\w:-]*)/u.exec(tag);
|
|
27
|
+
const tagName = match?.[1]?.toLowerCase();
|
|
28
|
+
if (tagName === "script" || tagName === "style") return tagName;
|
|
29
|
+
return undefined;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function isTagBoundary(char: string | undefined): boolean {
|
|
33
|
+
return char === undefined || /\s|\/|>/u.test(char);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function findRawTextClosingTagStart(
|
|
37
|
+
lowerHtml: string,
|
|
38
|
+
tagName: "script" | "style",
|
|
39
|
+
fromIndex: number,
|
|
40
|
+
): number {
|
|
41
|
+
const needle = `</${tagName}`;
|
|
42
|
+
let searchIndex = fromIndex;
|
|
43
|
+
|
|
44
|
+
while (searchIndex < lowerHtml.length) {
|
|
45
|
+
const closingIndex = lowerHtml.indexOf(needle, searchIndex);
|
|
46
|
+
if (closingIndex === -1) return -1;
|
|
47
|
+
|
|
48
|
+
if (isTagBoundary(lowerHtml[closingIndex + needle.length])) {
|
|
49
|
+
return closingIndex;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
searchIndex = closingIndex + needle.length;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return -1;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function injectNonceIntoOpeningTag(tag: string, escapedNonce: string): string {
|
|
59
|
+
if (/(?:\s|<)nonce\s*=/iu.test(tag)) return tag;
|
|
60
|
+
|
|
61
|
+
const closeIndex = tag.lastIndexOf(">");
|
|
62
|
+
if (closeIndex === -1) return tag;
|
|
63
|
+
|
|
64
|
+
const insertAt = /\/\s*>$/u.test(tag) ? closeIndex - 1 : closeIndex;
|
|
65
|
+
return `${tag.slice(0, insertAt)} nonce="${escapedNonce}"${tag.slice(insertAt)}`;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function addNonceToHtmlTags(html: string, nonce?: string): string {
|
|
69
|
+
if (!nonce) return html;
|
|
70
|
+
|
|
71
|
+
const escapedNonce = escapeHtml(nonce);
|
|
72
|
+
const lowerHtml = html.toLowerCase();
|
|
73
|
+
let result = "";
|
|
74
|
+
let index = 0;
|
|
75
|
+
let rawTextTag: "script" | "style" | null = null;
|
|
76
|
+
|
|
77
|
+
while (index < html.length) {
|
|
78
|
+
if (rawTextTag) {
|
|
79
|
+
const closingIndex = findRawTextClosingTagStart(lowerHtml, rawTextTag, index);
|
|
80
|
+
if (closingIndex === -1) {
|
|
81
|
+
result += html.slice(index);
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
result += html.slice(index, closingIndex);
|
|
86
|
+
index = closingIndex;
|
|
87
|
+
rawTextTag = null;
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (html.startsWith("<!--", index)) {
|
|
92
|
+
const commentEnd = html.indexOf("-->", index + 4);
|
|
93
|
+
const endIndex = commentEnd === -1 ? html.length : commentEnd + 3;
|
|
94
|
+
result += html.slice(index, endIndex);
|
|
95
|
+
index = endIndex;
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (html[index] !== "<") {
|
|
100
|
+
result += html[index];
|
|
101
|
+
index++;
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const tagEnd = findTagEnd(html, index);
|
|
106
|
+
if (tagEnd === -1) {
|
|
107
|
+
result += html.slice(index);
|
|
108
|
+
break;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const tag = html.slice(index, tagEnd + 1);
|
|
112
|
+
const tagName = getOpeningTagName(tag);
|
|
113
|
+
|
|
114
|
+
if (!tagName) {
|
|
115
|
+
result += tag;
|
|
116
|
+
index = tagEnd + 1;
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
result += injectNonceIntoOpeningTag(tag, escapedNonce);
|
|
121
|
+
index = tagEnd + 1;
|
|
122
|
+
|
|
123
|
+
if (!/\/\s*>$/u.test(tag)) {
|
|
124
|
+
rawTextTag = tagName;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return result;
|
|
129
|
+
}
|
|
@@ -20,6 +20,12 @@ import type { RuntimeRunAgentInput } from "./schema.js";
|
|
|
20
20
|
|
|
21
21
|
const anyObjectSchema = z.record(z.string(), z.unknown());
|
|
22
22
|
|
|
23
|
+
type RuntimeFilteredAgent = Agent & {
|
|
24
|
+
config: Agent["config"] & {
|
|
25
|
+
__vfAllowedRemoteTools?: string[];
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
|
|
23
29
|
export interface RuntimeAgentStreamExecutionDeps {
|
|
24
30
|
sessionManager: AgentRunSessionManager;
|
|
25
31
|
createRuntime?: (
|
|
@@ -203,6 +209,22 @@ function normalizeRuntimeMessages(messages: RuntimeRunAgentInput["messages"]): M
|
|
|
203
209
|
}));
|
|
204
210
|
}
|
|
205
211
|
|
|
212
|
+
function getAllowedRemoteToolNames(
|
|
213
|
+
forwardedProps: RuntimeRunAgentInput["forwardedProps"],
|
|
214
|
+
): string[] | undefined {
|
|
215
|
+
const runtimeOverrides = isRecord(forwardedProps?.runtimeOverrides)
|
|
216
|
+
? forwardedProps.runtimeOverrides
|
|
217
|
+
: null;
|
|
218
|
+
if (!runtimeOverrides || !Object.hasOwn(runtimeOverrides, "allowedTools")) {
|
|
219
|
+
return undefined;
|
|
220
|
+
}
|
|
221
|
+
const allowedTools = runtimeOverrides.allowedTools;
|
|
222
|
+
if (!Array.isArray(allowedTools)) {
|
|
223
|
+
return [];
|
|
224
|
+
}
|
|
225
|
+
return allowedTools.every((toolName) => typeof toolName === "string") ? allowedTools : [];
|
|
226
|
+
}
|
|
227
|
+
|
|
206
228
|
export async function createRuntimeAgentStreamResponse(
|
|
207
229
|
input: RuntimeRunAgentInput,
|
|
208
230
|
agent: Agent,
|
|
@@ -214,10 +236,19 @@ export async function createRuntimeAgentStreamResponse(
|
|
|
214
236
|
});
|
|
215
237
|
|
|
216
238
|
const mergedTools = buildMergedTools(agent, input, deps.sessionManager);
|
|
217
|
-
const
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
239
|
+
const allowedRemoteToolNames = getAllowedRemoteToolNames(input.forwardedProps);
|
|
240
|
+
const runtimeAgent: RuntimeFilteredAgent = {
|
|
241
|
+
...agent,
|
|
242
|
+
config: {
|
|
243
|
+
...agent.config,
|
|
244
|
+
tools: mergedTools,
|
|
245
|
+
...(allowedRemoteToolNames !== undefined
|
|
246
|
+
? { __vfAllowedRemoteTools: allowedRemoteToolNames }
|
|
247
|
+
: {}),
|
|
248
|
+
},
|
|
249
|
+
};
|
|
250
|
+
const runtime = deps.createRuntime?.(runtimeAgent, mergedTools) ??
|
|
251
|
+
new AgentRuntime(runtimeAgent.id, runtimeAgent.config);
|
|
221
252
|
|
|
222
253
|
let completedResponse: AgentResponse | null = null;
|
|
223
254
|
const runtimeMessages = normalizeRuntimeMessages(input.messages);
|
|
@@ -19,7 +19,7 @@ import type {
|
|
|
19
19
|
PageBundle,
|
|
20
20
|
} from "../../types/index.js";
|
|
21
21
|
import { DEFAULT_DASHBOARD_PORT, rendererLogger } from "../../utils/index.js";
|
|
22
|
-
import {
|
|
22
|
+
import { addNonceToHtmlTags } from "../../html/nonce-injection.js";
|
|
23
23
|
import type { RenderOptions } from "./types.js";
|
|
24
24
|
import { injectElementSelectors } from "../../studio/element-selector-injector.js";
|
|
25
25
|
import { computeSourceHash } from "../../studio/hash-utils.js";
|
|
@@ -41,108 +41,6 @@ import type { ResolvedContentContext } from "../../platform/adapters/fs/veryfron
|
|
|
41
41
|
const logger = rendererLogger.component("html-generator");
|
|
42
42
|
type ProjectCSSResult = Awaited<ReturnType<typeof getProjectCSS>> | null;
|
|
43
43
|
|
|
44
|
-
function findTagEnd(html: string, start: number): number {
|
|
45
|
-
let activeQuote: '"' | "'" | null = null;
|
|
46
|
-
|
|
47
|
-
for (let index = start + 1; index < html.length; index++) {
|
|
48
|
-
const char = html[index];
|
|
49
|
-
|
|
50
|
-
if (activeQuote) {
|
|
51
|
-
if (char === activeQuote) activeQuote = null;
|
|
52
|
-
continue;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
if (char === '"' || char === "'") {
|
|
56
|
-
activeQuote = char;
|
|
57
|
-
continue;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
if (char === ">") return index;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
return -1;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
function getOpeningTagName(tag: string): "script" | "style" | undefined {
|
|
67
|
-
const match = /^<\s*([a-zA-Z][\w:-]*)/u.exec(tag);
|
|
68
|
-
const tagName = match?.[1]?.toLowerCase();
|
|
69
|
-
if (tagName === "script" || tagName === "style") return tagName;
|
|
70
|
-
return undefined;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
function injectNonceIntoOpeningTag(tag: string, escapedNonce: string): string {
|
|
74
|
-
if (/\bnonce\s*=/iu.test(tag)) return tag;
|
|
75
|
-
|
|
76
|
-
const closeIndex = tag.lastIndexOf(">");
|
|
77
|
-
if (closeIndex === -1) return tag;
|
|
78
|
-
|
|
79
|
-
const insertAt = /\/\s*>$/u.test(tag) ? closeIndex - 1 : closeIndex;
|
|
80
|
-
return `${tag.slice(0, insertAt)} nonce="${escapedNonce}"${tag.slice(insertAt)}`;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
function addNonceToRenderedTags(html: string, nonce?: string): string {
|
|
84
|
-
if (!nonce) return html;
|
|
85
|
-
|
|
86
|
-
const escapedNonce = escapeHtml(nonce);
|
|
87
|
-
const lowerHtml = html.toLowerCase();
|
|
88
|
-
let result = "";
|
|
89
|
-
let index = 0;
|
|
90
|
-
let rawTextTag: "script" | "style" | null = null;
|
|
91
|
-
|
|
92
|
-
while (index < html.length) {
|
|
93
|
-
if (rawTextTag) {
|
|
94
|
-
const closingIndex = lowerHtml.indexOf(`</${rawTextTag}`, index);
|
|
95
|
-
if (closingIndex === -1) {
|
|
96
|
-
result += html.slice(index);
|
|
97
|
-
break;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
result += html.slice(index, closingIndex);
|
|
101
|
-
index = closingIndex;
|
|
102
|
-
rawTextTag = null;
|
|
103
|
-
continue;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
if (html.startsWith("<!--", index)) {
|
|
107
|
-
const commentEnd = html.indexOf("-->", index + 4);
|
|
108
|
-
const endIndex = commentEnd === -1 ? html.length : commentEnd + 3;
|
|
109
|
-
result += html.slice(index, endIndex);
|
|
110
|
-
index = endIndex;
|
|
111
|
-
continue;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
if (html[index] !== "<") {
|
|
115
|
-
result += html[index];
|
|
116
|
-
index++;
|
|
117
|
-
continue;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
const tagEnd = findTagEnd(html, index);
|
|
121
|
-
if (tagEnd === -1) {
|
|
122
|
-
result += html.slice(index);
|
|
123
|
-
break;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
const tag = html.slice(index, tagEnd + 1);
|
|
127
|
-
const tagName = getOpeningTagName(tag);
|
|
128
|
-
|
|
129
|
-
if (!tagName) {
|
|
130
|
-
result += tag;
|
|
131
|
-
index = tagEnd + 1;
|
|
132
|
-
continue;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
result += injectNonceIntoOpeningTag(tag, escapedNonce);
|
|
136
|
-
index = tagEnd + 1;
|
|
137
|
-
|
|
138
|
-
if (!/\/\s*>$/u.test(tag)) {
|
|
139
|
-
rawTextTag = tagName;
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
return result;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
44
|
export interface HTMLGeneratorConfig {
|
|
147
45
|
projectDir: string;
|
|
148
46
|
adapter: RuntimeAdapter;
|
|
@@ -182,7 +80,7 @@ export class HTMLGenerator {
|
|
|
182
80
|
logger.debug("Injected element selectors for Studio");
|
|
183
81
|
}
|
|
184
82
|
|
|
185
|
-
return
|
|
83
|
+
return addNonceToHtmlTags(finalHtml, context.options?.nonce);
|
|
186
84
|
}
|
|
187
85
|
|
|
188
86
|
async generateHTMLStream(
|
|
@@ -223,7 +121,7 @@ export class HTMLGenerator {
|
|
|
223
121
|
);
|
|
224
122
|
|
|
225
123
|
const encoder = new TextEncoder();
|
|
226
|
-
const fullHtml =
|
|
124
|
+
const fullHtml = addNonceToHtmlTags(
|
|
227
125
|
`${start}${reactContent}${end}`,
|
|
228
126
|
context.options?.nonce,
|
|
229
127
|
);
|
|
@@ -21,6 +21,12 @@ import {
|
|
|
21
21
|
} from "../../../utils/constants/index.js";
|
|
22
22
|
import { withSpan } from "../../../observability/tracing/otlp-setup.js";
|
|
23
23
|
import { StaticFileService } from "../../services/static/index.js";
|
|
24
|
+
import { addNonceToHtmlTags } from "../../../html/nonce-injection.js";
|
|
25
|
+
import { computeEtag } from "../utils/etag.js";
|
|
26
|
+
|
|
27
|
+
function isHtmlResponse(contentType: string): boolean {
|
|
28
|
+
return /\btext\/html\b/i.test(contentType);
|
|
29
|
+
}
|
|
24
30
|
|
|
25
31
|
export class StaticHandler extends BaseHandler {
|
|
26
32
|
metadata: HandlerMetadata = {
|
|
@@ -59,6 +65,8 @@ export class StaticHandler extends BaseHandler {
|
|
|
59
65
|
const isHead = method === "HEAD";
|
|
60
66
|
const isLocal = !!ctx.isLocalProject;
|
|
61
67
|
const isPreviewMode = ctx.requestContext?.mode === "preview" && !isLocal;
|
|
68
|
+
const builder = this.createResponseBuilder(ctx)
|
|
69
|
+
.withCORS(req, ctx.securityConfig?.cors);
|
|
62
70
|
|
|
63
71
|
const result = await this.staticService.resolveFile(pathname, {
|
|
64
72
|
projectDir: ctx.projectDir,
|
|
@@ -70,8 +78,7 @@ export class StaticHandler extends BaseHandler {
|
|
|
70
78
|
if (!result) {
|
|
71
79
|
if (!this.staticService.isAssetRequest(pathname)) return null;
|
|
72
80
|
|
|
73
|
-
return
|
|
74
|
-
.withCORS(req, ctx.securityConfig?.cors)
|
|
81
|
+
return builder
|
|
75
82
|
.withSecurity(ctx.securityConfig ?? undefined, req)
|
|
76
83
|
.withCache("no-cache")
|
|
77
84
|
.withContentType(
|
|
@@ -81,19 +88,24 @@ export class StaticHandler extends BaseHandler {
|
|
|
81
88
|
);
|
|
82
89
|
}
|
|
83
90
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
.
|
|
91
|
+
const responseData = isHtmlResponse(result.contentType)
|
|
92
|
+
? new TextEncoder().encode(
|
|
93
|
+
addNonceToHtmlTags(new TextDecoder().decode(result.data), builder.nonce),
|
|
94
|
+
)
|
|
95
|
+
: result.data;
|
|
96
|
+
const etag = computeEtag(responseData);
|
|
97
|
+
|
|
98
|
+
if (hasMatchingEtag(req, etag)) {
|
|
99
|
+
return builder
|
|
87
100
|
.withSecurity(ctx.securityConfig ?? undefined, req)
|
|
88
|
-
.notModified(
|
|
101
|
+
.notModified(etag);
|
|
89
102
|
}
|
|
90
103
|
|
|
91
|
-
const body: dntShim.BodyInit | null = isHead ? null :
|
|
92
|
-
const response =
|
|
93
|
-
.withCORS(req, ctx.securityConfig?.cors)
|
|
104
|
+
const body: dntShim.BodyInit | null = isHead ? null : responseData.slice();
|
|
105
|
+
const response = builder
|
|
94
106
|
.withSecurity(ctx.securityConfig ?? undefined, req)
|
|
95
107
|
.withCache(result.cacheStrategy)
|
|
96
|
-
.withETag(
|
|
108
|
+
.withETag(etag)
|
|
97
109
|
.withContentType(result.contentType, body, HTTP_OK);
|
|
98
110
|
|
|
99
111
|
this.logDebug(
|