dashscopeTextToImage(
});
}
+ /**
+ * Edit or transform an image based on a text prompt and an input image.
+ *
+ * Logging contract: only the kind and length of {@code image_url} and the length of
+ * {@code prompt} are logged. Neither the reference itself nor the prompt text reaches the log,
+ * because the reference may be a Base64 data URL carrying the whole image.
+ *
+ * @param imageUrl The public URL, oss:// URL, local file path, or Base64 data URL of the
+ * input image to edit.
+ * @param prompt The text prompt describing the desired edit or transformation.
+ * @param model The image-edit model to use, e.g., 'qwen-image-edit'.
+ * @param size Size of the output image, e.g., '1024*1024'. Supported by the numbered
+ * generations (2.0 and later) and by the first-generation 'plus' and
+ * 'max' tiers.
+ * @param useBase64 Whether to return image as base64 data instead of URL.
+ * @return A ToolResultBlock containing the generated image url/base64 or error message.
+ */
+ @Tool(
+ name = "dashscope_image_to_image",
+ description =
+ "Edit or transform an existing image based on a text prompt and an input"
+ + " image. The input image must be reachable by the service: a public"
+ + " http(s) URL (the address an uploaded attachment is served from),"
+ + " an oss:// URL or a Base64 data URL. A path inside the sandbox"
+ + " workspace is not readable by this tool, so never invent one - ask"
+ + " for a link instead. Returns the edited image as URL or base64."
+ + " Use dashscope_text_to_image when there is no input image.")
+ public Mono dashscopeImageToImage(
+ @ToolParam(
+ name = "image_url",
+ description =
+ "The URL, local file path or Base64 data URL (the format"
+ + " pattern is data:[MIME_type];base64,{base64_image},"
+ + " e.g., 'data:image/png;base64,iVBORw0KGgo...') of"
+ + " the input image to edit")
+ String imageUrl,
+ @ToolParam(
+ name = "prompt",
+ description =
+ "The text prompt describing the desired edit or"
+ + " transformation")
+ String prompt,
+ @ToolParam(
+ name = "model",
+ description =
+ "The image-edit model to use, e.g., 'qwen-image-edit',"
+ + " 'qwen-image-edit-plus', 'qwen-image-edit-max',"
+ + " 'qwen-image-2.0-pro'. Every numbered generation"
+ + " (2.0 and later) edits an input image too."
+ + " Text-to-image models such as 'qwen-image' or"
+ + " 'wanx-v1' take no image input.",
+ required = false)
+ String model,
+ @ToolParam(
+ name = "size",
+ description =
+ "Size of the output image, e.g., '1024*1024', '1280*1280'."
+ + " Only supported by 'qwen-image-edit-plus',"
+ + " 'qwen-image-edit-max' and the numbered generations"
+ + " ('qwen-image-2.0' and later); otherwise the"
+ + " resolution follows the input image.",
+ required = false)
+ String size,
+ @ToolParam(
+ name = "use_base64",
+ description = "Whether to return image as base64 data instead of URL",
+ required = false)
+ Boolean useBase64) {
+
+ String finalModel =
+ Optional.ofNullable(model)
+ .filter(s -> !s.trim().isEmpty())
+ .orElse(DEFAULT_IMAGE_EDIT_MODEL);
+ Boolean finalUseBase64 = Optional.ofNullable(useBase64).orElse(false);
+
+ // Rejected before the request is built, so an unusable model costs no call. This also has
+ // to come first: resolving the size of a request that is about to be refused logs a
+ // warning about a parameter that is never sent.
+ if (rejectsImageInput(finalModel)) {
+ log.error(
+ "dashscope_image_to_image rejected model '{}': it takes no image input on this"
+ + " endpoint",
+ finalModel);
+ return Mono.just(ToolResultBlock.error(unsupportedEditModelMessage(finalModel)));
+ }
+
+ String finalSize = resolveOutputSize(finalModel, size);
+
+ log.debug(
+ "dashscope_image_to_image called: {}, model='{}', size='{}', useBase64='{}'",
+ describeEditRequest(imageUrl, prompt),
+ finalModel,
+ finalSize,
+ useBase64);
+
+ return Mono.fromCallable(
+ () -> {
+ // This endpoint takes exactly one message and its role must be `user`.
+ // A leading system message, or any second message, is rejected with
+ // "Input should be 'user'" / "messages parameter length invalid".
+ List