mirror of
https://github.com/tiennm99/goclaw.git
synced 2026-07-27 02:19:35 +00:00
- Add enrich_auto_linking.go: deterministic auto-link logic for task/delegation contexts - Add team_task_siblings.go (PG + SQLite): find all tasks in same delegation for batch link - Update enrich_worker.go: call enrich_auto_linking Phase 2 hook + skip re-embed for binary - Update team_store.go: add TaskSiblings interface method + TeamStore binding - Add context_keys.go + test: define ContextDelegationIDKey + ContextTaskIDKey for propagation - Update vault_interceptor.go: extract + inject delegation ID from request - Update run_context.go: propagate DelegationID from request - Update loop_context.go: inject DelegationID from run context - Update teams_tasks.go: DeleteTask(s) → cleanup auto-links via vault_source_cleanup - Update teams_tasks_activity.go: DetachFileFromTask → cleanup related auto-links - Update vault_documents_enrichment.go: populate summary from media_summary - Update cmd/gateway.go: wire TeamStore to handler bootstrap
120 lines
2.9 KiB
Go
120 lines
2.9 KiB
Go
//go:build sqlite || sqliteonly
|
|
|
|
package sqlitestore
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/google/uuid"
|
|
"github.com/nextlevelbuilder/goclaw/internal/store"
|
|
)
|
|
|
|
// BatchGetTaskSiblingsByBasenames — SQLite mirror of the PG implementation.
|
|
// Uses dynamic `?,?,?` placeholders (no array type in sqlite) and the same
|
|
// PARTITION BY (source_base, task_id) cap semantics.
|
|
func (s *SQLiteTeamStore) BatchGetTaskSiblingsByBasenames(
|
|
ctx context.Context,
|
|
tenantID uuid.UUID,
|
|
basenames []string,
|
|
limit int,
|
|
) (map[string][]store.TaskSibling, error) {
|
|
if len(basenames) == 0 {
|
|
return nil, nil
|
|
}
|
|
if limit <= 0 {
|
|
limit = 9
|
|
}
|
|
|
|
// Lowercase + dedup defensively.
|
|
seen := make(map[string]bool, len(basenames))
|
|
clean := make([]string, 0, len(basenames))
|
|
for _, b := range basenames {
|
|
lb := strings.ToLower(b)
|
|
if lb == "" || seen[lb] {
|
|
continue
|
|
}
|
|
seen[lb] = true
|
|
clean = append(clean, lb)
|
|
}
|
|
|
|
out := make(map[string][]store.TaskSibling, len(clean))
|
|
const chunkSize = 500
|
|
|
|
for start := 0; start < len(clean); start += chunkSize {
|
|
end := start + chunkSize
|
|
if end > len(clean) {
|
|
end = len(clean)
|
|
}
|
|
chunk := clean[start:end]
|
|
|
|
ph := make([]string, len(chunk))
|
|
args := []any{tenantID.String()}
|
|
for i, b := range chunk {
|
|
ph[i] = "?"
|
|
args = append(args, b)
|
|
}
|
|
args = append(args, limit)
|
|
|
|
q := fmt.Sprintf(`
|
|
WITH target_tasks AS (
|
|
SELECT DISTINCT tta.base_name AS source_base, tta.task_id
|
|
FROM team_task_attachments tta
|
|
WHERE tta.tenant_id = ? AND tta.base_name IN (%s)
|
|
),
|
|
ranked AS (
|
|
SELECT
|
|
tt.source_base,
|
|
tta2.task_id,
|
|
vd.id AS doc_id,
|
|
tta2.base_name,
|
|
tta2.created_at,
|
|
ROW_NUMBER() OVER (
|
|
PARTITION BY tt.source_base, tta2.task_id
|
|
ORDER BY tta2.created_at DESC, vd.id DESC
|
|
) AS rn
|
|
FROM target_tasks tt
|
|
JOIN team_task_attachments tta2 ON tta2.task_id = tt.task_id
|
|
JOIN vault_documents vd
|
|
ON vd.tenant_id = tta2.tenant_id
|
|
AND vd.team_id = tta2.team_id
|
|
AND vd.path_basename = tta2.base_name
|
|
WHERE tta2.base_name != tt.source_base
|
|
)
|
|
SELECT source_base, task_id, doc_id, base_name, created_at
|
|
FROM ranked
|
|
WHERE rn <= ?
|
|
ORDER BY source_base, task_id, created_at DESC
|
|
`, strings.Join(ph, ","))
|
|
|
|
rows, err := s.db.QueryContext(ctx, q, args...)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("batch task siblings: %w", err)
|
|
}
|
|
for rows.Next() {
|
|
var sourceBase string
|
|
var taskIDStr, docIDStr string
|
|
var sib store.TaskSibling
|
|
ca := &sqliteTime{}
|
|
if err := rows.Scan(&sourceBase, &taskIDStr, &docIDStr, &sib.BaseName, ca); err != nil {
|
|
rows.Close()
|
|
return nil, err
|
|
}
|
|
if tid, perr := uuid.Parse(taskIDStr); perr == nil {
|
|
sib.TaskID = tid
|
|
}
|
|
if did, perr := uuid.Parse(docIDStr); perr == nil {
|
|
sib.DocID = did
|
|
}
|
|
sib.AttachmentTime = ca.Time
|
|
out[sourceBase] = append(out[sourceBase], sib)
|
|
}
|
|
rows.Close()
|
|
if err := rows.Err(); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
return out, nil
|
|
}
|