From 1b04e03cc4c7c23c216ae0f4830b593700b06eda Mon Sep 17 00:00:00 2001 From: spongehah <2635879218@qq.com> Date: Mon, 3 Aug 2026 17:38:04 +0800 Subject: [PATCH] fix(prompt-audit): parse responses output text --- .../internal/securityaudit/prompt_snapshot.go | 2 +- .../securityaudit/prompt_snapshot_test.go | 32 +++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/backend/internal/securityaudit/prompt_snapshot.go b/backend/internal/securityaudit/prompt_snapshot.go index c3219366f..b47e84674 100644 --- a/backend/internal/securityaudit/prompt_snapshot.go +++ b/backend/internal/securityaudit/prompt_snapshot.go @@ -419,7 +419,7 @@ func contentTexts(value any) []string { continue } typeName := strings.ToLower(stringValue(object["type"])) - if typeName != "" && typeName != "text" && typeName != "input_text" { + if typeName != "" && typeName != "text" && typeName != "input_text" && typeName != "output_text" { continue } if text := stringValue(object["text"]); text != "" { diff --git a/backend/internal/securityaudit/prompt_snapshot_test.go b/backend/internal/securityaudit/prompt_snapshot_test.go index 4802138cf..70d26f925 100644 --- a/backend/internal/securityaudit/prompt_snapshot_test.go +++ b/backend/internal/securityaudit/prompt_snapshot_test.go @@ -336,6 +336,38 @@ func TestBlockingPromptSnapshotLimitsInputToLatestUserAndPreviousOutput(t *testi } } +func TestContentTextsIncludesSupportedTextTypes(t *testing.T) { + value := []any{ + map[string]any{"type": "text", "text": "plain text"}, + map[string]any{"type": "input_text", "text": "input text"}, + map[string]any{"type": "output_text", "text": "output text"}, + map[string]any{"type": "image_url", "text": "ignored text"}, + } + + require.Equal(t, []string{"plain text", "input text", "output text"}, contentTexts(value)) +} + +func TestResponsesOutputTextIncludedInFullAndLatestTurnSnapshots(t *testing.T) { + body := []byte(`{"input":[ + {"type":"message","role":"user","content":[{"type":"input_text","text":"earlier user input"}]}, + {"type":"message","role":"assistant","status":"completed","content":[{"type":"output_text","annotations":[],"text":"captured previous assistant output"}]}, + {"type":"message","role":"user","content":[{"type":"input_text","text":"captured latest user input"}]} + ]}`) + + req := Request{Protocol: "openai_responses", Body: body} + full, err := ExtractPromptSnapshot(req) + require.NoError(t, err) + require.Contains(t, full.ScanText, "captured previous assistant output") + require.Contains(t, full.FullPrompt, "captured previous assistant output") + require.Equal(t, 3, full.MessageCount) + + latestTurn, err := ExtractBlockingPromptSnapshot(req, true) + require.NoError(t, err) + require.Equal(t, "captured latest user input"+promptAuditPrioritySeparator+"captured previous assistant output", latestTurn.ScanText) + require.Equal(t, 2, latestTurn.MessageCount) + require.NotContains(t, latestTurn.ScanText, "earlier user input") +} + func TestBlockingPromptSnapshotPreservesFullScopeByDefaultAndWithoutUserInput(t *testing.T) { req := Request{Protocol: "openai_chat_completions", Body: []byte(`{"messages":[{"role":"system","content":"system instruction"},{"role":"user","content":"older user input"},{"role":"assistant","content":"previous output"},{"role":"user","content":"latest user input"}]}`)} full, err := ExtractPromptSnapshot(req)