// Force strict mode and setup for ESM
"use strict";
import {
  FileOperationEvent,
  getFileReadDefaultPermission,
  getSpecificMimeType,
  logFileOperation
} from "./chunk-NKHOVMWF.js";
import "./chunk-VGC4I5JJ.js";
import "./chunk-SGFT55XI.js";
import "./chunk-Y4IHBGBP.js";
import {
  BaseDeclarativeTool,
  BaseToolInvocation,
  ToolDisplayNames,
  ToolNames
} from "./chunk-Y6AXW2OG.js";
import "./chunk-2M3XQKPR.js";
import "./chunk-46UV252V.js";
import "./chunk-ZBVS26BY.js";
import "./chunk-WZRWHXFE.js";
import "./chunk-A3NDJ5SB.js";
import "./chunk-7XATOOE7.js";
import "./chunk-BGTQCTQW.js";
import "./chunk-W4RQUHY3.js";
import "./chunk-S7W2GKIO.js";
import {
  makeRelative,
  shortenPath,
  unescapePath
} from "./chunk-UHUSJ6X7.js";
import "./chunk-VOQXFAY5.js";
import "./chunk-75DOP5OR.js";
import "./chunk-DMTGGOSA.js";
import "./chunk-YQ3U5MUC.js";
import "./chunk-QUGAUQGJ.js";
import {
  init_esbuild_shims
} from "./chunk-5O2XNYP6.js";
import {
  __name
} from "./chunk-J2S4EL5Y.js";

