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 导入导致黑屏
This commit is contained in:
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* Metona IR — 统一导出
|
||||
*
|
||||
* 所有 Metona IR 类型的单入口导出。
|
||||
* 项目内部只从此文件导入类型,确保类型一致性。
|
||||
*/
|
||||
|
||||
// ===== 请求类型 =====
|
||||
export type {
|
||||
MetonaRequest,
|
||||
MetonaRequestMeta,
|
||||
MetonaSystemPrompt,
|
||||
MetonaGenerationParams,
|
||||
MetonaConstraints,
|
||||
MetonaMessage,
|
||||
MetonaImageContent,
|
||||
MetonaToolDef,
|
||||
MetonaToolParams,
|
||||
MetonaParamField,
|
||||
MetonaToolCall,
|
||||
MetonaToolResult,
|
||||
} from './metona-request';
|
||||
|
||||
export { MetonaToolCategory, MetonaRiskLevel } from './metona-request';
|
||||
|
||||
// ===== 响应类型 =====
|
||||
export type {
|
||||
MetonaResponse,
|
||||
MetonaResponseMeta,
|
||||
MetonaTokenUsage,
|
||||
MetonaStreamEvent,
|
||||
MetonaThinking,
|
||||
MetonaError,
|
||||
} from './metona-response';
|
||||
|
||||
export {
|
||||
MetonaFinishReason,
|
||||
MetonaStreamEventType,
|
||||
MetonaErrorCode,
|
||||
} from './metona-response';
|
||||
|
||||
// ===== 上下文与记忆 =====
|
||||
export type { MetonaContext, MetonaMemoryItem } from './metona-context';
|
||||
|
||||
// ===== 适配器接口 =====
|
||||
export type { IMetonaProviderAdapter, AdapterConfig } from './metona-adapter';
|
||||
@@ -0,0 +1,72 @@
|
||||
/**
|
||||
* Metona IR — Provider Adapter 接口定义
|
||||
*
|
||||
* 所有 LLM Provider 适配器必须实现此接口。
|
||||
*
|
||||
* @see docs/MetonaAI-Desktop 内部API请求与响应标准.html
|
||||
*/
|
||||
|
||||
import type { MetonaRequest, MetonaResponse, MetonaStreamEvent } from './index';
|
||||
|
||||
/**
|
||||
* Provider 适配器配置
|
||||
*/
|
||||
export interface AdapterConfig {
|
||||
/** Provider 标识(如 'deepseek'、'agnes'、'ollama') */
|
||||
provider: string;
|
||||
/** API 基础 URL */
|
||||
baseURL: string;
|
||||
/** API 密钥(Ollama 等本地 Provider 可为空) */
|
||||
apiKey?: string;
|
||||
/** 默认模型名 */
|
||||
defaultModel: string;
|
||||
/** 请求超时(ms) */
|
||||
timeoutMs?: number;
|
||||
/** 自定义请求头 */
|
||||
headers?: Record<string, string>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provider 适配器统一接口
|
||||
*
|
||||
* 职责:
|
||||
* 1. 将 MetonaRequest 转换为目标 Provider 原生请求格式
|
||||
* 2. 调用外部 API
|
||||
* 3. 将原生响应转换为 MetonaResponse / MetonaStreamEvent
|
||||
*
|
||||
* 铁律:外部 API 原始类型不得穿透到此接口之外
|
||||
*/
|
||||
export interface IMetonaProviderAdapter {
|
||||
/** Provider 标识 */
|
||||
readonly provider: string;
|
||||
|
||||
/** 支持的模型列表 */
|
||||
readonly supportedModels: string[];
|
||||
|
||||
/** 是否支持 Tool Calling */
|
||||
readonly supportsToolCalling: boolean;
|
||||
|
||||
/** 是否支持 Thinking / Reasoning 模式 */
|
||||
readonly supportsThinking: boolean;
|
||||
|
||||
/**
|
||||
* 发送非流式请求
|
||||
*/
|
||||
chat(request: MetonaRequest): Promise<MetonaResponse>;
|
||||
|
||||
/**
|
||||
* 发送流式请求
|
||||
* @returns AsyncIterable 逐事件推送 MetonaStreamEvent
|
||||
*/
|
||||
chatStream(request: MetonaRequest): AsyncIterable<MetonaStreamEvent>;
|
||||
|
||||
/**
|
||||
* 检查 Provider 可用性
|
||||
*/
|
||||
healthCheck(): Promise<boolean>;
|
||||
|
||||
/**
|
||||
* 列出可用模型(可选)
|
||||
*/
|
||||
listModels?(): Promise<string[]>;
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* Metona IR — 上下文与记忆类型定义
|
||||
*
|
||||
* @see docs/MetonaAI-Desktop 内部API请求与响应标准.html
|
||||
*/
|
||||
|
||||
import type { MetonaMessage, MetonaSystemPrompt, MetonaToolDef } from './metona-request';
|
||||
|
||||
// ===== 上下文标准 =====
|
||||
|
||||
export interface MetonaContext {
|
||||
/** 上下文唯一标识 */
|
||||
id: string;
|
||||
/** 关联的会话 */
|
||||
sessionId: string;
|
||||
/** System Prompt 分区 */
|
||||
systemPrompt: MetonaSystemPrompt;
|
||||
/** 会话历史(最近 N 轮) */
|
||||
history: MetonaMessage[];
|
||||
/** 检索到的相关记忆 */
|
||||
relevantMemories: MetonaMemoryItem[];
|
||||
/** 当前任务信息 */
|
||||
currentTask: {
|
||||
userInput: string;
|
||||
iteration: number;
|
||||
taskGoal?: string;
|
||||
};
|
||||
/** 可用工具列表 */
|
||||
availableTools: MetonaToolDef[];
|
||||
/** 预估 Token 数 */
|
||||
estimatedTokens: number;
|
||||
/** 上下文使用率(estimatedTokens / contextWindow) */
|
||||
usageRatio: number;
|
||||
/** 是否需要压缩 */
|
||||
needsCompression: boolean;
|
||||
}
|
||||
|
||||
// ===== 记忆格式 =====
|
||||
|
||||
export interface MetonaMemoryItem {
|
||||
id: string;
|
||||
type: 'episodic' | 'semantic' | 'working';
|
||||
|
||||
/** 可被 LLM 阅读的记忆内容 */
|
||||
content: string;
|
||||
/** 精简摘要(上下文紧张时使用) */
|
||||
summary?: string;
|
||||
|
||||
/** 来源 */
|
||||
source: 'user_input' | 'tool_result' | 'agent_thought' | 'imported';
|
||||
|
||||
/** 重要程度 0-1 */
|
||||
importance: number;
|
||||
|
||||
/** 检索相关性分数(仅在检索结果中出现) */
|
||||
relevanceScore?: number;
|
||||
|
||||
sessionId?: string;
|
||||
createdAt: number;
|
||||
expiresAt?: number;
|
||||
}
|
||||
@@ -0,0 +1,195 @@
|
||||
/**
|
||||
* Metona IR — 请求标准类型定义
|
||||
*
|
||||
* 本文件是项目内所有 AI 交互请求的统一类型定义。
|
||||
* 无论底层对接 DeepSeek、Ollama、Agnes 还是其他 LLM,
|
||||
* Agent Loop、UI、记忆系统均读写此标准格式。
|
||||
*
|
||||
* @see docs/MetonaAI-Desktop 内部API请求与响应标准.html
|
||||
*/
|
||||
|
||||
// ===== 请求元信息 =====
|
||||
|
||||
export interface MetonaRequestMeta {
|
||||
/** 会话 ID */
|
||||
sessionId: string;
|
||||
/** 当前 ReAct 迭代轮次(从 1 开始) */
|
||||
iteration: number;
|
||||
/** 本次请求的唯一 ID */
|
||||
requestId: string;
|
||||
/** Unix 毫秒时间戳 */
|
||||
timestamp: number;
|
||||
/** Agent 引擎版本 */
|
||||
agentVersion: string;
|
||||
}
|
||||
|
||||
// ===== System Prompt =====
|
||||
|
||||
export interface MetonaSystemPrompt {
|
||||
/** 角色定义(静态区,利用 LLM 缓存) */
|
||||
roleDefinition: string;
|
||||
/** 输出格式约束 */
|
||||
outputConstraints: string;
|
||||
/** 安全准则 */
|
||||
safetyGuidelines: string;
|
||||
/** 动态注入的尾部提醒 */
|
||||
dynamicReminders?: string;
|
||||
}
|
||||
|
||||
// ===== 生成参数 =====
|
||||
|
||||
export interface MetonaGenerationParams {
|
||||
/** 最大生成 token 数 */
|
||||
maxTokens?: number;
|
||||
/** 温度(默认 0.0,Agent 需要确定性) */
|
||||
temperature?: number;
|
||||
/** 核采样 */
|
||||
topP?: number;
|
||||
/** 是否流式输出 */
|
||||
stream?: boolean;
|
||||
/** 停止序列 */
|
||||
stopSequences?: string[];
|
||||
/** 是否启用思考模式 */
|
||||
thinkingEnabled?: boolean;
|
||||
/** 思考强度(替代 thinkingBudget,各 Provider 映射见 Adapter 规范) */
|
||||
thinkingEffort?: 'low' | 'medium' | 'high' | 'max';
|
||||
}
|
||||
|
||||
// ===== 安全约束 =====
|
||||
|
||||
export interface MetonaConstraints {
|
||||
/** 本迭代允许使用的工具白名单 */
|
||||
allowedTools?: string[];
|
||||
/** 单轮最大工具调用数 */
|
||||
maxToolCalls?: number;
|
||||
/** 本请求整体超时 */
|
||||
timeoutMs?: number;
|
||||
}
|
||||
|
||||
// ===== 消息格式 =====
|
||||
|
||||
export interface MetonaMessage {
|
||||
role: 'system' | 'user' | 'assistant' | 'tool';
|
||||
|
||||
/** 文本内容(纯文本或 Markdown) */
|
||||
content: string;
|
||||
|
||||
/** (仅 assistant)思考/推理内容 */
|
||||
reasoningContent?: string;
|
||||
|
||||
/** (仅 assistant)工具调用请求 */
|
||||
toolCalls?: MetonaToolCall[];
|
||||
|
||||
/** (仅 tool)工具执行结果 */
|
||||
toolResult?: MetonaToolResult;
|
||||
|
||||
/** 时间戳 */
|
||||
timestamp: number;
|
||||
|
||||
/** 所属迭代轮次 */
|
||||
iteration?: number;
|
||||
|
||||
/** 图片内容(可选,用于多模态) */
|
||||
images?: MetonaImageContent[];
|
||||
}
|
||||
|
||||
export interface MetonaImageContent {
|
||||
/** 图片公网 URL 或 base64 data URI */
|
||||
url: string;
|
||||
detail?: 'low' | 'high' | 'auto';
|
||||
}
|
||||
|
||||
// ===== 工具定义 =====
|
||||
|
||||
export interface MetonaToolDef {
|
||||
/** 工具唯一名称 */
|
||||
name: string;
|
||||
/** 功能描述(供 LLM 阅读) */
|
||||
description: string;
|
||||
/** 参数 JSON Schema */
|
||||
parameters: MetonaToolParams;
|
||||
/** 分类 */
|
||||
category: MetonaToolCategory;
|
||||
/** 风险等级 */
|
||||
riskLevel: MetonaRiskLevel;
|
||||
/** 是否需要用户授权 */
|
||||
requiresPermission: boolean;
|
||||
/** 超时时间 */
|
||||
timeoutMs: number;
|
||||
}
|
||||
|
||||
export interface MetonaToolParams {
|
||||
type: 'object';
|
||||
properties: Record<string, MetonaParamField>;
|
||||
required?: string[];
|
||||
}
|
||||
|
||||
export interface MetonaParamField {
|
||||
type: 'string' | 'number' | 'boolean' | 'object' | 'array';
|
||||
description: string;
|
||||
enum?: string[];
|
||||
items?: MetonaParamField;
|
||||
}
|
||||
|
||||
export enum MetonaToolCategory {
|
||||
FILESYSTEM = 'filesystem',
|
||||
SEARCH = 'search',
|
||||
CALCULATION = 'calculation',
|
||||
CODE_EXECUTION = 'code_execution',
|
||||
NETWORK = 'network',
|
||||
DATABASE = 'database',
|
||||
MCP = 'mcp',
|
||||
CUSTOM = 'custom',
|
||||
}
|
||||
|
||||
export enum MetonaRiskLevel {
|
||||
SAFE = 'safe',
|
||||
LOW = 'low',
|
||||
MEDIUM = 'medium',
|
||||
HIGH = 'high',
|
||||
CRITICAL = 'critical',
|
||||
}
|
||||
|
||||
// ===== 工具调用 =====
|
||||
|
||||
export interface MetonaToolCall {
|
||||
/** 工具调用唯一 ID */
|
||||
id: string;
|
||||
/** 工具名称 */
|
||||
name: string;
|
||||
/** 调用参数 */
|
||||
args: Record<string, unknown>;
|
||||
/** 所属 ReAct 迭代 */
|
||||
iteration: number;
|
||||
timestamp: number;
|
||||
}
|
||||
|
||||
export interface MetonaToolResult {
|
||||
toolCallId: string;
|
||||
toolName: string;
|
||||
/** 工具原始返回值 */
|
||||
result: unknown;
|
||||
/** 人工可读摘要(用于 LLM 上下文注入) */
|
||||
summary?: string;
|
||||
success: boolean;
|
||||
error?: string;
|
||||
durationMs: number;
|
||||
timestamp: number;
|
||||
}
|
||||
|
||||
// ===== 完整请求 =====
|
||||
|
||||
export interface MetonaRequest {
|
||||
/** 请求元信息 */
|
||||
meta: MetonaRequestMeta;
|
||||
/** System Prompt(行为宪法) */
|
||||
systemPrompt: MetonaSystemPrompt;
|
||||
/** 消息列表(含历史 + 当前用户输入 + 工具结果) */
|
||||
messages: MetonaMessage[];
|
||||
/** 本轮可用的工具定义列表 */
|
||||
tools?: MetonaToolDef[];
|
||||
/** 生成参数 */
|
||||
params: MetonaGenerationParams;
|
||||
/** 安全约束 */
|
||||
constraints?: MetonaConstraints;
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
/**
|
||||
* Metona IR — 响应标准类型定义
|
||||
*
|
||||
* @see docs/MetonaAI-Desktop 内部API请求与响应标准.html
|
||||
*/
|
||||
|
||||
import type { MetonaToolCall, MetonaToolResult } from './metona-request';
|
||||
|
||||
// ===== 响应元信息 =====
|
||||
|
||||
export interface MetonaResponseMeta {
|
||||
/** 对应的请求 ID */
|
||||
requestId: string;
|
||||
/** Provider 标识(如 'deepseek') */
|
||||
provider: string;
|
||||
/** 实际使用的模型名称 */
|
||||
model: string;
|
||||
/** 端到端延迟 */
|
||||
latencyMs: number;
|
||||
/** 响应时间戳 */
|
||||
timestamp: number;
|
||||
|
||||
/** Provider 原生性能统计(可选,主要用于 Ollama) */
|
||||
perfStats?: {
|
||||
/** 模型加载耗时 */
|
||||
loadDurationMs?: number;
|
||||
/** Prompt 评估耗时 */
|
||||
promptEvalDurationMs?: number;
|
||||
/** 生成耗时 */
|
||||
evalDurationMs?: number;
|
||||
/** 生成速率 */
|
||||
tokensPerSecond?: number;
|
||||
};
|
||||
}
|
||||
|
||||
// ===== Token 使用统计 =====
|
||||
|
||||
export interface MetonaTokenUsage {
|
||||
inputTokens: number;
|
||||
outputTokens: number;
|
||||
totalTokens: number;
|
||||
/** Thinking 模式专用 */
|
||||
reasoningTokens?: number;
|
||||
cacheHitTokens?: number;
|
||||
cacheMissTokens?: number;
|
||||
}
|
||||
|
||||
// ===== 停止原因 =====
|
||||
|
||||
export enum MetonaFinishReason {
|
||||
STOP = 'stop',
|
||||
LENGTH = 'length',
|
||||
TOOL_CALLS = 'tool_calls',
|
||||
CONTENT_FILTER = 'content_filter',
|
||||
ERROR = 'error',
|
||||
}
|
||||
|
||||
// ===== 完整响应 =====
|
||||
|
||||
export interface MetonaResponse {
|
||||
/** 响应元信息 */
|
||||
meta: MetonaResponseMeta;
|
||||
/** 模型输出(完整文本) */
|
||||
content: string;
|
||||
/** 思考/推理内容(Thinking 模式) */
|
||||
reasoningContent?: string;
|
||||
/** 结构化输出(如果模型原生支持 JSON Schema) */
|
||||
structuredOutput?: unknown;
|
||||
/** 工具调用请求列表 */
|
||||
toolCalls?: MetonaToolCall[];
|
||||
/** Token 使用统计 */
|
||||
usage: MetonaTokenUsage;
|
||||
/** 停止原因 */
|
||||
finishReason: MetonaFinishReason;
|
||||
/** 错误信息(如果出错) */
|
||||
error?: MetonaError;
|
||||
}
|
||||
|
||||
// ===== 流式事件 =====
|
||||
|
||||
export enum MetonaStreamEventType {
|
||||
TEXT_DELTA = 'text_delta',
|
||||
REASONING_DELTA = 'reasoning_delta',
|
||||
TOOL_CALL_DELTA = 'tool_call_delta',
|
||||
TOOL_CALL_COMPLETE = 'tool_call_complete',
|
||||
THINKING_START = 'thinking_start',
|
||||
THINKING_END = 'thinking_end',
|
||||
ERROR = 'error',
|
||||
DONE = 'done',
|
||||
USAGE = 'usage',
|
||||
}
|
||||
|
||||
export interface MetonaStreamEvent {
|
||||
type: MetonaStreamEventType;
|
||||
requestId: string;
|
||||
sessionId: string;
|
||||
iteration: number;
|
||||
/** 序列号 */
|
||||
seq: number;
|
||||
timestamp: number;
|
||||
|
||||
/** 根据 type 使用不同字段 */
|
||||
/** TEXT_DELTA / REASONING_DELTA */
|
||||
delta?: string;
|
||||
|
||||
/** TOOL_CALL_DELTA */
|
||||
toolCallDelta?: {
|
||||
/** 工具调用索引(同一轮可能有多个) */
|
||||
index: number;
|
||||
/** 工具名称片段(首个事件携带) */
|
||||
name?: string;
|
||||
/** 参数 JSON 增量片段 */
|
||||
argsDelta?: string;
|
||||
};
|
||||
|
||||
/** TOOL_CALL_COMPLETE(拼接完成后的完整调用) */
|
||||
toolCall?: MetonaToolCall;
|
||||
|
||||
/** USAGE */
|
||||
usage?: MetonaTokenUsage;
|
||||
|
||||
/** ERROR */
|
||||
error?: MetonaError;
|
||||
}
|
||||
|
||||
// ===== 思考内容 =====
|
||||
|
||||
export interface MetonaThinking {
|
||||
/** 思考内容文本 */
|
||||
content: string;
|
||||
/** 思考状态 */
|
||||
status: 'thinking' | 'complete';
|
||||
/** 思考耗时 (ms) */
|
||||
durationMs: number;
|
||||
/** 思考消耗的 token 数 */
|
||||
tokensUsed: number;
|
||||
}
|
||||
|
||||
// ===== 错误格式 =====
|
||||
|
||||
export interface MetonaError {
|
||||
/** 错误码 */
|
||||
code: MetonaErrorCode;
|
||||
/** 人类可读的错误描述 */
|
||||
message: string;
|
||||
/** 出错的 Provider */
|
||||
provider?: string;
|
||||
/** Provider 原始错误码 */
|
||||
providerCode?: string;
|
||||
/** 是否可重试 */
|
||||
retryable: boolean;
|
||||
/** 建议重试等待时间 */
|
||||
retryAfterMs?: number;
|
||||
}
|
||||
|
||||
export enum MetonaErrorCode {
|
||||
// 网络层
|
||||
NETWORK_TIMEOUT = 'network_timeout',
|
||||
NETWORK_ERROR = 'network_error',
|
||||
|
||||
// 认证层
|
||||
AUTH_INVALID = 'auth_invalid',
|
||||
AUTH_EXPIRED = 'auth_expired',
|
||||
|
||||
// 频率限制
|
||||
RATE_LIMITED = 'rate_limited',
|
||||
QUOTA_EXCEEDED = 'quota_exceeded',
|
||||
|
||||
// 模型层
|
||||
MODEL_OVERLOADED = 'model_overloaded',
|
||||
MODEL_NOT_FOUND = 'model_not_found',
|
||||
CONTEXT_LENGTH_EXCEEDED = 'context_length_exceeded',
|
||||
OUTPUT_LENGTH_EXCEEDED = 'output_length_exceeded',
|
||||
|
||||
// 内容层
|
||||
CONTENT_FILTERED = 'content_filtered',
|
||||
|
||||
// 解析层
|
||||
PARSE_ERROR = 'parse_error',
|
||||
INVALID_RESPONSE = 'invalid_response',
|
||||
|
||||
// Agent 层
|
||||
MAX_ITERATIONS = 'max_iterations',
|
||||
USER_ABORTED = 'user_aborted',
|
||||
TIMEOUT = 'timeout',
|
||||
UNKNOWN = 'unknown',
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* Metona IR — 工具相关类型定义
|
||||
*
|
||||
* 独立于 metona-request.ts 中的工具定义,用于 Tool Registry 内部。
|
||||
*
|
||||
* @see docs/MetonaAI-Desktop 架构与交互设计.html
|
||||
*/
|
||||
|
||||
import type { MetonaToolDef, MetonaToolCall, MetonaToolResult } from './metona-request';
|
||||
|
||||
/**
|
||||
* 工具执行上下文(传递给工具的 execute 方法)
|
||||
*/
|
||||
export interface ToolExecutionContext {
|
||||
/** 当前会话 ID */
|
||||
sessionId: string;
|
||||
/** 当前工作空间根路径 */
|
||||
workspacePath: string;
|
||||
/** 当前迭代轮次 */
|
||||
iteration: number;
|
||||
/** 请求 ID */
|
||||
requestId: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 工具基类接口
|
||||
* 所有内置工具和 MCP 工具都实现此接口
|
||||
*/
|
||||
export interface IMetonaTool {
|
||||
/** 工具定义(供 LLM 阅读) */
|
||||
readonly definition: MetonaToolDef;
|
||||
|
||||
/**
|
||||
* 执行工具
|
||||
* @param args 工具参数
|
||||
* @param context 执行上下文
|
||||
* @returns 工具执行结果
|
||||
*/
|
||||
execute(args: Record<string, unknown>, context: ToolExecutionContext): Promise<unknown>;
|
||||
}
|
||||
|
||||
/**
|
||||
* 工具注册表中存储的工具记录
|
||||
*/
|
||||
export interface ToolRegistryEntry {
|
||||
tool: IMetonaTool;
|
||||
/** 来源:'builtin' | 'mcp' */
|
||||
source: 'builtin' | 'mcp';
|
||||
/** MCP Server 名称(仅 mcp 来源) */
|
||||
serverName?: string;
|
||||
/** 是否已启用 */
|
||||
enabled: boolean;
|
||||
}
|
||||
Reference in New Issue
Block a user