@stack-spot/ai-chat-widget 2.1.1 → 2.2.0-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 (82) hide show
  1. package/CHANGELOG.md +30 -2
  2. package/dist/app-metadata.json +5 -5
  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/layout.css +6 -0
  7. package/dist/state/ChatEntry.d.ts +1 -1
  8. package/dist/state/ChatEntry.d.ts.map +1 -1
  9. package/dist/state/ChatEntry.js +2 -1
  10. package/dist/state/ChatEntry.js.map +1 -1
  11. package/dist/state/ChatState.d.ts +8 -0
  12. package/dist/state/ChatState.d.ts.map +1 -1
  13. package/dist/state/ChatState.js.map +1 -1
  14. package/dist/utils/chat.d.ts.map +1 -1
  15. package/dist/utils/chat.js +1 -0
  16. package/dist/utils/chat.js.map +1 -1
  17. package/dist/utils/planning-tool.d.ts +17 -0
  18. package/dist/utils/planning-tool.d.ts.map +1 -0
  19. package/dist/utils/planning-tool.js +32 -0
  20. package/dist/utils/planning-tool.js.map +1 -0
  21. package/dist/utils/update-tool-step.d.ts +3 -0
  22. package/dist/utils/update-tool-step.d.ts.map +1 -0
  23. package/dist/utils/update-tool-step.js +23 -0
  24. package/dist/utils/update-tool-step.js.map +1 -0
  25. package/dist/views/Chat/ChatMessage.d.ts +1 -1
  26. package/dist/views/Chat/ChatMessage.d.ts.map +1 -1
  27. package/dist/views/Chat/ChatMessage.js +21 -6
  28. package/dist/views/Chat/ChatMessage.js.map +1 -1
  29. package/dist/views/Chat/StepsList.d.ts +12 -2
  30. package/dist/views/Chat/StepsList.d.ts.map +1 -1
  31. package/dist/views/Chat/StepsList.js +155 -18
  32. package/dist/views/Chat/StepsList.js.map +1 -1
  33. package/dist/views/Chat/styled.d.ts.map +1 -1
  34. package/dist/views/Chat/styled.js +17 -10
  35. package/dist/views/Chat/styled.js.map +1 -1
  36. package/dist/views/MessageInput/ButtonBar.d.ts.map +1 -1
  37. package/dist/views/MessageInput/ButtonBar.js +2 -1
  38. package/dist/views/MessageInput/ButtonBar.js.map +1 -1
  39. package/dist/views/MessageInput/ModelSwitcher.d.ts +2 -0
  40. package/dist/views/MessageInput/ModelSwitcher.d.ts.map +1 -0
  41. package/dist/views/MessageInput/ModelSwitcher.js +77 -0
  42. package/dist/views/MessageInput/ModelSwitcher.js.map +1 -0
  43. package/dist/views/MessageInput/SelectContent.js +1 -1
  44. package/dist/views/MessageInput/SelectContent.js.map +1 -1
  45. package/dist/views/MessageInput/dictionary.d.ts +1 -1
  46. package/dist/views/MessageInput/styled.d.ts +3 -0
  47. package/dist/views/MessageInput/styled.d.ts.map +1 -1
  48. package/dist/views/MessageInput/styled.js +12 -0
  49. package/dist/views/MessageInput/styled.js.map +1 -1
  50. package/dist/views/Steps/FlowChart/NodeStep.js +1 -1
  51. package/dist/views/Steps/FlowChart/NodeStep.js.map +1 -1
  52. package/dist/views/Steps/FlowChart/layout.d.ts +1 -1
  53. package/dist/views/Steps/FlowChart/layout.d.ts.map +1 -1
  54. package/dist/views/Steps/FlowChart/layout.js +1 -0
  55. package/dist/views/Steps/FlowChart/layout.js.map +1 -1
  56. package/dist/views/Steps/FlowChart/types.d.ts +1 -1
  57. package/dist/views/Steps/FlowChart/types.d.ts.map +1 -1
  58. package/dist/views/Steps/StepModal.js +2 -2
  59. package/dist/views/Steps/StepModal.js.map +1 -1
  60. package/dist/views/Steps/dictionary.d.ts +1 -1
  61. package/dist/views/Steps/utils.d.ts +1 -1
  62. package/dist/views/Steps/utils.d.ts.map +1 -1
  63. package/package.json +3 -3
  64. package/src/app-metadata.json +5 -5
  65. package/src/chat-interceptors/send-message.ts +137 -2
  66. package/src/layout.css +6 -0
  67. package/src/state/ChatEntry.ts +2 -1
  68. package/src/state/ChatState.ts +8 -0
  69. package/src/utils/chat.ts +1 -0
  70. package/src/utils/planning-tool.ts +41 -0
  71. package/src/utils/update-tool-step.tsx +27 -0
  72. package/src/views/Chat/ChatMessage.tsx +25 -5
  73. package/src/views/Chat/StepsList.tsx +337 -44
  74. package/src/views/Chat/styled.ts +17 -10
  75. package/src/views/MessageInput/ButtonBar.tsx +2 -0
  76. package/src/views/MessageInput/ModelSwitcher.tsx +127 -0
  77. package/src/views/MessageInput/SelectContent.tsx +1 -1
  78. package/src/views/MessageInput/styled.ts +12 -0
  79. package/src/views/Steps/FlowChart/NodeStep.tsx +1 -1
  80. package/src/views/Steps/FlowChart/layout.ts +1 -0
  81. package/src/views/Steps/FlowChart/types.ts +1 -1
  82. package/src/views/Steps/StepModal.tsx +2 -2
