Skip to content

Commit 97e4332

Browse files
author
MouseWW
committed
fix(llm): reject responses function calls without ids
1 parent a2b26c3 commit 97e4332

4 files changed

Lines changed: 36 additions & 16 deletions

File tree

RELEASE_NOTES.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
1-
# Anything Analyzer v3.6.36
1+
# Anything Analyzer v3.6.37
22

33
## 修复
44

5-
- **Anthropic/MiniMax 非流式文本格式校验**避免 text content 不是字符串时被拼成 `[object Object]`
6-
- 普通请求和工具调用最终轮次复用同一段 Anthropic 文本块校验逻辑
7-
- 新增回归测试覆盖非字符串 text content 的异常路径
5+
- **Responses API 工具调用格式校验**避免缺少 call_id 的 function_call 继续进入工具执行轮次
6+
- 工具调用入站阶段直接拒绝缺失 call_id 的畸形响应
7+
- 新增回归测试覆盖 Responses API function_call 缺少调用 ID 的异常路径
88

99
## 下载
1010

1111
| 平台 | 文件 |
1212
|------|------|
13-
| Windows | Anything-Analyzer-Setup-3.6.36.exe |
14-
| macOS (Apple Silicon) | Anything-Analyzer-3.6.36-arm64.dmg |
15-
| macOS (Intel) | Anything-Analyzer-3.6.36-x64.dmg |
16-
| Linux | Anything-Analyzer-3.6.36.AppImage |
13+
| Windows | Anything-Analyzer-Setup-3.6.37.exe |
14+
| macOS (Apple Silicon) | Anything-Analyzer-3.6.37-arm64.dmg |
15+
| macOS (Intel) | Anything-Analyzer-3.6.37-x64.dmg |
16+
| Linux | Anything-Analyzer-3.6.37.AppImage |

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "anything-analyzer",
3-
"version": "3.6.36",
3+
"version": "3.6.37",
44
"description": "Universal web protocol analyzer with embedded browser and AI-powered analysis",
55
"packageManager": "pnpm@10.24.0",
66
"main": "./out/main/index.js",

src/main/ai/llm-router.ts

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -570,13 +570,14 @@ export class LLMRouter {
570570
onChunk(`\n\n> 🔧 调用工具: ${toolNames}\n\n`);
571571
}
572572

573-
for (const fc of functionCalls) {
574-
let result: string;
575-
try {
576-
if (!fc.name) throw new Error("function_call missing name");
577-
const args = JSON.parse(fc.arguments || "{}");
578-
result = await callTool(fc.name, args);
579-
} catch (err) {
573+
for (const fc of functionCalls) {
574+
let result: string;
575+
if (!fc.id) throw new Error("function_call missing call_id");
576+
if (!fc.name) throw new Error("function_call missing name");
577+
try {
578+
const args = JSON.parse(fc.arguments || "{}");
579+
result = await callTool(fc.name, args);
580+
} catch (err) {
580581
result = `Error: ${err instanceof Error ? err.message : String(err)}`;
581582
}
582583
input.push({

tests/main/ai/llm-router.test.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -537,6 +537,25 @@ describe("LLMRouter", () => {
537537
),
538538
).rejects.toThrow("Responses API incomplete: max_output_tokens");
539539
});
540+
541+
it("should reject Responses API function calls without call id", async () => {
542+
const config: LLMProviderConfig = { ...baseConfig, apiType: "responses" };
543+
fetchSpy.mockResolvedValueOnce(
544+
createJSONResponse({
545+
output: [{ type: "function_call", name: "lookup", arguments: "{}" }],
546+
}),
547+
);
548+
549+
const router = new LLMRouter(config);
550+
551+
await expect(
552+
router.completeWithTools(
553+
[{ role: "user", content: "test" }],
554+
[{ name: "lookup", description: "Lookup", inputSchema: { type: "object" } }],
555+
async () => "unused",
556+
),
557+
).rejects.toThrow("function_call missing call_id");
558+
});
540559
});
541560

542561
describe("completeWithTools - Anthropic", () => {

0 commit comments

Comments
 (0)