Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
Het bèta-Python-pakket agent-framework-tools biedt shell-uitvoering en hulpprogramma's voor omgevingsbewustzijn via de agent_framework.tools naamruimte.
| Tool | Gebruik deze wanneer |
|---|---|
LocalShellTool |
Opdrachten worden als vertrouwd beschouwd of individueel goedgekeurd en moeten worden uitgevoerd in de hostomgeving van het agentproces. |
DockerShellTool |
Door model gegenereerde shell-opdrachten hebben OCI-containerisolatie nodig. |
ShellEnvironmentProvider |
Het model heeft de actieve shell-familie, het besturingssysteem, de werkmap en de geïnstalleerde CLI-versies nodig. |
ShellPolicy |
U wilt een vooraf filter voor toestaan of weigeren voordat goedkeuring of uitvoering wordt uitgevoerd. |
Warning
Shell-uitvoering kan bestanden wijzigen, processen starten, referenties openen en communiceren met externe systemen. Gebruik de laag met minimale bevoegdheden die ondersteuning biedt voor de taak.
Installeer het pakket
dotnet add package Microsoft.Agents.AI.Tools.Shell --prerelease
Gebruik de lokale shell en kennis van de omgeving
LocalShellExecutor ondersteunt toestandsloze en persistente modi.
ShellEnvironmentProvider test de actieve omgeving en voegt gezaghebbende shellrichtlijnen toe aan de agentcontext.
using Azure.AI.Projects;
using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.Agents.AI.Tools.Shell;
using Microsoft.Extensions.AI;
var endpoint = Environment.GetEnvironmentVariable("FOUNDRY_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("FOUNDRY_PROJECT_ENDPOINT is not set.");
var deploymentName = Environment.GetEnvironmentVariable("FOUNDRY_MODEL") ?? "gpt-5.4-mini";
// WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production.
// In production, consider using a specific credential (e.g., ManagedIdentityCredential) to avoid
// latency issues, unintended credential probing, and potential security risks from fallback mechanisms.
var aiProjectClient = new AIProjectClient(new Uri(endpoint), new DefaultAzureCredential());
const string Instructions = """
You are an agent with a single tool: run_shell. Use it to satisfy the
user's request. Do not describe what you would do — actually run the
commands. Reply with the final answer derived from real output.
""";
// --------------------------------------------------------------------
// 1. Stateless mode — each call gets a fresh shell.
// --------------------------------------------------------------------
Console.WriteLine("### Stateless mode\n");
await using (var statelessShell = new LocalShellExecutor(new() { Mode = ShellMode.Stateless, AcknowledgeUnsafe = true }))
{
var envProvider = new ShellEnvironmentProvider(statelessShell);
var statelessAgent = aiProjectClient.AsAIAgent(new ChatClientAgentOptions
{
ChatOptions = new()
{
ModelId = deploymentName,
Instructions = Instructions,
Tools = [statelessShell.AsAIFunction(requireApproval: false)],
},
AIContextProviders = [envProvider],
});
// --------------------------------------------------------------------
// 2. Persistent mode — one shell, reused across calls. State carries.
// --------------------------------------------------------------------
Console.WriteLine("\n### Persistent mode\n");
await using (var persistentShell = new LocalShellExecutor(new() { Mode = ShellMode.Persistent, AcknowledgeUnsafe = true }))
{
var envProvider = new ShellEnvironmentProvider(persistentShell);
var persistentAgent = aiProjectClient.AsAIAgent(new ChatClientAgentOptions
{
ChatOptions = new()
{
ModelId = deploymentName,
Instructions = Instructions,
Tools = [persistentShell.AsAIFunction(requireApproval: false)],
},
AIContextProviders = [envProvider],
});
var persistentSession = await persistentAgent.CreateSessionAsync();
// State carries across calls in persistent mode: cd into temp, then
// verify the next call sees the new CWD.
Console.WriteLine(await persistentAgent.RunAsync("Change directory into the system temp folder, then print the current working directory.", persistentSession));
Console.WriteLine();
Console.WriteLine(await persistentAgent.RunAsync("In a NEW shell call, print the current working directory again. Tell me whether it still matches the temp folder.", persistentSession));
Console.WriteLine();
// Same idea with an exported variable: set in one call, read in the next.
Console.WriteLine(await persistentAgent.RunAsync("Set the environment variable DEMO_TOKEN to the value 'hello-world'.", persistentSession));
Console.WriteLine();
Console.WriteLine(await persistentAgent.RunAsync("Print the current value of DEMO_TOKEN. Tell me exactly what value the shell reports.", persistentSession));
Console.WriteLine();
PrintSnapshot(envProvider.CurrentSnapshot!);
}
ShellPolicy is ook beschikbaar voor het vooraf filteren van opdrachten. Er is momenteel geen afzonderlijk DockerShellExecutor uitvoerbaar voorbeeld gepubliceerd.
Installeer het pakket
pip install agent-framework-tools --pre
Het pakket installeert psutil om onderliggende procesbomen te beëindigen wanneer een uitvoering een time-out bereikt.
Gebruik LocalShellTool
LocalShellTool voert opdrachten rechtstreeks op de host uit. Standaard gebruikt het een persistente shell, een time-out van 30 seconden, afkapping van uitvoer tot 64 KiB en herverankering van de werkmap. Agent-aanroepen via as_function() vereisen standaard goedkeuring. Voor directe aanroepen naar run() is geen goedkeuring vereist.
import asyncio
from typing import Any
from agent_framework import Agent, Message
from agent_framework.openai import OpenAIChatClient
from agent_framework.tools import LocalShellTool
from dotenv import load_dotenv
# Load environment variables from .env file
load_dotenv()
async def main() -> None:
print("=== OpenAI Agent with LocalShellTool Example ===")
print("NOTE: Commands will execute on your local machine.\n")
client = OpenAIChatClient(model="gpt-5.4-nano")
async with LocalShellTool() as shell:
agent = Agent(
client=client,
instructions="You are a helpful assistant that can run shell commands to help the user.",
tools=[client.get_shell_tool(func=shell.as_function())],
)
query = "Use the shell tool to execute `python --version` and show only the command output."
print(f"User: {query}")
result = await run_with_approvals(query, agent)
if isinstance(result, str):
print(f"Agent: {result}\n")
return
if result.text:
print(f"Agent: {result.text}\n")
else:
printed = False
for message in result.messages:
for content in message.contents:
if content.type == "function_result" and content.result:
print(f"Agent (tool output): {content.result}\n")
printed = True
if not printed:
print("Agent: (no text output returned)\n")
async def run_with_approvals(query: str, agent: Agent) -> Any:
"""Run the agent and handle shell approvals outside tool execution."""
current_input: str | list[Any] = query
while True:
result = await agent.run(current_input)
if not result.user_input_requests:
return result
next_input: list[Any] = [query]
rejected = False
for user_input_needed in result.user_input_requests:
if user_input_needed.function_call is None:
continue
print(
f"\nShell request: {user_input_needed.function_call.name}"
f"\nArguments: {user_input_needed.function_call.arguments}"
)
user_approval = await asyncio.to_thread(input, "\nApprove shell command? (y/n): ")
approved = user_approval.strip().lower() == "y"
next_input.append(Message("assistant", [user_input_needed]))
next_input.append(Message("user", [user_input_needed.to_function_approval_response(approved)]))
if not approved:
rejected = True
break
if rejected:
print("\nShell command rejected. Stopping without additional approval prompts.")
return "Shell command execution was rejected by user."
current_input = next_input
if __name__ == "__main__":
asyncio.run(main())
Directe aanroepen naar run() retourneren een ShellResult met afzonderlijke stdout, stderr, exit_code, duration_ms, truncated en timed_out velden. Wanneer de shell wordt uitgevoerd via OpenAI Responses of Foundry-hosting, behoudt Agent Framework standaarduitvoer, standaardfout, afsluitresultaten en time-outresultaten bij providercontinuatie. Niet-nuluitgangen blijven fouten, standaardfoutuitvoer blijft gescheiden en een time-out geldt niet als een succesvolle beëindiging.
Transcriptitems van openAI-shell die door de provider worden gehost, blijven informatief, zelfs wanneer een lokale shell-uitvoerder is geconfigureerd. Alleen een goed gevormde expliciete local_shell_call, of een shell-aanroep gemarkeerd met environment.type="local", komt in de lokale functie en het goedkeuringstraject terecht. Alleen het configureren van LocalShellTool zorgt er niet voor dat providergehoste shell-aanroepen op de host worden uitgevoerd.
Gebruik mode="stateless" wanneer elke aanroep in een nieuw proces moet worden uitgevoerd. Gebruik de AGENT_FRAMEWORK_SHELL omgevingsvariabele of het shell constructorargument om de opgeloste shell te overschrijven.
Persistente opdrachten worden geserialiseerd. Na een overloop van uitvoer of na een time-out die de sessie onherstelbaar laat, begint een opdracht in de wachtrij in een nieuwe shell en raakt shell-lokale variabelen, functies en wijzigingen in de werkmap van de beëindigde sessie kwijt. Een gecontroleerd onderbroken POSIX-time-out kan de bestaande shell en de status ervan behouden. Op Windows sluit een time-out altijd de huidige permanente shell, zelfs als de onderbroken opdracht de voltooiingsmarkering verzendt.
Als u close() aanroept, worden opdrachten in de wachtrij van vóór of tijdens het afsluiten geweigerd in plaats van de shell opnieuw te starten. Een latere oproep kan een nieuwe sessie openen.
Belangrijk
LocalShellTool is geen sandbox. Menselijke goedkeuring voegt een beoordelingspoort toe, maar de shell wordt niet geïsoleerd. Het uitschakelen van goedkeuring voor oproepen van de agent vereist acknowledge_unsafe=True.
Opdrachten beperken met ShellPolicy
ShellPolicy past lijsten met reguliere expressies voor toegestane en geblokkeerde items toe op de opdrachttekst voordat deze wordt uitgevoerd. Weigeringsregels hebben voorrang. Er wordt niet gecontroleerd wat de shell uiteindelijk uitvoert of de toegang tot bestanden beperkt.
import asyncio
from agent_framework import Agent
from agent_framework.openai import OpenAIChatClient
from agent_framework.tools import LocalShellTool, ShellPolicy
from dotenv import load_dotenv
load_dotenv()
async def main() -> None:
client = OpenAIChatClient(model="gpt-5.4-nano")
shell = LocalShellTool(
mode="stateless",
# Unsafe for production as shown: these filters do not replace human approval or isolation.
approval_mode="never_require",
acknowledge_unsafe=True,
policy=ShellPolicy(
allowlist=[
r"^ls(\s|$)",
r"^pwd$",
r"^cat\s[^|;&]+$",
r"^git\s+(status|log|diff)(\s|$)",
r"^python\s+--version$",
],
),
timeout=10,
)
agent = Agent(
client=client,
instructions=("Use only these shell commands: ls, pwd, cat, git status/log/diff, python --version."),
tools=[client.get_shell_tool(func=shell.as_function())],
)
Warning
Het voorbeeld schakelt menselijke goedkeuring uit en is alleen geschikt voor een geïsoleerde, wegwerpomgeving zonder geheimen of waardevolle gegevens. Opdrachtvervangingen, zoals $(...) en backticks, kunnen eenvoudige patronen voor acceptatielijsten doorgeven. Patronen die alleen overeenkomen met het begin van een opdracht kunnen ook extra bewerkingen toestaan. Gebruik afzonderlijk afgedwongen isolatie en beperkte machtigingen voor productie. Menselijke beoordeling kan een controle toevoegen, maar de shell wordt niet geïsoleerd.
Geef de voorkeur aan tekenreekspatronen. Python compileert tekenreeksen met de regex-engine en hanteert een tijdslimiet van één seconde voor elke match. Een time-out voor de weigeringslijst weigert de opdracht en een time-out voor de acceptatielijst verleent geen machtiging. Een voorgecompileerde regex.Pattern gebruikt dezelfde grens. Een voorgecompileerde standaardbibliotheek re.Pattern behoudt zijn vlaggen, maar kan niet worden onderbroken, dus vermijd kostbare of dubbelzinnige expressies in die vorm.
ShellEnvironmentProvider toevoegen
ShellEnvironmentProvider test de shell-familie, versie, besturingssysteem, werkmap en geselecteerde CLI-versies, en injecteert die informatie voordat de agent wordt uitgevoerd. De standaardprobelijst is git, node, python en docker.
import asyncio
from agent_framework import Agent
from agent_framework.openai import OpenAIChatClient
from agent_framework.tools import (
LocalShellTool,
ShellEnvironmentProvider,
ShellEnvironmentProviderOptions,
)
from dotenv import load_dotenv
load_dotenv()
def _print_snapshot(label: str, provider: ShellEnvironmentProvider) -> None:
snapshot = provider.current_snapshot
if snapshot is None:
print(f"[{label}] no snapshot captured")
return
print(f"\n[{label}] snapshot:")
print(f" family = {snapshot.family.value}")
print(f" os = {snapshot.os_description}")
print(f" shell_version = {snapshot.shell_version}")
print(f" working_directory = {snapshot.working_directory}")
for tool, version in snapshot.tool_versions.items():
print(f" {tool:<17} = {version}")
async def _ask(agent: Agent, query: str) -> None:
print(f"\nUser: {query}")
result = await agent.run(query)
if result.text:
print(f"Agent: {result.text}")
async def main() -> None:
client = OpenAIChatClient(model="gpt-5.4-nano")
options = ShellEnvironmentProviderOptions(
probe_tools=("git", "python", "uv", "node"),
)
print("=== stateless mode ===")
async with LocalShellTool(
mode="stateless",
approval_mode="never_require",
acknowledge_unsafe=True,
) as shell:
provider = ShellEnvironmentProvider(shell, options)
agent = Agent(
client=client,
instructions="Use the shell tool to answer the user's question.",
tools=[client.get_shell_tool(func=shell.as_function())],
context_providers=[provider],
)
await _ask(agent, "Show me the current working directory.")
await _ask(agent, "Now `cd ..` then show the working directory again.")
await _ask(agent, "Show the working directory once more — did `cd` persist?")
_print_snapshot("stateless", provider)
print("\n=== persistent mode ===")
async with LocalShellTool(
mode="persistent",
confine_workdir=False,
approval_mode="never_require",
acknowledge_unsafe=True,
) as shell:
provider = ShellEnvironmentProvider(shell, options)
agent = Agent(
client=client,
instructions="Use the shell tool to answer the user's question.",
tools=[client.get_shell_tool(func=shell.as_function())],
context_providers=[provider],
)
await _ask(agent, "Show me the current working directory.")
await _ask(agent, "Now `cd ..` then show the working directory again.")
await _ask(agent, "Show the working directory once more — did `cd` persist?")
_print_snapshot("persistent", provider)
Gebruik DockerShellTool
DockerShellTool vereist Docker of Podman op PATH. De standaardinstellingen schakelen netwerkfunctionaliteit uit, worden uitgevoerd als een gebruiker zonder rootrechten, gebruiken een alleen-lezen rootbestandssysteem, laten capabilities vallen, beperken het geheugen tot 512 MiB en beperken het aantal processen in de container tot 256.
from agent_framework.tools import DockerShellTool
async with DockerShellTool(
image="mcr.microsoft.com/azurelinux/base/core:3.0",
approval_mode="never_require",
) as shell:
result = await shell.run("uname -a && id")
print(result.stdout)
De standaardafbeelding is mcr.microsoft.com/azurelinux/base/core:3.0. Geef docker_binary="podman" door om Podman te gebruiken. Er is momenteel geen afzonderlijk DockerShellTool uitvoerbaar voorbeeld gepubliceerd.
Gebruik extra_run_args alleen voor Docker-opties die de geconfigureerde isolatie- of resourcelimieten niet verzwakken. Validatie herkent lange vlaggen, korte vlaggen, gekoppelde waarden en gegroepeerde korte vlaggen. Het wijst overschrijvingen af, zoals -u / --user, -m / --memory, / --volume-v, --network, en --pids-limit. Gebruik in plaats daarvan de bijbehorende DockerShellTool constructoroptie.
Een uitvoeringslaag kiezen
| Scenario | Tool | Isolatiegrens |
|---|---|---|
| Vertrouwde ontwikkelopdrachten | LocalShellTool |
Geen; menselijke goedkeuring is standaard ingeschakeld |
| Niet-vertrouwde shell-opdrachten | DockerShellTool |
OCI-container met standaardisolatievlagmen |
| Niet-vertrouwde gegenereerde code zonder shell | Hyperlight CodeAct | Hyperlight microVM |
Go biedt lokale shelluitvoering en omgevingsdetectie via tool/shelltool. Zie Het lokale shell-hulpprogramma gebruiken.
DockerShellTool richtlijnen zijn momenteel niet beschikbaar voor Go.
Shell-hulpprogramma's gebruiken met Harness Agent
Gewone agents en HarnessAgent gebruiken dezelfde tweedelige shellinstallatie: registreer de functie van de uitvoerder als een hulpprogramma en voeg toe ShellEnvironmentProvider wanneer het model shell, besturingssysteem, werkmap en CLI-versiecontext moet ontvangen.
HarnessAgent maakt of bezit geen shell-uitvoerprogramma:
using System.IO;
using Microsoft.Agents.AI;
using Microsoft.Agents.AI.Tools.Shell;
using Microsoft.Extensions.AI;
await using var shell = new LocalShellExecutor(new LocalShellExecutorOptions
{
WorkingDirectory = Directory.GetCurrentDirectory(),
Timeout = LocalShellExecutor.DefaultTimeout,
});
AIAgent agent = chatClient.AsHarnessAgent(new HarnessAgentOptions
{
AIContextProviders = [new ShellEnvironmentProvider(shell)],
ChatOptions = new ChatOptions
{
Tools = [shell.AsAIFunction(requireApproval: true)],
},
});
AsAIFunction is standaard ingesteld op de naam run_shell en requireApproval: true.
LocalShellExecutor standaard ingesteld op permanente modus, een limiet van 64 KiB per uitvoerstroom en geen time-out; in het voorbeeld wordt expliciet de aanbevolen 30 seconden LocalShellExecutor.DefaultTimeoutgebruikt.
ShellEnvironmentProviderOptions is standaard ingesteld op het testen van git, dotnet, node, python en docker, met een time-out van vijf seconden per test.
Maak één permanente uitvoerder per gebruikerssessie en verwijder deze wanneer de sessie afloopt. Deel deze niet tussen gebruikers of gelijktijdige gesprekken omdat werkmap, omgeving, shellgeschiedenis, achtergrondtaken en de opdrachtwachtrij worden gedeeld.
ShellPolicy is alleen een voorfilter; goedkeuring ingeschakeld houden, referenties met minimale bevoegdheden gebruiken en de voorkeur geven DockerShellExecutor aan wanneer opdrachten een sterkere isolatiegrens vereisen.
Shell-hulpprogramma's zijn beschikbaar via het voorlopige Microsoft.Agents.AI.Tools.Shell pakket.
HarnessAgent is beschikbaar vanaf Microsoft.Agents.AI.Harness.
Voor een gewone agent maakt u de shell-functie met client.get_shell_tool(func=shell.as_function()) en voegt u deze afzonderlijk toe ShellEnvironmentProvider .
create_harness_agent voert beide stappen uit wanneer u shell_executor doorgeeft:
from agent_framework import create_harness_agent
from agent_framework.tools import LocalShellTool, ShellEnvironmentProviderOptions
async with LocalShellTool() as shell:
agent = create_harness_agent(
client=client,
shell_executor=shell,
shell_environment_provider_options=ShellEnvironmentProviderOptions(
probe_tools=("git", "python"),
),
)
session = agent.create_session()
response = await agent.run("Inspect the current repository.", session=session)
shell_executor is optioneel en moet as_function() beschikbaar stellen. De factory voegt het shell-hulpprogramma en ShellEnvironmentProvider alleen toe wanneer de client SupportsShellTool implementeert; anders wordt er een waarschuwing gelogd en worden beide overgeslagen.
shell_environment_provider_options is optioneel en wordt alleen gebruikt met shell_executor.
LocalShellTool is standaard ingesteld op persistente modus, een time-out van 30 seconden, 64 KiB gecombineerde uitvoer, het opnieuw verankeren van de werkmap en approval_mode="always_require". Omdat goedkeuring voor Harness-tools standaard is ingeschakeld, geeft u een AgentSession mee aan run. De aanroeper beheert de levenscyclus van de executor; gebruik async with of roep close() aan, en maak één persistent hulpprogramma per gebruikerssessie. Deel geen wijzigbare shellstatus tussen gebruikers of gelijktijdige gesprekken.
De hostshell is geen sandbox. Houd goedkeuring ingeschakeld, gebruik aanmeldgegevens met minimale rechten en gebruik DockerShellTool voor containerisolatie. Het uitschakelen van goedkeuring vereist approval_mode="never_require" en acknowledge_unsafe=True; ShellPolicy alleen is geen beveiligingsgrens.
create_harness_agent wordt uitgebracht in agent-framework-core. Shell-integratie wordt geleverd door het pre-releasepakket agent-framework-tools en verzendt een ExperimentalWarning wanneer deze optie is ingeschakeld.
Een verpakte Go Harness is momenteel niet beschikbaar. Stel het lokale shell-hulpprogramma en de omgevingsprovider rechtstreeks samen op een gewone Go-agent.