Conjure.Conversation.Anthropic (Conjure v0.1.1-alpha)

View Source

Conversation loop for Anthropic Skills API with pause_turn handling.

Unlike local/Docker execution where Conjure manages tool execution, here Anthropic executes skills in their container. However, long-running operations return pause_turn and require continuation.

Conversation Flow

User Message
     
     
Call Claude API 
                                
                                
Parse Response                   
                                
                                
    Yes   
pause_turn?  Build Continue 
          
      No                       
                               
Return Final             Update Messages
 Response                Container ID 

Example

{:ok, container} = Conjure.API.Anthropic.container_config([
  {:anthropic, "xlsx", "latest"}
])

messages = [%{"role" => "user", "content" => "Create a budget spreadsheet"}]

{:ok, result} = Conjure.Conversation.Anthropic.run(
  messages,
  container,
  &call_claude/1,
  max_iterations: 10,
  on_pause: fn _response, attempt -> IO.puts("Pause #{attempt}") end
)

References

Summary

Functions

Check if a result indicates the conversation is complete.

Extract the final text response from a result.

Run a conversation with Anthropic-hosted skills, handling pause_turn.

Types

api_callback()

@type api_callback() :: ([message()] -> {:ok, map()} | {:error, term()})

message()

@type message() :: map()

opts()

@type opts() :: [
  max_iterations: pos_integer(),
  on_pause: (response :: map(), attempt :: pos_integer() -> any()),
  on_response: (response :: map() -> any())
]

result()

@type result() :: %{
  response: map(),
  messages: [message()],
  container_id: String.t() | nil,
  iterations: pos_integer(),
  file_ids: [String.t()]
}

Functions

complete?(map)

@spec complete?(result()) :: boolean()

Check if a result indicates the conversation is complete.

Returns false if the result came from a pause_turn that hit max iterations.

continue(previous_result, additional_messages, api_callback, opts \\ [])

@spec continue(result(), [message()], api_callback(), opts()) ::
  {:ok, result()} | {:error, Conjure.Error.t()}

Continue from a previous result.

Use this to resume a conversation that was completed but you want to continue with additional user messages.

Example

# First conversation
{:ok, result1} = run(messages1, container, callback)

# Continue with new message, reusing container
updated_messages = result1.messages ++ [%{"role" => "user", "content" => "Now add headers"}]
updated_container = Conjure.API.Anthropic.with_container_id(container, result1.container_id)

{:ok, result2} = run(updated_messages, updated_container, callback)

extract_text(map)

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

Extract the final text response from a result.

run(messages, container_config, api_callback, opts \\ [])

@spec run([message()], map(), api_callback(), opts()) ::
  {:ok, result()} | {:error, Conjure.Error.t()}

Run a conversation with Anthropic-hosted skills, handling pause_turn.

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 pause_turn iterations (default: 10)
  • :on_pause - Callback when pause_turn received fn response, attempt -> :ok end
  • :on_response - Callback for each response fn response -> :ok end

Returns

On success, returns {:ok, result} where result contains:

  • :response - The final API response
  • :messages - Complete conversation history
  • :container_id - Container ID for session reuse
  • :iterations - Number of iterations taken
  • :file_ids - List of file IDs created during execution

Example

{:ok, container} = Conjure.API.Anthropic.container_config([
  {:anthropic, "xlsx", "latest"}
])

{:ok, result} = Conjure.Conversation.Anthropic.run(
  [%{"role" => "user", "content" => "Create a spreadsheet"}],
  container,
  fn messages ->
    body = Conjure.API.Anthropic.build_request(messages, container)
    MyApp.Claude.post("/v1/messages", body)
  end
)

# Access results
result.file_ids
# => ["file_abc123"]