@ray-js/t-agent-plugin-aistream 0.2.7 → 0.2.8-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.
@@ -4,10 +4,11 @@ import "core-js/modules/es.json.stringify.js";
4
4
  import "core-js/modules/es.regexp.exec.js";
5
5
  import "core-js/modules/esnext.iterator.constructor.js";
6
6
  import "core-js/modules/esnext.iterator.filter.js";
7
+ import "core-js/modules/esnext.iterator.find.js";
7
8
  import "core-js/modules/esnext.iterator.map.js";
8
9
  import "core-js/modules/web.dom-collections.iterator.js";
9
10
  import { mock } from './mock';
10
- import { EmitterEvent, generateId } from '@ray-js/t-agent';
11
+ import { EmitterEvent, generateId, safeParseJSON } from '@ray-js/t-agent';
11
12
  import { AIStreamAppErrorCode, AIStreamServerErrorCode, BizCode, ConnectState, EventType, NetworkType, ReceivedTextPacketEof, ReceivedTextPacketType, SessionState, StreamFlag } from '../AIStreamTypes';
12
13
  import AbortController from './abort';
13
14
  import { tryCatch } from './misc';
@@ -17,6 +18,9 @@ function splitString(input) {
17
18
  }
18
19
  mock.data.set('sessionMap', new Map());
19
20
  mock.data.set('tokenMap', new Map());
21
+ mock.data.set('mcpRequestId', 1);
22
+ mock.data.set('sentEvents', []);
23
+ mock.data.set('mcpAutoHandshake', true);
20
24
  const getSession = (sessionId, eventId) => {
21
25
  const connection = getCurrentConnection();
22
26
  if (!connection) {
@@ -131,6 +135,46 @@ const dispatch = (type, detail) => {
131
135
  detail
132
136
  }));
133
137
  };
