PHI-safe chat completion (OpenAI-compatible)
An OpenAI-compatible chat completion endpoint that redacts PHI before the model sees it and restores the real values in the answer.
client = OpenAI(base_url="https://<host>/api/v1/llm", api_key="hpx_...")
client.chat.completions.create(model="<model>", messages=[...])
Per request: your message content is redacted (Malaysian IC/MRN/passport/phone, names, emails, account numbers — clinical content such as ages, dates like “day 3 post-op”, vitals and dosages is preserved), the placeholders go to the model, and the model’s answer has your values substituted back. The mapping lives only in the request’s memory and is never stored.
Every response carries redaction_receipt, including rehydration_complete
and unresolved_placeholder_count — if the model altered our placeholders, the
receipt says so rather than returning residue silently.
Tool calling is supported: send OpenAI-style tools, receive tool_calls
with your values re-hydrated. Your tool role results are redacted on the way
out like any other message, and so are the arguments of an assistant turn you
send back.
Not supported (refused, not silently dropped): streaming while re-hydrating
(stream with redact_only=false), tools combined with stream, non-text
content parts, forcing a specific tool via tool_choice, and the deprecated
functions/function_call form.
Authorizations
Your hpx_ API key as a Bearer token, so OpenAI-compatible SDKs work unmodified. X-API-Key and first-party JWTs are also accepted.
Body
A model id from the registry. External keys may only use models approved for PHI traffic.
11 <= x <= 320001Reasoning-model controls, e.g. {"effort": "high", "summary": "detailed"}. Only effort and summary are forwarded; other keys are ignored. Applies to the GPT-5.x family; ignored by other models.
Return the model's answer WITHOUT substituting your values back (placeholders remain). Required if you want streaming, and useful when the answer is going somewhere that should not hold PHI.
OpenAI-style function tools. Forwarded to the model; returned tool_calls come back with your values re-hydrated.
"auto" (default) or "none". Forcing a specific call ("required", or a named function) is refused rather than downgraded to "auto", so a forced call never appears to have been honoured when it was not.
Supply the same value across turns so a given person keeps the same placeholder; multi-turn clients resend history and renaming mid-conversation confuses the model.
200Response
chat.completion with a redaction receipt attached

