Skip to content

bug: ai-prompt plugins have protocol, template-context, and input-validation gaps #14155

Open

Description

@shreemaan-abhishek

Current Behavior\n\nReviewing the existing ai-prompt plugins exposed three problems that predate pull request #14139:\n\n1. ai-prompt-template always emits the configured Chat Completions-shaped object, regardless of the request protocol.\n\n- On /v1/messages, a configured system message remains inside messages, which Anthropic rejects.\n- On /model/.../converse, message content remains a string instead of Bedrock Converse content blocks.\n- On /v1/responses, the generated body has messages rather than input and instructions.\n\n2. Template evaluation inherits unsafe and surprising name-resolution behavior from the current body-transformer path.\n\n- Request fields can shadow Lua globals used by the compiled template. For example, a request field named table can break a template with an error about table.concat.\n- A false request value can fall through during lookup and render as an empty value.\n- An absent variable can resolve to a Lua global instead of being treated as missing.\n\n3. Malformed request shapes can raise Lua exceptions and return 500 responses.\n\n- A top-level JSON number or boolean reaches template_name indexing in ai-prompt-template.\n- A non-string template_name reaches string concatenation.\n- An Anthropic request with messages set to a string can reach ipairs in the protocol adapter.\n\nThese behaviors exist on the base branch without the changes from #14139. They are being tracked separately so fixes for newly introduced regressions in that pull request do not silently expand into an unrelated compatibility redesign.\n\n## Expected Behavior\n\n- ai-prompt-template should either serialize its canonical template into each explicitly supported protocol or reject unsupported protocols with a deterministic 4xx response. Its documented protocol scope should be explicit.\n- Template variable lookup should preserve false values, avoid collisions with runtime globals/helpers, and produce a clear client error for missing variables.\n- The prompt plugins and protocol matchers should validate top-level and nested request shapes before indexing or iterating them. Malformed client input should return a sanitized 4xx response rather than a Lua exception or 500.\n\n## Steps to Reproduce\n\nProtocol output:\n\n1. Configure ai-prompt-template with a template containing model and messages.\n2. Send template parameters through routes using /v1/messages, /model/test/converse, and /v1/responses.\n3. Observe that every generated body keeps the Chat Completions messages shape.\n\nTemplate context lookup:\n\n1. Configure a message containing Describe {{ table }}.\n2. Send a request containing a string field named table.\n3. Observe a 503 caused by the request value shadowing the Lua table global.\n4. Repeat with a false variable or a missing name and observe that the rendered value does not preserve the request semantics.\n\nMalformed input:\n\n1. Send a JSON number or boolean to an ai-prompt-template route.\n2. Send an object whose template_name is an object.\n3. Send an Anthropic-shaped request whose messages value is a string through ai-prompt-decorator.\n4. Observe Lua runtime errors and 500 responses instead of schema-style 4xx errors.\n\n## Acceptance Criteria\n\n- Define and document the protocol scope of ai-prompt-template.\n- Add protocol-specific output or explicit rejection tests for Anthropic Messages, Bedrock Converse, and OpenAI Responses.\n- Define safe variable-resolution semantics, including false and missing values and reserved names.\n- Validate top-level JSON objects, template_name, and protocol message containers before use.\n- Return sanitized 4xx errors for malformed client input.\n- Preserve compatibility intentionally or document and plan any required migration.\n\n## Environment\n\n- APISIX: current master before #14139\n- OpenResty: 1.25.3.2 in the local reproduction environment\n- Reproduced through source inspection and focused Lua tests; the malformed-shape paths are directly reachable in the current modules.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions