added max token support && event support for indexing

pull/5714/head
STetsing 2 weeks ago
parent ac02d8f228
commit 5302560a13
  1. 25
      apps/remix-ide/src/app/plugins/remixAIPlugin.tsx
  2. 79
      libs/remix-ai-core/src/agents/completionAgent.ts
  3. 2
      libs/remix-ai-core/src/inferencers/remote/remoteInference.ts

@ -65,13 +65,6 @@ export class RemixAIPlugin extends ViewPlugin {
this.initialize() this.initialize()
} }
this.completionAgent = new CodeCompletionAgent(this) this.completionAgent = new CodeCompletionAgent(this)
setInterval(() => {
console.log('Indexing workspace')
this.completionAgent.indexWorkspace()
}, 60000)
this.securityAgent = new SecurityAgent(this) this.securityAgent = new SecurityAgent(this)
} }
@ -119,11 +112,13 @@ export class RemixAIPlugin extends ViewPlugin {
if (this.completionAgent.indexer == null || this.completionAgent.indexer == undefined) await this.completionAgent.indexWorkspace() if (this.completionAgent.indexer == null || this.completionAgent.indexer == undefined) await this.completionAgent.indexWorkspace()
const currentFile = await this.call('fileManager', 'getCurrentFile') const currentFile = await this.call('fileManager', 'getCurrentFile')
const contextfiles = await this.completionAgent.getContextFiles() const contextfiles = await this.completionAgent.getContextFiles(prompt)
const refined = CodeCompletionAgent.refineContext(prompt, promptAfter)
console.log('contextfiles', contextfiles)
if (this.isOnDesktop && !this.useRemoteInferencer) { if (this.isOnDesktop && !this.useRemoteInferencer) {
return await this.call(this.remixDesktopPluginName, 'code_completion', prompt, promptAfter) return await this.call(this.remixDesktopPluginName, 'code_completion', refined[0], refined[1])
} else { } else {
return await this.remoteInferencer.code_completion(prompt, promptAfter, contextfiles, currentFile) return await this.remoteInferencer.code_completion(refined[0], refined[1], contextfiles, currentFile)
} }
} }
@ -185,11 +180,13 @@ export class RemixAIPlugin extends ViewPlugin {
if (this.completionAgent.indexer == null || this.completionAgent.indexer == undefined) await this.completionAgent.indexWorkspace() if (this.completionAgent.indexer == null || this.completionAgent.indexer == undefined) await this.completionAgent.indexWorkspace()
const currentFile = await this.call('fileManager', 'getCurrentFile') const currentFile = await this.call('fileManager', 'getCurrentFile')
const contextfiles = this.completionAgent.getContextFiles() const contextfiles = this.completionAgent.getContextFiles(msg_pfx)
const refined = CodeCompletionAgent.refineContext(msg_pfx, msg_sfx)
if (this.isOnDesktop && !this.useRemoteInferencer) { if (this.isOnDesktop && !this.useRemoteInferencer) {
return await this.call(this.remixDesktopPluginName, 'code_insertion', msg_pfx, msg_sfx) return await this.call(this.remixDesktopPluginName, 'code_insertion', refined[0], refined[1])
} else { } else {
return await this.remoteInferencer.code_insertion(msg_pfx, msg_sfx, contextfiles, currentFile) return await this.remoteInferencer.code_insertion(refined[0], refined[1], contextfiles, currentFile)
} }
} }
@ -212,7 +209,7 @@ export class RemixAIPlugin extends ViewPlugin {
else { else {
console.log("chatRequestBuffer is not empty. First process the last request.", this.chatRequestBuffer) console.log("chatRequestBuffer is not empty. First process the last request.", this.chatRequestBuffer)
} }
_paq.push(['trackEvent', 'ai', 'remixAI_chat', 'askFromTerminal']) _paq.push(['trackEvent', 'ai', 'remixAI', 'remixAI_chat'])
} }
async ProcessChatRequestBuffer(params:IParams=GenerationParams){ async ProcessChatRequestBuffer(params:IParams=GenerationParams){

@ -7,6 +7,12 @@ interface Document {
identifier: number; identifier: number;
} }
interface indexT{
isIndexed: boolean;
lastIndexedTime?: number;
reason?: string;
}
enum SupportedFileExtensions { enum SupportedFileExtensions {
solidity = '.sol', solidity = '.sol',
vyper = '.vy', vyper = '.vy',
@ -20,17 +26,36 @@ export class CodeCompletionAgent {
Documents: Document[] = []; Documents: Document[] = [];
INDEX_THRESHOLD = 0.1; INDEX_THRESHOLD = 0.1;
N_MATCHES = 1; N_MATCHES = 1;
indexed: indexT = {
isIndexed: false,
lastIndexedTime: 0,
reason: 'Init',
};
constructor(props) { constructor(props) {
this.props = props; this.props = props;
this.props.on('fileManager', 'fileAdded', (path) => { }); this.listenForChanges();
this.props.on('filePanel', 'workspaceCreated', async () => { });
this.indexer =lunr(function () { this.indexer =lunr(function () {
this.ref('id') this.ref('id')
this.field('filename') this.field('filename')
this.field('content') this.field('content')
this.field('Identifier'); this.field('Identifier');
}); });
// listen for file changes
this.props.on('fileManager', 'fileRemoved', (path) => { this.indexed.isIndexed = false; });
setInterval(() => {
this.indexWorkspace()
}, 60000)
}
listenForChanges() {
this.props.on('fileManager', 'fileAdded', (path) => { this.indexed = { isIndexed: false, reason:"fileAdded" } });
this.props.on('fileManager', 'fileRemoved', (path) => { this.indexed = { isIndexed: false, reason:"fileRemoved" } });
this.props.on('filePanel', 'workspaceCreated', () => { this.indexed = { isIndexed: false, reason:"workspaceCreated" } });
this.props.on('filePanel', 'workspaceRenamed', () => { this.indexed = { isIndexed: false, reason:"workspaceRenamed" }});
this.props.on('filePanel', 'workspaceDeleted', () => { this.indexed = { isIndexed: false, reason:"workspaceDeleted" } });
} }
async getDcocuments() { async getDcocuments() {
@ -56,7 +81,6 @@ export class CodeCompletionAgent {
indexWorkspace() { indexWorkspace() {
this.getDcocuments().then((documents) => { this.getDcocuments().then((documents) => {
this.Documents = documents;
this.indexer =lunr(function () { this.indexer =lunr(function () {
this.ref('id') this.ref('id')
this.field('filename') this.field('filename')
@ -67,13 +91,19 @@ export class CodeCompletionAgent {
this.add(doc); this.add(doc);
}); });
}); });
this.Documents = documents;
}); });
this.indexed = { isIndexed: true, lastIndexedTime: Date.now(), reason: 'init Indexing' };
} }
async getContextFiles() { async getContextFiles(prompt) {
try { try {
if (!this.indexed.isIndexed) {
this.indexWorkspace();
}
const currentFile = await this.props.call('fileManager', 'getCurrentFile'); const currentFile = await this.props.call('fileManager', 'getCurrentFile');
const content = await this.props.call('fileManager', 'readFile', currentFile); const content = prompt;
const searchResult = this.indexer.search(content) const searchResult = this.indexer.search(content)
const fcps = await this.processResults(searchResult, currentFile); const fcps = await this.processResults(searchResult, currentFile);
const resolvedFcps = await Promise.all(fcps); const resolvedFcps = await Promise.all(fcps);
@ -100,4 +130,43 @@ export class CodeCompletionAgent {
return fileContentPairs; return fileContentPairs;
} }
// TODO rm context files length
static refineContext(words1: string, words2: string, maxWords: number=6500) {
// Avoid model out of context
const totalWords = words1.length + words2.length;
if (totalWords <= maxWords) {
console.log('total words less than max words', totalWords);
return [words1, words2];
}
const halfMaxWords = Math.floor(maxWords / 2);
let takeFromText1 = words1.length < halfMaxWords ? words1.length : halfMaxWords;
let takeFromText2 = words2.length < halfMaxWords ? words2.length : halfMaxWords;
// Adjust if one text is taking more than half, we balance by limiting the other text
if (words1.length < halfMaxWords && words2.length + words1.length <= maxWords) {
takeFromText2 = Math.min(words2.length, maxWords - words1.length);
} else if (words2.length < halfMaxWords && words1.length + words2.length <= maxWords) {
takeFromText1 = Math.min(words1.length, maxWords - words2.length);
} else if (words1.length < halfMaxWords && words2.length + words1.length >= maxWords) {
takeFromText2 = Math.min(words2.length, maxWords - words1.length);
} else if (words2.length > halfMaxWords && words1.length + words2.length <= maxWords) {
takeFromText1 = Math.min(words1.length, maxWords - words2.length);
}
const splicedText1 = words1.slice(words1.length - takeFromText1);
const splicedText2 = words2.slice(words2.length - takeFromText2);
console.log('take from text 1', takeFromText1)
console.log('take from text 2', takeFromText2)
console.log('Spliced text 1 length:', splicedText1.length);
console.log('Spliced text 2 length:', splicedText2.length);
console.log('initial word 1 length:', words1.length);
console.log('initial word 2 length:', words2.length);
console.log('text 1:', splicedText1);
console.log('text 2:', splicedText2);
return [splicedText1 , splicedText2]
}
} }

@ -12,7 +12,7 @@ export class RemoteInferencer implements ICompletions {
max_history = 7 max_history = 7
model_op = RemoteBackendOPModel.CODELLAMA // default model operation change this to llama if necessary model_op = RemoteBackendOPModel.CODELLAMA // default model operation change this to llama if necessary
event: EventEmitter event: EventEmitter
test_env=false test_env=true
test_url="http://solcodertest.org" test_url="http://solcodertest.org"
constructor(apiUrl?:string, completionUrl?:string) { constructor(apiUrl?:string, completionUrl?:string) {

Loading…
Cancel
Save