N AgentNavaKit
AgentNavaKit · Guide

Build AI agents in TypeScript.
Bring your own UI.

AgentNavaKit lets you describe an AI agent in a single TypeScript object and run it on a managed runtime. The runtime executes the agent loop, handles tool calls, and streams typed events back — render them in any UI you like.

Quickstart

One TypeScript file walks the whole lifecycle: push a spec, configure an agent version, optionally deploy to test, then deploy to prod. No CLI, no login flow — just the SDK and an API key.

One prompt → working agent
Paste this into Claude Code, Codex, or Cursor. It installs the SDK, scaffolds a real agent end-to-end as TypeScript, runs it, and opens a test URL.
Set up AgentNavaKit (`@agentnava/kit`) in this project end-to-end using ONLY the TypeScript SDK. There is no CLI. Agents always run on the AgentNava backend.

1. Detect the package manager from the lockfile (bun.lockb → bun, pnpm-lock.yaml → pnpm, yarn.lock → yarn, else npm). Use it consistently.
2. Install `@agentnava/kit`.
3. Confirm `AGENTNAVA_API_KEY` is set in `.env` (or `process.env`). If it isn't, stop and tell me to generate one at https://agentnava.com → Settings → API keys, and paste it into `.env`. Don't proceed until I confirm.
4. Create `agents/hello/role.md` with a single H1 "# What this agent does" and one short paragraph: a concise, helpful generalist that calls users "you".
5. Create `agents/hello.ts` that does the full lifecycle in code:
   - Import { AgentNava } from '@agentnava/kit'
   - const an = new AgentNava()
   - Push the spec as one bundle (key: 'hello', files: [{ name: 'role', content: readFileSync('./agents/hello/role.md', 'utf8') }])
   - Configure the agent (key: 'hello-bot', name: 'Hello', modelClass: 'standard', spec: , triggers: [{ kind: 'chat' }])
   - Deploy to test: an.agents.deployToTest(version.versionId)
   - console.log the test URL the call returns
   - Do NOT deploy to prod — the user does that explicitly.
6. Run the file: `bun run agents/hello.ts` (or `tsx agents/hello.ts` for npm/pnpm). Wait for the test URL.
7. Curl-test the chat endpoint at the test URL with a sample message; show the streaming SSE output.
8. Print a one-paragraph summary of what was created (spec ID, agent ID, version ID, test URL) and what to try next.

Reference: https://docs.agentnava.com
Don't modify unrelated files. Ask before any ambiguous choice.

Or do it by hand

1

Install the SDK

npm install @agentnava/kit
# or: bun add @agentnava/kit

AgentNavaKit ships TypeScript source. No build step. There is no CLI to install — everything happens via the SDK.

2

Set your API key

# .env
AGENTNAVA_API_KEY=sk_live_…

Generate the key at agentnava.com → Settings → API keys. The SDK reads process.env.AGENTNAVA_API_KEY automatically. You can override per-instance with new AgentNava({ apiKey: '…' }).

3

Write the spec files

// agents/hello/role.md
# What this agent does

You are a concise, helpful generalist.
Answer in two paragraphs max unless the user asks for detail.
Always address the user as "you".

The Spec is one bundle that can contain multiple .md files. Their concatenated content is what the runtime sends to the model on every turn — write exactly what you want the agent to do.

4

Write the lifecycle in TypeScript

// agents/hello.ts
import { AgentNava } from '@agentnava/kit';
import { readFileSync } from 'fs';

const an = new AgentNava();

// 1. Push the spec — one bundle, versioned per push.
const spec = await an.specs.push({
  key: 'hello',
  files: [
    { name: 'role', content: readFileSync('./agents/hello/role.md', 'utf8') },
  ],
});
// → { id: 'spec_4f1c9a', version: 1 }

// 2. Configure the agent → returns a new agent version.
const v = await an.agents.configure({
  key: 'hello-bot',                      // dev-chosen, stable; backend assigns agt_…
  name: 'Hello',                          // what users address the agent as in chat
  modelClass: 'standard',
  spec,                                   // ties this version to spec@v1
  triggers: [{ kind: 'chat' }],
});
// → { agentId: 'agt_2b8e', versionId: 'ver_3c5f' }

// 3. (Optional) deploy to test. Dev-only URL; no end-user traffic.
const test = await an.agents.deployToTest(v.versionId);
console.log('test:', test.url);

