@rimori/client 1.1.9 → 1.2.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 (151) hide show
  1. package/README.md +128 -45
  2. package/dist/cli/scripts/init/dev-registration.d.ts +35 -0
  3. package/dist/cli/scripts/init/dev-registration.js +175 -0
  4. package/dist/cli/scripts/init/env-setup.d.ts +9 -0
  5. package/dist/cli/scripts/init/env-setup.js +43 -0
  6. package/dist/cli/scripts/init/file-operations.d.ts +4 -0
  7. package/dist/cli/scripts/init/file-operations.js +51 -0
  8. package/dist/cli/scripts/init/html-cleaner.d.ts +4 -0
  9. package/dist/cli/scripts/init/html-cleaner.js +38 -0
  10. package/dist/cli/scripts/init/main.d.ts +2 -0
  11. package/dist/cli/scripts/init/main.js +159 -0
  12. package/dist/cli/scripts/init/package-setup.d.ts +32 -0
  13. package/dist/cli/scripts/init/package-setup.js +75 -0
  14. package/dist/cli/scripts/init/router-transformer.d.ts +6 -0
  15. package/dist/cli/scripts/init/router-transformer.js +254 -0
  16. package/dist/cli/scripts/init/tailwind-config.d.ts +4 -0
  17. package/dist/cli/scripts/init/tailwind-config.js +56 -0
  18. package/dist/cli/scripts/init/vite-config.d.ts +20 -0
  19. package/dist/cli/scripts/init/vite-config.js +54 -0
  20. package/dist/cli/scripts/release/release-config-upload.d.ts +7 -0
  21. package/dist/cli/scripts/release/release-config-upload.js +116 -0
  22. package/dist/cli/scripts/release/release-db-update.d.ts +6 -0
  23. package/dist/cli/scripts/release/release-db-update.js +100 -0
  24. package/dist/cli/scripts/release/release-file-upload.d.ts +6 -0
  25. package/dist/cli/scripts/release/release-file-upload.js +136 -0
  26. package/dist/cli/scripts/release/release.d.ts +23 -0
  27. package/dist/cli/scripts/release/release.js +70 -0
  28. package/dist/cli/types/DatabaseTypes.d.ts +103 -0
  29. package/dist/cli/types/DatabaseTypes.js +2 -0
  30. package/dist/components/ai/Assistant.js +4 -4
  31. package/dist/components/ai/Avatar.d.ts +3 -2
  32. package/dist/components/ai/Avatar.js +10 -5
  33. package/dist/components/ai/EmbeddedAssistent/CircleAudioAvatar.js +1 -1
  34. package/dist/components/ai/EmbeddedAssistent/VoiceRecoder.d.ts +1 -0
  35. package/dist/components/ai/EmbeddedAssistent/VoiceRecoder.js +12 -6
  36. package/dist/components/ai/utils.js +0 -1
  37. package/dist/components/audio/Playbutton.js +3 -3
  38. package/dist/{core → components}/components/ContextMenu.js +2 -2
  39. package/dist/components.d.ts +5 -5
  40. package/dist/components.js +5 -5
  41. package/dist/core/controller/AIController.d.ts +15 -0
  42. package/dist/core/controller/AIController.js +120 -0
  43. package/dist/{controller → core/controller}/ObjectController.d.ts +8 -0
  44. package/dist/{controller → core/controller}/SettingsController.d.ts +12 -4
  45. package/dist/{controller → core/controller}/SettingsController.js +0 -25
  46. package/dist/{controller → core/controller}/SharedContentController.d.ts +10 -19
  47. package/dist/{controller → core/controller}/SharedContentController.js +11 -11
  48. package/dist/core/core.d.ts +13 -0
  49. package/dist/core/core.js +8 -0
  50. package/dist/{plugin/fromRimori → fromRimori}/EventBus.d.ts +3 -3
  51. package/dist/{plugin/fromRimori → fromRimori}/EventBus.js +25 -8
  52. package/dist/fromRimori/PluginTypes.d.ts +171 -0
  53. package/dist/hooks/UseChatHook.d.ts +2 -1
  54. package/dist/hooks/UseChatHook.js +3 -3
  55. package/dist/index.d.ts +5 -3
  56. package/dist/index.js +4 -3
  57. package/dist/plugin/AccomplishmentHandler.d.ts +1 -1
  58. package/dist/plugin/AccomplishmentHandler.js +1 -1
  59. package/dist/plugin/PluginController.d.ts +16 -3
  60. package/dist/plugin/PluginController.js +24 -18
  61. package/dist/plugin/RimoriClient.d.ts +22 -17
  62. package/dist/plugin/RimoriClient.js +35 -25
  63. package/dist/plugin/StandaloneClient.js +11 -8
  64. package/dist/plugin/ThemeSetter.d.ts +1 -0
  65. package/dist/plugin/ThemeSetter.js +9 -6
  66. package/dist/providers/PluginProvider.d.ts +3 -0
  67. package/dist/providers/PluginProvider.js +4 -4
  68. package/dist/utils/Language.d.ts +2 -1
  69. package/dist/utils/Language.js +4 -2
  70. package/dist/utils/difficultyConverter.js +1 -1
  71. package/dist/utils/endpoint.d.ts +2 -0
  72. package/dist/utils/endpoint.js +2 -0
  73. package/dist/worker/WorkerSetup.js +3 -1
  74. package/example/docs/devdocs.md +231 -0
  75. package/example/docs/overview.md +29 -0
  76. package/example/docs/userdocs.md +123 -0
  77. package/example/rimori.config.ts +89 -0
  78. package/example/worker/vite.config.ts +23 -0
  79. package/example/worker/worker.ts +11 -0
  80. package/package.json +15 -9
  81. package/src/cli/scripts/init/dev-registration.ts +193 -0
  82. package/src/cli/scripts/init/env-setup.ts +44 -0
  83. package/src/cli/scripts/init/file-operations.ts +58 -0
  84. package/src/cli/scripts/init/html-cleaner.ts +48 -0
  85. package/src/cli/scripts/init/main.ts +171 -0
  86. package/src/cli/scripts/init/package-setup.ts +117 -0
  87. package/src/cli/scripts/init/router-transformer.ts +329 -0
  88. package/src/cli/scripts/init/tailwind-config.ts +75 -0
  89. package/src/cli/scripts/init/vite-config.ts +73 -0
  90. package/src/cli/scripts/release/release-config-upload.ts +114 -0
  91. package/src/cli/scripts/release/release-db-update.ts +97 -0
  92. package/src/cli/scripts/release/release-file-upload.ts +138 -0
  93. package/src/cli/scripts/release/release.ts +69 -0
  94. package/src/cli/types/DatabaseTypes.ts +117 -0
  95. package/src/components/ai/Assistant.tsx +4 -4
  96. package/src/components/ai/Avatar.tsx +24 -7
  97. package/src/components/ai/EmbeddedAssistent/CircleAudioAvatar.tsx +1 -1
  98. package/src/components/ai/EmbeddedAssistent/VoiceRecoder.tsx +16 -8
  99. package/src/components/ai/utils.ts +0 -2
  100. package/src/components/audio/Playbutton.tsx +3 -3
  101. package/src/{core → components}/components/ContextMenu.tsx +3 -3
  102. package/src/components.ts +6 -6
  103. package/src/core/controller/AIController.ts +122 -0
  104. package/src/core/controller/ObjectController.ts +115 -0
  105. package/src/{controller → core/controller}/SettingsController.ts +13 -29
  106. package/src/{controller → core/controller}/SharedContentController.ts +18 -28
  107. package/src/core/core.ts +15 -0
  108. package/src/{plugin/fromRimori → fromRimori}/EventBus.ts +28 -10
  109. package/src/fromRimori/PluginTypes.ts +203 -0
  110. package/src/hooks/UseChatHook.ts +5 -4
  111. package/src/index.ts +5 -3
  112. package/src/plugin/AccomplishmentHandler.ts +1 -1
  113. package/src/plugin/PluginController.ts +35 -23
  114. package/src/plugin/RimoriClient.ts +48 -41
  115. package/src/plugin/StandaloneClient.ts +11 -8
  116. package/src/plugin/ThemeSetter.ts +12 -8
  117. package/src/providers/PluginProvider.tsx +7 -4
  118. package/src/utils/Language.ts +4 -2
  119. package/src/utils/difficultyConverter.ts +3 -3
  120. package/src/utils/endpoint.ts +2 -0
  121. package/src/worker/WorkerSetup.ts +4 -2
  122. package/dist/components/PluginController.d.ts +0 -21
  123. package/dist/components/PluginController.js +0 -116
  124. package/dist/controller/AIController.d.ts +0 -23
  125. package/dist/controller/AIController.js +0 -93
  126. package/dist/controller/SidePluginController.d.ts +0 -3
  127. package/dist/controller/SidePluginController.js +0 -31
  128. package/dist/core.d.ts +0 -7
  129. package/dist/core.js +0 -7
  130. package/dist/plugin/ContextMenu.d.ts +0 -17
  131. package/dist/plugin/ContextMenu.js +0 -45
  132. package/dist/plugin/fromRimori/PluginTypes.d.ts +0 -48
  133. package/dist/plugin/fromRimori/SupabaseHandler.d.ts +0 -13
  134. package/dist/plugin/fromRimori/SupabaseHandler.js +0 -55
  135. package/dist/providers/PluginController.d.ts +0 -21
  136. package/dist/providers/PluginController.js +0 -116
  137. package/dist/types/Actions.d.ts +0 -4
  138. package/dist/types/Actions.js +0 -1
  139. package/src/controller/AIController.ts +0 -112
  140. package/src/controller/ObjectController.ts +0 -107
  141. package/src/controller/SidePluginController.ts +0 -25
  142. package/src/core.ts +0 -8
  143. package/src/plugin/fromRimori/PluginTypes.ts +0 -64
  144. package/src/types/Actions.ts +0 -6
  145. /package/dist/{core → components}/components/ContextMenu.d.ts +0 -0
  146. /package/dist/{controller → core/controller}/ObjectController.js +0 -0
  147. /package/dist/{controller → core/controller}/VoiceController.d.ts +0 -0
  148. /package/dist/{controller → core/controller}/VoiceController.js +0 -0
  149. /package/dist/{plugin/fromRimori → fromRimori}/PluginTypes.js +0 -0
  150. /package/src/{controller → core/controller}/VoiceController.ts +0 -0
  151. /package/src/{plugin/fromRimori → fromRimori}/readme.md +0 -0
