feat: 个人定制版 —— API Key 模式显示剩余积分 + 悬浮卡片
基于 @axiaohungry/dsh-llm-workbuddy 1.3.21 (MIT)。 详见 README.CUSTOM.md。
This commit is contained in:
commit
a44227b69a
14 files changed
+5517
No files matched your search
@@ -0,0 +1,579 @@
|
||||
# WorkBuddy API 调用开发文档
|
||||
|
||||
> 适用对象:需要在其他 Agent、CLI、IDE 插件或本地代理中接入 CodeBuddy 模型的开发者
|
||||
> 验证日期:2026-08-14
|
||||
> 验证客户端:`@tencent-ai/codebuddy-code 2.136.0`
|
||||
> 文档性质:基于已安装客户端、实际接口响应和本项目适配代码整理的第三方开发说明,不是腾讯官方 API 承诺。
|
||||
|
||||
## 1. 先说明名称关系
|
||||
|
||||
日常说的“调用 WorkBuddy API”实际包含两个不同角色:
|
||||
|
||||
| 名称 | 实际作用 |
|
||||
|---|---|
|
||||
| WorkBuddy | 提供或签发 API Key |
|
||||
| CodeBuddy | 使用该 Key 的 Agent/CLI 产品 |
|
||||
| `copilot.tencent.com` | 当前实际提供模型目录和推理接口的服务端 |
|
||||
| 本项目 | 把上述服务适配为 DSH Provider |
|
||||
|
||||
因此,当前观察到的调用链是:
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A["WorkBuddy 提供 API Key"] --> B["CodeBuddy 或第三方 Agent"]
|
||||
B --> C["GET /v3/config\n获取当前 Key 的模型权限"]
|
||||
B --> D["POST /v2/chat/completions\n发起模型推理"]
|
||||
C --> E["copilot.tencent.com"]
|
||||
D --> E
|
||||
```
|
||||
|
||||
不存在一个需要额外调用的“WorkBuddy 换取 CodeBuddy Token”步骤。开发者拿到有效 Key
|
||||
后,直接把它用于模型目录和聊天请求。
|
||||
|
||||
## 2. 重要边界
|
||||
|
||||
1. 接口目前不是公开、稳定承诺的开发者 API,路径、Header 和字段可能随 CodeBuddy 更新。
|
||||
2. 只能使用本人或组织授权的 API Key,不要绕过账号、额度、模型权限或企业策略。
|
||||
3. 模型列表与 API Key 绑定,不同 Key 返回的模型 ID 可能不同。
|
||||
4. 不要把模型目录写死在代码中;每次添加或替换 Key 后应重新获取 `/v3/config`。
|
||||
5. API Key 只能放在环境变量、凭据服务或 Secret Manager 中,不能提交到 Git。
|
||||
|
||||
## 3. 接口总览
|
||||
|
||||
| 用途 | 方法 | 地址 | 协议 |
|
||||
|---|---|---|---|
|
||||
| 获取模型与产品配置 | `GET` | `https://copilot.tencent.com/v3/config` | JSON |
|
||||
| 模型推理 | `POST` | `https://copilot.tencent.com/v2/chat/completions` | OpenAI Chat Completions 兼容,推荐 SSE 流式 |
|
||||
|
||||
当前不是 OpenAI Responses API,也不是 Anthropic Messages API。第三方 Agent 应优先实现
|
||||
`openai-completions` / Chat Completions 适配。
|
||||
|
||||
## 4. API Key 管理
|
||||
|
||||
推荐环境变量:
|
||||
|
||||
```text
|
||||
WORKBUDDY_API_KEY=<从 WorkBuddy 获取的 Key>
|
||||
```
|
||||
|
||||
Windows PowerShell 设置用户环境变量:
|
||||
|
||||
```powershell
|
||||
[Environment]::SetEnvironmentVariable(
|
||||
"WORKBUDDY_API_KEY",
|
||||
"<在本机填写,不要提交到仓库>",
|
||||
"User"
|
||||
)
|
||||
```
|
||||
|
||||
新进程才能读取新设置。不要在日志中输出 Key;诊断两个 Key 是否相同时,可以比较
|
||||
SHA-256 指纹,而不是打印明文。
|
||||
|
||||
本插件新版本使用 `WORKBUDDY_API_KEY`。为兼容旧版本,仍可读取 `CODEBUDDY_API_KEY`,但新
|
||||
项目建议统一改用前者。
|
||||
|
||||
## 5. 获取当前 Key 可用的模型
|
||||
|
||||
### 5.1 请求
|
||||
|
||||
```http
|
||||
GET /v3/config HTTP/1.1
|
||||
Host: copilot.tencent.com
|
||||
Accept: application/json
|
||||
X-API-Key: <API_KEY>
|
||||
User-Agent: CLI/unknown CodeBuddy/2.136.0
|
||||
X-Product: SaaS
|
||||
```
|
||||
|
||||
其中:
|
||||
|
||||
- `X-API-Key`:模型目录接口的关键鉴权 Header;
|
||||
- `User-Agent`:按当前 CodeBuddy CLI 行为填写,建议版本升级时同步验证;
|
||||
- `X-Product: SaaS`:标识当前产品部署类型;
|
||||
- Header 名大小写不敏感。
|
||||
|
||||
### 5.2 响应骨架
|
||||
|
||||
成功时 HTTP 通常为 `200`,同时还要检查业务字段 `code`:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"msg": "OK",
|
||||
"data": {
|
||||
"agents": [
|
||||
{
|
||||
"name": "cli",
|
||||
"models": ["hy3", "glm-5.3", "deepseek-v4-flash"]
|
||||
}
|
||||
],
|
||||
"models": [
|
||||
{
|
||||
"id": "deepseek-v4-flash",
|
||||
"name": "Deepseek-V4-Flash",
|
||||
"maxInputTokens": 1000000,
|
||||
"maxOutputTokens": 50000,
|
||||
"maxAllowedSize": 1000000,
|
||||
"supportsImages": true,
|
||||
"supportsReasoning": true,
|
||||
"onlyReasoning": true,
|
||||
"reasoning": {
|
||||
"effort": "high",
|
||||
"summary": "auto"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
示例只展示与适配有关的字段;实际响应还可能包含企业信息和产品功能开关。
|
||||
|
||||
### 5.3 正确的模型筛选算法
|
||||
|
||||
不能直接把 `data.models` 全部暴露给用户。正确流程是:
|
||||
|
||||
1. 在 `data.agents` 中找到 `name === "cli"` 的 Agent;
|
||||
2. 读取该 Agent 的 `models`,这是当前 Key 对 CLI 开放的模型 ID;
|
||||
3. 用这些 ID 与 `data.models[].id` 关联;
|
||||
4. 丢弃没有容量信息或没有对应配置的异常条目;
|
||||
5. 保留服务端顺序,避免客户端自行重排造成默认模型变化。
|
||||
|
||||
兼容旧响应时,可以同时检查:
|
||||
|
||||
```javascript
|
||||
const agents = Array.isArray(data.agents)
|
||||
? data.agents
|
||||
: data.agent?.agents;
|
||||
```
|
||||
|
||||
### 5.4 Node.js 获取模型示例
|
||||
|
||||
Node.js 22 以上可直接使用内置 `fetch`,不需要 SDK:
|
||||
|
||||
```javascript
|
||||
const apiKey = process.env.WORKBUDDY_API_KEY;
|
||||
if (!apiKey) throw new Error("缺少 WORKBUDDY_API_KEY");
|
||||
|
||||
const response = await fetch("https://copilot.tencent.com/v3/config", {
|
||||
headers: {
|
||||
accept: "application/json",
|
||||
"x-api-key": apiKey,
|
||||
"user-agent": "CLI/unknown CodeBuddy/2.136.0",
|
||||
"x-product": "SaaS",
|
||||
},
|
||||
signal: AbortSignal.timeout(20_000),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`模型目录 HTTP ${response.status}`);
|
||||
}
|
||||
|
||||
const body = await response.json();
|
||||
if (body?.code !== 0) {
|
||||
throw new Error(`模型目录业务错误:${body?.msg ?? body?.code}`);
|
||||
}
|
||||
|
||||
const agents = Array.isArray(body.data?.agents)
|
||||
? body.data.agents
|
||||
: body.data?.agent?.agents;
|
||||
const allowedIds = agents?.find((agent) => agent?.name === "cli")?.models ?? [];
|
||||
const byId = new Map((body.data?.models ?? []).map((model) => [model.id, model]));
|
||||
|
||||
const models = allowedIds.flatMap((id) => {
|
||||
const model = byId.get(id);
|
||||
if (!model) return [];
|
||||
const contextWindow = model.maxInputTokens ?? model.maxAllowedSize;
|
||||
const maxTokens = model.maxOutputTokens;
|
||||
if (!Number.isSafeInteger(contextWindow) || !Number.isSafeInteger(maxTokens)) return [];
|
||||
return [{
|
||||
id,
|
||||
name: model.name ?? id,
|
||||
contextWindow,
|
||||
maxTokens,
|
||||
supportsImages: model.supportsImages === true,
|
||||
supportsReasoning: model.supportsReasoning === true,
|
||||
onlyReasoning: model.onlyReasoning === true,
|
||||
defaultReasoningEffort: model.reasoning?.effort,
|
||||
thinkingLevelMap: model.thinkingLevelMap,
|
||||
thinkingFormat: model.thinkingFormat,
|
||||
}];
|
||||
});
|
||||
|
||||
console.table(models);
|
||||
```
|
||||
|
||||
## 6. 为什么不同账号看到的模型不同
|
||||
|
||||
`agents[name=cli].models` 是 Key 级别的授权结果,不是全平台公共目录。
|
||||
|
||||
2026-08-14 实测,同一台电脑上的两把有效 Key 返回了不同结果:
|
||||
|
||||
| 现象 | Key A | Key B |
|
||||
|---|---|---|
|
||||
| GLM 新版本 | 包含 `glm-5.3` | 最高为 `glm-5.2` |
|
||||
| MiniMax ID | `minimax-m3-pay` | `minimax-m3` |
|
||||
| Kimi ID | `kimi-k3-2` | `kimi-k3-1` |
|
||||
|
||||
因此,出现“CodeBuddy 能看到 `glm-5.3`,另一个 Agent 看不到”时,先确认两个程序实际使用
|
||||
的是不是同一把 Key。不要通过硬编码 `glm-5.3` 解决,否则请求阶段仍会被服务端拒绝。
|
||||
|
||||
## 7. 发起 Chat Completions 请求
|
||||
|
||||
### 7.1 请求地址
|
||||
|
||||
```text
|
||||
POST https://copilot.tencent.com/v2/chat/completions
|
||||
```
|
||||
|
||||
### 7.2 鉴权 Header
|
||||
|
||||
当前 CodeBuddy CLI 会为模型请求同时准备:
|
||||
|
||||
```http
|
||||
Authorization: Bearer <API_KEY>
|
||||
X-API-Key: <API_KEY>
|
||||
Content-Type: application/json
|
||||
Accept: text/event-stream
|
||||
```
|
||||
|
||||
本项目基于 OpenAI SDK 的适配路径使用 `Authorization: Bearer` 即可完成请求;为了更贴近
|
||||
CodeBuddy CLI 并兼容服务端策略变化,独立开发的新客户端建议同时发送 `Authorization`
|
||||
和 `X-API-Key`。不要把 Key 放进 URL Query。
|
||||
|
||||
CodeBuddy CLI 还会添加请求 ID、会话 ID、IDE 名称、产品类型等内部 Header。第三方开发的
|
||||
最小客户端不应伪造这些字段;只有在服务端明确要求时再增加。
|
||||
|
||||
### 7.3 最小请求体
|
||||
|
||||
```json
|
||||
{
|
||||
"model": "deepseek-v4-flash",
|
||||
"messages": [
|
||||
{ "role": "user", "content": "请只回复:连接成功" }
|
||||
],
|
||||
"stream": true,
|
||||
"stream_options": { "include_usage": true },
|
||||
"max_tokens": 1024
|
||||
}
|
||||
```
|
||||
|
||||
注意:
|
||||
|
||||
- 使用 `max_tokens`,不是 `max_completion_tokens`;
|
||||
- `model` 必须来自当前 Key 的 CLI 模型列表;
|
||||
- 推荐 `stream: true`,这是 CodeBuddy Agent 的主要工作模式;
|
||||
- `max_tokens` 不应超过目录中的 `maxOutputTokens`;
|
||||
- 输入和预期输出总量不能超过模型上下文限制。
|
||||
|
||||
## 8. 思考能力必须逐模型处理
|
||||
|
||||
不能为所有模型统一写死 `high`,也不能假设所有模型都支持 `xhigh` 或 `max`。至少读取:
|
||||
|
||||
| 字段 | 含义 | 处理方式 |
|
||||
|---|---|---|
|
||||
| `supportsReasoning` | 模型是否支持推理 | `false` 时不显示思考档位,不发送推理参数 |
|
||||
| `onlyReasoning` | 是否只能以推理模式工作 | `true` 时不提供 `off` |
|
||||
| `reasoning.effort` | 该模型的默认思考档位 | 用户未选择时使用;不要拿一个模型的默认值套给其他模型 |
|
||||
| `thinkingLevelMap` | UI 档位到线上参数的逐模型映射 | 存在时严格按映射提供选项和转换 |
|
||||
| `thinkingFormat` | 推理参数协议 | 存在时按该格式转换;缺失时才使用当前端点的兼容默认 |
|
||||
|
||||
当前实测就存在不同默认值:部分模型为 `high`,部分模型为 `medium`。
|
||||
|
||||
### 8.1 选择规则
|
||||
|
||||
1. 用户显式选择档位:发送该模型声明支持的档位;
|
||||
2. 用户选择“默认”或未选择:使用该模型自己的 `reasoning.effort`;
|
||||
3. 服务端没有声明默认值:省略思考参数,让服务端决定;
|
||||
4. `supportsReasoning === false`:删除所有推理参数;
|
||||
5. `onlyReasoning === true`:不要提供 `off`;
|
||||
6. `thinkingLevelMap` 存在:未出现在 Map 中的档位视为不支持;
|
||||
7. 不要自动把不支持的档位静默替换成另一个档位,最好在请求前报错。
|
||||
|
||||
### 8.2 OpenAI 风格
|
||||
|
||||
当前适配使用的默认格式是:
|
||||
|
||||
```json
|
||||
{
|
||||
"reasoning_effort": "medium"
|
||||
}
|
||||
```
|
||||
|
||||
常见候选值为:
|
||||
|
||||
```text
|
||||
minimal / low / medium / high / xhigh / max
|
||||
```
|
||||
|
||||
候选值不等于所有模型均支持。以当前模型的能力声明为准。
|
||||
|
||||
### 8.3 其他思考格式
|
||||
|
||||
如果未来目录返回不同 `thinkingFormat`,适配器可能需要转换,例如:
|
||||
|
||||
```json
|
||||
{ "reasoning": { "effort": "high" } }
|
||||
```
|
||||
|
||||
或:
|
||||
|
||||
```json
|
||||
{ "thinking": { "type": "enabled" }, "reasoning_effort": "high" }
|
||||
```
|
||||
|
||||
不要同时无条件发送所有格式。应为每个模型只生成一种服务端声明的格式。
|
||||
|
||||
## 9. 工具调用
|
||||
|
||||
请求中的工具遵循 OpenAI Chat Completions 格式:
|
||||
|
||||
```json
|
||||
{
|
||||
"tools": [
|
||||
{
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "get_weather",
|
||||
"description": "查询天气",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"city": { "type": "string" }
|
||||
},
|
||||
"required": ["city"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"tool_choice": "auto"
|
||||
}
|
||||
```
|
||||
|
||||
流式响应中的工具参数会分段出现在:
|
||||
|
||||
```text
|
||||
choices[0].delta.tool_calls[].function.arguments
|
||||
```
|
||||
|
||||
客户端必须按 `tool_calls[].index` 累积字符串,结束后再解析 JSON。执行工具后,把结果作为
|
||||
`role: "tool"`、带相同 `tool_call_id` 的消息加入下一轮请求。
|
||||
|
||||
## 10. 图片输入
|
||||
|
||||
只有 `supportsImages === true` 的模型才能接收图片。OpenAI 兼容格式示例:
|
||||
|
||||
```json
|
||||
{
|
||||
"role": "user",
|
||||
"content": [
|
||||
{ "type": "text", "text": "描述这张图片" },
|
||||
{
|
||||
"type": "image_url",
|
||||
"image_url": {
|
||||
"url": "data:image/png;base64,<BASE64>"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
发送前应限制文件大小和 MIME 类型,不要仅根据扩展名判断图片。
|
||||
|
||||
## 11. SSE 流式响应解析
|
||||
|
||||
服务端返回 `text/event-stream`。每个事件通常形如:
|
||||
|
||||
```text
|
||||
data: {"id":"...","choices":[{"delta":{"content":"你"}}]}
|
||||
|
||||
data: {"id":"...","choices":[{"delta":{"content":"好"},"finish_reason":"stop"}]}
|
||||
|
||||
data: [DONE]
|
||||
```
|
||||
|
||||
需要处理的字段:
|
||||
|
||||
| 字段 | 用途 |
|
||||
|---|---|
|
||||
| `choices[0].delta.content` | 最终回答文本增量 |
|
||||
| `choices[0].delta.reasoning_content` | 思考内容增量之一 |
|
||||
| `choices[0].delta.reasoning` | 部分模型使用的思考内容字段 |
|
||||
| `choices[0].delta.reasoning_text` | 另一种兼容思考字段 |
|
||||
| `choices[0].delta.tool_calls` | 工具调用增量 |
|
||||
| `choices[0].finish_reason` | `stop`、`length`、`tool_calls` 等结束原因 |
|
||||
| `usage` | Token 用量,通常在开启 `include_usage` 后的尾部 Chunk 返回 |
|
||||
|
||||
同一个 Chunk 可能没有 `choices`,只有 `usage`,不能因此判定响应异常。
|
||||
|
||||
## 12. 完整 Node.js 流式示例
|
||||
|
||||
```javascript
|
||||
const apiKey = process.env.WORKBUDDY_API_KEY;
|
||||
if (!apiKey) throw new Error("缺少 WORKBUDDY_API_KEY");
|
||||
|
||||
const response = await fetch("https://copilot.tencent.com/v2/chat/completions", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
authorization: `Bearer ${apiKey}`,
|
||||
"x-api-key": apiKey,
|
||||
"content-type": "application/json",
|
||||
accept: "text/event-stream",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
model: "deepseek-v4-flash",
|
||||
messages: [{ role: "user", content: "请只回复:连接成功" }],
|
||||
stream: true,
|
||||
stream_options: { include_usage: true },
|
||||
max_tokens: 1024,
|
||||
// reasoning_effort: "high", // 只在当前模型明确支持且用户选择时添加
|
||||
}),
|
||||
signal: AbortSignal.timeout(300_000),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const detail = await response.text();
|
||||
throw new Error(`推理接口 HTTP ${response.status}: ${detail.slice(0, 500)}`);
|
||||
}
|
||||
|
||||
const decoder = new TextDecoder();
|
||||
let buffer = "";
|
||||
let answer = "";
|
||||
let reasoning = "";
|
||||
|
||||
for await (const chunk of response.body) {
|
||||
buffer += decoder.decode(chunk, { stream: true });
|
||||
let boundary;
|
||||
while ((boundary = buffer.indexOf("\n\n")) !== -1) {
|
||||
const event = buffer.slice(0, boundary);
|
||||
buffer = buffer.slice(boundary + 2);
|
||||
|
||||
for (const line of event.split(/\r?\n/)) {
|
||||
if (!line.startsWith("data:")) continue;
|
||||
const data = line.slice(5).trim();
|
||||
if (!data || data === "[DONE]") continue;
|
||||
|
||||
const payload = JSON.parse(data);
|
||||
const delta = payload.choices?.[0]?.delta;
|
||||
if (typeof delta?.content === "string") {
|
||||
answer += delta.content;
|
||||
process.stdout.write(delta.content);
|
||||
}
|
||||
const thought = delta?.reasoning_content ?? delta?.reasoning ?? delta?.reasoning_text;
|
||||
if (typeof thought === "string") reasoning += thought;
|
||||
if (payload.usage) console.error("\nusage:", payload.usage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log("\n\nanswer:", answer);
|
||||
console.log("reasoning length:", reasoning.length);
|
||||
```
|
||||
|
||||
生产代码还需要按 `tool_calls[].index` 累积工具参数,并处理单个 SSE 事件跨网络 Chunk 的情况。
|
||||
|
||||
## 13. 错误处理与重试
|
||||
|
||||
### 13.1 模型目录
|
||||
|
||||
同时检查 HTTP 状态和 JSON 业务状态:
|
||||
|
||||
```javascript
|
||||
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
||||
if (body.code !== 0) throw new Error(body.msg ?? String(body.code));
|
||||
```
|
||||
|
||||
### 13.2 常见分类
|
||||
|
||||
| 情况 | 建议处理 |
|
||||
|---|---|
|
||||
| `401` / `403` | Key 无效、过期或无权限;停止重试并要求重新填写 |
|
||||
| `408` / 网络断开 | 指数退避重试 |
|
||||
| `429` | 遵守 `Retry-After`;提示额度或频率限制 |
|
||||
| `5xx` | 短暂退避后有限重试 |
|
||||
| 模型不在 CLI 列表 | 刷新目录,不要强制调用 |
|
||||
| 流结束但没有结束原因 | 视为不完整响应,不要保存为成功回答 |
|
||||
|
||||
流式请求只应在“尚未收到任何有效增量”时自动重试。收到文本或工具调用后再次自动重试,
|
||||
可能造成重复输出或重复执行工具。
|
||||
|
||||
### 13.3 推荐超时
|
||||
|
||||
- 模型目录:20 秒总超时;
|
||||
- 建立推理连接:30–60 秒;
|
||||
- 流空闲超时:300 秒;
|
||||
- 用户取消:通过 `AbortController` 立即向上游传播。
|
||||
|
||||
## 14. 缓存策略
|
||||
|
||||
模型目录可以按 Key 指纹缓存,但不能跨 Key 共用:
|
||||
|
||||
```text
|
||||
cache key = SHA-256(API Key) + 客户端产品类型
|
||||
```
|
||||
|
||||
建议:
|
||||
|
||||
- 缓存 5–15 分钟;
|
||||
- 用户点击“刷新模型”时绕过缓存;
|
||||
- 更换 Key 后立即清除旧缓存;
|
||||
- 缓存失败时可以使用最近一次成功目录,但 UI 必须标注“可能过期”;
|
||||
- 不要把完整 Key 写进缓存键或日志。
|
||||
|
||||
## 15. 适配其他 Agent 的最小接口
|
||||
|
||||
一个可维护的 Provider 只需要四个职责:
|
||||
|
||||
```text
|
||||
resolveCredential() -> 安全读取 Key
|
||||
discoverModels() -> 获取并按 CLI 权限过滤模型
|
||||
describeModel(id) -> 返回该模型容量、模态、思考档位和默认值
|
||||
stream(request) -> 转换消息并解析 SSE
|
||||
```
|
||||
|
||||
DSH、OpenCode 或其他 Agent 自己负责:
|
||||
|
||||
- Agent 循环;
|
||||
- 上下文裁剪与压缩;
|
||||
- 工具实际执行;
|
||||
- 权限确认;
|
||||
- 会话持久化;
|
||||
- 重试策略和用户取消。
|
||||
|
||||
CodeBuddy 服务端负责模型推理,不会替第三方 Agent 自动执行本地工具。
|
||||
|
||||
## 16. 验收清单
|
||||
|
||||
开发完成后至少验证:
|
||||
|
||||
- [ ] Key 不出现在源码、Git、日志和异常堆栈中;
|
||||
- [ ] 两把不同 Key 的模型目录不会串用;
|
||||
- [ ] 只显示 `agents[name=cli].models` 授权的模型;
|
||||
- [ ] 新模型无需发布新代码即可出现;
|
||||
- [ ] 旧模型下线后不会继续从缓存永久显示;
|
||||
- [ ] 上下文窗口和最大输出来自逐模型字段;
|
||||
- [ ] 非图片模型会在请求前拒绝图片;
|
||||
- [ ] 非推理模型不显示思考控件;
|
||||
- [ ] `onlyReasoning` 模型不显示 `off`;
|
||||
- [ ] 每个模型使用自己的默认思考档位;
|
||||
- [ ] 用户显式档位会转换为该模型自己的线上值;
|
||||
- [ ] 能累计文本、思考和工具调用 SSE 增量;
|
||||
- [ ] 用户取消能中止网络请求;
|
||||
- [ ] 429 和 5xx 有限重试,不会无限循环;
|
||||
- [ ] 工具调用不会因自动重试而重复执行。
|
||||
|
||||
## 17. 版本漂移检查
|
||||
|
||||
升级 CodeBuddy CLI 后,应重新核对:
|
||||
|
||||
1. `product.json` 和 CLI 版本;
|
||||
2. 配置接口是否仍为 `/v3/config`;
|
||||
3. 推理接口是否仍为 `/v2/chat/completions`;
|
||||
4. 鉴权是否仍接受 `Authorization` / `X-API-Key`;
|
||||
5. 模型能力字段是否新增 `thinkingLevelMap`、`thinkingFormat` 等;
|
||||
6. SSE 推理和工具字段是否变化;
|
||||
7. 当前 Key 实际返回的 CLI 模型目录。
|
||||
|
||||
本项目的可执行实现位于 [`index.js`](../index.js),安装和使用说明见
|
||||
[`README.md`](../README.md)。
|
||||
Reference in new issue
Block a user