Integrate Morpheus Inference API with Vercel AI SDK
Learn how to integrate the Morpheus Inference API with Vercel’s AI SDK v5 to build AI-powered applications with decentralized AI inference. This guide covers streaming responses, tool calling, and handling Morpheus-specific implementation details.
The Morpheus Inference API provides AI inference through a decentralized compute marketplace. By integrating with Vercel’s AI SDK, you get access to powerful models like Qwen, Llama, and more while maintaining a familiar OpenAI-compatible API structure.
llama-3.3-70b:web - Meta’s Llama 3.3 with web search tool calling
llama-3.3-70b - Meta’s Llama 3.3 base model
qwen3-235b:web - Qwen 3 with web search tool calling
qwen3-235b - Qwen 3 base model
Model availability may vary based on provider availability in the Morpheus marketplace. The API automatically routes to the highest-rated provider for your selected model. The :web suffix indicates models optimized for web content and browsing tasks.
For interactive applications, use streamText to stream responses in real-time:
app/api/chat/route.ts
import { streamText } from 'ai';import { morpheus } from '@/lib/morpheus';export async function POST(req: Request) { const { prompt } = await req.json(); const result = streamText({ model: morpheus('llama-3.3-70b:web'), prompt, temperature: 0.7, }); return result.toDataStreamResponse();}
Use toDataStreamResponse() for easy integration with AI SDK UI components. For more control, use toTextStreamResponse() or iterate over result.textStream directly.
Here’s a complete example of a chat API route using Morpheus:
app/api/chat/route.ts
import { streamText, convertToModelMessages } from 'ai';import { morpheus } from '@/lib/morpheus';export async function POST(req: Request) { const { messages, model = 'llama-3.3-70b:web' } = await req.json(); const result = streamText({ model: morpheus(model), messages: convertToModelMessages(messages), temperature: 0.7, maxTokens: 2048, }); return result.toDataStreamResponse();}
The convertToModelMessages function transforms AI SDK UI messages into the format expected by language models. It handles user messages, assistant messages, and system prompts automatically.
The useChat hook automatically handles message state, streaming updates, and tool invocations. It provides a simple interface for building chat applications with minimal boilerplate.
Your API route receives the model parameter and passes it to Morpheus:
app/api/chat/route.ts
export async function POST(req: Request) { const { messages, model = 'llama-3.3-70b:web' } = await req.json(); const result = streamText({ model: morpheus(model), // Use the selected model messages: convertToModelMessages(messages), }); return result.toDataStreamResponse();}
The :web suffix indicates models optimized for web browsing and content generation. These models typically perform better for tasks involving current events or web-based information.
Tool calls fail with 'Expected function.name to be a string'
Cause: Morpheus may send tool call metadata and arguments in separate chunks during streaming.Solution: This issue has been resolved in recent versions of the Morpheus API. If you still encounter it, implement a custom stream transformer:
const customFetch = async (url: RequestInfo, init?: RequestInit) => { const response = await fetch(url, init); if (!response.body) return response; let toolCallBuffer: Record<string, { arguments: string }> = {}; const transformStream = new TransformStream({ transform(chunk, controller) { const text = new TextDecoder().decode(chunk); const lines = text.split('\n'); let modifiedChunk = ''; for (const line of lines) { if (!line.startsWith('data: ') || line === 'data: [DONE]') { modifiedChunk += line + '\n'; continue; } try { const data = JSON.parse(line.substring(6)); if (data.choices?.[0]?.delta?.tool_calls) { for (const toolCall of data.choices[0].delta.tool_calls) { const key = `${toolCall.index || 0}`; if (!toolCallBuffer[key]) { toolCallBuffer[key] = { arguments: '' }; } // Remove initial empty "{}" but keep metadata if (toolCall.function?.arguments === '{}' && toolCallBuffer[key].arguments === '') { delete toolCall.function.arguments; } else if (toolCall.function?.arguments) { toolCallBuffer[key].arguments += toolCall.function.arguments; } } } modifiedChunk += `data: ${JSON.stringify(data)}\n`; } catch { modifiedChunk += line + '\n'; } } controller.enqueue(new TextEncoder().encode(modifiedChunk)); }, }); return new Response(response.body.pipeThrough(transformStream), { headers: response.headers, });};// Use in createModel:const morpheus = createOpenAICompatible({ name: 'morpheus', apiKey: env.MORPHEUS_AI_API_KEY, baseURL: 'https://api.mor.org/api/v1', fetch: customFetch,});
Model calls tools for simple questions
Cause: The system prompt doesn’t provide clear guidance on when to use tools vs. direct answers.Solution: Add explicit instructions in your system prompt:
const result = streamText({ model: morpheus('llama-3.3-70b:web'), system: `You are a helpful AI assistant. Answer simple questions directly without using tools. Only use tools when you need to: - Access external data or APIs - Perform complex calculations - Execute actions that require tool capabilities`, messages, tools,});
Stream stops with 'finishReason: unknown'
Cause: Morpheus may be sending error JSON mixed into the SSE stream.Solution: Ensure your transformer filters out non-SSE error messages:
// Add this check in your transformer:if (line.startsWith('{') && line.includes('"error"')) { console.log('[MORPHEUS FIX] Filtering error JSON:', line); continue; // Skip this line}
Multi-parameter tool calls fail
Cause: Some Morpheus models struggle with complex tool calls requiring multiple parameters.Solution: Try a different model (llama-3.3-70b often performs better) or simplify your tools. Provide explicit examples in tool descriptions:
description: 'Generate a random number. Example: for "1 to 10", use min=1, max=10'
API returns 'invalid response format' errors
Cause: Morpheus occasionally sends malformed error responses that break SSE parsing.Solution: The stream transformer should filter these out. Add comprehensive logging to identify problematic chunks:
if (text.includes('tool_calls') || text.includes('finish_reason') || text.includes('error')) { console.log('[MORPHEUS FULL CHUNK]:', text);}
You’ve successfully integrated the Morpheus Inference API with Vercel’s AI SDK! Key takeaways:
OpenAI Compatibility: Morpheus works seamlessly with the AI SDK’s OpenAI-compatible provider
Streaming Support: Real-time streaming responses work out of the box with streamText
Tool Calling: Define tools with Zod schemas for type-safe, multi-step interactions
Model Selection: Choose between different Morpheus models (Llama, Qwen) based on your needs
The combination of Morpheus’s decentralized AI inference and the AI SDK’s powerful abstractions enables you to build sophisticated AI applications without infrastructure costs or vendor lock-in.