HyphenHyphen
HomeConsole
  • Get Started
  • Connect your coding agent
  • Build with Hyphen
  • Chat UIs & automation
  • Recipes
  • Guides
  • API Reference
OverviewLangChain & LangGraphLlamaIndexPydantic AICrewAIInstructorDSPyVercel AI SDKMastraOpenAI Node SDK
powered by Zudoku
Build with Hyphen

Vercel AI SDK

The Vercel AI SDK is the standard way to call models from TypeScript, React and Next.js. Use the openai-compatible provider, not the OpenAI one.

TerminalCode
npm install ai @ai-sdk/openai-compatible zod export HYPHEN_API_KEY="sk-..."

Setup guide: this config comes from the Vercel AI SDK's official documentation and has not been run end to end against the gateway. Corrections to support@hyphen-solution.com.

The provider

Code
import { createOpenAICompatible } from "@ai-sdk/openai-compatible"; const hyphen = createOpenAICompatible({ name: "hyphen", baseURL: "https://api.hyphen-solution.com/v1", apiKey: process.env.HYPHEN_API_KEY!, includeUsage: true, }); const model = hyphen("minimax-m3");

Do not reach for @ai-sdk/openai first

@ai-sdk/openai is built for OpenAI's own service, and since AI SDK 5 its default openai('model-id') call targets the Responses API. Hyphen serves Chat Completions at /v1/chat/completions, so the default call shape can miss.

If you must use that package, .chat() is mandatory:

Code
import { createOpenAI } from "@ai-sdk/openai"; const openai = createOpenAI({ baseURL: "https://api.hyphen-solution.com/v1", apiKey: process.env.HYPHEN_API_KEY!, }); const model = openai.chat("minimax-m3"); // .chat() is not optional here

createOpenAICompatible avoids the whole question. Use it.

Generate text

Code
import { generateText } from "ai"; const { text, usage } = await generateText({ model, prompt: "Explain a Bloom filter in three sentences.", maxOutputTokens: 2000, }); console.log(text); console.log(usage);

It is maxOutputTokens, not maxTokens

The rename landed in AI SDK 5 and stuck. Snippets older than that use maxTokens, which is silently ignored on current versions, so you get the default budget and occasionally an empty string.

Stream text

Code
import { streamText } from "ai"; const result = streamText({ model, prompt: "Invent a new holiday and describe its traditions.", maxOutputTokens: 2000, }); for await (const part of result.textStream) { process.stdout.write(part); }

Note streamText is not awaited. It returns immediately and you consume the stream.

Tool calling

Code
import { generateText, tool, isStepCount } from "ai"; import { z } from "zod"; const { text } = await generateText({ model, tools: { weather: tool({ description: "Get the weather in a location", inputSchema: z.object({ location: z.string().describe("The location to get the weather for"), }), execute: async ({ location }) => ({ location, temperature: 31, conditions: "thunderstorms", }), }), }, stopWhen: isStepCount(5), maxOutputTokens: 4000, prompt: "What is the weather in Kuala Lumpur?", }); console.log(text);

Two names that changed and will bite anyone copying older snippets:

  • inputSchema, not parameters, on tool().
  • isStepCount(n) in AI SDK 7. It was stepCountIs(n) in versions 5 and 6.

stopWhen is what turns a single call into an agent loop. Without it the SDK stops after the first tool call instead of feeding the result back.

Structured output

generateObject asks the provider for a JSON schema by default, which the M-series do not support. Pass output: 'tool', or use tool calling directly.

Code
import { generateObject } from "ai"; import { z } from "zod"; const { object } = await generateObject({ model, schema: z.object({ title: z.string(), severity: z.enum(["low", "medium", "high", "critical"]), component: z.string(), }), mode: "tool", maxOutputTokens: 4000, prompt: "The CSV exporter drops the last row on 2.4.1.", }); console.log(object);

If mode: "tool" is rejected by your version, fall back to the explicit generateText plus tool() pattern above, which is the stable one. See Structured JSON output.

In a Next.js route handler

Code
// app/api/chat/route.ts import { createOpenAICompatible } from "@ai-sdk/openai-compatible"; import { streamText, convertToModelMessages } from "ai"; const hyphen = createOpenAICompatible({ name: "hyphen", baseURL: "https://api.hyphen-solution.com/v1", apiKey: process.env.HYPHEN_API_KEY!, }); export async function POST(req: Request) { const { messages } = await req.json(); const result = streamText({ model: hyphen("minimax-m3"), messages: convertToModelMessages(messages), maxOutputTokens: 4000, }); return result.toUIMessageStreamResponse(); }

Keep HYPHEN_API_KEY server-side. Never expose it to the browser, and never prefix it with NEXT_PUBLIC_.

Gotchas

  • maxOutputTokens, not maxTokens. 2000 for chat, 4000 for tools. See Choosing a model.
  • inputSchema, not parameters.
  • isStepCount, not stepCountIs, on AI SDK 7.
  • @ai-sdk/openai defaults to the Responses API. Use createOpenAICompatible, or .chat().
  • No embedding models. embed and embedMany need another provider.
  • 429 means the monthly budget is spent. See Handling the 429 cap.

Related

  • OpenAI-compatible provider docs
  • Tool calling docs
  • Mastra: agents and workflows on top of this.
  • OpenAI Node SDK: no framework at all.
Last modified on July 28, 2026
DSPyMastra
On this page
  • The provider
  • Generate text
  • Stream text
  • Tool calling
  • Structured output
  • In a Next.js route handler
  • Gotchas
  • Related
TypeScript
TypeScript
TypeScript
TypeScript
TypeScript
TypeScript
TypeScript