- 
                Notifications
    You must be signed in to change notification settings 
- Fork 5.9k
chore: Context in message metadata #1181
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
chore: Context in message metadata #1181
Conversation
| @FranciscoMoretti is attempting to deploy a commit to the Vercel Team on Vercel. A member of the Team first needs to authorize it. | 
| createdAt: new Date(), | ||
| attachments: [], | ||
| chatId: id, | ||
| lastContext: null, | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The lastContext field is hardcoded to null when saving messages, but the client receives usage data through messageMetadata, creating a disconnect between stored and displayed data.
View Details
📝 Patch Details
diff --git a/app/(chat)/api/chat/route.ts b/app/(chat)/api/chat/route.ts
index 05df486..fad9af8 100644
--- a/app/(chat)/api/chat/route.ts
+++ b/app/(chat)/api/chat/route.ts
@@ -150,6 +150,9 @@ export async function POST(request: Request) {
     const streamId = generateUUID();
     await createStreamId({ streamId, chatId: id });
 
+    // Store usage data to be captured from streamText
+    let totalUsage: any = null;
+
     const stream = createUIMessageStream({
       execute: ({ writer: dataStream }) => {
         const result = streamText({
@@ -180,6 +183,10 @@ export async function POST(request: Request) {
             isEnabled: isProductionEnvironment,
             functionId: 'stream-text',
           },
+          onFinish: ({ totalUsage: usage }) => {
+            // Capture usage data from streamText for later storage
+            totalUsage = usage;
+          },
         });
 
         result.consumeStream();
@@ -210,7 +217,7 @@ export async function POST(request: Request) {
             createdAt: new Date(),
             attachments: [],
             chatId: id,
-            lastContext: null,
+            lastContext: message.role === 'assistant' ? totalUsage : null,
           })),
         });
       },
Analysis
Usage Data Loss Bug in Chat API
Summary
The chat API is losing usage data (token counts) when messages are persisted to the database, creating a disconnect between what users see during active sessions and what's available after page refreshes.
Technical Details
The Problem
In app/(chat)/api/chat/route.ts, the onFinish callback of createUIMessageStream hardcodes lastContext: null when saving messages to the database (line 213), despite having access to usage data from the underlying streamText operation.
onFinish: async ({ messages }) => {
  await saveMessages({
    messages: messages.map((message) => ({
      id: message.id,
      role: message.role,
      parts: message.parts,
      createdAt: new Date(),
      attachments: [],
      chatId: id,
      lastContext: null, // ❌ Hardcoded null loses usage data
    })),
  });
},Data Flow Analysis
- During streaming: The messageMetadatafunction (lines 189-198) correctly sends usage data to clients viapart.totalUsage
- During persistence: lastContextis hardcoded tonull, losing usage information
- On reload: convertToUIMessagesmapsmessage.lastContexttometadata.usage, resulting inundefinedinstead of actual usage data
Database Schema Evidence
The database schema confirms lastContext is designed to store usage data:
lastContext: jsonb('lastContext').$type<LanguageModelV2Usage | null>()API Documentation Verification
According to the AI SDK documentation, streamText's onFinish callback provides a totalUsage parameter containing token usage information. The current implementation fails to capture this data.
Impact
- User Experience: Usage information disappears after page refresh/reload
- Analytics: Lost token usage data prevents accurate billing and usage tracking
- Debugging: Difficulty troubleshooting expensive API calls without persistent usage data
Solution Implemented
The fix captures usage data from streamText's onFinish callback and stores it in the database:
- Added a variable to capture totalUsagefrom thestreamTextresult
- Used onFinishcallback onstreamTextto capture the usage data
- Modified the message persistence to store usage data for assistant messages
// Capture usage data from streamText
onFinish: ({ totalUsage: usage }) => {
  totalUsage = usage;
},
// Store usage data for assistant messages
lastContext: message.role === 'assistant' ? totalUsage : null,Verification
- ✅ TypeScript compilation passes
- ✅ Next.js build succeeds
- ✅ Code follows existing patterns in the codebase
- ✅ Database schema supports the fix
- ✅ API documentation confirms usage data availability
This fix ensures usage data persists across sessions while maintaining backward compatibility with existing null values for user messages.
| The latest updates on your projects. Learn more about Vercel for GitHub. 
 | 
| @dancer review pls | 
Moving context to message metadata
Message metadata is a better fit:
NOTE: Haven't been able to verify these changes because I'm getting a few db errors. I think I need to setup this project again.