diff --git a/README.md b/README.md
index 4b70ee2..873f59d 100644
--- a/README.md
+++ b/README.md
@@ -78,7 +78,6 @@ Check the CLI Proxy API server documentation/config comments for the full authen
- **AI Providers**:
- Gemini/Codex/Claude/Vertex key entries (base URL, headers, proxy, model aliases, excluded models, prefix).
- OpenAI-compatible providers (multiple API keys, custom headers, model alias import via `/v1/models`, optional browser-side "chat/completions" test).
- - Ampcode integration (upstream URL/key, force mappings, model mapping table).
- **Auth Files**: upload/download/delete JSON credentials, filter/search/pagination, runtime-only indicators, view supported models per credential (when the server supports it), manage OAuth excluded models (supports `*` wildcards), configure OAuth model alias mappings.
- **OAuth**: start OAuth/device flows for Codex, Anthropic/Claude, Antigravity, Gemini CLI, Kimi, and xAI/Grok; poll status; submit callback URLs or xAI/Grok displayed codes; import Vertex JSON credentials and iFlow cookies.
- **Quota Management**: manage quota limits and usage for Claude, Antigravity, Codex, Gemini CLI, and other providers.
diff --git a/README_CN.md b/README_CN.md
index 5d9ec6a..d4827b2 100644
--- a/README_CN.md
+++ b/README_CN.md
@@ -78,7 +78,6 @@ bun run build
- **AI 提供商**:
- Gemini/Codex/Claude/Vertex 配置(Base URL、Headers、代理、模型别名、排除模型、Prefix)。
- OpenAI 兼容提供商(多 Key、Header、自助从 `/v1/models` 拉取并导入模型别名、可选浏览器侧 `chat/completions` 测试)。
- - Ampcode 集成(上游地址/密钥、强制映射、模型映射表)。
- **认证文件**:上传/下载/删除 JSON 凭据,筛选/搜索/分页,标记 runtime-only;查看单个凭据可用模型(依赖后端支持);管理 OAuth 排除模型(支持 `*` 通配符);配置 OAuth 模型别名映射。
- **OAuth**:对 Codex、Anthropic/Claude、Antigravity、Gemini CLI、Kimi、xAI/Grok 发起 OAuth/设备码流程并轮询状态;支持提交回调 URL 或 xAI/Grok 页面显示的 code;包含 Vertex JSON 凭据导入与 iFlow Cookie 导入。
- **配额管理**:管理 Claude、Antigravity、Codex、Gemini CLI 等提供商的配额上限与使用情况。
diff --git a/src/assets/icons/amp.svg b/src/assets/icons/amp.svg
deleted file mode 100644
index db56603..0000000
--- a/src/assets/icons/amp.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-
diff --git a/src/features/providers/ProvidersWorkbenchPage.tsx b/src/features/providers/ProvidersWorkbenchPage.tsx
index eef5dd2..bf05f64 100644
--- a/src/features/providers/ProvidersWorkbenchPage.tsx
+++ b/src/features/providers/ProvidersWorkbenchPage.tsx
@@ -79,7 +79,6 @@ const getResourceRecentSuccess = (
usageByProvider
).success;
}
- if (resource.brand === 'ampcode') return 0;
return getProviderRecentWindowStats(
usageByProvider,
resource.brand,
@@ -285,15 +284,8 @@ export function ProvidersWorkbenchPage() {
const openCreate = useCallback(() => {
const brand = activeBrand;
- if (brand === 'ampcode') {
- // ampcode 走单例编辑
- const r =
- groups.find((g) => g.id === 'ampcode')?.resources[0] ?? null;
- setSheetState({ open: true, brand: 'ampcode', mode: 'edit', resource: r });
- } else {
- setSheetState({ open: true, brand, mode: 'create', resource: null });
- }
- }, [activeBrand, groups]);
+ setSheetState({ open: true, brand, mode: 'create', resource: null });
+ }, [activeBrand]);
const openView = useCallback((resource: ProviderResource) => {
setSheetState({
@@ -319,20 +311,13 @@ export function ProvidersWorkbenchPage() {
const handleDelete = useCallback(
(resource: ProviderResource) => {
- const isAmpcode = resource.brand === 'ampcode';
const name =
resource.name ?? resource.apiKeyPreview ?? resource.identifier ?? '';
showConfirmation({
- title: isAmpcode
- ? t('providersPage.delete.ampcodeTitle')
- : t('providersPage.delete.title'),
- message: isAmpcode
- ? t('providersPage.delete.ampcodeConfirm')
- : t('providersPage.delete.confirm', { name }),
+ title: t('providersPage.delete.title'),
+ message: t('providersPage.delete.confirm', { name }),
variant: 'danger',
- confirmText: isAmpcode
- ? t('providersPage.actions.clear')
- : t('providersPage.actions.delete'),
+ confirmText: t('providersPage.actions.delete'),
onConfirm: async () => {
try {
await workbench.deleteProvider(resource);
@@ -408,8 +393,6 @@ export function ProvidersWorkbenchPage() {
);
}
- const ampcodeBrandActive = activeBrand === 'ampcode';
-
return (
void handleRefresh()}
onNew={openCreate}
/>
diff --git a/src/features/providers/adapters.ts b/src/features/providers/adapters.ts
index a2b5b43..a8664f1 100644
--- a/src/features/providers/adapters.ts
+++ b/src/features/providers/adapters.ts
@@ -1,9 +1,4 @@
-import type {
- AmpcodeConfig,
- GeminiKeyConfig,
- OpenAIProviderConfig,
- ProviderKeyConfig,
-} from '@/types';
+import type { GeminiKeyConfig, OpenAIProviderConfig, ProviderKeyConfig } from '@/types';
import {
hasDisableAllModelsRule,
stripDisableAllModelsRule,
@@ -27,17 +22,6 @@ const collectModelNames = (models?: Array<{ name?: string }>): string[] => {
return Array.from(seen);
};
-const collectAmpcodeModelNames = (mappings: AmpcodeConfig['modelMappings']): string[] => {
- const seen = new Set();
- (mappings ?? []).forEach((mapping) => {
- const from = (mapping?.from ?? '').trim();
- const to = (mapping?.to ?? '').trim();
- if (from) seen.add(from);
- if (to) seen.add(to);
- });
- return Array.from(seen);
-};
-
const normalizePriority = (priority?: number): number =>
typeof priority === 'number' && Number.isFinite(priority) ? priority : 0;
@@ -146,37 +130,3 @@ export function openaiToResource(
raw: config,
};
}
-
-export function ampcodeToResource(config?: AmpcodeConfig | null): ProviderResource {
- const safe: AmpcodeConfig = config ?? {};
- const upstreamApiKey = safe.upstreamApiKey ?? '';
- const upstreamUrl = (safe.upstreamUrl ?? '').trim();
- const hasUpstream = upstreamUrl.length > 0;
- const upstreamKeyMappingsCount = safe.upstreamApiKeys?.length ?? 0;
- return {
- id: 'ampcode:singleton',
- brand: 'ampcode',
- originalIndex: 0,
- name: null,
- identifier: 'Amp CLI',
- apiKeyPreview: upstreamApiKey ? maskApiKey(upstreamApiKey) : null,
- apiKey: upstreamApiKey || null,
- authIndex: null,
- baseUrl: upstreamUrl || null,
- proxyUrl: null,
- prefix: null,
- modelCount: safe.modelMappings?.length ?? 0,
- models: collectAmpcodeModelNames(safe.modelMappings),
- priority: 0,
- headerCount: 0,
- excludedModelCount: 0,
- apiKeyEntryCount: upstreamKeyMappingsCount,
- disabled: !hasUpstream,
- flags: {
- forceModelMappings: safe.forceModelMappings === true,
- isPlaceholder: !hasUpstream && upstreamKeyMappingsCount === 0,
- },
- selector: { brand: 'ampcode' },
- raw: safe,
- };
-}
diff --git a/src/features/providers/brandLogos.ts b/src/features/providers/brandLogos.ts
index 1507a45..7b7ec93 100644
--- a/src/features/providers/brandLogos.ts
+++ b/src/features/providers/brandLogos.ts
@@ -1,4 +1,3 @@
-import ampcodeLogo from '@/assets/icons/amp.svg';
import claudeLogo from '@/assets/icons/claude.svg';
import codexLogo from '@/assets/icons/codex.svg';
import geminiLogo from '@/assets/icons/gemini.svg';
@@ -17,5 +16,4 @@ export const PROVIDER_LOGOS: Record = {
codex: { src: codexLogo },
vertex: { src: vertexLogo },
openaiCompatibility: { src: openaiLogo, invertOnDark: true },
- ampcode: { src: ampcodeLogo },
};
diff --git a/src/features/providers/components/ProviderCategoryList.tsx b/src/features/providers/components/ProviderCategoryList.tsx
index cd8fb56..f86bf45 100644
--- a/src/features/providers/components/ProviderCategoryList.tsx
+++ b/src/features/providers/components/ProviderCategoryList.tsx
@@ -25,7 +25,7 @@ export function ProviderCategoryList({
const realResources = group.resources.filter(
(r) => !r.flags.isPlaceholder
);
- const total = realResources.length || (group.id === 'ampcode' ? 1 : 0);
+ const total = realResources.length;
const activeCount = realResources.filter((r) => !r.disabled).length;
const logo = PROVIDER_LOGOS[group.id];
const itemClass = `${styles.item} ${active ? styles.active : ''}`;
@@ -52,25 +52,19 @@ export function ProviderCategoryList({
{t(`providersPage.providerNames.${group.id}`)}
- {group.id === 'ampcode'
- ? t(
- group.resources[0]?.disabled
- ? 'providersPage.categories.ampcodeInactive'
- : 'providersPage.categories.ampcodeActive'
- )
- : t('providersPage.categories.activeCount', {
- active: activeCount,
- total,
- })}
+ {t('providersPage.categories.activeCount', {
+ active: activeCount,
+ total,
+ })}
- {group.id === 'ampcode' ? (group.resources[0]?.disabled ? '—' : '1') : total}
+ {total}
);
diff --git a/src/features/providers/components/ProviderResourcePanel.tsx b/src/features/providers/components/ProviderResourcePanel.tsx
index 7935da1..8cfdcaa 100644
--- a/src/features/providers/components/ProviderResourcePanel.tsx
+++ b/src/features/providers/components/ProviderResourcePanel.tsx
@@ -73,20 +73,18 @@ export function ProviderResourcePanel({
- {group.id !== 'ampcode' ? (
-
-
-
-
- onFilterChange(event.target.value)}
- placeholder={t('providersPage.table.filterPlaceholder')}
- />
-
- ) : null}
+
+
+
+
+ onFilterChange(event.target.value)}
+ placeholder={t('providersPage.table.filterPlaceholder')}
+ />
+
{toolbarControls ? (
@@ -104,7 +102,7 @@ export function ProviderResourcePanel({
) : null}
- {realResources.length === 0 && group.id !== 'ampcode' ? (
+ {realResources.length === 0 ? (
{t('providersPage.table.empty')}
diff --git a/src/features/providers/components/ProviderResourceTable.tsx b/src/features/providers/components/ProviderResourceTable.tsx
index 50d9ec5..e421977 100644
--- a/src/features/providers/components/ProviderResourceTable.tsx
+++ b/src/features/providers/components/ProviderResourceTable.tsx
@@ -112,11 +112,6 @@ export function ProviderResourceTable({
renderMetric('keys', t('providersPage.table.metrics.keys'), r.apiKeyEntryCount),
renderMetric('headers', t('providersPage.table.metrics.headers'), r.headerCount),
);
- } else if (r.brand === 'ampcode') {
- items.push(
- renderMetric('mappings', t('providersPage.table.metrics.mappings'), r.modelCount),
- renderMetric('keys', t('providersPage.table.metrics.keys'), r.apiKeyEntryCount),
- );
} else {
items.push(
renderMetric('models', t('providersPage.table.metrics.models'), r.modelCount),
@@ -133,14 +128,6 @@ export function ProviderResourceTable({
};
const renderStatus = (r: ProviderResource) => {
- if (r.brand === 'ampcode' && r.flags.isPlaceholder) {
- return (
-
-
- {t('providersPage.status.notConfigured')}
-
- );
- }
if (r.disabled) {
return (
@@ -169,16 +156,6 @@ export function ProviderResourceTable({
);
}
- if (r.brand === 'ampcode') {
- return (
-
- Amp CLI
-
- {r.apiKeyPreview ?? t('providersPage.table.noFallbackKey')}
-
-
- );
- }
return (
{r.apiKeyPreview ?? '—'}
@@ -197,9 +174,6 @@ export function ProviderResourceTable({
);
}
- if (r.brand === 'ampcode' && !r.baseUrl) {
- return
{t('providersPage.status.notConfigured')};
- }
return (
{r.baseUrl ?? t('providersPage.status.notSet')}
@@ -225,15 +199,12 @@ export function ProviderResourceTable({
{resources.map((resource) => {
- const isAmpcode = resource.brand === 'ampcode';
return (
{renderPrimary(resource)}
{renderBaseUrl(resource)}
- {resource.brand === 'ampcode' ? (
- —
- ) : resource.prefix ? (
+ {resource.prefix ? (
{resource.prefix}
) : (
{t('providersPage.status.none')}
@@ -243,7 +214,7 @@ export function ProviderResourceTable({
{renderStatus(resource)}
- {usageByProvider && resource.brand !== 'ampcode' ? (
+ {usageByProvider ? (
<>
{(() => {
const stats = resolveTotalStats(resource, usageByProvider);
@@ -268,7 +239,7 @@ export function ProviderResourceTable({
- {!isAmpcode && onToggleDisabled ? (
+ {onToggleDisabled ? (
e.stopPropagation()}
@@ -312,35 +283,19 @@ export function ProviderResourceTable({
>
- {isAmpcode ? (
-
- ) : (
-
- )}
+
diff --git a/src/features/providers/descriptors.ts b/src/features/providers/descriptors.ts
index 48972ef..29cfab5 100644
--- a/src/features/providers/descriptors.ts
+++ b/src/features/providers/descriptors.ts
@@ -17,7 +17,6 @@ export interface ProviderDescriptor {
supportsWebsockets: boolean;
supportsCloak: boolean;
supportsApiKeyEntries: boolean;
- supportsAmpcodeMappings: boolean;
/** Sheet 默认宽度 */
sheetSize: 'md' | 'lg' | 'xl';
}
@@ -40,7 +39,6 @@ export const PROVIDER_DESCRIPTORS: Record
= {
supportsWebsockets: false,
supportsCloak: false,
supportsApiKeyEntries: false,
- supportsAmpcodeMappings: false,
sheetSize: 'md',
},
codex: {
@@ -60,7 +58,6 @@ export const PROVIDER_DESCRIPTORS: Record = {
supportsWebsockets: true,
supportsCloak: false,
supportsApiKeyEntries: false,
- supportsAmpcodeMappings: false,
sheetSize: 'md',
},
claude: {
@@ -80,7 +77,6 @@ export const PROVIDER_DESCRIPTORS: Record = {
supportsWebsockets: false,
supportsCloak: true,
supportsApiKeyEntries: false,
- supportsAmpcodeMappings: false,
sheetSize: 'md',
},
vertex: {
@@ -100,7 +96,6 @@ export const PROVIDER_DESCRIPTORS: Record = {
supportsWebsockets: false,
supportsCloak: false,
supportsApiKeyEntries: false,
- supportsAmpcodeMappings: false,
sheetSize: 'md',
},
openaiCompatibility: {
@@ -120,27 +115,6 @@ export const PROVIDER_DESCRIPTORS: Record = {
supportsWebsockets: false,
supportsCloak: false,
supportsApiKeyEntries: true,
- supportsAmpcodeMappings: false,
- sheetSize: 'lg',
- },
- ampcode: {
- id: 'ampcode',
- supportsName: false,
- supportsApiKey: false,
- supportsDisabled: false,
- supportsBaseUrl: true,
- baseUrlRequired: false,
- supportsProxyUrl: false,
- supportsPrefix: false,
- supportsModels: false,
- supportsHeaders: false,
- supportsExcludedModels: false,
- supportsPriority: false,
- supportsTestModel: false,
- supportsWebsockets: false,
- supportsCloak: false,
- supportsApiKeyEntries: false,
- supportsAmpcodeMappings: true,
sheetSize: 'lg',
},
};
@@ -151,5 +125,4 @@ export const PROVIDER_BRAND_ORDER: ProviderBrand[] = [
'claude',
'vertex',
'openaiCompatibility',
- 'ampcode',
];
diff --git a/src/features/providers/sheets/ProviderSheet.tsx b/src/features/providers/sheets/ProviderSheet.tsx
index c63ca6c..afcc926 100644
--- a/src/features/providers/sheets/ProviderSheet.tsx
+++ b/src/features/providers/sheets/ProviderSheet.tsx
@@ -11,7 +11,6 @@ import type {
ProviderResource,
} from '../types';
import type { UseProviderWorkbenchResult } from '../useProviderWorkbench';
-import { AmpcodeForm } from './forms/AmpcodeForm';
import { BaseProviderForm } from './forms/BaseProviderForm';
import { ResourceDetailView } from './ResourceDetailView';
import styles from './forms/sharedForm.module.scss';
@@ -70,7 +69,6 @@ export function ProviderSheet({
}, []);
const descriptor = PROVIDER_DESCRIPTORS[state.brand];
- const isAmpcode = state.brand === 'ampcode';
const isEditingForm = state.mode === 'create' || state.mode === 'edit';
const formMutating = submitting || mutationDisabled;
const submitDisabled = formMutating || (state.mode === 'edit' && !isDirty);
@@ -141,20 +139,6 @@ export function ProviderSheet({
[isDirty, mutationDisabled, onUpdated, state.resource, workbench]
);
- const handleAmpcodeSubmit = useCallback(
- async (config: Parameters[0]) => {
- if (mutationDisabled || !isDirty) return;
- setSubmitting(true);
- try {
- await workbench.saveAmpcode(config);
- onUpdated();
- } finally {
- setSubmitting(false);
- }
- },
- [isDirty, mutationDisabled, onUpdated, workbench]
- );
-
const renderBody = () => {
if (state.mode === 'detail') {
if (!state.resource) {
@@ -163,22 +147,10 @@ export function ProviderSheet({
return ;
}
const formKey = `${state.brand}:${state.resource?.id ?? 'new'}:${state.mode}`;
- if (isAmpcode) {
- return (
-
- );
- }
return (
}
+ brand={state.brand}
resource={state.resource}
mode={state.mode}
mutating={formMutating}
diff --git a/src/features/providers/sheets/forms/AmpcodeForm.tsx b/src/features/providers/sheets/forms/AmpcodeForm.tsx
deleted file mode 100644
index 49eafc3..0000000
--- a/src/features/providers/sheets/forms/AmpcodeForm.tsx
+++ /dev/null
@@ -1,315 +0,0 @@
-import { useEffect, useId, useMemo, useState } from 'react';
-import { useTranslation } from 'react-i18next';
-import { Collapsible } from '@/components/ui/Collapsible';
-import { IconPlus, IconX } from '@/components/ui/icons';
-import type { AmpcodeConfig, AmpcodeModelMapping, AmpcodeUpstreamApiKeyMapping } from '@/types';
-import type { ProviderResource } from '../../types';
-import styles from './sharedForm.module.scss';
-
-interface AmpcodeFormState {
- upstreamUrl: string;
- upstreamApiKey: string;
- forceModelMappings: boolean;
- upstreamMappings: Array<{ upstreamApiKey: string; clientKeysText: string }>;
- modelMappings: Array<{ from: string; to: string }>;
-}
-
-const emptyUpstream = () => ({ upstreamApiKey: '', clientKeysText: '' });
-const emptyModelMapping = () => ({ from: '', to: '' });
-
-function buildState(config?: AmpcodeConfig | null): AmpcodeFormState {
- const safe = config ?? {};
- const upstreamMappings = (safe.upstreamApiKeys ?? []).length
- ? (safe.upstreamApiKeys ?? []).map((m) => ({
- upstreamApiKey: m.upstreamApiKey ?? '',
- clientKeysText: (m.apiKeys ?? []).join('\n'),
- }))
- : [emptyUpstream()];
- const modelMappings = (safe.modelMappings ?? []).length
- ? (safe.modelMappings ?? []).map((m) => ({ from: m.from ?? '', to: m.to ?? '' }))
- : [emptyModelMapping()];
- return {
- upstreamUrl: safe.upstreamUrl ?? '',
- upstreamApiKey: '',
- forceModelMappings: safe.forceModelMappings === true,
- upstreamMappings,
- modelMappings,
- };
-}
-
-const parseClientKeys = (text: string): string[] =>
- text
- .split(/[\n,]+/)
- .map((s) => s.trim())
- .filter(Boolean);
-
-interface AmpcodeFormProps {
- resource: ProviderResource | null;
- mutating: boolean;
- formId: string;
- onSubmit: (config: AmpcodeConfig) => Promise;
- onDirtyChange?: (dirty: boolean) => void;
-}
-
-export function AmpcodeForm({
- resource,
- mutating,
- formId,
- onSubmit,
- onDirtyChange,
-}: AmpcodeFormProps) {
- const { t } = useTranslation();
- const fid = useId();
- const initialConfig = (resource?.raw as AmpcodeConfig | undefined) ?? {};
- const [form, setForm] = useState(() => buildState(initialConfig));
- const [initialFormSignature] = useState(() => JSON.stringify(buildState(initialConfig)));
- const [error, setError] = useState(null);
-
- const isDirty = useMemo(
- () => JSON.stringify(form) !== initialFormSignature,
- [form, initialFormSignature]
- );
-
- useEffect(() => {
- onDirtyChange?.(isDirty);
- }, [isDirty, onDirtyChange]);
-
- const handleSubmit = async (e: React.FormEvent) => {
- e.preventDefault();
- try {
- setError(null);
- const upstreamApiKeys: AmpcodeUpstreamApiKeyMapping[] = [];
- const seen = new Set();
- form.upstreamMappings.forEach((m) => {
- const key = m.upstreamApiKey.trim();
- if (!key || seen.has(key)) return;
- const clientKeys = parseClientKeys(m.clientKeysText);
- if (!clientKeys.length) return;
- seen.add(key);
- upstreamApiKeys.push({ upstreamApiKey: key, apiKeys: clientKeys });
- });
-
- const modelMappings: AmpcodeModelMapping[] = [];
- const seenFrom = new Set();
- form.modelMappings.forEach((m) => {
- const from = m.from.trim();
- const to = m.to.trim();
- if (!from || !to) return;
- const id = from.toLowerCase();
- if (seenFrom.has(id)) return;
- seenFrom.add(id);
- modelMappings.push({ from, to });
- });
-
- const next: AmpcodeConfig = {
- upstreamUrl: form.upstreamUrl.trim() || undefined,
- upstreamApiKey:
- form.upstreamApiKey.trim() || initialConfig.upstreamApiKey?.trim() || undefined,
- upstreamApiKeys: upstreamApiKeys.length ? upstreamApiKeys : undefined,
- modelMappings: modelMappings.length ? modelMappings : undefined,
- forceModelMappings: form.forceModelMappings,
- };
- await onSubmit(next);
- } catch (err) {
- setError(err instanceof Error ? err.message : String(err));
- }
- };
-
- return (
-
- );
-}
diff --git a/src/features/providers/sheets/forms/BaseProviderForm.tsx b/src/features/providers/sheets/forms/BaseProviderForm.tsx
index f8ad727..5b3cecc 100644
--- a/src/features/providers/sheets/forms/BaseProviderForm.tsx
+++ b/src/features/providers/sheets/forms/BaseProviderForm.tsx
@@ -37,7 +37,7 @@ export interface BaseProviderFormHandle {
}
interface BaseProviderFormProps {
- brand: Exclude;
+ brand: ProviderBrand;
resource: ProviderResource | null;
mode: 'create' | 'edit';
mutating: boolean;
@@ -62,7 +62,7 @@ const formatJsonObject = (value?: Record): string => {
};
function buildInitialForm(
- brand: Exclude,
+ brand: ProviderBrand,
resource: ProviderResource | null,
mode: 'create' | 'edit'
): ProviderEntryFormInput {
diff --git a/src/features/providers/types.ts b/src/features/providers/types.ts
index 6ee3c49..656778b 100644
--- a/src/features/providers/types.ts
+++ b/src/features/providers/types.ts
@@ -7,8 +7,7 @@ export type ProviderBrand =
| 'codex'
| 'claude'
| 'vertex'
- | 'openaiCompatibility'
- | 'ampcode';
+ | 'openaiCompatibility';
export const PROVIDER_SORT_BY_VALUES = ['name', 'priority', 'recent-success'] as const;
export type ProviderSortBy = (typeof PROVIDER_SORT_BY_VALUES)[number];
@@ -21,13 +20,11 @@ export type ProviderResourceSelector =
| { brand: 'codex'; apiKey: string; baseUrl?: string; index: number }
| { brand: 'claude'; apiKey: string; baseUrl?: string; index: number }
| { brand: 'vertex'; apiKey: string; baseUrl?: string; index: number }
- | { brand: 'openaiCompatibility'; name: string; index: number }
- | { brand: 'ampcode' };
+ | { brand: 'openaiCompatibility'; name: string; index: number };
export interface ProviderResourceFlags {
cloakEnabled?: boolean;
websockets?: boolean;
- forceModelMappings?: boolean;
isPlaceholder?: boolean;
}
@@ -35,7 +32,7 @@ export interface ProviderResource {
/** 稳定 id,用作 React key 与选中态判断 */
id: string;
brand: ProviderBrand;
- /** 在原数组中的下标。Ampcode 永远为 0 */
+ /** 在原数组中的下标 */
originalIndex: number;
/** 表格 key 列显示名(OpenAI=name,其余=null) */
name: string | null;
@@ -50,7 +47,7 @@ export interface ProviderResource {
proxyUrl: string | null;
prefix: string | null;
modelCount: number;
- /** 去重后的模型名(ampcode 为映射两端), 供筛选/搜索用 */
+ /** 去重后的模型名, 供筛选/搜索用 */
models: string[];
/** 排序用优先级,未配置时为 0 */
priority: number;
diff --git a/src/features/providers/useProviderWorkbench.ts b/src/features/providers/useProviderWorkbench.ts
index 2c4f6bf..97b97b3 100644
--- a/src/features/providers/useProviderWorkbench.ts
+++ b/src/features/providers/useProviderWorkbench.ts
@@ -1,5 +1,5 @@
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
-import { ampcodeApi, providersApi } from '@/services/api';
+import { providersApi } from '@/services/api';
import { getErrorMessage } from '@/utils/helpers';
import { useAuthStore, useConfigStore } from '@/stores';
import {
@@ -7,13 +7,11 @@ import {
withoutDisableAllModelsRule,
} from '@/components/providers/utils';
import type {
- AmpcodeConfig,
GeminiKeyConfig,
OpenAIProviderConfig,
ProviderKeyConfig,
} from '@/types';
import {
- ampcodeToResource,
claudeToResource,
codexToResource,
geminiToResource,
@@ -42,7 +40,6 @@ export interface UseProviderWorkbenchResult {
updateProvider: (resource: ProviderResource, input: ProviderEntryFormInput) => Promise;
deleteProvider: (resource: ProviderResource) => Promise;
toggleDisabled: (resource: ProviderResource, disabled: boolean) => Promise;
- saveAmpcode: (config: AmpcodeConfig) => Promise;
mutating: boolean;
refreshSnapshot: () => void;
}
@@ -208,10 +205,9 @@ export function useProviderWorkbench(): UseProviderWorkbenchResult {
setIsFetching(true);
setErrorMessage(null);
try {
- const [configResult, vertexResult, ampcodeResult, openaiResult] = await Promise.allSettled([
+ const [configResult, vertexResult, openaiResult] = await Promise.allSettled([
fetchConfig(undefined, true),
providersApi.getVertexConfigs(),
- ampcodeApi.getAmpcode(),
providersApi.getOpenAIProviders(),
]);
if (configResult.status !== 'fulfilled') {
@@ -220,9 +216,6 @@ export function useProviderWorkbench(): UseProviderWorkbenchResult {
if (vertexResult.status === 'fulfilled') {
updateConfigValue('vertex-api-key', vertexResult.value || []);
}
- if (ampcodeResult.status === 'fulfilled') {
- updateConfigValue('ampcode', ampcodeResult.value);
- }
if (openaiResult.status === 'fulfilled') {
updateConfigValue('openai-compatibility', openaiResult.value || []);
}
@@ -268,9 +261,6 @@ export function useProviderWorkbench(): UseProviderWorkbenchResult {
case 'openaiCompatibility':
resources = (config.openaiCompatibility ?? []).map((c, i) => openaiToResource(c, i));
break;
- case 'ampcode':
- resources = [ampcodeToResource(config.ampcode)];
- break;
}
return {
id: brand,
@@ -349,8 +339,6 @@ export function useProviderWorkbench(): UseProviderWorkbenchResult {
const next = [...(config?.openaiCompatibility ?? [])];
next.push(buildOpenAIConfig(input));
await persistOpenAIConfigs(next);
- } else if (brand === 'ampcode') {
- throw new Error('Use saveAmpcode for ampcode create/update');
}
refreshSnapshot();
} finally {
@@ -399,8 +387,6 @@ export function useProviderWorkbench(): UseProviderWorkbenchResult {
const existing = list[idx];
list[idx] = buildOpenAIConfig(input, existing);
await persistOpenAIConfigs(list);
- } else if (brand === 'ampcode') {
- throw new Error('Use saveAmpcode for ampcode update');
}
refreshSnapshot();
} finally {
@@ -443,13 +429,6 @@ export function useProviderWorkbench(): UseProviderWorkbenchResult {
await providersApi.deleteOpenAIProvider(sel.index);
const next = (config?.openaiCompatibility ?? []).filter((_, i) => i !== sel.index);
updateConfigValue('openai-compatibility', next);
- } else if (sel.brand === 'ampcode') {
- await Promise.allSettled([
- ampcodeApi.clearUpstreamUrl(),
- ampcodeApi.clearUpstreamApiKey(),
- ampcodeApi.clearModelMappings(),
- ]);
- updateConfigValue('ampcode', {});
}
refreshSnapshot();
} finally {
@@ -499,8 +478,6 @@ export function useProviderWorkbench(): UseProviderWorkbenchResult {
list[idx] = { ...current, disabled };
updateConfigValue('openai-compatibility', list);
}
- } else if (brand === 'ampcode') {
- /* ampcode toggle 不支持,跳过 */
}
refreshSnapshot();
} finally {
@@ -518,48 +495,6 @@ export function useProviderWorkbench(): UseProviderWorkbenchResult {
]
);
- const saveAmpcode = useCallback(
- async (next: AmpcodeConfig) => {
- setMutating(true);
- try {
- // 细粒度 PUT 序列以保留兼容性
- const url = (next.upstreamUrl ?? '').trim();
- if (url) {
- await ampcodeApi.updateUpstreamUrl(url);
- } else {
- await ampcodeApi.clearUpstreamUrl();
- }
-
- const fallbackKey = (next.upstreamApiKey ?? '').trim();
- if (fallbackKey) {
- await ampcodeApi.updateUpstreamApiKey(fallbackKey);
- } else {
- await ampcodeApi.clearUpstreamApiKey();
- }
-
- if (Array.isArray(next.upstreamApiKeys) && next.upstreamApiKeys.length) {
- await ampcodeApi.saveUpstreamApiKeys(next.upstreamApiKeys);
- } else {
- await ampcodeApi.saveUpstreamApiKeys([]);
- }
-
- if (Array.isArray(next.modelMappings) && next.modelMappings.length) {
- await ampcodeApi.saveModelMappings(next.modelMappings);
- } else {
- await ampcodeApi.clearModelMappings();
- }
-
- await ampcodeApi.updateForceModelMappings(next.forceModelMappings === true);
-
- updateConfigValue('ampcode', next);
- refreshSnapshot();
- } finally {
- setMutating(false);
- }
- },
- [updateConfigValue, refreshSnapshot]
- );
-
return {
connected,
isPending,
@@ -572,7 +507,6 @@ export function useProviderWorkbench(): UseProviderWorkbenchResult {
updateProvider,
deleteProvider,
toggleDisabled,
- saveAmpcode,
mutating,
refreshSnapshot,
};
diff --git a/src/i18n/locales/en.json b/src/i18n/locales/en.json
index 9c891f8..14fb8f9 100644
--- a/src/i18n/locales/en.json
+++ b/src/i18n/locales/en.json
@@ -148,7 +148,7 @@
"quick_actions": "Quick Actions",
"current_config": "Current Configuration",
"management_keys": "Management Keys",
- "provider_keys_detail": "G:{{gemini}} C:{{codex}} Cl:{{claude}} V:{{vertex}} O:{{openai}} Amp:{{ampcode}}",
+ "provider_keys_detail": "G:{{gemini}} C:{{codex}} Cl:{{claude}} V:{{vertex}} O:{{openai}}",
"oauth_credentials": "OAuth Credentials",
"edit_settings": "Edit Settings",
"routing_strategy": "Routing Strategy",
@@ -1309,8 +1309,6 @@
"openai_provider_added": "OpenAI provider added successfully",
"openai_provider_updated": "OpenAI provider updated successfully",
"openai_provider_deleted": "OpenAI provider deleted successfully",
- "ampcode_updated": "Ampcode configuration updated",
- "ampcode_upstream_api_key_cleared": "Ampcode upstream API key override cleared",
"openai_model_name_required": "Model name is required",
"openai_test_url_required": "Please provide a valid Base URL before testing",
"openai_test_key_required": "Please add at least one API key before testing",
@@ -1385,17 +1383,14 @@
},
"categories": {
"title": "Providers",
- "activeCount": "{{active}}/{{total}} active",
- "ampcodeActive": "Connected",
- "ampcodeInactive": "Not configured"
+ "activeCount": "{{active}}/{{total}} active"
},
"providerNames": {
"gemini": "Gemini",
"codex": "Codex",
"claude": "Claude",
"vertex": "Vertex",
- "openaiCompatibility": "OpenAI Compatible",
- "ampcode": "Amp CLI"
+ "openaiCompatibility": "OpenAI Compatible"
},
"table": {
"key": "Key",
@@ -1407,12 +1402,10 @@
"metrics": {
"models": "Models",
"keys": "Keys",
- "headers": "Headers",
- "mappings": "Mappings"
+ "headers": "Headers"
},
"websocketsTag": "WebSockets",
"cloakTag": "Cloak",
- "noFallbackKey": "No fallback key",
"empty": "No resources yet, click \"New\" to add.",
"filterPlaceholder": "Search keys, URLs, prefixes…",
"description": "Manage resources under {{route}}",
@@ -1495,25 +1488,9 @@
"baseUrlRequired": "Base URL is required"
}
},
- "ampcode": {
- "upstreamUrl": "Upstream URL",
- "upstreamApiKey": "Upstream API key (fallback)",
- "upstreamApiKeyHint": "Used when no key mapping matches",
- "keyMappingsSection": "Upstream key mappings",
- "mappingRow": "Mapping #{{index}}",
- "clientKeys": "Client keys",
- "clientKeysHint": "One per line; matched keys forward to the upstream key above",
- "addMapping": "Add key mapping",
- "modelMappingsSection": "Model mappings",
- "addModelMapping": "Add model mapping",
- "forceModelMappings": "Force model mappings",
- "forceModelMappingsHint": "Requests that don't match a mapping are rejected"
- },
"delete": {
"title": "Delete resource",
- "confirm": "Delete {{name}}? This action cannot be undone.",
- "ampcodeTitle": "Clear Amp CLI configuration",
- "ampcodeConfirm": "Clear all Amp CLI configuration? Upstream URL, keys and model mappings will be removed."
+ "confirm": "Delete {{name}}? This action cannot be undone."
},
"toast": {
"created": "Created",
diff --git a/src/i18n/locales/ru.json b/src/i18n/locales/ru.json
index b584195..025235e 100644
--- a/src/i18n/locales/ru.json
+++ b/src/i18n/locales/ru.json
@@ -147,7 +147,7 @@
"quick_actions": "Быстрые действия",
"current_config": "Текущая конфигурация",
"management_keys": "Ключи управления",
- "provider_keys_detail": "G:{{gemini}} C:{{codex}} Cl:{{claude}} V:{{vertex}} O:{{openai}} Amp:{{ampcode}}",
+ "provider_keys_detail": "G:{{gemini}} C:{{codex}} Cl:{{claude}} V:{{vertex}} O:{{openai}}",
"oauth_credentials": "Учётные данные OAuth",
"edit_settings": "Изменить настройки",
"routing_strategy": "Стратегия маршрутизации",
@@ -1286,8 +1286,6 @@
"openai_provider_added": "Провайдер OpenAI успешно добавлен",
"openai_provider_updated": "Провайдер OpenAI успешно обновлён",
"openai_provider_deleted": "Провайдер OpenAI успешно удалён",
- "ampcode_updated": "Настройки Ampcode обновлены",
- "ampcode_upstream_api_key_cleared": "Переопределение upstream-ключа Ampcode очищено",
"openai_model_name_required": "Введите имя модели",
"openai_test_url_required": "Укажите корректный базовый URL перед тестированием",
"openai_test_key_required": "Добавьте хотя бы один API-ключ перед тестированием",
@@ -1362,17 +1360,14 @@
},
"categories": {
"title": "Провайдеры",
- "activeCount": "{{active}}/{{total}} активных",
- "ampcodeActive": "Подключено",
- "ampcodeInactive": "Не настроено"
+ "activeCount": "{{active}}/{{total}} активных"
},
"providerNames": {
"gemini": "Gemini",
"codex": "Codex",
"claude": "Claude",
"vertex": "Vertex",
- "openaiCompatibility": "OpenAI-совместимый",
- "ampcode": "Amp CLI"
+ "openaiCompatibility": "OpenAI-совместимый"
},
"table": {
"key": "Ключ",
@@ -1384,12 +1379,10 @@
"metrics": {
"models": "Модели",
"keys": "Ключи",
- "headers": "Заголовки",
- "mappings": "Сопоставления"
+ "headers": "Заголовки"
},
"websocketsTag": "WebSockets",
"cloakTag": "Cloak",
- "noFallbackKey": "Резервный ключ не задан",
"empty": "Нет ресурсов, нажмите \"Создать\".",
"filterPlaceholder": "Поиск по ключам, URL, префиксам…",
"description": "Управление ресурсами {{route}}",
@@ -1472,25 +1465,9 @@
"baseUrlRequired": "Base URL обязателен"
}
},
- "ampcode": {
- "upstreamUrl": "Upstream URL",
- "upstreamApiKey": "Резервный API-ключ",
- "upstreamApiKeyHint": "Используется, когда нет совпадений",
- "keyMappingsSection": "Сопоставление ключей",
- "mappingRow": "Сопоставление #{{index}}",
- "clientKeys": "Клиентские ключи",
- "clientKeysHint": "По одному в строке; совпавшие пересылаются на ключ выше",
- "addMapping": "Добавить сопоставление",
- "modelMappingsSection": "Сопоставление моделей",
- "addModelMapping": "Добавить сопоставление",
- "forceModelMappings": "Принудительное сопоставление",
- "forceModelMappingsHint": "Запросы без совпадений отклоняются"
- },
"delete": {
"title": "Удалить ресурс",
- "confirm": "Удалить {{name}}? Действие необратимо.",
- "ampcodeTitle": "Очистить настройки Amp CLI",
- "ampcodeConfirm": "Удалить все настройки Amp CLI? Upstream URL, ключи и сопоставления будут удалены."
+ "confirm": "Удалить {{name}}? Действие необратимо."
},
"toast": {
"created": "Создано",
diff --git a/src/i18n/locales/zh-CN.json b/src/i18n/locales/zh-CN.json
index 21e0ea5..8c694fd 100644
--- a/src/i18n/locales/zh-CN.json
+++ b/src/i18n/locales/zh-CN.json
@@ -148,7 +148,7 @@
"quick_actions": "快捷操作",
"current_config": "当前配置",
"management_keys": "管理密钥",
- "provider_keys_detail": "G:{{gemini}} C:{{codex}} Cl:{{claude}} V:{{vertex}} O:{{openai}} Amp:{{ampcode}}",
+ "provider_keys_detail": "G:{{gemini}} C:{{codex}} Cl:{{claude}} V:{{vertex}} O:{{openai}}",
"oauth_credentials": "OAuth 凭证",
"edit_settings": "编辑设置",
"routing_strategy": "路由策略",
@@ -1309,8 +1309,6 @@
"openai_provider_added": "OpenAI提供商添加成功",
"openai_provider_updated": "OpenAI提供商更新成功",
"openai_provider_deleted": "OpenAI提供商删除成功",
- "ampcode_updated": "Ampcode 配置已更新",
- "ampcode_upstream_api_key_cleared": "Ampcode upstream API key 覆盖已清除",
"openai_model_name_required": "请填写模型名称",
"openai_test_url_required": "请先填写有效的 Base URL 以进行测试",
"openai_test_key_required": "请至少填写一个 API 密钥以进行测试",
@@ -1385,17 +1383,14 @@
},
"categories": {
"title": "提供商",
- "activeCount": "{{active}}/{{total}} 活跃",
- "ampcodeActive": "已连接",
- "ampcodeInactive": "未配置"
+ "activeCount": "{{active}}/{{total}} 活跃"
},
"providerNames": {
"gemini": "Gemini",
"codex": "Codex",
"claude": "Claude",
"vertex": "Vertex",
- "openaiCompatibility": "OpenAI 兼容",
- "ampcode": "Amp CLI"
+ "openaiCompatibility": "OpenAI 兼容"
},
"table": {
"key": "密钥",
@@ -1407,12 +1402,10 @@
"metrics": {
"models": "模型",
"keys": "密钥",
- "headers": "请求头",
- "mappings": "映射"
+ "headers": "请求头"
},
"websocketsTag": "WebSockets",
"cloakTag": "Cloak",
- "noFallbackKey": "未设置兜底密钥",
"empty": "尚未添加配置,点击右上角新建。",
"filterPlaceholder": "搜索密钥、地址、前缀…",
"description": "在 {{route}} 下管理资源",
@@ -1495,25 +1488,9 @@
"baseUrlRequired": "服务地址必填"
}
},
- "ampcode": {
- "upstreamUrl": "上游 URL",
- "upstreamApiKey": "上游 API 密钥(兜底)",
- "upstreamApiKeyHint": "未匹配密钥映射时使用",
- "keyMappingsSection": "上游密钥映射",
- "mappingRow": "映射 #{{index}}",
- "clientKeys": "客户端密钥",
- "clientKeysHint": "每行一个,匹配后转发到上述上游密钥",
- "addMapping": "添加密钥映射",
- "modelMappingsSection": "模型映射",
- "addModelMapping": "添加模型映射",
- "forceModelMappings": "强制模型映射",
- "forceModelMappingsHint": "启用后,所有请求必须命中模型映射规则"
- },
"delete": {
"title": "删除资源",
- "confirm": "确定要删除 {{name}} 吗?此操作不可撤销。",
- "ampcodeTitle": "清空 Amp CLI 配置",
- "ampcodeConfirm": "确定要清空 Amp CLI 配置吗?上游 URL、API 密钥与模型映射都会被移除。"
+ "confirm": "确定要删除 {{name}} 吗?此操作不可撤销。"
},
"toast": {
"created": "创建成功",
diff --git a/src/i18n/locales/zh-TW.json b/src/i18n/locales/zh-TW.json
index 6c6da9d..9f53eca 100644
--- a/src/i18n/locales/zh-TW.json
+++ b/src/i18n/locales/zh-TW.json
@@ -148,7 +148,7 @@
"quick_actions": "快速操作",
"current_config": "目前設定",
"management_keys": "管理金鑰",
- "provider_keys_detail": "G:{{gemini}} C:{{codex}} Cl:{{claude}} V:{{vertex}} O:{{openai}} Amp:{{ampcode}}",
+ "provider_keys_detail": "G:{{gemini}} C:{{codex}} Cl:{{claude}} V:{{vertex}} O:{{openai}}",
"oauth_credentials": "OAuth 憑證",
"edit_settings": "編輯設定",
"routing_strategy": "路由策略",
@@ -1335,8 +1335,6 @@
"openai_provider_added": "OpenAI 供應商新增成功",
"openai_provider_updated": "OpenAI 供應商更新成功",
"openai_provider_deleted": "OpenAI 供應商刪除成功",
- "ampcode_updated": "Ampcode 設定已更新",
- "ampcode_upstream_api_key_cleared": "Ampcode upstream API key 覆寫已清除",
"openai_model_name_required": "請填寫模型名稱",
"openai_test_url_required": "請先填寫有效的 Base URL 以進行測試",
"openai_test_key_required": "請至少填寫一個 API 金鑰以進行測試",
@@ -1411,17 +1409,14 @@
},
"categories": {
"title": "提供商",
- "activeCount": "{{active}}/{{total}} 活躍",
- "ampcodeActive": "已連線",
- "ampcodeInactive": "未設定"
+ "activeCount": "{{active}}/{{total}} 活躍"
},
"providerNames": {
"gemini": "Gemini",
"codex": "Codex",
"claude": "Claude",
"vertex": "Vertex",
- "openaiCompatibility": "OpenAI 相容",
- "ampcode": "Amp CLI"
+ "openaiCompatibility": "OpenAI 相容"
},
"table": {
"key": "金鑰",
@@ -1433,12 +1428,10 @@
"metrics": {
"models": "模型",
"keys": "金鑰",
- "headers": "請求標頭",
- "mappings": "映射"
+ "headers": "請求標頭"
},
"websocketsTag": "WebSockets",
"cloakTag": "Cloak",
- "noFallbackKey": "未設定備援金鑰",
"empty": "尚未新增設定,點擊右上角新增。",
"filterPlaceholder": "搜尋金鑰、位址、前綴…",
"description": "在 {{route}} 下管理資源",
@@ -1521,25 +1514,9 @@
"baseUrlRequired": "服務位址必填"
}
},
- "ampcode": {
- "upstreamUrl": "上游 URL",
- "upstreamApiKey": "上游 API 金鑰(備援)",
- "upstreamApiKeyHint": "未匹配金鑰映射時使用",
- "keyMappingsSection": "上游金鑰映射",
- "mappingRow": "映射 #{{index}}",
- "clientKeys": "客戶端金鑰",
- "clientKeysHint": "每行一個,匹配後轉發到上述上游金鑰",
- "addMapping": "新增金鑰映射",
- "modelMappingsSection": "模型映射",
- "addModelMapping": "新增模型映射",
- "forceModelMappings": "強制模型映射",
- "forceModelMappingsHint": "啟用後,所有請求必須命中模型映射規則"
- },
"delete": {
"title": "刪除資源",
- "confirm": "確定要刪除 {{name}} 嗎?此操作不可復原。",
- "ampcodeTitle": "清空 Amp CLI 設定",
- "ampcodeConfirm": "確定要清空 Amp CLI 設定嗎?上游 URL、API 金鑰與模型映射都會被移除。"
+ "confirm": "確定要刪除 {{name}} 嗎?此操作不可復原。"
},
"toast": {
"created": "建立成功",
diff --git a/src/pages/DashboardPage.tsx b/src/pages/DashboardPage.tsx
index 79d45e0..4fab543 100644
--- a/src/pages/DashboardPage.tsx
+++ b/src/pages/DashboardPage.tsx
@@ -5,7 +5,6 @@ import { IconKey, IconBot, IconFileText, IconSatellite } from '@/components/ui/i
import { useAuthStore, useConfigStore, useModelsStore } from '@/stores';
import { authFilesApi } from '@/services/api';
import { useApiKeysForModels } from '@/hooks/useApiKeysForModels';
-import type { AmpcodeConfig } from '@/types';
import { formatDateValue } from '@/utils/format';
import styles from './DashboardPage.module.scss';
@@ -20,17 +19,6 @@ interface QuickStat {
type TimeOfDay = 'morning' | 'afternoon' | 'evening' | 'night';
-const countAmpcodeConfig = (value: AmpcodeConfig | undefined): number => {
- if (!value) return 0;
- const configured =
- Boolean(value.upstreamUrl?.trim()) ||
- Boolean(value.upstreamApiKey?.trim()) ||
- (value.upstreamApiKeys?.length ?? 0) > 0 ||
- (value.modelMappings?.length ?? 0) > 0 ||
- value.forceModelMappings === true;
- return configured ? 1 : 0;
-};
-
function getTimeOfDay(): TimeOfDay {
const hour = new Date().getHours();
if (hour >= 5 && hour < 12) return 'morning';
@@ -121,7 +109,6 @@ export function DashboardPage() {
claude: config.claudeApiKeys?.length ?? 0,
vertex: config.vertexApiKeys?.length ?? 0,
openai: config.openaiCompatibility?.length ?? 0,
- ampcode: countAmpcodeConfig(config.ampcode),
}
: null;
const totalProviderKeys = providerStats
@@ -150,7 +137,6 @@ export function DashboardPage() {
claude: providerStats.claude,
vertex: providerStats.vertex,
openai: providerStats.openai,
- ampcode: providerStats.ampcode,
})
: undefined,
},
diff --git a/src/services/api/ampcode.ts b/src/services/api/ampcode.ts
deleted file mode 100644
index 4071f08..0000000
--- a/src/services/api/ampcode.ts
+++ /dev/null
@@ -1,59 +0,0 @@
-/**
- * Amp CLI Integration (ampcode) 相关 API
- */
-
-import { apiClient } from './client';
-import {
- normalizeAmpcodeConfig,
- normalizeAmpcodeModelMappings,
- normalizeAmpcodeUpstreamApiKeys,
-} from './transformers';
-import type { AmpcodeConfig, AmpcodeModelMapping, AmpcodeUpstreamApiKeyMapping } from '@/types';
-
-const serializeUpstreamApiKeyMappings = (mappings: AmpcodeUpstreamApiKeyMapping[]) =>
- mappings.map((mapping) => ({
- 'upstream-api-key': mapping.upstreamApiKey,
- 'api-keys': mapping.apiKeys,
- }));
-
-export const ampcodeApi = {
- async getAmpcode(): Promise {
- const data = await apiClient.get('/ampcode');
- return normalizeAmpcodeConfig(data) ?? {};
- },
-
- updateUpstreamUrl: (url: string) => apiClient.put('/ampcode/upstream-url', { value: url }),
- clearUpstreamUrl: () => apiClient.delete('/ampcode/upstream-url'),
-
- updateUpstreamApiKey: (apiKey: string) => apiClient.put('/ampcode/upstream-api-key', { value: apiKey }),
- clearUpstreamApiKey: () => apiClient.delete('/ampcode/upstream-api-key'),
-
- async getUpstreamApiKeys(): Promise {
- const data = await apiClient.get>('/ampcode/upstream-api-keys');
- const list = data?.['upstream-api-keys'] ?? data?.upstreamApiKeys ?? data?.items ?? data;
- return normalizeAmpcodeUpstreamApiKeys(list);
- },
-
- saveUpstreamApiKeys: (mappings: AmpcodeUpstreamApiKeyMapping[]) =>
- apiClient.put('/ampcode/upstream-api-keys', { value: serializeUpstreamApiKeyMappings(mappings) }),
- patchUpstreamApiKeys: (mappings: AmpcodeUpstreamApiKeyMapping[]) =>
- apiClient.patch('/ampcode/upstream-api-keys', { value: serializeUpstreamApiKeyMappings(mappings) }),
- deleteUpstreamApiKeys: (upstreamApiKeys: string[]) =>
- apiClient.delete('/ampcode/upstream-api-keys', { data: { value: upstreamApiKeys } }),
-
- async getModelMappings(): Promise {
- const data = await apiClient.get>('/ampcode/model-mappings');
- const list = data?.['model-mappings'] ?? data?.modelMappings ?? data?.items ?? data;
- return normalizeAmpcodeModelMappings(list);
- },
-
- saveModelMappings: (mappings: AmpcodeModelMapping[]) =>
- apiClient.put('/ampcode/model-mappings', { value: mappings }),
- patchModelMappings: (mappings: AmpcodeModelMapping[]) =>
- apiClient.patch('/ampcode/model-mappings', { value: mappings }),
- clearModelMappings: () => apiClient.delete('/ampcode/model-mappings'),
- deleteModelMappings: (fromList: string[]) =>
- apiClient.delete('/ampcode/model-mappings', { data: { value: fromList } }),
-
- updateForceModelMappings: (enabled: boolean) => apiClient.put('/ampcode/force-model-mappings', { value: enabled })
-};
diff --git a/src/services/api/index.ts b/src/services/api/index.ts
index 08bb1f2..c5cf424 100644
--- a/src/services/api/index.ts
+++ b/src/services/api/index.ts
@@ -4,7 +4,6 @@ export * from './apiKeyUsage';
export * from './config';
export * from './configFile';
export * from './apiKeys';
-export * from './ampcode';
export * from './providers';
export * from './authFiles';
export * from './oauth';
diff --git a/src/services/api/transformers.ts b/src/services/api/transformers.ts
index 90dce78..4267065 100644
--- a/src/services/api/transformers.ts
+++ b/src/services/api/transformers.ts
@@ -4,10 +4,7 @@ import type {
GeminiKeyConfig,
ModelAlias,
OpenAIProviderConfig,
- ProviderKeyConfig,
- AmpcodeConfig,
- AmpcodeModelMapping,
- AmpcodeUpstreamApiKeyMapping
+ ProviderKeyConfig
} from '@/types';
import type { Config } from '@/types/config';
import { buildHeaderObject } from '@/utils/headers';
@@ -272,79 +269,6 @@ const normalizeOauthExcluded = (payload: unknown): Record | un
return map;
};
-const normalizeAmpcodeModelMappings = (input: unknown): AmpcodeModelMapping[] => {
- if (!Array.isArray(input)) return [];
- const seen = new Set();
- const mappings: AmpcodeModelMapping[] = [];
-
- input.forEach((entry) => {
- if (!isRecord(entry)) return;
- const from = String(entry.from ?? '').trim();
- const to = String(entry.to ?? '').trim();
- if (!from || !to) return;
- const key = from.toLowerCase();
- if (seen.has(key)) return;
- seen.add(key);
- mappings.push({ from, to });
- });
-
- return mappings;
-};
-
-const normalizeAmpcodeUpstreamApiKeys = (input: unknown): AmpcodeUpstreamApiKeyMapping[] => {
- if (!Array.isArray(input)) return [];
-
- const seen = new Set();
- const mappings: AmpcodeUpstreamApiKeyMapping[] = [];
-
- input.forEach((entry) => {
- if (!isRecord(entry)) return;
-
- const upstreamApiKey = String(entry['upstream-api-key'] ?? '').trim();
- if (!upstreamApiKey || seen.has(upstreamApiKey)) return;
-
- const rawApiKeys = entry['api-keys'] ?? [];
- const apiKeys = Array.isArray(rawApiKeys)
- ? Array.from(new Set(rawApiKeys.map((item) => String(item ?? '').trim()).filter(Boolean)))
- : [];
- if (!apiKeys.length) return;
-
- seen.add(upstreamApiKey);
- mappings.push({ upstreamApiKey, apiKeys });
- });
-
- return mappings;
-};
-
-const normalizeAmpcodeConfig = (payload: unknown): AmpcodeConfig | undefined => {
- const sourceRaw = isRecord(payload) ? (payload.ampcode ?? payload) : payload;
- if (!isRecord(sourceRaw)) return undefined;
- const source = sourceRaw;
-
- const config: AmpcodeConfig = {};
- const upstreamUrl = source['upstream-url'];
- if (upstreamUrl) config.upstreamUrl = String(upstreamUrl);
- const upstreamApiKey = source['upstream-api-key'];
- if (upstreamApiKey) config.upstreamApiKey = String(upstreamApiKey);
-
- const upstreamApiKeys = normalizeAmpcodeUpstreamApiKeys(source['upstream-api-keys']);
- if (upstreamApiKeys.length) {
- config.upstreamApiKeys = upstreamApiKeys;
- }
-
- const forceModelMappings = normalizeBoolean(source['force-model-mappings']);
- if (forceModelMappings !== undefined) {
- config.forceModelMappings = forceModelMappings;
- }
-
- const modelMappings = normalizeAmpcodeModelMappings(source['model-mappings']);
- if (modelMappings.length) {
- config.modelMappings = modelMappings;
- }
-
- return config;
-};
-
/**
* 规范化 /config 返回值
*/
@@ -435,11 +359,6 @@ export const normalizeConfigResponse = (raw: unknown): Config => {
.filter(Boolean) as OpenAIProviderConfig[];
}
- const ampcode = normalizeAmpcodeConfig(raw.ampcode);
- if (ampcode) {
- config.ampcode = ampcode;
- }
-
const oauthExcluded = normalizeOauthExcluded(raw['oauth-excluded-models']);
if (oauthExcluded) {
config.oauthExcludedModels = oauthExcluded;
@@ -455,8 +374,5 @@ export {
normalizeOpenAIProvider,
normalizeProviderKeyConfig,
normalizeHeaders,
- normalizeExcludedModels,
- normalizeAmpcodeConfig,
- normalizeAmpcodeModelMappings,
- normalizeAmpcodeUpstreamApiKeys
+ normalizeExcludedModels
};
diff --git a/src/stores/useConfigStore.ts b/src/stores/useConfigStore.ts
index 9a21739..0f2e35d 100644
--- a/src/stores/useConfigStore.ts
+++ b/src/stores/useConfigStore.ts
@@ -45,7 +45,6 @@ const SECTION_KEYS: RawConfigSection[] = [
'force-model-prefix',
'routing/strategy',
'api-keys',
- 'ampcode',
'gemini-api-key',
'codex-api-key',
'claude-api-key',
@@ -79,8 +78,6 @@ const extractSectionValue = (config: Config | null, section?: RawConfigSection)
return config.routingStrategy;
case 'api-keys':
return config.apiKeys;
- case 'ampcode':
- return config.ampcode;
case 'gemini-api-key':
return config.geminiApiKeys;
case 'codex-api-key':
@@ -220,9 +217,6 @@ export const useConfigStore = create((set, get) => ({
case 'api-keys':
nextConfig.apiKeys = value as Config['apiKeys'];
break;
- case 'ampcode':
- nextConfig.ampcode = value as Config['ampcode'];
- break;
case 'gemini-api-key':
nextConfig.geminiApiKeys = value as Config['geminiApiKeys'];
break;
diff --git a/src/types/ampcode.ts b/src/types/ampcode.ts
deleted file mode 100644
index e2af8cc..0000000
--- a/src/types/ampcode.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-/**
- * Amp CLI Integration (ampcode) 配置
- */
-
-export interface AmpcodeModelMapping {
- from: string;
- to: string;
-}
-
-export interface AmpcodeUpstreamApiKeyMapping {
- upstreamApiKey: string;
- apiKeys: string[];
-}
-
-export interface AmpcodeConfig {
- upstreamUrl?: string;
- upstreamApiKey?: string;
- upstreamApiKeys?: AmpcodeUpstreamApiKeyMapping[];
- modelMappings?: AmpcodeModelMapping[];
- forceModelMappings?: boolean;
-}
diff --git a/src/types/config.ts b/src/types/config.ts
index df38b8a..7d5c2af 100644
--- a/src/types/config.ts
+++ b/src/types/config.ts
@@ -4,7 +4,6 @@
*/
import type { GeminiKeyConfig, ProviderKeyConfig, OpenAIProviderConfig } from './provider';
-import type { AmpcodeConfig } from './ampcode';
export interface QuotaExceededConfig {
switchProject?: boolean;
@@ -24,7 +23,6 @@ export interface Config {
forceModelPrefix?: boolean;
routingStrategy?: string;
apiKeys?: string[];
- ampcode?: AmpcodeConfig;
geminiApiKeys?: GeminiKeyConfig[];
codexApiKeys?: ProviderKeyConfig[];
claudeApiKeys?: ProviderKeyConfig[];
@@ -46,7 +44,6 @@ export type RawConfigSection =
| 'force-model-prefix'
| 'routing/strategy'
| 'api-keys'
- | 'ampcode'
| 'gemini-api-key'
| 'codex-api-key'
| 'claude-api-key'
diff --git a/src/types/index.ts b/src/types/index.ts
index ef57a3c..bafc732 100644
--- a/src/types/index.ts
+++ b/src/types/index.ts
@@ -7,7 +7,6 @@ export * from './api';
export * from './config';
export * from './auth';
export * from './provider';
-export * from './ampcode';
export * from './authFile';
export * from './oauth';
export * from './log';