@stack-spot/ai-chat-widget 0.10.0 → 1.0.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 (181) 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 +250 -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 +18 -14
  23. package/dist/chat-interceptors/send-message.js.map +1 -1
  24. package/dist/components/AdaptiveTextArea.d.ts +1 -1
  25. package/dist/components/AdaptiveTextArea.d.ts.map +1 -1
  26. package/dist/components/AdaptiveTextArea.js +6 -4
  27. package/dist/components/AdaptiveTextArea.js.map +1 -1
  28. package/dist/components/AutoFocus.d.ts +6 -0
  29. package/dist/components/AutoFocus.d.ts.map +1 -0
  30. package/dist/components/AutoFocus.js +15 -0
  31. package/dist/components/AutoFocus.js.map +1 -0
  32. package/dist/components/Fading.d.ts +15 -0
  33. package/dist/components/Fading.d.ts.map +1 -0
  34. package/dist/components/Fading.js +31 -0
  35. package/dist/components/Fading.js.map +1 -0
  36. package/dist/components/FallbackBoundary/ErrorBoundary.d.ts +3 -0
  37. package/dist/components/FallbackBoundary/ErrorBoundary.d.ts.map +1 -1
  38. package/dist/components/FallbackBoundary/ErrorBoundary.js +18 -4
  39. package/dist/components/FallbackBoundary/ErrorBoundary.js.map +1 -1
  40. package/dist/components/FallbackBoundary/Loading.js +1 -1
  41. package/dist/components/FallbackBoundary/Loading.js.map +1 -1
  42. package/dist/components/FallbackBoundary/index.d.ts +6 -1
  43. package/dist/components/FallbackBoundary/index.d.ts.map +1 -1
  44. package/dist/components/FallbackBoundary/index.js +1 -1
  45. package/dist/components/FallbackBoundary/index.js.map +1 -1
  46. package/dist/components/OverlayMenu.d.ts +1 -1
  47. package/dist/components/OverlayMenu.d.ts.map +1 -1
  48. package/dist/components/OverlayMenu.js +26 -9
  49. package/dist/components/OverlayMenu.js.map +1 -1
  50. package/dist/components/RightPanelForm.d.ts.map +1 -1
  51. package/dist/components/RightPanelForm.js +5 -4
  52. package/dist/components/RightPanelForm.js.map +1 -1
  53. package/dist/components/Tooltip/Tooltip.d.ts +3 -1
  54. package/dist/components/Tooltip/Tooltip.d.ts.map +1 -1
  55. package/dist/components/Tooltip/Tooltip.js +14 -5
  56. package/dist/components/Tooltip/Tooltip.js.map +1 -1
  57. package/dist/components/Tooltip/TooltipAPI.d.ts +2 -2
  58. package/dist/components/Tooltip/TooltipAPI.d.ts.map +1 -1
  59. package/dist/components/Tooltip/TooltipAPI.js +51 -51
  60. package/dist/components/Tooltip/TooltipAPI.js.map +1 -1
  61. package/dist/layout.css +5 -0
  62. package/dist/regex.d.ts +2 -0
  63. package/dist/regex.d.ts.map +1 -0
  64. package/dist/regex.js +2 -0
  65. package/dist/regex.js.map +1 -0
  66. package/dist/right-panel/DefaultPanel.d.ts.map +1 -1
  67. package/dist/right-panel/DefaultPanel.js +3 -1
  68. package/dist/right-panel/DefaultPanel.js.map +1 -1
  69. package/dist/right-panel/constants.d.ts +2 -0
  70. package/dist/right-panel/constants.d.ts.map +1 -0
  71. package/dist/right-panel/constants.js +2 -0
  72. package/dist/right-panel/constants.js.map +1 -0
  73. package/dist/right-panel/hooks.d.ts.map +1 -1
  74. package/dist/right-panel/hooks.js +2 -1
  75. package/dist/right-panel/hooks.js.map +1 -1
  76. package/dist/state/ChatEntry.d.ts +8 -8
  77. package/dist/state/ChatEntry.d.ts.map +1 -1
  78. package/dist/state/ChatEntry.js +4 -16
  79. package/dist/state/ChatEntry.js.map +1 -1
  80. package/dist/state/ChatState.d.ts +13 -1
  81. package/dist/state/ChatState.d.ts.map +1 -1
  82. package/dist/state/ChatState.js +38 -3
  83. package/dist/state/ChatState.js.map +1 -1
  84. package/dist/state/ObservableState.d.ts +1 -1
  85. package/dist/state/ObservableState.d.ts.map +1 -1
  86. package/dist/state/ObservableState.js.map +1 -1
  87. package/dist/utils/chat.d.ts.map +1 -1
  88. package/dist/utils/chat.js +3 -2
  89. package/dist/utils/chat.js.map +1 -1
  90. package/dist/utils/knowledge-source.d.ts +2 -2
  91. package/dist/utils/knowledge-source.d.ts.map +1 -1
  92. package/dist/utils/knowledge-source.js +4 -6
  93. package/dist/utils/knowledge-source.js.map +1 -1
  94. package/dist/utils/programming-languages.d.ts +1 -0
  95. package/dist/utils/programming-languages.d.ts.map +1 -1
  96. package/dist/utils/programming-languages.js +1 -0
  97. package/dist/utils/programming-languages.js.map +1 -1
  98. package/dist/utils/string.d.ts +2 -0
  99. package/dist/utils/string.d.ts.map +1 -0
  100. package/dist/utils/string.js +7 -0
  101. package/dist/utils/string.js.map +1 -0
  102. package/dist/utils/url.d.ts +2 -0
  103. package/dist/utils/url.d.ts.map +1 -0
  104. package/dist/utils/url.js +8 -0
  105. package/dist/utils/url.js.map +1 -0
  106. package/dist/views/Chat/ChatMessage.d.ts +2 -1
  107. package/dist/views/Chat/ChatMessage.d.ts.map +1 -1
  108. package/dist/views/Chat/ChatMessage.js +38 -5
  109. package/dist/views/Chat/ChatMessage.js.map +1 -1
  110. package/dist/views/Chat/ChatMessages.d.ts.map +1 -1
  111. package/dist/views/Chat/ChatMessages.js +1 -1
  112. package/dist/views/Chat/ChatMessages.js.map +1 -1
  113. package/dist/views/Chat/styled.d.ts.map +1 -1
  114. package/dist/views/Chat/styled.js +31 -0
  115. package/dist/views/Chat/styled.js.map +1 -1
  116. package/dist/views/ChatHistory/ChatHistoryPanel.d.ts.map +1 -1
  117. package/dist/views/ChatHistory/ChatHistoryPanel.js +2 -1
  118. package/dist/views/ChatHistory/ChatHistoryPanel.js.map +1 -1
  119. package/dist/views/ChatHistory/HistoryItem.d.ts.map +1 -1
  120. package/dist/views/ChatHistory/HistoryItem.js +10 -1
  121. package/dist/views/ChatHistory/HistoryItem.js.map +1 -1
  122. package/dist/views/Editor.d.ts.map +1 -1
  123. package/dist/views/Editor.js +3 -4
  124. package/dist/views/Editor.js.map +1 -1
  125. package/dist/views/MessageInput/ButtonGroup.d.ts +1 -1
  126. package/dist/views/MessageInput/ButtonGroup.d.ts.map +1 -1
  127. package/dist/views/MessageInput/QuickCommandSelector.d.ts +6 -0
  128. package/dist/views/MessageInput/QuickCommandSelector.d.ts.map +1 -0
  129. package/dist/views/MessageInput/QuickCommandSelector.js +137 -0
  130. package/dist/views/MessageInput/QuickCommandSelector.js.map +1 -0
  131. package/dist/views/MessageInput/index.d.ts.map +1 -1
  132. package/dist/views/MessageInput/index.js +10 -4
  133. package/dist/views/MessageInput/index.js.map +1 -1
  134. package/dist/views/MessageInput/styled.d.ts.map +1 -1
  135. package/dist/views/MessageInput/styled.js +137 -0
  136. package/dist/views/MessageInput/styled.js.map +1 -1
  137. package/package.json +3 -3
  138. package/src/AbortedError.ts +7 -0
  139. package/src/StackspotAIWidget.tsx +13 -3
  140. package/src/chat-interceptors/CustomInputs.ts +70 -0
  141. package/src/chat-interceptors/quick-command-questions.ts +15 -0
  142. package/src/chat-interceptors/quick-commands.ts +270 -7
  143. package/src/chat-interceptors/send-message.ts +27 -15
  144. package/src/components/AdaptiveTextArea.tsx +9 -4
  145. package/src/components/AutoFocus.tsx +20 -0
  146. package/src/components/Fading.tsx +46 -0
  147. package/src/components/FallbackBoundary/ErrorBoundary.tsx +26 -3
  148. package/src/components/FallbackBoundary/Loading.tsx +1 -1
  149. package/src/components/FallbackBoundary/index.tsx +7 -2
  150. package/src/components/OverlayMenu.tsx +59 -19
  151. package/src/components/RightPanelForm.tsx +12 -9
  152. package/src/components/Tooltip/Tooltip.tsx +24 -5
  153. package/src/components/Tooltip/TooltipAPI.ts +42 -42
  154. package/src/layout.css +5 -0
  155. package/src/regex.ts +1 -0
  156. package/src/right-panel/DefaultPanel.tsx +14 -9
  157. package/src/right-panel/constants.ts +1 -0
  158. package/src/right-panel/hooks.tsx +2 -1
  159. package/src/state/ChatEntry.ts +7 -20
  160. package/src/state/ChatState.ts +41 -3
  161. package/src/state/ObservableState.ts +1 -1
  162. package/src/utils/chat.ts +3 -2
  163. package/src/utils/knowledge-source.ts +6 -8
  164. package/src/utils/programming-languages.ts +2 -0
  165. package/src/utils/string.ts +6 -0
  166. package/src/utils/url.ts +8 -0
  167. package/src/views/Chat/ChatMessage.tsx +67 -13
  168. package/src/views/Chat/ChatMessages.tsx +4 -1
  169. package/src/views/Chat/styled.ts +31 -0
  170. package/src/views/ChatHistory/ChatHistoryPanel.tsx +3 -2
  171. package/src/views/ChatHistory/HistoryItem.tsx +11 -2
  172. package/src/views/Editor.tsx +3 -4
  173. package/src/views/MessageInput/ButtonGroup.tsx +1 -1
  174. package/src/views/MessageInput/QuickCommandSelector.tsx +210 -0
  175. package/src/views/MessageInput/index.tsx +12 -4
  176. package/src/views/MessageInput/styled.ts +137 -0
  177. package/dist/components/Editor.d.ts +0 -9
  178. package/dist/components/Editor.d.ts.map +0 -1
  179. package/dist/components/Editor.js +0 -2
  180. package/dist/components/Editor.js.map +0 -1
  181. package/src/components/Editor.tsx +0 -12
