"use client"; import type React from "react"; import { v4 as uuidv4 } from "uuid"; import { Dispatch, SetStateAction, useEffect, useState } from "react"; import { Textarea } from "@/components/ui/textarea"; import { Loader2, Send } from "lucide-react"; import { RepositoryBranchSelectors } from "../github/repo-branch-selectors"; import { Button } from "../ui/button"; import { useStream } from "@langchain/langgraph-sdk/react"; import { useRouter } from "next/navigation"; import { useGitHubAppProvider } from "@/providers/GitHubApp"; import { GraphState } from "@open-swe/shared/open-swe/types"; import { Base64ContentBlock, HumanMessage } from "@langchain/core/messages"; import { toast } from "sonner"; import { DEFAULT_CONFIG_KEY, useConfigStore } from "@/hooks/useConfigStore"; interface TerminalInputProps { placeholder?: string; disabled?: boolean; apiUrl: string; assistantId: string; contentBlocks: Base64ContentBlock[]; setContentBlocks: Dispatch>; onPaste?: (e: React.ClipboardEvent) => void; quickActionPrompt?: string; setQuickActionPrompt?: Dispatch>; } export function TerminalInput({ placeholder = "Enter your command...", disabled = false, apiUrl, assistantId, contentBlocks, setContentBlocks, onPaste, quickActionPrompt, setQuickActionPrompt, }: TerminalInputProps) { const { push } = useRouter(); const [message, setMessage] = useState(""); const { getConfig } = useConfigStore(); const { selectedRepository } = useGitHubAppProvider(); const [loading, setLoading] = useState(false); const stream = useStream({ apiUrl, assistantId, reconnectOnMount: true, }); const handleSend = async () => { const assistantId = process.env.NEXT_PUBLIC_MANAGER_ASSISTANT_ID; if (!assistantId) { toast.error("No assistant ID found", { richColors: true, closeButton: true, }); return; } if (!selectedRepository) { toast.error("Please select a repository first", { richColors: true, closeButton: true, }); return; } setLoading(true); const trimmedMessage = message.trim(); if (trimmedMessage.length > 0 || contentBlocks.length > 0) { const newHumanMessage = new HumanMessage({ id: uuidv4(), content: [ ...(trimmedMessage.length > 0 ? [{ type: "text", text: trimmedMessage }] : []), ...contentBlocks, ], }); try { const newThreadId = uuidv4(); const run = await stream.client.runs.create(newThreadId, assistantId, { input: { messages: [newHumanMessage], targetRepository: selectedRepository, }, config: { recursion_limit: 400, configurable: { ...getConfig(DEFAULT_CONFIG_KEY), }, }, ifNotExists: "create", streamResumable: true, streamMode: ["values", "messages", "custom"], }); // set session storage so the stream can be resumed after redirect. sessionStorage.setItem(`lg:stream:${newThreadId}`, run.run_id); push(`/chat/${newThreadId}`); setMessage(""); setContentBlocks([]); } catch (e) { console.error(e); } finally { setLoading(false); } } }; const handleKeyPress = (e: React.KeyboardEvent) => { if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) { e.preventDefault(); handleSend(); } }; useEffect(() => { if (quickActionPrompt && message !== quickActionPrompt) { setMessage(quickActionPrompt); // Clear quick action prompt setQuickActionPrompt?.(""); } }, [quickActionPrompt]); return (
open-swe @ github : {/* Repository & Branch Selectors */} {/* Prompt */} $
{/* Multiline Input */}