mirror of
https://gitcode.com/JianFeeeee/ModelRouter.git
synced 2026-09-20 08:57:57 +00:00
Four adapters handled tool_calls in transform_stream_chunk but lost them in
transform_response, so any NON-streaming tool-using conversation broke on its
second request: the client received finish_reason:"tool_calls" with no
tool_calls payload, replayed an assistant message whose function
name/arguments were empty, and the upstream rejected the next turn with
400 invalid tool_call function, function/name/arguments cannot be empty
The production audit trail shows 46 such failures on sensenova alone.
- sensenova.lua: forward message.tool_calls, decoding the arguments JSON string
into an object as the unified shape expects.
- gemini.lua: collect functionCall parts from candidates[].content.parts. Also
correct finish_reason, since Gemini reports "STOP" even when it emitted a
function call and clients keyed on it treat that as a finished answer.
- ollama.lua: the field was initialized to an empty table and never filled;
fill it and likewise correct done_reason "stop" -> "tool_calls".
trae is a different failure with the same symptom: trae-local-api's OpenAI
endpoint (/v1/chat/completions, src/server.js:353) never reads the request's
`tools` array — only its Anthropic endpoint does — so the relayed model is never
told the tool schema and instead PRINTS a <tool_call>{...}</tool_call> block into
content, leaving message.tool_calls null and finish_reason "stop". An OpenAI
client sees an ordinary completion and its agent loop ends mid-conversation.
trae.lua now recovers the structured call from that text, strips the block from
user-visible content, and corrects finish_reason. Both tag spellings
(<tool_call>/<toolcall>, the latter is what the same codebase's Anthropic prompt
asks for) and all three argument key names (arguments/params/input) are accepted.
This is a defensive fallback: fixing the upstream shim to honour `tools` remains
the real fix, since the model still guesses parameter names.
Tests: TestNonStreamToolCallsPreserved covers all ten OpenAI-shaped adapters,
TestGeminiNonStreamToolCalls and TestOllamaNonStreamToolCalls cover their native
shapes, TestTraeTextToolCallRecovery covers both tag spellings, prose around the
block, and asserts a plain text answer never gains tool_calls.
Verified end-to-end against mock upstreams reproducing each shape: a full
two-round agent loop (tool call -> tool result -> final answer) now completes for
both the structured and the text-emitted variants.
93 lines
2.2 KiB
JSON
93 lines
2.2 KiB
JSON
{
|
|
"name": "modelrouter-gui",
|
|
"version": "1.4.2",
|
|
"description": "ModelRouter Desktop — embedded ModelRouter core with tray",
|
|
"author": "ModelRouter",
|
|
"main": "main.js",
|
|
"license": "Proprietary",
|
|
"scripts": {
|
|
"start": "electron . --no-sandbox",
|
|
"dev": "electron . --no-sandbox --dev",
|
|
"core:linux": "node scripts/prepare-core.js linux",
|
|
"core:win": "node scripts/prepare-core.js win",
|
|
"dist:linux": "npm run core:linux && electron-builder --linux deb rpm AppImage",
|
|
"dist:debian": "npm run core:linux && electron-builder --linux deb",
|
|
"dist:win": "npm run core:win && electron-builder --win nsis",
|
|
"dist:dir": "npm run core:linux && electron-builder --dir"
|
|
},
|
|
"devDependencies": {
|
|
"electron": "^33.0.0",
|
|
"electron-builder": "^26.15.3"
|
|
},
|
|
"build": {
|
|
"appId": "com.modelrouter.gui",
|
|
"productName": "ModelRouter",
|
|
"linux": {
|
|
"target": [
|
|
"deb",
|
|
"rpm",
|
|
"AppImage"
|
|
],
|
|
"category": "Network",
|
|
"icon": "build/icon.png",
|
|
"maintainer": "ModelRouter",
|
|
"synopsis": "ModelRouter Desktop",
|
|
"desktop": {
|
|
"entry": {
|
|
"StartupWMClass": "modelrouter-gui"
|
|
}
|
|
},
|
|
"extraResources": [
|
|
{
|
|
"from": "bin/llmsproxy",
|
|
"to": "bin/llmsproxy"
|
|
},
|
|
{
|
|
"from": "build/icon.png",
|
|
"to": "build/icon.png"
|
|
}
|
|
]
|
|
},
|
|
"directories": {
|
|
"output": "../build/gui-dist"
|
|
},
|
|
"mac": {
|
|
"target": "dmg",
|
|
"icon": "build/icon.png",
|
|
"extraResources": [
|
|
{
|
|
"from": "build/icon.png",
|
|
"to": "build/icon.png"
|
|
}
|
|
]
|
|
},
|
|
"win": {
|
|
"target": "nsis",
|
|
"icon": "build/icon.ico",
|
|
"extraResources": [
|
|
{
|
|
"from": "bin/llmsproxy.exe",
|
|
"to": "bin/llmsproxy.exe"
|
|
},
|
|
{
|
|
"from": "bin/lua51.dll",
|
|
"to": "bin/lua51.dll"
|
|
},
|
|
{
|
|
"from": "build/icon.png",
|
|
"to": "build/icon.png"
|
|
}
|
|
]
|
|
},
|
|
"files": [
|
|
"main.js",
|
|
"preload.js",
|
|
"renderer/**/*",
|
|
"build/**/*",
|
|
"!node_modules/**/*"
|
|
],
|
|
"asar": true
|
|
},
|
|
"homepage": "https://gitcode.com/JianFeeeee/ModelRouter"
|
|
}
|