glove-react
v2.2.6
Published
React bindings for Glove agent framework
Readme
glove-react
React bindings for the Glove agent framework — hooks, components, and tools with colocated renderers.
Install
npm install glove-react glove-nextRequires react >= 18.0.0 as a peer dependency.
Quick start
1. Server route (Next.js)
// app/api/chat/route.ts
import { createChatHandler } from "glove-next";
export const POST = createChatHandler({
provider: "anthropic",
model: "claude-sonnet-4-20250514",
});2. Define tools
// lib/glove.tsx
import { GloveClient, defineTool } from "glove-react";
import type { ToolConfig } from "glove-react";
import { z } from "zod";
const inputSchema = z.object({
question: z.string().describe("The question to display"),
options: z.array(z.object({
label: z.string().describe("Display text"),
value: z.string().describe("Value returned when selected"),
})),
});
const askPreferenceTool = defineTool({
name: "ask_preference",
description: "Present options for the user to choose from.",
inputSchema,
displayPropsSchema: inputSchema, // optional, recommended for tools with UI
resolveSchema: z.string(),
displayStrategy: "hide-on-complete",
async do(input, display) {
const selected = await display.pushAndWait(input);
return {
status: "success" as const,
data: `User selected: ${selected}`,
renderData: { question: input.question, selected }, // client-only, not sent to AI
};
},
render({ props, resolve }) {
return (
<div>
<p>{props.question}</p>
{props.options.map(opt => (
<button key={opt.value} onClick={() => resolve(opt.value)}>
{opt.label}
</button>
))}
</div>
);
},
renderResult({ data }) {
const { question, selected } = data as { question: string; selected: string };
return <div><p>{question}</p><span>Selected: {selected}</span></div>;
},
});
// Tools without display stay as raw ToolConfig
const getDateTool: ToolConfig = {
name: "get_date",
description: "Get today's date",
inputSchema: z.object({}),
async do() { return { status: "success", data: new Date().toLocaleDateString() }; },
};
export const gloveClient = new GloveClient({
endpoint: "/api/chat",
systemPrompt: "You are a helpful assistant.",
tools: [askPreferenceTool, getDateTool],
// Optional: resolve session ID asynchronously (e.g. from your backend)
// getSessionId: () => fetch("/api/session").then(r => r.json()).then(d => d.sessionId),
});3. Provider + UI
// app/providers.tsx
"use client";
import { GloveProvider } from "glove-react";
import { gloveClient } from "@/lib/glove";
export function Providers({ children }: { children: React.ReactNode }) {
return <GloveProvider client={gloveClient}>{children}</GloveProvider>;
}// app/page.tsx
"use client";
import { useGlove, Render } from "glove-react";
export default function Chat() {
const glove = useGlove();
return (
<Render
glove={glove}
strategy="interleaved"
renderMessage={({ entry }) => (
<div><strong>{entry.kind === "user" ? "You" : "AI"}:</strong> {entry.text}</div>
)}
renderStreaming={({ text }) => <div style={{ opacity: 0.7 }}>{text}</div>}
/>
);
}Key exports
Components & hooks
GloveProvider— Context provider wrapping your appuseGlove(config?)— Main hook returningtimeline,streamingText,busy,slots,tasks,stats,sessionReady,sessionId,sendMessage,abort,renderSlot,renderToolResult,resolveSlot,rejectSlot. Accepts an optionalgetSessionIdasync function to resolve the session ID at runtime (overrides the client-level one if set).Render— Headless render component with automatic slot visibility, interleaving, andrenderResultrendering
Tool helpers
defineTool(config)— Type-safe tool builder with colocatedrenderandrenderResult. Provides typed display props and resolve values.ToolConfig— Raw tool interface for tools without display UI
Client
GloveClient— Configuration container. Passendpoint(for server-side models viaglove-next) orcreateModel(for client-side models). Optionally passgetSessionIdto resolve the session ID asynchronously instead of providing one directly.
Adapters
MemoryStore— In-memory store for prototypingcreateRemoteStore— Delegates store operations to your API endpointscreateRemoteModel— Custom model adapter withpromptand optionalpromptStreamcreateEndpointModel— SSE-based model compatible withglove-nexthandlersparseSSEStream— Parse an SSE response stream intoRemoteStreamEventobjects
Voice bindings
Voice hooks and components are exported from glove-react/voice:
useGloveVoice— Core voice hook (mode, transcript, start/stop/interrupt)useGlovePTT— Push-to-talk with click-vs-hold detection, hotkey, min-durationVoicePTTButton— Headless PTT button with render prop and ARIA attributes
Requires glove-voice as a peer dependency.
Async session ID
When your session ID comes from a backend (auth tokens, server-assigned IDs, etc.), use getSessionId instead of a static sessionId:
// At the client level — applies to all useGlove consumers
const client = new GloveClient({
endpoint: "/api/chat",
systemPrompt: "You are a helpful assistant.",
getSessionId: async () => {
const res = await fetch("/api/session");
const { sessionId } = await res.json();
return sessionId;
},
});// Or at the hook level — overrides the client-level getSessionId
function Chat() {
const glove = useGlove({
getSessionId: async () => {
const res = await fetch("/api/session");
const { sessionId } = await res.json();
return sessionId;
},
});
// sessionReady is false while the async ID is resolving
if (!glove.sessionReady) return <div>Loading session...</div>;
// sessionId contains the resolved value
console.log("Session:", glove.sessionId);
return <Render glove={glove} />;
}When getSessionId is configured, the store is null until the ID resolves. The hook guards the build, hydration, and sendMessage flows against the null store, so consumers only need to check sessionReady before rendering. When no getSessionId is provided, behavior is unchanged -- sessionReady is always true and the session ID is either the provided sessionId or an auto-generated UUID.
Display strategies
| Strategy | Behavior |
|----------|----------|
| "stay" (default) | Slot always visible |
| "hide-on-complete" | Hidden when slot is resolved/rejected |
| "hide-on-new" | Hidden when a newer slot from the same tool appears |
Documentation
- React API Reference
- Display Stack Guide
- Server-Side Agents — using glove-core directly without React
- Getting Started
License
MIT
