@ray-js/t-agent-ui-ray 0.2.7-beta.1 → 0.2.7-beta.10

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
@@ -771,6 +771,7 @@ const createAgent = () => {
771
771
  - `indexId` 索引 ID,默认为 'default'
772
772
  - `homeId` 家庭 ID,不填默认当前家庭
773
773
  - `earlyStart` 是否在 onAgentStart 阶段就建立连接
774
+ - `eventIdPrefix` eventId 前缀,用于方便云端调试和日志追踪
774
775
  - `tokenOptions` 获取 agent token 的参数
775
776
  - `api` API 接口名
776
777
  - `version` 接口版本
@@ -779,14 +780,30 @@ const createAgent = () => {
779
780
 
780
781
  方法:
781
782
 
782
- - `agent.plugins.aiStream.send` 向智能体发送一条消息
783
- - `agent.plugins.aiStream.chat` 向智能体发送一条消息,并生成提问 ChatMessage 对象和 AI 回答 ChatMessage 对象,流式更新
783
+ - `agent.plugins.aiStream.send(blocks, signal, userData)` 向智能体发送一条消息
784
+ - `blocks` 输入块数组
785
+ - `signal` 可选的 AbortSignal,用于中断请求
786
+ - `userData` 可选的用户数据,会附带在发送的消息中
787
+ - `agent.plugins.aiStream.chat(blocks, signal, options)` 向智能体发送一条消息,并生成提问 ChatMessage 对象和 AI 回答 ChatMessage 对象,流式更新
788
+ - `blocks` 输入块数组
789
+ - `signal` 可选的 AbortSignal
790
+ - `options.sendBy` 发送者角色,默认为 'user'
791
+ - `options.responseBy` 响应者角色,默认为 'assistant'
792
+ - `options.userData` 可选的用户数据
793
+ - `agent.plugins.aiStream.getChatId()` 获取当前会话的 chatId,返回 Promise<string>
784
794
 
785
795
  Hooks:
786
796
 
787
797
  - `onMessageParse` 当读取历史消息,解析消息时触发,可以在这个 Hook 里修改消息
788
798
  - `msgItem` 存储的消息对象
789
799
  - `result.messages` 解析后的消息列表
800
+ - `onChatMessageSent` 当用户消息和响应消息创建后触发
801
+ - `userMessage` 用户发送的消息
802
+ - `respMessage` AI 的响应消息
803
+ - `onTextCompose` 当收到文本数据时触发,用于处理文本的渲染
804
+ - `respMsg` 响应消息
805
+ - `status` 消息状态
806
+ - `result.text` 文本内容,可以修改
790
807
  - `onSkillCompose` 当收到技能数据时触发,用于处理技能的渲染
791
808
  - `skill` 技能数据数组 (ReceivedTextSkillPacketBody[])
792
809
  - `respMsg` 响应消息
@@ -801,6 +818,47 @@ Hooks:
801
818
  - `onCardsReceived` 当收到卡片数据时触发
802
819
  - `skills` 技能数据列表 (ReceivedTextSkillPacketBody[])
803
820
  - `result.cards` 卡片列表
821
+ - `onUserDataRead` **(0.2.x 新增)** 当需要读取用户自定义数据时触发,用于向 AI 平台传递额外的上下文信息
822
+ - `type` 触发类型,可以是 'create-session' 或 'start-event'
823
+ - `'create-session'` 创建会话时触发,只触发一次
824
+ - `'start-event'` 每次发送消息时触发
825
+ - `data` 上下文数据
826
+ - `data.blocks` 当 type 为 'start-event' 时,包含本次发送的输入块
827
+ - `result.userData` 返回的用户数据对象,会被合并后发送给 AI 平台
828
+
829
+ **使用示例**:
830
+
831
+ ```tsx
832
+ const agent = createChatAgent(
833
+ withUI(),
834
+ withAIStream({
835
+ agentId: 'your-agent-id',
836
+ })
837
+ );
838
+
839
+ agent.plugins.aiStream.onUserDataRead((type, data, result) => {
840
+ // 在创建会话时传递用户信息
841
+ if (type === 'create-session') {
842
+ result.sessionAttributes = {
843
+ 'custom.param': {
844
+ userName: { value: 'John' },
845
+ userLevel: { value: 'Plus' },
846
+ },
847
+ };
848
+ return;
849
+ }
850
+ // 在每次发送消息时传递动态上下文
851
+ if (type === 'start-event') {
852
+ result.userData = {
853
+ 'custom.param': {
854
+ timestamp: { value: Date.now() },
855
+ pid: { value: '123456' },
856
+ },
857
+ };
858
+ return;
859
+ }
860
+ });
861
+ ```
804
862
 
805
863
  ### withBuildIn 插件
806
864
 
package/README.md CHANGED
@@ -766,6 +766,7 @@ Parameters:
766
766
  - `indexId` Index ID, defaults to 'default'
767
767
  - `homeId` Home ID, defaults to current home if not provided
768
768
  - `earlyStart` Whether to establish connection during onAgentStart phase
769
+ - `eventIdPrefix` Event ID prefix for cloud debugging and log tracing
769
770
  - `tokenOptions` Parameters for getting agent token
770
771
  - `api` API interface name
771
772
  - `version` Interface version
@@ -774,14 +775,30 @@ Parameters:
774
775
 
775
776
  Methods:
776
777
 
777
- - `agent.plugins.aiStream.send`: Send a message to the agent
778
- - `agent.plugins.aiStream.chat`: Send a message to the agent while generating a ChatMessage object for the question and the AI's answer, updating in a streaming manner
778
+ - `agent.plugins.aiStream.send(blocks, signal, userData)` Send a message to the agent
779
+ - `blocks` Input block array
780
+ - `signal` Optional AbortSignal for interrupting requests
781
+ - `userData` Optional user data to be included with the message
782
+ - `agent.plugins.aiStream.chat(blocks, signal, options)` Send a message to the agent while generating a ChatMessage object for the question and the AI's answer, updating in a streaming manner
783
+ - `blocks` Input block array
784
+ - `signal` Optional AbortSignal
785
+ - `options.sendBy` Sender role, defaults to 'user'
786
+ - `options.responseBy` Responder role, defaults to 'assistant'
787
+ - `options.userData` Optional user data
788
+ - `agent.plugins.aiStream.getChatId()` Get the current session's chatId, returns Promise<string>
779
789
 
780
790
  Hooks:
781
791
 
782
792
  - `onMessageParse` Triggered when reading history messages and parsing them, allowing for message modification in this Hook
783
793
  - `msgItem` Stored message object
784
794
  - `result.messages` Parsed message list
795
+ - `onChatMessageSent` Triggered after user message and response message are created
796
+ - `userMessage` User's sent message
797
+ - `respMessage` AI's response message
798
+ - `onTextCompose` Triggered when receiving text data, used for handling text rendering
799
+ - `respMsg` Response message
800
+ - `status` Message status
801
+ - `result.text` Text content, can be modified
785
802
  - `onSkillCompose` Triggered when receiving skill data, used for handling skill rendering
786
803
  - `skill` Skill data array (ReceivedTextSkillPacketBody[])
787
804
  - `respMsg` Response message
@@ -796,6 +813,47 @@ Hooks:
796
813
  - `onCardsReceived` Triggered when receiving card data
797
814
  - `skills` Skill data list (ReceivedTextSkillPacketBody[])
798
815
  - `result.cards` Card list
816
+ - `onUserDataRead` **(0.2.x New)** Triggered when user custom data needs to be read, used to pass additional context information to the AI platform
817
+ - `type` Trigger type, can be 'create-session' or 'start-event'
818
+ - `'create-session'` Triggered when creating a session, only once
819
+ - `'start-event'` Triggered each time a message is sent
820
+ - `data` Context data
821
+ - `data.blocks` When type is 'start-event', contains the input blocks for this send
822
+ - `result.userData` Returned user data object, will be merged and sent to the AI platform
823
+
824
+ **Usage Example**:
825
+
826
+ ```tsx
827
+ const agent = createChatAgent(
828
+ withUI(),
829
+ withAIStream({
830
+ agentId: 'your-agent-id',
831
+ })
832
+ );
833
+
834
+ agent.plugins.aiStream.onUserDataRead((type, data, result) => {
835
+ // Pass user information when creating a session
836
+ if (type === 'create-session') {
837
+ result.sessionAttributes = {
838
+ 'custom.param': {
839
+ userName: { value: 'John' },
840
+ userLevel: { value: 'Plus' },
841
+ },
842
+ };
843
+ return;
844
+ }
845
+ // Pass dynamic context each time a message is sent
846
+ if (type === 'start-event') {
847
+ result.userData = {
848
+ 'custom.param': {
849
+ timestamp: { value: Date.now() },
850
+ pid: { value: '123456' },
851
+ },
852
+ };
853
+ return;
854
+ }
855
+ });
856
+ ```
799
857
 
800
858
  ### withBuildIn Plugin
801
859
 
@@ -77,7 +77,8 @@ export default function ChatContainer(props) {
77
77
  } = _ref;
78
78
  setMessages(messages);
79
79
  emitEvent('scrollToBottom', {
80
- animation: false
80
+ animation: false,
81
+ scene: 'message-list-init'
81
82
  });
82
83
  });
