When working on #1362 I encountered a few compiler bugs with classes on closure variables. Tested and validated on the WDK compiler playground
Bug 1: Closer Variables not captured with class constructors
Input:
import { MockLanguageModelV3 } from 'ai/test';
import { xai as xaiProvider } from '@ai-sdk/xai';
export function mockModel(...args) {
return async () => {
'use step';
return new MockLanguageModelV3(...args);
};
}
export function xai(...args: Parameters<typeof xaiProvider>) {
return async () => {
'use step';
return xaiProvider(...args);
};
}
Notice that the args closure variable is not getting captured correctly in the workflow context or hydrated in the step context for the MockLanguageModelV3 but it is working for xaiProvider
Bug 2: Closure variables break steps from being reused as normal functions outside workflow
Sam input as above - notice that in both the functions in step output (i.e. even in the xai output), the ...args doesn't get propagated anymore correctly to the anonymous function that's extracted. This is fine when the step is being used from workflow context since we capture the the closure variables in workflow mode and rehydrate it inside the anonymous function - but this means that when using xai normal within the step, it wouldn't work since the args don't get captured and rehydrated inside the step.
The solution here is probably that in the step bundle itself, xai needs to wrap the replaced anonymous function with an AsyncLocalStorage that mimics the same way it would be called when used by a workflow - so that the step function continues to work as expected when executed from either, workflow or client code
Bug 3: Over-capturing of closure variables
I tried to sidestep the class constructor issue by wrapping it in a function like so:
import { MockLanguageModelV3 } from 'ai/test';
function mockProvider(...args) {
return new MockLanguageModelV3(...args);
}
export function mockModel(...args) {
return async () => {
'use step';
return mockProvider(...args);
};
}
you can see in the step and workflow outputs that args is now being captured and rehydrated.
However, also notice that mockProvider is being captured and hydrated as if it was a closure variable. It shouldn't be since it's actually available inside the step bundle output, and the anonymous step should actually just be using the local function instead of the closure variable (the current output would fail at runtime since it would try and serialize a function as a closure variable).
furthermore, we need to make sure that DCE removes the mockProvider (and recursively removes the import) from the workflow output. otherwise the workflow bundle will unnecessarily try and bundle the entire import (which is likely incompatible) even though it's not being used in the workflow itself and is only being used inside the step
When working on #1362 I encountered a few compiler bugs with classes on closure variables. Tested and validated on the WDK compiler playground
Bug 1: Closer Variables not captured with class constructors
Input:
Notice that the
argsclosure variable is not getting captured correctly in the workflow context or hydrated in the step context for theMockLanguageModelV3but it is working forxaiProviderBug 2: Closure variables break steps from being reused as normal functions outside workflow
Sam input as above - notice that in both the functions in step output (i.e. even in the
xaioutput), the ...args doesn't get propagated anymore correctly to the anonymous function that's extracted. This is fine when the step is being used from workflow context since we capture the the closure variables in workflow mode and rehydrate it inside the anonymous function - but this means that when usingxainormal within the step, it wouldn't work since the args don't get captured and rehydrated inside the step.The solution here is probably that in the step bundle itself,
xaineeds to wrap the replaced anonymous function with anAsyncLocalStoragethat mimics the same way it would be called when used by a workflow - so that the step function continues to work as expected when executed from either, workflow or client codeBug 3: Over-capturing of closure variables
I tried to sidestep the class constructor issue by wrapping it in a function like so:
you can see in the step and workflow outputs that args is now being captured and rehydrated.
However, also notice that
mockProvideris being captured and hydrated as if it was a closure variable. It shouldn't be since it's actually available inside the step bundle output, and the anonymous step should actually just be using the local function instead of the closure variable (the current output would fail at runtime since it would try and serialize a function as a closure variable).furthermore, we need to make sure that DCE removes the
mockProvider(and recursively removes the import) from the workflow output. otherwise the workflow bundle will unnecessarily try and bundle the entire import (which is likely incompatible) even though it's not being used in the workflow itself and is only being used inside the step