mirror of
https://github.com/lobehub/lobe-chat.git
synced 2026-06-18 05:18:31 +00:00
✨ feat: gtd create plan support streaming render (#11034)
feat: add the gtd stream render
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
'use client';
|
||||
|
||||
import { Block, Flexbox, Icon, Text } from '@lobehub/ui';
|
||||
import { Block, Flexbox, Icon, Markdown, Text } from '@lobehub/ui';
|
||||
import { createStyles } from 'antd-style';
|
||||
import { ListChecksIcon } from 'lucide-react';
|
||||
import { memo } from 'react';
|
||||
|
||||
@@ -8,37 +9,76 @@ import { useChatStore } from '@/store/chat';
|
||||
|
||||
import type { Plan } from '../../types';
|
||||
|
||||
const MAX_CONTENT_HEIGHT = 100;
|
||||
|
||||
const useStyles = createStyles(({ css, token }) => ({
|
||||
content: css`
|
||||
overflow: hidden auto;
|
||||
|
||||
max-height: ${MAX_CONTENT_HEIGHT}px;
|
||||
padding: 12px;
|
||||
border-radius: ${token.borderRadius}px;
|
||||
|
||||
background: ${token.colorFillQuaternary};
|
||||
`,
|
||||
header: css`
|
||||
cursor: pointer;
|
||||
padding-block: 4px;
|
||||
padding-inline: 0;
|
||||
transition: opacity 0.2s;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
`,
|
||||
}));
|
||||
|
||||
interface PlanCardProps {
|
||||
plan: Plan;
|
||||
}
|
||||
|
||||
const PlanCard = memo<PlanCardProps>(({ plan }) => {
|
||||
const { styles } = useStyles();
|
||||
const openDocument = useChatStore((s) => s.openDocument);
|
||||
|
||||
const handleClick = () => {
|
||||
const handleHeaderClick = () => {
|
||||
openDocument(plan.id);
|
||||
};
|
||||
|
||||
const hasContext = !!plan.context;
|
||||
|
||||
return (
|
||||
<Block
|
||||
clickable
|
||||
gap={8}
|
||||
onClick={handleClick}
|
||||
padding={12}
|
||||
style={{ overflow: 'hidden' }}
|
||||
variant={'outlined'}
|
||||
>
|
||||
<Flexbox align={'center'} gap={8} horizontal style={{ overflow: 'hidden' }}>
|
||||
<Block gap={8} padding={12} style={{ overflow: 'hidden' }} variant={'outlined'}>
|
||||
{/* Header - clickable to open document */}
|
||||
<Flexbox
|
||||
align={'center'}
|
||||
className={styles.header}
|
||||
gap={8}
|
||||
horizontal
|
||||
onClick={handleHeaderClick}
|
||||
style={{ overflow: 'hidden' }}
|
||||
>
|
||||
<Icon icon={ListChecksIcon} size={18} />
|
||||
<Text ellipsis fontSize={16} weight={500}>
|
||||
{plan.goal}
|
||||
</Text>
|
||||
</Flexbox>
|
||||
|
||||
{/* Description */}
|
||||
{plan.description && (
|
||||
<Text ellipsis={{ rows: 2 }} fontSize={14} type={'secondary'}>
|
||||
{plan.description}
|
||||
</Text>
|
||||
)}
|
||||
|
||||
{/* Context content */}
|
||||
{hasContext && (
|
||||
<div className={styles.content}>
|
||||
<Markdown fontSize={13} variant={'chat'}>
|
||||
{plan.context!}
|
||||
</Markdown>
|
||||
</div>
|
||||
)}
|
||||
</Block>
|
||||
);
|
||||
});
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
'use client';
|
||||
|
||||
import type { BuiltinStreamingProps } from '@lobechat/types';
|
||||
import { Flexbox, Icon, Markdown, Text } from '@lobehub/ui';
|
||||
import { createStaticStyles } from 'antd-style';
|
||||
import { ListChecksIcon } from 'lucide-react';
|
||||
import { memo } from 'react';
|
||||
|
||||
import type { CreatePlanParams } from '../../../types';
|
||||
|
||||
const MAX_CONTENT_HEIGHT = 100;
|
||||
|
||||
const styles = createStaticStyles(({ css, cssVar }) => ({
|
||||
container: css`
|
||||
overflow: hidden;
|
||||
padding: 12px;
|
||||
border: 1px solid ${cssVar.colorBorder};
|
||||
border-radius: 8px;
|
||||
`,
|
||||
content: css`
|
||||
overflow: hidden auto;
|
||||
|
||||
max-height: ${MAX_CONTENT_HEIGHT}px;
|
||||
padding: 12px;
|
||||
border-radius: 8px;
|
||||
|
||||
background: ${cssVar.colorFillQuaternary};
|
||||
`,
|
||||
description: css`
|
||||
font-size: 14px;
|
||||
color: ${cssVar.colorTextSecondary};
|
||||
`,
|
||||
header: css`
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
padding-block: 4px;
|
||||
`,
|
||||
title: css`
|
||||
overflow: hidden;
|
||||
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
color: ${cssVar.colorText};
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
`,
|
||||
}));
|
||||
|
||||
export const CreatePlanStreaming = memo<BuiltinStreamingProps<CreatePlanParams>>(({ args }) => {
|
||||
const { goal, description, context } = args || {};
|
||||
|
||||
if (!goal) return null;
|
||||
|
||||
return (
|
||||
<Flexbox className={styles.container} gap={8}>
|
||||
{/* Header */}
|
||||
<div className={styles.header}>
|
||||
<Icon icon={ListChecksIcon} size={18} />
|
||||
<Text className={styles.title} ellipsis>
|
||||
{goal}
|
||||
</Text>
|
||||
</div>
|
||||
|
||||
{/* Description */}
|
||||
{description && (
|
||||
<Text className={styles.description} ellipsis={{ rows: 2 }}>
|
||||
{description}
|
||||
</Text>
|
||||
)}
|
||||
|
||||
{/* Context content - streaming with animation */}
|
||||
{context && (
|
||||
<div className={styles.content}>
|
||||
<Markdown animated fontSize={13} variant={'chat'}>
|
||||
{context}
|
||||
</Markdown>
|
||||
</div>
|
||||
)}
|
||||
</Flexbox>
|
||||
);
|
||||
});
|
||||
|
||||
CreatePlanStreaming.displayName = 'CreatePlanStreaming';
|
||||
|
||||
export default CreatePlanStreaming;
|
||||
@@ -14,7 +14,7 @@ const styles = createStaticStyles(({ css, cssVar }) => ({
|
||||
background: ${cssVar.colorFillQuaternary};
|
||||
`,
|
||||
description: css`
|
||||
margin-bottom: 8px;
|
||||
margin-block-end: 8px;
|
||||
font-weight: 500;
|
||||
color: ${cssVar.colorText};
|
||||
`,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import type { BuiltinStreaming } from '@lobechat/types';
|
||||
|
||||
import { GTDApiName } from '../../types';
|
||||
import { CreatePlanStreaming } from './CreatePlan';
|
||||
import { ExecTaskStreaming } from './ExecTask';
|
||||
import { ExecTasksStreaming } from './ExecTasks';
|
||||
|
||||
@@ -11,8 +12,13 @@ import { ExecTasksStreaming } from './ExecTasks';
|
||||
* still executing, allowing real-time feedback to users.
|
||||
*/
|
||||
export const GTDStreamings: Record<string, BuiltinStreaming> = {
|
||||
[GTDApiName.createPlan]: CreatePlanStreaming as BuiltinStreaming,
|
||||
[GTDApiName.execTask]: ExecTaskStreaming as BuiltinStreaming,
|
||||
[GTDApiName.execTasks]: ExecTasksStreaming as BuiltinStreaming,
|
||||
};
|
||||
|
||||
export { ExecTaskStreaming, ExecTasksStreaming };
|
||||
|
||||
|
||||
export {CreatePlanStreaming} from './CreatePlan';
|
||||
export {ExecTaskStreaming} from './ExecTask';
|
||||
export {ExecTasksStreaming} from './ExecTasks';
|
||||
@@ -6,7 +6,12 @@ export type { TodoListRenderState } from './Render';
|
||||
export { GTDRenders, TodoListRender, TodoListUI } from './Render';
|
||||
|
||||
// Streaming components (real-time tool execution feedback)
|
||||
export { ExecTaskStreaming, ExecTasksStreaming, GTDStreamings } from './Streaming';
|
||||
export {
|
||||
CreatePlanStreaming,
|
||||
ExecTasksStreaming,
|
||||
ExecTaskStreaming,
|
||||
GTDStreamings,
|
||||
} from './Streaming';
|
||||
|
||||
// Intervention components (interactive editing)
|
||||
export { AddTodoIntervention, ClearTodosIntervention, GTDInterventions } from './Intervention';
|
||||
|
||||
Reference in New Issue
Block a user