feat: add ai-peyeeye plugin for PII redaction & rehydration#13300
Open
tim-peyeeye wants to merge 1 commit intoapache:masterfrom
Open
feat: add ai-peyeeye plugin for PII redaction & rehydration#13300tim-peyeeye wants to merge 1 commit intoapache:masterfrom
tim-peyeeye wants to merge 1 commit intoapache:masterfrom
Conversation
Adds an `ai-peyeeye` AI plugin that redacts PII from prompts before they reach the upstream LLM and rehydrates the model's response so the client sees the original values. The plugin calls the peyeeye.ai HTTP API (`/v1/redact`, `/v1/rehydrate`, `DELETE /v1/sessions/<id>`) and is designed to sit alongside `ai-proxy` / `ai-proxy-multi` on the same route, at priority 1074 (ahead of `ai-proxy`'s 1040). Behavior invariants: - Length-guard: if `/v1/redact` returns a different number of texts than were sent, or returns an unexpected response shape, the request is failed with HTTP 500. Unredacted text is never forwarded upstream. - Auth required: missing `api_key` (in config or `PEYEEYE_API_KEY` env var) fails schema validation. - Best-effort rehydrate: if `/v1/rehydrate` fails the redacted output is preserved rather than risking PII leakage. - Best-effort cleanup: stateful sessions are `DELETE`'d after rehydrate; failures are logged only. Two session modes are supported: `stateful` (default; peyeeye holds the token-to-value map under a `ses_…` id) and `stateless` (peyeeye returns a sealed `skey_…` blob and retains nothing). Includes English and Chinese documentation, plugin registration in `apisix/cli/config.lua`, `conf/config.yaml.example`, the docs sidebars, and the admin plugin list (`t/admin/plugins.t`). Plugin tests under `t/plugin/ai-peyeeye.t` mock the peyeeye HTTP API and a fake LLM upstream so they run with no external dependencies, exercising: schema validation (3 cases), the stateful redact+rehydrate end-to-end flow, the stateless mode, the length-guard branch, the unexpected-response-shape branch, and the empty-body short-circuit.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this PR adds
A new AI plugin,
ai-peyeeye, that performs PII redaction on the request body sent upstream to an LLM and rehydrates the LLM's response before it reaches the client. It is designed to sit alongsideai-proxy/ai-proxy-multion the same route, at priority1074(ahead ofai-proxy's1040), and calls the peyeeye.ai HTTP API:POST /v1/redact— pre-call, replaces detected entities with deterministic tokens (e.g.[EMAIL_1],[CARD_2]).POST /v1/rehydrate— post-call, swaps the tokens in the LLM's response back to the original values.DELETE /v1/sessions/<id>— best-effort cleanup for stateful sessions.Behavior
accessphase): extracts text from the OpenAI-stylemessages[].contentarray (string or content-parttext), batches it to/v1/redact, and rewrites the body in place. The detection engine is regex + checksum-validated (Luhn for cards, mod-97 for IBAN, SSN/IP shape) on the peyeeye side, so the gateway just sends/receives strings.body_filterphase): buffers the upstream response, then calls/v1/rehydratewith the buffered body and the session id (or sealedskey_…blob).stateful(default): peyeeye returns ases_…session id; the plugin stores it on the request context andDELETEs it after rehydrate.stateless: peyeeye returns an AES-GCM-sealedskey_…blob containing the token map; nothing is retained server-side./v1/redactreturns a different number of texts than were sent, the request is failed with HTTP 500. Unredacted text is never forwarded upstream./v1/redactreturns an unexpected response shape (missingtexts, missing session/key for the chosen mode), the request is failed with HTTP 500./v1/rehydratefails (network, 5xx), the redacted output is preserved rather than risking PII leakage by falling back to the raw upstream response.api_key(in config orPEYEEYE_API_KEYenv var) fails schema validation.Files added
apisix/plugins/ai-peyeeye.lua— the plugin (546 lines)apisix/cli/config.lua— registration in the default plugin listconf/config.yaml.example— example entryt/admin/plugins.t— admin plugin list assertiont/plugin/ai-peyeeye.t— test suite (445 lines), follows theai-prompt-guard/ai-aliyun-content-moderationpattern: mocks the peyeeye HTTP API and a fake LLM upstream so the tests have no external dependencies. Covers:skey_…)docs/en/latest/plugins/ai-peyeeye.md+docs/en/latest/config.jsondocs/zh/latest/plugins/ai-peyeeye.md+docs/zh/latest/config.jsonTest status — please read
I want to be transparent here: I was not able to run
t/plugin/ai-peyeeye.tlocally, because APISIX's test framework requires a customapisix-runtimebuild (custom OpenResty plus atoolkit.jsonLua module) that I could not reproduce on macOS —toolkit.jsonis not packaged in any public OpenResty/LuaRocks artifact I could find, and themake depspath against stock OpenResty fails before the test runner can start. I'm relying on this PR's CI (apache/apisix's test workflow) to actually exercise the suite.Static checks that did pass locally:
luacheck apisix/plugins/ai-peyeeye.lua t/plugin/ai-peyeeye.t— clean, no warnings.luajit -bl apisix/plugins/ai-peyeeye.lua— parses cleanly (no syntax errors).If CI surfaces issues, I'll iterate on this PR. If a maintainer can point me at a working local test setup for macOS (or a CI job I can self-trigger on the fork), I'd appreciate it.