@huyooo/ai-chat-frontend-react 0.2.13 → 0.2.14

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 (109) hide show
  1. package/README.md +99 -84
  2. package/dist/KaTeX_AMS-Regular-CYEKBG2K.woff +0 -0
  3. package/dist/KaTeX_AMS-Regular-JKX5W2C4.ttf +0 -0
  4. package/dist/KaTeX_AMS-Regular-U6PRYMIZ.woff2 +0 -0
  5. package/dist/KaTeX_Caligraphic-Bold-5QL5CMTE.woff2 +0 -0
  6. package/dist/KaTeX_Caligraphic-Bold-WZ3QSGD3.woff +0 -0
  7. package/dist/KaTeX_Caligraphic-Bold-ZTS3R3HK.ttf +0 -0
  8. package/dist/KaTeX_Caligraphic-Regular-3LKEU76G.woff +0 -0
  9. package/dist/KaTeX_Caligraphic-Regular-A7XRTZ5Q.ttf +0 -0
  10. package/dist/KaTeX_Caligraphic-Regular-KX5MEWCF.woff2 +0 -0
  11. package/dist/KaTeX_Fraktur-Bold-2QVFK6NQ.woff2 +0 -0
  12. package/dist/KaTeX_Fraktur-Bold-T4SWXBMT.woff +0 -0
  13. package/dist/KaTeX_Fraktur-Bold-WGHVTYOR.ttf +0 -0
  14. package/dist/KaTeX_Fraktur-Regular-2PEIFJSJ.woff2 +0 -0
  15. package/dist/KaTeX_Fraktur-Regular-5U4OPH2X.ttf +0 -0
  16. package/dist/KaTeX_Fraktur-Regular-PQMHCIK6.woff +0 -0
  17. package/dist/KaTeX_Main-Bold-2GA4IZIN.woff +0 -0
  18. package/dist/KaTeX_Main-Bold-W5FBVCZM.ttf +0 -0
  19. package/dist/KaTeX_Main-Bold-YP5VVQRP.woff2 +0 -0
  20. package/dist/KaTeX_Main-BoldItalic-4P4C7HJH.woff +0 -0
  21. package/dist/KaTeX_Main-BoldItalic-N4V3DX7S.woff2 +0 -0
  22. package/dist/KaTeX_Main-BoldItalic-ODMLBJJQ.ttf +0 -0
  23. package/dist/KaTeX_Main-Italic-I43T2HSR.ttf +0 -0
  24. package/dist/KaTeX_Main-Italic-RELBIK7M.woff2 +0 -0
  25. package/dist/KaTeX_Main-Italic-SASNQFN2.woff +0 -0
  26. package/dist/KaTeX_Main-Regular-ARRPAO67.woff2 +0 -0
  27. package/dist/KaTeX_Main-Regular-P5I74A2A.woff +0 -0
  28. package/dist/KaTeX_Main-Regular-W74P5G27.ttf +0 -0
  29. package/dist/KaTeX_Math-BoldItalic-6EBV3DK5.woff +0 -0
  30. package/dist/KaTeX_Math-BoldItalic-K4WTGH3J.woff2 +0 -0
  31. package/dist/KaTeX_Math-BoldItalic-VB447A4D.ttf +0 -0
  32. package/dist/KaTeX_Math-Italic-6KGCHLFN.woff2 +0 -0
  33. package/dist/KaTeX_Math-Italic-KKK3USB2.woff +0 -0
  34. package/dist/KaTeX_Math-Italic-SON4MRCA.ttf +0 -0
  35. package/dist/KaTeX_SansSerif-Bold-RRNVJFFW.woff2 +0 -0
  36. package/dist/KaTeX_SansSerif-Bold-STQ6RXC7.ttf +0 -0
  37. package/dist/KaTeX_SansSerif-Bold-X5M5EMOD.woff +0 -0
  38. package/dist/KaTeX_SansSerif-Italic-HMPFTM52.woff2 +0 -0
  39. package/dist/KaTeX_SansSerif-Italic-PSN4QKYX.woff +0 -0
  40. package/dist/KaTeX_SansSerif-Italic-WTBAZBGY.ttf +0 -0
  41. package/dist/KaTeX_SansSerif-Regular-2TL3USAE.ttf +0 -0
  42. package/dist/KaTeX_SansSerif-Regular-OQCII6EP.woff +0 -0
  43. package/dist/KaTeX_SansSerif-Regular-XIQ62X4E.woff2 +0 -0
  44. package/dist/KaTeX_Script-Regular-72OLXYNA.ttf +0 -0
  45. package/dist/KaTeX_Script-Regular-A5IFOEBS.woff +0 -0
  46. package/dist/KaTeX_Script-Regular-APUWIHLP.woff2 +0 -0
  47. package/dist/KaTeX_Size1-Regular-4HRHTS65.woff +0 -0
  48. package/dist/KaTeX_Size1-Regular-5LRUTBFT.woff2 +0 -0
  49. package/dist/KaTeX_Size1-Regular-7K6AASVL.ttf +0 -0
  50. package/dist/KaTeX_Size2-Regular-222HN3GT.ttf +0 -0
  51. package/dist/KaTeX_Size2-Regular-K5ZHAIS6.woff +0 -0
  52. package/dist/KaTeX_Size2-Regular-LELKET5D.woff2 +0 -0
  53. package/dist/KaTeX_Size3-Regular-TLFPAHDE.woff +0 -0
  54. package/dist/KaTeX_Size3-Regular-UFCO6WCA.ttf +0 -0
  55. package/dist/KaTeX_Size3-Regular-WQRQ47UD.woff2 +0 -0
  56. package/dist/KaTeX_Size4-Regular-7PGNVPQK.ttf +0 -0
  57. package/dist/KaTeX_Size4-Regular-CDMV7U5C.woff2 +0 -0
  58. package/dist/KaTeX_Size4-Regular-PKMWZHNC.woff +0 -0
  59. package/dist/KaTeX_Typewriter-Regular-3F5K6SQ6.ttf +0 -0
  60. package/dist/KaTeX_Typewriter-Regular-MJMFSK64.woff +0 -0
  61. package/dist/KaTeX_Typewriter-Regular-VBYJ4NRC.woff2 +0 -0
  62. package/dist/index.css +2156 -603
  63. package/dist/index.css.map +1 -1
  64. package/dist/index.d.ts +126 -92
  65. package/dist/index.js +1599 -981
  66. package/dist/index.js.map +1 -1
  67. package/dist/style.css +130 -0
  68. package/package.json +3 -3
  69. package/src/components/ChatPanel.tsx +82 -19
  70. package/src/components/common/SettingsPanel.css +81 -0
  71. package/src/components/common/SettingsPanel.tsx +96 -1
  72. package/src/components/input/ChatInput.css +0 -1
  73. package/src/components/input/ChatInput.tsx +48 -26
  74. package/src/components/input/DropdownSelector.css +66 -0
  75. package/src/components/input/DropdownSelector.tsx +157 -19
  76. package/src/components/message/MessageBubble.css +5 -2
  77. package/src/components/message/MessageBubble.tsx +44 -35
  78. package/src/components/message/PartsRenderer.css +8 -0
  79. package/src/components/message/PartsRenderer.tsx +137 -83
  80. package/src/components/message/parts/CollapsibleCard.css +4 -2
  81. package/src/components/message/parts/CollapsibleCard.tsx +4 -1
  82. package/src/components/message/parts/ImagePart.css +0 -1
  83. package/src/components/message/parts/TextPart.css +574 -5
  84. package/src/components/message/parts/TextPart.tsx +201 -8
  85. package/src/components/message/parts/ToolCallPart.css +139 -115
  86. package/src/components/message/parts/ToolCallPart.tsx +138 -134
  87. package/src/components/message/parts/ToolResultPart.css +0 -1
  88. package/src/components/message/parts/index.ts +3 -1
  89. package/src/components/message/parts/visual-predicate.ts +43 -0
  90. package/src/components/message/parts/visual-render.ts +19 -0
  91. package/src/components/message/parts/visual.ts +12 -0
  92. package/src/context/RenderersContext.tsx +19 -25
  93. package/src/hooks/useChat.ts +567 -79
  94. package/src/hooks/useImageUpload.ts +104 -12
  95. package/src/index.ts +19 -16
  96. package/src/styles.css +130 -0
  97. package/src/types/index.ts +52 -68
  98. package/src/components/message/ContentRenderer.tsx +0 -63
  99. package/src/components/message/ToolResultRenderer.tsx +0 -21
  100. package/src/components/message/blocks/CodeBlock.tsx +0 -60
  101. package/src/components/message/blocks/TextBlock.tsx +0 -15
  102. package/src/components/message/blocks/blocks.css +0 -141
  103. package/src/components/message/blocks/index.ts +0 -6
  104. package/src/components/message/parts/ToolResultPart.tsx +0 -96
  105. package/src/components/message/tool-results/DefaultToolResult.tsx +0 -26
  106. package/src/components/message/tool-results/SearchResults.tsx +0 -69
  107. package/src/components/message/tool-results/WeatherCard.tsx +0 -63
  108. package/src/components/message/tool-results/index.ts +0 -7
  109. package/src/components/message/tool-results/tool-results.css +0 -181
