Skip to content

Remix AI Assistant Plugin #5966

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion apps/remix-ide/src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { AstWalker } from '@remix-project/remix-astwalker'
import { LinkLibraries, DeployLibraries, OpenZeppelinProxy } from '@remix-project/core-plugin'
import { CodeParser } from './app/plugins/parser/code-parser'
import { SolidityScript } from './app/plugins/solidity-script'
import { RemixAIAssistant } from './app/plugins/remix-ai-assistant'

import { WalkthroughService } from './walkthroughService'

Expand Down Expand Up @@ -314,6 +315,7 @@ class AppComponent {

// ----------------- AI --------------------------------------
const remixAI = new RemixAIPlugin(isElectron())
const remixAiAssistant = new RemixAIAssistant()

// ----------------- import content service ------------------------
const contentImport = new CompilerImports()
Expand Down Expand Up @@ -444,6 +446,7 @@ class AppComponent {
templateSelection,
scriptRunnerUI,
remixAI,
remixAiAssistant,
walletConnect
])

Expand Down Expand Up @@ -601,7 +604,8 @@ class AppComponent {
'contentImport',
'gistHandler',
'compilerloader',
'remixAI'
'remixAI',
'remixaiassistant'
])
await this.appManager.activatePlugin(['settings'])

Expand Down
5 changes: 4 additions & 1 deletion apps/remix-ide/src/app/components/side-panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ export class SidePanel extends AbstractPanel {
}

