fix(openai): Auto-Context, Tool-Result-Matching, Payload-Preview, leere Bubbles

- Auto-Context (Embedding-Suche) für OpenAI-Provider aktiviert: BuildAutoContextAsync
  auf internal static refactored und in StreamChat + ChatNonStreaming integriert
- Tool-Results mit Role="tool" (OpenAI-Konvention) werden in BuildHistoryFromDb
  jetzt korrekt erkannt (vorher nur Role="user"/Anthropic)
- Payload-Preview zeigt für OpenAI-Provider echtes API-Format (function-Wrapper,
  tool_choice:"auto", max_tokens, stream_options, extra_body)
- Tool-Input (Argumente) wird im SSE tool_end-Event mitgesendet (fehlte im OpenAI-Pfad)
- Leere Bubbles durch Whitespace-only Text nach </think>-Extraktion behoben
  (Trim in DB-Save, BuildHistoryFromDb und Frontend-Guard)
- History-Toggle-Bug: var→const in for-Loop (Block-Scoping für Closures),
  tool_result-Matching per data-tool-call-id statt blindes letztes Element
- Non-Streaming max_tokens für MiniMax auf 32768 + extra_body.reasoning_split

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
MelekiandClaude Opus 4.6 committed 2026-05-14 11:16:40 +02:00
1 parent ecddbe5f36
commit 1fe04025d3
9 files changed
+164 -42

No files matched your search

+11 -5
View File
@@ -299,12 +299,12 @@ Für welche Plattform soll die App entwickelt werden? Web, Mobile oder Desktop?
["content"] = new List<object> { new { type = "text", text = msg.Content } }
});
}
else if (msg.Role == "assistant" && msg.Type == "text" && !string.IsNullOrEmpty(msg.Content))
else if (msg.Role == "assistant" && msg.Type == "text" && !string.IsNullOrWhiteSpace(msg.Content))
{
history.Add(new Dictionary<string, object>
{
["role"] = "assistant",
["content"] = new List<object> { new { type = "text", text = msg.Content } }
["content"] = new List<object> { new { type = "text", text = msg.Content.Trim() } }
});
}
}
@@ -383,11 +383,14 @@ Für welche Plattform soll die App entwickelt werden? Web, Mobile oder Desktop?
}
else if (msg.Role == "assistant" && msg.Type == "text")
{
if (!string.IsNullOrEmpty(msg.Content))
// Trim: Nach </think>-Extraktion bleibt oft nur "\n" als Text übrig.
// Whitespace-only Text nicht in die History aufnehmen (verursacht leere Bubbles).
var trimmedContent = msg.Content?.Trim();
if (!string.IsNullOrEmpty(trimmedContent))
{
// Wenn die letzte Message bereits assistant ist (z.B. mit Thinking-Block
// aus derselben Iteration), Text dort anhängen statt neue Message zu starten.
AppendToLastMessage(history, "assistant", new { type = "text", text = msg.Content });
AppendToLastMessage(history, "assistant", new { type = "text", text = trimmedContent });
}
}
else if (msg.Role == "assistant" && msg.Type == "tool_use")
@@ -436,8 +439,11 @@ Für welche Plattform soll die App entwickelt werden? Web, Mobile oder Desktop?
AppendToLastMessage(history, "assistant", resultEl);
}
else if (msg.Role == "user" && msg.Type == "tool_result")
else if ((msg.Role == "user" || msg.Role == "tool") && msg.Type == "tool_result")
{
// Anthropic speichert tool_results mit Role="user", OpenAI mit Role="tool".
// Beide werden in Anthropic-Format (user-Message mit tool_result-Block) eingefügt,
// da BuildApiMessages später das Format für OpenAI-Provider konvertiert.
var toolResultBlock = new { type = "tool_result", tool_use_id = msg.ToolCallId, content = SseHelper.TruncateToolResult(msg.Content ?? ""), is_error = msg.IsError };
AppendToLastMessage(history, "user", toolResultBlock);
}