@stack-spot/portal-network 0.201.0-beta.1 → 0.202.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.
- package/CHANGELOG.md +44 -5
- package/dist/api/accountAssetManager.d.ts +16 -0
- package/dist/api/accountAssetManager.d.ts.map +1 -1
- package/dist/api/accountAssetManager.js.map +1 -1
- package/dist/api/codeShift.d.ts +6 -1
- package/dist/api/codeShift.d.ts.map +1 -1
- package/dist/api/codeShift.js +5 -2
- package/dist/api/codeShift.js.map +1 -1
- package/dist/api-addresses.d.ts.map +1 -1
- package/dist/api-addresses.js +1 -0
- package/dist/api-addresses.js.map +1 -1
- package/dist/client/agent-tools.d.ts.map +1 -1
- package/dist/client/agent-tools.js +9 -6
- package/dist/client/agent-tools.js.map +1 -1
- package/dist/client/ai.d.ts.map +1 -1
- package/dist/client/ai.js +57 -16
- package/dist/client/ai.js.map +1 -1
- package/dist/client/code-shift.d.ts +2 -0
- package/dist/client/code-shift.d.ts.map +1 -1
- package/dist/client/types.d.ts +11 -3
- package/dist/client/types.d.ts.map +1 -1
- package/dist/network/NetworkClient.js +7 -6
- package/dist/network/NetworkClient.js.map +1 -1
- package/package.json +2 -2
- package/src/api/accountAssetManager.ts +112 -12
- package/src/api/codeShift.ts +10 -2
- package/src/api-addresses.ts +1 -0
- package/src/client/agent-tools.ts +11 -8
- package/src/client/ai.ts +63 -19
- package/src/client/types.ts +12 -3
- package/src/network/NetworkClient.ts +7 -7
package/src/client/ai.ts
CHANGED
|
@@ -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
|
|
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
|
|
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
|
-
//
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
currentStep.attempts[
|
|
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
|
-
|
|
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
|
|
538
|
-
if (
|
|
539
|
-
|
|
540
|
-
|
|
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
|
}
|
package/src/client/types.ts
CHANGED
|
@@ -247,6 +247,7 @@ export interface ChatAgentTool {
|
|
|
247
247
|
input?: string,
|
|
248
248
|
output?: string,
|
|
249
249
|
goal?: string,
|
|
250
|
+
status?: 'running' | 'success' | 'error',
|
|
250
251
|
}
|
|
251
252
|
|
|
252
253
|
export interface ChatStepAttempt {
|
|
@@ -308,10 +309,10 @@ export interface AnswerChatStep extends BaseChatStep {
|
|
|
308
309
|
export type ChatStep = PlanningChatStep | StepChatStep | AnswerChatStep | ToolChatStep
|
|
309
310
|
|
|
310
311
|
export interface BaseAgentInfo {
|
|
311
|
-
type: 'chat' | 'planning' | 'step' | 'tool' | 'final_answer',
|
|
312
|
+
type: 'chat' | 'planning' | 'step' | 'tool' | 'final_answer' | 'tool_calls',
|
|
312
313
|
action: 'start' | 'end' | 'awaiting_approval',
|
|
313
314
|
duration?: number,
|
|
314
|
-
id
|
|
315
|
+
id?: string,
|
|
315
316
|
}
|
|
316
317
|
|
|
317
318
|
export interface AgentTool {
|
|
@@ -355,7 +356,15 @@ export interface GenericAgentInfo extends BaseAgentInfo {
|
|
|
355
356
|
type: 'chat' | 'final_answer',
|
|
356
357
|
}
|
|
357
358
|
|
|
358
|
-
export
|
|
359
|
+
export interface ToolCallsAgentInfo extends BaseAgentInfo {
|
|
360
|
+
type: 'tool_calls',
|
|
361
|
+
data?: {
|
|
362
|
+
tools?: string[],
|
|
363
|
+
duration?: number,
|
|
364
|
+
},
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
export type AgentInfo = GenericAgentInfo | PlanningAgentInfo | StepAgentInfo | ToolAgentInfo | ToolCallsAgentInfo
|
|
359
368
|
|
|
360
369
|
export interface FixedChatResponse extends ChatResponse3 {
|
|
361
370
|
agent_info: AgentInfo,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AuthenticationError, SessionExpiredError } from '@stack-spot/auth'
|
|
1
|
+
import { AuthenticationError, Session, SessionExpiredError } from '@stack-spot/auth'
|
|
2
2
|
import { requestPermission, setup as setupPermissions } from '@stack-spot/opa'
|
|
3
3
|
import { events } from 'fetch-event-stream'
|
|
4
4
|
import { getApisBaseUrlConfig, getBaseUrlByTenantWithOverride, getPermissionsAPIMap } from '../api-addresses'
|
|
@@ -44,12 +44,12 @@ export abstract class NetworkClient {
|
|
|
44
44
|
NetworkClient.tenant = tenant
|
|
45
45
|
const url = getApisBaseUrlConfig(env, tenant).permissionValidation
|
|
46
46
|
const apiMap = getPermissionsAPIMap(env, tenant)
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
47
|
+
const onChange = (session?: Session) => {
|
|
48
|
+
queryClient.invalidateQueries()
|
|
49
|
+
session && setupPermissions({ url, session, apiMap })
|
|
50
|
+
}
|
|
51
|
+
sessionManager.onChange?.(onChange)
|
|
52
|
+
if (sessionManager.hasSession()) onChange(sessionManager.getSession())
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
/**
|