# 一次调用与持续输入

选择 Prompt、Query 或 Session，理解输入关闭、结果边界和资源归属。

## 先选择调用方式

| 入口 | 适合的任务 | 谁关闭会话 |
| --- | --- | --- |
| `client.Prompt` | 后台摘要、只需要最终结果 | 函数内部关闭一次性流 |
| `client.Query` | 一次任务，但要展示过程 | 调用者关闭返回的 Stream |
| `client.NewSession` | 对话、审批界面、多个连续回合 | 调用者关闭 Session |
| `Session.StreamInput` | 宿主持续提供用户消息 | 调用者管理输入通道并关闭 Session |

这些入口共用底层执行核心。选择 `Prompt` 不会关闭运行时的工具能力，它只是替你消费消息直到首个 `result`。若要限制工具，应配置权限与工具集合。

## 一次性流的使用顺序

先调用 `Query`，成功后安排 `Close`，再选择 `Recv` 或 `Result` 消费输出。读取到结果后即可结束本次任务，不需要等待所有内部后台事件。

```go
stream, err := client.Query(ctx, client.QueryRequest{
    Prompt: "阅读 README.md，说明如何启动项目。",
    Options: options,
})
if err != nil {
    return err
}
defer stream.Close(context.Background())
result, err := stream.Result(ctx)
if err != nil {
    return err
}
if result.IsError {
    return fmt.Errorf("任务失败：%s", result.Subtype)
}
fmt.Println(result.Result)
```

本页片段放在已有的 Go 函数中使用，`ctx` 和 `options` 来自[快速开始](/docs/sdk-quickstart)。服务端清理时应为 Close 使用独立的短超时，避免沿用已经取消的请求 context。

## 持续输入不是并发会话

`QueryRequest.Messages` 和 `Session.StreamInput` 接受 `<-chan protocol.OutboundMessage`。通道提供一条持续输入来源；启用 `Messages` 时，不要同时依赖 `Prompt` 字段作为额外首条消息。

```go
messages := make(chan protocol.OutboundMessage, 1)
messages <- protocol.NewUserTextMessage("阅读 README.md，提取启动步骤。")
close(messages)
stream, err := client.Query(ctx, client.QueryRequest{
    Messages: messages,
    Options: options,
})
if err != nil {
    return err
}
defer stream.Close(context.Background())
```

宿主应确定谁拥有通道、谁关闭通道、取消时如何停止生产消息。不要由多个发送者各自调用 `close`。输入通道结束与任务成功是两件事，仍要消费最终结果。

## 一个输出流只保留一个消费者

`Stream.Recv`、`Stream.Result` 和 `Session.Recv` 都读取同一条底层消息通道。它们不是各自独立的订阅。如果一个 goroutine 展示文本，另一个 goroutine 同时等待 Result，两者会争抢消息。

应让一个读取循环拥有消息流，在循环内部把文本转发到界面，把终态交给任务管理器。使用 `Recv` 已读走 `result` 后，不要再调用 `Result` 等待同一结果。完整循环见[消息流](/docs/sdk-streaming)。

## 结束与取消

一次性 Query 返回的 Stream 拥有会话，`Stream.Close` 负责释放它。Session.Send 返回的 Stream 不拥有 Session；关闭它不能代替 `Session.Close`。停止当前回合应调用 `Session.Interrupt`，停止整个连接才调用 Close。

为长任务设置截止时间，并在停止后确认终态或连接关闭。不要把 HTTP 客户端断开直接解释成“运行时已停止”，详见[取消与错误](/docs/sdk-errors)。
