diff --git a/lib/shared/src/chat/transcript/index.ts b/lib/shared/src/chat/transcript/index.ts index 41a33cf1be04..ec4046d3f1a9 100644 --- a/lib/shared/src/chat/transcript/index.ts +++ b/lib/shared/src/chat/transcript/index.ts @@ -1,5 +1,4 @@ import { ContextFile, ContextMessage, OldContextMessage, PreciseContext } from '../../codebase-context/messages' -import { PluginFunctionExecutionInfo } from '../../plugins/api/types' import { CHARS_PER_TOKEN, MAX_AVAILABLE_PROMPT_LENGTH } from '../../prompt/constants' import { PromptMixin } from '../../prompt/prompt-mixin' import { Message } from '../../sourcegraph-api' @@ -37,7 +36,6 @@ export class Transcript { usedContextFiles, usedPreciseContext, timestamp, - pluginExecutionInfos, }) => { if (!fullContext) { fullContext = context || [] @@ -61,8 +59,7 @@ export class Transcript { ), usedContextFiles || [], usedPreciseContext || [], - timestamp || new Date().toISOString(), - pluginExecutionInfos || [] + timestamp || new Date().toISOString() ) } ), @@ -166,7 +163,6 @@ export class Transcript { public async getPromptForLastInteraction( preamble: Message[] = [], maxPromptLength: number = MAX_AVAILABLE_PROMPT_LENGTH, - pluginsPrompt: Message[] = [], onlyHumanMessages: boolean = false ): Promise<{ prompt: Message[]; contextFiles: ContextFile[]; preciseContexts: PreciseContext[] }> { if (this.interactions.length === 0) { @@ -181,18 +177,14 @@ export class Transcript { const assistantMessage = interaction.getAssistantMessage() const contextMessages = await interaction.getFullContext() if (index === lastInteractionWithContextIndex && !onlyHumanMessages) { - messages.push(...contextMessages, ...pluginsPrompt, humanMessage, assistantMessage) + messages.push(...contextMessages, humanMessage, assistantMessage) } else { - messages.push(...pluginsPrompt, humanMessage, assistantMessage) + messages.push(humanMessage, assistantMessage) } } const preambleTokensUsage = preamble.reduce((acc, message) => acc + estimateTokensUsage(message), 0) - const pluginPreambleTokenUsage = pluginsPrompt.reduce((acc, message) => acc + estimateTokensUsage(message), 0) - let truncatedMessages = truncatePrompt( - messages, - maxPromptLength - preambleTokensUsage - pluginPreambleTokenUsage - ) + let truncatedMessages = truncatePrompt(messages, maxPromptLength - preambleTokensUsage) // Return what context fits in the window const contextFiles: ContextFile[] = [] const preciseContexts: PreciseContext[] = [] @@ -220,17 +212,12 @@ export class Transcript { public setUsedContextFilesForLastInteraction( contextFiles: ContextFile[], - preciseContexts: PreciseContext[] = [], - pluginExecutionInfos: PluginFunctionExecutionInfo[] = [] + preciseContexts: PreciseContext[] = [] ): void { if (this.interactions.length === 0) { throw new Error('Cannot set context files for empty transcript') } - this.interactions[this.interactions.length - 1].setUsedContext( - contextFiles, - pluginExecutionInfos, - preciseContexts - ) + this.interactions[this.interactions.length - 1].setUsedContext(contextFiles, preciseContexts) } public toChat(): ChatMessage[] { diff --git a/lib/shared/src/chat/transcript/interaction.ts b/lib/shared/src/chat/transcript/interaction.ts index bb3ea9f24292..b0221cb5aee9 100644 --- a/lib/shared/src/chat/transcript/interaction.ts +++ b/lib/shared/src/chat/transcript/interaction.ts @@ -1,5 +1,4 @@ import { ContextFile, ContextMessage, PreciseContext } from '../../codebase-context/messages' -import { PluginFunctionExecutionInfo } from '../../plugins/api/types' import { ChatMessage, InteractionMessage } from './messages' @@ -9,7 +8,6 @@ export interface InteractionJSON { fullContext: ContextMessage[] usedContextFiles: ContextFile[] usedPreciseContext: PreciseContext[] - pluginExecutionInfos: PluginFunctionExecutionInfo[] timestamp: string // DEPRECATED: Legacy field for backcompat, renamed to `fullContext` @@ -23,8 +21,7 @@ export class Interaction { private fullContext: Promise, private usedContextFiles: ContextFile[], private usedPreciseContext: PreciseContext[] = [], - public readonly timestamp: string = new Date().toISOString(), - private pluginExecutionInfos: PluginFunctionExecutionInfo[] = [] + public readonly timestamp: string = new Date().toISOString() ) {} public getAssistantMessage(): InteractionMessage { @@ -49,13 +46,8 @@ export class Interaction { return contextMessages.length > 0 } - public setUsedContext( - usedContextFiles: ContextFile[], - pluginExecutionInfos: PluginFunctionExecutionInfo[], - usedPreciseContext: PreciseContext[] - ): void { + public setUsedContext(usedContextFiles: ContextFile[], usedPreciseContext: PreciseContext[]): void { this.usedContextFiles = usedContextFiles - this.pluginExecutionInfos = pluginExecutionInfos this.usedPreciseContext = usedPreciseContext } @@ -69,7 +61,6 @@ export class Interaction { ...this.assistantMessage, contextFiles: this.usedContextFiles, preciseContext: this.usedPreciseContext, - pluginExecutionInfos: this.pluginExecutionInfos, }, ] } @@ -86,7 +77,6 @@ export class Interaction { fullContext: await this.fullContext, usedContextFiles: this.usedContextFiles, usedPreciseContext: this.usedPreciseContext, - pluginExecutionInfos: this.pluginExecutionInfos, timestamp: this.timestamp, } } diff --git a/lib/shared/src/chat/transcript/messages.ts b/lib/shared/src/chat/transcript/messages.ts index 6fcc4cb4867c..54430f14d0c1 100644 --- a/lib/shared/src/chat/transcript/messages.ts +++ b/lib/shared/src/chat/transcript/messages.ts @@ -1,5 +1,4 @@ import { ContextFile, PreciseContext } from '../../codebase-context/messages' -import { PluginFunctionExecutionInfo } from '../../plugins/api/types' import { Message } from '../../sourcegraph-api' import { TranscriptJSON } from '.' @@ -14,7 +13,6 @@ export interface ChatMessage extends Message { displayText?: string contextFiles?: ContextFile[] preciseContext?: PreciseContext[] - pluginExecutionInfos?: PluginFunctionExecutionInfo[] buttons?: ChatButton[] data?: any } diff --git a/lib/shared/src/configuration.ts b/lib/shared/src/configuration.ts index e2e4507e593b..d17b4a73852a 100644 --- a/lib/shared/src/configuration.ts +++ b/lib/shared/src/configuration.ts @@ -33,25 +33,7 @@ export interface Configuration { autocompleteAdvancedEmbeddings: boolean autocompleteExperimentalCompleteSuggestWidgetSelection?: boolean autocompleteExperimentalSyntacticPostProcessing?: boolean - pluginsEnabled?: boolean - pluginsDebugEnabled?: boolean isRunningInsideAgent?: boolean - pluginsConfig?: { - confluence?: { - baseUrl: string - email?: string - apiToken?: string - } - github?: { - apiToken?: string - baseURL?: string - org?: string - repo?: string - } - apiNinjas?: { - apiKey?: string - } - } } export interface ConfigurationWithAccessToken extends Configuration { diff --git a/lib/shared/src/plugins/api/index.ts b/lib/shared/src/plugins/api/index.ts deleted file mode 100644 index b67bff1120a6..000000000000 --- a/lib/shared/src/plugins/api/index.ts +++ /dev/null @@ -1,125 +0,0 @@ -import { ChatClient } from '../../chat/chat' -import { Configuration } from '../../configuration' -import { Message } from '../../sourcegraph-api/completions/types' - -import { makePrompt } from './prompt' -import { - Plugin, - PluginChosenFunctionDescriptor, - PluginFunctionExecutionInfo, - PluginFunctionOutput, - PluginFunctionWithParameters, -} from './types' - -export const chooseDataSources = ( - humanChatInput: string, - client: ChatClient, - plugins: Plugin[], - previousMessages: Message[] = [] -): Promise => { - const dataSources = plugins.flatMap(plugin => plugin.dataSources) - - const messages = makePrompt( - humanChatInput, - dataSources.map(({ descriptor }) => descriptor), - previousMessages - ) - return new Promise((resolve, reject) => { - let lastResponse = '' - client.chat( - messages, - { - onChange: text => { - lastResponse = text - }, - onComplete: () => { - try { - const chosenFunctions = JSON.parse(lastResponse.trim()) as PluginChosenFunctionDescriptor[] - const functionsWithParameters = chosenFunctions - .map(item => { - const dataSource = dataSources.find(ds => ds.descriptor.name === item.name) - const plugin = plugins.find(plugin => - plugin.dataSources.some(ds => ds.descriptor.name === item.name) - ) - if (!plugin || !dataSource) { - return undefined - } - return { - ...dataSource, - pluginName: plugin?.name, - parameters: item.parameters, - } - }) - .filter(Boolean) - resolve(functionsWithParameters as PluginFunctionWithParameters[]) - } catch (error) { - reject(new Error(`Error parsing llm intent detection response: ${error}`)) - } - }, - onError: (error, statusCode) => { - reject(new Error(`error: ${error}\nstatus code: ${statusCode}`)) - }, - }, - { - fast: true, - } - ) - }) -} - -export const runPluginFunctions = async ( - functionsWithParameters: PluginFunctionWithParameters[], - config: Configuration['pluginsConfig'] -): Promise<{ prompt: Message[]; executionInfos: PluginFunctionExecutionInfo[] }> => { - const executionInfos = await Promise.all( - functionsWithParameters.map( - async ({ pluginName, descriptor, handler, parameters }): Promise => { - const { output = [], error }: { output?: PluginFunctionOutput[]; error?: any } = await handler( - parameters, - { config } - ) - .then(output => ({ output })) - .catch(error => ({ - error: `${error}`, - })) - - return { - pluginName, - name: descriptor.name, - parameters, - output, - error, - } - } - ) - ) - - const filtered = executionInfos.filter(executionInfo => !executionInfo.error) - - if (filtered.length > 0) { - return { - prompt: [ - { - speaker: 'human', - text: - 'I have following responses from external API plugins that I called now:\n' + - filtered - .map( - executionInfo => - `from "${executionInfo.pluginName}":\n\`\`\`json\n${JSON.stringify( - executionInfo.output - )}` - ) - .join('\n'), - }, - { - speaker: 'assistant', - text: 'Understood, I have additional knowledge when answering your question.', - }, - ], - executionInfos, - } - } - - return { prompt: [], executionInfos } -} diff --git a/lib/shared/src/plugins/api/prompt.ts b/lib/shared/src/plugins/api/prompt.ts deleted file mode 100644 index 61a1d4df0f2b..000000000000 --- a/lib/shared/src/plugins/api/prompt.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { Message } from '../../sourcegraph-api/completions/types' - -import { PluginChosenFunctionDescriptor, PluginFunctionDescriptor } from './types' - -export const makePrompt = ( - humanChatInput: string, - funcs: PluginFunctionDescriptor[], - history: Message[] = [] -): Message[] => [ - ...history, - { - speaker: 'human', - text: `Some facts you should know are: -- Today is ${new Date().toISOString()} - -Also, I have following functions to call: -\`\`\`json -${JSON.stringify(funcs, null, 2)} -\`\`\` - -Choose up to 3 functions that you want to call to properly reply to the conversation. Only choose functions that you absolutely need. Respond in a only json format like this, example: -\`\`\`json -${JSON.stringify( - [ - { - name: 'function_name', - parameters: { - parameter_name: 'parameter_value', - }, - }, - ] as PluginChosenFunctionDescriptor[], - null, - 2 -)} -\`\`\` - -If no additional functions calls are needed or you don't know what to reply respond with empty JSON array, like this: -\`\`\`json -[] -\`\`\` - -Order array elements by priority, the first element is the most important one. - -Conversation starts here:\n\n - -${JSON.stringify(humanChatInput)} -`, - }, - { - speaker: 'assistant', - }, -] diff --git a/lib/shared/src/plugins/api/types.ts b/lib/shared/src/plugins/api/types.ts deleted file mode 100644 index ec7650d4c73f..000000000000 --- a/lib/shared/src/plugins/api/types.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { Configuration } from '../../configuration' - -export type PluginFunctionParameters = Record - -export interface PluginFunctionDescriptor { - name: string - description: string - parameters: { - type: 'object' - properties: { - [key: string]: { - type: 'string' | 'number' | 'boolean' - enum?: string[] - description?: string - default?: string | number | boolean - } - } - description?: string - required?: string[] - } -} - -export interface PluginFunctionOutput { - url: string - [key: string]: any -} - -type FunctionHandler = (parameters: PluginFunctionParameters, api: PluginAPI) => Promise - -interface PluginFunction { - descriptor: PluginFunctionDescriptor - handler: FunctionHandler -} - -export interface PluginFunctionWithParameters extends PluginFunction { - pluginName: string - parameters: PluginFunctionParameters -} - -export interface PluginFunctionExecutionInfo { - name: string - pluginName: string - parameters?: PluginFunctionParameters - output: PluginFunctionOutput[] - error?: any -} - -export interface PluginChosenFunctionDescriptor { - name: string - parameters: PluginFunctionParameters -} - -export interface Plugin { - name: string - description: string - dataSources: PluginFunction[] -} - -export interface PluginAPI { - config: TConfig -} diff --git a/lib/shared/src/plugins/built-in/air-quality.ts b/lib/shared/src/plugins/built-in/air-quality.ts deleted file mode 100644 index 153b5398541f..000000000000 --- a/lib/shared/src/plugins/built-in/air-quality.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { Plugin, PluginAPI, PluginFunctionOutput, PluginFunctionParameters } from '../api/types' - -import { fetchAPINinjas } from './lib/fetch-api-ninjas' - -export const airQualityPlugin: Plugin = { - name: 'Air Quality plugin', - description: 'Get air quality information for any city in the world.', - dataSources: [ - { - descriptor: { - name: 'get_air_quality_in_city', - description: - 'This API provides the latest air quality information for any city in the world. It provides not only the overall Air Quality Index (AQI) but also concentrations for major pollutants such as Carbon monoxide (CO), Nitrogen dioxide (NO2), Ozone (O3), Sulphur dioxide (SO2), PM2.5 particulates, and PM10 particulates.', - parameters: { - type: 'object', - properties: { - city: { - type: 'string', - description: 'A valid full city name to get the weather for, e.g San Francisco', - }, - }, - required: ['city'], - }, - }, - handler: (parameters: PluginFunctionParameters, api: PluginAPI): Promise => { - if (typeof parameters?.city !== 'string') { - return Promise.reject(new Error('Invalid parameters')) - } - const url = 'https://api.api-ninjas.com/v1/airquality?city=' + parameters.city - const apiKey = api.config?.apiNinjas?.apiKey - if (!apiKey) { - return Promise.reject(new Error('Missing API key')) - } - return fetchAPINinjas(url, apiKey).then(async response => { - if (!response.ok) { - return [ - { - url, - error: 'Could not fetch air quality data', - }, - ] - } - const json = await response.json() - return [ - { - url, - city: parameters.city, - ...json, - }, - ] - }) - }, - }, - ], -} diff --git a/lib/shared/src/plugins/built-in/confluence.ts b/lib/shared/src/plugins/built-in/confluence.ts deleted file mode 100644 index ff5615c1671d..000000000000 --- a/lib/shared/src/plugins/built-in/confluence.ts +++ /dev/null @@ -1,116 +0,0 @@ -import fetch from 'isomorphic-fetch' - -import { Plugin, PluginAPI, PluginFunctionOutput, PluginFunctionParameters } from '../api/types' - -interface SearchResult { - content: { - id: string - } - url: string - excerpt: string -} - -interface WikiContent { - body: { - storage: { - value: string - } - } -} - -const searchWiki = async (query: string, opts: { email: string; token: string; baseUrl: string }): Promise => { - const searchUrl = `${opts.baseUrl}/wiki/rest/api/search?cql=${encodeURIComponent(`text ~ "${query}"`)}&limit=2` - const searchOptions = { - method: 'GET', - headers: { - Authorization: 'Basic ' + btoa(opts.email + ':' + opts.token), - 'Content-Type': 'application/json', - }, - } - - try { - const searchResponse = await fetch(searchUrl, searchOptions) - const searchJson = await searchResponse.json() - const results = searchJson?.results as SearchResult[] - - return results.map(async result => { - const contentUrl = `${opts.baseUrl}/wiki/rest/api/content/${result.content.id}?expand=body.storage` - const contentResponse = await fetch(contentUrl, searchOptions) - const contentJson = await contentResponse.json() - const content = contentJson as WikiContent - const sanitizedParagraph = removeHtmlTags(content.body.storage.value) - const sanitizedBlurb = removeHtmlTags(result.excerpt) - const text = getSurroundingText(sanitizedParagraph, sanitizedBlurb) - return { - content: text, - url: `${opts.baseUrl}/${result.url}`, - } - }) - } catch (error) { - // Handle and log any errors - console.error('Error in searchWiki:', error) - throw error - } -} - -// todo: add isEnabled check function -export const confluencePlugin: Plugin = { - name: 'Confluence plugin', - description: 'Search Confluence Wiki pages.', - dataSources: [ - { - descriptor: { - name: 'search_confluence_wiki_pages', - description: - 'The API provides a powerful search functionality for finding content within your connected Confluence Wiki. It allows users to search for pages, blog posts, comments, attachments, and other content types within the Confluence space. The search results include the matching piece of content and its unique URL.', - parameters: { - type: 'object', - properties: { - query: { - type: 'string', - description: - 'Keyword to search against Confluence Wiki pages. It can be a title, a page content, or a page excerpt.', - }, - }, - required: ['query'], - }, - }, - handler: async (parameters: PluginFunctionParameters, api: PluginAPI): Promise => { - const { query } = parameters - - const email = api.config?.confluence?.email - const token = api.config?.confluence?.apiToken - const baseUrl = api.config?.confluence?.baseUrl - if (!email || !token || !baseUrl) { - return Promise.reject(new Error('Confluence plugin not configured')) - } - if (typeof query === 'string') { - const items = await searchWiki(query, { - email, - token, - baseUrl, - }) - return Promise.all(items) - } - return Promise.reject(new Error('Invalid parameters')) - }, - }, - ], -} - -// This function is meant to sanitize confluence content that's semi-html: -//

hello

and @@@h1@@@ hello @@@endh1@@@ will both result in `hello`. -function removeHtmlTags(input: string): string { - return input.replace(/<[^>]+>|@@@[^@]+@@@/g, '') -} - -function getSurroundingText(paragraph: string, blurb: string): string { - const blurbIndex = paragraph.indexOf(blurb) - if (blurbIndex === -1) { - return '' - } - - const start = Math.max(0, blurbIndex - 300) - const end = Math.min(paragraph.length, blurbIndex + blurb.length + 300) - return paragraph.slice(start, end) -} diff --git a/lib/shared/src/plugins/built-in/github-issues.ts b/lib/shared/src/plugins/built-in/github-issues.ts deleted file mode 100644 index e89df51ac713..000000000000 --- a/lib/shared/src/plugins/built-in/github-issues.ts +++ /dev/null @@ -1,153 +0,0 @@ -import fetch from 'isomorphic-fetch' -import { pick } from 'lodash' - -import { Plugin, PluginAPI, PluginFunctionOutput, PluginFunctionParameters } from '../api/types' - -// TODO: this is only useful for our organization -const defaultOrg = 'sourcegraph' -const defaultBaseURL = 'https://api.github.com/' -const path = '/search/issues' - -interface User { - name: string | null - login: string - html_url?: string - url?: string -} - -interface Item { - title: string - body: string - html_url: string - assignee: User | null - user: User | null - created_at: string - updated_at: string - state: string -} - -interface OutputItem extends Omit { - url: Item['html_url'] -} - -interface GitHubResponse { - items: Item[] -} - -const searchGitHub = async ( - query: string, - baseUrl: string, - apiToken: string, - limit: number = 5, - org?: string, - repo?: string -): Promise => { - const url = new URL(path, baseUrl) - - // create a filter for org and repo, if defined - let filter = `org:${org ?? defaultOrg}` - if (repo) { - filter += ` repo:${repo}` - } - - url.searchParams.set('per_page', `${limit}`) - url.searchParams.set('q', `${query} ${filter}`) - const opts = { - method: 'GET', - headers: { - Authorization: apiToken, - 'Content-Type': 'application/json', - }, - } - - try { - const rawResponse = await fetch(url, opts) - const response = (await rawResponse.json()) as GitHubResponse - - const items = response?.items - return ( - items?.map(item => { - const title = item.title.slice(0, 180) // up to 180 characters - const body = removeHtmlTags(item.body).slice(0, 300) // up to 300 characters - const user: User | null = item.user - ? { - name: item.user.name, - login: item.user.login, - url: item.user.html_url, - } - : null - const assignee: User | null = item.assignee - ? { - name: item.assignee.name, - login: item.assignee.login, - url: item.assignee.html_url, - } - : null - const output: OutputItem = { - ...pick(item, ['created_at', 'updated_at', 'state']), - title, - body, - user, - assignee, - url: item.html_url, - } - return output - }) ?? [] - ) - } catch (error) { - // Handle and log any errors - console.error('Error in searchGitHub:', error) - throw error - } -} - -// todo: add isEnabled check function -export const githubIssuesPlugin: Plugin = { - name: 'GitHub plugin', - description: 'Search GitHub Issues and pull requests.', - dataSources: [ - { - descriptor: { - name: 'search_github_issues', - description: - 'Search GitHub Issues and pull requests. Use this to understand current code problems, feature implementations, their rationale, and to gain deeper insights into various topics.', - parameters: { - type: 'object', - properties: { - query: { - type: 'string', - description: 'Query, uses github issue search query format', - }, - limit: { - type: 'number', - description: 'Maximum number of results to return.', - default: 5, - }, - }, - required: ['query'], - }, - }, - handler: async (parameters: PluginFunctionParameters, api: PluginAPI): Promise => { - const { query, limit = 5 } = parameters - - if (typeof query !== 'string') { - return Promise.reject(new Error('Invalid parameters')) - } - const apiToken = api.config?.github?.apiToken - if (!apiToken) { - return Promise.reject(new Error('Missing GitHub API token')) - } - const baseUrl = api.config?.github?.baseURL ?? defaultBaseURL - const { org, repo } = api.config?.github ?? {} - - return searchGitHub(query, baseUrl, apiToken, Number(limit), org, repo) - }, - }, - ], -} - -// This function is meant to sanitize confluence content that's semi-html: -//

hello

and @@@h1@@@ hello @@@endh1@@@ will both result in `hello`. -function removeHtmlTags(input: string): string { - return input.replace(/<[^>]+>|@@@[^@]+@@@/g, '') -} diff --git a/lib/shared/src/plugins/built-in/index.ts b/lib/shared/src/plugins/built-in/index.ts deleted file mode 100644 index a7b48859c7b2..000000000000 --- a/lib/shared/src/plugins/built-in/index.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { Plugin } from '../api/types' - -import { airQualityPlugin } from './air-quality' -import { confluencePlugin } from './confluence' -import { githubIssuesPlugin } from './github-issues' -import { timezonePlugin } from './timezone' -import { urlReaderPlugin } from './url-reader' -import { weatherPlugin } from './weather' - -export const defaultPlugins: Plugin[] = [ - weatherPlugin, - timezonePlugin, - airQualityPlugin, - urlReaderPlugin, - confluencePlugin, - githubIssuesPlugin, -].sort((a, b) => a.name.localeCompare(b.name)) diff --git a/lib/shared/src/plugins/built-in/lib/fetch-api-ninjas.ts b/lib/shared/src/plugins/built-in/lib/fetch-api-ninjas.ts deleted file mode 100644 index 7ad307554a6c..000000000000 --- a/lib/shared/src/plugins/built-in/lib/fetch-api-ninjas.ts +++ /dev/null @@ -1,9 +0,0 @@ -import fetch from 'isomorphic-fetch' - -export const fetchAPINinjas = (url: string, apiKey: string): Promise => - fetch(url, { - method: 'GET', - headers: { - 'X-API-Key': apiKey, - }, - }) diff --git a/lib/shared/src/plugins/built-in/timezone.ts b/lib/shared/src/plugins/built-in/timezone.ts deleted file mode 100644 index 56df913e5751..000000000000 --- a/lib/shared/src/plugins/built-in/timezone.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { Plugin, PluginAPI, PluginFunctionOutput, PluginFunctionParameters } from '../api/types' - -import { fetchAPINinjas } from './lib/fetch-api-ninjas' - -export const timezonePlugin: Plugin = { - name: 'Timezone plugin', - description: 'Get current data and time for any city in the world.', - dataSources: [ - { - descriptor: { - name: 'get_city_time', - description: - 'The API provides the current date and time for any city in the world. The data returned includes the timezone, full datetime, and day of the week.', - parameters: { - type: 'object', - properties: { - city: { - type: 'string', - description: 'A valid full city name to get the weather for, e.g San Francisco', - }, - }, - required: ['city'], - }, - }, - handler: (parameters: PluginFunctionParameters, api: PluginAPI): Promise => { - if (typeof parameters?.city !== 'string') { - return Promise.reject(new Error('Invalid parameters')) - } - const url = 'https://api.api-ninjas.com/v1/worldtime?city=' + parameters.city - const apiKey = api.config?.apiNinjas?.apiKey - if (!apiKey) { - return Promise.reject(new Error('Missing API key')) - } - return fetchAPINinjas(url, apiKey).then(async response => { - if (!response.ok) { - return [ - { - url, - error: 'Could not fetch timezone data', - }, - ] - } - const json = await response.json() - return [ - { - url: '', - city: parameters.city, - current_datetime: json.datetime, - current_day_of_week: json.day_of_week, - timezone: json.timezone, - }, - ] - }) - }, - }, - ], -} diff --git a/lib/shared/src/plugins/built-in/url-reader.ts b/lib/shared/src/plugins/built-in/url-reader.ts deleted file mode 100644 index 822ef713d518..000000000000 --- a/lib/shared/src/plugins/built-in/url-reader.ts +++ /dev/null @@ -1,54 +0,0 @@ -import fetch from 'isomorphic-fetch' - -import { Plugin, PluginFunctionOutput, PluginFunctionParameters } from '../api/types' - -async function fetchURL(url: string): Promise { - // Use the fetch API to get the webpage content - const response = await fetch(url) - - // Check if the request was successful - if (!response.ok) { - throw new Error(`HTTP error! status: ${response.status}`) - } - - // Parse the webpage content as text - const text = await response.text() - - // Return the web page content - const result = { - url, - body: text.slice(0, 1000), - } - - return result -} - -export const urlReaderPlugin: Plugin = { - name: 'URL Reader plugin', - description: 'Get the content of a web page by URL.', - dataSources: [ - { - descriptor: { - name: 'get_page_content_by_url', - description: - 'The API provides web scraper service to retrieve HTML from any website URL. The API returns the scraped data from the provided URL, with a maximum size of initial 1000 chars of the content.', - parameters: { - type: 'object', - properties: { - url: { - type: 'string', - description: 'The URL of the web page to get the content of.', - }, - }, - required: ['url'], - }, - }, - handler: async (parameters: PluginFunctionParameters): Promise => { - if (typeof parameters?.url === 'string') { - return fetchURL(parameters.url).then(page => [page]) - } - return Promise.reject(new Error('Invalid parameters')) - }, - }, - ], -} diff --git a/lib/shared/src/plugins/built-in/weather.ts b/lib/shared/src/plugins/built-in/weather.ts deleted file mode 100644 index 282b66adf721..000000000000 --- a/lib/shared/src/plugins/built-in/weather.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { Plugin, PluginAPI, PluginFunctionOutput, PluginFunctionParameters } from '../api/types' - -import { fetchAPINinjas } from './lib/fetch-api-ninjas' - -export const weatherPlugin: Plugin = { - name: 'Weather plugin', - description: 'Get weather information for any city in the world.', - dataSources: [ - { - descriptor: { - name: 'get_city_weather_info', - description: - "The API provides the latest weather information for any city in the world. The API returns a variety of weather data including wind speed, wind degrees, temperature, humidity, sunset and sunrise times, minimum and maximum temperatures, cloud percentage, and the 'feels like' temperature.", - parameters: { - type: 'object', - properties: { - city: { - type: 'string', - description: 'A valid full city name to get the weather for, e.g San Francisco', - }, - }, - required: ['city'], - }, - }, - handler: (parameters: PluginFunctionParameters, api: PluginAPI): Promise => { - if (typeof parameters?.city !== 'string') { - return Promise.reject(new Error('Invalid parameters')) - } - const url = 'https://api.api-ninjas.com/v1/weather?city=' + parameters.city - const apiKey = api.config?.apiNinjas?.apiKey - if (!apiKey) { - return Promise.reject(new Error('Missing API key')) - } - return fetchAPINinjas(url, apiKey).then(async response => { - if (!response.ok) { - return [ - { - url, - error: 'Could not fetch weather data', - }, - ] - } - const json = await response.json() - return [ - { - url, - city: parameters.city, - temperature: json.temp, - feels_like: json.feels_like, - max_temperature: json.temp_max, - }, - ] - }) - }, - }, - ], -} diff --git a/lib/ui/src/Chat.tsx b/lib/ui/src/Chat.tsx index 1369357e13c4..333b02936f9f 100644 --- a/lib/ui/src/Chat.tsx +++ b/lib/ui/src/Chat.tsx @@ -50,7 +50,6 @@ interface ChatProps extends ChatClassNames { onAbortMessageInProgress?: () => void isCodyEnabled: boolean ChatButtonComponent?: React.FunctionComponent - pluginsDevMode?: boolean chatCommands?: [string, CodyPrompt][] | null filterChatCommands?: (chatCommands: [string, CodyPrompt][], input: string) => [string, CodyPrompt][] ChatCommandsComponent?: React.FunctionComponent @@ -167,7 +166,6 @@ export const Chat: React.FunctionComponent = ({ onAbortMessageInProgress = () => {}, isCodyEnabled, ChatButtonComponent, - pluginsDevMode, chatCommands, filterChatCommands, ChatCommandsComponent, @@ -395,7 +393,6 @@ export const Chat: React.FunctionComponent = ({ submitButtonComponent={SubmitButton} chatInputClassName={chatInputClassName} ChatButtonComponent={ChatButtonComponent} - pluginsDevMode={pluginsDevMode} isTranscriptError={isTranscriptError} /> )} diff --git a/lib/ui/src/chat/PluginExecutionInfos.module.css b/lib/ui/src/chat/PluginExecutionInfos.module.css deleted file mode 100644 index 51f0b7be8593..000000000000 --- a/lib/ui/src/chat/PluginExecutionInfos.module.css +++ /dev/null @@ -1,5 +0,0 @@ - -.item { - padding: 0.5rem; - overflow-x: auto; -} diff --git a/lib/ui/src/chat/PluginExecutionInfos.tsx b/lib/ui/src/chat/PluginExecutionInfos.tsx deleted file mode 100644 index 368a34cd7fd6..000000000000 --- a/lib/ui/src/chat/PluginExecutionInfos.tsx +++ /dev/null @@ -1,47 +0,0 @@ -import * as React from 'react' - -import { mdiCodeJson } from '@mdi/js' - -import { ChatMessage, pluralize } from '@sourcegraph/cody-shared' - -import { TranscriptAction } from './actions/TranscriptAction' - -import styles from './PluginExecutionInfos.module.css' - -interface PluginExecutionInfosProps { - pluginExecutionInfos: NonNullable - devMode?: boolean - className?: string -} - -export const PluginExecutionInfos: React.FC = ({ - pluginExecutionInfos, - devMode, - className, -}) => ( - ({ - verb: '', - object: ( -
-

from "{pluginName}" got:

-
-                            {JSON.stringify(
-                                devMode ? { function: name, input: parameters, output, error } : error || output,
-                                null,
-                                2
-                            )}
-                        
-
- ), - icon: mdiCodeJson, - })), - ]} - className={className} - /> -) diff --git a/lib/ui/src/chat/Transcript.tsx b/lib/ui/src/chat/Transcript.tsx index 460169d3c8fb..57bb322ed64d 100644 --- a/lib/ui/src/chat/Transcript.tsx +++ b/lib/ui/src/chat/Transcript.tsx @@ -36,7 +36,6 @@ export const Transcript: React.FunctionComponent< copyButtonOnSubmit?: CopyButtonProps['copyButtonOnSubmit'] submitButtonComponent?: React.FunctionComponent ChatButtonComponent?: React.FunctionComponent - pluginsDevMode?: boolean isTranscriptError?: boolean } & TranscriptItemClassNames > = React.memo(function TranscriptContent({ @@ -62,7 +61,6 @@ export const Transcript: React.FunctionComponent< submitButtonComponent, chatInputClassName, ChatButtonComponent, - pluginsDevMode, isTranscriptError, }) { // Scroll down whenever a new human message is received as input. @@ -148,7 +146,6 @@ export const Transcript: React.FunctionComponent< submitButtonComponent={submitButtonComponent} chatInputClassName={chatInputClassName} ChatButtonComponent={ChatButtonComponent} - pluginsDevMode={pluginsDevMode} /> ) )} diff --git a/lib/ui/src/chat/TranscriptItem.tsx b/lib/ui/src/chat/TranscriptItem.tsx index 4427be1991d3..80a5a78f6261 100644 --- a/lib/ui/src/chat/TranscriptItem.tsx +++ b/lib/ui/src/chat/TranscriptItem.tsx @@ -16,7 +16,6 @@ import { import { BlinkingCursor } from './BlinkingCursor' import { CodeBlocks } from './CodeBlocks' import { ContextFiles, FileLinkProps } from './ContextFiles' -import { PluginExecutionInfos } from './PluginExecutionInfos' import { PreciseContexts, SymbolLinkProps } from './PreciseContext' import styles from './TranscriptItem.module.css' @@ -57,7 +56,6 @@ export const TranscriptItem: React.FunctionComponent< abortMessageInProgressComponent?: React.FunctionComponent<{ onAbortMessageInProgress: () => void }> onAbortMessageInProgress?: () => void ChatButtonComponent?: React.FunctionComponent - pluginsDevMode?: boolean } & TranscriptItemClassNames > = React.memo(function TranscriptItemContent({ message, @@ -83,7 +81,6 @@ export const TranscriptItem: React.FunctionComponent< submitButtonComponent: SubmitButton, chatInputClassName, ChatButtonComponent, - pluginsDevMode, }) { const [formInput, setFormInput] = useState(message.displayText ?? '') const textarea = @@ -166,15 +163,6 @@ export const TranscriptItem: React.FunctionComponent< /> )} - {message.pluginExecutionInfos && message.pluginExecutionInfos.length > 0 && ( -
- -
- )}
export enum ContextEvent { @@ -209,8 +206,6 @@ export class ContextProvider implements vscode.Disposable { ...localProcess, debugEnable: this.config.debugEnable, serverEndpoint: this.config.serverEndpoint, - pluginsEnabled: this.config.pluginsEnabled, - pluginsDebugEnabled: this.config.pluginsDebugEnabled, } // update codebase context on configuration change diff --git a/vscode/src/chat/FixupViewProvider.ts b/vscode/src/chat/FixupViewProvider.ts index ff511c74ed8a..54d8efff3f59 100644 --- a/vscode/src/chat/FixupViewProvider.ts +++ b/vscode/src/chat/FixupViewProvider.ts @@ -114,10 +114,6 @@ export class FixupProvider extends MessageProvider { // not implemented } - protected handleEnabledPlugins(): void { - // not implemented - } - protected handleMyPrompts(): void { // not implemented } diff --git a/vscode/src/chat/InlineChatViewProvider.ts b/vscode/src/chat/InlineChatViewProvider.ts index 589e24d68b96..69b636326141 100644 --- a/vscode/src/chat/InlineChatViewProvider.ts +++ b/vscode/src/chat/InlineChatViewProvider.ts @@ -128,10 +128,6 @@ export class InlineChatViewProvider extends MessageProvider { // showing suggestions not yet implemented for inline chat } - protected handleEnabledPlugins(): void { - // plugins not yet implemented for inline chat - } - protected handleCodyCommands(): void { // my prompts not yet implemented for inline chat } diff --git a/vscode/src/chat/MessageProvider.ts b/vscode/src/chat/MessageProvider.ts index 4cf2259b1d03..8de5bfa1ab4f 100644 --- a/vscode/src/chat/MessageProvider.ts +++ b/vscode/src/chat/MessageProvider.ts @@ -13,9 +13,6 @@ import { Typewriter } from '@sourcegraph/cody-shared/src/chat/typewriter' import { reformatBotMessage } from '@sourcegraph/cody-shared/src/chat/viewHelpers' import { annotateAttribution, Guardrails } from '@sourcegraph/cody-shared/src/guardrails' import { IntentDetector } from '@sourcegraph/cody-shared/src/intent-detector' -import * as plugins from '@sourcegraph/cody-shared/src/plugins/api' -import { PluginFunctionExecutionInfo } from '@sourcegraph/cody-shared/src/plugins/api/types' -import { defaultPlugins } from '@sourcegraph/cody-shared/src/plugins/built-in' import { ANSWER_TOKENS, DEFAULT_MAX_TOKENS } from '@sourcegraph/cody-shared/src/prompt/constants' import { Message } from '@sourcegraph/cody-shared/src/sourcegraph-api' import { TelemetryService } from '@sourcegraph/cody-shared/src/telemetry' @@ -55,7 +52,6 @@ abstract class MessageHandler { protected abstract handleHistory(history: UserLocalHistory): void protected abstract handleError(errorMsg: string): void protected abstract handleSuggestions(suggestions: string[]): void - protected abstract handleEnabledPlugins(plugins: string[]): void protected abstract handleCodyCommands(prompts: [string, CodyPrompt][]): void protected abstract handleTranscriptErrors(transciptError: boolean): void } @@ -123,7 +119,6 @@ export abstract class MessageProvider extends MessageHandler implements vscode.D this.loadChatHistory() this.sendTranscript() this.sendHistory() - this.sendEnabledPlugins(localStorage.getEnabledPlugins() ?? []) await this.loadRecentChat() await this.contextProvider.init() await this.sendCodyCommands() @@ -165,10 +160,6 @@ export abstract class MessageProvider extends MessageHandler implements vscode.D this.telemetryService.log('CodyVSCodeExtension:restoreChatHistoryButton:clicked') } - private sendEnabledPlugins(plugins: string[]): void { - this.handleEnabledPlugins(plugins) - } - private createNewChatID(): void { this.currentChatID = new Date(Date.now()).toUTCString() } @@ -286,58 +277,6 @@ export abstract class MessageProvider extends MessageHandler implements vscode.D await this.onCompletionEnd() } - private async getPluginsContext( - humanChatInput: string - ): Promise<{ prompt?: Message[]; executionInfos?: PluginFunctionExecutionInfo[] }> { - this.telemetryService.log('CodyVSCodeExtension:getPluginsContext:used') - const enabledPluginNames = localStorage.getEnabledPlugins() ?? [] - const enabledPlugins = defaultPlugins.filter(plugin => enabledPluginNames.includes(plugin.name)) - if (enabledPlugins.length === 0) { - return {} - } - this.telemetryService.log('CodyVSCodeExtension:getPluginsContext:enabledPlugins', { names: enabledPluginNames }) - - this.transcript.addAssistantResponse('', 'Identifying applicable plugins...\n') - this.sendTranscript() - - const { prompt: previousMessages } = await this.transcript.getPromptForLastInteraction( - [], - this.maxPromptTokens, - [], - true - ) - - try { - this.telemetryService.log('CodyVSCodeExtension:getPluginsContext:chooseDataSourcesUsed') - const descriptors = await plugins.chooseDataSources( - humanChatInput, - this.chat, - enabledPlugins, - previousMessages - ) - this.telemetryService.log('CodyVSCodeExtension:getPluginsContext:descriptorsFound', { - count: descriptors.length, - }) - if (descriptors.length !== 0) { - this.transcript.addAssistantResponse( - '', - `Using ${descriptors - .map(descriptor => descriptor.pluginName) - .join(', ')} for additional context...\n` - ) - this.sendTranscript() - - this.telemetryService.log('CodyVSCodeExtension:getPluginsContext:runPluginFunctionsCalled', { - count: descriptors.length, - }) - return await plugins.runPluginFunctions(descriptors, this.contextProvider.config.pluginsConfig) - } - } catch (error) { - console.error('Error getting plugin context', error) - } - return {} - } - private getRecipe(id: RecipeID): Recipe | undefined { return this.platform.recipes.find(recipe => recipe.id === id) } @@ -386,14 +325,6 @@ export abstract class MessageProvider extends MessageHandler implements vscode.D this.isMessageInProgress = true this.transcript.addInteraction(interaction) - let pluginsPrompt: Message[] = [] - let pluginExecutionInfos: PluginFunctionExecutionInfo[] = [] - if (this.contextProvider.config.pluginsEnabled && recipeId === 'chat-question') { - const result = await this.getPluginsContext(humanChatInput) - pluginsPrompt = result?.prompt ?? [] - pluginExecutionInfos = result?.executionInfos ?? [] - } - // Check whether or not to connect to LLM backend for responses // Ex: performing fuzzy / context-search does not require responses from LLM backend switch (recipeId) { @@ -412,14 +343,9 @@ export abstract class MessageProvider extends MessageHandler implements vscode.D const { prompt, contextFiles, preciseContexts } = await this.transcript.getPromptForLastInteraction( getPreamble(this.contextProvider.context.getCodebase(), myPremade), - this.maxPromptTokens, - pluginsPrompt - ) - this.transcript.setUsedContextFilesForLastInteraction( - contextFiles, - preciseContexts, - pluginExecutionInfos + this.maxPromptTokens ) + this.transcript.setUsedContextFilesForLastInteraction(contextFiles, preciseContexts) this.sendPrompt(prompt, interaction.getAssistantMessage().prefix ?? '', recipe.multiplexerTopic) await this.saveTranscriptToChatHistory() } diff --git a/vscode/src/chat/protocol.ts b/vscode/src/chat/protocol.ts index 270c1f83e609..1c6d0d0b2367 100644 --- a/vscode/src/chat/protocol.ts +++ b/vscode/src/chat/protocol.ts @@ -39,7 +39,6 @@ export type WebviewMessage = value?: string } | { command: 'abort' } - | { command: 'setEnabledPlugins'; plugins: string[] } | { command: 'custom-prompt'; title: string; value?: CodyPromptType } | { command: 'reload' } @@ -56,15 +55,13 @@ export type ExtensionMessage = | { type: 'errors'; errors: string } | { type: 'suggestions'; suggestions: string[] } | { type: 'app-state'; isInstalled: boolean } - | { type: 'enabled-plugins'; plugins: string[] } | { type: 'custom-prompts'; prompts: [string, CodyPrompt][] } | { type: 'transcript-errors'; isTranscriptError: boolean } /** * The subset of configuration that is visible to the webview. */ -export interface ConfigurationSubsetForWebview - extends Pick {} +export interface ConfigurationSubsetForWebview extends Pick {} /** * URLs for the Sourcegraph instance and app. diff --git a/vscode/src/configuration.test.ts b/vscode/src/configuration.test.ts index 290b7e68dfc3..ca20ec6fe692 100644 --- a/vscode/src/configuration.test.ts +++ b/vscode/src/configuration.test.ts @@ -11,9 +11,6 @@ describe('getConfiguration', () => { get: (_key: string, defaultValue?: T): typeof defaultValue | undefined => defaultValue, } expect(getConfiguration(config)).toEqual({ - pluginsConfig: {}, - pluginsDebugEnabled: true, - pluginsEnabled: false, serverEndpoint: DOTCOM_URL.href, codebase: '', customHeaders: {}, @@ -100,14 +97,6 @@ describe('getConfiguration', () => { return false case 'cody.autocomplete.experimental.syntacticPostProcessing': return false - case 'cody.plugins.enabled': - return true - case 'cody.plugins.config': - return { - foo: 'bar', - } - case 'cody.plugins.debug.enabled': - return false case 'cody.advanced.agent.running': return false default: @@ -116,9 +105,6 @@ describe('getConfiguration', () => { }, } expect(getConfiguration(config)).toEqual({ - pluginsEnabled: true, - pluginsConfig: { foo: 'bar' }, - pluginsDebugEnabled: false, serverEndpoint: 'http://example.com', codebase: 'my/codebase', useContext: 'keyword', diff --git a/vscode/src/configuration.ts b/vscode/src/configuration.ts index 10d8a490b8e5..383450d062da 100644 --- a/vscode/src/configuration.ts +++ b/vscode/src/configuration.ts @@ -73,9 +73,6 @@ export function getConfiguration(config: ConfigGetter = vscode.workspace.getConf CONFIG_KEY.autocompleteExperimentalSyntacticPostProcessing, false ), - pluginsEnabled: config.get(CONFIG_KEY.pluginsEnabled, false), - pluginsDebugEnabled: config.get(CONFIG_KEY.pluginsDebugEnabled, true), - pluginsConfig: config.get(CONFIG_KEY.pluginsConfig, {}), // Note: In spirit, we try to minimize agent-specific code paths in the VSC extension. // We currently use this flag for the agent to provide more helpful error messages diff --git a/vscode/src/services/LocalStorageProvider.ts b/vscode/src/services/LocalStorageProvider.ts index 8696c6f41a9b..cb48db79223d 100644 --- a/vscode/src/services/LocalStorageProvider.ts +++ b/vscode/src/services/LocalStorageProvider.ts @@ -9,7 +9,6 @@ export class LocalStorage { protected ANONYMOUS_USER_ID_KEY = 'sourcegraphAnonymousUid' protected LAST_USED_ENDPOINT = 'SOURCEGRAPH_CODY_ENDPOINT' protected CODY_ENDPOINT_HISTORY = 'SOURCEGRAPH_CODY_ENDPOINT_HISTORY' - protected KEY_ENABLED_PLUGINS = 'KEY_ENABLED_PLUGINS' protected KEY_LAST_USED_RECIPES = 'SOURCEGRAPH_CODY_LAST_USED_RECIPE_NAMES' /** @@ -120,18 +119,6 @@ export class LocalStorage { return { anonymousUserID: id, created } } - public async setEnabledPlugins(plugins: string[]): Promise { - try { - await this.storage.update(this.KEY_ENABLED_PLUGINS, plugins) - } catch (error) { - console.error(error) - } - } - - public getEnabledPlugins(): string[] | null { - return this.storage.get(this.KEY_ENABLED_PLUGINS, null) - } - public async setLastUsedCommands(recipes: string[]): Promise { if (recipes.length === 0) { return diff --git a/vscode/webviews/App.tsx b/vscode/webviews/App.tsx index f0b16e3e9e1a..2ac146a74c1b 100644 --- a/vscode/webviews/App.tsx +++ b/vscode/webviews/App.tsx @@ -2,8 +2,6 @@ import { useCallback, useEffect, useMemo, useState } from 'react' import './App.css' -import { uniq, without } from 'lodash' - import { ChatContextStatus } from '@sourcegraph/cody-shared/src/chat/context' import { CodyPrompt } from '@sourcegraph/cody-shared/src/chat/prompts' import { ChatHistory, ChatMessage } from '@sourcegraph/cody-shared/src/chat/transcript/messages' @@ -16,16 +14,14 @@ import { LoadingPage } from './LoadingPage' import { Login } from './Login' import { View } from './NavBar' import { Notices } from './Notices' -import { Plugins } from './Plugins' import { UserHistory } from './UserHistory' import { createWebviewTelemetryService } from './utils/telemetry' import type { VSCodeWrapper } from './utils/VSCodeApi' export const App: React.FunctionComponent<{ vscodeAPI: VSCodeWrapper }> = ({ vscodeAPI }) => { - const [config, setConfig] = useState< - | (Pick & LocalEnv) - | null - >(null) + const [config, setConfig] = useState<(Pick & LocalEnv) | null>( + null + ) const [endpoint, setEndpoint] = useState(null) const [view, setView] = useState() const [messageInProgress, setMessageInProgress] = useState(null) @@ -39,7 +35,6 @@ export const App: React.FunctionComponent<{ vscodeAPI: VSCodeWrapper }> = ({ vsc const [errorMessages, setErrorMessages] = useState([]) const [suggestions, setSuggestions] = useState() const [isAppInstalled, setIsAppInstalled] = useState(false) - const [enabledPlugins, setEnabledPlugins] = useState([]) const [myPrompts, setMyPrompts] = useState< [string, CodyPrompt & { isLastInGroup?: boolean; instruction?: string }][] | null >(null) @@ -89,9 +84,6 @@ export const App: React.FunctionComponent<{ vscodeAPI: VSCodeWrapper }> = ({ vsc case 'app-state': setIsAppInstalled(message.isInstalled) break - case 'enabled-plugins': - setEnabledPlugins(message.plugins) - break case 'custom-prompts': { let prompts: [string, CodyPrompt & { isLastInGroup?: boolean; instruction?: string }][] = message.prompts @@ -147,15 +139,6 @@ export const App: React.FunctionComponent<{ vscodeAPI: VSCodeWrapper }> = ({ vsc [setEndpoint, vscodeAPI] ) - const onPluginToggle = useCallback( - (pluginName: string, enabled: boolean) => { - const newPlugins = enabled ? uniq([...enabledPlugins, pluginName]) : without(enabledPlugins, pluginName) - vscodeAPI.postMessage({ command: 'setEnabledPlugins', plugins: newPlugins }) - setEnabledPlugins(newPlugins) - }, - [enabledPlugins, vscodeAPI] - ) - const telemetryService = useMemo(() => createWebviewTelemetryService(vscodeAPI), [vscodeAPI]) if (!view || !authStatus || !config) { @@ -207,7 +190,6 @@ export const App: React.FunctionComponent<{ vscodeAPI: VSCodeWrapper }> = ({ vsc setInputHistory={setInputHistory} vscodeAPI={vscodeAPI} suggestions={suggestions} - pluginsDevMode={Boolean(config?.pluginsDebugEnabled)} setSuggestions={setSuggestions} telemetryService={telemetryService} chatCommands={myPrompts || undefined} @@ -217,10 +199,6 @@ export const App: React.FunctionComponent<{ vscodeAPI: VSCodeWrapper }> = ({ vsc )} )} - - {config.pluginsEnabled && view === 'plugins' && ( - - )}
) } diff --git a/vscode/webviews/Chat.tsx b/vscode/webviews/Chat.tsx index 79312cd33574..3275cd7c01e6 100644 --- a/vscode/webviews/Chat.tsx +++ b/vscode/webviews/Chat.tsx @@ -41,7 +41,6 @@ interface ChatboxProps { telemetryService: TelemetryService suggestions?: string[] setSuggestions?: (suggestions: undefined | string[]) => void - pluginsDevMode?: boolean chatCommands?: [string, CodyPrompt][] isTranscriptError: boolean showOnboardingButtons?: boolean | null @@ -61,7 +60,6 @@ export const Chat: React.FunctionComponent telemetryService, suggestions, setSuggestions, - pluginsDevMode, chatCommands, isTranscriptError, showOnboardingButtons, @@ -155,7 +153,6 @@ export const Chat: React.FunctionComponent afterMarkdown={welcomeMessageMarkdown} helpMarkdown="" ChatButtonComponent={ChatButton} - pluginsDevMode={pluginsDevMode} chatCommands={chatCommands} filterChatCommands={filterChatCommands} ChatCommandsComponent={ChatCommandsComponent} diff --git a/vscode/webviews/NavBar.tsx b/vscode/webviews/NavBar.tsx index 6d9567f04ec1..be9806c88443 100644 --- a/vscode/webviews/NavBar.tsx +++ b/vscode/webviews/NavBar.tsx @@ -1,13 +1,12 @@ -import React, { useMemo } from 'react' +import React from 'react' import styles from './NavBar.module.css' -export type View = 'chat' | 'login' | 'history' | 'plugins' +export type View = 'chat' | 'login' | 'history' interface NavBarProps { setView: (selectedView: View) => void view: View - pluginsEnabled?: boolean } interface NavBarItem { @@ -17,24 +16,14 @@ interface NavBarItem { const navBarItems: NavBarItem[] = [{ tab: 'chat', title: 'Chat' }] -export const NavBar: React.FunctionComponent> = ({ - setView, - view, - pluginsEnabled = false, -}) => { - const memoizedNavBarItems = useMemo( - (): NavBarItem[] => (pluginsEnabled ? [...navBarItems, { tab: 'plugins', title: 'Plugins' }] : navBarItems), - [pluginsEnabled] - ) - return ( -
-
- {memoizedNavBarItems.map(({ title, tab }) => ( - - ))} -
+export const NavBar: React.FunctionComponent> = ({ setView, view }) => ( +
+
+ {navBarItems.map(({ title, tab }) => ( + + ))}
- ) -} +
+) diff --git a/vscode/webviews/Plugins.module.css b/vscode/webviews/Plugins.module.css deleted file mode 100644 index da7027e05767..000000000000 --- a/vscode/webviews/Plugins.module.css +++ /dev/null @@ -1,39 +0,0 @@ -.container { - display: flex; - flex-direction: column; - height: 100%; - padding: 1rem; -} - -.list { - list-style: none; - padding: 0; - margin: 0; -} - -.list-item { - background-color: var(--vscode-tab-inactiveBackground); - padding: 0.5rem; - margin-bottom: 0.5rem; -} - -.plugin { - display: block; - cursor: pointer; -} - -.plugin-checkbox { - float: left; - margin: 0.1rem 0.25rem 0 0; -} - -.plugin-header { - font-weight: 600; - margin: 0 0 0.5rem 0; - font-size: 1rem; -} - -.plugin-description { - margin: 0; - line-height: 1.1rem; -} diff --git a/vscode/webviews/Plugins.tsx b/vscode/webviews/Plugins.tsx deleted file mode 100644 index 019870ef6de8..000000000000 --- a/vscode/webviews/Plugins.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import { defaultPlugins } from '@sourcegraph/cody-shared/src/plugins/built-in' - -import styles from './Plugins.module.css' - -interface PluginItemProps { - name: string - description: string - enabled: boolean - onToggle: (pluginName: string, enabled: boolean) => void -} - -const PluginItem: React.FC = ({ name, description, enabled, onToggle }) => ( - -) - -export const Plugins: React.FC<{ - plugins: string[] - onPluginToggle: PluginItemProps['onToggle'] -}> = ({ plugins, onPluginToggle }) => ( -
-
    - {defaultPlugins.map(plugin => ( -
  • - -
  • - ))} -
-
-)