feat(agents): register Redpill AI provider

Add provider builder and implicit registration with API key resolution.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
HashWarlock 2026-01-25 18:23:29 -06:00
parent 24a4bf4a0d
commit 36cd0c82df
3 changed files with 30 additions and 9 deletions

View File

@ -13,6 +13,7 @@ import {
SYNTHETIC_MODEL_CATALOG, SYNTHETIC_MODEL_CATALOG,
} from "./synthetic-models.js"; } from "./synthetic-models.js";
import { discoverVeniceModels, VENICE_BASE_URL } from "./venice-models.js"; import { discoverVeniceModels, VENICE_BASE_URL } from "./venice-models.js";
import { discoverRedpillModels, REDPILL_BASE_URL } from "./redpill-models.js";
type ModelsConfig = NonNullable<ClawdbotConfig["models"]>; type ModelsConfig = NonNullable<ClawdbotConfig["models"]>;
export type ProviderConfig = NonNullable<ModelsConfig["providers"]>[string]; export type ProviderConfig = NonNullable<ModelsConfig["providers"]>[string];
@ -350,6 +351,15 @@ async function buildVeniceProvider(): Promise<ProviderConfig> {
}; };
} }
async function buildRedpillProvider(): Promise<ProviderConfig> {
const models = discoverRedpillModels();
return {
baseUrl: REDPILL_BASE_URL,
api: "openai-completions",
models,
};
}
async function buildOllamaProvider(): Promise<ProviderConfig> { async function buildOllamaProvider(): Promise<ProviderConfig> {
const models = await discoverOllamaModels(); const models = await discoverOllamaModels();
return { return {
@ -402,6 +412,17 @@ export async function resolveImplicitProviders(params: {
providers.venice = { ...(await buildVeniceProvider()), apiKey: veniceKey }; providers.venice = { ...(await buildVeniceProvider()), apiKey: veniceKey };
} }
// Redpill
const redpillKey =
resolveEnvApiKeyVarName("redpill") ??
resolveApiKeyFromProfiles({ provider: "redpill", store: authStore });
if (redpillKey) {
providers.redpill = {
...(await buildRedpillProvider()),
apiKey: redpillKey,
};
}
const qwenProfiles = listProfilesForProvider(authStore, "qwen-portal"); const qwenProfiles = listProfilesForProvider(authStore, "qwen-portal");
if (qwenProfiles.length > 0) { if (qwenProfiles.length > 0) {
providers["qwen-portal"] = { providers["qwen-portal"] = {

View File

@ -4,7 +4,7 @@ import {
REDPILL_DEFAULT_MODEL, REDPILL_DEFAULT_MODEL,
REDPILL_DEFAULT_MODEL_REF, REDPILL_DEFAULT_MODEL_REF,
REDPILL_BASE_URL, REDPILL_BASE_URL,
getRedpillModels, discoverRedpillModels,
resetRedpillModelCache, resetRedpillModelCache,
type RedpillCatalogEntry, type RedpillCatalogEntry,
} from "./redpill-models.js"; } from "./redpill-models.js";
@ -122,9 +122,9 @@ describe("Redpill Models", () => {
}); });
}); });
describe("getRedpillModels", () => { describe("discoverRedpillModels", () => {
it("should convert catalog to model definitions", () => { it("should convert catalog to model definitions", () => {
const models = getRedpillModels(); const models = discoverRedpillModels();
expect(models).toHaveLength(18); expect(models).toHaveLength(18);
for (const model of models) { for (const model of models) {
@ -146,15 +146,15 @@ describe("Redpill Models", () => {
}); });
it("should cache results", () => { it("should cache results", () => {
const models1 = getRedpillModels(); const models1 = discoverRedpillModels();
const models2 = getRedpillModels(); const models2 = discoverRedpillModels();
expect(models1).toBe(models2); // Same reference expect(models1).toBe(models2); // Same reference
}); });
it("should return fresh data after cache reset", () => { it("should return fresh data after cache reset", () => {
const models1 = getRedpillModels(); const models1 = discoverRedpillModels();
resetRedpillModelCache(); resetRedpillModelCache();
const models2 = getRedpillModels(); const models2 = discoverRedpillModels();
expect(models1).not.toBe(models2); // Different reference expect(models1).not.toBe(models2); // Different reference
expect(models1).toEqual(models2); // Same content expect(models1).toEqual(models2); // Same content
}); });

View File

@ -250,9 +250,9 @@ function catalogEntryToModelDefinition(entry: RedpillCatalogEntry): ModelDefinit
} }
/** /**
* Get cached model list or convert from catalog * Discover cached model list or convert from catalog
*/ */
export function getRedpillModels(): ModelDefinitionConfig[] { export function discoverRedpillModels(): ModelDefinitionConfig[] {
const now = Date.now(); const now = Date.now();
// Return cached models if still valid // Return cached models if still valid