> ## Documentation Index
> Fetch the complete documentation index at: https://onr.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Writing Providers

> Add a new Native Provider adapter.

Most providers should start with the DSL rather than a new Go adapter.

## Start with the DSL

Use the provider DSL to describe request routing, response mapping, and usage extraction
first. Add native Go code only when the provider requires request/response rewriting or
runtime-derived metrics that the DSL cannot express yet.

Typical skeleton:

```nginx theme={null}
provider "example" {
  match api = "chat.completions" {
    metrics {
      usage_extract custom;
      finish_reason_extract custom;

      usage_fact input token path="$.usage.input_tokens";
      usage_fact output token path="$.usage.output_tokens";
    }

    upstream {
      set_path "/v1/chat/completions";
    }
  }
}
```

For credential-aware providers such as Vertex AI, keep the runtime-specific values in
`keys.yaml` and reference them through DSL variables:

```nginx theme={null}
provider "vertex" {
  defaults {
    upstream_config {
      base_url = "https://aiplatform.googleapis.com";
    }

    auth {
      oauth_mode google_service_account_file;
      oauth_scope "https://www.googleapis.com/auth/cloud-platform";
      auth_oauth_bearer;
    }

    request {
      set_header "x-goog-user-project" template("${credential.project_id}");
    }
  }

  match api = "gemini.generateContent" {
    upstream {
      set_path template("/v1/projects/${credential.project_id}/locations/${channel.location}/publishers/google/models/${request.model_mapped}:generateContent");
    }
  }
}
```

Use `base_url_override` in `keys.yaml` when a deployment needs a regional endpoint, for example `https://us-central1-aiplatform.googleapis.com`.

## Prefer explicit `usage_fact`

Current `usage_fact` supports three data sources:

* `source=response` (default)
* `source=request`
* `source=derived`

Examples:

```nginx theme={null}
metrics {
  usage_extract custom;

  usage_fact image.generate image count_path="$.data[*]";
  usage_fact image.generate image source=request expr="$.n" fallback=true;
}
```

```nginx theme={null}
metrics {
  usage_extract custom;

  usage_fact audio.tts second source=derived path="$.audio.tts.seconds";
}
```

```nginx theme={null}
metrics {
  usage_extract custom;

  usage_fact server_tool.web_search call count_path="$.output[*]" type="web_search_call" status="completed";
}
```

## When native code is still needed

Keep native Go code as small as possible and treat it as a provider-specific usage
derivation helper, not a second billing system. Native code is still appropriate when:

* the provider returns binary output and usage must be derived from bytes or media duration;
* the provider uses stream or realtime event aggregation;
* the provider requires request rewriting that the DSL cannot express cleanly yet.

For OpenAI specialized APIs, ONR already reuses a shared provider-usage helper layer for:

* image generation and edit counts
* speech duration and audio token estimation
* transcription and translation response usage
* Responses API `web_search_call` counting

The preferred path is:

1. express request/response matching in the DSL,
2. express usage with `usage_fact`,
3. add native helper code only for the irreducible derived pieces.
