@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
package/src/Conversation.ts
CHANGED
|
@@ -10,7 +10,7 @@ import { TiktokenModel, encoding_for_model } from 'tiktoken';
|
|
|
10
10
|
import { searchLibrariesFunctionName } from './fs/package/PackageFunctions';
|
|
11
11
|
|
|
12
12
|
export type ConversationParams = {
|
|
13
|
-
name: string
|
|
13
|
+
name: string;
|
|
14
14
|
modules?: ConversationModule[];
|
|
15
15
|
logLevel?: LogLevel;
|
|
16
16
|
limits?: {
|
|
@@ -18,7 +18,7 @@ export type ConversationParams = {
|
|
|
18
18
|
maxMessagesInHistory?: number;
|
|
19
19
|
tokenLimit?: number;
|
|
20
20
|
};
|
|
21
|
-
}
|
|
21
|
+
};
|
|
22
22
|
|
|
23
23
|
export class Conversation {
|
|
24
24
|
private tokenLimit = 3000;
|
|
@@ -33,26 +33,30 @@ export class Conversation {
|
|
|
33
33
|
|
|
34
34
|
constructor(params: ConversationParams) {
|
|
35
35
|
this.params = params;
|
|
36
|
-
this.history = new MessageHistory({
|
|
36
|
+
this.history = new MessageHistory({
|
|
37
|
+
maxMessages: params.limits?.maxMessagesInHistory,
|
|
38
|
+
enforceMessageLimit: params.limits?.enforceLimits,
|
|
39
|
+
});
|
|
37
40
|
this.logger = new Logger(params.name, params.logLevel);
|
|
38
41
|
|
|
39
|
-
if (params.modules)
|
|
42
|
+
if (params.modules) {
|
|
40
43
|
this.addModules(params.modules);
|
|
44
|
+
}
|
|
41
45
|
|
|
42
46
|
if (typeof params.limits?.enforceLimits === 'undefined' || params.limits.enforceLimits) {
|
|
43
|
-
this.addFunctions('Conversation', [
|
|
44
|
-
summarizeConversationHistoryFunction(this),
|
|
45
|
-
]);
|
|
47
|
+
this.addFunctions('Conversation', [summarizeConversationHistoryFunction(this)]);
|
|
46
48
|
}
|
|
47
49
|
|
|
48
|
-
if (params.limits?.tokenLimit)
|
|
50
|
+
if (params.limits?.tokenLimit) {
|
|
49
51
|
this.tokenLimit = params.limits.tokenLimit;
|
|
52
|
+
}
|
|
50
53
|
}
|
|
51
54
|
|
|
52
55
|
private addModules(modules: ConversationModule[]) {
|
|
53
|
-
for (
|
|
54
|
-
if (module.getSystemMessages().length < 1)
|
|
56
|
+
for (const module of modules) {
|
|
57
|
+
if (module.getSystemMessages().length < 1) {
|
|
55
58
|
continue;
|
|
59
|
+
}
|
|
56
60
|
|
|
57
61
|
this.addSystemMessagesToHistory([
|
|
58
62
|
`The following are instructions from the ${module.getName()} module: ${module.getSystemMessages().join('. ')}`,
|
|
@@ -66,10 +70,11 @@ export class Conversation {
|
|
|
66
70
|
this.functions.push(...functions);
|
|
67
71
|
let functionInstructions = `The following are instructions from functions in the ${moduleName} module:`;
|
|
68
72
|
let functionInstructionsAdded = false;
|
|
69
|
-
for (
|
|
73
|
+
for (const f of functions) {
|
|
70
74
|
if (f.instructions) {
|
|
71
|
-
if (!f.instructions || f.instructions.length < 1)
|
|
75
|
+
if (!f.instructions || f.instructions.length < 1) {
|
|
72
76
|
continue;
|
|
77
|
+
}
|
|
73
78
|
|
|
74
79
|
functionInstructionsAdded = true;
|
|
75
80
|
const instructionsParagraph = f.instructions.join('. ');
|
|
@@ -77,8 +82,9 @@ export class Conversation {
|
|
|
77
82
|
}
|
|
78
83
|
}
|
|
79
84
|
|
|
80
|
-
if (!functionInstructionsAdded)
|
|
85
|
+
if (!functionInstructionsAdded) {
|
|
81
86
|
return;
|
|
87
|
+
}
|
|
82
88
|
|
|
83
89
|
this.addSystemMessagesToHistory([functionInstructions]);
|
|
84
90
|
}
|
|
@@ -88,21 +94,37 @@ export class Conversation {
|
|
|
88
94
|
}
|
|
89
95
|
|
|
90
96
|
private async enforceTokenLimit(messages: string[], model?: TiktokenModel) {
|
|
91
|
-
if (this.params.limits?.enforceLimits === false)
|
|
97
|
+
if (this.params.limits?.enforceLimits === false) {
|
|
92
98
|
return;
|
|
93
|
-
|
|
99
|
+
}
|
|
100
|
+
|
|
94
101
|
const resolvedModel = model ? model : DEFAULT_MODEL;
|
|
95
102
|
const encoder = encoding_for_model(resolvedModel);
|
|
96
103
|
const conversation = this.history.toString() + messages.join('. ');
|
|
97
104
|
const encoded = encoder.encode(conversation);
|
|
98
105
|
console.log(`current tokens: ${encoded.length}`);
|
|
99
|
-
if (encoded.length < this.tokenLimit)
|
|
106
|
+
if (encoded.length < this.tokenLimit) {
|
|
100
107
|
return;
|
|
108
|
+
}
|
|
101
109
|
|
|
102
110
|
const summarizeConversationRequest = `First, call the ${summarizeConversationHistoryFunctionName} function`;
|
|
103
|
-
await OpenAi.generateResponse(
|
|
111
|
+
await OpenAi.generateResponse(
|
|
112
|
+
[summarizeConversationRequest],
|
|
113
|
+
model,
|
|
114
|
+
this.history,
|
|
115
|
+
this.functions,
|
|
116
|
+
this.messageModerators,
|
|
117
|
+
this.params.logLevel
|
|
118
|
+
);
|
|
104
119
|
const referenceSummaryRequest = `If there's a file mentioned in the conversation summary, find and read the file to better respond to my next request. If that doesn't find anything, call the ${searchLibrariesFunctionName} function on other keywords in the conversation summary to find a file to read`;
|
|
105
|
-
await OpenAi.generateResponse(
|
|
120
|
+
await OpenAi.generateResponse(
|
|
121
|
+
[referenceSummaryRequest],
|
|
122
|
+
model,
|
|
123
|
+
this.history,
|
|
124
|
+
this.functions,
|
|
125
|
+
this.messageModerators,
|
|
126
|
+
this.params.logLevel
|
|
127
|
+
);
|
|
106
128
|
}
|
|
107
129
|
|
|
108
130
|
summarizeConversationHistory(summary: string) {
|
|
@@ -116,7 +138,9 @@ export class Conversation {
|
|
|
116
138
|
}
|
|
117
139
|
|
|
118
140
|
addSystemMessagesToHistory(messages: string[], unshift = false) {
|
|
119
|
-
const chatCompletions: ChatCompletionMessageParam[] = messages.map(message => {
|
|
141
|
+
const chatCompletions: ChatCompletionMessageParam[] = messages.map((message) => {
|
|
142
|
+
return { role: 'system', content: message };
|
|
143
|
+
});
|
|
120
144
|
if (unshift) {
|
|
121
145
|
this.history.getMessages().unshift(...chatCompletions);
|
|
122
146
|
this.history.prune();
|
|
@@ -128,40 +152,66 @@ export class Conversation {
|
|
|
128
152
|
}
|
|
129
153
|
|
|
130
154
|
addAssistantMessagesToHistory(messages: string[], unshift = false) {
|
|
131
|
-
const chatCompletions: ChatCompletionMessageParam[] = messages.map(message => {
|
|
155
|
+
const chatCompletions: ChatCompletionMessageParam[] = messages.map((message) => {
|
|
156
|
+
return { role: 'assistant', content: message };
|
|
157
|
+
});
|
|
132
158
|
if (unshift) {
|
|
133
159
|
this.history.getMessages().unshift(...chatCompletions);
|
|
134
160
|
this.history.prune();
|
|
135
|
-
} else
|
|
161
|
+
} else {
|
|
136
162
|
this.history.push(chatCompletions);
|
|
163
|
+
}
|
|
137
164
|
}
|
|
138
165
|
|
|
139
166
|
addUserMessagesToHistory(messages: string[], unshift = false) {
|
|
140
|
-
const chatCompletions: ChatCompletionMessageParam[] = messages.map(message => {
|
|
167
|
+
const chatCompletions: ChatCompletionMessageParam[] = messages.map((message) => {
|
|
168
|
+
return { role: 'user', content: message };
|
|
169
|
+
});
|
|
141
170
|
if (unshift) {
|
|
142
171
|
this.history.getMessages().unshift(...chatCompletions);
|
|
143
172
|
this.history.prune();
|
|
144
|
-
} else
|
|
173
|
+
} else {
|
|
145
174
|
this.history.push(chatCompletions);
|
|
175
|
+
}
|
|
146
176
|
}
|
|
147
177
|
|
|
148
178
|
async generateResponse(messages: string[], model?: TiktokenModel) {
|
|
149
179
|
await this.enforceTokenLimit(messages, model);
|
|
150
|
-
return await OpenAi.generateResponse(
|
|
180
|
+
return await OpenAi.generateResponse(
|
|
181
|
+
messages,
|
|
182
|
+
model,
|
|
183
|
+
this.history,
|
|
184
|
+
this.functions,
|
|
185
|
+
this.messageModerators,
|
|
186
|
+
this.params.logLevel
|
|
187
|
+
);
|
|
151
188
|
}
|
|
152
189
|
|
|
153
190
|
async generateCode(description: string[], model?: TiktokenModel) {
|
|
154
191
|
this.logger.info(`Generating code for description:\n${description.join('\n')}`);
|
|
155
|
-
const code = await OpenAi.generateCode(
|
|
192
|
+
const code = await OpenAi.generateCode(
|
|
193
|
+
description,
|
|
194
|
+
model,
|
|
195
|
+
this.history,
|
|
196
|
+
this.functions,
|
|
197
|
+
this.messageModerators,
|
|
198
|
+
!this.generatedCode,
|
|
199
|
+
this.params.logLevel
|
|
200
|
+
);
|
|
156
201
|
this.logger.info(`Generated code:\n${code.slice(0, 150)}${code.length > 150 ? '...' : ''}`);
|
|
157
202
|
this.generatedCode = true;
|
|
158
203
|
return code;
|
|
159
204
|
}
|
|
160
205
|
|
|
161
|
-
async updateCodeFromFile(
|
|
206
|
+
async updateCodeFromFile(
|
|
207
|
+
codeToUpdateFilePath: string,
|
|
208
|
+
dependencyCodeFilePaths: string[],
|
|
209
|
+
description: string,
|
|
210
|
+
model?: TiktokenModel
|
|
211
|
+
) {
|
|
162
212
|
const codeToUpdate = await Fs.readFile(codeToUpdateFilePath);
|
|
163
213
|
let dependencyDescription = `Assume the following exists:\n`;
|
|
164
|
-
for (
|
|
214
|
+
for (const dependencyCodeFilePath of dependencyCodeFilePaths) {
|
|
165
215
|
const dependencCode = await Fs.readFile(dependencyCodeFilePath);
|
|
166
216
|
dependencyDescription += dependencCode + '\n\n';
|
|
167
217
|
}
|
|
@@ -171,15 +221,34 @@ export class Conversation {
|
|
|
171
221
|
}
|
|
172
222
|
|
|
173
223
|
async updateCode(code: string, description: string, model?: TiktokenModel) {
|
|
174
|
-
this.logger.info(
|
|
175
|
-
|
|
224
|
+
this.logger.info(
|
|
225
|
+
`Updating code:\n${code.slice(0, 150)}${code.length > 150 ? '...' : ''}\nFrom description: ${description}`
|
|
226
|
+
);
|
|
227
|
+
const updatedCode = await OpenAi.updateCode(
|
|
228
|
+
code,
|
|
229
|
+
description,
|
|
230
|
+
model,
|
|
231
|
+
this.history,
|
|
232
|
+
this.functions,
|
|
233
|
+
this.messageModerators,
|
|
234
|
+
!this.generatedCode,
|
|
235
|
+
this.params.logLevel
|
|
236
|
+
);
|
|
176
237
|
this.logger.info(`Updated code:\n${updatedCode.slice(0, 150)}${updatedCode.length > 150 ? '...' : ''}`);
|
|
177
238
|
this.generatedCode = true;
|
|
178
239
|
return updatedCode;
|
|
179
240
|
}
|
|
180
241
|
|
|
181
242
|
async generateList(description: string[], model?: TiktokenModel) {
|
|
182
|
-
const list = await OpenAi.generateList(
|
|
243
|
+
const list = await OpenAi.generateList(
|
|
244
|
+
description,
|
|
245
|
+
model,
|
|
246
|
+
this.history,
|
|
247
|
+
this.functions,
|
|
248
|
+
this.messageModerators,
|
|
249
|
+
!this.generatedList,
|
|
250
|
+
this.params.logLevel
|
|
251
|
+
);
|
|
183
252
|
this.generatedList = true;
|
|
184
253
|
return list;
|
|
185
254
|
}
|
|
@@ -199,9 +268,9 @@ export const summarizeConversationHistoryFunction = (conversation: Conversation)
|
|
|
199
268
|
description: 'A 1-3 sentence summary of the current chat history',
|
|
200
269
|
},
|
|
201
270
|
},
|
|
202
|
-
required: ['summary']
|
|
271
|
+
required: ['summary'],
|
|
203
272
|
},
|
|
204
273
|
},
|
|
205
274
|
call: async (params: { summary: string }) => conversation.summarizeConversationHistory(params.summary),
|
|
206
|
-
}
|
|
207
|
-
}
|
|
275
|
+
};
|
|
276
|
+
};
|
|
@@ -2,7 +2,7 @@ import { Function } from './Function';
|
|
|
2
2
|
import { MessageModerator } from './history/MessageModerator';
|
|
3
3
|
|
|
4
4
|
export interface ConversationModule {
|
|
5
|
-
getName(): string
|
|
5
|
+
getName(): string;
|
|
6
6
|
getSystemMessages(): string[];
|
|
7
7
|
getFunctions(): Function[];
|
|
8
8
|
getMessageModerators(): MessageModerator[];
|
|
@@ -10,4 +10,4 @@ export interface ConversationModule {
|
|
|
10
10
|
|
|
11
11
|
export interface ConversationModuleFactory {
|
|
12
12
|
createModule(repoPath: string): Promise<ConversationModule>;
|
|
13
|
-
}
|
|
13
|
+
}
|
package/src/Function.ts
CHANGED
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
|
+
}
|