QuiverAI

Learn how to use QuiverAI models with the AI SDK.

QuiverAI provides Arrow language models that can reason about and create SVG documents, plus native SVG generation, vectorization, editing, and animation endpoints. The AI SDK provider exposes Arrow 2 through generateText and streamText and exposes image operations through generateImage.

Setup

The QuiverAI provider is available via the @ai-sdk/quiverai module. You can install it with

$ pnpm add @ai-sdk/quiverai

Provider Instance

You can import the default provider instance quiverai from @ai-sdk/quiverai:

import { quiverai } from '@ai-sdk/quiverai';

If you need a customized setup, you can import createQuiverAI and create a provider instance with your settings:

import { createQuiverAI } from '@ai-sdk/quiverai';

const quiverai = createQuiverAI({
  apiKey: 'your-api-key', // optional, defaults to QUIVERAI_API_KEY environment variable
  baseURL: 'custom-url', // optional, defaults to QUIVERAI_BASE_URL or https://api.quiver.ai/v1
  headers: {
    /* custom headers */
  }, // optional
});

You can use the following optional settings to customize the QuiverAI provider instance:

  • baseURL string

    Use a different URL prefix for API calls, e.g. to use proxy servers. The default prefix is https://api.quiver.ai/v1. It also reads QUIVERAI_BASE_URL from the environment.

  • apiKey string

    API key that is sent as a Bearer token in the Authorization header. It defaults to the QUIVERAI_API_KEY environment variable.

  • headers Record<string,string>

    Custom headers to include in the requests.

  • fetch (input: RequestInfo, init?: RequestInit) => Promise<Response>

    Custom fetch implementation. You can use it as a middleware to intercept requests, or to provide a custom fetch implementation for e.g. testing.

Language Models

Create an Arrow language model by calling the provider or using .languageModel():

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

const { text } = await generateText({
  model: quiverai('arrow-2'),
  prompt: 'Design a simple compass icon and explain the visual choices.',
});

console.log(text);

The language-model factory supports arrow-2 and arrow-2-telos through QuiverAI's stateless POST /v1/responses endpoint.

Reasoning Options

Configure QuiverAI reasoning through providerOptions.quiverai:

import { quiverai, type QuiverAILanguageModelOptions } from '@ai-sdk/quiverai';
import { generateText } from 'ai';

await generateText({
  model: quiverai('arrow-2-telos'),
  prompt: 'Create a precise technical SVG diagram.',
  providerOptions: {
    quiverai: {
      reasoningEffort: 'xhigh',
      reasoningSummary: 'auto',
    } satisfies QuiverAILanguageModelOptions,
  },
});
  • reasoningEffort 'low' | 'medium' | 'high' | 'xhigh'
  • reasoningSummary 'auto'

The provider does not request encrypted reasoning. During tool loops it replays the full conversation, matching tool calls and results, and opaque reasoning item IDs in order without resending private reasoning text or encrypted reasoning state.

Caller-Executed Tools

Standard AI SDK tools are sent as Responses API function tools and execute in your application. Use a bounded loop because each step performs another model request:

import { quiverai } from '@ai-sdk/quiverai';
import { generateText, isStepCount, tool } from 'ai';
import { z } from 'zod';

const result = await generateText({
  model: quiverai('arrow-2'),
  prompt: 'Create an SVG compass and stage it as compass.svg.',
  tools: {
    write_file: tool({
      description: 'Stage an SVG file in the calling application.',
      inputSchema: z.object({
        path: z.string(),
        content: z.string(),
      }),
      execute: async ({ path, content }) => {
        // Validate and restrict paths before writing model-generated content.
        return { path, staged: content.startsWith('<svg') };
      },
    }),
  },
  stopWhen: isStepCount(4),
});

QuiverAI custom tools return raw strings and are also executed by the caller:

const result = await generateText({
  model: quiverai('arrow-2'),
  prompt: 'Return a minimal SVG document.',
  tools: {
    write_svg: quiverai.tools.customTool({
      description: 'Return SVG source.',
      format: { type: 'text' },
      execute: async svg => ({ accepted: svg.startsWith('<svg') }),
    }),
  },
  stopWhen: isStepCount(3),
});

Hosted tools, including legacy quiver:* tools, are not supported.

Responses API Limitations

  • Requests are stateless. The provider does not enable response storage or response-ID continuation.
  • QuiverAI currently documents text response format for this endpoint. Structured-output settings are omitted and reported in warnings.
  • Streaming tool calls are assembled completely before application execution.
  • Abort signals, custom headers, and custom fetch implementations are forwarded to the Responses request.

Language Model Usage

result.usage and streaming finish events include input, cache-read, cache-write, text-output, and reasoning token counts when returned by QuiverAI.

Image Models

You can create QuiverAI image models using the .image() factory method. For more on image generation with the AI SDK see generateImage().

Basic Usage

import { quiverai } from '@ai-sdk/quiverai';
import { generateImage } from 'ai';
import fs from 'fs';

const { image } = await generateImage({
  model: quiverai.image('arrow-2'),
  prompt: 'A logo for the next AI Design startup',
});

