Skip to main content
SDK

TypeScript SDK

Qoder Cloud Agents TypeScript SDK のインストールと使用方法。型、非同期呼び出し、ストリーミングレスポンス、キャンセル、ページネーション、カスタム fetch を説明します。

Qoder Cloud Agents TypeScript SDK は TypeScript と JavaScript アプリケーションで使用でき、Forward、Managed クライアント、リクエスト・レスポンス型、非同期ページネーション、SSE ストリーミング読み取りを提供します。パッケージには ES Modules と CommonJS の両方のエントリーポイントがあります。

インストール

Node.js 20.12 以降が必要です:
npm install qca-sdk
パッケージのバージョンとロックファイルをバージョン管理に含めてください。本ドキュメントの例は Node.js サーバー上で実行します。

基本的な使い方

個人アクセストークン(PAT)を環境変数に保存します:
export QODER_PAT="替换为你的 PAT"
Forward クライアントでテンプレートと ID を作成し、セッションを開始してメッセージを送信します。次のコードは .mjs ファイルに保存して直接実行するか、ES Modules 対応の TypeScript プロジェクトで使用できます:
import { ForwardClient } from 'qca-sdk';

const client = new ForwardClient();

const env = await client.environments.create({
  name: 'demo',
  config: { type: 'cloud' },
});

const identity = await client.identities.create({
  external_id: 'demo-user',
  name: 'Demo User',
});

const template = await client.templates.create({
  name: 'assistant',
  model: 'auto',
  environment_id: env.id,
});

const session = await client.sessions.create({
  identity_id: identity.id,
  template_id: template.id,
});

await client.sessions.events.send(session.id, {
  events: [{
    type: 'user.message',
    content: [{ type: 'text', text: '你好' }],
  }],
});

console.log(session.id);
Managed クライアントで Agent と環境を作成し、セッションを開始してメッセージを送信します:
import { ManagedClient } from 'qca-sdk';

const client = new ManagedClient();

const agent = await client.agents.create({
  name: 'assistant',
  model: 'auto',
});

const env = await client.environments.create({
  name: 'demo',
  config: { type: 'cloud' },
});

const session = await client.sessions.create({
  agent: agent.id,
  environment_id: env.id,
});

await client.sessions.events.send(session.id, {
  events: [{
    type: 'user.message',
    content: [{ type: 'text', text: '你好' }],
  }],
});

console.log(session.id);
qca-sdk/forward、qca-sdk/managed から対応するクライアントをインポートすることもできます。CommonJS プロジェクトでは require('qca-sdk') を使用し、await 呼び出しを非同期関数内に置きます。 以降のコード断片で再作成していない client は、設定済みの Forward クライアントです。sess_example などの ID は現在の認証情報でアクセスできる実際の ID に置き換えてください。詳細は Managed クイックスタートと Forward API リファレンスを参照してください。

クライアント設定

設定ForwardManaged
クライアントForwardClientManagedClient
Base URL 環境変数QODER_FORWARD_BASE_URLQODER_BASE_URL
Global のデフォルト URLhttps://api.qoder.com/api/v1/forwardhttps://api.qoder.com/api/v1/cloud
CN の URLhttps://api.qoder.com.cn/api/v1/forwardhttps://api.qoder.com.cn/api/v1/cloud
明示的な設定は環境変数より優先されます。デフォルトの PAT モードは QODER_ACCESS_TOKEN、次に QODER_PAT を読み取ります。SDK は .env ファイルを自動読み込みしません。Base URL には完全な API プレフィックスを含め、アカウント、認証情報、リソースのリージョンと一致させてください。
import { ForwardClient } from 'qca-sdk';

const client = new ForwardClient({
  baseURL: 'https://api.qoder.com.cn/api/v1/forward',
  timeout: 30_000,
  maxRetries: 2,
  defaultHeaders: { 'X-Application': 'my-app' },
});

