Changeset 0.28.0.8 (#180)

This commit is contained in:
2026-03-12 22:49:35 +00:00
parent f3f5afd14c
commit aa870f1040
14 changed files with 679 additions and 116 deletions

View File

@@ -117,8 +117,14 @@ func (e *Extractor) Extract(ctx context.Context, channelID, userID, teamID, pers
prompt := defaultExtractionPrompt
if personaID != "" && e.stores.Personas != nil {
persona, err := e.stores.Personas.GetByID(ctx, personaID)
if err == nil && persona.MemoryExtractionPrompt != nil && *persona.MemoryExtractionPrompt != "" {
prompt = *persona.MemoryExtractionPrompt
if err == nil {
// Respect persona memory_enabled flag (H6 — audit v0.28.0)
if !persona.MemoryEnabled {
return nil
}
if persona.MemoryExtractionPrompt != nil && *persona.MemoryExtractionPrompt != "" {
prompt = *persona.MemoryExtractionPrompt
}
}
}

View File

@@ -76,21 +76,23 @@ type candidate struct {
ChannelID string
UserID string
TeamID string
PersonaID string // non-empty if a persona is active on the channel
}
func (s *Scanner) scan() {
ctx := context.Background()
// Check global kill switch
// Check global kill switch.
// Default: ENABLED. Only disable if the key exists and is explicitly false.
// This inverts the previous behavior where a missing key blocked all extraction.
if s.stores.GlobalConfig != nil {
val, err := s.stores.GlobalConfig.Get(ctx, "memory_extraction_enabled")
if err != nil || val == nil {
return // disabled or not configured
}
// val is a map; check the "value" key
if enabled, ok := val["value"].(bool); !ok || !enabled {
return
if err == nil && val != nil {
if enabled, ok := val["value"].(bool); ok && !enabled {
return // explicitly disabled
}
}
// If key is missing (err != nil or val == nil), extraction is enabled.
}
candidates, err := s.findCandidates(ctx)
@@ -124,7 +126,7 @@ func (s *Scanner) scan() {
extractCtx, cancel := context.WithTimeout(ctx, 2*time.Minute)
defer cancel()
if err := s.extractor.Extract(extractCtx, cand.ChannelID, cand.UserID, cand.TeamID, ""); err != nil {
if err := s.extractor.Extract(extractCtx, cand.ChannelID, cand.UserID, cand.TeamID, cand.PersonaID); err != nil {
log.Printf("⚠ memory extraction failed: channel=%s user=%s: %v",
cand.ChannelID, cand.UserID, err)
}
@@ -135,6 +137,12 @@ func (s *Scanner) scan() {
}
// findCandidates queries for channels with enough new activity since last extraction.
//
// Fixes from v0.28.0 audit:
// - Uses channels.user_id (was: non-existent created_by)
// - Uses channels.team_id directly (was: JOIN to non-existent channel_users table)
// - JOINs channel_participants + personas to check memory_enabled (H6)
// - Filters out channels whose active persona has memory_enabled=false
func (s *Scanner) findCandidates(ctx context.Context) ([]candidate, error) {
db := database.DB
if db == nil {
@@ -144,11 +152,17 @@ func (s *Scanner) findCandidates(ctx context.Context) ([]candidate, error) {
var query string
if database.IsSQLite() {
query = `
SELECT c.id, c.created_by, COALESCE(cu.team_id, '')
SELECT c.id, c.user_id, COALESCE(c.team_id, ''),
COALESCE(cp.participant_id, '')
FROM channels c
LEFT JOIN channel_users cu ON cu.channel_id = c.id AND cu.user_id = c.created_by
LEFT JOIN memory_extraction_log mel ON mel.channel_id = c.id AND mel.user_id = c.created_by
WHERE c.created_by IS NOT NULL
LEFT JOIN channel_participants cp
ON cp.channel_id = c.id AND cp.participant_type = 'persona'
LEFT JOIN personas p
ON p.id = cp.participant_id
LEFT JOIN memory_extraction_log mel
ON mel.channel_id = c.id AND mel.user_id = c.user_id
WHERE c.user_id IS NOT NULL
AND (cp.id IS NULL OR p.memory_enabled = 1)
AND (
SELECT COUNT(*) FROM messages m
WHERE m.channel_id = c.id
@@ -161,11 +175,17 @@ func (s *Scanner) findCandidates(ctx context.Context) ([]candidate, error) {
`
} else {
query = `
SELECT c.id, c.created_by, COALESCE(cu.team_id, '')
SELECT c.id, c.user_id, COALESCE(c.team_id::text, ''),
COALESCE(cp.participant_id::text, '')
FROM channels c
LEFT JOIN channel_users cu ON cu.channel_id = c.id AND cu.user_id = c.created_by
LEFT JOIN memory_extraction_log mel ON mel.channel_id = c.id AND mel.user_id = c.created_by
WHERE c.created_by IS NOT NULL
LEFT JOIN channel_participants cp
ON cp.channel_id = c.id AND cp.participant_type = 'persona'
LEFT JOIN personas p
ON p.id = cp.participant_id
LEFT JOIN memory_extraction_log mel
ON mel.channel_id = c.id AND mel.user_id = c.user_id
WHERE c.user_id IS NOT NULL
AND (cp.id IS NULL OR p.memory_enabled = true)
AND (
SELECT COUNT(*) FROM messages m
WHERE m.channel_id = c.id
@@ -187,7 +207,7 @@ func (s *Scanner) findCandidates(ctx context.Context) ([]candidate, error) {
var candidates []candidate
for rows.Next() {
var c candidate
if err := rows.Scan(&c.ChannelID, &c.UserID, &c.TeamID); err != nil {
if err := rows.Scan(&c.ChannelID, &c.UserID, &c.TeamID, &c.PersonaID); err != nil {
continue
}
candidates = append(candidates, c)