fix(config): 优雅处理 Provider 未配置错误
- 添加 ConfigurationError 类替代 process.exit(1) - Server 端捕获配置错误并返回友好消息 - UI 端支持 config_error 类型的 WebSocket 消息 - 服务器不再因配置缺失而崩溃
This commit is contained in:
@@ -122,6 +122,8 @@ export type {
|
||||
CompressionStatus,
|
||||
CompressionType,
|
||||
CompressionResult,
|
||||
// WebSocket error types
|
||||
ConfigErrorPayload,
|
||||
} from './types.js';
|
||||
|
||||
// API Configuration
|
||||
|
||||
@@ -756,3 +756,21 @@ export interface CompressionResult {
|
||||
summaryTokens?: number;
|
||||
}
|
||||
|
||||
// ============ WebSocket 错误相关 ============
|
||||
|
||||
/**
|
||||
* 配置错误 Payload
|
||||
*
|
||||
* 当 Provider 未配置 API Key 时,通过 WebSocket 返回此错误
|
||||
*/
|
||||
export interface ConfigErrorPayload {
|
||||
/** 错误类型标识 */
|
||||
type: 'config_error';
|
||||
/** 错误消息 */
|
||||
message: string;
|
||||
/** 缺失配置的 Provider */
|
||||
provider?: string;
|
||||
/** 建议的操作 */
|
||||
action: 'open_providers_panel' | 'open_settings';
|
||||
}
|
||||
|
||||
|
||||
@@ -7,12 +7,15 @@
|
||||
import { useState, useEffect, useCallback, useRef } from 'react';
|
||||
import { createWebSocket, getMessages, type Message } from '../api/client.js';
|
||||
import type { PermissionRequest } from '../components/PermissionDialog.js';
|
||||
import type { ConfigErrorPayload } from '../api/types.js';
|
||||
|
||||
interface UseChatOptions {
|
||||
sessionId: string;
|
||||
onError?: (error: Error) => void;
|
||||
onSessionNotFound?: () => void;
|
||||
onSessionUpdated?: (sessionId: string, name: string) => void;
|
||||
/** 配置错误回调(如 API Key 未配置) */
|
||||
onConfigError?: (error: ConfigErrorPayload) => void;
|
||||
}
|
||||
|
||||
interface ChatState {
|
||||
@@ -23,7 +26,7 @@ interface ChatState {
|
||||
permissionRequest: PermissionRequest | null;
|
||||
}
|
||||
|
||||
export function useChat({ sessionId, onError, onSessionNotFound, onSessionUpdated }: UseChatOptions) {
|
||||
export function useChat({ sessionId, onError, onSessionNotFound, onSessionUpdated, onConfigError }: UseChatOptions) {
|
||||
const [state, setState] = useState<ChatState>({
|
||||
messages: [],
|
||||
isConnected: false,
|
||||
@@ -43,9 +46,11 @@ export function useChat({ sessionId, onError, onSessionNotFound, onSessionUpdate
|
||||
const onErrorRef = useRef(onError);
|
||||
const onSessionNotFoundRef = useRef(onSessionNotFound);
|
||||
const onSessionUpdatedRef = useRef(onSessionUpdated);
|
||||
const onConfigErrorRef = useRef(onConfigError);
|
||||
onErrorRef.current = onError;
|
||||
onSessionNotFoundRef.current = onSessionNotFound;
|
||||
onSessionUpdatedRef.current = onSessionUpdated;
|
||||
onConfigErrorRef.current = onConfigError;
|
||||
|
||||
// 加载历史消息
|
||||
const loadMessages = useCallback(async () => {
|
||||
@@ -137,7 +142,12 @@ export function useChat({ sessionId, onError, onSessionNotFound, onSessionUpdate
|
||||
break;
|
||||
|
||||
case 'error':
|
||||
onErrorRef.current?.(new Error(message.payload?.message || 'Unknown error'));
|
||||
// 检查是否为配置错误
|
||||
if (message.payload?.type === 'config_error') {
|
||||
onConfigErrorRef.current?.(message.payload as ConfigErrorPayload);
|
||||
} else {
|
||||
onErrorRef.current?.(new Error(message.payload?.message || 'Unknown error'));
|
||||
}
|
||||
setState((prev) => ({ ...prev, isLoading: false, streamingContent: '' }));
|
||||
break;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user