feat: add Todos

This commit is contained in:
Henry Li
2026-01-22 00:26:11 +08:00
parent 085dff8d29
commit 44850d9a61
16 changed files with 232 additions and 72 deletions

View File

@@ -1,7 +1,7 @@
"use client";
import type { ChatStatus } from "ai";
import { CheckIcon, LightbulbIcon, LightbulbOffIcon } from "lucide-react";
import { CheckIcon, LightbulbIcon, ListTodoIcon } from "lucide-react";
import { useCallback, useMemo, useState, type ComponentProps } from "react";
import {
@@ -35,6 +35,7 @@ export function InputBox({
autoFocus,
status = "ready",
context,
extraHeader,
onContextChange,
onSubmit,
onStop,
@@ -43,6 +44,7 @@ export function InputBox({
assistantId?: string | null;
status?: ChatStatus;
context: Omit<AgentThreadContext, "thread_id">;
extraHeader?: React.ReactNode;
onContextChange?: (context: Omit<AgentThreadContext, "thread_id">) => void;
onSubmit?: (message: PromptInputMessage) => void;
onStop?: () => void;
@@ -72,6 +74,12 @@ export function InputBox({
thinking_enabled: !context.thinking_enabled,
});
}, [onContextChange, context]);
const handlePlanModeToggle = useCallback(() => {
onContextChange?.({
...context,
is_plan_mode: !context.is_plan_mode,
});
}, [onContextChange, context]);
const handleSubmit = useCallback(
async (message: PromptInputMessage) => {
if (status === "streaming") {
@@ -89,7 +97,6 @@ export function InputBox({
<PromptInput
className={cn(
"bg-background/85 rounded-2xl backdrop-blur-sm transition-all duration-300 ease-out *:data-[slot='input-group']:rounded-2xl",
"-translate-y-4 overflow-hidden",
className,
)}
globalDrop
@@ -97,6 +104,11 @@ export function InputBox({
onSubmit={handleSubmit}
{...props}
>
{extraHeader && (
<div className="absolute top-0 right-0 left-0 z-100">
<div className="absolute right-0 bottom-0 left-0">{extraHeader}</div>
</div>
)}
<PromptInputBody>
<PromptInputTextarea
className={cn("size-full")}
@@ -105,7 +117,7 @@ export function InputBox({
/>
</PromptInputBody>
<PromptInputFooter className="flex">
<div>
<div className="flex items-center">
<Tooltip
content={
context.thinking_enabled ? (
@@ -131,7 +143,7 @@ export function InputBox({
{context.thinking_enabled ? (
<LightbulbIcon className="text-primary size-4" />
) : (
<LightbulbOffIcon className="size-4" />
<LightbulbIcon className="size-4" />
)}
<span
className={cn(
@@ -147,6 +159,47 @@ export function InputBox({
</PromptInputButton>
)}
</Tooltip>
<Tooltip
content={
context.is_plan_mode ? (
<div className="tex-sm flex flex-col gap-1">
<div>{t.inputBox.planMode}</div>
<div className="opacity-50">
{t.inputBox.clickToDisablePlanMode}
</div>
</div>
) : (
<div className="tex-sm flex flex-col gap-1">
<div>{t.inputBox.planMode}</div>
<div className="opacity-50">
{t.inputBox.clickToEnablePlanMode}
</div>
</div>
)
}
>
{selectedModel?.supports_thinking && (
<PromptInputButton onClick={handlePlanModeToggle}>
<>
{context.is_plan_mode ? (
<ListTodoIcon className="text-primary size-4" />
) : (
<ListTodoIcon className="size-4" />
)}
<span
className={cn(
"text-xs font-normal",
context.is_plan_mode
? "text-primary"
: "text-muted-foreground",
)}
>
{t.inputBox.planMode}
</span>
</>
</PromptInputButton>
)}
</Tooltip>
</div>
<div className="flex items-center gap-2">
<ModelSelector