fix: integrate PermissionPrompt dialog into chat UI

- Add PermissionPrompt component to chat page
- Detect request_permission tool calls and show dialog
- Extract path and command from tool call arguments
- Fix TypeScript errors (null check, unused variable)
- Fix locale files (trailing comma errors)
This commit is contained in:
Dark aura 2026-05-06 04:21:00 +01:00
parent 1fc04f7c77
commit 15eb2e6249
3 changed files with 63 additions and 6 deletions

View file

@ -25,6 +25,7 @@ import type { ConnectionState } from "@/store/chat"
import type { ChatAttachment } from "@/store/chat"
import { showAssistantDetailsAtom } from "@/store/chat"
import type { GatewayState } from "@/store/gateway"
import { PermissionPrompt } from "@/components/permission/PermissionPrompt"
const MAX_IMAGE_SIZE_BYTES = 7 * 1024 * 1024
const MAX_IMAGE_SIZE_LABEL = "7 MB"
@ -115,6 +116,11 @@ export function ChatPage() {
const [showAssistantDetails, setShowAssistantDetails] = useAtom(
showAssistantDetailsAtom,
)
const [permissionRequest, setPermissionRequest] = useState<{
toolName: string
path: string
originalCommand: string
} | null>(null)
const {
messages,
@ -191,6 +197,45 @@ export function ChatPage() {
}
}
// Check for permission requests in messages
useEffect(() => {
if (permissionRequest) return // Already showing a permission prompt
// Check the last few messages for request_permission tool calls
for (let i = messages.length - 1; i >= Math.max(0, messages.length - 5); i--) {
const msg = messages[i]
if (msg.role !== "assistant") continue
if (!msg.toolCalls) continue
const permCall = msg.toolCalls.find(
(tc) => tc.function?.name === "request_permission"
)
if (!permCall || !permCall.function) continue
try {
const args = JSON.parse(permCall.function.arguments ?? "{}")
if (args.path && args.command) {
setPermissionRequest({
toolName: "request_permission",
path: args.path,
originalCommand: args.command,
})
return
}
} catch {
// Ignore parse errors
}
}
}, [messages, permissionRequest])
const handlePermissionGranted = () => {
setPermissionRequest(null)
}
const handlePermissionDenied = () => {
setPermissionRequest(null)
}
const handleAddImages = () => {
if (!canInput) return
fileInputRef.current?.click()
@ -324,6 +369,18 @@ export function ChatPage() {
/>
)}
{permissionRequest && (
<div className="flex w-full">
<PermissionPrompt
toolName={permissionRequest.toolName}
path={permissionRequest.path}
originalCommand={permissionRequest.originalCommand}
onPermissionGranted={handlePermissionGranted}
onPermissionDenied={handlePermissionDenied}
/>
</div>
)}
{messages.map((msg) => {
if (
!showAssistantDetails &&

View file

@ -49,7 +49,7 @@
"websocketConnecting": "Connecting to chat service... Please wait.",
"websocketDisconnected": "Unable to chat: WebSocket connection is disconnected. Check network and gateway status, then refresh the page or restart Launcher.",
"websocketError": "Unable to chat: WebSocket connection failed. Check network and gateway status, then retry.",
"noDefaultModel": "Unable to chat: No default model is selected. Set a default model on the Models page."
"noDefaultModel": "Unable to chat: No default model is selected. Set a default model on the Models page.",
"permissionRequiredTitle": "Permission Required",
"permissionRequiredMessage": "PicoClaw wants to use {{tool}} to access {{path}} which is outside your workspace.",
"commandToExecute": "Command to execute:",
@ -58,8 +58,8 @@
"permissionSession": "Allow for session",
"permissionGrantedOnce": "Permission granted for one-time access to {{path}}",
"permissionGrantedSession": "Permission granted for session access to {{path}}",
"permissionDenied": "Permission denied for {{path}}",
"permissionError": "An error occurred while handling the permission request.",
"permissionDenied": "Permission denied for {{path}}",
"permissionError": "An error occurred while handling the permission request."
},
"newChat": "New Chat",
"notConnected": "Gateway is not running. Start it to chat.",

View file

@ -49,7 +49,7 @@
"websocketConnecting": "正在连接聊天服务,请稍候。",
"websocketDisconnected": "无法对话WebSocket 连接已断开。请检查网络与服务状态,然后刷新页面或重启 Launcher。",
"websocketError": "无法对话WebSocket 连接失败。请检查网络与服务状态后重试。",
"noDefaultModel": "无法对话:尚未设置默认模型。请前往模型页面设置默认模型。"
"noDefaultModel": "无法对话:尚未设置默认模型。请前往模型页面设置默认模型。",
"permissionRequiredTitle": "需要权限",
"permissionRequiredMessage": "PicoClaw 想要使用 {{tool}} 访问 {{path}},但该路径位于工作区之外。",
"commandToExecute": "要执行的命令:",
@ -58,8 +58,8 @@
"permissionSession": "允许整个会话",
"permissionGrantedOnce": "已授予对 {{path}} 的一次性访问权限",
"permissionGrantedSession": "已授予对 {{path}} 的会话访问权限",
"permissionDenied": "已拒绝对 {{path}} 的访问权限",
"permissionError": "处理权限请求时发生错误。",
"permissionDenied": "已拒绝对 {{path}} 的访问权限",
"permissionError": "处理权限请求时发生错误。"
},
"newChat": "新建对话",
"notConnected": "服务未运行,请先启动以进行对话。",