Skip to main content
会話とセッション

入力モード

入力モードが決めるのは、タスクの開始後もアプリケーションから Agent にメッセージを送り続けられるかどうかです。 テキストや画像などのメッセージ内容を区別するものではなく、応答を逐次表示するかどうかを決めるものでもありません。どちらの入力モードでも、SDK は Agent の応答をメッセージストリームとして返します。応答の処理方法はストリーミング出力を参照してください。 Qoder Agent SDK には 2 種類の入力モードがあります。
入力モードTypeScriptPython使用する場面
単一メッセージ入力query({ prompt: string })query(prompt=str)1 回限りのタスク、バッチ処理、CI スクリプト
ストリーミング入力query({ prompt: AsyncIterable<SDKUserMessage> })QoderSDKClient を推奨。事前に確定したメッセージストリームは query() にも渡せますチャット UI、複数メッセージのセッション、実行中の情報追加や方向修正
選択するときは、タスクの開始後も Agent にメッセージを送る必要があるかだけを考えます。
  • 必要がない場合は、単一メッセージ入力を使用します。
  • 必要がある場合、たとえばユーザーが追加で質問する、または Agent の応答に基づいてアプリケーションが次の処理を決める場合は、ストリーミング入力を使用します。

単一メッセージ入力

文字列を query() に渡すと、独立したタスクが開始されます。タスク開始後、この呼び出しに別のユーザーメッセージを追加することはできません。タスクが完了すると、SDK はセッションを終了します。
import { accessTokenFromEnv, query } from '@qoder-ai/qoder-agent-sdk';

for await (const message of query({
  prompt: '現在のプロジェクトでテストカバレッジが不足している関数を調べ、レポートしてください。',
  options: {
    auth: accessTokenFromEnv(),
    allowedTools: ['Read', 'Glob', 'Grep'],
  },
})) {
  if (message.type === 'result' && message.subtype === 'success') {
    console.log(message.result);
  }
}
単一メッセージ入力でもツール承認は利用できます。Agent がまだ許可されていないツールを実行する必要がある場合、canUseTool / can_use_tool でユーザーに確認できます。そのために prompt をメッセージストリームへ変更する必要はありません。詳しくは承認とユーザー入力を参照してください。

ストリーミング入力

ストリーミング入力では、タスク開始後もアプリケーションからメッセージを送れます。マルチターンのチャットだけでなく、実行中のタスクに情報を追加する、方向を変える、後で処理するメッセージを予約するといった用途にも使用できます。 推奨インターフェースは SDK ごとに異なります。
  • TypeScriptAsyncIterable<SDKUserMessage>query() に渡します。この非同期イテレーターは、チャット UI、メッセージキュー、その他のイベントから受け取ったユーザーメッセージを継続して yield できます。
  • PythonQoderSDKClient でセッションを維持します。client.query(...) で新しいメッセージを送り、client.receive_response() でそのターンの応答を受け取ります。

複数メッセージのセッション

import {
  accessTokenFromEnv,
  query,
  type SDKUserMessage,
} from '@qoder-ai/qoder-agent-sdk';

async function* messages(): AsyncGenerator<SDKUserMessage> {
  yield {
    type: 'user',
    message: {
      role: 'user',
      content: [{ type: 'text', text: 'このコードベースのセキュリティ上の問題を確認してください。' }],
    },
    parent_tool_use_id: null,
  };

  // 実際のアプリケーションでは、ここで UI、メッセージキュー、その他のイベントを待機できます。
  await new Promise((resolve) => setTimeout(resolve, 2_000));

  yield {
    type: 'user',
    message: {
      role: 'user',
      content: [{ type: 'text', text: '分析が終わったら、簡潔なレポートも作成してください。' }],
    },
    parent_tool_use_id: null,
    priority: 'later',
  };
}

for await (const message of query({
  prompt: messages(),
  options: {
    auth: accessTokenFromEnv(),
    allowedTools: ['Read', 'Glob', 'Grep'],
  },
})) {
  if (message.type === 'result' && message.subtype === 'success') {
    console.log(message.result);
  }
}
TypeScript のメッセージフィールドは SDKUserMessage を参照してください。Python では、receive_response() ごとに 1 ターンの応答を受け取ります。ResultMessage を受信した後、次のメッセージを送信できます。

Python 非同期メッセージストリームの境界

Python の query()AsyncIterable[dict[str, Any]] も受け取ります。すべてのメッセージがタスク開始前に確定している場合は、この方法で順番に送信できます。次のコードは非同期メッセージストリームの中心部分だけを示しています。queryoptions の作成方法は、前の完全な例を参照してください。
Python
async def prompts():
    yield {
        "type": "user",
        "message": {"role": "user", "content": "認証モジュールを確認してください。"},
        "parent_tool_use_id": None,
    }
    yield {
        "type": "user",
        "message": {"role": "user", "content": "その後、検出した問題をまとめてください。"},
        "parent_tool_use_id": None,
    }


