@stack-spot/ai-chat-widget 2.3.0-alpha.1 → 2.3.1-beta.1

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 (124) hide show
  1. package/CHANGELOG.md +119 -4
  2. package/dist/StackspotAIWidget.d.ts +1 -5
  3. package/dist/StackspotAIWidget.d.ts.map +1 -1
  4. package/dist/StackspotAIWidget.js +2 -2
  5. package/dist/StackspotAIWidget.js.map +1 -1
  6. package/dist/app-metadata.json +6 -6
  7. package/dist/chat-interceptors/quick-commands.d.ts.map +1 -1
  8. package/dist/chat-interceptors/quick-commands.js +8 -3
  9. package/dist/chat-interceptors/quick-commands.js.map +1 -1
  10. package/dist/chat-interceptors/send-message.d.ts.map +1 -1
  11. package/dist/chat-interceptors/send-message.js +140 -1
  12. package/dist/chat-interceptors/send-message.js.map +1 -1
  13. package/dist/state/ChatEntry.d.ts.map +1 -1
  14. package/dist/state/ChatState.d.ts +8 -0
  15. package/dist/state/ChatState.d.ts.map +1 -1
  16. package/dist/state/ChatState.js.map +1 -1
  17. package/dist/utils/chat.d.ts.map +1 -1
  18. package/dist/utils/chat.js +1 -0
  19. package/dist/utils/chat.js.map +1 -1
  20. package/dist/utils/check-is-trial.d.ts.map +1 -1
  21. package/dist/utils/check-is-trial.js +2 -6
  22. package/dist/utils/check-is-trial.js.map +1 -1
  23. package/dist/utils/knowledge-source.d.ts +2 -2
  24. package/dist/utils/planning-tool.d.ts +17 -0
  25. package/dist/utils/planning-tool.d.ts.map +1 -0
  26. package/dist/utils/planning-tool.js +32 -0
  27. package/dist/utils/planning-tool.js.map +1 -0
  28. package/dist/utils/update-tool-step.d.ts +3 -0
  29. package/dist/utils/update-tool-step.d.ts.map +1 -0
  30. package/dist/utils/update-tool-step.js +23 -0
  31. package/dist/utils/update-tool-step.js.map +1 -0
  32. package/dist/views/Agents/AgentsTab.d.ts.map +1 -1
  33. package/dist/views/Agents/AgentsTab.js +3 -4
  34. package/dist/views/Agents/AgentsTab.js.map +1 -1
  35. package/dist/views/Agents/useAgentFavorites.d.ts.map +1 -1
  36. package/dist/views/Agents/useAgentFavorites.js +1 -3
  37. package/dist/views/Agents/useAgentFavorites.js.map +1 -1
  38. package/dist/views/Chat/ChatMessage.d.ts +1 -1
  39. package/dist/views/Chat/ChatMessage.d.ts.map +1 -1
  40. package/dist/views/Chat/ChatMessage.js +21 -6
  41. package/dist/views/Chat/ChatMessage.js.map +1 -1
  42. package/dist/views/Chat/StepsList.d.ts +12 -2
  43. package/dist/views/Chat/StepsList.d.ts.map +1 -1
  44. package/dist/views/Chat/StepsList.js +156 -18
  45. package/dist/views/Chat/StepsList.js.map +1 -1
  46. package/dist/views/Chat/styled.d.ts.map +1 -1
  47. package/dist/views/Chat/styled.js +17 -10
  48. package/dist/views/Chat/styled.js.map +1 -1
  49. package/dist/views/MessageInput/AgentSelector.d.ts.map +1 -1
  50. package/dist/views/MessageInput/AgentSelector.js +2 -8
  51. package/dist/views/MessageInput/AgentSelector.js.map +1 -1
  52. package/dist/views/MessageInput/ButtonAgent.js +1 -1
  53. package/dist/views/MessageInput/ButtonAgent.js.map +1 -1
  54. package/dist/views/MessageInput/ButtonBar.d.ts +1 -2
  55. package/dist/views/MessageInput/ButtonBar.d.ts.map +1 -1
  56. package/dist/views/MessageInput/ButtonBar.js +3 -2
  57. package/dist/views/MessageInput/ButtonBar.js.map +1 -1
  58. package/dist/views/MessageInput/ModelSwitcher/index.d.ts +2 -0
  59. package/dist/views/MessageInput/ModelSwitcher/index.d.ts.map +1 -0
  60. package/dist/views/MessageInput/ModelSwitcher/index.js +25 -0
  61. package/dist/views/MessageInput/ModelSwitcher/index.js.map +1 -0
  62. package/dist/views/MessageInput/ModelSwitcher/utils.d.ts +30 -0
  63. package/dist/views/MessageInput/ModelSwitcher/utils.d.ts.map +1 -0
  64. package/dist/views/MessageInput/ModelSwitcher/utils.js +91 -0
  65. package/dist/views/MessageInput/ModelSwitcher/utils.js.map +1 -0
  66. package/dist/views/MessageInput/QuickCommandSelector.js +1 -1
  67. package/dist/views/MessageInput/QuickCommandSelector.js.map +1 -1
  68. package/dist/views/MessageInput/dictionary.d.ts +1 -1
  69. package/dist/views/MessageInput/dictionary.d.ts.map +1 -1
  70. package/dist/views/MessageInput/dictionary.js +6 -0
  71. package/dist/views/MessageInput/dictionary.js.map +1 -1
  72. package/dist/views/MessageInput/index.d.ts +1 -2
  73. package/dist/views/MessageInput/index.d.ts.map +1 -1
  74. package/dist/views/MessageInput/index.js +2 -2
  75. package/dist/views/MessageInput/index.js.map +1 -1
  76. package/dist/views/MessageInput/styled.d.ts +12 -0
  77. package/dist/views/MessageInput/styled.d.ts.map +1 -1
  78. package/dist/views/MessageInput/styled.js +35 -0
  79. package/dist/views/MessageInput/styled.js.map +1 -1
  80. package/dist/views/Resources.js.map +1 -1
  81. package/dist/views/Steps/FlowChart/NodeStep.js +1 -1
  82. package/dist/views/Steps/FlowChart/NodeStep.js.map +1 -1
  83. package/dist/views/Steps/FlowChart/layout.d.ts +1 -1
  84. package/dist/views/Steps/FlowChart/layout.d.ts.map +1 -1
  85. package/dist/views/Steps/FlowChart/layout.js +1 -0
  86. package/dist/views/Steps/FlowChart/layout.js.map +1 -1
  87. package/dist/views/Steps/FlowChart/types.d.ts +1 -1
  88. package/dist/views/Steps/FlowChart/types.d.ts.map +1 -1
  89. package/dist/views/Steps/StepModal.js +2 -2
  90. package/dist/views/Steps/StepModal.js.map +1 -1
  91. package/dist/views/Steps/dictionary.d.ts +1 -1
  92. package/dist/views/Steps/utils.d.ts +1 -1
  93. package/dist/views/Steps/utils.d.ts.map +1 -1
  94. package/package.json +4 -4
  95. package/src/StackspotAIWidget.tsx +1 -7
  96. package/src/app-metadata.json +6 -6
  97. package/src/chat-interceptors/quick-commands.ts +10 -3
  98. package/src/chat-interceptors/send-message.ts +156 -2
  99. package/src/state/ChatEntry.ts +6 -6
  100. package/src/state/ChatState.ts +8 -0
  101. package/src/utils/chat.ts +1 -0
  102. package/src/utils/check-is-trial.ts +2 -5
  103. package/src/utils/knowledge-source.ts +2 -2
  104. package/src/utils/planning-tool.ts +41 -0
  105. package/src/utils/update-tool-step.tsx +27 -0
  106. package/src/views/Agents/AgentsTab.tsx +3 -4
  107. package/src/views/Agents/useAgentFavorites.ts +1 -3
  108. package/src/views/Chat/ChatMessage.tsx +39 -18
  109. package/src/views/Chat/StepsList.tsx +340 -44
  110. package/src/views/Chat/styled.ts +17 -10
  111. package/src/views/MessageInput/AgentSelector.tsx +2 -7
  112. package/src/views/MessageInput/ButtonAgent.tsx +1 -1
  113. package/src/views/MessageInput/ButtonBar.tsx +3 -3
  114. package/src/views/MessageInput/ModelSwitcher/index.tsx +67 -0
  115. package/src/views/MessageInput/ModelSwitcher/utils.tsx +143 -0
  116. package/src/views/MessageInput/QuickCommandSelector.tsx +1 -1
  117. package/src/views/MessageInput/dictionary.ts +6 -0
  118. package/src/views/MessageInput/index.tsx +4 -4
  119. package/src/views/MessageInput/styled.ts +37 -0
  120. package/src/views/Resources.tsx +0 -1
  121. package/src/views/Steps/FlowChart/NodeStep.tsx +1 -1
  122. package/src/views/Steps/FlowChart/layout.ts +1 -0
  123. package/src/views/Steps/FlowChart/types.ts +1 -1
  124. package/src/views/Steps/StepModal.tsx +2 -2
