# JAC-1.1 侏罗纪AI通信标准（Jurassic AI Communication Standard）

**文档编号**：JAC-SPEC-1.1
**状态**：正式发布（Release）
**发布机构**：侏罗纪AI标准工作组（Jurassic AI Standard Working Group, JASWG）
**发布日期**：2026-09-05
**版本**：1.1（正式版；在 JAC-1.0 基础上并入文件传输扩展，原扩展文档 JAC-EXT-FT-1.0 自本版起并入并废止）

**依循基础标准**：
- RFC 6455 —— The WebSocket Protocol（唯一传输基础）
- RFC 8259 —— The JavaScript Object Notation (JSON) Data Interchange Format
- RFC 2119 / RFC 8174 —— 规范性用语
- Chat Completions API 惯例 —— 工具定义与流式增量格式兼容

**与 JAC-1.0 的差异（本版增补，全部向下兼容）**：

| # | 增补内容 | 落点 |
|---|---|---|
| 1 | **双向文件传输**：`file.offer/accept/reject/ack/complete/cancel` 控制面消息 + `file.data` 二进制数据帧，credit 窗口流控、SHA-256 校验、断点续传、终态状态机 | §9.5（新增章） |
| 2 | 能力声明 `server_caps` 新增 `"file.transfer"`；能力协商失败时按 §5.2 忽略降级 | §4.5、§9.5 |
| 3 | 错误码新增 4403~4406 | 附录A |
| 4 | 一致性等级 L2/L3 纳入文件传输能力 | §13 |
| 5 | 关闭语义、心跳、子协议 `jac.v1`、既有消息类型**均不变**（线上与 JAC-1.0 完全互通） | 全文 |

**版本摘要**：本标准定义运行于 WebSocket 之上的侏罗纪AI（JAI）实体间 JSON 应用层协议，核心特性：
1. 一条会话 = 一条 WebSocket 连接；
2. 会话上下文（环境、可用工具、代码模块）一次声明、终身有效；
3. 纯流式输出（无非流式模式）；
4. 工具定义与流式增量兼容 Chat API；
5. 模型思考过程（thinking）流式披露，深度可设置（effort / depth）；
6. 三级 Token 与消息统计（chunk 快照 / turn 明细 / 会话累计）；
7. **双向文件传输（credit 流控 + SHA-256 校验 + 断点续传）**。

---

## 目录

1. 范围与术语
2. 核心模型
3. 传输层要求
4. 会话建立与上下文声明
5. 消息格式
6. 消息类型注册表
7. 用户消息
8. 工具定义与工具调用
9. 代码模块、多模态分块与文件传输
10. 流式输出、思考字段与统计
11. 心跳、超时与关闭
12. 安全要求
13. 一致性等级与符合性测试
14. 附录A：错误码注册表
15. 附录B：完整会话示例（含文件传输）
16. 附录C：与 Chat API 字段映射表
17. 附录D：基础标准条款对照

---

## 1. 范围与术语

### 1.1 范围

本标准规定运行于 WebSocket（RFC 6455）之上的侏罗纪AI（JAI）实体间 JSON 应用层协议（下称 **JAC 协议**），包括：

- 连接建立、上下文声明与能力协商；
- 会话推进：用户消息、流式输出、工具调用、代码模块执行、多模态传输；
- 模型思考过程的披露与深度控制；
- Token 与消息统计；
- **会话内双向文件传输**（1.1 新增）；
- 心跳、超时、关闭、安全与一致性要求。

本标准**不**规定：模型内部实现、训练协议、服务发现机制、底层 TLS 密码套件细节。

### 1.2 核心原则

| # | 原则 | 规范落点 |
|---|---|---|
| P1 | **一连接一会话**：打开连接即创建会话，关闭连接即销毁会话 | §2、§11 |
| P2 | **上下文一次声明**：环境、可用工具、代码模块仅在首条消息声明 | §4.3 |
| P3 | **会话五要素**：环境、可用工具、代码模块、用户消息、工具调用输出 | §2、§7、§8 |
| P4 | **纯流式**：assistant 输出只有流式增量一种交付方式 | §10.1 |
| P5 | **Chat API 兼容**：工具定义、流式增量、思考字段与 Chat Completions API 互通 | §4.4、§8、附录C |
| P6 | **思考可控**：思考过程可披露（thinking 流），深度可设置（effort/depth） | §4.3、§10.2、§10.3 |
| P7 | **统计完备**：chunk 快照 → turn 明细 → 会话累计 | §10.4、§10.5 |
| P8 | **文件可控传输**（1.1 新增）：控制面 JSON + 数据面二进制、credit 流控、完整性校验、可续传、可取消 | §9.5 |

### 1.3 术语

| 术语 | 定义 |
|---|---|
| JAI 实体 | 实现本标准的 AI 客户端或服务端节点 |
| 会话（Session） | 一次完整对话上下文，与一条 WebSocket 连接一一对应 |
| 上下文声明 | 会话首条消息 `session.declare`（环境 + 工具 + 模块） |
| turn（轮次） | 一次 user.message 到 assistant.done 的完整交互 |
| thinking（思考） | 模型生成最终回复前的推理过程文本 |
| effort / depth | 思考投入档位（minimal/low/medium/high）/ 数值深度（0~10） |
| 生效深度（effective） | 服务端钳制/降级后本轮实际采用的深度 |
| usage 快照 | chunk 内携带的截至该 seq 的累积用量 |
| session_usage | 自会话建立以来的累计用量 |
| 文件传输（File Transfer） | 会话内以 file.* 消息族进行的双向文件交换（1.1 新增） |
| file_id | 一次文件传输的唯一标识，发起方生成，终态后不得复用 |
| credit | 接收方授予发送方的数据块发送配额（文件传输流控） |
| DID | 实体标识，`did:jai:<hex>` |
| Chat API | Chat Completions 类 API 的工具定义/消息/流式增量惯例 |

### 1.4 规范性用语

MUST / MUST NOT / SHOULD / MAY 按 RFC 2119 / RFC 8174 解释。

---

## 2. 核心模型

```
┌────────────────────── 一条 WebSocket 连接 ──────────────────────┐
│ [打开]                                                            │
│   C→S  session.declare    （环境 + 工具 + 模块 + reasoning 配置，    │
│                            仅此一次）                                │
│   S→C  session.ready      （accepted_tools、生效深度、统计策略、      │
│                             server_caps 含 file.transfer?）         │
│                                                                  │
│ [会话推进]（turn 循环）                                             │
│   C→S  user.message       （可含轮次级 reasoning 覆盖）              │
│   S→C  assistant.chunk ×n   （thinking / content / tool_calls 增量， │
│                             节流 usage 快照）                       │
│   S→C  tool.call → C→S tool.output（可循环，深度恒定）             │
│   S→C  assistant.chunk ×n …                                       │
│   S→C  assistant.done      （usage + stats + session_usage +        │
│                             effective_reasoning）                  │
│                                                                  │
│ [文件传输]（与会话推进并行，双向，1.1 新增）                          │
│   发起方 file.offer → 接收方 file.accept（credit）                   │
│        → file.data ×n（二进制帧，credit 窗口）                       │
│        → file.ack ×k（流控/续传基线）                                │
│        → file.complete（SHA-256 终态确认）                          │
│   任意时刻 file.cancel / file.reject 可终止                          │
│                                                                  │
│ [关闭]                                                            │
│   双向 session.end → WebSocket Close                              │
└──────────────────────────────────────────────────────────────────┘
```

