Skip to content

Commit f22a263

Browse files
feat: improve execution state management and enhance message handling in iframe communication
1 parent e6ec07c commit f22a263

7 files changed

Lines changed: 44 additions & 24 deletions

File tree

apps/browser-demo/src/App.tsx

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,16 @@ export function App() {
3535

3636
const { startCapture, stopCapture } = useConsoleCapture();
3737

38-
const handleRun = useCallback(async () => {
39-
if (!ready || running) return;
40-
setRunning(true);
38+
const resetExecutionState = useCallback(() => {
4139
setResult(null);
4240
setConsoleEntries([]);
4341
setStats(null);
42+
}, []);
43+
44+
const handleRun = useCallback(async () => {
45+
if (!ready || running) return;
46+
setRunning(true);
47+
resetExecutionState();
4448

4549
try {
4650
startCapture();
@@ -65,18 +69,24 @@ export function App() {
6569
});
6670
setStats(zeroStats);
6771
} finally {
68-
const captured = stopCapture();
72+
let captured: ConsoleEntry[] = [];
73+
try {
74+
captured = stopCapture();
75+
} catch (_err) {
76+
/* stopCapture failure should not block UI reset */
77+
}
6978
setConsoleEntries(captured);
7079
setRunning(false);
7180
}
72-
}, [ready, running, code, run, startCapture, stopCapture]);
81+
}, [ready, running, code, run, startCapture, stopCapture, resetExecutionState]);
7382

74-
const handleExampleSelect = useCallback((exampleCode: string) => {
75-
setCode(exampleCode);
76-
setResult(null);
77-
setConsoleEntries([]);
78-
setStats(null);
79-
}, []);
83+
const handleExampleSelect = useCallback(
84+
(exampleCode: string) => {
85+
setCode(exampleCode);
86+
resetExecutionState();
87+
},
88+
[resetExecutionState],
89+
);
8090

8191
return (
8292
<div className="app">

libs/browser/e2e/fixtures/debug-inner.html

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@
135135
window.addEventListener('message', function (event) {
136136
var data = event.data;
137137
if (!data || data.__enclave_msg__ !== true) return;
138-
if (data.requestId && data.requestId !== requestId) return;
138+
if (data.requestId !== requestId) return;
139139

140140
if (data.type === 'tool-response') {
141141
var pending = pendingToolCalls[data.callId];
@@ -407,7 +407,6 @@
407407
// Memory-safe prototype patches
408408
(function () {
409409
var ml = 1048576;
410-
if (ml <= 0) return;
411410
var totalTracked = 0;
412411
function track(bytes) {
413412
totalTracked += bytes;
@@ -539,8 +538,6 @@
539538
'indexedDB',
540539
'caches',
541540
'navigator',
542-
'location',
543-
'document',
544541
'open',
545542
'close',
546543
'alert',
@@ -692,6 +689,9 @@
692689
// Execute User Code
693690
// ============================================================
694691
(async function () {
692+
// Shadow non-deletable browser globals so user code sees undefined
693+
var document = undefined;
694+
695695
try {
696696
// The transformed code defines __ag_main as a function declaration.
697697
// We embed it directly — CSP 'unsafe-inline' allows inline scripts

libs/browser/e2e/fixtures/debug-inner2.html

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@
135135
window.addEventListener('message', function (event) {
136136
var data = event.data;
137137
if (!data || data.__enclave_msg__ !== true) return;
138-
if (data.requestId && data.requestId !== requestId) return;
138+
if (data.requestId !== requestId) return;
139139

140140
if (data.type === 'tool-response') {
141141
var pending = pendingToolCalls[data.callId];
@@ -407,7 +407,6 @@
407407
// Memory-safe prototype patches
408408
(function () {
409409
var ml = 1048576;
410-
if (ml <= 0) return;
411410
var totalTracked = 0;
412411
function track(bytes) {
413412
totalTracked += bytes;
@@ -539,8 +538,6 @@
539538
'indexedDB',
540539
'caches',
541540
'navigator',
542-
'location',
543-
'document',
544541
'open',
545542
'close',
546543
'alert',
@@ -693,6 +690,9 @@
693690
// Execute User Code
694691
// ============================================================
695692
(async function () {
693+
// Shadow non-deletable browser globals so user code sees undefined
694+
var document = undefined;
695+
696696
try {
697697
// The transformed code defines __ag_main as a function declaration.
698698
// We embed it directly — CSP 'unsafe-inline' allows inline scripts

libs/browser/e2e/fixtures/debug-outer.html

Lines changed: 2 additions & 2 deletions
Large diffs are not rendered by default.

libs/browser/src/adapters/inner-iframe-bootstrap.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ function generateInnerIframeScript(userCode: string, config: SerializedIframeCon
152152
window.addEventListener('message', function(event) {
153153
var data = event.data;
154154
if (!data || data.__enclave_msg__ !== true) return;
155-
if (data.requestId && data.requestId !== requestId) return;
155+
if (data.requestId !== requestId) return;
156156
157157
if (data.type === 'tool-response') {
158158
var pending = pendingToolCalls[data.callId];
@@ -660,7 +660,9 @@ function generateUserCodeExecution(userCode: string): string {
660660
// The user code has already been transformed by @enclave-vm/ast
661661
// and contains __ag_main() function definition.
662662
// We embed it directly - it runs in the same script context.
663-
return userCode;
663+
// Escape closing script tags to prevent HTML parser breakout
664+
// when embedded via buildIframeHtml's <script>${content}</script>
665+
return userCode.replace(/<\//g, '<\\/');
664666
}
665667

666668
/**

libs/browser/src/adapters/outer-iframe-bootstrap.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ function generateOuterIframeScript(options: OuterIframeBootstrapOptions): string
197197
198198
var fromInner = (innerFrame && event.source === innerFrame.contentWindow);
199199
var fromHost = (event.source === window.parent);
200-
if (data.requestId && data.requestId !== requestId) return;
200+
if (data.requestId !== requestId) return;
201201
202202
// Messages from inner iframe (tool-call, result, console)
203203
if (data.type === 'tool-call') {

libs/browser/src/browser-enclave.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,14 @@ export class BrowserEnclave {
215215

216216
// Create validator
217217
const presetName: AstPreset = options.preset ?? 'agentscript';
218+
219+
if (this.customGlobalNames.length > 0 && presetName !== 'agentscript') {
220+
throw new Error(
221+
"Custom globals are only supported with the 'agentscript' preset. " +
222+
'Remove globals or switch to preset: "agentscript".',
223+
);
224+
}
225+
218226
this.validator = this.createValidator(presetName, customAllowedGlobals);
219227

220228
// Config flags

0 commit comments

Comments
 (0)