AI.Completion (fnord v0.9.29)
View SourceThis module sends a request to the model and handles the response. It is able to handle tool calls and responses.
Input options
toolbox- a map of tool names to modules implementingAI.Tools; the specs list is derived automatically viaAI.Tools.toolbox_to_specs/1.
Output options
Output is controlled by the following mechanisms.
log_msgs- log messages from the user and assistant asinfolog_tool_calls- log tool calls asinfoand tool call results asdebug
LOGGER_LEVEL must be set to debug to see the output of tool call results.
Summary
Functions
If a tool produced a very large textual output, attempt to write it to a temporary file and replace the in-memory content with a short placeholder that points to the temp file and includes a preview. Fail silently and return the original content on any error.
Returns a map of tool names to the number of times each tool was called during this completion round - that is, in messages that were appended after AI.Completion.new/1 captured the starting message length.
Types
@type response() :: {:ok, t()} | {:error, t()} | {:error, binary()} | {:error, :context_length_exceeded, non_neg_integer()}
@type t() :: %AI.Completion{ archive_notes: boolean(), compact?: bool(), conversation_pid: term(), initial_message_count: non_neg_integer(), is_compacting?: bool(), log_msgs: boolean(), log_tool_calls: boolean(), messages: [AI.Util.msg()], model: String.t(), name: String.t() | nil, replay_conversation: boolean(), response: String.t() | nil, response_format: map() | nil, specs: [AI.Tools.tool_spec()] | nil, tool_call_requests: list(), tool_round_cap: pos_integer(), tool_round_count: non_neg_integer(), toolbox: AI.Tools.toolbox() | nil, usage: integer(), verbosity: String.t() | nil, web_search?: boolean() }
Functions
@spec handle_tool_call(t(), AI.Util.tool_call()) :: {:ok, AI.Util.tool_request_msg(), AI.Util.tool_response_msg()}
If a tool produced a very large textual output, attempt to write it to a temporary file and replace the in-memory content with a short placeholder that points to the temp file and includes a preview. Fail silently and return the original content on any error.
@spec new_from_conversation(Store.Project.Conversation.t(), Keyword.t()) :: {:ok, t()} | {:error, :conversation_not_found}
@spec tools_used(t()) :: %{required(binary()) => non_neg_integer()}
Returns a map of tool names to the number of times each tool was called during this completion round - that is, in messages that were appended after AI.Completion.new/1 captured the starting message length.
This delimiter is stable in the presence of mid-loop interrupt injection. An earlier implementation used "tools after the last user message" as the round boundary, which broke whenever a user interjection arrived mid-round: the injected user message became the new "last user", hiding any tool calls that had already executed earlier in the same round. That bug silently dropped the editing_tools_used flag and skipped end-of-session worktree merges.
Falls back to scanning all messages when initial_message_count is missing (older state structs that predate this field).