@icen.ai/ui 0.9.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (431) hide show
  1. package/AGENTS.md +82 -254
  2. package/LICENSE +21 -0
  3. package/README.md +60 -96
  4. package/dist/base.css +258 -188
  5. package/dist/behaviors/accordion.mjs +8 -8
  6. package/dist/behaviors/ai-branch.d.mts +1 -1
  7. package/dist/behaviors/ai-branch.mjs +1011 -94
  8. package/dist/behaviors/ai-chat.d.mts +9 -9
  9. package/dist/behaviors/ai-chat.mjs +1122 -169
  10. package/dist/behaviors/ai-composer.d.mts +47 -15
  11. package/dist/behaviors/ai-composer.mjs +2018 -534
  12. package/dist/behaviors/ai-core.d.mts +1 -1
  13. package/dist/behaviors/ai-core.mjs +1017 -107
  14. package/dist/behaviors/ai-diff.mjs +1020 -127
  15. package/dist/behaviors/ai-feedback.d.mts +1 -1
  16. package/dist/behaviors/ai-feedback.mjs +1036 -126
  17. package/dist/behaviors/ai-panel.d.mts +10 -10
  18. package/dist/behaviors/ai-panel.mjs +1285 -266
  19. package/dist/behaviors/ai-provider.d.mts +1 -1
  20. package/dist/behaviors/ai-provider.mjs +1004 -101
  21. package/dist/behaviors/ai-threads.d.mts +1 -1
  22. package/dist/behaviors/ai-threads.mjs +1069 -154
  23. package/dist/behaviors/ai-tool.d.mts +3 -3
  24. package/dist/behaviors/ai-tool.mjs +2087 -413
  25. package/dist/behaviors/ai-tools.d.mts +89 -16
  26. package/dist/behaviors/ai-tools.mjs +5365 -380
  27. package/dist/behaviors/autocomplete.d.mts +53 -0
  28. package/dist/behaviors/autocomplete.mjs +1601 -0
  29. package/dist/behaviors/back-top.d.mts +1 -1
  30. package/dist/behaviors/back-top.mjs +952 -14
  31. package/dist/behaviors/carousel.d.mts +1 -1
  32. package/dist/behaviors/carousel.mjs +914 -12
  33. package/dist/behaviors/cascader.d.mts +48 -0
  34. package/dist/behaviors/cascader.mjs +1867 -0
  35. package/dist/behaviors/charts.d.mts +72 -8
  36. package/dist/behaviors/charts.mjs +1953 -272
  37. package/dist/behaviors/code-block.d.mts +36 -0
  38. package/dist/behaviors/code-block.mjs +1619 -0
  39. package/dist/behaviors/command-palette.d.mts +9 -6
  40. package/dist/behaviors/command-palette.mjs +164 -62
  41. package/dist/behaviors/context-menu.d.mts +10 -9
  42. package/dist/behaviors/context-menu.mjs +1113 -44
  43. package/dist/behaviors/controls.d.mts +21 -21
  44. package/dist/behaviors/controls.mjs +1024 -134
  45. package/dist/behaviors/copy.d.mts +21 -2
  46. package/dist/behaviors/copy.mjs +1207 -42
  47. package/dist/behaviors/datatable.d.mts +55 -5
  48. package/dist/behaviors/datatable.mjs +2033 -212
  49. package/dist/behaviors/date-picker.d.mts +0 -1
  50. package/dist/behaviors/date-picker.mjs +1341 -293
  51. package/dist/behaviors/design.d.mts +54 -0
  52. package/dist/behaviors/design.mjs +109 -0
  53. package/dist/behaviors/dropdown.d.mts +5 -6
  54. package/dist/behaviors/dropdown.mjs +262 -110
  55. package/dist/behaviors/events.d.mts +127 -10
  56. package/dist/behaviors/events.mjs +58 -3
  57. package/dist/behaviors/feedback.d.mts +30 -0
  58. package/dist/behaviors/feedback.mjs +296 -0
  59. package/dist/behaviors/focus.d.mts +8 -0
  60. package/dist/behaviors/focus.mjs +24 -0
  61. package/dist/behaviors/form-validate.d.mts +111 -0
  62. package/dist/behaviors/form-validate.mjs +1746 -0
  63. package/dist/behaviors/i18n.d.mts +790 -0
  64. package/dist/behaviors/i18n.mjs +1713 -0
  65. package/dist/behaviors/icons.d.mts +93 -0
  66. package/dist/behaviors/icons.mjs +113 -0
  67. package/dist/behaviors/input.d.mts +9 -1
  68. package/dist/behaviors/input.mjs +1059 -60
  69. package/dist/behaviors/kb-access.d.mts +3 -3
  70. package/dist/behaviors/kb-access.mjs +2135 -239
  71. package/dist/behaviors/kb-acl.d.mts +8 -8
  72. package/dist/behaviors/kb-acl.mjs +1120 -179
  73. package/dist/behaviors/kb-answer.d.mts +2 -2
  74. package/dist/behaviors/kb-answer.mjs +2120 -435
  75. package/dist/behaviors/kb-audit.d.mts +3 -3
  76. package/dist/behaviors/kb-audit.mjs +1077 -154
  77. package/dist/behaviors/kb-canvas.d.mts +3 -3
  78. package/dist/behaviors/kb-canvas.mjs +1101 -177
  79. package/dist/behaviors/kb-chain.d.mts +2 -2
  80. package/dist/behaviors/kb-chain.mjs +1023 -100
  81. package/dist/behaviors/kb-checkpoint.d.mts +3 -3
  82. package/dist/behaviors/kb-checkpoint.mjs +1320 -169
  83. package/dist/behaviors/kb-chunks.d.mts +2 -2
  84. package/dist/behaviors/kb-chunks.mjs +1153 -213
  85. package/dist/behaviors/kb-citation.d.mts +3 -3
  86. package/dist/behaviors/kb-citation.mjs +1221 -185
  87. package/dist/behaviors/kb-clarify.d.mts +2 -2
  88. package/dist/behaviors/kb-clarify.mjs +1059 -130
  89. package/dist/behaviors/kb-conflict.d.mts +2 -2
  90. package/dist/behaviors/kb-conflict.mjs +1042 -119
  91. package/dist/behaviors/kb-connector.d.mts +2 -2
  92. package/dist/behaviors/kb-connector.mjs +1105 -176
  93. package/dist/behaviors/kb-core.d.mts +7 -2
  94. package/dist/behaviors/kb-core.mjs +1078 -162
  95. package/dist/behaviors/kb-eval.d.mts +2 -2
  96. package/dist/behaviors/kb-eval.mjs +1977 -144
  97. package/dist/behaviors/kb-explain.d.mts +3 -3
  98. package/dist/behaviors/kb-explain.mjs +1037 -104
  99. package/dist/behaviors/kb-filter.d.mts +2 -2
  100. package/dist/behaviors/kb-filter.mjs +2014 -178
  101. package/dist/behaviors/kb-gap.d.mts +3 -3
  102. package/dist/behaviors/kb-gap.mjs +1044 -121
  103. package/dist/behaviors/kb-hittest.d.mts +3 -3
  104. package/dist/behaviors/kb-hittest.mjs +1095 -151
  105. package/dist/behaviors/kb-metadata.mjs +1058 -130
  106. package/dist/behaviors/kb-passage.d.mts +4 -4
  107. package/dist/behaviors/kb-passage.mjs +1102 -161
  108. package/dist/behaviors/kb-pipeline.d.mts +4 -4
  109. package/dist/behaviors/kb-pipeline.mjs +1083 -162
  110. package/dist/behaviors/kb-qa.mjs +1089 -160
  111. package/dist/behaviors/kb-rerank.d.mts +2 -2
  112. package/dist/behaviors/kb-rerank.mjs +1048 -114
  113. package/dist/behaviors/kb-retrieval.d.mts +2 -2
  114. package/dist/behaviors/kb-retrieval.mjs +2079 -226
  115. package/dist/behaviors/kb-review.d.mts +2 -2
  116. package/dist/behaviors/kb-review.mjs +1996 -159
  117. package/dist/behaviors/kb-sandbox.d.mts +3 -3
  118. package/dist/behaviors/kb-sandbox.mjs +1033 -105
  119. package/dist/behaviors/kb-segment.d.mts +2 -2
  120. package/dist/behaviors/kb-segment.mjs +1112 -179
  121. package/dist/behaviors/kb-select.d.mts +24 -0
  122. package/dist/behaviors/kb-select.mjs +1995 -0
  123. package/dist/behaviors/kb-sources.d.mts +3 -3
  124. package/dist/behaviors/kb-sources.mjs +1085 -170
  125. package/dist/behaviors/kb-sql.d.mts +3 -3
  126. package/dist/behaviors/kb-sql.mjs +1144 -226
  127. package/dist/behaviors/kb-trace.d.mts +3 -3
  128. package/dist/behaviors/kb-trace.mjs +1051 -131
  129. package/dist/behaviors/kb-visibility.d.mts +2 -2
  130. package/dist/behaviors/kb-visibility.mjs +1087 -158
  131. package/dist/behaviors/kb-who-can.d.mts +2 -2
  132. package/dist/behaviors/kb-who-can.mjs +1980 -137
  133. package/dist/behaviors/mentions.d.mts +93 -0
  134. package/dist/behaviors/mentions.mjs +2153 -0
  135. package/dist/behaviors/modal.d.mts +4 -3
  136. package/dist/behaviors/modal.mjs +1056 -33
  137. package/dist/behaviors/nav.d.mts +1 -1
  138. package/dist/behaviors/nav.mjs +6 -6
  139. package/dist/behaviors/notification.d.mts +16 -8
  140. package/dist/behaviors/notification.mjs +1629 -268
  141. package/dist/behaviors/panel.d.mts +4 -0
  142. package/dist/behaviors/panel.mjs +995 -0
  143. package/dist/behaviors/popover.d.mts +28 -5
  144. package/dist/behaviors/popover.mjs +225 -24
  145. package/dist/behaviors/scroll-area.d.mts +17 -0
  146. package/dist/behaviors/scroll-area.mjs +59 -0
  147. package/dist/behaviors/select.d.mts +5 -2
  148. package/dist/behaviors/select.mjs +1416 -117
  149. package/dist/behaviors/sidebar.d.mts +1 -1
  150. package/dist/behaviors/sidebar.mjs +13 -13
  151. package/dist/behaviors/slider.d.mts +1 -1
  152. package/dist/behaviors/slider.mjs +12 -12
  153. package/dist/behaviors/split-pane.d.mts +1 -1
  154. package/dist/behaviors/split-pane.mjs +9 -7
  155. package/dist/behaviors/suggestions.d.mts +27 -0
  156. package/dist/behaviors/suggestions.mjs +1090 -0
  157. package/dist/behaviors/svg-parse.d.mts +14 -0
  158. package/dist/behaviors/svg-parse.mjs +37 -0
  159. package/dist/behaviors/tabs.d.mts +2 -2
  160. package/dist/behaviors/tabs.mjs +35 -25
  161. package/dist/behaviors/tag-input.d.mts +23 -5
  162. package/dist/behaviors/tag-input.mjs +1360 -104
  163. package/dist/behaviors/theme-switcher.d.mts +24 -0
  164. package/dist/behaviors/theme-switcher.mjs +1996 -0
  165. package/dist/behaviors/theme.d.mts +15 -8
  166. package/dist/behaviors/theme.mjs +406 -30
  167. package/dist/behaviors/toast.d.mts +24 -25
  168. package/dist/behaviors/toast.mjs +1267 -88
  169. package/dist/behaviors/tooltip.d.mts +4 -0
  170. package/dist/behaviors/tooltip.mjs +378 -0
  171. package/dist/behaviors/tree-select.d.mts +69 -0
  172. package/dist/behaviors/tree-select.mjs +1921 -0
  173. package/dist/behaviors/tree.d.mts +1 -1
  174. package/dist/behaviors/tree.mjs +18 -18
  175. package/dist/behaviors/upload.d.mts +3 -2
  176. package/dist/behaviors/upload.mjs +1077 -66
  177. package/dist/behaviors/url-safety.d.mts +8 -0
  178. package/dist/behaviors/url-safety.mjs +11 -0
  179. package/dist/cli.mjs +5 -6
  180. package/dist/components/accordion.d.mts +2 -0
  181. package/dist/components/ai-branch.d.mts +2 -0
  182. package/dist/components/ai-chat.css +682 -582
  183. package/dist/components/ai-chat.d.mts +2 -0
  184. package/dist/components/ai-composer.d.mts +2 -0
  185. package/dist/components/ai-context.d.mts +2 -0
  186. package/dist/components/ai-context.mjs +1 -0
  187. package/dist/components/ai-diff.css +153 -132
  188. package/dist/components/ai-diff.d.mts +2 -0
  189. package/dist/components/ai-feedback.d.mts +2 -0
  190. package/dist/components/ai-files.d.mts +2 -0
  191. package/dist/components/ai-message.d.mts +2 -0
  192. package/dist/components/ai-panel.css +353 -343
  193. package/dist/components/ai-reasoning.d.mts +2 -0
  194. package/dist/components/ai-subagent.d.mts +2 -0
  195. package/dist/components/ai-subagent.mjs +1 -0
  196. package/dist/components/ai-threads.d.mts +2 -0
  197. package/dist/components/ai-todo.d.mts +2 -0
  198. package/dist/components/ai-todo.mjs +1 -0
  199. package/dist/components/ai-tool-call.d.mts +2 -0
  200. package/dist/components/ai-tool-call.mjs +1 -0
  201. package/dist/components/ai-tool.css +397 -242
  202. package/dist/components/ai-usage.d.mts +2 -0
  203. package/dist/components/alert.d.mts +2 -0
  204. package/dist/components/autocomplete.css +61 -0
  205. package/dist/components/autocomplete.d.mts +2 -0
  206. package/dist/components/autocomplete.mjs +3 -0
  207. package/dist/components/avatar.d.mts +2 -0
  208. package/dist/components/back-top.css +74 -40
  209. package/dist/components/back-top.d.mts +2 -0
  210. package/dist/components/badge.css +44 -41
  211. package/dist/components/badge.d.mts +2 -0
  212. package/dist/components/breadcrumb.css +85 -46
  213. package/dist/components/breadcrumb.d.mts +2 -0
  214. package/dist/components/btn.css +105 -94
  215. package/dist/components/btn.d.mts +2 -0
  216. package/dist/components/card.css +124 -113
  217. package/dist/components/card.d.mts +2 -0
  218. package/dist/components/carousel.d.mts +2 -0
  219. package/dist/components/cascader.css +332 -0
  220. package/dist/components/cascader.d.mts +2 -0
  221. package/dist/components/cascader.mjs +3 -0
  222. package/dist/components/chart-area.css +54 -2
  223. package/dist/components/chart-area.d.mts +2 -0
  224. package/dist/components/chart-bar.css +147 -38
  225. package/dist/components/chart-bar.d.mts +2 -0
  226. package/dist/components/chart-calendar.d.mts +2 -0
  227. package/dist/components/chart-gauge.css +36 -13
  228. package/dist/components/chart-gauge.d.mts +2 -0
  229. package/dist/components/chart-graph.css +35 -20
  230. package/dist/components/chart-graph.d.mts +2 -0
  231. package/dist/components/chart-heatmap.css +67 -39
  232. package/dist/components/chart-heatmap.d.mts +2 -0
  233. package/dist/components/chart-line.css +62 -3
  234. package/dist/components/chart-line.d.mts +2 -0
  235. package/dist/components/chart-map.d.mts +2 -0
  236. package/dist/components/chart-pie.css +38 -6
  237. package/dist/components/chart-pie.d.mts +2 -0
  238. package/dist/components/chart-radar.css +57 -5
  239. package/dist/components/chart-radar.d.mts +2 -0
  240. package/dist/components/chart-scatter.css +47 -7
  241. package/dist/components/chart-scatter.d.mts +2 -0
  242. package/dist/components/chart-sparkline.css +25 -2
  243. package/dist/components/chart-sparkline.d.mts +2 -0
  244. package/dist/components/chart-stack.css +27 -13
  245. package/dist/components/chart-stack.d.mts +2 -0
  246. package/dist/components/charts.css +220 -84
  247. package/dist/components/charts.d.mts +2 -0
  248. package/dist/components/code-block.css +420 -0
  249. package/dist/components/code-block.d.mts +2 -0
  250. package/dist/components/code-block.mjs +4 -0
  251. package/dist/components/command-palette.css +150 -122
  252. package/dist/components/command-palette.d.mts +2 -0
  253. package/dist/components/content.css +274 -263
  254. package/dist/components/context-menu.d.mts +2 -0
  255. package/dist/components/copy.css +73 -45
  256. package/dist/components/copy.d.mts +2 -0
  257. package/dist/components/datatable.css +457 -202
  258. package/dist/components/datatable.d.mts +2 -0
  259. package/dist/components/date-picker.css +136 -105
  260. package/dist/components/date-picker.d.mts +2 -0
  261. package/dist/components/desc.d.mts +2 -0
  262. package/dist/components/dropdown.d.mts +2 -0
  263. package/dist/components/empty.css +72 -69
  264. package/dist/components/empty.d.mts +2 -0
  265. package/dist/components/feedback.css +211 -191
  266. package/dist/components/form-validate.css +134 -0
  267. package/dist/components/form-validate.d.mts +2 -0
  268. package/dist/components/form-validate.mjs +3 -0
  269. package/dist/components/form.css +157 -131
  270. package/dist/components/form.d.mts +2 -0
  271. package/dist/components/icon.css +113 -0
  272. package/dist/components/icon.d.mts +2 -0
  273. package/dist/components/icon.mjs +3 -0
  274. package/dist/components/input.css +163 -108
  275. package/dist/components/input.d.mts +2 -0
  276. package/dist/components/kb-access.d.mts +2 -0
  277. package/dist/components/kb-acl.d.mts +2 -0
  278. package/dist/components/kb-agent.css +300 -206
  279. package/dist/components/kb-answer.d.mts +2 -0
  280. package/dist/components/kb-audit.d.mts +2 -0
  281. package/dist/components/kb-canvas.d.mts +2 -0
  282. package/dist/components/kb-chain.d.mts +2 -0
  283. package/dist/components/kb-checkpoint.d.mts +2 -0
  284. package/dist/components/kb-chunks.d.mts +2 -0
  285. package/dist/components/kb-citation.d.mts +2 -0
  286. package/dist/components/kb-clarify.d.mts +2 -0
  287. package/dist/components/kb-conflict.d.mts +2 -0
  288. package/dist/components/kb-connector.d.mts +2 -0
  289. package/dist/components/kb-data.css +431 -315
  290. package/dist/components/kb-eval.d.mts +2 -0
  291. package/dist/components/kb-explain.d.mts +2 -0
  292. package/dist/components/kb-filter.d.mts +2 -0
  293. package/dist/components/kb-gap.d.mts +2 -0
  294. package/dist/components/kb-ground.css +333 -229
  295. package/dist/components/kb-hittest.d.mts +2 -0
  296. package/dist/components/kb-ingest.css +613 -434
  297. package/dist/components/kb-metadata.d.mts +2 -0
  298. package/dist/components/kb-ops.css +422 -302
  299. package/dist/components/kb-passage.d.mts +2 -0
  300. package/dist/components/kb-perm.css +374 -314
  301. package/dist/components/kb-pipeline.d.mts +2 -0
  302. package/dist/components/kb-qa.d.mts +2 -0
  303. package/dist/components/kb-rerank.d.mts +2 -0
  304. package/dist/components/kb-retrieval.d.mts +2 -0
  305. package/dist/components/kb-review.d.mts +2 -0
  306. package/dist/components/kb-sandbox.d.mts +2 -0
  307. package/dist/components/kb-search.css +653 -459
  308. package/dist/components/kb-segment.d.mts +2 -0
  309. package/dist/components/kb-sources.d.mts +2 -0
  310. package/dist/components/kb-sql.d.mts +2 -0
  311. package/dist/components/kb-trace.d.mts +2 -0
  312. package/dist/components/kb-visibility.d.mts +2 -0
  313. package/dist/components/kb-who-can.d.mts +2 -0
  314. package/dist/components/kb.css +170 -135
  315. package/dist/components/kb.d.mts +2 -0
  316. package/dist/components/kbd.d.mts +2 -0
  317. package/dist/components/layout.css +86 -83
  318. package/dist/components/layout.d.mts +2 -0
  319. package/dist/components/list.d.mts +2 -0
  320. package/dist/components/material-chinese.css +83 -0
  321. package/dist/components/material-soviet.css +86 -0
  322. package/dist/components/material.css +318 -0
  323. package/dist/components/media-card.d.mts +2 -0
  324. package/dist/components/media.css +225 -176
  325. package/dist/components/mentions.css +190 -0
  326. package/dist/components/mentions.d.mts +2 -0
  327. package/dist/components/mentions.mjs +3 -0
  328. package/dist/components/menu.css +121 -109
  329. package/dist/components/modal.css +116 -118
  330. package/dist/components/modal.d.mts +2 -0
  331. package/dist/components/nav.css +136 -129
  332. package/dist/components/nav.d.mts +2 -0
  333. package/dist/components/notification.css +247 -177
  334. package/dist/components/notification.d.mts +2 -0
  335. package/dist/components/pagination.css +62 -57
  336. package/dist/components/pagination.d.mts +2 -0
  337. package/dist/components/panel.css +70 -68
  338. package/dist/components/panel.d.mts +2 -0
  339. package/dist/components/panel.mjs +1 -0
  340. package/dist/components/pill.css +83 -72
  341. package/dist/components/pill.d.mts +2 -0
  342. package/dist/components/popover.css +80 -57
  343. package/dist/components/popover.d.mts +2 -0
  344. package/dist/components/progress.d.mts +2 -0
  345. package/dist/components/rating.d.mts +2 -0
  346. package/dist/components/result.d.mts +2 -0
  347. package/dist/components/scroll-area.css +29 -54
  348. package/dist/components/scroll-area.d.mts +2 -0
  349. package/dist/components/scroll-area.mjs +1 -0
  350. package/dist/components/segmented.css +167 -146
  351. package/dist/components/segmented.d.mts +2 -0
  352. package/dist/components/select.css +250 -191
  353. package/dist/components/select.d.mts +2 -0
  354. package/dist/components/sidebar.css +157 -143
  355. package/dist/components/sidebar.d.mts +2 -0
  356. package/dist/components/skeleton.d.mts +2 -0
  357. package/dist/components/slider.css +135 -128
  358. package/dist/components/slider.d.mts +2 -0
  359. package/dist/components/spinner.d.mts +2 -0
  360. package/dist/components/split-pane.css +120 -108
  361. package/dist/components/split-pane.d.mts +2 -0
  362. package/dist/components/stat.css +116 -109
  363. package/dist/components/stat.d.mts +2 -0
  364. package/dist/components/steps.css +114 -108
  365. package/dist/components/steps.d.mts +2 -0
  366. package/dist/components/switch.css +192 -149
  367. package/dist/components/switch.d.mts +2 -0
  368. package/dist/components/table.css +158 -112
  369. package/dist/components/table.d.mts +2 -0
  370. package/dist/components/tabs.css +143 -116
  371. package/dist/components/tabs.d.mts +2 -0
  372. package/dist/components/tag-input.css +52 -133
  373. package/dist/components/tag-input.d.mts +2 -0
  374. package/dist/components/tag.css +90 -72
  375. package/dist/components/tag.d.mts +2 -0
  376. package/dist/components/theme-switcher.css +105 -0
  377. package/dist/components/theme-switcher.d.mts +2 -0
  378. package/dist/components/theme-switcher.mjs +3 -0
  379. package/dist/components/timeline.d.mts +2 -0
  380. package/dist/components/toast.css +115 -97
  381. package/dist/components/toast.d.mts +2 -0
  382. package/dist/components/toolbar.css +47 -43
  383. package/dist/components/toolbar.d.mts +2 -0
  384. package/dist/components/tooltip.css +103 -43
  385. package/dist/components/tooltip.d.mts +2 -0
  386. package/dist/components/tooltip.mjs +1 -0
  387. package/dist/components/tree-select.css +439 -0
  388. package/dist/components/tree-select.d.mts +2 -0
  389. package/dist/components/tree-select.mjs +3 -0
  390. package/dist/components/tree.d.mts +2 -0
  391. package/dist/components/upload.css +138 -97
  392. package/dist/components/upload.d.mts +2 -0
  393. package/dist/fonts/LICENSES/ark-pixel/OFL.txt +96 -0
  394. package/dist/fonts/LICENSES/cubic-11/OFL.txt +108 -0
  395. package/dist/fonts/LICENSES/galmuri/LICENSE.txt +93 -0
  396. package/dist/fonts/OFL.txt +96 -0
  397. package/dist/fonts/README.md +14 -0
  398. package/dist/fonts/fusion-pixel-12px-zh-hans.woff2 +0 -0
  399. package/dist/index.d.mts +85 -70
  400. package/dist/index.mjs +17330 -5773
  401. package/dist/react.d.mts +91 -0
  402. package/dist/react.mjs +8307 -0
  403. package/dist/registry.json +918 -70
  404. package/dist/tokens/chinese.css +44 -0
  405. package/dist/tokens/colors.css +371 -1222
  406. package/dist/tokens/design.css +209 -0
  407. package/dist/tokens/dtcg.json +15926 -0
  408. package/dist/tokens/figma.variables.json +10779 -0
  409. package/dist/tokens/icon-masks.css +78 -0
  410. package/dist/tokens/pixel.css +53 -0
  411. package/dist/tokens/scrollbars.css +40 -0
  412. package/dist/tokens/soviet.css +44 -0
  413. package/dist/tokens/style-profiles.css +36 -547
  414. package/dist/tokens/themes.json +308 -0
  415. package/dist/tokens/tokens-studio.json +11648 -0
  416. package/dist/tokens/typography.css +21 -18
  417. package/dist/tokens.css +1783 -1806
  418. package/dist/ui.css +14796 -10750
  419. package/dist/vue.d.mts +344 -0
  420. package/dist/vue.mjs +7876 -0
  421. package/docs/spec/ai-input-experience.md +75 -0
  422. package/docs/spec/ai-native.md +238 -147
  423. package/docs/spec/design-philosophy.md +189 -0
  424. package/docs/spec/design-primitives.md +196 -0
  425. package/docs/spec/kb-family.md +147 -115
  426. package/docs/spec/scrollbars.md +46 -0
  427. package/package.json +56 -8
  428. package/dist/retro-effects.css +0 -255
  429. package/dist/tokens/retro-effects.css +0 -255
  430. package/docs/research/2026-10-03-ai-kb-components.md +0 -392
  431. package/docs/research/2026-10-03-kb-permissions.md +0 -992
