Packages

fnord

0.9.38

AI code archaeology

Current section

Files

Jump to
fnord lib ai tools ui choose.ex
Raw

lib/ai/tools/ui/choose.ex

defmodule AI.Tools.UI.Choose do
@behaviour AI.Tools
@impl AI.Tools
def async?, do: false
@impl AI.Tools
def is_available?, do: true
@impl AI.Tools
def ui_note_on_request(%{prompt: prompt}), do: {"Choosing", prompt}
def ui_note_on_request(%{"prompt" => prompt}), do: {"Choosing", prompt}
@impl AI.Tools
def ui_note_on_result(_args, _result), do: nil
@impl AI.Tools
def tool_call_failure_message(_args, reason) do
case reason do
:no_tty -> {"No TTY", "Cannot prompt the user (no tty or quiet mode)."}
_ -> :default
end
end
@impl AI.Tools
def read_args(args), do: {:ok, args}
@impl AI.Tools
def spec do
%{
type: "function",
name: "ui_choose_tool",
description: """
Ask the user a multiple-choice question.
This tool automatically adds a final choice, "Something else", which
switches to a free-form prompt.
""",
parameters: %{
type: "object",
required: ["prompt", "options"],
additionalProperties: false,
properties: %{
prompt: %{
type: "string",
description: "The question/prompt to show the user."
},
options: %{
type: "array",
description: "List of options to present.",
items: %{type: "string"}
},
something_else_label: %{
type: "string",
description: "Optional label for the final free-form option.",
default: "Something else"
},
something_else_prompt: %{
type: "string",
description: "Prompt shown when the user chooses the free-form option.",
default: "Please specify"
}
}
}
}
end
@impl AI.Tools
def call(args) do
with {:ok, prompt} <- AI.Tools.get_arg(args, "prompt"),
{:ok, options} <- AI.Tools.get_arg(args, "options"),
{:ok, selection} <- choose(prompt, options, args) do
{:ok, selection}
end
end
defp choose(prompt, options, args) when is_list(options) do
something_else_label = Map.get(args, "something_else_label") || "Something else"
something_else_prompt = Map.get(args, "something_else_prompt") || "Please specify"
display_options =
options
|> Enum.reject(&(&1 == something_else_label))
|> Kernel.++([something_else_label])
case UI.choose(prompt, display_options) do
{:error, :no_tty} ->
{:error, :no_tty}
^something_else_label ->
case UI.prompt("#{something_else_prompt}:") do
{:error, :no_tty} -> {:error, :no_tty}
val -> {:ok, %{choice: :something_else, value: val}}
end
val ->
{:ok, %{choice: :option, value: val}}
end
end
end