@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.
- package/.prettierignore +35 -0
- package/README.md +77 -71
- package/dist/cli/scripts/init/dev-registration.d.ts +1 -1
- package/dist/cli/scripts/init/dev-registration.js +4 -4
- package/dist/cli/scripts/init/main.js +1 -1
- package/dist/cli/scripts/init/package-setup.d.ts +1 -1
- package/dist/cli/scripts/init/package-setup.js +3 -3
- package/dist/cli/scripts/init/router-transformer.js +19 -12
- package/dist/cli/scripts/init/vite-config.d.ts +2 -2
- package/dist/cli/scripts/init/vite-config.js +2 -2
- package/dist/cli/scripts/release/release-config-upload.js +9 -9
- package/dist/cli/scripts/release/release-db-update.d.ts +1 -1
- package/dist/cli/scripts/release/release-db-update.js +9 -9
- package/dist/cli/scripts/release/release-file-upload.js +2 -2
- package/dist/cli/scripts/release/release.js +2 -2
- package/dist/cli/types/DatabaseTypes.d.ts +2 -2
- package/dist/components/CRUDModal.d.ts +1 -1
- package/dist/components/CRUDModal.js +3 -3
- package/dist/components/MarkdownEditor.js +16 -16
- package/dist/components/Spinner.js +2 -2
- package/dist/components/ai/Assistant.js +7 -8
- package/dist/components/ai/Avatar.d.ts +2 -2
- package/dist/components/ai/Avatar.js +14 -7
- package/dist/components/ai/EmbeddedAssistent/AudioInputField.js +5 -6
- package/dist/components/ai/EmbeddedAssistent/CircleAudioAvatar.d.ts +1 -1
- package/dist/components/ai/EmbeddedAssistent/CircleAudioAvatar.js +1 -2
- package/dist/components/ai/EmbeddedAssistent/TTS/MessageSender.d.ts +1 -2
- package/dist/components/ai/EmbeddedAssistent/TTS/MessageSender.js +4 -2
- package/dist/components/ai/EmbeddedAssistent/TTS/Player.js +1 -1
- package/dist/components/ai/EmbeddedAssistent/VoiceRecoder.js +2 -3
- package/dist/components/audio/Playbutton.js +10 -7
- package/dist/components/components/ContextMenu.d.ts +1 -1
- package/dist/components/components/ContextMenu.js +19 -16
- package/dist/components.d.ts +10 -10
- package/dist/components.js +10 -10
- package/dist/core/controller/AIController.d.ts +2 -2
- package/dist/core/controller/AIController.js +20 -18
- package/dist/core/controller/ExerciseController.d.ts +52 -0
- package/dist/core/controller/ExerciseController.js +73 -0
- package/dist/core/controller/ObjectController.js +5 -5
- package/dist/core/controller/SettingsController.d.ts +22 -7
- package/dist/core/controller/SettingsController.js +73 -8
- package/dist/core/controller/SharedContentController.d.ts +3 -3
- package/dist/core/controller/SharedContentController.js +38 -20
- package/dist/core/controller/VoiceController.js +6 -4
- package/dist/core/core.d.ts +15 -14
- package/dist/core/core.js +7 -7
- package/dist/fromRimori/EventBus.js +23 -23
- package/dist/fromRimori/PluginTypes.d.ts +4 -4
- package/dist/hooks/UseChatHook.d.ts +3 -3
- package/dist/hooks/UseChatHook.js +9 -3
- package/dist/index.d.ts +10 -10
- package/dist/index.js +9 -9
- package/dist/plugin/AccomplishmentHandler.d.ts +5 -5
- package/dist/plugin/AccomplishmentHandler.js +31 -27
- package/dist/plugin/AudioController.d.ts +1 -1
- package/dist/plugin/AudioController.js +6 -6
- package/dist/plugin/Logger.d.ts +5 -0
- package/dist/plugin/Logger.js +65 -13
- package/dist/plugin/PluginController.d.ts +7 -1
- package/dist/plugin/PluginController.js +32 -27
- package/dist/plugin/RimoriClient.d.ts +39 -14
- package/dist/plugin/RimoriClient.js +60 -31
- package/dist/plugin/StandaloneClient.d.ts +1 -1
- package/dist/plugin/StandaloneClient.js +35 -16
- package/dist/plugin/ThemeSetter.js +4 -4
- package/dist/providers/PluginProvider.js +44 -14
- package/dist/utils/Language.js +57 -57
- package/dist/utils/PluginUtils.js +3 -3
- package/dist/utils/difficultyConverter.d.ts +1 -1
- package/dist/utils/difficultyConverter.js +1 -1
- package/dist/utils/endpoint.js +2 -2
- package/dist/worker/WorkerSetup.d.ts +1 -1
- package/dist/worker/WorkerSetup.js +6 -6
- package/eslint.config.js +53 -0
- package/example/docs/devdocs.md +50 -40
- package/example/docs/overview.md +1 -1
- package/example/docs/userdocs.md +4 -1
- package/example/rimori.config.ts +51 -49
- package/example/worker/vite.config.ts +3 -3
- package/example/worker/worker.ts +2 -2
- package/package.json +17 -4
- package/prettier.config.js +8 -0
- package/src/cli/scripts/init/dev-registration.ts +5 -8
- package/src/cli/scripts/init/env-setup.ts +1 -1
- package/src/cli/scripts/init/file-operations.ts +1 -1
- package/src/cli/scripts/init/html-cleaner.ts +2 -5
- package/src/cli/scripts/init/main.ts +16 -13
- package/src/cli/scripts/init/package-setup.ts +11 -15
- package/src/cli/scripts/init/router-transformer.ts +40 -37
- package/src/cli/scripts/init/tailwind-config.ts +17 -26
- package/src/cli/scripts/init/vite-config.ts +3 -3
- package/src/cli/scripts/release/release-config-upload.ts +11 -11
- package/src/cli/scripts/release/release-db-update.ts +12 -12
- package/src/cli/scripts/release/release-file-upload.ts +3 -3
- package/src/cli/scripts/release/release.ts +4 -4
- package/src/cli/types/DatabaseTypes.ts +7 -8
- package/src/components/CRUDModal.tsx +64 -48
- package/src/components/MarkdownEditor.tsx +58 -27
- package/src/components/Spinner.tsx +24 -17
- package/src/components/ai/Assistant.tsx +70 -70
- package/src/components/ai/Avatar.tsx +20 -16
- package/src/components/ai/EmbeddedAssistent/AudioInputField.tsx +63 -54
- package/src/components/ai/EmbeddedAssistent/CircleAudioAvatar.tsx +14 -5
- package/src/components/ai/EmbeddedAssistent/TTS/MessageSender.ts +75 -74
- package/src/components/ai/EmbeddedAssistent/TTS/Player.ts +177 -178
- package/src/components/ai/EmbeddedAssistent/VoiceRecoder.tsx +109 -94
- package/src/components/ai/utils.ts +4 -4
- package/src/components/audio/Playbutton.tsx +101 -93
- package/src/components/components/ContextMenu.tsx +47 -35
- package/src/components.ts +10 -10
- package/src/core/controller/AIController.ts +62 -50
- package/src/core/controller/ExerciseController.ts +98 -0
- package/src/core/controller/ObjectController.ts +15 -10
- package/src/core/controller/SettingsController.ts +89 -16
- package/src/core/controller/SharedContentController.ts +80 -44
- package/src/core/controller/VoiceController.ts +10 -8
- package/src/core/core.ts +15 -15
- package/src/fromRimori/EventBus.ts +76 -47
- package/src/fromRimori/PluginTypes.ts +26 -17
- package/src/fromRimori/readme.md +2 -2
- package/src/hooks/UseChatHook.ts +25 -15
- package/src/index.ts +10 -10
- package/src/plugin/AccomplishmentHandler.ts +53 -35
- package/src/plugin/AudioController.ts +18 -12
- package/src/plugin/Logger.ts +77 -19
- package/src/plugin/PluginController.ts +60 -44
- package/src/plugin/RimoriClient.ts +133 -69
- package/src/plugin/StandaloneClient.ts +51 -24
- package/src/plugin/ThemeSetter.ts +5 -5
- package/src/providers/PluginProvider.tsx +90 -36
- package/src/style.scss +3 -3
- package/src/utils/Language.ts +58 -58
- package/src/utils/PluginUtils.ts +16 -20
- package/src/utils/difficultyConverter.ts +2 -2
- package/src/utils/endpoint.ts +3 -2
- package/src/worker/WorkerSetup.ts +8 -9
- package/tsconfig.json +2 -4
- package/dist/components/LoggerExample.d.ts +0 -6
- package/dist/components/LoggerExample.js +0 -79
- package/dist/core/controller/AudioController.d.ts +0 -0
- package/dist/core/controller/AudioController.js +0 -1
- package/dist/hooks/UseLogger.d.ts +0 -30
- package/dist/hooks/UseLogger.js +0 -122
- package/dist/plugin/LoggerExample.d.ts +0 -16
- package/dist/plugin/LoggerExample.js +0 -140
- package/dist/utils/audioFormats.d.ts +0 -26
- package/dist/utils/audioFormats.js +0 -67
|
@@ -8,22 +8,87 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
10
|
export class SettingsController {
|
|
11
|
-
constructor(supabase, pluginId) {
|
|
11
|
+
constructor(supabase, pluginId, guild) {
|
|
12
12
|
this.supabase = supabase;
|
|
13
13
|
this.pluginId = pluginId;
|
|
14
|
+
this.guild = guild;
|
|
14
15
|
}
|
|
16
|
+
/**
|
|
17
|
+
* Fetches settings based on guild configuration.
|
|
18
|
+
* If guild doesn't allow user settings, fetches guild-level settings.
|
|
19
|
+
* Otherwise, fetches user-specific settings.
|
|
20
|
+
* @returns The settings object or null if not found.
|
|
21
|
+
*/
|
|
15
22
|
fetchSettings() {
|
|
16
23
|
return __awaiter(this, void 0, void 0, function* () {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
24
|
+
var _a;
|
|
25
|
+
const isGuildSetting = !this.guild.allowUserPluginSettings;
|
|
26
|
+
const { data } = yield this.supabase
|
|
27
|
+
.from('plugin_settings')
|
|
28
|
+
.select('*')
|
|
29
|
+
.eq('plugin_id', this.pluginId)
|
|
30
|
+
.eq('guild_id', this.guild.id)
|
|
31
|
+
.eq('is_guild_setting', isGuildSetting)
|
|
32
|
+
.maybeSingle();
|
|
33
|
+
return (_a = data === null || data === void 0 ? void 0 : data.settings) !== null && _a !== void 0 ? _a : null;
|
|
22
34
|
});
|
|
23
35
|
}
|
|
36
|
+
/**
|
|
37
|
+
* Sets settings for the plugin.
|
|
38
|
+
* Automatically saves as guild settings if guild doesn't allow user settings,
|
|
39
|
+
* otherwise saves as user-specific settings.
|
|
40
|
+
* @param settings - The settings object to save.
|
|
41
|
+
* @throws {Error} if RLS blocks the operation.
|
|
42
|
+
*/
|
|
24
43
|
setSettings(settings) {
|
|
25
44
|
return __awaiter(this, void 0, void 0, function* () {
|
|
26
|
-
|
|
45
|
+
var _a;
|
|
46
|
+
const isGuildSetting = !this.guild.allowUserPluginSettings;
|
|
47
|
+
const payload = {
|
|
48
|
+
plugin_id: this.pluginId,
|
|
49
|
+
settings,
|
|
50
|
+
guild_id: this.guild.id,
|
|
51
|
+
is_guild_setting: isGuildSetting,
|
|
52
|
+
};
|
|
53
|
+
if (isGuildSetting) {
|
|
54
|
+
payload.user_id = null;
|
|
55
|
+
}
|
|
56
|
+
// Try UPDATE first (safe with RLS). If nothing updated, INSERT.
|
|
57
|
+
const updateQuery = this.supabase
|
|
58
|
+
.from('plugin_settings')
|
|
59
|
+
.update({ settings })
|
|
60
|
+
.eq('plugin_id', this.pluginId)
|
|
61
|
+
.eq('guild_id', this.guild.id)
|
|
62
|
+
.eq('is_guild_setting', isGuildSetting);
|
|
63
|
+
const { data: updatedRows, error: updateError } = yield (isGuildSetting
|
|
64
|
+
? updateQuery.is('user_id', null).select('id')
|
|
65
|
+
: updateQuery.select('id'));
|
|
66
|
+
if (updateError) {
|
|
67
|
+
if (updateError.code === '42501' || ((_a = updateError.message) === null || _a === void 0 ? void 0 : _a.includes('policy'))) {
|
|
68
|
+
throw new Error(`Cannot set ${isGuildSetting ? 'guild' : 'user'} settings: Permission denied.`);
|
|
69
|
+
}
|
|
70
|
+
// proceed to try insert in case of other issues
|
|
71
|
+
}
|
|
72
|
+
if (updatedRows && updatedRows.length > 0) {
|
|
73
|
+
return; // updated successfully
|
|
74
|
+
}
|
|
75
|
+
// No row updated -> INSERT
|
|
76
|
+
const { error: insertError } = yield this.supabase.from('plugin_settings').insert(payload);
|
|
77
|
+
if (insertError) {
|
|
78
|
+
// In case of race condition (duplicate), try one more UPDATE
|
|
79
|
+
if (insertError.code === '23505' /* unique_violation */) {
|
|
80
|
+
const retry = this.supabase
|
|
81
|
+
.from('plugin_settings')
|
|
82
|
+
.update({ settings })
|
|
83
|
+
.eq('plugin_id', this.pluginId)
|
|
84
|
+
.eq('guild_id', this.guild.id)
|
|
85
|
+
.eq('is_guild_setting', isGuildSetting);
|
|
86
|
+
const { error: retryError } = yield (isGuildSetting ? retry.is('user_id', null) : retry);
|
|
87
|
+
if (!retryError)
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
throw insertError;
|
|
91
|
+
}
|
|
27
92
|
});
|
|
28
93
|
}
|
|
29
94
|
/**
|
|
@@ -33,7 +98,7 @@ export class SettingsController {
|
|
|
33
98
|
*/
|
|
34
99
|
getSettings(defaultSettings) {
|
|
35
100
|
return __awaiter(this, void 0, void 0, function* () {
|
|
36
|
-
const storedSettings = yield this.fetchSettings();
|
|
101
|
+
const storedSettings = (yield this.fetchSettings());
|
|
37
102
|
if (!storedSettings) {
|
|
38
103
|
yield this.setSettings(defaultSettings);
|
|
39
104
|
return defaultSettings;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { SupabaseClient } from '@supabase/supabase-js';
|
|
2
|
-
import { RimoriClient } from
|
|
3
|
-
import { ObjectRequest } from
|
|
2
|
+
import { RimoriClient } from '../../plugin/RimoriClient';
|
|
3
|
+
import { ObjectRequest } from './ObjectController';
|
|
4
4
|
export interface SharedContentObjectRequest extends ObjectRequest {
|
|
5
5
|
fixedProperties?: Record<string, string | number | boolean>;
|
|
6
6
|
}
|
|
@@ -69,7 +69,7 @@ export declare class SharedContentController {
|
|
|
69
69
|
* @returns The inserted shared content.
|
|
70
70
|
* @throws {Error} if insertion fails.
|
|
71
71
|
*/
|
|
72
|
-
createSharedContent<T>({ contentType, title, keywords, data, privateTopic }: Omit<SharedContent<T>, 'id'>): Promise<SharedContent<T>>;
|
|
72
|
+
createSharedContent<T>({ contentType, title, keywords, data, privateTopic, }: Omit<SharedContent<T>, 'id'>): Promise<SharedContent<T>>;
|
|
73
73
|
/**
|
|
74
74
|
* Update existing shared content in the database.
|
|
75
75
|
* @param id - The ID of the content to update.
|
|
@@ -28,8 +28,9 @@ export class SharedContentController {
|
|
|
28
28
|
//this filter is there if the content should be filtered additionally by a column and value
|
|
29
29
|
filter, options) {
|
|
30
30
|
return __awaiter(this, void 0, void 0, function* () {
|
|
31
|
-
let query = this.supabase
|
|
32
|
-
.
|
|
31
|
+
let query = this.supabase
|
|
32
|
+
.from('shared_content')
|
|
33
|
+
.select('*, scc:shared_content_completed(id, state)')
|
|
33
34
|
.eq('content_type', contentType)
|
|
34
35
|
.not('scc.state', 'in', '("completed","ongoing","hidden")')
|
|
35
36
|
.is('deleted_at', null);
|
|
@@ -56,7 +57,7 @@ export class SharedContentController {
|
|
|
56
57
|
console.log('instructions:', instructions);
|
|
57
58
|
//create the shared content object
|
|
58
59
|
const data = {
|
|
59
|
-
id:
|
|
60
|
+
id: 'internal-temp-id-' + Math.random().toString(36).substring(2, 15),
|
|
60
61
|
contentType,
|
|
61
62
|
title: instructions.title,
|
|
62
63
|
keywords: instructions.keywords.map(({ text }) => text),
|
|
@@ -82,20 +83,21 @@ export class SharedContentController {
|
|
|
82
83
|
generatorInstructions.instructions += `
|
|
83
84
|
The following topics are already taken: ${completedTopics.join(', ')}`;
|
|
84
85
|
generatorInstructions.tool.title = {
|
|
85
|
-
type:
|
|
86
|
-
description:
|
|
86
|
+
type: 'string',
|
|
87
|
+
description: 'What the topic is about. Short. ',
|
|
87
88
|
};
|
|
88
89
|
generatorInstructions.tool.keywords = {
|
|
89
|
-
type: [{ text: { type:
|
|
90
|
-
description:
|
|
90
|
+
type: [{ text: { type: 'string' } }],
|
|
91
|
+
description: 'Keywords around the topic of the assignment.',
|
|
91
92
|
};
|
|
92
93
|
return generatorInstructions;
|
|
93
94
|
});
|
|
94
95
|
}
|
|
95
96
|
getCompletedTopics(contentType, filter) {
|
|
96
97
|
return __awaiter(this, void 0, void 0, function* () {
|
|
97
|
-
const query = this.supabase
|
|
98
|
-
.
|
|
98
|
+
const query = this.supabase
|
|
99
|
+
.from('shared_content')
|
|
100
|
+
.select('title, keywords, scc:shared_content_completed(id)')
|
|
99
101
|
.eq('content_type', contentType)
|
|
100
102
|
.not('scc.id', 'is', null)
|
|
101
103
|
.is('deleted_at', null);
|
|
@@ -112,7 +114,13 @@ export class SharedContentController {
|
|
|
112
114
|
}
|
|
113
115
|
getSharedContent(contentType, id) {
|
|
114
116
|
return __awaiter(this, void 0, void 0, function* () {
|
|
115
|
-
const { data, error } = yield this.supabase
|
|
117
|
+
const { data, error } = yield this.supabase
|
|
118
|
+
.from('shared_content')
|
|
119
|
+
.select()
|
|
120
|
+
.eq('content_type', contentType)
|
|
121
|
+
.eq('id', id)
|
|
122
|
+
.is('deleted_at', null)
|
|
123
|
+
.single();
|
|
116
124
|
if (error) {
|
|
117
125
|
console.error('error fetching shared content:', error);
|
|
118
126
|
throw new Error('error fetching shared content');
|
|
@@ -124,7 +132,7 @@ export class SharedContentController {
|
|
|
124
132
|
return __awaiter(this, void 0, void 0, function* () {
|
|
125
133
|
// Idempotent completion: upsert on (id, user_id) so repeated calls don't fail
|
|
126
134
|
const { error } = yield this.supabase
|
|
127
|
-
.from(
|
|
135
|
+
.from('shared_content_completed')
|
|
128
136
|
.upsert({ content_type: contentType, id: assignmentId }, { onConflict: 'id' });
|
|
129
137
|
if (error) {
|
|
130
138
|
console.error('error completing shared content:', error);
|
|
@@ -153,9 +161,7 @@ export class SharedContentController {
|
|
|
153
161
|
if (bookmarked !== undefined)
|
|
154
162
|
payload.bookmarked = bookmarked;
|
|
155
163
|
// Prefer upsert, fall back to insert/update if upsert not allowed
|
|
156
|
-
const { error } = yield this.supabase
|
|
157
|
-
.from('shared_content_completed')
|
|
158
|
-
.upsert(payload, { onConflict: 'id' });
|
|
164
|
+
const { error } = yield this.supabase.from('shared_content_completed').upsert(payload, { onConflict: 'id' });
|
|
159
165
|
if (error) {
|
|
160
166
|
console.error('error updating shared content state:', error);
|
|
161
167
|
throw new Error('error updating shared content state');
|
|
@@ -171,7 +177,12 @@ export class SharedContentController {
|
|
|
171
177
|
*/
|
|
172
178
|
getSharedContentList(contentType, filter, limit) {
|
|
173
179
|
return __awaiter(this, void 0, void 0, function* () {
|
|
174
|
-
const query = this.supabase
|
|
180
|
+
const query = this.supabase
|
|
181
|
+
.from('shared_content')
|
|
182
|
+
.select('*')
|
|
183
|
+
.eq('content_type', contentType)
|
|
184
|
+
.is('deleted_at', null)
|
|
185
|
+
.limit(limit !== null && limit !== void 0 ? limit : 30);
|
|
175
186
|
if (filter) {
|
|
176
187
|
query.contains('data', filter);
|
|
177
188
|
}
|
|
@@ -195,14 +206,17 @@ export class SharedContentController {
|
|
|
195
206
|
* @throws {Error} if insertion fails.
|
|
196
207
|
*/
|
|
197
208
|
createSharedContent(_a) {
|
|
198
|
-
return __awaiter(this, arguments, void 0, function* ({ contentType, title, keywords, data, privateTopic }) {
|
|
199
|
-
const { data: newContent, error } = yield this.supabase
|
|
209
|
+
return __awaiter(this, arguments, void 0, function* ({ contentType, title, keywords, data, privateTopic, }) {
|
|
210
|
+
const { data: newContent, error } = yield this.supabase
|
|
211
|
+
.from('shared_content')
|
|
212
|
+
.insert({
|
|
200
213
|
private: privateTopic,
|
|
201
214
|
content_type: contentType,
|
|
202
215
|
title,
|
|
203
216
|
keywords,
|
|
204
217
|
data,
|
|
205
|
-
})
|
|
218
|
+
})
|
|
219
|
+
.select();
|
|
206
220
|
if (error) {
|
|
207
221
|
console.error('error inserting shared content:', error);
|
|
208
222
|
throw new Error('error inserting shared content');
|
|
@@ -230,7 +244,11 @@ export class SharedContentController {
|
|
|
230
244
|
updateData.data = updates.data;
|
|
231
245
|
if (updates.privateTopic !== undefined)
|
|
232
246
|
updateData.private = updates.privateTopic;
|
|
233
|
-
const { data: updatedContent, error } = yield this.supabase
|
|
247
|
+
const { data: updatedContent, error } = yield this.supabase
|
|
248
|
+
.from('shared_content')
|
|
249
|
+
.update(updateData)
|
|
250
|
+
.eq('id', id)
|
|
251
|
+
.select();
|
|
234
252
|
if (error) {
|
|
235
253
|
console.error('error updating shared content:', error);
|
|
236
254
|
throw new Error('error updating shared content');
|
|
@@ -250,7 +268,7 @@ export class SharedContentController {
|
|
|
250
268
|
removeSharedContent(id) {
|
|
251
269
|
return __awaiter(this, void 0, void 0, function* () {
|
|
252
270
|
const { data: deletedContent, error } = yield this.supabase
|
|
253
|
-
.from(
|
|
271
|
+
.from('shared_content')
|
|
254
272
|
.update({ deleted_at: new Date().toISOString() })
|
|
255
273
|
.eq('id', id)
|
|
256
274
|
.select();
|
|
@@ -13,9 +13,11 @@ export function getSTTResponse(backendUrl, audio, token) {
|
|
|
13
13
|
formData.append('file', audio);
|
|
14
14
|
return yield fetch(`${backendUrl}/voice/stt`, {
|
|
15
15
|
method: 'POST',
|
|
16
|
-
headers: {
|
|
16
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
17
17
|
body: formData,
|
|
18
|
-
})
|
|
18
|
+
})
|
|
19
|
+
.then((r) => r.json())
|
|
20
|
+
.then((r) => {
|
|
19
21
|
// console.log("STT response: ", r);
|
|
20
22
|
return r.text;
|
|
21
23
|
});
|
|
@@ -27,9 +29,9 @@ export function getTTSResponse(backendUrl, request, token) {
|
|
|
27
29
|
method: 'POST',
|
|
28
30
|
headers: {
|
|
29
31
|
'Content-Type': 'application/json',
|
|
30
|
-
|
|
32
|
+
Authorization: `Bearer ${token}`,
|
|
31
33
|
},
|
|
32
34
|
body: JSON.stringify(request),
|
|
33
|
-
}).then(r => r.blob());
|
|
35
|
+
}).then((r) => r.blob());
|
|
34
36
|
});
|
|
35
37
|
}
|
package/dist/core/core.d.ts
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
export * from
|
|
2
|
-
export * from
|
|
3
|
-
export * from
|
|
4
|
-
export * from
|
|
5
|
-
export * from
|
|
6
|
-
export * from
|
|
7
|
-
export * from
|
|
8
|
-
export { EventBusMessage } from
|
|
9
|
-
export { Buddy, UserInfo } from
|
|
10
|
-
export { SharedContent } from
|
|
11
|
-
export {
|
|
12
|
-
export {
|
|
13
|
-
export {
|
|
14
|
-
export {
|
|
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 { Exercise, TriggerAction } from './controller/ExerciseController';
|
|
12
|
+
export { Message, OnLLMResponse, ToolInvocation } from './controller/AIController';
|
|
13
|
+
export { MacroAccomplishmentPayload, MicroAccomplishmentPayload } from '../plugin/AccomplishmentHandler';
|
|
14
|
+
export { Tool } from '../fromRimori/PluginTypes';
|
|
15
|
+
export { SharedContentObjectRequest } from './controller/SharedContentController';
|
package/dist/core/core.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// Core functionality exports
|
|
2
|
-
export * from
|
|
3
|
-
export * from
|
|
4
|
-
export * from
|
|
5
|
-
export * from
|
|
6
|
-
export * from
|
|
7
|
-
export * from
|
|
8
|
-
export * from
|
|
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';
|
|
@@ -12,18 +12,18 @@ export class EventBusHandler {
|
|
|
12
12
|
this.listeners = new Map();
|
|
13
13
|
this.responseResolvers = new Map();
|
|
14
14
|
this.debugEnabled = false;
|
|
15
|
-
this.evName =
|
|
15
|
+
this.evName = '';
|
|
16
16
|
//private constructor
|
|
17
17
|
}
|
|
18
18
|
static getInstance(name) {
|
|
19
19
|
if (!EventBusHandler.instance) {
|
|
20
20
|
EventBusHandler.instance = new EventBusHandler();
|
|
21
|
-
EventBusHandler.instance.on(
|
|
21
|
+
EventBusHandler.instance.on('global.system.requestDebug', () => {
|
|
22
22
|
EventBusHandler.instance.debugEnabled = true;
|
|
23
23
|
console.log(`[${EventBusHandler.instance.evName}] Debug mode enabled. Make sure debugging messages are enabled in the browser console.`);
|
|
24
24
|
});
|
|
25
25
|
}
|
|
26
|
-
if (name && EventBusHandler.instance.evName ===
|
|
26
|
+
if (name && EventBusHandler.instance.evName === '') {
|
|
27
27
|
EventBusHandler.instance.evName = name;
|
|
28
28
|
}
|
|
29
29
|
return EventBusHandler.instance;
|
|
@@ -67,7 +67,7 @@ export class EventBusHandler {
|
|
|
67
67
|
}
|
|
68
68
|
const event = this.createEvent(sender, topic, data, eventId);
|
|
69
69
|
const handlers = this.getMatchingHandlers(event.topic);
|
|
70
|
-
handlers.forEach(handler => {
|
|
70
|
+
handlers.forEach((handler) => {
|
|
71
71
|
if (handler.ignoreSender && handler.ignoreSender.includes(sender)) {
|
|
72
72
|
// console.log("ignore event as its in the ignoreSender list", { event, ignoreList: handler.ignoreSender });
|
|
73
73
|
return;
|
|
@@ -93,7 +93,7 @@ export class EventBusHandler {
|
|
|
93
93
|
* @returns An EventListener object containing an off() method to unsubscribe the listeners.
|
|
94
94
|
*/
|
|
95
95
|
on(topics, handler, ignoreSender = []) {
|
|
96
|
-
const ids = this.toArray(topics).map(topic => {
|
|
96
|
+
const ids = this.toArray(topics).map((topic) => {
|
|
97
97
|
this.logIfDebug(`Subscribing to ` + topic, { ignoreSender });
|
|
98
98
|
if (!this.validateTopic(topic)) {
|
|
99
99
|
this.logAndThrowError(true, `Invalid topic: ` + topic);
|
|
@@ -109,7 +109,7 @@ export class EventBusHandler {
|
|
|
109
109
|
return btoa(JSON.stringify({ topic, id }));
|
|
110
110
|
});
|
|
111
111
|
return {
|
|
112
|
-
off: () => this.off(ids)
|
|
112
|
+
off: () => this.off(ids),
|
|
113
113
|
};
|
|
114
114
|
}
|
|
115
115
|
/**
|
|
@@ -121,10 +121,10 @@ export class EventBusHandler {
|
|
|
121
121
|
*/
|
|
122
122
|
respond(sender, topic, handler) {
|
|
123
123
|
const topics = Array.isArray(topic) ? topic : [topic];
|
|
124
|
-
const listeners = topics.map(topic => {
|
|
124
|
+
const listeners = topics.map((topic) => {
|
|
125
125
|
const blackListedEventIds = [];
|
|
126
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(
|
|
127
|
+
const finalIgnoreSender = !topic.startsWith('self.') ? [sender] : [];
|
|
128
128
|
const listener = this.on(topic, (data) => __awaiter(this, void 0, void 0, function* () {
|
|
129
129
|
if (blackListedEventIds.includes(data.eventId)) {
|
|
130
130
|
// console.log("BLACKLISTED EVENT ID", data.eventId);
|
|
@@ -134,16 +134,16 @@ export class EventBusHandler {
|
|
|
134
134
|
if (blackListedEventIds.length > 20) {
|
|
135
135
|
blackListedEventIds.shift();
|
|
136
136
|
}
|
|
137
|
-
const response = typeof handler ===
|
|
137
|
+
const response = typeof handler === 'function' ? yield handler(data) : handler;
|
|
138
138
|
this.emit(sender, topic, response, data.eventId);
|
|
139
139
|
}), finalIgnoreSender);
|
|
140
|
-
this.logIfDebug(`Added respond listener ` + sender +
|
|
140
|
+
this.logIfDebug(`Added respond listener ` + sender + ' to topic ' + topic, { listener, sender });
|
|
141
141
|
return {
|
|
142
|
-
off: () => listener.off()
|
|
142
|
+
off: () => listener.off(),
|
|
143
143
|
};
|
|
144
144
|
});
|
|
145
145
|
return {
|
|
146
|
-
off: () => listeners.forEach(listener => listener.off())
|
|
146
|
+
off: () => listeners.forEach((listener) => listener.off()),
|
|
147
147
|
};
|
|
148
148
|
}
|
|
149
149
|
/**
|
|
@@ -169,10 +169,10 @@ export class EventBusHandler {
|
|
|
169
169
|
* @param listenerIds - The ids of the listeners to unsubscribe from.
|
|
170
170
|
*/
|
|
171
171
|
off(listenerIds) {
|
|
172
|
-
this.toArray(listenerIds).forEach(fullId => {
|
|
172
|
+
this.toArray(listenerIds).forEach((fullId) => {
|
|
173
173
|
const { topic, id } = JSON.parse(atob(fullId));
|
|
174
174
|
const listeners = this.listeners.get(topic) || new Set();
|
|
175
|
-
listeners.forEach(listener => {
|
|
175
|
+
listeners.forEach((listener) => {
|
|
176
176
|
if (listener.id === Number(id)) {
|
|
177
177
|
listeners.delete(listener);
|
|
178
178
|
this.logIfDebug(`Removed listener ` + fullId, { topic, listenerId: id });
|
|
@@ -197,7 +197,7 @@ export class EventBusHandler {
|
|
|
197
197
|
}
|
|
198
198
|
const event = this.createEvent(sender, topic, data || {});
|
|
199
199
|
this.logIfDebug(`Requesting data from ` + topic, { event });
|
|
200
|
-
return new Promise(resolve => {
|
|
200
|
+
return new Promise((resolve) => {
|
|
201
201
|
this.responseResolvers.set(event.eventId, (value) => resolve(value));
|
|
202
202
|
this.emitInternal(sender, topic, data || {}, event.eventId, true);
|
|
203
203
|
});
|
|
@@ -212,7 +212,7 @@ export class EventBusHandler {
|
|
|
212
212
|
const exact = this.listeners.get(topic) || new Set();
|
|
213
213
|
// Find wildcard matches
|
|
214
214
|
const wildcard = [...this.listeners.entries()]
|
|
215
|
-
.filter(([key]) => key.endsWith(
|
|
215
|
+
.filter(([key]) => key.endsWith('*') && topic.startsWith(key.slice(0, -1)))
|
|
216
216
|
.flatMap(([_, handlers]) => [...handlers]);
|
|
217
217
|
return new Set([...exact, ...wildcard]);
|
|
218
218
|
}
|
|
@@ -223,27 +223,27 @@ export class EventBusHandler {
|
|
|
223
223
|
*/
|
|
224
224
|
validateTopic(topic) {
|
|
225
225
|
// Split event type into parts
|
|
226
|
-
const parts = topic.split(
|
|
226
|
+
const parts = topic.split('.');
|
|
227
227
|
const [plugin, area, action] = parts;
|
|
228
228
|
if (parts.length !== 3) {
|
|
229
|
-
if (parts.length === 1 && plugin ===
|
|
229
|
+
if (parts.length === 1 && plugin === '*') {
|
|
230
230
|
return true;
|
|
231
231
|
}
|
|
232
|
-
if (parts.length === 2 && plugin !==
|
|
232
|
+
if (parts.length === 2 && plugin !== '*' && area === '*') {
|
|
233
233
|
return true;
|
|
234
234
|
}
|
|
235
235
|
this.logAndThrowError(false, `Event type must have 3 parts separated by dots. Received: ` + topic);
|
|
236
236
|
return false;
|
|
237
237
|
}
|
|
238
|
-
if (action ===
|
|
238
|
+
if (action === '*') {
|
|
239
239
|
return true;
|
|
240
240
|
}
|
|
241
241
|
// Validate action part
|
|
242
|
-
const validActions = [
|
|
243
|
-
if (validActions.some(a => action.startsWith(a))) {
|
|
242
|
+
const validActions = ['request', 'create', 'update', 'delete', 'trigger'];
|
|
243
|
+
if (validActions.some((a) => action.startsWith(a))) {
|
|
244
244
|
return true;
|
|
245
245
|
}
|
|
246
|
-
this.logAndThrowError(false, `Invalid event topic name. The action: ` + action +
|
|
246
|
+
this.logAndThrowError(false, `Invalid event topic name. The action: ` + action + '. Must be or start with one of: ' + validActions.join(', '));
|
|
247
247
|
return false;
|
|
248
248
|
}
|
|
249
249
|
logIfDebug(...args) {
|
|
@@ -3,7 +3,7 @@ export type Plugin<T extends {} = {}> = Omit<RimoriPluginConfig<T>, 'context_men
|
|
|
3
3
|
endpoint: string;
|
|
4
4
|
assetEndpoint: string;
|
|
5
5
|
context_menu_actions: MenuEntry[];
|
|
6
|
-
release_channel:
|
|
6
|
+
release_channel: 'alpha' | 'beta' | 'stable';
|
|
7
7
|
};
|
|
8
8
|
export type ActivePlugin = Plugin<{
|
|
9
9
|
active?: boolean;
|
|
@@ -14,7 +14,7 @@ export interface PluginPage {
|
|
|
14
14
|
url: string;
|
|
15
15
|
show: boolean;
|
|
16
16
|
description: string;
|
|
17
|
-
root:
|
|
17
|
+
root: 'vocabulary' | 'grammar' | 'reading' | 'listening' | 'watching' | 'writing' | 'speaking' | 'other' | 'community';
|
|
18
18
|
action?: {
|
|
19
19
|
key: string;
|
|
20
20
|
parameters: ObjectTool;
|
|
@@ -79,7 +79,7 @@ export interface RimoriPluginConfig<T extends {} = {}> {
|
|
|
79
79
|
/**
|
|
80
80
|
* Context menu actions that the plugin registers to appear in right-click menus throughout the application.
|
|
81
81
|
*/
|
|
82
|
-
context_menu_actions: Omit<MenuEntry,
|
|
82
|
+
context_menu_actions: Omit<MenuEntry, 'plugin_id'>[];
|
|
83
83
|
/**
|
|
84
84
|
* Documentation paths for different types of plugin documentation.
|
|
85
85
|
*/
|
|
@@ -107,7 +107,7 @@ export interface Tool {
|
|
|
107
107
|
parameters: {
|
|
108
108
|
name: string;
|
|
109
109
|
description: string;
|
|
110
|
-
type:
|
|
110
|
+
type: 'string' | 'number' | 'boolean';
|
|
111
111
|
}[];
|
|
112
112
|
execute?: (args: Record<string, any>) => Promise<unknown> | unknown | void;
|
|
113
113
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import React from
|
|
2
|
-
import { Tool } from
|
|
3
|
-
import { Message } from
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Tool } from '../fromRimori/PluginTypes';
|
|
3
|
+
import { Message } from '../core/controller/AIController';
|
|
4
4
|
export declare function useChat(tools?: Tool[]): {
|
|
5
5
|
messages: Message[];
|
|
6
6
|
append: (appendMessages: Message[]) => void;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import React from
|
|
2
|
-
import { useRimori } from
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { useRimori } from '../providers/PluginProvider';
|
|
3
3
|
export function useChat(tools) {
|
|
4
4
|
const [messages, setMessages] = React.useState([]);
|
|
5
5
|
const [isLoading, setIsLoading] = React.useState(false);
|
|
@@ -19,5 +19,11 @@ export function useChat(tools) {
|
|
|
19
19
|
}
|
|
20
20
|
}, tools);
|
|
21
21
|
};
|
|
22
|
-
return {
|
|
22
|
+
return {
|
|
23
|
+
messages,
|
|
24
|
+
append,
|
|
25
|
+
isLoading,
|
|
26
|
+
setMessages,
|
|
27
|
+
lastMessage: messages[messages.length - 1],
|
|
28
|
+
};
|
|
23
29
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
export * from './components';
|
|
2
|
-
export * from
|
|
3
|
-
export * from
|
|
4
|
-
export * from
|
|
5
|
-
export * from
|
|
6
|
-
export * from
|
|
7
|
-
export * from
|
|
8
|
-
export * from
|
|
9
|
-
export * from
|
|
10
|
-
export { FirstMessages } from
|
|
11
|
-
export { AudioController } from
|
|
2
|
+
export * from './hooks/UseChatHook';
|
|
3
|
+
export * from './plugin/PluginController';
|
|
4
|
+
export * from './providers/PluginProvider';
|
|
5
|
+
export * from './cli/types/DatabaseTypes';
|
|
6
|
+
export * from './utils/difficultyConverter';
|
|
7
|
+
export * from './utils/PluginUtils';
|
|
8
|
+
export * from './utils/Language';
|
|
9
|
+
export * from './fromRimori/PluginTypes';
|
|
10
|
+
export { FirstMessages } from './components/ai/utils';
|
|
11
|
+
export { AudioController } from './plugin/AudioController';
|
package/dist/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
// Re-export everything
|
|
2
2
|
export * from './components';
|
|
3
|
-
export * from
|
|
4
|
-
export * from
|
|
5
|
-
export * from
|
|
6
|
-
export * from
|
|
7
|
-
export * from
|
|
8
|
-
export * from
|
|
9
|
-
export * from
|
|
10
|
-
export * from
|
|
11
|
-
export { AudioController } from
|
|
3
|
+
export * from './hooks/UseChatHook';
|
|
4
|
+
export * from './plugin/PluginController';
|
|
5
|
+
export * from './providers/PluginProvider';
|
|
6
|
+
export * from './cli/types/DatabaseTypes';
|
|
7
|
+
export * from './utils/difficultyConverter';
|
|
8
|
+
export * from './utils/PluginUtils';
|
|
9
|
+
export * from './utils/Language';
|
|
10
|
+
export * from './fromRimori/PluginTypes';
|
|
11
|
+
export { AudioController } from './plugin/AudioController';
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { EventBusMessage } from
|
|
1
|
+
import { EventBusMessage } from '../fromRimori/EventBus';
|
|
2
2
|
export type AccomplishmentMessage = EventBusMessage<MicroAccomplishmentPayload>;
|
|
3
3
|
export declare const skillCategories: readonly ["reading", "listening", "speaking", "writing", "learning", "community"];
|
|
4
4
|
interface BaseAccomplishmentPayload {
|
|
5
|
-
type:
|
|
5
|
+
type: 'micro' | 'macro';
|
|
6
6
|
skillCategory: (typeof skillCategories)[number];
|
|
7
7
|
accomplishmentKeyword: string;
|
|
8
8
|
description: string;
|
|
@@ -13,10 +13,10 @@ interface BaseAccomplishmentPayload {
|
|
|
13
13
|
}[];
|
|
14
14
|
}
|
|
15
15
|
export interface MicroAccomplishmentPayload extends BaseAccomplishmentPayload {
|
|
16
|
-
type:
|
|
16
|
+
type: 'micro';
|
|
17
17
|
}
|
|
18
18
|
export interface MacroAccomplishmentPayload extends BaseAccomplishmentPayload {
|
|
19
|
-
type:
|
|
19
|
+
type: 'macro';
|
|
20
20
|
errorRatio: number;
|
|
21
21
|
durationMinutes: number;
|
|
22
22
|
}
|
|
@@ -24,7 +24,7 @@ export type AccomplishmentPayload = MicroAccomplishmentPayload | MacroAccomplish
|
|
|
24
24
|
export declare class AccomplishmentHandler {
|
|
25
25
|
private pluginId;
|
|
26
26
|
constructor(pluginId: string);
|
|
27
|
-
emitAccomplishment(payload: Omit<AccomplishmentPayload,
|
|
27
|
+
emitAccomplishment(payload: Omit<AccomplishmentPayload, 'type'>): void;
|
|
28
28
|
private validateAccomplishment;
|
|
29
29
|
private sanitizeAccomplishment;
|
|
30
30
|
private getDecoupledTopic;
|