fix: read env vars directly from localStorage to avoid React closure issue

The previous approach using useEnvVars() hook had a closure problem:
- envVars started as [] on first render
- buildEnvObject captured this empty array
- Even with function body, the transport memoized the old buildEnvObject

Solution: Read directly from localStorage inside the body function
- Bypasses React state entirely
- Gets fresh values on each request
- No closure issues

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Ajax Davis 2025-12-04 14:36:51 +10:00
parent c6b4456baf
commit d0110f990d

View file

@ -4,38 +4,51 @@ import { useChat as useAISDKChat } from '@ai-sdk/react';
import { DefaultChatTransport } from 'ai';
import { nanoid } from 'nanoid';
import { useState } from 'react';
import { useEnvVars } from '~/components/sidebar/SettingsSidebar';
/**
* Custom chat hook that wraps the official @ai-sdk/react useChat
* Handles SSE streaming with tool calls and UI message protocol
* Includes conversation ID tracking for dynamic tool loading
*/
const ENV_STORAGE_KEY = 'tpmjs-playground-env-vars';
export function useChat(): ReturnType<typeof useAISDKChat> & { conversationId: string } {
// Generate stable conversation ID for session
const [conversationId] = useState(() => nanoid());
// Get environment variables from settings sidebar
const envVars = useEnvVars();
// Convert env vars to object format (called fresh on each request)
const buildEnvObject = () =>
envVars.reduce(
(acc, { key, value }) => {
acc[key] = value;
return acc;
},
{} as Record<string, string>
);
const chat = useAISDKChat({
transport: new DefaultChatTransport({
api: '/api/chat',
// Use function body so it's evaluated on each request (not just once on mount)
body: () => ({
conversationId, // Pass conversation ID to API
env: buildEnvObject(), // Pass LATEST environment variables to API
}),
// Use function body that reads FRESH from localStorage on each request
// This avoids React closure issues where envVars would be stale
body: () => {
// Read env vars directly from localStorage (not from React state)
let envVars: Array<{ key: string; value: string }> = [];
try {
const stored = localStorage.getItem(ENV_STORAGE_KEY);
if (stored) {
envVars = JSON.parse(stored);
}
} catch (error) {
console.error('Failed to read env vars from localStorage:', error);
}
// Convert to object format
const env = envVars.reduce(
(acc, { key, value }) => {
acc[key] = value;
return acc;
},
{} as Record<string, string>
);
console.log('🔑 [useChat] Reading env vars from localStorage:', Object.keys(env));
return {
conversationId,
env,
};
},
}),
});