Preserve bio policy errors as a distinct non-retryable error (#46306)

## Why

Streaming `bio_policy` failures were classified as generic invalid requests, losing their policy-specific classification.

## What changed

- Add `BioPolicy` errors across the API and core protocol, recognizing streaming failures and HTTP 400 responses, including wrapped WebSocket errors.
- Preserve server messages and use a biological-risk fallback when the message is missing or blank.
- Treat bio policy errors as non-retryable in core and guardian handling, and classify them in diagnostics and telemetry.
- Map `BioPolicy` to `other` in the app-server v2 protocol.

## Testing

Add coverage for error classification, message preservation and fallbacks, HTTP and wrapped WebSocket responses, guardian retry decisions, and app-server conversion. Extend the core integration test to verify that bio policy failures emit a typed error and complete the turn after a single request.

GitOrigin-RevId: 78c2647e8fc8f80297cb8a23fff06ab141099632
This commit is contained in:
Rennie
2026-09-17 21:25:55 +00:00
committed by copyberry
parent 55db7e8c88
commit fa8cf44985
16 changed files with 146 additions and 24 deletions
@@ -129,6 +129,7 @@ impl From<CoreCodexErrorInfo> for CodexErrorInfo {
CoreCodexErrorInfo::RateLimitExceeded => CodexErrorInfo::RateLimitExceeded,
CoreCodexErrorInfo::ServerOverloaded => CodexErrorInfo::ServerOverloaded,
CoreCodexErrorInfo::CyberPolicy => CodexErrorInfo::CyberPolicy,
CoreCodexErrorInfo::BioPolicy => CodexErrorInfo::Other,
CoreCodexErrorInfo::MisalignmentPolicyViolation => {
CodexErrorInfo::MisalignmentPolicyViolation
}
@@ -4671,6 +4671,7 @@ fn codex_error_info_serializes_http_status_code_in_camel_case() {
fn core_error_info_converts_to_camel_case() {
for (core, expected) in [
(CoreCodexErrorInfo::CyberPolicy, json!("cyberPolicy")),
(CoreCodexErrorInfo::BioPolicy, json!("other")),
(
CoreCodexErrorInfo::RateLimitExceeded,
json!("rateLimitExceeded"),