@@ -193,6 +193,95 @@ async def _handle_debug(ctx: CommandContext) -> str | None:
193193 return reply_text or "診斷完成,但未產生回報內容。"
194194
195195
196+ async def _handle_agent (ctx : CommandContext ) -> str | None :
197+ """切換對話使用的 AI Agent
198+
199+ 用法:
200+ /agent — 顯示目前使用的 Agent 和可切換清單
201+ /agent <name> — 用名稱切換
202+ /agent <number> — 用編號切換
203+ /agent reset — 恢復預設
204+ """
205+ from .. import ai_manager
206+ from ..linebot_agents import (
207+ get_group_active_agent_id ,
208+ get_user_active_agent_id ,
209+ set_group_active_agent ,
210+ set_user_active_agent ,
211+ )
212+
213+ args = ctx .raw_args .strip ()
214+
215+ # 取得可切換的 Agent 清單(按 name 排序)
216+ selectable = await ai_manager .get_selectable_agents ()
217+
218+ async def _apply_preference (agent_id : str | None ) -> None :
219+ """將 Agent 偏好寫入群組或個人"""
220+ if ctx .is_group and ctx .group_id :
221+ await set_group_active_agent (ctx .group_id , agent_id )
222+ elif ctx .bot_user_id :
223+ await set_user_active_agent (ctx .bot_user_id , agent_id )
224+
225+ # === /agent reset ===
226+ if args .lower () == "reset" :
227+ await _apply_preference (None )
228+ return "已恢復預設 Agent"
229+
230+ # === 查詢目前 Agent ===
231+ current_agent_id = None
232+ if ctx .is_group and ctx .group_id :
233+ current_agent_id = await get_group_active_agent_id (ctx .group_id )
234+ elif ctx .bot_user_id :
235+ current_agent_id = await get_user_active_agent_id (ctx .bot_user_id )
236+
237+ # 取得目前 Agent 的顯示資訊
238+ current_label = "預設"
239+ if current_agent_id :
240+ from uuid import UUID
241+ current_agent = await ai_manager .get_agent (UUID (current_agent_id ))
242+ if current_agent :
243+ current_label = f"{ current_agent ['name' ]} ({ current_agent .get ('display_name' , '' )} )"
244+ else :
245+ current_label = "預設(偏好 Agent 已不存在)"
246+
247+ # === /agent(無參數)— 顯示狀態和清單 ===
248+ if not args :
249+ lines = [f"目前 Agent:{ current_label } " ]
250+ if selectable :
251+ lines .append ("" )
252+ lines .append ("可切換的 Agent:" )
253+ for i , agent in enumerate (selectable , 1 ):
254+ display = agent .get ("display_name" ) or agent ["name" ]
255+ lines .append (f"{ i } . { agent ['name' ]} — { display } " )
256+ lines .append ("" )
257+ lines .append ("用法:/agent <名稱或編號>" )
258+ lines .append ("恢復預設:/agent reset" )
259+ else :
260+ lines .append ("目前沒有可切換的 Agent" )
261+ lines .append ("請在 AI 管理介面將 Agent 的 settings.user_selectable 設為 true" )
262+ return "\n " .join (lines )
263+
264+ # === /agent <number> — 編號切換 ===
265+ if args .isdigit ():
266+ idx = int (args )
267+ if idx < 1 or idx > len (selectable ):
268+ return f"編號 { idx } 超出範圍(1-{ len (selectable )} ),請用 /agent 查看可用清單"
269+ target = selectable [idx - 1 ]
270+ else :
271+ # === /agent <name> — 名稱切換 ===
272+ target = next ((a for a in selectable if a ["name" ] == args ), None )
273+ if not target :
274+ # 檢查 Agent 是否存在但不可選
275+ existing = await ai_manager .get_agent_by_name (args )
276+ if existing :
277+ return f"Agent { args } 不可切換,請用 /agent 查看可用清單"
278+ return f"找不到 Agent: { args } ,請用 /agent 查看可用清單"
279+
280+ await _apply_preference (str (target ["id" ]))
281+ display = target .get ("display_name" ) or target ["name" ]
282+ return f"已切換到 { display } "
283+
284+
196285_registered = False
197286
198287
@@ -243,6 +332,15 @@ def register_builtin_commands() -> None:
243332 require_admin = True ,
244333 private_only = True ,
245334 ),
335+ SlashCommand (
336+ name = "agent" ,
337+ aliases = ["切換助理" ],
338+ handler = _handle_agent ,
339+ description = "切換 AI Agent" ,
340+ require_bound = True ,
341+ require_admin = True ,
342+ private_only = False ,
343+ ),
246344 ]
247345
248346 for cmd in all_commands :
0 commit comments