feat: OpenAI 모델 목록 조회 라우트 추가, LM Studio thinking 비활성화 스위치

프론트엔드가 예전부터 호출하던 POST /api/openai/models가 백엔드에 구현이
안 되어 있어 항상 404였던 버그 수정 - OpenAICompatAdapter로 실제 OpenAI
API에 모델 목록을 조회하도록 구현.

지서버(LM Studio)의 gemma-4-26b-a4b가 응답당 완성 토큰을 2.5배 더 많이
쓰는 것을 벤치마크로 확인(322 vs 132 토큰/응답, thinking 오버헤드로 추정) -
chat_template_kwargs.enable_thinking=false를 기본 적용하되, 복잡한 질문에서
품질이 떨어질 수 있어 설정 화면(모델 → LM Studio)에 체크박스로 켜고 끌 수
있게 구현. 기본값은 비활성화(현재 상태 유지).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
kim
2026-08-07 12:57:22 +09:00
co-authored by Claude Sonnet 5
parent ae6e347339
commit b001cd9318
6 changed files with 47 additions and 1 deletions
+24
View File
@@ -3943,6 +3943,7 @@ app.post('/api/open-path', requireGatewayAuth, async (req, res) => {
// trigger the OpenAI OAuth flow.
import { getProvider, resetProvider, buildProviderForLLM, getModelForRole } from '../providers/factory';
import { OpenAICompatAdapter } from '../providers/openai-compat-adapter';
import { getGoogleUsageToday } from '../providers/google-usage';
import { buildWebhookRouter, resolveHookConfig } from './channels/webhook-handler';
import { getMCPManager } from './infra/mcp-manager';
@@ -4004,6 +4005,29 @@ app.post('/api/models/test', async (req, res) => {
}
});
// POST /api/openai/models — list models for a (possibly not-yet-saved) OpenAI API key,
// used by the Settings → Models → OpenAI panel to populate the model dropdown before the
// key is saved via /api/settings/provider. The frontend has called this since the OpenAI
// provider was added, but the route was never implemented (always 404'd until now).
app.post('/api/openai/models', async (req, res) => {
try {
let apiKey = String(req.body?.api_key || '').trim();
if (apiKey === '••••••••') {
apiKey = ((getConfig().getConfig() as any)?.llm?.providers?.openai?.api_key) || '';
}
if (!apiKey) { res.json({ success: false, models: [], error: 'API 키가 필요합니다' }); return; }
const adapter = new OpenAICompatAdapter({ endpoint: 'https://api.openai.com', apiKey, providerId: 'openai' });
const models = await adapter.listModels();
res.json({
success: models.length > 0,
models: models.map(m => m.name),
error: models.length ? undefined : '모델 목록을 가져오지 못했습니다 (키를 확인하세요)',
});
} catch (err: any) {
res.json({ success: false, models: [], error: err.message });
}
});
registerMusicRoutes(app);
// ── Guitar Pro tab search/download (guitarprotabs.org proxy) ─────────────────