@stack-spot/portal-network 0.211.1 → 0.212.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stack-spot/portal-network",
3
- "version": "0.211.1",
3
+ "version": "0.212.0",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -65,6 +65,12 @@ export type FolderResponse = {
65
65
  /** Sub folders */
66
66
  folders: any[];
67
67
  };
68
+ export type AccessGroupIdsRequest = {
69
+ /** Group id */
70
+ groupId: string;
71
+ /** Group access level: read or write */
72
+ accessLevel: string;
73
+ };
68
74
  export type CreateFolderRequest = {
69
75
  /** New folder's name */
70
76
  name: string;
@@ -74,6 +80,8 @@ export type CreateFolderRequest = {
74
80
  description: string;
75
81
  /** Parent folder's api id, null if creating root folder. ULID Format */
76
82
  parentFolderId?: string;
83
+ /** Access group Id's */
84
+ accessGroupIds?: AccessGroupIdsRequest[];
77
85
  };
78
86
  export type AssetTypeResponse = {
79
87
  apiId: string;
@@ -166,11 +174,19 @@ export type FoldersDetailsResponse = {
166
174
  /** Folder linked to a folder */
167
175
  folders?: FoldersDetailsResponse[];
168
176
  };
177
+ export type AccessGroupRequest = {
178
+ /** Group id */
179
+ groupId: string;
180
+ /** Access Level. (e.g READ, WRITE) */
181
+ accessLevel: "READ" | "WRITE";
182
+ };
169
183
  export type UpdateFolderRequest = {
170
184
  /** Folder name */
171
185
  name: string;
172
186
  /** Folder description */
173
187
  description: string;
188
+ /** List of access groupId level */
189
+ accessGroupIds?: AccessGroupRequest[];
174
190
  };
175
191
  export type UpdateAssetTypeRequest = {
176
192
  /** Asset type's name */
@@ -196,14 +212,19 @@ export function saveProject({ createProjectRequest }: {
196
212
  status: 401;
197
213
  } | {
198
214
  status: 403;
199
- data: ApiIdResponse;
200
215
  } | {
201
216
  status: 404;
217
+ } | {
218
+ status: 408;
219
+ data: ErrorBody;
202
220
  } | {
203
221
  status: 422;
204
222
  data: ErrorBody;
205
223
  } | {
206
224
  status: 500;
225
+ } | {
226
+ status: 503;
227
+ data: ErrorBody;
207
228
  }>("/v1/account/projects", oazapfts.json({
208
229
  ...opts,
209
230
  method: "POST",
@@ -227,15 +248,20 @@ export function saveAsset({ projectId, createAssetRequest }: {
227
248
  status: 401;
228
249
  } | {
229
250
  status: 403;
230
- data: ApiIdResponse;
231
251
  } | {
232
252
  status: 404;
233
253
  data: ErrorBody;
254
+ } | {
255
+ status: 408;
256
+ data: ErrorBody;
234
257
  } | {
235
258
  status: 422;
236
259
  data: ErrorBody;
237
260
  } | {
238
261
  status: 500;
262
+ } | {
263
+ status: 503;
264
+ data: ErrorBody;
239
265
  }>(`/v1/account/projects/${encodeURIComponent(projectId)}/assets`, oazapfts.json({
240
266
  ...opts,
241
267
  method: "POST",
@@ -256,15 +282,20 @@ export function listFolders(opts?: Oazapfts.RequestOpts) {
256
282
  status: 401;
257
283
  } | {
258
284
  status: 403;
259
- data: FolderResponse[];
260
285
  } | {
261
286
  status: 404;
262
287
  data: ErrorBody;
288
+ } | {
289
+ status: 408;
290
+ data: ErrorBody;
263
291
  } | {
264
292
  status: 422;
265
293
  data: ErrorBody;
266
294
  } | {
267
295
  status: 500;
296
+ } | {
297
+ status: 503;
298
+ data: ErrorBody;
268
299
  }>("/v1/account/folders", {
269
300
  ...opts
270
301
  }));
@@ -288,15 +319,20 @@ export function saveFolder({ createFolderRequest }: {
288
319
  status: 401;
289
320
  } | {
290
321
  status: 403;
291
- data: ApiIdResponse;
292
322
  } | {
293
323
  status: 404;
294
324
  data: ErrorBody;
325
+ } | {
326
+ status: 408;
327
+ data: ErrorBody;
295
328
  } | {
296
329
  status: 422;
297
330
  data: ErrorBody;
298
331
  } | {
299
332
  status: 500;
333
+ } | {
334
+ status: 503;
335
+ data: ErrorBody;
300
336
  }>("/v1/account/folders", oazapfts.json({
301
337
  ...opts,
302
338
  method: "POST",
@@ -319,15 +355,20 @@ export function listAssetTypes({ name }: {
319
355
  status: 401;
320
356
  } | {
321
357
  status: 403;
322
- data: AssetTypeResponse[];
323
358
  } | {
324
359
  status: 404;
325
360
  data: ErrorBody;
361
+ } | {
362
+ status: 408;
363
+ data: ErrorBody;
326
364
  } | {
327
365
  status: 422;
328
366
  data: ErrorBody;
329
367
  } | {
330
368
  status: 500;
369
+ } | {
370
+ status: 503;
371
+ data: ErrorBody;
331
372
  }>(`/v1/account/assets/types${QS.query(QS.explode({
332
373
  name
333
374
  }))}`, {
@@ -350,15 +391,20 @@ export function saveAssetType({ createAssetTypeRequest }: {
350
391
  status: 401;
351
392
  } | {
352
393
  status: 403;
353
- data: ApiIdResponse;
354
394
  } | {
355
395
  status: 404;
356
396
  data: ErrorBody;
397
+ } | {
398
+ status: 408;
399
+ data: ErrorBody;
357
400
  } | {
358
401
  status: 422;
359
402
  data: ErrorBody;
360
403
  } | {
361
404
  status: 500;
405
+ } | {
406
+ status: 503;
407
+ data: ErrorBody;
362
408
  }>("/v1/account/assets/types", oazapfts.json({
363
409
  ...opts,
364
410
  method: "POST",
@@ -381,14 +427,19 @@ export function getProjectDetails({ projectId }: {
381
427
  status: 401;
382
428
  } | {
383
429
  status: 403;
384
- data: ProjectDetailsResponse;
385
430
  } | {
386
431
  status: 404;
432
+ } | {
433
+ status: 408;
434
+ data: ErrorBody;
387
435
  } | {
388
436
  status: 422;
389
437
  data: ErrorBody;
390
438
  } | {
391
439
  status: 500;
440
+ } | {
441
+ status: 503;
442
+ data: ErrorBody;
392
443
  }>(`/v1/account/projects/${encodeURIComponent(projectId)}`, {
393
444
  ...opts
394
445
  }));
@@ -410,10 +461,16 @@ export function deleteProject({ projectId }: {
410
461
  status: 403;
411
462
  } | {
412
463
  status: 404;
464
+ } | {
465
+ status: 408;
466
+ data: ErrorBody;
413
467
  } | {
414
468
  status: 422;
415
469
  } | {
416
470
  status: 500;
471
+ } | {
472
+ status: 503;
473
+ data: ErrorBody;
417
474
  }>(`/v1/account/projects/${encodeURIComponent(projectId)}`, {
418
475
  ...opts,
419
476
  method: "DELETE"
@@ -436,14 +493,19 @@ export function updateProject({ projectId, updateProjectRequest }: {
436
493
  status: 401;
437
494
  } | {
438
495
  status: 403;
439
- data: ProjectResponse;
440
496
  } | {
441
497
  status: 404;
498
+ } | {
499
+ status: 408;
500
+ data: ErrorBody;
442
501
  } | {
443
502
  status: 422;
444
503
  data: ErrorBody;
445
504
  } | {
446
505
  status: 500;
506
+ } | {
507
+ status: 503;
508
+ data: ErrorBody;
447
509
  }>(`/v1/account/projects/${encodeURIComponent(projectId)}`, oazapfts.json({
448
510
  ...opts,
449
511
  method: "PATCH",
@@ -468,11 +530,17 @@ export function disassociateProjectAsset({ projectId, assetId }: {
468
530
  status: 403;
469
531
  } | {
470
532
  status: 404;
533
+ } | {
534
+ status: 408;
535
+ data: ErrorBody;
471
536
  } | {
472
537
  status: 422;
473
538
  data: ErrorBody;
474
539
  } | {
475
540
  status: 500;
541
+ } | {
542
+ status: 503;
543
+ data: ErrorBody;
476
544
  }>(`/v1/account/projects/${encodeURIComponent(projectId)}/assets/${encodeURIComponent(assetId)}`, {
477
545
  ...opts,
478
546
  method: "DELETE"
@@ -496,15 +564,20 @@ export function updateAsset({ projectId, assetId, updateAssetRequest }: {
496
564
  status: 401;
497
565
  } | {
498
566
  status: 403;
499
- data: ApiIdResponse;
500
567
  } | {
501
568
  status: 404;
502
569
  data: ErrorBody;
570
+ } | {
571
+ status: 408;
572
+ data: ErrorBody;
503
573
  } | {
504
574
  status: 422;
505
575
  data: ErrorBody;
506
576
  } | {
507
577
  status: 500;
578
+ } | {
579
+ status: 503;
580
+ data: ErrorBody;
508
581
  }>(`/v1/account/projects/${encodeURIComponent(projectId)}/assets/${encodeURIComponent(assetId)}`, oazapfts.json({
509
582
  ...opts,
510
583
  method: "PATCH",
@@ -527,14 +600,19 @@ export function getFolderDetails({ folderId }: {
527
600
  status: 401;
528
601
  } | {
529
602
  status: 403;
530
- data: FoldersDetailsResponse;
531
603
  } | {
532
604
  status: 404;
605
+ } | {
606
+ status: 408;
607
+ data: ErrorBody;
533
608
  } | {
534
609
  status: 422;
535
610
  data: ErrorBody;
536
611
  } | {
537
612
  status: 500;
613
+ } | {
614
+ status: 503;
615
+ data: ErrorBody;
538
616
  }>(`/v1/account/folders/${encodeURIComponent(folderId)}`, {
539
617
  ...opts
540
618
  }));
@@ -556,10 +634,16 @@ export function deleteFolder({ folderId }: {
556
634
  status: 403;
557
635
  } | {
558
636
  status: 404;
637
+ } | {
638
+ status: 408;
639
+ data: ErrorBody;
559
640
  } | {
560
641
  status: 422;
561
642
  } | {
562
643
  status: 500;
644
+ } | {
645
+ status: 503;
646
+ data: ErrorBody;
563
647
  }>(`/v1/account/folders/${encodeURIComponent(folderId)}`, {
564
648
  ...opts,
565
649
  method: "DELETE"
@@ -582,14 +666,19 @@ export function updateFolders({ folderId, updateFolderRequest }: {
582
666
  status: 401;
583
667
  } | {
584
668
  status: 403;
585
- data: ApiIdResponse;
586
669
  } | {
587
670
  status: 404;
671
+ } | {
672
+ status: 408;
673
+ data: ErrorBody;
588
674
  } | {
589
675
  status: 422;
590
676
  data: ErrorBody;
591
677
  } | {
592
678
  status: 500;
679
+ } | {
680
+ status: 503;
681
+ data: ErrorBody;
593
682
  }>(`/v1/account/folders/${encodeURIComponent(folderId)}`, oazapfts.json({
594
683
  ...opts,
595
684
  method: "PATCH",
@@ -613,10 +702,16 @@ export function deleteAssetType({ assetTypeId }: {
613
702
  status: 403;
614
703
  } | {
615
704
  status: 404;
705
+ } | {
706
+ status: 408;
707
+ data: ErrorBody;
616
708
  } | {
617
709
  status: 422;
618
710
  } | {
619
711
  status: 500;
712
+ } | {
713
+ status: 503;
714
+ data: ErrorBody;
620
715
  }>(`/v1/account/assets/types/${encodeURIComponent(assetTypeId)}`, {
621
716
  ...opts,
622
717
  method: "DELETE"
@@ -639,14 +734,19 @@ export function updateAssetType({ assetTypeId, updateAssetTypeRequest }: {
639
734
  status: 401;
640
735
  } | {
641
736
  status: 403;
642
- data: ApiIdResponse;
643
737
  } | {
644
738
  status: 404;
739
+ } | {
740
+ status: 408;
741
+ data: ErrorBody;
645
742
  } | {
646
743
  status: 422;
647
744
  data: ErrorBody;
648
745
  } | {
649
746
  status: 500;
747
+ } | {
748
+ status: 503;
749
+ data: ErrorBody;
650
750
  }>(`/v1/account/assets/types/${encodeURIComponent(assetTypeId)}`, oazapfts.json({
651
751
  ...opts,
652
752
  method: "PATCH",
@@ -326,6 +326,9 @@ export type TargetFilesRequest = {
326
326
  totalTokenSent?: number | null;
327
327
  totalTokenReceived?: number | null;
328
328
  modified?: boolean | null;
329
+ customOutputs?: {
330
+ [key: string]: any;
331
+ } | null;
329
332
  };
330
333
  export type LanguageInfoRequest = {
331
334
  bytes: number;
@@ -399,6 +402,9 @@ export type TargetFilesResponse = {
399
402
  totalTokenSent?: number | null;
400
403
  totalTokenReceived?: number | null;
401
404
  modified?: boolean | null;
405
+ customOutputs?: {
406
+ [key: string]: any;
407
+ } | null;
402
408
  };
403
409
  export type ReportStatus = "waiting_dispatch" | "waiting_runner" | "dispatch_failure" | "in_progress" | "suspended" | "error" | "success" | "cancelled";
404
410
  export type PullRequestResponse = {
@@ -1112,6 +1118,9 @@ export type ProgramGroupsTargetDetailsResponse = {
1112
1118
  customOutputs?: {
1113
1119
  [key: string]: any;
1114
1120
  } | null;
1121
+ targetCustomOutputs?: {
1122
+ [key: string]: any;
1123
+ } | null;
1115
1124
  customerScore?: number | null;
1116
1125
  totalTokenSent: number | null;
1117
1126
  totalTokenReceived: number | null;
@@ -1139,6 +1148,9 @@ export type RepositoryTargetDetailsItemResponse = {
1139
1148
  totalTokenSent: number | null;
1140
1149
  totalTokenReceived: number | null;
1141
1150
  modified: boolean | null;
1151
+ targetCustomOutputs?: {
1152
+ [key: string]: any;
1153
+ } | null;
1142
1154
  };
1143
1155
  export type AnalyticsRepositoryTargetDetailsResponse = {
1144
1156
  totalFiles?: number;
@@ -1246,7 +1258,7 @@ export type ValidateRepositoryStatus = "PENDING" | "SUCCESS" | "FAILURE" | "CONF
1246
1258
  export type BatchRepositoryResponse = {
1247
1259
  repositoryId: string | null;
1248
1260
  repositoryUrl: string;
1249
- repositoryBranch: string;
1261
+ repositoryBranch: string | null;
1250
1262
  repositoryTags: string[];
1251
1263
  status: ValidateRepositoryStatus;
1252
1264
  line: number;
@@ -1259,7 +1271,7 @@ export type BatchRepositoryResponse = {
1259
1271
  export type BatchRepositoryResponseRead = {
1260
1272
  repositoryId: string | null;
1261
1273
  repositoryUrl: string;
1262
- repositoryBranch: string;
1274
+ repositoryBranch: string | null;
1263
1275
  repositoryTags: string[];
1264
1276
  status: ValidateRepositoryStatus;
1265
1277
  line: number;
@@ -1328,6 +1340,9 @@ export type ModuleExecution = {
1328
1340
  progress: number | null;
1329
1341
  executionCreatedAt: string | null;
1330
1342
  executionCompletedAt: string | null;
1343
+ batchName: string | null;
1344
+ batchStatus: ModuleExecutionBatchStatus | null;
1345
+ batchCreatedAt: string | null;
1331
1346
  };
1332
1347
  export type GetModuleExecutionBatchActivitiesById = {
1333
1348
  items: ModuleExecution[];
@@ -4302,7 +4317,7 @@ export function patHealthCheckV1ScmPatHealthCheckGet({ authorization }: {
4302
4317
  }, opts?: Oazapfts.RequestOpts) {
4303
4318
  return oazapfts.ok(oazapfts.fetchJson<{
4304
4319
  status: 200;
4305
- data: boolean;
4320
+ data: true;
4306
4321
  } | {
4307
4322
  status: 422;
4308
4323
  data: HttpValidationError;
@@ -4340,8 +4355,10 @@ export function listModuleExecutionBatchActivitiesV1ActivitiesModuleExecutionBat
4340
4355
  /**
4341
4356
  * Get Module Execution Batch Activities By Id
4342
4357
  */
4343
- export function getModuleExecutionBatchActivitiesByIdV1ActivitiesModuleExecutionBatchModuleExecutionBatchIdGet({ moduleExecutionBatchId, authorization }: {
4358
+ export function getModuleExecutionBatchActivitiesByIdV1ActivitiesModuleExecutionBatchModuleExecutionBatchIdGet({ moduleExecutionBatchId, pageSize, page, authorization }: {
4344
4359
  moduleExecutionBatchId: string;
4360
+ pageSize?: number;
4361
+ page?: number;
4345
4362
  authorization: string;
4346
4363
  }, opts?: Oazapfts.RequestOpts) {
4347
4364
  return oazapfts.ok(oazapfts.fetchJson<{
@@ -4350,7 +4367,10 @@ export function getModuleExecutionBatchActivitiesByIdV1ActivitiesModuleExecution
4350
4367
  } | {
4351
4368
  status: 422;
4352
4369
  data: HttpValidationError;
4353
- }>(`/v1/activities/module-execution-batch/${encodeURIComponent(moduleExecutionBatchId)}`, {
4370
+ }>(`/v1/activities/module-execution-batch/${encodeURIComponent(moduleExecutionBatchId)}${QS.query(QS.explode({
4371
+ pageSize,
4372
+ page
4373
+ }))}`, {
4354
4374
  ...opts,
4355
4375
  headers: oazapfts.mergeHeaders(opts?.headers, {
4356
4376
  authorization
@@ -98,11 +98,11 @@ class AgentToolsClient extends ReactQueryNetworkClient {
98
98
  agentDefault = this.query({
99
99
  name: 'agentDefault',
100
100
  request: async (signal) => {
101
- const agentDefault = await listAgentsV1AgentsGet(
102
- { visibility: 'built_in', slug: this.agentDefaultSlug, authorization: '' }, { signal },
101
+ const agentDefault = await listAgentsV3AgentsGet(
102
+ { filters: { visibility_list: ['built_in'], slug: this.agentDefaultSlug }, authorization: '' }, { signal },
103
103
  )
104
104
 
105
- const agentId = agentDefault?.find((agent) => agent.slug === this.agentDefaultSlug)?.id
105
+ const agentId = agentDefault?.items?.find((agent) => agent.slug === this.agentDefaultSlug)?.id
106
106
  const agent = agentId ? await this.agent.query({ agentId }) : undefined
107
107
  return agent
108
108
  },
@@ -125,20 +125,23 @@ class AgentToolsClient extends ReactQueryNetworkClient {
125
125
  ? workspaceAiClient.workspacesContentsByType.query({ contentType: 'agent' })
126
126
  : Promise.resolve([])
127
127
 
128
- const [workspaceAgents, ...agentsByVisibility] = await Promise.all([
128
+ const [workspaceAgents, agentsByVisibility] = await Promise.all([
129
129
  workspaceAgentsPromise,
130
- ...visibilities.map((visibility) => listAgentsV1AgentsGet({ visibility, authorization: '' }, { signal })),
130
+ listAgentsV3AgentsGet({ filters: {
131
+ visibility_list: visibilities as (AgentVisibilityLevelEnum | VisibilityLevelEnum)[],
132
+ },
133
+ authorization: '' }, { signal }),
131
134
  ])
132
135
 
133
136
  const workspaceAgentsWithSpaceName = workspaceAgents.flatMap(({ agents, space_name }) =>
134
137
  agents?.map((agent) => ({ ...agent, spaceName: space_name, builtIn: false }))) as AgentResponseWithBuiltIn[]
135
138
 
136
139
  const allAgents: AgentResponseWithBuiltIn[] = workspaceAgentsWithSpaceName ?? []
137
-
138
- agentsByVisibility.forEach(agents => allAgents.push(...agents.map(agent => ({
140
+
141
+ agentsByVisibility.items?.forEach(agent => allAgents.push(({
139
142
  ...agent,
140
143
  builtIn: agent?.visibility_level === 'built_in',
141
- }))))
144
+ })))
142
145
 
143
146
  return allAgents
144
147
  },
package/src/client/ai.ts CHANGED
@@ -26,8 +26,8 @@ import {
26
26
  getContentDependenciesV1ContentContentTypeContentIdDependenciesGet,
27
27
  getFlagsV1FlagsGet,
28
28
  getQuickCommandV1QuickCommandsSlugGet,
29
- getScriptExecutionStatusV1QuickCommandsScriptExecutionsScriptExecutionIdGet,
30
29
  getReviewsByResourceV1ResourcesResourceTypeSlugResourceSlugReviewsGet,
30
+ getScriptExecutionStatusV1QuickCommandsScriptExecutionsScriptExecutionIdGet,
31
31
  getUploadFormV1FileUploadFormPost,
32
32
  HttpValidationError,
33
33
  listAiStacksV1AiStacksGet,
@@ -64,6 +64,7 @@ import { StreamedJson } from '../utils/StreamedJson'
64
64
  import { formatJson } from '../utils/string'
65
65
  import { agentToolsClient } from './agent-tools'
66
66
  import {
67
+ AgentInfo,
67
68
  ChatAgentTool,
68
69
  ChatResponseWithSteps,
69
70
  FixedChatRequest,
@@ -367,6 +368,10 @@ class AIClient extends ReactQueryNetworkClient {
367
368
  { method: 'post', body: JSON.stringify(request), headers, signal: abortController.signal },
368
369
  )
369
370
 
371
+ const DYNAMIC_TOOL_ID = 'dynamic'
372
+ function isDynamicTool(info: AgentInfo) {
373
+ return info.type === 'tool' && info.id === DYNAMIC_TOOL_ID
374
+ }
370
375
  /**
371
376
  * This function treats events in the streaming that deals with the execution of tools. Since these events are not concatenated like
372
377
  * normal streamings of data, we need this separate function to deal with them. It transforms the internal data model of the
@@ -374,12 +379,10 @@ class AIClient extends ReactQueryNetworkClient {
374
379
  */
375
380
  async function transform(event: Partial<FixedChatResponse>, data: Partial<ChatResponseWithSteps>) {
376
381
  const info = event.agent_info
377
-
378
382
  if (!info) return
379
-
380
383
  const tools = await AIClient.toolsOfAgent(request.context?.agent_id)
381
384
  data.steps = data.steps ? [...data.steps] : []
382
-
385
+
383
386
  if (info.type === 'planning' && info.action === 'end') {
384
387
  data.steps.push({
385
388
  id: 'planning',
@@ -448,6 +451,39 @@ class AIClient extends ReactQueryNetworkClient {
448
451
  }
449
452
  }
450
453
 
454
+ if (info.type === 'tool_calls' && info.action === 'start') {
455
+ const hasPlanning = data.steps.find(s => s.type === 'planning')
456
+ // On the first tool_calls:start, create the synthetic planning ("dynamic") step.
457
+ if (!hasPlanning) {
458
+ const userPrompt = request.user_prompt === 'string' ? request.user_prompt : JSON.stringify(request.user_prompt)
459
+ data.steps.push({
460
+ id: 'dynamic',
461
+ type: 'planning',
462
+ status: 'success',
463
+ steps: [],
464
+ goal: userPrompt,
465
+ user_question: userPrompt,
466
+ })
467
+ }
468
+ const toolsStepId = data.steps.filter(s => s.id === 'tools' || s.id.startsWith('tools-')).length + 1
469
+ data.steps.push({
470
+ id: `tools-${toolsStepId.toString()}`,
471
+ type: 'step',
472
+ status: 'running',
473
+ attempts: [{ tools: [] }],
474
+ } as StepChatStep)
475
+ }
476
+
477
+ if (info.type === 'tool_calls' && info.action === 'end') {
478
+ const lastStep = findLast(data.steps, s => s.id === 'tools' || s.id.startsWith('tools-')) as StepChatStep
479
+ if (lastStep) {
480
+ lastStep.status = 'success'
481
+ lastStep.duration = info.duration
482
+ const lastAttemptOfLastTool = last(lastStep.attempts.map(a => a.tools).flat())
483
+ lastStep.output = lastAttemptOfLastTool?.output
484
+ }
485
+ }
486
+
451
487
  if (info.type === 'tool' && info.action === 'awaiting_approval') {
452
488
  const tool = tools.find(({ id }) => id === info.data?.tool_id)
453
489
  data.steps.push({
@@ -471,13 +507,14 @@ class AIClient extends ReactQueryNetworkClient {
471
507
  }
472
508
 
473
509
  if (info.type === 'tool' && info.action === 'start') {
474
- const currentStep = data.steps.find(s => s.status === 'running') as StepChatStep
475
510
  if (!info.data) return
511
+ const input = formatJson(info.data.input)
512
+ const tool = findLast(tools, ({ id }) => id === info.data?.tool_id) ?? { id: info.data?.tool_id, name: info.data?.tool_id }
513
+
514
+ const currentStep = findLast(data.steps, s => s.status === 'running') as StepChatStep
476
515
 
477
516
  //There might be a tool with status awaiting_approval, so we want to inform tool has already started
478
- if (!currentStep || !currentStep.attempts[0].tools) {
479
- const input = formatJson(info.data.input)
480
- const tool = tools.find(({ id }) => id === info.data?.tool_id) ?? { id: info.data?.tool_id, name: info.data?.tool_id }
517
+ if (!currentStep || !currentStep?.attempts?.[0]?.tools) {
481
518
  data.steps.push({
482
519
  id: info.id,
483
520
  type: 'tool',
@@ -490,23 +527,23 @@ class AIClient extends ReactQueryNetworkClient {
490
527
  }],
491
528
  })
492
529
  } else {
493
- const toolInFirstAttempt = currentStep.attempts[0].tools?.find(t => t.executionId === info.id)
530
+ const toolInFirstAttempt = findLast(currentStep?.attempts?.[0]?.tools, t => t.executionId === info.id)
494
531
  //One step might have multiple tools. When in an approval mode, we might not have all the tools in the array yet.
495
- //So we make sure to add any tools that are not in there.
496
- if (!toolInFirstAttempt) {
497
- const input = formatJson(info.data.input)
498
- const tool = tools?.find(({ id }) => id === info.data?.tool_id) ?? { id: info.data?.tool_id, name: info.data?.tool_id }
499
- currentStep.attempts[info.data.attempt - 1].tools?.push({
532
+ //For dynamic tools (id === 'dynamic'), we always push a new tool, since dynamic executions can trigger
533
+ //multiple tool runs in the same step and do not follow the planned tool structure.
534
+ //So we make sure to add any tools that are not in there, or always add for dynamic tools.
535
+ if (!toolInFirstAttempt || isDynamicTool(info)) {
536
+ currentStep.attempts?.[0].tools?.push({
500
537
  ...tool,
501
538
  executionId: info.id,
502
539
  input,
540
+ status: 'running',
503
541
  })
504
542
  } else {
505
543
  const input = formatJson(info.data.input)
506
544
  if (info.data.attempt === 1) {
507
545
  toolInFirstAttempt.input = input
508
546
  } else {
509
- const tool = tools.find(({ id }) => id === info.data?.tool_id) ?? { id: info.data?.tool_id, name: info.data?.tool_id }
510
547
  currentStep.attempts[info.data.attempt - 1] ??= { tools: [] }
511
548
  currentStep.attempts[info.data.attempt - 1].tools?.push({
512
549
  ...tool,
@@ -521,10 +558,14 @@ class AIClient extends ReactQueryNetworkClient {
521
558
  if (info.type === 'tool' && info.action === 'end') {
522
559
  const currentStep = data.steps.find(s => s.status === 'running') as StepChatStep
523
560
  if (!currentStep || !info.data) return
524
- const tool = currentStep.attempts[info.data.attempt - 1]?.tools?.find(t => t.executionId === info.id)
561
+
562
+ // attempt index for tool execution starts at 0 for dynamically executed tools,while for planned tools it starts at 1
563
+ const attempt = isDynamicTool(info) ? info.data.attempt : info.data.attempt - 1
564
+ const tool = last(currentStep?.attempts?.[attempt]?.tools)
525
565
  if (tool) {
526
566
  tool.output = formatJson(info.data.output)
527
567
  tool.duration = info.duration
568
+ tool.status = 'success'
528
569
  }
529
570
  }
530
571
 
@@ -533,11 +574,14 @@ class AIClient extends ReactQueryNetworkClient {
533
574
  if (answerStep) answerStep.status = 'running'
534
575
  }
535
576
 
577
+
536
578
  if (info.type === 'chat' && info.action === 'end') {
537
- const answerStep = last(data.steps)
538
- if (answerStep) {
539
- answerStep.status = 'success'
540
- answerStep.duration = info.duration
579
+ const lastStep = last(data.steps)
580
+ if (lastStep?.type === 'answer') {
581
+ lastStep.status = 'success'
582
+ lastStep.duration = info.duration
583
+ } else {
584
+ data.steps.push({ id: 'answer', type: 'answer', status: 'success' })
541
585
  }
542
586
  }
543
587
  }