Files
story/internal/elderagent/native_memory.go
T

90 lines
3.3 KiB
Go
Raw Normal View History

package elderagent
import (
"bytes"
"context"
"encoding/json"
"fmt"
"strings"
"data-terminal-cloud/internal/memoryidentity"
)
// Native memory uses exactly the identity used by transcript uploads. Never
// inherit the template's shared user filter or use a device as the identity.
func (s *Service) nativeMemoryConfiguration(tenant, subject string, allowed bool) (map[string]any, error) {
if !allowed {
return map[string]any{"Enable": false}, nil
}
collection, event := strings.TrimSpace(s.VikingCollectionName), strings.TrimSpace(s.VikingEventType)
if collection == "" || event == "" || tenant == "" || subject == "" {
return nil, fmt.Errorf("VIKING_NATIVE_MEMORY_CONFIG_REQUIRED")
}
return map[string]any{"Enable": true, "Provider": "volc", "ProviderParams": map[string]any{
"collection_name": collection, "limit": 3,
"filter": map[string]any{"user_id": []string{memoryidentity.UserID(tenant, subject)}, "assistant_id": []string{memoryidentity.AssistantID}, "memory_type": []string{event}},
}}, nil
}
// NativeMemoryConfiguration keeps saved-bot upgrades in the upload namespace.
func (s *Service) NativeMemoryConfiguration(tenant, subject string, allowed bool) (map[string]any, error) {
return s.nativeMemoryConfiguration(tenant, subject, allowed)
}
func (s *Service) configureNativeMemory(ctx context.Context, subject string, config map[string]any) error {
var tenant string
var allowed bool
err := s.Pool.QueryRow(ctx, `SELECT p.tenant_id::text,p.status='active' AND call_memory_authorized(p.id) AND COALESCE((SELECT effective_consents @> '{"voice_chat":true}'::jsonb FROM consent_snapshot WHERE subject_id=p.id ORDER BY snapshot_version DESC LIMIT 1),false) AND NOT EXISTS(SELECT 1 FROM privacy_request WHERE subject_id=p.id AND request_type='DELETE') FROM subject_profile p WHERE p.id=$1::uuid`, subject).Scan(&tenant, &allowed)
if err != nil {
return err
}
config["MemoryConfig"], err = s.nativeMemoryConfiguration(tenant, subject, allowed)
return err
}
// Read back the filter too: checking Enable alone cannot detect cross-elder
// retrieval or an incorrect collection. Provider credentials are never read.
func (c *Client) VerifyNativeMemory(ctx context.Context, id string, expected map[string]any) error {
var result struct {
Bots []Bot `json:"Bots"`
}
if err := c.call(ctx, "AibotQuery", map[string]any{"Id": id}, &result); err != nil {
return err
}
for _, bot := range result.Bots {
if bot.ID != id {
continue
}
actual, _ := bot.Config["MemoryConfig"].(map[string]any)
rawEnabled, present := actual["Enable"]
enabled, valid := rawEnabled.(bool)
if present && !valid {
break
}
wantEnabled, _ := expected["Enable"].(bool)
if enabled != wantEnabled {
break
}
if !wantEnabled {
return nil
}
want, _ := json.Marshal(expected["ProviderParams"])
got, _ := json.Marshal(actual["ProviderParams"])
if actual["Provider"] == expected["Provider"] && bytes.Equal(want, got) {
return nil
}
break
}
return fmt.Errorf("VIKING_NATIVE_MEMORY_VERIFY_FAILED")
}
func (s *Service) verifyNativeMemory(ctx context.Context, bot string, config map[string]any) error {
if verifier, ok := s.Provider.(interface {
VerifyNativeMemory(context.Context, string, map[string]any) error
}); ok {
memory, _ := config["MemoryConfig"].(map[string]any)
return verifier.VerifyNativeMemory(ctx, bot, memory)
}
return nil
}