optimize: channel Message Commands — Multilingual Support and Prefixes
This commit is contained in:
@@ -156,7 +156,7 @@ async fn dispatch_command(
|
||||
};
|
||||
if has_session {
|
||||
return session_commands::handle_followup(
|
||||
db, text, channel_id, sender_id, conn_mgr, bridge, lang,
|
||||
db, text, channel_id, sender_id, conn_mgr, bridge, lang, prefix,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
@@ -193,23 +193,23 @@ async fn dispatch_command(
|
||||
|
||||
// Session commands
|
||||
"folder" => {
|
||||
session_commands::handle_folder(db, args, channel_id, sender_id, lang).await
|
||||
session_commands::handle_folder(db, args, channel_id, sender_id, lang, prefix).await
|
||||
}
|
||||
"agent" => {
|
||||
session_commands::handle_agent(db, args, channel_id, sender_id, lang).await
|
||||
session_commands::handle_agent(db, args, channel_id, sender_id, lang, prefix).await
|
||||
}
|
||||
"task" | "do" => {
|
||||
session_commands::handle_task(
|
||||
db, args, channel_id, sender_id, conn_mgr, emitter, bridge, lang,
|
||||
db, args, channel_id, sender_id, conn_mgr, emitter, bridge, lang, prefix,
|
||||
)
|
||||
.await
|
||||
}
|
||||
"sessions" => {
|
||||
session_commands::handle_sessions(db, channel_id, sender_id, lang).await
|
||||
session_commands::handle_sessions(db, channel_id, sender_id, lang, prefix).await
|
||||
}
|
||||
"resume" => {
|
||||
session_commands::handle_resume(
|
||||
db, args, channel_id, sender_id, conn_mgr, emitter, bridge, lang,
|
||||
db, args, channel_id, sender_id, conn_mgr, emitter, bridge, lang, prefix,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
@@ -610,14 +610,14 @@ pub fn help_title(lang: Lang) -> &'static str {
|
||||
pub fn help_body(lang: Lang, prefix: &str) -> String {
|
||||
match lang {
|
||||
Lang::ZhCn => format!(
|
||||
"📂 {prefix}folder - 选择工作目录\n\
|
||||
🤖 {prefix}agent - 选择 Agent\n\
|
||||
🚀 {prefix}task <描述> - 创建会话并执行任务\n\
|
||||
📋 {prefix}sessions - 当前目录的活跃会话\n\
|
||||
▶️ {prefix}resume <ID> - 恢复已有会话\n\
|
||||
⏹️ {prefix}cancel - 取消当前任务\n\
|
||||
✅ {prefix}approve [always] - 批准权限请求\n\
|
||||
❌ {prefix}deny - 拒绝权限请求\n\
|
||||
"{prefix}folder - 选择工作目录\n\
|
||||
{prefix}agent - 选择 Agent\n\
|
||||
{prefix}task <描述> - 创建会话并执行任务\n\
|
||||
{prefix}sessions - 当前目录的活跃会话\n\
|
||||
{prefix}resume <ID> - 恢复已有会话\n\
|
||||
{prefix}cancel - 取消当前任务\n\
|
||||
{prefix}approve [always] - 批准权限请求\n\
|
||||
{prefix}deny - 拒绝权限请求\n\
|
||||
\n\
|
||||
{prefix}recent - 最近 5 条会话\n\
|
||||
{prefix}search <关键词> - 搜索会话\n\
|
||||
@@ -626,81 +626,169 @@ pub fn help_body(lang: Lang, prefix: &str) -> String {
|
||||
{prefix}status - 渠道连接状态\n\
|
||||
{prefix}help - 显示帮助\n\
|
||||
\n\
|
||||
💡 有活跃会话时,直接发文本即可继续对话"
|
||||
有活跃会话时,直接发文本即可继续对话"
|
||||
),
|
||||
Lang::ZhTw => format!(
|
||||
"{prefix}recent - 最近 5 條對話\n\
|
||||
"{prefix}folder - 選擇工作目錄\n\
|
||||
{prefix}agent - 選擇 Agent\n\
|
||||
{prefix}task <描述> - 建立對話並執行任務\n\
|
||||
{prefix}sessions - 當前目錄的活躍對話\n\
|
||||
{prefix}resume <ID> - 恢復已有對話\n\
|
||||
{prefix}cancel - 取消當前任務\n\
|
||||
{prefix}approve [always] - 批准權限請求\n\
|
||||
{prefix}deny - 拒絕權限請求\n\
|
||||
\n\
|
||||
{prefix}recent - 最近 5 條對話\n\
|
||||
{prefix}search <關鍵字> - 搜尋對話\n\
|
||||
{prefix}detail <ID> - 對話詳情\n\
|
||||
{prefix}today - 今日活動匯總\n\
|
||||
{prefix}status - 頻道連線狀態\n\
|
||||
{prefix}help - 顯示幫助"
|
||||
{prefix}help - 顯示幫助\n\
|
||||
\n\
|
||||
有活躍對話時,直接發文字即可繼續對話"
|
||||
),
|
||||
Lang::Ja => format!(
|
||||
"{prefix}recent - 最新5件のセッション\n\
|
||||
"{prefix}folder - 作業フォルダを選択\n\
|
||||
{prefix}agent - エージェントを選択\n\
|
||||
{prefix}task <説明> - セッションを作成してタスクを実行\n\
|
||||
{prefix}sessions - フォルダ内のアクティブセッション\n\
|
||||
{prefix}resume <ID> - セッションを再開\n\
|
||||
{prefix}cancel - 現在のタスクをキャンセル\n\
|
||||
{prefix}approve [always] - 権限を承認\n\
|
||||
{prefix}deny - 権限を拒否\n\
|
||||
\n\
|
||||
{prefix}recent - 最新5件のセッション\n\
|
||||
{prefix}search <キーワード> - セッション検索\n\
|
||||
{prefix}detail <ID> - セッション詳細\n\
|
||||
{prefix}today - 本日の活動まとめ\n\
|
||||
{prefix}status - チャンネル接続状況\n\
|
||||
{prefix}help - ヘルプを表示"
|
||||
{prefix}help - ヘルプを表示\n\
|
||||
\n\
|
||||
セッションがアクティブな場合、テキストを送信するだけで会話を続けられます"
|
||||
),
|
||||
Lang::Ko => format!(
|
||||
"{prefix}recent - 최근 5개 대화\n\
|
||||
"{prefix}folder - 작업 폴더 선택\n\
|
||||
{prefix}agent - 에이전트 선택\n\
|
||||
{prefix}task <설명> - 세션 생성 및 작업 실행\n\
|
||||
{prefix}sessions - 폴더 내 활성 세션\n\
|
||||
{prefix}resume <ID> - 세션 재개\n\
|
||||
{prefix}cancel - 현재 작업 취소\n\
|
||||
{prefix}approve [always] - 권한 승인\n\
|
||||
{prefix}deny - 권한 거부\n\
|
||||
\n\
|
||||
{prefix}recent - 최근 5개 대화\n\
|
||||
{prefix}search <키워드> - 대화 검색\n\
|
||||
{prefix}detail <ID> - 대화 상세\n\
|
||||
{prefix}today - 오늘의 활동 요약\n\
|
||||
{prefix}status - 채널 연결 상태\n\
|
||||
{prefix}help - 도움말 표시"
|
||||
{prefix}help - 도움말 표시\n\
|
||||
\n\
|
||||
세션이 활성화된 경우 텍스트를 보내면 대화를 계속할 수 있습니다"
|
||||
),
|
||||
Lang::Es => format!(
|
||||
"{prefix}recent - 5 conversaciones más recientes\n\
|
||||
"{prefix}folder - Seleccionar carpeta de trabajo\n\
|
||||
{prefix}agent - Seleccionar agente\n\
|
||||
{prefix}task <desc> - Crear sesion y ejecutar tarea\n\
|
||||
{prefix}sessions - Sesiones activas en la carpeta\n\
|
||||
{prefix}resume <ID> - Reanudar una sesion\n\
|
||||
{prefix}cancel - Cancelar tarea actual\n\
|
||||
{prefix}approve [always] - Aprobar permiso\n\
|
||||
{prefix}deny - Denegar permiso\n\
|
||||
\n\
|
||||
{prefix}recent - 5 conversaciones mas recientes\n\
|
||||
{prefix}search <palabra> - Buscar conversaciones\n\
|
||||
{prefix}detail <ID> - Detalles de conversación\n\
|
||||
{prefix}detail <ID> - Detalles de conversacion\n\
|
||||
{prefix}today - Resumen de hoy\n\
|
||||
{prefix}status - Estado de canales\n\
|
||||
{prefix}help - Mostrar ayuda"
|
||||
{prefix}help - Mostrar ayuda\n\
|
||||
\n\
|
||||
Cuando hay una sesion activa, simplemente escriba texto para continuar"
|
||||
),
|
||||
Lang::De => format!(
|
||||
"{prefix}recent - 5 neueste Sitzungen\n\
|
||||
"{prefix}folder - Arbeitsordner auswahlen\n\
|
||||
{prefix}agent - Agent auswahlen\n\
|
||||
{prefix}task <Beschreibung> - Sitzung erstellen und Aufgabe ausfuhren\n\
|
||||
{prefix}sessions - Aktive Sitzungen im Ordner\n\
|
||||
{prefix}resume <ID> - Sitzung fortsetzen\n\
|
||||
{prefix}cancel - Aktuelle Aufgabe abbrechen\n\
|
||||
{prefix}approve [always] - Berechtigung genehmigen\n\
|
||||
{prefix}deny - Berechtigung verweigern\n\
|
||||
\n\
|
||||
{prefix}recent - 5 neueste Sitzungen\n\
|
||||
{prefix}search <Stichwort> - Sitzungen suchen\n\
|
||||
{prefix}detail <ID> - Sitzungsdetails\n\
|
||||
{prefix}today - Heutige Zusammenfassung\n\
|
||||
{prefix}status - Kanalstatus\n\
|
||||
{prefix}help - Hilfe anzeigen"
|
||||
{prefix}help - Hilfe anzeigen\n\
|
||||
\n\
|
||||
Bei aktiver Sitzung einfach Text eingeben, um das Gesprach fortzusetzen"
|
||||
),
|
||||
Lang::Fr => format!(
|
||||
"{prefix}recent - 5 dernières sessions\n\
|
||||
{prefix}search <mot-clé> - Rechercher des sessions\n\
|
||||
{prefix}detail <ID> - Détails de la session\n\
|
||||
{prefix}today - Résumé du jour\n\
|
||||
"{prefix}folder - Selectionner le dossier de travail\n\
|
||||
{prefix}agent - Selectionner l'agent\n\
|
||||
{prefix}task <desc> - Creer une session et executer une tache\n\
|
||||
{prefix}sessions - Sessions actives dans le dossier\n\
|
||||
{prefix}resume <ID> - Reprendre une session\n\
|
||||
{prefix}cancel - Annuler la tache en cours\n\
|
||||
{prefix}approve [always] - Approuver la permission\n\
|
||||
{prefix}deny - Refuser la permission\n\
|
||||
\n\
|
||||
{prefix}recent - 5 dernieres sessions\n\
|
||||
{prefix}search <mot-cle> - Rechercher des sessions\n\
|
||||
{prefix}detail <ID> - Details de la session\n\
|
||||
{prefix}today - Resume du jour\n\
|
||||
{prefix}status - Statut des canaux\n\
|
||||
{prefix}help - Afficher l'aide"
|
||||
{prefix}help - Afficher l'aide\n\
|
||||
\n\
|
||||
Lorsqu'une session est active, envoyez du texte pour continuer la conversation"
|
||||
),
|
||||
Lang::Pt => format!(
|
||||
"{prefix}recent - 5 sessões mais recentes\n\
|
||||
{prefix}search <palavra> - Buscar sessões\n\
|
||||
{prefix}detail <ID> - Detalhes da sessão\n\
|
||||
"{prefix}folder - Selecionar pasta de trabalho\n\
|
||||
{prefix}agent - Selecionar agente\n\
|
||||
{prefix}task <desc> - Criar sessao e executar tarefa\n\
|
||||
{prefix}sessions - Sessoes ativas na pasta\n\
|
||||
{prefix}resume <ID> - Retomar uma sessao\n\
|
||||
{prefix}cancel - Cancelar tarefa atual\n\
|
||||
{prefix}approve [always] - Aprovar permissao\n\
|
||||
{prefix}deny - Negar permissao\n\
|
||||
\n\
|
||||
{prefix}recent - 5 sessoes mais recentes\n\
|
||||
{prefix}search <palavra> - Buscar sessoes\n\
|
||||
{prefix}detail <ID> - Detalhes da sessao\n\
|
||||
{prefix}today - Resumo de hoje\n\
|
||||
{prefix}status - Status dos canais\n\
|
||||
{prefix}help - Mostrar ajuda"
|
||||
{prefix}help - Mostrar ajuda\n\
|
||||
\n\
|
||||
Quando uma sessao esta ativa, basta digitar texto para continuar a conversa"
|
||||
),
|
||||
Lang::Ar => format!(
|
||||
"{prefix}recent - أحدث 5 جلسات\n\
|
||||
"{prefix}folder - اختيار مجلد العمل\n\
|
||||
{prefix}agent - اختيار الوكيل\n\
|
||||
{prefix}task <وصف> - انشاء جلسة وتنفيذ مهمة\n\
|
||||
{prefix}sessions - الجلسات النشطة في المجلد\n\
|
||||
{prefix}resume <ID> - استئناف جلسة\n\
|
||||
{prefix}cancel - الغاء المهمة الحالية\n\
|
||||
{prefix}approve [always] - الموافقة على الاذن\n\
|
||||
{prefix}deny - رفض الاذن\n\
|
||||
\n\
|
||||
{prefix}recent - احدث 5 جلسات\n\
|
||||
{prefix}search <كلمة> - البحث في الجلسات\n\
|
||||
{prefix}detail <ID> - تفاصيل الجلسة\n\
|
||||
{prefix}today - ملخص اليوم\n\
|
||||
{prefix}status - حالة القنوات\n\
|
||||
{prefix}help - عرض المساعدة"
|
||||
{prefix}help - عرض المساعدة\n\
|
||||
\n\
|
||||
عندما تكون الجلسة نشطة، ارسل نصا لمتابعة المحادثة"
|
||||
),
|
||||
Lang::En => format!(
|
||||
"📂 {prefix}folder - Select working folder\n\
|
||||
🤖 {prefix}agent - Select agent\n\
|
||||
🚀 {prefix}task <desc> - Create session & run task\n\
|
||||
📋 {prefix}sessions - Active sessions in folder\n\
|
||||
▶️ {prefix}resume <ID> - Resume a session\n\
|
||||
⏹️ {prefix}cancel - Cancel current task\n\
|
||||
✅ {prefix}approve [always] - Approve permission\n\
|
||||
❌ {prefix}deny - Deny permission\n\
|
||||
"{prefix}folder - Select working folder\n\
|
||||
{prefix}agent - Select agent\n\
|
||||
{prefix}task <desc> - Create session & run task\n\
|
||||
{prefix}sessions - Active sessions in folder\n\
|
||||
{prefix}resume <ID> - Resume a session\n\
|
||||
{prefix}cancel - Cancel current task\n\
|
||||
{prefix}approve [always] - Approve permission\n\
|
||||
{prefix}deny - Deny permission\n\
|
||||
\n\
|
||||
{prefix}recent - 5 most recent conversations\n\
|
||||
{prefix}search <keyword> - Search conversations\n\
|
||||
@@ -709,7 +797,7 @@ pub fn help_body(lang: Lang, prefix: &str) -> String {
|
||||
{prefix}status - Channel connection status\n\
|
||||
{prefix}help - Show help\n\
|
||||
\n\
|
||||
💡 When a session is active, just type text to continue the conversation"
|
||||
When a session is active, just type text to continue the conversation"
|
||||
),
|
||||
}
|
||||
}
|
||||
@@ -810,3 +898,20 @@ pub fn unknown_command_title(lang: Lang) -> &'static str {
|
||||
Lang::En => "Unknown Command",
|
||||
}
|
||||
}
|
||||
|
||||
// ── Session progress messages ──
|
||||
|
||||
pub fn agent_responding(lang: Lang) -> &'static str {
|
||||
match lang {
|
||||
Lang::ZhCn => "Claude Code 正在响应中...",
|
||||
Lang::ZhTw => "Claude Code 正在回應中...",
|
||||
Lang::Ja => "Claude Code が応答中...",
|
||||
Lang::Ko => "Claude Code 응답 중...",
|
||||
Lang::Es => "Claude Code respondiendo...",
|
||||
Lang::De => "Claude Code antwortet...",
|
||||
Lang::Fr => "Claude Code en cours de reponse...",
|
||||
Lang::Pt => "Claude Code respondendo...",
|
||||
Lang::Ar => "...Claude Code يستجيب",
|
||||
Lang::En => "Claude Code is responding...",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,14 +24,15 @@ pub async fn handle_folder(
|
||||
channel_id: i32,
|
||||
sender_id: &str,
|
||||
lang: Lang,
|
||||
prefix: &str,
|
||||
) -> RichMessage {
|
||||
if args.is_empty() {
|
||||
return list_folders(db, channel_id, sender_id, lang).await;
|
||||
return list_folders(db, channel_id, sender_id, lang, prefix).await;
|
||||
}
|
||||
|
||||
// Try parse as index (1-based)
|
||||
if let Ok(idx) = args.parse::<usize>() {
|
||||
return select_folder_by_index(db, idx, channel_id, sender_id, lang).await;
|
||||
return select_folder_by_index(db, idx, channel_id, sender_id, lang, prefix).await;
|
||||
}
|
||||
|
||||
// Treat as path
|
||||
@@ -43,6 +44,7 @@ async fn list_folders(
|
||||
channel_id: i32,
|
||||
sender_id: &str,
|
||||
lang: Lang,
|
||||
prefix: &str,
|
||||
) -> RichMessage {
|
||||
let folders = match folder_service::list_folders(db).await {
|
||||
Ok(f) => f,
|
||||
@@ -77,10 +79,11 @@ async fn list_folders(
|
||||
|
||||
body.push_str(&format!(
|
||||
"\n{}",
|
||||
t(
|
||||
tp(
|
||||
lang,
|
||||
"Reply /folder <number> to select.",
|
||||
"回复 /folder <数字> 选择目录。"
|
||||
prefix,
|
||||
"Reply {prefix}folder <number> to select.",
|
||||
"回复 {prefix}folder <数字> 选择目录。"
|
||||
)
|
||||
));
|
||||
|
||||
@@ -94,6 +97,7 @@ async fn select_folder_by_index(
|
||||
channel_id: i32,
|
||||
sender_id: &str,
|
||||
lang: Lang,
|
||||
prefix: &str,
|
||||
) -> RichMessage {
|
||||
if idx == 0 {
|
||||
return RichMessage::info(t(lang, "Index starts from 1.", "序号从 1 开始。"));
|
||||
@@ -105,10 +109,11 @@ async fn select_folder_by_index(
|
||||
};
|
||||
|
||||
let Some(folder) = folders.get(idx - 1) else {
|
||||
return RichMessage::info(t(
|
||||
return RichMessage::info(tp(
|
||||
lang,
|
||||
"Index out of range. Use /folder to list.",
|
||||
"序号超出范围,请使用 /folder 查看列表。",
|
||||
prefix,
|
||||
"Index out of range. Use {prefix}folder to list.",
|
||||
"序号超出范围,请使用 {prefix}folder 查看列表。",
|
||||
));
|
||||
};
|
||||
|
||||
@@ -146,14 +151,15 @@ pub async fn handle_agent(
|
||||
channel_id: i32,
|
||||
sender_id: &str,
|
||||
lang: Lang,
|
||||
prefix: &str,
|
||||
) -> RichMessage {
|
||||
if args.is_empty() {
|
||||
return list_agents(db, channel_id, sender_id, lang).await;
|
||||
return list_agents(db, channel_id, sender_id, lang, prefix).await;
|
||||
}
|
||||
|
||||
// Try parse as index
|
||||
if let Ok(idx) = args.parse::<usize>() {
|
||||
return select_agent_by_index(db, idx, channel_id, sender_id, lang).await;
|
||||
return select_agent_by_index(db, idx, channel_id, sender_id, lang, prefix).await;
|
||||
}
|
||||
|
||||
// Try parse as agent type name
|
||||
@@ -165,6 +171,7 @@ async fn list_agents(
|
||||
channel_id: i32,
|
||||
sender_id: &str,
|
||||
lang: Lang,
|
||||
prefix: &str,
|
||||
) -> RichMessage {
|
||||
let agents = all_acp_agents();
|
||||
let ctx = sender_context_service::get_or_create(db, channel_id, sender_id)
|
||||
@@ -185,10 +192,11 @@ async fn list_agents(
|
||||
|
||||
body.push_str(&format!(
|
||||
"\n{}",
|
||||
t(
|
||||
tp(
|
||||
lang,
|
||||
"Reply /agent <number> or /agent <name> to select.",
|
||||
"回复 /agent <数字> 或 /agent <名称> 选择。"
|
||||
prefix,
|
||||
"Reply {prefix}agent <number> or {prefix}agent <name> to select.",
|
||||
"回复 {prefix}agent <数字> 或 {prefix}agent <名称> 选择。"
|
||||
)
|
||||
));
|
||||
|
||||
@@ -202,13 +210,15 @@ async fn select_agent_by_index(
|
||||
channel_id: i32,
|
||||
sender_id: &str,
|
||||
lang: Lang,
|
||||
prefix: &str,
|
||||
) -> RichMessage {
|
||||
let agents = all_acp_agents();
|
||||
if idx == 0 || idx > agents.len() {
|
||||
return RichMessage::info(t(
|
||||
return RichMessage::info(tp(
|
||||
lang,
|
||||
"Index out of range. Use /agent to list.",
|
||||
"序号超出范围,请使用 /agent 查看列表。",
|
||||
prefix,
|
||||
"Index out of range. Use {prefix}agent to list.",
|
||||
"序号超出范围,请使用 {prefix}agent 查看列表。",
|
||||
));
|
||||
}
|
||||
|
||||
@@ -257,12 +267,14 @@ pub async fn handle_task(
|
||||
emitter: &EventEmitter,
|
||||
bridge: &Arc<Mutex<SessionBridge>>,
|
||||
lang: Lang,
|
||||
prefix: &str,
|
||||
) -> RichMessage {
|
||||
if task_description.is_empty() {
|
||||
return RichMessage::info(t(
|
||||
return RichMessage::info(tp(
|
||||
lang,
|
||||
"Usage: /task <description>",
|
||||
"用法: /task <任务描述>",
|
||||
prefix,
|
||||
"Usage: {prefix}task <description>",
|
||||
"用法: {prefix}task <任务描述>",
|
||||
));
|
||||
}
|
||||
|
||||
@@ -275,10 +287,11 @@ pub async fn handle_task(
|
||||
let folder_id = match ctx.current_folder_id {
|
||||
Some(id) => id,
|
||||
None => {
|
||||
return RichMessage::info(t(
|
||||
return RichMessage::info(tp(
|
||||
lang,
|
||||
"No folder selected. Use /folder first.",
|
||||
"未选择工作目录,请先使用 /folder 选择。",
|
||||
prefix,
|
||||
"No folder selected. Use {prefix}folder first.",
|
||||
"未选择工作目录,请先使用 {prefix}folder 选择。",
|
||||
));
|
||||
}
|
||||
};
|
||||
@@ -287,10 +300,11 @@ pub async fn handle_task(
|
||||
let folder = match folder_service::get_folder_by_id(db, folder_id).await {
|
||||
Ok(Some(f)) => f,
|
||||
_ => {
|
||||
return RichMessage::info(t(
|
||||
return RichMessage::info(tp(
|
||||
lang,
|
||||
"Folder not found. Use /folder to select.",
|
||||
"目录不存在,请使用 /folder 重新选择。",
|
||||
prefix,
|
||||
"Folder not found. Use {prefix}folder to select.",
|
||||
"目录不存在,请使用 {prefix}folder 重新选择。",
|
||||
));
|
||||
}
|
||||
};
|
||||
@@ -381,6 +395,7 @@ pub async fn handle_sessions(
|
||||
channel_id: i32,
|
||||
sender_id: &str,
|
||||
lang: Lang,
|
||||
prefix: &str,
|
||||
) -> RichMessage {
|
||||
let ctx = match sender_context_service::get_or_create(db, channel_id, sender_id).await {
|
||||
Ok(c) => c,
|
||||
@@ -390,10 +405,11 @@ pub async fn handle_sessions(
|
||||
let folder_id = match ctx.current_folder_id {
|
||||
Some(id) => id,
|
||||
None => {
|
||||
return RichMessage::info(t(
|
||||
return RichMessage::info(tp(
|
||||
lang,
|
||||
"No folder selected. Use /folder first.",
|
||||
"未选择工作目录,请先使用 /folder 选择。",
|
||||
prefix,
|
||||
"No folder selected. Use {prefix}folder first.",
|
||||
"未选择工作目录,请先使用 {prefix}folder 选择。",
|
||||
));
|
||||
}
|
||||
};
|
||||
@@ -456,10 +472,11 @@ pub async fn handle_sessions(
|
||||
|
||||
body.push_str(&format!(
|
||||
"\n{}",
|
||||
t(
|
||||
tp(
|
||||
lang,
|
||||
"Reply /resume <id> to continue.",
|
||||
"回复 /resume <ID> 继续会话。"
|
||||
prefix,
|
||||
"Reply {prefix}resume <id> to continue.",
|
||||
"回复 {prefix}resume <ID> 继续会话。"
|
||||
)
|
||||
));
|
||||
|
||||
@@ -482,14 +499,16 @@ pub async fn handle_resume(
|
||||
emitter: &EventEmitter,
|
||||
bridge: &Arc<Mutex<SessionBridge>>,
|
||||
lang: Lang,
|
||||
prefix: &str,
|
||||
) -> RichMessage {
|
||||
let conversation_id: i32 = match args.parse() {
|
||||
Ok(id) => id,
|
||||
Err(_) => {
|
||||
return RichMessage::info(t(
|
||||
return RichMessage::info(tp(
|
||||
lang,
|
||||
"Usage: /resume <conversation_id>",
|
||||
"用法: /resume <会话ID>",
|
||||
prefix,
|
||||
"Usage: {prefix}resume <conversation_id>",
|
||||
"用法: {prefix}resume <会话ID>",
|
||||
));
|
||||
}
|
||||
};
|
||||
@@ -753,6 +772,7 @@ pub async fn handle_followup(
|
||||
conn_mgr: &ConnectionManager,
|
||||
bridge: &Arc<Mutex<SessionBridge>>,
|
||||
lang: Lang,
|
||||
prefix: &str,
|
||||
) -> RichMessage {
|
||||
let ctx = match sender_context_service::get_or_create(db, channel_id, sender_id).await {
|
||||
Ok(c) => c,
|
||||
@@ -762,10 +782,11 @@ pub async fn handle_followup(
|
||||
let connection_id = match &ctx.current_connection_id {
|
||||
Some(id) => id.clone(),
|
||||
None => {
|
||||
return RichMessage::info(t(
|
||||
return RichMessage::info(tp(
|
||||
lang,
|
||||
"No active session. Use /task to start one.",
|
||||
"没有活跃的会话,请使用 /task 开始新任务。",
|
||||
prefix,
|
||||
"No active session. Use {prefix}task to start one.",
|
||||
"没有活跃的会话,请使用 {prefix}task 开始新任务。",
|
||||
));
|
||||
}
|
||||
};
|
||||
@@ -777,10 +798,11 @@ pub async fn handle_followup(
|
||||
// Connection lost, clear context
|
||||
drop(bridge_guard);
|
||||
let _ = sender_context_service::clear_session(db, channel_id, sender_id).await;
|
||||
return RichMessage::info(t(
|
||||
return RichMessage::info(tp(
|
||||
lang,
|
||||
"Session connection lost. Use /task to start a new one.",
|
||||
"会话连接已断开,请使用 /task 开始新任务。",
|
||||
prefix,
|
||||
"Session connection lost. Use {prefix}task to start a new one.",
|
||||
"会话连接已断开,请使用 {prefix}task 开始新任务。",
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -812,6 +834,11 @@ fn t(lang: Lang, en: &str, zh: &str) -> String {
|
||||
}
|
||||
}
|
||||
|
||||
/// Like `t()` but replaces `{prefix}` placeholders with the actual command prefix.
|
||||
fn tp(lang: Lang, prefix: &str, en: &str, zh: &str) -> String {
|
||||
t(lang, en, zh).replace("{prefix}", prefix)
|
||||
}
|
||||
|
||||
fn agent_type_to_string(at: AgentType) -> String {
|
||||
serde_json::to_value(at)
|
||||
.ok()
|
||||
|
||||
@@ -17,10 +17,12 @@ use crate::web::event_bridge::WebEventBroadcaster;
|
||||
|
||||
use super::manager::ChatChannelManager;
|
||||
|
||||
const FLUSH_INTERVAL_SECS: u64 = 5;
|
||||
const FLUSH_INTERVAL_SECS: u64 = 10;
|
||||
const BUFFER_FLUSH_THRESHOLD: usize = 500;
|
||||
const MAX_MESSAGE_LEN: usize = 2000;
|
||||
const MESSAGE_LANGUAGE_KEY: &str = "chat_message_language";
|
||||
const COMMAND_PREFIX_KEY: &str = "chat_command_prefix";
|
||||
const DEFAULT_COMMAND_PREFIX: &str = "/";
|
||||
|
||||
pub fn spawn_session_event_subscriber(
|
||||
broadcaster: Arc<WebEventBroadcaster>,
|
||||
@@ -59,7 +61,7 @@ pub fn spawn_session_event_subscriber(
|
||||
}
|
||||
_ = tokio::time::sleep(Duration::from_secs(FLUSH_INTERVAL_SECS)) => {
|
||||
if last_heartbeat.elapsed() >= Duration::from_secs(FLUSH_INTERVAL_SECS) {
|
||||
flush_progress(&bridge, &manager).await;
|
||||
flush_progress(&bridge, &manager, &db_conn).await;
|
||||
last_heartbeat = Instant::now();
|
||||
}
|
||||
}
|
||||
@@ -77,6 +79,14 @@ async fn get_lang(db: &DatabaseConnection) -> Lang {
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
async fn get_prefix(db: &DatabaseConnection) -> String {
|
||||
app_metadata_service::get_value(db, COMMAND_PREFIX_KEY)
|
||||
.await
|
||||
.ok()
|
||||
.flatten()
|
||||
.unwrap_or_else(|| DEFAULT_COMMAND_PREFIX.to_string())
|
||||
}
|
||||
|
||||
async fn handle_acp_event_payload(
|
||||
payload: &serde_json::Value,
|
||||
bridge: &Arc<Mutex<SessionBridge>>,
|
||||
@@ -135,11 +145,11 @@ async fn handle_acp_event_payload(
|
||||
&& session.last_flushed.elapsed() >= Duration::from_secs(2)
|
||||
{
|
||||
let channel_id = session.channel_id;
|
||||
let buf_len = session.content_buffer.len();
|
||||
let last_tool = session.tool_calls.last().cloned();
|
||||
session.last_flushed = Instant::now();
|
||||
|
||||
let mut status = format!("... ({buf_len} chars)");
|
||||
let lang = get_lang(db).await;
|
||||
let mut status = super::i18n::agent_responding(lang).to_string();
|
||||
if let Some(tool) = last_tool {
|
||||
status.push_str(&format!(" | {tool}"));
|
||||
}
|
||||
@@ -252,12 +262,13 @@ async fn handle_acp_event_payload(
|
||||
drop(guard);
|
||||
|
||||
let lang = get_lang(db).await;
|
||||
let prefix = get_prefix(db).await;
|
||||
let body = match lang {
|
||||
Lang::ZhCn | Lang::ZhTw => {
|
||||
format!("Agent 请求权限: {tool_desc}\n\n/approve 批准 | /deny 拒绝 | /approve always 自动批准")
|
||||
format!("Agent 请求权限: {tool_desc}\n\n{prefix}approve 批准 | {prefix}deny 拒绝 | {prefix}approve always 自动批准")
|
||||
}
|
||||
_ => {
|
||||
format!("Agent requests permission: {tool_desc}\n\n/approve | /deny | /approve always")
|
||||
format!("Agent requests permission: {tool_desc}\n\n{prefix}approve | {prefix}deny | {prefix}approve always")
|
||||
}
|
||||
};
|
||||
|
||||
@@ -387,7 +398,11 @@ async fn handle_acp_event_payload(
|
||||
}
|
||||
}
|
||||
|
||||
async fn flush_progress(bridge: &Arc<Mutex<SessionBridge>>, manager: &ChatChannelManager) {
|
||||
async fn flush_progress(
|
||||
bridge: &Arc<Mutex<SessionBridge>>,
|
||||
manager: &ChatChannelManager,
|
||||
db: &DatabaseConnection,
|
||||
) {
|
||||
let updates: Vec<(i32, String)> = {
|
||||
let mut guard = bridge.lock().await;
|
||||
let mut out = Vec::new();
|
||||
@@ -395,13 +410,14 @@ async fn flush_progress(bridge: &Arc<Mutex<SessionBridge>>, manager: &ChatChanne
|
||||
if !session.content_buffer.is_empty()
|
||||
&& session.last_flushed.elapsed() >= Duration::from_secs(FLUSH_INTERVAL_SECS)
|
||||
{
|
||||
let buf_len = session.content_buffer.len();
|
||||
let tool_count = session.tool_calls.len();
|
||||
session.last_flushed = Instant::now();
|
||||
out.push((
|
||||
session.channel_id,
|
||||
format!("... ({buf_len} chars, {tool_count} tools)"),
|
||||
));
|
||||
let last_tool = session.tool_calls.last().cloned();
|
||||
let lang = get_lang(db).await;
|
||||
let mut status = super::i18n::agent_responding(lang).to_string();
|
||||
if let Some(tool) = last_tool {
|
||||
status.push_str(&format!(" | {tool}"));
|
||||
}
|
||||
out.push((session.channel_id, status));
|
||||
}
|
||||
}
|
||||
out
|
||||
|
||||
Reference in New Issue
Block a user