How to Create a Custom Provider Integration for an Unsupported Model in Prime Agent
To create a custom provider integration for an unsupported model in Prime Agent, implement a provider registration object with a unique API identifier, define your model specifications, and provide a streamSimple function that translates Prime Agent's unified Context into the provider's request format while emitting AssistantMessageEvent streams.
Prime Agent supports a plug-in architecture that allows developers to extend its capabilities beyond built-in LLM providers. This guide walks through the exact steps to register a new provider for models not natively supported by the framework, referencing the core types and registration patterns found in the PrimeIntellect-ai/prime-agent repository.
Understanding the Core Provider Types
Before implementing a custom provider, you must understand the type definitions that govern all provider integrations. The core interfaces live in packages/ai/src/types.ts, which defines the contracts for Api, Provider, Model<TApi>, and SimpleStreamOptions.
The Model<TApi> interface requires you to specify capabilities such as context window size, supported input modalities (text, image), reasoning capabilities, and pricing metrics. Each model must reference a unique API identifier that distinguishes it from built-in providers. The SimpleStreamOptions type defines the optional parameters passed to your streaming function, including API keys and abort signals.
Your custom provider must implement the streamSimple function signature: it receives a Model instance, a Context object containing the conversation history, and optional SimpleStreamOptions, then returns an AssistantMessageEventStream that follows Prime Agent's event protocol.
Implementing the Streaming Function
The streamSimple function serves as the translation layer between Prime Agent's unified interface and the target provider's API. This function must return an AssistantMessageEventStream that emits specific event types defined in packages/ai/src/types.ts.
Your implementation should handle the following event types:
start– Emitted immediately with a partialAssistantMessageobject containing metadatatext_delta– Contains incremental text content from the modeltoolcall_startandtoolcall_delta– For function calling capabilitiesdone– Signals successful completion with the final stop reasonerror– Indicates failure with error details
The function must convert Prime Agent's Context format into the provider-specific request payload. For example, you might map the context messages to OpenAI-style chat completion formats or Anthropic's message structures, depending on your target API.
Registering Your Custom Provider
Registration occurs through the ExtensionAPI.registerProvider method exposed by the coding-agent package. Your extension entry point receives an ExtensionAPI instance and must call registerProvider with a configuration object containing:
api– A unique string identifier (must not conflict with built-inKnownApivalues)baseUrl– The root endpoint for the provider's HTTP APIapiKey– The environment variable name holding the static API key (if applicable)models– An array ofModeldescriptors defining available models, their costs, and capabilitiesoauth– Optional OAuth configuration object withlogin,refreshToken, andgetApiKeymethodsstreamSimple– Your implemented streaming function
Once registered, Prime Agent automatically adds these models to the internal registry, making them selectable via the /model command without requiring core code modifications.
Handling Authentication
Prime Agent delegates credential management to the auth-storage subsystem found in packages/coding-agent/src/core/auth-storage.ts. You have two authentication patterns available for custom providers.
API Key Authentication is the simplest approach. Specify the apiKey field in your registration object with the name of an environment variable (e.g., "MY_CUSTOM_API_KEY"). The auth-storage system automatically retrieves this value and passes it through SimpleStreamOptions when calling your streamSimple function.
OAuth Authentication requires implementing three methods in the oauth configuration object: login to initiate the authorization flow, refreshToken to handle token renewal, and getApiKey to extract the usable credential from stored OAuth data. Reference the example in packages/ai/src/utils/oauth/anthropic.ts for a working implementation pattern that you can adapt to other OAuth-capable services.
Complete Working Example
The following implementation demonstrates a custom provider for a hypothetical API service. This pattern mirrors the reference implementation found in packages/coding-agent/examples/extensions/custom-provider-anthropic/index.ts.
First, implement the streaming function that handles the HTTP translation:
import {
Model,
Api,
Context,
SimpleStreamOptions,
createAssistantMessageEventStream,
AssistantMessageEventStream
} from '@prime-intellect-ai/ai';
export function streamMyProvider(
model: Model<Api>,
context: Context,
options?: SimpleStreamOptions,
): AssistantMessageEventStream {
const stream = createAssistantMessageEventStream();
(async () => {
const output = {
role: "assistant" as const,
content: [],
api: model.api,
provider: model.provider,
model: model.id,
usage: {
input: 0,
output: 0,
cacheRead: 0,
cacheWrite: 0,
totalTokens: 0,
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 }
},
stopReason: "stop" as const,
timestamp: Date.now(),
};
stream.push({ type: "start", partial: output });
const payload = {
model: model.id,
messages: context.messages,
stream: true,
max_tokens: model.maxTokens,
};
const response = await fetch(`${model.baseUrl}/v1/chat/completions`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${options?.apiKey}`
},
body: JSON.stringify(payload),
});
for await (const chunk of response.body as any) {
const text = parseChunkToText(chunk);
if (text) {
stream.push({ type: "text_delta", text });
}
}
stream.push({ type: "done", reason: "stop", message: output });
stream.end();
})().catch(err => {
output.stopReason = "error";
output.errorMessage = err.message;
stream.push({ type: "error", reason: "error", error: output });
stream.end();
});
return stream;
}
Then, register the provider through your extension's entry point:
import { ExtensionAPI } from '@prime-intellect-ai/coding-agent';
export default function (pi: ExtensionAPI) {
pi.registerProvider("my-custom", {
baseUrl: "https://api.myprovider.com",
apiKey: "MY_CUSTOM_API_KEY",
api: "my-custom-api",
models: [
{
id: "my-model-1",
name: "My Model 1",
reasoning: true,
input: ["text", "image"],
cost: { input: 0.5, output: 1.5, cacheRead: 0.1, cacheWrite: 0.2 },
contextWindow: 100000,
maxTokens: 32768,
},
],
streamSimple: streamMyProvider,
});
}
Summary
-
Core types for custom providers are defined in
packages/ai/src/types.ts, includingModel<TApi>,SimpleStreamOptions, andAssistantMessageEventStream. -
Implementation requires creating a
streamSimplefunction that converts Prime Agent'sContextinto provider-specific HTTP requests while emitting standardized events likestart,text_delta, anddone. -
Registration happens via
ExtensionAPI.registerProvider, which accepts configuration for base URLs, model descriptors, authentication methods, and your streaming implementation. -
Authentication supports both static API keys (referenced by environment variable name) and dynamic OAuth flows managed by the
auth-storagesubsystem inpackages/coding-agent/src/core/auth-storage.ts. -
Reference implementation is available in
packages/coding-agent/examples/extensions/custom-provider-anthropic/index.ts, demonstrating OAuth integration and complete event streaming.
Frequently Asked Questions
What file contains the type definitions required for custom provider integration?
The type definitions live in packages/ai/src/types.ts. This file contains the Api, Provider, Model<TApi>, and SimpleStreamOptions interfaces that your custom implementation must conform to, along with the event types for the streaming protocol.
How does Prime Agent handle API keys for custom providers?
Prime Agent uses the auth-storage subsystem located in packages/coding-agent/src/core/auth-storage.ts to resolve credentials. When you specify an apiKey field in your provider registration, the system reads that environment variable and passes the value through SimpleStreamOptions to your streamSimple function.
Can I use OAuth instead of static API keys for my custom provider?
Yes. The provider registration object accepts an optional oauth configuration object containing login, refreshToken, and getApiKey methods. You can reference the implementation pattern in packages/ai/src/utils/oauth/anthropic.ts to implement OAuth flows for services that support them.
What event types must my streamSimple function emit?
Your implementation must emit events according to the protocol defined in packages/ai/src/types.ts. Required events include start (with initial metadata), text_delta (for content chunks), toolcall_start and toolcall_delta (for function calls), and either done (successful completion) or error (failure states).
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →