Make the final reply always visible and fix artifacts-panel dead clicks
Why: field report two — the final answer collapsed into the process area (the CF0 long-reply fold swallowed 2000+ char replies and the model inlines narration, so users saw "everything folded") and the artifacts workspace panel preview clicks did nothing (the full-screen overlay stayed up, hiding the rail the preview opened in). Evidence: - Conversation.tsx: removed the CF0 LongReplyCollapse entirely — the final output contract is "the reply to the user is always fully visible; only process parts fold"; deliverable cards stay pinned after the reply - Workspaces.tsx ArtifactsPanel: row click and fullscreen action now close the workspace overlay before requesting the rail/fullscreen preview, so the preview is actually on screen - vitest 40/40, tsc clean; no design-guard regressions (no new colors, keyframes, or inline font sizes) Impact: replies are readable in place; ⌘1 panel clicks visibly open previews; no other surfaces changed. Refs: task feature/agent-native-deliverables-r1 (backend: artifact backfill root fix + agent-native deliverables)
This commit is contained in:
@@ -165,29 +165,6 @@ function ProcessCollapse({ parts, idKey }: { parts: Part[]; idKey: string }) {
|
||||
)
|
||||
}
|
||||
|
||||
// 长回复折叠阈值(CF0):终态后超长正文收成摘要行,点击展开全文;live 期间全文可见。
|
||||
const LONG_REPLY_CHARS = 800
|
||||
|
||||
function LongReplyCollapse({ text, idKey }: { text: string; idKey: string }) {
|
||||
// 摘句取压缩空白后的前 100 字;字数按 Markdown 源码长度计。
|
||||
const excerpt = text.replace(/\s+/g, ' ').trim().slice(0, 100)
|
||||
return (
|
||||
<div className="process-collapse long-reply">
|
||||
<Collapsible id={`long:${idKey}`} triggerClassName="process-collapse-summary" unmountDelay={300}
|
||||
trigger={<>
|
||||
<span className="process-collapse-chev">▸</span>
|
||||
<span>📄 长回复</span>
|
||||
<span className="process-collapse-meta">{text.length} 字(按 Markdown 源码计)</span>
|
||||
{excerpt && <span className="process-collapse-excerpt">{excerpt}…</span>}
|
||||
</>}>
|
||||
<div className="body">
|
||||
<div className="part-text" dangerouslySetInnerHTML={{ __html: marked.parse(text) }} />
|
||||
</div>
|
||||
</Collapsible>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
// 已工作计时(ZCode「已工作 X 分 X 秒」摘要行;1s 步进,仅 live 期间挂载)。
|
||||
function useElapsed(startedAt: number): string {
|
||||
const [, tick] = useState(0)
|
||||
@@ -239,14 +216,13 @@ function AssistantMessage({ msg, live }: { msg: Message; live?: LiveState | null
|
||||
? (showProcess
|
||||
? <div className="part-group" key={i}><ProcessParts parts={b.parts} live={!!live} idKey={`${msg.id}:${i}`} /></div>
|
||||
: <ProcessCollapse key={i} parts={b.parts} idKey={`${msg.id}:${i}`} />)
|
||||
: (() => {
|
||||
// CF0:非 live 的超长文本部件折叠为摘要行;live 与短文本不受影响。
|
||||
if (!live && b.part.type === 'text' && (b.part.text?.length ?? 0) > LONG_REPLY_CHARS)
|
||||
return <LongReplyCollapse key={i} text={b.part.text ?? ''} idKey={`${msg.id}:${i}`} />
|
||||
return <div className="part" key={i}>
|
||||
: (
|
||||
// 最终输出契约:终轮正文是对用户的回复,一律完整可见(CF0 长回复折叠
|
||||
// 已废除——过程进折叠区,回复不再折叠);交付卡片钉在正文之后。
|
||||
<div className="part" key={i}>
|
||||
<PartView part={b.part} live={!!(live && i === lastContentIdx && b.part.type === 'text')} />
|
||||
</div>
|
||||
})())}
|
||||
))}
|
||||
{live && <LiveAgentNotes live={live} />}
|
||||
{!live && ctxObs && <ContextObsView obs={ctxObs} />}
|
||||
</div>
|
||||
|
||||
@@ -93,15 +93,17 @@ export function ArtifactsPanel() {
|
||||
: visible.length === 0
|
||||
? <div className="empty-note">没有匹配「{q}」的文件</div>
|
||||
: visible.map(a => (
|
||||
// 预览落位在右栏——弹层必须先收起,否则预览换到被盖住的右栏,
|
||||
// 用户看到的是「点了没反应」(工件面板是全屏 OverlayHost)。
|
||||
<div key={a.id} className="artifact-row" data-artifact-row={a.id}
|
||||
onClick={() => store.requestPreview(a)} title={`预览 ${a.name}(右栏,边聊边看)`}>
|
||||
onClick={() => { store.closeWorkspace(); store.requestPreview(a) }} title={`预览 ${a.name}(右栏,边聊边看)`}>
|
||||
<span className="ar-icon"><Icon name={artifactIcon(a.name, a.kind)} size={15} /></span>
|
||||
<span className="ar-main">
|
||||
<span className="name">{a.name}</span>
|
||||
<span className="meta">{a.kind} · {humanSize(a.size) || '—'} · {shortTime(a.updatedAt)}</span>
|
||||
</span>
|
||||
<span className="ar-acts">
|
||||
<button className="icon-btn" title="全屏预览" onClick={e => { e.stopPropagation(); store.requestPreview(a, 'full') }}><Icon name="eye" size={14} /></button>
|
||||
<button className="icon-btn" title="全屏预览" onClick={e => { e.stopPropagation(); store.closeWorkspace(); store.requestPreview(a, 'full') }}><Icon name="eye" size={14} /></button>
|
||||
<a className="icon-btn" title="下载" href={api.artifactDownloadUrl(a.id)} download={a.name}
|
||||
onClick={e => e.stopPropagation()}><Icon name="download" size={14} /></a>
|
||||
</span>
|
||||
|
||||
Reference in New Issue
Block a user