async pinView (profile) {
await this.call('pinnedPanel', 'pinView', profile, this.plugins[profile.name].view)
await this.call('pinnedPanel', 'pinView', profile, this.plugins[profile.name]?.view)
if (this.plugins[profile.name].active) this.call('menuicons', 'select', 'filePanel')
super.remove(profile.name)
this.renderComponent()
Expand All @@ -93,6 +93,9 @@ export class SidePanel extends AbstractPanel {
*/
async showContent(name) {
super.showContent(name)
if (name === 'remixaiassistant') { // TODO: should this be a plugin feature?
this.pinView(this.plugins['remixaiassistant'].profile)
}
this.emit('focusChanged', name)
this.renderComponent()
}
Expand Down
2 changes: 1 addition & 1 deletion apps/remix-ide/src/app/components/vertical-icons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export class VerticalIcons extends Plugin {
}

renderComponent() {
const fixedOrder = ['filePanel', 'search', 'solidity', 'udapp', 'debugger', 'solidityStaticAnalysis', 'solidityUnitTesting', 'pluginManager']
const fixedOrder = ['remixaiassistant', 'filePanel', 'search', 'solidity', 'udapp', 'debugger', 'solidityStaticAnalysis', 'solidityUnitTesting', 'pluginManager']

const divived = Object.values(this.icons)
.map((value) => {
Expand Down
69 changes: 69 additions & 0 deletions apps/remix-ide/src/app/plugins/remix-ai-assistant.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import React from 'react'
import { ViewPlugin } from '@remixproject/engine-web'
import * as packageJson from '../../../../../package.json'
import { PluginViewWrapper } from '@remix-ui/helper'
import { RemixUiRemixAiAssistant } from '@remix-ui/remix-ai-assistant'

const profile = {
name: 'remixaiassistant',
displayName: 'Remix AI Assistant',
icon: 'assets/img/aiLogoHead.webp',
description: 'AI code assistant for Remix IDE',
kind: 'remixaiassistant',
location: 'sidePanel',
documentation: 'https://remix-ide.readthedocs.io/en/latest/run.html',
version: packageJson.version,
maintainedBy: 'Remix',
permission: true,
events: [],
methods: []
}

export class RemixAIAssistant extends ViewPlugin {
element: HTMLDivElement
dispatch: React.Dispatch<any> = () => {}
constructor() {
super(profile)
this.element = document.createElement('div')
this.element.setAttribute('id', 'remix-ai-assistant')
}

onActivation() {

}

onDeactivation() {

}

async makePluginCall(pluginName: string, methodName: string, payload: any) {
const result = await this.call(pluginName, methodName, payload)
return result
}

setDispatch(dispatch: React.Dispatch<any>) {
this.dispatch = dispatch
this.renderComponent()
}

renderComponent() {
this.dispatch({
...this
})
}

render() {
return (
<div id="remix-ai-assistant">
<PluginViewWrapper plugin={this} />
</div>
)
}

updateComponent(state: any) {
return (
<RemixUiRemixAiAssistant plugin={this} makePluginCall={this.makePluginCall} />
)
}

}
6 changes: 4 additions & 2 deletions apps/remix-ide/src/remixAppManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,8 @@ let requiredModules = [
'walletconnect',
'popupPanel',
'remixAI',
'remixAID'
'remixAID',
'remixaiassistant'
]

// dependentModules shouldn't be manually activated (e.g hardhat is activated by remixd)
Expand Down Expand Up @@ -153,7 +154,8 @@ export function isNative(name) {
'contract-verification',
'popupPanel',
'LearnEth',
'noir-compiler'
'noir-compiler',
'remixaiassistant'
]
return nativePlugins.includes(name) || requiredModules.includes(name) || isInjectedProvider(name) || isVM(name) || isScriptRunner(name)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import React from 'react'

export default function DefaultResponseContent() {
return (
<>
<h5 className="ai-assistant-text-heading">RemixAI</h5>
<p className="ai-assistant-text">RemixAI provides you personalized guidance as you build. It can break down concepts, answer questions about blockchain technology and assist you with your smart contracts.</p>
<div className="mb-3 w-100">
<button className="btn btn-secondary btn-block">
<div className="d-flex flex-row justify-content-start align-items-center">
<span className="fas fa-user-robot-xmarks"></span>
<span className="ml-2">Ask to explain a contract</span>
</div>
</button>
<button className="btn btn-secondary btn-block">
<div className="d-flex flex-row justify-content-start align-items-center">
<span className="fas fa-user-robot-xmarks"></span>
<span className="ml-2">Ask to explain a function</span>
</div>
</button>
<button className="btn btn-secondary btn-block">
<div className="d-flex flex-row justify-content-start align-items-center">
<span className="fas fa-user-robot-xmarks"></span>
<span className="ml-2">Ask to solve an error</span>
</div>
</button>
</div>
<p>
<a href="#" className="text-primary ai-assistant-text">Discover all functionalities</a>
</p>
</>
)
}
14 changes: 14 additions & 0 deletions libs/remix-ui/remix-ai-assistant/src/components/Responsezone.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import React from 'react'
import DefaultResponseContent from './DefaultResponseContent'

export default function ResponseZone({ response, responseId }: { response: string[], responseId: string }) {
return (
<section className="flex-wrap">
{response.map((item, index) => (
<span key={`${responseId}-${index}`}>
{item}
</span>
))}
</section>
)
}
21 changes: 21 additions & 0 deletions libs/remix-ui/remix-ai-assistant/src/components/promptzone.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import React from 'react'

export default function PromptZone() {
return (
<section className="w-100 mt-auto ai-assistant-bottom-height d-flex flex-column align-items-end">
<div className="bg-light d-flex flex-column w-100 p-3">
<div className="mb-3">
<button className="btn bg-dark btn-sm text-secondary">{"@ Add context"}</button>
</div>
<div className="mb-3">
<input type="text" className="form-control bg-light" placeholder="Ask me anything, use @ to mention a file" />
</div>
<div id="context-holder" className="d-flex flex-row text-white justify-content-start align-items-center flex-wrap text-success">
<span className="bg-info p-1 rounded">file1.sol <i className="fas fa-times"></i></span>
<span className="bg-info p-1 rounded ml-2">file2.sol <i className="fas fa-times"></i></span>
<span className="bg-info p-1 rounded ml-2">file3.sol <i className="fas fa-times"></i></span>
</div>
</div>
</section>
)
}
Loading