import { BestAgentError } from "@best-agent/foundation";
import { resolveToolHeartbeatPolicy, resolveToolReplayPolicy, } from "../../tool/registry.js";
const TOOL_HEARTBEAT_POLL_INTERVAL_MS = 25;
const TOOL_HEARTBEAT_STALE_AFTER_MS = 250;
export async function executePreparedTool(input) {
    const { options, persistTerminalToolFailure, prepared, preparedToolResumeContext, runtime, shellDebugBase, toolCallId, toolDefinition, toolName, turn, } = input;
    let toolDispatchCheckpointId;
    let toolWorkerLeaseStatus = "failed";
    const toolReplayPolicy = resolveToolReplayPolicy(toolDefinition);
    if (options.resumeCheckpoint?.kind !== "tool-dispatch" &&
        (toolReplayPolicy === "never" ||
            toolReplayPolicy === "repair-only" ||
            toolName === "shell" ||
            toolDefinition.source === "mcp" ||
            toolDefinition.source === "plugin")) {
        if (shellDebugBase) {
            runtime.tracing.logShellToolDebug(runtime.cwd, "shell.dispatch_checkpoint.start", {
                ...shellDebugBase,
                callId: toolCallId,
            });
        }
        toolDispatchCheckpointId = await runtime.checkpointPersistence.saveToolDispatchCheckpoint(turn.id, {
            ...preparedToolResumeContext,
            toolCallId,
        });
        if (shellDebugBase) {
            runtime.tracing.logShellToolDebug(runtime.cwd, "shell.dispatch_checkpoint.done", {
                ...shellDebugBase,
                callId: toolCallId,
                checkpointId: toolDispatchCheckpointId,
            });
        }
    }
    const runtimeStart = runtime.runtimeSample.captureRuntimeSampleStart();
    const toolStartedAt = Date.now();
    const heartbeatPolicy = resolveToolHeartbeatPolicy(toolDefinition);
    const toolAbortController = new AbortController();
    const unregisterActiveToolAbortController = runtime.preparedTools.registerActiveToolAbortController(turn.id, toolAbortController);
    let toolHeartbeatAt = Date.now();
    const executionToolContext = runtime.preparedTools.createToolContext(turn, {
        abortSignal: toolAbortController.signal,
        heartbeat: () => {
            toolHeartbeatAt = Date.now();
        },
        reportOutput: (output) => {
            toolHeartbeatAt = Date.now();
            runtime.preparedTools.emitTurnToolOutputDelta(turn, toolCallId, toolName, output.stream, output.text);
        },
        setResultMetadata: input.setToolResultMetadata,
        sandboxProfile: input.executionSandboxProfile,
        webSearchBudget: input.webSearchBudget,
    });
    let output;
    try {
        if (shellDebugBase) {
            runtime.tracing.logShellToolDebug(runtime.cwd, "shell.execute.start", {
                ...shellDebugBase,
                callId: toolCallId,
                checkpointId: toolDispatchCheckpointId,
            });
        }
        output =
            heartbeatPolicy === "required"
                ? await new Promise((resolve, reject) => {
                    let settled = false;
                    const interval = setInterval(() => {
                        if (Date.now() - toolHeartbeatAt <= TOOL_HEARTBEAT_STALE_AFTER_MS) {
                            return;
                        }
                        settled = true;
                        clearInterval(interval);
                        reject(new BestAgentError("TOOL_HEARTBEAT_STALLED", `Tool ${toolName} exceeded the heartbeat timeout of ${TOOL_HEARTBEAT_STALE_AFTER_MS}ms.`));
                    }, TOOL_HEARTBEAT_POLL_INTERVAL_MS);
                    interval.unref?.();
                    void Promise.resolve(runtime.preparedTools.tools.executePrepared(toolName, prepared.normalizedInput, executionToolContext))
                        .then((value) => {
                        if (settled) {
                            return;
                        }
                        settled = true;
                        clearInterval(interval);
                        resolve(value);
                    })
                        .catch((error) => {
                        if (settled) {
                            return;
                        }
                        settled = true;
                        clearInterval(interval);
                        reject(error);
                    });
                })
                : await runtime.preparedTools.tools.executePrepared(toolName, prepared.normalizedInput, executionToolContext);
        if (shellDebugBase) {
            runtime.tracing.logShellToolDebug(runtime.cwd, "shell.execute.done", {
                ...shellDebugBase,
                callId: toolCallId,
                checkpointId: toolDispatchCheckpointId,
                elapsedMs: Date.now() - toolStartedAt,
                outputBytes: Buffer.byteLength(output, "utf8"),
            });
        }
        toolWorkerLeaseStatus = "completed";
    }
    catch (error) {
        if (shellDebugBase) {
            runtime.tracing.logShellToolDebug(runtime.cwd, "shell.execute.error", {
                ...shellDebugBase,
                callId: toolCallId,
                checkpointId: toolDispatchCheckpointId,
                elapsedMs: Date.now() - toolStartedAt,
                error: runtime.tracing.describeErrorForDebugLog(error),
            });
        }
        if (runtime.interruptions.isTurnTerminatedError(error)) {
            toolWorkerLeaseStatus = "abandoned";
        }
        const failureOutput = await persistTerminalToolFailure(toolCallId, prepared.normalizedInput, {
            ...preparedToolResumeContext,
            toolCallId,
        }, error);
        if (failureOutput !== undefined) {
            return { output: failureOutput, terminalFailureOutput: true, toolStartedAt };
        }
        throw error;
    }
    finally {
        unregisterActiveToolAbortController();
        if (toolDispatchCheckpointId && toolWorkerLeaseStatus !== "completed") {
            if (shellDebugBase) {
                runtime.tracing.logShellToolDebug(runtime.cwd, "shell.dispatch_checkpoint.complete.start", {
                    ...shellDebugBase,
                    callId: toolCallId,
                    checkpointId: toolDispatchCheckpointId,
                    workerLeaseStatus: toolWorkerLeaseStatus,
                });
            }
            await runtime.runCheckpoints
                .completeRunCheckpointById(turn.threadId, turn.id, toolDispatchCheckpointId, toolWorkerLeaseStatus)
                .catch((error) => {
                if (shellDebugBase) {
                    runtime.tracing.logShellToolDebug(runtime.cwd, "shell.dispatch_checkpoint.complete.error", {
                        ...shellDebugBase,
                        callId: toolCallId,
                        checkpointId: toolDispatchCheckpointId,
                        error: runtime.tracing.describeErrorForDebugLog(error),
                        workerLeaseStatus: toolWorkerLeaseStatus,
                    });
                }
                if (runtime.interruptions.isTurnTerminatedError(error) ||
                    (error instanceof BestAgentError && error.code === "RUN_ATTEMPT_FENCED")) {
                    return;
                }
                console.warn("[best-agent] Failed to finalize tool-dispatch checkpoint cleanup.", error);
            });
            if (shellDebugBase) {
                runtime.tracing.logShellToolDebug(runtime.cwd, "shell.dispatch_checkpoint.complete.done", {
                    ...shellDebugBase,
                    callId: toolCallId,
                    checkpointId: toolDispatchCheckpointId,
                    workerLeaseStatus: toolWorkerLeaseStatus,
                });
            }
        }
    }
    runtime.runtimeSample.memory.recordToolExecution(turn.threadId, runtime.runtimeSample.finishRuntimeSample(runtimeStart));
    return { output, toolStartedAt };
}
//# sourceMappingURL=prepared-tool-execution.js.map