Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 18 additions & 9 deletions crates/jp_cli/src/cmd/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -434,15 +434,13 @@ impl Query {
chat_request.schema = schema.as_object().cloned();
}

// If the query was composed in an editor, the user has lost sight
// of what they wrote by the time the editor closes. Echo it back
// through the same role-aware rendering machinery used by replay
// and live streaming — a labeled user header followed by the
// request body — so the boundary between user input and the
// forthcoming assistant response is visually clear. Render this
// before any post-edit work (MCP init, attachments, tools) so that
// failures in those stages don't swallow the user's message.
if query_from_editor {
// Echo the request back through the same role-aware rendering
// machinery used by replay and live streaming — a labeled user header
// followed by the request body — so the boundary between user input
// and the forthcoming assistant response is visually clear. Render
// this before any post-edit work (MCP init, attachments, tools) so
// that failures in those stages don't swallow the user's message.
if self.should_echo_request(query_from_editor) {
let mut echo = TurnView::new(
ctx.printer.clone(),
cfg.style.clone(),
Expand Down Expand Up @@ -846,6 +844,17 @@ impl Query {
.await
}

/// Whether the chat request should be echoed to the terminal before the
/// turn starts.
///
/// Echo when the user can't already see what's being sent: a query composed
/// in an editor (the editor took over the screen) or a `--replay` (the
/// message is pulled from history, not typed on the command line).
/// A plain inline query needs no echo — the user just typed it.
fn should_echo_request(&self, query_from_editor: bool) -> bool {
query_from_editor || self.replay
}

/// Returns `true` if editing is explicitly disabled.
///
/// This signals that even if no query is provided, no editor should be
Expand Down
17 changes: 17 additions & 0 deletions crates/jp_cli/src/cmd/query_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -929,6 +929,23 @@ fn no_title_does_not_persist_into_partial_config() {
assert_eq!(with_flag.conversation.title.generate.auto, None);
}

#[test]
fn echo_request_when_from_editor_or_replay() {
// Editor-composed query: the editor took over the screen, so echo.
assert!(Query::default().should_echo_request(true));

// Plain inline query, no editor: the user already sees their input.
assert!(!Query::default().should_echo_request(false));

// Replay without an editor: the message comes from history and isn't
// otherwise visible on the terminal, so it must be echoed.
let replay = Query {
replay: true,
..Default::default()
};
assert!(replay.should_echo_request(false));
}

#[test]
fn blockquote_prefixes_each_line() {
assert_eq!(blockquote("hello"), "> hello");
Expand Down
Loading