import { buildShellDescription, hasApplyPatchToolDeclared, isShellToolName } from '../../tools/tool-description-utils.js';
function isObject(v) {
    return !!v && typeof v === 'object' && !Array.isArray(v);
}
/**
 * Normalize OpenAI tools definitions at the final request stage.
 * - Enforces { command: string | string[], workdir?: string } shape for shell-like tools.
 * - Best-effort; never throws.
 */
export class RequestOpenAIToolsNormalizeFilter {
    name = 'request_openai_tools_normalize';
    stage = 'request_finalize';
    async apply(input) {
        try {
            const out = JSON.parse(JSON.stringify(input || {}));
            const tools = Array.isArray(out.tools) ? out.tools : [];
            const hasApplyPatchTool = hasApplyPatchToolDeclared(tools);
            if (!tools.length) {
                // No tools present: drop tool_choice to avoid provider-side validation errors
                try {
                    if ('tool_choice' in out)
                        delete out.tool_choice;
                }
                catch { /* ignore */ }
                return { ok: true, data: out };
            }
            let normalizedList = [];
            try {
                const mod = await import('../../conversion/args-mapping.js');
                const normalizeTools = mod?.normalizeTools;
                if (typeof normalizeTools === 'function')
                    normalizedList = normalizeTools(tools);
            }
            catch { /* passthrough on failure */ }
            const finalTools = [];
            const max = Math.max(tools.length, normalizedList.length);
            for (let i = 0; i < max; i++) {
                const src = tools[i];
                const dst = normalizedList[i];
                if (dst && isObject(dst) && isObject(dst.function) && typeof dst.function.name === 'string') {
                    const fn = dst.function;
                    // Ensure type and minimal function shape
                    if (typeof dst.type !== 'string' || !String(dst.type).trim()) {
                        dst.type = 'function';
                    }
                    // Ensure parameters object shape exists
                    if (!isObject(fn.parameters)) {
                        dst.function = { ...fn, parameters: { type: 'object', properties: {}, additionalProperties: true } };
                    }
                    // Ensure description string exists
                    if (typeof fn.description !== 'string') {
                        dst.function = { ...dst.function, description: '' };
                    }
                    // Drop non-standard strict flag to pass strict providers that reject unknown tool fields
                    try {
                        if ('strict' in dst.function)
                            delete dst.function.strict;
                    }
                    catch { /* ignore */ }
                    // Switch schema for specific built-in tools at unified shaping point
                    try {
                        const rawToolName = String(dst.function.name || '');
                        const isShell = isShellToolName(rawToolName);
                        if (isShell) {
                            dst.function.parameters = {
                                type: 'object',
                                properties: {
                                    command: { oneOf: [{ type: 'string' }, { type: 'array', items: { type: 'string' } }] },
                                    workdir: { type: 'string' }
                                },
                                required: ['command'],
                                additionalProperties: false
                            };
                            const label = rawToolName && rawToolName.trim().length > 0 ? rawToolName.trim() : 'shell';
                            dst.function.description = buildShellDescription(label, hasApplyPatchTool);
                        }
                    }
                    catch { /* ignore */ }
                    finalTools.push(dst);
                }
                else if (src && isObject(src)) {
                    // Fallback: minimally enforce required fields on raw src entries
                    const item = JSON.parse(JSON.stringify(src));
                    if (typeof item.type !== 'string' || !String(item.type).trim())
                        item.type = 'function';
                    if (!isObject(item.function))
                        item.function = {};
                    if (typeof item.function.name !== 'string')
                        item.function.name = String(item.name || 'tool');
                    if (!isObject(item.function.parameters))
                        item.function.parameters = { type: 'object', properties: {}, additionalProperties: true };
                    try {
                        if ('strict' in item.function)
                            delete item.function.strict;
                    }
                    catch { /* ignore */ }
                    finalTools.push(item);
                }
            }
            out.tools = finalTools;
            // If tools ended up empty, drop tool_choice to avoid upstream validation issues
            try {
                if (Array.isArray(out.tools) && out.tools.length === 0 && 'tool_choice' in out)
                    delete out.tool_choice;
            }
            catch { /* ignore */ }
            return { ok: true, data: out };
        }
        catch {
            return { ok: true, data: input };
        }
    }
}
