Improve Default mode prompt (less confusion with Plan mode) (#10545)

## Summary

This PR updates `request_user_input` behavior and Default-mode guidance
to match current collaboration-mode semantics and reduce model
confusion.

## Why

- `request_user_input` should be explicitly documented as **Plan-only**.
- Tool description and runtime availability checks should be driven by
the **same centralized mode policy**.
- Default mode prompt needed stronger execution guidance and explicit
instruction that `request_user_input` is unavailable.
- Error messages should report the **actual mode name** (not aliases
that can read as misleading).

## What changed

- Centralized `request_user_input` mode policy in `core` handler logic:
  - Added a single allowed-modes config (`Plan` only).
  - Reused that policy for:
    - runtime rejection messaging
    - tool description text
- Updated tool description to include availability constraint:
  - `"This tool is only available in Plan mode."`
- Updated runtime rejection behavior:
  - `Default` -> `"request_user_input is unavailable in Default mode"`
  - `Execute` -> `"request_user_input is unavailable in Execute mode"`
- `PairProgramming` -> `"request_user_input is unavailable in Pair
Programming mode"`
- Strengthened Default collaboration prompt:
  - Added explicit execution-first behavior
  - Added assumptions-first guidance
  - Added explicit `request_user_input` unavailability instruction
  - Added concise progress-reporting expectations
- Simplified formatting implementation:
  - Inlined allowed-mode name collection into `format_allowed_modes()`
- Kept `format_allowed_modes()` output for 3+ modes as CSV style
(`modes: a,b,c`)
This commit is contained in:
Charley Cunningham
2026-02-03 12:08:38 -08:00
committed by GitHub
parent d9ad5c3c49
commit 998eb8f32b
5 changed files with 130 additions and 19 deletions

View File

@@ -74,11 +74,6 @@ async fn request_user_input_round_trip_resolves_pending() -> anyhow::Result<()>
request_user_input_round_trip_for_mode(ModeKind::Plan).await
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn request_user_input_round_trip_works_in_pair_mode() -> anyhow::Result<()> {
request_user_input_round_trip_for_mode(ModeKind::PairProgramming).await
}
async fn request_user_input_round_trip_for_mode(mode: ModeKind) -> anyhow::Result<()> {
skip_if_no_network!(Ok(()));
@@ -216,7 +211,7 @@ where
.build(&server)
.await?;
let mode_slug = mode_name.to_lowercase();
let mode_slug = mode_name.to_lowercase().replace(' ', "-");
let call_id = format!("user-input-{mode_slug}-call");
let request_args = json!({
"questions": [{
@@ -283,7 +278,7 @@ where
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn request_user_input_rejected_in_execute_mode_alias() -> anyhow::Result<()> {
assert_request_user_input_rejected("Default", |model| CollaborationMode {
assert_request_user_input_rejected("Execute", |model| CollaborationMode {
mode: ModeKind::Execute,
settings: Settings {
model,
@@ -306,3 +301,16 @@ async fn request_user_input_rejected_in_default_mode() -> anyhow::Result<()> {
})
.await
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn request_user_input_rejected_in_pair_mode_alias() -> anyhow::Result<()> {
assert_request_user_input_rejected("Pair Programming", |model| CollaborationMode {
mode: ModeKind::PairProgramming,
settings: Settings {
model,
reasoning_effort: None,
developer_instructions: None,
},
})
.await
}