feat(codex): add automatic model catalog updates from GitHub

This commit is contained in:
lzt404 committed 2026-07-29 21:05:47 +08:00
1 parent 8d8f619720
commit 0f3e5093e8
6 files changed
+244 -9

No files matched your search

+4
View File
@@ -409,6 +409,10 @@ export const jaOverrides = {
'agents.model.search': 'モデル名またはエイリアスを検索',
'agents.model.clearSearch': '検索を消去',
'agents.model.refresh': 'モデルを更新',
'agents.catalog.update': 'モデル設定情報を更新',
'agents.catalog.updating': 'モデル設定を更新しています',
'agents.catalog.updated': 'GitHub からモデル設定を更新しました',
'agents.catalog.unchanged': 'モデル設定は最新です',
'agents.model.fetching': 'モデルを取得しています',
'agents.model.noMatch': '一致するモデルがありません',
'agents.model.unavailable': '現在利用可能なモデルはありません',
+8
View File
@@ -412,6 +412,10 @@ export const zhCN = {
'agents.model.search': '搜索模型名称或别名',
'agents.model.clearSearch': '清空搜索',
'agents.model.refresh': '刷新模型',
'agents.catalog.update': '更新模型配置信息',
'agents.catalog.updating': '正在更新模型配置',
'agents.catalog.updated': '模型配置已从 GitHub 更新',
'agents.catalog.unchanged': '模型配置已是最新版本',
'agents.model.fetching': '正在获取模型',
'agents.model.noMatch': '没有匹配的模型',
'agents.model.unavailable': '暂时没有可用模型',
@@ -1256,6 +1260,10 @@ export const en: Record<MessageKey, string> = {
'agents.model.search': 'Search model names or aliases',
'agents.model.clearSearch': 'Clear search',
'agents.model.refresh': 'Refresh models',
'agents.catalog.update': 'Update model configuration',
'agents.catalog.updating': 'Updating model configuration',
'agents.catalog.updated': 'Model configuration updated from GitHub',
'agents.catalog.unchanged': 'Model configuration is already up to date',
'agents.model.fetching': 'Fetching models',
'agents.model.noMatch': 'No matching models',
'agents.model.unavailable': 'No models are currently available',
+51 -1
View File
@@ -85,6 +85,10 @@ type AgentConfigActionResult = {
conflictFiles: string[];
};
type CodexModelCatalogUpdateResult = {
outcome: 'updated' | 'unchanged';
};
type ChatGptCloseResult = {
wasRunning: boolean;
closedProcesses: number;
@@ -484,11 +488,13 @@ export function AgentsPage() {
const [launchTargetByClient, setLaunchTargetByClient] = useState<Partial<Record<AgentClientId, string>>>({});
const [loading, setLoading] = useState(true);
const [modelLoading, setModelLoading] = useState(false);
const [busyAction, setBusyAction] = useState<'apply' | 'default' | 'clear' | 'launch' | 'close-app' | null>(null);
const [busyAction, setBusyAction] = useState<'apply' | 'default' | 'clear' | 'launch' | 'close-app' | 'catalog' | null>(null);
const busy = busyAction !== null;
const [detectionError, setDetectionError] = useState('');
const [modelError, setModelError] = useState('');
const [modelSelectionError, setModelSelectionError] = useState('');
const [catalogUpdateError, setCatalogUpdateError] = useState('');
const [catalogUpdateNotice, setCatalogUpdateNotice] = useState('');
const [configurationError, setConfigurationError] = useState('');
const [launchError, setLaunchError] = useState('');
const [defaultError, setDefaultError] = useState('');
@@ -586,6 +592,8 @@ export function AgentsPage() {
useEffect(() => {
setActiveSubpage(DEFAULT_AGENT_SUBPAGE);
setModelSelectionError('');
setCatalogUpdateError('');
setCatalogUpdateNotice('');
setConfigurationError('');
setLaunchError('');
setDefaultError('');
@@ -680,6 +688,23 @@ export function AgentsPage() {
void loadModels(selected);
};
const updateCodexModelCatalog = async () => {
setCatalogUpdateError('');
setCatalogUpdateNotice('');
setBusyAction('catalog');
try {
const result = await invoke<CodexModelCatalogUpdateResult>('update_codex_model_catalog');
setCatalogUpdateNotice(result.outcome === 'updated'
? t('agents.catalog.updated')
: t('agents.catalog.unchanged'));
await loadModels('codex');
} catch (requestError) {
setCatalogUpdateError(String(requestError));
} finally {
setBusyAction(null);
}
};
const reloadStatusesAfterAction = async () => {
setDetectionError('');
try {
@@ -964,6 +989,31 @@ export function AgentsPage() {
{modelHint}
</span>
) : null}
{selected === 'codex' ? (
<div className="agent-catalog-update-control">
<button
type="button"
className="secondary-button compact-button"
onClick={() => void updateCodexModelCatalog()}
disabled={busy}
>
<RefreshCw size={15} className={busyAction === 'catalog' ? 'spin' : ''} />
{busyAction === 'catalog'
? t('agents.catalog.updating')
: t('agents.catalog.update')}
</button>
{catalogUpdateError ? (
<span className="agent-inline-message error" role="alert" aria-live="polite">
{catalogUpdateError}
</span>
) : null}
{catalogUpdateNotice ? (
<span className="agent-inline-message" role="status" aria-live="polite">
{catalogUpdateNotice}
</span>
) : null}
</div>
) : null}
</section>
<section className={`agent-core-setting-section agent-modification-actions ${activeStatus?.modificationState === 'applied' ? 'enabled' : ''}`}>
+17
View File
@@ -4934,6 +4934,18 @@ input:focus-visible {
overflow-wrap: anywhere;
}
.agent-catalog-update-control {
display: flex;
align-items: center;
gap: 10px;
min-width: 0;
}
.agent-catalog-update-control .agent-inline-message {
min-width: 0;
overflow-wrap: anywhere;
}
.agent-pending-badge {
flex: none;
padding: 4px 8px;
@@ -7164,6 +7176,11 @@ input:focus-visible {
flex-direction: column;
}
.agent-catalog-update-control {
align-items: stretch;
flex-direction: column;
}
.codex-auto-restore-toggle {
width: 100%;
min-width: 0;