-
Notifications
You must be signed in to change notification settings - Fork 184
Open
Description
Summary
AsyncLocalStorage.getStore() returns undefined inside AI SDK tool execute() callbacks, even though the context is correctly set earlier in the same step.
Regression
| Version | Result |
|---|---|
| beta.39 | ✅ Works |
| beta.40 | ❌ Broken |
Reproduction
// lib/context.ts
import { AsyncLocalStorage } from 'async_hooks';
export const requestContext = new AsyncLocalStorage<{ userId: string }>();
// lib/tool.ts
import { tool } from 'ai';
import { z } from 'zod';
import { requestContext } from './context';
export const myTool = tool({
description: 'Test tool',
parameters: z.object({ message: z.string() }),
execute: async ({ message }) => {
const store = requestContext.getStore();
console.log('[Tool] store:', store); // ❌ undefined in beta.40+
return { success: !!store, store, message };
},
});
// workflows/test.ts
export async function testWorkflow() {
'use workflow';
return await testStep();
}
async function testStep() {
'use step';
const { streamText } = await import('ai');
const { anthropic } = await import('@ai-sdk/anthropic');
const { requestContext } = await import('@/lib/context');
const { myTool } = await import('@/lib/tool');
return requestContext.run({ userId: 'xyz' }, async () => {
console.log('[Step] Before streamText:', requestContext.getStore()); // ✅ { userId: 'xyz' }
const result = streamText({
model: anthropic('claude-sonnet-4-20250514'),
messages: [{ role: 'user', content: 'Call myTool with message "test"' }],
tools: { myTool },
toolChoice: 'required',
});
let toolResult = null;
for await (const chunk of result.fullStream) {
if (chunk.type === 'tool-result') toolResult = chunk.result;
}
return { storeBeforeStreamText: requestContext.getStore(), toolResult };
});
}
// app/api/test/route.ts
import { NextResponse } from 'next/server';
import { start } from 'workflow/api';
import { testWorkflow } from '@/workflows/test';
export async function GET() {
const run = await start(testWorkflow, []);
return NextResponse.json(await run.returnValue);
}beta.39 result:
{"storeBeforeStreamText":{"userId":"xyz"},"toolResult":{"success":true,"store":{"userId":"xyz"},"message":"test"}}beta.40 result:
{"storeBeforeStreamText":{"userId":"xyz"},"toolResult":{"success":false,"message":"test"}}Root Cause
The bundler creates duplicate module instances. The step and tool end up using different AsyncLocalStorage instances.
Environment
- workflow: 4.0.1-beta.40+
- Node.js: 24
- Next.js: 16.0.10
- ai: 6.0.45
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels