后端核心变更: - 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 (文献信息渲染)
357 lines
12 KiB
SQL
357 lines
12 KiB
SQL
-- 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)。
|
|
-- ============================================================
|