From 0b5c2a570024fd86dbe69f7c5d68b50f312182fb Mon Sep 17 00:00:00 2001 From: Ettore Di Giacinto Date: Mon, 10 Nov 2025 16:05:43 +0100 Subject: [PATCH] Small fixups Signed-off-by: Ettore Di Giacinto --- .air.toml | 1 + core/http/static/chat.js | 21 ++++++++++++++++++--- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/.air.toml b/.air.toml index 123d7272c..1e8442249 100644 --- a/.air.toml +++ b/.air.toml @@ -2,6 +2,7 @@ [build] cmd = "make build" bin = "./local-ai" +args_bin = [ "--debug" ] include_ext = ["go", "html", "yaml", "toml", "json", "txt", "md"] exclude_dir = ["pkg/grpc/proto"] delay = 1000 diff --git a/core/http/static/chat.js b/core/http/static/chat.js index a598cea9d..993c956ac 100644 --- a/core/http/static/chat.js +++ b/core/http/static/chat.js @@ -454,12 +454,27 @@ async function promptGPT(systemPrompt, input) { Alpine.store("chat").updateTokenUsage(data.usage); } - // MCP endpoint returns content in choices[0].text, not choices[0].message.content - const content = data.choices[0]?.text || ""; + // MCP endpoint returns content in choices[0].message.content (chat completion format) + // Fallback to choices[0].text for backward compatibility (completion format) + const content = data.choices[0]?.message?.content || data.choices[0]?.text || ""; + + if (!content && (!data.choices || data.choices.length === 0)) { + Alpine.store("chat").add( + "assistant", + `Error: Empty response from MCP endpoint`, + ); + toggleLoader(false); + return; + } if (content) { // Count tokens for rate calculation (MCP mode - full content at once) - tokensReceived += Math.ceil(content.length / 4); + // Prefer actual token count from API if available + if (data.usage && data.usage.completion_tokens) { + tokensReceived = data.usage.completion_tokens; + } else { + tokensReceived += Math.ceil(content.length / 4); + } updateTokensPerSecond(); // Process thinking tags using shared function