接入项目聊天 Markdown 渲染
统一三个项目聊天视图的 assistant 消息展示 让 Direct Codex 流式回复复用 Markdown 组件 移除纯聊天视图的无条件滚动到底部行为
This commit is contained in:
+26
-10
@@ -16,6 +16,7 @@ import type {
|
||||
PlanGddDecisionAction,
|
||||
PlanGddStateViewV1,
|
||||
} from '../../app/types';
|
||||
import { ChatMarkdownMessage } from '../../components/ChatMarkdownMessage';
|
||||
import {
|
||||
projectProfessionalAgentLabel,
|
||||
projectRuntimeVisibleError,
|
||||
@@ -142,15 +143,22 @@ export function ProjectSupervisorView({
|
||||
</button>
|
||||
) : null}
|
||||
{visibleMessages.map((message, index) => (
|
||||
<p
|
||||
<div
|
||||
key={message.messageId ?? `${message.role}-${index}`}
|
||||
className={`message message--${message.role}`}
|
||||
>
|
||||
{projectSupervisorVisibleConversationText(
|
||||
message.text,
|
||||
message.role,
|
||||
)}
|
||||
</p>
|
||||
<ChatMarkdownMessage
|
||||
role={message.role}
|
||||
text={
|
||||
message.role === 'assistant'
|
||||
? projectSupervisorVisibleConversationText(
|
||||
message.text,
|
||||
message.role,
|
||||
)
|
||||
: message.text
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
{directCodex &&
|
||||
(runtimePanelProps.controlBusy || Boolean(transientReply)) ? (
|
||||
@@ -167,18 +175,26 @@ export function ProjectSupervisorView({
|
||||
<strong>{directActivity || '陶泥儿正在处理'}</strong>
|
||||
</header>
|
||||
{transientReply ? (
|
||||
<p aria-label="陶泥儿实时回复">{transientReply}</p>
|
||||
<ChatMarkdownMessage
|
||||
role="assistant"
|
||||
text={transientReply}
|
||||
streaming
|
||||
/>
|
||||
) : null}
|
||||
</section>
|
||||
) : transientReply ? (
|
||||
<p
|
||||
<div
|
||||
className="message message--assistant"
|
||||
aria-label="项目总控 Agent 实时回复"
|
||||
aria-live="polite"
|
||||
data-runtime-owned="true"
|
||||
>
|
||||
{transientReply}
|
||||
</p>
|
||||
<ChatMarkdownMessage
|
||||
role="assistant"
|
||||
text={transientReply}
|
||||
streaming
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
{directCodex ? null : isPlanningLaneRuntime(
|
||||
|
||||
+21
-9
@@ -26,6 +26,7 @@ import type {
|
||||
PendingCommand,
|
||||
PendingUiConfirmation,
|
||||
} from '../../app/types';
|
||||
import { ChatMarkdownMessage } from '../../components/ChatMarkdownMessage';
|
||||
import type { ProjectAgentResultSummary } from '../../view/project-development';
|
||||
import {
|
||||
formatAgentRecentRuntimeTask,
|
||||
@@ -804,12 +805,19 @@ export function ProjectWorkspaceChatPane({
|
||||
) : null}
|
||||
{visibleMessages.map((message, index) => (
|
||||
<Fragment key={index}>
|
||||
<p className={`message message--${message.role}`}>
|
||||
{projectSupervisorVisibleConversationText(
|
||||
message.text,
|
||||
message.role,
|
||||
)}
|
||||
</p>
|
||||
<div className={`message message--${message.role}`}>
|
||||
<ChatMarkdownMessage
|
||||
role={message.role}
|
||||
text={
|
||||
message.role === 'assistant'
|
||||
? projectSupervisorVisibleConversationText(
|
||||
message.text,
|
||||
message.role,
|
||||
)
|
||||
: message.text
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
{message.draftCommand ? (
|
||||
<button
|
||||
type="button"
|
||||
@@ -822,14 +830,18 @@ export function ProjectWorkspaceChatPane({
|
||||
</Fragment>
|
||||
))}
|
||||
{projectSupervisorTransientReply ? (
|
||||
<p
|
||||
<div
|
||||
className="message message--assistant"
|
||||
aria-label="项目总控 Agent 实时回复"
|
||||
aria-live="polite"
|
||||
data-runtime-owned="true"
|
||||
>
|
||||
{projectSupervisorTransientReply}
|
||||
</p>
|
||||
<ChatMarkdownMessage
|
||||
role="assistant"
|
||||
text={projectSupervisorTransientReply}
|
||||
streaming
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
<ProjectSupervisorRuntimePanel
|
||||
|
||||
+21
-14
@@ -7,7 +7,6 @@ import type {
|
||||
SetStateAction,
|
||||
UIEventHandler,
|
||||
} from 'react';
|
||||
import { useLayoutEffect } from 'react';
|
||||
|
||||
import type {
|
||||
AgentRuntimeState,
|
||||
@@ -15,6 +14,7 @@ import type {
|
||||
PendingCommand,
|
||||
PendingUiConfirmation,
|
||||
} from '../../app/types';
|
||||
import { ChatMarkdownMessage } from '../../components/ChatMarkdownMessage';
|
||||
import {
|
||||
isAgentRuntimeTerminalState,
|
||||
projectRuntimeVisibleError,
|
||||
@@ -107,10 +107,6 @@ export function SupervisorChatOnlyView({
|
||||
: runtime
|
||||
? projectSupervisorChatRuntimeStatus(runtime)
|
||||
: projectWorkspaceStatusForDisplay(workspaceStatus);
|
||||
useLayoutEffect(() => {
|
||||
if (running && messagesRef.current)
|
||||
messagesRef.current.scrollTop = messagesRef.current.scrollHeight;
|
||||
}, [messagesRef, running, transientReply, runtime?.updatedAt]);
|
||||
const conversationLabel = directCodex
|
||||
? '陶泥儿项目对话'
|
||||
: '项目总控 Agent 纯聊天';
|
||||
@@ -153,18 +149,25 @@ export function SupervisorChatOnlyView({
|
||||
>{`显示更早 · 还有 ${hiddenConversationCount} 条对话`}</button>
|
||||
) : null}
|
||||
{visibleMessages.map((message, index) => (
|
||||
<p
|
||||
<div
|
||||
key={message.messageId ?? `${message.role}-${index}`}
|
||||
className={`message message--${message.role}`}
|
||||
>
|
||||
{projectSupervisorVisibleConversationText(
|
||||
message.text,
|
||||
message.role,
|
||||
)}
|
||||
</p>
|
||||
<ChatMarkdownMessage
|
||||
role={message.role}
|
||||
text={
|
||||
message.role === 'assistant'
|
||||
? projectSupervisorVisibleConversationText(
|
||||
message.text,
|
||||
message.role,
|
||||
)
|
||||
: message.text
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
{transientReply ? (
|
||||
<p
|
||||
<div
|
||||
className="message message--assistant supervisor-chat-only-stream"
|
||||
aria-label={
|
||||
directCodex ? '陶泥儿实时回复' : '项目总控 Agent 实时回复'
|
||||
@@ -172,8 +175,12 @@ export function SupervisorChatOnlyView({
|
||||
aria-live="polite"
|
||||
data-runtime-owned="true"
|
||||
>
|
||||
{transientReply}
|
||||
</p>
|
||||
<ChatMarkdownMessage
|
||||
role="assistant"
|
||||
text={transientReply}
|
||||
streaming
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
{running && !transientReply ? (
|
||||
<div
|
||||
|
||||
Reference in New Issue
Block a user