import { BestAgentError } from "@best-agent/foundation";
import { DELEGATE_TASKS_TOOL_NAME } from "../../provider/provider-tool-names.js";
import { executeAskUserTool } from "./ask-user-tool-execution.js";
import { executeDelegateTool } from "./delegate-tool-execution.js";
import { executePreparedTool } from "./prepared-tool-execution.js";
import { authorizeToolExecutionFlow } from "./tool-execution-authorization-flow.js";
import { finalizeExecutedToolResult } from "./tool-execution-finalizer.js";
import { createToolFailurePersistence } from "./tool-failure-persistence.js";
import { appendToolReasoningPrelude, prepareToolInvocationForExecution, } from "./tool-preparation-runner.js";
export class ToolExecutionRunner {
    #runtime;
    constructor(runtime) {
        this.#runtime = runtime;
    }
    async execute(request) {
        const { approvalTurn, input: toolInput, previewCallId, profile, reasoning, toolName, turn, } = request;
        const activeSkillIds = request.activeSkillIds ?? [];
        const options = request.options ?? {};
        const input = toolInput;
        const runtime = this.#runtime;
        const shellDebugBase = toolName === "shell"
            ? {
                profileName: profile.name,
                threadId: turn.threadId,
                turnId: turn.id,
            }
            : undefined;
        if (shellDebugBase) {
            runtime.tracing.logShellToolDebug(runtime.cwd, "shell.invocation.start", {
                ...shellDebugBase,
                input: runtime.formatting.previewToolInputForDebugLog(input),
                previewCallId,
                resumeCheckpointKind: options.resumeCheckpoint?.kind,
                skipPrelude: options.skipPrelude,
            });
        }
        await runtime.turnState.assertTurnAttemptWritable(turn.id);
        const currentPhaseName = (await runtime.turnState.getRunByTurn(turn.id))?.phaseName;
        const threadMode = await runtime.turnState.getThreadMode(turn.threadId);
        const normalizedReasoning = toolName === DELEGATE_TASKS_TOOL_NAME && reasoning
            ? runtime.formatting.stripChildPersistenceDirectives(reasoning)
            : reasoning;
        if (threadMode !== "plan" && !profile.allowedTools.includes(toolName)) {
            throw new BestAgentError("TOOL_NOT_ALLOWED", `Tool ${toolName} is not allowed by the ${profile.name} profile.`);
        }
        let toolResultMetadata;
        const appendReasoningPrelude = async () => {
            await appendToolReasoningPrelude({
                options,
                profile,
                reasoning: normalizedReasoning,
                runtime,
                toolName,
                turn,
            });
        };
        const delayReasoningPreludeForReplay = options.customLoopReplay !== undefined;
        if (!delayReasoningPreludeForReplay) {
            await appendReasoningPrelude();
        }
        const persistTerminalToolFailure = createToolFailurePersistence({
            getToolResultMetadata: () => toolResultMetadata,
            runtime,
            shellDebugBase,
            toolName,
            turn,
        });
        if (toolName === DELEGATE_TASKS_TOOL_NAME) {
            return executeDelegateTool({
                activeSkillIds,
                appendReasoningPrelude,
                approvalTurn,
                currentPhaseName,
                delayReasoningPreludeForReplay,
                options,
                persistTerminalToolFailure,
                previewCallId,
                profile,
                reasoning: normalizedReasoning,
                runtime,
                toolInput: input,
                turn,
            });
        }
        const preparation = await prepareToolInvocationForExecution({
            activeSkillIds,
            approvalTurn,
            currentPhaseName,
            options,
            persistTerminalToolFailure,
            previewCallId,
            profile,
            reasoning: normalizedReasoning,
            runtime,
            shellDebugBase,
            toolInput: input,
            toolName,
            turn,
        });
        if (preparation.kind !== "prepared") {
            return preparation.output;
        }
        const { prepared, preparedToolResumeContext, toolResumeContext } = preparation;
        if (delayReasoningPreludeForReplay) {
            await appendReasoningPrelude();
        }
        const authorizationTurn = approvalTurn ?? turn;
        const authorized = await authorizeToolExecutionFlow({
            authorizationTurn,
            options,
            persistTerminalToolFailure,
            prepared,
            preparedToolResumeContext,
            previewCallId,
            profile,
            runtime,
            shellDebugBase,
            threadMode,
            toolName,
            toolResumeContext,
            turn,
        });
        if (authorized.kind !== "authorized") {
            return authorized.output;
        }
        if (toolName === "ask-user") {
            return executeAskUserTool({
                options,
                persistTerminalToolFailure,
                prepared,
                preparedToolResumeContext,
                profileName: profile.name,
                runtime,
                toolCallId: authorized.toolCallId,
                turn,
            });
        }
        const executedTool = await executePreparedTool({
            executionSandboxProfile: authorized.executionSandboxProfile,
            options,
            persistTerminalToolFailure,
            prepared,
            preparedToolResumeContext,
            runtime,
            setToolResultMetadata: (metadata) => {
                toolResultMetadata = metadata;
            },
            shellDebugBase,
            toolCallId: authorized.toolCallId,
            toolDefinition: authorized.toolDefinition,
            toolName,
            turn,
            webSearchBudget: authorized.webSearchBudget,
        });
        if (executedTool.terminalFailureOutput) {
            return executedTool.output;
        }
        return finalizeExecutedToolResult({
            output: executedTool.output,
            persistTerminalToolFailure,
            prepared,
            preparedToolResumeContext,
            profile,
            resultMetadata: toolResultMetadata,
            runtime,
            shellDebugBase,
            toolCallId: authorized.toolCallId,
            toolName,
            toolStartedAt: executedTool.toolStartedAt,
            turn,
        });
    }
}
//# sourceMappingURL=tool-execution-runner.js.map