IntegrationsOpenCode (gateway)

OpenCode with the Langfuse AI Gateway

Beta. The Langfuse AI Gateway is in public beta and can still change.

Requires OpenCode 2.0 or later and an ANTHROPIC and/or OPENAI provider credential. Verified with OpenCode 2.0.25.

For tracing OpenCode without the gateway, see the OpenCode integration.

Setup

Create a gateway API key

Create a gateway API key under Organization settings → AI Gateway → Gateway keys. See API keys.

Export it in the shell you start OpenCode from:

export LANGFUSE_GATEWAY_KEY="<your-gateway-key>"

To keep the setup across sessions, add the export lines to ~/.zshrc.

Configure the providers

Use opencode.json in the project root or ~/.config/opencode/opencode.json:

{
  "$schema": "https://opencode.ai/config.json",
  "model": "anthropic/<model-id>",
  "small_model": "anthropic/<small-model-id>",
  "providers": {
    "anthropic": {
      "settings": {
        "baseURL": "https://gateway.cloud.langfuse.com/anthropic/v1",
        "apiKey": "{env:LANGFUSE_GATEWAY_KEY}"
      },
      "headers": {
        "langfuse-tags": "opencode,<team>",
        "langfuse-environment": "local",
        "langfuse-metadata": "repo:<repo>"
      }
    },
    "openai": {
      "settings": {
        "baseURL": "https://gateway.cloud.langfuse.com/openai/v1",
        "apiKey": "{env:LANGFUSE_GATEWAY_KEY}"
      },
      "headers": {
        "langfuse-tags": "opencode,<team>",
        "langfuse-environment": "local"
      }
    }
  }
}
  • Replace <model-id> and <small-model-id> with model IDs from /models. OpenCode uses small_model for titles, so a small, fast model works best.
  • The Anthropic baseURL includes /v1, because OpenCode appends only /messages. Claude Code and Pi are the opposite.
  • The built-in OpenAI provider uses the Responses API. OpenAI-compatible providers that use Chat Completions are supported by the gateway but have not been verified with OpenCode.
  • To set a session per run, add "langfuse-session-id": "{env:LF_SESSION}". An unset variable sends an empty value, which is ignored.
  • Headers apply to every call from that provider, including title generation and subagents. See request headers.

OpenCode continues to use stored account connections when you override the built-in anthropic or openai provider. Remove those connections before using this configuration, or configure the gateway under a separate provider ID as shown below.

Keep existing account connections

To keep your existing OpenCode account connections, configure the gateway as a separate provider and declare each model manually. For example:

{
  "$schema": "https://opencode.ai/config.json",
  "model": "langfuse/<model-id>",
  "providers": {
    "langfuse": {
      "package": "@opencode/ai/providers/openai-compatible/responses",
      "settings": {
        "baseURL": "https://gateway.cloud.langfuse.com/openai/v1",
        "apiKey": "{env:LANGFUSE_GATEWAY_KEY}"
      },
      "headers": {
        "langfuse-tags": "opencode,<team>",
        "langfuse-environment": "local"
      },
      "models": {
        "<model-id>": {}
      }
    }
  }
}

Add every model you want to use to models, then select it as langfuse/<model-id>.

Verify

Run a prompt:

opencode run "Reply with exactly: pong"

If OpenCode replies, it runs through the gateway.

Turn grouping (experimental, optional)

Experimental. This plugin works with the current gateway but is not an official, published package yet.

With the stock anthropic and openai providers, every model call is its own trace. A small plugin can send OpenCode's user message ID as the turn key, which the gateway already understands. Save it as .opencode/plugin/langfuse-turn.ts in your project or as ~/.config/opencode/plugin/langfuse-turn.ts:

import type { Plugin } from "@opencode-ai/plugin";

export const LangfuseTurn: Plugin = async () => ({
  "chat.headers": async (input, output) => {
    output.headers["x-opencode-request"] = input.message.id;
  },
});
  • All model calls of a prompt, including retries and parallel tool calls, land in one trace. The title call joins the first turn.
  • Subagents (task tool) get their own trace, because they have their own session and user message.
  • Auto-compaction and a message typed while the agent is busy start a new trace.

Troubleshooting and FAQ

How do I tell title calls apart from agent steps?

Title calls have the same session, trace name, and generation name as agent steps. Tell them apart by the small model and zero tools. Some title calls are stored as WARNING "Client cancelled the response", because OpenCode aborts them.

Why do subagents get their own session?

OpenCode starts a new session for subagents (task tool). The parent session ID is stored in agent.parent_session_id.

OpenCode fails with UnknownError: Unexpected server error

The model is missing from OpenCode's catalog, so OpenCode fails locally and sends nothing. Declare the model under providers.<id>.models.

OpenCode ignores the gateway provider

Stored OpenCode account connections take precedence when you override the built-in providers. Remove the existing anthropic and openai connections, or use a separate provider ID and declare its models explicitly.

OpenCode still uses an old key

OpenCode's background service keeps the environment variables from when it started. After exporting or changing LANGFUSE_GATEWAY_KEY, run opencode service restart before retrying.

Why does a wrong model ID show six ERROR generations?

OpenCode retries OpenAI 404 errors up to six times with backoff.


Was this page helpful?

Last updated on