// frontend/src/shell/SteerInput.tsx import { useEffect, useRef, useState } from "react"; import { CornerDownLeft } from "lucide-react"; import { useQuery, useQueryClient } from "@tanstack/react-query"; import { postSteer, createSession } from "../api/sessions"; import { getSettings, putSettings, type Settings } from "../api/settings"; import { listWorkspaces } from "../api/workspaces"; import { listModels } from "../api/models"; import { useSessionStore } from "../store/sessionStore"; const THINKING_LEVELS = ["low", "medium", "high"] as const; interface Props { /** Active session, or null when no session has been started yet. */ sessionId: string | null; /** Called with the new session id when the box starts a fresh session. */ onSessionCreated?: (id: string) => void; /** Interrupt the running session, persisting its state. */ onStop?: () => void; /** Lets the parent focus the composer (e.g. on "New session"). */ inputRef?: React.Ref; } export function SteerInput({ sessionId, onSessionCreated, onStop, inputRef }: Props) { const [text, setText] = useState(""); const [busy, setBusy] = useState(false); const setLastUserEntry = useSessionStore((s) => s.setLastUserEntry); const setPhase = useSessionStore((s) => s.setPhase); const taRef = useRef(null); // Merge our own ref (for autosizing) with the forwarded one (parent focus). function attachRef(el: HTMLTextAreaElement | null) { taRef.current = el; if (typeof inputRef === "function") inputRef(el); else if (inputRef) (inputRef as React.MutableRefObject).current = el; } // Grow the textarea to fit its content (up to a cap, then it scrolls), and shrink // back when the text is cleared. Runs after every value change so height tracks text. useEffect(() => { const el = taRef.current; if (!el) return; el.style.height = "auto"; el.style.height = `${Math.min(el.scrollHeight, 160)}px`; }, [text]); async function submit() { const trimmed = text.trim(); if (!trimmed || busy) return; setBusy(true); try { if (sessionId) { await postSteer(sessionId, trimmed); } else { const { id } = await createSession({ question: trimmed }); setPhase("F1"); // optimistic: paint F1 yellow during the cold start, before the first gate onSessionCreated?.(id); } setLastUserEntry({ kind: "input", text: trimmed }); setText(""); } finally { setBusy(false); } } function handleKeyDown(e: React.KeyboardEvent) { // Enter sends; Shift+Enter inserts a newline (the textarea grows to fit it). if (e.key === "Enter" && !e.shiftKey) { e.preventDefault(); submit(); } } return (
{sessionId && ( )}