mirror of
https://github.com/openai/codex.git
synced 2026-11-13 21:30:47 +00:00
Hide TUI status details for read-only history (#61219)
## What changed Track whether a thread is being viewed without a live attachment. Hide the status line and context usage for saved history and unavailable conversations, even when token usage updates arrive. Restore these displays when the thread resumes interactively, including sessions using read-only permissions. Avoid a leading separator before the Vim mode indicator when context usage is hidden. ## Testing Add regression coverage for history viewing, token updates, and interactive resume. Update unavailable-conversation snapshots to omit the status line. GitOrigin-RevId: 14dfd2ee0f232001814b7fc45a5ac8a5d755669b
This commit is contained in:
@@ -1942,6 +1942,7 @@ enabled = false
|
||||
|
||||
app.chat_widget
|
||||
.handle_thread_session(crate::session_state::ThreadSessionState {
|
||||
read_only_history: false,
|
||||
daybreak_enabled: false,
|
||||
windows_sandbox_host: crate::app::WindowsSandboxHost::Local,
|
||||
thread_id: ThreadId::new(),
|
||||
|
||||
@@ -35,6 +35,7 @@ pub(in crate::app) fn user_cell(message: &str) -> Arc<dyn HistoryCell> {
|
||||
|
||||
pub(in crate::app) fn attach_thread(app: &mut App, thread_id: ThreadId) {
|
||||
app.chat_widget.handle_thread_session(ThreadSessionState {
|
||||
read_only_history: false,
|
||||
daybreak_enabled: false,
|
||||
windows_sandbox_host: crate::app::WindowsSandboxHost::Local,
|
||||
thread_id,
|
||||
|
||||
@@ -485,6 +485,9 @@ impl App {
|
||||
store.pending_interactive_replay = Default::default();
|
||||
store.pending_interrupt_turn_id = None;
|
||||
store.active = false;
|
||||
if let Some(session) = &mut store.session {
|
||||
session.read_only_history = true;
|
||||
}
|
||||
store
|
||||
.buffer
|
||||
.retain(|event| matches!(event, ThreadBufferedEvent::Notification(_)));
|
||||
|
||||
@@ -837,6 +837,9 @@ impl App {
|
||||
display,
|
||||
});
|
||||
}
|
||||
if is_replay_only && let Some(session) = snapshot.session.as_mut() {
|
||||
session.read_only_history = true;
|
||||
}
|
||||
self.render_thread_snapshot(tui, app_server, thread_id, snapshot, !is_replay_only)?;
|
||||
if !is_replay_only
|
||||
&& let Some(message) = self
|
||||
|
||||
@@ -7469,6 +7469,7 @@ async fn inactive_thread_started_notification_initializes_replay_session() -> Re
|
||||
let primary_cwd = test_path_buf("/tmp/main").abs();
|
||||
let shared_root = test_path_buf("/tmp/shared").abs();
|
||||
let primary_session = ThreadSessionState {
|
||||
read_only_history: true,
|
||||
daybreak_enabled: false,
|
||||
windows_sandbox_host: WindowsSandboxHost::Local,
|
||||
approval_policy: AskForApproval::OnRequest,
|
||||
@@ -7546,6 +7547,7 @@ async fn inactive_thread_started_notification_initializes_replay_session() -> Re
|
||||
let session = store.session.clone().expect("inferred session");
|
||||
drop(store);
|
||||
|
||||
assert!(!session.read_only_history);
|
||||
assert_eq!(session.thread_id, agent_thread_id);
|
||||
assert!(session.daybreak_enabled);
|
||||
assert_eq!(session.windows_sandbox_host, WindowsSandboxHost::Remote);
|
||||
@@ -7674,7 +7676,6 @@ async fn thread_read_session_state_does_not_reuse_primary_permission_profile() {
|
||||
runtime_workspace_roots: vec![primary_cwd.clone()],
|
||||
..test_thread_session(main_thread_id, primary_cwd.to_path_buf())
|
||||
};
|
||||
app.primary_session_configured = Some(primary_session);
|
||||
|
||||
let thread = Thread {
|
||||
originator: None,
|
||||
@@ -7712,10 +7713,17 @@ async fn thread_read_session_state_does_not_reuse_primary_permission_profile() {
|
||||
turns: Vec::new(),
|
||||
};
|
||||
|
||||
let cold_session = app
|
||||
.session_state_for_thread_read(read_thread_id, &thread)
|
||||
.await;
|
||||
assert!(cold_session.read_only_history);
|
||||
|
||||
app.primary_session_configured = Some(primary_session);
|
||||
let session = app
|
||||
.session_state_for_thread_read(read_thread_id, &thread)
|
||||
.await;
|
||||
|
||||
assert!(session.read_only_history);
|
||||
assert_eq!(session.thread_id, read_thread_id);
|
||||
assert_eq!(session.model, "server-reported-model");
|
||||
assert_eq!(session.cwd.as_path(), test_path_buf("/tmp/read").as_path());
|
||||
@@ -8820,6 +8828,7 @@ async fn render_clear_ui_header_after_long_transcript_for_snapshot() -> String {
|
||||
};
|
||||
let make_header = |is_first| -> Arc<dyn HistoryCell> {
|
||||
let session = ThreadSessionState {
|
||||
read_only_history: false,
|
||||
daybreak_enabled: false,
|
||||
windows_sandbox_host: crate::app::WindowsSandboxHost::Local,
|
||||
thread_id: ThreadId::new(),
|
||||
@@ -9533,6 +9542,7 @@ async fn replace_goal_confirmation_snapshot() {
|
||||
|
||||
pub(super) fn test_thread_session(thread_id: ThreadId, cwd: PathBuf) -> ThreadSessionState {
|
||||
ThreadSessionState {
|
||||
read_only_history: false,
|
||||
daybreak_enabled: false,
|
||||
windows_sandbox_host: crate::app::WindowsSandboxHost::Local,
|
||||
thread_id,
|
||||
@@ -10849,6 +10859,7 @@ async fn backtrack_selection_preserves_selected_prompt_and_requests_branch() {
|
||||
|
||||
let make_header = |is_first| {
|
||||
let session = ThreadSessionState {
|
||||
read_only_history: false,
|
||||
daybreak_enabled: false,
|
||||
windows_sandbox_host: crate::app::WindowsSandboxHost::Local,
|
||||
thread_id: ThreadId::new(),
|
||||
@@ -10922,6 +10933,7 @@ async fn backtrack_selection_preserves_selected_prompt_and_requests_branch() {
|
||||
let base_id = ThreadId::new();
|
||||
app.chat_widget
|
||||
.handle_thread_session(crate::session_state::ThreadSessionState {
|
||||
read_only_history: false,
|
||||
daybreak_enabled: false,
|
||||
windows_sandbox_host: crate::app::WindowsSandboxHost::Local,
|
||||
thread_id: base_id,
|
||||
@@ -12318,6 +12330,7 @@ async fn new_session_requests_shutdown_for_previous_conversation() {
|
||||
|
||||
let thread_id = ThreadId::new();
|
||||
let event = crate::session_state::ThreadSessionState {
|
||||
read_only_history: false,
|
||||
daybreak_enabled: false,
|
||||
windows_sandbox_host: crate::app::WindowsSandboxHost::Local,
|
||||
thread_id,
|
||||
@@ -13097,6 +13110,7 @@ async fn clear_only_ui_reset_preserves_chat_session_state() {
|
||||
let thread_id = ThreadId::new();
|
||||
app.chat_widget
|
||||
.handle_thread_session(crate::session_state::ThreadSessionState {
|
||||
read_only_history: false,
|
||||
daybreak_enabled: false,
|
||||
windows_sandbox_host: crate::app::WindowsSandboxHost::Local,
|
||||
thread_id,
|
||||
|
||||
@@ -1873,6 +1873,73 @@ async fn make_history_test_app() -> Result<(Box<App>, tempfile::TempDir)> {
|
||||
Ok((app, codex_home))
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn read_only_history_hides_the_statusline_until_interactive_resume() -> Result<()> {
|
||||
let (mut app, _codex_home) = make_history_test_app().await?;
|
||||
let thread_id = create_history_rollout(&app.config, ThreadHistoryMode::Legacy, "saved prompt")?;
|
||||
app.config
|
||||
.permissions
|
||||
.set_permission_profile(PermissionProfile::read_only())?;
|
||||
let mut server = crate::start_embedded_app_server_for_picker(&app.config).await?;
|
||||
app.chat_widget.setup_status_line(
|
||||
vec![crate::bottom_pane::StatusLineItem::SessionId],
|
||||
/*use_theme_colors*/ false,
|
||||
);
|
||||
|
||||
app.enqueue_primary_thread_session(
|
||||
test_thread_session(thread_id, app.config.cwd.to_path_buf()),
|
||||
Vec::new(),
|
||||
)
|
||||
.await?;
|
||||
assert!(render_bottom_popup(&app.chat_widget, /*width*/ 100).contains(&thread_id.to_string()));
|
||||
|
||||
let (view, _) = server
|
||||
.read_thread_for_viewing(&app.config, &app.local_settings, thread_id)
|
||||
.await?;
|
||||
app.enqueue_primary_thread_session(view.session, view.turns)
|
||||
.await?;
|
||||
let footer = render_bottom_popup(&app.chat_widget, /*width*/ 100);
|
||||
insta::assert_snapshot!(footer, @r"
|
||||
› Ask Codex to do anything
|
||||
|
||||
? for shortcuts
|
||||
");
|
||||
|
||||
for window in [Some(100_000), None] {
|
||||
app.chat_widget.handle_server_notification(
|
||||
token_usage_notification(thread_id, "turn-1", window),
|
||||
/*replay_kind*/ None,
|
||||
);
|
||||
assert_eq!(render_bottom_popup(&app.chat_widget, /*width*/ 100), footer);
|
||||
}
|
||||
|
||||
let live = server
|
||||
.resume_thread(
|
||||
&app.local_settings,
|
||||
app.config.clone(),
|
||||
thread_id,
|
||||
app.resume_model_settings(),
|
||||
)
|
||||
.await?;
|
||||
assert_eq!(
|
||||
live.session.permission_profile,
|
||||
PermissionProfile::read_only()
|
||||
);
|
||||
app.enqueue_primary_thread_session(live.session, live.turns)
|
||||
.await?;
|
||||
let footer = render_bottom_popup(&app.chat_widget, /*width*/ 100);
|
||||
assert!(footer.contains(&thread_id.to_string()), "{footer}");
|
||||
app.chat_widget
|
||||
.setup_status_line(Vec::new(), /*use_theme_colors*/ false);
|
||||
app.chat_widget.handle_server_notification(
|
||||
token_usage_notification(thread_id, "turn-2", /*model_context_window*/ None),
|
||||
/*replay_kind*/ None,
|
||||
);
|
||||
assert!(render_bottom_popup(&app.chat_widget, /*width*/ 100).contains("10 used"));
|
||||
server.shutdown().await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn cloud_resume_with_current_directory_needs_no_cwd_override() -> Result<()> {
|
||||
use codex_config::types::ResumeCwdMode;
|
||||
|
||||
-2
@@ -6,5 +6,3 @@ expression: "format!(\"{history}\\n{}\",\nrender_bottom_popup(&app.chat_widget,\
|
||||
⚠ A background Codex service is running v2.0.0, different from your Codex CLI
|
||||
v0.0.0.
|
||||
› unavailable draft
|
||||
|
||||
gpt-test default · /tmp/project
|
||||
|
||||
-2
@@ -7,5 +7,3 @@ Cached previous conversation
|
||||
• This conversation is unavailable. Its cached transcript and draft remain here; input is paused. Open the agent picker or return to the parent to continue.
|
||||
• The rename target disappeared. Unsubmitted title: Keep this task draft!
|
||||
› latest draft
|
||||
|
||||
gpt-test default · /tmp/project
|
||||
|
||||
@@ -744,6 +744,7 @@ mod tests {
|
||||
|
||||
fn test_thread_session(thread_id: ThreadId, cwd: PathBuf) -> ThreadSessionState {
|
||||
ThreadSessionState {
|
||||
read_only_history: false,
|
||||
daybreak_enabled: false,
|
||||
windows_sandbox_host: crate::app::WindowsSandboxHost::Local,
|
||||
thread_id,
|
||||
|
||||
@@ -1430,6 +1430,7 @@ impl App {
|
||||
notification: &ThreadStartedNotification,
|
||||
) -> Option<ThreadSessionState> {
|
||||
let mut session = self.primary_session_configured.clone()?;
|
||||
session.read_only_history = false;
|
||||
session.thread_id = thread_id;
|
||||
// The primary session supplies defaults. The new thread supplies its own fork parent.
|
||||
session.set_fork_parent(notification.thread.forked_from_id.as_deref());
|
||||
|
||||
@@ -78,6 +78,7 @@ impl App {
|
||||
let permission_profile = self.current_permission_profile();
|
||||
let active_permission_profile = self.current_active_permission_profile();
|
||||
let mut session = if let Some(mut session) = self.primary_session_configured.clone() {
|
||||
session.read_only_history = true;
|
||||
if session.thread_id != thread_id {
|
||||
// `thread/read` does not include all thread settings, so do not carry
|
||||
// thread-scoped state from the currently active session.
|
||||
@@ -87,6 +88,7 @@ impl App {
|
||||
session
|
||||
} else {
|
||||
ThreadSessionState {
|
||||
read_only_history: true,
|
||||
daybreak_enabled: false,
|
||||
windows_sandbox_host: crate::app::WindowsSandboxHost::Local,
|
||||
thread_id,
|
||||
@@ -174,6 +176,7 @@ mod tests {
|
||||
|
||||
fn test_thread_session(thread_id: ThreadId, cwd: PathBuf) -> ThreadSessionState {
|
||||
ThreadSessionState {
|
||||
read_only_history: false,
|
||||
daybreak_enabled: false,
|
||||
windows_sandbox_host: crate::app::WindowsSandboxHost::Local,
|
||||
thread_id,
|
||||
|
||||
@@ -3111,6 +3111,7 @@ async fn thread_session_state_from_thread_response(
|
||||
);
|
||||
let (log_id, entry_count) = codex_message_history::history_metadata(&history_config).await;
|
||||
Ok(ThreadSessionState {
|
||||
read_only_history: false,
|
||||
daybreak_enabled: false,
|
||||
windows_sandbox_host,
|
||||
thread_id,
|
||||
|
||||
@@ -76,7 +76,7 @@ impl AppServerSession {
|
||||
"Showing up to 100 recent prompts and final replies. Intermediate messages and tool activity are unavailable.",
|
||||
);
|
||||
}
|
||||
let session = thread_session_state_from_thread_response(
|
||||
let mut session = thread_session_state_from_thread_response(
|
||||
&thread.id,
|
||||
crate::windows_sandbox::host_from_environments(thread.environments.as_deref()),
|
||||
thread.forked_from_id.clone(),
|
||||
@@ -97,6 +97,7 @@ impl AppServerSession {
|
||||
)
|
||||
.await
|
||||
.map_err(color_eyre::eyre::Report::msg)?;
|
||||
session.read_only_history = true;
|
||||
self.freeze_viewed_receipt(thread_id);
|
||||
Ok((
|
||||
AppServerStartedThread {
|
||||
|
||||
@@ -790,7 +790,7 @@ impl ChatComposer {
|
||||
flash: None,
|
||||
context_window_percent: None,
|
||||
context_window_used_tokens: None,
|
||||
context_window_pending: false,
|
||||
context_window_hidden: false,
|
||||
collaboration_mode_indicator: None,
|
||||
goal_status_indicator: None,
|
||||
ide_context_active: false,
|
||||
@@ -1496,7 +1496,7 @@ impl ChatComposer {
|
||||
}
|
||||
|
||||
fn right_footer_line_with_context(&self) -> Line<'static> {
|
||||
let mut line = if self.footer.context_window_pending {
|
||||
let mut line = if self.footer.context_window_hidden {
|
||||
Line::default()
|
||||
} else {
|
||||
context_window_line(
|
||||
@@ -1505,7 +1505,9 @@ impl ChatComposer {
|
||||
)
|
||||
};
|
||||
if let Some(vim_mode) = self.vim_mode_indicator_span() {
|
||||
line.spans.push(" | ".dim());
|
||||
if !line.spans.is_empty() {
|
||||
line.spans.push(" | ".dim());
|
||||
}
|
||||
line.spans.push(vim_mode);
|
||||
}
|
||||
line
|
||||
@@ -4472,8 +4474,8 @@ impl ChatComposer {
|
||||
self.footer.context_window_used_tokens = used_tokens;
|
||||
}
|
||||
|
||||
pub(crate) fn set_context_window_pending(&mut self, pending: bool) {
|
||||
self.footer.context_window_pending = pending;
|
||||
pub(crate) fn set_context_window_hidden(&mut self, hidden: bool) {
|
||||
self.footer.context_window_hidden = hidden;
|
||||
}
|
||||
|
||||
pub(crate) fn set_esc_backtrack_hint(&mut self, show: bool) {
|
||||
|
||||
@@ -55,7 +55,7 @@ fn embedded_composer_shows_validation_error_without_losing_draft() {
|
||||
let (mut composer, mut rx) = new_test_composer();
|
||||
composer.config = ChatComposerConfig::plain_text();
|
||||
composer.set_footer_hint_override(Some(vec![("enter".into(), "submit".into())]));
|
||||
composer.set_context_window_pending(/*pending*/ true);
|
||||
composer.set_context_window_hidden(/*hidden*/ true);
|
||||
let text = "x".repeat(MAX_USER_INPUT_TEXT_CHARS + 1);
|
||||
composer.handle_paste(text.clone());
|
||||
assert_eq!(
|
||||
|
||||
@@ -379,7 +379,7 @@ pub(super) struct FooterState {
|
||||
pub(super) flash: Option<FooterFlash>,
|
||||
pub(super) context_window_percent: Option<i64>,
|
||||
pub(super) context_window_used_tokens: Option<i64>,
|
||||
pub(super) context_window_pending: bool,
|
||||
pub(super) context_window_hidden: bool,
|
||||
pub(super) collaboration_mode_indicator: Option<CollaborationModeIndicator>,
|
||||
pub(super) goal_status_indicator: Option<GoalStatusIndicator>,
|
||||
pub(super) ide_context_active: bool,
|
||||
|
||||
@@ -329,7 +329,7 @@ impl ChatComposer {
|
||||
}
|
||||
let show_warning = self.show_warning_notice(options);
|
||||
if !self.footer.status_line_enabled
|
||||
&& !self.footer.context_window_pending
|
||||
&& !self.footer.context_window_hidden
|
||||
&& self.footer.side_conversation_context_label.is_none()
|
||||
&& !self.is_bang_shell_command()
|
||||
{
|
||||
|
||||
@@ -871,7 +871,7 @@ fn oversized_goal_yields_to_an_eligible_whole_hint_with_status_disabled() {
|
||||
Some("100% context left")
|
||||
);
|
||||
|
||||
composer.set_context_window_pending(/*pending*/ true);
|
||||
composer.set_context_window_hidden(/*hidden*/ true);
|
||||
composer.set_goal_status_indicator(Some(GoalStatusIndicator::Paused));
|
||||
let (text, _) = render(&composer, /*width*/ 18, /*footer*/ None);
|
||||
assert_eq!(text.lines().last().map(str::trim), Some("? for shortcuts"));
|
||||
|
||||
@@ -1503,8 +1503,8 @@ impl BottomPane {
|
||||
self.request_redraw();
|
||||
}
|
||||
|
||||
pub(crate) fn set_context_window_pending(&mut self, pending: bool) {
|
||||
self.composer.set_context_window_pending(pending);
|
||||
pub(crate) fn set_context_window_hidden(&mut self, hidden: bool) {
|
||||
self.composer.set_context_window_hidden(hidden);
|
||||
self.request_redraw();
|
||||
}
|
||||
|
||||
|
||||
@@ -688,6 +688,7 @@ pub(crate) struct ChatWidget {
|
||||
active_side_conversation: bool,
|
||||
blocks_direct_input: bool,
|
||||
external_writer_view: bool,
|
||||
read_only_history: bool,
|
||||
provider_error: Option<codex_app_server_protocol::ModelProviderError>,
|
||||
/// Covers both queued and executing forks so repeated shortcuts cannot queue another one.
|
||||
pub(crate) fork_in_progress: bool,
|
||||
@@ -1161,13 +1162,17 @@ impl ChatWidget {
|
||||
self.config.memories.generate_memories = generate_memories;
|
||||
}
|
||||
|
||||
fn sync_context_window_visibility(&mut self) {
|
||||
self.bottom_pane
|
||||
.set_context_window_hidden(self.read_only_history || self.token_usage_pending);
|
||||
}
|
||||
|
||||
pub(crate) fn set_token_info(&mut self, info: Option<TokenUsageInfo>) {
|
||||
match info {
|
||||
Some(info) => self.apply_token_info(info),
|
||||
None => {
|
||||
self.token_usage_pending = true;
|
||||
self.bottom_pane
|
||||
.set_context_window_pending(/*pending*/ true);
|
||||
self.sync_context_window_visibility();
|
||||
self.bottom_pane
|
||||
.set_context_window(/*percent*/ None, /*used_tokens*/ None);
|
||||
self.token_info = None;
|
||||
@@ -1177,8 +1182,7 @@ impl ChatWidget {
|
||||
|
||||
fn apply_token_info(&mut self, info: TokenUsageInfo) {
|
||||
self.token_usage_pending = false;
|
||||
self.bottom_pane
|
||||
.set_context_window_pending(/*pending*/ false);
|
||||
self.sync_context_window_visibility();
|
||||
let percent = self.context_remaining_percent(&info);
|
||||
let used_tokens = self.context_used_tokens(&info, percent.is_some());
|
||||
self.bottom_pane.set_context_window(percent, used_tokens);
|
||||
|
||||
@@ -246,6 +246,7 @@ impl ChatWidget {
|
||||
active_side_conversation: false,
|
||||
blocks_direct_input: false,
|
||||
external_writer_view: false,
|
||||
read_only_history: false,
|
||||
provider_error: None,
|
||||
fork_in_progress: false,
|
||||
misalignment_policy_violation: None,
|
||||
|
||||
@@ -130,6 +130,9 @@ impl ChatWidget {
|
||||
}
|
||||
|
||||
pub(crate) fn pause_unavailable_thread(&mut self) {
|
||||
self.read_only_history = true;
|
||||
self.sync_context_window_visibility();
|
||||
self.refresh_status_line();
|
||||
if let Some(questions) = &mut self.bottom_pane.questions {
|
||||
questions.delivery_enabled = false;
|
||||
}
|
||||
|
||||
@@ -96,6 +96,8 @@ impl ChatWidget {
|
||||
let connector_scope_changed = previous_thread_id != Some(session.thread_id)
|
||||
|| self.config.cwd.as_path() != session.cwd.as_path();
|
||||
self.thread_id = Some(session.thread_id);
|
||||
self.read_only_history = session.read_only_history;
|
||||
self.sync_context_window_visibility();
|
||||
self.daybreak_enabled = self.config.features.enabled(Feature::CliDaybreak)
|
||||
&& session.daybreak_enabled
|
||||
&& !matches!(display, SessionConfiguredDisplay::SideConversation);
|
||||
|
||||
@@ -465,6 +465,9 @@ impl ChatWidget {
|
||||
///
|
||||
/// Unknown ids are deduplicated in insertion order for warning messages.
|
||||
fn status_line_items_with_invalids(&self) -> (Vec<StatusLineItem>, Vec<String>) {
|
||||
if self.read_only_history {
|
||||
return Default::default();
|
||||
}
|
||||
parse_items_with_invalids(self.configured_status_line_items())
|
||||
}
|
||||
|
||||
|
||||
@@ -47,6 +47,7 @@ fn thread_settings_for_test(
|
||||
|
||||
fn configured_thread_session(thread_id: ThreadId) -> crate::session_state::ThreadSessionState {
|
||||
crate::session_state::ThreadSessionState {
|
||||
read_only_history: false,
|
||||
daybreak_enabled: false,
|
||||
windows_sandbox_host: crate::app::WindowsSandboxHost::Local,
|
||||
thread_id,
|
||||
|
||||
@@ -629,6 +629,7 @@ async fn submission_preserves_text_elements_and_local_images() {
|
||||
let thread_id = ThreadId::new();
|
||||
let rollout_file = NamedTempFile::new().unwrap();
|
||||
let configured = crate::session_state::ThreadSessionState {
|
||||
read_only_history: false,
|
||||
daybreak_enabled: false,
|
||||
windows_sandbox_host: crate::app::WindowsSandboxHost::Local,
|
||||
thread_id,
|
||||
@@ -739,6 +740,7 @@ async fn submission_includes_configured_active_permission_profile() {
|
||||
};
|
||||
let expected_active_permission_profile = ActivePermissionProfile::new("custom");
|
||||
let configured = crate::session_state::ThreadSessionState {
|
||||
read_only_history: false,
|
||||
daybreak_enabled: false,
|
||||
windows_sandbox_host: crate::app::WindowsSandboxHost::Local,
|
||||
thread_id,
|
||||
@@ -795,6 +797,7 @@ async fn submission_omits_active_permission_profile_for_legacy_snapshot() {
|
||||
file_system: ManagedFileSystemPermissions::Unrestricted,
|
||||
};
|
||||
let configured = crate::session_state::ThreadSessionState {
|
||||
read_only_history: false,
|
||||
daybreak_enabled: false,
|
||||
windows_sandbox_host: crate::app::WindowsSandboxHost::Local,
|
||||
thread_id,
|
||||
@@ -841,6 +844,7 @@ async fn submission_with_remote_and_local_images_keeps_local_placeholder_numberi
|
||||
let thread_id = ThreadId::new();
|
||||
let rollout_file = NamedTempFile::new().unwrap();
|
||||
let configured = crate::session_state::ThreadSessionState {
|
||||
read_only_history: false,
|
||||
daybreak_enabled: false,
|
||||
windows_sandbox_host: crate::app::WindowsSandboxHost::Local,
|
||||
thread_id,
|
||||
@@ -942,6 +946,7 @@ async fn enter_with_only_remote_images_submits_user_turn() {
|
||||
let thread_id = ThreadId::new();
|
||||
let rollout_file = NamedTempFile::new().unwrap();
|
||||
let configured = crate::session_state::ThreadSessionState {
|
||||
read_only_history: false,
|
||||
daybreak_enabled: false,
|
||||
windows_sandbox_host: crate::app::WindowsSandboxHost::Local,
|
||||
thread_id,
|
||||
@@ -1012,6 +1017,7 @@ async fn shift_enter_with_only_remote_images_does_not_submit_user_turn() {
|
||||
let thread_id = ThreadId::new();
|
||||
let rollout_file = NamedTempFile::new().unwrap();
|
||||
let configured = crate::session_state::ThreadSessionState {
|
||||
read_only_history: false,
|
||||
daybreak_enabled: false,
|
||||
windows_sandbox_host: crate::app::WindowsSandboxHost::Local,
|
||||
thread_id,
|
||||
@@ -1054,6 +1060,7 @@ async fn enter_with_only_remote_images_does_not_submit_when_modal_is_active() {
|
||||
let thread_id = ThreadId::new();
|
||||
let rollout_file = NamedTempFile::new().unwrap();
|
||||
let configured = crate::session_state::ThreadSessionState {
|
||||
read_only_history: false,
|
||||
daybreak_enabled: false,
|
||||
windows_sandbox_host: crate::app::WindowsSandboxHost::Local,
|
||||
thread_id,
|
||||
@@ -1096,6 +1103,7 @@ async fn enter_with_only_remote_images_does_not_submit_when_input_disabled() {
|
||||
let thread_id = ThreadId::new();
|
||||
let rollout_file = NamedTempFile::new().unwrap();
|
||||
let configured = crate::session_state::ThreadSessionState {
|
||||
read_only_history: false,
|
||||
daybreak_enabled: false,
|
||||
windows_sandbox_host: crate::app::WindowsSandboxHost::Local,
|
||||
thread_id,
|
||||
@@ -1141,6 +1149,7 @@ async fn submission_prefers_selected_duplicate_skill_path() {
|
||||
let thread_id = ThreadId::new();
|
||||
let rollout_file = NamedTempFile::new().unwrap();
|
||||
let configured = crate::session_state::ThreadSessionState {
|
||||
read_only_history: false,
|
||||
daybreak_enabled: false,
|
||||
windows_sandbox_host: crate::app::WindowsSandboxHost::Local,
|
||||
thread_id,
|
||||
|
||||
@@ -1269,6 +1269,7 @@ async fn bang_shell_enter_while_task_running_submits_run_user_shell_command() {
|
||||
let thread_id = ThreadId::new();
|
||||
let rollout_file = NamedTempFile::new().unwrap();
|
||||
let configured = crate::session_state::ThreadSessionState {
|
||||
read_only_history: false,
|
||||
daybreak_enabled: false,
|
||||
windows_sandbox_host: crate::app::WindowsSandboxHost::Local,
|
||||
thread_id,
|
||||
|
||||
@@ -22,6 +22,7 @@ async fn resumed_initial_messages_render_history() {
|
||||
let thread_id = ThreadId::new();
|
||||
let rollout_file = NamedTempFile::new().unwrap();
|
||||
let mut configured = crate::session_state::ThreadSessionState {
|
||||
read_only_history: false,
|
||||
daybreak_enabled: true,
|
||||
windows_sandbox_host: crate::app::WindowsSandboxHost::Local,
|
||||
thread_id,
|
||||
@@ -184,6 +185,7 @@ async fn restored_conversation_ultra_remains_selected_after_switching_to_plan()
|
||||
chat.set_plan_mode_reasoning_effort(Some(ReasoningEffortConfig::High));
|
||||
|
||||
chat.handle_thread_session(crate::session_state::ThreadSessionState {
|
||||
read_only_history: false,
|
||||
daybreak_enabled: false,
|
||||
windows_sandbox_host: crate::app::WindowsSandboxHost::Local,
|
||||
thread_id: ThreadId::new(),
|
||||
@@ -507,6 +509,7 @@ async fn replayed_user_message_preserves_text_elements_and_local_images() {
|
||||
let thread_id = ThreadId::new();
|
||||
let rollout_file = NamedTempFile::new().unwrap();
|
||||
let configured = crate::session_state::ThreadSessionState {
|
||||
read_only_history: false,
|
||||
daybreak_enabled: false,
|
||||
windows_sandbox_host: crate::app::WindowsSandboxHost::Local,
|
||||
thread_id,
|
||||
@@ -580,6 +583,7 @@ async fn replayed_user_message_preserves_remote_image_urls() {
|
||||
let thread_id = ThreadId::new();
|
||||
let rollout_file = NamedTempFile::new().unwrap();
|
||||
let configured = crate::session_state::ThreadSessionState {
|
||||
read_only_history: false,
|
||||
daybreak_enabled: false,
|
||||
windows_sandbox_host: crate::app::WindowsSandboxHost::Local,
|
||||
thread_id,
|
||||
@@ -687,6 +691,7 @@ async fn session_configured_syncs_widget_config_permissions_and_cwd() {
|
||||
.expect("permission profile should project to legacy sandbox policy");
|
||||
let expected_sandbox = SandboxPolicy::from(expected_core_sandbox);
|
||||
let configured = crate::session_state::ThreadSessionState {
|
||||
read_only_history: false,
|
||||
daybreak_enabled: false,
|
||||
windows_sandbox_host: crate::app::WindowsSandboxHost::Local,
|
||||
thread_id: ThreadId::new(),
|
||||
@@ -768,6 +773,7 @@ async fn session_configured_preserves_profile_workspace_roots() {
|
||||
let session_permission_profile = PermissionProfile::workspace_write()
|
||||
.materialize_project_roots_with_workspace_roots(&session_effective_workspace_roots);
|
||||
let configured = crate::session_state::ThreadSessionState {
|
||||
read_only_history: false,
|
||||
daybreak_enabled: false,
|
||||
windows_sandbox_host: crate::app::WindowsSandboxHost::Local,
|
||||
thread_id: ThreadId::new(),
|
||||
@@ -816,6 +822,7 @@ async fn session_configured_external_sandbox_keeps_external_runtime_policy() {
|
||||
network_access: NetworkAccess::Restricted,
|
||||
};
|
||||
let configured = crate::session_state::ThreadSessionState {
|
||||
read_only_history: false,
|
||||
daybreak_enabled: false,
|
||||
windows_sandbox_host: crate::app::WindowsSandboxHost::Local,
|
||||
thread_id: ThreadId::new(),
|
||||
@@ -858,6 +865,7 @@ async fn replayed_user_message_with_only_remote_images_renders_history_cell() {
|
||||
let thread_id = ThreadId::new();
|
||||
let rollout_file = NamedTempFile::new().unwrap();
|
||||
let configured = crate::session_state::ThreadSessionState {
|
||||
read_only_history: false,
|
||||
daybreak_enabled: false,
|
||||
windows_sandbox_host: crate::app::WindowsSandboxHost::Local,
|
||||
thread_id,
|
||||
@@ -919,6 +927,7 @@ async fn replayed_user_message_with_only_local_images_renders_history_cell() {
|
||||
let thread_id = ThreadId::new();
|
||||
let rollout_file = NamedTempFile::new().unwrap();
|
||||
let configured = crate::session_state::ThreadSessionState {
|
||||
read_only_history: false,
|
||||
daybreak_enabled: false,
|
||||
windows_sandbox_host: crate::app::WindowsSandboxHost::Local,
|
||||
thread_id,
|
||||
@@ -1277,6 +1286,7 @@ async fn replayed_reasoning_item_preserves_summary_parts_and_hides_raw_reasoning
|
||||
let (mut chat, mut rx, _op_rx) = make_chatwidget_manual(/*model_override*/ None).await;
|
||||
chat.config.show_raw_agent_reasoning = false;
|
||||
chat.handle_thread_session(crate::session_state::ThreadSessionState {
|
||||
read_only_history: false,
|
||||
daybreak_enabled: false,
|
||||
windows_sandbox_host: crate::app::WindowsSandboxHost::Local,
|
||||
thread_id: ThreadId::new(),
|
||||
@@ -1329,6 +1339,7 @@ async fn replayed_reasoning_item_shows_raw_reasoning_when_enabled() {
|
||||
let (mut chat, mut rx, _op_rx) = make_chatwidget_manual(/*model_override*/ None).await;
|
||||
chat.config.show_raw_agent_reasoning = true;
|
||||
chat.handle_thread_session(crate::session_state::ThreadSessionState {
|
||||
read_only_history: false,
|
||||
daybreak_enabled: false,
|
||||
windows_sandbox_host: crate::app::WindowsSandboxHost::Local,
|
||||
thread_id: ThreadId::new(),
|
||||
|
||||
@@ -1162,6 +1162,7 @@ async fn required_windows_sandbox_setup_defers_configured_initial_prompt() {
|
||||
create_initial_user_message(Some(initial_prompt.clone()), Vec::new(), Vec::new());
|
||||
|
||||
chat.handle_thread_session(crate::session_state::ThreadSessionState {
|
||||
read_only_history: false,
|
||||
daybreak_enabled: false,
|
||||
windows_sandbox_host: crate::app::WindowsSandboxHost::Local,
|
||||
thread_id: ThreadId::new(),
|
||||
@@ -1612,6 +1613,7 @@ async fn permissions_selection_marks_auto_review_current_after_session_configure
|
||||
.set_enabled(Feature::GuardianApproval, /*enabled*/ true);
|
||||
|
||||
chat.handle_thread_session(crate::session_state::ThreadSessionState {
|
||||
read_only_history: false,
|
||||
daybreak_enabled: false,
|
||||
windows_sandbox_host: crate::app::WindowsSandboxHost::Local,
|
||||
thread_id: ThreadId::new(),
|
||||
@@ -1666,6 +1668,7 @@ async fn permissions_selection_marks_auto_review_current_with_custom_workspace_w
|
||||
let permission_profile = app_server_workspace_write_profile(extra_root);
|
||||
|
||||
chat.handle_thread_session(crate::session_state::ThreadSessionState {
|
||||
read_only_history: false,
|
||||
daybreak_enabled: false,
|
||||
windows_sandbox_host: crate::app::WindowsSandboxHost::Local,
|
||||
thread_id: ThreadId::new(),
|
||||
|
||||
@@ -16,6 +16,7 @@ fn paste_hidden_plan_shell_payload(chat: &mut ChatWidget) -> String {
|
||||
|
||||
fn plan_test_session(thread_id: ThreadId) -> crate::session_state::ThreadSessionState {
|
||||
crate::session_state::ThreadSessionState {
|
||||
read_only_history: false,
|
||||
daybreak_enabled: false,
|
||||
windows_sandbox_host: crate::app::WindowsSandboxHost::Local,
|
||||
thread_id,
|
||||
@@ -1229,6 +1230,7 @@ async fn submit_user_message_emits_structured_plugin_mentions_from_bindings() {
|
||||
let thread_id = ThreadId::new();
|
||||
let rollout_file = NamedTempFile::new().unwrap();
|
||||
let configured = crate::session_state::ThreadSessionState {
|
||||
read_only_history: false,
|
||||
daybreak_enabled: false,
|
||||
windows_sandbox_host: crate::app::WindowsSandboxHost::Local,
|
||||
thread_id,
|
||||
|
||||
@@ -4719,6 +4719,7 @@ async fn session_configured_clears_goal_status_footer() {
|
||||
|
||||
let rollout_file = NamedTempFile::new().unwrap();
|
||||
chat.handle_thread_session(crate::session_state::ThreadSessionState {
|
||||
read_only_history: false,
|
||||
daybreak_enabled: false,
|
||||
windows_sandbox_host: crate::app::WindowsSandboxHost::Local,
|
||||
thread_id: ThreadId::new(),
|
||||
|
||||
@@ -622,6 +622,7 @@ fn image_generation_call_renders_saved_path() {
|
||||
|
||||
fn session_configured_event(model: &str) -> ThreadSessionState {
|
||||
ThreadSessionState {
|
||||
read_only_history: false,
|
||||
daybreak_enabled: false,
|
||||
windows_sandbox_host: crate::app::WindowsSandboxHost::Local,
|
||||
thread_id: ThreadId::new(),
|
||||
|
||||
@@ -27,6 +27,8 @@ pub(crate) struct MessageHistoryMetadata {
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub(crate) struct ThreadSessionState {
|
||||
/// This TUI opened saved history without a live attachment.
|
||||
pub(crate) read_only_history: bool,
|
||||
pub(crate) daybreak_enabled: bool,
|
||||
pub(crate) windows_sandbox_host: crate::app::WindowsSandboxHost,
|
||||
pub(crate) thread_id: ThreadId,
|
||||
|
||||
@@ -544,7 +544,7 @@ fn startup_draft_bottom_pane(
|
||||
..ChatComposerConfig::plain_text()
|
||||
},
|
||||
);
|
||||
bottom_pane.set_context_window_pending(/*pending*/ true);
|
||||
bottom_pane.set_context_window_hidden(/*hidden*/ true);
|
||||
bottom_pane
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user