// 4. When ready, deploy to prod. End users hit this version.
// const prod = await an.agents.deployToProd(v.versionId);
// console.log('prod:', prod.url);
5

Run it

bun run agents/hello.ts
# or: npx tsx agents/hello.ts
#
# spec pushed: spec_4f1c9a@v1
# agent version: ver_3c5f (agt_2b8e)
# test: https://<temp-id>.test.agents.agentnava.com

The TS file IS the deployment script. Re-run it whenever you change the spec or the configuration — push is idempotent on key, configure upserts on key, only changed content gets a new version.

6

Chat with the test agent

curl -N -X POST https://<temp-id>.test.agents.agentnava.com/chat \
  -H 'Content-Type: application/json' \
  -d '{"messages":[{"role":"user","content":"Hi!"}]}'

SSE stream of AgentEvents. Plug it into any UI that reads SSE — your own React app, Vue, vanilla JS, our embed widget. See Sessions for the full chat protocol with attachments and multi-turn history.

7

Deploy to prod when ready

const prod = await an.agents.deployToProd(v.versionId);
console.log('prod:', prod.url);
// → https://hello-bot.agents.agentnava.com

Promotes the agent version to the stable production URL. End users now hit this version. See Operate for custom domains, rollbacks, and BYOK.

Spec & agent versions

Configuring an agent assembles four first-class objects — a Spec, an optional set of Docs, a list of Connections, and a list of Secrets — into a new agent version. The version is what you deploy.

The four object types

ObjectWhat it isHow to create it
Spec One bundle of .md files describing the agent's behavior — what it does, how it talks, what it won't do. an.specs.push({ key, files }). Each push stamps a new spec version.
Docs RAG knowledge — PDFs, MDs, DOCXs the agent reads before replying. Optional. an.docs.upload({ key, files }). Versioned per upload.
Connections Pre-authorized OAuth integrations (Slack, Gmail, GitHub, …) — set up once in the workspace, referenced by key. Dashboard, or connect.slack({ key: 'slack-acme' }) in code. Full catalog at Connections.
Secrets Workspace-level API keys / env values injected into tool handlers. Dashboard, or an.secrets.set('ZILLOW_API_KEY', '…'). Referenced from agents by name.

Why the Spec is a bundle, not one file

Behavior is rarely one paragraph. Splitting it into multiple files inside the same bundle keeps each one focused, reviewable, and reusable:

  • By concernwhat the agent does, how it talks, what it won't do. Changing tone shouldn't require re-reading the role file.
  • By owner — legal owns off-limits.md; product owns role.md; design owns tone.md. Each PR's diff lives where the reviewer expects it.
  • By reusability — push the same legal-off-limits.md file into multiple specs. Update it once, repush, every agent that references it picks up the new version on next configure.

On every push, the entire bundle is uploaded. The runtime concatenates the files in the order you list them — that becomes the agent's instructions.

The lifecycle in TypeScript

The whole flow is a single file. Each step is an SDK call.

// agents/concierge.ts
import { AgentNava, connect } from '@agentnava/kit';
import { readFileSync } from 'fs';

const an = new AgentNava();   // reads process.env.AGENTNAVA_API_KEY

// 1) Push the Spec — one bundle, versioned per push.
const spec = await an.specs.push({
  key: 'concierge',
  files: [
    { name: 'role',       content: readFileSync('./concierge/role.md',       'utf8') },
    { name: 'tone',       content: readFileSync('./concierge/tone.md',       'utf8') },
    { name: 'off-limits', content: readFileSync('./concierge/off-limits.md', 'utf8') },
  ],
});
// → { id: 'spec_4f1c9a', version: 2 }

// 2) (Optional) upload Docs for RAG.
const docs = await an.docs.upload({
  key: 'bayhomes-handbook',
  files: ['./docs/handbook.pdf', './docs/policies.md'],
});
// → { id: 'doc_8b07', version: 3 }

// 3) Configure → returns a new agent version that pins to spec@v2 and docs@v3.
const v = await an.agents.configure({
  key:        'bayhomes-concierge',                     // dev-chosen, stable; backend assigns agt_…
  name:       'BayHomes Concierge',                     // what users address it as in chat
  modelClass: 'standard',
  spec,                                                  // the Spec object you just pushed
  docs:       [docs],                                    // optional, can be []
  triggers:   [{ kind: 'chat' }],
  connections:[connect.slack({ key: 'slack-bayhomes' })],
  secrets:    ['ZILLOW_API_KEY'],                        // workspace secret keys, injected to tool handlers
});
// → { agentId: 'agt_2b8e', versionId: 'ver_3c5f' }

