zuplo 7.7.9 → 7.7.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -111,19 +111,53 @@ resource serves Claude on either host family the provider accepts.
111
111
  | ---------------------- | ------------------------ | ------------- |
112
112
  | `/v1/chat/completions` | ✅ Forwarded | ✅ Translated |
113
113
  | `/v1/embeddings` | ✅ Embedding models | ❌ |
114
- | `/v1/messages` | ❌ | ✅ Native |
115
- | `/v1/responses` | | ❌ |
114
+ | `/v1/messages` | ❌ | ✅ Forwarded |
115
+ | `/v1/responses` | ✅ Models that serve it | ❌ |
116
116
 
117
- Streaming (`stream: true`) works on chat completions and messages.
117
+ **Forwarded** means the gateway sends your request on in the shape you wrote it.
118
+ **Translated** means it converts between two API shapes, which limits you to the
119
+ parameters listed below.
120
+
121
+ Streaming (`stream: true`) works on chat completions, messages, and responses.
118
122
 
119
123
  The catalog carries three embedding models—`text-embedding-3-small`,
120
124
  `text-embedding-3-large` and `text-embedding-ada-002`—so `/v1/embeddings` works
121
125
  once you deploy one of them and map your deployment to it.
122
126
 
123
- `/v1/responses` isn't served for Azure AI, and a Responses request fails with a
124
- `400` error before any upstream call. Azure does serve a Responses API on its
125
- own endpoint; the gateway doesn't route to it yet. Use `/v1/chat/completions`
126
- instead.
127
+ `/v1/responses` serves the OpenAI Responses API, buffered and streaming. Support
128
+ is **per deployed model**, not per resource: Azure serves Responses for
129
+ particular model and version combinations, and a deployment outside that set
130
+ answers `400` with `The requested operation is unsupported`—which is what an
131
+ embedding deployment on this endpoint returns. Check Azure's own Responses API
132
+ model list for your model and version before relying on it.
133
+
134
+ The management operations on a stored response are forwarded too:
135
+
136
+ | Operation | Does |
137
+ | ------------------------------------ | ------------------------------------- |
138
+ | `GET /v1/responses/{id}` | Retrieves the response |
139
+ | `GET /v1/responses/{id}/input_items` | Lists the input items of one response |
140
+ | `DELETE /v1/responses/{id}` | Deletes the response |
141
+
142
+ Two things they need. Send **`store: true`** on the create, since your resource
143
+ serves them only for a response it kept. And because these requests carry no
144
+ body, there is no `model` in them for the gateway to route on—it uses the app's
145
+ first configured completions model instead, so the app needs a
146
+ [Model Filtering](../policies/ai-gateway-model-filtering-v2-inbound.mdx) policy
147
+ whose completions allow list **starts with an OpenAI-compatible Azure
148
+ deployment**. Without one the gateway answers `400`, asking for preselected
149
+ routing, before reaching Azure.
150
+
151
+ A Claude deployment doesn't work in that first slot, even though the allow list
152
+ accepts it—Claude doesn't serve Responses at all, so the request still fails.
153
+
154
+ Azure also takes a moment to make a new response readable. A `GET` immediately
155
+ after a create can return `404` before it settles, so retry rather than treating
156
+ the first `404` as final.
157
+
158
+ Claude deployments don't serve Responses, so a Claude model on this endpoint
159
+ fails with a `400` error—use
160
+ [`/v1/messages`](#call-claude-models-on-the-messages-api) for those.
127
161
 
128
162
  Claude models work on `/v1/chat/completions` through the gateway's translation
129
163
  to the Messages API, which supports the core chat parameters: `messages`,
@@ -334,20 +368,27 @@ different beta still gets an answer, without that feature.
334
368
  The `model` field in a response doesn't always say what you might expect, and
335
369
  what it says depends on the model you called.
336
370
 
337
- **Claude responses report your deployment name.** Every other response reports
338
- Azure's own model ID, which usually carries a version date the short name
339
- doesn't.
371
+ **Claude models and `/v1/responses` report your deployment name.** Everything
372
+ else reports Azure's own model ID, which usually carries a version date the
373
+ short name doesn't.
340
374
 
341
375
  | Endpoint | Deployment `my-gpt` / `my-embed` / `my-claude` serves | `model` in the response |
342
376
  | ---------------------- | ----------------------------------------------------- | ------------------------- |
343
377
  | `/v1/chat/completions` | `gpt-4.1-mini` | `gpt-4.1-mini-2025-04-14` |
378
+ | `/v1/responses` | `gpt-4.1-mini` | `my-gpt` |
344
379
  | `/v1/embeddings` | `text-embedding-3-small` | `text-embedding-3-small` |
345
380
  | `/v1/messages` | `claude-haiku-4-5` | `my-claude` |
346
381
  | `/v1/chat/completions` | `claude-haiku-4-5` | `my-claude` |
347
382
 
383
+ The same deployment reports two different values depending on the endpoint you
384
+ call it on: chat completions answers with Azure's dated ID, Responses with the
385
+ name you gave the deployment. That's Azure's own behavior on each surface, not
386
+ something the gateway changes.
387
+
348
388
  A Claude model reports your deployment name on both endpoints—the native
349
- Messages API and the chat completions translation—because the gateway builds
350
- those responses itself and echoes back the model you asked for.
389
+ Messages API and the chat completions translation—but for a different reason:
390
+ there the gateway builds the response itself and echoes back the model you asked
391
+ for.
351
392
 
352
393
  One exception, if you stream Claude: the `message_start` event reports Azure's
353
394
  ID (`claude-haiku-4-5-20251001`) rather than your deployment name, because the
@@ -388,8 +429,23 @@ resources deploy Claude. Confirm the deployment exists and is Anthropic-format,
388
429
  and see [Deploying Claude on Foundry](#deploying-claude-on-foundry) for the
389
430
  requirements Azure applies to those deployments.
390
431
 
391
- **A `400` error names `/v1/responses`.** The gateway doesn't serve the Responses
392
- API for Azure AI. Use `/v1/chat/completions`.
432
+ **A `400` error names `/v1/responses`.** Two different causes, and the message
433
+ tells you which. If it names the provider or the endpoint, the deployment is a
434
+ **Claude** one—Claude doesn't serve Responses, so call
435
+ [`/v1/messages`](#call-claude-models-on-the-messages-api) instead, or
436
+ `/v1/chat/completions` for the translated form. If it says
437
+ `The requested operation is unsupported`, that came from Azure: the deployed
438
+ model doesn't serve Responses. Support is per model and version, so check
439
+ Azure's Responses API model list—an embedding deployment always fails this way.
440
+
441
+ **A `400` asks for preselected routing.** You called `GET` or `DELETE` on a
442
+ response, or listed its input items. Those requests carry no body, so there is
443
+ no `model` for the gateway to route on and it falls back to the app's first
444
+ configured completions model. Add a
445
+ [Model Filtering](../policies/ai-gateway-model-filtering-v2-inbound.mdx) policy
446
+ to the app with an **OpenAI-compatible** Azure deployment first in its
447
+ completions allow list. A Claude deployment in that slot still fails, since
448
+ Claude doesn't serve Responses.
393
449
 
394
450
  **A model in the picker fails at request time.** The picker lists the full Azure
395
451
  catalog, but a model only works once you deploy it in your resource, and model
@@ -72,9 +72,13 @@ either way.
72
72
  | ---------------------- | ---------------------------- | ------------- |
73
73
  | `/v1/chat/completions` | ✅ Forwarded | ✅ Translated |
74
74
  | `/v1/responses` | ✅ Models that serve it | ❌ |
75
- | `/v1/messages` | ❌ | ✅ Native |
75
+ | `/v1/messages` | ❌ | ✅ Forwarded |
76
76
  | `/v1/embeddings` | ❌ Mantle has no such models | ❌ |
77
77
 
78
+ **Forwarded** means the gateway sends your request on in the shape you wrote it.
79
+ **Translated** means it converts between two API shapes, which limits you to the
80
+ parameters listed below.
81
+
78
82
  Streaming (`stream: true`) works on all three serving endpoints.
79
83
 
80
84
  On the OpenAI-compatible side, endpoint support is per model, decided by AWS:
@@ -10,6 +10,17 @@ You can configure [Claude Code](https://www.claude.com/product/claude-code) to
10
10
  send its model requests through the Zuplo AI Gateway, so the gateway
11
11
  authenticates, meters, and routes every Claude Code session.
12
12
 
13
+ The gateway can authenticate to Anthropic in two ways. Pick one before you
14
+ configure Claude Code:
15
+
16
+ | Approach | The gateway sends Anthropic | Claude Code sends the gateway |
17
+ | --------------------------------------------------------- | --------------------------------------------------------------------- | ------------------------------------------------------------------------- |
18
+ | [Configured provider key](#use-a-configured-provider-key) | The Anthropic API key saved on your provider | The app's API key as `ANTHROPIC_AUTH_TOKEN` |
19
+ | [Your Claude subscription](#use-your-claude-subscription) | The credential from your `claude.ai` login, such as a Claude Max plan | The app's API key in a `zp-gateway-api-key` header, plus your login as-is |
20
+
21
+ Both approaches share the same provider, team, and app setup, and the same model
22
+ configuration.
23
+
13
24
  ## Claude Code Setup
14
25
 
15
26
  <Stepper>
@@ -19,12 +30,18 @@ authenticates, meters, and routes every Claude Code session.
19
30
 
20
31
  2. [Set up a new team](../managing-teams.mdx)
21
32
 
22
- 3. Create a [new app](../managing-apps.mdx) to use with Claude Code and assign
33
+ 3. If you plan to use your Claude subscription, configure the team's
34
+ [API Key Authentication policy](#configure-the-api-key-authentication-policy)
35
+ for passthrough before you create the app
36
+
37
+ 4. Create a [new app](../managing-apps.mdx) to use with Claude Code and assign
23
38
  it to the team you created
24
39
 
25
- 4. Copy the **API URL** and **API Key** shown at the top of the app page
40
+ 5. Copy the **API URL** and **API Key** shown at the top of the app page
26
41
 
27
- 5. Add the API key, gateway URL, and model mappings to `.claude/settings.json`
42
+ 6. Add the gateway URL, the app's API key, and model mappings to
43
+ `.claude/settings.json`, following the section below for the approach you
44
+ chose
28
45
 
29
46
  </Stepper>
30
47
 
@@ -45,7 +62,7 @@ The gateway routes every request using `providerName/model`. The provider prefix
45
62
  picks which of your providers handles the request — a gateway can contain
46
63
  several providers that serve Anthropic models.
47
64
 
48
- ### Using settings.json
65
+ ### Where Claude Code reads its settings
49
66
 
50
67
  You can configure Claude Code either globally or per project by editing the
51
68
  settings file:
@@ -53,7 +70,24 @@ settings file:
53
70
  - **Global:** `~/.claude/settings.json`
54
71
  - **Project-specific:** `.claude/settings.json` in your project directory
55
72
 
56
- Add the following environment configuration to the settings file:
73
+ Each approach below shows the `env` and `modelOverrides` blocks to add to that
74
+ file. Restart Claude Code after saving it, and all your Claude Code LLM requests
75
+ route through the AI Gateway.
76
+
77
+ :::note
78
+
79
+ Claude Code appends `/v1/messages` to the base URL itself, so
80
+ `ANTHROPIC_BASE_URL` is the app's URL _without_ the `/v1` suffix.
81
+
82
+ :::
83
+
84
+ ## Use a configured provider key
85
+
86
+ With this approach the gateway calls Anthropic with the API key you saved on the
87
+ [provider](../managing-providers.mdx). Claude Code presents only the app's API
88
+ key, and Anthropic bills the account that owns the provider key.
89
+
90
+ Add the following configuration to the settings file:
57
91
 
58
92
  ```json
59
93
  {
@@ -65,22 +99,155 @@ Add the following environment configuration to the settings file:
65
99
  "ANTHROPIC_DEFAULT_OPUS_MODEL": "anthropic/claude-opus-5",
66
100
  "ANTHROPIC_DEFAULT_SONNET_MODEL": "anthropic/claude-sonnet-5",
67
101
  "ANTHROPIC_DEFAULT_HAIKU_MODEL": "anthropic/claude-haiku-4-5",
68
- "ANTHROPIC_DEFAULT_FABLE_MODEL": "anthropic/claude-fable-5"
102
+ "ANTHROPIC_DEFAULT_FABLE_MODEL": "anthropic/claude-fable-5-1"
103
+ },
104
+ "modelOverrides": {
105
+ "claude-opus-5": "anthropic/claude-opus-5",
106
+ "claude-sonnet-5": "anthropic/claude-sonnet-5",
107
+ "claude-haiku-4-5-20251001": "anthropic/claude-haiku-4-5-20251001",
108
+ "claude-fable-5-1": "anthropic/claude-fable-5-1"
69
109
  }
70
110
  }
71
111
  ```
72
112
 
73
- :::note
113
+ `ANTHROPIC_AUTH_TOKEN` replaces whatever login Claude Code would otherwise use,
114
+ so this approach doesn't consume your Claude subscription.
74
115
 
75
- Claude Code appends `/v1/messages` to the base URL itself, so
76
- `ANTHROPIC_BASE_URL` is the app's URL _without_ the `/v1` suffix.
116
+ ## Use your Claude subscription
77
117
 
78
- :::
118
+ With this approach Claude Code stays signed in to `claude.ai` — for example with
119
+ a Claude Max plan — and the gateway forwards that login credential to Anthropic
120
+ as the request's provider credential. The app's API key travels in a separate
121
+ `zp-gateway-api-key` header, so the gateway still authenticates the app, applies
122
+ its policy chain, and meters its usage.
123
+
124
+ Two pieces of configuration make this work: the app's **API Key Authentication**
125
+ policy accepts the app key from the `zp-gateway-api-key` header and passes the
126
+ `Authorization` header through, and Claude Code sends both headers.
127
+
128
+ ### Configure the API Key Authentication policy
129
+
130
+ The [API Key Authentication](../../policies/ai-gateway-auth-v2-inbound.mdx)
131
+ policy needs three options for passthrough:
132
+
133
+ | Option | Value | Effect |
134
+ | ----------------------- | -------------------- | -------------------------------------------------------- |
135
+ | `credentialPassthrough` | On | Forward the caller's `Authorization` header to Anthropic |
136
+ | `authHeader` | `zp-gateway-api-key` | Read the app's API key from this header instead |
137
+ | `authScheme` | Empty value | The header holds the bare key, with no `Bearer` prefix |
138
+
139
+ You can set these options on the team's
140
+ [policy template](../policy-templates.mdx), so every app created in the team
141
+ starts with passthrough enabled, or on a single app's **Policies** tab. The
142
+ steps below use the team template; the app's policy editor works the same way.
143
+
144
+ <Stepper>
79
145
 
80
- Restart Claude and it will switch to using your new AI Gateway configuration and
81
- all your Claude Code LLM requests will route through the AI Gateway.
146
+ 1. Open the team in the Zuplo Portal and select its **Policy Template** tab.
82
147
 
83
- ### Configure every Claude Code model variable
148
+ 2. Click the edit (pencil) icon on the **API Key Authentication** entry.
149
+
150
+ 3. Turn on **credentialPassthrough**.
151
+
152
+ 4. Set **authHeader** to `zp-gateway-api-key`.
153
+
154
+ 5. Leave **authScheme** blank and click **Use an empty value for authScheme**.
155
+ The field then reports "Empty value set. The default (Bearer) is not
156
+ applied." Clearing the field alone isn't enough: a blank field omits the
157
+ option, so the `Bearer` default still applies and every request fails with
158
+ `401 Invalid Authorization Scheme`.
159
+
160
+ 6. Click **Apply**, then **Save changes**.
161
+
162
+ </Stepper>
163
+
164
+ The **JSON** editor mode shows the equivalent options:
165
+
166
+ ```json
167
+ {
168
+ "credentialPassthrough": true,
169
+ "authHeader": "zp-gateway-api-key",
170
+ "authScheme": ""
171
+ }
172
+ ```
173
+
174
+ ### The provider still needs an API key
175
+
176
+ The Portal requires an API key to save an Anthropic provider, and passthrough
177
+ requests never send it: the request to Anthropic carries the caller's credential
178
+ instead. Anything else that uses this provider's configured credential still
179
+ needs a real key. That includes apps on this gateway that don't use passthrough
180
+ and any
181
+ [Fallback Model](../../policies/ai-gateway-fallback-model-v2-inbound.mdx)
182
+ target, because fallback requests use the provider's configured credential
183
+ rather than the caller's. If nothing on the gateway uses the configured
184
+ credential, a placeholder value works.
185
+
186
+ The app's playground in the Portal sends the app key as a bearer token in
187
+ `Authorization`, so it can't call an app that uses passthrough. Test the app
188
+ from Claude Code instead, as described below.
189
+
190
+ ### Configure Claude Code
191
+
192
+ Add the following configuration to the settings file. Don't set
193
+ `ANTHROPIC_AUTH_TOKEN` or `ANTHROPIC_API_KEY` here or in your shell: either one
194
+ replaces your `claude.ai` login, and the gateway would then forward that value
195
+ to Anthropic as the credential.
196
+
197
+ ```json
198
+ {
199
+ "env": {
200
+ "ANTHROPIC_BASE_URL": "https://my-gateway-main-2e18f50.zuplo.app/config_fe0a04972d2848e0a94ae4b8bcd1497e",
201
+ "ANTHROPIC_CUSTOM_HEADERS": "zp-gateway-api-key: <your-ai-gateway-app-api-key>",
202
+ "ANTHROPIC_MODEL": "anthropic/claude-sonnet-5",
203
+ "ANTHROPIC_SMALL_FAST_MODEL": "anthropic/claude-haiku-4-5",
204
+ "ANTHROPIC_DEFAULT_OPUS_MODEL": "anthropic/claude-opus-5",
205
+ "ANTHROPIC_DEFAULT_SONNET_MODEL": "anthropic/claude-sonnet-5",
206
+ "ANTHROPIC_DEFAULT_HAIKU_MODEL": "anthropic/claude-haiku-4-5",
207
+ "ANTHROPIC_DEFAULT_FABLE_MODEL": "anthropic/claude-fable-5-1"
208
+ },
209
+ "modelOverrides": {
210
+ "claude-opus-5": "anthropic/claude-opus-5",
211
+ "claude-sonnet-5": "anthropic/claude-sonnet-5",
212
+ "claude-haiku-4-5-20251001": "anthropic/claude-haiku-4-5-20251001",
213
+ "claude-fable-5-1": "anthropic/claude-fable-5-1"
214
+ }
215
+ }
216
+ ```
217
+
218
+ `ANTHROPIC_CUSTOM_HEADERS` adds the `zp-gateway-api-key` header to every request
219
+ Claude Code makes, while Claude Code keeps sending its own `Authorization`
220
+ header from your login. The gateway consumes those incoming headers, uses the
221
+ login credential to authenticate the Anthropic request, and never sends your app
222
+ key to Anthropic.
223
+
224
+ ### Verify the subscription setup
225
+
226
+ Restart Claude Code, then confirm which credential it's using and send one
227
+ request through the gateway:
228
+
229
+ ```bash
230
+ claude auth status --text
231
+ claude -p "Reply with the single word OK"
232
+ ```
233
+
234
+ The first command should report that you're signed in with your `claude.ai`
235
+ account rather than an API key or auth token. The second returns a short reply,
236
+ and the request appears in the app's usage in the Zuplo Portal. In an
237
+ interactive session, `/status` shows the same login information.
238
+
239
+ If the request fails:
240
+
241
+ - `401` with `Invalid Authorization Scheme` — `authScheme` still has its
242
+ `Bearer` default. Set it to an explicit empty value in the policy.
243
+ - `401` with `Header configured by options.authHeader is missing` — Claude Code
244
+ didn't send `zp-gateway-api-key`. Check `ANTHROPIC_CUSTOM_HEADERS`.
245
+ - `401` with `credentialPassthrough requires a non-empty Authorization header` —
246
+ Claude Code isn't signed in. Run `claude` and use `/login`.
247
+ - An authentication error from Anthropic — Anthropic rejected the forwarded
248
+ login credential. Sign in to Claude Code again.
249
+
250
+ ## Configure every Claude Code model variable
84
251
 
85
252
  The model ids in these examples reflect what was current when this page was
86
253
  written, and ids differ across providers — a Bedrock provider serves different
@@ -91,23 +258,27 @@ it currently serves, and use those ids.
91
258
  None of Claude Code's built-in model names carry a provider prefix, so each of
92
259
  the model variables above must be set to a prefixed reference:
93
260
 
94
- - `ANTHROPIC_MODEL` — the main model. Required: without it Claude Code sends its
95
- built-in default model unprefixed and the first request fails.
261
+ - `ANTHROPIC_MODEL` — the startup model. Set it to a prefixed reference so the
262
+ gateway can route the first request.
96
263
  - `ANTHROPIC_SMALL_FAST_MODEL` — the model for background tasks.
97
264
  - `ANTHROPIC_DEFAULT_OPUS_MODEL`, `ANTHROPIC_DEFAULT_SONNET_MODEL`,
98
265
  `ANTHROPIC_DEFAULT_HAIKU_MODEL`, `ANTHROPIC_DEFAULT_FABLE_MODEL` — what the
99
266
  `opus`/`sonnet`/`haiku`/`fable` aliases resolve to, so `claude --model opus`
100
267
  and `/model sonnet` keep working. In these examples,
101
- `ANTHROPIC_DEFAULT_FABLE_MODEL` maps `fable` to `anthropic/claude-fable-5`.
268
+ `ANTHROPIC_DEFAULT_FABLE_MODEL` maps `fable` to `anthropic/claude-fable-5-1`.
269
+
270
+ Claude Code's `/model` picker can select either an alias or an exact model ID.
271
+ `ANTHROPIC_DEFAULT_*_MODEL` maps aliases to gateway model names;
272
+ [`modelOverrides`](https://code.claude.com/docs/en/model-config#override-model-ids-per-version)
273
+ maps exact IDs. The examples configure both so either selection works through
274
+ the gateway.
102
275
 
103
276
  :::caution{title='HTTP 400: model must use "providerName/model"'}
104
277
 
105
- If Claude Code fails immediately with
106
- `The request body model must use "providerName/model"`, the request carried a
107
- model name without a provider prefix. The tier alias variables
108
- (`ANTHROPIC_DEFAULT_*_MODEL`) alone don't prevent this — they don't cover Claude
109
- Code's built-in default model. Always set `ANTHROPIC_MODEL` to a prefixed model
110
- reference.
278
+ This error means the selected model lacks its provider prefix. At startup, check
279
+ `ANTHROPIC_MODEL`. After choosing a picker entry, check its `modelOverrides`
280
+ entry, or type `/model fable` to use the configured alias. Restart Claude Code
281
+ after editing the settings file.
111
282
 
112
283
  :::
113
284
 
@@ -0,0 +1,165 @@
1
+ ---
2
+ title: GitHub Copilot
3
+ sidebar_label: GitHub Copilot
4
+ description:
5
+ Route GitHub Copilot in VS Code and the Copilot CLI through an AI Gateway app
6
+ so the gateway authenticates, meters, and routes every Copilot model request.
7
+ ---
8
+
9
+ [GitHub Copilot](https://github.com/features/copilot) can use your own model
10
+ endpoint instead of GitHub's hosted models — the
11
+ [Copilot CLI](https://docs.github.com/en/copilot/how-tos/copilot-cli/customize-copilot/use-byok-models)
12
+ through environment variables, and VS Code through its
13
+ [Custom Endpoint provider](https://code.visualstudio.com/docs/agent-customization/language-models#_add-a-custom-endpoint-model).
14
+ Point that endpoint at an AI Gateway app, and every Copilot chat and agent
15
+ request is authenticated with the app's key, metered against the app's budgets,
16
+ and limited to the models you allow. Developers keep using Copilot exactly as
17
+ before; the app's page in the Zuplo Portal shows their requests, tokens, and
18
+ spend as they work.
19
+
20
+ ## Before you start
21
+
22
+ <Stepper>
23
+
24
+ 1. Create a [provider](../managing-providers.mdx) for the models Copilot will
25
+ use, such as OpenAI or Anthropic
26
+
27
+ 2. [Create a team](../managing-teams.mdx) for the developers using Copilot
28
+
29
+ 3. Create an [app](../managing-apps.mdx) for Copilot and assign it to the team
30
+
31
+ 4. Copy the **API URL** and **API Key** shown at the top of the app page
32
+
33
+ </Stepper>
34
+
35
+ The gateway names models as `providerName/model`, where `providerName` is the
36
+ name you gave the provider. The examples below use `openai` and `anthropic`;
37
+ substitute your own provider names.
38
+
39
+ ## Copilot CLI
40
+
41
+ The CLI reads its provider from four environment variables. Set the base URL to
42
+ the app's API URL plus `/v1`, and name a model that supports tool calls, such as
43
+ GPT-4.1:
44
+
45
+ ```bash
46
+ export COPILOT_PROVIDER_BASE_URL="https://my-gateway-main-2e18f50.zuplo.app/config_fe0a04972d2848e0a94ae4b8bcd1497e/v1"
47
+ export COPILOT_PROVIDER_API_KEY="<your-ai-gateway-app-api-key>"
48
+ export COPILOT_PROVIDER_TYPE="openai"
49
+ export COPILOT_MODEL="openai/gpt-4.1-mini"
50
+ ```
51
+
52
+ Start `copilot` from the same shell. Every request in the session now passes
53
+ through the gateway.
54
+
55
+ For a Claude model, use the `anthropic` provider type with the app's API URL
56
+ without `/v1` — the CLI appends `/v1/messages` itself — and pass the key as a
57
+ bearer token, which is the header the gateway reads:
58
+
59
+ ```bash
60
+ export COPILOT_PROVIDER_BASE_URL="https://my-gateway-main-2e18f50.zuplo.app/config_fe0a04972d2848e0a94ae4b8bcd1497e"
61
+ export COPILOT_PROVIDER_BEARER_TOKEN="<your-ai-gateway-app-api-key>"
62
+ export COPILOT_PROVIDER_TYPE="anthropic"
63
+ export COPILOT_MODEL="anthropic/claude-sonnet-4-6"
64
+ ```
65
+
66
+ The CLI speaks Chat Completions and the Messages API and sets a `temperature` on
67
+ every request. GPT-4.1, GPT-4o, Claude Sonnet 4.6, and Claude Haiku 4.5 all
68
+ accept that; OpenAI's GPT-5.x reasoning models and Claude Sonnet 5 don't, so use
69
+ them from VS Code instead.
70
+
71
+ ## VS Code
72
+
73
+ Add the gateway as a Custom Endpoint provider, then describe your models in the
74
+ configuration file VS Code opens.
75
+
76
+ <Stepper>
77
+
78
+ 1. Run **Chat: Manage Language Models** from the Command Palette
79
+
80
+ 2. Select **Add Models**, then **Custom Endpoint**
81
+
82
+ 3. Enter a name for the group, such as `Zuplo AI Gateway`, and paste the app's
83
+ API key
84
+
85
+ 4. Select **Chat Completions** as the API type
86
+
87
+ 5. Replace the `models` array in the `chatLanguageModels.json` file that opens
88
+ with the models you want in the picker
89
+
90
+ </Stepper>
91
+
92
+ This configuration offers a GPT model and a Claude model from one app:
93
+
94
+ ```json
95
+ [
96
+ {
97
+ "name": "Zuplo AI Gateway",
98
+ "vendor": "customendpoint",
99
+ "apiKey": "${input:chat.lm.secret.321f64a2}",
100
+ "models": [
101
+ {
102
+ "id": "openai/gpt-5.6",
103
+ "name": "GPT-5.6 (Zuplo)",
104
+ "apiType": "responses",
105
+ "url": "https://my-gateway-main-2e18f50.zuplo.app/config_fe0a04972d2848e0a94ae4b8bcd1497e/v1/responses",
106
+ "toolCalling": true,
107
+ "vision": true,
108
+ "maxInputTokens": 128000,
109
+ "maxOutputTokens": 16000,
110
+ "requestHeaders": { "Authorization": "Bearer ${apiKey}" }
111
+ },
112
+ {
113
+ "id": "anthropic/claude-sonnet-5",
114
+ "name": "Claude Sonnet 5 (Zuplo)",
115
+ "apiType": "messages",
116
+ "url": "https://my-gateway-main-2e18f50.zuplo.app/config_fe0a04972d2848e0a94ae4b8bcd1497e/v1/messages",
117
+ "toolCalling": true,
118
+ "vision": true,
119
+ "maxInputTokens": 200000,
120
+ "maxOutputTokens": 64000,
121
+ "requestHeaders": { "Authorization": "Bearer ${apiKey}" }
122
+ }
123
+ ]
124
+ }
125
+ ]
126
+ ```
127
+
128
+ Three lines carry the integration:
129
+
130
+ - **`apiKey`** is a reference to the key you pasted, which VS Code keeps in its
131
+ secret storage and reads at request time. Leave it as written; to change the
132
+ key, use **Chat: Manage Language Models**.
133
+ - **`requestHeaders`** sends the key as `Authorization: Bearer <key>`, the
134
+ header the gateway's
135
+ [Authentication policy](../../policies/ai-gateway-auth-v2-inbound.mdx) reads.
136
+ VS Code's default header depends on the API type, so set it on every model.
137
+ - **`apiType`** and the `url` path select the API the model speaks: `responses`
138
+ for OpenAI's reasoning models such as GPT-5.x, `messages` for Claude through
139
+ the gateway's native Messages passthrough, and `chat-completions` with a
140
+ `/v1/chat/completions` URL for other chat models. Set it on each model so
141
+ models with different APIs share one entry in the picker.
142
+
143
+ Save the file and pick a model from the chat model picker.
144
+
145
+ ## What routes through the gateway
146
+
147
+ Chat and agent requests, on both surfaces. Copilot's inline code completions
148
+ stay on GitHub's infrastructure. The app's
149
+ [Model Filtering](../../policies/ai-gateway-model-filtering-v2-inbound.mdx)
150
+ policy decides which models Copilot may use.
151
+
152
+ ## Troubleshooting
153
+
154
+ Copilot reports gateway errors as a retry failure, such as
155
+ `502 token expired or invalid: 401`. The gateway's own response is in the
156
+ **GitHub Copilot Chat** channel of VS Code's Output panel, or in the CLI's error
157
+ text.
158
+
159
+ | The gateway responds | Cause | Fix |
160
+ | ----------------------------------------------------------------- | ------------------------------------------------------------------------------ | ----------------------------------------------------------------------- |
161
+ | `401` `Header configured by options.authHeader is missing` | The key was sent as `x-api-key` | VS Code: add `requestHeaders`. CLI: use `COPILOT_PROVIDER_BEARER_TOKEN` |
162
+ | `401` `Invalid Authorization Scheme` | VS Code's `apiKey` was replaced with the key itself, so the key sent was empty | Re-enter the key with **Chat: Manage Language Models** |
163
+ | `404` | The `url` stops at the app ID | Append `/v1/responses`, `/v1/messages`, or `/v1/chat/completions` |
164
+ | `Function tools with reasoning_effort are not supported` | A GPT-5.x model on Chat Completions | VS Code: `"apiType": "responses"`. CLI: use a GPT-4.1 or Claude model |
165
+ | `'temperature' does not support 0` or `temperature is deprecated` | The CLI's temperature setting on a GPT-5.x or Claude Sonnet 5 model | Use GPT-4.1, GPT-4o, Claude Sonnet 4.6, or Claude Haiku 4.5 |
@@ -38,7 +38,7 @@ The following capabilities are supported across providers:
38
38
  | Google | ✅ | ✅ | ❌ | ❌ |
39
39
  | Mistral | ✅ | ✅ | ❌ | ❌ |
40
40
  | xAI | ✅ | ✅ | ❌ | ❌ |
41
- | Azure AI | ✅ | ✅ | | ✅ |
41
+ | Azure AI | ✅ | ✅ | | ✅ |
42
42
  | Bedrock Mantle | ✅ | ❌ | ✅ | ✅ |
43
43
  | Vertex AI | ✅ | ✅ | ❌ | ✅ |
44
44
  | Zuplo Demo | ✅ | ❌ | ❌ | ❌ |
@@ -54,8 +54,12 @@ Messages (plus chat completions through translation), while its other models
54
54
  serve chat completions and—per model—Responses. See
55
55
  [Using Bedrock Mantle](./bedrock-mantle.mdx#supported-endpoints-by-model-family).
56
56
 
57
- Azure AI's Messages support needs a Microsoft Foundry resource, since Claude
58
- can't be deployed on an Azure OpenAI resource. Azure also addresses models by
57
+ Azure AI's capabilities split by model family, and within the OpenAI-compatible
58
+ family they split per deployed model: a chat model serves chat completions and—
59
+ per model and version—Responses, while an embedding model serves embeddings and
60
+ neither of the others. Claude serves Messages (plus chat completions through
61
+ translation) and needs a Microsoft Foundry resource, since Claude can't be
62
+ deployed on an Azure OpenAI resource. Azure also addresses models by
59
63
  **deployment name** rather than by published model ID, so a deployment named
60
64
  differently from the model it serves needs mapping for the gateway to price it.
61
65
  See [Using Azure AI](./azure-ai.mdx#azure-serves-deployments-not-model-names).
@@ -76,8 +80,8 @@ name you give the provider configuration. See the
76
80
  configuration covers both kinds of resource, and which capabilities apply
77
81
  depends on the resource and the model:
78
82
 
79
- - An **Azure OpenAI** resource deploys OpenAI models and serves chat completions
80
- and embeddings.
83
+ - An **Azure OpenAI** resource deploys OpenAI models and serves chat
84
+ completions, embeddings, and the Responses API.
81
85
  - A **Microsoft Foundry** resource serves those plus every Foundry model
82
86
  family—Grok, DeepSeek, Llama, Mistral, Phi, Kimi and more—and serves **Claude
83
87
  models** on the native Anthropic Messages API, with chat completions through
@@ -67,5 +67,5 @@ list—so clients that can't set a model still work.
67
67
  | ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
68
68
  | `/v1/chat/completions` | Chat completions for every provider |
69
69
  | `/v1/embeddings` | Embeddings for the providers marked in the [capability matrix](./providers.mdx#supported-providers) |
70
- | `/v1/responses` | OpenAI Responses API: OpenAI, and [Bedrock Mantle](./bedrock-mantle.mdx) OpenAI-compatible models that serve it |
70
+ | `/v1/responses` | OpenAI Responses API: OpenAI, and the OpenAI-compatible models that serve it on [Azure AI](./azure-ai.mdx) and [Bedrock Mantle](./bedrock-mantle.mdx) |
71
71
  | `/v1/messages` | Anthropic Messages API: Anthropic, and the Claude models of [Azure AI](./azure-ai.mdx), [Bedrock Mantle](./bedrock-mantle.mdx) and [Vertex AI](./vertex-ai.mdx) |
@@ -129,7 +129,12 @@ send your traffic and your spend to someone else's Google Cloud project.
129
129
  | `/v1/chat/completions` | ✅ Forwarded | ❌ |
130
130
  | `/v1/embeddings` | ✅ Translated | ❌ |
131
131
  | `/v1/responses` | ❌ | ❌ |
132
- | `/v1/messages` | ❌ | ✅ Native |
132
+ | `/v1/messages` | ❌ | ✅ Forwarded |
133
+
134
+ **Forwarded** means the gateway sends your request on in the shape you wrote it.
135
+ **Translated** means it converts between two API shapes—for embeddings, from the
136
+ OpenAI shape onto Vertex's own embedding APIs, which is invisible from your
137
+ side.
133
138
 
134
139
  Streaming (`stream: true`) works on chat completions and on Messages.
135
140