强制约束：

- 一条连接上 MUST 只有唯一会话；第二条 `session.declare` MUST 触发 `error(4002)` 并关闭（关闭码 4002）；
- 环境、工具、模块 MUST NOT 在后续消息中重复完整声明；工具变更仅可走 §8.5 的 `tool.update` 增量操作；
- 服务端 MUST 以流式增量交付全部 assistant 输出（P4）；
- `session.ready` 之前收到的其他消息类型 MUST 被拒绝（`error 4001`）；
- 文件传输与会话推进并行进行，同一连接复用；文件传输不改变 turn 语义。

---

## 3. 传输层要求

### 3.1 连接与握手

- 端点 MUST 按 RFC 6455 §4 完成握手，子协议协商：

  ```
  Sec-WebSocket-Protocol: jac.v1
  ```

  服务端 MUST 回显同值；不回显时客户端 SHOULD 视为不支持本标准并关闭。
  （注：1.1 不升级子协议，文件传输经 `server_caps` 能力声明协商，保证与 JAC-1.0 线上互通。）

### 3.2 帧与 JSON

- JAC 控制面消息 MUST 使用 WebSocket **文本帧**（opcode=0x1），载荷为 UTF-8 编码的 JSON，遵循 RFC 8259（含 §8.1 互操作性约束：UTF-8 合法性、对象键唯一）；
- 单条消息（含分片重组后）MUST NOT 超过 `max_msg_bytes`（服务端在 ready 中声明，默认 4 MiB）；超长消息 SHOULD 使用 RFC 6455 §5.4 continuation 分片发送；
- 二进制帧（opcode=0x2）仅用于：① 多模态分块数据（§9.4）；② 文件传输数据 `file.data`（§9.5，1.1 新增）；二者首块前 MUST 有对应的 JSON 控制消息；
- 根对象 MUST 为 JSON 对象且 MUST 含字符串字段 `"type"`；键名 snake_case；接收方 MUST 忽略未知字段（前向兼容）。

### 3.3 URI

```
wss://<authority>/jac/v1/session
```

- 跨网络通信 MUST 使用 `wss://`（TLS 1.2+，SHOULD TLS 1.3）；明文 `ws://` 仅限内网测试域。

---

## 4. 会话建立与上下文声明

### 4.1 时序

1. 完成 TCP/TLS 与 WebSocket 握手（子协议 `jac.v1`）；
2. 客户端 MUST 在 **5 秒内**发送 `session.declare`（超时关闭码 4001）；
3. 服务端 MUST 回复 `session.ready`（成功）或 `error`（失败后关闭连接）。

### 4.2 session.declare（会话内仅一次）

```json
{
  "type": "session.declare",
  "msg_id": 1,
  "did": "did:jai:9f3c01a2",
  "auth": { "kind": "jwt", "token": "..." },
  "session": {
    "session_id": "s-7f21",
    "model": "jurassic-1.1-tyranno",
    "time_format": "ms",
    "reasoning": {
      "expose": "always",
      "effort": "medium",
      "depth": 5,
      "include_tokens": true
    }
  },
  "environment": {
    "runtime": "node-22",
    "os": "linux",
    "locale": "zh-CN",
    "tz": "Asia/Shanghai",
    "cwd": "/workspace",
    "limits": { "max_tokens_per_turn": 8192, "deadline_ms": 60000 },
    "metadata": { "client_version": "jai-sdk/1.1" }
  },
  "tools": [
    {
      "type": "function",
      "function": {
        "name": "search_fossil",
        "description": "检索化石数据库",
        "parameters": {
          "type": "object",
          "properties": {
            "era": { "type": "string" },
            "query": { "type": "string" }
          },
          "required": ["query"]
        }
      }
    }
  ],
  "modules": [
    {
      "module_id": "mod-render",
      "kind": "code",
      "language": "python",
      "uri": "jacmodule://repo/render.py",
      "hash": "sha256:1a2b…",
      "exports": ["render_scene", "RenderConfig"]
    }
  ]
}
```

| 字段 | 必要性 | 说明 |
|---|---|---|
| `type` | MUST | 固定 `"session.declare"` |
| `msg_id` | MUST | 客户端消息序号，会话内单调递增 |
| `did` | SHOULD | 客户端实体标识 |
| `auth` | SHOULD | 认证凭据（§12） |
| `session` | MUST | 会话参数：`session_id`、`model`、`time_format`、`reasoning` |
| `environment` | MUST | 当前运行环境（runtime/os/locale/tz/cwd/limits…），子键可自由扩展 |
| `tools` | MUST（可为空数组） | 全部可用工具，**会话内只声明这一次**（格式见 §4.4） |
| `modules` | SHOULD | 可引用的代码模块清单（§9.1） |

### 4.3 reasoning 声明（思考披露与深度）

| 字段 | 取值 | 说明 |
|---|---|---|
| `expose` | `"always"`（默认）/ `"on_done"` / `"never"` | 思考披露策略：流式下发 / 仅 done 摘要 / 不下发 |
| `effort` | `"minimal"` / `"low"` / `"medium"`（默认）/ `"high"` | 会话级思考投入档位（Chat API 对齐） |
| `depth` | 整数 0~10（可选，侏罗纪扩展） | 数值思考深度，与 effort 等价换算或并用 |
| `include_tokens` | bool（默认 true） | 思考 token 是否计入 `thinking_tokens` |

**effort ↔ depth 换算规则**（服务端 MUST 按此归一）：

| effort | 等价 depth |
|---|---|
| `minimal` | 0（不思考） |
| `low` | 2 |
| `medium` | 5 |
| `high` | 8 |

- 两者同时提供且矛盾时以 `depth` 为准，服务端 SHOULD 在 ready 的 `notices` 中说明；
- 仅提供 `depth` 时反向折算：{0}→minimal，{1..3}→low，{4..6}→medium，{7..10}→high；
- depth 9~10（"深渊级思考"）为本标准扩展区间，仅数值深度服务端可用；
- **单调性约束**：深度越高，思考资源投入 MUST NOT 减少；
- 校验：非法枚举或 depth 超出 0~10 → `error(4306)`；
- 模型不支持思考时 effort/depth MUST 被忽略，ready 回 `reasoning: false` 并附 notice；
- 服务端上限低于请求深度时 MUST 钳制并在 ready 回报生效值，MUST NOT 静默降级。

