@ray-js/t-agent 0.0.9-beta-1 → 0.0.9-beta-3

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
@@ -572,6 +572,10 @@ ui 插件的主要事件如下,你还可以自由地注册需要的事件:
572
572
  - `payload.blocks: InputBlock[]` 输入块
573
573
  - `setInputBlocks` 设置输入块到 MessageInput 输入框
574
574
  - `payload.blocks: InputBlock[]` 输入块
575
+ - `sessionChange`: 会话数据变化
576
+ - `payload.key: string`: 会话数据 key
577
+ - `payload.value: any`: 会话数据 value
578
+ - `payload.oldValue: any`: 会话数据旧值
575
579
 
576
580
  > 注意,这里的 ChatMessageObject 是一个消息对象,不是 ChatMessage 类型,
577
581
  > 它包含了消息的一些属性和方法,这是为了避免在 UI 层修改消息对象,导致 ChatAgent 中的消息对象不一致。
@@ -702,6 +706,12 @@ Hooks:
702
706
  - `extension` 扩展数据
703
707
  - `responseMessage` 响应消息
704
708
  - `result.messages` 消息列表
709
+ - `onTTTAction` tile 使用 `sendAction` 时触发
710
+ - `tile` 触发的 tile
711
+ - `action` TTTAction
712
+ - `onCardsReceived` 当收到卡片时触发
713
+ - `extension` 扩展数据
714
+ - `result.cards` 卡片列表
705
715
 
706
716
  ### withBuildIn 插件
707
717
 
@@ -1229,9 +1239,11 @@ import {
1229
1239
  } from '@ray-js/t-agent-ui-ray';
1230
1240
  import { View, Text, Button } from '@ray-js/ray';
1231
1241
 
1232
- function MyCard(props: { card: ChatCardObject }) {
1242
+ const MyCard: ChatCardComponent<{ title: string }, { clicked: boolean }> = props => {
1233
1243
  // 如果你需要拿到 agent、message、tile、emitEvent 等属性,可以使用 useTileProps
1234
1244
  const { message, agent, tile, emitEvent } = useTileProps();
1245
+ const { card, setCardState } = props;
1246
+ const { cardData, cardState, cardCode } = card as ChatCardObject<{ title: string }>;
1235
1247
 
1236
1248
  // 如果你需要发送一个 TTTAction,可以使用 useSendAction
1237
1249
  const sendAction = useSendAction();
@@ -1240,15 +1252,18 @@ function MyCard(props: { card: ChatCardObject }) {
1240
1252
  <View>
1241
1253
  <Text>My Card</Text>
1242
1254
  <Button
1243
- onClick={() =>
1244
- sendAction({ type: 'sendMessage', blocks: [{ type: 'text', text: 'hello' }] })
1245
- }
1255
+ onClick={() => {
1256
+ sendAction({ type: 'sendMessage', blocks: [{ type: 'text', text: 'hello' }] });
1257
+ // 如果需要更新卡片状态,可以使用 setCardState
1258
+ // 第二个参数表示是否持久化状态
1259
+ setCardState({ clicked: true }, { persist: true });
1260
+ }}
1246
1261
  >
1247
1262
  填充文本到输入框
1248
1263
  </Button>
1249
1264
  </View>
1250
1265
  );
1251
- }
1266
+ };
1252
1267
 
