Your application owns
- Users, identity, and permissions
- Credentials and vendor clients
- Data, memory, and retention
- Approval and authorization policy
- Where and how it is deployed
Install the core runtime and one provider adapter. Everything else on this page is a package you add when the product needs it.
$pnpm add @anvia/core @anvia/openai1import { Agent } from '@anvia/core'2import { OpenAIClient } from '@anvia/openai'34const client = new OpenAIClient({ apiKey: process.env.OPENAI_API_KEY! })5const model = client.completionModel({6 modelId: 'gpt-5.6-sol',7 api: 'responses',8})910const agent = new Agent({11 id: 'support',12 model,13 instructions: 'Answer support questions clearly.',14 maxTurns: 4,15})1617const response = await agent.generate({18 prompt: 'Draft a reply.',19})Every provider adapter returns the same model contract, so tools, memory, streaming, and results stay as they are. Point @anvia/openai at any OpenAI-compatible endpoint with baseUrl.
Models you already use
-import { OpenAIClient } from '@anvia/openai'+import { AnthropicClient } from '@anvia/anthropic'-const client = new OpenAIClient({ apiKey: process.env.OPENAI_API_KEY! })-const model = client.completionModel({ modelId: 'gpt-5.6-sol', api: 'responses' })+const client = new AnthropicClient({ apiKey: process.env.ANTHROPIC_API_KEY! })+const model = client.completionModel({ modelId: 'claude-opus-5' })const agent = new Agent({ id: 'support', model, tools, memory })Sessions, embeddings, and graphs persist in stores you already run. Let Anvia provision the tables, or validate against the migrations you own.
1const database = new PostgresMemoryClient({ connectionString: process.env.DATABASE_URL! })2const store = database.memoryStore()3await store.ensure()45const agent = new Agent({6 id: 'support',7 model,8 memory: { store, savePolicy: 'turn' },9})1011await agent.generate({12 prompt: 'Remember that my order number is 1234.',13 session: { sessionId: 'support-123', userId: 'user-456' },14})Tools validate their input before they run. A protected action can suspend the run, hand an approval to your application, and resume in a linked phase, even from another process. generate() and stream() always end in a state you can handle.
1const issueRefund = createTool({2 name: 'issue_refund',3 inputSchema: refundInput,4 outputSchema: refundResult,5 requiresApproval: ({ amount }) =>6 amount > 1007 ? { reason: 'High-value refund.' }8 : false,9 async execute(input) {10 await auth.require(actor, input)11 return billing.refund(input)12 },13})One typed input starts a bounded model-and-tool loop.
Arguments are validated before the protected action can run.
An interaction and JSON-safe continuation return to your application.
Your server claims the response and starts a linked phase.
The approved tool runs and one typed result closes the lifecycle.
Validate input, require approval, and authorize the side effect in your code.
Generate and stream finish as completed, blocked, or suspended.
Every resumed phase keeps its relationship to the original run.
@anvia/durable journals submissions, model responses, tool results, approvals, and progress events. When a worker restarts, the runtime finds unfinished runs and recovers them from committed checkpoints.
1const runtime = await DurableRuntime.open({2 store: new SqliteDurableStore('./support-runs.sqlite'),3 agents: [{ agent, version: '1', stream: true }],4})56await runtime.resume() // recover unfinished work78const run = await runtime.submit({9 agentId: agent.id,10 sessionId: 'customer-42',11 requestId: 'support-request-123',12 prompt: 'Explain how to resolve a duplicate payment.',13})1415for await (const event of run.stream()) render(event)Completed model responses and tool results are reused when unfinished work recovers.
Submissions are deduplicated by session and request ID, so a retry never starts the work twice.
Pending approvals and questions are still there after a restart.
Clients pick up from the last event cursor they applied.
Interrupted tools default to manual reconciliation. Mark read-only tools safe, and idempotent ones keyed by operation ID.
Each generation, tool call, and subagent is a span. Inspect them in Studio while you build, then send the same traces to Lens, OpenTelemetry, or Langfuse in production.
Run and debug locally. Studio inspects the agent your application runs.
Explore Studio ProductionObserve and evaluate production. Self-hosted, and entirely optional.
Explore LensExport the same spans through OpenTelemetry or Langfuse instead.
OpenTelemetry LangfuseAnvia coordinates the bounded model-and-tool loop. Your application keeps authority over users, credentials, data, permissions, persistence, and deployment.
One typed contract. Everything else is a package.
Hosted, OpenAI-compatible, or custom providers.
Studio on your machine. Tracing and evaluation in production.
Three complete patterns for products that need grounded answers, connected data, or visible browser work.
Authenticate before retrieval, derive filters from trusted roles, and rank only documents the user may access.
Extract a typed graph, traverse allowed relationships, and return provenance-linked evidence.
Run Chromium in Docker, restrict navigation, expose semantic tools, and coordinate human takeover.
Agents, providers, memory, streaming, React, Studio, observability, and evaluation now share runtime contracts. Packages release independently, so check dependency compatibility when upgrading.
What stable means, and what changed since the release candidate.
Compatibility and versioning across packages.
Every package release, in order.
The source, the cookbook, and the issue tracker.
$pnpm add @anvia/core @anvia/openaiBuild your first agent