@stack-spot/ai-chat-widget 2.2.1 → 2.2.2-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 (86) hide show
  1. package/CHANGELOG.md +34 -6
  2. package/dist/app-metadata.json +6 -6
  3. package/dist/chat-interceptors/send-message.d.ts.map +1 -1
  4. package/dist/chat-interceptors/send-message.js +125 -1
  5. package/dist/chat-interceptors/send-message.js.map +1 -1
  6. package/dist/state/ChatEntry.d.ts +1 -1
  7. package/dist/state/ChatEntry.d.ts.map +1 -1
  8. package/dist/state/ChatEntry.js +2 -1
  9. package/dist/state/ChatEntry.js.map +1 -1
  10. package/dist/state/ChatState.d.ts +8 -0
  11. package/dist/state/ChatState.d.ts.map +1 -1
  12. package/dist/state/ChatState.js.map +1 -1
  13. package/dist/utils/chat.d.ts.map +1 -1
  14. package/dist/utils/chat.js +1 -0
  15. package/dist/utils/chat.js.map +1 -1
  16. package/dist/utils/planning-tool.d.ts +17 -0
  17. package/dist/utils/planning-tool.d.ts.map +1 -0
  18. package/dist/utils/planning-tool.js +32 -0
  19. package/dist/utils/planning-tool.js.map +1 -0
  20. package/dist/utils/update-tool-step.d.ts +3 -0
  21. package/dist/utils/update-tool-step.d.ts.map +1 -0
  22. package/dist/utils/update-tool-step.js +23 -0
  23. package/dist/utils/update-tool-step.js.map +1 -0
  24. package/dist/views/Chat/ChatMessage.d.ts +1 -1
  25. package/dist/views/Chat/ChatMessage.d.ts.map +1 -1
  26. package/dist/views/Chat/ChatMessage.js +21 -6
  27. package/dist/views/Chat/ChatMessage.js.map +1 -1
  28. package/dist/views/Chat/StepsList.d.ts +12 -2
  29. package/dist/views/Chat/StepsList.d.ts.map +1 -1
  30. package/dist/views/Chat/StepsList.js +155 -21
  31. package/dist/views/Chat/StepsList.js.map +1 -1
  32. package/dist/views/Chat/styled.d.ts.map +1 -1
  33. package/dist/views/Chat/styled.js +17 -10
  34. package/dist/views/Chat/styled.js.map +1 -1
  35. package/dist/views/MessageInput/ButtonBar.d.ts.map +1 -1
  36. package/dist/views/MessageInput/ButtonBar.js +2 -1
  37. package/dist/views/MessageInput/ButtonBar.js.map +1 -1
  38. package/dist/views/MessageInput/ModelSwitcher/index.d.ts +2 -0
  39. package/dist/views/MessageInput/ModelSwitcher/index.d.ts.map +1 -0
  40. package/dist/views/MessageInput/ModelSwitcher/index.js +25 -0
  41. package/dist/views/MessageInput/ModelSwitcher/index.js.map +1 -0
  42. package/dist/views/MessageInput/ModelSwitcher/utils.d.ts +29 -0
  43. package/dist/views/MessageInput/ModelSwitcher/utils.d.ts.map +1 -0
  44. package/dist/views/MessageInput/ModelSwitcher/utils.js +100 -0
  45. package/dist/views/MessageInput/ModelSwitcher/utils.js.map +1 -0
  46. package/dist/views/MessageInput/dictionary.d.ts +1 -1
  47. package/dist/views/MessageInput/dictionary.d.ts.map +1 -1
  48. package/dist/views/MessageInput/dictionary.js +2 -0
  49. package/dist/views/MessageInput/dictionary.js.map +1 -1
  50. package/dist/views/MessageInput/styled.d.ts +12 -0
  51. package/dist/views/MessageInput/styled.d.ts.map +1 -1
  52. package/dist/views/MessageInput/styled.js +35 -0
  53. package/dist/views/MessageInput/styled.js.map +1 -1
  54. package/dist/views/Steps/FlowChart/NodeStep.js +1 -1
  55. package/dist/views/Steps/FlowChart/NodeStep.js.map +1 -1
  56. package/dist/views/Steps/FlowChart/layout.d.ts +1 -1
  57. package/dist/views/Steps/FlowChart/layout.d.ts.map +1 -1
  58. package/dist/views/Steps/FlowChart/layout.js +1 -0
  59. package/dist/views/Steps/FlowChart/layout.js.map +1 -1
  60. package/dist/views/Steps/FlowChart/types.d.ts +1 -1
  61. package/dist/views/Steps/FlowChart/types.d.ts.map +1 -1
  62. package/dist/views/Steps/StepModal.js +2 -2
  63. package/dist/views/Steps/StepModal.js.map +1 -1
  64. package/dist/views/Steps/dictionary.d.ts +1 -1
  65. package/dist/views/Steps/utils.d.ts +1 -1
  66. package/dist/views/Steps/utils.d.ts.map +1 -1
  67. package/package.json +4 -4
  68. package/src/app-metadata.json +6 -6
  69. package/src/chat-interceptors/send-message.ts +137 -2
  70. package/src/state/ChatEntry.ts +2 -1
  71. package/src/state/ChatState.ts +8 -0
  72. package/src/utils/chat.ts +1 -0
  73. package/src/utils/planning-tool.ts +41 -0
  74. package/src/utils/update-tool-step.tsx +27 -0
  75. package/src/views/Chat/ChatMessage.tsx +25 -5
  76. package/src/views/Chat/StepsList.tsx +337 -48
  77. package/src/views/Chat/styled.ts +17 -10
  78. package/src/views/MessageInput/ButtonBar.tsx +2 -0
  79. package/src/views/MessageInput/ModelSwitcher/index.tsx +65 -0
  80. package/src/views/MessageInput/ModelSwitcher/utils.tsx +149 -0
  81. package/src/views/MessageInput/dictionary.ts +2 -0
  82. package/src/views/MessageInput/styled.ts +37 -0
  83. package/src/views/Steps/FlowChart/NodeStep.tsx +1 -1
  84. package/src/views/Steps/FlowChart/layout.ts +1 -0
  85. package/src/views/Steps/FlowChart/types.ts +1 -1
  86. package/src/views/Steps/StepModal.tsx +2 -2
