mirror of
https://github.com/CJackHwang/ds2api.git
synced 2026-05-04 16:35:27 +08:00
Preserve suffix after non-tool XML passthrough
This commit is contained in:
@@ -74,7 +74,7 @@ func consumeXMLToolCapture(captured string, toolNames []string) (prefix string,
|
||||
// If this block does not look like an executable tool-call payload,
|
||||
// pass it through as normal content (e.g. user-requested XML snippets).
|
||||
if !looksLikeExecutableXMLToolCallBlock(xmlBlock, pair.open) {
|
||||
return captured, nil, "", true
|
||||
return prefixPart + xmlBlock, nil, suffixPart, true
|
||||
}
|
||||
// Looks like XML tool syntax but failed to parse — consume it to avoid leak.
|
||||
return prefixPart, nil, suffixPart, true
|
||||
|
||||
@@ -98,6 +98,29 @@ func TestProcessToolSievePassesThroughNonToolXMLBlock(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestProcessToolSieveNonToolXMLKeepsSuffixForToolParsing(t *testing.T) {
|
||||
var state toolStreamSieveState
|
||||
chunk := `<tool_call><title>plain xml</title></tool_call><invoke name="read_file"><parameters>{"path":"README.MD"}</parameters></invoke>`
|
||||
events := processToolSieveChunk(&state, chunk, []string{"read_file"})
|
||||
events = append(events, flushToolSieve(&state, []string{"read_file"})...)
|
||||
|
||||
var textContent strings.Builder
|
||||
toolCalls := 0
|
||||
for _, evt := range events {
|
||||
textContent.WriteString(evt.Content)
|
||||
toolCalls += len(evt.ToolCalls)
|
||||
}
|
||||
if !strings.Contains(textContent.String(), `<tool_call><title>plain xml</title></tool_call>`) {
|
||||
t.Fatalf("expected leading non-tool XML to be preserved, got %q", textContent.String())
|
||||
}
|
||||
if strings.Contains(textContent.String(), `<invoke name="read_file">`) {
|
||||
t.Fatalf("expected invoke tool XML to be intercepted, got %q", textContent.String())
|
||||
}
|
||||
if toolCalls != 1 {
|
||||
t.Fatalf("expected exactly one parsed tool call from suffix, got %d events=%#v", toolCalls, events)
|
||||
}
|
||||
}
|
||||
|
||||
func TestProcessToolSievePartialXMLTagHeldBack(t *testing.T) {
|
||||
var state toolStreamSieveState
|
||||
// Chunk ends with a partial XML tool tag.
|
||||
@@ -384,7 +407,7 @@ func TestOpeningXMLTagNotLeakedAsContent(t *testing.T) {
|
||||
|
||||
func TestProcessToolSieveInterceptsAttemptCompletionLeak(t *testing.T) {
|
||||
var state toolStreamSieveState
|
||||
// Simulate an agent outputting attempt_completion XML tag
|
||||
// Simulate an agent outputting attempt_completion XML tag
|
||||
// which shouldn't leak to text output, even if it fails to parse as a valid tool.
|
||||
chunks := []string{
|
||||
"Done with task.\n",
|
||||
|
||||
Reference in New Issue
Block a user