Skip to content

Commit 7397c06

Browse files
committed
Choose best of 3 patches
1 parent 965fada commit 7397c06

File tree

1 file changed

+94
-10
lines changed

1 file changed

+94
-10
lines changed

backend/src/generate-patch.ts

Lines changed: 94 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { Message } from 'common/actions'
22
import { OpenAIMessage, promptOpenAI } from './openai-api'
33
import { createPatch } from 'diff'
4+
import { applyPatch } from 'common/util/patch'
45
import { openaiModels } from 'common/constants'
56
import { replaceNonStandardPlaceholderComments } from 'common/util/string'
67
import { logger } from './util/logger'
@@ -31,7 +32,6 @@ export async function generatePatch(
3132
userInputId,
3233
normalizedOldContent,
3334
normalizedNewContent,
34-
filePath,
3535
messageHistory,
3636
fullResponse,
3737
userId
@@ -47,15 +47,12 @@ export async function generatePatch(
4747
let newContentWithPlaceholders = shouldAddPlaceholderComments
4848
? `... existing code ...\n\n${normalizedNewContent}\n\n... existing code ...`
4949
: normalizedNewContent
50-
patch = await generatePatchPrompt(
50+
patch = await generateBestOfNPatch(
5151
clientSessionId,
5252
fingerprintId,
5353
userInputId,
5454
normalizedOldContent,
5555
newContentWithPlaceholders,
56-
filePath,
57-
messageHistory,
58-
fullResponse,
5956
userId
6057
)
6158
}
@@ -69,7 +66,6 @@ const isSketchCompletePrompt = async (
6966
userInputId: string,
7067
oldContent: string,
7168
newContent: string,
72-
filePath: string,
7369
messageHistory: Message[],
7470
fullResponse: string,
7571
userId?: string
@@ -118,7 +114,10 @@ If you strongly believe this is the scenario, please write "INCOMPLETE_SKETCH".
118114
const shouldAddPlaceholderComments = response.includes('INCOMPLETE_SKETCH')
119115
const isSketchComplete =
120116
response.includes('NO') && !shouldAddPlaceholderComments
121-
logger.debug({ response, isSketchComplete, shouldAddPlaceholderComments }, 'isSketchComplete response')
117+
logger.debug(
118+
{ response, isSketchComplete, shouldAddPlaceholderComments },
119+
'isSketchComplete response'
120+
)
122121

123122
return { isSketchComplete, shouldAddPlaceholderComments }
124123
}
@@ -129,9 +128,6 @@ const generatePatchPrompt = async (
129128
userInputId: string,
130129
oldContent: string,
131130
newContent: string,
132-
filePath: string,
133-
messageHistory: Message[],
134-
fullResponse: string,
135131
userId?: string
136132
) => {
137133
const oldFileWithLineNumbers = oldContent
@@ -170,3 +166,91 @@ Please produce a patch file based on this change.
170166
// ft:${models.gpt4o}:manifold-markets:run-1:A4VfZwvz`
171167
)
172168
}
169+
170+
const generateBestOfNPatch = async (
171+
clientSessionId: string,
172+
fingerprintId: string,
173+
userInputId: string,
174+
oldContent: string,
175+
newContent: string,
176+
userId?: string
177+
) => {
178+
const generateSinglePatch = () =>
179+
generatePatchPrompt(
180+
clientSessionId,
181+
fingerprintId,
182+
userInputId,
183+
oldContent,
184+
newContent,
185+
userId
186+
)
187+
188+
// Generate three patches in parallel
189+
const patches = await Promise.all([
190+
generateSinglePatch(),
191+
generateSinglePatch(),
192+
generateSinglePatch(),
193+
])
194+
195+
const results = patches.map((p) => applyPatch(oldContent, p))
196+
197+
const comparePrompt = `
198+
I have an original file and a sketch of how to change it. Help me choose from among three different variations of the updated file based on the following criteria:
199+
1. Correctness: The updated content should accurately reflect the intended changes in the sketch.
200+
2. Minimal changes: The updated content should make only the necessary modifications. Be careful with patches that delete too much code.
201+
3. Readability: The updated content should be easy to understand.
202+
203+
Try not to choose the updated content if it contains comments like "// ... existing code ..." or "# .... rest of the function ...". Those placeholders should have been replaced with content from the original file.
204+
205+
Here are the original file, sketch of the changes, and three updated content variations:
206+
207+
Original file:
208+
\`\`\`
209+
${oldContent}
210+
\`\`\`
211+
212+
Sketch of the changes:
213+
\`\`\`
214+
${newContent}
215+
\`\`\`
216+
217+
${results
218+
.map((result, index) =>
219+
`
220+
Updated content ${index + 1}:
221+
\`\`\`
222+
${result}
223+
\`\`\`
224+
`.trim()
225+
)
226+
.join('\n\n')}
227+
228+
Please respond with just the number of the best updated content only ("1", "2", or "3") and nothing else.
229+
`.trim()
230+
231+
const compareMessages = [
232+
{
233+
role: 'user' as const,
234+
content: comparePrompt,
235+
},
236+
]
237+
238+
const comparison = await promptOpenAI(
239+
clientSessionId,
240+
fingerprintId,
241+
userInputId,
242+
compareMessages,
243+
openaiModels.gpt4o,
244+
userId
245+
)
246+
247+
logger.debug({ response: comparison, patches }, 'Best of n patch')
248+
249+
const bestPatchNumber = parseInt(comparison.match(/^(\d+)/)?.[1] || '1')
250+
if ([1, 2, 3].includes(bestPatchNumber)) {
251+
return patches[bestPatchNumber - 1]
252+
} else {
253+
logger.error({ comparison, bestPatchNumber }, 'Invalid best patch number')
254+
return patches[0]
255+
}
256+
}

0 commit comments

Comments
 (0)