@stack-spot/ai-chat-widget 1.29.0-beta.0 → 1.29.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.
Files changed (84) hide show
  1. package/dist/StackspotAIWidget.d.ts.map +1 -1
  2. package/dist/StackspotAIWidget.js +3 -2
  3. package/dist/StackspotAIWidget.js.map +1 -1
  4. package/dist/app-metadata.json +3 -3
  5. package/dist/components/AdaptiveTextArea.d.ts +2 -2
  6. package/dist/components/AdaptiveTextArea.d.ts.map +1 -1
  7. package/dist/components/AdaptiveTextArea.js +8 -2
  8. package/dist/components/AdaptiveTextArea.js.map +1 -1
  9. package/dist/components/AgentCard/dictionary.d.ts +4 -2
  10. package/dist/components/AgentCard/dictionary.d.ts.map +1 -1
  11. package/dist/components/AgentCard/dictionary.js +4 -2
  12. package/dist/components/AgentCard/dictionary.js.map +1 -1
  13. package/dist/components/Selector/index.d.ts +2 -2
  14. package/dist/components/Selector/index.d.ts.map +1 -1
  15. package/dist/components/Selector/index.js +2 -2
  16. package/dist/components/Selector/index.js.map +1 -1
  17. package/dist/state/types.d.ts +1 -1
  18. package/dist/state/types.d.ts.map +1 -1
  19. package/dist/utils/tools.d.ts +2 -2
  20. package/dist/utils/tools.d.ts.map +1 -1
  21. package/dist/utils/tools.js +3 -6
  22. package/dist/utils/tools.js.map +1 -1
  23. package/dist/views/Agents/AgentDescription.d.ts +2 -9
  24. package/dist/views/Agents/AgentDescription.d.ts.map +1 -1
  25. package/dist/views/Agents/AgentDescription.js +12 -9
  26. package/dist/views/Agents/AgentDescription.js.map +1 -1
  27. package/dist/views/Agents/AgentsPanel.d.ts.map +1 -1
  28. package/dist/views/Agents/AgentsPanel.js +11 -11
  29. package/dist/views/Agents/AgentsPanel.js.map +1 -1
  30. package/dist/views/Agents/AgentsTab.d.ts +2 -2
  31. package/dist/views/Agents/AgentsTab.d.ts.map +1 -1
  32. package/dist/views/Agents/AgentsTab.js +6 -6
  33. package/dist/views/Agents/AgentsTab.js.map +1 -1
  34. package/dist/views/Agents/useAgentFavorites.d.ts +1 -1
  35. package/dist/views/Agents/useAgentFavorites.js +4 -4
  36. package/dist/views/Agents/useAgentFavorites.js.map +1 -1
  37. package/dist/views/Chat/ChatMessage.js +3 -3
  38. package/dist/views/Chat/ChatMessage.js.map +1 -1
  39. package/dist/views/ChatHistory/HistoryItem.d.ts.map +1 -1
  40. package/dist/views/ChatHistory/HistoryItem.js +8 -5
  41. package/dist/views/ChatHistory/HistoryItem.js.map +1 -1
  42. package/dist/views/ChatHistory/utils.d.ts +0 -6
  43. package/dist/views/ChatHistory/utils.d.ts.map +1 -1
  44. package/dist/views/ChatHistory/utils.js +1 -16
  45. package/dist/views/ChatHistory/utils.js.map +1 -1
  46. package/dist/views/Home/CustomAgent.js +3 -3
  47. package/dist/views/Home/CustomAgent.js.map +1 -1
  48. package/dist/views/MessageInput/AgentSelector.js +4 -4
  49. package/dist/views/MessageInput/AgentSelector.js.map +1 -1
  50. package/dist/views/MessageInput/ButtonAgent.js +2 -2
  51. package/dist/views/MessageInput/ButtonAgent.js.map +1 -1
  52. package/dist/views/MessageInput/index.d.ts +3 -1
  53. package/dist/views/MessageInput/index.d.ts.map +1 -1
  54. package/dist/views/MessageInput/index.js +5 -6
  55. package/dist/views/MessageInput/index.js.map +1 -1
  56. package/dist/views/MessageInput/styled.d.ts +0 -1
  57. package/dist/views/MessageInput/styled.d.ts.map +1 -1
  58. package/dist/views/MessageInput/styled.js +0 -1
  59. package/dist/views/MessageInput/styled.js.map +1 -1
  60. package/dist/views/Tools.js +3 -3
  61. package/dist/views/Tools.js.map +1 -1
  62. package/dist/views/Workspaces/WorkspacesTab.js +1 -1
  63. package/package.json +2 -2
  64. package/src/StackspotAIWidget.tsx +4 -3
  65. package/src/app-metadata.json +3 -3
  66. package/src/components/AdaptiveTextArea.tsx +13 -4
  67. package/src/components/AgentCard/dictionary.ts +4 -2
  68. package/src/components/Selector/index.tsx +4 -5
  69. package/src/state/types.ts +1 -1
  70. package/src/utils/tools.ts +5 -7
  71. package/src/views/Agents/AgentDescription.tsx +19 -25
  72. package/src/views/Agents/AgentsPanel.tsx +11 -12
  73. package/src/views/Agents/AgentsTab.tsx +12 -17
  74. package/src/views/Agents/useAgentFavorites.ts +4 -4
  75. package/src/views/Chat/ChatMessage.tsx +3 -3
  76. package/src/views/ChatHistory/HistoryItem.tsx +10 -5
  77. package/src/views/ChatHistory/utils.ts +1 -18
  78. package/src/views/Home/CustomAgent.tsx +4 -4
  79. package/src/views/MessageInput/AgentSelector.tsx +4 -4
  80. package/src/views/MessageInput/ButtonAgent.tsx +2 -2
  81. package/src/views/MessageInput/index.tsx +4 -5
  82. package/src/views/MessageInput/styled.ts +0 -1
  83. package/src/views/Tools.tsx +4 -3
  84. package/src/views/Workspaces/WorkspacesTab.tsx +1 -1
