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@tools.erl
Raw

src/anthropic@tools.erl

-module(anthropic@tools).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/anthropic/tools.gleam").
-export([needs_tool_execution/1, extract_tool_calls/1, get_tool_call_by_id/2, get_tool_calls_by_name/2, get_first_tool_call/1, count_tool_calls/1, get_tool_names/1, has_tool_call/2, tool_result_to_content_block/1, create_tool_result_message/1, build_tool_result_messages/3, build_continuation_messages/2, success_for_call/2, failure_for_call/2, execute_tool_calls/2, map_tool_calls/2, dispatch_tool_call/2, dispatch_tool_calls/2, all_tools_succeeded/1, any_tools_failed/1, get_failures/1, get_successes/1, get_error_message/1, get_success_content/1]).
-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 use utilities for handling the complete tool workflow\n"
"\n"
" This module provides utilities for:\n"
" - Extracting tool calls from responses\n"
" - Building tool result messages\n"
" - Managing the tool_use -> execute -> tool_result flow\n"
"\n"
" ## Tool Use Workflow\n"
"\n"
" 1. Send a request with tools defined\n"
" 2. Claude responds with tool_use blocks (stop_reason: \"tool_use\")\n"
" 3. Extract tool calls from the response\n"
" 4. Execute the tools and collect results\n"
" 5. Send a new request with tool_result blocks\n"
" 6. Claude responds with the final answer\n"
"\n"
" ## Example\n"
"\n"
" ```gleam\n"
" // Step 1: Create request with tools\n"
" let request = create_request(model, messages, max_tokens)\n"
" |> with_tools([weather_tool])\n"
"\n"
" // Step 2: Get response\n"
" let response = api.create_message(client, request)\n"
"\n"
" // Step 3: Check for tool use and extract calls\n"
" case needs_tool_execution(response) {\n"
" True -> {\n"
" let tool_calls = extract_tool_calls(response)\n"
" // Step 4: Execute tools and build results\n"
" let results = list.map(tool_calls, fn(call) {\n"
" let result = execute_my_tool(call.name, call.input)\n"
" tool_success(call.id, result)\n"
" })\n"
" // Step 5: Continue conversation with tool results\n"
" let messages = build_tool_result_messages(response, results)\n"
" let next_request = create_request(model, messages, max_tokens)\n"
" api.create_message(client, next_request)\n"
" }\n"
" False -> response\n"
" }\n"
" ```\n"
).
-file("src/anthropic/tools.gleam", 62).
?DOC(
" Check if a response requires tool execution\n"
" Returns True if stop_reason is ToolUse\n"
).
-spec needs_tool_execution(anthropic@types@request:create_message_response()) -> boolean().
needs_tool_execution(Response) ->
case erlang:element(7, Response) of
{some, tool_use} ->
true;
_ ->
false
end.
-file("src/anthropic/tools.gleam", 70).
?DOC(" Extract all tool calls from a response\n").
-spec extract_tool_calls(anthropic@types@request:create_message_response()) -> list(anthropic@types@tool:tool_call()).
extract_tool_calls(Response) ->
_pipe = erlang:element(5, Response),
gleam@list:filter_map(_pipe, fun(Block) -> case Block of
{tool_use_block, Id, Name, Input} ->
{ok, {tool_call, Id, Name, Input}};
_ ->
{error, nil}
end end).
-file("src/anthropic/tools.gleam", 82).
?DOC(" Extract a specific tool call by ID\n").
-spec get_tool_call_by_id(
anthropic@types@request:create_message_response(),
binary()
) -> {ok, anthropic@types@tool:tool_call()} | {error, nil}.
get_tool_call_by_id(Response, Tool_id) ->
_pipe = extract_tool_calls(Response),
gleam@list:find(_pipe, fun(Call) -> erlang:element(2, Call) =:= Tool_id end).
-file("src/anthropic/tools.gleam", 91).
?DOC(" Extract tool calls by name\n").
-spec get_tool_calls_by_name(
anthropic@types@request:create_message_response(),
binary()
) -> list(anthropic@types@tool:tool_call()).
get_tool_calls_by_name(Response, Tool_name) ->
_pipe = extract_tool_calls(Response),
gleam@list:filter(
_pipe,
fun(Call) -> erlang:element(3, Call) =:= Tool_name end
).
-file("src/anthropic/tools.gleam", 100).
?DOC(" Get the first tool call from a response\n").
-spec get_first_tool_call(anthropic@types@request:create_message_response()) -> {ok,
anthropic@types@tool:tool_call()} |
{error, nil}.
get_first_tool_call(Response) ->
_pipe = extract_tool_calls(Response),
gleam@list:first(_pipe).
-file("src/anthropic/tools.gleam", 108).
?DOC(" Count the number of tool calls in a response\n").
-spec count_tool_calls(anthropic@types@request:create_message_response()) -> integer().
count_tool_calls(Response) ->
_pipe = extract_tool_calls(Response),
erlang:length(_pipe).
-file("src/anthropic/tools.gleam", 114).
?DOC(" Get all unique tool names from a response\n").
-spec get_tool_names(anthropic@types@request:create_message_response()) -> list(binary()).
get_tool_names(Response) ->
_pipe = extract_tool_calls(Response),
_pipe@1 = gleam@list:map(_pipe, fun(Call) -> erlang:element(3, Call) end),
gleam@list:unique(_pipe@1).
-file("src/anthropic/tools.gleam", 121).
?DOC(" Check if a response contains a specific tool call\n").
-spec has_tool_call(anthropic@types@request:create_message_response(), binary()) -> boolean().
has_tool_call(Response, Tool_name) ->
_pipe = extract_tool_calls(Response),
gleam@list:any(
_pipe,
fun(Call) -> erlang:element(3, Call) =:= Tool_name end
).
-file("src/anthropic/tools.gleam", 131).
?DOC(" Create a tool result content block from a ToolResult\n").
-spec tool_result_to_content_block(anthropic@types@tool:tool_result()) -> anthropic@types@message:content_block().
tool_result_to_content_block(Result) ->
case Result of
{tool_success, Tool_use_id, Content} ->
{tool_result_block, Tool_use_id, Content, none};
{tool_failure, Tool_use_id@1, Error} ->
{tool_result_block, Tool_use_id@1, Error, {some, true}}
end.
-file("src/anthropic/tools.gleam", 149).
?DOC(" Create a user message with tool results\n").
-spec create_tool_result_message(list(anthropic@types@tool:tool_result())) -> anthropic@types@message:message().
create_tool_result_message(Results) ->
Content = gleam@list:map(Results, fun tool_result_to_content_block/1),
{message, user, Content}.
-file("src/anthropic/tools.gleam", 157).
?DOC(
" Build the complete message list for continuing a conversation after tool use\n"
" This includes the original messages, the assistant's tool use response,\n"
" and the user's tool results\n"
).
-spec build_tool_result_messages(
list(anthropic@types@message:message()),
anthropic@types@request:create_message_response(),
list(anthropic@types@tool:tool_result())
) -> list(anthropic@types@message:message()).
build_tool_result_messages(Original_messages, Assistant_response, Tool_results) ->
Assistant_message = {message,
assistant,
erlang:element(5, Assistant_response)},
Tool_result_message = create_tool_result_message(Tool_results),
lists:append(Original_messages, [Assistant_message, Tool_result_message]).
-file("src/anthropic/tools.gleam", 174).
?DOC(
" Simplified version: build messages from just the response and results\n"
" Assumes original messages are tracked elsewhere\n"
).
-spec build_continuation_messages(
anthropic@types@request:create_message_response(),
list(anthropic@types@tool:tool_result())
) -> list(anthropic@types@message:message()).
build_continuation_messages(Assistant_response, Tool_results) ->
Assistant_message = {message,
assistant,
erlang:element(5, Assistant_response)},
Tool_result_message = create_tool_result_message(Tool_results),
[Assistant_message, Tool_result_message].
-file("src/anthropic/tools.gleam", 189).
?DOC(" Create a successful tool result for a specific tool call\n").
-spec success_for_call(anthropic@types@tool:tool_call(), binary()) -> anthropic@types@tool:tool_result().
success_for_call(Call, Content) ->
{tool_success, erlang:element(2, Call), Content}.
-file("src/anthropic/tools.gleam", 194).
?DOC(" Create a failed tool result for a specific tool call\n").
-spec failure_for_call(anthropic@types@tool:tool_call(), binary()) -> anthropic@types@tool:tool_result().
failure_for_call(Call, Error) ->
{tool_failure, erlang:element(2, Call), Error}.
-file("src/anthropic/tools.gleam", 200).
?DOC(
" Execute a handler function on each tool call and collect results\n"
" The handler should return Ok(content) for success or Error(message) for failure\n"
).
-spec execute_tool_calls(
list(anthropic@types@tool:tool_call()),
fun((anthropic@types@tool:tool_call()) -> {ok, binary()} | {error, binary()})
) -> list(anthropic@types@tool:tool_result()).
execute_tool_calls(Calls, Handler) ->
gleam@list:map(Calls, fun(Call) -> case Handler(Call) of
{ok, Content} ->
{tool_success, erlang:element(2, Call), Content};
{error, Err} ->
{tool_failure, erlang:element(2, Call), Err}
end end).
-file("src/anthropic/tools.gleam", 213).
?DOC(" Execute a handler that returns a ToolResult directly\n").
-spec map_tool_calls(
list(anthropic@types@tool:tool_call()),
fun((anthropic@types@tool:tool_call()) -> anthropic@types@tool:tool_result())
) -> list(anthropic@types@tool:tool_result()).
map_tool_calls(Calls, Handler) ->
gleam@list:map(Calls, Handler).
-file("src/anthropic/tools.gleam", 222).
?DOC(
" Match a tool call by name and execute the appropriate handler\n"
" Returns an error message if no handler matches\n"
).
-spec dispatch_tool_call(
anthropic@types@tool:tool_call(),
list({binary(), fun((binary()) -> {ok, binary()} | {error, binary()})})
) -> anthropic@types@tool:tool_result().
dispatch_tool_call(Call, Handlers) ->
case gleam@list:find(
Handlers,
fun(H) -> erlang:element(1, H) =:= erlang:element(3, Call) end
) of
{ok, {_, Handler}} ->
case Handler(erlang:element(4, Call)) of
{ok, Content} ->
{tool_success, erlang:element(2, Call), Content};
{error, Err} ->
{tool_failure, erlang:element(2, Call), Err}
end;
{error, _} ->
{tool_failure,
erlang:element(2, Call),
<<"Unknown tool: "/utf8, (erlang:element(3, Call))/binary>>}
end.
-file("src/anthropic/tools.gleam", 239).
?DOC(" Dispatch multiple tool calls using a handler map\n").
-spec dispatch_tool_calls(
list(anthropic@types@tool:tool_call()),
list({binary(), fun((binary()) -> {ok, binary()} | {error, binary()})})
) -> list(anthropic@types@tool:tool_result()).
dispatch_tool_calls(Calls, Handlers) ->
gleam@list:map(Calls, fun(Call) -> dispatch_tool_call(Call, Handlers) end).
-file("src/anthropic/tools.gleam", 251).
?DOC(" Check if all tool results are successful\n").
-spec all_tools_succeeded(list(anthropic@types@tool:tool_result())) -> boolean().
all_tools_succeeded(Results) ->
gleam@list:all(Results, fun(R) -> case R of
{tool_success, _, _} ->
true;
{tool_failure, _, _} ->
false
end end).
-file("src/anthropic/tools.gleam", 261).
?DOC(" Check if any tool results failed\n").
-spec any_tools_failed(list(anthropic@types@tool:tool_result())) -> boolean().
any_tools_failed(Results) ->
gleam@list:any(Results, fun(R) -> case R of
{tool_success, _, _} ->
false;
{tool_failure, _, _} ->
true
end end).
-file("src/anthropic/tools.gleam", 271).
?DOC(" Get all failed tool results\n").
-spec get_failures(list(anthropic@types@tool:tool_result())) -> list(anthropic@types@tool:tool_result()).
get_failures(Results) ->
gleam@list:filter(Results, fun(R) -> case R of
{tool_success, _, _} ->
false;
{tool_failure, _, _} ->
true
end end).
-file("src/anthropic/tools.gleam", 281).
?DOC(" Get all successful tool results\n").
-spec get_successes(list(anthropic@types@tool:tool_result())) -> list(anthropic@types@tool:tool_result()).
get_successes(Results) ->
gleam@list:filter(Results, fun(R) -> case R of
{tool_success, _, _} ->
true;
{tool_failure, _, _} ->
false
end end).
-file("src/anthropic/tools.gleam", 291).
?DOC(" Get the error message from a ToolResult if it's a failure\n").
-spec get_error_message(anthropic@types@tool:tool_result()) -> gleam@option:option(binary()).
get_error_message(Result) ->
case Result of
{tool_success, _, _} ->
none;
{tool_failure, _, Error} ->
{some, Error}
end.
-file("src/anthropic/tools.gleam", 299).
?DOC(" Get the content from a ToolResult if it's a success\n").
-spec get_success_content(anthropic@types@tool:tool_result()) -> gleam@option:option(binary()).
get_success_content(Result) ->
case Result of
{tool_success, _, Content} ->
{some, Content};
{tool_failure, _, _} ->
none
end.