diff --git a/crates/aether-ai/formats/src/formats/registry.rs b/crates/aether-ai/formats/src/formats/registry.rs index c845077e9..3f8e2ef4a 100644 --- a/crates/aether-ai/formats/src/formats/registry.rs +++ b/crates/aether-ai/formats/src/formats/registry.rs @@ -978,6 +978,7 @@ fn standard_request_root_field_is_audited(source: FormatId, key: &str) -> bool { FormatId::OpenAiResponses | FormatId::OpenAiResponsesCompact => matches!( key, "background" + | "client_metadata" | "context_management" | "conversation" | "include" @@ -1418,6 +1419,7 @@ fn request_extension_key_is_cross_format_safe( FormatId::OpenAiChat, "openai_responses" | "openai_cli", "stream" + | "client_metadata" | "store" | "service_tier" | "safety_identifier" @@ -3781,6 +3783,26 @@ mod tests { )); } + #[test] + fn pure_openai_responses_to_chat_ignores_client_transport_metadata() { + let body = json!({ + "model": "gpt-source", + "input": [{"role": "user", "content": "hello"}], + "client_metadata": { + "session_id": "session-123", + "thread_id": "thread-123" + } + }); + + let converted = convert_request_pure("openai:responses", "openai:chat", &body) + .expect("client transport metadata should not block cross-format conversion") + .value; + + assert_eq!(converted["model"], "gpt-source"); + assert_eq!(converted["messages"][0]["content"], "hello"); + assert!(converted.get("client_metadata").is_none()); + } + #[test] fn pure_cross_format_rejects_unknown_source_root_field() { let body = json!({ diff --git a/docs/api/format-conversion-audit.md b/docs/api/format-conversion-audit.md index c279d4f1f..3cdafba31 100644 --- a/docs/api/format-conversion-audit.md +++ b/docs/api/format-conversion-audit.md @@ -9,6 +9,7 @@ Statuses: - `native`: emitted as a target-native field without semantic change. - `mapped`: converted through canonical/provider-specific mapping. - `extension-preserved`: preserved in same-format canonical roundtrip or target-approved extension namespace. +- `transport-only`: audited client transport metadata intentionally omitted when the target has no compatible transport channel. - `unaudited`: rejected because the source field is not in the audited provider schema inventory for cross-format conversion. - `unsupported`: rejected because the request/field shape is outside the supported conversion surface, independent of schema drift. - `lossy-blocked`: conversion fails closed. @@ -83,6 +84,7 @@ Provider schema refresh is not a runtime dependency. Same-format runtime paths d | `top_p` | generation | `top_p` | native | | `top_logprobs` | generation | `top_logprobs` | native | | `metadata` | canonical metadata | `metadata` | native | +| `client_metadata` | Responses client transport metadata | none | transport-only; omitted | | `parallel_tool_calls` | canonical bool | `parallel_tool_calls` | native | | `text.format` | canonical response format | `response_format` | mapped | | `text.verbosity` | Responses extension | `verbosity` | mapped |