062d4252ef
The context block now lists her real capabilities: reminders, notes and facts (write and recall), and the calendar — all three are code paths in mavend today. Weather, telegram and shell acts are listed only when the config actually has them, because offering something she cannot do is worse than staying quiet about it. Also drops the pronouns from the optional name/city line. The block's own "ты" is Maven, so "тебя зовут" read as her name and "его" would have shown her the third-person form she must never use about him. They are plain labels now. Vikunja #394. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CGeSZxh1DCtRxmFVSYVGvJ
73 lines
2.3 KiB
Go
73 lines
2.3 KiB
Go
package persona
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
var ref = time.Date(2026, 7, 31, 14, 5, 0, 0, time.UTC)
|
|
|
|
// The block must be correct with an empty config: the address form and the
|
|
// gender rules are hard constraints, not preferences.
|
|
func TestBlockWorksWithZeroConfig(t *testing.T) {
|
|
b := Facts{}.Block(ref)
|
|
for _, want := range []string{"женском роде", "ОБРАЩЕНИЕ", "\"ты\"", "31 июля 2026", "пятница", "14:05"} {
|
|
if !strings.Contains(b, want) {
|
|
t.Errorf("block missing %q:\n%s", want, b)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestBlockAddsOptionalFacts(t *testing.T) {
|
|
b := Facts{OwnerName: "Ками", City: "Москва", Static: "Будь краткой."}.Block(ref)
|
|
for _, want := range []string{"Ками", "Москва", "Будь краткой."} {
|
|
if !strings.Contains(b, want) {
|
|
t.Errorf("block missing %q:\n%s", want, b)
|
|
}
|
|
}
|
|
}
|
|
|
|
// The time changes between turns, so two renders must differ.
|
|
func TestBlockRendersTimePerTurn(t *testing.T) {
|
|
a := Facts{}.Block(ref)
|
|
c := Facts{}.Block(ref.Add(time.Hour))
|
|
if a == c {
|
|
t.Errorf("block did not change with the clock:\n%s", a)
|
|
}
|
|
}
|
|
|
|
// She may only offer what this deployment actually has.
|
|
func TestCapabilitiesAreConfigGated(t *testing.T) {
|
|
bare := Facts{}.Block(ref)
|
|
for _, want := range []string{"напоминания", "заметки", "календарь"} {
|
|
if !strings.Contains(bare, want) {
|
|
t.Errorf("block missing always-on capability %q:\n%s", want, bare)
|
|
}
|
|
}
|
|
for _, unwanted := range []string{"погоду", "телеграм", "команды"} {
|
|
if strings.Contains(bare, unwanted) {
|
|
t.Errorf("block offers unconfigured %q:\n%s", unwanted, bare)
|
|
}
|
|
}
|
|
|
|
full := Facts{Weather: true, Telegram: true, Tools: true}.Block(ref)
|
|
for _, want := range []string{"погоду", "телеграм", "команды"} {
|
|
if !strings.Contains(full, want) {
|
|
t.Errorf("block missing configured capability %q:\n%s", want, full)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestPrependNilIsSafe(t *testing.T) {
|
|
if got := Prepend(nil, "PROMPT"); got != "PROMPT" {
|
|
t.Errorf("Prepend(nil) = %q", got)
|
|
}
|
|
if got := Prepend(func() string { return " " }, "PROMPT"); got != "PROMPT" {
|
|
t.Errorf("Prepend(blank) = %q", got)
|
|
}
|
|
if got := Prepend(func() string { return "CTX" }, "PROMPT"); got != "CTX\n\nPROMPT" {
|
|
t.Errorf("Prepend = %q", got)
|
|
}
|
|
}
|