@stack-spot/ai-chat-widget 0.9.0 → 0.11.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 (96) hide show
  1. package/dist/AbortedError.d.ts +5 -0
  2. package/dist/AbortedError.d.ts.map +1 -0
  3. package/dist/AbortedError.js +7 -0
  4. package/dist/AbortedError.js.map +1 -0
  5. package/dist/StackspotAIWidget.d.ts.map +1 -1
  6. package/dist/StackspotAIWidget.js +11 -3
  7. package/dist/StackspotAIWidget.js.map +1 -1
  8. package/dist/chat-interceptors/CustomInputs.d.ts +19 -0
  9. package/dist/chat-interceptors/CustomInputs.d.ts.map +1 -0
  10. package/dist/chat-interceptors/CustomInputs.js +62 -0
  11. package/dist/chat-interceptors/CustomInputs.js.map +1 -0
  12. package/dist/chat-interceptors/quick-command-questions.d.ts +4 -0
  13. package/dist/chat-interceptors/quick-command-questions.d.ts.map +1 -0
  14. package/dist/chat-interceptors/quick-command-questions.js +18 -0
  15. package/dist/chat-interceptors/quick-command-questions.js.map +1 -0
  16. package/dist/chat-interceptors/quick-commands.d.ts +3 -1
  17. package/dist/chat-interceptors/quick-commands.d.ts.map +1 -1
  18. package/dist/chat-interceptors/quick-commands.js +249 -8
  19. package/dist/chat-interceptors/quick-commands.js.map +1 -1
  20. package/dist/chat-interceptors/send-message.d.ts +1 -1
  21. package/dist/chat-interceptors/send-message.d.ts.map +1 -1
  22. package/dist/chat-interceptors/send-message.js +4 -4
  23. package/dist/chat-interceptors/send-message.js.map +1 -1
  24. package/dist/components/Code.d.ts.map +1 -1
  25. package/dist/components/Code.js +9 -3
  26. package/dist/components/Code.js.map +1 -1
  27. package/dist/state/ChatEntry.d.ts +8 -8
  28. package/dist/state/ChatEntry.d.ts.map +1 -1
  29. package/dist/state/ChatEntry.js +4 -16
  30. package/dist/state/ChatEntry.js.map +1 -1
  31. package/dist/state/ChatState.d.ts +13 -1
  32. package/dist/state/ChatState.d.ts.map +1 -1
  33. package/dist/state/ChatState.js +38 -3
  34. package/dist/state/ChatState.js.map +1 -1
  35. package/dist/state/ObservableState.d.ts +1 -1
  36. package/dist/state/ObservableState.d.ts.map +1 -1
  37. package/dist/state/ObservableState.js.map +1 -1
  38. package/dist/utils/chat.d.ts.map +1 -1
  39. package/dist/utils/chat.js +2 -1
  40. package/dist/utils/chat.js.map +1 -1
  41. package/dist/utils/knowledge-source.d.ts +2 -2
  42. package/dist/utils/knowledge-source.d.ts.map +1 -1
  43. package/dist/utils/knowledge-source.js +4 -6
  44. package/dist/utils/knowledge-source.js.map +1 -1
  45. package/dist/utils/programming-languages.d.ts +1 -0
  46. package/dist/utils/programming-languages.d.ts.map +1 -1
  47. package/dist/utils/programming-languages.js +1 -0
  48. package/dist/utils/programming-languages.js.map +1 -1
  49. package/dist/utils/string.d.ts +2 -0
  50. package/dist/utils/string.d.ts.map +1 -0
  51. package/dist/utils/string.js +7 -0
  52. package/dist/utils/string.js.map +1 -0
  53. package/dist/views/Chat/ChatMessage.d.ts +2 -1
  54. package/dist/views/Chat/ChatMessage.d.ts.map +1 -1
  55. package/dist/views/Chat/ChatMessage.js +15 -4
  56. package/dist/views/Chat/ChatMessage.js.map +1 -1
  57. package/dist/views/Chat/ChatMessages.d.ts.map +1 -1
  58. package/dist/views/Chat/ChatMessages.js +1 -1
  59. package/dist/views/Chat/ChatMessages.js.map +1 -1
  60. package/dist/views/Chat/styled.d.ts.map +1 -1
  61. package/dist/views/Chat/styled.js +31 -0
  62. package/dist/views/Chat/styled.js.map +1 -1
  63. package/dist/views/Editor.d.ts.map +1 -1
  64. package/dist/views/Editor.js +3 -4
  65. package/dist/views/Editor.js.map +1 -1
  66. package/dist/views/MessageInput/ButtonGroup.d.ts +1 -1
  67. package/dist/views/MessageInput/ButtonGroup.d.ts.map +1 -1
  68. package/dist/views/MessageInput/index.d.ts.map +1 -1
  69. package/dist/views/MessageInput/index.js +8 -4
  70. package/dist/views/MessageInput/index.js.map +1 -1
  71. package/package.json +2 -2
  72. package/src/AbortedError.ts +7 -0
  73. package/src/StackspotAIWidget.tsx +13 -3
  74. package/src/chat-interceptors/CustomInputs.ts +70 -0
  75. package/src/chat-interceptors/quick-command-questions.ts +15 -0
  76. package/src/chat-interceptors/quick-commands.ts +269 -7
  77. package/src/chat-interceptors/send-message.ts +4 -4
  78. package/src/components/Code.tsx +16 -3
  79. package/src/state/ChatEntry.ts +7 -20
  80. package/src/state/ChatState.ts +41 -3
  81. package/src/state/ObservableState.ts +1 -1
  82. package/src/utils/chat.ts +2 -1
  83. package/src/utils/knowledge-source.ts +6 -8
  84. package/src/utils/programming-languages.ts +2 -0
  85. package/src/utils/string.ts +6 -0
  86. package/src/views/Chat/ChatMessage.tsx +38 -8
  87. package/src/views/Chat/ChatMessages.tsx +4 -1
  88. package/src/views/Chat/styled.ts +31 -0
  89. package/src/views/Editor.tsx +3 -4
  90. package/src/views/MessageInput/ButtonGroup.tsx +1 -1
  91. package/src/views/MessageInput/index.tsx +9 -5
  92. package/dist/components/Editor.d.ts +0 -9
  93. package/dist/components/Editor.d.ts.map +0 -1
  94. package/dist/components/Editor.js +0 -2
  95. package/dist/components/Editor.js.map +0 -1
  96. package/src/components/Editor.tsx +0 -12