const result = await client.models.list({ timeout: 5_000 });
console.log(result.data.length);
時間の単位はミリ秒です。呼び出しごとのリクエスト設定は通常メソッドの最後の引数です。クエリまたは本文パラメーターがあるメソッドでは、そのパラメーターを先に渡します。両者を混同しないでください。

設定の再利用

withOptions() は同じ型の新しいクライアントを作成し、上書きされない設定を保持します。元のクライアントの設定は変わりません:
const slowClient = client.withOptions({ timeout: 60_000, maxRetries: 1 });
const result = await slowClient.sessions.list({ limit: 20 });
console.log(result.data.length);
新しい defaultHeaders、defaultQuery、middleware を渡すと、対応する設定値全体を置き換えます。個々のリクエスト設定は派生クライアントのデフォルトより優先されます。

認証

PAT

pat で個人アクセストークンを明示的に渡すか、環境変数を使用します。トークンは信頼できるサーバー環境に保存し、フロントエンドからは自社の業務サービスを介して QCA にアクセスします。

Service Account

QODER_SA_KEY の設定後、認証情報コンポーネントを明示的に作成します。SAT(サービスアカウントトークン)を交換・キャッシュし、後続リクエストで必要になった際に更新します:
import {
  ForwardClient,
  ManagedClient,
  ServiceAccountCredential,
} from 'qca-sdk';

const credential = ServiceAccountCredential.fromEnv({
  region: 'global',
  scopes: ['qca.access', 'forward.access'],
});

const forward = new ForwardClient({
  credential,
  baseURL: 'https://api.qoder.com/api/v1/forward',
});
const managed = new ManagedClient({
  credential,
  baseURL: 'https://api.qoder.com/api/v1/cloud',
});
複数クライアントで同じ認証情報インスタンスとキャッシュを共有できます。中国サイトでは region: 'cn' と CN Base URL の両方を設定します。Managed のみを利用する場合は qca.access scope を要求できます。権限とワークスペースの紐付けはサーバー側で設定します。 環境に QODER_SA_KEY が存在するだけでは、通常のクライアントは自動的にトークン交換を有効にしません。SA Key を業務 API のアクセストークンとして直接使用することもできません。SA 認証が失敗しても PAT にフォールバックしません。 アプリケーションが SAT を管理する場合は { authMode: 'sa', accessToken: token } を使用します。accessToken はトークンまたは Promise<string> を返す関数も受け付け、各リクエスト試行前に再評価されます。静的 SAT の更新はアプリケーションが行います。accessToken、pat、credential など複数のソースを同時に設定しないでください。詳細は認証ドキュメントを参照してください。

リクエストとレスポンスの型

リクエストとレスポンスの型は対応するモードのサブパスからインポートし、フィールドは API の snake_case 名を保持します:
import type { SessionUpdateParams } from 'qca-sdk/forward';

const omitted: SessionUpdateParams = {};
const explicitNull: SessionUpdateParams = { title: null };
const emptyString: SessionUpdateParams = { title: '' };
JavaScript の値JSON オブジェクトフィールドの動作
プロパティを省略、または値が undefinedフィールドを送信しない
nullnull を送信
false、0、''そのまま送信
空の配列、オブジェクト[]、{} を送信
フィールドが null を受け付けるか、その値をどう処理するかは、対応する API の定義に従います。ユニオン型は判別フィールドまたはプロパティチェックで絞り込んでから具体的なフィールドを読み取ってください。 サーバーが追加した未知のレスポンスフィールドは保持されますが、現在の TypeScript 型宣言に含まれているとは限りません。使用時は実際の値を確認した上で必要な拡張型を宣言してください。TypeScript の型自体は実行時のデータ検証ではありません。

ストリーミングレスポンス

