@@ -24,6 +24,8 @@ interface MessageAreaProps {
2424 *
2525 * 布局优化:
2626 * - Header 作为 Static 的第一个子项,确保永远在历史消息顶部
27+ * - TodoPanel 独立显示在动态区域底部,不随消息滚动被冻结
28+ * - 只在有活动 TODO(pending/in_progress)时显示 TodoPanel
2729 */
2830export const MessageArea : React . FC < MessageAreaProps > = React . memo (
2931 ( { sessionState, terminalWidth, todos = [ ] , showTodoPanel = false } ) => {
@@ -47,10 +49,12 @@ export const MessageArea: React.FC<MessageAreaProps> = React.memo(
4749 } ;
4850 } , [ sessionState . messages , sessionState . isThinking ] ) ;
4951
50- // 找到最后一条用户消息的索引(用于 TodoPanel 定位)
51- const lastUserMessageIndex = useMemo ( ( ) => {
52- return sessionState . messages . findLastIndex ( ( msg ) => msg . role === 'user' ) ;
53- } , [ sessionState . messages ] ) ;
52+ // 检测是否有活动的 TODO(进行中或待处理)
53+ const hasActiveTodos = useMemo ( ( ) => {
54+ return todos . some (
55+ ( todo ) => todo . status === 'pending' || todo . status === 'in_progress'
56+ ) ;
57+ } , [ todos ] ) ;
5458
5559 // 渲染单个消息(用于 Static 和 dynamic 区域)
5660 const renderMessage = ( msg : SessionMessage , index : number , isPending = false ) => (
@@ -62,10 +66,6 @@ export const MessageArea: React.FC<MessageAreaProps> = React.memo(
6266 metadata = { msg . metadata as Record < string , unknown > }
6367 isPending = { isPending }
6468 />
65- { /* 在最后一条用户消息后显示 TodoPanel */ }
66- { index === lastUserMessageIndex && showTodoPanel && todos . length > 0 && (
67- < TodoPanel todos = { todos } visible = { true } compact = { false } />
68- ) }
6969 </ Box >
7070 ) ;
7171
@@ -82,7 +82,7 @@ export const MessageArea: React.FC<MessageAreaProps> = React.memo(
8282 } ) ;
8383
8484 return items ;
85- } , [ completedMessages , lastUserMessageIndex , showTodoPanel , todos ] ) ;
85+ } , [ completedMessages ] ) ;
8686
8787 return (
8888 < Box flexDirection = "column" flexGrow = { 1 } paddingX = { 2 } >
@@ -93,6 +93,13 @@ export const MessageArea: React.FC<MessageAreaProps> = React.memo(
9393 { /* 动态区域:只有流式传输的消息会重新渲染 */ }
9494 { streamingMessage &&
9595 renderMessage ( streamingMessage , completedMessages . length , true ) }
96+
97+ { /* TodoPanel 独立显示(仅在有活动 TODO 时) */ }
98+ { showTodoPanel && hasActiveTodos && (
99+ < Box marginTop = { 1 } >
100+ < TodoPanel todos = { todos } visible = { true } compact = { false } />
101+ </ Box >
102+ ) }
96103 </ Box >
97104 </ Box >
98105 ) ;
0 commit comments