Files
metona-ai-desktop/electron/harness/adapters/base-adapter.ts
T
thzxx 1d185db6b3 feat: MetonaAI Desktop 初始项目
- 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 导入导致黑屏
2026-06-27 21:33:27 +08:00

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,
};
}
}