138
+ const scheduleMcpHandshake = session => {
139
+ var _userData$sessionAttr;
140
+ if (!mock.data.get('mcpAutoHandshake')) {
141
+ return;
142
+ }
143
+ const userData = safeParseJSON(session.userDataJson || '');
144
+ if (!(userData !== null && userData !== void 0 && (_userData$sessionAttr = userData.sessionAttributes) !== null && _userData$sessionAttr !== void 0 && _userData$sessionAttr.deviceMcp)) {
145
+ return;
146
+ }
147
+ setTimeout(() => {
148
+ if (session.closed) {
149
+ return;
150
+ }
151
+ dispatch('onEventReceived', {
152
+ sessionId: session.sessionId,
153
+ eventId: generateId(),
154
+ eventType: EventType.MCP_CMD,
155
+ payload: JSON.stringify({
156
+ jsonrpc: '2.0',
157
+ id: 1,
158
+ method: 'initialize',
159
+ params: {}
160
+ })
161
+ });
162
+ }, 0);
163
+ setTimeout(() => {
164
+ if (session.closed) {
165
+ return;
166
+ }
167
+ dispatch('onEventReceived', {
168
+ sessionId: session.sessionId,
169
+ eventId: generateId(),
170
+ eventType: EventType.MCP_CMD,
171
+ payload: JSON.stringify({
172
+ jsonrpc: '2.0',
173
+ method: 'notifications/initialized'
174
+ })
175
+ });
176
+ }, 10);
177
+ };
134
178
  mock.hooks.hook('createSession', context => {
135
179
  const connection = getCurrentConnection();
136
180
  if (!connection) {
@@ -146,7 +190,8 @@ mock.hooks.hook('createSession', context => {
146
190
  revDataChannels: ['text', 'audio'],
147
191
  currentEvent: null,
148
192
  tokenConfig,
149
- chatId: tokenConfig.chatId
193
+ chatId: tokenConfig.chatId,
194
+ userDataJson: context.options.userDataJson
150
195
  };
151
196
  map.set(session.sessionId, session);
152
197
  context.result = {
@@ -154,6 +199,7 @@ mock.hooks.hook('createSession', context => {
154
199
  sendDataChannels: session.sendDataChannels,
155
200
  revDataChannels: session.revDataChannels
156
201
  };
202
+ scheduleMcpHandshake(session);
157
203
 
158
204
  // 用于测试断开连接;
159
205
  // setTimeout(() => {
@@ -185,6 +231,10 @@ mock.hooks.hook('closeSession', context => {
185
231
  const map = mock.data.get('sessionMap');
186
232
  const sessionId = context.options.sessionId;
187
233
  const session = map.get(sessionId);
234
+ if (!session) {
235
+ context.result = true;
236
+ return;
237
+ }
188
238
  session.closed = true;
189
239
  map.delete(sessionId);
190
240
  context.result = true;
@@ -221,7 +271,7 @@ mock.hooks.hook('sendEventStart', async context => {
221
271
  text: data ? JSON.stringify(data) : ''
222
272
  });
223
273
  },
224
- replyEvent: eventType => {
274
+ replyEvent: (eventType, payload) => {
225
275
  if (session.closed || event.controller.signal.aborted) {
226
276
  return;
227
277
  }
@@ -231,9 +281,12 @@ mock.hooks.hook('sendEventStart', async context => {
231
281
  dispatch('onEventReceived', {
232
282
  eventId,
233
283
  sessionId: session.sessionId,
234
- eventType
284
+ eventType,
285
+ payload
235
286
  });
236
287
  },
288
+ resolveMcpResponse: () => undefined,
289
+ rejectMcpResponse: () => undefined,
237
290
  asr: {
238
291
  finishController: new AbortController(),
239
292
  promise: Promise.resolve()
@@ -257,7 +310,12 @@ mock.hooks.hook('unregisterVoiceAmplitudes', context => {
257
310
  context.result = true;
258
311
  });
259
312
  mock.hooks.hook('sendEventEnd', async context => {
260
- const session = getSession(context.options.sessionId, context.options.eventId);
313
+ const map = mock.data.get('sessionMap');
314
+ const session = map.get(context.options.sessionId);
315
+ if (!(session !== null && session !== void 0 && session.currentEvent) || session.currentEvent.eventId !== context.options.eventId) {
316
+ context.result = true;
317
+ return;
318
+ }
261
319
  context.result = true;
262
320
  const event = session.currentEvent;
263
321
  if (event.eventId !== context.options.eventId) {
@@ -265,18 +323,184 @@ mock.hooks.hook('sendEventEnd', async context => {
265
323
  }
266
324
  await mock.sleep(100);
267
325
  (async () => {
268
- var _ctx$responseSkills;
269
- await event.asr.promise;
270
- if (session.tokenConfig.onlyAsr) {
326
+ let streamEnded = false;
327
+ let hasStreamedResponse = false;
328
+ const isEventActive = () => {
329
+ return !streamEnded && !event.controller.signal.aborted && !session.closed && !!session.currentEvent && session.currentEvent.eventId === event.eventId;
330
+ };
331
+ const finishEvent = async function () {
332
+ let delayMs = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
333
+ if (streamEnded) {
334
+ return;
335
+ }
336
+ if (delayMs > 0) {
337
+ await mock.sleep(delayMs);
338
+ }
339
+ if (!isEventActive()) {
340
+ var _session$currentEvent;
341
+ streamEnded = true;
342
+ if (((_session$currentEvent = session.currentEvent) === null || _session$currentEvent === void 0 ? void 0 : _session$currentEvent.eventId) === event.eventId) {
343
+ session.currentEvent = null;
344
+ }
345
+ return;
346
+ }
347
+ streamEnded = true;
271
348
  event.replyEvent(EventType.EVENT_END);
272
349
  session.currentEvent = null;
350
+ };
351
+ await event.asr.promise;
352
+ if (session.tokenConfig.onlyAsr) {
353
+ await finishEvent();
273
354
  return;
274
355
  }
356
+ event.replyEvent(EventType.EVENT_START);
275
357
  const ctx = {
276
358
  data: event.data,
277
359
  responseText: '',
278
360
  wordDelayMs: 100,
279
- chatId: session.chatId
361
+ chatId: session.chatId,
362
+ writeText: async (text, options) => {
363
+ var _ref, _options$wordDelayMs;
364
+ if (!text) {
365
+ return;
366
+ }
367
+ if (options !== null && options !== void 0 && options.delayMs) {
368
+ await mock.sleep(options.delayMs);
369
+ }
370
+ if (!isEventActive()) {
371
+ return;
372
+ }
373
+ const wordDelayMs = (_ref = (_options$wordDelayMs = options === null || options === void 0 ? void 0 : options.wordDelayMs) !== null && _options$wordDelayMs !== void 0 ? _options$wordDelayMs : ctx.wordDelayMs) !== null && _ref !== void 0 ? _ref : 100;
374
+ const words = splitString(text);
375
+ const bizId = generateId();
376
+ hasStreamedResponse = true;
377
+ event.replyText(StreamFlag.START);
378
+ for (let i = 0; i < words.length; i++) {
379
+ const word = words[i];
380
+ if (wordDelayMs > 0) {
381
+ await mock.sleep(wordDelayMs);
382
+ }
383
+ if (!isEventActive()) {
384
+ return;
385
+ }
386
+ event.replyText(StreamFlag.IN_PROGRESS, {
387
+ bizType: ReceivedTextPacketType.NLG,
388
+ eof: ReceivedTextPacketEof.CONTINUE,
389
+ bizId,
390
+ data: {
391
+ content: word,
392
+ appendMode: 'append',
393
+ finish: false
394
+ }
395
+ });
396
+ }
397
+ if (!isEventActive()) {
398
+ return;
399
+ }
400
+ event.replyText(StreamFlag.IN_PROGRESS, {
401
+ bizType: ReceivedTextPacketType.NLG,
402
+ eof: ReceivedTextPacketEof.END,
403
+ bizId,
404
+ data: {
405
+ content: '',
406
+ appendMode: 'append',
407
+ finish: true
408
+ }
409
+ });
410
+ if (!isEventActive()) {
411
+ return;
412
+ }
413
+ event.replyText(StreamFlag.END);
414
+ },
415
+ writeSkill: async (skill, options) => {
416
+ if (!skill) {
417
+ return;
418
+ }
419
+ if (options !== null && options !== void 0 && options.delayMs) {
420
+ await mock.sleep(options.delayMs);
421
+ }
422
+ if (!isEventActive()) {
423
+ return;
424
+ }
425
+ hasStreamedResponse = true;
426
+ event.replyText(StreamFlag.IN_PROGRESS, {
427
+ bizType: ReceivedTextPacketType.SKILL,
428
+ eof: ReceivedTextPacketEof.END,
429
+ bizId: generateId(),
430
+ data: skill
431
+ });
432
+ },
433
+ end: async options => {
434
+ await finishEvent((options === null || options === void 0 ? void 0 : options.delayMs) || 0);
435
+ },
436
+ callMCPTool: async (toolName, params, options) => {
437
+ if (!isEventActive()) {
438
+ return undefined;
439
+ }
440
+ const requestId = mock.data.get('mcpRequestId') || 1;
441
+ mock.data.set('mcpRequestId', requestId + 1);
442
+ const request = {
443
+ jsonrpc: '2.0',
444
+ id: requestId,
445
+ method: 'tools/call',
446
+ params: {
447
+ name: toolName,
448
+ arguments: params || {}
449
+ }
450
+ };
451
+ const shouldWaitResponse = typeof (options === null || options === void 0 ? void 0 : options.waitResponse) === 'boolean' ? options.waitResponse : !!(request !== null && request !== void 0 && request.id) && (request === null || request === void 0 ? void 0 : request.method) !== 'notifications/initialized';
452
+ await mock.sleep((options === null || options === void 0 ? void 0 : options.delayMs) || 0);
453
+ if (!isEventActive()) {
454
+ return undefined;
455
+ }
456
+ event.replyEvent(EventType.MCP_CMD, JSON.stringify(request));
457
+ if (!shouldWaitResponse) {
458
+ return undefined;
459
+ }
460
+ try {
461
+ var _result$content2;
462
+ const responsePayload = await new Promise((resolve, reject) => {
463
+ event.resolveMcpResponse = resolve;
464
+ event.rejectMcpResponse = reject;
465
+ });
466
+ event.resolveMcpResponse = () => undefined;
467
+ event.rejectMcpResponse = () => undefined;
468
+ if (!responsePayload) {
469
+ return undefined;
470
+ }
471
+ const response = safeParseJSON(responsePayload);
472
+ if (!response || typeof response !== 'object') {
473
+ throw new Error('Invalid MCP response payload');
474
+ }
475
+ if (response.error) {
476
+ throw new Error(response.error.message || 'MCP tool call failed');
477
+ }
478
+ const result = response.result || {};
479
+ if (result.isError) {
480
+ var _result$content;
481
+ const text = (_result$content = result.content) === null || _result$content === void 0 || (_result$content = _result$content.find(item => (item === null || item === void 0 ? void 0 : item.type) === 'text')) === null || _result$content === void 0 ? void 0 : _result$content.text;
482
+ const parsed = typeof text === 'string' ? safeParseJSON(text) : undefined;
483
+ const message = typeof parsed === 'string' ? parsed : (parsed === null || parsed === void 0 ? void 0 : parsed.message) || (parsed === null || parsed === void 0 ? void 0 : parsed.error) || 'MCP tool call failed';
484
+ throw new Error(message);
485
+ }
486
+ if (result.structuredContent !== undefined) {
487
+ return result.structuredContent;
488
+ }
489
+ const text = (_result$content2 = result.content) === null || _result$content2 === void 0 || (_result$content2 = _result$content2.find(item => (item === null || item === void 0 ? void 0 : item.type) === 'text')) === null || _result$content2 === void 0 ? void 0 : _result$content2.text;
490
+ if (typeof text === 'string') {
491
+ var _safeParseJSON;
492
+ return (_safeParseJSON = safeParseJSON(text)) !== null && _safeParseJSON !== void 0 ? _safeParseJSON : text;
493
+ }
494
+ if (result.content !== undefined) {
495
+ return result.content;
496
+ }
497
+ return result;
498
+ } catch (error) {
499
+ event.resolveMcpResponse = () => undefined;
500
+ event.rejectMcpResponse = () => undefined;
501
+ throw error;
502
+ }
503
+ }
280
504
  };
281
505
  const [error] = await tryCatch(() => mock.hooks.callHook('sendToAIStream', ctx));
282
506
  if (error) {
@@ -291,98 +515,80 @@ mock.hooks.hook('sendEventEnd', async context => {
291
515
  return;
292
516
  }
293
517
  if (ctx.data.length === 0) {
294
- event.replyEvent(EventType.EVENT_START);
295
518
  await mock.sleep(100);
296
- if (event.controller.signal.aborted || session.closed) {
519
+ if (!isEventActive()) {
297
520
  return;
298
521
  }
299
- event.replyEvent(EventType.EVENT_END);
300
- session.currentEvent = null;
522
+ await finishEvent();
301
523
  return;
302
524
  }
303
- const text = ctx.responseText || '⚠️ No mock text response matched!';
304
- const wordDelayMs = ctx.wordDelayMs || 100;
305
- const words = splitString(text);
306
- if (event.controller.signal.aborted || session.closed) {
525
+ if (streamEnded) {
307
526
  return;
308
527
  }
309
- event.replyEvent(EventType.EVENT_START);
310
- await mock.sleep(500);
311
- if (event.controller.signal.aborted || session.closed) {
312
- return;
313
- }
314
- const bizId = generateId();
315
- event.replyText(StreamFlag.START);
316
- for (let i = 0; i < words.length; i++) {
317
- const word = words[i];
318
- await mock.sleep(wordDelayMs);
319
- if (event.controller.signal.aborted || session.closed) {
320
- return;
321
- }
322
- event.replyText(StreamFlag.IN_PROGRESS, {
323
- bizType: ReceivedTextPacketType.NLG,
324
- eof: ReceivedTextPacketEof.CONTINUE,
325
- bizId,
326
- data: {
327
- content: word,
328
- appendMode: 'append',
329
- finish: false
330
- }
528
+ if (!hasStreamedResponse) {
529
+ var _ctx$responseSkills;
530
+ const text = ctx.responseText || '⚠️ No mock text response matched!';
531
+ await mock.sleep(500);
532
+ await ctx.writeText(text, {
533
+ wordDelayMs: ctx.wordDelayMs
331
534
  });
332
- }
333
- await mock.sleep(100);
334
- if (event.controller.signal.aborted || session.closed) {
335
- return;
336
- }
337
- event.replyText(StreamFlag.IN_PROGRESS, {
338
- bizType: ReceivedTextPacketType.NLG,
339
- eof: ReceivedTextPacketEof.END,
340
- bizId,
341
- data: {
342
- content: '',
343
- appendMode: 'append',
344
- finish: true
345
- }
346
- });
347
- await mock.sleep(10);
348
- if (event.controller.signal.aborted || session.closed) {
349
- return;
350
- }
351
- if ((_ctx$responseSkills = ctx.responseSkills) !== null && _ctx$responseSkills !== void 0 && _ctx$responseSkills.length) {
352
- for (let i = 0; i < ctx.responseSkills.length; i++) {
353
- const skill = ctx.responseSkills[i];
354
- await mock.sleep(100);
355
- if (event.controller.signal.aborted || session.closed) {
356
- return;
535
+ if ((_ctx$responseSkills = ctx.responseSkills) !== null && _ctx$responseSkills !== void 0 && _ctx$responseSkills.length) {
536
+ for (let i = 0; i < ctx.responseSkills.length; i++) {
537
+ await ctx.writeSkill(ctx.responseSkills[i], {
538
+ delayMs: 100
539
+ });
357
540
  }
358
- event.replyText(StreamFlag.IN_PROGRESS, {
359
- bizType: ReceivedTextPacketType.SKILL,
360
- eof: ReceivedTextPacketEof.END,
361
- bizId,
362
- data: skill
363
- });
364
541
  }
365
542
  }
366
- event.replyText(StreamFlag.END);
367
- await mock.sleep(500);
368
- if (event.controller.signal.aborted || session.closed) {
543
+ if (streamEnded || !isEventActive()) {
369
544
  return;
370
545
  }
371
- event.replyEvent(EventType.EVENT_END);
372
- session.currentEvent = null;
546
+ await finishEvent(500);
373
547
  })();
374
548
  });
375
549
  mock.hooks.hook('sendEventPayloadEnd', async context => {
376
- getSession(context.options.sessionId, context.options.eventId);
550
+ const map = mock.data.get('sessionMap');
551
+ const session = map.get(context.options.sessionId);
552
+ if (!session || !session.currentEvent || session.currentEvent.eventId !== context.options.eventId) {
553
+ context.result = true;
554
+ return;
555
+ }
377
556
  context.result = true;
378
557
  await mock.sleep(100);
379
558
  });
380
559
  mock.hooks.hook('sendEventChatBreak', async context => {
381
- const session = getSession(context.options.sessionId, context.options.eventId);
560
+ const map = mock.data.get('sessionMap');
561
+ const session = map.get(context.options.sessionId);
562
+ if (!(session !== null && session !== void 0 && session.currentEvent) || session.currentEvent.eventId !== context.options.eventId) {
563
+ context.result = true;
564
+ return;
565
+ }
566
+ session.currentEvent.rejectMcpResponse(new Error('sendEventChatBreak'));
382
567
  session.currentEvent.controller.abort(new Error('sendEventChatBreak'));
383
568
  session.currentEvent = null;
384
569
  context.result = true;
385
570
  });
571
+ mock.hooks.hook('sendEvent', async context => {
572
+ var _context$options;
573
+ if (((_context$options = context.options) === null || _context$options === void 0 ? void 0 : _context$options.eventType) !== EventType.MCP_CMD) {
574
+ context.result = true;
575
+ return;
576
+ }
577
+ const session = getSession(context.options.sessionId);
578
+ if (session.currentEvent && session.currentEvent.eventId === context.options.eventId) {
579
+ session.currentEvent.resolveMcpResponse(context.options.payload);
580
+ } else {
581
+ const sentEvents = mock.data.get('sentEvents') || [];
582
+ sentEvents.push({
583
+ sessionId: context.options.sessionId,
584
+ eventId: context.options.eventId,
585
+ eventType: context.options.eventType,
586
+ payload: context.options.payload
587
+ });
588
+ mock.data.set('sentEvents', sentEvents);
589
+ }
590
+ context.result = true;
591
+ });
386
592
  mock.hooks.hook('startRecordAndSendAudioData', async context => {
387
593
  const session = getSession(context.options.sessionId);
388
594
  if (!session.currentEvent) {
@@ -584,10 +790,10 @@ mock.hooks.hook('queryRecordList', context => {
584
790
  mock.hooks.hook('deleteRecordList', context => {
585
791
  const options = context.options;
586
792
  const records = filterRecords(options);
587
- records.map(_ref => {
793
+ records.map(_ref2 => {
588
794
  let {
589
795
  id
590
- } = _ref;
796
+ } = _ref2;
591
797
  return mock.deleteRecord(id);
592
798
  });
593
799
  context.result = true;
@@ -96,9 +96,11 @@ export async function tryCatchTTT(fn) {
96
96
  code,
97
97
  message
98
98
  } = error;
99
- message = "".concat(message, " (original_code: ").concat(code || '-', ")");
99
+ const originalCode = code;
100
+ message = "".concat(message, " (original_code: ").concat(originalCode || '-', ")");
100
101
  code = transformErrorCode(code);
101
102
  const e = removeTopStackFrame(new AIStreamError(message, code));
103
+ e.originalCode = originalCode;
102
104
  return [e, null];
103
105
  }
104
106
  return [null, result];
@@ -16,6 +16,20 @@ export interface SendToAIStreamContext {
16
16
  responseText: string | undefined;
17
17
  wordDelayMs: number;
18
18
  responseSkills?: ReceivedTextSkillPacketBody[];
19
+ writeText: (text: string, options?: {
20
+ delayMs?: number;
21
+ wordDelayMs?: number;
22
+ }) => Promise<void>;
23
+ writeSkill: (skill: ReceivedTextSkillPacketBody, options?: {
24
+ delayMs?: number;
25
+ }) => Promise<void>;
26
+ end: (options?: {
27
+ delayMs?: number;
28
+ }) => Promise<void>;
29
+ callMCPTool: (toolName: string, params?: Record<string, any>, options?: {
30
+ delayMs?: number;
31
+ waitResponse?: boolean;
32
+ }) => Promise<any>;
19
33
  }
20
34
  interface AsrDetectionContext {
21
35
  responseText: string | undefined;
@@ -40,9 +54,9 @@ declare const mock: {
40
54
  emitter: Emitter;
41
55
  hooks: import("hookable").Hookable<MockHooks, string>;
42
56
  getRecords: <T = any>() => Row<T>[];
43
- getRecord: <T_1 = any>(id: number) => Row<T_1> | undefined;
44
- setRecord: <T_2 = any>(entry: Row<T_2>) => void;
45
- updateRecord: <T_3 = any>(entry: Row<T_3>) => void;
57
+ getRecord: <T = any>(id: number) => Row<T> | undefined;
58
+ setRecord: <T = any>(entry: Row<T>) => void;
59
+ updateRecord: <T = any>(entry: Row<T>) => void;
46
60
  deleteRecord: (id: number) => void;
47
61
  clearRecords: () => void;
48
62
  getId: () => number;
@@ -5,4 +5,3 @@ 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,27 +22,4 @@ export const createResolvable = () => {
22
22
  };
23
23
  });
24
24
  return ret;
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
- }
25
+ };
@@ -1,4 +1,4 @@
1
- import { AudioBody, ConnectStateBody, EventBody, FileBody, ImageBody, SessionStateBody, TextBody, VideoBody } from '../AIStreamTypes';
1
+ import { AudioBody, ConnectStateBody, EventBody, FileBody, ImageBody, SessionEventBody, SessionStateBody, TextBody, VideoBody } from '../AIStreamTypes';
2
2
  export type AIStreamDataEntry = {
3
3
  type: 'text';
4
4
  body: TextBody;
@@ -23,10 +23,14 @@ export type AIStreamDataEntry = {
23
23
  } | {
24
24
  type: 'sessionState';
25
25
  body: SessionStateBody;
26
+ } | {
27
+ type: 'sessionEvent';
28
+ body: SessionEventBody;
26
29
  };
27
30
  export interface AIStreamObserverOptions {
28
- sessionState?: boolean;
29
31
  connectionState?: boolean;
32
+ sessionState?: boolean;
33
+ sessionEvent?: boolean;
30
34
  event?: boolean;
31
35
  text?: boolean;
32
36
  audio?: boolean;
@@ -5,7 +5,7 @@ import "core-js/modules/web.dom-collections.iterator.js";
5
5
  import { ConnectState, EventType, SessionState, StreamFlag } from '../AIStreamTypes';
6
6
  import { listenAudioReceived, listenConnectStateChanged, listenEventReceived, listenImageReceived, listenSessionStateChanged, listenTextReceived } from './ttt';
7
7
  import logger from './logger';
8
- const types = ['connectionState', 'sessionState', 'event', 'text', 'audio', 'video', 'file', 'image'];
8
+ const types = ['connectionState', 'sessionState', 'sessionEvent', 'event', 'text', 'audio', 'video', 'file', 'image'];
9
9
  export class AIStreamObserverPool {
10
10
  constructor() {
11
11
  _defineProperty(this, "isStarted", false);
@@ -13,6 +13,7 @@ export class AIStreamObserverPool {
13
13
  this.observerMap = {
14
14
  connectionState: new Set(),
15
15
  sessionState: new Set(),
16
+ sessionEvent: new Set(),
16
17
  event: new Set(),
17
18
  text: new Set(),
18
19
  audio: new Set(),
@@ -33,7 +34,7 @@ export class AIStreamObserverPool {
33
34
  state = "".concat(ConnectState[entry.body.connectState], " ").concat(entry.body.code || '');
34
35
  } else if (entry.type === 'sessionState') {
35
36
  state = "".concat(SessionState[entry.body.sessionState], " ").concat(entry.body.code || '');
36
- } else if (entry.type === 'event') {
37
+ } else if (entry.type === 'event' || entry.type === 'sessionEvent') {
37
38
  state = "".concat(EventType[entry.body.eventType]);
38
39
  } else if ((_entry$body = entry.body) !== null && _entry$body !== void 0 && _entry$body.streamFlag) {
39
40
  state = "".concat(StreamFlag[entry.body.streamFlag]);
@@ -66,10 +67,19 @@ export class AIStreamObserverPool {
66
67
  })), listenSessionStateChanged(body => handle({
67
68
  type: 'sessionState',
68
69
  body
69
- })), listenEventReceived(body => handle({
70
- type: 'event',
71
- body
72
- })), listenTextReceived(body => handle({
70
+ })), listenEventReceived(body => {
71
+ if (body.eventType === EventType.MCP_CMD) {
72
+ handle({
73
+ type: 'sessionEvent',
74
+ body
75
+ });
76
+ } else {
77
+ handle({
78
+ type: 'event',
79
+ body
80
+ });
81
+ }
82
+ }), listenTextReceived(body => handle({
73
83
  type: 'text',
74
84
  body
75
85
  })), listenAudioReceived(body => handle({
@@ -91,6 +101,7 @@ export class AIStreamObserverPool {
91
101
  this.observerMap = {
92
102
  connectionState: new Set(),
93
103
  sessionState: new Set(),
104
+ sessionEvent: new Set(),
94
105
  event: new Set(),
95
106
  text: new Set(),
96
107
  audio: new Set(),
@@ -13,6 +13,6 @@ interface AsyncTTTFnParams<P> {
13
13
  }
14
14
  export declare const getEnableMock: () => boolean;
15
15
  export declare const setEnableMock: (enable: boolean) => boolean;
16
- export declare function promisify<T extends AsyncTTTFnParams<any>>(fn: (options: any) => void, enableMock?: boolean): (options?: Omit<T, 'success' | 'fail'>) => Promise<Parameters<NonNullable<T["success"]>>[0]>;
16
+ export declare function promisify<T extends AsyncTTTFnParams<any>>(fn: (options: any) => void, enableMock?: boolean): (options?: Omit<T, "success" | "fail">) => Promise<Parameters<NonNullable<T["success"]>>[0]>;
17
17
  export declare function listening<T>(on: (listener: (params: T) => void) => void, off: (listener: (params: T) => void) => void, enableMock?: boolean): (listener: (params: T) => void) => () => void;
18
18
  export {};