feat(body-rules): 支持按 provider_type 覆盖 cache-sensitive 保护字段集合

Codex 通过 OpenAI CLI/Compact 格式转发时,endpoint body_rules 需要能
修改 instructions/input/tools 等 prompt 字段。新增 provider_type 维度的
保护集合映射,Codex 场景仅保护 prompt_cache_key,其余 prompt 字段交由
body_rules 自由调整。
This commit is contained in:
fawney19
2026-03-17 17:09:39 +08:00
parent c4bb6b8161
commit c1ed42fd3a
7 changed files with 98 additions and 7 deletions

View File

@@ -279,6 +279,37 @@ def test_codex_passthrough_builder_preserves_real_codex_headers() -> None:
assert "x-forwarded-scheme" not in headers
def test_codex_passthrough_builder_applies_prompt_body_rules() -> None:
from src.api.handlers.base.request_builder import get_cache_sensitive_protected_body_keys
from src.core.api_format.metadata import CODEX_DEFAULT_BODY_RULES
builder = PassthroughRequestBuilder()
endpoint = SimpleNamespace(
api_family="openai",
endpoint_kind="cli",
header_rules=None,
body_rules=list(CODEX_DEFAULT_BODY_RULES),
)
key = SimpleNamespace(api_key="unused")
payload, _headers = builder.build(
{"model": "gpt-test", "input": []},
{"content-type": "application/json"},
endpoint,
key,
pre_computed_auth=("Authorization", "Bearer upstream-token"),
protected_body_keys=get_cache_sensitive_protected_body_keys(
"openai:cli",
provider_type="codex",
),
provider_api_format="openai:cli",
)
assert payload["instructions"] == "You are GPT-5."
assert payload["store"] is False
assert "max_output_tokens" not in payload
def _encode_unsigned_jwt(payload: dict[str, object]) -> str:
token = jwt.encode(payload, key="", algorithm="none")
return token.decode("utf-8") if isinstance(token, bytes) else token

View File

@@ -1532,6 +1532,14 @@ class TestProtectedBodyKeys:
"prompt_cache_key",
}
)
assert get_cache_sensitive_protected_body_keys(
"openai:cli",
provider_type="codex",
) == frozenset({"model", "stream", "prompt_cache_key"})
assert get_cache_sensitive_protected_body_keys(
"openai:compact",
provider_type="codex",
) == frozenset({"model", "stream", "prompt_cache_key"})
assert get_cache_sensitive_protected_body_keys("claude:chat") == frozenset(
{"model", "stream", "messages", "system", "tools", "tool_choice"}
)
@@ -1550,6 +1558,30 @@ class TestProtectedBodyKeys:
}
)
def test_codex_openai_cli_allows_body_rules_on_prompt_fields(self) -> None:
body = {
"model": "gpt-5-codex",
"input": [{"role": "user", "content": "hi"}],
}
protected_keys = get_cache_sensitive_protected_body_keys(
"openai:cli",
provider_type="codex",
)
result = apply_body_rules(
body,
[
{"action": "set", "path": "instructions", "value": "You are GPT-5."},
{"action": "set", "path": "input[0].content", "value": "patched"},
{"action": "set", "path": "prompt_cache_key", "value": "blocked"},
],
protected_keys=protected_keys,
)
assert result["instructions"] == "You are GPT-5."
assert result["input"][0]["content"] == "patched"
assert "prompt_cache_key" not in result
def test_gemini_camelcase_alias_prompt_fields_are_protected(self) -> None:
body = {
"contents": [{"role": "user", "parts": [{"text": "hi"}]}],