refactor(memory): update delegate, sqlc queries (agent_audit_log, recall, rl)

This commit is contained in:
ZanzyTHEbar 2026-03-05 21:16:49 +00:00
parent b9208c0bf8
commit ab4655901a
9 changed files with 563 additions and 141 deletions

View file

@ -180,17 +180,10 @@ func TestSQLiteDelegate_UpdateMemoryWeight(t *testing.T) {
// Insert a recall item first // Insert a recall item first
memoryID := insertTestRecallItem(ctx, t, d, agentID) memoryID := insertTestRecallItem(ctx, t, d, agentID)
// Update the memory weight via direct query // Update the memory weight via delegate API
newWeight := 2.5 newWeight := 2.5
credit := 3.0 credit := 3.0
paramsRLWeight := newWeight err := d.UpdateMemoryWeight(ctx, memoryID, newWeight, credit)
paramsRLCredit := credit
err := d.Queries().UpdateMemoryWeight(ctx, memsqlc.UpdateMemoryWeightParams{
RlWeight: &paramsRLWeight,
RlCredit: &paramsRLCredit,
ID: memoryID,
AgentID: agentID,
})
if err != nil { if err != nil {
t.Fatalf("UpdateMemoryWeight: %v", err) t.Fatalf("UpdateMemoryWeight: %v", err)
} }
@ -209,21 +202,12 @@ func TestSQLiteDelegate_UpdateMemoryWeight_NonExistent(t *testing.T) {
t.Parallel() t.Parallel()
d := setupRLTest(t) d := setupRLTest(t)
ctx := t.Context() ctx := t.Context()
agentID := "test-agent"
// Try to update weight for non-existent memory via direct query // Try to update weight for non-existent memory.
nonExistentID := ids.New() nonExistentID := ids.New()
paramsWeight := 2.0 err := d.UpdateMemoryWeight(ctx, nonExistentID, 2.0, 1.0)
paramsCredit := 1.0 if err == nil {
err := d.Queries().UpdateMemoryWeight(ctx, memsqlc.UpdateMemoryWeightParams{ t.Fatal("expected error for non-existent memory update")
RlWeight: &paramsWeight,
RlCredit: &paramsCredit,
ID: nonExistentID,
AgentID: agentID,
})
// Query succeeds but doesn't update anything (no error for non-existent)
if err != nil {
t.Errorf("UpdateMemoryWeight should not error for non-existent: %v", err)
} }
} }
@ -236,13 +220,8 @@ func TestSQLiteDelegate_UpdateMemorySelfReport(t *testing.T) {
// Insert a recall item first // Insert a recall item first
memoryID := insertTestRecallItem(ctx, t, d, agentID) memoryID := insertTestRecallItem(ctx, t, d, agentID)
// Update self-report score via direct query // Update self-report score via delegate API.
score := int64(2) err := d.UpdateMemorySelfReport(ctx, memoryID, 2)
err := d.Queries().UpdateMemorySelfReportScore(ctx, memsqlc.UpdateMemorySelfReportScoreParams{
SelfReportScore: &score,
ID: memoryID,
AgentID: agentID,
})
if err != nil { if err != nil {
t.Fatalf("UpdateMemorySelfReportScore: %v", err) t.Fatalf("UpdateMemorySelfReportScore: %v", err)
} }
@ -261,19 +240,12 @@ func TestSQLiteDelegate_UpdateMemorySelfReport_NonExistent(t *testing.T) {
t.Parallel() t.Parallel()
d := setupRLTest(t) d := setupRLTest(t)
ctx := t.Context() ctx := t.Context()
agentID := "test-agent"
// Try to update self-report for non-existent memory via direct query // Try to update self-report for non-existent memory.
nonExistentID := ids.New() nonExistentID := ids.New()
score := int64(3) err := d.UpdateMemorySelfReport(ctx, nonExistentID, 3)
err := d.Queries().UpdateMemorySelfReportScore(ctx, memsqlc.UpdateMemorySelfReportScoreParams{ if err == nil {
SelfReportScore: &score, t.Fatal("expected error for non-existent memory self-report update")
ID: nonExistentID,
AgentID: agentID,
})
// Query succeeds but doesn't update anything (no error for non-existent)
if err != nil {
t.Errorf("UpdateMemorySelfReportScore should not error for non-existent: %v", err)
} }
} }
@ -547,6 +519,7 @@ func TestSQLiteDelegate_GetRecentAuditEntries(t *testing.T) {
t.Parallel() t.Parallel()
d := setupRLTest(t) d := setupRLTest(t)
ctx := t.Context() ctx := t.Context()
since := time.Now().Add(-1 * time.Minute)
// Insert some audit entries // Insert some audit entries
entries := []*memory.AuditEntry{ entries := []*memory.AuditEntry{
@ -561,8 +534,8 @@ func TestSQLiteDelegate_GetRecentAuditEntries(t *testing.T) {
}, },
{ {
ID: ids.New(), ID: ids.New(),
AgentID: "audit-agent", AgentID: "audit-agent-2",
SessionKey: "session-1", SessionKey: "session-2",
Action: "write_file", Action: "write_file",
Target: "/path/to/output", Target: "/path/to/output",
Input: `{"path": "/output"}`, Input: `{"path": "/output"}`,
@ -576,15 +549,27 @@ func TestSQLiteDelegate_GetRecentAuditEntries(t *testing.T) {
} }
} }
// Get recent audit entries (all of them, since time is in the past) // Get recent audit entries across all agents.
auditEntries, err := d.GetRecentAuditEntries(ctx, time.Time{}) auditEntries, err := d.GetRecentAuditEntries(ctx, since)
if err != nil { if err != nil {
t.Fatalf("GetRecentAuditEntries: %v", err) t.Fatalf("GetRecentAuditEntries: %v", err)
} }
if len(auditEntries) != 2 {
t.Fatalf("expected 2 recent audit entries, got %d", len(auditEntries))
}
// The implementation uses ListAuditEntries with empty agent_id which may filter results foundAgents := map[string]bool{}
// Just verify the query executes without error foundTools := map[string]bool{}
t.Logf("Got %d audit entries", len(auditEntries)) for _, entry := range auditEntries {
foundAgents[entry.AgentID] = true
foundTools[entry.ToolName] = true
}
if !foundAgents["audit-agent"] || !foundAgents["audit-agent-2"] {
t.Fatalf("expected entries from both agents, got %+v", foundAgents)
}
if !foundTools["read_file"] || !foundTools["write_file"] {
t.Fatalf("expected tool names mapped from action, got %+v", foundTools)
}
} }
func TestSQLiteDelegate_GetHighTokenSessions(t *testing.T) { func TestSQLiteDelegate_GetHighTokenSessions(t *testing.T) {
@ -592,13 +577,79 @@ func TestSQLiteDelegate_GetHighTokenSessions(t *testing.T) {
d := setupRLTest(t) d := setupRLTest(t)
ctx := t.Context() ctx := t.Context()
// This is a placeholder implementation that returns empty list // Recreate task_completions with relaxed constraints for focused aggregation testing.
sessions, err := d.GetHighTokenSessions(ctx, 1000) _, _ = d.db.ExecContext(ctx, `DROP TABLE IF EXISTS task_completions`)
_, err := d.db.ExecContext(ctx, `
CREATE TABLE task_completions (
id BLOB PRIMARY KEY,
agent_id TEXT NOT NULL,
conversation_id BLOB NOT NULL,
run_id BLOB NOT NULL,
description TEXT,
tokens_used INTEGER DEFAULT 0,
tool_calls INTEGER DEFAULT 0,
errors INTEGER DEFAULT 0,
user_corrections INTEGER DEFAULT 0,
completed BOOLEAN NOT NULL DEFAULT 0,
created_at DATETIME NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))
) WITHOUT ROWID
`)
if err != nil {
t.Fatalf("create task_completions table: %v", err)
}
session1 := ids.New()
session2 := ids.New()
session3 := ids.New()
runID := ids.New()
_, err = d.db.ExecContext(ctx, `
INSERT INTO task_completions (id, agent_id, conversation_id, run_id, description, tokens_used, completed)
VALUES (?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?, ?)
`,
ids.New(), "agent-a", session1, runID, "task-1", 800, true,
ids.New(), "agent-a", session1, runID, "task-2", 900, true,
ids.New(), "agent-b", session2, runID, "task-3", 400, true,
ids.New(), "agent-c", session3, runID, "task-4", 300, true,
ids.New(), "agent-c", session3, runID, "task-5", 450, true,
)
if err != nil {
t.Fatalf("insert task completions: %v", err)
}
sessions, err := d.GetHighTokenSessions(ctx, 700)
if err != nil { if err != nil {
t.Fatalf("GetHighTokenSessions: %v", err) t.Fatalf("GetHighTokenSessions: %v", err)
} }
if len(sessions) != 0 { if len(sessions) != 2 {
t.Errorf("expected 0 sessions (placeholder), got %d", len(sessions)) t.Fatalf("expected 2 high-token sessions, got %d", len(sessions))
}
gotByAgent := map[string]SessionSummary{}
for _, s := range sessions {
gotByAgent[s.AgentID] = s
}
a, ok := gotByAgent["agent-a"]
if !ok {
t.Fatalf("expected aggregated session for agent-a, got %+v", gotByAgent)
}
if a.SessionID != session1.String() {
t.Fatalf("expected session %s for agent-a, got %s", session1.String(), a.SessionID)
}
if a.TotalTokens < 1700 {
t.Fatalf("expected aggregated tokens >= 1700 for agent-a, got %d", a.TotalTokens)
}
c, ok := gotByAgent["agent-c"]
if !ok {
t.Fatalf("expected aggregated session for agent-c, got %+v", gotByAgent)
}
if c.SessionID != session3.String() {
t.Fatalf("expected session %s for agent-c, got %s", session3.String(), c.SessionID)
}
if c.TotalTokens < 750 {
t.Fatalf("expected aggregated tokens >= 750 for agent-c, got %d", c.TotalTokens)
} }
} }
@ -654,19 +705,11 @@ func TestSQLiteDelegate_RLStore_Integration(t *testing.T) {
memoryIDs[i] = insertTestRecallItem(ctx, t, d, agentID) memoryIDs[i] = insertTestRecallItem(ctx, t, d, agentID)
} }
// Update weights for each memory via direct query // Update weights for each memory via delegate API.
// Note: GetRecallItem doesn't return RL fields, so we just verify no errors
weights := []float64{1.5, 2.0, 2.5} weights := []float64{1.5, 2.0, 2.5}
credits := []float64{1.0, 2.0, 3.0} credits := []float64{1.0, 2.0, 3.0}
for i, memoryID := range memoryIDs { for i, memoryID := range memoryIDs {
paramsRLWeight := weights[i] err := d.UpdateMemoryWeight(ctx, memoryID, weights[i], credits[i])
paramsRLCredit := credits[i]
err := d.Queries().UpdateMemoryWeight(ctx, memsqlc.UpdateMemoryWeightParams{
RlWeight: &paramsRLWeight,
RlCredit: &paramsRLCredit,
ID: memoryID,
AgentID: agentID,
})
if err != nil { if err != nil {
t.Fatalf("UpdateMemoryWeight %d: %v", i, err) t.Fatalf("UpdateMemoryWeight %d: %v", i, err)
} }
@ -687,15 +730,10 @@ func TestSQLiteDelegate_RLStore_Integration(t *testing.T) {
t.Run("SelfReportUpdates", func(t *testing.T) { t.Run("SelfReportUpdates", func(t *testing.T) {
memoryID := insertTestRecallItem(ctx, t, d, agentID) memoryID := insertTestRecallItem(ctx, t, d, agentID)
// Update self-report scores via direct query // Update self-report scores via delegate API.
// Note: GetRecallItem doesn't return self_report_score, so we just verify no errors
scores := []int64{0, 1, 2, 3} scores := []int64{0, 1, 2, 3}
for _, score := range scores { for _, score := range scores {
err := d.Queries().UpdateMemorySelfReportScore(ctx, memsqlc.UpdateMemorySelfReportScoreParams{ err := d.UpdateMemorySelfReport(ctx, memoryID, int(score))
SelfReportScore: &score,
ID: memoryID,
AgentID: agentID,
})
if err != nil { if err != nil {
t.Fatalf("UpdateMemorySelfReportScore %d: %v", score, err) t.Fatalf("UpdateMemorySelfReportScore %d: %v", score, err)
} }

View file

@ -5,6 +5,7 @@ import (
"context" "context"
"database/sql" "database/sql"
"fmt" "fmt"
"strings"
"time" "time"
"github.com/ZanzyTHEbar/dragonscale/pkg/ids" "github.com/ZanzyTHEbar/dragonscale/pkg/ids"
@ -1079,19 +1080,20 @@ func (d *LibSQLDelegate) UpdateTaskBaseline(ctx context.Context, agentID string,
func (d *LibSQLDelegate) UpdateMemoryWeight(ctx context.Context, memoryID ids.UUID, weight, credit float64) error { func (d *LibSQLDelegate) UpdateMemoryWeight(ctx context.Context, memoryID ids.UUID, weight, credit float64) error {
rlWeight := weight rlWeight := weight
rlCredit := credit rlCredit := credit
// Get the agent_id from the memory item first row, err := d.queries.GetRecallItemByID(ctx, memsqlc.GetRecallItemByIDParams{
item, err := d.GetRecallItem(ctx, "", memoryID) ID: memoryID,
})
if err == sql.ErrNoRows {
return fmt.Errorf("memory item not found: %s", memoryID)
}
if err != nil { if err != nil {
return err return err
} }
if item == nil {
return fmt.Errorf("memory item not found: %s", memoryID)
}
return d.queries.UpdateMemoryWeight(ctx, memsqlc.UpdateMemoryWeightParams{ return d.queries.UpdateMemoryWeight(ctx, memsqlc.UpdateMemoryWeightParams{
RlWeight: &rlWeight, RlWeight: &rlWeight,
RlCredit: &rlCredit, RlCredit: &rlCredit,
ID: memoryID, ID: memoryID,
AgentID: item.AgentID, AgentID: row.AgentID,
}) })
} }
@ -1099,18 +1101,19 @@ func (d *LibSQLDelegate) UpdateMemoryWeight(ctx context.Context, memoryID ids.UU
// Implements cortex.RLStore interface. // Implements cortex.RLStore interface.
func (d *LibSQLDelegate) UpdateMemorySelfReport(ctx context.Context, memoryID ids.UUID, score int) error { func (d *LibSQLDelegate) UpdateMemorySelfReport(ctx context.Context, memoryID ids.UUID, score int) error {
selfReportScore := int64(score) selfReportScore := int64(score)
// Get the agent_id from the memory item first row, err := d.queries.GetRecallItemByID(ctx, memsqlc.GetRecallItemByIDParams{
item, err := d.GetRecallItem(ctx, "", memoryID) ID: memoryID,
})
if err == sql.ErrNoRows {
return fmt.Errorf("memory item not found: %s", memoryID)
}
if err != nil { if err != nil {
return err return err
} }
if item == nil {
return fmt.Errorf("memory item not found: %s", memoryID)
}
return d.queries.UpdateMemorySelfReportScore(ctx, memsqlc.UpdateMemorySelfReportScoreParams{ return d.queries.UpdateMemorySelfReportScore(ctx, memsqlc.UpdateMemorySelfReportScoreParams{
SelfReportScore: &selfReportScore, SelfReportScore: &selfReportScore,
ID: memoryID, ID: memoryID,
AgentID: item.AgentID, AgentID: row.AgentID,
}) })
} }
@ -1207,33 +1210,67 @@ func (d *LibSQLDelegate) ListActiveAgents(ctx context.Context, since time.Time)
// GetRecentAuditEntries returns audit entries since the given time. // GetRecentAuditEntries returns audit entries since the given time.
// Implements cortex.AuditAnalysisStore interface. // Implements cortex.AuditAnalysisStore interface.
func (d *LibSQLDelegate) GetRecentAuditEntries(ctx context.Context, since time.Time) ([]AuditEntry, error) { func (d *LibSQLDelegate) GetRecentAuditEntries(ctx context.Context, since time.Time) ([]AuditEntry, error) {
// Get all audit entries and filter by time cutoff := since.UTC()
rows, err := d.queries.ListAuditEntries(ctx, memsqlc.ListAuditEntriesParams{ if cutoff.IsZero() {
AgentID: "", // Get all agents cutoff = time.Unix(0, 0).UTC()
Lim: 10000,
})
if err != nil {
return nil, err
} }
var entries []AuditEntry const pageSize int64 = 1000
for _, row := range rows { offset := int64(0)
if row.CreatedAt.After(since) { entries := make([]AuditEntry, 0, pageSize)
for {
rows, err := d.queries.ListAuditEntriesGlobalSincePaged(ctx, memsqlc.ListAuditEntriesGlobalSincePagedParams{
Since: cutoff,
Lim: pageSize,
Off: offset,
})
if err != nil {
return nil, fmt.Errorf("list audit entries since: %w", err)
}
if len(rows) == 0 {
break
}
for _, row := range rows {
lowerAction := strings.ToLower(strings.TrimSpace(row.Action))
toolName := strings.TrimSpace(row.Action)
if strings.HasPrefix(lowerAction, "tool_") && strings.TrimSpace(row.Target) != "" {
toolName = strings.TrimSpace(row.Target)
}
if toolName == "" {
toolName = strings.TrimSpace(row.Target)
}
success := true
if lowerAction == "tool_error" || strings.Contains(lowerAction, "error") || strings.Contains(lowerAction, "fail") {
success = false
}
entry := AuditEntry{ entry := AuditEntry{
ID: row.ID.String(), ID: row.ID.String(),
Timestamp: row.CreatedAt, Timestamp: row.CreatedAt,
ToolName: row.Action, // Using action as tool name proxy ToolName: toolName,
ToolInput: "", ToolInput: "",
Success: true, // Default to success Success: success,
SessionID: row.SessionKey, SessionID: row.SessionKey,
AgentID: row.AgentID, AgentID: row.AgentID,
} }
if row.Input != nil { if row.Input != nil {
entry.ToolInput = *row.Input entry.ToolInput = *row.Input
} }
if !success && row.Output != nil {
entry.ErrorMsg = *row.Output
}
entries = append(entries, entry) entries = append(entries, entry)
} }
if len(rows) < int(pageSize) {
break
}
offset += int64(len(rows))
} }
return entries, nil return entries, nil
} }
@ -1258,10 +1295,31 @@ func (d *LibSQLDelegate) StoreDetectedPattern(ctx context.Context, pattern Detec
// GetHighTokenSessions returns sessions with token usage above threshold. // GetHighTokenSessions returns sessions with token usage above threshold.
// Implements cortex.AuditAnalysisStore interface. // Implements cortex.AuditAnalysisStore interface.
// Note: This is a placeholder - actual token tracking needs to be implemented.
func (d *LibSQLDelegate) GetHighTokenSessions(ctx context.Context, minTokens int64) ([]SessionSummary, error) { func (d *LibSQLDelegate) GetHighTokenSessions(ctx context.Context, minTokens int64) ([]SessionSummary, error) {
// TODO: Implement token-based session filtering when token tracking is available min := minTokens
return []SessionSummary{}, nil rows, err := d.queries.GetHighTokenSessions(ctx, memsqlc.GetHighTokenSessionsParams{
MinTokens: &min,
Lim: 100,
})
if err != nil {
return nil, fmt.Errorf("get high token sessions: %w", err)
}
summaries := make([]SessionSummary, 0, len(rows))
for _, row := range rows {
totalTokens := int64(0)
if row.TotalTokens != nil {
totalTokens = int64(*row.TotalTokens)
}
summaries = append(summaries, SessionSummary{
SessionID: row.SessionID.String(),
AgentID: row.AgentID,
TotalTokens: totalTokens,
ToolCounts: map[string]int{},
})
}
return summaries, nil
} }
// --- Batch Operations for Cortex Tasks (via sqlc) --- // --- Batch Operations for Cortex Tasks (via sqlc) ---

View file

@ -80,9 +80,17 @@ VALUES (
?6, ?6,
?7, ?7,
?8, ?8,
datetime('now') strftime('%Y-%m-%dT%H:%M:%fZ', 'now')
) )
RETURNING id, agent_id, session_key, action, target, input, output, duration_ms, created_at RETURNING id,
agent_id,
session_key,
action,
target,
input,
output,
duration_ms,
created_at
` `
type InsertAuditEntryParams struct { type InsertAuditEntryParams struct {
@ -118,9 +126,17 @@ type InsertAuditEntryParams struct {
// ?6, // ?6,
// ?7, // ?7,
// ?8, // ?8,
// datetime('now') // strftime('%Y-%m-%dT%H:%M:%fZ', 'now')
// ) // )
// RETURNING id, agent_id, session_key, action, target, input, output, duration_ms, created_at // RETURNING id,
// agent_id,
// session_key,
// action,
// target,
// input,
// output,
// duration_ms,
// created_at
func (q *Queries) InsertAuditEntry(ctx context.Context, arg InsertAuditEntryParams) (AgentAuditLog, error) { func (q *Queries) InsertAuditEntry(ctx context.Context, arg InsertAuditEntryParams) (AgentAuditLog, error) {
row := q.db.QueryRowContext(ctx, InsertAuditEntry, row := q.db.QueryRowContext(ctx, InsertAuditEntry,
arg.ID, arg.ID,
@ -360,6 +376,142 @@ func (q *Queries) ListAuditEntriesBySession(ctx context.Context, arg ListAuditEn
return items, nil return items, nil
} }
const ListAuditEntriesGlobal = `-- name: ListAuditEntriesGlobal :many
SELECT id,
agent_id,
session_key,
action,
target,
input,
output,
duration_ms,
created_at
FROM agent_audit_log
ORDER BY created_at DESC
LIMIT ?1
`
type ListAuditEntriesGlobalParams struct {
Lim int64 `db:"lim" json:"lim"`
}
// ListAuditEntriesGlobal
//
// SELECT id,
// agent_id,
// session_key,
// action,
// target,
// input,
// output,
// duration_ms,
// created_at
// FROM agent_audit_log
// ORDER BY created_at DESC
// LIMIT ?1
func (q *Queries) ListAuditEntriesGlobal(ctx context.Context, arg ListAuditEntriesGlobalParams) ([]AgentAuditLog, error) {
rows, err := q.db.QueryContext(ctx, ListAuditEntriesGlobal, arg.Lim)
if err != nil {
return nil, err
}
defer rows.Close()
items := []AgentAuditLog{}
for rows.Next() {
var i AgentAuditLog
if err := rows.Scan(
&i.ID,
&i.AgentID,
&i.SessionKey,
&i.Action,
&i.Target,
&i.Input,
&i.Output,
&i.DurationMs,
&i.CreatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const ListAuditEntriesGlobalSincePaged = `-- name: ListAuditEntriesGlobalSincePaged :many
SELECT id,
agent_id,
session_key,
action,
target,
input,
output,
duration_ms,
created_at
FROM agent_audit_log
WHERE julianday(created_at) > julianday(?1)
ORDER BY created_at ASC, id ASC
LIMIT ?3 OFFSET ?2
`
type ListAuditEntriesGlobalSincePagedParams struct {
Since interface{} `db:"since" json:"since"`
Off int64 `db:"off" json:"off"`
Lim int64 `db:"lim" json:"lim"`
}
// ListAuditEntriesGlobalSincePaged
//
// SELECT id,
// agent_id,
// session_key,
// action,
// target,
// input,
// output,
// duration_ms,
// created_at
// FROM agent_audit_log
// WHERE julianday(created_at) > julianday(?1)
// ORDER BY created_at ASC, id ASC
// LIMIT ?3 OFFSET ?2
func (q *Queries) ListAuditEntriesGlobalSincePaged(ctx context.Context, arg ListAuditEntriesGlobalSincePagedParams) ([]AgentAuditLog, error) {
rows, err := q.db.QueryContext(ctx, ListAuditEntriesGlobalSincePaged, arg.Since, arg.Off, arg.Lim)
if err != nil {
return nil, err
}
defer rows.Close()
items := []AgentAuditLog{}
for rows.Next() {
var i AgentAuditLog
if err := rows.Scan(
&i.ID,
&i.AgentID,
&i.SessionKey,
&i.Action,
&i.Target,
&i.Input,
&i.Output,
&i.DurationMs,
&i.CreatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const PruneOldAuditEntries = `-- name: PruneOldAuditEntries :exec const PruneOldAuditEntries = `-- name: PruneOldAuditEntries :exec
DELETE FROM agent_audit_log DELETE FROM agent_audit_log
WHERE agent_id = ?1 WHERE agent_id = ?1

View file

@ -509,13 +509,12 @@ type Querier interface {
// SELECT // SELECT
// conversation_id as session_id, // conversation_id as session_id,
// agent_id, // agent_id,
// SUM(tokens_used) as total_tokens, // SUM(COALESCE(tokens_used, 0)) as total_tokens,
// COUNT(*) as task_count // COUNT(*) as task_count
// FROM task_completions // FROM task_completions
// WHERE tokens_used > ?1 // WHERE created_at > strftime('%Y-%m-%dT%H:%M:%fZ', 'now', '-24 hours')
// AND created_at > datetime('now', '-24 hours')
// GROUP BY conversation_id, agent_id // GROUP BY conversation_id, agent_id
// HAVING total_tokens > ?1 // HAVING SUM(COALESCE(tokens_used, 0)) > ?1
// ORDER BY total_tokens DESC // ORDER BY total_tokens DESC
// LIMIT ?2 // LIMIT ?2
GetHighTokenSessions(ctx context.Context, arg GetHighTokenSessionsParams) ([]GetHighTokenSessionsRow, error) GetHighTokenSessions(ctx context.Context, arg GetHighTokenSessionsParams) ([]GetHighTokenSessionsRow, error)
@ -661,6 +660,25 @@ type Querier interface {
// AND suppressed_at IS NULL // AND suppressed_at IS NULL
// LIMIT 1 // LIMIT 1
GetRecallItem(ctx context.Context, arg GetRecallItemParams) (GetRecallItemRow, error) GetRecallItem(ctx context.Context, arg GetRecallItemParams) (GetRecallItemRow, error)
//GetRecallItemByID
//
// SELECT id,
// agent_id,
// session_key,
// role,
// sector,
// importance,
// salience,
// decay_rate,
// content,
// tags,
// created_at,
// updated_at
// FROM recall_items
// WHERE id = ?1
// AND suppressed_at IS NULL
// LIMIT 1
GetRecallItemByID(ctx context.Context, arg GetRecallItemByIDParams) (GetRecallItemByIDRow, error)
//GetRecallItemsByIDs //GetRecallItemsByIDs
// //
// SELECT id, // SELECT id,
@ -788,9 +806,17 @@ type Querier interface {
// ?6, // ?6,
// ?7, // ?7,
// ?8, // ?8,
// datetime('now') // strftime('%Y-%m-%dT%H:%M:%fZ', 'now')
// ) // )
// RETURNING id, agent_id, session_key, action, target, input, output, duration_ms, created_at // RETURNING id,
// agent_id,
// session_key,
// action,
// target,
// input,
// output,
// duration_ms,
// created_at
InsertAuditEntry(ctx context.Context, arg InsertAuditEntryParams) (AgentAuditLog, error) InsertAuditEntry(ctx context.Context, arg InsertAuditEntryParams) (AgentAuditLog, error)
//InsertDAGEdge //InsertDAGEdge
// //
@ -1355,6 +1381,37 @@ type Querier interface {
// ORDER BY created_at DESC // ORDER BY created_at DESC
// LIMIT ?3 // LIMIT ?3
ListAuditEntriesBySession(ctx context.Context, arg ListAuditEntriesBySessionParams) ([]AgentAuditLog, error) ListAuditEntriesBySession(ctx context.Context, arg ListAuditEntriesBySessionParams) ([]AgentAuditLog, error)
//ListAuditEntriesGlobal
//
// SELECT id,
// agent_id,
// session_key,
// action,
// target,
// input,
// output,
// duration_ms,
// created_at
// FROM agent_audit_log
// ORDER BY created_at DESC
// LIMIT ?1
ListAuditEntriesGlobal(ctx context.Context, arg ListAuditEntriesGlobalParams) ([]AgentAuditLog, error)
//ListAuditEntriesGlobalSincePaged
//
// SELECT id,
// agent_id,
// session_key,
// action,
// target,
// input,
// output,
// duration_ms,
// created_at
// FROM agent_audit_log
// WHERE julianday(created_at) > julianday(?1)
// ORDER BY created_at ASC, id ASC
// LIMIT ?3 OFFSET ?2
ListAuditEntriesGlobalSincePaged(ctx context.Context, arg ListAuditEntriesGlobalSincePagedParams) ([]AgentAuditLog, error)
//ListDAGEdgesBySnapshotID //ListDAGEdgesBySnapshotID
// //
// SELECT id, // SELECT id,

View file

@ -20,9 +20,17 @@ VALUES (
sqlc.arg(input), sqlc.arg(input),
sqlc.arg(output), sqlc.arg(output),
sqlc.arg(duration_ms), sqlc.arg(duration_ms),
datetime('now') strftime('%Y-%m-%dT%H:%M:%fZ', 'now')
) )
RETURNING id, agent_id, session_key, action, target, input, output, duration_ms, created_at; RETURNING id,
agent_id,
session_key,
action,
target,
input,
output,
duration_ms,
created_at;
-- name: ListAuditEntries :many -- name: ListAuditEntries :many
SELECT id, SELECT id,
agent_id, agent_id,
@ -37,6 +45,34 @@ FROM agent_audit_log
WHERE agent_id = sqlc.arg(agent_id) WHERE agent_id = sqlc.arg(agent_id)
ORDER BY created_at DESC ORDER BY created_at DESC
LIMIT sqlc.arg(lim); LIMIT sqlc.arg(lim);
-- name: ListAuditEntriesGlobal :many
SELECT id,
agent_id,
session_key,
action,
target,
input,
output,
duration_ms,
created_at
FROM agent_audit_log
ORDER BY created_at DESC
LIMIT sqlc.arg(lim);
-- name: ListAuditEntriesGlobalSincePaged :many
SELECT id,
agent_id,
session_key,
action,
target,
input,
output,
duration_ms,
created_at
FROM agent_audit_log
WHERE julianday(created_at) > julianday(sqlc.arg(since))
ORDER BY created_at ASC,
id ASC
LIMIT sqlc.arg(lim) OFFSET sqlc.arg(off);
-- name: ListAuditEntriesByAction :many -- name: ListAuditEntriesByAction :many
SELECT id, SELECT id,
agent_id, agent_id,

View file

@ -61,6 +61,23 @@ WHERE id = sqlc.arg(id)
AND agent_id = sqlc.arg(agent_id) AND agent_id = sqlc.arg(agent_id)
AND suppressed_at IS NULL AND suppressed_at IS NULL
LIMIT 1; LIMIT 1;
-- name: GetRecallItemByID :one
SELECT id,
agent_id,
session_key,
role,
sector,
importance,
salience,
decay_rate,
content,
tags,
created_at,
updated_at
FROM recall_items
WHERE id = sqlc.arg(id)
AND suppressed_at IS NULL
LIMIT 1;
-- name: UpdateRecallItem :exec -- name: UpdateRecallItem :exec
UPDATE recall_items UPDATE recall_items
SET role = sqlc.arg(role), SET role = sqlc.arg(role),

View file

@ -1,6 +1,5 @@
-- RL (Reinforcement Learning) queries for Memelord integration -- RL (Reinforcement Learning) queries for Memelord integration
-- Task baseline queries for per-agent performance statistics -- Task baseline queries for per-agent performance statistics
-- name: GetTaskBaseline :one -- name: GetTaskBaseline :one
-- Get the baseline statistics for an agent -- Get the baseline statistics for an agent
SELECT agent_id, SELECT agent_id,
@ -15,7 +14,6 @@ SELECT agent_id,
FROM task_baselines FROM task_baselines
WHERE agent_id = sqlc.arg(agent_id) WHERE agent_id = sqlc.arg(agent_id)
LIMIT 1; LIMIT 1;
-- name: UpdateTaskBaseline :exec -- name: UpdateTaskBaseline :exec
-- Insert or replace task baseline statistics for an agent -- Insert or replace task baseline statistics for an agent
INSERT INTO task_baselines ( INSERT INTO task_baselines (
@ -39,8 +37,7 @@ VALUES (
sqlc.arg(m2_errors), sqlc.arg(m2_errors),
sqlc.arg(m2_user_corrections), sqlc.arg(m2_user_corrections),
datetime('now') datetime('now')
) ) ON CONFLICT (agent_id) DO
ON CONFLICT (agent_id) DO
UPDATE UPDATE
SET count = excluded.count, SET count = excluded.count,
mean_tokens = excluded.mean_tokens, mean_tokens = excluded.mean_tokens,
@ -50,7 +47,6 @@ SET count = excluded.count,
m2_errors = excluded.m2_errors, m2_errors = excluded.m2_errors,
m2_user_corrections = excluded.m2_user_corrections, m2_user_corrections = excluded.m2_user_corrections,
updated_at = excluded.updated_at; updated_at = excluded.updated_at;
-- name: UpdateMemoryWeight :exec -- name: UpdateMemoryWeight :exec
-- Update the RL weight and credit for a specific memory item -- Update the RL weight and credit for a specific memory item
UPDATE recall_items UPDATE recall_items
@ -59,7 +55,6 @@ SET rl_weight = sqlc.arg(rl_weight),
updated_at = datetime('now') updated_at = datetime('now')
WHERE id = sqlc.arg(id) WHERE id = sqlc.arg(id)
AND agent_id = sqlc.arg(agent_id); AND agent_id = sqlc.arg(agent_id);
-- name: UpdateMemorySelfReportScore :exec -- name: UpdateMemorySelfReportScore :exec
-- Update the self-reported score for a memory item -- Update the self-reported score for a memory item
UPDATE recall_items UPDATE recall_items
@ -67,7 +62,6 @@ SET self_report_score = sqlc.arg(self_report_score),
updated_at = datetime('now') updated_at = datetime('now')
WHERE id = sqlc.arg(id) WHERE id = sqlc.arg(id)
AND agent_id = sqlc.arg(agent_id); AND agent_id = sqlc.arg(agent_id);
-- name: IncrementTaskRetrievalCount :exec -- name: IncrementTaskRetrievalCount :exec
-- Increment the task retrieval counter for a memory item -- Increment the task retrieval counter for a memory item
UPDATE recall_items UPDATE recall_items
@ -75,7 +69,6 @@ SET task_retrieval_count = task_retrieval_count + 1,
updated_at = datetime('now') updated_at = datetime('now')
WHERE id = sqlc.arg(id) WHERE id = sqlc.arg(id)
AND agent_id = sqlc.arg(agent_id); AND agent_id = sqlc.arg(agent_id);
-- name: GetMemoriesByRetrievalCount :many -- name: GetMemoriesByRetrievalCount :many
-- Get memories ordered by their task retrieval count (for RL analysis) -- Get memories ordered by their task retrieval count (for RL analysis)
SELECT id, SELECT id,
@ -99,7 +92,6 @@ WHERE agent_id = sqlc.arg(agent_id)
AND suppressed_at IS NULL AND suppressed_at IS NULL
ORDER BY task_retrieval_count DESC ORDER BY task_retrieval_count DESC
LIMIT sqlc.arg(lim); LIMIT sqlc.arg(lim);
-- name: ListHighValueMemories :many -- name: ListHighValueMemories :many
-- List memories with high RL weights (credits) for priority retention -- List memories with high RL weights (credits) for priority retention
SELECT id, SELECT id,
@ -127,7 +119,6 @@ WHERE agent_id = sqlc.arg(agent_id)
) )
ORDER BY rl_credit DESC NULLS LAST ORDER BY rl_credit DESC NULLS LAST
LIMIT sqlc.arg(lim); LIMIT sqlc.arg(lim);
-- name: StoreTaskCompletion :one -- name: StoreTaskCompletion :one
-- Store a task completion record for RL analysis -- Store a task completion record for RL analysis
INSERT INTO task_completions ( INSERT INTO task_completions (
@ -165,7 +156,6 @@ RETURNING id,
user_corrections, user_corrections,
completed, completed,
created_at; created_at;
-- name: GetCompletedTasks :many -- name: GetCompletedTasks :many
-- Get tasks completed since the given time for RL processing -- Get tasks completed since the given time for RL processing
SELECT id, SELECT id,
@ -184,14 +174,17 @@ WHERE agent_id = sqlc.arg(agent_id)
AND created_at > sqlc.arg(since) AND created_at > sqlc.arg(since)
AND completed = 1 AND completed = 1
ORDER BY created_at ASC; ORDER BY created_at ASC;
-- name: StoreTaskRetrieval :exec -- name: StoreTaskRetrieval :exec
-- Store a memory retrieval record for a task -- Store a memory retrieval record for a task
INSERT INTO task_retrievals (id, task_id, memory_id, similarity) INSERT INTO task_retrievals (id, task_id, memory_id, similarity)
VALUES (sqlc.arg(id), sqlc.arg(task_id), sqlc.arg(memory_id), sqlc.arg(similarity)) VALUES (
ON CONFLICT (task_id, memory_id) DO UPDATE SET sqlc.arg(id),
similarity = excluded.similarity; sqlc.arg(task_id),
sqlc.arg(memory_id),
sqlc.arg(similarity)
) ON CONFLICT (task_id, memory_id) DO
UPDATE
SET similarity = excluded.similarity;
-- name: GetRetrievedMemories :many -- name: GetRetrievedMemories :many
-- Get memories retrieved during a specific task with their self-report scores -- Get memories retrieved during a specific task with their self-report scores
SELECT tr.memory_id, SELECT tr.memory_id,
@ -200,25 +193,22 @@ SELECT tr.memory_id,
FROM task_retrievals tr FROM task_retrievals tr
JOIN recall_items ri ON tr.memory_id = ri.id JOIN recall_items ri ON tr.memory_id = ri.id
WHERE tr.task_id = sqlc.arg(task_id); WHERE tr.task_id = sqlc.arg(task_id);
-- name: ListActiveAgents :many -- name: ListActiveAgents :many
-- Get all unique agent IDs that have completed tasks (for multi-agent processing) -- Get all unique agent IDs that have completed tasks (for multi-agent processing)
SELECT DISTINCT agent_id SELECT DISTINCT agent_id
FROM task_completions FROM task_completions
WHERE created_at > sqlc.arg(since) WHERE created_at > sqlc.arg(since)
ORDER BY agent_id; ORDER BY agent_id;
-- name: GetHighTokenSessions :many -- name: GetHighTokenSessions :many
-- Get sessions with high token usage grouped by conversation/agent -- Get sessions with high token usage grouped by conversation/agent
SELECT SELECT conversation_id as session_id,
conversation_id as session_id,
agent_id, agent_id,
SUM(tokens_used) as total_tokens, SUM(COALESCE(tokens_used, 0)) as total_tokens,
COUNT(*) as task_count COUNT(*) as task_count
FROM task_completions FROM task_completions
WHERE tokens_used > sqlc.arg(min_tokens) WHERE created_at > strftime('%Y-%m-%dT%H:%M:%fZ', 'now', '-24 hours')
AND created_at > datetime('now', '-24 hours') GROUP BY conversation_id,
GROUP BY conversation_id, agent_id agent_id
HAVING total_tokens > sqlc.arg(min_tokens) HAVING SUM(COALESCE(tokens_used, 0)) > sqlc.arg(min_tokens)
ORDER BY total_tokens DESC ORDER BY total_tokens DESC
LIMIT sqlc.arg(lim); LIMIT sqlc.arg(lim);

View file

@ -174,6 +174,82 @@ func (q *Queries) GetRecallItem(ctx context.Context, arg GetRecallItemParams) (G
return i, err return i, err
} }
const GetRecallItemByID = `-- name: GetRecallItemByID :one
SELECT id,
agent_id,
session_key,
role,
sector,
importance,
salience,
decay_rate,
content,
tags,
created_at,
updated_at
FROM recall_items
WHERE id = ?1
AND suppressed_at IS NULL
LIMIT 1
`
type GetRecallItemByIDParams struct {
ID ids.UUID `db:"id" json:"id"`
}
type GetRecallItemByIDRow struct {
ID ids.UUID `db:"id" json:"id"`
AgentID string `db:"agent_id" json:"agent_id"`
SessionKey string `db:"session_key" json:"session_key"`
Role string `db:"role" json:"role"`
Sector memory.Sector `db:"sector" json:"sector"`
Importance float64 `db:"importance" json:"importance"`
Salience float64 `db:"salience" json:"salience"`
DecayRate float64 `db:"decay_rate" json:"decay_rate"`
Content string `db:"content" json:"content"`
Tags string `db:"tags" json:"tags"`
CreatedAt time.Time `db:"created_at" json:"created_at"`
UpdatedAt time.Time `db:"updated_at" json:"updated_at"`
}
// GetRecallItemByID
//
// SELECT id,
// agent_id,
// session_key,
// role,
// sector,
// importance,
// salience,
// decay_rate,
// content,
// tags,
// created_at,
// updated_at
// FROM recall_items
// WHERE id = ?1
// AND suppressed_at IS NULL
// LIMIT 1
func (q *Queries) GetRecallItemByID(ctx context.Context, arg GetRecallItemByIDParams) (GetRecallItemByIDRow, error) {
row := q.db.QueryRowContext(ctx, GetRecallItemByID, arg.ID)
var i GetRecallItemByIDRow
err := row.Scan(
&i.ID,
&i.AgentID,
&i.SessionKey,
&i.Role,
&i.Sector,
&i.Importance,
&i.Salience,
&i.DecayRate,
&i.Content,
&i.Tags,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const GetRecallItemsByIDs = `-- name: GetRecallItemsByIDs :many const GetRecallItemsByIDs = `-- name: GetRecallItemsByIDs :many
SELECT id, SELECT id,
agent_id, agent_id,

View file

@ -94,13 +94,12 @@ const GetHighTokenSessions = `-- name: GetHighTokenSessions :many
SELECT SELECT
conversation_id as session_id, conversation_id as session_id,
agent_id, agent_id,
SUM(tokens_used) as total_tokens, SUM(COALESCE(tokens_used, 0)) as total_tokens,
COUNT(*) as task_count COUNT(*) as task_count
FROM task_completions FROM task_completions
WHERE tokens_used > ?1 WHERE created_at > strftime('%Y-%m-%dT%H:%M:%fZ', 'now', '-24 hours')
AND created_at > datetime('now', '-24 hours')
GROUP BY conversation_id, agent_id GROUP BY conversation_id, agent_id
HAVING total_tokens > ?1 HAVING SUM(COALESCE(tokens_used, 0)) > ?1
ORDER BY total_tokens DESC ORDER BY total_tokens DESC
LIMIT ?2 LIMIT ?2
` `
@ -122,13 +121,12 @@ type GetHighTokenSessionsRow struct {
// SELECT // SELECT
// conversation_id as session_id, // conversation_id as session_id,
// agent_id, // agent_id,
// SUM(tokens_used) as total_tokens, // SUM(COALESCE(tokens_used, 0)) as total_tokens,
// COUNT(*) as task_count // COUNT(*) as task_count
// FROM task_completions // FROM task_completions
// WHERE tokens_used > ?1 // WHERE created_at > strftime('%Y-%m-%dT%H:%M:%fZ', 'now', '-24 hours')
// AND created_at > datetime('now', '-24 hours')
// GROUP BY conversation_id, agent_id // GROUP BY conversation_id, agent_id
// HAVING total_tokens > ?1 // HAVING SUM(COALESCE(tokens_used, 0)) > ?1
// ORDER BY total_tokens DESC // ORDER BY total_tokens DESC
// LIMIT ?2 // LIMIT ?2
func (q *Queries) GetHighTokenSessions(ctx context.Context, arg GetHighTokenSessionsParams) ([]GetHighTokenSessionsRow, error) { func (q *Queries) GetHighTokenSessions(ctx context.Context, arg GetHighTokenSessionsParams) ([]GetHighTokenSessionsRow, error) {