@stack-spot/portal-network 0.192.1 → 0.193.0-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.
Files changed (68) hide show
  1. package/CHANGELOG.md +170 -0
  2. package/dist/api/account.d.ts +4 -116
  3. package/dist/api/account.d.ts.map +1 -1
  4. package/dist/api/account.js +9 -95
  5. package/dist/api/account.js.map +1 -1
  6. package/dist/api/ai.d.ts +189 -86
  7. package/dist/api/ai.d.ts.map +1 -1
  8. package/dist/api/ai.js +238 -142
  9. package/dist/api/ai.js.map +1 -1
  10. package/dist/api/cloudPlatform.d.ts +73 -126
  11. package/dist/api/cloudPlatform.d.ts.map +1 -1
  12. package/dist/api/cloudPlatform.js +82 -66
  13. package/dist/api/cloudPlatform.js.map +1 -1
  14. package/dist/api/codeShift.d.ts +171 -40
  15. package/dist/api/codeShift.d.ts.map +1 -1
  16. package/dist/api/codeShift.js +80 -10
  17. package/dist/api/codeShift.js.map +1 -1
  18. package/dist/api/discover.d.ts +23 -12
  19. package/dist/api/discover.d.ts.map +1 -1
  20. package/dist/api/discover.js +10 -0
  21. package/dist/api/discover.js.map +1 -1
  22. package/dist/client/account.d.ts +4 -0
  23. package/dist/client/account.d.ts.map +1 -1
  24. package/dist/client/account.js +10 -1
  25. package/dist/client/account.js.map +1 -1
  26. package/dist/client/ai.d.ts +46 -0
  27. package/dist/client/ai.d.ts.map +1 -1
  28. package/dist/client/ai.js +140 -15
  29. package/dist/client/ai.js.map +1 -1
  30. package/dist/client/cloud-platform.d.ts +155 -51
  31. package/dist/client/cloud-platform.d.ts.map +1 -1
  32. package/dist/client/cloud-platform.js +146 -47
  33. package/dist/client/cloud-platform.js.map +1 -1
  34. package/dist/client/code-shift.d.ts +53 -3
  35. package/dist/client/code-shift.d.ts.map +1 -1
  36. package/dist/client/code-shift.js +55 -1
  37. package/dist/client/code-shift.js.map +1 -1
  38. package/dist/client/discover.d.ts +7 -1
  39. package/dist/client/discover.d.ts.map +1 -1
  40. package/dist/client/discover.js +208 -0
  41. package/dist/client/discover.js.map +1 -1
  42. package/dist/client/types.d.ts +39 -5
  43. package/dist/client/types.d.ts.map +1 -1
  44. package/dist/error/dictionary/cloud-platform.d.ts +6 -0
  45. package/dist/error/dictionary/cloud-platform.d.ts.map +1 -1
  46. package/dist/error/dictionary/cloud-platform.js +6 -0
  47. package/dist/error/dictionary/cloud-platform.js.map +1 -1
  48. package/dist/utils/StreamedJson.d.ts.map +1 -1
  49. package/dist/utils/StreamedJson.js +9 -1
  50. package/dist/utils/StreamedJson.js.map +1 -1
  51. package/package.json +2 -2
  52. package/readme.md +2 -1
  53. package/src/api/account.ts +21 -192
  54. package/src/api/agent-tools.ts +3 -0
  55. package/src/api/agent.ts +2 -0
  56. package/src/api/ai.ts +364 -157
  57. package/src/api/cloudPlatform.ts +147 -204
  58. package/src/api/codeShift.ts +284 -45
  59. package/src/api/discover.ts +35 -12
  60. package/src/api/notification.ts +2 -0
  61. package/src/client/account.ts +5 -0
  62. package/src/client/ai.ts +136 -13
  63. package/src/client/cloud-platform.ts +84 -29
  64. package/src/client/code-shift.ts +30 -1
  65. package/src/client/discover.ts +220 -3
  66. package/src/client/types.ts +43 -7
  67. package/src/error/dictionary/cloud-platform.ts +6 -0
  68. package/src/utils/StreamedJson.tsx +9 -2
