@stack-spot/portal-network 0.194.1 → 0.195.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 (95) hide show
  1. package/CHANGELOG.md +181 -0
  2. package/dist/api/agent-tools.d.ts +6 -0
  3. package/dist/api/agent-tools.d.ts.map +1 -1
  4. package/dist/api/agent-tools.js.map +1 -1
  5. package/dist/api/agent.d.ts +55 -55
  6. package/dist/api/agent.d.ts.map +1 -1
  7. package/dist/api/ai.d.ts +189 -86
  8. package/dist/api/ai.d.ts.map +1 -1
  9. package/dist/api/ai.js +238 -142
  10. package/dist/api/ai.js.map +1 -1
  11. package/dist/api/cloudPlatform.d.ts +70 -129
  12. package/dist/api/cloudPlatform.d.ts.map +1 -1
  13. package/dist/api/cloudPlatform.js +79 -72
  14. package/dist/api/cloudPlatform.js.map +1 -1
  15. package/dist/api/codeShift.d.ts +315 -62
  16. package/dist/api/codeShift.d.ts.map +1 -1
  17. package/dist/api/codeShift.js +153 -12
  18. package/dist/api/codeShift.js.map +1 -1
  19. package/dist/api/discover.d.ts +23 -12
  20. package/dist/api/discover.d.ts.map +1 -1
  21. package/dist/api/discover.js +10 -0
  22. package/dist/api/discover.js.map +1 -1
  23. package/dist/api-addresses.d.ts.map +1 -1
  24. package/dist/client/account.d.ts +233 -233
  25. package/dist/client/account.d.ts.map +1 -1
  26. package/dist/client/agent-tools.d.ts +124 -124
  27. package/dist/client/agent-tools.d.ts.map +1 -1
  28. package/dist/client/agent-tools.js +10 -1
  29. package/dist/client/agent-tools.js.map +1 -1
  30. package/dist/client/agent.d.ts +46 -46
  31. package/dist/client/agent.d.ts.map +1 -1
  32. package/dist/client/ai.d.ts +123 -77
  33. package/dist/client/ai.d.ts.map +1 -1
  34. package/dist/client/ai.js +47 -2
  35. package/dist/client/ai.js.map +1 -1
  36. package/dist/client/api-management.d.ts +2 -2
  37. package/dist/client/cloud-account.d.ts +13 -13
  38. package/dist/client/cloud-platform-horizon.d.ts +19 -19
  39. package/dist/client/cloud-platform.d.ts +114 -89
  40. package/dist/client/cloud-platform.d.ts.map +1 -1
  41. package/dist/client/cloud-platform.js +73 -46
  42. package/dist/client/cloud-platform.js.map +1 -1
  43. package/dist/client/cloud-runtimes.d.ts +4 -4
  44. package/dist/client/cloud-services.d.ts +17 -17
  45. package/dist/client/cloud-services.d.ts.map +1 -1
  46. package/dist/client/code-shift.d.ts +356 -258
  47. package/dist/client/code-shift.d.ts.map +1 -1
  48. package/dist/client/code-shift.js +91 -1
  49. package/dist/client/code-shift.js.map +1 -1
  50. package/dist/client/content.d.ts +127 -132
  51. package/dist/client/content.d.ts.map +1 -1
  52. package/dist/client/data-integration.d.ts +55 -55
  53. package/dist/client/data-integration.d.ts.map +1 -1
  54. package/dist/client/discover.d.ts +15 -9
  55. package/dist/client/discover.d.ts.map +1 -1
  56. package/dist/client/discover.js +208 -0
  57. package/dist/client/discover.js.map +1 -1
  58. package/dist/client/event-bus.d.ts.map +1 -1
  59. package/dist/client/gen-ai-inference.d.ts +20 -20
  60. package/dist/client/insights.d.ts +7 -7
  61. package/dist/client/notification.d.ts +10 -10
  62. package/dist/client/runtime-manager.d.ts +8 -8
  63. package/dist/client/types.d.ts +14 -0
  64. package/dist/client/types.d.ts.map +1 -1
  65. package/dist/client/workflow.d.ts +10 -10
  66. package/dist/client/workspace-ai.d.ts +48 -48
  67. package/dist/client/workspace-manager.d.ts +77 -77
  68. package/dist/client/workspace-search.d.ts +2 -2
  69. package/dist/client/workspace.d.ts +58 -105
  70. package/dist/client/workspace.d.ts.map +1 -1
  71. package/dist/error/dictionary/cloud-platform.d.ts +6 -0
  72. package/dist/error/dictionary/cloud-platform.d.ts.map +1 -1
  73. package/dist/error/dictionary/cloud-platform.js +6 -0
  74. package/dist/error/dictionary/cloud-platform.js.map +1 -1
  75. package/dist/utils/StreamedJson.d.ts.map +1 -1
  76. package/dist/utils/StreamedJson.js +9 -1
  77. package/dist/utils/StreamedJson.js.map +1 -1
  78. package/package.json +2 -2
  79. package/readme.md +2 -1
  80. package/src/api/account.ts +1 -0
  81. package/src/api/agent-tools.ts +9 -0
  82. package/src/api/agent.ts +2 -0
  83. package/src/api/ai.ts +364 -157
  84. package/src/api/cloudPlatform.ts +142 -216
  85. package/src/api/codeShift.ts +607 -69
  86. package/src/api/discover.ts +35 -12
  87. package/src/api/notification.ts +2 -0
  88. package/src/client/agent-tools.ts +10 -1
  89. package/src/client/ai.ts +42 -1
  90. package/src/client/cloud-platform.ts +40 -25
  91. package/src/client/code-shift.ts +54 -1
  92. package/src/client/discover.ts +220 -3
  93. package/src/client/types.ts +17 -2
  94. package/src/error/dictionary/cloud-platform.ts +6 -0
  95. package/src/utils/StreamedJson.tsx +9 -2
