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
+2 -4
View File
@@ -19,10 +19,7 @@ pub struct ResponseDebugContext {
pub fn extract_response_debug_context(transport: &TransportError) -> ResponseDebugContext {
let mut context = ResponseDebugContext::default();
let TransportError::Http {
headers, body: _, ..
} = transport
else {
let TransportError::Http { headers, .. } = transport else {
return context;
};
@@ -85,6 +82,7 @@ pub fn telemetry_api_error_message(error: &ApiError) -> String {
ApiError::RateLimit(_) => "rate limit".to_string(),
ApiError::InvalidRequest { .. } => "invalid request".to_string(),
ApiError::CyberPolicy { .. } => "cyber policy".to_string(),
ApiError::BioPolicy { .. } => "bio policy".to_string(),
ApiError::MisalignmentPolicyViolation { .. } => "misalignment policy violation".to_string(),
ApiError::ServerOverloaded => "server overloaded".to_string(),
}