Atlas エージェント エンジン用のフレームワークに依存しないテナント ランタイム SDK。
これは内部コアパッケージです。エージェントは、それを直接インストールしません。フレームワークSDK (
agent-engine-sdk-langgraphまたはagent-engine-sdk-adk)をインストールします。これは、それに依存します。
アーキテクチャの概要
Runner SDK は、プラットフォーム アーキテクチャの AER、ツール ポッド、メモリサーバー統合コンポーネントを提供します。 Ops Manager は、Atlas Agent エンジンの別のサービスです。
コンポーネント | ポート | 信頼レベル | ネットワーク アクセス | シークレット アクセス | 目的 |
|---|---|---|---|---|---|
AER(エージェント実行ランタイム) | 8001 | 平均 | LM API のみ | LVM キーのみ | 実行プレーン -エージェントロジックを実行します |
ツール | 8002 | 変化する | 必要に応じて | 必要に応じて | データプレーン - 分離されたツール実行 |
メモリ サーバー | 8081 | 平均 | MongoDB | DB 認証 | セマンティック/エポック/タックス メモリのメモリ サービス |
::6http://[::]:port6IPV6_V6ONLY=00.0.0.06スタートアップ時にリスナーバインドを自動検出します::: (IPv6 は 2} がURL形式でこれを としてレンダリングする)、カーネルで IPv が有効になっている場合、 。構成は必要ありません。IPv ファーストのネットワーク(セル テナント名前空間)に本番環境を配置すると、自動的に が取得され、ローカルDocker取得(ブリッジ IPv が無効になることが多い)は にフォールバックします。パイプ解決されたホストはスタートアップにログに記録されるため( )、デプロイ後の検証は0.0.0.0 listener bind resolved: host=...uviron 独自のスタートアップ行を推測する必要はありません。
調査を上書きするには、環境内で APP_HOST を設定します。カーネルでは IPv6 が利用可能と報告され、かつ周囲のネットワークでは IPv4 のみがルーティングされているコンテナで必要です(例: host_ip: 127.0.0.1 によるDockerポート転送)。この理由で、統合テストで使用されるテンプレートは APP_HOST=0.0.0.0 と設定されています。
リスナーは、アクティブな RUNNER_MODE の固定のデフォルトポートを使用します(8001/8002/8081)。 RUNNER_MODE は必須であり、プラットフォーム ランタイムによって挿入されます。ローカル Develop はユーザー .env のオーバーライドを無視し、ワークスペース シークレットは名前を完全に予約します。
ロギングを開始する
イメージCMD はpython -m agent_engine_runner_shared.launcher (TypeScript:node …/launcher.js )です。ランサーは AGENT_ENTRYPOINTをインポートする前にログをインストールするため、インポート時のクラッシュやエントリポイント関数からの例外は、ワークスペースERROR STRUCTURED_LOGGING=trueINFOTenantRuntimesetup_loggingsetupLoggingログが`docs/api-gateway/README.md { として表示される未加工のトレースバックではなく、 レコード( の場合は構造化されたJSON )になります。 。 はその後も引き続き / を呼び出しますが、 2 番目のインストールは冪等である必要があります。ランサー プロセスが開始する前に発生する障害(インタープリター/イメージ エラー)は、 <:../../../../docs/api- で文書化されているAPI Gateway 読み取りパス ホスティングに依存します。ゲートウェイ/README.md#エージェント--operator-logs-s3 -read-path+gt:__.
3 つのコンポーネントを使用する理由
これにより、以下が可能になります。 -監査- OA は、実行せずにすべてのツール/ LM 呼び出しを認識します - ポリシーの適用 - OA は実行前に呼び出しをブロックできます。最小特権- 各コンポーネントは、必要なアクセス権のみを持ちます - リプレイ - OA は、確定的な再開のためにキャッシュされた結果を返すことができます。
実行ライフサイクルの長さシークレットが利用できる場所
完全な正規表現契約: `docs/runner/README.md <:../../../../docs/runner/README.md#execution-Lifesphere--secret-available+gt]`__.エージェントユーザーが正しいコードを記述するために必要なルール。
モジュールの最上位コード(関数本体の外部の任意)は、 AER と ツール ポッドの両方で、 プロセスのスタートアップ時に 1 回実行されます。 MCP OAuth 構成とテナントが提供可能なスタートアップシークレット(
MONGODB_URIや LM APIキーなど)に依存できます。スタートアップでは、呼び出しセッションおよび委任されたリクエストの認証情報は利用できません。 MCP OAuthキャッシュの書込み(~/.agentic/mcp-oauth/<server>.json、配置されたランタイムではAGENTIC_MCP_OAUTH_DIR)は助言の<server>.json.lockファイルでシリアル化されるため、同じサーバーの同時トークン更新が相互にブロッキングすることはできません。ツールアプリケーションの構築では、スタートアップ中に
@app.entrypoint関数を試行し、すべてのapp.llm(llm_id=...)登録を検出します。モデルは作成されたレジストリの再利用を要求します。構築は静的スタートアップ構成を使用するため、ビジネス ターム、モデル呼び出し、またはツール本体を実行してはなりません。構築に失敗すると警告が発せられ、以前の登録が復元されますが、後のモデルリクエストは再試行できます。名前付き LVM がない場合でも成功した構築はキャッシュされます。 AERグラフキャッシュとウォームアップはフレームワーク所有のままです。``アプリ.llm(llm,llm_id=...)`` は、エントリポイントが呼び出しスタックにあるときに呼び出す必要があります。これは、本体またはヘルパー関数の中で直接実行されます。これを外部の場所(モジュールのトップレベル、ツールボディ、エントリポイント以外の場所から呼び出されるヘルパー)から呼び出すと、
RuntimeErrorが直ちに発生し、問題の呼び出しサイトに名前を付けます。ローカル ツール ボディ(
is_local=True)は、AER の自分のプロセスでのみ実行されます。 AER ワークロードとツール ワークロードの両方は、スタートアップ時にテナント提供可能なシークレットを受け取ります。リモート ツール ボディ( 、または委任された認証情報を必要とするツール)は、OA が呼び出しをルーティングする場合にのみツール ポッドでオンデマンドで実行されます(構築中は存在しません)。
is_local=Falserequired_secretsはドキュメントシークレット要件を宣言します。スタートアップシークレット環境を絞り込みません。SDK がローカルのデフォルトを提供していても、認証済みツールはリモートのままになります。これは、委任された認可とツールスコープのシークレットインジェクションは Tools ポッド ルートでのみ発生するためです。
実行フロー
通常の実行(開始 → 完了)
┌────────┐ ┌─────┐ ┌─────┐ │ Client │ │ OE │ │ AER │ └───┬────┘ └──┬──┘ └──┬──┘ │ │ │ │ POST /invoke │ │ │ ──────────────────────────►│ │ │ │ │ │ │ Create Execution (PENDING) │ │ │ │ │ POST /execute │ │ │─────────────────────────►│ │ │ │ │ │ │ Build LangGraph │ │ │ Start ainvoke() │ │ │ │ ┌───────────────────────┼──────────────────────────┼───────────────┐ │ │ LOOP: For each tool/LLM call │ │ │ │ │ │ │ │ │ │ POST /tool/execute │ │ │ │ │◄─────────────────────────│ │ │ │ │ {tool, args, step} │ │ │ │ │ │ │ │ │ │ Log + Policy Check │ │ │ │ │ │ │ │ │ │ {proceed, route_to} │ │ │ │ │─────────────────────────►│ │ │ │ │ │ │ │ │ │ │ Execute tool │ │ │ │ │ │ │ │ │ POST /tool/result │ │ │ │ │◄─────────────────────────│ │ │ │ │ {result, status} │ │ │ └───────────────────────┼──────────────────────────┼───────────────┘ │ │ │ │ │ │ Graph completes │ │ │ │ │ POST /executor/callback │ │ │◄─────────────────────────│ │ │ {COMPLETED, result} │ │ │ │ │ GET /execution/{id} │ │ │ ──────────────────────────►│ │ │ │ │ │ {status: completed, result}│ │ │ ◄──────────────────────────│ │ │ │ │
ループ内の人間(SUSPEND/RESUME)
┌────────┐ ┌─────┐ ┌─────┐ │ Client │ │ OE │ │ AER │ └───┬────┘ └──┬──┘ └──┬──┘ │ │ │ │ POST /invoke │ │ │ ──────────────────────────►│ │ │ │ │ │ │ POST /execute │ │ │─────────────────────────►│ │ │ │ │ │ ... tool calls ... │ │ │ │ │ │ │ app.suspend(reason) │ │ │ → tool pod reports │ │ │ status: "suspend" │ │ │ (out-of-band, not │ │ │ result content) │ │ │ │ │ │ interrupt() on the │ │ │ OE-confirmed status │ │ │ Save checkpoint │ │ │ │ │ POST /executor/callback │ │ │◄─────────────────────────│ │ │ {SUSPENDED, metadata} │ │ │ │ │ GET /execution/{id} │ │ │ ──────────────────────────►│ │ │ {status: suspended} │ │ │ ◄──────────────────────────│ │ │ │ │ ╠════════════════════════════╬══════════════════════════╣ ║ ⏸️ WAITING FOR HUMAN - Reviews and Approves ║ ╠════════════════════════════╬══════════════════════════╣ │ │ │ │ POST /resume/{id} │ │ │ {decision: "approved"} │ │ │ ──────────────────────────►│ │ │ │ │ │ │ Store human decision │ │ │ │ │ │ POST /execute │ │ │ {resume: true} │ │ │─────────────────────────►│ │ │ │ │ │ │ Resume from checkpoint │ │ │ │ ┌───────────────────────┼──────────────────────────┼───────────────┐ │ │ Replayed steps return CACHED results │ │ │ │ │ │ │ │ │ │ POST /tool/execute │ │ │ │ │◄─────────────────────────│ │ │ │ │ │ │ │ │ │ {cached_result} │ │ │ │ │─────────────────────────►│ │ │ └───────────────────────┼──────────────────────────┼───────────────┘ │ │ │ │ │ │ Continue execution │ │ │ (new steps) │ │ │ │ │ POST /executor/callback │ │ │◄─────────────────────────│ │ │ {COMPLETED, result} │ │ │ │ │ GET /execution/{id} │ │ │ ──────────────────────────►│ │ │ {status: completed} │ │ │ ◄──────────────────────────│ │ │ │ │
注意
API Gateway 経由で再開: 上の図では、簡潔にするために UE の内部/resume/{id}POST /api/v1/projects/{project_id}/executions/{execution_id}/resume パスを使用しています。開発者は、平面JSONボディを使用して のAPI Gateway を呼び出します。
{"decision": "approved", "reviewer_notes": "optional context"}
ラップされた{"human_review": {"decision": "..."}}シェイプは OA の内部エンドポイント契約であり、ゲートウェイはHTTP 400 で拒否します。
実行ドキュメント(キャンセル)
UE が実行を永続的にキャンセルする場合、それを所有するツールまたは AER ランタイムに /drain を POST します。受信者契約(client-libraries/test-fixtures/drain/contract.json の共有フィックスによって固定されている)
POST /drain {request_id, execution_id, reason, deadline_at_ms, workspace_id}ワークスペースをスコープとするランタイム(APP_IDセット、つまり、すべての管理対象ランタイム)では、workspace_idは必須であり、完全に一致する必要があります。Bearer トークンは呼び出し元を認証しますが、名前付き実行がこのランタイムに属していることを証明しません。202 {"outcome": "accepted"}ドレイン中。200と最終結果(completed/timed_out/delivery_failed)の後にacceptedはHTTPレベルのみを受け入れるため、completedは 唯一の 休止シグナルです。request_idの冪等、実行ごとに 1 つのドレイン。再試行は、サイド影響を再実行するのではなく、記録された結果を再読み取ります。deadline_at_msは絶対であり、拡張されない。ランタイムがRUNNER_DRAIN_MAX_DEADLINE_MSを超える期限を拒否するようになりました(デフォルトは60s)。確定されたレコードはRUNNER_DRAIN_RECORD_TTL_S(デフォルトでは900s)に耐えられるため、呼び出し元の再試行は調整ウィンドウを通じて冪等性が維持されます - 呼び出し元の再試行ウィンドウよりもそれ以上に維持されます(OE は 15 分間ドレインを再試行します)。TTL が短いとレコードはレコードされます。呼び出し元がまだ再試行している間に行われ、その後の再送信では、記録された結果の代わりにexecution_not_foundが返されます。このランタイムでは、
reason_code=execution_not_foundを使用してdelivery_failedの応答が提供されることはありません。1 回の実行では AER 実行時間と ツール 実行時間に個別にまたがることができるため、正確な OA を用いたターゲットによって誤ったcompletedが安全になることはありません。
言語ごとの制限は、実装の詳細ではなく、契約の一部です。 Python は追跡されている非同期タスクをキャンセルするため、連携作業は completed として解決されます。 Promise はキャンセルされないため、TypeScript ランタイム(agent-engine-runner-shared はこの契約をミラーリングし、それとともに変更する必要がある)は登録された AbortController のみ( AER オンと LM ストリーム)を中止しますが、プレーン ツール関数は シグナルを受け取りません。は追跡されて認証ブロックされ、期限を過ぎた場合は正の timed_out です。状態は設計的にプロセスローカルです。再起動されたランタイムはアクティブな作業を失い、delivery_failed と応答します。再起動後の調整は、このレジストリではなく、呼び出し元の 永続的レコードに属します。
呼び出しごとの割り込み
POST /interrupt/call は、ドレインの組織的な識別です。OE の呼び出しごとの割り込み名は {execution_id, step_number} によって 1 回呼び出しが行われ、ランタイムはその呼び出しの追跡処理を完全に中止します。Pythonはasyncioタスク をキャンセルし、TS ランタイムは呼び出しの AbortController を中止します。は開いたままですが、その後の呼び出しは続行されます(許可ラッチはありません)。常に 200 を使用し次の結果が得られます。interrupted(署名付き、または接続時に起動するように記録)、not_found(移動中の呼び出しはなし)、already_settled(呼び出しが最初に終了した)、not_cancellable(追跡作業シグナル チャンネルなし - スレッド上の同期ツール本体、プレーン TS ツール関数 - が正確に報告され、破棄されたことはありません)。ワークスペースのスコープはドレイン ルートの と一致し、共有ベクトルは client-libraries/test-fixtures/interrupt-call/contract.json に存在します。
キー コンポーネント
クエリが OA を介してルーティングされる方法
インターコムのツール呼び出しと invoke_llm は、同じ OA 所有の実行フローを使用するようになりました。 AER で実行中エージェントがツールまたは LM を呼び出す必要がある場合、ラッパーは中断されたリクエストを OA に送信し、OA が最終結果を返すのを待機します。 UE はツール呼び出しを Tool Pod /execute を通じてルーティングし、LM 呼び出しを Tool Pod /invoke_llm を通じてルーティングした後、最終的な成功、一時停止、またはエラーの結果を AER に返します。
シーケンス図:
┌─────┐ ┌─────┐ ┌──────────┐ │ AER │ │ OE │ │ Tool Pod │ └──┬──┘ └──┬──┘ └────┬─────┘ │ │ │ │ 1. POST /tool/execute │ │ │ ────────────────────────►│ │ │ {name or invoke_llm, │ │ │ args/messages, step} │ │ │ │ │ │ │ Log + Policy Check │ │ │ │ │ │ 2a. Replay cache hit │ │ 2a. Final cached result │ │ │ ◄────────────────────────│ │ │ {status, result, │ │ │ from_cache} │ │ │ │ │ ├──────────────────────────┼────────────────────────────┤ │ if OE must execute the tool │ │ │ │ │ │ 2b. POST /execute or │ │ │ /invoke_llm │ │ │ ───────────────────────────────────────► │ │ via Tool Pod │ │ │ ◄─────────────────────────────────────── │ │ {status, result} │ │ │ │ ├──────────────────────────┼────────────────────────────┤ │ │ │ │ 3. Final OE-owned result │ │ │ ◄────────────────────────│ │ │ {status, result, error, │ │ │ duration_ms, pod_name} │ │ │ │ │
重要な点:
すべてのインタラクティブ ツールまたは LM 呼び出しは、ポリシー、ロギング、およびリプレイ所有権のために最初に OA を横断します。
UE はルーティングを所有しており、リモート
Tool Pod /executeツールは を使用しています。承認されたローカル ツールは元の AER 呼び出しスタックに戻り、フレームワークネイティブのコンテキストは有効のままになります。 LM 呼び出しを中断したインスタンスではTool Pod /invoke_llmが使用されます。プレイではキャッシュされた結果が使用されます。SUSPEND 後の再開では、重複するサイド 影響を防ぐために、UE は保存された最終結果を返します。
一時停止は引き続きラッパーを通じて展開されます。 UE はシリアル化された一時停止ペイロードを返し、
SecureToolWrapperはそれをフレームワーク割り込みに変換します。``invoice_llm``
status/result/errorがツール契約と一致するようになりました。承認後に AER に実行を許可する代わりに、UE は最終的な ペイロードを返します。LVM ストリーム チャンクは最終メッセージメタデータを保持します。
id、name、additional_kwargs、response_metadataは型指定されたストリームイベントを通過し、リプレイ用と同じ最終応答シェイプに収集されます。
agent.yaml 環境変数の補間
ランタイム構成の読み込みで、テナント所有の agent.yaml パスの数少ない許可リストの ${VAR} 補間がサポートされるようになりました(現在は mcp.servers.*.url)。
仕組み:
load_runtime_agent_config(env_vars=...)は許可リストされたパスでのみ${VAR}参照を置き換えます。ランタイムは未加工の
os.environではなくtenant_env_vars()を渡すため、プラットフォームが所有する env 変数とシークレットは置換から除外されます。許可リストされたパスが設定されていない変数を参照している場合、または不正な
${...}マークが含まれている場合、ローダーは明確な検証エラーを発生させます。mcp.servers.*.auth.token_envは、プラットフォームが所有する環境変数を点はなりません。
例:
mcp: servers: tableau: url: https://${TABLEAU_HOST}/mcp
実行時に、${TABLEAU_HOST} はテナント所有の環境サブセットから解決されます。 ${OPENAI_API_KEY} などの参照は拒否されます。この変数はプラットフォームに所有され、補間前にフィルタリングされるためです。
SecureToolW wrapper(secure_wrapper.py )
ツール呼び出しを中断する中央セキュリティ コンポーネントは、次の呼び出しを行います。
# Every tool call goes through this flow: def execute_tool(tool_name, arguments): # 1. Send the intercepted tool call to OE response = request_oe_approval(oe_url, execution_id, tool_name, arguments) # 2. Check for policy denial if not response.proceed: raise PolicyDeniedException(response.reason) # 3. OE either returns a final outcome or routes the call back in process if response.route_to == "callback": result = local_executor() report_oe_result(result) return result if response.status == "error": raise ToolExecutionError(response.error) if response.status == "suspend": interrupt(response.result) return response.result
不変: ツールまたは LM 呼び出しは、OE がその詳細を認識していない限り実行されません。
主な機能
ポリシーの強制
UE は、ポリシー ルールに基づいてツール/ LM 呼び出しをブロックできます。
ポリシーの適用はGo OA によって処理されます。詳しくは、 docs/orchestration-engine/README.md を参照してください。
リプレイ キャッシュ
SSPEND 後にエージェントが再開すると、LingGraph の実行は最初から再生されます。キャッシュを使用しない場合、これによりツールと LM 呼び出しが再実行され、サイド効果が重複します(例: 通知が 2 回送信されるなど)。
仕組み:
UE はすべてのステップを追跡します。すべてのツール/TLM 呼び出しは、ステップ番号、名前、および結果でログに記録されます。
再開時に、エージェントはリプレイ - LagGraph が最初から再実行され、同じ呼び出しが順番に実行されます
UE はキャッシュされた結果を返します - 再実行の代わりに、UE は保存された結果を返します
Original Execution: Step 1: lookup_policy("POL-123") → executed, result stored Step 2: query_mongogpt(...) → executed, result stored Step 3: human_review(...) → SUSPEND (waiting for human) Resume Execution: Step 1: lookup_policy("POL-123") → CACHED (returns stored result) Step 2: query_mongogpt(...) → CACHED (returns stored result) Step 3: human_review(...) → CACHED (returns human's decision) Step 4: send_notification(...) → executed (new step)
リプレイ キャッシュはGo UE によって処理されます。 AER/SecureToolW wrapper は、キャッシュされた応答を透過的に処理します。
AER/SecureToolW wrapper の処理:
# In secure_wrapper.py - OE already returns the final replay outcome response = await request_oe_approval(...) if response.from_cache: log_cached_result(tool_name, step) return response.result
これにより確定的な再開が保証されます。エージェントには一時停止前と同じ結果が表示されるため、重複するサイド効果を防ぐことができます。
チェックポイント
インメモリ チェックポイントとMongoDBチェックポイントの両方をサポートします。
# In runtime.py def get_checkpointer(self): if mongodb_uri: return MongoDBSaver(client, db_name) return MemorySaver() # Development only
ファイル構造
src/agent_engine_runner_shared/ ├── runtime.py # TenantRuntime - main SDK entry point ├── secure_wrapper.py # SecureToolWrapper, SecureWrappedLLM ├── models.py # Pydantic models for all API contracts ├── context.py # Per-execution context (contextvars) ├── metrics.py # Metrics collection and @with_metrics decorator ├── utils.py # Logging utilities, env helpers ├── logging.py # Durable execution logging (JSONL + MongoDB) ├── memory.py # MemoryEngine integration, MemoryWriter ├── voyage.py # VoyageService for embeddings ├── events.py # SSE event streaming, observability ├── types.py # Protocol definitions (MemoryEngineProtocol) ├── tracing/ # OpenTelemetry tracing │ ├── setup.py # setup_tracing(), get_current_trace_context() │ └── exporters.py # JSONLSpanExporter, MongoDBSpanExporter └── server/ ├── base.py # BaseServer abstract class ├── aer.py # AER implementation ├── tool.py # Tool Pod implementation └── memory.py # Memory Server implementation
設計上の決定
すべてのものが OA 経由でルーティングされる理由
レイテンシは追加されますが、UE1 を介したルーティングでは 23が提供されます。完全な監査するログ - すべての呼び出しがログに記録されます 。ポリシー適用点- 呼び出しをブロックする単一の場所。リプレイ機能 - UE は再開 のキャッシュされた結果を返すことができます。フレームワークに依存しないフレームワーク4 - UE は LgGraph のことを認識していない
AER と ツールを分ける理由
AER は LVM APIアクセスが必要ですが、データベース認証情報が必要ではありません
ツールにはデータベースアクセスが必要になる可能性がありますが、LM キーは不要です
異なるツールは、異なる権限を持つ異なるツールで実行可能
エージェント実行時間との機能の同等性
Runner SDK が単調な agent-runtime との同等の機能を提供するようになりました。
機能 | エージェントランタイム | Runner SDK |
|---|---|---|
@ アプリ.tool 修飾子 | ✅ | ✅ |
明示的なネットワーク/タイムアウトメタデータ | ✅ | ✅ |
フィールドリダクション | ✅ | ✅ |
MongoDBチェックポイント | ✅ | ✅ |
実行ログ(JSONL + MongoDB) | ✅ | ✅ |
OpenTelemetry トレース | ✅ | ✅ |
メモリ統合 | ✅ | ✅ |
投票AI埋め込み | ✅ | ✅ |
マルチテナント(org_id/user_id) | ✅ | ✅ |
SSE イベント ストリーミング | ✅ | ✅ |
gRPC サーバー | ✅ | ✅ |
ストリーミング サポート | ✅ | ✅ |
ループ内の人間 | ❌ | ✅ |
3 コンポーネント アーキテクチャ | ❌ | ✅ |
リプレイ キャッシュ | ❌ | ✅ |
オプションの依存関係
必要に応じて機能をインストールします。プロジェクトが rv で管理されている場合は uv add を使用し、それ以外の場合は pip install を使用します。
# uv projects uv add agent-engine-runner-shared uv add "agent-engine-runner-shared[mongodb,tracing]" uv add "agent-engine-runner-shared[tracing]" uv add "agent-engine-runner-shared[mongodb]" # pip pip install agent-engine-runner-shared pip install "agent-engine-runner-shared[mongodb,tracing]" pip install "agent-engine-runner-shared[tracing]" pip install "agent-engine-runner-shared[mongodb]"