OpenSource-Hub

ax

CLI ツール

google/ax

宣言的なエージェントオーケストレーションエンジンで、クラスタ内でサンドボックス化されたAIタスクを大規模に実行できます。

概要

AX は Google がオープンソース化した宣言型エージェントオーケストレーションランタイムです。Kubernetes スタイルのマニフェストでタスク、ワークスペース、ゲートウェイ、モデルを定義し、分離されたサンドボックス内で信頼できないエージェントコードを実行し、ネットワークアウトバウンドホワイトリストをサポートします。そのコマンドラインツールは kubectl を模倣しており、リアルタイムモニタリング、リモート shell、サスペンド/レジューム機能を提供します。

README プレビュー

\n  \n  AX\n\n\n> [!WARNING]\n> We are still actively refining our core concepts, protocols,\n> and specifications. We will likely to introduce major breaking\n> changes prior to a stable release.\n\n**Declare an agentic task with workspaces and gateway specifications. AX sandboxes it, wires up its workspace, fences its network, and helps running it at scale.**\n\nAX is a high-throughput, declarative orchestrator to run billions of autonomous agent workloads in a cluster. It runs on top of [Agent Substrate](https://github.com/agent-substrate/substrate) for sandboxed execution and is built to run billions of tasks per cluster. If you have used Kubernetes, `ax` will feel similar.\n\n```yaml\n# task.yaml\napiVersion: ax.io/v1alpha1\nkind: Workspace\nmetadata:\n  name: golang\nspec:\n  git:\n    - repo: https://github.com/golang/go.git\n      branch: "my-fix"\n---\napiVersion: ax.io/v1alpha1\nkind: Task\nmetadata:\n  name: test\nspec:\n  workspaces:\n    - name: golang\n      goal: "Ensure that Go tool chain is available and is built from source"\n  debug: true   # lets you `ax ssh` into the sandbox\n```\n\nThen apply it, watch it come up, and look over the agent's shoulder:\n\n```bash\nax apply -f task.yaml\nax watch task test\nax ssh test -- ls -al /workspace\n```\n\n## Why?\n\nAgents are a new kind of workload. They are neither stateless microservices nor run-to-completion batch jobs. They accumulate state, need strict isolation, call out to model APIs and tool servers, and can burn money in a loop if nobody is watching. AX gives you four small primitives that handle all of that declaratively:\n\n| You want to... | AX gives you |\n|---|---|\n| Run untrusted agent code in an isolated sandbox with CPU/memory limits | **`Task`** |\n| Pre-wire Git repos, MCP servers, and skill packages so every agent starts warm | **`Workspace`** |\n| Lock outbound traffic down to an explicit host allowlist | **`Gateway`** |\n| Configure which LLM the platform itself uses, with credentia

FAQ (5)

トラブル対応
なぜ `ax ssh <task> -- <cmd>` はリモートコマンド内の `-a`、`-n`、`--server` のようなフラグを削除したり、誤って解釈したりするのですか?

これはグローバルフラグパーサー(cmd/ax/main.go、58〜93行目)のバグです。このパーサーは -- セパレーターで解析を停止しないため、リモートコマンドから -a/--atespace、-n/--namespace、--server、--context を消費し、それらを ax 自身に適用してしまいます。症状としては、task not found in atespace ...、namespaces "50" not found、またはサイレントな失敗(例: uname -a が単なる uname として実行される)などがあります。**修正:** パーサーループにパッチを適用し、-- 以降のすべてを変更せずそのまま渡すようにします:

if arg == "--" {
	cleanArgs = append(cleanArgs, args[i:]...)
	break
} else if arg == "-a" || arg == "--atespace" {

修正済みのブランチは issue #373 からもリンクされています。**パッチ適用までの回避策:** 短いフラグが ax のフラグに一致しないように組み合わせてください(例: ls -a -l の代わりに ls -al を使用)。また、リモートコマンド内で -a、-n、--server、--context を使用しないでください。-- の*前*に配置されたフラグ(例: ax ssh mytask -a team -- ls)は引き続き正常に動作します。

参照 Issue #410
トラブル対応
`ax resume`が成功を返したのに、タスクがSuspendedのままなのはなぜですか?

これは、コミット ac23328 より前の ax バージョンにおける競合状態(race condition)です。ax apply の直後(数ミリ秒以内)に ax resume を実行すると、コントローラーの processEvent(internal/controller/worker.go 内)がタスクを読み取り、リコンサイルし、バージョンチェックなしで UpdateTaskStatus を介してステータス全体を書き戻していました。この遅れて行われた create イベントの書き込みが、ResumeTask によって設定された Running フェーズを上書きし、CLI が成功を報告したにもかかわらず、タスクが Suspended のまま動かなくなっていました。

修正: コミット ac23328 以降を含むビルドにアップグレードしてください。コントローラーの書き直しにより、Redis Streams キューがタスクごとのロック(Redis リース)下での直接実行に置き換えられ、create/resume 操作が直列化され、ロストアップデートの時間枠が排除されました。並行処理のリグレッションテストがこの不変条件を担保しています。

古いバージョンでの回避策: 自動化スクリプトで ax apply と ax resume の間に遅延を挿入し、再開後にタスクのフェーズを確認してください(例: タスクのステータスをポーリングする)。タスクがまだ Suspended の場合は ax resume を再試行してください。

注意: タスクごとのロックは、30秒の TTL を持ち、更新(renewal)のない Redis リースです。CLI のデッドライン(apply は 30秒、suspend/resume は 15秒)により、ハンドラーはその範囲内に収まりますが、ax delete task は最大2分間実行される可能性があるため、非常に遅い delete がまだロックを保持している間に resume が理論上ロックを取得する可能性があります。ただし、これによる状態の喪失は観測されていません。

参照 Issue #429
トラブル対応
ax-server をアップグレードした後、または Task に新しいフィールドを追加した後に、ax-task-runner が "unknown field" エラーで失敗するのはなぜですか?

ランナーは pkg/apis/v1alpha1/types.go で厳格な protojson.UnmarshalOptions{} を使って AX_TASK_YAML 環境変数から Task をデコードするため、ランナーのイメージより新しい Task フィールドが含まれていると unknown field "egress" のようなパースエラーが発生し、ランナーはエージェントを起動する前に終了してしまいます。修正方法(ランナー側):既存の UnmarshalYAML と同じ kind ごとのノーマライザーを実行しながら、protojson.UnmarshalOptions{DiscardUnknown: true} でデコードする UnmarshalYAMLLenient メソッドを pkg/apis/v1alpha1 に追加し、それを cmd/ax-task-runner/main.go で AX_TASK_YAML/--task-file および AX_WORKSPACES_YAML/--workspace-file の処理に使用します。既存の UnmarshalYAML は厳格なまま維持し、ax apply で適用されるマニフェストでは引き続きタイポが拒否されるようにします。さらに、ランナーが使用しないコントロールプレーン専用のフィールドは、リコンサイラー側で AX_TASK_YAML から取り除くようにし、古いランナーとの互換性も維持します。参照コミット: mastersingh24/ax@4363c253。

参照 Issue #503
トラブル対応
なぜリクエストでタスクがウェイクした後にAXがそのタスクをSuspendedと表示するのか、また、ax sshが接続を拒否する問題はどう修正すればよいですか?

AXはタスクフェーズの独自のキャッシュコピーを保持しており、AX自身がタスクをサスペンドまたはレジュームしたときにのみ更新していました。そのため、Agent Substrateルーターによってトリガーされたウェイク(またはkubectl ate suspend actorのような外部からのサスペンド)はAXからは見えませんでした。このため、アクターが実際にはACTOR_STATE_RUNNINGであったにもかかわらず、ax get taskにはワーカーアドレスなしでSuspendedと表示され、ax sshはtask "..." is in phase "Suspended" (must be Running to ssh)というエラーで失敗していました。

修正: PR #515を含むリリースにアップグレードしてください。AXはタスク状態の独自コピーを保持しなくなりました。ax-serverはax getおよびax listのたびにSubstrate/ATEコントロールAPIからアクターのライブ状態を読み取るため、誰がアクターをサスペンドまたはレジュームしたかに関わらず、フェーズとワーカーアドレスは常に実際の状態を反映します。

旧バージョンでの回避策: AX自身を通じてタスクをレジュームすることで(例: ax resume task <task-name>)、AXに強制的に状態を整合させます。その後、ax sshは再び動作するようになります。

参照 Issue #502
トラブル対応
なぜ AX SuspendTask は、Substrate アクターがまだ実行中であるにもかかわらず、フェーズ Suspended で成功を返すのですか?

これは AX のバグです(main のコミット ac2332829f22360ff97b0ba34d94dd0dd782f17e で確認)。Substrate の SuspendActor RPC が失敗した場合(例:codes.Unavailable や codes.PermissionDenied を返す場合)、Client.SuspendActor はエラーを正しく伝播しますが、TaskReconciler.Reconcile のサスペンド分岐(internal/controller/reconciler.go、~L192-L204)は 'could not suspend actor on Substrate' とログに出力するだけで、サスペンド状態を設定した後も task, nil を返してしまいます。その後、Server.SuspendTask(internal/server/server.go、~L256-L306)は phase: Suspended を永続化し、保存されている worker IP をクリアし、理由 TaskSuspended で Ready=False を設定し、gRPC 呼び出しは OK を返します。アクターが ACTOR_STATE_RUNNING のままであるにもかかわらずです。

修正方法(メンテナー/フォーク向け):reconciler にパッチを適用し、SuspendActor エラーを握りつぶすのではなく伝播させ、確認済みのライフサイクル結果のみを永続化するようにしてください。ピン留めされた Substrate 実装では繰り返しのサスペンドが冪等として扱われるため、アクターがすでにサスペンドされている場合は引き続き成功を返してください。以下のケースについてリグレッションテストを追加してください:正常なサスペンド、拒否されたサスペンド、すでにサスペンドされているアクター、および Task 作成(作成はこのリコンシリエーション分岐を共有します)。曖昧なタイムアウトやキャンセルによる失敗については、失敗した RPC がアクターがまだ実行中であることを保証しないため、永続化する前に Substrate から実際のアクター状態を再照会してください。

運用上の回避策:保存されている Task フェーズや SuspendTask レスポンスだけを信用しないでください。実行が停止したと判断する前に、Substrate に直接アクター状態を照会してサスペンドを確認してください。

参照 Issue #441