mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
ecfe174d5f
## Why Clients running an app-server on one OS and an exec-server on another OS need to be able to pass sandbox config to app-server that refers to resources on the executor's foreign OS. ## What `AbsolutePathBuf` can't represent these paths and we don't want users to be exposed to `PathUri` yet, so this moves the public app-server API to be expressed in terms of `ApiPathString`. Stacked on #28165. - change app-server v2 filesystem permission paths, including legacy read/write roots, to `ApiPathString` - localize API paths through `PathUri` when converting into the current native core permission types - make path-bearing permission conversions fallible and surface localization failures instead of silently treating malformed grants as ordinary denials - propagate conversion failures through app-server and TUI approval handling - regenerate the app-server JSON and TypeScript schemas - leave migration TODOs on native-path conversions so they can be removed once core permission paths use `PathUri`
169 lines
7.1 KiB
Rust
169 lines
7.1 KiB
Rust
//! App-server request and notification dispatch for `ChatWidget`.
|
|
//!
|
|
//! This module translates protocol requests into the focused chat-widget flows
|
|
//! that render approvals, permissions, tool input, and guardian reviews.
|
|
|
|
use super::*;
|
|
|
|
impl ChatWidget {
|
|
pub(crate) fn handle_server_request(
|
|
&mut self,
|
|
request: ServerRequest,
|
|
replay_kind: Option<ReplayKind>,
|
|
) {
|
|
let id = request.id().to_string();
|
|
match request {
|
|
ServerRequest::CommandExecutionRequestApproval { params, .. } => {
|
|
let fallback_cwd = self.config.cwd.clone();
|
|
self.on_exec_approval_request(
|
|
id,
|
|
exec_approval_request_from_params(params, &fallback_cwd),
|
|
);
|
|
}
|
|
ServerRequest::FileChangeRequestApproval { params, .. } => {
|
|
self.on_apply_patch_approval_request(
|
|
id,
|
|
patch_approval_request_from_params(params),
|
|
);
|
|
}
|
|
ServerRequest::McpServerElicitationRequest { request_id, params } => {
|
|
self.on_elicitation_request(request_id, params);
|
|
}
|
|
ServerRequest::PermissionsRequestApproval { params, .. } => {
|
|
// TODO(anp): Remove this native-path localization error path once core permission
|
|
// paths remain PathUri after crossing the app-server boundary.
|
|
match request_permissions_from_params(params) {
|
|
Ok(event) => self.on_request_permissions(event),
|
|
Err(err) => {
|
|
self.add_error_message(format!(
|
|
"failed to localize requested filesystem paths: {err}"
|
|
));
|
|
}
|
|
}
|
|
}
|
|
ServerRequest::ToolRequestUserInput { params, .. } => {
|
|
self.on_request_user_input(params);
|
|
}
|
|
ServerRequest::DynamicToolCall { .. }
|
|
| ServerRequest::AttestationGenerate { .. }
|
|
| ServerRequest::ChatgptAuthTokensRefresh { .. }
|
|
| ServerRequest::ApplyPatchApproval { .. }
|
|
| ServerRequest::ExecCommandApproval { .. } => {
|
|
if replay_kind.is_none() {
|
|
self.add_error_message(TUI_STUB_MESSAGE.to_string());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
pub(crate) fn handle_skills_list_response(&mut self, response: SkillsListResponse) {
|
|
self.on_list_skills(response);
|
|
}
|
|
|
|
pub(super) fn on_patch_apply_output_delta(&mut self, _item_id: String, _delta: String) {}
|
|
|
|
pub(super) fn on_guardian_review_notification(
|
|
&mut self,
|
|
id: String,
|
|
turn_id: String,
|
|
started_at_ms: i64,
|
|
review: codex_app_server_protocol::GuardianApprovalReview,
|
|
completion: Option<(i64, codex_app_server_protocol::AutoReviewDecisionSource)>,
|
|
action: GuardianApprovalReviewAction,
|
|
) {
|
|
// TODO(anp): Remove this native-path localization error path once core permission paths
|
|
// remain PathUri after crossing the app-server boundary.
|
|
let action = match action.try_into() {
|
|
Ok(action) => action,
|
|
Err(err) => {
|
|
self.add_error_message(format!(
|
|
"failed to localize guardian filesystem paths: {err}"
|
|
));
|
|
return;
|
|
}
|
|
};
|
|
let (completed_at_ms, decision_source) = match completion {
|
|
Some((completed_at_ms, decision_source)) => {
|
|
(Some(completed_at_ms), Some(decision_source))
|
|
}
|
|
None => (None, None),
|
|
};
|
|
|
|
self.on_guardian_assessment(GuardianAssessmentEvent {
|
|
id,
|
|
target_item_id: None,
|
|
turn_id,
|
|
started_at_ms,
|
|
completed_at_ms,
|
|
status: match review.status {
|
|
codex_app_server_protocol::GuardianApprovalReviewStatus::InProgress => {
|
|
GuardianAssessmentStatus::InProgress
|
|
}
|
|
codex_app_server_protocol::GuardianApprovalReviewStatus::Approved => {
|
|
GuardianAssessmentStatus::Approved
|
|
}
|
|
codex_app_server_protocol::GuardianApprovalReviewStatus::Denied => {
|
|
GuardianAssessmentStatus::Denied
|
|
}
|
|
codex_app_server_protocol::GuardianApprovalReviewStatus::TimedOut => {
|
|
GuardianAssessmentStatus::TimedOut
|
|
}
|
|
codex_app_server_protocol::GuardianApprovalReviewStatus::Aborted => {
|
|
GuardianAssessmentStatus::Aborted
|
|
}
|
|
},
|
|
risk_level: review.risk_level.map(|risk_level| match risk_level {
|
|
codex_app_server_protocol::GuardianRiskLevel::Low => {
|
|
codex_protocol::approvals::GuardianRiskLevel::Low
|
|
}
|
|
codex_app_server_protocol::GuardianRiskLevel::Medium => {
|
|
codex_protocol::approvals::GuardianRiskLevel::Medium
|
|
}
|
|
codex_app_server_protocol::GuardianRiskLevel::High => {
|
|
codex_protocol::approvals::GuardianRiskLevel::High
|
|
}
|
|
codex_app_server_protocol::GuardianRiskLevel::Critical => {
|
|
codex_protocol::approvals::GuardianRiskLevel::Critical
|
|
}
|
|
}),
|
|
user_authorization: review.user_authorization.map(|user_authorization| {
|
|
match user_authorization {
|
|
codex_app_server_protocol::GuardianUserAuthorization::Unknown => {
|
|
codex_protocol::approvals::GuardianUserAuthorization::Unknown
|
|
}
|
|
codex_app_server_protocol::GuardianUserAuthorization::Low => {
|
|
codex_protocol::approvals::GuardianUserAuthorization::Low
|
|
}
|
|
codex_app_server_protocol::GuardianUserAuthorization::Medium => {
|
|
codex_protocol::approvals::GuardianUserAuthorization::Medium
|
|
}
|
|
codex_app_server_protocol::GuardianUserAuthorization::High => {
|
|
codex_protocol::approvals::GuardianUserAuthorization::High
|
|
}
|
|
}
|
|
}),
|
|
rationale: review.rationale,
|
|
decision_source: decision_source.map(|source| match source {
|
|
codex_app_server_protocol::AutoReviewDecisionSource::Agent => {
|
|
GuardianAssessmentDecisionSource::Agent
|
|
}
|
|
}),
|
|
action,
|
|
});
|
|
}
|
|
|
|
pub(super) fn on_shutdown_complete(&mut self) {
|
|
self.request_immediate_exit();
|
|
}
|
|
|
|
pub(super) fn on_turn_diff(&mut self, unified_diff: String) {
|
|
debug!("TurnDiffEvent: {unified_diff}");
|
|
self.refresh_status_line();
|
|
}
|
|
|
|
pub(super) fn on_deprecation_notice(&mut self, summary: String, details: Option<String>) {
|
|
self.add_to_history(history_cell::new_deprecation_notice(summary, details));
|
|
self.request_redraw();
|
|
}
|
|
}
|