Files
Genarrative/apps/ai-game-creator-shell/src/services/llmModelCatalog.ts
T
kdletters c36a5170f8
Project CI / AI game creator shell Rust shard 1/4 (push) Successful in 5m28s
Project CI / AI game creator shell Rust shard 3/4 (push) Successful in 5m29s
Project CI / AI game creator shell Rust shard 4/4 (push) Successful in 6m6s
Project CI / AI game creator shell Rust shard 2/4 (push) Successful in 6m6s
Project CI / AI game creator shell Rust smoke (push) Successful in 1m46s
Project CI / AI game creator shell Rust crates (push) Successful in 2m51s
Project CI / Frontend tests (push) Successful in 4m44s
Project CI / Native shell tests (push) Successful in 6m31s
Project CI / Repository checks (push) Successful in 4m17s
Project CI / Backend tests (push) Successful in 7m48s
Project CI / AI game creator shell web tests (push) Successful in 3m43s
AGC 新增本地自定义 LLM 配置与展示模型勾选
- 本地配置新增 llm.customEnabled 与 llm.visibleModels,显式开启后保留自定义连接和勾选列表,官方路由下仍清空凭据
- 配置迁移始终写出 customEnabled、visibleModels、apiKey、baseUrl、model、apiKind、reasoningEffort,便于手写自定义连接
- 新增 discover_game_creator_llm_models 命令,直连自定义端点 GET /models,限制超时与响应大小并脱敏错误
- codex_app_server 自定义模式改用配置里的地址与 Key 走本地凭据代理,不再经过平台 /api/llm,也不回退官方路由
- 模型目录按官方与自定义来源隔离缓存,自定义模式只展示勾选模型,选项失效时回退第一项
- 设置页在自定义模式展示 API 地址、API Key、协议与推理档,并提供模型读取、搜索、勾选与已勾选预览
- 补齐固定项排版与读取按钮样式,同步 AGC 模型选择规范、实施计划与共享概览
2026-09-16 16:39:15 +08:00

84 lines
2.5 KiB
TypeScript

import { resolveTauriInvoke } from '../app/tauri';
import type { GameCreatorAppConfigView } from '../app/types';
import { type ClientLlmModelCatalog, loadClientLlmModels } from './clientApi';
let cached: ClientLlmModelCatalog | null = null;
let inFlight: Promise<ClientLlmModelCatalog> | null = null;
let source = '';
let generation = 0;
let localRevision = 0;
export const LLM_CONFIG_CHANGED_EVENT = 'agc-llm-config-changed';
export class LlmModelCatalogConfigError extends Error {}
export function notifyLlmConfigChanged() {
generation += 1;
cached = null;
inFlight = null;
source = '';
window.dispatchEvent(new Event(LLM_CONFIG_CHANGED_EVENT));
}
async function loadEffectiveCatalog(epoch: number) {
const invoke = resolveTauriInvoke();
let config: GameCreatorAppConfigView | undefined;
try {
config = invoke
? await invoke<GameCreatorAppConfigView>('read_game_creator_app_config')
: undefined;
} catch (error) {
if (epoch === generation) cached = null;
throw new LlmModelCatalogConfigError('读取客户端配置失败');
}
if (epoch !== generation) throw new Error('模型配置已更新');
const llm = config?.config.llm;
const nextSource = llm?.customEnabled
? JSON.stringify(['custom', llm.baseUrl, llm.visibleModels ?? []])
: 'official';
if (source !== nextSource) {
source = nextSource;
cached = null;
}
if (llm?.customEnabled) {
if (cached) return cached;
const ids = llm.visibleModels ?? [];
return {
defaultModelId: ids[0] ?? '',
models: ids.map((id) => ({ id, displayName: id })),
revision: --localRevision,
};
}
return loadClientLlmModels();
}
/** 最近一次成功读取的模型目录,用于首屏渲染与刷新失败时兜底。 */
export function cachedLlmModelCatalog() {
return cached;
}
/**
* 读取模型目录;同一时刻只保留一个在途请求,重复触发复用同一结果。
* 读取失败时保留上一次成功目录,不覆盖调用方已生效的选择。
*/
export function refreshLlmModelCatalog() {
if (inFlight) return inFlight;
const epoch = generation;
const request = loadEffectiveCatalog(epoch)
.then((catalog) => {
if (epoch !== generation) throw new Error('模型配置已更新');
cached = catalog;
return catalog;
})
.finally(() => {
if (inFlight === request) inFlight = null;
});
inFlight = request;
return request;
}
export function resetLlmModelCatalogCacheForTest() {
generation += 1;
source = '';
cached = null;
inFlight = null;
}