@ray-js/t-agent-plugin-aistream 0.2.6-beta-8 → 0.2.7-beta.1

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.
@@ -216,6 +216,23 @@ export type MiniProgramAccountInfo = {
216
216
  /** 小程序图标 */
217
217
  appIcon: string;
218
218
  };
219
+ export interface CustomParamItem {
220
+ value: any;
221
+ /** 生效次数,不传一直生效 */
222
+ effectiveCount?: number;
223
+ }
224
+ export type AIStreamUserData = {
225
+ sessionAttributes?: {
226
+ 'custom.param'?: Record<string, CustomParamItem>;
227
+ [key: string]: any;
228
+ };
229
+ eventAttributes?: {
230
+ 'custom.param'?: Record<string, CustomParamItem>;
231
+ [key: string]: any;
232
+ };
233
+ chatAttributes?: AIStreamChatAttribute;
234
+ [key: string]: any;
235
+ };
219
236
  /**
220
237
  * 获取小程序账号信息
221
238
  */
@@ -630,9 +647,7 @@ export declare enum EventType {
630
647
  /** 聊天中断 */
631
648
  CHAT_BREAK = 4,
632
649
  /** 服务端 VAD */
633
- SERVER_VAD = 5,
634
- /** 服务端错误 */
635
- SERVER_ERROR = 6
650
+ SERVER_VAD = 5
636
651
  }
