mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
Chore: update plan mode output in prompt (#9592)
### Summary * Update plan prompt output * Update requestUserInput response to be a single key value pair `answer: String`.
This commit is contained in:
committed by
GitHub
Unverified
parent
f2e1ad59bc
commit
3fcb40245e
@@ -2327,8 +2327,7 @@ pub struct ToolRequestUserInputParams {
|
||||
#[ts(export_to = "v2/")]
|
||||
/// EXPERIMENTAL. Captures a user's answer to a request_user_input question.
|
||||
pub struct ToolRequestUserInputAnswer {
|
||||
pub selected: Vec<String>,
|
||||
pub other: Option<String>,
|
||||
pub answers: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
|
||||
@@ -1445,8 +1445,7 @@ async fn on_request_user_input_response(
|
||||
(
|
||||
id,
|
||||
CoreRequestUserInputAnswer {
|
||||
selected: answer.selected,
|
||||
other: answer.other,
|
||||
answers: answer.answers,
|
||||
},
|
||||
)
|
||||
})
|
||||
|
||||
@@ -87,7 +87,7 @@ async fn request_user_input_round_trip() -> Result<()> {
|
||||
request_id,
|
||||
serde_json::json!({
|
||||
"answers": {
|
||||
"confirm_path": { "selected": ["yes"], "other": serde_json::Value::Null }
|
||||
"confirm_path": { "answers": ["yes"] }
|
||||
}
|
||||
}),
|
||||
)
|
||||
|
||||
@@ -33,7 +33,7 @@ Example: "I checked the readme and searched for the feature you mentioned, but d
|
||||
|
||||
Use `request_user_input` only when you are genuinely blocked on a decision that materially changes the plan (requirements, trade-offs, rollout or risk posture).The maximum number of `request_user_input` tool calls should be **5**.
|
||||
|
||||
Only include an "Other" option when a free-form answer is truly useful. If the question is purely free-form, leave `options` unset entirely.
|
||||
**The options should be mutually exclusive.** Only include an "Other" option when a free-form answer is truly useful. If the question is purely free-form, leave `options` unset entirely.
|
||||
|
||||
Do **not** use `request_user_input` to ask "is my plan ready?" or "should I proceed?".
|
||||
|
||||
@@ -112,22 +112,12 @@ A well written and informative plan should be as detailed as a design doc or PRD
|
||||
|
||||
- tools and frameworks you use, any dependencies you need to install
|
||||
- functions, files, or directories you're likely going to edit
|
||||
- QUestions that were asked and the responses from users
|
||||
- Questions that were asked and the responses from users
|
||||
- architecture if the code changes are significant
|
||||
- if developing features, describe the features you are going to build in detail like a PM in a PRD
|
||||
- if you are developing a frontend, describe the design in detail
|
||||
- include a list of todos in markdown format if needed. Please do not include a **plan** step given that we are planning here already
|
||||
|
||||
### Output schema - — MUST MATCH _exactly_
|
||||
### Plan output
|
||||
|
||||
When you present the plan, format the final response as a JSON object with a single key, `plan`, whose value is the full plan text.
|
||||
|
||||
Example:
|
||||
|
||||
```json
|
||||
{
|
||||
"plan": "Title: Schema migration rollout\n\n1. Validate the current schema on staging...\n2. Add the new columns with nullable defaults...\n3. Backfill in batches with feature-flagged writes...\n4. Flip reads to the new fields and monitor...\n5. Remove legacy columns after one full release cycle..."
|
||||
}
|
||||
```
|
||||
|
||||
PLEASE DO NOT confirm the plan with the user before ending. The user will be responsible for telling us to update, iterate or execute the plan.
|
||||
**The final output should contain the plan and plan only with a good title.** PLEASE DO NOT confirm the plan with the user before ending. The user will be responsible for telling us to update, iterate or execute the plan. The
|
||||
|
||||
@@ -152,8 +152,7 @@ async fn request_user_input_round_trip_resolves_pending() -> anyhow::Result<()>
|
||||
answers.insert(
|
||||
"confirm_path".to_string(),
|
||||
RequestUserInputAnswer {
|
||||
selected: vec!["yes".to_string()],
|
||||
other: None,
|
||||
answers: vec!["yes".to_string()],
|
||||
},
|
||||
);
|
||||
let response = RequestUserInputResponse { answers };
|
||||
@@ -173,7 +172,7 @@ async fn request_user_input_round_trip_resolves_pending() -> anyhow::Result<()>
|
||||
output_json,
|
||||
json!({
|
||||
"answers": {
|
||||
"confirm_path": { "selected": ["yes"], "other": Value::Null }
|
||||
"confirm_path": { "answers": ["yes"] }
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
@@ -27,8 +27,7 @@ pub struct RequestUserInputArgs {
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq, JsonSchema, TS)]
|
||||
pub struct RequestUserInputAnswer {
|
||||
pub selected: Vec<String>,
|
||||
pub other: Option<String>,
|
||||
pub answers: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq, JsonSchema, TS)]
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
//!
|
||||
//! Core behaviors:
|
||||
//! - Each question can be answered by selecting one option and/or providing notes.
|
||||
//! - When options exist, notes are stored per selected option (notes become "other").
|
||||
//! - When options exist, notes are stored per selected option and appended as extra answers.
|
||||
//! - Typing while focused on options jumps into notes to keep freeform input fast.
|
||||
//! - Enter advances to the next question; the last question submits all answers.
|
||||
//! - Freeform-only questions submit "skipped" when empty.
|
||||
//! - Freeform-only questions submit an empty answer list when empty.
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
use std::collections::VecDeque;
|
||||
@@ -278,7 +278,7 @@ impl RequestUserInputOverlay {
|
||||
} else {
|
||||
answer_state.selected
|
||||
};
|
||||
// Notes map to "other". When options exist, notes are per selected option.
|
||||
// Notes are appended as extra answers. When options exist, notes are per selected option.
|
||||
let notes = if options.is_some_and(|opts| !opts.is_empty()) {
|
||||
selected_idx
|
||||
.and_then(|selected| answer_state.option_notes.get(selected))
|
||||
@@ -294,18 +294,15 @@ impl RequestUserInputOverlay {
|
||||
.and_then(|opts| opts.get(selected_idx))
|
||||
.map(|opt| opt.label.clone())
|
||||
});
|
||||
let selected = selected_label.into_iter().collect::<Vec<_>>();
|
||||
// For option questions, only send notes when present.
|
||||
let other = if notes.is_empty() && options.is_some_and(|opts| !opts.is_empty()) {
|
||||
None
|
||||
} else if notes.is_empty() && selected.is_empty() {
|
||||
Some("skipped".to_string())
|
||||
} else {
|
||||
Some(notes)
|
||||
};
|
||||
let mut answer_list = selected_label.into_iter().collect::<Vec<_>>();
|
||||
if !notes.is_empty() {
|
||||
answer_list.push(format!("user_note: {notes}"));
|
||||
}
|
||||
answers.insert(
|
||||
question.id.clone(),
|
||||
RequestUserInputAnswer { selected, other },
|
||||
RequestUserInputAnswer {
|
||||
answers: answer_list,
|
||||
},
|
||||
);
|
||||
}
|
||||
self.app_event_tx
|
||||
@@ -605,12 +602,11 @@ mod tests {
|
||||
};
|
||||
assert_eq!(id, "turn-1");
|
||||
let answer = response.answers.get("q1").expect("answer missing");
|
||||
assert_eq!(answer.selected, vec!["Option 1".to_string()]);
|
||||
assert_eq!(answer.other, None);
|
||||
assert_eq!(answer.answers, vec!["Option 1".to_string()]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn freeform_questions_submit_skipped_when_empty() {
|
||||
fn freeform_questions_submit_empty_when_empty() {
|
||||
let (tx, mut rx) = test_sender();
|
||||
let mut overlay = RequestUserInputOverlay::new(
|
||||
request_event("turn-1", vec![question_without_options("q1", "Notes")]),
|
||||
@@ -624,8 +620,7 @@ mod tests {
|
||||
panic!("expected UserInputAnswer");
|
||||
};
|
||||
let answer = response.answers.get("q1").expect("answer missing");
|
||||
assert_eq!(answer.selected, Vec::<String>::new());
|
||||
assert_eq!(answer.other, Some("skipped".to_string()));
|
||||
assert_eq!(answer.answers, Vec::<String>::new());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -654,8 +649,13 @@ mod tests {
|
||||
panic!("expected UserInputAnswer");
|
||||
};
|
||||
let answer = response.answers.get("q1").expect("answer missing");
|
||||
assert_eq!(answer.selected, vec!["Option 2".to_string()]);
|
||||
assert_eq!(answer.other, Some("Notes for option 2".to_string()));
|
||||
assert_eq!(
|
||||
answer.answers,
|
||||
vec![
|
||||
"Option 2".to_string(),
|
||||
"user_note: Notes for option 2".to_string(),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user