@stack-spot/ai-chat-widget 0.3.0 → 0.5.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 (61) hide show
  1. package/dist/StackspotAIWidget.js +1 -1
  2. package/dist/StackspotAIWidget.js.map +1 -1
  3. package/dist/chat-interceptors/quick-commands.js +2 -2
  4. package/dist/chat-interceptors/quick-commands.js.map +1 -1
  5. package/dist/chat-interceptors/send-message.d.ts.map +1 -1
  6. package/dist/chat-interceptors/send-message.js +4 -3
  7. package/dist/chat-interceptors/send-message.js.map +1 -1
  8. package/dist/components/Tooltip/TooltipAPI.d.ts +2 -0
  9. package/dist/components/Tooltip/TooltipAPI.d.ts.map +1 -1
  10. package/dist/components/Tooltip/TooltipAPI.js +24 -7
  11. package/dist/components/Tooltip/TooltipAPI.js.map +1 -1
  12. package/dist/components/Tooltip/context.js +1 -1
  13. package/dist/components/Tooltip/context.js.map +1 -1
  14. package/dist/layout.css +6 -0
  15. package/dist/state/ChatEntry.d.ts +3 -2
  16. package/dist/state/ChatEntry.d.ts.map +1 -1
  17. package/dist/state/ChatEntry.js +2 -2
  18. package/dist/state/ChatEntry.js.map +1 -1
  19. package/dist/state/ChatState.d.ts +1 -7
  20. package/dist/state/ChatState.d.ts.map +1 -1
  21. package/dist/state/ChatState.js.map +1 -1
  22. package/dist/state/types.d.ts +8 -0
  23. package/dist/state/types.d.ts.map +1 -0
  24. package/dist/state/types.js +2 -0
  25. package/dist/state/types.js.map +1 -0
  26. package/dist/views/Agents.d.ts.map +1 -1
  27. package/dist/views/Agents.js +19 -6
  28. package/dist/views/Agents.js.map +1 -1
  29. package/dist/views/Chat/AgentInfo.d.ts +3 -2
  30. package/dist/views/Chat/AgentInfo.d.ts.map +1 -1
  31. package/dist/views/Chat/AgentInfo.js +3 -3
  32. package/dist/views/Chat/AgentInfo.js.map +1 -1
  33. package/dist/views/Chat/ChatMessage.js +2 -2
  34. package/dist/views/Chat/ChatMessage.js.map +1 -1
  35. package/dist/views/Chat/styled.d.ts.map +1 -1
  36. package/dist/views/Chat/styled.js +8 -1
  37. package/dist/views/Chat/styled.js.map +1 -1
  38. package/dist/views/ChatHistory/HistoryItem.d.ts.map +1 -1
  39. package/dist/views/ChatHistory/HistoryItem.js +15 -8
  40. package/dist/views/ChatHistory/HistoryItem.js.map +1 -1
  41. package/dist/views/ChatHistory/utils.d.ts +1 -0
  42. package/dist/views/ChatHistory/utils.d.ts.map +1 -1
  43. package/dist/views/ChatHistory/utils.js +12 -1
  44. package/dist/views/ChatHistory/utils.js.map +1 -1
  45. package/dist/views/MessageInput/dictionary.d.ts +1 -1
  46. package/package.json +1 -1
  47. package/src/StackspotAIWidget.tsx +1 -1
  48. package/src/chat-interceptors/quick-commands.ts +2 -2
  49. package/src/chat-interceptors/send-message.ts +4 -3
  50. package/src/components/Tooltip/TooltipAPI.ts +25 -7
  51. package/src/components/Tooltip/context.tsx +1 -1
  52. package/src/layout.css +6 -0
  53. package/src/state/ChatEntry.ts +5 -4
  54. package/src/state/ChatState.ts +1 -9
  55. package/src/state/types.ts +8 -0
  56. package/src/views/Agents.tsx +20 -7
  57. package/src/views/Chat/AgentInfo.tsx +8 -8
  58. package/src/views/Chat/ChatMessage.tsx +3 -3
  59. package/src/views/Chat/styled.ts +8 -1
  60. package/src/views/ChatHistory/HistoryItem.tsx +20 -8
  61. package/src/views/ChatHistory/utils.ts +12 -1
@@ -4,6 +4,7 @@ import { Check, Download, EllipsisHorizontal, Pencil, Trash } from '@citric/icon
4
4
  import { IconButton, LoadingCircular } from '@citric/ui';
5
5
  import { aiClient } from '@stack-spot/portal-network';
6
6
  import { theme } from '@stack-spot/portal-theme';
7
+ import { last } from 'lodash';
7
8
  import { useCallback, useEffect, useRef, useState } from 'react';
8
9
  import { OverlayMenu } from '../../components/OverlayMenu.js';
9
10
  import { useWidget } from '../../context/hooks.js';
@@ -13,7 +14,7 @@ import { download } from '../../utils/download.js';
13
14
  import { genericSourcesToKnowledgeSources } from '../../utils/knowledge-source.js';
