@stack-spot/ai-chat-widget 1.0.0-dev.1769003016623 → 1.0.0-dev.1769120820021

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 (79) hide show
  1. package/dist/app-metadata.json +3 -3
  2. package/dist/chat-interceptors/send-message.d.ts.map +1 -1
  3. package/dist/chat-interceptors/send-message.js +5 -1
  4. package/dist/chat-interceptors/send-message.js.map +1 -1
  5. package/dist/components/Selector/SelectVersion.d.ts +12 -0
  6. package/dist/components/Selector/SelectVersion.d.ts.map +1 -0
  7. package/dist/components/Selector/SelectVersion.js +33 -0
  8. package/dist/components/Selector/SelectVersion.js.map +1 -0
  9. package/dist/components/Selector/index.d.ts +2 -0
  10. package/dist/components/Selector/index.d.ts.map +1 -1
  11. package/dist/components/Selector/index.js +5 -2
  12. package/dist/components/Selector/index.js.map +1 -1
  13. package/dist/components/Selector/styled.d.ts +2 -0
  14. package/dist/components/Selector/styled.d.ts.map +1 -1
  15. package/dist/components/Selector/styled.js +45 -0
  16. package/dist/components/Selector/styled.js.map +1 -1
  17. package/dist/hooks/enabled-feature-flags.d.ts +5 -0
  18. package/dist/hooks/enabled-feature-flags.d.ts.map +1 -0
  19. package/dist/hooks/enabled-feature-flags.js +28 -0
  20. package/dist/hooks/enabled-feature-flags.js.map +1 -0
  21. package/dist/state/types.d.ts +1 -0
  22. package/dist/state/types.d.ts.map +1 -1
  23. package/dist/utils/tools.d.ts +5 -5
  24. package/dist/utils/tools.d.ts.map +1 -1
  25. package/dist/utils/tools.js +2 -2
  26. package/dist/utils/tools.js.map +1 -1
  27. package/dist/views/Agents/AgentDescription.d.ts +6 -2
  28. package/dist/views/Agents/AgentDescription.d.ts.map +1 -1
  29. package/dist/views/Agents/AgentDescription.js +25 -10
  30. package/dist/views/Agents/AgentDescription.js.map +1 -1
  31. package/dist/views/Agents/AgentsTab.d.ts.map +1 -1
  32. package/dist/views/Agents/AgentsTab.js +21 -4
  33. package/dist/views/Agents/AgentsTab.js.map +1 -1
  34. package/dist/views/Agents/dictionary.d.ts +1 -1
  35. package/dist/views/Agents/dictionary.d.ts.map +1 -1
  36. package/dist/views/Agents/dictionary.js +2 -0
  37. package/dist/views/Agents/dictionary.js.map +1 -1
  38. package/dist/views/Chat/ChatMessage.d.ts.map +1 -1
  39. package/dist/views/Chat/ChatMessage.js +6 -5
  40. package/dist/views/Chat/ChatMessage.js.map +1 -1
  41. package/dist/views/ChatHistory/utils.d.ts.map +1 -1
  42. package/dist/views/ChatHistory/utils.js +14 -7
  43. package/dist/views/ChatHistory/utils.js.map +1 -1
  44. package/dist/views/Home/CustomAgent.js +3 -3
  45. package/dist/views/Home/CustomAgent.js.map +1 -1
  46. package/dist/views/MessageInput/AgentSelector.d.ts.map +1 -1
  47. package/dist/views/MessageInput/AgentSelector.js +11 -1
  48. package/dist/views/MessageInput/AgentSelector.js.map +1 -1
  49. package/dist/views/MessageInput/ModelSwitcher/index.d.ts.map +1 -1
  50. package/dist/views/MessageInput/ModelSwitcher/index.js +3 -1
  51. package/dist/views/MessageInput/ModelSwitcher/index.js.map +1 -1
  52. package/dist/views/MessageInput/ModelSwitcher/utils.d.ts +2 -2
  53. package/dist/views/MessageInput/ModelSwitcher/utils.d.ts.map +1 -1
  54. package/dist/views/MessageInput/ModelSwitcher/utils.js +6 -6
  55. package/dist/views/MessageInput/ModelSwitcher/utils.js.map +1 -1
  56. package/dist/views/Resources.js +8 -5
  57. package/dist/views/Resources.js.map +1 -1
  58. package/dist/views/Tools.js +3 -2
  59. package/dist/views/Tools.js.map +1 -1
  60. package/package.json +2 -2
  61. package/src/app-metadata.json +3 -3
  62. package/src/chat-interceptors/send-message.ts +6 -2
  63. package/src/components/Selector/SelectVersion.tsx +55 -0
  64. package/src/components/Selector/index.tsx +11 -2
  65. package/src/components/Selector/styled.ts +47 -0
  66. package/src/hooks/enabled-feature-flags.ts +31 -0
  67. package/src/state/types.ts +1 -0
  68. package/src/utils/tools.ts +4 -4
  69. package/src/views/Agents/AgentDescription.tsx +48 -14
  70. package/src/views/Agents/AgentsTab.tsx +31 -13
  71. package/src/views/Agents/dictionary.ts +2 -1
  72. package/src/views/Chat/ChatMessage.tsx +8 -6
  73. package/src/views/ChatHistory/utils.ts +18 -10
  74. package/src/views/Home/CustomAgent.tsx +4 -4
  75. package/src/views/MessageInput/AgentSelector.tsx +15 -5
  76. package/src/views/MessageInput/ModelSwitcher/index.tsx +3 -2
  77. package/src/views/MessageInput/ModelSwitcher/utils.tsx +9 -8
  78. package/src/views/Resources.tsx +10 -6
  79. package/src/views/Tools.tsx +5 -4
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@stack-spot/ai-chat-widget",
3
- "version": "1.0.0-dev.1769003016623",
4
- "date": "Wed Jan 21 2026 13:43:43 GMT+0000 (Coordinated Universal Time)",
3
+ "version": "1.0.0-dev.1769120820021",
4
+ "date": "Thu Jan 22 2026 22:27:05 GMT+0000 (Coordinated Universal Time)",
5
5
  "dependencies": [
6
6
  {
7
7
  "name": "@stack-spot/app-metadata",
@@ -125,7 +125,7 @@
125
125
  },
126
126
  {
127
127
  "name": "@stack-spot/portal-network",
128
- "version": "1.0.0-dev.1768944806600(@stack-spot/auth@6.1.0)(@stack-spot/opa@2.5.0(@stack-spot/auth@6.1.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(@stack-spot/portal-translate@2.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)"
128
+ "version": "1.0.0-dev.1769117840606(@stack-spot/auth@6.1.0)(@stack-spot/opa@2.5.0(@stack-spot/auth@6.1.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(@stack-spot/portal-translate@2.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)"
129
129
  },
130
130
  {
131
131
  "name": "@stack-spot/portal-theme",
@@ -202,8 +202,12 @@ export async function sendMessageInterceptor(entry: ChatEntry, chat: ChatState,
202
202
  chat.set('label', content || entry.getValue().upload?.[0]?.name || 'Chat')
203
203
  chat.untitled = false
204
204
  }
205
-
206
- const stream = aiClient.sendChatMessage({ context, user_prompt: buildPrompt(content, data) })
205
+
206
+ const stream = aiClient.sendChatMessage({
207
+ context,
208
+ user_prompt: buildPrompt(content, data),
209
+ agent_version_number: chat.get('agent')?.agent_version_number,
210
+ })
207
211
  signal.addEventListener('abort', () => stream.cancel())
208
212
  const botEntry = ChatEntry.createStreamedBotEntry()
209
213
  // we add the chat entry and show the streaming if the streaming feature is enabled
@@ -0,0 +1,55 @@
1
+
2
+ import { Select } from '@stack-spot/citric-react'
3
+ import { useTranslate } from '@stack-spot/portal-translate'
4
+ import { Dispatch, MouseEvent, SetStateAction, useEffect, useState } from 'react'
5
+ import { isEqual } from 'lodash'
6
+ import { VersionSelector } from './styled'
7
+
8
+ interface Props {
9
+ value?: number,
10
+ onChange: Dispatch<SetStateAction<number | undefined>>,
11
+ options?: number[],
12
+ lazyLoadOptions?: boolean,
13
+ useVersions?: (id: string, enabled: boolean) => number[] | undefined,
14
+ id: string,
15
+ }
16
+
17
+ export const SelectVersion = ({ useVersions, value, onChange, options: initialOptions, id, lazyLoadOptions=false }: Props) => {
18
+ const t = useTranslate(dictionary)
19
+ const [options, setOptions] = useState(initialOptions)
20
+ const [enabled, setEnabled] = useState(!lazyLoadOptions)
21
+ const versions = useVersions?.(id, enabled)
22
+
23
+ const onClick = (e?: MouseEvent<HTMLDivElement>) => {
24
+ e?.stopPropagation()
25
+ if (lazyLoadOptions) {
26
+ setEnabled(true)
27
+ }
28
+ }
29
+
30
+ useEffect(() => {
31
+ if (lazyLoadOptions && !isEqual(versions, options)){
32
+ setOptions(versions)
33
+ }
34
+ }, [versions])
35
+
36
+ return (
37
+ <VersionSelector>
38
+ <Select className="version-selector"
39
+ options={options || []}
40
+ value={value}
41
+ onChange={onChange}
42
+ onClick={onClick}
43
+ renderLabel={(item) =>`${t.version} ${item}`} />
44
+ </VersionSelector>
45
+ )
46
+ }
47
+
48
+ const dictionary = {
49
+ en: {
50
+ version: 'Version',
51
+ },
52
+ pt: {
53
+ version: 'Versão',
54
+ },
55
+ }
@@ -10,6 +10,7 @@ import { useCurrentChatState, useWidgetState } from '../../context/hooks'
10
10
  import { getUrlToStackSpotAI } from '../../utils/url'
11
11
  import { ButtonFavorite } from '../ButtonFavorite'
12
12
  import { Fading } from '../Fading'
13
+ import { SelectVersion } from './SelectVersion'
13
14
  import { SelectorBox } from './styled'
14
15
 
15
16
  type SectionVisibility = AgentVisibilityLevel | VisibilityLevelEnum
@@ -20,6 +21,7 @@ interface Item {
20
21
  slug: string,
21
22
  description: string,
22
23
  visibility_level: SectionVisibility,
24
+ version_number?: number,
23
25
  }
24
26
 
25
27
  interface Favorite<T> {
@@ -69,6 +71,8 @@ interface SelectorConfig<T> {
69
71
  regex: RegExp,
70
72
  urlBuilder: (item: T) => string,
71
73
  searchProp: keyof T,
74
+ isEnabledVersionContent?: boolean,
75
+ useVersions?: (id: string, enabled: boolean) => number[] | undefined,
72
76
  isEnabled: boolean,
73
77
  sections: SectionVisibility[],
74
78
  renderComponentItem: FC<T>,
@@ -91,10 +95,11 @@ interface SelectorProps<T> {
91
95
 
92
96
  const ListItem = <T extends Item>({ item, selectorConfig, onSelect, favorite }: ListItemProps<T>) => {
93
97
  const t = useTranslate(dictionary)
94
- const { urlBuilder, renderComponentItem } = selectorConfig
98
+ const { urlBuilder, renderComponentItem, useVersions, isEnabledVersionContent } = selectorConfig
95
99
  const linkTitle = interpolate(t.open, item.slug)
96
100
  const listFavorites = favorite?.useFavorites?.()
97
-
101
+ const [selectedVersion, setSelectedVersion] = useState(item.version_number)
102
+
98
103
  return (
99
104
  <li>
100
105
  <button
@@ -106,6 +111,10 @@ const ListItem = <T extends Item>({ item, selectorConfig, onSelect, favorite }:
106
111
  >
107
112
  {renderComponentItem(item)}
108
113
  </button>
114
+ {isEnabledVersionContent &&
115
+ <SelectVersion options={item.version_number ? [item.version_number] : []} id={item.id}
116
+ value={selectedVersion} onChange={setSelectedVersion} lazyLoadOptions={true} useVersions={useVersions}
117
+ /> }
109
118
  <IconLink
110
119
  icon="ExternalLink"
111
120
  title={linkTitle}
@@ -156,3 +156,50 @@ export const SelectorBox = styled.div<{ $tabsCount: number }>`
156
156
  }
157
157
  }
158
158
  `
159
+
160
+ export const VersionSelector = styled.div`
161
+ position: relative;
162
+ min-width: 100px;
163
+
164
+ .version-selector {
165
+ height: 28px;
166
+ position: absolute;
167
+ top: -18px;
168
+ left: -12px;
169
+
170
+ header {
171
+ height: 20px;
172
+ background-color: ${theme.color.light[300]};
173
+ border: none;
174
+ margin-bottom: 0;
175
+ gap: 0;
176
+ padding: 0;
177
+
178
+ }
179
+ .selection-panel .options{
180
+ overflow: hidden;
181
+ }
182
+ li {
183
+ gap: 5px;
184
+ padding: 0 8px 0 !important;
185
+ padding-left: 5px;
186
+ }
187
+ }
188
+
189
+ `
190
+
191
+ export const VersionSelectorBox = styled.div`
192
+ border: 1px solid ${theme.color.light[500]};
193
+ border-radius: 4px;
194
+ .version-selector {
195
+ position: relative;
196
+ top: 0;
197
+ left: 0;
198
+ }
199
+ > div {
200
+ position: relative;
201
+ .options {
202
+ overflow: hidden;
203
+ }
204
+ }
205
+ `
@@ -0,0 +1,31 @@
1
+ import { accountClient } from '@stack-spot/portal-network'
2
+
3
+ const useEnabledFeatureFlags = (resourceType?: string, resourceSlug?: string) => {
4
+ const queryParams = resourceType && resourceSlug ? { [resourceType]: resourceSlug } : {}
5
+ const [featureFlags, , error, { isLoading }] = accountClient.getEnabledFeatureFlagsForAccount.useStatefulQuery({
6
+ queryParams,
7
+ })
8
+ return { featureFlags, isLoading, error }
9
+ }
10
+
11
+ export const useIsFeatureFlagEnabled = (
12
+ flagSlug: string,
13
+ resourceType?: string,
14
+ resourceSlug?: string,
15
+ ) => {
16
+ const { featureFlags, isLoading } = useEnabledFeatureFlags(resourceType, resourceSlug)
17
+ if (resourceType && resourceSlug) {
18
+ const featureFlag = featureFlags?.find((flag) => flag.slug === flagSlug)
19
+ const resourcesByType = featureFlag?.resources?.[resourceType]
20
+ if (!!featureFlag && !!resourcesByType) {
21
+ if (resourcesByType.mode === 'ALL') {
22
+ return { flagEnabled: true, isLoading }
23
+ } else {
24
+ return { flagEnabled: !!featureFlag.resources?.[resourceType].slugs.some((slug) => slug === resourceSlug), isLoading }
25
+ }
26
+ }
27
+ return { flagEnabled: false, isLoading }
28
+ } else {
29
+ return { flagEnabled: !!featureFlags?.some((flag) => flag.slug === flagSlug), isLoading }
30
+ }
31
+ }
@@ -11,6 +11,7 @@ export interface LabeledAgent extends LabeledWithImage {
11
11
  builtIn?: boolean,
12
12
  slug?: string,
13
13
  visibility_level?: string,
14
+ agent_version_number?: number,
14
15
  }
15
16
 
16
17
  export interface FileSize {
@@ -1,9 +1,9 @@
1
1
 
2
- export type ToolWithImage = { id?: string, image?: string, name: string, description?: string }
2
+ export type ToolWithImage = { id?: string | null, image?: string, name?: string, description?: string }
3
3
 
4
4
  interface Toolkit {
5
5
  id?: string | null,
6
- tools?: { id?: string, name?: string, description?: string, function?: { name: string, description?: string } }[] | null,
6
+ tools?: { id?: string | null, name?: string, description?: string, function?: { name: string, description: string } | null }[] | null,
7
7
  image_url?: string | null,
8
8
  avatar?: string | null,
9
9
  }
@@ -22,8 +22,8 @@ export function toolById(id: string, toolkits: Toolkit[] | undefined): ToolWithI
22
22
  if (mcp) {
23
23
  const [, toolkitId, toolName] = mcp
24
24
  const toolkit = toolkits?.find(tk => tk.id === toolkitId)
25
- const tool = toolkit?.tools?.find(t => t.name === toolName)
26
- return { id, image: toolkit?.avatar ?? undefined, name: toolName, description: tool?.function?.description }
25
+ const tool = toolkit?.tools?.find(t => t.name === toolName || t.function?.name === toolName)
26
+ return { id, image: toolkit?.avatar ?? undefined, name: tool?.function?.name, description: tool?.function?.description }
27
27
  }
28
28
  const { tool, toolkit } = findToolById(id, toolkits ?? []) ?? {}
29
29
  return (tool && toolkit)
@@ -1,17 +1,31 @@
1
1
  import { Icon } from '@stack-spot/citric-icons'
2
- import { AsyncContent, Badge, Card, IconBox, ImageBox, ImageWithFallback, Text } from '@stack-spot/citric-react'
2
+ import { AsyncContent, Badge, Card, IconBox, ImageBox, ImageWithFallback, Row, Text } from '@stack-spot/citric-react'
3
3
  import { agentToolsClient } from '@stack-spot/portal-network'
4
- import { useMemo } from 'react'
4
+ import { useEffect, useMemo, useState } from 'react'
5
+ import { SelectVersion } from '../../components/Selector/SelectVersion'
6
+ import { VersionSelectorBox } from '../../components/Selector/styled'
5
7
  import { useAgentsDictionary } from './dictionary'
6
8
  import { AgentDescriptionBox } from './styled'
7
9
 
8
- export const AgentDescription = ({ agentId }: { agentId?: string }) => {
10
+ interface Props {
11
+ agentId?: string,
12
+ enableVersionSelect?: boolean,
13
+ onVersionChange?: (version?: number) => void,
14
+ }
15
+
16
+ export const AgentDescription = ({ agentId, enableVersionSelect, onVersionChange }:Props) => {
9
17
  const t = useAgentsDictionary()
10
- const [agent,, error, { isLoading }] = agentToolsClient.agent.useStatefulQuery({ agentId: agentId! }, { enabled: !!agentId })
11
- const numberOfKnowledgeSources = agent?.knowledge_sources_config?.knowledge_sources.length ?? 0
18
+ const [selectedVersion, setSelectedVersion] = useState<number | undefined>(undefined)
19
+ const [agent,, error, { isLoading }] = agentToolsClient.agentV2.useStatefulQuery({ agentCoreId: agentId!,
20
+ versionNumber: selectedVersion }, { enabled: !!agentId })
21
+ const [listVersions, , errorAgentWithVersion, { isLoading: isLoadingAgentWithVersions }] =
22
+ agentToolsClient.listAgentVersions.useStatefulQuery({ agentCoreId: agentId! },
23
+ { enabled: enableVersionSelect && !!agentId })
24
+ const optionsVersions = listVersions?.map((version) => version.version_number)
25
+ const numberOfKnowledgeSources = agent?.version.knowledge_sources_config?.knowledge_sources.length ?? 0
12
26
 
13
27
  const knowledgeSources = useMemo(
14
- () => agent?.knowledge_sources_config?.knowledge_sources_details?.map((ks, index) => (
28
+ () => agent?.version.knowledge_sources_config?.knowledge_sources_details?.map((ks, index) => (
15
29
  <li key={index}>
16
30
  <Card gap="10px" direction="row" flex={1} size="xxs" bgLevel={500} justifyContent="space-between">
17
31
  <Text color="light.contrastText">{ks.name}</Text>
@@ -21,12 +35,12 @@ export const AgentDescription = ({ agentId }: { agentId?: string }) => {
21
35
  )),
22
36
  [agent],
23
37
  )
24
-
38
+
25
39
  const { tools, multiAgents } = useMemo(() => {
26
40
  const tools: React.ReactElement[] = []
27
41
  const multiAgents: React.ReactElement[] = []
28
- const builtInTools = agent?.toolkits?.builtin_toolkits ?? []
29
- const customToolkits = agent?.toolkits?.custom_toolkits ?? []
42
+ const builtInTools = agent?.version.toolkits?.builtin_toolkits ?? []
43
+ const customToolkits = agent?.version.toolkits?.custom_toolkits ?? []
30
44
  for (const toolkit of builtInTools) {
31
45
  for (const tool of toolkit.tools ?? []) {
32
46
  if (toolkit.id == 'UTILITIES'){
@@ -66,22 +80,42 @@ export const AgentDescription = ({ agentId }: { agentId?: string }) => {
66
80
  return { tools, multiAgents }
67
81
  }, [agent])
68
82
 
69
- const mcpToolkits = useMemo(() => agent?.toolkits?.mcp_toolkits?.map(t => (
83
+ const mcpToolkits = useMemo(() => agent?.version.toolkits?.mcp_toolkits?.map(t => (
70
84
  <li key={`mcp-${t.id}`}>
71
85
  <Card gap="10px" direction="row" flex={1} size="xxs" bgLevel={500}>
72
86
  <ImageBox><ImageWithFallback src={t.avatar ?? undefined} fallback={<Icon icon="Cog" />} /></ImageBox>
73
87
  <Text color="light.contrastText">{t.name}</Text>
74
88
  </Card>
75
89
  </li>
76
- )), [agent?.toolkits?.mcp_toolkits])
90
+ )), [agent?.version.toolkits?.mcp_toolkits])
91
+
92
+ useEffect(() => {
93
+ if (!selectedVersion && agent?.version.version_number !== selectedVersion){
94
+ setSelectedVersion(agent?.version.version_number)
95
+ }
96
+ }, [agent?.version.version_number])
97
+
98
+ const onChangeVersion = (version?: number) => {
99
+ setSelectedVersion(version)
100
+ onVersionChange?.(version)
101
+ }
77
102
 
78
103
  return (
79
- <AsyncContent loading={isLoading} error={error}>
104
+ <AsyncContent loading={isLoading || isLoadingAgentWithVersions} error={error || errorAgentWithVersion}>
80
105
  <AgentDescriptionBox>
81
106
  {agent?.description && <section>
82
107
  <Text appearance="microtext1" className="title">{t.description}</Text>
83
108
  <Text>{agent?.description}</Text>
84
109
  </section>}
110
+ {enableVersionSelect && optionsVersions && optionsVersions?.length > 0 && <section>
111
+ <VersionSelectorBox>
112
+ <Row justifyContent="space-between" p={4}>
113
+ <Text>{t.version}</Text>
114
+ <SelectVersion options={optionsVersions} value={selectedVersion}
115
+ onChange={(value?: any) => onChangeVersion(value)} id={agent?.id ?? ''} />
116
+ </Row>
117
+ </VersionSelectorBox>
118
+ </section>}
85
119
  {(!!numberOfKnowledgeSources || !!knowledgeSources?.length) && <section>
86
120
  <Text appearance="microtext1" className="title">Knowledge sources</Text>
87
121
  <ul>{knowledgeSources}</ul>
@@ -97,9 +131,9 @@ export const AgentDescription = ({ agentId }: { agentId?: string }) => {
97
131
  <Text appearance="microtext1" className="title">{t.multiAgent}</Text>
98
132
  <ul>{multiAgents}</ul>
99
133
  </section>}
100
- {agent?.model_name && <section>
134
+ {agent?.version.model_name && <section>
101
135
  <Text appearance="microtext1" className="title">LLM</Text>
102
- <Badge colorPalette="orange" appearance="square">{agent?.model_name}</Badge>
136
+ <Badge colorPalette="orange" appearance="square">{agent?.version.model_name}</Badge>
103
137
  </section>}
104
138
  </AgentDescriptionBox>
105
139
  </AsyncContent>
@@ -9,6 +9,7 @@ import { NavigationComponent } from '../../components/ComponentNavigator'
9
9
  import { DescribedRadioGroup } from '../../components/form/DescribedRadioGroup'
10
10
  import { WorkspaceTabNavigator } from '../../components/WorkspaceTabNavigator'
11
11
  import { useCurrentChat } from '../../context/hooks'
12
+ import { useIsFeatureFlagEnabled } from '../../hooks/enabled-feature-flags'
12
13
  import { useRightPanel } from '../../right-panel/hooks'
13
14
  import { ChatProperties } from '../../state/ChatState'
14
15
  import { AgentDescription } from './AgentDescription'
@@ -28,9 +29,10 @@ export const AgentsTab = ({ visibility, workspaceId, agent, showSubmitButton = t
28
29
  const chat = useCurrentChat()
29
30
  const { useFavorites, onAddFavorite, onRemoveFavorite } = useAgentFavorites()
30
31
  const [submitEnabled, setSubmitEnabled] = useState(false)
32
+ const featureFlag = useIsFeatureFlagEnabled('ENABLE_VERSION_CONTENT_AI')
31
33
  const listFavorites = useFavorites()
32
34
  const agentDefault = agentToolsClient.agentDefault.useQuery()
33
-
35
+ const [agentVersions, setAgentVersions] = useState<Record<string, number | undefined>>({})
34
36
  const [filter, setFilter] = useState<string | undefined>()
35
37
  const [apiFilter, setApiFilter] = useState<string | undefined>()
36
38
  const [isPending, startTransition] = useTransition()
@@ -59,15 +61,15 @@ export const AgentsTab = ({ visibility, workspaceId, agent, showSubmitButton = t
59
61
 
60
62
  const agents = workspaceId ? workspaceAgents : agentsData
61
63
 
62
- const initialValue = useMemo<AgentResponseWithBuiltIn | undefined>(
63
- () => {
64
- const initial = agent.current
65
- ? agents?.find(a => a.id === agent.current?.id)
66
- : chat.get('agent') ? agents?.find(a => a.id === chat.get('agent')?.id) : agentDefault as unknown as AgentResponseWithBuiltIn
67
- if (initial && !submitEnabled) setSubmitEnabled(true)
68
- return initial
69
- },
70
- [agents],
64
+ const initialValue = useMemo<AgentResponseWithBuiltIn | undefined>(() => {
65
+ const initial = agent.current
66
+ ? agents?.find(a => a.id === agent.current?.id)
67
+ : chat.get('agent') ?
68
+ agents?.find(a => a.id === chat.get('agent')?.id) : { ...agentDefault, suggested_prompts: null } as AgentResponseWithBuiltIn
69
+ if (initial && !submitEnabled) setSubmitEnabled(true)
70
+ return initial
71
+ },
72
+ [agents],
71
73
  )
72
74
 
73
75
  function submit() {
@@ -75,12 +77,26 @@ export const AgentsTab = ({ visibility, workspaceId, agent, showSubmitButton = t
75
77
  close()
76
78
  }
77
79
 
80
+ const onVersionChange = (ag: AgentResponseWithBuiltIn, version?: number) => {
81
+ setAgentVersions(prev => ({
82
+ ...prev,
83
+ [ag.id]: version,
84
+ }))
85
+
86
+ if (agent.current?.id === ag.id) {
87
+ agent.current = {
88
+ ...agent.current,
89
+ agent_version_number: version,
90
+ }
91
+ }
92
+ }
93
+
78
94
  return <>
79
95
  <div className="content">
80
96
  <DescribedRadioGroup
81
97
  fetchNextPage={fetchNextPage}
82
98
  hasNextPage={hasNextPage && !workspaceId}
83
- options={agents}
99
+ options={agents || []}
84
100
  initialValue={initialValue}
85
101
  filter={workspaceId ? undefined : filter}
86
102
  setFilter={workspaceId ? undefined : (value?: string) => {
@@ -89,7 +105,8 @@ export const AgentsTab = ({ visibility, workspaceId, agent, showSubmitButton = t
89
105
  }}
90
106
  onChange={(ag) => {
91
107
  agent.current = ag
92
- ? { ...ag, label: ag.name, image: ag.avatar!, slug: ag.slug, builtIn: ag.visibility_level === 'built_in' }
108
+ ? { ...ag, label: ag.name, image: ag.avatar!, slug: ag.slug, builtIn: ag.visibility_level === 'built_in',
109
+ agent_version_number: agentVersions[ag.id] ?? ag.version_number }
93
110
  : undefined
94
111
  setSubmitEnabled(true)
95
112
  }}
@@ -98,7 +115,8 @@ export const AgentsTab = ({ visibility, workspaceId, agent, showSubmitButton = t
98
115
  idOrSlug: ag.id,
99
116
  // below, "key" is important. I don't know why exactly, but sometimes the avatar doesn't update if we don't do this.
100
117
  image: <ImageWithFallback key={ag.id} src={ag.avatar ?? undefined} fallback={<Icon icon="Agent" />} />,
101
- description: <AgentDescription agentId={ag.id} />,
118
+ description: <AgentDescription agentId={ag.id} enableVersionSelect={featureFlag.flagEnabled}
119
+ onVersionChange={(version?: number) => onVersionChange(ag, version)} />,
102
120
  name: ag.name,
103
121
  listFavorites,
104
122
  onAddFavorite,
@@ -19,6 +19,7 @@ const dictionary = {
19
19
  tools: 'Tools',
20
20
  spots: 'Spots',
21
21
  multiAgent: 'Multi-agents',
22
+ version: 'Version',
22
23
  },
23
24
  pt: {
24
25
  title: 'Agentes',
@@ -38,7 +39,7 @@ const dictionary = {
38
39
  tools: 'Ferramentas',
39
40
  spots: 'Spots',
40
41
  multiAgent: 'Multi-agents',
41
-
42
+ version: 'Versão',
42
43
  },
43
44
  } satisfies Dictionary
44
45
 
@@ -215,14 +215,16 @@ export const ChatMessage = ({ message, isLast, beforeMessage, afterMessage, cust
215
215
  const chat = useCurrentChat()
216
216
  const agentId = entry.agent?.id ?? ''
217
217
  // enabled: we don't want to make any request if there is no agent
218
- const [agent] = agentToolsClient.agent.useStatefulQuery({ agentId }, { enabled: !!agentId })
218
+ const [agent] = agentToolsClient.agentV2.useStatefulQuery({ agentCoreId: agentId, versionNumber: entry.agent?.agent_version_number },
219
+ { enabled: !!agentId })
219
220
  const toolkits = useMemo(() => [
220
- ...agent?.toolkits?.builtin_toolkits ?? [],
221
- ...agent?.toolkits?.custom_toolkits ?? [],
222
- ...agent?.toolkits?.mcp_toolkits ?? [],
221
+ ...agent?.version?.toolkits?.builtin_toolkits ?? [],
222
+ ...agent?.version?.toolkits?.custom_toolkits ?? [],
223
+ ...agent?.version?.toolkits?.mcp_toolkits ?? [],
223
224
  ], [agent])
224
- const [agentsTools] = agentToolsClient.agentsByIds.useStatefulQuery(
225
- { searchAgentsRequest: { ids: entry.tools || [''] } }, { enabled: !!entry.tools?.length })
225
+ const agentsSearch = entry.tools?.map((id) => ({ agent_core_id: id })) ?? []
226
+ const [agentsTools] = agentToolsClient.agentsByIdsV2.useStatefulQuery(
227
+ { searchAgentsRequestV2: { agents: agentsSearch } }, { enabled: !!entry.tools?.length })
226
228
  const [copied, setCopied] = useState(false)
227
229
  const [showUserButtonCopy, setShowUserButtonCopy] = useState(false)
228
230
  const isPlanning = useCurrentChatState('isPlaning') ?? false
@@ -1,5 +1,5 @@
1
1
  import { agentToolsClient, aiClient, AnswerChatStep, ChatAgentTool, ChatStep, PlanningChatStep, workspaceClient } from '@stack-spot/portal-network'
2
- import { AgentModel } from '@stack-spot/portal-network/api/agent-tools'
2
+ import { AgentCoreWithSingleVersionResponse2 } from '@stack-spot/portal-network/api/agent-tools'
3
3
  import { last } from 'lodash'
4
4
  import { ChatEntry } from '../../state/ChatEntry'
5
5
  import { ChatProperties, ChatState } from '../../state/ChatState'
@@ -56,11 +56,11 @@ function toJSONString(data: any) {
56
56
  return `${data}`
57
57
  }
58
58
 
59
- function findTool(agent: AgentModel | undefined, id: string) {
59
+ function findTool(agent: AgentCoreWithSingleVersionResponse2 | undefined, id: string) {
60
60
  const allToolkits = [
61
- ...agent?.toolkits?.builtin_toolkits ?? [],
62
- ...agent?.toolkits?.custom_toolkits ?? [],
63
- ...agent?.toolkits?.mcp_toolkits ?? [],
61
+ ...agent?.version?.toolkits?.builtin_toolkits ?? [],
62
+ ...agent?.version?.toolkits?.custom_toolkits ?? [],
63
+ ...agent?.version?.toolkits?.mcp_toolkits ?? [],
64
64
  ]
65
65
  for (const toolkit of allToolkits) {
66
66
  for (const tool of toolkit.tools ?? []) {
@@ -75,9 +75,10 @@ async function stepsFromAgentInfo(
75
75
  ): Promise<ChatStep[] | undefined> {
76
76
  const planningInfo = agentInfo?.find(i => i.type === 'planning' && !!i.data)
77
77
  if (planningInfo) {
78
- let agent: AgentModel | undefined
78
+ let agent: AgentCoreWithSingleVersionResponse2 | undefined
79
79
  try {
80
- agent = agentId ? await agentToolsClient.agent.query({ agentId }) : undefined
80
+ //TODO: avaliar se vamos precisar da versao aqui
81
+ agent = agentId ? await agentToolsClient.agentV2.query({ agentCoreId: agentId }) : undefined
81
82
  } catch { /* empty */ }
82
83
  const planning: PlanningChatStep = {
83
84
  type: 'planning',
@@ -105,7 +106,7 @@ async function stepsFromAgentInfo(
105
106
  return {
106
107
  id: t.tool_id,
107
108
  executionId: t.tool_execution_id,
108
- name: tool?.name,
109
+ name: ('name' in tool ? tool.name : ('function' in tool ? tool?.function?.name : undefined) ?? ''),
109
110
  description: 'description' in tool ? tool.description : undefined,
110
111
  image: toolkit ? (('image_url' in toolkit ? toolkit?.image_url : toolkit?.avatar) ?? undefined) : undefined,
111
112
  goal: t.goal,
@@ -139,11 +140,18 @@ function toolsFromAgentInfo(agentInfo: any[] | null | undefined): string[] {
139
140
  */
140
141
  export async function loadChat(widget: WidgetState, conversationId: string) {
141
142
  const chat = await aiClient.chat.query({ conversationId })
142
- const historyAgentIds = chat.history?.map(item => item.custom_agent?.id).filter(Boolean) as string[] ?? []
143
+ const historyAgents = chat.history?.reduce<{ agent_core_id: string }[]>((accumulator, item) => {
144
+ const agentId = item.custom_agent?.id
145
+ if (agentId !== undefined) {
146
+ accumulator.push({ agent_core_id: agentId })
147
+ }
148
+ return accumulator
149
+ }, []) ?? []
150
+
143
151
  const [stack, workspace, agents] = await Promise.all([
144
152
  findStack(chat.ai_stack_id),
145
153
  findWorkspace(chat.workspace_id),
146
- agentToolsClient.agentsByIds.query({ searchAgentsRequest: { ids: historyAgentIds } }),
154
+ agentToolsClient.agentsByIdsV2.query({ searchAgentsRequestV2: { agents: historyAgents } }),
147
155
  ])
148
156
  const agentsAsLabeledAgents: LabeledAgent[] = agents
149
157
  .map((a) => ({ ...a, label: a.name, image: a.avatar ?? '', builtIn: a.visibility_level === 'built_in' }))
@@ -11,16 +11,16 @@ import { HomeBox } from './styled'
11
11
  * This is the home rendered when the agent is custom.
12
12
  */
13
13
  export const CustomAgent = () => {
14
- const { id, label, image } = useCurrentChatState('agent') ?? {}
15
- const [agent] = agentToolsClient.agent.useStatefulQuery({ agentId: id! })
14
+ const { id, label, image, agent_version_number } = useCurrentChatState('agent') ?? {}
15
+ const [agent] = agentToolsClient.agentV2.useStatefulQuery({ agentCoreId: id!, versionNumber: agent_version_number })
16
16
  const chat = useCurrentChat()
17
- const suggestions = useMemo(() => agent?.conversation_starter?.map((prompt, index) => (
17
+ const suggestions = useMemo(() => agent?.version?.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?.conversation_starter])
23
+ )), [agent?.version?.conversation_starter])
24
24
 
25
25
  function send(message: string) {
26
26
  chat.pushMessage(ChatEntry.createUserEntry(message))
@@ -5,16 +5,16 @@ import { VisibilityLevelEnum } from '@stack-spot/portal-network/api/agent-tools'
5
5
  import { useCallback } from 'react'
6
6
  import { Selector } from '../../components/Selector'
7
7
  import { useCurrentChat, useCurrentChatState, useWidgetState } from '../../context/hooks'
8
+ import { useIsFeatureFlagEnabled } from '../../hooks/enabled-feature-flags'
8
9
  import { agentRegex } from '../../regex'
9
10
  import { useAgentFavorites } from '../Agents/useAgentFavorites'
10
11
 
11
- type AgentWithSpaceName = AgentResponseWithBuiltIn
12
-
13
- const AgentItem = ({ avatar, name, spaceName }: AgentWithSpaceName) => {
12
+ const AgentItem = ({ avatar, name, spaceName }: AgentResponseWithBuiltIn) => {
14
13
  const avatarComponent = avatar
15
14
  ? <img style={{ width: '32px', height: '32px', borderRadius: '50%' }} src={avatar} />
16
15
  : <IconBox size="md" icon="Agent" style={{ backgroundColor: 'transparent' }} />
17
16
 
17
+
18
18
  return <Row gap="8px" style={{ flexWrap: 'nowrap' }}>
19
19
  {avatarComponent}
20
20
  <div>
@@ -31,10 +31,11 @@ export const AgentSelector = ({ inputRef, isTrial }: {
31
31
  const chat = useCurrentChat()
32
32
  const isAgentEnabled = useCurrentChatState('features').agent
33
33
  const spotId = useWidgetState('features')?.workspaceId
34
+ const featureFlag = useIsFeatureFlagEnabled('ENABLE_VERSION_CONTENT_AI')
34
35
 
35
36
  const { useFavorites, onAddFavorite, onRemoveFavorite } = useAgentFavorites()
36
37
 
37
- const onSelectItem = useCallback(async (agent: AgentResponseWithBuiltIn) => {
38
+ const onSelectItem = useCallback(async (agent: AgentResponseWithBuiltIn, selectedVersion?: number) => {
38
39
  const newValue = `@${agent.slug}`
39
40
  chat.set('nextMessage', undefined)
40
41
  chat.set(
@@ -42,10 +43,11 @@ export const AgentSelector = ({ inputRef, isTrial }: {
42
43
  {
43
44
  id: agent.id,
44
45
  label: agent.name,
45
- image: agent.avatar,
46
+ image: agent.avatar,
46
47
  slug: agent.slug,
47
48
  builtIn: agent.builtIn,
48
49
  visibility_level: agent.visibility_level,
50
+ agent_version_number: selectedVersion || agent.version_number,
49
51
  },
50
52
  )
51
53
 
@@ -70,6 +72,12 @@ export const AgentSelector = ({ inputRef, isTrial }: {
70
72
  }) }
71
73
  }
72
74
 
75
+ const getAgentVersions = (id: string, enabled: boolean) => {
76
+ const [listVersions] = agentToolsClient.listAgentVersions.useStatefulQuery({ agentCoreId: id }, { enabled })
77
+ const optionsVersions = listVersions?.map((version) => version.version_number)
78
+ return optionsVersions
79
+ }
80
+
73
81
  return <Selector
74
82
  inputRef={inputRef}
75
83
  favorite={{ useFavorites, onAddFavorite, onRemoveFavorite }}
@@ -85,8 +93,10 @@ export const AgentSelector = ({ inputRef, isTrial }: {
85
93
  ['favorite', 'personal', 'workspace', 'account', 'shared', 'built_in', 'recently_used'],
86
94
  renderComponentItem: AgentItem,
87
95
  isEnabled: isAgentEnabled,
96
+ isEnabledVersionContent: featureFlag.flagEnabled,
88
97
  onSelect: onSelectItem,
89
98
  useData: getAgents,
99
+ useVersions: getAgentVersions,
90
100
  }}
91
101
  />
92
102
  }