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

+6 -6
View File
@@ -138,7 +138,7 @@ public partial class AnthropicService
}
/// <summary>Extrahiert die letzten N User-Texte für Query-Erweiterung.</summary>
private static string ExtractRecentUserTexts(List<object> messages, int count = 3, int maxLength = 500)
internal static string ExtractRecentUserTexts(List<object> messages, int count = 3, int maxLength = 500)
{
var texts = new List<string>();
for (int i = messages.Count - 1; i >= 0 && texts.Count < count; i--)
@@ -171,21 +171,21 @@ public partial class AnthropicService
/// <summary>
/// Baut den AutoContext-String aus Embedding-Suche.
/// Shared zwischen StreamChat und StreamChatViaCli.
/// Shared zwischen StreamChat, StreamChatViaCli und OpenAiService.
/// </summary>
private async Task<string> BuildAutoContextAsync(List<object> messages, string chainId, string agentId)
internal static async Task<string> BuildAutoContextAsync(VectorSearchService vectorSearch, List<object> messages, string chainId, string agentId)
{
if (_vectorSearch == null || messages.Count == 0) return null;
if (vectorSearch == null || messages.Count == 0) return null;
// Query-Erweiterung: letzte 2-3 User-Messages statt nur die letzte
var queryText = ExtractRecentUserTexts(messages, count: 3, maxLength: 500);
if (string.IsNullOrWhiteSpace(queryText)) return null;
var contextResults = await _vectorSearch.SearchAsync(queryText, agentId, topN: 5, minScore: 0.35f);
var contextResults = await vectorSearch.SearchAsync(queryText, agentId, topN: 5, minScore: 0.35f);
// Note: threshold lowered from 0.45 to 0.35 because hybrid search is now more precise
contextResults.RemoveAll(r => r.ChainId == chainId || (r.TextPreview?.Length ?? 0) < 20);
var memoryResults = await _vectorSearch.SearchMemoryFilesAsync(queryText, agentId, topN: 3, minScore: 0.35f);
var memoryResults = await vectorSearch.SearchMemoryFilesAsync(queryText, agentId, topN: 3, minScore: 0.35f);
if (contextResults.Count == 0 && memoryResults.Count == 0) return null;