Propagate approval rejection reasons (#34400)

## What changed

- Change `ReviewDecision::Denied` to carry a rejection string and update the generated protocol schemas.
- Preserve specific rejection reasons through command, patch, network, MCP, delegated, and automatic approval flows so tool results can return them to the model.
- Distinguish invalid approval responses from user declines and truncate oversized rejection messages before adding them to model context.

## Testing

- Add coverage for denial serialization, invalid app-server approval responses, dropped automatic reviews, network rejection propagation, and rejection-message truncation.

GitOrigin-RevId: d48a55643aa03c7ecfa08a8e4b669913eec5464a
This commit is contained in:
Dylan Hurd authored and copyberry committed 2026-07-20 19:23:21 +00:00
1 parent 8c41ed33ce
commit e52c35b000
36 files changed
+499 -452

No files matched your search

+12
View File
@@ -34,9 +34,21 @@ use pretty_assertions::assert_eq;
use std::collections::HashMap;
use std::sync::Arc;
use tokio::sync::Mutex;
use tokio::sync::oneshot;
use tokio::sync::watch;
use tokio::time::timeout;
#[tokio::test]
async fn dropped_approval_review_fails_closed() {
let (tx, rx) = oneshot::channel();
drop(tx);
assert_eq!(
receive_approval_review(rx).await,
ReviewDecision::denied("automatic approval review could not complete")
);
}
#[tokio::test]
async fn forward_events_filters_private_events_before_blocked_send_is_cancelled() {
let (tx_events, rx_events) = bounded(SUBMISSION_CHANNEL_CAPACITY);