@proteinjs/conversation 1.0.6 → 1.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.js +20 -0
- package/.prettierignore +4 -0
- package/.prettierrc +8 -0
- package/CHANGELOG.md +18 -4
- package/LICENSE +21 -0
- package/dist/src/CodegenConversation.d.ts.map +1 -1
- package/dist/src/CodegenConversation.js +2 -2
- package/dist/src/CodegenConversation.js.map +1 -1
- package/dist/src/Conversation.d.ts.map +1 -1
- package/dist/src/Conversation.js +33 -17
- package/dist/src/Conversation.js.map +1 -1
- package/dist/src/Function.d.ts.map +1 -1
- package/dist/src/OpenAi.d.ts.map +1 -1
- package/dist/src/OpenAi.js +55 -38
- package/dist/src/OpenAi.js.map +1 -1
- package/dist/src/Paragraph.d.ts.map +1 -1
- package/dist/src/Paragraph.js +2 -1
- package/dist/src/Paragraph.js.map +1 -1
- package/dist/src/Sentence.d.ts.map +1 -1
- package/dist/src/Sentence.js +4 -2
- package/dist/src/Sentence.js.map +1 -1
- package/dist/src/code_template/Code.d.ts.map +1 -1
- package/dist/src/code_template/Code.js +6 -2
- package/dist/src/code_template/Code.js.map +1 -1
- package/dist/src/code_template/CodeTemplate.d.ts.map +1 -1
- package/dist/src/code_template/CodeTemplate.js +2 -1
- package/dist/src/code_template/CodeTemplate.js.map +1 -1
- package/dist/src/code_template/Repo.d.ts.map +1 -1
- package/dist/src/code_template/Repo.js +8 -4
- package/dist/src/code_template/Repo.js.map +1 -1
- package/dist/src/fs/conversation_fs/ConversationFsModerator.d.ts.map +1 -1
- package/dist/src/fs/conversation_fs/ConversationFsModerator.js +18 -7
- package/dist/src/fs/conversation_fs/ConversationFsModerator.js.map +1 -1
- package/dist/src/fs/conversation_fs/ConversationFsModule.d.ts.map +1 -1
- package/dist/src/fs/conversation_fs/ConversationFsModule.js +1 -3
- package/dist/src/fs/conversation_fs/ConversationFsModule.js.map +1 -1
- package/dist/src/fs/conversation_fs/FsFunctions.d.ts.map +1 -1
- package/dist/src/fs/conversation_fs/FsFunctions.js +15 -29
- package/dist/src/fs/conversation_fs/FsFunctions.js.map +1 -1
- package/dist/src/fs/git/GitModule.d.ts.map +1 -1
- package/dist/src/fs/git/GitModule.js.map +1 -1
- package/dist/src/fs/keyword_to_files_index/KeywordToFilesIndexFunctions.d.ts.map +1 -1
- package/dist/src/fs/keyword_to_files_index/KeywordToFilesIndexFunctions.js +2 -2
- package/dist/src/fs/keyword_to_files_index/KeywordToFilesIndexFunctions.js.map +1 -1
- package/dist/src/fs/keyword_to_files_index/KeywordToFilesIndexModule.d.ts.map +1 -1
- package/dist/src/fs/keyword_to_files_index/KeywordToFilesIndexModule.js +1 -3
- package/dist/src/fs/keyword_to_files_index/KeywordToFilesIndexModule.js.map +1 -1
- package/dist/src/fs/package/PackageFunctions.d.ts.map +1 -1
- package/dist/src/fs/package/PackageFunctions.js +20 -30
- package/dist/src/fs/package/PackageFunctions.js.map +1 -1
- package/dist/src/fs/package/PackageModule.d.ts.map +1 -1
- package/dist/src/fs/package/PackageModule.js +15 -8
- package/dist/src/fs/package/PackageModule.js.map +1 -1
- package/dist/src/history/MessageHistory.d.ts.map +1 -1
- package/dist/src/history/MessageHistory.js +6 -3
- package/dist/src/history/MessageHistory.js.map +1 -1
- package/dist/src/template/ConversationTemplate.d.ts.map +1 -1
- package/dist/src/template/ConversationTemplateFunctions.d.ts.map +1 -1
- package/dist/src/template/ConversationTemplateFunctions.js +2 -2
- package/dist/src/template/ConversationTemplateFunctions.js.map +1 -1
- package/dist/src/template/ConversationTemplateModule.d.ts.map +1 -1
- package/dist/src/template/ConversationTemplateModule.js +9 -7
- package/dist/src/template/ConversationTemplateModule.js.map +1 -1
- package/dist/src/template/createCode/CreateCodeConversationTemplate.d.ts.map +1 -1
- package/dist/src/template/createCode/CreateCodeConversationTemplate.js +2 -9
- package/dist/src/template/createCode/CreateCodeConversationTemplate.js.map +1 -1
- package/dist/src/template/createPackage/CreatePackageConversationTemplate.d.ts.map +1 -1
- package/dist/src/template/createPackage/CreatePackageConversationTemplate.js +1 -8
- package/dist/src/template/createPackage/CreatePackageConversationTemplate.js.map +1 -1
- package/dist/test/createKeywordFilesIndex.test.js.map +1 -1
- package/dist/test/openai/openai.generateList.test.js.map +1 -1
- package/dist/test/openai/openai.parseCodeFromMarkdown.test.js +7 -3
- package/dist/test/openai/openai.parseCodeFromMarkdown.test.js.map +1 -1
- package/dist/test/repo/repo.test.js.map +1 -1
- package/jest.config.js +2 -2
- package/package.json +9 -3
- package/src/CodegenConversation.ts +6 -4
- package/src/Conversation.ts +102 -33
- package/src/ConversationModule.ts +2 -2
- package/src/Function.ts +0 -1
- package/src/OpenAi.ts +128 -63
- package/src/Paragraph.ts +3 -2
- package/src/Sentence.ts +5 -3
- package/src/code_template/Code.ts +25 -19
- package/src/code_template/CodeTemplate.ts +8 -7
- package/src/code_template/CodeTemplateModule.ts +2 -2
- package/src/code_template/Repo.ts +25 -19
- package/src/fs/conversation_fs/ConversationFsModerator.ts +34 -20
- package/src/fs/conversation_fs/ConversationFsModule.ts +13 -7
- package/src/fs/conversation_fs/FsFunctions.ts +33 -44
- package/src/fs/git/GitModule.ts +2 -4
- package/src/fs/keyword_to_files_index/KeywordToFilesIndexFunctions.ts +31 -31
- package/src/fs/keyword_to_files_index/KeywordToFilesIndexModule.ts +19 -18
- package/src/fs/package/PackageFunctions.ts +34 -41
- package/src/fs/package/PackageModule.ts +33 -21
- package/src/history/MessageHistory.ts +7 -4
- package/src/history/MessageModerator.ts +1 -1
- package/src/template/ConversationTemplate.ts +9 -9
- package/src/template/ConversationTemplateFunctions.ts +8 -7
- package/src/template/ConversationTemplateModule.ts +24 -15
- package/src/template/createApp/CreateAppTemplate.ts +1 -1
- package/src/template/createCode/CreateCodeConversationTemplate.ts +9 -11
- package/src/template/createPackage/CreatePackageConversationTemplate.ts +2 -9
- package/src/template/createPackage/jest.config.js +2 -2
- package/test/createKeywordFilesIndex.test.ts +3 -3
- package/test/openai/openai.generateList.test.ts +5 -3
- package/test/openai/openai.parseCodeFromMarkdown.test.ts +10 -5
- package/test/repo/repo.test.ts +3 -4
- package/tsconfig.json +16 -20
|
@@ -3,21 +3,21 @@ import { Conversation } from '../Conversation';
|
|
|
3
3
|
import { Repo } from './Repo';
|
|
4
4
|
|
|
5
5
|
export type SourceFile = {
|
|
6
|
-
relativePath: string
|
|
7
|
-
code: Code
|
|
8
|
-
}
|
|
6
|
+
relativePath: string;
|
|
7
|
+
code: Code;
|
|
8
|
+
};
|
|
9
9
|
|
|
10
|
-
export type Import = {
|
|
11
|
-
moduleNames: string[]
|
|
12
|
-
importPathFromGeneratedFile: string
|
|
13
|
-
sourceFilePath: string
|
|
14
|
-
}
|
|
10
|
+
export type Import = {
|
|
11
|
+
moduleNames: string[];
|
|
12
|
+
importPathFromGeneratedFile: string;
|
|
13
|
+
sourceFilePath: string;
|
|
14
|
+
};
|
|
15
15
|
|
|
16
16
|
export type CodeArgs = {
|
|
17
|
-
conversation: Conversation
|
|
18
|
-
description: string[]
|
|
19
|
-
imports?: Import[]
|
|
20
|
-
}
|
|
17
|
+
conversation: Conversation;
|
|
18
|
+
description: string[];
|
|
19
|
+
imports?: Import[];
|
|
20
|
+
};
|
|
21
21
|
|
|
22
22
|
export class Code {
|
|
23
23
|
private args: CodeArgs;
|
|
@@ -27,27 +27,33 @@ export class Code {
|
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
async generate(): Promise<string> {
|
|
30
|
-
if (this.args.imports)
|
|
30
|
+
if (this.args.imports) {
|
|
31
31
|
this.addImports(this.args.imports, this.args.conversation);
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return await this.args.conversation.generateCode(this.args.description, 'gpt-4');
|
|
34
35
|
}
|
|
35
36
|
|
|
36
37
|
private addImports(imports: Import[], conversation: Conversation) {
|
|
37
38
|
conversation.addSystemMessagesToHistory([
|
|
38
|
-
this.declarationMessage(imports.map(d => d.sourceFilePath)),
|
|
39
|
+
this.declarationMessage(imports.map((d) => d.sourceFilePath)),
|
|
39
40
|
this.importMessage(imports),
|
|
40
41
|
]);
|
|
41
42
|
}
|
|
42
43
|
|
|
43
44
|
private declarationMessage(tsFilePaths: string[]) {
|
|
44
|
-
const declarationMap = PackageUtil.generateTypescriptDeclarations({
|
|
45
|
+
const declarationMap = PackageUtil.generateTypescriptDeclarations({
|
|
46
|
+
tsFilePaths,
|
|
47
|
+
includeDependencyDeclarations: true,
|
|
48
|
+
});
|
|
45
49
|
const declarations = Object.values(declarationMap).join('\n');
|
|
46
50
|
return `Assume the following code exists in other files:\n${declarations}`;
|
|
47
51
|
}
|
|
48
52
|
|
|
49
53
|
private importMessage(imports: Omit<Import, 'filePath'>[]) {
|
|
50
|
-
const importStatements = imports.map(
|
|
54
|
+
const importStatements = imports.map(
|
|
55
|
+
(i) => `import { ${i.moduleNames.join(', ')} } from '${i.importPathFromGeneratedFile}'`
|
|
56
|
+
);
|
|
51
57
|
return `Add the following imports:\n${importStatements}`;
|
|
52
58
|
}
|
|
53
|
-
}
|
|
59
|
+
}
|
|
@@ -3,10 +3,10 @@ import { Fs, PackageUtil, Package } from '@proteinjs/util-node';
|
|
|
3
3
|
import { SourceFile } from './Code';
|
|
4
4
|
|
|
5
5
|
export type TemplateArgs = {
|
|
6
|
-
srcPath: string
|
|
7
|
-
additionalPackages?: Package[]
|
|
8
|
-
replacePackages?: boolean
|
|
9
|
-
}
|
|
6
|
+
srcPath: string;
|
|
7
|
+
additionalPackages?: Package[];
|
|
8
|
+
replacePackages?: boolean;
|
|
9
|
+
};
|
|
10
10
|
|
|
11
11
|
export abstract class CodeTemplate {
|
|
12
12
|
protected logger = new Logger(this.constructor.name);
|
|
@@ -21,7 +21,7 @@ export abstract class CodeTemplate {
|
|
|
21
21
|
|
|
22
22
|
async generate() {
|
|
23
23
|
await PackageUtil.installPackages(this.resolvePackages());
|
|
24
|
-
for (
|
|
24
|
+
for (const sourceFile of this.sourceFiles()) {
|
|
25
25
|
const filePath = Fs.baseContainedJoin(this.templateArgs.srcPath, sourceFile.relativePath);
|
|
26
26
|
this.logger.info(`Generating source file: ${filePath}`);
|
|
27
27
|
const code = await sourceFile.code.generate();
|
|
@@ -32,8 +32,9 @@ export abstract class CodeTemplate {
|
|
|
32
32
|
|
|
33
33
|
private resolvePackages() {
|
|
34
34
|
const packages: Package[] = this.templateArgs.replacePackages ? [] : this.dependencyPackages();
|
|
35
|
-
if (this.templateArgs.additionalPackages)
|
|
35
|
+
if (this.templateArgs.additionalPackages) {
|
|
36
36
|
packages.push(...this.templateArgs.additionalPackages);
|
|
37
|
+
}
|
|
37
38
|
return packages;
|
|
38
39
|
}
|
|
39
|
-
}
|
|
40
|
+
}
|
|
@@ -8,7 +8,7 @@ export class CodeTemplateModule implements ConversationModule {
|
|
|
8
8
|
getName(): string {
|
|
9
9
|
return 'Code Template';
|
|
10
10
|
}
|
|
11
|
-
|
|
11
|
+
|
|
12
12
|
getSystemMessages(): string[] {
|
|
13
13
|
return [
|
|
14
14
|
`If they want to create a function/class/object using an API we are familiar with, we will ask the user for the required information to fill in all mandatory parameters and ask them if they want to provide optional parameter values`,
|
|
@@ -47,4 +47,4 @@ export class CodeTemplateModule implements ConversationModule {
|
|
|
47
47
|
// await cmd(command, args, {OPENAI_API_KEY: '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'});
|
|
48
48
|
// console.info(`Ran command: ${commandLog}`);
|
|
49
49
|
// console.info(`Generated code from template: ${codePath}`);
|
|
50
|
-
// }
|
|
50
|
+
// }
|
|
@@ -8,20 +8,20 @@ export interface TsFile extends FileDescriptor {
|
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
export interface PackageInfo {
|
|
11
|
-
packageJSON: any;
|
|
11
|
+
packageJSON: any; // The content of the package.json
|
|
12
12
|
dirPath: string;
|
|
13
13
|
tsFiles: { [tsFilePath: string]: TsFile };
|
|
14
14
|
fileDescriptors: FileDescriptor[];
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
export type SlimPackageInfo = Omit<PackageInfo, 'packageJSON'|'tsFiles'>;
|
|
17
|
+
export type SlimPackageInfo = Omit<PackageInfo, 'packageJSON' | 'tsFiles'>;
|
|
18
18
|
|
|
19
19
|
export type RepoParams = {
|
|
20
|
-
packages: Record<string, PackageInfo
|
|
21
|
-
slimPackages: Record<string, SlimPackageInfo
|
|
22
|
-
tsFiles: { [tsFilePath: string]: TsFile }
|
|
23
|
-
keywordFilesIndex: { [keyword: string]: string[] /** file paths */ }
|
|
24
|
-
}
|
|
20
|
+
packages: Record<string, PackageInfo>;
|
|
21
|
+
slimPackages: Record<string, SlimPackageInfo>;
|
|
22
|
+
tsFiles: { [tsFilePath: string]: TsFile };
|
|
23
|
+
keywordFilesIndex: { [keyword: string]: string[] /** file paths */ };
|
|
24
|
+
};
|
|
25
25
|
|
|
26
26
|
export class Repo {
|
|
27
27
|
private logger = new Logger(this.constructor.name);
|
|
@@ -55,7 +55,7 @@ export class Repo {
|
|
|
55
55
|
|
|
56
56
|
getDeclarations(params: { tsFilePaths: string[] }) {
|
|
57
57
|
const queriedDeclarations: { [tsFilePath: string]: string } = {};
|
|
58
|
-
for (
|
|
58
|
+
for (const tsFilePath of params.tsFilePaths) {
|
|
59
59
|
queriedDeclarations[tsFilePath] = this.params.tsFiles[tsFilePath].declaration;
|
|
60
60
|
this.logger.info(`Accessed declaration: ${tsFilePath}`);
|
|
61
61
|
}
|
|
@@ -68,25 +68,26 @@ export class RepoFactory {
|
|
|
68
68
|
|
|
69
69
|
public static async createRepo(dir: string): Promise<Repo> {
|
|
70
70
|
this.LOGGER.info(`Creating repo for dir: ${dir}`);
|
|
71
|
-
|
|
71
|
+
const repoParams: RepoParams = { packages: {}, slimPackages: {}, tsFiles: {}, keywordFilesIndex: {} };
|
|
72
72
|
|
|
73
73
|
async function traverse(dir: string) {
|
|
74
74
|
const childrenNames = await fs.readdir(dir, { withFileTypes: true });
|
|
75
|
-
|
|
75
|
+
const hasPackageJson = childrenNames.some((dirent) => dirent.name === 'package.json');
|
|
76
76
|
if (hasPackageJson) {
|
|
77
77
|
const packageContent = await fs.readFile(path.join(dir, 'package.json'), 'utf-8');
|
|
78
78
|
const packageJSON = JSON.parse(packageContent);
|
|
79
|
-
repoParams.packages[packageJSON.name] = {
|
|
79
|
+
repoParams.packages[packageJSON.name] = {
|
|
80
80
|
packageJSON: packageJSON,
|
|
81
81
|
dirPath: dir,
|
|
82
82
|
fileDescriptors: [],
|
|
83
83
|
tsFiles: {},
|
|
84
84
|
};
|
|
85
85
|
}
|
|
86
|
-
|
|
86
|
+
|
|
87
87
|
for (const dirent of childrenNames) {
|
|
88
|
-
if (!dirent.isDirectory())
|
|
88
|
+
if (!dirent.isDirectory()) {
|
|
89
89
|
continue;
|
|
90
|
+
}
|
|
90
91
|
|
|
91
92
|
// Exclude directories 'node_modules' and 'dist' right at the beginning
|
|
92
93
|
if (dirent.name.includes('node_modules') || dirent.name.includes('dist')) {
|
|
@@ -101,7 +102,7 @@ export class RepoFactory {
|
|
|
101
102
|
|
|
102
103
|
await traverse(dir);
|
|
103
104
|
await RepoFactory.loadFiles(repoParams);
|
|
104
|
-
Object.keys(repoParams.packages).forEach(packageName => {
|
|
105
|
+
Object.keys(repoParams.packages).forEach((packageName) => {
|
|
105
106
|
const { packageJSON, tsFiles, ...slimPackage } = repoParams.packages[packageName];
|
|
106
107
|
repoParams.slimPackages[packageName] = slimPackage;
|
|
107
108
|
});
|
|
@@ -110,18 +111,23 @@ export class RepoFactory {
|
|
|
110
111
|
}
|
|
111
112
|
|
|
112
113
|
private static async loadFiles(repoParams: RepoParams) {
|
|
113
|
-
for (
|
|
114
|
+
for (const packageName of Object.keys(repoParams.packages)) {
|
|
114
115
|
this.LOGGER.info(`Loading files for package: ${packageName}`);
|
|
115
116
|
const dirPath = repoParams.packages[packageName].dirPath;
|
|
116
117
|
if (dirPath) {
|
|
117
|
-
repoParams.packages[packageName].fileDescriptors.push(
|
|
118
|
-
|
|
119
|
-
|
|
118
|
+
repoParams.packages[packageName].fileDescriptors.push(
|
|
119
|
+
...(await Fs.getFilesInDirectory(dirPath, ['node_modules', 'dist']))
|
|
120
|
+
);
|
|
121
|
+
for (const fileDescriptor of repoParams.packages[packageName].fileDescriptors) {
|
|
122
|
+
const typescriptDeclaration = PackageUtil.generateTypescriptDeclarations({
|
|
123
|
+
tsFilePaths: [fileDescriptor.path],
|
|
124
|
+
})[fileDescriptor.path];
|
|
120
125
|
const tsFile = Object.assign({ declaration: typescriptDeclaration }, fileDescriptor);
|
|
121
126
|
repoParams.packages[packageName].tsFiles[fileDescriptor.path] = tsFile;
|
|
122
127
|
repoParams.tsFiles[fileDescriptor.path] = tsFile;
|
|
123
|
-
if (!repoParams.keywordFilesIndex[fileDescriptor.nameWithoutExtension])
|
|
128
|
+
if (!repoParams.keywordFilesIndex[fileDescriptor.nameWithoutExtension]) {
|
|
124
129
|
repoParams.keywordFilesIndex[fileDescriptor.nameWithoutExtension] = [];
|
|
130
|
+
}
|
|
125
131
|
|
|
126
132
|
repoParams.keywordFilesIndex[fileDescriptor.nameWithoutExtension].push(fileDescriptor.path);
|
|
127
133
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/* eslint-disable no-empty */
|
|
1
2
|
import { LogLevel, Logger } from '@proteinjs/util';
|
|
2
3
|
import { FileContentMap } from '@proteinjs/util-node';
|
|
3
4
|
import { ChatCompletionMessageParam } from 'openai/resources/chat';
|
|
@@ -23,12 +24,12 @@ export class ConversationFsFactory {
|
|
|
23
24
|
}
|
|
24
25
|
|
|
25
26
|
merge(existingFs: ConversationFs, updates: FileContentMap): ConversationFs {
|
|
26
|
-
for (
|
|
27
|
+
for (const filePath of Object.keys(updates)) {
|
|
27
28
|
// if the file already exists in the fs
|
|
28
29
|
if (existingFs.fileContentMap[filePath]) {
|
|
29
|
-
this.logger.debug(`Updating existing file: ${filePath}`)
|
|
30
|
+
this.logger.debug(`Updating existing file: ${filePath}`);
|
|
30
31
|
existingFs.fileContentMap[filePath] = updates[filePath];
|
|
31
|
-
const oldIndex = existingFs.order.findIndex(item => item == filePath);
|
|
32
|
+
const oldIndex = existingFs.order.findIndex((item) => item == filePath);
|
|
32
33
|
existingFs.order.splice(oldIndex, 1);
|
|
33
34
|
existingFs.order.push(filePath);
|
|
34
35
|
continue;
|
|
@@ -36,12 +37,12 @@ export class ConversationFsFactory {
|
|
|
36
37
|
|
|
37
38
|
// if we have less than the max number of files in the fs
|
|
38
39
|
if (Object.keys(existingFs.fileContentMap).length < this.params.maxFiles) {
|
|
39
|
-
this.logger.debug(`Adding new file (under limit): ${filePath}`)
|
|
40
|
+
this.logger.debug(`Adding new file (under limit): ${filePath}`);
|
|
40
41
|
existingFs.fileContentMap[filePath] = updates[filePath];
|
|
41
42
|
existingFs.order.push(filePath);
|
|
42
43
|
continue;
|
|
43
44
|
} else {
|
|
44
|
-
this.logger.debug(`Adding new file (over limit): ${filePath}`)
|
|
45
|
+
this.logger.debug(`Adding new file (over limit): ${filePath}`);
|
|
45
46
|
const removedFilePath = existingFs.order.splice(0, 1)[0];
|
|
46
47
|
delete existingFs.fileContentMap[removedFilePath];
|
|
47
48
|
existingFs.fileContentMap[filePath] = updates[filePath];
|
|
@@ -57,15 +58,16 @@ export class ConversationFsModerator implements MessageModerator {
|
|
|
57
58
|
private logLevel: LogLevel = 'info';
|
|
58
59
|
|
|
59
60
|
constructor(logLevel?: LogLevel) {
|
|
60
|
-
if (logLevel)
|
|
61
|
+
if (logLevel) {
|
|
61
62
|
this.logLevel = logLevel;
|
|
63
|
+
}
|
|
62
64
|
}
|
|
63
65
|
|
|
64
66
|
observe(messages: ChatCompletionMessageParam[]): ChatCompletionMessageParam[] {
|
|
65
67
|
let conversationFileSystemMessageIndex: number = -1;
|
|
66
|
-
let conversationFileSystem: ConversationFs|undefined;
|
|
67
|
-
|
|
68
|
-
|
|
68
|
+
let conversationFileSystem: ConversationFs | undefined;
|
|
69
|
+
const readFilesFunctionCallMessageIndexes: number[] = [];
|
|
70
|
+
const writeFilesFunctionCallMessageIndexes: number[] = [];
|
|
69
71
|
const readFilesConsolidatedOutput: FileContentMap = {}; // newest version of file wins
|
|
70
72
|
for (let i = 0; i < messages.length; i++) {
|
|
71
73
|
const message = messages[i];
|
|
@@ -74,8 +76,9 @@ export class ConversationFsModerator implements MessageModerator {
|
|
|
74
76
|
try {
|
|
75
77
|
parsedContent = JSON.parse(message.content);
|
|
76
78
|
} catch (error) {}
|
|
77
|
-
if (!parsedContent || !parsedContent['fileSystem'])
|
|
79
|
+
if (!parsedContent || !parsedContent['fileSystem']) {
|
|
78
80
|
continue;
|
|
81
|
+
}
|
|
79
82
|
|
|
80
83
|
conversationFileSystem = parsedContent['fileSystem'];
|
|
81
84
|
conversationFileSystemMessageIndex = i;
|
|
@@ -83,14 +86,15 @@ export class ConversationFsModerator implements MessageModerator {
|
|
|
83
86
|
}
|
|
84
87
|
|
|
85
88
|
if (message.role == 'function' && message.name == 'readFiles' && message.content) {
|
|
86
|
-
let parsedContent: any|undefined;
|
|
89
|
+
let parsedContent: any | undefined;
|
|
87
90
|
try {
|
|
88
91
|
parsedContent = JSON.parse(message.content);
|
|
89
92
|
} catch (error) {}
|
|
90
|
-
if (!parsedContent)
|
|
93
|
+
if (!parsedContent) {
|
|
91
94
|
continue;
|
|
95
|
+
}
|
|
92
96
|
|
|
93
|
-
for (
|
|
97
|
+
for (const filePath of Object.keys(parsedContent)) {
|
|
94
98
|
readFilesConsolidatedOutput[filePath] = parsedContent[filePath];
|
|
95
99
|
}
|
|
96
100
|
|
|
@@ -103,19 +107,29 @@ export class ConversationFsModerator implements MessageModerator {
|
|
|
103
107
|
}
|
|
104
108
|
|
|
105
109
|
if (conversationFileSystem) {
|
|
106
|
-
conversationFileSystem = new ConversationFsFactory({ logLevel: this.logLevel }).merge(
|
|
110
|
+
conversationFileSystem = new ConversationFsFactory({ logLevel: this.logLevel }).merge(
|
|
111
|
+
conversationFileSystem,
|
|
112
|
+
readFilesConsolidatedOutput
|
|
113
|
+
);
|
|
107
114
|
const content = JSON.stringify({ fileSystem: conversationFileSystem });
|
|
108
115
|
messages[conversationFileSystemMessageIndex].content = content;
|
|
109
116
|
} else {
|
|
110
|
-
conversationFileSystem = {
|
|
111
|
-
|
|
117
|
+
conversationFileSystem = {
|
|
118
|
+
fileContentMap: readFilesConsolidatedOutput,
|
|
119
|
+
order: Object.keys(readFilesConsolidatedOutput),
|
|
120
|
+
};
|
|
121
|
+
messages.push({
|
|
122
|
+
role: 'system',
|
|
123
|
+
content: `Whenever you make a call to readFiles, the file content will be loaded into the { fileSystem } object in the message history. Do not respond with fileSystem's content in a message.`,
|
|
124
|
+
});
|
|
112
125
|
const content = JSON.stringify({ fileSystem: conversationFileSystem });
|
|
113
126
|
messages.push({ role: 'system', content });
|
|
114
127
|
}
|
|
115
128
|
|
|
116
|
-
const moderatedMessages = messages
|
|
117
|
-
|
|
118
|
-
|
|
129
|
+
const moderatedMessages = messages.filter(
|
|
130
|
+
(message, i) =>
|
|
131
|
+
!readFilesFunctionCallMessageIndexes.includes(i) && !writeFilesFunctionCallMessageIndexes.includes(i)
|
|
132
|
+
);
|
|
119
133
|
return moderatedMessages;
|
|
120
134
|
}
|
|
121
|
-
}
|
|
135
|
+
}
|
|
@@ -3,7 +3,15 @@ import { Function } from '../../Function';
|
|
|
3
3
|
import { searchFilesFunctionName } from '../keyword_to_files_index/KeywordToFilesIndexFunctions';
|
|
4
4
|
import { searchLibrariesFunctionName, searchPackagesFunctionName } from '../package/PackageFunctions';
|
|
5
5
|
import { ConversationFsModerator } from './ConversationFsModerator';
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
fsFunctions,
|
|
8
|
+
getRecentlyAccessedFilePathsFunction,
|
|
9
|
+
getRecentlyAccessedFilePathsFunctionName,
|
|
10
|
+
readFilesFunction,
|
|
11
|
+
readFilesFunctionName,
|
|
12
|
+
writeFilesFunction,
|
|
13
|
+
writeFilesFunctionName,
|
|
14
|
+
} from './FsFunctions';
|
|
7
15
|
|
|
8
16
|
export class ConversationFsModule implements ConversationModule {
|
|
9
17
|
private repoPath: string;
|
|
@@ -16,7 +24,7 @@ export class ConversationFsModule implements ConversationModule {
|
|
|
16
24
|
getName(): string {
|
|
17
25
|
return 'Conversation Fs';
|
|
18
26
|
}
|
|
19
|
-
|
|
27
|
+
|
|
20
28
|
getSystemMessages(): string[] {
|
|
21
29
|
return [
|
|
22
30
|
`Assume the current working directory is: ${this.repoPath} unless specified by the user`,
|
|
@@ -38,14 +46,12 @@ export class ConversationFsModule implements ConversationModule {
|
|
|
38
46
|
readFilesFunction(this),
|
|
39
47
|
writeFilesFunction(this),
|
|
40
48
|
getRecentlyAccessedFilePathsFunction(this),
|
|
41
|
-
...fsFunctions
|
|
49
|
+
...fsFunctions,
|
|
42
50
|
];
|
|
43
51
|
}
|
|
44
52
|
|
|
45
53
|
getMessageModerators() {
|
|
46
|
-
return [
|
|
47
|
-
new ConversationFsModerator(),
|
|
48
|
-
];
|
|
54
|
+
return [new ConversationFsModerator()];
|
|
49
55
|
}
|
|
50
56
|
|
|
51
57
|
pushRecentlyAccessedFilePath(filePaths: string[]) {
|
|
@@ -61,4 +67,4 @@ export class ConversationFsModuleFactory implements ConversationModuleFactory {
|
|
|
61
67
|
async createModule(repoPath: string): Promise<ConversationFsModule> {
|
|
62
68
|
return new ConversationFsModule(repoPath);
|
|
63
69
|
}
|
|
64
|
-
}
|
|
70
|
+
}
|
|
@@ -19,17 +19,15 @@ export function readFilesFunction(fsModule: ConversationFsModule) {
|
|
|
19
19
|
},
|
|
20
20
|
},
|
|
21
21
|
},
|
|
22
|
-
required: ['filePaths']
|
|
22
|
+
required: ['filePaths'],
|
|
23
23
|
},
|
|
24
24
|
},
|
|
25
25
|
call: async (params: { filePaths: string[] }) => {
|
|
26
26
|
fsModule.pushRecentlyAccessedFilePath(params.filePaths);
|
|
27
27
|
return await Fs.readFiles(params.filePaths);
|
|
28
28
|
},
|
|
29
|
-
instructions: [
|
|
30
|
-
|
|
31
|
-
],
|
|
32
|
-
}
|
|
29
|
+
instructions: [`To read files from the local file system, use the ${readFilesFunctionName} function`],
|
|
30
|
+
};
|
|
33
31
|
}
|
|
34
32
|
|
|
35
33
|
export const writeFilesFunctionName = 'writeFiles';
|
|
@@ -59,17 +57,15 @@ export function writeFilesFunction(fsModule: ConversationFsModule) {
|
|
|
59
57
|
},
|
|
60
58
|
},
|
|
61
59
|
},
|
|
62
|
-
required: ['files']
|
|
60
|
+
required: ['files'],
|
|
63
61
|
},
|
|
64
62
|
},
|
|
65
63
|
call: async (params: { files: File[] }) => {
|
|
66
|
-
fsModule.pushRecentlyAccessedFilePath(params.files.map(file => file.path));
|
|
64
|
+
fsModule.pushRecentlyAccessedFilePath(params.files.map((file) => file.path));
|
|
67
65
|
return await Fs.writeFiles(params.files);
|
|
68
66
|
},
|
|
69
|
-
instructions: [
|
|
70
|
-
|
|
71
|
-
],
|
|
72
|
-
}
|
|
67
|
+
instructions: [`To write files to the local file system, use the ${writeFilesFunctionName} function`],
|
|
68
|
+
};
|
|
73
69
|
}
|
|
74
70
|
|
|
75
71
|
export const getRecentlyAccessedFilePathsFunctionName = 'getRecentlyAccessedFilePaths';
|
|
@@ -85,7 +81,7 @@ export function getRecentlyAccessedFilePathsFunction(fsModule: ConversationFsMod
|
|
|
85
81
|
},
|
|
86
82
|
},
|
|
87
83
|
call: async () => fsModule.getRecentlyAccessedFilePaths(),
|
|
88
|
-
}
|
|
84
|
+
};
|
|
89
85
|
}
|
|
90
86
|
|
|
91
87
|
const createFolderFunctionName = 'createFolder';
|
|
@@ -101,14 +97,12 @@ const createFolderFunction: Function = {
|
|
|
101
97
|
description: 'Path of the new directory',
|
|
102
98
|
},
|
|
103
99
|
},
|
|
104
|
-
required: ['path']
|
|
100
|
+
required: ['path'],
|
|
105
101
|
},
|
|
106
102
|
},
|
|
107
103
|
call: async (params: { path: string }) => await Fs.createFolder(params.path),
|
|
108
|
-
instructions: [
|
|
109
|
-
|
|
110
|
-
],
|
|
111
|
-
}
|
|
104
|
+
instructions: [`To create a folder on the local file system, use the ${createFolderFunctionName} function`],
|
|
105
|
+
};
|
|
112
106
|
|
|
113
107
|
export const fileOrDirectoryExistsFunctionName = 'fileOrDirectoryExists';
|
|
114
108
|
export const fileOrDirectoryExistsFunction: Function = {
|
|
@@ -123,14 +117,14 @@ export const fileOrDirectoryExistsFunction: Function = {
|
|
|
123
117
|
description: 'Path of the file or directory',
|
|
124
118
|
},
|
|
125
119
|
},
|
|
126
|
-
required: ['path']
|
|
120
|
+
required: ['path'],
|
|
127
121
|
},
|
|
128
122
|
},
|
|
129
123
|
call: async (params: { path: string }) => await Fs.exists(params.path),
|
|
130
124
|
instructions: [
|
|
131
125
|
`To check if a file or folder exists on the local file system, use the ${fileOrDirectoryExistsFunctionName} function`,
|
|
132
126
|
],
|
|
133
|
-
}
|
|
127
|
+
};
|
|
134
128
|
|
|
135
129
|
export const getFilePathsMatchingGlobFunctionName = 'getFilePathsMatchingGlob';
|
|
136
130
|
const getFilePathsMatchingGlobFunction: Function = {
|
|
@@ -156,14 +150,13 @@ const getFilePathsMatchingGlobFunction: Function = {
|
|
|
156
150
|
},
|
|
157
151
|
},
|
|
158
152
|
},
|
|
159
|
-
required: ['dirPrefix', 'glob']
|
|
153
|
+
required: ['dirPrefix', 'glob'],
|
|
160
154
|
},
|
|
161
155
|
},
|
|
162
|
-
call: async (params: { dirPrefix: string
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
}
|
|
156
|
+
call: async (params: { dirPrefix: string; glob: string; globIgnorePatterns?: string[] }) =>
|
|
157
|
+
await Fs.getFilePathsMatchingGlob(params.dirPrefix, params.glob, params.globIgnorePatterns),
|
|
158
|
+
instructions: [`To get file paths matching a glob, use the ${getFilePathsMatchingGlobFunctionName} function`],
|
|
159
|
+
};
|
|
167
160
|
|
|
168
161
|
export const renameFunctionName = 'renameFileOrDirectory';
|
|
169
162
|
const renameFunction: Function = {
|
|
@@ -182,14 +175,12 @@ const renameFunction: Function = {
|
|
|
182
175
|
description: 'New name for the file or directory',
|
|
183
176
|
},
|
|
184
177
|
},
|
|
185
|
-
required: ['oldPath', 'newName']
|
|
178
|
+
required: ['oldPath', 'newName'],
|
|
186
179
|
},
|
|
187
180
|
},
|
|
188
|
-
call: async (params: { oldPath: string
|
|
189
|
-
instructions: [
|
|
190
|
-
|
|
191
|
-
],
|
|
192
|
-
}
|
|
181
|
+
call: async (params: { oldPath: string; newName: string }) => await Fs.rename(params.oldPath, params.newName),
|
|
182
|
+
instructions: [`To rename a file or directory, use the ${renameFunctionName} function`],
|
|
183
|
+
};
|
|
193
184
|
|
|
194
185
|
export const copyFunctionName = 'copyFileOrDirectory';
|
|
195
186
|
const copyFunction: Function = {
|
|
@@ -208,14 +199,13 @@ const copyFunction: Function = {
|
|
|
208
199
|
description: 'Destination path for the copied file or directory',
|
|
209
200
|
},
|
|
210
201
|
},
|
|
211
|
-
required: ['sourcePath', 'destinationPath']
|
|
202
|
+
required: ['sourcePath', 'destinationPath'],
|
|
212
203
|
},
|
|
213
204
|
},
|
|
214
|
-
call: async (params: { sourcePath: string
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
}
|
|
205
|
+
call: async (params: { sourcePath: string; destinationPath: string }) =>
|
|
206
|
+
await Fs.copy(params.sourcePath, params.destinationPath),
|
|
207
|
+
instructions: [`To copy a file or directory, use the ${copyFunctionName} function`],
|
|
208
|
+
};
|
|
219
209
|
|
|
220
210
|
export const moveFunctionName = 'moveFileOrDirectory';
|
|
221
211
|
const moveFunction: Function = {
|
|
@@ -234,14 +224,13 @@ const moveFunction: Function = {
|
|
|
234
224
|
description: 'Destination path for the moved file or directory',
|
|
235
225
|
},
|
|
236
226
|
},
|
|
237
|
-
required: ['sourcePath', 'destinationPath']
|
|
227
|
+
required: ['sourcePath', 'destinationPath'],
|
|
238
228
|
},
|
|
239
229
|
},
|
|
240
|
-
call: async (params: { sourcePath: string
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
}
|
|
230
|
+
call: async (params: { sourcePath: string; destinationPath: string }) =>
|
|
231
|
+
await Fs.move(params.sourcePath, params.destinationPath),
|
|
232
|
+
instructions: [`To move a file or directory, use the ${moveFunctionName} function`],
|
|
233
|
+
};
|
|
245
234
|
|
|
246
235
|
export const fsFunctions: Function[] = [
|
|
247
236
|
createFolderFunction,
|
|
@@ -250,4 +239,4 @@ export const fsFunctions: Function[] = [
|
|
|
250
239
|
renameFunction,
|
|
251
240
|
copyFunction,
|
|
252
241
|
moveFunction,
|
|
253
|
-
]
|
|
242
|
+
];
|
package/src/fs/git/GitModule.ts
CHANGED
|
@@ -22,9 +22,7 @@ export class GitModule implements ConversationModule {
|
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
getFunctions(): Function[] {
|
|
25
|
-
return [
|
|
26
|
-
...gitFunctions,
|
|
27
|
-
];
|
|
25
|
+
return [...gitFunctions];
|
|
28
26
|
}
|
|
29
27
|
|
|
30
28
|
getMessageModerators() {
|
|
@@ -36,4 +34,4 @@ export class GitModuleFactory implements ConversationModuleFactory {
|
|
|
36
34
|
async createModule(repoPath: string): Promise<GitModule> {
|
|
37
35
|
return new GitModule(repoPath);
|
|
38
36
|
}
|
|
39
|
-
}
|
|
37
|
+
}
|