@@ -83,7 +83,8 @@ export const StackspotAIWidget = (
83
83
  const isCurrentChatEmpty = currentChat.length === 0
84
84
  const isTrial = checkIsTrial()
85
85
  const features = useCurrentChatState('features')
86
-
86
+ const containerRef = useRef<HTMLDivElement>(null)
87
+
87
88
  return useMemo(() => (
88
89
  <FallbackBoundary>
89
90
  <TooltipProvider>
@@ -97,7 +98,7 @@ export const StackspotAIWidget = (
97
98
  }
98
99
  </>
99
100
  }
100
- <div className="chat-container">
101
+ <div ref={containerRef} className="chat-container">
101
102
  <div className="chat-content">
102
103
  {prefix}
103
104
  {isCurrentChatEmpty
@@ -105,7 +106,7 @@ export const StackspotAIWidget = (
105
106
  : <Chat username={username} beforeMessage={beforeMessage} afterMessage={afterMessage} />
106
107
  }
107
108
  </div>
108
- {features.messageInput && <MessageInput />}
109
+ {features.messageInput && <MessageInput containerRef={containerRef} />}
109
110
  </div>
110
111
  </div>
111
112
  <Stacks />
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@stack-spot/ai-chat-widget",
3
- "version": "1.29.0-beta.0",
4
- "date": "Thu Jul 03 2025 09:44:54 GMT-0300 (Horário Padrão de Brasília)",
3
+ "version": "1.29.1-beta.0",
4
+ "date": "Thu Jul 03 2025 20:43:41 GMT-0300 (Brasilia Standard Time)",
5
5
  "dependencies": [
6
6
  {
7
7
  "name": "@stack-spot/app-metadata",
@@ -113,7 +113,7 @@
113
113
  },
114
114
  {
115
115
  "name": "@stack-spot/portal-network",
116
- "version": "0.143.3(@stack-spot/auth@5.3.2)(@stack-spot/opa@2.5.0(@stack-spot/auth@5.3.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(@stack-spot/portal-translate@1.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(@tanstack/react-query@5.59.16(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)"
116
+ "version": "0.149.0-beta.2(@stack-spot/auth@5.3.2)(@stack-spot/opa@2.5.0(@stack-spot/auth@5.3.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(@stack-spot/portal-translate@1.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(@tanstack/react-query@5.59.16(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)"
117
117
  },
118
118
  {
119
119
  "name": "@stack-spot/portal-theme",
@@ -1,7 +1,8 @@
1
1
  /* eslint-disable react/display-name */
2
2
  import { Textarea } from '@citric/core'
3
- import { forwardRef, useEffect, useRef } from 'react'
3
+ import { forwardRef, useEffect, useMemo, useRef } from 'react'
4
4
  import { PropsOf } from '../types'
5
+ import { MIN_INPUT_HEIGHT } from '../views/MessageInput/styled'
5
6
 
6
7
  interface Props extends PropsOf<typeof Textarea> {
7
8
  /**
@@ -13,20 +14,28 @@ interface Props extends PropsOf<typeof Textarea> {
13
14
  */
14
15
  onResetSize?: () => void,
15
16
  /**
16
- * The maximum height this textarea can get to.
17
+ * Reference to parent container to calculate dynamic max height
17
18
  */
18
- maxHeight?: number,
19
+ containerRef?: React.RefObject<HTMLElement>,
19
20
  }
20
21
 
21
22
  /**
22
23
  * The adaptive textarea grows in height whenever needed until the maximum height is reached.
23
24
  */
24
25
  export const AdaptiveTextArea = forwardRef<HTMLTextAreaElement, Props>((
25
- { value, onIncreaseSize, onResetSize, maxHeight, style, ...props },
26
+ { value, onIncreaseSize, onResetSize, style, containerRef, ...props },
26
27
  externalRef,
27
28
  ) => {
28
29
  const localRef = useRef<HTMLTextAreaElement>(null)
29
30
  const ref = externalRef as React.RefObject<HTMLTextAreaElement> ?? localRef
31
+ /**
32
+ * Calculates the maximum height for the textarea.
33
+ * Uses 40% of container height if available, otherwise falls back to MIN_INPUT_HEIGHT.
34
+ */
35
+ const maxHeight = useMemo(
36
+ () => containerRef?.current?.offsetHeight ? containerRef?.current?.offsetHeight * 0.4 : MIN_INPUT_HEIGHT,
37
+ [containerRef?.current?.offsetHeight],
38
+ )
30
39
 
31
40
  const handleIncreaseSize = (newHeight: number) => {
32
41
  onIncreaseSize?.()
@@ -2,7 +2,8 @@ import { Dictionary } from '@stack-spot/portal-translate'
2
2
 
3
3
  export const dictionary = {
4
4
  en: {
5
- builtin: 'Built-in',
5
+ 'built_in': 'Built-in',
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
- builtin: 'Embutido',
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 { VisibilityLevelEnum } from '@stack-spot/portal-network/api/ai'
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 = VisibilityLevelEnum | 'built-in'
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
- 'built-in': 'Built-in',
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
- 'built-in': 'Embutido',
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.',
@@ -4,7 +4,7 @@ export interface Labeled {
4
4
  }
5
5
 
6
6
  export interface LabeledWithImage extends Labeled {
7
- image?: string,
7
+ image?: string | undefined | null,
8
8
  }
9
9
 
10
10
  export interface LabeledAgent extends LabeledWithImage {
@@ -1,11 +1,9 @@
1
- import { BuiltinToolResponse, ToolkitsInAgentResponse } from '@stack-spot/portal-network/api/agent'
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: ToolkitsInAgentResponse | undefined): ToolWithImage | undefined {
6
- for (const toolkit of toolkits?.builtins ?? []) {
7
- for (const tool of toolkit.tools ?? []) {
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 { agentClient, AgentVisibilityLevel } from '@stack-spot/portal-network'
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
- interface Props {
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 }] = agentClient.agentById.useStatefulQuery(
20
- { agentId: agentId!, builtIn: visibility === 'BUILT-IN' },
21
- { enabled: !!agentId },
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?.knowledge_sources_config?.knowledge_sources_details?.map((ks, index) => (
26
- <li key={index}><Badge palette="teal" appearance="square">{ks.name}</Badge></li>
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,33 @@ export const AgentDescription = ({ agentId, llm, description, numberOfKnowledgeS
36
28
  }, [numberOfKnowledgeSources])
37
29
  const tools = useMemo(() => {
38
30
  const result: React.ReactElement[] = []
39
- for (const kit of agent?.toolkits?.builtins ?? []) {
40
- for (const tool of kit.tools ?? []) {
41
- result.push(<li key={tool.id}><ToolBadge name={tool.name || tool.id || 'unknown'} image={kit.image_url} /></li>)
42
- }
31
+ const builtInTools = agent?.toolkits?.builtin_toolkits?.[0].tools
32
+ for (const tool of builtInTools ?? []) {
33
+ const toolWithImage = toolById(tool.id, toolKits)
34
+ result.push(<li key={tool.id}>
35
+ <ToolBadge name={toolWithImage?.name || toolWithImage?.id || 'unknown'} image={toolWithImage?.image} />
36
+ </li>)
43
37
  }
44
38
  return result
45
39
  }, [agent])
46
40
 
47
41
  return (
48
42
  <AgentDescriptionBox>
49
- {description && <section>
43
+ {agent?.description && <section>
50
44
  <Text appearance="microtext1" className="title">{t.description}</Text>
51
- <Text>{description}</Text>
45
+ <Text>{agent?.description}</Text>
52
46
  </section>}
53
47
  {(!!numberOfKnowledgeSources || !!knowledgeSources?.length) && <section>
54
48
  <Text appearance="microtext1" className="title">Knowledge sources</Text>
55
- <ul>{isLoading ? skeleton : knowledgeSources}</ul>
49
+ <ul>{isLoading || isLoadingToolKit ? skeleton : knowledgeSources}</ul>
56
50
  </section>}
57
51
  {!!tools.length && <section>
58
52
  <Text appearance="microtext1" className="title">{t.tools}</Text>
59
53
  <ul>{tools}</ul>
60
54
  </section>}
61
- {llm && <section>
55
+ {agent?.model_name && <section>
62
56
  <Text appearance="microtext1" className="title">LLM</Text>
63
- <Badge palette="orange" appearance="square">{llm}</Badge>
57
+ <Badge palette="orange" appearance="square">{agent?.model_name}</Badge>
64
58
  </section>}
65
59
  </AgentDescriptionBox>
66
60
  )
@@ -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="FAVORITE" agent={agent} /> },
27
- { title: t.builtin, content: <AgentsTab key="builtin" visibility="BUILT-IN" agent={agent} /> },
28
- { title: t.personal, content: <AgentsTab key="personal" visibility="PERSONAL" agent={agent} /> },
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="FAVORITE" agent={agent} /> },
31
- { title: t.builtin, content: <AgentsTab key="builtin" visibility="BUILT-IN" agent={agent} /> },
32
- { title: t.personal, content: <AgentsTab key="personal" visibility="PERSONAL" agent={agent} /> },
33
- { title: t.shared, content: <AgentsTab key="shared" visibility="SHARED" agent={agent} /> },
34
- { title: t.spots, content: <AgentsTabWorkspace key="workspace" visibility="WORKSPACE" agent={agent} /> },
35
- { title: t.account, content: <AgentsTab key="account" visibility="ACCOUNT" agent={agent} /> },
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 { agentClient, AgentResponseWithBuiltIn, workspaceAiClient } from '@stack-spot/portal-network'
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: VisibilityLevel | 'BUILT-IN',
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 = agentClient.agentDefault.useQuery({})
35
+ const agentDefault = agentToolsClient.agentDefault.useQuery()
37
36
  const agents = workspaceId
38
- ? workspaceAiClient.getAgentFromWorkspaceAi.useQuery({ workspaceId })
39
- : agentClient.allAgents.useQuery({ visibilities: [visibility] })
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 unknown 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('agent', { id: value.id, label: value.name, image: value.avatar, builtIn: !!value.builtIn, slug: value.slug })
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: !!newValue.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 = () => agentClient.allAgents.useQuery({ visibilities: ['FAVORITE'] })
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 agentClient.allAgents.invalidate({ visibilities: ['FAVORITE'] })
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 agentClient.allAgents.invalidate({ visibilities: ['FAVORITE'] })
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 { agentClient } from '@stack-spot/portal-network'
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,7 +193,7 @@ 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 [agent] = agentClient.agentById.useStatefulQuery({ agentId, builtIn: !!entry?.agent?.builtIn }, { enabled: !!agentId })
196
+ const [toolKits] = agentToolsClient.tools.useStatefulQuery({}, { enabled: !!agentId })
197
197
  const [copied, setCopied] = useState(false)
198
198
  const [showUserButtonCopy, setShowUserButtonCopy] = useState(false)
199
199
 
@@ -348,7 +348,7 @@ export const ChatMessage = ({ message, isLast, beforeMessage, afterMessage }: Pr
348
348
  className="tools-badge"
349
349
  label={t.tools}
350
350
  images={entry.tools.slice(0, 3).map((id) => {
351
- const tool = toolById(id, agent?.toolkits)
351
+ const tool = toolById(id, toolKits)
352
352
  return { key: id, name: tool?.name || id, icon: <Cog />, url: tool?.image }
353
353
  })}
354
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, getAllAgents } from './utils'
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
- getAllAgents(),
96
+ agentToolsClient.agentsByIds.query({ searchAgentsRequest: { ids: historyAgentIds } }),
95
97
  ])
96
- const agent = agents.find(a => a.id === last(chat.history)?.custom_agent?.id)
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: agents.find(a => a.id === item.custom_agent?.id),
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 { agentClient, aiClient, workspaceClient } from '@stack-spot/portal-network'
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 { agentClient } from '@stack-spot/portal-network'
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] = agentClient.agent.useStatefulQuery({ agentId: id! })
15
+ const [agent] = agentToolsClient.agent.useStatefulQuery({ agentId: id! })
16
16
  const chat = useCurrentChat()
17
- const suggestions = useMemo(() => agent?.suggested_prompts?.map((prompt, index) => (
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?.suggested_prompts])
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 { agentClient, AgentResponseWithBuiltIn } from '@stack-spot/portal-network'
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 agentClient.allAgents.useQuery({ visibilities: ['PERSONAL', 'BUILT-IN'] })
56
+ return agentToolsClient.allAgents.useQuery({ visibilities: ['personal', 'built_in'] })
57
57
  }
58
- return agentClient.allAgents.useQuery({ visibilities: ['ACCOUNT', 'SHARED', 'PERSONAL', 'BUILT-IN', 'WORKSPACE'] })
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', 'built-in'] : ['favorite', 'personal', 'workspace', 'account', 'shared', 'built-in'],
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 { agentClient } from '@stack-spot/portal-network'
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 = agentClient.agentDefault.useQuery({})
12
+ const agentDefault = agentToolsClient.agentDefault.useQuery()
13
13
  const widget = useWidget()
14
14
  const chat = useCurrentChat()
15
15
  const agent = useCurrentChatState('agent')
@@ -3,7 +3,7 @@ import { interpolate } from '@stack-spot/portal-translate'
3
3
  import { useCallback, useEffect, useRef, useState } from 'react'
4
4
  import { AdaptiveTextArea } from '../../components/AdaptiveTextArea'
5
5
  import { ProgressBar } from '../../components/ProgressBar'
6
- import { useCurrentChat, useCurrentChatState, useWidgetState } from '../../context/hooks'
6
+ import { useCurrentChat, useCurrentChatState } from '../../context/hooks'
7
7
  import { quickCommandRegex } from '../../regex'
8
8
  import { ChatEntry } from '../../state/ChatEntry'
9
9
  import { checkIsTrial } from '../../utils/check-is-trial'
@@ -16,7 +16,7 @@ import { useUserEntryHistoryShortcut } from './chat-entry-history'
16
16
  import { ContextBar } from './ContextBar'
17
17
  import { useMessageInputDictionary } from './dictionary'
18
18
  import { QuickCommandSelector } from './QuickCommandSelector'
19
- import { MAX_INPUT_HEIGHT, MessageInputBox, MIN_INPUT_HEIGHT } from './styled'
19
+ import { MessageInputBox } from './styled'
20
20
  import { UploadBar } from './UploadBar'
21
21
  import { UploadDragNDrop, useUploadDragDrop } from './UploadDragNDrop'
22
22
 
@@ -25,7 +25,7 @@ import { UploadDragNDrop, useUploadDragDrop } from './UploadDragNDrop'
25
25
  * going to be used for the question and the buttons to send, cancel, set the workspace, among others. This also includes the Quick
26
26
  * Commands panel for auto completing.
27
27
  */
28
- export const MessageInput = () => {
28
+ export const MessageInput = ({ containerRef }: { containerRef?: React.RefObject<HTMLElement> }) => {
29
29
  const t = useMessageInputDictionary()
30
30
  const [focused, setFocused] = useState(false)
31
31
  const [, setExpanded] = useState(true)
@@ -33,7 +33,6 @@ export const MessageInput = () => {
33
33
  const chat = useCurrentChat()
34
34
  const isLoading = useCurrentChatState('isLoading') ?? false
35
35
  const value = useCurrentChatState('nextMessage') ?? ''
36
- const isMinimized = useWidgetState('isMinimized')
37
36
  const textAreaRef = useRef<HTMLTextAreaElement>(null)
38
37
  const agentLabel = useCurrentChatState('agent')?.label
39
38
  const { handleKeyDown, handleKeyUp } = useUserEntryHistoryShortcut()
@@ -120,6 +119,7 @@ export const MessageInput = () => {
120
119
  <div className={listToClass(['action-box', focused && 'focused', isLoading && 'disabled'])}>
121
120
  <ButtonAgent />
122
121
  <AdaptiveTextArea
122
+ containerRef={containerRef}
123
123
  ref={textAreaRef}
124
124
  placeholder={
125
125
  agentLabel
@@ -134,7 +134,6 @@ export const MessageInput = () => {
134
134
  onKeyUp={handleKeyUp}
135
135
  onIncreaseSize={() => setExpanded(false)}
136
136
  onResetSize={() => !expansionLocked.current && setExpanded(true)}
137
- maxHeight={isMinimized ? MIN_INPUT_HEIGHT : MAX_INPUT_HEIGHT}
138
137
  />
139
138
  </div>
140
139
  </div>