An agent-oriented AI SDK for AdonisJS 7.
adonis-ai gives Adonis applications one typed API for AI SDK-compatible language models. Use OpenAI and Anthropic directly, reach every model available through Vercel AI Gateway, or register any official, community, self-hosted, registry-backed, or middleware-wrapped AI SDK language model. The first release focuses on the parts needed to build dependable text agents: streaming, structured output, application tools, observability, cancellation, and network-free tests.
The npm badge above is the source of truth for the current version. During
0.x, breaking changes ship only at minor-version boundaries with migration notes.
The 0.1 public API, provider, security, testing, troubleshooting, and upgrade guide defines the supported stable contract.
| Dependency | Supported version |
|---|---|
| AdonisJS | ^7.0.0 |
| Node.js | >=24.0.0 |
| Zod | ^4.0.0 |
| Vercel AI SDK | Core, AI Gateway, and compatible language models |
| OpenAI | Responses API via @ai-sdk/openai |
| Anthropic | Messages API via @ai-sdk/anthropic |
- Reusable
BaseAgentclasses and anagent({...})factory - Vercel AI Gateway access to its full language-model catalog
- A public shared adapter for any AI SDK-compatible language model
- Built-in direct OpenAI Responses and Anthropic Messages drivers
- Async-iterable streaming with SSE conversion
- Zod 4 structured output with provider-native JSON Schema
- Zod-validated application tools and a shared multi-step tool loop
- Normalized responses, token usage, steps, request IDs, and errors
- Abort and timeout propagation, including SSE disconnect cancellation
- Adonis IoC singleton, typed events, configure hook, and Ace generators
- Queued or dynamic fakes with prompt assertions and stray-call prevention
- A real AdonisJS playground with functional and browser tests
The current Adonis agent surface covers text generation, streaming, structured output, application tools, provider-neutral image/document input, application-owned conversations, provider options, retries, timeouts, cancellation, and middleware-wrapped language models. Provider-executed tools, embeddings, image/video generation, speech, transcription, reranking, realtime, provider-stored conversations, queues, approvals, MCP, and vector stores remain deferred.
packages/adonis-ai Publishable SDK package
apps/playground AdonisJS 7 consumer app and package lab
npm install adonis-ai zod
node ace configure adonis-aiSet at least one provider and model in .env.
AI_DEFAULT_PROVIDER=openai
OPENAI_API_KEY=
OPENAI_MODEL=
ANTHROPIC_API_KEY=
ANTHROPIC_MODEL=
AI_GATEWAY_API_KEY=
AI_GATEWAY_MODEL=openai/gpt-5Create an agent.
node ace make:ai-agent Supportimport { BaseAgent } from "adonis-ai";
export default class SupportAgent extends BaseAgent {
instructions() {
return "Answer product questions clearly and concisely.";
}
}Use direct construction for dependency-free agents, or ai.make when the Adonis container should construct the class.
import SupportAgent from "#ai/agents/support_agent";
import ai from "adonis-ai/services/main";
const agent = await ai.make(SupportAgent);
const response = await agent.prompt("How do I reset my password?");
console.log(response.text);
console.log(response.usage);
console.log(response.steps);Every stream is an async iterable and can also be sent directly from an Adonis controller.
const stream = agent.stream("Explain server-sent events");
for await (const event of stream) {
if (event.type === "text.delta") {
process.stdout.write(event.delta);
}
}
const final = await stream.finalResponse();async stream({ response }: HttpContext) {
const stream = agent.stream('Explain server-sent events')
response.header('Content-Type', 'text/event-stream')
return response.stream(stream.toSseReadable())
}Normalized events are:
run.startedtext.deltatool.startedtool.completedstep.completedrun.completedrun.failed
Destroying the readable SSE stream aborts the upstream provider request.
import { BaseAgent } from "adonis-ai";
import { z } from "zod";
const output = z.object({
summary: z.string(),
risks: z.array(z.string()),
});
class ReviewAgent extends BaseAgent<typeof output> {
readonly outputSchema = output;
instructions() {
return "Review the input and identify its risks.";
}
}
const response = await new ReviewAgent().prompt("Review this proposal");
response.data.summary; // string
response.data.risks; // string[]The adapter asks the provider to enforce JSON Schema, then the shared engine parses and validates the completed value with Zod. During structured streaming, text deltas remain partial strings and typed data is exposed only on the final response.
import { defineTool } from "adonis-ai";
import { z } from "zod";
const weather = defineTool({
name: "weather",
description: "Get the weather for a city",
input: z.object({ city: z.string() }),
async execute({ city }, { signal }) {
return getWeather(city, { signal });
},
});Return tools from an agent’s tools() method. Multiple tool requests are executed sequentially in provider order. The default maximum is eight model steps. Input and handler errors are sent back to the model as safe tool results; pass { toolErrorMode: 'throw' } to stop immediately.
Register an application-owned store and pass a conversation identifier. The SDK loads history before the run and atomically appends the successful user, assistant, and tool messages before emitting completion.
import type { ConversationStore } from "adonis-ai";
const conversations: ConversationStore = {
load: (id) => database.loadMessages(id),
append: (id, turn) => database.appendTurn(id, turn.runId, turn.messages),
};
ai.useConversationStore(conversations);
await agent.prompt("Continue our discussion", {
conversation: { id: "conversation_123" },
});Nothing is persisted by default. Failed, cancelled, and maximum-step runs append nothing; load or append failures reject with ConversationPersistenceError.
String prompts remain supported. For multimodal input, pass text and file parts using bytes, base64, or an absolute HTTP(S) URL.
await agent.prompt([
{ type: "text", text: "Summarize this report" },
{
type: "file",
mediaType: "application/pdf",
filename: "report.pdf",
source: { type: "bytes", data: uploadedBytes },
},
]);Direct OpenAI and Anthropic support JPEG, PNG, GIF, WebP, and PDF; Anthropic also supports text/plain. Gateway and custom adapters must declare attachment capabilities explicitly. Applications own file-size limits, URL policy, durable storage, and upload authorization. See the conversations and files guide.
import ai from "adonis-ai/services/main";
const fake = ai
.fake([
"First answer",
{ data: { summary: "Typed fake", risks: [] } },
{ text: "Streamed", chunks: ["Stream", "ed"] },
])
.preventStrayRequests();
await agent.prompt("Question");
fake.assertPrompted("Question");Dynamic fakes receive both the recorded prompt and normalized provider request, so tests can model tool loops without network access.
Requires Node.js 24 and npm 11.
npm install
npm run check
npm run dev --workspace playgroundThe playground resolves adonis-ai directly from the local workspace and acts as an executable
feature catalog. It covers direct providers and Gateway, ordinary and structured generation,
streaming, local tools, application-owned conversations, every attachment source, one-off message
history, run limits, provider options, raw response opt-in, normalized events, and cancellation.
Its functional and browser suites use package fakes, so the examples stay deterministic.
To verify the exact artifact that npm consumers receive, run the isolated package-consumer check:
npm run test:package-consumerThis packs the SDK, installs the tarball into a temporary standalone copy of the playground, and runs its typecheck, tests, and production build.
Maintainers can follow the release qualification and publication checklist to verify live providers, npm dist-tags, provenance, and the published package.
The default suite never calls a real AI API. Live acceptance is opt-in and cost-bounded:
AI_LIVE_PROVIDER=openai npm run test:live:openai --workspace adonis-ai
AI_LIVE_PROVIDER=anthropic npm run test:live:anthropic --workspace adonis-ai
AI_LIVE_PROVIDER=gateway npm run test:live:gateway --workspace adonis-aiThe built-in gateway driver uses creator/model IDs and reaches every language model available in Vercel AI Gateway with one API key:
export default defineConfig({
default: "gateway",
providers: {
gateway: {
driver: "gateway",
apiKey: env.get("AI_GATEWAY_API_KEY"),
model: "anthropic/claude-sonnet-4",
},
},
});Gateway routing, fallback, attribution, and provider-specific settings pass through providerOptions:
await agent.prompt("Explain the tradeoff", {
providerOptions: {
gateway: {
order: ["vertex", "anthropic"],
models: ["openai/gpt-5-mini"],
tags: ["support"],
},
anthropic: {
thinking: { type: "enabled", budgetTokens: 4_000 },
},
},
});To use a provider package directly, install only that package and register its language model with the public adapter:
import { google } from "@ai-sdk/google";
import { AiSdkProvider } from "adonis-ai/providers/ai-sdk";
ai.extend("google", (_config, context) => {
return new AiSdkProvider({
name: context.name,
providerOptionsKey: "google",
model: (modelId) => google(modelId),
});
});This same entrypoint accepts AI SDK provider registries, community and self-hosted providers, custom providers, and models wrapped with AI SDK middleware. For a non-AI-SDK integration, implement ProviderAdapter directly:
ai.extend("community-driver", (config, context) => {
return new CommunityProvider(config, context.name);
});The Vercel AI SDK provider layer translates model requests, responses, errors, usage, and streaming events. Agent composition and the multi-step application tool loop remain in Adonis AI, preserving the existing public API and extension contract. Individual providers and models still differ in capability; Adonis AI forwards supported features and normalizes their results rather than emulating capabilities a model does not have.
- OpenAI response storage defaults to
false - Prompts are excluded from emitted events unless explicitly enabled
- Raw provider payloads are opt-in and typed as
unknown - Default timeout is 60 seconds with two SDK-level retries
- API keys are never included in normalized events or errors
- Ask usage and design questions in GitHub Discussions.
- Report reproducible bugs and request features through GitHub Issues.
- Report vulnerabilities privately through GitHub Security Advisories.
- See SUPPORT.md, SECURITY.md, and CONTRIBUTING.md for project policies.
The developer experience follows AdonisJS and TypeScript conventions and uses Vercel AI SDK Core. OpenAI uses its Responses API; Anthropic uses its Messages API.
MIT licensed.