directed all logs to chat element

pull/5241/head
STetsing 2 months ago
parent abeac7d4e6
commit 4c843e9b5f
  1. 9
      apps/circuit-compiler/src/app/components/container.tsx
  2. 43
      apps/remix-ide/src/app/plugins/remixAIPlugin.tsx
  3. 5
      apps/remix-ide/src/app/tabs/locales/en/editor.json
  4. 3
      apps/vyper/src/app/utils/remix-client.tsx
  5. 1
      libs/remix-ai-core/src/helpers/streamHandler.ts
  6. 14
      libs/remix-ai-core/src/inferencers/remote/remoteInference.ts
  7. 3
      libs/remix-ui/editor/src/lib/providers/inlineCompletionProvider.ts
  8. 13
      libs/remix-ui/editor/src/lib/remix-ui-editor.tsx
  9. 10
      libs/remix-ui/remix-ai/src/lib/components/Default.tsx
  10. 3
      libs/remix-ui/renderer/src/lib/renderer.tsx
  11. 28
      libs/remix-ui/tabs/src/lib/remix-ui-tabs.tsx
  12. 4
      libs/remix-ui/terminal/src/lib/remix-ui-terminal.tsx

@ -74,7 +74,8 @@ export function Container () {
explain why the error occurred and how to fix it.
`
// @ts-ignore
await circuitApp.plugin.call('remixAI', 'error_explaining', message)
await circuitApp.plugin.call('remixAI' as any, 'chatPipe', 'error_explaining', message)
// await circuitApp.plugin.call('remixAI', 'error_explaining', message)
} else {
const message = `
error message: ${error}
@ -82,7 +83,8 @@ export function Container () {
explain why the error occurred and how to fix it.
`
// @ts-ignore
await circuitApp.plugin.call('remixAI', 'error_explaining', message)
await circuitApp.plugin.call('remixAI' as any, 'chatPipe', 'error_explaining', message)
//await circuitApp.plugin.call('remixAI', 'error_explaining', message)
}
} else {
const error = report.message
@ -92,7 +94,8 @@ export function Container () {
explain why the error occurred and how to fix it.
`
// @ts-ignore
await circuitApp.plugin.call('remixAI', 'error_explaining', message)
//await circuitApp.plugin.call('remixAI', 'error_explaining', message)
await circuitApp.plugin.call('remixAI' as any, 'chatPipe', 'error_explaining', message)
}
}

