mirror of
https://github.com/tiennm99/goclaw.git
synced 2026-08-06 10:21:11 +00:00
Five files, targeted CRITICAL-site migrations: - knowledge_graph_temporal.go: SupersedeEntity (line 71 — C1 from red-team, UPDATE + INSERT in transaction). ListEntitiesTemporal remains on mustParseUUID (WARN-acceptable SELECT WHERE). - memory_admin.go: ListAllDocuments, GetDocumentDetail, ListChunks (3 sites, all return errors). Adds fmt import. - memory_search.go: Search (1 site, agent_id resolves hybrid FTS+vector). - knowledge_graph_traversal.go: Traverse (2 sites — agent + startEntity). - vault_documents_enrichment.go: UpdateSummaryAndReembed (2 sites — tenant, doc). FindSimilarDocs was migrated earlier with optAgentUUID wrapper fix. Phase 4 Steps 4b.6, 4b.8, 4b.9, 4b.11, 4b.12 of agent identity hardening. Still pending: - vault_links.go (16 sites — next commit) - knowledge_graph_embedding.go line 124 (SAFE per scout — audit only) - agents_export_queries.go lines 312,354 (SAFE cursor per scout — audit only)
154 lines
4.6 KiB
Go
154 lines
4.6 KiB
Go
package pg
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
"github.com/nextlevelbuilder/goclaw/internal/store"
|
|
)
|
|
|
|
// ListAllDocumentsGlobal returns all documents across all agents (for admin overview).
|
|
func (s *PGMemoryStore) ListAllDocumentsGlobal(ctx context.Context) ([]store.DocumentInfo, error) {
|
|
var whereClause string
|
|
var args []any
|
|
if !store.IsCrossTenant(ctx) {
|
|
tid, err := requireTenantID(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
whereClause = "WHERE tenant_id = $1"
|
|
args = []any{tid}
|
|
}
|
|
|
|
var rows []documentInfoRow
|
|
if err := pkgSqlxDB.SelectContext(ctx, &rows,
|
|
`SELECT agent_id, path, hash, user_id, updated_at
|
|
FROM memory_documents `+whereClause+`
|
|
ORDER BY updated_at DESC`, args...); err != nil {
|
|
return nil, err
|
|
}
|
|
result := make([]store.DocumentInfo, len(rows))
|
|
for i := range rows {
|
|
result[i] = rows[i].toDocumentInfo()
|
|
}
|
|
return result, nil
|
|
}
|
|
|
|
// ListAllDocuments returns all documents for an agent across all users (global + personal).
|
|
func (s *PGMemoryStore) ListAllDocuments(ctx context.Context, agentID string) ([]store.DocumentInfo, error) {
|
|
aid, err := parseUUID(agentID)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("memory list all documents: %w", err)
|
|
}
|
|
tc, tcArgs, _, err := scopeClause(ctx, 2)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var rows []documentInfoRow
|
|
if err := pkgSqlxDB.SelectContext(ctx, &rows,
|
|
`SELECT agent_id, path, hash, user_id, updated_at
|
|
FROM memory_documents WHERE agent_id = $1`+tc+`
|
|
ORDER BY updated_at DESC`, append([]any{aid}, tcArgs...)...); err != nil {
|
|
return nil, err
|
|
}
|
|
result := make([]store.DocumentInfo, len(rows))
|
|
for i := range rows {
|
|
result[i] = rows[i].toDocumentInfo()
|
|
}
|
|
return result, nil
|
|
}
|
|
|
|
// GetDocumentDetail returns full document info with chunk and embedding counts.
|
|
func (s *PGMemoryStore) GetDocumentDetail(ctx context.Context, agentID, userID, path string) (*store.DocumentDetail, error) {
|
|
aid, err := parseUUID(agentID)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("memory get document detail: %w", err)
|
|
}
|
|
|
|
var q string
|
|
var args []any
|
|
if userID == "" {
|
|
tc, tcArgs, _, err := scopeClauseAlias(ctx, 3, "d")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
q = `SELECT d.path, d.content, d.hash, d.user_id, d.created_at, d.updated_at,
|
|
COUNT(c.id) AS chunk_count,
|
|
COUNT(c.embedding) AS embedded_count
|
|
FROM memory_documents d
|
|
LEFT JOIN memory_chunks c ON c.document_id = d.id
|
|
WHERE d.agent_id = $1 AND d.path = $2 AND d.user_id IS NULL` + tc + `
|
|
GROUP BY d.id`
|
|
args = append([]any{aid, path}, tcArgs...)
|
|
} else {
|
|
tc, tcArgs, _, err := scopeClauseAlias(ctx, 4, "d")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
q = `SELECT d.path, d.content, d.hash, d.user_id, d.created_at, d.updated_at,
|
|
COUNT(c.id) AS chunk_count,
|
|
COUNT(c.embedding) AS embedded_count
|
|
FROM memory_documents d
|
|
LEFT JOIN memory_chunks c ON c.document_id = d.id
|
|
WHERE d.agent_id = $1 AND d.path = $2 AND d.user_id = $3` + tc + `
|
|
GROUP BY d.id`
|
|
args = append([]any{aid, path, userID}, tcArgs...)
|
|
}
|
|
|
|
var row documentDetailRow
|
|
if err := pkgSqlxDB.GetContext(ctx, &row, q, args...); err != nil {
|
|
return nil, err
|
|
}
|
|
detail := row.toDocumentDetail()
|
|
return &detail, nil
|
|
}
|
|
|
|
// ListChunks returns chunks for a document identified by agent, user, and path.
|
|
func (s *PGMemoryStore) ListChunks(ctx context.Context, agentID, userID, path string) ([]store.ChunkInfo, error) {
|
|
aid, err := parseUUID(agentID)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("memory list chunks: %w", err)
|
|
}
|
|
|
|
var q string
|
|
var args []any
|
|
if userID == "" {
|
|
tc, tcArgs, _, err := scopeClauseAlias(ctx, 3, "d")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
q = `SELECT c.id, c.start_line, c.end_line,
|
|
c.text AS text_preview,
|
|
(c.embedding IS NOT NULL) AS has_embedding
|
|
FROM memory_chunks c
|
|
JOIN memory_documents d ON c.document_id = d.id
|
|
WHERE d.agent_id = $1 AND d.path = $2 AND d.user_id IS NULL` + tc + `
|
|
ORDER BY c.start_line`
|
|
args = append([]any{aid, path}, tcArgs...)
|
|
} else {
|
|
tc, tcArgs, _, err := scopeClauseAlias(ctx, 4, "d")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
q = `SELECT c.id, c.start_line, c.end_line,
|
|
c.text AS text_preview,
|
|
(c.embedding IS NOT NULL) AS has_embedding
|
|
FROM memory_chunks c
|
|
JOIN memory_documents d ON c.document_id = d.id
|
|
WHERE d.agent_id = $1 AND d.path = $2 AND d.user_id = $3` + tc + `
|
|
ORDER BY c.start_line`
|
|
args = append([]any{aid, path, userID}, tcArgs...)
|
|
}
|
|
|
|
var rows []chunkInfoRow
|
|
if err := pkgSqlxDB.SelectContext(ctx, &rows, q, args...); err != nil {
|
|
return nil, err
|
|
}
|
|
result := make([]store.ChunkInfo, len(rows))
|
|
for i := range rows {
|
|
result[i] = rows[i].toChunkInfo()
|
|
}
|
|
return result, nil
|
|
}
|