@proteinjs/conversation 1.0.5 → 1.0.7
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/.prettierrc +8 -0
- package/CHANGELOG.md +7 -4
- package/LICENSE +21 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +40 -28
- package/dist/src/CodegenConversation.d.ts +11 -11
- package/dist/src/CodegenConversation.d.ts.map +1 -1
- package/dist/src/CodegenConversation.js +294 -180
- package/dist/src/CodegenConversation.js.map +1 -1
- package/dist/src/Conversation.d.ts +52 -49
- package/dist/src/Conversation.d.ts.map +1 -1
- package/dist/src/Conversation.js +480 -274
- package/dist/src/Conversation.js.map +1 -1
- package/dist/src/ConversationModule.d.ts +6 -6
- package/dist/src/ConversationModule.js +3 -3
- package/dist/src/Function.d.ts +4 -4
- package/dist/src/Function.d.ts.map +1 -1
- package/dist/src/Function.js +3 -3
- package/dist/src/OpenAi.d.ts +42 -10
- package/dist/src/OpenAi.d.ts.map +1 -1
- package/dist/src/OpenAi.js +496 -289
- package/dist/src/OpenAi.js.map +1 -1
- package/dist/src/Paragraph.d.ts +4 -4
- package/dist/src/Paragraph.d.ts.map +1 -1
- package/dist/src/Paragraph.js +17 -16
- package/dist/src/Paragraph.js.map +1 -1
- package/dist/src/Sentence.d.ts +4 -4
- package/dist/src/Sentence.d.ts.map +1 -1
- package/dist/src/Sentence.js +21 -19
- package/dist/src/Sentence.js.map +1 -1
- package/dist/src/code_template/Code.d.ts +15 -15
- package/dist/src/code_template/Code.d.ts.map +1 -1
- package/dist/src/code_template/Code.js +167 -69
- package/dist/src/code_template/Code.js.map +1 -1
- package/dist/src/code_template/CodeTemplate.d.ts +11 -11
- package/dist/src/code_template/CodeTemplate.d.ts.map +1 -1
- package/dist/src/code_template/CodeTemplate.js +169 -79
- package/dist/src/code_template/CodeTemplate.js.map +1 -1
- package/dist/src/code_template/CodeTemplateModule.d.ts +6 -6
- package/dist/src/code_template/CodeTemplateModule.js +28 -26
- package/dist/src/code_template/Repo.d.ts +34 -38
- package/dist/src/code_template/Repo.d.ts.map +1 -1
- package/dist/src/code_template/Repo.js +291 -191
- package/dist/src/code_template/Repo.js.map +1 -1
- package/dist/src/fs/conversation_fs/ConversationFsModerator.d.ts +12 -12
- package/dist/src/fs/conversation_fs/ConversationFsModerator.d.ts.map +1 -1
- package/dist/src/fs/conversation_fs/ConversationFsModerator.js +111 -98
- package/dist/src/fs/conversation_fs/ConversationFsModerator.js.map +1 -1
- package/dist/src/fs/conversation_fs/ConversationFsModule.d.ts +11 -11
- package/dist/src/fs/conversation_fs/ConversationFsModule.d.ts.map +1 -1
- package/dist/src/fs/conversation_fs/ConversationFsModule.js +204 -99
- package/dist/src/fs/conversation_fs/ConversationFsModule.js.map +1 -1
- package/dist/src/fs/conversation_fs/FsFunctions.d.ts +58 -62
- package/dist/src/fs/conversation_fs/FsFunctions.d.ts.map +1 -1
- package/dist/src/fs/conversation_fs/FsFunctions.js +414 -266
- package/dist/src/fs/conversation_fs/FsFunctions.js.map +1 -1
- package/dist/src/fs/git/GitModule.d.ts +8 -8
- package/dist/src/fs/git/GitModule.d.ts.map +1 -1
- package/dist/src/fs/git/GitModule.js +163 -74
- package/dist/src/fs/git/GitModule.js.map +1 -1
- package/dist/src/fs/keyword_to_files_index/KeywordToFilesIndexFunctions.d.ts +16 -18
- package/dist/src/fs/keyword_to_files_index/KeywordToFilesIndexFunctions.d.ts.map +1 -1
- package/dist/src/fs/keyword_to_files_index/KeywordToFilesIndexFunctions.js +158 -58
- package/dist/src/fs/keyword_to_files_index/KeywordToFilesIndexFunctions.js.map +1 -1
- package/dist/src/fs/keyword_to_files_index/KeywordToFilesIndexModule.d.ts +27 -26
- package/dist/src/fs/keyword_to_files_index/KeywordToFilesIndexModule.d.ts.map +1 -1
- package/dist/src/fs/keyword_to_files_index/KeywordToFilesIndexModule.js +234 -133
- package/dist/src/fs/keyword_to_files_index/KeywordToFilesIndexModule.js.map +1 -1
- package/dist/src/fs/package/PackageFunctions.d.ts +54 -60
- package/dist/src/fs/package/PackageFunctions.d.ts.map +1 -1
- package/dist/src/fs/package/PackageFunctions.js +366 -223
- package/dist/src/fs/package/PackageFunctions.js.map +1 -1
- package/dist/src/fs/package/PackageModule.d.ts +24 -24
- package/dist/src/fs/package/PackageModule.d.ts.map +1 -1
- package/dist/src/fs/package/PackageModule.js +292 -163
- package/dist/src/fs/package/PackageModule.js.map +1 -1
- package/dist/src/history/MessageHistory.d.ts +12 -12
- package/dist/src/history/MessageHistory.d.ts.map +1 -1
- package/dist/src/history/MessageHistory.js +52 -43
- package/dist/src/history/MessageHistory.js.map +1 -1
- package/dist/src/history/MessageModerator.d.ts +2 -2
- package/dist/src/history/MessageModerator.js +3 -3
- package/dist/src/template/ConversationTemplate.d.ts +8 -8
- package/dist/src/template/ConversationTemplate.d.ts.map +1 -1
- package/dist/src/template/ConversationTemplate.js +3 -3
- package/dist/src/template/ConversationTemplateFunctions.d.ts +33 -35
- package/dist/src/template/ConversationTemplateFunctions.d.ts.map +1 -1
- package/dist/src/template/ConversationTemplateFunctions.js +176 -75
- package/dist/src/template/ConversationTemplateFunctions.js.map +1 -1
- package/dist/src/template/ConversationTemplateModule.d.ts +51 -48
- package/dist/src/template/ConversationTemplateModule.d.ts.map +1 -1
- package/dist/src/template/ConversationTemplateModule.js +211 -114
- package/dist/src/template/ConversationTemplateModule.js.map +1 -1
- package/dist/src/template/createApp/CreateAppTemplate.d.ts +1 -1
- package/dist/src/template/createApp/CreateAppTemplate.js +151 -59
- package/dist/src/template/createCode/CreateCodeConversationTemplate.d.ts +1 -1
- package/dist/src/template/createCode/CreateCodeConversationTemplate.d.ts.map +1 -1
- package/dist/src/template/createCode/CreateCodeConversationTemplate.js +183 -74
- package/dist/src/template/createCode/CreateCodeConversationTemplate.js.map +1 -1
- package/dist/src/template/createPackage/CreatePackageConversationTemplate.d.ts +1 -1
- package/dist/src/template/createPackage/CreatePackageConversationTemplate.d.ts.map +1 -1
- package/dist/src/template/createPackage/CreatePackageConversationTemplate.js +174 -84
- package/dist/src/template/createPackage/CreatePackageConversationTemplate.js.map +1 -1
- package/dist/src/template/createPackage/tsconfig.json +11 -11
- package/dist/test/createKeywordFilesIndex.test.d.ts +1 -1
- package/dist/test/createKeywordFilesIndex.test.js +132 -41
- package/dist/test/createKeywordFilesIndex.test.js.map +1 -1
- package/dist/test/openai/openai.generateList.test.d.ts +1 -1
- package/dist/test/openai/openai.generateList.test.js +136 -47
- package/dist/test/openai/openai.generateList.test.js.map +1 -1
- package/dist/test/openai/openai.parseCodeFromMarkdown.test.d.ts +1 -1
- package/dist/test/openai/openai.parseCodeFromMarkdown.test.js +15 -10
- package/dist/test/openai/openai.parseCodeFromMarkdown.test.js.map +1 -1
- package/dist/test/repo/repo.test.d.ts +1 -1
- package/dist/test/repo/repo.test.js +127 -38
- package/dist/test/repo/repo.test.js.map +1 -1
- package/jest.config.js +2 -2
- package/package.json +11 -5
- 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
package/src/OpenAi.ts
CHANGED
|
@@ -7,26 +7,38 @@ import { MessageHistory } from './history/MessageHistory';
|
|
|
7
7
|
import { TiktokenModel } from 'tiktoken';
|
|
8
8
|
|
|
9
9
|
function delay(ms: number) {
|
|
10
|
-
return new Promise(resolve => setTimeout(resolve, ms));
|
|
10
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
export const DEFAULT_MODEL: TiktokenModel = 'gpt-3.5-turbo';
|
|
14
14
|
export class OpenAi {
|
|
15
|
-
static async generateResponse(
|
|
15
|
+
static async generateResponse(
|
|
16
|
+
messages: string[],
|
|
17
|
+
model?: string,
|
|
18
|
+
history?: MessageHistory,
|
|
19
|
+
functions?: Function[],
|
|
20
|
+
messageModerators?: MessageModerator[],
|
|
21
|
+
logLevel: LogLevel = 'info'
|
|
22
|
+
): Promise<string> {
|
|
16
23
|
const logger = new Logger('OpenAi.generateResponse', logLevel);
|
|
17
|
-
const messageParams: ChatCompletionMessageParam[] = messages.map(message => {
|
|
18
|
-
|
|
24
|
+
const messageParams: ChatCompletionMessageParam[] = messages.map((message) => {
|
|
25
|
+
return { role: 'user', content: message };
|
|
26
|
+
});
|
|
27
|
+
if (history) {
|
|
19
28
|
history.push(messageParams);
|
|
29
|
+
}
|
|
20
30
|
let messageParamsWithHistory = history ? history : new MessageHistory().push(messageParams);
|
|
21
|
-
if (messageModerators)
|
|
31
|
+
if (messageModerators) {
|
|
22
32
|
messageParamsWithHistory = OpenAi.moderateHistory(messageParamsWithHistory, messageModerators);
|
|
33
|
+
}
|
|
23
34
|
const response = await OpenAi.executeRequest(messageParamsWithHistory, logLevel, functions, model);
|
|
24
35
|
const responseMessage = response.choices[0].message;
|
|
25
36
|
if (responseMessage.function_call) {
|
|
26
37
|
messageParamsWithHistory.push([responseMessage]);
|
|
27
38
|
const functionReturnMessage = await this.callFunction(logLevel, responseMessage.function_call, functions);
|
|
28
|
-
if (functionReturnMessage)
|
|
29
|
-
messageParamsWithHistory.push([functionReturnMessage])
|
|
39
|
+
if (functionReturnMessage) {
|
|
40
|
+
messageParamsWithHistory.push([functionReturnMessage]);
|
|
41
|
+
}
|
|
30
42
|
return await this.generateResponse([], model, messageParamsWithHistory, functions, messageModerators, logLevel);
|
|
31
43
|
}
|
|
32
44
|
|
|
@@ -41,50 +53,61 @@ export class OpenAi {
|
|
|
41
53
|
}
|
|
42
54
|
|
|
43
55
|
private static moderateHistory(history: MessageHistory, messageModerators: MessageModerator[]) {
|
|
44
|
-
for (
|
|
56
|
+
for (const messageModerator of messageModerators) {
|
|
45
57
|
history.setMessages(messageModerator.observe(history.getMessages()));
|
|
58
|
+
}
|
|
46
59
|
|
|
47
60
|
return history;
|
|
48
61
|
}
|
|
49
62
|
|
|
50
|
-
private static async executeRequest(
|
|
63
|
+
private static async executeRequest(
|
|
64
|
+
messageParamsWithHistory: MessageHistory,
|
|
65
|
+
logLevel: LogLevel,
|
|
66
|
+
functions?: Function[],
|
|
67
|
+
model?: string
|
|
68
|
+
): Promise<ChatCompletion> {
|
|
51
69
|
const logger = new Logger('OpenAi.executeRequest', logLevel);
|
|
52
70
|
const openaiApi = new OpenAIApi();
|
|
53
71
|
let response: ChatCompletion;
|
|
54
72
|
try {
|
|
55
73
|
const latestMessage = messageParamsWithHistory.getMessages()[messageParamsWithHistory.getMessages().length - 1];
|
|
56
|
-
if (latestMessage.content)
|
|
74
|
+
if (latestMessage.content) {
|
|
57
75
|
logger.info(`Sending request: ${latestMessage.content}`);
|
|
58
|
-
else if (latestMessage.role == 'function')
|
|
76
|
+
} else if (latestMessage.role == 'function') {
|
|
59
77
|
logger.info(`Sending request: returning output of ${latestMessage.name} function`);
|
|
60
|
-
else
|
|
78
|
+
} else {
|
|
61
79
|
logger.info(`Sending request`);
|
|
80
|
+
}
|
|
62
81
|
logger.debug(`Sending messages: ${JSON.stringify(messageParamsWithHistory.getMessages(), null, 2)}`, true);
|
|
63
82
|
response = await openaiApi.chat.completions.create({
|
|
64
83
|
model: model ? model : DEFAULT_MODEL,
|
|
65
84
|
temperature: 0,
|
|
66
85
|
messages: messageParamsWithHistory.getMessages(),
|
|
67
|
-
functions: functions?.map(f => f.definition),
|
|
86
|
+
functions: functions?.map((f) => f.definition),
|
|
68
87
|
});
|
|
69
88
|
const responseMessage = response.choices[0].message;
|
|
70
|
-
if (responseMessage.content)
|
|
89
|
+
if (responseMessage.content) {
|
|
71
90
|
logger.info(`Received response: ${responseMessage.content}`);
|
|
72
|
-
else if (responseMessage.function_call)
|
|
91
|
+
} else if (responseMessage.function_call) {
|
|
73
92
|
logger.info(`Received response: call ${responseMessage.function_call.name} function`);
|
|
74
|
-
else
|
|
93
|
+
} else {
|
|
75
94
|
logger.info(`Received response`);
|
|
76
|
-
|
|
95
|
+
}
|
|
96
|
+
if (response.usage) {
|
|
77
97
|
logger.info(JSON.stringify(response.usage));
|
|
78
|
-
else
|
|
98
|
+
} else {
|
|
79
99
|
logger.info(JSON.stringify(`Usage data missing`));
|
|
80
|
-
|
|
100
|
+
}
|
|
101
|
+
} catch (error: any) {
|
|
81
102
|
logger.info(`Received error response, error type: ${error.type}`);
|
|
82
103
|
if (typeof error.status !== 'undefined' && error.status == 429) {
|
|
83
104
|
if (error.type == 'tokens' && typeof error.headers['x-ratelimit-reset-tokens'] === 'string') {
|
|
84
105
|
const waitTime = parseInt(error.headers['x-ratelimit-reset-tokens']);
|
|
85
106
|
const remainingTokens = error.headers['x-ratelimit-remaining-tokens'];
|
|
86
107
|
const delayMs = 15000;
|
|
87
|
-
logger.warn(
|
|
108
|
+
logger.warn(
|
|
109
|
+
`Waiting to retry in ${delayMs / 1000}s, token reset in: ${waitTime}s, remaining tokens: ${remainingTokens}`
|
|
110
|
+
);
|
|
88
111
|
await delay(delayMs);
|
|
89
112
|
return await OpenAi.executeRequest(messageParamsWithHistory, logLevel, functions, model);
|
|
90
113
|
}
|
|
@@ -96,21 +119,25 @@ export class OpenAi {
|
|
|
96
119
|
return response;
|
|
97
120
|
}
|
|
98
121
|
|
|
99
|
-
private static async callFunction(
|
|
122
|
+
private static async callFunction(
|
|
123
|
+
logLevel: LogLevel,
|
|
124
|
+
functionCall: ChatCompletionMessage.FunctionCall,
|
|
125
|
+
functions?: Function[]
|
|
126
|
+
): Promise<ChatCompletionMessageParam | undefined> {
|
|
100
127
|
const logger = new Logger('OpenAi.callFunction', logLevel);
|
|
101
128
|
if (!functions) {
|
|
102
129
|
const warning = `Assistant attempted to call a function when no functions were provided`;
|
|
103
130
|
logger.warn(warning);
|
|
104
|
-
const message: ChatCompletionMessageParam = { role: 'user', content: warning }
|
|
131
|
+
const message: ChatCompletionMessageParam = { role: 'user', content: warning };
|
|
105
132
|
return message;
|
|
106
133
|
}
|
|
107
134
|
|
|
108
135
|
functionCall.name = functionCall.name.split('.').pop() as string;
|
|
109
|
-
const f = functions.find(f => f.definition.name === functionCall.name);
|
|
136
|
+
const f = functions.find((f) => f.definition.name === functionCall.name);
|
|
110
137
|
if (!f) {
|
|
111
138
|
const warning = `Assistant attempted to call nonexistent function: ${functionCall.name}`;
|
|
112
139
|
logger.warn(warning);
|
|
113
|
-
const message: ChatCompletionMessageParam = { role: 'user', content: warning }
|
|
140
|
+
const message: ChatCompletionMessageParam = { role: 'user', content: warning };
|
|
114
141
|
return message;
|
|
115
142
|
}
|
|
116
143
|
|
|
@@ -118,46 +145,74 @@ export class OpenAi {
|
|
|
118
145
|
try {
|
|
119
146
|
logger.info(`Assistant calling function: ${f.definition.name}(${functionCall.arguments})`);
|
|
120
147
|
returnObject = JSON.stringify(await f.call(JSON.parse(functionCall.arguments)));
|
|
121
|
-
logger.info(
|
|
148
|
+
logger.info(
|
|
149
|
+
`Assistant called function: ${f.definition.name}(${functionCall.arguments}) => ${returnObject}`,
|
|
150
|
+
1000
|
|
151
|
+
);
|
|
122
152
|
} catch (error: any) {
|
|
123
153
|
logger.error(error.message);
|
|
124
154
|
}
|
|
125
155
|
|
|
126
|
-
if (!returnObject)
|
|
156
|
+
if (!returnObject) {
|
|
127
157
|
return;
|
|
158
|
+
}
|
|
128
159
|
|
|
129
160
|
return {
|
|
130
|
-
role: 'function',
|
|
131
|
-
name: f.definition.name,
|
|
161
|
+
role: 'function',
|
|
162
|
+
name: f.definition.name,
|
|
132
163
|
content: returnObject,
|
|
133
164
|
};
|
|
134
165
|
}
|
|
135
166
|
|
|
136
|
-
static async generateCode(
|
|
167
|
+
static async generateCode(
|
|
168
|
+
messages: string[],
|
|
169
|
+
model?: string,
|
|
170
|
+
history?: MessageHistory,
|
|
171
|
+
functions?: Function[],
|
|
172
|
+
messageModerators?: MessageModerator[],
|
|
173
|
+
includeSystemMessages: boolean = true,
|
|
174
|
+
logLevel: LogLevel = 'info'
|
|
175
|
+
) {
|
|
137
176
|
const systemMessages: ChatCompletionMessageParam[] = [
|
|
138
|
-
{
|
|
177
|
+
{
|
|
178
|
+
role: 'system',
|
|
179
|
+
content: 'Return only the code and exclude example usage, markdown, explanations, comments and notes.',
|
|
180
|
+
},
|
|
139
181
|
{ role: 'system', content: `Write code in typescript.` },
|
|
140
182
|
{ role: 'system', content: `Declare explicit types for all function parameters.` },
|
|
141
183
|
{ role: 'system', content: 'Export all functions and objects generated.' },
|
|
142
184
|
{ role: 'system', content: 'Do not omit function implementations.' },
|
|
143
185
|
];
|
|
144
|
-
const resolvedHistory = history
|
|
145
|
-
includeSystemMessages
|
|
146
|
-
history.push(systemMessages)
|
|
147
|
-
:
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
new MessageHistory().push(systemMessages)
|
|
152
|
-
:
|
|
153
|
-
undefined
|
|
154
|
-
;
|
|
186
|
+
const resolvedHistory = history
|
|
187
|
+
? includeSystemMessages
|
|
188
|
+
? history.push(systemMessages)
|
|
189
|
+
: history
|
|
190
|
+
: includeSystemMessages
|
|
191
|
+
? new MessageHistory().push(systemMessages)
|
|
192
|
+
: undefined;
|
|
155
193
|
const code = await this.generateResponse(messages, model, resolvedHistory, functions, messageModerators, logLevel);
|
|
156
194
|
return this.parseCodeFromMarkdown(code);
|
|
157
195
|
}
|
|
158
196
|
|
|
159
|
-
static async updateCode(
|
|
160
|
-
|
|
197
|
+
static async updateCode(
|
|
198
|
+
code: string,
|
|
199
|
+
description: string,
|
|
200
|
+
model?: string,
|
|
201
|
+
history?: MessageHistory,
|
|
202
|
+
functions?: Function[],
|
|
203
|
+
messageModerators?: MessageModerator[],
|
|
204
|
+
includeSystemMessages: boolean = true,
|
|
205
|
+
logLevel: LogLevel = 'info'
|
|
206
|
+
) {
|
|
207
|
+
return await this.generateCode(
|
|
208
|
+
[this.updateCodeDescription(code, description)],
|
|
209
|
+
model,
|
|
210
|
+
history,
|
|
211
|
+
functions,
|
|
212
|
+
messageModerators,
|
|
213
|
+
includeSystemMessages,
|
|
214
|
+
logLevel
|
|
215
|
+
);
|
|
161
216
|
}
|
|
162
217
|
|
|
163
218
|
static updateCodeDescription(code: string, description: string) {
|
|
@@ -165,22 +220,25 @@ export class OpenAi {
|
|
|
165
220
|
}
|
|
166
221
|
|
|
167
222
|
static parseCodeFromMarkdown(code: string) {
|
|
168
|
-
if (!code.match(/```([\s\S]+?)```/g))
|
|
223
|
+
if (!code.match(/```([\s\S]+?)```/g)) {
|
|
169
224
|
return code;
|
|
225
|
+
}
|
|
170
226
|
|
|
171
227
|
const filteredLines: string[] = [];
|
|
172
228
|
let inCodeBlock = false;
|
|
173
|
-
for (
|
|
229
|
+
for (const line of code.split('\n')) {
|
|
174
230
|
if (line.startsWith('```')) {
|
|
175
231
|
inCodeBlock = !inCodeBlock;
|
|
176
|
-
if (!inCodeBlock)
|
|
232
|
+
if (!inCodeBlock) {
|
|
177
233
|
filteredLines.push('');
|
|
178
|
-
|
|
234
|
+
}
|
|
235
|
+
|
|
179
236
|
continue;
|
|
180
237
|
}
|
|
181
238
|
|
|
182
|
-
if (inCodeBlock)
|
|
239
|
+
if (inCodeBlock) {
|
|
183
240
|
filteredLines.push(line);
|
|
241
|
+
}
|
|
184
242
|
}
|
|
185
243
|
|
|
186
244
|
// remove the last '' that will become a \n
|
|
@@ -190,23 +248,30 @@ export class OpenAi {
|
|
|
190
248
|
return filteredLines.join('\n');
|
|
191
249
|
}
|
|
192
250
|
|
|
193
|
-
static async generateList(
|
|
251
|
+
static async generateList(
|
|
252
|
+
messages: string[],
|
|
253
|
+
model?: string,
|
|
254
|
+
history?: MessageHistory,
|
|
255
|
+
functions?: Function[],
|
|
256
|
+
messageModerators?: MessageModerator[],
|
|
257
|
+
includeSystemMessages: boolean = true,
|
|
258
|
+
logLevel: LogLevel = 'info'
|
|
259
|
+
): Promise<string[]> {
|
|
194
260
|
const systemMessages: ChatCompletionMessageParam[] = [
|
|
195
|
-
{
|
|
261
|
+
{
|
|
262
|
+
role: 'system',
|
|
263
|
+
content: 'Return only the list and exclude example usage, markdown and all explanations, comments and notes.',
|
|
264
|
+
},
|
|
196
265
|
{ role: 'system', content: 'Separate each item in the list by a ;' },
|
|
197
266
|
];
|
|
198
|
-
const resolvedHistory = history
|
|
199
|
-
includeSystemMessages
|
|
200
|
-
history.push(systemMessages)
|
|
201
|
-
:
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
new MessageHistory().push(systemMessages)
|
|
206
|
-
:
|
|
207
|
-
undefined
|
|
208
|
-
;
|
|
267
|
+
const resolvedHistory = history
|
|
268
|
+
? includeSystemMessages
|
|
269
|
+
? history.push(systemMessages)
|
|
270
|
+
: history
|
|
271
|
+
: includeSystemMessages
|
|
272
|
+
? new MessageHistory().push(systemMessages)
|
|
273
|
+
: undefined;
|
|
209
274
|
const list = await this.generateResponse(messages, model, resolvedHistory, functions, messageModerators, logLevel);
|
|
210
|
-
return list.split(';').map(item => item.trim());
|
|
275
|
+
return list.split(';').map((item) => item.trim());
|
|
211
276
|
}
|
|
212
|
-
}
|
|
277
|
+
}
|
package/src/Paragraph.ts
CHANGED
package/src/Sentence.ts
CHANGED
|
@@ -8,13 +8,15 @@ export class Sentence {
|
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
toString(): string {
|
|
11
|
-
if (this.lines.length == 0)
|
|
11
|
+
if (this.lines.length == 0) {
|
|
12
12
|
return '';
|
|
13
|
+
}
|
|
13
14
|
|
|
14
15
|
let sentence = this.lines.join(', ');
|
|
15
|
-
if (sentence.lastIndexOf('.') !=
|
|
16
|
+
if (sentence.lastIndexOf('.') != sentence.length - 1) {
|
|
16
17
|
sentence += '.';
|
|
18
|
+
}
|
|
17
19
|
|
|
18
20
|
return sentence;
|
|
19
21
|
}
|
|
20
|
-
}
|
|
22
|
+
}
|
|
@@ -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
|
}
|