Skip to content

fix(ai-prompt-guard): check embeddings string arrays before forwarding - #14073

Merged
guoqqqi merged 5 commits into
apache:masterfrom
ruanweihong-aaa:codex/ai-prompt-guard-array-fix
Oct 29, 2026
Merged

guoqqqi merged 5 commits into
apache:masterfrom
ruanweihong-aaa:codex/ai-prompt-guard-array-fix

Conversation

@ruanweihong-aaa

@ruanweihong-aaa ruanweihong-aaa commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

Description

When ai-prompt-guard selects no messages, it returns an empty HTTP 200
without forwarding the request upstream.

PR #14006 fixes this early termination, but embeddings string arrays
still skip inspection because get_messages only extracts string inputs.
For example, with deny_patterns: ["secret"], the batch
{"input": ["secret", "hello"]} would be forwarded without being checked.

This PR:

  • Continues request processing when no messages are selected.
  • Reuses the existing embeddings text extractor to check all strings in
    a batch, keeping them together so the default last-message filter
    cannot discard earlier items.
  • Adds regression tests in a separate file.
  • Updates the English and Chinese documentation.

This follows the fix proposed in #14006 and addresses @Baoyuantop's
comments about array inspection and splitting the test file.

Fixes #13944.

Compatibility

No configuration changes are required. String inputs and chat
role/history filtering retain their existing behavior.

Embeddings string arrays now undergo the configured allow/deny checks.
Batch strings are joined with spaces and checked together: allow
patterns apply to the combined text, and any deny-pattern match rejects
the request.

Token-ID arrays are not decoded or inspected. Recognized requests with
no selected text continue processing even with fail_mode: "error",
which applies to unrecognized protocols.

Validation

  • New regression tests: 52 assertions pass; the same tests fail
    15 assertions against unmodified master.
  • Existing ai-prompt-guard tests: 170 assertions pass.
  • Real HTTP tests with a local mock upstream: 23 direct-upstream cases
    and 11 ai-proxy cases pass.
  • Changed-file Lua lint, test formatting, and git diff --check pass.
  • Full repository CI has not been run.

AlinsRan
AlinsRan previously approved these changes Oct 27, 2026
@guoqqqi
guoqqqi requested review from membphis and nic-6443 October 28, 2026 01:48
Comment thread apisix/plugins/ai-prompt-guard.lua Outdated
Comment on lines +147 to +154
-- A batch contains independent inputs, not conversation history. Keep
-- all its text in one user message so the last-message filter below
-- cannot discard earlier inputs.
local contents = protocols.get(proto_name).extract_request_content(json_body)
messages = {}
if #contents > 0 then
messages[1] = {role = "user", content = table.concat(contents, " ")}
end

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't the openai-response below the same? Can it be placed together with the existing judgment branches?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated in 8aa196b: Embeddings now shares the history-filtering condition with Responses, while retaining extraction and inspection of all batch strings. The embeddings and existing guard tests pass (52 + 170 assertions).

Comment thread apisix/plugins/ai-prompt-guard.lua Outdated
@guoqqqi
guoqqqi merged commit ef71358 into apache:master Oct 29, 2026
25 of 26 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug: ai-prompt-guard returns an empty 200 instead of proxying when no content is selected for checking

5 participants