> ## 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.

# マルチターン会話

`query()` には 2 つの入力モードがあります：

* **シングルメッセージクエリモード**：1 つのユーザーメッセージを送信し、SDK は応答完了後にセッションを閉じます。[クイックスタート](/ja/cli/sdk/quick-start) を参照してください。
* **マルチメッセージセッションモード**：セッションを開いたまま、モデルとマルチターン対話を行います。

***

<div id="マルチメッセージセッション" />

## マルチメッセージセッション

ユーザーメッセージを順番に産出するシーケンスを定義します：

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

async function* messages(): AsyncGenerator<SDKUserMessage> {
  yield {
    type: 'user',
    message: { role: 'user', content: [{ type: 'text', text: 'Analyze this codebase for security issues' }] },
    parent_tool_use_id: null,
  };

  // 次のメッセージを産出する前に任意の外部条件を待つことができます
  await new Promise((resolve) => setTimeout(resolve, 2000));

  yield {
    type: 'user',
    message: { role: 'user', content: [{ type: 'text', text: 'Now write a short report' }] },
    parent_tool_use_id: null,
  };
}

for await (const msg of query({
  prompt: messages(),
  options: {
    auth: qodercliAuth(),
    allowedTools: ['Read', 'Grep'],
  },
})) {
  if (msg.type === 'result' && msg.subtype === 'success') {
    console.log(msg.result);
  }
}
```

モデルはユーザーメッセージを受け取るたびに 1 ターン応答します。メッセージシーケンスが終了するとセッションは自動的に閉じます。メッセージフィールドの定義は [`SDKUserMessage`](/ja/cli/sdk/references#sdkusermessage) を参照してください。

***

<div id="セッションライフサイクルの管理" />

## セッションライフサイクルの管理

マルチメッセージセッションでは、**`query()` が返すオブジェクトのライフサイクルは呼び出し側が管理します**。SDK はメッセージシーケンスが自然に終了した場合のみセッションを閉じます。それ以外のすべてのケースでは呼び出し側がいつ終了するかを決定する必要があり、さもないとセッションはハングし続けます。

呼び出し側が能動的にクローズを管理する必要がある一般的なシナリオ：

* メッセージシーケンス自体が終了しない場合、例えば外部入力をループ待ちするジェネレータ：

  ```typescript theme={null}
  async function* fromUserUI(): AsyncGenerator<SDKUserMessage> {
    while (true) {
      const text = await waitForUserInput();   // UI の入力ソース
      yield {
        type: 'user',
        message: { role: 'user', content: [{ type: 'text', text }] },
        parent_tool_use_id: null,
      };
    }
  }
  ```

* メッセージシーケンスが正常に終了する前に終了したい場合：タイムアウト、ユーザーキャンセル、その他のビジネス条件。

2 つのクローズ方法：

<div id="自動管理推奨node-22-または-explicit-resource-management-対応ランタイム" />

### 自動管理（推奨。Node 22+ または explicit resource management 対応ランタイム）

セッションのライフタイムが関数 / コードブロックのスコープと一致する場合に使用します——スコープを抜けると自動的に解放されます。

```typescript theme={null}
{
  await using q = query({ prompt: fromUserUI(), options: { auth: qodercliAuth() } });
  for await (const msg of q) { /* ... */ }
}  // スコープを抜けると自動的にクローズ
```

<div id="手動クローズ" />

### 手動クローズ

クローズのトリガーが外部から来る場合に使用します：タイムアウト、ユーザーのキャンセル、その他のビジネス条件など。

```typescript theme={null}
const q = query({ prompt: fromUserUI(), options: { auth: qodercliAuth() } });
setTimeout(() => q.close(), 30_000);   // 30 秒後に強制クローズ

for await (const msg of q) { /* ... */ }
```
