@stack-spot/ai-chat-widget 1.31.2-beta.1 → 1.32.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/CHANGELOG.md +25 -7
- package/dist/app-metadata.json +3 -3
- package/dist/chat-interceptors/quick-commands.d.ts.map +1 -1
- package/dist/chat-interceptors/quick-commands.js +16 -71
- package/dist/chat-interceptors/quick-commands.js.map +1 -1
- package/dist/components/RightPanelContentList.d.ts +10 -0
- package/dist/components/RightPanelContentList.d.ts.map +1 -0
- package/dist/components/RightPanelContentList.js +7 -0
- package/dist/components/RightPanelContentList.js.map +1 -0
- package/dist/components/Selector/index.d.ts.map +1 -1
- package/dist/components/Selector/index.js +3 -2
- package/dist/components/Selector/index.js.map +1 -1
- package/dist/features.d.ts +15 -0
- package/dist/features.d.ts.map +1 -1
- package/dist/features.js +1 -0
- package/dist/features.js.map +1 -1
- package/dist/layout.css +5 -1
- package/dist/state/constants.js +1 -1
- package/dist/state/constants.js.map +1 -1
- package/dist/views/Agents/AgentDescription.js +1 -1
- package/dist/views/Agents/AgentDescription.js.map +1 -1
- package/dist/views/Agents/AgentsPanel.d.ts.map +1 -1
- package/dist/views/Agents/AgentsPanel.js +24 -15
- package/dist/views/Agents/AgentsPanel.js.map +1 -1
- package/dist/views/Agents/AgentsTab.d.ts +1 -1
- package/dist/views/Agents/AgentsTab.d.ts.map +1 -1
- package/dist/views/Agents/dictionary.d.ts +1 -1
- package/dist/views/ChatHistory/HistoryItem.d.ts.map +1 -1
- package/dist/views/ChatHistory/HistoryItem.js +3 -1
- package/dist/views/ChatHistory/HistoryItem.js.map +1 -1
- package/dist/views/KSDocument.d.ts.map +1 -1
- package/dist/views/KSDocument.js +2 -1
- package/dist/views/KSDocument.js.map +1 -1
- package/dist/views/KnowledgeSources.d.ts +1 -1
- package/dist/views/KnowledgeSources.d.ts.map +1 -1
- package/dist/views/KnowledgeSources.js +24 -11
- package/dist/views/KnowledgeSources.js.map +1 -1
- package/dist/views/MessageInput/AgentSelector.d.ts.map +1 -1
- package/dist/views/MessageInput/AgentSelector.js +6 -2
- package/dist/views/MessageInput/AgentSelector.js.map +1 -1
- package/dist/views/MessageInput/QuickCommandSelector.d.ts.map +1 -1
- package/dist/views/MessageInput/QuickCommandSelector.js +9 -4
- package/dist/views/MessageInput/QuickCommandSelector.js.map +1 -1
- package/dist/views/Stacks.d.ts +1 -1
- package/dist/views/Stacks.d.ts.map +1 -1
- package/dist/views/Stacks.js +21 -11
- package/dist/views/Stacks.js.map +1 -1
- package/package.json +2 -2
- package/src/app-metadata.json +3 -3
- package/src/chat-interceptors/quick-commands.ts +18 -84
- package/src/components/RightPanelContentList.tsx +15 -0
- package/src/components/Selector/index.tsx +8 -6
- package/src/features.ts +17 -0
- package/src/index.ts +1 -0
- package/src/layout.css +5 -1
- package/src/state/constants.ts +1 -1
- package/src/views/Agents/AgentDescription.tsx +1 -1
- package/src/views/Agents/AgentsPanel.tsx +36 -17
- package/src/views/Agents/AgentsTab.tsx +1 -1
- package/src/views/ChatHistory/HistoryItem.tsx +2 -1
- package/src/views/KSDocument.tsx +2 -1
- package/src/views/KnowledgeSources.tsx +38 -14
- package/src/views/MessageInput/AgentSelector.tsx +9 -3
- package/src/views/MessageInput/QuickCommandSelector.tsx +18 -5
- package/src/views/Stacks.tsx +34 -14
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { aiClient, CancelledError, FixedChatRequest, StackspotAPIError } from '@stack-spot/portal-network'
|
|
2
|
-
import { QuickCommandFetchResponseResult, QuickCommandPromptResponse2, QuickCommandResponse, QuickCommandStepFetchResponse
|
|
2
|
+
import { QuickCommandFetchResponseResult, QuickCommandPromptResponse2, QuickCommandResponse, QuickCommandStepFetchResponse } from '@stack-spot/portal-network/api/ai'
|
|
3
3
|
import { Dictionary, interpolate, translate } from '@stack-spot/portal-translate'
|
|
4
4
|
import type { editor } from 'monaco-editor'
|
|
5
5
|
import { ulid } from 'ulid'
|
|
@@ -13,13 +13,12 @@ import { buildConversationContext } from '../utils/chat'
|
|
|
13
13
|
import { getSizeOfString } from '../utils/string'
|
|
14
14
|
import { CustomInputs } from './CustomInputs'
|
|
15
15
|
|
|
16
|
-
type SlugExecution = Record<string, QuickCommandFetchResponseResult | QuickCommandPromptResponse2>
|
|
16
|
+
type SlugExecution = Record<string, string | QuickCommandFetchResponseResult | QuickCommandPromptResponse2>
|
|
17
17
|
|
|
18
18
|
interface QCContext {
|
|
19
19
|
qc: QuickCommandResponse,
|
|
20
20
|
context: Required<FixedChatRequest>['context'],
|
|
21
21
|
resultMap: SlugExecution,
|
|
22
|
-
customInputs: Record<string, string>,
|
|
23
22
|
chat: ChatState,
|
|
24
23
|
code?: string,
|
|
25
24
|
executionId: string,
|
|
@@ -65,61 +64,21 @@ export function createQuickCommandInterceptor(widget: WidgetState, getEditor: ()
|
|
|
65
64
|
const inputsValues = await customInputs.getValue()
|
|
66
65
|
chat.set('isLoading', true)
|
|
67
66
|
CustomInputs.deleteCustomInputsFromChat(chat)
|
|
68
|
-
ctx.
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Runs an Router step of a quick command.
|
|
73
|
-
*/
|
|
74
|
-
async function runRouterStep(
|
|
75
|
-
ctx: QCContext,
|
|
76
|
-
stepIndex: number, iteration: number,
|
|
77
|
-
progress: { update: (index: number) => void, remove: () => void },
|
|
78
|
-
) {
|
|
79
|
-
const { qc: { slug, steps }, code, resultMap, customInputs } = ctx
|
|
80
|
-
const step = steps![stepIndex]
|
|
81
|
-
const inputData = Object.keys(customInputs).length > 0 && code ? { ...customInputs, [code]: code } : code ?? customInputs
|
|
82
|
-
try {
|
|
83
|
-
const { next_step_slug } = await aiClient.calculateNextStep.mutate({
|
|
84
|
-
stepSlug: step.slug,
|
|
85
|
-
slug: slug,
|
|
86
|
-
quickCommandEvaluateStepRouterRequest: {
|
|
87
|
-
executions_count: iteration,
|
|
88
|
-
input_data: inputData,
|
|
89
|
-
slugs_executions: resultMap,
|
|
90
|
-
},
|
|
91
|
-
})
|
|
92
|
-
|
|
93
|
-
if (next_step_slug === step.slug) {
|
|
94
|
-
return runStepsRecursively(stepIndex, progress, ctx, iteration+1)
|
|
95
|
-
}
|
|
96
|
-
const nextStepIndex = steps?.findIndex((step) => step.slug === next_step_slug)
|
|
97
|
-
|
|
98
|
-
if (!nextStepIndex || nextStepIndex === -1) return
|
|
99
|
-
|
|
100
|
-
return runStepsRecursively(nextStepIndex, progress, ctx, iteration)
|
|
101
|
-
}
|
|
102
|
-
catch (error: any) {
|
|
103
|
-
// eslint-disable-next-line no-console
|
|
104
|
-
console.error('Error executing QC step', error)
|
|
105
|
-
}
|
|
67
|
+
ctx.resultMap = { ...ctx.resultMap, ...inputsValues }
|
|
106
68
|
}
|
|
107
69
|
|
|
108
70
|
/**
|
|
109
71
|
* Runs a fetch step of a quick command and puts the result in the `resultMap` of the context passed as parameter.
|
|
110
72
|
*/
|
|
111
73
|
async function runFetchStep(ctx: QCContext, stepIndex: number) {
|
|
112
|
-
const { qc: { slug, steps }, code, context, resultMap,
|
|
74
|
+
const { qc: { slug, steps }, code, context, resultMap, executionId, signal } = ctx
|
|
113
75
|
const step = steps![stepIndex] as QuickCommandStepFetchResponse
|
|
114
76
|
if (step.is_remote) {
|
|
115
77
|
ctx.isRemote = true
|
|
116
78
|
|
|
117
79
|
const { data } = await aiClient.fetchStepOfQuickCommandRemotely.mutate({
|
|
118
80
|
slug, stepSlug: step.slug,
|
|
119
|
-
quickCommandsExecutionRequest: {
|
|
120
|
-
code_selection: code, context, qc_execution_id: executionId,
|
|
121
|
-
slugs_executions: { ...resultMap, ...customInputs },
|
|
122
|
-
},
|
|
81
|
+
quickCommandsExecutionRequest: { code_selection: code, context, slugs_executions: resultMap, qc_execution_id: executionId },
|
|
123
82
|
})
|
|
124
83
|
|
|
125
84
|
//data is the return of the request in the QC so we do not have full control over the response
|
|
@@ -136,9 +95,7 @@ export function createQuickCommandInterceptor(widget: WidgetState, getEditor: ()
|
|
|
136
95
|
const { headers, data, method, url } = await aiClient.fetchStepOfQuickCommand.mutate({
|
|
137
96
|
slug,
|
|
138
97
|
stepSlug: step.slug,
|
|
139
|
-
quickCommandsExecutionRequest: { input_data: code, context, qc_execution_id: executionId,
|
|
140
|
-
slugs_executions: { ...resultMap, ...customInputs },
|
|
141
|
-
},
|
|
98
|
+
quickCommandsExecutionRequest: { input_data: code, context, slugs_executions: resultMap, qc_execution_id: executionId },
|
|
142
99
|
}, signal)
|
|
143
100
|
const body = ['get', 'head'].includes(method.toLowerCase()) ? undefined : data
|
|
144
101
|
const response = await fetch(url, { headers: headers || undefined, body, method, signal })
|
|
@@ -154,17 +111,12 @@ export function createQuickCommandInterceptor(widget: WidgetState, getEditor: ()
|
|
|
154
111
|
* Runs an LLM step of a quick command and puts the result in the `resultMap` of the context passed as parameter.
|
|
155
112
|
*/
|
|
156
113
|
async function runLLMStep(
|
|
157
|
-
{ qc: { slug, steps }, code,
|
|
114
|
+
{ qc: { slug, steps }, code, context, executionId, resultMap, signal }: QCContext,
|
|
158
115
|
stepIndex: number,
|
|
159
116
|
) {
|
|
160
117
|
const step = steps![stepIndex]
|
|
161
118
|
const stream = aiClient.streamLlmStepOfQuickCommand(
|
|
162
|
-
slug, step.slug, {
|
|
163
|
-
input_data: code,
|
|
164
|
-
context,
|
|
165
|
-
qc_execution_id: executionId,
|
|
166
|
-
slugs_executions: { ...resultMap, ...customInputs },
|
|
167
|
-
},
|
|
119
|
+
slug, step.slug, { input_data: code, context, qc_execution_id: executionId, slugs_executions: resultMap },
|
|
168
120
|
)
|
|
169
121
|
|
|
170
122
|
signal.addEventListener('abort', () => stream.cancel())
|
|
@@ -183,7 +135,7 @@ export function createQuickCommandInterceptor(widget: WidgetState, getEditor: ()
|
|
|
183
135
|
const t = translate(dictionary)
|
|
184
136
|
message.setValue({
|
|
185
137
|
...message.getValue(),
|
|
186
|
-
content: interpolate(t.progress, qc.steps?.[stepIndex]?.slug, qc.
|
|
138
|
+
content: interpolate(t.progress, qc.name || qc.slug, stepIndex + 1, qc.steps?.[stepIndex]?.slug, qc.steps?.length),
|
|
187
139
|
})
|
|
188
140
|
}
|
|
189
141
|
|
|
@@ -211,44 +163,27 @@ export function createQuickCommandInterceptor(widget: WidgetState, getEditor: ()
|
|
|
211
163
|
return controller
|
|
212
164
|
}
|
|
213
165
|
|
|
214
|
-
async function runStepsRecursively(currentIndex: number, progress: { update: (index: number) => void, remove: () => void },
|
|
215
|
-
ctx: QCContext, iteration: number) {
|
|
216
|
-
const { qc } = ctx
|
|
217
|
-
if (!qc.steps || currentIndex >= qc.steps?.length) return
|
|
218
|
-
progress.update(currentIndex)
|
|
219
|
-
|
|
220
|
-
if (qc.steps[currentIndex].type === 'ROUTER') {
|
|
221
|
-
await runRouterStep(ctx, currentIndex, iteration, progress)
|
|
222
|
-
return
|
|
223
|
-
}
|
|
224
|
-
const currentStep = qc.steps?.[currentIndex] as QuickCommandStepFetchResponse | QuickCommandStepLlmResponse
|
|
225
|
-
await (currentStep.type === 'FETCH' ? runFetchStep(ctx, currentIndex) : runLLMStep(ctx, currentIndex))
|
|
226
|
-
|
|
227
|
-
let nextIndex = currentIndex + 1
|
|
228
|
-
if (currentStep.next_step_slug) {
|
|
229
|
-
nextIndex = currentStep.next_step_slug === 'end' ?
|
|
230
|
-
qc.steps.length : qc.steps?.findIndex((step) => step.slug === currentStep.next_step_slug)
|
|
231
|
-
}
|
|
232
|
-
await runStepsRecursively(nextIndex, progress, ctx, iteration)
|
|
233
|
-
}
|
|
234
|
-
|
|
235
166
|
async function runSteps(ctx: QCContext) {
|
|
167
|
+
const { qc } = ctx
|
|
236
168
|
const progress = showProgressMessage(ctx)
|
|
237
169
|
try {
|
|
238
|
-
|
|
170
|
+
for (let i = 0; i < (qc.steps?.length ?? 0); i++) {
|
|
171
|
+
progress.update(i)
|
|
172
|
+
await (qc.steps?.[i].type === 'FETCH' ? runFetchStep(ctx, i) : runLLMStep(ctx, i))
|
|
173
|
+
}
|
|
239
174
|
} finally {
|
|
240
175
|
progress.remove()
|
|
241
176
|
}
|
|
242
177
|
}
|
|
243
178
|
|
|
244
|
-
async function formatResult({ qc, code, executionId, context, resultMap,
|
|
179
|
+
async function formatResult({ qc, code, executionId, context, resultMap, signal }: QCContext) {
|
|
245
180
|
const formatted = await aiClient.formatResultOfQuickCommand.mutate({
|
|
246
181
|
slug: qc.slug,
|
|
247
182
|
quickCommandsExecutionRequest: {
|
|
248
183
|
input_data: code,
|
|
249
184
|
context,
|
|
250
185
|
qc_execution_id: executionId,
|
|
251
|
-
slugs_executions:
|
|
186
|
+
slugs_executions: resultMap,
|
|
252
187
|
},
|
|
253
188
|
}, signal)
|
|
254
189
|
return formatted.result
|
|
@@ -363,7 +298,6 @@ export function createQuickCommandInterceptor(widget: WidgetState, getEditor: ()
|
|
|
363
298
|
context: buildConversationContext(chat) ?? {},
|
|
364
299
|
executionId: ulid(),
|
|
365
300
|
resultMap: {},
|
|
366
|
-
customInputs: {},
|
|
367
301
|
signal,
|
|
368
302
|
}
|
|
369
303
|
chat.set('isLoading', true)
|
|
@@ -397,14 +331,14 @@ const dictionary = {
|
|
|
397
331
|
en: {
|
|
398
332
|
requiresSelection: 'This quick command requires some code to be selected in the editor. To open the editor click the icon "{/}" in the field below.',
|
|
399
333
|
startQuestioning: 'To execute the Quick Command "$0", I\'ll need you to provide some information. Some may be mandatory, and others optional. Let\'s get started.',
|
|
400
|
-
progress: 'Running
|
|
334
|
+
progress: 'Running quick command "$0". Step $1 ($2) of $3.',
|
|
401
335
|
aborted: 'The quick command execution aborted by the user.',
|
|
402
336
|
notFound: 'There\'s no quick command with the provided name. If you don\'t wish to run a command, prefix the first "/" with a "\\".',
|
|
403
337
|
},
|
|
404
338
|
pt: {
|
|
405
339
|
requiresSelection: 'Este quick command precisa que algum código esteja selecionado no editor. Para abrir o editor clique no ícone "{/}" no campo abaixo.',
|
|
406
340
|
startQuestioning: 'Para executar o Quick Command "$0", vou precisar que você providencie algumas explicações. Algumas são obrigatórias e outras opcionais. Vamos começar.',
|
|
407
|
-
progress: 'Executando
|
|
341
|
+
progress: 'Executando quick command "$0". Passo $1 ($2) de $3.',
|
|
408
342
|
aborted: 'A execução do quick command foi abortada pelo usuário.',
|
|
409
343
|
notFound: 'Não existe quick command com o nome providenciado. Se você não quiser rodar um comando, prefixe o primeiro "/" com um "\\".',
|
|
410
344
|
},
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { ReactElement } from 'react'
|
|
2
|
+
import { RightPanelForm } from './RightPanelForm'
|
|
3
|
+
|
|
4
|
+
interface Props {
|
|
5
|
+
children: ReactElement,
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* List content for the right panel.
|
|
10
|
+
*/
|
|
11
|
+
export const RightPanelContentList = ({ children }: Props) => (
|
|
12
|
+
<RightPanelForm>
|
|
13
|
+
{children}
|
|
14
|
+
</RightPanelForm>
|
|
15
|
+
)
|
|
@@ -5,7 +5,7 @@ import { useKeyboardControls } from '@stack-spot/portal-components'
|
|
|
5
5
|
import { AgentVisibilityLevel } from '@stack-spot/portal-network'
|
|
6
6
|
import { Dictionary, interpolate, useTranslate } from '@stack-spot/portal-translate'
|
|
7
7
|
import React, { FC, useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
|
8
|
-
import { useCurrentChatState } from '../../context/hooks'
|
|
8
|
+
import { useCurrentChatState, useWidgetState } from '../../context/hooks'
|
|
9
9
|
import { getUrlToStackSpotAI } from '../../utils/url'
|
|
10
10
|
import { ButtonFavorite } from '../ButtonFavorite'
|
|
11
11
|
import { Fading } from '../Fading'
|
|
@@ -112,7 +112,6 @@ const List = <T extends Item>({ selectorConfig, filter, visibility, onSelect, fa
|
|
|
112
112
|
const t = useTranslate(dictionary)
|
|
113
113
|
const items = selectorConfig.useData()
|
|
114
114
|
const favorites = favorite?.useFavorites?.()
|
|
115
|
-
|
|
116
115
|
const filtered = useMemo(() => {
|
|
117
116
|
if (!filter && !visibility) return [...items]
|
|
118
117
|
const lowerFilter = filter?.toLowerCase() ?? ''
|
|
@@ -152,6 +151,7 @@ const SelectorContent = ({ filter, onClose, selectorConfig, favorite }: ContentP
|
|
|
152
151
|
const t = useTranslate(dictionary)
|
|
153
152
|
const ref = useRef<HTMLDivElement>(null)
|
|
154
153
|
const [visibility, setVisibility] = useState<SectionVisibility | undefined>()
|
|
154
|
+
const isGroupResourcesByScope = useWidgetState('features')?.groupResourcesByScope
|
|
155
155
|
const { resourceName, icon, onSelect, sections } = selectorConfig
|
|
156
156
|
const onSelectItem = useCallback((slug: string) => {
|
|
157
157
|
onSelect(slug)
|
|
@@ -184,10 +184,12 @@ const SelectorContent = ({ filter, onClose, selectorConfig, favorite }: ContentP
|
|
|
184
184
|
<Text as="h3" className="uppercase"> {resourceName} </Text>
|
|
185
185
|
</header>
|
|
186
186
|
<div className="body">
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
187
|
+
{isGroupResourcesByScope && (
|
|
188
|
+
<ul className="tabs">
|
|
189
|
+
{createSectionItem()}
|
|
190
|
+
{sections.map(createSectionItem)}
|
|
191
|
+
</ul>
|
|
192
|
+
)}
|
|
191
193
|
<FallbackBoundary message={interpolate(t.error, selectorConfig.resourceName)} mini>
|
|
192
194
|
<List filter={filter} visibility={visibility} selectorConfig={selectorConfig} onSelect={onSelectItem} favorite={favorite} />
|
|
193
195
|
</FallbackBoundary>
|
package/src/features.ts
CHANGED
|
@@ -41,11 +41,27 @@ export interface ChatFeatures {
|
|
|
41
41
|
streaming: boolean,
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
+
export type Scope = 'favorite' | 'builtin' | 'personal' | 'shared' | 'workspace' | 'account'
|
|
45
|
+
|
|
44
46
|
export interface GlobalFeatures {
|
|
45
47
|
/**
|
|
46
48
|
* Enables the chat history.
|
|
47
49
|
*/
|
|
48
50
|
chatHistory: boolean,
|
|
51
|
+
/**
|
|
52
|
+
* When selecting a resource, they're separated by scope (account, personal, workspace, etc.).
|
|
53
|
+
*
|
|
54
|
+
* If this is set, only the scopes in this list will be enabled.
|
|
55
|
+
*/
|
|
56
|
+
scopes?: Scope[],
|
|
57
|
+
/**
|
|
58
|
+
* When set, only items(knowledge sources, agents, stacks ai, quick commands) from that workspace will be shown to the user.
|
|
59
|
+
*/
|
|
60
|
+
workspaceId?: string,
|
|
61
|
+
/**
|
|
62
|
+
* when set to false it does not show tab by scope, it shows a single list.
|
|
63
|
+
*/
|
|
64
|
+
groupResourcesByScope?: boolean,
|
|
49
65
|
}
|
|
50
66
|
|
|
51
67
|
export type AIWidgetFeatures = ChatFeatures & GlobalFeatures
|
|
@@ -68,6 +84,7 @@ export function getFeaturesWithDefaults(features?: Partial<AIWidgetFeatures>): A
|
|
|
68
84
|
upload: true,
|
|
69
85
|
streaming: true,
|
|
70
86
|
showSourcesInResponse: true,
|
|
87
|
+
groupResourcesByScope: true,
|
|
71
88
|
...features,
|
|
72
89
|
}
|
|
73
90
|
}
|
package/src/index.ts
CHANGED
|
@@ -16,3 +16,4 @@ export { ObservableState } from './state/ObservableState'
|
|
|
16
16
|
export type { Labeled, LabeledAgent, LabeledWithImage } from './state/types'
|
|
17
17
|
export { WidgetState } from './state/WidgetState'
|
|
18
18
|
export { defaultLanguage, languages } from './utils/programming-languages'
|
|
19
|
+
|
package/src/layout.css
CHANGED
|
@@ -143,6 +143,10 @@
|
|
|
143
143
|
display: flex;
|
|
144
144
|
flex-direction: column;
|
|
145
145
|
|
|
146
|
+
code {
|
|
147
|
+
overflow: auto;
|
|
148
|
+
}
|
|
149
|
+
|
|
146
150
|
&.visible {
|
|
147
151
|
left: 50%;
|
|
148
152
|
}
|
|
@@ -205,4 +209,4 @@
|
|
|
205
209
|
z-index: 9999;
|
|
206
210
|
pointer-events: auto;
|
|
207
211
|
color: var(--light-contrastText)
|
|
208
|
-
}
|
|
212
|
+
}
|
package/src/state/constants.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { FileSize } from './types'
|
|
2
2
|
|
|
3
3
|
export const acceptedFileTypes = [
|
|
4
|
-
'json', 'yaml', 'txt', 'md', 'json', 'yaml', 'pdf', /*'xls', 'xlsx'
|
|
4
|
+
'json', 'yaml', 'txt', 'md', 'json', 'yaml', 'pdf', /*'xls', 'xlsx',*/ 'csv', 'cbl', 'cpp', 'cxx', 'cc', 'c', 'hpp', 'hxx', 'hh', 'h',
|
|
5
5
|
'cs', 'go', 'html', 'htm', 'kt', 'kts', 'md', 'php', 'proto', 'py', 'java', 'js', 'jsx', 'ts', 'tsx', 'rst', 'rb', 'rs', 'scala', 'swift',
|
|
6
6
|
'sql', 'yaml', 'yml', 'tf', 'sh', 'ps1', 'psd1', 'psm1', 'bat', 'cmd', 'rego', 'f', 'for', 'r', 'pl', 'vb', 'dart', 'hs', 'lua',
|
|
7
7
|
'asm', 'groovy', 'gvy', 'gy', 'mat', 'clj', 'lisp', 'm', 'cls', 'css', 'scss', 'json', 'jpg', 'jpeg', 'png',
|
|
@@ -28,7 +28,7 @@ export const AgentDescription = ({ agentId }: { agentId?: string }) => {
|
|
|
28
28
|
}, [numberOfKnowledgeSources])
|
|
29
29
|
const tools = useMemo(() => {
|
|
30
30
|
const result: React.ReactElement[] = []
|
|
31
|
-
const builtInTools = agent?.toolkits?.builtin_toolkits?.[0]
|
|
31
|
+
const builtInTools = agent?.toolkits?.builtin_toolkits?.[0]?.tools
|
|
32
32
|
const customToolkits = agent?.toolkits?.custom_toolkits ?? []
|
|
33
33
|
for (const tool of builtInTools ?? []) {
|
|
34
34
|
const toolWithImage = toolById(tool.id, toolKits)
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import { agentToolsClient } from '@stack-spot/portal-network'
|
|
2
|
-
import {
|
|
2
|
+
import { ReactElement, useEffect, useRef } from 'react'
|
|
3
|
+
import { RightPanelContentList } from '../../components/RightPanelContentList'
|
|
3
4
|
import { RightPanelTabs } from '../../components/RightPanelTabs'
|
|
4
|
-
import { useCurrentChat } from '../../context/hooks'
|
|
5
|
+
import { useCurrentChat, useWidgetState } from '../../context/hooks'
|
|
6
|
+
import { Scope } from '../../features'
|
|
5
7
|
import { checkIsTrial } from '../../utils/check-is-trial'
|
|
6
8
|
import { AgentsTab, AgentsTabWorkspace } from './AgentsTab'
|
|
7
9
|
import { useAgentsDictionary } from './dictionary'
|
|
8
10
|
|
|
11
|
+
type TabElement = { title: string, content: ReactElement }
|
|
12
|
+
|
|
9
13
|
/**
|
|
10
14
|
* Renders the Agent selection form in the Right Panel if this is the panel that is currently opened.
|
|
11
15
|
*/
|
|
@@ -14,6 +18,10 @@ export const AgentsPanel = () => {
|
|
|
14
18
|
const chat = useCurrentChat()
|
|
15
19
|
const isTrial = checkIsTrial()
|
|
16
20
|
const agent = useRef(chat.get('agent'))
|
|
21
|
+
const features = useWidgetState('features')
|
|
22
|
+
const isGroupResourcesByScope = features?.groupResourcesByScope
|
|
23
|
+
const scopes = features?.scopes ?? []
|
|
24
|
+
const spotId = features?.workspaceId
|
|
17
25
|
|
|
18
26
|
useEffect(() => {
|
|
19
27
|
if (agentToolsClient.agentDefaultSlug !== chat.get('agent')?.slug) {
|
|
@@ -21,19 +29,30 @@ export const AgentsPanel = () => {
|
|
|
21
29
|
}
|
|
22
30
|
}, [chat])
|
|
23
31
|
|
|
24
|
-
const
|
|
25
|
-
{ title: t.favorites, content: <AgentsTab key="favorite" visibility="favorite" agent={agent} /> },
|
|
26
|
-
{ title: t.builtin, content: <AgentsTab key="builtin" visibility="built_in" agent={agent} /> },
|
|
27
|
-
{ title: t.personal, content: <AgentsTab key="personal" visibility="personal" agent={agent} /> },
|
|
28
|
-
|
|
29
|
-
{ title: t.
|
|
30
|
-
{ title: t.
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
32
|
+
const allTabsMap: Record<Scope, TabElement> = {
|
|
33
|
+
favorite: { title: t.favorites, content: <AgentsTab key="favorite" visibility="favorite" agent={agent} /> },
|
|
34
|
+
builtin: { title: t.builtin, content: <AgentsTab key="builtin" visibility="built_in" agent={agent} /> },
|
|
35
|
+
personal: { title: t.personal, content: <AgentsTab key="personal" visibility="personal" agent={agent} /> },
|
|
36
|
+
shared: { title: t.shared, content: <AgentsTab key="shared" visibility="shared" agent={agent} /> },
|
|
37
|
+
workspace: { title: t.spots, content: <AgentsTabWorkspace key="workspace" visibility="workspace" agent={agent} /> },
|
|
38
|
+
account: { title: t.account, content: <AgentsTab key="account" visibility="account" agent={agent} /> },
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const defaultScopes: Scope[] = ['favorite', 'builtin', 'personal', 'shared', 'workspace', 'account']
|
|
42
|
+
|
|
43
|
+
const rawScopes: Scope[] = scopes?.length ? scopes : defaultScopes
|
|
44
|
+
|
|
45
|
+
const scopesToRender: Scope[] = isTrial
|
|
46
|
+
? ['favorite', 'builtin', 'personal']
|
|
47
|
+
: rawScopes
|
|
48
|
+
|
|
49
|
+
const tabs = scopesToRender
|
|
50
|
+
.map(scope => allTabsMap[scope])
|
|
51
|
+
.filter(Boolean) as TabElement[]
|
|
52
|
+
|
|
53
|
+
return (isGroupResourcesByScope ? (
|
|
54
|
+
<RightPanelTabs key={chat.id} tabs={tabs} />
|
|
55
|
+
) : (
|
|
56
|
+
<RightPanelContentList><AgentsTab workspaceId={spotId} agent={agent} /></RightPanelContentList>
|
|
57
|
+
))
|
|
39
58
|
}
|
|
@@ -19,7 +19,7 @@ import { AgentLabel } from './styled'
|
|
|
19
19
|
import { useAgentFavorites } from './useAgentFavorites'
|
|
20
20
|
|
|
21
21
|
export interface AgentTabProps {
|
|
22
|
-
visibility
|
|
22
|
+
visibility?: AgentVisibilityLevel,
|
|
23
23
|
workspaceId?: string,
|
|
24
24
|
agent: React.MutableRefObject<ChatProperties['agent']>,
|
|
25
25
|
showSubmitButton?: boolean,
|
|
@@ -102,7 +102,8 @@ export const HistoryItem = ({ item }: { item: ConversationResponse }) => {
|
|
|
102
102
|
const builtIn = !!last(chat.history ?? [])?.custom_agent?.built_in
|
|
103
103
|
widget.chatTabs.add(new ChatState({
|
|
104
104
|
id: chat.id,
|
|
105
|
-
initial: { label: chat.title, stack, workspace, agent: agent ? {
|
|
105
|
+
initial: { features: widget.chatFeatures, label: chat.title, stack, workspace, agent: agent ? {
|
|
106
|
+
...agent, builtIn } : undefined },
|
|
106
107
|
interceptors: widget.interceptors,
|
|
107
108
|
entries: chat.history?.map(item => new ChatEntry({
|
|
108
109
|
agentType: item.agent === 'USER' ? 'user' : 'bot',
|
package/src/views/KSDocument.tsx
CHANGED
|
@@ -4,6 +4,7 @@ import { aiClient } from '@stack-spot/portal-network'
|
|
|
4
4
|
import { Dictionary, useTranslate } from '@stack-spot/portal-translate'
|
|
5
5
|
import { useEffect } from 'react'
|
|
6
6
|
import { Code } from '../components/Code'
|
|
7
|
+
import { FallbackBoundary } from '../components/FallbackBoundary'
|
|
7
8
|
import { useWidget, useWidgetState } from '../context/hooks'
|
|
8
9
|
import { useRightPanel } from '../right-panel/hooks'
|
|
9
10
|
import { extractCodeFromKSDocument } from '../utils/knowledge-source'
|
|
@@ -20,7 +21,7 @@ export const KSDocument = () => {
|
|
|
20
21
|
|
|
21
22
|
useEffect(() => {
|
|
22
23
|
if (panel === 'ks-details' && ks) open(
|
|
23
|
-
<KSDocumentPanel documentId={ks.documentId} slug={ks.slug}
|
|
24
|
+
<FallbackBoundary><KSDocumentPanel documentId={ks.documentId} slug={ks.slug} /></FallbackBoundary>,
|
|
24
25
|
{
|
|
25
26
|
title: (
|
|
26
27
|
<Flex flexDirection="row" alignItems="center" flex="1">
|
|
@@ -6,26 +6,30 @@ import { KnowledgeSourceItemResponse, VisibilityLevelEnum } from '@stack-spot/po
|
|
|
6
6
|
import { WorkspaceResponse } from '@stack-spot/portal-network/api/workspace-ai'
|
|
7
7
|
import { Dictionary, useTranslate } from '@stack-spot/portal-translate'
|
|
8
8
|
import { difference, uniqBy } from 'lodash'
|
|
9
|
-
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
|
9
|
+
import React, { ReactElement, useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
|
10
10
|
import { ButtonFavorite } from '../components/ButtonFavorite'
|
|
11
11
|
import { NavigationComponent } from '../components/ComponentNavigator'
|
|
12
12
|
import { DescribedCheckboxGroup } from '../components/form/DescribedCheckboxGroup'
|
|
13
13
|
import { IconInput } from '../components/IconInput'
|
|
14
|
+
import { RightPanelContentList } from '../components/RightPanelContentList'
|
|
14
15
|
import { RightPanelTabs } from '../components/RightPanelTabs'
|
|
15
16
|
import { WorkspaceTabNavigator } from '../components/WorkspaceTabNavigator'
|
|
16
17
|
import { useCurrentChat, useWidget, useWidgetState } from '../context/hooks'
|
|
18
|
+
import { Scope } from '../features'
|
|
17
19
|
import { useRightPanel } from '../right-panel/hooks'
|
|
18
20
|
import { ChatProperties } from '../state/ChatState'
|
|
19
21
|
import { checkIsTrial } from '../utils/check-is-trial'
|
|
20
22
|
|
|
21
23
|
export interface TabProps {
|
|
22
|
-
visibility
|
|
24
|
+
visibility?: VisibilityLevelEnum,
|
|
23
25
|
allKS: React.MutableRefObject<ChatProperties['knowledgeSources']>,
|
|
24
26
|
workspaceId?: string,
|
|
25
27
|
showSubmitButton?: boolean,
|
|
26
28
|
onSubmit?: () => void,
|
|
27
29
|
}
|
|
28
30
|
|
|
31
|
+
type TabElement = { title: string, content: ReactElement }
|
|
32
|
+
|
|
29
33
|
export const KnowledgeSources = () => {
|
|
30
34
|
const t = useTranslate(dictionary)
|
|
31
35
|
const panel = useWidgetState('panel')
|
|
@@ -51,6 +55,10 @@ const KnowledgeSourcesPanel = () => {
|
|
|
51
55
|
const allKS = useRef(chat.get('knowledgeSources') ?? [])
|
|
52
56
|
const { close } = useRightPanel()
|
|
53
57
|
const isTrial = checkIsTrial()
|
|
58
|
+
const features = useWidgetState('features')
|
|
59
|
+
const isGroupResourcesByScope = features?.groupResourcesByScope
|
|
60
|
+
const scopes = features?.scopes ?? []
|
|
61
|
+
const spotId = features?.workspaceId
|
|
54
62
|
|
|
55
63
|
const onSubmit = useCallback(() => {
|
|
56
64
|
chat.set('knowledgeSources', allKS.current)
|
|
@@ -61,18 +69,34 @@ const KnowledgeSourcesPanel = () => {
|
|
|
61
69
|
allKS.current = chat.get('knowledgeSources') ?? []
|
|
62
70
|
}, [chat])
|
|
63
71
|
|
|
64
|
-
const
|
|
65
|
-
{ title: t.favorites,
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
{ title: t.
|
|
70
|
-
{ title: t.
|
|
71
|
-
|
|
72
|
-
{ title: t.account, content: <KnowledgeSourcesTab key="account" visibility="account" allKS={allKS} onSubmit={onSubmit} /> },
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
72
|
+
const allTabsMap: Partial<Record<Scope, TabElement>> = {
|
|
73
|
+
favorite: { title: t.favorites,
|
|
74
|
+
content: <KnowledgeSourcesTab key="favorite" visibility="favorite" allKS={allKS} onSubmit={onSubmit} /> },
|
|
75
|
+
personal: { title: t.personal,
|
|
76
|
+
content: <KnowledgeSourcesTab key="personal" visibility="personal" allKS={allKS} onSubmit={onSubmit} /> },
|
|
77
|
+
shared: { title: t.shared, content: <KnowledgeSourcesTab key="shared" visibility="shared" allKS={allKS} onSubmit={onSubmit} /> },
|
|
78
|
+
workspace: { title: t.spots,
|
|
79
|
+
content: <KnowledgeSourcesTabWorkspace key="workspace" visibility="workspace" allKS={allKS} onSubmit={onSubmit} /> },
|
|
80
|
+
account: { title: t.account, content: <KnowledgeSourcesTab key="account" visibility="account" allKS={allKS} onSubmit={onSubmit} /> },
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const defaultScopes: Scope[] = ['favorite', 'personal', 'shared', 'workspace', 'account']
|
|
84
|
+
|
|
85
|
+
const rawScopes: Scope[] = scopes?.length ? scopes : defaultScopes
|
|
86
|
+
|
|
87
|
+
const scopesToRender: Scope[] = isTrial
|
|
88
|
+
? ['favorite', 'personal']
|
|
89
|
+
: rawScopes
|
|
90
|
+
|
|
91
|
+
const tabs = scopesToRender
|
|
92
|
+
.map(scope => allTabsMap[scope])
|
|
93
|
+
.filter(Boolean) as TabElement[]
|
|
94
|
+
|
|
95
|
+
return (isGroupResourcesByScope ? (
|
|
96
|
+
<RightPanelTabs key={chat.id} tabs={tabs} />
|
|
97
|
+
) : (
|
|
98
|
+
<RightPanelContentList><KnowledgeSourcesTab allKS={allKS} onSubmit={onSubmit} workspaceId={spotId} /></RightPanelContentList>
|
|
99
|
+
))
|
|
76
100
|
}
|
|
77
101
|
|
|
78
102
|
export const KnowledgeSourcesTab = ({ visibility, allKS, onSubmit, workspaceId, showSubmitButton = true }: TabProps) => {
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { Flex, IconBox, Image } from '@citric/core'
|
|
2
2
|
import { Agent } from '@citric/icons'
|
|
3
|
-
import { AgentResponseWithBuiltIn, agentToolsClient } from '@stack-spot/portal-network'
|
|
3
|
+
import { AgentResponseWithBuiltIn, agentToolsClient, workspaceAiClient } from '@stack-spot/portal-network'
|
|
4
4
|
import { useCallback } from 'react'
|
|
5
5
|
import { Selector } from '../../components/Selector'
|
|
6
|
-
import { useCurrentChat, useCurrentChatState } from '../../context/hooks'
|
|
6
|
+
import { useCurrentChat, useCurrentChatState, useWidgetState } from '../../context/hooks'
|
|
7
7
|
import { agentRegex } from '../../regex'
|
|
8
8
|
import { useAgentFavorites } from '../Agents/useAgentFavorites'
|
|
9
9
|
|
|
@@ -27,7 +27,8 @@ export const AgentSelector = ({ inputRef, isTrial }: {
|
|
|
27
27
|
}) => {
|
|
28
28
|
const chat = useCurrentChat()
|
|
29
29
|
const isAgentEnabled = useCurrentChatState('features').agent
|
|
30
|
-
|
|
30
|
+
const spotId = useWidgetState('features')?.workspaceId
|
|
31
|
+
|
|
31
32
|
const { useFavorites, onAddFavorite, onRemoveFavorite } = useAgentFavorites()
|
|
32
33
|
|
|
33
34
|
const onSelectItem = useCallback(async (agent: AgentResponseWithBuiltIn) => {
|
|
@@ -52,9 +53,14 @@ export const AgentSelector = ({ inputRef, isTrial }: {
|
|
|
52
53
|
|
|
53
54
|
|
|
54
55
|
const getAgents = () => {
|
|
56
|
+
if (spotId) {
|
|
57
|
+
return workspaceAiClient.getAgentFromWorkspaceAi.useQuery({ workspaceId: spotId }) as AgentResponseWithBuiltIn[]
|
|
58
|
+
}
|
|
59
|
+
|
|
55
60
|
if (isTrial) {
|
|
56
61
|
return agentToolsClient.allAgents.useQuery({ visibilities: ['personal', 'built_in'] })
|
|
57
62
|
}
|
|
63
|
+
|
|
58
64
|
return agentToolsClient.allAgents.useQuery({ visibilities: ['account', 'shared', 'personal', 'built_in', 'workspace'] })
|
|
59
65
|
}
|
|
60
66
|
|
|
@@ -3,7 +3,7 @@ import { aiClient, workspaceAiClient } from '@stack-spot/portal-network'
|
|
|
3
3
|
import { QuickCommandResponse } from '@stack-spot/portal-network/api/ai'
|
|
4
4
|
import { useCallback } from 'react'
|
|
5
5
|
import { Selector } from '../../components/Selector'
|
|
6
|
-
import { useCurrentChat, useCurrentChatState } from '../../context/hooks'
|
|
6
|
+
import { useCurrentChat, useCurrentChatState, useWidgetState } from '../../context/hooks'
|
|
7
7
|
import { quickCommandRegex } from '../../regex'
|
|
8
8
|
|
|
9
9
|
type QuickCommandResponseWithSpaceName = QuickCommandResponse & { spaceName?: string }
|
|
@@ -12,6 +12,7 @@ export const QuickCommandSelector = ({ inputRef, isTrial }:
|
|
|
12
12
|
{ isTrial: boolean, inputRef: React.RefObject<HTMLTextAreaElement | HTMLInputElement> }) => {
|
|
13
13
|
const chat = useCurrentChat()
|
|
14
14
|
const isQuickCommandEnabled = useCurrentChatState('features').quickCommands
|
|
15
|
+
const spotId = useWidgetState('features')?.workspaceId
|
|
15
16
|
|
|
16
17
|
const useFavorites = () => aiClient.allQuickCommands.useQuery({ visibility: 'favorite' })
|
|
17
18
|
const [addFavorite, pendingAddFav] = aiClient.addFavoriteQuickCommand.useMutation()
|
|
@@ -77,11 +78,23 @@ export const QuickCommandSelector = ({ inputRef, isTrial }:
|
|
|
77
78
|
}, [chat, inputRef])
|
|
78
79
|
|
|
79
80
|
const getQuickCommands = () => {
|
|
81
|
+
if (spotId) {
|
|
82
|
+
return workspaceAiClient.getQCFromWorkspaceAi.useQuery({ workspaceId: spotId })
|
|
83
|
+
}
|
|
84
|
+
|
|
80
85
|
const quickCommands = aiClient.allQuickCommands.useQuery({ order: 'a-to-z' })
|
|
81
|
-
const quickCommandsFiltered = quickCommands.filter(
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
86
|
+
const quickCommandsFiltered = quickCommands.filter(
|
|
87
|
+
(qc) => qc.visibility_level.toLowerCase() !== 'workspace',
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
const workspaceQuickCommands = workspaceAiClient.workspacesContentsByType.useQuery({
|
|
91
|
+
contentType: 'quick_command',
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
const workspaceQuickCommandsWithWorkspaceName: QuickCommandResponseWithSpaceName[] =
|
|
95
|
+
workspaceQuickCommands.flatMap(({ qcs, space_name }) =>
|
|
96
|
+
qcs?.map((qc) => ({ ...qc, spaceName: space_name })),
|
|
97
|
+
) as QuickCommandResponseWithSpaceName[]
|
|
85
98
|
|
|
86
99
|
return [...quickCommandsFiltered, ...workspaceQuickCommandsWithWorkspaceName]
|
|
87
100
|
}
|