From 92aeec7540117d1fde85fa297947e580e70ca6fe Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 21 May 2026 08:59:18 +0000 Subject: [PATCH 1/5] Initial plan From 855a8f7bc1bc6dab364421763c2aa69342e9fe6b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 21 May 2026 09:04:46 +0000 Subject: [PATCH 2/5] fix(local-agent): scope always-approve to current chat session Agent-Logs-Url: https://github.com/LiteyukiStudio/agent/sessions/b222c897-7521-4d49-8269-36cfe06e2874 Co-authored-by: snowykami <79104275+snowykami@users.noreply.github.com> --- local_agent/src/connection.ts | 24 +++++++++++++++++++++++- root_agent/tools/local_agent.py | 3 +++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/local_agent/src/connection.ts b/local_agent/src/connection.ts index 8d6c6b8..bf3f283 100644 --- a/local_agent/src/connection.ts +++ b/local_agent/src/connection.ts @@ -51,11 +51,13 @@ export function connect(url: string, token: string): void { currentUrl = url; currentToken = token; shouldReconnect = true; + resetSessionApprovalState(); doConnect(); } export function disconnect(): void { shouldReconnect = false; + resetSessionApprovalState(); if (reconnectTimer) { clearTimeout(reconnectTimer); reconnectTimer = null; @@ -157,10 +159,23 @@ const pendingConfirms: Map(); // 本次会话缓存的 sudo 密码(连接断开后清空,绝不写盘) let cachedSudoPassword: string | null = null; +function resetSessionApprovalState(): void { + sessionAlwaysApprove = false; + alwaysApproveChatSessionIds.clear(); + cachedSudoPassword = null; +} + +function getChatSessionId(request: ToolRequest): string | null { + const sessionId = request.args.__chat_session_id; + return typeof sessionId === "string" && sessionId.length > 0 ? sessionId : null; +} + /** 处理服务端发来的确认响应 */ export function handleConfirmResponse(id: string, approved: boolean, always?: boolean, password?: string): void { const pending = pendingConfirms.get(id); @@ -207,11 +222,14 @@ function needsSudo(command: string): boolean { async function handleRequest(request: ToolRequest): Promise { const command = typeof request.args.command === "string" ? request.args.command : ""; const isSudoCommand = request.tool === "run_command" && needsSudo(command); + const chatSessionId = getChatSessionId(request); + const approvedForThisChatSession = !!chatSessionId && alwaysApproveChatSessionIds.has(chatSessionId); // Check if dangerous — skip confirmation if autoApprove or sessionAlwaysApprove is on if ( !autoApprove && !sessionAlwaysApprove && + !approvedForThisChatSession && request.tool === "run_command" && isDangerous(command) ) { @@ -222,7 +240,11 @@ async function handleRequest(request: ToolRequest): Promise { const result = await requestWebConfirmation(request, requirePassword); if (result.action === "always") { // 「始终允许」:本次会话后续所有命令都跳过确认 - sessionAlwaysApprove = true; + if (chatSessionId) { + alwaysApproveChatSessionIds.add(chatSessionId); + } else { + sessionAlwaysApprove = true; + } if (result.password) { cachedSudoPassword = result.password; } diff --git a/root_agent/tools/local_agent.py b/root_agent/tools/local_agent.py index 6e35403..5147f79 100644 --- a/root_agent/tools/local_agent.py +++ b/root_agent/tools/local_agent.py @@ -113,8 +113,11 @@ async def local_list_files( async def _call(tool_context: ToolContext, tool: str, args: dict, device: str = "") -> str: """实际调用 local_agent 的内部方法。""" user_id = tool_context.state.get("__user_id") + chat_session_id = tool_context.state.get("__chat_session_id") if not user_id: return "错误:无法确定用户身份" + if isinstance(chat_session_id, str) and chat_session_id: + args = {**args, "__chat_session_id": chat_session_id} from server.routers.local_agent import ( _connections, From 7ad4df86cd53f6a5478384d42ab8b475098862f1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 21 May 2026 09:06:44 +0000 Subject: [PATCH 3/5] chore(local-agent): address review feedback on session approval handling Agent-Logs-Url: https://github.com/LiteyukiStudio/agent/sessions/b222c897-7521-4d49-8269-36cfe06e2874 Co-authored-by: snowykami <79104275+snowykami@users.noreply.github.com> --- local_agent/src/connection.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/local_agent/src/connection.ts b/local_agent/src/connection.ts index bf3f283..06af66e 100644 --- a/local_agent/src/connection.ts +++ b/local_agent/src/connection.ts @@ -172,7 +172,7 @@ function resetSessionApprovalState(): void { } function getChatSessionId(request: ToolRequest): string | null { - const sessionId = request.args.__chat_session_id; + const sessionId = request.args?.__chat_session_id; return typeof sessionId === "string" && sessionId.length > 0 ? sessionId : null; } @@ -223,13 +223,13 @@ async function handleRequest(request: ToolRequest): Promise { const command = typeof request.args.command === "string" ? request.args.command : ""; const isSudoCommand = request.tool === "run_command" && needsSudo(command); const chatSessionId = getChatSessionId(request); - const approvedForThisChatSession = !!chatSessionId && alwaysApproveChatSessionIds.has(chatSessionId); + const isSessionApproved = !!chatSessionId && alwaysApproveChatSessionIds.has(chatSessionId); // Check if dangerous — skip confirmation if autoApprove or sessionAlwaysApprove is on if ( !autoApprove && !sessionAlwaysApprove && - !approvedForThisChatSession && + !isSessionApproved && request.tool === "run_command" && isDangerous(command) ) { From b285839f811ecf602ebdb762bc0f91f8dab6062d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 21 May 2026 09:07:58 +0000 Subject: [PATCH 4/5] refactor(local-agent): clarify approval fallback logic Agent-Logs-Url: https://github.com/LiteyukiStudio/agent/sessions/b222c897-7521-4d49-8269-36cfe06e2874 Co-authored-by: snowykami <79104275+snowykami@users.noreply.github.com> --- local_agent/src/connection.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/local_agent/src/connection.ts b/local_agent/src/connection.ts index 06af66e..2e282d6 100644 --- a/local_agent/src/connection.ts +++ b/local_agent/src/connection.ts @@ -224,12 +224,11 @@ async function handleRequest(request: ToolRequest): Promise { const isSudoCommand = request.tool === "run_command" && needsSudo(command); const chatSessionId = getChatSessionId(request); const isSessionApproved = !!chatSessionId && alwaysApproveChatSessionIds.has(chatSessionId); + const isApproved = autoApprove || sessionAlwaysApprove || isSessionApproved; // Check if dangerous — skip confirmation if autoApprove or sessionAlwaysApprove is on if ( - !autoApprove && - !sessionAlwaysApprove && - !isSessionApproved && + !isApproved && request.tool === "run_command" && isDangerous(command) ) { @@ -243,6 +242,7 @@ async function handleRequest(request: ToolRequest): Promise { if (chatSessionId) { alwaysApproveChatSessionIds.add(chatSessionId); } else { + // 兼容未携带 __chat_session_id 的旧请求:仍在当前连接会话内放行。 sessionAlwaysApprove = true; } if (result.password) { From f6cb3037002db4bdd360c1bb6b5db872d37c425b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 21 May 2026 09:08:59 +0000 Subject: [PATCH 5/5] docs(local-agent): update approval logic comment Agent-Logs-Url: https://github.com/LiteyukiStudio/agent/sessions/b222c897-7521-4d49-8269-36cfe06e2874 Co-authored-by: snowykami <79104275+snowykami@users.noreply.github.com> --- local_agent/src/connection.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/local_agent/src/connection.ts b/local_agent/src/connection.ts index 2e282d6..38d95b6 100644 --- a/local_agent/src/connection.ts +++ b/local_agent/src/connection.ts @@ -226,7 +226,7 @@ async function handleRequest(request: ToolRequest): Promise { const isSessionApproved = !!chatSessionId && alwaysApproveChatSessionIds.has(chatSessionId); const isApproved = autoApprove || sessionAlwaysApprove || isSessionApproved; - // Check if dangerous — skip confirmation if autoApprove or sessionAlwaysApprove is on + // Check if dangerous — skip confirmation when current request is already approved. if ( !isApproved && request.tool === "run_command" &&