// packages/core/src/tools/zoom-image.ts
init_esbuild_shims();
import path from "node:path";
import fs from "node:fs/promises";
var IMAGE_VIEW_MAX_EDGE = 1568;
var IMAGE_VIEW_MAX_PATCHES = 1568;
var IMAGE_PATCH_SIZE = 28;
var IMAGE_MAX_UPSCALE = 8;
var IMAGE_JPEG_QUALITY = 92;
var IMAGE_MAX_SOURCE_BYTES = 100 * 1024 * 1024;
var IMAGE_MAX_OUTPUT_BYTES = 9 * 1024 * 1024;
var SUPPORTED_IMAGE_FORMATS = /* @__PURE__ */ new Set(["jpeg", "png", "webp"]);
function failureResult(message, type) {
  return {
    llmContent: message,
    returnDisplay: message,
    error: { message, type }
  };
}
__name(failureResult, "failureResult");
function fitsVisualBudget({ width, height }) {
  return width <= IMAGE_VIEW_MAX_EDGE && height <= IMAGE_VIEW_MAX_EDGE && Math.ceil(width / IMAGE_PATCH_SIZE) * Math.ceil(height / IMAGE_PATCH_SIZE) <= IMAGE_VIEW_MAX_PATCHES;
}
__name(fitsVisualBudget, "fitsVisualBudget");
function magnifiedSize(width, height) {
  const widthIsLongEdge = width >= height;
  const maxLongEdge = Math.min(
    IMAGE_VIEW_MAX_EDGE,
    Math.max(width, height) * IMAGE_MAX_UPSCALE
  );
  let low = 1;
  let high = maxLongEdge;
  let best = { width: 1, height: 1 };
  while (low <= high) {
    const longEdge = Math.floor((low + high) / 2);
    const candidate = widthIsLongEdge ? {
      width: longEdge,
      height: Math.max(1, Math.round(height / width * longEdge))
    } : {
      width: Math.max(1, Math.round(width / height * longEdge)),
      height: longEdge
    };
    if (fitsVisualBudget(candidate)) {
      best = candidate;
      low = longEdge + 1;
    } else {
      high = longEdge - 1;
    }
  }
  return best;
}
__name(magnifiedSize, "magnifiedSize");
var ZoomImageInvocation = class extends BaseToolInvocation {
  constructor(config, params) {
    super(params);
    this.config = config;
  }
  static {
    __name(this, "ZoomImageInvocation");
  }
  getDescription() {
    const relativePath = makeRelative(
      this.params.file_path,
      this.config.getTargetDir()
    );
    return `${shortenPath(relativePath)} (${this.params.x1},${this.params.y1})-(${this.params.x2},${this.params.y2})`;
  }
  toolLocations() {
    return [{ path: this.params.file_path }];
  }
  getDefaultPermission() {
    return Promise.resolve(
      getFileReadDefaultPermission(this.config, this.params.file_path)
    );
  }
  async execute(signal) {
    signal.throwIfAborted();
    if (this.config.getEffectiveInputModalities().image !== true) {
      return failureResult(
        "zoom_image requires a model that accepts image inputs, but the current model does not. Switch to an image-capable model to zoom images.",
        "read_content_failure" /* READ_CONTENT_FAILURE */
      );
    }
    let sharp;
    try {
      sharp = (await import("sharp")).default;
    } catch {
      return failureResult(
        'zoom_image is unavailable because the "sharp" image module could not be loaded.',
        "read_content_failure" /* READ_CONTENT_FAILURE */
      );
    }
    let stats;
    try {
      stats = await fs.stat(this.params.file_path);
    } catch (error) {
      if (error.code === "ENOENT") {
        return failureResult(
          `Image file not found: ${this.params.file_path}`,
          "file_not_found" /* FILE_NOT_FOUND */
        );
      }
      throw error;
    }
    if (stats.isDirectory()) {
      return failureResult(
        `Image path is a directory: ${this.params.file_path}`,
        "target_is_directory" /* TARGET_IS_DIRECTORY */
      );
    }
    if (!stats.isFile()) {
      return failureResult(
        `Image path is not a regular file: ${this.params.file_path}`,
        "target_not_regular_file" /* TARGET_NOT_REGULAR_FILE */
      );
    }
    if (stats.size > IMAGE_MAX_SOURCE_BYTES) {
      return failureResult(
        `Image file exceeds the 100 MB source limit: ${this.params.file_path}`,
        "file_too_large" /* FILE_TOO_LARGE */
      );
    }
    let metadata;
    try {
      metadata = await sharp(this.params.file_path, {
        failOn: "error",
        limitInputPixels: true
      }).metadata();
    } catch {
      return failureResult(
        `Unsupported image. zoom_image accepts static PNG, JPEG, or WebP files: ${this.params.file_path}`,
        "read_content_failure" /* READ_CONTENT_FAILURE */
      );
    }
    signal.throwIfAborted();
    if (!SUPPORTED_IMAGE_FORMATS.has(metadata.format)) {
      return failureResult(
        `Unsupported image. zoom_image accepts static PNG, JPEG, or WebP files: ${this.params.file_path}`,
        "read_content_failure" /* READ_CONTENT_FAILURE */
      );
    }
    if ((metadata.pages ?? 1) > 1) {
      return failureResult(
        `zoom_image accepts static images only: ${this.params.file_path}`,
        "read_content_failure" /* READ_CONTENT_FAILURE */
      );
    }
    const sourceWidth = metadata.autoOrient.width;
    const sourceHeight = metadata.autoOrient.height;
    const left = Math.min(
      sourceWidth - 1,
      Math.max(0, Math.floor(this.params.x1 / 1e3 * sourceWidth))
    );
    const top = Math.min(
      sourceHeight - 1,
      Math.max(0, Math.floor(this.params.y1 / 1e3 * sourceHeight))
    );
    const right = Math.min(
      sourceWidth,
      Math.max(left + 1, Math.ceil(this.params.x2 / 1e3 * sourceWidth))
    );
    const bottom = Math.min(
      sourceHeight,
      Math.max(top + 1, Math.ceil(this.params.y2 / 1e3 * sourceHeight))
    );
    const cropWidth = right - left;
    const cropHeight = bottom - top;
    const outputSize = magnifiedSize(cropWidth, cropHeight);
    let output;
    try {
      output = await sharp(this.params.file_path, {
        autoOrient: true,
        failOn: "error",
        limitInputPixels: true
      }).extract({ left, top, width: cropWidth, height: cropHeight }).resize(outputSize.width, outputSize.height, {
        fit: "fill",
        kernel: sharp.kernel.lanczos3
      }).flatten({ background: "#ffffff" }).jpeg({
        quality: IMAGE_JPEG_QUALITY,
        chromaSubsampling: "4:4:4"
      }).toBuffer();
    } catch {
      signal.throwIfAborted();
      return failureResult(
        `Failed to decode image: ${this.params.file_path}`,
        "read_content_failure" /* READ_CONTENT_FAILURE */
      );
    }
    signal.throwIfAborted();
    if (output.length > IMAGE_MAX_OUTPUT_BYTES) {
      return failureResult(
        `Zoomed image exceeds the 9 MB output limit: ${this.params.file_path}`,
        "file_too_large" /* FILE_TOO_LARGE */
      );
    }
    const text = `Zoomed normalized region (${this.params.x1},${this.params.y1})-(${this.params.x2},${this.params.y2}) from ${this.params.file_path}. Oriented source: ${sourceWidth}x${sourceHeight}; source crop: ${cropWidth}x${cropHeight}; returned view: ${outputSize.width}x${outputSize.height}.`;
    const llmContent = [
      { text },
      {
        inlineData: {
          mimeType: "image/jpeg",
          data: output.toString("base64")
        }
      }
    ];
    logFileOperation(
      this.config,
      new FileOperationEvent(
        ZoomImageTool.Name,
        "read" /* READ */,
        void 0,
        getSpecificMimeType(this.params.file_path),
        path.extname(this.params.file_path)
      )
    );
    return {
      llmContent,
      returnDisplay: `Zoomed image: ${shortenPath(
        makeRelative(this.params.file_path, this.config.getTargetDir())
      )}`
    };
  }
};
var ZoomImageTool = class _ZoomImageTool extends BaseDeclarativeTool {
  constructor(config) {
    super(
      _ZoomImageTool.Name,
      ToolDisplayNames.ZOOM_IMAGE,
      "Crops a region from a full-resolution static image and returns a magnified view. Coordinates are integers normalized from 0 to 1000 against the displayed image, with (0,0) at top-left and (1000,1000) at bottom-right. Use this when text, numbers, lines, or other details are too small to inspect confidently. You may call it repeatedly; coordinates always refer to the original full-resolution image, never to a previously returned view.",
      "read" /* Read */,
      {
        type: "object",
        properties: {
          file_path: {
            type: "string",
            description: "Absolute path to a static PNG, JPEG, or WebP image."
          },
          x1: {
            type: "integer",
            minimum: 0,
            maximum: 1e3,
            description: "Left edge in normalized image coordinates."
          },
          y1: {
            type: "integer",
            minimum: 0,
            maximum: 1e3,
            description: "Top edge in normalized image coordinates."
          },
          x2: {
            type: "integer",
            minimum: 0,
            maximum: 1e3,
            description: "Right edge in normalized image coordinates."
          },
          y2: {
            type: "integer",
            minimum: 0,
            maximum: 1e3,
            description: "Bottom edge in normalized image coordinates."
          }
        },
        required: ["file_path", "x1", "y1", "x2", "y2"]
      },
      true,
      false,
      true,
      false,
      "zoom crop magnify image picture screenshot chart diagram small text detail"
    );
    this.config = config;
  }
  static {
    __name(this, "ZoomImageTool");
  }
  static Name = ToolNames.ZOOM_IMAGE;
  validateToolParamValues(params) {
    params.file_path = unescapePath(params.file_path.trim());
    if (!params.file_path) {
      return "The 'file_path' parameter must be non-empty.";
    }
    if (!path.isAbsolute(params.file_path)) {
      return `File path must be absolute, but was relative: ${params.file_path}.`;
    }
    if (params.x1 >= params.x2) {
      return "x1 must be less than x2.";
    }
    if (params.y1 >= params.y2) {
      return "y1 must be less than y2.";
    }
    const fileService = this.config.getFileService();
    if (fileService.shouldQwenIgnoreFile(params.file_path)) {
      return `File path '${params.file_path}' is ignored by ${fileService.getQwenIgnoreFileDisplayForPath(params.file_path)} pattern(s).`;
    }
    return null;
  }
  createInvocation(params) {
    return new ZoomImageInvocation(this.config, params);
  }
};
export {
  ZoomImageTool
};
/**
 * @license
 * Copyright 2026 Qwen
 * SPDX-License-Identifier: Apache-2.0
 */