### 4.4 tools 字段规范（Chat API 兼容）

- `tools` 数组每一项 MUST 为：

  ```json
  { "type": "function",
    "function": {
      "name": "<标识符>",
      "description": "<描述>",
      "parameters": { "<JSON Schema Draft 2020-12>" },
      "strict": false
    } }
  ```

- `function.name`：MUST，`^[a-zA-Z0-9_-]{1,64}$`；
- `function.description`：SHOULD；
- `function.parameters`：MUST，顶层 SHOULD 为 `{"type":"object",…}`；
- `function.strict`：MAY，严格 schema 输出模式；
- JAC 私有扩展（`timeout_ms`/`safety` 等）收纳于可选 `jac_ext` 对象，Chat API 网关忽略未知键即天然兼容；

  ```json
  { "type": "function", "function": { … },
    "jac_ext": { "timeout_ms": 30000, "safety": "read_only" } }
  ```

### 4.5 session.ready

```json
{
  "type": "session.ready",
  "msg_id": 1,
  "corr_id": 1,
  "epoch": 42,
  "max_msg_bytes": 4194304,
  "heartbeat_ms": 15000,
  "first_chunk_deadline_ms": 2000,
  "accepted_tools": ["search_fossil"],
  "accepted_modules": ["mod-render"],
  "stream_only": true,
  "reasoning": true,
  "reasoning_field": "thinking",
  "reasoning_effort": {
    "effective_effort": "medium",
    "effective_depth": 5,
    "max_effort": "high",
    "max_depth": 10,
    "depth_granularity": 1
  },
  "usage_interval_chunks": 30,
  "server_caps": ["stream", "thinking", "reasoning.effort", "reasoning.depth",
                  "usage.snapshot", "tool.call", "tool_update", "module.exec",
                  "mm.chunk", "file.transfer"]
}
```

| 字段 | 说明 |
|---|---|
| `accepted_tools` / `accepted_modules` | 服务端确认接受的清单；MAY 剔除不支持项并在 `notices` 说明原因；剔除致空且会话强依赖工具 SHOULD 以 `error(4102)` 拒绝 |
| `stream_only` | 恒为 `true`，明示本标准纯流式语义 |
| `reasoning` | 服务端是否产生思考流（bool） |
| `reasoning_field` | 本会话思考字段实际用名：`"thinking"`（本标准）或 `"reasoning_content"`（Chat API 别名），全会话恒定，客户端 MUST 按此解析 |
| `reasoning_effort` | 会话级生效深度（钳制后）、服务端上限（`max_effort`/`max_depth`/`depth_granularity`） |
| `usage_interval_chunks` | usage 快照节流间隔（帧数） |
| `server_caps` | 能力声明；**1.1 起包含 `"file.transfer"` 表示支持 §9.5 文件传输**；实现 MUST 如实声明，虚报视为不合格 |

---

## 5. 消息格式

### 5.1 通用信封

```json
{
  "type": "<消息类型>",
  "msg_id": 123,
  "corr_id": 100,
  "ts": 1735689600000,
  "payload": { }
}
```

| 字段 | 必要性 | 说明 |
|---|---|---|
| `type` | MUST | 字符串，见第 6 章注册表 |
| `msg_id` | MUST | 发送方各自的会话内单调递增序号 |
| `corr_id` | SHOULD | 响应/输出类必填，等于触发消息的 `msg_id` |
| `ts` | SHOULD | 按 `time_format` 约定 |
| `payload` | MUST | 类型相关载荷对象 |

### 5.2 通用规则

- 接收方 MUST 忽略未知字段；未知 `type` MUST 忽略该消息并 SHOULD 回 `notice(2010)`；
- 响应与输出的 `corr_id` MUST 精确等于触发方消息的 `msg_id`；
- 帧序即语义序：会话内消息按 WebSocket 帧顺序交付，无重排、无重发；断线即会话终结（§11.3）；
- 重放防护：`msg_id` 单调 + `ts` 窗口 ±120 s（§12）。

---

## 6. 消息类型注册表

| type | 方向 | 帧类型 | 说明 |
|---|---|---|---|
| `session.declare` | C→S | text | 上下文声明（环境+工具+模块+reasoning），会话内仅一次 |
| `session.ready` | S→C | text | 确认、生效配置与能力（含 file.transfer?） |
| `session.end` | 双向 | text | 正常结束，可带 `reason` |
| `user.message` | C→S | text | 用户消息（可含轮次级 reasoning 覆盖） |
| `assistant.chunk` | S→C | text | 流式增量（唯一输出模式）：`delta.thinking` / `delta.content` / `delta.tool_calls`，可选累积 `usage` 快照 |
| `assistant.done` | S→C | text | 流终止：`usage` + `stats` + `session_usage` + `effective_reasoning` |
| `tool.call` | S→C | text | 工具调用执行请求（完整已解析参数） |
| `tool.output` | C→S | text | 工具调用输出（role=tool 语义） |
| `tool.update` | 双向 | text | 工具清单增量变更（可选能力） |
| `module.load` | 双向 | text | 请求/确认装载代码模块 |
| `module.exec` | S→C | text | 请求在模块命名空间内执行 |
| `module.result` | C→S | text | 模块执行结果 |
| `mm.begin` / `mm.end` | 双向 | text | 多模态分块传输控制 |
| `file.offer` | 双向 | text | 文件传输发起：元数据声明（1.1） |
| `file.accept` | 双向 | text | 接收方同意（credit、resume_from）（1.1） |
| `file.reject` | 双向 | text | 接收方拒绝（1.1） |
| `file.ack` | 双向 | text | 接收方流控确认与续传基线（1.1） |
| `file.complete` | 双向 | text | 接收方 SHA-256 终态确认（1.1） |
| `file.cancel` | 双向 | text | 任一方取消（1.1） |
| `mm.data` | 双向 | **binary** | 多模态分块数据 |
| `file.data` | 双向 | **binary** | 文件数据块（1.1，格式见 §9.5.4） |
| `ping` / `pong` | 双向 | text | 应用层心跳（pong 可携带统计摘要） |
| `notice` / `error` | 双向 | text | 通知 / 错误 |

---

## 7. 用户消息

### 7.1 user.message

```json
{
  "type": "user.message",
  "msg_id": 5,
  "payload": {
    "turn": 3,
    "role": "user",
    "content": "帮我检索白垩纪的暴龙化石记录",
    "reasoning": { "effort": "high" }
  }
}
```

多模态 content（Chat API parts 数组）：

```json
{
  "type": "user.message",
  "msg_id": 6,
  "payload": {
    "turn": 4,
    "role": "user",
    "content": [
      { "type": "text", "text": "这块化石是什么？" },
      { "type": "image_url", "image_url": { "url": "jacmm://mm-asset-01" } }
    ]
  }
}
```

