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 }