Current section

Files

Jump to
llm_composer lib llm_composer function_call_helpers.ex
Raw

lib/llm_composer/function_call_helpers.ex

defmodule LlmComposer.FunctionCallHelpers do
@moduledoc """
Helpers for building assistant messages and tool-result messages when handling
function (tool) calls returned by LLM providers.
This module provides a default implementation for composing the assistant
message that preserves the original assistant response and its function calls.
Providers can optionally implement `build_assistant_with_tools/3` to customize
behavior.
"""
alias LlmComposer.LlmResponse
alias LlmComposer.Message
@doc """
Build an assistant message that preserves the original assistant response and
its function calls so it can be sent back to the provider along with tool
result messages.
If `provider_mod` exports `build_assistant_with_tools/3`, this function will
delegate to that implementation; otherwise it uses a sensible default.
"""
@spec build_assistant_with_tools(module(), LlmResponse.t(), Message.t(), keyword()) ::
Message.t()
def build_assistant_with_tools(
provider_mod,
%LlmResponse{} = resp,
%Message{} = user_msg,
opts \\ []
) do
if function_exported?(provider_mod, :build_assistant_with_tools, 3) do
provider_mod.build_assistant_with_tools(resp, user_msg, opts)
else
%Message{
type: :assistant,
content: resp.main_response.content || "Using tool results",
function_calls: resp.main_response.function_calls,
metadata: %{
original: resp.main_response.metadata[:original]
}
}
end
end
@doc """
Convert executed function-call results into `:tool_result` messages which
include the mapping back to the tool call id in `metadata["tool_call_id"]`.
"""
@spec build_tool_result_messages(list()) :: list(Message.t())
def build_tool_result_messages(executed_calls) when is_list(executed_calls) do
Enum.map(executed_calls, fn call ->
%Message{
type: :tool_result,
content: to_string(call.result),
metadata: %{"tool_call_id" => call.id}
}
end)
end
end