diff --git a/CHANGELOG.md b/CHANGELOG.md index a214fd4..c34ec51 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,7 +15,7 @@ image and creates the GitHub release from this file. ### Added -- `POST /v1/responses` (the OpenAI Responses API) is redacted like `/v1/chat/completions`. Current OpenAI clients (`client.responses.create`, the Agents SDK, Codex) use it by default, and until now it passed through verbatim, so a modern OpenAI client pointed at cordon sent raw PII upstream with `X-Redacted: 0`. The request walk covers `instructions` (under `REDACT_SYSTEM`, with `system` and `developer` items), `input` as a string or an item list (`input_text` parts, `function_call` arguments as parsed JSON, `function_call_output` text) and flat function tool definitions; `input_image` and `input_file` parts are left untouched. Non-streaming replies restore `output_text` and `refusal` parts; streaming restores `response.output_text.delta` through the same hold-back buffer as chat, re-emitting each delta under its original `item_id` / `output_index` / `content_index`, and restores the full text carried by `output_text.done`, `content_part.done`, `output_item.done` and `response.completed`. Same modes, headers and audit record (provider `openai`). Sub-paths such as `/v1/responses/{id}` still pass through verbatim. +- `POST /v1/responses` (the OpenAI Responses API) is redacted like `/v1/chat/completions`. Current OpenAI clients (`client.responses.create`, the Agents SDK, Codex) use it by default, and until now it passed through verbatim, so a modern OpenAI client pointed at cordon sent raw PII upstream with `X-Redacted: 0`. The request walk covers `instructions` (under `REDACT_SYSTEM`, with `system` and `developer` items), `input` as a string or an item list (`input_text` parts, `function_call` arguments as parsed JSON, `function_call_output` text) and flat function tool definitions; `input_image` and `input_file` parts are left untouched. Non-streaming replies restore `output_text` and `refusal` parts; streaming restores `response.output_text.delta` and `response.refusal.delta` under their own event kind, giving EACH content part its own hold-back buffer keyed by `item_id` / `output_index` / `content_index` (parts of one turn interleave on the wire, and one shared buffer spliced their text together). A part is flushed on its own done frame; `output_item.done` flushes only the item it names; `response.completed` / `incomplete` / `failed`, `[DONE]`, a reader error and an upstream that stops without any terminal frame all flush whatever is still held. The full text carried by `output_text.done`, `content_part.done`, `output_item.done` and `response.completed` is restored in place. Prior assistant turns fed back as input (`output_text` and `refusal` parts) are redacted too: a stateless client appends the previous reply, which cordon had already restored. Same modes, headers and audit record (provider `openai`). Sub-paths such as `/v1/responses/{id}` still pass through verbatim. ## [0.2.1] - 2026-09-11 diff --git a/README.md b/README.md index 4957d6c..2af61ea 100644 --- a/README.md +++ b/README.md @@ -81,7 +81,7 @@ All four sets are on by default; narrow per tenant or per request with `X-Redact ## What it does not do - **Names, free-text addresses, medical conditions.** There is no NER. A person's name in prose passes through. The detector is an interface (`src/detect`), so a Presidio-style sidecar can be added; it is not included. -- **Embeddings, `count_tokens`, images.** Only the two generation endpoints (`/v1/chat/completions`, `/v1/messages`) are redacted; other `/v1/*` paths pass through verbatim. Image parts are left untouched. +- **Embeddings, `count_tokens`, images.** Only the three generation endpoints (`/v1/chat/completions`, `/v1/responses`, `/v1/messages`) are redacted; other `/v1/*` paths, including `/v1/responses/{id}`, pass through verbatim. Image and file parts are left untouched. - **Token counts.** Streaming usage figures are the provider's, computed on the de-identified text. If you need one of those, say so in an issue. The scope above is deliberate, not accidental.