@@ -98,6 +98,37 @@ export const ChatList = styled.ul `
98
98
  }
99
99
  }
100
100
 
101
+ .message-content {
102
+ > .badges, > .actions {
103
+ display: flex;
104
+ flex-direction: row;
105
+ gap: 4px;
106
+ }
107
+ > .badges {
108
+ margin-bottom: 20px;
109
+ }
110
+ > .actions {
111
+ margin-top: 20px;
112
+ }
113
+ &.card {
114
+ margin-top: 5px;
115
+ position: relative;
116
+ padding: 16px;
117
+ border: 2px solid ${theme.color.light[500]};
118
+ border-radius: 4px;
119
+ overflow: hidden;
120
+ &:before {
121
+ content: '';
122
+ position: absolute;
123
+ top: 0;
124
+ left: 0;
125
+ bottom: 0;
126
+ width: 2px;
127
+ background: linear-gradient(180deg, ${theme.color.blue[500]} 0%, ${theme.color.indigo[500]} 100%);
128
+ }
129
+ }
130
+ }
131
+
101
132
  &.user {
102
133
  align-items: end;
103
134
 
@@ -1 +1 @@
1
- {"version":3,"file":"styled.js","sourceRoot":"","sources":["../../../src/views/Chat/styled.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,0BAA0B,CAAA;AAChD,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAA;AAE1C,MAAM,CAAC,MAAM,QAAQ,GAAG,MAAM,CAAC,EAAE,CAAA;;;;;;;;;;;;;;wBAcT,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC;aAClC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,YAAY;;;;;cAK9B,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,YAAY;;;;;;;;;;;;;;;;;;;;;;;;0BAwBnB,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8BAmCjB,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8BA8BtB,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;wBAyB5B,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC;;;;;;;;;;;;;;;;;CAiB7C,CAAA"}
1
+ {"version":3,"file":"styled.js","sourceRoot":"","sources":["../../../src/views/Chat/styled.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,0BAA0B,CAAA;AAChD,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAA;AAE1C,MAAM,CAAC,MAAM,QAAQ,GAAG,MAAM,CAAC,EAAE,CAAA;;;;;;;;;;;;;;wBAcT,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC;aAClC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,YAAY;;;;;cAK9B,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,YAAY;;;;;;;;;;;;;;;;;;;;;;;;0BAwBnB,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8BAmCjB,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4BAmCxB,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC;;;;;;;;;;gDAUF,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC;;;;;;;;;;;;;;;;8BAgBtE,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;wBAyB5B,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC;;;;;;;;;;;;;;;;;CAiB7C,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"Editor.d.ts","sourceRoot":"","sources":["../../src/views/Editor.tsx"],"names":[],"mappings":"AA6CA,eAAO,MAAM,MAAM,YAmBlB,CAAA"}
1
+ {"version":3,"file":"Editor.d.ts","sourceRoot":"","sources":["../../src/views/Editor.tsx"],"names":[],"mappings":"AA4CA,eAAO,MAAM,MAAM,YAmBlB,CAAA"}
@@ -10,8 +10,7 @@ import { useCallback, useEffect, useMemo, useRef } from 'react';
10
10
  import { styled } from 'styled-components';
11
11
  import { useCurrentChat, useCurrentChatState, useWidget, useWidgetState } from '../context/hooks.js';
12
12
  import { useRightPanel } from '../right-panel/hooks.js';
13
- import { languages } from '../utils/programming-languages.js';
14
- const DEFAULT_LANGUAGE = 'python';
13
+ import { defaultLanguage, languages } from '../utils/programming-languages.js';
15
14
  const MIN_SELECTION_UPDATE_MS = 200;
16
15
  const EditorBox = styled.div `
