Anthropic tools study

from bs4 import BeautifulSoup
from cloudscraper import create_scraper
from html2text import HTML2Text
from pathlib import Path
from urllib.parse import urljoin, urlparse
import re
from textwrap import dedent

Text editor tool

The model can use an the text editor tool to view and modify text files, helping you debug, fix, and improve your code or other text documents. This allows the model to directly interact with your files, providing hands-on assistance rather than just suggesting changes.

When to use the text editor tool

Some examples of when to use the text editor tool are: - Code debugging: Have the model identify and fix bugs in your code, from syntax errors to logic issues. - Code refactoring: Let the model improve your code structure, readability, and performance through targeted edits. - Documentation generation: Ask the model to add docstrings, comments, or README files to your codebase. - Test creation: Have the model create unit tests for your code based on its understanding of the implementation.

Use the text editor tool

Provide the text editor tool (named str_replace_based_edit_tool) to the model.

You can optionally specify a max_characters parameter to control truncation when viewing large files.

The text editor tool can be used in the following way:

1 Provide the model with the text editor tool and a user prompt

  • Include the text editor tool in your API call
  • Provide a user prompt that may require examining or modifying files, such as “Can you fix the syntax error in my code?”

2 The model uses the tool to examine files or directories

  • The model assesses what it needs to look at and uses the view command to examine file contents or list directory contents
  • The model response will contain a tool use request with the view command

3 Execute the view command and return results

  • Extract the file or directory path from the model’s tool use request
  • Read the file’s contents or list the directory contents
  • If a max_characters parameter was specified in the tool configuration, truncate the file contents to that length
  • Return the results to the model by continuing the conversation with a new user message containing a tool result

4 The model uses the tool to modify files

  • After examining the file or directory, the model may use a command such as str_replace to make changes or insert to add text at a specific line number.
  • If the model uses the str_replace command, it constructs a properly formatted tool use request with the old text and new text to replace it with

5 Execute the edit and return results

  • Extract the file path, old text, and new text from the model’s tool use request
  • Perform the text replacement in the file
  • Return the results to the model

6 The model provides its analysis and explanation

  • After examining and possibly editing the files, the model provides a complete explanation of what it found and what changes it made

Text editor tool commands

The text editor tool supports several commands for viewing and modifying files:

view

The view command allows the model to examine the contents of a file or list the contents of a directory. It can read the entire file or a specific range of lines.

Parameters: - command: Must be “view” - path: The path to the file or directory to view - view_range (optional): An array of two integers specifying the start and end line numbers to view. Line numbers are 1-indexed, and -1 for the end line means read to the end of the file. This parameter only applies when viewing files, not directories.

Example view commands

// Example for viewing a file
{
  "input": {
    "command": "view",
    "path": "primes.py"
  }
}

// Example for viewing a directory
{
  "input": {
    "command": "view",
    "path": "src/"
  }
}

str_replace

The str_replace command allows the model to replace a specific string in a file with a new string. This is used for making precise edits.

Parameters: - command: Must be “str_replace” - path: The path to the file to modify - old_str: The text to replace (must match exactly, including whitespace and indentation) - new_str: The new text to insert in place of the old text

Example str_replace command

{
  "input": {
    "command": "str_replace",
    "path": "primes.py",
    "old_str": "for num in range(2, limit + 1)",
    "new_str": "for num in range(2, limit + 1):"
  }
}

create

The create command allows the model to create a new file with specified content.

Parameters: - command: Must be “create” - path: The path where the new file should be created - file_text: The content to write to the new file

Example create command

{
  "input": {
    "command": "create",
    "path": "test_primes.py",
    "file_text": "import unittest\nimport primes\n\nclass TestPrimes(unittest.TestCase):\n    def test_is_prime(self):\n        self.assertTrue(primes.is_prime(2))\n        self.assertTrue(primes.is_prime(3))\n        self.assertFalse(primes.is_prime(4))\n\nif __name__ == '__main__':\n    unittest.main()"
  }
}

insert

The insert command allows the model to insert text at a specific location in a file.

Parameters: - command: Must be “insert” - path: The path to the file to modify - insert_line: The line number after which to insert the text (0 for beginning of file) - new_str: The text to insert

Example insert command

{
  "input": {
    "command": "insert",
    "path": "primes.py",
    "insert_line": 0,
    "new_str": "\"\"\"Module for working with prime numbers.\n\nThis module provides functions to check if a number is prime\nand to generate a list of prime numbers up to a given limit.\n\"\"\"\n"
  }
}

