Spaces:
Running
Running
| /** | |
| * OpenAI Chat Completions streaming conversion helpers. | |
| */ | |
| import crypto from 'crypto'; | |
| function mapFinishReason(stopReason) { | |
| if (stopReason === 'max_tokens') return 'length'; | |
| if (stopReason === 'tool_use') return 'tool_calls'; | |
| return 'stop'; | |
| } | |
| export function createOpenAIStreamState(requestedModel, includeUsage = false) { | |
| return { | |
| id: `chatcmpl_${crypto.randomUUID().replace(/-/g, '')}`, | |
| created: Math.floor(Date.now() / 1000), | |
| model: requestedModel, | |
| includeUsage, | |
| started: false, | |
| finishReason: null, | |
| promptTokens: 0, | |
| completionTokens: 0, | |
| toolCallIndexes: new Map(), | |
| nextToolCallIndex: 0 | |
| }; | |
| } | |
| function makeChunk(state, delta, finishReason = null, usage = undefined) { | |
| const chunk = { | |
| id: state.id, | |
| object: 'chat.completion.chunk', | |
| created: state.created, | |
| model: state.model, | |
| choices: [{ | |
| index: 0, | |
| delta, | |
| finish_reason: finishReason, | |
| logprobs: null | |
| }] | |
| }; | |
| if (usage !== undefined) chunk.usage = usage; | |
| return chunk; | |
| } | |
| export function convertAnthropicEventToOpenAIChunks(event, state) { | |
| const chunks = []; | |
| if (!event || !state) return chunks; | |
| if (event.type === 'message_start') { | |
| state.id = event.message?.id?.replace(/^msg_/, 'chatcmpl_') || state.id; | |
| state.promptTokens = event.message?.usage?.input_tokens || 0; | |
| if (!state.started) { | |
| state.started = true; | |
| chunks.push(makeChunk(state, { role: 'assistant', content: '' })); | |
| } | |
| return chunks; | |
| } | |
| if (!state.started) { | |
| state.started = true; | |
| chunks.push(makeChunk(state, { role: 'assistant', content: '' })); | |
| } | |
| if (event.type === 'content_block_start' && event.content_block?.type === 'tool_use') { | |
| const toolIndex = state.nextToolCallIndex++; | |
| state.toolCallIndexes.set(event.index, toolIndex); | |
| chunks.push(makeChunk(state, { | |
| tool_calls: [{ | |
| index: toolIndex, | |
| id: event.content_block.id, | |
| type: 'function', | |
| function: { | |
| name: event.content_block.name, | |
| arguments: '' | |
| } | |
| }] | |
| })); | |
| return chunks; | |
| } | |
| if (event.type === 'content_block_delta') { | |
| if (event.delta?.type === 'text_delta') { | |
| chunks.push(makeChunk(state, { content: event.delta.text || '' })); | |
| } else if (event.delta?.type === 'thinking_delta') { | |
| chunks.push(makeChunk(state, { reasoning_content: event.delta.thinking || '' })); | |
| } else if (event.delta?.type === 'input_json_delta') { | |
| const toolIndex = state.toolCallIndexes.get(event.index) ?? 0; | |
| chunks.push(makeChunk(state, { | |
| tool_calls: [{ | |
| index: toolIndex, | |
| function: { | |
| arguments: event.delta.partial_json || '' | |
| } | |
| }] | |
| })); | |
| } | |
| return chunks; | |
| } | |
| if (event.type === 'message_delta') { | |
| state.finishReason = mapFinishReason(event.delta?.stop_reason); | |
| state.completionTokens = event.usage?.output_tokens || 0; | |
| // Emit search grounding (citations) just before the finish chunk. | |
| if (event.grounding?.annotations?.length > 0) { | |
| chunks.push(makeChunk(state, { | |
| annotations: event.grounding.annotations, | |
| grounding: event.grounding | |
| })); | |
| } | |
| chunks.push(makeChunk(state, {}, state.finishReason)); | |
| return chunks; | |
| } | |
| if (event.type === 'message_stop' && state.includeUsage) { | |
| chunks.push({ | |
| id: state.id, | |
| object: 'chat.completion.chunk', | |
| created: state.created, | |
| model: state.model, | |
| choices: [], | |
| usage: { | |
| prompt_tokens: state.promptTokens, | |
| completion_tokens: state.completionTokens, | |
| total_tokens: state.promptTokens + state.completionTokens | |
| } | |
| }); | |
| } | |
| return chunks; | |
| } | |