fix: TodoWrite-Tool über CLI korrekt als Todo-Liste rendern

TodoWrite → todo_write Mapping in Backend und Frontend ergänzt.
Todo-Liste wird jetzt aus dem Input-Array gebaut statt aus dem
Result, da die CLI nur einen generischen Erfolgstext zurückgibt.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
MelekiandClaude Opus 4.6 committed 2026-03-20 07:07:12 +01:00
1 parent 2494ca89b8
commit 9c507e4716
2 files changed
+67 -3

No files matched your search

+1
View File
@@ -340,6 +340,7 @@ public partial class AnthropicService
"WebSearch" => "web_search", "WebSearch" => "web_search",
"WebFetch" => "web_fetch", "WebFetch" => "web_fetch",
"NotebookEdit" => "notebook_edit", "NotebookEdit" => "notebook_edit",
"TodoWrite" => "todo_write",
_ => cliName?.StartsWith("mcp__") == true ? cliName.Split("__").LastOrDefault() ?? cliName : cliName _ => cliName?.StartsWith("mcp__") == true ? cliName.Split("__").LastOrDefault() ?? cliName : cliName
}; };
} }
+66 -3
View File
@@ -10,6 +10,7 @@ const CLI_TOOL_NAME_MAP = {
'WebSearch': 'web_search', 'WebSearch': 'web_search',
'WebFetch': 'web_fetch', 'WebFetch': 'web_fetch',
'NotebookEdit': 'notebook_edit', 'NotebookEdit': 'notebook_edit',
'TodoWrite': 'todo_write',
'ToolSearch': 'tool_search', 'ToolSearch': 'tool_search',
'mcp__gott-remote__remote_execute': 'remote_execute' 'mcp__gott-remote__remote_execute': 'remote_execute'
}; };
@@ -195,8 +196,13 @@ function renderToolBoxContent(div, rawName, inputJson, result, isError, sources)
foldTarget = preview; foldTarget = preview;
} else if (name === 'todo_write') { } else if (name === 'todo_write') {
// Todo-Liste: kein tool-input, standardmäßig sichtbar, custom parser // Todo-Liste: aus Input bauen (CLI hat nur generisches Result, API formatiert Result)
if (result) { // Priorität: parsedInput.todos (immer vorhanden) > result (nur bei API-Pfad formatiert)
if (parsedInput && parsedInput.todos && Array.isArray(parsedInput.todos)) {
const todoList = buildTodoListFromInput(parsedInput.todos, isError);
div.appendChild(todoList);
foldTarget = todoList;
} else if (result) {
const todoList = buildTodoList(result, isError); const todoList = buildTodoList(result, isError);
div.appendChild(todoList); div.appendChild(todoList);
foldTarget = todoList; foldTarget = todoList;
@@ -325,6 +331,52 @@ function buildTodoList(result, isError) {
return container; return container;
} }
/** Baut Todo-Liste direkt aus dem Input-Array (für CLI-Pfad, wo Result nur generischer Text ist). */
function buildTodoListFromInput(todos, isError) {
const container = document.createElement('div');
container.className = 'todo-list' + (isError ? ' tool-error' : '');
for (var i = 0; i < todos.length; i++) {
const todo = todos[i];
const row = document.createElement('div');
row.className = 'todo-item';
const status = todo.status || 'pending';
const icon = status === 'completed' ? '✅' : status === 'in_progress' ? '🔄' : '⬜';
const statusClass = status === 'completed' ? 'todo-done' : status === 'in_progress' ? 'todo-progress' : 'todo-pending';
row.classList.add(statusClass);
const iconSpan = document.createElement('span');
iconSpan.className = 'todo-icon';
iconSpan.textContent = icon;
const idSpan = document.createElement('span');
idSpan.className = 'todo-id';
idSpan.textContent = (todo.id || (i + 1)) + '.';
const textSpan = document.createElement('span');
textSpan.className = 'todo-text';
// CLI hat "activeForm" statt nur "content" – zeige content (Imperativ-Form)
textSpan.textContent = todo.content || todo.activeForm || '';
row.appendChild(iconSpan);
row.appendChild(idSpan);
row.appendChild(textSpan);
if (todo.priority) {
const prioSpan = document.createElement('span');
prioSpan.className = 'todo-prio todo-prio-' + todo.priority.toLowerCase();
prioSpan.textContent = todo.priority;
row.appendChild(prioSpan);
}
container.appendChild(row);
}
parseFluentEmojis(container);
return container;
}
function finishToolBox(div, data) { function finishToolBox(div, data) {
if (!div) return; if (!div) return;
renderToolBoxContent(div, data.name, data.input, data.result, data.isError, data.sources); renderToolBoxContent(div, data.name, data.input, data.result, data.isError, data.sources);
@@ -334,10 +386,21 @@ function finishToolBox(div, data) {
/** Fügt ein Tool-Result nachträglich an eine bestehende Tool-Box an (CLI tool_result Events). */ /** Fügt ein Tool-Result nachträglich an eine bestehende Tool-Box an (CLI tool_result Events). */
function appendToolResult(div, result, isError) { function appendToolResult(div, result, isError) {
if (!div || !result) return; if (!div || !result) return;
var toolName = div.dataset.toolName;
// todo_write: Liste wurde bereits aus Input gebaut (in renderToolBoxContent)
if (toolName === 'todo_write') {
if (div.querySelector('.todo-list')) return; // Bereits vorhanden
// Fallback: versuche aus Result zu parsen (API-Pfad)
var todoList = buildTodoList(result, isError);
div.appendChild(todoList);
scrollDown();
return;
}
// Nur anfügen wenn noch kein Result vorhanden // Nur anfügen wenn noch kein Result vorhanden
if (div.querySelector('.tool-result')) return; if (div.querySelector('.tool-result')) return;
// Bei edit_file/write_file: Diff reicht, kein extra Result nötig // Bei edit_file/write_file: Diff reicht, kein extra Result nötig
var toolName = div.dataset.toolName;
if (toolName === 'edit_file' || toolName === 'write_file') return; if (toolName === 'edit_file' || toolName === 'write_file') return;
var rd = document.createElement('div'); var rd = document.createElement('div');