@ray-js/t-agent-plugin-aistream 0.2.5-beta-1 → 0.2.5-beta-2

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.
package/README-zh_CN.md CHANGED
@@ -1,12 +1,1732 @@
1
- # @ray-js/t-agent-plugin-assistant
1
+ # AI 智能体 SDK
2
2
 
3
- > AI 智能体 SDK
4
- > 详细文档参见 @ray-js/t-agent
3
+ ## 版本说明
4
+
5
+ **⚠️ 重要提示**:从 0.2.x 版本开始,`@ray-js/t-agent-plugin-assistant` 已被废弃,请使用 `@ray-js/t-agent-plugin-aistream` 替代。
6
+
7
+ ## 安装(ray 小程序)
8
+
9
+ ```shell
10
+ yarn add @ray-js/t-agent @ray-js/t-agent-plugin-aistream @ray-js/t-agent-ui-ray
11
+ ```
12
+
13
+ > 确保 `@ray-js/t-agent` `@ray-js/t-agent-plugin-aistream` `@ray-js/t-agent-ui-ray` 版本一致
14
+
15
+ ## 小程序 kit 要求
16
+
17
+ ```json
18
+ {
19
+ "dependencies": {
20
+ "BaseKit": "3.12.0",
21
+ "BizKit": "4.10.0",
22
+ "DeviceKit": "4.6.1",
23
+ "HomeKit": "3.4.0",
24
+ "MiniKit": "3.12.1",
25
+ "AIStreamKit": "1.0.0"
26
+ },
27
+ "baseversion": "2.21.10"
28
+ }
29
+ ```
30
+
31
+ ## package.json 依赖要求
32
+
33
+ ```json
34
+ {
35
+ "dependencies": {
36
+ "@ray-js/ray": ">=1.6.8"
37
+ }
38
+ }
39
+ ```
40
+
41
+ ## 开发
42
+
43
+ ```shell
44
+ # 开发 sdk
45
+ yarn run dev
46
+
47
+ # 开发模板小程序
48
+ yarn run miniapp
49
+ ```
50
+
51
+ ## 使用示例
52
+
53
+ 使用 ray ui 实现一个对话页面
54
+
55
+ ![ChatPage1](https://static1.tuyacn.com/static/txp-ray-TAgent/ChatPage1.png)
56
+
57
+ ```tsx
58
+ // ChatPage.tsx
59
+ import React from 'react';
60
+ import { View } from '@ray-js/components';
61
+ import { createChatAgent, withDebug, withUI } from '@ray-js/t-agent';
62
+ import { ChatContainer, MessageInput, MessageList, MessageActionBar } from '@ray-js/t-agent-ui-ray';
63
+ import { withAIStream, withBuildIn } from '@ray-js/t-agent-plugin-aistream';
64
+
65
+ const createAgent = () => {
66
+ try {
67
+ // 应用插件是有顺序的
68
+ const agent = createChatAgent(
69
+ withUI(), // 第一个插件 withUI 插件提供了一些默认的 UI 行为,必选
70
+ withAIStream({
71
+ // withAIStream 插件对接小程序 AI 智能体平台,在小程序中必选
72
+ enableTts: false, // 是否开启语音合成
73
+ earlyStart: true, // 是否在 onAgentStart 阶段就建立连接
74
+ agentId: '', // 输入你的智能体ID
75
+ }),
76
+ withDebug(), // withDebug 会在 console 里打印日志
77
+ withBuildIn() // withBuildIn 插件提供了一些内置的功能
78
+ );
79
+
80
+ // 将生命周期钩子拿出来,方便注册自定义行为
81
+ const { onChatStart, createMessage, onChatResume, onError, onInputBlocksPush, session } = agent;
82
+
83
+ // 初始化聊天时,发送一条消息
84
+ onChatStart(async result => {
85
+ const hello = createMessage({
86
+ role: 'assistant',
87
+ });
88
+
89
+ hello.bubble.setText('Hello, world!');
90
+ result.messages.push(hello);
91
+ // 持久化消息,下次进入时会展示
92
+ await hello.persist();
93
+ });
94
+
95
+ // 恢复聊天时,发送一条消息
96
+ onChatResume(async result => {
97
+ const welcomeBack = createMessage({
98
+ role: 'assistant',
99
+ });
100
+
101
+ welcomeBack.bubble.setText('Welcome back');
102
+ result.messages.push(welcomeBack);
103
+ await welcomeBack.persist();
104
+ });
105
+ return agent;
106
+ } catch (error) {
107
+ console.error('Agent creation failed:', error);
108
+ throw error;
109
+ }
110
+ };
111
+
112
+ export default function ChatPage() {
113
+ return (
114
+ <View style={{ height: '100vh' }}>
115
+ <ChatContainer createAgent={createAgent}>
116
+ <MessageList />
117
+ <MessageInput />
118
+ <MessageActionBar />
119
+ </ChatContainer>
120
+ </View>
121
+ );
122
+ }
123
+ ```
124
+
125
+ # t-agent
126
+
127
+ t-agent 包是使用 TypeScript 编写的对话智能体 SDK,用于构建对话智能体,支持插件机制,可以扩展对话智能体的功能。
128
+ 该包是纯 SDK 包,不包含任何 UI 组件,可以和任何 UI 框架搭配使用。
129
+
130
+ ## 基本概念
131
+
132
+ ![flow.png](https://static1.tuyacn.com/static/txp-ray-TAgent/flow.png)
133
+
134
+ ### ChatAgent 对话智能体 Agent
135
+
136
+ 对话智能体的核心类,负责管理对话的生命周期,消息的创建,消息的持久化等,支持插件和 hook 机制,可以扩展对话智能体的功能。
137
+
138
+ 使用 `createChatAgent` 创建一个 ChatAgent 实例,如下:
139
+
140
+ ```tsx
141
+ import { createChatAgent } from '@ray-js/t-agent';
142
+ const createAgent = () => {
143
+ /* 在 createChatAgent 参数里应用插件,注意插件是有顺序的 */
144
+ const agent = createChatAgent();
145
+
146
+ return agent;
147
+ };
148
+ ```
149
+
150
+ 主要属性:
151
+
152
+ - `agent.session` ChatSession 会话容器,用于存储会话相关的数据
153
+ - `agent.plugins` 应用插件后,会在这里存储插件的相关方法和 Hooks
154
+
155
+ 主要方法:
156
+
157
+ - `agent.start()` 启动
158
+ - `agent.dispose()` 释放
159
+ - `agent.pushInputBlocks(blocks, signal)` 从外部将消息 block 推到 ChatAgent 里,用于用户向 AI 发送消息
160
+ - `agent.createMessage(data)` 创建一个与当前 Agent 绑定的消息
161
+ - `agent.emitTileEvent(tileId: string, payload: any)` tile 发送事件
162
+ - `agent.removeMessage(messageId: string)` 删除消息
163
+ - `agent.flushStreamToShow(message: ChatMessage, response: StreamResponse, composer: ComposeHandler)` 流式更新消息
164
+
165
+ ### Hooks 机制
166
+
167
+ ChatAgent 仅定义了一个运行框架和数据结构,具体行为是由 Hook 机制实现的,Hook 机制是一种事件驱动的编程模型,通过注册回调函数来实现对话智能体的行为。
168
+
169
+ ```tsx
170
+ import { createChatAgent } from '@ray-js/t-agent';
171
+ const createAgent = () => {
172
+ const agent = createChatAgent();
173
+
174
+ const { onChatStart } = agent;
175
+
176
+ // 在对话开始时触发 onChatStart Hook
177
+ onChatStart(result => {
178
+ console.log('Chat start', result);
179
+ });
180
+ return agent;
181
+ };
182
+ ```
183
+
184
+ #### Hook 执行顺序
185
+
186
+ Hook 按照以下顺序执行:
187
+
188
+ ```
189
+ onAgentStart → onChatStart/onChatResume → onMessageListInit → onInputBlocksPush
190
+ ```
191
+
192
+ ChatAgent 主要 Hook 和参数:
193
+
194
+ - `agent.onAgentStart` 初始化 Agent
195
+ - `agent.onChatStart` 对话开始时触发
196
+ - `result.messages` 用于初始化消息列表
197
+ - `agent.onChatResume` 对话恢复时触发
198
+ - `result.messages` 已经恢复好了的消息列表
199
+ - `agent.onMessageListInit` 对话开始、对话恢复后,消息列表初始化时触发
200
+ - `result.messages` 用于渲染的消息列表,和前面两个 hooks 的 message 是同一个列表
201
+ - `agent.onInputBlocksPush` 推送消息 block 时触发
202
+ - `blocks` 输入的消息块 blocks
203
+ - `signal` 中断信号
204
+ - `agent.onMessageChange` 消息变化时触发
205
+ - `type` 变化的类型,`show`、`update`、`remove`
206
+ - `message` 变化的消息
207
+ - `agent.onMessagePersist` 消息持久化时触发
208
+ - `payload` 持久化相关参数
209
+ - `message` 持久化的目标消息
210
+ - `agent.onTileEvent` 消息持久化完成时触发
211
+ - `tile` 触发事件的 tile
212
+ - `payload` 事件的 payload
213
+ - `agent.onAgentDispose` 释放 Agent 时触发
214
+ - `agent.onUserAbort` 用户中断时触发
215
+ - `reason` 中断原因
216
+ - `agent.onError` 出错时触发
217
+ - `error` 错误对象
218
+
219
+ 这些 hooks 都接收一个回调函数作为参数,当触发时会调用这个回调函数,回调函数可以是同步也可以是异步,回调函数的返回不影响结果,
220
+ 如果需要改变结果,可以通过修改回调函数的 result 参数或修改 tile、message 对象来修改。
221
+
222
+ ### ChatSession 会话容器
223
+
224
+ ChatSession 存储和智能体聊天的消息列表,上下文数据等内容,在 ChatAgent 创建时一同创建
225
+
226
+ 主要属性:
227
+
228
+ - `session.messages` 消息列表
229
+ - `session.sessionId` 会话 id
230
+ - `session.isNewChat` 是否是新会话,用于区分新会话 `onChatStart` 和恢复会话 `onChatResume`
231
+
232
+ 主要方法:
233
+
234
+ - `session.set` 设置会话数据,可以是任意类型
235
+ - `session.get` 获取会话数据
236
+ - `session.getData` 用对象的方式获取会话数据
237
+ - `session.getLatestMessage` 获取最后一条消息
238
+
239
+ Hooks:
240
+
241
+ - `session.onChange` 注册会话数据变化的回调
242
+
243
+ ### ChatMessage 对话消息
244
+
245
+ ChatMessage 是对话消息的抽象,用于存储消息的内容,状态等信息,也提供了一系列方便的方法用于操作消息。
246
+ 一条消息 ChatMessage 下,会有多个 ChatTile,用于展示不同的内容。
247
+
248
+ 创建一条消息使用 `createMessage` 方法,如下:
249
+
250
+ ```tsx
251
+ const createAgent = () => {
252
+ const agent = createChatAgent();
253
+
254
+ const { createMessage, onChatStart } = agent;
255
+
256
+ // 初始化聊天时,发送一条消息
257
+ onChatStart(async result => {
258
+ // 创建一条由智能体助手发送的消息
259
+ const message = createMessage({
260
+ role: 'assistant',
261
+ });
262
+
263
+ // 访问 message.bubble 可以快速创建一个文本气泡
264
+ message.bubble.setText('Hello!');
265
+ result.messages.push(message);
266
+ });
267
+
268
+ return agent;
269
+ };
270
+ ```
271
+
272
+ 主要属性:
273
+
274
+ - `message.id` 消息 id
275
+ - `message.role` 消息角色,可以是 assistant 或者 user
276
+ - `message.tiles` 消息的 tile 列表
277
+ - `message.status` 消息状态,`ChatMessageStatus` 枚举,可以是 `START`、`UPDATING`、`FINISH` 等
278
+ - `message.meta` 消息附带的额外数据
279
+ - `message.isShow` 是否已经展示到界面上
280
+ - `message.bubble` 消息中,气泡 tile 的快捷方式
281
+
282
+ 主要方法
283
+
284
+ - `message.show` 消息展示到界面上
285
+ - `message.update` 将当前消息状态更新到界面上
286
+ - `message.remove` 将当前消息从界面上移除
287
+ - `message.persist` 持久化消息
288
+ - `message.addTile` 添加一个 tile
289
+ - `message.removeTile` 移除一个 tile
290
+ - `message.setTilesLocked` 设置所有的 tile 的锁定状态
291
+ - `message.set` 设置消息的属性
292
+ - `message.setMetaValue` 按 key-value 设置 meta 的属性
293
+ - `message.deleteMetaValue` 删除 meta 的属性
294
+ - `message.setMeta` 直接设置 meta 对象
295
+ - `message.findTileByType` 通过 tile 类型查找 tile
296
+
297
+ #### ChatTile 对话消息块
298
+
299
+ ChatTile 是对话消息的块,用于展示消息内的不同内容,例如文本、图片、卡片等。
300
+
301
+ 为消息添加一个 tile 使用 `addTile` 方法,如下:
302
+
303
+ ```tsx
304
+ const message = createMessage({
305
+ role: 'assistant',
306
+ });
307
+
308
+ // 添加一个图片 tile
309
+ message.addTile('image', {
310
+ src: '/image.jpg',
311
+ });
312
+
313
+ await message.show();
314
+ ```
315
+
316
+ ChatTile 的主要属性:
317
+
318
+ - `tile.id` tile 的 id
319
+ - `tile.type` tile 类型
320
+ - `tile.data` tile 数据
321
+ - `tile.children` tile 的子 tile
322
+ - `tile.locked` tile 是否被锁定
323
+ - `tile.fallback` 当 tile 无法展示时的回退内容
324
+ - `tile.message` tile 所属的消息
325
+
326
+ ChatTile 的主要方法:
327
+
328
+ - `tile.update` 是 `tile.message.update` 的快捷方式
329
+ - `tile.show` 是 `tile.message.show` 的快捷方式
330
+ - `tile.setLocked` 设置 tile 的锁定状态
331
+ - `tile.addTile` 添加一个子 tile
332
+ - `tile.setData` 设置 tile 的数据
333
+ - `tile.setFallback` 设置 tile 的回退内容
334
+ - `tile.findByType` 通过 tile 类型查找子 tile
335
+
336
+ `message.bubble` 是一个快捷方式,只要访问它,就会在当前的消息中快速添加一个气泡 tile,如下:
337
+
338
+ ```tsx
339
+ const message = createMessage({
340
+ role: 'assistant',
341
+ });
342
+
343
+ message.bubble.setText('Hello, world!');
344
+ // 等价于
345
+ message.addTile('bubble', {}).addTile('text', { text: 'Hello, world!' });
346
+
347
+ await message.show();
348
+ ```
349
+
350
+ 针对气泡消息,除了支持 tile 基本方法外,还额外提供了一些属性和方法:
351
+
352
+ - `message.bubble.text` 属性,读取气泡文本
353
+ - `message.bubble.setText` 方法,设置气泡文本
354
+ - `message.bubble.isMarkdown` 属性,是否是 markdown 格式
355
+ - `message.bubble.setIsMarkdown` 方法,设置是否是 markdown 格式
356
+ - `message.bubble.status` 属性,气泡状态 BubbleTileStatus
357
+ - `message.bubble.setStatus` 方法,设置气泡状态
358
+ - `message.bubble.info` 属性,气泡信息
359
+ - `message.bubble.setInfo` 方法,设置气泡信息
360
+ - `message.bubble.initWithInputBlocks` 方法,用输入块初始化气泡
361
+
362
+ **气泡消息支持长按操作**,可以进行复制、删除等操作,同时在消息加载和更新过程中会有动画显示。
363
+
364
+ 气泡消息支持以下长按操作:
365
+
366
+ - 复制:复制消息文本内容
367
+ - 删除:删除当前消息
368
+
369
+ ### 生命周期
370
+
371
+ ChatAgent 在不同的阶段会触发不同的 Hook,开发者可以通过注册 Hook 来实现自定义行为,下面的时序图展示了 ChatAgent 的生命周期。
372
+
373
+ ```mermaid
374
+ sequenceDiagram
375
+ participant AI as Backend(AI)
376
+ participant A as ChatAgent
377
+ participant UI as UI界面
378
+ actor User as 用户
379
+
380
+ User ->> UI: 打开聊天界面
381
+ UI ->> UI: 创建 Agent 对象 agent
382
+ UI ->> A: agent.start() 启动 Agent
383
+ rect rgba(255,255,0,0.1)
384
+ note over A: Hook: onAgentStart
385
+ A ->> AI: 获取是否新会话
386
+ AI ->> A: 返回
387
+ end
388
+ alt 是新会话
389
+ A ->> AI: 开始新会话
390
+ note over A: Hook: onChatStart
391
+ else 是恢复会话
392
+ A ->> AI: 读取会话历史
393
+ AI ->> A: 返回历史消息
394
+ note over A: Hook: onChatResume
395
+ end
396
+ rect rgba(255,255,0,0.1)
397
+ note over A: Hook: onMessageListInit
398
+ A ->> UI: 组装要展示的消息
399
+ UI ->> User: 展示消息
400
+ end
401
+ opt 对话
402
+ User ->> UI: 输入并发送消息
403
+ UI ->> A: agent.pushInputBlocks()
404
+ rect rgba(255,255,0,0.1)
405
+ note over A: Hook: onInputBlocksPush
406
+ A ->> A: 创建 Message 对象 msg<br/>msg 设置为用户输入的文本<br/>msg.show()
407
+ note over A: Hook: onMessageChange show
408
+ A -->> UI: 更新界面
409
+ UI -->> User: 展示新消息
410
+ A ->> A: 创建 Message 对象 respMsg<br/>respMsg 设置为 loading<br/>respMsg.show()
411
+ note over A: Hook: onMessageChange show
412
+ A -->> UI: 更新界面
413
+ UI -->> User: 展示响应消息loading
414
+ A ->> AI: 调用 AI
415
+ AI ->> A: 返回消息流
416
+ loop 流式消息
417
+ AI ->> A: 消息包
418
+ A ->> A: 更新respMsg数据<br/>respMsg.update()
419
+ note over A: Hook: onMessageChange update
420
+ A -->> UI: 更新界面
421
+ UI -->> User: 蹦字/展示卡片
422
+ end
423
+ end
424
+ end
425
+
426
+ opt 操作消息行动点(以单选为例)
427
+ User ->> UI: 选中选项
428
+ UI ->> A: agent.emitTileEvent()
429
+ rect rgba(255,255,0,0.1)
430
+ note over A: Hook: onTileEvent
431
+ A ->> A: 设置 msg 状态<br/>msg.persist()
432
+ note over A: Hook: onMessagePersist
433
+ A ->> AI: 持久化消息
434
+ AI ->> A: 返回结果
435
+ A ->> A: msg.update()
436
+ note over A: Hook: onMessageChange update
437
+ A ->> UI: 更新界面
438
+ UI ->> User: 消息置灰,高亮选中
439
+ end
440
+ end
441
+ opt 删除消息
442
+ User ->> UI: 删除消息
443
+ UI ->> A: agent.removeMessage()
444
+ rect rgba(255,255,0,0.1)
445
+ A ->> A: msg.remove()
446
+ A ->> AI: 标记消息删除
447
+ note over A: Hook: onMessageChange remove
448
+ A ->> UI: 更新界面
449
+ UI ->> User: 消息消失
450
+ end
451
+ end
452
+ ```
453
+
454
+ ### Plugin 插件机制
455
+
456
+ 插件是基于以上的 Hook 机制实现的,插件可以实现对话智能体的功能,例如对接 AI 平台,提供 UI 界面等。
457
+ 插件也可以暴露一些方法和属性,供开发者使用。
458
+
459
+ ```tsx
460
+ import { createChatAgent, withUI } from '@ray-js/t-agent';
461
+ const createAgent = () => {
462
+ const agent = createChatAgent(
463
+ withUI() // withUI 插件提供了一些渲染 UI 的方法
464
+ );
465
+
466
+ return agent;
467
+ };
468
+
469
+ // ScrollToBottom.tsx
470
+ import React from 'react';
471
+ import { Button } from '@ray-js/components';
472
+ import { useChatAgent } from '@ray-js/t-agent-ui-ray';
473
+ const ScrollToBottom = () => {
474
+ const agent = useChatAgent();
475
+
476
+ const scroll = () => {
477
+ // 使用插件暴露的方法
478
+ agent.plugins.ui.emitEvent('scrollToBottom', { animation: false });
479
+ };
480
+
481
+ return <Button onClick={scroll}>Scroll to bottom</Button>;
482
+ };
483
+ ```
484
+
485
+ #### 编写一个插件
486
+
487
+ 插件是一个高阶函数,接收一个选项,返回一个函数,这个函数接收一个 ChatAgent 对象,可以在这个函数中注册 Hook。
488
+
489
+ ```tsx
490
+ import { ChatAgent, createHooks, Hookable } from '@ray-js/t-agent';
491
+
492
+ // 试下一个 MyPlugin 插件
493
+ export type MyPlugin = GetChatPluginHandler<typeof withMyPlugin>;
494
+
495
+ export const withMyPlugin = (options: any) => {
496
+ // 创建一个 Hookable 对象
497
+ const hooks = createHooks();
498
+
499
+ return (agent: ChatAgent) => {
500
+ const { onChatStart } = agent;
501
+
502
+ onChatStart(async () => {
503
+ console.log('Chat start');
504
+ // 触发插件的 Hook
505
+ await hooks.callHook('onMyHook', 'Hello, world!');
506
+ });
507
+
508
+ // 暴露插件的方法和 Hook
509
+ return {
510
+ hooks,
511
+ myPlugin: {
512
+ // 暴露一个方法
513
+ myMethod() {
514
+ console.log('My method');
515
+ },
516
+ // 暴露一个 Hook
517
+ onMyHook: fn => {
518
+ return hooks.hook('onMyHook', fn);
519
+ },
520
+ },
521
+ };
522
+ };
523
+ };
524
+ ```
525
+
526
+ ```tsx
527
+ // 使用插件
528
+ import { createChatAgent } from '@ray-js/t-agent';
529
+
530
+ const createAgent = () => {
531
+ const agent = createChatAgent(
532
+ // 使用插件
533
+ withMyPlugin({})
534
+ );
535
+
536
+ // 调用插件暴露的方法
537
+ agent.plugins.myPlugin.myMethod();
538
+
539
+ // 注册插件的 Hook
540
+ agent.plugins.myPlugin.onMyHook(msg => {
541
+ console.log(msg);
542
+ });
543
+
544
+ return agent;
545
+ };
546
+ ```
547
+
548
+ ## 内置插件
549
+
550
+ ### withDebug
551
+
552
+ withDebug 插件会在 console 里打印日志,方便调试
553
+
554
+ ```tsx
555
+ const agent = createChatAgent(
556
+ withDebug({
557
+ autoStart: true, // 是否自动启动,默认为 true
558
+ })
559
+ );
560
+
561
+ // 启动
562
+ agent.plugins.debug.start();
563
+
564
+ // 停止
565
+ agent.plugins.debug.stop();
566
+ ```
567
+
568
+ ### withUI
569
+
570
+ withUI 插件提供了一些默认的 UI 行为,例如消息的展示,消息的删除等,消息总线
571
+
572
+ ```tsx
573
+ const agent = createChatAgent(withUI());
574
+
575
+ agent.plugins.ui.emitter; // 消息总线
576
+
577
+ // 滚动到底部
578
+ agent.plugins.ui.emitEvent('scrollToBottom', { animation: false });
579
+
580
+ // 监听事件
581
+ const off = agent.plugins.ui.onEvent('scrollToBottom', payload => {
582
+ console.log('scroll to bottom', payload.animation);
583
+ });
584
+
585
+ // 取消监听
586
+ off();
587
+ ```
588
+
589
+ ui 插件的主要事件如下,你还可以自由地注册需要的事件:
590
+
591
+ - `messageListInit` 初始化消息列表
592
+ - `payload.messages: ChatMessageObject[]` 消息列表
593
+ - `messageChange` 消息变化
594
+ - `payload.type: 'show' | 'update' | 'remove'` 变化类型
595
+ - `payload.message: ChatMessageObject` 消息
596
+ - `scrollToBottom` 滚动到底部
597
+ - `payload.animation: boolean` 是否使用动画
598
+ - `sendMessage` 发送消息,触发 UI 界面更新
599
+ - `payload.blocks: InputBlock[]` 输入块
600
+ - `setInputBlocks` 设置输入块到 MessageInput 输入框
601
+ - `payload.blocks: InputBlock[]` 输入块
602
+ - `sessionChange`: 会话数据变化
603
+ - `payload.key: string`: 会话数据 key
604
+ - `payload.value: any`: 会话数据 value
605
+ - `payload.oldValue: any`: 会话数据旧值
606
+
607
+ UI 插件增强功能(0.2.x 新增):
608
+
609
+ withUI 插件在 0.2.x 版本中新增了 Hook 机制,可以让开发者自定义消息反馈和历史清理的行为:
610
+
611
+ **消息反馈 Hook**:
612
+
613
+ - `agent.plugins.ui.hook('onMessageFeedback', async context => {})` 注册消息反馈 Hook
614
+ - `context.payload.messageId: string` 消息 ID
615
+ - `context.payload.rate: 'like' | 'unlike'` 反馈类型
616
+ - `context.payload.content?: string` 反馈内容(可选)
617
+ - `context.result: { success: boolean }` 返回结果,需要设置是否成功
618
+
619
+ **清空历史 Hook**:
620
+
621
+ - `agent.plugins.ui.hook('onClearHistory', async context => {})` 注册清空历史 Hook
622
+ - `context.payload: any` 清空历史的参数
623
+ - `context.result: { success: boolean }` 返回结果,需要设置是否成功
624
+
625
+ **调用 Hook**:
626
+
627
+ - `agent.plugins.ui.callHook('onMessageFeedback', payload)` 调用消息反馈 Hook
628
+ - `agent.plugins.ui.callHook('onClearHistory', payload)` 调用清空历史 Hook
629
+
630
+ 使用示例:
631
+
632
+ ```tsx
633
+ const agent = createChatAgent(withUI(), withAIStream({ agentId: 'your-agent-id' }));
634
+
635
+ // 注册消息反馈处理
636
+ agent.plugins.ui.hook('onMessageFeedback', async context => {
637
+ const { messageId, rate, content } = context.payload;
638
+ try {
639
+ // 调用你的 API 提交反馈
640
+ await submitFeedback({ messageId, rate, content });
641
+ context.result = { success: true };
642
+ } catch (error) {
643
+ context.result = { success: false };
644
+ }
645
+ });
646
+
647
+ // 注册清空历史处理
648
+ agent.plugins.ui.hook('onClearHistory', async context => {
649
+ try {
650
+ // 调用你的 API 清空历史
651
+ await clearChatHistory();
652
+ context.result = { success: true };
653
+ } catch (error) {
654
+ context.result = { success: false };
655
+ }
656
+ });
657
+ ```
658
+
659
+ > 注意,这里的 ChatMessageObject 是一个消息对象,不是 ChatMessage 类型,
660
+ > 它包含了消息的一些属性和方法,这是为了避免在 UI 层修改消息对象,导致 ChatAgent 中的消息对象不一致。
661
+ > 对消息对象的修改应该始终在 ChatAgent 中进行。
662
+
663
+ ## 附带 utils 工具
664
+
665
+ ### getLogger(prefix: string): Logger
666
+
667
+ 创建一个 logger,用于打印日志
668
+
669
+ ```tsx
670
+ import { getLogger } from '@ray-js/t-agent';
671
+ const logger = getLogger('MyPlugin');
672
+ logger.debug('Hello, world!');
673
+ ```
674
+
675
+ ### Emitter 事件总线
676
+
677
+ Emitter 是一个事件总线,用于注册和触发事件
678
+
679
+ ```tsx
680
+ import { Emitter, EmitterEvent } from '@ray-js/t-agent';
681
+ const emitter = new Emitter();
682
+
683
+ // 注册事件
684
+ const cb = event => console.log('detail', event.detail);
685
+ emitter.addEventListener('event', cb);
686
+
687
+ // 触发事件
688
+ emitter.dispatchEvent(new EmitterEvent('event', { detail: 'Hello, world!' }));
689
+
690
+ // 移除事件
691
+ emitter.removeEventListener('event', cb);
692
+ ```
693
+
694
+ ### StreamResponse
695
+
696
+ StreamResponse 是一个流式响应对象,用于处理流式消息
697
+
698
+ ```tsx
699
+ import { StreamResponse } from '@ray-js/t-agent';
700
+
701
+ const partStream = await getPartStream(); // 获取流数据
702
+ const response = new StreamResponse(partStream);
703
+
704
+ const parts = response.parts();
705
+ for await (const part of parts) {
706
+ console.log('part', part);
707
+ }
708
+ ```
709
+
710
+ ### createHooks、Hookable
711
+
712
+ 参见 `hookable` npm 包
713
+
714
+ ### isAbortError
715
+
716
+ 判断是否是中断错误
717
+
718
+ ### safeParseJSON
719
+
720
+ 安全地解析 JSON 字符串,解析失败返回 `undefined`
721
+
722
+ ```tsx
723
+ import { safeParseJSON } from '@ray-js/t-agent';
724
+
725
+ const obj = safeParseJSON<{ a: number }>('{"a": 1}');
726
+
727
+ console.log(obj.a); // 1
728
+ ```
729
+
730
+ # t-agent-plugin-aistream
731
+
732
+ t-agent-plugin-aistream 是一个对接小程序 AI 智能体平台的插件,提供了对接小程序 AI 智能体平台的能力。
5
733
 
6
734
  ## 安装
7
735
 
8
- ```sh
9
- $ npm install @ray-js/t-agent-plugin-assistant
10
- // 或者
11
- $ yarn add @ray-js/t-agent-plugin-assistant
736
+ ```shell
737
+ yarn add @ray-js/t-agent-plugin-aistream
12
738
  ```
739
+
740
+ ## 使用
741
+
742
+ ```tsx
743
+ import { createChatAgent, withUI } from '@ray-js/t-agent';
744
+ import { withAIStream, withBuildIn } from '@ray-js/t-agent-plugin-aistream';
745
+
746
+ const createAgent = () => {
747
+ const agent = createChatAgent(
748
+ withUI(), // 一般都需要应用 withUI 插件
749
+ withAIStream({
750
+ agentId: 'your-agent-id', // 输入你的智能体ID
751
+ enableTts: false, // 是否开启语音合成,默认为 false
752
+ }),
753
+ withBuildIn()
754
+ );
755
+
756
+ return agent;
757
+ };
758
+ ```
759
+
760
+ ## 包含的插件
761
+
762
+ ### withAIStream 插件
763
+
764
+ 提供了对接小程序 AI 智能体平台的能力
765
+
766
+ 参数:
767
+
768
+ - `agentId` 智能体 ID(必填)
769
+ - `clientType` 客户端类型,默认为 APP (2)
770
+ - `deviceId` 设备 ID,当 clientType 为 DEVICE (1) 时必填
771
+ - `enableTts` 是否开启语音合成,默认为 false
772
+ - `wireInput` 是否将输入块传递给智能体,默认为 true,设置为 false 时,需要你自己编写 onInputBlocksPush Hook 来处理输入块
773
+ - `historySize` 历史消息大小,默认为 1000
774
+ - `indexId` 索引 ID,默认为 'default'
775
+ - `homeId` 家庭 ID,不填默认当前家庭
776
+ - `earlyStart` 是否在 onAgentStart 阶段就建立连接
777
+ - `tokenOptions` 获取 agent token 的参数
778
+ - `api` API 接口名
779
+ - `version` 接口版本
780
+ - `extParams` 额外参数
781
+ - `createChatHistoryStore` 自定义消息存储函数
782
+
783
+ 方法:
784
+
785
+ - `agent.plugins.aiStream.send` 向智能体发送一条消息
786
+ - `agent.plugins.aiStream.chat` 向智能体发送一条消息,并生成提问 ChatMessage 对象和 AI 回答 ChatMessage 对象,流式更新
787
+
788
+ Hooks:
789
+
790
+ - `onMessageParse` 当读取历史消息,解析消息时触发,可以在这个 Hook 里修改消息
791
+ - `msgItem` 存储的消息对象
792
+ - `result.messages` 解析后的消息列表
793
+ - `onSkillCompose` 当收到技能数据时触发,用于处理技能的渲染
794
+ - `skill` 技能数据数组 (ReceivedTextSkillPacketBody[])
795
+ - `respMsg` 响应消息
796
+ - `result.messages` 消息列表
797
+ - `onSkillsEnd` 当所有技能处理完成时触发
798
+ - `skills` 技能数据列表 (ReceivedTextSkillPacketBody[])
799
+ - `respMsg` 响应消息
800
+ - `result.messages` 消息列表
801
+ - `onTTTAction` tile 使用 `sendAction` 时触发
802
+ - `tile` 触发的 tile
803
+ - `result.action` TTTAction,可以修改要执行的动作
804
+ - `onCardsReceived` 当收到卡片数据时触发
805
+ - `skills` 技能数据列表 (ReceivedTextSkillPacketBody[])
806
+ - `result.cards` 卡片列表
807
+
808
+ ### withBuildIn 插件
809
+
810
+ 提供了一些内置的功能,比如智能家居、知识库搜索等。
811
+
812
+ **支持的技能**:
813
+
814
+ - **智能家居**:设备控制、场景管理
815
+ - **知识库搜索**:关联文档展示
816
+
817
+ ## mock 机制
818
+
819
+ 为了方便开发,我们提供了一个 mock 机制,可以在开发时不用连接小程序 AI 智能体平台,直接使用 mock 数据进行开发。
820
+
821
+ ### mock AI Stream 响应
822
+
823
+ ```tsx
824
+ import { mock } from '@ray-js/t-agent-plugin-aistream';
825
+
826
+ mock.hooks.hook('sendToAIStream', context => {
827
+ if (context.options.blocks?.some(block => block.text?.includes('hello'))) {
828
+ context.responseText = 'hello, who are you?';
829
+ }
830
+
831
+ if (context.options.blocks?.some(block => block.text?.includes('智能家居'))) {
832
+ context.responseText = '正在为您控制智能设备...';
833
+ context.responseSkills = [
834
+ {
835
+ code: 'smart_home',
836
+ general: {
837
+ action: 'control_device',
838
+ data: {
839
+ devices: [
840
+ {
841
+ deviceId: 'vdevo174796589841019',
842
+ icon: '',
843
+ dps: { range: '0', toggle: 'ON' },
844
+ name: '毛巾架',
845
+ },
846
+ ],
847
+ },
848
+ },
849
+ custom: {},
850
+ },
851
+ ];
852
+ }
853
+ });
854
+ ```
855
+
856
+ ### mock ASR 语音识别
857
+
858
+ ```tsx
859
+ import { mock } from '@ray-js/t-agent-plugin-aistream';
860
+
861
+ mock.hooks.hook('asrDetection', context => {
862
+ context.responseText = 'Hello world!, I am a virtual assistant.';
863
+ });
864
+ ```
865
+
866
+ ## 附带的 utils 工具(现在不稳定,还在开发中)
867
+
868
+ ### AbortController
869
+
870
+ 这个是小程序里的 AbortController ponyfill,参见 mdn
871
+
872
+ ### runTTTAction
873
+
874
+ 运行一个 TTTAction,用于处理用户的操作行为,目前支持以下动作
875
+
876
+ - `openRoute` 打开一个路由
877
+ - `openMiniApp` 打开一个小程序
878
+ - `openH5` 打开一个 H5 页面
879
+ - `sendMessage` 发送一条消息
880
+ - `buildIn` 内置行动
881
+
882
+ ### AsrAgent
883
+
884
+ ASR 语音识别代理,用于识别用户的语音输入
885
+
886
+ 使用方法:
887
+
888
+ ```tsx
889
+ import { createAsrAgent } from '@ray-js/t-agent-plugin-aistream';
890
+
891
+ async function startAsr() {
892
+ const asrAgent = createAsrAgent({
893
+ agentId: 'your-agent-id',
894
+ onMessage: message => {
895
+ if (message.type === 'text') {
896
+ console.log('识别结果:', message.text);
897
+ } else if (message.type === 'file') {
898
+ console.log('音频文件:', message.file);
899
+ }
900
+ },
901
+ onFinish: () => {
902
+ console.log('识别完成');
903
+ },
904
+ onError: error => {
905
+ console.error('识别出错:', error);
906
+ },
907
+ recordingOptions: {
908
+ saveFile: false,
909
+ sampleRate: 16000,
910
+ maxDuration: 60000, // 最长60秒
911
+ },
912
+ });
913
+
914
+ // 开始识别
915
+ await asrAgent.start();
916
+
917
+ // 结束识别
918
+ await asrAgent.stop();
919
+ }
920
+ ```
921
+
922
+ ### promisify TTT
923
+
924
+ 内置大量 TTT API 的 promisify 方法,用于将 TTT API 转换为 Promise,同时支持 mock
925
+
926
+ 使用方法:
927
+
928
+ ```tsx
929
+ import { promisify } from '@ray-js/t-agent-plugin-aistream';
930
+
931
+ interface RouterParams {
932
+ /** 路由链接 */
933
+ url: string;
934
+ complete?: () => void;
935
+ success?: (params: null) => void;
936
+ fail?: (params: {
937
+ errorMsg: string;
938
+ errorCode: string | number;
939
+ innerError: {
940
+ errorCode: string | number;
941
+ errorMsg: string;
942
+ };
943
+ }) => void;
944
+ }
945
+ const router = promisify<RouterParams>(ty.router);
946
+
947
+ // mock,只在 IDE 下生效
948
+ mock.hooks.hook('router', context => {
949
+ console.log('call router', context.options);
950
+ });
951
+
952
+ // 调用
953
+ await router({ url: '/pages/index/index' });
954
+ ```
955
+
956
+ ### sendBlocksToAIStream
957
+
958
+ **注意:此函数仅供内部使用,一般开发者不需要直接调用**
959
+
960
+ 给 AIStream 发送消息块,这是一个底层函数,通常应该使用 `agent.plugins.aiStream.send` 或 `agent.plugins.aiStream.chat` 方法。
961
+
962
+ #### 适用场景
963
+
964
+ - ✅ **适用**:需要直接控制流式响应的处理时
965
+ - ✅ **适用**:实现自定义的消息发送逻辑
966
+ - ❌ **不适用**:一般的对话场景,应使用 `agent.plugins.aiStream.chat`
967
+ - ❌ **不适用**:简单的消息发送,应使用 `agent.plugins.aiStream.send`
968
+
969
+ #### 函数签名
970
+
971
+ ```tsx
972
+ import { sendBlocksToAIStream } from '@ray-js/t-agent-plugin-aistream';
973
+
974
+ export interface SendBlocksToAIStreamParams {
975
+ blocks: InputBlock[];
976
+ session: AIStreamSession;
977
+ attribute?: AIStreamChatAttribute;
978
+ signal?: AbortSignal;
979
+ enableTts?: boolean;
980
+ }
981
+
982
+ export function sendBlocksToAIStream(params: SendBlocksToAIStreamParams): {
983
+ response: StreamResponse;
984
+ metaPromise: Promise<Record<string, any>>;
985
+ };
986
+ ```
987
+
988
+ #### 使用示例
989
+
990
+ ```tsx
991
+ const send = async () => {
992
+ try {
993
+ // 需要先获取 AIStreamSession 对象
994
+ const streamSession = agent.session.get('AIStream.streamSession');
995
+
996
+ const result = sendBlocksToAIStream({
997
+ blocks: [{ type: 'text', text: 'hello' }],
998
+ session: streamSession,
999
+ signal: new AbortController().signal,
1000
+ });
1001
+
1002
+ // 获取发送后的元数据
1003
+ const meta = await result.metaPromise;
1004
+
1005
+ // 获取流式消息
1006
+ const parts = result.response.parts();
1007
+ for await (const part of parts) {
1008
+ console.log('part', part);
1009
+ }
1010
+ } catch (error) {
1011
+ console.error('Send message failed:', error);
1012
+ // 错误处理逻辑
1013
+ }
1014
+ };
1015
+ ```
1016
+
1017
+ ### 媒体文件相关函数
1018
+
1019
+ `uploadMedia`、`uploadVideo`、`uploadImage` 用于上传媒体文件,带缓存
1020
+
1021
+ `isFullLink` 用于判断是否是 http(s) 协议开头的链接
1022
+
1023
+ `parseCloudKey` 用于解析 URL 中云存储的 key
1024
+
1025
+ `isLinkExpired` 用于判断链接是否过期
1026
+
1027
+ `getUrlByCloudKey` 从缓存中获取云存储的下载签名 URL,如果没有则返回 `undefined`
1028
+
1029
+ `setUrlByCloudKey` 设置云存储的下载签名 URL 到缓存中
1030
+
1031
+ `resetUrlByCloudKey` 重置云存储的下载签名 URL 缓存
1032
+
1033
+ `chooseImage`、`chooseVideo` 选择媒体文件
1034
+
1035
+ ```tsx
1036
+ import { useEffect } from 'react';
1037
+
1038
+ async function getPictureList() {
1039
+ // 从云端拉取用户私有的图片列表
1040
+ const list = await pictureListRequest();
1041
+ // 这样设置到缓存里,下次就不用再请求了
1042
+ for (const item of list) {
1043
+ setUrlByCloudKey(item.path, item.displayUrl);
1044
+ }
1045
+ }
1046
+ ```
1047
+
1048
+ # t-agent-ui-ray
1049
+
1050
+ t-agent-ui-ray 是一个基于 ray 的 UI 组件库,包含了一些常用的对话界面组件,例如消息列表、消息输入框等。
1051
+
1052
+ ## 安装
1053
+
1054
+ ```shell
1055
+ yarn add @ray-js/t-agent-ui-ray
1056
+ ```
1057
+
1058
+ ## 使用
1059
+
1060
+ ```tsx
1061
+ import { ChatContainer, MessageList, MessageInput } from '@ray-js/t-agent-ui-ray';
1062
+ // createAgent 实现参见 t-agent 的使用示例
1063
+ import { createAgent } from './createAgent';
1064
+
1065
+ export default function ChatPage() {
1066
+ // createAgent 必须返回一个 ChatAgent 应用过 withUI、withAIStream 插件的实例
1067
+ return (
1068
+ <View style={{ height: '100vh' }}>
1069
+ <ChatContainer createAgent={createAgent}>
1070
+ <MessageList />
1071
+ <MessageInput />
1072
+ </ChatContainer>
1073
+ </View>
1074
+ );
1075
+ }
1076
+ ```
1077
+
1078
+ ## 组件
1079
+
1080
+ ### ChatContainer
1081
+
1082
+ 对话容器,用于包裹消息列表和消息输入框,提供了 `ChatAgent` 的上下文
1083
+
1084
+ props:
1085
+
1086
+ - `className` 容器的类名
1087
+ - `createAgent` 创建 `ChatAgent` 的函数,在 `ChatContainer` 挂载后会调用这个函数创建 `ChatAgent` 实例
1088
+ - `agentRef` 用于获取 `ChatAgent` 实例的 ref
1089
+ - `renderOptions` 渲染选项,用于决定 `MessageList` 中各个元素的渲染方式,具体参照下面的 renderOptions 自定义渲染 部分
1090
+ - `renderTileAs` 该函数决定如何在消息中渲染 tile
1091
+ - `customBlockTypes` 自定义 block 类型,只有在这里注册的 block 类型才会被 `renderCustomBlockAs` 渲染
1092
+ - `renderCustomBlockAs` 该函数决定如何在 markdown 气泡消息中渲染自定义 block,默认支持 `echarts`
1093
+ - `renderCardAs` 该函数决定如何在消息中渲染卡片,一般不需要自定义此项
1094
+ - `renderLongPressAs` **(0.2.x 新增)** 该函数决定如何渲染长按菜单,可以自定义长按菜单的样式和行为
1095
+ - `formatErrorMessageAs` **(0.2.x 新增)** 该函数决定如何格式化错误消息,可以根据错误代码返回用户友好的错误信息
1096
+ - `customCardMap` 自定义卡片映射,无需修改 `renderCardAs` 函数,只需要在这里注册卡片类型和对应的组件
1097
+ - `getStaticResourceBizType` 获取静态资源 `bizType`,用于获取静态资源
1098
+
1099
+ ### MessageList
1100
+
1101
+ 消息列表,用于展示消息。在 0.2.x 版本中集成了 LazyScrollView 组件,提供了更好的性能优化。
1102
+
1103
+ **Props**:
1104
+
1105
+ - `className` 列表的类名
1106
+ - `roleSide` 消息角色的对齐方式,默认 `{ user: 'end', assistant: 'start' }`
1107
+
1108
+ **LazyScrollView 集成(0.2.x 新增)**:
1109
+
1110
+ MessageList 内部使用了 LazyScrollView 组件来优化大量消息的渲染性能:
1111
+
1112
+ - **懒加载渲染**:只渲染可见区域内的消息,大幅提升性能
1113
+ - **高度自适应**:自动计算消息高度,支持动态内容
1114
+ - **notifyHeightChanged()**:当消息内容发生变化时,自动通知高度更新
1115
+
1116
+ 组件会自动处理以下场景:
1117
+
1118
+ - 保证最下面 10 条消息始终渲染,避免滚动到底部时出现白屏
1119
+ - 消息高度变化时自动更新滚动位置
1120
+ - 支持滚动到底部的动画效果
1121
+
1122
+ ### MessageInput
1123
+
1124
+ 消息输入框,用于输入消息、上传附件、ASR 语音识别
1125
+
1126
+ props:
1127
+
1128
+ - `className` 输入框的类名
1129
+ - `placeholder` 输入框的占位符
1130
+ - `renderTop` 用于渲染输入框上方的内容
1131
+
1132
+ ### MessageActionBar(0.2.x 新增)
1133
+
1134
+ 消息操作栏组件,用于多选消息时显示操作按钮,支持删除选中消息和清空历史记录。
1135
+
1136
+ **Props**:
1137
+
1138
+ 无需传入任何 props,组件会自动根据多选状态显示和隐藏
1139
+
1140
+ **功能**:
1141
+
1142
+ - **返回按钮**:退出多选模式
1143
+ - **清空历史按钮**:清空所有历史消息,会调用 `onClearHistory` Hook
1144
+ - **删除选中按钮**:删除当前选中的消息,当没有选中消息时按钮会被禁用
1145
+
1146
+ **工作原理**:
1147
+
1148
+ MessageActionBar 组件会监听会话数据中的 `UIRay.multiSelect.show` 状态来决定是否显示。当用户长按消息选择"多选"时,该组件会自动显示。
1149
+
1150
+ **使用示例**:
1151
+
1152
+ ```tsx
1153
+ export default function ChatPage() {
1154
+ return (
1155
+ <View style={{ height: '100vh' }}>
1156
+ <ChatContainer createAgent={createAgent}>
1157
+ <MessageList />
1158
+ <MessageInput />
1159
+ <MessageActionBar />
1160
+ </ChatContainer>
1161
+ </View>
1162
+ );
1163
+ }
1164
+ ```
1165
+
1166
+ ### PrivateImage
1167
+
1168
+ 私有图片组件,用于展示私有图片,props 同 Image,增加 bizType 参数
1169
+
1170
+ ### LazyScrollView
1171
+
1172
+ 懒加载滚动视图组件,用于优化长列表性能,自动管理可见区域的渲染
1173
+
1174
+ 主要特性:
1175
+
1176
+ - 虚拟滚动:只渲染可见区域的元素
1177
+ - 高度缓存:自动缓存元素高度,提升滚动性能
1178
+ - 动态加载:根据滚动位置动态显示/隐藏元素
1179
+ - `notifyHeightChanged()` 功能:当元素高度发生变化时,可以调用此方法通知滚动视图更新
1180
+
1181
+ 使用说明:
1182
+
1183
+ LazyScrollView 主要在 MessageList 内部使用,开发者一般不需要直接使用。如果需要在消息中动态改变高度,可以通过 `notifyHeightChanged` 参数来通知高度变化:
1184
+
1185
+ ```tsx
1186
+ // 在 tile 组件中使用
1187
+ const MyTile = ({ notifyHeightChanged }) => {
1188
+ const [expanded, setExpanded] = useState(false);
1189
+
1190
+ const handleToggle = () => {
1191
+ setExpanded(!expanded);
1192
+ // 通知高度变化
1193
+ notifyHeightChanged();
1194
+ };
1195
+
1196
+ return (
1197
+ <View>
1198
+ <Button onClick={handleToggle}>展开/收起</Button>
1199
+ {expanded && <View>详细内容...</View>}
1200
+ </View>
1201
+ );
1202
+ };
1203
+ ```
1204
+
1205
+ ### 内置 tile 组件
1206
+
1207
+ - bubble 气泡
1208
+ - buttons 按钮组
1209
+ - card 卡片
1210
+ - image 图片
1211
+ - recommendations 推荐行动
1212
+ - text 文本,包含 markdown 支持
1213
+ - time 时间标识
1214
+ - tip 提示
1215
+ - video 视频
1216
+ - workflow 工作选项
1217
+
1218
+ ### 内置 card
1219
+
1220
+ - WorkflowReplyCard 工作流回复卡片
1221
+
1222
+ ## React Hooks
1223
+
1224
+ ### useChatAgent
1225
+
1226
+ 在 `ChatContainer` 上下文里取得 `ChatAgent` 实例
1227
+
1228
+ ### useAgentMessage
1229
+
1230
+ 在 `ChatContainer` 上下文里取得 `messages: ChatMessageObject[]` 列表
1231
+
1232
+ ### useRenderOptions
1233
+
1234
+ 在 `ChatContainer` 上下文里取得 `renderOptions` 对象
1235
+
1236
+ ### useOnEvent
1237
+
1238
+ 在 `ChatContainer` 上下文里注册 ui 事件,在组件卸载时自动取消注册
1239
+
1240
+ ```tsx
1241
+ import { useOnEvent } from '@ray-js/t-agent-ui-ray';
1242
+
1243
+ const MyComponent = () => {
1244
+ useOnEvent('scrollToBottom', payload => {
1245
+ console.log('scroll to bottom', payload.animation);
1246
+ });
1247
+
1248
+ return <div>My Component</div>;
1249
+ };
1250
+ ```
1251
+
1252
+ ### useEmitEvent
1253
+
1254
+ 在 `ChatContainer` 上下文里触发 ui 事件
1255
+
1256
+ ```tsx
1257
+ import { useEmitEvent } from '@ray-js/t-agent-ui-ray';
1258
+
1259
+ const MyComponent = () => {
1260
+ const emitEvent = useEmitEvent();
1261
+
1262
+ const scroll = () => {
1263
+ emitEvent('scrollToBottom', { animation: false });
1264
+ };
1265
+
1266
+ return <button onClick={scroll}>Scroll to bottom</button>;
1267
+ };
1268
+ ```
1269
+
1270
+ ### useTileProps
1271
+
1272
+ 在 tile 组件里取得 `TileProps` 对象,如果是 tile,可以直接从 props 中获取
1273
+
1274
+ ```tsx
1275
+ import { useTileProps } from '@ray-js/t-agent-ui-ray';
1276
+
1277
+ const MyTilePart = () => {
1278
+ const { message, agent, tile, emitTileEvent } = useTileProps();
1279
+
1280
+ return <div>My Tile</div>;
1281
+ };
1282
+ ```
1283
+
1284
+ ### useSendAction
1285
+
1286
+ 发送一个 TTTAction,注意只能在 tile 组件(或 card)里使用
1287
+
1288
+ ```tsx
1289
+ import { useSendAction } from '@ray-js/t-agent-ui-ray';
1290
+
1291
+ const MyTilePart = () => {
1292
+ const sendAction = useSendAction();
1293
+
1294
+ const handleClick = () => {
1295
+ sendAction({ type: 'sendMessage', blocks: [{ type: 'text', text: 'hello' }] });
1296
+ };
1297
+
1298
+ return <button onClick={handleClick}>Send Message</button>;
1299
+ };
1300
+ ```
1301
+
1302
+ ### useTranslate
1303
+
1304
+ 获取国际化翻译函数,用于翻译界面文本,提供了完整的多语言支持。
1305
+
1306
+ ```tsx
1307
+ import { useTranslate } from '@ray-js/t-agent-ui-ray';
1308
+
1309
+ const MyComponent = () => {
1310
+ const t = useTranslate();
1311
+
1312
+ return (
1313
+ <div>
1314
+ {t('t-agent.message.action.copy')} {/* 输出: "复制消息" */}
1315
+ {t('t-agent.message.delete.title')} {/* 输出: "删除消息" */}
1316
+ {t('t-agent.message.clear-history.title')} {/* 输出: "清空历史" */}
1317
+ </div>
1318
+ );
1319
+ };
1320
+ ```
1321
+
1322
+ **支持的语言**:
1323
+
1324
+ 内置的多语言支持包括:
1325
+
1326
+ - **中文简体** (`zh-Hans`):简体中文
1327
+ - **中文繁体** (`zh-Hant`):繁体中文
1328
+ - **英文** (`en`):英语
1329
+ - **日文** (`ja`):日语
1330
+ - **德文** (`de`):德语
1331
+ - **法文** (`fr`):法语
1332
+ - **西班牙文** (`es`):西班牙语
1333
+ - **意大利文** (`it`):意大利语
1334
+
1335
+ 系统会根据用户的系统语言自动选择对应的翻译,如果不支持当前语言则回退到英文。
1336
+
1337
+ ## renderOptions 自定义渲染
1338
+
1339
+ ### 替换或新增 tile
1340
+
1341
+ 如果你需要将某个 tile 替换成自己的实现,或者新增一个 tile,可以覆写 `renderTileAs`,例如:
1342
+
1343
+ ```tsx
1344
+ import { ImageTileData } from '@ray-js/t-agent';
1345
+ import { Image } from '@ray-js/ray';
1346
+ import { defaultRenderOptions, TileProps } from '@ray-js/t-agent-ui-ray';
1347
+
1348
+ function MyImageTile(props: TileProps<ImageTileData>) {
1349
+ // 实现自己的 ImageTile
1350
+ return <Image src={props.tile.data.src}></Image>;
1351
+ }
1352
+
1353
+ const renderOptions = {
1354
+ ...defaultRenderOptions,
1355
+ renderTileAs: (props: TileProps) => {
1356
+ if (props.tile.type === 'image') {
1357
+ return <MyImageTile {...props} />;
1358
+ }
1359
+ // 保持默认行为
1360
+ return defaultRenderOptions.renderTileAs(props);
1361
+ },
1362
+ };
1363
+ ```
1364
+
1365
+ ### 自定义长按菜单(0.2.x 新增)
1366
+
1367
+ 如果你需要自定义长按菜单的样式或行为,可以覆写 `renderLongPressAs` 函数,例如:
1368
+
1369
+ ```tsx
1370
+ import { defaultRenderOptions, LongPressResult } from '@ray-js/t-agent-ui-ray';
1371
+ import { View, Button } from '@ray-js/ray';
1372
+
1373
+ const renderOptions = {
1374
+ ...defaultRenderOptions,
1375
+ renderLongPressAs: (res: LongPressResult) => {
1376
+ if (!res.menuProps.showActionMenu) {
1377
+ return null;
1378
+ }
1379
+
1380
+ return (
1381
+ <View className="my-custom-menu">
1382
+ {res.menuProps.menuItems.map(item => (
1383
+ <Button key={item.key} onClick={() => res.menuProps.handleMenuItemClick(item)}>
1384
+ {item.displayLabel}
1385
+ </Button>
1386
+ ))}
1387
+ </View>
1388
+ );
1389
+ },
1390
+ };
1391
+ ```
1392
+
1393
+ 长按菜单功能包括:
1394
+
1395
+ - **复制消息**:复制文本内容到剪贴板
1396
+ - **删除消息**:删除单条消息
1397
+ - **多选**:进入多选模式,配合 MessageActionBar 使用
1398
+ - **喜欢/不喜欢**:对助手消息进行反馈(仅对 assistant 角色消息可用)
1399
+
1400
+ ### 自定义错误消息格式化(0.2.x 新增)
1401
+
1402
+ 如果你需要自定义错误消息的显示格式,可以覆写 `formatErrorMessageAs` 函数,例如:
1403
+
1404
+ ```tsx
1405
+ import { defaultRenderOptions } from '@ray-js/t-agent-ui-ray';
1406
+
1407
+ const renderOptions = {
1408
+ ...defaultRenderOptions,
1409
+ formatErrorMessageAs: (message: string, code: string | undefined) => {
1410
+ // 根据错误代码返回自定义的错误消息
1411
+ if (code === 'network-offline') {
1412
+ return '网络连接异常,请检查您的网络设置';
1413
+ }
1414
+ if (code === 'timeout') {
1415
+ return '请求超时,请稍后重试';
1416
+ }
1417
+ // 使用默认的错误消息
1418
+ return message;
1419
+ },
1420
+ };
1421
+ ```
1422
+
1423
+ 内置支持的错误代码包括:
1424
+
1425
+ - `network-offline`:网络已断开
1426
+ - `timeout`:发送超时
1427
+ - `invalid-params`:无效参数
1428
+ - `session-create-failed`:连接失败
1429
+ - `connection-closed`:连接已关闭
1430
+ - 等等
1431
+
1432
+ ### 自定义卡片
1433
+
1434
+ 卡片分为三类:内置卡片(buildIn)、自定义卡片(custom)、低代码卡片(lowCode),目前低代码卡片还在开发中,自定义卡片可以通过 `customCardMap` 注册自己的卡片组件。
1435
+
1436
+ 卡片的数据结构如下:
1437
+
1438
+ ```tsx
1439
+ enum ChatCardType {
1440
+ CUSTOM = 'custom', // 可供业务方使用的自定义卡片
1441
+ BUILD_IN = 'buildIn', // 平台内置的卡片
1442
+ LOW_CODE = 'lowCode', // 低代码卡片
1443
+ }
1444
+
1445
+ interface ChatCardObject<T = any> {
1446
+ cardCode: string; // 唯一标识卡片的 code
1447
+ cardType: ChatCardType; // 卡片类型
1448
+ cardData: T; // 卡片携带的数据
1449
+ }
1450
+ ```
1451
+
1452
+ 注册一个自定义卡片:
1453
+
1454
+ ```tsx
1455
+ import {
1456
+ ChatCardObject,
1457
+ ChatCardType,
1458
+ defaultRenderOptions,
1459
+ useTileProps,
1460
+ useSendAction,
1461
+ } from '@ray-js/t-agent-ui-ray';
1462
+ import { View, Text, Button } from '@ray-js/ray';
1463
+
1464
+ const MyCard: ChatCardComponent<{ title: string }, { clicked: boolean }> = props => {
1465
+ // 如果你需要拿到 agent、message、tile、emitTileEvent 等属性,可以使用 useTileProps
1466
+ const { message, agent, tile, emitTileEvent } = useTileProps();
1467
+ const { card, setCardState } = props;
1468
+ const { cardData, cardState, cardCode } = card as ChatCardObject<{ title: string }>;
1469
+
1470
+ // 如果你需要发送一个 TTTAction,可以使用 useSendAction
1471
+ const sendAction = useSendAction();
1472
+
1473
+ return (
1474
+ <View>
1475
+ <Text>My Card</Text>
1476
+ <Button
1477
+ onClick={() => {
1478
+ sendAction({ type: 'sendMessage', blocks: [{ type: 'text', text: 'hello' }] });
1479
+ // 如果需要更新卡片状态,可以使用 setCardState
1480
+ // 第二个参数表示是否持久化状态
1481
+ setCardState({ clicked: true }, { persist: true });
1482
+ }}
1483
+ >
1484
+ 填充文本到输入框
1485
+ </Button>
1486
+ </View>
1487
+ );
1488
+ };
1489
+
1490
+ const renderOptions = {
1491
+ ...defaultRenderOptions,
1492
+ customCardMap: {
1493
+ myCard: MyCard,
1494
+ },
1495
+ };
1496
+ ```
1497
+
1498
+ ### 自定义 block
1499
+
1500
+ 在 `TextTile` 里的 markdown 渲染器是支持自定义 block 的,你可以通过 `customBlockTypes` 和 `renderCustomBlockAs` 来注册和渲染自定义 block。
1501
+
1502
+ block 的数据结构如下:
1503
+
1504
+ ```tsx
1505
+ export interface MarkdownBlock {
1506
+ id: string;
1507
+ type: string;
1508
+ children: string; // block 里的内容
1509
+ }
1510
+ ```
1511
+
1512
+ 注册一个自定义 block:
1513
+
1514
+ ```tsx
1515
+ import { defaultRenderOptions, MarkdownBlock } from '@ray-js/t-agent-ui-ray';
1516
+ import { View, Text } from '@ray-js/ray';
1517
+
1518
+ const renderOptions = {
1519
+ ...defaultRenderOptions,
1520
+ customBlockTypes: ['my-block'],
1521
+ renderCustomBlockAs: (block: MarkdownBlock) => {
1522
+ if (block.type === 'my-block') {
1523
+ return (
1524
+ <View>
1525
+ <View>This is My Block</View>
1526
+ <View>{block.children}</View>
1527
+ </View>
1528
+ );
1529
+ }
1530
+ return defaultRenderOptions.renderCustomBlockAs(props);
1531
+ },
1532
+ };
1533
+ ```
1534
+
1535
+ 假设 AI 给你发了 markdown 文本,里面有一个类型是 `my-block` 的 `fence`,在上面我们注册了 `my-block`,那这个 `fence` 可以当做自定义 block。
1536
+
1537
+ ````markdown
1538
+ 这是我的自定义 block!
1539
+
1540
+ ```my-block
1541
+ Hello, world!
1542
+ ```
1543
+ ````
1544
+
1545
+ 以下 fence 没有注册过,不会被渲染成自定义 block,仅当做普通的代码块渲染。
1546
+
1547
+ ```javascript
1548
+ console.log('Hello, world!');
1549
+ ```
1550
+
1551
+ 渲染结果如下:
1552
+
1553
+ 这是我的自定义 block!
1554
+ This is My Block
1555
+ Hello, world!
1556
+ 以下 fence 没有注册过,不会被渲染成自定义 block,仅当做普通的代码块渲染。
1557
+
1558
+ console.log('Hello, world!');
1559
+
1560
+ ### getStaticResourceBizType
1561
+
1562
+ 如果你的静态资源需要带上 `bizType`,可以通过 `getStaticResourceBizType` 来获取 `bizType`。
1563
+
1564
+ ```tsx
1565
+ import { defaultRenderOptions } from '@ray-js/t-agent-ui-ray';
1566
+
1567
+ const renderOptions = {
1568
+ ...defaultRenderOptions,
1569
+ getStaticResourceBizType: (src: string, scene: string) => 'bizType',
1570
+ };
1571
+ ```
1572
+
1573
+ 针对不同的场景,你可能需要不同的 `bizType`,你可以根据 `src` 和 `scene` 来返回不同的 `bizType`。
1574
+
1575
+ 内置的 `scene` 有以下几种:
1576
+
1577
+ - `image:view` 图片查看
1578
+ - `image:upload` 图片上传
1579
+ - `video:view` 视频查看
1580
+ - `video:upload` 视频上传
1581
+ - `videoThumb:view` 视频缩略图查看
1582
+ - `videoThumb:upload` 视频缩略图上传
1583
+
1584
+ ### 自定义多语言
1585
+
1586
+ 如果你需要自定义 t-agent 里的多语言,可以覆写 `i18nTranslate` 函数,例如:
1587
+
1588
+ ```tsx
1589
+ import { defaultRenderOptions } from '@ray-js/t-agent-ui-ray';
1590
+
1591
+ const renderOptions = {
1592
+ ...defaultRenderOptions,
1593
+ i18nTranslate: (key: string) => {
1594
+ if (key === 'hello') {
1595
+ return '你好';
1596
+ }
1597
+ // 使用默认的多语言
1598
+ return I18n.t(key);
1599
+ },
1600
+ };
1601
+ ```
1602
+
1603
+ 以下是内置的多语言 key:
1604
+
1605
+ | key | 使用场景 | 含义 |
1606
+ | ---------------------------------------------------------- | --------------------------- | ---------------------------------------- |
1607
+ | t-agent.build-in.button.create_scene_manually | ButtonTile 内置按钮 | 手动创建场景 |
1608
+ | t-agent.build-in.button.enter_home_manage | ButtonTile 内置按钮 | 进入"家庭管理" |
1609
+ | t-agent.build-in.button.enter_room_manage | ButtonTile 内置按钮 | 进入"房间管理" |
1610
+ | t-agent.build-in.button.enter_alarm_message | ButtonTile 内置按钮 | 进入"告警消息列表" |
1611
+ | t-agent.build-in.button.enter_home_message | ButtonTile 内置按钮 | 进入"家庭消息列表" |
1612
+ | t-agent.build-in.button.enter_bulletin | ButtonTile 内置按钮 | 进入"通知消息列表" |
1613
+ | t-agent.build-in.button.enter_notification_setting | ButtonTile 内置按钮 | 进入"消息推送设置" |
1614
+ | t-agent.build-in.button.enter_personal_information | ButtonTile 内置按钮 | 进入"个人资料" |
1615
+ | t-agent.build-in.button.enter_account_security | ButtonTile 内置按钮 | 进入"账号与安全" |
1616
+ | t-agent.build-in.button.enter_setting | ButtonTile 内置按钮 | 进入"通用设置" |
1617
+ | t-agent.build-in.button.enter_paring | ButtonTile 内置按钮 | 进入"设备配网" |
1618
+ | t-agent.build-in.button.enter_share_device | ButtonTile 内置按钮 | 进入"设备分享" |
1619
+ | t-agent.build-in.button.enter_faq_feedback | ButtonTile 内置按钮 | 进入"常见问题与反馈" |
1620
+ | t-agent.build-in.button.questionnaire_take | ButtonTile 内置按钮 | 填写问卷 |
1621
+ | t-agent.build-in.button.set_home_location | ButtonTile 内置按钮 | 设置家庭位置 |
1622
+ | t-agent.input.voice.require-permission | MessageInput 切换语音输入 | 需要授权录音权限 |
1623
+ | t-agent.input.upload.failed | MessageInput 上传文件 | 文件上传失败 |
1624
+ | t-agent.input.asr.oninput.text.top | MessageInput ASR 语音输入 | 我在听,请说话 |
1625
+ | t-agent.input.asr.oninput.text.center | MessageInput ASR 语音输入 | 松开发送,上划取消 |
1626
+ | t-agent.input.asr.ptt | MessageInput ASR 语音输入 | 按住说话 |
1627
+ | t-agent.input.asr.error.too-short | MessageInput ASR 错误 | 说话时间太短 |
1628
+ | t-agent.input.asr.error.empty | MessageInput ASR 错误 | 未能从语音中识别到文字 |
1629
+ | t-agent.input.asr.error.unknown | MessageInput ASR 错误 | 语音识别失败 |
1630
+ | t-agent.input.asr.error.timeout | MessageInput ASR 错误 | 语音识别已达时长限制,将直接发送 |
1631
+ | t-agent.input.upload.source-type.camera | MessageInput 上传文件 | 拍照 |
1632
+ | t-agent.input.upload.source-type.camera.require-permission | MessageInput 上传文件 | 拍照需要摄像头权限,请在设置中开启 |
1633
+ | t-agent.input.upload.source-type.album | MessageInput 上传文件 | 从相册中选择 |
1634
+ | t-agent.input.upload.source-type.album.require-permission | MessageInput 上传文件 | 从相册中选择需要相册权限,请在设置中开启 |
1635
+ | t-agent.input.upload.image.max-reached | MessageInput 上传文件 | 已达到图片上传上限 |
1636
+ | t-agent.input.upload.video.max-reached | MessageInput 上传文件 | 已达到视频上传上限 |
1637
+ | t-agent.file-tile.unknown-filename | FileTile 文件显示 | 文件 |
1638
+ | t-agent.message.feedback.success | BubbleTile 消息评价 | 反馈成功 |
1639
+ | t-agent.message.bubble.aborted | BubbleTile 消息 | 用户中断 |
1640
+ | t-agent.message.action.copy | BubbleTile 长按菜单 | 复制消息 |
1641
+ | t-agent.message.action.delete | BubbleTile 长按菜单 | 删除消息 |
1642
+ | t-agent.message.action.multi-select | BubbleTile 长按菜单 | 多选 |
1643
+ | t-agent.message.action.like | BubbleTile 长按菜单 | 喜欢消息 |
1644
+ | t-agent.message.action.unlike | BubbleTile 长按菜单 | 不喜欢消息 |
1645
+ | t-agent.message.copy.success | BubbleTile 复制成功 | 复制成功 |
1646
+ | t-agent.message.delete.success | BubbleTile 删除成功 | 删除成功 |
1647
+ | t-agent.message.like.success | BubbleTile 反馈 | 点赞成功 |
1648
+ | t-agent.message.unlike.success | BubbleTile 反馈 | 取消点赞成功 |
1649
+ | t-agent.message.delete.title | BubbleTile 删除消息弹窗标题 | 删除消息 |
1650
+ | t-agent.message.delete.content | BubbleTile 删除消息弹窗内容 | 确定要删除这条消息吗? |
1651
+ | t-agent.message.delete.confirm | BubbleTile 删除消息弹窗确认 | 确认 |
1652
+ | t-agent.message.delete.cancel | BubbleTile 删除消息弹窗取消 | 取消 |
1653
+ | t-agent.message.clear-history.title | MessageActionBar 清空历史 | 清空历史 |
1654
+ | t-agent.message.clear-history.content | MessageActionBar 清空历史 | 确定要清空历史吗? |
1655
+ | t-agent.message.clear-history.button | MessageActionBar 清空历史 | 清空历史 |
1656
+ | t-agent.message.multi-select-delete.title | MessageActionBar 多选删除 | 删除选中消息 |
1657
+ | t-agent.message.multi-select-delete.content | MessageActionBar 多选删除 | 确定要删除这些选中的消息吗? |
1658
+ | t-agent.execute-card-tile.execution.success | ExecuteCardTile 执行结果 | 执行成功 |
1659
+ | t-agent.execute-card-tile.execution.failed | ExecuteCardTile 执行结果 | 执行失败 |
1660
+ | t-agent.execute-card-tile.scene.invalid | ExecuteCardTile 场景状态 | 场景失效 |
1661
+ | t-agent.execute-card-tile.delete | ExecuteCardTile 按钮 | 删除 |
1662
+ | t-agent.execute-card-tile.execute | ExecuteCardTile 按钮 | 执行 |
1663
+ | t-agent.execute-card-tile.switch.scene.state | ExecuteCardTile 操作 | 切换场景状态 |
1664
+ | t-agent.operate-card-tile.open.device.failed | OperateCardTile 操作结果 | 打开设备失败 |
1665
+ | t-agent.operate-card-tile.open.scene.failed | OperateCardTile 操作结果 | 打开场景失败 |
1666
+ | t-agent.operate-card-tile.operation.impact | OperateCardTile 标题 | 本次操作影响: |
1667
+ | t-agent.operate-card-tile.hide.details | OperateCardTile 按钮 | 收起详情 |
1668
+ | t-agent.operate-card-tile.view.details | OperateCardTile 按钮 | 查看详情 |
1669
+ | t-agent.operate-card-tile.device.move.desc | OperateCardTile 设备移动 | 设备"{device}"移动到"{room}" |
1670
+ | t-agent.operate-card-tile.device.rename.desc | OperateCardTile 设备重命名 | 设备"{oldName}"改名"{newName}" |
1671
+ | t-agent.operate-card-tile.device.count | OperateCardTile 设备计数 | {count}个设备 |
1672
+ | t-agent.operate-card-tile.scene.count | OperateCardTile 场景计数 | {count}个场景 |
1673
+ | t-agent.operate-card-tile.home.count | OperateCardTile 家庭计数 | {count}个家庭 |
1674
+ | t-agent.operate-card-tile.room.count | OperateCardTile 房间计数 | {count}个房间 |
1675
+ | t-agent.operate-card-tile.group.count | OperateCardTile 群组计数 | {count}个群组 |
1676
+ | t-agent.operate-card-tile.description.format | OperateCardTile 描述格式 | {items}。 |
1677
+ | t-agent.operate-card-tile.description.separator | OperateCardTile 描述分隔符 | , |
1678
+ | t-agent.expand.tab.device | ExpandTile 标签页 | 设备 |
1679
+ | t-agent.expand.tab.scene | ExpandTile 标签页 | 场景 |
1680
+ | t-agent.expand.tab.more | ExpandTile 标签页 | 其他 |
1681
+ | t-agent.expand.execution.success | ExpandTile 执行结果 | 执行成功 |
1682
+ | t-agent.expand.execution.failed | ExpandTile 执行结果 | 执行失败 |
1683
+ | t-agent.expand.device.rename | ExpandTile 设备重命名 | {oldName}改名成{newName} |
1684
+ | t-agent.expand.scene.rename | ExpandTile 场景重命名 | {oldName}改名成{newName} |
1685
+ | t-agent.expand.scene.one-click | ExpandTile 场景类型 | 一键执行 |
1686
+ | t-agent.expand.scene.auto | ExpandTile 场景类型 | 自动执行 |
1687
+ | t-agent.expand.no.details | ExpandTile 详情显示 | 没有可显示的详情内容 |
1688
+ | t-agent.error.unknown-error | 错误提示 | 未知错误 |
1689
+ | t-agent.error.network-offline | 错误提示 | 网络已断开,请检查网络连接 |
1690
+ | t-agent.error.invalid-params | 错误提示 | 无效参数,请重试 |
1691
+ | t-agent.error.session-create-failed | 错误提示 | 连接失败,请重试 |
1692
+ | t-agent.error.connection-closed | 错误提示 | 连接已关闭,请重试 |
1693
+ | t-agent.error.event-exists | 错误提示 | 消息发送异常,请稍后再试 |
1694
+ | t-agent.error.event-disposed | 错误提示 | 消息发送异常,请稍后再试 |
1695
+ | t-agent.error.event-closed | 错误提示 | 消息发送异常,请稍后再试 |
1696
+ | t-agent.error.event-aborted | 错误提示 | 消息已中断 |
1697
+ | t-agent.error.event-write-failed | 错误提示 | 消息发送异常,请稍后再试 |
1698
+ | t-agent.error.event-no-data-code | 错误提示 | 消息发送异常,请稍后再试 |
1699
+ | t-agent.error.stream-exists | 错误提示 | 消息发送异常,请稍后再试 |
1700
+ | t-agent.error.timeout | 错误提示 | 发送超时 |
1701
+ | t-agent.error.asr-empty | 错误提示 | 语音识别结果为空 |
1702
+
1703
+ # 更新日志
1704
+
1705
+ ## 0.2.x 版本
1706
+
1707
+ ### @ray-js/t-agent
1708
+
1709
+ - **Hook 机制增强**:新增 `onMessageFeedback` 和 `onClearHistory` 等生命周期钩子
1710
+ - **消息状态管理**:优化消息状态管理,提供更精确的消息状态控制
1711
+ - **错误处理**:增强错误处理机制,支持更详细的错误信息和错误分类
1712
+ - **性能优化**:优化内存管理和垃圾回收机制
1713
+
1714
+ ### @ray-js/t-agent-plugin-aistream
1715
+
1716
+ - **全新插件**:替代废弃的 assistant 插件,提供更强大的功能
1717
+ - **语音合成**:支持 TTS 功能,通过 `enableTts` 参数控制
1718
+ - **连接优化**:新增 `earlyStart` 参数,支持提前建立连接,减少首次响应时间
1719
+ - **Token 管理**:优化 Token 获取机制,支持自定义 `tokenOptions`
1720
+ - **语音识别**:新增 AsrAgent 语音识别功能,支持实时语音转文字
1721
+ - **Mock 机制**:改进的 mock 机制,支持更灵活的测试场景
1722
+ - **多模态支持**:默认支持文本、图片、语音等多种输入类型
1723
+
1724
+ ### @ray-js/t-agent-ui-ray
1725
+
1726
+ - **消息操作栏**:新增 MessageActionBar 组件,支持多选操作和批量删除
1727
+ - **虚拟滚动**:集成 LazyScrollView,提供虚拟滚动和性能优化
1728
+ - **国际化系统**:完整的国际化系统,支持中文简繁体、英文、日文等 8 种语言
1729
+ - **翻译 Hook**:新增 useTranslate Hook,简化多语言使用
1730
+ - **自定义渲染**:扩展 renderOptions,支持更多自定义渲染选项
1731
+ - **交互优化**:优化长按菜单功能,支持复制、删除、多选、点赞等操作
1732
+ - **UI 完善**:新增多语言键值对,覆盖所有 UI 交互场景