async for message in query(prompt=prompts(), options=options):
    print(message)
この形式は、事前に用意したメッセージにだけ使用してください。Agent が返した直後の内容に基づいて次のメッセージを決めることはできず、interrupt() の呼び出しやキュー内メッセージのキャンセルもできません。チャット UI などの対話型アプリケーションでは QoderSDKClient を使用してください。

Agent の実行中に入力を追加する

Agent の応答中にも別のメッセージを送信できます。priority は Agent がそのメッセージを処理するタイミングを決めます。
動作
now現在の応答を停止し、このメッセージをすぐに処理する
nextデフォルト。次の適切なタイミングで処理する
later現在の応答が終わるまで待つ
同じ優先度のメッセージは送信順に処理されます。現在の処理方向をすぐに変えるには priority: 'now' を使用します。新しいメッセージを送らずに現在の応答だけを止めたい場合は、現在の応答を中断するを使用してください。 次のコードは、前述の TypeScript メッセージジェネレーターまたは接続済みの Python client セッション内に配置します。
yield {
  type: 'user',
  message: {
    role: 'user',
    content: [{ type: 'text', text: '現在の方針を止め、失敗しているテストだけを分析してください。' }],
  },
  parent_tool_use_id: null,
  priority: 'now',
};

応答を開始せずコンテキストを追加する

Agent にすぐ応答させず、背景情報だけを追加したい場合があります。その場合は TypeScript で shouldQuery: false、Python で should_query=False を設定します。メッセージは会話に追加され、いつ有効になるかは priority で決まります。
yield {
  type: 'user',
  message: {
    role: 'user',
    content: [{ type: 'text', text: '以降の提案はすべて Python 3.10 に対応させてください。' }],
  },
  parent_tool_use_id: null,
  shouldQuery: false,
};

現在の応答を中断する

interrupt() を呼び出すと、セッションを終了せずに Agent の現在の応答を停止できます。中断後もメッセージを送信できます。TypeScript では query() が返すオブジェクトで呼び出し、Python では QoderSDKClient を使用します。
import { accessTokenFromEnv, query } from '@qoder-ai/qoder-agent-sdk';

const q = query({
  prompt: 'プロジェクト内のすべてのファイルを確認してください。',
  options: { auth: accessTokenFromEnv() },
});

const interruptTimer = setTimeout(() => {
  void q.interrupt().catch(console.error);
}, 5_000);

try {
  for await (const message of q) {
    console.dir(message, { depth: null });
  }
} finally {
  clearTimeout(interruptTimer);
}
interrupt() はキューで待機中のメッセージを削除しません。不要になったメッセージは個別にキャンセルしてください。セッション全体を終了するには、close メソッドを呼び出すか async with ブロックを終了します。

キュー内メッセージをキャンセルする

まだ処理が始まっていないメッセージをキャンセルするには、まずセッション内で一意の UUID を設定します。TypeScript ではメッセージの uuid フィールド、Python では message_uuid 引数を使用します。 次のコードはキャンセル操作だけを示しており、q / client と対応するメッセージ UUID がすでに作成されていることを前提とします。
const cancelled = await q.cancelAsyncMessage(uuid);
キャンセルに成功すると true / True、メッセージが存在しない、またはすでに処理が始まっている場合は false / False を返します。UUID のないメッセージは個別にキャンセルできません。同じセッション内で UUID を再利用しないでください。

入力を終了してセッションを閉じる

  • TypeScript:文字列プロンプトのタスクが完了すると SDK はセッションを終了します。非同期メッセージストリームでは、イテレーターの終了がメッセージ送信の終了を表します。セッション全体を早期に閉じるには、AbortController を使うか q.close() を呼び出します。
  • Python:1 回限りの query() は自動的に終了します。QoderSDKClient では async with による自動接続・切断を推奨しますが、connect() / disconnect() を手動で呼び出すこともできます。
次のコードはセッションの終了方法だけを示し、前の例で定義した import、messages()options を再利用します。

自動的に閉じる

const q = query({
  prompt: messages(),
  options: { auth: accessTokenFromEnv() },
});

try {
  for await (const message of q) {
    console.dir(message, { depth: null });
  }
} finally {
  await q.close();
}

外部条件に応じて早期に閉じる

const abortController = new AbortController();
const q = query({
  prompt: 'プロジェクト内のすべてのファイルを確認してください。',
  options: { auth: accessTokenFromEnv(), abortController },
});

const taskTimeout = setTimeout(() => abortController.abort(), 5_000);
try {
  for await (const message of q) {
    console.dir(message, { depth: null });
  }
} finally {
  clearTimeout(taskTimeout);
}
セッションを閉じた後は、新しいメッセージを送信できません。