@stack-spot/ai-chat-widget 2.3.1 → 2.4.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 (53) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/dist/app-metadata.json +6 -6
  3. package/dist/chat-interceptors/quick-commands.d.ts.map +1 -1
  4. package/dist/chat-interceptors/quick-commands.js +8 -3
  5. package/dist/chat-interceptors/quick-commands.js.map +1 -1
  6. package/dist/chat-interceptors/send-message.d.ts.map +1 -1
  7. package/dist/chat-interceptors/send-message.js +12 -2
  8. package/dist/chat-interceptors/send-message.js.map +1 -1
  9. package/dist/state/ChatState.d.ts +4 -0
  10. package/dist/state/ChatState.d.ts.map +1 -1
  11. package/dist/state/ChatState.js.map +1 -1
  12. package/dist/utils/chat.d.ts.map +1 -1
  13. package/dist/utils/chat.js +1 -0
  14. package/dist/utils/chat.js.map +1 -1
  15. package/dist/utils/knowledge-source.d.ts +2 -2
  16. package/dist/views/Chat/StepsList.d.ts +1 -2
  17. package/dist/views/Chat/StepsList.d.ts.map +1 -1
  18. package/dist/views/Chat/StepsList.js +6 -6
  19. package/dist/views/Chat/StepsList.js.map +1 -1
  20. package/dist/views/MessageInput/ButtonBar.d.ts.map +1 -1
  21. package/dist/views/MessageInput/ButtonBar.js +2 -1
  22. package/dist/views/MessageInput/ButtonBar.js.map +1 -1
  23. package/dist/views/MessageInput/ModelSwitcher/index.d.ts +2 -0
  24. package/dist/views/MessageInput/ModelSwitcher/index.d.ts.map +1 -0
  25. package/dist/views/MessageInput/ModelSwitcher/index.js +25 -0
  26. package/dist/views/MessageInput/ModelSwitcher/index.js.map +1 -0
  27. package/dist/views/MessageInput/ModelSwitcher/utils.d.ts +30 -0
  28. package/dist/views/MessageInput/ModelSwitcher/utils.d.ts.map +1 -0
  29. package/dist/views/MessageInput/ModelSwitcher/utils.js +91 -0
  30. package/dist/views/MessageInput/ModelSwitcher/utils.js.map +1 -0
  31. package/dist/views/MessageInput/dictionary.d.ts +1 -1
  32. package/dist/views/MessageInput/dictionary.d.ts.map +1 -1
  33. package/dist/views/MessageInput/dictionary.js +6 -0
  34. package/dist/views/MessageInput/dictionary.js.map +1 -1
  35. package/dist/views/MessageInput/styled.d.ts +12 -0
  36. package/dist/views/MessageInput/styled.d.ts.map +1 -1
  37. package/dist/views/MessageInput/styled.js +35 -0
  38. package/dist/views/MessageInput/styled.js.map +1 -1
  39. package/dist/views/Resources.js.map +1 -1
  40. package/package.json +4 -4
  41. package/src/app-metadata.json +6 -6
  42. package/src/chat-interceptors/quick-commands.ts +10 -3
  43. package/src/chat-interceptors/send-message.ts +13 -3
  44. package/src/state/ChatState.ts +4 -0
  45. package/src/utils/chat.ts +1 -0
  46. package/src/utils/knowledge-source.ts +2 -2
  47. package/src/views/Chat/StepsList.tsx +7 -7
  48. package/src/views/MessageInput/ButtonBar.tsx +2 -0
  49. package/src/views/MessageInput/ModelSwitcher/index.tsx +68 -0
  50. package/src/views/MessageInput/ModelSwitcher/utils.tsx +143 -0
  51. package/src/views/MessageInput/dictionary.ts +6 -0
  52. package/src/views/MessageInput/styled.ts +37 -0
  53. package/src/views/Resources.tsx +0 -1
@@ -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 getListModelsData(
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 modelDefaultActive = modelListData.find((model) => model?.active)
49
+
50
+ return { modelName: modelDefaultActive?.label, modelProviderType: modelDefaultProviderType, listItemsData: modelListData }
51
+ }
52
+
53
+ const modelAccount = models?.items.find((modelAccount) => modelAccount.id === (chatSelectedModelId || agent.model_id))
54
+ const modelProviderType = modelAccount?.model_configuration.provider.provider_type
55
+ const modelSelectedName = modelAccount?.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: modelAccount?.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: ChatState,
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 handleFilterTypeModel(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
+ }
@@ -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
 
@@ -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 })