Packages
A well-typed, idiomatic Gleam client for Anthropic's Claude API with streaming support and tool use
Current section
Files
Jump to
Current section
Files
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.