mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
287 lines
12 KiB
Rust
287 lines
12 KiB
Rust
//! Construction and initial wiring for `ChatWidget`.
|
|
|
|
use super::*;
|
|
|
|
impl ChatWidget {
|
|
pub(crate) fn new_with_app_event(common: ChatWidgetInit) -> Self {
|
|
Self::new_with_op_target(common, CodexOpTarget::AppEvent)
|
|
}
|
|
|
|
pub(super) fn new_with_op_target(
|
|
common: ChatWidgetInit,
|
|
codex_op_target: CodexOpTarget,
|
|
) -> Self {
|
|
let ChatWidgetInit {
|
|
config,
|
|
frame_requester,
|
|
app_event_tx,
|
|
workspace_command_runner,
|
|
initial_user_message,
|
|
enhanced_keys_supported,
|
|
has_chatgpt_account,
|
|
has_codex_backend_auth,
|
|
model_catalog,
|
|
feedback,
|
|
is_first_run,
|
|
status_account_display,
|
|
runtime_model_provider_base_url,
|
|
initial_plan_type,
|
|
model,
|
|
startup_tooltip_override,
|
|
status_line_invalid_items_warned,
|
|
terminal_title_invalid_items_warned,
|
|
session_telemetry,
|
|
} = common;
|
|
let model = model.filter(|m| !m.trim().is_empty());
|
|
let mut config = config;
|
|
config.model = model.clone();
|
|
let prevent_idle_sleep = config.features.enabled(Feature::PreventIdleSleep);
|
|
let mut rng = rand::rng();
|
|
let placeholder = PLACEHOLDERS[rng.random_range(0..PLACEHOLDERS.len())].to_string();
|
|
let side_placeholder =
|
|
SIDE_PLACEHOLDERS[rng.random_range(0..SIDE_PLACEHOLDERS.len())].to_string();
|
|
|
|
let model_override = model.as_deref();
|
|
let model_for_header = model
|
|
.clone()
|
|
.unwrap_or_else(|| DEFAULT_MODEL_DISPLAY_NAME.to_string());
|
|
let active_collaboration_mask =
|
|
Self::initial_collaboration_mask(&config, model_catalog.as_ref(), model_override);
|
|
let header_model = active_collaboration_mask
|
|
.as_ref()
|
|
.and_then(|mask| mask.model.clone())
|
|
.unwrap_or_else(|| model_for_header.clone());
|
|
let fallback_default = Settings {
|
|
model: header_model.clone(),
|
|
reasoning_effort: None,
|
|
developer_instructions: None,
|
|
};
|
|
// Collaboration modes start in Default mode.
|
|
let current_collaboration_mode = CollaborationMode {
|
|
mode: ModeKind::Default,
|
|
settings: fallback_default,
|
|
};
|
|
|
|
let active_cell = Some(Self::placeholder_session_header_cell(&config));
|
|
|
|
let current_cwd = Some(config.cwd.to_path_buf());
|
|
let effective_service_tier = crate::service_tier_resolution::effective_service_tier(
|
|
&config,
|
|
&header_model,
|
|
&model_catalog.try_list_models().unwrap_or_default(),
|
|
);
|
|
let current_terminal_info = terminal_info();
|
|
let runtime_keymap = RuntimeKeymap::from_config(&config.tui_keymap).ok();
|
|
let default_keymap = RuntimeKeymap::defaults();
|
|
let copy_last_response_binding = runtime_keymap
|
|
.as_ref()
|
|
.map(|keymap| keymap.app.copy.clone())
|
|
.unwrap_or_else(|| default_keymap.app.copy.clone());
|
|
let chat_keymap = runtime_keymap
|
|
.as_ref()
|
|
.map(|keymap| keymap.chat.clone())
|
|
.unwrap_or_else(|| default_keymap.chat.clone());
|
|
let queued_message_edit_hint_binding = queued_message_edit_hint_binding(
|
|
&chat_keymap.edit_queued_message,
|
|
current_terminal_info,
|
|
);
|
|
pets::start_configured_pet_load_if_needed(
|
|
&config,
|
|
/*ambient_pet_missing*/ true,
|
|
frame_requester.clone(),
|
|
app_event_tx.clone(),
|
|
);
|
|
let mut widget = Self {
|
|
app_event_tx: app_event_tx.clone(),
|
|
frame_requester: frame_requester.clone(),
|
|
codex_op_target,
|
|
bottom_pane: BottomPane::new(BottomPaneParams {
|
|
frame_requester,
|
|
app_event_tx,
|
|
has_input_focus: true,
|
|
enhanced_keys_supported,
|
|
placeholder_text: placeholder.clone(),
|
|
disable_paste_burst: config.disable_paste_burst,
|
|
animations_enabled: config.animations,
|
|
skills: None,
|
|
}),
|
|
transcript: TranscriptState::new(active_cell),
|
|
raw_output_mode: config.tui_raw_output_mode,
|
|
config,
|
|
effective_service_tier,
|
|
skills_all: Vec::new(),
|
|
skills_initial_state: None,
|
|
current_collaboration_mode,
|
|
active_collaboration_mask,
|
|
has_chatgpt_account,
|
|
has_codex_backend_auth,
|
|
model_catalog,
|
|
session_telemetry,
|
|
session_header: SessionHeader::new(header_model),
|
|
initial_user_message,
|
|
status_account_display,
|
|
runtime_model_provider_base_url,
|
|
remote_connection: None,
|
|
token_info: None,
|
|
rate_limit_snapshots_by_limit_id: BTreeMap::new(),
|
|
refreshing_status_outputs: Vec::new(),
|
|
next_status_refresh_request_id: 0,
|
|
refreshing_token_activity_output: None,
|
|
completed_token_activity_output: None,
|
|
next_token_activity_request_id: 0,
|
|
pending_rate_limit_reset_request_id: None,
|
|
pending_rate_limit_reset_hint_request_id: None,
|
|
pending_usage_menu_rate_limit_request_id: None,
|
|
pending_rate_limit_reset_hint: None,
|
|
available_rate_limit_reset_credits: None,
|
|
next_rate_limit_reset_request_id: 0,
|
|
plan_type: initial_plan_type,
|
|
codex_rate_limit_reached_type: None,
|
|
rate_limit_warnings: RateLimitWarningState::default(),
|
|
warning_display_state: WarningDisplayState::default(),
|
|
rate_limit_switch_prompt: RateLimitSwitchPromptState::default(),
|
|
add_credits_nudge_email_in_flight: None,
|
|
adaptive_chunking: AdaptiveChunkingPolicy::default(),
|
|
stream_controller: None,
|
|
plan_stream_controller: None,
|
|
pending_stream_consolidations: 0,
|
|
clipboard_lease: None,
|
|
copy_last_response_binding,
|
|
running_commands: HashMap::new(),
|
|
collab_agent_metadata: HashMap::new(),
|
|
pending_collab_spawn_requests: HashMap::new(),
|
|
suppressed_exec_calls: HashSet::new(),
|
|
last_unified_wait: None,
|
|
unified_exec_wait_streak: None,
|
|
turn_lifecycle: TurnLifecycleState::new(prevent_idle_sleep),
|
|
safety_buffering: SafetyBufferingState::default(),
|
|
task_complete_pending: false,
|
|
unified_exec_processes: Vec::new(),
|
|
mcp_startup_status: None,
|
|
mcp_startup_expected_servers: None,
|
|
mcp_startup_ignore_updates_until_next_start: false,
|
|
mcp_startup_allow_terminal_only_next_round: false,
|
|
mcp_startup_pending_next_round: HashMap::new(),
|
|
mcp_startup_pending_next_round_saw_starting: false,
|
|
connectors: ConnectorsState::default(),
|
|
ide_context: IdeContextState::default(),
|
|
plugins_cache: PluginsCacheState::default(),
|
|
plugins_fetch_state: PluginListFetchState::default(),
|
|
plugin_remote_sections_loading: false,
|
|
plugin_remote_sections_loaded: false,
|
|
plugin_remote_section_errors: Vec::new(),
|
|
plugin_install_apps_needing_auth: Vec::new(),
|
|
plugin_install_auth_flow: None,
|
|
plugins_active_tab_id: None,
|
|
newly_installed_marketplace_tab_id: None,
|
|
interrupts: InterruptManager::new(),
|
|
reasoning_buffer: String::new(),
|
|
full_reasoning_buffer: String::new(),
|
|
status_state: StatusState::default(),
|
|
review: ReviewState::default(),
|
|
active_hook_cell: None,
|
|
ambient_pet: None,
|
|
pet_picker_preview_state: crate::pets::PetPickerPreviewState::default(),
|
|
pet_picker_preview_pet: None,
|
|
pet_picker_preview_request_id: 0,
|
|
pet_picker_preview_image_visible: std::cell::Cell::new(/*value*/ false),
|
|
pet_selection_load_request_id: 0,
|
|
#[cfg(test)]
|
|
pet_image_support_override: None,
|
|
thread_id: None,
|
|
dismissed_plan_mode_nudge_scopes: HashSet::new(),
|
|
thread_name: None,
|
|
thread_rename_block_message: None,
|
|
active_side_conversation: false,
|
|
normal_placeholder_text: placeholder,
|
|
side_placeholder_text: side_placeholder,
|
|
forked_from: None,
|
|
interrupted_turn_notice_mode: InterruptedTurnNoticeMode::Default,
|
|
input_queue: InputQueueState::default(),
|
|
cancel_edit: CancelEditState::default(),
|
|
chat_keymap,
|
|
queued_message_edit_hint_binding,
|
|
show_welcome_banner: is_first_run,
|
|
startup_tooltip_override,
|
|
suppress_session_configured_redraw: false,
|
|
suppress_initial_user_message_submit: false,
|
|
pending_notification: None,
|
|
quit_shortcut_expires_at: None,
|
|
quit_shortcut_key: None,
|
|
turn_runtime_metrics: RuntimeMetricsSummary::default(),
|
|
last_rendered_width: std::cell::Cell::new(None),
|
|
feedback,
|
|
current_rollout_path: None,
|
|
current_cwd,
|
|
workspace_command_runner,
|
|
instruction_source_paths: Vec::new(),
|
|
session_network_proxy: None,
|
|
status_line_invalid_items_warned,
|
|
terminal_title_invalid_items_warned,
|
|
last_terminal_title: None,
|
|
last_terminal_title_requires_action: false,
|
|
terminal_title_setup_original_items: None,
|
|
terminal_title_animation_origin: Instant::now(),
|
|
status_line_project_root_name_cache: None,
|
|
status_line_branch: None,
|
|
status_line_branch_cwd: None,
|
|
status_line_branch_pending: false,
|
|
status_line_branch_lookup_complete: false,
|
|
status_line_git_summary: None,
|
|
status_line_git_summary_cwd: None,
|
|
status_line_git_summary_pending: false,
|
|
status_line_git_summary_lookup_complete: false,
|
|
status_line_workspace_headline: None,
|
|
status_line_workspace_headline_pending_request_id: None,
|
|
next_status_line_workspace_headline_request_id: 0,
|
|
status_line_workspace_headline_last_requested_at: None,
|
|
status_line_workspace_messages_disabled: false,
|
|
current_goal_status_indicator: None,
|
|
current_goal_status: None,
|
|
external_editor_state: ExternalEditorState::Closed,
|
|
last_rendered_user_message_display: None,
|
|
last_non_retry_error: None,
|
|
};
|
|
|
|
widget.prefetch_rate_limits();
|
|
if let Some(keymap) = runtime_keymap {
|
|
widget.bottom_pane.set_keymap_bindings(&keymap);
|
|
}
|
|
widget
|
|
.bottom_pane
|
|
.set_vim_enabled(widget.config.tui_vim_mode_default);
|
|
widget
|
|
.bottom_pane
|
|
.set_status_line_enabled(!widget.configured_status_line_items().is_empty());
|
|
widget
|
|
.bottom_pane
|
|
.set_collaboration_modes_enabled(/*enabled*/ true);
|
|
widget.sync_service_tier_commands();
|
|
widget.sync_personality_command_enabled();
|
|
widget.sync_plugins_command_enabled();
|
|
widget.sync_goal_command_enabled();
|
|
widget.sync_mentions_v2_enabled();
|
|
widget
|
|
.bottom_pane
|
|
.set_queued_message_edit_binding(widget.queued_message_edit_hint_binding);
|
|
#[cfg(target_os = "windows")]
|
|
widget
|
|
.bottom_pane
|
|
.set_windows_degraded_sandbox_active(matches!(
|
|
crate::windows_sandbox::level_from_config(&widget.config),
|
|
WindowsSandboxLevel::RestrictedToken
|
|
));
|
|
widget.update_collaboration_mode_indicator();
|
|
|
|
widget
|
|
.bottom_pane
|
|
.set_connectors_enabled(widget.connectors_enabled());
|
|
widget
|
|
.bottom_pane
|
|
.set_token_activity_command_enabled(widget.has_codex_backend_auth);
|
|
widget.refresh_status_surfaces();
|
|
|
|
widget
|
|
}
|
|
}
|