Skip to content

Commit daf67d0

Browse files
committed
fix: v3.4.1 — GLM tool message name 字段 + content null + reasoning_content 修复
GLM 不支持 tool role 消息中的 name 字段、content: null、reasoning_content, 三者都会触发 'messages 参数非法' 400 错误。 - tool 消息: GLM 时去掉 name 字段(3 处) - assistant content: null → '' 空字符串(3 处) - reasoning_content: 只对 deepseek/kimi 注入(3 处) - 添加 [GLM-DEBUG] 日志用于诊断 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent b92d9c1 commit daf67d0

4 files changed

Lines changed: 59 additions & 17 deletions

File tree

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "augment-proxy-manager",
33
"displayName": "Augment Proxy Manager",
44
"description": "管理 Augment API 代理服务器,支持自定义 API 端点和多种 AI 供应商",
5-
"version": "3.4.0",
5+
"version": "3.4.1",
66
"publisher": "legna",
77
"repository": {
88
"type": "git",

readme.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
零注入 · 零登录 · 零配置
1010

11-
[![Version](https://img.shields.io/badge/version-3.4.0-blue.svg)](https://github.com/LegnaOS/VSC-Augment-Proxy-Manager)
11+
[![Version](https://img.shields.io/badge/version-3.4.1-blue.svg)](https://github.com/LegnaOS/VSC-Augment-Proxy-Manager)
1212
[![Platform](https://img.shields.io/badge/platform-macOS%20%7C%20Windows%20%7C%20Linux-lightgrey.svg)]()
1313

1414
</div>
@@ -221,6 +221,12 @@ v3.4.0 Agent 工具系统进化 — Tool 类型系统 + ToolRegistry
221221

222222
## 更新日志
223223

224+
### v3.4.1 — GLM 工具循环 messages 参数修复
225+
226+
- **GLM 400 修复** — GLM (glm-5.1) 不支持 `reasoning_content` 字段和 `content: null`,工具循环第二轮回传 assistant 消息时触发 `messages 参数非法` 400 错误
227+
- **assistant content 修复** — 工具循环和历史回放中 `content: null` 改为 `content: ''`(空字符串),兼容所有 provider
228+
- **reasoning_content 条件注入** — 只对 DeepSeek/Kimi 注入 `reasoning_content`,GLM/OpenAI/其他 provider 跳过,避免不兼容字段污染请求
229+
224230
### v3.4.0 — Agent 工具系统进化
225231

226232
**🏗️ 架构重构 — 参考 Claude Code Tool 类型系统**

src/messages.ts

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -737,10 +737,13 @@ export function augmentToOpenAIMessages(req: any) {
737737
};
738738
if (content) {
739739
assistantMessage.content = content;
740-
} else if (reasoningContent) {
741-
assistantMessage.content = null;
740+
} else {
741+
assistantMessage.content = '';
742742
}
743-
if (reasoningContent) {
743+
// reasoning_content 只有部分 provider 支持回传(DeepSeek/Kimi)
744+
// GLM 不支持,会导致 "messages 参数非法" 400 错误
745+
const supportsReasoningReplay = ['deepseek', 'kimi'].includes(state.currentConfig.provider);
746+
if (reasoningContent && supportsReasoningReplay) {
744747
assistantMessage.reasoning_content = reasoningContent;
745748
}
746749
messages.push(assistantMessage);
@@ -754,12 +757,16 @@ export function augmentToOpenAIMessages(req: any) {
754757
}
755758

756759
for (const toolResult of turn.toolResults || []) {
757-
messages.push({
760+
const toolMsg: any = {
758761
role: 'tool',
759762
tool_call_id: toolResult.id,
760-
name: toolResult.name || 'unknown',
761763
content: toolResult.content || ''
762-
});
764+
};
765+
// GLM 不支持 tool 消息中的 name 字段,会导致 "messages 参数非法"
766+
if (state.currentConfig.provider !== 'glm') {
767+
toolMsg.name = toolResult.name || 'unknown';
768+
}
769+
messages.push(toolMsg);
763770
}
764771

765772
if (turn.text) {

src/providers/openai.ts

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -582,6 +582,19 @@ export async function executeOpenAIRequest(
582582
}
583583

584584
const apiBody = JSON.stringify(requestBody);
585+
586+
// DEBUG: dump messages 结构(仅 GLM 时输出)
587+
if (state.currentConfig.provider === 'glm') {
588+
for (let mi = 0; mi < messages.length; mi++) {
589+
const m = messages[mi];
590+
const keys = Object.keys(m || {}).join(',');
591+
const contentType = m?.content === null ? 'null' : typeof m?.content;
592+
const hasToolCalls = Array.isArray(m?.tool_calls) ? m.tool_calls.length : 0;
593+
const hasReasoning = m?.reasoning_content ? 'yes' : 'no';
594+
log(`[GLM-DEBUG] msg[${mi}] role=${m?.role} keys=[${keys}] content=${contentType}(${String(m?.content).substring(0, 50)}) tool_calls=${hasToolCalls} reasoning=${hasReasoning}`);
595+
}
596+
}
597+
585598
const url = new URL(resolvedEndpoint);
586599
const headers: any = {
587600
'Content-Type': 'application/json',
@@ -1071,22 +1084,29 @@ export async function forwardToOpenAIStream(augmentReq: any, res: any) {
10711084
const assistantReplay = splitReasoningContentFromText(result.text);
10721085
const assistantReplayMessage: any = {
10731086
role: 'assistant',
1074-
content: assistantReplay.content || null,
1087+
content: assistantReplay.content || '',
10751088
tool_calls: assistantToolCallsMsg
10761089
};
1077-
if (assistantReplay.reasoningContent) {
1090+
// reasoning_content 只有部分 provider 支持回传(DeepSeek/Kimi)
1091+
// GLM 不支持,会导致 "messages 参数非法" 400 错误
1092+
const supportsReasoningReplay = ['deepseek', 'kimi'].includes(state.currentConfig.provider);
1093+
if (assistantReplay.reasoningContent && supportsReasoningReplay) {
10781094
assistantReplayMessage.reasoning_content = assistantReplay.reasoningContent;
10791095
}
10801096
currentMessages.push(assistantReplayMessage);
10811097

10821098
// 2. 添加拦截工具的执行结果作为 tool message
10831099
for (const { tc, toolNode } of interceptedTools) {
1084-
currentMessages.push({
1100+
const toolMsg: any = {
10851101
role: 'tool',
10861102
tool_call_id: tc.id,
1087-
name: tc.name,
10881103
content: toolNode.tool_result_node.content
1089-
});
1104+
};
1105+
// GLM 不支持 tool 消息中的 name 字段
1106+
if (state.currentConfig.provider !== 'glm') {
1107+
toolMsg.name = tc.name;
1108+
}
1109+
currentMessages.push(toolMsg);
10901110
// 流式显示执行状态和 diff 给用户
10911111
try {
10921112
const resultObj = JSON.parse(toolNode.tool_result_node.content);
@@ -1103,7 +1123,11 @@ export async function forwardToOpenAIStream(augmentReq: any, res: any) {
11031123
// 3. 同时处理 codebase_search(如果有)
11041124
for (const cs of codebaseSearchCalls) {
11051125
const searchResult = await executeRAGSearch(cs.query);
1106-
currentMessages.push({ role: 'tool', tool_call_id: cs.id, name: 'codebase_search', content: searchResult });
1126+
const csMsg: any = { role: 'tool', tool_call_id: cs.id, content: searchResult };
1127+
if (state.currentConfig.provider !== 'glm') {
1128+
csMsg.name = 'codebase_search';
1129+
}
1130+
currentMessages.push(csMsg);
11071131
res.write(JSON.stringify({
11081132
text: `\n📚 **代码库搜索** ("${cs.query.substring(0, 30)}...")\n`,
11091133
nodes: [], stop_reason: 0
@@ -1149,17 +1173,22 @@ export async function forwardToOpenAIStream(augmentReq: any, res: any) {
11491173
const assistantReplay = splitReasoningContentFromText(result.text);
11501174
const assistantReplayMessage: any = {
11511175
role: 'assistant',
1152-
content: assistantReplay.content || null,
1176+
content: assistantReplay.content || '',
11531177
tool_calls: toolCallsForMsg
11541178
};
1155-
if (assistantReplay.reasoningContent) {
1179+
const supportsReasoningReplay2 = ['deepseek', 'kimi'].includes(state.currentConfig.provider);
1180+
if (assistantReplay.reasoningContent && supportsReasoningReplay2) {
11561181
assistantReplayMessage.reasoning_content = assistantReplay.reasoningContent;
11571182
}
11581183
currentMessages.push(assistantReplayMessage);
11591184

11601185
for (const cs of codebaseSearchCalls) {
11611186
const searchResult = await executeRAGSearch(cs.query);
1162-
currentMessages.push({ role: 'tool', tool_call_id: cs.id, name: 'codebase_search', content: searchResult });
1187+
const csMsg2: any = { role: 'tool', tool_call_id: cs.id, content: searchResult };
1188+
if (state.currentConfig.provider !== 'glm') {
1189+
csMsg2.name = 'codebase_search';
1190+
}
1191+
currentMessages.push(csMsg2);
11631192
res.write(JSON.stringify({
11641193
text: `\n\n🔍 **代码库搜索** (查询: "${cs.query}")\n${searchResult.split('\n').slice(0, 5).join('\n')}...\n\n`,
11651194
nodes: [], stop_reason: 0

0 commit comments

Comments
 (0)