Skip to content

Commit dfd2b8b

Browse files
committed
update an example
Signed-off-by: Akihiko Kuroda <akihikokuroda2020@gmail.com>
1 parent a9be3c5 commit dfd2b8b

1 file changed

Lines changed: 48 additions & 3 deletions

File tree

docs/examples/tools/shell_example.py

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,22 @@
1-
# pytest: unit, qualitative
1+
# pytest: unit, qualitative, ollama, e2e
22
"""Example usage patterns for bash_executor and local_bash_executor tools.
33
4-
Demonstrates three ways to use Mellea's bash execution capabilities:
4+
Demonstrates multiple ways to use Mellea's bash execution capabilities:
55
1. Direct execution for non-LLM tasks
66
2. Wrapping as a MelleaTool for agent use
7-
3. Integration with requirements framework for rejection sampling
7+
3. LLM-based tool calling with forced tool use
8+
4. Integration with error handling
89
910
Safety note: bash_executor uses Docker isolation via llm-sandbox (recommended
1011
for production). local_bash_executor runs commands directly (for dev/testing only).
1112
Both enforce a conservative safety denylist: no sudo, no rm -rf, no destructive
1213
git operations, no writes to /etc, /sys, /proc, etc.
1314
"""
1415

16+
from mellea import MelleaSession, start_session
17+
from mellea.backends import ModelOption
1518
from mellea.backends.tools import MelleaTool
19+
from mellea.stdlib.requirements import uses_tool
1620
from mellea.stdlib.tools.shell import bash_executor, local_bash_executor
1721

1822

@@ -60,6 +64,41 @@ def example_2_wrapped_as_tool() -> None:
6064
print()
6165

6266

67+
def example_3_llm_with_forced_tool_use(m: MelleaSession) -> None:
68+
"""Example 3: LLM generates bash commands with forced tool use (requires Ollama).
69+
70+
This mirrors the Python interpreter pattern: ask the LLM to generate
71+
a bash command, force it to use the tool, then execute the command.
72+
"""
73+
print("=== Example 3: LLM-Generated Bash Commands with Forced Tool Use ===")
74+
75+
result = m.instruct(
76+
description="Use bash to count how many Python files are in the current directory.",
77+
requirements=[uses_tool(local_bash_executor)],
78+
model_options={
79+
ModelOption.TOOLS: [MelleaTool.from_callable(local_bash_executor)]
80+
},
81+
tool_calls=True,
82+
)
83+
84+
if result.tool_calls is None:
85+
raise ValueError("Expected tool_calls but got None")
86+
87+
# Extract the bash command the LLM generated
88+
command = result.tool_calls["local_bash_executor"].args["command"]
89+
print(f"LLM generated bash command:\n {command}\n")
90+
91+
# Execute the command
92+
exec_result = result.tool_calls["local_bash_executor"].call_func()
93+
94+
print("Execution result:")
95+
print(f" Success: {exec_result.success}")
96+
print(f" Output: {exec_result.stdout}")
97+
if exec_result.stderr:
98+
print(f" Error: {exec_result.stderr}")
99+
print()
100+
101+
63102
def example_3_with_working_dir() -> None:
64103
"""Example 3: Restrict command execution to a specific directory."""
65104
print("=== Example 3: Working Directory Restriction ===")
@@ -136,6 +175,12 @@ def example_5_error_handling() -> None:
136175
if __name__ == "__main__":
137176
example_1_direct_execution()
138177
example_2_wrapped_as_tool()
178+
179+
# Example 3 requires a running Mellea session with LLM (Ollama recommended)
180+
# Uncomment to run with LLM:
181+
# m = start_session()
182+
# example_3_llm_with_forced_tool_use(m)
183+
139184
example_3_with_working_dir()
140185
example_4_safety_features()
141186
example_5_error_handling()

0 commit comments

Comments
 (0)