initial impl

workspace_completion
STetsing 2 weeks ago
parent 214768a3e6
commit fab2076eb3
  1. 5
      apps/remix-ide/src/app/plugins/remixAIPlugin.tsx
  2. 1
      apps/vyper/src/app/utils/remix-client.tsx
  3. 85
      libs/remix-ai-core/src/agents/completionAgent.ts
  4. 3
      libs/remix-ai-core/src/index.ts
  5. 22
      libs/remix-ui/remix-ai/src/lib/components/dynamicButtons.tsx
  6. 2
      package.json
  7. 10
      yarn.lock

@ -6,6 +6,7 @@ import React, { useCallback } from 'react';
import { ICompletions, IModel, RemoteInferencer, IRemoteModel, IParams, GenerationParams, CodeExplainAgent } from '@remix/remix-ai-core';
import { CustomRemixApi } from '@remix-api'
import { PluginViewWrapper } from '@remix-ui/helper'
import { CodeCompletionAgent } from '@remix/remix-ai-core';
const _paq = (window._paq = window._paq || [])
type chatRequestBufferT<T> = {
@ -41,6 +42,7 @@ export class RemixAIPlugin extends ViewPlugin {
agent: CodeExplainAgent
useRemoteInferencer:boolean = false
dispatch: any
completionAgent: CodeCompletionAgent
constructor(inDesktop:boolean) {
super(profile)
@ -62,6 +64,7 @@ export class RemixAIPlugin extends ViewPlugin {
this.useRemoteInferencer = true
this.initialize()
}
this.completionAgent = new CodeCompletionAgent(this)
}
async initialize(model1?:IModel, model2?:IModel, remoteModel?:IRemoteModel, useRemote?:boolean){
@ -110,6 +113,7 @@ export class RemixAIPlugin extends ViewPlugin {
}
async code_completion(prompt: string, promptAfter: string): Promise<any> {
this.completionAgent.searchIndex(prompt)
if (this.isOnDesktop && !this.useRemoteInferencer) {
return await this.call(this.remixDesktopPluginName, 'code_completion', prompt, promptAfter)
} else {
@ -175,6 +179,7 @@ export class RemixAIPlugin extends ViewPlugin {
}
async code_insertion(msg_pfx: string, msg_sfx: string): Promise<any> {
this.completionAgent.indexWorkspace()
if (this.isOnDesktop && !this.useRemoteInferencer) {
return await this.call(this.remixDesktopPluginName, 'code_insertion', msg_pfx, msg_sfx)
} else {

@ -69,6 +69,7 @@ export class RemixClient extends PluginClient<any, CustomRemixApi> {
try {
// TODO: remove! no formatting required since already handled on server
const file = await this.client.call('fileManager', 'getCurrentFile')
const content = await this.client.call('fileManager', 'readFile', file)
const messageAI = `Vyper code: ${content}\n error message: ${message}\n explain why the error occurred and how to fix it.`

@ -1,23 +1,78 @@
import * as fs from 'fs';
import FlexSearch from 'flexsearch';
import lunr from 'lunr';
class CodeCompletionAgent {
private codebase: string[];
interface Document {
id: number;
filename: string;
content: string;
identifier: number;
}
enum SupportedFileExtensions {
solidity = '.sol',
vyper = '.vy',
circom = '.circom',
}
export class CodeCompletionAgent {
private workspacesIndexes = new Map<string, any>();
props: any;
indexer: any;
Documents: Document[] = [];
constructor(codebasePath: string) {
// git or fs
this.codebase = this.loadCodebase(codebasePath);
constructor(props) {
this.props = props;
this.props.on('fileManager', 'fileAdded', (path) => { });
this.props.on('filePanel', 'workspaceCreated', async () => { });
}
private loadCodebase(path: string): string[] {
const files = fs.readdirSync(path);
return files
.filter(file => file.endsWith('.ts'))
.flatMap(file => fs.readFileSync(`${path}/${file}`, 'utf-8').split('\n'));
async getDcocuments() {
const documents: Document[] = [];
const dirs = await this.props.call('fileManager', 'dirList', '/');
let c = 0;
for (const dir of dirs) {
const files = await this.props.call('fileManager', 'fileList', dir);
for (const file of files) {
const content = await this.props.call('fileManager', 'readFile', file);
// filter out any SupportedFileExtensions
if (! Object.values(SupportedFileExtensions).some(ext => file.endsWith(ext))) continue;
documents.push({
id: ++c,
filename: file,
content: content,
identifier: c*34,
});
}
}
console.log('Documents', documents);
return documents;
}
public getSuggestions(currentLine: string, numSuggestions: number = 3): string[] {
const suggestions: string[] = [];
// get `numSuggestions` from the llm
return suggestions;
indexWorkspace() {
this.getDcocuments().then((documents) => {
this.Documents = documents;
this.indexer =lunr(function () {
this.ref('id')
this.field('filename')
this.field('content')
this.field('Identifier');
documents.forEach(doc => {
this.add(doc);
});
});
});
}
async searchIndex(query: string) {
try {
const searchResult = this.indexer.search(query);
console.log('Search result', searchResult);
return searchResult[0];
} catch (error) {
console.log('Error searching index', error);
return null;
}
}
}

@ -21,4 +21,5 @@ export {
export * from './types/types'
export * from './helpers/streamHandler'
export * from './agents/codeExplainAgent'
export * from './agents/codeExplainAgent'
export * from './agents/completionAgent'

@ -0,0 +1,22 @@
import React from 'react';
interface ButtonProps {
label: string;
onClick: () => void;
icon?: string;
}
const DynamicButtons: React.FC<{ buttons: ButtonProps[] }> = ({ buttons }) => {
return (
<div className="dynamic-buttons">
{buttons.map((button, index) => (
<button key={index} onClick={button.onClick}>
{button.icon && <i className={button.icon}></i>}
{button.label}
</button>
))}
</div>
);
};
export default DynamicButtons;

@ -153,6 +153,7 @@
"express-ws": "^5.0.2",
"file-path-filter": "^3.0.2",
"file-saver": "^2.0.5",
"flexsearch": "^0.7.43",
"form-data": "^4.0.0",
"formik": "^2.4.5",
"from-exponential": "1.1.1",
@ -171,6 +172,7 @@
"jszip": "^3.6.0",
"just-once": "^2.2.0",
"latest-version": "^5.1.0",
"lunr": "^2.3.9",
"merge": "^2.1.1",
"npm-install-version": "^6.0.2",
"octokit": "^3.1.2",

@ -16080,6 +16080,11 @@ flatted@^3.1.0:
resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.7.tgz#609f39207cb614b89d0765b477cb2d437fbf9787"
integrity sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==
flexsearch@^0.7.43:
version "0.7.43"
resolved "https://registry.yarnpkg.com/flexsearch/-/flexsearch-0.7.43.tgz#34f89b36278a466ce379c5bf6fb341965ed3f16c"
integrity sha512-c5o/+Um8aqCSOXGcZoqZOm+NqtVwNsvVpWv6lfmSclU954O3wvQKxxK8zj74fPaSJbXpSLTs4PRhh+wnoCXnKg==
flora-colossus@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/flora-colossus/-/flora-colossus-1.0.1.tgz#aba198425a8185341e64f9d2a6a96fd9a3cbdb93"
@ -21348,6 +21353,11 @@ lru_map@^0.3.3:
resolved "https://registry.yarnpkg.com/lru_map/-/lru_map-0.3.3.tgz#b5c8351b9464cbd750335a79650a0ec0e56118dd"
integrity sha512-Pn9cox5CsMYngeDbmChANltQl+5pi6XmTrraMSzhPmMBbmgcxmqWry0U3PGapCU1yB4/LqCcom7qhHZiF/jGfQ==
lunr@^2.3.9:
version "2.3.9"
resolved "https://registry.yarnpkg.com/lunr/-/lunr-2.3.9.tgz#18b123142832337dd6e964df1a5a7707b25d35e1"
integrity sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==
lz-string@^1.4.4:
version "1.4.4"
resolved "https://registry.yarnpkg.com/lz-string/-/lz-string-1.4.4.tgz#c0d8eaf36059f705796e1e344811cf4c498d3a26"

Loading…
Cancel
Save