Packages

A well-typed, idiomatic Gleam client for Anthropic's Claude API with streaming support and tool use

Current section

Files

Jump to
anthropic_gleam src anthropic@tool.erl
Raw

src/anthropic@tool.erl

-module(anthropic@tool).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/anthropic/tool.gleam").
-export([tool_name_unchecked/1, tool_name_to_string/1, tool_name_error_to_string/1, tool_name/1, property/1, property_with_description/2, enum_property/2, array_property/2, object_property/3, property_schema_to_json/1, empty_input_schema/0, input_schema/2, input_schema_to_json/1, tool_to_json/1, tool_to_json_string/1, tools_to_json/1, tool_choice_to_json/1, tool_result_id/1, is_tool_success/1]).
-export_type([tool_name_error/0, tool_name/0, property_schema/0, input_schema/0, tool/0, tool_choice/0, tool_call/0, tool_result/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.
?MODULEDOC(
" Tool definition types for the Anthropic Messages API\n"
"\n"
" This module defines types for tool definitions following the Anthropic schema.\n"
" Tools allow Claude to call external functions and receive results.\n"
"\n"
" ## Example\n"
"\n"
" ```gleam\n"
" import anthropic/types/tool.{tool_name, Tool, InputSchema}\n"
" import gleam/option.{None, Some}\n"
"\n"
" let assert Ok(name) = tool_name(\"get_weather\")\n"
" let weather_tool = Tool(\n"
" name: name,\n"
" description: Some(\"Get the current weather for a location\"),\n"
" input_schema: InputSchema(\n"
" schema_type: \"object\",\n"
" properties: Some([\n"
" #(\"location\", PropertySchema(\n"
" property_type: \"string\",\n"
" description: Some(\"City and state, e.g. 'San Francisco, CA'\"),\n"
" enum_values: None,\n"
" )),\n"
" ]),\n"
" required: Some([\"location\"]),\n"
" ),\n"
" )\n"
" ```\n"
).
-type tool_name_error() :: empty_tool_name |
{invalid_tool_name_characters, binary()} |
{tool_name_too_long, binary(), integer()}.
-opaque tool_name() :: {tool_name, binary()}.
-type property_schema() :: {property_schema,
binary(),
gleam@option:option(binary()),
gleam@option:option(list(binary())),
gleam@option:option(property_schema()),
gleam@option:option(list({binary(), property_schema()})),
gleam@option:option(list(binary()))}.
-type input_schema() :: {input_schema,
binary(),
gleam@option:option(list({binary(), property_schema()})),
gleam@option:option(list(binary()))}.
-type tool() :: {tool,
tool_name(),
gleam@option:option(binary()),
input_schema()}.
-type tool_choice() :: auto | any | {specific_tool, binary()} | no_tool.
-type tool_call() :: {tool_call, binary(), binary(), binary()}.
-type tool_result() :: {tool_success, binary(), binary()} |
{tool_failure, binary(), binary()}.
-file("src/anthropic/tool.gleam", 102).
?DOC(
" Create a ToolName without validation.\n"
"\n"
" Use this only when you trust the input, such as:\n"
" - Compile-time constants\n"
" - Values received from the Anthropic API\n"
" - Values already validated elsewhere\n"
"\n"
" For user input or untrusted sources, use `tool_name()` instead.\n"
).
-spec tool_name_unchecked(binary()) -> tool_name().
tool_name_unchecked(Raw) ->
{tool_name, Raw}.
-file("src/anthropic/tool.gleam", 109).
?DOC(
" Get the raw string value from a ToolName.\n"
"\n"
" Use this when you need to serialize the name to JSON or display it.\n"
).
-spec tool_name_to_string(tool_name()) -> binary().
tool_name_to_string(Name) ->
erlang:element(2, Name).
-file("src/anthropic/tool.gleam", 114).
?DOC(" Convert a ToolNameError to a human-readable string.\n").
-spec tool_name_error_to_string(tool_name_error()) -> binary().
tool_name_error_to_string(Error) ->
case Error of
empty_tool_name ->
<<"Tool name cannot be empty"/utf8>>;
{invalid_tool_name_characters, Name} ->
<<<<"Tool name '"/utf8, Name/binary>>/binary,
"' contains invalid characters (only a-z, A-Z, 0-9, _, - allowed)"/utf8>>;
{tool_name_too_long, Name@1, Length} ->
<<<<<<<<"Tool name '"/utf8, Name@1/binary>>/binary,
"' is too long ("/utf8>>/binary,
(gleam@string:inspect(Length))/binary>>/binary,
" characters, max 64)"/utf8>>
end.
-file("src/anthropic/tool.gleam", 138).
?DOC(" Check if a character is alphanumeric (a-z, A-Z, 0-9)\n").
-spec is_alphanumeric(binary()) -> boolean().
is_alphanumeric(Char) ->
case gleam@string:to_utf_codepoints(Char) of
[Codepoint] ->
Code = gleam_stdlib:identity(Codepoint),
(((Code >= 97) andalso (Code =< 122)) orelse ((Code >= 65) andalso (Code
=< 90)))
orelse ((Code >= 48) andalso (Code =< 57));
_ ->
false
end.
-file("src/anthropic/tool.gleam", 131).
?DOC(" Check if a string only contains valid tool name characters\n").
-spec is_valid_tool_name_string(binary()) -> boolean().
is_valid_tool_name_string(Name) ->
_pipe = Name,
_pipe@1 = gleam@string:to_graphemes(_pipe),
gleam@list:all(
_pipe@1,
fun(Char) ->
(is_alphanumeric(Char) orelse (Char =:= <<"_"/utf8>>)) orelse (Char
=:= <<"-"/utf8>>)
end
).
-file("src/anthropic/tool.gleam", 76).
?DOC(
" Create a validated tool name.\n"
"\n"
" Returns `Ok(ToolName)` if the name matches Anthropic's requirements:\n"
" - Non-empty\n"
" - Only alphanumeric characters, underscores, and hyphens\n"
" - Maximum 64 characters\n"
"\n"
" ## Examples\n"
"\n"
" ```gleam\n"
" tool_name(\"get_weather\") // Ok(ToolName)\n"
" tool_name(\"my-tool-123\") // Ok(ToolName)\n"
" tool_name(\"\") // Error(EmptyToolName)\n"
" tool_name(\"has spaces\") // Error(InvalidToolNameCharacters(...))\n"
" ```\n"
).
-spec tool_name(binary()) -> {ok, tool_name()} | {error, tool_name_error()}.
tool_name(Raw) ->
case Raw of
<<""/utf8>> ->
{error, empty_tool_name};
_ ->
Length = string:length(Raw),
case Length > 64 of
true ->
{error, {tool_name_too_long, Raw, Length}};
false ->
case is_valid_tool_name_string(Raw) of
true ->
{ok, {tool_name, Raw}};
false ->
{error, {invalid_tool_name_characters, Raw}}
end
end
end.
-file("src/anthropic/tool.gleam", 174).
?DOC(" Create a simple property schema with just a type\n").
-spec property(binary()) -> property_schema().
property(Property_type) ->
{property_schema, Property_type, none, none, none, none, none}.
-file("src/anthropic/tool.gleam", 186).
?DOC(" Create a property schema with type and description\n").
-spec property_with_description(binary(), binary()) -> property_schema().
property_with_description(Property_type, Description) ->
{property_schema,
Property_type,
{some, Description},
none,
none,
none,
none}.
-file("src/anthropic/tool.gleam", 201).
?DOC(" Create an enum property schema\n").
-spec enum_property(gleam@option:option(binary()), list(binary())) -> property_schema().
enum_property(Description, Values) ->
{property_schema,
<<"string"/utf8>>,
Description,
{some, Values},
none,
none,
none}.
-file("src/anthropic/tool.gleam", 216).
?DOC(" Create an array property schema\n").
-spec array_property(gleam@option:option(binary()), property_schema()) -> property_schema().
array_property(Description, Item_schema) ->
{property_schema,
<<"array"/utf8>>,
Description,
none,
{some, Item_schema},
none,
none}.
-file("src/anthropic/tool.gleam", 231).
?DOC(" Create an object property schema with nested properties\n").
-spec object_property(
gleam@option:option(binary()),
list({binary(), property_schema()}),
list(binary())
) -> property_schema().
object_property(Description, Properties, Required) ->
{property_schema,
<<"object"/utf8>>,
Description,
none,
none,
{some, Properties},
{some, Required}}.
-file("src/anthropic/tool.gleam", 247).
?DOC(" Encode a PropertySchema to JSON\n").
-spec property_schema_to_json(property_schema()) -> gleam@json:json().
property_schema_to_json(Schema) ->
Base_fields = [{<<"type"/utf8>>,
gleam@json:string(erlang:element(2, Schema))}],
With_description = case erlang:element(3, Schema) of
{some, Desc} ->
lists:append(
Base_fields,
[{<<"description"/utf8>>, gleam@json:string(Desc)}]
);
none ->
Base_fields
end,
With_enum = case erlang:element(4, Schema) of
{some, Values} ->
lists:append(
With_description,
[{<<"enum"/utf8>>,
gleam@json:array(Values, fun gleam@json:string/1)}]
);
none ->
With_description
end,
With_items = case erlang:element(5, Schema) of
{some, Item_schema} ->
lists:append(
With_enum,
[{<<"items"/utf8>>, property_schema_to_json(Item_schema)}]
);
none ->
With_enum
end,
With_properties = case erlang:element(6, Schema) of
{some, Props} ->
Props_json = begin
_pipe = Props,
gleam@list:map(
_pipe,
fun(Pair) ->
{Name, Prop_schema} = Pair,
{Name, property_schema_to_json(Prop_schema)}
end
)
end,
lists:append(
With_items,
[{<<"properties"/utf8>>, gleam@json:object(Props_json)}]
);
none ->
With_items
end,
With_required = case erlang:element(7, Schema) of
{some, Req} ->
lists:append(
With_properties,
[{<<"required"/utf8>>,
gleam@json:array(Req, fun gleam@json:string/1)}]
);
none ->
With_properties
end,
gleam@json:object(With_required).
-file("src/anthropic/tool.gleam", 311).
?DOC(" Create an empty input schema (for tools with no parameters)\n").
-spec empty_input_schema() -> input_schema().
empty_input_schema() ->
{input_schema, <<"object"/utf8>>, none, none}.
-file("src/anthropic/tool.gleam", 316).
?DOC(" Create an input schema with properties\n").
-spec input_schema(list({binary(), property_schema()}), list(binary())) -> input_schema().
input_schema(Properties, Required) ->
{input_schema, <<"object"/utf8>>, {some, Properties}, {some, Required}}.
-file("src/anthropic/tool.gleam", 328).
?DOC(" Encode an InputSchema to JSON\n").
-spec input_schema_to_json(input_schema()) -> gleam@json:json().
input_schema_to_json(Schema) ->
Base_fields = [{<<"type"/utf8>>,
gleam@json:string(erlang:element(2, Schema))}],
With_properties = case erlang:element(3, Schema) of
{some, Props} ->
Props_json = begin
_pipe = Props,
gleam@list:map(
_pipe,
fun(Pair) ->
{Name, Prop_schema} = Pair,
{Name, property_schema_to_json(Prop_schema)}
end
)
end,
lists:append(
Base_fields,
[{<<"properties"/utf8>>, gleam@json:object(Props_json)}]
);
none ->
Base_fields
end,
With_required = case erlang:element(4, Schema) of
{some, Req} ->
lists:append(
With_properties,
[{<<"required"/utf8>>,
gleam@json:array(Req, fun gleam@json:string/1)}]
);
none ->
With_properties
end,
gleam@json:object(With_required).
-file("src/anthropic/tool.gleam", 372).
?DOC(" Encode a Tool to JSON\n").
-spec tool_to_json(tool()) -> gleam@json:json().
tool_to_json(T) ->
Base_fields = [{<<"name"/utf8>>,
gleam@json:string(tool_name_to_string(erlang:element(2, T)))},
{<<"input_schema"/utf8>>, input_schema_to_json(erlang:element(4, T))}],
With_description = case erlang:element(3, T) of
{some, Desc} ->
lists:append(
Base_fields,
[{<<"description"/utf8>>, gleam@json:string(Desc)}]
);
none ->
Base_fields
end,
gleam@json:object(With_description).
-file("src/anthropic/tool.gleam", 388).
?DOC(" Convert a tool to a JSON string\n").
-spec tool_to_json_string(tool()) -> binary().
tool_to_json_string(T) ->
_pipe = T,
_pipe@1 = tool_to_json(_pipe),
gleam@json:to_string(_pipe@1).
-file("src/anthropic/tool.gleam", 395).
?DOC(" Encode a list of tools to JSON\n").
-spec tools_to_json(list(tool())) -> gleam@json:json().
tools_to_json(Tools) ->
gleam@json:array(Tools, fun tool_to_json/1).
-file("src/anthropic/tool.gleam", 416).
?DOC(" Encode a ToolChoice to JSON\n").
-spec tool_choice_to_json(tool_choice()) -> gleam@json:json().
tool_choice_to_json(Choice) ->
case Choice of
auto ->
gleam@json:object(
[{<<"type"/utf8>>, gleam@json:string(<<"auto"/utf8>>)}]
);
any ->
gleam@json:object(
[{<<"type"/utf8>>, gleam@json:string(<<"any"/utf8>>)}]
);
{specific_tool, Name} ->
gleam@json:object(
[{<<"type"/utf8>>, gleam@json:string(<<"tool"/utf8>>)},
{<<"name"/utf8>>, gleam@json:string(Name)}]
);
no_tool ->
gleam@json:object(
[{<<"type"/utf8>>, gleam@json:string(<<"none"/utf8>>)}]
)
end.
-file("src/anthropic/tool.gleam", 461).
?DOC(" Get the tool_use_id from a ToolResult\n").
-spec tool_result_id(tool_result()) -> binary().
tool_result_id(Result) ->
case Result of
{tool_success, Tool_use_id, _} ->
Tool_use_id;
{tool_failure, Tool_use_id@1, _} ->
Tool_use_id@1
end.
-file("src/anthropic/tool.gleam", 469).
?DOC(" Check if a tool result is successful\n").
-spec is_tool_success(tool_result()) -> boolean().
is_tool_success(Result) ->
case Result of
{tool_success, _, _} ->
true;
{tool_failure, _, _} ->
false
end.