Files
Prompt-Envelope-Protocol/CLAUDE.md
T

8.3 KiB
Raw Blame History

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

项目语言:中文。所有注释、文档、commit message、UI 文案均使用中文。

项目概述

HCI 课程设计项目:Prompt Envelope Protocol — 一套让 LLM 上下文在聊天界面中可见的协议与 UI。

核心思想:每条聊天消息由若干带类型的 Segment 组成(而非原始文本)。每种 Segment 有独立的视觉呈现,让 system prompt、memory、tools、skills、变量、文档、多媒体成为可见的一等元素,而非隐藏的上下文。

MVP 为纯前端 React 应用,使用 mock 数据演示。无后端、无真实 LLM 调用。

命令

npm run dev          # Vite 开发服务器 → http://localhost:5173
npm run build        # tsc 类型检查 + vite 构建
npm test             # vitest 运行全部测试(2 个文件,export.test.ts + parseSkill.test.ts,共 ~26 个用例)
npm run preview      # 预览生产构建
npx vitest run src/__tests__/export.test.ts       # 运行单个测试文件
npx vitest run src/__tests__/parseSkill.test.ts

架构

数据模型 (src/types/protocol.ts)

PromptEnvelope { version, model?, messages: Message[] } — 顶层协议文档。可选 model 字段用于导出时指定模型名(默认 "gpt-4-turbo")。

Message { id, role: "system"|"user"|"assistant"|"tool", segments: Segment[], timestamp } — 单条聊天消息。role: "tool" 用于独立的工具调用消息。

Segment 是基于 kind 的可辨识联合类型,共 11 种变体:textstatic_varsystem_promptmemoryskillstool_overviewtool_call_requesttool_call_resultdocumentlong_textmedia

关键类型细节:

  • StaticVarSegmentnamevalue、可选 description — 会话级变量,如 {{current_date}}"2026年6月8日"不在消息气泡内渲染,由 MessageList.extractSessionVars() 提取到 SessionBar 横栏中
  • SkillItemnamedescriptionL1 始终可见)、bodyL2 触发时加载的 Markdown 正文)——遵循 Anthropic SKILL.md 规范
  • ToolItem 有可选 schema 字段(JSON Schema 对象),导出时作为 tools[].function.parameters
  • DocumentSegment 有可选 parsedContent 字段,「查看解析」时用 MarkdownRenderer 展示
  • MemorySegmentSkillSegment 有可选 description 字段,在 UI 中解释其用途

Skills 系统

遵循 Anthropic SKILL.md 规范,实现渐进式披露。管线:

SKILL.md 文件 (YAML frontmatter + Markdown body)
  │
  ├─ parseSkillMarkdown()        → ParsedSkill { name, description, body, bodyLineCount, ... }
  │   (src/utils/parseSkill.ts)     极简手写 YAML 解析器(不依赖外部库),提取顶层 string 键值
  │
  ├─ skills-loader.ts            → PARSED_SKILLS (Record<string, ParsedSkill>)
  │   (src/data/skills-loader.ts)    通过 Vite ?raw 导入 4 个真实 Anthropic SKILL.md 文件
  │                                  + toSkillItem() / getRealSkills() / getAllRealSkillItems()
  │
  ├─ skills.ts                   → ALL_SKILLS (Record<string, SkillItem>)
  │   (src/data/skills.ts)           8 个手写 skillcode-review、deep-research、verify、simplify、
  │                                  loop、summarize、translate、qa
  │                                  + getSkills(names) 按名称选取
  │
  ├─ demos-loader.ts             → buildSkillLookup() 合并两个源 → hydrateSkills(envelope)
  │   (src/data/demos/demos-loader.ts)     按 name 匹配,补全 JSON 中只包含 name+description 的 skill items
  │                                 + validateEnvelope() 运行时类型守卫
  │                                 + loadEnvelope() = validateEnvelope + hydrateSkills
  │
  └─ UI: SkillsView              → SkillDisclosure 逐项展开:L1 name+description(始终可见),L2 body(点击展开)

渲染管线