// 4) (Optional) deploy to test. Dev-only URL — your users never see it.
const test = await an.agents.deployToTest(v.versionId);
console.log('test:', test.url);

// 5) Deploy to prod when you're happy. End users hit this version.
const prod = await an.agents.deployToProd(v.versionId);
console.log('prod:', prod.url);

Re-running the file is safe and idempotent. specs.push only stamps a new version if file contents changed. agents.configure upserts on key — first call creates the agent, later calls update its draft. deployToTest and deployToProd always produce a new instance.

What configure takes

Every field below is a property of the object you pass to an.agents.configure(...).

key string Required

A dev-chosen, stable identifier for this agent in your workspace. The backend uses it to upsert — first configure with a new key creates the agent (and assigns an opaque agt_… ID); later calls with the same key update the existing one.

key: 'bayhomes-concierge'

You control key. The backend controls agentId. Use key in source code; use agentId for sessions, deploys, and rollbacks at runtime.

name string Required

What users address the agent as in chat (e.g. "Hey Concierge, …") and how it introduces itself. Also appears in the workspace header, embed widget, and catalog cards — but the conversational identity is what matters.

name: 'BayHomes Concierge'
spec Spec | string Required

The Spec object you got from an.specs.push(...), or its ID + version as a string ('spec_4f1c9a@v2'). The agent version pins to whichever spec version you pass — re-pushing the spec doesn't change deployed agents.

spec  // pass the object directly
// or
spec: 'spec_4f1c9a@v2'
// or
spec: 'spec_4f1c9a'   // resolves to latest at configure time, then pinned
docs (Docs | string)[] Optional

One or more Docs bundles for RAG. The runtime indexes them, retrieves relevant chunks each turn, and asks the agent to cite them. Pin to specific Docs versions the same way as Spec.

docs: [docs, 'doc_legal@v5']

End users (or you, post-deploy) can also upload files into a Docs bundle — see Uploading documents.

modelClass 'standard' | 'premium' | 'advanced' Required

How much reasoning the agent applies on each turn. Higher classes think longer, can chain more tool calls before replying, and cost more.

ClassWhen to pick itDefault route
standardShort replies, FAQ, simple Q&A. One shot, at most one tool call.GLM-4.7 tier
premiumDrafts, multi-step reasoning, RAG across several sources, summarization with citations.Sonnet tier
advancedPlanning across many tools and steps — research, code generation, complex workflows.Opus tier

Pin a snapshot if you want behavior frozen across model upgrades:

modelClass: 'standard'           // rolling — auto-upgrades over time
modelClass: 'standard@2026-05'   // pinned to the May 2026 snapshot
modelClass: 'premium@v3'         // pinned to integer release v3
provider 'auto' | 'bedrock' | 'azure-openai' | 'vertex' | 'openrouter' Optional default: 'auto'

Whose account pays for the model calls. 'auto' bills the managed runtime. Any other value routes inference through your own cloud account — tokens billed there. See Operate → BYOK.

triggers Trigger[] Required

When the agent wakes up. Without at least one trigger, the agent never runs.

triggers: [
  { kind: 'chat' },
  { kind: 'webhook' },
  { kind: 'schedule', cron: '0 7 * * 1-5' },
  { kind: 'loop', everySeconds: 600, maxRuns: 24 },
  { kind: 'manual' },
]
KindThe agent runs when
chatA user sends a message via the embed widget, hosted chat page, or your own UI.
webhookAn external service POSTs to the agent's URL — Stripe events, GitHub webhooks, your own backend.
scheduleA cron expression matches. Daily standup digests, hourly polls, weekly reports.
loopA self-driving loop runs the agent every N seconds, optionally capped. Useful for monitoring tasks.
manualYour code calls an.agents.run(agentId, { ... }). Useful for batch jobs.
connections ConnectionRef[] Optional

Pre-authorized OAuth integrations the agent can use during a turn. Each connection registers a handful of tools (Slack registers post_message, list_channels, etc.) and may add a trigger. Set up the OAuth once in the workspace dashboard, then reference by key from code. Full catalog at Connections.

