feat: Prompt Envelope Protocol MVP
- 定义 11 种 Segment 类型(text, static_var, system_prompt, memory, skills, tool_overview, tool_call_request/result, document, long_text, media) - 每种 Segment 有独立的颜色编码和折叠交互 - 通用 CollapsiblePanel + SegmentRenderer 路由架构 - 4 个 Demo 场景覆盖全部 9 种上下文类型 - 导出为 OpenAI Chat Completions Format(model + messages + tools) - tool_overview -> 请求级 tools[](含 JSON Schema) - tool_call_request -> assistant.tool_calls[] - tool_call_result -> tool-role message(ID 配对) - 17 个单元测试全部通过 - React 18 + TypeScript + Vite + Tailwind CSS
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
import { useState, useMemo } from 'react'
|
||||
import type { PromptEnvelope } from '../types/protocol'
|
||||
import { exportToOpenAIFormat } from '../utils/export'
|
||||
import { Code, Copy, Download, Check } from 'lucide-react'
|
||||
|
||||
interface ProtocolPanelProps {
|
||||
envelope: PromptEnvelope
|
||||
}
|
||||
|
||||
export default function ProtocolPanel({ envelope }: ProtocolPanelProps) {
|
||||
const [copied, setCopied] = useState(false)
|
||||
|
||||
const openaiFormat = useMemo(() => exportToOpenAIFormat(envelope), [envelope])
|
||||
|
||||
const handleCopy = async () => {
|
||||
await navigator.clipboard.writeText(JSON.stringify(openaiFormat, null, 2))
|
||||
setCopied(true)
|
||||
setTimeout(() => setCopied(false), 2000)
|
||||
}
|
||||
|
||||
const handleDownload = () => {
|
||||
const blob = new Blob([JSON.stringify(openaiFormat, null, 2)], {
|
||||
type: 'application/json',
|
||||
})
|
||||
const url = URL.createObjectURL(blob)
|
||||
const a = document.createElement('a')
|
||||
a.href = url
|
||||
a.download = 'openai-export.json'
|
||||
a.click()
|
||||
URL.revokeObjectURL(url)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="w-96 border-l border-gray-200 bg-white flex flex-col h-full">
|
||||
{/* Header */}
|
||||
<div className="flex items-center gap-2 px-4 py-3 border-b border-gray-100">
|
||||
<Code size={18} className="text-gray-500" />
|
||||
<span className="text-sm font-semibold text-gray-700 flex-1">
|
||||
Protocol View
|
||||
</span>
|
||||
<button
|
||||
onClick={handleCopy}
|
||||
className="flex items-center gap-1 px-2 py-1 rounded text-xs text-gray-500 hover:bg-gray-100 transition-colors"
|
||||
>
|
||||
{copied ? <Check size={14} className="text-green-500" /> : <Copy size={14} />}
|
||||
{copied ? '已复制' : '复制'}
|
||||
</button>
|
||||
<button
|
||||
onClick={handleDownload}
|
||||
className="flex items-center gap-1 px-2 py-1 rounded text-xs text-gray-500 hover:bg-gray-100 transition-colors"
|
||||
>
|
||||
<Download size={14} />
|
||||
下载
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Tabs */}
|
||||
<div className="flex text-xs border-b border-gray-100">
|
||||
<div className="flex-1 text-center py-2 font-semibold text-blue-600 border-b-2 border-blue-500 bg-blue-50/50">
|
||||
OpenAI Format
|
||||
</div>
|
||||
<div className="flex-1 text-center py-2 text-gray-400">
|
||||
Raw Protocol (soon)
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* JSON Content */}
|
||||
<div className="flex-1 overflow-y-auto">
|
||||
<pre className="p-4 text-xs font-mono text-gray-600 whitespace-pre-wrap break-all leading-relaxed">
|
||||
{JSON.stringify(openaiFormat, null, 2)}
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
{/* Footer stats */}
|
||||
<div className="px-4 py-2 border-t border-gray-100 text-[10px] text-gray-400 flex items-center gap-3">
|
||||
<span>model: {openaiFormat.model}</span>
|
||||
<span>{envelope.messages.length} 条协议消息</span>
|
||||
<span>{openaiFormat.messages.length} OpenAI messages</span>
|
||||
{openaiFormat.tools && <span>{openaiFormat.tools.length} tools</span>}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user