@webex/internal-plugin-ai-assistant 3.12.0-next.9 → 3.12.0-task-refactor.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.
@@ -16,14 +16,7 @@ import {
16
16
  AI_ASSISTANT_ERROR_CODES,
17
17
  AI_ASSISTANT_ERRORS,
18
18
  } from '@webex/internal-plugin-ai-assistant/src/constants';
19
- import {
20
- jsonResponse,
21
- messageResponse,
22
- workspaceResponse,
23
- scheduleMeetingResponse,
24
- assistantActivity,
25
- citedAnswerWithSourcesResponse,
26
- } from '../data/messages';
19
+ import {jsonResponse, messageResponse, workspaceResponse, scheduleMeetingResponse} from '../data/messages';
27
20
 
28
21
  const waitForAsync = () =>
29
22
  new Promise<void>((resolve) =>
@@ -85,15 +78,12 @@ describe('plugin-ai-assistant', () => {
85
78
  it('registers correctly', async () => {
86
79
  await webex.internal.aiAssistant.register();
87
80
 
88
- assert.callCount(webex.internal.mercury.on, 2);
81
+ assert.callCount(webex.internal.mercury.on, 1);
89
82
 
90
- const firstCallArgs = webex.internal.mercury.on.getCall(0).args;
91
- expect(firstCallArgs[0]).to.equal('event:assistant-api.response');
92
- expect(firstCallArgs[1]).to.be.a('function');
83
+ const callArgs = webex.internal.mercury.on.getCall(0).args;
93
84
 
94
- const secondCallArgs = webex.internal.mercury.on.getCall(1).args;
95
- expect(secondCallArgs[0]).to.equal('assistant-api.activity');
96
- expect(secondCallArgs[1]).to.be.a('function');
85
+ expect(callArgs[0]).to.equal('event:assistant-api.response');
86
+ expect(callArgs[1]).to.be.a('function');
97
87
 
98
88
  assert.equal(webex.internal.aiAssistant.registered, true);
99
89
  });
@@ -125,13 +115,11 @@ describe('plugin-ai-assistant', () => {
125
115
 
126
116
  await webex.internal.aiAssistant.unregister();
127
117
 
128
- assert.callCount(webex.internal.mercury.off, 2);
118
+ assert.callCount(webex.internal.mercury.off, 1);
129
119
 
130
- const firstCallOrg = webex.internal.mercury.off.getCall(0).args;
131
- expect(firstCallOrg[0]).to.equal('event:assistant-api.response');
120
+ const callArgs = webex.internal.mercury.off.getCall(0).args;
132
121
 
133
- const secondCallOrg = webex.internal.mercury.off.getCall(1).args;
134
- expect(secondCallOrg[0]).to.equal('assistant-api.activity');
122
+ expect(callArgs[0]).to.equal('event:assistant-api.response');
135
123
 
136
124
  assert.equal(webex.internal.aiAssistant.registered, false);
137
125
  });
@@ -142,6 +130,7 @@ describe('plugin-ai-assistant', () => {
142
130
  const result = await webex.internal.aiAssistant.unregister();
143
131
 
144
132
  expect(result).to.be.undefined;
133
+ assert.callCount(webex.internal.mercury.disconnect, 0);
145
134
  assert.equal(webex.internal.aiAssistant.registered, false);
146
135
  });
147
136
  });
@@ -236,47 +225,6 @@ describe('plugin-ai-assistant', () => {
236
225
  clientRequestId: 'test-request-id',
237
226
  param1: 'value1',
238
227
  },
239
- headers: undefined,
240
- });
241
-
242
- const result = await requestPromise;
243
-
244
- expect(result).to.deep.equal({
245
- id: 'test-message-id',
246
- url: 'https://assistant-api-a.wbx2.com:443/assistant-api/api/v1/sessions/test-session-id/messages/test-message-id',
247
- sessionId: 'test-session-id',
248
- sessionUrl:
249
- 'https://assistant-api-a.wbx2.com:443/assistant-api/api/v1/sessions/test-session-id',
250
- creatorId: 'test-creator-id',
251
- createdAt: '2025-08-05T02:11:12.361Z',
252
- requestId: 'test-request-id',
253
- streamEventName: 'aiassistant:stream:test-request-id',
254
- });
255
- });
256
-
257
- it('makes a request with additional headers', async () => {
258
- const requestPromise = webex.internal.aiAssistant._request({
259
- resource: 'test-resource',
260
- params: {param1: 'value1'},
261
- headers: {
262
- 'X-Custom-Header': 'foo',
263
- 'X-Another-Header': 'bar',
264
- },
265
- });
266
-
267
- expect(webex.request.getCall(0).args[0]).to.deep.equal({
268
- service: 'assistant-api',
269
- resource: 'test-resource',
270
- method: 'POST',
271
- contentType: 'application/json',
272
- body: {
273
- clientRequestId: 'test-request-id',
274
- param1: 'value1',
275
- },
276
- headers: {
277
- 'X-Custom-Header': 'foo',
278
- 'X-Another-Header': 'bar',
279
- },
280
228
  });
281
229
 
282
230
  const result = await requestPromise;
@@ -334,28 +282,6 @@ describe('plugin-ai-assistant', () => {
334
282
  expect(triggerSpy.getCall(2).args[1]).to.deep.equal(expectedResult);
335
283
  });
336
284
 
337
- it('handles an activity', async () => {
338
- const triggerSpy = sinon.spy(webex.internal.aiAssistant, 'trigger');
339
-
340
- webex.internal.encryption.decryptText.callsFake(async (keyUrl, value) => {
341
- return `decrypted-with-${keyUrl}-${value}`;
342
- });
343
-
344
- // assume assistant event is received
345
- await webex.internal.aiAssistant._handleAssistantActivity(cloneDeep(assistantActivity[0]));
346
-
347
- await waitForAsync();
348
-
349
- let expectedResult = set(
350
- cloneDeep(assistantActivity[0]),
351
- 'activity.content.value.message',
352
- 'decrypted-with-kms://kms-cisco.wbx2.com/keys/9b838423-f31b-49d5-a7c7-182572340a37-message_encrypted_value_for_activity'
353
- );
354
-
355
- expect(triggerSpy.getCall(0).args[0]).to.deep.equal('aiassistant:activityReceived');
356
- expect(triggerSpy.getCall(0).args[1]).to.deep.equal(expectedResult);
357
- });
358
-
359
285
  it('decrypts a chunked json response', async () => {
360
286
  const triggerSpy = sinon.spy(webex.internal.aiAssistant, 'trigger');
361
287
  webex.internal.encryption.decryptText.callsFake(async (keyUrl, value) => {
@@ -406,7 +332,9 @@ describe('plugin-ai-assistant', () => {
406
332
  responseType: 'thought',
407
333
  };
408
334
  expect(triggerSpy.getCall(1).args[0]).to.deep.equal('aiassistant:stream:test-request-id');
409
- expect(triggerSpy.getCall(1).args[1]).to.deep.equal(expectedResult);
335
+ expect(triggerSpy.getCall(1).args[1]).to.deep.equal(
336
+ expectedResult
337
+ );
410
338
 
411
339
  triggerSpy.resetHistory();
412
340
 
@@ -515,8 +443,7 @@ describe('plugin-ai-assistant', () => {
515
443
  type: 'json',
516
444
  encryptionKeyUrl: 'kms://kms-us.wbx2.com/keys/9565506d-78b1-4742-b0fd-63719748282e',
517
445
  value: {
518
- value:
519
- 'decrypted-with-kms://kms-us.wbx2.com/keys/9565506d-78b1-4742-b0fd-63719748282e-json_3_encrypted_value',
446
+ value: 'decrypted-with-kms://kms-us.wbx2.com/keys/9565506d-78b1-4742-b0fd-63719748282e-json_3_encrypted_value',
520
447
  type: 'markdown',
521
448
  },
522
449
  },
@@ -647,10 +574,12 @@ describe('plugin-ai-assistant', () => {
647
574
  // Update the clientRequestId to match the test setup
648
575
  const firstEvent = cloneDeep(workspaceResponse[0]);
649
576
  firstEvent.clientRequestId = 'test-request-id';
650
-
577
+
651
578
  await webex.internal.aiAssistant._handleEvent(firstEvent);
652
579
 
653
- expect(triggerSpy.getCall(0).args[0]).to.equal(`aiassistant:result:test-request-id`);
580
+ expect(triggerSpy.getCall(0).args[0]).to.equal(
581
+ `aiassistant:result:test-request-id`
582
+ );
654
583
 
655
584
  await waitForAsync();
656
585
 
@@ -665,7 +594,7 @@ describe('plugin-ai-assistant', () => {
665
594
  // second event is another workspace chunk with an encrypted value
666
595
  const secondEvent = cloneDeep(workspaceResponse[1]);
667
596
  secondEvent.clientRequestId = 'test-request-id';
668
-
597
+
669
598
  await webex.internal.aiAssistant._handleEvent(secondEvent);
670
599
 
671
600
  expectedResult = set(
@@ -675,7 +604,7 @@ describe('plugin-ai-assistant', () => {
675
604
  );
676
605
 
677
606
  expect(triggerSpy.getCall(2).args[1]).to.deep.equal(expectedResult);
678
- });
607
+ });
679
608
 
680
609
  it('handles a schedule meeting response', async () => {
681
610
  const triggerSpy = sinon.spy(webex.internal.aiAssistant, 'trigger');
@@ -691,130 +620,35 @@ describe('plugin-ai-assistant', () => {
691
620
  // Handle schedule meeting event with encrypted fields
692
621
  const event = cloneDeep(scheduleMeetingResponse[0]);
693
622
  event.clientRequestId = 'test-request-id';
694
-
623
+
695
624
  await webex.internal.aiAssistant._handleEvent(event);
696
625
 
697
- expect(triggerSpy.getCall(0).args[0]).to.equal(`aiassistant:result:test-request-id`);
626
+ expect(triggerSpy.getCall(0).args[0]).to.equal(
627
+ `aiassistant:result:test-request-id`
628
+ );
698
629
 
699
630
  await waitForAsync();
700
631
 
701
632
  // Verify all encrypted fields were decrypted
702
633
  const expectedResult = cloneDeep(event);
703
- expectedResult.response.content.parameters.commentary =
634
+ expectedResult.response.content.parameters.commentary =
704
635
  'decrypted-with-kms://kms-cisco.wbx2.com/keys/dd6053f0-a1b3-428d-8104-317527d73630-schedule_meeting_encrypted_commentary';
705
- expectedResult.response.content.value.results.data.attendees[0].email =
636
+ expectedResult.response.content.value.results.data.attendees[0].email =
706
637
  'decrypted-with-kms://kms-cisco.wbx2.com/keys/dd6053f0-a1b3-428d-8104-317527d73630-schedule_meeting_encrypted_email_0';
707
- expectedResult.response.content.value.results.data.attendees[1].email =
638
+ expectedResult.response.content.value.results.data.attendees[1].email =
708
639
  'decrypted-with-kms://kms-cisco.wbx2.com/keys/dd6053f0-a1b3-428d-8104-317527d73630-schedule_meeting_encrypted_email_1';
709
- expectedResult.response.content.value.results.data.title =
640
+ expectedResult.response.content.value.results.data.title =
710
641
  'decrypted-with-kms://kms-cisco.wbx2.com/keys/dd6053f0-a1b3-428d-8104-317527d73630-schedule_meeting_encrypted_title';
711
- expectedResult.response.content.value.results.data.description =
642
+ expectedResult.response.content.value.results.data.description =
712
643
  'decrypted-with-kms://kms-cisco.wbx2.com/keys/dd6053f0-a1b3-428d-8104-317527d73630-schedule_meeting_encrypted_description';
713
- expectedResult.response.content.value.results.data.inScopeReply =
644
+ expectedResult.response.content.value.results.data.inScopeReply =
714
645
  'decrypted-with-kms://kms-cisco.wbx2.com/keys/dd6053f0-a1b3-428d-8104-317527d73630-schedule_meeting_encrypted_inScopeReply';
715
- expectedResult.response.content.value.results.data.meetingLink =
646
+ expectedResult.response.content.value.results.data.meetingLink =
716
647
  'decrypted-with-kms://kms-cisco.wbx2.com/keys/dd6053f0-a1b3-428d-8104-317527d73630-schedule_meeting_encrypted_meetingLink';
717
648
 
718
649
  expect(triggerSpy.getCall(0).args[1]).to.deep.equal(expectedResult);
719
650
  });
720
651
 
721
- it('handles a cited answer with sources response', async () => {
722
- const triggerSpy = sinon.spy(webex.internal.aiAssistant, 'trigger');
723
- webex.internal.encryption.decryptText.callsFake(async (keyUrl, value) => {
724
- return `decrypted-with-${keyUrl}-${value}`;
725
- });
726
-
727
- await webex.internal.aiAssistant._request({
728
- resource: 'test-resource',
729
- params: {param1: 'value1'},
730
- });
731
-
732
- const event = cloneDeep(citedAnswerWithSourcesResponse[0]);
733
- event.clientRequestId = 'test-request-id';
734
-
735
- await webex.internal.aiAssistant._handleEvent(event);
736
-
737
- expect(triggerSpy.getCall(0).args[0]).to.equal(`aiassistant:result:test-request-id`);
738
-
739
- await waitForAsync();
740
-
741
- const expectedResult = {
742
- sessionId: '3c1939c0-92fe-11f0-8e9f-1bafc66fbbc5',
743
- sessionUrl:
744
- 'https://assistant-api-a.wbx2.com:443/assistant-api/api/v1/sessions/3c1939c0-92fe-11f0-8e9f-1bafc66fbbc5',
745
- messageId: '3c19fd10-92fe-11f0-8e9f-1bafc66fbbc5',
746
- messageUrl:
747
- 'https://assistant-api-a.wbx2.com:443/assistant-api/api/v1/sessions/3c1939c0-92fe-11f0-8e9f-1bafc66fbbc5/messages/3c19fd10-92fe-11f0-8e9f-1bafc66fbbc5',
748
- responseId: '3c1a4b30-92fe-11f0-8e9f-1bafc66fbbc5',
749
- responseUrl:
750
- 'https://assistant-api-a.wbx2.com:443/assistant-api/api/v1/sessions/3c1939c0-92fe-11f0-8e9f-1bafc66fbbc5/messages/3c1a4b30-92fe-11f0-8e9f-1bafc66fbbc5',
751
- content: {
752
- name: 'cited_answer',
753
- type: 'json',
754
- encryptionKeyUrl: 'kms://kms-us.wbx2.com/keys/9565506d-78b1-4742-b0fd-63719748282e',
755
- value: {
756
- value:
757
- 'decrypted-with-kms://kms-us.wbx2.com/keys/9565506d-78b1-4742-b0fd-63719748282e-json_1_encrypted_value',
758
- type: 'markdown',
759
- citations: [
760
- {
761
- id: '6ccc8286e2084e05a6b9a29faae77095',
762
- index: 1,
763
- name: 'decrypted-with-kms://kms-us.wbx2.com/keys/9565506d-78b1-4742-b0fd-63719748282e-json_1_encrypted_citation_0',
764
- url: 'https://co.webex.com/webappng/sites/co/recording/playback/6ccc8286e2084e05a6b9a29faae77095',
765
- metadata: {
766
- provider: 'webex',
767
- type: 'meeting_recording',
768
- },
769
- },
770
- ],
771
- sources: [
772
- {
773
- id: '6ccc8286e2084e05a6b9a29faae77096',
774
- index: 1,
775
- type: 'post_meeting',
776
- name: 'decrypted-with-kms://kms-us.wbx2.com/keys/9565506d-78b1-4742-b0fd-63719748282e-json_1_encrypted_source_0',
777
- metadata: {
778
- meetingContainerId: 'mccc8286e2084e05a6b9a29faae77096',
779
- },
780
- },
781
- {
782
- id: '6ccc8286e2084e05a6b9a29faae77096',
783
- index: 2,
784
- type: 'post_call',
785
- name: 'decrypted-with-kms://kms-us.wbx2.com/keys/9565506d-78b1-4742-b0fd-63719748282e-json_1_encrypted_source_1',
786
- metadata: {
787
- callContainerId: 'mccc8286e2084e05a6b9a29faae77096',
788
- },
789
- },
790
- {
791
- id: '6ccc8286e2084e05a6b9a29faae77096',
792
- index: 3,
793
- type: 'message',
794
- name: 'decrypted-with-kms://kms-us.wbx2.com/keys/9565506d-78b1-4742-b0fd-63719748282e-json_1_encrypted_source_2',
795
- metadata: {
796
- spaceId: 'mccc8286e2084e05a6b9a29faae77096',
797
- },
798
- },
799
- ],
800
- },
801
- },
802
- createdAt: '2025-09-16T13:08:30.594220705Z',
803
- creator: {
804
- role: 'assistant',
805
- },
806
- // the below fields are added by the SDK
807
- errorCode: undefined,
808
- errorMessage: undefined,
809
- finished: true,
810
- requestId: 'test-request-id',
811
- responseType: 'response',
812
- };
813
-
814
- expect(triggerSpy.getCall(1).args[0]).to.deep.equal('aiassistant:stream:test-request-id');
815
- expect(triggerSpy.getCall(1).args[1]).to.deep.equal(expectedResult);
816
- });
817
-
818
652
  it('decrypts and emits data when receiving event data', async () => {
819
653
  const triggerSpy = sinon.spy(webex.internal.aiAssistant, 'trigger');
820
654
 
@@ -996,8 +830,7 @@ describe('plugin-ai-assistant', () => {
996
830
  id: 'test-message-id',
997
831
  url: 'https://assistant-api-a.wbx2.com:443/assistant-api/api/v1/sessions/test-session-id/messages/test-message-id',
998
832
  sessionId: 'test-session-id',
999
- sessionUrl:
1000
- 'https://assistant-api-a.wbx2.com:443/assistant-api/api/v1/sessions/test-session-id',
833
+ sessionUrl: 'https://assistant-api-a.wbx2.com:443/assistant-api/api/v1/sessions/test-session-id',
1001
834
  creatorId: 'test-creator-id',
1002
835
  createdAt: '2025-08-05T02:11:12.361Z',
1003
836
  },
@@ -1034,7 +867,7 @@ describe('plugin-ai-assistant', () => {
1034
867
  // Verify the request was made correctly
1035
868
  expect(webex.request.calledOnce).to.be.true;
1036
869
  const requestArgs = webex.request.getCall(0).args[0];
1037
-
870
+
1038
871
  expect(requestArgs.service).to.equal('assistant-api');
1039
872
  expect(requestArgs.resource).to.equal('sessions/test-session-id/messages');
1040
873
  expect(requestArgs.method).to.equal('POST');
@@ -1068,8 +901,7 @@ describe('plugin-ai-assistant', () => {
1068
901
  id: 'test-message-id',
1069
902
  url: 'https://assistant-api-a.wbx2.com:443/assistant-api/api/v1/sessions/test-session-id/messages/test-message-id',
1070
903
  sessionId: 'test-session-id',
1071
- sessionUrl:
1072
- 'https://assistant-api-a.wbx2.com:443/assistant-api/api/v1/sessions/test-session-id',
904
+ sessionUrl: 'https://assistant-api-a.wbx2.com:443/assistant-api/api/v1/sessions/test-session-id',
1073
905
  creatorId: 'test-creator-id',
1074
906
  createdAt: '2025-08-05T02:11:12.361Z',
1075
907
  requestId: 'custom-request-id',
@@ -1171,7 +1003,7 @@ describe('plugin-ai-assistant', () => {
1171
1003
  // Should use the UUID stub
1172
1004
  expect(result.requestId).to.equal('test-request-id');
1173
1005
  expect(result.streamEventName).to.equal('aiassistant:stream:test-request-id');
1174
-
1006
+
1175
1007
  const requestArgs = webex.request.getCall(0).args[0];
1176
1008
  expect(requestArgs.body.clientRequestId).to.equal('test-request-id');
1177
1009
  });
@@ -1222,24 +1054,6 @@ describe('plugin-ai-assistant', () => {
1222
1054
  expect(requestArgs.body.entryPoint).to.be.undefined;
1223
1055
  });
1224
1056
 
1225
- it('includes AI-Assistant-Render-Protocol in the request header when renderProtocolVersion is provided', async () => {
1226
- const options = {
1227
- sessionId: 'test-session-id',
1228
- encryptionKeyUrl: 'test-key-url',
1229
- contextResources: [],
1230
- contentType: 'action' as const,
1231
- contentValue: 'test_action',
1232
- renderProtocolVersion: '1.0',
1233
- };
1234
-
1235
- await webex.internal.aiAssistant.makeAiAssistantRequest(options);
1236
-
1237
- const requestArgs = webex.request.getCall(0).args[0];
1238
- expect(requestArgs.headers).to.deep.equal({
1239
- 'AI-Assistant-Render-Protocol': '1.0',
1240
- });
1241
- });
1242
-
1243
1057
  it('handles request rejection', async () => {
1244
1058
  webex.request.rejects(new Error('Network error'));
1245
1059
 
@@ -1251,9 +1065,9 @@ describe('plugin-ai-assistant', () => {
1251
1065
  contentValue: 'test_action',
1252
1066
  };
1253
1067
 
1254
- await expect(webex.internal.aiAssistant.makeAiAssistantRequest(options)).to.be.rejectedWith(
1255
- 'Network error'
1256
- );
1068
+ await expect(
1069
+ webex.internal.aiAssistant.makeAiAssistantRequest(options)
1070
+ ).to.be.rejectedWith('Network error');
1257
1071
  });
1258
1072
 
1259
1073
  it('starts timer when making a request', async () => {
@@ -1273,7 +1087,7 @@ describe('plugin-ai-assistant', () => {
1273
1087
 
1274
1088
  it('handles timeout when no streaming response comes back', async () => {
1275
1089
  const triggerSpy = sinon.spy(webex.internal.aiAssistant, 'trigger');
1276
-
1090
+
1277
1091
  const options = {
1278
1092
  sessionId: 'test-session-id',
1279
1093
  encryptionKeyUrl: 'test-key-url',
@@ -1291,13 +1105,10 @@ describe('plugin-ai-assistant', () => {
1291
1105
 
1292
1106
  // Should trigger timeout event on the stream
1293
1107
  expect(triggerSpy.calledWith('aiassistant:stream:test-request-id')).to.be.true;
1294
- const timeoutCall = triggerSpy
1295
- .getCalls()
1296
- .find(
1297
- (call) =>
1298
- call.args[0] === 'aiassistant:stream:test-request-id' &&
1299
- call.args[1].errorMessage === AI_ASSISTANT_ERRORS.AI_ASSISTANT_TIMEOUT
1300
- );
1108
+ const timeoutCall = triggerSpy.getCalls().find(call =>
1109
+ call.args[0] === 'aiassistant:stream:test-request-id' &&
1110
+ call.args[1].errorMessage === AI_ASSISTANT_ERRORS.AI_ASSISTANT_TIMEOUT
1111
+ );
1301
1112
  expect(timeoutCall).to.exist;
1302
1113
  expect(timeoutCall.args[1]).to.deep.include({
1303
1114
  requestId: 'test-request-id',
@@ -1310,7 +1121,7 @@ describe('plugin-ai-assistant', () => {
1310
1121
  it('resets timer when streaming responses are received', async () => {
1311
1122
  const timerResetSpy = sinon.spy(Timer.prototype, 'reset');
1312
1123
  const timerCancelSpy = sinon.spy(Timer.prototype, 'cancel');
1313
-
1124
+
1314
1125
  const options = {
1315
1126
  sessionId: 'test-session-id',
1316
1127
  encryptionKeyUrl: 'test-key-url',