refactor: deprecate extension type implementation (#1677)

* refactor: deprecate extension type implementation

* chore: update README.md

* refactor: EventName to use the events defined in /types
This commit is contained in:
Louis 2024-01-22 10:26:49 +07:00 committed by GitHub
parent 99d083d84a
commit a50ea4a634
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
34 changed files with 241 additions and 626 deletions

View File

@ -1,348 +1,69 @@
## @janhq/core
> The module includes functions for communicating with core APIs, registering plugin extensions, and exporting type definitions.
> This module includes functions for communicating with core APIs, registering app extensions, and exporting type definitions.
## Usage
### Import the package
```js
// javascript
const core = require("@janhq/core");
// typescript
// Web / extension runtime
import * as core from "@janhq/core";
// Node runtime
import * as node from "@janhq/core/node";
```
### Register Plugin Extensions
Every plugin must define an `init` function in its main entry file to initialize the plugin and register its extensions with the Jan platform.
You can `register` any function as a plugin extension using `CoreServiceAPI` below. For example, the `DataService.GetConversations` entry name can be used to register a function that retrieves conversations.
Once the extension is registered, it can be used by other plugins or components in the Jan platform. For example, a UI component might use the DataService.GetConversations extension to retrieve a list of conversations to display to the user.
```js
import { RegisterExtensionPoint, DataService } from "@janhq/core";
function getConversations() {
// Your logic here
}
export function init({ register }: { register: RegisterExtensionPoint }) {
register(DataService.GetConversations, getConversations.name, getConversations);
}
```
### Interact with Local Data Storage
The Core API allows you to interact with local data storage. Here are a couple of examples of how you can use it:
#### Insert Data
You can use the store.insertOne function to insert data into a specific collection in the local data store.
```js
import { store } from "@janhq/core";
function insertData() {
store.insertOne("conversations", { name: "meow" });
// Insert a new document with { name: "meow" } into the "conversations" collection.
}
```
#### Get Data
To retrieve data from a collection in the local data store, you can use the `store.findOne` or `store.findMany` function. It allows you to filter and retrieve documents based on specific criteria.
store.getOne(collectionName, key) retrieves a single document that matches the provided key in the specified collection.
store.getMany(collectionName, selector, sort) retrieves multiple documents that match the provided selector in the specified collection.
```js
import { store } from "@janhq/core";
function getData() {
const selector = { name: "meow" };
const data = store.findMany("conversations", selector);
// Retrieve documents from the "conversations" collection that match the filter.
}
```
#### Update Data
You can update data in the local store using these functions:
store.updateOne(collectionName, key, update) updates a single document that matches the provided key in the specified collection.
store.updateMany(collectionName, selector, update) updates multiple documents that match the provided selector in the specified collection.
```js
function updateData() {
const selector = { name: "meow" };
const update = { name: "newName" };
store.updateOne("conversations", selector, update);
// Update a document in the "conversations" collection.
}
```
#### Delete Data
You can delete data from the local data store using these functions:
store.deleteOne(collectionName, key) deletes a single document that matches the provided key in the specified collection.
store.deleteMany(collectionName, selector) deletes multiple documents that match the provided selector in the specified collection.
```js
function deleteData() {
const selector = { name: "meow" };
store.deleteOne("conversations", selector);
// Delete a document from the "conversations" collection.
}
```
### Events
You can subscribe to NewMessageRequest events by defining a function to handle the event and registering it with the events object:
```js
import { events } from "@janhq/core";
function handleMessageRequest(message: NewMessageRequest) {
// Your logic here. For example:
// const response = openai.createChatCompletion({...})
}
function registerListener() {
events.on(EventName.OnNewMessageRequest, handleMessageRequest);
}
// Register the listener function with the relevant extension points.
export function init({ register }) {
registerListener();
}
```
In this example, we're defining a function called handleMessageRequest that takes a NewMessageRequest object as its argument. We're also defining a function called registerListener that registers the handleMessageRequest function as a listener for NewMessageRequest events using the on method of the events object.
```js
import { events } from "@janhq/core";
function handleMessageRequest(data: NewMessageRequest) {
// Your logic here. For example:
const response = openai.createChatCompletion({...})
const message: NewMessageResponse = {
...data,
message: response.data.choices[0].message.content
}
// Now emit event so the app can display in the conversation
events.emit(EventName.OnNewMessageResponse, message)
}
```
### Preferences
To register plugin preferences, you can use the preferences object from the @janhq/core package. Here's an example of how to register and retrieve plugin preferences:
```js
import { PluginService, preferences } from "@janhq/core";
const pluginName = "your-first-plugin";
const preferenceKey = "";
const preferenceName = "Your First Preference";
const preferenceDescription = "This is for example only";
const defaultValue = "";
export function init({ register }: { register: RegisterExtensionPoint }) {
// Register preference update handlers. E.g. update plugin instance with new configuration
register(PluginService.OnPreferencesUpdate, pluginName, onPreferencesUpdate);
// Register plugin preferences. E.g. Plugin need apiKey to connect to your service
preferences.registerPreferences <
string >
(register, pluginName, preferenceKey, preferenceName, preferenceDescription, defaultValue);
}
```
In this example, we're registering preference update handlers and plugin preferences using the preferences object. We're also defining a PluginName constant to use as the name of the plugin.
To retrieve the values of the registered preferences, we're using the get method of the preferences object and passing in the name of the plugin and the name of the preference.
```js
import { preferences } from "@janhq/core";
const pluginName = "your-first-plugin";
const preferenceKey = "apiKey";
const setup = async () => {
// Retrieve apiKey
const apiKey: string = (await preferences.get(pluginName, preferenceKey)) ?? "";
};
```
### Access Core API
To access the Core API in your plugin, you can follow the code examples and explanations provided below.
##### Import Core API and Store Module
In your main entry code (e.g., `index.ts`), start by importing the necessary modules and functions from the `@janhq/core` library.
```js
// index.ts
import * as core from "@janhq/core";
```
#### Perform File Operations
The Core API also provides functions to perform file operations. Here are a couple of examples:
#### Download a File
You can download a file from a specified URL and save it with a given file name using the core.downloadFile function.
```js
function downloadModel(url: string, fileName: string, network?: { proxy?: string, ignoreSSL?: boolean }) {
core.downloadFile(url, fileName, network);
}
```
#### Delete a File
To delete a file, you can use the core.deleteFile function, providing the path to the file you want to delete.
```js
function deleteModel(filePath: string) {
core.deleteFile(path);
}
```
#### Execute plugin module in main process
To execute a plugin module in the main process of your application, you can follow the steps outlined below.
##### Import the `core` Object
In your main process code (e.g., `index.ts`), start by importing the `core` object from the `@janhq/core` library.
```js
// index.ts
import * as core from "@janhq/core";
```
##### Define the Module Path
Specify the path to the plugin module you want to execute. This path should lead to the module file (e.g., module.js) that contains the functions you wish to call.
```js
// index.ts
const MODULE_PATH = "data-plugin/dist/module.js";
```
##### Define the Function to Execute
Create a function that will execute a function defined in your plugin module. In the example provided, the function `getConversationMessages` is created to invoke the `getConvMessages` function from the plugin module.
```js
// index.ts
function getConversationMessages(id: number) {
return core.invokePluginFunc(MODULE_PATH, "getConvMessages", id);
}
export function init({ register }: { register: RegisterExtensionPoint }) {
register(DataService.GetConversationMessages, getConversationMessages.name, getConversationMessages);
}
```
##### Define Your Plugin Module
In your plugin module (e.g., module.ts), define the logic for the function you wish to execute. In the example, the function getConvMessages is defined with a placeholder comment indicating where your logic should be implemented.
```js
// module.ts
function getConvMessages(id: number) {
// Your logic here
}
module.exports = {
getConvMessages,
};
```
## CoreService API
The `CoreService` type is an exported union type that includes:
- `StoreService`
- `DataService`
- `InferenceService`
- `ModelManagementService`
- `SystemMonitoringService`
- `PreferenceService`
## StoreService
The `StoreService` enum represents available methods for managing the database store. It includes the following methods:
- `CreateCollection`: Creates a new collection in the data store.
- `DeleteCollection`: Deletes an existing collection from the data store.
- `InsertOne`: Inserts a new value into an existing collection in the data store.
- `UpdateOne`: Updates an existing value in an existing collection in the data store.
- `UpdateMany`: Updates multiple records in a collection in the data store.
- `DeleteOne`: Deletes an existing value from an existing collection in the data store.
- `DeleteMany`: Deletes multiple records in a collection in the data store.
- `FindMany`: Retrieves multiple records from a collection in the data store.
- `FindOne`: Retrieves a single record from a collection in the data store.
## DataService
The `DataService` enum represents methods related to managing conversations and messages. It includes the following methods:
- `GetConversations`: Gets a list of conversations from the data store.
- `CreateConversation`: Creates a new conversation in the data store.
- `DeleteConversation`: Deletes an existing conversation from the data store.
- `CreateMessage`: Creates a new message in an existing conversation in the data store.
- `UpdateMessage`: Updates an existing message in an existing conversation in the data store.
- `GetConversationMessages`: Gets a list of messages for an existing conversation from the data store.
## InferenceService
The `InferenceService` enum exports:
- `InitModel`: Initializes a model for inference.
- `StopModel`: Stops a running inference model.
## ModelManagementService
The `ModelManagementService` enum provides methods for managing models:
- `GetDownloadedModels`: Gets a list of downloaded models.
- `GetAvailableModels`: Gets a list of available models from data store.
- `DeleteModel`: Deletes a downloaded model.
- `DownloadModel`: Downloads a model from the server.
- `SearchModels`: Searches for models on the server.
- `GetConfiguredModels`: Gets configured models from the data store.
- `StoreModel`: Stores a model in the data store.
- `UpdateFinishedDownloadAt`: Updates the finished download time for a model in the data store.
- `GetUnfinishedDownloadModels`: Gets a list of unfinished download models from the data store.
- `GetFinishedDownloadModels`: Gets a list of finished download models from the data store.
- `DeleteDownloadModel`: Deletes a downloaded model from the data store.
- `GetModelById`: Gets a model by its ID from the data store.
## PreferenceService
The `PreferenceService` enum provides methods for managing plugin preferences:
- `ExperimentComponent`: Represents the UI experiment component for a testing function.
## SystemMonitoringService
The `SystemMonitoringService` enum includes methods for monitoring system resources:
- `GetResourcesInfo`: Gets information about system resources.
- `GetCurrentLoad`: Gets the current system load.
## PluginService
The `PluginService` enum includes plugin cycle handlers:
- `OnStart`: Handler for starting. E.g. Create a collection.
- `OnPreferencesUpdate`: Handler for preferences update. E.g. Update instances with new configurations.
For more detailed information on each of these components, please refer to the source code.
## Build an Extension
1. Download an extension template, for example, [https://github.com/janhq/extension-template](https://github.com/janhq/extension-template).
2. Update the source code:
1. Open `index.ts` in your code editor.
2. Rename the extension class from `SampleExtension` to your preferred extension name.
3. Import modules from the core package.
```ts
import * as core from "@janhq/core";
```
4. In the `onLoad()` method, add your code:
```ts
// Example of listening to app events and providing customized inference logic:
import * as core from "@janhq/core";
export default class MyExtension extends BaseExtension {
// On extension load
onLoad() {
core.events.on(MessageEvent.OnMessageSent, (data) => MyExtension.inference(data, this));
}
// Customized inference logic
private static inference(incomingMessage: MessageRequestData) {
// Prepare customized message content
const content: ThreadContent = {
type: ContentType.Text,
text: {
value: "I'm Jan Assistant!",
annotations: [],
},
};
// Modify message and send out
const outGoingMessage: ThreadMessage = {
...incomingMessage,
content
};
}
}
```
3. Build the extension:
1. Navigate to the extension directory.
2. Install dependencies.
```bash
yarn install
```
3. Compile the source code. The following command keeps running in the terminal and rebuilds the extension when you modify the source code.
```bash
yarn build
```
4. Select the generated .tgz from Jan > Settings > Extension > Manual Installation.

View File

@ -1,28 +1,3 @@
// TODO: refactor EventName to use the events defined in /types
/**
* The `EventName` enumeration contains the names of all the available events in the Jan platform.
*/
export enum EventName {
/** The `OnMessageSent` event is emitted when a message is sent. */
OnMessageSent = 'OnMessageSent',
/** The `OnMessageResponse` event is emitted when a message is received. */
OnMessageResponse = 'OnMessageResponse',
/** The `OnMessageUpdate` event is emitted when a message is updated. */
OnMessageUpdate = 'OnMessageUpdate',
/** The `OnModelInit` event is emitted when a model inits. */
OnModelInit = 'OnModelInit',
/** The `OnModelReady` event is emitted when a model ready. */
OnModelReady = 'OnModelReady',
/** The `OnModelFail` event is emitted when a model fails loading. */
OnModelFail = 'OnModelFail',
/** The `OnModelStop` event is emitted when a model start to stop. */
OnModelStop = 'OnModelStop',
/** The `OnModelStopped` event is emitted when a model stopped ok. */
OnModelStopped = 'OnModelStopped',
/** The `OnInferenceStopped` event is emitted when a inference is stopped. */
OnInferenceStopped = 'OnInferenceStopped',
}
/**
* Adds an observer for an event.
*

View File

@ -1,4 +1,4 @@
export enum ExtensionType {
export enum ExtensionTypeEnum {
Assistant = "assistant",
Conversational = "conversational",
Inference = "inference",
@ -6,17 +6,22 @@ export enum ExtensionType {
SystemMonitoring = "systemMonitoring",
}
export interface ExtensionType {
type(): ExtensionTypeEnum | undefined;
}
/**
* Represents a base extension.
* This class should be extended by any class that represents an extension.
*/
export abstract class BaseExtension {
export abstract class BaseExtension implements ExtensionType {
/**
* Returns the type of the extension.
* @returns {ExtensionType} The type of the extension
* Undefined means its not extending any known extension by the application.
*/
abstract type(): ExtensionType | undefined;
type(): ExtensionTypeEnum | undefined {
return undefined;
}
/**
* Called when the extension is loaded.
* Any initialization logic for the extension should be put here.

View File

@ -1,12 +1,19 @@
import { Assistant, AssistantInterface } from '../index'
import { BaseExtension } from '../extension'
import { Assistant, AssistantInterface } from "../index";
import { BaseExtension, ExtensionTypeEnum } from "../extension";
/**
* Assistant extension for managing assistants.
* @extends BaseExtension
*/
export abstract class AssistantExtension extends BaseExtension implements AssistantInterface {
abstract createAssistant(assistant: Assistant): Promise<void>
abstract deleteAssistant(assistant: Assistant): Promise<void>
abstract getAssistants(): Promise<Assistant[]>
/**
* Assistant extension type.
*/
type(): ExtensionTypeEnum | undefined {
return ExtensionTypeEnum.Assistant;
}
abstract createAssistant(assistant: Assistant): Promise<void>;
abstract deleteAssistant(assistant: Assistant): Promise<void>;
abstract getAssistants(): Promise<Assistant[]>;
}

View File

@ -1,5 +1,5 @@
import { Thread, ThreadInterface, ThreadMessage, MessageInterface } from '../index'
import { BaseExtension } from '../extension'
import { BaseExtension, ExtensionTypeEnum } from '../extension'
/**
* Conversational extension. Persists and retrieves conversations.
@ -10,6 +10,13 @@ export abstract class ConversationalExtension
extends BaseExtension
implements ThreadInterface, MessageInterface
{
/**
* Conversation extension type.
*/
type(): ExtensionTypeEnum | undefined {
return ExtensionTypeEnum.Conversational;
}
abstract getThreads(): Promise<Thread[]>
abstract saveThread(thread: Thread): Promise<void>
abstract deleteThread(threadId: string): Promise<void>

View File

@ -1,9 +1,16 @@
import { InferenceInterface, MessageRequest, ThreadMessage } from '../index'
import { BaseExtension } from '../extension'
import { InferenceInterface, MessageRequest, ThreadMessage } from "../index";
import { BaseExtension, ExtensionTypeEnum } from "../extension";
/**
* Inference extension. Start, stop and inference models.
*/
export abstract class InferenceExtension extends BaseExtension implements InferenceInterface {
abstract inference(data: MessageRequest): Promise<ThreadMessage>
/**
* Inference extension type.
*/
type(): ExtensionTypeEnum | undefined {
return ExtensionTypeEnum.Inference;
}
abstract inference(data: MessageRequest): Promise<ThreadMessage>;
}

View File

@ -1,14 +1,24 @@
import { BaseExtension } from '../extension'
import { Model, ModelInterface } from '../index'
import { BaseExtension, ExtensionTypeEnum } from "../extension";
import { Model, ModelInterface } from "../index";
/**
* Model extension for managing models.
*/
export abstract class ModelExtension extends BaseExtension implements ModelInterface {
abstract downloadModel(model: Model, network?: { proxy: string, ignoreSSL?: boolean }): Promise<void>
abstract cancelModelDownload(modelId: string): Promise<void>
abstract deleteModel(modelId: string): Promise<void>
abstract saveModel(model: Model): Promise<void>
abstract getDownloadedModels(): Promise<Model[]>
abstract getConfiguredModels(): Promise<Model[]>
/**
* Model extension type.
*/
type(): ExtensionTypeEnum | undefined {
return ExtensionTypeEnum.Model;
}
abstract downloadModel(
model: Model,
network?: { proxy: string; ignoreSSL?: boolean },
): Promise<void>;
abstract cancelModelDownload(modelId: string): Promise<void>;
abstract deleteModel(modelId: string): Promise<void>;
abstract saveModel(model: Model): Promise<void>;
abstract getDownloadedModels(): Promise<Model[]>;
abstract getConfiguredModels(): Promise<Model[]>;
}

View File

@ -1,11 +1,18 @@
import { BaseExtension } from '../extension'
import { MonitoringInterface } from '../index'
import { BaseExtension, ExtensionTypeEnum } from "../extension";
import { MonitoringInterface } from "../index";
/**
* Monitoring extension for system monitoring.
* @extends BaseExtension
*/
export abstract class MonitoringExtension extends BaseExtension implements MonitoringInterface {
abstract getResourcesInfo(): Promise<any>
abstract getCurrentLoad(): Promise<any>
/**
* Monitoring extension type.
*/
type(): ExtensionTypeEnum | undefined {
return ExtensionTypeEnum.SystemMonitoring;
}
abstract getResourcesInfo(): Promise<any>;
abstract getCurrentLoad(): Promise<any>;
}

View File

@ -1,14 +1,10 @@
import { ExtensionType, fs, Assistant } from "@janhq/core";
import { fs, Assistant } from "@janhq/core";
import { AssistantExtension } from "@janhq/core";
import { join } from "path";
export default class JanAssistantExtension implements AssistantExtension {
export default class JanAssistantExtension extends AssistantExtension {
private static readonly _homeDir = "file://assistants";
type(): ExtensionType {
return ExtensionType.Assistant;
}
async onLoad() {
// making the assistant directory
if (!(await fs.existsSync(JanAssistantExtension._homeDir)))

View File

@ -1,5 +1,4 @@
import {
ExtensionType,
fs,
joinPath,
ConversationalExtension,
@ -12,19 +11,12 @@ import {
* functionality for managing threads.
*/
export default class JSONConversationalExtension
implements ConversationalExtension
extends ConversationalExtension
{
private static readonly _homeDir = 'file://threads'
private static readonly _threadInfoFileName = 'thread.json'
private static readonly _threadMessagesFileName = 'messages.jsonl'
/**
* Returns the type of the extension.
*/
type(): ExtensionType {
return ExtensionType.Conversational
}
/**
* Called when the extension is loaded.
*/

View File

@ -9,10 +9,8 @@
import {
ChatCompletionRole,
ContentType,
EventName,
MessageRequest,
MessageStatus,
ExtensionType,
ThreadContent,
ThreadMessage,
events,
@ -23,6 +21,9 @@ import {
InferenceExtension,
log,
InferenceEngine,
MessageEvent,
ModelEvent,
InferenceEvent,
} from "@janhq/core";
import { requestInference } from "./helpers/sse";
import { ulid } from "ulid";
@ -32,7 +33,7 @@ import { ulid } from "ulid";
* The class provides methods for initializing and stopping a model, and for making inference requests.
* It also subscribes to events emitted by the @janhq/core package and handles new message requests.
*/
export default class JanInferenceNitroExtension implements InferenceExtension {
export default class JanInferenceNitroExtension extends InferenceExtension {
private static readonly _homeDir = "file://engines";
private static readonly _settingsDir = "file://settings";
private static readonly _engineMetadataFileName = "nitro.json";
@ -66,14 +67,6 @@ export default class JanInferenceNitroExtension implements InferenceExtension {
*/
private nitroProcessInfo: any = undefined;
/**
* Returns the type of the extension.
* @returns {ExtensionType} The type of the extension.
*/
type(): ExtensionType {
return ExtensionType.Inference;
}
/**
* Subscribes to events emitted by the @janhq/core package.
*/
@ -89,15 +82,15 @@ export default class JanInferenceNitroExtension implements InferenceExtension {
this.writeDefaultEngineSettings();
// Events subscription
events.on(EventName.OnMessageSent, (data: MessageRequest) =>
events.on(MessageEvent.OnMessageSent, (data: MessageRequest) =>
this.onMessageRequest(data)
);
events.on(EventName.OnModelInit, (model: Model) => this.onModelInit(model));
events.on(ModelEvent.OnModelInit, (model: Model) => this.onModelInit(model));
events.on(EventName.OnModelStop, (model: Model) => this.onModelStop(model));
events.on(ModelEvent.OnModelStop, (model: Model) => this.onModelStop(model));
events.on(EventName.OnInferenceStopped, () => this.onInferenceStopped());
events.on(InferenceEvent.OnInferenceStopped, () => this.onInferenceStopped());
// Attempt to fetch nvidia info
await executeOnMain(NODE, "updateNvidiaInfo", {});
@ -140,12 +133,12 @@ export default class JanInferenceNitroExtension implements InferenceExtension {
});
if (nitroInitResult?.error) {
events.emit(EventName.OnModelFail, model);
events.emit(ModelEvent.OnModelFail, model);
return;
}
this._currentModel = model;
events.emit(EventName.OnModelReady, model);
events.emit(ModelEvent.OnModelReady, model);
this.getNitroProcesHealthIntervalId = setInterval(
() => this.periodicallyGetNitroHealth(),
@ -157,7 +150,7 @@ export default class JanInferenceNitroExtension implements InferenceExtension {
if (model.engine !== "nitro") return;
await executeOnMain(NODE, "stopModel");
events.emit(EventName.OnModelStopped, {});
events.emit(ModelEvent.OnModelStopped, {});
// stop the periocally health check
if (this.getNitroProcesHealthIntervalId) {
@ -175,7 +168,7 @@ export default class JanInferenceNitroExtension implements InferenceExtension {
const isRunning = this.nitroProcessInfo?.isRunning ?? false;
if (isRunning && health.isRunning === false) {
console.debug("Nitro process is stopped");
events.emit(EventName.OnModelStopped, {});
events.emit(ModelEvent.OnModelStopped, {});
}
this.nitroProcessInfo = health;
}
@ -241,7 +234,7 @@ export default class JanInferenceNitroExtension implements InferenceExtension {
updated: timestamp,
object: "thread.message",
};
events.emit(EventName.OnMessageResponse, message);
events.emit(MessageEvent.OnMessageResponse, message);
this.isCancelled = false;
this.controller = new AbortController();
@ -261,22 +254,22 @@ export default class JanInferenceNitroExtension implements InferenceExtension {
},
};
message.content = [messageContent];
events.emit(EventName.OnMessageUpdate, message);
events.emit(MessageEvent.OnMessageUpdate, message);
},
complete: async () => {
message.status = message.content.length
? MessageStatus.Ready
: MessageStatus.Error;
events.emit(EventName.OnMessageUpdate, message);
events.emit(MessageEvent.OnMessageUpdate, message);
},
error: async (err) => {
if (this.isCancelled || message.content.length) {
message.status = MessageStatus.Stopped;
events.emit(EventName.OnMessageUpdate, message);
events.emit(MessageEvent.OnMessageUpdate, message);
return;
}
message.status = MessageStatus.Error;
events.emit(EventName.OnMessageUpdate, message);
events.emit(MessageEvent.OnMessageUpdate, message);
log(`[APP]::Error: ${err.message}`);
},
});

View File

@ -9,16 +9,17 @@
import {
ChatCompletionRole,
ContentType,
EventName,
MessageRequest,
MessageStatus,
ExtensionType,
ThreadContent,
ThreadMessage,
events,
fs,
BaseExtension,
MessageEvent,
ModelEvent,
InferenceEvent,
} from "@janhq/core";
import { InferenceExtension } from "@janhq/core";
import { requestInference } from "./helpers/sse";
import { ulid } from "ulid";
import { join } from "path";
@ -28,7 +29,7 @@ import { join } from "path";
* The class provides methods for initializing and stopping a model, and for making inference requests.
* It also subscribes to events emitted by the @janhq/core package and handles new message requests.
*/
export default class JanInferenceOpenAIExtension implements InferenceExtension {
export default class JanInferenceOpenAIExtension extends BaseExtension {
private static readonly _homeDir = "file://engines";
private static readonly _engineMetadataFileName = "openai.json";
@ -42,14 +43,6 @@ export default class JanInferenceOpenAIExtension implements InferenceExtension {
controller = new AbortController();
isCancelled = false;
/**
* Returns the type of the extension.
* @returns {ExtensionType} The type of the extension.
*/
// TODO: To fix
type(): ExtensionType {
return undefined;
}
/**
* Subscribes to events emitted by the @janhq/core package.
*/
@ -63,18 +56,18 @@ export default class JanInferenceOpenAIExtension implements InferenceExtension {
JanInferenceOpenAIExtension.writeDefaultEngineSettings();
// Events subscription
events.on(EventName.OnMessageSent, (data) =>
events.on(MessageEvent.OnMessageSent, (data) =>
JanInferenceOpenAIExtension.handleMessageRequest(data, this)
);
events.on(EventName.OnModelInit, (model: OpenAIModel) => {
events.on(ModelEvent.OnModelInit, (model: OpenAIModel) => {
JanInferenceOpenAIExtension.handleModelInit(model);
});
events.on(EventName.OnModelStop, (model: OpenAIModel) => {
events.on(ModelEvent.OnModelStop, (model: OpenAIModel) => {
JanInferenceOpenAIExtension.handleModelStop(model);
});
events.on(EventName.OnInferenceStopped, () => {
events.on(InferenceEvent.OnInferenceStopped, () => {
JanInferenceOpenAIExtension.handleInferenceStopped(this);
});
}
@ -104,43 +97,6 @@ export default class JanInferenceOpenAIExtension implements InferenceExtension {
console.error(err);
}
}
/**
* Makes a single response inference request.
* @param {MessageRequest} data - The data for the inference request.
* @returns {Promise<any>} A promise that resolves with the inference response.
*/
async inference(data: MessageRequest): Promise<ThreadMessage> {
const timestamp = Date.now();
const message: ThreadMessage = {
thread_id: data.threadId,
created: timestamp,
updated: timestamp,
status: MessageStatus.Ready,
id: "",
role: ChatCompletionRole.Assistant,
object: "thread.message",
content: [],
};
return new Promise(async (resolve, reject) => {
requestInference(
data.messages ?? [],
JanInferenceOpenAIExtension._engineSettings,
JanInferenceOpenAIExtension._currentModel
).subscribe({
next: (_content) => {},
complete: async () => {
resolve(message);
},
error: async (err) => {
reject(err);
},
});
});
}
private static async handleModelInit(model: OpenAIModel) {
if (model.engine !== "openai") {
return;
@ -148,7 +104,7 @@ export default class JanInferenceOpenAIExtension implements InferenceExtension {
JanInferenceOpenAIExtension._currentModel = model;
JanInferenceOpenAIExtension.writeDefaultEngineSettings();
// Todo: Check model list with API key
events.emit(EventName.OnModelReady, model);
events.emit(ModelEvent.OnModelReady, model);
}
}
@ -156,7 +112,7 @@ export default class JanInferenceOpenAIExtension implements InferenceExtension {
if (model.engine !== "openai") {
return;
}
events.emit(EventName.OnModelStopped, model);
events.emit(ModelEvent.OnModelStopped, model);
}
private static async handleInferenceStopped(
@ -192,7 +148,7 @@ export default class JanInferenceOpenAIExtension implements InferenceExtension {
updated: timestamp,
object: "thread.message",
};
events.emit(EventName.OnMessageResponse, message);
events.emit(MessageEvent.OnMessageResponse, message);
instance.isCancelled = false;
instance.controller = new AbortController();
@ -215,18 +171,18 @@ export default class JanInferenceOpenAIExtension implements InferenceExtension {
},
};
message.content = [messageContent];
events.emit(EventName.OnMessageUpdate, message);
events.emit(MessageEvent.OnMessageUpdate, message);
},
complete: async () => {
message.status = message.content.length
? MessageStatus.Ready
: MessageStatus.Error;
events.emit(EventName.OnMessageUpdate, message);
events.emit(MessageEvent.OnMessageUpdate, message);
},
error: async (err) => {
if (instance.isCancelled || message.content.length > 0) {
message.status = MessageStatus.Error;
events.emit(EventName.OnMessageUpdate, message);
events.emit(MessageEvent.OnMessageUpdate, message);
return;
}
const messageContent: ThreadContent = {
@ -238,7 +194,7 @@ export default class JanInferenceOpenAIExtension implements InferenceExtension {
};
message.content = [messageContent];
message.status = MessageStatus.Ready;
events.emit(EventName.OnMessageUpdate, message);
events.emit(MessageEvent.OnMessageUpdate, message);
},
});
}

View File

@ -9,18 +9,18 @@
import {
ChatCompletionRole,
ContentType,
EventName,
MessageRequest,
MessageStatus,
ModelSettingParams,
ExtensionType,
ThreadContent,
ThreadMessage,
events,
fs,
Model,
BaseExtension,
MessageEvent,
ModelEvent,
} from "@janhq/core";
import { InferenceExtension } from "@janhq/core";
import { requestInference } from "./helpers/sse";
import { ulid } from "ulid";
import { join } from "path";
@ -32,7 +32,7 @@ import { EngineSettings } from "./@types/global";
* It also subscribes to events emitted by the @janhq/core package and handles new message requests.
*/
export default class JanInferenceTritonTrtLLMExtension
implements InferenceExtension
extends BaseExtension
{
private static readonly _homeDir = "file://engines";
private static readonly _engineMetadataFileName = "triton_trtllm.json";
@ -46,14 +46,6 @@ export default class JanInferenceTritonTrtLLMExtension
controller = new AbortController();
isCancelled = false;
/**
* Returns the type of the extension.
* @returns {ExtensionType} The type of the extension.
*/
// TODO: To fix
type(): ExtensionType {
return undefined;
}
/**
* Subscribes to events emitted by the @janhq/core package.
*/
@ -62,15 +54,15 @@ export default class JanInferenceTritonTrtLLMExtension
JanInferenceTritonTrtLLMExtension.writeDefaultEngineSettings();
// Events subscription
events.on(EventName.OnMessageSent, (data) =>
events.on(MessageEvent.OnMessageSent, (data) =>
JanInferenceTritonTrtLLMExtension.handleMessageRequest(data, this)
);
events.on(EventName.OnModelInit, (model: Model) => {
events.on(ModelEvent.OnModelInit, (model: Model) => {
JanInferenceTritonTrtLLMExtension.handleModelInit(model);
});
events.on(EventName.OnModelStop, (model: Model) => {
events.on(ModelEvent.OnModelStop, (model: Model) => {
JanInferenceTritonTrtLLMExtension.handleModelStop(model);
});
}
@ -131,41 +123,6 @@ export default class JanInferenceTritonTrtLLMExtension
this.controller?.abort();
}
/**
* Makes a single response inference request.
* @param {MessageRequest} data - The data for the inference request.
* @returns {Promise<any>} A promise that resolves with the inference response.
*/
async inference(data: MessageRequest): Promise<ThreadMessage> {
const timestamp = Date.now();
const message: ThreadMessage = {
thread_id: data.threadId,
created: timestamp,
updated: timestamp,
status: MessageStatus.Ready,
id: "",
role: ChatCompletionRole.Assistant,
object: "thread.message",
content: [],
};
return new Promise(async (resolve, reject) => {
requestInference(
data.messages ?? [],
JanInferenceTritonTrtLLMExtension._engineSettings,
JanInferenceTritonTrtLLMExtension._currentModel
).subscribe({
next: (_content) => {},
complete: async () => {
resolve(message);
},
error: async (err) => {
reject(err);
},
});
});
}
private static async handleModelInit(model: Model) {
if (model.engine !== "triton_trtllm") {
return;
@ -173,8 +130,7 @@ export default class JanInferenceTritonTrtLLMExtension
JanInferenceTritonTrtLLMExtension._currentModel = model;
JanInferenceTritonTrtLLMExtension.writeDefaultEngineSettings();
// Todo: Check model list with API key
events.emit(EventName.OnModelReady, model);
// events.emit(EventName.OnModelFail, model)
events.emit(ModelEvent.OnModelReady, model);
}
}
@ -182,7 +138,7 @@ export default class JanInferenceTritonTrtLLMExtension
if (model.engine !== "triton_trtllm") {
return;
}
events.emit(EventName.OnModelStopped, model);
events.emit(ModelEvent.OnModelStopped, model);
}
/**
@ -211,7 +167,7 @@ export default class JanInferenceTritonTrtLLMExtension
updated: timestamp,
object: "thread.message",
};
events.emit(EventName.OnMessageResponse, message);
events.emit(MessageEvent.OnMessageResponse, message);
instance.isCancelled = false;
instance.controller = new AbortController();
@ -234,18 +190,18 @@ export default class JanInferenceTritonTrtLLMExtension
},
};
message.content = [messageContent];
events.emit(EventName.OnMessageUpdate, message);
events.emit(MessageEvent.OnMessageUpdate, message);
},
complete: async () => {
message.status = message.content.length
? MessageStatus.Ready
: MessageStatus.Error;
events.emit(EventName.OnMessageUpdate, message);
events.emit(MessageEvent.OnMessageUpdate, message);
},
error: async (err) => {
if (instance.isCancelled || message.content.length) {
message.status = MessageStatus.Error;
events.emit(EventName.OnMessageUpdate, message);
events.emit(MessageEvent.OnMessageUpdate, message);
return;
}
const messageContent: ThreadContent = {
@ -257,7 +213,7 @@ export default class JanInferenceTritonTrtLLMExtension
};
message.content = [messageContent];
message.status = MessageStatus.Ready;
events.emit(EventName.OnMessageUpdate, message);
events.emit(MessageEvent.OnMessageUpdate, message);
},
});
}

View File

@ -1,5 +1,4 @@
import {
ExtensionType,
fs,
downloadFile,
abortDownload,
@ -14,7 +13,7 @@ import {
/**
* A extension for models
*/
export default class JanModelExtension implements ModelExtension {
export default class JanModelExtension extends ModelExtension {
private static readonly _homeDir = 'file://models'
private static readonly _modelMetadataFileName = 'model.json'
private static readonly _supportedModelFormat = '.gguf'
@ -24,15 +23,6 @@ export default class JanModelExtension implements ModelExtension {
private static readonly _configDirName = 'config'
private static readonly _defaultModelFileName = 'default-model.json'
/**
* Implements type from JanExtension.
* @override
* @returns The type of the extension.
*/
type(): ExtensionType {
return ExtensionType.Model
}
/**
* Called when the extension is loaded.
* @override

View File

@ -1,4 +1,3 @@
import { ExtensionType } from "@janhq/core";
import { MonitoringExtension } from "@janhq/core";
import { executeOnMain } from "@janhq/core";
@ -6,15 +5,7 @@ import { executeOnMain } from "@janhq/core";
* JanMonitoringExtension is a extension that provides system monitoring functionality.
* It implements the MonitoringExtension interface from the @janhq/core package.
*/
export default class JanMonitoringExtension implements MonitoringExtension {
/**
* Returns the type of the extension.
* @returns The ExtensionType.SystemMonitoring value.
*/
type(): ExtensionType {
return ExtensionType.SystemMonitoring;
}
export default class JanMonitoringExtension extends MonitoringExtension {
/**
* Called when the extension is loaded.
*/

View File

@ -3,12 +3,13 @@ import { ReactNode, useEffect, useRef } from 'react'
import {
events,
EventName,
ThreadMessage,
ExtensionType,
ExtensionTypeEnum,
MessageStatus,
Model,
ConversationalExtension,
MessageEvent,
ModelEvent,
} from '@janhq/core'
import { useAtomValue, useSetAtom } from 'jotai'
@ -100,14 +101,14 @@ export default function EventHandler({ children }: { children: ReactNode }) {
lastMessage: messageContent,
}
extensionManager
.get<ConversationalExtension>(ExtensionType.Conversational)
.get<ConversationalExtension>(ExtensionTypeEnum.Conversational)
?.saveThread({
...thread,
metadata,
})
extensionManager
.get<ConversationalExtension>(ExtensionType.Conversational)
.get<ConversationalExtension>(ExtensionTypeEnum.Conversational)
?.addNewMessage(message)
}
}
@ -115,19 +116,19 @@ export default function EventHandler({ children }: { children: ReactNode }) {
useEffect(() => {
if (window.core?.events) {
events.on(EventName.OnMessageResponse, handleNewMessageResponse)
events.on(EventName.OnMessageUpdate, handleMessageResponseUpdate)
events.on(EventName.OnModelReady, handleModelReady)
events.on(EventName.OnModelFail, handleModelFail)
events.on(EventName.OnModelStopped, handleModelStopped)
events.on(MessageEvent.OnMessageResponse, handleNewMessageResponse)
events.on(MessageEvent.OnMessageUpdate, handleMessageResponseUpdate)
events.on(ModelEvent.OnModelReady, handleModelReady)
events.on(ModelEvent.OnModelFail, handleModelFail)
events.on(ModelEvent.OnModelStopped, handleModelStopped)
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])
useEffect(() => {
return () => {
events.off(EventName.OnMessageResponse, handleNewMessageResponse)
events.off(EventName.OnMessageUpdate, handleMessageResponseUpdate)
events.off(MessageEvent.OnMessageResponse, handleNewMessageResponse)
events.off(MessageEvent.OnMessageUpdate, handleMessageResponseUpdate)
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])

View File

@ -1,6 +1,6 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { BaseExtension, ExtensionType } from '@janhq/core'
import { BaseExtension, ExtensionTypeEnum } from '@janhq/core'
import Extension from './Extension'
@ -23,7 +23,7 @@ export class ExtensionManager {
* @param type - The type of the extension to retrieve.
* @returns The extension, if found.
*/
get<T extends BaseExtension>(type: ExtensionType): T | undefined {
get<T extends BaseExtension>(type: ExtensionTypeEnum): T | undefined {
return this.extensions.get(type) as T | undefined
}

View File

@ -1,5 +1,4 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { EventName, events, Model } from '@janhq/core'
import { events, Model, ModelEvent } from '@janhq/core'
import { atom, useAtom, useAtomValue } from 'jotai'
import { toaster } from '@/containers/Toast'
@ -64,14 +63,14 @@ export function useActiveModel() {
}
localStorage.setItem(LAST_USED_MODEL_ID, model.id)
events.emit(EventName.OnModelInit, model)
events.emit(ModelEvent.OnModelInit, model)
}
const stopModel = async () => {
if (activeModel) {
setActiveModel(undefined)
setStateModel({ state: 'stop', loading: true, model: activeModel.id })
events.emit(EventName.OnModelStop, activeModel)
events.emit(ModelEvent.OnModelStop, activeModel)
}
}

View File

@ -1,7 +1,7 @@
import {
Assistant,
ConversationalExtension,
ExtensionType,
ExtensionTypeEnum,
Thread,
ThreadAssistantInfo,
ThreadState,
@ -104,7 +104,7 @@ export const useCreateNewThread = () => {
}
extensionManager
.get<ConversationalExtension>(ExtensionType.Conversational)
.get<ConversationalExtension>(ExtensionTypeEnum.Conversational)
?.saveThread(thread)
}

View File

@ -1,4 +1,4 @@
import { ExtensionType, ModelExtension, Model } from '@janhq/core'
import { ExtensionTypeEnum, ModelExtension, Model } from '@janhq/core'
import { toaster } from '@/containers/Toast'
@ -11,7 +11,7 @@ export default function useDeleteModel() {
const deleteModel = async (model: Model) => {
await extensionManager
.get<ModelExtension>(ExtensionType.Model)
.get<ModelExtension>(ExtensionTypeEnum.Model)
?.deleteModel(model.id)
// reload models

View File

@ -1,6 +1,6 @@
import {
ChatCompletionRole,
ExtensionType,
ExtensionTypeEnum,
ConversationalExtension,
} from '@janhq/core'
@ -44,7 +44,7 @@ export default function useDeleteThread() {
if (thread) {
await extensionManager
.get<ConversationalExtension>(ExtensionType.Conversational)
.get<ConversationalExtension>(ExtensionTypeEnum.Conversational)
?.writeMessages(
threadId,
messages.filter((msg) => msg.role === ChatCompletionRole.System)
@ -61,7 +61,7 @@ export default function useDeleteThread() {
}
try {
await extensionManager
.get<ConversationalExtension>(ExtensionType.Conversational)
.get<ConversationalExtension>(ExtensionTypeEnum.Conversational)
?.deleteThread(threadId)
const availableThreads = threads.filter((c) => c.id !== threadId)
setThreads(availableThreads)

View File

@ -2,7 +2,7 @@ import { useContext } from 'react'
import {
Model,
ExtensionType,
ExtensionTypeEnum,
ModelExtension,
abortDownload,
joinPath,
@ -43,7 +43,7 @@ export default function useDownloadModel() {
addNewDownloadingModel(model)
await extensionManager
.get<ModelExtension>(ExtensionType.Model)
.get<ModelExtension>(ExtensionTypeEnum.Model)
?.downloadModel(model, { ignoreSSL, proxy })
}
const abortModelDownload = async (model: Model) => {

View File

@ -1,12 +1,12 @@
import { useEffect, useState } from 'react'
import { Assistant, ExtensionType, AssistantExtension } from '@janhq/core'
import { Assistant, ExtensionTypeEnum, AssistantExtension } from '@janhq/core'
import { extensionManager } from '@/extension/ExtensionManager'
export const getAssistants = async (): Promise<Assistant[]> =>
extensionManager
.get<AssistantExtension>(ExtensionType.Assistant)
.get<AssistantExtension>(ExtensionTypeEnum.Assistant)
?.getAssistants() ?? []
/**

View File

@ -1,6 +1,6 @@
import { useEffect, useState } from 'react'
import { ExtensionType, ModelExtension } from '@janhq/core'
import { ExtensionTypeEnum, ModelExtension } from '@janhq/core'
import { Model } from '@janhq/core'
import { extensionManager } from '@/extension/ExtensionManager'
@ -11,7 +11,7 @@ export function useGetConfiguredModels() {
const getConfiguredModels = async (): Promise<Model[]> => {
const models = await extensionManager
.get<ModelExtension>(ExtensionType.Model)
.get<ModelExtension>(ExtensionTypeEnum.Model)
?.getConfiguredModels()
return models ?? []
}

View File

@ -1,6 +1,6 @@
import { useEffect } from 'react'
import { ExtensionType, ModelExtension, Model } from '@janhq/core'
import { ExtensionTypeEnum, ModelExtension, Model } from '@janhq/core'
import { atom, useAtom } from 'jotai'
@ -22,5 +22,5 @@ export function useGetDownloadedModels() {
export const getDownloadedModels = async (): Promise<Model[]> =>
extensionManager
.get<ModelExtension>(ExtensionType.Model)
.get<ModelExtension>(ExtensionTypeEnum.Model)
?.getDownloadedModels() ?? []

View File

@ -1,6 +1,6 @@
import { useEffect, useState } from 'react'
import { ExtensionType } from '@janhq/core'
import { ExtensionTypeEnum } from '@janhq/core'
import { MonitoringExtension } from '@janhq/core'
import { useSetAtom } from 'jotai'
@ -21,12 +21,14 @@ export default function useGetSystemResources() {
const getSystemResources = async () => {
if (
!extensionManager.get<MonitoringExtension>(ExtensionType.SystemMonitoring)
!extensionManager.get<MonitoringExtension>(
ExtensionTypeEnum.SystemMonitoring
)
) {
return
}
const monitoring = extensionManager.get<MonitoringExtension>(
ExtensionType.SystemMonitoring
ExtensionTypeEnum.SystemMonitoring
)
const resourceInfor = await monitoring?.getResourcesInfo()
const currentLoadInfor = await monitoring?.getCurrentLoad()

View File

@ -4,15 +4,15 @@ import {
ChatCompletionMessage,
ChatCompletionRole,
ContentType,
EventName,
MessageRequest,
MessageStatus,
ExtensionType,
ExtensionTypeEnum,
Thread,
ThreadMessage,
events,
Model,
ConversationalExtension,
MessageEvent,
} from '@janhq/core'
import { useAtom, useAtomValue, useSetAtom } from 'jotai'
@ -116,7 +116,7 @@ export default function useSendChatMessage() {
await WaitForModelStarting(modelId)
setQueuedMessage(false)
}
events.emit(EventName.OnMessageSent, messageRequest)
events.emit(MessageEvent.OnMessageSent, messageRequest)
}
// TODO: Refactor @louis
@ -181,7 +181,7 @@ export default function useSendChatMessage() {
updateThread(updatedThread)
await extensionManager
.get<ConversationalExtension>(ExtensionType.Conversational)
.get<ConversationalExtension>(ExtensionTypeEnum.Conversational)
?.saveThread(updatedThread)
}
@ -253,7 +253,7 @@ export default function useSendChatMessage() {
addNewMessage(threadMessage)
await extensionManager
.get<ConversationalExtension>(ExtensionType.Conversational)
.get<ConversationalExtension>(ExtensionTypeEnum.Conversational)
?.addNewMessage(threadMessage)
const modelId = selectedModel?.id ?? activeThread.assistants[0].model.id
@ -265,7 +265,7 @@ export default function useSendChatMessage() {
setQueuedMessage(false)
}
events.emit(EventName.OnMessageSent, messageRequest)
events.emit(MessageEvent.OnMessageSent, messageRequest)
setReloadModel(false)
setEngineParamsUpdate(false)

View File

@ -1,6 +1,6 @@
import {
EventName,
ExtensionType,
InferenceEvent,
ExtensionTypeEnum,
Thread,
events,
ConversationalExtension,
@ -29,11 +29,11 @@ export default function useSetActiveThread() {
return
}
events.emit(EventName.OnInferenceStopped, thread.id)
events.emit(InferenceEvent.OnInferenceStopped, thread.id)
// load the corresponding messages
const messages = await extensionManager
.get<ConversationalExtension>(ExtensionType.Conversational)
.get<ConversationalExtension>(ExtensionTypeEnum.Conversational)
?.getAllMessages(thread.id)
setThreadMessage(thread.id, messages ?? [])

View File

@ -1,5 +1,5 @@
import {
ExtensionType,
ExtensionTypeEnum,
Thread,
ThreadState,
ConversationalExtension,
@ -99,7 +99,7 @@ const useThreads = () => {
const getLocalThreads = async (): Promise<Thread[]> =>
(await extensionManager
.get<ConversationalExtension>(ExtensionType.Conversational)
.get<ConversationalExtension>(ExtensionTypeEnum.Conversational)
?.getThreads()) ?? []
export default useThreads

View File

@ -1,7 +1,7 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import {
ConversationalExtension,
ExtensionType,
ExtensionTypeEnum,
Thread,
ThreadAssistantInfo,
} from '@janhq/core'
@ -73,7 +73,7 @@ export default function useUpdateModelParameters() {
}
await extensionManager
.get<ConversationalExtension>(ExtensionType.Conversational)
.get<ConversationalExtension>(ExtensionTypeEnum.Conversational)
?.saveThread(updatedThread)
}

View File

@ -1,7 +1,7 @@
import {
ChatCompletionRole,
ConversationalExtension,
ExtensionType,
ExtensionTypeEnum,
MessageStatus,
ThreadMessage,
} from '@janhq/core'
@ -32,7 +32,7 @@ const ErrorMessage = ({ message }: { message: ThreadMessage }) => {
deleteMessage(message.id ?? '')
if (thread) {
await extensionManager
.get<ConversationalExtension>(ExtensionType.Conversational)
.get<ConversationalExtension>(ExtensionTypeEnum.Conversational)
?.writeMessages(
thread.id,
messages.filter((msg) => msg.id !== message.id)

View File

@ -1,6 +1,6 @@
import {
MessageStatus,
ExtensionType,
ExtensionTypeEnum,
ThreadMessage,
ChatCompletionRole,
} from '@janhq/core'
@ -31,7 +31,7 @@ const MessageToolbar = ({ message }: { message: ThreadMessage }) => {
deleteMessage(message.id ?? '')
if (thread) {
await extensionManager
.get<ConversationalExtension>(ExtensionType.Conversational)
.get<ConversationalExtension>(ExtensionTypeEnum.Conversational)
?.writeMessages(
thread.id,
messages.filter((msg) => msg.id !== message.id)

View File

@ -1,6 +1,6 @@
import { ChangeEvent, Fragment, KeyboardEvent, useEffect, useRef } from 'react'
import { EventName, MessageStatus, events } from '@janhq/core'
import { InferenceEvent, MessageStatus, events } from '@janhq/core'
import { Button, Textarea } from '@janhq/uikit'
import { useAtom, useAtomValue } from 'jotai'
@ -104,7 +104,7 @@ const ChatScreen = () => {
)
const onStopInferenceClick = async () => {
events.emit(EventName.OnInferenceStopped, {})
events.emit(InferenceEvent.OnInferenceStopped, {})
}
return (

View File

@ -1,15 +1,15 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
'use client'
import { ExtensionType } from '@janhq/core'
import { ExtensionTypeEnum } from '@janhq/core'
import { extensionManager } from '@/extension/ExtensionManager'
export const isCoreExtensionInstalled = () => {
if (!extensionManager.get(ExtensionType.Conversational)) {
if (!extensionManager.get(ExtensionTypeEnum.Conversational)) {
return false
}
if (!extensionManager.get(ExtensionType.Inference)) return false
if (!extensionManager.get(ExtensionType.Model)) {
if (!extensionManager.get(ExtensionTypeEnum.Inference)) return false
if (!extensionManager.get(ExtensionTypeEnum.Model)) {
return false
}
return true
@ -21,9 +21,9 @@ export const setupBaseExtensions = async () => {
const baseExtensions = await window.core?.api.baseExtensions()
if (
!extensionManager.get(ExtensionType.Conversational) ||
!extensionManager.get(ExtensionType.Inference) ||
!extensionManager.get(ExtensionType.Model)
!extensionManager.get(ExtensionTypeEnum.Conversational) ||
!extensionManager.get(ExtensionTypeEnum.Inference) ||
!extensionManager.get(ExtensionTypeEnum.Model)
) {
const installed = await extensionManager.install(baseExtensions)
if (installed) {