mirror of
https://github.com/openai/codex.git
synced 2026-11-06 00:30:29 +00:00
Preserve in-flight state when restoring thread input (#33203)
## What changed - Add an explicit restore mode for thread input snapshots and use it when replaying thread snapshots. - Preserve the pending-steer interrupt flag alongside running-turn and queued-input state when restoring an in-flight turn. - When in-flight state is not preserved, clear stale running flags and move pending steers ahead of already queued follow-ups while retaining their history records. ## Testing - Expand TUI tests to cover both restoration modes, including sleep-inhibitor state, pending-steer ordering, history records, and queued submission. GitOrigin-RevId: f4e8b2bdf065ef6c6644b7f0ea9cf32c8a9af619
This commit is contained in:
1 parent
469ce0db51
commit
77a3f4e80f
7 files changed
+184
-58
No files matched your search
@@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
use super::session_lifecycle::ThreadAttachPresentation;
|
use super::session_lifecycle::ThreadAttachPresentation;
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::chatwidget::ThreadInputStateRestoreMode;
|
||||||
use crate::session_resume::read_session_model;
|
use crate::session_resume::read_session_model;
|
||||||
|
|
||||||
impl App {
|
impl App {
|
||||||
@@ -1344,8 +1345,12 @@ impl App {
|
|||||||
}
|
}
|
||||||
self.chat_widget
|
self.chat_widget
|
||||||
.set_queue_autosend_suppressed(/*suppressed*/ true);
|
.set_queue_autosend_suppressed(/*suppressed*/ true);
|
||||||
self.chat_widget
|
self.chat_widget.restore_thread_input_state(
|
||||||
.restore_thread_input_state(snapshot.input_state);
|
snapshot.input_state,
|
||||||
|
ThreadInputStateRestoreMode {
|
||||||
|
preserve_in_flight_turn: true,
|
||||||
|
},
|
||||||
|
);
|
||||||
if !snapshot.turns.is_empty() {
|
if !snapshot.turns.is_empty() {
|
||||||
self.chat_widget
|
self.chat_widget
|
||||||
.replay_thread_turns(snapshot.turns, ReplayKind::ThreadSnapshot);
|
.replay_thread_turns(snapshot.turns, ReplayKind::ThreadSnapshot);
|
||||||
|
|||||||
@@ -427,6 +427,7 @@ use self::user_messages::QueuedUserMessage;
|
|||||||
use self::user_messages::ShellEscapePolicy;
|
use self::user_messages::ShellEscapePolicy;
|
||||||
use self::user_messages::ThreadComposerState;
|
use self::user_messages::ThreadComposerState;
|
||||||
pub(crate) use self::user_messages::ThreadInputState;
|
pub(crate) use self::user_messages::ThreadInputState;
|
||||||
|
pub(crate) use self::user_messages::ThreadInputStateRestoreMode;
|
||||||
pub(crate) use self::user_messages::UserMessage;
|
pub(crate) use self::user_messages::UserMessage;
|
||||||
use self::user_messages::UserMessageDisplay;
|
use self::user_messages::UserMessageDisplay;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
//! Input queue restore and thread-input snapshot behavior for `ChatWidget`.
|
//! Input queue restore and thread-input snapshot behavior for `ChatWidget`.
|
||||||
|
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
use super::user_messages::remap_colliding_paste_placeholders;
|
use super::user_messages::remap_colliding_paste_placeholders;
|
||||||
use super::*;
|
use super::*;
|
||||||
@@ -338,6 +339,9 @@ impl ChatWidget {
|
|||||||
.queued_user_message_history_records
|
.queued_user_message_history_records
|
||||||
.clone(),
|
.clone(),
|
||||||
user_turn_pending_start: self.input_queue.user_turn_pending_start,
|
user_turn_pending_start: self.input_queue.user_turn_pending_start,
|
||||||
|
submit_pending_steers_after_interrupt: self
|
||||||
|
.input_queue
|
||||||
|
.submit_pending_steers_after_interrupt,
|
||||||
current_collaboration_mode: self.current_collaboration_mode.clone(),
|
current_collaboration_mode: self.current_collaboration_mode.clone(),
|
||||||
active_collaboration_mask: self.active_collaboration_mask.clone(),
|
active_collaboration_mask: self.active_collaboration_mask.clone(),
|
||||||
task_running: self.bottom_pane.is_task_running(),
|
task_running: self.bottom_pane.is_task_running(),
|
||||||
@@ -345,15 +349,26 @@ impl ChatWidget {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn restore_thread_input_state(&mut self, input_state: Option<ThreadInputState>) {
|
pub(crate) fn restore_thread_input_state(
|
||||||
let restored_task_running = input_state.as_ref().is_some_and(|state| state.task_running);
|
&mut self,
|
||||||
|
input_state: Option<ThreadInputState>,
|
||||||
|
restore_mode: ThreadInputStateRestoreMode,
|
||||||
|
) {
|
||||||
|
let preserve_in_flight_turn = restore_mode.preserve_in_flight_turn;
|
||||||
|
let restored_task_running =
|
||||||
|
preserve_in_flight_turn && input_state.as_ref().is_some_and(|state| state.task_running);
|
||||||
if let Some(input_state) = input_state {
|
if let Some(input_state) = input_state {
|
||||||
self.current_collaboration_mode = input_state.current_collaboration_mode;
|
self.current_collaboration_mode = input_state.current_collaboration_mode;
|
||||||
self.active_collaboration_mask = input_state.active_collaboration_mask;
|
self.active_collaboration_mask = input_state.active_collaboration_mask;
|
||||||
self.safety_buffering_prompt = input_state.safety_buffering_prompt;
|
self.safety_buffering_prompt = input_state.safety_buffering_prompt;
|
||||||
self.turn_lifecycle
|
self.turn_lifecycle.restore_running(
|
||||||
.restore_running(input_state.agent_turn_running, Instant::now());
|
preserve_in_flight_turn && input_state.agent_turn_running,
|
||||||
self.input_queue.user_turn_pending_start = input_state.user_turn_pending_start;
|
Instant::now(),
|
||||||
|
);
|
||||||
|
self.input_queue.user_turn_pending_start =
|
||||||
|
preserve_in_flight_turn && input_state.user_turn_pending_start;
|
||||||
|
self.input_queue.submit_pending_steers_after_interrupt =
|
||||||
|
preserve_in_flight_turn && input_state.submit_pending_steers_after_interrupt;
|
||||||
self.update_collaboration_mode_indicator();
|
self.update_collaboration_mode_indicator();
|
||||||
self.refresh_model_dependent_surfaces();
|
self.refresh_model_dependent_surfaces();
|
||||||
self.restore_composer_state(input_state.composer.unwrap_or_default());
|
self.restore_composer_state(input_state.composer.unwrap_or_default());
|
||||||
@@ -363,22 +378,37 @@ impl ChatWidget {
|
|||||||
UserMessageHistoryRecord::UserMessageText,
|
UserMessageHistoryRecord::UserMessageText,
|
||||||
);
|
);
|
||||||
let mut pending_steer_compare_keys = input_state.pending_steer_compare_keys;
|
let mut pending_steer_compare_keys = input_state.pending_steer_compare_keys;
|
||||||
self.input_queue.pending_steers = input_state
|
let pending_steers = input_state.pending_steers;
|
||||||
.pending_steers
|
let mut queued_user_messages = input_state.queued_user_messages;
|
||||||
.into_iter()
|
let mut queued_user_message_history_records =
|
||||||
.zip(pending_steer_history_records)
|
input_state.queued_user_message_history_records;
|
||||||
.map(|(user_message, history_record)| PendingSteer {
|
if preserve_in_flight_turn {
|
||||||
compare_key: pending_steer_compare_keys.pop_front().unwrap_or_else(|| {
|
self.input_queue.pending_steers = pending_steers
|
||||||
PendingSteerCompareKey {
|
.into_iter()
|
||||||
message: user_message.text.clone(),
|
.zip(pending_steer_history_records)
|
||||||
image_count: user_message.local_images.len()
|
.map(|(user_message, history_record)| PendingSteer {
|
||||||
+ user_message.remote_image_urls.len(),
|
compare_key: pending_steer_compare_keys.pop_front().unwrap_or_else(|| {
|
||||||
}
|
PendingSteerCompareKey {
|
||||||
}),
|
message: user_message.text.clone(),
|
||||||
history_record,
|
image_count: user_message.local_images.len()
|
||||||
user_message,
|
+ user_message.remote_image_urls.len(),
|
||||||
})
|
}
|
||||||
.collect();
|
}),
|
||||||
|
history_record,
|
||||||
|
user_message,
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
} else {
|
||||||
|
self.input_queue.pending_steers.clear();
|
||||||
|
let mut safety_retry_follow_ups = pending_steers
|
||||||
|
.into_iter()
|
||||||
|
.map(QueuedUserMessage::from)
|
||||||
|
.collect::<VecDeque<_>>();
|
||||||
|
safety_retry_follow_ups.append(&mut queued_user_messages);
|
||||||
|
queued_user_messages = safety_retry_follow_ups;
|
||||||
|
pending_steer_history_records.append(&mut queued_user_message_history_records);
|
||||||
|
queued_user_message_history_records = pending_steer_history_records;
|
||||||
|
}
|
||||||
self.input_queue.rejected_steers_queue = input_state.rejected_steers_queue;
|
self.input_queue.rejected_steers_queue = input_state.rejected_steers_queue;
|
||||||
self.input_queue.rejected_steer_history_records =
|
self.input_queue.rejected_steer_history_records =
|
||||||
input_state.rejected_steer_history_records;
|
input_state.rejected_steer_history_records;
|
||||||
@@ -386,9 +416,9 @@ impl ChatWidget {
|
|||||||
self.input_queue.rejected_steers_queue.len(),
|
self.input_queue.rejected_steers_queue.len(),
|
||||||
UserMessageHistoryRecord::UserMessageText,
|
UserMessageHistoryRecord::UserMessageText,
|
||||||
);
|
);
|
||||||
self.input_queue.queued_user_messages = input_state.queued_user_messages;
|
self.input_queue.queued_user_messages = queued_user_messages;
|
||||||
self.input_queue.queued_user_message_history_records =
|
self.input_queue.queued_user_message_history_records =
|
||||||
input_state.queued_user_message_history_records;
|
queued_user_message_history_records;
|
||||||
self.input_queue.queued_user_message_history_records.resize(
|
self.input_queue.queued_user_message_history_records.resize(
|
||||||
self.input_queue.queued_user_messages.len(),
|
self.input_queue.queued_user_messages.len(),
|
||||||
UserMessageHistoryRecord::UserMessageText,
|
UserMessageHistoryRecord::UserMessageText,
|
||||||
|
|||||||
@@ -1068,38 +1068,101 @@ async fn pending_steer_interrupt_uses_remapped_binding() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn restore_thread_input_state_syncs_sleep_inhibitor_state() {
|
async fn restore_thread_input_state_applies_running_state_policy() {
|
||||||
let (mut chat, _rx, _op_rx) = make_chatwidget_manual(/*model_override*/ None).await;
|
let (mut chat, _rx, mut op_rx) = make_chatwidget_manual(/*model_override*/ None).await;
|
||||||
|
chat.thread_id = Some(ThreadId::new());
|
||||||
chat.set_feature_enabled(Feature::PreventIdleSleep, /*enabled*/ true);
|
chat.set_feature_enabled(Feature::PreventIdleSleep, /*enabled*/ true);
|
||||||
|
|
||||||
chat.restore_thread_input_state(Some(ThreadInputState {
|
let pending_history = UserMessageHistoryRecord::Override(UserMessageHistoryOverride {
|
||||||
composer: None,
|
text: "submitted history".to_string(),
|
||||||
|
text_elements: Vec::new(),
|
||||||
|
});
|
||||||
|
let queued_history = UserMessageHistoryRecord::Override(UserMessageHistoryOverride {
|
||||||
|
text: "queued history".to_string(),
|
||||||
|
text_elements: Vec::new(),
|
||||||
|
});
|
||||||
|
let input_state = ThreadInputState {
|
||||||
|
composer: Some(ThreadComposerState {
|
||||||
|
text: "composer draft".to_string(),
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
safety_buffering_prompt: Some(UserMessage::from("buffered prompt")),
|
safety_buffering_prompt: Some(UserMessage::from("buffered prompt")),
|
||||||
pending_steers: VecDeque::new(),
|
pending_steers: VecDeque::from([UserMessage::from("submitted to the interrupted turn")]),
|
||||||
pending_steer_history_records: VecDeque::new(),
|
pending_steer_history_records: VecDeque::from([pending_history.clone()]),
|
||||||
pending_steer_compare_keys: VecDeque::new(),
|
pending_steer_compare_keys: VecDeque::new(),
|
||||||
rejected_steers_queue: VecDeque::new(),
|
rejected_steers_queue: VecDeque::new(),
|
||||||
rejected_steer_history_records: VecDeque::new(),
|
rejected_steer_history_records: VecDeque::new(),
|
||||||
queued_user_messages: VecDeque::new(),
|
queued_user_messages: VecDeque::from([UserMessage::from("already queued").into()]),
|
||||||
queued_user_message_history_records: VecDeque::new(),
|
queued_user_message_history_records: VecDeque::from([queued_history.clone()]),
|
||||||
user_turn_pending_start: false,
|
user_turn_pending_start: true,
|
||||||
|
submit_pending_steers_after_interrupt: true,
|
||||||
current_collaboration_mode: chat.current_collaboration_mode.clone(),
|
current_collaboration_mode: chat.current_collaboration_mode.clone(),
|
||||||
active_collaboration_mask: chat.active_collaboration_mask.clone(),
|
active_collaboration_mask: chat.active_collaboration_mask.clone(),
|
||||||
task_running: true,
|
task_running: true,
|
||||||
agent_turn_running: true,
|
agent_turn_running: true,
|
||||||
}));
|
};
|
||||||
|
chat.restore_thread_input_state(
|
||||||
|
Some(input_state.clone()),
|
||||||
|
ThreadInputStateRestoreMode {
|
||||||
|
preserve_in_flight_turn: true,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
assert!(chat.turn_lifecycle.agent_turn_running);
|
assert!(chat.turn_lifecycle.agent_turn_running);
|
||||||
assert!(chat.turn_lifecycle.sleep_inhibitor.is_turn_running());
|
assert!(chat.turn_lifecycle.sleep_inhibitor.is_turn_running());
|
||||||
assert!(chat.bottom_pane.is_task_running());
|
assert!(chat.bottom_pane.is_task_running());
|
||||||
|
assert!(chat.input_queue.user_turn_pending_start);
|
||||||
|
assert!(chat.input_queue.submit_pending_steers_after_interrupt);
|
||||||
|
let captured_input_state = chat
|
||||||
|
.capture_thread_input_state()
|
||||||
|
.expect("thread input state");
|
||||||
|
assert!(captured_input_state.submit_pending_steers_after_interrupt);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
chat.capture_thread_input_state()
|
captured_input_state.safety_buffering_prompt,
|
||||||
.expect("thread input state")
|
Some(UserMessage::from("buffered prompt"))
|
||||||
.safety_buffering_prompt,
|
);
|
||||||
|
assert_eq!(chat.input_queue.pending_steers.len(), 1);
|
||||||
|
assert_eq!(
|
||||||
|
chat.safety_buffering_prompt,
|
||||||
Some(UserMessage::from("buffered prompt"))
|
Some(UserMessage::from("buffered prompt"))
|
||||||
);
|
);
|
||||||
|
|
||||||
chat.restore_thread_input_state(/*input_state*/ None);
|
chat.restore_thread_input_state(
|
||||||
|
Some(input_state),
|
||||||
|
ThreadInputStateRestoreMode {
|
||||||
|
preserve_in_flight_turn: false,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(!chat.turn_lifecycle.agent_turn_running);
|
||||||
|
assert!(!chat.turn_lifecycle.sleep_inhibitor.is_turn_running());
|
||||||
|
assert!(!chat.bottom_pane.is_task_running());
|
||||||
|
assert!(!chat.input_queue.user_turn_pending_start);
|
||||||
|
assert!(!chat.input_queue.submit_pending_steers_after_interrupt);
|
||||||
|
assert!(chat.input_queue.pending_steers.is_empty());
|
||||||
|
assert_eq!(chat.bottom_pane.composer_text(), "composer draft");
|
||||||
|
assert_eq!(
|
||||||
|
chat.safety_buffering_prompt,
|
||||||
|
Some(UserMessage::from("buffered prompt"))
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
chat.queued_user_message_texts(),
|
||||||
|
vec!["submitted to the interrupted turn", "already queued"]
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
chat.input_queue.queued_user_message_history_records,
|
||||||
|
VecDeque::from([pending_history, queued_history])
|
||||||
|
);
|
||||||
|
assert!(chat.maybe_send_next_queued_input());
|
||||||
|
assert_matches!(next_submit_op(&mut op_rx), Op::UserTurn { .. });
|
||||||
|
assert_eq!(chat.queued_user_message_texts(), vec!["already queued"]);
|
||||||
|
|
||||||
|
chat.restore_thread_input_state(
|
||||||
|
/*input_state*/ None,
|
||||||
|
ThreadInputStateRestoreMode {
|
||||||
|
preserve_in_flight_turn: true,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
assert!(!chat.turn_lifecycle.agent_turn_running);
|
assert!(!chat.turn_lifecycle.agent_turn_running);
|
||||||
assert!(!chat.turn_lifecycle.sleep_inhibitor.is_turn_running());
|
assert!(!chat.turn_lifecycle.sleep_inhibitor.is_turn_running());
|
||||||
|
|||||||
@@ -373,22 +373,28 @@ async fn restore_thread_input_state_restores_pending_steers_without_downgrading_
|
|||||||
let mut queued_user_messages = VecDeque::new();
|
let mut queued_user_messages = VecDeque::new();
|
||||||
queued_user_messages.push_back(UserMessage::from("queued draft").into());
|
queued_user_messages.push_back(UserMessage::from("queued draft").into());
|
||||||
|
|
||||||
chat.restore_thread_input_state(Some(ThreadInputState {
|
chat.restore_thread_input_state(
|
||||||
composer: None,
|
Some(ThreadInputState {
|
||||||
safety_buffering_prompt: None,
|
composer: None,
|
||||||
pending_steers,
|
safety_buffering_prompt: None,
|
||||||
pending_steer_history_records: VecDeque::new(),
|
pending_steers,
|
||||||
pending_steer_compare_keys,
|
pending_steer_history_records: VecDeque::new(),
|
||||||
rejected_steers_queue,
|
pending_steer_compare_keys,
|
||||||
rejected_steer_history_records: VecDeque::new(),
|
rejected_steers_queue,
|
||||||
queued_user_messages,
|
rejected_steer_history_records: VecDeque::new(),
|
||||||
queued_user_message_history_records: VecDeque::new(),
|
queued_user_messages,
|
||||||
user_turn_pending_start: false,
|
queued_user_message_history_records: VecDeque::new(),
|
||||||
current_collaboration_mode: chat.current_collaboration_mode.clone(),
|
user_turn_pending_start: false,
|
||||||
active_collaboration_mask: chat.active_collaboration_mask.clone(),
|
submit_pending_steers_after_interrupt: false,
|
||||||
task_running: false,
|
current_collaboration_mode: chat.current_collaboration_mode.clone(),
|
||||||
agent_turn_running: false,
|
active_collaboration_mask: chat.active_collaboration_mask.clone(),
|
||||||
}));
|
task_running: false,
|
||||||
|
agent_turn_running: false,
|
||||||
|
}),
|
||||||
|
ThreadInputStateRestoreMode {
|
||||||
|
preserve_in_flight_turn: true,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
chat.queued_user_message_texts(),
|
chat.queued_user_message_texts(),
|
||||||
|
|||||||
@@ -539,9 +539,19 @@ async fn queued_inline_rename_does_not_drain_again_before_turn_started() {
|
|||||||
);
|
);
|
||||||
let input_state = chat.capture_thread_input_state().unwrap();
|
let input_state = chat.capture_thread_input_state().unwrap();
|
||||||
assert!(input_state.user_turn_pending_start);
|
assert!(input_state.user_turn_pending_start);
|
||||||
chat.restore_thread_input_state(/*input_state*/ None);
|
chat.restore_thread_input_state(
|
||||||
|
/*input_state*/ None,
|
||||||
|
ThreadInputStateRestoreMode {
|
||||||
|
preserve_in_flight_turn: true,
|
||||||
|
},
|
||||||
|
);
|
||||||
assert!(!chat.input_queue.user_turn_pending_start);
|
assert!(!chat.input_queue.user_turn_pending_start);
|
||||||
chat.restore_thread_input_state(Some(input_state));
|
chat.restore_thread_input_state(
|
||||||
|
Some(input_state),
|
||||||
|
ThreadInputStateRestoreMode {
|
||||||
|
preserve_in_flight_turn: true,
|
||||||
|
},
|
||||||
|
);
|
||||||
assert!(chat.input_queue.user_turn_pending_start);
|
assert!(chat.input_queue.user_turn_pending_start);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
chat.queued_user_message_texts(),
|
chat.queued_user_message_texts(),
|
||||||
@@ -987,7 +997,12 @@ async fn restored_queued_goal_slash_command_emits_set_goal_event() {
|
|||||||
let (mut restored_chat, mut restored_rx, mut restored_op_rx) =
|
let (mut restored_chat, mut restored_rx, mut restored_op_rx) =
|
||||||
make_chatwidget_manual(/*model_override*/ None).await;
|
make_chatwidget_manual(/*model_override*/ None).await;
|
||||||
restored_chat.set_feature_enabled(Feature::Goals, /*enabled*/ true);
|
restored_chat.set_feature_enabled(Feature::Goals, /*enabled*/ true);
|
||||||
restored_chat.restore_thread_input_state(Some(input_state));
|
restored_chat.restore_thread_input_state(
|
||||||
|
Some(input_state),
|
||||||
|
ThreadInputStateRestoreMode {
|
||||||
|
preserve_in_flight_turn: true,
|
||||||
|
},
|
||||||
|
);
|
||||||
let thread_id = ThreadId::new();
|
let thread_id = ThreadId::new();
|
||||||
restored_chat.thread_id = Some(thread_id);
|
restored_chat.thread_id = Some(thread_id);
|
||||||
restored_chat.maybe_send_next_queued_input();
|
restored_chat.maybe_send_next_queued_input();
|
||||||
|
|||||||
@@ -132,12 +132,18 @@ pub(crate) struct ThreadInputState {
|
|||||||
pub(super) queued_user_messages: VecDeque<QueuedUserMessage>,
|
pub(super) queued_user_messages: VecDeque<QueuedUserMessage>,
|
||||||
pub(super) queued_user_message_history_records: VecDeque<UserMessageHistoryRecord>,
|
pub(super) queued_user_message_history_records: VecDeque<UserMessageHistoryRecord>,
|
||||||
pub(super) user_turn_pending_start: bool,
|
pub(super) user_turn_pending_start: bool,
|
||||||
|
pub(super) submit_pending_steers_after_interrupt: bool,
|
||||||
pub(super) current_collaboration_mode: CollaborationMode,
|
pub(super) current_collaboration_mode: CollaborationMode,
|
||||||
pub(super) active_collaboration_mask: Option<CollaborationModeMask>,
|
pub(super) active_collaboration_mask: Option<CollaborationModeMask>,
|
||||||
pub(super) task_running: bool,
|
pub(super) task_running: bool,
|
||||||
pub(super) agent_turn_running: bool,
|
pub(super) agent_turn_running: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub(crate) struct ThreadInputStateRestoreMode {
|
||||||
|
pub(crate) preserve_in_flight_turn: bool,
|
||||||
|
}
|
||||||
|
|
||||||
impl From<String> for UserMessage {
|
impl From<String> for UserMessage {
|
||||||
fn from(text: String) -> Self {
|
fn from(text: String) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
|||||||
Reference in new issue
Block a user