> ## Documentation Index
> Fetch the complete documentation index at: https://niceeval.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# 标准事件流参考

> StreamEvent 的九种事件：每种的字段、什么时候吐、哪些断言消费它。adapter 的核心工作就是产出这条流。

adapter 的 `send` 返回一个 `Turn`，其中 `events: StreamEvent[]` 是**断言的唯一数据源**：`t.calledTool()`、`t.reply`、`toolOrder`、`noFailedActions`……全部从这条流上读。把你的 agent"这一轮做了什么"翻成这条流，整套断言就都能用。

## Turn：send 的返回值

```ts theme={null}
interface Turn {
  events: StreamEvent[];                          // 本轮事件,按真实发生顺序
  data?: unknown;                                 // 结构化输出 → outputEquals / outputMatches
  status: "completed" | "failed" | "waiting";     // waiting = 停下等人(HITL)
  usage?: { inputTokens: number; outputTokens: number };  // → maxTokens / maxCost / 成本报表
}
```

`data` 放结构化输出，不要序列化塞进 `events`；`usage` 拿得到就带，拿不到就不填——**别编数字**。

## 事件总表

| 事件                   | 说什么             | 消费它的断言 / API                                            |
| -------------------- | --------------- | ------------------------------------------------------- |
| `message`            | agent（或用户）说了一段话 | `t.reply`、`messageIncludes`、judge 的材料                   |
| `action.called`      | 发起一次工具调用        | `calledTool`、`toolOrder`、`maxToolCalls`、`notCalledTool` |
| `action.result`      | 该次调用的结果         | `calledTool` 的 `status` 匹配、`noFailedActions`            |
| `subagent.called`    | 委派一个子 agent     | `calledSubagent`                                        |
| `subagent.completed` | 子 agent 返回      | `calledSubagent` 的 `status`、`noFailedActions`           |
| `input.requested`    | 停下来等人输入（HITL）   | `t.parked()`、`t.requireInputRequest()`                  |
| `thinking`           | 思考文本            | `event("thinking")`、view 展示                             |
| `compaction`         | 上下文被压缩          | `event("compaction")`（需声明 `compactionObservability`）    |
| `error`              | 本轮出错            | `event("error")`、view 展示                                |

任何事件都能被通用断言消费：`event(type)` / `notEvent(type)` / `eventOrder(types)` / `eventsSatisfy(label, predicate)`。

## 逐事件说明

### `message` —— 说了什么

```ts theme={null}
{ type: "message", role: "assistant" | "user", text: string }
```

每段助手文本吐一条 `role: "assistant"` 的 `message`。**工具结果不是助手消息**——不要把工具输出包成 `message`，否则 `t.reply` 会读到错误内容。用户输入的 `message` 由 NiceEval 自动记录，adapter 不用吐。

### `action.called` / `action.result` —— 调了什么工具、结果如何

```ts theme={null}
{ type: "action.called", callId: string, name: string, input: JsonValue }
{ type: "action.result", callId: string, output?: JsonValue,
  status: "completed" | "failed" | "rejected" }
```

* 每个 `action.called` 配一个**同 `callId`** 的 `action.result`——并发调用靠它不错配。你的 agent 返回里有显式 id（AI SDK 的 `toolCallId`、Anthropic 的 `tool_use.id`）就直接用；实在没有再按顺序合成。
* `status` 如实填：工具执行失败是 `"failed"`（`noFailedActions()` 会响）；**人否决是 `"rejected"`**（`noFailedActions()` 依然通过，`calledTool(..., { status: "rejected" })` 可精确断言）。两回事，别混。
* `name` 用工具的原始名字。

### `subagent.called` / `subagent.completed` —— 委派了谁

```ts theme={null}
{ type: "subagent.called", callId: string, name: string, remoteUrl?: string }
{ type: "subagent.completed", callId: string, output?: JsonValue,
  status: "completed" | "failed" }
```

被测系统把任务委派给子 agent（等它返回）时吐这一对，`callId` 配对规则同上。喂 `calledSubagent("researcher")` 这类断言。

### `input.requested` —— 停下等人（HITL）

```ts theme={null}
{ type: "input.requested", request: {
    id?: string,
    action?: string,        // 停在哪个动作上(如工具名)
    input?: JsonValue,      // 该动作的入参
    prompt?: string,        // 问人的问题
    options?: { id: string, label?: string }[],   // 可选项(approve / deny…)
} }
```

agent 停轮等人时，每个待回答的问题吐一条，同时整轮 `status` 返回 `"waiting"`。`t.requireInputRequest(filter)` 的 filter 逐字段匹配这个 `request`——**能填的字段尽量填**，否则 eval 侧筛选不到。接法见[接入教程的 HITL 部分](/zh/guides/connect-your-agent)。

### `thinking` / `compaction` / `error`

```ts theme={null}
{ type: "thinking", text: string }
{ type: "compaction", reason?: string }   // 上下文压缩;吐它才声明 compactionObservability
{ type: "error", message: string }
```

有就吐，没有不硬造。`compaction` 主要来自 coding agent CLI（上下文满了自动压缩）。

## 映射的三条纪律

1. **时序即事实**：事件按真实发生顺序排。`toolOrder` / `eventOrder` 靠子序匹配，顺序错了断言就失真。
2. **`callId` 配对**：每个 `called` 都要有同 id 的 `result`，缺一半会让 `calledTool(..., { status })` 匹配不上。
3. **完整性**：声明了 `toolObservability: true` 就意味着**所有**工具调用都在流里。只吐一部分时，`notCalledTool` / `maxToolCalls` 这类负断言会静默通过——没有报错，比失败更难发现。手工映射做不到完整就[不要声明这个能力](/zh/reference/capabilities)。

## 一个完整的映射示例

agent 返回里带步骤记录时，映射就是一段小循环：

```ts theme={null}
import type { StreamEvent } from "niceeval";

function toStreamEvents(body: MyBotResponse): StreamEvent[] {
  const events: StreamEvent[] = [];
  for (const step of body.steps) {
    if (step.type === "tool_call") {
      events.push({ type: "action.called", callId: step.id, name: step.tool, input: step.args });
      events.push({
        type: "action.result",
        callId: step.id,
        output: step.result,
        status: step.error ? "failed" : "completed",
      });
    }
    if (step.type === "text") events.push({ type: "message", role: "assistant", text: step.text });
  }
  return events;
}
```

## 相关阅读

* [接入你的 agent](/zh/guides/connect-your-agent) —— 从零跑通的教程。
* [能力位](/zh/reference/capabilities) —— 声明"事件流是完整的"意味着什么。
* [编写 eval](/zh/guides/authoring) —— 消费这条流的断言全集。