17
16
  flex: 1;
@@ -56,7 +55,7 @@ export const Editor = () => {
56
55
  return null;
57
56
  };
58
57
  const Title = () => {
59
- const languageValue = useCurrentChatState('codeLanguage') || DEFAULT_LANGUAGE;
58
+ const languageValue = useCurrentChatState('codeLanguage') || defaultLanguage;
60
59
  const language = useMemo(() => languages.find(l => l.value === languageValue), [languageValue]);
61
60
  const chat = useCurrentChat();
62
61
  return (_jsxs(TitleBox, { children: [_jsx(Text, { appearance: "h5", children: "Editor" }), _jsx(Select, { options: languages, renderLabel: l => l.label, renderValue: l => l.value, value: language, onChange: l => chat.set('codeLanguage', l.value), className: "language-selector" })] }));
@@ -64,7 +63,7 @@ const Title = () => {
64
63
  const EditorPanel = () => {
65
64
  const themeKind = useThemeKind();
66
65
  const value = useCurrentChatState('code');
67
- const language = useCurrentChatState('codeLanguage') || DEFAULT_LANGUAGE;
66
+ const language = useCurrentChatState('codeLanguage') || defaultLanguage;
68
67
  const chat = useCurrentChat();
69
68
  const selectionObserver = useRef();
70
69
  const setup = useCallback((editor) => {
@@ -1 +1 @@
1
- {"version":3,"file":"Editor.js","sourceRoot":"","sources":["../../src/views/Editor.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Editor.js","sourceRoot":"","sources":["../../src/views/Editor.tsx"],"names":[],"mappings":"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"}
@@ -5,7 +5,7 @@ interface ButtonGroupProps {
5
5
  setExpanded: React.Dispatch<React.SetStateAction<boolean>>;
6
6
  isLoading: boolean;
7
7
  onSend: () => void;
8
- onCancel?: () => void;
8
+ onCancel: () => void;
9
9
  }
10
10
  export declare const ButtonGroup: ({ features, onSend, onCancel, expanded, setExpanded, isLoading }: ButtonGroupProps) => import("react/jsx-runtime").JSX.Element;
11
11
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"ButtonGroup.d.ts","sourceRoot":"","sources":["../../../src/views/MessageInput/ButtonGroup.tsx"],"names":[],"mappings":"AAMA,OAAO,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAA;AAGrD,UAAU,gBAAgB;IACxB,QAAQ,EAAE,oBAAoB,CAAC;IAC/B,QAAQ,EAAE,OAAO,CAAC;IAClB,WAAW,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC;IAC3D,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;CACvB;AAED,eAAO,MAAM,WAAW,qEAAsE,gBAAgB,4CAwE7G,CAAA"}
1
+ {"version":3,"file":"ButtonGroup.d.ts","sourceRoot":"","sources":["../../../src/views/MessageInput/ButtonGroup.tsx"],"names":[],"mappings":"AAMA,OAAO,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAA;AAGrD,UAAU,gBAAgB;IACxB,QAAQ,EAAE,oBAAoB,CAAC;IAC/B,QAAQ,EAAE,OAAO,CAAC;IAClB,WAAW,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC;IAC3D,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,QAAQ,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,eAAO,MAAM,WAAW,qEAAsE,gBAAgB,4CAwE7G,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/views/MessageInput/index.tsx"],"names":[],"mappings":"AAMA,OAAO,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAA;AAOrD,UAAU,KAAK;IACb,QAAQ,EAAE,oBAAoB,CAAC;CAChC;AAED,eAAO,MAAM,YAAY,iBAAkB,KAAK,4CA2D/C,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/views/MessageInput/index.tsx"],"names":[],"mappings":"AAKA,OAAO,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAA;AAOrD,UAAU,KAAK;IACb,QAAQ,EAAE,oBAAoB,CAAC;CAChC;AAED,eAAO,MAAM,YAAY,iBAAkB,KAAK,4CAgE/C,CAAA"}
@@ -1,7 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { listToClass } from '@stack-spot/portal-theme';
3
- import { last } from 'lodash';
4
- import { useCallback, useRef, useState } from 'react';
3
+ import { useCallback, useEffect, useRef, useState } from 'react';
5
4
  import { AdaptiveTextArea } from '../../components/AdaptiveTextArea.js';
6
5
  import { ProgressBar } from '../../components/ProgressBar.js';
7
6
  import { useCurrentChat, useCurrentChatState, useWidgetState } from '../../context/hooks.js';
@@ -19,13 +18,14 @@ export const MessageInput = ({ features }) => {
19
18
  const isLoading = useCurrentChatState('isLoading') ?? false;
20
19
  const value = useCurrentChatState('nextMessage') ?? '';
21
20
  const isMinimized = useWidgetState('isMinimized');
21
+ const elementRef = useRef(null);
22
22
  const onSend = useCallback(async () => {
23
23
  const message = chat.get('nextMessage');
24
24
  if (!message)
25
25
  return;
26
26
  const code = chat.get('codeSelection');
27
27
  const language = chat.get('codeLanguage');
28
- const prompt = code ? `${message}\n\`\`\`${language}\n${code}\n\`\`\`` : message;
28
+ const prompt = code && !message.startsWith('/') ? `${message}\n\`\`\`${language}\n${code}\n\`\`\`` : message;
29
29
  chat.pushMessage(ChatEntry.createUserEntry(prompt, true));
30
30
  chat.set('nextMessage', '');
31
31
  setFocused(false);
@@ -36,7 +36,11 @@ export const MessageInput = ({ features }) => {
36
36
  onSend();
37
37
  }
38
38
  }, [onSend]);
39
- return (_jsxs(MessageInputBox, { "aria-busy": isLoading, className: "message-input", children: [_jsx(ProgressBar, { visible: isLoading, shimmer: true }), _jsx(InfoBar, {}), _jsxs("div", { className: listToClass(['action-box', focused && 'focused', isLoading && 'disabled']), children: [_jsx(AdaptiveTextArea, { disabled: isLoading, placeholder: t.placeholder, onChange: e => chat.set('nextMessage', e.target.value), value: value, onFocus: () => setFocused(true), onBlur: () => setFocused(false), onKeyDown: onKeyDown, onIncreaseSize: () => setExpanded(false), onResetSize: () => !expansionLocked.current && setExpanded(true), maxHeight: isMinimized ? MIN_INPUT_HEIGHT : MAX_INPUT_HEIGHT }), _jsx(ButtonGroup, { features: features, onSend: onSend, onCancel: () => last(chat.getMessages())?.abort(), expanded: expanded, isLoading: isLoading, setExpanded: (value) => {
39
+ useEffect(() => {
40
+ if (!isLoading)
41
+ elementRef.current?.querySelector('textarea')?.focus();
42
+ }, [isLoading]);
43
+ return (_jsxs(MessageInputBox, { ref: elementRef, "aria-busy": isLoading, className: "message-input", children: [_jsx(ProgressBar, { visible: isLoading, shimmer: true }), _jsx(InfoBar, {}), _jsxs("div", { className: listToClass(['action-box', focused && 'focused', isLoading && 'disabled']), children: [_jsx(AdaptiveTextArea, { disabled: isLoading, placeholder: t.placeholder, onChange: e => chat.set('nextMessage', e.target.value), value: value, onFocus: () => setFocused(true), onBlur: () => setFocused(false), onKeyDown: onKeyDown, onIncreaseSize: () => setExpanded(false), onResetSize: () => !expansionLocked.current && setExpanded(true), maxHeight: isMinimized ? MIN_INPUT_HEIGHT : MAX_INPUT_HEIGHT }), _jsx(ButtonGroup, { features: features, onSend: onSend, onCancel: () => chat.abort(), expanded: expanded, isLoading: isLoading, setExpanded: (value) => {
40
44
  setExpanded(value);
41
45
  expansionLocked.current = expanded;
42
46
  } })] })] }));
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/views/MessageInput/index.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/views/MessageInput/index.tsx"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stack-spot/ai-chat-widget",
3
- "version": "0.9.0",
3
+ "version": "0.11.0",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -9,7 +9,7 @@
9
9
  "@citric/icons": "^5.4.0 || ^6.0.0",
10
10
  "@citric/ui": "^5.4.0 || ^6.0.0",
11
11
  "@stack-spot/portal-components": "^2.6.1",
12
- "@stack-spot/portal-network": "^0.42.2",
12
+ "@stack-spot/portal-network": "^0.46.0",
13
13
  "@stack-spot/portal-theme": "^1.0.0",
14
14
  "@stack-spot/portal-translate": "^1.1.0",
15
15
  "lodash": "^4.17.0",
@@ -0,0 +1,7 @@
1
+ import { StackspotAPIError } from '@stack-spot/portal-network'
2
+
3
+ export class AbortedError extends StackspotAPIError {
4
+ constructor() {
5
+ super({ status: 0, message: 'Operation canceled by the user.' })
6
+ }
7
+ }
@@ -1,9 +1,11 @@
1
+ import { loader } from '@monaco-editor/react'
1
2
  import { listToClass } from '@stack-spot/portal-theme'
2
3
  import { useMemo, useRef } from 'react'
3
- import { quickCommandInterceptor } from './chat-interceptors/quick-commands'
4
+ import { quickCommandQuestionsInterceptor } from './chat-interceptors/quick-command-questions'
5
+ import { createQuickCommandInterceptor } from './chat-interceptors/quick-commands'
4
6
  import { sendMessageInterceptor } from './chat-interceptors/send-message'
5
7
  import { TooltipProvider } from './components/Tooltip'
6
- import { useCurrentChatMessages, useFirstChat, useWidgetState } from './context/hooks'
8
+ import { useCurrentChatMessages, useFirstChat, useWidget, useWidgetState } from './context/hooks'
7
9
  import { AIWidgetFeatures, defaultFeatures } from './features'
8
10
  import './layout.css'
9
11
  import { RightPanel } from './right-panel/RightPanel'
@@ -34,7 +36,15 @@ export interface AIWidgetProps {
34
36
  export const StackspotAIWidget = (
35
37
  { username, features = defaultFeatures, interceptors: userInterceptors = [], minimizedActions = {}, children }: AIWidgetProps,
36
38
  ) => {
37
- const interceptors: MessageInterceptor[] = useMemo(() => [...userInterceptors, quickCommandInterceptor, sendMessageInterceptor], [])
39
+ const widget = useWidget()
40
+ const interceptors: MessageInterceptor[] = useMemo(
41
+ () => [
42
+ ...userInterceptors,
43
+ quickCommandQuestionsInterceptor,
44
+ createQuickCommandInterceptor(widget, () => loader.__getMonacoInstance()?.editor),
45
+ sendMessageInterceptor],
46
+ [],
47
+ )
38
48
  useFirstChat(interceptors)
39
49
  const rightPanelRef = useRef<HTMLDivElement>(null)
40
50
  const chatWindowRef = useRef<HTMLDivElement>(null)
@@ -0,0 +1,70 @@
1
+ import { CustomInputResponse } from '@stack-spot/portal-network/api/ai'
2
+ import { Dictionary, translate } from '@stack-spot/portal-translate'
3
+ import { ChatEntry } from '../state/ChatEntry'
4
+ import { LabeledWithImage } from '../state/types'
5
+
6
+ export const CUSTOM_INPUTS_KEY = 'customInputs'
7
+
8
+ export class CustomInputs {
9
+ private value: Record<string, string> = {}
10
+ private inputs: CustomInputResponse[]
11
+ private index = 0
12
+ private resolve?: (value: Record<string, string>) => void
13
+ private promise: Promise<Record<string, string>>
14
+ private agent?: LabeledWithImage
15
+
16
+ constructor(inputs: CustomInputResponse[], agent?: LabeledWithImage) {
17
+ this.inputs = inputs
18
+ this.agent = agent
19
+ this.promise = new Promise(resolve => {
20
+ this.resolve = resolve
21
+ })
22
+ }
23
+
24
+ ask(): ChatEntry {
25
+ if (this.index >= this.inputs.length) throw new Error('No more questions to ask.')
26
+ const t = translate(dictionary)
27
+ const input = this.inputs[this.index]
28
+ return new ChatEntry({
29
+ agentType: 'bot',
30
+ content: input.question,
31
+ type: 'text',
32
+ agent: this.agent,
33
+ badges: [{ label: input.mandatory ? t.required : t.optional }],
34
+ card: true,
35
+ actions: input.mandatory ? undefined : [{ type: 'command', appearance: 'primary', title: t.skip, exec: '/skip' }],
36
+ updated: new Date().toISOString(),
37
+ })
38
+ }
39
+
40
+ answer(value: string) {
41
+ this.value[this.inputs[this.index].slug] = value
42
+ this.skip()
43
+ }
44
+
45
+ skip() {
46
+ this.index++
47
+ if (this.hasFinished()) this.resolve?.(this.value)
48
+ }
49
+
50
+ hasFinished() {
51
+ return this.index === this.inputs.length
52
+ }
53
+
54
+ getValue() {
55
+ return this.promise
56
+ }
57
+ }
58
+
59
+ const dictionary = {
60
+ en: {
61
+ required: 'Required information',
62
+ optional: 'Optional information',
63
+ skip: 'Skip',
64
+ },
65
+ pt: {
66
+ required: 'Informação obrigatória',
67
+ optional: 'Informação opcional',
68
+ skip: 'Pular',
69
+ },
70
+ } satisfies Dictionary
@@ -0,0 +1,15 @@
1
+ import { ChatEntry } from '../state/ChatEntry'
2
+ import { ChatState } from '../state/ChatState'
3
+ import { CUSTOM_INPUTS_KEY } from './CustomInputs'
4
+
5
+ export function quickCommandQuestionsInterceptor(entry: ChatEntry, chat: ChatState) {
6
+ const { agentType, content } = entry.getValue()
7
+ if (agentType !== 'user') return
8
+ const customInputs = chat.interceptorMemory.get(CUSTOM_INPUTS_KEY)
9
+ if (!customInputs) return
10
+ if (content === '/skip') customInputs.skip()
11
+ else customInputs.answer(content)
12
+ if (!customInputs.hasFinished()) chat.pushMessage(customInputs.ask())
13
+ // prevents next interceptors from running
14
+ return false
15
+ }
@@ -1,12 +1,274 @@
1
+ import { aiClient, CancelledError, FixedChatRequest, StackspotAPIError } from '@stack-spot/portal-network'
2
+ import { QuickCommandFetchResponseResult, QuickCommandPromptResponse2, QuickCommandResponse } from '@stack-spot/portal-network/api/ai'
3
+ import { Dictionary, interpolate, translate } from '@stack-spot/portal-translate'
4
+ import type { editor } from 'monaco-editor'
5
+ import { ulid } from 'ulid'
6
+ import { AbortedError } from '../AbortedError'
1
7
  import { ChatEntry } from '../state/ChatEntry'
2
8
  import { ChatState } from '../state/ChatState'
9
+ import { LabeledWithImage } from '../state/types'
10
+ import { WidgetState } from '../state/WidgetState'
11
+ import { buildConversationContext } from '../utils/chat'
12
+ import { getSizeOfString } from '../utils/string'
13
+ import { CUSTOM_INPUTS_KEY, CustomInputs } from './CustomInputs'
3
14
 
4
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
5
- export function quickCommandInterceptor(entry: ChatEntry, _chat: ChatState) {
6
- const { agentType, content } = entry.getValue()
7
- if (agentType !== 'user') return
8
- if (content.startsWith('/')) {
9
- alert('Quick commands are not yet supported!') /* todo */
10
- return false // by returning false, the next interceptor are not run. i.e. the message is not sent to the AI agent.
15
+ type SlugExecution = Record<string, string | QuickCommandFetchResponseResult | QuickCommandPromptResponse2>
16
+
17
+ interface QCContext {
18
+ qc: QuickCommandResponse,
19
+ context: Required<FixedChatRequest>['context'],
20
+ resultMap: SlugExecution,
21
+ chat: ChatState,
22
+ code?: string,
23
+ executionId: string,
24
+ signal: AbortSignal,
25
+ }
26
+
27
+ const commandRegex = /^\/[\w\d-_]+$/
28
+ const progressMessageDelayMS = 1000
29
+
30
+ export function createQuickCommandInterceptor(widget: WidgetState, getEditor: () => typeof editor | undefined) {
31
+ async function computeCustomInputs(ctx: QCContext) {
32
+ const { chat, qc: { custom_inputs: inputs, name, slug } } = ctx
33
+ if (!inputs?.length) return
34
+ chat.set('isLoading', false)
35
+ const t = translate(dictionary)
36
+ const customInputs = new CustomInputs(inputs, chat.get('agent'))
37
+ chat.interceptorMemory.set(CUSTOM_INPUTS_KEY, customInputs)
38
+ chat.pushMessage(new ChatEntry({
39
+ agentType: 'bot',
40
+ type: 'text',
41
+ content: interpolate(t.startQuestioning, name || slug),
42
+ }))
43
+ chat.pushMessage(customInputs.ask())
44
+ const inputsValues = await customInputs.getValue()
45
+ chat.set('isLoading', true)
46
+ chat.interceptorMemory.delete(CUSTOM_INPUTS_KEY)
47
+ ctx.resultMap = { ...ctx.resultMap, ...inputsValues }
48
+ }
49
+
50
+ async function runFetchStep(ctx: QCContext, stepIndex: number) {
51
+ const { qc: { slug, steps }, code, context, resultMap, executionId, signal } = ctx
52
+ const step = steps![stepIndex]
53
+ const { headers, data, method, url } = await aiClient.fetchStepOfQuickCommand.mutate({
54
+ slug,
55
+ stepSlug: step.slug,
56
+ quickCommandsExecutionRequest: { input_data: code, context, slugs_executions: resultMap, qc_execution_id: executionId },
57
+ }, signal)
58
+ const body = ['get', 'head'].includes(method.toLowerCase()) ? undefined : data
59
+ const response = await fetch(url, { headers: headers || undefined, body, method, signal })
60
+ if (!response.ok) throw new Error(`Failed to execute step "${step.slug}" of quick command "${slug}". Status ${response.status}.`)
61
+ resultMap[step.slug] = {
62
+ status: response.status,
63
+ data: await response.text(),
64
+ headers: Object.fromEntries(response.headers.entries()),
65
+ }
66
+ }
67
+
68
+ async function runLLMStep(
69
+ { qc: { slug, steps }, code, context, executionId, resultMap, signal }: QCContext,
70
+ stepIndex: number,
71
+ ) {
72
+ const step = steps![stepIndex]
73
+ resultMap[step.slug] = await aiClient.llmStepOfQuickCommand.mutate({
74
+ slug,
75
+ stepSlug: step.slug,
76
+ quickCommandsExecutionRequest: { input_data: code, context, qc_execution_id: executionId, slugs_executions: resultMap },
77
+ }, signal)
78
+ }
79
+
80
+ function updateProgressMessageForStep(message: ChatEntry, qc: QuickCommandResponse, stepIndex: number) {
81
+ const t = translate(dictionary)
82
+ message.setValue({
83
+ ...message.getValue(),
84
+ content: interpolate(t.progress, qc.name || qc.slug, stepIndex + 1, qc.steps?.[stepIndex]?.slug, qc.steps?.length),
85
+ updated: new Date().toISOString(),
86
+ })
87
+ }
88
+
89
+ function showProgressMessage(ctx: QCContext, message: ChatEntry) {
90
+ const result = {
91
+ removeProgressMessage: () => clearTimeout(timeout),
92
+ }
93
+ const timeout = window.setTimeout(() => {
94
+ const chat = ctx.chat
95
+ chat.pushMessage(message)
96
+ result.removeProgressMessage = () => chat.popMessage()
97
+ }, progressMessageDelayMS)
98
+ return result
99
+ }
100
+
101
+ function createProgressMessage(agent?: LabeledWithImage) {
102
+ return new ChatEntry({
103
+ agentType: 'bot',
104
+ content: '',
105
+ type: 'text',
106
+ agent,
107
+ updated: new Date().toISOString(),
108
+ })
109
+ }
110
+
111
+ async function runSteps(ctx: QCContext) {
112
+ const { qc, chat } = ctx
113
+ const progress = createProgressMessage(chat.get('agent'))
114
+ const { removeProgressMessage } = showProgressMessage(ctx, progress)
115
+ try {
116
+ for (let i = 0; i < (qc.steps?.length ?? 0); i++) {
117
+ updateProgressMessageForStep(progress, qc, i)
118
+ await (qc.steps?.[i].type === 'FETCH' ? runFetchStep(ctx, i) : runLLMStep(ctx, i))
119
+ }
120
+ } finally {
121
+ removeProgressMessage()
122
+ }
123
+ }
124
+
125
+ async function formatResult({ qc, code, executionId, context, resultMap, signal }: QCContext) {
126
+ const formatted = await aiClient.formatResultOfQuickCommand.mutate({
127
+ slug: qc.slug,
128
+ quickCommandsExecutionRequest: {
129
+ input_data: code,
130
+ context,
131
+ qc_execution_id: executionId,
132
+ slugs_executions: resultMap,
133
+ },
134
+ }, signal)
135
+ return formatted.result
136
+ }
137
+
138
+ // opens a new chat tab if the quick command doesn't preserve the conversation and the current conversation isn't clean.
139
+ function manageConversationContext(ctx: QCContext) {
140
+ if (!ctx.qc.preserve_conversation && ctx.chat.getMessages().length > 1) {
141
+ if (ctx.qc.return_type === 'CHAT') {
142
+ ctx.chat.set('isLoading', false)
143
+ ctx.chat = ctx.chat.transferToNewChat(ctx.qc.name || ctx.qc.slug)
144
+ ctx.chat.set('isLoading', true)
145
+ widget.chatTabs.add(ctx.chat)
146
+ widget.chatTabs.select(ctx.chat.id)
147
+ ctx.context.conversation_id = ctx.chat.id
148
+ } else {
149
+ ctx.context.conversation_id = ulid()
150
+ }
151
+ }
152
+ }
153
+
154
+ async function runQuickCommand(ctx: QCContext) {
155
+ const { qc: { slug }, code } = ctx
156
+ const t = translate(dictionary)
157
+ ctx.signal.addEventListener('abort', () => aiClient.quickCommand.cancel({ slug }))
158
+ await aiClient.quickCommand.invalidate({ slug })
159
+ try {
160
+ ctx.qc = await aiClient.quickCommand.query({ slug })
161
+ } catch (error) {
162
+ throw error instanceof StackspotAPIError && error.status === 404 ? new Error(t.notFound) : error
163
+ }
164
+ if (ctx.qc.use_selected_code && !code) {
165
+ throw new Error(t.requiresSelection)
166
+ }
167
+ manageConversationContext(ctx)
168
+ await computeCustomInputs(ctx)
169
+ await runSteps(ctx)
170
+ return formatResult(ctx)
11
171
  }
172
+
173
+ async function registerAnalyticsEvent({ qc, executionId, code = '', context }: QCContext, status: string, start: number) {
174
+ const now = new Date().getTime()
175
+ try {
176
+ await aiClient.createEvent.mutate({
177
+ body: [{
178
+ type: 'custom_quick_command_execution',
179
+ quick_command_event: {
180
+ type: qc.type || '',
181
+ duration_execution: now - start,
182
+ status_execution: status,
183
+ slug: qc.slug,
184
+ qc_execution_id: executionId,
185
+ id: qc.id,
186
+ },
187
+ code,
188
+ context,
189
+ knowledge_sources: [],
190
+ size: getSizeOfString(code),
191
+ generated_at: now,
192
+ }],
193
+ })
194
+ } catch (error) {
195
+ // eslint-disable-next-line no-console
196
+ console.warn('Failed to register event: quick command.')
197
+ }
198
+ }
199
+
200
+ function outputResult({ qc, chat, code }: QCContext, result: string) {
201
+ if (qc.return_type === 'CHAT') {
202
+ chat.pushMessage(new ChatEntry({
203
+ agentType: 'bot',
204
+ content: result,
205
+ agent: chat.get('agent'),
206
+ type: 'md',
207
+ }))
208
+ } else {
209
+ const editor = getEditor()?.getEditors()[0]
210
+ let finalCode = result
211
+ if (qc.return_type === 'BEFORE_CODE') finalCode = `${result}\n${code}`
212
+ else if (qc.return_type === 'AFTER_CODE') finalCode = `${code}\n${result}`
213
+ finalCode = finalCode.replace(/(\$[{a-z]|\})/g, '\\$1')
214
+ editor?.trigger('keyboard', 'type', { text: finalCode })
215
+ }
216
+ }
217
+
218
+ async function quickCommandInterceptor(entry: ChatEntry, chat: ChatState, signal: AbortSignal) {
219
+ const { agentType, content } = entry.getValue()
220
+ if (agentType !== 'user' || !commandRegex.test(content.trim())) return
221
+ const t = translate(dictionary)
222
+ const slug = content.trim().substring(1)
223
+ const ctx: QCContext = {
224
+ qc: { slug } as QuickCommandResponse,
225
+ chat,
226
+ code: chat.get('codeSelection'),
227
+ context: buildConversationContext(chat) ?? {},
228
+ executionId: ulid(),
229
+ resultMap: {},
230
+ signal,
231
+ }
232
+ chat.set('isLoading', true)
233
+ const start = new Date().getTime()
234
+ try {
235
+ const result = await runQuickCommand(ctx)
236
+ outputResult(ctx, result)
237
+ registerAnalyticsEvent(ctx, '200', start)
238
+ } catch (error: any) {
239
+ let message = error.message || `${error}`
240
+ if (error instanceof AbortedError || error instanceof CancelledError) message = t.aborted
241
+ else if (error instanceof StackspotAPIError) message = error.translate()
242
+ ctx.chat.pushMessage(new ChatEntry({
243
+ agentType: 'bot',
244
+ content: '',
245
+ error: message,
246
+ agent: chat.get('agent'),
247
+ type: 'text',
248
+ }))
249
+ registerAnalyticsEvent(ctx, message, start)
250
+ }
251
+ ctx.chat.set('isLoading', false)
252
+ // prevents the next interceptors from running
253
+ return false
254
+ }
255
+
256
+ return quickCommandInterceptor
12
257
  }
258
+
259
+ const dictionary = {
260
+ en: {
261
+ requiresSelection: 'This quick command requires some code to be selected in the editor.',
262
+ startQuestioning: 'To execute the Quick Command "$0", I\'ll need you to provide some information. Some may be mandatory, and others optional. Let\'s get started.',
263
+ progress: 'Running quick command "$0". Step $1 ($2) of $3.',
264
+ aborted: 'The quick command execution aborted by the user.',
265
+ notFound: 'There\'s no quick command with the provided name. If you don\'t wish to run a command, prefix the first "/" with a "\\".',
266
+ },
267
+ pt: {
268
+ requiresSelection: 'Este quick command precisa que algum código esteja selecionado no editor.',
269
+ startQuestioning: 'Para executar o Quick Command "$0", vou precisar que você providencie algumas explicações. Algumas são obrigatórias e outras opcionais. Vamos começar.',
270
+ progress: 'Executando quick command "$0". Passo $1 ($2) de $3.',
271
+ aborted: 'A execução do quick command foi abortada pelo usuário.',
272
+ notFound: 'Não existe quick command com o nome providenciado. Se você não quiser rodar um comando, prefixe o primeiro "/" com um "\\".',
273
+ },
274
+ } satisfies Dictionary
@@ -4,15 +4,16 @@ import { ChatState } from '../state/ChatState'
4
4
  import { buildConversationContext } from '../utils/chat'
5
5
  import { genericSourcesToKnowledgeSources } from '../utils/knowledge-source'
6
6
 
7
- export async function sendMessageInterceptor(entry: ChatEntry, chat: ChatState) {
7
+ export async function sendMessageInterceptor(entry: ChatEntry, chat: ChatState, signal: AbortSignal) {
8
8
  const { agentType, content } = entry.getValue()
9
9
  if (agentType !== 'user') return
10
10
  const context = buildConversationContext(chat)
11
11
  chat.set('isLoading', true)
12
12
  const isFirstMessage = chat.getMessages().length === 1
13
13
  if (isFirstMessage) chat.set('label', content)
14
- const stream = aiClient.sendChatMessage({ context, user_prompt: content })
15
- const botEntry = ChatEntry.createStreamedBotEntry(() => stream.cancel())
14
+ const stream = aiClient.sendChatMessage({ context, user_prompt: content.replace(/^\s*\\(\\|\/)/, '$1') })
15
+ signal.addEventListener('abort', () => stream.cancel())
16
+ const botEntry = ChatEntry.createStreamedBotEntry()
16
17
  chat.pushMessage(botEntry)
17
18
  let knowledgeSources: KnowledgeSource[] | undefined
18
19
  stream.onChange(value => {
@@ -39,6 +40,5 @@ export async function sendMessageInterceptor(entry: ChatEntry, chat: ChatState)
39
40
  error: error instanceof StackspotAPIError ? error.translate() : (error.message ?? `${error}`),
40
41
  })
41
42
  }
42
- botEntry.finish()
43
43
  chat.set('isLoading', false)
44
44
  }