v0.11.11: 彻底移除技能系统,工具 44→42,SQLite 7→6 张表

- 删除 src/renderer/services/skill-manager.ts (480行)
- sqlite.ts: 删除 skills 表/索引/迁移/SkillRow接口/CRUD
- ipc.ts: 删除 6 个 skills IPC handler
- preload.ts/types.d.ts: 删除 skills bridge 方法/类型
- agent-engine.ts: 删除技能匹配上下文注入/自动提取
- tool-registry.ts: 删除 skill_list/skill_view 工具定义/执行
- log-service.ts/sub-agent.ts/workspace-panel.ts: 清理引用
- index.html: 帮助面板/工具卡片更新,44→42
- README/release-notes/DEVELOPMENT/AGENT: 文档全量同步
This commit is contained in:
thzxx
2026-06-22 18:13:01 +08:00
parent 6099c2ad21
commit 20cbfbd169
19 changed files with 41 additions and 738 deletions
-90
View File
@@ -205,22 +205,6 @@ export async function initDatabase(): Promise<SQL.Database> {
);
CREATE INDEX IF NOT EXISTS idx_traces_session ON traces(session_id, created_at);
-- v4.2 技能表(自动从成功工具调用链提取)
CREATE TABLE IF NOT EXISTS skills (
id TEXT PRIMARY KEY,
name TEXT NOT NULL,
description TEXT NOT NULL,
summary TEXT DEFAULT '',
trigger_keywords TEXT,
tool_chain TEXT NOT NULL,
success_count INTEGER DEFAULT 0,
fail_count INTEGER DEFAULT 0,
avg_duration_ms INTEGER DEFAULT 0,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL,
last_used_at INTEGER
);
CREATE INDEX IF NOT EXISTS idx_skills_updated ON skills(updated_at DESC);
`);
// 兼容迁移:为已有 messages 表补充 attachments 列(文件/视频等附件 JSON)
@@ -228,8 +212,6 @@ export async function initDatabase(): Promise<SQL.Database> {
// 兼容迁移:为已有 messages 表补充 prompt_eval_count 列
// 兼容迁移:为已有 skills 表补充 summary 列
try { db.run("ALTER TABLE skills ADD COLUMN summary TEXT DEFAULT ''"); } catch { /* 列已存在,忽略 */ }
// 尝试创建 FTS5 全文搜索(可选,sql.js 默认 WASM 可能不包含 FTS5
try {
@@ -314,22 +296,6 @@ export interface ToolCallRow {
created_at: number;
}
// v4.2
export interface SkillRow {
id: string;
name: string;
description: string;
summary: string;
trigger_keywords: string | null;
tool_chain: string;
success_count: number;
fail_count: number;
avg_duration_ms: number;
created_at: number;
updated_at: number;
last_used_at: number | null;
}
export interface TraceRow {
id: string;
session_id: string;
@@ -527,62 +493,6 @@ export function getTracesBySession(sessionId: string): TraceRow[] {
return queryAll(getDb(), 'SELECT * FROM traces WHERE session_id = ? ORDER BY step_index ASC', [sessionId]) as unknown as TraceRow[];
}
// ─── Skills CRUD (v4.2) ───
export function saveSkill(skill: SkillRow): string {
runExec(getDb(), `INSERT OR REPLACE INTO skills (id, name, description, summary, trigger_keywords, tool_chain, success_count, fail_count, avg_duration_ms, created_at, updated_at, last_used_at)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
[skill.id, skill.name, skill.description, skill.summary || '', skill.trigger_keywords, skill.tool_chain,
skill.success_count, skill.fail_count, skill.avg_duration_ms,
skill.created_at, skill.updated_at, skill.last_used_at]
);
persist();
return skill.id;
}
export function getAllSkills(): SkillRow[] {
return queryAll(getDb(), 'SELECT * FROM skills ORDER BY success_count DESC, updated_at DESC') as unknown as SkillRow[];
}
export function deleteSkill(id: string): void {
runExec(getDb(), 'DELETE FROM skills WHERE id = ?', [id]);
persist();
}
export function clearAllSkills(): void {
getDb().run('DELETE FROM skills');
persist();
}
export function searchSkills(keywords: string, limit = 5): SkillRow[] {
const likeQ = `%${keywords.replace(/[^\w\u4e00-\u9fff]/g, '%')}%`;
return queryAll(getDb(), `
SELECT * FROM skills
WHERE trigger_keywords LIKE ? OR name LIKE ? OR description LIKE ?
ORDER BY success_count DESC, updated_at DESC
LIMIT ?
`, [likeQ, likeQ, likeQ, limit]) as unknown as SkillRow[];
}
export function incrementSkillUsage(id: string, success: boolean, durationMs: number): void {
const d = getDb();
const skill = queryOne(d, 'SELECT success_count, fail_count, avg_duration_ms FROM skills WHERE id = ?', [id]) as any;
if (!skill) return;
const newSuccess = success ? skill.success_count + 1 : skill.success_count;
const newFail = success ? skill.fail_count : skill.fail_count + 1;
const totalUses = newSuccess + newFail;
// 指数移动平均
const alpha = 0.3;
const newAvg = Math.round(alpha * durationMs + (1 - alpha) * (skill.avg_duration_ms || durationMs));
runExec(d, `UPDATE skills SET success_count = ?, fail_count = ?, avg_duration_ms = ?, updated_at = ?, last_used_at = ? WHERE id = ?`,
[newSuccess, newFail, newAvg, Date.now(), Date.now(), id]
);
persist();
}
// ─── Token 全局统计 ───
export interface SessionTokenStat {
-27
View File
@@ -15,7 +15,6 @@ import {
saveSetting, getSetting,
saveToolCall, getToolCallsBySession,
saveTrace, getTracesBySession,
saveSkill, getAllSkills, deleteSkill, clearAllSkills, searchSkills, incrementSkillUsage,
exportAllSessions, importSessions,
getAllSessionsTokenStats
} from './db/sqlite.js';
@@ -433,32 +432,6 @@ export async function setupIPC(): Promise<void> {
catch (err) { sendLog('error', '导入失败', (err as Error).message); return { imported: 0, skipped: 0 }; }
});
// ── Skills (v4.2) ──
ipcMain.handle('db:saveSkill', (_, skill) => {
try { return { success: true, id: saveSkill(skill) }; }
catch (err) { return { success: false, error: (err as Error).message }; }
});
ipcMain.handle('db:getAllSkills', () => {
try { return getAllSkills(); }
catch { return []; }
});
ipcMain.handle('db:deleteSkill', (_, id) => {
try { deleteSkill(id); return { success: true }; }
catch (err) { return { success: false, error: (err as Error).message }; }
});
ipcMain.handle('db:clearAllSkills', () => {
try { clearAllSkills(); return { success: true }; }
catch (err) { return { success: false, error: (err as Error).message }; }
});
ipcMain.handle('db:searchSkills', (_, query: string, limit?: number) => {
try { return searchSkills(query, limit ?? 5); }
catch { return []; }
});
ipcMain.handle('db:incrementSkillUsage', (_, id: string, success: boolean, durationMs: number) => {
try { incrementSkillUsage(id, success, durationMs); return { success: true }; }
catch (err) { return { success: false, error: (err as Error).message }; }
});
// ── Token 全局统计 ──
ipcMain.handle('db:getAllTokenStats', () => {
try { return getAllSessionsTokenStats(); }
+1 -1
View File
@@ -101,7 +101,7 @@ export function createMenu(): void {
dialog.showMessageBox(mainWindow!, {
type: 'info',
title: '关于 Metona Ollama',
message: 'Metona Ollama Desktop v0.11.10',
message: 'Metona Ollama Desktop v0.11.11',
detail: 'TypeScript + Electron Ollama AI 聊天客户端\n\nhttps://gitee.com/thzxx/metona-ollama',
icon: getIconPath()
});
+1 -7
View File
@@ -77,13 +77,7 @@ contextBridge.exposeInMainWorld('metonaDesktop', {
getTraces: (sessionId: string) => ipcRenderer.invoke('db:getTraces', sessionId),
exportSessions: () => ipcRenderer.invoke('db:exportSessions'),
importSessions: (data: unknown) => ipcRenderer.invoke('db:importSessions', data),
// v4.2 Skills
saveSkill: (skill: unknown) => ipcRenderer.invoke('db:saveSkill', skill),
getAllSkills: () => ipcRenderer.invoke('db:getAllSkills'),
deleteSkill: (id: string) => ipcRenderer.invoke('db:deleteSkill', id),
clearAllSkills: () => ipcRenderer.invoke('db:clearAllSkills'),
searchSkills: (query: string, limit?: number) => ipcRenderer.invoke('db:searchSkills', query, limit),
incrementSkillUsage: (id: string, success: boolean, durationMs: number) => ipcRenderer.invoke('db:incrementSkillUsage', id, success, durationMs),
getAllTokenStats: () => ipcRenderer.invoke('db:getAllTokenStats'),
},
workspace: {