> ## 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()` 有两种输入模式：

* **单消息查询模式**：一次提交一条用户消息，SDK 完成本轮回复后关闭会话。见 [快速开始](/zh/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,
  };

  // Wait for any external condition before sending the next message.
  await new Promise((resolve) => setTimeout(resolve, 2000));

  yield {
    type: 'user',
    message: { role: 'user', content: [{ type: 'text', text: 'Now write a brief 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);
  }
}
```

通常，发送用户消息后，模型会开始回复。在回复结束前发送的新消息，会在 `priority` 指定的时机处理。输入消息流结束后，会话自动关闭。消息字段定义见 [`SDKUserMessage`](/zh/cli/sdk/references#sdkusermessage)。

***

<div id="运行中插话" />

## 运行中插话

模型回复期间，异步输入流仍可继续发送 `SDKUserMessage`。

```typescript theme={null}
yield {
  type: 'user',
  message: { role: 'user', content: [{ type: 'text', text: 'Stop the current direction and analyze only the failing tests.' }] },
  parent_tool_use_id: null,
  priority: 'now',
};
```

`priority` 决定消息何时交给会话：

| 值       | 行为              |
| ------- | --------------- |
| `now`   | 停止当前回复，立即处理这条消息 |
| `next`  | 默认值；在下一个合适的时机处理 |
| `later` | 等当前回复结束后处理      |

相同优先级的消息按发送顺序处理。`priority: 'now'` 适合立即改变当前方向；如果只想停止当前回复、不发送新消息，应使用 [`q.interrupt()`](#中断当前轮次)。

<div id="写入上下文但不启动新-turn" />

### 添加上下文但不触发回复

`shouldQuery: false` 会把消息加入对话，但不会仅凭这条消息触发回复。消息的处理时机仍由 `priority` 决定。

***

<div id="中断当前轮次" />

## 中断当前回复

调用 `await q.interrupt()` 可以停止当前回复，但不会关闭会话，之后仍可继续对话。

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

const q = query({
  prompt: 'Inspect all files in the repository.',
  options: { auth: qodercliAuth() },
});

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

try {
  for await (const msg of q) {
    console.dir(msg, { depth: null });
  }
} finally {
  clearTimeout(interruptTimer);
}
```

`interrupt()` 不会清空排队消息。如果某条排队消息不能继续执行，请使用 `cancelAsyncMessage()`。结束整个会话的方式见[管理会话生命周期](#管理会话生命周期)。

<div id="取消排队消息" />

### 取消排队消息

给需要跟踪的消息设置会话内唯一的 `uuid`，再使用 `q.cancelAsyncMessage(uuid)` 取消尚未开始执行的消息：

```typescript theme={null}
const cancelled = await q.cancelAsyncMessage(uuid);
```

取消成功返回 `true`；消息不存在或已无法取消时返回 `false`。未设置 `uuid` 的消息无法通过该方法取消。不要在同一会话内复用 UUID。

***

<div id="管理会话生命周期" />

## 管理会话生命周期

单条字符串输入处理完成或输入消息流结束后，SDK 会自动关闭会话。如果需要提前结束会话，可以通过 `AbortController` 自定义结束时机，也可以直接调用 `q.close()`。

### 自定义会话结束时机

如果需要根据业务条件决定何时结束会话，请创建 `AbortController`，并在调用 `query()` 时通过 `options.abortController` 传入。自定义条件满足时，调用同一个控制器的 `abort()`。条件可以来自用户操作、上游请求、任务超时、应用退出或其他业务逻辑：

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

const abortController = new AbortController();
const q = query({
  prompt: 'Inspect all files in the repository.',
  options: { auth: qodercliAuth(), abortController },
});

const taskTimeout = setTimeout(() => abortController.abort(), 5_000);
try {
  for await (const msg of q) {
    console.dir(msg, { depth: null });
  }
} finally {
  clearTimeout(taskTimeout);
}
```

调用 `abort()` 会关闭整个会话并结束消息迭代，之后不能继续发送消息。

### 主动关闭会话

如果当前代码已经确定不再使用会话，可以直接调用 `await q.close()`。它适用于正常收尾、提前退出和异常清理；放在 `finally` 中可以确保相关资源关闭完成：

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

const q = query({
  prompt: 'Inspect all files in the repository.',
  options: { auth: qodercliAuth() },
});

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