refactor: 全栈架构重构与质量硬化——API 错误统一、工具域重组、安全加固、前端组件化

后端核心变更:
  - API 层: 新增 AppError 枚举统一错误类型,替代散落的 (StatusCode, String)
  - Agent 工具域: 重组为 astro/system/ 和 astro/research/ 两级域,新增 ProcessPaperTool 流水线工具
  - 安全: 新增 SSRF 双层防护 (同步字符串级 + 异步 DNS 解析级),覆盖 IPv4/IPv6 私网段
  - 弱密码检测: 扩展弱密码列表并增加最小长度检查
  - LLM 客户端: 新增 ChatCompleter/Embedder trait,支持依赖注入与批量向量化 embed_batch
  - 批量处理: AssetBatch 从串行改为 Semaphore 并发池 (BATCH_CONCURRENCY=3)
  - 分块器: 重写为三阶段结构化管线 (章节解析→短节合并→带标题路径子块)
  - RAG: embedding 计算移出事务,RetrievalResult 新增 headings/section_index 字段
  - 检索: ADS/arXiv 并行检索 (tokio::join!),去重改用 HashSet,本地库回填批量 IN 查询
  - 天体查询: Sesame API 升级到 v4,新增视差误差/自行/视向速度/多波段测光字段
  - 迁移: 14 个增量文件合并为单一 init.sql,支持 sqlx::migrate! 内存库集成测试
  - 测试: circuit_breaker/hooks/task_board/session/memory/streaming_executor 新增修正 15+ 测试

  前端架构重构:
  - 目录重组: features/ → pages/ + components/ + hooks/ 三层分离
  - App.tsx 从 1181 行压缩至 ~174 行 (逻辑抽入 9 个自定义 Hook)
  - Agent 面板拆分为 AgentSessionSidebar/AgentMessageList/AgentInputArea 子组件
  - 新增 GlobalDialog/PaperDetailModal/UncachedPaperModal 通用对话框组件
  - 工具函数抽取: celestial.ts (天体坐标格式), paper.tsx (文献信息渲染)