@@ -1,4 +1,4 @@
1
- # AI 原生组件族 · 设计规格(v0.6.x 新增)
1
+ # AI 原生组件族 · 设计规格
2
2
 
3
3
  > 唯一事实源。施工代理按此文件执行,不得偏离契约(类名 / 导出签名 / 事件名)。
4
4
  > 设计调研依据:AG-UI 协议、Vercel AI SDK UIMessage parts、OpenAI/Anthropic wire 格式、
@@ -6,7 +6,7 @@
6
6
 
7
7
  ## 0. 设计原则
8
8
 
9
- 1. **继承用 CSS 变量级联实现**:`.ai-item` 基元定义 `--ai-item-*` 局部变量,kind/变体只覆盖变量不改结构(btn.css 的 `--btn-*` 模式的推广)。
9
+ 1. **继承用 CSS 变量级联实现**:`.icen-ai-item` 基元定义 `--ai-item-*` 局部变量,kind/变体只覆盖变量不改结构(btn.css 的 `--btn-*` 模式的推广)。
10
10
  2. **多态用 kind 注册表**:MCP、skill 不是独立组件,是 tool-call 的 kind。`registerAiKind()` 开放第三方扩展。
11
11
  3. **组件只消费归一化模型**:业界格式(OpenAI / Anthropic / AI SDK / 素朴)由适配层统一翻译,组件不认识任何 provider。
