diff --git a/internal/adapter/openai/chat_stream_runtime.go b/internal/adapter/openai/chat_stream_runtime.go index 03ed429..3a25f79 100644 --- a/internal/adapter/openai/chat_stream_runtime.go +++ b/internal/adapter/openai/chat_stream_runtime.go @@ -97,7 +97,7 @@ func (s *chatStreamRuntime) sendDone() { func (s *chatStreamRuntime) finalize(finishReason string) { finalThinking := s.thinking.String() - finalText := sanitizeLeakedToolHistory(s.text.String()) + finalText := sanitizeLeakedOutput(s.text.String()) detected := util.ParseStandaloneToolCallsDetailed(finalText, s.toolNames) if len(detected.Calls) > 0 && !s.toolCallsDoneEmitted { finishReason = "tool_calls" @@ -141,7 +141,7 @@ func (s *chatStreamRuntime) finalize(finishReason string) { if evt.Content == "" { continue } - cleaned := sanitizeLeakedToolHistory(evt.Content) + cleaned := sanitizeLeakedOutput(evt.Content) if cleaned == "" { continue } @@ -250,7 +250,7 @@ func (s *chatStreamRuntime) onParsed(parsed sse.LineResult) streamengine.ParsedD continue } if evt.Content != "" { - cleaned := sanitizeLeakedToolHistory(evt.Content) + cleaned := sanitizeLeakedOutput(evt.Content) if cleaned == "" { continue } diff --git a/internal/adapter/openai/handler_chat.go b/internal/adapter/openai/handler_chat.go index 5f4668f..8847097 100644 --- a/internal/adapter/openai/handler_chat.go +++ b/internal/adapter/openai/handler_chat.go @@ -105,7 +105,7 @@ func (h *Handler) handleNonStream(w http.ResponseWriter, ctx context.Context, re result := sse.CollectStream(resp, thinkingEnabled, true) finalThinking := result.Thinking - finalText := sanitizeLeakedToolHistory(result.Text) + finalText := sanitizeLeakedOutput(result.Text) respBody := openaifmt.BuildChatCompletion(completionID, model, finalPrompt, finalThinking, finalText, toolNames) writeJSON(w, http.StatusOK, respBody) } diff --git a/internal/adapter/openai/tool_history_sanitize.go b/internal/adapter/openai/leaked_output_sanitize.go similarity index 96% rename from internal/adapter/openai/tool_history_sanitize.go rename to internal/adapter/openai/leaked_output_sanitize.go index fde447e..bb06d4d 100644 --- a/internal/adapter/openai/tool_history_sanitize.go +++ b/internal/adapter/openai/leaked_output_sanitize.go @@ -17,7 +17,7 @@ var leakedMetaMarkerPattern = regexp.MustCompile(`(?i)<[|\|]\s*(?:assistant|to // the sieve fails to capture them (e.g. incomplete blocks at stream end). var leakedAgentXMLPattern = regexp.MustCompile(`(?is)`) -func sanitizeLeakedToolHistory(text string) string { +func sanitizeLeakedOutput(text string) string { if text == "" { return text } diff --git a/internal/adapter/openai/tool_history_sanitize_test.go b/internal/adapter/openai/leaked_output_sanitize_test.go similarity index 67% rename from internal/adapter/openai/tool_history_sanitize_test.go rename to internal/adapter/openai/leaked_output_sanitize_test.go index 69063a2..12e3137 100644 --- a/internal/adapter/openai/tool_history_sanitize_test.go +++ b/internal/adapter/openai/leaked_output_sanitize_test.go @@ -2,33 +2,33 @@ package openai import "testing" -func TestSanitizeLeakedToolHistoryRemovesEmptyJSONFence(t *testing.T) { +func TestSanitizeLeakedOutputRemovesEmptyJSONFence(t *testing.T) { raw := "before\n```json\n```\nafter" - got := sanitizeLeakedToolHistory(raw) + got := sanitizeLeakedOutput(raw) if got != "before\n\nafter" { t.Fatalf("unexpected sanitized empty json fence: %q", got) } } -func TestSanitizeLeakedToolHistoryRemovesLeakedWireToolCallAndResult(t *testing.T) { +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 := sanitizeLeakedToolHistory(raw) + got := sanitizeLeakedOutput(raw) if got != "开始\n\n结束" { t.Fatalf("unexpected sanitize result for leaked wire format: %q", got) } } -func TestSanitizeLeakedToolHistoryRemovesStandaloneMetaMarkers(t *testing.T) { +func TestSanitizeLeakedOutputRemovesStandaloneMetaMarkers(t *testing.T) { raw := "A<| end_of_sentence |><| Assistant |>B<| end_of_thinking |>C<|end▁of▁thinking|>D<|end▁of▁sentence|>E" - got := sanitizeLeakedToolHistory(raw) + got := sanitizeLeakedOutput(raw) if got != "ABCDE" { t.Fatalf("unexpected sanitize result for meta markers: %q", got) } } -func TestSanitizeLeakedToolHistoryRemovesAgentXMLLeaks(t *testing.T) { +func TestSanitizeLeakedOutputRemovesAgentXMLLeaks(t *testing.T) { raw := "Done.Some final answer" - got := sanitizeLeakedToolHistory(raw) + got := sanitizeLeakedOutput(raw) if got != "Done.Some final answer" { t.Fatalf("unexpected sanitize result for agent XML leak: %q", got) } diff --git a/internal/adapter/openai/responses_handler.go b/internal/adapter/openai/responses_handler.go index dafd9a7..a7d0828 100644 --- a/internal/adapter/openai/responses_handler.go +++ b/internal/adapter/openai/responses_handler.go @@ -113,7 +113,7 @@ func (h *Handler) handleResponsesNonStream(w http.ResponseWriter, resp *http.Res return } result := sse.CollectStream(resp, thinkingEnabled, true) - sanitizedText := sanitizeLeakedToolHistory(result.Text) + sanitizedText := sanitizeLeakedOutput(result.Text) textParsed := util.ParseStandaloneToolCallsDetailed(sanitizedText, toolNames) logResponsesToolPolicyRejection(traceID, toolChoice, textParsed, "text") diff --git a/internal/adapter/openai/responses_stream_runtime_core.go b/internal/adapter/openai/responses_stream_runtime_core.go index 727bae0..460ce2a 100644 --- a/internal/adapter/openai/responses_stream_runtime_core.go +++ b/internal/adapter/openai/responses_stream_runtime_core.go @@ -97,7 +97,7 @@ func newResponsesStreamRuntime( func (s *responsesStreamRuntime) finalize() { finalThinking := s.thinking.String() - finalText := sanitizeLeakedToolHistory(s.text.String()) + finalText := sanitizeLeakedOutput(s.text.String()) if s.bufferToolContent { s.processToolStreamEvents(flushToolSieve(&s.sieve, s.toolNames), true) @@ -194,7 +194,7 @@ func (s *responsesStreamRuntime) onParsed(parsed sse.LineResult) streamengine.Pa continue } - cleanedText := sanitizeLeakedToolHistory(p.Text) + cleanedText := sanitizeLeakedOutput(p.Text) if cleanedText == "" { continue }