src/server/internal/orchestrator/prompt_test.go
9,866 bytes · 286 lines · capsule://quake0day/[email protected]
raw on github
package orchestrator
import (
"path/filepath"
"strings"
"testing"
"time"
"github.com/cyberverse/server/internal/agenttask"
"github.com/cyberverse/server/internal/character"
)
func TestComposeSystemPromptSeparatesGlobalAndRole(t *testing.T) {
got := composeSystemPrompt("全局规则", "角色设定")
if !strings.Contains(got, "【全局输出规范】\n全局规则") {
t.Fatalf("expected global section, got %q", got)
}
if !strings.Contains(got, "【角色设定】\n角色设定") {
t.Fatalf("expected role section, got %q", got)
}
}
func TestStandardSystemPromptUsesGlobalWithoutCharacter(t *testing.T) {
orch := New(nil, nil, nil, nil, nil)
session := NewSession("s1", ModeStandard, "")
got := orch.standardSystemPrompt(session)
if got != composeSystemPrompt(standardGlobalSystemPrompt, "") {
t.Fatalf("unexpected system prompt: %q", got)
}
}
func TestBuildVoiceLLMSessionConfigUsesPersonaAndOnlyOmniRolePrompt(t *testing.T) {
store, err := character.NewStore(t.TempDir())
if err != nil {
t.Fatal(err)
}
char, err := store.Create(&character.Character{
Name: "晴天",
Description: "日常聊天伙伴",
VoiceProvider: "qwen_omni",
VoiceType: "Tina",
SpeakingStyle: "自然、简洁",
Personality: "温和真诚",
SystemPrompt: "你和用户像熟悉的朋友。",
})
if err != nil {
t.Fatal(err)
}
orch := New(nil, nil, nil, nil, store)
session := NewSession("s1", ModeOmni, char.ID)
got := orch.buildVoiceLLMSessionConfig(session, "s1")
if got.Provider != "persona" {
t.Fatalf("expected persona provider, got %q", got.Provider)
}
if got.BotName != "晴天" || got.SpeakingStyle != "自然、简洁" {
t.Fatalf("expected voice-specific fields to stay separate, got %+v", got)
}
if got.CharacterID != char.ID || got.CharacterDir == "" {
t.Fatalf("expected character RAG identity fields, got %+v", got)
}
if got.SystemPrompt != "你和用户像熟悉的朋友。" {
t.Fatalf("expected omni mode to keep only the character prompt, got %q", got.SystemPrompt)
}
for _, unexpected := range []string{"【全局输出规范】", "默认简短", "角色描述:", "角色性格:", "说话风格:"} {
if strings.Contains(got.SystemPrompt, unexpected) {
t.Fatalf("omni prompt should not contain %q: %q", unexpected, got.SystemPrompt)
}
}
}
func TestBuildVoiceLLMSessionConfigIncludesLiveHistoryOnReconnect(t *testing.T) {
store, err := character.NewStore(t.TempDir())
if err != nil {
t.Fatal(err)
}
char, err := store.Create(&character.Character{
Name: "晴天",
VoiceProvider: "qwen_omni",
VoiceType: "Tina",
SystemPrompt: "你和用户像熟悉的朋友。",
})
if err != nil {
t.Fatal(err)
}
orch := New(nil, nil, nil, nil, store)
session := NewSession("s1", ModeOmni, char.ID)
session.SetDialogContext([]DialogContextItem{
{Role: "user", Text: "上次我们聊到她喜欢睡前吃零食。", Timestamp: 1},
{Role: "assistant", Text: "我记得这个细节。", Timestamp: 2},
})
now := time.Date(2026, 5, 26, 0, 0, 0, 0, time.UTC)
session.AddMessage(ChatMessage{Role: "user", Content: "她睡前不洗脚,吃饭不擦嘴", Timestamp: now, TurnSeq: 1})
session.AddMessage(ChatMessage{Role: "assistant", Content: "你说的是她的生活习惯。", Timestamp: now.Add(time.Second), TurnSeq: 1})
session.AddMessage(ChatMessage{Role: "user", Content: "就是,快点说说她", Timestamp: now.Add(2 * time.Second), TurnSeq: 2})
session.AddMessage(ChatMessage{Role: "user", Content: "她,当前前面提到的她,你还有上下文吗", Timestamp: now.Add(3 * time.Second), TurnSeq: 3})
got := orch.buildVoiceLLMSessionConfigExcludingTurn(session, "s1", 3)
texts := make([]string, 0, len(got.DialogContext))
for _, item := range got.DialogContext {
texts = append(texts, item.Text)
}
joined := strings.Join(texts, "\n")
for _, want := range []string{
"上次我们聊到她喜欢睡前吃零食。",
"我记得这个细节。",
"她睡前不洗脚,吃饭不擦嘴",
"你说的是她的生活习惯。",
"就是,快点说说她",
} {
if !strings.Contains(joined, want) {
t.Fatalf("expected live reconnect context to contain %q, got %+v", want, got.DialogContext)
}
}
if strings.Contains(joined, "她,当前前面提到的她,你还有上下文吗") {
t.Fatalf("current text input should not be duplicated in dialog context: %+v", got.DialogContext)
}
}
func TestVoiceStartupGreetingUsesUnderlyingProviderAndNoFixedWelcome(t *testing.T) {
store, err := character.NewStore(t.TempDir())
if err != nil {
t.Fatal(err)
}
char, err := store.Create(&character.Character{
Name: "晴天",
VoiceProvider: "qwen_omni",
VoiceType: "Tina",
SpeakingStyle: "自然、简洁",
SystemPrompt: "你和用户像熟悉的朋友。",
WelcomeMessage: "欢迎回来,我们继续聊。",
})
if err != nil {
t.Fatal(err)
}
orch := New(nil, nil, nil, nil, store)
session := NewSession("s1", ModeOmni, char.ID)
normal := orch.buildVoiceLLMSessionConfig(session, "s1")
if normal.Provider != "persona" {
t.Fatalf("expected normal omni config to use persona, got %q", normal.Provider)
}
if normal.WelcomeMessage != "" {
t.Fatalf("expected fixed welcome to be withheld from normal voice config, got %q", normal.WelcomeMessage)
}
greeting := orch.buildVoiceStartupGreetingSessionConfig(session, "s1")
if greeting.Provider != "qwen_omni" {
t.Fatalf("expected startup greeting to use underlying provider, got %q", greeting.Provider)
}
if greeting.WelcomeMessage != "" {
t.Fatalf("expected startup greeting to disable provider SayHello, got %q", greeting.WelcomeMessage)
}
}
func TestBuildVoiceStartupGreetingPromptUsesHistory(t *testing.T) {
store, err := character.NewStore(t.TempDir())
if err != nil {
t.Fatal(err)
}
char, err := store.Create(&character.Character{
Name: "晴天",
SpeakingStyle: "自然、简洁",
SystemPrompt: "你和用户像熟悉的朋友。",
WelcomeMessage: "见到你很高兴。",
})
if err != nil {
t.Fatal(err)
}
orch := New(nil, nil, nil, nil, store)
session := NewSession("s1", ModeOmni, char.ID)
session.SetDialogContext([]DialogContextItem{
{Role: "user", Text: "上次我们在聊出差计划。", Timestamp: 1},
{Role: "assistant", Text: "我帮你整理了行程重点。", Timestamp: 2},
})
got := orch.buildVoiceStartupGreetingPrompt(session)
for _, want := range []string{
"你的名字:晴天",
"可参考的开场偏好:见到你很高兴。",
"用户:上次我们在聊出差计划。",
"你:我帮你整理了行程重点。",
"默认不要回顾、总结、复述或主动延续这些内容",
"不要主动提及取消、失败、争执、情绪化表达、敏感内容或具体历史细节",
} {
if !strings.Contains(got, want) {
t.Fatalf("expected prompt to contain %q, got %q", want, got)
}
}
if strings.Contains(got, "可以自然提到上次关注的话题") {
t.Fatalf("expected startup greeting not to encourage routine history recall: %q", got)
}
if strings.Contains(got, "当前没有可用的历史对话") {
t.Fatalf("expected history prompt, got no-history branch: %q", got)
}
}
func TestBuildVoiceStartupGreetingPromptIntroducesSelfWithoutHistory(t *testing.T) {
store, err := character.NewStore(t.TempDir())
if err != nil {
t.Fatal(err)
}
char, err := store.Create(&character.Character{Name: "晴天"})
if err != nil {
t.Fatal(err)
}
orch := New(nil, nil, nil, nil, store)
session := NewSession("s1", ModeOmni, char.ID)
got := orch.buildVoiceStartupGreetingPrompt(session)
for _, want := range []string{"你的名字:晴天", "当前没有可用的历史对话", "实时语音视频聊天", "查询、调研、整理资料"} {
if !strings.Contains(got, want) {
t.Fatalf("expected prompt to contain %q, got %q", want, got)
}
}
}
func TestBuildVoiceLLMSessionConfigUsesPersonaWhenAgentEnabled(t *testing.T) {
store, err := character.NewStore(t.TempDir())
if err != nil {
t.Fatal(err)
}
char, err := store.Create(&character.Character{
Name: "晴天",
VoiceProvider: "qwen_omni",
VoiceType: "Tina",
SystemPrompt: "你和用户像熟悉的朋友。",
})
if err != nil {
t.Fatal(err)
}
taskRoot := t.TempDir()
taskStore, err := agenttask.OpenStore(filepath.Join(taskRoot, "tasks.db"), filepath.Join(taskRoot, "artifacts"))
if err != nil {
t.Fatal(err)
}
defer taskStore.Close()
orch := New(nil, nil, nil, nil, store)
orch.SetTaskService(agenttask.NewService(taskStore, nil))
session := NewSession("s1", ModeOmni, char.ID)
got := orch.buildVoiceLLMSessionConfig(session, "s1")
if got.Provider != "persona" {
t.Fatalf("expected persona provider, got %q", got.Provider)
}
if !orch.sessionSupportsVisualInput(session) {
t.Fatal("expected qwen_omni visual support to use the underlying character provider")
}
}
func TestStandardSystemPromptWithRAGAppendsMaterialContext(t *testing.T) {
store, err := character.NewStore(t.TempDir())
if err != nil {
t.Fatal(err)
}
char, err := store.Create(&character.Character{
Name: "晴天",
SystemPrompt: "你是晴天。",
})
if err != nil {
t.Fatal(err)
}
orch := New(nil, nil, nil, nil, store)
session := NewSession("s1", ModeStandard, char.ID)
got := orch.standardSystemPromptWithRAG(session, "【角色素材检索结果】\n[1] 早年经历\n出生在海边。")
if !strings.Contains(got, "角色提示:你是晴天。") {
t.Fatalf("expected role prompt, got %q", got)
}
if !strings.Contains(got, "【角色素材检索结果】") || !strings.Contains(got, "出生在海边") {
t.Fatalf("expected RAG context, got %q", got)
}
if strings.Contains(got, "biography|") {
t.Fatalf("expected material type label to be omitted, got %q", got)
}
}