fix(Vercel AI SDK): Streaming not working properly (#3386)
This commit is contained in:
@@ -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,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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 {}
|
||||||
|
|||||||
@@ -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,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user