1253
1268
  const renderOptions = {
1254
1269
  ...defaultRenderOptions,
package/README.md CHANGED
@@ -567,6 +567,10 @@ The main events of the UI plugin are as follows, and you can freely register add
567
567
  - `payload.blocks: InputBlock[]`: Input blocks
568
568
  - `setInputBlocks`: Set input blocks in MessageInput
569
569
  - `payload.blocks: InputBlock[]`: Input blocks
570
+ - `sessionChange`: Session data changes
571
+ - `payload.key: string`: Session key
572
+ - `payload.value: any`: Session value
573
+ - `payload.oldValue: any`: Old session value
570
574
 
571
575
  > Note: `ChatMessageObject` here is a message object, not a `ChatMessage` type.
572
576
  > It contains various attributes and methods to ensure changes are made in the ChatAgent, avoiding conflicts with the UI layer.
@@ -696,6 +700,12 @@ Hooks:
696
700
  - `extension`: Extension data
697
701
  - `responseMessage`: Response message
698
702
  - `result.messages`: Message list
703
+ - `onTTTAction` When using `sendAction` in the tile, this hook triggers.
704
+ - `tile` Tile object
705
+ - `action` TTTAction
706
+ - `onCardsReceived` When receiving cards, this hook triggers.
707
+ - `extension` Extension data
708
+ - `result.cards` Card list
699
709
 
700
710
  ### withBuildIn Plugin
701
711
 
@@ -1224,9 +1234,11 @@ import {
1224
1234
  } from '@ray-js/t-agent-ui-ray';
1225
1235
  import { View, Text, Button } from '@ray-js/ray';
1226
1236
 
1227
- function MyCard(props: { card: ChatCardObject }) {
1237
+ const MyCard: ChatCardComponent<{ title: string }, { clicked: boolean }> = props => {
1228
1238
  // If you need to access attributes like agent, message, tile, emitEvent, use useTileProps
1229
1239
  const { message, agent, tile, emitEvent } = useTileProps();
1240
+ const { card, setCardState } = props;
1241
+ const { cardData, cardState, cardCode } = card as ChatCardObject<{ title: string }>;
1230
1242
 
1231
1243
  // If you need to send a TTTAction, use useSendAction
1232
1244
  const sendAction = useSendAction();
@@ -1235,15 +1247,18 @@ function MyCard(props: { card: ChatCardObject }) {
1235
1247
  <View>
1236
1248
  <Text>My Card</Text>
1237
1249
  <Button
1238
- onClick={() =>
1239
- sendAction({ type: 'sendMessage', blocks: [{ type: 'text', text: 'hello' }] })
1240
- }
1250
+ onClick={() => {
1251
+ sendAction({ type: 'sendMessage', blocks: [{ type: 'text', text: 'hello' }] });
1252
+ // If you want to set the card state, use setCardState
1253
+ // The second parameter is used to determine whether to persist the card state, default is false
1254
+ setCardState({ clicked: true }, { persist: true });
1255
+ }}
1241
1256
  >
1242
1257
  Fill text into input
1243
1258
  </Button>
1244
1259
  </View>
1245
1260
  );
1246
- }
1261
+ };
1247
1262
 
1248
1263
  const renderOptions = {
1249
1264
  ...defaultRenderOptions,
@@ -1,12 +1,13 @@
1
1
  import ChatAgent from './ChatAgent';
2
+ import ChatSession from './ChatSession';
2
3
  import StreamResponse from './StreamResponse';
3
4
  import ChatTile from './ChatTile';
4
5
  import ChatBubbleTile from './ChatBubbleTile';
5
6
  import ChatMessage from './ChatMessage';
6
- import { generateId, safeParseJSON, sleep, generateInt, isAbortError, debounce, shuffleWithSeed } from './utils';
7
+ import { generateId, safeParseJSON, isAbortError, shuffleWithSeed } from './utils';
7
8
  import Logger, { getLogger } from './Logger';
8
9
  import { Emitter, EmitterEvent } from './Emitter';
9
10
  export { createHooks, Hookable } from 'hookable';
10
- export { ChatAgent, StreamResponse, ChatTile, ChatBubbleTile, ChatMessage, generateId, generateInt, safeParseJSON, getLogger, Logger, Emitter, EmitterEvent, isAbortError, sleep, debounce, shuffleWithSeed, };
11
+ export { ChatAgent, ChatSession, StreamResponse, ChatTile, ChatBubbleTile, ChatMessage, generateId, safeParseJSON, getLogger, Logger, Emitter, EmitterEvent, isAbortError, shuffleWithSeed, };
11
12
  export * from './createChatAgent';
12
13
  export * from './types';
@@ -1,12 +1,13 @@
1
1
  import ChatAgent from './ChatAgent';
2
+ import ChatSession from './ChatSession';
2
3
  import StreamResponse from './StreamResponse';
3
4
  import ChatTile from './ChatTile';
4
5
  import ChatBubbleTile from './ChatBubbleTile';
5
6
  import ChatMessage from './ChatMessage';
6
- import { generateId, safeParseJSON, sleep, generateInt, isAbortError, debounce, shuffleWithSeed } from './utils';
7
+ import { generateId, safeParseJSON, isAbortError, shuffleWithSeed } from './utils';
7
8
  import Logger, { getLogger } from './Logger';
8
9
  import { Emitter, EmitterEvent } from './Emitter';
9
10
  export { createHooks, Hookable } from 'hookable';
10
- export { ChatAgent, StreamResponse, ChatTile, ChatBubbleTile, ChatMessage, generateId, generateInt, safeParseJSON, getLogger, Logger, Emitter, EmitterEvent, isAbortError, sleep, debounce, shuffleWithSeed };
11
+ export { ChatAgent, ChatSession, StreamResponse, ChatTile, ChatBubbleTile, ChatMessage, generateId, safeParseJSON, getLogger, Logger, Emitter, EmitterEvent, isAbortError, shuffleWithSeed };
11
12
  export * from './createChatAgent';
12
13
  export * from './types';
@@ -1,32 +1,6 @@
1
1
  export declare function generateId(length?: number): string;
2
- export declare function generateInt(min: number, max: number): number;
3
- export declare function deepCloneToPlainObject(obj: any): any;
2
+ export declare function deepCloneToPlainObject(obj: any, visited?: WeakMap<object, any>): any;
4
3
  export declare function safeParseJSON<T = any>(str: any): T | undefined;
5
4
  export declare function deepMerge(target: any, source: any): any;
6
- export declare const sleep: (ms: number) => Promise<unknown>;
7
5
  export declare function isAbortError(reason: any): any;
8
- type AnyFunction = (...arguments_: readonly any[]) => unknown;
9
- /**
10
- * Creates a debounced function that delays execution until `wait` milliseconds have passed since its last invocation.
11
- *
12
- * Set the `immediate` option to `true` to execute the function immediately at the start of the `wait` interval, preventing issues such as double-clicks on a button.
13
- *
14
- * The returned function has the following methods:
15
- *
16
- * - `.isPending` indicates whether the debounce delay is currently active.
17
- * - `.clear()` cancels any scheduled executions.
18
- * - `.flush()` if an execution is scheduled then it will be immediately executed and the timer will be cleared.
19
- * - `.trigger()` executes the function immediately and clears the timer if it was previously set.
20
- */
21
- export declare function debounce<F extends AnyFunction>(function_: F, wait?: number, options?: {
22
- immediate?: boolean;
23
- }): DebouncedFunction<F>;
24
- interface DebouncedFunction<F extends AnyFunction> {
25
- (...arguments_: Parameters<F>): ReturnType<F> | undefined;
26
- readonly isPending: boolean;
27
- clear(): void;
28
- flush(): void;
29
- trigger(): void;
30
- }
31
6
  export declare function shuffleWithSeed<T>(array: T[], seed: string): T[];
32
- export {};
@@ -1,6 +1,6 @@
1
- import "core-js/modules/esnext.iterator.constructor.js";
2
- import "core-js/modules/esnext.iterator.filter.js";
3
- import "core-js/modules/esnext.iterator.map.js";
1
+ import "core-js/modules/es.regexp.constructor.js";
2
+ import "core-js/modules/es.regexp.dot-all.js";
3
+ import "core-js/modules/es.regexp.exec.js";
4
4
  import "core-js/modules/web.dom-collections.iterator.js";
5
5
  /* eslint no-bitwise: 0 */
6
6
 
@@ -14,38 +14,77 @@ export function generateId() {
14
14
  }
15
15
  return result;
16
16
  }
17
- export function generateInt(min, max) {
18
- return Math.floor(Math.random() * (max - min + 1) + min);
19
- }
20
17
  export function deepCloneToPlainObject(obj) {
21
- // 判断是否是对象或数组
22
- if (obj === null || typeof obj !== 'object') {
23
- return undefined;
24
- }
18
+ let visited = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : new WeakMap();
19
+ // 如果是 null,直接返回 null
20
+ if (obj === null) return null;
21
+
22
+ // 如果是基本类型(数字、字符串、布尔等),直接返回自身;函数在 JSON 中会被忽略
23
+ if (typeof obj !== 'object') return obj;
24
+ if (typeof obj === 'function') return undefined;
25
25
 
26
- // 如果是 Date 或其他不可直接 JSON 化的类型
26
+ // 如果对象已被处理过,直接返回缓存结果,防止循环引用
27
+ if (visited.has(obj)) return visited.get(obj);
28
+
29
+ // 处理 Date:转成 ISO 字符串
27
30
  if (obj instanceof Date) {
28
31
  return obj.toISOString();
29
32
  }
30
- if (obj instanceof Array) {
31
- return obj.map(item => deepCloneToPlainObject(item)).filter(item => item !== undefined); // 移除 undefined 项
33
+
34
+ // 处理 RegExp:转换为字符串表示形式
35
+ if (obj instanceof RegExp) {
36
+ return obj.toString();
32
37
  }
33
- if (obj instanceof Object) {
34
- const plainObject = {};
35
- for (const key in obj) {
36
- if (Object.prototype.hasOwnProperty.call(obj, key)) {
37
- const value = deepCloneToPlainObject(obj[key]);
38
- if (value !== undefined) {
39
- // 只添加可以转换的值
40
- plainObject[key] = value;
41
- }
38
+
39
+ // 处理数组:保留结构,将 undefined 转为 null(符合 JSON.stringify 行为)
40
+ if (Array.isArray(obj)) {
41
+ const clonedArr = new Array(obj.length);
42
+ visited.set(obj, clonedArr);
43
+ for (let i = 0; i < obj.length; i++) {
44
+ if (i in obj) {
45
+ const clonedValue = deepCloneToPlainObject(obj[i], visited);
46
+ clonedArr[i] = clonedValue === undefined ? null : clonedValue;
47
+ } else {
48
+ // 对于稀疏数组,补成 null
49
+ clonedArr[i] = null;
42
50
  }
43
51
  }
44
- return plainObject;
52
+ return clonedArr;
45
53
  }
46
54
 
47
- // 如果遇到其他类型,直接忽略返回 undefined
48
- return undefined;
55
+ // 处理 Map:转换为数组的键值对;注意 JSON 不能直接表示 Map,所以这里转成数组
56
+ if (obj instanceof Map) {
57
+ const clonedMap = [];
58
+ visited.set(obj, clonedMap);
59
+ for (const [key, value] of obj.entries()) {
60
+ clonedMap.push([deepCloneToPlainObject(key, visited), deepCloneToPlainObject(value, visited)]);
61
+ }
62
+ return clonedMap;
63
+ }
64
+
65
+ // 处理 Set:转换为数组
66
+ if (obj instanceof Set) {
67
+ const clonedSet = [];
68
+ visited.set(obj, clonedSet);
69
+ for (const value of obj.values()) {
70
+ clonedSet.push(deepCloneToPlainObject(value, visited));
71
+ }
72
+ return clonedSet;
73
+ }
74
+
75
+ // 处理普通对象
76
+ const clonedObj = {};
77
+ visited.set(obj, clonedObj);
78
+ for (const key in obj) {
79
+ if (Object.prototype.hasOwnProperty.call(obj, key)) {
80
+ const clonedValue = deepCloneToPlainObject(obj[key], visited);
81
+ // JSON.stringify 会忽略 undefined 属性,这里保持一致
82
+ if (clonedValue !== undefined) {
83
+ clonedObj[key] = clonedValue;
84
+ }
85
+ }
86
+ }
87
+ return clonedObj;
49
88
  }
50
89
  export function safeParseJSON(str) {
51
90
  if (str && typeof str === 'string') {
@@ -83,101 +122,9 @@ export function deepMerge(target, source) {
83
122
  }
84
123
  return target;
85
124
  }
86
- export const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
87
125
  export function isAbortError(reason) {
88
126
  return reason && typeof Error !== 'undefined' && reason instanceof Error && reason.name === 'AbortError';
89
127
  }
90
- /**
91
- * Creates a debounced function that delays execution until `wait` milliseconds have passed since its last invocation.
92
- *
93
- * Set the `immediate` option to `true` to execute the function immediately at the start of the `wait` interval, preventing issues such as double-clicks on a button.
94
- *
95
- * The returned function has the following methods:
96
- *
97
- * - `.isPending` indicates whether the debounce delay is currently active.
98
- * - `.clear()` cancels any scheduled executions.
99
- * - `.flush()` if an execution is scheduled then it will be immediately executed and the timer will be cleared.
100
- * - `.trigger()` executes the function immediately and clears the timer if it was previously set.
101
- */
102
- export function debounce(function_) {
103
- let wait = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 100;
104
- let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
105
- if (typeof function_ !== 'function') {
106
- throw new TypeError("Expected the first parameter to be a function, got `".concat(typeof function_, "`."));
107
- }
108
- if (wait < 0) {
109
- throw new RangeError('`wait` must not be negative.');
110
- }
111
- const {
112
- immediate = false
113
- } = options;
114
- let storedContext;
115
- let storedArguments;
116
- let timeoutId;
117
- let timestamp;
118
- let result;
119
- function run() {
120
- const callContext = storedContext;
121
- const callArguments = storedArguments;
122
- storedContext = undefined;
123
- storedArguments = undefined;
124
- result = function_.apply(callContext, callArguments);
125
- return result;
126
- }
127
- function later() {
128
- const last = Date.now() - timestamp;
129
- if (last < wait && last >= 0) {
130
- timeoutId = setTimeout(later, wait - last);
131
- } else {
132
- timeoutId = undefined;
133
- if (!immediate) {
134
- result = run();
135
- }
136
- }
137
- }
138
- const debounced = function () {
139
- if (storedContext && this !== storedContext && Object.getPrototypeOf(this) === Object.getPrototypeOf(storedContext)) {
140
- throw new Error('Debounced method called with different contexts of the same prototype.');
141
- }
142
- storedContext = this;
143
- for (var _len = arguments.length, arguments_ = new Array(_len), _key = 0; _key < _len; _key++) {
144
- arguments_[_key] = arguments[_key];
145
- }
146
- storedArguments = arguments_;
147
- timestamp = Date.now();
148
- const callNow = immediate && !timeoutId;
149
- if (!timeoutId) {
150
- timeoutId = setTimeout(later, wait);
151
- }
152
- if (callNow) {
153
- result = run();
154
- }
155
- return result;
156
- };
157
- Object.defineProperty(debounced, 'isPending', {
158
- get() {
159
- return timeoutId !== undefined;
160
- }
161
- });
162
- debounced.clear = () => {
163
- if (!timeoutId) {
164
- return;
165
- }
166
- clearTimeout(timeoutId);
167
- timeoutId = undefined;
168
- };
169
- debounced.flush = () => {
170
- if (!timeoutId) {
171
- return;
172
- }
173
- debounced.trigger();
174
- };
175
- debounced.trigger = () => {
176
- result = run();
177
- debounced.clear();
178
- };
179
- return debounced;
180
- }
181
128
  function seedRandom(seed) {
182
129
  let h = 0;
183
130
  // 将字符串种子转化为哈希值
@@ -28,6 +28,13 @@ export function withUI() {
28
28
  };
29
29
  emitEvent('messageChange', detail);
30
30
  }, 'after');
31
+ agent.session.onChange((key, value, oldValue) => {
32
+ emitEvent('sessionChange', {
33
+ key,
34
+ value,
35
+ oldValue
36
+ });
37
+ });
31
38
  return {
32
39
  ui: {
33
40
  emitter,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ray-js/t-agent",
3
- "version": "0.0.9-beta-1",
3
+ "version": "0.0.9-beta-3",
4
4
  "author": "Tuya.inc",
5
5
  "license": "MIT",
6
6
  "private": false,
@@ -26,5 +26,5 @@
26
26
  "build": "ray build --type=component --output dist",
27
27
  "clean": "rimraf ./dist"
28
28
  },
29
- "gitHead": "df6f4f35caa6e62408450f14d9dcdd26f068283c"
29
+ "gitHead": "7330e1a07e32629668a6edf933d4682f286d957a"
30
30
  }