diff --git a/apps/remix-ide/src/app/plugins/copilot/suggestion-service/copilot-suggestion.ts b/apps/remix-ide/src/app/plugins/copilot/suggestion-service/copilot-suggestion.ts index e094677026..61616ea4ce 100644 --- a/apps/remix-ide/src/app/plugins/copilot/suggestion-service/copilot-suggestion.ts +++ b/apps/remix-ide/src/app/plugins/copilot/suggestion-service/copilot-suggestion.ts @@ -17,7 +17,7 @@ export class CopilotSuggestion extends Plugin { service: SuggestionService remoteService: string context: string - ready: boolean + ready: boolean=false constructor() { super(profile) this.context = '' @@ -31,6 +31,7 @@ export class CopilotSuggestion extends Plugin { this.service.events.on('done', (data) => { }) this.service.events.on('ready', (data) => { + this.emit('ready', data) this.ready = true }) } diff --git a/apps/remix-ide/src/app/plugins/copilot/suggestion-service/worker.js b/apps/remix-ide/src/app/plugins/copilot/suggestion-service/worker.js index 04b77ba634..0623b3712f 100644 --- a/apps/remix-ide/src/app/plugins/copilot/suggestion-service/worker.js +++ b/apps/remix-ide/src/app/plugins/copilot/suggestion-service/worker.js @@ -22,7 +22,6 @@ class CodeCompletionPipeline { // Listen for messages from the main thread self.addEventListener('message', async (event) => { - console.log("worker message ", event.data) const { id, model, text, max_new_tokens, cmd, diff --git a/apps/remix-ide/src/app/plugins/solcoderAI.tsx b/apps/remix-ide/src/app/plugins/solcoderAI.tsx index aa99c74f3a..e443fa6c05 100644 --- a/apps/remix-ide/src/app/plugins/solcoderAI.tsx +++ b/apps/remix-ide/src/app/plugins/solcoderAI.tsx @@ -35,7 +35,7 @@ export class SolCoder extends Plugin { body: JSON.stringify({"data":[prompt, "code_generation", false,1000,0.2,0.8,50]}), }) ).json() - return result.data[0] + return "error" in result? result.error : result.data[0] } catch (e) { this.call('terminal', 'log', { type: 'typewritererror', value: `Unable to get a response ${e.message}` }) return @@ -135,7 +135,11 @@ export class SolCoder extends Plugin { }) ).json() - return result.data + if ("error" in result){ + this.call('terminal', 'log', { type: 'typewriterwarning', value: result.error }) + return result + } + } catch (e) { this.call('terminal', 'log', { type: 'typewritererror', value: `Unable to get a response ${e.message}` }) return diff --git a/apps/remix-ide/src/app/tabs/settings-tab.tsx b/apps/remix-ide/src/app/tabs/settings-tab.tsx index 7954bf5d36..a09c661e50 100644 --- a/apps/remix-ide/src/app/tabs/settings-tab.tsx +++ b/apps/remix-ide/src/app/tabs/settings-tab.tsx @@ -61,9 +61,8 @@ module.exports = class SettingsTab extends ViewPlugin { } onActivation(): void { - this.on('copilot-suggestion', 'loading', (data) => { - this.call('terminal', 'log', { type: 'typewritererror', value: `.` }) - console.log("oninit") + this.once('copilot-suggestion', 'loading', (data) => { + this.call('terminal', 'log', {type: 'typewriterlog', value: `loading Solidity copilot ...` }) }) } render() { diff --git a/libs/remix-ui/editor/src/lib/providers/inlineCompletionProvider.ts b/libs/remix-ui/editor/src/lib/providers/inlineCompletionProvider.ts index 9944f29ec4..e5e7e22649 100644 --- a/libs/remix-ui/editor/src/lib/providers/inlineCompletionProvider.ts +++ b/libs/remix-ui/editor/src/lib/providers/inlineCompletionProvider.ts @@ -11,11 +11,9 @@ const result: string = '' export class RemixInLineCompletionProvider implements monacoTypes.languages.InlineCompletionsProvider { props: EditorUIProps monaco: any - running:boolean constructor(props: any, monaco: any) { this.props = props this.monaco = monaco - this.running = false } async provideInlineCompletions(model: monacoTypes.editor.ITextModel, position: monacoTypes.Position, context: monacoTypes.languages.InlineCompletionContext, token: monacoTypes.CancellationToken): Promise> { @@ -49,29 +47,31 @@ export class RemixInLineCompletionProvider implements monacoTypes.languages.Inli const split = word.split('\n') if (split.length < 2) return const ask = split[split.length - 2].trimStart() - if (split[split.length - 1].trim() === '' && ask.startsWith('///') && (!this.running)) { + if (split[split.length - 1].trim() === '' && ask.startsWith('///')) { // use the code generation model, only take max 1000 word as context - this.running = true + this.props.plugin.call('terminal', 'log', {type: 'typewriterwarning', value: 'Solcoder - generating code for following comment: ' + ask.replace('///', '')}) + const data = await this.props.plugin.call('solcoder', 'code_completion', word) - console.log("solcoder completion data", data) + if ("error" in data) return + const parsedData = data[0].trimStart() //JSON.parse(data).trimStart() const item: monacoTypes.languages.InlineCompletion = { insertText: parsedData }; - this.running =false return { items: [item], enableForwardStability: true } } } catch (e) { - console.error(e) + return } if (word.split('\n').at(-1).trimStart().startsWith('//') || word.split('\n').at(-1).trimStart().startsWith('/*') || word.split('\n').at(-1).trimStart().startsWith('*') || - word.split('\n').at(-1).trimStart().startsWith('*/') + word.split('\n').at(-1).trimStart().startsWith('*/') || + word.split('\n').at(-1).endsWith(';') ){ return; // do not do completion on single and multiline comment } @@ -84,38 +84,31 @@ export class RemixInLineCompletionProvider implements monacoTypes.languages.Inli let result try { - if (!this.running){ - result = await this.props.plugin.call('copilot-suggestion', 'suggest', word) - this.running = true + console.log('processing completion', word) + result = await this.props.plugin.call('copilot-suggestion', 'suggest', word) + const generatedText = (result as any).output[0].generated_text as string + let clean = generatedText + + if (generatedText.indexOf('@custom:dev-run-script./') !== -1) { + clean = generatedText.replace('@custom:dev-run-script', '@custom:dev-run-script ') + } + clean = clean.replace(word, '').trimStart() + console.log('completion', clean, clean.split('\n')[0]) + clean = clean.split('\n')[0].startsWith('\n') ? [clean.split('\n')[0], clean.split('\n')[1]].join('\n'): clean.split('\n')[0] + console.log('completion after ', clean) + + const item: monacoTypes.languages.InlineCompletion = { + insertText: clean + }; + return { + items: [item], + enableForwardStability: true } } catch (err) { - this.running=false - return - } - - const generatedText = (result as any).output[0].generated_text as string - let clean = generatedText - console.log('solcoder inline data:\n', clean) - if (generatedText.indexOf('@custom:dev-run-script./') !== -1) { - clean = generatedText.replace('@custom:dev-run-script', '@custom:dev-run-script ') - } - clean = clean.replace(word, '') - - const item: monacoTypes.languages.InlineCompletion = { - insertText: clean - }; - this.running=false - - // abort if there is a signal - if (token.isCancellationRequested) { return } - return { - items: [item], - enableForwardStability: true - } - } + handleItemDidShow?(completions: monacoTypes.languages.InlineCompletions, item: monacoTypes.languages.InlineCompletion, updatedInsertText: string): void { } diff --git a/libs/remix-ui/settings/src/lib/remix-ui-settings.tsx b/libs/remix-ui/settings/src/lib/remix-ui-settings.tsx index aeaa5f8b22..f9b903669d 100644 --- a/libs/remix-ui/settings/src/lib/remix-ui-settings.tsx +++ b/libs/remix-ui/settings/src/lib/remix-ui-settings.tsx @@ -4,12 +4,6 @@ import React, {useState, useRef, useReducer, useEffect, useCallback} from 'react import {AppModal, AlertModal, ModalTypes} from '@remix-ui/app' import {labels, textDark, textSecondary} from './constants' -enum CONSENT { - GIVEN = 0, - NOT_GIVEN, - NOT_ASKED -} - import './remix-ui-settings.css' import { generateContractMetadat, @@ -62,7 +56,6 @@ export const RemixUiSettings = (props: RemixUiSettingsProps) => { const [ipfsProjectSecret, setipfsProjectSecret] = useState('') const copilotDownload = useRef(null) - let consentGivenForAI = CONSENT.NOT_ASKED const intl = useIntl() const initValue = () => { const metadataConfig = props.config.get('settings/generate-contract-metadata') @@ -129,15 +122,6 @@ export const RemixUiSettings = (props: RemixUiSettingsProps) => { if (props.useMatomoAnalytics !== null) useMatomoAnalytics(props.config, props.useMatomoAnalytics, dispatch) }, [props.useMatomoAnalytics]) - useEffect(() => { - console.log("useEffect on useCopilot") - if (props.useCopilot !== null) copilotActivate(props.config, props.useCopilot, dispatch) - if (props.useCopilot) { - onchangeCopilotActivate() - } - console.log("useEffect on useCopilot finish") - }, [props.useCopilot]) - const onchangeGenerateContractMetadata = (event) => { generateContractMetadat(props.config, event.target.checked, dispatch) } @@ -151,66 +135,34 @@ export const RemixUiSettings = (props: RemixUiSettingsProps) => { if (!props.useCopilot) { copilotActivate(props.config, props.useCopilot, dispatch) props.plugin.call('copilot-suggestion', 'uninstall') + props.plugin.call('terminal', 'log', {type: 'typewriterlog', value: `Solidity copilot deactivated` }) return } - const message =
Please wait while the copilot is downloaded. 0/100 .
- props.plugin.on('copilot-suggestion', 'loading', (data) => { - if (!copilotDownload.current) return - const loaded = ((data.loaded / data.total) * 100).toString() - const dot = loaded.match(/(.*)\./g) - copilotDownload.current.innerText = dot ? dot[0].replace('.', '') : loaded + props.plugin.on('copilot-suggestion', 'ready', (data) => { + props.plugin.call('terminal', 'log', {type: 'typewriterlog', value: `loading Solidity copilot: 100% done.` }) }) + const startCopilot = async () => { await props.plugin.call('copilot-suggestion', 'init') - props.plugin.off('copilot-suggestion', 'loading') if (await props.plugin.call('copilot-suggestion', 'status')) { copilotActivate(props.config, true, dispatch) - } else { - props.plugin.call('copilot-suggestion', 'uninstall') - copilotActivate(props.config, false, dispatch) - } - } - const modalActivate: AppModal = { - id: 'loadcopilotActivate', - title: 'Download Solidity copilot', - modalType: ModalTypes.default, - okLabel: 'Hide', - cancelLabel: 'Cancel', - message, - okFn: async() => { - consentGivenForAI = CONSENT.GIVEN - startCopilot() - }, - hideFn: async () => { - consentGivenForAI = CONSENT.NOT_GIVEN - props.plugin.off('copilot-suggestion', 'loading') - // if (await props.plugin.call('copilot-suggestion', 'status')) { - // copilotActivate(props.config, true, dispatch) - // } else { - // props.plugin.call('copilot-suggestion', 'uninstall') - // copilotActivate(props.config, false, dispatch) - // } } } - if (consentGivenForAI === CONSENT.NOT_ASKED) { - console.log("CONSENT.NOT_ASKED modal") - props.plugin.call('notification', 'modal', modalActivate) - } else if (consentGivenForAI === CONSENT.GIVEN) { - startCopilot() - } else { - // NOT_GIVEN - } - + startCopilot() if (props.plugin.call('copilot-suggestion', 'status')) { copilotActivate(props.config, true, dispatch) - } else { - props.plugin.call('copilot-suggestion', 'uninstall') - copilotActivate(props.config, false, dispatch) + }else { + startCopilot() } } + useEffect(() => { + if (props.useCopilot !== null) copilotActivate(props.config, props.useCopilot, dispatch) + onchangeCopilotActivate() + }, [props.useCopilot]) + const onchangeCopilotMaxNewToken = (event) => { copilotMaxNewToken(props.config, parseInt(event.target.value), dispatch) } @@ -477,13 +429,13 @@ export const RemixUiSettings = (props: RemixUiSettingsProps) => { const isCopilotActivated = props.config.get('settings/copilot/suggest/activate') || false let copilotMaxnewToken = props.config.get('settings/copilot/suggest/max_new_tokens') if (!copilotMaxnewToken) { - props.config.set('settings/copilot/suggest/max_new_tokens', 5) - copilotMaxnewToken = 5 + props.config.set('settings/copilot/suggest/max_new_tokens', 10) + copilotMaxnewToken = 10 } let copilotTemperatureValue = (props.config.get('settings/copilot/suggest/temperature')) * 100 if (!copilotTemperatureValue) { - props.config.set('settings/copilot/suggest/temperature', 0.5) - copilotTemperatureValue = 0.5 + props.config.set('settings/copilot/suggest/temperature', 0.9) + copilotTemperatureValue = 0.9 } //if (isCopilotActivated) props.plugin.call('copilot-suggestion', 'init')