- Remove assistant message headers; show provider icon, model, agent, thinking variant, duration and time in the turn footer (metadata left, hover-revealed actions right) - Merge turns started by hidden user messages (subagent nudges) into the previous turn so Activity, footer and spacing stay continuous - Treat compaction summary text (info.summary) as justification activity in sorted mode and skip it when picking the turn summary - Interleave activity segments with standalone tool rows so Agent Task sits chronologically between activity sections
35 lines
1.4 KiB
TypeScript
35 lines
1.4 KiB
TypeScript
import type { Message, Part } from '@opencode-ai/sdk/v2';
|
|
|
|
import { deriveMessageRole } from './messageRole';
|
|
import { filterVisibleParts, normalizeParts } from './partUtils';
|
|
import { normalizeUserDisplayParts } from './normalizeUserDisplayParts';
|
|
|
|
/**
|
|
* A user message is hidden when none of its parts survive display
|
|
* normalization (e.g. synthetic subagent-completion nudges). Turns separated
|
|
* only by such messages should render as one continuous flow.
|
|
*/
|
|
// Streaming recomputes turn projections often; cache by parts reference so
|
|
// unchanged messages resolve without re-running display normalization.
|
|
const hiddenByPartsPlanMode = new WeakMap<Part[], boolean>();
|
|
const hiddenByPartsNoPlanMode = new WeakMap<Part[], boolean>();
|
|
|
|
export const isHiddenUserMessage = (
|
|
entry: { info: Message; parts: Part[] } | null | undefined,
|
|
options: { planModeEnabled: boolean }
|
|
): boolean => {
|
|
if (!entry) return false;
|
|
if (!deriveMessageRole(entry.info).isUser) return false;
|
|
|
|
const cache = options.planModeEnabled ? hiddenByPartsPlanMode : hiddenByPartsNoPlanMode;
|
|
const cached = cache.get(entry.parts);
|
|
if (cached !== undefined) {
|
|
return cached;
|
|
}
|
|
|
|
const parts = normalizeUserDisplayParts(normalizeParts(entry.parts), { planModeEnabled: options.planModeEnabled });
|
|
const hidden = filterVisibleParts(parts, { includeReasoning: true }).length === 0;
|
|
cache.set(entry.parts, hidden);
|
|
return hidden;
|
|
};
|