Agix abstracts every AI model behind theDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/manusapis/Agix/llms.txt
Use this file to discover all available pages before exploring further.
IAIProvider interface. Adding support for a new provider — whether it is Google Gemini, a self-hosted Ollama instance, or any other model API — involves four focused changes spread across four files. No call sites in the React UI or service layer need to change.
The IAIProvider contract
Every provider must satisfy the following interface, defined in src/services/ai/base.provider.ts:
isConfigured() is already implemented by BaseAIProvider — it returns true when both apiKey and baseUrl are non-empty strings. Concrete providers only need to implement chat() along with the id and name getters.
Steps
Open
src/types/ai.types.ts and add your new identifier to the ProviderId union. This is the canonical string key used everywhere — in the config registry, the factory switch, and persisted settings.// src/types/ai.types.ts
export type ProviderId = "openai" | "openrouter" | "claude" | "custom" | "gemini";
TypeScript’s exhaustiveness checking will now flag any
switch statement on ProviderId that does not handle the new case, which makes it easy to find every place that needs updating.Create a new file at
src/services/ai/gemini.provider.ts. Extend BaseAIProvider so you inherit the constructor, the config field, and the default isConfigured() implementation, then implement id, name, and chat().// src/services/ai/gemini.provider.ts
import { BaseAIProvider } from "./base.provider";
import type { ChatRequest, ChatResponse } from "@/types/ai.types";
export class GeminiProvider extends BaseAIProvider {
get id() {
return this.config.id;
}
get name() {
return this.config.name;
}
async chat(request: ChatRequest): Promise<ChatResponse> {
const res = await fetch(`${this.config.baseUrl}/generateContent`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${this.config.apiKey}`,
},
body: JSON.stringify({ contents: request.messages }),
});
if (!res.ok) {
throw new Error(`Gemini request failed: ${res.status} ${await res.text()}`);
}
const data = await res.json();
return {
provider: this.id,
model: request.model,
content: data.candidates[0].content.parts[0].text,
finishReason: data.candidates[0].finishReason,
};
}
}
The
ChatResponse shape — provider, model, content, and finishReason — is required. The optional usage field can be populated if the API returns token counts.Open
src/services/ai/provider.factory.ts and add an import and a case to the createProvider() switch:// src/services/ai/provider.factory.ts
import { GeminiProvider } from "./gemini.provider";
export function createProvider(config: AIProviderConfig): IAIProvider {
switch (config.id) {
case "openai":
case "openrouter":
case "custom":
return new OpenAIProvider(config);
case "claude":
return new ClaudeProvider(config);
case "gemini":
return new GeminiProvider(config);
default:
throw new Error(`Unknown AI provider: ${(config as { id: ProviderId }).id}`);
}
}
This is the only place that needs to know which class backs which provider ID. All other code goes through
IAIProvider.Open
src/config/providers.config.ts and add an entry for the new provider. The apiKey is always left blank here — keys are entered at runtime via the sidebar and persisted by settingsStore.// src/config/providers.config.ts
export const DEFAULT_PROVIDERS: Record<ProviderId, AIProviderConfig> = {
// … existing entries …
gemini: {
id: "gemini",
name: "Google Gemini",
apiKey: "",
baseUrl: "https://generativelanguage.googleapis.com/v1beta",
defaultModel: "gemini-1.5-flash",
enabled: true,
},
};
Existing providers for reference
The two shipped providers illustrate the two main API shapes you are likely to encounter:Files changed summary
| File | Change |
|---|---|
src/types/ai.types.ts | Add the new ID to the ProviderId union |
src/services/ai/<name>.provider.ts | New file — implements IAIProvider |
src/services/ai/provider.factory.ts | One new case in createProvider() |
src/config/providers.config.ts | One new entry in DEFAULT_PROVIDERS |