シェルツールを使うと、モデルは完全なターミナル環境内で作業できます。Responses API を通じて、ローカル環境とホスト型環境の両方でシェルを実行できます。
シェルツールを使うと、モデルは次のいずれかの環境でコマンドを実行できます。
シェルは Responses API で利用できます。Chat Completions API では利用できません。
任意のシェルコマンドの実行には危険が伴う場合があります。必ずサンドボックス内で実行し、可能な限り許可リストや拒否リストを適用して、監査用にツールの操作ログを記録してください。
ホスト型シェルは、計算からマルチメディアの操作まで、より高度で決定論的な処理を必要とするタスクに適した、組み込みの使いやすい選択肢です。
リクエスト用のコンテナのプロビジョニングと管理を OpenAI に任せる場合は、container_auto を使用します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 curl -L 'https://api.openai.com/v1/responses' \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $OPENAI_API_KEY " \
-d '{
"model": "gpt-6-astra",
"tools": [
{ "type": "shell", "environment": { "type": "container_auto" } }
],
"input": [
{
"type": "message",
"role": "user",
"content": [
{ "type": "input_text", "text": "Execute: ls -lah /mnt/data && python --version && node --version" }
]
}
],
"tool_choice": "auto"
}' 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 import OpenAI from "openai";
const client = new OpenAI();
const response = await client.responses.create({
model: "gpt-6-astra",
tools: [{ type: "shell", environment: { type: "container_auto" } }],
input: [
{
type: "message",
role: "user",
content: [
{
type: "input_text",
text: "Execute: ls -lah /mnt/data && python --version && node --version",
},
],
},
],
tool_choice: "auto",
});
console.log(response.output_text); 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 from openai import OpenAI
client = OpenAI()
response = client.responses.create(
model="gpt-6-astra",
tools=[{"type": "shell", "environment": {"type": "container_auto"}}],
input=[
{
"type": "message",
"role": "user",
"content": [
{
"type": "input_text",
"text": "Execute: ls -lah /mnt/data && python --version && node --version",
}
],
}
],
tool_choice="auto",
)
print(response.output_text) 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 package main
import (
"context"
"fmt"
"github.com/openai/openai-go/v3"
"github.com/openai/openai-go/v3/responses"
)
func main() {
client := openai.NewClient()
tool := responses.ToolUnionParam{OfShell: &responses.FunctionShellToolParam{
Environment: responses.FunctionShellToolEnvironmentUnionParam{OfContainerAuto: &responses.ContainerAutoParam{}},
}}
response, err := client.Responses.New(context.Background(), responses.ResponseNewParams{
Model: "gpt-6-astra",
Tools: []responses.ToolUnionParam{tool},
Input: responses.ResponseNewParamsInputUnion{OfString: openai.String("Execute: ls -lah /mnt/data && python --version && node --version")},
})
if err != nil {
panic(err)
}
fmt.Println(response.OutputText())
} 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.models.responses.ContainerAuto;
import com.openai.models.responses.FunctionShellTool;
import com.openai.models.responses.ResponseCreateParams;
ResponseCreateParams params =
ResponseCreateParams.builder()
.model("gpt-6-astra")
.input("Run ls -lah /mnt/data, then show the Python and Node.js versions.")
.addTool(
FunctionShellTool.builder().environment(ContainerAuto.builder().build()).build())
.build();
client.responses().create(params).output().stream()
.flatMap(item -> item.message().stream())
.flatMap(message -> message.content().stream())
.flatMap(content -> content.outputText().stream())
.forEach(text -> System.out.println(text.text())); 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 require "openai"
client = OpenAI::Client.new
response = client.responses.create(
model: "gpt-6-astra",
input: "Run ls -lah /mnt/data, then show the Python and Node.js versions.",
tools: [
{
type: :shell,
environment: { type: :container_auto }
}
]
)
puts(response.output_text)
ランタイムは現在 Debian 12 をベースとしており、今後変更される可能性があります。
デフォルトの作業ディレクトリは /mnt/data です。
/mnt/data は常に存在し、ユーザーがダウンロードできる成果物の保存先としてサポートされているパスです。
ホスト型シェルは対話型の TTY セッションをサポートしていません。
ホスト型シェルのコマンドは sudo では実行されません。
ワークフローで必要な場合は、コンテナ内でサービスを実行できます。
現在、以下の言語がプリインストールされています。
Python 3.11
Node.js 22.16
Java 17.0
PHP 8.2
Ruby 3.1
Go 1.23
反復的なワークフローで長時間実行する環境が必要な場合は、コンテナを作成し、以降の Responses API 呼び出しでそのコンテナを参照します。
1
2
3
4
5
6
7
8 curl -L 'https://api.openai.com/v1/containers' \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $OPENAI_API_KEY " \
-d '{
"name": "analysis-container",
"memory_limit": "1g",
"expires_after": { "anchor": "last_active_at", "minutes": 20 }
}' 1
2
3
4
5
6
7
8
9
10
11 import OpenAI from "openai";
const client = new OpenAI();
const container = await client.containers.create({
name: "analysis-container",
memory_limit: "1g",
expires_after: { anchor: "last_active_at", minutes: 20 },
});
console.log(container.id); 1
2
3
4
5
6
7
8
9
10
11 from openai import OpenAI
client = OpenAI()
container = client.containers.create(
name="analysis-container",
memory_limit="1g",
expires_after={"anchor": "last_active_at", "minutes": 20},
)
print(container.id) 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 package main
import (
"context"
"fmt"
"github.com/openai/openai-go/v3"
)
func main() {
client := openai.NewClient()
container, err := client.Containers.New(context.Background(), openai.ContainerNewParams{
Name: "analysis-container",
MemoryLimit: openai.ContainerNewParamsMemoryLimit1g,
ExpiresAfter: openai.ContainerNewParamsExpiresAfter{
Anchor: "last_active_at",
Minutes: 20,
},
})
if err != nil {
panic(err)
}
fmt.Println(container.ID)
} 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.models.containers.ContainerCreateParams;
var container =
client
.containers()
.create(
ContainerCreateParams.builder()
.name("analysis")
.expiresAfter(
ContainerCreateParams.ExpiresAfter.builder()
.anchor(ContainerCreateParams.ExpiresAfter.Anchor.LAST_ACTIVE_AT)
.minutes(20)
.build())
.build());
System.out.println(container.id()); 1
2
3
4
5
6
7
8
9
10 require "openai"
client = OpenAI::Client.new
container = client.containers.create(
name: "analysis", expires_after: {
anchor: :last_active_at,
minutes: 20
}
)
puts(container.id)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 curl -L 'https://api.openai.com/v1/responses' \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $OPENAI_API_KEY " \
-d '{
"model": "gpt-6-astra",
"tools": [
{
"type": "shell",
"environment": {
"type": "container_reference",
"container_id": "cntr_08f3d96c87a585390069118b594f7481a088b16cda7d9415fe"
}
}
],
"input": "List files in the container and show disk usage."
}' 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 import OpenAI from "openai";
const client = new OpenAI();
const response = await client.responses.create({
model: "gpt-6-astra",
tools: [
{
type: "shell",
environment: {
type: "container_reference",
container_id: "cntr_08f3d96c87a585390069118b594f7481a088b16cda7d9415fe",
},
},
],
input: "List files in the container and show disk usage.",
});
console.log(response.output_text); 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 response = client.responses.create(
model="gpt-6-astra",
tools=[
{
"type": "shell",
"environment": {
"type": "container_reference",
"container_id": container.id,
},
}
],
input="List files in the container and show disk usage.",
)
print(response.output_text) 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 package main
import (
"context"
"fmt"
"github.com/openai/openai-go/v3"
"github.com/openai/openai-go/v3/responses"
)
func main() {
client := openai.NewClient()
tool := responses.ToolUnionParam{OfShell: &responses.FunctionShellToolParam{
Environment: responses.FunctionShellToolEnvironmentUnionParam{OfContainerReference: &responses.ContainerReferenceParam{ContainerID: "cntr_08f3d96c87a585390069118b594f7481a088b16cda7d9415fe"}},
}}
response, err := client.Responses.New(context.Background(), responses.ResponseNewParams{
Model: "gpt-6-astra",
Tools: []responses.ToolUnionParam{tool},
Input: responses.ResponseNewParamsInputUnion{OfString: openai.String("List files in the container and show disk usage.")},
})
if err != nil {
panic(err)
}
fmt.Println(response.OutputText())
} 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.models.responses.FunctionShellTool;
import com.openai.models.responses.ResponseCreateParams;
String containerId = "cntr_08f3d96c87a585390069118b594f7481a088b16cda7d9415fe";
ResponseCreateParams params =
ResponseCreateParams.builder()
.model("gpt-6-astra")
.input("List files in the container and show disk usage.")
.addTool(FunctionShellTool.builder().containerReferenceEnvironment(containerId).build())
.build();
client.responses().create(params).output().stream()
.flatMap(item -> item.message().stream())
.flatMap(message -> message.content().stream())
.flatMap(content -> content.outputText().stream())
.forEach(text -> System.out.println(text.text())); 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 require "openai"
client = OpenAI::Client.new
response = client.responses.create(
model: "gpt-6-astra",
input: "List files in the container and show disk usage.",
tools: [
{
type: :shell,
environment: {
type: :container_reference,
container_id: "cntr_08f3d96c87a585390069118b594f7481a088b16cda7d9415fe"
}
}
]
)
puts(response.output_text)
スキルは、ホスト型シェル環境にマウントできる、再利用可能でバージョン管理されたバンドルです。マウントによって利用可能なスキルが定義され、シェルの実行時にモデルがそれらを呼び出すかどうかを判断します。
アップロードとバージョン管理の詳細は、スキルガイド を参照してください。
1
2
3
4
5
6
7
8
9
10 curl -L 'https://api.openai.com/v1/containers' \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $OPENAI_API_KEY " \
-d '{
"name": "skill-container",
"skills": [
{ "type": "skill_reference", "skill_id": "skill_4db6f1a2c9e73508b41f9da06e2c7b5f" },
{ "type": "skill_reference", "skill_id": "openai-spreadsheets", "version": "latest" }
]
}' 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 import OpenAI from "openai";
const client = new OpenAI();
const container = await client.containers.create({
name: "skill-container",
skills: [
{
type: "skill_reference",
skill_id: "skill_4db6f1a2c9e73508b41f9da06e2c7b5f",
},
{
type: "skill_reference",
skill_id: "openai-spreadsheets",
version: "latest",
},
],
});
console.log(container.id); 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 # Replace the illustrative IDs and URLs below with your own resource values.
from openai import OpenAI
client = OpenAI()
skill_id = "skill_123"
container = client.containers.create(
name="skill-container",
skills=[
{
"type": "skill_reference",
"skill_id": skill_id,
},
{
"type": "skill_reference",
"skill_id": "openai-spreadsheets",
"version": "latest",
},
],
)
print(container.id) 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 package main
import (
"context"
"fmt"
"github.com/openai/openai-go/v3"
"github.com/openai/openai-go/v3/responses"
)
func main() {
client := openai.NewClient()
container, err := client.Containers.New(context.Background(), openai.ContainerNewParams{
Name: "skill-container",
Skills: []openai.ContainerNewParamsSkillUnion{
{OfSkillReference: &responses.SkillReferenceParam{SkillID: "skill_4db6f1a2c9e73508b41f9da06e2c7b5f"}},
{OfSkillReference: &responses.SkillReferenceParam{SkillID: "openai-spreadsheets", Version: openai.String("latest")}},
},
})
if err != nil {
panic(err)
}
fmt.Println(container.ID)
} 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.models.containers.ContainerCreateParams;
import com.openai.models.responses.SkillReference;
String skillId = "skill_4db6f1a2c9e73508b41f9da06e2c7b5f";
var container =
client
.containers()
.create(
ContainerCreateParams.builder()
.name("skill-container")
.addSkill(SkillReference.builder().skillId(skillId).build())
.addSkill(
SkillReference.builder()
.skillId("openai-spreadsheets")
.version("latest")
.build())
.build());
System.out.println(container.id()); 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 require "openai"
client = OpenAI::Client.new
container = client.containers.create(
name: "skill-container",
skills: [
{
type: :skill_reference,
skill_id: "skill_4db6f1a2c9e73508b41f9da06e2c7b5f"
},
{
type: :skill_reference,
skill_id: "openai-spreadsheets",
version: "latest"
}
]
)
puts(container.id)
ホスト型コンテナは、デフォルトでは外部ネットワークにアクセスできません。
有効にするには、次の設定が必要です。
管理者がダッシュボードで組織の許可リストを設定する必要があります。
リクエスト内のコンテナ環境で network_policy を明示的に設定する必要があります。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 curl -L 'https://api.openai.com/v1/responses' \
-H "Authorization: Bearer $OPENAI_API_KEY " \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-6-astra",
"tool_choice": "required",
"tools": [
{
"type": "shell",
"environment": {
"type": "container_auto",
"network_policy": {
"type": "allowlist",
"allowed_domains": ["pypi.org", "files.pythonhosted.org", "github.com"]
}
}
}
],
"input": [
{
"role": "user",
"content": "In the container, pip install httpx beautifulsoup4, fetch release pages, and write /mnt/data/release_digest.md."
}
]
}' 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 import OpenAI from "openai";
const client = new OpenAI();
const response = await client.responses.create({
model: "gpt-6-astra",
tool_choice: "required",
tools: [
{
type: "shell",
environment: {
type: "container_auto",
network_policy: {
type: "allowlist",
allowed_domains: ["pypi.org", "files.pythonhosted.org", "github.com"],
},
},
},
],
input: [
{
role: "user",
content:
"In the container, pip install httpx beautifulsoup4, fetch release pages, and write /mnt/data/release_digest.md.",
},
],
});
console.log(response.output_text); 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32 from openai import OpenAI
client = OpenAI()
response = client.responses.create(
model="gpt-6-astra",
tool_choice="required",
tools=[
{
"type": "shell",
"environment": {
"type": "container_auto",
"network_policy": {
"type": "allowlist",
"allowed_domains": [
"pypi.org",
"files.pythonhosted.org",
"github.com",
],
},
},
}
],
input=[
{
"role": "user",
"content": "In the container, pip install httpx beautifulsoup4, fetch release pages, and write /mnt/data/release_digest.md.",
}
],
)
print(response.output_text) 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 package main
import (
"context"
"fmt"
"github.com/openai/openai-go/v3"
"github.com/openai/openai-go/v3/responses"
)
func main() {
client := openai.NewClient()
tool := responses.ToolUnionParam{OfShell: &responses.FunctionShellToolParam{
Environment: responses.FunctionShellToolEnvironmentUnionParam{OfContainerAuto: &responses.ContainerAutoParam{
NetworkPolicy: responses.ContainerAutoNetworkPolicyUnionParam{OfAllowlist: &responses.ContainerNetworkPolicyAllowlistParam{
AllowedDomains: []string{"pypi.org", "files.pythonhosted.org", "github.com"},
}},
}},
}}
response, err := client.Responses.New(context.Background(), responses.ResponseNewParams{
Model: "gpt-6-astra",
ToolChoice: responses.ResponseNewParamsToolChoiceUnion{OfToolChoiceMode: openai.Opt(responses.ToolChoiceOptionsRequired)},
Tools: []responses.ToolUnionParam{tool},
Input: responses.ResponseNewParamsInputUnion{OfString: openai.String("In the container, pip install httpx beautifulsoup4, fetch release pages, and write /mnt/data/release_digest.md.")},
})
if err != nil {
panic(err)
}
fmt.Println(response.OutputText())
} 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32 import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.models.responses.ContainerAuto;
import com.openai.models.responses.ContainerNetworkPolicyAllowlist;
import com.openai.models.responses.FunctionShellTool;
import com.openai.models.responses.ResponseCreateParams;
import com.openai.models.responses.ToolChoiceOptions;
ResponseCreateParams params =
ResponseCreateParams.builder()
.model("gpt-6-astra")
.input("Fetch release pages and write /mnt/data/release_digest.md.")
.toolChoice(ToolChoiceOptions.REQUIRED)
.addTool(
FunctionShellTool.builder()
.environment(
ContainerAuto.builder()
.networkPolicy(
ContainerNetworkPolicyAllowlist.builder()
.addAllowedDomain("pypi.org")
.addAllowedDomain("files.pythonhosted.org")
.addAllowedDomain("github.com")
.build())
.build())
.build())
.build();
client.responses().create(params).output().stream()
.flatMap(item -> item.message().stream())
.flatMap(message -> message.content().stream())
.flatMap(content -> content.outputText().stream())
.forEach(text -> System.out.println(text.text())); 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 require "openai"
client = OpenAI::Client.new
response = client.responses.create(
model: "gpt-6-astra",
input: "Fetch release pages and write /mnt/data/release_digest.md.",
tool_choice: :required,
tools: [
{
type: :shell,
environment: {
type: :container_auto,
network_policy: {
type: :allowlist,
allowed_domains: ["pypi.org", "files.pythonhosted.org", "github.com"]
}
}
}
]
)
puts(response.output_text)
ドメインを許可リストに追加すると、
プロンプトインジェクションによるデータの不正持ち出しなどのセキュリティリスクが生じます。許可リストに追加するのは、信頼でき、
攻撃者が不正に持ち出したデータの受信先として利用できないドメインだけにしてください。このツールを使用する前に、以下のリスクと
安全性 のセクションをよく確認してください。
複数の制御が設定されている場合は、次のように適用されます。
組織の許可リストによって、allowed_domains に指定できるドメイン全体が定義されます。
リクエスト単位の network_policy によって、アクセスがさらに制限されます。
allowed_domains に組織の許可リストにないドメインが含まれていると、リクエストは失敗します。
ホスト型シェルと Code Interpreter が使用するホスト型コンテナでは、コンテナがアクティブな間、一時的なアプリケーションの状態がコンテナのファイルシステム(一時的なブロックストレージを使用)に書き込まれる場合があります。コンテナの有効期限が切れるか、明示的に削除されると、コンテナ内のデータは削除されます。
データ制御の詳細は、ZDR とデータレジデンシー を参照してください。
ホスト型シェルでは、ダウンロード可能なファイルを生成できます。/mnt/data 配下に書き込まれた成果物を取得するには、Code Interpreter と同じ container/files API を使用します。
コンテンツやファイルの保持をホスト環境のライフサイクル内に限定するには、リクエストにファイルをインラインで含め、コンテナにインラインスキルをマウントできます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55 INLINE_ZIP = $( base64 -i ./csv_insights.zip )
REPORT_CSV = $( base64 -i ./report.csv )
CONTAINER_ID = $(
curl -sL 'https://api.openai.com/v1/containers' \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $OPENAI_API_KEY " \
-d '{
"name": "inline-skill-container",
"skills": [
{
"type": "inline",
"name": "csv-insights",
"description": "Summarize CSV files and produce a markdown report.",
"source": {
"type": "base64",
"media_type": "application/zip",
"data": "'" $INLINE_ZIP "'"
}
}
]
}' | jq -r '.id'
)
curl -L 'https://api.openai.com/v1/responses' \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $OPENAI_API_KEY " \
-d '{
"model": "gpt-6-astra",
"tools": [
{
"type": "shell",
"environment": {
"type": "container_reference",
"container_id": "'" $CONTAINER_ID "'"
}
}
],
"input": [
{
"role": "user",
"content": [
{
"type": "input_file",
"filename": "report.csv",
"file_data": "data:text/csv;base64,'"${ REPORT_CSV }"'"
},
{
"type": "input_text",
"text": "Use the csv-insights skill to summarize report.csv."
}
]
}
]
}' 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56 import fs from "fs";
import OpenAI from "openai";
const client = new OpenAI();
const inlineZip = fs
.readFileSync("fixtures/csv_insights.zip")
.toString("base64");
const reportCsv = fs.readFileSync("fixtures/report.csv").toString("base64");
const container = await client.containers.create({
name: "inline-skill-container",
skills: [
{
type: "inline",
name: "csv-insights",
description: "Summarize CSV files and produce a markdown report.",
source: {
type: "base64",
media_type: "application/zip",
data: inlineZip,
},
},
],
});
const response = await client.responses.create({
model: "gpt-6-astra",
tools: [
{
type: "shell",
environment: {
type: "container_reference",
container_id: container.id,
},
},
],
input: [
{
role: "user",
content: [
{
type: "input_file",
filename: "report.csv",
file_data: `data:text/csv;base64,${reportCsv}`,
},
{
type: "input_text",
text: "Use the csv-insights skill to summarize report.csv.",
},
],
},
],
});
console.log(response.output_text); 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57 import base64
from openai import OpenAI
client = OpenAI()
with open("csv_insights.zip", "rb") as f:
inline_zip = base64.b64encode(f.read()).decode("utf-8")
with open("report.csv", "rb") as f:
base64_string = base64.b64encode(f.read()).decode("utf-8")
container = client.containers.create(
name="inline-skill-container",
skills=[
{
"type": "inline",
"name": "csv-insights",
"description": "Summarize CSV files and produce a markdown report.",
"source": {
"type": "base64",
"media_type": "application/zip",
"data": inline_zip,
},
}
],
)
response = client.responses.create(
model="gpt-6-astra",
tools=[
{
"type": "shell",
"environment": {
"type": "container_reference",
"container_id": container.id,
},
}
],
input=[
{
"role": "user",
"content": [
{
"type": "input_file",
"filename": "report.csv",
"file_data": f"data:text/csv;base64,{base64_string}",
},
{
"type": "input_text",
"text": "Use the csv-insights skill to summarize report.csv.",
},
],
}
],
)
print(response.output_text) 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50 require "base64"
require "openai"
client = OpenAI::Client.new
inline_zip = Base64.strict_encode64(File.binread("csv_insights.zip"))
base64_string = Base64.strict_encode64(File.binread("report.csv"))
container = client.containers.create(
name: "inline-skill-container",
skills: [
{
type: :inline,
name: "csv-insights",
description: "Summarize CSV files and produce a markdown report.",
source: {
type: :base64,
media_type: "application/zip",
data: inline_zip
}
}
]
)
response = client.responses.create(
model: "gpt-6-astra",
tools: [
{
type: :shell,
environment: {
type: :container_reference,
container_id: container.id
}
}
],
input: [
{
role: :user,
content: [
{
type: :input_file,
filename: "report.csv",
file_data: "data:text/csv;base64,#{base64_string}"
},
{
type: :input_text,
text: "Use the csv-insights skill to summarize report.csv."
}
]
}
]
)
puts(response.output_text)
後続のリクエストでは、container_reference で同じ container_id を渡します。コンテナがアクティブな間は、マウントしたスキルとコンテナ内の既存ファイルを引き続き利用できます。
非アクティブ状態が続いて有効期限が切れるのを待たずに、作業が完了した時点でコンテナを明示的に削除できます。
curl -L -X DELETE 'https://api.openai.com/v1/containers/container_id' \
-H "Authorization: Bearer $OPENAI_API_KEY " import OpenAI from "openai";
const client = new OpenAI();
const deleted = await client.containers.delete("container_id");
console.log(deleted); # Replace the illustrative IDs and URLs below with your own resource values.
from openai import OpenAI
client = OpenAI()
container_id = "cntr_123"
deleted = client.containers.delete(container_id)
print(deleted) package main
import (
"context"
"fmt"
"github.com/openai/openai-go/v3"
)
func main() {
client := openai.NewClient()
if err := client.Containers.Delete(context.Background(), "container_id"); err != nil {
panic(err)
}
fmt.Println("Container deleted")
} import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
String containerId = "container_id";
client.containers().delete(containerId);
System.out.println("Container deleted."); require "openai"
client = OpenAI::Client.new
client.containers.delete("container_id")
puts("Deleted container_id")
ドメインシークレット
allowed_domains リスト内のドメインで、Authorization: Bearer <token> などの機密情報を含む認可ヘッダーが必要な場合は、domain_secrets を使用します。
各シークレットエントリには、次の情報を含めます。
対象ドメイン
わかりやすいシークレット名
シークレットの値
実行時の動作は次のとおりです。
モデルとランタイムには、認証情報の実際の値ではなく、プレースホルダー名(例:$API_KEY)が渡されます。
auth-translation サイドカーは、承認済みの接続先に対してのみ、シークレットの実際の値を適用します。
シークレットの実際の値は API サーバーに永続化されず、モデルが参照できるコンテキストにも含まれません。
これにより、アシスタントは漏えいのリスクを抑えながら、保護されたサービスを呼び出せます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32 curl -L 'https://api.openai.com/v1/responses' \
-H "Authorization: Bearer $OPENAI_API_KEY " \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-6-astra",
"input": [
{
"role": "user",
"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."
}
],
"tool_choice": "required",
"tools": [
{
"type": "shell",
"environment": {
"type": "container_auto",
"network_policy": {
"type": "allowlist",
"allowed_domains": ["httpbin.org"],
"domain_secrets": [
{
"domain": "httpbin.org",
"name": "API_KEY",
"value": "debug-secret-123"
}
]
}
}
}
]
}' 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36 import OpenAI from "openai";
const client = new OpenAI();
const response = await client.responses.create({
model: "gpt-6-astra",
input: [
{
role: "user",
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.",
},
],
tool_choice: "required",
tools: [
{
type: "shell",
environment: {
type: "container_auto",
network_policy: {
type: "allowlist",
allowed_domains: ["httpbin.org"],
domain_secrets: [
{
domain: "httpbin.org",
name: "API_KEY",
value: "debug-secret-123",
},
],
},
},
},
],
});
console.log(response.output_text); 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35 from openai import OpenAI
client = OpenAI()
response = client.responses.create(
model="gpt-6-astra",
input=[
{
"role": "user",
"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.",
}
],
tool_choice="required",
tools=[
{
"type": "shell",
"environment": {
"type": "container_auto",
"network_policy": {
"type": "allowlist",
"allowed_domains": ["httpbin.org"],
"domain_secrets": [
{
"domain": "httpbin.org",
"name": "API_KEY",
"value": "debug-secret-123",
}
],
},
},
}
],
)
print(response.output_text) 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35 package main
import (
"context"
"fmt"
"github.com/openai/openai-go/v3"
"github.com/openai/openai-go/v3/responses"
)
func main() {
client := openai.NewClient()
tool := responses.ToolUnionParam{OfShell: &responses.FunctionShellToolParam{
Environment: responses.FunctionShellToolEnvironmentUnionParam{OfContainerAuto: &responses.ContainerAutoParam{
NetworkPolicy: responses.ContainerAutoNetworkPolicyUnionParam{OfAllowlist: &responses.ContainerNetworkPolicyAllowlistParam{
AllowedDomains: []string{"httpbin.org"},
DomainSecrets: []responses.ContainerNetworkPolicyDomainSecretParam{{
Domain: "httpbin.org",
Name: "API_KEY",
Value: "debug-secret-123",
}},
}},
}},
}}
response, err := client.Responses.New(context.Background(), responses.ResponseNewParams{
Model: "gpt-6-astra",
ToolChoice: responses.ResponseNewParamsToolChoiceUnion{OfToolChoiceMode: openai.Opt(responses.ToolChoiceOptionsRequired)},
Tools: []responses.ToolUnionParam{tool},
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.")},
})
if err != nil {
panic(err)
}
fmt.Println(response.OutputText())
} 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40 import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.models.responses.ContainerAuto;
import com.openai.models.responses.ContainerNetworkPolicyAllowlist;
import com.openai.models.responses.ContainerNetworkPolicyDomainSecret;
import com.openai.models.responses.FunctionShellTool;
import com.openai.models.responses.ResponseCreateParams;
import com.openai.models.responses.ToolChoiceOptions;
ResponseCreateParams params =
ResponseCreateParams.builder()
.model("gpt-6-astra")
.input(
"Use curl to call https://httpbin.org/status/204 with an "
+ "Authorization: Bearer $API_KEY header. Print only the HTTP status code; "
+ "never print request headers or secret values.")
.toolChoice(ToolChoiceOptions.REQUIRED)
.addTool(
FunctionShellTool.builder()
.environment(
ContainerAuto.builder()
.networkPolicy(
ContainerNetworkPolicyAllowlist.builder()
.addAllowedDomain("httpbin.org")
.addDomainSecret(
ContainerNetworkPolicyDomainSecret.builder()
.domain("httpbin.org")
.name("API_KEY")
.value(System.getenv("OPENAI_EXAMPLE_DOMAIN_SECRET"))
.build())
.build())
.build())
.build())
.build();
client.responses().create(params).output().stream()
.flatMap(item -> item.message().stream())
.flatMap(message -> message.content().stream())
.flatMap(content -> content.outputText().stream())
.forEach(text -> System.out.println(text.text())); 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 require "openai"
client = OpenAI::Client.new
response = client.responses.create(
model: "gpt-6-astra",
input: "Use curl to call https://httpbin.org/headers with an " \
'"Authorization: Bearer $API_KEY" header.',
tool_choice: :required,
tools: [
{
type: :shell,
environment: {
type: :container_auto,
network_policy: {
type: :allowlist,
allowed_domains: ["httpbin.org"],
domain_secrets: [
{
domain: "httpbin.org",
name: "API_KEY",
value: "debug-secret-123"
}
]
}
}
}
]
)
puts(response.output_text)
同じホスト環境で作業を続けるには、コンテナを再利用し、previous_response_id を渡します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 curl -L 'https://api.openai.com/v1/responses' \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $OPENAI_API_KEY " \
-d '{
"model": "gpt-6-astra",
"previous_response_id": "resp_2a8e5c9174d63b0f18a4c572de9f64a1b3c76d508e12f9ab47",
"tools": [
{
"type": "shell",
"environment": {
"type": "container_reference",
"container_id": "cntr_f19c2b51e4a06793d82d54a7be0fc9154d3361ab28ce7f6041"
}
}
],
"input": "Read /mnt/data/top5.csv and report the top candidate."
}' 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 import OpenAI from "openai";
const client = new OpenAI();
const response = await client.responses.create({
model: "gpt-6-astra",
previous_response_id:
"resp_2a8e5c9174d63b0f18a4c572de9f64a1b3c76d508e12f9ab47",
tools: [
{
type: "shell",
environment: {
type: "container_reference",
container_id: "cntr_f19c2b51e4a06793d82d54a7be0fc9154d3361ab28ce7f6041",
},
},
],
input: "Read /mnt/data/top5.csv and report the top candidate.",
});
console.log(response.output_text); 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 from openai import OpenAI
client = OpenAI()
response = client.responses.create(
model="gpt-6-astra",
previous_response_id="resp_2a8e5c9174d63b0f18a4c572de9f64a1b3c76d508e12f9ab47",
tools=[
{
"type": "shell",
"environment": {
"type": "container_reference",
"container_id": "cntr_f19c2b51e4a06793d82d54a7be0fc9154d3361ab28ce7f6041",
},
}
],
input="Read /mnt/data/top5.csv and report the top candidate.",
)
print(response.output_text) 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 package main
import (
"context"
"fmt"
"github.com/openai/openai-go/v3"
"github.com/openai/openai-go/v3/responses"
)
func main() {
client := openai.NewClient()
tool := responses.ToolUnionParam{OfShell: &responses.FunctionShellToolParam{
Environment: responses.FunctionShellToolEnvironmentUnionParam{OfContainerReference: &responses.ContainerReferenceParam{ContainerID: "cntr_f19c2b51e4a06793d82d54a7be0fc9154d3361ab28ce7f6041"}},
}}
response, err := client.Responses.New(context.Background(), responses.ResponseNewParams{
Model: "gpt-6-astra",
PreviousResponseID: openai.String("resp_2a8e5c9174d63b0f18a4c572de9f64a1b3c76d508e12f9ab47"),
Tools: []responses.ToolUnionParam{tool},
Input: responses.ResponseNewParamsInputUnion{OfString: openai.String("Read /mnt/data/top5.csv and report the top candidate.")},
})
if err != nil {
panic(err)
}
fmt.Println(response.OutputText())
} 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.models.responses.FunctionShellTool;
import com.openai.models.responses.ResponseCreateParams;
String responseId = "resp_2a8e5c9174d63b0f18a4c572de9f64a1b3c76d508e12f9ab47";
String containerId = "cntr_f19c2b51e4a06793d82d54a7be0fc9154d3361ab28ce7f6041";
ResponseCreateParams params =
ResponseCreateParams.builder()
.model("gpt-6-astra")
.input("Read /mnt/data/top5.csv and report the top candidate.")
.previousResponseId(responseId)
.addTool(FunctionShellTool.builder().containerReferenceEnvironment(containerId).build())
.build();
client.responses().create(params).output().stream()
.flatMap(item -> item.message().stream())
.flatMap(message -> message.content().stream())
.flatMap(content -> content.outputText().stream())
.forEach(text -> System.out.println(text.text())); 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 require "openai"
client = OpenAI::Client.new
response = client.responses.create(
model: "gpt-6-astra",
input: "Read /mnt/data/top5.csv and report the top candidate.",
previous_response_id: "resp_2a8e5c9174d63b0f18a4c572de9f64a1b3c76d508e12f9ab47",
tools: [
{
type: :shell,
environment: {
type: :container_reference,
container_id: "cntr_f19c2b51e4a06793d82d54a7be0fc9154d3361ab28ce7f6041"
}
}
]
)
puts(response.output_text)
ホスト型シェルとローカルシェルは、同じ出力アイテム型を使用します。シェルの実行は、次の出力アイテムのペアで表されます。
shell_call:モデルが実行を要求したコマンド
shell_call_output:コマンドの出力と終了結果
1
2
3
4
5
6
7
8
9
10 {
"type" : "shell_call" ,
"call_id" : "call_9d14ac6f2b73485e91c0f4da6e1b27c8" ,
"action" : {
"commands" : [ "ls -l" ],
"timeout_ms" : 120000 ,
"max_output_length" : 4096
},
"status" : "in_progress"
}
shell_call アクションを実行し、shell_call_output をモデルに返すことで、独自のローカルランタイムでシェルコマンドを実行することもできます。
実行環境、ファイルシステムへのアクセス、既存の内部ツールを完全に制御する必要がある場合は、このモードを使用します。
1
2
3
4
5
6
7
8
9 curl -L 'https://api.openai.com/v1/responses' \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $OPENAI_API_KEY " \
-d '{
"model": "gpt-6-astra",
"instructions": "The local bash shell environment is on Mac.",
"input": "find me the largest pdf file in ~/Documents",
"tools": [{ "type": "shell", "environment": { "type": "local" } }]
}' 1
2
3
4
5
6
7
8
9
10
11
12 import OpenAI from "openai";
const client = new OpenAI();
const response = await client.responses.create({
model: "gpt-6-astra",
instructions: "The local bash shell environment is on Mac.",
input: "find me the largest pdf file in ~/Documents",
tools: [{ type: "shell", environment: { type: "local" } }],
});
console.log(response); 1
2
3
4
5
6
7
8
9
10
11
12 from openai import OpenAI
client = OpenAI()
response = client.responses.create(
model="gpt-6-astra",
instructions="The local bash shell environment is on Mac.",
input="find me the largest pdf file in ~/Documents",
tools=[{"type": "shell", "environment": {"type": "local"}}],
)
print(response) 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 package main
import (
"context"
"fmt"
"github.com/openai/openai-go/v3"
"github.com/openai/openai-go/v3/responses"
)
func main() {
client := openai.NewClient()
tool := responses.ToolUnionParam{OfShell: &responses.FunctionShellToolParam{
Environment: responses.FunctionShellToolEnvironmentUnionParam{OfLocal: &responses.LocalEnvironmentParam{}},
}}
response, err := client.Responses.New(context.Background(), responses.ResponseNewParams{
Model: "gpt-6-astra",
Instructions: openai.String("The local bash shell environment is on Mac."),
Input: responses.ResponseNewParamsInputUnion{OfString: openai.String("find me the largest pdf file in ~/Documents")},
Tools: []responses.ToolUnionParam{tool},
})
if err != nil {
panic(err)
}
fmt.Println(response.Output)
} 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.core.JsonValue;
import com.openai.models.responses.ResponseCreateParams;
import java.util.List;
import java.util.Map;
ResponseCreateParams params =
ResponseCreateParams.builder()
.model("gpt-6-astra")
.input("Find the largest PDF in ~/Documents.")
.instructions("The local shell environment is macOS.")
.putAdditionalBodyProperty(
"tools",
JsonValue.from(
List.of(Map.of("type", "shell", "environment", Map.of("type", "local")))))
.build();
client.responses().create(params).output().stream()
.flatMap(item -> item.shellCall().stream())
.flatMap(call -> call.action().commands().stream())
.forEach(System.out::println); 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 require "openai"
client = OpenAI::Client.new
response = client.responses.create(
model: "gpt-6-astra",
instructions: "The local shell environment is macOS.",
input: "Find the largest PDF in ~/Documents.",
tools: [
{
type: :shell,
environment: { type: :local }
}
]
)
puts(response.output)
shell_call 出力アイテムを受け取ったら、次の手順を実行します。
要求されたコマンドを自分のランタイムで実行します。
stdout、stderr、および実行結果を取得します。
次のリクエストで、結果を shell_call_output として返します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 import { exec as execCallback } from "node:child_process";
import { promisify } from "node:util";
const exec = promisify(execCallback);
class ShellExecutor {
constructor(defaultTimeoutMs = 60_000) {
this.defaultTimeoutMs = defaultTimeoutMs;
}
async run(cmd, timeoutMs) {
const timeout = timeoutMs ?? this.defaultTimeoutMs;
try {
const { stdout, stderr } = await exec(cmd, { timeout });
return { stdout, stderr, exitCode: 0, timedOut: false };
} catch (error) {
const timedOut = Boolean(error?.killed) && error?.signal === "SIGTERM";
const exitCode = timedOut ? null : (error?.code ?? null);
return {
stdout: error?.stdout ?? "",
stderr: error?.stderr ?? String(error),
exitCode,
timedOut,
};
}
}
} 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 @dataclass
class CmdResult :
stdout: str
stderr: str
exit_code: int | None
timed_out: bool
class ShellExecutor :
def __init__ (self, default_timeout: float = 60 ):
self .default_timeout = default_timeout
def run (self, cmd: str , timeout: float | None = None ) -> CmdResult:
t = timeout or self .default_timeout
p = subprocess.Popen(
cmd,
shell = True ,
stdout = subprocess. PIPE ,
stderr = subprocess. PIPE ,
text = True ,
)
try :
out, err = p.communicate( timeout = t)
return CmdResult(out, err, p.returncode, False )
except subprocess.TimeoutExpired:
p.kill()
out, err = p.communicate()
return CmdResult(out, err, p.returncode, True ) 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55 package main
import (
"bytes"
"context"
"fmt"
"os/exec"
"time"
)
type shellResult struct {
Stdout string
Stderr string
ExitCode int
TimedOut bool
}
type shellExecutor struct {
DefaultTimeout time.Duration
}
func (e shellExecutor) run(command string, timeout time.Duration) shellResult {
if timeout == 0 {
timeout = e.DefaultTimeout
}
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
cmd := exec.CommandContext(ctx, "sh", "-c", command)
var stdout, stderr bytes.Buffer
cmd.Stdout = &stdout
cmd.Stderr = &stderr
err := cmd.Run()
result := shellResult{Stdout: stdout.String(), Stderr: stderr.String()}
if ctx.Err() == context.DeadlineExceeded {
result.TimedOut = true
result.ExitCode = -1
return result
}
if err != nil {
if exitError, ok := err.(*exec.ExitError); ok {
result.ExitCode = exitError.ExitCode()
return result
}
if result.Stderr == "" {
result.Stderr = err.Error()
}
result.ExitCode = -1
}
return result
}
func main() {
executor := shellExecutor{DefaultTimeout: time.Minute}
fmt.Println(executor.run("printf shell-executor-ready", 0))
} 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40 require "open3"
class ShellExecutor
Result = Data.define(:stdout, :stderr, :exit_code, :timed_out)
def initialize(default_timeout: 60)
@default_timeout = default_timeout
end
def run(command, timeout: @default_timeout)
Open3.popen3("sh", "-c", command, pgroup: true) do |stdin, stdout, stderr, wait_thread|
stdin.close
stdout_reader = Thread.new { stdout.read }
stderr_reader = Thread.new { stderr.read }
finished = wait_thread.join(timeout)
terminate_process_group(wait_thread) unless finished
Result.new(
stdout: stdout_reader.value,
stderr: stderr_reader.value,
exit_code: wait_thread.value.exitstatus || -1,
timed_out: finished.nil?
)
end
end
private
def terminate_process_group(wait_thread)
Process.kill("TERM", -wait_thread.pid)
wait_thread.join(1)
Process.kill("KILL", -wait_thread.pid)
rescue Errno::ESRCH
nil
ensure
wait_thread.join
end
end
puts(ShellExecutor.new.run("printf shell-executor-ready"))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 {
"type" : "shell_call_output" ,
"call_id" : "call_3ef1b8c79a4d6520f9e3ab7d41c68f25" ,
"max_output_length" : 4096 ,
"output" : [
{
"stdout" : "..." ,
"stderr" : "..." ,
"outcome" : {
"type" : "exit" ,
"exit_code" : 0
}
},
{
"stdout" : "..." ,
"stderr" : "..." ,
"outcome" : {
"type" : "timeout"
}
}
]
}
従来の実装からの移行については、旧版のローカルシェルガイド を参照してください。
Agents SDK を使用している場合は、独自に実装したシェルの実行処理をシェルツールのヘルパーに渡せます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42 import { Agent, run, withTrace, shellTool } from "@openai/agents" ;
class LocalShell {
async run ( action ) {
return {
output: [
{
stdout: "Shell is not available. Needs to be implemented first." ,
stderr: "" ,
outcome: {
type: "exit" ,
exitCode: 1 ,
},
},
],
maxOutputLength: action.maxOutputLength,
};
}
}
const shell = new LocalShell ();
const agent = new Agent ({
name: "Shell Assistant" ,
model: "gpt-6-astra" ,
instructions:
"You can execute shell commands to inspect the repository. Keep responses concise and include command output when helpful." ,
tools: [
shellTool ({
shell,
needsApproval: true ,
onApproval : async ( _ctx , _approvalItem ) => {
return { approve: true };
},
}),
],
});
await withTrace ( "shell-tool-example" , async () => {
const result = await run (agent, "Show the Node.js version." );
console. log ( ` \n Final response: \n ${ result . finalOutput }` );
}); 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50 from agents import (
Agent,
Runner,
ShellCallOutcome,
ShellCommandOutput,
ShellCommandRequest,
ShellResult,
ShellTool,
)
class LocalShell:
async def __call__(self, request: ShellCommandRequest) -> ShellResult:
action = request.data.action
return ShellResult(
output=[
ShellCommandOutput(
command="(not executed)",
stdout="Shell is not available. Needs to be implemented first.",
stderr="",
outcome=ShellCallOutcome(type="exit", exit_code=1),
)
],
max_output_length=action.max_output_length,
)
shell_tool = ShellTool(
executor=LocalShell(),
needs_approval=True,
on_approval=lambda _ctx, _approval_item: {"approve": True},
)
agent = Agent(
name="Shell Assistant",
model="gpt-6-astra",
instructions="You can execute shell commands to inspect the repository. Keep responses concise and include command output when helpful.",
tools=[shell_tool],
)
async def main():
result = await Runner.run(agent, input="Show the Node.js version.")
print(f"\nFinal response:\n{result.final_output}")
if __name__ == "__main__":
import asyncio
asyncio.run(main())
SDK のリポジトリには、実際に動作するサンプルがあります。
Agents SDK のシェルツールを使用する TypeScript のサンプルです。
Agents SDK のシェルツールを使用する Python のサンプルです。
コマンドの実行がタイムアウトした場合は、タイムアウトを示す結果と、それまでに取得した出力を返してください。
shell_call に max_output_length が含まれている場合は、shell_call_output にも含めてください。
対話型のコマンドには依存せず、シェルツールは非対話形式で実行してください。
モデルが復旧手順を検討できるように、終了コードがゼロ以外の場合も出力を保持してください。
Containers API のネットワークアクセスを有効にすると強力な機能を利用できますが、セキュリティとデータガバナンスに関する重大なリスクも生じます。デフォルトでは、ネットワークアクセスは無効です。有効にする場合も、外部へのアクセスはタスクに必要な信頼できるドメインに厳しく限定してください。
ネットワークアクセスを有効にしたコンテナは、サードパーティーのサービスやパッケージレジストリと通信できます。そのため、データ漏えい、プロンプトインジェクションによるツールの不正利用、意図した範囲を超える偶発的なアクセスなどのリスクが生じます。ポリシーの許可範囲が広すぎる場合、見直されず固定されたままの場合、適用が一貫していない場合には、こうしたリスクが高まります。
ネットワーク経由で取得したコンテンツのプロンプトインジェクションリスクの理解
ネットワーク経由で取得する外部コンテンツには、モデルの動作を操作するための指示が隠されている可能性があります。信頼できないネットワーク上のコンテンツは、悪意がある可能性を前提に扱い、データやシステムを変更しうる操作には特に注意してください。
信頼でき、自ら継続的に管理しているドメインのみを許可してください。他のサービスへの通信を中継する仲介サービスやアグリゲーターには注意し、許可ドメインリストに追加する前に、データの取り扱いと保持の実態を確認してください。
Responses API のレスポンスに含まれるシェルツールのコマンドと実行出力をレビューしてください。セッションごとに、要求されたホストと実際の外部接続先を記録してください。ログを定期的にレビューし、アクセスパターンが想定どおりであることを確認するとともに、想定からのずれや不審な動作を検出してください。
OpenAI のデータ管理 は、OpenAI の管理範囲内で適用されます。ただし、ネットワーク接続を介してサードパーティーのサービスに送信されたデータには、そのサービスのデータ保持ポリシーが適用されます。外部エンドポイントが、自社のデータレジデンシー、保持、コンプライアンスの要件を満たしていることを確認してください。