- `role` 恒为 `"user"`；客户端 MUST NOT 伪造 assistant/system 历史注入（历史由服务端维护）；
- `content` 为 string 或 parts 数组（`text`/`image_url` 等，未知 part MUST 忽略）；`image_url.url` 支持 `data:`、`https:`、`jacmm://<mm_id>`（通道内资产）；
- `turn` 单调递增，服务端据此维护历史；
- **`payload.reasoning`（可选）**：轮次级深度覆盖，字段与 §4.3 相同；仅对本 turn 生效，下一 turn 自动回落到 ready 确认的会话默认；非法值 → `error(4306)`，本 turn 拒绝执行；超上限时服务端 MUST 钳制并在 done 的 `clamped: true` 明示；
- done（非 `tool_calls` 终止）后才接受下一轮 `user.message`，提前到达默认拒绝 `error(4202)`。

### 7.2 一轮（turn）的构成

```
user.message（可含 reasoning 覆盖）
 └─ assistant.chunk ×n     （thinking → content / tool_calls，节流 usage 快照）
     [finish_reason:"tool_calls"] → tool.call → tool.output
                                 →（继续同 turn 流式，深度恒定）
 └─ assistant.done         （usage + stats + session_usage + effective_reasoning）
```

一轮 MUST 以 `assistant.done` 终止（除非 `error` 或连接关闭）。

---

## 8. 工具定义与工具调用

### 8.1 声明一次原则

- 工具集合在 `session.declare.tools`（§4.4 格式）一次性声明；
- 会话期间 `tool.call` 只能引用 `accepted_tools` 中的 `function.name`，引用未声明工具 MUST 回 `error(4301)`。

### 8.2 流式 tool_calls 增量（assistant.chunk 内）

```json
{
  "type": "assistant.chunk",
  "msg_id": 41,
  "corr_id": 5,
  "payload": {
    "turn": 3,
    "seq": 7,
    "delta": {
      "role": "assistant",
      "tool_calls": [
        { "index": 0, "id": "call_abc123", "type": "function",
          "function": { "name": "search_fossil",
                        "arguments": "{\"era\":" } }
      ]
    }
  }
}
```

- 拼接规则（Chat API 同构）：同 `index` 标识一个工具调用槽；首帧含 `id`/`type`/`function.name` 与 `arguments` 首段，后续帧仅含 `arguments` 增量段；客户端按 `seq` 顺序拼接得完整 JSON 参数。

### 8.3 tool.call（执行请求）

```json
{
  "type": "tool.call",
  "msg_id": 45,
  "corr_id": 5,
  "payload": {
    "tool_call_id": "call_abc123",
    "function": {
      "name": "search_fossil",
      "arguments": { "era": "cretaceous", "query": "tyrannosaurid" }
    },
    "deadline_ms": 30000
  }
}
```

- `tool_call_id` 与流式增量中的 `id` 一致；`arguments` 为已解析 JSON 对象（客户端可只依赖本消息执行，无需自行拼接）；
- 一轮 MAY 并发多个 `tool.call`，以 `tool_call_id` 区分；
- 客户端 MUST 在 `deadline_ms`（默认 30 s，`jac_ext.timeout_ms` 可覆盖）内回复，超时按 `timeout` 处理；
- 每轮工具调用深度默认上限 8，超过 MUST 以 `error(4302)` 终止本轮（会话不关闭）。

### 8.4 tool.output

```json
{
  "type": "tool.output",
  "msg_id": 6,
  "corr_id": 45,
  "payload": {
    "role": "tool",
    "tool_call_id": "call_abc123",
    "content": "{\"hits\": 2, \"records\": [\"FMNH PR2081\", \"AMNH 5027\"]}"
  }
}
```

- 对齐 Chat API `role:"tool"` 消息：`tool_call_id` + `content`（string，JSON 序列化文本或纯文本）；
- 执行失败时 `content` 携带错误描述并附加 `"error": {"code","message"}` 扩展键；
- 服务端 MUST 将 tool.output 并入会话上下文，作为后续生成的可见信息。

### 8.5 tool.update（增量变更，可选能力）

```json
{ "type": "tool.update", "msg_id": 12,
  "payload": { "op": "add",
    "tools": [ { "type": "function",
                 "function": { "name": "map_pangea", "description": "…",
                               "parameters": { } } } ] } }
```

- `op`：`add` / `remove` / `replace`，均为增量操作；条目格式同 §4.4；
- 仅双方声明 `tool_update` 能力时可用，否则 MUST 回 `error(4102)`；
- MUST NOT 用于替代 `session.declare` 的首次声明。

---

## 9. 代码模块、多模态分块与文件传输

### 9.1 模块清单

`session.declare.modules` 每项：`module_id`（MUST）、`language`（MUST）、`uri` 或内联 `source`（二选一）、`hash`（SHA-256，SHOULD）、`exports`（SHOULD）。

### 9.2 module.load / 模块校验

```json
{ "type": "module.load", "msg_id": 50, "payload": { "module_id": "mod-render" } }
```

- 客户端以二进制帧分块返回源码，或小模块直接在应答中携带 `source`；
- 接收方校验 `hash`，不符 MUST 回 `error(4401)`。

### 9.3 module.exec / module.result

```json
{ "type": "module.exec", "msg_id": 51, "corr_id": 5,
  "payload": { "exec_id": "e-1", "module_id": "mod-render",
               "entry": "render_scene", "args": { "scene": "jurassic_night" } } }

{ "type": "module.result", "msg_id": 9, "corr_id": 51,
  "payload": { "exec_id": "e-1", "status": "ok", "value": { "png": "mm-asset-07" } } }
```

- 执行于会话声明的 `environment` 沙箱内；超时/异常以 `status:"error"` + `error` 字段描述；
- 服务端 MUST NOT 请求超出 `exports` 清单的符号；模块 MUST NOT 获得 environment 之外的系统权限；
- 大型结果 SHOULD 走多模态分块通道。

### 9.4 多模态分块

- `mm.begin`：声明 `mm_id`、`mime`、`total_bytes`、`sha256`；
- `mm.data`：WebSocket 二进制帧（opcode=0x2），每块 ≤ 256 KiB，前 16 字节为 `mm_id` 哈希前缀；
- `mm.end`：接收方校验长度与指纹，失败回 `error(4402)`（可经 extensions `resend-from` 请求重传）。

### 9.5 文件传输（1.1 新增）

会话内**双向文件传输**：上传（C→S）与下载（S→C）使用同一套消息，方向由发起方决定。能力经 `server_caps: ["file.transfer"]` 声明；未声明即不支持，对端 MUST 降级为不发起（或按 §5.2 忽略并回 `notice(2010)`）。

设计原则：控制面 JSON 文本帧、数据面二进制帧；credit 窗口流控；SHA-256 端到端校验；可续传、可取消；同一连接与会话推进并行复用。

#### 9.5.1 消息族与流程