const filename = `image-${Date.now()}.svg`;
fs.writeFileSync(filename, image.uint8Array);
console.log(`Saved SVG to ${filename}`);

QuiverAI returns SVG documents. The generated SVG bytes are available through result.image.uint8Array (or result.images when generating multiple).

Model Capabilities

QuiverAI supports the following Arrow models:

ModelDescription
arrow-2Arrow 2 balances SVG generation quality and speed. Supports SVG editing when enabled for the API key. Uses token-based billing.
arrow-2-telosHigher-fidelity Arrow 2 variant for complex designs. Supports SVG editing when enabled for the API key. Uses token-based billing.
arrow-1Base text-to-SVG model. Accepts up to 4 reference images.
arrow-1.1Improved text-to-SVG model. Accepts up to 4 reference images.
arrow-1.1-maxHigher quality variant with extended context. Accepts up to 16 reference images.

All models in this table advertise supportsFileInputs: true and supportsMaskInputs: false. Other model IDs leave both capabilities unknown. File-input support includes reference images for generation; SVG editing and animation still require the corresponding providerOptions.quiverai.operation, supported input formats, and access to that operation for your API key.

Provider Options

You can fine-tune the request using providerOptions.quiverai:

import { quiverai, type QuiverAIImageModelOptions } from '@ai-sdk/quiverai';
import { generateImage } from 'ai';

await generateImage({
  model: quiverai.image('arrow-2'),
  prompt: 'A geometric unicorn icon',
  providerOptions: {
    quiverai: {
      instructions: 'Use a flat monochrome style with clean geometry.',
      reasoningEffort: 'high',
      attributes: {
        viewBox: { minX: 0, minY: 0, width: 100, height: 100 },
      },
      maxOutputTokens: 4096,
    } satisfies QuiverAIImageModelOptions,
  },
});

Supported options:

  • operation 'generate' | 'vectorize' | 'edit' | 'animate'

    Choose between text-to-SVG generation (generate, default), image-to-SVG vectorization (vectorize), SVG editing (edit), and SVG animation (animate).

  • instructions string

    Extra style guidance for prompt-based generation. This option is not used as the SVG edit instruction; use prompt.text for editing.

  • reasoningEffort 'low' | 'medium' | 'high' | 'xhigh'

    Reasoning effort for generation, vectorization, or editing. When omitted, QuiverAI uses its default.

  • attributes object

    Requested SVG root attributes. Supports viewBox with numeric minX, minY, and positive width and height. This is separate from the unsupported size and aspectRatio options.

  • temperature number (0-2)

    Sampling temperature.

  • topP number (0-1)

    Nucleus sampling top-p value.

  • presencePenalty number (-2 to 2)

    Presence penalty.

  • maxOutputTokens number

    Maximum number of output tokens. Arrow 2 and Arrow 2 Telos accept 1-65536. The provider retains its legacy validation bound of 131072 for other model IDs; the API may enforce a lower model-specific limit.

  • referenceImages Array<{ url: string } | { base64: string }>

    Up to four optional reference images for SVG editing. URL references must use HTTP or HTTPS. Base64 references must decode to PNG, JPEG, WebP, GIF, or SVG data. Use prepareQuiverAIImageReference to convert binary, data URL, or URL inputs into this JSON-safe provider option shape.

  • maxReviewSteps number (0-5)

    Maximum number of edit review and redo steps after the initial edit.

  • orchestratorMaxOutputTokens number (1-65536)

    Optional provider orchestrator token budget for SVG editing.

  • shallowMaxOutputTokens number (1-65536)

    Optional provider shallow edit token budget for SVG editing.

  • autoCrop boolean

    When vectorizing, automatically crop the input image. Only used with operation: 'vectorize'.

  • targetSize number (128-4096)

    When vectorizing, target canvas size in pixels. Only used with operation: 'vectorize'.

Reference Images

Pass reference images through prompt.images:

await generateImage({
  model: quiverai.image('arrow-2'),
  prompt: {
    text: 'A geometric unicorn icon',
    images: ['https://example.com/reference-1.png'],
  },
});

arrow-1 and arrow-1.1 accept up to 4 reference images. arrow-1.1-max accepts up to 16. For Arrow 2 and other model IDs, the provider allows the endpoint maximum of 16 references and lets the API enforce any lower model-specific limit.

Vectorizing a Raster Image

Set operation to vectorize and pass a single image in prompt.images:

import { quiverai, type QuiverAIImageModelOptions } from '@ai-sdk/quiverai';
import { generateImage } from 'ai';
import fs from 'fs';

const { image } = await generateImage({
  model: quiverai.image('arrow-2'),
  prompt: {
    images: [fs.readFileSync('./logo.png')],
  },
  providerOptions: {
    quiverai: {
      operation: 'vectorize',
      autoCrop: true,
      targetSize: 1024,
    } satisfies QuiverAIImageModelOptions,
  },
});

fs.writeFileSync('logo.svg', image.uint8Array);

