Ensure MCP loops output the right response format

In a tool loop, you can't set response_format because the model needs to
be able to think in plain English. But you still need the final response
to be in the desired format, so we add response_format only on the last
iteration.
This commit is contained in:
Sean Goedecke
2025-08-05 22:06:49 +00:00
parent 0cbed4a106
commit 866ae2b5d7
4 changed files with 281 additions and 9 deletions

28
dist/index.js generated vendored
View File

@@ -48678,6 +48678,9 @@ async function mcpInference(request, githubMcpClient) {
const messages = [...request.messages];
let iterationCount = 0;
const maxIterations = 5; // Prevent infinite loops
// We want to use response_format (e.g. JSON) on the last iteration only, so the model can output
// the final result in the expected format without interfering with tool calls
let finalMessage = false;
while (iterationCount < maxIterations) {
iterationCount++;
coreExports.info(`MCP inference iteration ${iterationCount}`);
@@ -48685,13 +48688,15 @@ async function mcpInference(request, githubMcpClient) {
messages: messages,
max_tokens: request.maxTokens,
model: request.modelName,
tools: githubMcpClient.tools,
};
// Add response format if specified (only on first iteration to avoid conflicts)
if (iterationCount === 1 && request.responseFormat) {
// Add response format if specified (only on final iteration to avoid conflicts with tool calls)
if (finalMessage && request.responseFormat) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
chatCompletionRequest.response_format = request.responseFormat;
}
else {
chatCompletionRequest.tools = githubMcpClient.tools;
}
try {
const response = await client.chat.completions.create(chatCompletionRequest);
if (!('choices' in response)) {
@@ -48708,7 +48713,22 @@ async function mcpInference(request, githubMcpClient) {
});
if (!toolCalls || toolCalls.length === 0) {
coreExports.info('No tool calls requested, ending GitHub MCP inference loop');
return modelResponse || null;
// If we have a response format set and we haven't explicitly run one final message iteration,
// do another loop with the response format set
if (request.responseFormat && !finalMessage) {
coreExports.info('Making one more MCP loop with the requested response format...');
// Add a user message requesting JSON format and try again
messages.push({
role: 'user',
content: `Please provide your response in the exact ${request.responseFormat} format specified.`,
});
finalMessage = true;
// Continue the loop to get a properly formatted response
continue;
}
else {
return modelResponse || null;
}
}
coreExports.info(`Model requested ${toolCalls.length} tool calls`);
// Execute all tool calls via GitHub MCP

2
dist/index.js.map generated vendored

File diff suppressed because one or more lines are too long