# 发送消息与任务系统（后台运行 + 轮询）

本节覆盖：

- 创建对话（工作区内，可选）：`POST /api/v1/workspaces/{workspace_id}/conversations`
- 发送消息（工作区内，创建后台任务）：`POST /api/v1/workspaces/{workspace_id}/messages`
- 轮询事件：`GET /api/v1/tasks/{task_id}?from=<offset>`
- 停止任务：`POST /api/v1/tasks/{task_id}/cancel`

重要限制：

- **单工作区禁止并发任务**：同一个 API 用户的同一个 workspace 同一时间只允许 1 个 `running/pending` 任务；否则返回 `409`。
- 不同 workspace 之间可以并行。

---

## 1) 创建对话（工作区内）

### POST `/api/v1/workspaces/{workspace_id}/conversations`

创建一个新的对话，并返回 `conversation_id`。

请求：

- Headers：`Authorization: Bearer <TOKEN>`
- Path：`workspace_id`
- Body：可选（JSON），用于在创建对话时绑定自定义 prompt / personalization（不传则使用默认）

Body(JSON，可选)：

```json
{
  "prompt_name": "prompt_strict",
  "personalization_name": "biz_mobile"
}
```

响应（200）：

```json
{
  "success": true,
  "workspace_id": "ws1",
  "conversation_id": "conv_20260123_234245_036"
}
```

常见错误：

- `400`：workspace_id 不合法
- `401`：缺少或无效 token
- `503`：系统未初始化（资源繁忙/容器不可用等）
- `500`：创建失败

---

## 2) 发送消息（工作区内，创建后台任务）

### POST `/api/v1/workspaces/{workspace_id}/messages`

创建一个后台任务执行智能体流程，并立即返回 `task_id`。

#### 请求

Headers：

- `Authorization: Bearer <TOKEN>`
- `Content-Type: application/json`

Path：

- `workspace_id`：工作区 id（必填）

Body(JSON)：

| 字段 | 类型 | 必填 | 说明 |
|---|---:|---:|---|
| `message` | string | 是（或 images） | 用户消息文本；`message` 与 `images` 至少其一不为空 |
| `conversation_id` | string | 否 | 不传则自动新建对话（在该 workspace 内） |
| `model_key` | string/null | 否 | 指定模型 key（可选）；具体可用值取决于服务端配置 |
| `run_mode` | string/null | 否 | 运行模式：`fast` \| `thinking` \| `deep` |
| `thinking_mode` | boolean/null | 否 | 兼容字段：true=thinking，false=fast；仅当 `run_mode` 为空时生效 |
| `max_iterations` | integer/null | 否 | 最大迭代次数，默认 **100**；传入可覆盖 |
| `prompt_name` | string/null | 否 | 自定义主 prompt 名称（用户级共享，见 `prompts_personalization.md`）；若不存在返回 404 |
| `personalization_name` | string/null | 否 | 个性化配置名称（用户级共享，见 `prompts_personalization.md`）；若不存在返回 404 |
| `images` | string[] | 否 | 图片路径列表（服务端可访问的路径）；一般配合特定模型使用 |

优先级：`run_mode` > `thinking_mode` > 终端当前配置。

#### 响应

成功（202）：

```json
{
  "success": true,
  "task_id": "60322db3-f884-4a1e-a9b3-6eeb07fbab47",
  "conversation_id": "conv_20260123_234245_036",
  "workspace_id": "ws1",
  "status": "running",
  "created_at": 1769182965.3038778
}
```

常见错误：

- `400`：`message/images` 都为空；或 `conversation_id` 无法加载
- `401`：缺少或无效 token
- `404`：prompt/personalization 不存在
- `409`：该 workspace 已有运行中的任务（禁止并发）
- `503`：系统未初始化/资源繁忙

---

## 3) 轮询任务事件（增量）

### GET `/api/v1/tasks/{task_id}?from=<offset>`

用于以 **HTTP 轮询**方式获取任务执行过程中的流式事件（与网页端 WebSocket 同粒度）。

#### 请求

- Headers：`Authorization: Bearer <TOKEN>`
- Query：
  - `from`：起始 offset（默认 0）

#### 响应（200）

```json
{
  "success": true,
  "data": {
    "task_id": "60322db3-f884-4a1e-a9b3-6eeb07fbab47",
    "workspace_id": "ws1",
    "status": "running",
    "created_at": 1769182965.30,
    "updated_at": 1769182968.15,
    "error": null,
    "events": [
      { "idx": 0, "type": "ai_message_start", "data": {}, "ts": 1769182965.30 },
      { "idx": 1, "type": "text_start", "data": {}, "ts": 1769182968.09 },
      { "idx": 2, "type": "text_chunk", "data": { "content": "我来", "index": 1, "elapsed": 0.0 }, "ts": 1769182968.15 }
    ],
    "next_offset": 3
  }
}
```

字段说明：

- `status`：任务状态，常见值：
  - `running`：执行中
  - `cancel_requested`：已请求停止，等待实际停下
  - `canceled`：已停止
  - `succeeded`：成功结束
  - `failed`：失败结束（`error` 会给出原因）
- `events`：从 `idx>=from` 的事件列表（按 idx 升序）
- `next_offset`：建议下一次轮询的 `from` 值

#### 推荐轮询策略

- 轮询间隔：`0.5s ~ 2s`（任务越密集越推荐更快）
- 客户端必须：
  1) 保存 `next_offset`
  2) 追加处理 `events`
  3) 当 `status != running` 时停止轮询

> 重要：服务端事件缓冲是 `deque(maxlen=1000)`，轮询过慢会丢失早期事件；客户端应自行落盘你需要的内容。

---

## 4) 停止任务

### POST `/api/v1/tasks/{task_id}/cancel`

请求停止某个任务。

请求：

- Headers：`Authorization: Bearer <TOKEN>`
- Body：无

成功（200）：

```json
{ "success": true }
```

说明：

- 该接口是“请求停止”，任务可能不会立刻停下；
- 停止后的最终状态以轮询结果为准（`status` 变为 `canceled` / `failed` / `succeeded`）。