streamEvents() は非同期反復可能な SSE ストリームを返します。for await...of で読み取り、finally で接続を解放します:
const stream = await client.sessions.events.streamEvents('sess_example');
try {
  for await (const event of stream) {
    console.log(event.type);
  }
} finally {
  await stream.close();
}
通常のストリームは EOF で終了します。回復可能な切断後も購読するには、明示的に resumableStream() を使用します:
const stream = client.sessions.events.resumableStream(
  'sess_example',
  { last_event_id: 'evt_checkpoint' },
  { signal: AbortSignal.timeout(60_000) },
);

try {
  for await (const event of stream) {
    console.log(event.type);
    // 应用成功处理事件后,再持久化该恢复位置。
    console.log('cursor:', stream.lastEventID);
  }
} finally {
  await stream.close();
}
evt_checkpoint を有効な再開位置に置き換えてください。初回購読では last_event_id を省略できます。resumableStream() は非同期反復可能オブジェクトを直接返し、作成時に await は不要です。例の AbortSignal は購読全体を 60 秒に制限し、期限によるキャンセルはキャンセルエラーとして呼び出し元に伝播します。 再開可能ストリームは最後に配信されたイベントの SSE カーソルを保持し、再接続時に再利用します。業務リクエストを再送せず、「厳密に 1 回」の処理も保証しません。同じイベントの複数の差分が同一 ID を共有する場合があるため、ID だけですべての重複フレームを破棄しないでください。 カーソルがなければ現在のイベントストリーム末尾から開始します。履歴の読み取りには有効な過去の再開位置が必要です。HTTP リクエストのリトライ回数は購読全体の再接続上限ではありません。イベントの意味とタスク完了条件は対応する API 定義を参照してください。 ストリームを閉じる、またはローカル HTTP リクエストをキャンセルしても、終了するのは現在の購読のみです。クラウドで開始済みの実行は自動停止しません。

エラー処理と Request ID

instanceof で呼び出し元によるキャンセル、タイムアウト、HTTP エラーなどを区別します:
import {
  APIConnectionTimeoutError,
  APIError,
  APIUserAbortError,
} from 'qca-sdk';

try {
  const result = await client.sessions.retrieve('sess_example');
  console.log(result._request_id);
} catch (error) {
  if (error instanceof APIUserAbortError) {
    console.log('请求已取消');
  } else if (error instanceof APIConnectionTimeoutError) {
    console.log('请求超时');
  } else if (error instanceof APIError) {
    console.log(error.status, error.code, error.request_id);
  } else {
    throw error;
  }
}
APIError は HTTP、接続、タイムアウト、キャンセルのエラーを対象とします。HTTP レスポンスを受け取っていない場合、status、headers、response は undefined の可能性があるため、常に存在するとは仮定しないでください。クライアント設定エラーはより広い QoderError に属します。 主な HTTP サブクラスは BadRequestError(400)、AuthenticationError(401)、PermissionDeniedError(403)、NotFoundError(404)、ConflictError(409)、RateLimitError(429)、InternalServerError(5xx)です。 通常の JSON オブジェクトレスポンスの _request_id はレスポンスヘッダーに由来し、存在しない場合は null です。列挙不可のプロパティで、JSON.stringify() やオブジェクトのスプレッド結果には含まれません。HTTP エラーは request_id で識別子を提供します。ページネーションやストリームとともにメタデータを読むには .withResponse() を使用します。個々のストリームイベントやネストしたオブジェクトにこのメタデータは自動付与されません。

リトライと冪等性

デフォルトのリトライは最大 2 回、合計で最大 3 回の試行です。自動リトライには安全に再実行できることが必要です:
リクエストデフォルトでリトライする条件
GET、HEAD、または冪等キー付きリクエスト接続エラー、タイムアウト、408、429、5xx
冪等キーのないその他のリクエスト429
409 レスポンス自動リトライしない
本文が再読み取りできない ReadableStream自動再実行しない
SDK はこれらのルール内でサーバーのリトライ指示と待機時間を処理します。一部 API にはより厳しいルールがあります。クライアントの maxRetries でデフォルト回数を設定するか、個々の呼び出しのリクエスト設定で上書きします:
const result = await client.sessions.retrieve('sess_example', { maxRetries: 0 });
console.log(result.id);
書き込みリクエストではリクエスト設定の idempotencyKey で冪等キーを渡します。同じ論理操作の全リトライで同じキーを再利用し、新しい操作には新しいキーを使用します。