@@ -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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"}
@@ -1 +1 @@
1
- {"version":3,"file":"styled.d.ts","sourceRoot":"","sources":["../../../src/views/MessageInput/styled.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,gBAAgB,MAAM,CAAA;AACnC,eAAO,MAAM,gBAAgB,KAAK,CAAA;AAElC,eAAO,MAAM,eAAe,wOAkM3B,CAAA"}
1
+ {"version":3,"file":"styled.d.ts","sourceRoot":"","sources":["../../../src/views/MessageInput/styled.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,gBAAgB,MAAM,CAAA;AACnC,eAAO,MAAM,gBAAgB,KAAK,CAAA;AAElC,eAAO,MAAM,eAAe,wOA2U3B,CAAA"}
@@ -80,6 +80,7 @@ export const MessageInputBox = styled.div `
80
80
 
81
81
  .action-box {
82
82
  display: flex;
83
+ position: relative;
83
84
  flex-direction: row;
84
85
  gap: 4px;
85
86
  align-items: end;
@@ -199,5 +200,141 @@ export const MessageInputBox = styled.div `
199
200
  box-shadow: none;
200
201
  }
201
202
  }
203
+
204
+ .quick-command-selector {
205
+ position: absolute;
206
+ border-radius: 4px;
207
+ border: 1px solid ${theme.color.light[600]};
208
+ background-color: ${theme.color.light[500]};
209
+ box-shadow: 0px 2px 16px 0px #0000005C;
210
+ display: flex;
211
+ flex-direction: column;
212
+ width: 480px;
213
+ bottom: 55px;
214
+
215
+ .loading, .error {
216
+ padding-bottom: 26px;
217
+ p {
218
+ width: 200px;
219
+ text-align: center;
220
+ line-height: 20px;
221
+ }
222
+ }
223
+
224
+ .empty {
225
+ padding-bottom: 26px;
226
+ width: 200px;
227
+ text-align: center;
228
+ line-height: 20px;
229
+ margin: auto;
230
+ }
231
+
232
+ header {
233
+ display: flex;
234
+ flex-direction: row;
235
+ gap: 8px;
236
+ align-items: center;
237
+ padding: 8px;
238
+ font-family: 'San Francisco';
239
+ font-weight: 500;
240
+ font-size: 11px;
241
+ }
242
+
243
+ .body {
244
+ display: flex;
245
+ flex-direction: row;
246
+ align-items: center;
247
+ }
248
+
249
+ ul {
250
+ margin: 0;
251
+ padding: 0;
252
+ list-style: none;
253
+ }
254
+
255
+ ul.tabs {
256
+ display: flex;
257
+ flex-direction: column;
258
+
259
+ li {
260
+ display: flex;
261
+ flex-direction: column;
262
+ }
263
+
264
+ button {
265
+ box-sizing: border-box;
266
+ color: ${theme.color.light[700]};
267
+ text-align: left;
268
+ padding: 10px;
269
+ font-weight: 600;
270
+ font-size: 12px;
271
+ transition: background-color 0.3s;
272
+ border-top-right-radius: 4px;
273
+ border-bottom-right-radius: 4px;
274
+ background-color: transparent;
275
+ border: none;
276
+ cursor: pointer;
277
+ outline: none;
278
+
279
+ &:hover, &.active, &:focus {
280
+ background-color: ${theme.color.light[600]};
281
+ }
282
+
283
+ &.active {
284
+ border-left: 1px solid ${theme.color.light.contrastText};
285
+ color: ${theme.color.light.contrastText};
286
+ }
287
+ }
288
+ }
289
+
290
+ ul.command-list {
291
+ align-self: stretch;
292
+ display: flex;
293
+ flex-direction: column;
294
+ gap: 2px;
295
+ overflow-y: auto;
296
+ flex: 1;
297
+ max-height: 170px;
298
+
299
+ li {
300
+ display: flex;
301
+ flex-direction: row;
302
+ align-items: center;
303
+ gap: 8px;
304
+ padding: 8px;
305
+ border-radius: 4px;
306
+
307
+ &:hover, &.focus {
308
+ background-color: ${theme.color.light[600]};
309
+ }
310
+
311
+ button.qc {
312
+ flex: 1;
313
+ border: none;
314
+ text-align: left;
315
+ background-color: transparent;
316
+ text-align: left;
317
+ outline: none;
318
+ overflow: hidden;
319
+ cursor: pointer;
320
+
321
+ .qc-title {
322
+ font-size: 11px;
323
+ margin: 0 0 4px 0;
324
+ color: ${theme.color.light.contrastText};
325
+ text-transform: uppercase;
326
+ text-overflow: ellipsis;
327
+ overflow: hidden;
328
+ }
329
+
330
+ .qc-description {
331
+ color: ${theme.color.light[700]};
332
+ font-size: 12px;
333
+ margin: 0;
334
+ }
335
+ }
336
+ }
337
+ }
338
+ }
202
339
  `;
203
340
  //# sourceMappingURL=styled.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"styled.js","sourceRoot":"","sources":["../../../src/views/MessageInput/styled.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AACvC,OAAO,EAAE,KAAK,EAAE,MAAM,0BAA0B,CAAA;AAChD,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAA;AAE1C,MAAM,eAAe,GAAG,EAAE,CAAA;AAC1B,MAAM,qBAAqB,GAAG,CAAC,CAAA;AAC/B,MAAM,CAAC,MAAM,gBAAgB,GAAG,GAAG,CAAA;AACnC,MAAM,CAAC,MAAM,gBAAgB,GAAG,EAAE,CAAA;AAElC,MAAM,CAAC,MAAM,eAAe,GAAG,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;kBAWvB,eAAe,GAAG,qBAAqB;;;;;;;;;;;;;;;;gBAgBzC,eAAe;;0BAEL,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;UA4BtC,UAAU;;;;;;;;;;;;;;;;;;;;;;wBAsBI,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC;wBACtB,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC;;;;;sBAKxB,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC;;;;0BAIpB,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC;;;;;;;;;;;;;;;;;;;;gBAoBhC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC;;;;;;4BAMV,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC;;;;4BAItB,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC;;;;;kBAKlC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAmD5C,UAAU;;;;;;;;;;;cAWF,gBAAgB;;;;;;;;CAQ7B,CAAA"}
1
+ {"version":3,"file":"styled.js","sourceRoot":"","sources":["../../../src/views/MessageInput/styled.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AACvC,OAAO,EAAE,KAAK,EAAE,MAAM,0BAA0B,CAAA;AAChD,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAA;AAE1C,MAAM,eAAe,GAAG,EAAE,CAAA;AAC1B,MAAM,qBAAqB,GAAG,CAAC,CAAA;AAC/B,MAAM,CAAC,MAAM,gBAAgB,GAAG,GAAG,CAAA;AACnC,MAAM,CAAC,MAAM,gBAAgB,GAAG,EAAE,CAAA;AAElC,MAAM,CAAC,MAAM,eAAe,GAAG,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;kBAWvB,eAAe,GAAG,qBAAqB;;;;;;;;;;;;;;;;gBAgBzC,eAAe;;0BAEL,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;UA4BtC,UAAU;;;;;;;;;;;;;;;;;;;;;;;wBAuBI,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC;wBACtB,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC;;;;;sBAKxB,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC;;;;0BAIpB,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC;;;;;;;;;;;;;;;;;;;;gBAoBhC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC;;;;;;4BAMV,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC;;;;4BAItB,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC;;;;;kBAKlC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAmD5C,UAAU;;;;;;;;;;;cAWF,gBAAgB;;;;;;;;;;;;wBAYN,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC;wBACtB,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA0D7B,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC;;;;;;;;;;;;;;8BAcT,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC;;;;mCAIjB,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,YAAY;mBAC9C,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,YAAY;;;;;;;;;;;;;;;;;;;;;;;8BAuBnB,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC;;;;;;;;;;;;;;;;qBAgB/B,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,YAAY;;;;;;;qBAO9B,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC;;;;;;;;CAQ1C,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stack-spot/ai-chat-widget",
3
- "version": "0.10.0",
3
+ "version": "1.0.0",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -8,8 +8,8 @@
8
8
  "@citric/core": "^6.0.0",
9
9
  "@citric/icons": "^5.4.0 || ^6.0.0",
10
10
  "@citric/ui": "^5.4.0 || ^6.0.0",
11
- "@stack-spot/portal-components": "^2.6.1",
12
- "@stack-spot/portal-network": "^0.42.2",
11
+ "@stack-spot/portal-components": "^2.8.0",
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,275 @@
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'
7
+ import { quickCommandRegex } from '../regex'
1
8
  import { ChatEntry } from '../state/ChatEntry'
2
9
  import { ChatState } from '../state/ChatState'
10
+ import { LabeledWithImage } from '../state/types'
11
+ import { WidgetState } from '../state/WidgetState'
12
+ import { buildConversationContext } from '../utils/chat'
13
+ import { getSizeOfString } from '../utils/string'
14
+ import { CUSTOM_INPUTS_KEY, CustomInputs } from './CustomInputs'
3
15
 
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.
16
+ type SlugExecution = Record<string, string | QuickCommandFetchResponseResult | QuickCommandPromptResponse2>
17
+
18
+ interface QCContext {
19
+ qc: QuickCommandResponse,
20
+ context: Required<FixedChatRequest>['context'],
21
+ resultMap: SlugExecution,
22
+ chat: ChatState,
23
+ code?: string,
24
+ executionId: string,
25
+ signal: AbortSignal,
26
+ }
27
+
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
+ })
86
+ }
87
+
88
+ function createProgressMessage(agent?: LabeledWithImage) {
89
+ return new ChatEntry({
90
+ agentType: 'bot',
91
+ content: '',
92
+ type: 'text',
93
+ agent,
94
+ })
95
+ }
96
+
97
+ function showProgressMessage(ctx: QCContext) {
98
+ const showImmediately = ctx.qc.steps?.some(s => s.type === 'LLM')
99
+ const message = createProgressMessage(ctx.chat.get('agent'))
100
+ const controller = {
101
+ update: (index: number) => updateProgressMessageForStep(message, ctx.qc, index),
102
+ remove: () => clearTimeout(timeout),
103
+ }
104
+ const timeout = window.setTimeout(() => {
105
+ const chat = ctx.chat
106
+ chat.pushMessage(message)
107
+ controller.remove = () => chat.popMessage()
108
+ }, showImmediately ? 0 : progressMessageDelayMS)
109
+ return controller
110
+ }
111
+
112
+ async function runSteps(ctx: QCContext) {
113
+ const { qc } = ctx
114
+ const progress = showProgressMessage(ctx)
115
+ try {
116
+ for (let i = 0; i < (qc.steps?.length ?? 0); i++) {
117
+ progress.update(i)
118
+ await (qc.steps?.[i].type === 'FETCH' ? runFetchStep(ctx, i) : runLLMStep(ctx, i))
119
+ }
120
+ } finally {
121
+ progress.remove()
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
+ updated: new Date().toISOString(),
208
+ }))
209
+ } else {
210
+ const editor = getEditor()?.getEditors()[0]
211
+ let finalCode = result
212
+ if (qc.return_type === 'BEFORE_CODE') finalCode = `${result}\n${code}`
213
+ else if (qc.return_type === 'AFTER_CODE') finalCode = `${code}\n${result}`
214
+ finalCode = finalCode.replace(/(\$[{a-z]|\})/g, '\\$1')
215
+ editor?.trigger('keyboard', 'type', { text: finalCode })
216
+ }
217
+ }
218
+
219
+ async function quickCommandInterceptor(entry: ChatEntry, chat: ChatState, signal: AbortSignal) {
220
+ const { agentType, content } = entry.getValue()
221
+ if (agentType !== 'user' || !quickCommandRegex.test(content.trim())) return
222
+ const t = translate(dictionary)
223
+ const slug = content.trim().substring(1)
224
+ const ctx: QCContext = {
225
+ qc: { slug } as QuickCommandResponse,
226
+ chat,
227
+ code: chat.get('codeSelection'),
228
+ context: buildConversationContext(chat) ?? {},
229
+ executionId: ulid(),
230
+ resultMap: {},
231
+ signal,
232
+ }
233
+ chat.set('isLoading', true)
234
+ const start = new Date().getTime()
235
+ try {
236
+ const result = await runQuickCommand(ctx)
237
+ outputResult(ctx, result)
238
+ registerAnalyticsEvent(ctx, '200', start)
239
+ } catch (error: any) {
240
+ let message = error.message || `${error}`
241
+ if (error instanceof AbortedError || error instanceof CancelledError) message = t.aborted
242
+ else if (error instanceof StackspotAPIError) message = error.translate()
243
+ ctx.chat.pushMessage(new ChatEntry({
244
+ agentType: 'bot',
245
+ content: '',
246
+ error: message,
247
+ agent: chat.get('agent'),
248
+ type: 'text',
249
+ }))
250
+ registerAnalyticsEvent(ctx, message, start)
251
+ }
252
+ ctx.chat.set('isLoading', false)
253
+ // prevents the next interceptors from running
254
+ return false
255
+ }
256
+
257
+ return quickCommandInterceptor
12
258
  }
259
+
260
+ const dictionary = {
261
+ en: {
262
+ requiresSelection: 'This quick command requires some code to be selected in the editor. To open the editor click the icon "{/}" in the field below.',
263
+ 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.',
264
+ progress: 'Running quick command "$0". Step $1 ($2) of $3.',
265
+ aborted: 'The quick command execution aborted by the user.',
266
+ notFound: 'There\'s no quick command with the provided name. If you don\'t wish to run a command, prefix the first "/" with a "\\".',
267
+ },
268
+ pt: {
269
+ requiresSelection: 'Este quick command precisa que algum código esteja selecionado no editor. Para abrir o editor clique no ícone "{/}" no campo abaixo.',
270
+ 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.',
271
+ progress: 'Executando quick command "$0". Passo $1 ($2) de $3.',
272
+ aborted: 'A execução do quick command foi abortada pelo usuário.',
273
+ notFound: 'Não existe quick command com o nome providenciado. Se você não quiser rodar um comando, prefixe o primeiro "/" com um "\\".',
274
+ },
275
+ } satisfies Dictionary
@@ -1,36 +1,49 @@
1
1
  import { aiClient, StackspotAPIError } from '@stack-spot/portal-network'
2
- import { ChatEntry, KnowledgeSource } from '../state/ChatEntry'
2
+ import { ChatResponse3 } from '@stack-spot/portal-network/api/ai'
3
+ import { ChatEntry, KnowledgeSource, TextChatEntry } from '../state/ChatEntry'
3
4
  import { ChatState } from '../state/ChatState'
5
+ import { LabeledWithImage } from '../state/types'
4
6
  import { buildConversationContext } from '../utils/chat'
5
7
  import { genericSourcesToKnowledgeSources } from '../utils/knowledge-source'
6
8
 
7
- export async function sendMessageInterceptor(entry: ChatEntry, chat: ChatState) {
9
+ function createEntryValueFromChatResponse(
10
+ response: Partial<ChatResponse3>,
11
+ knowledgeSources: KnowledgeSource[] | undefined,
12
+ agent: LabeledWithImage | undefined,
13
+ includeDate = false,
14
+ ): TextChatEntry {
15
+ return {
16
+ agentType: 'bot',
17
+ type: 'md',
18
+ content: response.answer ?? '',
19
+ messageId: response.message_id ?? undefined,
20
+ knowledgeSources,
21
+ agent: agent,
22
+ updated: includeDate ? new Date().toISOString() : undefined,
23
+ }
24
+ }
25
+
26
+ export async function sendMessageInterceptor(entry: ChatEntry, chat: ChatState, signal: AbortSignal) {
8
27
  const { agentType, content } = entry.getValue()
9
28
  if (agentType !== 'user') return
10
29
  const context = buildConversationContext(chat)
11
30
  chat.set('isLoading', true)
12
31
  const isFirstMessage = chat.getMessages().length === 1
13
32
  if (isFirstMessage) chat.set('label', content)
14
- const stream = aiClient.sendChatMessage({ context, user_prompt: content })
15
- const botEntry = ChatEntry.createStreamedBotEntry(() => stream.cancel())
33
+ const stream = aiClient.sendChatMessage({ context, user_prompt: content.replace(/^\s*\\(\\|\/)/, '$1') })
34
+ signal.addEventListener('abort', () => stream.cancel())
35
+ const botEntry = ChatEntry.createStreamedBotEntry()
16
36
  chat.pushMessage(botEntry)
17
37
  let knowledgeSources: KnowledgeSource[] | undefined
18
38
  stream.onChange(value => {
19
39
  if (value.sources?.length !== knowledgeSources?.length) {
20
40
  knowledgeSources = genericSourcesToKnowledgeSources(value.sources)
21
41
  }
22
- botEntry.setValue({
23
- agentType: 'bot',
24
- type: 'md',
25
- content: value.answer ?? '',
26
- messageId: value.message_id ?? undefined,
27
- knowledgeSources,
28
- updated: new Date().toISOString(),
29
- agent: chat.get('agent'),
30
- })
42
+ botEntry.setValue(createEntryValueFromChatResponse(value, knowledgeSources, chat.get('agent')))
31
43
  })
32
44
  try {
33
- await stream.getValue()
45
+ const finalValue = await stream.getValue()
46
+ botEntry.setValue(createEntryValueFromChatResponse(finalValue, knowledgeSources, chat.get('agent'), true))
34
47
  aiClient.chat.invalidate({ conversationId: chat.id })
35
48
  if (isFirstMessage) aiClient.chats.invalidate()
36
49
  } catch (error: any) {
@@ -39,6 +52,5 @@ export async function sendMessageInterceptor(entry: ChatEntry, chat: ChatState)
39
52
  error: error instanceof StackspotAPIError ? error.translate() : (error.message ?? `${error}`),
40
53
  })
41
54
  }
42
- botEntry.finish()
43
55
  chat.set('isLoading', false)
44
56
  }