UNPKG

openai-code

Version:

An unofficial proxy layer that lets you use Anthropic Claude Code with any OpenAI API backend.

179 lines (159 loc) 5.89 kB
// New modular answering logic function. // This function handles the final response, either using an existing choice or calling sendOpenAIRequest. // It supports both streaming and non-streaming responses. export async function processAnswer({ useTools, textMessage, usage = { input_tokens: 0, output_tokens: 0 }, stream, model, res, postProcessToolExecution }) { if (stream) { // Prepare headers for a simulated stream response. res.setHeader("Content-Type", "text/event-stream") res.setHeader("Cache-Control", "no-cache") res.setHeader("Connection", "keep-alive") const messageId = `msg_${Date.now()}` const messageStart = { type: "message_start", message: { id: messageId, type: "message", role: "assistant", content: [], model: model, stop_reason: null, stop_sequence: null, usage: usage, }, } res.write(`event: message_start\ndata: ${JSON.stringify(messageStart)}\n\n`) // If the response includes tool calls, simulate tool_use events. if (useTools && useTools.length > 0) { const aggregatedToolContent = [] let index = 0 useTools = useTools.some(tool => tool.name === "Edit" || tool.name === "Replace") ? [useTools[0]] : useTools; for (const toolCall of useTools) { // Create a unique ID for this tool use. const toolId = `toolu_${Date.now()}${Math.floor(Math.random() * 1000)}` // Send a content block start event for this tool use. const toolBlockStart = { type: "content_block_start", index: index, content_block: { type: "tool_use", id: toolId, name: toolCall.name, input: toolCall.parameters || {}, }, } await postProcessToolExecution(toolCall, toolId) res.write(`event: content_block_start\ndata: ${JSON.stringify(toolBlockStart)}\n\n`) // End this tool content block. const toolBlockStop = { type: "content_block_stop", index: index, } res.write(`event: content_block_stop\ndata: ${JSON.stringify(toolBlockStop)}\n\n`) aggregatedToolContent.push({ type: "tool_use", id: toolId, name: toolCall.name, input: toolCall.parameters, }) index++ } // Send a message_delta event indicating tool use. const messageDelta = { type: "message_delta", delta: { stop_reason: "tool_use", stop_sequence: null, content: aggregatedToolContent, }, usage: usage, } res.write(`event: message_delta\ndata: ${JSON.stringify(messageDelta)}\n\n`) console.log("") console.log("---") console.log("") console.log("Final response with tool calls:", messageDelta.delta.content) // Signal end of message. const messageStop = { type: "message_stop" } res.write(`event: message_stop\ndata: ${JSON.stringify(messageStop)}\n\n`) res.end() } else { // Otherwise, simulate a single text content block. const aggregatedContent = textMessage // Start a text content block. const textBlockStart = { type: "content_block_start", index: 0, content_block: { type: "text", text: "" }, } res.write(`event: content_block_start\ndata: ${JSON.stringify(textBlockStart)}\n\n`) // Send the aggregated text as one delta event. const contentDelta = { type: "content_block_delta", index: 0, delta: { type: "text_delta", text: aggregatedContent }, } res.write(`event: content_block_delta\ndata: ${JSON.stringify(contentDelta)}\n\n`) // End the text content block. const textBlockStop = { type: "content_block_stop", index: 0, } res.write(`event: content_block_stop\ndata: ${JSON.stringify(textBlockStop)}\n\n`) // Send the final message_delta event. const messageDelta = { type: "message_delta", delta: { stop_reason: "end_turn", stop_sequence: null, content: [{ type: "text", text: aggregatedContent }], }, usage: usage, } res.write(`event: message_delta\ndata: ${JSON.stringify(messageDelta)}\n\n`) console.log("") console.log("---") console.log("") // TODO: if the text is a JSON here, re-reason? (Cause this is clearly wrong) console.log("Final response:", messageDelta.delta.content) // Close the stream. const messageStop = { type: "message_stop" } res.write(`event: message_stop\ndata: ${JSON.stringify(messageStop)}\n\n`) res.end() } } else { // Non-streaming mode. const formattedResponse = { id: `msg_${Date.now()}`, type: "message", role: "assistant", model: model, stop_reason: "end_turn", stop_sequence: null, usage: usage, } if (useTools && useTools.length > 0) { const toolId = `toolu_${Date.now()}${Math.floor(Math.random() * 1000)}`; formattedResponse.content = []; useTools = useTools.some(tool => tool.name === "Edit" || tool.name === "Replace") ? [useTools[0]] : useTools; for (const toolCall of useTools) { formattedResponse.content.push({ type: "tool_use", id: toolId, name: toolCall.name, input: toolCall.function.parameters, }); await postProcessToolExecution(toolCall, toolId) } formattedResponse.stop_reason = "tool_use" } else { formattedResponse.content = [{ type: "text", text: textMessage }] } console.log("") console.log("---") console.log("") console.log("Final response:", formattedResponse.content) res.json(formattedResponse) } }