"use strict";
Object.defineProperty(exports, "__esModule", {
    value: true
});
function _export(target, all) {
    for(var name in all)Object.defineProperty(target, name, {
        enumerable: true,
        get: all[name]
    });
}
_export(exports, {
    OpenAIAgent: function() {
        return OpenAIAgent;
    },
    OpenAIAgentWorker: function() {
        return OpenAIAgentWorker;
    }
});
const _env = require("@llamaindex/env");
const _Settings = require("../Settings.js");
const _utils = require("../internal/utils.js");
const _openai = require("../llm/openai.js");
const _base = require("./base.js");
const _utils1 = require("./utils.js");
class OpenAIAgentWorker extends _base.AgentWorker {
    taskHandler = OpenAIAgent.taskHandler;
}
class OpenAIAgent extends _base.AgentRunner {
    constructor(params){
        super({
            llm: params.llm ?? (_Settings.Settings.llm instanceof _openai.OpenAI ? _Settings.Settings.llm : new _openai.OpenAI()),
            chatHistory: params.chatHistory ?? [],
            runner: new OpenAIAgentWorker(),
            systemPrompt: params.systemPrompt ?? null,
            tools: "tools" in params ? params.tools : params.toolRetriever.retrieve.bind(params.toolRetriever),
            verbose: params.verbose ?? false
        });
    }
    createStore = _base.AgentRunner.defaultCreateStore;
    static taskHandler = async (step, enqueueOutput)=>{
        const { llm, stream, getTools } = step.context;
        const lastMessage = step.context.store.messages.at(-1).content;
        const tools = await getTools(lastMessage);
        const response = await llm.chat({
            // @ts-expect-error
            stream,
            tools,
            messages: [
                ...step.context.store.messages
            ]
        });
        if (!stream) {
            step.context.store.messages = [
                ...step.context.store.messages,
                response.message
            ];
            const options = response.message.options ?? {};
            enqueueOutput({
                taskStep: step,
                output: response,
                isLast: !("toolCall" in options)
            });
            if ("toolCall" in options) {
                const { toolCall } = options;
                for (const call of toolCall){
                    const targetTool = tools.find((tool)=>tool.metadata.name === call.name);
                    const toolOutput = await (0, _utils1.callTool)(targetTool, call, step.context.logger);
                    step.context.store.toolOutputs.push(toolOutput);
                    step.context.store.messages = [
                        ...step.context.store.messages,
                        {
                            role: "user",
                            content: (0, _utils.stringifyJSONToMessageContent)(toolOutput.output),
                            options: {
                                toolResult: {
                                    result: toolOutput.output,
                                    isError: toolOutput.isError,
                                    id: call.id
                                }
                            }
                        }
                    ];
                }
            }
        } else {
            const responseChunkStream = new _env.ReadableStream({
                async start (controller) {
                    for await (const chunk of response){
                        controller.enqueue(chunk);
                    }
                    controller.close();
                }
            });
            const [pipStream, finalStream] = responseChunkStream.tee();
            const reader = pipStream.getReader();
            const { value } = await reader.read();
            reader.releaseLock();
            if (value === undefined) {
                throw new Error("first chunk value is undefined, this should not happen");
            }
            // check if first chunk has tool calls, if so, this is a function call
            // otherwise, it's a regular message
            const hasToolCall = !!(value.options && "toolCall" in value.options);
            enqueueOutput({
                taskStep: step,
                output: finalStream,
                isLast: !hasToolCall
            });
            if (hasToolCall) {
                // you need to consume the response to get the full toolCalls
                const toolCalls = new Map();
                for await (const chunk of pipStream){
                    if (chunk.options && "toolCall" in chunk.options) {
                        const toolCall = chunk.options.toolCall;
                        toolCall.forEach((toolCall)=>{
                            toolCalls.set(toolCall.id, toolCall);
                        });
                    }
                }
                step.context.store.messages = [
                    ...step.context.store.messages,
                    {
                        role: "assistant",
                        content: "",
                        options: {
                            toolCall: [
                                ...toolCalls.values()
                            ]
                        }
                    }
                ];
                for (const toolCall of toolCalls.values()){
                    const targetTool = tools.find((tool)=>tool.metadata.name === toolCall.name);
                    const toolOutput = await (0, _utils1.callTool)(targetTool, toolCall, step.context.logger);
                    step.context.store.messages = [
                        ...step.context.store.messages,
                        {
                            role: "user",
                            content: (0, _utils.stringifyJSONToMessageContent)(toolOutput.output),
                            options: {
                                toolResult: {
                                    result: toolOutput.output,
                                    isError: toolOutput.isError,
                                    id: toolCall.id
                                }
                            }
                        }
                    ];
                    step.context.store.toolOutputs.push(toolOutput);
                }
            }
        }
    };
}
