CI / fmt (rustfmt --check) (push) Canceled after 0s
CI / clippy (ubuntu-latest) (push) Canceled after 0s
CI / clippy (windows-latest) (push) Canceled after 0s
CI / test (ubuntu-latest) (push) Canceled after 0s
CI / test (windows-latest) (push) Canceled after 0s
CI / build release (ubuntu-latest) (push) Canceled after 0s
CI / build release (windows-latest) (push) Canceled after 0s
Guards / core 零 UI 守门 (push) Canceled after 0s
Guards / 文件行数 ≤400 守门 (push) Canceled after 0s
Guards / 依赖许可与来源(cargo-deny) (push) Canceled after 0s
Rust 原生单文件 Minecraft 启动器:CLI 完整可用(install/launch/accounts/java/diagnose/agent), MCP server 接入外部 Agent 工具,GUI 开发中。
104 lines
3.7 KiB
Rust
104 lines
3.7 KiB
Rust
//! AI 页与覆盖层:会话消息、对话框(一次一条)、Toast。
|
|
|
|
use crate::dialogs as dlg;
|
|
use crate::dto::ChatRole as DtoChatRole;
|
|
use crate::state::AppState;
|
|
use crate::toast as toast_mod;
|
|
use crate::{ChatRole, DialogKind, UiChatMessage, UiDialog, UiToast};
|
|
|
|
/// AI 会话消息。
|
|
pub fn chat(state: &AppState) -> Vec<UiChatMessage> {
|
|
state
|
|
.ai
|
|
.messages
|
|
.iter()
|
|
.map(|message| UiChatMessage {
|
|
role: match message.role {
|
|
DtoChatRole::User => ChatRole::User,
|
|
DtoChatRole::Assistant => ChatRole::Assistant,
|
|
DtoChatRole::Tool => ChatRole::Tool,
|
|
DtoChatRole::System => ChatRole::System,
|
|
},
|
|
text: message.text.clone().into(),
|
|
tool_name: message
|
|
.tool
|
|
.as_ref()
|
|
.map(|tool| tool.name.clone())
|
|
.unwrap_or_default()
|
|
.into(),
|
|
tool_ok: message.tool.as_ref().is_none_or(|tool| tool.ok),
|
|
streaming: message.streaming,
|
|
})
|
|
.collect()
|
|
}
|
|
|
|
/// 当前对话框(一次一条)+ 是否显示 + 队列剩余条数。
|
|
pub fn dialog(state: &AppState) -> (UiDialog, bool, i32) {
|
|
let queued = i32::try_from(state.dialogs.pending_len()).unwrap_or(0);
|
|
match state.dialogs.current() {
|
|
None => (UiDialog::default(), false, queued),
|
|
Some(request) => {
|
|
let (kind, primary, secondary) = match &request.kind {
|
|
dlg::DialogKind::Confirm { primary, secondary } => {
|
|
(DialogKind::Confirm, primary.clone(), secondary.clone())
|
|
}
|
|
dlg::DialogKind::Input { primary, .. } => {
|
|
(DialogKind::Input, primary.clone(), String::new())
|
|
}
|
|
dlg::DialogKind::Progress { .. } => {
|
|
(DialogKind::Progress, "取消".to_string(), String::new())
|
|
}
|
|
dlg::DialogKind::Error { primary, .. } => {
|
|
(DialogKind::Error, primary.clone(), "忽略".to_string())
|
|
}
|
|
};
|
|
let progress = match &request.kind {
|
|
dlg::DialogKind::Progress { progress, .. } => *progress,
|
|
_ => 0.0,
|
|
};
|
|
let input_label = match &request.kind {
|
|
dlg::DialogKind::Input { label, .. } => label.clone(),
|
|
_ => String::new(),
|
|
};
|
|
let input_value = match &request.kind {
|
|
dlg::DialogKind::Input { value, .. } => value.clone(),
|
|
_ => String::new(),
|
|
};
|
|
(
|
|
UiDialog {
|
|
id: request.id.to_string().into(),
|
|
kind,
|
|
title: request.title.clone().into(),
|
|
body: request.body.clone().into(),
|
|
primary: primary.into(),
|
|
secondary: secondary.into(),
|
|
progress,
|
|
input_label: input_label.into(),
|
|
input_value: input_value.into(),
|
|
},
|
|
true,
|
|
queued,
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Toast 列表。
|
|
pub fn toasts(state: &AppState) -> Vec<UiToast> {
|
|
state
|
|
.toasts
|
|
.items()
|
|
.iter()
|
|
.map(|toast| UiToast {
|
|
id: toast.id.to_string().into(),
|
|
kind: match toast.kind {
|
|
toast_mod::ToastKind::Info => crate::ToastKind::Info,
|
|
toast_mod::ToastKind::Success => crate::ToastKind::Success,
|
|
toast_mod::ToastKind::Warn => crate::ToastKind::Warn,
|
|
toast_mod::ToastKind::Error => crate::ToastKind::Error,
|
|
},
|
|
text: toast.text.clone().into(),
|
|
})
|
|
.collect()
|
|
}
|