/**
 * Ensure assistant.tool_calls[].function.arguments is a JSON string containing valid JSON.
 * - If arguments is not a string, JSON.stringify it.
 * - If arguments is a string but not parseable as JSON, wrap it into a JSON object so the
 *   provider always receives syntactically valid JSON (e.g. {"input": "<raw>"}).
 * Also set assistant.content=null when tool_calls exist (request-side invariant).
 */
export class RequestToolCallsStringifyFilter {
    name = 'request_toolcalls_stringify';
    stage = 'request_post';
    apply(input) {
        try {
            const out = JSON.parse(JSON.stringify(input || {}));
            const msgs = Array.isArray(out.messages) ? out.messages : [];
            for (const m of msgs) {
                if (!m || typeof m !== 'object')
                    continue;
                if (m.role === 'assistant' && Array.isArray(m.tool_calls) && m.tool_calls.length) {
                    try {
                        for (const tc of m.tool_calls) {
                            if (!tc || typeof tc !== 'object')
                                continue;
                            const fn = tc.function || {};
                            if (!fn || typeof fn !== 'object')
                                continue;
                            const currentArgs = fn.arguments;
                            const fnName = typeof fn.name === 'string' ? fn.name.trim() : '';
                            // Case 1: non-string arguments → stringify directly
                            if (currentArgs !== undefined && typeof currentArgs !== 'string') {
                                let argsJson = '{}';
                                try {
                                    argsJson = JSON.stringify(currentArgs ?? {});
                                }
                                catch {
                                    argsJson = '{}';
                                }
                                fn.arguments = argsJson;
                                tc.function = fn;
                                continue;
                            }
                            // Case 2: string arguments → ensure it is valid JSON
                            if (typeof currentArgs === 'string') {
                                const trimmed = currentArgs.trim();
                                if (trimmed.length === 0) {
                                    fn.arguments = '{}';
                                    tc.function = fn;
                                    continue;
                                }
                                let parsedOk = false;
                                let parsedValue = undefined;
                                try {
                                    parsedValue = JSON.parse(trimmed);
                                    parsedOk = true;
                                }
                                catch {
                                    parsedOk = false;
                                }
                                if (!parsedOk) {
                                    // Wrap raw string into a JSON object to keep payload syntactically valid.
                                    // For shell, align with GLM/统一工具治理约定，优先映射到 { command }，
                                    // 其余模型仍使用 { input } 形式。
                                    try {
                                        if (fnName === 'shell') {
                                            fn.arguments = JSON.stringify({ command: currentArgs });
                                        }
                                        else {
                                            fn.arguments = JSON.stringify({ input: currentArgs });
                                        }
                                    }
                                    catch {
                                        fn.arguments = '{}';
                                    }
                                    tc.function = fn;
                                    continue;
                                }
                                // 合法 JSON 场景保持原样
                                fn.arguments = trimmed;
                                tc.function = fn;
                            }
                        }
                    }
                    catch { /* ignore per-item errors */ }
                    // Invariant: assistant with tool_calls should use content=null
                    m.content = null;
                }
            }
            out.messages = msgs;
            return { ok: true, data: out };
        }
        catch {
            return { ok: true, data: input };
        }
    }
}
