Ctrl K
ComunidadGuías…

internal/memory/run_answers_test.go

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

Archivo original ↗Preguntar a KiBot
package memory_test

import (
	"encoding/json"
	"sync"
	"testing"
	"time"

	"github.com/yeomyeonggeori/blueclaw/internal/memory"
	"github.com/yeomyeonggeori/blueclaw/internal/memory/memorytest"
	"github.com/yeomyeonggeori/blueprotocol/agentcontract"
)

func TestWhatARunsToolAlreadyAnsweredIsNotRememberedForThePerson(t *testing.T) {
	stores := memorytest.OpenJudgingSame(t)

	remember(t, stores, "run-1", toolAnswered("observation-1", "The weekly review is on Monday at 10:00"))

	if count := memorytest.Count(t, stores, memory.PersonScope("person-1")); count != 0 {
		t.Fatalf("a person's memory took %d copies of what the calendar answered", count)
	}
}

func TestAFailedToolIsNotTakenAsAnAnswer(t *testing.T) {
	stores := memorytest.OpenJudgingSame(t)

	remember(t, stores, "run-1", toolFailed("observation-1", "The weekly review is on Monday at 10:00"))

	if count := memorytest.Count(t, stores, memory.PersonScope("person-1")); count != 1 {
		t.Fatalf("a run with only a failed tool left %d memories, so a failure would read as an answer", count)
	}
}

func remember(t *testing.T, stores *memory.Stores, taskRunID string, events ...agentcontract.TaskEvent) {
	t.Helper()
	taskRuns := &recordedRun{events: events}
	memory.TaskRunTransitionObserver{Stores: stores, TaskRuns: taskRuns}.Observe(agentcontract.TaskRun{
		TaskRunID:         taskRunID,
		RequesterPersonID: "person-1",
		Prompt:            "When is the weekly review?",
		Result:            "The weekly review is on Monday at 10:00",
		Status:            agentcontract.TaskStatusCompleted,
	})
	deadline := time.Now().Add(10 * time.Second)
	for !taskRuns.has("memory.extraction_completed") {
		if failure := taskRuns.body("memory.extraction_failed"); failure != "" {
			t.Fatalf("remembering failed: %s", failure)
		}
		if time.Now().After(deadline) {
			t.Fatal("the run was never remembered")
		}
		time.Sleep(10 * time.Millisecond)
	}
}

func toolAnswered(observationID string, summary string) agentcontract.TaskEvent {
	return toolResult(map[string]any{"observationID": observationID, "summary": summary})
}

func toolFailed(observationID string, summary string) agentcontract.TaskEvent {
	return toolResult(map[string]any{"observationID": observationID, "summary": summary, "failure": map[string]any{"kind": "unknown"}})
}

func toolResult(observation map[string]any) agentcontract.TaskEvent {
	body, _ := json.Marshal(observation)
	return agentcontract.TaskEvent{Name: agentcontract.ToolTaskEventName("calendar_event_list", agentcontract.ToolTaskEventResultSuffix), Body: string(body)}
}

type recordedRun struct {
	mutex  sync.Mutex
	events []agentcontract.TaskEvent
}

func (run *recordedRun) FindTaskRun(string) (agentcontract.TaskRun, bool) {
	return agentcontract.TaskRun{}, false
}

func (run *recordedRun) ListTaskEvent(string) []agentcontract.TaskEvent {
	run.mutex.Lock()
	defer run.mutex.Unlock()
	return append([]agentcontract.TaskEvent{}, run.events...)
}

func (run *recordedRun) AppendTaskEvent(_ string, name string, body string) {
	run.mutex.Lock()
	defer run.mutex.Unlock()
	run.events = append(run.events, agentcontract.TaskEvent{Name: name, Body: body})
}

func (run *recordedRun) has(name string) bool {
	for _, event := range run.ListTaskEvent("") {
		if event.Name == name {
			return true
		}
	}
	return false
}

func (run *recordedRun) body(name string) string {
	for _, event := range run.ListTaskEvent("") {
		if event.Name == name {
			return event.Body
		}
	}
	return ""
}