@ -73,7 +73,6 @@ export class RemixAIPlugin extends ViewPlugin {
}
} else {
// on browser
this.remoteInferencer = new RemoteInferencer(remoteModel?.apiUrl, remoteModel?.completionUrl)
this.remoteInferencer.event.on('onInference', () => {
this.isInferencing = true
@ -114,8 +113,6 @@ export class RemixAIPlugin extends ViewPlugin {
return
}
this.call('terminal', 'log', { type: 'aitypewriterwarning', value: `\n\nWaiting for RemixAI answer...` })
let result
if (this.isOnDesktop) {
result = await this.call(this.remixDesktopPluginName, 'solidity_answer', prompt)
@ -123,7 +120,6 @@ export class RemixAIPlugin extends ViewPlugin {
result = await this.remoteInferencer.solidity_answer(prompt)
}
if (result && params.terminal_output) this.call('terminal', 'log', { type: 'aitypewriterwarning', value: result })
// this.call('terminal', 'log', { type: 'aitypewriterwarning', value: "RemixAI Done" })
return result
}
@ -132,8 +128,6 @@ export class RemixAIPlugin extends ViewPlugin {
this.call('terminal', 'log', { type: 'aitypewriterwarning', value: "RemixAI is already busy!" })
return
}
this.call('terminal', 'log', { type: 'aitypewriterwarning', value: `\n\nWaiting for RemixAI answer...` })
let result
if (this.isOnDesktop) {
@ -143,33 +137,22 @@ export class RemixAIPlugin extends ViewPlugin {
result = await this.remoteInferencer.code_explaining(prompt, context, params)
}
if (result && params.terminal_output) this.call('terminal', 'log', { type: 'aitypewriterwarning', value: result })
// this.call('terminal', 'log', { type: 'aitypewriterwarning', value: "RemixAI Done" })
// HandleStreamResponse(result, (text) => {
// this.call('terminal', 'log', { type: 'aitypewriterwarning', value: text })
// })
return result
}
async error_explaining(prompt: string): Promise<any> {
async error_explaining(prompt: string, context: string="", params: IParams=GenerationParams): Promise<any> {
if (this.isInferencing) {
this.call('terminal', 'log', { type: 'aitypewriterwarning', value: "RemixAI is already busy!" })
return
}
const params:IParams = GenerationParams
params.stream_result = true
this.call('terminal', 'log', { type: 'aitypewriterwarning', value: `\n\nWaiting for RemixAI answer...` })
let result
if (this.isOnDesktop) {
result = await this.call(this.remixDesktopPluginName, 'error_explaining', prompt)
} else {
result = await this.remoteInferencer.error_explaining(prompt, params)
}
if (result) this.call('terminal', 'log', { type: 'aitypewriterwarning', value: result })
// this.call('terminal', 'log', { type: 'aitypewriterwarning', value: "RemixAI Done" })
if (result && params.terminal_output) this.call('terminal', 'log', { type: 'aitypewriterwarning', value: result })
return result
}
@ -181,20 +164,20 @@ export class RemixAIPlugin extends ViewPlugin {
}
}
chatPipe(fn, prompt: string, context?: string, params: IParams=GenerationParams){
chatPipe(fn, prompt: string, context?: string, pipeMessage?: string){
if (this.chatRequestBuffer == null){
this.chatRequestBuffer = {
fn_name: fn,
prompt: prompt,
params: params,
context: context
}
if (fn === "code_explaining"){
ChatApi.composer.send("Explain the current code")
}
else if (fn === "solidity_answer"){
ChatApi.composer.send("Answer the following question")
console.log('pipe message', pipeMessage)
if (pipeMessage) ChatApi.composer.send(pipeMessage)
else {
if (fn === "code_explaining") ChatApi.composer.send("Explain the current code")
else if (fn === "error_explaining") ChatApi.composer.send("Explain the error")
else if (fn === "solidity_answer") ChatApi.composer.send("Answer the following question")
else console.log("chatRequestBuffer is not empty. First process the last request.")
}
}
else{
@ -202,7 +185,8 @@ export class RemixAIPlugin extends ViewPlugin {
}
}
ProcessChatRequestBuffer(params:IParams=GenerationParams){
async ProcessChatRequestBuffer(params:IParams=GenerationParams){
if (this.chatRequestBuffer != null){
const result = this[this.chatRequestBuffer.fn_name](this.chatRequestBuffer.prompt, this.chatRequestBuffer.context, params)
this.chatRequestBuffer = null
@ -210,14 +194,13 @@ export class RemixAIPlugin extends ViewPlugin {
}
else{
console.log("chatRequestBuffer is empty.")
return ""
}
}
isChatRequestPending(){
return this.chatRequestBuffer != null
}
render() {
return (
<RemixAITab plugin={this}></RemixAITab>

@ -25,8 +25,9 @@
"editor.explainFunction": "Explain this function",
"editor.explainFunctionSol": "Explain this code",
"editor.explainFunction2": "Explain the function \"{name}\"",
"editor.explainFunctionByAI": "solidity code: {content}\n Explain the function {currentFunction}",
"editor.explainFunctionByAISol": "solidity code: {content}\n Explain the function {currentFunction}",
"editor.explainFunctionByAI": "```\n{content}\n```\nExplain the function {currentFunction}",
"editor.explainFunctionByAISol": "```\n{content}\n```\nExplain the function {currentFunction}",
"editor.ExplainPipeMessage": "```\n {content}\n```\nExplain the snipped above",
"editor.executeFreeFunction": "Run a free function",
"editor.executeFreeFunction2": "Run the free function \"{name}\"",
"editor.toastText1": "This can only execute free function",

@ -72,7 +72,8 @@ export class RemixClient extends PluginClient<any, CustomRemixApi> {
${message}
can you explain why this error occurred and how to fix it?
`
await this.client.call('remixAI' as any, 'error_explaining', message)
// await this.client.call('remixAI' as any, 'error_explaining', message)
await this.client.call('remixAI' as any, 'chatPipe', 'error_explaining', message)
} catch (err) {
console.error('unable to askGpt')
console.error(err)

@ -22,7 +22,6 @@ export const HandleStreamResponse = async (streamResponse,
cb?: (streamText: string) => void,
done_cb?: (result: string) => void) => {
try {
console.log("streamResponse handler", streamResponse)
let resultText = ''
const parser = new JsonStreamParser();
const reader = streamResponse.body!.getReader();

@ -26,11 +26,11 @@ export class RemoteInferencer implements ICompletions {
private async _makeRequest(endpoint, payload, rType:AIRequestType){
this.event.emit("onInference")
const requesURL = rType === AIRequestType.COMPLETION ? this.completion_url : this.api_url
const requestURL = rType === AIRequestType.COMPLETION ? this.completion_url : this.api_url
try {
const options = { headers: { 'Content-Type': 'application/json', } }
const result = await axios.post(`${requesURL}/${endpoint}`, payload, options)
const result = await axios.post(`${requestURL}/${endpoint}`, payload, options)
switch (rType) {
case AIRequestType.COMPLETION:
@ -76,7 +76,6 @@ export class RemoteInferencer implements ICompletions {
return response
}
const reader = response.body!.getReader();
const decoder = new TextDecoder();
const parser = new JsonStreamParser();
@ -117,19 +116,15 @@ export class RemoteInferencer implements ICompletions {
}
async code_completion(prompt, options:IParams=CompletionParams): Promise<any> {
const payload = { prompt, "endpoint":"code_completion", ...options }
if (options.stream_result) return this._streamInferenceRequest(payload.endpoint, payload, AIRequestType.COMPLETION)
else return this._makeRequest(payload.endpoint, payload, AIRequestType.COMPLETION)
return this._makeRequest(payload.endpoint, payload, AIRequestType.COMPLETION)
}
async code_insertion(msg_pfx, msg_sfx, options:IParams=InsertionParams): Promise<any> {
// const payload = { "data":[msg_pfx, "code_insertion", msg_sfx, 1024, 0.5, 0.92, 50]}
const payload = {"endpoint":"code_insertion", msg_pfx, msg_sfx, ...options, prompt: '' }
if (options.stream_result) return this._streamInferenceRequest(payload.endpoint, payload, AIRequestType.COMPLETION)
else return this._makeRequest(payload.endpoint, payload, AIRequestType.COMPLETION)
return this._makeRequest(payload.endpoint, payload, AIRequestType.COMPLETION)
}
async code_generation(prompt, options:IParams=GenerationParams): Promise<any> {
@ -156,6 +151,7 @@ export class RemoteInferencer implements ICompletions {
async error_explaining(prompt, options:IParams=GenerationParams): Promise<any> {
const payload = { prompt, "endpoint":"error_explaining", ...options }
console.log("payload: ", payload)
if (options.stream_result) return this._streamInferenceRequest(payload.endpoint, payload , AIRequestType.GENERAL)
else return this._makeRequest(payload.endpoint, payload, AIRequestType.GENERAL)
}

@ -1,5 +1,6 @@
/* eslint-disable no-control-regex */
import { EditorUIProps, monacoTypes } from '@remix-ui/editor';
import { JsonStreamParser } from '@remix/remix-ai-core';
const _paq = (window._paq = window._paq || [])
export class RemixInLineCompletionProvider implements monacoTypes.languages.InlineCompletionsProvider {
@ -81,6 +82,7 @@ export class RemixInLineCompletionProvider implements monacoTypes.languages.Inli
const data = await this.props.plugin.call('remixAI', 'code_insertion', word, word_after)
this.task = 'code_generation'
console.log("data: " + this.task, data)
const parsedData = data.trimStart() //JSON.parse(data).trimStart()
const item: monacoTypes.languages.InlineCompletion = {
@ -131,6 +133,7 @@ export class RemixInLineCompletionProvider implements monacoTypes.languages.Inli
}
}
catch (err){
console.log("err: " + err)
return
}
}

@ -776,6 +776,8 @@ export const EditorUI = (props: EditorUIProps) => {
const file = await props.plugin.call('fileManager', 'getCurrentFile')
const content = await props.plugin.call('fileManager', 'readFile', file)
const message = intl.formatMessage({ id: 'editor.generateDocumentationByAI' }, { content, currentFunction: currentFunction.current })
// do not stream this response
const cm = await await props.plugin.call('remixAI', 'code_explaining', message)
const natSpecCom = "\n" + extractNatspecComments(cm)
@ -827,9 +829,10 @@ export const EditorUI = (props: EditorUIProps) => {
],
run: async () => {
const file = await props.plugin.call('fileManager', 'getCurrentFile')
const content = await props.plugin.call('fileManager', 'readFile', file)
const message = intl.formatMessage({ id: 'editor.explainFunctionByAI' }, { content, currentFunction: currentFunction.current })
await props.plugin.call('remixAI', 'code_explaining', message, content)
const context = await props.plugin.call('fileManager', 'readFile', file)
const message = intl.formatMessage({ id: 'editor.explainFunctionByAI' }, { content:context, currentFunction: currentFunction.current })
// await props.plugin.call('remixAI', 'code_explaining', message, context)
await props.plugin.call('remixAI' as any, 'chatPipe', 'code_explaining', message, context)
_paq.push(['trackEvent', 'ai', 'remixAI', 'explainFunction'])
},
}
@ -848,8 +851,10 @@ export const EditorUI = (props: EditorUIProps) => {
const file = await props.plugin.call('fileManager', 'getCurrentFile')
const content = await props.plugin.call('fileManager', 'readFile', file)
const selectedCode = editor.getModel().getValueInRange(editor.getSelection())
const pipeMessage = intl.formatMessage({ id: 'editor.ExplainPipeMessage' }, { content:selectedCode })
await props.plugin.call('remixAI', 'code_explaining', selectedCode, content)
await props.plugin.call('remixAI' as any, 'chatPipe', 'code_explaining', selectedCode, content, pipeMessage)
// await props.plugin.call('remixAI', 'code_explaining', selectedCode, content)
_paq.push(['trackEvent', 'ai', 'remixAI', 'explainFunction'])
},
}

@ -1,7 +1,7 @@
import React, { useContext, useEffect, useState, useCallback} from 'react'
import '../remix-ai.css'
import { DefaultModels, GenerationParams, ChatHistory, HandleStreamResponse, HandleSimpleResponse } from '@remix/remix-ai-core';
import { StreamSend, StreamingAdapterObserver, useAiChatApi } from '@nlux/react';
import { ConversationStarter, StreamSend, StreamingAdapterObserver, useAiChatApi } from '@nlux/react';
import axios from 'axios';
import { AiChat, useAsStreamAdapter, ChatItem, AiChatUI} from '@nlux/react';
import '@nlux/themes/nova.css';
@ -29,7 +29,6 @@ export const Default = (props) => {
response = await props.plugin.call('remixAI', 'solidity_answer', prompt, GenerationParams);
}
if (GenerationParams.return_stream_response) HandleStreamResponse(response,
(text) => {observer.next(text)},
(result) => {
@ -44,6 +43,9 @@ export const Default = (props) => {
};
ChatApi = useAiChatApi();
const conversationStarters: ConversationStarter[] = [
{prompt: 'Explain what is a solidity contract!', icon: <span></span>},
{prompt: 'Explain the current file in Editor'}]
// Define initial messages
const initialMessages: ChatItem[] = [
@ -68,8 +70,8 @@ export const Default = (props) => {
}}
//initialConversation={initialMessages}
conversationOptions={{ layout: 'bubbles' }}
displayOptions={{ colorScheme: "auto" }}
conversationOptions={{ layout: 'bubbles', conversationStarters }}
displayOptions={{ colorScheme: "auto", themeId: "nova" }}
composerOptions={{ placeholder: "Type your query",
submitShortcut: 'Enter',
hideStopButton: false,

@ -75,7 +75,8 @@ export const Renderer = ({ message, opt = {}, plugin }: RendererProps) => {
try {
const content = await plugin.call('fileManager', 'readFile', editorOptions.errFile)
const message = intl.formatMessage({ id: 'solidity.openaigptMessage' }, { content, messageText })
await plugin.call('remixAI', 'error_explaining', message)
// await plugin.call('remixAI', 'error_explaining', message)
await plugin.call('remixAI' as any, 'chatPipe', 'error_explaining', message)
_paq.push(['trackEvent', 'ai', 'remixAI', 'error_explaining_SolidityError'])
} catch (err) {
console.error('unable to askGtp')

@ -250,7 +250,35 @@ export const TabsUI = (props: TabsUIProps) => {
const content = await props.plugin.call('fileManager', 'readFile', path)
if (tabsState.currentExt === 'sol') {
setExplaining(true)
// if plugin is pinned,
if (await props.plugin.call('pinnedPanel', 'currentFocus') === 'remixAI'){
console.log("pinned has focus")
await props.plugin.call('remixAI', 'chatPipe', 'code_explaining', content)
}
else{
const profile = {
name: 'remixAI',
displayName: 'Remix AI',
methods: ['code_generation', 'code_completion',
"solidity_answer", "code_explaining",
"code_insertion", "error_explaining",
"initialize", 'chatPipe', 'ProcessChatRequestBuffer', 'isChatRequestPending'],
events: [],
icon: 'assets/img/remix-logo-blue.png',
description: 'RemixAI provides AI services to Remix IDE.',
kind: '',
location: 'sidePanel',
documentation: 'https://remix-ide.readthedocs.io/en/latest/remixai.html',
maintainedBy: 'Remix'
}
console.log("pinned does not have focus")
// await props.plugin.call('sidePanel', 'focus', 'remixAI')
await props.plugin.call('sidePanel', 'pinView', profile)
setTimeout(async () => {
await props.plugin.call('remixAI', 'chatPipe', 'code_explaining', content)
}, 500)
}
// await props.plugin.call('remixAI', 'code_explaining', content)
setExplaining(false)
_paq.push(['trackEvent', 'ai', 'remixAI', 'explain_file'])

@ -238,11 +238,11 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
// TODO: rm gpt or redirect gpt to sol-pgt
} else if (script.trim().startsWith('gpt')) {
call('terminal', 'log',{ type: 'warn', value: `> ${script}` })
await call('remixAI', 'solidity_answer', script)
await call('remixAI', 'solidity_answer', script) // No streaming supported in terminal
_paq.push(['trackEvent', 'ai', 'remixAI', 'askFromTerminal'])
} else if (script.trim().startsWith('sol-gpt')) {
call('terminal', 'log',{ type: 'warn', value: `> ${script}` })
await call('remixAI', 'solidity_answer', script)
await call('remixAI', 'solidity_answer', script) // No streaming supported in terminal
_paq.push(['trackEvent', 'ai', 'remixAI', 'askFromTerminal'])
} else {
await call('scriptRunner', 'execute', script)

Loading…
Cancel
Save