Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/app/api/cron/sync-model-stats/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
12 changes: 9 additions & 3 deletions src/app/api/openrouter/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<OpenRouterModelsResponse> => {
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
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WARNING: includeSlackbotOnly option is ignored when organizationId is set

useModelSelectorList() adds includeSlackbotOnly to the query key and builds a URL for /api/openrouter/models, but when organizationId is present it fetches /api/organizations/:id/models without forwarding the query param. That makes includeSlackbotOnly a no-op for org-scoped requests (likely the common case).

Suggested change
organizationId ? `/api/organizations/${organizationId}/models` : modelsUrl
organizationId ? `/api/organizations/${organizationId}/models${includeSlackbotOnly ? '?includeSlackbotOnly=true' : ''}` : modelsUrl

);
if (!response.ok) {
throw new Error(`Failed to fetch: ${response.status} ${response.statusText}`);
Expand Down
5 changes: 3 additions & 2 deletions src/app/api/openrouter/models/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<NextResponse<{ error: string; message: string } | OpenRouterModelsResponse>> {
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, {
Expand Down
6 changes: 5 additions & 1 deletion src/app/api/organizations/[id]/models/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<OpenRouterModelsResponse>(request, async caller => {
return caller.organizations.settings.listAvailableModels({ organizationId });
return caller.organizations.settings.listAvailableModels({
organizationId,
includeSlackbotOnly,
});
});
}
16 changes: 12 additions & 4 deletions src/lib/providers/openrouter/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand Down Expand Up @@ -149,13 +155,15 @@ export async function getRawOpenRouterModels(): Promise<OpenRouterModelsResponse
* Fetch enhanced models from OpenRouter API with filtering and UI enhancements
* Use this for user-facing model selection where you want filtered, sorted models
*/
export async function getEnhancedOpenRouterModels(): Promise<OpenRouterModelsResponse> {
export async function getEnhancedOpenRouterModels(
options: { includeSlackbotOnly?: boolean } = {}
): Promise<OpenRouterModelsResponse> {
const rawResponse = await getRawOpenRouterModels();

// If data is not in expected format (e.g., validation failed), return as-is
if (!rawResponse.data || !Array.isArray(rawResponse.data)) {
return rawResponse;
}

return { data: enhancedModelList(rawResponse.data) };
return { data: enhancedModelList(rawResponse.data, options) };
}
6 changes: 3 additions & 3 deletions src/routers/organizations/organization-settings-router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,10 +144,10 @@ const SettingsResponseSchema = z.object({

export const organizationsSettingsRouter = createTRPCRouter({
listAvailableModels: organizationMemberProcedure
.input(OrganizationIdInputSchema)
.input(OrganizationIdInputSchema.extend({ includeSlackbotOnly: z.boolean().optional() }))
.output(z.custom<OpenRouterModelsResponse>())
.query(async ({ input }) => {
const { organizationId } = input;
const { organizationId, includeSlackbotOnly } = input;

const organization = await getOrganizationById(organizationId);
if (!organization) {
Expand All @@ -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) {
Expand Down
Loading