feat(frontend): implement comprehensive API Settings Management Interface

Implement a complete API Management Interface for React frontend with split-
panel layout, migrating all features from legacy JS frontend.

New Features:
- API Settings page with 5 tabs: Providers, Endpoints, Cache, Model Pools, CLI Settings
- Provider Management: CRUD operations, multi-key rotation, health checks, test connection
- Endpoint Management: CRUD operations, cache strategy configuration, enable/disable toggle
- Cache Settings: Global configuration, statistics display, clear cache functionality
- Model Pool Management: CRUD operations, auto-discovery feature, provider exclusion
- CLI Settings Management: Provider-based and Direct modes, full CRUD support
- Multi-Key Settings Modal: Manage API keys with rotation strategies and weights
- Manage Models Modal: View and manage models per provider (LLM and Embedding)
- Sync to CodexLens: Integration handler for provider configuration sync

Technical Implementation:
- Created 12 new React components in components/api-settings/
- Extended lib/api.ts with 460+ lines of API client functions
- Created hooks/useApiSettings.ts with 772 lines of TanStack Query hooks
- Added RadioGroup UI component for form selections
- Implemented unified error handling with useNotifications across all operations
- Complete i18n support (500+ keys in English and Chinese)
- Route integration (/api-settings) and sidebar navigation

Code Quality:
- All acceptance criteria from plan.json verified
- Code review passed with Gemini (all 7 IMPL tasks complete)
- Follows existing patterns: Shadcn UI, TanStack Query, react-intl, Lucide icons
This commit is contained in:
catlog22
2026-02-01 23:58:04 +08:00
parent 690597bae8
commit abce912ee5
33 changed files with 5874 additions and 45 deletions

View File

@@ -345,6 +345,45 @@ import {
const BUILTIN_CLI_TOOLS = ['gemini', 'qwen', 'codex', 'opencode', 'claude'] as const;
type BuiltinCliTool = typeof BUILTIN_CLI_TOOLS[number];
/**
* Transaction ID type for concurrent session disambiguation
* Format: ccw-tx-${conversationId}-${timestamp}
*/
export type TransactionId = string;
/**
* Generate a unique transaction ID for the current execution
* @param conversationId - CCW conversation ID
* @returns Transaction ID in format: ccw-tx-${conversationId}-${uniquePart}
*/
export function generateTransactionId(conversationId: string): TransactionId {
// Use crypto.randomUUID() if available, otherwise use timestamp + random
const uniquePart = typeof crypto !== 'undefined' && crypto.randomUUID
? crypto.randomUUID().slice(0, 8)
: `${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
return `ccw-tx-${conversationId}-${uniquePart}`;
}
/**
* Inject transaction ID into user prompt
* @param prompt - Original user prompt
* @param txId - Transaction ID to inject
* @returns Prompt with transaction ID injected at the start
*/
export function injectTransactionId(prompt: string, txId: TransactionId): string {
return `[CCW-TX-ID: ${txId}]\n\n${prompt}`;
}
/**
* Extract transaction ID from prompt
* @param prompt - Prompt that may contain transaction ID
* @returns Transaction ID if found, null otherwise
*/
export function extractTransactionId(prompt: string): TransactionId | null {
const match = prompt.match(/\[CCW-TX-ID:\s+([^\]]+)\]/);
return match ? match[1] : null;
}
// Define Zod schema for validation
// tool accepts built-in tools or custom endpoint IDs (CLI封装)
const ParamsSchema = z.object({
@@ -788,6 +827,17 @@ async function executeCliTool(
timestamp: new Date().toISOString()
});
}
// Info message for Codex TTY limitation
if (tool === 'codex' && !supportsNativeResume(tool) && resumeDecision.strategy !== 'native') {
if (onOutput) {
onOutput({
type: 'stderr',
content: '[ccw] Using prompt-concat mode for Codex (Codex TTY limitation for native resume)\n',
timestamp: new Date().toISOString()
});
}
}
}
// Use configured primary model if no explicit model provided