@unboundcx/sdk 4.13.94 → 4.13.96

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/base.js CHANGED
@@ -16,17 +16,6 @@
16
16
  const requestBySdk = new WeakMap();
17
17
  const SDK_REQUEST = Symbol.for('unbound.sdk.request');
18
18
 
19
- /**
20
- * Safely read a process.env var. `process` is an undeclared global in a
21
- * browser/Vite bundle -- `process?.env?.X` does NOT protect against that
22
- * (optional chaining only guards property access, not a bare identifier
23
- * reference), so a browser bundle throws `ReferenceError: process is not
24
- * defined` the moment `process` is referenced at all. Gate on
25
- * `typeof process !== 'undefined'` first.
26
- */
27
- export const env = (key) =>
28
- typeof process !== 'undefined' && process.env ? process.env[key] : undefined;
29
-
30
19
  /**
31
20
  * Service-internal request. Not part of the public SDK surface.
32
21
  * Named SDK methods call this; app code must not. Optional transports
@@ -54,14 +43,14 @@ export class BaseSDK {
54
43
  // Support both object and legacy positional parameters for backwards compatibility
55
44
  if (typeof options === 'string') {
56
45
  // Legacy positional parameters: (namespace, callId, token, fwRequestId)
57
- this.namespace = options || env('namespace');
46
+ this.namespace = options || process?.env?.namespace;
58
47
  this.callId = arguments[1];
59
48
  this.token = arguments[2];
60
49
  this.fwRequestId = arguments[3];
61
50
  } else {
62
51
  // New object-based parameters
63
52
  const { namespace, callId, token, fwRequestId, baseURL } = options;
64
- this.namespace = namespace || env('namespace');
53
+ this.namespace = namespace || process?.env?.namespace;
65
54
  this.callId = callId;
66
55
  this.token = token;
67
56
  this.fwRequestId = fwRequestId;
@@ -89,7 +78,7 @@ export class BaseSDK {
89
78
  // Server-side (Node.js)
90
79
  this.environment = 'node';
91
80
  this.baseURL = this._constructorBaseURL || `https://${this.namespace ? this.namespace : 'login'}.${
92
- env('API_BASE_URL') || defaultDomain
81
+ process.env?.API_BASE_URL || defaultDomain
93
82
  }`;
94
83
  } else {
95
84
  // Client-side (browser)
@@ -102,7 +91,7 @@ export class BaseSDK {
102
91
  this.baseUrl = url.hostname.replace(/^[^.]+\./, '');
103
92
  } else {
104
93
  this.baseUrl =
105
- this.baseUrl || env('API_BASE_URL') || defaultDomain;
94
+ this.baseUrl || process?.env?.API_BASE_URL || defaultDomain;
106
95
  if (this.baseUrl && !this.baseUrl.startsWith('api.')) {
107
96
  this.baseUrl = `api.${this.baseUrl}`;
108
97
  }
@@ -122,23 +111,9 @@ export class BaseSDK {
122
111
  if (this.environment === 'node') {
123
112
  if (!this._constructorBaseURL) {
124
113
  this.baseURL = `https://${this.namespace ? this.namespace : 'login'}.${
125
- env('API_BASE_URL') || defaultDomain
114
+ process.env?.API_BASE_URL || defaultDomain
126
115
  }`;
127
116
  }
128
- } else if (this._constructorBaseURL && !this.namespace) {
129
- // Forms v2 P3 fix: a browser-environment instance constructed with
130
- // ONLY a literal baseURL (no namespace) -- e.g. sdk.forms.public /
131
- // sdk.webchat.visitor on a page that resolves its tenant server-side
132
- // from an opaque key, never a namespace subdomain -- must hit that
133
- // exact baseURL. Before this fix, this branch unconditionally built
134
- // `https://${namespace}.${baseUrl}` even when namespace was
135
- // undefined, producing a literal "https://undefined.<host>" request
136
- // URL (caught via forms-v2 marketing-site integration, P3). The
137
- // Node branch above already had the equivalent guard
138
- // (`if (!this._constructorBaseURL)`); this mirrors it for browser.
139
- // A namespace passed ALONGSIDE baseURL still prefixes it (unchanged,
140
- // existing behavior other callers rely on).
141
- this.fullUrl = this._constructorBaseURL;
142
117
  } else {
143
118
  this.fullUrl = `https://${this.namespace}.${this.baseUrl}`;
144
119
  }
@@ -307,9 +282,9 @@ export class BaseSDK {
307
282
  }
308
283
  } else {
309
284
  // No transport available, fallback to HTTP
310
- if (forceFetch && env('AUTH_V3_TOKEN_TYPE_OVERRIDE')) {
285
+ if (forceFetch && process.env.AUTH_V3_TOKEN_TYPE_OVERRIDE) {
311
286
  params.headers['x-token-type-override'] =
312
- env('AUTH_V3_TOKEN_TYPE_OVERRIDE');
287
+ process.env.AUTH_V3_TOKEN_TYPE_OVERRIDE;
313
288
  }
314
289
  return this._httpRequest(
315
290
  endpoint,
@@ -383,7 +358,7 @@ export class BaseSDK {
383
358
  returnRawResponse = false,
384
359
  startTime = Date.now(),
385
360
  ) {
386
- const { body, query, headers = {}, credentials } = params;
361
+ const { body, query, headers = {} } = params;
387
362
 
388
363
  const options = {
389
364
  method,
@@ -398,13 +373,9 @@ export class BaseSDK {
398
373
  },
399
374
  };
400
375
 
401
- // Set credentials for browser environment. Public/unauthenticated
402
- // endpoints called from third-party origins (forms, webchat loader) opt
403
- // out via params.credentials = 'omit' — app1-api's CORS only sends
404
- // access-control-allow-credentials for trusted app1 base domains, so a
405
- // browser rejects the response for `include` requests from other origins.
376
+ // Set credentials for browser environment
406
377
  if (this.environment === 'browser') {
407
- options.credentials = credentials === 'omit' ? 'omit' : 'include';
378
+ options.credentials = 'include';
408
379
  }
409
380
 
410
381
  let url;
package/index.js CHANGED
@@ -26,7 +26,6 @@ import { CobrowseService } from './services/cobrowse.js';
26
26
  import { MessageTemplatesService } from './services/messageTemplates.js';
27
27
  import { ExternalOAuthService } from './services/externalOAuth.js';
28
28
  import { GoogleCalendarService } from './services/googleCalendar.js';
29
- import { FormsService } from './services/forms.js';
30
29
  import { DriveService } from './services/drive.js';
31
30
  import { EnrollService } from './services/enroll.js';
32
31
  import { PhoneNumbersService } from './services/phoneNumbers.js';
@@ -126,7 +125,6 @@ class UnboundSDK extends BaseSDK {
126
125
  this.messageTemplates = new MessageTemplatesService(this);
127
126
  this.externalOAuth = new ExternalOAuthService(this);
128
127
  this.googleCalendar = new GoogleCalendarService(this);
129
- this.forms = new FormsService(this);
130
128
  this.drive = new DriveService(this);
131
129
  this.enroll = new EnrollService(this);
132
130
  this.phoneNumbers = new PhoneNumbersService(this);
@@ -328,9 +326,6 @@ export { MessageTemplatesService } from './services/messageTemplates.js';
328
326
  export { WebchatVisitorService } from './services/webchat/VisitorService.js';
329
327
  export { ExternalOAuthService } from './services/externalOAuth.js';
330
328
  export { GoogleCalendarService } from './services/googleCalendar.js';
331
- export { FormsService } from './services/forms.js';
332
- export { FormsPublicService } from './services/forms/PublicService.js';
333
- export { FormsHealthService } from './services/forms/HealthService.js';
334
329
  export { DriveService } from './services/drive.js';
335
330
  export { EnrollService } from './services/enroll.js';
336
331
  export {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unboundcx/sdk",
3
- "version": "4.13.94",
3
+ "version": "4.13.96",
4
4
  "description": "Official JavaScript SDK for the Unbound API - A comprehensive toolkit for integrating with Unbound's communication, AI, and data management services",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -52,9 +52,6 @@
52
52
  "import": "./index.js",
53
53
  "require": "./index.cjs"
54
54
  },
55
- "./base.js": {
56
- "import": "./base.js"
57
- },
58
55
  "./services/*": {
59
56
  "import": "./services/*.js"
60
57
  },
@@ -80,9 +80,9 @@ export class AssistService {
80
80
  * @example
81
81
  * const { suggestions } = await sdk.ai.assist.listSuggestions({ queueId: 'queue_123', limit: 50 });
82
82
  */
