Loading...
    • Costruisci
    • Admin
    • Modelli e prezzi
    • Client SDK
    • Riferimento API
    Search...
    ⌘K
    Primi passi
    Introduzione a ClaudeAvvio rapido
    Costruire con Claude
    Panoramica delle funzionalitàUtilizzo delle Messages APIGestione dei motivi di arresto
    Capacità del modello
    Ragionamento estesoRagionamento adattivoImpegnoModalità rapida (beta: anteprima di ricerca)Output strutturatiCitazioniMessaggi in streamingElaborazione batchRisultati di ricercaRifiuti in streamingSupporto multilingueEmbeddings
    Strumenti
    PanoramicaCome funziona l'uso degli strumentiStrumento di ricerca webStrumento di recupero webStrumento di esecuzione del codiceStrumento di memoriaStrumento BashStrumento di utilizzo del computerStrumento editor di testo
    Infrastruttura degli strumenti
    Ricerca strumentiChiamata programmatica degli strumentiStreaming granulare degli strumenti
    Gestione del contesto
    Finestre di contestoCompattazioneModifica del contestoCaching dei promptConteggio dei token
    Lavorare con i file
    Files APISupporto PDFImmagini e visione
    Skills
    PanoramicaAvvio rapidoBest practiceSkills per l'impresaSkills nell'API
    MCP
    Server MCP remotiConnettore MCP
    Prompt engineering
    PanoramicaBest practice per i promptStrumenti di prompting in Console
    Testa e valuta
    Definisci il successo e crea valutazioniUtilizzo dello strumento di valutazione in ConsoleRiduzione della latenza
    Rafforzare i guardrail
    Ridurre le allucinazioniAumentare la coerenza dell'outputMitigare i jailbreakRidurre la perdita di prompt
    Risorse
    Glossario
    Note di rilascio
    Claude Platform
    Console
    Log in
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...

    Solutions

    • AI agents
    • Code modernization
    • Coding
    • Customer support
    • Education
    • Financial services
    • Government
    • Life sciences

    Partners

    • Amazon Bedrock
    • Google Cloud's Vertex AI

    Learn

    • Blog
    • Catalog
    • Courses
    • Use cases
    • Connectors
    • Customer stories
    • Engineering at Anthropic
    • Events
    • Powered by Claude
    • Service partners
    • Startups program

    Company

    • Anthropic
    • Careers
    • Economic Futures
    • Research
    • News
    • Responsible Scaling Policy
    • Security and compliance
    • Transparency

    Learn

    • Blog
    • Catalog
    • Courses
    • Use cases
    • Connectors
    • Customer stories
    • Engineering at Anthropic
    • Events
    • Powered by Claude
    • Service partners
    • Startups program

    Help and security

    • Availability
    • Status
    • Support
    • Discord

    Terms and policies

    • Privacy policy
    • Responsible disclosure policy
    • Terms of service: Commercial
    • Terms of service: Consumer
    • Usage policy
    Documentation

    Tutorial: Costruisci un agente che utilizza strumenti

    Una guida passo dopo passo da una singola chiamata di strumento a un ciclo agentico pronto per la produzione.

    Was this page helpful?

    • Anello 1: Un singolo strumento, un singolo turno
    • Anello 2: Il ciclo agentico
    • Anello 3: Più strumenti, chiamate parallele
    • Anello 4: Gestione degli errori
    • Anello 5: L'astrazione SDK di Tool Runner
    • Cosa hai costruito
    • Passaggi successivi

    Questo tutorial costruisce un agente di gestione del calendario in cinque anelli concentrici. Ogni anello è un programma completo e eseguibile che aggiunge esattamente un concetto all'anello precedente. Alla fine avrai scritto il ciclo agentico manualmente e poi lo avrai sostituito con l'astrazione SDK di Tool Runner.

    Lo strumento di esempio è create_calendar_event. Il suo schema utilizza oggetti annidati, array e campi facoltativi, quindi vedrai come Claude gestisce forme di input realistiche piuttosto che una singola stringa piatta.

    Ogni anello viene eseguito in modo autonomo. Copia qualsiasi anello in un file nuovo e si eseguirà senza il codice degli anelli precedenti.

    Anello 1: Un singolo strumento, un singolo turno

    Il programma più piccolo possibile che utilizza strumenti: uno strumento, un messaggio utente, una chiamata di strumento, un risultato. Il codice è pesantemente commentato in modo che tu possa mappare ogni riga al ciclo di vita dell'uso dello strumento.

    La richiesta invia un array tools insieme al messaggio dell'utente. Quando Claude decide di chiamare uno strumento, la risposta ritorna con stop_reason: "tool_use" e un blocco di contenuto tool_use contenente il nome dello strumento, un id univoco e l'input strutturato. Il tuo codice esegue lo strumento, quindi invia il risultato in un blocco tool_result il cui tool_use_id corrisponde all'id della chiamata.

    #!/bin/bash
    # Ring 1: Single tool, single turn.
    # Source for <CodeSource> in build-a-tool-using-agent.mdx.
    
    # Define one tool as a JSON fragment. The input_schema is a JSON Schema
    # object describing the arguments Claude should pass when it calls this
    # tool. This schema includes nested objects (recurrence), arrays
    # (attendees), and optional fields, which is closer to real-world tools
    # than a flat string argument.
    TOOLS='[
      {
        "name": "create_calendar_event",
        "description": "Create a calendar event with attendees and optional recurrence.",
        "input_schema": {
          "type": "object",
          "properties": {
            "title": {"type": "string"},
            "start": {"type": "string", "format": "date-time"},
            "end": {"type": "string", "format": "date-time"},
            "attendees": {
              "type": "array",
              "items": {"type": "string", "format": "email"}
            },
            "recurrence": {
              "type": "object",
              "properties": {
                "frequency": {"enum": ["daily", "weekly", "monthly"]},
                "count": {"type": "integer", "minimum": 1}
              }
            }
          },
          "required": ["title", "start", "end"]
        }
      }
    ]'
    
    USER_MSG="Schedule a 30-minute sync with [email protected] and [email protected] next Monday at 10am."
    
    # Send the user's request along with the tool definition. Claude decides
    # whether to call the tool based on the request and the tool description.
    RESPONSE=$(curl -s https://api.anthropic.com/v1/messages \
      -H "x-api-key: $ANTHROPIC_API_KEY" \
      -H "anthropic-version: 2023-06-01" \
      -H "content-type: application/json" \
      -d "$(jq -n \
        --argjson tools "$TOOLS" \
        --arg msg "$USER_MSG" \
        '{
          model: "claude-opus-4-6",
          max_tokens: 1024,
          tools: $tools,
          tool_choice: {type: "auto", disable_parallel_tool_use: true},
          messages: [{role: "user", content: $msg}]
        }')")
    
    # When Claude calls a tool, the response has stop_reason "tool_use"
    # and the content array contains a tool_use block alongside any text.
    echo "stop_reason: $(echo "$RESPONSE" | jq -r '.stop_reason')"
    
    # Find the tool_use block. A response may contain text blocks before the
    # tool_use block, so filter by type rather than assuming position.
    TOOL_USE=$(echo "$RESPONSE" | jq '.content[] | select(.type == "tool_use")')
    TOOL_USE_ID=$(echo "$TOOL_USE" | jq -r '.id')
    echo "Tool: $(echo "$TOOL_USE" | jq -r '.name')"
    echo "Input: $(echo "$TOOL_USE" | jq -c '.input')"
    
    # Execute the tool. In a real system this would call your calendar API.
    # Here the result is hardcoded to keep the example self-contained.
    RESULT='{"event_id": "evt_123", "status": "created"}'
    
    # Send the result back. The tool_result block goes in a user message and
    # its tool_use_id must match the id from the tool_use block above. The
    # assistant's previous response is included so Claude has the full history.
    ASSISTANT_CONTENT=$(echo "$RESPONSE" | jq '.content')
    FOLLOWUP=$(curl -s https://api.anthropic.com/v1/messages \
      -H "x-api-key: $ANTHROPIC_API_KEY" \
      -H "anthropic-version: 2023-06-01" \
      -H "content-type: application/json" \
      -d "$(jq -n \
        --argjson tools "$TOOLS" \
        --arg msg "$USER_MSG" \
        --argjson assistant "$ASSISTANT_CONTENT" \
        --arg tool_use_id "$TOOL_USE_ID" \
        --arg result "$RESULT" \
        '{
          model: "claude-opus-4-6",
          max_tokens: 1024,
          tools: $tools,
          tool_choice: {type: "auto", disable_parallel_tool_use: true},
          messages: [
            {role: "user", content: $msg},
            {role: "assistant", content: $assistant},
            {role: "user", content: [
              {type: "tool_result", tool_use_id: $tool_use_id, content: $result}
            ]}
          ]
        }')")
    
    # With the tool result in hand, Claude produces a final natural-language
    # answer and stop_reason becomes "end_turn".
    echo "stop_reason: $(echo "$FOLLOWUP" | jq -r '.stop_reason')"
    echo "$FOLLOWUP" | jq -r '.content[] | select(.type == "text") | .text'

    Cosa aspettarsi

    Output
    stop_reason: tool_use
    Tool: create_calendar_event
    Input: {'title': 'Sync', 'start': '2026-03-30T10:00:00', 'end': '2026-03-30T10:30:00', 'attendees': ['[email protected]', '[email protected]']}
    stop_reason: end_turn
    I've scheduled your 30-minute sync with Alice and Bob for next Monday at 10am.

    Il primo stop_reason è tool_use perché Claude sta aspettando il risultato del calendario. Dopo aver inviato il risultato, il secondo stop_reason è end_turn e il contenuto è linguaggio naturale per l'utente.

    Anello 2: Il ciclo agentico

    L'Anello 1 presupponeva che Claude avrebbe chiamato lo strumento esattamente una volta. I compiti reali spesso richiedono diverse chiamate: Claude potrebbe creare un evento, leggere la conferma, quindi crearne un altro. La soluzione è un ciclo while che continua a eseguire strumenti e alimentare i risultati finché stop_reason non è più "tool_use".

    L'altro cambiamento è la cronologia della conversazione. Invece di ricostruire l'array messages da zero ad ogni richiesta, mantieni un elenco in esecuzione e aggiungi ad esso. Ogni turno vede il contesto precedente completo.

    Cosa aspettarsi

    Output
    I've set up your weekly team standup for the next 4 Mondays at 9am with Alice, Bob, and Carol invited.

    Il ciclo può essere eseguito una o più volte a seconda di come Claude scompone il compito. Il tuo codice non ha più bisogno di saperlo in anticipo.

    Anello 3: Più strumenti, chiamate parallele

    Gli agenti raramente hanno una sola capacità. Aggiungi un secondo strumento, list_calendar_events, in modo che Claude possa controllare la pianificazione esistente prima di creare qualcosa di nuovo.

    Quando Claude ha più chiamate di strumenti indipendenti da effettuare, potrebbe restituire diversi blocchi tool_use in una singola risposta. Il tuo ciclo deve elaborarli tutti e inviare indietro tutti i risultati insieme in un unico messaggio utente. Itera su ogni blocco tool_use in response.content, non solo il primo.

    Cosa aspettarsi

    Output
    I checked your calendar for next Monday and found an existing meeting from 2pm to 3pm. I've scheduled the planning session for 10am to 11am to avoid the conflict.

    Per ulteriori informazioni sull'esecuzione concorrente e le garanzie di ordinamento, vedi Uso parallelo dello strumento.

    Anello 4: Gestione degli errori

    Gli strumenti falliscono. Un'API del calendario potrebbe rifiutare un evento con troppi partecipanti, oppure una data potrebbe essere malformata. Quando uno strumento genera un errore, invia il messaggio di errore indietro con is_error: true invece di arrestarsi. Claude legge l'errore e può riprovare con input corretto, chiedere chiarimenti all'utente o spiegare il limite.

    Cosa aspettarsi

    Output
    I tried to schedule the all-hands but the calendar only allows 10 attendees per event. I can split this into two sessions, or you can let me know which 10 people to prioritize.

    Il flag is_error è l'unica differenza da un risultato riuscito. Claude vede il flag e il testo di errore e risponde di conseguenza. Vedi Gestisci le chiamate di strumento per il riferimento completo sulla gestione degli errori.

    Anello 5: L'astrazione SDK di Tool Runner

    Gli Anelli 2 attraverso 4 hanno scritto lo stesso ciclo manualmente: chiama l'API, controlla stop_reason, esegui strumenti, aggiungi risultati, ripeti. Tool Runner lo fa per te. Definisci ogni strumento come una funzione, passa l'elenco a tool_runner e recupera il messaggio finale una volta completato il ciclo. Il wrapping degli errori, la formattazione dei risultati e la gestione della conversazione vengono gestiti internamente.

    L'SDK Python utilizza il decoratore @beta_tool per dedurre lo schema dai suggerimenti di tipo e dalla docstring. L'SDK TypeScript utilizza betaZodTool con uno schema Zod.

    Tool Runner è disponibile negli SDK Python, TypeScript e Ruby. Le schede Shell e CLI mostrano una nota invece del codice; mantieni il ciclo Ring 4 per gli script basati su shell.

    Cosa aspettarsi

    Output
    I checked your calendar for next Monday and found an existing meeting from 2pm to 3pm. I've scheduled the planning session for 10am to 11am to avoid the conflict.

    L'output è identico all'Anello 3. La differenza è nel codice: circa la metà delle righe, nessun ciclo manuale e lo schema vive accanto all'implementazione.

    Cosa hai costruito

    Hai iniziato con una singola chiamata di strumento hardcoded e sei terminato con un agente di forma pronta per la produzione che gestisce più strumenti, chiamate parallele ed errori, quindi hai compresso tutto in Tool Runner. Nel processo hai visto ogni parte del protocollo di uso dello strumento: blocchi tool_use, blocchi tool_result, corrispondenza tool_use_id, controllo stop_reason e segnalazione is_error.

    Passaggi successivi

    Affina i tuoi schemi

    Specifica dello schema e migliori pratiche.

    Approfondimento su Tool Runner

    Il riferimento completo dell'astrazione SDK.

    Risoluzione dei problemi

    Correggi gli errori comuni di uso dello strumento.

    #!/bin/bash
    # Ring 2: The agentic loop.
    # Source for <CodeSource> in build-a-tool-using-agent.mdx.
    
    TOOLS='[
      {
        "name": "create_calendar_event",
        "description": "Create a calendar event with attendees and optional recurrence.",
        "input_schema": {
          "type": "object",
          "properties": {
            "title": {"type": "string"},
            "start": {"type": "string", "format": "date-time"},
            "end": {"type": "string", "format": "date-time"},
            "attendees": {"type": "array", "items": {"type": "string", "format": "email"}},
            "recurrence": {
              "type": "object",
              "properties": {
                "frequency": {"enum": ["daily", "weekly", "monthly"]},
                "count": {"type": "integer", "minimum": 1}
              }
            }
          },
          "required": ["title", "start", "end"]
        }
      }
    ]'
    
    run_tool() {
      local name="$1"
      local input="$2"
      if [ "$name" = "create_calendar_event" ]; then
        local title=$(echo "$input" | jq -r '.title')
        jq -n --arg title "$title" '{event_id: "evt_123", status: "created", title: $title}'
      else
        echo "{\"error\": \"Unknown tool: $name\"}"
      fi
    }
    
    # Keep the full conversation history in a JSON array so each turn sees prior context.
    MESSAGES='[{"role": "user", "content": "Schedule a weekly team standup every Monday at 9am for the next 4 weeks. Invite the whole team: [email protected], [email protected], [email protected]."}]'
    
    call_api() {
      curl -s https://api.anthropic.com/v1/messages \
        -H "x-api-key: $ANTHROPIC_API_KEY" \
        -H "anthropic-version: 2023-06-01" \
        -H "content-type: application/json" \
        -d "$(jq -n --argjson tools "$TOOLS" --argjson messages "$MESSAGES" \
          '{model: "claude-opus-4-6", max_tokens: 1024, tools: $tools, tool_choice: {type: "auto", disable_parallel_tool_use: true}, messages: $messages}')"
    }
    
    RESPONSE=$(call_api)
    
    # Loop until Claude stops asking for tools. Each iteration runs the requested
    # tool, appends the result to history, and asks Claude to continue.
    while [ "$(echo "$RESPONSE" | jq -r '.stop_reason')" = "tool_use" ]; do
      TOOL_USE=$(echo "$RESPONSE" | jq '.content[] | select(.type == "tool_use")')
      TOOL_NAME=$(echo "$TOOL_USE" | jq -r '.name')
      TOOL_INPUT=$(echo "$TOOL_USE" | jq -c '.input')
      TOOL_USE_ID=$(echo "$TOOL_USE" | jq -r '.id')
      RESULT=$(run_tool "$TOOL_NAME" "$TOOL_INPUT")
    
      ASSISTANT_CONTENT=$(echo "$RESPONSE" | jq '.content')
      MESSAGES=$(echo "$MESSAGES" | jq \
        --argjson assistant "$ASSISTANT_CONTENT" \
        --arg tool_use_id "$TOOL_USE_ID" \
        --arg result "$RESULT" \
        '. + [
          {role: "assistant", content: $assistant},
          {role: "user", content: [{type: "tool_result", tool_use_id: $tool_use_id, content: $result}]}
        ]')
    
      RESPONSE=$(call_api)
    done
    
    echo "$RESPONSE" | jq -r '.content[] | select(.type == "text") | .text'
    #!/bin/bash
    # Ring 3: Multiple tools, parallel calls.
    # Source for <CodeSource> in build-a-tool-using-agent.mdx.
    
    TOOLS='[
      {
        "name": "create_calendar_event",
        "description": "Create a calendar event with attendees and optional recurrence.",
        "input_schema": {
          "type": "object",
          "properties": {
            "title": {"type": "string"},
            "start": {"type": "string", "format": "date-time"},
            "end": {"type": "string", "format": "date-time"},
            "attendees": {"type": "array", "items": {"type": "string", "format": "email"}},
            "recurrence": {
              "type": "object",
              "properties": {
                "frequency": {"enum": ["daily", "weekly", "monthly"]},
                "count": {"type": "integer", "minimum": 1}
              }
            }
          },
          "required": ["title", "start", "end"]
        }
      },
      {
        "name": "list_calendar_events",
        "description": "List all calendar events on a given date.",
        "input_schema": {
          "type": "object",
          "properties": {"date": {"type": "string", "format": "date"}},
          "required": ["date"]
        }
      }
    ]'
    
    run_tool() {
      case "$1" in
        create_calendar_event)
          jq -n --arg title "$(echo "$2" | jq -r '.title')" '{event_id: "evt_123", status: "created", title: $title}' ;;
        list_calendar_events)
          echo '{"events": [{"title": "Existing meeting", "start": "14:00", "end": "15:00"}]}' ;;
        *)
          echo "{\"error\": \"Unknown tool: $1\"}" ;;
      esac
    }
    
    MESSAGES='[{"role": "user", "content": "Check what I have next Monday, then schedule a planning session that avoids any conflicts."}]'
    
    call_api() {
      curl -s https://api.anthropic.com/v1/messages \
        -H "x-api-key: $ANTHROPIC_API_KEY" \
        -H "anthropic-version: 2023-06-01" \
        -H "content-type: application/json" \
        -d "$(jq -n --argjson tools "$TOOLS" --argjson messages "$MESSAGES" \
          '{model: "claude-opus-4-6", max_tokens: 1024, tools: $tools, messages: $messages}')"
    }
    
    RESPONSE=$(call_api)
    
    while [ "$(echo "$RESPONSE" | jq -r '.stop_reason')" = "tool_use" ]; do
      # A single response can contain multiple tool_use blocks. Process all of
      # them and return all results together in one user message.
      TOOL_RESULTS='[]'
      while read -r block; do
        NAME=$(echo "$block" | jq -r '.name')
        INPUT=$(echo "$block" | jq -c '.input')
        ID=$(echo "$block" | jq -r '.id')
        RESULT=$(run_tool "$NAME" "$INPUT")
        TOOL_RESULTS=$(echo "$TOOL_RESULTS" | jq --arg id "$ID" --arg result "$RESULT" \
          '. + [{type: "tool_result", tool_use_id: $id, content: $result}]')
      done < <(echo "$RESPONSE" | jq -c '.content[] | select(.type == "tool_use")')
    
      MESSAGES=$(echo "$MESSAGES" | jq \
        --argjson assistant "$(echo "$RESPONSE" | jq '.content')" \
        --argjson results "$TOOL_RESULTS" \
        '. + [{role: "assistant", content: $assistant}, {role: "user", content: $results}]')
    
      RESPONSE=$(call_api)
    done
    
    echo "$RESPONSE" | jq -r '.content[] | select(.type == "text") | .text'
    #!/bin/bash
    # Ring 4: Error handling.
    # Source for <CodeSource> in build-a-tool-using-agent.mdx.
    
    TOOLS='[
      {
        "name": "create_calendar_event",
        "description": "Create a calendar event with attendees and optional recurrence.",
        "input_schema": {
          "type": "object",
          "properties": {
            "title": {"type": "string"},
            "start": {"type": "string", "format": "date-time"},
            "end": {"type": "string", "format": "date-time"},
            "attendees": {"type": "array", "items": {"type": "string", "format": "email"}},
            "recurrence": {
              "type": "object",
              "properties": {
                "frequency": {"enum": ["daily", "weekly", "monthly"]},
                "count": {"type": "integer", "minimum": 1}
              }
            }
          },
          "required": ["title", "start", "end"]
        }
      },
      {
        "name": "list_calendar_events",
        "description": "List all calendar events on a given date.",
        "input_schema": {
          "type": "object",
          "properties": {"date": {"type": "string", "format": "date"}},
          "required": ["date"]
        }
      }
    ]'
    
    run_tool() {
      case "$1" in
        create_calendar_event)
          local count=$(echo "$2" | jq '.attendees | length // 0')
          if [ "$count" -gt 10 ]; then
            echo "ERROR: Too many attendees (max 10)"
            return 1
          fi
          jq -n --arg title "$(echo "$2" | jq -r '.title')" '{event_id: "evt_123", status: "created", title: $title}' ;;
        list_calendar_events)
          echo '{"events": [{"title": "Existing meeting", "start": "14:00", "end": "15:00"}]}' ;;
        *)
          echo "ERROR: Unknown tool: $1"
          return 1 ;;
      esac
    }
    
    EMAILS=$(seq 0 14 | sed 's/.*/user&@example.com/' | paste -sd, -)
    MESSAGES="[{\"role\": \"user\", \"content\": \"Schedule an all-hands with everyone: $EMAILS\"}]"
    
    call_api() {
      curl -s https://api.anthropic.com/v1/messages \
        -H "x-api-key: $ANTHROPIC_API_KEY" \
        -H "anthropic-version: 2023-06-01" \
        -H "content-type: application/json" \
        -d "$(jq -n --argjson tools "$TOOLS" --argjson messages "$MESSAGES" \
          '{model: "claude-opus-4-6", max_tokens: 1024, tools: $tools, messages: $messages}')"
    }
    
    RESPONSE=$(call_api)
    
    while [ "$(echo "$RESPONSE" | jq -r '.stop_reason')" = "tool_use" ]; do
      TOOL_RESULTS='[]'
      while read -r block; do
        NAME=$(echo "$block" | jq -r '.name')
        INPUT=$(echo "$block" | jq -c '.input')
        ID=$(echo "$block" | jq -r '.id')
        if OUTPUT=$(run_tool "$NAME" "$INPUT"); then
          TOOL_RESULTS=$(echo "$TOOL_RESULTS" | jq --arg id "$ID" --arg result "$OUTPUT" \
            '. + [{type: "tool_result", tool_use_id: $id, content: $result}]')
        else
          # Signal failure so Claude can retry or ask for clarification.
          TOOL_RESULTS=$(echo "$TOOL_RESULTS" | jq --arg id "$ID" --arg result "$OUTPUT" \
            '. + [{type: "tool_result", tool_use_id: $id, content: $result, is_error: true}]')
        fi
      done < <(echo "$RESPONSE" | jq -c '.content[] | select(.type == "tool_use")')
    
      MESSAGES=$(echo "$MESSAGES" | jq \
        --argjson assistant "$(echo "$RESPONSE" | jq '.content')" \
        --argjson results "$TOOL_RESULTS" \
        '. + [{role: "assistant", content: $assistant}, {role: "user", content: $results}]')
    
      RESPONSE=$(call_api)
    done
    
    echo "$RESPONSE" | jq -r '.content[] | select(.type == "text") | .text'
    #!/bin/bash
    # Ring 5: The Tool Runner SDK abstraction.
    # Source for <CodeSource> in build-a-tool-using-agent.mdx.
    
    # The Tool Runner SDK abstraction is available in the Python, TypeScript,
    # and Ruby SDKs. There is no equivalent for raw curl requests. Switch to
    # the Python or TypeScript tab to see Ring 5, or keep the Ring 4 loop as
    # your shell implementation.