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:
1 parent
ecddbe5f36
commit
1fe04025d3
9 files changed
+164
-42
No files matched your search
+25
-14
@@ -220,7 +220,7 @@ function _renderMessagesIntoFragment(fragment, msgs, imageMessageIds, opts) {
|
||||
// ── Grouped Review/Preparer/Finalizer Bubble (tag-based) ──
|
||||
if (msg.tag && (msg.tag === 'review' || msg.tag === 'preparer' || msg.tag === 'finalizer')) {
|
||||
// Collect all consecutive messages with the same tag
|
||||
var tagGroup = [msg];
|
||||
const tagGroup = [msg];
|
||||
while (_msgIdx + 1 < msgs.length && msgs[_msgIdx + 1].tag === msg.tag) {
|
||||
_msgIdx++;
|
||||
tagGroup.push(msgs[_msgIdx]);
|
||||
@@ -250,6 +250,8 @@ function _renderMessagesIntoFragment(fragment, msgs, imageMessageIds, opts) {
|
||||
_addBubbleActions(div, { timestamp: msg.createdAt, messageId: msg.id, deletedOn: msg.deletedOn, isMarked: msg.isMarked });
|
||||
fragment.appendChild(div);
|
||||
} else if (msg.role === 'assistant') {
|
||||
// Whitespace-only Content nicht rendern (z.B. "\n" nach </think>-Extraktion)
|
||||
if (!msg.content || !msg.content.trim()) break;
|
||||
const div = _createMessageBubble({ role: 'assistant', timestamp: msg.createdAt, messageId: msg.id, isMarked: msg.isMarked, deletedOn: msg.deletedOn, archived });
|
||||
div.innerHTML = renderMarkdown(msg.content);
|
||||
parseFluentEmojis(div);
|
||||
@@ -261,12 +263,12 @@ function _renderMessagesIntoFragment(fragment, msgs, imageMessageIds, opts) {
|
||||
}
|
||||
case 'auto_context': {
|
||||
if (msg.content) {
|
||||
var acDiv = document.createElement('div');
|
||||
const acDiv = document.createElement('div');
|
||||
acDiv.className = 'tool-box auto-context-box' + (archived ? ' archived' : '');
|
||||
var acHeader = document.createElement('div');
|
||||
const acHeader = document.createElement('div');
|
||||
acHeader.className = 'tool-box-header clickable';
|
||||
acHeader.innerHTML = '<span class="tool-name">Auto-Context</span>';
|
||||
var acContent = document.createElement('div');
|
||||
const acContent = document.createElement('div');
|
||||
acContent.className = 'auto-context-content markdown';
|
||||
acContent.innerHTML = renderMarkdown(msg.content.replace(/<\/?recalled_context>/g, '').trim());
|
||||
acContent.hidden = true;
|
||||
@@ -279,12 +281,12 @@ function _renderMessagesIntoFragment(fragment, msgs, imageMessageIds, opts) {
|
||||
}
|
||||
case 'thinking': {
|
||||
if (msg.role === 'assistant' && msg.content) {
|
||||
var thinkDiv = document.createElement('div');
|
||||
const thinkDiv = document.createElement('div');
|
||||
thinkDiv.className = 'tool-box thinking-box' + (archived ? ' archived' : '');
|
||||
var thinkHeader = document.createElement('div');
|
||||
const thinkHeader = document.createElement('div');
|
||||
thinkHeader.className = 'tool-box-header clickable';
|
||||
thinkHeader.innerHTML = '<span class="tool-name">Denkprozess</span>';
|
||||
var thinkContent = document.createElement('div');
|
||||
const thinkContent = document.createElement('div');
|
||||
thinkContent.className = 'thinking-content markdown';
|
||||
thinkContent.innerHTML = renderMarkdown(msg.content);
|
||||
thinkContent.hidden = true;
|
||||
@@ -301,17 +303,18 @@ function _renderMessagesIntoFragment(fragment, msgs, imageMessageIds, opts) {
|
||||
continue;
|
||||
}
|
||||
if (!isToolVisible(msg.toolName)) continue;
|
||||
var toolDiv = document.createElement('div');
|
||||
const toolDiv = document.createElement('div');
|
||||
toolDiv.className = 'tool-box' + (archived ? ' archived' : '');
|
||||
toolDiv.dataset.toolName = msg.toolName;
|
||||
if (msg.toolCallId) toolDiv.dataset.toolCallId = msg.toolCallId;
|
||||
renderToolBoxContent(toolDiv, msg.toolName, msg.content, null, false);
|
||||
fragment.appendChild(toolDiv);
|
||||
break;
|
||||
case 'web_search_result': {
|
||||
if (!isToolVisible('web_search')) continue;
|
||||
var wsSources = _extractWebSearchSources(msg.content);
|
||||
const wsSources = _extractWebSearchSources(msg.content);
|
||||
if (wsSources.length === 0) continue;
|
||||
var wsDiv = document.createElement('div');
|
||||
const wsDiv = document.createElement('div');
|
||||
wsDiv.className = 'tool-box' + (archived ? ' archived' : '');
|
||||
wsDiv.dataset.toolName = 'web_search';
|
||||
renderToolBoxContent(wsDiv, 'web_search', null, null, false, wsSources);
|
||||
@@ -320,10 +323,18 @@ function _renderMessagesIntoFragment(fragment, msgs, imageMessageIds, opts) {
|
||||
}
|
||||
case 'tool_result': {
|
||||
if (msg._choiceHandled) continue;
|
||||
const prevBoxes = fragment.querySelectorAll('.tool-box');
|
||||
const lastToolBox = prevBoxes[prevBoxes.length - 1];
|
||||
// Passendes Tool-Box per toolCallId finden (falls verfügbar),
|
||||
// sonst Fallback auf letztes Tool-Box (ältere DB-Einträge ohne toolCallId)
|
||||
let lastToolBox = null;
|
||||
if (msg.toolCallId) {
|
||||
lastToolBox = fragment.querySelector('.tool-box[data-tool-call-id="' + msg.toolCallId + '"]');
|
||||
}
|
||||
if (!lastToolBox) {
|
||||
const prevBoxes = fragment.querySelectorAll('.tool-box');
|
||||
lastToolBox = prevBoxes[prevBoxes.length - 1];
|
||||
}
|
||||
if (lastToolBox) {
|
||||
var existingResult = lastToolBox.querySelector('.tool-result');
|
||||
const existingResult = lastToolBox.querySelector('.tool-result');
|
||||
// todo_write: nachträglich die Todo-Liste rendern (sichtbar)
|
||||
if (lastToolBox.dataset.toolName === 'todo_write' && !lastToolBox.querySelector('.todo-list')) {
|
||||
lastToolBox.appendChild(buildTodoList(msg.content || '', msg.isError));
|
||||
@@ -339,7 +350,7 @@ function _renderMessagesIntoFragment(fragment, msgs, imageMessageIds, opts) {
|
||||
rd.hidden = true;
|
||||
lastToolBox.appendChild(rd);
|
||||
// Header clickable machen
|
||||
var hdr = lastToolBox.querySelector('.tool-box-header');
|
||||
const hdr = lastToolBox.querySelector('.tool-box-header');
|
||||
if (hdr && !hdr.classList.contains('clickable')) {
|
||||
hdr.classList.add('clickable');
|
||||
hdr.addEventListener('click', function() { rd.hidden = !rd.hidden; });
|
||||
|
||||
Reference in new issue
Block a user