14
15
  import { useHistoryDictionary } from './dictionary.js';
15
16
  import { HistoryItemBox } from './styled.js';
16
- import { findStack, findWorkspace } from './utils.js';
17
+ import { findStack, findWorkspace, getAllAgents } from './utils.js';
17
18
  export const HistoryItem = ({ item, interceptors }) => {
18
19
  const t = useHistoryDictionary();
19
20
  const [isLoading, setLoading] = useState(false);
@@ -31,17 +32,19 @@ export const HistoryItem = ({ item, interceptors }) => {
31
32
  setRenaming(true);
32
33
  }, []);
33
34
  async function onSubmitRename() {
35
+ const prev = title;
34
36
  setRenaming(false);
37
+ setTitle(renamed);
35
38
  if (!renamed || renamed === item.title)
36
39
  return;
37
40
  try {
38
41
  await aiClient.renameChat.mutate({ conversationId: item.id, conversationUpdateTitleRequest: { title: renamed } });
39
- setTitle(renamed);
40
42
  aiClient.chats.invalidate();
41
43
  }
42
44
  catch (error) {
43
45
  // eslint-disable-next-line no-console
44
46
  console.error(error);
47
+ setTitle(prev);
45
48
  setRenaming(true);
46
49
  }
47
50
  }
@@ -76,18 +79,22 @@ export const HistoryItem = ({ item, interceptors }) => {
76
79
  setLoading(true);
77
80
  try {
78
81
  const chat = await aiClient.chat.query({ conversationId: item.id });
79
- const [stack, workspace] = await Promise.all([findStack(chat.ai_stack_id), findWorkspace(chat.workspace_id)]);
82
+ const [stack, workspace, agents] = await Promise.all([
83
+ findStack(chat.ai_stack_id),
84
+ findWorkspace(chat.workspace_id),
85
+ getAllAgents(),
86
+ ]);
80
87
  widget.chatTabs.add(new ChatState({
81
88
  id: chat.id,
82
- initial: { label: chat.title, stack, workspace },
89
+ initial: { label: chat.title, stack, workspace, agent: agents.find(a => a.id === last(chat.history)?.custom_agent?.id) },
83
90
  interceptors,
84
91
  entries: chat.history?.map(item => new ChatEntry({
85
- agent: item.agent === 'USER' ? 'user' : 'bot',
92
+ agentType: item.agent === 'USER' ? 'user' : 'bot',
86
93
  content: item.content,
87
94
  type: item.agent === 'USER' ? 'text' : 'md',
88
- agentId: item.custom_agent?.id,
95
+ agent: agents.find(a => a.id === item.custom_agent?.id),
89
96
  messageId: item.message_id,
90
- knowledgeSources: genericSourcesToKnowledgeSources(item.sources),
97
+ knowledgeSources: item.agent === 'USER' ? undefined : genericSourcesToKnowledgeSources(item.sources),
91
98
  updated: item.updated,
92
99
  })),
93
100
  }));
@@ -104,6 +111,6 @@ export const HistoryItem = ({ item, interceptors }) => {
104
111
  { label: t.download, onClick: onDownload, icon: _jsx(Download, {}) },
105
112
  { label: t.delete, onClick: onDelete, icon: _jsx(Trash, {}), color: theme.color.danger[500] },
106
113
  ];
107
- return isDeleted ? null : (_jsx(HistoryItemBox, { className: isLoading ? 'loading' : '', children: isRenaming ? (_jsxs(_Fragment, { children: [_jsx(Input, { ref: renameInput, value: renamed, onChange: e => setRenamed(e.target.value) }), _jsx(IconButton, { onClick: onSubmitRename, children: _jsx(Check, {}) })] })) : (_jsxs(_Fragment, { children: [_jsx("button", { className: "label", onClick: onSelect, disabled: isLoading, children: title }), isLoading ? _jsx(LoadingCircular, { size: "xs" }) : _jsx(OverlayMenu, { actions: actions, position: "left", children: _jsx(IconBox, { children: _jsx(EllipsisHorizontal, {}) }) })] })) }));
114
+ return isDeleted ? null : (_jsx(HistoryItemBox, { className: isLoading ? 'loading' : '', children: isRenaming ? (_jsxs(_Fragment, { children: [_jsx(Input, { ref: renameInput, value: renamed, onChange: e => setRenamed(e.target.value), onKeyDown: e => e.key === 'Enter' && onSubmitRename() }), _jsx(IconButton, { onClick: onSubmitRename, children: _jsx(Check, {}) })] })) : (_jsxs(_Fragment, { children: [_jsx("button", { className: "label", onClick: onSelect, disabled: isLoading, children: title }), isLoading ? _jsx(LoadingCircular, { size: "xs" }) : _jsx(OverlayMenu, { actions: actions, position: "left", children: _jsx(IconBox, { children: _jsx(EllipsisHorizontal, {}) }) })] })) }));
108
115
  };
109
116
  //# sourceMappingURL=HistoryItem.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"HistoryItem.js","sourceRoot":"","sources":["../../../src/views/ChatHistory/HistoryItem.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"HistoryItem.js","sourceRoot":"","sources":["../../../src/views/ChatHistory/HistoryItem.tsx"],"names":[],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  import { ChatProperties } from '../../state/ChatState.js';
2
2
  export declare function findStack(id: string | null): Promise<ChatProperties['stack'] | undefined>;
3
3
  export declare function findWorkspace(id: string | null): Promise<ChatProperties['workspace'] | undefined>;
4
+ export declare function getAllAgents(): Promise<Required<ChatProperties>['agent'][]>;
4
5
  //# sourceMappingURL=utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/views/ChatHistory/utils.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAEtD,wBAAsB,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,cAAc,CAAC,OAAO,CAAC,GAAG,SAAS,CAAC,CAU/F;AAED,wBAAsB,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,cAAc,CAAC,WAAW,CAAC,GAAG,SAAS,CAAC,CAUvG"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/views/ChatHistory/utils.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAEtD,wBAAsB,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,cAAc,CAAC,OAAO,CAAC,GAAG,SAAS,CAAC,CAU/F;AAED,wBAAsB,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,cAAc,CAAC,WAAW,CAAC,GAAG,SAAS,CAAC,CAUvG;AAED,wBAAsB,YAAY,IAAI,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CASjF"}
@@ -1,4 +1,4 @@
1
- import { aiClient, workspaceClient } from '@stack-spot/portal-network';
1
+ import { agentClient, aiClient, workspaceClient } from '@stack-spot/portal-network';
2
2
  export async function findStack(id) {
3
3
  if (!id)
4
4
  return;
@@ -25,4 +25,15 @@ export async function findWorkspace(id) {
25
25
  return { id, label: id };
26
26
  }
27
27
  }
28
+ export async function getAllAgents() {
29
+ try {
30
+ const [agents, publicAgents] = await Promise.all([agentClient.agents.query({}), agentClient.publicAgents.query({})]);
31
+ return [...agents, ...publicAgents].map(a => ({ id: a.id, label: a.name, image: a.avatar }));
32
+ }
33
+ catch (error) {
34
+ // eslint-disable-next-line no-console
35
+ console.error(error);
36
+ return [];
37
+ }
38
+ }
28
39
  //# sourceMappingURL=utils.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../src/views/ChatHistory/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAA;AAGtE,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,EAAiB;IAC/C,IAAI,CAAC,EAAE;QAAE,OAAM;IACf,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;QAChD,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,IAAI,EAAE,EAAE,CAAA;IACjE,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,sCAAsC;QACtC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;QACpB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,CAAA;IAC1B,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,EAAiB;IACnD,IAAI,CAAC,EAAE;QAAE,OAAM;IACf,IAAI,CAAC;QACH,MAAM,EAAE,GAAG,MAAM,eAAe,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC,CAAA;QACrE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,CAAC,IAAI,EAAE,CAAA;IAC/B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,sCAAsC;QACtC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;QACpB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,CAAA;IAC1B,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../src/views/ChatHistory/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAA;AAGnF,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,EAAiB;IAC/C,IAAI,CAAC,EAAE;QAAE,OAAM;IACf,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;QAChD,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,IAAI,EAAE,EAAE,CAAA;IACjE,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,sCAAsC;QACtC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;QACpB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,CAAA;IAC1B,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,EAAiB;IACnD,IAAI,CAAC,EAAE;QAAE,OAAM;IACf,IAAI,CAAC;QACH,MAAM,EAAE,GAAG,MAAM,eAAe,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC,CAAA;QACrE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,CAAC,IAAI,EAAE,CAAA;IAC/B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,sCAAsC;QACtC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;QACpB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,CAAA;IAC1B,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY;IAChC,IAAI,CAAC;QACH,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,WAAW,CAAC,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;QACpH,OAAO,CAAC,GAAG,MAAM,EAAE,GAAG,YAAY,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAA;IAC9F,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,sCAAsC;QACtC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;QACpB,OAAO,EAAE,CAAA;IACX,CAAC;AACH,CAAC"}
@@ -1,2 +1,2 @@
1
- export declare const useMessageInputDictionary: () => Record<"agent" | "stack" | "workspace" | "cancel" | "placeholder" | "send" | "collapse" | "knowledgeSource" | "expand" | "removeConfig" | "removeStack" | "removeWorkspace" | "removeKS", string>;
1
+ export declare const useMessageInputDictionary: () => Record<"stack" | "workspace" | "agent" | "cancel" | "placeholder" | "send" | "collapse" | "knowledgeSource" | "expand" | "removeConfig" | "removeStack" | "removeWorkspace" | "removeKS", string>;
2
2
  //# sourceMappingURL=dictionary.d.ts.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stack-spot/ai-chat-widget",
3
- "version": "0.3.0",
3
+ "version": "0.5.0",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -63,7 +63,7 @@ export const StackspotAIWidget = (
63
63
  <KSDocument />
64
64
  <Agents />
65
65
  <ChatHistory interceptors={interceptors} />
66
- {!isMinimized && <div className="chat-right-panel" ref={rightPanelRef}><RightPanel /></div>}
66
+ <div className="chat-right-panel" ref={rightPanelRef}><RightPanel /></div>
67
67
  </div>
68
68
  </RightPanelProvider>
69
69
  </TooltipProvider>
@@ -3,8 +3,8 @@ import { ChatState } from '../state/ChatState'
3
3
 
4
4
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
5
5
  export function quickCommandInterceptor(entry: ChatEntry, _chat: ChatState) {
6
- const { agent, content } = entry.getValue()
7
- if (agent !== 'user') return
6
+ const { agentType, content } = entry.getValue()
7
+ if (agentType !== 'user') return
8
8
  if (content.startsWith('/')) {
9
9
  alert('Quick commands are not yet supported!') /* todo */
10
10
  return false // by returning false, the next interceptor are not run. i.e. the message is not sent to the AI agent.
@@ -5,8 +5,8 @@ import { buildConversationContext } from '../utils/chat'
5
5
  import { genericSourcesToKnowledgeSources } from '../utils/knowledge-source'
6
6
 
7
7
  export async function sendMessageInterceptor(entry: ChatEntry, chat: ChatState) {
8
- const { agent, content } = entry.getValue()
9
- if (agent !== 'user') return
8
+ const { agentType, content } = entry.getValue()
9
+ if (agentType !== 'user') return
10
10
  const context = buildConversationContext(chat)
11
11
  chat.set('isLoading', true)
12
12
  // if this is the first message, let's rename the chat.
@@ -22,12 +22,13 @@ export async function sendMessageInterceptor(entry: ChatEntry, chat: ChatState)
22
22
  knowledgeSources = genericSourcesToKnowledgeSources(value.sources)
23
23
  }
24
24
  botEntry.setValue({
25
- agent: 'bot',
25
+ agentType: 'bot',
26
26
  type: 'md',
27
27
  content: value.answer ?? '',
28
28
  messageId: value.message_id ?? undefined,
29
29
  knowledgeSources,
30
30
  updated: new Date().toISOString(),
31
+ agent: chat.get('agent'),
31
32
  })
32
33
  })
33
34
  try {
@@ -3,17 +3,30 @@ import { ShowOptions } from './types'
3
3
 
4
4
  const MARGIN_TO_CORNERS_PX = 10
5
5
 
6
+ function isRelative(element: HTMLElement) {
7
+ return ['relative', 'absolute', 'fixed'].includes(element.computedStyleMap().get('position')?.toString() ?? '')
8
+ }
9
+
6
10
  export class TooltipAPI {
7
11
  private tooltipRef: React.RefObject<HTMLDivElement>
8
12
  private setContent: React.Dispatch<React.SetStateAction<React.ReactNode>>
9
13
  private hideTimeoutId: number | undefined
10
14
  private clickListener: ((e: MouseEvent) => void) | undefined
15
+ private relativeTo: HTMLElement | undefined
11
16
 
12
17
  constructor(tooltipRef: React.RefObject<HTMLDivElement>, setContent: React.Dispatch<React.SetStateAction<React.ReactNode>>) {
13
18
  this.tooltipRef = tooltipRef
14
19
  this.setContent = setContent
15
20
  }
16
21
 
22
+ private computeRelativeTo() {
23
+ if (this.relativeTo) return
24
+ this.relativeTo = this.tooltipRef.current?.parentElement as HTMLElement
25
+ while (this.relativeTo && this.relativeTo !== document.body && !isRelative(this.relativeTo)) {
26
+ this.relativeTo = this.relativeTo.parentElement as HTMLElement
27
+ }
28
+ }
29
+
17
30
  show({ content, anchor, position = 'bottom', hideOnClickOutside }: ShowOptions): void {
18
31
  window.clearTimeout(this.hideTimeoutId)
19
32
  this.hideTimeoutId = undefined
@@ -21,21 +34,26 @@ export class TooltipAPI {
21
34
  this.setContent(content)
22
35
  setTimeout(() => {
23
36
  if (!this.tooltipRef.current) return
24
- const rect = anchor.getClientRects()[0]
37
+ const anchorRect = anchor.getClientRects()[0]
25
38
  this.tooltipRef.current.classList.add('visible')
26
39
  const tooltipWidth = this.tooltipRef.current.clientWidth
27
40
  const tooltipHeight = this.tooltipRef.current.clientHeight
28
41
  let top = 0
29
42
  let left = 0
30
43
  if (position === 'left' || position === 'right') {
31
- top = rect.top + rect.height / 2 - tooltipHeight / 2
32
- if (position === 'left') left = rect.left - tooltipWidth
33
- else left = rect.left + rect.width
44
+ top = anchorRect.top + anchorRect.height / 2 - tooltipHeight / 2
45
+ if (position === 'left') left = anchorRect.left - tooltipWidth
46
+ else left = anchorRect.left + anchorRect.width
34
47
  } else {
35
- left = rect.left + rect.width / 2 - tooltipWidth / 2
36
- if (position === 'top') top = rect.top - tooltipHeight
37
- else top = rect.top + rect.height
48
+ left = anchorRect.left + anchorRect.width / 2 - tooltipWidth / 2
49
+ if (position === 'top') top = anchorRect.top - tooltipHeight
50
+ else top = anchorRect.top + anchorRect.height
38
51
  }
52
+ // takes the parent the tooltip is positioned relative to into consideration
53
+ this.computeRelativeTo()
54
+ const relativeRect = this.relativeTo?.getClientRects()[0] ?? { top: 0, left: 0 }
55
+ top -= relativeRect.top
56
+ left -= relativeRect.left
39
57
  // adjusts positions in order to avoid overflowing the window and leaving a margin to the corners
40
58
  if (top <= 0) top += MARGIN_TO_CORNERS_PX
41
59
  else if (top + tooltipHeight >= document.body.clientHeight - MARGIN_TO_CORNERS_PX) {
@@ -12,7 +12,7 @@ export const TooltipProvider = ({ children }: Required<WithChildren>) => {
12
12
  return (
13
13
  <Context.Provider value={api}>
14
14
  {children}
15
- <TooltipBox ref={ref} aria-hidden>{content}</TooltipBox>
15
+ <TooltipBox ref={ref}>{content}</TooltipBox>
16
16
  </Context.Provider>
17
17
  )
18
18
  }
package/src/layout.css CHANGED
@@ -44,6 +44,12 @@
44
44
  padding: 0 10px;
45
45
  width: calc(100% - 20px);
46
46
  }
47
+ .chat-window.narrow {
48
+ width: auto;
49
+ }
50
+ .chat-right-panel {
51
+ display: none;
52
+ }
47
53
  .home-page {
48
54
  .title {
49
55
  margin-top: 40px;
@@ -1,4 +1,5 @@
1
1
  import { pull } from 'lodash'
2
+ import { LabeledWithImage } from './types'
2
3
 
3
4
  export interface SerializableAction {
4
5
  title: string,
@@ -25,14 +26,14 @@ export interface KnowledgeSource {
25
26
 
26
27
  export interface TextChatEntry {
27
28
  type: 'text' | 'md',
28
- agent: 'bot' | 'user' | 'system',
29
+ agentType: 'bot' | 'user' | 'system',
29
30
  // image?: string,
30
31
  actions?: ChatAction[],
31
32
  subtitle?: string,
32
33
  content: string,
33
34
  knowledgeSources?: KnowledgeSource[],
34
35
  updated?: string,
35
- agentId?: string,
36
+ agent?: LabeledWithImage,
36
37
  messageId?: string,
37
38
  error?: string,
38
39
  // customInput?: CustomInputResponse,
@@ -63,7 +64,7 @@ export class ChatEntry {
63
64
 
64
65
  static createUserEntry(content: string) {
65
66
  return new ChatEntry({
66
- agent: 'user',
67
+ agentType: 'user',
67
68
  type: 'text',
68
69
  content,
69
70
  updated: new Date().toISOString(),
@@ -71,7 +72,7 @@ export class ChatEntry {
71
72
  }
72
73
 
73
74
  static createStreamedBotEntry(abort: () => void) {
74
- return new ChatEntry({ agent: 'bot', type: 'md', content: '' }, true, abort)
75
+ return new ChatEntry({ agentType: 'bot', type: 'md', content: '' }, true, abort)
75
76
  }
76
77
 
77
78
  setValue(value: TextChatEntry) {
@@ -1,15 +1,7 @@
1
1
  import { dropRight, last, pull } from 'lodash'
2
2
  import { ChatEntry } from './ChatEntry'
3
3
  import { ObservableState } from './ObservableState'
4
-
5
- interface Labeled {
6
- id: string,
7
- label: string,
8
- }
9
-
10
- interface LabeledWithImage extends Labeled {
11
- image?: string,
12
- }
4
+ import { Labeled, LabeledWithImage } from './types'
13
5
 
14
6
  export interface ChatProperties {
15
7
  label: string,
@@ -0,0 +1,8 @@
1
+ export interface Labeled {
2
+ id: string,
3
+ label: string,
4
+ }
5
+
6
+ export interface LabeledWithImage extends Labeled {
7
+ image?: string,
8
+ }
@@ -2,6 +2,7 @@ import { Button, Text } from '@citric/core'
2
2
  import { Search } from '@citric/icons'
3
3
  import { Badge } from '@citric/ui'
4
4
  import { Placeholder } from '@stack-spot/portal-components/Placeholder'
5
+ import { MiniLogo } from '@stack-spot/portal-components/svg'
5
6
  import { agentClient } from '@stack-spot/portal-network'
6
7
  import { AgentResponse, VisibilityLevel } from '@stack-spot/portal-network/api/agent'
7
8
  import { theme } from '@stack-spot/portal-theme'
@@ -20,7 +21,7 @@ const AgentLabel = styled.div`
20
21
  align-items: center;
21
22
  gap: 6px;
22
23
 
23
- img {
24
+ img, svg {
24
25
  width: 20px;
25
26
  height: 20px;
26
27
  border-radius: 50%;
@@ -86,8 +87,8 @@ const AgentsPanel = () => {
86
87
  const chat = useCurrentChat()
87
88
 
88
89
  return <RightPanelTabs key={chat.id} tabs={[
89
- { title: t.personal, content: <AgentsTab key="personal" visibility="PERSONAL" /> },
90
90
  { title: t.builtin, content: <AgentsTab key="builtin" visibility="BUILT-IN" /> },
91
+ { title: t.personal, content: <AgentsTab key="personal" visibility="PERSONAL" /> },
91
92
  { title: t.shared, content: <AgentsTab key="shared" visibility="SHARED" /> },
92
93
  { title: t.account, content: <AgentsTab key="account" visibility="ACCOUNT" /> },
93
94
  ]} />
@@ -98,15 +99,23 @@ const AgentsTab = ({ visibility }: { visibility: VisibilityLevel | 'BUILT-IN' })
98
99
  const { close } = useRightPanel()
99
100
  const chat = useCurrentChat()
100
101
  const [filter, setFilter] = useState('')
102
+ const defaultAgent = useMemo(() => ({
103
+ name: t.defaultAgentName,
104
+ description: t.defaultAgentDescription,
105
+ llm_config: { model_slug: 'gpt4o' },
106
+ } as AgentResponse), [])
101
107
  const agents = visibility === 'BUILT-IN' ? agentClient.publicAgents.useQuery({}) : agentClient.agents.useQuery({ visibility })
102
- const [value, setValue] = useState<AgentResponse | undefined>(agents.find(a => a.id === chat.get('agent')?.id))
108
+ const [value, setValue] = useState<AgentResponse | undefined>(agents.find(a => a.id === chat.get('agent')?.id) ?? defaultAgent)
103
109
  const filtered = useMemo(
104
- () => filter ? agents.filter(a => a === value || a.name.toLocaleLowerCase().includes(filter.toLocaleLowerCase())) : agents,
110
+ () => {
111
+ const ags = visibility === 'BUILT-IN' ? [defaultAgent as AgentResponse, ...agents] : agents
112
+ return filter ? ags.filter(a => a === value || a.name.toLocaleLowerCase().includes(filter.toLocaleLowerCase())) : ags
113
+ },
105
114
  [agents, filter, value],
106
115
  )
107
116
 
108
117
  function submit() {
109
- if (value) chat.set('agent', { id: value.id, label: value.name, image: value.avatar })
118
+ if (value) chat.set('agent', value.id ? { id: value.id, label: value.name, image: value.avatar } : undefined)
110
119
  close()
111
120
  }
112
121
 
@@ -119,9 +128,9 @@ const AgentsTab = ({ visibility }: { visibility: VisibilityLevel | 'BUILT-IN' })
119
128
  keygen={a => a.id}
120
129
  value={value}
121
130
  onChange={setValue}
122
- renderLabel={({ name, avatar }) => (
131
+ renderLabel={({ name, avatar, id }) => (
123
132
  <AgentLabel>
124
- {avatar && <img src={avatar} />}
133
+ {id ? (avatar && <img src={avatar} />) : <MiniLogo />}
125
134
  <Text>{name}</Text>
126
135
  </AgentLabel>
127
136
  )}
@@ -170,6 +179,8 @@ const dictionary = {
170
179
  noSearchResultsDescription: 'Please, try another search term.',
171
180
  noData: 'There are no agents in this category yet.',
172
181
  noDataDescription: 'Use the tabs above to try other categories or use the AI portal to create new agents.',
182
+ defaultAgentName: 'Stackspot AI (default)',
183
+ defaultAgentDescription: 'The StackSpot CodeGen is an advanced artificial intelligence agent designed to optimize and accelerate software development. Integrated directly into your integrated development environment, StackSpot CodeGen offers real-time code suggestions, helping developers write high-quality code more efficiently. With robust features such as creating Stacks AI, customized knowledge sources, and quick commands, StackSpot CodeGen contextualizes your development needs to provide the best answers and code suggestions.',
173
184
  },
174
185
  pt: {
175
186
  title: 'Agentes',
@@ -183,5 +194,7 @@ const dictionary = {
183
194
  noSearchResultsDescription: 'Por favor, tente outra busca.',
184
195
  noData: 'Ainda não há agentes nesta categoria.',
185
196
  noDataDescription: 'Use as abas acima para tentar outras categorias ou use o Portal AI para criar novos agentes.',
197
+ defaultAgentName: 'Stackspot AI (padrão)',
198
+ defaultAgentDescription: 'O StackSpot CodeGen é um agente de inteligência artificial avançado projetado para otimizar e acelerar o desenvolvimento de software. Integrado diretamente ao seu ambiente de desenvolvimento, o StackSpot CodeGen oferece sugestões de código em tempo real, ajudando os desenvolvedores a escreverem código de alta qualidade de forma mais eficiente. Com recursos robustos, como a criação de Stacks AI, Knowledge Sources personalizadas e comandos rápidos, o StackSpot CodeGen contextualiza suas necessidades de desenvolvimento para fornecer as melhores respostas e sugestões de código.',
186
199
  },
187
200
  } satisfies Dictionary
@@ -1,17 +1,17 @@
1
1
  import { Text } from '@citric/core'
2
2
  import { MiniLogo } from '@stack-spot/portal-components/svg'
3
+ import { LabeledWithImage } from '../../state/types'
3
4
 
4
5
  interface Props {
5
- agentId?: string,
6
+ agent?: LabeledWithImage,
6
7
  }
7
8
 
8
- // todo: retrieve agent data and render accordingly
9
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
10
- export const AgentInfo = ({ agentId: _agentId }: Props) => (
9
+ export const AgentInfo = ({ agent }: Props) => (
11
10
  <>
12
- <div className="agent-image-wrapper">
13
- <MiniLogo className="agent-image" />
14
- </div>
15
- <Text appearance="body2">Stackspot AI</Text>
11
+ {agent?.image
12
+ ? <img src={agent.image} className="custom-agent-image" />
13
+ : <div className="default-image-wrapper"><MiniLogo className="agent-image" /></div>
14
+ }
15
+ <Text appearance="body2">{agent?.label || 'Stackspot AI'}</Text>
16
16
  </>
17
17
  )
@@ -16,7 +16,7 @@ export const ChatMessage = ({ message, username }: { message: ChatEntry, usernam
16
16
  const [liked, setLiked] = useState<boolean | undefined>()
17
17
  const entry = useChatEntry(message)
18
18
  const dateFormatter = useDateFormatter()
19
- const userInfo = entry.agent === 'user' ? <Avatar size="xs">{username}</Avatar> : <AgentInfo agentId={entry.agentId} />
19
+ const userInfo = entry.agentType === 'user' ? <Avatar size="xs">{username}</Avatar> : <AgentInfo agent={entry.agent} />
20
20
  const date = new Date(entry.updated ?? '')
21
21
  const shouldShowDate = entry.updated && !isNaN(date.getTime())
22
22
  const ref = useRef<HTMLLIElement>(null)
@@ -55,7 +55,7 @@ export const ChatMessage = ({ message, username }: { message: ChatEntry, usernam
55
55
  }, [entry.messageId, liked])
56
56
 
57
57
  return (entry.content || entry.error) && (
58
- <li className={entry.agent} ref={ref}>
58
+ <li className={entry.agentType} ref={ref}>
59
59
  <div className="chat-message">
60
60
  <div className="user-info">{userInfo}</div>
61
61
  {entry.content && <div className="message-content">
@@ -77,7 +77,7 @@ export const ChatMessage = ({ message, username }: { message: ChatEntry, usernam
77
77
  ))}</ul>
78
78
  </div>}
79
79
  <div className="message-footer">
80
- {entry.agent === 'bot' && entry.messageId && !entry.error && <div className="message-actions">
80
+ {entry.agentType === 'bot' && entry.messageId && !entry.error && <div className="message-actions">
81
81
  <IconButton title={t.like} aria-label={t.like} onClick={like}>
82
82
  {liked === true ? <LikeFill /> : <Like />}
83
83
  </IconButton>
@@ -76,7 +76,7 @@ export const ChatList = styled.ul`
76
76
  flex-direction: column;
77
77
  gap: 4px;
78
78
 
79
- .agent-image-wrapper {
79
+ .default-image-wrapper {
80
80
  width: 24px;
81
81
  height: 24px;
82
82
  border-radius: 4px;
@@ -90,6 +90,12 @@ export const ChatList = styled.ul`
90
90
  height: 18px;
91
91
  }
92
92
  }
93
+
94
+ .custom-agent-image {
95
+ width: 24px;
96
+ height: 24px;
97
+ border-radius: 50%;
98
+ }
93
99
  }
94
100
  }
95
101
 
@@ -100,6 +106,7 @@ export const ChatList = styled.ul`
100
106
  display: flex;
101
107
  flex-direction: row;
102
108
  gap: 8px;
109
+ align-items: center;
103
110
 
104
111
  .message-content {
105
112
  padding: 10px;
@@ -4,6 +4,7 @@ import { IconButton, LoadingCircular } from '@citric/ui'
4
4
  import { aiClient } from '@stack-spot/portal-network'
5
5
  import { ConversationResponse } from '@stack-spot/portal-network/api/ai'
6
6
  import { theme } from '@stack-spot/portal-theme'
7
+ import { last } from 'lodash'
7
8
  import { useCallback, useEffect, useRef, useState } from 'react'
8
9
  import { OverlayMenu } from '../../components/OverlayMenu'
9
10
  import { useWidget } from '../../context/hooks'
@@ -14,7 +15,7 @@ import { download } from '../../utils/download'
14
15
  import { genericSourcesToKnowledgeSources } from '../../utils/knowledge-source'
15
16
  import { useHistoryDictionary } from './dictionary'
16
17
  import { HistoryItemBox } from './styled'
17
- import { findStack, findWorkspace } from './utils'
18
+ import { findStack, findWorkspace, getAllAgents } from './utils'
18
19
 
19
20
  export const HistoryItem = ({ item, interceptors }: { item: ConversationResponse, interceptors: MessageInterceptor[] }) => {
20
21
  const t = useHistoryDictionary()
@@ -35,15 +36,17 @@ export const HistoryItem = ({ item, interceptors }: { item: ConversationResponse
35
36
  }, [])
36
37
 
37
38
  async function onSubmitRename() {
39
+ const prev = title
38
40
  setRenaming(false)
41
+ setTitle(renamed)
39
42
  if (!renamed || renamed === item.title) return
40
43
  try {
41
44
  await aiClient.renameChat.mutate({ conversationId: item.id, conversationUpdateTitleRequest: { title: renamed } })
42
- setTitle(renamed)
43
45
  aiClient.chats.invalidate()
44
46
  } catch (error) {
45
47
  // eslint-disable-next-line no-console
46
48
  console.error(error)
49
+ setTitle(prev)
47
50
  setRenaming(true)
48
51
  }
49
52
  }
@@ -78,18 +81,22 @@ export const HistoryItem = ({ item, interceptors }: { item: ConversationResponse
78
81
  setLoading(true)
79
82
  try {
80
83
  const chat = await aiClient.chat.query({ conversationId: item.id })
81
- const [stack, workspace] = await Promise.all([findStack(chat.ai_stack_id), findWorkspace(chat.workspace_id)])
84
+ const [stack, workspace, agents] = await Promise.all([
85
+ findStack(chat.ai_stack_id),
86
+ findWorkspace(chat.workspace_id),
87
+ getAllAgents(),
88
+ ])
82
89
  widget.chatTabs.add(new ChatState({
83
90
  id: chat.id,
84
- initial: { label: chat.title, stack, workspace },
91
+ initial: { label: chat.title, stack, workspace, agent: agents.find(a => a.id === last(chat.history)?.custom_agent?.id) },
85
92
  interceptors,
86
93
  entries: chat.history?.map(item => new ChatEntry({
87
- agent: item.agent === 'USER' ? 'user' : 'bot',
94
+ agentType: item.agent === 'USER' ? 'user' : 'bot',
88
95
  content: item.content,
89
96
  type: item.agent === 'USER' ? 'text' : 'md',
90
- agentId: item.custom_agent?.id,
97
+ agent: agents.find(a => a.id === item.custom_agent?.id),
91
98
  messageId: item.message_id,
92
- knowledgeSources: genericSourcesToKnowledgeSources(item.sources),
99
+ knowledgeSources: item.agent === 'USER' ? undefined : genericSourcesToKnowledgeSources(item.sources),
93
100
  updated: item.updated,
94
101
  })),
95
102
  }))
@@ -111,7 +118,12 @@ export const HistoryItem = ({ item, interceptors }: { item: ConversationResponse
111
118
  <HistoryItemBox className={isLoading ? 'loading' : ''}>
112
119
  {isRenaming ? (
113
120
  <>
114
- <Input ref={renameInput} value={renamed} onChange={e => setRenamed(e.target.value)} />
121
+ <Input
122
+ ref={renameInput}
123
+ value={renamed}
124
+ onChange={e => setRenamed(e.target.value)}
125
+ onKeyDown={e => e.key === 'Enter' && onSubmitRename()}
126
+ />
115
127
  <IconButton onClick={onSubmitRename}><Check /></IconButton>
116
128
  </>
117
129
  ) : (
@@ -1,4 +1,4 @@
1
- import { aiClient, workspaceClient } from '@stack-spot/portal-network'
1
+ import { agentClient, aiClient, workspaceClient } from '@stack-spot/portal-network'
2
2
  import { ChatProperties } from '../../state/ChatState'
3
3
 
4
4
  export async function findStack(id: string | null): Promise<ChatProperties['stack'] | undefined> {
@@ -24,3 +24,14 @@ export async function findWorkspace(id: string | null): Promise<ChatProperties['
24
24
  return { id, label: id }
25
25
  }
26
26
  }
27
+
28
+ export async function getAllAgents(): Promise<Required<ChatProperties>['agent'][]> {
29
+ try {
30
+ const [agents, publicAgents] = await Promise.all([agentClient.agents.query({}), agentClient.publicAgents.query({})])
31
+ return [...agents, ...publicAgents].map(a => ({ id: a.id, label: a.name, image: a.avatar }))
32
+ } catch (error) {
33
+ // eslint-disable-next-line no-console
34
+ console.error(error)
35
+ return []
36
+ }
37
+ }