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
JavaScript
// 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)
}
}