- Electron + React + TypeScript 架构 - 三栏布局: Sidebar | ChatPanel | DetailPanel - 9 个内置工具 (文件系统/网络/记忆/命令) - SQLite 持久化 (better-sqlite3) - MUI 暗色/亮色主题系统 - Agent Loop ReAct 状态机引擎 - DeepSeek / Agnes AI / Ollama Provider 适配器 - MCP 协议集成 - 系统托盘 + 全局快捷键 - Tailwind CSS v4 + Tailwind Merge - 修复: Sidebar 缺失 TextField 导入导致黑屏
89 lines
2.2 KiB
TypeScript
89 lines
2.2 KiB
TypeScript
/**
|
|
* Provider Adapter — 基类
|
|
*
|
|
* 所有 Provider 适配器共享的基类逻辑:
|
|
* - 请求超时处理
|
|
* - 错误映射到 MetonaError
|
|
* - 流式事件标准化
|
|
*/
|
|
|
|
import type {
|
|
IMetonaProviderAdapter,
|
|
AdapterConfig,
|
|
MetonaRequest,
|
|
MetonaResponse,
|
|
MetonaStreamEvent,
|
|
MetonaError,
|
|
} from '../types';
|
|
import { MetonaErrorCode } from '../types';
|
|
|
|
export abstract class BaseAdapter implements IMetonaProviderAdapter {
|
|
abstract readonly provider: string;
|
|
abstract readonly supportedModels: string[];
|
|
abstract readonly supportsToolCalling: boolean;
|
|
abstract readonly supportsThinking: boolean;
|
|
|
|
constructor(protected config: AdapterConfig) {}
|
|
|
|
abstract chat(request: MetonaRequest): Promise<MetonaResponse>;
|
|
abstract chatStream(request: MetonaRequest): AsyncIterable<MetonaStreamEvent>;
|
|
|
|
async healthCheck(): Promise<boolean> {
|
|
try {
|
|
await this.listModels?.();
|
|
return true;
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
async listModels(): Promise<string[]> {
|
|
return this.supportedModels;
|
|
}
|
|
|
|
/**
|
|
* 将原生错误映射为 MetonaError
|
|
*/
|
|
protected mapError(error: unknown): MetonaError {
|
|
if (error instanceof Error) {
|
|
const msg = error.message.toLowerCase();
|
|
|
|
if (msg.includes('timeout') || msg.includes('ETIMEDOUT')) {
|
|
return {
|
|
code: MetonaErrorCode.NETWORK_TIMEOUT,
|
|
message: error.message,
|
|
provider: this.provider,
|
|
retryable: true,
|
|
retryAfterMs: 3000,
|
|
};
|
|
}
|
|
|
|
if (msg.includes('401') || msg.includes('unauthorized')) {
|
|
return {
|
|
code: MetonaErrorCode.AUTH_INVALID,
|
|
message: 'API key 无效或已过期',
|
|
provider: this.provider,
|
|
retryable: false,
|
|
};
|
|
}
|
|
|
|
if (msg.includes('429') || msg.includes('rate limit')) {
|
|
return {
|
|
code: MetonaErrorCode.RATE_LIMITED,
|
|
message: '请求过于频繁,请稍后重试',
|
|
provider: this.provider,
|
|
retryable: true,
|
|
retryAfterMs: 5000,
|
|
};
|
|
}
|
|
}
|
|
|
|
return {
|
|
code: MetonaErrorCode.UNKNOWN,
|
|
message: error instanceof Error ? error.message : 'Unknown error',
|
|
provider: this.provider,
|
|
retryable: false,
|
|
};
|
|
}
|
|
}
|