SPB Git

Repository Public

tools-shell.md 52.3 KB 2,001 lines markdown

1# Shell23> For the complete documentation index, see [llms.txt](/llms.txt). Markdown versions of documentation pages are available by appending `.md` to the page URL.45The shell tool gives models the ability to work inside a complete terminal environment. We support shell for local execution and for hosted execution through the Responses API.67The shell tool lets models run commands through either:89- Hosted shell containers managed by OpenAI.10- [A local shell runtime](#local-shell-mode) that you host and execute yourself.1112Shell is available through the [Responses API](https://developers.openai.com/api/docs/guides/migrate-to-responses). It's not available via the Chat Completions API.1314Running arbitrary shell commands can be dangerous. Always sandbox execution,15  apply allowlists or denylists where possible, and log tool activity for16  auditing.1718## Hosted shell quickstart1920Hosted shell is a native and streamlined option for tasks that need richer, deterministic processing, from running calculations to working with multimedia.2122Use `container_auto` when you want OpenAI to provision and manage a container for the request.2324Shell tool with container_auto2526```bash27curl -L 'https://api.openai.com/v1/responses' \28  -H "Content-Type: application/json" \29  -H "Authorization: Bearer $OPENAI_API_KEY" \30  -d '{31    "model": "gpt-6-astra",32    "tools": [33      { "type": "shell", "environment": { "type": "container_auto" } }34    ],35    "input": [36      {37        "type": "message",38        "role": "user",39        "content": [40          { "type": "input_text", "text": "Execute: ls -lah /mnt/data && python --version && node --version" }41        ]42      }43    ],44    "tool_choice": "auto"45  }'46```4748```javascript49import OpenAI from "openai";5051const client = new OpenAI();5253const response = await client.responses.create({54  model: "gpt-6-astra",55  tools: [{ type: "shell", environment: { type: "container_auto" } }],56  input: [57    {58      type: "message",59      role: "user",60      content: [61        {62          type: "input_text",63          text: "Execute: ls -lah /mnt/data && python --version && node --version",64        },65      ],66    },67  ],68  tool_choice: "auto",69});7071console.log(response.output_text);72```7374```python75from openai import OpenAI7677client = OpenAI()7879response = client.responses.create(80    model="gpt-6-astra",81    tools=[{"type": "shell", "environment": {"type": "container_auto"}}],82    input=[83        {84            "type": "message",85            "role": "user",86            "content": [87                {88                    "type": "input_text",89                    "text": "Execute: ls -lah /mnt/data && python --version && node --version",90                }91            ],92        }93    ],94    tool_choice="auto",95)9697print(response.output_text)98```99100```go101package main102103import (104	"context"105	"fmt"106107	"github.com/openai/openai-go/v3"108	"github.com/openai/openai-go/v3/responses"109)110111func main() {112	client := openai.NewClient()113	tool := responses.ToolUnionParam{OfShell: &responses.FunctionShellToolParam{114		Environment: responses.FunctionShellToolEnvironmentUnionParam{OfContainerAuto: &responses.ContainerAutoParam{}},115	}}116	response, err := client.Responses.New(context.Background(), responses.ResponseNewParams{117		Model: "gpt-6-astra",118		Tools: []responses.ToolUnionParam{tool},119		Input: responses.ResponseNewParamsInputUnion{OfString: openai.String("Execute: ls -lah /mnt/data && python --version && node --version")},120	})121	if err != nil {122		panic(err)123	}124	fmt.Println(response.OutputText())125}126```127128```java129import com.openai.client.OpenAIClient;130import com.openai.client.okhttp.OpenAIOkHttpClient;131import com.openai.models.responses.ContainerAuto;132import com.openai.models.responses.FunctionShellTool;133import com.openai.models.responses.ResponseCreateParams;134135ResponseCreateParams params =136    ResponseCreateParams.builder()137        .model("gpt-6-astra")138        .input("Run ls -lah /mnt/data, then show the Python and Node.js versions.")139        .addTool(140            FunctionShellTool.builder().environment(ContainerAuto.builder().build()).build())141        .build();142143client.responses().create(params).output().stream()144    .flatMap(item -> item.message().stream())145    .flatMap(message -> message.content().stream())146    .flatMap(content -> content.outputText().stream())147    .forEach(text -> System.out.println(text.text()));148```149150```ruby151require "openai"152153client = OpenAI::Client.new154response = client.responses.create(155  model: "gpt-6-astra",156  input: "Run ls -lah /mnt/data, then show the Python and Node.js versions.",157  tools: [158    {159      type: :shell,160      environment: { type: :container_auto }161    }162  ]163)164165puts(response.output_text)166```167168169## Hosted runtime details170171- Runtime is currently based on `Debian 12` and may change over time.172- Default working directory is `/mnt/data`.173- `/mnt/data` is always present and is the supported path for user-downloadable artifacts.174- Hosted shell doesn't support interactive TTY sessions.175- Hosted shell commands don't run with `sudo`.176- You can run services inside the container when your workflow needs them.177178Current preinstalled languages include:179180- Python `3.11`181- Node.js `22.16`182- Java `17.0`183- PHP `8.2`184- Ruby `3.1`185- Go `1.23`186187## Reuse a container across requests188189If you need a long-running environment for iterative workflows, create a container and then reference it in subsequent Responses API calls.190191### 1. Create a container192193Create a reusable container194195```bash196curl -L 'https://api.openai.com/v1/containers' \197  -H "Content-Type: application/json" \198  -H "Authorization: Bearer $OPENAI_API_KEY" \199  -d '{200    "name": "analysis-container",201    "memory_limit": "1g",202    "expires_after": { "anchor": "last_active_at", "minutes": 20 }203  }'204```205206```javascript207import OpenAI from "openai";208209const client = new OpenAI();210211const container = await client.containers.create({212  name: "analysis-container",213  memory_limit: "1g",214  expires_after: { anchor: "last_active_at", minutes: 20 },215});216217console.log(container.id);218```219220```python221from openai import OpenAI222223client = OpenAI()224225container = client.containers.create(226    name="analysis-container",227    memory_limit="1g",228    expires_after={"anchor": "last_active_at", "minutes": 20},229)230231print(container.id)232```233234```go235package main236237import (238	"context"239	"fmt"240241	"github.com/openai/openai-go/v3"242)243244func main() {245	client := openai.NewClient()246	container, err := client.Containers.New(context.Background(), openai.ContainerNewParams{247		Name:        "analysis-container",248		MemoryLimit: openai.ContainerNewParamsMemoryLimit1g,249		ExpiresAfter: openai.ContainerNewParamsExpiresAfter{250			Anchor:  "last_active_at",251			Minutes: 20,252		},253	})254	if err != nil {255		panic(err)256	}257	fmt.Println(container.ID)258}259```260261```java262import com.openai.client.OpenAIClient;263import com.openai.client.okhttp.OpenAIOkHttpClient;264import com.openai.models.containers.ContainerCreateParams;265266var container =267    client268        .containers()269        .create(270            ContainerCreateParams.builder()271                .name("analysis")272                .expiresAfter(273                    ContainerCreateParams.ExpiresAfter.builder()274                        .anchor(ContainerCreateParams.ExpiresAfter.Anchor.LAST_ACTIVE_AT)275                        .minutes(20)276                        .build())277                .build());278279System.out.println(container.id());280```281282```ruby283require "openai"284285client = OpenAI::Client.new286container = client.containers.create(287  name: "analysis", expires_after: {288    anchor: :last_active_at,289    minutes: 20290  }291)292puts(container.id)293```294295296### 2. Reference the container in Responses297298Use shell with container_reference299300```bash301curl -L 'https://api.openai.com/v1/responses' \302  -H "Content-Type: application/json" \303  -H "Authorization: Bearer $OPENAI_API_KEY" \304  -d '{305    "model": "gpt-6-astra",306    "tools": [307      {308        "type": "shell",309        "environment": {310          "type": "container_reference",311          "container_id": "cntr_08f3d96c87a585390069118b594f7481a088b16cda7d9415fe"312        }313      }314    ],315    "input": "List files in the container and show disk usage."316  }'317```318319```javascript320import OpenAI from "openai";321322const client = new OpenAI();323324const response = await client.responses.create({325  model: "gpt-6-astra",326  tools: [327    {328      type: "shell",329      environment: {330        type: "container_reference",331        container_id: "cntr_08f3d96c87a585390069118b594f7481a088b16cda7d9415fe",332      },333    },334  ],335  input: "List files in the container and show disk usage.",336});337338console.log(response.output_text);339```340341```python342response = client.responses.create(343    model="gpt-6-astra",344    tools=[345        {346            "type": "shell",347            "environment": {348                "type": "container_reference",349                "container_id": container.id,350            },351        }352    ],353    input="List files in the container and show disk usage.",354)355356print(response.output_text)357```358359```go360package main361362import (363	"context"364	"fmt"365366	"github.com/openai/openai-go/v3"367	"github.com/openai/openai-go/v3/responses"368)369370func main() {371	client := openai.NewClient()372	tool := responses.ToolUnionParam{OfShell: &responses.FunctionShellToolParam{373		Environment: responses.FunctionShellToolEnvironmentUnionParam{OfContainerReference: &responses.ContainerReferenceParam{ContainerID: "cntr_08f3d96c87a585390069118b594f7481a088b16cda7d9415fe"}},374	}}375	response, err := client.Responses.New(context.Background(), responses.ResponseNewParams{376		Model: "gpt-6-astra",377		Tools: []responses.ToolUnionParam{tool},378		Input: responses.ResponseNewParamsInputUnion{OfString: openai.String("List files in the container and show disk usage.")},379	})380	if err != nil {381		panic(err)382	}383	fmt.Println(response.OutputText())384}385```386387```java388import com.openai.client.OpenAIClient;389import com.openai.client.okhttp.OpenAIOkHttpClient;390import com.openai.models.responses.FunctionShellTool;391import com.openai.models.responses.ResponseCreateParams;392393String containerId = "cntr_08f3d96c87a585390069118b594f7481a088b16cda7d9415fe";394395ResponseCreateParams params =396    ResponseCreateParams.builder()397        .model("gpt-6-astra")398        .input("List files in the container and show disk usage.")399        .addTool(FunctionShellTool.builder().containerReferenceEnvironment(containerId).build())400        .build();401402client.responses().create(params).output().stream()403    .flatMap(item -> item.message().stream())404    .flatMap(message -> message.content().stream())405    .flatMap(content -> content.outputText().stream())406    .forEach(text -> System.out.println(text.text()));407```408409```ruby410require "openai"411412client = OpenAI::Client.new413response = client.responses.create(414  model: "gpt-6-astra",415  input: "List files in the container and show disk usage.",416  tools: [417    {418      type: :shell,419      environment: {420        type: :container_reference,421        container_id: "cntr_08f3d96c87a585390069118b594f7481a088b16cda7d9415fe"422      }423    }424  ]425)426427puts(response.output_text)428```429430431## Attach skills432433Skills are reusable, versioned bundles that you can mount in hosted shell environments. This defines the available skills, and at shell execution time the model decides whether to invoke them.434435Use the [Skills guide](https://developers.openai.com/api/docs/guides/tools-skills) for upload and versioning details.436437Create a container with attached skills438439```bash440curl -L 'https://api.openai.com/v1/containers' \441  -H "Content-Type: application/json" \442  -H "Authorization: Bearer $OPENAI_API_KEY" \443  -d '{444    "name": "skill-container",445    "skills": [446      { "type": "skill_reference", "skill_id": "skill_4db6f1a2c9e73508b41f9da06e2c7b5f" },447      { "type": "skill_reference", "skill_id": "openai-spreadsheets", "version": "latest" }448    ]449  }'450```451452```javascript453import OpenAI from "openai";454455const client = new OpenAI();456457const container = await client.containers.create({458  name: "skill-container",459  skills: [460    {461      type: "skill_reference",462      skill_id: "skill_4db6f1a2c9e73508b41f9da06e2c7b5f",463    },464    {465      type: "skill_reference",466      skill_id: "openai-spreadsheets",467      version: "latest",468    },469  ],470});471472console.log(container.id);473```474475```python476# Replace the illustrative IDs and URLs below with your own resource values.477from openai import OpenAI478479client = OpenAI()480skill_id = "skill_123"481482container = client.containers.create(483    name="skill-container",484    skills=[485        {486            "type": "skill_reference",487            "skill_id": skill_id,488        },489        {490            "type": "skill_reference",491            "skill_id": "openai-spreadsheets",492            "version": "latest",493        },494    ],495)496497print(container.id)498```499500```go501package main502503import (504	"context"505	"fmt"506507	"github.com/openai/openai-go/v3"508	"github.com/openai/openai-go/v3/responses"509)510511func main() {512	client := openai.NewClient()513	container, err := client.Containers.New(context.Background(), openai.ContainerNewParams{514		Name: "skill-container",515		Skills: []openai.ContainerNewParamsSkillUnion{516			{OfSkillReference: &responses.SkillReferenceParam{SkillID: "skill_4db6f1a2c9e73508b41f9da06e2c7b5f"}},517			{OfSkillReference: &responses.SkillReferenceParam{SkillID: "openai-spreadsheets", Version: openai.String("latest")}},518		},519	})520	if err != nil {521		panic(err)522	}523	fmt.Println(container.ID)524}525```526527```java528import com.openai.client.OpenAIClient;529import com.openai.client.okhttp.OpenAIOkHttpClient;530import com.openai.models.containers.ContainerCreateParams;531import com.openai.models.responses.SkillReference;532533String skillId = "skill_4db6f1a2c9e73508b41f9da06e2c7b5f";534535var container =536    client537        .containers()538        .create(539            ContainerCreateParams.builder()540                .name("skill-container")541                .addSkill(SkillReference.builder().skillId(skillId).build())542                .addSkill(543                    SkillReference.builder()544                        .skillId("openai-spreadsheets")545                        .version("latest")546                        .build())547                .build());548549System.out.println(container.id());550```551552```ruby553require "openai"554555client = OpenAI::Client.new556container = client.containers.create(557  name: "skill-container",558  skills: [559    {560      type: :skill_reference,561      skill_id: "skill_4db6f1a2c9e73508b41f9da06e2c7b5f"562    },563    {564      type: :skill_reference,565      skill_id: "openai-spreadsheets",566      version: "latest"567    }568  ]569)570571puts(container.id)572```573574575## Network access576577Hosted containers don't have outbound network access by default.578579To enable it:5805811. An admin must configure your org allow list in the dashboard.5822. You must explicitly set `network_policy` on the container environment in your request.583584Shell tool with network allowlist585586```bash587curl -L 'https://api.openai.com/v1/responses' \588  -H "Authorization: Bearer $OPENAI_API_KEY" \589  -H "Content-Type: application/json" \590  -d '{591    "model": "gpt-6-astra",592    "tool_choice": "required",593    "tools": [594      {595        "type": "shell",596        "environment": {597          "type": "container_auto",598          "network_policy": {599            "type": "allowlist",600            "allowed_domains": ["pypi.org", "files.pythonhosted.org", "github.com"]601          }602        }603      }604    ],605    "input": [606      {607        "role": "user",608        "content": "In the container, pip install httpx beautifulsoup4, fetch release pages, and write /mnt/data/release_digest.md."609      }610    ]611  }'612```613614```javascript615import OpenAI from "openai";616617const client = new OpenAI();618619const response = await client.responses.create({620  model: "gpt-6-astra",621  tool_choice: "required",622  tools: [623    {624      type: "shell",625      environment: {626        type: "container_auto",627        network_policy: {628          type: "allowlist",629          allowed_domains: ["pypi.org", "files.pythonhosted.org", "github.com"],630        },631      },632    },633  ],634  input: [635    {636      role: "user",637      content:638        "In the container, pip install httpx beautifulsoup4, fetch release pages, and write /mnt/data/release_digest.md.",639    },640  ],641});642643console.log(response.output_text);644```645646```python647from openai import OpenAI648649client = OpenAI()650651response = client.responses.create(652    model="gpt-6-astra",653    tool_choice="required",654    tools=[655        {656            "type": "shell",657            "environment": {658                "type": "container_auto",659                "network_policy": {660                    "type": "allowlist",661                    "allowed_domains": [662                        "pypi.org",663                        "files.pythonhosted.org",664                        "github.com",665                    ],666                },667            },668        }669    ],670    input=[671        {672            "role": "user",673            "content": "In the container, pip install httpx beautifulsoup4, fetch release pages, and write /mnt/data/release_digest.md.",674        }675    ],676)677678print(response.output_text)679```680681```go682package main683684import (685	"context"686	"fmt"687688	"github.com/openai/openai-go/v3"689	"github.com/openai/openai-go/v3/responses"690)691692func main() {693	client := openai.NewClient()694	tool := responses.ToolUnionParam{OfShell: &responses.FunctionShellToolParam{695		Environment: responses.FunctionShellToolEnvironmentUnionParam{OfContainerAuto: &responses.ContainerAutoParam{696			NetworkPolicy: responses.ContainerAutoNetworkPolicyUnionParam{OfAllowlist: &responses.ContainerNetworkPolicyAllowlistParam{697				AllowedDomains: []string{"pypi.org", "files.pythonhosted.org", "github.com"},698			}},699		}},700	}}701	response, err := client.Responses.New(context.Background(), responses.ResponseNewParams{702		Model:      "gpt-6-astra",703		ToolChoice: responses.ResponseNewParamsToolChoiceUnion{OfToolChoiceMode: openai.Opt(responses.ToolChoiceOptionsRequired)},704		Tools:      []responses.ToolUnionParam{tool},705		Input:      responses.ResponseNewParamsInputUnion{OfString: openai.String("In the container, pip install httpx beautifulsoup4, fetch release pages, and write /mnt/data/release_digest.md.")},706	})707	if err != nil {708		panic(err)709	}710	fmt.Println(response.OutputText())711}712```713714```java715import com.openai.client.OpenAIClient;716import com.openai.client.okhttp.OpenAIOkHttpClient;717import com.openai.models.responses.ContainerAuto;718import com.openai.models.responses.ContainerNetworkPolicyAllowlist;719import com.openai.models.responses.FunctionShellTool;720import com.openai.models.responses.ResponseCreateParams;721import com.openai.models.responses.ToolChoiceOptions;722723ResponseCreateParams params =724    ResponseCreateParams.builder()725        .model("gpt-6-astra")726        .input("Fetch release pages and write /mnt/data/release_digest.md.")727        .toolChoice(ToolChoiceOptions.REQUIRED)728        .addTool(729            FunctionShellTool.builder()730                .environment(731                    ContainerAuto.builder()732                        .networkPolicy(733                            ContainerNetworkPolicyAllowlist.builder()734                                .addAllowedDomain("pypi.org")735                                .addAllowedDomain("files.pythonhosted.org")736                                .addAllowedDomain("github.com")737                                .build())738                        .build())739                .build())740        .build();741742client.responses().create(params).output().stream()743    .flatMap(item -> item.message().stream())744    .flatMap(message -> message.content().stream())745    .flatMap(content -> content.outputText().stream())746    .forEach(text -> System.out.println(text.text()));747```748749```ruby750require "openai"751752client = OpenAI::Client.new753response = client.responses.create(754  model: "gpt-6-astra",755  input: "Fetch release pages and write /mnt/data/release_digest.md.",756  tool_choice: :required,757  tools: [758    {759      type: :shell,760      environment: {761        type: :container_auto,762        network_policy: {763          type: :allowlist,764          allowed_domains: ["pypi.org", "files.pythonhosted.org", "github.com"]765        }766      }767    }768  ]769)770771puts(response.output_text)772```773774775Allowlisting domains introduces security risks such as prompt776  injection-driven data exfiltration. Only allowlist domains you trust and that777  attackers cannot use to receive exfiltrated data. Carefully review the [Risks778  and safety](#risks-and-safety) section below before using this tool.779780## Network policy precedence781782When multiple controls are present:783784- Your org allow list defines the full set of `allowed_domains`.785- Request-level `network_policy` further restricts access.786- Requests fail if `allowed_domains` includes domains outside your org allow list.787788## Data retention and container lifecycle789790Hosted containers used by Hosted Shell and Code Interpreter may write temporary application state to the container filesystem (backed by ephemeral block storage) while the container is active. Container data is deleted when the container expires or is explicitly deleted.791792For more details on data controls, see [ZDR and data residency](https://developers.openai.com/api/docs/guides/your-data).793794### Download artifacts795796Hosted shell can produce downloadable files. Use the same container/files APIs as code interpreter to retrieve artifacts written under `/mnt/data`.797798### Additional data controls799800If you want to keep content and files ephemeral within the hosted lifecycle, you can inline files in the request and mount inline skills in the container.801802Use inline files and inline skills803804```bash805INLINE_ZIP=$(base64 -i ./csv_insights.zip)806REPORT_CSV=$(base64 -i ./report.csv)807808CONTAINER_ID=$(809  curl -sL 'https://api.openai.com/v1/containers' \810    -H "Content-Type: application/json" \811    -H "Authorization: Bearer $OPENAI_API_KEY" \812    -d '{813      "name": "inline-skill-container",814      "skills": [815        {816          "type": "inline",817          "name": "csv-insights",818          "description": "Summarize CSV files and produce a markdown report.",819          "source": {820            "type": "base64",821            "media_type": "application/zip",822            "data": "'"$INLINE_ZIP"'"823          }824        }825      ]826    }' | jq -r '.id'827)828829curl -L 'https://api.openai.com/v1/responses' \830  -H "Content-Type: application/json" \831  -H "Authorization: Bearer $OPENAI_API_KEY" \832  -d '{833    "model": "gpt-6-astra",834    "tools": [835      {836        "type": "shell",837        "environment": {838          "type": "container_reference",839          "container_id": "'"$CONTAINER_ID"'"840        }841      }842    ],843    "input": [844      {845        "role": "user",846        "content": [847          {848            "type": "input_file",849            "filename": "report.csv",850            "file_data": "data:text/csv;base64,'"${REPORT_CSV}"'"851          },852          {853            "type": "input_text",854            "text": "Use the csv-insights skill to summarize report.csv."855          }856        ]857      }858    ]859  }'860```861862```javascript863import fs from "fs";864import OpenAI from "openai";865866const client = new OpenAI();867868const inlineZip = fs869  .readFileSync("fixtures/csv_insights.zip")870  .toString("base64");871const reportCsv = fs.readFileSync("fixtures/report.csv").toString("base64");872873const container = await client.containers.create({874  name: "inline-skill-container",875  skills: [876    {877      type: "inline",878      name: "csv-insights",879      description: "Summarize CSV files and produce a markdown report.",880      source: {881        type: "base64",882        media_type: "application/zip",883        data: inlineZip,884      },885    },886  ],887});888889const response = await client.responses.create({890  model: "gpt-6-astra",891  tools: [892    {893      type: "shell",894      environment: {895        type: "container_reference",896        container_id: container.id,897      },898    },899  ],900  input: [901    {902      role: "user",903      content: [904        {905          type: "input_file",906          filename: "report.csv",907          file_data: `data:text/csv;base64,${reportCsv}`,908        },909        {910          type: "input_text",911          text: "Use the csv-insights skill to summarize report.csv.",912        },913      ],914    },915  ],916});917918console.log(response.output_text);919```920921```python922import base64923from openai import OpenAI924925client = OpenAI()926927with open("csv_insights.zip", "rb") as f:928    inline_zip = base64.b64encode(f.read()).decode("utf-8")929930with open("report.csv", "rb") as f:931    base64_string = base64.b64encode(f.read()).decode("utf-8")932933container = client.containers.create(934    name="inline-skill-container",935    skills=[936        {937            "type": "inline",938            "name": "csv-insights",939            "description": "Summarize CSV files and produce a markdown report.",940            "source": {941                "type": "base64",942                "media_type": "application/zip",943                "data": inline_zip,944            },945        }946    ],947)948949response = client.responses.create(950    model="gpt-6-astra",951    tools=[952        {953            "type": "shell",954            "environment": {955                "type": "container_reference",956                "container_id": container.id,957            },958        }959    ],960    input=[961        {962            "role": "user",963            "content": [964                {965                    "type": "input_file",966                    "filename": "report.csv",967                    "file_data": f"data:text/csv;base64,{base64_string}",968                },969                {970                    "type": "input_text",971                    "text": "Use the csv-insights skill to summarize report.csv.",972                },973            ],974        }975    ],976)977978print(response.output_text)979```980981```ruby982require "base64"983require "openai"984985client = OpenAI::Client.new986inline_zip = Base64.strict_encode64(File.binread("csv_insights.zip"))987base64_string = Base64.strict_encode64(File.binread("report.csv"))988container = client.containers.create(989  name: "inline-skill-container",990  skills: [991    {992      type: :inline,993      name: "csv-insights",994      description: "Summarize CSV files and produce a markdown report.",995      source: {996        type: :base64,997        media_type: "application/zip",998        data: inline_zip999      }1000    }1001  ]1002)1003response = client.responses.create(1004  model: "gpt-6-astra",1005  tools: [1006    {1007      type: :shell,1008      environment: {1009        type: :container_reference,1010        container_id: container.id1011      }1012    }1013  ],1014  input: [1015    {1016      role: :user,1017      content: [1018        {1019          type: :input_file,1020          filename: "report.csv",1021          file_data: "data:text/csv;base64,#{base64_string}"1022        },1023        {1024          type: :input_text,1025          text: "Use the csv-insights skill to summarize report.csv."1026        }1027      ]1028    }1029  ]1030)1031puts(response.output_text)1032```103310341035For follow-up requests, pass the same `container_id` with `container_reference`. The mounted skills and existing container files remain available while the container is active.10361037### Proactively delete a container10381039You can explicitly delete the container when the work is done instead of waiting for inactivity expiration.10401041Delete a container10421043```bash1044curl -L -X DELETE 'https://api.openai.com/v1/containers/container_id' \1045  -H "Authorization: Bearer $OPENAI_API_KEY"1046```10471048```javascript1049import OpenAI from "openai";10501051const client = new OpenAI();10521053const deleted = await client.containers.delete("container_id");10541055console.log(deleted);1056```10571058```python1059# Replace the illustrative IDs and URLs below with your own resource values.1060from openai import OpenAI10611062client = OpenAI()1063container_id = "cntr_123"10641065deleted = client.containers.delete(container_id)10661067print(deleted)1068```10691070```go1071package main10721073import (1074	"context"1075	"fmt"10761077	"github.com/openai/openai-go/v3"1078)10791080func main() {1081	client := openai.NewClient()1082	if err := client.Containers.Delete(context.Background(), "container_id"); err != nil {1083		panic(err)1084	}1085	fmt.Println("Container deleted")1086}1087```10881089```java1090import com.openai.client.OpenAIClient;1091import com.openai.client.okhttp.OpenAIOkHttpClient;10921093String containerId = "container_id";10941095client.containers().delete(containerId);10961097System.out.println("Container deleted.");1098```10991100```ruby1101require "openai"11021103client = OpenAI::Client.new1104client.containers.delete("container_id")1105puts("Deleted container_id")1106```110711081109## Domain secrets11101111Use `domain_secrets` when a domain in your `allowed_domains` list requires private authorization headers, such as `Authorization: Bearer <token>`.11121113Each secret entry includes:11141115- Target domain1116- Friendly secret name1117- Secret value11181119At runtime:11201121- The model and runtime see placeholder names (for example, `$API_KEY`) instead of raw credentials.1122- The auth-translation sidecar applies raw secret values only for approved destinations.1123- Raw secret values don't persist on API servers and don't appear in model-visible context.11241125This lets the assistant call protected services while reducing leakage risk.11261127Shell tool with domain_secrets11281129```bash1130curl -L 'https://api.openai.com/v1/responses' \1131  -H "Authorization: Bearer $OPENAI_API_KEY" \1132  -H "Content-Type: application/json" \1133  -d '{1134    "model": "gpt-6-astra",1135    "input": [1136      {1137        "role": "user",1138        "content": "Use curl to call https://httpbin.org/headers with header Authorization: Bearer $API_KEY. Tell me what you see in the final text response."1139      }1140    ],1141    "tool_choice": "required",1142    "tools": [1143      {1144        "type": "shell",1145        "environment": {1146          "type": "container_auto",1147          "network_policy": {1148            "type": "allowlist",1149            "allowed_domains": ["httpbin.org"],1150            "domain_secrets": [1151              {1152                "domain": "httpbin.org",1153                "name": "API_KEY",1154                "value": "debug-secret-123"1155              }1156            ]1157          }1158        }1159      }1160    ]1161  }'1162```11631164```javascript1165import OpenAI from "openai";11661167const client = new OpenAI();11681169const response = await client.responses.create({1170  model: "gpt-6-astra",1171  input: [1172    {1173      role: "user",1174      content:1175        "Use curl to call https://httpbin.org/headers with header Authorization: Bearer $API_KEY. Tell me what you see in the final text response.",1176    },1177  ],1178  tool_choice: "required",1179  tools: [1180    {1181      type: "shell",1182      environment: {1183        type: "container_auto",1184        network_policy: {1185          type: "allowlist",1186          allowed_domains: ["httpbin.org"],1187          domain_secrets: [1188            {1189              domain: "httpbin.org",1190              name: "API_KEY",1191              value: "debug-secret-123",1192            },1193          ],1194        },1195      },1196    },1197  ],1198});11991200console.log(response.output_text);1201```12021203```python1204from openai import OpenAI12051206client = OpenAI()12071208response = client.responses.create(1209    model="gpt-6-astra",1210    input=[1211        {1212            "role": "user",1213            "content": "Use curl to call https://httpbin.org/headers with header Authorization: Bearer $API_KEY. Tell me what you see in the final text response.",1214        }1215    ],1216    tool_choice="required",1217    tools=[1218        {1219            "type": "shell",1220            "environment": {1221                "type": "container_auto",1222                "network_policy": {1223                    "type": "allowlist",1224                    "allowed_domains": ["httpbin.org"],1225                    "domain_secrets": [1226                        {1227                            "domain": "httpbin.org",1228                            "name": "API_KEY",1229                            "value": "debug-secret-123",1230                        }1231                    ],1232                },1233            },1234        }1235    ],1236)12371238print(response.output_text)1239```12401241```go1242package main12431244import (1245	"context"1246	"fmt"12471248	"github.com/openai/openai-go/v3"1249	"github.com/openai/openai-go/v3/responses"1250)12511252func main() {1253	client := openai.NewClient()1254	tool := responses.ToolUnionParam{OfShell: &responses.FunctionShellToolParam{1255		Environment: responses.FunctionShellToolEnvironmentUnionParam{OfContainerAuto: &responses.ContainerAutoParam{1256			NetworkPolicy: responses.ContainerAutoNetworkPolicyUnionParam{OfAllowlist: &responses.ContainerNetworkPolicyAllowlistParam{1257				AllowedDomains: []string{"httpbin.org"},1258				DomainSecrets: []responses.ContainerNetworkPolicyDomainSecretParam{{1259					Domain: "httpbin.org",1260					Name:   "API_KEY",1261					Value:  "debug-secret-123",1262				}},1263			}},1264		}},1265	}}1266	response, err := client.Responses.New(context.Background(), responses.ResponseNewParams{1267		Model:      "gpt-6-astra",1268		ToolChoice: responses.ResponseNewParamsToolChoiceUnion{OfToolChoiceMode: openai.Opt(responses.ToolChoiceOptionsRequired)},1269		Tools:      []responses.ToolUnionParam{tool},1270		Input:      responses.ResponseNewParamsInputUnion{OfString: openai.String("Use curl to call https://httpbin.org/headers with header Authorization: Bearer $API_KEY. Tell me what you see in the final text response.")},1271	})1272	if err != nil {1273		panic(err)1274	}1275	fmt.Println(response.OutputText())1276}1277```12781279```java1280import com.openai.client.OpenAIClient;1281import com.openai.client.okhttp.OpenAIOkHttpClient;1282import com.openai.models.responses.ContainerAuto;1283import com.openai.models.responses.ContainerNetworkPolicyAllowlist;1284import com.openai.models.responses.ContainerNetworkPolicyDomainSecret;1285import com.openai.models.responses.FunctionShellTool;1286import com.openai.models.responses.ResponseCreateParams;1287import com.openai.models.responses.ToolChoiceOptions;12881289ResponseCreateParams params =1290    ResponseCreateParams.builder()1291        .model("gpt-6-astra")1292        .input(1293            "Use curl to call https://httpbin.org/status/204 with an "1294                + "Authorization: Bearer $API_KEY header. Print only the HTTP status code; "1295                + "never print request headers or secret values.")1296        .toolChoice(ToolChoiceOptions.REQUIRED)1297        .addTool(1298            FunctionShellTool.builder()1299                .environment(1300                    ContainerAuto.builder()1301                        .networkPolicy(1302                            ContainerNetworkPolicyAllowlist.builder()1303                                .addAllowedDomain("httpbin.org")1304                                .addDomainSecret(1305                                    ContainerNetworkPolicyDomainSecret.builder()1306                                        .domain("httpbin.org")1307                                        .name("API_KEY")1308                                        .value(System.getenv("OPENAI_EXAMPLE_DOMAIN_SECRET"))1309                                        .build())1310                                .build())1311                        .build())1312                .build())1313        .build();13141315client.responses().create(params).output().stream()1316    .flatMap(item -> item.message().stream())1317    .flatMap(message -> message.content().stream())1318    .flatMap(content -> content.outputText().stream())1319    .forEach(text -> System.out.println(text.text()));1320```13211322```ruby1323require "openai"13241325client = OpenAI::Client.new1326response = client.responses.create(1327  model: "gpt-6-astra",1328  input: "Use curl to call https://httpbin.org/headers with an " \1329    '"Authorization: Bearer $API_KEY" header.',1330  tool_choice: :required,1331  tools: [1332    {1333      type: :shell,1334      environment: {1335        type: :container_auto,1336        network_policy: {1337          type: :allowlist,1338          allowed_domains: ["httpbin.org"],1339          domain_secrets: [1340            {1341              domain: "httpbin.org",1342              name: "API_KEY",1343              value: "debug-secret-123"1344            }1345          ]1346        }1347      }1348    }1349  ]1350)13511352puts(response.output_text)1353```135413551356## Multi-turn workflows13571358To continue work in the same hosted environment, reuse the container and pass `previous_response_id`.13591360Continue a shell workflow13611362```bash1363curl -L 'https://api.openai.com/v1/responses' \1364  -H "Content-Type: application/json" \1365  -H "Authorization: Bearer $OPENAI_API_KEY" \1366  -d '{1367    "model": "gpt-6-astra",1368    "previous_response_id": "resp_2a8e5c9174d63b0f18a4c572de9f64a1b3c76d508e12f9ab47",1369    "tools": [1370      {1371        "type": "shell",1372        "environment": {1373          "type": "container_reference",1374          "container_id": "cntr_f19c2b51e4a06793d82d54a7be0fc9154d3361ab28ce7f6041"1375        }1376      }1377    ],1378    "input": "Read /mnt/data/top5.csv and report the top candidate."1379  }'1380```13811382```javascript1383import OpenAI from "openai";13841385const client = new OpenAI();13861387const response = await client.responses.create({1388  model: "gpt-6-astra",1389  previous_response_id:1390    "resp_2a8e5c9174d63b0f18a4c572de9f64a1b3c76d508e12f9ab47",1391  tools: [1392    {1393      type: "shell",1394      environment: {1395        type: "container_reference",1396        container_id: "cntr_f19c2b51e4a06793d82d54a7be0fc9154d3361ab28ce7f6041",1397      },1398    },1399  ],1400  input: "Read /mnt/data/top5.csv and report the top candidate.",1401});14021403console.log(response.output_text);1404```14051406```python1407from openai import OpenAI14081409client = OpenAI()14101411response = client.responses.create(1412    model="gpt-6-astra",1413    previous_response_id="resp_2a8e5c9174d63b0f18a4c572de9f64a1b3c76d508e12f9ab47",1414    tools=[1415        {1416            "type": "shell",1417            "environment": {1418                "type": "container_reference",1419                "container_id": "cntr_f19c2b51e4a06793d82d54a7be0fc9154d3361ab28ce7f6041",1420            },1421        }1422    ],1423    input="Read /mnt/data/top5.csv and report the top candidate.",1424)14251426print(response.output_text)1427```14281429```go1430package main14311432import (1433	"context"1434	"fmt"14351436	"github.com/openai/openai-go/v3"1437	"github.com/openai/openai-go/v3/responses"1438)14391440func main() {1441	client := openai.NewClient()1442	tool := responses.ToolUnionParam{OfShell: &responses.FunctionShellToolParam{1443		Environment: responses.FunctionShellToolEnvironmentUnionParam{OfContainerReference: &responses.ContainerReferenceParam{ContainerID: "cntr_f19c2b51e4a06793d82d54a7be0fc9154d3361ab28ce7f6041"}},1444	}}1445	response, err := client.Responses.New(context.Background(), responses.ResponseNewParams{1446		Model:              "gpt-6-astra",1447		PreviousResponseID: openai.String("resp_2a8e5c9174d63b0f18a4c572de9f64a1b3c76d508e12f9ab47"),1448		Tools:              []responses.ToolUnionParam{tool},1449		Input:              responses.ResponseNewParamsInputUnion{OfString: openai.String("Read /mnt/data/top5.csv and report the top candidate.")},1450	})1451	if err != nil {1452		panic(err)1453	}1454	fmt.Println(response.OutputText())1455}1456```14571458```java1459import com.openai.client.OpenAIClient;1460import com.openai.client.okhttp.OpenAIOkHttpClient;1461import com.openai.models.responses.FunctionShellTool;1462import com.openai.models.responses.ResponseCreateParams;14631464String responseId = "resp_2a8e5c9174d63b0f18a4c572de9f64a1b3c76d508e12f9ab47";14651466String containerId = "cntr_f19c2b51e4a06793d82d54a7be0fc9154d3361ab28ce7f6041";14671468ResponseCreateParams params =1469    ResponseCreateParams.builder()1470        .model("gpt-6-astra")1471        .input("Read /mnt/data/top5.csv and report the top candidate.")1472        .previousResponseId(responseId)1473        .addTool(FunctionShellTool.builder().containerReferenceEnvironment(containerId).build())1474        .build();14751476client.responses().create(params).output().stream()1477    .flatMap(item -> item.message().stream())1478    .flatMap(message -> message.content().stream())1479    .flatMap(content -> content.outputText().stream())1480    .forEach(text -> System.out.println(text.text()));1481```14821483```ruby1484require "openai"14851486client = OpenAI::Client.new1487response = client.responses.create(1488  model: "gpt-6-astra",1489  input: "Read /mnt/data/top5.csv and report the top candidate.",1490  previous_response_id: "resp_2a8e5c9174d63b0f18a4c572de9f64a1b3c76d508e12f9ab47",1491  tools: [1492    {1493      type: :shell,1494      environment: {1495        type: :container_reference,1496        container_id: "cntr_f19c2b51e4a06793d82d54a7be0fc9154d3361ab28ce7f6041"1497      }1498    }1499  ]1500)15011502puts(response.output_text)1503```150415051506## Shell output in Responses15071508Hosted shell and local shell use the same output item types. Shell runs are represented by paired output items:15091510- `shell_call`: commands requested by the model.1511- `shell_call_output`: command output and exit outcomes.15121513Example shell_call item15141515```json1516{1517  "type": "shell_call",1518  "call_id": "call_9d14ac6f2b73485e91c0f4da6e1b27c8",1519  "action": {1520    "commands": ["ls -l"],1521    "timeout_ms": 120000,1522    "max_output_length": 40961523  },1524  "status": "in_progress"1525}1526```152715281529## Local shell mode15301531You can also run shell commands in your own local runtime by executing `shell_call` actions and sending `shell_call_output` back to the model.15321533Use this mode when you need full control over execution environment, filesystem access, or existing internal tooling.15341535Local shell request15361537```bash1538curl -L 'https://api.openai.com/v1/responses' \1539  -H "Content-Type: application/json" \1540  -H "Authorization: Bearer $OPENAI_API_KEY" \1541  -d '{1542    "model": "gpt-6-astra",1543    "instructions": "The local bash shell environment is on Mac.",1544    "input": "find me the largest pdf file in ~/Documents",1545    "tools": [{ "type": "shell", "environment": { "type": "local" } }]1546  }'1547```15481549```javascript1550import OpenAI from "openai";15511552const client = new OpenAI();15531554const response = await client.responses.create({1555  model: "gpt-6-astra",1556  instructions: "The local bash shell environment is on Mac.",1557  input: "find me the largest pdf file in ~/Documents",1558  tools: [{ type: "shell", environment: { type: "local" } }],1559});15601561console.log(response);1562```15631564```python1565from openai import OpenAI15661567client = OpenAI()15681569response = client.responses.create(1570    model="gpt-6-astra",1571    instructions="The local bash shell environment is on Mac.",1572    input="find me the largest pdf file in ~/Documents",1573    tools=[{"type": "shell", "environment": {"type": "local"}}],1574)15751576print(response)1577```15781579```go1580package main15811582import (1583	"context"1584	"fmt"15851586	"github.com/openai/openai-go/v3"1587	"github.com/openai/openai-go/v3/responses"1588)15891590func main() {1591	client := openai.NewClient()1592	tool := responses.ToolUnionParam{OfShell: &responses.FunctionShellToolParam{1593		Environment: responses.FunctionShellToolEnvironmentUnionParam{OfLocal: &responses.LocalEnvironmentParam{}},1594	}}1595	response, err := client.Responses.New(context.Background(), responses.ResponseNewParams{1596		Model:        "gpt-6-astra",1597		Instructions: openai.String("The local bash shell environment is on Mac."),1598		Input:        responses.ResponseNewParamsInputUnion{OfString: openai.String("find me the largest pdf file in ~/Documents")},1599		Tools:        []responses.ToolUnionParam{tool},1600	})1601	if err != nil {1602		panic(err)1603	}1604	fmt.Println(response.Output)1605}1606```16071608```java1609import com.openai.client.OpenAIClient;1610import com.openai.client.okhttp.OpenAIOkHttpClient;1611import com.openai.core.JsonValue;1612import com.openai.models.responses.ResponseCreateParams;1613import java.util.List;1614import java.util.Map;16151616ResponseCreateParams params =1617    ResponseCreateParams.builder()1618        .model("gpt-6-astra")1619        .input("Find the largest PDF in ~/Documents.")1620        .instructions("The local shell environment is macOS.")1621        .putAdditionalBodyProperty(1622            "tools",1623            JsonValue.from(1624                List.of(Map.of("type", "shell", "environment", Map.of("type", "local")))))1625        .build();16261627client.responses().create(params).output().stream()1628    .flatMap(item -> item.shellCall().stream())1629    .flatMap(call -> call.action().commands().stream())1630    .forEach(System.out::println);1631```16321633```ruby1634require "openai"16351636client = OpenAI::Client.new1637response = client.responses.create(1638  model: "gpt-6-astra",1639  instructions: "The local shell environment is macOS.",1640  input: "Find the largest PDF in ~/Documents.",1641  tools: [1642    {1643      type: :shell,1644      environment: { type: :local }1645    }1646  ]1647)16481649puts(response.output)1650```165116521653When you receive `shell_call` output items:16541655- Execute requested commands in your runtime.1656- Capture `stdout`, `stderr`, and outcome.1657- Return results as `shell_call_output` in the next request.16581659Local shell executor example16601661```javascript1662import { exec as execCallback } from "node:child_process";1663import { promisify } from "node:util";16641665const exec = promisify(execCallback);16661667class ShellExecutor {1668  constructor(defaultTimeoutMs = 60_000) {1669    this.defaultTimeoutMs = defaultTimeoutMs;1670  }16711672  async run(cmd, timeoutMs) {1673    const timeout = timeoutMs ?? this.defaultTimeoutMs;16741675    try {1676      const { stdout, stderr } = await exec(cmd, { timeout });1677      return { stdout, stderr, exitCode: 0, timedOut: false };1678    } catch (error) {1679      const timedOut = Boolean(error?.killed) && error?.signal === "SIGTERM";1680      const exitCode = timedOut ? null : (error?.code ?? null);1681      return {1682        stdout: error?.stdout ?? "",1683        stderr: error?.stderr ?? String(error),1684        exitCode,1685        timedOut,1686      };1687    }1688  }1689}1690```16911692```python1693@dataclass1694class CmdResult:1695    stdout: str1696    stderr: str1697    exit_code: int | None1698    timed_out: bool169917001701class ShellExecutor:1702    def __init__(self, default_timeout: float = 60):1703        self.default_timeout = default_timeout17041705    def run(self, cmd: str, timeout: float | None = None) -> CmdResult:1706        t = timeout or self.default_timeout1707        p = subprocess.Popen(1708            cmd,1709            shell=True,1710            stdout=subprocess.PIPE,1711            stderr=subprocess.PIPE,1712            text=True,1713        )1714        try:1715            out, err = p.communicate(timeout=t)1716            return CmdResult(out, err, p.returncode, False)1717        except subprocess.TimeoutExpired:1718            p.kill()1719            out, err = p.communicate()1720            return CmdResult(out, err, p.returncode, True)1721```17221723```go1724package main17251726import (1727	"bytes"1728	"context"1729	"fmt"1730	"os/exec"1731	"time"1732)17331734type shellResult struct {1735	Stdout   string1736	Stderr   string1737	ExitCode int1738	TimedOut bool1739}17401741type shellExecutor struct {1742	DefaultTimeout time.Duration1743}17441745func (e shellExecutor) run(command string, timeout time.Duration) shellResult {1746	if timeout == 0 {1747		timeout = e.DefaultTimeout1748	}1749	ctx, cancel := context.WithTimeout(context.Background(), timeout)1750	defer cancel()1751	cmd := exec.CommandContext(ctx, "sh", "-c", command)1752	var stdout, stderr bytes.Buffer1753	cmd.Stdout = &stdout1754	cmd.Stderr = &stderr1755	err := cmd.Run()1756	result := shellResult{Stdout: stdout.String(), Stderr: stderr.String()}1757	if ctx.Err() == context.DeadlineExceeded {1758		result.TimedOut = true1759		result.ExitCode = -11760		return result1761	}1762	if err != nil {1763		if exitError, ok := err.(*exec.ExitError); ok {1764			result.ExitCode = exitError.ExitCode()1765			return result1766		}1767		if result.Stderr == "" {1768			result.Stderr = err.Error()1769		}1770		result.ExitCode = -11771	}1772	return result1773}17741775func main() {1776	executor := shellExecutor{DefaultTimeout: time.Minute}1777	fmt.Println(executor.run("printf shell-executor-ready", 0))1778}1779```17801781```ruby1782require "open3"17831784class ShellExecutor1785  Result = Data.define(:stdout, :stderr, :exit_code, :timed_out)17861787  def initialize(default_timeout: 60)1788    @default_timeout = default_timeout1789  end17901791  def run(command, timeout: @default_timeout)1792    Open3.popen3("sh", "-c", command, pgroup: true) do |stdin, stdout, stderr, wait_thread|1793      stdin.close1794      stdout_reader = Thread.new { stdout.read }1795      stderr_reader = Thread.new { stderr.read }1796      finished = wait_thread.join(timeout)1797      terminate_process_group(wait_thread) unless finished17981799      Result.new(1800        stdout: stdout_reader.value,1801        stderr: stderr_reader.value,1802        exit_code: wait_thread.value.exitstatus || -1,1803        timed_out: finished.nil?1804      )1805    end1806  end18071808  private18091810  def terminate_process_group(wait_thread)1811    Process.kill("TERM", -wait_thread.pid)1812    wait_thread.join(1)1813    Process.kill("KILL", -wait_thread.pid)1814  rescue Errno::ESRCH1815    nil1816  ensure1817    wait_thread.join1818  end1819end18201821puts(ShellExecutor.new.run("printf shell-executor-ready"))1822```182318241825Example shell_call_output payload18261827```json1828{1829  "type": "shell_call_output",1830  "call_id": "call_3ef1b8c79a4d6520f9e3ab7d41c68f25",1831  "max_output_length": 4096,1832  "output": [1833    {1834      "stdout": "...",1835      "stderr": "...",1836      "outcome": {1837        "type": "exit",1838        "exit_code": 01839      }1840    },1841    {1842      "stdout": "...",1843      "stderr": "...",1844      "outcome": {1845        "type": "timeout"1846      }1847    }1848  ]1849}1850```185118521853For legacy migration details, see the older [Local shell guide](https://developers.openai.com/api/docs/guides/tools-local-shell).18541855## Use local shell with Agents SDK18561857If you are using the [Agents SDK](https://developers.openai.com/api/docs/guides/tools#usage-in-the-agents-sdk), you can pass your own shell executor implementation to the shell tool helper.18581859Use local shell with Agents SDK18601861```javascript1862import { Agent, run, withTrace, shellTool } from "@openai/agents";18631864class LocalShell {1865  async run(action) {1866    return {1867      output: [1868        {1869          stdout: "Shell is not available. Needs to be implemented first.",1870          stderr: "",1871          outcome: {1872            type: "exit",1873            exitCode: 1,1874          },1875        },1876      ],1877      maxOutputLength: action.maxOutputLength,1878    };1879  }1880}18811882const shell = new LocalShell();18831884const agent = new Agent({1885  name: "Shell Assistant",1886  model: "gpt-6-astra",1887  instructions:1888    "You can execute shell commands to inspect the repository. Keep responses concise and include command output when helpful.",1889  tools: [1890    shellTool({1891      shell,1892      needsApproval: true,1893      onApproval: async (_ctx, _approvalItem) => {1894        return { approve: true };1895      },1896    }),1897  ],1898});18991900await withTrace("shell-tool-example", async () => {1901  const result = await run(agent, "Show the Node.js version.");1902  console.log(`\nFinal response:\n${result.finalOutput}`);1903});1904```19051906```python1907from agents import (1908    Agent,1909    Runner,1910    ShellCallOutcome,1911    ShellCommandOutput,1912    ShellCommandRequest,1913    ShellResult,1914    ShellTool,1915)191619171918class LocalShell:1919    async def __call__(self, request: ShellCommandRequest) -> ShellResult:1920        action = request.data.action1921        return ShellResult(1922            output=[1923                ShellCommandOutput(1924                    command="(not executed)",1925                    stdout="Shell is not available. Needs to be implemented first.",1926                    stderr="",1927                    outcome=ShellCallOutcome(type="exit", exit_code=1),1928                )1929            ],1930            max_output_length=action.max_output_length,1931        )193219331934shell_tool = ShellTool(1935    executor=LocalShell(),1936    needs_approval=True,1937    on_approval=lambda _ctx, _approval_item: {"approve": True},1938)19391940agent = Agent(1941    name="Shell Assistant",1942    model="gpt-6-astra",1943    instructions="You can execute shell commands to inspect the repository. Keep responses concise and include command output when helpful.",1944    tools=[shell_tool],1945)194619471948async def main():1949    result = await Runner.run(agent, input="Show the Node.js version.")1950    print(f"\nFinal response:\n{result.final_output}")195119521953if __name__ == "__main__":1954    import asyncio19551956    asyncio.run(main())1957```195819591960You can find working examples in the SDK repositories.19611962[Shell tool example - TypeScript1963196419651966      TypeScript example for the shell tool in the Agents SDK.](https://github.com/openai/openai-agents-js/blob/main/examples/tools/shell.ts)19671968[Shell tool example - Python1969197019711972      Python example for the shell tool in the Agents SDK.](https://github.com/openai/openai-agents-python/blob/main/examples/tools/shell.py)19731974## Handling common errors19751976- If a command exceeds your execution timeout, return a timeout outcome and include partial captured output.1977- If `max_output_length` is present on `shell_call`, include it in `shell_call_output`.1978- Don't rely on interactive commands; shell tool execution should be non-interactive.1979- Preserve non-zero exit outputs so the model can reason about recovery steps.19801981## Risks and safety19821983Enabling network access in the Containers API is a powerful capability, and it introduces meaningful security and data-governance risk. By default, network access isn't enabled. When enabled, outbound access should remain tightly scoped to trusted domains needed for the task.19841985Network-enabled containers can interact with third-party services and package registries. That creates risks including data leakage, prompt-injection-driven tool misuse, and accidental access beyond intended boundaries. These risks increase when policies are broad, static, or inconsistently enforced.19861987#### Understand prompt injection risks from network-retrieved content19881989Any external content fetched over the network may contain hidden instructions intended to manipulate model behavior. Treat untrusted network content as potentially adversarial, and require additional caution for actions that can modify data or systems.19901991#### Connect only to trusted destinations19921993Allow only domains you trust and actively maintain. Be cautious with intermediaries and aggregators that proxy to other services, and review their data handling and retention practices before you add them to your allowed domains list.19941995#### Build in reviews before and after requests are executed19961997Review the shell tool command and execution output, which are provided in the Responses API response. Capture requested hosts and actual outbound destinations for each session. Periodically review logs to verify access patterns match expectations, detect drift, and identify suspicious behavior.19981999#### Validate data residency and retention requirements20002001[OpenAI data controls](https://developers.openai.com/api/docs/guides/your-data) apply within OpenAI boundaries. However, data transmitted to third-party services over network connections is subject to their data retention policies. Ensure external endpoints meet your residency, retention, and compliance requirements.
Files main
Menu

Theme