Skip to content

Commit

Permalink
plugins tests
Browse files Browse the repository at this point in the history
  • Loading branch information
nbonamy committed May 17, 2024
1 parent e5bc37e commit 207f3c9
Show file tree
Hide file tree
Showing 8 changed files with 236 additions and 72 deletions.
11 changes: 11 additions & 0 deletions src/plugins/plugins.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@

import { anyDict } from '../types/index.d'
import BrowsePlugin from '../plugins/browse'
import TavilyPlugin from '../plugins/tavily'
import PythonPlugin from '../plugins/python'

export const availablePlugins: anyDict = {
browse: BrowsePlugin,
python: PythonPlugin,
tavily: TavilyPlugin,
}
2 changes: 1 addition & 1 deletion src/plugins/python.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export default class extends Plugin {
}

isEnabled(): boolean {
return this.config.enabled && this.config.binpath
return this.config.enabled && this.config.binpath != null
}

getName(): string {
Expand Down
2 changes: 1 addition & 1 deletion src/plugins/tavily.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export default class extends Plugin {
}

isEnabled(): boolean {
return this.config.enabled && this.config.apiKey
return this.config.enabled && this.config.apiKey != null
}

getName(): string {
Expand Down
10 changes: 1 addition & 9 deletions src/services/engine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,10 @@ import { LlmResponse, LlmCompletionOpts, LLmCompletionPayload, LlmStream, LlmChu
import { Configuration, Model } from '../types/config.d'
import { getFileContents } from './download'
import Plugin from '../plugins/plugin'
import BrowsePlugin from '../plugins/browse'
import TavilyPlugin from '../plugins/tavily'
import PythonPlugin from '../plugins/python'
import { availablePlugins } from '../plugins/plugins'
import { PluginParameter } from '../types/plugin.d'
import { minimatch } from 'minimatch'

export const availablePlugins: anyDict = {
browse: BrowsePlugin,
python: PythonPlugin,
tavily: TavilyPlugin,
}

export default class LlmEngine {

config: Configuration
Expand Down
2 changes: 1 addition & 1 deletion src/settings/SettingsPlugins.vue
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
<script setup>
import { ref, computed, nextTick } from 'vue'
import { availablePlugins } from '../services/engine'
import { availablePlugins } from '../plugins/plugins'
import SettingsBrowse from './SettingsBrowse.vue'
import SettingsPython from './SettingsPython.vue'
import SettingsTavily from './SettingsTavily.vue'
Expand Down
88 changes: 88 additions & 0 deletions tests/mocks/plugins.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@

import Plugin from '../../src/plugins/plugin'

export class Plugin1 extends Plugin {

isEnabled(): boolean {
return true
}

getName(): string {
return 'plugin1'
}

getDescription(): string {
return 'Plugin 1'
}

getRunningDescription(): string {
return 'run1'
}

getParameters(): any[] {
return []
}

async execute(parameters: any): Promise<any> {
return 'result1'
}
}

export class Plugin2 extends Plugin {

isEnabled(): boolean {
return true
}

getName(): string {
return 'plugin2'
}

getDescription(): string {
return 'Plugin 2'
}

getPreparationDescription(): string {
return 'prep2'
}

getRunningDescription(): string {
return 'run2'
}

getParameters(): any[] {
return [
{
name: 'param1',
type: 'string',
description: 'Parameter 1',
required: true
},
{
name: 'param2',
type: 'number',
description: 'Parameter 2',
required: false
}
]
}

async execute(parameters: any): Promise<any> {
return parameters
}
}

export class Plugin3 extends Plugin {

getName(): string {
return 'plugin3'
}

getDescription(): string {
return 'Plugin 3'
}

getParameters(): any[] {
return []
}
}
117 changes: 57 additions & 60 deletions tests/unit/engine_plugins.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,22 @@

import { beforeEach, expect, test } from 'vitest'
import { vi, beforeEach, expect, test } from 'vitest'
import { store } from '../../src/services/store'
import defaults from '../../defaults/settings.json'
import OpenAI from '../../src/services/openai'
import Browse from '../../src/plugins/browse'
import Tavily from '../../src/plugins/tavily'
import Python from '../../src/plugins/python'

vi.mock('../../src/vendor/tavily', async () => {
const Tavily = vi.fn()
Tavily.prototype.search = vi.fn(() => ({ results: [ 'page1' ] }))
return { default: Tavily }
})

window.api = {
interpreter: {
python: vi.fn(() => ({ result: ['bonjour'] }))
}
}

beforeEach(() => {
store.config = defaults
Expand All @@ -20,62 +34,45 @@ beforeEach(() => {
}
})

test('OpenAI Functions', () => {
const llm = new OpenAI(store.config)
expect(llm.getAvailableTools()).toStrictEqual([
{
type: 'function',
function: {
name: 'get_html_as_text',
description: 'Download an HTML page and return the text content',
parameters: {
type: 'object',
properties: {
'url': {
type: 'string',
'enum': undefined,
description: 'The URL of the page to download',
}
},
required: ['url'],
},
},
},
{
type: 'function',
function: {
name: 'run_python_code',
description: 'Execute Python code and return the result',
parameters: {
type: 'object',
properties: {
'script': {
type: 'string',
'enum': undefined,
description: 'The script to run',
}
},
required: ['script'],
},
},
},
{
type: 'function',
function: {
name: 'search_tavily',
description: 'This tool allows you to search the web for information on a given topic',
parameters: {
type: 'object',
properties: {
'query': {
type: 'string',
'enum': undefined,
description: 'The query to search for',
}
},
required: ['query'],
},
},
},
])
test('Browse Plugin', async () => {
const browse = new Browse(store.config.plugins.browse)
expect(browse.isEnabled()).toBe(true)
expect(browse.getName()).toBe('get_html_as_text')
expect(browse.getDescription()).not.toBeFalsy()
expect(browse.getPreparationDescription()).toBeFalsy()
expect(browse.getRunningDescription()).not.toBeFalsy()
expect(browse.getParameters()[0].name).toBe('url')
expect(browse.getParameters()[0].type).toBe('string')
expect(browse.getParameters()[0].description).not.toBeFalsy()
expect(browse.getParameters()[0].required).toBe(true)
expect(await browse.execute({ url: 'https://google.com' })).toHaveProperty('content')
})

test('Tavily Plugin', async () => {
const tavily = new Tavily(store.config.plugins.tavily)
expect(tavily.isEnabled()).toBe(true)
expect(tavily.getName()).toBe('search_tavily')
expect(tavily.getDescription()).not.toBeFalsy()
expect(tavily.getPreparationDescription()).toBeFalsy()
expect(tavily.getRunningDescription()).not.toBeFalsy()
expect(tavily.getParameters()[0].name).toBe('query')
expect(tavily.getParameters()[0].type).toBe('string')
expect(tavily.getParameters()[0].description).not.toBeFalsy()
expect(tavily.getParameters()[0].required).toBe(true)
expect(await tavily.execute({ query: 'test' })).toHaveProperty('results')
})

test('Python Plugin', async () => {
const python = new Python(store.config.plugins.python)
expect(python.isEnabled()).toBe(true)
expect(python.getName()).toBe('run_python_code')
expect(python.getDescription()).not.toBeFalsy()
expect(python.getPreparationDescription()).not.toBeFalsy()
expect(python.getRunningDescription()).not.toBeFalsy()
expect(python.getParameters()[0].name).toBe('script')
expect(python.getParameters()[0].type).toBe('string')
expect(python.getParameters()[0].description).not.toBeFalsy()
expect(python.getParameters()[0].required).toBe(true)
expect(await python.execute({ script: 'print("hello")' })).toHaveProperty('result')
expect((await python.execute({ script: 'print("hello")' })).result).toBe('bonjour')
})
76 changes: 76 additions & 0 deletions tests/unit/engine_plugins_mocked.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@

import { vi, beforeEach, expect, test } from 'vitest'
import { Plugin1, Plugin2, Plugin3 } from '../mocks/plugins'
import OpenAI from '../../src/services/openai'
import { store } from '../../src/services/store'
import defaults from '../../defaults/settings.json'

vi.mock('../../src/plugins/plugins', async () => {
return {
availablePlugins: {
plugin1: Plugin1,
plugin2: Plugin2,
plugin3: Plugin3,
}
}
})

beforeEach(() => {
store.config = defaults
store.config.llm.engine = 'mock'
})

test('Engine plugin descriptions', () => {
const llm = new OpenAI(store.config)
expect(llm.getToolPreparationDescription('plugin1')).toBeNull()
expect(llm.getToolRunningDescription('plugin1')).toBe('run1')
expect(llm.getToolPreparationDescription('plugin2')).toBe('prep2')
expect(llm.getToolRunningDescription('plugin2')).toBe('run2')
})

test('Engine plugin execution', async () => {
const llm = new OpenAI(store.config)
expect(await llm.callTool('plugin1', {})).toStrictEqual('result1')
expect(await llm.callTool('plugin2', { param1: 'a', param2: 1 })).toStrictEqual({ param1: 'a', param2: 1 })
})

test('OpenAI Functions', () => {
const llm = new OpenAI(store.config)
expect(llm.getAvailableTools()).toStrictEqual([
{
type: 'function',
function: {
name: 'plugin1',
description: 'Plugin 1',
parameters: {
type: 'object',
properties: { },
required: [],
},
},
},
{
type: 'function',
function: {
name: 'plugin2',
description: 'Plugin 2',
parameters: {
type: 'object',
properties: {
'param1': {
type: 'string',
'enum': undefined,
description: 'Parameter 1',
},
'param2': {
type: 'number',
'enum': undefined,
description: 'Parameter 2',
},
},
required: ['param1'],
},
},
},
])
})

0 comments on commit 207f3c9

Please sign in to comment.