83
84
  const offMessageChange = onEvent('messageChange', async _ref2 => {
@@ -90,7 +91,8 @@ export default function ChatContainer(props) {
90
91
  {
91
92
  setMessages(prev => [...prev, message]);
92
93
  emitEvent('scrollToBottom', {
93
- animation: false
94
+ animation: false,
95
+ scene: 'message-show'
94
96
  });
95
97
  break;
96
98
  }
@@ -113,7 +115,8 @@ export default function ChatContainer(props) {
113
115
  });
114
116
  emitEvent('scrollToBottom', {
115
117
  animation: false,
116
- follow: true
118
+ follow: true,
119
+ scene: 'message-remove'
117
120
  });
118
121
  break;
119
122
  }
@@ -196,7 +196,8 @@ export class BlockParser {
196
196
  }
197
197
  const map = new Map();
198
198
  const ids = [];
199
- for (const item of this.pendingBlocks) {
199
+ for (let i = 0; i < this.pendingBlocks.length; i++) {
200
+ const item = this.pendingBlocks[i];
200
201
  map.set("<".concat(item.id, " />"), item);
201
202
  ids.push(item.id);
202
203
  }
@@ -10,6 +10,7 @@ interface Props {
10
10
  className?: string;
11
11
  renderTop?: React.ReactNode;
12
12
  placeholder?: string;
13
+ placeholderStyle?: string;
13
14
  style?: React.CSSProperties;
14
15
  attachment?: boolean | AttachmentOptions;
15
16
  maxTextLength?: number;
@@ -177,7 +177,8 @@ export default function MessageInputAIStream(props) {
177
177
  }
178
178
  attachmentInput.loadBlocks(blocks);
179
179
  let t = '';
180
- for (const block of blocks) {
180
+ for (let i = 0; i < blocks.length; i++) {
181
+ const block = blocks[i];
181
182
  if (block.type === 'text') {
182
183
  t = block.text;
183
184
  }
@@ -191,7 +192,8 @@ export default function MessageInputAIStream(props) {
191
192
  setMoreOpen(!moreOpen);
192
193
  if (!moreOpen) {
193
194
  emitEvent('scrollToBottom', {
194
- animation: true
195
+ animation: true,
196
+ scene: 'message-input-expand'
195
197
  });
196
198
  }
197
199
  };
@@ -221,17 +223,19 @@ export default function MessageInputAIStream(props) {
221
223
  }
222
224
  },
223
225
  maxLength: props.maxTextLength || 200,
224
- placeholderStyle: "color: var(--app-B1-N4)",
226
+ placeholderStyle: props.placeholderStyle || 'color: var(--app-B1-N4)',
225
227
  onFocus: () => {
226
228
  setMoreOpen(false);
227
229
  emitEvent('scrollToBottom', {
228
- animation: true
230
+ animation: true,
231
+ scene: 'message-input-focus'
229
232
  });
230
233
  },
231
234
  onBlur: () => {
232
235
  sleep(200).then(() => {
233
236
  emitEvent('scrollToBottom', {
234
- follow: true
237
+ follow: true,
238
+ scene: 'message-input-blur'
235
239
  });
236
240
  });
237
241
  }
@@ -8,6 +8,7 @@ import { chooseImage, chooseVideo, uploadImage, uploadVideo } from '../utils/fil
8
8
  import { generateId } from '@ray-js/t-agent';
9
9
  import { useRenderOptions } from './context';
10
10
  import { useTranslate } from './useTranslate';
11
+ import { authorize } from '../utils/ttt';
11
12
  export function useAttachmentInput() {
12
13
  let {
13
14
  local
@@ -20,7 +21,8 @@ export function useAttachmentInput() {
20
21
  const blocks = useMemo(() => {
21
22
  const b = [];
22
23
  if (uploaded.length) {
23
- for (const uploadFile of uploaded) {
24
+ for (let i = 0; i < uploaded.length; i++) {
25
+ const uploadFile = uploaded[i];
24
26
  if (uploadFile.type === 'image') {
25
27
  if (local) {
26
28
  b.push({
@@ -65,7 +67,8 @@ export function useAttachmentInput() {
65
67
  }, [uploaded, local]);
66
68
  const loadBlocks = useCallback((blocks, append) => {
67
69
  const uploaded = [];
68
- for (const block of blocks) {
70
+ for (let i = 0; i < blocks.length; i++) {
71
+ const block = blocks[i];
69
72
  if (block.type === 'image_url') {
70
73
  uploaded.push({
71
74
  id: generateId(),
@@ -148,6 +151,15 @@ export function useAttachmentInput() {
148
151
  if (!sourceType) {
149
152
  return;
150
153
  }
154
+ const result = await authorize({
155
+ scope: 'scope.writePhotosAlbum'
156
+ });
157
+ if (!result) {
158
+ ty.showToast({
159
+ title: t('t-agent.input.upload.source-type.album.require-permission')
160
+ });
161
+ return;
162
+ }
151
163
  file = await chooseImage(count, sourceType);
152
164
  } catch (err) {
153
165
  return;
@@ -155,30 +167,41 @@ export function useAttachmentInput() {
155
167
  }
156
168
  if (type === 'camera') {
157
169
  try {
158
- const allowUseCamera = await new Promise(resolve => {
159
- ty.authorize({
160
- scope: 'scope.camera',
161
- success() {
162
- resolve(true);
163
- },
164
- fail() {
165
- ty.showToast({
166
- title: t('t-agent.input.upload.source-type.camera.require-permission'),
167
- icon: 'none'
168
- });
169
- resolve(false);
170
- }
170
+ const allowUseCamera = authorize({
171
+ scope: 'scope.camera'
172
+ });
173
+ if (!allowUseCamera) {
174
+ ty.showToast({
175
+ title: t('t-agent.input.upload.source-type.camera.require-permission'),
176
+ icon: 'none'
171
177
  });
178
+ return;
179
+ }
180
+ const result = await authorize({
181
+ scope: 'scope.writePhotosAlbum'
172
182
  });
173
- if (allowUseCamera) {
174
- file = await chooseImage(count, 'camera');
183
+ if (!result) {
184
+ ty.showToast({
185
+ title: t('t-agent.input.upload.source-type.album.require-permission')
186
+ });
187
+ return;
175
188
  }
189
+ file = await chooseImage(count, 'camera');
176
190
  } catch (err) {
177
191
  return;
178
192
  }
179
193
  }
180
194
  if (type === 'album') {
181
195
  try {
196
+ const result = await authorize({
197
+ scope: 'scope.writePhotosAlbum'
198
+ });
199
+ if (!result) {
200
+ ty.showToast({
201
+ title: t('t-agent.input.upload.source-type.album.require-permission')
202
+ });
203
+ return;
204
+ }
182
205
  file = await chooseImage(count, 'album');
183
206
  } catch (err) {
184
207
  return;
@@ -24,7 +24,8 @@ const normalizeLanguage = lang => {
24
24
  if (cache.has(lang)) {
25
25
  return cache.get(lang);
26
26
  }
27
- for (const key of keys) {
27
+ for (let i = 0; i < keys.length; i++) {
28
+ const key = keys[i];
28
29
  if (langRE[key].test(lang)) {
29
30
  cache.set(lang, key);
30
31
  return key;
@@ -3,7 +3,6 @@ import "core-js/modules/esnext.iterator.constructor.js";
3
3
  import "core-js/modules/esnext.iterator.find.js";
4
4
  import "core-js/modules/esnext.iterator.map.js";
5
5
  import "core-js/modules/esnext.iterator.some.js";
6
- import "core-js/modules/web.dom-collections.iterator.js";
7
6
  import './index.less';
8
7
  import { View } from '@ray-js/components';
9
8
  import React, { memo, useCallback, useMemo } from 'react';
@@ -61,7 +60,8 @@ const BubbleTile = props => {
61
60
  const longPressBlock = renderLongPressAs(longPressRes);
62
61
  const isErrorBubble = useMemo(() => {
63
62
  let empty = true;
64
- for (const child of children) {
63
+ for (let i = 0; i < children.length; i++) {
64
+ const child = children[i];
65
65
  // 如果子元素是文本类型,并且文本不为空,则不是空消息
66
66
  if (child.type === 'text') {
67
67
  if (child.data.text !== '') {
@@ -16,7 +16,9 @@ export function createSharedStore() {
16
16
  setValue(newValue) {
17
17
  const oldValue = storeRef.current.value;
18
18
  storeRef.current.value = newValue;
19
- for (const key of Object.keys(newValue)) {
19
+ const keys = Object.keys(newValue);
20
+ for (let i = 0; i < keys.length; i++) {
21
+ const key = keys[i];
20
22
  if (oldValue[key] !== newValue[key]) {
21
23
  var _storeRef$current$lis;
22
24
  (_storeRef$current$lis = storeRef.current.listeners.get(key)) === null || _storeRef$current$lis === void 0 || _storeRef$current$lis.forEach(fn => fn());
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ray-js/t-agent-ui-ray",
3
- "version": "0.2.7-beta.1",
3
+ "version": "0.2.7-beta.10",
4
4
  "author": "Tuya.inc",
5
5
  "license": "MIT",
6
6
  "private": false,
@@ -40,5 +40,5 @@
40
40
  "@types/echarts": "^4.9.22",
41
41
  "@types/markdown-it": "^14.1.1"
42
42
  },
43
- "gitHead": "d7754f9879a7ec837eb343ac759a08734cc789d3"
43
+ "gitHead": "4fa71cb1278f9ef5d4a171f81ff87dbbc8040e4d"
44
44
  }