- ホーム
- Documentation
- ランタイムツール
- Bash ツールランタイム
Bash ツールランタイム
このドキュメントでは、エージェントのツール呼び出しで使用される bash ツール のランタイムパスについて、コマンドの正規化から実行、切り詰め/アーティファクト、レンダリングまでを説明します。
また、インタラクティブ TUI、プリントモード、RPC モード、およびユーザーが開始するバン(!)シェル実行において動作が異なる箇所も示しています。
スコープとランタイムサーフェス
Section titled “スコープとランタイムサーフェス”coding-agent には2つの異なる bash 実行サーフェスがあります:
- ツール呼び出しサーフェス(
toolName: "bash"):モデルが bash ツールを呼び出す際に使用されます。- エントリポイント:
BashTool.execute()
- エントリポイント:
- ユーザーバンコマンドサーフェス(インタラクティブ入力からの
!cmdまたは RPCbashコマンド):セッションレベルのヘルパーパスです。- エントリポイント:
AgentSession.executeBash()
- エントリポイント:
どちらも最終的には src/exec/bash-executor.ts の executeBash() を非 PTY 実行に使用しますが、ツール呼び出しパスのみが正規化/インターセプションとツールレンダラーのロジックを実行します。
エンドツーエンドのツール呼び出しパイプライン
Section titled “エンドツーエンドのツール呼び出しパイプライン”1) 入力の正規化とパラメータマージ
Section titled “1) 入力の正規化とパラメータマージ”BashTool.execute() はまず normalizeBashCommand() を通じて生のコマンドを正規化します:
- 末尾の
| head -n N、| head -N、| tail -n N、| tail -Nを構造化されたリミットとして抽出します - 末尾/先頭の空白をトリムします
- 内部の空白はそのまま保持します
次に、抽出されたリミットを明示的なツール引数とマージします:
- 明示的な
head/tail引数は抽出された値をオーバーライドします - 抽出された値はフォールバックとしてのみ使用されます
bash-normalize.ts のコメントには 2>&1 の除去について言及がありますが、現在の実装ではそれを削除しません。ランタイムの動作は依然として正しいですが(stdout/stderr は既にマージされています)、正規化の動作はコメントが示唆するよりも狭い範囲です。
2) オプショナルインターセプション(ブロックコマンドパス)
Section titled “2) オプショナルインターセプション(ブロックコマンドパス)”bashInterceptor.enabled が true の場合、BashTool は設定からルールを読み込み、正規化されたコマンドに対して checkBashInterception() を実行します。
インターセプションの動作:
- コマンドがブロックされるのは以下の 両方 が満たされた場合のみ:
- 正規表現ルールがマッチする、かつ
- 提案されたツールが
ctx.toolNamesに存在する
- 無効な正規表現ルールは暗黙的にスキップされます
- ブロック時、
BashToolは以下のメッセージでToolErrorをスローします:Blocked: ...- 元のコマンドが含まれます
デフォルトのルールパターン(コードで定義)は一般的な誤用を対象としています:
- ファイルリーダー(
cat、head、tail、…) - 検索ツール(
grep、rg、…) - ファイルファインダー(
find、fd、…) - インプレースエディタ(
sed -i、perl -i、awk -i inplace) - シェルリダイレクト書き込み(
echo ... > file、ヒアドキュメントリダイレクション)
InterceptionResult には suggestedTool が含まれていますが、BashTool は現在メッセージテキストのみを表面化しています(details に構造化された提案ツールフィールドはありません)。
3) CWD の検証とタイムアウトのクランプ
Section titled “3) CWD の検証とタイムアウトのクランプ”cwd はセッションの cwd(resolveToCwd)に対して相対的に解決され、その後 stat で検証されます:
- パスが存在しない ->
ToolError("Working directory does not exist: ...") - ディレクトリではない ->
ToolError("Working directory is not a directory: ...")
タイムアウトは [1, 3600] 秒にクランプされ、ミリ秒に変換されます。
4) アーティファクトの割り当て
Section titled “4) アーティファクトの割り当て”実行前に、ツールは切り詰められた出力の保存用にアーティファクトのパス/ID を(ベストエフォートで)割り当てます。
- アーティファクトの割り当て失敗は致命的ではありません(アーティファクトスピルファイルなしで実行が続行されます)
- アーティファクトの ID/パスは、切り詰め時の完全な出力の永続化のために実行パスに渡されます
5) PTY vs 非 PTY 実行の選択
Section titled “5) PTY vs 非 PTY 実行の選択”BashTool は以下のすべてが true の場合にのみ PTY 実行を選択します:
bash.virtualTerminal === "on"PI_NO_PTY !== "1"- ツールコンテキストに UI がある(
ctx.hasUI === trueかつctx.uiが設定されている)
それ以外の場合は非インタラクティブな executeBash() を使用します。
つまり、プリントモードと非 UI の RPC/ツールコンテキストは常に非 PTY を使用します。
非インタラクティブ実行エンジン(executeBash)
Section titled “非インタラクティブ実行エンジン(executeBash)”シェルセッション再利用モデル
Section titled “シェルセッション再利用モデル”executeBash() はネイティブの Shell インスタンスを以下でキーイングされたプロセスグローバルマップにキャッシュします:
- シェルパス
- 設定されたコマンドプレフィックス
- スナップショットパス
- シリアライズされたシェル環境変数
- オプショナルなエージェントセッションキー
セッションレベルの実行では、AgentSession.executeBash() が sessionKey: this.sessionId を渡し、セッションごとに再利用を分離します。
ツール呼び出しパスは sessionKey を渡さ ない ため、再利用スコープはシェル設定/スナップショット/環境変数に基づきます。
シェル設定とスナップショットの動作
Section titled “シェル設定とスナップショットの動作”各呼び出し時に、エグゼキュータは設定のシェル構成(shell、env、オプショナルな prefix)を読み込みます。
選択されたシェルに bash が含まれる場合、getOrCreateSnapshot() を試行します:
- スナップショットはユーザー rc からのエイリアス/関数/オプションをキャプチャします
- スナップショットの作成はベストエフォートです
- 失敗した場合はスナップショットなしにフォールバックします
prefix が設定されている場合、コマンドは以下のようになります:
<prefix> <command>ストリーミングとキャンセル
Section titled “ストリーミングとキャンセル”Shell.run() はチャンクをコールバックにストリーミングします。エグゼキュータは各チャンクを OutputSink とオプショナルな onChunk コールバックにパイプします。
キャンセル:
- 中止シグナルは
shellSession.abort(...)をトリガーします - ネイティブ結果からのタイムアウトは
cancelled: true+ アノテーションテキストにマッピングされます - 明示的なキャンセルも同様に
cancelled: true+ アノテーションを返します
タイムアウト/キャンセル時にエグゼキュータ内で例外はスローされません。構造化された BashResult を返し、呼び出し元にエラーセマンティクスのマッピングを委ねます。
インタラクティブ PTY パス(runInteractiveBashPty)
Section titled “インタラクティブ PTY パス(runInteractiveBashPty)”PTY が有効な場合、ツールは runInteractiveBashPty() を実行し、オーバーレイコンソールコンポーネントを開いてネイティブの PtySession を駆動します。
動作のハイライト:
- xterm-headless 仮想ターミナルがオーバーレイにビューポートをレンダリングします
- キーボード入力は正規化されます(Kitty シーケンスやアプリケーションカーソルモードの処理を含む)
- 実行中の
escは PTY セッションを終了します - ターミナルのリサイズは PTY に伝播されます(
session.resize(cols, rows))
無人実行のための環境ハードニングデフォルトが注入されます:
- ページャー無効化(
PAGER=cat、GIT_PAGER=catなど) - エディタプロンプト無効化(
GIT_EDITOR=true、EDITOR=true、…) - ターミナル/認証プロンプトの削減(
GIT_TERMINAL_PROMPT=0、SSH_ASKPASS=/usr/bin/false、CI=1) - 非インタラクティブ動作のためのパッケージマネージャー/ツール自動化フラグ
PTY 出力は正規化され(CRLF/CR を LF に、sanitizeText)、アーティファクトスピルサポートを含めて OutputSink に書き込まれます。
PTY の起動/ランタイムエラー時、シンクは PTY error: ... 行を受け取り、コマンドは未定義の終了コードで完了します。
出力処理:ストリーミング、切り詰め、アーティファクトスピル
Section titled “出力処理:ストリーミング、切り詰め、アーティファクトスピル”PTY パスと非 PTY パスの両方が OutputSink を使用します。
OutputSink のセマンティクス
Section titled “OutputSink のセマンティクス”- インメモリの UTF-8 セーフなテールバッファを保持します(
DEFAULT_MAX_BYTES、現在 50KB) - 総バイト数/行数を追跡します
- アーティファクトパスが存在し、出力がオーバーフローした場合(またはファイルが既にアクティブな場合)、完全なストリームをアーティファクトファイルに書き込みます
- メモリしきい値がオーバーフローした場合、インメモリバッファをテール(UTF-8 境界セーフ)にトリムします
- オーバーフロー/ファイルスピルが発生した場合に
truncatedをマークします
dump() は以下を返します:
output(アノテーション付きプレフィックスの可能性あり)truncatedtotalLines/totalBytesoutputLines/outputBytes- アーティファクトファイルがアクティブな場合は
artifactId
長い出力に関する注意事項
Section titled “長い出力に関する注意事項”ランタイムの切り詰めは OutputSink のバイトしきい値ベースです(デフォルト 50KB)。このコードパスでは、ハードな 2000 行の制限は強制されません。
ライブツール更新
Section titled “ライブツール更新”非 PTY 実行の場合、BashTool は部分更新用に別の TailBuffer を使用し、コマンド実行中に onUpdate スナップショットを発行します。
PTY 実行の場合、ライブレンダリングは onUpdate テキストチャンクではなく、カスタム UI オーバーレイによって処理されます。
結果の整形、メタデータ、エラーマッピング
Section titled “結果の整形、メタデータ、エラーマッピング”実行後:
cancelledの処理:- 中止シグナルが中止されている場合 ->
ToolAbortErrorをスロー(中止セマンティクス) - それ以外 ->
ToolErrorをスロー(ツール失敗として扱われます)
- 中止シグナルが中止されている場合 ->
- PTY の
timedOut->ToolErrorをスロー - 最終出力テキストに head/tail フィルターを適用(
applyHeadTail、head が先で tail が後) - 空の出力は
(no output)になります toolResult(...).truncationFromSummary(result, { direction: "tail" })を通じて切り詰めメタデータを付加- 終了コードのマッピング:
- 終了コードが欠落 ->
ToolError("... missing exit status") - 非ゼロ終了 ->
ToolError("... Command exited with code N") - ゼロ終了 -> 成功結果
- 終了コードが欠落 ->
成功ペイロードの構造:
content:テキスト出力- 切り詰め時の
details.meta.truncation。以下を含みます:direction、truncatedBy、総/出力の行数+バイト数shownRange- 利用可能な場合は
artifactId
ビルトインツールは wrapToolWithMetaNotice() でラップされているため、切り詰め通知テキストは最終テキストコンテンツに自動的に追加されます(例:Full: artifact://<id>)。
レンダリングパス
Section titled “レンダリングパス”ツール呼び出しレンダラー(bashToolRenderer)
Section titled “ツール呼び出しレンダラー(bashToolRenderer)”bashToolRenderer はツール呼び出しメッセージ(toolCall / toolResult)に使用されます:
- 折りたたみモードでは視覚的な行切り詰めプレビューを表示します
- 展開モードでは現在利用可能なすべての出力テキストを表示します
- 警告行には切り詰め理由と、切り詰め時の
artifact://<id>が含まれます - タイムアウト値(引数から)はフッターのメタデータ行に表示されます
注意事項:完全なアーティファクト展開
Section titled “注意事項:完全なアーティファクト展開”BashRenderContext には isFullOutput がありますが、現在のレンダラーコンテキストビルダーは bash ツール結果に対してそれを設定しません。展開ビューは、別の呼び出し元が完全なアーティファクトコンテンツを提供しない限り、結果コンテンツ内のテキスト(テール/切り詰められた出力)を依然として使用します。
ユーザーバンコマンドコンポーネント(BashExecutionComponent)
Section titled “ユーザーバンコマンドコンポーネント(BashExecutionComponent)”BashExecutionComponent はインタラクティブモードでのユーザーの ! コマンド用です(モデルのツール呼び出しではありません):
- チャンクをライブストリーミングします
- 折りたたみプレビューは最後の 20 論理行を保持します
- 1行あたり 4000 文字で行クランプします
- メタデータが存在する場合、切り詰め + アーティファクト警告を表示します
- キャンセル/エラー/終了状態を個別にマークします
このコンポーネントは CommandController.handleBashCommand() によって配線され、AgentSession.executeBash() からデータが供給されます。
モード固有の動作の違い
Section titled “モード固有の動作の違い”| サーフェス | エントリパス | PTY 対象 | ライブ出力 UX | エラーの表面化 |
|---|---|---|---|---|
| インタラクティブツール呼び出し | BashTool.execute | はい、bash.virtualTerminal=on かつ UI が存在し PI_NO_PTY!=1 の場合 | PTY オーバーレイ(インタラクティブ)またはストリーミングテール更新 | ツールエラーは toolResult.isError になります |
| プリントモードツール呼び出し | BashTool.execute | いいえ(UI コンテキストなし) | TUI オーバーレイなし;出力はイベントストリーム/最終アシスタントテキストフローに表示 | 同じツールエラーマッピング |
| RPC ツール呼び出し(エージェントツーリング) | BashTool.execute | 通常 UI なし -> 非 PTY | 構造化されたツールイベント/結果 | 同じツールエラーマッピング |
インタラクティブバンコマンド(!) | AgentSession.executeBash + BashExecutionComponent | いいえ(エグゼキュータを直接使用) | 専用の bash 実行コンポーネント | コントローラーが例外をキャッチし UI エラーを表示 |
RPC bash コマンド | rpc-mode -> session.executeBash | いいえ | BashResult を直接返します | コンシューマーが返されたフィールドを処理 |
運用上の注意事項
Section titled “運用上の注意事項”- インターセプターは、提案されたツールが現在のコンテキストで利用可能な場合にのみコマンドをブロックします。
- アーティファクトの割り当てが失敗した場合、切り詰めは依然として発生しますが、
artifact://の逆参照は利用できません。 - シェルセッションキャッシュはこのモジュールに明示的なエビクションがありません。ライフタイムはプロセススコープです。
- PTY と非 PTY のタイムアウトサーフェスは異なります:
- PTY は明示的な
timedOut結果フィールドを公開します - 非 PTY はタイムアウトを
cancelled + annotationサマリーにマッピングします
- PTY は明示的な
実装ファイル
Section titled “実装ファイル”src/tools/bash.ts— ツールエントリポイント、正規化/インターセプション、PTY/非 PTY 選択、結果/エラーマッピング、bash ツールレンダラー。src/tools/bash-normalize.ts— コマンドの正規化と実行後の head/tail フィルタリング。src/tools/bash-interceptor.ts— インターセプタールールのマッチングとブロックコマンドメッセージ。src/exec/bash-executor.ts— 非 PTY エグゼキュータ、シェルセッション再利用、キャンセル配線、出力シンク統合。src/tools/bash-interactive.ts— PTY ランタイム、オーバーレイ UI、入力正規化、非インタラクティブ環境デフォルト。src/session/streaming-output.ts—OutputSink切り詰め/アーティファクトスピルとサマリーメタデータ。src/tools/output-utils.ts— アーティファクト割り当てヘルパーとストリーミングテールバッファ。src/tools/output-meta.ts— 切り詰めメタデータの形状 + 通知注入ラッパー。src/session/agent-session.ts— セッションレベルのexecuteBash、メッセージ記録、中止ライフサイクル。src/modes/components/bash-execution.ts— インタラクティブ!コマンド実行コンポーネント。src/modes/controllers/command-controller.ts— インタラクティブ!コマンド UI ストリーム/更新完了の配線。src/modes/rpc/rpc-mode.ts— RPCbashおよびabort_bashコマンドサーフェス。src/internal-urls/artifact-protocol.ts—artifact://<id>の解決。