connections: [
  connect.slack({ key: 'slack-acme' }),
  connect.gmail({ key: 'gmail-support' }),
  connect.mcp({ url: 'https://mcp.linear.app/sse' }),
]
secrets string[] Optional

Workspace secret names that should be injected into tool handlers as environment variables. Set the actual values once via the dashboard or an.secrets.set(name, value) — they never appear in your TS source.

secrets: ['ZILLOW_API_KEY', 'STRIPE_KEY']

// in a tool handler:
defineTool({
  // ...
  handler: async ({ address }, ctx) => {
    const r = await fetch(`https://zillow…`, {
      headers: { 'X-Key': ctx.secrets.ZILLOW_API_KEY },
    });
  },
});
tools ToolDef[] Optional

Custom functions you write in TypeScript. The agent decides when to call them. Use this for behavior no connection covers — calling your internal API, computing something, or hitting a SaaS the catalog doesn't yet support.

import { defineTool, t } from '@agentnava/kit';

const lookupZestimate = defineTool({
  name: 'lookup_zestimate',
  description: 'Get the Zillow zestimate for an address',
  input: t.object({ address: t.string() }),
  handler: async ({ address }, ctx) => {
    // ctx.secrets, ctx.sessionId, ctx.user available here
  },
});

tools: [lookupZestimate]

Uploading Docs (RAG)

The Docs object holds files the agent retrieves from before each reply. Three ways to populate it:

  • From your deploy script. an.docs.upload({ key, files: ['./handbook.pdf', …] }) creates or updates the Docs bundle. Each call stamps a new version.
  • From your backend. Same an.docs.upload call from anywhere with your API key — useful when end-users upload files via your UI.
  • From our embed widget. Set data-uploads="true" on the embed script; end-users get a file-attach button in the chat composer. Files go into the agent's Docs bundle if you've configured one as shared; otherwise they're transient session attachments (see Sessions).
const docs = await an.docs.upload({
  key:   'bayhomes-handbook',
  files: ['./docs/handbook.pdf', './docs/policies.md'],
});
// → { id: 'doc_8b07', version: 3, indexedAt: '…' }

// pass into configure:
await an.agents.configure({ /* … */ docs: [docs] });

Event stream

The agent runtime emits a typed SSE stream that any host UI can consume. The same shape comes back whether you're hitting a test or a prod deploy.

type AgentEvent =
  | { type: 'message-start'; messageId: string }
  | { type: 'message-delta'; messageId: string; delta: string }
  | { type: 'message-end'; messageId: string; final: string }
  | { type: 'tool-start'; toolId: string; name: string; input: unknown }
  | { type: 'tool-end'; toolId: string; ok: boolean; result?: unknown; error?: string }
  | { type: 'phase'; label: string; state: 'start' | 'end' }
  | { type: 'error'; message: string }
  | { type: 'done' };

Advanced

meta Record<string, unknown> Optional

Anything you set here is readable from tool handlers via ctx.meta.X. Use it for per-deploy config the agent doesn't reason about — brand colors, deploy targets, feature flags.

meta: {
  deployTarget: 'embed',
  brandColor: '#B91C1C',
  region: 'eu-west',
}

Connections

A connection wires an agent to a third-party service in one declaration. It handles auth, auto-registers a set of tools, and may add a trigger. Most agents only need connections — never individual defineTool calls.

Add a connection with one prompt
Paste this in. Swap the service name to install any of the connections below.
Add the Slack connection to the AgentNavaKit agent in this project.

1. Locate the agent's TS file (likely `agents/*.ts` calling `defineAgent({...})`).
2. Import `connect` from `@agentnava/kit` if not already imported.
3. Add `connect.slack({ workspace: '' })` to the `connections` array. Ask me for the workspace slug if you can't infer it.
4. Run `agentnava-kit auth slack`, print the OAuth URL it returns, and wait for me to authorize it in the browser.
5. Once authorized, run `agentnava-kit configure .ts` to push the updated configuration.
6. Run `agentnava-kit test .ts` and verify the agent can call `post_message` to a test channel.

Reference: https://docs.agentnava.com#connections
Don't deploy to production. Don't touch unrelated agents.

Catalog

