fix(Vercel AI SDK): Streaming not working properly (#3386)

This commit is contained in:
Saket Aryan
2025-08-30 21:58:30 +05:30
committed by GitHub
parent 0b2aa36e98
commit 748620f29b
4 changed files with 15 additions and 76 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@mem0/vercel-ai-provider", "name": "@mem0/vercel-ai-provider",
"version": "2.0.1", "version": "2.0.2",
"description": "Vercel AI Provider for providing memory to LLMs", "description": "Vercel AI Provider for providing memory to LLMs",
"main": "./dist/index.js", "main": "./dist/index.js",
"module": "./dist/index.mjs", "module": "./dist/index.mjs",
@@ -2,17 +2,16 @@
import { import {
LanguageModelV2CallOptions, LanguageModelV2CallOptions,
LanguageModelV2Message, LanguageModelV2Message,
LanguageModelV2Source, LanguageModelV2Source
LanguageModelV2StreamPart
} from '@ai-sdk/provider'; } from '@ai-sdk/provider';
import { LanguageModelV2 } from '@ai-sdk/provider'; import { LanguageModelV2 } from '@ai-sdk/provider';
import { simulateStreamingMiddleware, wrapLanguageModel } from 'ai'; // streaming uses provider-native doStream; no middleware needed
import { Mem0ChatConfig, Mem0ChatModelId, Mem0ChatSettings, Mem0ConfigSettings, Mem0StreamResponse } from "./mem0-types"; import { Mem0ChatConfig, Mem0ChatModelId, Mem0ChatSettings, Mem0ConfigSettings, Mem0StreamResponse } from "./mem0-types";
import { Mem0ClassSelector } from "./mem0-provider-selector"; import { Mem0ClassSelector } from "./mem0-provider-selector";
import { Mem0ProviderSettings } from "./mem0-provider"; import { Mem0ProviderSettings } from "./mem0-provider";
import { addMemories, getMemories, retrieveMemories } from "./mem0-utils"; import { addMemories, getMemories } from "./mem0-utils";
const generateRandomId = () => { const generateRandomId = () => {
return Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15); return Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);
@@ -203,13 +202,8 @@ export class Mem0GenericLanguageModel implements LanguageModelV2 {
const baseModel = selector.createProvider(); const baseModel = selector.createProvider();
// Wrap the model with streaming middleware using the new Vercel AI SDK 5.0 approach // Use the provider's native streaming directly to avoid buffering
const model = wrapLanguageModel({ const streamResponse = await baseModel.doStream({
model: baseModel,
middleware: simulateStreamingMiddleware(),
});
const streamResponse = await model.doStream({
...options, ...options,
prompt: updatedPrompts, prompt: updatedPrompts,
}); });
@@ -219,65 +213,9 @@ export class Mem0GenericLanguageModel implements LanguageModelV2 {
return streamResponse; return streamResponse;
} }
// Create a new stream that includes memory sources // Return stream untouched for true streaming behavior
const originalStream = streamResponse.stream;
// Create a transform stream that adds memory sources at the beginning
const transformStream = new TransformStream({
start(controller) {
// Add source chunks for each memory at the beginning
try {
if (Array.isArray(memories) && memories?.length > 0) {
// Create a single source that contains all memories
controller.enqueue({
type: 'source',
title: "Mem0 Memories",
sourceType: "url",
id: "mem0-" + generateRandomId(),
url: "https://app.mem0.ai",
providerOptions: {
mem0: {
memories: memories,
memoriesText: memories?.map((memory: any) => memory?.memory).join("\n\n")
}
}
});
// Also add individual memory sources for more detailed information
memories?.forEach((memory: any) => {
controller.enqueue({
type: 'source',
title: memory?.title || "Memory",
sourceType: "url",
id: "mem0-memory-" + generateRandomId(),
url: "https://app.mem0.ai",
providerOptions: {
mem0: {
memory: memory,
memoryText: memory?.memory
}
}
});
});
}
} catch (error) {
console.error("Error adding memory sources:", error);
}
},
transform(chunk, controller) {
// Pass through all chunks from the original stream
controller.enqueue(chunk);
}
});
// Pipe the original stream through our transform stream
const enhancedStream = originalStream.pipeThrough(transformStream);
// Return a new stream response with our enhanced stream
return { return {
stream: enhancedStream, stream: streamResponse.stream,
request: streamResponse.request, request: streamResponse.request,
response: streamResponse.response, response: streamResponse.response,
}; };
+1
View File
@@ -29,6 +29,7 @@ export interface Mem0ConfigSettings {
host?: string; host?: string;
output_format?: string; output_format?: string;
filter_memories?: boolean; filter_memories?: boolean;
async_mode?: boolean;
} }
export interface Mem0ChatConfig extends Mem0ConfigSettings, Mem0ProviderSettings {} export interface Mem0ChatConfig extends Mem0ConfigSettings, Mem0ProviderSettings {}
+6 -6
View File
@@ -62,26 +62,26 @@ const convertToMem0Format = (messages: LanguageModelV2Prompt) => {
const searchInternalMemories = async (query: string, config?: Mem0ConfigSettings, top_k: number = 5) => { const searchInternalMemories = async (query: string, config?: Mem0ConfigSettings, top_k: number = 5) => {
try { try {
const filters: { AND: Array<{ [key: string]: string | undefined }> } = { const filters: { OR: Array<{ [key: string]: string | undefined }> } = {
AND: [], OR: [],
}; };
if (config?.user_id) { if (config?.user_id) {
filters.AND.push({ filters.OR.push({
user_id: config.user_id, user_id: config.user_id,
}); });
} }
if (config?.app_id) { if (config?.app_id) {
filters.AND.push({ filters.OR.push({
app_id: config.app_id, app_id: config.app_id,
}); });
} }
if (config?.agent_id) { if (config?.agent_id) {
filters.AND.push({ filters.OR.push({
agent_id: config.agent_id, agent_id: config.agent_id,
}); });
} }
if (config?.run_id) { if (config?.run_id) {
filters.AND.push({ filters.OR.push({
run_id: config.run_id, run_id: config.run_id,
}); });
} }