637
652
  export declare enum StreamFlag {
638
653
  /** 仅一包 */
@@ -821,8 +836,6 @@ export type EventBody = {
821
836
  sessionId: string;
822
837
  /** 事件类型: 0-Event Start, 1-Event Payload End, 2-Event End, 3 - OneShot, 4-Chat Break, 5-Server VAD */
823
838
  eventType: EventType;
824
- /** 属性列表 */
825
- userData?: Attribute[];
826
839
  };
827
840
  export type AudioBody = {
828
841
  /** 接收数据通道 Code */
@@ -831,8 +844,6 @@ export type AudioBody = {
831
844
  streamFlag: number;
832
845
  /** 音频缓存路径 */
833
846
  path: string;
834
- /** 扩展属性 */
835
- userData?: Attribute[];
836
847
  /** SessionId 列表, 云端返回,可能为空 */
837
848
  sessionIdList?: string[];
838
849
  /**
@@ -945,8 +956,6 @@ export type VideoBody = {
945
956
  streamFlag: StreamFlag;
946
957
  /** 视频缓存路径,传输结束后可访问(streamFlag == 1 || StreamFlag == 3) */
947
958
  path: string;
948
- /** 扩展属性 */
949
- userData?: Attribute[];
950
959
  /** SessionId 列表, 云端返回,可能为空 */
951
960
  sessionIdList?: string[];
952
961
  };
@@ -961,8 +970,6 @@ export type ImageBody = {
961
970
  width: number;
962
971
  /** 图片高度 */
963
972
  height: number;
964
- /** 扩展属性 */
965
- userData?: Attribute[];
966
973
  /** SessionId 列表, 云端返回,可能为空 */
967
974
  sessionIdList?: string[];
968
975
  };
@@ -973,8 +980,6 @@ export type TextBody = {
973
980
  streamFlag: StreamFlag;
974
981
  /** 文本内容(JSON String,见云端文档定义) */
975
982
  text: string;
976
- /** 扩展属性 */
977
- userData?: Attribute[];
978
983
  /** SessionId 列表, 云端返回,可能为空 */
979
984
  sessionIdList?: string[];
980
985
  };
@@ -987,8 +992,6 @@ export type FileBody = {
987
992
  path: string;
988
993
  /** 文件类型: 1 - MP4, 2 - OGG_OPUS, 3 - PDF, 4 - JSON, 5 - IPC_LOG, 6 - SweeperMap */
989
994
  format: FileFormat;
990
- /** 扩展属性 */
991
- userData?: Attribute[];
992
995
  /** SessionId 列表, 云端返回,可能为空 */
993
996
  sessionIdList?: string[];
994
997
  };
@@ -1142,8 +1145,13 @@ export type CreateSessionParams = {
1142
1145
  sessionId?: string;
1143
1146
  /** 业务配置定义(通过 queryAgentToken 传递) */
1144
1147
  bizConfig: BizConfig;
1145
- /** 扩展属性 */
1148
+ /**
1149
+ * 扩展属性
1150
+ * @deprecated
1151
+ */
1146
1152
  userData?: Attribute[];
1153
+ /** 扩展属性 */
1154
+ userDataJson?: string;
1147
1155
  /** 是否复用数据通道,默认不复用 */
1148
1156
  reuseDataChannel?: boolean;
1149
1157
  success?: (params: {
@@ -1211,8 +1219,13 @@ export type SendEventStartParams = {
1211
1219
  /** 会话 id */
1212
1220
  sessionId: string;
1213
1221
  eventIdPrefix?: string;
1214
- /** 扩展属性 */
1222
+ /**
1223
+ * 扩展属性
1224
+ * @deprecated
1225
+ */
1215
1226
  userData?: Attribute[];
1227
+ /** 扩展属性 */
1228
+ userDataJson?: string;
1216
1229
  success?: (params: {
1217
1230
  /** 事件 id。此后 sendEventPayloadEnd、sendEventEnd、sendEventChatBreak 都需要使用该 eventId 直到下发一次 sendEventStart 生成新 eventId 之前。 */
1218
1231
  eventId: string;
@@ -1228,7 +1241,7 @@ export type SendEventStartParams = {
1228
1241
  complete?: () => void;
1229
1242
  };
1230
1243
  /**
1231
- *@description 某个数据流传输结束事件
1244
+ * @description 某个数据流传输结束事件
1232
1245
  */
1233
1246
  export type SendEventPayloadEndParams = {
1234
1247
  /** 事件 id */
@@ -1237,8 +1250,6 @@ export type SendEventPayloadEndParams = {
1237
1250
  sessionId: string;
1238
1251
  /** 发送结束 的 dataChannel */
1239
1252
  dataChannel: string;
1240
- /** 扩展属性 */
1241
- userData?: Attribute[];
1242
1253
  success?: (params: null) => void;
1243
1254
  fail?: (params: {
1244
1255
  errorMsg: string;
@@ -1258,8 +1269,6 @@ export type SendEventEndParams = {
1258
1269
  eventId: string;
1259
1270
  /** 会话 id */
1260
1271
  sessionId: string;
1261
- /** 扩展属性 */
1262
- userData?: Attribute[];
1263
1272
  success?: (params: null) => void;
1264
1273
  fail?: (params: {
1265
1274
  errorMsg: string;
@@ -1279,8 +1288,13 @@ export type SendEventChatBreakParams = {
1279
1288
  eventId: string;
1280
1289
  /** 会话 id */
1281
1290
  sessionId: string;
1282
- /** 扩展属性 */
1291
+ /**
1292
+ * 扩展属性
1293
+ * @deprecated
1294
+ */
1283
1295
  userData?: Attribute[];
1296
+ /** 扩展属性 */
1297
+ userDataJson?: string;
1284
1298
  success?: (params: null) => void;
1285
1299
  fail?: (params: {
1286
1300
  errorMsg: string;
@@ -1304,8 +1318,6 @@ export type StartRecordAndSendAudioDataParams = {
1304
1318
  sessionId: string;
1305
1319
  /** 下发数据通道,当音频只有单路的时候,可以不传 */
1306
1320
  dataChannel?: string;
1307
- /** 扩展属性 */
1308
- userData?: Attribute[];
1309
1321
  success?: (params: null) => void;
1310
1322
  fail?: (params: {
1311
1323
  errorMsg: string;
@@ -1322,8 +1334,6 @@ export type StopRecordAndSendAudioDataParams = {
1322
1334
  sessionId: string;
1323
1335
  /** 下发数据通道,当音频只有单路的时候,可以不传 */
1324
1336
  dataChannel?: string;
1325
- /** 扩展属性 */
1326
- userData?: Attribute[];
1327
1337
  success?: (params: AIStreamAudioFile | null) => void;
1328
1338
  fail?: (params: {
1329
1339
  errorMsg: string;
@@ -1372,8 +1382,6 @@ export type StopRecordAndSendVideoDataParams = {
1372
1382
  * 1-前置摄像头, 2-后置摄像头
1373
1383
  */
1374
1384
  cameraType: VideoCameraType;
1375
- /** 扩展属性 */
1376
- userData?: Attribute[];
1377
1385
  success?: (params: null) => void;
1378
1386
  fail?: (params: {
1379
1387
  errorMsg: string;
@@ -1392,8 +1400,6 @@ export type SendImageDataParams = {
1392
1400
  dataChannel?: string;
1393
1401
  /** 图片路径 */
1394
1402
  path: string;
1395
- /** 扩展属性 */
1396
- userData?: Attribute[];
1397
1403
  success?: (params: null) => void;
1398
1404
  fail?: (params: {
1399
1405
  errorMsg: string;
@@ -1412,8 +1418,6 @@ export type SendTextDataParams = {
1412
1418
  dataChannel?: string;
1413
1419
  /** 文本内容 */
1414
1420
  text: string;
1415
- /** 扩展属性 */
1416
- userData?: Attribute[];
1417
1421
  success?: (params: null) => void;
1418
1422
  fail?: (params: {
1419
1423
  errorMsg: string;
@@ -1447,8 +1451,6 @@ export type SendFileDataParams = {
1447
1451
  path: string;
1448
1452
  /** 文件类型: 1 - MP4, 2 - OGG_OPUS, 3 - PDF, 4 - JSON, 5 - IPC_LOG, 6 - SweeperMap */
1449
1453
  format: FileFormat;
1450
- /** 扩展属性 */
1451
- userData?: Attribute[];
1452
1454
  success?: (params: null) => void;
1453
1455
  fail?: (params: {
1454
1456
  errorMsg: string;
@@ -100,7 +100,6 @@ export let EventType = /*#__PURE__*/function (EventType) {
100
100
  EventType[EventType["ONE_SHOT"] = 3] = "ONE_SHOT";
101
101
  EventType[EventType["CHAT_BREAK"] = 4] = "CHAT_BREAK";
102
102
  EventType[EventType["SERVER_VAD"] = 5] = "SERVER_VAD";
103
- EventType[EventType["SERVER_ERROR"] = 6] = "SERVER_ERROR";
104
103
  return EventType;
105
104
  }({});
106
105
  export let StreamFlag = /*#__PURE__*/function (StreamFlag) {
@@ -228,7 +227,7 @@ export let NetworkType = /*#__PURE__*/function (NetworkType) {
228
227
  */
229
228
 
230
229
  /**
231
- *@description 某个数据流传输结束事件
230
+ * @description 某个数据流传输结束事件
232
231
  */
233
232
 
234
233
  /**
@@ -177,7 +177,7 @@ export class AsrAgent {
177
177
  return;
178
178
  }
179
179
  const activeSession = await this.createSession();
180
- const attribute = {
180
+ const chatAttributes = {
181
181
  'processing.interrupt': 'false',
182
182
  'asr.enableVad': 'false'
183
183
  };
@@ -186,8 +186,11 @@ export class AsrAgent {
186
186
  userData: [{
187
187
  type: AIStreamAttributeType.AI_CHAT,
188
188
  payloadType: AIStreamAttributePayloadType.STRING,
189
- value: JSON.stringify(attribute)
190
- }]
189
+ value: JSON.stringify(chatAttributes)
190
+ }],
191
+ userDataJson: JSON.stringify({
192
+ chatAttributes
193
+ })
191
194
  }));
192
195
  if (startEventError) {
193
196
  finish(startEventError);
@@ -1,4 +1,4 @@
1
- import { AIStreamAudioFile, Attribute, BizTag, ConnectClientType, ConnectState, FileFormat, VideoCameraType } from '../AIStreamTypes';
1
+ import { AIStreamAudioFile, AIStreamUserData, Attribute, BizTag, ConnectClientType, ConnectState, FileFormat, VideoCameraType } from '../AIStreamTypes';
2
2
  import { AIStreamDataEntry, AIStreamObserverPool } from './observer';
3
3
  import { AIStreamError } from './errors';
4
4
  interface AIStreamConnectionOptions {
@@ -40,12 +40,13 @@ interface AIStreamSessionOptions {
40
40
  apiVersion?: string;
41
41
  /** 业务额外参数 */
42
42
  extParams?: any;
43
- userData?: Attribute[];
43
+ getSessionUserData?: () => Promise<AIStreamUserData>;
44
44
  }
45
45
  interface AIStreamEventOptions {
46
46
  signal?: AbortSignal;
47
- userData?: Attribute[];
48
47
  eventIdPrefix?: string;
48
+ userData?: Attribute[];
49
+ userDataJson?: string;
49
50
  }
50
51
  export declare class AIStreamSession {
51
52
  private connection;
@@ -75,30 +76,25 @@ type AIStreamEventWriteChunk = {
75
76
  type: 'text';
76
77
  text: string;
77
78
  dataChannel?: string;
78
- userData?: Attribute[];
79
79
  } | {
80
80
  type: 'file';
81
81
  path: string;
82
82
  format: FileFormat;
83
83
  dataChannel?: string;
84
- userData?: Attribute[];
85
84
  } | {
86
85
  type: 'image';
87
86
  path: string;
88
87
  dataChannel?: string;
89
- userData?: Attribute[];
90
88
  };
91
89
  type AIStreamEventSource = {
92
90
  type: 'audio';
93
91
  dataChannel?: string;
94
- userData?: Attribute[];
95
92
  saveFile?: boolean;
96
93
  sampleRate?: number;
97
94
  } | {
98
95
  type: 'video';
99
96
  dataChannel?: string;
100
97
  cameraType?: VideoCameraType;
101
- userData?: Attribute[];
102
98
  };
103
99
  export interface AIStreamEventStream {
104
100
  type: 'video' | 'audio';
@@ -123,12 +119,8 @@ export declare class AIStreamEvent {
123
119
  private findFirstCode;
124
120
  write(chunk: AIStreamEventWriteChunk): Promise<void>;
125
121
  stream(source: AIStreamEventSource): AIStreamEventStream;
126
- end(options?: {
127
- userData?: Attribute[];
128
- }): Promise<void>;
129
- abort(options?: {
130
- userData?: Attribute[];
131
- }): void;
122
+ end(): Promise<void>;
123
+ abort(): void;
132
124
  on(name: 'close', callback: () => void): void;
133
125
  on(name: 'finish', callback: () => void): void;
134
126
  on(name: 'error', callback: (error: AIStreamError) => void): void;
@@ -1,13 +1,12 @@
1
- import _objectWithoutProperties from "@babel/runtime/helpers/esm/objectWithoutProperties";
2
1
  import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
3
2
  import _defineProperty from "@babel/runtime/helpers/esm/defineProperty";
4
- const _excluded = ["signal"];
3
+ import "core-js/modules/es.json.stringify.js";
5
4
  import "core-js/modules/esnext.iterator.constructor.js";
6
5
  import "core-js/modules/esnext.iterator.find.js";
7
6
  import "core-js/modules/esnext.iterator.for-each.js";
8
7
  import "core-js/modules/esnext.iterator.map.js";
9
8
  import "core-js/modules/web.dom-collections.iterator.js";
10
- import { AIStreamAttributeType, AIStreamErrorCode, AIStreamServerErrorCode, BizTag, ConnectClientType, ConnectState, EventType, NetworkType, SessionState } from '../AIStreamTypes';
9
+ import { AIStreamErrorCode, AIStreamServerErrorCode, BizTag, ConnectClientType, ConnectState, EventType, NetworkType, SessionState } from '../AIStreamTypes';
11
10
  import { closeSession, connect, createSession, disconnect, getCurrentHomeInfo, getNetworkType, isConnected, queryAgentToken, sendEventChatBreak, sendEventEnd, sendEventPayloadEnd, sendEventStart, sendImageData, sendTextData, startRecordAndSendAudioData, stopRecordAndSendAudioData } from './ttt';
12
11
  import { AIStreamObserver, AIStreamObserverPool } from './observer';
13
12
  import { isAbortError, safeParseJSON } from '@ray-js/t-agent';
@@ -180,27 +179,12 @@ export class AIStreamSession {
180
179
  (_this$activeEvent2 = this.activeEvent) === null || _this$activeEvent2 === void 0 || _this$activeEvent2.emit('data', entry);
181
180
  if (entry.type === 'event' && entry.body.eventId === this.activeEvent.eventId) {
182
181
  const {
183
- eventType,
184
- userData
182
+ eventType
185
183
  } = entry.body;
186
184
  if (eventType === EventType.EVENT_END || eventType === EventType.CHAT_BREAK || eventType === EventType.ONE_SHOT) {
187
185
  var _this$activeEvent3;
188
186
  (_this$activeEvent3 = this.activeEvent) === null || _this$activeEvent3 === void 0 || _this$activeEvent3.emit('finish');
189
187
  this.cleanupEvent();
190
- } else if (eventType === EventType.SERVER_ERROR) {
191
- var _this$activeEvent4;
192
- let code = '';
193
- let message = '';
194
- for (const item of userData) {
195
- if (item.type === AIStreamAttributeType.ERROR_CODE) {
196
- code = item.value;
197
- } else if (item.type === AIStreamAttributeType.ERROR_MESSAGE) {
198
- message = item.value;
199
- }
200
- }
201
- const error = new AIStreamError(message || 'Event error occurred', code || AIStreamErrorCode.UNKNOWN_ERROR);
202
- (_this$activeEvent4 = this.activeEvent) === null || _this$activeEvent4 === void 0 || _this$activeEvent4.emit('error', error);
203
- this.cleanupEvent();
204
188
  }
205
189
  }
206
190
  });
@@ -274,12 +258,16 @@ export class AIStreamSession {
274
258
  } else {
275
259
  this.tokenExtParamsResolvable.resolve({});
276
260
  }
261
+ let userData = {};
262
+ if (options.getSessionUserData) {
263
+ userData = await options.getSessionUserData();
264
+ }
277
265
  {
278
266
  const [err, res] = await tryCatchTTT(() => createSession({
279
267
  bizTag: options.bizTag,
280
268
  agentToken,
281
269
  bizConfig,
282
- userData: options.userData
270
+ userDataJson: JSON.stringify(userData)
283
271
  }));
284
272
  if (err) {
285
273
  this.promise = null;
@@ -302,18 +290,23 @@ export class AIStreamSession {
302
290
  throw new AIStreamError('Cannot start a new event while another is active', AIStreamErrorCode.EVENT_EXISTS);
303
291
  }
304
292
  const {
305
- signal
306
- } = options,
307
- rest = _objectWithoutProperties(options, _excluded);
293
+ signal,
294
+ userData,
295
+ eventIdPrefix,
296
+ userDataJson
297
+ } = options;
308
298
  await this.ensureSession();
309
299
  if (signal !== null && signal !== void 0 && signal.aborted) {
310
300
  const error = new AIStreamError('start event was aborted', AIStreamErrorCode.EVENT_ABORTED);
311
301
  error.name = 'AbortError';
312
302
  throw error;
313
303
  }
314
- const [error, result] = await tryCatchTTT(() => sendEventStart(_objectSpread({
315
- sessionId: this.sessionId
316
- }, rest)));
304
+ const [error, result] = await tryCatchTTT(() => sendEventStart({
305
+ sessionId: this.sessionId,
306
+ userDataJson,
307
+ userData,
308
+ eventIdPrefix
309
+ }));
317
310
  if (error) {
318
311
  throw error;
319
312
  }
@@ -358,11 +351,11 @@ export class AIStreamSession {
358
351
  return this.activeEvent;
359
352
  }
360
353
  cleanupEvent() {
361
- var _this$activeObserver, _this$activeEvent5;
354
+ var _this$activeObserver, _this$activeEvent4;
362
355
  logger.debug('AIStreamSession cleanupEvent');
363
356
  (_this$activeObserver = this.activeObserver) === null || _this$activeObserver === void 0 || _this$activeObserver.disconnect();
364
357
  this.activeObserver = null;
365
- (_this$activeEvent5 = this.activeEvent) === null || _this$activeEvent5 === void 0 || _this$activeEvent5.emit('close');
358
+ (_this$activeEvent4 = this.activeEvent) === null || _this$activeEvent4 === void 0 || _this$activeEvent4.emit('close');
366
359
  this.activeEvent = null;
367
360
  }
368
361
  cleanup() {
@@ -420,8 +413,7 @@ export class AIStreamEvent {
420
413
  const [error] = await tryCatchTTT(() => sendTextData({
421
414
  sessionId: this.sessionId,
422
415
  text: chunk.text,
423
- dataChannel,
424
- userData: chunk.userData
416
+ dataChannel
425
417
  }));
426
418
  if (error) {
427
419
  throw error;
@@ -433,13 +425,11 @@ export class AIStreamEvent {
433
425
  // path: chunk.path,
434
426
  // format: chunk.format,
435
427
  // dataChannel,
436
- // userData: chunk.userData,
437
428
  // });
438
429
  } else if (chunk.type === 'image') {
439
430
  const [error] = await tryCatchTTT(() => sendImageData({
440
431
  sessionId: this.sessionId,
441
- path: chunk.path,
442
- userData: chunk.userData
432
+ path: chunk.path
443
433
  }));
444
434
  if (error) {
445
435
  throw error;
@@ -485,7 +475,6 @@ export class AIStreamEvent {
485
475
  startPromise = startRecordAndSendAudioData({
486
476
  sessionId: this.sessionId,
487
477
  dataChannel,
488
- userData: source.userData,
489
478
  recordInitParams: source.sampleRate ? {
490
479
  sampleRate: source.sampleRate
491
480
  } : undefined,
@@ -497,7 +486,6 @@ export class AIStreamEvent {
497
486
  // await startRecordAndSendVideoData({
498
487
  // dataChannel,
499
488
  // cameraType,
500
- // userData: source.userData,
501
489
  // });
502
490
  }
503
491
  },
@@ -514,8 +502,7 @@ export class AIStreamEvent {
514
502
  if (source.type === 'audio') {
515
503
  file = await stopRecordAndSendAudioData({
516
504
  sessionId: this.sessionId,
517
- dataChannel,
518
- userData: source.userData
505
+ dataChannel
519
506
  });
520
507
  } else if (source.type === 'video') {
521
508
  logger.warn('Video data sending is not implemented yet');
@@ -523,7 +510,6 @@ export class AIStreamEvent {
523
510
  // await stopRecordAndSendVideoData({
524
511
  // dataChannel,
525
512
  // cameraType,
526
- // userData: source.userData,
527
513
  // });
528
514
  }
529
515
  sendEventPayloadEnd({
@@ -539,18 +525,17 @@ export class AIStreamEvent {
539
525
  this.streams[dataChannel] = stream;
540
526
  return stream;
541
527
  }
542
- async end(options) {
528
+ async end() {
543
529
  if (this.closed) {
544
530
  return;
545
531
  }
546
532
  await Promise.all([...Object.values(this.chains), ...Object.values(this.streams).map(s => s.stop())]);
547
533
  await sendEventEnd({
548
534
  eventId: this.eventId,
549
- sessionId: this.sessionId,
550
- userData: options === null || options === void 0 ? void 0 : options.userData
535
+ sessionId: this.sessionId
551
536
  });
552
537
  }
553
- abort(options) {
538
+ abort() {
554
539
  if (this.closed) {
555
540
  return;
556
541
  }
@@ -558,8 +543,7 @@ export class AIStreamEvent {
558
543
  // 故意不等,直接发送中断事件
559
544
  sendEventChatBreak({
560
545
  eventId: this.eventId,
561
- sessionId: this.sessionId,
562
- userData: options === null || options === void 0 ? void 0 : options.userData
546
+ sessionId: this.sessionId
563
547
  });
564
548
  }
565
549
  const error = new AIStreamError('This operation was aborted', AIStreamErrorCode.EVENT_ABORTED);
@@ -504,8 +504,7 @@ mock.hooks.hook('sendImageData', context => {
504
504
  }
505
505
  session.currentEvent.data.push({
506
506
  type: 'image',
507
- path: context.options.path,
508
- userData: context.options.userData
507
+ path: context.options.path
509
508
  });
510
509
  context.result = true;
511
510
  });
@@ -517,8 +516,7 @@ mock.hooks.hook('sendTextData', context => {
517
516
  }
518
517
  session.currentEvent.data.push({
519
518
  type: 'text',
520
- text: context.options.text,
521
- userData: context.options.userData
519
+ text: context.options.text
522
520
  });
523
521
  });
524
522
  const filterRecords = query => {
@@ -1,5 +1,5 @@
1
1
  import { Emitter } from '@ray-js/t-agent';
2
- import { Attribute, ReceivedTextSkillPacketBody } from '../AIStreamTypes';
2
+ import { ReceivedTextSkillPacketBody } from '../AIStreamTypes';
3
3
  interface TTTCallContext {
4
4
  options: any;
5
5
  result: any;
@@ -8,11 +8,9 @@ export interface SendToAIStreamContext {
8
8
  data: Array<{
9
9
  type: 'text';
10
10
  text: string;
11
- userData?: Attribute[];
12
11
  } | {
13
12
  type: 'image';
14
13
  path: string;
15
- userData?: Attribute[];
16
14
  }>;
17
15
  responseText: string | undefined;
18
16
  wordDelayMs: number;
@@ -5,3 +5,4 @@ export interface Resolvable<T = void> {
5
5
  state: 'pending' | 'fulfilled' | 'rejected';
6
6
  }
7
7
  export declare const createResolvable: <T = void>() => Resolvable<T>;
8
+ export declare function deepMerge(target: any, source: any): any;
@@ -22,4 +22,27 @@ export const createResolvable = () => {
22
22
  };
23
23
  });
24
24
  return ret;
25
- };
25
+ };
26
+ export function deepMerge(target, source) {
27
+ if (typeof target !== 'object' || target === null) {
28
+ return source; // 如果目标不是对象,直接返回来源
29
+ }
30
+ if (typeof source !== 'object' || source === null) {
31
+ return target; // 如果来源不是对象,返回目标
32
+ }
33
+ for (const key in source) {
34
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
35
+ const sourceValue = source[key];
36
+ const targetValue = target[key];
37
+
38
+ // 如果是对象,递归合并
39
+ if (typeof sourceValue === 'object' && sourceValue !== null) {
40
+ target[key] = deepMerge(Array.isArray(targetValue) ? [] : targetValue || {}, sourceValue);
41
+ } else {
42
+ // 否则直接赋值
43
+ target[key] = sourceValue;
44
+ }
45
+ }
46
+ }
47
+ return target;
48
+ }
@@ -1,14 +1,14 @@
1
1
  import '../polyfill';
2
2
  import { AIStreamSession } from './AIStream';
3
- import { AIStreamChatAttribute } from '../AIStreamTypes';
3
+ import { AIStreamUserData } from '../AIStreamTypes';
4
4
  import { InputBlock, StreamResponse } from '@ray-js/t-agent';
5
5
  export interface SendBlocksToAIStreamParams {
6
6
  blocks: InputBlock[];
7
7
  session: AIStreamSession;
8
- attribute?: AIStreamChatAttribute;
9
8
  signal?: AbortSignal;
10
9
  enableTts?: boolean;
11
10
  eventIdPrefix?: string;
11
+ getUserData: () => Promise<AIStreamUserData>;
12
12
  }
13
13
  export declare function sendBlocksToAIStream(params: SendBlocksToAIStreamParams): {
14
14
  response: StreamResponse;
@@ -1,4 +1,3 @@
1
- import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
2
1
  import "core-js/modules/es.json.stringify.js";
3
2
  import "core-js/modules/web.dom-collections.iterator.js";
4
3
  import '../polyfill';
@@ -8,6 +7,7 @@ import { EmitterEvent, generateId, safeParseJSON, StreamResponse } from '@ray-js
8
7
  import { tryCatch } from './misc';
9
8
  import { AIStreamError, transformErrorCode } from './errors';
10
9
  import logger from './logger';
10
+ import { deepMerge } from './object';
11
11
  const mimeTypeToFormatMap = {
12
12
  'video/mp4': FileFormat.MP4,
13
13
  'text/json': FileFormat.JSON,
@@ -20,7 +20,8 @@ export function sendBlocksToAIStream(params) {
20
20
  session,
21
21
  blocks,
22
22
  signal,
23
- eventIdPrefix
23
+ eventIdPrefix,
24
+ getUserData
24
25
  } = params;
25
26
  let audioEmitter = null;
26
27
  for (const block of blocks) {
@@ -31,10 +32,6 @@ export function sendBlocksToAIStream(params) {
31
32
  audioEmitter = block.audio_emitter;
32
33
  }
33
34
  }
34
- const attribute = _objectSpread({
35
- 'processing.interrupt': 'false',
36
- 'asr.enableVad': 'false'
37
- }, params.attribute);
38
35
  let canceled = false;
39
36
  let closed = false;
40
37
  let event = null;
@@ -103,14 +100,26 @@ export function sendBlocksToAIStream(params) {
103
100
  }
104
101
  });
105
102
  }
103
+ const chatAttributes = {
104
+ 'processing.interrupt': 'false',
105
+ 'asr.enableVad': 'false'
106
+ };
107
+ let eventUserData = {};
108
+ if (getUserData) {
109
+ eventUserData = await getUserData();
110
+ }
111
+ const userData = deepMerge({
112
+ chatAttributes
113
+ }, eventUserData);
106
114
  let error;
107
115
  [error, event] = await tryCatch(() => session.startEvent({
108
116
  signal,
109
117
  eventIdPrefix,
118
+ userDataJson: JSON.stringify(userData),
110
119
  userData: [{
111
120
  type: AIStreamAttributeType.AI_CHAT,
112
121
  payloadType: AIStreamAttributePayloadType.STRING,
113
- value: JSON.stringify(attribute)
122
+ value: JSON.stringify(chatAttributes)
114
123
  }]
115
124
  }));
116
125
  if (error) {
@@ -77,6 +77,7 @@ export declare const closeSession: (options?: Omit<CloseSessionParams, "success"
77
77
  export declare const sendEventStart: (options?: Omit<SendEventStartParams, "success" | "fail"> | undefined) => Promise<{
78
78
  eventId: string;
79
79
  }>;
80
+ /** @deprecated */
80
81
  export declare const sendEventPayloadEnd: (options?: Omit<SendEventPayloadEndParams, "success" | "fail"> | undefined) => Promise<null>;
81
82
  export declare const sendEventEnd: (options?: Omit<SendEventEndParams, "success" | "fail"> | undefined) => Promise<null>;
82
83
  export declare const sendEventChatBreak: (options?: Omit<SendEventChatBreakParams, "success" | "fail"> | undefined) => Promise<null>;
package/dist/utils/ttt.js CHANGED
@@ -37,6 +37,8 @@ export const queryAgentToken = promisify(ty.aistream.queryAgentToken, true);
37
37
  export const createSession = promisify(ty.aistream.createSession, true);
38
38
  export const closeSession = promisify(ty.aistream.closeSession, true);
39
39
  export const sendEventStart = promisify(ty.aistream.sendEventStart, true);
40
+
41
+ /** @deprecated */
40
42
  export const sendEventPayloadEnd = promisify(ty.aistream.sendEventPayloadEnd, true);
41
43
  export const sendEventEnd = promisify(ty.aistream.sendEventEnd, true);
42
44
  export const sendEventChatBreak = promisify(ty.aistream.sendEventChatBreak, true);
@@ -1,6 +1,6 @@
1
1
  import { ChatAgent, ChatCardObject, ChatMessage, ChatMessageStatus, ChatTile, GetChatPluginHandler, InputBlock } from '@ray-js/t-agent';
2
2
  import { TTTAction } from './utils';
3
- import { ConnectClientType, ReceivedTextSkillPacketBody } from './AIStreamTypes';
3
+ import { AIStreamUserData, ConnectClientType, ReceivedTextSkillPacketBody } from './AIStreamTypes';
4
4
  import { ChatHistoryStore, StoredMessageObject } from './ChatHistoryStore';
5
5
  export interface AIStreamOptions {
6
6
  /** client 类型: 1-作为设备代理, 2-作为 App,3-作为开发者(行业 App) */
@@ -58,18 +58,23 @@ export interface AIStreamHooks {
58
58
  onCardsReceived: (skills: ReceivedTextSkillPacketBody[], result: {
59
59
  cards: ChatCardObject[];
60
60
  }) => void;
61
+ onUserDataRead: (type: 'create-session' | 'start-event', data: {
62
+ blocks?: InputBlock[];
63
+ }, result: {
64
+ userData: AIStreamUserData;
65
+ }) => void;
61
66
  }
62
67
  export declare function withAIStream(options?: AIStreamOptions): (agent: ChatAgent) => {
63
68
  hooks: import("hookable").Hookable<AIStreamHooks, import("hookable").HookKeys<AIStreamHooks>>;
64
69
  aiStream: {
65
- send: (blocks: InputBlock[], signal?: AbortSignal, extraOptions?: Record<string, any>) => {
70
+ send: (blocks: InputBlock[], signal?: AbortSignal, eventUserData?: AIStreamUserData) => {
66
71
  response: import("@ray-js/t-agent").StreamResponse;
67
72
  metaPromise: Promise<Record<string, any>>;
68
73
  };
69
74
  chat: (blocks: InputBlock[], signal?: AbortSignal, options?: {
70
75
  sendBy?: string | undefined;
71
76
  responseBy?: string | undefined;
72
- extraOptions?: Record<string, any> | undefined;
77
+ userData?: AIStreamUserData | undefined;
73
78
  } | undefined) => Promise<ChatMessage[]>;
74
79
  options: AIStreamOptions;
75
80
  removeMessage: (message: ChatMessage) => Promise<void>;
@@ -86,6 +91,7 @@ export declare function withAIStream(options?: AIStreamOptions): (agent: ChatAge
86
91
  onTextCompose: (fn: AIStreamHooks['onTextCompose']) => () => void;
87
92
  onSkillsEnd: (fn: AIStreamHooks['onSkillsEnd']) => () => void;
88
93
  onCardsReceived: (fn: AIStreamHooks['onCardsReceived']) => () => void;
94
+ onUserDataRead: (fn: AIStreamHooks['onUserDataRead']) => () => void;
89
95
  onTTTAction: (fn: AIStreamHooks['onTTTAction']) => () => void;
90
96
  getChatId: () => Promise<string>;
91
97
  };
@@ -14,6 +14,7 @@ import { BizCode, ConnectClientType } from './AIStreamTypes';
14
14
  import { DEFAULT_TOKEN_API, DEFAULT_TOKEN_API_VERSION, globalAIStreamClient } from './global';
15
15
  import logger from './utils/logger';
16
16
  import { ChatHistoryLocalStore } from './ChatHistoryLocalStore';
17
+ import { deepMerge } from './utils/object';
17
18
  export function withAIStream() {
18
19
  let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
19
20
  const hooks = createHooks();
@@ -88,7 +89,14 @@ export function withAIStream() {
88
89
  extParams: _objectSpread({
89
90
  needTts: !!options.enableTts,
90
91
  deviceId
91
- }, tokenOptions.extParams)
92
+ }, tokenOptions.extParams),
93
+ getSessionUserData: async () => {
94
+ const result = {
95
+ userData: {}
96
+ };
97
+ await hooks.callHook('onUserDataRead', 'create-session', {}, result);
98
+ return result.userData;
99
+ }
92
100
  });
93
101
  await session.set('AIStream.streamSession', streamSession);
94
102
  if (options.earlyStart) {
@@ -221,14 +229,25 @@ export function withAIStream() {
221
229
  };
222
230
  }
223
231
  });
224
- const send = (blocks, signal, extraOptions) => {
232
+ const send = (blocks, signal, eventUserData) => {
225
233
  const streamSession = session.get('AIStream.streamSession');
226
234
  const result = sendBlocksToAIStream({
227
235
  blocks,
228
236
  session: streamSession,
229
237
  signal,
230
238
  eventIdPrefix: options.eventIdPrefix,
231
- attribute: _objectSpread({}, extraOptions)
239
+ getUserData: async () => {
240
+ const userDataResult = {
241
+ userData: {}
242
+ };
243
+ await hooks.callHook('onUserDataRead', 'start-event', {
244
+ blocks
245
+ }, userDataResult);
246
+ const userData = {};
247
+ deepMerge(userData, userDataResult.userData);
248
+ deepMerge(userData, eventUserData);
249
+ return userData;
250
+ }
232
251
  });
233
252
  signal === null || signal === void 0 || signal.addEventListener('abort', event => {
234
253
  logger.debug('withAIStream signal aborted, response.started:', result.response.started);
@@ -245,7 +264,7 @@ export function withAIStream() {
245
264
  const {
246
265
  sendBy = 'user',
247
266
  responseBy = 'assistant',
248
- extraOptions
267
+ userData
249
268
  } = options || {};
250
269
  let audioEmitter = null;
251
270
  for (const block of blocks) {
@@ -345,7 +364,7 @@ export function withAIStream() {
345
364
  const {
346
365
  response,
347
366
  metaPromise
348
- } = send(blocks, signal, extraOptions);
367
+ } = send(blocks, signal, userData);
349
368
  if (audioPromise) {
350
369
  try {
351
370
  await audioPromise;
@@ -585,6 +604,9 @@ export function withAIStream() {
585
604
  onCardsReceived: fn => {
586
605
  return hooks.hook('onCardsReceived', fn);
587
606
  },
607
+ onUserDataRead: fn => {
608
+ return hooks.hook('onUserDataRead', fn);
609
+ },
588
610
  onTTTAction: fn => {
589
611
  return hooks.hook('onTTTAction', fn);
590
612
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ray-js/t-agent-plugin-aistream",
3
- "version": "0.2.6-beta-8",
3
+ "version": "0.2.7-beta.1",
4
4
  "author": "Tuya.inc",
5
5
  "license": "MIT",
6
6
  "private": false,
@@ -35,5 +35,5 @@
35
35
  "devDependencies": {
36
36
  "@types/url-parse": "^1.4.11"
37
37
  },
38
- "gitHead": "6fc9a8195706d72c2bab10479e8d65a26854bdde"
38
+ "gitHead": "d7754f9879a7ec837eb343ac759a08734cc789d3"
39
39
  }