Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
158 changes: 0 additions & 158 deletions packages/web/src/components/sdk/RunningBorder.tsx

This file was deleted.

19 changes: 10 additions & 9 deletions packages/web/src/components/sdk/SDKAssistantMessage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,10 @@ interface Props {
responses: QuestionDraftResponse[]
) => void;
/**
* When true, child tool / thinking / subagent blocks in this message are
* each wrapped in <RunningBorder> so the animated arc traces their border.
* Set by the compact task thread renderer for the last non-terminal message.
* When true, child tool / thinking / subagent blocks in this message each
* show a faint white shimmer sweep (the `.running-shimmer` overlay) across
* their surface. Set by the compact task thread renderer for the last
* non-terminal message.
*/
isRunning?: boolean;
/** Tool use IDs within this message whose cards are currently running. */
Expand Down Expand Up @@ -257,10 +258,10 @@ export function SDKAssistantMessage({
// If so, we should not show a checkbox for this message (the sub-agent messages will have their own).
// Normal mode - original layout
//
// When isRunning, ALL blocks in this message receive the animated arc so
// When isRunning, ALL blocks in this message show the running shimmer so
// every block type is visible for debugging/verification. Each component
// applies the arc via a wrapper div (not directly on its overflow:hidden
// root) so the inset:-2px extension isn't clipped.
// renders the `.running-shimmer` overlay inside its own card, contained by
// the card's overflow-hidden rounded surface.
const messageContent = (
<div
class="py-2 space-y-3"
Expand Down Expand Up @@ -358,9 +359,9 @@ function ToolUseBlock({
state: 'submitted' | 'cancelled',
responses: QuestionDraftResponse[]
) => void;
/** When true, wrap this block's outermost visible bordered card in
* <RunningBorder>. Used by the compact task thread renderer to indicate the
* last still-executing event message. */
/** When true, show a faint white shimmer sweep (the `.running-shimmer`
* overlay) across this block's surface. Used by the compact task thread
* renderer to indicate the last still-executing event message. */
isRunning?: boolean;
/** Render Task/Agent tool_use blocks as generic tool cards when true. */
flattenSubagentTools?: boolean;
Expand Down
6 changes: 3 additions & 3 deletions packages/web/src/components/sdk/SDKMessageRenderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,9 @@ interface Props {
showToolResultUserMessages?: boolean;
/**
* When true, the last non-terminal event message in a compact task thread is
* still executing. The receiving component wraps its visible boundary element
* (e.g. the assistant message bubble or tool card) in <RunningBorder> so the
* animated arc traces exactly that element's rounded-rect border.
* still executing. The receiving component shows a faint white shimmer sweep
* (the `.running-shimmer` overlay) across its visible boundary element (e.g.
* the assistant message bubble or tool card).
*/
isRunning?: boolean;
/** Tool use IDs within this assistant message whose cards are currently running. */
Expand Down
27 changes: 16 additions & 11 deletions packages/web/src/components/sdk/SubagentBlock.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
import type { ComponentChild } from 'preact';
import { useState, useMemo } from 'preact/hooks';
import { cn } from '../../lib/utils.ts';
import { RunningBorder } from './RunningBorder.tsx';
import MarkdownRenderer from '../chat/MarkdownRenderer.tsx';
import type { AgentInput } from '@hyperneo/shared/sdk/sdk-tools.d.ts';
import type {
Expand Down Expand Up @@ -133,8 +132,8 @@ interface SubagentBlockProps {
taskProgressMap?: Map<string, SDKTaskProgressMessage>;
/** Additional CSS classes */
className?: string;
/** When true, wrap this block in <RunningBorder> so the animated arc traces
* this card's outer rounded-rectangle border. */
/** When true, show a faint white shimmer sweep (the `.running-shimmer`
* overlay) across this block's surface. */
isRunning?: boolean;
}

Expand Down Expand Up @@ -416,12 +415,19 @@ export function SubagentBlock({
return completed;
}, [nestedMessages]);

// The running-state arc is rendered by <RunningBorder> as an absolutely
// positioned SVG sibling (applied via a wrapper below). It cannot live on
// this div because overflow:hidden would clip the SVG that extends slightly
// past the card's outer edge.
// The running-state shimmer is a `.running-shimmer` overlay rendered inside
// this card while isRunning (added below). overflow-hidden contains it to
// the card's rounded surface.
const block = (
<div class={cn('border rounded-lg overflow-hidden', colors.bg, colors.border, className)}>
<div
class={cn(
'border rounded-lg overflow-hidden',
isRunning && 'relative',
colors.bg,
colors.border,
className
)}
>
{/* Header */}
<button
onClick={() => setIsExpanded(!isExpanded)}
Expand Down Expand Up @@ -580,11 +586,10 @@ export function SubagentBlock({
</div>
</div>
)}
{isRunning && <div class="running-shimmer" aria-hidden="true" />}
</div>
);
if (isRunning) {
return <RunningBorder borderRadius={8}>{block}</RunningBorder>;
}

return block;
}

Expand Down
18 changes: 11 additions & 7 deletions packages/web/src/components/sdk/ThinkingBlock.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,14 @@

import { useState, useRef, useLayoutEffect } from 'preact/hooks';
import { cn } from '../../lib/utils.ts';
import { RunningBorder } from './RunningBorder.tsx';

interface ThinkingBlockProps {
content: string;
className?: string;
/** Compact mode: shows only first line with no expand/collapse button */
compact?: boolean;
/** When true, wrap this card in <RunningBorder> so the animated arc traces
* this card's outer rounded-rectangle border. */
/** When true, show a faint white shimmer sweep (the `.running-shimmer`
* overlay) across this card's surface. */
isRunning?: boolean;
/** Optional estimated token count for this thinking block (persisted from SDK) */
estimatedTokens?: number;
Expand Down Expand Up @@ -78,7 +77,13 @@ export function ThinkingBlock({

const inner = (
<div
class={cn('border rounded-lg overflow-hidden', colors.bg, colors.border, className)}
class={cn(
'border rounded-lg overflow-hidden',
isRunning && 'relative',
colors.bg,
colors.border,
className
)}
data-testid="thinking-block"
>
{/* Header */}
Expand Down Expand Up @@ -176,11 +181,10 @@ export function ThinkingBlock({
</div>
)}
</div>

{isRunning && <div class="running-shimmer" aria-hidden="true" />}
</div>
);

if (isRunning) {
return <RunningBorder borderRadius={8}>{inner}</RunningBorder>;
}
return inner;
}
15 changes: 15 additions & 0 deletions packages/web/src/components/sdk/__tests__/ThinkingBlock.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -333,4 +333,19 @@ describe('ThinkingBlock', () => {
expect(container.textContent).toContain('Thinking');
});
});

describe('Running shimmer indicator', () => {
it('shows the .running-shimmer overlay while running', () => {
const { container } = render(<ThinkingBlock content="Thinking..." isRunning />);

const card = container.querySelector('[data-testid="thinking-block"]');
expect(card?.querySelector('.running-shimmer')).toBeTruthy();
});

it('does not show the .running-shimmer overlay when not running', () => {
const { container } = render(<ThinkingBlock content="Thinking..." />);

expect(container.querySelector('.running-shimmer')).toBeNull();
});
});
});
23 changes: 14 additions & 9 deletions packages/web/src/components/sdk/tools/ToolResultCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import {
} from './tool-utils.ts';
import { isFileReadOutput, isFileEditOutput, isFileWriteOutput } from './sdk-tool-types.ts';
import { cn } from '../../../lib/utils.ts';
import { RunningBorder } from '../RunningBorder.tsx';
import { connectionManager } from '../../../lib/connection-manager.ts';
import { toast } from '../../../lib/toast.ts';
import { ConfirmModal } from '../../ui/ConfirmModal.tsx';
Expand Down Expand Up @@ -257,12 +256,19 @@ export function ToolResultCard({
const lineCountDisplay = getLineCountDisplay();

// Default & detailed variants - full display with expand/collapse
// Note: the running-state arc is rendered by <RunningBorder> as an absolutely
// positioned SVG sibling (applied via a wrapper below). It cannot live on this
// div because overflow:hidden would clip the SVG that extends slightly past
// the card's outer edge.
// Note: the running-state shimmer is a `.running-shimmer` overlay rendered
// inside this card while isRunning (added below). overflow-hidden contains
// it to the card's rounded surface.
const card = (
<div class={cn('border rounded-lg overflow-hidden', colors.bg, colors.border, className)}>
<div
class={cn(
'border rounded-lg overflow-hidden',
isRunning && 'relative',
colors.bg,
colors.border,
className
)}
>
{/* Header - clickable to expand/collapse */}
<button
onClick={() => !disableExpand && setIsExpanded(!isExpanded)}
Expand Down Expand Up @@ -653,10 +659,9 @@ export function ToolResultCard({
confirmButtonVariant="danger"
isLoading={deleting}
/>
{isRunning && <div class="running-shimmer" aria-hidden="true" />}
</div>
);
if (isRunning) {
return <RunningBorder borderRadius={8}>{card}</RunningBorder>;
}

return card;
}
4 changes: 2 additions & 2 deletions packages/web/src/components/sdk/tools/tool-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,8 @@ export interface ToolResultCardProps {
isOutputRemoved?: boolean;
/** Disable expand/collapse and hide the chevron icon */
disableExpand?: boolean;
/** When true, wrap this card in <RunningBorder> so the animated arc traces
* this card's outer rounded-rectangle border. */
/** When true, show a faint white shimmer sweep (the `.running-shimmer`
* overlay) across this card's surface. */
isRunning?: boolean;
/** Terminal task_notification for this tool_use (status/summary/usage).
* Folded onto the card instead of rendered as a standalone system row. */
Expand Down
Loading
Loading