12
12
  4. **状态机是唯一语言**:所有 AI 条目共享 7 态,语义色与动画全库一致。
@@ -33,24 +33,24 @@ pending → running → streaming → done
33
33
 
34
34
  协议映射:AI SDK `input-streaming/input-available`→pending、`approval-requested`→approval、`output-available`→done、`output-error`→error;AG-UI `TOOL_CALL_RESULT`→done、`outcome.interrupt`→approval;A2A `INPUT_REQUIRED/AUTH_REQUIRED`→approval、`WORKING`→running、终态→done/error/cancelled。
35
35
 
36
- ## 2. 条目基元 `.ai-item`(CSS 骨架,所有行式条目的"基类")
36
+ ## 2. 条目基元 `.icen-ai-item`(CSS 骨架,所有行式条目的"基类")
37
37
 
38
38
  ```html
39
- <div class="ai-item is-running" style="--ai-item-tint: var(--token-accent)">
40
- <span class="ai-item-icon"><!-- svg --></span>
41
- <div class="ai-item-main">
42
- <div class="ai-item-title">一行摘要</div>
43
- <div class="ai-item-sub">次要信息(路径/参数)</div>
39
+ <div class="icen-ai-item is-running" style="--ai-item-tint: var(--icen-token-accent)">
40
+ <span class="icen-ai-item-icon"><!-- svg --></span>
41
+ <div class="icen-ai-item-main">
42
+ <div class="icen-ai-item-title">一行摘要</div>
43
+ <div class="icen-ai-item-sub">次要信息(路径/参数)</div>
44
44
  </div>
45
- <div class="ai-item-side">
46
- <span class="ai-item-status"></span> <!-- 状态点,纯 CSS 由 .is-* 驱动 -->
47
- <span class="ai-item-meta">1.2s</span>
45
+ <div class="icen-ai-item-side">
46
+ <span class="icen-ai-item-status"></span> <!-- 状态点,纯 CSS 由 .is-* 驱动 -->
47
+ <span class="icen-ai-item-meta">1.2s</span>
48
48
  </div>
49
- <div class="ai-item-detail" hidden>展开详情</div>
49
+ <div class="icen-ai-item-detail" hidden>展开详情</div>
50
50
  </div>
51
51
  ```