Implement the text editor tool

1 Initialize your editor implementation

Create helper functions to handle file operations like reading, writing, and modifying files. Consider implementing backup functionality to recover from mistakes.

2 Handle editor tool calls

Create a function that processes tool calls from the model based on the command type:

3 Implement security measures

Add validation and security checks: - Validate file paths to prevent directory traversal - Create backups before making changes - Handle errors gracefully - Implement permissions checks

When implementing the text editor tool, keep in mind: - Security: The tool has access to your local filesystem, so implement proper security measures. - Backup: Always create backups before allowing edits to important files. - Validation: Validate all inputs to prevent unintended changes. - Unique matching: Make sure replacements match exactly one location to avoid unintended edits.

Handle errors

File not found

If the model tries to view or modify a file that doesn’t exist, return an appropriate error message in the tool_result: “Error: File not found”

Multiple matches for replacement

If the str_replace command matches multiple locations in the file, return an appropriate error message: “Error: Found 3 matches for replacement text. Please provide more context to make a unique match.”

No matches for replacement

If the str_replace command doesn’t match any text in the file, return an appropriate error message: “Error: No match found for replacement. Please check your text and try again.”

Permission errors

If there are permission issues with creating, reading, or modifying files, return an appropriate error message: “Error: Permission denied. Cannot write to file.”

Implementation best practices

Provide clear context

When asking the model to fix or modify code, be specific about what files need to be examined or what issues need to be addressed. Clear context helps the model identify the right files and make appropriate changes.

  • Less helpful prompt: “Can you fix my code?”
  • Better prompt: “There’s a syntax error in my primes.py file that prevents it from running. Can you fix it?”

Be explicit about file paths

Specify file paths clearly when needed, especially if you’re working with multiple files or files in different directories. - Less helpful prompt: “Review my helper file” - Better prompt: “Can you check my utils/helpers.py file for any performance issues?”

Create backups before editing

Implement a backup system in your application that creates copies of files before allowing the model to edit them, especially for important or production code.

Handle unique text replacement carefully

The str_replace command requires an exact match for the text to be replaced. Your application should ensure that there is exactly one match for the old text or provide appropriate error messages.

if count == 0:
    return "Error: No match found"
elif count > 1:
    return f"Error: Found {count} matches"
else:
    ...
    return "Successfully replaced text"

Verify changes

After the model makes changes to a file, verify the changes by running tests or checking that the code still works as expected.

Answerai Text editor tools implementation

Implementation from https://github.com/AnswerDotAI/claudette

Implements functions for Anthropic’s Text Editor Tool API, allowing a model to view and edit files.

def view(path:str,  # The path to the file or directory to view
         view_range:tuple[int,int]=None, # Optional array of two integers specifying the start and end line numbers to view. Line numbers are 1-indexed, and -1 for the end line means read to the end of the file. This parameter only applies when viewing files, not directories.
         nums:bool=False # Optionally prefix all lines of the file with a line number
        ) -> str:
    'Examine the contents of a file or list the contents of a directory. It can read the entire file or a specific range of lines. With or without line numbers.'
    try:
        p = Path(path).expanduser().resolve()
        if not p.exists(): return f'Error: File not found: {p}'
        if p.is_dir():
            res = [str(f) for f in p.glob('**/*') 
                   if not any(part.startswith('.') for part in f.relative_to(p).parts)]
            return f'Directory contents of {p}:\n' + '\n'.join(res)
        
        lines = p.read_text().splitlines()
        s,e = 1,len(lines)
        if view_range:
            s,e = view_range
            if not (1 <= s <= len(lines)): return f'Error: Invalid start line {s}'
            if e != -1 and not (s <= e <= len(lines)): return f'Error: Invalid end line {e}'
            lines = lines[s-1:None if e==-1 else e]
            
        return '\n'.join([f'{i+s-1:6d}{l}' for i,l in enumerate(lines,1)] if nums else lines)
    except Exception as e: return f'Error viewing file: {str(e)}'
