Skip to main content

Cloud Agent

query() はデフォルトでローカルに bundled qodercli を起動します。cloud agent オプション(TypeScript の options.experimentalCloudAgent、Python の options.experimental_cloud_agent)を渡すと、SDK は Qoder Cloud Agent runtime に切り替わります——agent と session は Qoder Cloud コンテナで動き、ローカルはリクエスト送信と SSE イベントストリームの消費だけを担います。
ステータス:experimental / unstable。API 形状はマイナーバージョン間で変化する可能性があります。安定化されていないフィールドを本番のコードパスで依存しないでください。

使うべきタイミング

  • qodercli、バンドル済みバイナリ、ローカルランタイムを管理したくない
  • 同じ agent インスタンスをマシン間で長期間再利用したい(agent は Cloud に永続化される)
  • session のコンテキストを Cloud に置いて、複数のプロセス / ホストから再開したい
ローカル CLI 固有の機能——MCP servers / settings / hooks / plugins / ローカル permissions / checkpoint など——は Cloud runtime ではサポートされず、渡すと同期的にエラーになります。

前提条件

  • Personal Access Token (PAT)qoder.com/account/integrations で生成します。詳細は SDK 認証。Cloud runtime は access token 認証(accessToken() / accessTokenFromEnv()、Python は access_token() / access_token_from_env())のみを受け付け、ローカルログイン状態や job token を渡すと同期的にエラーになります。
  • Cloud environment_id:session 作成時に必須。Qoder コンソールまたは管理 API から取得します。
export QODER_PERSONAL_ACCESS_TOKEN="<your-pat>"
export QODER_CLOUD_AGENT_ENVIRONMENT_ID="<your-env-id>"

初回呼び出し:agent 作成 + session 作成

最も一般的なエントリパス — 新しい Cloud Agent を作成し、すぐにその session を開いて prompt を実行します:
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 を継続できます(マルチターン を参照)。

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

tools[].enabled_tools で現在サポートされているもの:bashwriteglobweb_fetchreadeditgrepweb_searchtools を省略すると agent はツールを持ちません。

session へのファイルマウント

Files API でアップロードしたファイルを session.create.resources で session コンテナにマウントできます:
session: {
  create: {
    environment_id,
    resources: [
      { type: 'file', file_id: 'file_abc123', path: '/workspace/data.json' },
    ],
  },
}

既存 agent の再利用

すでに agent.id がある場合(コンソール経由または前回の呼び出しで取得)、agent: { id } を渡し create は省略します:
experimentalCloudAgent: {
  agent: { id: 'agent_xxx' },
  session: { create: { environment_id } },
}

マルチターン:session の再開

初回ターンから session_id を得たら、次の呼び出しは**session: { id } のみ**を渡します — agent は含めないでください。session は既に agent を束縛しており、両方を渡すと同期的にエラーになります。
// 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 さえあれば再開できます。

QoderSDKClient によるマルチターン会話(Python)

Python の QoderSDKClient はより高レベルの Cloud session 管理を提供します——connect() が Cloud session を作成/解決し、以降の query() がターンごとに再利用します。session_id の手動追跡は不要です:
import asyncio
import os

from qoder_agent_sdk import (
    QoderAgentOptions,
    QoderSDKClient,
    ResultMessage,
    access_token_from_env,
)


async def main():
    environment_id = os.environ["QODER_CLOUD_AGENT_ENVIRONMENT_ID"]

    client = QoderSDKClient(
        options=QoderAgentOptions(
            auth=access_token_from_env(),
            experimental_cloud_agent={
                "agent": {"create": {"name": "demo", "model": "ultimate"}},
                "session": {"create": {"environment_id": environment_id}},
            },
        )
    )

    # connect() creates the Cloud session; optionally pass a first-turn prompt
    await client.connect("My favorite color is teal. Reply with: noted.")

    # Consume first turn messages
    async for msg in client.receive_messages():
        if isinstance(msg, ResultMessage):
            break

    # Turn 2: call query() directly — session is already bound
    await client.query("What is my favorite color?")
    async for msg in client.receive_messages():
        if isinstance(msg, ResultMessage):
            print(msg.result)  # → "teal"
            break

    await client.disconnect()