52
52
 
53
- 局部变量:`--ai-item-tint`(图标/状态点着色槽,默认 accent)。状态点 `.ai-item-status` 是纯 CSS 圆点,由 `.is-*` 决定颜色与动效(running 脉冲用 `--pill-pulse-duration` 同款变量化时长)。
53
+ 局部变量:`--ai-item-tint`(图标/状态点着色槽,默认 accent)。状态点 `.icen-ai-item-status` 是纯 CSS 圆点,由 `.is-*` 决定颜色与动效(running 脉冲用 `--pill-pulse-duration` 同款变量化时长)。
54
54
 
55
55
  ## 3. 文件与 slug 组织
56
56
 
@@ -87,20 +87,20 @@ pending → running → streaming → done
87
87
  ### 4.1 ai-chat(ai-chat.css + ai-chat.ts)
88
88
 
89
89
  ```html
90
- <div class="ai-chat" data-density="normal"> <!-- verbose|normal|summary 透明度三档 -->
91
- <div class="ai-chat-scroll">
92
- <div class="ai-msg ai-msg--user | ai-msg--assistant | ai-msg--system | ai-msg--tool">
93
- <span class="ai-msg-avatar"></span>
94
- <div class="ai-msg-body">…内容(消费方可自行渲染 markdown)…</div>
95
- <div class="ai-msg-actions"><button data-ai-msg-action="copy">…<button data-ai-msg-action="retry">…</div>
96
- <div class="ai-msg-meta">12:04 · 1.2k tok</div>
90
+ <div class="icen-ai-chat" data-icen-density="normal"> <!-- verbose|normal|summary 透明度三档 -->
91
+ <div class="icen-ai-chat-scroll">
92
+ <div class="icen-ai-msg icen-ai-msg--user | icen-ai-msg--assistant | icen-ai-msg--system | icen-ai-msg--tool">
93
+ <span class="icen-ai-msg-avatar"></span>
94
+ <div class="icen-ai-msg-body">…内容(消费方可自行渲染 markdown)…</div>
95
+ <div class="icen-ai-msg-actions"><button data-icen-ai-msg-action="copy">…<button data-icen-ai-msg-action="retry">…</div>
96
+ <div class="icen-ai-msg-meta">12:04 · 1.2k tok</div>
97
97
  </div>
98
98
  </div>
99
- <button class="ai-chat-jump" hidden>回到底部 · 3 条新消息</button>
99
+ <button class="icen-ai-chat-jump" hidden>回到底部 · 3 条新消息</button>
100
100
  </div>
101
101
  ```
102
102
 
103
- - `initAiChat(root?)`:幂等(`__icenAiChatInit`)。滚动钉底:scroll 监听,贴底时自动跟随新内容(监听 scroll 容器尺寸变化用 ResizeObserver);用户上滚暂停跟随并显示 `.ai-chat-jump`(带未读计数),点击回底恢复。消息动作委托:copy→复制正文+派 `icen:ai-copy`;retry→派 `icen:ai-retry`(detail 含消息元素)。reasoning 折叠委托也在这里(`.ai-reasoning-head` 点击切换)。
103
+ - `initAiChat(root?)`:幂等(`__icenAiChatInit`)。滚动钉底:scroll 监听,贴底时自动跟随新内容(监听 scroll 容器尺寸变化用 ResizeObserver);用户上滚暂停跟随并显示 `.icen-ai-chat-jump`(带未读计数),点击回底恢复。消息动作委托:copy→复制正文+派 `icen:ai-copy`;retry→派 `icen:ai-retry`(detail 含消息元素)。reasoning 折叠委托也在这里(`.icen-ai-reasoning-head` 点击切换)。
104
104
  - `createAiStream(el)` → `{ append(text), done(), cancel(), fail(message?) }`:textContent 级追加(不解析 HTML),追加期间宿主挂 `.is-streaming`,done/cancel 移除;`fail()` 终止流并给宿主挂 `.is-error`(错误路径,append 之后失效)。Markdown 重渲染是消费方职责(文档里写明)。
105
105
  - `renderAiMessage(scrollEl, model)` → `{ el, body, setMeta, setError, stream() }`:DOM API 构建整条消息(含多模态部件渲染,见 §10),返回句柄;`stream()` 在正文末尾开 `createAiStream`。model:
106
106
 
@@ -110,7 +110,7 @@ interface AiMessageModel {
110
110
  content: AiContent; // string | AiContentPart[](§10)
111
111
  meta?: string; // "12:04 · 1.2k tok"
112
112
  model?: string; // assistant 消息的模型名标签
113
- error?: string; // → .ai-msg--error + 错误文本行
113
+ error?: string; // → .icen-ai-msg--error + 错误文本行
114
114
  streaming?: boolean; // 初始即流式态
115
115
  }
116
116
  ```
@@ -118,11 +118,11 @@ interface AiMessageModel {
118
118
  ### 4.2 ai-message / ai-reasoning(ai-chat.css 一族)
119
119
 
120
120
  ```html
121
- <div class="ai-reasoning is-done">
122
- <button class="ai-reasoning-head" aria-expanded="false">
123
- <span class="ai-reasoning-label">思考过程</span><span class="ai-reasoning-time">3s</span>
121
+ <div class="icen-ai-reasoning is-done">
122
+ <button class="icen-ai-reasoning-head" aria-expanded="false">
123
+ <span class="icen-ai-reasoning-label">思考过程</span><span class="icen-ai-reasoning-time">3s</span>
124
124
  </button>
125
- <div class="ai-reasoning-body" hidden>…</div>
125
+ <div class="icen-ai-reasoning-body" hidden>…</div>
126
126
  </div>
127
127
  ```
128
128
 
@@ -131,40 +131,41 @@ interface AiMessageModel {
131
131
  ### 4.3 ai-composer(ai-chat.css + ai-composer.ts)
132
132
 
133
133
  ```html
134
- <div class="ai-composer" data-ai-composer>
135
- <div class="ai-composer-queue" hidden><!-- 排队消息 chips,可逐个 × --></div>
136
- <div class="ai-composer-attach" hidden><!-- 附件 chips --></div>
137
- <div class="ai-composer-box control">
138
- <textarea class="ai-composer-input" rows="1" placeholder="…"></textarea>
139
- <div class="ai-composer-actions">
140
- <button class="ai-composer-btn" data-ai-attach aria-label="附件"></button>
141
- <button class="ai-composer-send" data-ai-send></button> <!-- 运行态变 .is-stop 停止钮 -->
134
+ <div class="icen-ai-composer" data-icen-ai-composer>
135
+ <div class="icen-ai-composer-queue" hidden><!-- 排队消息 chips,可逐个 × --></div>
136
+ <div class="icen-ai-composer-attach" hidden><!-- 附件 chips --></div>
137
+ <div class="icen-ai-composer-box icen-control">
138
+ <textarea class="icen-ai-composer-input" rows="1" placeholder="…"></textarea>
139
+ <div class="icen-ai-composer-toolbar">
140
+ <span class="icen-ai-composer-spacer"></span>
141
+ <button class="icen-ai-composer-btn" data-icen-ai-attach aria-label="附件"></button>
142
+ <button class="icen-ai-composer-send" data-icen-ai-send></button> <!-- 运行态变 .is-stop 停止钮 -->
142
143
  </div>
143
144
  </div>
144
145
  </div>
145
146
  ```
146
147
 
147
- - `initAiComposer(root?)`:autosize(上限 ~8 行后内滚);Enter 发送 / Shift+Enter 换行 / IME 组合态安全(复用 input.ts 模式);发送派 `icen:ai-send {text}` 并清空。
148
- - **运行/停止态**:`setComposerRunning(el, bool)` 导出——运行中发送钮变停止钮(点击派 `icen:ai-stop`),此时输入不丢:回车转为入队(queue chip)并派 `icen:ai-queue {text}`;chip × 移除派 `icen:ai-dequeue {index}`。(queue / steer / stop 三动词分化,对齐 Cursor/Copilot 2026 模式)
148
+ - `initAiComposer(root?)`:autosize(上限 ~8 行后内滚);Enter 发送 / Shift+Enter 换行 / IME 组合态安全(复用 input.ts 模式);发送派 `icen:ai-send {text, refs?, files?}` 并清空。
149
+ - **运行/停止态**:`setComposerRunning(el, bool)` 导出——运行中发送钮变停止钮(点击派 `icen:ai-stop`),此时输入不丢:回车转为入队(queue chip)并派 `icen:ai-queue {text, refs?, files?}`;chip × 移除派 `icen:ai-dequeue {index}`。(queue / steer / stop 三动词分化,对齐 Cursor/Copilot 2026 模式)
149
150
  - 附件钮打开 file input,选中文件生成 chip,派 `icen:ai-attach {files}`。
150
151
 
151
152
  ### 4.4 ai-tool-call(ai-tool.css + ai-tool.ts)
152
153
 
153
154
  ```html
154
- <div class="ai-tool ai-tool--shell is-done"> <!-- kind 修饰类:--shell/--read/--edit/… -->
155
- <button class="ai-tool-head" aria-expanded="false">
156
- <span class="ai-item-icon"></span>
157
- <span class="ai-item-main"><span class="ai-item-title">Read</span>
158
- <span class="ai-item-sub">src/foo.ts:1-50</span></span>
159
- <span class="ai-item-status"></span>
160
- <span class="ai-item-meta">0.4s</span>
155
+ <div class="icen-ai-tool icen-ai-tool--shell is-done"> <!-- kind 修饰类:--shell/--read/--edit/… -->
156
+ <button class="icen-ai-tool-head" aria-expanded="false">
157
+ <span class="icen-ai-item-icon"></span>
158
+ <span class="icen-ai-item-main"><span class="icen-ai-item-title">Read</span>
159
+ <span class="icen-ai-item-sub">src/foo.ts:1-50</span></span>
160
+ <span class="icen-ai-item-status"></span>
161
+ <span class="icen-ai-item-meta">0.4s</span>
161
162
  </button>