```
发起方                              接收方
   │ file.offer ─────────────────────────▶│
   │◀────────────── file.accept(credit) ──│ （或 file.reject）
   │ file.data ×n（二进制，credit 窗口内）  │
   │◀────────── file.ack(bytes, credit) ──│ （周期性）
   │ file.data … 直至发满 size             │
   │◀────────────── file.complete(ok) ────│ （SHA-256 校验后）
   （任意时刻任一方可 file.cancel）
```

#### 9.5.2 file.offer（发起方 → 接收方）

```json
{
  "type": "file.offer",
  "msg_id": 30,
  "payload": {
    "file_id": "f-9c2e",
    "name": "t-rex-scan.ply",
    "size": 10485760,
    "mime": "application/octet-stream",
    "sha256": "1a2b3c…",
    "chunk_size": 262144,
    "direction": "upload",
    "meta": { "scan_date": "2026-08-30" }
  }
}
```

| 字段 | 必要性 | 说明 |
|---|---|---|
| `file_id` | MUST | 发起方生成的传输唯一标识（会话内唯一，建议 UUID） |
| `name` | MUST | 文件名（UTF-8，禁止路径分隔符；接收方 MUST 只取 basename，防路径穿越） |
| `size` | MUST | 总字节数（>0） |
| `mime` | SHOULD | MIME 类型，默认 `application/octet-stream` |
| `sha256` | SHOULD | 全文件 SHA-256（十六进制小写）；提供时接收方完成校验，未提供时 `file.complete.status` 恒为 `"ok"`（仅长度校验） |
| `chunk_size` | MUST | 数据块字节数，范围 [4096, 262144]，默认 262144 |
| `direction` | MUST | `"upload"`（发起方为客户端）或 `"download"`（发起方为服务端），仅作元信息 |
| `meta` | MAY | 自由扩展键值；续传时可携带 `meta.resume: {token\|from}` |

约束：同一 `file_id` 未终态（complete/cancel/failed）前 MUST NOT 复用（违反回 `error(4404)`）；并发传输数建议 ≤ 4，超出接收方 MAY `file.reject{reason:"too_many"}`。

#### 9.5.3 file.accept / file.reject（接收方 → 发起方）

```json
{ "type": "file.accept", "msg_id": 31, "corr_id": 30,
  "payload": { "file_id": "f-9c2e", "credit": 8,
               "resume_from": 0, "resume_token": null } }

{ "type": "file.reject", "msg_id": 32, "corr_id": 30,
  "payload": { "file_id": "f-9c2e", "reason": "disk_full" } }
```

- 接收方 MUST 在 `file.offer` 后 30 s 内回 `file.accept` 或 `file.reject`；超时未回，发起方以 `file.cancel` 结束；
- `credit`：初始信用（允许发送的数据块数，§9.5.5）；`resume_from`：续传起始偏移（0 为全新）；`resume_token`：MAY，接收方断点令牌（opaque），发起方须在续传 offer 的 `meta.resume` 中原样带回；
- `reject.reason` 建议值：`disk_full` / `permission` / `too_many` / `policy` / `unsupported` / 自定义。

#### 9.5.4 file.data（数据面，二进制帧 opcode=0x2）

```
+----------------------+----------------+--------------------+
| 8B file_id 哈希前缀    |  4B seq（网络序） |  4B data_len（网络序）|
+----------------------+----------------+--------------------+
|                     data (≤ chunk_size)                  |
+----------------------------------------------------------+
```

| 字段 | 说明 |
|---|---|
| file_id 哈希前缀 | `file_id` 的 SHA-256 前 8 字节（控制面 MAY 携带 `file_prefix` 便于调试配对） |
| seq | 块序号，从 0 单调递增（`resume_from > 0` 时从对应块号续起） |
| data_len | 本块字节数（最后一块可小于 chunk_size） |
| data | 原始字节（不嵌套 JSON） |

- 接收方按 seq 缓冲重排，**连续**字节数才计入 ack 基线；重复块丢弃；
- 丢失块不逐块 NACK：接收方以 ack 连续基线 + 续传策略处理；
- 数据块不计入 `max_msg_bytes`（JSON 限额仅约束控制面）。

#### 9.5.5 流控（credit 窗口）

- 每收到一次 `file.ack{bytes_received, credit}`，发送方信用恢复为 `ack.credit`（窗口默认 8 块 = 2 MiB @256 KiB）；
- `bytes_received` 为**连续**已落盘字节数，同时是续传基线；
- credit 为 0 时发送方 MUST 等待；超过 60 s MAY `file.cancel{reason:"stalled"}`（`error 4406`）；
- ack SHOULD 周期性发送（每 8~16 块或 500 ms），MUST NOT 逐块发送；
- 文件传输 credit 独立于 §10.1 assistant 流式 credit。

#### 9.5.6 file.complete / file.cancel（终态）

```json
{ "type": "file.complete", "msg_id": 36, "corr_id": 30,
  "payload": { "file_id": "f-9c2e", "status": "ok",
               "bytes_received": 10485760, "sha256_verified": true } }

{ "type": "file.cancel", "msg_id": 37,
  "payload": { "file_id": "f-9c2e", "reason": "user_abort" } }
```

- 接收方收满 `size` 后 MUST 校验并发送 `file.complete`：`status: "ok"` 或 `"failed"`（SHA-256 失败，附 `error: {code:4403}`）；终态后 `file_id` 不得复用；
- `file.cancel` 任一方可发（reason：`user_abort`/`stalled`/`policy`…）；接收方应清理半成品（或保留 `.jacpart` 供续传，经 `meta` 声明）。

#### 9.5.7 断线与恢复

1. 传输中途断线：`file_id` 随会话销毁；接收方实现 MAY 保留 `.jacpart` 并生成 `resume_token`；
2. 重连后的新会话中，发起方重发 `file.offer`（同 sha256/size，`meta.resume: {token|from}`），接收方以 `file.accept{resume_from, resume_token}` 续传；
3. 端点 SHOULD 限定续传令牌有效期（建议 ≤ 24 h）。

#### 9.5.8 与既有机制的关系

| 既有机制 | 关系 |
|---|---|
| §9.4 多模态分块 | mm 通道面向模型输入资产；文件传输是通用文件语义（落盘/续传/流控/终态），二者共存，`jacmm://` 可引用已传输文件 |
| §10.1 流式 credit | 相互独立，各自计数 |
| §5.2 未知类型忽略 | 未支持本能力的端点自然降级 |

---

## 10. 流式输出、思考字段与统计

### 10.1 纯流式约束

- 服务端 MUST 以 `assistant.chunk` 增量交付全部输出；**不存在非流式响应消息类型**；
- 首 chunk MUST 在 `first_chunk_deadline_ms`（默认 2000 ms；高深度时服务端 MAY 在 ready 声明放宽值，如 depth ≥ 8 用 8000 ms）内发出，可为空增量心跳帧；超时 `error(4203)`；
- `payload.seq` 本轮内单调递增，客户端据此保序去重（断裂 `error 4204`）；
- 合并节奏 SHOULD 为 20~50 ms 或 8~32 token；
- `delta.role` 仅首 chunk 携带（`"assistant"`）；
- 背压：客户端 MAY 携带 `extensions.credit: n`（可接收 chunk 配额）；服务端发满 n 个 MUST 暂停，直至新 credit 或 2×heartbeat 自动补半；持续背压 > 60 s 任一方 MAY 以关闭码 4020 关闭。

