@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
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
// whole configuration of a plugin (from the database)
|
|
2
|
+
export type Plugin = Omit<RimoriPluginConfig, 'context_menu_actions'> & {
|
|
3
|
+
version: string;
|
|
4
|
+
endpoint: string;
|
|
5
|
+
assetEndpoint: string;
|
|
6
|
+
context_menu_actions: MenuEntry[];
|
|
7
|
+
release_channel: "alpha" | "beta" | "stable";
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
// browsable page of a plugin
|
|
11
|
+
export interface PluginPage {
|
|
12
|
+
id: string;
|
|
13
|
+
name: string;
|
|
14
|
+
url: string;
|
|
15
|
+
// Whether the page should be shown in the navbar
|
|
16
|
+
show: boolean;
|
|
17
|
+
description: string;
|
|
18
|
+
root: "vocabulary" | "grammar" | "reading" | "listening" | "watching" | "writing" | "speaking" | "other" | "community";
|
|
19
|
+
// The actions that can be triggered in the plugin
|
|
20
|
+
// The key is the action key. The other entries are additional properties needed when triggering the action
|
|
21
|
+
action?: {
|
|
22
|
+
key: string;
|
|
23
|
+
parameters: ObjectTool;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// a sidebar page of a plugin
|
|
28
|
+
export interface SidebarPage {
|
|
29
|
+
// identifier of the page. Used to know which page to trigger when clicking on the sidebar
|
|
30
|
+
id: string;
|
|
31
|
+
// name of the page. Shown in the settings
|
|
32
|
+
name: string;
|
|
33
|
+
// description of the page. Shown in the settings
|
|
34
|
+
description: string;
|
|
35
|
+
// relative or absolute URL or path to the plugin's page
|
|
36
|
+
url: string;
|
|
37
|
+
// relative or absolute URL or path to the plugin's icon image
|
|
38
|
+
icon: string;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// context menu entry being configured in the plugin configuration
|
|
42
|
+
export interface MenuEntry {
|
|
43
|
+
// id of the plugin that the menu entry belongs to
|
|
44
|
+
plugin_id: string;
|
|
45
|
+
// identifier of the menu entry action. Used to know which entry to trigger when clicking on the context menu
|
|
46
|
+
action_key: string;
|
|
47
|
+
// text of the menu entry. Shown in the context menu
|
|
48
|
+
text: string;
|
|
49
|
+
// icon of the menu entry. Shown in the context menu
|
|
50
|
+
icon?: React.ReactNode;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// an action from the main panel that can be triggered and performs an action in the main panel
|
|
54
|
+
export type MainPanelAction = {
|
|
55
|
+
plugin_id: string;
|
|
56
|
+
action_key: string;
|
|
57
|
+
} & Record<string, string>;
|
|
58
|
+
|
|
59
|
+
// an action from the context menu that can be triggered and performs an action in the sidebar plugin
|
|
60
|
+
export interface ContextMenuAction {
|
|
61
|
+
// selected text when clicking on the context menu
|
|
62
|
+
text: string;
|
|
63
|
+
// id of the plugin that the action belongs to
|
|
64
|
+
plugin_id: string;
|
|
65
|
+
// key of the action. Used to know which action to trigger when clicking on the context menu
|
|
66
|
+
action_key: string
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Rimori plugin structure representing the complete configuration
|
|
71
|
+
* of a Rimori plugin with all metadata and configuration options.
|
|
72
|
+
*/
|
|
73
|
+
export interface RimoriPluginConfig {
|
|
74
|
+
id: string;
|
|
75
|
+
/**
|
|
76
|
+
* Basic information about the plugin including branding and core details.
|
|
77
|
+
*/
|
|
78
|
+
info: {
|
|
79
|
+
/** The display name of the plugin shown to users */
|
|
80
|
+
title: string;
|
|
81
|
+
/** Detailed description introducing the plugin */
|
|
82
|
+
description: string;
|
|
83
|
+
/** relative or absolute URL or path to the plugin's logo/icon image */
|
|
84
|
+
logo: string;
|
|
85
|
+
/** Optional website URL for the plugin's homepage or link to plugins owner for contributions */
|
|
86
|
+
website?: string;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Configuration for different types of pages.
|
|
90
|
+
*/
|
|
91
|
+
pages: {
|
|
92
|
+
/** Optional external URL where the plugin is hosted instead of the default CDN */
|
|
93
|
+
external_hosted_url?: string;
|
|
94
|
+
/** Array of main plugin pages that appear in the application's main navigation (can be disabled using the 'show' flag) */
|
|
95
|
+
main: PluginPage[];
|
|
96
|
+
/** Array of sidebar pages that appear in the sidebar for quick access (can be disabled using the 'show' flag) */
|
|
97
|
+
sidebar: SidebarPage[];
|
|
98
|
+
/** Optional path to the plugin's settings/configuration page */
|
|
99
|
+
settings?: string;
|
|
100
|
+
/** Optional array of event topics the plugin pages can listen to for cross-plugin communication */
|
|
101
|
+
topics?: string[];
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Context menu actions that the plugin registers to appear in right-click menus throughout the application.
|
|
105
|
+
*/
|
|
106
|
+
context_menu_actions: Omit<MenuEntry, "plugin_id">[];
|
|
107
|
+
/**
|
|
108
|
+
* Documentation paths for different types of plugin documentation.
|
|
109
|
+
*/
|
|
110
|
+
documentation: {
|
|
111
|
+
/** Path to the general overview documentation. It's shown upon installation of the plugin. */
|
|
112
|
+
overview_path: string;
|
|
113
|
+
/** Path to user-facing documentation and guides */
|
|
114
|
+
user_path: string;
|
|
115
|
+
/** Path to developer documentation for plugin development */
|
|
116
|
+
developer_path: string;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Configuration for the plugin's web worker if it uses background processing or exposes actions to other plugins.
|
|
120
|
+
*/
|
|
121
|
+
worker?: {
|
|
122
|
+
/** Relative path to the web worker JavaScript file. Mostly it's 'web-worker.js' which is located in the public folder. */
|
|
123
|
+
url: string;
|
|
124
|
+
/** Optional array of event topics the worker should listen to in addition to events having the pluginId in the topic. Can be a wildcard. Example: 'global.topic.*' or 'pluginId.*' */
|
|
125
|
+
topics?: string[];
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// copied from llm edge function
|
|
130
|
+
|
|
131
|
+
export interface Tool {
|
|
132
|
+
name: string;
|
|
133
|
+
description: string;
|
|
134
|
+
parameters: {
|
|
135
|
+
name: string;
|
|
136
|
+
description: string;
|
|
137
|
+
type: "string" | "number" | "boolean";
|
|
138
|
+
}[];
|
|
139
|
+
execute?: (args: Record<string, any>) => Promise<unknown> | unknown | void;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* The tool definition structure is used for LLM function calling and plugin action parameters.
|
|
144
|
+
* It defines the schema for tools that can be used by Language Learning Models (LLMs)
|
|
145
|
+
* and plugin actions.
|
|
146
|
+
*
|
|
147
|
+
* @example
|
|
148
|
+
* ```typescript
|
|
149
|
+
* const flashcardTool: Tool = {
|
|
150
|
+
* total_amount: {
|
|
151
|
+
* type: 'string',
|
|
152
|
+
* enum: ['default', '10', '20', '50'],
|
|
153
|
+
* description: 'Number of flashcards to practice'
|
|
154
|
+
* },
|
|
155
|
+
* deck: {
|
|
156
|
+
* type: 'string',
|
|
157
|
+
* enum: ['latest', 'random', 'oldest', 'mix', 'best_known'],
|
|
158
|
+
* description: 'Type of deck to practice'
|
|
159
|
+
* }
|
|
160
|
+
* };
|
|
161
|
+
* ```
|
|
162
|
+
*
|
|
163
|
+
*/
|
|
164
|
+
export type ObjectTool = {
|
|
165
|
+
[key: string]: ToolParameter;
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Parameter definition for LLM tools and plugin actions.
|
|
170
|
+
* Defines the structure, validation rules, and metadata for individual tool parameters.
|
|
171
|
+
* Used to create type-safe interfaces between LLMs, plugins, and the Rimori platform.
|
|
172
|
+
*/
|
|
173
|
+
interface ToolParameter {
|
|
174
|
+
/** The data type of the parameter - can be primitive, nested object, or array */
|
|
175
|
+
type: ToolParameterType;
|
|
176
|
+
/** Human-readable description of the parameter's purpose and usage */
|
|
177
|
+
description: string;
|
|
178
|
+
/** Optional array of allowed values for enumerated parameters */
|
|
179
|
+
enum?: string[];
|
|
180
|
+
/** Whether the parameter is optional */
|
|
181
|
+
optional?: boolean;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Union type defining all possible parameter types for LLM tools.
|
|
186
|
+
* Supports primitive types, nested objects for complex data structures,
|
|
187
|
+
* and arrays of objects for collections. The tuple notation [{}] indicates
|
|
188
|
+
* arrays of objects with a specific structure.
|
|
189
|
+
*
|
|
190
|
+
* @example Primitive: 'string' | 'number' | 'boolean'
|
|
191
|
+
* @example Nested object: { name: { type: 'string' }, age: { type: 'number' } }
|
|
192
|
+
* @example Array of objects: [{ id: { type: 'string' }, value: { type: 'number' } }]
|
|
193
|
+
*/
|
|
194
|
+
type ToolParameterType =
|
|
195
|
+
| PrimitiveType
|
|
196
|
+
| { [key: string]: ToolParameter } // for nested objects
|
|
197
|
+
| [{ [key: string]: ToolParameter }]; // for arrays of objects (notice the tuple type)
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Primitive data types supported by the LLM tool system.
|
|
201
|
+
* These align with JSON schema primitive types and TypeScript basic types.
|
|
202
|
+
*/
|
|
203
|
+
type PrimitiveType = 'string' | 'number' | 'boolean';
|
package/src/hooks/UseChatHook.ts
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import {
|
|
2
|
+
import { Tool } from "../fromRimori/PluginTypes";
|
|
3
3
|
import { usePlugin } from "../providers/PluginProvider";
|
|
4
|
+
import { Message, ToolInvocation } from "../core/controller/AIController";
|
|
4
5
|
|
|
5
6
|
export function useChat(tools?: Tool[]) {
|
|
6
7
|
const [messages, setMessages] = React.useState<Message[]>([]);
|
|
7
8
|
const [isLoading, setIsLoading] = React.useState(false);
|
|
8
|
-
const {
|
|
9
|
+
const { ai } = usePlugin();
|
|
9
10
|
|
|
10
11
|
const append = (appendMessages: Message[]) => {
|
|
11
|
-
|
|
12
|
+
ai.getSteamedText([...messages, ...appendMessages], (id, message, finished: boolean, toolInvocations?: ToolInvocation[]) => {
|
|
12
13
|
const lastMessage = messages[messages.length - 1];
|
|
13
14
|
setIsLoading(!finished);
|
|
14
15
|
|
|
@@ -16,7 +17,7 @@ export function useChat(tools?: Tool[]) {
|
|
|
16
17
|
lastMessage.content = message;
|
|
17
18
|
setMessages([...messages, lastMessage]);
|
|
18
19
|
} else {
|
|
19
|
-
setMessages([...messages, ...appendMessages, { id, role: 'assistant', content: message, toolInvocations }]);
|
|
20
|
+
setMessages([...messages, ...appendMessages, { id, role: 'assistant', content: message, toolCalls: toolInvocations }]);
|
|
20
21
|
}
|
|
21
22
|
}, tools);
|
|
22
23
|
};
|
package/src/index.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
// Re-export everything
|
|
2
|
-
export * from './core';
|
|
3
2
|
export * from './components';
|
|
4
3
|
export * from "./hooks/UseChatHook";
|
|
5
|
-
export * from "./plugin/
|
|
4
|
+
export * from "./plugin/PluginController";
|
|
6
5
|
export * from "./providers/PluginProvider";
|
|
6
|
+
export * from "./cli/types/DatabaseTypes";
|
|
7
7
|
export * from "./utils/difficultyConverter";
|
|
8
8
|
export * from "./utils/PluginUtils";
|
|
9
|
-
export * from "./
|
|
9
|
+
export * from "./utils/Language";
|
|
10
|
+
export * from "./fromRimori/PluginTypes";
|
|
11
|
+
export { FirstMessages } from "./components/ai/utils";
|
|
@@ -1,19 +1,24 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { createClient, SupabaseClient } from '@supabase/supabase-js';
|
|
2
|
+
import { UserInfo } from '../core/controller/SettingsController';
|
|
3
|
+
import { EventBus, EventBusMessage } from '../fromRimori/EventBus';
|
|
4
|
+
import { Plugin } from '../fromRimori/PluginTypes';
|
|
3
5
|
import { RimoriClient } from "./RimoriClient";
|
|
4
|
-
import { setTheme } from './ThemeSetter';
|
|
5
6
|
import { StandaloneClient } from './StandaloneClient';
|
|
7
|
+
import { setTheme } from './ThemeSetter';
|
|
6
8
|
|
|
7
9
|
// Add declaration for WorkerGlobalScope
|
|
8
10
|
declare const WorkerGlobalScope: any;
|
|
9
11
|
|
|
10
|
-
interface
|
|
12
|
+
export interface RimoriInfo {
|
|
11
13
|
url: string,
|
|
12
14
|
key: string,
|
|
15
|
+
backendUrl: string,
|
|
13
16
|
token: string,
|
|
14
17
|
expiration: Date,
|
|
15
18
|
tablePrefix: string,
|
|
16
19
|
pluginId: string
|
|
20
|
+
installedPlugins: Plugin[]
|
|
21
|
+
profile: UserInfo
|
|
17
22
|
}
|
|
18
23
|
|
|
19
24
|
export class PluginController {
|
|
@@ -21,7 +26,7 @@ export class PluginController {
|
|
|
21
26
|
private static instance: PluginController;
|
|
22
27
|
private communicationSecret: string | null = null;
|
|
23
28
|
private supabase: SupabaseClient | null = null;
|
|
24
|
-
private
|
|
29
|
+
private rimoriInfo: RimoriInfo | null = null;
|
|
25
30
|
private pluginId: string;
|
|
26
31
|
|
|
27
32
|
private constructor(pluginId: string, standalone: boolean) {
|
|
@@ -34,7 +39,7 @@ export class PluginController {
|
|
|
34
39
|
|
|
35
40
|
//no need to forward messages to parent in standalone mode
|
|
36
41
|
if (standalone) return;
|
|
37
|
-
|
|
42
|
+
|
|
38
43
|
window.addEventListener("message", (event) => {
|
|
39
44
|
// console.log("client: message received", event);
|
|
40
45
|
const { topic, sender, data, eventId } = event.data.event as EventBusMessage;
|
|
@@ -78,47 +83,54 @@ export class PluginController {
|
|
|
78
83
|
return this.communicationSecret;
|
|
79
84
|
}
|
|
80
85
|
|
|
81
|
-
public async getClient(): Promise<{ supabase: SupabaseClient,
|
|
86
|
+
public async getClient(): Promise<{ supabase: SupabaseClient, info: RimoriInfo }> {
|
|
82
87
|
if (
|
|
83
88
|
this.supabase &&
|
|
84
|
-
this.
|
|
85
|
-
this.
|
|
89
|
+
this.rimoriInfo &&
|
|
90
|
+
this.rimoriInfo.expiration > new Date()
|
|
86
91
|
) {
|
|
87
|
-
return { supabase: this.supabase,
|
|
92
|
+
return { supabase: this.supabase, info: this.rimoriInfo };
|
|
88
93
|
}
|
|
89
94
|
|
|
90
|
-
const { data } = await EventBus.request<
|
|
91
|
-
this.
|
|
92
|
-
this.supabase = createClient(this.
|
|
95
|
+
const { data } = await EventBus.request<RimoriInfo>(this.pluginId, "global.supabase.requestAccess");
|
|
96
|
+
this.rimoriInfo = data;
|
|
97
|
+
this.supabase = createClient(this.rimoriInfo.url, this.rimoriInfo.key, {
|
|
93
98
|
accessToken: () => Promise.resolve(this.getToken())
|
|
94
99
|
});
|
|
95
100
|
|
|
96
|
-
return { supabase: this.supabase,
|
|
101
|
+
return { supabase: this.supabase, info: this.rimoriInfo };
|
|
97
102
|
}
|
|
98
103
|
|
|
99
104
|
public async getToken() {
|
|
100
|
-
if (this.
|
|
101
|
-
return this.
|
|
105
|
+
if (this.rimoriInfo && this.rimoriInfo.expiration && this.rimoriInfo.expiration > new Date()) {
|
|
106
|
+
return this.rimoriInfo.token;
|
|
102
107
|
}
|
|
103
108
|
|
|
104
109
|
const { data } = await EventBus.request<{ token: string, expiration: Date }>(this.pluginId, "global.supabase.requestAccess");
|
|
105
110
|
|
|
106
|
-
if (!this.
|
|
111
|
+
if (!this.rimoriInfo) {
|
|
107
112
|
throw new Error("Supabase info not found");
|
|
108
113
|
}
|
|
109
114
|
|
|
110
|
-
this.
|
|
111
|
-
this.
|
|
115
|
+
this.rimoriInfo.token = data.token;
|
|
116
|
+
this.rimoriInfo.expiration = data.expiration;
|
|
112
117
|
|
|
113
|
-
return this.
|
|
118
|
+
return this.rimoriInfo.token;
|
|
114
119
|
}
|
|
115
120
|
|
|
116
121
|
public getSupabaseUrl() {
|
|
117
|
-
if (!this.
|
|
122
|
+
if (!this.rimoriInfo) {
|
|
118
123
|
throw new Error("Supabase info not found");
|
|
119
124
|
}
|
|
120
125
|
|
|
121
|
-
return this.
|
|
126
|
+
return this.rimoriInfo.url;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
public getBackendUrl() {
|
|
130
|
+
if (!this.rimoriInfo) {
|
|
131
|
+
throw new Error("Rimori info not found");
|
|
132
|
+
}
|
|
133
|
+
return this.rimoriInfo.backendUrl;
|
|
122
134
|
}
|
|
123
135
|
|
|
124
136
|
public getGlobalEventTopic(preliminaryTopic: string) {
|
|
@@ -138,7 +150,7 @@ export class PluginController {
|
|
|
138
150
|
throw new Error(`The event topic must consist of 3 parts. <pluginId>.<topic area>.<action>. Received: ${preliminaryTopic}`);
|
|
139
151
|
}
|
|
140
152
|
|
|
141
|
-
const topicRoot = this.
|
|
153
|
+
const topicRoot = this.rimoriInfo?.pluginId ?? "global";
|
|
142
154
|
return `${topicRoot}.${preliminaryTopic}`;
|
|
143
155
|
}
|
|
144
156
|
|
|
@@ -1,23 +1,16 @@
|
|
|
1
1
|
import { PostgrestQueryBuilder } from "@supabase/postgrest-js";
|
|
2
2
|
import { SupabaseClient } from "@supabase/supabase-js";
|
|
3
3
|
import { GenericSchema } from "@supabase/supabase-js/dist/module/lib/types";
|
|
4
|
-
import { generateText, Message, OnLLMResponse, streamChatGPT
|
|
5
|
-
import { generateObject as generateObjectFunction, ObjectRequest } from "../controller/ObjectController";
|
|
6
|
-
import { SettingsController, UserInfo } from "../controller/SettingsController";
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
4
|
+
import { generateText, Message, OnLLMResponse, streamChatGPT } from "../core/controller/AIController";
|
|
5
|
+
import { generateObject as generateObjectFunction, ObjectRequest } from "../core/controller/ObjectController";
|
|
6
|
+
import { SettingsController, UserInfo } from "../core/controller/SettingsController";
|
|
7
|
+
import { SharedContent, SharedContentController, SharedContentFilter, SharedContentObjectRequest } from "../core/controller/SharedContentController";
|
|
8
|
+
import { getSTTResponse, getTTSResponse } from "../core/controller/VoiceController";
|
|
9
|
+
import { EventBus, EventBusMessage, EventHandler, EventPayload } from "../fromRimori/EventBus";
|
|
10
|
+
import { Plugin, Tool } from "../fromRimori/PluginTypes";
|
|
10
11
|
import { AccomplishmentHandler, AccomplishmentPayload } from "./AccomplishmentHandler";
|
|
11
|
-
import {
|
|
12
|
-
import { Plugin } from "./fromRimori/PluginTypes";
|
|
13
|
-
import { PluginController } from "./PluginController";
|
|
12
|
+
import { PluginController, RimoriInfo } from "./PluginController";
|
|
14
13
|
|
|
15
|
-
interface RimoriClientOptions {
|
|
16
|
-
pluginController: PluginController;
|
|
17
|
-
supabase: SupabaseClient;
|
|
18
|
-
tablePrefix: string;
|
|
19
|
-
pluginId: string;
|
|
20
|
-
}
|
|
21
14
|
|
|
22
15
|
interface Db {
|
|
23
16
|
from: {
|
|
@@ -66,16 +59,20 @@ export class RimoriClient {
|
|
|
66
59
|
private sharedContentController: SharedContentController;
|
|
67
60
|
private accomplishmentHandler: AccomplishmentHandler;
|
|
68
61
|
private supabaseUrl: string;
|
|
69
|
-
|
|
62
|
+
private installedPlugins: Plugin[];
|
|
63
|
+
private profile: UserInfo;
|
|
70
64
|
public plugin: PluginInterface;
|
|
65
|
+
public db: Db;
|
|
71
66
|
|
|
72
|
-
private constructor(
|
|
73
|
-
this.superbase =
|
|
74
|
-
this.pluginController =
|
|
75
|
-
this.settingsController = new SettingsController(
|
|
67
|
+
private constructor(supabase: SupabaseClient, info: RimoriInfo, pluginController: PluginController) {
|
|
68
|
+
this.superbase = supabase;
|
|
69
|
+
this.pluginController = pluginController;
|
|
70
|
+
this.settingsController = new SettingsController(supabase, info.pluginId);
|
|
76
71
|
this.sharedContentController = new SharedContentController(this.superbase, this);
|
|
77
72
|
this.supabaseUrl = this.pluginController.getSupabaseUrl();
|
|
78
|
-
this.accomplishmentHandler = new AccomplishmentHandler(
|
|
73
|
+
this.accomplishmentHandler = new AccomplishmentHandler(info.pluginId);
|
|
74
|
+
this.installedPlugins = info.installedPlugins;
|
|
75
|
+
this.profile = info.profile;
|
|
79
76
|
|
|
80
77
|
this.from = this.from.bind(this);
|
|
81
78
|
|
|
@@ -83,11 +80,11 @@ export class RimoriClient {
|
|
|
83
80
|
from: this.from,
|
|
84
81
|
storage: this.superbase.storage,
|
|
85
82
|
// functions: this.superbase.functions,
|
|
86
|
-
tablePrefix:
|
|
83
|
+
tablePrefix: info.tablePrefix,
|
|
87
84
|
getTableName: this.getTableName.bind(this),
|
|
88
85
|
}
|
|
89
86
|
this.plugin = {
|
|
90
|
-
pluginId:
|
|
87
|
+
pluginId: info.pluginId,
|
|
91
88
|
setSettings: async (settings: any) => {
|
|
92
89
|
await this.settingsController.setSettings(settings);
|
|
93
90
|
},
|
|
@@ -95,10 +92,10 @@ export class RimoriClient {
|
|
|
95
92
|
return await this.settingsController.getSettings<T>(defaultSettings);
|
|
96
93
|
},
|
|
97
94
|
getInstalled: async (): Promise<Plugin[]> => {
|
|
98
|
-
return
|
|
95
|
+
return this.installedPlugins;
|
|
99
96
|
},
|
|
100
97
|
getUserInfo: async (): Promise<UserInfo> => {
|
|
101
|
-
return this.
|
|
98
|
+
return this.profile;
|
|
102
99
|
}
|
|
103
100
|
}
|
|
104
101
|
}
|
|
@@ -132,11 +129,11 @@ export class RimoriClient {
|
|
|
132
129
|
* Subscribe to an event.
|
|
133
130
|
* @param topic The topic to subscribe to.
|
|
134
131
|
* @param callback The callback to call when the event is emitted.
|
|
135
|
-
* @returns
|
|
132
|
+
* @returns An EventListener object containing an off() method to unsubscribe the listeners.
|
|
136
133
|
*/
|
|
137
134
|
on: <T = EventPayload>(topic: string | string[], callback: EventHandler<T>) => {
|
|
138
135
|
const topics = Array.isArray(topic) ? topic : [topic];
|
|
139
|
-
return topics.map(
|
|
136
|
+
return EventBus.on<T>(topics.map(t => this.pluginController.getGlobalEventTopic(t)), callback);
|
|
140
137
|
},
|
|
141
138
|
/**
|
|
142
139
|
* Subscribe to an event once.
|
|
@@ -151,8 +148,9 @@ export class RimoriClient {
|
|
|
151
148
|
* @param topic The topic to respond to.
|
|
152
149
|
* @param data The data to respond with.
|
|
153
150
|
*/
|
|
154
|
-
respond: <T = EventPayload>(topic: string, data: EventPayload | ((data: EventBusMessage<T>) => EventPayload | Promise<EventPayload>)) => {
|
|
155
|
-
|
|
151
|
+
respond: <T = EventPayload>(topic: string | string[], data: EventPayload | ((data: EventBusMessage<T>) => EventPayload | Promise<EventPayload>)) => {
|
|
152
|
+
const topics = Array.isArray(topic) ? topic : [topic];
|
|
153
|
+
EventBus.respond(this.plugin.pluginId, topics.map(t => this.pluginController.getGlobalEventTopic(t)), data);
|
|
156
154
|
},
|
|
157
155
|
/**
|
|
158
156
|
* Emit an accomplishment.
|
|
@@ -176,14 +174,20 @@ export class RimoriClient {
|
|
|
176
174
|
* @param text Optional text to be used for the action like for example text that the translator would look up.
|
|
177
175
|
*/
|
|
178
176
|
emitSidebarAction: (pluginId: string, actionKey: string, text?: string) => {
|
|
179
|
-
this.event.emit("global.sidebar.triggerAction", { pluginId, actionKey, text });
|
|
177
|
+
this.event.emit("global.sidebar.triggerAction", { plugin_id: pluginId, action_key: actionKey, text });
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
public navigation = {
|
|
182
|
+
toDashboard: () => {
|
|
183
|
+
this.event.emit("global.navigation.triggerToDashboard");
|
|
180
184
|
}
|
|
181
185
|
}
|
|
182
186
|
|
|
183
187
|
public static async getInstance(pluginController: PluginController): Promise<RimoriClient> {
|
|
184
188
|
if (!RimoriClient.instance) {
|
|
185
|
-
const
|
|
186
|
-
RimoriClient.instance = new RimoriClient(
|
|
189
|
+
const client = await pluginController.getClient();
|
|
190
|
+
RimoriClient.instance = new RimoriClient(client.supabase, client.info, pluginController);
|
|
187
191
|
}
|
|
188
192
|
return RimoriClient.instance;
|
|
189
193
|
}
|
|
@@ -201,17 +205,20 @@ export class RimoriClient {
|
|
|
201
205
|
}
|
|
202
206
|
|
|
203
207
|
private getTableName(type: string) {
|
|
208
|
+
if (type.startsWith("global_")) {
|
|
209
|
+
return type.replace("global_", "");
|
|
210
|
+
}
|
|
204
211
|
return this.db.tablePrefix + "_" + type;
|
|
205
212
|
}
|
|
206
213
|
|
|
207
|
-
public
|
|
214
|
+
public ai = {
|
|
208
215
|
getText: async (messages: Message[], tools?: Tool[]): Promise<string> => {
|
|
209
216
|
const token = await this.pluginController.getToken();
|
|
210
|
-
return generateText(this.
|
|
217
|
+
return generateText(this.pluginController.getBackendUrl(), messages, tools || [], token).then(({ messages }) => messages[0].content[0].text);
|
|
211
218
|
},
|
|
212
219
|
getSteamedText: async (messages: Message[], onMessage: OnLLMResponse, tools?: Tool[]) => {
|
|
213
220
|
const token = await this.pluginController.getToken();
|
|
214
|
-
streamChatGPT(this.
|
|
221
|
+
streamChatGPT(this.pluginController.getBackendUrl(), messages, tools || [], onMessage, token);
|
|
215
222
|
},
|
|
216
223
|
getVoice: async (text: string, voice = "alloy", speed = 1, language?: string): Promise<Blob> => {
|
|
217
224
|
const token = await this.pluginController.getToken();
|
|
@@ -240,7 +247,7 @@ export class RimoriClient {
|
|
|
240
247
|
* @param id The id of the shared content item.
|
|
241
248
|
* @returns The shared content item.
|
|
242
249
|
*/
|
|
243
|
-
get: async <T = any>(contentType: string, id: string): Promise<
|
|
250
|
+
get: async <T = any>(contentType: string, id: string): Promise<SharedContent<T>> => {
|
|
244
251
|
return await this.sharedContentController.getSharedContent(contentType, id);
|
|
245
252
|
},
|
|
246
253
|
/**
|
|
@@ -250,7 +257,7 @@ export class RimoriClient {
|
|
|
250
257
|
* @param limit The optional limit for the number of results.
|
|
251
258
|
* @returns The list of shared content items.
|
|
252
259
|
*/
|
|
253
|
-
getList: async <T = any>(contentType: string, filter?: SharedContentFilter, limit?: number): Promise<
|
|
260
|
+
getList: async <T = any>(contentType: string, filter?: SharedContentFilter, limit?: number): Promise<SharedContent<T>[]> => {
|
|
254
261
|
return await this.sharedContentController.getSharedContentList(contentType, filter, limit);
|
|
255
262
|
},
|
|
256
263
|
/**
|
|
@@ -266,7 +273,7 @@ export class RimoriClient {
|
|
|
266
273
|
generatorInstructions: SharedContentObjectRequest,
|
|
267
274
|
filter?: SharedContentFilter,
|
|
268
275
|
privateTopic?: boolean,
|
|
269
|
-
): Promise<
|
|
276
|
+
): Promise<SharedContent<T>> => {
|
|
270
277
|
return await this.sharedContentController.getNewSharedContent(contentType, generatorInstructions, filter, privateTopic);
|
|
271
278
|
},
|
|
272
279
|
/**
|
|
@@ -274,7 +281,7 @@ export class RimoriClient {
|
|
|
274
281
|
* @param content The content to create.
|
|
275
282
|
* @returns The new shared content item.
|
|
276
283
|
*/
|
|
277
|
-
create: async <T = any>(content: Omit<SharedContent<T>, 'id'>): Promise<
|
|
284
|
+
create: async <T = any>(content: Omit<SharedContent<T>, 'id'>): Promise<SharedContent<T>> => {
|
|
278
285
|
return await this.sharedContentController.createSharedContent(content);
|
|
279
286
|
},
|
|
280
287
|
/**
|
|
@@ -283,7 +290,7 @@ export class RimoriClient {
|
|
|
283
290
|
* @param content The content to update.
|
|
284
291
|
* @returns The updated shared content item.
|
|
285
292
|
*/
|
|
286
|
-
update: async <T = any>(id: string, content: Partial<SharedContent<T>>): Promise<
|
|
293
|
+
update: async <T = any>(id: string, content: Partial<SharedContent<T>>): Promise<SharedContent<T>> => {
|
|
287
294
|
return await this.sharedContentController.updateSharedContent(id, content);
|
|
288
295
|
},
|
|
289
296
|
/**
|
|
@@ -299,7 +306,7 @@ export class RimoriClient {
|
|
|
299
306
|
* @param id The id of the shared content item to remove.
|
|
300
307
|
* @returns The removed shared content item.
|
|
301
308
|
*/
|
|
302
|
-
remove: async (id: string): Promise<
|
|
309
|
+
remove: async (id: string): Promise<SharedContent<any>> => {
|
|
303
310
|
return await this.sharedContentController.removeSharedContent(id);
|
|
304
311
|
}
|
|
305
312
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { EventBus } from "./fromRimori/EventBus";
|
|
2
1
|
import { createClient, SupabaseClient } from "@supabase/supabase-js";
|
|
2
|
+
import { EventBus } from "../fromRimori/EventBus";
|
|
3
|
+
import { DEFAULT_ANON_KEY, DEFAULT_ENDPOINT } from "../utils/endpoint";
|
|
3
4
|
|
|
4
5
|
export interface StandaloneConfig {
|
|
5
6
|
url: string,
|
|
@@ -18,14 +19,13 @@ export class StandaloneClient {
|
|
|
18
19
|
|
|
19
20
|
public static async getInstance(): Promise<StandaloneClient> {
|
|
20
21
|
if (!StandaloneClient.instance) {
|
|
21
|
-
const config = await fetch("
|
|
22
|
+
const config = await fetch("https://app.rimori.se/config.json").then(res => res.json()).catch(err => {
|
|
22
23
|
console.warn("Error fetching config.json, using default values", err);
|
|
23
|
-
return {
|
|
24
|
-
SUPABASE_URL: "https://pheptqdoqsdnadgoihvr.supabase.co",
|
|
25
|
-
SUPABASE_ANON_KEY: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InBoZXB0cWRvcXNkbmFkZ29paHZyIiwicm9sZSI6ImFub24iLCJpYXQiOjE3MzE2OTY2ODcsImV4cCI6MjA0NzI3MjY4N30.4GPFAXTF8685FaXISdAPNCIM-H3RGLo8GbyhQpu1mP0",
|
|
26
|
-
}
|
|
27
24
|
});
|
|
28
|
-
StandaloneClient.instance = new StandaloneClient({
|
|
25
|
+
StandaloneClient.instance = new StandaloneClient({
|
|
26
|
+
url: config?.SUPABASE_URL || DEFAULT_ENDPOINT,
|
|
27
|
+
key: config?.SUPABASE_ANON_KEY || DEFAULT_ANON_KEY,
|
|
28
|
+
});
|
|
29
29
|
}
|
|
30
30
|
return StandaloneClient.instance;
|
|
31
31
|
}
|
|
@@ -58,7 +58,10 @@ export class StandaloneClient {
|
|
|
58
58
|
EventBus.respond("standalone", "global.supabase.requestAccess", async () => {
|
|
59
59
|
const session = await supabase.auth.getSession();
|
|
60
60
|
console.log("session", session);
|
|
61
|
-
const { data, error } = await supabase.functions.invoke("plugin-token", {
|
|
61
|
+
const { data, error } = await supabase.functions.invoke("plugin-token", {
|
|
62
|
+
body: { pluginId },
|
|
63
|
+
headers: { authorization: `Bearer ${session.data.session?.access_token}` },
|
|
64
|
+
});
|
|
62
65
|
if (error) {
|
|
63
66
|
throw new Error("Failed to get plugin token. " + error.message);
|
|
64
67
|
}
|
|
@@ -1,16 +1,20 @@
|
|
|
1
1
|
export function setTheme() {
|
|
2
|
-
const urlParams = new URLSearchParams(window.location.search);
|
|
3
|
-
|
|
4
|
-
let theme = urlParams.get('theme');
|
|
5
|
-
if (!theme || theme === 'system') {
|
|
6
|
-
theme = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
|
|
7
|
-
}
|
|
8
|
-
|
|
9
2
|
document.documentElement.classList.add("dark:text-gray-200");
|
|
10
3
|
|
|
11
|
-
if (
|
|
4
|
+
if (isDarkTheme()) {
|
|
12
5
|
document.documentElement.setAttribute("data-theme", "dark");
|
|
13
6
|
document.documentElement.classList.add('dark', "dark:bg-gray-950");
|
|
14
7
|
document.documentElement.style.background = "hsl(var(--background))";
|
|
15
8
|
}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function isDarkTheme(): boolean {
|
|
12
|
+
const urlParams = new URLSearchParams(window.location.search);
|
|
13
|
+
|
|
14
|
+
let theme = urlParams.get('theme');
|
|
15
|
+
if (!theme || theme === 'system') {
|
|
16
|
+
return window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return theme === 'dark';
|
|
16
20
|
}
|