mirror of
https://github.com/rowboatlabs/rowboat.git
synced 2026-04-29 02:24:02 +02:00
remove unused token estimation logic
add full-screen chat functionality
This commit is contained in:
parent
a5cb47c885
commit
e44664cb17
2 changed files with 48 additions and 51 deletions
|
|
@ -80,11 +80,6 @@ type ConversationItem = ChatMessage | ToolCall | ReasoningBlock;
|
|||
|
||||
type ToolState = 'input-streaming' | 'input-available' | 'output-available' | 'output-error';
|
||||
|
||||
const estimateTokens = (text: string) => {
|
||||
if (!text) return 0
|
||||
return Math.ceil(text.trim().length / 4)
|
||||
}
|
||||
|
||||
const isChatMessage = (item: ConversationItem): item is ChatMessage => 'role' in item
|
||||
const isToolCall = (item: ConversationItem): item is ToolCall => 'name' in item
|
||||
const isReasoningBlock = (item: ConversationItem): item is ReasoningBlock =>
|
||||
|
|
@ -274,7 +269,7 @@ function ChatInputInner({
|
|||
placeholder="Type your message..."
|
||||
disabled={isProcessing}
|
||||
onKeyDown={handleKeyDown}
|
||||
className="min-h-[1.5rem] py-0 border-0 shadow-none focus-visible:ring-0 rounded-none"
|
||||
className="min-h-6 py-0 border-0 shadow-none focus-visible:ring-0 rounded-none"
|
||||
/>
|
||||
<Button
|
||||
size="icon"
|
||||
|
|
@ -348,7 +343,7 @@ function App() {
|
|||
const [conversation, setConversation] = useState<ConversationItem[]>([])
|
||||
const [currentAssistantMessage, setCurrentAssistantMessage] = useState<string>('')
|
||||
const [currentReasoning, setCurrentReasoning] = useState<string>('')
|
||||
const [modelUsage, setModelUsage] = useState<LanguageModelUsage | null>(null)
|
||||
const [, setModelUsage] = useState<LanguageModelUsage | null>(null)
|
||||
const [runId, setRunId] = useState<string | null>(null)
|
||||
const [isProcessing, setIsProcessing] = useState(false)
|
||||
const [agentId] = useState<string>('copilot')
|
||||
|
|
@ -718,6 +713,11 @@ function App() {
|
|||
handlePromptSubmit({ text, files: [] })
|
||||
}
|
||||
|
||||
const handleOpenFullScreenChat = useCallback(() => {
|
||||
setSelectedPath(null)
|
||||
setIsGraphOpen(false)
|
||||
}, [])
|
||||
|
||||
const toggleExpand = (path: string, kind: 'file' | 'dir') => {
|
||||
if (kind === 'file') {
|
||||
setSelectedPath(path)
|
||||
|
|
@ -1057,38 +1057,6 @@ function App() {
|
|||
return null
|
||||
}
|
||||
|
||||
const chatMessages = conversation.filter(isChatMessage)
|
||||
const reasoningBlocks = conversation.filter(isReasoningBlock)
|
||||
const estimatedInputTokens = chatMessages
|
||||
.filter((item) => item.role === 'user')
|
||||
.reduce((total, item) => total + estimateTokens(item.content), 0)
|
||||
const estimatedOutputTokens = chatMessages
|
||||
.filter((item) => item.role === 'assistant')
|
||||
.reduce((total, item) => total + estimateTokens(item.content), 0)
|
||||
+ estimateTokens(currentAssistantMessage)
|
||||
const estimatedReasoningTokens = reasoningBlocks
|
||||
.reduce((total, item) => total + estimateTokens(item.content), 0)
|
||||
+ estimateTokens(currentReasoning)
|
||||
const estimatedTotalTokens = estimatedInputTokens + estimatedOutputTokens + estimatedReasoningTokens
|
||||
const maxTokens = 128_000
|
||||
const estimatedUsage = {
|
||||
inputTokens: estimatedInputTokens,
|
||||
outputTokens: estimatedOutputTokens,
|
||||
totalTokens: estimatedTotalTokens,
|
||||
cachedInputTokens: 0,
|
||||
reasoningTokens: estimatedReasoningTokens,
|
||||
} as LanguageModelUsage
|
||||
const effectiveUsage = modelUsage ?? estimatedUsage
|
||||
const effectiveTotalTokens = effectiveUsage.totalTokens
|
||||
?? (effectiveUsage.inputTokens ?? 0)
|
||||
+ (effectiveUsage.outputTokens ?? 0)
|
||||
+ (effectiveUsage.reasoningTokens ?? 0)
|
||||
const usedTokens = Math.min(effectiveTotalTokens, maxTokens)
|
||||
const contextUsage = {
|
||||
...effectiveUsage,
|
||||
totalTokens: effectiveTotalTokens,
|
||||
} as LanguageModelUsage
|
||||
|
||||
const hasConversation = conversation.length > 0 || currentAssistantMessage || currentReasoning
|
||||
const conversationContentClassName = hasConversation
|
||||
? "mx-auto w-full max-w-4xl pb-28"
|
||||
|
|
@ -1262,6 +1230,7 @@ function App() {
|
|||
defaultWidth={400}
|
||||
isOpen={isChatSidebarOpen}
|
||||
onNewChat={handleNewChat}
|
||||
onOpenFullScreen={handleOpenFullScreenChat}
|
||||
conversation={conversation}
|
||||
currentAssistantMessage={currentAssistantMessage}
|
||||
currentReasoning={currentReasoning}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
||||
import { ArrowUp, Plus } from 'lucide-react'
|
||||
import { ArrowUp, Expand, Plus } from 'lucide-react'
|
||||
import type { ToolUIPart } from 'ai'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
|
@ -105,6 +105,7 @@ interface ChatSidebarProps {
|
|||
defaultWidth?: number
|
||||
isOpen?: boolean
|
||||
onNewChat: () => void
|
||||
onOpenFullScreen?: () => void
|
||||
conversation: ConversationItem[]
|
||||
currentAssistantMessage: string
|
||||
currentReasoning: string
|
||||
|
|
@ -122,6 +123,7 @@ export function ChatSidebar({
|
|||
defaultWidth = DEFAULT_WIDTH,
|
||||
isOpen = true,
|
||||
onNewChat,
|
||||
onOpenFullScreen,
|
||||
conversation,
|
||||
currentAssistantMessage,
|
||||
currentReasoning,
|
||||
|
|
@ -136,6 +138,17 @@ export function ChatSidebar({
|
|||
}: ChatSidebarProps) {
|
||||
const [width, setWidth] = useState(defaultWidth)
|
||||
const [isResizing, setIsResizing] = useState(false)
|
||||
const [showContent, setShowContent] = useState(isOpen)
|
||||
|
||||
// Delay showing content when opening, hide immediately when closing
|
||||
useEffect(() => {
|
||||
if (isOpen) {
|
||||
const timer = setTimeout(() => setShowContent(true), 150)
|
||||
return () => clearTimeout(timer)
|
||||
} else {
|
||||
setShowContent(false)
|
||||
}
|
||||
}, [isOpen])
|
||||
const startXRef = useRef(0)
|
||||
const startWidthRef = useRef(0)
|
||||
const textareaRef = useRef<HTMLTextAreaElement>(null)
|
||||
|
|
@ -414,17 +427,30 @@ export function ChatSidebar({
|
|||
)}
|
||||
/>
|
||||
|
||||
{/* Header - minimal, just new chat button */}
|
||||
<header className="flex h-12 shrink-0 items-center justify-end px-2">
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button variant="ghost" size="icon" onClick={onNewChat} className="h-8 w-8 text-muted-foreground hover:text-foreground">
|
||||
<Plus className="h-4 w-4" />
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="bottom">New chat</TooltipContent>
|
||||
</Tooltip>
|
||||
</header>
|
||||
{/* Content - delayed on open, hidden immediately on close to avoid layout issues during animation */}
|
||||
{showContent && (
|
||||
<>
|
||||
{/* Header - minimal, expand and new chat buttons */}
|
||||
<header className="flex h-12 shrink-0 items-center justify-end gap-1 px-2">
|
||||
{onOpenFullScreen && (
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button variant="ghost" size="icon" onClick={onOpenFullScreen} className="h-8 w-8 text-muted-foreground hover:text-foreground">
|
||||
<Expand className="h-4 w-4" />
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="bottom">Full screen chat</TooltipContent>
|
||||
</Tooltip>
|
||||
)}
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button variant="ghost" size="icon" onClick={onNewChat} className="h-8 w-8 text-muted-foreground hover:text-foreground">
|
||||
<Plus className="h-4 w-4" />
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="bottom">New chat</TooltipContent>
|
||||
</Tooltip>
|
||||
</header>
|
||||
|
||||
{/* Conversation area */}
|
||||
<div className="flex min-h-0 flex-1 flex-col relative">
|
||||
|
|
@ -536,6 +562,8 @@ export function ChatSidebar({
|
|||
)}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue