@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.
- package/README.md +128 -45
- package/dist/cli/scripts/init/dev-registration.d.ts +35 -0
- package/dist/cli/scripts/init/dev-registration.js +175 -0
- package/dist/cli/scripts/init/env-setup.d.ts +9 -0
- package/dist/cli/scripts/init/env-setup.js +43 -0
- package/dist/cli/scripts/init/file-operations.d.ts +4 -0
- package/dist/cli/scripts/init/file-operations.js +51 -0
- package/dist/cli/scripts/init/html-cleaner.d.ts +4 -0
- package/dist/cli/scripts/init/html-cleaner.js +38 -0
- package/dist/cli/scripts/init/main.d.ts +2 -0
- package/dist/cli/scripts/init/main.js +159 -0
- package/dist/cli/scripts/init/package-setup.d.ts +32 -0
- package/dist/cli/scripts/init/package-setup.js +75 -0
- package/dist/cli/scripts/init/router-transformer.d.ts +6 -0
- package/dist/cli/scripts/init/router-transformer.js +254 -0
- package/dist/cli/scripts/init/tailwind-config.d.ts +4 -0
- package/dist/cli/scripts/init/tailwind-config.js +56 -0
- package/dist/cli/scripts/init/vite-config.d.ts +20 -0
- package/dist/cli/scripts/init/vite-config.js +54 -0
- package/dist/cli/scripts/release/release-config-upload.d.ts +7 -0
- package/dist/cli/scripts/release/release-config-upload.js +116 -0
- package/dist/cli/scripts/release/release-db-update.d.ts +6 -0
- package/dist/cli/scripts/release/release-db-update.js +100 -0
- package/dist/cli/scripts/release/release-file-upload.d.ts +6 -0
- package/dist/cli/scripts/release/release-file-upload.js +136 -0
- package/dist/cli/scripts/release/release.d.ts +23 -0
- package/dist/cli/scripts/release/release.js +70 -0
- package/dist/cli/types/DatabaseTypes.d.ts +103 -0
- package/dist/cli/types/DatabaseTypes.js +2 -0
- package/dist/components/ai/Assistant.js +4 -4
- package/dist/components/ai/Avatar.d.ts +3 -2
- package/dist/components/ai/Avatar.js +10 -5
- package/dist/components/ai/EmbeddedAssistent/CircleAudioAvatar.js +1 -1
- package/dist/components/ai/EmbeddedAssistent/VoiceRecoder.d.ts +1 -0
- package/dist/components/ai/EmbeddedAssistent/VoiceRecoder.js +12 -6
- package/dist/components/ai/utils.js +0 -1
- package/dist/components/audio/Playbutton.js +3 -3
- package/dist/{core → components}/components/ContextMenu.js +2 -2
- package/dist/components.d.ts +5 -5
- package/dist/components.js +5 -5
- package/dist/core/controller/AIController.d.ts +15 -0
- package/dist/core/controller/AIController.js +120 -0
- package/dist/{controller → core/controller}/ObjectController.d.ts +8 -0
- package/dist/{controller → core/controller}/SettingsController.d.ts +12 -4
- package/dist/{controller → core/controller}/SettingsController.js +0 -25
- package/dist/{controller → core/controller}/SharedContentController.d.ts +10 -19
- package/dist/{controller → core/controller}/SharedContentController.js +11 -11
- package/dist/core/core.d.ts +13 -0
- package/dist/core/core.js +8 -0
- package/dist/{plugin/fromRimori → fromRimori}/EventBus.d.ts +3 -3
- package/dist/{plugin/fromRimori → fromRimori}/EventBus.js +25 -8
- package/dist/fromRimori/PluginTypes.d.ts +171 -0
- package/dist/hooks/UseChatHook.d.ts +2 -1
- package/dist/hooks/UseChatHook.js +3 -3
- package/dist/index.d.ts +5 -3
- package/dist/index.js +4 -3
- package/dist/plugin/AccomplishmentHandler.d.ts +1 -1
- package/dist/plugin/AccomplishmentHandler.js +1 -1
- package/dist/plugin/PluginController.d.ts +16 -3
- package/dist/plugin/PluginController.js +24 -18
- package/dist/plugin/RimoriClient.d.ts +22 -17
- package/dist/plugin/RimoriClient.js +35 -25
- package/dist/plugin/StandaloneClient.js +11 -8
- package/dist/plugin/ThemeSetter.d.ts +1 -0
- package/dist/plugin/ThemeSetter.js +9 -6
- package/dist/providers/PluginProvider.d.ts +3 -0
- package/dist/providers/PluginProvider.js +4 -4
- package/dist/utils/Language.d.ts +2 -1
- package/dist/utils/Language.js +4 -2
- package/dist/utils/difficultyConverter.js +1 -1
- package/dist/utils/endpoint.d.ts +2 -0
- package/dist/utils/endpoint.js +2 -0
- package/dist/worker/WorkerSetup.js +3 -1
- package/example/docs/devdocs.md +231 -0
- package/example/docs/overview.md +29 -0
- package/example/docs/userdocs.md +123 -0
- package/example/rimori.config.ts +89 -0
- package/example/worker/vite.config.ts +23 -0
- package/example/worker/worker.ts +11 -0
- package/package.json +15 -9
- package/src/cli/scripts/init/dev-registration.ts +193 -0
- package/src/cli/scripts/init/env-setup.ts +44 -0
- package/src/cli/scripts/init/file-operations.ts +58 -0
- package/src/cli/scripts/init/html-cleaner.ts +48 -0
- package/src/cli/scripts/init/main.ts +171 -0
- package/src/cli/scripts/init/package-setup.ts +117 -0
- package/src/cli/scripts/init/router-transformer.ts +329 -0
- package/src/cli/scripts/init/tailwind-config.ts +75 -0
- package/src/cli/scripts/init/vite-config.ts +73 -0
- package/src/cli/scripts/release/release-config-upload.ts +114 -0
- package/src/cli/scripts/release/release-db-update.ts +97 -0
- package/src/cli/scripts/release/release-file-upload.ts +138 -0
- package/src/cli/scripts/release/release.ts +69 -0
- package/src/cli/types/DatabaseTypes.ts +117 -0
- package/src/components/ai/Assistant.tsx +4 -4
- package/src/components/ai/Avatar.tsx +24 -7
- package/src/components/ai/EmbeddedAssistent/CircleAudioAvatar.tsx +1 -1
- package/src/components/ai/EmbeddedAssistent/VoiceRecoder.tsx +16 -8
- package/src/components/ai/utils.ts +0 -2
- package/src/components/audio/Playbutton.tsx +3 -3
- package/src/{core → components}/components/ContextMenu.tsx +3 -3
- package/src/components.ts +6 -6
- package/src/core/controller/AIController.ts +122 -0
- package/src/core/controller/ObjectController.ts +115 -0
- package/src/{controller → core/controller}/SettingsController.ts +13 -29
- package/src/{controller → core/controller}/SharedContentController.ts +18 -28
- package/src/core/core.ts +15 -0
- package/src/{plugin/fromRimori → fromRimori}/EventBus.ts +28 -10
- package/src/fromRimori/PluginTypes.ts +203 -0
- package/src/hooks/UseChatHook.ts +5 -4
- package/src/index.ts +5 -3
- package/src/plugin/AccomplishmentHandler.ts +1 -1
- package/src/plugin/PluginController.ts +35 -23
- package/src/plugin/RimoriClient.ts +48 -41
- package/src/plugin/StandaloneClient.ts +11 -8
- package/src/plugin/ThemeSetter.ts +12 -8
- package/src/providers/PluginProvider.tsx +7 -4
- package/src/utils/Language.ts +4 -2
- package/src/utils/difficultyConverter.ts +3 -3
- package/src/utils/endpoint.ts +2 -0
- package/src/worker/WorkerSetup.ts +4 -2
- package/dist/components/PluginController.d.ts +0 -21
- package/dist/components/PluginController.js +0 -116
- package/dist/controller/AIController.d.ts +0 -23
- package/dist/controller/AIController.js +0 -93
- package/dist/controller/SidePluginController.d.ts +0 -3
- package/dist/controller/SidePluginController.js +0 -31
- package/dist/core.d.ts +0 -7
- package/dist/core.js +0 -7
- package/dist/plugin/ContextMenu.d.ts +0 -17
- package/dist/plugin/ContextMenu.js +0 -45
- package/dist/plugin/fromRimori/PluginTypes.d.ts +0 -48
- package/dist/plugin/fromRimori/SupabaseHandler.d.ts +0 -13
- package/dist/plugin/fromRimori/SupabaseHandler.js +0 -55
- package/dist/providers/PluginController.d.ts +0 -21
- package/dist/providers/PluginController.js +0 -116
- package/dist/types/Actions.d.ts +0 -4
- package/dist/types/Actions.js +0 -1
- package/src/controller/AIController.ts +0 -112
- package/src/controller/ObjectController.ts +0 -107
- package/src/controller/SidePluginController.ts +0 -25
- package/src/core.ts +0 -8
- package/src/plugin/fromRimori/PluginTypes.ts +0 -64
- package/src/types/Actions.ts +0 -6
- /package/dist/{core → components}/components/ContextMenu.d.ts +0 -0
- /package/dist/{controller → core/controller}/ObjectController.js +0 -0
- /package/dist/{controller → core/controller}/VoiceController.d.ts +0 -0
- /package/dist/{controller → core/controller}/VoiceController.js +0 -0
- /package/dist/{plugin/fromRimori → fromRimori}/PluginTypes.js +0 -0
- /package/src/{controller → core/controller}/VoiceController.ts +0 -0
- /package/src/{plugin/fromRimori → fromRimori}/readme.md +0 -0
|
@@ -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
|
-
|
|
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: "
|
|
80
|
-
_jsx(FaMicrophone, { size: iconSize, className:
|
|
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
|
});
|
|
@@ -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 '../../
|
|
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 {
|
|
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
|
|
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 "../../
|
|
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.
|
|
87
|
+
client.event.emitSidebarAction(action.plugin_id, action.action_key, position.text);
|
|
88
88
|
} }, index))) }));
|
|
89
89
|
};
|
|
90
90
|
function MenuEntryItem(props) {
|
package/dist/components.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
export * from "./components/
|
|
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";
|
package/dist/components.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
// React components and hooks exports
|
|
2
|
-
export * from "./components/
|
|
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 "
|
|
3
|
-
import { Language } from "
|
|
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:
|
|
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 "
|
|
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<
|
|
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<
|
|
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<
|
|
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.
|
|
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,
|
|
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<
|
|
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<
|
|
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
|
|
80
|
-
|
|
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.
|
|
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
|
-
|
|
54
|
+
title: instructions.title,
|
|
55
55
|
keywords: instructions.keywords.map(({ text }) => text),
|
|
56
|
-
data: Object.assign(Object.assign(Object.assign({}, instructions), {
|
|
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.
|
|
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("
|
|
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(({
|
|
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.
|
|
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,
|
|
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
|
-
|
|
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.
|
|
175
|
-
updateData.
|
|
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
|
|
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
|
|
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
|
|
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
|
|
120
|
+
* @returns An EventListener object containing an off() method to unsubscribe the listeners.
|
|
121
121
|
*/
|
|
122
122
|
respond(sender, topic, handler) {
|
|
123
|
-
const
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
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
|
/**
|