auto-sync: 2026-05-17 00:42:06

This commit is contained in:
cfdaily
2026-05-17 00:42:06 +08:00
parent ed191c11eb
commit 867b096b4f
+160 -189
View File
@@ -12,7 +12,8 @@ def init_db(db_path: Path) -> None:
db_path.parent.mkdir(parents=True, exist_ok=True) db_path.parent.mkdir(parents=True, exist_ok=True)
conn = _connect(db_path) conn = _connect(db_path)
try: try:
conn.executescript(SCHEMA_SQL) for stmt in _SCHEMA_STATEMENTS:
conn.execute(stmt)
conn.commit() conn.commit()
finally: finally:
conn.close() conn.close()
@@ -90,203 +91,173 @@ ATTEMPT_OUTCOMES = frozenset({
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# Schema SQL # Schema - split into individual statements to avoid SQLite 3.51 CHECK bug
# (table-level CHECK as non-last column definition causes parse error)
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
SCHEMA_SQL = """ _SCHEMA_STATEMENTS = [
-- ===== 任务表 ===== # tasks
CREATE TABLE IF NOT EXISTS tasks ( """CREATE TABLE IF NOT EXISTS tasks (
id TEXT PRIMARY KEY, id TEXT PRIMARY KEY,
title TEXT NOT NULL, title TEXT NOT NULL,
description TEXT, description TEXT,
status TEXT NOT NULL DEFAULT 'pending', status TEXT NOT NULL DEFAULT 'pending' CHECK (status IN ('pending','claimed','working','review','done','failed','blocked','cancelled')),
CHECK (status IN ('pending','claimed','working','review','done','failed','blocked','cancelled')), assignee TEXT,
assigned_by TEXT,
depends_on TEXT,
parent_task TEXT,
priority INTEGER NOT NULL DEFAULT 5,
task_type TEXT,
created_at TEXT NOT NULL DEFAULT (datetime('now')),
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
claimed_at TEXT,
started_at TEXT,
completed_at TEXT,
deadline TEXT,
retry_count INTEGER NOT NULL DEFAULT 0,
max_retries INTEGER NOT NULL DEFAULT 2,
must_haves TEXT,
risk_level TEXT DEFAULT 'standard',
estimated_duration_minutes INTEGER,
escalated INTEGER DEFAULT 0
)""",
"CREATE INDEX IF NOT EXISTS idx_tasks_status ON tasks(status)",
"CREATE INDEX IF NOT EXISTS idx_tasks_assignee ON tasks(assignee)",
"CREATE INDEX IF NOT EXISTS idx_tasks_parent ON tasks(parent_task)",
assignee TEXT, # comments
assigned_by TEXT, """CREATE TABLE IF NOT EXISTS comments (
id INTEGER PRIMARY KEY AUTOINCREMENT,
task_id TEXT NOT NULL REFERENCES tasks(id),
author TEXT NOT NULL,
comment_type TEXT NOT NULL DEFAULT 'general' CHECK (comment_type IN ('general','handoff','observation','rebuttal','rebuttal_response','debate_argument','debate_rebuttal','debate_judgment')),
body TEXT NOT NULL,
mentions TEXT,
created_at TEXT NOT NULL DEFAULT (datetime('now'))
)""",
"CREATE INDEX IF NOT EXISTS idx_comments_task ON comments(task_id)",
"CREATE INDEX IF NOT EXISTS idx_comments_type ON comments(task_id, comment_type)",
"CREATE INDEX IF NOT EXISTS idx_comments_author ON comments(author)",
depends_on TEXT, # outputs
parent_task TEXT, """CREATE TABLE IF NOT EXISTS outputs (
id INTEGER PRIMARY KEY AUTOINCREMENT,
task_id TEXT NOT NULL REFERENCES tasks(id),
agent TEXT NOT NULL,
output_type TEXT NOT NULL CHECK (output_type IN ('code','document','data','config','other')),
title TEXT NOT NULL,
content_path TEXT,
summary TEXT,
metadata TEXT,
attempt_number INTEGER DEFAULT 1,
created_at TEXT NOT NULL DEFAULT (datetime('now'))
)""",
"CREATE INDEX IF NOT EXISTS idx_outputs_task ON outputs(task_id)",
priority INTEGER NOT NULL DEFAULT 5, # decisions
task_type TEXT, """CREATE TABLE IF NOT EXISTS decisions (
id INTEGER PRIMARY KEY AUTOINCREMENT,
task_id TEXT NOT NULL REFERENCES tasks(id),
decider TEXT NOT NULL,
decision TEXT NOT NULL,
rationale TEXT NOT NULL,
alternatives TEXT,
created_at TEXT NOT NULL DEFAULT (datetime('now'))
)""",
"CREATE INDEX IF NOT EXISTS idx_decisions_task ON decisions(task_id)",
created_at TEXT NOT NULL DEFAULT (datetime('now')), # observations
updated_at TEXT NOT NULL DEFAULT (datetime('now')), """CREATE TABLE IF NOT EXISTS observations (
claimed_at TEXT, id INTEGER PRIMARY KEY AUTOINCREMENT,
started_at TEXT, task_id TEXT NOT NULL REFERENCES tasks(id),
completed_at TEXT, observer TEXT NOT NULL,
deadline TEXT, severity TEXT NOT NULL DEFAULT 'info' CHECK (severity IN ('blocking','warning','info','audit')),
body TEXT NOT NULL,
resolved_by TEXT,
resolved_at TEXT,
created_at TEXT NOT NULL DEFAULT (datetime('now'))
)""",
retry_count INTEGER NOT NULL DEFAULT 0, # events
max_retries INTEGER NOT NULL DEFAULT 2, """CREATE TABLE IF NOT EXISTS events (
id INTEGER PRIMARY KEY AUTOINCREMENT,
task_id TEXT,
agent TEXT,
event_type TEXT NOT NULL,
detail TEXT,
created_at TEXT NOT NULL DEFAULT (datetime('now'))
)""",
"CREATE INDEX IF NOT EXISTS idx_events_task ON events(task_id)",
"CREATE INDEX IF NOT EXISTS idx_events_time ON events(created_at)",
must_haves TEXT, # agents
risk_level TEXT DEFAULT 'standard', """CREATE TABLE IF NOT EXISTS agents (
estimated_duration_minutes INTEGER, agent_id TEXT PRIMARY KEY,
role TEXT,
current_status TEXT DEFAULT 'idle',
current_task TEXT,
last_active TEXT,
capabilities TEXT
)""",
escalated INTEGER DEFAULT 0 # task_attempts
); """CREATE TABLE IF NOT EXISTS task_attempts (
id INTEGER PRIMARY KEY AUTOINCREMENT,
task_id TEXT NOT NULL REFERENCES tasks(id),
attempt_number INTEGER NOT NULL,
agent TEXT NOT NULL,
outcome TEXT NOT NULL CHECK (outcome IN ('completed','blocked','crashed','timed_out','spawn_failed','reclaimed')),
exit_code INTEGER,
log_path TEXT,
summary TEXT,
metadata TEXT,
started_at TEXT NOT NULL DEFAULT (datetime('now')),
completed_at TEXT
)""",
"CREATE INDEX IF NOT EXISTS idx_attempts_task ON task_attempts(task_id)",
CREATE INDEX IF NOT EXISTS idx_tasks_status ON tasks(status); # reviews
CREATE INDEX IF NOT EXISTS idx_tasks_assignee ON tasks(assignee); """CREATE TABLE IF NOT EXISTS reviews (
CREATE INDEX IF NOT EXISTS idx_tasks_parent ON tasks(parent_task); id TEXT PRIMARY KEY,
task_id TEXT NOT NULL REFERENCES tasks(id),
output_id TEXT,
reviewer TEXT NOT NULL,
review_type TEXT NOT NULL CHECK (review_type IN ('plan_review','output_review','guardrail','final_review')),
verdict TEXT NOT NULL CHECK (verdict IN ('approved','rejected','needs_revision')),
confidence REAL,
round INTEGER NOT NULL DEFAULT 1,
max_rounds INTEGER NOT NULL DEFAULT 3,
consensus_reached INTEGER DEFAULT 0,
summary TEXT NOT NULL,
detail_path TEXT,
created_at TEXT NOT NULL DEFAULT (datetime('now'))
)""",
"CREATE INDEX IF NOT EXISTS idx_reviews_task ON reviews(task_id)",
"CREATE INDEX IF NOT EXISTS idx_reviews_output ON reviews(output_id)",
-- ===== 评论线程表 ===== # experiences
CREATE TABLE IF NOT EXISTS comments ( """CREATE TABLE IF NOT EXISTS experiences (
id INTEGER PRIMARY KEY AUTOINCREMENT, experience_id TEXT PRIMARY KEY,
task_id TEXT NOT NULL, source TEXT NOT NULL CHECK (source IN ('task_completion','error_correction','review_finding','manual')),
author TEXT NOT NULL, task_id TEXT,
comment_type TEXT NOT NULL DEFAULT 'general', summary TEXT NOT NULL,
body TEXT NOT NULL, category TEXT NOT NULL CHECK (category IN ('pitfall','best_practice','pattern','anti_pattern')),
mentions TEXT, confidence REAL DEFAULT 0.8,
created_at TEXT NOT NULL DEFAULT (datetime('now')), status TEXT DEFAULT 'active' CHECK (status IN ('draft','active','deprecated')),
FOREIGN KEY (task_id) REFERENCES tasks(id), skill_id TEXT,
CHECK (comment_type IN ('general','handoff','observation','rebuttal','rebuttal_response','debate_argument','debate_rebuttal','debate_judgment')) usage_count INTEGER DEFAULT 0,
); last_used_at TEXT,
created_at TEXT NOT NULL,
created_by TEXT NOT NULL,
updated_at TEXT,
deprecated_reason TEXT
)""",
CREATE INDEX IF NOT EXISTS idx_comments_task ON comments(task_id); # experience_tags
CREATE INDEX IF NOT EXISTS idx_comments_type ON comments(task_id, comment_type); """CREATE TABLE IF NOT EXISTS experience_tags (
CREATE INDEX IF NOT EXISTS idx_comments_author ON comments(author); experience_id TEXT NOT NULL REFERENCES experiences(experience_id),
tag TEXT NOT NULL,
-- ===== 产出表 ===== PRIMARY KEY (experience_id, tag)
CREATE TABLE IF NOT EXISTS outputs ( )""",
id INTEGER PRIMARY KEY AUTOINCREMENT, "CREATE INDEX IF NOT EXISTS idx_exptags_tag ON experience_tags(tag)",
task_id TEXT NOT NULL, ]
agent TEXT NOT NULL,
output_type TEXT NOT NULL,
title TEXT NOT NULL,
content_path TEXT,
summary TEXT,
metadata TEXT,
attempt_number INTEGER DEFAULT 1,
created_at TEXT NOT NULL DEFAULT (datetime('now')),
FOREIGN KEY (task_id) REFERENCES tasks(id),
CHECK (output_type IN ('code','document','data','config','other'))
);
CREATE INDEX IF NOT EXISTS idx_outputs_task ON outputs(task_id);
-- ===== 决策记录表 =====
CREATE TABLE IF NOT EXISTS decisions (
id INTEGER PRIMARY KEY AUTOINCREMENT,
task_id TEXT NOT NULL,
decider TEXT NOT NULL,
decision TEXT NOT NULL,
rationale TEXT NOT NULL,
alternatives TEXT,
created_at TEXT NOT NULL DEFAULT (datetime('now')),
FOREIGN KEY (task_id) REFERENCES tasks(id)
);
CREATE INDEX IF NOT EXISTS idx_decisions_task ON decisions(task_id);
-- ===== 观察表 =====
CREATE TABLE IF NOT EXISTS observations (
id INTEGER PRIMARY KEY AUTOINCREMENT,
task_id TEXT NOT NULL,
observer TEXT NOT NULL,
severity TEXT NOT NULL DEFAULT 'info',
CHECK (severity IN ('blocking','warning','info','audit')),
body TEXT NOT NULL,
resolved_by TEXT,
resolved_at TEXT,
created_at TEXT NOT NULL DEFAULT (datetime('now')),
FOREIGN KEY (task_id) REFERENCES tasks(id)
);
-- ===== 事件日志 =====
CREATE TABLE IF NOT EXISTS events (
id INTEGER PRIMARY KEY AUTOINCREMENT,
task_id TEXT,
agent TEXT,
event_type TEXT NOT NULL,
detail TEXT,
created_at TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE INDEX IF NOT EXISTS idx_events_task ON events(task_id);
CREATE INDEX IF NOT EXISTS idx_events_time ON events(created_at);
-- ===== Agent 注册表 =====
CREATE TABLE IF NOT EXISTS agents (
agent_id TEXT PRIMARY KEY,
role TEXT,
current_status TEXT DEFAULT 'idle',
current_task TEXT,
last_active TEXT,
capabilities TEXT
);
-- ===== 任务尝试记录 =====
CREATE TABLE IF NOT EXISTS task_attempts (
id INTEGER PRIMARY KEY AUTOINCREMENT,
task_id TEXT NOT NULL,
attempt_number INTEGER NOT NULL,
agent TEXT NOT NULL,
outcome TEXT NOT NULL,
CHECK (outcome IN ('completed','blocked','crashed','timed_out','spawn_failed','reclaimed')),
exit_code INTEGER,
log_path TEXT,
summary TEXT,
metadata TEXT,
started_at TEXT NOT NULL DEFAULT (datetime('now')),
completed_at TEXT,
FOREIGN KEY (task_id) REFERENCES tasks(id)
);
CREATE INDEX IF NOT EXISTS idx_attempts_task ON task_attempts(task_id);
-- ===== 评审表 =====
CREATE TABLE IF NOT EXISTS reviews (
id TEXT PRIMARY KEY,
task_id TEXT NOT NULL,
output_id TEXT,
reviewer TEXT NOT NULL,
review_type TEXT NOT NULL,
CHECK (review_type IN ('plan_review','output_review','guardrail','final_review')),
verdict TEXT NOT NULL,
CHECK (verdict IN ('approved','rejected','needs_revision')),
confidence REAL,
round INTEGER NOT NULL DEFAULT 1,
max_rounds INTEGER NOT NULL DEFAULT 3,
consensus_reached INTEGER DEFAULT 0,
summary TEXT NOT NULL,
detail_path TEXT,
created_at TEXT NOT NULL DEFAULT (datetime('now')),
FOREIGN KEY (task_id) REFERENCES tasks(id)
);
CREATE INDEX IF NOT EXISTS idx_reviews_task ON reviews(task_id);
CREATE INDEX IF NOT EXISTS idx_reviews_output ON reviews(output_id);
-- ===== 经验表 =====
CREATE TABLE IF NOT EXISTS experiences (
experience_id TEXT PRIMARY KEY,
source TEXT NOT NULL,
CHECK (source IN ('task_completion','error_correction','review_finding','manual')),
task_id TEXT,
summary TEXT NOT NULL,
category TEXT NOT NULL,
CHECK (category IN ('pitfall','best_practice','pattern','anti_pattern')),
confidence REAL DEFAULT 0.8,
status TEXT DEFAULT 'active',
CHECK (status IN ('draft','active','deprecated')),
skill_id TEXT,
usage_count INTEGER DEFAULT 0,
last_used_at TEXT,
created_at TEXT NOT NULL,
created_by TEXT NOT NULL,
updated_at TEXT,
deprecated_reason TEXT
);
-- ===== 经验标签关联表 =====
CREATE TABLE IF NOT EXISTS experience_tags (
experience_id TEXT NOT NULL REFERENCES experiences(experience_id),
tag TEXT NOT NULL,
PRIMARY KEY (experience_id, tag)
);
CREATE INDEX IF NOT EXISTS idx_exptags_tag ON experience_tags(tag);
"""