asyncio.run(main())
注意:Cloud ランタイムは client.set_model()client.reload_plugins()、MCP OAuth などのローカル CLI 制御メソッドをサポートしません。呼び出すと ValueError が投げられます。

SSE イベントの消費

Cloud runtime は SSE で session のイベントストリームを送り返します。SDK は各イベントを cloud agent イベントメッセージ(TypeScript は cloud_agent_event、Python は CloudAgentEventMessage)にラップします:
for await (const msg of q) {
  if (msg.type === 'cloud_agent_event') {
    console.log(msg.event, msg.data);   // e.g. "user.message", "agent.message", "session.status_idle"
  } else if (msg.type === 'result') {
    // SDK synthesizes a result after receiving session.status_idle for the current turn
    console.log('turn end:', msg.subtype);
  }
}
イベント構造:
フィールド説明
eventCloud イベント名(例:user.messageagent.messagesession.status_idle
idSSE ストリーム内のイベント ID。replay の起点として使える
dataCloud イベント payload(turn_id などのフィールドを含む)
uuid(Python)SDK 内部生成の一意 ID。重複排除に使用
session_idこのイベントが属する Cloud session ID

履歴イベントの replay 隔離

既存 session を再利用すると、SSE はまず過去ターンのイベントをリプレイします——SDK は turn_id で分離します:現在のターンsession.status_idle だけが result 終端をトリガーし、過去のイベントで query が早期終了することはありません。

SSE チューニング

experimentalCloudAgent: {
  session: { id: sessionId },
  stream: {
    afterId: 'evt_xxx',         // start replay after this event ID
    deltaFlushIntervalMs: 250,  // delta merge / flush interval (SDK default if omitted)
  },
}
互換性:Python では afterId / deltaFlushIntervalMs(camelCase)も受け付けられ、ランタイムが自動認識します。

異常終了

現在のターンが終端に達する前に SSE が切断された場合、SDK はエラー result(subtype != 'success'is_error: true)を合成し、上位層で統一的に処理できるようにします。

終端状態:result の内容

フィールド説明
subtypesuccess または各種エラー subtype
is_errorboolean。異常終了かどうか
session_idCloud session ID(create 分岐時は SDK が回填)
resultこのターンの agent テキスト返答(複数 text block は連結される)
usage / model usage / total_cost_usd現在のターンの span.model_request_end.usage からバックフィル

制約サマリ

  • agentsession はそれぞれ id / create が排他です(TypeScript は union 型で強制)。
  • 既存 session.id を渡すとき、agent渡してはなりません
  • session.create には environment_id を明示的に渡す必要があります。
  • Cloud runtime はローカル CLI のトップレベル option をサポートしません:modelagent、MCP servers、settingshooksplugins、権限モードなどを渡すと同期的にエラーになります。
  • Cloud runtime はモデル切り替え、プラグインリロード、MCP OAuth などのランタイム制御メソッドをサポートしません。許されるのはメッセージの反復消費とセッションのクローズ(TypeScript の q.close()、Python の client.disconnect())だけです。

エラーコード

TypeScript code / Python 例外クラストリガー条件
cloud_agent_auth_requires_access_token / CloudAgentUnsupportedAuthErrorローカルログイン状態 / job token などの非 PAT 認証を使用
cloud_agent_api_error / CloudAgentApiErrorCloud OpenAPI が非 2xx を返す、または SSE チャンネル異常

関連ドキュメント

  • SDK 認証 — PAT の取得と環境変数
  • 入力モード — ローカル SDK の単一メッセージ入力とストリーミング入力
  • API References — cloud agent オプションとイベントメッセージの完全なフィールド
Cloud Agent - Qoder