refactor(ui): use tokenlens as sole model source, remove provider listModels

Remove the per-provider listModels API (GET /providers/:id/models) and all
four provider implementations (OpenAI Compatible, OpenAI Responses, Anthropic,
Gemini). ModelCombobox now only shows tokenlens suggestions (tagged '推荐') plus
free-form custom input — no more unfiltered 'API' models from provider SDKs.

Fixes: switching provider type in ProviderDialog no longer shows stale models
from the original provider's API.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)
This commit is contained in:
jeffusion
2026-03-05 23:18:33 +08:00
committed by 路遥知码力
parent 71bd310459
commit fdfd49be63
12 changed files with 29 additions and 125 deletions

View File

@@ -55,29 +55,6 @@ llmConfigRouter.get('/providers/:id', (c) => {
});
});
llmConfigRouter.get('/providers/:id/models', async (c) => {
const id = c.req.param('id');
const provider = providerRepo.getById(id);
if (!provider) return c.json({ message: 'Provider not found' }, 404);
if (!secretRepo.has(id)) {
return c.json({ message: 'No API key configured' }, 400);
}
try {
llmGateway.invalidateProvider(id);
const providerInstance = llmGateway.getProviderInstance(id);
if (!providerInstance.listModels) {
return c.json({ message: 'This provider does not support listing models' }, 501);
}
const models = await providerInstance.listModels();
return c.json({ models });
} catch (error: any) {
return c.json({ message: error.message || 'Failed to fetch models' }, 500);
}
});
llmConfigRouter.post('/providers', async (c) => {
const body = await c.req.json<{
name: string;

View File

@@ -220,15 +220,6 @@ class AnthropicProvider implements LLMProvider {
}
}
async listModels(): Promise<string[]> {
const response = await this.client.models.list();
const models: string[] = [];
for await (const page of response.iterPages()) {
models.push(...page.data.map((model) => model.id));
}
return models;
}
private wrapError(error: unknown): Error {
if (error instanceof Anthropic.APIError) {
if (error.status === 401) return new LLMAuthError(TYPE, error.message);

View File

@@ -33,8 +33,6 @@ export interface LLMProvider {
/** Optional: embedding interface (only for providers that support it). */
embed?(texts: string[]): Promise<number[][]>;
/** Optional: list available models for this provider. */
listModels?(): Promise<string[]>;
}
// ---------------------------------------------------------------------------

View File

@@ -203,17 +203,6 @@ class GeminiProvider implements LLMProvider {
}
}
async listModels(): Promise<string[]> {
const pager = await this.genAI.models.list();
const models: string[] = [];
for await (const model of pager) {
if (model.name) {
models.push(model.name.replace('models/', ''));
}
}
return models;
}
private wrapError(error: unknown): Error {
if (error instanceof Error) {
const msg = error.message;

View File

@@ -143,11 +143,6 @@ class OpenAICompatibleProvider implements LLMProvider {
}
}
async listModels(): Promise<string[]> {
const response = await this.client.models.list();
return response.data.map((model) => model.id);
}
private wrapError(error: unknown): Error {
if (error instanceof OpenAI.APIError) {
if (error.status === 401) return new LLMAuthError(TYPE, error.message);

View File

@@ -182,11 +182,6 @@ class OpenAIResponsesProvider implements LLMProvider {
}
}
async listModels(): Promise<string[]> {
const response = await this.client.models.list();
return response.data.map((model) => model.id);
}
private wrapError(error: unknown): Error {
if (error instanceof OpenAI.APIError) {
if (error.status === 401) return new LLMAuthError(TYPE, error.message);