defmodule AI.Tools.TaskValidation do @moduledoc """ Explicit validation tool that wraps the heavy QA validator. Use this when you want to validate the set of completed tasks holistically. The tool will compute a change summary from the current task list. """ @behaviour AI.Tools @impl AI.Tools def async?, do: false @impl AI.Tools def is_available?, do: true @impl AI.Tools def read_args(args) when is_map(args), do: {:ok, args} @impl AI.Tools def ui_note_on_request(%{"task_list_id" => id}) do {"Validating tasks", "Task list: #{id}"} end @impl AI.Tools def ui_note_on_result(_args, result) do {"Validation complete", inspect(result)} end @impl AI.Tools def spec do %{ type: "function", function: %{ name: "task_validation_tool", description: "Run the heavy QA validator for the current set of completed tasks.", parameters: %{ type: "object", required: ["task_list_id", "requirements"], additionalProperties: false, properties: %{ task_list_id: %{ type: "string", description: "The ID of the task list to validate." }, requirements: %{ type: "string", description: "The overall project requirements text that the tasks aim to satisfy." }, change_summary: %{ type: "string", description: "Optional precomputed change summary. If not provided, it will be computed from the task list.", default: "" } } } } } end @impl AI.Tools def call(args) do with {:ok, task_list_id} <- AI.Tools.get_arg(args, "task_list_id"), {:ok, requirements} <- AI.Tools.get_arg(args, "requirements") do # Compute change summary if not provided change_summary = case Map.get(args, "change_summary") do s when is_binary(s) and s != "" -> s _ -> Services.Task.as_string(task_list_id, true) end AI.Agent.Code.TaskValidator |> AI.Agent.new() |> AI.Agent.get_response(%{ task_list_id: task_list_id, requirements: requirements, change_summary: change_summary }) end end end