### 10.2 模型思考字段（S→C）

```json
{
  "type": "assistant.chunk",
  "msg_id": 20,
  "corr_id": 5,
  "payload": {
    "turn": 3,
    "seq": 2,
    "delta": { "thinking": "先确认用户要的是白垩纪暴龙科标本，需要调用检索工具…" }
  }
}
```

1. **字段名**：正式字段 `delta.thinking`，Chat API 兼容别名 `reasoning_content`；`session.ready.reasoning_field` 声明本会话实际用名（恒定，MUST NOT 混用），客户端 MUST 按该字段解析；实现 MUST 同时具备两个字段名的解析能力；
2. **披露策略**：由 `session.reasoning.expose` 控制（`always`/`on_done`/`never`）；`on_done` 时 done MAY 携带 `thinking_summary`；
3. **流式语义**：thinking 增量与 content 同构，按 `seq` 拼接；通常先于 content/tool_calls 出现，MAY 交错或同帧共存；
4. **呈现与隔离**：客户端 SHOULD 与最终回复视觉区分；thinking 不计入正文，MUST NOT 作为上下文回传；
5. `expose:"never"` 时出现 thinking 字段客户端 MUST 忽略（实现缺陷），冲突回 `error(4305)`。

### 10.3 思考深度生效语义

1. **优先级**：`user.message.payload.reasoning`（轮次覆盖）> `session.declare.session.reasoning`（会话默认）> 服务端默认（`medium`/depth 5）；
2. **工具循环内恒定**：同一 turn 内（含 `tool_calls` 续流）生效深度不变；
3. **钳制透明**：请求深度超服务端上限时钳制并在 done 的 `clamped: true` 明示；静默降级为不合格实现；
4. **与 thinking 流关系**：`minimal`/depth 0 时 thinking 流通常为空或极短；
5. **与统计关系**：不同深度思考 token 均计入 `thinking_tokens`（`include_tokens: true` 时）；
6. **中途变更**：会话级默认 MUST NOT 中途变更（重连即新会话）；仅轮次级覆盖可逐轮变化。

### 10.4 assistant.done（终帧与统计）

```json
{
  "type": "assistant.done",
  "msg_id": 65,
  "corr_id": 5,
  "payload": {
    "turn": 3,
    "finish_reason": "stop",
    "usage": {
      "prompt_tokens": 812,
      "completion_tokens": 214,
      "thinking_tokens": 96,
      "total_tokens": 1122
    },
    "effective_reasoning": {
      "effort": "high",
      "depth": 8,
      "clamped": false
    },
    "stats": {
      "chunks": 37,
      "thinking_chunks": 11,
      "content_chunks": 26,
      "tool_calls": 1,
      "mm_bytes": 0,
      "file_bytes": 0,
      "first_chunk_ms": 640,
      "elapsed_ms": 5210
    },
    "session_usage": {
      "turns": 3,
      "prompt_tokens": 2140,
      "completion_tokens": 620,
      "thinking_tokens": 233,
      "total_tokens": 2993,
      "tool_calls": 4
    }
  }
}
```

| 字段组 | 内容 | 必要性 |
|---|---|---|
| `finish_reason` | `"stop"` / `"tool_calls"` / `"length"` / `"abort"` / `"error"`；`tool_calls` 表示等待 tool.output 后**继续同 turn 流式输出** | MUST |
| `usage` | 本轮 token 明细：`prompt_tokens` / `completion_tokens`（不含 thinking）/ `thinking_tokens`（分离计数）/ `total_tokens`（三者之和） | MUST |
| `effective_reasoning` | 本轮实际生效深度（`effort`+`depth` 双表示）与 `clamped` 钳制标志 | SHOULD（L3 必备） |
| `stats` | 消息统计：`chunks` / `thinking_chunks` / `content_chunks` / `tool_calls` / `mm_bytes` / **`file_bytes`（1.1 新增，本 turn 期间文件传输字节数）** / `first_chunk_ms` / `elapsed_ms` | SHOULD（L1 起必备） |
| `session_usage` | 会话累计：`turns` / 各类 token / `tool_calls`；以最后一次 done 为准 | SHOULD |

### 10.5 chunk 级 usage 快照（节流）

```json
{
  "type": "assistant.chunk",
  "msg_id": 21,
  "corr_id": 5,
  "payload": {
    "turn": 3,
    "seq": 31,
    "delta": { "content": "……" },
    "usage": { "prompt_tokens": 812, "completion_tokens": 120,
               "thinking_tokens": 96, "total_tokens": 1028 }
  }
}
```

- 快照为截至该 seq 的**本轮累积值**（非增量）；
- 节流：每 `usage_interval_chunks` 帧（默认 30）或 ≥1 s 一次；MUST NOT 每帧都发；最后一帧前 MUST 至少一次快照；
- 客户端 MUST 以 `assistant.done.usage` 为权威值，快照仅用于进度展示；非累积/回退回 `error(4205)`。

---

## 11. 心跳、超时与关闭

### 11.1 定时器

| 定时器 | 默认值 | 说明 |
|---|---|---|
| declare 超时 | 5000 ms | 关闭码 4001 |
| heartbeat_ms | 15000 | 应用层 ping/pong |
| 心跳超时 | 2 × interval | 判定半开，客户端 SHOULD 重连（新会话） |
| 工具 deadline | 30000 ms | `tool.call.deadline_ms` 覆盖 |
| 文件 accept 超时 | 30000 ms | 发起方以 cancel 结束（§9.5.3） |
| 文件 credit 停滞 | 60000 ms | cancel reason:`stalled`（§9.5.5） |
| first_chunk deadline | 2000 ms（高深度可放宽） | 超时 `error(4203)` |
| 空闲超时 | 1800 s | 关闭码 4003 |

- `pong` MAY 携带轻量统计摘要（`last_seq`、累积 usage）供客户端对账。

### 11.2 正常关闭

- 任一方 MUST 先发 `session.end`（可带 `reason`），再执行 RFC 6455 关闭握手（Close 帧携带本标准关闭码）；关闭前所有进行中的文件传输视为取消；
- 连接关闭即会话终结；服务端 MAY 异步留存化石记录用于审计（默认 30 天）。

### 11.3 故障语义

- 连接与会话 1:1，断线即会话中断；恢复 = 新建连接 + 新会话；
- 客户端 MAY 在新会话 `user.message` 中引用旧 `session_id` 与 `turn` 号由服务端业务层续接历史（协议层不承诺）；
- 文件传输可凭 §9.5.7 的 resume 机制在新会话续传。

