/**
 * Wire codec for providers that implement the OpenAI-compatible
 * `/chat/completions` shape. Keep provider-family quirks here so the agent
 * loop and hosts only depend on Heddle's neutral chat/tool contracts.
 */
export class OpenAiCompatibleCodec {
    static toMessages(messages) {
        return messages.map((message) => {
            if (message.role === 'assistant') {
                return {
                    role: 'assistant',
                    content: message.content || null,
                    tool_calls: message.toolCalls?.map((call) => OpenAiCompatibleCodec.toToolCall(call)),
                };
            }
            if (message.role === 'tool') {
                return {
                    role: 'tool',
                    content: message.content,
                    tool_call_id: message.toolCallId,
                };
            }
            return {
                role: message.role,
                content: message.content,
            };
        });
    }
    static toTools(tools) {
        return tools.map((tool) => ({
            type: 'function',
            function: {
                name: tool.name,
                description: tool.description,
                parameters: tool.parameters,
            },
        }));
    }
    static extractContent(response) {
        const content = OpenAiCompatibleCodec.firstMessage(response)?.content;
        return typeof content === 'string' && content.length > 0 ? content : undefined;
    }
    static extractToolCalls(response) {
        const toolCalls = OpenAiCompatibleCodec.firstMessage(response)?.tool_calls;
        if (!Array.isArray(toolCalls)) {
            return undefined;
        }
        const parsed = toolCalls.flatMap((call) => {
            if (!call || typeof call !== 'object') {
                return [];
            }
            const entry = call;
            const id = typeof entry.id === 'string' ? entry.id : undefined;
            const name = typeof entry.function?.name === 'string' ? entry.function.name : undefined;
            const argumentsText = typeof entry.function?.arguments === 'string' ? entry.function.arguments : undefined;
            if (!id || !name || typeof argumentsText !== 'string') {
                return [];
            }
            return [{
                    id,
                    tool: name,
                    input: argumentsText.trim() ? JSON.parse(argumentsText) : {},
                }];
        });
        return parsed.length > 0 ? parsed : undefined;
    }
    static extractUsage(response) {
        if (!response || typeof response !== 'object') {
            return undefined;
        }
        const usage = response.usage;
        if (!usage || typeof usage !== 'object') {
            return undefined;
        }
        const inputTokens = OpenAiCompatibleCodec.numberField(usage, 'prompt_tokens') ?? 0;
        const outputTokens = OpenAiCompatibleCodec.numberField(usage, 'completion_tokens') ?? 0;
        return {
            inputTokens,
            outputTokens,
            totalTokens: OpenAiCompatibleCodec.numberField(usage, 'total_tokens') ?? inputTokens + outputTokens,
            requests: 1,
        };
    }
    static toToolCall(call) {
        return {
            id: call.id,
            type: 'function',
            function: {
                name: call.tool,
                arguments: JSON.stringify(call.input),
            },
        };
    }
    static firstMessage(response) {
        if (!response || typeof response !== 'object') {
            return undefined;
        }
        const choices = response.choices;
        if (!Array.isArray(choices)) {
            return undefined;
        }
        const message = choices[0]?.message;
        return message && typeof message === 'object' ? message : undefined;
    }
    static numberField(value, key) {
        const field = value[key];
        return typeof field === 'number' ? field : undefined;
    }
}
//# sourceMappingURL=openai-compatible-codec.js.map