支持显示权限请求里面的plan markdown
This commit is contained in:
@@ -8,10 +8,12 @@ import {
|
|||||||
FilePenLine,
|
FilePenLine,
|
||||||
ListTodo,
|
ListTodo,
|
||||||
Compass,
|
Compass,
|
||||||
|
FileText,
|
||||||
} from "lucide-react"
|
} from "lucide-react"
|
||||||
import { Button } from "@/components/ui/button"
|
import { Button } from "@/components/ui/button"
|
||||||
import { Badge } from "@/components/ui/badge"
|
import { Badge } from "@/components/ui/badge"
|
||||||
import { CodeBlock } from "@/components/ai-elements/code-block"
|
import { CodeBlock } from "@/components/ai-elements/code-block"
|
||||||
|
import { MessageResponse } from "@/components/ai-elements/message"
|
||||||
import type { PendingPermission } from "@/contexts/acp-connections-context"
|
import type { PendingPermission } from "@/contexts/acp-connections-context"
|
||||||
import { parsePermissionToolCall } from "@/lib/permission-request"
|
import { parsePermissionToolCall } from "@/lib/permission-request"
|
||||||
|
|
||||||
@@ -39,10 +41,14 @@ export function PermissionDialog({
|
|||||||
const hasFileChanges = parsed.fileChanges.length > 0
|
const hasFileChanges = parsed.fileChanges.length > 0
|
||||||
const hasPlan =
|
const hasPlan =
|
||||||
parsed.planEntries.length > 0 || Boolean(parsed.planExplanation)
|
parsed.planEntries.length > 0 || Boolean(parsed.planExplanation)
|
||||||
|
const hasPlanMarkdown = Boolean(parsed.planMarkdown)
|
||||||
|
const hasAllowedPrompts = parsed.allowedPrompts.length > 0
|
||||||
const hasStructured =
|
const hasStructured =
|
||||||
Boolean(parsed.command) ||
|
Boolean(parsed.command) ||
|
||||||
hasFileChanges ||
|
hasFileChanges ||
|
||||||
hasPlan ||
|
hasPlan ||
|
||||||
|
hasPlanMarkdown ||
|
||||||
|
hasAllowedPrompts ||
|
||||||
Boolean(parsed.modeTarget)
|
Boolean(parsed.modeTarget)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -138,6 +144,42 @@ export function PermissionDialog({
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{hasPlanMarkdown && (
|
||||||
|
<div className="space-y-1.5 rounded-md border border-border/60 bg-muted/20 p-2">
|
||||||
|
<div className="flex items-center gap-1 text-xs text-muted-foreground">
|
||||||
|
<FileText className="h-3.5 w-3.5" />
|
||||||
|
<span>{t("plan")}</span>
|
||||||
|
</div>
|
||||||
|
<div className="text-sm prose prose-sm dark:prose-invert max-w-none [&_ul]:list-inside [&_ol]:list-inside">
|
||||||
|
<MessageResponse>{parsed.planMarkdown!}</MessageResponse>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{hasAllowedPrompts && (
|
||||||
|
<div className="space-y-1.5 rounded-md border border-border/60 bg-muted/20 p-2">
|
||||||
|
<div className="flex items-center gap-1 text-xs text-muted-foreground">
|
||||||
|
<Terminal className="h-3.5 w-3.5" />
|
||||||
|
<span>{t("allowedActions")}</span>
|
||||||
|
</div>
|
||||||
|
<div className="space-y-1 rounded-md bg-muted/40 p-2">
|
||||||
|
{parsed.allowedPrompts.map((item, index) => (
|
||||||
|
<div
|
||||||
|
key={`${item.prompt}-${index}`}
|
||||||
|
className="flex items-center gap-2 text-xs"
|
||||||
|
>
|
||||||
|
{item.tool && (
|
||||||
|
<Badge variant="outline" className="shrink-0 text-[10px]">
|
||||||
|
{item.tool}
|
||||||
|
</Badge>
|
||||||
|
)}
|
||||||
|
<span className="text-foreground/90">{item.prompt}</span>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{parsed.modeTarget && (
|
{parsed.modeTarget && (
|
||||||
<div className="rounded-md border border-border/60 bg-muted/20 p-2 text-xs">
|
<div className="rounded-md border border-border/60 bg-muted/20 p-2 text-xs">
|
||||||
<div className="flex items-center gap-1 text-muted-foreground">
|
<div className="flex items-center gap-1 text-muted-foreground">
|
||||||
|
|||||||
@@ -1173,6 +1173,7 @@
|
|||||||
"filesSummary": "الملفات: {count}",
|
"filesSummary": "الملفات: {count}",
|
||||||
"moreFiles": "+{count} ملف إضافي",
|
"moreFiles": "+{count} ملف إضافي",
|
||||||
"plan": "الخطة",
|
"plan": "الخطة",
|
||||||
|
"allowedActions": "الإجراءات المسموح بها",
|
||||||
"targetMode": "وضع الهدف: {mode}"
|
"targetMode": "وضع الهدف: {mode}"
|
||||||
},
|
},
|
||||||
"questionDialog": {
|
"questionDialog": {
|
||||||
|
|||||||
@@ -1173,6 +1173,7 @@
|
|||||||
"filesSummary": "Dateien: {count}",
|
"filesSummary": "Dateien: {count}",
|
||||||
"moreFiles": "+{count} weitere Dateien",
|
"moreFiles": "+{count} weitere Dateien",
|
||||||
"plan": "Arbeitsplan",
|
"plan": "Arbeitsplan",
|
||||||
|
"allowedActions": "Erlaubte Aktionen",
|
||||||
"targetMode": "Zielmodus: {mode}"
|
"targetMode": "Zielmodus: {mode}"
|
||||||
},
|
},
|
||||||
"questionDialog": {
|
"questionDialog": {
|
||||||
|
|||||||
@@ -1173,6 +1173,7 @@
|
|||||||
"filesSummary": "Files: {count}",
|
"filesSummary": "Files: {count}",
|
||||||
"moreFiles": "+{count} more files",
|
"moreFiles": "+{count} more files",
|
||||||
"plan": "Plan",
|
"plan": "Plan",
|
||||||
|
"allowedActions": "Allowed actions",
|
||||||
"targetMode": "Target mode: {mode}"
|
"targetMode": "Target mode: {mode}"
|
||||||
},
|
},
|
||||||
"questionDialog": {
|
"questionDialog": {
|
||||||
|
|||||||
@@ -1173,6 +1173,7 @@
|
|||||||
"filesSummary": "Archivos: {count}",
|
"filesSummary": "Archivos: {count}",
|
||||||
"moreFiles": "+{count} archivos más",
|
"moreFiles": "+{count} archivos más",
|
||||||
"plan": "Plan de trabajo",
|
"plan": "Plan de trabajo",
|
||||||
|
"allowedActions": "Acciones permitidas",
|
||||||
"targetMode": "Modo objetivo: {mode}"
|
"targetMode": "Modo objetivo: {mode}"
|
||||||
},
|
},
|
||||||
"questionDialog": {
|
"questionDialog": {
|
||||||
|
|||||||
@@ -1173,6 +1173,7 @@
|
|||||||
"filesSummary": "Fichiers : {count}",
|
"filesSummary": "Fichiers : {count}",
|
||||||
"moreFiles": "+{count} fichiers supplémentaires",
|
"moreFiles": "+{count} fichiers supplémentaires",
|
||||||
"plan": "Plan de travail",
|
"plan": "Plan de travail",
|
||||||
|
"allowedActions": "Actions autorisées",
|
||||||
"targetMode": "Mode cible : {mode}"
|
"targetMode": "Mode cible : {mode}"
|
||||||
},
|
},
|
||||||
"questionDialog": {
|
"questionDialog": {
|
||||||
|
|||||||
@@ -1173,6 +1173,7 @@
|
|||||||
"filesSummary": "ファイル: {count}",
|
"filesSummary": "ファイル: {count}",
|
||||||
"moreFiles": "+{count} 件の追加ファイル",
|
"moreFiles": "+{count} 件の追加ファイル",
|
||||||
"plan": "計画",
|
"plan": "計画",
|
||||||
|
"allowedActions": "許可されたアクション",
|
||||||
"targetMode": "対象モード: {mode}"
|
"targetMode": "対象モード: {mode}"
|
||||||
},
|
},
|
||||||
"questionDialog": {
|
"questionDialog": {
|
||||||
|
|||||||
@@ -1173,6 +1173,7 @@
|
|||||||
"filesSummary": "파일: {count}",
|
"filesSummary": "파일: {count}",
|
||||||
"moreFiles": "+{count}개 파일 더",
|
"moreFiles": "+{count}개 파일 더",
|
||||||
"plan": "계획",
|
"plan": "계획",
|
||||||
|
"allowedActions": "허용된 작업",
|
||||||
"targetMode": "대상 모드: {mode}"
|
"targetMode": "대상 모드: {mode}"
|
||||||
},
|
},
|
||||||
"questionDialog": {
|
"questionDialog": {
|
||||||
|
|||||||
@@ -1173,6 +1173,7 @@
|
|||||||
"filesSummary": "Arquivos: {count}",
|
"filesSummary": "Arquivos: {count}",
|
||||||
"moreFiles": "+{count} arquivos a mais",
|
"moreFiles": "+{count} arquivos a mais",
|
||||||
"plan": "Plano",
|
"plan": "Plano",
|
||||||
|
"allowedActions": "Ações permitidas",
|
||||||
"targetMode": "Modo de destino: {mode}"
|
"targetMode": "Modo de destino: {mode}"
|
||||||
},
|
},
|
||||||
"questionDialog": {
|
"questionDialog": {
|
||||||
|
|||||||
@@ -1173,6 +1173,7 @@
|
|||||||
"filesSummary": "文件:{count}",
|
"filesSummary": "文件:{count}",
|
||||||
"moreFiles": "+{count} 个更多文件",
|
"moreFiles": "+{count} 个更多文件",
|
||||||
"plan": "计划",
|
"plan": "计划",
|
||||||
|
"allowedActions": "允许的操作",
|
||||||
"targetMode": "目标模式:{mode}"
|
"targetMode": "目标模式:{mode}"
|
||||||
},
|
},
|
||||||
"questionDialog": {
|
"questionDialog": {
|
||||||
|
|||||||
@@ -1173,6 +1173,7 @@
|
|||||||
"filesSummary": "檔案:{count}",
|
"filesSummary": "檔案:{count}",
|
||||||
"moreFiles": "+{count} 個更多檔案",
|
"moreFiles": "+{count} 個更多檔案",
|
||||||
"plan": "計畫",
|
"plan": "計畫",
|
||||||
|
"allowedActions": "允許的操作",
|
||||||
"targetMode": "目標模式:{mode}"
|
"targetMode": "目標模式:{mode}"
|
||||||
},
|
},
|
||||||
"questionDialog": {
|
"questionDialog": {
|
||||||
|
|||||||
@@ -19,6 +19,11 @@ export interface PermissionPlanEntry {
|
|||||||
status: string | null
|
status: string | null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface PermissionAllowedPrompt {
|
||||||
|
prompt: string
|
||||||
|
tool: string
|
||||||
|
}
|
||||||
|
|
||||||
export interface ParsedPermissionToolCall {
|
export interface ParsedPermissionToolCall {
|
||||||
title: string
|
title: string
|
||||||
normalizedKind: string
|
normalizedKind: string
|
||||||
@@ -30,6 +35,8 @@ export interface ParsedPermissionToolCall {
|
|||||||
diffPreview: string | null
|
diffPreview: string | null
|
||||||
planEntries: PermissionPlanEntry[]
|
planEntries: PermissionPlanEntry[]
|
||||||
planExplanation: string | null
|
planExplanation: string | null
|
||||||
|
planMarkdown: string | null
|
||||||
|
allowedPrompts: PermissionAllowedPrompt[]
|
||||||
modeTarget: string | null
|
modeTarget: string | null
|
||||||
jsonPreview: string
|
jsonPreview: string
|
||||||
}
|
}
|
||||||
@@ -529,6 +536,28 @@ function parsePlanEntries(
|
|||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function parseAllowedPrompts(
|
||||||
|
rawInputObj: ObjectLike | null
|
||||||
|
): PermissionAllowedPrompt[] {
|
||||||
|
if (!rawInputObj) return []
|
||||||
|
const list = asArray(
|
||||||
|
pickValue(rawInputObj, ["allowedPrompts", "allowed_prompts"])
|
||||||
|
)
|
||||||
|
if (!list || list.length === 0) return []
|
||||||
|
|
||||||
|
const prompts: PermissionAllowedPrompt[] = []
|
||||||
|
for (const item of list) {
|
||||||
|
const record = asObject(item)
|
||||||
|
if (!record) continue
|
||||||
|
const prompt = pickString(record, ["prompt", "description", "text"])
|
||||||
|
const tool = pickString(record, ["tool", "toolName", "tool_name"])
|
||||||
|
if (prompt) {
|
||||||
|
prompts.push({ prompt, tool: tool ?? "" })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return prompts
|
||||||
|
}
|
||||||
|
|
||||||
function formatFallbackTitle(kind: string): string {
|
function formatFallbackTitle(kind: string): string {
|
||||||
const normalized = kind.replace(/_/g, " ").trim()
|
const normalized = kind.replace(/_/g, " ").trim()
|
||||||
if (!normalized) return "Permission Request"
|
if (!normalized) return "Permission Request"
|
||||||
@@ -631,6 +660,13 @@ export function parsePermissionToolCall(
|
|||||||
|
|
||||||
const planEntries = parsePlanEntries(rawInputObj)
|
const planEntries = parsePlanEntries(rawInputObj)
|
||||||
const planExplanation = pickString(rawInputObj, ["explanation"])
|
const planExplanation = pickString(rawInputObj, ["explanation"])
|
||||||
|
|
||||||
|
const rawPlan = rawInputObj ? pickValue(rawInputObj, ["plan"]) : null
|
||||||
|
const planMarkdown =
|
||||||
|
typeof rawPlan === "string" && rawPlan.trim().length > 0 ? rawPlan : null
|
||||||
|
|
||||||
|
const allowedPrompts = parseAllowedPrompts(rawInputObj)
|
||||||
|
|
||||||
const modeTarget =
|
const modeTarget =
|
||||||
pickString(rawInputObj, [
|
pickString(rawInputObj, [
|
||||||
"mode_id",
|
"mode_id",
|
||||||
@@ -654,6 +690,8 @@ export function parsePermissionToolCall(
|
|||||||
diffPreview,
|
diffPreview,
|
||||||
planEntries,
|
planEntries,
|
||||||
planExplanation,
|
planExplanation,
|
||||||
|
planMarkdown,
|
||||||
|
allowedPrompts,
|
||||||
modeTarget,
|
modeTarget,
|
||||||
jsonPreview: stringifyJson(toolCallObj ?? toolCall),
|
jsonPreview: stringifyJson(toolCallObj ?? toolCall),
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user