ISMS Copilot Docs

Use the API with the Vercel AI SDK

Use @ai-sdk/openai-compatible to call api.ismscopilot.com/v1 from generateText and streamText, with framework pins in providerOptions.

The AI SDK's OpenAI-compatible provider works with the ISMS Copilot API. You get generateText and streamText over the compliance aliases, with the modules you pin.

No tool calling, no structured output. The API is a text-only subset. Passing tools to generateText / streamText, or using generateObject / streamObject (which rely on JSON mode or tools), returns a 400. Run your agent loop on another model and call ISMS Copilot from inside one of its tools. See Errors.

Install

npm install ai @ai-sdk/openai-compatible
export ISMS_API_KEY=sk-isms-...

Create the provider

import { createOpenAICompatible } from "@ai-sdk/openai-compatible";

export const ismscopilot = createOpenAICompatible({
  name: "ismscopilot",
  baseURL: "https://api.ismscopilot.com/v1",
  apiKey: process.env.ISMS_API_KEY,
});

Keep this on the server (a route handler, a server action, a job). The key must never reach the browser.

First call with a pinned module

import { generateText } from "ai";
import { ismscopilot } from "./ismscopilot";

const { text, response } = await generateText({
  model: ismscopilot.chatModel("isms-fast"),
  prompt: "Which NIS 2 incident reports does an Italian managed service provider owe, and to whom?",
  providerOptions: {
    ismscopilot: { ismscopilot: { frameworks: ["NIS_2_IT"] } },
  },
});

console.log(text);
console.log("modules:", response.headers?.["x-isms-frameworks"]);

The outer ismscopilot key in providerOptions is the provider name you chose above; whatever is inside it is merged into the request body. The inner ismscopilot is the API's extension field. If you name the provider something else, change the outer key to match.

Streaming

import { streamText } from "ai";

const result = streamText({
  model: ismscopilot.chatModel("isms-thinking-eu"),
  system: "You are the assistant inside our compliance platform.",
  prompt: "Do we have to register under NIS 2, and by when?",
  providerOptions: {
    ismscopilot: { ismscopilot: { system: "none", frameworks: ["NIS_2_NL"] } },
  },
});

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

system: "none" drops the ISMS Copilot persona so your own system prompt stays in charge; the pinned module is still injected. See The system prompt, in full.

As a tool inside an agent on another model

import { generateText, tool } from "ai";
import { z } from "zod";

const askCompliance = tool({
  description: "Answer an ISO 27001:2022 or GDPR question with control and article ids.",
  inputSchema: z.object({ question: z.string() }),
  execute: async ({ question }) => {
    const { text } = await generateText({
      model: ismscopilot.chatModel("isms-fast"),
      prompt: question,
      providerOptions: { ismscopilot: { ismscopilot: { frameworks: ["ISO_27001", "GDPR"] } } },
    });
    return text;
  },
});

Hand askCompliance to an agent that runs on a model with tool calling. ISMS Copilot only receives the plain question.

Limits

  • No tools, no JSON mode or structured output, n is 1, no images. Text and streaming work.
  • Thinking aliases raise maxOutputTokens below 1024 to 1024.
  • Checked with ai 7.0.155 and @ai-sdk/openai-compatible 3.0.80 on 2026-10-28: the request body carries ismscopilot at the top level and the x-isms-frameworks header is readable on response.headers.

On this page