import { ReadableStream } from "@llamaindex/env";
import { getCallbackManager } from "../internal/settings/CallbackManager.js";
import { isAsyncIterable, prettifyError } from "../internal/utils.js";
export async function callTool(tool, toolCall, logger) {
    let input;
    if (typeof toolCall.input === "string") {
        try {
            input = JSON.parse(toolCall.input);
        } catch (e) {
            const output = `Tool ${toolCall.name} can't be called. Input is not a valid JSON object.`;
            logger.error(`${output} Try increasing the maxTokens parameter of your LLM. Invalid Input: ${toolCall.input}`);
            return {
                tool,
                input: {},
                output,
                isError: true
            };
        }
    } else {
        input = toolCall.input;
    }
    if (!tool) {
        logger.error(`Tool ${toolCall.name} does not exist.`);
        const output = `Tool ${toolCall.name} does not exist.`;
        return {
            tool,
            input,
            output,
            isError: true
        };
    }
    const call = tool.call;
    let output;
    if (!call) {
        logger.error(`Tool ${tool.metadata.name} (remote:${toolCall.name}) does not have a implementation.`);
        output = `Tool ${tool.metadata.name} (remote:${toolCall.name}) does not have a implementation.`;
        return {
            tool,
            input,
            output,
            isError: true
        };
    }
    try {
        getCallbackManager().dispatchEvent("llm-tool-call", {
            payload: {
                toolCall: {
                    ...toolCall,
                    input
                }
            }
        });
        output = await call.call(tool, input);
        logger.log(`Tool ${tool.metadata.name} (remote:${toolCall.name}) succeeded.`);
        logger.log(`Output: ${JSON.stringify(output)}`);
        const toolOutput = {
            tool,
            input,
            output,
            isError: false
        };
        getCallbackManager().dispatchEvent("llm-tool-result", {
            payload: {
                toolCall: {
                    ...toolCall,
                    input
                },
                toolResult: {
                    ...toolOutput
                }
            }
        });
        return toolOutput;
    } catch (e) {
        output = prettifyError(e);
        logger.error(`Tool ${tool.metadata.name} (remote:${toolCall.name}) failed: ${output}`);
    }
    return {
        tool,
        input,
        output,
        isError: true
    };
}
export async function consumeAsyncIterable(input, previousContent = "") {
    if (isAsyncIterable(input)) {
        const result = {
            content: previousContent,
            // only assistant will give streaming response
            role: "assistant",
            options: {}
        };
        for await (const chunk of input){
            result.content += chunk.delta;
            if (chunk.options) {
                result.options = {
                    ...result.options,
                    ...chunk.options
                };
            }
        }
        return result;
    } else {
        return input;
    }
}
export function createReadableStream(asyncIterable) {
    return new ReadableStream({
        async start (controller) {
            for await (const chunk of asyncIterable){
                controller.enqueue(chunk);
            }
            controller.close();
        }
    });
}