package/src/client/ai.ts CHANGED
@@ -38,6 +38,8 @@ import {
38
38
  resetKnowledgeObjectsV1KnowledgeSourcesSlugObjectsDelete,
39
39
  runFetchStepV1QuickCommandsSlugStepsStepSlugFetchRunPost,
40
40
  searchKnowledgeSourcesV1KnowledgeSourcesSearchPost,
41
+ tokensByUserV1AnalyticsTokensByUserGet,
42
+ tokensDailyUsageV1AnalyticsTokensDailyUsageGet,
41
43
  updateQuickCommandV1QuickCommandsSlugPatch,
42
44
  updateTitleV1ConversationsConversationIdPatch,
43
45
  vectorizeCustomKnowledgeSourceV1KnowledgeSourcesSlugCustomPost,
@@ -257,6 +259,14 @@ class AIClient extends ReactQueryNetworkClient {
257
259
  * Removes the resource of type Quick Command from the list of favorites.
258
260
  */
259
261
  removeFavoriteQuickCommand = this.mutation(removeAuthorizationParam(deleteFavoriteV1QuickCommandsSlugFavoriteDelete))
262
+ /**
263
+ * Get Tokens Daily usage
264
+ */
265
+ analyticsTokensDailyUsage = this.query(removeAuthorizationParam(tokensDailyUsageV1AnalyticsTokensDailyUsageGet))
266
+ /**
267
+ * Get Tokens By User
268
+ */
269
+ analyticsTokensByUser = this.query(tokensByUserV1AnalyticsTokensByUserGet)
260
270
 
261
271
  private static async toolsOfAgent(agentId?: string) {
262
272
  try {
@@ -266,6 +276,9 @@ class AIClient extends ReactQueryNetworkClient {
266
276
  agent.toolkits?.builtin_toolkits?.forEach(kit => kit.tools?.forEach(({ id, name, description }) => {
267
277
  if (id) tools.push({ image: kit.image_url, id, name: name || id, description })
268
278
  }))
279
+ agent.toolkits?.custom_toolkits?.forEach(kit => kit.tools?.forEach(({ id, name, description }) => {
280
+ if (id) tools.push({ image: kit.avatar ?? undefined, id, name: name || id, description })
281
+ }))
269
282
  return tools
270
283
  } catch {
271
284
  return []
@@ -290,7 +303,9 @@ class AIClient extends ReactQueryNetworkClient {
290
303
  */
291
304
  async function transform(event: Partial<FixedChatResponse>, data: Partial<ChatResponseWithSteps>) {
292
305
  const info = event.agent_info
306
+
293
307
  if (!info) return
308
+
294
309
  const tools = await AIClient.toolsOfAgent(request.context?.agent_id)
295
310
  data.steps = data.steps ? [...data.steps] : []
296
311
 
@@ -303,6 +318,59 @@ class AIClient extends ReactQueryNetworkClient {
303
318
  steps: info.data?.steps?.map(s => s.goal) ?? [],
304
319
  goal: info.data?.plan_goal ?? '',
305
320
  })
321
+
322
+ info.data?.steps.forEach(s => data.steps?.push({
323
+ id: s.id,
324
+ type: 'step',
325
+ status: 'pending',
326
+ input: s.goal,
327
+ attempts: [{
328
+ tools: s.tools?.map(t => ({
329
+ ...(tools.find(({ id }) => id === t.tool_id) ?? { id: t.tool_id, name: t.tool_id }),
330
+ executionId: t.tool_execution_id,
331
+ goal: t.goal,
332
+ })),
333
+ }],
334
+ }))
335
+ data.steps.push({ id: 'answer', type: 'answer', status: 'pending' })
336
+ }
337
+
338
+ if (info.type === 'planning' && info.action === 'awaiting_approval') {
339
+ data.steps.push({
340
+ id: 'planning',
341
+ type: 'planning',
342
+ status: 'awaiting_approval',
343
+ user_question: info.data?.user_question,
344
+ duration: info.duration || 0,
345
+ steps: info.data?.steps?.map(s => s.goal) ?? [],
346
+ goal: info.data?.plan_goal ?? '',
347
+ })
348
+ info.data?.steps.forEach(s => data.steps?.push({
349
+ id: s.id,
350
+ type: 'step',
351
+ status: 'pending',
352
+ input: s.goal,
353
+ attempts: [{
354
+ tools: s.tools?.map(t => ({
355
+ ...(tools.find(({ id }) => id === t.tool_id) ?? { id: t.tool_id, name: t.tool_id }),
356
+ executionId: t.tool_execution_id,
357
+ goal: t.goal,
358
+ })),
359
+ }],
360
+ }))
361
+ data.steps.push({ id: 'answer', type: 'answer', status: 'pending' })
362
+ }
363
+
364
+ if (info.type === 'planning' && info.action === 'awaiting_approval') {
365
+ data.steps.push({
366
+ id: 'planning',
367
+ type: 'planning',
368
+ status: 'awaiting_approval',
369
+ user_question: info.data?.user_question,
370
+ duration: info.duration || 0,
371
+ steps: info.data?.steps?.map(s => s.goal) ?? [],
372
+ goal: info.data?.plan_goal ?? '',
373
+ })
306
374
  info.data?.steps.forEach(s => data.steps?.push({
307
375
  id: s.id,
308
376
  type: 'step',
@@ -312,6 +380,7 @@ class AIClient extends ReactQueryNetworkClient {
312
380
  tools: s.tools?.map(t => ({
313
381
  ...(tools.find(({ id }) => id === t.tool_id) ?? { id: t.tool_id, name: t.tool_id }),
314
382
  executionId: t.tool_execution_id,
383
+ goal: t.goal,
315
384
  })),
316
385
  }],
317
386
  }))
@@ -334,27 +403,80 @@ class AIClient extends ReactQueryNetworkClient {
334
403
  }
335
404
  }
336
405
 
406
+ if (info.type === 'tool' && info.action === 'awaiting_approval') {
407
+ const tool = tools.find(({ id }) => id === info.data?.tool_id)
408
+ data.steps.push({
409
+ id: info.id,
410
+ type: 'tool',
411
+ status: 'awaiting_approval',
412
+ duration: info.duration || 0,
413
+ input: info.data?.input,
414
+ user_question: info.data?.user_question,
415
+ attempts: [{
416
+ tools: [{
417
+ executionId: info.id,
418
+ id: info.data?.tool_id ?? '',
419
+ name: tool?.name ?? '',
420
+ goal: tool?.goal,
421
+ ...tool,
422
+ }],
423
+ }],
424
+ })
425
+ data.steps.push({ id: 'answer', type: 'answer', status: 'pending' })
426
+ }
427
+
337
428
  if (info.type === 'tool' && info.action === 'start') {
338
429
  const currentStep = data.steps.find(s => s.status === 'running') as StepChatStep
339
- if (!currentStep || !info.data || !currentStep.attempts[0].tools) return
340
- const toolInFirstAttempt = currentStep.attempts[0].tools.find(t => t.executionId === info.id)
341
- if (!toolInFirstAttempt) return
342
- const input = formatJson(info.data.input)
343
- if (info.data.attempt === 0) {
344
- toolInFirstAttempt.input = input
345
- } else {
346
- currentStep.attempts[info.data.attempt] ??= { tools: [] }
347
- currentStep.attempts[info.data.attempt].tools?.push({
348
- ...toolInFirstAttempt,
349
- input,
430
+ if (!info.data) return
431
+
432
+ //There might be a tool with status awaiting_approval, so we want to inform tool has already started
433
+ if (!currentStep || !currentStep.attempts[0].tools) {
434
+ const input = formatJson(info.data.input)
435
+ const tool = tools.find(({ id }) => id === info.data?.tool_id) ?? { id: info.data?.tool_id, name: info.data?.tool_id }
436
+ data.steps.push({
437
+ id: info.id,
438
+ type: 'tool',
439
+ status: 'running',
440
+ duration: info.duration || 0,
441
+ input: info.data?.input,
442
+ user_question: info.data?.user_question,
443
+ attempts: [{
444
+ tools:[{ ...tool, executionId: info.id, input }],
445
+ }],
350
446
  })
447
+ } else {
448
+ const toolInFirstAttempt = currentStep.attempts[0].tools?.find(t => t.executionId === info.id)
449
+ //One step might have multiple tools. When in an approval mode, we might not have all the tools in the array yet.
450
+ //So we make sure to add any tools that are not in there.
451
+ if (!toolInFirstAttempt) {
452
+ const input = formatJson(info.data.input)
453
+ const tool = tools?.find(({ id }) => id === info.data?.tool_id) ?? { id: info.data?.tool_id, name: info.data?.tool_id }
454
+ currentStep.attempts[info.data.attempt-1].tools?.push({
455
+ ...tool,
456
+ executionId: info.id,
457
+ input,
458
+ })
459
+ } else {
460
+ const input = formatJson(info.data.input)
461
+ if (info.data.attempt === 1) {
462
+ toolInFirstAttempt.input = input
463
+ } else {
464
+ const tool = tools.find(({ id }) => id === info.data?.tool_id) ?? { id: info.data?.tool_id, name: info.data?.tool_id }
465
+ currentStep.attempts[info.data.attempt-1] ??= { tools: [] }
466
+ currentStep.attempts[info.data.attempt-1].tools?.push({
467
+ ...tool,
468
+ executionId: info.id,
469
+ input,
470
+ })
471
+ }
472
+ }
351
473
  }
352
474
  }
353
475
 
354
476
  if (info.type === 'tool' && info.action === 'end') {
355
477
  const currentStep = data.steps.find(s => s.status === 'running') as StepChatStep
356
478
  if (!currentStep || !info.data) return
357
- const tool = currentStep.attempts[info.data.attempt]?.tools?.find(t => t.executionId === info.id)
479
+ const tool = currentStep.attempts[info.data.attempt-1]?.tools?.find(t => t.executionId === info.id)
358
480
  if (tool) {
359
481
  tool.output = formatJson(info.data.output)
360
482
  tool.duration = info.duration
@@ -366,7 +488,7 @@ class AIClient extends ReactQueryNetworkClient {
366
488
  if (answerStep) answerStep.status = 'running'
367
489
  }
368
490
 
369
- if (info.type === 'final_answer' && info.action === 'end') {
491
+ if (info.type === 'chat' && info.action === 'end') {
370
492
  const answerStep = last(data.steps)
371
493
  if (answerStep) {
372
494
  answerStep.status = 'success'
@@ -393,3 +515,4 @@ class AIClient extends ReactQueryNetworkClient {
393
515
  }
394
516
 
395
517
  export const aiClient = new AIClient()
518
+
@@ -1,22 +1,28 @@
1
1
  import { HttpError } from '@oazapfts/runtime'
2
2
  import {
3
- acceptNetworkConnection,
4
3
  createCertificate,
5
4
  createCidr,
6
5
  createDnsRecord,
7
6
  createDnsZone,
8
7
  createFolder,
9
8
  createFoundation,
10
- createInbound,
11
9
  createNetwork,
12
- createNetworkConnection,
13
10
  createProject,
14
11
  createRuntime,
15
12
  createTenant,
16
13
  createVpn,
17
14
  defaults,
15
+ deleteCertificate,
16
+ deleteCidr,
17
+ deleteDnsRecord,
18
+ deleteDnsZone,
19
+ deleteFolder,
20
+ deleteNetwork,
21
+ deleteProject,
22
+ deleteVpn,
18
23
  getCertificate,
19
24
  getFolder,
25
+ getFolderTags,
20
26
  getFoundation,
21
27
  getNetwork,
22
28
  getProject,
@@ -26,13 +32,18 @@ import {
26
32
  listDnsRecord,
27
33
  listDnsZone,
28
34
  listFoundations,
29
- listInbound,
30
35
  listNetwork,
31
- listNetworkConnection,
32
36
  listRuntime,
33
37
  listTenant,
34
38
  listVpns,
35
39
  providers,
40
+ putCertificateTags,
41
+ putCidrTags,
42
+ putDnsZoneTags,
43
+ putFolderTags,
44
+ putNetworkTags,
45
+ putProjectTags,
46
+ putVpnTags,
36
47
  } from '../api/cloudPlatform'
37
48
  import { DefaultAPIError } from '../error/DefaultAPIError'
38
49
  import { StackspotAPIError } from '../error/StackspotAPIError'
@@ -125,26 +136,6 @@ class CloudPlatformClient extends ReactQueryNetworkClient {
125
136
  * Create a network
126
137
  */
127
138
  createNetwork = this.mutation(removeAuthorizationParam(createNetwork))
128
- /**
129
- * Get a list of inbounds
130
- */
131
- listInbounds = this.query(removeAuthorizationParam(listInbound))
132
- /**
133
- * Create a inbound
134
- */
135
- createInbound = this.mutation(removeAuthorizationParam(createInbound))
136
- /**
137
- * Add a network connection
138
- */
139
- addNetworkConnection = this.mutation(removeAuthorizationParam(createNetworkConnection))
140
- /**
141
- * Get a network connection request
142
- */
143
- getNetworkConnections = this.query(removeAuthorizationParam(listNetworkConnection))
144
- /**
145
- * Accept a network connection
146
- */
147
- acceptNetworkConnection = this.mutation(removeAuthorizationParam(acceptNetworkConnection))
148
139
  /**
149
140
  * Get a list of vpn's
150
141
  */
@@ -170,13 +161,77 @@ class CloudPlatformClient extends ReactQueryNetworkClient {
170
161
  */
171
162
  createTenant = this.mutation(removeAuthorizationParam(createTenant))
172
163
  /**
173
- * Get a list of runtimes
174
- */
164
+ * Get a list of runtimes
165
+ */
175
166
  listRuntimes = this.query(removeAuthorizationParam(listRuntime))
176
167
  /**
177
- * Create a runtime
178
- */
168
+ * Create a runtime
169
+ */
179
170
  createRuntime = this.mutation(removeAuthorizationParam(createRuntime))
171
+ /**
172
+ * Get a list of tags in folder
173
+ */
174
+ getFolderTags = this.query(removeAuthorizationParam(getFolderTags))
175
+ /**
176
+ * Update folder tags
177
+ */
178
+ updateFolderTags = this.mutation(removeAuthorizationParam(putFolderTags))
179
+ /**
180
+ * Update project tags
181
+ */
182
+ updateProjectTags = this.mutation(removeAuthorizationParam(putProjectTags))
183
+ /**
184
+ * Update network tags
185
+ */
186
+ updateNetworkTags = this.mutation(removeAuthorizationParam(putNetworkTags))
187
+ /**
188
+ * Update cidr tags
189
+ */
190
+ updateCidrTags = this.mutation(removeAuthorizationParam(putCidrTags))
191
+ /**
192
+ * Update dns zone tags
193
+ */
194
+ updateDnsZoneTags = this.mutation(removeAuthorizationParam(putDnsZoneTags))
195
+ /**
196
+ * Update certificate tags
197
+ */
198
+ updateCertificateTags = this.mutation(removeAuthorizationParam(putCertificateTags))
199
+ /**
200
+ * Update vpn tags
201
+ */
202
+ updateVpnTags = this.mutation(removeAuthorizationParam(putVpnTags))
203
+ /**
204
+ * Delete a folder
205
+ */
206
+ deleteFolder = this.mutation(removeAuthorizationParam(deleteFolder))
207
+ /**
208
+ * Delete a project
209
+ */
210
+ deleteProject = this.mutation(removeAuthorizationParam(deleteProject))
211
+ /**
212
+ * Delete a network
213
+ */
214
+ deleteNetwork = this.mutation(removeAuthorizationParam(deleteNetwork))
215
+ /**
216
+ * Delete a certificate
217
+ */
218
+ deleteCertificate = this.mutation(removeAuthorizationParam(deleteCertificate))
219
+ /**
220
+ * Delete a dns zone
221
+ */
222
+ deleteDnsZone = this.mutation(removeAuthorizationParam(deleteDnsZone))
223
+ /**
224
+ * Delete a dns record
225
+ */
226
+ deleteDnsRecord = this.mutation(removeAuthorizationParam(deleteDnsRecord))
227
+ /**
228
+ * Delete a VPN
229
+ */
230
+ deleteVPN = this.mutation(removeAuthorizationParam(deleteVpn))
231
+ /**
232
+ * Delete a CIDR
233
+ */
234
+ deleteCidr = this.mutation(removeAuthorizationParam(deleteCidr))
180
235
  }
181
236
 
182
237
  export const cloudPlatformClient = new CloudPlatformClient()
@@ -58,14 +58,19 @@ import {
58
58
  getModuleV1ModulesModuleIdGet,
59
59
  analyticsProgramGroupsTargetDetailsV1AnalyticsProgramGroupsTargetDetailsGet,
60
60
  analyticsProgramGroupsTargetDetailsDownloadV1AnalyticsProgramGroupsTargetDetailsDownloadGet,
61
+ putCustomerRatingReportV1ReportsReportIdCustomerRatingPut,
61
62
  searchReposScmServiceV2ReposSearchScmPost,
62
63
  importReposWithTagsScmServiceV2ReposSearchScmSearchIdPost,
63
64
  searchReposScmV2V2ReposSearchScmSearchIdGet,
64
65
  analyticsRepositoryTargetDetailsV1AnalyticsRepositoriesTargetDetailsGet,
65
66
  analyticsRepositoryTargetDetailsDownloadV1AnalyticsRepositoriesTargetDetailsDownloadGet,
66
- putCustomerRatingReportV1ReportsReportIdCustomerRatingPut,
67
67
  updateModuleServiceV1ModulesModuleIdPut,
68
68
  downloadSearchReposScmV2V2ReposSearchScmSearchIdDownloadGet,
69
+ moduleFavoriteServiceAddV1ModulesModuleIdFavoritesPost,
70
+ moduleFavoriteServiceDeleteV1ModulesModuleIdFavoritesDelete,
71
+ patHealthCheckV1ScmPatHealthCheckGet,
72
+ createReposBatchServiceV2ReposBatchPost,
73
+ getImportResultV2ReposBatchImportIdGet,
69
74
  } from '../api/codeShift'
70
75
  import { DefaultAPIError } from '../error/DefaultAPIError'
71
76
  import { codeShiftDictionary } from '../error/dictionary/code-shift'
@@ -91,6 +96,14 @@ class CodeShift extends ReactQueryNetworkClient {
91
96
  * Creates repositories in batch.
92
97
  */
93
98
  createRepositoriesBatch = this.mutation(removeAuthorizationParam(createReposBatchServiceV1ReposBatchPost))
99
+ /**
100
+ * Imports repositories in batch.
101
+ */
102
+ createRepositoriesBatchV2 = this.mutation(removeAuthorizationParam(createReposBatchServiceV2ReposBatchPost))
103
+ /**
104
+ * Gets the status of a batch import.
105
+ */
106
+ getImportBatchResultsV2 = this.query(removeAuthorizationParam(getImportResultV2ReposBatchImportIdGet))
94
107
  /**
95
108
  * Gets list of repositories.
96
109
  */
@@ -123,6 +136,14 @@ class CodeShift extends ReactQueryNetworkClient {
123
136
  * Gets module by id.
124
137
  */
125
138
  module = this.query(removeAuthorizationParam(getModuleV1ModulesModuleIdGet))
139
+ /**
140
+ * Add a module in favorites.
141
+ */
142
+ addFavoriteModule = this.mutation(removeAuthorizationParam(moduleFavoriteServiceAddV1ModulesModuleIdFavoritesPost))
143
+ /**
144
+ * Remove a module from favorites.
145
+ */
146
+ removeFavoriteModule = this.mutation(removeAuthorizationParam(moduleFavoriteServiceDeleteV1ModulesModuleIdFavoritesDelete))
126
147
  /**
127
148
  * Gets module inputs.
128
149
  */
@@ -135,6 +156,10 @@ class CodeShift extends ReactQueryNetworkClient {
135
156
  * Updates a module.
136
157
  */
137
158
  updateModule = this.mutation(removeAuthorizationParam(updateModuleServiceV1ModulesModuleIdPut))
159
+ /**
160
+ * Adds a module to favorites.
161
+ */
162
+ addModuleToFavorites = this.mutation(removeAuthorizationParam(moduleFavoriteServiceAddV1ModulesModuleIdFavoritesPost))
138
163
  /**
139
164
  * Generates a report.
140
165
  */
@@ -263,6 +288,10 @@ class CodeShift extends ReactQueryNetworkClient {
263
288
  * Validates a SCM URL.
264
289
  */
265
290
  validateSCMUrl = this.mutation(removeAuthorizationParam(validateScmUrlServiceV1ReposValidateScmUrlPost))
291
+ /**
292
+ * PAT Health Check
293
+ */
294
+ checkScmPatHealth = this.query(removeAuthorizationParam(patHealthCheckV1ScmPatHealthCheckGet))
266
295
  /**
267
296
  * Get Branches for a Repository
268
297
  */
@@ -1,12 +1,17 @@
1
1
  import { HttpError } from '@oazapfts/runtime'
2
+ import { findLast, last } from 'lodash'
2
3
  import { getApiAddresses } from '../api-addresses'
3
4
  import { ConversationResponse } from '../api/ai'
4
- import { create, create1, create2, defaults, deleteById, deleteById1, deleteById2, getAll, getAll1, getAll2, getAllByHypothesis, getById, getById1, getById2, GetOpportunityResponse } from '../api/discover'
5
+ import { create, create1, create2, defaults, deleteById, deleteById1, deleteById2, getAll, getAll1, getAll2, getAllByHypothesis, getById, getById1, getById2, GetOpportunityResponse, MessageRequest } from '../api/discover'
5
6
  import { DefaultAPIError } from '../error/DefaultAPIError'
6
7
  import { StackspotAPIError } from '../error/StackspotAPIError'
8
+ import { StreamedJson } from '../utils/StreamedJson'
7
9
  import { baseDictionary } from '../error/dictionary/base'
10
+ import { formatJson } from '../utils/string'
8
11
  import { ReactQueryNetworkClient } from '../network/ReactQueryNetworkClient'
9
12
  import { aiClient } from './ai'
13
+ import { ChatAgentTool, ChatResponseWithSteps, FixedChatResponse, StepChatStep } from './types'
14
+ import { agentToolsClient } from './agent-tools'
10
15
 
11
16
  export interface ChatConversionDetails extends ConversationResponse {
12
17
  opportunityName?: string,
@@ -67,8 +72,8 @@ class DiscoverClient extends ReactQueryNetworkClient {
67
72
  { ...variables, page: variables.page, size: variables.size ?? 40 },
68
73
  )
69
74
 
70
- const filteredItems = variables.filter
71
- ? chatsHistory.filter((chat) => chat.title.toLowerCase().includes(variables.filter!.toLowerCase()))
75
+ const filteredItems = variables.filter
76
+ ? chatsHistory.filter((chat) => chat.title.toLowerCase().includes(variables.filter!.toLowerCase()))
72
77
  : chatsHistory
73
78
 
74
79
  const enrichedChats = filteredItems?.map(chat => {
@@ -84,6 +89,218 @@ class DiscoverClient extends ReactQueryNetworkClient {
84
89
  return enrichedChats as ChatConversionDetails[]
85
90
  },
86
91
  })
92
+
93
+ private static async toolsOfAgent(agentId?: string) {
94
+ try {
95
+ const agent = agentId ? await agentToolsClient.agent.query({ agentId }) : undefined
96
+ if (!agent) return []
97
+ const tools: (Omit<ChatAgentTool, 'duration' | 'prompt' | 'output'>)[] = []
98
+ agent.toolkits?.builtin_toolkits?.forEach(kit => kit.tools?.forEach(({ id, name, description }) => {
99
+ if (id) tools.push({ image: kit.image_url, id, name: name || id, description })
100
+ }))
101
+ agent.toolkits?.custom_toolkits?.forEach(kit => kit.tools?.forEach(({ id, name, description }) => {
102
+ if (id) tools.push({ image: kit.avatar ?? undefined, id, name: name || id, description })
103
+ }))
104
+ return tools
105
+ } catch {
106
+ return []
107
+ }
108
+ }
109
+
110
+
111
+ sendChatMessage(request: MessageRequest & { agentId: string }, minChangeIntervalMS?: number): StreamedJson<ChatResponseWithSteps> {
112
+ const abortController = new AbortController()
113
+ const headers = {
114
+ 'Content-Type': 'application/json',
115
+ 'Accept': 'text/event-stream',
116
+ }
117
+ const events = this.stream(
118
+ this.resolveURL('/v2/ai/chat'),
119
+ { method: 'post', body: JSON.stringify(request), headers, signal: abortController.signal },
120
+ )
121
+ /**
122
+ * This function treats events in the streaming that deals with the execution of tools. Since these events are not concatenated like
123
+ * normal streamings of data, we need this separate function to deal with them. It transforms the internal data model of the
124
+ * StreamedJson object whenever an event is triggered.
125
+ */
126
+ async function transform(event: Partial<FixedChatResponse>, data: Partial<ChatResponseWithSteps>) {
127
+ const info = event.agent_info
128
+
129
+ if (!info) return
130
+
131
+ const tools = await DiscoverClient.toolsOfAgent(request.agentId)
132
+ data.steps = data.steps ? [...data.steps] : []
133
+
134
+ if (info.type === 'planning' && info.action === 'end') {
135
+ data.steps.push({
136
+ id: 'planning',
137
+ type: 'planning',
138
+ status: 'success',
139
+ duration: info.duration || 0,
140
+ steps: info.data?.steps?.map(s => s.goal) ?? [],
141
+ goal: info.data?.plan_goal ?? '',
142
+ })
143
+
144
+ info.data?.steps.forEach(s => data.steps?.push({
145
+ id: s.id,
146
+ type: 'step',
147
+ status: 'pending',
148
+ input: s.goal,
149
+ attempts: [{
150
+ tools: s.tools?.map(t => ({
151
+ ...(tools.find(({ id }) => id === t.tool_id) ?? { id: t.tool_id, name: t.tool_id }),
152
+ executionId: t.tool_execution_id,
153
+ goal: t.goal,
154
+ })),
155
+ }],
156
+ }))
157
+ data.steps.push({ id: 'answer', type: 'answer', status: 'pending' })
158
+ }
159
+
160
+ if (info.type === 'planning' && info.action === 'awaiting_approval') {
161
+ data.steps.push({
162
+ id: 'planning',
163
+ type: 'planning',
164
+ status: 'awaiting_approval',
165
+ user_question: info.data?.user_question,
166
+ duration: info.duration || 0,
167
+ steps: info.data?.steps?.map(s => s.goal) ?? [],
168
+ goal: info.data?.plan_goal ?? '',
169
+ })
170
+ info.data?.steps.forEach(s => data.steps?.push({
171
+ id: s.id,
172
+ type: 'step',
173
+ status: 'pending',
174
+ input: s.goal,
175
+ attempts: [{
176
+ tools: s.tools?.map(t => ({
177
+ ...(tools.find(({ id }) => id === t.tool_id) ?? { id: t.tool_id, name: t.tool_id }),
178
+ executionId: t.tool_execution_id,
179
+ goal: t.goal,
180
+ })),
181
+ }],
182
+ }))
183
+ data.steps.push({ id: 'answer', type: 'answer', status: 'pending' })
184
+ }
185
+
186
+ if (info.type === 'step' && info.action === 'start') {
187
+ const step = data.steps.find(s => s.id === info.id)
188
+ if (step) step.status = 'running'
189
+ }
190
+
191
+ if (info.type === 'step' && info.action === 'end') {
192
+ const step = data.steps.find(s => s.id === info.id) as StepChatStep
193
+ if (step) {
194
+ step.status = 'success'
195
+ step.duration = info.duration
196
+ const lastToolId = last(step.attempts[0].tools)?.id
197
+ const lastAttemptOfLastTool = findLast(step.attempts.map(a => a.tools).flat(), t => t?.id === lastToolId)
198
+ step.output = lastAttemptOfLastTool?.output
199
+ }
200
+ }
201
+
202
+ if (info.type === 'tool' && info.action === 'awaiting_approval') {
203
+ const tool = tools.find(({ id }) => id === info.data?.tool_id)
204
+ data.steps.push({
205
+ id: info.id,
206
+ type: 'tool',
207
+ status: 'awaiting_approval',
208
+ duration: info.duration || 0,
209
+ input: info.data?.input,
210
+ user_question: info.data?.user_question,
211
+ attempts: [{
212
+ tools: [{
213
+ executionId: info.id,
214
+ id: info.data?.tool_id ?? '',
215
+ name: tool?.name ?? '',
216
+ goal: tool?.goal,
217
+ ...tool,
218
+ }],
219
+ }],
220
+ })
221
+ data.steps.push({ id: 'answer', type: 'answer', status: 'pending' })
222
+ }
223
+
224
+ if (info.type === 'tool' && info.action === 'start') {
225
+ const currentStep = data.steps.find(s => s.status === 'running') as StepChatStep
226
+ if (!info.data) return
227
+
228
+ //There might be a tool with status awaiting_approval, so we want to inform tool has already started
229
+ if (!currentStep || !currentStep.attempts[0].tools) {
230
+ const input = formatJson(info.data.input)
231
+ const tool = tools.find(({ id }) => id === info.data?.tool_id) ?? { id: info.data?.tool_id, name: info.data?.tool_id }
232
+ data.steps.push({
233
+ id: info.id,
234
+ type: 'tool',
235
+ status: 'running',
236
+ duration: info.duration || 0,
237
+ input: info.data?.input,
238
+ user_question: info.data?.user_question,
239
+ attempts: [{
240
+ tools: [{ ...tool, executionId: info.id, input }],
241
+ }],
242
+ })
243
+ } else {
244
+ const toolInFirstAttempt = currentStep.attempts[0].tools?.find(t => t.executionId === info.id)
245
+ //One step might have multiple tools. When in an approval mode, we might not have all the tools in the array yet.
246
+ //So we make sure to add any tools that are not in there.
247
+ if (!toolInFirstAttempt) {
248
+ const input = formatJson(info.data.input)
249
+ const tool = tools?.find(({ id }) => id === info.data?.tool_id) ?? { id: info.data?.tool_id, name: info.data?.tool_id }
250
+ currentStep.attempts[info.data.attempt - 1].tools?.push({
251
+ ...tool,
252
+ executionId: info.id,
253
+ input,
254
+ })
255
+ } else {
256
+ const input = formatJson(info.data.input)
257
+ if (info.data.attempt === 1) {
258
+ toolInFirstAttempt.input = input
259
+ } else {
260
+ const tool = tools.find(({ id }) => id === info.data?.tool_id) ?? { id: info.data?.tool_id, name: info.data?.tool_id }
261
+ currentStep.attempts[info.data.attempt - 1] ??= { tools: [] }
262
+ currentStep.attempts[info.data.attempt - 1].tools?.push({
263
+ ...tool,
264
+ executionId: info.id,
265
+ input,
266
+ })
267
+ }
268
+ }
269
+ }
270
+ }
271
+
272
+ if (info.type === 'tool' && info.action === 'end') {
273
+ const currentStep = data.steps.find(s => s.status === 'running') as StepChatStep
274
+ if (!currentStep || !info.data) return
275
+ const tool = currentStep.attempts[info.data.attempt - 1]?.tools?.find(t => t.executionId === info.id)
276
+ if (tool) {
277
+ tool.output = formatJson(info.data.output)
278
+ tool.duration = info.duration
279
+ }
280
+ }
281
+
282
+ if (info.type === 'final_answer' && info.action === 'start') {
283
+ const answerStep = last(data.steps)
284
+ if (answerStep) answerStep.status = 'running'
285
+ }
286
+
287
+ if (info.type === 'chat' && info.action === 'end') {
288
+ const answerStep = last(data.steps)
289
+ if (answerStep) {
290
+ answerStep.status = 'success'
291
+ answerStep.duration = info.duration
292
+ }
293
+ }
294
+ }
295
+
296
+ return new StreamedJson({
297
+ eventsPromise: events,
298
+ abortController,
299
+ minChangeIntervalMS,
300
+ ignoreKeys: ['agent_info'],
301
+ transform,
302
+ })
303
+ }
87
304
  }
88
305
 
89
306
  export const discoverClient = new DiscoverClient()