@rimori/client 1.3.1 → 1.4.3

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 (148) hide show
  1. package/.prettierignore +35 -0
  2. package/README.md +77 -71
  3. package/dist/cli/scripts/init/dev-registration.d.ts +1 -1
  4. package/dist/cli/scripts/init/dev-registration.js +4 -4
  5. package/dist/cli/scripts/init/main.js +1 -1
  6. package/dist/cli/scripts/init/package-setup.d.ts +1 -1
  7. package/dist/cli/scripts/init/package-setup.js +3 -3
  8. package/dist/cli/scripts/init/router-transformer.js +19 -12
  9. package/dist/cli/scripts/init/vite-config.d.ts +2 -2
  10. package/dist/cli/scripts/init/vite-config.js +2 -2
  11. package/dist/cli/scripts/release/release-config-upload.js +9 -9
  12. package/dist/cli/scripts/release/release-db-update.d.ts +1 -1
  13. package/dist/cli/scripts/release/release-db-update.js +9 -9
  14. package/dist/cli/scripts/release/release-file-upload.js +2 -2
  15. package/dist/cli/scripts/release/release.js +2 -2
  16. package/dist/cli/types/DatabaseTypes.d.ts +2 -2
  17. package/dist/components/CRUDModal.d.ts +1 -1
  18. package/dist/components/CRUDModal.js +3 -3
  19. package/dist/components/MarkdownEditor.js +16 -16
  20. package/dist/components/Spinner.js +2 -2
  21. package/dist/components/ai/Assistant.js +7 -8
  22. package/dist/components/ai/Avatar.d.ts +2 -2
  23. package/dist/components/ai/Avatar.js +14 -7
  24. package/dist/components/ai/EmbeddedAssistent/AudioInputField.js +5 -6
  25. package/dist/components/ai/EmbeddedAssistent/CircleAudioAvatar.d.ts +1 -1
  26. package/dist/components/ai/EmbeddedAssistent/CircleAudioAvatar.js +1 -2
  27. package/dist/components/ai/EmbeddedAssistent/TTS/MessageSender.d.ts +1 -2
  28. package/dist/components/ai/EmbeddedAssistent/TTS/MessageSender.js +4 -2
  29. package/dist/components/ai/EmbeddedAssistent/TTS/Player.js +1 -1
  30. package/dist/components/ai/EmbeddedAssistent/VoiceRecoder.js +2 -3
  31. package/dist/components/audio/Playbutton.js +10 -7
  32. package/dist/components/components/ContextMenu.d.ts +1 -1
  33. package/dist/components/components/ContextMenu.js +19 -16
  34. package/dist/components.d.ts +10 -10
  35. package/dist/components.js +10 -10
  36. package/dist/core/controller/AIController.d.ts +2 -2
  37. package/dist/core/controller/AIController.js +20 -18
  38. package/dist/core/controller/ExerciseController.d.ts +52 -0
  39. package/dist/core/controller/ExerciseController.js +73 -0
  40. package/dist/core/controller/ObjectController.js +5 -5
  41. package/dist/core/controller/SettingsController.d.ts +22 -7
  42. package/dist/core/controller/SettingsController.js +73 -8
  43. package/dist/core/controller/SharedContentController.d.ts +3 -3
  44. package/dist/core/controller/SharedContentController.js +38 -20
  45. package/dist/core/controller/VoiceController.js +6 -4
  46. package/dist/core/core.d.ts +15 -14
  47. package/dist/core/core.js +7 -7
  48. package/dist/fromRimori/EventBus.js +23 -23
  49. package/dist/fromRimori/PluginTypes.d.ts +4 -4
  50. package/dist/hooks/UseChatHook.d.ts +3 -3
  51. package/dist/hooks/UseChatHook.js +9 -3
  52. package/dist/index.d.ts +10 -10
  53. package/dist/index.js +9 -9
  54. package/dist/plugin/AccomplishmentHandler.d.ts +5 -5
  55. package/dist/plugin/AccomplishmentHandler.js +31 -27
  56. package/dist/plugin/AudioController.d.ts +1 -1
  57. package/dist/plugin/AudioController.js +6 -6
  58. package/dist/plugin/Logger.d.ts +5 -0
  59. package/dist/plugin/Logger.js +65 -13
  60. package/dist/plugin/PluginController.d.ts +7 -1
  61. package/dist/plugin/PluginController.js +32 -27
  62. package/dist/plugin/RimoriClient.d.ts +39 -14
  63. package/dist/plugin/RimoriClient.js +60 -31
  64. package/dist/plugin/StandaloneClient.d.ts +1 -1
  65. package/dist/plugin/StandaloneClient.js +35 -16
  66. package/dist/plugin/ThemeSetter.js +4 -4
  67. package/dist/providers/PluginProvider.js +44 -14
  68. package/dist/utils/Language.js +57 -57
  69. package/dist/utils/PluginUtils.js +3 -3
  70. package/dist/utils/difficultyConverter.d.ts +1 -1
  71. package/dist/utils/difficultyConverter.js +1 -1
  72. package/dist/utils/endpoint.js +2 -2
  73. package/dist/worker/WorkerSetup.d.ts +1 -1
  74. package/dist/worker/WorkerSetup.js +6 -6
  75. package/eslint.config.js +53 -0
  76. package/example/docs/devdocs.md +50 -40
  77. package/example/docs/overview.md +1 -1
  78. package/example/docs/userdocs.md +4 -1
  79. package/example/rimori.config.ts +51 -49
  80. package/example/worker/vite.config.ts +3 -3
  81. package/example/worker/worker.ts +2 -2
  82. package/package.json +17 -4
  83. package/prettier.config.js +8 -0
  84. package/src/cli/scripts/init/dev-registration.ts +5 -8
  85. package/src/cli/scripts/init/env-setup.ts +1 -1
  86. package/src/cli/scripts/init/file-operations.ts +1 -1
  87. package/src/cli/scripts/init/html-cleaner.ts +2 -5
  88. package/src/cli/scripts/init/main.ts +16 -13
  89. package/src/cli/scripts/init/package-setup.ts +11 -15
  90. package/src/cli/scripts/init/router-transformer.ts +40 -37
  91. package/src/cli/scripts/init/tailwind-config.ts +17 -26
  92. package/src/cli/scripts/init/vite-config.ts +3 -3
  93. package/src/cli/scripts/release/release-config-upload.ts +11 -11
  94. package/src/cli/scripts/release/release-db-update.ts +12 -12
  95. package/src/cli/scripts/release/release-file-upload.ts +3 -3
  96. package/src/cli/scripts/release/release.ts +4 -4
  97. package/src/cli/types/DatabaseTypes.ts +7 -8
  98. package/src/components/CRUDModal.tsx +64 -48
  99. package/src/components/MarkdownEditor.tsx +58 -27
  100. package/src/components/Spinner.tsx +24 -17
  101. package/src/components/ai/Assistant.tsx +70 -70
  102. package/src/components/ai/Avatar.tsx +20 -16
  103. package/src/components/ai/EmbeddedAssistent/AudioInputField.tsx +63 -54
  104. package/src/components/ai/EmbeddedAssistent/CircleAudioAvatar.tsx +14 -5
  105. package/src/components/ai/EmbeddedAssistent/TTS/MessageSender.ts +75 -74
  106. package/src/components/ai/EmbeddedAssistent/TTS/Player.ts +177 -178
  107. package/src/components/ai/EmbeddedAssistent/VoiceRecoder.tsx +109 -94
  108. package/src/components/ai/utils.ts +4 -4
  109. package/src/components/audio/Playbutton.tsx +101 -93
  110. package/src/components/components/ContextMenu.tsx +47 -35
  111. package/src/components.ts +10 -10
  112. package/src/core/controller/AIController.ts +62 -50
  113. package/src/core/controller/ExerciseController.ts +98 -0
  114. package/src/core/controller/ObjectController.ts +15 -10
  115. package/src/core/controller/SettingsController.ts +89 -16
  116. package/src/core/controller/SharedContentController.ts +80 -44
  117. package/src/core/controller/VoiceController.ts +10 -8
  118. package/src/core/core.ts +15 -15
  119. package/src/fromRimori/EventBus.ts +76 -47
  120. package/src/fromRimori/PluginTypes.ts +26 -17
  121. package/src/fromRimori/readme.md +2 -2
  122. package/src/hooks/UseChatHook.ts +25 -15
  123. package/src/index.ts +10 -10
  124. package/src/plugin/AccomplishmentHandler.ts +53 -35
  125. package/src/plugin/AudioController.ts +18 -12
  126. package/src/plugin/Logger.ts +77 -19
  127. package/src/plugin/PluginController.ts +60 -44
  128. package/src/plugin/RimoriClient.ts +133 -69
  129. package/src/plugin/StandaloneClient.ts +51 -24
  130. package/src/plugin/ThemeSetter.ts +5 -5
  131. package/src/providers/PluginProvider.tsx +90 -36
  132. package/src/style.scss +3 -3
  133. package/src/utils/Language.ts +58 -58
  134. package/src/utils/PluginUtils.ts +16 -20
  135. package/src/utils/difficultyConverter.ts +2 -2
  136. package/src/utils/endpoint.ts +3 -2
  137. package/src/worker/WorkerSetup.ts +8 -9
  138. package/tsconfig.json +2 -4
  139. package/dist/components/LoggerExample.d.ts +0 -6
  140. package/dist/components/LoggerExample.js +0 -79
  141. package/dist/core/controller/AudioController.d.ts +0 -0
  142. package/dist/core/controller/AudioController.js +0 -1
  143. package/dist/hooks/UseLogger.d.ts +0 -30
  144. package/dist/hooks/UseLogger.js +0 -122
  145. package/dist/plugin/LoggerExample.d.ts +0 -16
  146. package/dist/plugin/LoggerExample.js +0 -140
  147. package/dist/utils/audioFormats.d.ts +0 -26
  148. package/dist/utils/audioFormats.js +0 -67
