> ## Documentation Index
> Fetch the complete documentation index at: https://docs.freeplay.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Anthropic Tools

> Implement tool calling with Anthropic models and record to Freeplay.

### 1. Setup clients

Initialize Freeplay and Anthropic client SDKs.

### 2. Fetch prompt from Freeplay

Pull in the formatted prompt with Freeplay. The prompt contains tools schema that'll we'll pass down below.

### 3. Call Anthropic with the tools

When creating a new completion, pass in the tools schema from the prompt we fetched.

### 4. Handle tool call

When LLM responds back with a tool call, call the external function in your service. As an example here, we are calling `get_temperature` function

### 5. Record tool call and schema

Pass in the schema and completion response to capture the tool call and its associated schema.

## Examples

<CodeGroup>
  ```python Python theme={null}
  import os
  import time
  import json
  from anthropic import Anthropic, NotGiven
  from anthropic.types import ToolUseBlock
  from freeplay import Freeplay, RecordPayload, CallInfo

  # A mock function that gets temperature for a location 
  def get_temperature(location: str) -> float:
      return 72.5
    
  project_id=os.environ['FREEPLAY_PROJECT_ID']
  fp_client = Freeplay(
      freeplay_api_key=os.environ['FREEPLAY_API_KEY'],
      api_base=f"{os.environ['FREEPLAY_API_URL']}/api"
  )
  client = Anthropic(api_key=os.environ.get("ANTHROPIC_API_KEY"))

  input_variables = {'location': "Boulder, CO"}
  formatted_prompt = fp_client.prompts.get_formatted(
      project_id=project_id,
      template_name='my-anthropic-prompt',
      environment='latest',
      variables=input_variables
  )

  start = time.time()
  completion = client.messages.create(
      system=formatted_prompt.system_content or NotGiven(),
      messages=formatted_prompt.llm_prompt,
      model=formatted_prompt.prompt_info.model,
      tools=formatted_prompt.tool_schema,
      **formatted_prompt.prompt_info.model_parameters
  )
  end = time.time()

  # Get all messages including the completion
  messages = formatted_prompt.all_messages({
      'content': completion.content,
      'role': completion.role,
  })

  # Handle tool calls if present
  if isinstance(completion.content, list):
      for block in completion.content:
          if isinstance(block, ToolUseBlock) and block.name == "weather_of_location":
              temperature = get_temperature(block.input["location"])
              tool_response_message = {
                  "role": "user", 
                  "content": [
                      {
                          "type": "tool_result",
                          "tool_use_id": block.id,
                          "content": str(temperature),
                      }
                  ]
              }
              messages.append(tool_response_message)

  session = fp_client.sessions.create()
  fp_client.recordings.create(
      RecordPayload(
          project_id=project_id,
          all_messages=messages,
          session_info=session.session_info,
          inputs=input_variables,
          prompt_version_info=formatted_prompt.prompt_info,
          call_info=CallInfo.from_prompt_info(formatted_prompt.prompt_info, start, end),
          tool_schema=formatted_prompt.tool_schema
      )
  )
  ```

  ```javascript Node theme={null}
  import Anthropic from "@anthropic-ai/sdk";
  import Freeplay, { getSessionInfo, getCallInfo } from "freeplay";

  // A mock function that gets temperature for a location
  function getTemperature(location) {
    return 72.5;
  }

  const fp_client = new Freeplay({
    freeplayApiKey: process.env.FREEPLAY_API_KEY,
    baseUrl: `${process.env.FREEPLAY_API_URL}/api`,
  });
  const client = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY });

  const inputVariables = { location: "Boulder, CO" };
  const formattedPrompt = await fp_client.prompts.getFormatted({
    projectId: process.env.FREEPLAY_PROJECT_ID,
    templateName: "my-anthropic-prompt",
    environment: "latest",
    variables: inputVariables,
  });

  const start = new Date();
  const completion = await client.messages.create({
    system: formattedPrompt.systemContent || undefined,
    messages: formattedPrompt.llmPrompt,
    model: formattedPrompt.promptInfo.model,
    tools: formattedPrompt.toolSchema,
    ...formattedPrompt.promptInfo.modelParameters,
  });
  const end = new Date();

  // Get all messages including the completion
  const messages = formattedPrompt.allMessages({
    content: completion.content,
    role: completion.role,
  });

  // Handle tool calls if present
  if (Array.isArray(completion.content)) {
    for (const block of completion.content) {
      if (block.type === "tool_use" && block.name === "weather_of_location") {
        const temperature = getTemperature(block.input.location);
        const toolResponseMessage = {
          role: "user",
          content: [
            {
              type: "tool_result",
              tool_use_id: block.id,
              content: temperature.toString(),
            },
          ],
        };
        messages.push(toolResponseMessage);
      }
    }
  }

  const session = fp_client.sessions.create();
  await fp_client.recordings.create({
    allMessages: messages,
    sessionInfo: getSessionInfo(session),
    inputs: inputVariables,
    promptInfo: formattedPrompt.promptInfo,
    callInfo: getCallInfo(formattedPrompt.promptInfo, start, end),
    toolSchema: formattedPrompt.toolSchema
  });
  ```

  ```java Kotlin theme={null}
  package ai.freeplay.example.kotlin

  import ai.freeplay.client.thin.Freeplay
  import ai.freeplay.client.thin.resources.prompts.ChatMessage
  import ai.freeplay.client.thin.resources.recordings.*
  import com.fasterxml.jackson.databind.ObjectMapper
  import ai.freeplay.example.java.ThinExampleUtils.callAnthropic

  object AnthropicToolsExample {
      private val objectMapper = ObjectMapper()

      // Mock weather function
      private fun getTemperature(location: String): Double = 72.5

      @JvmStatic
      fun main(args: Array<String>) {
          val freeplayApiKey = System.getenv("FREEPLAY_API_KEY")
          val projectId = System.getenv("FREEPLAY_PROJECT_ID")
          val apiRoot = System.getenv("FREEPLAY_API_URL")
          val baseUrl = "${apiRoot}/api"
          val anthropicApiKey = System.getenv("ANTHROPIC_API_KEY")

          val fpClient = Freeplay(
              Freeplay.Config()
                  .freeplayAPIKey(freeplayApiKey)
                  .baseUrl(baseUrl)
          )

          val variables = mapOf("location" to "Boulder, CO")

          fpClient.prompts()
              .getFormatted<List<ChatMessage>>(
                  projectId,
                  "my-anthropic-prompt",
                  "latest",
                  variables,
                  null
              ).thenCompose { formattedPrompt ->
                  val startTime = System.currentTimeMillis()
                  callAnthropic(
                      objectMapper,
                      anthropicApiKey,
                      formattedPrompt.promptInfo.model,
                      formattedPrompt.promptInfo.modelParameters,
                      formattedPrompt.formattedPrompt,
                      formattedPrompt.systemContent.orElse(null),
                      formattedPrompt.toolSchema
                  ).thenApply { Triple(formattedPrompt, it, startTime) }
              }.thenCompose { (formattedPrompt, response, startTime) ->
                  try {
                      val bodyNode = objectMapper.readTree(response.body())
                      val contentNode = bodyNode.get("content")

                      // Create initial message list
                      val allMessages = formattedPrompt.allMessages(
                          ChatMessage("assistant", objectMapper.convertValue(contentNode, List::class.java))
                      ).toMutableList()

                      // Handle tool calls
                      if (contentNode.isArray) {
                          contentNode.forEach { block ->
                              if (block["type"]?.asText() == "tool_use" && 
                                  block["name"]?.asText() == "weather_of_location") {
                                  
                                  val input = block["input"]
                                  val temperature = getTemperature(input["location"].asText())

                                  val toolResponse = mapOf(
                                      "role" to "user",
                                      "content" to listOf(
                                          mapOf(
                                              "type" to "tool_result",
                                              "content" to temperature.toString(),
                                              "tool_use_id" to block["id"].asText()
                                          )
                                      )
                                  )
                                  allMessages.add(ChatMessage(toolResponse))
                              }
                          }
                      }

                      val callInfo = CallInfo.from(
                          formattedPrompt.promptInfo,
                          startTime,
                          System.currentTimeMillis()
                      )

                      val sessionInfo = fpClient.sessions().create().sessionInfo

                      // Print the completion for debugging
                      if (contentNode.isArray && contentNode.size() > 0) {
                          contentNode[0]?.get("text")?.asText()?.let { text ->
                              println("Completion: $text")
                          }
                      }

                      val record = RecordInfo(
                            projectId,
                            allMessages
                        ).inputs(variables)
                            .sessionInfo(session.sessionInfo)
                            .promptVersionInfo(prompt.promptInfo)
                            .callInfo(callInfo)
                            .traceInfo(trace)
                            .toolSchema(formattedPrompt.toolSchema)
                      )

                      fpClient.recordings().create(record)

                  } catch (e: Exception) {
                      throw RuntimeException("Failed to process JSON response", e)
                  }
              }
              .exceptionally { exception ->
                  System.err.println("Error: ${exception.message}")
                  exception.printStackTrace()
                  RecordResponse(null)
              }
              .join()
      }
  }
  ```
</CodeGroup>