83
- async listSuggestions({ queueId, limit } = {}) {
83
+ async listSuggestions({ queueId, limit, actorKind } = {}) {
84
84
  const result = await internalRequest(this.sdk, '/ai/assist/suggestions', 'GET', {
85
- query: { queueId, limit },
85
+ query: { queueId, limit, actorKind },
86
86
  });
87
87
  return result;
88
88
  }
@@ -97,9 +97,9 @@ export class AssistService {
97
97
  * @example
98
98
  * const stats = await sdk.ai.assist.suggestionStats({ queueId: 'queue_123' });
99
99
  */
100
- async suggestionStats({ queueId } = {}) {
100
+ async suggestionStats({ queueId, actorKind } = {}) {
101
101
  const result = await internalRequest(this.sdk, '/ai/assist/suggestions/stats', 'GET', {
102
- query: { queueId },
102
+ query: { queueId, actorKind },
103
103
  });
104
104
  return result;
105
105
  }
package/services/ai.js CHANGED
@@ -964,14 +964,16 @@ export class SpeechToTextService {
964
964
  * @param {Object} message - Message data
965
965
  * @param {string} message.text - Transcribed text
966
966
  * @param {Object} [message.transcriptionJson] - Full transcription metadata
967
+ * @param {string} [message.transcriptionJson.source] - 'tts' for synthetic bot ingest
967
968
  * @param {number} [message.duration] - Duration of this segment in seconds
968
- * @param {number} [message.confidence] - Confidence score (0-1)
969
+ * @param {number} [message.confidence] - Confidence score (0-1). Omit for TTS.
969
970
  * @param {string} [message.languageCode] - Language code for this segment
970
971
  * @param {string} [message.userId] - User associated with this message
971
972
  * @param {string} [message.role] - Speaker role
972
973
  * @param {string} [message.sipCallId] - SIP call identifier
973
974
  * @param {string} [message.side] - Stream side ('send' or 'recv')
974
975
  * @param {string} [message.bridgeId] - bridge id
976
+ * @param {string} [message.taskId] - Task id (stamped on the transcription session)
975
977
  * @param {Object} [message.sentiment] - Sentiment analysis data
976
978
  * @param {number} [message.sentiment.score] - Overall sentiment score (-100 to +100)
977
979
  * @param {number} [message.sentiment.previousScore] - Previous sentiment score (-100 to +100)
@@ -999,13 +1001,14 @@ export class SpeechToTextService {
999
1001
  sipCallId,
1000
1002
  side,
1001
1003
  bridgeId,
1004
+ taskId,
1002
1005
  sentiment,
1003
1006
  videoRoomId,
1004
1007
  videoParticipantId,
1005
1008
  },
1006
1009
  ) {
1007
1010
  this.sdk.validateParams(
1008
- { messageId, sessionId, text, bridgeId },
1011
+ { messageId, sessionId, text, bridgeId, taskId },
1009
1012
  {
1010
1013
  sessionId: { type: 'string', required: true },
1011
1014
  messageId: { type: 'string', required: false },
@@ -1020,6 +1023,7 @@ export class SpeechToTextService {
1020
1023
  sipCallId: { type: 'string', required: false },
1021
1024
  side: { type: 'string', required: false },
1022
1025
  bridgeId: { type: 'string', required: false },
1026
+ taskId: { type: 'string', required: false },
1023
1027
  sentiment: { type: 'object', required: false },
1024
1028
  videoRoomId: { type: 'string', required: false },
1025
1029
  videoParticipantId: { type: 'string', required: false },
@@ -1040,6 +1044,7 @@ export class SpeechToTextService {
1040
1044
  sipCallId,
1041
1045
  side,
1042
1046
  bridgeId,
1047
+ taskId,
1043
1048
  sentiment,
1044
1049
  videoRoomId,
1045
1050
  videoParticipantId,
@@ -19,19 +19,19 @@ export class ReportingAgentsService {
19
19
 
20
20
  /**
21
21
  * Agent summary rows (§6 metrics), grouped by agent, queue, or team.
22
- * @param {Object} params - { from, to, userIds, queueIds, teamIds, groupBy }
22
+ * @param {Object} params - { from, to, userIds, queueIds, teamIds, groupBy, agentKind }
23
23
  * @returns {Promise<Object>} { columns, rows, definitions, meta }
24
24
  * @example
25
25
  * await sdk.reporting.agents.summary({ from, to, groupBy: 'team' });
26
26
  */
27
- async summary({ from, to, userIds, queueIds, teamIds, groupBy } = {}) {
27
+ async summary({ from, to, userIds, queueIds, teamIds, groupBy, agentKind } = {}) {
28
28
  this.sdk.validateParams(
29
29
  { from, to },
30
30
  { from: { type: 'string', required: true }, to: { type: 'string', required: true } },
31
31
  );
32
32
  return internalRequest(
33
33
  this.sdk,
34
- `/reporting/agents/summary${queryString({ from, to, userIds, queueIds, teamIds, groupBy })}`,
34
+ `/reporting/agents/summary${queryString({ from, to, userIds, queueIds, teamIds, groupBy, agentKind })}`,
35
35
  'GET',
36
36
  );
37
37
  }
@@ -90,19 +90,19 @@ export class ReportingAgentsService {
90
90
  /**
91
91
  * Per-agent per-local-day timesheet rows (net paid hours), plus one
92
92
  * additive-sum row per agent (`agents`) for grouped totals.
93
- * @param {Object} params - { from, to, userIds, teamIds }
93
+ * @param {Object} params - { from, to, userIds, teamIds, agentKind }
94
94
  * @returns {Promise<Object>} { columns, rows, agents }
95
95
  * @example
96
96
  * await sdk.reporting.agents.timesheet({ from, to, userIds: ['u1'] });
97
97
  */
98
- async timesheet({ from, to, userIds, teamIds } = {}) {
98
+ async timesheet({ from, to, userIds, teamIds, agentKind } = {}) {
99
99
  this.sdk.validateParams(
100
100
  { from, to },
101
101
  { from: { type: 'string', required: true }, to: { type: 'string', required: true } },
102
102
  );
103
103
  return internalRequest(
104
104
  this.sdk,
105
- `/reporting/agents/timesheet${queryString({ from, to, userIds, teamIds })}`,
105
+ `/reporting/agents/timesheet${queryString({ from, to, userIds, teamIds, agentKind })}`,
106
106
  'GET',
107
107
  );
108
108
  }
@@ -111,7 +111,7 @@ export class ReportingAgentsService {
111
111
  * CSV export of any of the four views above. For view: 'timesheet', pass
112
112
  * `totals: true` to get one additive-sum row per agent instead of the
113
113
  * flat per-agent-per-day rows.
114
- * @param {Object} params - { view: 'summary'|'states'|'interactions'|'timesheet', from, to, userId, userIds, queueIds, teamIds, groupBy, totals }
114
+ * @param {Object} params - { view: 'summary'|'states'|'interactions'|'timesheet', from, to, userId, userIds, queueIds, teamIds, groupBy, agentKind, totals }
115
115
  * @returns {Promise<Object>} raw CSV response (transport-dependent)
116
116
  * @example
117
117
  * await sdk.reporting.agents.export({ view: 'timesheet', from, to });
@@ -126,6 +126,7 @@ export class ReportingAgentsService {
126
126
  queueIds,
127
127
  teamIds,
128
128
  groupBy,
129
+ agentKind,
129
130
  totals,
130
131
  } = {}) {
131
132
  this.sdk.validateParams(
@@ -141,6 +142,7 @@ export class ReportingAgentsService {
141
142
  queueIds,
142
143
  teamIds,
143
144
  groupBy,
145
+ agentKind,
144
146
  totals: totals ? '1' : undefined,
145
147
  format: 'csv',
146
148
  });
@@ -1,4 +1,4 @@
1
- import { internalRequest, env } from '../base.js';
1
+ import { internalRequest } from '../base.js';
2
2
  export class StorageService {
3
3
  constructor(sdk) {
4
4
  this.sdk = sdk;
@@ -314,12 +314,13 @@ export class StorageService {
314
314
  headers = result.headers;
315
315
  }
316
316
 
317
- if (env('AUTH_V3_TOKEN_TYPE_OVERRIDE')) {
318
- headers['x-token-type-override'] = env('AUTH_V3_TOKEN_TYPE_OVERRIDE');
317
+ if (process?.env?.AUTH_V3_TOKEN_TYPE_OVERRIDE) {
318
+ headers['x-token-type-override'] =
319
+ process.env.AUTH_V3_TOKEN_TYPE_OVERRIDE;
319
320
  }
320
321
 
321
- if (skipClamscan && env('CLAMSCAN_OVERRIDE_KEY')) {
322
- headers['x-clamscan-override-key'] = env('CLAMSCAN_OVERRIDE_KEY');
322
+ if (skipClamscan && process?.env?.CLAMSCAN_OVERRIDE_KEY) {
323
+ headers['x-clamscan-override-key'] = process.env.CLAMSCAN_OVERRIDE_KEY;
323
324
  }
324
325
 
325
326
  const params = {
@@ -407,16 +408,16 @@ export class StorageService {
407
408
  }
408
409
 
409
410
  // Add environment variable override headers
410
- if (env('AUTH_V3_TOKEN_TYPE_OVERRIDE')) {
411
+ if (process?.env?.AUTH_V3_TOKEN_TYPE_OVERRIDE) {
411
412
  xhr.setRequestHeader(
412
413
  'x-token-type-override',
413
- env('AUTH_V3_TOKEN_TYPE_OVERRIDE'),
414
+ process.env.AUTH_V3_TOKEN_TYPE_OVERRIDE,
414
415
  );
415
416
  }
416
- if (skipClamscan && env('CLAMSCAN_OVERRIDE_KEY')) {
417
+ if (skipClamscan && process?.env?.CLAMSCAN_OVERRIDE_KEY) {
417
418
  xhr.setRequestHeader(
418
419
  'x-clamscan-override-key',
419
- env('CLAMSCAN_OVERRIDE_KEY'),
420
+ process.env.CLAMSCAN_OVERRIDE_KEY,
420
421
  );
421
422
  }
422
423
 
@@ -655,8 +656,8 @@ Response:
655
656
  if (metadata) formData.append('metadata', JSON.stringify(metadata));
656
657
  }
657
658
 
658
- if (_options?.skipScan && env('CLAMSCAN_OVERRIDE_KEY')) {
659
- headers['x-clamscan-override-key'] = env('CLAMSCAN_OVERRIDE_KEY');
659
+ if (_options?.skipScan && process?.env?.CLAMSCAN_OVERRIDE_KEY) {
660
+ headers['x-clamscan-override-key'] = process.env.CLAMSCAN_OVERRIDE_KEY;
660
661
  }
661
662
 
662
663
  const params = {
@@ -0,0 +1,242 @@
1
+ import { internalRequest } from '../../base.js';
2
+
3
+ /**
4
+ * CC worker bots — Setup → Bots (K21). Not Graham /chat/bots.
5
+ */
6
+ export class CcBotsService {
7
+ constructor(sdk) {
8
+ this.sdk = sdk;
9
+ }
10
+
11
+ /**
12
+ * Platform defaults for When to get help + model pickers.
13
+ * @returns {Promise<Object>}
14
+ */
15
+ async defaults() {
16
+ return internalRequest(this.sdk, '/taskRouter/ccBots/defaults', 'GET');
17
+ }
18
+
19
+ /**
20
+ * List CC worker bots for the account.
21
+ * @returns {Promise<Object>} { results }
22
+ */
23
+ async list() {
24
+ return internalRequest(this.sdk, '/taskRouter/ccBots', 'GET');
25
+ }
26
+
27
+ /**
28
+ * Create a named CC worker bot (user + worker, capacity 1).
29
+ * @param {Object} params
30
+ * @param {string} params.name
31
+ * @param {string} params.slug
32
+ * @param {string} [params.soulMd]
33
+ * @param {string} [params.provider]
34
+ * @param {string} [params.model]
35
+ * @param {string} [params.queueId]
36
+ * @param {string} [params.mailboxId]
37
+ * @returns {Promise<Object>}
38
+ */
39
+ async create({
40
+ name,
41
+ slug,
42
+ soulMd,
43
+ provider,
44
+ model,
45
+ queueId,
46
+ mailboxId,
47
+ } = {}) {
48
+ this.sdk.validateParams(
49
+ { name, slug },
50
+ {
51
+ name: { type: 'string', required: true },
52
+ slug: { type: 'string', required: true },
53
+ },
54
+ );
55
+ const body = { name, slug };
56
+ if (soulMd !== undefined) body.soulMd = soulMd;
57
+ if (provider !== undefined) body.provider = provider;
58
+ if (model !== undefined) body.model = model;
59
+ if (queueId !== undefined) body.queueId = queueId;
60
+ if (mailboxId !== undefined) body.mailboxId = mailboxId;
61
+ return internalRequest(this.sdk, '/taskRouter/ccBots', 'POST', { body });
62
+ }
63
+
64
+ /**
65
+ * Get one CC worker bot.
66
+ * @param {string} id
67
+ * @returns {Promise<Object>}
68
+ */
69
+ async get(id) {
70
+ this.sdk.validateParams({ id }, { id: { type: 'string', required: true } });
71
+ return internalRequest(this.sdk, `/taskRouter/ccBots/${id}`, 'GET');
72
+ }
73
+
74
+ /**
75
+ * Patch name / soul / model / pause kill-switch.
76
+ * @param {string} id
77
+ * @param {Object} [params]
78
+ * @returns {Promise<Object>}
79
+ */
80
+ async update(id, params = {}) {
81
+ this.sdk.validateParams({ id }, { id: { type: 'string', required: true } });
82
+ const body = {};
83
+ for (const key of [
84
+ 'name',
85
+ 'soulMd',
86
+ 'additionalDetails',
87
+ 'provider',
88
+ 'model',
89
+ 'mediaProvider',
90
+ 'mediaModel',
91
+ 'voiceId',
92
+ 'profilePhoto',
93
+ 'paused',
94
+ 'acceptChannels',
95
+ 'useChannels',
96
+ 'groupId',
97
+ 'groupOverrides',
98
+ 'inherit',
99
+ ]) {
100
+ if (key in params) body[key] = params[key];
101
+ }
102
+ return internalRequest(this.sdk, `/taskRouter/ccBots/${id}`, 'PATCH', {
103
+ body,
104
+ });
105
+ }
106
+
107
+ /**
108
+ * Clone a CC worker bot (new user + worker, copied config).
109
+ * @param {string} id
110
+ * @param {Object} [params]
111
+ * @param {string} [params.name]
112
+ * @returns {Promise<Object>}
113
+ */
114
+ async clone(id, { name } = {}) {
115
+ this.sdk.validateParams({ id }, { id: { type: 'string', required: true } });
116
+ const body = {};
117
+ if (name !== undefined) body.name = name;
118
+ return internalRequest(this.sdk, `/taskRouter/ccBots/${id}/clone`, 'POST', {
119
+ body,
120
+ });
121
+ }
122
+
123
+ /**
124
+ * Enable or disable many CC bots.
125
+ * @param {Object} params
126
+ * @param {string[]} params.ids
127
+ * @param {boolean} params.paused
128
+ * @returns {Promise<Object>}
129
+ */
130
+ async bulkPaused({ ids, paused } = {}) {
131
+ this.sdk.validateParams(
132
+ { ids, paused },
133
+ {
134
+ ids: { type: 'object', required: true },
135
+ paused: { type: 'boolean', required: true },
136
+ },
137
+ );
138
+ return internalRequest(this.sdk, '/taskRouter/ccBots/bulkPaused', 'POST', {
139
+ body: { ids, paused },
140
+ });
141
+ }
142
+
143
+ /**
144
+ * List bot groups.
145
+ * @returns {Promise<Object>}
146
+ */
147
+ async listGroups() {
148
+ return internalRequest(this.sdk, '/taskRouter/ccBotGroups', 'GET');
149
+ }
150
+
151
+ /**
152
+ * Create a bot group.
153
+ * @param {Object} params
154
+ * @returns {Promise<Object>}
155
+ */
156
+ async createGroup(params = {}) {
157
+ this.sdk.validateParams(
158
+ { name: params.name },
159
+ { name: { type: 'string', required: true } },
160
+ );
161
+ return internalRequest(this.sdk, '/taskRouter/ccBotGroups', 'POST', {
162
+ body: params,
163
+ });
164
+ }
165
+
166
+ /**
167
+ * Get one bot group.
168
+ * @param {string} id
169
+ * @returns {Promise<Object>}
170
+ */
171
+ async getGroup(id) {
172
+ this.sdk.validateParams({ id }, { id: { type: 'string', required: true } });
173
+ return internalRequest(this.sdk, `/taskRouter/ccBotGroups/${id}`, 'GET');
174
+ }
175
+
176
+ /**
177
+ * Patch a bot group (propagates inherited fields to member bots).
178
+ * @param {string} id
179
+ * @param {Object} [params]
180
+ * @returns {Promise<Object>}
181
+ */
182
+ async updateGroup(id, params = {}) {
183
+ this.sdk.validateParams({ id }, { id: { type: 'string', required: true } });
184
+ const body = {};
185
+ for (const key of [
186
+ 'name',
187
+ 'soulMd',
188
+ 'provider',
189
+ 'model',
190
+ 'mediaProvider',
191
+ 'mediaModel',
192
+ 'voiceId',
193
+ 'paused',
194
+ 'acceptChannels',
195
+ 'useChannels',
196
+ 'queueIds',
197
+ 'skillIds',
198
+ ]) {
199
+ if (key in params) body[key] = params[key];
200
+ }
201
+ return internalRequest(this.sdk, `/taskRouter/ccBotGroups/${id}`, 'PATCH', {
202
+ body,
203
+ });
204
+ }
205
+
206
+ /**
207
+ * Soft-delete a bot group and detach members.
208
+ * @param {string} id
209
+ * @returns {Promise<Object>}
210
+ */
211
+ async deleteGroup(id) {
212
+ this.sdk.validateParams({ id }, { id: { type: 'string', required: true } });
213
+ return internalRequest(
214
+ this.sdk,
215
+ `/taskRouter/ccBotGroups/${id}`,
216
+ 'DELETE',
217
+ );
218
+ }
219
+
220
+ /**
221
+ * Login a CC bot into a queue (queueUsers + worker addQueues).
222
+ * @param {string} id
223
+ * @param {Object} params
224
+ * @param {string} params.queueId
225
+ * @returns {Promise<Object>}
226
+ */
227
+ async addToQueue(id, { queueId } = {}) {
228
+ this.sdk.validateParams(
229
+ { id, queueId },
230
+ {
231
+ id: { type: 'string', required: true },
232
+ queueId: { type: 'string', required: true },
233
+ },
234
+ );
235
+ return internalRequest(
236
+ this.sdk,
237
+ `/taskRouter/ccBots/${id}/queues`,
238
+ 'POST',
239
+ { body: { queueId } },
240
+ );
241
+ }
242
+ }
@@ -170,15 +170,23 @@ export class ParticipantService {
170
170
  * @example
171
171
  * await sdk.taskRouter.participants.update({ taskId: 'task_123', participantId: 'tp_456', held: true });
172
172
  */
173
- async update({ taskId, participantId, held, muted, bridgeRole } = {}) {
173
+ async update({
174
+ taskId,
175
+ participantId,
176
+ held,
177
+ muted,
178
+ bridgeRole,
179
+ joinAudio,
180
+ } = {}) {
174
181
  this.sdk.validateParams(
175
- { taskId, participantId, held, muted, bridgeRole },
182
+ { taskId, participantId, held, muted, bridgeRole, joinAudio },
176
183
  {
177
184
  taskId: { type: 'string', required: true },
178
185
  participantId: { type: 'string', required: true },
179
186
  held: { type: 'boolean', required: false },
180
187
  muted: { type: 'boolean', required: false },
181
188
  bridgeRole: { type: 'string', required: false },
189
+ joinAudio: { type: 'boolean', required: false },
182
190
  },
183
191
  );
184
192
 
@@ -186,6 +194,7 @@ export class ParticipantService {
186
194
  if (held !== undefined) params.body.held = held;
187
195
  if (muted !== undefined) params.body.muted = muted;
188
196
  if (bridgeRole !== undefined) params.body.bridgeRole = bridgeRole;
197
+ if (joinAudio !== undefined) params.body.joinAudio = joinAudio;
189
198
 
190
199
  return await internalRequest(
191
200
  this.sdk,
@@ -4,6 +4,7 @@ import { MetricsService } from './MetricsService.js';
4
4
  import { CCService } from './CCService.js';
5
5
  import { OfferService } from './OfferService.js';
6
6
  import { ParticipantService } from './ParticipantService.js';
7
+ import { CcBotsService } from './CcBotsService.js';
7
8
 
8
9
  export class TaskRouterService {
9
10
  constructor(sdk) {
@@ -14,5 +15,6 @@ export class TaskRouterService {
14
15
  this.cc = new CCService(sdk);
15
16
  this.offer = new OfferService(sdk);
16
17
  this.participants = new ParticipantService(sdk);
18
+ this.ccBots = new CcBotsService(sdk);
17
19
  }
18
20
  }