package/README.md CHANGED
@@ -39,6 +39,7 @@ function App() {
39
39
  models={modelList}
40
40
  hideHeader={false}
41
41
  welcomeConfig={welcomeConfig}
42
+ partRenderers={partRenderers}
42
43
  onClose={handleClose}
43
44
  />
44
45
  ```
@@ -55,8 +56,7 @@ function App() {
55
56
  | `hideHeader` | `boolean` | `false` | 是否隐藏标题栏 |
56
57
  | `welcomeConfig` | `Partial<WelcomeConfig>` | - | 欢迎页配置 |
57
58
  | `stepsExpandedType` | `'open' \| 'close' \| 'auto'` | `'auto'` | 执行步骤展开模式 |
58
- | `toolRenderers` | `ToolRenderers` | `{}` | 自定义工具结果渲染器 |
59
- | `blockRenderers` | `BlockRenderers` | `{}` | 自定义内容块渲染器 |
59
+ | `partRenderers` | `PartRenderers` | `{}` | 自定义 Part 类型渲染器 |
60
60
  | `autoRunConfig` | `AutoRunConfig` | - | 自动运行配置 |
61
61
  | `onClose` | `() => void` | - | 关闭回调 |
62
62
  | `onToolComplete` | `(event: ToolCompleteEvent) => void` | - | 工具执行完成回调 |
@@ -197,26 +197,45 @@ const welcomeConfig = {
197
197
  }
198
198
  ```
199
199
 
200
- ## 自定义工具结果渲染器
200
+ ## 自定义 Part 渲染器(新架构)
201
201
 
202
- 可以为特定工具注入自定义渲染组件,替代默认的 JSON 显示:
202
+ 新架构使用 `partRenderers` 为特定的 Part 类型注入自定义渲染组件。工具执行结果会直接生成对应类型的 Part(如 `weather`),前端根据 `part.type` 选择渲染组件。
203
+
204
+ ### 工作原理
205
+
206
+ ```
207
+ 工具执行完成
208
+
209
+ 后端发送 tool_call_result { id, name, result, resultType: 'weather' }
210
+
211
+ 前端 useChat 处理:
212
+ 1. 更新 tool_call 状态为 done
213
+ 2. 根据 resultType 创建 { type: 'weather', ...result } Part
214
+
215
+ PartsRenderer 渲染:
216
+ - 检查 partRenderers['weather']
217
+ - 找到 → 使用自定义 WeatherCard 渲染
218
+ - 没找到 → 显示 JSON fallback
219
+ ```
220
+
221
+ ### 使用示例
203
222
 
204
223
  ```tsx
205
224
  import { useMemo } from 'react'
206
- import { ChatPanel, ToolRenderers } from '@huyooo/ai-chat-frontend-react'
225
+ import { ChatPanel, PartRenderers } from '@huyooo/ai-chat-frontend-react'
207
226
  import { CustomWeatherCard } from './components/CustomWeatherCard'
208
227
 
209
228
  function App() {
210
- // 工具名称 -> 渲染组件映射
211
- const toolRenderers = useMemo<ToolRenderers>(() => ({
212
- get_weather: CustomWeatherCard,
213
- // search_web: CustomSearchResults,
229
+ // Part 类型 -> 渲染组件映射
230
+ const partRenderers = useMemo<PartRenderers>(() => ({
231
+ weather: CustomWeatherCard, // weather 类型使用自定义卡片
232
+ // stock: CustomStockCard,
214
233
  }), [])
215
234
 
216
235
  return (
217
236
  <ChatPanel
218
237
  adapter={adapter}
219
- toolRenderers={toolRenderers}
238
+ partRenderers={partRenderers}
220
239
  />
221
240
  )
222
241
  }
@@ -224,85 +243,73 @@ function App() {
224
243
 
225
244
  ### 创建自定义渲染组件
226
245
 
246
+ 自定义组件直接接收 Part 的所有字段作为 props:
247
+
227
248
  ```tsx
228
249
  // CustomWeatherCard.tsx
229
- import { FC, useMemo } from 'react'
230
- import type { ToolRendererProps, WeatherData } from '@huyooo/ai-chat-shared'
250
+ import { FC } from 'react'
231
251
  import './CustomWeatherCard.css'
232
252
 
233
- export const CustomWeatherCard: FC<ToolRendererProps> = ({ toolResult }) => {
234
- const weather = useMemo<WeatherData>(() => {
235
- if (typeof toolResult === 'object' && toolResult !== null) {
236
- return toolResult as WeatherData
237
- }
238
- return { city: '未知', temperature: 0, condition: '未知' }
239
- }, [toolResult])
240
-
241
- return (
242
- <div className="weather-card">
243
- <div className="city">{weather.city}</div>
244
- <div className="temp">{weather.temperature}°C</div>
245
- <div className="condition">{weather.condition}</div>
246
- <div className="details">
247
- {weather.humidity && <span>湿度 {weather.humidity}%</span>}
248
- {weather.wind && <span>{weather.wind}</span>}
249
- </div>
250
- </div>
251
- )
252
- }
253
- ```
254
-
255
- ### ToolRendererProps 接口
256
-
257
- ```typescript
258
- interface ToolRendererProps {
259
- toolName: string // 工具名称
260
- toolArgs: object // 工具调用参数
261
- toolResult: unknown // 工具返回结果
262
- status: 'running' | 'done' | 'error' // 执行状态
263
- }
264
- ```
265
-
266
- ### 内置数据类型
267
-
268
- ```typescript
269
- // 天气数据
270
- interface WeatherData {
253
+ interface WeatherPartProps {
254
+ type: 'weather' // Part 类型
271
255
  city: string
272
256
  temperature: number
273
257
  condition: string
274
258
  humidity?: number
275
259
  wind?: string
260
+ reportTime?: string
261
+ province?: string
276
262
  }
277
263
 
278
- // 搜索结果
279
- interface SearchResultItem {
280
- title: string
281
- url: string
282
- snippet: string
264
+ export const CustomWeatherCard: FC<WeatherPartProps> = ({
265
+ city,
266
+ temperature,
267
+ condition,
268
+ humidity,
269
+ wind,
270
+ }) => {
271
+ return (
272
+ <div className="weather-card">
273
+ <div className="city">{city}</div>
274
+ <div className="temp">{temperature}°C</div>
275
+ <div className="condition">{condition}</div>
276
+ <div className="details">
277
+ {humidity && <span>湿度 {humidity}%</span>}
278
+ {wind && <span>{wind}</span>}
279
+ </div>
280
+ </div>
281
+ )
283
282
  }
284
283
  ```
285
284
 
286
- ## 自定义内容块渲染器
285
+ ### 内置 Part 类型
287
286
 
288
- 可以为特定内容类型注入自定义渲染组件:
287
+ | Part 类型 | 说明 | 内置渲染器 |
288
+ |-----------|------|-----------|
289
+ | `text` | 文本内容 | TextPart(支持 Markdown) |
290
+ | `thinking` | 思考过程 | ThinkingPart(可折叠卡片) |
291
+ | `search` | 搜索结果 | SearchPart |
292
+ | `tool_call` | 工具执行状态 | ToolCallPart(仅显示状态) |
293
+ | `image` | 图片 | ImagePart |
294
+ | `error` | 错误信息 | ErrorPart |
289
295
 
290
- ```tsx
291
- import { useMemo } from 'react'
292
- import { ChatPanel, BlockRenderers } from '@huyooo/ai-chat-frontend-react'
293
- import { CustomMathBlock } from './components/CustomMathBlock'
296
+ ### 扩展 Part 类型
294
297
 
295
- function App() {
296
- const blockRenderers = useMemo<BlockRenderers>(() => ({
297
- math: CustomMathBlock,
298
- }), [])
298
+ 可以通过工具的 `resultType` 定义新的 Part 类型:
299
299
 
300
- return (
301
- <ChatPanel
302
- adapter={adapter}
303
- blockRenderers={blockRenderers}
304
- />
305
- )
300
+ ```typescript
301
+ // 后端工具定义
302
+ export function getWeatherTool(): ToolPlugin {
303
+ return tool({
304
+ name: 'get_weather',
305
+ description: '获取城市天气',
306
+ parameters: { city: { type: 'string' } },
307
+ resultType: 'weather', // ← 指定结果 Part 类型
308
+ execute: async (args, context) => {
309
+ // 返回值会自动转换为 { type: 'weather', ...result }
310
+ return { city: args.city, temperature: 25, condition: '晴' }
311
+ }
312
+ })
306
313
  }
307
314
  ```
308
315
 
@@ -329,31 +336,39 @@ const {
329
336
  // 主组件
330
337
  export { ChatPanel, WelcomeMessage, ChatInput, ChatHeader, MessageBubble }
331
338
 
332
- // 内容渲染组件
333
- export { ContentRenderer, TextBlock, CodeBlock }
334
-
335
- // 工具结果渲染组件
336
- export { ToolResultRenderer, DefaultToolResult, WeatherCard, SearchResults }
339
+ // Part 渲染组件
340
+ export { PartsRenderer }
341
+ export {
342
+ TextPartComponent,
343
+ ThinkingPartComponent,
344
+ SearchPartComponent,
345
+ ToolCallPartComponent,
346
+ ImagePartComponent,
347
+ ErrorPartComponent,
348
+ }
337
349
 
338
350
  // Context Provider
339
- export { RenderersProvider, BlockRenderersContext, ToolRenderersContext }
351
+ export { PartRenderersProvider, PartRenderersContext }
340
352
 
341
353
  // Hook
342
354
  export { useChat }
343
355
 
344
- // 类型 (来自 @huyooo/ai-chat-shared)
356
+ // 类型
345
357
  export type {
346
358
  WelcomeConfig,
347
359
  WelcomeFeature,
348
360
  WelcomeTask,
349
- ToolRendererProps,
350
- ToolRenderers,
351
- BlockRenderers,
361
+ PartRenderers,
362
+ PartRendererProps,
363
+ ContentPart,
364
+ TextPart,
365
+ ThinkingPart,
366
+ SearchPart,
367
+ ToolCallPart,
368
+ ImagePart,
369
+ ErrorPart,
352
370
  WeatherData,
353
371
  SearchResultItem,
354
- ContentBlock,
355
- TextBlock,
356
- CodeBlock
357
372
  }
358
373
 
359
374
  // 工具函数 (来自 @huyooo/ai-chat-shared)