Just-Use-Convex Docs
AI Agent

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

VariableDescription
OPENROUTER_API_KEYOpenRouter API key for LLM access
CONVEX_URLConvex deployment URL (e.g., https://your-deployment.convex.cloud)
CONVEX_SITE_URLConvex site URL (e.g., https://your-deployment.convex.site)

Optional (with defaults)

VariableDefaultDescription
DEFAULT_MODELopenai/gpt-5.2-chatDefault LLM model (OpenRouter model ID)
SITE_URLhttp://localhost:3001Frontend URL for CORS
EXTERNAL_TOKENmeowShared secret for external token auth
DAYTONA_API_KEY""Daytona API key for sandbox access
DAYTONA_API_URLhttps://app.daytona.io/apiDaytona API endpoint
DAYTONA_TARGETusDaytona deployment target region
EXA_API_KEY""Exa API key for web search
MAX_BACKGROUND_DURATION_MS3600000 (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-key

For 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 --destroy

Model 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-maverick

The 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:

LevelDescription
lowMinimal reasoning, fastest responses
mediumBalanced reasoning and speed
highMaximum 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:

SettingValueDescription
Max foreground duration30 minutesBefore a task is moved to background
Max background durationMAX_BACKGROUND_DURATION_MS (default 1 hour)Total background execution limit
Allow agent-set durationtrueAgent can override timeout per-task

Next, learn about Frontend Integration.