@@ -12,7 +12,7 @@ import { useRimori } from '../../../components';
12
12
  import { FaMicrophone, FaSpinner } from 'react-icons/fa6';
13
13
  import { AudioController } from '../../../plugin/AudioController';
14
14
  import { useState, useRef, forwardRef, useImperativeHandle, useEffect } from 'react';
15
- export const VoiceRecorder = forwardRef(({ onVoiceRecorded, iconSize, className, disabled, loading, onRecordingStatusChange, enablePushToTalk = false }, ref) => {
15
+ export const VoiceRecorder = forwardRef(({ onVoiceRecorded, iconSize, className, disabled, loading, onRecordingStatusChange, enablePushToTalk = false, }, ref) => {
16
16
  const [isRecording, setIsRecording] = useState(false);
17
17
  const [internalIsProcessing, setInternalIsProcessing] = useState(false);
18
18
  const audioControllerRef = useRef(null);
@@ -91,6 +91,5 @@ export const VoiceRecorder = forwardRef(({ onVoiceRecorded, iconSize, className,
91
91
  window.removeEventListener('keyup', handleKeyUp);
92
92
  };
93
93
  }, [enablePushToTalk]);
94
- return (_jsx("button", { className: "flex flex-row justify-center items-center rounded-full mx-auto disabled:opacity-50 " + className, onClick: isRecording ? stopRecording : startRecording, disabled: disabled || loading || internalIsProcessing, children: loading || internalIsProcessing ? _jsx(FaSpinner, { className: "animate-spin" }) :
95
- _jsx(FaMicrophone, { size: iconSize, className: (isRecording ? "text-red-600" : "") }) }));
94
+ return (_jsx("button", { className: 'flex flex-row justify-center items-center rounded-full mx-auto disabled:opacity-50 ' + className, onClick: isRecording ? stopRecording : startRecording, disabled: disabled || loading || internalIsProcessing, children: loading || internalIsProcessing ? (_jsx(FaSpinner, { className: "animate-spin" })) : (_jsx(FaMicrophone, { size: iconSize, className: isRecording ? 'text-red-600' : '' })) }));
96
95
  });
@@ -9,8 +9,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  };
10
10
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
11
11
  import { useState, useEffect } from 'react';
12
- import { FaPlayCircle, FaStopCircle } from "react-icons/fa";
13
- import { useRimori } from "../../providers/PluginProvider";
12
+ import { FaPlayCircle, FaStopCircle } from 'react-icons/fa';
13
+ import { useRimori } from '../../providers/PluginProvider';
14
14
  import { Spinner } from '../Spinner';
15
15
  import { EventBus } from '../../fromRimori/EventBus';
16
16
  export const AudioPlayOptions = [0.8, 0.9, 1.0, 1.1, 1.2, 1.5];
@@ -35,7 +35,7 @@ export const AudioPlayer = ({ text, voice, language, hide, playListenerEvent, in
35
35
  // Function to generate audio from text using API
36
36
  const generateAudio = () => __awaiter(void 0, void 0, void 0, function* () {
37
37
  setIsLoading(true);
38
- const blob = yield ai.getVoice(text, voice || (language ? "aws_default" : "openai_alloy"), 1, language);
38
+ const blob = yield ai.getVoice(text, voice || (language ? 'aws_default' : 'openai_alloy'), 1, language);
39
39
  setAudioUrl(URL.createObjectURL(blob));
40
40
  setIsLoading(false);
41
41
  });
@@ -45,13 +45,16 @@ export const AudioPlayer = ({ text, voice, language, hide, playListenerEvent, in
45
45
  return;
46
46
  const audio = new Audio(audioUrl);
47
47
  audio.playbackRate = speed;
48
- audio.play().then(() => {
48
+ audio
49
+ .play()
50
+ .then(() => {
49
51
  audio.onended = () => {
50
52
  setIsPlaying(false);
51
53
  isFetchingAudio = false;
52
54
  };
53
- }).catch(e => {
54
- console.warn("Error playing audio:", e);
55
+ })
56
+ .catch((e) => {
57
+ console.warn('Error playing audio:', e);
55
58
  setIsPlaying(false);
56
59
  });
57
60
  return () => {
@@ -73,5 +76,5 @@ export const AudioPlayer = ({ text, voice, language, hide, playListenerEvent, in
73
76
  // console.log("playOnMount", playOnMount);
74
77
  togglePlayback();
75
78
  }, [playOnMount]);
76
- return (_jsx("div", { className: "group relative", children: _jsxs("div", { className: 'flex flex-row items-end', children: [!hide && _jsx("button", { className: "text-gray-500", onClick: togglePlayback, disabled: isLoading, children: isLoading ? _jsx(Spinner, {}) : isPlaying ? _jsx(FaStopCircle, { size: "25px" }) : _jsx(FaPlayCircle, { size: "25px" }) }), enableSpeedAdjustment && (_jsxs("div", { className: "ml-1 opacity-0 group-hover:opacity-100 transition-opacity duration-300 flex flex-row text-sm text-gray-500", children: [_jsx("span", { className: 'pr-1', children: "Speed: " }), _jsx("select", { value: speed, className: 'appearance-none cursor-pointer pr-0 p-0 rounded shadow leading-tight focus:outline-none focus:bg-gray-800 focus:ring bg-transparent border-0', onChange: (e) => setSpeed(parseFloat(e.target.value)), disabled: isLoading, children: AudioPlayOptions.map((s) => (_jsx("option", { value: s, children: s }, s))) })] }))] }) }));
79
+ return (_jsx("div", { className: "group relative", children: _jsxs("div", { className: "flex flex-row items-end", children: [!hide && (_jsx("button", { className: "text-gray-500", onClick: togglePlayback, disabled: isLoading, children: isLoading ? _jsx(Spinner, {}) : isPlaying ? _jsx(FaStopCircle, { size: '25px' }) : _jsx(FaPlayCircle, { size: '25px' }) })), enableSpeedAdjustment && (_jsxs("div", { className: "ml-1 opacity-0 group-hover:opacity-100 transition-opacity duration-300 flex flex-row text-sm text-gray-500", children: [_jsx("span", { className: "pr-1", children: "Speed: " }), _jsx("select", { value: speed, className: "appearance-none cursor-pointer pr-0 p-0 rounded shadow leading-tight focus:outline-none focus:bg-gray-800 focus:ring bg-transparent border-0", onChange: (e) => setSpeed(parseFloat(e.target.value)), disabled: isLoading, children: AudioPlayOptions.map((s) => (_jsx("option", { value: s, children: s }, s))) })] }))] }) }));
77
80
  };
@@ -1,4 +1,4 @@
1
- import { RimoriClient } from "../../plugin/RimoriClient";
1
+ import { RimoriClient } from '../../plugin/RimoriClient';
2
2
  export interface Position {
3
3
  x: number;
4
4
  y: number;
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useState, useEffect, useRef } from "react";
3
- import { EventBus } from "../../fromRimori/EventBus";
2
+ import { useState, useEffect, useRef } from 'react';
3
+ import { EventBus } from '../../fromRimori/EventBus';
4
4
  const ContextMenu = ({ client }) => {
5
5
  const [isOpen, setIsOpen] = useState(false);
6
6
  const [actions, setActions] = useState([]);
@@ -24,16 +24,19 @@ const ContextMenu = ({ client }) => {
24
24
  const range = selection.getRangeAt(0);
25
25
  const rect = range.getBoundingClientRect();
26
26
  // Center horizontally over the selected text, accounting for menu width
27
- const centerX = rect.left + (rect.width / 2) - (menuWidth / 2);
27
+ const centerX = rect.left + rect.width / 2 - menuWidth / 2;
28
28
  // Position 12px below where the text ends vertically
29
29
  const textEndY = rect.bottom + 12;
30
30
  return { x: centerX, y: textEndY, text: selectedText };
31
31
  };
32
32
  useEffect(() => {
33
- const actions = client.plugin.getPluginInfo().installedPlugins.flatMap(p => p.context_menu_actions).filter(Boolean);
33
+ const actions = client.plugin
34
+ .getPluginInfo()
35
+ .installedPlugins.flatMap((p) => p.context_menu_actions)
36
+ .filter(Boolean);
34
37
  setActions(actions);
35
38
  setOpenOnTextSelect(client.plugin.getUserInfo().context_menu_on_select);
36
- EventBus.on("global.contextMenu.createActions", ({ data }) => {
39
+ EventBus.on('global.contextMenu.createActions', ({ data }) => {
37
40
  setActions([...data.actions, ...actions]);
38
41
  });
39
42
  }, []);
@@ -67,8 +70,8 @@ const ContextMenu = ({ client }) => {
67
70
  }
68
71
  // Prevent context menu on textarea or text input selection
69
72
  const target = e.target;
70
- const isTextInput = target && ((target.tagName === 'TEXTAREA') ||
71
- (target.tagName === 'INPUT' && target.type === 'text'));
73
+ const isTextInput = target &&
74
+ (target.tagName === 'TEXTAREA' || (target.tagName === 'INPUT' && target.type === 'text'));
72
75
  if (isTextInput) {
73
76
  setIsOpen(false);
74
77
  return;
@@ -105,15 +108,15 @@ const ContextMenu = ({ client }) => {
105
108
  setPosition(calculateMobilePosition(selectedText, menuWidth));
106
109
  }
107
110
  };
108
- document.addEventListener("mouseup", handleMouseUp);
109
- window.addEventListener("mousemove", handleMouseMove);
110
- document.addEventListener("contextmenu", handleMouseUp);
111
- document.addEventListener("selectionchange", handleSelectionChange);
111
+ document.addEventListener('mouseup', handleMouseUp);
112
+ window.addEventListener('mousemove', handleMouseMove);
113
+ document.addEventListener('contextmenu', handleMouseUp);
114
+ document.addEventListener('selectionchange', handleSelectionChange);
112
115
  return () => {
113
- document.removeEventListener("mouseup", handleMouseUp);
114
- window.removeEventListener("mousemove", handleMouseMove);
115
- document.removeEventListener("contextmenu", handleMouseUp);
116
- document.removeEventListener("selectionchange", handleSelectionChange);
116
+ document.removeEventListener('mouseup', handleMouseUp);
117
+ window.removeEventListener('mousemove', handleMouseMove);
118
+ document.removeEventListener('contextmenu', handleMouseUp);
119
+ document.removeEventListener('selectionchange', handleSelectionChange);
117
120
  };
118
121
  }, [openOnTextSelect, isOpen, position.text]);
119
122
  if (!isOpen) {
@@ -127,6 +130,6 @@ const ContextMenu = ({ client }) => {
127
130
  } }, index))) }));
128
131
  };
129
132
  function MenuEntryItem(props) {
130
- return _jsxs("button", { onClick: props.onClick, className: "px-4 py-2 text-left hover:bg-gray-500 dark:hover:bg-gray-600 w-full flex flex-row", children: [_jsx("span", { className: "flex-grow", children: props.icon }), _jsx("span", { className: "flex-grow", children: props.text })] });
133
+ return (_jsxs("button", { onClick: props.onClick, className: "px-4 py-2 text-left hover:bg-gray-500 dark:hover:bg-gray-600 w-full flex flex-row", children: [_jsx("span", { className: "flex-grow", children: props.icon }), _jsx("span", { className: "flex-grow", children: props.text })] }));
131
134
  }
132
135
  export default ContextMenu;
@@ -1,10 +1,10 @@
1
- export * from "./components/ai/Assistant";
2
- export * from "./components/ai/Avatar";
3
- export * from "./components/ai/EmbeddedAssistent/VoiceRecoder";
4
- export * from "./components/audio/Playbutton";
5
- export * from "./components/CRUDModal";
6
- export * from "./components/MarkdownEditor";
7
- export * from "./components/Spinner";
8
- export * from "./hooks/UseChatHook";
9
- export * from "./plugin/ThemeSetter";
10
- export * from "./providers/PluginProvider";
1
+ export * from './components/ai/Assistant';
2
+ export * from './components/ai/Avatar';
3
+ export * from './components/ai/EmbeddedAssistent/VoiceRecoder';
4
+ export * from './components/audio/Playbutton';
5
+ export * from './components/CRUDModal';
6
+ export * from './components/MarkdownEditor';
7
+ export * from './components/Spinner';
8
+ export * from './hooks/UseChatHook';
9
+ export * from './plugin/ThemeSetter';
10
+ export * from './providers/PluginProvider';
@@ -1,11 +1,11 @@
1
1
  // React components and hooks exports
2
- export * from "./components/ai/Assistant";
3
- export * from "./components/ai/Avatar";
4
- export * from "./components/ai/EmbeddedAssistent/VoiceRecoder";
5
- export * from "./components/audio/Playbutton";
6
- export * from "./components/CRUDModal";
7
- export * from "./components/MarkdownEditor";
8
- export * from "./components/Spinner";
9
- export * from "./hooks/UseChatHook";
10
- export * from "./plugin/ThemeSetter";
11
- export * from "./providers/PluginProvider";
2
+ export * from './components/ai/Assistant';
3
+ export * from './components/ai/Avatar';
4
+ export * from './components/ai/EmbeddedAssistent/VoiceRecoder';
5
+ export * from './components/audio/Playbutton';
6
+ export * from './components/CRUDModal';
7
+ export * from './components/MarkdownEditor';
8
+ export * from './components/Spinner';
9
+ export * from './hooks/UseChatHook';
10
+ export * from './plugin/ThemeSetter';
11
+ export * from './providers/PluginProvider';
@@ -1,4 +1,4 @@
1
- import { Tool } from "../../fromRimori/PluginTypes";
1
+ import { Tool } from '../../fromRimori/PluginTypes';
2
2
  export interface ToolInvocation {
3
3
  toolCallId: string;
4
4
  toolName: string;
@@ -6,7 +6,7 @@ export interface ToolInvocation {
6
6
  }
7
7
  export interface Message {
8
8
  id?: string;
9
- role: "user" | "assistant" | "system";
9
+ role: 'user' | 'assistant' | 'system';
10
10
  content: string;
11
11
  toolCalls?: ToolInvocation[];
12
12
  }
@@ -23,7 +23,7 @@ export function generateText(backendUrl, messages, tools, token) {
23
23
  const response = yield fetch(`${backendUrl}/ai/llm`, {
24
24
  method: 'POST',
25
25
  body: JSON.stringify({ messages, tools }),
26
- headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' }
26
+ headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
27
27
  });
28
28
  return yield response.json();
29
29
  });
@@ -36,7 +36,7 @@ export function streamChatGPT(backendUrl, messages, tools, onResponse, token) {
36
36
  messageId,
37
37
  messageCount: messages.length,
38
38
  toolCount: tools.length,
39
- backendUrl
39
+ backendUrl,
40
40
  });