This commit is contained in:
fmq
2026-06-25 23:45:37 +08:00
parent b11b8ad015
commit 5db4cc5998
131 changed files with 13934 additions and 7887 deletions
+356
View File
@@ -0,0 +1,356 @@
-- AstroResearch 完整数据库初始化迁移
-- 合并自 18 个开发期增量迁移文件,版本: 2026-06-25
--
-- 领域划分:
-- 1. 文献与引用
-- 2. 笔记与高亮
-- 3. 批量同步
-- 4. RAG 切片与天体目标
-- 5. Agent 会话与消息
-- 6. Agent 任务看板
-- 7. Agent 审计日志
-- 8. Agent 团队协作
-- 9. 全文搜索 (FTS5)
-- ============================================================
-- 1. 文献与引用
-- ============================================================
CREATE TABLE IF NOT EXISTS papers (
bibcode TEXT PRIMARY KEY,
title TEXT NOT NULL,
authors TEXT, -- JSON array of author names
year TEXT,
pub TEXT, -- journal / publisher
keywords TEXT, -- JSON array of keywords
abstract TEXT,
doi TEXT,
arxiv_id TEXT,
citation_count INTEGER DEFAULT 0,
reference_count INTEGER DEFAULT 0,
pdf_path TEXT,
html_path TEXT,
markdown_path TEXT,
translation_path TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
doctype TEXT
);
CREATE INDEX IF NOT EXISTS idx_papers_doi ON papers(doi);
CREATE INDEX IF NOT EXISTS idx_papers_arxiv_id ON papers(arxiv_id);
CREATE TABLE IF NOT EXISTS citations_references (
source_bibcode TEXT NOT NULL,
target_bibcode TEXT NOT NULL,
PRIMARY KEY (source_bibcode, target_bibcode)
);
CREATE INDEX IF NOT EXISTS idx_citations_ref_source ON citations_references(source_bibcode);
CREATE INDEX IF NOT EXISTS idx_citations_ref_target ON citations_references(target_bibcode);
-- ============================================================
-- 2. 笔记与高亮
-- ============================================================
CREATE TABLE IF NOT EXISTS notes (
id INTEGER PRIMARY KEY AUTOINCREMENT,
bibcode TEXT NOT NULL,
paragraph_index INTEGER NOT NULL,
note_text TEXT NOT NULL DEFAULT '',
highlight_color TEXT NOT NULL DEFAULT 'yellow',
selected_text TEXT NOT NULL DEFAULT '',
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (bibcode) REFERENCES papers(bibcode) ON DELETE CASCADE
);
CREATE INDEX IF NOT EXISTS idx_notes_bibcode ON notes(bibcode);
-- ============================================================
-- 3. 批量同步
-- ============================================================
CREATE TABLE IF NOT EXISTS sync_queries (
id INTEGER PRIMARY KEY AUTOINCREMENT,
query TEXT NOT NULL,
source TEXT NOT NULL,
limit_count INTEGER NOT NULL,
last_run DATETIME DEFAULT CURRENT_TIMESTAMP,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
UNIQUE(query, source, limit_count)
);
-- ============================================================
-- 4. RAG 切片与天体目标
-- ============================================================
CREATE TABLE IF NOT EXISTS paper_chunks_content (
rowid INTEGER PRIMARY KEY AUTOINCREMENT,
bibcode TEXT,
paragraph_index INTEGER,
content TEXT,
headings TEXT DEFAULT 'Document',
section_index INTEGER DEFAULT 0,
FOREIGN KEY(bibcode) REFERENCES papers(bibcode) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS paper_targets (
id INTEGER PRIMARY KEY AUTOINCREMENT,
bibcode TEXT,
target_name TEXT,
ra TEXT,
dec TEXT,
parallax REAL,
spectral_type TEXT,
v_magnitude REAL,
aliases TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
otype TEXT,
oname TEXT,
pm_ra REAL,
pm_de REAL,
radial_velocity REAL,
parallax_err REAL,
photometry TEXT,
FOREIGN KEY(bibcode) REFERENCES papers(bibcode) ON DELETE CASCADE,
UNIQUE(bibcode, target_name)
);
CREATE INDEX IF NOT EXISTS idx_paper_targets_name ON paper_targets(target_name);
-- ============================================================
-- 5. Agent 会话与消息
-- ============================================================
CREATE TABLE IF NOT EXISTS agent_sessions (
session_id TEXT PRIMARY KEY,
title TEXT NOT NULL DEFAULT '',
model TEXT NOT NULL DEFAULT '',
turn_count INTEGER NOT NULL DEFAULT 0,
last_error TEXT,
summary TEXT,
metadata TEXT,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
deleted_at DATETIME,
rewind_count INTEGER NOT NULL DEFAULT 0,
parent_session_id TEXT REFERENCES agent_sessions(session_id),
branch_metadata TEXT,
mode TEXT NOT NULL DEFAULT 'default'
);
CREATE INDEX IF NOT EXISTS idx_agent_sessions_updated
ON agent_sessions(updated_at) WHERE deleted_at IS NULL;
CREATE TABLE IF NOT EXISTS agent_messages (
id INTEGER PRIMARY KEY AUTOINCREMENT,
session_id TEXT NOT NULL,
turn_index INTEGER NOT NULL DEFAULT 0,
step_index INTEGER NOT NULL DEFAULT 0,
role TEXT NOT NULL CHECK(role IN ('system', 'user', 'assistant', 'tool')),
content TEXT NOT NULL DEFAULT '',
thought TEXT,
tool_calls TEXT,
tool_call_id TEXT,
token_count INTEGER NOT NULL DEFAULT 0,
metadata TEXT,
raw_json TEXT,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
agent_name TEXT NOT NULL DEFAULT 'lead',
active INTEGER NOT NULL DEFAULT 1,
FOREIGN KEY (session_id) REFERENCES agent_sessions(session_id) ON DELETE CASCADE
);
CREATE INDEX IF NOT EXISTS idx_agent_messages_session ON agent_messages(session_id);
CREATE INDEX IF NOT EXISTS idx_agent_messages_turn ON agent_messages(session_id, turn_index);
CREATE INDEX IF NOT EXISTS idx_agent_messages_agent ON agent_messages(session_id, agent_name);
CREATE INDEX IF NOT EXISTS idx_agent_messages_active ON agent_messages(session_id, active);
-- ============================================================
-- 6. Agent 任务看板
-- ============================================================
CREATE TABLE IF NOT EXISTS agent_tasks (
id INTEGER PRIMARY KEY AUTOINCREMENT,
session_id TEXT NOT NULL,
task_id TEXT NOT NULL,
content TEXT NOT NULL DEFAULT '',
status TEXT NOT NULL DEFAULT 'pending'
CHECK(status IN ('pending', 'in_progress', 'completed')),
blocked_by TEXT NOT NULL DEFAULT '[]',
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
owner TEXT NOT NULL DEFAULT '',
FOREIGN KEY (session_id) REFERENCES agent_sessions(session_id) ON DELETE CASCADE
);
CREATE INDEX IF NOT EXISTS idx_agent_tasks_session ON agent_tasks(session_id);
CREATE INDEX IF NOT EXISTS idx_agent_tasks_status ON agent_tasks(session_id, status);
CREATE UNIQUE INDEX IF NOT EXISTS idx_agent_tasks_session_task ON agent_tasks(session_id, task_id);
-- ============================================================
-- 7. Agent 审计日志
-- ============================================================
CREATE TABLE IF NOT EXISTS agent_audit_log (
id INTEGER PRIMARY KEY AUTOINCREMENT,
session_id TEXT NOT NULL,
step INTEGER NOT NULL DEFAULT 0,
tool_name TEXT,
status TEXT NOT NULL CHECK(status IN ('OK', 'FAIL', 'SESSION_STOP')),
elapsed_ms INTEGER NOT NULL DEFAULT 0,
output_preview TEXT,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
agent_name TEXT NOT NULL DEFAULT 'lead',
FOREIGN KEY (session_id) REFERENCES agent_sessions(session_id) ON DELETE CASCADE
);
CREATE INDEX IF NOT EXISTS idx_audit_log_session ON agent_audit_log(session_id);
CREATE INDEX IF NOT EXISTS idx_audit_log_created ON agent_audit_log(created_at);
-- ============================================================
-- 8. Agent 团队协作
-- ============================================================
CREATE TABLE IF NOT EXISTS agent_team_members (
id INTEGER PRIMARY KEY AUTOINCREMENT,
session_id TEXT NOT NULL,
agent_name TEXT NOT NULL,
agent_role TEXT NOT NULL,
status TEXT NOT NULL DEFAULT 'active'
CHECK(status IN ('spawning', 'active', 'idle', 'shutdown')),
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (session_id) REFERENCES agent_sessions(session_id) ON DELETE CASCADE,
UNIQUE(session_id, agent_name)
);
CREATE INDEX IF NOT EXISTS idx_team_members_session ON agent_team_members(session_id);
CREATE INDEX IF NOT EXISTS idx_team_members_status ON agent_team_members(session_id, status);
-- ============================================================
-- 9. 全文搜索 (FTS5)
-- ============================================================
-- 文献全文搜索
CREATE VIRTUAL TABLE IF NOT EXISTS papers_fts USING fts5(
title,
authors,
keywords,
abstract,
pub,
content='papers',
content_rowid='rowid'
);
CREATE TRIGGER IF NOT EXISTS papers_fts_insert AFTER INSERT ON papers
BEGIN
INSERT INTO papers_fts(rowid, title, authors, keywords, abstract, pub)
VALUES (NEW.rowid, NEW.title, NEW.authors, NEW.keywords, NEW.abstract, NEW.pub);
END;
CREATE TRIGGER IF NOT EXISTS papers_fts_update AFTER UPDATE ON papers
BEGIN
UPDATE papers_fts SET
title = NEW.title,
authors = NEW.authors,
keywords = NEW.keywords,
abstract = NEW.abstract,
pub = NEW.pub
WHERE rowid = OLD.rowid;
END;
CREATE TRIGGER IF NOT EXISTS papers_fts_delete AFTER DELETE ON papers
BEGIN
DELETE FROM papers_fts WHERE rowid = OLD.rowid;
END;
-- Agent 会话全文搜索
CREATE VIRTUAL TABLE IF NOT EXISTS agent_sessions_fts USING fts5(
session_id,
title,
summary,
metadata,
content='agent_sessions',
content_rowid='rowid'
);
CREATE TRIGGER IF NOT EXISTS sessions_fts_insert AFTER INSERT ON agent_sessions
BEGIN
INSERT INTO agent_sessions_fts(rowid, session_id, title, summary, metadata)
VALUES (NEW.rowid, NEW.session_id, NEW.title, NEW.summary, NEW.metadata);
END;
CREATE TRIGGER IF NOT EXISTS sessions_fts_update AFTER UPDATE ON agent_sessions
BEGIN
UPDATE agent_sessions_fts SET
session_id = NEW.session_id,
title = NEW.title,
summary = NEW.summary,
metadata = NEW.metadata
WHERE rowid = OLD.rowid;
END;
CREATE TRIGGER IF NOT EXISTS sessions_fts_delete AFTER DELETE ON agent_sessions
BEGIN
DELETE FROM agent_sessions_fts WHERE rowid = OLD.rowid;
END;
-- Agent 消息全文搜索
CREATE VIRTUAL TABLE IF NOT EXISTS agent_messages_fts USING fts5(
session_id,
role,
content,
thought,
tool_calls,
content='agent_messages',
content_rowid='rowid'
);
CREATE TRIGGER IF NOT EXISTS messages_fts_insert AFTER INSERT ON agent_messages
BEGIN
INSERT INTO agent_messages_fts(rowid, session_id, role, content, thought, tool_calls)
VALUES (NEW.rowid, NEW.session_id, NEW.role, NEW.content, NEW.thought, NEW.tool_calls);
END;
CREATE TRIGGER IF NOT EXISTS messages_fts_update AFTER UPDATE ON agent_messages
BEGIN
UPDATE agent_messages_fts SET
session_id = NEW.session_id,
role = NEW.role,
content = NEW.content,
thought = NEW.thought,
tool_calls = NEW.tool_calls
WHERE rowid = OLD.rowid;
END;
CREATE TRIGGER IF NOT EXISTS messages_fts_delete AFTER DELETE ON agent_messages
BEGIN
DELETE FROM agent_messages_fts WHERE rowid = OLD.rowid;
END;
-- 段落切片全文搜索(配合 vec_paper_chunks 向量检索做混合搜索)
CREATE VIRTUAL TABLE IF NOT EXISTS paper_chunks_fts USING fts5(
content,
content='paper_chunks_content',
content_rowid='rowid'
);
CREATE TRIGGER IF NOT EXISTS chunks_fts_insert AFTER INSERT ON paper_chunks_content
BEGIN
INSERT INTO paper_chunks_fts(rowid, content) VALUES (NEW.rowid, NEW.content);
END;
CREATE TRIGGER IF NOT EXISTS chunks_fts_update AFTER UPDATE ON paper_chunks_content
BEGIN
UPDATE paper_chunks_fts SET content = NEW.content WHERE rowid = OLD.rowid;
END;
CREATE TRIGGER IF NOT EXISTS chunks_fts_delete AFTER DELETE ON paper_chunks_content
BEGIN
DELETE FROM paper_chunks_fts WHERE rowid = OLD.rowid;
END;
-- ============================================================
-- 注意: vec_paper_chunks 向量虚拟表由 main.rs 在运行时动态创建,
-- 维度由 EMBEDDING_DIM 环境变量控制 (默认 1536)。
-- ============================================================
-32
View File
@@ -1,32 +0,0 @@
-- migrations/20260608000000_init.sql
CREATE TABLE IF NOT EXISTS papers (
bibcode TEXT PRIMARY KEY,
title TEXT NOT NULL,
authors TEXT, -- JSON array of author names
year TEXT,
pub TEXT, -- journal / publisher
keywords TEXT, -- JSON array of keywords
abstract TEXT,
doi TEXT,
arxiv_id TEXT,
citation_count INTEGER DEFAULT 0,
reference_count INTEGER DEFAULT 0,
pdf_path TEXT,
html_path TEXT,
markdown_path TEXT,
translation_path TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS citations_references (
source_bibcode TEXT NOT NULL,
target_bibcode TEXT NOT NULL,
PRIMARY KEY (source_bibcode, target_bibcode)
);
-- Indexes for performance
CREATE INDEX IF NOT EXISTS idx_papers_doi ON papers(doi);
CREATE INDEX IF NOT EXISTS idx_papers_arxiv_id ON papers(arxiv_id);
CREATE INDEX IF NOT EXISTS idx_citations_ref_source ON citations_references(source_bibcode);
CREATE INDEX IF NOT EXISTS idx_citations_ref_target ON citations_references(target_bibcode);
-15
View File
@@ -1,15 +0,0 @@
-- migrations/20260608000001_notes.sql
-- 笔记/高亮表:每条记录对应一篇文献中某个段落的标注笔记
CREATE TABLE IF NOT EXISTS notes (
id INTEGER PRIMARY KEY AUTOINCREMENT,
bibcode TEXT NOT NULL,
paragraph_index INTEGER NOT NULL, -- 在文章 Markdown 段落中的序号(从 0 开始)
note_text TEXT NOT NULL DEFAULT '',
highlight_color TEXT NOT NULL DEFAULT 'yellow', -- 'yellow' | 'green' | 'blue' | 'pink'
selected_text TEXT NOT NULL DEFAULT '', -- 被高亮选中的原始文本片段
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (bibcode) REFERENCES papers(bibcode) ON DELETE CASCADE
);
CREATE INDEX IF NOT EXISTS idx_notes_bibcode ON notes(bibcode);
@@ -1,3 +0,0 @@
-- migrations/20260608000002_add_doctype.sql
ALTER TABLE papers ADD COLUMN doctype TEXT;
@@ -1,12 +0,0 @@
-- migrations/20260608000003_sync_features.sql
-- 批量同步检索配置表 (支持唯一去重机制)
CREATE TABLE IF NOT EXISTS sync_queries (
id INTEGER PRIMARY KEY AUTOINCREMENT,
query TEXT NOT NULL,
source TEXT NOT NULL,
limit_count INTEGER NOT NULL,
last_run DATETIME DEFAULT CURRENT_TIMESTAMP,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
UNIQUE(query, source, limit_count) -- 去重约束
);
@@ -1,29 +0,0 @@
-- migrations/20260613000000_paper_chunks_metadata.sql
-- RAG 文本切片内容表与天体目标缓存表
-- 存储文献 Markdown 段落切片的元数据与文本内容
-- rowid 与 vec_paper_chunks 虚拟表的 rowid 保持 1:1 对齐
CREATE TABLE IF NOT EXISTS paper_chunks_content (
rowid INTEGER PRIMARY KEY AUTOINCREMENT,
bibcode TEXT,
paragraph_index INTEGER,
content TEXT,
FOREIGN KEY(bibcode) REFERENCES papers(bibcode) ON DELETE CASCADE
);
-- 天体目标信息缓存表,从 SIMBAD/Sesame 解析后本地持久化
CREATE TABLE IF NOT EXISTS paper_targets (
id INTEGER PRIMARY KEY AUTOINCREMENT,
bibcode TEXT,
target_name TEXT, -- 标准化天体名称 (如 GD 358)
ra TEXT, -- 赤道坐标:赤经 (Right Ascension)
dec TEXT, -- 赤道坐标:赤纬 (Declination)
parallax REAL, -- 视差 (mas,毫角秒)
spectral_type TEXT, -- 光谱分类 (如 DA1)
v_magnitude REAL, -- 视星等
aliases TEXT, -- 天体别名 (JSON 数组文本)
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY(bibcode) REFERENCES papers(bibcode) ON DELETE CASCADE,
UNIQUE(bibcode, target_name)
);
CREATE INDEX IF NOT EXISTS idx_paper_targets_name ON paper_targets(target_name);
@@ -1,36 +0,0 @@
-- 科研智能体会话与消息持久化表
-- 支持 ReAct 框架的多轮对话、工具调用与思考链存储
CREATE TABLE IF NOT EXISTS agent_sessions (
session_id TEXT PRIMARY KEY,
title TEXT NOT NULL DEFAULT '',
model TEXT NOT NULL DEFAULT '',
turn_count INTEGER NOT NULL DEFAULT 0,
last_error TEXT,
summary TEXT,
metadata TEXT,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
deleted_at DATETIME
);
CREATE TABLE IF NOT EXISTS agent_messages (
id INTEGER PRIMARY KEY AUTOINCREMENT,
session_id TEXT NOT NULL,
turn_index INTEGER NOT NULL DEFAULT 0,
step_index INTEGER NOT NULL DEFAULT 0,
role TEXT NOT NULL CHECK(role IN ('system', 'user', 'assistant', 'tool')),
content TEXT NOT NULL DEFAULT '',
thought TEXT,
tool_calls TEXT,
tool_call_id TEXT,
token_count INTEGER NOT NULL DEFAULT 0,
metadata TEXT,
raw_json TEXT,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (session_id) REFERENCES agent_sessions(session_id) ON DELETE CASCADE
);
CREATE INDEX IF NOT EXISTS idx_agent_messages_session ON agent_messages(session_id);
CREATE INDEX IF NOT EXISTS idx_agent_messages_turn ON agent_messages(session_id, turn_index);
CREATE INDEX IF NOT EXISTS idx_agent_sessions_updated ON agent_sessions(updated_at) WHERE deleted_at IS NULL;
-31
View File
@@ -1,31 +0,0 @@
-- 智能体任务持久化表
-- 支持 DAG 依赖模式 (blocked_by) 和任务状态生命周期
--
-- Status lifecycle:
-- pending -> in_progress -> completed
-- (可回退: in_progress -> pending)
--
-- blocked_by 存储 JSON 数组格式: ["task_id_1", "task_id_2"]
-- 应用层负责验证 DAG 有效性(无自引用、无循环依赖)
CREATE TABLE IF NOT EXISTS agent_tasks (
id INTEGER PRIMARY KEY AUTOINCREMENT,
session_id TEXT NOT NULL,
task_id TEXT NOT NULL,
content TEXT NOT NULL DEFAULT '',
status TEXT NOT NULL DEFAULT 'pending'
CHECK(status IN ('pending', 'in_progress', 'completed')),
blocked_by TEXT NOT NULL DEFAULT '[]',
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (session_id) REFERENCES agent_sessions(session_id) ON DELETE CASCADE
);
-- 按会话查询任务(最常用)
CREATE INDEX IF NOT EXISTS idx_agent_tasks_session ON agent_tasks(session_id);
-- 按状态过滤(用于恢复/展示)
CREATE INDEX IF NOT EXISTS idx_agent_tasks_status ON agent_tasks(session_id, status);
-- 保证同一会话内 task_id 唯一
CREATE UNIQUE INDEX IF NOT EXISTS idx_agent_tasks_session_task ON agent_tasks(session_id, task_id);
@@ -1,19 +0,0 @@
-- 智能体审计日志表
-- 记录所有工具调用的详细信息:工具名称、执行状态、耗时、输出预览
--
-- status: OK (成功) / FAIL (失败) / SESSION_STOP (会话终止)
CREATE TABLE IF NOT EXISTS agent_audit_log (
id INTEGER PRIMARY KEY AUTOINCREMENT,
session_id TEXT NOT NULL,
step INTEGER NOT NULL DEFAULT 0,
tool_name TEXT,
status TEXT NOT NULL CHECK(status IN ('OK', 'FAIL', 'SESSION_STOP')),
elapsed_ms INTEGER NOT NULL DEFAULT 0,
output_preview TEXT,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (session_id) REFERENCES agent_sessions(session_id) ON DELETE CASCADE
);
CREATE INDEX IF NOT EXISTS idx_audit_log_session ON agent_audit_log(session_id);
CREATE INDEX IF NOT EXISTS idx_audit_log_created ON agent_audit_log(created_at);
@@ -1,36 +0,0 @@
-- 智能体身份隔离与团队协作支持
--
-- 为子代理(delegate_research)和多智能体团队(spawn_teammate
-- 提供 agent 粒度的消息隔离、审计追踪和任务归属。
--
-- 所有 ALTER TABLE 使用 DEFAULT 值,保证向后兼容:
-- 现有数据自动标记为 'lead',旧代码无需修改。
-- 1. agent_messages: 消息归属
ALTER TABLE agent_messages ADD COLUMN agent_name TEXT NOT NULL DEFAULT 'lead';
-- 2. agent_audit_log: 审计归属
ALTER TABLE agent_audit_log ADD COLUMN agent_name TEXT NOT NULL DEFAULT 'lead';
-- 3. agent_tasks: 任务分配目标(支持角色路由)
ALTER TABLE agent_tasks ADD COLUMN owner TEXT NOT NULL DEFAULT '';
-- 4. 新建: 团队成员注册表
CREATE TABLE IF NOT EXISTS agent_team_members (
id INTEGER PRIMARY KEY AUTOINCREMENT,
session_id TEXT NOT NULL,
agent_name TEXT NOT NULL,
agent_role TEXT NOT NULL,
status TEXT NOT NULL DEFAULT 'active'
CHECK(status IN ('spawning', 'active', 'idle', 'shutdown')),
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (session_id) REFERENCES agent_sessions(session_id) ON DELETE CASCADE,
UNIQUE(session_id, agent_name)
);
CREATE INDEX IF NOT EXISTS idx_team_members_session ON agent_team_members(session_id);
CREATE INDEX IF NOT EXISTS idx_team_members_status ON agent_team_members(session_id, status);
-- 重建 agent_messages 索引(包含 agent_name 过滤加速)
CREATE INDEX IF NOT EXISTS idx_agent_messages_agent ON agent_messages(session_id, agent_name);
@@ -1,20 +0,0 @@
-- Migration: Session Rewind Support
--
-- 添加会话回退 (undo) 所需的软删除基础设施。
-- 参考 Hermes-Agent hermes_state.py active=0 模型。
--
-- active 列:
-- 1 = 活跃消息(对 LLM 可见,默认值)
-- 0 = 软删除(rewind 操作移除,LLM 不可见,保留用于审计)
--
-- rewind_count:
-- 单调递增计数器,记录会话被回退的次数
-- 1. agent_messages: 添加 active 列
ALTER TABLE agent_messages ADD COLUMN active INTEGER NOT NULL DEFAULT 1;
-- 2. agent_sessions: 添加 rewind_count
ALTER TABLE agent_sessions ADD COLUMN rewind_count INTEGER NOT NULL DEFAULT 0;
-- 3. 加速 active=1 过滤的索引(覆盖最常用的查询模式)
CREATE INDEX IF NOT EXISTS idx_agent_messages_active ON agent_messages(session_id, active);
@@ -1,13 +0,0 @@
-- Migration: Session Branch Support
--
-- 添加会话分叉所需的基础设施。
-- 参考 Hermes-Agent parent_session_id 模型。
--
-- parent_session_id: 分叉的源会话 IDNULL = 根会话)
-- branched_from: 分叉的消息 ID(在源会话中的分叉点)
-- 1. agent_sessions: 添加 parent_session_id
ALTER TABLE agent_sessions ADD COLUMN parent_session_id TEXT REFERENCES agent_sessions(session_id);
-- 2. agent_sessions: 添加分支元数据 JSON(存储 {branched_from, branch_reason} 等)
ALTER TABLE agent_sessions ADD COLUMN branch_metadata TEXT;
-73
View File
@@ -1,73 +0,0 @@
-- FTS5 跨会话全文搜索
-- 在 agent_sessions 和 agent_messages 上创建虚拟表,支持 BM25 排序搜索。
CREATE VIRTUAL TABLE IF NOT EXISTS agent_sessions_fts USING fts5(
session_id,
title,
summary,
metadata,
content='agent_sessions',
content_rowid='rowid'
);
CREATE VIRTUAL TABLE IF NOT EXISTS agent_messages_fts USING fts5(
session_id,
role,
content,
thought,
tool_calls,
content='agent_messages',
content_rowid='rowid'
);
-- Triggers: sessions
CREATE TRIGGER IF NOT EXISTS sessions_fts_insert AFTER INSERT ON agent_sessions
BEGIN
INSERT INTO agent_sessions_fts(session_id, title, summary, metadata)
VALUES (NEW.session_id, NEW.title, NEW.summary, NEW.metadata);
END;
CREATE TRIGGER IF NOT EXISTS sessions_fts_update AFTER UPDATE ON agent_sessions
BEGIN
UPDATE agent_sessions_fts SET
session_id = NEW.session_id,
title = NEW.title,
summary = NEW.summary,
metadata = NEW.metadata
WHERE rowid = OLD.rowid;
END;
CREATE TRIGGER IF NOT EXISTS sessions_fts_delete AFTER DELETE ON agent_sessions
BEGIN
DELETE FROM agent_sessions_fts WHERE rowid = OLD.rowid;
END;
-- Triggers: messages
CREATE TRIGGER IF NOT EXISTS messages_fts_insert AFTER INSERT ON agent_messages
BEGIN
INSERT INTO agent_messages_fts(session_id, role, content, thought, tool_calls)
VALUES (NEW.session_id, NEW.role, NEW.content, NEW.thought, NEW.tool_calls);
END;
CREATE TRIGGER IF NOT EXISTS messages_fts_update AFTER UPDATE ON agent_messages
BEGIN
UPDATE agent_messages_fts SET
session_id = NEW.session_id,
role = NEW.role,
content = NEW.content,
thought = NEW.thought,
tool_calls = NEW.tool_calls
WHERE rowid = OLD.rowid;
END;
CREATE TRIGGER IF NOT EXISTS messages_fts_delete AFTER DELETE ON agent_messages
BEGIN
DELETE FROM agent_messages_fts WHERE rowid = OLD.rowid;
END;
-- 回填已有数据
INSERT OR IGNORE INTO agent_sessions_fts(session_id, title, summary, metadata)
SELECT session_id, title, summary, metadata FROM agent_sessions;
INSERT OR IGNORE INTO agent_messages_fts(session_id, role, content, thought, tool_calls)
SELECT session_id, role, content, thought, tool_calls FROM agent_messages;
@@ -1,30 +0,0 @@
-- 修复 FTS5 全文搜索中虚拟表与原始物理表的 rowid 不一致问题
-- 增量迁移:删除旧触发器,以正确映射 rowid 的触发器替代,并重建现有 FTS5 数据
-- 1. 删除旧的不安全触发器
DROP TRIGGER IF EXISTS sessions_fts_insert;
DROP TRIGGER IF EXISTS messages_fts_insert;
-- 2. 重新创建指定 rowid 列的插入触发器,确保 FTS 行 ID 与原始物理表行 ID 完全一致
CREATE TRIGGER IF NOT EXISTS sessions_fts_insert AFTER INSERT ON agent_sessions
BEGIN
INSERT INTO agent_sessions_fts(rowid, session_id, title, summary, metadata)
VALUES (NEW.rowid, NEW.session_id, NEW.title, NEW.summary, NEW.metadata);
END;
CREATE TRIGGER IF NOT EXISTS messages_fts_insert AFTER INSERT ON agent_messages
BEGIN
INSERT INTO agent_messages_fts(rowid, session_id, role, content, thought, tool_calls)
VALUES (NEW.rowid, NEW.session_id, NEW.role, NEW.content, NEW.thought, NEW.tool_calls);
END;
-- 3. 清理之前因不一致导致的错乱 FTS 数据
DELETE FROM agent_sessions_fts;
DELETE FROM agent_messages_fts;
-- 4. 使用正确的 rowid 重新索引现有数据
INSERT OR IGNORE INTO agent_sessions_fts(rowid, session_id, title, summary, metadata)
SELECT rowid, session_id, title, summary, metadata FROM agent_sessions;
INSERT OR IGNORE INTO agent_messages_fts(rowid, session_id, role, content, thought, tool_calls)
SELECT rowid, session_id, role, content, thought, tool_calls FROM agent_messages;
@@ -1,11 +0,0 @@
-- Migration: Add Agent Session Mode Support
--
-- 为代理会话增加运行模式 (mode) 字段,支持多模式 Agent 架构。
-- 现有会话自动获得 mode='default'(保持当前行为不变)。
--
-- mode 取值:
-- 'default' — 通用科研助手
-- 'deep-research' — 深度研究模式
-- 'literature-reader' — 文献阅读助手模式
ALTER TABLE agent_sessions ADD COLUMN mode TEXT NOT NULL DEFAULT 'default';