const PROMPT_TEMPLATE_VARIABLES = [ { name: "current_time", sample: "2026年06月11日 15时" }, { name: "user_id", sample: "tenant-demo" }, { name: "thread_id", sample: "thread_demo" }, { name: "run_id", sample: "run_demo" }, { name: "agent_id", sample: "agent_demo" }, { name: "agent_name", sample: "Agent Demo" }, { name: "skill_list", sample: "1. document-summary\n2. deep-research" }, { name: "mcp_list", sample: "1. mcp_web_search" }, { name: "attachments", sample: "1. input/example.pdf (application/pdf, 102400 bytes)" }, { name: "meeting_id", sample: "meeting_demo", condition: true }, ]; function isPromptVariableName(name) { return /^[A-Za-z_][A-Za-z0-9_]*$/.test(String(name || "").trim()); } function uniquePromptVariables(items) { const seen = new Set(); const out = []; for (const raw of items || []) { const name = String(raw || "").trim(); if (!isPromptVariableName(name) || seen.has(name)) continue; seen.add(name); out.push(name); } return out; } function scanPromptVariables(template) { const re = /\{\{\s*([A-Za-z_][A-Za-z0-9_]*)\s*\}\}/g; const seen = new Set(); const out = []; let m; while ((m = re.exec(template || ""))) { if (seen.has(m[1])) continue; seen.add(m[1]); out.push(m[1]); } return out; } function mergePromptVariables(template, extraVariables = []) { return uniquePromptVariables([ ...scanPromptVariables(template || ""), ...(extraVariables || []), ]); } function previewPromptTemplate(template, variables) { let rendered = String(template || ""); rendered = rendered.replace(/\{%\s*if\s+([A-Za-z_][A-Za-z0-9_]*)\s*%\}([\s\S]*?)\{%\s*endif\s*%\}/g, (_, key, body) => ( variables[key] ? body : "" )); rendered = rendered.replace(/\{\{\s*([A-Za-z_][A-Za-z0-9_]*)\s*\}\}/g, (_, key) => { const value = variables[key]; if (value == null) return ""; if (typeof value === "object") return JSON.stringify(value); return String(value); }); return rendered; } function samplePromptVariables(agent) { const out = {}; for (const item of PROMPT_TEMPLATE_VARIABLES) out[item.name] = item.sample; for (const name of agent?.promptVariables || []) { if (out[name] === undefined) out[name] = `sample_${name}`; } out.agent_id = agent?.id || out.agent_id; out.agent_name = agent?.name || out.agent_name; return out; } function PromptTemplateEditor({ value, onChange, agent, className = "textarea-lg", rows, style, placeholder, }) { const textareaRef = React.useRef(null); const [selectedVariable, setSelectedVariable] = React.useState("current_time"); const detectedVariables = React.useMemo(() => scanPromptVariables(value || ""), [value]); const savedPromptVariables = React.useMemo( () => uniquePromptVariables(agent?.promptVariables || []), [JSON.stringify(agent?.promptVariables || [])] ); const variableChoices = React.useMemo(() => uniquePromptVariables([ ...PROMPT_TEMPLATE_VARIABLES.map((item) => item.name), ...savedPromptVariables, ...detectedVariables, ]), [JSON.stringify(savedPromptVariables), JSON.stringify(detectedVariables)]); const sampleValues = React.useMemo( () => samplePromptVariables(agent), [agent?.id, agent?.name, JSON.stringify(agent?.promptVariables || [])] ); const preview = React.useMemo( () => previewPromptTemplate(value || "", sampleValues), [value, sampleValues] ); const update = (next) => onChange(next, mergePromptVariables(next)); const insertText = (text, selectStartOffset = text.length, selectEndOffset = text.length) => { const textarea = textareaRef.current; const current = String(value || ""); const start = textarea ? textarea.selectionStart : current.length; const end = textarea ? textarea.selectionEnd : current.length; const next = current.slice(0, start) + text + current.slice(end); update(next); requestAnimationFrame(() => { if (!textareaRef.current) return; textareaRef.current.focus(); const cursorStart = start + selectStartOffset; const cursorEnd = start + selectEndOffset; textareaRef.current.setSelectionRange(cursorStart, cursorEnd); }); }; const insertVariable = (name) => insertText(`{{ ${name} }}`); const insertCondition = (name) => { const textarea = textareaRef.current; const current = String(value || ""); const start = textarea ? textarea.selectionStart : current.length; const end = textarea ? textarea.selectionEnd : current.length; const selected = current.slice(start, end) || "content"; const before = `{% if ${name} %}\n`; const after = `\n{% endif %}`; insertText(before + selected + after, before.length, before.length + selected.length); }; const selectedName = variableChoices.includes(selectedVariable) ? selectedVariable : (variableChoices[0] || PROMPT_TEMPLATE_VARIABLES[0].name); const selectedMeta = PROMPT_TEMPLATE_VARIABLES.find((item) => item.name === selectedName) || { name: selectedName }; return (