Conversation
This was a tough one. The naive fix, and my initial thought, was to just make the wrapper async/await the result. Turns out that broke nearly everything. isolated-vm deadlocks when called inside an async function which itself is being awaited from another async. I tried various "simple" fixes and kept breaking synchronous tool call tests. That mean a dual-path: - For IIFE, use .then() to avoid the extra nested await - With an explicit return, use the await wrapper ... and I have no idea how to solve this without literally parsing the code, which super sucks. This should be considered a temporary hack until we can get to the bottom of a Real Fix(TM).
There was a problem hiding this comment.
4 issues found across 3 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="typescript-library/src/code_mode_utcp_client.ts">
<violation number="1" location="typescript-library/src/code_mode_utcp_client.ts:262">
P2: Heuristic expression/statement detection can misclassify valid expressions, causing the statement wrapper to run and silently return undefined.</violation>
<violation number="2" location="typescript-library/src/code_mode_utcp_client.ts:287">
P2: Expression-mode wrapping breaks empty/whitespace input by generating invalid syntax (`var __userResult = ;`), regressing prior no-op behavior.</violation>
<violation number="3" location="typescript-library/src/code_mode_utcp_client.ts:319">
P1: `callToolChain` can hang indefinitely because it awaits `resultPromise` without a timeout after `script.run` timeout has already elapsed scope.</violation>
</file>
<file name="typescript-library/tests/code_mode_utcp_client.test.ts">
<violation number="1" location="typescript-library/tests/code_mode_utcp_client.test.ts:599">
P2: Regression test claims top-level await coverage but never uses `await`, so it does not validate the intended behavior.</violation>
</file>
Since this is your first cubic review, here's how it works:
- cubic automatically reviews your code and comments on bugs and improvements
- Teach cubic by replying to its comments. cubic learns from your replies and gets better over time
- Add one-off context when rerunning by tagging
@cubic-dev-aiwith guidance or docs links (includingllms.txt) - Ask questions if you need clarification on any suggestion
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
|
|
||
| // Run the script (starts the async IIFE); then await the callback-based promise. | ||
| await script.run(context, { timeout }); | ||
| const resultJson = await resultPromise; |
There was a problem hiding this comment.
P1: callToolChain can hang indefinitely because it awaits resultPromise without a timeout after script.run timeout has already elapsed scope.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At typescript-library/src/code_mode_utcp_client.ts, line 319:
<comment>`callToolChain` can hang indefinitely because it awaits `resultPromise` without a timeout after `script.run` timeout has already elapsed scope.</comment>
<file context>
@@ -204,25 +205,124 @@ ${interfaces.join('\n\n')}`;
+
+ // Run the script (starts the async IIFE); then await the callback-based promise.
+ await script.run(context, { timeout });
+ const resultJson = await resultPromise;
+
// Parse the result from JSON
</file context>
| if (ch === ')' || ch === ']' || ch === '}') { depth--; i++; continue; } | ||
| if (depth === 0) { | ||
| for (const kw of stmtKeywords) { | ||
| if (s.startsWith(kw, i)) return false; |
There was a problem hiding this comment.
P2: Heuristic expression/statement detection can misclassify valid expressions, causing the statement wrapper to run and silently return undefined.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At typescript-library/src/code_mode_utcp_client.ts, line 262:
<comment>Heuristic expression/statement detection can misclassify valid expressions, causing the statement wrapper to run and silently return undefined.</comment>
<file context>
@@ -204,25 +205,124 @@ ${interfaces.join('\n\n')}`;
+ if (ch === ')' || ch === ']' || ch === '}') { depth--; i++; continue; }
+ if (depth === 0) {
+ for (const kw of stmtKeywords) {
+ if (s.startsWith(kw, i)) return false;
+ }
+ }
</file context>
| wrappedCode = ` | ||
| (async function() { | ||
| try { | ||
| var __userResult = ${code}; |
There was a problem hiding this comment.
P2: Expression-mode wrapping breaks empty/whitespace input by generating invalid syntax (var __userResult = ;), regressing prior no-op behavior.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At typescript-library/src/code_mode_utcp_client.ts, line 287:
<comment>Expression-mode wrapping breaks empty/whitespace input by generating invalid syntax (`var __userResult = ;`), regressing prior no-op behavior.</comment>
<file context>
@@ -204,25 +205,124 @@ ${interfaces.join('\n\n')}`;
+ wrappedCode = `
+ (async function() {
+ try {
+ var __userResult = ${code};
+ if (__userResult && typeof __userResult.then === 'function') {
+ __userResult.then(function(v) {
</file context>
| var __userResult = ${code}; | |
| var __userResult = ${code.trim() ? code : 'undefined'}; |
| expect(result.operation).toBe('addition'); | ||
| }); | ||
|
|
||
| test('should support top-level await syntax (issue #33)', async () => { |
There was a problem hiding this comment.
P2: Regression test claims top-level await coverage but never uses await, so it does not validate the intended behavior.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At typescript-library/tests/code_mode_utcp_client.test.ts, line 599:
<comment>Regression test claims top-level await coverage but never uses `await`, so it does not validate the intended behavior.</comment>
<file context>
@@ -580,6 +580,48 @@ describe('CodeModeUtcpClient', () => {
+ expect(result.operation).toBe('addition');
+ });
+
+ test('should support top-level await syntax (issue #33)', async () => {
+ // Top-level await works because the wrapper is now an async function.
+ const code = `
</file context>
|
Yeah I was also having some issues with the whole async stuff and I'm not a TS expert. I'm not sure I understand why this is temporary fix only. Do you think it would be easier to just remove the result altogher and standardize it so it only supports returning via console.log? |
This was a tough one. The naive fix, and my initial thought, was to just make the wrapper async/await the result. Turns out that broke nearly everything.
isolated-vm deadlocks when called inside an async function which itself is being awaited from another async. I tried various "simple" fixes and kept breaking synchronous tool call tests.
That mean a dual-path:
This should be considered a temporary hack until we can get to the bottom of a Real Fix(TM).
Summary by cubic
Fixes #33 by correctly returning results from async IIFEs and top‑level await in
callToolChain, while keeping synchronous tool calls stable. Uses a dual-path wrapper to avoidisolated-vmdeadlocks and premature Promise serialization.ivm.Referencecallbacks, ensuring Promises settle before JSON serialization..then()expression wrapper or anasync/awaitstatement wrapper.awaiton tools is supported; added regression tests andjest.config.cjsusingts-jest.Written for commit 6ce36e4. Summary will update on new commits.