@@ -0,0 +1,149 @@
1
+ import { CitricIconOutline, CitricIconSocial } from '@stack-spot/citric-icons'
2
+ import { Icon, IconBox } from '@stack-spot/citric-react'
3
+ import { AgentLlmModelDto, 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
+
8
+ export interface ItemProps {
9
+ active?: boolean,
10
+ label?: string,
11
+ icon?: ReactElement,
12
+ self_hosted?: boolean,
13
+ onClick?: VoidFunction,
14
+ }
15
+
16
+ export const providerIcon: Record<string, CitricIconSocial | CitricIconOutline> = {
17
+ openai: 'OpenAI',
18
+ bedrock: 'AWSBedrock',
19
+ azure: 'Azure',
20
+ stackspot: 'StackSpot',
21
+ gemini: 'Gemini',
22
+ deepseek: 'DeepSeek',
23
+ anthropic: 'Anthropic',
24
+ }
25
+
26
+ export function getModelData(
27
+ chat: any,
28
+ setVisibleMenu: Dispatch<React.SetStateAction<boolean>>,
29
+ agent?: AgentModel,
30
+ models?: PaginatedResponseLlmModelsResponse) {
31
+
32
+ const listModelsToShow = agent?.visibility_level !== 'built_in' && !!agent?.model_id ? agent?.available_llm_models : models?.items
33
+
34
+ const modelListData = parseModelList(chat, setVisibleMenu, listModelsToShow, models?.items)
35
+
36
+ const modelAvailableDefault = agent?.available_llm_models?.find((model) => model.is_default)
37
+ const modelFromListAccount = models?.items.find((modelAccount) => modelAccount.active)
38
+ const modelProviderType = modelFromListAccount?.model_configuration.provider.provider_type
39
+
40
+ if (agent?.visibility_level === 'built_in' || !agent?.model_id) {
41
+ const modelDefaultFromList = modelListData.find((model) => model?.active)
42
+
43
+ return { modelName: modelDefaultFromList?.label, modelProviderType, listItemsData: modelListData }
44
+ }
45
+
46
+ const listItemsData =
47
+ modelListData && modelListData?.length > 0 ? modelListData :
48
+ [{
49
+ active: true,
50
+ label: modelAvailableDefault?.model_name || agent?.model_name || '',
51
+ icon: <IconBox icon={providerIcon[modelProviderType || 'stackspot']}
52
+ appearance="square"
53
+ group={modelProviderType === 'stackspot' ? 'outline' : 'social'} />,
54
+ self_hosted: modelFromListAccount?.self_hosted || false,
55
+ onClick: () => {
56
+ chat.set('selected_model_id', modelAvailableDefault?.model_id)
57
+ setVisibleMenu(false)
58
+ },
59
+ }]
60
+
61
+ const modelSelectedName = chat.get('selected_model_id') || agent?.model_name || modelAvailableDefault?.model_name
62
+
63
+ return { modelName: modelSelectedName, modelProviderType, listItemsData }
64
+ }
65
+
66
+ function parseModelList(
67
+ chat: any,
68
+ setVisibleMenu: Dispatch<React.SetStateAction<boolean>>,
69
+ listModelToShow?: Array<AgentLlmModelDto | LlmModelsResponse>,
70
+ listModelAccount?: LlmModelsResponse[],
71
+ ) {
72
+
73
+ const data = Array<ItemProps>()
74
+
75
+ const chatModelId = chat.get('selected_model_id')
76
+
77
+ listModelToShow?.forEach((model) => {
78
+ if ('model_id' in model) {
79
+ const modelFromListModels = listModelAccount?.find((modelAccount) => model.model_id === modelAccount.id)
80
+ data.push({
81
+ active: chatModelId === model.model_id || model.is_default,
82
+ label: model?.model_name || 'LLM',
83
+ icon: <Icon icon="Bookmark"/>,
84
+ self_hosted: modelFromListModels?.self_hosted || false,
85
+ onClick: () => {
86
+ chat.set('selected_model_id', model.model_id)
87
+ setVisibleMenu(false)
88
+ },
89
+ })
90
+ }
91
+ else {
92
+ data.push({
93
+ active: chatModelId === model.id || model.resources[0]?.is_default,
94
+ label: model?.display_name || 'LLM',
95
+ icon: <IconBox
96
+ style={{ backgroundColor: theme.color.light[300] }}
97
+ appearance="square"
98
+ icon={providerIcon[model.model_configuration.provider.provider_type]}
99
+ group={model.model_configuration.provider.provider_type === 'stackspot' ? 'outline' : 'social'}
100
+ />,
101
+ self_hosted: model.self_hosted,
102
+ onClick: () => {
103
+ chat.set('selected_model_id', model.id)
104
+ setVisibleMenu(false)
105
+ },
106
+ })
107
+ }
108
+ })
109
+ return data
110
+ }
111
+
112
+ export function handleFilter(items: ItemProps[], filter?: string) {
113
+
114
+ const filterLower = filter?.toLocaleLowerCase()
115
+ const filteredItens = items.filter((item) => filterLower ? item?.label?.toLocaleLowerCase().includes(filterLower) : item)
116
+
117
+ const { selfHosted, hosted } = filteredItens.reduce(
118
+ (acc, model) => {
119
+ if (model?.self_hosted) {
120
+ acc.selfHosted.push(model)
121
+ } else {
122
+ acc.hosted.push(model)
123
+ }
124
+ return acc
125
+ },
126
+ { selfHosted: [], hosted: [] } as { selfHosted: typeof items, hosted: typeof items },
127
+ )
128
+
129
+ const sections = [
130
+ {
131
+ label: 'Hosted',
132
+ children: hosted,
133
+ },
134
+ {
135
+ label: 'Self Hosted',
136
+ children: selfHosted,
137
+ },
138
+ ]
139
+
140
+ const filteredByHavingItens = sections
141
+ .filter(section => section.children.length > 0)
142
+ .map(section => ({
143
+ type: 'section',
144
+ label: section.label,
145
+ children: section.children,
146
+ }))
147
+
148
+ return filteredByHavingItens
149
+ }
@@ -35,6 +35,7 @@ const dictionary = {
35
35
  chatAgent: 'Agents',
36
36
  uploadSuccessStatus: 'File sent successfully',
37
37
  chatViewMenu: 'Chat options menu',
38
+ nothingFound: 'Nothing Found',
38
39
  },
39
40
  pt: {
40
41
  stack: 'Selecionar stack',
@@ -70,6 +71,7 @@ const dictionary = {
70
71
  chatAgent: 'Agentes',
71
72
  uploadSuccessStatus: 'Arquivo anexado com sucesso',
72
73
  chatViewMenu: 'Menu de opções do chat',
74
+ nothingFound: 'Nada encontrado',
73
75
  },
74
76
  } satisfies Dictionary
75
77
 
@@ -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
+ `
@@ -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>}