56 lines
2.5 KiB
Go
56 lines
2.5 KiB
Go
package callmemory
|
|||
|
|
|
||
|
|
import (
|
||
|
|
"context"
|
||
|
|
|
||
|
|
"github.com/jackc/pgx/v5"
|
||
|
|
)
|
||
|
|
|
||
|
|
// The caller holds memory_user_state before expanding or locking any memory.
|
||
|
|
// Resolve original provenance once: a derived provider summary may cover a
|
||
|
|
// whole call, but deleting it as a consequence must not enlarge the requested
|
||
|
|
// source deletion to unrelated utterances from that call.
|
||
|
|
func expandSourceDeletionTargets(ctx context.Context, tx pgx.Tx, access Access, requested []string) ([]string, error) {
|
||
|
|
rows, err := tx.Query(ctx, `WITH refs AS (
|
||
|
|
SELECT cm.id AS memory_id,r FROM curated_memory cm JOIN memory_version mv ON mv.memory_id=cm.id
|
||
|
|
CROSS JOIN LATERAL jsonb_array_elements(mv.source_refs) r
|
||
|
|
WHERE cm.subject_id=$1::uuid AND cm.tenant_id=$2::uuid AND cm.status<>'DELETED'
|
||
|
|
), origins AS (
|
||
|
|
SELECT memory_id,r->>'session_id' AS session_id,r->>'utterance_id' AS utterance_id,
|
||
|
|
NULL::uuid AS turn_id,r->>'story_id' AS story_id FROM refs
|
||
|
|
UNION ALL
|
||
|
|
SELECT refs.memory_id,ss.call_session_id::text,ss.call_utterance_id,ss.conversation_turn_id,NULL::text
|
||
|
|
FROM refs JOIN story_draft sd ON sd.public_id::text=r->>'story_id' AND sd.subject_id=$1::uuid
|
||
|
|
JOIN story_revision sr ON sr.story_id=sd.id JOIN story_source ss ON ss.story_revision_id=sr.id
|
||
|
|
), requested_origins AS (
|
||
|
|
SELECT o.* FROM origins o JOIN curated_memory cm ON cm.id=o.memory_id
|
||
|
|
WHERE cm.public_id IN(SELECT value::uuid FROM jsonb_array_elements_text($3::jsonb))
|
||
|
|
)
|
||
|
|
SELECT cm.public_id::text,cm.sensitivity FROM curated_memory cm
|
||
|
|
WHERE cm.subject_id=$1::uuid AND cm.tenant_id=$2::uuid AND cm.status<>'DELETED'
|
||
|
|
AND cm.public_id NOT IN(SELECT value::uuid FROM jsonb_array_elements_text($3::jsonb))
|
||
|
|
AND EXISTS(SELECT 1 FROM origins o JOIN requested_origins wanted ON
|
||
|
|
(o.story_id IS NOT NULL AND o.story_id=wanted.story_id) OR
|
||
|
|
(o.turn_id IS NOT NULL AND o.turn_id=wanted.turn_id) OR
|
||
|
|
(o.session_id IS NOT NULL AND o.session_id=wanted.session_id AND
|
||
|
|
(o.utterance_id IS NULL OR wanted.utterance_id IS NULL OR o.utterance_id=wanted.utterance_id))
|
||
|
|
WHERE o.memory_id=cm.id)
|
||
|
|
ORDER BY cm.id FOR UPDATE OF cm`, access.Subject, access.Tenant, jsonBytes(requested))
|
||
|
|
if err != nil {
|
||
|
|
return nil, err
|
||
|
|
}
|
||
|
|
defer rows.Close()
|
||
|
|
ids := append([]string{}, requested...)
|
||
|
|
for rows.Next() {
|
||
|
|
var id, sensitivity string
|
||
|
|
if err = rows.Scan(&id, &sensitivity); err != nil {
|
||
|
|
return nil, err
|
||
|
|
}
|
||
|
|
if sensitivity != "normal" && !access.Sensitive {
|
||
|
|
return nil, fault(403, "SENSITIVE_MEMORY_ACCESS_DENIED")
|
||
|
|
}
|
||
|
|
ids = append(ids, id)
|
||
|
|
}
|
||
|
|
return ids, rows.Err()
|
||
|
|
}
|