mirror of
https://github.com/CJackHwang/ds2api.git
synced 2026-05-19 23:47:45 +08:00
PR #460 introduced fullwidth pipe characters (|) in DSML tool call formatting to improve parsing robustness, but models exposed to these fullwidth pipes in system prompts exhibit significantly higher rates of tool output hallucinations. Reverting to halfwidth pipes (|) drastically reduces tokenizer/perplexity-driven hallucinations while retaining the existing confusable-hardening in the parser. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
101 lines
3.9 KiB
Go
101 lines
3.9 KiB
Go
package openai
|
|
|
|
import "testing"
|
|
|
|
func TestSanitizeLeakedOutputRemovesEmptyJSONFence(t *testing.T) {
|
|
raw := "before\n```json\n```\nafter"
|
|
got := sanitizeLeakedOutput(raw)
|
|
if got != "before\n\nafter" {
|
|
t.Fatalf("unexpected sanitized empty json fence: %q", got)
|
|
}
|
|
}
|
|
|
|
func TestSanitizeLeakedOutputRemovesLeakedWireToolCallAndResult(t *testing.T) {
|
|
raw := "开始\n[{\"function\":{\"arguments\":\"{\\\"command\\\":\\\"java -version\\\"}\",\"name\":\"exec\"},\"id\":\"callb9a321\",\"type\":\"function\"}]< | Tool | >{\"content\":\"openjdk version 21\",\"tool_call_id\":\"callb9a321\"}\n结束"
|
|
got := sanitizeLeakedOutput(raw)
|
|
if got != "开始\n\n结束" {
|
|
t.Fatalf("unexpected sanitize result for leaked wire format: %q", got)
|
|
}
|
|
}
|
|
|
|
func TestSanitizeLeakedOutputRemovesStandaloneMetaMarkers(t *testing.T) {
|
|
raw := "A<| end_of_sentence |><| Assistant |>B<| end_of_thinking |>C<|end▁of▁thinking|>D<|end▁of▁sentence|>E<| end_of_toolresults |>F<|end▁of▁instructions|>G"
|
|
got := sanitizeLeakedOutput(raw)
|
|
if got != "ABCDEFG" {
|
|
t.Fatalf("unexpected sanitize result for meta markers: %q", got)
|
|
}
|
|
}
|
|
|
|
func TestSanitizeLeakedOutputRemovesThinkAndBosMarkers(t *testing.T) {
|
|
raw := "A<think>B</think>C<|begin▁of▁sentence|>D<| begin_of_sentence |>E<|begin_of_sentence|>F"
|
|
got := sanitizeLeakedOutput(raw)
|
|
if got != "ABCDEF" {
|
|
t.Fatalf("unexpected sanitize result for think/BOS markers: %q", got)
|
|
}
|
|
}
|
|
|
|
func TestSanitizeLeakedOutputRemovesThoughtMarkers(t *testing.T) {
|
|
raw := "A<|▁of▁thought|>B<| of_thought |>C<| begin_of_thought |>D<| end_of_thought |>E"
|
|
got := sanitizeLeakedOutput(raw)
|
|
if got != "ABCDE" {
|
|
t.Fatalf("unexpected sanitize result for leaked thought markers: %q", got)
|
|
}
|
|
}
|
|
|
|
func TestSanitizeLeakedOutputRemovesDanglingThinkBlock(t *testing.T) {
|
|
raw := "Answer prefix<think>internal reasoning that never closes"
|
|
got := sanitizeLeakedOutput(raw)
|
|
if got != "Answer prefix" {
|
|
t.Fatalf("unexpected sanitize result for dangling think block: %q", got)
|
|
}
|
|
}
|
|
|
|
func TestSanitizeLeakedOutputRemovesCompleteDSMLToolCallWrapper(t *testing.T) {
|
|
raw := "前置文本\n<|DSML|tool_calls>\n<|DSML|invoke name=\"Bash\">\n<|DSML|parameter name=\"command\"></|DSML|parameter>\n</|DSML|invoke>\n</|DSML|tool_calls>\n后置文本"
|
|
got := sanitizeLeakedOutput(raw)
|
|
if got != "前置文本\n\n后置文本" {
|
|
t.Fatalf("unexpected sanitize result for leaked dsml wrapper: %q", got)
|
|
}
|
|
}
|
|
|
|
func TestSanitizeLeakedOutputRemovesAgentXMLLeaks(t *testing.T) {
|
|
raw := "Done.<attempt_completion><result>Some final answer</result></attempt_completion>"
|
|
got := sanitizeLeakedOutput(raw)
|
|
if got != "Done.Some final answer" {
|
|
t.Fatalf("unexpected sanitize result for agent XML leak: %q", got)
|
|
}
|
|
}
|
|
|
|
func TestSanitizeLeakedOutputPreservesStandaloneResultTags(t *testing.T) {
|
|
raw := "Example XML: <result>value</result>"
|
|
got := sanitizeLeakedOutput(raw)
|
|
if got != raw {
|
|
t.Fatalf("unexpected sanitize result for standalone result tag: %q", got)
|
|
}
|
|
}
|
|
|
|
func TestSanitizeLeakedOutputRemovesDanglingAgentXMLOpeningTags(t *testing.T) {
|
|
raw := "Done.<attempt_completion><result>Some final answer"
|
|
got := sanitizeLeakedOutput(raw)
|
|
if got != "Done.Some final answer" {
|
|
t.Fatalf("unexpected sanitize result for dangling opening tags: %q", got)
|
|
}
|
|
}
|
|
|
|
func TestSanitizeLeakedOutputRemovesDanglingAgentXMLClosingTags(t *testing.T) {
|
|
raw := "Done.Some final answer</result></attempt_completion>"
|
|
got := sanitizeLeakedOutput(raw)
|
|
if got != "Done.Some final answer" {
|
|
t.Fatalf("unexpected sanitize result for dangling closing tags: %q", got)
|
|
}
|
|
}
|
|
|
|
func TestSanitizeLeakedOutputPreservesUnrelatedResultTagsWhenWrapperLeaks(t *testing.T) {
|
|
raw := "Done.<attempt_completion><result>Some final answer\nExample XML: <result>value</result>"
|
|
got := sanitizeLeakedOutput(raw)
|
|
want := "Done.Some final answer\nExample XML: <result>value</result>"
|
|
if got != want {
|
|
t.Fatalf("unexpected sanitize result for mixed leaked wrapper + xml example: %q", got)
|
|
}
|
|
}
|