@stack-spot/portal-network 1.0.0-dev.1768944806600 → 1.0.0-dev.1769537511491
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/CHANGELOG.md +13 -0
- package/dist/api/accountAssetManager.d.ts +14 -10
- package/dist/api/accountAssetManager.d.ts.map +1 -1
- package/dist/api/accountAssetManager.js +5 -2
- package/dist/api/accountAssetManager.js.map +1 -1
- package/dist/api/agent-tools.d.ts +752 -164
- package/dist/api/agent-tools.d.ts.map +1 -1
- package/dist/api/agent-tools.js +203 -43
- package/dist/api/agent-tools.js.map +1 -1
- package/dist/api/ai.d.ts +3 -2
- package/dist/api/ai.d.ts.map +1 -1
- package/dist/api/ai.js +1 -2
- package/dist/api/ai.js.map +1 -1
- package/dist/api/workspace-ai.d.ts +41 -0
- package/dist/api/workspace-ai.d.ts.map +1 -1
- package/dist/api/workspace-ai.js +34 -0
- package/dist/api/workspace-ai.js.map +1 -1
- package/dist/client/account-asset-manager.d.ts +3 -0
- package/dist/client/account-asset-manager.d.ts.map +1 -1
- package/dist/client/agent-tools.d.ts +130 -3
- package/dist/client/agent-tools.d.ts.map +1 -1
- package/dist/client/agent-tools.js +105 -2
- package/dist/client/agent-tools.js.map +1 -1
- package/dist/client/ai.d.ts +98 -6
- package/dist/client/ai.d.ts.map +1 -1
- package/dist/client/ai.js +382 -8
- package/dist/client/ai.js.map +1 -1
- package/dist/client/types.d.ts +24 -1
- package/dist/client/types.d.ts.map +1 -1
- package/dist/client/workspace-ai.d.ts +15 -4
- package/dist/client/workspace-ai.d.ts.map +1 -1
- package/dist/client/workspace-ai.js +17 -3
- package/dist/client/workspace-ai.js.map +1 -1
- package/dist/utils/string.d.ts +6 -0
- package/dist/utils/string.d.ts.map +1 -1
- package/dist/utils/string.js +10 -0
- package/dist/utils/string.js.map +1 -1
- package/package.json +1 -1
- package/src/api/accountAssetManager.ts +18 -11
- package/src/api/agent-tools.ts +1259 -472
- package/src/api/ai.ts +3 -3
- package/src/api/workspace-ai.ts +83 -0
- package/src/client/agent-tools.ts +55 -2
- package/src/client/ai.ts +404 -8
- package/src/client/types.ts +30 -1
- package/src/client/workspace-ai.ts +23 -7
- package/src/utils/string.ts +12 -0
package/src/client/ai.ts
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import { HttpError } from '@oazapfts/runtime'
|
|
2
|
-
import { findLast, isArray, last } from 'lodash'
|
|
2
|
+
import { findLast, isArray, isNil, last } from 'lodash'
|
|
3
3
|
import { getApiAddresses } from '../api-addresses'
|
|
4
4
|
import {
|
|
5
5
|
addFavoriteV1AiStacksStackIdFavoritePost,
|
|
6
6
|
addFavoriteV1QuickCommandsSlugFavoritePost,
|
|
7
7
|
calculateNextStepV1QuickCommandsSlugStepsStepSlugCalculateNextStepPost,
|
|
8
8
|
callbackV1QuickCommandsCallbackExecutionIdGet,
|
|
9
|
+
checkQuickCommandExistsV1QuickCommandsSlugExistsGet,
|
|
9
10
|
conversationHistoryV1ConversationsConversationIdGet,
|
|
10
11
|
createAnswerForReviewV1ResourcesResourceTypeSlugResourceSlugReviewsReviewIdAnswersPost,
|
|
11
12
|
createExecutionV1QuickCommandsCreateExecutionSlugPost,
|
|
13
|
+
createQuickCommandV1QuickCommandsPost,
|
|
12
14
|
createResourceReviewV1ResourcesResourceTypeSlugResourceSlugReviewsPost,
|
|
13
15
|
currentV1TokensUsageCurrentGet,
|
|
14
16
|
defaults,
|
|
@@ -16,11 +18,15 @@ import {
|
|
|
16
18
|
deleteFavoriteV1AiStacksStackIdFavoriteDelete,
|
|
17
19
|
deleteFavoriteV1QuickCommandsSlugFavoriteDelete,
|
|
18
20
|
deleteKnowledgeObjectByCustomIdV1KnowledgeSourcesSlugObjectsCustomIdDelete,
|
|
21
|
+
deleteKnowledgeSourceV1KnowledgeSourcesSlugDelete,
|
|
22
|
+
deleteQuickCommandV1QuickCommandsSlugDelete,
|
|
19
23
|
deleteResourceReviewV1ResourcesResourceTypeSlugResourceSlugReviewsReviewIdDelete,
|
|
20
24
|
deleteReviewCommentV1ResourcesResourceTypeSlugResourceSlugReviewsReviewIdAnswersAnswerIdDelete,
|
|
21
25
|
downloadConversationV1ConversationsConversationIdDownloadGet,
|
|
22
26
|
findKnowledgeObjectByCustomIdV1KnowledgeSourcesSlugObjectsCustomIdGet,
|
|
27
|
+
findKnowledgeSourceDependenciesV1KnowledgeSourcesSlugDependenciesGet,
|
|
23
28
|
findKnowledgeSourceV1KnowledgeSourcesSlugGet,
|
|
29
|
+
forkV1QuickCommandsSlugForkPost,
|
|
24
30
|
formatFetchStepV1QuickCommandsSlugStepsStepSlugFetchFormatPost,
|
|
25
31
|
formatResultV1QuickCommandsSlugResultFormatPost,
|
|
26
32
|
getContentDependenciesV1ContentContentTypeContentIdDependenciesGet,
|
|
@@ -38,10 +44,15 @@ import {
|
|
|
38
44
|
listConversationsV1ConversationsGet,
|
|
39
45
|
listKnowledgeSourcesV1KnowledgeSourcesGet,
|
|
40
46
|
postEventV1EventsPost,
|
|
47
|
+
publishV1QuickCommandsSlugPublishPost,
|
|
41
48
|
quickActionsV1QuickActionsPost,
|
|
49
|
+
QuickCommandPromptResponse,
|
|
42
50
|
QuickCommandPromptResponse2,
|
|
51
|
+
QuickCommandScriptExecutionResponse,
|
|
43
52
|
QuickCommandsExecutionRequest,
|
|
44
53
|
quickCommandsRunV2V2QuickCommandsSlugStepsStepSlugRunPost,
|
|
54
|
+
QuickCommandStepFetchResponse,
|
|
55
|
+
QuickCommandStepLlmResponse,
|
|
45
56
|
resetKnowledgeObjectsV1KnowledgeSourcesSlugObjectsDelete,
|
|
46
57
|
runFetchStepV1QuickCommandsSlugStepsStepSlugFetchRunPost,
|
|
47
58
|
searchKnowledgeSourcesV1KnowledgeSourcesSearchPost,
|
|
@@ -56,12 +67,11 @@ import {
|
|
|
56
67
|
vectorizeCustomKnowledgeSourceV1KnowledgeSourcesSlugCustomPost,
|
|
57
68
|
} from '../api/ai'
|
|
58
69
|
|
|
59
|
-
|
|
60
70
|
import { StackspotAPIError } from '../error/StackspotAPIError'
|
|
61
71
|
import { ReactQueryNetworkClient } from '../network/ReactQueryNetworkClient'
|
|
62
72
|
import { removeAuthorizationParam } from '../utils/remove-authorization-param'
|
|
63
73
|
import { StreamedJson } from '../utils/StreamedJson'
|
|
64
|
-
import { formatJson } from '../utils/string'
|
|
74
|
+
import { formatJson, getSizeOfString } from '../utils/string'
|
|
65
75
|
import { agentToolsClient } from './agent-tools'
|
|
66
76
|
import {
|
|
67
77
|
AgentInfo,
|
|
@@ -71,6 +81,9 @@ import {
|
|
|
71
81
|
FixedChatResponse,
|
|
72
82
|
FixedConversationResponse,
|
|
73
83
|
FixedDependencyResponse,
|
|
84
|
+
QCContext,
|
|
85
|
+
QCContextExecution,
|
|
86
|
+
QCProgressProps,
|
|
74
87
|
ReplaceResult,
|
|
75
88
|
StepChatStep,
|
|
76
89
|
} from './types'
|
|
@@ -117,6 +130,10 @@ class AIClient extends ReactQueryNetworkClient {
|
|
|
117
130
|
*/
|
|
118
131
|
vectorizeCustomKS = this.mutation(
|
|
119
132
|
removeAuthorizationParam(vectorizeCustomKnowledgeSourceV1KnowledgeSourcesSlugCustomPost))
|
|
133
|
+
/**
|
|
134
|
+
* Deletes a KS
|
|
135
|
+
*/
|
|
136
|
+
deleteKS = this.mutation(removeAuthorizationParam(deleteKnowledgeSourceV1KnowledgeSourcesSlugDelete))
|
|
120
137
|
/**
|
|
121
138
|
* Lists the AI Stacks according to their visibilities.
|
|
122
139
|
*/
|
|
@@ -158,6 +175,26 @@ class AIClient extends ReactQueryNetworkClient {
|
|
|
158
175
|
* Gets the execution status and result of a quick command by its execution ID.
|
|
159
176
|
*/
|
|
160
177
|
quickCommandCallbackExecutionId = this.query(removeAuthorizationParam(callbackV1QuickCommandsCallbackExecutionIdGet))
|
|
178
|
+
/**
|
|
179
|
+
* Creates a QC
|
|
180
|
+
*/
|
|
181
|
+
createQuickCommand = this.mutation(removeAuthorizationParam(createQuickCommandV1QuickCommandsPost))
|
|
182
|
+
/**
|
|
183
|
+
* Deletes a QC
|
|
184
|
+
*/
|
|
185
|
+
deleteQuickCommand = this.mutation(removeAuthorizationParam(deleteQuickCommandV1QuickCommandsSlugDelete))
|
|
186
|
+
/**
|
|
187
|
+
* Forks a QC
|
|
188
|
+
*/
|
|
189
|
+
forkQuickCommand = this.mutation(removeAuthorizationParam(forkV1QuickCommandsSlugForkPost))
|
|
190
|
+
/**
|
|
191
|
+
* Publishes a QC
|
|
192
|
+
*/
|
|
193
|
+
publishQuickCommand = this.mutation(removeAuthorizationParam(publishV1QuickCommandsSlugPublishPost))
|
|
194
|
+
/**
|
|
195
|
+
* Check Quick Command Available slug
|
|
196
|
+
*/
|
|
197
|
+
checkAvailableQuickCommandSlug = this.query(removeAuthorizationParam(checkQuickCommandExistsV1QuickCommandsSlugExistsGet))
|
|
161
198
|
/**
|
|
162
199
|
* Lists the knowledge sources according to filters passed as parameter.
|
|
163
200
|
*/
|
|
@@ -174,6 +211,10 @@ class AIClient extends ReactQueryNetworkClient {
|
|
|
174
211
|
* Lists knowledge sources matching the provided IDs.
|
|
175
212
|
*/
|
|
176
213
|
searchKnowledgeSources = this.query(removeAuthorizationParam(searchKnowledgeSourcesV1KnowledgeSourcesSearchPost))
|
|
214
|
+
/**
|
|
215
|
+
* Finds Knowledge Source Dependencies
|
|
216
|
+
*/
|
|
217
|
+
dependenciesKnowledgeSources = this.query(removeAuthorizationParam(findKnowledgeSourceDependenciesV1KnowledgeSourcesSlugDependenciesGet))
|
|
177
218
|
/**
|
|
178
219
|
* Gets the chat history. This is a paginated resource.
|
|
179
220
|
*/
|
|
@@ -340,15 +381,16 @@ class AIClient extends ReactQueryNetworkClient {
|
|
|
340
381
|
deleteReviewComment = this.mutation(
|
|
341
382
|
removeAuthorizationParam(deleteReviewCommentV1ResourcesResourceTypeSlugResourceSlugReviewsReviewIdAnswersAnswerIdDelete))
|
|
342
383
|
|
|
343
|
-
private static async toolsOfAgent(agentId?: string) {
|
|
384
|
+
private static async toolsOfAgent(agentId?: string, agent_version_number?: number) {
|
|
344
385
|
try {
|
|
345
|
-
const agent = agentId ? await agentToolsClient.
|
|
386
|
+
const agent = agentId ? await agentToolsClient.agentV2.query({
|
|
387
|
+
agentCoreId: agentId, versionNumber: agent_version_number }) : undefined
|
|
346
388
|
if (!agent) return []
|
|
347
389
|
const tools: (Omit<ChatAgentTool, 'duration' | 'prompt' | 'output'>)[] = []
|
|
348
|
-
agent.toolkits?.builtin_toolkits?.forEach(kit => kit.tools?.forEach(({ id, name, description }) => {
|
|
390
|
+
agent.version?.toolkits?.builtin_toolkits?.forEach(kit => kit.tools?.forEach(({ id, name, description }) => {
|
|
349
391
|
if (id) tools.push({ image: kit.image_url, id, name: name || id, description })
|
|
350
392
|
}))
|
|
351
|
-
agent.toolkits?.custom_toolkits?.forEach(kit => kit.tools?.forEach(({ id, name, description }) => {
|
|
393
|
+
agent.version?.toolkits?.custom_toolkits?.forEach(kit => kit.tools?.forEach(({ id, name, description }) => {
|
|
352
394
|
if (id) tools.push({ image: kit.avatar ?? undefined, id, name: name || id, description })
|
|
353
395
|
}))
|
|
354
396
|
return tools
|
|
@@ -357,6 +399,359 @@ class AIClient extends ReactQueryNetworkClient {
|
|
|
357
399
|
}
|
|
358
400
|
}
|
|
359
401
|
|
|
402
|
+
/**
|
|
403
|
+
* Runs an Router step of a quick command.
|
|
404
|
+
*/
|
|
405
|
+
async runRouterStep(
|
|
406
|
+
ctx: QCContextExecution,
|
|
407
|
+
stepIndex: number, iteration: Record<string, number>,
|
|
408
|
+
progress?:QCProgressProps,
|
|
409
|
+
) {
|
|
410
|
+
const { qc: { slug, steps }, code, resultMap, customInputs } = ctx
|
|
411
|
+
const step = steps![stepIndex]
|
|
412
|
+
const inputData = Object.keys(customInputs).length > 0 && code ? { ...customInputs, [code]: code } : code ?? customInputs
|
|
413
|
+
try {
|
|
414
|
+
progress?.onStepChange?.({ step: step.slug, ...resultMap, ...{ statusResult: 'START' } })
|
|
415
|
+
if (step.slug in iteration) {
|
|
416
|
+
iteration[step.slug] = iteration[step.slug] + 1
|
|
417
|
+
} else {
|
|
418
|
+
iteration[step.slug] = 1
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
const { next_step_slug } = await aiClient.calculateNextStep.mutate({
|
|
422
|
+
stepSlug: step.slug,
|
|
423
|
+
slug: slug,
|
|
424
|
+
quickCommandEvaluateStepRouterRequest: {
|
|
425
|
+
executions_count: iteration[step.slug],
|
|
426
|
+
input_data: inputData,
|
|
427
|
+
slugs_executions: resultMap,
|
|
428
|
+
},
|
|
429
|
+
})
|
|
430
|
+
|
|
431
|
+
progress?.onStepChange?.({ step: step.slug, ...resultMap, ...{ statusResult: 'END' } })
|
|
432
|
+
|
|
433
|
+
if (next_step_slug === step.slug) {
|
|
434
|
+
return aiClient.runStepsRecursively(stepIndex, ctx, iteration, progress)
|
|
435
|
+
}
|
|
436
|
+
const nextStepIndex = steps?.findIndex((step) => step.slug === next_step_slug)
|
|
437
|
+
|
|
438
|
+
if (isNil(nextStepIndex) || nextStepIndex === -1) return
|
|
439
|
+
|
|
440
|
+
return aiClient.runStepsRecursively(nextStepIndex, ctx, iteration, progress)
|
|
441
|
+
}
|
|
442
|
+
catch (error: any) {
|
|
443
|
+
progress?.onStepChange?.({
|
|
444
|
+
step: step.slug, error: error, answer: JSON.stringify(error.message), statusResult: 'ERROR', ...resultMap,
|
|
445
|
+
})
|
|
446
|
+
// eslint-disable-next-line no-console
|
|
447
|
+
console.error('Error executing QC step', error)
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
async getScriptStepStatus(
|
|
452
|
+
scriptExecutionId: string,
|
|
453
|
+
interval = 5000,
|
|
454
|
+
maxAttempts = 500,
|
|
455
|
+
currentAttempt = 0,
|
|
456
|
+
): Promise<QuickCommandScriptExecutionResponse> {
|
|
457
|
+
if (currentAttempt >= maxAttempts) {
|
|
458
|
+
throw new Error('Max attempts reached in verify script status')
|
|
459
|
+
}
|
|
460
|
+
await aiClient.getStatusScriptStep.invalidate({ scriptExecutionId })
|
|
461
|
+
const response = await aiClient.getStatusScriptStep.query({ scriptExecutionId })
|
|
462
|
+
|
|
463
|
+
if (response.status === 'success') {
|
|
464
|
+
return response
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
if (response.status === 'failure') {
|
|
468
|
+
throw response
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
await new Promise(resolve => {setTimeout(resolve, interval)})
|
|
472
|
+
|
|
473
|
+
return aiClient.getScriptStepStatus(scriptExecutionId, interval, maxAttempts, currentAttempt + 1)
|
|
474
|
+
}
|
|
475
|
+
/**
|
|
476
|
+
* Runs a fetch step of a quick command and puts the result in the `resultMap` of the context passed as parameter.
|
|
477
|
+
*/
|
|
478
|
+
async runFetchStep(ctx: QCContextExecution, stepIndex: number, progress?: QCProgressProps) {
|
|
479
|
+
const { qc: { slug, steps }, code, context, resultMap, customInputs, executionId, signal } = ctx
|
|
480
|
+
const step = steps![stepIndex] as QuickCommandStepFetchResponse
|
|
481
|
+
progress?.onStepChange?.({ step: step.slug, ...resultMap, answer: undefined, statusResult: 'START' })
|
|
482
|
+
|
|
483
|
+
//If is_remote we call backend to execute for us and we only have the response
|
|
484
|
+
if (step.is_remote) {
|
|
485
|
+
ctx.isRemote = true
|
|
486
|
+
try {
|
|
487
|
+
const { data } = await aiClient.fetchStepOfQuickCommandRemotely.mutate({
|
|
488
|
+
slug, stepSlug: step.slug,
|
|
489
|
+
quickCommandsExecutionRequest: {
|
|
490
|
+
code_selection: code, context, qc_execution_id: executionId,
|
|
491
|
+
slugs_executions: { ...resultMap, ...customInputs },
|
|
492
|
+
},
|
|
493
|
+
}, signal)
|
|
494
|
+
|
|
495
|
+
//data is the return of the request in the QC so we do not have full control over the response
|
|
496
|
+
//We handle the usual format with body, status_code and headers, but we might also handle other formats
|
|
497
|
+
const responseData = data as any
|
|
498
|
+
progress?.onStepChange?.({
|
|
499
|
+
step: step.slug, ...resultMap, answer: JSON.stringify(responseData.body) ?? JSON.stringify(responseData), statusResult: 'END' })
|
|
500
|
+
resultMap[step.slug] = {
|
|
501
|
+
status: responseData.status_code || 200,
|
|
502
|
+
data: JSON.stringify(responseData.body) ?? JSON.stringify(responseData),
|
|
503
|
+
headers: responseData.headers ?? {},
|
|
504
|
+
}
|
|
505
|
+
return
|
|
506
|
+
} catch (error) {
|
|
507
|
+
const errorMessage = `${error}, Failed to execute step "${step.slug}" of quick command "${slug}".`
|
|
508
|
+
progress?.onStepChange?.({ step: step.slug, ...resultMap, answer: errorMessage, error: errorMessage, statusResult: 'ERROR' })
|
|
509
|
+
throw new Error(errorMessage)
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
const { headers, data, method, url } = await aiClient.fetchStepOfQuickCommand.mutate({
|
|
514
|
+
slug,
|
|
515
|
+
stepSlug: step.slug,
|
|
516
|
+
quickCommandsExecutionRequest: {
|
|
517
|
+
input_data: code, context, qc_execution_id: executionId,
|
|
518
|
+
slugs_executions: { ...resultMap, ...customInputs },
|
|
519
|
+
},
|
|
520
|
+
}, signal)
|
|
521
|
+
const body = ['get', 'head'].includes(method.toLowerCase()) ? undefined : data
|
|
522
|
+
|
|
523
|
+
try {
|
|
524
|
+
//Local execution
|
|
525
|
+
const response = await fetch(url, { headers: headers || undefined, body, method, signal })
|
|
526
|
+
const responseData = await response.text()
|
|
527
|
+
if (!response.ok) throw new Error(`Failed to execute step "${step.slug}" of quick command "${slug}". Status ${response.status}.`)
|
|
528
|
+
progress?.onStepChange?.({ step: step.slug, ...resultMap, answer: responseData, statusResult: 'END' })
|
|
529
|
+
|
|
530
|
+
resultMap[step.slug] = {
|
|
531
|
+
status: response.status,
|
|
532
|
+
data: responseData,
|
|
533
|
+
headers: Object.fromEntries(response.headers.entries()),
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
catch (error) {
|
|
537
|
+
const errorMessage = `${error}, Failed to execute step "${step.slug}" of quick command "${slug}".`
|
|
538
|
+
progress?.onStepChange?.({ step: step.slug, ...resultMap, answer: errorMessage, error: errorMessage, statusResult: 'ERROR' })
|
|
539
|
+
throw new Error(errorMessage)
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
/**
|
|
544
|
+
* Runs an LLM step of a quick command and puts the result in the `resultMap` of the context passed as parameter.
|
|
545
|
+
*/
|
|
546
|
+
async runLLMStep(
|
|
547
|
+
{ qc: { slug, steps }, code, customInputs, context, executionId, resultMap, signal }: QCContextExecution,
|
|
548
|
+
stepIndex: number,
|
|
549
|
+
progress?: QCProgressProps,
|
|
550
|
+
) {
|
|
551
|
+
const step = steps![stepIndex] as QuickCommandStepLlmResponse
|
|
552
|
+
let stepContext = context
|
|
553
|
+
if (!step.use_uploaded_files) {
|
|
554
|
+
const { upload_ids: _upload_ids, ...contextDataProps } = context
|
|
555
|
+
stepContext = { ...contextDataProps }
|
|
556
|
+
}
|
|
557
|
+
// eslint-disable-next-line no-async-promise-executor
|
|
558
|
+
return new Promise(async (resolve) => {
|
|
559
|
+
progress?.onStepChange?.({ step: step.slug, ...resultMap, answer: undefined, statusResult: 'START' })
|
|
560
|
+
|
|
561
|
+
const stream = aiClient.streamLlmStepOfQuickCommand(
|
|
562
|
+
slug,
|
|
563
|
+
step.slug,
|
|
564
|
+
{
|
|
565
|
+
input_data: code,
|
|
566
|
+
context: stepContext,
|
|
567
|
+
qc_execution_id: executionId,
|
|
568
|
+
slugs_executions: { ...resultMap, ...customInputs },
|
|
569
|
+
},
|
|
570
|
+
)
|
|
571
|
+
|
|
572
|
+
signal.addEventListener('abort', () => stream.cancel())
|
|
573
|
+
|
|
574
|
+
stream.onChange(item => {
|
|
575
|
+
if (item?.sources?.length) {
|
|
576
|
+
progress?.onStepChange?.({ step: step.slug, ...resultMap, sources: JSON.stringify(item.sources) })
|
|
577
|
+
} else {
|
|
578
|
+
item.answer !== undefined && progress?.onStepChange?.({ step: step.slug, ...resultMap, answer: item.answer })
|
|
579
|
+
}
|
|
580
|
+
})
|
|
581
|
+
|
|
582
|
+
try {
|
|
583
|
+
const finalValue = await stream.getValue()
|
|
584
|
+
resultMap[step.slug] = finalValue
|
|
585
|
+
progress?.onStepChange?.({ step: step.slug, ...resultMap, answer: finalValue.answer,
|
|
586
|
+
sources: finalValue.sources ? JSON.stringify(finalValue.sources) : '', statusResult: 'END' })
|
|
587
|
+
resolve(finalValue)
|
|
588
|
+
} catch (error: any) {
|
|
589
|
+
// eslint-disable-next-line no-console
|
|
590
|
+
console.error('Error executing QC step', error)
|
|
591
|
+
const errorStep = `Failed to execute step "${step.slug}" of quick command "${slug}". Reason: ${error.message}`
|
|
592
|
+
progress?.onStepChange?.({ step: step.slug, ...resultMap, answer: errorStep, error: errorStep, statusResult: 'ERROR' })
|
|
593
|
+
throw error
|
|
594
|
+
}
|
|
595
|
+
})
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
async runScriptStep(
|
|
599
|
+
{ qc: { slug, steps }, code, context, resultMap, customInputs, signal }: QCContextExecution,
|
|
600
|
+
stepIndex: number,
|
|
601
|
+
progress?: QCProgressProps,
|
|
602
|
+
) {
|
|
603
|
+
const step = steps![stepIndex] as QuickCommandStepLlmResponse
|
|
604
|
+
let stepContext = context
|
|
605
|
+
progress?.onStepChange?.({ step: step.slug, ...resultMap, ...{ statusResult: 'START' } })
|
|
606
|
+
|
|
607
|
+
if (!step.use_uploaded_files) {
|
|
608
|
+
const { upload_ids: _upload_ids, ...contextDataProps } = context
|
|
609
|
+
stepContext = { ...contextDataProps }
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
try {
|
|
613
|
+
const { script_execution_id } = await aiClient.startScriptStep.mutate({
|
|
614
|
+
stepSlug: step.slug,
|
|
615
|
+
slug: slug,
|
|
616
|
+
quickCommandStartScriptRequest: {
|
|
617
|
+
input_data: code,
|
|
618
|
+
custom_inputs: customInputs,
|
|
619
|
+
context: stepContext,
|
|
620
|
+
slugs_executions: resultMap,
|
|
621
|
+
},
|
|
622
|
+
}, signal)
|
|
623
|
+
const scriptResult = await aiClient.getScriptStepStatus(script_execution_id)
|
|
624
|
+
progress?.onStepChange?.({ step: step.slug, ...scriptResult, ...{ statusResult: 'END' } })
|
|
625
|
+
resultMap[step.slug] = scriptResult
|
|
626
|
+
}
|
|
627
|
+
catch (error: any) {
|
|
628
|
+
progress?.onStepChange?.({ step: step.slug, ...error, statusResult: 'ERROR', ...resultMap })
|
|
629
|
+
let message = error.result?.error ?? error.message ?? `${error}`
|
|
630
|
+
if (error instanceof StackspotAPIError) message = error.translate()
|
|
631
|
+
throw new Error(`Failed to execute step "${step.slug}" of quick command "${slug}". Error ${message}.`)
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
async runStepsRecursively(currentIndex: number, ctx: QCContextExecution, iteration: Record<string, number>,
|
|
636
|
+
progress?: QCProgressProps) {
|
|
637
|
+
const { qc, resultMap } = ctx
|
|
638
|
+
|
|
639
|
+
if (!qc.steps || currentIndex >= qc.steps?.length) return
|
|
640
|
+
progress?.update?.(currentIndex)
|
|
641
|
+
|
|
642
|
+
const currentStep = qc.steps[currentIndex]
|
|
643
|
+
|
|
644
|
+
if (currentStep.type === 'ROUTER') {
|
|
645
|
+
await aiClient.runRouterStep(ctx, currentIndex, iteration, progress)
|
|
646
|
+
return
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
const parsedStep = currentStep as QuickCommandStepFetchResponse | QuickCommandStepLlmResponse
|
|
650
|
+
let nextIndex = currentIndex + 1
|
|
651
|
+
let nextStepSlug = parsedStep.next_step_slug
|
|
652
|
+
|
|
653
|
+
if (currentStep.type === 'SCRIPT') {
|
|
654
|
+
await aiClient.runScriptStep(ctx, currentIndex, progress)
|
|
655
|
+
} else if (currentStep.type === 'FETCH') {
|
|
656
|
+
await aiClient.runFetchStep(ctx, currentIndex, progress)
|
|
657
|
+
} else {
|
|
658
|
+
try {
|
|
659
|
+
await aiClient.runLLMStep(ctx, currentIndex, progress)
|
|
660
|
+
} catch (error: any) {
|
|
661
|
+
progress?.onStepChange?.({ step: currentStep.slug,
|
|
662
|
+
error: error, answer: JSON.stringify(error), statusResult: 'ERROR', ...resultMap })
|
|
663
|
+
}
|
|
664
|
+
const stepResult = resultMap[currentStep.slug] as QuickCommandPromptResponse
|
|
665
|
+
|
|
666
|
+
//When we have an error but there is an error path defined
|
|
667
|
+
if (typeof stepResult !== 'string' && stepResult.answer_status?.next_step_slug) {
|
|
668
|
+
nextStepSlug = stepResult?.answer_status?.next_step_slug
|
|
669
|
+
} else if (!stepResult?.answer_status?.success) { //When we have an error but no error path defined we should fail the execution
|
|
670
|
+
progress?.onStepChange?.({
|
|
671
|
+
step: currentStep.slug, error: stepResult?.answer_status,
|
|
672
|
+
answer: JSON.stringify(stepResult?.answer_status?.failure_message), statusResult: 'ERROR', ...resultMap })
|
|
673
|
+
throw new Error()
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
const stepResult = ctx.resultMap[currentStep.slug]
|
|
678
|
+
if (stepResult && typeof stepResult !== 'string' && 'answer_status' in stepResult && !!stepResult.answer_status?.next_step_slug) {
|
|
679
|
+
nextStepSlug = stepResult.answer_status.next_step_slug
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
if (nextStepSlug) {
|
|
683
|
+
nextIndex = nextStepSlug === 'end' ?
|
|
684
|
+
qc.steps.length : qc.steps?.findIndex((step) => step.slug === nextStepSlug)
|
|
685
|
+
}
|
|
686
|
+
await aiClient.runStepsRecursively(nextIndex, ctx, iteration, progress)
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
async formatResult({ qc, code, executionId, context, resultMap, customInputs, signal }: QCContextExecution) {
|
|
690
|
+
const formatted = await aiClient.formatResultOfQuickCommand.mutate({
|
|
691
|
+
slug: qc.slug,
|
|
692
|
+
quickCommandsExecutionRequest: {
|
|
693
|
+
input_data: code,
|
|
694
|
+
context,
|
|
695
|
+
qc_execution_id: executionId,
|
|
696
|
+
slugs_executions: { ...resultMap, ...customInputs },
|
|
697
|
+
},
|
|
698
|
+
|
|
699
|
+
}, signal)
|
|
700
|
+
return formatted.result
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
/**
|
|
704
|
+
* This registers a quick command event in the backend (analytics).
|
|
705
|
+
*/
|
|
706
|
+
private async registerQCAnalyticsEvent({
|
|
707
|
+
qc, isRemote, executionId, code = '', context }: QCContextExecution, status: string, start: number) {
|
|
708
|
+
const now = new Date().getTime()
|
|
709
|
+
try {
|
|
710
|
+
await aiClient.createEvent.mutate({
|
|
711
|
+
body: [{
|
|
712
|
+
type: 'custom_quick_command_execution',
|
|
713
|
+
quick_command_event: {
|
|
714
|
+
type: qc.type || '',
|
|
715
|
+
duration_execution: now - start,
|
|
716
|
+
status_execution: status,
|
|
717
|
+
slug: qc.slug,
|
|
718
|
+
qc_execution_id: executionId,
|
|
719
|
+
id: qc.id,
|
|
720
|
+
is_remote: isRemote,
|
|
721
|
+
},
|
|
722
|
+
code,
|
|
723
|
+
context,
|
|
724
|
+
knowledge_sources: [],
|
|
725
|
+
size: getSizeOfString(code),
|
|
726
|
+
generated_at: now,
|
|
727
|
+
}],
|
|
728
|
+
})
|
|
729
|
+
} catch (error) {
|
|
730
|
+
// eslint-disable-next-line no-console
|
|
731
|
+
console.warn('Failed to register event: quick command.')
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
async runQuickCommand(ctx: QCContext, progress?: QCProgressProps) {
|
|
736
|
+
const start = new Date().getTime()
|
|
737
|
+
|
|
738
|
+
const { slug } = ctx
|
|
739
|
+
const qc = await aiClient.quickCommand.query({ slug })
|
|
740
|
+
const ctxExecution: QCContextExecution = { ...ctx, qc }
|
|
741
|
+
try {
|
|
742
|
+
await aiClient.runStepsRecursively(0, ctxExecution, {}, progress)
|
|
743
|
+
progress?.remove?.()
|
|
744
|
+
const result = await aiClient.formatResult(ctxExecution)
|
|
745
|
+
await aiClient.registerQCAnalyticsEvent(ctxExecution, '200', start)
|
|
746
|
+
return result
|
|
747
|
+
} catch (error: any) {
|
|
748
|
+
let message = error.message || `${error}`
|
|
749
|
+
if (error instanceof StackspotAPIError) message = error.translate()
|
|
750
|
+
await aiClient.registerQCAnalyticsEvent(ctxExecution, message, start)
|
|
751
|
+
throw error
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
|
|
360
755
|
sendChatMessage(request: FixedChatRequest, minChangeIntervalMS?: number): StreamedJson<ChatResponseWithSteps> {
|
|
361
756
|
const abortController = new AbortController()
|
|
362
757
|
const headers = {
|
|
@@ -380,7 +775,7 @@ class AIClient extends ReactQueryNetworkClient {
|
|
|
380
775
|
async function transform(event: Partial<FixedChatResponse>, data: Partial<ChatResponseWithSteps>) {
|
|
381
776
|
const info = event.agent_info
|
|
382
777
|
if (!info) return
|
|
383
|
-
const tools = await AIClient.toolsOfAgent(request.context?.agent_id)
|
|
778
|
+
const tools = await AIClient.toolsOfAgent(request.context?.agent_id, request.agent_version_number ?? undefined)
|
|
384
779
|
data.steps = data.steps ? [...data.steps] : []
|
|
385
780
|
|
|
386
781
|
if (info.type === 'planning' && info.action === 'end') {
|
|
@@ -602,6 +997,7 @@ class AIClient extends ReactQueryNetworkClient {
|
|
|
602
997
|
FixedDependencyResponse
|
|
603
998
|
>,
|
|
604
999
|
))
|
|
1000
|
+
|
|
605
1001
|
}
|
|
606
1002
|
|
|
607
1003
|
export const aiClient = new AIClient()
|
package/src/client/types.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { RequestOpts } from '@oazapfts/runtime'
|
|
2
2
|
import { AccountScmInfoSaveRequest, AccountScmInfoUpdateRequest, AccountScmStatusResponse, GroupsFromResourceResponse, MembersFromResourceResponse } from '../api/account'
|
|
3
3
|
import { AgentVisibilityLevelEnum, HttpMethod, ListAgentResponse, VisibilityLevelEnum } from '../api/agent-tools'
|
|
4
|
-
import { ChatRequest, ChatResponse3, ContentDependencyResponse, ConversationHistoryResponse, ConversationResponse, DependencyResponse } from '../api/ai'
|
|
4
|
+
import { ChatRequest, ChatResponse3, ContentDependencyResponse, ConversationHistoryResponse, ConversationResponse, DependencyResponse, QuickCommandResponse, QuickCommandStepResult } from '../api/ai'
|
|
5
5
|
import { ConnectAccountRequestV2, ManagedAccountProvisionRequest } from '../api/cloudAccount'
|
|
6
6
|
import { AllocationCostRequest, AllocationCostResponse, ChargePeriod, getAllocationCostFilters, ManagedService, ServiceResource } from '../api/cloudServices'
|
|
7
7
|
import { Action } from '../api/workspace-ai'
|
|
@@ -421,3 +421,32 @@ export interface AgentToolsOpenAPIPreview {
|
|
|
421
421
|
parameters?: Record<string, any>,
|
|
422
422
|
request_body?: Record<string, any>,
|
|
423
423
|
}
|
|
424
|
+
|
|
425
|
+
type SlugExecution = Record<string, QuickCommandStepResult>
|
|
426
|
+
|
|
427
|
+
|
|
428
|
+
interface BaseQCContext {
|
|
429
|
+
context: Required<FixedChatRequest>['context'],
|
|
430
|
+
resultMap: SlugExecution,
|
|
431
|
+
customInputs: Record<string, string>,
|
|
432
|
+
code?: string,
|
|
433
|
+
executionId: string,
|
|
434
|
+
signal: AbortSignal,
|
|
435
|
+
isRemote?: boolean,
|
|
436
|
+
headers?: Record<string, string>,
|
|
437
|
+
conversation_id?: string,
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
export interface QCContext extends BaseQCContext {
|
|
441
|
+
slug: string,
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
export interface QCContextExecution extends BaseQCContext {
|
|
445
|
+
qc: QuickCommandResponse,
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
export interface QCProgressProps{
|
|
449
|
+
update?: (index: number) => void,
|
|
450
|
+
remove?: () => void,
|
|
451
|
+
onStepChange?: (stepResult: any) => void,
|
|
452
|
+
}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { HttpError } from '@oazapfts/runtime'
|
|
2
|
-
import {
|
|
2
|
+
import { getApiAddresses } from '../api-addresses'
|
|
3
3
|
import { CustomToolkitResponse } from '../api/agent-tools'
|
|
4
|
-
import { GetAiStackResponse,
|
|
4
|
+
import { GetAiStackResponse, QuickCommandResponse } from '../api/ai'
|
|
5
|
+
import { KnowledgeSourceItemResponse } from '../api/dataIntegration'
|
|
5
6
|
import {
|
|
6
7
|
addContentV1WorkspacesWorkspaceIdContentTypePost,
|
|
8
|
+
addContentV2WorkspacesWorkspaceIdContentTypePost,
|
|
7
9
|
addFavoriteV1WorkspacesWorkspaceIdFavoritePost,
|
|
8
10
|
addPermissionV1ResourceTypeResourceTypeResourcesResourceIdentifierPatch,
|
|
9
11
|
addPermissionV1WorkspacesWorkspaceIdPermissionsPatch,
|
|
@@ -24,13 +26,12 @@ import {
|
|
|
24
26
|
updateWorkspaceV1WorkspacesWorkspaceIdPatch,
|
|
25
27
|
useShareableLinkV1ShareShareIdPatch,
|
|
26
28
|
} from '../api/workspace-ai'
|
|
29
|
+
import { DefaultAPIError } from '../error/DefaultAPIError'
|
|
30
|
+
import { wksAiDictionary } from '../error/dictionary/workspace-ai'
|
|
27
31
|
import { StackspotAPIError } from '../error/StackspotAPIError'
|
|
28
32
|
import { ReactQueryNetworkClient } from '../network/ReactQueryNetworkClient'
|
|
29
33
|
import { removeAuthorizationParam } from '../utils/remove-authorization-param'
|
|
30
|
-
import {
|
|
31
|
-
import { DefaultAPIError } from '../error/DefaultAPIError'
|
|
32
|
-
import { wksAiDictionary } from '../error/dictionary/workspace-ai'
|
|
33
|
-
import { FixedAddResourceToWorkspaceAi, FixedWorkspaceAiPermissions, ReplaceResult } from './types'
|
|
34
|
+
import { AgentResponseWithBuiltIn, FixedAddResourceToWorkspaceAi, FixedWorkspaceAiPermissions, ReplaceResult } from './types'
|
|
34
35
|
|
|
35
36
|
class WorkspaceAiClient extends ReactQueryNetworkClient {
|
|
36
37
|
constructor() {
|
|
@@ -48,6 +49,7 @@ class WorkspaceAiClient extends ReactQueryNetworkClient {
|
|
|
48
49
|
deleteWorkspaceAi = this.mutation(removeAuthorizationParam(deleteWorkspaceV1WorkspacesWorkspaceIdDelete))
|
|
49
50
|
|
|
50
51
|
/**
|
|
52
|
+
* @deprecated
|
|
51
53
|
* Adds a resource to the Spot.
|
|
52
54
|
*/
|
|
53
55
|
addResourceTypeToWorkspaceAi = this.mutation({
|
|
@@ -61,6 +63,20 @@ class WorkspaceAiClient extends ReactQueryNetworkClient {
|
|
|
61
63
|
permission: this.createPermissionFunctionFor(addContentV1WorkspacesWorkspaceIdContentTypePost),
|
|
62
64
|
})
|
|
63
65
|
|
|
66
|
+
/**
|
|
67
|
+
* V2 for adding a resource to the Spot.
|
|
68
|
+
*/
|
|
69
|
+
addResourceTypeV2ToSpot = this.mutation({
|
|
70
|
+
name: 'addResourceTypeToWorkspaceAi',
|
|
71
|
+
request: (
|
|
72
|
+
signal,
|
|
73
|
+
variables: Omit<Parameters<typeof addContentV2WorkspacesWorkspaceIdContentTypePost>[0], 'authorization'>,
|
|
74
|
+
) =>
|
|
75
|
+
addContentV2WorkspacesWorkspaceIdContentTypePost({ ...variables, authorization: '' },
|
|
76
|
+
{ signal }) as unknown as Promise<FixedAddResourceToWorkspaceAi>,
|
|
77
|
+
permission: this.createPermissionFunctionFor(addContentV2WorkspacesWorkspaceIdContentTypePost),
|
|
78
|
+
})
|
|
79
|
+
|
|
64
80
|
/**
|
|
65
81
|
* Lists all the knowledge sources in a Spot.
|
|
66
82
|
*/
|
|
@@ -117,7 +133,7 @@ class WorkspaceAiClient extends ReactQueryNetworkClient {
|
|
|
117
133
|
'authorization' | 'contentType'>,
|
|
118
134
|
) =>
|
|
119
135
|
listAllByContentTypeV1WorkspacesWorkspaceIdContentTypeGet({ ...variables, contentType: 'agent', authorization: '' },
|
|
120
|
-
{ signal }) as unknown as Promise<
|
|
136
|
+
{ signal }) as unknown as Promise<AgentResponseWithBuiltIn[]>,
|
|
121
137
|
permission: this.createPermissionFunctionFor(listAllByContentTypeV1WorkspacesWorkspaceIdContentTypeGet),
|
|
122
138
|
})
|
|
123
139
|
|
package/src/utils/string.ts
CHANGED
|
@@ -17,3 +17,15 @@ export function formatJson(data: any): string {
|
|
|
17
17
|
}
|
|
18
18
|
return JSON.stringify(data, null, 2)
|
|
19
19
|
}
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Gets the size of a string removing control characters and spaces
|
|
24
|
+
* @param str the string to count.
|
|
25
|
+
* @returns the count value.
|
|
26
|
+
*/
|
|
27
|
+
export function getSizeOfString(str: string): number {
|
|
28
|
+
// eslint-disable-next-line no-control-regex
|
|
29
|
+
const withoutSpacesAndControls = str.replace(/[\u0000-\u001F\u007F-\u009F\u061C\u200E\u200F\u202A-\u202E\u2066-\u2069\s]/g, '')
|
|
30
|
+
return withoutSpacesAndControls.length
|
|
31
|
+
}
|