S
SlackOAuth
Post, read channels, reply in threads, mention-trigger.
connect.slack({ workspace: 'acme' })
Auto-registered tools
post_messagelist_channelsthread_replysearch
G
GitHubOAuth
PRs, issues, commits, repo file access.
connect.github({ org: 'acme' })
Auto-registered tools
open_prcomment_issuelist_reposget_file
M
GmailOAuth
Send, search, label. Trigger on inbound matching a query.
connect.gmail({ account: '[email protected]' })
Auto-registered tools
send_emailsearch_threadsdraft_replyadd_label
C
Google CalendarOAuth
List, create, update events. Suggest free slots.
connect.googleCalendar({ account: '…' })
Auto-registered tools
list_eventscreate_eventupdate_eventsuggest_time
H
HubSpotOAuth
Capture leads, update deals, query contacts.
connect.hubspot({ portalId: 12345 })
Auto-registered tools
capture_leadupdate_dealquery_contacts
K
CalendlyAPI key
Read availability, book on behalf of a user.
connect.calendly({ user: 'swati' })
Auto-registered tools
list_event_typescreate_bookingget_availability
MCP serverURL / token
Any MCP-compatible server. Tools exposed by the protocol become callable.
connect.mcp({ url: 'https://mcp.linear.app/sse' })
Auto-registered tools
* (mirrors the server's tool list)

How it looks in a spec

import { defineAgent, connect } from '@agentnava/kit';

export default defineAgent({
  name: 'Inbound triage',
  modelClass: 'standard',
  spec: ['triage/role'],
  triggers: [{ kind: 'chat' }],
  connections: [
    connect.slack({ workspace: 'acme' }),
    connect.gmail({ account: '[email protected]' }),
    connect.hubspot({ portalId: 12345 }),
  ],
});

The agent now has nine new tools and a Slack mention trigger, with zero credential handling in the spec.

Sessions

Once an agent is deployed, end users interact with it through sessions. Each session is one user's ongoing conversation — its own message history, its own attached files, its own state. A single deployed agent serves many concurrent sessions in parallel; each one is independent.

How sessions get created

  • Embed widget. Mounting <script src="https://embed.agentnava.com/v1.js" data-agent="…"> on a page creates one session per browser tab automatically. The session ID is persisted in localStorage so the user can refresh and resume.
  • Your own UI. Call POST /agents/<id>/sessions to mint a session ID, then use it on every subsequent chat call.
  • Implicit (single-turn). Hit POST /chat directly without a session ID — the runtime mints a one-shot session that's torn down after the response.

The chat protocol

To send a turn to an existing session:

POST https://<agent-url>/sessions/<session-id>/messages
Authorization: Bearer <public-token>
Content-Type: application/json

{
  "role": "user",
  "content": "Can you walk me through this floor plan?",
  "attachments": [
    { "id": "file_4f1c9a", "type": "image", "name": "floor-plan.png" },
    { "id": "file_2a9d12", "type": "file",  "name": "hoa-rules.pdf"  }
  ]
}

Response is an SSE stream of AgentEvents — message-delta chunks, then message-end, plus any tool-start/tool-end/phase events the agent emits along the way.

Attachments

An attachments entry references a file the user already uploaded for this session. Two ways to put files there:

// 1. Upload a file to a session — returns a file ID you attach to messages
POST https://<agent-url>/sessions/<session-id>/files
Authorization: Bearer <public-token>
Content-Type: multipart/form-data

[email protected]

// → { "id": "file_4f1c9a", "type": "image", "status": "ready" }
// 2. The embed widget does this automatically when the user drops a file
//    into the chat composer (if data-uploads="true" is on the script tag).

Attached files live for the lifetime of the session. They're not added to the agent's RAG index — they're transient context for that one conversation. (For persistent knowledge, use document upload on a documents source instead.)

Session lifecycle

StateWhat it means
activeThe session has been touched in the last hour. Messages stream as SSE.
idleNo activity for an hour, but history is still in memory. Resuming is instant.
hibernatedNo activity for 24h. History persisted to durable storage; first resume after this state has a small wake-up cost (~200ms).
closedExplicitly ended via DELETE /sessions/<id>, or by the agent emitting a handoff event. Attachments are deleted; messages remain queryable from the audit log.

Querying sessions

GET https://<agent-url>/sessions/<session-id>/messages
# → full message history, newest first

GET https://<agent-url>/sessions?since=2026-05-10T00:00:00Z
# → list of recent sessions (workspace-scoped, requires a workspace token)

For analytics, the workspace dashboard surfaces session counts, average turn count, common handoff reasons, and per-version metrics.

Operate

Deploy an agent to test or prod, roll back to a previous version, point a custom domain at it, embed it in a webpage, and route model calls through your own cloud account. All via the SDK.

Deploy to test and to prod

Configure creates an agent version (a snapshot). Deploying that version runs it on the backend. You pick the destination:

// the configure call returned:
//   const v = { agentId: 'agt_2b8e', versionId: 'ver_3c5f' }

// dev-only URL — no end-user traffic, ephemeral
const test = await an.agents.deployToTest(v.versionId);
// → { url: 'https://<temp>.test.agents.agentnava.com', expiresAt: '…' }

// production URL — end users hit this
const prod = await an.agents.deployToProd(v.versionId);
// → { url: 'https://hello-bot.agents.agentnava.com', versionNumber: 4 }

Both calls are idempotent on the version ID. deployToProd promotes the version atomically and keeps the previous one warm until the new one passes a health check. Skip deployToTest if you don't need a dev-only environment.

Versions & rollback

// list every version of this agent (newest first)
const versions = await an.agents.versions('agt_2b8e');
// → [{ id: 'ver_3c5f', number: 4, deployedAt: '…', isProd: true }, …]

// instant rollback to a previous version
await an.agents.rollback('agt_2b8e', 'ver_9a1b');

Rollback is instant — every version's spec content and configuration is preserved as long as the agent exists.

Custom domain

Map agent.yourdomain.com to the agent's public URL via CNAME, then attach it in code:

await an.domains.add({
  domain:  'agent.yourdomain.com',
  agentId: 'agt_2b8e',
});

The runtime provisions a managed TLS cert and serves the agent at that domain within a minute.

Embed snippet

<script
  src="https://embed.agentnava.com/v1.js"
  data-agent="<agentId>"
  data-theme="auto"
  defer
></script>

Drops into any HTML page. The widget creates a session automatically on first message and resumes it across reloads (session ID in localStorage). data-theme accepts light, dark, or auto.

BYOK — bring your own keys

Route inference through your own cloud account. The runtime still runs on AgentNava; only model calls hit the chosen provider. Attach credentials once per workspace — they're validated with a small probe call before any agent uses them.

No setup. AgentNava bills inference. Cheapest to start; switch to BYOK once volume picks up.

In your configure call, omit provider or set it to 'auto':

await an.agents.configure({
  // ...
  provider: 'auto',   // or omit entirely
});
Tokens billed to your AWS account. Validates against Bedrock model access at attach time.

Attach an IAM user (or assume-role ARN) with bedrock:InvokeModelWithResponseStream on the models you'll use:

await an.byok.bedrock.set({
  accessKey: 'AKIA…',
  secretKey: process.env.AWS_SECRET,
  region:    'us-west-2',
});

Then in configure:

await an.agents.configure({
  // ...
  provider: 'bedrock',
});
Routes through your Azure OpenAI deployment. Map model classes to your deployment names.
await an.byok.azureOpenai.set({
  resource: 'my-resource',
  apiKey:   process.env.AZURE_OPENAI_KEY,
  deployments: {                            // map our classes to your deployment names
    standard: 'gpt-4o-mini-deploy',
    premium:  'gpt-4o-deploy',
    advanced: 'o1-deploy',
  },
});
await an.agents.configure({
  // ...
  provider: 'azure-openai',
});
Routes through Vertex AI. Validates against the configured GCP project + region.

Attach a service-account JSON with aiplatform.endpoints.predict on the relevant Vertex models:

import { readFileSync } from 'fs';

await an.byok.vertex.set({
  serviceAccount: JSON.parse(readFileSync('./sa.json', 'utf8')),
  project: 'my-gcp',
  region:  'us-central1',
});
await an.agents.configure({
  // ...
  provider: 'vertex',
});
Broadest model catalog with the lowest setup. Good fit for early-stage workspaces.
await an.byok.openrouter.set({
  apiKey: process.env.OPENROUTER_KEY,
});
await an.agents.configure({
  // ...
  provider: 'openrouter',
});

Regions

Agents deploy to the region closest to the workspace owner by default. Override on a per-agent basis via meta:

await an.agents.configure({
  // ...
  meta: { region: 'eu-west' },
});

Supported: us-west, us-east, eu-west, eu-central, ap-southeast.

Billing

The runtime is charged per workspace plan; model usage is metered separately. With provider: 'auto', model calls are billed by AgentNava. With BYOK, they're billed by your cloud provider. Plan details and pricing are on agentnava.com/pricing.