From e4beca6241ad3b6e9ec6d53f7fdc17ca6b0b0352 Mon Sep 17 00:00:00 2001 From: Akihiko Kuroda Date: Tue, 23 Jun 2026 18:21:37 -0400 Subject: [PATCH 1/3] update docs/examples/tools/README.md Signed-off-by: Akihiko Kuroda --- docs/examples/tools/README.md | 105 +++++++++++++++++++++++++++++----- 1 file changed, 92 insertions(+), 13 deletions(-) diff --git a/docs/examples/tools/README.md b/docs/examples/tools/README.md index 65562c751..6d54ba882 100644 --- a/docs/examples/tools/README.md +++ b/docs/examples/tools/README.md @@ -1,10 +1,14 @@ -# Tool Calling Examples +--- +title: Tool Calling Examples +description: Learn how to define and use tools with Mellea +--- This directory contains examples of using tool calling (function calling) with Mellea. ## Files ### interpreter_example.py + Comprehensive examples of using the code interpreter tool with LLMs. **Key Features:** @@ -18,22 +22,28 @@ Comprehensive examples of using the code interpreter tool with LLMs. Shows how to use pre-built tools from Hugging Face's smolagents library. **Key Features:** -- Loading existing smolagents tools (PythonInterpreterTool, WikipediaSearchTool, etc.) + +- Loading existing smolagents tools (PythonInterpreterTool, + WikipediaSearchTool, etc.) - Converting to Mellea tools with `MelleaTool.from_smolagents()` - Using tools from the Hugging Face ecosystem ### python_tool_example.py + Demonstrates creating and using custom Python tools with Mellea. **Key Features:** + - Defining custom tool functions - Tool registration and discovery - Integrating custom tools with LLM calls ### tool_decorator_example.py + Shows how to use the `@tool` decorator for tool definition. **Key Features:** + - Decorator-based tool creation - Automatic argument parsing from type hints - Tool documentation generation @@ -49,10 +59,12 @@ Shows how to use the `@tool` decorator for tool definition. ## Basic Usage ### Direct Tool Use + ```python from mellea.stdlib.tools import python_tool -tool = python_tool(tier="local_unsafe", name="python") +# Create the tool +tool = python_tool(tier='docker_unsafe') # Execute code directly result = tool.run(code="print(1+1)") @@ -60,6 +72,7 @@ print(result.stdout) # Output: 2 ``` ### Tool with LLM + ```python from mellea import start_session from mellea.backends import ModelOption @@ -67,10 +80,20 @@ from mellea.stdlib.tools import python_tool tool = python_tool(tier="local_unsafe", name="python") m = start_session() +tool = python_tool(tier='docker_unsafe') result = m.instruct( "Make a plot of y=x^2", - model_options={ModelOption.TOOLS: [tool]} + model_options={ModelOption.TOOLS: [tool]}, + tool_calls=True ) + +# Print the tool calls +print("Tool calls:", result.tool_calls) + +# Access the generated code +if result.tool_calls: + code = result.tool_calls["python"].args["code"] + print(f"Generated code:\n{code}") ``` ### Forcing Tool Use @@ -80,8 +103,8 @@ from mellea.backends import ModelOption from mellea.stdlib.requirements import uses_tool from mellea.stdlib.tools import python_tool -tool = python_tool(tier="local_unsafe", name="python") m = start_session() +tool = python_tool(tier='docker_unsafe') result = m.instruct( "Use the code interpreter to make a plot of y=x^2", requirements=[uses_tool("python")], @@ -95,17 +118,28 @@ print(f"Generated code:\n{code}") # Execute the tool exec_result = result.tool_calls["python"].call_func() +print(f"Execution success: {exec_result.success}") +print(f"Exit code: {exec_result.exit_code}") + +# Check for generated artifacts (plots, images, etc.) +if exec_result.artifacts: + print(f"Generated artifacts: {len(exec_result.artifacts)}") + for artifact in exec_result.artifacts: + print(f" - {artifact.path}") +else: + print("No artifacts generated (plot saved internally)") ``` ### Validating Tool Arguments + ```python from mellea import start_session from mellea.backends import ModelOption from mellea.stdlib.requirements import tool_arg_validator, uses_tool from mellea.stdlib.tools import python_tool -tool = python_tool(tier="local_unsafe", name="python") m = start_session() +tool = python_tool(tier='docker_unsafe') result = m.instruct( "Use the code interpreter to make a plot of y=x^2", requirements=[ @@ -120,6 +154,20 @@ result = m.instruct( model_options={ModelOption.TOOLS: [tool]}, tool_calls=True ) + +# Access the tool call +code = result.tool_calls["python"].args["code"] +print(f"Generated code:\n{code}") + +# Verify the constraint was satisfied +if "/tmp/output.png" in code: + print("\nāœ“ Code constraint satisfied: plot will be saved to /tmp/output.png") +else: + print("\nāœ— Code constraint NOT satisfied") + +# Execute the tool +exec_result = result.tool_calls["python"].call_func() +print(f"Execution success: {exec_result.success}") ``` ## Available Tools @@ -129,37 +177,67 @@ result = m.instruct( - `python_tool(tier="docker_unsafe")`: Execute Python code in Docker (no resource limits) - `python_tool(tier="docker")`: Execute Python code in Docker with capability policy +### Python Tool + +- `python_tool`: Execute Python code with configurable execution tiers + (e.g., `tier='docker_unsafe'` for sandboxed, `tier='local'` for local + execution) + ### Custom Tools Create custom tools by defining functions: + ```python +from mellea import start_session +from mellea.backends import ModelOption from mellea.backends.tools import MelleaTool def my_tool(arg1: str, arg2: int) -> str: """Tool description for the LLM.""" return f"Processed {arg1} with {arg2}" -# Use in model_options -model_options={ModelOption.TOOLS: [MelleaTool.from_callable(my_tool)]} +m = start_session() +result = m.instruct( + "Use my_tool to process 'hello' with 5", + model_options={ModelOption.TOOLS: [MelleaTool.from_callable(my_tool)]}, + tool_calls=True +) + +# Access the tool call +print("Tool calls:", result.tool_calls) + +if result.tool_calls: + # Get the tool call details + tool_call = result.tool_calls["my_tool"] + print(f"Tool name: {tool_call.name}") + print(f"Arguments: {tool_call.args}") + + # Execute the tool + tool_result = tool_call.call_func() + print(f"Tool result: {tool_result}") ``` ## Tool Requirements ### uses_tool + Ensures the LLM uses a specific tool: + ```python from mellea.stdlib.requirements import uses_tool -requirements=[uses_tool(my_tool)] +requirements=[uses_tool("python")] ``` ### tool_arg_validator + Validates tool arguments: + ```python from mellea.stdlib.requirements import tool_arg_validator tool_arg_validator( description="Validation description", - tool_name=my_tool, + tool_name="my_tool", arg_name="arg1", validation_fn=lambda x: len(x) > 5 ) @@ -168,13 +246,14 @@ tool_arg_validator( ## Safety Considerations - **Tier selection**: Pass `tier=` explicitly — `"local_unsafe"` runs code as an unrestricted subprocess; use `"docker"` for real isolation +- **Sandboxing**: Use `python_tool(tier='docker_unsafe')` for untrusted code; + use `tier='local'` only for trusted code - **Validation**: Always validate tool arguments - **Permissions**: Be careful with file system access - **Resource Limits**: Set timeouts and memory limits ## Related Documentation -- See `mellea/stdlib/tools/interpreter.py` for interpreter implementation +- See `mellea/stdlib/tools/python_tool.py` for python_tool implementation - See `mellea/stdlib/requirements/tool_reqs.py` for tool requirements -- See `docs/dev/tool_calling.md` for architecture details -- See `test/backends/test_tool_calls.py` for more examples \ No newline at end of file +- See `test/backends/test_tool_calls.py` for more examples From 6cd1ce1d05bef156c42b846067c0c0d76b5f19dd Mon Sep 17 00:00:00 2001 From: Akihiko Kuroda Date: Wed, 24 Jun 2026 14:41:53 -0400 Subject: [PATCH 2/3] review comment Signed-off-by: Akihiko Kuroda --- docs/examples/tools/README.md | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/docs/examples/tools/README.md b/docs/examples/tools/README.md index 6d54ba882..551f44c9c 100644 --- a/docs/examples/tools/README.md +++ b/docs/examples/tools/README.md @@ -64,7 +64,7 @@ Shows how to use the `@tool` decorator for tool definition. from mellea.stdlib.tools import python_tool # Create the tool -tool = python_tool(tier='docker_unsafe') +tool = python_tool(tier="local_unsafe", name="python") # Execute code directly result = tool.run(code="print(1+1)") @@ -78,9 +78,8 @@ from mellea import start_session from mellea.backends import ModelOption from mellea.stdlib.tools import python_tool -tool = python_tool(tier="local_unsafe", name="python") m = start_session() -tool = python_tool(tier='docker_unsafe') +tool = python_tool(tier="local_unsafe", name="python") result = m.instruct( "Make a plot of y=x^2", model_options={ModelOption.TOOLS: [tool]}, @@ -104,7 +103,7 @@ from mellea.stdlib.requirements import uses_tool from mellea.stdlib.tools import python_tool m = start_session() -tool = python_tool(tier='docker_unsafe') +tool = python_tool(tier="local_unsafe", name="python") result = m.instruct( "Use the code interpreter to make a plot of y=x^2", requirements=[uses_tool("python")], @@ -139,7 +138,7 @@ from mellea.stdlib.requirements import tool_arg_validator, uses_tool from mellea.stdlib.tools import python_tool m = start_session() -tool = python_tool(tier='docker_unsafe') +tool = python_tool(tier="local_unsafe", name="python") result = m.instruct( "Use the code interpreter to make a plot of y=x^2", requirements=[ @@ -177,12 +176,6 @@ print(f"Execution success: {exec_result.success}") - `python_tool(tier="docker_unsafe")`: Execute Python code in Docker (no resource limits) - `python_tool(tier="docker")`: Execute Python code in Docker with capability policy -### Python Tool - -- `python_tool`: Execute Python code with configurable execution tiers - (e.g., `tier='docker_unsafe'` for sandboxed, `tier='local'` for local - execution) - ### Custom Tools Create custom tools by defining functions: @@ -246,14 +239,12 @@ tool_arg_validator( ## Safety Considerations - **Tier selection**: Pass `tier=` explicitly — `"local_unsafe"` runs code as an unrestricted subprocess; use `"docker"` for real isolation -- **Sandboxing**: Use `python_tool(tier='docker_unsafe')` for untrusted code; - use `tier='local'` only for trusted code - **Validation**: Always validate tool arguments - **Permissions**: Be careful with file system access - **Resource Limits**: Set timeouts and memory limits ## Related Documentation -- See `mellea/stdlib/tools/python_tool.py` for python_tool implementation +- See `mellea/stdlib/tools/interpreter.py` for python_tool implementation - See `mellea/stdlib/requirements/tool_reqs.py` for tool requirements - See `test/backends/test_tool_calls.py` for more examples From 7d0f24a1890d271d032f481a2fb84879f1ee140c Mon Sep 17 00:00:00 2001 From: Akihiko Kuroda Date: Wed, 24 Jun 2026 15:05:28 -0400 Subject: [PATCH 3/3] review comment Signed-off-by: Akihiko Kuroda --- docs/examples/tools/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/examples/tools/README.md b/docs/examples/tools/README.md index 551f44c9c..a7d6bd250 100644 --- a/docs/examples/tools/README.md +++ b/docs/examples/tools/README.md @@ -103,9 +103,9 @@ from mellea.stdlib.requirements import uses_tool from mellea.stdlib.tools import python_tool m = start_session() -tool = python_tool(tier="local_unsafe", name="python") +tool = python_tool(tier="local_unsafe", name="python", packages=["matplotlib"]) result = m.instruct( - "Use the code interpreter to make a plot of y=x^2", + "Use the code interpreter to make and save a plot of y=x^2", requirements=[uses_tool("python")], model_options={ModelOption.TOOLS: [tool]}, tool_calls=True