@@ -0,0 +1,127 @@
1
+ import { Button, Icon } from '@stack-spot/citric-react'
2
+ import { SelectionList } from '@stack-spot/portal-components/SelectionList'
3
+ import { agentToolsClient, genAiInferenceClient } from '@stack-spot/portal-network'
4
+ import { AgentLlmModelDto, AgentModel } from '@stack-spot/portal-network/api/agent-tools'
5
+ import { LlmModelsResponse, PaginatedResponseLlmModelsResponse } from '@stack-spot/portal-network/api/genAiInference'
6
+ import { Dispatch, ReactElement, useState } from 'react'
7
+ import { CSSProperties } from 'styled-components'
8
+ import { useCurrentChat, useCurrentChatState } from '../../context/hooks'
9
+ import { useMessageInputDictionary } from './dictionary'
10
+ import { RowWrapperStyled } from './styled'
11
+
12
+ const styles = {
13
+ selection: {
14
+ position: 'absolute',
15
+ bottom: 'calc(100% + 10px)',
16
+ right: '0',
17
+ margin: '0',
18
+ 'ul': {
19
+ margin: '0px',
20
+ },
21
+ },
22
+ }
23
+
24
+ export const ModelSwitcher = () => {
25
+ const t = useMessageInputDictionary()
26
+ const agent = useCurrentChatState('agent')
27
+ const chat = useCurrentChat()
28
+ const [visibleMenu, setVisibleMenu] = useState(false)
29
+ const [agentData] = agentToolsClient.agent.useStatefulQuery({ agentId: agent?.id || '' })
30
+ const [selectedLLMName, setSelectedLLMName] = useState<string | undefined>()
31
+ const [models] = genAiInferenceClient.listModels.useStatefulQuery({ pageSize: 999 })
32
+
33
+ const { modelName, listItems } = getModelData(chat, setSelectedLLMName, setVisibleMenu, selectedLLMName, agentData, models)
34
+
35
+ return (
36
+ <RowWrapperStyled>
37
+ <Button
38
+ className="button-select-model"
39
+ colorScheme="light"
40
+ size="sm"
41
+ aria-label={t.agent}
42
+ title={t.agent}
43
+ onClick={() => setVisibleMenu(state => !state)}
44
+ >
45
+ {modelName}
46
+ <Icon icon="ChevronDown" group="fill" size="sm" />
47
+ </Button>
48
+ <SelectionList
49
+ id="menuModelSwitcher"
50
+ visible={visibleMenu}
51
+ onHide={() => setVisibleMenu(false)}
52
+ items={listItems || []}
53
+ style={styles.selection as CSSProperties}
54
+ />
55
+ </RowWrapperStyled>
56
+ )
57
+ }
58
+
59
+
60
+ function getModelData(
61
+ chat: any,
62
+ setSelectedModelName: Dispatch<React.SetStateAction<string | undefined>>,
63
+ setVisibleMenu: Dispatch<React.SetStateAction<boolean>>,
64
+ selectedModelName?: string,
65
+ agent?: AgentModel,
66
+ models?: PaginatedResponseLlmModelsResponse) {
67
+
68
+ const modelListData = parseModelList(
69
+ setSelectedModelName, setVisibleMenu, chat,
70
+ agent?.visibility_level !== 'built_in' && !!agent?.model_id ? agent?.available_llm_models : models?.items,
71
+ )
72
+
73
+ if (agent?.visibility_level === 'built_in' || !!agent?.model_id) {
74
+ const modelDefaultFromList = modelListData.find((model) => model.active)
75
+ return { modelName: modelDefaultFromList?.label, listItems: modelListData }
76
+ }
77
+
78
+ const listItems =
79
+ modelListData && modelListData?.length > 0 ? modelListData :
80
+ [{
81
+ active: true,
82
+ label: agent?.model_name || agent?.available_llm_models?.find((model) => model.is_default)?.model_name || '',
83
+ icon: <Icon icon="StackSpot" />,
84
+ }]
85
+
86
+ const modelSelectedName = selectedModelName || agent?.model_name ||
87
+ agent?.available_llm_models?.find((model) => model.is_default)?.model_name
88
+
89
+ return { modelName: modelSelectedName, listItems }
90
+ }
91
+
92
+ function parseModelList(
93
+ setSelectedModelName: Dispatch<React.SetStateAction<string | undefined>>,
94
+ setVisibleMenu: Dispatch<React.SetStateAction<boolean>>,
95
+ chat: any,
96
+ listModel?: Array<AgentLlmModelDto | LlmModelsResponse>,
97
+ ) {
98
+ const data = Array<{active?: boolean, label: string, icon: ReactElement, onClick: VoidFunction }>()
99
+
100
+ listModel?.forEach((model) => {
101
+ if ('model_id' in model) {
102
+ data.push({
103
+ active: chat.get('selected_model_id') ? chat.get('selected_model_id') === model.model_id : model.is_default,
104
+ label: model?.model_name || 'LLM',
105
+ icon: <Icon icon="Bookmark"/>,
106
+ onClick: () => {
107
+ setSelectedModelName(model.model_name)
108
+ chat.set('selected_model_id', model.model_id)
109
+ setVisibleMenu(false)
110
+ },
111
+ })
112
+ }
113
+ else {
114
+ data.push({
115
+ active: chat.get('selected_model_id') ? chat.get('selected_model_id') === model.id : model.resources[0]?.is_default,
116
+ label: model?.display_name || 'LLM',
117
+ icon: <Icon icon="Bookmark"/>,
118
+ onClick: () => {
119
+ setSelectedModelName(model.display_name)
120
+ chat.set('selected_model_id', model.id)
121
+ setVisibleMenu(false)
122
+ },
123
+ })
124
+ }
125
+ })
126
+ return data
127
+ }
@@ -83,7 +83,7 @@ export const SelectContent = () => {
83
83
  if (!hasFeatureButtons) return null
84
84
 
85
85
  return itemConfigs.length > 1 ? (
86
- <MenuOverlay items={listItems} position="top" bgLevel={500} spaced roundedItems>
86
+ <MenuOverlay items={listItems} position="right" bgLevel={500} roundedItems menuClass="menu-citric-hr" alignment="end">
87
87
  <IconButton icon="Plus" />
88
88
  </MenuOverlay>
89
89
  ) : (
@@ -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,14 @@ export const MessageInputBox = styled.div`
302
303
  }
303
304
  }
304
305
  `
306
+ export const RowWrapperStyled = styled(Flex)`
307
+ width: 100%;
308
+ justify-content: end;
309
+ margin-right: 4px;
310
+ ul {
311
+ margin: 0;
312
+ }
313
+ .button-select-model {
314
+ border-radius: 15px !important;
315
+ }
316
+ `
@@ -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>}