[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M71V8GA53EWDYMKDCE95JN9M":3,"skill-same:01M71V8GA53EWDYMKDCE95JN9M":84},{"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":22,"publishedAt":40,"linkOnly":41,"markdownContent":42,"markdownBody":43,"frontMatter":44,"refName":46,"commitSha":47,"skillDirectory":48,"forksCount":49,"repositoryHtmlUrl":50,"repositoryHomepageUrl":51,"ownerHtmlUrl":52,"ownerBlogUrl":53,"ownerDescription":54,"updatedAt":55,"install":56,"resources":69},"01M71V8GA53EWDYMKDCE95JN9M","tools",null,"Guide for tool registration and tool UI in assistant-ui. Use when implementing LLM tools, tool call rendering, or human-in-the-loop patterns.","AkaraChen\u002Fangel-engine","AkaraChen","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F85140972?v=4","01M6E197RY34TPAFK03227R387","01M71V2QPZM89DQ8R1AB7021P4",19,"MIT","https:\u002F\u002Fgithub.com\u002FAkaraChen\u002Fangel-engine\u002Fblob\u002Fmaster\u002F.claude\u002Fskills\u002Ftools\u002FSKILL.md",[17],{"categoryNo":18,"categoryName":19,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000010","后端与接口","SCENARIO","使用场景",[23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39],"Tools","registration","when","for","implementing","rendering","human","llm tools","call","patterns","assistant","use","guide","tool","loop","human-in-the-loop","ui","2026-11-10 13:02:02",false,"---\nname: tools\ndescription: Guide for tool registration and tool UI in assistant-ui. Use when implementing LLM tools, tool call rendering, or human-in-the-loop patterns.\nversion: 0.0.1\nlicense: MIT\n---\n\n# assistant-ui Tools\n\n**Always consult [assistant-ui.com\u002Fllms.txt](https:\u002F\u002Fassistant-ui.com\u002Fllms.txt) for latest API.**\n\nTools let LLMs trigger actions with custom UI rendering.\n\n## References\n\n- [.\u002Freferences\u002Fmake-tool.md](.\u002Freferences\u002Fmake-tool.md) -- makeAssistantTool\u002FuseAssistantTool\n- [.\u002Freferences\u002Ftool-ui.md](.\u002Freferences\u002Ftool-ui.md) -- makeAssistantToolUI rendering\n- [.\u002Freferences\u002Fhuman-in-loop.md](.\u002Freferences\u002Fhuman-in-loop.md) -- Confirmation patterns\n\n## Tool Types\n\n```\nWhere does the tool execute?\n├─ Backend (LLM calls API) → AI SDK tool()\n│  └─ Want custom UI? → makeAssistantToolUI\n└─ Frontend (browser-only) → makeAssistantTool\n   └─ Want custom UI? → makeAssistantToolUI\n```\n\n## Backend Tool with UI\n\n```ts\n\u002F\u002F Backend (app\u002Fapi\u002Fchat\u002Froute.ts)\nimport { tool, stepCountIs } from \"ai\";\nimport { z } from \"zod\";\n\nconst tools = {\n  get_weather: tool({\n    description: \"Get weather for a city\",\n    inputSchema: z.object({ city: z.string() }),\n    execute: async ({ city }) => ({ temp: 22, city }),\n  }),\n};\n\nconst result = streamText({\n  model: openai(\"gpt-4o\"),\n  messages,\n  tools,\n  stopWhen: stepCountIs(5),\n});\n```\n\n```tsx\n\u002F\u002F Frontend\nimport { makeAssistantToolUI } from \"@assistant-ui\u002Freact\";\n\nconst WeatherToolUI = makeAssistantToolUI({\n  toolName: \"get_weather\",\n  render: ({ args, result, status }) => {\n    if (status === \"running\") return \u003Cdiv>Loading weather...\u003C\u002Fdiv>;\n    return \u003Cdiv>{result?.city}: {result?.temp}°C\u003C\u002Fdiv>;\n  },\n});\n\n\u002F\u002F Register in app\n\u003CAssistantRuntimeProvider runtime={runtime}>\n  \u003CWeatherToolUI \u002F>\n  \u003CThread \u002F>\n\u003C\u002FAssistantRuntimeProvider>\n```\n\n## Frontend-Only Tool\n\n```tsx\nimport { makeAssistantTool } from \"@assistant-ui\u002Freact\";\nimport { z } from \"zod\";\n\nconst CopyTool = makeAssistantTool({\n  toolName: \"copy_to_clipboard\",\n  parameters: z.object({ text: z.string() }),\n  execute: async ({ text }) => {\n    await navigator.clipboard.writeText(text);\n    return { success: true };\n  },\n});\n\n\u003CAssistantRuntimeProvider runtime={runtime}>\n  \u003CCopyTool \u002F>\n  \u003CThread \u002F>\n\u003C\u002FAssistantRuntimeProvider>\n```\n\n## API Reference\n\n```tsx\n\u002F\u002F makeAssistantToolUI props\ninterface ToolUIProps {\n  toolCallId: string;\n  toolName: string;\n  args: Record\u003Cstring, unknown>;\n  argsText: string;\n  result?: unknown;\n  status: \"running\" | \"complete\" | \"incomplete\" | \"requires-action\";\n  submitResult: (result: unknown) => void;  \u002F\u002F For interactive tools\n}\n```\n\n## Human-in-the-Loop\n\n```tsx\nconst DeleteToolUI = makeAssistantToolUI({\n  toolName: \"delete_file\",\n  render: ({ args, status, submitResult }) => {\n    if (status === \"requires-action\") {\n      return (\n        \u003Cdiv>\n          \u003Cp>Delete {args.path}?\u003C\u002Fp>\n          \u003Cbutton onClick={() => submitResult({ confirmed: true })}>Confirm\u003C\u002Fbutton>\n          \u003Cbutton onClick={() => submitResult({ confirmed: false })}>Cancel\u003C\u002Fbutton>\n        \u003C\u002Fdiv>\n      );\n    }\n    return \u003Cdiv>File deleted\u003C\u002Fdiv>;\n  },\n});\n```\n\n## Common Gotchas\n\n**Tool UI not rendering**\n- `toolName` must match exactly (case-sensitive)\n- Register UI inside `AssistantRuntimeProvider`\n\n**Tool not being called**\n- Check tool description is clear\n- Use `stopWhen: stepCountIs(n)` to allow multi-step\n\n**Result not showing**\n- Tool must return a value\n- Check `status === \"complete\"` before accessing result\n","# assistant-ui Tools\n\n**Always consult [assistant-ui.com\u002Fllms.txt](https:\u002F\u002Fassistant-ui.com\u002Fllms.txt) for latest API.**\n\nTools let LLMs trigger actions with custom UI rendering.\n\n## References\n\n- [.\u002Freferences\u002Fmake-tool.md](.\u002Freferences\u002Fmake-tool.md) -- makeAssistantTool\u002FuseAssistantTool\n- [.\u002Freferences\u002Ftool-ui.md](.\u002Freferences\u002Ftool-ui.md) -- makeAssistantToolUI rendering\n- [.\u002Freferences\u002Fhuman-in-loop.md](.\u002Freferences\u002Fhuman-in-loop.md) -- Confirmation patterns\n\n## Tool Types\n\n```\nWhere does the tool execute?\n├─ Backend (LLM calls API) → AI SDK tool()\n│  └─ Want custom UI? → makeAssistantToolUI\n└─ Frontend (browser-only) → makeAssistantTool\n   └─ Want custom UI? → makeAssistantToolUI\n```\n\n## Backend Tool with UI\n\n```ts\n\u002F\u002F Backend (app\u002Fapi\u002Fchat\u002Froute.ts)\nimport { tool, stepCountIs } from \"ai\";\nimport { z } from \"zod\";\n\nconst tools = {\n  get_weather: tool({\n    description: \"Get weather for a city\",\n    inputSchema: z.object({ city: z.string() }),\n    execute: async ({ city }) => ({ temp: 22, city }),\n  }),\n};\n\nconst result = streamText({\n  model: openai(\"gpt-4o\"),\n  messages,\n  tools,\n  stopWhen: stepCountIs(5),\n});\n```\n\n```tsx\n\u002F\u002F Frontend\nimport { makeAssistantToolUI } from \"@assistant-ui\u002Freact\";\n\nconst WeatherToolUI = makeAssistantToolUI({\n  toolName: \"get_weather\",\n  render: ({ args, result, status }) => {\n    if (status === \"running\") return \u003Cdiv>Loading weather...\u003C\u002Fdiv>;\n    return \u003Cdiv>{result?.city}: {result?.temp}°C\u003C\u002Fdiv>;\n  },\n});\n\n\u002F\u002F Register in app\n\u003CAssistantRuntimeProvider runtime={runtime}>\n  \u003CWeatherToolUI \u002F>\n  \u003CThread \u002F>\n\u003C\u002FAssistantRuntimeProvider>\n```\n\n## Frontend-Only Tool\n\n```tsx\nimport { makeAssistantTool } from \"@assistant-ui\u002Freact\";\nimport { z } from \"zod\";\n\nconst CopyTool = makeAssistantTool({\n  toolName: \"copy_to_clipboard\",\n  parameters: z.object({ text: z.string() }),\n  execute: async ({ text }) => {\n    await navigator.clipboard.writeText(text);\n    return { success: true };\n  },\n});\n\n\u003CAssistantRuntimeProvider runtime={runtime}>\n  \u003CCopyTool \u002F>\n  \u003CThread \u002F>\n\u003C\u002FAssistantRuntimeProvider>\n```\n\n## API Reference\n\n```tsx\n\u002F\u002F makeAssistantToolUI props\ninterface ToolUIProps {\n  toolCallId: string;\n  toolName: string;\n  args: Record\u003Cstring, unknown>;\n  argsText: string;\n  result?: unknown;\n  status: \"running\" | \"complete\" | \"incomplete\" | \"requires-action\";\n  submitResult: (result: unknown) => void;  \u002F\u002F For interactive tools\n}\n```\n\n## Human-in-the-Loop\n\n```tsx\nconst DeleteToolUI = makeAssistantToolUI({\n  toolName: \"delete_file\",\n  render: ({ args, status, submitResult }) => {\n    if (status === \"requires-action\") {\n      return (\n        \u003Cdiv>\n          \u003Cp>Delete {args.path}?\u003C\u002Fp>\n          \u003Cbutton onClick={() => submitResult({ confirmed: true })}>Confirm\u003C\u002Fbutton>\n          \u003Cbutton onClick={() => submitResult({ confirmed: false })}>Cancel\u003C\u002Fbutton>\n        \u003C\u002Fdiv>\n      );\n    }\n    return \u003Cdiv>File deleted\u003C\u002Fdiv>;\n  },\n});\n```\n\n## Common Gotchas\n\n**Tool UI not rendering**\n- `toolName` must match exactly (case-sensitive)\n- Register UI inside `AssistantRuntimeProvider`\n\n**Tool not being called**\n- Check tool description is clear\n- Use `stopWhen: stepCountIs(n)` to allow multi-step\n\n**Result not showing**\n- Tool must return a value\n- Check `status === \"complete\"` before accessing result\n",{"name":5,"license":14,"version":45,"description":7},"0.0.1","master","48a57981043dbb2c534a27f410715a205f50bcfb",".claude\u002Fskills\u002Ftools",2,"https:\u002F\u002Fgithub.com\u002FAkaraChen\u002Fangel-engine","https:\u002F\u002Fangel-engine.vercel.app\u002F","https:\u002F\u002Fgithub.com\u002FAkaraChen","https:\u002F\u002Fakr.moe","button painter, string concatenator, log alchemist.\r\n\r\nNo slop, no lag.","2026-09-09 08:58:26",{"source":8,"skillName":5,"commands":57,"prompt":67,"zipAvailable":68},[58,61,64],{"tool":59,"command":60},"npx","npx skills add AkaraChen\u002Fangel-engine --skill tools",{"tool":62,"command":63},"bunx","bunx skills add AkaraChen\u002Fangel-engine --skill tools",{"tool":65,"command":66},"pnpm","pnpm dlx skills add AkaraChen\u002Fangel-engine --skill tools","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FAkaraChen\u002Fangel-engine\u002Fblob\u002Fmaster\u002F.claude\u002Fskills\u002Ftools\u002FSKILL.md",true,[70,76,80],{"path":71,"resourceType":72,"resourceTypeDesc":73,"sizeBytes":74,"sourceHtmlUrl":75},"references\u002Fhuman-in-loop.md","REFERENCE","参考文档",8679,"https:\u002F\u002Fgithub.com\u002FAkaraChen\u002Fangel-engine\u002Fblob\u002Fmaster\u002F.claude\u002Fskills\u002Ftools\u002Freferences\u002Fhuman-in-loop.md",{"path":77,"resourceType":72,"resourceTypeDesc":73,"sizeBytes":78,"sourceHtmlUrl":79},"references\u002Fmake-tool.md",5641,"https:\u002F\u002Fgithub.com\u002FAkaraChen\u002Fangel-engine\u002Fblob\u002Fmaster\u002F.claude\u002Fskills\u002Ftools\u002Freferences\u002Fmake-tool.md",{"path":81,"resourceType":72,"resourceTypeDesc":73,"sizeBytes":82,"sourceHtmlUrl":83},"references\u002Ftool-ui.md",6269,"https:\u002F\u002Fgithub.com\u002FAkaraChen\u002Fangel-engine\u002Fblob\u002Fmaster\u002F.claude\u002Fskills\u002Ftools\u002Freferences\u002Ftool-ui.md",[85,97,113,126,142,155],{"skillNo":86,"name":87,"nameZh":6,"description":88,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":89,"categories":90,"keywords":91,"publishedAt":40},"01M71V8NX6JM9719CJM1R07JNF","update","Update assistant-ui and AI SDK to latest versions. Detects current versions, identifies breaking changes, and executes migrations.","https:\u002F\u002Fgithub.com\u002FAkaraChen\u002Fangel-engine\u002Fblob\u002Fmaster\u002F.claude\u002Fskills\u002Fupdate\u002FSKILL.md",[],[87,92,93,94,95,39,96,33],"changes","latest","migrations","ai sdk","sdk",{"skillNo":98,"name":99,"nameZh":6,"description":100,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":101,"categories":102,"keywords":103,"publishedAt":40},"01M71V8EK5HG1TY1JSJA9ZG6RA","thread-list","Guide for multi-thread management in assistant-ui. Use when implementing thread lists, switching threads, or managing conversation history.","https:\u002F\u002Fgithub.com\u002FAkaraChen\u002Fangel-engine\u002Fblob\u002Fmaster\u002F.claude\u002Fskills\u002Fthread-list\u002FSKILL.md",[],[104,105,106,107,39,33,35,26,25,108,27,109,110,111,112,34],"thread","list","thread list","history","management","threads","multi","switching","conversation",{"skillNo":114,"name":115,"nameZh":6,"description":116,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":117,"categories":118,"keywords":119,"publishedAt":40},"01M71V8CQ30TTQP2KHPYCGCR3R","streaming","Guide for assistant-stream package and streaming protocols. Use when implementing streaming backends, custom protocols, or debugging stream issues.","https:\u002F\u002Fgithub.com\u002FAkaraChen\u002Fangel-engine\u002Fblob\u002Fmaster\u002F.claude\u002Fskills\u002Fstreaming\u002FSKILL.md",[],[115,120,33,121,25,122,26,27,34,123,35,124,125],"stream","debugging","custom","issues","protocols","package",{"skillNo":127,"name":128,"nameZh":6,"description":129,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":130,"categories":131,"keywords":132,"publishedAt":40},"01M71V86CFGGT33XS5FCVAYPVG","setup","Setup and configure assistant-ui in a project. Use when installing packages, configuring runtimes, setting up chat UI, or troubleshooting setup issues.","https:\u002F\u002Fgithub.com\u002FAkaraChen\u002Fangel-engine\u002Fblob\u002Fmaster\u002F.claude\u002Fskills\u002Fsetup\u002FSKILL.md",[],[128,133,39,25,134,135,136,137,34,138,139,140,123,141,33],"chat ui","runtimes","project","chat","up","troubleshooting","configure","setting","packages",{"skillNo":143,"name":144,"nameZh":6,"description":145,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":146,"categories":147,"keywords":148,"publishedAt":40},"01M71V84DGS3SN4VJ829MHNBB8","runtime","Guide for assistant-ui runtime system and state management. Use when working with runtimes, accessing state, or managing thread\u002Fmessage data.","https:\u002F\u002Fgithub.com\u002FAkaraChen\u002Fangel-engine\u002Fblob\u002Fmaster\u002F.claude\u002Fskills\u002Fruntime\u002FSKILL.md",[],[144,34,35,108,149,150,39,151,152,33,153,25,104,26,154,134],"system","data","state","state management","message","with",{"skillNo":156,"name":157,"nameZh":6,"description":158,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":159,"categories":160,"keywords":161,"publishedAt":40},"01M71V82YXWTCQS0M06D2HK4C4","primitives","Guide for assistant-ui UI primitives - ThreadPrimitive, ComposerPrimitive, MessagePrimitive. Use when customizing chat UI components.","https:\u002F\u002Fgithub.com\u002FAkaraChen\u002Fangel-engine\u002Fblob\u002Fmaster\u002F.claude\u002Fskills\u002Fprimitives\u002FSKILL.md",[],[157,25,26,133,162,136,34,35,39,163,33],"ui components","components"]