Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -647,4 +647,25 @@ describe("OpenGenUIActivityRenderer", () => {
});
expect(parsed.success).toBe(true);
});

it("waits for complete streamed function source before injection", async () => {
const base = { html: ["<body><button onclick='greet()'>Go</button></body>"], htmlComplete: true, generating: true };
const partial = "function greet() {";
const complete = "function greet() { return 'hi'; }";
const { rerender } = renderRenderer({ ...base, jsFunctions: partial, jsFunctionsComplete: false });
await flushImport();
await resolveSandboxReady();
expect(mockRun.mock.calls.some((call) => call[0] === partial)).toBe(false);
rerender(rendererElement({ ...base, jsFunctions: complete, jsFunctionsComplete: true }));
await flushImport();
expect(mockRun.mock.calls.filter((call) => call[0] === complete)).toHaveLength(1);
});

it("does not run incomplete function source when generation stops", async () => {
const partial = "function greet() {";
renderRenderer({ html: ["<body>Interrupted</body>"], htmlComplete: true, generating: false, jsFunctions: partial, jsFunctionsComplete: false });
await flushImport(); await resolveSandboxReady();
expect(mockRun.mock.calls.some((call) => call[0] === partial)).toBe(false);
});

});
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,14 @@ const OpenGenUIActivityRendererInner = React.memo(

// Effect 2 — jsFunctions injection (once per final sandbox)
useEffect(() => {
if (!content.jsFunctions || jsFunctionsInjectedRef.current) return;
// Partial function source cannot run until the middleware completes it.
// Completed activities without the flag remain compatible.
if (
!content.jsFunctions ||
content.jsFunctionsComplete === false ||
(content.jsFunctionsComplete !== true && content.generating !== false) ||
jsFunctionsInjectedRef.current
) return;
jsFunctionsInjectedRef.current = true;

const sandbox = sandboxRef.current;
Expand All @@ -335,7 +342,7 @@ const OpenGenUIActivityRendererInner = React.memo(
} else {
pendingQueueRef.current.push(content.jsFunctions);
}
}, [content.jsFunctions]);
}, [content.jsFunctions, content.jsFunctionsComplete, content.generating]);

// Effect 3 — jsExpressions execution (arrival order, sequential await)
useEffect(() => {
Expand Down