feat: expand companion platform, device controls, and memoir workflows
ci / verify (push) Canceled after 0s
ci / verify (push) Canceled after 0s
Add customer and operator login, BLE provisioning, device fleet controls, call memory, memoir generation, and refreshed family and maintenance portals. Include API contracts, migrations, firmware sources, tests, assets, and deployment documentation.
This commit is contained in:
@@ -0,0 +1,121 @@
|
||||
package elderagent
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"data-terminal-cloud/internal/companionopening"
|
||||
)
|
||||
|
||||
func TestPrepareConfigurationWelcomeOverrideAndLegacyBehavior(t *testing.T) {
|
||||
s := Service{CallbackURL: "https://example.com/callback", CallbackSecret: []byte(strings.Repeat("k", 32))}
|
||||
raw := []byte(`{"S2SConfig":{"ProviderParams":{"dialog":{"system_role":"基础人设"}}},"MemoryConfig":{"Enable":false}}`)
|
||||
agentRaw := []byte(`{"WelcomeMessage":"已保存的开场。","EnableConversationStateCallback":false}`)
|
||||
custom, blank := " \t我给您讲个老机器的小故事。\n", " \t\n"
|
||||
for _, tc := range []struct {
|
||||
name string
|
||||
override *string
|
||||
welcome string
|
||||
}{
|
||||
{name: "legacy", welcome: "已保存的开场。"},
|
||||
{name: "custom", override: &custom, welcome: "我给您讲个老机器的小故事。"},
|
||||
{name: "blank", override: &blank, welcome: "你好,今天想聊些什么?"},
|
||||
} {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
config, agent, err := s.prepareConfiguration(raw, agentRaw, "call-one", "喜欢喝淡茶", tc.override)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if agent["WelcomeMessage"] != tc.welcome || agent["EnableConversationStateCallback"] != false {
|
||||
t.Fatal("incorrect welcome or changed callback policy", agent)
|
||||
}
|
||||
if agent["ServerMessageURLForRTS"] != "https://example.com/callbacks/v1/volcengine/chat?session_id=call-one" {
|
||||
t.Fatal("wrong call callback", agent)
|
||||
}
|
||||
role := config["S2SConfig"].(map[string]any)["ProviderParams"].(map[string]any)["dialog"].(map[string]any)["system_role"].(string)
|
||||
if strings.Contains(role, "喜欢喝淡茶") || config["MemoryConfig"].(map[string]any)["Enable"] != false {
|
||||
t.Fatal("changed authorized facts or memory policy", role)
|
||||
}
|
||||
if tc.override == nil {
|
||||
if role != withEventTimeGuidance("基础人设") {
|
||||
t.Fatal("legacy preparation added opening guidance", role)
|
||||
}
|
||||
} else {
|
||||
quotedWelcome, _ := json.Marshal(tc.welcome)
|
||||
if !strings.Contains(role, string(quotedWelcome)) || !strings.Contains(role, "沿当前开场继续") || !strings.Contains(role, "不得把开场中的一般内容归到长者本人") {
|
||||
t.Fatal("missing opening continuation or factual boundary", role)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
if string(agentRaw) != `{"WelcomeMessage":"已保存的开场。","EnableConversationStateCallback":false}` || string(raw) != `{"S2SConfig":{"ProviderParams":{"dialog":{"system_role":"基础人设"}}},"MemoryConfig":{"Enable":false}}` {
|
||||
t.Fatal("preparation changed saved configuration bytes")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrepareIntroductionWaitsForElderWithoutStartingAnActivity(t *testing.T) {
|
||||
s := Service{CallbackURL: "https://example.com/callback", CallbackSecret: []byte(strings.Repeat("k", 32))}
|
||||
raw := []byte(`{"S2SConfig":{"ProviderParams":{"dialog":{"system_role":"基础人设"}}},"MemoryConfig":{"Enable":false}}`)
|
||||
agentRaw := []byte(`{"WelcomeMessage":"已保存的开场。","EnableConversationStateCallback":false}`)
|
||||
intro := companionopening.Introduction().Text
|
||||
config, agent, err := s.prepareConfiguration(raw, agentRaw, "intro-call", "", &intro)
|
||||
if err != nil || agent["WelcomeMessage"] != intro {
|
||||
t.Fatal("introduction changed between provider and device", err)
|
||||
}
|
||||
role := config["S2SConfig"].(map[string]any)["ProviderParams"].(map[string]any)["dialog"].(map[string]any)["system_role"].(string)
|
||||
for _, instruction := range []string{"口播介绍后等待长者回应", "不立即讲故事", "不反复索要姓名", "不要承诺已保存或已修改个人资料"} {
|
||||
if !strings.Contains(role, instruction) {
|
||||
t.Fatalf("missing first-call behavior: %s", instruction)
|
||||
}
|
||||
}
|
||||
if strings.Count(intro, "?") != 1 || config["MemoryConfig"].(map[string]any)["Enable"] != false || agent["EnableConversationStateCallback"] != false {
|
||||
t.Fatal("introduction adds questions or changes call/privacy policy")
|
||||
}
|
||||
ordinary := "您好,咱们聊会儿。"
|
||||
next, _, err := s.prepareConfiguration(raw, agentRaw, "next-call", "", &ordinary)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
nextRole := next["S2SConfig"].(map[string]any)["ProviderParams"].(map[string]any)["dialog"].(map[string]any)["system_role"].(string)
|
||||
if strings.Contains(nextRole, "本次是首次自我介绍") {
|
||||
t.Fatal("first-call instructions leaked to later calls")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrepareConfigurationDoesNotAccumulateCallContext(t *testing.T) {
|
||||
s := Service{CallbackURL: "https://example.com/callback", CallbackSecret: []byte(strings.Repeat("k", 32))}
|
||||
raw := []byte(`{"S2SConfig":{"ProviderParams":{"dialog":{"system_role":"基础人设"}}}}`)
|
||||
agentRaw := []byte(`{"WelcomeMessage":"已保存的开场。"}`)
|
||||
firstWelcome, secondWelcome := "讲讲老机器。", "聊聊家常菜。"
|
||||
if _, _, err := s.prepareConfiguration(raw, agentRaw, "call-one", "前次资料", &firstWelcome); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
config, agent, err := s.prepareConfiguration(raw, agentRaw, "call-two", "本次资料", &secondWelcome)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
role := config["S2SConfig"].(map[string]any)["ProviderParams"].(map[string]any)["dialog"].(map[string]any)["system_role"].(string)
|
||||
if strings.Contains(role, "前次资料") || strings.Contains(role, firstWelcome) || strings.Count(role, "本次已选开场口播") != 1 || strings.Contains(role, "本次资料") || agent["WelcomeMessage"] != secondWelcome {
|
||||
t.Fatal("prior call context leaked into next preparation", role, agent)
|
||||
}
|
||||
if _, _, err = s.prepareConfiguration(raw, []byte(`null`), "call-invalid", "", &secondWelcome); err == nil {
|
||||
t.Fatal("accepted a null agent configuration")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrepareGreetingDoesNotTurnAcknowledgementIntoAnActivity(t *testing.T) {
|
||||
s := Service{CallbackURL: "https://example.com/callback", CallbackSecret: []byte(strings.Repeat("k", 32))}
|
||||
raw := []byte(`{"S2SConfig":{"ProviderParams":{"dialog":{"system_role":"基础人设"}}},"MemoryConfig":{"Enable":false}}`)
|
||||
agentRaw := []byte(`{"WelcomeMessage":"旧开场"}`)
|
||||
for _, welcome := range []string{"您好,咱们随便聊两句。", "您平常爱听哪一种戏?"} {
|
||||
config, agent, err := s.prepareConfiguration(raw, agentRaw, "new-call", "", &welcome)
|
||||
if err != nil || agent["WelcomeMessage"] != welcome {
|
||||
t.Fatal("selected greeting was not passed through unchanged", err)
|
||||
}
|
||||
role := config["S2SConfig"].(map[string]any)["ProviderParams"].(map[string]any)["dialog"].(map[string]any)["system_role"].(string)
|
||||
if strings.Contains(role, "先讲一小段相关内容") || !strings.Contains(role, "开场只是问候时,不把它扩展成故事") || !strings.Contains(role, "不代表请求猜谜、答题或游戏") || !strings.Contains(role, "只有长者本通明确提出想玩才开始") {
|
||||
t.Fatal("greeting or brief acknowledgement still directs an unsolicited activity", role)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user