auto(0129): agents_dashboard — secret_store_cpp_infra + CMakeLists register #4

Open
dataforge wants to merge 615 commits from auto/0129 into master
3 changed files with 125 additions and 0 deletions
Showing only changes of commit 169cb0853b - Show all commits
+14
View File
@@ -0,0 +1,14 @@
CREATE TABLE logs (
id TEXT PRIMARY KEY,
level TEXT NOT NULL DEFAULT 'info' CHECK(level IN ('debug','info','warn','error')),
source TEXT NOT NULL DEFAULT '',
entity_id TEXT NOT NULL DEFAULT '',
execution_id TEXT NOT NULL DEFAULT '',
message TEXT NOT NULL,
metadata TEXT NOT NULL DEFAULT '{}',
created_at TEXT NOT NULL
);
CREATE INDEX idx_logs_level ON logs(level);
CREATE INDEX idx_logs_source ON logs(source);
CREATE INDEX idx_logs_created_at ON logs(created_at);
+22
View File
@@ -145,6 +145,28 @@ type AssertionResult struct {
EvaluatedAt time.Time `json:"evaluated_at"`
}
// LogLevel represents the severity of a log entry.
type LogLevel string
const (
LogDebug LogLevel = "debug"
LogInfo LogLevel = "info"
LogWarn LogLevel = "warn"
LogError LogLevel = "error"
)
// Log is a free-form operational event within a project context.
type Log struct {
ID string `json:"id"`
Level LogLevel `json:"level"`
Source string `json:"source"` // who: agent, pipeline, reactive_loop, function name...
EntityID string `json:"entity_id"` // optional context
ExecutionID string `json:"execution_id"` // optional context
Message string `json:"message"`
Metadata map[string]any `json:"metadata"`
CreatedAt time.Time `json:"created_at"`
}
// TypeSnapshot is an immutable copy of a registry type at point of use.
type TypeSnapshot struct {
ID string `json:"id"`
+89
View File
@@ -814,3 +814,92 @@ func scanAssertionResults(rows *sql.Rows) ([]AssertionResult, error) {
}
return result, nil
}
// --- Log CRUD ---
// InsertLog inserts a log entry.
func (db *DB) InsertLog(l *Log) error {
if l.CreatedAt.IsZero() {
l.CreatedAt = time.Now().UTC()
}
_, err := db.conn.Exec(`
INSERT INTO logs (id, level, source, entity_id, execution_id, message, metadata, created_at)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
l.ID, string(l.Level), l.Source, l.EntityID, l.ExecutionID,
l.Message, marshalJSON(l.Metadata), l.CreatedAt.Format(time.RFC3339),
)
return err
}
// GetLog returns a log entry by ID.
func (db *DB) GetLog(id string) (*Log, error) {
row := db.conn.QueryRow(`
SELECT id, level, source, entity_id, execution_id, message, metadata, created_at
FROM logs WHERE id = ?`, id)
var l Log
var metadataJSON, createdAt string
err := row.Scan(&l.ID, &l.Level, &l.Source, &l.EntityID, &l.ExecutionID,
&l.Message, &metadataJSON, &createdAt)
if err == sql.ErrNoRows {
return nil, nil
}
if err != nil {
return nil, fmt.Errorf("scanning log: %w", err)
}
l.Metadata = unmarshalJSON(metadataJSON)
l.CreatedAt, _ = time.Parse(time.RFC3339, createdAt)
return &l, nil
}
// ListLogs returns logs filtered by level, source, entity, and/or execution.
func (db *DB) ListLogs(level LogLevel, source, entityID, executionID string, limit int) ([]Log, error) {
where := []string{}
args := []any{}
if level != "" {
where = append(where, "level = ?")
args = append(args, string(level))
}
if source != "" {
where = append(where, "source = ?")
args = append(args, source)
}
if entityID != "" {
where = append(where, "entity_id = ?")
args = append(args, entityID)
}
if executionID != "" {
where = append(where, "execution_id = ?")
args = append(args, executionID)
}
q := `SELECT id, level, source, entity_id, execution_id, message, metadata, created_at FROM logs`
if len(where) > 0 {
q += " WHERE " + strings.Join(where, " AND ")
}
q += " ORDER BY created_at DESC"
if limit > 0 {
q += fmt.Sprintf(" LIMIT %d", limit)
}
rows, err := db.conn.Query(q, args...)
if err != nil {
return nil, err
}
defer rows.Close()
var result []Log
for rows.Next() {
var l Log
var metadataJSON, createdAt string
if err := rows.Scan(&l.ID, &l.Level, &l.Source, &l.EntityID, &l.ExecutionID,
&l.Message, &metadataJSON, &createdAt); err != nil {
return nil, fmt.Errorf("scanning log: %w", err)
}
l.Metadata = unmarshalJSON(metadataJSON)
l.CreatedAt, _ = time.Parse(time.RFC3339, createdAt)
result = append(result, l)
}
return result, nil
}