# Responses

OpenAI 的 Responses API,Codex CLI 默认走这个端点(`wire_api = "responses"`)。相比 Chat Completions,它更适合带工具、带推理、带多模态输入的智能体场景。

```text
POST https://api.clomio.ai/v1/responses
GET  https://api.clomio.ai/v1/responses        # Codex/WS v2 流入口,不是 HTTP 查询历史响应
# 兼容/直连别名:
POST https://api.clomio.ai/responses
POST https://api.clomio.ai/responses/{subpath}
GET  https://api.clomio.ai/responses           # 同样只用于 WebSocket Upgrade
POST https://api.clomio.ai/backend-api/codex/responses
POST https://api.clomio.ai/backend-api/codex/responses/{subpath}
GET  https://api.clomio.ai/backend-api/codex/responses  # Codex direct WebSocket 入口
```

> **分组要求:** **OpenAI、Grok 分组**支持 `POST /v1/responses`；OpenAI 和 Grok 也支持 `GET /v1/responses` WebSocket 入口。Claude 分组请用 [Messages](#/api-messages)。需要实时语音请用 [Voice](#/api-voice)。见 [端点 × 分组](#/api-usage)。
>
> **没有** `GET /v1/responses/{id}` 这个 HTTP 查询路由。`POST /v1/responses/*` 子路径会进入 Responses 处理（例如 compact），但历史查询/取回请不要写成 GET。多轮请在下一次 `POST /v1/responses` 中传 `previous_response_id`,或让 Codex 自己维护会话。

---

## 请求头

| 请求头 | 必填 | 值 |
|--------|:----:|-----|
| `Authorization` | 是 | `Bearer 你的密钥` |
| `Content-Type` | 是 | `application/json` |
| `Accept` | 否 | 流式可用 `text/event-stream` |

---

## 请求参数

### 服务处理的字段

| 参数 | 类型 | 必填 | 说明 |
|------|------|:----:|------|
| `model` | string | 是 | 模型名，以当前分组可见列表为准 |
| `input` | string/array | 通常必填 | 输入:可为一段文本,或结构化消息数组 |
| `stream` | boolean | 否 | `true` 时以 SSE 流式返回；如出现必须是 boolean，否则返回 400 `invalid stream field type` |
| `previous_response_id` | string | 否 | 接续上一次 Responses 响应,必须是 `resp_*`。不能用 Anthropic `msg_*`、Chat Completions `chatcmpl-*`、工具调用 id 或自定义会话 id。HTTP 请求中带工具结果时仍需携带可关联的 `call_id` / item 引用 |
| `max_output_tokens` | integer | 否 | 最大输出 token |
| `reasoning` | object | 否 | 推理设置,如 `{"effort":"high","summary":"auto"}`；具体值以模型支持范围为准 |
| `service_tier` | string | 否 | 服务层级提示,如 `priority` / `flex`;具体是否生效取决于分组与上游 |

### 常用透传字段

| 参数 | 类型 | 说明 |
|------|------|------|
| `instructions` | string | 系统级指令(相当于 system) |
| `temperature` | number | 随机性 |
| `top_p` | number | 核采样 |
| `tools` | array | 可用工具定义;支持 `function`、`web_search`、`image_generation` 等上游支持的类型 |
| `tool_choice` | string/object | 工具选择策略,如 `auto`、`required`、`{"type":"function","name":"..."}` |
| `parallel_tool_calls` | boolean | 是否允许并行工具调用 |
| `include` | array | 要求上游额外返回的字段,如推理加密内容/工具结果等 |
| `store` | boolean | 是否让上游存储响应;Codex 会话续接通常由客户端处理 |

### `input` 结构化写法

`input` 可以是字符串,也可以是数组。数组里常见 item:

| item / content 类型 | 用途 |
|------|------|
| `{ "role":"user", "content":"..." }` | 普通消息 |
| `content: [{"type":"input_text","text":"..."}]` | 多模态消息里的文本块 |
| `content: [{"type":"input_image","image_url":"https://..."}]` | 图片 URL / data URI |
| `content: [{"type":"input_file","file_id":"..."}]` | 已上传文件引用 |
| `content: [{"type":"input_file","file_data":"...","filename":"a.pdf"}]` | 内联文件数据 |
| `{ "type":"function_call_output", "call_id":"...", "output":"..." }` | 把工具执行结果交还给模型 |

> 工具结果的 `call_id` 必须能对应前一轮模型返回的函数调用。缺少 `call_id` 或缺少可关联 item 时,HTTP 路径会直接返回 400,不会盲目转给上游。手写 HTTP 工具结果建议同时带 `previous_response_id`、`item_reference` 和 `function_call_output.call_id`;只有 Codex/Responses WS v2 才能依赖会话上下文自动补齐更多引用。

### 请求边界

- 请求体不能为空且必须是合法 JSON。
- `model` 必须存在且为非空 string；`stream` 如出现必须是 boolean，否则返回 400 `invalid stream field type`。`input` 通常必填，缺失时会返回请求参数错误。
- `input`、`instructions`、`tools`、`tool_choice`、`reasoning`、`include`、`store`、`parallel_tool_calls` 等字段会按 OpenAI/Grok 兼容路径转发；字段组合、工具类型和多模态文件能力是否可用由所选上游判断。
- 不同模型对 `temperature`、`top_p`、`verbosity`、`reasoning`、`metadata` 等字段的支持不同；不支持的字段可能被忽略或返回 400。需要稳定兼容时只使用本页标注为模型支持的字段，并以错误响应为准。
- Responses 图片工具需要在 `tools` 中声明 `image_generation`。图片模型、尺寸和格式必须使用当前分组支持的组合；未开放图片能力时会返回 403，请改用普通文本模型或 Images 端点。
- `previous_response_id` 会参与续接；`POST /v1/responses/*` 子路径可用于兼容客户端的 Responses 子操作，但没有 `GET /v1/responses/{id}`。
- Grok 分组支持 `POST /v1/responses` 和 `GET /v1/responses` WebSocket 入口。需要原生语音会话时请使用 [Voice Realtime](#/api-voice)，不要把 Responses WebSocket 当成 Voice WebSocket。
- `GET /v1/responses` 不是普通 HTTP API。过鉴权且分组允许后，普通 HTTP GET 会返回 426 `WebSocket upgrade required (Upgrade: websocket)`；真正 WS 首帧必须在超时内到达、必须是 JSON，且必须包含 `model`。

### 常见请求错误

| HTTP | `error.type` | `message` | 来源 / 处理 |
|------|--------------|-----------|-------------|
| 400 | `invalid_request_error` | `Request body is empty` | 请求体为空 |
| 400 | `invalid_request_error` | `Failed to parse request body` | JSON 非法 |
| 400 | `invalid_request_error` | `model is required` | `model` 缺失、非 string 或空字符串 |
| 400 | `invalid_request_error` | `invalid stream field type` | `stream` 不是 boolean |
| 400 | `invalid_request_error` | `previous_response_id must be a response.id (resp_*), not a message id` | 把 Anthropic `msg_*` 或其它 ID 当 Responses 续接 ID 使用 |
| 400 | `invalid_request_error` | `function_call_output requires call_id on HTTP requests; continuation via previous_response_id is only supported on Responses WebSocket v2` | HTTP 工具结果必须带 `call_id`;不能只靠 `previous_response_id` 让网关回放工具上下文 |
| 400 | `invalid_request_error` | `function_call_output requires item_reference ids matching each call_id on HTTP requests; continuation via previous_response_id is only supported on Responses WebSocket v2` | HTTP 工具结果缺少可关联的 item 引用;改用完整 `call_id` / item_reference 或交给 Codex WS v2 |
| 400 | `invalid_request_error` | `Failed to normalize compact request body` | compact 子路径 body 规范化失败 |
| 413 | `invalid_request_error` | `Request body too large` / body 超限 | 请求体超过网关限制,缩小输入或改用文件/分片方案 |
| 403 | `permission_error` | `This group is restricted to Claude Code clients (/v1/messages only)` | Claude Code only 分组拒绝 Responses |
| 404 | `not_found_error` | `Responses WebSocket API is not supported for this platform` | 当前分组未开放 Responses WebSocket；OpenAI/Grok 分组通常可用 |
| 426 | `invalid_request_error` | `WebSocket upgrade required (Upgrade: websocket)` | 对 `GET /v1/responses` 发了普通 HTTP 请求；该入口只给 Codex/Responses WS 使用 |
| 404 | `model_not_found` | `No accounts are configured to support model ...` / `model not found` | 当前分组无法服务该模型；先查控制台分组模型列表和请求模型名，仍异常时带 `request_id` 提交工单 |
| 503 | `api_error` | `No available accounts` / `All available accounts exhausted` | 当前分组暂时没有可用服务能力，可能是并发、冷却、限流或自动切换后仍不可用；稍后重试，持续异常带 `request_id` 提交工单 |

---

## 响应

| 字段 | 类型 | 说明 |
|------|------|------|
| `id` | string | 响应 ID(可用于 `previous_response_id`) |
| `object` | string | `response` |
| `status` | string | `completed` / `incomplete` / `failed` |
| `model` | string | 实际模型 |
| `output` | array | 输出项数组(文本、推理、工具调用、联网搜索等) |
| `output_text` | string | 部分 SDK 汇总出的便捷字段:纯文本输出 |
| `usage` | object | `input_tokens` / `output_tokens` / `total_tokens`,可能含缓存/推理明细 |
| `incomplete_details` | object | `status=incomplete` 时给出原因,如 `max_output_tokens` |
| `error` | object | `status=failed` 时给出错误 |

流式时常见事件包括 `response.output_text.delta`、`response.function_call_arguments.delta`、`response.reasoning_summary_text.delta`、`response.completed`、`response.failed`、`response.cancelled` 等。**流已经开始后**的失败通常会以 SSE 事件返回,而不是 HTTP 状态码变化。

```json
{
  "id": "resp_xxx",
  "object": "response",
  "status": "completed",
  "model": "gpt-5.4",
  "output": [
    { "type": "message", "role": "assistant",
      "content": [{ "type": "output_text", "text": "你好!" }] }
  ],
  "output_text": "你好!",
  "usage": { "input_tokens": 8, "output_tokens": 5, "total_tokens": 13 }
}
```

---

## 最小可验证 curl

下面请求可验证 `POST /v1/responses`、`model`/`input` 基本形态和非流式响应；把 `stream` 改成字符串可验证 400 `invalid stream field type`。

常用负例也建议保存下来,用来区分“客户端拼错路径/字段”与“上游模型失败”:

```bash
# GET /v1/responses 是 WS Upgrade 入口,不是 REST 查询
curl -i https://api.clomio.ai/v1/responses \
  -H "Authorization: Bearer 你的密钥"

# stream 类型错误:400 invalid stream field type
curl https://api.clomio.ai/v1/responses \
  -H "Authorization: Bearer 你的密钥" \
  -H "Content-Type: application/json" \
  -d '{"model":"gpt-5.4","input":"ping","stream":"true"}'

# previous_response_id 不是 resp_*:400
curl https://api.clomio.ai/v1/responses \
  -H "Authorization: Bearer 你的密钥" \
  -H "Content-Type: application/json" \
  -d '{"model":"gpt-5.4","previous_response_id":"msg_abc","input":"continue"}'
```

## 示例:基础调用

```bash
curl https://api.clomio.ai/v1/responses   -H "Authorization: Bearer 你的密钥"   -H "Content-Type: application/json"   -d '{
    "model": "gpt-5.4",
    "input": "用一句话解释什么是 API"
  }'
```

```python
from openai import OpenAI
client = OpenAI(api_key="你的密钥", base_url="https://api.clomio.ai/v1")

resp = client.responses.create(model="gpt-5.4", input="用一句话解释什么是 API")
print(resp.output_text)
```

```javascript
import OpenAI from "openai";
const client = new OpenAI({ apiKey: "你的密钥", baseURL: "https://api.clomio.ai/v1" });

const resp = await client.responses.create({ model: "gpt-5.4", input: "用一句话解释什么是 API" });
console.log(resp.output_text);
```

---

## 示例:带指令、高推理和服务层级

```bash
curl https://api.clomio.ai/v1/responses   -H "Authorization: Bearer 你的密钥"   -H "Content-Type: application/json"   -d '{
    "model": "gpt-5.4",
    "instructions": "你是严谨的算法专家,只给要点。",
    "input": "如何在 O(n) 时间内找出数组里出现次数过半的元素?",
    "reasoning": { "effort": "high", "summary": "auto" },
    "service_tier": "priority",
    "max_output_tokens": 600
  }'
```

---

## 示例:流式

```bash
curl https://api.clomio.ai/v1/responses   -H "Authorization: Bearer 你的密钥"   -H "Content-Type: application/json"   -d '{ "model": "gpt-5.4", "input": "讲个一句话冷笑话", "stream": true }'
```

客户端累积 `response.output_text.delta` 的 `delta` 即可。若收到 `response.failed` / `response.cancelled`,应把事件中的错误展示给用户并停止等待。

---

## 示例:多模态输入

```bash
curl https://api.clomio.ai/v1/responses   -H "Authorization: Bearer 你的密钥"   -H "Content-Type: application/json"   -d '{
    "model": "gpt-5.4",
    "input": [{
      "role": "user",
      "content": [
        {"type":"input_text","text":"这张图适合做什么标题?"},
        {"type":"input_image","image_url":"https://example.com/cat.png"}
      ]
    }]
  }'
```

---

## 示例:工具调用与工具结果

第一轮让模型决定是否调用函数:

```json
{
  "model": "gpt-5.4",
  "input": "查一下订单 123 的物流状态",
  "tools": [{
    "type": "function",
    "name": "get_order_status",
    "description": "查询订单物流状态",
    "parameters": {
      "type": "object",
      "properties": { "order_id": {"type":"string"} },
      "required": ["order_id"]
    }
  }]
}
```

模型返回 `function_call` 后,执行工具,再把结果交回:

```json
{
  "model": "gpt-5.4",
  "previous_response_id": "resp_xxx",
  "input": [
    {"type":"item_reference","id":"call_abc"},
    {"type":"function_call_output","call_id":"call_abc","output":"已发货,预计明天送达"}
  ]
}
```

如果是手写 HTTP 请求,`function_call_output` 需要保留能匹配原始工具调用的 `call_id` / `item_reference`；只保存工具输出文本或只填 `previous_response_id` 会返回 400。WebSocket 会话通常会自动维护这些引用,手写脚本不要删字段。

---

## 示例:图像生成工具

如果模型/分组支持 Responses 内置图像工具,可通过 `tools` 触发生图;标准图片端点见 [Images](#/api-images)。仅声明 `tools` 是“可用能力”,强制本轮生图请配 `tool_choice` 或使用明确的图片意图;否则模型也可能只文本回答。

```json
{
  "model": "gpt-5.4",
  "input": "生成一张 1024x1024 的扁平插画:一只橘猫在写代码",
  "tools": [{
    "type": "image_generation",
    "size": "1024x1024",
    "quality": "high"
  }]
}
```

---

## 实战场景

### 场景:命令行问答小工具(流式 + 接续)

```python
from openai import OpenAI
client = OpenAI(api_key="你的密钥", base_url="https://api.clomio.ai/v1")

last_id = None
while True:
    q = input("\n你: ").strip()
    if q in ("exit", "quit", ""):
        break
    stream = client.responses.create(
        model="gpt-5.4",
        input=q,
        previous_response_id=last_id,
        stream=True,
    )
    print("AI: ", end="")
    for event in stream:
        if event.type == "response.output_text.delta":
            print(event.delta, end="", flush=True)
        elif event.type == "response.completed":
            last_id = event.response.id
        elif event.type in ("response.failed", "response.cancelled"):
            print("\n[失败]", event)
            break

```

---

> 这是 Codex 默认端点,客户端配置见 [Codex 接入](#/codex)。普通 OpenAI 风格聊天也可用 [Chat Completions](#/api-chat)。

## 字段约束速查

| 字段 | 可选值/范围 | 说明 |
|---|---|---|
| `model` | 当前分组 `/v1/models` 中的非空字符串 | 必填 |
| `input` | string 或 input/message/function_call 等数组 | 多模态时使用结构化数组 |
| `stream` | `true` / `false` | 流式返回 `response.*` 事件 |
| `max_output_tokens` | 正整数 | 输出上限；不传由模型/上游决定 |
| `reasoning.effort` | `none`/`minimal`/`low`/`medium`/`high`/`xhigh` | 是否支持取决于模型；不支持时删掉 |
| `tools[].type` | `web_search`、`x_search`、`image_generation`、`function` | Grok 搜索、图片工具和函数工具 |
| `tool_choice` | `auto`、`none`、`required` 或指定工具 | 控制工具调用策略 |
| `previous_response_id` | `resp_*` 字符串 | 用于多轮接续；不要传 message/event ID |
| `store` | `true` / `false` | 是否保存响应；是否可用取决于模型和分组 |
| `truncation` | `auto` / `disabled` | 仅支持该字段的路径使用；不支持时删除 |

## 完整响应与错误

成功非流式响应通常包含 `id`、`object:"response"`、`status`、`output[]` 和 `usage`；流式响应按事件类型处理，不要只按 Chat 的 `choices[].delta` 解析。

```json
{
  "id": "resp_example",
  "object": "response",
  "status": "completed",
  "output": [{"type":"message","role":"assistant","content":[{"type":"output_text","text":"OK"}]}],
  "usage": {"input_tokens": 10, "output_tokens": 2, "total_tokens": 12}
}
```

| HTTP/事件 | 典型错误 | 处理 |
|---|---|---|
| 400 | `model is required`、`input is required`、`invalid_request_error` | 检查模型、input 和字段类型 |
| 400 | `previous_response_id` 无效、`reasoning.mode` 不支持 | 使用 `resp_*`，删除当前模型不支持的字段 |
| 401/403 | Key 无效、分组不支持模型或工具 | 换正确分组/模型 |
| 404 | `No handler found on route` | 检查是否误用了视频、图片或其他非 Responses 路径 |
| 429 | `rate_limit_exceeded` | 读取 `Retry-After` 并指数退避 |
| 502/503 | `response.failed`、`No available accounts` | 保存完整失败事件和 `x-request-id` |

流式失败应处理 `response.failed`、`response.incomplete`、`response.cancelled`，不能只等待 TCP 断开。
