diff --git a/internal/application/service/chat_pipeline/query_understand.go b/internal/application/service/chat_pipeline/query_understand.go index f4022da2..3b9ff1b0 100644 --- a/internal/application/service/chat_pipeline/query_understand.go +++ b/internal/application/service/chat_pipeline/query_understand.go @@ -470,14 +470,18 @@ func mergeImageDescAndOCR(desc, ocr string) (string, bool) { // applyIntentPromptOverride resolves the system-prompt override for the current // non-retrieval intent. Agent-level overrides take precedence; otherwise the -// tenant/global IntentSystemPrompts map is consulted. Whitespace-only agent -// overrides are treated as unset and fall through to the global default. Returns -// true when a non-empty override was applied. +// tenant/global IntentSystemPrompts map is consulted. When a custom agent +// system prompt is already applied, global intent prompts must not replace it. +// Whitespace-only agent overrides are treated as unset. Returns true when a +// non-empty override was applied. func applyIntentPromptOverride(chatManage *types.ChatManage, globalPrompts map[string]string) bool { intentKey := string(chatManage.Intent) if raw, ok := chatManage.IntentPromptOverrides[intentKey]; ok && strings.TrimSpace(raw) != "" { chatManage.SystemPromptOverride = raw } + if chatManage.AgentSystemPromptApplied { + return chatManage.SystemPromptOverride != "" + } if chatManage.SystemPromptOverride == "" { if prompt, ok := globalPrompts[intentKey]; ok { chatManage.SystemPromptOverride = prompt diff --git a/internal/application/service/chat_pipeline/query_understand_test.go b/internal/application/service/chat_pipeline/query_understand_test.go index e63a0a42..61f97f66 100644 --- a/internal/application/service/chat_pipeline/query_understand_test.go +++ b/internal/application/service/chat_pipeline/query_understand_test.go @@ -59,6 +59,23 @@ func TestApplyIntentPromptOverride_BlankAgentFallsBackToGlobal(t *testing.T) { } } +func TestApplyIntentPromptOverride_CustomAgentSystemPromptSkipsGlobalFallback(t *testing.T) { + cm := &types.ChatManage{ + PipelineRequest: types.PipelineRequest{ + AgentSystemPromptApplied: true, + }, + PipelineState: types.PipelineState{Intent: types.IntentGreeting}, + } + global := map[string]string{"greeting": "global prompt"} + + if applyIntentPromptOverride(cm, global) { + t.Fatal("expected applied=false") + } + if cm.SystemPromptOverride != "" { + t.Errorf("override should remain empty, got %q", cm.SystemPromptOverride) + } +} + func TestApplyIntentPromptOverride_NoOverrideAndNoGlobal(t *testing.T) { cm := &types.ChatManage{ PipelineState: types.PipelineState{Intent: types.IntentChitchat}, diff --git a/internal/application/service/session_qa_helpers.go b/internal/application/service/session_qa_helpers.go index d75de469..2d0b1a19 100644 --- a/internal/application/service/session_qa_helpers.go +++ b/internal/application/service/session_qa_helpers.go @@ -117,6 +117,7 @@ func (s *sessionService) applyAgentOverridesToChatManage( // Override summary config fields if customAgent.Config.SystemPrompt != "" { cm.SummaryConfig.Prompt = customAgent.Config.SystemPrompt + cm.AgentSystemPromptApplied = true logger.Infof(ctx, "Using custom agent's system_prompt") } if customAgent.Config.ContextTemplate != "" { diff --git a/internal/application/service/session_qa_helpers_test.go b/internal/application/service/session_qa_helpers_test.go new file mode 100644 index 00000000..f165022f --- /dev/null +++ b/internal/application/service/session_qa_helpers_test.go @@ -0,0 +1,25 @@ +package service + +import ( + "context" + "testing" + + "github.com/Tencent/WeKnora/internal/types" +) + +func TestApplyAgentOverridesToChatManageMarksCustomSystemPrompt(t *testing.T) { + s := &sessionService{} + cm := &types.ChatManage{} + agent := &types.CustomAgent{ + Config: types.CustomAgentConfig{SystemPrompt: "You are Xiaochi."}, + } + + s.applyAgentOverridesToChatManage(context.Background(), agent, cm) + + if cm.SummaryConfig.Prompt != "You are Xiaochi." { + t.Errorf("prompt: got %q", cm.SummaryConfig.Prompt) + } + if !cm.AgentSystemPromptApplied { + t.Fatal("expected custom agent system prompt to be marked as applied") + } +} diff --git a/internal/types/chat_manage.go b/internal/types/chat_manage.go index 7b8c4820..a00ede14 100644 --- a/internal/types/chat_manage.go +++ b/internal/types/chat_manage.go @@ -62,6 +62,9 @@ type PipelineRequest struct { // IntentPromptOverrides holds agent-level intent prompt overrides for the // query-understanding stage. Empty values fall back to tenant/global defaults. IntentPromptOverrides map[string]string `json:"-"` + // AgentSystemPromptApplied is true when SummaryConfig.Prompt was supplied + // by a custom agent. Global intent prompts must not replace that prompt. + AgentSystemPromptApplied bool `json:"-"` // Misc request-scoped config TenantID uint64 `json:"-"` @@ -226,6 +229,7 @@ func (c *ChatManage) Clone() *ChatManage { WebFetchTopN: c.WebFetchTopN, Language: c.Language, IntentPromptOverrides: maps.Clone(c.IntentPromptOverrides), + AgentSystemPromptApplied: c.AgentSystemPromptApplied, }, PipelineState: PipelineState{ RewriteQuery: c.RewriteQuery,