162
- <div class="ai-tool-body" hidden>
163
- <div class="ai-tool-io"><div class="ai-tool-io-label">输入</div><pre class="ai-tool-io-content">…</pre></div>
164
- <div class="ai-tool-io"><div class="ai-tool-io-label">输出</div><pre class="ai-tool-io-content">…</pre></div>
165
- <div class="ai-tool-approval"> <!-- 仅 .is-approval 显示 -->
166
- <button class="btn btn-sm btn-primary" data-ai-approve>允许</button>
167
- <button class="btn btn-sm" data-ai-reject>拒绝</button>
163
+ <div class="icen-ai-tool-body" hidden>
164
+ <div class="icen-ai-tool-io"><div class="icen-ai-tool-io-label">输入</div><pre class="icen-ai-tool-io-content">…</pre></div>
165
+ <div class="icen-ai-tool-io"><div class="icen-ai-tool-io-label">输出</div><pre class="icen-ai-tool-io-content">…</pre></div>
166
+ <div class="icen-ai-tool-approval"> <!-- 仅 .is-approval 显示 -->
167
+ <button class="icen-btn icen-btn-sm icen-btn-primary" data-icen-ai-approve>允许</button>
168
+ <button class="icen-btn icen-btn-sm" data-icen-ai-reject>拒绝</button>
168
169
  </div>
169
170
  </div>
170
171
  </div>
