Repository navigation
AI Helper v1.0.43
🔧🛡️ AI Helper v1.0.43 —— Accio Bridge 协议三连修 · 工具参数类型熔断 · 上游接口全面切换 /v1/responses · 测试端点精准对齐 🎯🦀✨
📅 发布日期:2026-10-01 🗓️
🏷️ 版本标签:v1.0.43 🎯
🧭 更新类型:协议 Bug 修复 🔧 · 上游接口对齐 🌐 · 类型安全加固 🛡️ · 测试端点校准 🧪 · 代码质量清洁 🧹
AI Helper v1.0.43 正式发布啦!🎉🥳🚀✨
本次更新聚焦于 Accio Work Local Bridge 的三处关键协议级 Bug 修复 🔧,是一次精准的"三连斩"手术版本 🗡️🗡️🗡️!
第一刀 🗡️ 斩断了 tools[0].parameters 字符串类型穿透导致上游 API 502 的幽灵问题 👻;
第二刀 🗡️ 将 Bridge 实际转发的上游接口从 /v1/chat/completions 全面切换至 /v1/responses,彻底对齐中转站真实接口规范 🌐;
第三刀 🗡️ 同步校准了连通性测试终端的测试端点与请求体格式,确保"测试所见即运行所得" ✅!
本次三处修复均在 Rust 后端层面完成,零前端改动,升级无任何兼容性风险 🛡️🦀。
🌟 本次更新速览 📋✨
| 模块类别 🧩 | 核心修复内容 💡 | 用户与开发者收益 🎁 |
|---|---|---|
| 🛡️ 工具参数类型熔断 | parametersJson 字符串值自动解析为 JSON 对象,不再原样透传字符串 |
彻底消灭 Invalid type for 'tools[0].parameters': expected an object, but got a string 502 报错 🎯 |
| 🌐 上游接口全面切换 | Bridge 转发端点从 /v1/chat/completions 改为 /v1/responses,新增 chat_to_responses_body 与 parse_responses_api_response 两个适配器 |
精准对接中转站 GPT 系模型的真实接口,请求格式完全正确 ✅ |
| 🧪 测试端点精准对齐 | test_accio_stream 测试函数同步切换至 /v1/responses,messages 改 input,max_tokens 改 max_output_tokens |
连通性测试与实际运行完全一致,终端日志所见即所得 🔍 |
| 🧹 代码质量清洁 | 移除不再使用的 merge_openai_chunks import,为保留函数添加 #[allow(dead_code)] |
零 warning 编译,保持代码库整洁健壮 💎 |
🗺️ 本次修复全链路示意图 🏗️✨
flowchart TD
subgraph AccioClient ["🤖 Accio Work 客户端 (Gemini ADK 协议)"]
ClientReq["📨 发起 LLM 请求<br/>tools[].parametersJson = JSON字符串<br/>modelCode = 内部混淆名"]
end
subgraph Bridge ["🔌 AI Helper Local Bridge (Rust / Axum)"]
Fix1["🛡️ Fix 1: protocol.rs<br/>parametersJson 字符串 → JSON 对象解析<br/>消灭 tools.parameters 类型错误"]
Fix2["🌐 Fix 2: bridge.rs<br/>chat_to_responses_body 转换<br/>端点: /v1/responses<br/>messages → input + instructions<br/>max_tokens → max_output_tokens"]
Fix3["🧪 Fix 3: api_test.rs<br/>测试端点同步 /v1/responses<br/>input: Hi | max_output_tokens: 16"]
ParseResp["📦 parse_responses_api_response<br/>output[].content[].type<br/>output_text / tool_use 解析<br/>input_tokens / output_tokens 计量"]
end
subgraph Upstream ["☁️ API 中转站 (GPT 系 /v1/responses)"]
UpstreamReq["🎯 正确接收 /v1/responses 格式请求<br/>tools.parameters 为对象类型 ✅<br/>input 数组 + instructions 字段"]
StreamResp["🌊 响应: output[].content[].text<br/>usage: input_tokens / output_tokens"]
end
ClientReq --> Fix1
Fix1 --> Fix2
Fix2 --> UpstreamReq
UpstreamReq --> StreamResp
StreamResp --> ParseResp
ParseResp --> ClientReq
Fix3 -. "测试阶段验证" .-> UpstreamReq
classDef client fill:#e0f2fe,stroke:#0284c7,stroke-width:2px;
classDef bridge fill:#ffedd5,stroke:#ea580c,stroke-width:2px;
classDef upstream fill:#ecfdf5,stroke:#059669,stroke-width:2px;
class ClientReq client;
class Fix1,Fix2,Fix3,ParseResp bridge;
class UpstreamReq,StreamResp upstream;🛡️ 1. 工具参数类型熔断修复:彻底消灭 tools[0].parameters 502 幽灵错误 👻🔧
🚨 Bug 根本原因剖析
当 Accio Work 客户端发来的工具声明(functionDeclarations)中使用了 parametersJson 或 parameters_json 字段时,这两个字段的值是一个 JSON 字符串,而不是 JSON 对象 🧵。例如:
{
"tools": [{
"functionDeclarations": [{
"name": "execute_code",
"description": "执行代码片段",
"parametersJson": "{\"type\":\"object\",\"properties\":{\"code\":{\"type\":\"string\"}}}"
}]
}]
}旧版本的代码在遇到 parametersJson 时,直接 .cloned() 拿到字符串值后原样放入 parameters 字段 🤦♂️,导致发送给 API 中转站的请求变成了:
{
"tools": [{
"type": "function",
"function": {
"name": "execute_code",
"parameters": "{\"type\":\"object\",\"properties\":{\"code\":{\"type\":\"string\"}}}"
}
}]
}parameters 字段本应是一个 JSON 对象,却被传成了一个字符串 😱。API 中转站的 GPT 系模型严格校验此字段类型,直接返回:
status_code=502, stream ended abnormally: reason=done soft_errors=1:
upstream stream error: Invalid type for 'tools[0].parameters':
expected an object, but got a string instead.
🛡️ 修复方案
在 src-tauri/src/accio/protocol.rs 的 accio_to_openai 函数中,对 parameters 字段加入类型守卫与自动反序列化逻辑 🔐:
// 修复前 ❌:直接 cloned(),字符串原样透传
let parameters = declaration
.get("parameters")
.or_else(|| declaration.get("parametersJson"))
.cloned()
.unwrap_or_else(|| json!({"type":"object","properties":{}}));
// 修复后 ✅:若为字符串则自动 JSON 解析,解析失败 fallback 空 schema
let parameters_raw = declaration
.get("parameters")
.or_else(|| declaration.get("parametersJson"))
.or_else(|| declaration.get("parameters_json"))
.cloned()
.unwrap_or_else(|| json!({"type":"object","properties":{}}));
let parameters = if let Some(s) = parameters_raw.as_str() {
// 🔄 字符串类型:自动解析为 JSON 对象
serde_json::from_str(s)
.unwrap_or_else(|_| json!({"type":"object","properties":{}}))
} else {
// ✅ 已是对象类型:直接使用
parameters_raw
};🎁 修复收益
- 🎯 彻底消除 502:无论 Accio Work 使用
parameters(对象)还是parametersJson/parameters_json(字符串),最终发给上游的parameters字段始终是 JSON 对象,完全符合 OpenAI API 规范; - 🛡️ 双重 fallback 保险:若字符串值本身也是无效 JSON,则 fallback 为安全的空 schema
{"type":"object","properties":{}},确保请求不因工具定义畸形而崩溃 💪; - 🌐 全字段覆盖:同时处理
parametersJson和parameters_json两种命名变体,兼容 Accio ADK 协议的新旧版本 🔄。
🌐 2. 上游接口全面切换至 /v1/responses:精准对齐中转站真实接口 🎯🔄
🧩 问题背景
AI Helper 的 Accio Bridge 在将 Gemini ADK 协议请求转发给第三方 API 中转站时,一直使用的是 /v1/chat/completions 端点 📡。然而,该中转站内的所有 GPT 系模型(包括 gpt-6-sol 等)实际上只暴露了 /v1/responses 接口 🌐。
这意味着:
- ❌ 连通性测试失败:测试终端打印
/v1/chat/completions发送探测请求,若中转站不支持该路径则直接 404; - ❌ Bridge 实际转发失败:即使测试侥幸通过(中转站两路都支持),真实工作流中的 GPT 模型调用也无法正确解析响应格式(
choices[]vsoutput[]); - ❌ 响应解析字段错位:
/v1/responses使用input_tokens/output_tokens而非prompt_tokens/completion_tokens,旧解析器无法正确统计 Token 用量。
✨ 修复方案:三层协同重构
🔧 Layer 1 — chat_to_responses_body() 请求格式转换器
在 src-tauri/src/accio/bridge.rs 中新增专用转换函数,将 accio_to_openai() 输出的 Chat Completions 格式体精准映射为 /v1/responses 请求格式:
fn chat_to_responses_body(chat_body: &Value) -> Value {
// 🔍 从 messages 中分离 system 消息 → instructions 字段
// 📋 其余消息 → input 数组
// 🔢 max_tokens → max_output_tokens
// 🌡️ 保留 temperature / tools / tool_choice / model
}字段映射对照表 📊:
| Chat Completions 格式 🗂️ | Responses API 格式 🌐 |
|---|---|
messages[{role:"system", content:"..."}] |
instructions: "..." |
messages[{role:"user",...}, ...] |
input: [{role:"user",...}, ...] |
max_tokens: 16384 |
max_output_tokens: 16384 |
model / temperature / tools / tool_choice |
保持不变 ✅ |
🔧 Layer 2 — parse_responses_api_response() 响应解析器
新增专用响应解析函数,完整支持 /v1/responses 的响应格式,并将其转换回 Accio Gemini 协议格式 🔄:
fn parse_responses_api_response(json_val: &Value, default_model: &str) -> Value {
// 📖 解析 output[].content[].type:
// "output_text" | "text" → parts[].text
// "tool_use" | "function_call" → parts[].functionCall
//
// 📊 Token 计量字段兼容:
// input_tokens → promptTokenCount
// output_tokens → candidatesTokenCount
}响应格式适配图 🗺️:
/v1/responses 响应格式 (上游返回) Accio Gemini 协议格式 (返回客户端)
───────────────────────────────── ──────────────────────────────────
{ ───► {
"output": [{ "content": {
"content": [{ "role": "model",
"type": "output_text", "parts": [{ "text": "..." }]
"text": "Hello!" },
}] "finishReason": "STOP",
}], "usageMetadata": {
"usage": { "promptTokenCount": 10,
"input_tokens": 10, "candidatesTokenCount": 5,
"output_tokens": 5 "totalTokenCount": 15
} }
} }
🔧 Layer 3 — call_upstream_llm() 端点与流程更新
// 修复前 ❌
let endpoint = format!("{root}/v1/chat/completions");
let request_body = accio_to_openai(&input, &config.model);
// 修复后 ✅
let endpoint = format!("{root}/v1/responses");
let chat_body = accio_to_openai(&input, &config.model);
let request_body = chat_to_responses_body(&chat_body);同时 SSE 兼容路径也升级适配了 /v1/responses 的流式事件格式 🌊:
- 🔍 优先识别含
output字段的完整响应对象; - 🌊 其次捕获
/delta/text增量流式片段; - 🛡️ 最后兜底兼容旧版 Chat Completions SSE 格式(
choices[0].delta.content)。
🎁 修复收益
- ✅ 请求格式完全正确:
input数组 +instructions字段 +max_output_tokens,中转站零格式报错; - ✅ 响应解析字段精准:
input_tokens/output_tokens正确映射,Token 用量统计不再为 0; - ✅ Tool Call 全链路贯通:
output[].content[].type = "tool_use"完整解析并转换为 AcciofunctionCall格式,工具调用场景全覆盖 🛠️; - 🌊 SSE 三段式兼容:无论中转站返回完整 JSON、增量流式还是旧版 SSE,均有对应解析路径保底 🛡️。
🧪 3. 连通性测试端点精准对齐:终端所见即运行所得 🔍✅
🚨 改前问题
test_accio_stream 测试函数沿用了 /v1/chat/completions 端点,而终端测试日志打印的提示信息也在告诉用户正在用 Chat Completions 协议,这与 Bridge 实际的 /v1/responses 工作链路形成了认知断层 🫤:
// 改前 ❌ — 端点、格式、日志三者均不对齐
let endpoint = format!("{root}/v1/chat/completions");
// ...
text: "发送握手测试消息: [POST /v1/chat/completions] payload: \"Hi\"..."
// ...
json!({
"model": model,
"max_tokens": 16,
"messages": [{ "role": "user", "content": "Hi" }],
})✨ 修复后
// 修复后 ✅ — 端点、格式、日志三者完全对齐
let endpoint = format!("{root}/v1/responses");
// ...
text: "发送握手测试消息: [POST /v1/responses] input: \"Hi\"..."
// ...
json!({
"model": model,
"input": "Hi",
"max_output_tokens": 16,
})终端测试模态框中的日志信息同步更新 📟:
| 日志项目 🔖 | 改前 ❌ | 改后 ✅ |
|---|---|---|
| 协议描述 | Accio Work 上游 Chat Completions 协议 |
OpenAI Responses 协议 → Accio Gemini Bridge |
| 探测日志 | [POST /v1/chat/completions] payload: "Hi" |
[POST /v1/responses] input: "Hi" |
| 请求体字段 | messages + max_tokens |
input + max_output_tokens |
🎁 修复收益
- 🎯 测试真实性:测试阶段打的端点与 Bridge 实际运行完全一致,中转站的
gpt-6-sol等模型能够被正确探测 ✅; - 🔍 日志可信度:终端日志明确展示
Responses 协议 → Accio Gemini Bridge的完整链路描述,排障时清晰无歧义 👁️; - 📋 格式合规性:探测请求使用
input: "Hi"与max_output_tokens: 16,符合/v1/responsesAPI 规范,不再触发中转站的字段校验报错 🚫。
🧹 4. 代码质量清洁:零 Warning 编译 · 保持代码库整洁 💎✨
🧽 清理项
移除无用 Import 🗑️
merge_openai_chunks 函数原先在 bridge.rs 中被引入,用于合并 Chat Completions SSE 流式 chunks。切换至 /v1/responses 后,该函数不再被 Bridge 直接调用,为避免 unused import 编译警告,已从 bridge.rs 的 use 声明中移除 🧹:
// 移除前 ⚠️ warning: unused import `merge_openai_chunks`
use crate::accio::protocol::{
accio_to_openai, format_accio_sse, merge_openai_chunks, SSE_HEARTBEAT,
};
// 移除后 ✅ 零 Warning
use crate::accio::protocol::{
accio_to_openai, format_accio_sse, SSE_HEARTBEAT,
};保留备用函数并标注 #[allow(dead_code)] 📌
protocol.rs 中的 merge_openai_chunks 函数本身依然有保留价值:
- 🧪 单元测试覆盖:函数有对应的
#[test] fn test_merge_openai_chunks()测试用例; - 🔮 未来兼容备用:部分中转站可能在特定场景仍返回 Chat Completions SSE 格式。
因此选择保留函数体,并添加 #[allow(dead_code)] 注解消除 Warning,而非直接删除 📎:
/// 合并 OpenAI 流式返回的所有 Chunk
#[allow(dead_code)]
pub fn merge_openai_chunks(chunks: &[Value]) -> Value {
// ...
}🏆 编译结果
✅ Checking ai-helper v1.0.43 (E:\Developer Tool\AI Helper\src-tauri)
✅ Finished `dev` profile [unoptimized + debuginfo] target(s) in 3.29s
🎉 零 Error · 零 Warning · 编译完全通过!
📝 完整代码变更清单 📋🔍
-
🦀
src-tauri/src/accio/protocol.rs- 🛡️ 修复
accio_to_openai中tools声明的parameters字段类型守卫:当parametersJson/parameters_json值为 JSON 字符串时,自动serde_json::from_str解析为对象,彻底消除tools[0].parameters expected object got string502 报错 🎯; - 🏷️ 为
merge_openai_chunks函数添加#[allow(dead_code)]注解,保留函数体供测试与未来兼容用 📌。
- 🛡️ 修复
-
🦀
src-tauri/src/accio/bridge.rs- 🌐 新增
chat_to_responses_body()辅助函数:将 Chat Completions 格式体转换为/v1/responses请求格式(messages→input+instructions,max_tokens→max_output_tokens,保留tools/tool_choice/temperature); - 📦 新增
parse_responses_api_response()辅助函数:完整解析/v1/responses响应格式,兼容output_text/tool_use内容类型与input_tokens/output_tokens计量字段,并转换为 Accio Gemini 协议格式; - 🔄 改写
call_upstream_llm()函数:端点由/v1/chat/completions切换为/v1/responses,请求体使用chat_to_responses_body()转换,响应解析使用parse_responses_api_response(),SSE 兼容路径同步适配三段式解析策略; - 🧹 移除不再使用的
merge_openai_chunksimport,消除unused import编译警告。
- 🌐 新增
-
🧪
src-tauri/src/api_test.rs- 🎯
test_accio_stream()函数测试端点由/v1/chat/completions改为/v1/responses; - 📋 请求体由
messages + max_tokens改为input + max_output_tokens,与实际运行格式完全一致; - 📟 更新终端日志文本,协议标签由
Accio Work 上游 Chat Completions 协议改为OpenAI Responses 协议 → Accio Gemini Bridge,探测日志同步更新为[POST /v1/responses] input: "Hi"。
- 🎯
🔄 兼容性与升级指南 💡🚀
💡 兼容性说明
- ✅ 配置完全兼容:现有
~/.ai-helper/accio_config.json配置文件无需任何修改,升级后直接生效; - ✅ Bridge 自动适配:重启 Bridge 网关即可自动切换为
/v1/responses接口,无需手动干预; - ✅ 仅限 Accio 模块:本次修复仅影响 Accio Work 相关的后端逻辑,ChatGPT、Claude Code、WorkBuddy 模块完全不受影响 🛡️;
⚠️ 中转站接口确认:若你的 API 中转站 同时支持/v1/chat/completions和/v1/responses,本次升级亦完全兼容,无任何副作用 👍。
🚀 推荐升级步骤
- 📥 下载
v1.0.43安装包或便携包,完成覆盖升级; - 🔌 重新打开 AI Helper,在 Accio Work 面板中停止并重启本地 Bridge 网关;
- 🧪 点击「保存并测试 Accio Work 连通性」,在测试终端中确认日志显示
[POST /v1/responses]字样 ✅; - 🤖 重启 Accio Work 客户端,使用工具调用功能验证
tools.parameters不再出现 502 报错 🎉; - 🎊 畅享稳定可靠、协议精准对齐的 Accio Work AI 编程体验!
🎉 结语 💖🌈
AI Helper 的每一次 Bug 修复,都是对用户信任的一次精准回应 💪!
v1.0.43 这次"三连斩" 🗡️🗡️🗡️,从 工具参数类型 🛡️ 到 上游接口规范 🌐,再到 测试端点对齐 🧪,覆盖了 Accio Work 接入链路上三个真实存在的核心痛点。每一处修复都经过严格的 Rust 类型安全验证与编译检查,确保上线零风险 🚀💯!
感谢每一位细心反馈问题的社区用户和开发者 ❤️🌟,正是你们的真实使用场景推动了 AI Helper 一步步走向更强大 🏆!
AI Helper —— 专为 AI 开发者与智能办公打造的全矩阵 Agent 配置中枢 & 协议桥接平台 ⚡
One Helper to Bridge Them All: ChatGPT 🤖 • Claude Code 🧠 • WorkBuddy ⚙️ • Accio Work 🚀 • MCP 🧩✨