Skip to content

Commit

Permalink
Update Wox and Wox.Plugin versions and improve feature validations
Browse files Browse the repository at this point in the history
This commit updates Wox and Wox.Plugin to version 0.0.67. It also refactors the handling of PluginSettingValidator for improved code clarity and maintainability. Additionally, it now checks if a plugin has the right to access a feature before accessing it to enhance security. Features for LLMStream usage now include explicit permissions.
  • Loading branch information
qianlifeng committed Jun 14, 2024
1 parent 3edbaca commit 87a272d
Show file tree
Hide file tree
Showing 21 changed files with 324 additions and 82 deletions.
2 changes: 1 addition & 1 deletion Wox.Plugin.Host.Nodejs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
"typescript": "^5.2.2"
},
"dependencies": {
"@wox-launcher/wox-plugin": "^0.0.66",
"@wox-launcher/wox-plugin": "^0.0.67",
"dayjs": "^1.11.9",
"promise-deferred": "^2.0.4",
"winston": "^3.10.0",
Expand Down
8 changes: 4 additions & 4 deletions Wox.Plugin.Host.Nodejs/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 20 additions & 0 deletions Wox.Plugin.Host.Nodejs/src/jsonrpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ export async function handleRequestFromWox(ctx: Context, request: PluginJsonRpcR
return unloadPlugin(ctx, request)
case "onPluginSettingChange":
return onPluginSettingChange(ctx, request)
case "onGetDynamicSetting":
return onGetDynamicSetting(ctx, request)
default:
logger.info(ctx, `unknown method handler: ${request.Method}`)
throw new Error(`unknown method handler: ${request.Method}`)
Expand Down Expand Up @@ -142,6 +144,24 @@ async function onPluginSettingChange(ctx: Context, request: PluginJsonRpcRequest
plugin.API.settingChangeCallbacks.get(callbackId)?.(settingKey, settingValue)
}

async function onGetDynamicSetting(ctx: Context, request: PluginJsonRpcRequest) {
const plugin = pluginInstances.get(request.PluginId)
if (plugin === undefined || plugin === null) {
logger.error(ctx, `plugin not found: ${request.PluginName}, forget to load plugin?`)
throw new Error(`plugin not found: ${request.PluginName}, forget to load plugin?`)
}

const settingKey = request.Params.Key
const callbackId = request.Params.CallbackId
const setting = plugin.API.getDynamicSettingCallbacks.get(callbackId)?.(settingKey)
if (setting === undefined || setting === null) {
logger.error(ctx, `dynamic setting not found: ${settingKey}`)
throw new Error(`dynamic setting not found: ${settingKey}`)
}

return setting
}

async function query(ctx: Context, request: PluginJsonRpcRequest) {
const plugin = pluginInstances.get(request.PluginId)
if (plugin === undefined || plugin === null) {
Expand Down
22 changes: 22 additions & 0 deletions Wox.Plugin.Host.Nodejs/src/pluginAPI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,22 @@ import * as crypto from "crypto"
import { waitingForResponse } from "./index"
import Deferred from "promise-deferred"
import { logger } from "./logger"
import { llm } from "@wox-launcher/wox-plugin/types/llm"
import { MetadataCommand, PluginSettingDefinitionItem } from "@wox-launcher/wox-plugin/types/setting"

export class PluginAPI implements PublicAPI {
ws: WebSocket
pluginId: string
pluginName: string
settingChangeCallbacks: Map<string, (key: string, value: string) => void>
getDynamicSettingCallbacks: Map<string, (key: string) => PluginSettingDefinitionItem>

constructor(ws: WebSocket, pluginId: string, pluginName: string) {
this.ws = ws
this.pluginId = pluginId
this.pluginName = pluginName
this.settingChangeCallbacks = new Map<string, (key: string, value: string) => void>()
this.getDynamicSettingCallbacks = new Map<string, (key: string) => PluginSettingDefinitionItem>()
}

async invokeMethod(ctx: Context, method: string, params: { [key: string]: string }): Promise<unknown> {
Expand Down Expand Up @@ -88,4 +92,22 @@ export class PluginAPI implements PublicAPI {
this.settingChangeCallbacks.set(callbackId, callback)
await this.invokeMethod(ctx, "OnPluginSettingChanged", { callbackId })
}

async OnGetDynamicSetting(ctx: Context, callback: (key: string) => PluginSettingDefinitionItem): Promise<void> {
const callbackId = crypto.randomUUID()
this.getDynamicSettingCallbacks.set(callbackId, callback)
await this.invokeMethod(ctx, "OnGetDynamicSetting", { callbackId })
}

async RegisterQueryCommands(ctx: Context, commands: MetadataCommand[]): Promise<void> {
await this.invokeMethod(ctx, "RegisterQueryCommands", { commands: JSON.stringify(commands) })
}

async LLMStream(ctx: Context, conversations: llm.Conversation[], callback: llm.ChatStreamFunc): Promise<void> {
const callbackId = crypto.randomUUID()
await this.invokeMethod(ctx, "LLMStream", { callbackId })

//TODO: implement LLMStream
return null
}
}
2 changes: 1 addition & 1 deletion Wox.Plugin.Nodejs/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@wox-launcher/wox-plugin",
"version": "0.0.66",
"version": "0.0.67",
"description": "All nodejs plugin for Wox should use types in this package",
"repository": {
"type": "git",
Expand Down
20 changes: 20 additions & 0 deletions Wox.Plugin.Nodejs/types/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
import { llm } from "./llm.js"
import { MetadataCommand, PluginSettingDefinitionItem } from "./setting.js"

export type Platform = "windows" | "darwin" | "linux"

export interface Plugin {
init: (ctx: Context, initParams: PluginInitParams) => Promise<void>
query: (ctx: Context, query: Query) => Promise<Result[]>
Expand Down Expand Up @@ -179,6 +184,21 @@ export interface PublicAPI {
* Register setting changed callback
*/
OnSettingChanged: (ctx: Context, callback: (key: string, value: string) => void) => Promise<void>

/**
* Get dynamic setting definition
*/
OnGetDynamicSetting: (ctx: Context, callback: (key: string) => PluginSettingDefinitionItem) => Promise<void>

/**
* Register query commands
*/
RegisterQueryCommands: (ctx: Context, commands: MetadataCommand[]) => Promise<void>

/**
* Chat using LLM
*/
LLMStream: (ctx: Context, conversations: llm.Conversation[], callback: llm.ChatStreamFunc) => Promise<void>
}

export type WoxImageType = "absolute" | "relative" | "base64" | "svg" | "url" | "emoji"
Expand Down
12 changes: 12 additions & 0 deletions Wox.Plugin.Nodejs/types/llm.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export namespace llm {
export type ConversationRole = "user" | "system"
export type ChatStreamDataType = "streaming" | "finished" | "error"

export interface Conversation {
Role: ConversationRole
Text: string
Timestamp: number
}

export type ChatStreamFunc = (dataType: ChatStreamDataType, data: string) => void
}
97 changes: 97 additions & 0 deletions Wox.Plugin.Nodejs/types/setting.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import { Context, Platform } from "./index.js"

export type PluginSettingDefinitionType = "head" | "textbox" | "checkbox" | "select" | "label" | "newline" | "table" | "dynamic"


export interface PluginSettingValueStyle {
PaddingLeft: number
PaddingTop: number
PaddingRight: number
PaddingBottom: number

Width: number
LabelWidth: number // if has label, E.g. select, checkbox, textbox
}

export interface PluginSettingDefinitionValue {
GetKey: () => string
GetDefaultValue: () => string
Translate: (translator: (ctx: Context, key: string) => string) => void
}

export interface PluginSettingDefinitionItem {
Type: PluginSettingDefinitionType
Value: PluginSettingDefinitionValue
DisabledInPlatforms: Platform[]
IsPlatformSpecific: boolean // if true, this setting may be different in different platforms
}

export interface MetadataCommand {
Command: string
Description: string
}

export interface PluginSettingValueCheckBox extends PluginSettingDefinitionValue {
Key: string
Label: string
DefaultValue: string
Tooltip: string
Style: PluginSettingValueStyle
}

export interface PluginSettingValueDynamic extends PluginSettingDefinitionValue {
Key: string
}

export interface PluginSettingValueHead extends PluginSettingDefinitionValue {
Content: string
Tooltip: string
Style: PluginSettingValueStyle
}

export interface PluginSettingValueLabel extends PluginSettingDefinitionValue {
Content: string
Tooltip: string
Style: PluginSettingValueStyle
}

export interface PluginSettingValueNewline extends PluginSettingDefinitionValue {
Style: PluginSettingValueStyle
}

export interface PluginSettingValueSelect extends PluginSettingDefinitionValue {
Key: string
Label: string
Suffix: string
DefaultValue: string
Tooltip: string
Options: PluginSettingValueSelectOption[]
Validators: PluginSettingValidator[] // validators for this setting, every validator should be satisfied

Style: PluginSettingValueStyle
}

export interface PluginSettingValueSelectOption {
Label: string
Value: string
}

export type PluginSettingValidatorType = "is_number" | "not_empty"

export interface PluginSettingValidator {
Type: PluginSettingValidatorType
Value: PluginSettingValidatorValue
}

export interface PluginSettingValidatorValue {
GetValidatorType(): PluginSettingValidatorType
}

export interface PluginSettingValidatorIsNumber extends PluginSettingValidatorValue {
IsInteger: boolean
IsFloat: boolean
}

export interface PluginSettingValidatorNotEmpty extends PluginSettingValidatorValue {

}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class PluginSettingValidatorItem {
if (type == "not_empty") {
validator = PluginSettingValidatorNotEmpty.fromJson(<String, dynamic>{});
} else if (type == "is_number") {
validator = PluginSettingValidatorIsNumber.fromJson(json);
validator = PluginSettingValidatorIsNumber.fromJson(json["Value"]);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -455,18 +455,24 @@ class WoxSettingPluginView extends GetView<WoxSettingController> {
return noDataAccess;
}

List<String> params = [];

//check if "queryEnv" feature is exist and list it's params
var queryEnv = plugin.features.where((element) => element.name == "queryEnv").toList();
if (queryEnv.isEmpty) {
return noDataAccess;
if (queryEnv.isNotEmpty) {
queryEnv.first.params.forEach((key, value) {
if (value == "true") {
params.add(key);
}
});
}

// check if llmChat feature is exist
var llmChat = plugin.features.where((element) => element.name == "llm").toList();
if (llmChat.isNotEmpty) {
params.add("llm");
}

List<String> params = [];
queryEnv.first.params.forEach((key, value) {
if (value == "true") {
params.add(key);
}
});
if (params.isEmpty) {
return noDataAccess;
}
Expand All @@ -478,7 +484,6 @@ class WoxSettingPluginView extends GetView<WoxSettingController> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text('This plugin requires access to the following data:'),
const SizedBox(height: 20),
...params.map((e) {
if (e == "requireActiveWindowName") {
return privacyItem(
Expand All @@ -494,6 +499,13 @@ class WoxSettingPluginView extends GetView<WoxSettingController> {
'E.g. you are using google chrome to view webpages, you activate Wox and this plugin will get the url of active tab you are viewing',
);
}
if (e == "llm") {
return privacyItem(
material.Icons.chat,
'Large Language Model (LLM)',
'This plugin uses large language model to provide better results, you need to configure the model in LLM Tools plugin first',
);
}
return Text(e);
}),
],
Expand All @@ -503,30 +515,33 @@ class WoxSettingPluginView extends GetView<WoxSettingController> {
}

Widget privacyItem(IconData icon, String title, String description) {
return Column(
children: [
Row(
children: [
Icon(icon),
SizedBox(width: 10),
Text(title),
],
),
const SizedBox(height: 10),
Row(
children: [
const SizedBox(width: 30),
Flexible(
child: Text(
description,
style: TextStyle(
color: Colors.grey[100],
return Padding(
padding: const EdgeInsets.only(top: 20.0),
child: Column(
children: [
Row(
children: [
Icon(icon),
SizedBox(width: 10),
Text(title),
],
),
const SizedBox(height: 6),
Row(
children: [
const SizedBox(width: 30),
Flexible(
child: Text(
description,
style: TextStyle(
color: Colors.grey[100],
),
),
),
),
],
)
],
],
)
],
),
);
}

Expand Down
Loading

0 comments on commit 87a272d

Please sign in to comment.