@@ -179,17 +180,17 @@ interface AiMessageModel {
179
180
  ### 4.5 ai-subagent(ai-tool.css + ai-tool.ts)
180
181
 
181
182
  ```html
182
- <div class="ai-subagent is-running">
183
- <button class="ai-subagent-head" aria-expanded="false">
184
- <span class="ai-item-icon"></span>
185
- <span class="ai-item-main"><span class="ai-item-title">explore</span>
186
- <span class="ai-item-sub">搜索 auth 模块的所有入口</span></span>
187
- <span class="ai-item-status"></span>
188
- <span class="ai-item-meta">12.3s · 4 步</span>
183
+ <div class="icen-ai-subagent is-running">
184
+ <button class="icen-ai-subagent-head" aria-expanded="false">
185
+ <span class="icen-ai-item-icon"></span>
186
+ <span class="icen-ai-item-main"><span class="icen-ai-item-title">explore</span>
187
+ <span class="icen-ai-item-sub">搜索 auth 模块的所有入口</span></span>
188
+ <span class="icen-ai-item-status"></span>
189
+ <span class="icen-ai-item-meta">12.3s · 4 步</span>
189
190
  </button>
190
- <div class="ai-subagent-body" hidden>
191
- <div class="ai-subagent-stream"><!-- 嵌套 .ai-item / .ai-tool / .ai-reasoning 活动流 --></div>
192
- <div class="ai-subagent-result">完成回执摘要</div>
191
+ <div class="icen-ai-subagent-body" hidden>
192
+ <div class="icen-ai-subagent-stream"><!-- 嵌套 .icen-ai-item / .icen-ai-tool / .icen-ai-reasoning 活动流 --></div>
193
+ <div class="icen-ai-subagent-result">完成回执摘要</div>
193
194
  </div>
194
195
  </div>
195
196
  ```
@@ -201,21 +202,21 @@ interface AiMessageModel {
201
202
  ### 4.6 ai-diff(ai-diff.css + ai-diff.ts)
202
203
 
203
204
  ```html
204
- <div class="ai-diff">
205
- <div class="ai-diff-file is-modified"> <!-- is-added/is-modified/is-deleted/is-renamed -->
206
- <div class="ai-diff-head">
207
- <span class="ai-diff-path">src/foo.ts</span>
208
- <span class="ai-diff-stat"><b class="ai-diff-add">+12</b> <b class="ai-diff-del">−4</b></span>
209
- <span class="ai-diff-actions">
210
- <button data-ai-diff-accept>接受</button><button data-ai-diff-reject>拒绝</button>
205
+ <div class="icen-ai-diff">
206
+ <div class="icen-ai-diff-file is-modified"> <!-- is-added/is-modified/is-deleted/is-renamed -->
207
+ <div class="icen-ai-diff-head">
208
+ <span class="icen-ai-diff-path">src/foo.ts</span>
209
+ <span class="icen-ai-diff-stat"><b class="icen-ai-diff-add">+12</b> <b class="icen-ai-diff-del">−4</b></span>
210
+ <span class="icen-ai-diff-actions">
211
+ <button data-icen-ai-diff-accept>接受</button><button data-icen-ai-diff-reject>拒绝</button>
211
212
  </span>
212
213
  </div>
213
- <div class="ai-diff-body" hidden>
214
- <table class="ai-diff-table">
215
- <tr class="ai-diff-line--hunk"><td colspan="3">@@ -10,6 +10,8 @@</td></tr>
216
- <tr class="ai-diff-line--ctx"><td class="ai-diff-ln">10</td><td class="ai-diff-ln">10</td><td class="ai-diff-code">…</td></tr>
217
- <tr class="ai-diff-line--add">…</tr>
218
- <tr class="ai-diff-line--del">…</tr>
214
+ <div class="icen-ai-diff-body" hidden>
215
+ <table class="icen-ai-diff-table">
216
+ <tr class="icen-ai-diff-line--hunk"><td colspan="3">@@ -10,6 +10,8 @@</td></tr>
217
+ <tr class="icen-ai-diff-line--ctx"><td class="icen-ai-diff-ln">10</td><td class="icen-ai-diff-ln">10</td><td class="icen-ai-diff-code">…</td></tr>
218
+ <tr class="icen-ai-diff-line--add">…</tr>
219
+ <tr class="icen-ai-diff-line--del">…</tr>
219
220
  </table>
220
221
  </div>
221
222
  </div>
@@ -229,8 +230,8 @@ interface AiMessageModel {
229
230
  ### 4.7 ai-files(ai-diff.css 一族,纯 CSS)
230
231
 
231
232
  ```html
232
- <div class="ai-files">
233
- <span class="ai-file-chip is-added"><span class="ai-file-icon"></span>src/foo.ts</span>
233
+ <div class="icen-ai-files">
234
+ <span class="icen-ai-file-chip is-added"><span class="icen-ai-file-icon"></span>src/foo.ts</span>
234
235
  </div>
235
236
  ```
236
237
 
@@ -240,68 +241,68 @@ chip 态:`is-added/is-modified/is-deleted` + hover 操作(可选)。无 be
240
241
 
241
242
  待办是**工具调用**(对话里只留折叠的 TodoWrite 卡,todo kind summarize 显示 x/y 完成),
242
243
  **实时状态挂在输入区**而非对话流:`setComposerTodo(el, items | null)` 在工具条渲染
243
- `.ai-composer-todo` chip(清单图标 + x/y;进行中 accent / 全部完成 success / 有失败
244
+ `.icen-ai-composer-todo` chip(清单图标 + x/y;进行中 accent / 全部完成 success / 有失败
244
245
  warning),点击弹层展示完整清单(popover + renderAiTodo 只读);传 null 清除。
245
246
 
246
247
  ### 4.8 ai-todo(ai-panel.css + ai-panel.ts)
247
248
 
248
249
  ```html
249
- <div class="ai-todo">
250
- <div class="ai-todo-head"><span class="ai-todo-progress">2/5</span><div class="ai-todo-bar"><i style="width:40%"></i></div></div>
251
- <div class="ai-todo-item is-running">
252
- <span class="ai-item-status"></span>
253
- <span class="ai-todo-text">实现登录页</span>
254
- <span class="ai-todo-active">正在实现登录页…</span> <!-- activeForm:运行中替换文案(Claude Code 模式) -->
250
+ <div class="icen-ai-todo">
251
+ <div class="icen-ai-todo-head"><span class="icen-ai-todo-progress">2/5</span><div class="icen-ai-todo-bar"><i style="width:40%"></i></div></div>
252
+ <div class="icen-ai-todo-item is-running">
253
+ <span class="icen-ai-item-status"></span>
254
+ <span class="icen-ai-todo-text">实现登录页</span>
255
+ <span class="icen-ai-todo-active">正在实现登录页…</span> <!-- activeForm:运行中替换文案(Claude Code 模式) -->
255
256
  </div>
256
257
  </div>
257
258
  ```
258
259
 
259
- - `renderAiTodo(el, items)`:`items: {content, status: AiStatus, activeForm?}[]`;`initAiTodo(root?)`:`data-ai-todo-interactive` 时可点击循环状态并派 `icen:ai-todo-toggle {index, status}`;默认只读。
260
+ - `renderAiTodo(el, items)`:`items: {content, status: AiStatus, activeForm?}[]`;`initAiTodo(root?)`:`data-icen-ai-todo-interactive` 时可点击循环状态并派 `icen:ai-todo-toggle {index, status}`;默认只读。
260
261
  - 进度条用 feedback 的 progress 视觉(token 消费)。
261
262
 
262
263
  ### 4.9 ai-usage(ai-panel.css + ai-panel.ts)
263
264
 
264
265
  ```html
265
- <div class="ai-usage">
266
- <div class="ai-usage-bar">
267
- <i class="ai-usage-seg ai-usage-seg--input" style="width:35%"></i>
268
- <i class="ai-usage-seg ai-usage-seg--cache-read" style="width:20%"></i>
269
- <i class="ai-usage-seg ai-usage-seg--cache-write" style="width:5%"></i>
270
- <i class="ai-usage-seg ai-usage-seg--reasoning" style="width:10%"></i>
271
- <i class="ai-usage-seg ai-usage-seg--output" style="width:12%"></i>
266
+ <div class="icen-ai-usage">
267
+ <div class="icen-ai-usage-bar">
268
+ <i class="icen-ai-usage-seg icen-ai-usage-seg--input" style="width:35%"></i>
269
+ <i class="icen-ai-usage-seg icen-ai-usage-seg--cache-read" style="width:20%"></i>
270
+ <i class="icen-ai-usage-seg icen-ai-usage-seg--cache-write" style="width:5%"></i>
271
+ <i class="icen-ai-usage-seg icen-ai-usage-seg--reasoning" style="width:10%"></i>
272
+ <i class="icen-ai-usage-seg icen-ai-usage-seg--output" style="width:12%"></i>
272
273
  </div>
273
- <div class="ai-usage-legend"><!-- 各段色点+数值;缓存分列(计费诚实) --></div>
274
- <div class="ai-usage-total">82k / 200k · 41%</div>
274
+ <div class="icen-ai-usage-legend"><!-- 各段色点+数值;缓存分列(计费诚实) --></div>
275
+ <div class="icen-ai-usage-total">82k / 200k · 41%</div>
275
276
  </div>
276
277
  ```
277
278
 
278
279
  - `renderAiUsage(el, usage: AiUsage, opts?: { total?: number; cost?: number })`:分段条 + 图例 + 占比;`normalizeUsage` 在 ai-core。
279
280
  - 配色:input=accent、output=success、cacheRead=info、cacheWrite=warning、reasoning=faint——语义 token。
280
- - **环形形态 `renderAiUsageRing`**(Claude Desktop 式上下文窗口指示器):紧凑圆环(SVG dasharray,`viewBox 36 / r 15.9155` → 周长恰为 100),中心百分比;点击弹出完整分段分解(弹层为一次性动态 `.popover.ai-usage-popover`,复用 `openPopover`/`closePopover`,anchor 豁免外点关闭,Esc/外点/再点关闭即移除)。状态档:<60% is-ok(accent)/ 60–85% is-warn / >85% is-hot(error + 脉冲)。`--lg` 大号变体。
281
+ - **环形形态 `renderAiUsageRing`**(Claude Desktop 式上下文窗口指示器):紧凑圆环(SVG dasharray,`viewBox 36 / r 15.9155` → 周长恰为 100),中心百分比;点击弹出完整分段分解(弹层为一次性动态 `.icen-popover.icen-ai-usage-popover`,复用 `openPopover`/`closePopover`,anchor 豁免外点关闭,Esc/外点/再点关闭即移除)。状态档:<60% is-ok(icen-accent)/ 60–85% is-warn / >85% is-hot(error + 脉冲)。`--lg` 大号变体。
281
282
 
282
283
  ### 4.10 ai-context(ai-panel.css + ai-panel.ts)—— 右上角资源抽屉
283
284
 
284
285
  ```html
285
- <aside class="ai-context" hidden>
286
- <div class="ai-context-head"><span>上下文</span><button data-ai-context-close>×</button></div>
287
- <section class="ai-context-section"><h3>用量</h3><!-- ai-usage --></section>
288
- <section class="ai-context-section"><h3>文件 (3)</h3><!-- ai-files chips --></section>
289
- <section class="ai-context-section"><h3>MCP (2)</h3><!-- server 行:名称+状态点+工具数 --></section>
290
- <section class="ai-context-section"><h3>Skills</h3><!-- skill chip 列表 --></section>
286
+ <aside class="icen-ai-context" hidden>
287
+ <div class="icen-ai-context-head"><span>上下文</span><button data-icen-ai-context-close>×</button></div>
288
+ <section class="icen-ai-context-section"><h3>用量</h3><!-- ai-usage --></section>
289
+ <section class="icen-ai-context-section"><h3>文件 (3)</h3><!-- ai-files chips --></section>
290
+ <section class="icen-ai-context-section"><h3>MCP (2)</h3><!-- server 行:名称+状态点+工具数 --></section>
291
+ <section class="icen-ai-context-section"><h3>Skills</h3><!-- skill chip 列表 --></section>
291
292
  </aside>
292
293
  ```
293
294
 
294
- - `initAiContext(root?)`:触发器 `[data-ai-context-open]` 全局委托开合;抽屉 fixed 右侧滑入(`--z-chrome`),Esc/外点关闭;`.ai-context--inline` 变体为页面流内嵌(不做 fixed)。开/合从抽屉根派 `icen:ai-context-open` / `icen:ai-context-close` `{}`。
295
+ - `initAiContext(root?)`:触发器 `[data-icen-ai-context-open]` 全局委托开合;抽屉 fixed 右侧滑入(`--icen-z-chrome`),Esc/外点关闭;`.icen-ai-context--inline` 变体为页面流内嵌(不做 fixed)。开/合从抽屉根派 `icen:ai-context-open` / `icen:ai-context-close` `{}`。
295
296
  - `renderAiContext(el, { usage?, files?, mcpServers?, skills? })`:组合渲染(内部复用 renderAiUsage / ai-files chip / ai-item 行)。
296
- - MCP server 行:`.ai-item` 基元 + `is-done`(已连接)/`is-error`(断开)。
297
+ - MCP server 行:`.icen-ai-item` 基元 + `is-done`(已连接)/`is-error`(断开)。
297
298
 
298
299
  ## 5. 事件汇总(全部 bubbles)
299
300
 
300
301
  | 事件 | detail | 来源 |
301
302
  |---|---|---|
302
- | `icen:ai-send` | `{text}` | composer 发送 |
303
+ | `icen:ai-send` | `{text, refs?, files?}` | composer 发送快照 |
303
304
  | `icen:ai-stop` | `{}` | composer 停止 |
304
- | `icen:ai-queue` / `icen:ai-dequeue` | `{text}` / `{index}` | 排队消息 |
305
+ | `icen:ai-queue` / `icen:ai-dequeue` | `{text, refs?, files?}` / `{index}` | 排队消息快照 |
305
306
  | `icen:ai-attach` | `{files}` | 附件(钮选 / 粘贴 / 拖放共用) |
306
307
  | `icen:ai-copy` / `icen:ai-retry` | `{el}` | 消息操作 |
307
308
  | `icen:ai-approve` / `icen:ai-reject` | `{id, kind}` | 工具审批 |
@@ -320,7 +321,7 @@ warning),点击弹层展示完整清单(popover + renderAiTodo 只读)
320
321
  ```ts
321
322
  export type AiStatus = 'pending'|'running'|'streaming'|'approval'|'done'|'error'|'cancelled';
322
323
  export interface AiUsage { input?; output?; cacheRead?; cacheWrite?; reasoning?; total?; }
323
- export interface AiKindDef { label: string; icon: string; tint?: 'accent'|'success'|'warning'|'error'|'info'|'muted'; summarize?: (input: unknown) => string; }
324
+ export interface AiKindDef { label: string; icon: string; tint?: 'icen-accent'|'success'|'warning'|'error'|'info'|'muted'; summarize?: (input: unknown) => string; }
324
325
  export interface AiToolCallModel {
325
326
  id: string; name: string; kind: string; status: AiStatus;
326
327
  input?: unknown; output?: unknown; errorText?: string;
@@ -356,18 +357,18 @@ export function svgIcon(svg: string): SVGElement | null; // DOMParser 消毒(
356
357
  结构(自底向上工具条,业界主流形态):
357
358
 
358
359
  ```html
359
- <div class="ai-composer" data-ai-composer>
360
- <div class="ai-composer-queue" hidden></div> <!-- 排队 chips(v1 已有) -->
361
- <div class="ai-composer-refs" hidden></div> <!-- @ 引用 chips(分离渲染:textarea 不嵌 chip) -->
362
- <div class="ai-composer-attach" hidden></div> <!-- 附件 chips(v1 已有) -->
363
- <div class="ai-composer-box control">
364
- <textarea class="ai-composer-input" rows="1"></textarea>
365
- <div class="ai-composer-toolbar">
366
- <button class="ai-composer-model" data-ai-model-open> <!-- 模型切换:provider 图标 + 模型名 + chevron -->
367
- <span class="ai-composer-spacer"></span>
368
- <span class="ai-composer-usage" data-ai-usage></span> <!-- 上下文环挂载点 -->
369
- <button class="ai-composer-btn" data-ai-attach></button>
370
- <button class="ai-composer-send" data-ai-send></button>
360
+ <div class="icen-ai-composer" data-icen-ai-composer>
361
+ <div class="icen-ai-composer-queue" hidden></div> <!-- 排队 chips(v1 已有) -->
362
+ <div class="icen-ai-composer-refs" hidden></div> <!-- @ 引用 chips(分离渲染:textarea 不嵌 chip) -->
363
+ <div class="icen-ai-composer-attach" hidden></div> <!-- 附件 chips(v1 已有) -->
364
+ <div class="icen-ai-composer-box icen-control">
365
+ <textarea class="icen-ai-composer-input" rows="1"></textarea>
366
+ <div class="icen-ai-composer-toolbar">
367
+ <button class="icen-ai-composer-model" data-icen-ai-model-open> <!-- 模型切换:provider 图标 + 模型名 + chevron -->
368
+ <span class="icen-ai-composer-spacer"></span>
369
+ <span class="icen-ai-composer-usage" data-icen-ai-usage></span> <!-- 上下文环挂载点 -->
370
+ <button class="icen-ai-composer-btn" data-icen-ai-attach></button>
371
+ <button class="icen-ai-composer-send" data-icen-ai-send></button>
371
372
  </div>
372
373
  </div>
373
374
  </div>
@@ -377,15 +378,15 @@ export function svgIcon(svg: string): SVGElement | null; // DOMParser 消毒(
377
378
 
378
379
  - `setComposerModels(el, providers: AiProviderOption[], current?: {provider, model})`:
379
380
  `AiProviderOption = { id, label, icon?, models: { id, label, context? }[] }`。
380
- 工具条出现模型钮;点击开 `.ai-composer-popup`(portal body,`computePopoverLayout` side:top)——
381
- 按 provider 分组(图标+名)+ 模型行(label + 上下文窗口如 `1M`)+ 搜索过滤 + 当前勾选。
381
+ 工具条出现模型钮;点击开 `.icen-ai-composer-popup`(portal body,`computePopoverLayout` side:top)——
382
+ 按 provider 分组(图标+名)+ 模型行(label + 上下文窗口如 `1M`)+ 搜索过滤 + 当前轻高亮与内描边。
382
383
  选择派 `icen:ai-model-change { provider, model, label, context }`;
383
384
  **切换时若 cacheRead 占比高则弹层内提示"换模型会使 prompt 缓存失效"**(Kimi Code 细节)。
384
385
  选中模型的 `context` 自动作为 `setComposerUsage` 的 total 默认值(闭环)。
385
386
  - `setComposerCommands(el, commands: { name, description?, argsHint? }[])`:
386
387
  输入开头为 `/` 时弹层过滤;↑↓ 导航、Enter/Tab 选中、Esc 关;选中派 `icen:ai-command { name, args }`
387
388
  并清空输入(命令被拦截执行、不进消息流——业界共识)。
388
- - `setComposerRefs(el, sources: { kind: 'file'|'folder'|'doc'|'agent', id, label, sub? }[])`:
389
+ - `setComposerRefs(el, sources: { kind: 'skill'|'tool'|'file'|'folder'|'doc'|'agent' | string, id, label, sub? }[])`:
389
390
  任意位置输入 `@` 触发弹层(分组按 kind + 图标);选中后文本插入 `@label ` 且 refs chip 行 +1,
390
391
  派 `icen:ai-ref { action: 'add', ref }`;chip × 移除(同时删文本里首个 `@label`)派 `{ action: 'remove' }`。
391
392
  kind 开放注册:`registerRefKind(kind, { label, icon?, order? })`(照 registerAiKind 的 Map + 兜底模式);
@@ -393,8 +394,8 @@ export function svgIcon(svg: string): SVGElement | null; // DOMParser 消毒(
393
394
  - `setComposerUsage(el, usage, opts)`:工具条右侧挂 `renderAiUsageRing`。
394
395
  - 历史:输入为空时按 `↑` 取回上一条已发送文本(会话内历史数组,每 composer 独立)。
395
396
  - 运行态(v1 已有 queue/stop)补充:运行中按 `↑` 把最后一条排队消息取回输入框重新编辑(Claude Code 模式)。
396
- - 弹层接管时键盘事件 preventDefault;IME 组合态安全(沿用 v1)。
397
- - 三弹层尺寸走 PanelSizing 契约:composer 根 `data-panel-*` 为用户覆盖(三弹层共用),
397
+ - 弹层接管方向与确认键,目录/模型搜索保留正常 Tab;IME 组合态安全。
398
+ - 四弹层尺寸走 PanelSizing 契约:composer 根 `data-panel-*` 为用户覆盖(四弹层共用),
398
399
  `bindComposer` opts.popoverSizing 整体覆盖,原内置魔数仅为默认。
399
400
  - 图标对齐修复:工具条按钮统一 28px 方形、svg 14px 居中、gap 走 density token。
400
401
 
@@ -491,7 +492,7 @@ client 每次请求自动产审计记录(onAudit 回调 + 若传了 auditor
491
492
 
492
493
  ---
493
494
 
494
- ## 10. 标准化内容模型 `AiContent`(v0.7.1 新增,ai-core)
495
+ ## 10. 标准化内容模型 `AiContent`(ai-core)
495
496
 
496
497
  > 调研依据(2026-10):Vercel AI SDK v5 UIMessage parts(text / reasoning / tool-\<name\> 六态 / file{mediaType,url} / source-url / source-document / data-*)、
497
498
  > MCP 内容类型(TextContent / ImageContent / AudioContent / ResourceLink / EmbeddedResource + structuredContent,全部带 annotations)、
@@ -553,7 +554,7 @@ export function contextEstimate(usage: AiUsage): number;
553
554
 
554
555
  ---
555
556
 
556
- ## 11. 绑定层 `bindComposer`(v0.7.1 新增,ai-composer.ts)
557
+ ## 11. 绑定层 `bindComposer`(ai-composer.ts)
557
558
 
558
559
  「零接线全链路」的胶水:**事件驱动、消费方拥有传输会话的所有权不变**。绑定层监听 §5 的 `icen:ai-*` 事件把 composer ↔ 消息区 ↔ client ↔ 用量环接成闭环。
559
560
 
@@ -562,25 +563,27 @@ export interface AiComposerBindOpts {
562
563
  client?: AiClient; // 传入即托管对话:send → 用户消息渲染 + running + client.stream
563
564
  // → assistant 消息 + createAiStream 逐 chunk 追加 → done 收尾
564
565
  // (错误 → fail + setError;stop → session.cancel;排队消息在
565
- // 每轮完成后自动发送下一条)
566
- messages?: HTMLElement; // .ai-chat-scroll 或任意消息容器:renderAiMessage 的挂载点(client 模式必填)
566
+ // 成功后自动续发,停止/失败则暂停队列)
567
+ messages?: HTMLElement; // .icen-ai-chat-scroll 或任意消息容器:renderAiMessage 的挂载点(client 模式必填)
567
568
  usage?: { from: 'context' | 'billing' | AiAuditor; total?: number };
568
569
  // 环口径:'context'(默认,icen:ai-done 的 contextEstimate——环语义正确)
569
570
  // | 'billing'(icen:ai-done 的请求 usage 累加——计费视角)
570
571
  // | 传 auditor 实例则用其 summary()
571
572
  running?: boolean; // 运行态自动管理(默认 true):icen:ai-send → running;icen:ai-done → 解除
572
573
  }
573
- export interface AiComposerBinding { unbind(): void }
574
+ export interface AiComposerBinding { retry(): boolean; unbind(): void }
574
575
  export function bindComposer(el: HTMLElement, opts?: AiComposerBindOpts): AiComposerBinding;
575
576
  ```
576
577
 
577
578
  - **client 模式**下 stop 钮绑定 `session.cancel()`;`icen:ai-done` 的 `cost` 自动进环的 `opts.cost` 累计;assistant 消息 meta 自动填 token 数与模型名。
579
+ - 停止立即结束本轮 UI,保留部分输出并暂停排队;空输入框按 ↑ 可取回待发消息。停止/解绑后迟到的 chunk 与 done 不能覆写状态或继续发送队列。
580
+ - 最近失败或停止的回答可通过 `binding.retry()` 或消息的继续生成/重试事件原位重试;保留消息节点与当前输入草稿,不重复添加用户消息。忙碌、已解绑或没有可重试回答时返回 false。更早消息和成功回答的重试仍由宿主处理。
578
581
  - 不传 client 时是纯状态绑定(send→running、done→解除、环更新),传输仍归消费方——**渐进采用**。
579
582
  - composer 同时新增:粘贴文件与拖放文件落附件(`icen:ai-attach` 同事件);`MODEL_CTX` 在选中模型无 `context` 时显式清除(环回退无上限形态)。
580
583
 
581
584
  ---
582
585
 
583
- ## 12. 定价与审计闭环(v0.7.1 新增,ai-provider.ts + ai-panel.ts)
586
+ ## 12. 定价与审计闭环(ai-provider.ts + ai-panel.ts)
584
587
 
585
588
  ### 12.1 定价表(注册表内联,USD / MTok,2026-10 调研近似值)
586
589
 
@@ -609,54 +612,142 @@ GLM-5.x ~$0.5/$3 档;Kimi K3 $3/$15、缓存读 ~$0.3,K2.6 ~$0.95/$3)。ca
609
612
 
610
613
  ---
611
614
 
612
- ## 13. AI 工具体系(v0.8,`src/behaviors/ai-tools.ts`)
615
+ ## 13. AI 工具体系(`src/behaviors/ai-tools.ts`)
613
616
 
614
617
  > 任何 UI 能力(图表渲染、未来的 diff 应用 / todo 写入……)注册为 **AiToolDef**,
615
618
  > 模型侧可调用、宿主侧全控。库内置 `render_chart` 一个工具(吃 ChartSpec 纯 JSON)。
619
+ > 设计纪律:**诚实失败优先于智能猜测**——参数校验不支持的关键字记清单不静默,
620
+ > 超时/拒绝/失败一律落 `record.icen-result = { ok:false, error:{ code, … } }` 信封。
616
621
 
617
- ### 13.1 注册表
622
+ ### 13.1 注册表(AiToolDef 执行契约)
618
623
 
619
624
  ```ts
625
+ export interface AiToolRunContext {
626
+ signal: AbortSignal; // 超时、卡片移除/淘汰/清空、unregister 时 abort
627
+ progress(line: string): void; // 活动流:追加进挂载卡 .icen-ai-tools-item-stream
628
+ }
629
+
620
630
  export interface AiToolDef<TInput = unknown> {
621
631
  name: string; // 模型侧 function name(snake_case)
622
- description: string; // 给模型看的说明
632
+ description: string; // 给模型看的说明;requiresApproval 时兼作审批区原因行
623
633
  inputSchema: Record<string, unknown>; // OpenAI parameters / MCP inputSchema 兼容
624
- run: (input: TInput, mount: HTMLElement) => unknown; // 在挂载点上渲染,返回值即工具结果
634
+ run: (input: TInput, mount: HTMLElement, ctx: AiToolRunContext) => unknown;
625
635
  present?: 'mount' | 'data';
636
+ timeoutMs?: number; // 超时 → { ok:false, error:{ code:'timeout' } }(只作用于 Promise 型 run)
637
+ requiresApproval?: boolean; // 执行前审批门禁(仅 'mount' 模式生效;'data' 无卡可审批)
638
+ idempotent?: boolean; // 同名同输入在途调用复用同一条记录
626
639
  }
627
640
  registerAiTool(def) / unregisterAiTool(name) / getAiTool(name) / listAiTools()
628
641
  ```
629
642
 
630
- ### 13.2 挂载区(挂不挂 / 挂哪些 / 挂几个——宿主三层控制)
643
+ - **Promise 结果契约**:`run` 允许返回 Promise;area 在落定后写 `record.icen-result` 并补派
644
+ `icen:ai-tool-result`(落定前不派)。超时竞速后晚到的兑现/拒绝被丢弃并吞掉
645
+ (不冒 unhandledrejection)。
646
+ - **timeoutMs 诚实边界**:只作用于 Promise 型 run——同步 run 在单线程内无法中断,
647
+ 设了也不生效(不假装)。定时器触发 → `signal.abort()` + 结果
648
+ `{ ok:false, error:{ code:'timeout', timeoutMs } }`,卡片 `.is-error`。
649
+ - **失败统一信封**:校验失败 `code:'validation'`(含 errors/unvalidated 明细)、
650
+ 执行异常 `code:'exec'`(含 message)、超时 `code:'timeout'`、审批拒绝 `code:'rejected'`。
651
+ 事件 `icen:ai-tool-result` 的 `error` 字段按 events.ts 契约为 **string** 摘要,
652
+ 机器可读细节一律在 `record.icen-result`。
653
+
654
+ ### 13.2 参数校验 `validateToolArgs`(诚实纪律)
655
+
656
+ ```ts
657
+ validateToolArgs(schema, args) → { ok, errors: { path, message }[], unvalidated: string[] }
658
+ ```
659
+
660
+ - 支持关键字:`type`(object/array/string/number/integer/boolean/null)/ `required` /
661
+ `properties`(递归不限深度)/ `enum` / `items`(**只展开一层**:二层数组记
662
+ `unvalidated` 不展开)/ `minimum` / `maximum` / `minLength` / `maxLength`。
663
+ - **不支持的关键字不猜不静默**:`oneOf`/`anyOf`/`allOf`/`not`/`$ref`/`format`/`pattern`/
664
+ `additionalProperties`/`minItems`/`uniqueItems` 等出现在**实际访问到的节点**上时,
665
+ 以 schema 路径(`'$.properties.email.format'`、`'$.properties.matrix.items.items'`、
666
+ 根节点直接 `'$.additionalProperties'`)记入 `unvalidated`,
667
+ 该断言不生效也不报错。注解类关键字(description/title/default/examples…)不作出
668
+ 校验承诺,静默跳过、不进清单。未访问节点的关键字不进清单(清单只对实际校验负责)。
669
+ - 错误 `path` 为 JSON-pointer 风参数路径(`'$'` 根;`'$.tags[1]'`、`'$.series[2].name'`);
670
+ 多错误并列收集不短路。`args` 为 `undefined` 的可选字段不做任何断言(由 required 把关)。
671
+ - `parseAiToolArgs(raw)` 保持现状:模型回包容错解析(JSON 字符串/对象/坏 JSON → `{}),
672
+ 不做校验——校验只走 `validateToolArgs`。
673
+
674
+ ### 13.3 挂载区(挂不挂 / 挂哪些 / 挂几个——宿主三层控制)
631
675
 
632
676
  ```ts
633
677
  createAiToolArea(el, { tools?: string[]; max?: number; itemMinHeight?: number }) → AiToolArea
634
- // tools 白名单支持通配 'chart-*';max 超出 FIFO 淘汰最旧挂载(present:'data' 的工具不占挂载位、不参与淘汰)
635
- // AiToolArea: { el, count, call(name, input), can(name), setTools, setMax, clear, onChange(fn) }
678
+ // tools 白名单支持通配 'chart-*';max 超出 LRU 淘汰最旧挂载(present:'data' 的工具不占挂载位、不参与淘汰)
679
+ // AiToolArea: { el, count, call(name, input, opts?), can(name), setTools, setMax, clear, onChange(fn) }
680
+ call(name, input, opts?: { validate?: boolean }) // validate 默认 true:校验失败不执行 run
636
681
  ```
637
682
 
638
683
  - 三层控制:① 不 import 本模块 = 生态无工具体系(tree-shake);② area 白名单 + max;
639
- ③ 运行时 setTools/setMax/clear + unregisterAiTool 全局下架。
640
- - 挂载项结构:`.ai-tools-mount > .ai-tools-item > head(折叠钮 chevron/工具名/时间/×,button,aria-expanded)+ body(工具自渲染,默认展开,head 点击折叠;× 拦截冒泡只做移除)`。
641
- - 事件(bubbles):`icen:ai-tool-call {name, input, el}` / `icen:ai-tool-result {name, ok, el, error?, count}`
642
- / `icen:ai-tool-evict {name, el}`。
643
-
644
- ### 13.3 模型侧导出(agent loop 直接消费)
684
+ ③ 运行时 setTools/setMax/clear + unregisterAiTool 全局下架(联动摘除各区域已挂载卡)。
685
+ - **call 管线**:白名单/注册检查 → `parseAiToolArgs` 归一 → 校验(可关)→ 幂等复用 →
686
+ 挂载卡('mount')/ 纯记录('data')→ 审批门禁(requiresApproval)→ 执行。
687
+ 每次 call 在挂载时触发一次 `onChange`,result 落定时再触发一次。
688
+ - 挂载卡结构(状态类挂 `.icen-ai-tools-item`,7 态状态机的挂载区形态):
689
+
690
+ ```
691
+ .icen-ai-tools-mount > .icen-ai-tools-item(.is-approval/.is-running/.is-done/.is-error/.is-cancelled)
692
+ > head(折叠钮 chevron/工具名/时间/状态点 .icen-ai-tools-item-status/×,button,aria-expanded)
693
+ + .icen-ai-tools-item-approval(仅审批态:原因行 = description + 归一输入 JSON 预览 + 批准/拒绝钮,裁决后移除)
694
+ + .icen-ai-tools-item-error(仅失败态:逐行一条错误,role=alert)
695
+ + .icen-ai-tools-item-body(工具自渲染,默认展开,head 点击折叠;折叠同时隐藏活动流)
696
+ + .icen-ai-tools-item-stream(活动流,progress(line) 懒建追加)
697
+ ```
698
+
699
+ - 校验失败仍挂载错误态卡(逐条列出 errors)并成对派 call + result(审计可关联),不执行 run。
700
+ - 事件(bubbles,全部经 emitIcen):`icen:ai-tool-call {name, input, el}`(挂载即派,input 为原始入参)/
701
+ `icen:ai-tool-result {name, ok, el, error?, count}`(error 为 string 摘要)/
702
+ `icen:ai-tool-evict {name, el}`。审批两事件见 §13.4。
703
+ - `ctx.signal` 中止时机:超时触发、卡片被 × 移除/LRU 淘汰/clear/unregister 下架。
704
+
705
+ ### 13.4 审批流与幂等(requiresApproval / idempotent)
706
+
707
+ - **requiresApproval**:call 时挂载卡进入 `.is-approval`(warning 边框 + 状态点外环),
708
+ 审批区 = 原因行(description)+ 输入 JSON 预览 + 批准/拒绝按钮。**批准** → 派
709
+ `icen:ai-tool-approve {name, input, el}`(input 为归一后的 Record)→ 移除审批区 →
710
+ 执行 run;**拒绝** → 派 `icen:ai-tool-reject {name, input, el}` → 卡片 `.is-cancelled`
711
+ (标题删除线),结果 `{ ok:false, error:{ code:'rejected' } }`,result 事件 `ok:false`。
712
+ 'data' 模式无挂载卡,requiresApproval 不生效(文档注明,不静默假装有门禁)。
713
+ - **idempotent**:以 `name + JSON.stringify(parseAiToolArgs(input))` 为键——JSON 字符串与
714
+ 对象形态的同输入同键;在途(执行中/待审批)的同键调用返回**同一条 record 引用**
715
+ (不重复挂载、不重复执行);落定后同键调用正常重新执行。
716
+
717
+ ### 13.5 模型侧导出(agent loop 直接消费;四族共享同一归一管线)
645
718
 
646
719
  ```ts
647
- aiToolsToOpenAI(names?) // → chat.completions tools 参数格式
648
- aiToolsToMcp(names?) // → MCP tools 格式(name/description/inputSchema)
649
- aiToolsManifest(names?) // → system prompt 能力清单文本
650
- parseAiToolArgs(raw) // tool_call 参数容错解析(JSON 字符串/对象/坏 JSON→{})
720
+ aiToolsToOpenAI(names?) // → [{ type:'function', function:{ name, description, parameters } }]
721
+ aiToolsToAnthropic(names?) // → [{ name, description, input_schema }]
722
+ aiToolsToMcp(names?) // → [{ name, description, inputSchema }]
723
+ aiToolsToAiSdk(names?) // → Record<name, { description, inputSchema }>——Vercel AI SDK v5 tool() 描述表
724
+ aiToolsManifest(names?) // → system prompt 能力清单文本
725
+ parseAiToolArgs(raw) // tool_call 参数容错解析(JSON 字符串/对象/坏 JSON→{})
651
726
  ```
652
727
 
653
- 宿主 agent loop 接线:模型回 `render_chart` tool_call → `area.call('render_chart', parseAiToolArgs(args))`。
728
+ - 四族经私有 `toDescriptor` 归一后各自映射(names 缺省 = 全部,支持通配过滤),
729
+ name/description/inputSchema 内容严格一致;`aiToolsToAiSdk` **不携带 execute**——
730
+ 执行永远留在宿主侧(createAiToolArea 挂载)。
731
+ - 宿主 agent loop 接线:模型回 `render_chart` tool_call →
732
+ `area.call('render_chart', parseAiToolArgs(args))`。
733
+
734
+ ### 13.6 `render_chart` 内置工具(schema 先行)
735
+
736
+ - inputSchema = ChartSpec JSON Schema(§13.7 接缝全数继承);另声明三个可选字段描述,
737
+ 渲染层随图表重度场景落地(schema-ahead,不提前实现):`downsample?: boolean|number`
738
+ (true=自动上限,数字=最大保留点数)、`zoom?: 'x'|'brush'`、`marks?: array`(标记层
739
+ 描述子)。`downsample` 的联合类型(type 数组)走 validateToolArgs 诚实清单。
654
740
 
655
- ### 13.4 图表与 AI 族的接缝
741
+ ### 13.7 图表与 AI 族的接缝
656
742
 
657
743
  - `render_chart` 工具:inputSchema = ChartSpec JSON Schema;run = renderChart(自动选型 /
658
744
  容错归一 / 交互事件族 / 可隐藏图例全数继承)。
659
745
  - **工具回执内嵌图**:`renderAiToolCall` 的 output 为 `{type:'chart', spec}` 信封或裸
660
- ChartSpec 时,IO 区直接渲染小图(`chartSpecOf` 探测,`.ai-tool-io-chart` 容器)。
746
+ ChartSpec 时,IO 区直接渲染小图(`chartSpecOf` 探测,`.icen-ai-tool-io-chart` 容器)。
661
747
  - **kind**:ai-core 内置 `chart` kind(折线图标,info tint,summarize 取 title);
662
748
  `inferKind`:工具名含 chart/plot/visualize → 'chart'。
749
+
750
+
751
+ ## 输入体验续修(2026-10-18)
752
+
753
+ 资源目录、技能/工具分组、可取消上传适配、独立请求快照和键盘/视觉契约见 [AI 输入体验](ai-input-experience.md)。新增字段全部可选。纯文本没有额外 payload 字段;选中文件需要宿主 prepareMessage 上传适配,不会默认丢弃附件。