Cogitator
Integrations

Vercel AI SDK

Bidirectional bridge between Cogitator and the Vercel AI SDK 4, 5, 6 and 7 -- use Cogitator agents as AI SDK models or use AI SDK models inside Cogitator.

Overview

The @cogitator-ai/ai-sdk package connects the two ecosystems in both directions:

  • Cogitator as model -- expose Cogitator agents as AI SDK language models, so you can use them with generateText, streamText and structured output.
  • AI SDK as backend -- wrap any AI SDK model as a Cogitator LLMBackend.
  • Tools -- convert tools in both directions.
pnpm add @cogitator-ai/ai-sdk @cogitator-ai/core ai

Supported AI SDK Versions

ai is a peer dependency: ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0.

AI SDKAccepted model specsDefault cogitatorModel() specfromAISDK() input
ai@4v1v1LanguageModelV1
ai@5v2v2LanguageModelV2
ai@6v2, v3v3LanguageModelV3
ai@7v2, v3, v4v4LanguageModelV4

Specification Auto-Detection

Without a specificationVersion option, the model spec follows the installed ai package:

  • At runtime ai/package.json is resolved from process.cwd(), then from @cogitator-ai/ai-sdk itself (ESM-only installs that hide package.json behind exports are handled). The result is cached. If ai cannot be resolved, 'v2' is used -- ai@5, ai@6 and ai@7 accept it.
  • In TypeScript the default return type is derived from the installed ai package's LanguageModel type with the same mapping, so code written for any major type-checks unchanged.

Pass specificationVersion: 'v1' | 'v2' | 'v3' | 'v4' to override it, e.g. when several ai majors are installed. AI SDK 6 and 7 accept v2 models only in a compatibility mode that logs a warning on every call, which the detected v3 / v4 defaults avoid.

Cogitator as AI SDK Model

cogitatorModel

Pass a Cogitator instance and an Agent to get an AI SDK language model:

import { generateText, streamText } from 'ai';
import { Cogitator, Agent } from '@cogitator-ai/core';
import { cogitatorModel } from '@cogitator-ai/ai-sdk';

const cog = new Cogitator({
  llm: {
    defaultProvider: 'openai',
    providers: { openai: { apiKey: process.env.OPENAI_API_KEY! } },
  },
});

const agent = new Agent({
  name: 'researcher',
  model: 'openai/gpt-6.1-sol',
  instructions: 'You are an expert researcher. Always cite sources.',
  tools: [webSearch, readUrl],
});

const { text } = await generateText({
  model: cogitatorModel(cog, agent, { temperature: 0.7 }),
  prompt: 'What are the latest advances in quantum computing?',
});

const result = streamText({
  model: cogitatorModel(cog, agent, { specificationVersion: 'v2' }),
  prompt: 'Summarize them in three bullet points',
});

for await (const chunk of result.textStream) {
  process.stdout.write(chunk);
}

The first model uses the auto-detected spec; the second overrides it. On ai@4 the default is a LanguageModelV1.

How an Agent Behaves as a Model

  • One model call runs the whole agent loop, including the agent's own tool calls, and finishes with finishReason: 'stop'.
  • The agent's tool calls are reported as provider-executed tool calls with results, so the AI SDK never runs them a second time:
    • v3 / v4 models always report them in toolCalls / toolResults and as tool-call / tool-result stream parts.
    • v2 models report them only for tools that you also pass in tools, because ai@5 cannot handle provider-executed calls of undeclared tools.
    • All models list them in providerMetadata.cogitator.toolCalls next to runId, threadId, agentId, model, cost and duration.
  • The text of user and assistant messages becomes the agent input; multi-turn prompts are sent as a User: / Assistant: transcript. System messages, images and files are not forwarded (the agent instructions are the system prompt) and produce a warning.
  • temperature, topP, maxOutputTokens (maxTokens on ai@4) and stopSequences override the agent configuration for that call. abortSignal and cancelling a stream abort the run.
  • The reasoning option of v4 models overrides the effort of the agent's reasoning. With reasoning: { summary: true } the agent's summary comes back as reasoning content and reasoning-* stream parts.
  • Structured output (Output.object, generateObject, ai@4 object modes) switches the agent to JSON mode and adds the JSON schema to the input.
  • AI SDK tools that the agent does not own cannot be called by the agent and produce a warning.
