-module(claude@types@tool). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/claude/types/tool.gleam"). -export([registry/0, register/2, dispatch/3, to_json/1, unregister/2, is_empty/1]). -export_type([tool/1, erased_tool/0, registry/0, tool_choice/0]). -if(?OTP_RELEASE >= 27). -define(MODULEDOC(Str), -moduledoc(Str)). -define(DOC(Str), -doc(Str)). -else. -define(MODULEDOC(Str), -compile([])). -define(DOC(Str), -compile([])). -endif. -type tool(HII) :: {tool, binary(), binary(), glon:json_schema(HII), fun((HII) -> {ok, binary()} | {error, binary()})}. -type erased_tool() :: {erased_tool, binary(), binary(), gleam@json:json(), fun((binary()) -> {ok, binary()} | {error, binary()})}. -opaque registry() :: {registry, gleam@dict:dict(binary(), erased_tool())}. -type tool_choice() :: {auto, boolean()} | {any, boolean()} | {specific_tool, binary(), boolean()} | no_tools. -file("src/claude/types/tool.gleam", 28). ?DOC(" Erase a typed tool into the internal representation.\n"). -spec erase(tool(any())) -> erased_tool(). erase(Tool) -> {erased_tool, erlang:element(2, Tool), erlang:element(3, Tool), glon:to_json(erlang:element(4, Tool)), fun(Input) -> case glon:decode(erlang:element(4, Tool), Input) of {ok, Params} -> (erlang:element(5, Tool))(Params); {error, _} -> {error, <<"Failed to decode tool input for: "/utf8, (erlang:element(2, Tool))/binary>>} end end}. -file("src/claude/types/tool.gleam", 48). ?DOC(" Create an empty tool registry.\n"). -spec registry() -> registry(). registry() -> {registry, maps:new()}. -file("src/claude/types/tool.gleam", 54). ?DOC( " Register a typed tool. Erases the type parameter internally.\n" " Pipeable: `registry() |> register(weather_tool()) |> register(search_tool())`\n" ). -spec register(registry(), tool(any())) -> registry(). register(Reg, Tool) -> T = erase(Tool), {registry, gleam@dict:insert(erlang:element(2, Reg), erlang:element(2, T), T)}. -file("src/claude/types/tool.gleam", 66). ?DOC( " Dispatch a tool call by name. Used by the tool runner.\n" "\n" " The input string is parsed from JSON on each call. This is a known\n" " trade-off: tool input is stored as a JSON string for conversation history\n" " serialization, requiring a parse-serialize-parse cycle when the API response\n" " is decoded and then dispatched. A future optimization could pass the raw\n" " Dynamic value directly to avoid the redundant JSON round-trip.\n" ). -spec dispatch(registry(), binary(), binary()) -> {ok, binary()} | {error, binary()}. dispatch(Reg, Name, Input) -> case gleam_stdlib:map_get(erlang:element(2, Reg), Name) of {ok, Tool} -> (erlang:element(5, Tool))(Input); {error, _} -> {error, <<"Unknown tool: "/utf8, Name/binary>>} end. -file("src/claude/types/tool.gleam", 78). ?DOC(" Encode all tools as a JSON array for the API request.\n"). -spec to_json(registry()) -> gleam@json:json(). to_json(Reg) -> _pipe = maps:values(erlang:element(2, Reg)), gleam@json:array( _pipe, fun(T) -> gleam@json:object( [{<<"name"/utf8>>, gleam@json:string(erlang:element(2, T))}, {<<"description"/utf8>>, gleam@json:string(erlang:element(3, T))}, {<<"input_schema"/utf8>>, erlang:element(4, T)}] ) end ). -file("src/claude/types/tool.gleam", 90). ?DOC(" Remove a tool by name.\n"). -spec unregister(registry(), binary()) -> registry(). unregister(Reg, Name) -> {registry, gleam@dict:delete(erlang:element(2, Reg), Name)}. -file("src/claude/types/tool.gleam", 95). ?DOC(" Check if the registry is empty.\n"). -spec is_empty(registry()) -> boolean(). is_empty(Reg) -> gleam@dict:is_empty(erlang:element(2, Reg)).