({
className = '',
onSendMessage
})
| 252 | } |
| 253 | |
| 254 | export const ChatInput: React.FC<ChatInputProps> = ({ |
| 255 | className = '', |
| 256 | onSendMessage |
| 257 | }) => { |
| 258 | const { t } = useTranslation('flow-chat'); |
| 259 | |
| 260 | const [inputState, dispatchInput] = useReducer(inputReducer, initialInputState); |
| 261 | const [modeState, dispatchMode] = useReducer(modeReducer, initialModeState); |
| 262 | |
| 263 | const richTextInputRef = useRef<HTMLDivElement>(null); |
| 264 | const containerRef = useRef<HTMLDivElement>(null); |
| 265 | const agentBoostRef = useRef<HTMLDivElement>(null); |
| 266 | const isImeComposingRef = useRef(false); |
| 267 | // Ref so the queuedInput sync effect can read the latest value without it being a dep |
| 268 | const inputValueRef = useRef(''); |
| 269 | const pendingLargePastesRef = useRef<PendingLargePasteMap>({}); |
| 270 | const largePasteCountersRef = useRef<Record<number, number>>({}); |
| 271 | const undoImageStackRef = useRef<string[]>([]); |
| 272 | |
| 273 | // History navigation state |
| 274 | const [historyIndex, setHistoryIndex] = useState(-1); |
| 275 | const [savedDraft, setSavedDraft] = useState(''); |
| 276 | const [inputTarget, setInputTarget] = useState<ChatInputTarget>('main'); |
| 277 | const { addMessage: addToHistory, getSessionHistory } = useInputHistoryStore(); |
| 278 | |
| 279 | const contexts = useContextStore(state => state.contexts); |
| 280 | const addContext = useContextStore(state => state.addContext); |
| 281 | const removeContext = useContextStore(state => state.removeContext); |
| 282 | const clearContexts = useContextStore(state => state.clearContexts); |
| 283 | |
| 284 | const contextsRef = useRef(contexts); |
| 285 | contextsRef.current = contexts; |
| 286 | |
| 287 | const imageContexts = useMemo( |
| 288 | () => contexts.filter((c): c is ImageContext => c.type === 'image'), |
| 289 | [contexts], |
| 290 | ); |
| 291 | const currentImageCount = imageContexts.length; |
| 292 | |
| 293 | const activeSessionState = useActiveSessionState(); |
| 294 | const activeBtwSessionTab = useAgentCanvasStore(state => selectActiveBtwSessionTab(state as any)); |
| 295 | const [flowChatState, setFlowChatState] = useState<FlowChatState>(() => FlowChatStore.getInstance().getState()); |
| 296 | const currentSessionId = activeSessionState.sessionId; |
| 297 | const currentSession = currentSessionId ? flowChatState.sessions.get(currentSessionId) : undefined; |
| 298 | const activeBtwSessionData = activeBtwSessionTab?.content.data as |
| 299 | | { childSessionId: string; parentSessionId: string; workspacePath?: string } |
| 300 | | undefined; |
| 301 | const activeBtwSessionId = activeBtwSessionData?.parentSessionId === currentSessionId |
| 302 | ? activeBtwSessionData.childSessionId |
| 303 | : undefined; |
| 304 | const effectiveTargetSessionId = |
| 305 | inputTarget === 'btw' && activeBtwSessionId ? activeBtwSessionId : currentSessionId; |
| 306 | const effectiveTargetSession = effectiveTargetSessionId |
| 307 | ? flowChatState.sessions.get(effectiveTargetSessionId) |
| 308 | : undefined; |
| 309 | const historySessionOpenTransition = useSyncExternalStore( |
| 310 | subscribeHistorySessionOpenTransition, |
| 311 | getHistorySessionOpenTransitionSnapshot, |
nothing calls this directly
no test coverage detected