Skip to main content
Glama
PromptsPage.tsx7.27 kB
import { Modal, Select, SelectItem, Stack, TextArea, TextInput, ToastNotification, } from "@carbon/react"; import React, { useCallback, useEffect, useState } from "react"; import { usePrompts } from "../../hooks/api/use-prompts"; import { Namespace, PromptReference } from "../../models"; import { PromptsTable } from "./PromptsTable"; import { listNamespaces } from "../../hooks/api/use-namespaces"; export const PromptsPage: React.FC = () => { const [fetchedData, setFetchedData] = useState<PromptReference[]>([]); const [isLoading, setIsLoading] = useState(true); const [isAddModalOpen, setIsAddModalOpen] = useState(false); const [errorMessage, setErrorMessage] = useState<string | null>(null); const { listPrompts, addPrompt, removePrompt } = usePrompts(); const updatePrompts = useCallback(async () => { return listPrompts().then((result) => { if (result.status !== 200 || !Array.isArray(result.data.data)) { setErrorMessage("Failed to fetch prompts. Please try again later."); setFetchedData([]); } else { setFetchedData(result.data.data); } setIsLoading(false); }); }, [listPrompts]); useEffect(() => { updatePrompts(); }, [updatePrompts]); useEffect(() => { if (errorMessage) { const timer = setTimeout(() => { setErrorMessage(null); }, 10_000); return () => { clearTimeout(timer); }; } }, [errorMessage]); if (isLoading) return <div>Loading...</div>; const handleAddPrompt = async (newPrompt: PromptReference) => { try { await addPrompt(newPrompt); setIsAddModalOpen(false); setErrorMessage(null); await updatePrompts(); } catch (error) { console.error("Error adding prompt:", error); setIsAddModalOpen(false); setErrorMessage("Error adding prompt: The prompt name must be unique"); } }; const handleDeletePrompt = async (promptName?: string) => { try { await removePrompt({ prompt: promptName }); await updatePrompts(); } catch (error) { console.error("Error deleting prompt:", error); setErrorMessage(`Failed to delete prompt: ${promptName}`); } }; return ( <div> {errorMessage && ( <ToastNotification kind="error" title="Error" subtitle={errorMessage} onCloseButtonClick={() => setErrorMessage(null)} timeout={10000} style={{ float: "right" }} /> )} <h1 className="title">Prompts</h1> <p className="description"> Prompts are reusable templates that can leverage multiple tools and provide example interactions for LLMs. Each prompt contains messages, arguments, and optional tool references. </p> <div id="page-content"> {fetchedData && ( <PromptsTable fetchedData={fetchedData} onDelete={handleDeletePrompt} onAdd={() => setIsAddModalOpen(true)} /> )} {isAddModalOpen && ( <AddPromptModal onRequestClose={() => setIsAddModalOpen(false)} onSubmit={handleAddPrompt} /> )} </div> </div> ); }; interface AddPromptModalProps { onRequestClose: () => void; onSubmit: (newPrompt: PromptReference) => void; } const AddPromptModal: React.FC<AddPromptModalProps> = ({ onRequestClose, onSubmit, }) => { const [promptName, setPromptName] = useState(""); const [description, setDescription] = useState(""); const [messagesJson, setMessagesJson] = useState(""); const [argumentsJson, setArgumentsJson] = useState(""); const [toolReferences, setToolReferences] = useState(""); const [fetchedNamespaceData, setFetchedNamespaceData] = useState<Namespace[]>([]); const [selectedNamespace, setSelectedNamespace] = useState(''); useEffect(() => { listNamespaces().then((result) => { setFetchedNamespaceData(result.data.data as Namespace[]); }); }, [listNamespaces]); const handleSelectionChange = (event) => { setSelectedNamespace(event.target.value); }; const handleSubmit = () => { try { const messages = messagesJson ? JSON.parse(messagesJson) : []; const args = argumentsJson ? JSON.parse(argumentsJson) : []; const toolRefs = toolReferences ? toolReferences.split(',').map(t => t.trim()) : []; onSubmit({ name: promptName, description, messages, arguments: args, toolReferences: toolRefs, namespace: selectedNamespace, }); } catch (error) { console.error("Invalid JSON in prompt data:", error); } }; return ( <Modal open={true} modalHeading="Add a Prompt" primaryButtonText="Add" secondaryButtonText="Cancel" onRequestClose={onRequestClose} onRequestSubmit={handleSubmit} > <Stack gap={5}> <TextInput id="prompt-name" labelText="Prompt Name" placeholder="e.g. code-reviewer" value={promptName} onChange={(e) => setPromptName(e.target.value)} /> <TextInput id="prompt-description" labelText="Description" placeholder="e.g. A prompt for reviewing code" value={description} onChange={(e) => setDescription(e.target.value)} /> <TextArea id="messages-json" labelText="Messages (JSON)" placeholder='Examples: Text: {"role": "user", "content": {"type": "text", "text": "Review {{code}}"}} Image: {"role": "user", "content": {"type": "image", "data": "base64...", "mimeType": "image/png"}} Audio: {"role": "user", "content": {"type": "audio", "data": "base64...", "mimeType": "audio/wav"}} Resource: {"role": "user", "content": {"type": "resource", "resource": {"location": "file:///path", "description": "File content", "mimeType": "text/plain"}}}' rows={6} value={messagesJson} onChange={(e) => setMessagesJson(e.target.value)} /> <TextArea id="arguments-json" labelText="Arguments (JSON, optional)" placeholder='e.g. [{"name": "code", "description": "The code to review", "required": true}]' rows={3} value={argumentsJson} onChange={(e) => setArgumentsJson(e.target.value)} /> <TextInput id="tool-references" labelText="Tool References (comma-separated, optional)" placeholder="e.g. code-analyzer, linter" value={toolReferences} onChange={(e) => setToolReferences(e.target.value)} /> <Select id="namespace" labelText="Select a Namespace" helperText="Choose a Namespace from the list" value={selectedNamespace} onChange={handleSelectionChange} > <SelectItem text="Choose an option" value="" /> {fetchedNamespaceData.map((namespace) => ( <SelectItem key={namespace.id} id={namespace.id} text={namespace.path || "default"} value={namespace.id} /> ))} </Select> </Stack> </Modal> ); };

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/wanaku-ai/wanaku'

If you have feedback or need assistance with the MCP directory API, please join our Discord server