|
| 1 | +import { publisher } from '../../constants' |
| 2 | + |
| 3 | +import type { SecretAgentDefinition } from '../../types/secret-agent-definition' |
| 4 | + |
| 5 | +export const createBestOfNImplementor2 = (options: { |
| 6 | + model: 'gpt-5' | 'opus' | 'sonnet' |
| 7 | +}): Omit<SecretAgentDefinition, 'id'> => { |
| 8 | + const { model } = options |
| 9 | + const isGpt5 = model === 'gpt-5' |
| 10 | + const isOpus = model === 'opus' |
| 11 | + return { |
| 12 | + publisher, |
| 13 | + model: isGpt5 |
| 14 | + ? 'openai/gpt-5.2' |
| 15 | + : isOpus |
| 16 | + ? 'anthropic/claude-opus-4.5' |
| 17 | + : 'anthropic/claude-sonnet-4.5', |
| 18 | + displayName: isGpt5 |
| 19 | + ? 'GPT-5 Implementation Generator v2' |
| 20 | + : isOpus |
| 21 | + ? 'Opus Implementation Generator v2' |
| 22 | + : 'Sonnet Implementation Generator v2', |
| 23 | + spawnerPrompt: |
| 24 | + 'Generates a complete implementation using propose_* tools that draft changes without applying them', |
| 25 | + |
| 26 | + includeMessageHistory: true, |
| 27 | + inheritParentSystemPrompt: true, |
| 28 | + |
| 29 | + toolNames: ['propose_write_file', 'propose_str_replace'], |
| 30 | + spawnableAgents: [], |
| 31 | + |
| 32 | + inputSchema: {}, |
| 33 | + outputMode: 'structured_output', |
| 34 | + |
| 35 | + instructionsPrompt: `You are an expert code editor with deep understanding of software engineering principles. You were spawned to generate an implementation for the user's request. |
| 36 | + |
| 37 | +Your task is to write out ALL the code changes needed to complete the user's request. |
| 38 | +
|
| 39 | +IMPORTANT: Use propose_str_replace and propose_write_file tools to make your edits. These tools draft changes without actually applying them - they will be reviewed first. |
| 40 | +
|
| 41 | +You can make multiple tool calls across multiple steps to complete the implementation. |
| 42 | +
|
| 43 | +After your edit tool calls, you can optionally mention any follow-up steps to take, like deleting a file, or a specific way to validate the changes. |
| 44 | +
|
| 45 | +Your implementation should: |
| 46 | +- Be complete and comprehensive |
| 47 | +- Include all necessary changes to fulfill the user's request |
| 48 | +- Follow the project's conventions and patterns |
| 49 | +- Be as simple and maintainable as possible |
| 50 | +- Reuse existing code wherever possible |
| 51 | +- Be well-structured and organized |
| 52 | +
|
| 53 | +More style notes: |
| 54 | +- Extra try/catch blocks clutter the code -- use them sparingly. |
| 55 | +- Optional arguments are code smell and worse than required arguments. |
| 56 | +- New components often should be added to a new file, not added to an existing file. |
| 57 | +
|
| 58 | +Write out your complete implementation now.`, |
| 59 | + |
| 60 | + handleSteps: function* ({ agentState: initialAgentState, logger }) { |
| 61 | + const initialMessageHistoryLength = |
| 62 | + initialAgentState.messageHistory.length |
| 63 | + |
| 64 | + const { agentState } = yield 'STEP_ALL' |
| 65 | + |
| 66 | + let postMessages = agentState.messageHistory.slice( |
| 67 | + initialMessageHistoryLength, |
| 68 | + ) |
| 69 | + |
| 70 | + if (postMessages.length === 0) { |
| 71 | + const { agentState: postMessagesAgentState } = yield 'STEP' |
| 72 | + postMessages = postMessagesAgentState.messageHistory.slice( |
| 73 | + initialMessageHistoryLength, |
| 74 | + ) |
| 75 | + } else if (postMessages.length == 1) { |
| 76 | + const message = postMessages[0] |
| 77 | + if ( |
| 78 | + message.role === 'assistant' && |
| 79 | + message.content.length === 1 && |
| 80 | + message.content[0].type === 'text' && |
| 81 | + !message.content[0].text |
| 82 | + ) { |
| 83 | + const { agentState: postMessagesAgentState } = yield 'STEP_ALL' |
| 84 | + postMessages = postMessagesAgentState.messageHistory.slice( |
| 85 | + initialMessageHistoryLength, |
| 86 | + ) |
| 87 | + } |
| 88 | + } |
| 89 | + |
| 90 | + logger.debug( |
| 91 | + { |
| 92 | + numMessages: postMessages.length, |
| 93 | + messageRoles: postMessages.map((m: any) => m.role), |
| 94 | + }, |
| 95 | + 'Post STEP_ALL messages', |
| 96 | + ) |
| 97 | + |
| 98 | + // Extract tool calls from assistant messages |
| 99 | + // Handle both 'input' and 'args' property names for compatibility |
| 100 | + const toolCalls: { toolName: string; input: any }[] = [] |
| 101 | + for (const message of postMessages) { |
| 102 | + if (message.role !== 'assistant' || !Array.isArray(message.content)) |
| 103 | + continue |
| 104 | + for (const part of message.content) { |
| 105 | + if (part.type === 'tool-call') { |
| 106 | + toolCalls.push({ |
| 107 | + toolName: part.toolName, |
| 108 | + input: part.input ?? (part as any).args ?? {}, |
| 109 | + }) |
| 110 | + } |
| 111 | + } |
| 112 | + } |
| 113 | + |
| 114 | + // Extract tool results (unified diffs) from tool messages |
| 115 | + const toolResults: any[] = [] |
| 116 | + for (const message of postMessages) { |
| 117 | + if (message.role !== 'tool' || !Array.isArray(message.content)) continue |
| 118 | + for (const part of message.content) { |
| 119 | + if (part.type === 'json' && part.value) { |
| 120 | + toolResults.push(part.value) |
| 121 | + } |
| 122 | + } |
| 123 | + } |
| 124 | + |
| 125 | + logger.debug( |
| 126 | + { numToolCalls: toolCalls.length, numToolResults: toolResults.length }, |
| 127 | + 'Extracted tool calls and results', |
| 128 | + ) |
| 129 | + |
| 130 | + // Concatenate all unified diffs for the selector to review |
| 131 | + const unifiedDiffs = toolResults |
| 132 | + .filter((result: any) => result.unifiedDiff) |
| 133 | + .map((result: any) => `--- ${result.file} ---\n${result.unifiedDiff}`) |
| 134 | + .join('\n\n') |
| 135 | + |
| 136 | + logger.debug( |
| 137 | + { |
| 138 | + unifiedDiffsLength: unifiedDiffs.length, |
| 139 | + hasContent: unifiedDiffs.length > 0, |
| 140 | + }, |
| 141 | + 'Generated unified diffs', |
| 142 | + ) |
| 143 | + |
| 144 | + yield { |
| 145 | + toolName: 'set_output', |
| 146 | + input: { |
| 147 | + toolCalls, |
| 148 | + toolResults, |
| 149 | + unifiedDiffs, |
| 150 | + }, |
| 151 | + includeToolCall: false, |
| 152 | + } |
| 153 | + }, |
| 154 | + } |
| 155 | +} |
| 156 | +const definition = { |
| 157 | + ...createBestOfNImplementor2({ model: 'opus' }), |
| 158 | + id: 'editor-implementor2', |
| 159 | +} |
| 160 | +export default definition |
0 commit comments