@@ -3,6 +3,7 @@ interface Props {
3
3
  className?: string;
4
4
  disabled?: boolean;
5
5
  loading?: boolean;
6
+ enablePushToTalk?: boolean;
6
7
  onRecordingStatusChange: (running: boolean) => void;
7
8
  onVoiceRecorded: (message: string) => void;
8
9
  }
@@ -11,12 +11,13 @@ import { jsx as _jsx } from "react/jsx-runtime";
11
11
  import { useState, useRef, forwardRef, useImperativeHandle, useEffect } from 'react';
12
12
  import { FaMicrophone, FaSpinner } from 'react-icons/fa6';
13
13
  import { usePlugin } from '../../../components';
14
- export const VoiceRecorder = forwardRef(({ onVoiceRecorded, iconSize, className, disabled, loading, onRecordingStatusChange }, ref) => {
14
+ export const VoiceRecorder = forwardRef(({ onVoiceRecorded, iconSize, className, disabled, loading, onRecordingStatusChange, enablePushToTalk = false }, ref) => {
15
15
  const [isRecording, setIsRecording] = useState(false);
16
+ const [internalIsProcessing, setInternalIsProcessing] = useState(false);
16
17
  const mediaRecorderRef = useRef(null);
17
18
  const audioChunksRef = useRef([]);
18
19
  const mediaStreamRef = useRef(null);
19
- const { llm } = usePlugin();
20
+ const { ai: llm } = usePlugin();
20
21
  // Ref for latest onVoiceRecorded callback
21
22
  const onVoiceRecordedRef = useRef(onVoiceRecorded);
22
23
  useEffect(() => {
@@ -33,7 +34,10 @@ export const VoiceRecorder = forwardRef(({ onVoiceRecorded, iconSize, className,
33
34
  mediaRecorder.onstop = () => __awaiter(void 0, void 0, void 0, function* () {
34
35
  const audioBlob = new Blob(audioChunksRef.current);
35
36
  audioChunksRef.current = [];
36
- onVoiceRecordedRef.current(yield llm.getTextFromVoice(audioBlob));
37
+ setInternalIsProcessing(true);
38
+ const text = yield llm.getTextFromVoice(audioBlob);
39
+ setInternalIsProcessing(false);
40
+ onVoiceRecordedRef.current(text);
37
41
  });
38
42
  mediaRecorder.start();
39
43
  setIsRecording(true);
@@ -57,6 +61,8 @@ export const VoiceRecorder = forwardRef(({ onVoiceRecorded, iconSize, className,
57
61
  // push to talk feature
58
62
  const spacePressedRef = useRef(false);
59
63
  useEffect(() => {
64
+ if (!enablePushToTalk)
65
+ return;
60
66
  const handleKeyDown = (event) => __awaiter(void 0, void 0, void 0, function* () {
61
67
  if (event.code === 'Space' && !spacePressedRef.current) {
62
68
  spacePressedRef.current = true;
@@ -75,7 +81,7 @@ export const VoiceRecorder = forwardRef(({ onVoiceRecorded, iconSize, className,
75
81
  window.removeEventListener('keydown', handleKeyDown);
76
82
  window.removeEventListener('keyup', handleKeyUp);
77
83
  };
78
- }, []);
79
- return (_jsx("button", { className: "w-16 h-16 flex text-4xl shadow-lg flex-row justify-center items-center rounded-full mx-auto bg-gray-400 dark:bg-gray-800 pl-[6px] disabled:opacity-50 " + className, onClick: isRecording ? stopRecording : startRecording, disabled: disabled || loading, children: loading ? _jsx(FaSpinner, { className: "animate-spin mr-[6px]" }) :
80
- _jsx(FaMicrophone, { size: iconSize, className: "h-7 w-7 mr-2 " + (isRecording ? "text-red-600" : "") }) }));
84
+ }, [enablePushToTalk]);
85
+ 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" }) :
86
+ _jsx(FaMicrophone, { size: iconSize, className: (isRecording ? "text-red-600" : "") }) }));
81
87
  });
@@ -9,6 +9,5 @@ export function getFirstMessages(instructions) {
9
9
  if (instructions.assistantMessage) {
10
10
  messages.push({ id: '3', role: 'assistant', content: instructions.assistantMessage });
11
11
  }
12
- console.log("getFirstMessages", messages);
13
12
  return messages;
14
13
  }
@@ -12,7 +12,7 @@ import { useState, useEffect } from 'react';
12
12
  import { FaPlayCircle, FaStopCircle } from "react-icons/fa";
13
13
  import { usePlugin } from "../../providers/PluginProvider";
14
14
  import { Spinner } from '../Spinner';
15
- import { EventBus } from '../../plugin/fromRimori/EventBus';
15
+ import { EventBus } from '../../fromRimori/EventBus';
16
16
  export const AudioPlayOptions = [0.8, 0.9, 1.0, 1.1, 1.2, 1.5];
17
17
  let isFetchingAudio = false;
18
18
  export const AudioPlayer = ({ text, voice, language, hide, playListenerEvent, initialSpeed = 1.0, playOnMount = false, enableSpeedAdjustment = false, }) => {
@@ -20,7 +20,7 @@ export const AudioPlayer = ({ text, voice, language, hide, playListenerEvent, in
20
20
  const [speed, setSpeed] = useState(initialSpeed);
21
21
  const [isPlaying, setIsPlaying] = useState(false);
22
22
  const [isLoading, setIsLoading] = useState(false);
23
- const { llm } = usePlugin();
23
+ const { ai } = usePlugin();
24
24
  useEffect(() => {
25
25
  if (!playListenerEvent)
26
26
  return;
@@ -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 llm.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
  });
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useState, useEffect, useRef } from "react";
3
- import { EventBus } from "../../plugin/fromRimori/EventBus";
3
+ import { EventBus } from "../../fromRimori/EventBus";
4
4
  const ContextMenu = ({ client }) => {
5
5
  const [isOpen, setIsOpen] = useState(false);
6
6
  const [actions, setActions] = useState([]);
@@ -84,7 +84,7 @@ const ContextMenu = ({ client }) => {
84
84
  var _a;
85
85
  setIsOpen(false);
86
86
  (_a = window.getSelection()) === null || _a === void 0 ? void 0 : _a.removeAllRanges();
87
- client.event.emitSidebarAction(action.pluginId, action.actionKey, position.text);
87
+ client.event.emitSidebarAction(action.plugin_id, action.action_key, position.text);
88
88
  } }, index))) }));
89
89
  };
90
90
  function MenuEntryItem(props) {
@@ -1,10 +1,10 @@
1
- export * from "./components/MarkdownEditor";
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";
2
5
  export * from "./components/CRUDModal";
6
+ export * from "./components/MarkdownEditor";
3
7
  export * from "./components/Spinner";
4
- export * from "./components/audio/Playbutton";
5
8
  export * from "./hooks/UseChatHook";
6
9
  export * from "./plugin/ThemeSetter";
7
10
  export * from "./providers/PluginProvider";
8
- export * from "./components/ai/Avatar";
9
- export * from "./components/ai/Assistant";
10
- export * from "./types/Actions";
@@ -1,11 +1,11 @@
1
1
  // React components and hooks exports
2
- export * from "./components/MarkdownEditor";
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";
3
6
  export * from "./components/CRUDModal";
7
+ export * from "./components/MarkdownEditor";
4
8
  export * from "./components/Spinner";
5
- export * from "./components/audio/Playbutton";
6
9
  export * from "./hooks/UseChatHook";
7
10
  export * from "./plugin/ThemeSetter";
8
11
  export * from "./providers/PluginProvider";
9
- export * from "./components/ai/Avatar";
10
- export * from "./components/ai/Assistant";
11
- export * from "./types/Actions";
@@ -0,0 +1,15 @@
1
+ import { Tool } from "../../fromRimori/PluginTypes";
2
+ export interface ToolInvocation {
3
+ toolCallId: string;
4
+ toolName: string;
5
+ args: Record<string, string>;
6
+ }
7
+ export interface Message {
8
+ id?: string;
9
+ role: "user" | "assistant" | "system";
10
+ content: string;
11
+ toolCalls?: ToolInvocation[];
12
+ }
13
+ export declare function generateText(backendUrl: string, messages: Message[], tools: Tool[], token: string): Promise<any>;
14
+ export type OnLLMResponse = (id: string, response: string, finished: boolean, toolInvocations?: ToolInvocation[]) => void;
15
+ export declare function streamChatGPT(backendUrl: string, messages: Message[], tools: Tool[], onResponse: OnLLMResponse, token: string): Promise<void>;
@@ -0,0 +1,120 @@
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
+ var __rest = (this && this.__rest) || function (s, e) {
11
+ var t = {};
12
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
13
+ t[p] = s[p];
14
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
15
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
16
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
17
+ t[p[i]] = s[p[i]];
18
+ }
19
+ return t;
20
+ };
21
+ export function generateText(backendUrl, messages, tools, token) {
22
+ return __awaiter(this, void 0, void 0, function* () {
23
+ const response = yield fetch(`${backendUrl}/ai/llm`, {
24
+ method: 'POST',
25
+ body: JSON.stringify({ messages, tools }),
26
+ headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' }
27
+ });
28
+ return yield response.json();
29
+ });
30
+ }
31
+ export function streamChatGPT(backendUrl, messages, tools, onResponse, token) {
32
+ return __awaiter(this, void 0, void 0, function* () {
33
+ const messageId = Math.random().toString(36).substring(3);
34
+ let currentMessages = [...messages];
35
+ while (true) {
36
+ const messagesForApi = currentMessages.map((_a) => {
37
+ var { id } = _a, rest = __rest(_a, ["id"]);
38
+ return rest;
39
+ });
40
+ const response = yield fetch(`${backendUrl}/ai/llm`, {
41
+ method: 'POST',
42
+ body: JSON.stringify({ messages: messagesForApi, tools, stream: true }),
43
+ headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' }
44
+ });
45
+ if (!response.body) {
46
+ console.error('No response body.');
47
+ return;
48
+ }
49
+ const reader = response.body.getReader();
50
+ const decoder = new TextDecoder('utf-8');
51
+ let content = "";
52
+ let done = false;
53
+ let toolInvocations = [];
54
+ let finishReason = "";
55
+ while (!done) {
56
+ const { value, done: readerDone } = yield reader.read();
57
+ if (value) {
58
+ const chunk = decoder.decode(value, { stream: true });
59
+ const lines = chunk.split('\n').filter(line => line.trim() !== '');
60
+ for (const line of lines) {
61
+ const command = line.substring(0, 1);
62
+ if (command === '0') {
63
+ const data = line.substring(3, line.length - 1);
64
+ content += data;
65
+ onResponse(messageId, content.replace(/\\n/g, '\n').replace(/\\+"/g, '"'), false);
66
+ }
67
+ else if (command === 'd' || command === 'e') {
68
+ const eventData = JSON.parse(line.substring(2));
69
+ finishReason = eventData.finishReason;
70
+ done = true;
71
+ break;
72
+ }
73
+ else if (command === '9') {
74
+ const toolInvocation = JSON.parse(line.substring(2));
75
+ toolInvocations.push(toolInvocation);
76
+ }
77
+ }
78
+ }
79
+ if (readerDone) {
80
+ done = true;
81
+ }
82
+ }
83
+ if (content || toolInvocations.length > 0) {
84
+ currentMessages.push({
85
+ id: messageId,
86
+ role: "assistant",
87
+ content: content,
88
+ toolCalls: toolInvocations.length > 0 ? toolInvocations : undefined,
89
+ });
90
+ }
91
+ if (finishReason !== 'tool-calls') {
92
+ onResponse(messageId, content.replace(/\\n/g, '\n'), true, toolInvocations);
93
+ return;
94
+ }
95
+ const toolResults = [];
96
+ for (const toolInvocation of toolInvocations) {
97
+ const tool = tools.find(t => t.name === toolInvocation.toolName);
98
+ if (tool && tool.execute) {
99
+ try {
100
+ const result = yield tool.execute(toolInvocation.args);
101
+ toolResults.push({
102
+ id: Math.random().toString(36).substring(3),
103
+ role: "user",
104
+ content: `Tool '${toolInvocation.toolName}' returned: ${JSON.stringify(result)}`,
105
+ });
106
+ }
107
+ catch (error) {
108
+ console.error(`Error executing tool ${toolInvocation.toolName}:`, error);
109
+ toolResults.push({
110
+ id: Math.random().toString(36).substring(3),
111
+ role: "user",
112
+ content: `Tool '${toolInvocation.toolName}' failed with error: ${error}`,
113
+ });
114
+ }
115
+ }
116
+ }
117
+ currentMessages.push(...toolResults);
118
+ }
119
+ });
120
+ }
@@ -8,7 +8,15 @@ interface ObjectToolParameter {
8
8
  type: ObjectToolParameterType;
9
9
  description?: string;
10
10
  enum?: string[];
11
+ optional?: boolean;
11
12
  }
13
+ /**
14
+ * The tools that the AI can use.
15
+ *
16
+ * The key is the name of the tool.
17
+ * The value is the parameter of the tool.
18
+ *
19
+ */
12
20
  export type ObjectTool = {
13
21
  [key: string]: ObjectToolParameter;
14
22
  };
@@ -1,6 +1,14 @@
1
1
  import { SupabaseClient } from "@supabase/supabase-js";
2
- import { LanguageLevel } from "../utils/difficultyConverter";
3
- import { Language } from "../utils/Language";
2
+ import { LanguageLevel } from "../../utils/difficultyConverter";
3
+ import { Language } from "../../utils/Language";
4
+ export interface Buddy {
5
+ id: string;
6
+ name: string;
7
+ description: string;
8
+ avatarUrl: string;
9
+ voiceId: string;
10
+ aiPersonality: string;
11
+ }
4
12
  export interface UserInfo {
5
13
  skill_level_reading: LanguageLevel;
6
14
  skill_level_writing: LanguageLevel;
@@ -10,13 +18,14 @@ export interface UserInfo {
10
18
  skill_level_understanding: LanguageLevel;
11
19
  goal_longterm: string;
12
20
  goal_weekly: string;
13
- study_buddy: string;
21
+ study_buddy: Buddy;
14
22
  story_genre: string;
15
23
  study_duration: number;
16
24
  mother_tongue: Language;
17
25
  motivation_type: string;
18
26
  onboarding_completed: boolean;
19
27
  context_menu_on_select: boolean;
28
+ user_name?: string;
20
29
  }
21
30
  export declare class SettingsController {
22
31
  private pluginId;
@@ -24,7 +33,6 @@ export declare class SettingsController {
24
33
  constructor(supabase: SupabaseClient, pluginId: string);
25
34
  private fetchSettings;
26
35
  setSettings(settings: any): Promise<void>;
27
- getUserInfo(): Promise<UserInfo>;
28
36
  /**
29
37
  * Get the settings for the plugin. T can be any type of settings, UserSettings or SystemSettings.
30
38
  * @param defaultSettings The default settings to use if no settings are found.
@@ -26,31 +26,6 @@ export class SettingsController {
26
26
  yield this.supabase.from("plugin_settings").upsert({ plugin_id: this.pluginId, settings });
27
27
  });
28
28
  }
29
- getUserInfo() {
30
- return __awaiter(this, void 0, void 0, function* () {
31
- const { data } = yield this.supabase.from("profiles").select("*");
32
- if (!data || data.length === 0) {
33
- return {
34
- mother_tongue: "en",
35
- skill_level_listening: "Pre-A1",
36
- skill_level_reading: "Pre-A1",
37
- skill_level_speaking: "Pre-A1",
38
- skill_level_writing: "Pre-A1",
39
- skill_level_understanding: "Pre-A1",
40
- skill_level_grammar: "Pre-A1",
41
- goal_longterm: "",
42
- goal_weekly: "",
43
- study_buddy: "clarence",
44
- story_genre: "adventure",
45
- study_duration: 30,
46
- motivation_type: "self-motivated",
47
- onboarding_completed: false,
48
- context_menu_on_select: false,
49
- };
50
- }
51
- return data[0].settings;
52
- });
53
- }
54
29
  /**
55
30
  * Get the settings for the plugin. T can be any type of settings, UserSettings or SystemSettings.
56
31
  * @param defaultSettings The default settings to use if no settings are found.
@@ -1,15 +1,6 @@
1
1
  import { SupabaseClient } from '@supabase/supabase-js';
2
- import { RimoriClient } from "../plugin/RimoriClient";
2
+ import { RimoriClient } from "../../plugin/RimoriClient";
3
3
  import { ObjectRequest } from "./ObjectController";
4
- export interface BasicAssignment<T> {
5
- id: string;
6
- createdAt: Date;
7
- topic: string;
8
- createdBy: string;
9
- verified: boolean;
10
- keywords: any;
11
- data: T;
12
- }
13
4
  export interface SharedContentObjectRequest extends ObjectRequest {
14
5
  fixedProperties?: Record<string, string | number | boolean>;
15
6
  }
@@ -26,10 +17,10 @@ export declare class SharedContentController {
26
17
  * @param privateTopic - An optional flag to indicate if the topic should be private and only be visible to the user.
27
18
  * @returns The new shared content.
28
19
  */
29
- getNewSharedContent<T>(contentType: string, generatorInstructions: SharedContentObjectRequest, filter?: SharedContentFilter, privateTopic?: boolean): Promise<BasicAssignment<T>>;
20
+ getNewSharedContent<T>(contentType: string, generatorInstructions: SharedContentObjectRequest, filter?: SharedContentFilter, privateTopic?: boolean): Promise<SharedContent<T>>;
30
21
  private getGeneratorInstructions;
31
22
  private getCompletedTopics;
32
- getSharedContent<T>(contentType: string, id: string): Promise<BasicAssignment<T>>;
23
+ getSharedContent<T>(contentType: string, id: string): Promise<SharedContent<T>>;
33
24
  completeSharedContent(contentType: string, assignmentId: string): Promise<void>;
34
25
  /**
35
26
  * Fetch shared content from the database based on optional filters.
@@ -38,19 +29,19 @@ export declare class SharedContentController {
38
29
  * @param limit - Optional limit for the number of results.
39
30
  * @returns Array of shared content matching the criteria.
40
31
  */
41
- getSharedContentList<T>(contentType: string, filter?: SharedContentFilter, limit?: number): Promise<BasicAssignment<T>[]>;
32
+ getSharedContentList<T>(contentType: string, filter?: SharedContentFilter, limit?: number): Promise<SharedContent<T>[]>;
42
33
  /**
43
34
  * Insert new shared content into the database.
44
35
  * @param param
45
36
  * @param param.contentType - The type of content to insert.
46
- * @param param.topic - The topic of the content.
37
+ * @param param.title - The title of the content.
47
38
  * @param param.keywords - Keywords associated with the content.
48
39
  * @param param.data - The content data to store.
49
40
  * @param param.privateTopic - Optional flag to indicate if the topic should be private.
50
41
  * @returns The inserted shared content.
51
42
  * @throws {Error} if insertion fails.
52
43
  */
53
- createSharedContent<T>({ contentType, topic, keywords, data, privateTopic }: Omit<SharedContent<T>, 'id'>): Promise<BasicAssignment<T>>;
44
+ createSharedContent<T>({ contentType, title, keywords, data, privateTopic }: Omit<SharedContent<T>, 'id'>): Promise<SharedContent<T>>;
54
45
  /**
55
46
  * Update existing shared content in the database.
56
47
  * @param id - The ID of the content to update.
@@ -58,14 +49,14 @@ export declare class SharedContentController {
58
49
  * @returns The updated shared content.
59
50
  * @throws {Error} if update fails.
60
51
  */
61
- updateSharedContent<T>(id: string, updates: Partial<SharedContent<T>>): Promise<BasicAssignment<T>>;
52
+ updateSharedContent<T>(id: string, updates: Partial<SharedContent<T>>): Promise<SharedContent<T>>;
62
53
  /**
63
54
  * Soft delete shared content by setting the deleted_at timestamp.
64
55
  * @param id - The ID of the content to delete.
65
56
  * @returns The deleted shared content record.
66
57
  * @throws {Error} if deletion fails or content not found.
67
58
  */
68
- removeSharedContent(id: string): Promise<BasicAssignment<any>>;
59
+ removeSharedContent(id: string): Promise<SharedContent<any>>;
69
60
  }
70
61
  /**
71
62
  * Interface representing shared content in the system.
@@ -76,8 +67,8 @@ export interface SharedContent<T> {
76
67
  id: string;
77
68
  /** The type/category of the content (e.g. 'grammar_exercises', 'flashcards', etc.) */
78
69
  contentType: string;
79
- /** The human readable title/topic of the content */
80
- topic: string;
70
+ /** The human readable title of the content */
71
+ title: string;
81
72
  /** Array of keywords/tags associated with the content for search and categorization */
82
73
  keywords: string[];
83
74
  /** The actual content data of type T */
@@ -46,14 +46,14 @@ export class SharedContentController {
46
46
  // generate new assignments
47
47
  const fullInstructions = yield this.getGeneratorInstructions(contentType, generatorInstructions, filter);
48
48
  console.log('fullInstructions:', fullInstructions);
49
- const instructions = yield this.rimoriClient.llm.getObject(fullInstructions);
49
+ const instructions = yield this.rimoriClient.ai.getObject(fullInstructions);
50
50
  console.log('instructions:', instructions);
51
51
  const { data: newAssignment, error: insertError } = yield this.supabase.from("shared_content").insert({
52
52
  private: privateTopic,
53
53
  content_type: contentType,
54
- topic: instructions.topic,
54
+ title: instructions.title,
55
55
  keywords: instructions.keywords.map(({ text }) => text),
56
- data: Object.assign(Object.assign(Object.assign({}, instructions), { topic: undefined, keywords: undefined }), generatorInstructions.fixedProperties),
56
+ data: Object.assign(Object.assign(Object.assign({}, instructions), { title: undefined, keywords: undefined }), generatorInstructions.fixedProperties),
57
57
  }).select();
58
58
  if (insertError) {
59
59
  console.error('error inserting new assignment:', insertError);
@@ -67,7 +67,7 @@ export class SharedContentController {
67
67
  const completedTopics = yield this.getCompletedTopics(contentType, filter);
68
68
  generatorInstructions.instructions += `
69
69
  The following topics are already taken: ${completedTopics.join(', ')}`;
70
- generatorInstructions.tool.topic = {
70
+ generatorInstructions.tool.title = {
71
71
  type: "string",
72
72
  description: "What the topic is about. Short. ",
73
73
  };
@@ -81,7 +81,7 @@ export class SharedContentController {
81
81
  getCompletedTopics(contentType, filter) {
82
82
  return __awaiter(this, void 0, void 0, function* () {
83
83
  const query = this.supabase.from("shared_content")
84
- .select("topic, keywords, scc:shared_content_completed(id)")
84
+ .select("title, keywords, scc:shared_content_completed(id)")
85
85
  .eq('content_type', contentType)
86
86
  .not('scc.id', 'is', null)
87
87
  .is('deleted_at', null);
@@ -93,7 +93,7 @@ export class SharedContentController {
93
93
  console.error('error fetching old assignments:', error);
94
94
  return [];
95
95
  }
96
- return oldAssignments.map(({ topic, keywords }) => `${topic}(${keywords.join(',')})`);
96
+ return oldAssignments.map(({ title, keywords }) => `${title}(${keywords.join(',')})`);
97
97
  });
98
98
  }
99
99
  getSharedContent(contentType, id) {
@@ -136,7 +136,7 @@ export class SharedContentController {
136
136
  * Insert new shared content into the database.
137
137
  * @param param
138
138
  * @param param.contentType - The type of content to insert.
139
- * @param param.topic - The topic of the content.
139
+ * @param param.title - The title of the content.
140
140
  * @param param.keywords - Keywords associated with the content.
141
141
  * @param param.data - The content data to store.
142
142
  * @param param.privateTopic - Optional flag to indicate if the topic should be private.
@@ -144,11 +144,11 @@ export class SharedContentController {
144
144
  * @throws {Error} if insertion fails.
145
145
  */
146
146
  createSharedContent(_a) {
147
- return __awaiter(this, arguments, void 0, function* ({ contentType, topic, keywords, data, privateTopic }) {
147
+ return __awaiter(this, arguments, void 0, function* ({ contentType, title, keywords, data, privateTopic }) {
148
148
  const { data: newContent, error } = yield this.supabase.from("shared_content").insert({
149
149
  private: privateTopic,
150
150
  content_type: contentType,
151
- topic,
151
+ title,
152
152
  keywords,
153
153
  data,
154
154
  }).select();
@@ -171,8 +171,8 @@ export class SharedContentController {
171
171
  const updateData = {};
172
172
  if (updates.contentType)
173
173
  updateData.content_type = updates.contentType;
174
- if (updates.topic)
175
- updateData.topic = updates.topic;
174
+ if (updates.title)
175
+ updateData.title = updates.title;
176
176
  if (updates.keywords)
177
177
  updateData.keywords = updates.keywords;
178
178
  if (updates.data)
@@ -0,0 +1,13 @@
1
+ export * from "../fromRimori/PluginTypes";
2
+ export * from "../plugin/PluginController";
3
+ export * from "../plugin/RimoriClient";
4
+ export * from "../utils/difficultyConverter";
5
+ export * from "../utils/Language";
6
+ export * from "../utils/PluginUtils";
7
+ export * from "../worker/WorkerSetup";
8
+ export { EventBusMessage } from "../fromRimori/EventBus";
9
+ export { Buddy, UserInfo } from "./controller/SettingsController";
10
+ export { SharedContent } from "./controller/SharedContentController";
11
+ export { Message, OnLLMResponse, ToolInvocation } from "./controller/AIController";
12
+ export { MacroAccomplishmentPayload, MicroAccomplishmentPayload } from "../plugin/AccomplishmentHandler";
13
+ export { Tool } from "../fromRimori/PluginTypes";
@@ -0,0 +1,8 @@
1
+ // Core functionality exports
2
+ export * from "../fromRimori/PluginTypes";
3
+ export * from "../plugin/PluginController";
4
+ export * from "../plugin/RimoriClient";
5
+ export * from "../utils/difficultyConverter";
6
+ export * from "../utils/Language";
7
+ export * from "../utils/PluginUtils";
8
+ export * from "../worker/WorkerSetup";
@@ -52,7 +52,7 @@ export declare class EventBusHandler {
52
52
  * @param topics - The topic of the event.
53
53
  * @param handler - The handler to be called when the event is emitted.
54
54
  * @param ignoreSender - The senders to ignore.
55
- * @returns The ids of the listeners.
55
+ * @returns An EventListener object containing an off() method to unsubscribe the listeners.
56
56
  */
57
57
  on<T = EventPayload>(topics: string | string[], handler: EventHandler<T>, ignoreSender?: string[]): EventListener;
58
58
  /**
@@ -60,9 +60,9 @@ export declare class EventBusHandler {
60
60
  * @param sender - The sender of the event.
61
61
  * @param topic - The topic of the event.
62
62
  * @param handler - The handler to be called when the event is received. The handler returns the data to be emitted. Can be a static object or a function.
63
- * @returns The ids of the listeners.
63
+ * @returns An EventListener object containing an off() method to unsubscribe the listeners.
64
64
  */
65
- respond(sender: string, topic: string, handler: EventPayload | ((data: EventBusMessage) => EventPayload | Promise<EventPayload>)): EventListener;
65
+ respond(sender: string, topic: string | string[], handler: EventPayload | ((data: EventBusMessage) => EventPayload | Promise<EventPayload>)): EventListener;
66
66
  /**
67
67
  * Subscribes to an event on the event bus. The handler will be called once and then removed.
68
68
  * @param topic - The topic of the event.
@@ -90,7 +90,7 @@ export class EventBusHandler {
90
90
  * @param topics - The topic of the event.
91
91
  * @param handler - The handler to be called when the event is emitted.
92
92
  * @param ignoreSender - The senders to ignore.
93
- * @returns The ids of the listeners.
93
+ * @returns An EventListener object containing an off() method to unsubscribe the listeners.
94
94
  */
95
95
  on(topics, handler, ignoreSender = []) {
96
96
  const ids = this.toArray(topics).map(topic => {
@@ -117,16 +117,33 @@ export class EventBusHandler {
117
117
  * @param sender - The sender of the event.
118
118
  * @param topic - The topic of the event.
119
119
  * @param handler - The handler to be called when the event is received. The handler returns the data to be emitted. Can be a static object or a function.
120
- * @returns The ids of the listeners.
120
+ * @returns An EventListener object containing an off() method to unsubscribe the listeners.
121
121
  */
122
122
  respond(sender, topic, handler) {
123
- const listener = this.on(topic, (data) => __awaiter(this, void 0, void 0, function* () {
124
- const response = typeof handler === "function" ? yield handler(data) : handler;
125
- this.emit(sender, topic, response, data.eventId);
126
- }), [sender]);
127
- this.logIfDebug(`Added respond listener ` + sender + " to topic " + topic, { listener, sender });
123
+ const topics = Array.isArray(topic) ? topic : [topic];
124
+ const listeners = topics.map(topic => {
125
+ const blackListedEventIds = [];
126
+ //To allow event communication inside the same plugin the sender needs to be ignored but the events still need to be checked for the same event just reaching the subscriber to prevent infinite loops
127
+ const finalIgnoreSender = !topic.startsWith("self.") ? [sender] : [];
128
+ const listener = this.on(topic, (data) => __awaiter(this, void 0, void 0, function* () {
129
+ if (blackListedEventIds.includes(data.eventId)) {
130
+ // console.log("BLACKLISTED EVENT ID", data.eventId);
131
+ return;
132
+ }
133
+ blackListedEventIds.push(data.eventId);
134
+ if (blackListedEventIds.length > 20) {
135
+ blackListedEventIds.shift();
136
+ }
137
+ const response = typeof handler === "function" ? yield handler(data) : handler;
138
+ this.emit(sender, topic, response, data.eventId);
139
+ }), finalIgnoreSender);
140
+ this.logIfDebug(`Added respond listener ` + sender + " to topic " + topic, { listener, sender });
141
+ return {
142
+ off: () => listener.off()
143
+ };
144
+ });
128
145
  return {
129
- off: () => listener.off()
146
+ off: () => listeners.forEach(listener => listener.off())
130
147
  };
131
148
  }
132
149
  /**