タイムアウトとキャンセル

デフォルトのタイムアウトは 10 分です。timeout は各 fetch がレスポンスを待つ時間を制御します。fetch 呼び出し前に計時を開始し、レスポンスヘッダーを受け取ると終了します。それ以前の認証情報取得、ミドルウェア実行、その後の本文読み取りは含みません。 そのため、SSE やダウンロードの読み取りは timeout を超える場合があります。操作全体の時間を制限するには AbortSignal を渡します:
const result = await client.sessions.retrieve('sess_example', {
  timeout: 10_000,
  signal: AbortSignal.timeout(30_000),
});
console.log(result.id);
アプリケーションが AbortController を保持し、ユーザーのキャンセル時に abort() を呼び出すこともできます:
const controller = new AbortController();
const pending = client.sessions.retrieve('sess_example', {
  signal: controller.signal,
});

// 在应用的取消事件处理中调用 controller.abort()。
const result = await pending;
console.log(result.id);
シグナルのキャンセルにより、呼び出しの待機、リトライ、本文読み取りが終了します。カスタムミドルウェアや外部認証情報コンポーネント自身の処理も、それぞれのキャンセルとリソース管理の規約に従う必要があります。

ページネーション

一覧メソッドは非同期反復をサポートし、必要に応じて後続ページを読み取ります:
for await (const item of client.sessions.list({ limit: 20 })) {
  console.log(item.id);
}
ページごとに処理する場合は .data を読み取り、先に次のページの有無を確認します:
const page = await client.sessions.list({ limit: 20 });
console.log(page.data.length);

if (page.hasNextPage()) {
  const next = await page.getNextPage();
  console.log(next.data.length);
}
for await (const currentPage of page.iterPages()) でもページを反復できます。getNextPage() は次のページがない場合に null ではなくエラーを送出します。自動反復は最終ページで正常終了します。ページネーターはフィルター条件とリクエスト設定を保持します。

詳細設定

元のレスポンス

通常のリクエストは APIPromise を返します。直接 await すると解析済みデータを取得し、.withResponse() はデータ、元のレスポンス、Request ID をまとめて返します:
const { data, response, request_id } = await client.sessions
  .retrieve('sess_example')
  .withResponse();

console.log(data.id, response.status, request_id);
.asResponse() は本文を読み取らずに元の Response を返します。呼び出し元が本文を消費またはキャンセルしてください:
const response = await client.sessions.retrieve('sess_example').asResponse();
try {
  console.log(response.status, response.headers.get('x-request-id'));
} finally {
  await response.body?.cancel();
}

カスタム fetch とミドルウェア

fetch で HTTP 実装を注入します。プロキシ、TLS、接続プールは選択した実装が管理します。ミドルウェアは各 API リクエスト試行の観測や調整に使用します:
import { ForwardClient } from 'qca-sdk';

const client = new ForwardClient({
  fetch: globalThis.fetch,
  middleware: [
    async (request, next) => {
      const started = Date.now();
      const response = await next(request);
      console.log(request.method, response.status, Date.now() - started);
      return response;
    },
  ],
});
ここで記録するのはレスポンス受信までの時間で、SSE の消費完了を表すものではありません。ミドルウェアは API リクエスト経路の一部であり、すべての外部接続を対象とするグローバルインターセプターではありません。 追加 Header と Query にはリクエスト設定の headers、query を使用します。型がまだ対応していないリクエストフィールドはパラメーターオブジェクトに追加できますが、サーバーが対応するフィールドのみ有効です。通常の呼び出しでは既存の型付きメソッドを優先してください。