Agent Configuration
Configure the AI agent with environment variables, models, and Alchemy infrastructure
Agent Configuration
Configure the agent system through environment variables and Alchemy infrastructure-as-code. No wrangler.toml or manual Cloudflare config needed -- Alchemy generates wrangler.json from alchemy.run.ts.
Environment Variables
All environment variables are validated via @t3-oss/env-core in packages/env/src/agent.ts.
Required
| Variable | Description |
|---|---|
OPENROUTER_API_KEY | OpenRouter API key for LLM access |
CONVEX_URL | Convex deployment URL (e.g., https://your-deployment.convex.cloud) |
CONVEX_SITE_URL | Convex site URL (e.g., https://your-deployment.convex.site) |
Optional (with defaults)
| Variable | Default | Description |
|---|---|---|
DEFAULT_MODEL | openai/gpt-5.2-chat | Default LLM model (OpenRouter model ID) |
SITE_URL | http://localhost:3001 | Frontend URL for CORS |
EXTERNAL_TOKEN | meow | Shared secret for external token auth |
DAYTONA_API_KEY | "" | Daytona API key for sandbox access |
DAYTONA_API_URL | https://app.daytona.io/api | Daytona API endpoint |
DAYTONA_TARGET | us | Daytona deployment target region |
EXA_API_KEY | "" | Exa API key for web search |
MAX_BACKGROUND_DURATION_MS | 3600000 (1 hour) | Max background task duration |
COMPOSIO_API_KEY | "" | Composio API key |
VOLTAGENT_PUBLIC_KEY | "" | VoltAgent VoltOps public key (observability) |
VOLTAGENT_SECRET_KEY | "" | VoltAgent VoltOps secret key (observability) |
ALCHEMY_PASSWORD | -- | Alchemy encryption password for secrets |
Setting Variables
For local development, set in packages/agent/.dev.vars:
OPENROUTER_API_KEY=sk-or-v1-xxxx
CONVEX_URL=https://your-deployment.convex.cloud
CONVEX_SITE_URL=https://your-deployment.convex.site
SITE_URL=http://localhost:3001
DAYTONA_API_KEY=your-daytona-key
EXA_API_KEY=your-exa-keyFor production, secrets are managed by Alchemy and deployed as Cloudflare Worker secrets.
Alchemy Infrastructure
The agent is deployed via Alchemy (packages/agent/alchemy.run.ts), which manages all Cloudflare resources declaratively.
DurableObjectNamespace
const agentWorkerNamespace = DurableObjectNamespace("agent-worker", {
className: "AgentWorker",
sqlite: true, // SQLite storage for message persistence
});Each chat session gets its own Durable Object instance with SQLite-backed storage for messages and state.
VectorizeIndex
const chatMessagesIndex = await VectorizeIndex("chat-messages", {
name: "chat-messages",
description: "Embeddings for chat messages",
dimensions: 768,
metric: "cosine",
adopt: true,
});Used for RAG -- messages are embedded and indexed for cross-chat retrieval by member.
Worker Bindings
export const worker = await Worker("agent-worker", {
entrypoint: "./src/index.ts",
url: false,
compatibility: "node",
bindings: {
agentWorker: agentWorkerNamespace,
vectorizeChatMessages: chatMessagesIndex,
NODE_ENV: "production",
// All env vars bound as secrets via alchemy.secret()
CONVEX_URL: alchemy.secret(env.CONVEX_URL),
OPENROUTER_API_KEY: alchemy.secret(env.OPENROUTER_API_KEY),
// ... remaining bindings
},
observability: {
logs: { enabled: true, invocationLogs: true },
},
});Alchemy also generates a wrangler.json with a custom transform that cleans up migrations and filters out stale bindings.
Deploying
# Deploy infrastructure + worker
cd packages/agent
bun run deploy
# Destroy resources
bun run deploy --destroyModel Configuration
OpenRouter Model IDs
Any model available on OpenRouter can be used. Pass the full model ID:
openai/gpt-5.2-chat
anthropic/claude-sonnet-4
google/gemini-2.5-pro
deepseek/deepseek-r1
meta-llama/llama-4-maverickThe default model is set via DEFAULT_MODEL env var and can be overridden per-chat from the frontend.
Reasoning Effort
For models that support extended thinking, set the reasoning effort level:
| Level | Description |
|---|---|
low | Minimal reasoning, fastest responses |
medium | Balanced reasoning and speed |
high | Maximum reasoning depth |
Reasoning effort is passed as a URL query param when connecting and can be updated via state sync:
// Frontend sets reasoning effort
agentRef.current?.setState({ reasoningEffort: "high" });The agent patches both the PlanAgent model and all sub-agent models when reasoning effort changes.
Input Modalities
Control which message parts are sent to the model:
// Only send text content (strip images, files, etc.)
agentRef.current?.setState({ inputModalities: ["text"] });CORS Configuration
CORS is configured at the request routing level, allowing the frontend origin specified by SITE_URL:
cors: {
"Access-Control-Allow-Origin": env.SITE_URL,
"Access-Control-Allow-Credentials": "true",
"Access-Control-Allow-Methods": "GET, POST, HEAD, OPTIONS",
"Access-Control-Allow-Headers": "Content-Type, Authorization, Cookie, Upgrade, Connection, Sec-WebSocket-Key, Sec-WebSocket-Version, Sec-WebSocket-Extensions, Sec-WebSocket-Protocol",
"Access-Control-Max-Age": "86400",
}Observability (Optional)
If VOLTAGENT_PUBLIC_KEY and VOLTAGENT_SECRET_KEY are set, the agent enables VoltAgent VoltOps observability:
observability: createVoltAgentObservability({
serviceName: "just-use-convex-agent",
serviceVersion: "1.0.0",
voltOpsSync: {
sampling: { strategy: "always" },
maxQueueSize: 2048,
maxExportBatchSize: 512,
scheduledDelayMillis: 5000,
exportTimeoutMillis: 30000,
},
}),This traces all agent executions, tool calls, and sub-agent delegations.
Background Task Configuration
The task tool (used to delegate to sub-agents) supports background execution:
| Setting | Value | Description |
|---|---|---|
| Max foreground duration | 30 minutes | Before a task is moved to background |
| Max background duration | MAX_BACKGROUND_DURATION_MS (default 1 hour) | Total background execution limit |
| Allow agent-set duration | true | Agent can override timeout per-task |
Next, learn about Frontend Integration.