@stack-spot/ai-chat-widget 1.27.0 → 1.27.1-beta.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 +7 -0
- 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 +19 -1
- package/dist/chat-interceptors/quick-commands.js.map +1 -1
- package/dist/components/AgentCard/dictionary.d.ts +4 -2
- package/dist/components/AgentCard/dictionary.d.ts.map +1 -1
- package/dist/components/AgentCard/dictionary.js +4 -2
- package/dist/components/AgentCard/dictionary.js.map +1 -1
- package/dist/components/Selector/index.d.ts +2 -2
- package/dist/components/Selector/index.d.ts.map +1 -1
- package/dist/components/Selector/index.js +2 -2
- package/dist/components/Selector/index.js.map +1 -1
- package/dist/state/types.d.ts +1 -1
- package/dist/state/types.d.ts.map +1 -1
- package/dist/utils/tools.d.ts +2 -2
- package/dist/utils/tools.d.ts.map +1 -1
- package/dist/utils/tools.js +3 -6
- package/dist/utils/tools.js.map +1 -1
- package/dist/views/Agents/AgentDescription.d.ts +2 -9
- package/dist/views/Agents/AgentDescription.d.ts.map +1 -1
- package/dist/views/Agents/AgentDescription.js +11 -9
- 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 +11 -11
- package/dist/views/Agents/AgentsPanel.js.map +1 -1
- package/dist/views/Agents/AgentsTab.d.ts +2 -2
- package/dist/views/Agents/AgentsTab.d.ts.map +1 -1
- package/dist/views/Agents/AgentsTab.js +6 -6
- package/dist/views/Agents/AgentsTab.js.map +1 -1
- package/dist/views/Agents/useAgentFavorites.d.ts +1 -1
- package/dist/views/Agents/useAgentFavorites.js +4 -4
- package/dist/views/Agents/useAgentFavorites.js.map +1 -1
- package/dist/views/Chat/ChatMessage.d.ts.map +1 -1
- package/dist/views/Chat/ChatMessage.js +3 -3
- package/dist/views/Chat/ChatMessage.js.map +1 -1
- package/dist/views/ChatHistory/HistoryItem.d.ts.map +1 -1
- package/dist/views/ChatHistory/HistoryItem.js +8 -5
- package/dist/views/ChatHistory/HistoryItem.js.map +1 -1
- package/dist/views/ChatHistory/utils.d.ts +0 -6
- package/dist/views/ChatHistory/utils.d.ts.map +1 -1
- package/dist/views/ChatHistory/utils.js +1 -16
- package/dist/views/ChatHistory/utils.js.map +1 -1
- package/dist/views/Home/CustomAgent.js +3 -3
- package/dist/views/Home/CustomAgent.js.map +1 -1
- package/dist/views/MessageInput/AgentSelector.js +4 -4
- package/dist/views/MessageInput/AgentSelector.js.map +1 -1
- package/dist/views/MessageInput/ButtonAgent.js +2 -2
- package/dist/views/MessageInput/ButtonAgent.js.map +1 -1
- package/dist/views/MessageInput/QuickCommandSelector.js +4 -4
- package/dist/views/MessageInput/QuickCommandSelector.js.map +1 -1
- package/dist/views/MessageInput/dictionary.js +4 -4
- package/dist/views/MessageInput/dictionary.js.map +1 -1
- package/dist/views/Tools.js +3 -3
- package/dist/views/Tools.js.map +1 -1
- package/dist/views/Workspaces/WorkspacesTab.js +1 -1
- package/package.json +2 -2
- package/src/app-metadata.json +3 -3
- package/src/chat-interceptors/quick-commands.ts +25 -3
- package/src/components/AgentCard/dictionary.ts +4 -2
- package/src/components/Selector/index.tsx +4 -5
- package/src/state/types.ts +1 -1
- package/src/utils/tools.ts +5 -7
- package/src/views/Agents/AgentDescription.tsx +18 -25
- package/src/views/Agents/AgentsPanel.tsx +11 -12
- package/src/views/Agents/AgentsTab.tsx +12 -17
- package/src/views/Agents/useAgentFavorites.ts +4 -4
- package/src/views/Chat/ChatMessage.tsx +3 -4
- package/src/views/ChatHistory/HistoryItem.tsx +10 -5
- package/src/views/ChatHistory/utils.ts +1 -18
- package/src/views/Home/CustomAgent.tsx +4 -4
- package/src/views/MessageInput/AgentSelector.tsx +4 -4
- package/src/views/MessageInput/ButtonAgent.tsx +2 -2
- package/src/views/MessageInput/QuickCommandSelector.tsx +4 -4
- package/src/views/MessageInput/dictionary.ts +4 -4
- package/src/views/Tools.tsx +4 -3
- package/src/views/Workspaces/WorkspacesTab.tsx +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { aiClient, CancelledError, FixedChatRequest, StackspotAPIError } from '@stack-spot/portal-network'
|
|
2
|
-
import { QuickCommandFetchResponseResult, QuickCommandPromptResponse2, QuickCommandResponse } from '@stack-spot/portal-network/api/ai'
|
|
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'
|
|
@@ -23,6 +23,7 @@ interface QCContext {
|
|
|
23
23
|
code?: string,
|
|
24
24
|
executionId: string,
|
|
25
25
|
signal: AbortSignal,
|
|
26
|
+
isRemote?: boolean,
|
|
26
27
|
}
|
|
27
28
|
|
|
28
29
|
/**
|
|
@@ -71,7 +72,26 @@ export function createQuickCommandInterceptor(widget: WidgetState, getEditor: ()
|
|
|
71
72
|
*/
|
|
72
73
|
async function runFetchStep(ctx: QCContext, stepIndex: number) {
|
|
73
74
|
const { qc: { slug, steps }, code, context, resultMap, executionId, signal } = ctx
|
|
74
|
-
const step = steps![stepIndex]
|
|
75
|
+
const step = steps![stepIndex] as QuickCommandStepFetchResponse
|
|
76
|
+
if (step.is_remote) {
|
|
77
|
+
ctx.isRemote = true
|
|
78
|
+
|
|
79
|
+
const { data } = await aiClient.fetchStepOfQuickCommandRemotely.mutate({
|
|
80
|
+
slug, stepSlug: step.slug,
|
|
81
|
+
quickCommandsExecutionRequest: { code_selection: code, context, slugs_executions: resultMap, qc_execution_id: executionId },
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
//data is the return of the request in the QC so we do not have full control over the response
|
|
85
|
+
//We handle the usual format with body, status_code and headers, but we might also handle other formats
|
|
86
|
+
const responseData = data as any
|
|
87
|
+
resultMap[step.slug] = {
|
|
88
|
+
status: responseData.status_code || 200,
|
|
89
|
+
data: JSON.stringify(responseData.body) ?? JSON.stringify(responseData),
|
|
90
|
+
headers: responseData.headers ?? {},
|
|
91
|
+
}
|
|
92
|
+
return
|
|
93
|
+
}
|
|
94
|
+
|
|
75
95
|
const { headers, data, method, url } = await aiClient.fetchStepOfQuickCommand.mutate({
|
|
76
96
|
slug,
|
|
77
97
|
stepSlug: step.slug,
|
|
@@ -208,7 +228,7 @@ export function createQuickCommandInterceptor(widget: WidgetState, getEditor: ()
|
|
|
208
228
|
/**
|
|
209
229
|
* This registers a quick command event in the backend (analytics).
|
|
210
230
|
*/
|
|
211
|
-
async function registerAnalyticsEvent({ qc, executionId, code = '', context }: QCContext, status: string, start: number) {
|
|
231
|
+
async function registerAnalyticsEvent({ qc, isRemote, executionId, code = '', context }: QCContext, status: string, start: number) {
|
|
212
232
|
const now = new Date().getTime()
|
|
213
233
|
try {
|
|
214
234
|
await aiClient.createEvent.mutate({
|
|
@@ -221,6 +241,8 @@ export function createQuickCommandInterceptor(widget: WidgetState, getEditor: ()
|
|
|
221
241
|
slug: qc.slug,
|
|
222
242
|
qc_execution_id: executionId,
|
|
223
243
|
id: qc.id,
|
|
244
|
+
//@ts-ignore
|
|
245
|
+
is_remote: isRemote,
|
|
224
246
|
},
|
|
225
247
|
code,
|
|
226
248
|
context,
|
|
@@ -2,7 +2,8 @@ import { Dictionary } from '@stack-spot/portal-translate'
|
|
|
2
2
|
|
|
3
3
|
export const dictionary = {
|
|
4
4
|
en: {
|
|
5
|
-
|
|
5
|
+
'built_in': 'Embutido',
|
|
6
|
+
workspace: 'Spot',
|
|
6
7
|
personal: 'Personal',
|
|
7
8
|
account: 'Account',
|
|
8
9
|
shared: 'Shared',
|
|
@@ -10,7 +11,8 @@ export const dictionary = {
|
|
|
10
11
|
create: 'Create',
|
|
11
12
|
},
|
|
12
13
|
pt: {
|
|
13
|
-
|
|
14
|
+
'built_in': 'Embutido',
|
|
15
|
+
workspace: 'Spot',
|
|
14
16
|
personal: 'Personal',
|
|
15
17
|
account: 'Conta',
|
|
16
18
|
shared: 'Compartilhado',
|
|
@@ -2,7 +2,7 @@ import { IconBox, Text } from '@citric/core'
|
|
|
2
2
|
import { ExternalLink } from '@citric/icons'
|
|
3
3
|
import { IconButton } from '@citric/ui'
|
|
4
4
|
import { useKeyboardControls } from '@stack-spot/portal-components'
|
|
5
|
-
import {
|
|
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
8
|
import { useCurrentChatState } from '../../context/hooks'
|
|
@@ -12,8 +12,7 @@ import { Fading } from '../Fading'
|
|
|
12
12
|
import { FallbackBoundary } from '../FallbackBoundary'
|
|
13
13
|
import { SelectorBox } from './styled'
|
|
14
14
|
|
|
15
|
-
type SectionVisibility =
|
|
16
|
-
|
|
15
|
+
type SectionVisibility = AgentVisibilityLevel
|
|
17
16
|
type SelectorShortcut = '/' | '@'
|
|
18
17
|
|
|
19
18
|
interface Item {
|
|
@@ -268,7 +267,7 @@ const dictionary = {
|
|
|
268
267
|
personal: 'Personal',
|
|
269
268
|
account: 'Account',
|
|
270
269
|
shared: 'Shared',
|
|
271
|
-
'
|
|
270
|
+
'built_in': 'Built-in',
|
|
272
271
|
workspace: 'Spot',
|
|
273
272
|
error: 'Could not load the $0s.',
|
|
274
273
|
noData: 'You don\'t have any $0 yet.',
|
|
@@ -282,7 +281,7 @@ const dictionary = {
|
|
|
282
281
|
account: 'Conta',
|
|
283
282
|
shared: 'Compartilhado',
|
|
284
283
|
workspace: 'Spot',
|
|
285
|
-
'
|
|
284
|
+
'built_in': 'Embutido',
|
|
286
285
|
error: 'Não foi possível carregar os $0s.',
|
|
287
286
|
noData: 'Você ainda não possui $0s.',
|
|
288
287
|
noResults: 'Não $0s para mostrar aqui.',
|
package/src/state/types.ts
CHANGED
package/src/utils/tools.ts
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { BuiltinToolkitResponse, BuiltinToolResponse } from '@stack-spot/portal-network/api/agent'
|
|
2
|
+
import { keyBy } from 'lodash'
|
|
2
3
|
|
|
3
4
|
export type ToolWithImage = BuiltinToolResponse & { id: string, image?: string }
|
|
4
5
|
|
|
5
|
-
export function toolById(id: string, toolkits:
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
if (tool.id === id) return { ...tool, id, image: toolkit.image_url }
|
|
9
|
-
}
|
|
10
|
-
}
|
|
6
|
+
export function toolById(id: string, toolkits: BuiltinToolkitResponse[] | undefined): ToolWithImage | undefined {
|
|
7
|
+
const tools = toolkits?.map(({ image_url, tools }) => tools?.map((tool) => ({ ...tool, id: tool.id!, image: image_url! }))).flat()
|
|
8
|
+
return keyBy(tools, 'id')[id]
|
|
11
9
|
}
|
|
@@ -1,29 +1,21 @@
|
|
|
1
1
|
import { Text } from '@citric/core'
|
|
2
2
|
import { Badge, Skeleton } from '@citric/ui'
|
|
3
|
-
import {
|
|
3
|
+
import { agentToolsClient } from '@stack-spot/portal-network'
|
|
4
4
|
import { useMemo } from 'react'
|
|
5
5
|
import { ToolBadge } from '../../components/ToolBadge'
|
|
6
|
+
import { toolById } from '../../utils/tools'
|
|
6
7
|
import { useAgentsDictionary } from './dictionary'
|
|
7
8
|
import { AgentDescriptionBox } from './styled'
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
agentId?: string,
|
|
11
|
-
llm?: string,
|
|
12
|
-
description?: string,
|
|
13
|
-
numberOfKnowledgeSources: number,
|
|
14
|
-
visibility: AgentVisibilityLevel,
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export const AgentDescription = ({ agentId, llm, description, numberOfKnowledgeSources, visibility }: Props) => {
|
|
10
|
+
export const AgentDescription = ({ agentId }: { agentId?: string }) => {
|
|
18
11
|
const t = useAgentsDictionary()
|
|
19
|
-
const [agent, , , { isLoading }] =
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
)
|
|
12
|
+
const [agent, , , { isLoading }] = agentToolsClient.agent.useStatefulQuery({ agentId: agentId! }, { enabled: !!agentId })
|
|
13
|
+
const [toolKits, , , { isLoading: isLoadingToolKit }] = agentToolsClient.tools.useStatefulQuery()
|
|
14
|
+
const numberOfKnowledgeSources = agent?.knowledge_source_config?.knowledge_sources.length ?? 0
|
|
23
15
|
|
|
24
16
|
const knowledgeSources = useMemo(
|
|
25
|
-
() => agent?.
|
|
26
|
-
<li key={index}><Badge palette="teal" appearance="square">{ks
|
|
17
|
+
() => agent?.knowledge_source_config?.knowledge_sources?.map((ks, index) => (
|
|
18
|
+
<li key={index}><Badge palette="teal" appearance="square">{ks}</Badge></li>
|
|
27
19
|
)),
|
|
28
20
|
[agent],
|
|
29
21
|
)
|
|
@@ -36,31 +28,32 @@ export const AgentDescription = ({ agentId, llm, description, numberOfKnowledgeS
|
|
|
36
28
|
}, [numberOfKnowledgeSources])
|
|
37
29
|
const tools = useMemo(() => {
|
|
38
30
|
const result: React.ReactElement[] = []
|
|
39
|
-
for (const
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
31
|
+
for (const tool of agent?.tools ?? []) {
|
|
32
|
+
const toolWithImage = toolById(tool.builtin_tool_id, toolKits)
|
|
33
|
+
result.push(<li key={tool.builtin_tool_id}>
|
|
34
|
+
<ToolBadge name={toolWithImage?.name || toolWithImage?.id || 'unknown'} image={toolWithImage?.image} />
|
|
35
|
+
</li>)
|
|
43
36
|
}
|
|
44
37
|
return result
|
|
45
38
|
}, [agent])
|
|
46
39
|
|
|
47
40
|
return (
|
|
48
41
|
<AgentDescriptionBox>
|
|
49
|
-
{description && <section>
|
|
42
|
+
{agent?.description && <section>
|
|
50
43
|
<Text appearance="microtext1" className="title">{t.description}</Text>
|
|
51
|
-
<Text>{description}</Text>
|
|
44
|
+
<Text>{agent?.description}</Text>
|
|
52
45
|
</section>}
|
|
53
46
|
{(!!numberOfKnowledgeSources || !!knowledgeSources?.length) && <section>
|
|
54
47
|
<Text appearance="microtext1" className="title">Knowledge sources</Text>
|
|
55
|
-
<ul>{isLoading ? skeleton : knowledgeSources}</ul>
|
|
48
|
+
<ul>{isLoading || isLoadingToolKit ? skeleton : knowledgeSources}</ul>
|
|
56
49
|
</section>}
|
|
57
50
|
{!!tools.length && <section>
|
|
58
51
|
<Text appearance="microtext1" className="title">{t.tools}</Text>
|
|
59
52
|
<ul>{tools}</ul>
|
|
60
53
|
</section>}
|
|
61
|
-
{
|
|
54
|
+
{agent?.model_name && <section>
|
|
62
55
|
<Text appearance="microtext1" className="title">LLM</Text>
|
|
63
|
-
<Badge palette="orange" appearance="square">{
|
|
56
|
+
<Badge palette="orange" appearance="square">{agent?.model_name}</Badge>
|
|
64
57
|
</section>}
|
|
65
58
|
</AgentDescriptionBox>
|
|
66
59
|
)
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { agentToolsClient } from '@stack-spot/portal-network'
|
|
1
2
|
import { useEffect, useMemo, useRef } from 'react'
|
|
2
3
|
import { RightPanelTabs } from '../../components/RightPanelTabs'
|
|
3
4
|
import { useCurrentChat } from '../../context/hooks'
|
|
@@ -5,8 +6,6 @@ import { checkIsTrial } from '../../utils/check-is-trial'
|
|
|
5
6
|
import { AgentsTab, AgentsTabWorkspace } from './AgentsTab'
|
|
6
7
|
import { useAgentsDictionary } from './dictionary'
|
|
7
8
|
|
|
8
|
-
const agentDefaultSlug = 'stk_code_buddy'
|
|
9
|
-
|
|
10
9
|
/**
|
|
11
10
|
* Renders the Agent selection form in the Right Panel if this is the panel that is currently opened.
|
|
12
11
|
*/
|
|
@@ -17,22 +16,22 @@ export const AgentsPanel = () => {
|
|
|
17
16
|
const agent = useRef(chat.get('agent'))
|
|
18
17
|
|
|
19
18
|
useEffect(() => {
|
|
20
|
-
if (agentDefaultSlug !== chat.get('agent')?.slug) {
|
|
19
|
+
if (agentToolsClient.agentDefaultSlug !== chat.get('agent')?.slug) {
|
|
21
20
|
agent.current = chat.get('agent')
|
|
22
21
|
}
|
|
23
22
|
}, [chat])
|
|
24
23
|
|
|
25
24
|
const tabs= useMemo(() => isTrial ? [
|
|
26
|
-
{ title: t.favorites, content: <AgentsTab key="favorite" visibility="
|
|
27
|
-
{ title: t.builtin, content: <AgentsTab key="builtin" visibility="
|
|
28
|
-
{ title: t.personal, content: <AgentsTab key="personal" visibility="
|
|
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} /> },
|
|
29
28
|
]: [
|
|
30
|
-
{ title: t.favorites, content: <AgentsTab key="favorite" visibility="
|
|
31
|
-
{ title: t.builtin, content: <AgentsTab key="builtin" visibility="
|
|
32
|
-
{ title: t.personal, content: <AgentsTab key="personal" visibility="
|
|
33
|
-
{ title: t.shared, content: <AgentsTab key="shared" visibility="
|
|
34
|
-
{ title: t.spots, content: <AgentsTabWorkspace key="workspace" visibility="
|
|
35
|
-
{ title: t.account, content: <AgentsTab key="account" visibility="
|
|
29
|
+
{ title: t.favorites, content: <AgentsTab key="favorite" visibility="favorite" agent={agent} /> },
|
|
30
|
+
{ title: t.builtin, content: <AgentsTab key="builtin" visibility="built_in" agent={agent} /> },
|
|
31
|
+
{ title: t.personal, content: <AgentsTab key="personal" visibility="personal" agent={agent} /> },
|
|
32
|
+
{ title: t.shared, content: <AgentsTab key="shared" visibility="shared" agent={agent} /> },
|
|
33
|
+
{ title: t.spots, content: <AgentsTabWorkspace key="workspace" visibility="workspace" agent={agent} /> },
|
|
34
|
+
{ title: t.account, content: <AgentsTab key="account" visibility="account" agent={agent} /> },
|
|
36
35
|
|
|
37
36
|
], [t, isTrial, agent])
|
|
38
37
|
|
|
@@ -2,8 +2,7 @@ import { Button, IconBox, Text } from '@citric/core'
|
|
|
2
2
|
import { Agent, Search } from '@citric/icons'
|
|
3
3
|
import { Placeholder } from '@stack-spot/portal-components/Placeholder'
|
|
4
4
|
import { MiniLogo } from '@stack-spot/portal-components/svg'
|
|
5
|
-
import {
|
|
6
|
-
import { VisibilityLevel } from '@stack-spot/portal-network/api/agent'
|
|
5
|
+
import { AgentResponseWithBuiltIn, agentToolsClient, AgentVisibilityLevel, workspaceAiClient } from '@stack-spot/portal-network'
|
|
7
6
|
import { WorkspaceResponse } from '@stack-spot/portal-network/api/workspace-ai'
|
|
8
7
|
import { useCallback, useMemo, useState } from 'react'
|
|
9
8
|
import { ButtonFavorite } from '../../components/ButtonFavorite'
|
|
@@ -20,7 +19,7 @@ import { AgentLabel } from './styled'
|
|
|
20
19
|
import { useAgentFavorites } from './useAgentFavorites'
|
|
21
20
|
|
|
22
21
|
export interface AgentTabProps {
|
|
23
|
-
visibility:
|
|
22
|
+
visibility: AgentVisibilityLevel,
|
|
24
23
|
workspaceId?: string,
|
|
25
24
|
agent: React.MutableRefObject<ChatProperties['agent']>,
|
|
26
25
|
showSubmitButton?: boolean,
|
|
@@ -33,16 +32,15 @@ export const AgentsTab = ({ visibility, workspaceId, agent, showSubmitButton = t
|
|
|
33
32
|
const [filter, setFilter] = useState('')
|
|
34
33
|
const { useFavorites, onAddFavorite, onRemoveFavorite } = useAgentFavorites()
|
|
35
34
|
const listFavorites = useFavorites()
|
|
36
|
-
const agentDefault =
|
|
35
|
+
const agentDefault = agentToolsClient.agentDefault.useQuery()
|
|
37
36
|
const agents = workspaceId
|
|
38
|
-
? workspaceAiClient.getAgentFromWorkspaceAi.useQuery({ workspaceId })
|
|
39
|
-
:
|
|
40
|
-
|
|
37
|
+
? workspaceAiClient.getAgentFromWorkspaceAi.useQuery({ workspaceId }) as AgentResponseWithBuiltIn[]
|
|
38
|
+
: agentToolsClient.agents.useQuery({ visibility })
|
|
41
39
|
|
|
42
40
|
const [value, setValue] = useState<AgentResponseWithBuiltIn | undefined>(
|
|
43
41
|
agent.current
|
|
44
42
|
? agents.find(a => a.id === agent.current?.id)
|
|
45
|
-
: chat.get('agent') ? agents.find(a => a.id === chat.get('agent')?.id) : agentDefault,
|
|
43
|
+
: chat.get('agent') ? agents.find(a => a.id === chat.get('agent')?.id) : agentDefault as AgentResponseWithBuiltIn,
|
|
46
44
|
)
|
|
47
45
|
|
|
48
46
|
const filtered = useMemo(
|
|
@@ -53,14 +51,17 @@ export const AgentsTab = ({ visibility, workspaceId, agent, showSubmitButton = t
|
|
|
53
51
|
|
|
54
52
|
function submit() {
|
|
55
53
|
if (value) {
|
|
56
|
-
chat.set(
|
|
54
|
+
chat.set(
|
|
55
|
+
'agent',
|
|
56
|
+
{ id: value.id, label: value.name, image: value.avatar!, builtIn: value.visibility_level === 'built_in', slug: value.slug },
|
|
57
|
+
)
|
|
57
58
|
}
|
|
58
59
|
close()
|
|
59
60
|
}
|
|
60
61
|
|
|
61
62
|
const onChange = useCallback((newValue: AgentResponseWithBuiltIn) => {
|
|
62
63
|
setValue(newValue)
|
|
63
|
-
agent.current = { ...newValue, label: newValue.name, builtIn:
|
|
64
|
+
agent.current = { ...newValue, label: newValue.name, builtIn: newValue.visibility_level === 'built_in' }
|
|
64
65
|
}, [])
|
|
65
66
|
|
|
66
67
|
return (
|
|
@@ -83,13 +84,7 @@ export const AgentsTab = ({ visibility, workspaceId, agent, showSubmitButton = t
|
|
|
83
84
|
<Text>{name}</Text>
|
|
84
85
|
</AgentLabel>
|
|
85
86
|
)}
|
|
86
|
-
renderDescription={a => <AgentDescription
|
|
87
|
-
agentId={a.id}
|
|
88
|
-
visibility={visibility}
|
|
89
|
-
description={a.description}
|
|
90
|
-
llm={a.llm_config?.model_slug}
|
|
91
|
-
numberOfKnowledgeSources={a.knowledge_sources_config?.knowledge_sources?.length ?? 0}
|
|
92
|
-
/>}
|
|
87
|
+
renderDescription={a => <AgentDescription agentId={a.id} />}
|
|
93
88
|
optionClassName={a => (a === value && filter && !a.name.toLocaleLowerCase().includes(filter.toLocaleLowerCase()))
|
|
94
89
|
? 'filtered-out'
|
|
95
90
|
: ''
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
/* eslint-disable filenames/match-regex */
|
|
2
|
-
import { agentClient } from '@stack-spot/portal-network'
|
|
2
|
+
import { agentClient, agentToolsClient } from '@stack-spot/portal-network'
|
|
3
3
|
|
|
4
4
|
export function useAgentFavorites() {
|
|
5
|
-
const useFavorites = () =>
|
|
5
|
+
const useFavorites = () => agentToolsClient.agents.useQuery({ visibility: 'favorite' })
|
|
6
6
|
const [addFavorite, pendingAddFav] = agentClient.addFavoriteAgent.useMutation()
|
|
7
7
|
const [removeFavorite, pendingRemoveFav] = agentClient.removeFavoriteAgent.useMutation()
|
|
8
8
|
|
|
9
9
|
const removeFavoriteAgent = async (idOrSlug?: string) => {
|
|
10
10
|
try {
|
|
11
11
|
await removeFavorite({ agentId: idOrSlug || '' })
|
|
12
|
-
await
|
|
12
|
+
await agentToolsClient.agents.invalidate({ visibility: 'favorite' })
|
|
13
13
|
} catch (error) {
|
|
14
14
|
// eslint-disable-next-line no-console
|
|
15
15
|
console.error(error)
|
|
@@ -19,7 +19,7 @@ export function useAgentFavorites() {
|
|
|
19
19
|
const addFavoriteAgent = async (idOrSlug?: string) => {
|
|
20
20
|
try {
|
|
21
21
|
await addFavorite({ agentId: idOrSlug || '' })
|
|
22
|
-
await
|
|
22
|
+
await agentToolsClient.agents.invalidate({ visibility: 'favorite' })
|
|
23
23
|
} catch (error) {
|
|
24
24
|
// eslint-disable-next-line no-console
|
|
25
25
|
console.error(error)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Box, Button, Checkbox, Flex, IconBox, Input, Label, Radio, Text } from '@citric/core'
|
|
2
2
|
import { Check, Cog, Copy, Dislike, DislikeFill, Like, LikeFill, TimesCircle } from '@citric/icons'
|
|
3
3
|
import { Badge, IconButton, Tooltip } from '@citric/ui'
|
|
4
|
-
import {
|
|
4
|
+
import { agentToolsClient } from '@stack-spot/portal-network'
|
|
5
5
|
import { listToClass } from '@stack-spot/portal-theme'
|
|
6
6
|
import { Dictionary, useTranslate } from '@stack-spot/portal-translate'
|
|
7
7
|
import { groupBy } from 'lodash'
|
|
@@ -193,11 +193,10 @@ export const ChatMessage = ({ message, isLast, beforeMessage, afterMessage }: Pr
|
|
|
193
193
|
const widget = useWidget()
|
|
194
194
|
const chat = useCurrentChat()
|
|
195
195
|
const agentId = entry.agent?.id ?? ''
|
|
196
|
-
const [
|
|
196
|
+
const [toolKits] = agentToolsClient.tools.useStatefulQuery({ enabled: !!agentId })
|
|
197
197
|
const [copied, setCopied] = useState(false)
|
|
198
198
|
const [showUserButtonCopy, setShowUserButtonCopy] = useState(false)
|
|
199
199
|
|
|
200
|
-
|
|
201
200
|
useChatScrollToBottomEffect(ref, [entry])
|
|
202
201
|
|
|
203
202
|
const detailKS = useCallback(({ name, slug, documentScore, documentId }: Required<TextChatEntry>['knowledgeSources'][number]) => {
|
|
@@ -349,7 +348,7 @@ export const ChatMessage = ({ message, isLast, beforeMessage, afterMessage }: Pr
|
|
|
349
348
|
className="tools-badge"
|
|
350
349
|
label={t.tools}
|
|
351
350
|
images={entry.tools.slice(0, 3).map((id) => {
|
|
352
|
-
const tool = toolById(id,
|
|
351
|
+
const tool = toolById(id, toolKits)
|
|
353
352
|
return { key: id, name: tool?.name || id, icon: <Cog />, url: tool?.image }
|
|
354
353
|
})}
|
|
355
354
|
onClick={openToolsPanel}
|
|
@@ -2,7 +2,7 @@ import { IconBox, Input } from '@citric/core'
|
|
|
2
2
|
import { Check, Download, EllipsisHorizontal, Pencil, Trash } from '@citric/icons'
|
|
3
3
|
import { IconButton, LoadingCircular } from '@citric/ui'
|
|
4
4
|
import { focusNextIgnoringChildren } from '@stack-spot/portal-components'
|
|
5
|
-
import { aiClient } from '@stack-spot/portal-network'
|
|
5
|
+
import { agentToolsClient, aiClient } from '@stack-spot/portal-network'
|
|
6
6
|
import { ConversationResponse } from '@stack-spot/portal-network/api/ai'
|
|
7
7
|
import { theme } from '@stack-spot/portal-theme'
|
|
8
8
|
import { last } from 'lodash'
|
|
@@ -11,12 +11,13 @@ import { OverlayMenu } from '../../components/OverlayMenu'
|
|
|
11
11
|
import { useWidget } from '../../context/hooks'
|
|
12
12
|
import { ChatEntry } from '../../state/ChatEntry'
|
|
13
13
|
import { ChatState } from '../../state/ChatState'
|
|
14
|
+
import { LabeledAgent } from '../../state/types'
|
|
14
15
|
import { ButtonAction } from '../../types'
|
|
15
16
|
import { download } from '../../utils/download'
|
|
16
17
|
import { genericSourcesToKnowledgeSources } from '../../utils/knowledge-source'
|
|
17
18
|
import { useHistoryDictionary } from './dictionary'
|
|
18
19
|
import { HistoryItemBox } from './styled'
|
|
19
|
-
import { findStack, findWorkspace
|
|
20
|
+
import { findStack, findWorkspace } from './utils'
|
|
20
21
|
|
|
21
22
|
/**
|
|
22
23
|
* Renders an item of the list of conversations (history).
|
|
@@ -88,12 +89,16 @@ export const HistoryItem = ({ item }: { item: ConversationResponse }) => {
|
|
|
88
89
|
setLoading(true)
|
|
89
90
|
try {
|
|
90
91
|
const chat = await aiClient.chat.query({ conversationId: item.id })
|
|
92
|
+
const historyAgentIds = chat.history?.map(item => item.custom_agent?.id).filter(Boolean) as string[] ?? []
|
|
91
93
|
const [stack, workspace, agents] = await Promise.all([
|
|
92
94
|
findStack(chat.ai_stack_id),
|
|
93
95
|
findWorkspace(chat.workspace_id),
|
|
94
|
-
|
|
96
|
+
agentToolsClient.agentsByIds.query({ searchAgentsRequest: { ids: historyAgentIds } }),
|
|
95
97
|
])
|
|
96
|
-
const
|
|
98
|
+
const agentsAsLabeledAgents: LabeledAgent[] = agents
|
|
99
|
+
.map((a) => ({ ...a, label: a.name, image: a.avatar ?? '', builtIn: a.visibility_level === 'built_in' }))
|
|
100
|
+
|
|
101
|
+
const agent = agentsAsLabeledAgents.find(a => a.id === last(chat.history)?.custom_agent?.id)
|
|
97
102
|
const builtIn = !!last(chat.history ?? [])?.custom_agent?.built_in
|
|
98
103
|
widget.chatTabs.add(new ChatState({
|
|
99
104
|
id: chat.id,
|
|
@@ -103,7 +108,7 @@ export const HistoryItem = ({ item }: { item: ConversationResponse }) => {
|
|
|
103
108
|
agentType: item.agent === 'USER' ? 'user' : 'bot',
|
|
104
109
|
content: item.content,
|
|
105
110
|
type: 'md',
|
|
106
|
-
agent:
|
|
111
|
+
agent: agentsAsLabeledAgents.find(a => a.id === item.custom_agent?.id),
|
|
107
112
|
messageId: item.message_id,
|
|
108
113
|
knowledgeSources: item.agent === 'USER' ? undefined : genericSourcesToKnowledgeSources(item.sources),
|
|
109
114
|
updated: item.updated,
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { aiClient, workspaceClient } from '@stack-spot/portal-network'
|
|
2
2
|
import { ChatProperties } from '../../state/ChatState'
|
|
3
|
-
import { LabeledWithImage } from '../../state/types'
|
|
4
3
|
|
|
5
4
|
/**
|
|
6
5
|
* Finds a stack by its id.
|
|
@@ -36,19 +35,3 @@ export async function findWorkspace(id: string | null): Promise<ChatProperties['
|
|
|
36
35
|
return { id, label: id }
|
|
37
36
|
}
|
|
38
37
|
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Finds all the agents, including common agents and public agents.
|
|
43
|
-
* @returns an array with every agent.
|
|
44
|
-
*/
|
|
45
|
-
export async function getAllAgents(): Promise<LabeledWithImage[]> {
|
|
46
|
-
try {
|
|
47
|
-
const agents = await agentClient.allAgents.query({ visibilities: ['ALL'] })
|
|
48
|
-
return agents.map(a => ({ id: a.id, label: a.name, image: a.avatar, slug: a.slug, builtIn: a.builtIn }))
|
|
49
|
-
} catch (error) {
|
|
50
|
-
// eslint-disable-next-line no-console
|
|
51
|
-
console.error(error)
|
|
52
|
-
return []
|
|
53
|
-
}
|
|
54
|
-
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { IconBox, Text } from '@citric/core'
|
|
2
2
|
import { Agent } from '@citric/icons'
|
|
3
|
-
import {
|
|
3
|
+
import { agentToolsClient } from '@stack-spot/portal-network'
|
|
4
4
|
import { useMemo } from 'react'
|
|
5
5
|
import { QuickStartButton } from '../../components/QuickStartButton'
|
|
6
6
|
import { useCurrentChat, useCurrentChatState } from '../../context/hooks'
|
|
@@ -12,15 +12,15 @@ import { HomeBox } from './styled'
|
|
|
12
12
|
*/
|
|
13
13
|
export const CustomAgent = () => {
|
|
14
14
|
const { id, label, image } = useCurrentChatState('agent') ?? {}
|
|
15
|
-
const [agent] =
|
|
15
|
+
const [agent] = agentToolsClient.agent.useStatefulQuery({ agentId: id! })
|
|
16
16
|
const chat = useCurrentChat()
|
|
17
|
-
const suggestions = useMemo(() => agent?.
|
|
17
|
+
const suggestions = useMemo(() => agent?.conversation_starter?.map((prompt, index) => (
|
|
18
18
|
<QuickStartButton
|
|
19
19
|
key={index}
|
|
20
20
|
label={prompt}
|
|
21
21
|
onClick={() => send(prompt)}
|
|
22
22
|
/>
|
|
23
|
-
)), [agent?.
|
|
23
|
+
)), [agent?.conversation_starter])
|
|
24
24
|
|
|
25
25
|
function send(message: string) {
|
|
26
26
|
chat.pushMessage(ChatEntry.createUserEntry(message))
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Flex, IconBox, Image } from '@citric/core'
|
|
2
2
|
import { Agent } from '@citric/icons'
|
|
3
|
-
import {
|
|
3
|
+
import { AgentResponseWithBuiltIn, agentToolsClient } from '@stack-spot/portal-network'
|
|
4
4
|
import { useCallback } from 'react'
|
|
5
5
|
import { Selector } from '../../components/Selector'
|
|
6
6
|
import { useCurrentChat, useCurrentChatState } from '../../context/hooks'
|
|
@@ -53,9 +53,9 @@ export const AgentSelector = ({ inputRef, isTrial }: {
|
|
|
53
53
|
|
|
54
54
|
const getAgents = () => {
|
|
55
55
|
if (isTrial) {
|
|
56
|
-
return
|
|
56
|
+
return agentToolsClient.allAgents.useQuery({ visibilities: ['personal', 'built_in'] })
|
|
57
57
|
}
|
|
58
|
-
return
|
|
58
|
+
return agentToolsClient.allAgents.useQuery({ visibilities: ['account', 'shared', 'personal', 'built_in', 'workspace'] })
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
return <Selector
|
|
@@ -68,7 +68,7 @@ export const AgentSelector = ({ inputRef, isTrial }: {
|
|
|
68
68
|
regex: agentRegex,
|
|
69
69
|
urlBuilder: (agent) => `/agents/${agent?.id}`,
|
|
70
70
|
searchProp: 'name',
|
|
71
|
-
sections: isTrial ? ['favorite', 'personal', '
|
|
71
|
+
sections: isTrial ? ['favorite', 'personal', 'built_in'] : ['favorite', 'personal', 'workspace', 'account', 'shared', 'built_in'],
|
|
72
72
|
renderComponentItem: AgentItem,
|
|
73
73
|
isEnabled: isAgentEnabled,
|
|
74
74
|
onSelect: onSelectItem,
|
|
@@ -2,14 +2,14 @@ import { Flex, IconBox } from '@citric/core'
|
|
|
2
2
|
import { Agent, TimesMini } from '@citric/icons'
|
|
3
3
|
import { IconButton, Tooltip } from '@citric/ui'
|
|
4
4
|
import { MiniLogo } from '@stack-spot/portal-components/svg'
|
|
5
|
-
import {
|
|
5
|
+
import { agentToolsClient } from '@stack-spot/portal-network'
|
|
6
6
|
import { useEffect } from 'react'
|
|
7
7
|
import { useCurrentChat, useCurrentChatState, useWidget } from '../../context/hooks'
|
|
8
8
|
import { useMessageInputDictionary } from './dictionary'
|
|
9
9
|
|
|
10
10
|
export const ButtonAgent = () => {
|
|
11
11
|
const t = useMessageInputDictionary()
|
|
12
|
-
const agentDefault =
|
|
12
|
+
const agentDefault = agentToolsClient.agentDefault.useQuery()
|
|
13
13
|
const widget = useWidget()
|
|
14
14
|
const chat = useCurrentChat()
|
|
15
15
|
const agent = useCurrentChatState('agent')
|
|
@@ -13,14 +13,14 @@ export const QuickCommandSelector = ({ inputRef, isTrial }:
|
|
|
13
13
|
const chat = useCurrentChat()
|
|
14
14
|
const isQuickCommandEnabled = useCurrentChatState('features').quickCommands
|
|
15
15
|
|
|
16
|
-
const useFavorites = () => aiClient.
|
|
16
|
+
const useFavorites = () => aiClient.allQuickCommands.useQuery({ visibility: 'favorite' })
|
|
17
17
|
const [addFavorite, pendingAddFav] = aiClient.addFavoriteQuickCommand.useMutation()
|
|
18
18
|
const [removeFavorite, pendingRemoveFav] = aiClient.removeFavoriteQuickCommand.useMutation()
|
|
19
19
|
|
|
20
20
|
const addFavoriteQc = async(idOrSlug?: string) => {
|
|
21
21
|
try {
|
|
22
22
|
await addFavorite({ slug: idOrSlug || '' })
|
|
23
|
-
await aiClient.
|
|
23
|
+
await aiClient.allQuickCommands.invalidate()
|
|
24
24
|
} catch (error) {
|
|
25
25
|
// eslint-disable-next-line no-console
|
|
26
26
|
console.error(error)
|
|
@@ -45,7 +45,7 @@ export const QuickCommandSelector = ({ inputRef, isTrial }:
|
|
|
45
45
|
const removeFavoriteQc = async(idOrSlug?: string) => {
|
|
46
46
|
try {
|
|
47
47
|
await removeFavorite({ slug: idOrSlug || '' })
|
|
48
|
-
await aiClient.
|
|
48
|
+
await aiClient.allQuickCommands.invalidate()
|
|
49
49
|
} catch (error) {
|
|
50
50
|
// eslint-disable-next-line no-console
|
|
51
51
|
console.error(error)
|
|
@@ -77,7 +77,7 @@ export const QuickCommandSelector = ({ inputRef, isTrial }:
|
|
|
77
77
|
}, [chat, inputRef])
|
|
78
78
|
|
|
79
79
|
const getQuickCommands = () => {
|
|
80
|
-
const quickCommands = aiClient.
|
|
80
|
+
const quickCommands = aiClient.allQuickCommands.useQuery({ order: 'a-to-z' })
|
|
81
81
|
const quickCommandsFiltered = quickCommands.filter((qc) => qc.visibility_level.toLowerCase() !== 'workspace')
|
|
82
82
|
const workspaceQuickCommands = workspaceAiClient.workspacesContentsByType.useQuery({ contentType: 'quick_command' })
|
|
83
83
|
const workspaceQuickCommandsWithWorkspaceName: QuickCommandResponseWithSpaceName[] = workspaceQuickCommands
|
|
@@ -8,7 +8,7 @@ const dictionary = {
|
|
|
8
8
|
knowledgeSource: 'Select knowledge sources',
|
|
9
9
|
agent: 'Select agent',
|
|
10
10
|
send: 'Send message',
|
|
11
|
-
placeholder: 'Send a message to $0',
|
|
11
|
+
placeholder: 'Send a message to $0. For commands, use @ or /',
|
|
12
12
|
cancel: 'Cancel',
|
|
13
13
|
removeConfig: 'Remove all the configuration',
|
|
14
14
|
removeStack: 'Stop using the current stack',
|
|
@@ -25,7 +25,7 @@ const dictionary = {
|
|
|
25
25
|
cantSendBecauseOfUploadError: 'Can\'t send the message because one of the files in the upload list could not be uploaded. Please, retry it or remove it from the list.',
|
|
26
26
|
cantSendBecauseOfUploadProgress: 'Please wait until all files are uploaded before sending the message. You can also cancel the upload by removing it from the list of uploads.',
|
|
27
27
|
cantSendBecauseOfEmptyContent: 'You can\'t send empty messages. Please write some text or upload a file.',
|
|
28
|
-
chatAgent: '
|
|
28
|
+
chatAgent: 'Agents',
|
|
29
29
|
},
|
|
30
30
|
pt: {
|
|
31
31
|
stack: 'Selecionar stack',
|
|
@@ -34,7 +34,7 @@ const dictionary = {
|
|
|
34
34
|
knowledgeSource: 'Selecionar knowledge sources',
|
|
35
35
|
agent: 'Selecionar agente',
|
|
36
36
|
send: 'Enviar mensagem',
|
|
37
|
-
placeholder: 'Envie uma mensagem para $0',
|
|
37
|
+
placeholder: 'Envie uma mensagem para $0. Para comandos, use @ ou /',
|
|
38
38
|
cancel: 'Cancelar',
|
|
39
39
|
removeConfig: 'Remover todas as configurações',
|
|
40
40
|
removeStack: 'Parar de usar a stack atual',
|
|
@@ -53,7 +53,7 @@ const dictionary = {
|
|
|
53
53
|
cantSendBecauseOfUploadError: 'Não é possível enviar a mensagem, pois um dos arquivos na lista de uploads não pôde ser enviado. Por favor, tente enviá-lo novamente ou remova-o da lista.',
|
|
54
54
|
cantSendBecauseOfUploadProgress: 'Por favor aguarde todos os uploads de arquivos antes de enviar a mensagem. Você pode cancelar o upload removendo o arquivo da lista de uploads.',
|
|
55
55
|
cantSendBecauseOfEmptyContent: 'Não é possível enviar mensagens vazias. Por favor, escreva algum texto ou envie um arquivo.',
|
|
56
|
-
chatAgent: '
|
|
56
|
+
chatAgent: 'Agentes',
|
|
57
57
|
},
|
|
58
58
|
} satisfies Dictionary
|
|
59
59
|
|