@doubleword/vercel-ai
v0.3.1
Published
Doubleword provider for the Vercel AI SDK
Readme
@doubleword/vercel-ai
A Vercel AI SDK provider for Doubleword.
This package wires Doubleword's OpenAI-compatible inference API
(https://api.doubleword.ai/v1) into the Vercel AI SDK as a custom provider,
with automatic API key resolution and a pre-configured base URL.
Installation
npm install @doubleword/vercel-ai aiAuthentication
Three resolution paths, in precedence order:
Explicit option:
const doubleword = createDoubleword({ apiKey: "sk-..." });Environment variable:
export DOUBLEWORD_API_KEY=sk-...~/.dw/credentials.toml— the same file written by Doubleword's CLI tooling. The active account is selected by~/.dw/config.toml'sactive_accountfield, andinference_keyfrom that account is used.# ~/.dw/config.toml active_account = "work"# ~/.dw/credentials.toml [accounts.work] inference_key = "sk-..."
Language models
Text generation
import { createDoubleword } from "@doubleword/vercel-ai";
import { generateText } from "ai";
const doubleword = createDoubleword();
const result = await generateText({
model: doubleword("your-model-name"),
prompt: "Explain bismuth in three sentences.",
});
console.log(result.text);Streaming
import { createDoubleword } from "@doubleword/vercel-ai";
import { streamText } from "ai";
const doubleword = createDoubleword();
const stream = streamText({
model: doubleword("your-model-name"),
prompt: "Explain bismuth in three sentences.",
});
for await (const chunk of stream.textStream) {
process.stdout.write(chunk);
}Tool calling
The provider supports multi-step tool use via generateText. The model decides
when to call tools, receives the results, and formulates a final answer:
import { createDoubleword } from "@doubleword/vercel-ai";
import { generateText, tool, jsonSchema, stepCountIs } from "ai";
const doubleword = createDoubleword();
const result = await generateText({
model: doubleword("your-model-name"),
tools: {
calculator: tool({
description: "Evaluate a basic arithmetic expression",
inputSchema: jsonSchema({
type: "object",
properties: {
expression: { type: "string", description: "The expression to evaluate" },
},
required: ["expression"],
additionalProperties: false,
}),
execute: async ({ expression }: { expression: string }) => {
return String(new Function(`return (${expression})`)());
},
}),
},
stopWhen: stepCountIs(5),
prompt: "What is 137 * 49?",
});
console.log(result.text);stopWhen: stepCountIs(5) allows up to 5 model→tool→model round-trips before
returning. Each step where the model calls a tool automatically feeds the
result back for the next step.
Embeddings
import { createDoubleword } from "@doubleword/vercel-ai";
import { embed } from "ai";
const doubleword = createDoubleword();
const result = await embed({
model: doubleword.embeddingModel("your-embedding-model"),
value: "Hello world",
});
console.log(result.embedding.length);Batch pricing with createDoublewordBatch
For background workloads where latency is not critical, use the batch provider
to transparently route requests through the
Doubleword Inference API Batch API — cutting
inference costs by up to 90%. Powered by
autobatcher under the hood.
createDoublewordBatch defaults to the 24-hour batch tier (deepest
discount). For results within an hour at intermediate cost, use
createDoublewordAsync instead.
import { createDoublewordBatch } from "@doubleword/vercel-ai";
import { generateText } from "ai";
const doubleword = createDoublewordBatch({
batchWindowSeconds: 2.5, // don't wait the full 10s to submit
});
const result = await generateText({
model: doubleword("your-model-name"),
prompt: "Summarize this document.",
});
console.log(result.text);
// When done, flush remaining requests and wait for completion
await doubleword.close();Concurrent generateText calls are automatically collected into batch
submissions. The interface is identical to the real-time provider — only
streaming is not supported (batch results return all at once).
Tuning the batch client
| Option | Default | Purpose |
|-----------------------|---------|----------------------------------------------------------------------|
| batchSize | 1000 | Submit a batch when this many requests are queued. |
| batchWindowSeconds | 10 | Submit after this many seconds even if the size cap is not reached. |
| pollIntervalSeconds | 5 | How often to poll for batch completion. |
| completionWindow | "24h" | Doubleword completion window. Set to "1h" to fall back to flex pricing without switching factory. |
Async pricing with createDoublewordAsync
Identical machinery to createDoublewordBatch, but pinned to Doubleword's
1-hour async (flex) tier — between realtime and 24-hour batch on both
cost and latency. Use this when next-day batch is too slow but realtime is
too expensive.
import { createDoublewordAsync } from "@doubleword/vercel-ai";
import { generateText } from "ai";
const doubleword = createDoublewordAsync();
const results = await Promise.all([
generateText({ model: doubleword("your-model-name"), prompt: "Summarize chapter 1." }),
generateText({ model: doubleword("your-model-name"), prompt: "Summarize chapter 2." }),
generateText({ model: doubleword("your-model-name"), prompt: "Summarize chapter 3." }),
]);
await doubleword.close();All the tuning knobs above apply unchanged. The only difference from
createDoublewordBatch is that the underlying autobatcher client defaults
to completionWindow="1h" rather than "24h".
Default singleton
For convenience, a pre-configured singleton is also exported that reads
DOUBLEWORD_API_KEY from the environment:
import { doubleword } from "@doubleword/vercel-ai";
import { generateText } from "ai";
const result = await generateText({
model: doubleword("your-model-name"),
prompt: "Say hello.",
});Configuration
| Option | Env var | Default |
|-----------|----------------------|----------------------------------|
| apiKey | DOUBLEWORD_API_KEY | required |
| baseURL | DOUBLEWORD_API_BASE| https://api.doubleword.ai/v1 |
| headers | — | {} |
The provider is built on top of @ai-sdk/openai-compatible, so all standard
Vercel AI SDK features (generateText, streamText, generateObject,
embed, etc.) work unchanged.
License
Apache-2.0
