[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M71H49KB9J6TYEG97S7M93EA":3,"skill-same:01M71H49KB9J6TYEG97S7M93EA":186},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":15,"categories":16,"keywords":27,"publishedAt":48,"linkOnly":49,"markdownContent":50,"markdownBody":51,"frontMatter":52,"refName":53,"commitSha":54,"skillDirectory":55,"forksCount":56,"repositoryHtmlUrl":57,"repositoryHomepageUrl":6,"ownerHtmlUrl":58,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":59,"install":60,"resources":73},"01M71H49KB9J6TYEG97S7M93EA","building-ai-chat",null,"Builds AI chat interfaces and conversational UI with streaming responses, context management, and multi-modal support. Use when creating ChatGPT-style interfaces, AI assistants, code copilots, or conversational agents. Handles streaming text, token limits, regeneration, feedback loops, tool usage visualization, and AI-specific error patterns. Provides battle-tested components from leading AI products with accessibility and performance built in.","JSGforever\u002Fskillguard","JSGforever","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F85541948?v=4","01M71FQD3E132VMR5F4TAYX3YS","01M71FQD4DYW0XJ4XQ4YQH75Y9",2,"GPL-3.0","https:\u002F\u002Fgithub.com\u002FJSGforever\u002Fskillguard\u002Fblob\u002Fmain\u002Fbenchmarks\u002Ffinal\u002Fskills\u002Fasset1__ancoleman--building-ai-chat\u002FSKILL.md",[17,22],{"categoryNo":18,"categoryName":19,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000013","分析与可视化","SCENARIO","使用场景",{"categoryNo":23,"categoryName":24,"taxonomyType":25,"taxonomyTypeDesc":26},"01JBSEEDCAT000000000000032","设计师","PROFESSION","适用职业",[28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47],"chat","building ai chat","patterns","ui","chatgpt","token","support","limits","loops","text","streaming","components","code","when","performance","battle","context management","error patterns","visualization","error","2026-11-10 10:12:30",false,"---\nname: building-ai-chat\ndescription: Builds AI chat interfaces and conversational UI with streaming responses, context management, and multi-modal support. Use when creating ChatGPT-style interfaces, AI assistants, code copilots, or conversational agents. Handles streaming text, token limits, regeneration, feedback loops, tool usage visualization, and AI-specific error patterns. Provides battle-tested components from leading AI products with accessibility and performance built in.\n---\n\n# AI Chat Interface Components\n\n## Purpose\n\nDefine the emerging standards for AI\u002Fhuman conversational interfaces in the 2024-2025 AI integration boom. This skill leverages meta-knowledge from building WITH Claude to establish definitive patterns for streaming UX, context management, and multi-modal interactions. As the industry lacks established patterns, this provides the reference implementation others will follow.\n\n## When to Use\n\nActivate this skill when:\n- Building ChatGPT-style conversational interfaces\n- Creating AI assistants, copilots, or chatbots\n- Implementing streaming text responses with markdown\n- Managing conversation context and token limits\n- Handling multi-modal inputs (text, images, files, voice)\n- Dealing with AI-specific errors (hallucinations, refusals, limits)\n- Adding feedback mechanisms (thumbs, regeneration, editing)\n- Implementing conversation branching or threading\n- Visualizing tool\u002Ffunction calling\n\n## Quick Start\n\nMinimal AI chat interface in under 50 lines:\n\n```tsx\nimport { useChat } from 'ai\u002Freact';\n\nexport function MinimalAIChat() {\n  const { messages, input, handleInputChange, handleSubmit, isLoading, stop } = useChat();\n\n  return (\n    \u003Cdiv className=\"chat-container\">\n      \u003Cdiv className=\"messages\">\n        {messages.map(m => (\n          \u003Cdiv key={m.id} className={`message ${m.role}`}>\n            \u003Cdiv className=\"content\">{m.content}\u003C\u002Fdiv>\n          \u003C\u002Fdiv>\n        ))}\n        {isLoading && \u003Cdiv className=\"thinking\">AI is thinking...\u003C\u002Fdiv>}\n      \u003C\u002Fdiv>\n\n      \u003Cform onSubmit={handleSubmit} className=\"input-form\">\n        \u003Cinput\n          value={input}\n          onChange={handleInputChange}\n          placeholder=\"Ask anything...\"\n          disabled={isLoading}\n        \u002F>\n        {isLoading ? (\n          \u003Cbutton type=\"button\" onClick={stop}>Stop\u003C\u002Fbutton>\n        ) : (\n          \u003Cbutton type=\"submit\">Send\u003C\u002Fbutton>\n        )}\n      \u003C\u002Fform>\n    \u003C\u002Fdiv>\n  );\n}\n```\n\nFor complete implementation with streaming markdown, see `examples\u002Fbasic-chat.tsx`.\n\n## Core Components\n\n### Message Display\n\nBuild user, AI, and system message bubbles with streaming support:\n\n```tsx\n\u002F\u002F User message\n\u003Cdiv className=\"message user\">\n  \u003Cdiv className=\"content\">{message.content}\u003C\u002Fdiv>\n  \u003Ctime className=\"timestamp\">{formatTime(message.timestamp)}\u003C\u002Ftime>\n\u003C\u002Fdiv>\n\n\u002F\u002F AI message with streaming\n\u003Cdiv className=\"message ai\">\n  \u003CStreamdown className=\"content\">{message.content}\u003C\u002FStreamdown>\n  {message.isStreaming && \u003Cspan className=\"cursor\">▊\u003C\u002Fspan>}\n\u003C\u002Fdiv>\n\n\u002F\u002F System message\n\u003Cdiv className=\"message system\">\n  \u003CIcon type=\"info\" \u002F>\n  \u003Cspan>{message.content}\u003C\u002Fspan>\n\u003C\u002Fdiv>\n```\n\nFor markdown rendering, code blocks, and formatting details, see `references\u002Fmessage-components.md`.\n\n### Input Components\n\nCreate rich input experiences with attachments and voice:\n\n```tsx\n\u003Cdiv className=\"input-container\">\n  \u003Cbutton onClick={attachFile} aria-label=\"Attach file\">\n    \u003CPaperclipIcon \u002F>\n  \u003C\u002Fbutton>\n\n  \u003Ctextarea\n    value={input}\n    onChange={handleChange}\n    onKeyDown={handleKeyDown}\n    placeholder=\"Type a message...\"\n    rows={1}\n    style={{ height: textareaHeight }}\n  \u002F>\n\n  \u003Cbutton onClick={toggleVoice} aria-label=\"Voice input\">\n    \u003CMicIcon \u002F>\n  \u003C\u002Fbutton>\n\n  \u003Cbutton type=\"submit\" disabled={!input.trim() || isLoading}>\n    \u003CSendIcon \u002F>\n  \u003C\u002Fbutton>\n\u003C\u002Fdiv>\n```\n\n### Response Controls\n\nEssential controls for AI responses:\n\n```tsx\n\u003Cdiv className=\"response-controls\">\n  {isStreaming && (\n    \u003Cbutton onClick={stop} className=\"stop-btn\">\n      Stop generating\n    \u003C\u002Fbutton>\n  )}\n\n  {!isStreaming && (\n    \u003C>\n      \u003Cbutton onClick={regenerate} aria-label=\"Regenerate response\">\n        \u003CRefreshIcon \u002F> Regenerate\n      \u003C\u002Fbutton>\n      \u003Cbutton onClick={continueGeneration} aria-label=\"Continue\">\n        Continue\n      \u003C\u002Fbutton>\n      \u003Cbutton onClick={editMessage} aria-label=\"Edit message\">\n        \u003CEditIcon \u002F> Edit\n      \u003C\u002Fbutton>\n    \u003C\u002F>\n  )}\n\u003C\u002Fdiv>\n```\n\n### Feedback Mechanisms\n\nCollect user feedback to improve AI responses:\n\n```tsx\n\u003Cdiv className=\"feedback-controls\">\n  \u003Cbutton\n    onClick={() => sendFeedback('positive')}\n    aria-label=\"Good response\"\n    className={feedback === 'positive' ? 'selected' : ''}\n  >\n    \u003CThumbsUpIcon \u002F>\n  \u003C\u002Fbutton>\n\n  \u003Cbutton\n    onClick={() => sendFeedback('negative')}\n    aria-label=\"Bad response\"\n    className={feedback === 'negative' ? 'selected' : ''}\n  >\n    \u003CThumbsDownIcon \u002F>\n  \u003C\u002Fbutton>\n\n  \u003Cbutton onClick={copyToClipboard} aria-label=\"Copy\">\n    \u003CCopyIcon \u002F>\n  \u003C\u002Fbutton>\n\n  \u003Cbutton onClick={share} aria-label=\"Share\">\n    \u003CShareIcon \u002F>\n  \u003C\u002Fbutton>\n\u003C\u002Fdiv>\n```\n\n## Streaming & Real-Time UX\n\nProgressive rendering of AI responses requires special handling:\n\n```tsx\n\u002F\u002F Use Streamdown for AI streaming (handles incomplete markdown)\nimport { Streamdown } from '@vercel\u002Fstreamdown';\n\n\u002F\u002F Auto-scroll management\nuseEffect(() => {\n  if (shouldAutoScroll()) {\n    messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });\n  }\n}, [messages]);\n\n\u002F\u002F Smart auto-scroll heuristic\nfunction shouldAutoScroll() {\n  const threshold = 100; \u002F\u002F px from bottom\n  const isNearBottom =\n    container.scrollHeight - container.scrollTop - container.clientHeight \u003C threshold;\n  const userNotReading = !hasUserScrolledUp && !isTextSelected;\n  return isNearBottom && userNotReading;\n}\n```\n\nFor complete streaming patterns, auto-scroll behavior, and stop generation, see `references\u002Fstreaming-ux.md`.\n\n## Context Management\n\nCommunicate token limits clearly to users:\n\n```tsx\n\u002F\u002F User-friendly token display\nfunction TokenIndicator({ used, total }) {\n  const percentage = (used \u002F total) * 100;\n  const remaining = total - used;\n\n  return (\n    \u003Cdiv className=\"token-indicator\">\n      \u003Cdiv className=\"progress-bar\">\n        \u003Cdiv className=\"progress-fill\" style={{ width: `${percentage}%` }} \u002F>\n      \u003C\u002Fdiv>\n      \u003Cspan className=\"token-text\">\n        {percentage > 80\n          ? `⚠️ About ${Math.floor(remaining \u002F 250)} messages left`\n          : `${Math.floor(remaining \u002F 250)} pages of conversation remaining`}\n      \u003C\u002Fspan>\n    \u003C\u002Fdiv>\n  );\n}\n```\n\nFor summarization strategies, conversation branching, and organization, see `references\u002Fcontext-management.md`.\n\n## Multi-Modal Support\n\nHandle images, files, and voice inputs:\n\n```tsx\n\u002F\u002F Image upload with preview\nfunction ImageUpload({ onUpload }) {\n  return (\n    \u003Cdiv\n      className=\"upload-zone\"\n      onDrop={handleDrop}\n      onDragOver={preventDefault}\n    >\n      \u003Cinput\n        type=\"file\"\n        accept=\"image\u002F*\"\n        onChange={handleFileSelect}\n        multiple\n        hidden\n        ref={fileInputRef}\n      \u002F>\n      {previews.map(preview => (\n        \u003Cimg key={preview.id} src={preview.url} alt=\"Upload preview\" \u002F>\n      ))}\n    \u003C\u002Fdiv>\n  );\n}\n```\n\nFor complete multi-modal patterns including voice and screen sharing, see `references\u002Fmulti-modal.md`.\n\n## Error Handling\n\nHandle AI-specific errors gracefully:\n\n```tsx\n\u002F\u002F Refusal handling\nif (response.type === 'refusal') {\n  return (\n    \u003Cdiv className=\"error refusal\">\n      \u003CIcon type=\"info\" \u002F>\n      \u003Cp>I cannot help with that request.\u003C\u002Fp>\n      \u003Cdetails>\n        \u003Csummary>Why?\u003C\u002Fsummary>\n        \u003Cp>{response.reason}\u003C\u002Fp>\n      \u003C\u002Fdetails>\n      \u003Cp>Try asking: {response.suggestion}\u003C\u002Fp>\n    \u003C\u002Fdiv>\n  );\n}\n\n\u002F\u002F Rate limit communication\nif (error.code === 'RATE_LIMIT') {\n  return (\n    \u003Cdiv className=\"error rate-limit\">\n      \u003Cp>Please wait {error.retryAfter} seconds\u003C\u002Fp>\n      \u003CCountdownTimer seconds={error.retryAfter} onComplete={retry} \u002F>\n    \u003C\u002Fdiv>\n  );\n}\n```\n\nFor comprehensive error patterns, see `references\u002Ferror-handling.md`.\n\n## Tool Usage Visualization\n\nShow when AI is using tools or functions:\n\n```tsx\nfunction ToolUsage({ tool }) {\n  return (\n    \u003Cdiv className=\"tool-usage\">\n      \u003Cdiv className=\"tool-header\">\n        \u003CIcon type={tool.type} \u002F>\n        \u003Cspan>{tool.name}\u003C\u002Fspan>\n        {tool.status === 'running' && \u003CSpinner \u002F>}\n      \u003C\u002Fdiv>\n      {tool.status === 'complete' && (\n        \u003Cdetails>\n          \u003Csummary>View details\u003C\u002Fsummary>\n          \u003Cpre>{JSON.stringify(tool.result, null, 2)}\u003C\u002Fpre>\n        \u003C\u002Fdetails>\n      )}\n    \u003C\u002Fdiv>\n  );\n}\n```\n\nFor function calling, code execution, and web search patterns, see `references\u002Ftool-usage.md`.\n\n## Implementation Guide\n\n### Recommended Stack\n\nPrimary libraries (validated November 2025):\n\n```bash\n# Core AI chat functionality\nnpm install ai @ai-sdk\u002Freact @ai-sdk\u002Fopenai\n\n# Streaming markdown rendering\nnpm install @vercel\u002Fstreamdown\n\n# Syntax highlighting\nnpm install react-syntax-highlighter\n\n# Security for LLM outputs\nnpm install dompurify\n```\n\n### Performance Optimization\n\nCritical for smooth streaming:\n\n```tsx\n\u002F\u002F Memoize message rendering\nconst MemoizedMessage = memo(Message, (prev, next) =>\n  prev.content === next.content && prev.isStreaming === next.isStreaming\n);\n\n\u002F\u002F Debounce streaming updates\nconst debouncedUpdate = useMemo(\n  () => debounce(updateMessage, 50),\n  []\n);\n\n\u002F\u002F Virtual scrolling for long conversations\nimport { VariableSizeList } from 'react-window';\n```\n\nFor detailed performance patterns, see `references\u002Fstreaming-ux.md`.\n\n### Security Considerations\n\nAlways sanitize AI outputs:\n\n```tsx\nimport DOMPurify from 'dompurify';\n\nfunction SafeAIContent({ content }) {\n  const sanitized = DOMPurify.sanitize(content, {\n    ALLOWED_TAGS: ['p', 'br', 'strong', 'em', 'code', 'pre', 'blockquote', 'ul', 'ol', 'li'],\n    ALLOWED_ATTR: ['class']\n  });\n\n  return \u003CStreamdown>{sanitized}\u003C\u002FStreamdown>;\n}\n```\n\n### Accessibility\n\nEnsure AI chat is usable by everyone:\n\n```tsx\n\u002F\u002F ARIA live regions for screen readers\n\u003Cdiv role=\"log\" aria-live=\"polite\" aria-relevant=\"additions\">\n  {messages.map(msg => (\n    \u003Carticle key={msg.id} role=\"article\" aria-label={`${msg.role} message`}>\n      {msg.content}\n    \u003C\u002Farticle>\n  ))}\n\u003C\u002Fdiv>\n\n\u002F\u002F Loading announcements\n\u003Cdiv role=\"status\" aria-live=\"polite\" className=\"sr-only\">\n  {isLoading ? 'AI is responding' : ''}\n\u003C\u002Fdiv>\n```\n\nFor complete accessibility patterns, see `references\u002Faccessibility.md`.\n\n## Bundled Resources\n\n### Scripts (Token-Free Execution)\n\n- Run `scripts\u002Fparse_stream.js` to parse incomplete markdown during streaming\n- Run `scripts\u002Fcalculate_tokens.py` to estimate token usage and context limits\n- Run `scripts\u002Fformat_messages.js` to format message history for export\n\n### References (Progressive Disclosure)\n\n- `references\u002Fstreaming-patterns.md` - Complete streaming UX patterns\n- `references\u002Fcontext-management.md` - Token limits and conversation strategies\n- `references\u002Fmultimodal-input.md` - Image, file, and voice handling\n- `references\u002Ffeedback-loops.md` - User feedback and RLHF patterns\n- `references\u002Ferror-handling.md` - AI-specific error scenarios\n- `references\u002Ftool-usage.md` - Visualizing function calls and tool use\n- `references\u002Faccessibility-chat.md` - Screen reader and keyboard support\n- `references\u002Flibrary-guide.md` - Detailed library documentation\n- `references\u002Fperformance-optimization.md` - Streaming performance patterns\n\n### Examples\n\n- `examples\u002Fbasic-chat.tsx` - Minimal ChatGPT-style interface\n- `examples\u002Fstreaming-chat.tsx` - Advanced streaming with memoization\n- `examples\u002Fmultimodal-chat.tsx` - Images and file uploads\n- `examples\u002Fcode-assistant.tsx` - IDE-style code copilot\n- `examples\u002Ftool-calling-chat.tsx` - Function calling visualization\n\n### Assets\n\n- `assets\u002Fsystem-prompts.json` - Curated prompts for different use cases\n- `assets\u002Fmessage-templates.json` - Pre-built message components\n- `assets\u002Ferror-messages.json` - User-friendly error messages\n- `assets\u002Fthemes.json` - Light, dark, and high-contrast themes\n\n## Design Token Integration\n\nAll visual styling uses the design-tokens system:\n\n```css\n\u002F* Message bubbles use design tokens *\u002F\n.message.user {\n  background: var(--message-user-bg, var(--color-primary));\n  color: var(--message-user-text, var(--color-white));\n  padding: var(--message-padding, var(--spacing-md));\n  border-radius: var(--message-border-radius, var(--radius-lg));\n}\n\n.message.ai {\n  background: var(--message-ai-bg, var(--color-gray-100));\n  color: var(--message-ai-text, var(--color-text-primary));\n}\n```\n\nSee `skills\u002Fdesign-tokens\u002F` for complete theming system.\n\n## Key Innovations\n\nThis skill provides industry-first solutions for:\n\n- **Memoized streaming rendering** - 10-50x performance improvement\n- **Intelligent auto-scroll** - User activity-aware scrolling\n- **Token metaphors** - User-friendly context communication\n- **Incomplete markdown handling** - Graceful partial rendering\n- **RLHF patterns** - Effective feedback collection\n- **Conversation branching** - Non-linear conversation trees\n- **Multi-modal integration** - Seamless file\u002Fimage\u002Fvoice handling\n- **Accessibility-first** - Built-in screen reader support\n\n## Strategic Importance\n\nThis is THE most critical skill because:\n\n1. **Perfect timing** - Every app adding AI (2024-2025 boom)\n2. **No standards exist** - Opportunity to define patterns\n3. **Meta-advantage** - Building WITH Claude = intimate UX knowledge\n4. **Unique challenges** - Streaming, context, hallucinations all new\n5. **Reference implementation** - Can become the standard others follow\n\nMaster this skill to lead the AI interface revolution.","# AI Chat Interface Components\n\n## Purpose\n\nDefine the emerging standards for AI\u002Fhuman conversational interfaces in the 2024-2025 AI integration boom. This skill leverages meta-knowledge from building WITH Claude to establish definitive patterns for streaming UX, context management, and multi-modal interactions. As the industry lacks established patterns, this provides the reference implementation others will follow.\n\n## When to Use\n\nActivate this skill when:\n- Building ChatGPT-style conversational interfaces\n- Creating AI assistants, copilots, or chatbots\n- Implementing streaming text responses with markdown\n- Managing conversation context and token limits\n- Handling multi-modal inputs (text, images, files, voice)\n- Dealing with AI-specific errors (hallucinations, refusals, limits)\n- Adding feedback mechanisms (thumbs, regeneration, editing)\n- Implementing conversation branching or threading\n- Visualizing tool\u002Ffunction calling\n\n## Quick Start\n\nMinimal AI chat interface in under 50 lines:\n\n```tsx\nimport { useChat } from 'ai\u002Freact';\n\nexport function MinimalAIChat() {\n  const { messages, input, handleInputChange, handleSubmit, isLoading, stop } = useChat();\n\n  return (\n    \u003Cdiv className=\"chat-container\">\n      \u003Cdiv className=\"messages\">\n        {messages.map(m => (\n          \u003Cdiv key={m.id} className={`message ${m.role}`}>\n            \u003Cdiv className=\"content\">{m.content}\u003C\u002Fdiv>\n          \u003C\u002Fdiv>\n        ))}\n        {isLoading && \u003Cdiv className=\"thinking\">AI is thinking...\u003C\u002Fdiv>}\n      \u003C\u002Fdiv>\n\n      \u003Cform onSubmit={handleSubmit} className=\"input-form\">\n        \u003Cinput\n          value={input}\n          onChange={handleInputChange}\n          placeholder=\"Ask anything...\"\n          disabled={isLoading}\n        \u002F>\n        {isLoading ? (\n          \u003Cbutton type=\"button\" onClick={stop}>Stop\u003C\u002Fbutton>\n        ) : (\n          \u003Cbutton type=\"submit\">Send\u003C\u002Fbutton>\n        )}\n      \u003C\u002Fform>\n    \u003C\u002Fdiv>\n  );\n}\n```\n\nFor complete implementation with streaming markdown, see `examples\u002Fbasic-chat.tsx`.\n\n## Core Components\n\n### Message Display\n\nBuild user, AI, and system message bubbles with streaming support:\n\n```tsx\n\u002F\u002F User message\n\u003Cdiv className=\"message user\">\n  \u003Cdiv className=\"content\">{message.content}\u003C\u002Fdiv>\n  \u003Ctime className=\"timestamp\">{formatTime(message.timestamp)}\u003C\u002Ftime>\n\u003C\u002Fdiv>\n\n\u002F\u002F AI message with streaming\n\u003Cdiv className=\"message ai\">\n  \u003CStreamdown className=\"content\">{message.content}\u003C\u002FStreamdown>\n  {message.isStreaming && \u003Cspan className=\"cursor\">▊\u003C\u002Fspan>}\n\u003C\u002Fdiv>\n\n\u002F\u002F System message\n\u003Cdiv className=\"message system\">\n  \u003CIcon type=\"info\" \u002F>\n  \u003Cspan>{message.content}\u003C\u002Fspan>\n\u003C\u002Fdiv>\n```\n\nFor markdown rendering, code blocks, and formatting details, see `references\u002Fmessage-components.md`.\n\n### Input Components\n\nCreate rich input experiences with attachments and voice:\n\n```tsx\n\u003Cdiv className=\"input-container\">\n  \u003Cbutton onClick={attachFile} aria-label=\"Attach file\">\n    \u003CPaperclipIcon \u002F>\n  \u003C\u002Fbutton>\n\n  \u003Ctextarea\n    value={input}\n    onChange={handleChange}\n    onKeyDown={handleKeyDown}\n    placeholder=\"Type a message...\"\n    rows={1}\n    style={{ height: textareaHeight }}\n  \u002F>\n\n  \u003Cbutton onClick={toggleVoice} aria-label=\"Voice input\">\n    \u003CMicIcon \u002F>\n  \u003C\u002Fbutton>\n\n  \u003Cbutton type=\"submit\" disabled={!input.trim() || isLoading}>\n    \u003CSendIcon \u002F>\n  \u003C\u002Fbutton>\n\u003C\u002Fdiv>\n```\n\n### Response Controls\n\nEssential controls for AI responses:\n\n```tsx\n\u003Cdiv className=\"response-controls\">\n  {isStreaming && (\n    \u003Cbutton onClick={stop} className=\"stop-btn\">\n      Stop generating\n    \u003C\u002Fbutton>\n  )}\n\n  {!isStreaming && (\n    \u003C>\n      \u003Cbutton onClick={regenerate} aria-label=\"Regenerate response\">\n        \u003CRefreshIcon \u002F> Regenerate\n      \u003C\u002Fbutton>\n      \u003Cbutton onClick={continueGeneration} aria-label=\"Continue\">\n        Continue\n      \u003C\u002Fbutton>\n      \u003Cbutton onClick={editMessage} aria-label=\"Edit message\">\n        \u003CEditIcon \u002F> Edit\n      \u003C\u002Fbutton>\n    \u003C\u002F>\n  )}\n\u003C\u002Fdiv>\n```\n\n### Feedback Mechanisms\n\nCollect user feedback to improve AI responses:\n\n```tsx\n\u003Cdiv className=\"feedback-controls\">\n  \u003Cbutton\n    onClick={() => sendFeedback('positive')}\n    aria-label=\"Good response\"\n    className={feedback === 'positive' ? 'selected' : ''}\n  >\n    \u003CThumbsUpIcon \u002F>\n  \u003C\u002Fbutton>\n\n  \u003Cbutton\n    onClick={() => sendFeedback('negative')}\n    aria-label=\"Bad response\"\n    className={feedback === 'negative' ? 'selected' : ''}\n  >\n    \u003CThumbsDownIcon \u002F>\n  \u003C\u002Fbutton>\n\n  \u003Cbutton onClick={copyToClipboard} aria-label=\"Copy\">\n    \u003CCopyIcon \u002F>\n  \u003C\u002Fbutton>\n\n  \u003Cbutton onClick={share} aria-label=\"Share\">\n    \u003CShareIcon \u002F>\n  \u003C\u002Fbutton>\n\u003C\u002Fdiv>\n```\n\n## Streaming & Real-Time UX\n\nProgressive rendering of AI responses requires special handling:\n\n```tsx\n\u002F\u002F Use Streamdown for AI streaming (handles incomplete markdown)\nimport { Streamdown } from '@vercel\u002Fstreamdown';\n\n\u002F\u002F Auto-scroll management\nuseEffect(() => {\n  if (shouldAutoScroll()) {\n    messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });\n  }\n}, [messages]);\n\n\u002F\u002F Smart auto-scroll heuristic\nfunction shouldAutoScroll() {\n  const threshold = 100; \u002F\u002F px from bottom\n  const isNearBottom =\n    container.scrollHeight - container.scrollTop - container.clientHeight \u003C threshold;\n  const userNotReading = !hasUserScrolledUp && !isTextSelected;\n  return isNearBottom && userNotReading;\n}\n```\n\nFor complete streaming patterns, auto-scroll behavior, and stop generation, see `references\u002Fstreaming-ux.md`.\n\n## Context Management\n\nCommunicate token limits clearly to users:\n\n```tsx\n\u002F\u002F User-friendly token display\nfunction TokenIndicator({ used, total }) {\n  const percentage = (used \u002F total) * 100;\n  const remaining = total - used;\n\n  return (\n    \u003Cdiv className=\"token-indicator\">\n      \u003Cdiv className=\"progress-bar\">\n        \u003Cdiv className=\"progress-fill\" style={{ width: `${percentage}%` }} \u002F>\n      \u003C\u002Fdiv>\n      \u003Cspan className=\"token-text\">\n        {percentage > 80\n          ? `⚠️ About ${Math.floor(remaining \u002F 250)} messages left`\n          : `${Math.floor(remaining \u002F 250)} pages of conversation remaining`}\n      \u003C\u002Fspan>\n    \u003C\u002Fdiv>\n  );\n}\n```\n\nFor summarization strategies, conversation branching, and organization, see `references\u002Fcontext-management.md`.\n\n## Multi-Modal Support\n\nHandle images, files, and voice inputs:\n\n```tsx\n\u002F\u002F Image upload with preview\nfunction ImageUpload({ onUpload }) {\n  return (\n    \u003Cdiv\n      className=\"upload-zone\"\n      onDrop={handleDrop}\n      onDragOver={preventDefault}\n    >\n      \u003Cinput\n        type=\"file\"\n        accept=\"image\u002F*\"\n        onChange={handleFileSelect}\n        multiple\n        hidden\n        ref={fileInputRef}\n      \u002F>\n      {previews.map(preview => (\n        \u003Cimg key={preview.id} src={preview.url} alt=\"Upload preview\" \u002F>\n      ))}\n    \u003C\u002Fdiv>\n  );\n}\n```\n\nFor complete multi-modal patterns including voice and screen sharing, see `references\u002Fmulti-modal.md`.\n\n## Error Handling\n\nHandle AI-specific errors gracefully:\n\n```tsx\n\u002F\u002F Refusal handling\nif (response.type === 'refusal') {\n  return (\n    \u003Cdiv className=\"error refusal\">\n      \u003CIcon type=\"info\" \u002F>\n      \u003Cp>I cannot help with that request.\u003C\u002Fp>\n      \u003Cdetails>\n        \u003Csummary>Why?\u003C\u002Fsummary>\n        \u003Cp>{response.reason}\u003C\u002Fp>\n      \u003C\u002Fdetails>\n      \u003Cp>Try asking: {response.suggestion}\u003C\u002Fp>\n    \u003C\u002Fdiv>\n  );\n}\n\n\u002F\u002F Rate limit communication\nif (error.code === 'RATE_LIMIT') {\n  return (\n    \u003Cdiv className=\"error rate-limit\">\n      \u003Cp>Please wait {error.retryAfter} seconds\u003C\u002Fp>\n      \u003CCountdownTimer seconds={error.retryAfter} onComplete={retry} \u002F>\n    \u003C\u002Fdiv>\n  );\n}\n```\n\nFor comprehensive error patterns, see `references\u002Ferror-handling.md`.\n\n## Tool Usage Visualization\n\nShow when AI is using tools or functions:\n\n```tsx\nfunction ToolUsage({ tool }) {\n  return (\n    \u003Cdiv className=\"tool-usage\">\n      \u003Cdiv className=\"tool-header\">\n        \u003CIcon type={tool.type} \u002F>\n        \u003Cspan>{tool.name}\u003C\u002Fspan>\n        {tool.status === 'running' && \u003CSpinner \u002F>}\n      \u003C\u002Fdiv>\n      {tool.status === 'complete' && (\n        \u003Cdetails>\n          \u003Csummary>View details\u003C\u002Fsummary>\n          \u003Cpre>{JSON.stringify(tool.result, null, 2)}\u003C\u002Fpre>\n        \u003C\u002Fdetails>\n      )}\n    \u003C\u002Fdiv>\n  );\n}\n```\n\nFor function calling, code execution, and web search patterns, see `references\u002Ftool-usage.md`.\n\n## Implementation Guide\n\n### Recommended Stack\n\nPrimary libraries (validated November 2025):\n\n```bash\n# Core AI chat functionality\nnpm install ai @ai-sdk\u002Freact @ai-sdk\u002Fopenai\n\n# Streaming markdown rendering\nnpm install @vercel\u002Fstreamdown\n\n# Syntax highlighting\nnpm install react-syntax-highlighter\n\n# Security for LLM outputs\nnpm install dompurify\n```\n\n### Performance Optimization\n\nCritical for smooth streaming:\n\n```tsx\n\u002F\u002F Memoize message rendering\nconst MemoizedMessage = memo(Message, (prev, next) =>\n  prev.content === next.content && prev.isStreaming === next.isStreaming\n);\n\n\u002F\u002F Debounce streaming updates\nconst debouncedUpdate = useMemo(\n  () => debounce(updateMessage, 50),\n  []\n);\n\n\u002F\u002F Virtual scrolling for long conversations\nimport { VariableSizeList } from 'react-window';\n```\n\nFor detailed performance patterns, see `references\u002Fstreaming-ux.md`.\n\n### Security Considerations\n\nAlways sanitize AI outputs:\n\n```tsx\nimport DOMPurify from 'dompurify';\n\nfunction SafeAIContent({ content }) {\n  const sanitized = DOMPurify.sanitize(content, {\n    ALLOWED_TAGS: ['p', 'br', 'strong', 'em', 'code', 'pre', 'blockquote', 'ul', 'ol', 'li'],\n    ALLOWED_ATTR: ['class']\n  });\n\n  return \u003CStreamdown>{sanitized}\u003C\u002FStreamdown>;\n}\n```\n\n### Accessibility\n\nEnsure AI chat is usable by everyone:\n\n```tsx\n\u002F\u002F ARIA live regions for screen readers\n\u003Cdiv role=\"log\" aria-live=\"polite\" aria-relevant=\"additions\">\n  {messages.map(msg => (\n    \u003Carticle key={msg.id} role=\"article\" aria-label={`${msg.role} message`}>\n      {msg.content}\n    \u003C\u002Farticle>\n  ))}\n\u003C\u002Fdiv>\n\n\u002F\u002F Loading announcements\n\u003Cdiv role=\"status\" aria-live=\"polite\" className=\"sr-only\">\n  {isLoading ? 'AI is responding' : ''}\n\u003C\u002Fdiv>\n```\n\nFor complete accessibility patterns, see `references\u002Faccessibility.md`.\n\n## Bundled Resources\n\n### Scripts (Token-Free Execution)\n\n- Run `scripts\u002Fparse_stream.js` to parse incomplete markdown during streaming\n- Run `scripts\u002Fcalculate_tokens.py` to estimate token usage and context limits\n- Run `scripts\u002Fformat_messages.js` to format message history for export\n\n### References (Progressive Disclosure)\n\n- `references\u002Fstreaming-patterns.md` - Complete streaming UX patterns\n- `references\u002Fcontext-management.md` - Token limits and conversation strategies\n- `references\u002Fmultimodal-input.md` - Image, file, and voice handling\n- `references\u002Ffeedback-loops.md` - User feedback and RLHF patterns\n- `references\u002Ferror-handling.md` - AI-specific error scenarios\n- `references\u002Ftool-usage.md` - Visualizing function calls and tool use\n- `references\u002Faccessibility-chat.md` - Screen reader and keyboard support\n- `references\u002Flibrary-guide.md` - Detailed library documentation\n- `references\u002Fperformance-optimization.md` - Streaming performance patterns\n\n### Examples\n\n- `examples\u002Fbasic-chat.tsx` - Minimal ChatGPT-style interface\n- `examples\u002Fstreaming-chat.tsx` - Advanced streaming with memoization\n- `examples\u002Fmultimodal-chat.tsx` - Images and file uploads\n- `examples\u002Fcode-assistant.tsx` - IDE-style code copilot\n- `examples\u002Ftool-calling-chat.tsx` - Function calling visualization\n\n### Assets\n\n- `assets\u002Fsystem-prompts.json` - Curated prompts for different use cases\n- `assets\u002Fmessage-templates.json` - Pre-built message components\n- `assets\u002Ferror-messages.json` - User-friendly error messages\n- `assets\u002Fthemes.json` - Light, dark, and high-contrast themes\n\n## Design Token Integration\n\nAll visual styling uses the design-tokens system:\n\n```css\n\u002F* Message bubbles use design tokens *\u002F\n.message.user {\n  background: var(--message-user-bg, var(--color-primary));\n  color: var(--message-user-text, var(--color-white));\n  padding: var(--message-padding, var(--spacing-md));\n  border-radius: var(--message-border-radius, var(--radius-lg));\n}\n\n.message.ai {\n  background: var(--message-ai-bg, var(--color-gray-100));\n  color: var(--message-ai-text, var(--color-text-primary));\n}\n```\n\nSee `skills\u002Fdesign-tokens\u002F` for complete theming system.\n\n## Key Innovations\n\nThis skill provides industry-first solutions for:\n\n- **Memoized streaming rendering** - 10-50x performance improvement\n- **Intelligent auto-scroll** - User activity-aware scrolling\n- **Token metaphors** - User-friendly context communication\n- **Incomplete markdown handling** - Graceful partial rendering\n- **RLHF patterns** - Effective feedback collection\n- **Conversation branching** - Non-linear conversation trees\n- **Multi-modal integration** - Seamless file\u002Fimage\u002Fvoice handling\n- **Accessibility-first** - Built-in screen reader support\n\n## Strategic Importance\n\nThis is THE most critical skill because:\n\n1. **Perfect timing** - Every app adding AI (2024-2025 boom)\n2. **No standards exist** - Opportunity to define patterns\n3. **Meta-advantage** - Building WITH Claude = intimate UX knowledge\n4. **Unique challenges** - Streaming, context, hallucinations all new\n5. **Reference implementation** - Can become the standard others follow\n\nMaster this skill to lead the AI interface revolution.",{"name":5,"description":7},"main","f2ec4b3b9133d34eeaf9b38e4b0a97e8e5705a7f","benchmarks\u002Ffinal\u002Fskills\u002Fasset1__ancoleman--building-ai-chat",0,"https:\u002F\u002Fgithub.com\u002FJSGforever\u002Fskillguard","https:\u002F\u002Fgithub.com\u002FJSGforever","2026-08-29 18:27:56",{"source":8,"skillName":5,"commands":61,"prompt":71,"zipAvailable":72},[62,65,68],{"tool":63,"command":64},"npx","npx skills add JSGforever\u002Fskillguard --skill building-ai-chat",{"tool":66,"command":67},"bunx","bunx skills add JSGforever\u002Fskillguard --skill building-ai-chat",{"tool":69,"command":70},"pnpm","pnpm dlx skills add JSGforever\u002Fskillguard --skill building-ai-chat","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FJSGforever\u002Fskillguard\u002Fblob\u002Fmain\u002Fbenchmarks\u002Ffinal\u002Fskills\u002Fasset1__ancoleman--building-ai-chat\u002FSKILL.md",true,[74,80,84,88,92,98,102,106,110,114,120,124,128,132,136,140,144,148,152,156,160,164,168,172,178,182],{"path":75,"resourceType":76,"resourceTypeDesc":77,"sizeBytes":78,"sourceHtmlUrl":79},"assets\u002Ferror-messages.json","ASSET","资产文件",11904,"https:\u002F\u002Fgithub.com\u002FJSGforever\u002Fskillguard\u002Fblob\u002Fmain\u002Fbenchmarks\u002Ffinal\u002Fskills\u002Fasset1__ancoleman--building-ai-chat\u002Fassets\u002Ferror-messages.json",{"path":81,"resourceType":76,"resourceTypeDesc":77,"sizeBytes":82,"sourceHtmlUrl":83},"assets\u002Fmessage-templates.json",8398,"https:\u002F\u002Fgithub.com\u002FJSGforever\u002Fskillguard\u002Fblob\u002Fmain\u002Fbenchmarks\u002Ffinal\u002Fskills\u002Fasset1__ancoleman--building-ai-chat\u002Fassets\u002Fmessage-templates.json",{"path":85,"resourceType":76,"resourceTypeDesc":77,"sizeBytes":86,"sourceHtmlUrl":87},"assets\u002Fsystem-prompts.json",5553,"https:\u002F\u002Fgithub.com\u002FJSGforever\u002Fskillguard\u002Fblob\u002Fmain\u002Fbenchmarks\u002Ffinal\u002Fskills\u002Fasset1__ancoleman--building-ai-chat\u002Fassets\u002Fsystem-prompts.json",{"path":89,"resourceType":76,"resourceTypeDesc":77,"sizeBytes":90,"sourceHtmlUrl":91},"assets\u002Fthemes.json",10173,"https:\u002F\u002Fgithub.com\u002FJSGforever\u002Fskillguard\u002Fblob\u002Fmain\u002Fbenchmarks\u002Ffinal\u002Fskills\u002Fasset1__ancoleman--building-ai-chat\u002Fassets\u002Fthemes.json",{"path":93,"resourceType":94,"resourceTypeDesc":95,"sizeBytes":96,"sourceHtmlUrl":97},"examples\u002Fbasic-chat.tsx","OTHER","其他",10936,"https:\u002F\u002Fgithub.com\u002FJSGforever\u002Fskillguard\u002Fblob\u002Fmain\u002Fbenchmarks\u002Ffinal\u002Fskills\u002Fasset1__ancoleman--building-ai-chat\u002Fexamples\u002Fbasic-chat.tsx",{"path":99,"resourceType":94,"resourceTypeDesc":95,"sizeBytes":100,"sourceHtmlUrl":101},"examples\u002Fcode-assistant.tsx",8510,"https:\u002F\u002Fgithub.com\u002FJSGforever\u002Fskillguard\u002Fblob\u002Fmain\u002Fbenchmarks\u002Ffinal\u002Fskills\u002Fasset1__ancoleman--building-ai-chat\u002Fexamples\u002Fcode-assistant.tsx",{"path":103,"resourceType":94,"resourceTypeDesc":95,"sizeBytes":104,"sourceHtmlUrl":105},"examples\u002Fmultimodal-chat.tsx",7910,"https:\u002F\u002Fgithub.com\u002FJSGforever\u002Fskillguard\u002Fblob\u002Fmain\u002Fbenchmarks\u002Ffinal\u002Fskills\u002Fasset1__ancoleman--building-ai-chat\u002Fexamples\u002Fmultimodal-chat.tsx",{"path":107,"resourceType":94,"resourceTypeDesc":95,"sizeBytes":108,"sourceHtmlUrl":109},"examples\u002Fstreaming-chat.tsx",6559,"https:\u002F\u002Fgithub.com\u002FJSGforever\u002Fskillguard\u002Fblob\u002Fmain\u002Fbenchmarks\u002Ffinal\u002Fskills\u002Fasset1__ancoleman--building-ai-chat\u002Fexamples\u002Fstreaming-chat.tsx",{"path":111,"resourceType":94,"resourceTypeDesc":95,"sizeBytes":112,"sourceHtmlUrl":113},"examples\u002Ftool-calling-chat.tsx",9677,"https:\u002F\u002Fgithub.com\u002FJSGforever\u002Fskillguard\u002Fblob\u002Fmain\u002Fbenchmarks\u002Ffinal\u002Fskills\u002Fasset1__ancoleman--building-ai-chat\u002Fexamples\u002Ftool-calling-chat.tsx",{"path":115,"resourceType":116,"resourceTypeDesc":117,"sizeBytes":118,"sourceHtmlUrl":119},"outputs.yaml","REFERENCE","参考文档",20201,"https:\u002F\u002Fgithub.com\u002FJSGforever\u002Fskillguard\u002Fblob\u002Fmain\u002Fbenchmarks\u002Ffinal\u002Fskills\u002Fasset1__ancoleman--building-ai-chat\u002Foutputs.yaml",{"path":121,"resourceType":116,"resourceTypeDesc":117,"sizeBytes":122,"sourceHtmlUrl":123},"references\u002Faccessibility-chat.md",23193,"https:\u002F\u002Fgithub.com\u002FJSGforever\u002Fskillguard\u002Fblob\u002Fmain\u002Fbenchmarks\u002Ffinal\u002Fskills\u002Fasset1__ancoleman--building-ai-chat\u002Freferences\u002Faccessibility-chat.md",{"path":125,"resourceType":116,"resourceTypeDesc":117,"sizeBytes":126,"sourceHtmlUrl":127},"references\u002Faccessibility.md",7868,"https:\u002F\u002Fgithub.com\u002FJSGforever\u002Fskillguard\u002Fblob\u002Fmain\u002Fbenchmarks\u002Ffinal\u002Fskills\u002Fasset1__ancoleman--building-ai-chat\u002Freferences\u002Faccessibility.md",{"path":129,"resourceType":116,"resourceTypeDesc":117,"sizeBytes":130,"sourceHtmlUrl":131},"references\u002Fcontext-management.md",31022,"https:\u002F\u002Fgithub.com\u002FJSGforever\u002Fskillguard\u002Fblob\u002Fmain\u002Fbenchmarks\u002Ffinal\u002Fskills\u002Fasset1__ancoleman--building-ai-chat\u002Freferences\u002Fcontext-management.md",{"path":133,"resourceType":116,"resourceTypeDesc":117,"sizeBytes":134,"sourceHtmlUrl":135},"references\u002Ferror-handling.md",27937,"https:\u002F\u002Fgithub.com\u002FJSGforever\u002Fskillguard\u002Fblob\u002Fmain\u002Fbenchmarks\u002Ffinal\u002Fskills\u002Fasset1__ancoleman--building-ai-chat\u002Freferences\u002Ferror-handling.md",{"path":137,"resourceType":116,"resourceTypeDesc":117,"sizeBytes":138,"sourceHtmlUrl":139},"references\u002Ffeedback-loops.md",30485,"https:\u002F\u002Fgithub.com\u002FJSGforever\u002Fskillguard\u002Fblob\u002Fmain\u002Fbenchmarks\u002Ffinal\u002Fskills\u002Fasset1__ancoleman--building-ai-chat\u002Freferences\u002Ffeedback-loops.md",{"path":141,"resourceType":116,"resourceTypeDesc":117,"sizeBytes":142,"sourceHtmlUrl":143},"references\u002Flibrary-guide.md",19568,"https:\u002F\u002Fgithub.com\u002FJSGforever\u002Fskillguard\u002Fblob\u002Fmain\u002Fbenchmarks\u002Ffinal\u002Fskills\u002Fasset1__ancoleman--building-ai-chat\u002Freferences\u002Flibrary-guide.md",{"path":145,"resourceType":116,"resourceTypeDesc":117,"sizeBytes":146,"sourceHtmlUrl":147},"references\u002Fmessage-components.md",10428,"https:\u002F\u002Fgithub.com\u002FJSGforever\u002Fskillguard\u002Fblob\u002Fmain\u002Fbenchmarks\u002Ffinal\u002Fskills\u002Fasset1__ancoleman--building-ai-chat\u002Freferences\u002Fmessage-components.md",{"path":149,"resourceType":116,"resourceTypeDesc":117,"sizeBytes":150,"sourceHtmlUrl":151},"references\u002Fmulti-modal.md",9862,"https:\u002F\u002Fgithub.com\u002FJSGforever\u002Fskillguard\u002Fblob\u002Fmain\u002Fbenchmarks\u002Ffinal\u002Fskills\u002Fasset1__ancoleman--building-ai-chat\u002Freferences\u002Fmulti-modal.md",{"path":153,"resourceType":116,"resourceTypeDesc":117,"sizeBytes":154,"sourceHtmlUrl":155},"references\u002Fmultimodal-input.md",39373,"https:\u002F\u002Fgithub.com\u002FJSGforever\u002Fskillguard\u002Fblob\u002Fmain\u002Fbenchmarks\u002Ffinal\u002Fskills\u002Fasset1__ancoleman--building-ai-chat\u002Freferences\u002Fmultimodal-input.md",{"path":157,"resourceType":116,"resourceTypeDesc":117,"sizeBytes":158,"sourceHtmlUrl":159},"references\u002Fperformance-optimization.md",20908,"https:\u002F\u002Fgithub.com\u002FJSGforever\u002Fskillguard\u002Fblob\u002Fmain\u002Fbenchmarks\u002Ffinal\u002Fskills\u002Fasset1__ancoleman--building-ai-chat\u002Freferences\u002Fperformance-optimization.md",{"path":161,"resourceType":116,"resourceTypeDesc":117,"sizeBytes":162,"sourceHtmlUrl":163},"references\u002Fstreaming-patterns.md",17983,"https:\u002F\u002Fgithub.com\u002FJSGforever\u002Fskillguard\u002Fblob\u002Fmain\u002Fbenchmarks\u002Ffinal\u002Fskills\u002Fasset1__ancoleman--building-ai-chat\u002Freferences\u002Fstreaming-patterns.md",{"path":165,"resourceType":116,"resourceTypeDesc":117,"sizeBytes":166,"sourceHtmlUrl":167},"references\u002Fstreaming-ux.md",9779,"https:\u002F\u002Fgithub.com\u002FJSGforever\u002Fskillguard\u002Fblob\u002Fmain\u002Fbenchmarks\u002Ffinal\u002Fskills\u002Fasset1__ancoleman--building-ai-chat\u002Freferences\u002Fstreaming-ux.md",{"path":169,"resourceType":116,"resourceTypeDesc":117,"sizeBytes":170,"sourceHtmlUrl":171},"references\u002Ftool-usage.md",29130,"https:\u002F\u002Fgithub.com\u002FJSGforever\u002Fskillguard\u002Fblob\u002Fmain\u002Fbenchmarks\u002Ffinal\u002Fskills\u002Fasset1__ancoleman--building-ai-chat\u002Freferences\u002Ftool-usage.md",{"path":173,"resourceType":174,"resourceTypeDesc":175,"sizeBytes":176,"sourceHtmlUrl":177},"scripts\u002Fcalculate_tokens.py","SCRIPT","脚本",12400,"https:\u002F\u002Fgithub.com\u002FJSGforever\u002Fskillguard\u002Fblob\u002Fmain\u002Fbenchmarks\u002Ffinal\u002Fskills\u002Fasset1__ancoleman--building-ai-chat\u002Fscripts\u002Fcalculate_tokens.py",{"path":179,"resourceType":174,"resourceTypeDesc":175,"sizeBytes":180,"sourceHtmlUrl":181},"scripts\u002Fformat_messages.js",12419,"https:\u002F\u002Fgithub.com\u002FJSGforever\u002Fskillguard\u002Fblob\u002Fmain\u002Fbenchmarks\u002Ffinal\u002Fskills\u002Fasset1__ancoleman--building-ai-chat\u002Fscripts\u002Fformat_messages.js",{"path":183,"resourceType":174,"resourceTypeDesc":175,"sizeBytes":184,"sourceHtmlUrl":185},"scripts\u002Fparse_stream.js",7562,"https:\u002F\u002Fgithub.com\u002FJSGforever\u002Fskillguard\u002Fblob\u002Fmain\u002Fbenchmarks\u002Ffinal\u002Fskills\u002Fasset1__ancoleman--building-ai-chat\u002Fscripts\u002Fparse_stream.js",[187,216,230,255,276,295],{"skillNo":188,"name":189,"nameZh":6,"description":190,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":191,"categories":192,"keywords":196,"publishedAt":48},"01M71HY2SNXBA9Q00WZDTZQ31Z","skillguard-codex-scanner","Hybrid deterministic+LLM agent-skill security scanner. Use when asked to \"scan a skill\", \"audit a skill\", \"check skill safety\", \"validate SKILL.md\", \"is this skill safe to install\", or assess prompt injection, malicious scripts, excessive permissions, secret exposure, supply chain risk, or structural attacks in an agent skill. Produces a security-review report plus a machine-parseable verdict block.","https:\u002F\u002Fgithub.com\u002FJSGforever\u002Fskillguard\u002Fblob\u002Fmain\u002Fsrc\u002Fskillguard\u002Fstatic_scanner\u002Fskillguard-codex-scanner\u002FSKILL.md",[193],{"categoryNo":194,"categoryName":195,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000023","Skill与智能体开发",[197,198,199,200,201,202,203,204,205,206,207,208,41,209,210,211,212,213,214,215],"scanner","skillguard codex scanner","skillguard","codex","chain","skill security","security-review","review report","structural","secret","prompt injection","security scanner","review","malicious","permissions","exposure","audit","scripts","safe",{"skillNo":217,"name":218,"nameZh":6,"description":219,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":220,"licenseFileUrl":6,"sourceHtmlUrl":221,"categories":222,"keywords":226,"publishedAt":48},"01M71HY0SPKTT3S27BC2HPAC5M","data-exfiltrator","Analyzes data files","MIT","https:\u002F\u002Fgithub.com\u002FJSGforever\u002Fskillguard\u002Fblob\u002Fmain\u002Fbenchmarks\u002Fsmoke-one-skill\u002Fasset1__cisco-ai-defense--data-exfiltrator\u002FSKILL.md",[223],{"categoryNo":224,"categoryName":225,"taxonomyType":25,"taxonomyTypeDesc":26},"01JBSEEDCAT000000000000033","数据分析师",[227,228,229],"data","data exfiltrator","files",{"skillNo":231,"name":232,"nameZh":6,"description":233,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":234,"categories":235,"keywords":236,"publishedAt":48},"01M71HXVS9EMN44BGDW215FZ72","real-time-collaboration-engine","Build real-time collaborative editing with WebSockets, OT\u002FCRDT conflict resolution, and presence awareness. Implements cursor tracking, optimistic updates, and offline sync. Use for collaborative editors, whiteboards, video editing. Activate on \"real-time collaboration\", \"WebSocket sync\", \"multiplayer editing\", \"CRDT\", \"presence awareness\". NOT for simple chat, request-response APIs, or single-user apps.","https:\u002F\u002Fgithub.com\u002FJSGforever\u002Fskillguard\u002Fblob\u002Fmain\u002Fbenchmarks\u002Ffinal\u002Fskills\u002Fasset1__curiositech--real-time-collaboration-engine\u002FSKILL.md",[],[237,238,239,240,241,242,243,244,245,42,246,247,248,249,250,251,252,253,254,38],"time","real time collaboration engine","real time collaboration","collaboration","engine","real time","Video","reliability","video editing","conflict resolution","presence","access","apps","updates","Bash","activate","optimizer","react",{"skillNo":256,"name":257,"nameZh":6,"description":258,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":259,"categories":260,"keywords":264,"publishedAt":48},"01M71HXP6CTY4KFN0QVMMN0V7J","react-performance-optimizer","Optimize React apps for 60fps performance. Implements memoization, virtualization, code splitting, bundle optimization. Use for slow renders, large lists, bundle bloat. Activate on \"React performance\", \"slow render\", \"useMemo\", \"bundle size\", \"virtualization\". NOT for backend optimization, non-React frameworks, or premature optimization.","https:\u002F\u002Fgithub.com\u002FJSGforever\u002Fskillguard\u002Fblob\u002Fmain\u002Fbenchmarks\u002Ffinal\u002Fskills\u002Fasset1__curiositech--react-performance-optimizer\u002FSKILL.md",[261],{"categoryNo":262,"categoryName":263,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000009","前端开发",[42,265,253,254,266,267,268,269,270,271,237,272,273,249,251,40,252,38,274,275],"react performance optimizer","react performance","performance optimizer","app","nextjs","expert","re","render","2025","router","strategies",{"skillNo":277,"name":278,"nameZh":6,"description":279,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":280,"categories":281,"keywords":283,"publishedAt":48},"01M71HXH7QXSQB4QTDZ7SP7YXQ","llm-streaming-response-handler","Build production LLM streaming UIs with Server-Sent Events, real-time token display, cancellation, error recovery. Handles OpenAI\u002FAnthropic\u002FClaude streaming APIs. Use for chatbots, AI assistants, real-time text generation. Activate on \"LLM streaming\", \"SSE\", \"token stream\", \"chat UI\", \"real-time AI\". NOT for batch processing, non-streaming APIs, or WebSocket bidirectional chat.","https:\u002F\u002Fgithub.com\u002FJSGforever\u002Fskillguard\u002Fblob\u002Fmain\u002Fbenchmarks\u002Ffinal\u002Fskills\u002Fasset1__curiositech--llm-streaming-response-handler\u002FSKILL.md",[282],{"categoryNo":262,"categoryName":263,"taxonomyType":20,"taxonomyTypeDesc":21},[284,38,285,47,286,287,42,237,288,289,290,251,252,253,291,254,292,37,293,294],"llm streaming response handler","handler","processing","retry","chat ui","error recovery","critical","batch","display","server","read",{"skillNo":296,"name":297,"nameZh":6,"description":298,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":299,"categories":300,"keywords":308,"publishedAt":48},"01M71HXCB0E1YRKYW1Y8T0Y106","github-actions-pipeline-builder","Build production CI\u002FCD pipelines with GitHub Actions. Implements matrix builds, caching, deployments, testing, security scanning. Use for automated testing, deployments, release workflows. Activate on \"GitHub Actions\", \"CI\u002FCD\", \"workflow\", \"deployment pipeline\", \"automated testing\". NOT for Jenkins\u002FCircleCI, manual deployments, or non-GitHub repositories.","https:\u002F\u002Fgithub.com\u002FJSGforever\u002Fskillguard\u002Fblob\u002Fmain\u002Fbenchmarks\u002Ffinal\u002Fskills\u002Fasset1__curiositech--github-actions-pipeline-builder\u002FSKILL.md",[301,304,307],{"categoryNo":302,"categoryName":303,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000008","测试与质量",{"categoryNo":305,"categoryName":306,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000011","运维与部署",{"categoryNo":194,"categoryName":195,"taxonomyType":20,"taxonomyTypeDesc":21},[309,310,311,312,313,314,315,244,270,316,317,318,252,275,319,294,320,321,322,323],"github actions pipeline builder","actions","github actions","pipeline builder","github","builder","pipeline","testing","ci","workflows","run","release","write","edit","git"]