消息在渲染前经过 MessageList 两步预处理:

  1. extractSessionVars() — 从所有消息中提取 static_var segment,构建 varMap,并将其从消息体中移除。变量展示在 SessionBar(对话区顶部横栏)
  2. extractToolMessages() — 将 tool_call_request/tool_call_result segment 拆分为独立 role: "tool" 消息

处理后的消息按 Segment kind 分发渲染:

SegmentRenderer (按 segment.kind 分发)
  ├─ TextSegmentView        → MarkdownRendererreact-markdown + remark-gfm,所有 HTML 元素自定义 Tailwind
  ├─ static_var              → 返回 null(已由 SessionBar 提取)
  ├─ SystemPromptView       → CollapsiblePanel(灰色),支持 {{var}} 模板可视化渲染
  ├─ MemoryView             → CollapsiblePanel(紫色)
  ├─ SkillsView             → CollapsiblePanel(绿色), SkillDisclosure 逐项逐层展开
  ├─ ToolOverviewView       → CollapsiblePanel(橙色),ToolItemRow 可独立展开 JSON Schema
  ├─ ToolCallRequestView    → 深色终端风格,参数以标签化键值行展示 + 长值折叠
  ├─ ToolCallResultView     → 绿/红状态条(失败默认展开,成功默认折叠)
  ├─ DocumentCard           → 文件图标 + 文件名 + 大小 + snippet,可选「查看解析」展开 Markdown
  ├─ LongTextView           → 折叠态前2行预览 + 展开态用 MarkdownRenderer 渲染
  └─ MediaView              → 图片有 URL 时直接渲染缩略图;加载失败/无URL/非图片则图标占位

CollapsiblePanel 是共享折叠容器,接收 titleiconcolorbgColordefaultCollapsedbadge props。

MarkdownRenderer 是所有文本类组的共享 Markdown 渲染组件,覆盖 h1-h4、p、code、pre、table、blockquote、list 等所有常见元素的 Tailwind 样式。

导出管线 (src/utils/export.ts)

exportToOpenAIFormat(envelope): OpenAIExport 输出 { model, messages: OpenAIMessage[], tools?: OpenAITool[] }——完整的 OpenAI Chat Completions request body。

关键映射:

  • system_prompt/memory/skills → 合并为一条 leading role: "system" 消息
  • system_prompt 中的 {{var}} 占位符在导出时展开
  • tool_overview → 顶层 tools[]item.schema 映射为 tool.function.parameters
  • tool_call_requestrole: "assistant" 消息带 tool_calls[](自动生成 call_id
  • tool_call_result → 独立 role: "tool" 消息,通过 call_id 与请求配对
  • static_var → user/assistant 消息中展开为值;system 消息中只参与模板展开,直接出现在 system 消息正文中
  • 含图片 media 的 user 消息 → 多模态 content 数组 ([{type: "text"}, {type: "image_url"}])
  • document / long_text → 原文输出(带 [Document: ...] 标注)
  • segmentToText() 对结构性/tool Segment 返回 null——在消息级别统一处理

Demo 数据 (src/data/demos/)

6 个场景(A–F),每个是独立的 JSON 文件(demo-{a..f}.json),通过 manifest.json 索引。默认激活场景 A"default": true 在 manifest 中标记为场景 F,但 ChatContext 初始化为 useState(0))。

加载流程:JSON import (unknown) → validateEnvelope() → hydrateSkills() → PromptEnvelope

状态管理

ChatContextsrc/context/ChatContext.tsx)持有 envelopeactiveDemodemos。切换场景时替换整个 envelope。默认激活索引 0(场景 A)。ChatInput 已禁用。

颜色系统

颜色 Segment / 用途
蓝色 static_varSessionBar + badge
灰色 system_prompt
紫色 memory
绿色 skills
橙色 tool_overview
深色 tool_call_request(代码块)
绿/红 tool_call_result(成功/失败)
琥珀 role: "tool" 消息气泡

布局

双栏:左侧 ChatViewSessionBar + MessageList + ChatInput),右侧 ProtocolPanel(双 TabOpenAI Format / Raw Protocol,支持复制/下载,底部统计信息)。顶栏有 6 个 Demo 场景切换按钮。