@stack-spot/ai-chat-widget 1.24.4 → 1.25.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/send-message.js +3 -3
- package/dist/chat-interceptors/send-message.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/FileDescription.d.ts +10 -0
- package/dist/components/FileDescription.d.ts.map +1 -0
- package/dist/components/FileDescription.js +85 -0
- package/dist/components/FileDescription.js.map +1 -0
- 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/ChatEntry.d.ts +9 -0
- package/dist/state/ChatEntry.d.ts.map +1 -1
- package/dist/state/ChatEntry.js.map +1 -1
- package/dist/state/ChatState.d.ts +5 -0
- package/dist/state/ChatState.d.ts.map +1 -1
- package/dist/state/ChatState.js +6 -0
- package/dist/state/ChatState.js.map +1 -1
- package/dist/state/constants.d.ts +5 -0
- package/dist/state/constants.d.ts.map +1 -0
- package/dist/state/constants.js +9 -0
- package/dist/state/constants.js.map +1 -0
- package/dist/state/types.d.ts +5 -1
- package/dist/state/types.d.ts.map +1 -1
- package/dist/utils/chat.d.ts +2 -1
- package/dist/utils/chat.d.ts.map +1 -1
- package/dist/utils/chat.js +2 -1
- package/dist/utils/chat.js.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/utils/upload/FileUpload.d.ts +21 -0
- package/dist/utils/upload/FileUpload.d.ts.map +1 -0
- package/dist/utils/upload/FileUpload.js +55 -0
- package/dist/utils/upload/FileUpload.js.map +1 -0
- package/dist/utils/upload/UploadManager.d.ts +40 -0
- package/dist/utils/upload/UploadManager.d.ts.map +1 -0
- package/dist/utils/upload/UploadManager.js +131 -0
- package/dist/utils/upload/UploadManager.js.map +1 -0
- package/dist/utils/upload/context.d.ts +15 -0
- package/dist/utils/upload/context.d.ts.map +1 -0
- package/dist/utils/upload/context.js +37 -0
- package/dist/utils/upload/context.js.map +1 -0
- package/dist/utils/upload/errors.d.ts +17 -0
- package/dist/utils/upload/errors.d.ts.map +1 -0
- package/dist/utils/upload/errors.js +27 -0
- package/dist/utils/upload/errors.js.map +1 -0
- package/dist/utils/upload/types.d.ts +7 -0
- package/dist/utils/upload/types.d.ts.map +1 -0
- package/dist/utils/upload/types.js +2 -0
- package/dist/utils/upload/types.js.map +1 -0
- package/dist/utils/upload/utils.d.ts +4 -0
- package/dist/utils/upload/utils.d.ts.map +1 -0
- package/dist/utils/upload/utils.js +10 -0
- package/dist/utils/upload/utils.js.map +1 -0
- 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 +4 -4
- 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/AgentInfo.d.ts +2 -1
- package/dist/views/Chat/AgentInfo.d.ts.map +1 -1
- package/dist/views/Chat/AgentInfo.js +2 -2
- package/dist/views/Chat/AgentInfo.js.map +1 -1
- package/dist/views/Chat/ChatMessage.d.ts +1 -1
- package/dist/views/Chat/ChatMessage.d.ts.map +1 -1
- package/dist/views/Chat/ChatMessage.js +27 -8
- package/dist/views/Chat/ChatMessage.js.map +1 -1
- package/dist/views/Chat/styled.d.ts.map +1 -1
- package/dist/views/Chat/styled.js +15 -1
- package/dist/views/Chat/styled.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/{InfoBar.d.ts → ContextBar.d.ts} +2 -2
- package/dist/views/MessageInput/ContextBar.d.ts.map +1 -0
- package/dist/views/MessageInput/{InfoBar.js → ContextBar.js} +5 -5
- package/dist/views/MessageInput/ContextBar.js.map +1 -0
- package/dist/views/MessageInput/SelectContent.d.ts.map +1 -1
- package/dist/views/MessageInput/SelectContent.js +14 -17
- package/dist/views/MessageInput/SelectContent.js.map +1 -1
- package/dist/views/MessageInput/UploadBar.d.ts +2 -0
- package/dist/views/MessageInput/UploadBar.d.ts.map +1 -0
- package/dist/views/MessageInput/UploadBar.js +47 -0
- package/dist/views/MessageInput/UploadBar.js.map +1 -0
- package/dist/views/MessageInput/dictionary.d.ts +1 -1
- package/dist/views/MessageInput/dictionary.d.ts.map +1 -1
- package/dist/views/MessageInput/dictionary.js +18 -4
- package/dist/views/MessageInput/dictionary.js.map +1 -1
- package/dist/views/MessageInput/index.d.ts.map +1 -1
- package/dist/views/MessageInput/index.js +46 -5
- package/dist/views/MessageInput/index.js.map +1 -1
- package/dist/views/MessageInput/styled.d.ts.map +1 -1
- package/dist/views/MessageInput/styled.js +56 -27
- package/dist/views/MessageInput/styled.js.map +1 -1
- package/dist/views/Steps/dictionary.d.ts +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/send-message.ts +3 -3
- package/src/components/AgentCard/dictionary.ts +4 -2
- package/src/components/FileDescription.tsx +114 -0
- package/src/components/Selector/index.tsx +4 -5
- package/src/state/ChatEntry.ts +10 -0
- package/src/state/ChatState.ts +6 -0
- package/src/state/constants.ts +12 -0
- package/src/state/types.ts +6 -1
- package/src/utils/chat.ts +3 -1
- package/src/utils/tools.ts +5 -7
- package/src/utils/upload/FileUpload.ts +64 -0
- package/src/utils/upload/UploadManager.ts +147 -0
- package/src/utils/upload/context.tsx +44 -0
- package/src/utils/upload/errors.ts +34 -0
- package/src/utils/upload/types.ts +7 -0
- package/src/utils/upload/utils.ts +12 -0
- package/src/views/Agents/AgentDescription.tsx +18 -25
- package/src/views/Agents/AgentsPanel.tsx +11 -12
- package/src/views/Agents/AgentsTab.tsx +8 -16
- package/src/views/Agents/useAgentFavorites.ts +4 -4
- package/src/views/Chat/AgentInfo.tsx +3 -2
- package/src/views/Chat/ChatMessage.tsx +51 -16
- package/src/views/Chat/styled.ts +15 -1
- 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/{InfoBar.tsx → ContextBar.tsx} +9 -9
- package/src/views/MessageInput/SelectContent.tsx +17 -21
- package/src/views/MessageInput/UploadBar.tsx +69 -0
- package/src/views/MessageInput/dictionary.ts +18 -4
- package/src/views/MessageInput/index.tsx +77 -32
- package/src/views/MessageInput/styled.ts +56 -27
- package/src/views/Tools.tsx +4 -3
- package/src/views/Workspaces/WorkspacesTab.tsx +1 -1
- package/dist/views/MessageInput/InfoBar.d.ts.map +0 -1
- package/dist/views/MessageInput/InfoBar.js.map +0 -1
|
@@ -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,7 +51,7 @@ export const AgentsTab = ({ visibility, workspaceId, agent, showSubmitButton = t
|
|
|
53
51
|
|
|
54
52
|
function submit() {
|
|
55
53
|
if (value) {
|
|
56
|
-
chat.set('agent', { id: value.id, label: value.name, image: value.avatar
|
|
54
|
+
chat.set('agent', { id: value.id, label: value.name, image: value.avatar!, builtIn: !!value.builtIn, slug: value.slug })
|
|
57
55
|
}
|
|
58
56
|
close()
|
|
59
57
|
}
|
|
@@ -83,13 +81,7 @@ export const AgentsTab = ({ visibility, workspaceId, agent, showSubmitButton = t
|
|
|
83
81
|
<Text>{name}</Text>
|
|
84
82
|
</AgentLabel>
|
|
85
83
|
)}
|
|
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
|
-
/>}
|
|
84
|
+
renderDescription={a => <AgentDescription agentId={a.id} />}
|
|
93
85
|
optionClassName={a => (a === value && filter && !a.name.toLocaleLowerCase().includes(filter.toLocaleLowerCase()))
|
|
94
86
|
? 'filtered-out'
|
|
95
87
|
: ''
|
|
@@ -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)
|
|
@@ -4,16 +4,17 @@ import { LabeledWithImage } from '../../state/types'
|
|
|
4
4
|
|
|
5
5
|
interface Props {
|
|
6
6
|
agent?: LabeledWithImage,
|
|
7
|
+
icon?: React.ReactElement,
|
|
7
8
|
}
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* Renders the avatar of an agent in a message.
|
|
11
12
|
*/
|
|
12
|
-
export const AgentInfo = ({ agent }: Props) => (
|
|
13
|
+
export const AgentInfo = ({ agent, icon }: Props) => (
|
|
13
14
|
<>
|
|
14
15
|
{agent?.image
|
|
15
16
|
? <img src={agent.image} className="custom-agent-image" />
|
|
16
|
-
: <IconBox className="default-image-wrapper" colorIcon="light.700"
|
|
17
|
+
: <IconBox className="default-image-wrapper" colorIcon="light.700">{icon ?? <Agent className="agent-image" />}</IconBox>
|
|
17
18
|
}
|
|
18
19
|
<Text appearance="body2">{agent?.label}</Text>
|
|
19
20
|
</>
|
|
@@ -1,12 +1,14 @@
|
|
|
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
|
+
import { groupBy } from 'lodash'
|
|
7
8
|
import { createElement, Dispatch, useCallback, useMemo, useRef, useState } from 'react'
|
|
8
9
|
import { PhoneInput } from 'react-international-phone'
|
|
9
10
|
import 'react-international-phone/style.css'
|
|
11
|
+
import { FileDescription } from '../../components/FileDescription'
|
|
10
12
|
import { Markdown } from '../../components/Markdown'
|
|
11
13
|
import { StackedBadge } from '../../components/StackedBadge'
|
|
12
14
|
import { useChatEntry, useCurrentChat, useWidget } from '../../context/hooks'
|
|
@@ -166,6 +168,14 @@ const RenderInputsEntry = ({ isLast, entry, value, setValue, labels, setLabels }
|
|
|
166
168
|
</Flex>
|
|
167
169
|
}
|
|
168
170
|
|
|
171
|
+
const UserInfo = ({ entry }: { entry: TextChatEntry }) => {
|
|
172
|
+
switch (entry.agentType) {
|
|
173
|
+
case 'user': return
|
|
174
|
+
case 'bot': return <AgentInfo agent={entry.agent} />
|
|
175
|
+
case 'system': return <AgentInfo agent={{ id: 'system', label: 'System' }} icon={<Cog />} />
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
169
179
|
/**
|
|
170
180
|
* Renders a message (ChatEntry) in the chat.
|
|
171
181
|
*/
|
|
@@ -176,7 +186,6 @@ export const ChatMessage = ({ message, isLast, beforeMessage, afterMessage }: Pr
|
|
|
176
186
|
const [labels, setLabels] = useState<string[]>(message.getValue()?.initialValue ?? [])
|
|
177
187
|
const entry = useChatEntry(message)
|
|
178
188
|
const dateFormatter = useDateFormatter()
|
|
179
|
-
const userInfo = entry.agentType === 'user' ? <></> : <AgentInfo agent={entry.agent} />
|
|
180
189
|
const date = new Date(entry.updated ?? '')
|
|
181
190
|
const shouldShowFooter = entry.updated && !isNaN(date.getTime())
|
|
182
191
|
const ref = useRef<HTMLLIElement>(null)
|
|
@@ -184,9 +193,10 @@ export const ChatMessage = ({ message, isLast, beforeMessage, afterMessage }: Pr
|
|
|
184
193
|
const widget = useWidget()
|
|
185
194
|
const chat = useCurrentChat()
|
|
186
195
|
const agentId = entry.agent?.id ?? ''
|
|
187
|
-
const [
|
|
196
|
+
const [toolKits] = agentToolsClient.tools.useStatefulQuery({ enabled: !!agentId })
|
|
188
197
|
const [copied, setCopied] = useState(false)
|
|
189
198
|
const [showUserButtonCopy, setShowUserButtonCopy] = useState(false)
|
|
199
|
+
|
|
190
200
|
|
|
191
201
|
useChatScrollToBottomEffect(ref, [entry])
|
|
192
202
|
|
|
@@ -258,9 +268,26 @@ export const ChatMessage = ({ message, isLast, beforeMessage, afterMessage }: Pr
|
|
|
258
268
|
setTimeout(() => setCopied(false), 2000)
|
|
259
269
|
}
|
|
260
270
|
|
|
271
|
+
const renderUploads = () => {
|
|
272
|
+
const groups = groupBy(entry.upload, f => f.image ? 'images' : 'documents')
|
|
273
|
+
const lists: React.ReactElement[] = []
|
|
274
|
+
if (groups.images?.length) {
|
|
275
|
+
lists.push(<ul className="image-uploads">{groups.images.map(f => <li key={f.id}><img src={f.image}></img></li>)}</ul>)
|
|
276
|
+
}
|
|
277
|
+
if (groups.documents?.length) {
|
|
278
|
+
lists.push(
|
|
279
|
+
<ul className="document-uploads">
|
|
280
|
+
{groups.documents.map(f => <li key={f.id}><FileDescription fileName={f.name} /></li>)}
|
|
281
|
+
</ul>,
|
|
282
|
+
)
|
|
283
|
+
}
|
|
284
|
+
return lists
|
|
285
|
+
}
|
|
286
|
+
|
|
261
287
|
const renderContent = () => {
|
|
262
288
|
if (entry.type === 'md') {
|
|
263
289
|
return <>
|
|
290
|
+
{renderUploads()}
|
|
264
291
|
<Markdown onCopyCode={(code) => onCopyCode(code, entry.messageId ?? '', chat)}>{entry.content}</Markdown>
|
|
265
292
|
{renderActions()}
|
|
266
293
|
</>
|
|
@@ -268,6 +295,7 @@ export const ChatMessage = ({ message, isLast, beforeMessage, afterMessage }: Pr
|
|
|
268
295
|
if (entry.type === 'text') {
|
|
269
296
|
return <>
|
|
270
297
|
<p className="plain-text">{entry.content}</p>
|
|
298
|
+
{renderUploads()}
|
|
271
299
|
{renderActions()}
|
|
272
300
|
</>
|
|
273
301
|
}
|
|
@@ -285,21 +313,26 @@ export const ChatMessage = ({ message, isLast, beforeMessage, afterMessage }: Pr
|
|
|
285
313
|
widget.set('panel', 'tools')
|
|
286
314
|
}
|
|
287
315
|
|
|
288
|
-
|
|
316
|
+
|
|
317
|
+
return (entry.content || entry.error || !!entry.steps?.length || entry.upload?.length) && (
|
|
289
318
|
<li key={entry.messageId} className={entry.agentType} ref={ref}>
|
|
290
319
|
<div className="chat-message-container"
|
|
291
320
|
onMouseEnter={entry.agentType === 'user' ? () => setShowUserButtonCopy(true) : undefined}
|
|
292
321
|
onMouseLeave={entry.agentType === 'user' ? () => setShowUserButtonCopy(false) : undefined}>
|
|
293
322
|
<div className="chat-message" ref={chatRef} onKeyDown={handleKeyDown} tabIndex={0}>
|
|
294
|
-
<div className={`user-info ${entry.agentType}`}
|
|
323
|
+
<div className={`user-info ${entry.agentType}`}><UserInfo entry={entry} /></div>
|
|
295
324
|
{beforeMessage && createElement(beforeMessage, { message })}
|
|
296
|
-
{(entry.content || entry.steps
|
|
297
|
-
{
|
|
298
|
-
{entry.badges
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
325
|
+
{(entry.content || entry.steps || entry.upload?.length) && (
|
|
326
|
+
<div className={listToClass(['message-content', entry.card && 'card', entry.type])}>
|
|
327
|
+
{!!entry.badges?.length && <div className="badges">
|
|
328
|
+
{entry.badges.map((b, index) => <Badge key={index} palette={b.color ?? 'cyan'} appearance="square">{b.label}</Badge>)}
|
|
329
|
+
</div>}
|
|
330
|
+
{renderContent()}
|
|
331
|
+
|
|
332
|
+
{!!entry.steps?.length && <StepsList steps={entry.steps} chatId={chat.id} messageId={message.id} />}
|
|
333
|
+
</div>
|
|
334
|
+
)}
|
|
335
|
+
|
|
303
336
|
{entry.error && (
|
|
304
337
|
<div className="error">
|
|
305
338
|
<IconBox size="xs"><TimesCircle /></IconBox>
|
|
@@ -316,7 +349,7 @@ export const ChatMessage = ({ message, isLast, beforeMessage, afterMessage }: Pr
|
|
|
316
349
|
className="tools-badge"
|
|
317
350
|
label={t.tools}
|
|
318
351
|
images={entry.tools.slice(0, 3).map((id) => {
|
|
319
|
-
const tool = toolById(id,
|
|
352
|
+
const tool = toolById(id, toolKits)
|
|
320
353
|
return { key: id, name: tool?.name || id, icon: <Cog />, url: tool?.image }
|
|
321
354
|
})}
|
|
322
355
|
onClick={openToolsPanel}
|
|
@@ -329,7 +362,7 @@ export const ChatMessage = ({ message, isLast, beforeMessage, afterMessage }: Pr
|
|
|
329
362
|
</li>
|
|
330
363
|
))}</ul>
|
|
331
364
|
</div>}
|
|
332
|
-
|
|
365
|
+
|
|
333
366
|
{shouldShowFooter && <div className="message-footer">
|
|
334
367
|
{entry.agentType === 'bot' && !entry.error && <div className="message-actions">
|
|
335
368
|
{entry.type === 'md' && (
|
|
@@ -368,6 +401,7 @@ export const ChatMessage = ({ message, isLast, beforeMessage, afterMessage }: Pr
|
|
|
368
401
|
</>
|
|
369
402
|
)}
|
|
370
403
|
</div>}
|
|
404
|
+
|
|
371
405
|
{entry.agentType === 'user' && (
|
|
372
406
|
<div className="message-actions">
|
|
373
407
|
{copied ? (
|
|
@@ -384,7 +418,7 @@ export const ChatMessage = ({ message, isLast, beforeMessage, afterMessage }: Pr
|
|
|
384
418
|
</Tooltip>
|
|
385
419
|
) : (
|
|
386
420
|
showUserButtonCopy && (
|
|
387
|
-
<div>
|
|
421
|
+
<div className="action-bar">
|
|
388
422
|
<IconButton
|
|
389
423
|
appearance="square"
|
|
390
424
|
color="light"
|
|
@@ -393,13 +427,14 @@ export const ChatMessage = ({ message, isLast, beforeMessage, afterMessage }: Pr
|
|
|
393
427
|
onClick={handleCopy}
|
|
394
428
|
size="sm"
|
|
395
429
|
>
|
|
396
|
-
<Copy/>
|
|
430
|
+
<Copy className="copy-btn"/>
|
|
397
431
|
</IconButton>
|
|
398
432
|
</div>
|
|
399
433
|
)
|
|
400
434
|
)}
|
|
401
435
|
</div>
|
|
402
436
|
)}
|
|
437
|
+
|
|
403
438
|
<Text as="label" appearance="microtext1" className="chat-date">
|
|
404
439
|
{dateFormatter.formatForChatMessage(date)}
|
|
405
440
|
</Text>
|
package/src/views/Chat/styled.ts
CHANGED
|
@@ -39,7 +39,7 @@ export const ChatList: IStyledComponentBase<
|
|
|
39
39
|
flex-direction: row;
|
|
40
40
|
gap: 10px;
|
|
41
41
|
|
|
42
|
-
&.bot {
|
|
42
|
+
&.bot, &.system {
|
|
43
43
|
align-items: center;
|
|
44
44
|
}
|
|
45
45
|
}
|
|
@@ -139,6 +139,20 @@ export const ChatList: IStyledComponentBase<
|
|
|
139
139
|
background: linear-gradient(180deg, ${theme.color.blue[500]} 0%, ${theme.color.indigo[500]} 100%);
|
|
140
140
|
}
|
|
141
141
|
}
|
|
142
|
+
.image-uploads, .document-uploads {
|
|
143
|
+
display: flex;
|
|
144
|
+
flex-direction: row;
|
|
145
|
+
flex-wrap: nowrap;
|
|
146
|
+
gap: 8px;
|
|
147
|
+
list-style: none;
|
|
148
|
+
margin: 0 0 4px 0;
|
|
149
|
+
padding: 0;
|
|
150
|
+
|
|
151
|
+
img {
|
|
152
|
+
max-width: 240px;
|
|
153
|
+
max-height: 240px;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
142
156
|
}
|
|
143
157
|
|
|
144
158
|
&.user {
|
|
@@ -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')
|