UI fixes, cleanups

This commit is contained in:
frdel 2026-01-28 15:53:54 +01:00
parent 5fdc0bdef4
commit dd717dc8cc
5 changed files with 64 additions and 625 deletions

View file

@ -493,6 +493,7 @@
.process-step.expanded > .process-step-detail > .process-step-detail-scroll {
max-height: 40em;
overflow-y: auto;
border-radius: var(--border-radius-sm);
}
.process-step.expanded > .process-step-detail > .process-step-detail-scroll > .process-step-detail-scroll {
@ -625,7 +626,7 @@
margin: var(--spacing-xs) 0 0 0;
padding: var(--spacing-xs);
background: rgba(0, 0, 0, 0.8);
border-radius: 8px;
border-radius: var(--border-radius-sm);
color: #c9d1d9;
white-space: pre;
font-family: monospace;

View file

@ -10,18 +10,14 @@
overflow-y: scroll;
overflow-x: hidden;
scroll-behavior: auto !important; /* avoid infinite scrolling! */
/* padding: var(--spacing-md) 10em 0 !important; */
padding-left: var(--spacing-sm) !important;
padding-right: var(--spacing-md) !important;
padding-top: 4rem !important;
padding-bottom: 4rem !important;
-webkit-transition: all 0.3s ease;
transition: all 0.3s ease;
scrollbar-width: thin;
scrollbar-color: #555 transparent;
padding-left: var(--spacing-sm);
padding-right: var(--spacing-sm);
padding-bottom: 5em;
}
#chat-history > *:first-child {
margin-top: 4.4em;
}
/* Scrollbar styling for Firefox */
@ -577,8 +573,11 @@
@media (max-width: 1024px) {
#chat-history {
padding: var(--spacing-md) var(--spacing-sm) 0 !important;
}
padding-left: var(--spacing-sm) !important;
padding-right: var(--spacing-md) !important;
padding-top: 4rem !important;
padding-bottom: 2rem !important;
}
}
@media (max-width: 640px) {

View file

@ -81,6 +81,7 @@
/* Other variables */
--border-radius: 1.125rem;
--border-radius-sm: 0.5rem;
--transition-speed: 0.3s;
--svg-filter: brightness(0) saturate(100%) var(--color-primary-filter);
--color-primary-filter: invert(73%) sepia(17%) saturate(360%)
@ -739,30 +740,6 @@ h4 {
padding: 0 !important;
}
/* #chat-history .attachment-item {
padding: 0 !important;
background-color: transparent !important;
border: none !important;
box-shadow: none !important;
transform: none !important;
}
#chat-history .attachment-item:hover {
background-color: transparent !important;
border: none !important;
box-shadow: none !important;
transform: none !important;
}
#chat-history .attachment-preview,
#chat-history .attachment-item.image-type .attachment-preview {
background: transparent;
}
.attachment-image .attachment-preview {
margin-right: 0;
} */
.attachment-info,
.file-info {
display: flex;

View file

@ -459,8 +459,6 @@ function setProgressBarShine(progressBarEl, active) {
if (!progressBarEl) return;
if (!active) {
removeClassFromElement(progressBarEl, "shiny-text");
// clear any lingering shines in process steps
msgs.clearActiveStepShine();
} else {
addClassToElement(progressBarEl, "shiny-text");
}

View file

@ -9,73 +9,15 @@ import { store as stepDetailStore } from "/components/modals/process-step-detail
import { store as preferencesStore } from "/components/sidebar/bottom/preferences/preferences-store.js";
import { formatDuration } from "./time-utils.js";
// ============================================
// Timing Constants
// ============================================
// Delay before collapsing previous steps when a new step is added
const STEP_COLLAPSE_DELAY_MS = 3000;
// Delay before collapsing the last step when processing completes
const FINAL_STEP_COLLAPSE_DELAY_MS = 3000;
// // Tool-specific status codes (fallback for tool steps)
// const TOOL_STATUS_CODES = {
// call_subordinate: "SUB",
// search_engine: "WEB",
// a2a_chat: "A2A",
// behaviour_adjustment: "ADJ",
// document_query: "DOC",
// vision_load: "EYE",
// notify_user: "NTF",
// scheduler: "SCH",
// unknown: "UNK",
// memory_save: "MEM",
// memory_load: "MEM",
// memory_forget: "MEM",
// memory_delete: "MEM",
// };
// Tool-specific status classes (fallback for tool steps)
// const TOOL_STATUS_CLASSES = {
// call_subordinate: "status-sub",
// };
const TYPE_STATUS_CODES = {
// agent: "GEN",
response: "END",
// tool: "USE",
// code_exe: "EXE",
// browser: "WWW",
// progress: "HLD",
// mcp: "MCP",
// subagent: "SUB",
info: "INF",
hint: "HNT",
// warning: "WRN",
rate_limit: "WRN",
// error: "ERR",
// util: "UTL",
done: "END",
};
const TYPE_STATUS_CLASSES = {
// agent: "status-gen",
response: "status-end",
// tool: "status-tool",
// code_exe: "status-exe",
// browser: "status-www",
// progress: "status-wait",
// mcp: "status-mcp",
// subagent: "status-sub",
info: "status-inf",
hint: "status-hnt",
// warning: "status-wrn",
rate_limit: "status-wrn",
// error: "status-err",
// util: "status-utl",
done: "status-end",
};
// dom references
let _chatHistory = null;
// state vars
let _massRender = false;
// handlers for log message rendering
@ -120,34 +62,25 @@ export function getMessageHandler(type) {
* Mark a process group as the active one (via .active class)
*/
function setActiveProcessGroup(group) {
if (!group) return;
// if (!group) return;
// Already active? Nothing to do
if (group.classList.contains("active")) return;
// // Already active? Nothing to do
// if (group.classList.contains("active")) return;
// Clear active + shiny from all other groups
getChatHistoryEl()
.querySelectorAll(".process-group.active")
.forEach((g) => {
if (g !== group) {
g.classList.remove("active");
g.querySelectorAll(".step-title.shiny-text").forEach((el) =>
el.classList.remove("shiny-text"),
);
}
});
// // Clear active + shiny from all other groups
// getChatHistoryEl()
// .querySelectorAll(".process-group.active")
// .forEach((g) => {
// if (g !== group) {
// g.classList.remove("active");
// g.querySelectorAll(".step-title.shiny-text").forEach((el) =>
// el.classList.remove("shiny-text"),
// );
// }
// });
// Mark this group as active
group.classList.add("active");
}
export function clearActiveStepShine() {
// Clear all shiny step titles in process steps
getChatHistoryEl()
.querySelectorAll(".process-step .step-title.shiny-text")
.forEach((el) => {
el.classList.remove("shiny-text");
});
// // Mark this group as active
// group.classList.add("active");
}
function getChatHistoryEl() {
@ -393,7 +326,7 @@ function drawProcessStep({
let step = document.getElementById(stepId);
const isNewStep = !step;
const isGroupCompleted = group.classList.contains("process-group-completed");
const isGroupComplete = isProcessGroupComplete(group);
if (isNewStep) {
// create the base DOM element for the step
@ -409,25 +342,6 @@ function drawProcessStep({
// apply step classes
if (classes) step.classList.add(...classes);
// if (toolName) {
// step.setAttribute("data-tool-name", toolName);
// }
// timestamp data
// if (log.timestamp) {
// step.setAttribute("data-timestamp", log.timestamp);
// if (!group.getAttribute("data-start-timestamp")) {
// group.setAttribute("data-start-timestamp", log.timestamp);
// const timeMetricEl = group.querySelector(".metric-time .metric-value");
// if (timeMetricEl) {
// const date = new Date(parseFloat(timestamp) * 1000);
// const hours = String(date.getHours()).padStart(2, "0");
// const minutes = String(date.getMinutes()).padStart(2, "0");
// timeMetricEl.textContent = `${hours}:${minutes}`;
// }
// }
// }
let appendTarget = stepsContainer;
const parentStep = findParentDelegationStep(group, log.agentno);
if (parentStep) {
@ -450,24 +364,22 @@ function drawProcessStep({
// expand all or current step based on settings
const detailMode = preferencesStore.detailMode;
const isActiveGroup = group.classList.contains("active");
// const isActiveGroup = group.classList.contains("active");
//expand all
if (detailMode === "expanded") {
step.classList.add("expanded");
// expand current step and schedule collapse of previous
} else if (detailMode === "current") {
if (isActiveGroup && !isGroupCompleted) {
step.classList.add("expanded");
const allExpandedSteps = stepsContainer.querySelectorAll(
".process-step.expanded",
);
allExpandedSteps.forEach((expandedStep) => {
if (expandedStep.id !== stepId) {
} else if (detailMode === "current" && !isMassRender() && !isGroupComplete) {
step.classList.add("expanded");
const allExpandedSteps = stepsContainer.querySelectorAll(
".process-step.expanded",
);
allExpandedSteps.forEach((expandedStep) => {
if (expandedStep.id !== stepId) {
scheduleStepCollapse(expandedStep, STEP_COLLAPSE_DELAY_MS);
}
});
}
}
}
@ -496,20 +408,7 @@ function drawProcessStep({
"process-step-detail-scroll",
);
// else {
// if (timestamp && !step.hasAttribute("data-timestamp")) {
// step.setAttribute("data-timestamp", timestamp);
// }
// if (agentno !== undefined) {
// step.setAttribute("data-agent-number", agentno);
// }
// }
// const toolNameToUse = resolveToolName(type, kvps, step) || toolName;
// if (toolNameToUse) {
// step.setAttribute("data-tool-name", toolNameToUse);
// }
// expand/collapse handler for step header
if (!stepHeader.hasAttribute("data-expand-handler")) {
stepHeader.setAttribute("data-expand-handler", "true");
stepHeader.addEventListener("click", (e) => {
@ -544,39 +443,7 @@ function drawProcessStep({
const titleEl = ensureChild(stepHeader, ".step-title", "span", "step-title");
titleEl.textContent = title;
// const detail = ensureChild(step, ".process-step-detail", "div", "process-step-detail");
// const detailContent = ensureChild(
// detail,
// ".process-step-detail-content",
// "div",
// "process-step-detail-content",
// );
// let skipFullRender = false;
// const terminal = stepDetailContent.querySelector(".terminal-output");
// const scroller = terminal ? new Scroller(terminal) : null;
// if (type === "browser" && kvps?.screenshot) {
// const existingImg = detailContent.querySelector(".screenshot-img");
// const newSrc = kvps.screenshot.replace("img://", "/image_get?path=");
// if (existingImg) {
// if (!existingImg.src.endsWith(newSrc.split("?path=")[1])) {
// existingImg.src = newSrc;
// }
// skipFullRender = true;
// }
// }
// if (!skipFullRender) {
// renderStepDetailContent(detailContent, content, kvps, type);
// const newTerminal = detailContent.querySelector(".terminal-output");
// if (newTerminal && scroller?.wasAtBottom) {
// newTerminal.scrollTop = newTerminal.scrollHeight;
// }
// }
// auto-scroller of the step detail
const detailScroller = new Scroller(stepDetailScroll); // scroller for step detail content
// update KVPs of the step detail
@ -592,14 +459,9 @@ function drawProcessStep({
);
stepDetailContent.textContent = content;
// const detailDataToUse =
// detailData ||
// buildDetailPayload({
// ...stepData,
// toolName: toolNameToUse,
// statusCode: resolvedStatusCode,
// statusClass: resolvedStatusClass,
// });
// reapply scroll position (autoscroll if bottom) - only when expanded already and not mass rendering
if (isExpanded && !isMassRender()) detailScroller.reApplyScroll();
// Render action buttons: get/create container, clear, append
const stepActionBtns = ensureChild(
@ -614,11 +476,15 @@ function drawProcessStep({
.filter(Boolean)
.forEach((button) => stepActionBtns.appendChild(button));
if (isExpanded && !isMassRender()) detailScroller.reApplyScroll(); // reapply scroll position (autoscroll if bottom) - only when expanded already and not
// update the process grop header by this step
updateProcessGroupHeader(group);
if (isNewStep && !isGroupCompleted) {
// remove shine from previous steps and add to this one if new and not completed
if (isNewStep && !isGroupComplete) {
stepDetailScroll.querySelectorAll(".step-title.shiny-text").forEach((el) => {
el.classList.remove("shiny-text");
});
titleEl.classList.add("shiny-text");
}
@ -1553,137 +1419,6 @@ export function drawMessageError({
});
}
// export function drawMessageError({
// id,
// heading,
// content,
// kvps = null,
// ...additional
// }) {
// const messageContainer = getOrCreateMessageContainer(id, "mid", [
// "ai-container",
// "center-container",
// ]);
// // Create or get the message div
// let messageDiv = messageContainer.querySelector(".message");
// if (!messageDiv) {
// messageDiv = document.createElement("div");
// messageDiv.classList.add("message", "message-error-group");
// messageContainer.appendChild(messageDiv);
// }
// // Check if error group already exists
// let errorGroup = messageDiv.querySelector(".error-group");
// if (!errorGroup) {
// errorGroup = document.createElement("div");
// errorGroup.classList.add("error-group");
// errorGroup.setAttribute("data-error-id", id);
// // Create header (clickable for expand/collapse)
// const header = document.createElement("div");
// header.classList.add("error-group-header");
// // Expand icon (triangle)
// const expandIcon = document.createElement("span");
// expandIcon.classList.add("expand-icon");
// header.appendChild(expandIcon);
// // Status badge (before title)
// const badge = document.createElement("span");
// badge.classList.add("step-badge", "status-err");
// badge.textContent = "ERR";
// header.appendChild(badge);
// // Title
// const title = document.createElement("span");
// title.classList.add("error-title");
// title.textContent = "Error";
// header.appendChild(title);
// // Subtitle (short error description)
// const subtitle = document.createElement("span");
// subtitle.classList.add("error-subtitle");
// header.appendChild(subtitle);
// // Click handler for expand/collapse
// header.addEventListener("click", () => {
// errorGroup.classList.toggle("expanded");
// });
// errorGroup.appendChild(header);
// // Create content container (collapsible)
// const contentWrapper = document.createElement("div");
// contentWrapper.classList.add("error-group-content");
// const contentInner = document.createElement("div");
// contentInner.classList.add("error-content-inner");
// contentWrapper.appendChild(contentInner);
// errorGroup.appendChild(contentWrapper);
// messageDiv.appendChild(errorGroup);
// // Check detail mode and expand if needed
// const detailMode = preferencesStore.detailMode || "current";
// if (detailMode === "current" || detailMode === "expanded") {
// errorGroup.classList.add("expanded");
// }
// }
// // Update subtitle with short error description
// const subtitle = errorGroup.querySelector(".error-subtitle");
// if (subtitle) {
// // Extract short description from heading or content
// let shortDesc = "";
// // Skip if heading is just "Error" (redundant with title)
// if (heading && heading.trim() && heading.trim().toLowerCase() !== "error") {
// shortDesc = heading.trim();
// }
// // If no useful heading, try to extract from content
// if (!shortDesc && content && content.trim()) {
// const lines = content.trim().split("\n");
// // Look for the error line (usually last meaningful line or one matching ErrorType: pattern)
// for (let i = lines.length - 1; i >= 0; i--) {
// const line = lines[i].trim();
// if (line && /^[\w\.]+Error[:\s]/.test(line)) {
// shortDesc = line;
// break;
// }
// }
// // Fallback to first non-empty line if no error pattern found
// if (!shortDesc) {
// for (const line of lines) {
// if (line.trim() && !line.startsWith("Traceback")) {
// shortDesc = line.trim();
// break;
// }
// }
// }
// }
// // Truncate if too long
// if (shortDesc.length > 100) {
// shortDesc = shortDesc.substring(0, 97) + "...";
// }
// subtitle.textContent = shortDesc;
// subtitle.title = shortDesc; // Full text on hover
// }
// // Update content (full callstack)
// const contentInner = errorGroup.querySelector(".error-content-inner");
// if (contentInner && content) {
// contentInner.innerHTML = "";
// // Create pre element for callstack/content
// const pre = document.createElement("pre");
// pre.classList.add("error-callstack");
// pre.textContent = content;
// contentInner.appendChild(pre);
// }
// messageContainer.classList.add("center-container");
// }
function drawKvpsIncremental(container, kvps, latex) {
// existing KVPS table
@ -1809,27 +1544,6 @@ function convertToTitleCase(str) {
});
}
/**
* Clean text value by removing standalone bracket lines and trimming
* Handles both strings and arrays (filters out bracket-only items)
*/
// function cleanTextValue(value) {
// if (Array.isArray(value)) {
// return value
// .filter(
// (item) =>
// item && String(item).trim() && !/^[\[\]]$/.test(String(item).trim()),
// )
// .join("\n");
// }
// if (typeof value === "object" && value !== null) {
// return JSON.stringify(value, null, 2);
// }
// return String(value)
// .replace(/^\s*[\[\]]\s*$/gm, "")
// .trim();
// }
function convertImageTags(content) {
// Regular expression to match <image> tags and extract base64 content
const imageTagRegex = /<image>(.*?)<\/image>/g;
@ -2173,15 +1887,6 @@ function findParentDelegationStep(group, agentno) {
* Get a concise title for a process step
*/
function getStepTitle(heading, kvps, type) {
// code_exe: show command when finished
// const showCommand =
// type === "code_exe" &&
// kvps?.code &&
// /done_all|code_execution_tool/.test(heading || "");
// if (showCommand) {
// const s = kvps.session ?? kvps.Session;
// return `${s != null ? `[${s}] ` : ""}${kvps.runtime || "bash"}> ${kvps.code.trim()}`;
// }
// Try to get a meaningful title from heading or kvps
if (heading && heading.trim()) {
@ -2243,222 +1948,6 @@ function cleanStepTitle(text, maxLength = 100) {
return truncateText(cleaned, maxLength);
}
/**
* Render content for step detail panel
*/
// function renderStepDetailContent(container, content, kvps, type = null) {
// container.innerHTML = "";
// drawKvpsIncremental(container, kvps);
// // Special handling for response type - show content as markdown (for subordinate responses)
// if (type === "response" && content && content.trim()) {
// const responseDiv = document.createElement("div");
// responseDiv.classList.add("step-response-content");
// // Parse markdown
// let processedContent = content;
// processedContent = convertImageTags(processedContent);
// processedContent = convertImgFilePaths(processedContent);
// processedContent = convertFilePaths(processedContent);
// processedContent = marked.parse(processedContent, { breaks: true });
// processedContent = convertPathsToLinks(processedContent);
// processedContent = addBlankTargetsToLinks(processedContent);
// responseDiv.innerHTML = processedContent;
// container.appendChild(responseDiv);
// return;
// }
// // Special handling for warning/error types - always show content prominently
// if ((type === "warning" || type === "error") && content && content.trim()) {
// const warningDiv = document.createElement("div");
// warningDiv.classList.add("step-warning-content");
// warningDiv.textContent = content;
// container.appendChild(warningDiv);
// // Don't return - also show kvps if present
// }
// // Special handling for code_exe type - render as terminal-style output
// if (type === "code_exe" && kvps) {
// const runtime = kvps.runtime || kvps.Runtime || "bash";
// const code = kvps.code || kvps.Code || "";
// const output = content || "";
// if (code || output) {
// const terminalDiv = document.createElement("div");
// terminalDiv.classList.add("step-terminal");
// // Show output if present (no truncation - CSS handles max-height)
// if (output && output.trim()) {
// const outputPre = document.createElement("pre");
// outputPre.classList.add("terminal-output");
// // Escape HTML first, then convert paths to clickable links
// let processedOutput = escapeHTML(output);
// processedOutput = convertPathsToLinks(processedOutput);
// outputPre.innerHTML = processedOutput;
// terminalDiv.appendChild(outputPre);
// }
// container.appendChild(terminalDiv);
// }
// // Still render thoughts if present (but not reasoning - that's native model thinking, not structured output)
// if (kvps.thoughts || kvps.thinking) {
// const thoughtKey = kvps.thoughts ? "thoughts" : "thinking";
// const thoughtValue = kvps[thoughtKey];
// renderThoughts(container, thoughtValue);
// }
// return;
// }
// // Add KVPs if present
// if (kvps && Object.keys(kvps).length > 0) {
// const kvpsDiv = document.createElement("div");
// kvpsDiv.classList.add("step-kvps");
// for (const [key, value] of Object.entries(kvps)) {
// // Skip internal/display keys
// if (key === "finished" || key === "attachments") continue;
// // Skip code_exe specific keys that we handle specially above
// if (
// type === "code_exe" &&
// (key.toLowerCase() === "runtime" ||
// key.toLowerCase() === "session" ||
// key.toLowerCase() === "code")
// ) {
// continue;
// }
// const lowerKey = key.toLowerCase();
// // Skip headline and tool_name - they're shown elsewhere
// if (lowerKey === "headline" || lowerKey === "tool_name") continue;
// // Skip query in agent steps - it's shown in the tool call step
// if (type === "agent" && lowerKey === "query") continue;
// // Special handling for thoughts - render with single lightbulb icon
// // Skip reasoning
// if (lowerKey === "reasoning") continue;
// if (
// lowerKey === "thoughts" ||
// lowerKey === "thinking" ||
// lowerKey === "reflection"
// ) {
// renderThoughts(kvpsDiv, value);
// continue;
// }
// // Special handling for tool_args - render only for tool/mcp types (skip for agent)
// if (lowerKey === "tool_args") {
// // Skip tool_args for agent steps - it's shown in the tool call step
// if (type === "agent") continue;
// if (typeof value !== "object" || value === null) continue;
// const argsDiv = document.createElement("div");
// argsDiv.classList.add("step-tool-args");
// for (const [argKey, argValue] of Object.entries(value)) {
// const argRow = document.createElement("div");
// argRow.classList.add("tool-arg-row");
// const argLabel = document.createElement("span");
// argLabel.classList.add("tool-arg-label");
// const iconName = extractIconFromKey(argKey);
// if (iconName) {
// argLabel.innerHTML = `<span class="material-symbols-outlined">${iconName}</span>`;
// } else {
// argLabel.textContent = convertToTitleCase(argKey) + ":";
// }
// const argVal = document.createElement("span");
// argVal.classList.add("tool-arg-value");
// const argText = cleanTextValue(argValue);
// argVal.textContent = truncateText(argText, 300);
// argRow.appendChild(argLabel);
// argRow.appendChild(argVal);
// argsDiv.appendChild(argRow);
// }
// kvpsDiv.appendChild(argsDiv);
// continue;
// }
// const kvpDiv = document.createElement("div");
// kvpDiv.classList.add("step-kvp");
// const keySpan = document.createElement("span");
// keySpan.classList.add("step-kvp-key");
// const iconName = extractIconFromKey(key);
// if (iconName) {
// keySpan.innerHTML = `<span class="material-symbols-outlined">${iconName}</span>`;
// } else {
// keySpan.textContent = convertToTitleCase(key) + ":";
// }
// const valueSpan = document.createElement("div");
// valueSpan.classList.add("step-kvp-value");
// if (typeof value === "string" && value.startsWith("img://")) {
// const imgElement = document.createElement("img");
// imgElement.classList.add("screenshot-img");
// imgElement.src = value.replace("img://", "/image_get?path=");
// imgElement.alt = "Image Attachment";
// imgElement.style.cursor = "pointer";
// imgElement.style.maxWidth = "100%";
// imgElement.style.display = "block";
// imgElement.style.marginTop = "4px";
// // Add click handler and cursor change
// imgElement.addEventListener("click", () => {
// imageViewerStore.open(imgElement.src, { name: "Image Attachment" });
// });
// valueSpan.appendChild(imgElement);
// } else {
// const valueText = cleanTextValue(value);
// valueSpan.textContent = truncateText(valueText, 1000);
// }
// kvpDiv.appendChild(keySpan);
// kvpDiv.appendChild(valueSpan);
// kvpsDiv.appendChild(kvpDiv);
// }
// container.appendChild(kvpsDiv);
// }
// // Add main content if present (JSON content)
// if (content && content.trim()) {
// const pre = document.createElement("pre");
// pre.classList.add("msg-json");
// pre.textContent = truncateText(content, 1000);
// container.appendChild(pre);
// }
// }
/**
* Helper to render thoughts/reasoning with lightbulb icon
*/
// function renderThoughts(container, value) {
// const thoughtsDiv = document.createElement("div");
// thoughtsDiv.classList.add("step-thoughts", "msg-thoughts");
// const thoughtText = cleanTextValue(value);
// if (thoughtText) {
// thoughtsDiv.innerHTML = `<span class="thought-icon material-symbols-outlined">lightbulb</span><span class="thought-text">${escapeHTML(thoughtText)}</span>`;
// container.appendChild(thoughtsDiv);
// }
// }
/**
* Update process group header with step count, status, and metrics
@ -2469,8 +1958,7 @@ function updateProcessGroupHeader(group) {
const titleEl = header.querySelector(".group-title");
const badgeEl = header.querySelector(".step-badge");
const metricsEl = header.querySelector(".group-metrics");
const response = group.querySelector(".process-group-response");
const isCompleted = !!response;
const isCompleted = isProcessGroupComplete(group);
const notificationsEl = metricsEl?.querySelector(".metric-notifications");
// Update group title with the latest agent step heading
@ -2494,7 +1982,12 @@ function updateProcessGroupHeader(group) {
// If completed, set badge to END
if (isCompleted) {
// set end badge
badgeEl.outerHTML = `<span class="step-badge END">END</span>`;
// remove shine from any steps
group.querySelectorAll(".step-title.shiny-text").forEach((el) => {
el.classList.remove("shiny-text");
});
} else {
// if not complete, clone the last step badge
if (badgeEl && steps.length > 0) {
@ -2502,6 +1995,7 @@ function updateProcessGroupHeader(group) {
const code = lastStep.getAttribute("data-step-code");
badgeEl.outerHTML = `<span class="step-badge ${code}">${code}</span>`;
}
}
// Update step count in metrics - All GEN steps from all agents per process group
@ -2573,42 +2067,12 @@ function updateProcessGroupHeader(group) {
}
}
if (steps.length > 0) {
// Get the last step's type for status
// const lastStep = steps[steps.length - 1];
// const lastType = lastStep.getAttribute("data-type");
// const lastToolName = lastStep.getAttribute("data-tool-name");
// const lastTitle = lastStep.querySelector(".step-title")?.textContent || "";
// Update status badge
// if (statusEl) {
// const statusCode = getStatusCode(lastType, lastToolName);
// const statusColorClass = getStatusClass(lastType, lastToolName);
// statusEl.textContent = statusCode;
// statusEl.className = `step-badge ${statusColorClass} group-status`;
// }
// Update title
// if (titleEl) {
// // Prefer agent type steps for the group title as they contain thinking/planning info
// if (lastType === "agent" && lastTitle) {
// titleEl.textContent = cleanStepTitle(lastTitle, 50);
// } else {
// // Try to find the most recent agent step for a better title
// const agentSteps = group.querySelectorAll(
// '.process-step[data-type="agent"]',
// );
// if (agentSteps.length > 0) {
// const lastAgentStep = agentSteps[agentSteps.length - 1];
// const agentTitle =
// lastAgentStep.querySelector(".step-title")?.textContent || "";
// if (agentTitle) {
// titleEl.textContent = cleanStepTitle(agentTitle, 50);
// return;
// }
// }
// titleEl.textContent = cleanStepTitle(lastTitle, 50) || `Processing...`;
// }
// }
}
}
function isProcessGroupComplete(group) {
const response = group.querySelector(".process-group-response");
return !!response;
}
/**