Files
Jordan Ritter 3f1259d060 fix: propagate custom provider config from service adapters to BuiltInAgent (#3283)
Fixes #2903

## The Bug

Azure OpenAI users get `AI_LoadAPIKeyError: OpenAI API key is missing`
despite passing a properly configured `OpenAI` instance to
`OpenAIAdapter`, exactly as shown in the docs.

**Root cause**: `CopilotRuntime.handleServiceAdapter()` discards the
adapter's configured OpenAI instance and constructs a plain string
`"openai/gpt-4o"` to pass to `BuiltInAgent`. The agent's
`resolveModel()` then creates a *brand new* OpenAI provider using only
`OPENAI_API_KEY`, losing all Azure configuration (baseURL, api-key
header, api-version query param).

The V1 adapter's `process()` method — which correctly uses the custom
OpenAI instance — is dead code. It's never called. Only `.provider` and
`.model` strings are extracted.

```
User configures Azure OpenAI instance →
  OpenAIAdapter stores it →
    CopilotRuntime extracts only "openai"/"gpt-4o" strings →
      BuiltInAgent.resolveModel("openai/gpt-4o") →
        createOpenAI({ apiKey: OPENAI_API_KEY }) →
          💥 API key missing / wrong endpoint
```

## Workaround

Until this is merged, users can bypass the broken adapter entirely by
using `BuiltInAgent` directly with the Vercel AI SDK Azure provider:

```typescript
import { createAzure } from "@ai-sdk/azure";
import { CopilotRuntime, copilotRuntimeNodeHttpEndpoint } from "@copilotkit/runtime";
import { BuiltInAgent } from "@copilotkitnext/agent";

const azure = createAzure({
  resourceName: process.env.AZURE_RESOURCE_NAME,
  apiKey: process.env.AZURE_API_KEY,
});

const runtime = new CopilotRuntime({
  agents: {
    default: new BuiltInAgent({
      model: azure("your-deployment-name"),
    }),
  },
});

// Then use copilotRuntimeNodeHttpEndpoint as usual — no serviceAdapter needed
```

This works because `BuiltInAgent` already accepts `LanguageModel`
instances and `resolveModel()` passes them straight through.

## The Fix

Add an optional `getLanguageModel()` method to `CopilotServiceAdapter`.
Adapters that accept custom SDK instances (OpenAI, Anthropic, Groq) now
implement this to produce a pre-configured Vercel AI SDK `LanguageModel`
that carries the full provider configuration. `CopilotRuntime` prefers
this over the string format when creating `BuiltInAgent`.

**Backward compatible**: `getLanguageModel()` is optional on the
interface, so existing custom adapters continue to work unchanged.

| File | Change |
|------|--------|
| `service-adapter.ts` | Add optional `getLanguageModel()` to
`CopilotServiceAdapter` interface |
| `openai-adapter.ts` | Implement `getLanguageModel()` using
`createOpenAI` with the configured instance's `baseURL`/`apiKey` |
| `anthropic-adapter.ts` | Implement `getLanguageModel()` using
`createAnthropic` |
| `groq-adapter.ts` | Implement `getLanguageModel()` using
`createOpenAI` (Groq is OpenAI-compatible) |
| `copilot-runtime.ts` | Prefer `serviceAdapter.getLanguageModel()` over
string model when creating `BuiltInAgent` |
| `package.json` | Add `ai`, `@ai-sdk/openai`, `@ai-sdk/anthropic`
dependencies |

## Test plan

- [x] V2 agent tests pass (101/101)
- [x] V1 runtime build succeeds with no type errors
- [x] V1 runtime tests: same pass/fail as `main` (pre-existing failures
unrelated to this change)
- [ ] Manual: configure Azure OpenAI via `OpenAIAdapter` without
`OPENAI_API_KEY` — should work without `AI_LoadAPIKeyError`
- [ ] Manual: standard OpenAI via `OpenAIAdapter` with `OPENAI_API_KEY`
— should continue working

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-02-26 18:36:11 -04:00
..

CopilotKit - Runtime

banner

✨ Why CopilotKit?

  • Minutes to integrate - Get started quickly with our CLI
  • Framework agnostic - Works with React, Next.js, AGUI and more
  • Production-ready UI - Use customizable components or build with headless UI
  • Built-in security - Prompt injection protection
  • Open source - Full transparency and community-driven
class-support-ecosystem

🧑‍💻 Real life use cases

Deploy deeply-integrated AI assistants & agents that work alongside your users inside your applications.

headless-ui

Documentation

To get started with CopilotKit, please check out the documentation.

Analytics & Privacy

CopilotKit uses Scarf for anonymous usage analytics to help improve the product. Scarf handles all privacy compliance and does not store raw IP addresses. This helps us understand how CopilotKit is being used and prioritize improvements.

Opting Out

To disable analytics, set the environment variable:

export COPILOTKIT_TELEMETRY_DISABLED=true

Or use the DO_NOT_TRACK standard:

export DO_NOT_TRACK=1