Realtime voice and avatars, agentic image generation, a working environment that can look at what it made, and memory that knows what to withhold. Eight packages landed this week. Here is what each one is for.
There is a shape to this release that only became obvious once it was finished. Almost everything in it gives an agent a faculty it did not have: a voice that answers in real time, a face, eyes to check its own output, hands to produce media, and judgement about what to keep to itself. Individually they are separate packages. Together they are the difference between an agent that returns text and one that does the work.
Glove has had a voice pipeline for a while — the cascade: speech → text → agent → text → speech. It works, and its latency is the sum of its parts. Realtime speech-to-speech models collapse that stack: the model listens and speaks directly, and turn taking is decided by something that can actually hear the caller.
glove-voice-s2s runs an ordinary Glove agent on those models — OpenAI Realtime and Gemini Live. The agent definition does not change. Your tools, your display stack, your context management all still apply; only the transport underneath is different.
const agent = new Glove({
store,
// The model slot carries the realtime config, so the agent definition
// stays the single source of truth and RealtimeAgent derives the session.
model: s2sDrivenModel({
provider: "openai",
turnDetection: { type: "server_vad", silence_duration_ms: 450 },
}),
displayManager: new Displaymanager(),
systemPrompt: "...",
}).fold(bookTableTool);
const rt = new RealtimeAgent({ agent });
await rt.start();Two details in there took the longest and matter the most. Turn-taking knobs are typed rather than raw JSON, because silence thresholds are the difference between an agent that interrupts people and one that feels patient. And barge-in does truncation sync — when a caller cuts the agent off, the model is told what the caller actually heard, not what it had planned to say. Without that, the agent carries on as though it delivered a sentence that nobody received.
glove-voice-avatar puts a face over that audio — an AvatarAdapter contract with a conformance suite, plus working Tavus and Anam adapters. And glove-voice-livekit replaces the hand-rolled audio duct with WebRTC in both directions: the browser side shrinks to Room.connect plus a microphone toggle, and barge-in becomes a server-authoritative buffer flush instead of a client-side race.
The working environment is a sandboxed filesystem an agent writes scripts against, instead of calling a fixed menu of tools. This week it gained five capability adapters, and one verb that changes what it can be trusted with.
| Adapter | What it gives the agent |
|---|---|
env:media | ffmpeg — describe a video without decoding it, thumbnail, clip, concat, transcode, extract frames |
env:slides | Build PowerPoint decks from a spec, and read decks back as text and outlines |
env:archives | zip / tar / tar.gz both directions, with traversal- and bomb-safe extraction. No dependencies |
env:render | Rasterize PDFs, decks, Word files and images to page PNGs — inside the sandbox |
env:motion | Render React scenes — including Reanimated — to deterministic frames, stills and video |
Everything above produces artifacts an agent could previously only reason about indirectly. It could build a slide deck and describe its own XML back to itself, and be entirely wrong about what the deck looked like. A table running off the page, a chart with no bars, a title overlapping a figure — none of those are visible in the markup.
view_image(path, prompt, page?) closes that loop. Paired with env:render, the agent rasterizes what it made and actually looks at it. It is the only verb in the environment that catches a visual defect, and it is the difference between “the file was written” and “the deliverable is correct”.
Alongside it, three quieter additions with real consequences: readOnlyPaths gives the agent directories it may read but never edit; cachedRemote backs the tree with object storage so a session survives the process; and pure modules expose synchronous libraries synchronously. That last one is subtler than it sounds — a missed await on a promise is silent garbage, so a synchronous library reached through an async binding fails in a way that still reports success.
glove-image is the newest package and the biggest conceptual shift in the release. A hand-rolled generate_image(prompt) tool works exactly once. The moment images are a repeated job, four things break: prompts are built rather than typed, recurring subjects drift between turns, settings need to stay consistent, and existing images have to come back in as inputs.
So each of those became a primitive:
The gallery is the honest version of this claim: a campaign shot in one scripted run, every frame shown with the prompt that produced it and what it cost, plus a canvas that draws one image's real provenance from its recorded recipe rather than from a diagram someone drew.
glove-memory gained three things that are all really the same thing: control over exposure.
Tool allowlists let a memory-backed agent be given a slice of the surface rather than all of it. Resource access control gates the resource filesystem by path, so a subagent can be handed a subtree instead of the tree. And layered memory merges a shared stratum and a private one into a single view — a team knowledge base underneath, a user's own memory on top, one coherent read.
Forms moved in the same direction: a trigger can now route on state rather than only on values, and can send a conversation back to a step it already completed — or stop collection outright when carrying on would be wrong rather than merely unfinished.
Eight new packages is also eight new ways to be lost. The documentation was restructured around what you are trying to do rather than which package does it, every package got covered, and two machine-readable surfaces landed: llms.txt as an index and llms-full.txt as a condensed reference.
That second one is not a novelty. Most Glove code is now written with a model in the loop, and a model that has to guess an API writes plausible code that does not run. Giving it the real surface is cheaper than debugging the invention.
The obvious gap in generative media is video — the image package is deliberately scoped to stills, and env:motion already handles the deterministic side of rendering. For images specifically: React renderers and a candidate picker, direct OpenAI and Gemini adapters, and bridges into the scratchpad and the working environment.
Everything here is MIT and on GitHub. If you build something with it, we would like to see it.