支持更多的权限请求格式

This commit is contained in:
xintaofei
2026-03-13 13:12:16 +08:00
parent bdbfa9ce97
commit bf14a99168
3 changed files with 72 additions and 2 deletions

View File

@@ -9,6 +9,8 @@ import {
ListTodo,
Compass,
FileText,
Globe,
Search,
} from "lucide-react"
import { Button } from "@/components/ui/button"
import { Badge } from "@/components/ui/badge"
@@ -43,13 +45,15 @@ export function PermissionDialog({
parsed.planEntries.length > 0 || Boolean(parsed.planExplanation)
const hasPlanMarkdown = Boolean(parsed.planMarkdown)
const hasAllowedPrompts = parsed.allowedPrompts.length > 0
const hasWeb = Boolean(parsed.url) || Boolean(parsed.query)
const hasStructured =
Boolean(parsed.command) ||
hasFileChanges ||
hasPlan ||
hasPlanMarkdown ||
hasAllowedPrompts ||
Boolean(parsed.modeTarget)
Boolean(parsed.modeTarget) ||
hasWeb
return (
<div className="mx-4 mb-3 rounded-xl border border-border/70 bg-card/95 p-3 shadow-sm">
@@ -189,6 +193,32 @@ export function PermissionDialog({
</div>
)}
{hasWeb && (
<div className="space-y-1.5 rounded-md border border-border/60 bg-muted/20 p-2">
{parsed.url && (
<div className="flex items-center gap-2 text-xs">
<Globe className="h-3.5 w-3.5 shrink-0 text-muted-foreground" />
<span className="break-all font-mono text-foreground/90">
{parsed.url}
</span>
</div>
)}
{parsed.query && (
<div className="flex items-center gap-2 text-xs">
<Search className="h-3.5 w-3.5 shrink-0 text-muted-foreground" />
<span className="break-all text-foreground/90">
{parsed.query}
</span>
</div>
)}
{parsed.prompt && (
<div className="mt-1 text-xs text-muted-foreground">
<MessageResponse>{parsed.prompt}</MessageResponse>
</div>
)}
</div>
)}
{!hasStructured && (
<pre className="rounded-md border border-border/60 bg-muted/20 p-2 text-xs whitespace-pre-wrap break-all text-foreground/90">
{parsed.jsonPreview}

View File

@@ -242,7 +242,34 @@ function serializePermissionToolCall(toolCall: unknown): string | null {
const record = asRecord(toolCall)
if (!record) return null
try {
return JSON.stringify(record)
// Extract the actual tool input from the nested rawInput/raw_input field
// rather than serializing the entire permission wrapper (which includes
// internal fields like content, kind, title, toolCallId).
const nestedInput = record.rawInput ?? record.raw_input
if (nestedInput !== undefined && nestedInput !== null) {
if (typeof nestedInput === "string") return nestedInput
return JSON.stringify(nestedInput)
}
// Fallback: strip wrapper-only fields to avoid rendering internal
// permission structure as raw text.
const wrapperKeys = new Set([
"content",
"kind",
"title",
"toolCallId",
"tool_call_id",
"callId",
"call_id",
"rawInput",
"raw_input",
])
const rest: Record<string, unknown> = {}
for (const [k, v] of Object.entries(record)) {
if (!wrapperKeys.has(k)) rest[k] = v
}
return Object.keys(rest).length > 0
? JSON.stringify(rest)
: JSON.stringify(record)
} catch {
return null
}

View File

@@ -38,6 +38,9 @@ export interface ParsedPermissionToolCall {
planMarkdown: string | null
allowedPrompts: PermissionAllowedPrompt[]
modeTarget: string | null
url: string | null
query: string | null
prompt: string | null
jsonPreview: string
}
@@ -675,6 +678,13 @@ export function parsePermissionToolCall(
"targetMode",
]) ?? null
const url =
pickString(rawInputObj, ["url"]) ?? pickString(toolCallObj, ["url"])
const query =
pickString(rawInputObj, ["query"]) ?? pickString(toolCallObj, ["query"])
const prompt =
pickString(rawInputObj, ["prompt"]) ?? pickString(toolCallObj, ["prompt"])
const title =
pickString(toolCallObj, ["title", "tool_name", "toolName", "name"]) ??
formatFallbackTitle(normalizedKind)
@@ -693,6 +703,9 @@ export function parsePermissionToolCall(
planMarkdown,
allowedPrompts,
modeTarget,
url,
query,
prompt,
jsonPreview: stringifyJson(toolCallObj ?? toolCall),
}
}