From aeb718688e81cc38b3032d34d7476587a74c5df0 Mon Sep 17 00:00:00 2001 From: creatixchu Date: Wed, 5 Aug 2026 15:15:47 +0800 Subject: [PATCH] refactor(web): share the model-facing content body across context forms The opaque and instructions bodies rendered the same text-plus-unknown-block pair, which the duplication gate flagged as a clone. Both now use one ModelFacingContent component; the CI lint gate (lint + duplication) passes. --- .../src/client/chat/ContextBody.tsx | 43 +++++++++++-------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/packages/client/ui-conversation/src/client/chat/ContextBody.tsx b/packages/client/ui-conversation/src/client/chat/ContextBody.tsx index d590d104b5..2978fd9400 100644 --- a/packages/client/ui-conversation/src/client/chat/ContextBody.tsx +++ b/packages/client/ui-conversation/src/client/chat/ContextBody.tsx @@ -83,15 +83,14 @@ function SourceFields({ source, t }: { source: unknown; t: Translate }): ReactNo } /** - * Default presentation: the model-facing text as text, with its real line - * breaks, and the remaining provenance beneath it. This is what every form - * this UI version does not recognize renders as. - * @param props - Durable content, its source, and the locale seat. - * @returns The opaque context body. + * The model-facing content of one context, shared by every form that shows it: + * the text with its real line breaks, then any block this UI version does not + * know, which keeps its own fallback rather than vanishing. + * @param props - Durable content and the locale seat. + * @returns The content blocks as the model received them. */ -export function OpaqueBody({ content, source, t }: { +function ModelFacingContent({ content, t }: { content: ContextMessageNode['content'] - source: unknown t: Translate }): ReactNode { const { text, rest } = partitionContent(content) @@ -106,6 +105,25 @@ export function OpaqueBody({ content, source, t }: { truncatedLabel={total => t('json.truncated', { total })} /> ))} + + ) +} + +/** + * Default presentation: the model-facing text as text, with its real line + * breaks, and the remaining provenance beneath it. This is what every form + * this UI version does not recognize renders as. + * @param props - Durable content, its source, and the locale seat. + * @returns The opaque context body. + */ +export function OpaqueBody({ content, source, t }: { + content: ContextMessageNode['content'] + source: unknown + t: Translate +}): ReactNode { + return ( + <> + ) @@ -168,7 +186,6 @@ export function InstructionsBody({ content, source, t }: { const changes = instructionChanges(source) if (changes === null) return const baseline = asRecord(source)?.['baseline'] === true - const { text, rest } = partitionContent(content) return ( <>
    @@ -181,15 +198,7 @@ export function InstructionsBody({ content, source, t }: { ))}
- {text !== '' &&
{boundedText(text, t)}
} - {rest.map((block, index) => ( - t('json.truncated', { total })} - /> - ))} + ) }