組み込みの antigravity プロバイダーは、daily-cloudcode-pa.googleapis.com において HTTP 経由で
Google の Antigravity バックエンドに到達します。このホストは Antigravity クライアント自身が
ディスカバリーと推論の両方に使う daily- コントロールプレーンです。gemini プロバイダーと同じ Code Assist プロトコルを話し —
shunt は Anthropic Messages を generateContent / streamGenerateContent へ変換します — ただし
Antigravity のサブスクリプショントークンで認証し、プロジェクトディスカバリーの際に自身を
ideType: ANTIGRAVITY として名乗ります。
Antigravity には、もう 1 つ古い転送があります。kind = "antigravity_cli" はローカルの agy バイナリを
サブプロセスとして実行するもので、非推奨です —
非推奨の antigravity-cli 転送を参照してください。
このページは HTTP プロバイダーを扱い、そうした仕組みは一切必要としません。
クイックスタート
コーディングエージェントにセットアップを任せることもできます — shunt add は組み込みのセットアップ
ブループリントを出力します(オフラインかつ読み取り専用で、設定を編集するのはエージェントです。この
コマンド自体は編集しません)。
shunt add upstream antigravity --print | claudeまたは、以下の手順に沿って手動で設定してください。
1. ログイン
shunt login antigravityこれは Antigravity 自身の OAuth クライアントを使う Google の authorization-code フローを実行し、shunt が
読み込んで自動リフレッシュする ~/.shunt/antigravity-auth.json を書き込みます。このフローは 5 つのスコープを
要求します。
https://www.googleapis.com/auth/cloud-platform
https://www.googleapis.com/auth/userinfo.email
https://www.googleapis.com/auth/userinfo.profile
https://www.googleapis.com/auth/cclog
https://www.googleapis.com/auth/experimentsandconfigs後ろの 2 つが、Gemini CLI のログインをここで流用できず、その逆もできない理由です。
~/.gemini/oauth_creds.json のトークンが cclog や experimentsandconfigs を持つことは決してありません。
google_oauth と antigravity_oauth は互換ではありません。
ログイン時には Code Assist プロジェクトも解決し — まず loadCodeAssist、次に初めてのアカウントには
onboardUser でプロビジョニングします — プロジェクト id を認証情報ファイルに保存します。最初のリクエストの
手前でディスカバリーが走ることはありません。ディスカバリーが失敗した場合でも、ログインはトークンを保存し、
最初のリクエストで再試行します。
2. upstream を設定する
このプロバイダーは組み込みなので、provider = "antigravity" を指定した [[routes]] エントリは、自前の
プロバイダーテーブルなしで機能します。順序付き upstream として宣言する場合は事情が異なります。
Antigravity の種別には [[upstreams]] プリセットがないため、そこでは provider = "antigravity" を使えず、
kind、base_url、auth を自分で設定する必要があります。
[[upstreams]]
name = "anthropic"
provider = "anthropic" # ルーティングされないモデル(例 claude-*)のデフォルトとして Anthropic を残す
[[upstreams]]
name = "antigravity"
kind = "antigravity"
base_url = "https://daily-cloudcode-pa.googleapis.com"
auth = "antigravity_oauth"順序付きの [[upstreams]] は shunt の組み込みプロバイダーを置き換えるため、明示的な設定ではフォールバック先の
anthropic デフォルトも宣言する必要があります(server.default_provider のデフォルトは anthropic)。
従来の [providers.antigravity] テーブル形式も引き続きサポートされます — ただし [[upstreams]] と
[providers.*] を 1 つのファイルで混在させないでください。
3. モデルをルーティングする
shunt はこのプロバイダーについてモデルの許可リストを持ちません。解決された upstream_model はそのまま
バックエンドへ送られ、判断はバックエンドが行います。Antigravity は Code Assist の gemini プロバイダーが
受け付けない Gemini ファミリーのスラッグを提供します — ただし effort を id に含めて、2 つの形の
どちらかで公開します。-low / -medium / -high のサフィックス(Pro には -low と -high しか
ありません)か、effort をリクエストのフィールドとして受け取る単一の -tiered id です。どちらの形が
提供されるかはアカウントごとに異なり、時間とともに変わります — あるアカウントには
gemini-3.8-flash-tiered が、別のアカウントには gemini-3.8-flash-medium が提供されます。
現在のカタログは agy models で一覧できます。本稿の執筆時点では gemini-3.8-flash-*、
gemini-3.7-flash-*、gemini-3.6-flash-*、gemini-3.1-pro-low / -high、claude-sonnet-4-6、
claude-opus-4-6-thinking、gpt-oss-120b-medium が含まれます。
サフィックスのないスラッグは提供されません。daily-cloudcode-pa.googleapis.com は 404 を返します。
本番ホストでは、以前の shunt のリクエスト — サフィックスのない id と素の Code Assist エンベロープ — が
レート制限のように見える 429 RESOURCE_EXHAUSTED(“check quota”)で返ってきました。ただしプローブは
両方の入力を同時に変えているため、そのどちらが 429 を生んだのかは確認できていません。
どちらの形かを推測しなくて済むよう、shunt はリクエストの経路でアカウント自身のカタログ
(fetchAvailableModels)を読み — アカウントごとに 10 分キャッシュ、時間制限つき、失敗時はそのまま
続行 — そのアカウントが実際に公開している id を選びます。
ローカルのエイリアスを、正確な Antigravity のモデルスラッグへマッピングします:
[[models]]
id = "claude-gemini-3.6-flash-via-antigravity"
display_name = "[AGY ] Gemini-3.6-Flash"
[[routes]]
model = "claude-gemini-3.6-flash-via-antigravity"
provider = "antigravity"
upstream_model = "gemini-3.6-flash-medium"サフィックスを自分で書く必要はありません。サフィックスのない gemini-* の id については、shunt が
ティアを解決して付与します。最初に当てはまったシグナルが使われます:
[[routes]]エントリまたはプロバイダーのeffort— 明示的な指定です。ここでもxhighとmaxはhighに畳まれ、大文字小文字と前後の空白は無視されます。shunt が知らないティアは書かれたまま (空白を取り除き小文字にして)通るので、カタログに後から追加されるティアを先に指定できます。- リクエストの
output_config.effort(Claude Code はlow/medium/high/xhigh/maxを送り、xhighとmaxはhighに畳まれます)。 thinking.type = "enabled"—budget_tokensが 2048 以下ならlow、8192 以下ならmedium、 それより大きい場合はhighです。budget を指定しない有効なブロックは、変換後のリクエストが載せる のと同じデフォルトの1024を使うため、lowになります。- それ以外は
mediumです。
そのティアが何になるかはカタログが決めます。アカウントが {id}-{ティア} を公開していればそれが送られ
ます。{id}-tiered だけを公開している場合、shunt は tiered の id を送り、ティアは
generationConfig.thinkingConfig.thinkingLevel に載せます(バックエンドは両方同時に受け付けるので、
既存の thinkingBudget はそのままです)。どちらもなく、同じモデルの別のティアが公開されている場合は、
最も近い公開ティアが選ばれ、同点なら上のティアになります — -pro の id での medium が -high に
なるのは Pro 専用の規則ではなく、この規則によるものです。
手で書いたサフィックスも同じ扱いです。アカウントが gemini-3.6-flash-medium をもう公開していない
場合、そのサフィックスはどのティアを望んだかをまだ示しているので、shunt はカタログが 404 だと確認した
ばかりの id をそのまま送らず、上のルールで解決し直します。カタログがそのファミリーを何も知らなければ、
書いた値はそのまま残ります。自分で指定した -tiered の id は id を保ったまま effort を
thinkingLevel として運び続けるので、実際に公開されている id を書いても effort の制御は失われません。
アカウントが後でサフィックス付きの id に戻った場合も、その指定は同じ規則で解決し直されます。id が
消えたと言えるのはたった今取得したカタログだけなので、更新に失敗して最後に知っていたカタログで動いて
いる間は、すべての指定が書いたとおりに送られます。
カタログが使えない場合(ディスカバリー障害、fetchAvailableModels に答えないバックエンド)は、Pro の
丸めを含む -{ティア} の付与 — 0.40.0 の挙動 — にフォールバックするので、参照の失敗で失うのは
推測であってリクエストではありません。失敗した参照は 1 分間記憶してから再試行するため、到達できない
コントロールプレーンのコストはメッセージごとではなく 1 分あたり 1 回に抑えられ、参照自体も Gemini の id
に対してのみ行われます。設定に書かれた認識できない effort は、カタログがないときはルール 1 のとおり
書かれたまま付与され、丸められません。カタログがあるときは、そのティアが提供されていないとアカウントが
たった今示したことになるので、公開されているティアへ畳まれます。-tiered の経路では、バックエンドが
知らない thinkingLevel を拒否するため medium に畳まれます。カタログがそのまま公開している id、
そして Gemini 以外の id(claude-sonnet-4-6、gpt-oss-120b-medium)は書かれたまま送られます。
認識できない output_config.effort は、モデル id に反映されずに medium へフォールバックします。
thinking を明示的に無効にしたリクエスト(thinking.type = "disabled")に thinkingLevel が付くことは
ありません。変換された thinkingBudget: 0 がそのまま残ります。
Antigravity は Claude モデルも提供していますが、shunt はそれらが必要とするリクエストの書き換えをまだ実装して いません(#368)。そうしたスラッグをローカルで拒否するものは 何もなく — 書かれたままバックエンドへ到達します — そのため当面は Gemini ファミリーのスラッグだけを ルーティングしてください。
アダプターが伝えるもの
アダプターはアシスタントのテキストとthinking を Anthropic SSE としてストリーミングし、クライアントの
ツールをネイティブにブリッジします: tool_use は Gemini の functionCall になり、あなたの tool_result は
functionResponse になり、ツール宣言とツール選択もあわせて変換されます。システムプロンプトは
systemInstruction になります。トークン使用量は Google が報告する値です — promptTokenCount と
candidatesTokenCount が input_tokens と output_tokens に対応します。
Thinking はリクエストに従います: thinking.type = "enabled" は budget_tokens(デフォルト 1024)から
thinkingConfig.thinkingBudget を設定し、"disabled" はそれを 0 にします。有効な thinking ブロックは、
上のモデルをルーティングするで説明したとおり、モデルの effort ティアを決めるシグナルの 1 つでもあります。
さらにすべてのリクエストは、Antigravity クライアントが送るエージェント識別情報を伴います:
userAgent: "antigravity"、requestType: "agent"、リクエストごとの requestId、そして続きのターンが
同じセッションに届くよう会話中で最初に現れるユーザーテキストから導出した sessionId です。gemini プロバイダーの
Code Assist リクエストは、これらをいずれも送りません。
ツールスキーマは Gemini の Schema 方言に合わせて調整されます — このプロバイダーでも、同じアダプターを共有する
gemini プロバイダーでも同様です。 $schema、$id、$comment、
propertyNames、patternProperties、exclusiveMinimum、exclusiveMaximum、const は削除され、それ以外の
キーワードは書かれたとおりに転送されます。type のリストは最初の非 null 項目を保ち、リストに null があれば
nullable: true が設定され、null だけのリストは nullable な string になります。配列でない
スキーマ — 別のメンバーに決まったユニオンでも、単なるスカラーでも — は prefixItems とスキーマオブジェクトでない items を捨て、
オブジェクト値の items はそのまま保ちます。型のないスキーマは、prefixItems か配列値またはオブジェクト値の items を
持てば配列として扱われ、そうでなければ単独の boolean の items だけを捨てます。すべての配列は単一の items
スキーマで送られます: タプル — prefixItems、または draft-07 の配列値 items — は 1 つに畳み込まれ、同一の
位置はそのスキーマを保ち、配列以外の型だけが一致する位置はその型を保ち、それ以外は先頭の位置のスキーマが
残ります。prefixItems の隣に型を宣言した items スキーマがすでにある場合は、そのスキーマがそのまま保たれ、
位置は捨てられます。型が anyOf/oneOf/allOf の分岐にある要素も同じ方法で畳み込まれます。要素について何も述べない
配列や、要素スキーマが型を宣言しない配列は、要素が enum や properties で型を暗示しない限り
items: {"type": "string"} として送られます。これらのフォールバックはリクエストを拒否する代わりに要素の型を
狭めるので、タプルが string 型で届くツールはルーティングの誤りではなく、この調整が働いた結果です。
本番トラフィックをルーティングする前に知っておく価値のある制限が 2 つあります。
- 画像はインラインである必要があります。 base64 の
imageブロックは Gemini のinlineDataになります。 URL の画像ソースは400で拒否されます(URL image sources are not supported by the Gemini adapter)。 - ツール結果はリッチメディアを運べません。
imageやdocumentブロックを含む内容のtool_resultは 拒否されます。
検証
shunt check # -> config ok
shunt run
curl -sS http://127.0.0.1:3001/v1/messages \
-H 'anthropic-version: 2023-06-01' \
-H 'content-type: application/json' \
-d '{"model":"claude-gemini-3.6-flash-via-antigravity","max_tokens":16,"messages":[{"role":"user","content":"Reply with OK."}]}'レスポンスの x-gateway-upstream ヘッダーが antigravity を示すことを確認したら、
Claude Code を shunt へ向けてください。