Vectorization returns one SVG per API request. To request multiple vectorizations with n, also set maxImagesPerCall: 1 so generateImage splits them into separate calls.

Editing an SVG

Set operation to edit, put exactly one source SVG in prompt.images, and provide the edit instruction in prompt.text:

import {
  prepareQuiverAIImageReference,
  quiverai,
  type QuiverAIImageModelOptions,
} from '@ai-sdk/quiverai';
import { generateImage } from 'ai';
import fs from 'node:fs/promises';

const { image } = await generateImage({
  model: quiverai.image('arrow-2'),
  prompt: {
    text: 'Make the logo blue and simplify the star points.',
    images: [await fs.readFile('./logo.svg')],
  },
  providerOptions: {
    quiverai: {
      operation: 'edit',
      referenceImages: [
        prepareQuiverAIImageReference(
          await fs.readFile('./blue-reference.png'),
        ),
        { url: 'https://example.com/second-reference.png' },
      ],
      maxReviewSteps: 2,
      reasoningEffort: 'medium',
      maxOutputTokens: 4096,
      orchestratorMaxOutputTokens: 4096,
      shallowMaxOutputTokens: 2048,
      temperature: 0.4,
    } satisfies QuiverAIImageModelOptions,
  },
});

await fs.writeFile('./edited-logo.svg', image.uint8Array);

The source SVG can be an HTTP/HTTPS URL, binary data such as a Buffer or Uint8Array, a base64 string, or an SVG data URL. Binary and base64 sources are validated as complete UTF-8 SVG documents and sent to QuiverAI as base64 SVG sources. Remote source URLs are fetched by QuiverAI and must resolve to an SVG.

Edit reference images are separate from the source SVG. Put them in providerOptions.quiverai.referenceImages, not prompt.images. Direct provider-option values use { url } or { base64 }; prepareQuiverAIImageReference converts an HTTP/HTTPS URL, URL, Uint8Array, ArrayBuffer, base64 string, or supported image data URL to that JSON-safe shape.

SVG editing has these validation constraints:

  • The model must be arrow-2 or arrow-2-telos, and the API key's live model catalog must include the svg_edit operation.
  • prompt.images must contain exactly one source SVG.
  • prompt.text is required, must not be blank, and must contain at most 4000 characters.
  • Binary source SVGs must be complete UTF-8 SVG documents no larger than 200000 bytes.
  • At most four reference images are accepted. Inline references can contain up to 12582912 decoded bytes.
  • Editing returns exactly one SVG per API request. To request multiple edits with n, set maxImagesPerCall: 1 so generateImage splits them into separate calls.
  • Masks and generation/vectorization-only provider options are rejected for edits.
  • Edit-only provider options are rejected for generation, vectorization, and animation.

The edited SVG is returned as bytes in result.image.uint8Array.

Animating an SVG

Arrow 2 and Arrow 2 Telos can animate an existing SVG. Set operation to animate and pass exactly one source SVG in prompt.images. The text instruction is optional; omit text to let QuiverAI choose an animation.

import { quiverai, type QuiverAIImageModelOptions } from '@ai-sdk/quiverai';
import { generateImage } from 'ai';
import fs from 'fs';

const { image, providerMetadata } = await generateImage({
  model: quiverai.image('arrow-2'),
  prompt: {
    images: [fs.readFileSync('./logo.svg')],
    text: 'Make the logo pulse gently.',
  },
  providerOptions: {
    quiverai: {
      operation: 'animate',
      reasoningEffort: 'medium',
      maxOutputTokens: 4096,
    } satisfies QuiverAIImageModelOptions,
  },
});

fs.writeFileSync('animated-logo.svg', image.uint8Array);

const timing = providerMetadata.quiverai?.images?.[0];
console.log(timing?.loopPeriodMs, timing?.openingAnimationMs);

The animation source can be an HTTP or HTTPS URL, SVG bytes, raw base64, or an image/svg+xml base64 data URL. Local file inputs are inspected before the request and rejected when they do not contain SVG data. Remote URLs are validated for their scheme and fetched and validated by QuiverAI.

Animation returns an animated SVG as bytes in image.uint8Array. When QuiverAI returns timing information, the per-image metadata includes loopPeriodMs and openingAnimationMs; either timing value can be null.

Animation requests must use arrow-2 or arrow-2-telos, contain exactly one source SVG, omit masks, and produce one result per provider request. To request multiple animations with n, set maxImagesPerCall: 1 so generateImage splits them into separate calls. Animation supports temperature, reasoningEffort, and maxOutputTokens; generation-only and vectorization-only provider options are rejected.

Source SVGs, text instructions, and remote source URLs are sent to QuiverAI. Animated SVG is active document content. Sanitize it or render it in an isolated context before embedding output from an untrusted source inline in a page.

Billing and Usage

Arrow 2 models return measured token counts in result.usage. Fixed-credit models may return compatibility token counts of zero; their credit charge is available in result.providerMetadata?.quiverai?.credits when supplied by the API.

Model availability and supported operations depend on your organization and API key permissions. Consult QuiverAI's model catalog for current capabilities and billing.