From 707537ed527881f3837954cd9b874eadbce2a553 Mon Sep 17 00:00:00 2001 From: Ishaan Jaffer Date: Wed, 6 May 2026 15:03:38 -0700 Subject: [PATCH] feat(ui/agents): add Composer Textarea + Send at the bottom of the conversation pane. POSTs to /v2/sessions/{sid}/followup; the resulting user_message lands via the SSE stream. --- .../agents/components/three-pane/composer.tsx | 69 +++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 ui/litellm-dashboard/src/app/(dashboard)/agents/components/three-pane/composer.tsx diff --git a/ui/litellm-dashboard/src/app/(dashboard)/agents/components/three-pane/composer.tsx b/ui/litellm-dashboard/src/app/(dashboard)/agents/components/three-pane/composer.tsx new file mode 100644 index 00000000000..7fde882c75a --- /dev/null +++ b/ui/litellm-dashboard/src/app/(dashboard)/agents/components/three-pane/composer.tsx @@ -0,0 +1,69 @@ +"use client"; + +/** + * Composer — textarea + send button at the bottom of the conversation pane. + * + * On submit, POSTs to the followup endpoint and lets the SSE stream + * surface the resulting `user_message` event via the parent's event list. + */ +import { useState } from "react"; +import { Button, Input, message } from "antd"; +import { sendSessionFollowup } from "@/lib/cloud-agents-client"; + +interface ComposerProps { + sessionId: string; + accessToken: string | null; + onSent?: () => void; +} + +export default function Composer({ sessionId, accessToken, onSent }: ComposerProps) { + const [value, setValue] = useState(""); + const [sending, setSending] = useState(false); + + const handleSend = async () => { + const trimmed = value.trim(); + if (!trimmed) return; + setSending(true); + try { + await sendSessionFollowup(accessToken, sessionId, trimmed); + setValue(""); + onSent?.(); + } catch (e) { + const errMsg = e instanceof Error ? e.message : String(e); + message.error(`Send failed: ${errMsg}`); + } finally { + setSending(false); + } + }; + + return ( +
+
+ setValue(e.target.value)} + placeholder="Add a follow-up..." + disabled={sending} + data-testid="composer-input" + onPressEnter={(e) => { + if (!e.shiftKey) { + e.preventDefault(); + void handleSend(); + } + }} + /> + +
+
+ ); +}