エージェントにツールを1回呼ばせるたびに、結果を丸ごとコンテキストに積んで、モデルにもう1往復させる。この設計の無駄に各社がほぼ同時期に気づき、「モデルにはコードを書かせて、ツール呼び出しの合成はランタイム側で済ませる」方式へ収束しつつある。CloudflareのCode Mode、Anthropicのcode execution with MCP、そしてOpenAIのCodex CLIに実験フラグとして入っている「code mode」。2026年6月9日にリリースされたCodex 0.139.0は、このcode modeに残っていた大きな穴、つまりWeb検索をようやく塞いだ。
リリースノートでは1行の地味な変更だが、個人的には今回の目玉はここだと思っている。順に見ていく。
code modeの世界には exec と wait しかない
前提を整理しておく。code modeはCodexのconfig.tomlで有効化する実験機能で、モデルに見せるツールを実質execとwaitの2つに絞り込める。モデルは個々のツールをJSONで直接呼ぶ代わりに、生のJavaScriptを書いてexecに渡す。コードはNodeではなく、Codexプロセスに組み込まれたV8 isolate(今回のリリースでrusty_v8 149.2.0に更新)で非同期モジュールとして評価される。ファイルシステムもネットワークもconsoleもない、素のJSだ。
代わりに、シェル実行やMCPツールがグローバルのtoolsオブジェクトに生えてくる。await tools.exec_command(...)やawait tools.mcp__github__get_issue(...)のように、登録済みツールを正規化された識別子で呼べる。text()で明示した値だけがモデルのコンテキストに返り、中間結果はstore()/load()でセッション内に保持できる。ループや条件分岐、複数ツールの合成がスクリプト1本で完結し、巨大な中間出力をモデルに見せずに済む。トークン消費の観点で、JSON関数呼び出しの逐次往復とは別物の経済性になる。
この仕様はcodex-rs/code-mode/src/description.rsに、モデルへ渡されるツール説明文としてそのまま書かれている。隠し機能の挙動を知りたければプロンプトのソースを読むのが一番早い、という良い例でもある。
検索だけがスクリプトの外にいた
問題は、CodexのstandaloneなWeb検索がこの世界に入っていなかったことだ。検索はサーバ側の/v1/alpha/searchエンドポイントで実行されるが、PR #26719の説明によれば、応答はこれまでencrypted_output、つまりクライアントのスクリプトからは中身を扱えない暗号化された形式だった。エンドポイントが平文のoutputを返すようになったのを受けて、検索がtoolsオブジェクト経由でcode modeに公開された。
統合テストにはこういうコードが出てくる。
const result = await tools.web__run({
search_query: [{ q: "standalone web search" }],
});
text(result);
検索して、結果をJSで絞り込み、必要なものだけ次のツールに渡す。あるいは複数クエリを投げて重複を落としてからtext()で要約対象だけ返す。これまで検索のたびにcode modeの外へ出てモデルを1往復させていた処理が、isolate内で完結する。「調べてから動く」型のエージェントを書いている人ほど効く変更だ。
oneOf を握りつぶさなくなったスキーマ変換
もう1つ、MCP利用者に直接効くのがスキーマ処理の改善(#24118, #27084)だ。ツールやコネクタの入力スキーマに含まれるoneOf/allOfが変換時に保持されるようになり、巨大なスキーマを圧縮する際も浅い階層の構造をより多く残すようになった。
ユニオン型を多用するMCPサーバでは、これまでスキーマが平坦化されてモデルから有効な入力の形が見えなくなることがあった。code modeではモデルがスキーマを頼りにJSの呼び出しコードを書くので、型情報の欠落は呼び出し失敗に直結する。地味だが、code modeを実用に寄せるための前提整備と読むべき変更だと思う。
試すなら config.toml の [features]
機能ステージはUnderDevelopmentでデフォルト無効。features/src/lib.rsにフラグ定義がある。最新版に上げてから(npmならnpm i -g @openai/codex@latest、codex --versionで0.139.0以降を確認)、~/.codex/config.tomlに追記する。
[features]
code_mode = true
# モデルに見せるツールを exec / wait だけに絞る場合
code_mode_only = true
code_mode_onlyを有効にすると依存解決でcode_modeも自動で有効になる。実験段階なので、フラグ名も挙動も予告なく変わりうる前提で触ってほしい。検索エンドポイントが/v1/alpha/searchというパスなのも、まだ固まっていないことの示唆だろう。
最後にひとつ注意点を。検索結果が平文でV8ランタイムに入るということは、外部Webの文字列が、モデルの目を通らずにstore()され、別のツールの引数に流れ込む経路ができたということでもある。スクリプトを書くのはモデル自身なので即座に危険とは言わないが、プロンプトインジェクション対策を「モデルが全入出力を見ている」前提で組んでいる場合、その前提はcode modeでは崩れる。同じリリースでサンドボックスのproxy経由ネットワーク強制が入っている(#27035)のは偶然ではないはずで、ツール呼び出しの主導権がランタイム側に移るほど、ガードレールも実行環境側に置く必要が出てくる。エージェントの設計がオーケストレーションからコード生成へ寄っていく流れは止まらないと見ているが、セキュリティ境界の引き直しはまだ追いついていない。