WeKnora deployment source with the reviewed wiki identity, summary and recovery fixes
Anydoc / anydoc parser engine (push) Canceled after 0s
App / Format, vet, test, and build (push) Canceled after 0s
CLI / test (macos-latest / go 1.26) (push) Canceled after 0s
CLI / test (ubuntu-latest / go 1.26) (push) Canceled after 0s
CLI / test (windows-latest / go 1.26) (push) Canceled after 0s
Build and Push Docker Image / build-ui (push) Canceled after 0s
Build and Push Docker Image / build-docreader (push) Canceled after 0s
Build and Push Docker Image / build-sandbox (push) Canceled after 0s
Build and Push Docker Image / build-app (amd64, linux/amd64, ubuntu-latest) (push) Canceled after 0s
Build and Push Docker Image / build-app (arm64, linux/arm64, ubuntu-24.04-arm) (push) Canceled after 0s
DocReader / Python tests and Go client tests (push) Canceled after 0s
Build & Publish (dsh-weknora) / Typecheck, test, pack (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (pinned) (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (latest, advisory) (push) Canceled after 0s
Frontend / Test, type-check, and build (push) Canceled after 0s
Go Lint Cache / warm lint cache (.) (push) Canceled after 0s
Go Lint Cache / warm lint cache (cli) (push) Canceled after 0s
Go Lint Cache / warm lint cache (client) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.10) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.11) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.12) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.13) (push) Canceled after 0s
Build and Push Docker Image / merge (push) Canceled after 0s
Build & Publish (dsh-weknora) / Publish to npm (push) Canceled after 0s
Build & Publish (mcp-server) / Build sdist + wheel (push) Canceled after 0s
Build & Publish (mcp-server) / Publish to PyPI (push) Canceled after 0s
Anydoc / anydoc parser engine (push) Canceled after 0s
App / Format, vet, test, and build (push) Canceled after 0s
CLI / test (macos-latest / go 1.26) (push) Canceled after 0s
CLI / test (ubuntu-latest / go 1.26) (push) Canceled after 0s
CLI / test (windows-latest / go 1.26) (push) Canceled after 0s
Build and Push Docker Image / build-ui (push) Canceled after 0s
Build and Push Docker Image / build-docreader (push) Canceled after 0s
Build and Push Docker Image / build-sandbox (push) Canceled after 0s
Build and Push Docker Image / build-app (amd64, linux/amd64, ubuntu-latest) (push) Canceled after 0s
Build and Push Docker Image / build-app (arm64, linux/arm64, ubuntu-24.04-arm) (push) Canceled after 0s
DocReader / Python tests and Go client tests (push) Canceled after 0s
Build & Publish (dsh-weknora) / Typecheck, test, pack (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (pinned) (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (latest, advisory) (push) Canceled after 0s
Frontend / Test, type-check, and build (push) Canceled after 0s
Go Lint Cache / warm lint cache (.) (push) Canceled after 0s
Go Lint Cache / warm lint cache (cli) (push) Canceled after 0s
Go Lint Cache / warm lint cache (client) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.10) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.11) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.12) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.13) (push) Canceled after 0s
Build and Push Docker Image / merge (push) Canceled after 0s
Build & Publish (dsh-weknora) / Publish to npm (push) Canceled after 0s
Build & Publish (mcp-server) / Build sdist + wheel (push) Canceled after 0s
Build & Publish (mcp-server) / Publish to PyPI (push) Canceled after 0s
This commit is contained in:
@@ -0,0 +1,151 @@
|
||||
package chatpipeline
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/Tencent/WeKnora/internal/types"
|
||||
)
|
||||
|
||||
func TestApplyIntentPromptOverride_AgentOverrideWins(t *testing.T) {
|
||||
cm := &types.ChatManage{
|
||||
PipelineRequest: types.PipelineRequest{
|
||||
IntentPromptOverrides: map[string]string{"chitchat": "agent prompt"},
|
||||
},
|
||||
PipelineState: types.PipelineState{Intent: types.IntentChitchat},
|
||||
}
|
||||
global := map[string]string{"chitchat": "global prompt"}
|
||||
|
||||
if !applyIntentPromptOverride(cm, global) {
|
||||
t.Fatal("expected applied=true")
|
||||
}
|
||||
if cm.SystemPromptOverride != "agent prompt" {
|
||||
t.Errorf("override: got %q, want %q", cm.SystemPromptOverride, "agent prompt")
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplyIntentPromptOverride_PreservesAgentWhitespace(t *testing.T) {
|
||||
// Agent-supplied prompts with surrounding whitespace must reach the model
|
||||
// verbatim; trim is only used for emptiness detection.
|
||||
raw := " agent prompt with trailing newline\n"
|
||||
cm := &types.ChatManage{
|
||||
PipelineRequest: types.PipelineRequest{
|
||||
IntentPromptOverrides: map[string]string{"chitchat": raw},
|
||||
},
|
||||
PipelineState: types.PipelineState{Intent: types.IntentChitchat},
|
||||
}
|
||||
|
||||
if !applyIntentPromptOverride(cm, nil) {
|
||||
t.Fatal("expected applied=true")
|
||||
}
|
||||
if cm.SystemPromptOverride != raw {
|
||||
t.Errorf("override: got %q, want %q", cm.SystemPromptOverride, raw)
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplyIntentPromptOverride_BlankAgentFallsBackToGlobal(t *testing.T) {
|
||||
cm := &types.ChatManage{
|
||||
PipelineRequest: types.PipelineRequest{
|
||||
IntentPromptOverrides: map[string]string{"chitchat": " \n\t "},
|
||||
},
|
||||
PipelineState: types.PipelineState{Intent: types.IntentChitchat},
|
||||
}
|
||||
global := map[string]string{"chitchat": "global prompt"}
|
||||
|
||||
if !applyIntentPromptOverride(cm, global) {
|
||||
t.Fatal("expected applied=true")
|
||||
}
|
||||
if cm.SystemPromptOverride != "global prompt" {
|
||||
t.Errorf("override: got %q, want %q", cm.SystemPromptOverride, "global prompt")
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplyIntentPromptOverride_NoOverrideAndNoGlobal(t *testing.T) {
|
||||
cm := &types.ChatManage{
|
||||
PipelineState: types.PipelineState{Intent: types.IntentChitchat},
|
||||
}
|
||||
|
||||
if applyIntentPromptOverride(cm, nil) {
|
||||
t.Fatal("expected applied=false")
|
||||
}
|
||||
if cm.SystemPromptOverride != "" {
|
||||
t.Errorf("override should remain empty, got %q", cm.SystemPromptOverride)
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplyIntentPromptOverride_GlobalOnly(t *testing.T) {
|
||||
cm := &types.ChatManage{
|
||||
PipelineState: types.PipelineState{Intent: types.IntentGreeting},
|
||||
}
|
||||
global := map[string]string{"greeting": "hi there"}
|
||||
|
||||
if !applyIntentPromptOverride(cm, global) {
|
||||
t.Fatal("expected applied=true")
|
||||
}
|
||||
if cm.SystemPromptOverride != "hi there" {
|
||||
t.Errorf("override: got %q, want %q", cm.SystemPromptOverride, "hi there")
|
||||
}
|
||||
}
|
||||
|
||||
// TestParseOutput_UnparsableFallsBackToOriginalQuery pins the degradation
|
||||
// contract for query understanding: when the LLM returns output that cannot be
|
||||
// parsed as the structured {"rewrite_query","intent",...} JSON, RewriteQuery
|
||||
// must remain the original user query (which OnEvent sets before calling
|
||||
// parseOutput) instead of leaking the raw model text into the downstream
|
||||
// retrieval query.
|
||||
func TestParseOutput_UnparsableFallsBackToOriginalQuery(t *testing.T) {
|
||||
p := &PluginQueryUnderstand{}
|
||||
cm := &types.ChatManage{
|
||||
PipelineState: types.PipelineState{
|
||||
RewriteQuery: "original user query",
|
||||
Intent: types.IntentKBSearch,
|
||||
},
|
||||
}
|
||||
|
||||
p.parseOutput(cm, "The answer is: check the admin console")
|
||||
|
||||
if cm.RewriteQuery != "original user query" {
|
||||
t.Fatalf("RewriteQuery = %q, want original user query", cm.RewriteQuery)
|
||||
}
|
||||
if cm.Intent != types.IntentKBSearch {
|
||||
t.Errorf("Intent = %q, want kb_search", cm.Intent)
|
||||
}
|
||||
}
|
||||
|
||||
// TestParseOutput_UnparsableBlankDoesNotRewrite verifies that empty LLM output
|
||||
// also leaves the original query untouched.
|
||||
func TestParseOutput_UnparsableBlankDoesNotRewrite(t *testing.T) {
|
||||
p := &PluginQueryUnderstand{}
|
||||
cm := &types.ChatManage{
|
||||
PipelineState: types.PipelineState{
|
||||
RewriteQuery: "original user query",
|
||||
Intent: types.IntentKBSearch,
|
||||
},
|
||||
}
|
||||
|
||||
p.parseOutput(cm, " \n\t ")
|
||||
|
||||
if cm.RewriteQuery != "original user query" {
|
||||
t.Fatalf("RewriteQuery = %q, want original user query", cm.RewriteQuery)
|
||||
}
|
||||
}
|
||||
|
||||
// TestParseOutput_ValidJSONStillAppliesRewrite guards the happy path: a
|
||||
// well-formed structured output still overrides RewriteQuery and Intent.
|
||||
func TestParseOutput_ValidJSONStillAppliesRewrite(t *testing.T) {
|
||||
p := &PluginQueryUnderstand{}
|
||||
cm := &types.ChatManage{
|
||||
PipelineState: types.PipelineState{
|
||||
RewriteQuery: "original user query",
|
||||
Intent: types.IntentKBSearch,
|
||||
},
|
||||
}
|
||||
|
||||
p.parseOutput(cm, `{"rewrite_query":"rewritten query","intent":"summarize"}`)
|
||||
|
||||
if cm.RewriteQuery != "rewritten query" {
|
||||
t.Fatalf("RewriteQuery = %q, want rewritten query", cm.RewriteQuery)
|
||||
}
|
||||
if cm.Intent != types.IntentSummarize {
|
||||
t.Errorf("Intent = %q, want summarize", cm.Intent)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user