### 11.4 WebSocket 关闭码（RFC 6455 §7.4.2 私有区间 4000-4999）

| 码 | 含义 |
|---|---|
| 4000 | 正常结束（session.end 后） |
| 4001 | declare 超时/非法 |
| 4002 | 重复 session.declare |
| 4003 | 会话空闲超时 |
| 4004 | 子协议/能力协商失败 |
| 4010 | 认证失败 |
| 4020 | 消息超限/持续背压 |
| 4030 | JSON 解析或协议结构错误 |

---

## 12. 安全要求

1. **传输加密**：跨网络 MUST TLS 1.2+（SHOULD TLS 1.3）；禁用 RC4/3DES/SHA-1 套件；
2. **认证**：`session.declare.auth` 三选一按强度降序：mTLS（证书指纹）、短期 JWT（aud = 服务 authority，exp ≤ 10 min）、预共享密钥挑战（内网）；
3. **重放防护**：`msg_id` 单调 + `ts` 窗口 ±120 s，超窗丢弃并 `notice(2030)`；
4. **校验与限额**：服务端 MUST 校验 `function.parameters`（JSON Schema）、`tool.output.content`、`max_msg_bytes`、轮次并发与 token 配额（以 `session_usage` 为计量依据，超限 `error(4503)`）；
5. **工具安全**：`jac_ext.safety`（`read_only`/`side_effect`/`destructive`）SHOULD 由客户端执行器强制校验；
6. **模块沙箱**：代码模块执行 MUST 沙箱化，限于 `environment` 声明的权限面；
7. **思考内容敏感性**：thinking 可能含服务端内部策略或未脱敏中间推理，服务端 SHOULD 脱敏审查后披露；客户端 MUST NOT 将 thinking 转发第三方（除非会话方明示授权）；
8. **深度滥用防护**：高深度请求消耗不成比例算力，服务端 MAY 按账户/会话限制最大可用深度与单位时间高深度轮次配额（超限钳制并 `clamped: true`，或 `error(4503)`）；
9. **文件传输安全**（1.1 新增）：
   - 文件名 MUST 只取 basename，禁止路径分隔符与 `..`，落盘 MUST 限定在声明目录内（防路径穿越）；
   - 接收方 MUST 强制单会话并发传输上限与磁盘配额；MAY 按文件大小/MIME 策略拒绝（`file.reject{reason:"policy"}`）；
   - 未校验完成的文件 MUST 以临时名（如 `.jacpart`）存放，校验通过后方可重命名生效；
   - 跨信任域的文件传输 MUST 复用会话 TLS；MAY 对敏感文件在应用层再加密（本标准不规定具体算法）。

---

## 13. 一致性等级与符合性测试

### 13.1 等级

| 等级 | 名称 | 必备能力 |
|---|---|---|
| L0 | 化石级 | 握手+子协议 `jac.v1`、declare/ready、**纯流式输出（含首 chunk 时限）**、ping/pong |
| L1 | 迅猛龙级 | tool_calls 增量拼接、tool.call/output、done 的 usage+stats+session_usage、关闭码语义 |
| L2 | 霸王龙级 | thinking 流式披露（双字段解析）、reasoning.effort 档位（会话级）、chunk 级 usage 快照、代码模块、多模态分块、tool.update、**文件传输（offer/accept/data/ack/complete + credit 流控 + SHA-256 校验）** |
| L3 | 沧龙级 | reasoning.depth 数值深度（轮次覆盖+钳制透明）、**文件断点续传（resume_from/resume_token）与并发多文件**、背压 credit、沙箱强校验、深度配额、完整错误码矩阵 |

实现 MUST 在 `session.ready.server_caps` 中如实声明，虚报视为不合格实现。

### 13.2 强制测试项（摘要）

1. **握手**：子协议协商、declare 超时、重复 declare 触发 4002；
2. **编解码**：JSON 往返、超长分片重组、未知字段/未知 type 忽略；
3. **流式**：首 chunk 时限、seq 有序性、abort 语义、credit 用尽停发；
4. **工具**：声明一次原则（引用未声明工具回 4301）、增量拼接、deadline 超时、深度上限 4302；
5. **思考**：expose 三策略、thinking/reasoning_content 别名解析、effort↔depth 换算、轮次覆盖回落、钳制 clamped 标志、4306 非法值；
6. **统计**：usage 快照节流与单调、done 权威值、session_usage 累计正确性；
7. **文件传输**（1.1 新增）：offer→accept→data→complete 上传/下载往返与 SHA-256 校验；credit 窗口停发与 ack 补充；校验失败回 4403；file_id 复用回 4404；reject/too_many；中途 cancel；stalled 超时 4406；文件名 basename 清洗与落盘目录限定；
8. **安全**：明文拒绝跨域、token 过期、重放窗口、配额、thinking 转发禁令、文件路径穿越防护；
9. **关闭**：逐关闭码触发验证。

---

## 附录A：错误码注册表（error.payload.code）

| code | 含义 | 可重试 |
|---|---|---|
| 4001 | ready 前非法消息 | 重连 |
| 4002 | 重复 session.declare | 否 |
| 4101 | 模型不存在/不可用 | 否 |
| 4102 | 能力/工具不支持 | 否 |
| 4201 | 消息超 max_msg_bytes | 分片重发 |
| 4202 | 轮次时序非法 | 是 |
| 4203 | 首 chunk 超时 | 是 |
| 4204 | chunk seq 断裂/乱序 | 是（重建会话） |
| 4205 | usage 快照非累积/回退 | 是（以 done 为准） |
| 4301 | 引用未声明工具 | 否 |
| 4302 | 工具循环超限 | 是 |
| 4303 | 工具参数 schema 校验失败 | 是 |
| 4304 | tool_calls 增量拼接非法 | 是 |
| 4305 | thinking 字段与 expose 策略冲突 | 忽略字段 |
| 4306 | reasoning effort/depth 值非法 | 是（修正重发） |
| 4401 | 模块哈希不符 | 是 |
| 4402 | 多模态指纹/长度校验失败 | 是 |
| 4403 | 文件 SHA-256 校验失败 | 是（重传） |
| 4404 | file_id 重复/状态非法 | 否 |
| 4405 | 文件被接收方拒绝（reason 详见 file.reject） | 视 reason |
| 4406 | 文件传输停滞（credit 长期为 0） | 是 |
| 4501 | 认证失败 | 否 |
| 4502 | 授权不足 | 否 |
| 4503 | 配额超限（含高深度配额） | 延迟 |
| 4600 | 服务内部错误 | 是 |

## 附录B：完整会话示例（含文件传输）

