Ctrl K
ComunidadGuías…

confidence_memory_test.go

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
package graymatter

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"net/http"
	"net/http/httptest"
	"testing"
	"time"

	"github.com/angelnicolasc/graymatter/pkg/memory"
)

func TestMemoryConfidenceOptionsAndNamespaces(t *testing.T) {
	m, err := NewWithConfig(Config{DataDir: t.TempDir(), EmbeddingMode: EmbeddingKeyword, TopK: 1, CandidateRetrieval: true})
	if err != nil {
		t.Fatal(err)
	}
	defer m.Close()
	ctx := context.Background()
	verified, unverified := "verified", "unverified"
	a, err := m.RememberWithOptions(ctx, "a", "deployment approved", memory.WriteOptions{Confidence: &verified})
	if err != nil {
		t.Fatal(err)
	}
	if _, err := m.RememberWithOptions(ctx, "a", "deployment rumored", memory.WriteOptions{Confidence: &unverified}); err != nil {
		t.Fatal(err)
	}
	s, err := m.RememberSharedWithOptions(ctx, "deployment global policy", memory.WriteOptions{Confidence: &verified})
	if err != nil {
		t.Fatal(err)
	}
	if a.ID == s.ID || a.Confidence != verified || s.AgentID != memory.SharedAgentID {
		t.Fatalf("invalid receipts: %+v / %+v", a, s)
	}
	zero := 0.0
	opts := memory.RecallOptions{MinConfidence: &verified, ConfidenceWeight: &zero}
	r, err := m.RecallWithOptions(ctx, "a", "deployment", opts)
	if err != nil || len(r.Facts) != 1 || r.Facts[0] != a.Text || r.Retrieval == nil {
		t.Fatalf("agent options: %+v %v", r, err)
	}
	e, err := m.RecallExplainWithOptions(ctx, "a", "deployment", opts)
	if err != nil || len(e.Receipts) != 1 || e.Receipts[0].Provenance.FactID != a.ID || e.Retrieval == nil {
		t.Fatalf("explain options: %+v %v", e, err)
	}
	r, err = m.RecallSharedWithOptions(ctx, "deployment", opts)
	if err != nil || len(r.Facts) != 1 || r.Facts[0] != s.Text {
		t.Fatalf("shared options: %+v %v", r, err)
	}
	r, err = m.RecallAllWithOptions(ctx, "a", "deployment", opts)
	if err != nil || len(r.Facts) != 1 || r.Retrieval == nil {
		t.Fatalf("all options: %+v %v", r, err)
	}
	bad := " verified"
	if _, err := m.RememberWithOptions(ctx, "a", "invalid", memory.WriteOptions{Confidence: &bad}); err == nil {
		t.Fatal("invalid write accepted")
	}
	facts, _ := m.Advanced().List("a")
	if len(facts) != 2 {
		t.Fatal("invalid write had effects")
	}
}

func confidenceAnthropicMessage(text string) string {
	content, _ := json.Marshal([]map[string]string{{"type": "text", "text": text}})
	return fmt.Sprintf(`{"id":"msg_test","type":"message","role":"assistant","model":"claude-test","content":%s,"stop_reason":"end_turn","usage":{"input_tokens":1,"output_tokens":1}}`, content)
}

func TestMemoryRememberExtractedConfidenceFollowsProvenance(t *testing.T) {
	for _, tc := range []struct{ name, key, response, want string }{
		{"offline", "", "", ""},
		{"generated identical text", "test-key", `["source"]`, "unverified"},
		{"malformed model fallback", "test-key", `not JSON`, ""},
	} {
		t.Run(tc.name, func(t *testing.T) {
			if tc.key != "" {
				srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
					w.Header().Set("Content-Type", "application/json")
					fmt.Fprint(w, confidenceAnthropicMessage(tc.response))
				}))
				defer srv.Close()
				t.Setenv("ANTHROPIC_BASE_URL", srv.URL)
			}
			m, err := NewWithConfig(Config{DataDir: t.TempDir(), EmbeddingMode: EmbeddingKeyword, AnthropicAPIKey: tc.key, ConsolidateModel: "claude-test"})
			if err != nil {
				t.Fatal(err)
			}
			defer m.Close()
			if err := m.RememberExtracted(context.Background(), "a", "source"); err != nil {
				t.Fatal(err)
			}
			facts, err := m.Advanced().List("a")
			if err != nil || len(facts) != 1 || facts[0].Text != "source" || facts[0].Confidence != tc.want {
				t.Fatalf("stored extraction: %+v %v", facts, err)
			}
		})
	}
}

func TestMemoryRememberWithOptionsConsolidatesAfterMetadataCommit(t *testing.T) {
	reported := make(chan error, 2)
	requests := make(chan struct{}, 1)
	srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
		requests <- struct{}{}
		w.Header().Set("Content-Type", "application/json")
		fmt.Fprint(w, confidenceAnthropicMessage(""))
	}))
	defer srv.Close()
	t.Setenv("ANTHROPIC_BASE_URL", srv.URL)
	m, err := NewWithConfig(Config{DataDir: t.TempDir(), EmbeddingMode: EmbeddingKeyword,
		AsyncConsolidate: true, ConsolidateThreshold: 2, ConsolidateLLM: "anthropic", AnthropicAPIKey: "test-key", ConsolidateModel: "claude-test",
		OnConsolidateError: func(_ string, err error) { reported <- err },
	})
	if err != nil {
		t.Fatal(err)
	}
	defer m.Close()
	for _, text := range []string{"source one", "source two"} {
		if err := m.Advanced().Put(context.Background(), "a", text); err != nil {
			t.Fatal(err)
		}
	}
	label := "unverified"
	f, err := m.RememberWithOptions(context.Background(), "a", "final atomic label", memory.WriteOptions{Confidence: &label})
	if err != nil {
		t.Fatal(err)
	}
	select {
	case err := <-reported:
		if !errors.Is(err, memory.ErrInvalidProposal) {
			t.Fatalf("unexpected consolidation error: %v", err)
		}
	case <-time.After(5 * time.Second):
		t.Fatal("new high-level write failed to trigger consolidation")
	}
	select {
	case <-requests:
	default:
		t.Fatal("consolidation never reached configured model")
	}
	facts, _ := m.Advanced().List("a")
	for _, stored := range facts {
		if stored.ID == f.ID {
			if stored.Confidence != label {
				t.Fatalf("consolidation restored transient confidence: %+v", stored)
			}
			return
		}
	}
	t.Fatal("committed confidence write disappeared")
}

func TestMemoryConfidenceOptionsRejectNoOpReceipt(t *testing.T) {
	m := New("invalid\x00path")
	if _, err := m.RememberWithOptions(context.Background(), "a", "source", memory.WriteOptions{}); err == nil {
		t.Fatal("unavailable store fabricated durable write")
	}
	if _, err := m.RecallWithOptions(context.Background(), "a", "source", memory.RecallOptions{}); err == nil {
		t.Fatal("unavailable store fabricated policy result")
	}
}