mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
feat: review in app server (#6613)
This commit is contained in:
@@ -1774,7 +1774,12 @@ async fn spawn_review_thread(
|
||||
text: review_prompt,
|
||||
}];
|
||||
let tc = Arc::new(review_turn_context);
|
||||
sess.spawn_task(tc.clone(), input, ReviewTask).await;
|
||||
sess.spawn_task(
|
||||
tc.clone(),
|
||||
input,
|
||||
ReviewTask::new(review_request.append_to_original_thread),
|
||||
)
|
||||
.await;
|
||||
|
||||
// Announce entering review mode so UIs can switch modes.
|
||||
sess.send_event(&tc, EventMsg::EnteredReviewMode(review_request))
|
||||
@@ -2780,7 +2785,8 @@ mod tests {
|
||||
let input = vec![UserInput::Text {
|
||||
text: "start review".to_string(),
|
||||
}];
|
||||
sess.spawn_task(Arc::clone(&tc), input, ReviewTask).await;
|
||||
sess.spawn_task(Arc::clone(&tc), input, ReviewTask::new(true))
|
||||
.await;
|
||||
|
||||
sess.abort_all_tasks(TurnAbortReason::Interrupted).await;
|
||||
|
||||
|
||||
@@ -23,8 +23,18 @@ use codex_protocol::user_input::UserInput;
|
||||
use super::SessionTask;
|
||||
use super::SessionTaskContext;
|
||||
|
||||
#[derive(Clone, Copy, Default)]
|
||||
pub(crate) struct ReviewTask;
|
||||
#[derive(Clone, Copy)]
|
||||
pub(crate) struct ReviewTask {
|
||||
append_to_original_thread: bool,
|
||||
}
|
||||
|
||||
impl ReviewTask {
|
||||
pub(crate) fn new(append_to_original_thread: bool) -> Self {
|
||||
Self {
|
||||
append_to_original_thread,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl SessionTask for ReviewTask {
|
||||
@@ -52,13 +62,25 @@ impl SessionTask for ReviewTask {
|
||||
None => None,
|
||||
};
|
||||
if !cancellation_token.is_cancelled() {
|
||||
exit_review_mode(session.clone_session(), output.clone(), ctx.clone()).await;
|
||||
exit_review_mode(
|
||||
session.clone_session(),
|
||||
output.clone(),
|
||||
ctx.clone(),
|
||||
self.append_to_original_thread,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
async fn abort(&self, session: Arc<SessionTaskContext>, ctx: Arc<TurnContext>) {
|
||||
exit_review_mode(session.clone_session(), None, ctx).await;
|
||||
exit_review_mode(
|
||||
session.clone_session(),
|
||||
None,
|
||||
ctx,
|
||||
self.append_to_original_thread,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -175,32 +197,35 @@ pub(crate) async fn exit_review_mode(
|
||||
session: Arc<Session>,
|
||||
review_output: Option<ReviewOutputEvent>,
|
||||
ctx: Arc<TurnContext>,
|
||||
append_to_original_thread: bool,
|
||||
) {
|
||||
let user_message = if let Some(out) = review_output.clone() {
|
||||
let mut findings_str = String::new();
|
||||
let text = out.overall_explanation.trim();
|
||||
if !text.is_empty() {
|
||||
findings_str.push_str(text);
|
||||
}
|
||||
if !out.findings.is_empty() {
|
||||
let block = format_review_findings_block(&out.findings, None);
|
||||
findings_str.push_str(&format!("\n{block}"));
|
||||
}
|
||||
crate::client_common::REVIEW_EXIT_SUCCESS_TMPL.replace("{results}", &findings_str)
|
||||
} else {
|
||||
crate::client_common::REVIEW_EXIT_INTERRUPTED_TMPL.to_string()
|
||||
};
|
||||
if append_to_original_thread {
|
||||
let user_message = if let Some(out) = review_output.clone() {
|
||||
let mut findings_str = String::new();
|
||||
let text = out.overall_explanation.trim();
|
||||
if !text.is_empty() {
|
||||
findings_str.push_str(text);
|
||||
}
|
||||
if !out.findings.is_empty() {
|
||||
let block = format_review_findings_block(&out.findings, None);
|
||||
findings_str.push_str(&format!("\n{block}"));
|
||||
}
|
||||
crate::client_common::REVIEW_EXIT_SUCCESS_TMPL.replace("{results}", &findings_str)
|
||||
} else {
|
||||
crate::client_common::REVIEW_EXIT_INTERRUPTED_TMPL.to_string()
|
||||
};
|
||||
|
||||
session
|
||||
.record_conversation_items(
|
||||
&ctx,
|
||||
&[ResponseItem::Message {
|
||||
id: None,
|
||||
role: "user".to_string(),
|
||||
content: vec![ContentItem::InputText { text: user_message }],
|
||||
}],
|
||||
)
|
||||
.await;
|
||||
session
|
||||
.record_conversation_items(
|
||||
&ctx,
|
||||
&[ResponseItem::Message {
|
||||
id: None,
|
||||
role: "user".to_string(),
|
||||
content: vec![ContentItem::InputText { text: user_message }],
|
||||
}],
|
||||
)
|
||||
.await;
|
||||
}
|
||||
session
|
||||
.send_event(
|
||||
ctx.as_ref(),
|
||||
|
||||
@@ -70,6 +70,7 @@ async fn codex_delegate_forwards_exec_approval_and_proceeds_on_approval() {
|
||||
review_request: ReviewRequest {
|
||||
prompt: "Please review".to_string(),
|
||||
user_facing_hint: "review".to_string(),
|
||||
append_to_original_thread: true,
|
||||
},
|
||||
})
|
||||
.await
|
||||
@@ -145,6 +146,7 @@ async fn codex_delegate_forwards_patch_approval_and_proceeds_on_decision() {
|
||||
review_request: ReviewRequest {
|
||||
prompt: "Please review".to_string(),
|
||||
user_facing_hint: "review".to_string(),
|
||||
append_to_original_thread: true,
|
||||
},
|
||||
})
|
||||
.await
|
||||
@@ -199,6 +201,7 @@ async fn codex_delegate_ignores_legacy_deltas() {
|
||||
review_request: ReviewRequest {
|
||||
prompt: "Please review".to_string(),
|
||||
user_facing_hint: "review".to_string(),
|
||||
append_to_original_thread: true,
|
||||
},
|
||||
})
|
||||
.await
|
||||
|
||||
@@ -82,6 +82,7 @@ async fn review_op_emits_lifecycle_and_review_output() {
|
||||
review_request: ReviewRequest {
|
||||
prompt: "Please review my changes".to_string(),
|
||||
user_facing_hint: "my changes".to_string(),
|
||||
append_to_original_thread: true,
|
||||
},
|
||||
})
|
||||
.await
|
||||
@@ -178,6 +179,7 @@ async fn review_op_with_plain_text_emits_review_fallback() {
|
||||
review_request: ReviewRequest {
|
||||
prompt: "Plain text review".to_string(),
|
||||
user_facing_hint: "plain text review".to_string(),
|
||||
append_to_original_thread: true,
|
||||
},
|
||||
})
|
||||
.await
|
||||
@@ -236,6 +238,7 @@ async fn review_filters_agent_message_related_events() {
|
||||
review_request: ReviewRequest {
|
||||
prompt: "Filter streaming events".to_string(),
|
||||
user_facing_hint: "Filter streaming events".to_string(),
|
||||
append_to_original_thread: true,
|
||||
},
|
||||
})
|
||||
.await
|
||||
@@ -320,6 +323,7 @@ async fn review_does_not_emit_agent_message_on_structured_output() {
|
||||
review_request: ReviewRequest {
|
||||
prompt: "check structured".to_string(),
|
||||
user_facing_hint: "check structured".to_string(),
|
||||
append_to_original_thread: true,
|
||||
},
|
||||
})
|
||||
.await
|
||||
@@ -373,6 +377,7 @@ async fn review_uses_custom_review_model_from_config() {
|
||||
review_request: ReviewRequest {
|
||||
prompt: "use custom model".to_string(),
|
||||
user_facing_hint: "use custom model".to_string(),
|
||||
append_to_original_thread: true,
|
||||
},
|
||||
})
|
||||
.await
|
||||
@@ -490,6 +495,7 @@ async fn review_input_isolated_from_parent_history() {
|
||||
review_request: ReviewRequest {
|
||||
prompt: review_prompt.clone(),
|
||||
user_facing_hint: review_prompt.clone(),
|
||||
append_to_original_thread: true,
|
||||
},
|
||||
})
|
||||
.await
|
||||
@@ -602,6 +608,7 @@ async fn review_history_does_not_leak_into_parent_session() {
|
||||
review_request: ReviewRequest {
|
||||
prompt: "Start a review".to_string(),
|
||||
user_facing_hint: "Start a review".to_string(),
|
||||
append_to_original_thread: true,
|
||||
},
|
||||
})
|
||||
.await
|
||||
|
||||
Reference in New Issue
Block a user