Conjure.Conversation (Conjure v0.1.1-alpha)

View Source

Manages the tool-use conversation loop.

The conversation module orchestrates the back-and-forth between Claude and tool execution. When Claude responds with tool_use blocks, this module executes the tools and formats the results to send back.

Conversation Flow

User Message
     
     
Call Claude API 
                                
                                
Parse Response                   
                                
                                
     Yes    
Tool Uses?│ Execute Tools   
            
      No                        
                                
Return Final            Format Results
 Response               Add to Messages 

Example

{:ok, skills} = Conjure.load("/path/to/skills")

messages = [%{role: "user", content: "Read the PDF skill"}]

{:ok, final_messages} = Conjure.Conversation.run_loop(
  messages,
  skills,
  &call_claude/1,
  max_iterations: 10
)

Manual Processing

For more control, use process_response/3 directly:

response = call_claude(messages)

case Conjure.Conversation.process_response(response, skills) do
  {:done, text} ->
    IO.puts(text)

  {:continue, tool_results} ->
    # Send results back to Claude
    next_response = call_claude(add_tool_results(messages, response, tool_results))
end

Summary

Functions

Check if the response indicates conversation is complete.

Extract text content from Claude's response.

Extract tool_use blocks from Claude's response.

Format tool results for sending back to Claude.

Process Claude's response, executing any tool calls.

Run a complete conversation loop until completion or max iterations.

Types

api_response()

@type api_response() :: %{required(String.t()) => term()}

message()

@type message() :: %{required(String.t()) => term()}

Functions

conversation_complete?(response)

@spec conversation_complete?(api_response()) :: boolean()

Check if the response indicates conversation is complete.

Returns true if there are no tool_use blocks.

execute_tool_calls(tool_calls, skills, executor, context, opts \\ [])

Execute multiple tool calls.

Executes in parallel using Task.async_stream for efficiency.

extract_text(arg1)

@spec extract_text(api_response()) :: String.t()

Extract text content from Claude's response.

extract_tool_uses(arg1)

@spec extract_tool_uses(api_response()) :: [Conjure.ToolCall.t()]

Extract tool_use blocks from Claude's response.

format_tool_results_message(results)

@spec format_tool_results_message([Conjure.ToolResult.t()]) :: message()

Format tool results for sending back to Claude.

Returns a message with role "user" containing tool_result blocks.

process_response(response, skills, opts \\ [])

@spec process_response(api_response(), [Conjure.Skill.t()], keyword()) ::
  {:done, String.t()} | {:continue, [Conjure.ToolResult.t()]} | {:error, term()}

Process Claude's response, executing any tool calls.

Returns:

  • {:done, text} - No tool calls, conversation complete
  • {:continue, tool_results} - Tool calls executed, send results back
  • {:error, reason} - Processing failed

run_loop(messages, skills, api_callback, opts \\ [])

@spec run_loop(
  messages :: [message()],
  skills :: [Conjure.Skill.t()],
  api_callback :: ([message()] -> {:ok, api_response()} | {:error, term()}),
  opts :: keyword()
) :: {:ok, [message()]} | {:error, Conjure.Error.t()}

Run a complete conversation loop until completion or max iterations.

Takes a callback function that makes Claude API calls. The callback receives the current messages list and should return {:ok, response} or {:error, reason}.

Options

  • :max_iterations - Maximum tool-use loops (default: 25)
  • :executor - Executor module to use (default: Conjure.Executor.Local)
  • :context - ExecutionContext to use (created if not provided)
  • :on_tool_call - Callback for each tool call fn tool_call -> :ok end
  • :on_tool_result - Callback for each tool result fn result -> :ok end