diff --git a/src/app/api/cron/sync-model-stats/route.ts b/src/app/api/cron/sync-model-stats/route.ts index 972275caf..11e3fe493 100644 --- a/src/app/api/cron/sync-model-stats/route.ts +++ b/src/app/api/cron/sync-model-stats/route.ts @@ -36,7 +36,9 @@ export async function GET(request: NextRequest) { // Fetch all models from OpenRouter (raw, unfiltered data) const openRouterResponse = await getRawOpenRouterModels(); - const enhancedOpenRouterResponse = await getEnhancedOpenRouterModels(); + const enhancedOpenRouterResponse = await getEnhancedOpenRouterModels({ + includeSlackbotOnly: true, + }); // Create a map of enhanced models for pricing lookup (includes Kilo free models with $0 pricing) const enhancedModelsMap = new Map( diff --git a/src/app/api/openrouter/hooks.ts b/src/app/api/openrouter/hooks.ts index b55d508d6..b3bee8773 100644 --- a/src/app/api/openrouter/hooks.ts +++ b/src/app/api/openrouter/hooks.ts @@ -106,12 +106,18 @@ async function parseModelsByProviderBackupData() { ); } -export function useModelSelectorList(organizationId: string | undefined) { +export function useModelSelectorList( + organizationId: string | undefined, + { includeSlackbotOnly = false }: { includeSlackbotOnly?: boolean } = {} +) { const query = useQuery({ - queryKey: ['openrouter-models', organizationId], + queryKey: ['openrouter-models', organizationId, { includeSlackbotOnly }], queryFn: async (): Promise => { + const modelsUrl = includeSlackbotOnly + ? '/api/openrouter/models?includeSlackbotOnly=true' + : '/api/openrouter/models'; const response = await fetch( - organizationId ? `/api/organizations/${organizationId}/models` : '/api/openrouter/models' + organizationId ? `/api/organizations/${organizationId}/models` : modelsUrl ); if (!response.ok) { throw new Error(`Failed to fetch: ${response.status} ${response.statusText}`); diff --git a/src/app/api/openrouter/models/route.ts b/src/app/api/openrouter/models/route.ts index 63db2d9e4..75b186e42 100644 --- a/src/app/api/openrouter/models/route.ts +++ b/src/app/api/openrouter/models/route.ts @@ -11,10 +11,11 @@ export const revalidate = 60; * curl -vvv 'http://localhost:3000/api/openrouter/models' */ export async function GET( - _request: NextRequest + request: NextRequest ): Promise> { try { - const data = await getEnhancedOpenRouterModels(); + const includeSlackbotOnly = request.nextUrl.searchParams.get('includeSlackbotOnly') === 'true'; + const data = await getEnhancedOpenRouterModels({ includeSlackbotOnly }); return NextResponse.json(data); } catch (error) { captureException(error, { diff --git a/src/app/api/organizations/[id]/models/route.ts b/src/app/api/organizations/[id]/models/route.ts index 295f785a1..e6cdbd6d2 100644 --- a/src/app/api/organizations/[id]/models/route.ts +++ b/src/app/api/organizations/[id]/models/route.ts @@ -4,8 +4,12 @@ import { handleTRPCRequest } from '@/lib/trpc-route-handler'; export async function GET(request: NextRequest, { params }: { params: Promise<{ id: string }> }) { const organizationId = (await params).id; + const includeSlackbotOnly = request.nextUrl.searchParams.get('includeSlackbotOnly') === 'true'; return handleTRPCRequest(request, async caller => { - return caller.organizations.settings.listAvailableModels({ organizationId }); + return caller.organizations.settings.listAvailableModels({ + organizationId, + includeSlackbotOnly, + }); }); } diff --git a/src/lib/providers/openrouter/index.ts b/src/lib/providers/openrouter/index.ts index 105c02ce9..220c6461b 100644 --- a/src/lib/providers/openrouter/index.ts +++ b/src/lib/providers/openrouter/index.ts @@ -51,14 +51,20 @@ function buildAutoModel(): OpenRouterModel { }; } -function enhancedModelList(models: OpenRouterModel[]) { +function enhancedModelList( + models: OpenRouterModel[], + { includeSlackbotOnly = false }: { includeSlackbotOnly?: boolean } = {} +) { const autoModel = buildAutoModel(); + const freeModelsToInclude = kiloFreeModels.filter( + m => m.is_enabled && (includeSlackbotOnly || !m.slackbot_only) + ); const enhancedModels = models .filter( (model: OpenRouterModel) => !kiloFreeModels.some(m => m.public_id === model.id && m.is_enabled) ) - .concat(kiloFreeModels.filter(m => m.is_enabled).map(model => convertFromKiloModel(model))) + .concat(freeModelsToInclude.map(model => convertFromKiloModel(model))) .concat([autoModel]) .map((model: OpenRouterModel) => { const preferredIndex = @@ -149,7 +155,9 @@ export async function getRawOpenRouterModels(): Promise { +export async function getEnhancedOpenRouterModels( + options: { includeSlackbotOnly?: boolean } = {} +): Promise { const rawResponse = await getRawOpenRouterModels(); // If data is not in expected format (e.g., validation failed), return as-is @@ -157,5 +165,5 @@ export async function getEnhancedOpenRouterModels(): Promise()) .query(async ({ input }) => { - const { organizationId } = input; + const { organizationId, includeSlackbotOnly } = input; const organization = await getOrganizationById(organizationId); if (!organization) { @@ -163,7 +163,7 @@ export const organizationsSettingsRouter = createTRPCRouter({ allowedModels = organization.settings.model_allow_list; } - const responseData = await getEnhancedOpenRouterModels(); + const responseData = await getEnhancedOpenRouterModels({ includeSlackbotOnly }); let filteredModels = responseData.data; if (allowedModels) {