Synced from monorepo

Changes:
- Persist submitter identity for /feedback
- Let custom models use rotating tokens from named auth providers
- Template stale tool/param name literals in server-native descriptions
- Minimal mode commits thinking in full, lookups as one-liners
- Tighten durable append internals
- Nudge model to end turn on no-op bash commands
- Per-fetch signing nonce in the managed-config envelope, with a server-side replay probe
- Include working tree in startup status
This commit is contained in:
grokkybara[bot] 2026-07-20 18:06:59 +01:00
commit a881e6703f
140 changed files with 6746 additions and 2377 deletions

View file

@ -6,20 +6,11 @@ use crate::common::*;
/// so screen assertions can tell the two apart.
const REASONING_SENTINEL: &str = "REASONINGSENTINEL";
/// Dogfood bug: "I don't see thoughts in the transcript". With thinking
/// enabled (`[ui] show_thinking_blocks` — the default, set
/// explicitly here so the test doesn't depend on the rollout default),
/// minimal commits reasoning as a **collapsed** `Thought for Xs` header
/// (print-once display policy) — the body is intentionally not in the live
/// scrollback. The advertised full-fidelity `/transcript` view must therefore
/// render the thinking body **expanded**, or the reasoning is unreachable.
///
/// Flow: stream a reasoning+text turn → the answer commits, the reasoning
/// collapses to its header (body nowhere on screen) → `/transcript` with
/// `PAGER=cat` dumps the full view → the reasoning body appears.
/// `[ui] show_thinking_blocks` is set explicitly (not left to the default)
/// so the test doesn't depend on the rollout default.
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
#[ignore]
async fn minimal_transcript_expands_collapsed_thinking() {
async fn minimal_commits_thinking_body_to_scrollback() {
// The model must run on the Responses backend — reasoning summary deltas
// are a Responses-API stream shape (the scripted events below).
let content = ContentController::start_with_models(vec![
@ -54,10 +45,7 @@ async fn minimal_transcript_expands_collapsed_thinking() {
)
.expect("write config");
// Minimal env + PAGER=cat (non-interactive dump, same as
// `minimal_transcript_opens_in_pager`).
let mut env = content.env_for_pager();
env.push(("PAGER".to_string(), "cat".to_string()));
let env = content.env_for_pager();
let env_refs: Vec<(&str, &str)> = env.iter().map(|(k, v)| (k.as_str(), v.as_str())).collect();
let binary = pager_binary().expect("resolve pager binary");
let mut harness = PtyHarness::new(&binary, DEFAULT_ROWS, DEFAULT_COLS, MINIMAL_ARGS, &env_refs)
@ -73,34 +61,17 @@ async fn minimal_transcript_expands_collapsed_thinking() {
.wait_for_full_text(MOCK_RESPONSE_SENTINEL, Duration::from_secs(30))
.expect("turn committed");
// The reasoning committed as its collapsed header: the body is NOT in the
// live view (that's the print-once display policy, not a bug)…
harness
.wait_for_full_text("Thought for", Duration::from_secs(10))
.expect("collapsed thinking header committed");
assert!(
!harness.full_text().contains(REASONING_SENTINEL),
"reasoning body must be collapsed in the live view\nfull:\n{}",
harness.full_text()
);
// …so the transcript is the only way to read it. cat dumps the full view.
inject_keys_paced(&mut harness, b"/transcript");
harness.inject_keys(b"\r").expect("submit /transcript");
.expect("thinking header committed");
harness
.wait_for_full_text(REASONING_SENTINEL, Duration::from_secs(15))
.wait_for_full_text(REASONING_SENTINEL, Duration::from_secs(10))
.unwrap_or_else(|e| {
panic!(
"transcript must expand the collapsed thinking body: {e}\nfull:\n{}",
"reasoning body must be committed to scrollback: {e}\nfull:\n{}",
harness.full_text()
)
});
// And the inline TUI survives the suspend/restore round trip.
harness
.wait_for_text(MINIMAL_IDLE_SENTINEL, Duration::from_secs(10))
.expect("inline TUI restored after the pager exited");
assert!(
!harness.contains_text("panicked"),
"pager panicked\nscreen:\n{}",

View file

@ -0,0 +1,74 @@
// Per-test-case module for the `pty_e2e` integration test crate.
#[allow(unused_imports)]
use crate::common::*;
const BODY_SENTINEL: &str = "READBODYONLYSENTINEL";
const DONE_SENTINEL: &str = "LOOKUP_TURN_DONE";
/// Uses `read_file` rather than `grep`: the grep tool shells out to `rg`,
/// which is absent from the Bazel remote-exec sandbox (only xai-grok-tools'
/// own test targets ship `@ripgrep_hermetic//:rg`), and a failed spawn
/// degrades to a zero-match result that vacuously passes the absence assert.
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
#[ignore]
async fn minimal_lookup_commits_one_line_summary() {
let content = ContentController::start().await.expect("start content");
let fixture = content.home().join("haystack.txt");
std::fs::write(&fixture, format!("{BODY_SENTINEL} body line\n")).expect("write fixture");
enqueue_tool_turn(
&content,
"call_read",
"read_file",
json!({ "target_file": fixture.to_string_lossy() }).to_string(),
);
content.set_response(DONE_SENTINEL);
let mut harness = spawn_minimal_in_dir(
&content,
DEFAULT_ROWS,
DEFAULT_COLS,
&["--yolo", "--trust"],
content.home(),
);
wait_minimal_ready(&mut harness);
harness
.inject_keys(format!("{PROMPT}\r").as_bytes())
.expect("submit prompt");
harness
.wait_for_full_text(DONE_SENTINEL, Duration::from_secs(60))
.expect("tool turn settles");
harness
.wait_for_text(MINIMAL_IDLE_SENTINEL, Duration::from_secs(20))
.expect("return to idle");
harness
.wait_for_full_text("haystack.txt", Duration::from_secs(10))
.expect("read header committed");
assert!(
!harness.full_text().contains(BODY_SENTINEL),
"successful read must commit as a one-line header, without file \
content\nfull:\n{}",
harness.full_text()
);
harness.inject_keys(b"\x05").expect("ctrl+e expand");
harness
.wait_for_full_text(BODY_SENTINEL, Duration::from_secs(10))
.unwrap_or_else(|e| {
panic!(
"Ctrl+E must re-print the read with its file content: {e}\nfull:\n{}",
harness.full_text()
)
});
assert!(
!harness.contains_text("panicked"),
"pager panicked\nscreen:\n{}",
harness.screen_contents()
);
quit_minimal(&mut harness);
}

View file

@ -9,6 +9,7 @@
mod minimal_cli_screen_mode_does_not_persist;
mod minimal_commits_response_to_scrollback;
mod minimal_commits_thinking_body_to_scrollback;
mod minimal_committed_content_survives_overlay_grow;
mod minimal_continue_reprints_transcript;
mod minimal_ctrl_c_arms_and_quits;
@ -16,6 +17,7 @@ mod minimal_double_esc_committed_queued_prompt_single_render;
mod minimal_esc_mid_turn_is_swallowed;
mod minimal_flush_left_no_hpad;
mod minimal_help_opens_command_palette;
mod minimal_lookup_commits_one_line_summary;
mod minimal_new_session_keeps_history_and_resets;
mod minimal_queue_indicator_shows_while_running;
mod minimal_resize_preserves_committed_scrollback;
@ -25,6 +27,5 @@ mod minimal_short_response_stays_on_screen;
mod minimal_slash_dropdown_dismisses_with_esc;
mod minimal_slash_switches_from_fullscreen;
mod minimal_slash_switches_to_fullscreen;
mod minimal_transcript_expands_collapsed_thinking;
mod minimal_transcript_opens_in_pager;
mod minimal_transcript_pager_restore_no_artifacts;