```
C→S {"type":"session.declare","msg_id":1,
     "session":{"session_id":"s-7f21","model":"jurassic-1.1-tyranno",
                "reasoning":{"expose":"always","effort":"medium","depth":5}},
     "environment":{"runtime":"node-22","os":"linux","locale":"zh-CN"},
     "tools":[{"type":"function","function":{
        "name":"search_fossil","description":"检索化石数据库",
        "parameters":{"type":"object","properties":{
          "query":{"type":"string"}},"required":["query"]}}}],
     "modules":[]}

S→C {"type":"session.ready","msg_id":1,"corr_id":1,"epoch":42,
     "accepted_tools":["search_fossil"],"stream_only":true,
     "reasoning":true,"reasoning_field":"thinking",
     "reasoning_effort":{"effective_effort":"medium","effective_depth":5,
                         "max_effort":"high","max_depth":10,"depth_granularity":1},
     "usage_interval_chunks":30,
     "server_caps":["stream","thinking","reasoning.effort","reasoning.depth",
                    "usage.snapshot","tool.call","file.transfer"]}

-- 例1：常规推理轮次（同 JAC-1.0，略，见正式版 1.0 附录B） --

-- 例2：客户端向服务端上传扫描件（与会话推进并行） --
C→S {"type":"file.offer","msg_id":30,
     "payload":{"file_id":"f-9c2e","name":"t-rex-scan.ply",
                "size":10485760,"mime":"application/octet-stream",
                "sha256":"1a2b3c…","chunk_size":262144,
                "direction":"upload","meta":{"scan_date":"2026-08-30"}}}
S→C {"type":"file.accept","msg_id":40,"corr_id":30,
     "payload":{"file_id":"f-9c2e","credit":8,"resume_from":0,"resume_token":null}}
C→S (binary) [8B sha256("f-9c2e")[:8]|4B seq=0|4B len=262144|data]
C→S (binary) [ … seq=1..7 … ]                        -- 信用窗口内连发
S→C {"type":"file.ack","msg_id":41,
     "payload":{"file_id":"f-9c2e","bytes_received":2097152,"credit":8}}
C→S (binary) [ … seq=8.. 续发，直至发满 10485760 字节 … ]
S→C {"type":"file.complete","msg_id":42,
     "payload":{"file_id":"f-9c2e","status":"ok",
                "bytes_received":10485760,"sha256_verified":true}}

-- 例3：模型请求下载生成的报告（服务端发起） --
S→C {"type":"file.offer","msg_id":50,
     "payload":{"file_id":"f-d41a","name":"fossil-report.pdf",
                "size":327680,"mime":"application/pdf",
                "sha256":"9f8e7d…","chunk_size":262144,
                "direction":"download"}}
C→S {"type":"file.accept","msg_id":20,"corr_id":50,
     "payload":{"file_id":"f-d41a","credit":8,"resume_from":0}}
S→C (binary) [8B sha256("f-d41a")[:8]|4B seq=0|4B len=262144|data]
S→C (binary) [ … seq=1（尾块 len=65536）… ]
C→S {"type":"file.complete","msg_id":21,
     "payload":{"file_id":"f-d41a","status":"ok",
                "bytes_received":327680,"sha256_verified":true}}

C→S {"type":"session.end","msg_id":60,"payload":{"reason":"user_close"}}
-- WebSocket Close (4000) --
```

## 附录C：与 Chat API 字段映射表

| Chat Completions 概念 | JAC-1.1 对应 |
|---|---|
| `tools[{type:"function", function:{name,description,parameters}}]` | `session.declare.tools`（同构，一次声明） |
| `tool_choice` | 不适用（服务端策略）；可经 `jac_ext.tool_choice` 扩展 |
| `reasoning_effort: "low"\|"medium"\|"high"` | `session.reasoning.effort`（会话默认）/ `user.message.payload.reasoning.effort`（轮次覆盖）；额外支持 `"minimal"` |
| reasoning_effort 数值化（业界扩展） | `reasoning.depth`（0~10，含 9~10 扩展区间） |
| `messages[{role:"user", content}]`（string/数组） | `user.message.payload.{role, content}` |
| `messages[{role:"tool", tool_call_id, content}]` | `tool.output.payload.{role, tool_call_id, content}` |
| streaming delta `choices[0].delta.content` | `assistant.chunk.payload.delta.content` |
| streaming delta `choices[0].delta.tool_calls` | `assistant.chunk.payload.delta.tool_calls`（同构增量拼接） |
| delta `reasoning_content`（扩展） | `assistant.chunk.payload.delta.thinking`（正式字段；`reasoning_field` 声明实际用名，二者等价） |
| `choices[0].finish_reason` | `assistant.done.payload.finish_reason`（stop/tool_calls/length…） |
| `usage{prompt_tokens, completion_tokens, total_tokens}` | `assistant.done.payload.usage`（另增 `thinking_tokens`；Chat API 侧可丢弃该键） |
| `stream_options.include_usage` | 恒开启：done 必带 usage；chunk 快照为本标准扩展 |
| 跨请求累计计费 | `assistant.done.payload.session_usage`（本标准扩展） |
| 生效档位回报（无对应） | `assistant.done.payload.effective_reasoning`（本标准扩展，钳制透明） |
| content part `{type:"image_url", image_url:{url}}` | 同构；url 额外支持 `jacmm://` |
| 文件上传/下载（Files API 概念） | §9.5 file.* 消息族（会话内双向、流控、续传；Chat API 无直接对应，网关需映射） |
| HTTP 请求-响应轮次 | 长连接 turn；工具循环与深度覆盖均无需重发请求 |

## 附录D：基础标准条款对照

| 本标准章节 | 依循基础条款 | 义务 |
|---|---|---|
| 3.1 握手/子协议 | RFC 6455 §4（含 §4.1 Sec-WebSocket-Protocol 协商） | MUST |
| 3.2 文本帧 | RFC 6455 §5.2（opcode 0x1，UTF-8） | MUST |
| 3.2 分片 | RFC 6455 §5.4（continuation） | SHOULD |
| 3.2 JSON | RFC 8259（§8.1 互操作性约束） | MUST |
| 9.4/9.5 二进制帧 | RFC 6455 §5.2（opcode 0x2） | MUST（L2+） |
| 11.2 关闭握手 | RFC 6455 §5.5.1 / §7 | MUST |
| 11.4 关闭码 | RFC 6455 §7.4.2（4000-4999 注册区间） | MUST |

---

**变更管理**：JAC-1.1 相对 JAC-1.0 为向下兼容增补（子协议 `jac.v1` 不变，仅新增消息类型/字段/错误码，未修改、未删除既有语义），JAC-1.0 端点可与 JAC-1.1 端点直接互通。自本版起接口语义冻结：注册表后续增补须向下兼容（仅新增、不修改、不删除）。勘误与注册表增补提交 JASWG 技术委员会。

**路线图（评估中，不构成承诺）**：JAC-1.2 —— 断线会话恢复协议、思考深度自适应；JAC-2.0 —— QUIC/HTTP-3 承载（RFC 9220）、structured outputs 增强、思考过程端到端加密（E2EE thinking）、大文件分片并行传输（多连接聚合）。
