-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Generate agent #5870
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Generate agent #5870
Changes from 6 commits
ab4e81b
655c06d
3a55986
eb94671
3528efb
01ecb20
833800f
3a53244
20fb2f5
4697ac8
278d6a5
0904e3c
8c421ff
0e0b6ec
b4b5f5d
694765f
4aad873
ac2006d
6b60e4e
d0f79dd
404bcf8
a0cca0f
07738dd
4425dd9
1f76be1
6fa8bf6
88338f4
60108e6
d78c8f5
b2f9afc
9660086
d5d1df1
60dc7f6
48da1aa
d883884
5119bb0
09be783
cb18d2d
d04081f
04e54dd
d70ce3e
14552dd
a182ced
8053ec1
219ee73
ef9f156
41ee3f0
f2fcfdc
2ab9075
90e29d1
af365ee
a68bca2
a3593cd
53329ba
b0dca79
3bd3ba2
7ef6e4b
1143654
79a5581
3cc33ac
48e8d46
3a1d395
ec6f5f1
c0f3f35
7a88dcd
dce2118
6c0e641
5c22a81
a5f122e
32d031b
0931de6
3939854
d548f79
115b111
8aa0a64
5173e33
bfe0ba2
f858536
080633c
2cce3d3
32bda2f
4a97566
f84c51c
a6ebdc9
4b4e915
6007cba
8a10442
4e500d7
fd57195
a336201
e065660
632574d
c1473db
4b22499
c59b8c2
8977dd2
c728966
8ed3412
e54518c
148204e
8292826
5e46649
01e3ccb
2f7dc3e
f31bd16
98c32eb
7d9778a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
import { parse } from "path"; | ||
import { AssistantParams } from "../types/models"; | ||
|
||
const compilationParams = { | ||
optimize: false, | ||
evmVersion: null, | ||
language: 'Solidity', | ||
version: '0.8.28+commit.7893614a' | ||
} | ||
|
||
interface CompilationResult { | ||
compilationSucceeded: boolean | ||
errors: string | ||
} | ||
|
||
export class ContractAgent { | ||
plugin: any; | ||
readonly generationAttempts: number = 3 | ||
nAttempts: number = 0 | ||
generationThreadID: string= '' | ||
workspaceName: string = '' | ||
contracts: any = {} | ||
|
||
constructor(props) { | ||
this.plugin = props; | ||
AssistantParams.provider = this.plugin.assistantProvider | ||
} | ||
|
||
async writeContracts(payload, userPrompt) { | ||
const currentWorkspace = await this.plugin.call('filePanel', 'getCurrentWorkspace') | ||
try { | ||
console.log('Writing contracts', payload) | ||
this.contracts = {} | ||
const parsedFiles = payload | ||
this.generationThreadID = parsedFiles['threadID'] | ||
this.workspaceName = parsedFiles['projectName'] | ||
|
||
this.nAttempts += 1 | ||
console.log('Attempts', this.nAttempts) | ||
console.log('Generation attempts', this.generationAttempts) | ||
if (this.nAttempts > this.generationAttempts) { | ||
console.error('Failed to generate the code') | ||
return "Failed to generate secure code on this prompt ```" + userPrompt + "````" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this should throw an error instead of returning a string. |
||
} | ||
|
||
for (const file of parsedFiles.files) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This doesn't handle yet solidity import? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I handle imports by adding all files for compilation see line 33, which make sense, the generation must be complete ( from a compilation point of view) |
||
if (file.fileName.endsWith('.sol')) { | ||
const result:CompilationResult = await this.compilecontracts(file.fileName, file.content) | ||
console.log('compilation result', result) | ||
if (!result.compilationSucceeded) { | ||
// nasty recursion | ||
console.log('compilation failed', file.fileName) | ||
const newPrompt = `The contract ${file.fileName} does not compile. Here is the error message; ${result.errors}. Try again with the same formatting!` | ||
await this.plugin.generate(newPrompt, AssistantParams, this.generationThreadID); // reuse the same thread | ||
return "Failed to generate secure code on this prompt ```" + userPrompt + "```" | ||
} | ||
} | ||
} | ||
|
||
console.log('All source files are compiling') | ||
await this.createWorkspace(this.workspaceName) | ||
await this.plugin.call('filePanel', 'switchToWorkspace', { name: this.workspaceName, isLocalHost: false }) | ||
const dirCreated = [] | ||
for (const file of parsedFiles.files) { | ||
console.log('Writing file', file.fileName) | ||
const dir = file.fileName.split('/').slice(0, -1).join('/') | ||
console.log('Creating directory', dir) | ||
if (!dirCreated.includes(dir) && dir) { | ||
console.log('Creating new directory', dir) | ||
await this.plugin.call('fileManager', 'mkdir', dir) | ||
dirCreated.push(dir) | ||
} | ||
await this.plugin.call('fileManager', 'writeFile', file.fileName, file.content) | ||
await this.plugin.call('codeFormatter', 'format', file.fileName) | ||
// recompile to have it in the workspace | ||
// await this.plugin.call('solidity' as any, 'setCompilerConfig', compilationParams) | ||
// await this.plugin.call('solidity' as any, 'compile', file.fileName) | ||
} | ||
this.nAttempts = 0 | ||
return "New workspace created: **" + this.workspaceName + "**\nUse the Hamburger menu to select it!" | ||
} catch (error) { | ||
console.log('Error writing contracts', error) | ||
this.deleteWorkspace(this.workspaceName ) | ||
this.nAttempts = 0 | ||
await this.plugin.call('filePanel', 'switchToWorkspace', currentWorkspace) | ||
return "Failed to generate secure code on this prompt ```" + userPrompt + "```" | ||
} | ||
|
||
} | ||
|
||
async createWorkspace(workspaceName) { | ||
// create random workspace surfixed with timestamp | ||
const timestamp = new Date().getTime() | ||
workspaceName += '-' + timestamp | ||
await this.plugin.call('filePanel', 'createWorkspace', workspaceName, true) | ||
this.workspaceName = workspaceName | ||
} | ||
|
||
deleteWorkspace(workspaceName) { | ||
this.plugin.call('filePanel', 'deleteWorkspace', workspaceName) | ||
} | ||
|
||
async compilecontracts(fileName, fileContent): Promise<CompilationResult> { | ||
// do not compile tests files | ||
if (fileName.includes('tests/')) return { compilationSucceeded: true, errors: null } | ||
|
||
this.contracts[fileName] = { content : fileContent } | ||
console.log('compiling contract', this.contracts) | ||
const result = await this.plugin.call('solidity' as any, 'compileWithParameters', this.contracts, compilationParams) | ||
console.log('compilation result', result) | ||
const data = result.data | ||
let error = false | ||
|
||
if (data.errors) { | ||
error = data.errors.find((error) => error.type !== 'Warning') | ||
} | ||
if (data.errors && data.errors.length && error) { | ||
const msg = ` | ||
- Compilation errors: ${data.errors.map((e) => e.formattedMessage)}. | ||
` | ||
return { compilationSucceeded: false, errors: msg } | ||
} | ||
|
||
return { compilationSucceeded: true, errors: null } | ||
} | ||
|
||
extractImportPaths(text) { | ||
// eslint-disable-next-line no-useless-escape | ||
const regex = /import\s*\"([^\"]+)\"\s*;/g; | ||
const paths = []; | ||
let match; | ||
|
||
// Use the regex to find all matches in the text | ||
while ((match = regex.exec(text)) !== null) { | ||
// Push the captured path to the paths array | ||
paths.push(match[1]); | ||
} | ||
|
||
return paths; | ||
} | ||
|
||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you add a documentation for this function?