mirror of
https://github.com/Ed1s0nZ/CyberStrikeAI.git
synced 2026-10-19 14:07:36 +02:00
feat: reconcile SQLite tables and columns at startup
This commit is contained in:
1 parent
8cc575b6ae
commit
7f8dab4ec9
18 files changed
+1669
-1836
No files matched your search
@@ -63,38 +63,11 @@ func NewHITLManager(db *database.DB, logger *zap.Logger) *HITLManager {
|
||||
}
|
||||
}
|
||||
|
||||
// EnsureSchema performs historical recovery after NewDB has checked all tables.
|
||||
func (m *HITLManager) EnsureSchema() error {
|
||||
if _, err := m.db.Exec(`
|
||||
CREATE TABLE IF NOT EXISTS hitl_interrupts (
|
||||
id TEXT PRIMARY KEY,
|
||||
conversation_id TEXT NOT NULL,
|
||||
message_id TEXT,
|
||||
mode TEXT NOT NULL,
|
||||
tool_name TEXT NOT NULL,
|
||||
tool_call_id TEXT,
|
||||
payload TEXT,
|
||||
status TEXT NOT NULL,
|
||||
reviewer TEXT NOT NULL DEFAULT 'human',
|
||||
decision TEXT,
|
||||
decision_comment TEXT,
|
||||
created_at DATETIME NOT NULL,
|
||||
decided_at DATETIME
|
||||
);`); err != nil {
|
||||
if err := m.backfillHitlReviewers(); err != nil {
|
||||
return err
|
||||
}
|
||||
_, err := m.db.Exec(`
|
||||
CREATE TABLE IF NOT EXISTS hitl_conversation_configs (
|
||||
conversation_id TEXT PRIMARY KEY,
|
||||
enabled INTEGER NOT NULL DEFAULT 0,
|
||||
mode TEXT NOT NULL DEFAULT 'off',
|
||||
sensitive_tools TEXT NOT NULL DEFAULT '[]',
|
||||
timeout_seconds INTEGER NOT NULL DEFAULT 0,
|
||||
updated_at DATETIME NOT NULL
|
||||
);`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
m.migrateHitlSchemaColumns()
|
||||
|
||||
// On startup, cancel all orphaned pending interrupts from previous process.
|
||||
// Their in-memory channels are gone, so they can never be resolved.
|
||||
|
||||
@@ -37,12 +37,10 @@ func normalizeHitlDecidedBy(v string) string {
|
||||
}
|
||||
}
|
||||
|
||||
func (m *HITLManager) migrateHitlSchemaColumns() {
|
||||
_, _ = m.db.Exec(`ALTER TABLE hitl_interrupts ADD COLUMN decided_by TEXT NOT NULL DEFAULT 'human'`)
|
||||
_, _ = m.db.Exec(`ALTER TABLE hitl_interrupts ADD COLUMN reviewer TEXT NOT NULL DEFAULT 'human'`)
|
||||
_, _ = m.db.Exec(`UPDATE hitl_interrupts SET reviewer='audit_agent'
|
||||
WHERE COALESCE(decided_by, '') IN ('audit_agent', 'agent', 'ai')`)
|
||||
_, _ = m.db.Exec(`ALTER TABLE hitl_conversation_configs ADD COLUMN reviewer TEXT NOT NULL DEFAULT 'human'`)
|
||||
func (m *HITLManager) backfillHitlReviewers() error {
|
||||
_, err := m.db.Exec(`UPDATE hitl_interrupts SET reviewer='audit_agent'
|
||||
WHERE COALESCE(decided_by, '') IN ('audit_agent', 'agent', 'ai')`)
|
||||
return err
|
||||
}
|
||||
|
||||
func hitlInterruptRowToMap(
|
||||
|
||||
@@ -582,25 +582,6 @@ func countUnread(items []NotificationSummaryItem) int {
|
||||
return total
|
||||
}
|
||||
|
||||
func createNotificationReadTableIfNeeded(db *database.DB) error {
|
||||
if db == nil {
|
||||
return fmt.Errorf("db is nil")
|
||||
}
|
||||
_, err := db.Exec(`
|
||||
CREATE TABLE IF NOT EXISTS notification_reads_by_user (
|
||||
user_id TEXT NOT NULL,
|
||||
event_id TEXT NOT NULL,
|
||||
read_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY(user_id, event_id)
|
||||
);
|
||||
`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, idxErr := db.Exec(`CREATE INDEX IF NOT EXISTS idx_notification_reads_user_read_at ON notification_reads_by_user(user_id, read_at DESC);`)
|
||||
return idxErr
|
||||
}
|
||||
|
||||
func pruneNotificationReads(db *database.DB, userID string, maxRows int) error {
|
||||
if db == nil {
|
||||
return fmt.Errorf("db is nil")
|
||||
@@ -648,7 +629,7 @@ func normalizeMarkableEventID(id string) (string, bool) {
|
||||
|
||||
// MarkRead 按事件 ID 标记已读
|
||||
func (h *NotificationHandler) MarkRead(c *gin.Context) {
|
||||
if err := createNotificationReadTableIfNeeded(h.db); err != nil {
|
||||
if h.db == nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to prepare notification read table"})
|
||||
return
|
||||
}
|
||||
@@ -713,12 +694,6 @@ func (h *NotificationHandler) GetSummary(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
if err := createNotificationReadTableIfNeeded(h.db); err != nil {
|
||||
h.logger.Warn("初始化通知已读表失败", zap.Error(err))
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to initialize notification read table"})
|
||||
return
|
||||
}
|
||||
|
||||
english := requestWantsEnglish(c)
|
||||
sinceMs := normalizeSinceMs(parseSinceMs(c.Query("since")))
|
||||
limit, _ := strconv.Atoi(strings.TrimSpace(c.DefaultQuery("limit", "50")))
|
||||
|
||||
Reference in new issue
Block a user