> ## Documentation Index
> Fetch the complete documentation index at: https://docs.qoder.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Cloud Agent（experimental）

`query()` はデフォルトでバンドル済みの qodercli をローカルで起動します。`options.experimentalCloudAgent` を渡すと SDK は Qoder Cloud Agent ランタイムに切り替わります — agent と session は Qoder Cloud のコンテナ内で実行され、ローカルプロセスはリクエスト送信と SSE イベントストリームの消費だけを担当します。

> **ステータス**：experimental / unstable。API 形状はマイナーバージョン間で変化する可能性があります。安定化されていないフィールドを本番のコードパスで依存しないでください。

<div id="使うべきタイミング" />

## 使うべきタイミング

* qodercli、バンドル済みバイナリ、ローカルランタイムを管理したくない
* 同じ agent インスタンスをマシン間で長期間再利用したい（agent は Cloud に永続化される）
* session のコンテキストを Cloud に置いて、複数のプロセス / ホストから再開したい

ローカル CLI 専用の機能 — `mcpServers` / `settings` / `hooks` / `plugins` / ローカル permissions / checkpoint — は Cloud ランタイムでは**サポートされません**。これらを渡すと同期的にエラーが投げられます。

<div id="前提条件" />

## 前提条件

* **Personal Access Token (PAT)**：[qoder.com/account/integrations](https://qoder.com/account/integrations) で生成。詳細は [SDK 認証](/ja/cli/sdk/authentication) を参照。Cloud ランタイムは `accessToken()` / `accessTokenFromEnv()` のみを受け付けます。`qodercliAuth()` / `jobToken()` を渡すと同期的にエラーになります。
* **Cloud `environment_id`**：session 作成時に必須。Qoder コンソールまたは管理 API から取得します。

```bash theme={null}
export QODER_PERSONAL_ACCESS_TOKEN="<your-pat>"
export QODER_CLOUD_AGENT_ENVIRONMENT_ID="<your-env-id>"
```

<div id="初回呼び出しagent-作成-session-作成" />

## 初回呼び出し：agent 作成 + session 作成

最も一般的なエントリパス — 新しい Cloud Agent を作成し、すぐにその session を開いて prompt を実行します：

```typescript theme={null}
import { accessTokenFromEnv, query } from '@qoder-ai/qoder-agent-sdk';

const q = query({
  prompt: 'Summarize this repository in one short paragraph.',
  options: {
    auth: accessTokenFromEnv(),
    experimentalCloudAgent: {
      agent: {
        create: {
          name: 'my-cloud-agent',
          model: 'ultimate',
          system: 'You are a concise code assistant.',
          tools: [
            {
              type: 'agent_toolset_20260401',
              enabled_tools: ['read', 'glob', 'grep'],
            },
          ],
        },
      },
      session: {
        create: {
          environment_id: process.env.QODER_CLOUD_AGENT_ENVIRONMENT_ID!,
          title: 'first-cloud-session',
        },
      },
    },
  },
});

for await (const msg of q) {
  if (msg.type === 'result') {
    console.log('done:', msg.subtype, msg.result);
  }
}
```

ターン終了時、最後の `result` メッセージから `session_id` を取得します — 後続のターンでこれを使って同じ session を再開します（[マルチターン：session の再開](#マルチターンsession-の再開) を参照）。

<div id="ビルトインツールの許可リスト" />

### ビルトインツールの許可リスト

`tools[].enabled_tools` で現在サポートされているもの：`bash`、`write`、`glob`、`web_fetch`、`read`、`edit`、`grep`、`web_search`。`tools` を省略すると agent はツールを持ちません。

<div id="session-へのファイルマウント" />

### session へのファイルマウント

Files API でアップロードしたファイルを `session.create.resources` で session コンテナにマウントできます：

```typescript theme={null}
session: {
  create: {
    environment_id,
    resources: [
      { type: 'file', file_id: 'file_abc123', path: '/workspace/data.json' },
    ],
  },
}
```

<div id="既存-agent-の再利用" />

## 既存 agent の再利用

すでに `agent.id` がある場合（コンソール経由または前回の呼び出しで取得）、`agent: { id }` を渡し `create` は省略します：

```typescript theme={null}
experimentalCloudAgent: {
  agent: { id: 'agent_xxx' },
  session: { create: { environment_id } },
}
```

<div id="マルチターンsession-の再開" />

## マルチターン：session の再開

初回ターンから `session_id` を得たら、次の呼び出しは **`session: { id }` のみ** を渡します — `agent` は含めないでください。session は既に agent を束縛しており、両方を渡すと同期的にエラーになります。

```typescript theme={null}
// Turn 1: create agent + session
const first = query({
  prompt: 'My favorite color is teal. Reply with: noted.',
  options: {
    auth: accessTokenFromEnv(),
    experimentalCloudAgent: {
      agent: { create: { name: 'demo', model: 'ultimate' } },
      session: { create: { environment_id } },
    },
  },
});

let sessionId: string | undefined;
for await (const msg of first) {
  if (msg.type === 'result') sessionId = msg.session_id;
}

// Turn 2: continue the same Cloud session
const second = query({
  prompt: 'What is my favorite color?',
  options: {
    auth: accessTokenFromEnv(),
    experimentalCloudAgent: {
      session: { id: sessionId! },
    },
  },
});

for await (const msg of second) {
  if (msg.type === 'result') console.log(msg.result);  // → "teal"
}
```

session のコンテキストは Cloud 側に保存されるため、ターン間でスクリプトを再起動したりマシンを変えたりしても、`session_id` さえあれば再開できます。

<div id="sse-イベントの消費" />

## SSE イベントの消費

Cloud ランタイムは SSE 経由で session のイベントストリームをプッシュバックします。SDK は各イベントを `cloud_agent_event` メッセージとしてラップします：

```typescript theme={null}
for await (const msg of q) {
  if (msg.type === 'cloud_agent_event') {
    console.log(msg.event, msg.data);   // 例：「user.message」「agent.message」「session.status_idle」
  } else if (msg.type === 'result') {
    // SDK は現在ターンの session.status_idle 受信後に result を合成
    console.log('turn end:', msg.subtype);
  }
}
```

イベント構造：

| フィールド        | 説明                                                                  |
| ------------ | ------------------------------------------------------------------- |
| `event`      | Cloud イベント名（例：`user.message`、`agent.message`、`session.status_idle`） |
| `id`         | SSE ストリーム内のイベント ID。replay の起点として使える                                 |
| `data`       | Cloud イベント payload（`turn_id` などのフィールドを含む）                           |
| `session_id` | このイベントが属する Cloud session ID                                         |

<div id="履歴イベントの-replay-隔離" />

### 履歴イベントの replay 隔離

既存 session を再開する際、SSE はまず履歴ターンのイベントを replay します。SDK は `turn_id` で隔離します — **現在のターン**の `session.status_idle` のみが `result` 終端をトリガーし、履歴イベントが query を早期終了させることはありません。

<div id="sse-チューニング" />

### SSE チューニング

```typescript theme={null}
experimentalCloudAgent: {
  session: { id: sessionId },
  stream: {
    afterId: 'evt_xxx',         // 指定イベント ID 以降から replay を開始
    deltaFlushIntervalMs: 250,  // デルタ内容のマージ / フラッシュ間隔（省略時は SDK デフォルト）
  },
}
```

<div id="異常終了" />

### 異常終了

現在ターンが終端イベントに達する前に SSE が切断された場合、SDK はエラー `result` を合成します（`subtype !== 'success'`、`is_error: true`）。呼び出し側は統一的に処理できます。

<div id="result-終端" />

## `result` 終端

| フィールド                                     | 説明                                         |
| ----------------------------------------- | ------------------------------------------ |
| `subtype`                                 | `success` または各種エラー subtype                 |
| `is_error`                                | boolean。異常終了かどうか                           |
| `session_id`                              | Cloud session ID（create 分岐時は SDK が回填）      |
| `result`                                  | このターンの agent テキスト返答（複数 text block は連結される）  |
| `usage` / `modelUsage` / `total_cost_usd` | 現在ターンの `span.model_request_end.usage` から回填 |

<div id="制約サマリ" />

## 制約サマリ

* `agent` と `session` の `id` / `create` はそれぞれ相互排他（TypeScript の union で強制）。
* 既存 `session.id` を渡すとき、`agent` は**渡してはなりません**。
* `session.create` には `environment_id` を明示的に渡す必要があります。
* Cloud ランタイムはローカル CLI 専用のトップレベル option を拒否します：`model`、`agent`、`mcpServers`、`settings`、`hooks`、`plugins`、`permissionMode` など。渡すと同期的にエラーが投げられます。
* Cloud ランタイムは `q.setModel()`、`q.reloadPlugins()`、MCP OAuth などをサポートしません。`for await` 消費と `q.close()` のみが保証されます。

<div id="エラーコード" />

## エラーコード

| code                                     | 発生条件                                               |
| ---------------------------------------- | -------------------------------------------------- |
| `cloud_agent_auth_requires_access_token` | 非 PAT 認証（`qodercliAuth()` / `jobToken()` など）が使用された |
| `cloud_agent_api_error`                  | Cloud OpenAPI が non-2xx を返したか、SSE チャネルが異常終了した      |

<div id="関連ドキュメント" />

## 関連ドキュメント

* [SDK 認証](/ja/cli/sdk/authentication) — PAT の取得と環境変数
* [マルチターン会話](/ja/cli/sdk/multi-turn-conversation) — ローカルランタイム下のマルチターン
* [API References](/ja/cli/sdk/references) — `Options.experimentalCloudAgent` と `SDKCloudAgentEventMessage` の完全フィールド