import { Output, generateText } from 'ai';
import { z } from 'zod';

const { output } = await generateText({
  model: cogitatorModel(cog, agent),
  output: Output.object({ schema: z.object({ title: z.string(), year: z.number() }) }),
  prompt: 'Name a landmark quantum computing paper',
});

createCogitatorProvider

When you have multiple agents, createCogitatorProvider resolves them by name:

import { generateText } from 'ai';
import { createCogitatorProvider } from '@cogitator-ai/ai-sdk';

const provider = createCogitatorProvider(cog, {
  agents: [researcher, summarizer],
  specificationVersion: 'v2',
});

const { text } = await generateText({
  model: provider('researcher', { temperature: 0.5 }),
  prompt: 'Explain CRISPR gene editing',
});

const { text: summary } = await generateText({
  model: provider.languageModel('summarizer', { maxTokens: 2048 }),
  prompt: text,
});

agents may be an array (keyed by agent name), a Map or a record. An unknown name throws with the list of available agents.

Options

OptionTypeDescription
temperaturenumberDefault temperature for the agent
maxTokensnumberDefault max output tokens
topPnumberDefault top-p sampling
specificationVersion'v1' | 'v2' | 'v3' | 'v4'Model spec to implement (cogitatorModel and createCogitatorProvider config), detected from the installed ai package when omitted

AI SDK Models in Cogitator

fromAISDK

Wrap any AI SDK language model -- LanguageModelV1 (ai@4 providers) through LanguageModelV4 (ai@7 providers) -- as a Cogitator LLMBackend:

import { google } from '@ai-sdk/google';
import { fromAISDK } from '@cogitator-ai/ai-sdk';

const backend = fromAISDK(google('gemini-3.5-flash-lite'));

const response = await backend.chat({
  model: 'gemini-3.5-flash-lite',
  messages: [
    { role: 'system', content: 'You are a creative writing assistant.' },
    { role: 'user', content: 'Write a haiku about TypeScript' },
  ],
});

for await (const chunk of backend.chatStream({
  model: 'gemini-3.5-flash-lite',
  messages: [{ role: 'user', content: 'Tell me a story' }],
})) {
  process.stdout.write(chunk.delta.content ?? '');
}

The backend branches on the model's specificationVersion and converts:

  • messages -- text, images (URL or base64), assistant tool calls and tool results as structured prompt parts
  • tools, toolChoice, responseFormat, temperature, topP, maxTokens, stop and the abort signal
  • reasoning.effort -- the reasoning call option of v4 models (max becomes xhigh); for older specifications, set reasoning on the AI SDK provider model
  • responses -- text, reasoning (ChatResponse.reasoning, delta.reasoning), client tool calls (provider-executed calls are skipped), finish reasons and usage including cached, cache-write and reasoning tokens
  • Gemini thought signatures on tool calls, which are replayed on the next turn

Running Agents on an AI SDK Model

To run Cogitator agents on an AI SDK model, register the backend under a name in llm.backends and point agents at it with name/model:

import { Agent, Cogitator } from '@cogitator-ai/core';

const cog = new Cogitator({
  llm: { backends: { gemini: fromAISDK(google('gemini-3.5-flash-lite')) } },
});

const agent = new Agent({
  name: 'writer',
  model: 'gemini/gemini-3.5-flash-lite',
  instructions: 'You write short poems.',
});

const result = await cog.run(agent, { input: 'A haiku about types' });

Tools, memory, streaming and every other run feature work as with built-in providers. The wrapped model is used whatever model name the request carries; cost is reported only for models the price registry knows.