@@ -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()
@@ -361,10 +361,25 @@ export interface FixedChatResponse extends ChatResponse3 {
361
361
  agent_info: AgentInfo,
362
362
  tools?: string[],
363
363
  }
364
+ export interface OpportunitiesPMAgent {
365
+ title: string,
366
+ description: string,
367
+ }
368
+
369
+ export type HypothesisPMAgent = OpportunitiesPMAgent
364
370
 
371
+ export type PrfaqPMAgent = {
372
+ title: string,
373
+ content: string,
374
+ }
365
375
  export interface ChatResponseWithSteps extends FixedChatResponse {
366
376
  steps: ChatStep[],
367
377
  }
378
+ export interface ChatResponseWithPMResources {
379
+ opportunities?: OpportunitiesPMAgent[],
380
+ hypothesis?: HypothesisPMAgent[],
381
+ prfaq?: PrfaqPMAgent,
382
+ }
368
383
 
369
384
  export type OazapftsFunction<Variables = any, Result = any> = (variables: Variables, opts?: RequestOpts) => Promise<Result>
370
385
 
@@ -380,12 +395,12 @@ export type FixVariables<
380
395
 
381
396
  export type ReplaceResult<T extends (...args: any[]) => Promise<any>, Fix> = (...args: Parameters<T>) => Promise<Fix>
382
397
 
383
- export interface AgentResponseWithBuiltIn extends Omit<ListAgentResponse, 'conversation_starter' | 'avatar'> {
398
+ export interface AgentResponseWithBuiltIn extends Omit<ListAgentResponse, 'conversation_starter' | 'avatar'> {
384
399
  builtIn?: boolean,
385
400
  spaceName?: string,
386
401
  conversation_starter?: string[] | null,
387
402
  avatar?: string | null | undefined,
388
- }
403
+ }
389
404
 
390
405
  export type AgentVisibilityLevel = AgentVisibilityLevelEnum | VisibilityLevelEnum
391
406
 
@@ -39,6 +39,9 @@ export const scfDictionary = {
39
39
  SCF_VPN_ERROR: 'VPN operation failed.',
40
40
  SCF_VPN_NOT_FOUND_ERROR: 'VPN with ID {1} not found.',
41
41
  SCF_VPN_NOT_READY_ERROR: 'VPN with ID {1} not ready.',
42
+ SCF_DNS_ZONE_NOT_EMPTY_ERROR: 'DNS Zone with ID {1} is not empty.',
43
+ SCF_FOLDER_NOT_EMPTY_ERROR: 'Folder with ID {1} is not empty.',
44
+ SCF_PROJECT_NOT_EMPTY_ERROR: 'Project with ID {1} is not empty.',
42
45
  },
43
46
  pt: {
44
47
  SCF_CERTIFICATE_ERROR: 'Falha na operação de Certificado.',
@@ -78,5 +81,8 @@ export const scfDictionary = {
78
81
  SCF_VPN_ERROR: 'Falha na operação de VPN.',
79
82
  SCF_VPN_NOT_FOUND_ERROR: 'VPN com ID {1} não encontrada.',
80
83
  SCF_VPN_NOT_READY_ERROR: 'VPN com ID {1} não está pronta.',
84
+ SCF_DNS_ZONE_NOT_EMPTY_ERROR: 'DNS Zone com ID {1} não está vazia.',
85
+ SCF_FOLDER_NOT_EMPTY_ERROR: 'Folder com ID {1} não está vazia.',
86
+ SCF_PROJECT_NOT_EMPTY_ERROR: 'Project com ID {1} não está vazia.',
81
87
  },
82
88
  } satisfies Dictionary
@@ -64,7 +64,14 @@ export class StreamedJson<T> {
64
64
  for await (const event of events) {
65
65
  if (this.error) return
66
66
  if (event.data) {
67
- const json = JSON.parse(event.data)
67
+ let json
68
+ try {
69
+ json = JSON.parse(event.data)
70
+ } catch (e) {
71
+ // eslint-disable-next-line no-console
72
+ console.warn('Mal formed JSON in streaming:', event.data)
73
+ continue
74
+ }
68
75
  await this.transform?.(json, this.data)
69
76
  this.merge(json, this.data)
70
77
  if (new Date().getTime() - lastChangeCall >= minChangeIntervalMS) {
@@ -138,7 +145,7 @@ export class StreamedJson<T> {
138
145
  onChange(listener: (value: Partial<T>) => void) {
139
146
  if (this.fullPromise.resolved) {
140
147
  listener(this.data)
141
- return () => {}
148
+ return () => { }
142
149
  }
143
150
  this.onChangeListeners.push(listener)
144
151
  return () => {