@@ -0,0 +1,143 @@
1
+ import { CitricIconOutline, CitricIconSocial } from '@stack-spot/citric-icons'
2
+ import { IconBox } from '@stack-spot/citric-react'
3
+ import { AgentModel } from '@stack-spot/portal-network/api/agent-tools'
4
+ import { LlmModelsResponse, PaginatedResponseLlmModelsResponse } from '@stack-spot/portal-network/api/genAiInference'
5
+ import { theme } from '@stack-spot/portal-theme'
6
+ import { Dispatch, ReactElement } from 'react'
7
+ import { ChatState } from '../../../state/ChatState'
8
+
9
+ export interface ItemProps {
10
+ active?: boolean,
11
+ label?: string,
12
+ icon?: ReactElement,
13
+ self_hosted?: boolean,
14
+ onClick?: VoidFunction,
15
+ }
16
+
17
+ export const providerIcon: Record<string, CitricIconSocial | CitricIconOutline> = {
18
+ openai: 'OpenAI',
19
+ bedrock: 'AWSBedrock',
20
+ azure: 'Azure',
21
+ stackspot: 'StackSpot',
22
+ gemini: 'Gemini',
23
+ deepseek: 'DeepSeek',
24
+ anthropic: 'Anthropic',
25
+ }
26
+
27
+ export function getModelData(
28
+ chat: ChatState,
29
+ setVisibleMenu: Dispatch<React.SetStateAction<boolean>>,
30
+ agent?: AgentModel,
31
+ models?: PaginatedResponseLlmModelsResponse) {
32
+
33
+ const chatSelectedModelId = chat.get('selected_model_id')
34
+
35
+ const listModelsToShow = agent?.visibility_level !== 'built_in' && !!agent?.model_id ?
36
+ models?.items.filter((model) => agent?.available_llm_models?.find((modelAvailable) => modelAvailable.model_id === model.id)) :
37
+ models?.items
38
+
39
+ const modelAvailableDefault = agent?.available_llm_models?.find((model) => (model.is_default || model.model_id === agent.model_id))
40
+ const modelListData = parseModelList(chat, setVisibleMenu, listModelsToShow, modelAvailableDefault?.model_id)
41
+
42
+ if (agent?.visibility_level === 'built_in' || !agent?.model_id) {
43
+
44
+ const modelDefaultProviderType = models?.items.find((modelAccount) =>
45
+ chatSelectedModelId ? modelAccount.id === chatSelectedModelId :
46
+ modelAccount.resources.find((resource) => resource.is_default))?.model_configuration.provider.provider_type
47
+
48
+ const modelDefaultFromList = modelListData.find((model) => model?.active)
49
+
50
+ return { modelName: modelDefaultFromList?.label, modelProviderType: modelDefaultProviderType, listItemsData: modelListData }
51
+ }
52
+
53
+ const modelFromListModelsAccount = models?.items.find((modelAccount) => modelAccount.id === (chatSelectedModelId || agent.model_id))
54
+ const modelProviderType = modelFromListModelsAccount?.model_configuration.provider.provider_type
55
+ const modelSelectedName = modelFromListModelsAccount?.display_name || modelAvailableDefault?.model_name || agent?.model_name
56
+
57
+ const listItemsData =
58
+ modelListData && modelListData?.length > 0 ? modelListData :
59
+ [{
60
+ active: true,
61
+ label: modelSelectedName || '',
62
+ icon: <IconBox icon={providerIcon[modelProviderType || 'stackspot']}
63
+ appearance="square"
64
+ group={modelProviderType === 'stackspot' ? 'outline' : 'social'} />,
65
+ self_hosted: modelFromListModelsAccount?.self_hosted || false,
66
+ onClick: () => {
67
+ chat.set('selected_model_id', modelAvailableDefault?.model_id)
68
+ setVisibleMenu(false)
69
+ },
70
+ }]
71
+
72
+
73
+ return { modelName: modelSelectedName, modelProviderType, listItemsData }
74
+ }
75
+
76
+ function parseModelList(
77
+ chat: any,
78
+ setVisibleMenu: Dispatch<React.SetStateAction<boolean>>,
79
+ listModel?: LlmModelsResponse[],
80
+ modelAvailableDefaultId?: string,
81
+ ) {
82
+
83
+ const data = Array<ItemProps>()
84
+ const chatModelId = chat.get('selected_model_id')
85
+
86
+ listModel?.forEach((model) => {
87
+ data.push({
88
+ active: chatModelId ? chatModelId === model.id : modelAvailableDefaultId === model.id ||
89
+ model.resources?.some((resource) => resource.is_default && resource.name === 'agents'),
90
+ label: model?.display_name || 'LLM',
91
+ icon: <IconBox
92
+ style={{ backgroundColor: theme.color.light[300] }}
93
+ appearance="square"
94
+ icon={providerIcon[model.model_configuration.provider.provider_type]}
95
+ group={model.model_configuration.provider.provider_type === 'stackspot' ? 'outline' : 'social'}
96
+ />,
97
+ self_hosted: model.self_hosted,
98
+ onClick: () => {
99
+ chat.set('selected_model_id', model.id)
100
+ setVisibleMenu(false)
101
+ },
102
+ })
103
+ })
104
+ return data
105
+ }
106
+
107
+ export function handleFilter(items: ItemProps[], t: Record<string, string>, filter?: string) {
108
+ const filterLower = filter?.toLocaleLowerCase()
109
+ const filteredItens = items.filter((item) => filterLower ? item?.label?.toLocaleLowerCase().includes(filterLower) : item)
110
+
111
+ const { selfHosted, hosted } = filteredItens.reduce(
112
+ (acc, model) => {
113
+ if (model?.self_hosted) {
114
+ acc.selfHosted.push(model)
115
+ } else {
116
+ acc.hosted.push(model)
117
+ }
118
+ return acc
119
+ },
120
+ { selfHosted: [], hosted: [] } as { selfHosted: typeof items, hosted: typeof items },
121
+ )
122
+
123
+ const sections = [
124
+ {
125
+ label: t.hosted,
126
+ children: hosted,
127
+ },
128
+ {
129
+ label: t.selfHosted,
130
+ children: selfHosted,
131
+ },
132
+ ]
133
+
134
+ const filteredByHavingItens = sections
135
+ .filter(section => section.children.length > 0)
136
+ .map(section => ({
137
+ type: 'section',
138
+ label: section.label,
139
+ children: section.children,
140
+ }))
141
+
142
+ return filteredByHavingItens
143
+ }
@@ -14,7 +14,7 @@ export const QuickCommandSelector = ({ inputRef, isTrial }:
14
14
  const isQuickCommandEnabled = useCurrentChatState('features').quickCommands
15
15
  const spotId = useWidgetState('features')?.workspaceId
16
16
 
17
- const useFavorites = () => aiClient.allQuickCommands.useQuery({ visibility: 'favorite' }, { enabled: isQuickCommandEnabled })
17
+ const useFavorites = () => aiClient.allQuickCommands.useQuery({ visibility: 'favorite' })
18
18
  const [addFavorite, pendingAddFav] = aiClient.addFavoriteQuickCommand.useMutation()
19
19
  const [removeFavorite, pendingRemoveFav] = aiClient.removeFavoriteQuickCommand.useMutation()
20
20
 
@@ -35,6 +35,9 @@ const dictionary = {
35
35
  chatAgent: 'Agents',
36
36
  uploadSuccessStatus: 'File sent successfully',
37
37
  chatViewMenu: 'Chat options menu',
38
+ nothingFound: 'Nothing Found',
39
+ hosted: 'Hosted',
40
+ selfHosted: 'Self Hosted',
38
41
  },
39
42
  pt: {
40
43
  stack: 'Selecionar stack',
@@ -70,6 +73,9 @@ const dictionary = {
70
73
  chatAgent: 'Agentes',
71
74
  uploadSuccessStatus: 'Arquivo anexado com sucesso',
72
75
  chatViewMenu: 'Menu de opções do chat',
76
+ nothingFound: 'Nada encontrado',
77
+ hosted: 'Hospedado',
78
+ selfHosted: 'Auto-hospedado',
73
79
  },
74
80
  } satisfies Dictionary
75
81
 
@@ -24,8 +24,8 @@ import { UploadDragNDrop, useUploadDragDrop } from './UploadDragNDrop'
24
24
  * going to be used for the question and the buttons to send, cancel, set the workspace, among others. This also includes the Quick
25
25
  * Commands panel for auto completing.
26
26
  */
27
- export const MessageInput = ({ chatWindowRef, customInputMessage, customButtonBarItems }:
28
- { chatWindowRef?: React.RefObject<HTMLElement>, customInputMessage?: string, customButtonBarItems?: React.ReactNode}) => {
27
+ export const MessageInput = ({ chatWindowRef, customInputMessage }:
28
+ { chatWindowRef?: React.RefObject<HTMLElement>, customInputMessage?: string }) => {
29
29
  const t = useMessageInputDictionary()
30
30
  const [focused, setFocused] = useState(false)
31
31
  const [, setExpanded] = useState(true)
@@ -152,7 +152,7 @@ export const MessageInput = ({ chatWindowRef, customInputMessage, customButtonBa
152
152
  placeholder={
153
153
  agentLabel
154
154
  ? customInputMessage ?? interpolate(t.placeholder, agentLabel)
155
- : customInputMessage ?? t.typing
155
+ : t.typing
156
156
  }
157
157
  onChange={v => chat.set('nextMessage', v)}
158
158
  value={value}
@@ -168,7 +168,7 @@ export const MessageInput = ({ chatWindowRef, customInputMessage, customButtonBa
168
168
  <ProgressBar className="progress-bar" progress={isLoading ? undefined : (focused ? 100 : 0)} speed="fast" />
169
169
  <ContextBar />
170
170
  {chat.get('features').upload && <UploadBar />}
171
- <ButtonBar onSend={onSend} isLoading={isLoading} customButtonBarItems={customButtonBarItems} />
171
+ <ButtonBar onSend={onSend} isLoading={isLoading} />
172
172
  </MessageInputBox>
173
173
  <UploadDragNDrop isDragging={isDragging} onDrop={handleDrop} onDragLeave={handleDragLeave} />
174
174
  </UploadProvider>
@@ -1,3 +1,4 @@
1
+ import { Flex } from '@citric/core'
1
2
  import { theme } from '@stack-spot/portal-theme'
2
3
  import { styled } from 'styled-components'
3
4
 
@@ -302,3 +303,39 @@ export const MessageInputBox = styled.div`
302
303
  }
303
304
  }
304
305
  `
306
+
307
+ export const stylesModelSwitcher = {
308
+ selection: {
309
+ minHeight: '300px',
310
+ position: 'absolute',
311
+ bottom: 'calc(100% + 10px)',
312
+ right: '0',
313
+ margin: '0',
314
+ },
315
+ }
316
+
317
+ export const RowWrapperStyled = styled(Flex)`
318
+ width: 100%;
319
+ justify-content: end;
320
+ margin-right: 4px;
321
+ ul {
322
+ margin: 0;
323
+ }
324
+ .button-select-model {
325
+ border-radius: 15px !important;
326
+ }
327
+ #menuModelSwitcher {
328
+ background-color: ${theme.color.light[500]};
329
+ }
330
+
331
+ .selection-list-content {
332
+ .action :hover {
333
+ cursor: pointer;
334
+ background-color: ${theme.color.light[600]};
335
+ }
336
+ ul :hover {
337
+ background-color: transparent;
338
+ cursor: default;
339
+ }
340
+ }
341
+ `
@@ -39,7 +39,6 @@ const ResourcesPanel = () => {
39
39
  const chat = widget.chatTabs.getAll().find(c => c.id === chatId)
40
40
  return chat?.getMessages().find(m => m.id === messageId)?.getValue()
41
41
  }, [messageId])
42
-
43
42
  const [toolKits] = agentToolsClient.tools.useStatefulQuery({}, { enabled: !!message?.agent?.id })
44
43
  const [agent] = agentToolsClient.agent.useStatefulQuery({ agentId: message?.agent?.id || '' },
45
44
  { enabled: !!message?.agent?.id })
@@ -37,7 +37,7 @@ export const NodeStep = ({ data: { step, index, nextStatus, onClick } }: Props)
37
37
  {!!step.attempts[0].tools?.length && <StackedBadge
38
38
  label={t.tools}
39
39
  images={step.attempts[0].tools?.slice(0, 3).map(
40
- tool => ({ key: tool.id, name: tool.name, url: tool.image, icon: <Icon icon="Cog" /> }),
40
+ tool => ({ key: tool.id, name: tool.name ?? '', url: tool.image, icon: <Icon icon="Cog" /> }),
41
41
  )}
42
42
  />}
43
43
  </div>}
@@ -8,6 +8,7 @@ const nodesSizes = {
8
8
  step: stepNodeSize,
9
9
  planning: planningNodeSize,
10
10
  answer: answerNodeSize,
11
+ tool: stepNodeSize,
11
12
  }
12
13
 
13
14
  export function useLayoutedElements(nodes: NodeWithoutLayout[], edges: Edge[]) {
@@ -9,6 +9,6 @@ export interface NodeData {
9
9
 
10
10
  export interface NodeWithoutLayout {
11
11
  id: string,
12
- type: 'step' | 'planning' | 'answer',
12
+ type: 'step' | 'planning' | 'answer' | 'tool',
13
13
  data?: NodeData,
14
14
  }
@@ -127,7 +127,7 @@ export const StepModal = ({ message, stepId, onClose }: Props) => {
127
127
 
128
128
  const tools = step?.type === 'step' ? step.attempts[attempt]?.tools?.map(tool => (
129
129
  <div className="tool" key={tool.id}>
130
- <ToolBadge name={tool.name} duration={tool.duration} image={tool.image} description={tool.description} />
130
+ <ToolBadge name={tool.name ?? ''} duration={tool.duration} image={tool.image} description={tool.description} />
131
131
  {tool.input && <>
132
132
  <Text appearance="microtext1" color="light.700">{t.input}:</Text>
133
133
  <Code language="json" className="tool-input" showLineNumbers={false} showActionBar>{tool.input}</Code>
@@ -191,7 +191,7 @@ export const StepModal = ({ message, stepId, onClose }: Props) => {
191
191
  {!!s.attempts[0].tools?.length && <ul className="side-by-side-tools">
192
192
  {s.attempts[0].tools.map((tool) => (
193
193
  <li key={tool.id}>
194
- <ToolBadge name={tool.name} image={tool.image} />
194
+ <ToolBadge name={tool.name ?? ''} image={tool.image} />
195
195
  </li>
196
196
  ))}
197
197
  </ul>}