Tool Conversion

Tools can be converted between the two systems, so you never need to rewrite tool definitions.

Cogitator to AI SDK

import { generateText, stepCountIs } from 'ai';
import { openai } from '@ai-sdk/openai';
import { toAISDKTool, convertToolsToAISDK } from '@cogitator-ai/ai-sdk';

const aiTool = toAISDKTool(calculator);

const { text } = await generateText({
  model: openai('gpt-6.1-sol'),
  tools: convertToolsToAISDK([calculator, webSearch]),
  stopWhen: stepCountIs(5),
  prompt: 'What is 42 * 17?',
});

Converted tools work with the tools option of every AI SDK major:

  • inputSchema (ai@5 – ai@7) is the Cogitator tool's zod schema.
  • parameters (ai@4) is an AI SDK Schema with draft-07 JSON Schema and validation.
  • execute(input, options) builds a Cogitator ToolContext: toolCallId becomes runId, abortSignal becomes signal, and the string fields agentId, runId, threadId, userId, channelType and channelId of the AI SDK tool context (context on ai@7, experimental_context on ai@5 / ai@6) are copied.

AI SDK to Cogitator

import { tool } from 'ai';
import { z } from 'zod';
import { fromAISDKTool, convertToolsFromAISDK } from '@cogitator-ai/ai-sdk';

const weatherTool = tool({
  description: 'Get current weather for a location',
  inputSchema: z.object({
    location: z.string().describe('City name'),
    unit: z.enum(['celsius', 'fahrenheit']).optional(),
  }),
  execute: async ({ location, unit }) => {
    return { temperature: 22, unit: unit ?? 'celsius', location };
  },
});

const cogWeather = fromAISDKTool(weatherTool, 'get_weather');

const agent = new Agent({
  name: 'weather-bot',
  model: 'openai/gpt-6.1-sol',
  instructions: 'Help users check the weather.',
  tools: [cogWeather],
});

fromAISDKTool reads inputSchema (ai@5+) or parameters (ai@4) and accepts zod 4 schemas, Standard JSON Schemas, jsonSchema() / zodSchema() from any AI SDK major and plain JSON Schema objects. Non-zod schemas are converted to JSON Schema and validated before execute runs. It resolves ai@7 dynamic descriptions, returns the last value of streaming (async function*) tools, and passes the Cogitator context as context / experimental_context. Wrap zod 3 schemas with zodSchema() from ai.

Convert multiple tools at once with convertToolsFromAISDK:

const cogTools = convertToolsFromAISDK({ weather: weatherTool, search: searchTool });

Full Example: Next.js Route with AI SDK 7

app/api/chat/route.ts
import { convertToModelMessages, streamText, type UIMessage } from 'ai';
import { Cogitator, Agent, tool } from '@cogitator-ai/core';
import { cogitatorModel } from '@cogitator-ai/ai-sdk';
import { z } from 'zod';

const cog = new Cogitator({
  llm: {
    defaultProvider: 'anthropic',
    providers: { anthropic: { apiKey: process.env.ANTHROPIC_API_KEY! } },
  },
});

const agent = new Agent({
  name: 'assistant',
  model: 'anthropic/claude-sonnet-5-5',
  instructions: 'You are a helpful coding assistant.',
  tools: [
    tool({
      name: 'lookup_docs',
      description: 'Look up a documentation page',
      parameters: z.object({ topic: z.string() }),
      execute: async ({ topic }) => ({ url: `https://docs.example.com/${topic}` }),
    }),
  ],
});

const model = cogitatorModel(cog, agent);

export async function POST(req: Request) {
  const { messages }: { messages: UIMessage[] } = await req.json();

  const result = streamText({
    model,
    messages: await convertToModelMessages(messages),
  });

  return result.toUIMessageStreamResponse();
}

The agent executes lookup_docs itself; the UI stream shows the call and its result as provider-executed tool parts.

On this page