41
41
  while (true) {
42
42
  const messagesForApi = currentMessages.map((_a) => {
@@ -47,7 +47,7 @@ export function streamChatGPT(backendUrl, messages, tools, onResponse, token) {
47
47
  const response = yield fetch(`${backendUrl}/ai/llm`, {
48
48
  method: 'POST',
49
49
  body: JSON.stringify({ messages: messagesForApi, tools, stream: true }),
50
- headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' }
50
+ headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
51
51
  });
52
52
  if (!response.ok) {
53
53
  throw new Error(`HTTP error! status: ${response.status}`);
@@ -58,12 +58,12 @@ export function streamChatGPT(backendUrl, messages, tools, onResponse, token) {
58
58
  }
59
59
  const reader = response.body.getReader();
60
60
  const decoder = new TextDecoder('utf-8');
61
- let content = "";
61
+ let content = '';
62
62
  let done = false;
63
63
  let toolInvocations = [];
64
- let currentTextId = "";
64
+ let currentTextId = '';
65
65
  let isToolCallMode = false;
66
- let buffer = ""; // Buffer for incomplete chunks
66
+ let buffer = ''; // Buffer for incomplete chunks
67
67
  while (!done) {
68
68
  const { value, done: readerDone } = yield reader.read();
69
69
  if (value) {
@@ -73,7 +73,7 @@ export function streamChatGPT(backendUrl, messages, tools, onResponse, token) {
73
73
  const lines = buffer.split('\n');
74
74
  // Keep the last line in buffer if it's incomplete
75
75
  if (lines.length > 1) {
76
- buffer = lines.pop() || "";
76
+ buffer = lines.pop() || '';
77
77
  }
78
78
  for (const line of lines) {
79
79
  if (line.trim() === '')
@@ -90,16 +90,16 @@ export function streamChatGPT(backendUrl, messages, tools, onResponse, token) {
90
90
  const data = JSON.parse(dataStr);
91
91
  // Log the first message to understand the format
92
92
  if (!content && !isToolCallMode) {
93
- console.log('First stream message received:', data);
93
+ // console.log('First stream message received:', data);
94
94
  }
95
95
  switch (data.type) {
96
96
  case 'start':
97
97
  // Stream started, no action needed
98
- console.log('Stream started');
98
+ // console.log('Stream started');
99
99
  break;
100
100
  case 'start-step':
101
101
  // Step started, no action needed
102
- console.log('Step started');
102
+ // console.log('Step started');
103
103
  break;
104
104
  case 'reasoning-start':
105
105
  // Reasoning started, no action needed
@@ -127,26 +127,28 @@ export function streamChatGPT(backendUrl, messages, tools, onResponse, token) {
127
127
  break;
128
128
  case 'finish-step':
129
129
  // Step finished, no action needed
130
- console.log('Step finished');
130
+ // console.log('Step finished');
131
131
  break;
132
132
  case 'finish':
133
133
  // Stream finished
134
- console.log('Stream finished');
134
+ // console.log('Stream finished');
135
135
  done = true;
136
136
  break;
137
137
  // Additional message types that might be present in the AI library
138
138
  case 'tool-call':
139
+ case 'tool-input-available': //for now input calls should be handled the same way as tool calls
139
140
  // Tool call initiated
140
141
  console.log('Tool call initiated:', data);
141
142
  isToolCallMode = true;
142
- if (data.toolCallId && data.toolName && data.args) {
143
+ if (data.toolCallId && data.toolName && (data.args || data.input)) {
143
144
  toolInvocations.push({
144
145
  toolCallId: data.toolCallId,
145
146
  toolName: data.toolName,
146
- args: data.args
147
+ args: data.args || data.input,
147
148
  });
148
149
  }
149
150
  break;
151
+ case 'tool-input-delta': //for now input calls should be handled the same way as tool calls
150
152
  case 'tool-call-delta':
151
153
  // Tool call delta (for streaming tool calls)
152
154
  console.log('Tool call delta:', data);
@@ -196,7 +198,7 @@ export function streamChatGPT(backendUrl, messages, tools, onResponse, token) {
196
198
  if (content || toolInvocations.length > 0) {
197
199
  currentMessages.push({
198
200
  id: messageId,
199
- role: "assistant",
201
+ role: 'assistant',
200
202
  content: content,
201
203
  toolCalls: toolInvocations.length > 0 ? toolInvocations : undefined,
202
204
  });
@@ -206,13 +208,13 @@ export function streamChatGPT(backendUrl, messages, tools, onResponse, token) {
206
208
  console.log('Tool calls detected, executing tools...');
207
209
  const toolResults = [];
208
210
  for (const toolInvocation of toolInvocations) {
209
- const tool = tools.find(t => t.name === toolInvocation.toolName);
211
+ const tool = tools.find((t) => t.name === toolInvocation.toolName);
210
212
  if (tool && tool.execute) {
211
213
  try {
212
214
  const result = yield tool.execute(toolInvocation.args);
213
215
  toolResults.push({
214
216
  id: Math.random().toString(36).substring(3),
215
- role: "user",
217
+ role: 'user',
216
218
  content: `Tool '${toolInvocation.toolName}' returned: ${JSON.stringify(result)}`,
217
219
  });
218
220
  }
@@ -220,7 +222,7 @@ export function streamChatGPT(backendUrl, messages, tools, onResponse, token) {
220
222
  console.error(`Error executing tool ${toolInvocation.toolName}:`, error);
221
223
  toolResults.push({
222
224
  id: Math.random().toString(36).substring(3),
223
- role: "user",
225
+ role: 'user',
224
226
  content: `Tool '${toolInvocation.toolName}' failed with error: ${error}`,
225
227
  });
226
228
  }
@@ -0,0 +1,52 @@
1
+ import { SupabaseClient } from '@supabase/supabase-js';
2
+ import { PluginController } from '../../plugin/PluginController';
3
+ export type TriggerAction = {
4
+ action_key: string;
5
+ } & Record<string, string | number | boolean>;
6
+ export interface CreateExerciseParams {
7
+ plugin_id: string;
8
+ start_date: string;
9
+ end_date: string;
10
+ trigger_action: TriggerAction;
11
+ name: string;
12
+ description: string;
13
+ estimated_duration: number;
14
+ }
15
+ export interface Exercise {
16
+ id: string;
17
+ plugin_id: string;
18
+ start_date: string;
19
+ end_date: string;
20
+ trigger_action: TriggerAction;
21
+ name: string;
22
+ description: string;
23
+ estimated_duration: number;
24
+ created_at?: string;
25
+ updated_at?: string;
26
+ }
27
+ export declare class ExerciseController {
28
+ private supabase;
29
+ private pluginController;
30
+ constructor(supabase: SupabaseClient, pluginController: PluginController);
31
+ /**
32
+ * Fetches weekly exercises from the weekly_exercises view.
33
+ * Shows exercises for the current week that haven't expired.
34
+ * @returns Array of exercise objects.
35
+ */
36
+ viewWeeklyExercises(): Promise<Exercise[]>;
37
+ /**
38
+ * Creates a new exercise via the backend API.
39
+ * @param params Exercise creation parameters.
40
+ * @returns Created exercise object.
41
+ */
42
+ addExercise(params: CreateExerciseParams): Promise<Exercise>;
43
+ /**
44
+ * Deletes an exercise via the backend API.
45
+ * @param id The exercise ID to delete.
46
+ * @returns Success status.
47
+ */
48
+ deleteExercise(id: string): Promise<{
49
+ success: boolean;
50
+ message: string;
51
+ }>;
52
+ }
@@ -0,0 +1,73 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ export class ExerciseController {
11
+ constructor(supabase, pluginController) {
12
+ this.supabase = supabase;
13
+ this.pluginController = pluginController;
14
+ }
15
+ /**
16
+ * Fetches weekly exercises from the weekly_exercises view.
17
+ * Shows exercises for the current week that haven't expired.
18
+ * @returns Array of exercise objects.
19
+ */
20
+ viewWeeklyExercises() {
21
+ return __awaiter(this, void 0, void 0, function* () {
22
+ const { data, error } = yield this.supabase.from('weekly_exercises').select('*');
23
+ if (error) {
24
+ throw new Error(`Failed to fetch weekly exercises: ${error.message}`);
25
+ }
26
+ return data || [];
27
+ });
28
+ }
29
+ /**
30
+ * Creates a new exercise via the backend API.
31
+ * @param params Exercise creation parameters.
32
+ * @returns Created exercise object.
33
+ */
34
+ addExercise(params) {
35
+ return __awaiter(this, void 0, void 0, function* () {
36
+ const token = yield this.pluginController.getToken();
37
+ const response = yield fetch(`${this.pluginController.getBackendUrl()}/exercises`, {
38
+ method: 'POST',
39
+ headers: {
40
+ 'Content-Type': 'application/json',
41
+ Authorization: `Bearer ${token}`,
42
+ },
43
+ body: JSON.stringify(params),
44
+ });
45
+ if (!response.ok) {
46
+ const errorText = yield response.text();
47
+ throw new Error(`Failed to create exercise: ${errorText}`);
48
+ }
49
+ return yield response.json();
50
+ });
51
+ }
52
+ /**
53
+ * Deletes an exercise via the backend API.
54
+ * @param id The exercise ID to delete.
55
+ * @returns Success status.
56
+ */
57
+ deleteExercise(id) {
58
+ return __awaiter(this, void 0, void 0, function* () {
59
+ const token = yield this.pluginController.getToken();
60
+ const response = yield fetch(`${this.pluginController.getBackendUrl()}/exercises/${id}`, {
61
+ method: 'DELETE',
62
+ headers: {
63
+ Authorization: `Bearer ${token}`,
64
+ },
65
+ });
66
+ if (!response.ok) {
67
+ const errorText = yield response.text();
68
+ throw new Error(`Failed to delete exercise: ${errorText}`);
69
+ }
70
+ return yield response.json();
71
+ });
72
+ }
73
+ }
@@ -17,8 +17,8 @@ export function generateObject(backendUrl, request, token) {
17
17
  behaviour: request.behaviour,
18
18
  instructions: request.instructions,
19
19
  }),
20
- headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' }
21
- }).then(response => response.json());
20
+ headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
21
+ }).then((response) => response.json());
22
22
  });
23
23
  }
24
24
  export function streamObject(backendUrl, request, onResponse, token) {
@@ -32,7 +32,7 @@ export function streamObject(backendUrl, request, onResponse, token) {
32
32
  systemInstructions: request.behaviour,
33
33
  secondaryInstructions: request.instructions,
34
34
  }),
35
- headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' }
35
+ headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
36
36
  });
37
37
  if (!response.body) {
38
38
  console.error('No response body.');
@@ -40,14 +40,14 @@ export function streamObject(backendUrl, request, onResponse, token) {
40
40
  }
41
41
  const reader = response.body.getReader();
42
42
  const decoder = new TextDecoder('utf-8');
43
- let content = "";
43
+ let content = '';
44
44
  let done = false;
45
45
  let toolInvocations = [];
46
46
  while (!done) {
47
47
  const { value } = yield reader.read();
48
48
  if (value) {
49
49
  const chunk = decoder.decode(value, { stream: true });
50
- const lines = chunk.split('\n').filter(line => line.trim() !== '');
50
+ const lines = chunk.split('\n').filter((line) => line.trim() !== '');
51
51
  for (const line of lines) {
52
52
  const data = line.substring(3, line.length - 1);
53
53
  const command = line.substring(0, 1);
@@ -1,6 +1,7 @@
1
- import { SupabaseClient } from "@supabase/supabase-js";
2
- import { LanguageLevel } from "../../utils/difficultyConverter";
3
- import { Language } from "../../utils/Language";
1
+ import { SupabaseClient } from '@supabase/supabase-js';
2
+ import { LanguageLevel } from '../../utils/difficultyConverter';
3
+ import { Language } from '../../utils/Language';
4
+ import { Guild } from '../core';
4
5
  export interface Buddy {
5
6
  id: string;
6
7
  name: string;
@@ -35,19 +36,33 @@ export interface UserInfo {
35
36
  context_menu_on_select: boolean;
36
37
  user_name?: string;
37
38
  /**
38
- * ISO 3166-1 alpha-2 country code of user's location (exposed to plugins)
39
+ * ISO 3166-1 alpha-2 country code of user's target location (exposed to plugins)
39
40
  */
40
- location_country: string;
41
+ target_country: string;
41
42
  /**
42
43
  * Optional: nearest big city (>100,000) near user's location
43
44
  */
44
- location_city?: string;
45
+ target_city?: string;
45
46
  }
46
47
  export declare class SettingsController {
47
48
  private pluginId;
48
49
  private supabase;
49
- constructor(supabase: SupabaseClient, pluginId: string);
50
+ private guild;
51
+ constructor(supabase: SupabaseClient, pluginId: string, guild: Guild);
52
+ /**
53
+ * Fetches settings based on guild configuration.
54
+ * If guild doesn't allow user settings, fetches guild-level settings.
55
+ * Otherwise, fetches user-specific settings.
56
+ * @returns The settings object or null if not found.
57
+ */
50
58
  private fetchSettings;
59
+ /**
60
+ * Sets settings for the plugin.
61
+ * Automatically saves as guild settings if guild doesn't allow user settings,
62
+ * otherwise saves as user-specific settings.
63
+ * @param settings - The settings object to save.
64
+ * @throws {Error} if RLS blocks the operation.
65
+ */
51
66
  setSettings(settings: any): Promise<void>;
52
67
  /**
53
68
  * Get the settings for the plugin. T can be any type of settings, UserSettings or SystemSettings.