print(view('styles.css', (1,10), nums=True))
     1 │ .cell {
     2 │   margin-bottom: 1rem;
     3 │ }
     4 │ 
     5 │ .cell > .sourceCode {
     6 │   margin-bottom: 0;
     7 │ }
     8 │ 
     9 │ .cell-output > pre {
    10 │   margin-bottom: 0;
def create(path: str, # The path where the new file should be created
           file_text: str, # The text content to write to the new file
           overwrite:bool=False # Allows overwriting an existing file
          ) -> str:
    'Creates a new file with the given text content at the specified path'
    try:
        p = Path(path)
        if p.exists():
            if not overwrite: return f'Error: File already exists: {p}'
        p.parent.mkdir(parents=True, exist_ok=True)
        p.write_text(file_text)
        return f'Created file {p} containing:\n{file_text}'
    except Exception as e: return f'Error creating file: {str(e)}'
print(create('test.txt', 'Hello, world!'))
print(view('test.txt', nums=True))
Created file test.txt containing:
Hello, world!
     1 │ Hello, world!
def insert(path: str,  # The path to the file to modify
           insert_line: int, # The line number after which to insert the text (0 for beginning of file)
           new_str: str # The text to insert
          ) -> str: 
    'Insert text at a specific line number in a file.'
    try:
        p = Path(path)
        if not p.exists(): return f'Error: File not found: {p}'
            
        content = p.read_text().splitlines()
        if not (0 <= insert_line <= len(content)): return f'Error: Invalid line number {insert_line}'
            
        content.insert(insert_line, new_str)
        new_content = '\n'.join(content)
        p.write_text(new_content)
        return f'Inserted text at line {insert_line} in {p}.\nNew contents:\n{new_content}'
    except Exception as e: return f'Error inserting text: {str(e)}'
insert('test.txt', 0, 'Let\'s add a new line')
print(view('test.txt', nums=True))
     1 │ Let's add a new line
     2 │ Hello, world!
def str_replace(path: str, # The path to the file to modify
                old_str: str, # The text to replace (must match exactly, including whitespace and indentation)
                new_str: str # The new text to insert in place of the old text
               ) -> str:
    'Replace a specific string in a file with a new string. This is used for making precise edits.'
    try:
        p = Path(path)
        if not p.exists(): return f'Error: File not found: {p}'
            
        content = p.read_text()
        count = content.count(old_str)
        
        if count == 0: return 'Error: Text not found in file'
        if count > 1: return f'Error: Multiple matches found ({count})'
            
        new_content = content.replace(old_str, new_str, 1)
        p.write_text(new_content)
        return f'Replaced text in {p}.\nNew contents:\n{new_content}'
    except Exception as e: return f'Error replacing text: {str(e)}'
str_replace('test.txt', 'new line', '')
print(view('test.txt', nums=True))
     1 │ Let's add a 
     2 │ Hello, world!

Bash tool

The bash tool enables the model to execute shell commands in a persistent bash session, allowing system operations, script execution, and command-line automation.

Overview

The bash tool provides the model with: - Persistent bash session that maintains state - Ability to run any shell command - Access to environment variables and working directory - Command chaining and scripting capabilities

Use cases

  • Development workflows: Run build commands, tests, and development tools
  • System automation: Execute scripts, manage files, automate tasks
  • Data processing: Process files, run analysis scripts, manage datasets
  • Environment setup: Install packages, configure environments

How it works

The bash tool maintains a persistent session: 1. the model determines what command to run 2. you execute the command in a bash shell 3. reurn the output (stdout and stderr) to the model 4. session state persists between commands (environment variables, working directory)

Parameters

Parameter Required Description
command Yes* The bash command to run
restart No Set to true to restart the bash session

*Required unless using restart

Example: Multi-step automation

The model can chain commands to complete complex tasks:

# User request
"Install the requests library and create a simple Python script that fetches a joke from an API, then run it."

# Model tool calls:
# 1. Install package
{"command": "pip install requests"}

# 2. Create script
{"command": "cat > fetch_joke.py << 'EOF'\nimport requests\nresponse = requests.get('https://official-joke-api.appspot.com/random_joke')\njoke = response.json()\nprint(f\"Setup: {joke['setup']}\")\nprint(f\"Punchline: {joke['punchline']}\")\nEOF"}

# 3. Run script
{"command": "python fetch_joke.py"}

The session maintains state between commands, so files created in step 2 are available in step 3.

Handle errors

Command execution timeout - If a command takes too long to execute: “Error: Command timed out after 30 seconds”

Command not found - If a command doesn’t exist: “bash: nonexistentcommand: command not found”

Permission denied - If there are permission issues: “bash: /root/sensitive-file: Permission denied”

Implementation best practices

Use command timeouts: Implement timeouts to prevent hanging commands.

Maintain session state: Keep the bash session persistent to maintain environment variables and working directory.

Handle large outputs: Truncate very large outputs to prevent token limit issues.

Log all commands: Keep an audit trail of executed commands.

Sanitize outputs: Remove sensitive information from command outputs.

Security

The bash tool provides direct system access. Implement these essential safety measures: - Running in isolated environments (Docker/VM) - Implementing command filtering and allowlists - Setting resource limits (CPU, memory, disk) - Logging all executed commands

Key recommendations - Use ulimit to set resource constraints - Filter dangerous commands (sudo, rm -rf, etc.) - Run with minimal user permissions - Monitor and log all command execution

Common patterns

Development workflows - Running tests: pytest && coverage report - Building projects: npm install && npm run build - Git operations: git status && git add . && git commit -m “message”

File operations - Processing data: wc -l .csv && ls -lh .csv - Searching files: find . -name “*.py” | xargs grep “pattern” - Creating backups: tar -czf backup.tar.gz ./data

System tasks - Checking resources: df -h && free -m - Process management: ps aux | grep python - Environment setup: export PATH=PATH:/new/path && echo PATH

Limitations

  • No interactive commands: Cannot handle vim, less, or password prompts
  • No GUI applications: Command-line only
  • Session scope: Persists within conversation, lost between API calls
  • Output limits: Large outputs may be truncated
  • No streaming: Results returned after completion

Combining with other tools

The bash tool is most powerful when combined with the text editor and other tools.

Code execution tool

Code execution tool = bash tool + text editor tool in a remote container.

The code execution tool defined by Anthropic is implemented as a remote execution container, and most of its features are designed around the interaction between a local and remote cloud environment.

In our wordslab-notebooks context, we want to execute everything locally, so we will only keep a few interesting parts of the Anthropic documentation.

When this tool is provided, the model automatically gains access to two sub-tools: - bash_code_execution: Run shell commands - text_editor_code_execution: View, create, and edit files, including writing code

How code execution works

When you add the code execution tool to your API request: 1. The model evaluates whether code execution would help answer your question 2. The tool automatically provides the model with the following capabilities: - Bash commands: Execute shell commands for system operations and package management - File operations: Create, view, and edit files directly, including writing code 3. The model can use any combination of these capabilities in a single request 4. All operations run in a secure sandbox environment 5. The tool provides results with any generated charts, calculations, or analysis

Containers

The code execution tool runs in a secure, containerized environment designed specifically for code execution, with a higher focus on Python.

Runtime environment - Python version: 3.11.12 - Operating system: Linux-based container - Architecture: x86_64 (AMD64)

Resource limits - Memory: 5GiB RAM - Disk space: 5GiB workspace storage - CPU: 1 CPU

Networking and security - Internet access: Completely disabled for security - External connections: No outbound network requests permitted - Sandbox isolation: Full isolation from host system and other containers - File access: Limited to workspace directory only - Workspace scoping: Like Files, containers are scoped to the workspace of the API key - Expiration: Containers expire 30 days after creation

Pre-installed libraries - Data Science: pandas, numpy, scipy, scikit-learn, statsmodels - Visualization: matplotlib, seaborn - File Processing: pyarrow, openpyxl, xlsxwriter, xlrd, pillow, python-pptx, python-docx, pypdf, pdfplumber, pypdfium2, pdf2image, pdfkit, tabula-py, reportlab[pycairo], Img2pdf - Math & Computing: sympy, mpmath - Utilities: tqdm, python-dateutil, pytz, joblib, unzip, unrar, 7zip, bc, rg (ripgrep), fd, sqlite

Container reuse - You can reuse an existing container across multiple API requests by providing the container ID from a previous response. - This allows you to maintain created files between requests.

How to use the tool

Execute Bash commands

Ask the model to check system information and install packages: “Check the Python version and list installed packages”

Create and edit files directly

The model can create, view, and edit files directly in the sandbox using the file manipulation capabilities: “Create a config.yaml file with database settings, then update the port from 5432 to 3306”

Upload and analyze your own files

To analyze your own data files (CSV, Excel, images, etc.), upload them via the Files API and reference them in your request: “Analyze this CSV data”

"content": [
                {"type": "text", "text": "Analyze this CSV data"},
                {"type": "container_upload", "file_id": "file_abc123"}
            ]

Retrieve generated files

When the tool creates files during code execution, you can retrieve these files using the Files API: “Create a matplotlib visualization and save it as output.png” - Extract file IDs from the response - Download the created files

Combine operations

A complex workflow using all capabilities: - First, upload a file - Extract file_id - Then use it with code execution - “Analyze this CSV data: create a summary report, save visualizations, and create a README with the findings”

Response format

The code execution tool can return two types of results depending on the operation:

Bash command response

    "stdout": "total 24\ndrwxr-xr-x 2 user user 4096 Jan 1 12:00 .\ndrwxr-xr-x 3 user user 4096 Jan 1 11:00 ..\n-rw-r--r-- 1 user user  220 Jan 1 12:00 data.csv\n-rw-r--r-- 1 user user  180 Jan 1 12:00 config.json",
    "stderr": "",
    "return_code": 0

File operation responses

  • View file
    "file_type": "text",
    "content": "{\n  \"setting\": \"value\",\n  \"debug\": true\n}",
    "numLines": 4,
    "startLine": 1,
    "totalLines": 4
  • Create file
    • is_file_update: whether file already existed
      "is_file_update": false
  • Edit file (str_replace)
    • lines: diff format
      "oldStart": 3,
      "oldLines": 1,
      "newStart": 3,
      "newLines": 1,
      "lines": ["-  \"debug\": true", "+  \"debug\": false"]

Errors

Error codes by tool type:

Tool Error Code Description
All tools unavailable The tool is temporarily unavailable
All tools execution_time_exceeded Execution exceeded maximum time limit
All tools container_expired Container expired and is no longer available
All tools invalid_tool_input Invalid parameters provided to the tool
All tools too_many_requests Rate limit exceeded for tool usage
text_editor file_not_found File doesn’t exist (for view/edit operations)
text_editor string_not_found The old_str not found in file (for str_replace)

Programmatic tool calling

The code execution tool powers programmatic tool calling, which allows the model to write code that calls your custom tools programmatically within the execution container. This enables efficient multi-tool workflows, data filtering before reaching the model’s context, and complex conditional logic.

Enable programmatic calling for your tools:

    tools=[
        {
            "name": "get_weather",
            "description": "Get weather for a city",
            "input_schema": {...},
            "allowed_callers": ["code_execution_20250825"]  # Enable programmatic calling
        }
    ]

Learn more in the Programmatic tool calling documentation.

Using code execution with Agent Skills

The code execution tool enables the mdeol to use Agent Skills. Skills are modular capabilities consisting of instructions, scripts, and resources that extend the model’s functionality.

Learn more in the Agent Skills documentation and Agent Skills API guide.

Code interpreter

From https://github.com/AnswerDotAI/claudette

Code interpreter Here is an example of using toolloop to implement a simple code interpreter with additional tools.

from toolslm.shell import get_shell from fastcore.meta import delegates import traceback

@delegates() class CodeChat(Chat): imps = ‘os, warnings, time, json, re, math, collections, itertools, functools, dateutil, datetime, string, types, copy, pprint, enum, numbers, decimal, fractions, random, operator, typing, dataclasses’ def init(self, model: Optional[str] = None, ask:bool=True, **kwargs): super().__init__(model=model, **kwargs) self.ask = askm self.tools.append(self.run_cell) self.shell = get_shell() self.shell.run_cell(‘import’+self.imps)

We have one additional parameter to creating a CodeChat beyond what we pass to Chat, which is ask – if that’s True, we’ll prompt the user before running code.

@patch def run_cell( self:CodeChat, code:str, # Code to execute in persistent IPython session )->str: “““Asks user for permission, and if provided, executes python code using persistent IPython session. Returns: Result of expression on last line (if exists); ‘#DECLINED#’ if user declines request to execute”“” confirm = f’Press Enter to execute, or enter “n” to skip?\n{code}\n’ if self.ask and input(confirm): return ‘#DECLINED#’ try: res = self.shell.run_cell(code) except Exception as e: return traceback.format_exc() return res.stdout if res.result is None else res.result

Web fetch tool

The web fetch tool allows the model to retrieve full content from specified web pages and PDF documents.

Security Warning

Enabling the web fetch tool in environments where the model processes untrusted input alongside sensitive data poses data exfiltration risks. We recommend only using this tool in trusted environments or when handling non-sensitive data.

To minimize exfiltration risks, the model should not be allowed to dynamically construct URLs. The system should only fetch URLs that have been explicitly provided by the user or that come from previous web search or web fetch results. However, there is still residual risk that should be carefully considered when using this tool.

If data exfiltration is a concern, consider: - Disabling the web fetch tool entirely - Using the max_uses parameter to limit the number of requests - Using the allowed_domains parameter to restrict to known safe domains

How web fetch works

When you add the web fetch tool to your API request: - The model decides when to fetch content based on the prompt and available URLs. - The tools retrieves the full text content from the specified URL. - For PDFs, automatic text extraction is performed. - The model analyzes the fetched content and provides a response with optional citations. - The web fetch tool currently does not support web sites dynamically rendered via Javascript.

Parameters

The web fetch tool supports the following parameters: - max_uses = 10: Optional: Limit the number of fetches per request - allowed_domains = [“example.com”, “docs.example.com”]: Optional: Only fetch from these domains - blocked_domains = [“private.example.com”]: Optional: Never fetch from these domains - citations = {“enabled”: true}: Optional: Enable citations for fetched content - max_content_tokens=100000: Optional: Maximum content length in tokens

Answerai web fetch implementation

This tool implementation is inspired by the library ipykernel_helper from Answer.ai. As of december 2025, this library is not open source, but it is available to users in the solve.it.com environment and is a dependency of other Apache 2.0 libraries, so I think it is OK to use it as an inspiration.


read_url


def read_url(
    url:str, as_md:bool=True, extract_section:bool=True, selector:str=None, math_mode:str=None
):

This functions extracts a web page information for LLM ingestion 1. Downloads a web page 2. Parses HTML 3. Optionally extracts a specific section (fragment or CSS selector) 4. Converts MathML → LaTeX 5. Optionally converts HTML → Markdown 6. Convert code sections to fenced markdown blocks 7. Makes image URLs absolute 8. Returns the processed text


scrape_url


def scrape_url(
    url
):

Get the html content of a web page using the cloudscraper library to bypass Cloudflare’s anti-bot page.

url2md = read_url("https://answerdotai.github.io/toolslm/")
url2md
'[ toolslm ](./index.html)\n\n__\n\n  1. [toolslm](./index.html)\n\n\n\n  * [ toolslm](./index.html)\n\n  * [ xml source](./xml.html)\n\n  * [ funccall source](./funccall.html)\n\n  * [ shell source](./shell.html)\n\n  * [ Download helpers](./download.html)\n\n  * [ Markdown Hierarchy Parser](./md_hier.html)\n\n\n\n\n## On this page\n\n  * Install\n  * How to use\n    * Context creation\n\n\n\n  * [__Report an issue](https://github.com/AnswerDotAI/toolslm/issues/new)\n\n\n\n## Other Formats\n\n  * [ __CommonMark](index.html.md)\n\n\n\n# toolslm\n\nTools to make language models a bit easier to use \n\nThis is a work in progress…\n\n## Install\n    \n    \n    pip install toolslm\n\n __\n\n## How to use\n\n### Context creation\n\ntoolslm has some helpers to make it easier to generate XML context from files, for instance [`folder2ctx`](https://AnswerDotAI.github.io/toolslm/xml.html#folder2ctx):\n    \n    \n    print(folder2ctx(\'samples\', prefix=False, file_glob=\'*.py\'))\n\n__\n    \n    \n    <documents><document index="1"><src>\n    samples/sample_core.py\n    </src><document-content>\n    import inspect\n    empty = inspect.Parameter.empty\n    models = \'claude-3-opus-20240229\',\'claude-3-sonnet-20240229\',\'claude-3-haiku-20240307\'\n    </document-content></document></documents>\n\nJSON doesn’t map as nicely to XML as the `ft` data structure from `fastcore.xml`, but for simple XML trees it can be convenient. The [`json_to_xml`](https://AnswerDotAI.github.io/toolslm/xml.html#json_to_xml) function handles that conversion:\n    \n    \n    a = dict(surname=\'Howard\', firstnames=[\'Jeremy\',\'Peter\'],\n             address=dict(state=\'Queensland\',country=\'Australia\'))\n    print(json_to_xml(a, \'person\'))\n\n__\n    \n    \n    <person>\n      <surname>Howard</surname>\n      <firstnames>\n        <item>Jeremy</item>\n        <item>Peter</item>\n      </firstnames>\n      <address>\n        <state>Queensland</state>\n        <country>Australia</country>\n      </address>\n    </person>\n\n  * [__Report an issue](https://github.com/AnswerDotAI/toolslm/issues/new)\n\n\n'