const isRecord = (value) => typeof value === 'object' && value !== null && !Array.isArray(value);
function readString(value) {
    return typeof value === 'string' ? value.trim() : '';
}
function collectToolNames(toolsRaw) {
    const out = [];
    if (!Array.isArray(toolsRaw)) {
        return out;
    }
    for (const item of toolsRaw) {
        if (!isRecord(item))
            continue;
        const fn = isRecord(item.function) ? item.function : item;
        const name = readString(fn.name);
        if (!name)
            continue;
        if (!out.includes(name)) {
            out.push(name);
        }
    }
    return out;
}
function isToolChoiceRequired(root) {
    const toolChoice = root.tool_choice;
    if (typeof toolChoice === 'string') {
        const normalized = toolChoice.trim().toLowerCase();
        if (normalized === 'required')
            return true;
        if (normalized === 'auto' || normalized === 'none')
            return false;
    }
    if (isRecord(toolChoice)) {
        return String(toolChoice.type || '').trim().toLowerCase() === 'function';
    }
    return false;
}
function buildDefaultInstruction(root, config) {
    const toolNames = collectToolNames(root.tools);
    const includeToolNames = config?.includeToolNames !== false;
    const required = isToolChoiceRequired(root);
    const marker = readString(config?.marker) || 'Tool-call output contract (STRICT)';
    const lines = [
        `${marker}:`,
        '1) If calling tools, output exactly one JSON object: {"tool_calls":[{"name":"tool_name","input":{...}}]}',
        '2) Use only keys: `tool_calls` + each call `name` and `input`.',
        '3) Do not output markdown fences, prose, or tool transcripts around JSON.',
        '4) Do NOT output pseudo tool results in text (forbidden examples: {"exec_command":...}, <function_results>...</function_results>).'
    ];
    if (includeToolNames && toolNames.length) {
        lines.push(`5) Allowed tool names this turn: ${toolNames.join(', ')}`);
    }
    else {
        lines.push('5) Tool name must match provided schema exactly.');
    }
    lines.push(required
        ? '6) tool_choice is required for this turn: return at least one tool call.'
        : '6) If no tool is needed, plain text is allowed.');
    return lines.join('\n');
}
function ensureSystemMessage(messages) {
    const first = messages[0];
    if (isRecord(first) && readString(first.role).toLowerCase() === 'system') {
        return first;
    }
    const created = { role: 'system', content: '' };
    messages.unshift(created);
    return created;
}
function contentToText(content) {
    if (typeof content === 'string') {
        return content;
    }
    if (Array.isArray(content)) {
        const parts = [];
        for (const part of content) {
            if (typeof part === 'string') {
                parts.push(part);
                continue;
            }
            if (!isRecord(part))
                continue;
            const text = readString(part.text) || readString(part.content);
            if (text)
                parts.push(text);
        }
        return parts.join('\n').trim();
    }
    if (isRecord(content)) {
        const text = readString(content.text) || readString(content.content);
        if (text) {
            return text;
        }
        if (Array.isArray(content.content)) {
            return contentToText(content.content);
        }
    }
    return '';
}
function contentHasMarker(content, marker) {
    if (!marker) {
        return false;
    }
    const text = contentToText(content);
    return text.includes(marker);
}
function appendInstructionToContent(content, instruction) {
    if (typeof content === 'string') {
        return content.trim() ? `${content}\n\n${instruction}` : instruction;
    }
    if (Array.isArray(content)) {
        return [
            ...content,
            {
                type: 'text',
                text: content.length ? `\n\n${instruction}` : instruction
            }
        ];
    }
    if (isRecord(content)) {
        if (typeof content.text === 'string') {
            const previous = content.text;
            return {
                ...content,
                text: previous.trim() ? `${previous}\n\n${instruction}` : instruction
            };
        }
        if (typeof content.content === 'string') {
            const previous = content.content;
            return {
                ...content,
                content: previous.trim() ? `${previous}\n\n${instruction}` : instruction
            };
        }
        if (Array.isArray(content.content)) {
            return {
                ...content,
                content: appendInstructionToContent(content.content, instruction)
            };
        }
        return [content, { type: 'text', text: instruction }];
    }
    return instruction;
}
export function applyToolTextRequestGuidance(payload, config) {
    const enabled = config?.enabled !== false;
    if (!enabled) {
        return payload;
    }
    const root = structuredClone(payload);
    const requireTools = config?.requireTools !== false;
    if (requireTools) {
        const tools = Array.isArray(root.tools) ? root.tools : [];
        if (!tools.length) {
            return root;
        }
    }
    if (!Array.isArray(root.messages)) {
        return root;
    }
    const messages = root.messages.filter((item) => isRecord(item));
    if (!messages.length) {
        return root;
    }
    const instruction = readString(config?.instruction) || buildDefaultInstruction(root, config);
    if (!instruction) {
        return root;
    }
    const marker = readString(config?.marker) || 'Tool-call output contract (STRICT)';
    const system = ensureSystemMessage(messages);
    if (contentHasMarker(system.content, marker)) {
        root.messages = messages;
        return root;
    }
    system.content = appendInstructionToContent(system.content, instruction);
    root.messages = messages;
    return root;
}
