Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 74 additions & 29 deletions docs/content/docs/openui-lang/examples/harnesses/vercel-eve.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,32 @@ The agent receives the OpenUI component-library prompt when a session starts, so

[View source on GitHub →](https://github.com/thesysdev/openui/tree/main/examples/harnesses/vercel-eve)

## Architecture

```text
browser ── Eve session HTTP ──▶ Eve agent ── model + tools
▲ │
└── AG-UI SSE ── event adapter ─┘
rendered by <FullScreen>
```

The integration has four main pieces:

| Piece | File | Role |
| --- | --- | --- |
| OpenUI chat | `src/app/page.tsx` | Renders `<FullScreen>` with `agUIAdapter()` and the built-in OpenUI component library. |
| Session bridge | `src/eve-chat.ts` | Delivers turns through Eve's HTTP API, follows its resumable event stream, and returns AG-UI SSE to OpenUI. |
| Event adapter | `src/eve-stream.ts` | Maps Eve text, tool-call, and failure events to AG-UI events. |
| Agent instructions | `agent/instructions/openui.ts` | Adds the generated OpenUI system prompt when each Eve session starts. |
<div className="bg-[rgba(0,0,0,0.05)] dark:bg-gray-900 rounded-2xl h-[500px] flex p-2">
<video
src="/videos/vercel-eve.mp4"
noControls
playsInline
muted
preload="metadata"
className="w-full rounded-lg m-auto"
autoPlay
loop
/>
</div>

## How it connects

| Piece | File | Role |
| ------------------ | ------------------------------ | ----------------------------------------------------------------------------------------------------------- |
| OpenUI chat | `src/app/page.tsx` | Renders `<FullScreen>` with `agUIAdapter()` and the built-in OpenUI component library. |
| Session bridge | `src/eve-chat.ts` | Delivers turns through Eve's HTTP API, follows its resumable event stream, and returns AG-UI SSE to OpenUI. |
| Event adapter | `src/eve-stream.ts` | Maps Eve text, tool-call, and failure events to AG-UI events. |
| Agent instructions | `agent/instructions/openui.ts` | Adds the generated OpenUI system prompt when each Eve session starts. |

The Next.js app and Eve development server start together through `withEve()`. The browser uses
Eve's same-origin session endpoints directly, so the integration does not need a custom backend
route or CORS configuration. OpenUI threads retain Eve's session ID, continuation token, and
stream cursor, preserving multi-turn context and resumable delivery.

## Connecting OpenUI

Expand Down Expand Up @@ -69,7 +78,34 @@ export default defineDynamic({

This keeps the model's instructions synchronized with the exact component library used by the renderer.

## Translating Eve events
## The session bridge

The browser talks to the same-origin Eve endpoints installed by `withEve()`:

```text
POST /eve/v1/session
POST /eve/v1/session/:id
GET /eve/v1/session/:id/stream?startIndex=N
```

The first turn creates a session. Follow-up turns send the saved continuation token, and the
stream request resumes from the saved event index. Completed sessions clear the cursor; waiting
and failed sessions remain resumable.

```ts
const delivered = await fetch(
state.sessionId ? `/eve/v1/session/${state.sessionId}` : "/eve/v1/session",
{
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ message, continuationToken: state.continuationToken }),
},
);

const streamed = await fetch(`/eve/v1/session/${sessionId}/stream?startIndex=${state.streamIndex}`);
```

## Tool calls and streamed UI

Eve emits typed session events. The adapter in `src/eve-stream.ts` converts the events OpenUI needs:

Expand All @@ -83,17 +119,17 @@ session.failed -> RUN_ERROR

Tool calls and text share one assistant message ID. OpenUI renders tool activity in its behind-the-scenes section and the final OpenUI Lang response in the conversation.

## Eve session protocol
The included `get_current_time` tool is a minimal example. Additional Eve tools automatically
surface through the same AG-UI tool-call mapping.

The browser talks to the same-origin Eve endpoints installed by `withEve()`:
## Thread persistence

```text
POST /eve/v1/session
POST /eve/v1/session/:id
GET /eve/v1/session/:id/stream?startIndex=N
```
`src/thread-store.ts` keeps OpenUI thread metadata and transcripts in browser `localStorage`.
`src/eve-chat.ts` stores the Eve session ID, continuation token, and stream index under the same
thread ID. Reopening a thread therefore restores both the visible transcript and its server-side
Eve conversation.

For a follow-up turn, the bridge sends the saved continuation token and resumes from the saved stream index. A completed session clears the cursor; waiting and failed sessions remain resumable.
## Authentication and security

The demo channel uses anonymous authentication for local development. Replace `none()` in `agent/channels/eve.ts` with an authenticated Eve channel before exposing the application.

Expand All @@ -114,16 +150,25 @@ examples/harnesses/vercel-eve/

## Run the example

Eve 0.11 requires Node.js 24. From the repository root:
Eve 0.11 requires Node.js 24. From the repository root, follow these steps:

```bash
# 1. Install workspace dependencies.
pnpm install

# 2. Enter the example.
cd examples/harnesses/vercel-eve
LLM_API_KEY=your-api-key pnpm dev

# 3. Configure an OpenAI-compatible model provider.
cp .env.example .env
# Edit .env and set LLM_API_KEY.

# 4. Start Next.js and the embedded Eve development server.
pnpm dev
```

By default the agent uses OpenAI. Configure `LLM_MODEL` and `LLM_BASE_URL` to use another OpenAI-compatible endpoint. Open [http://localhost:3000](http://localhost:3000) and start a conversation.
Open [http://localhost:3000](http://localhost:3000) and start a conversation. `OPENAI_API_KEY`,
`OPENAI_MODEL`, and `OPENAI_BASE_URL` are accepted as aliases for the `LLM_*` variables.

The repository scripts also expose Eve directly when you need to build or run the agent separately:

Expand Down
Binary file added docs/public/videos/vercel-eve.mp4
Binary file not shown.
3 changes: 3 additions & 0 deletions examples/harnesses/vercel-eve/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
LLM_API_KEY=your-api-key
LLM_MODEL=gpt-5.5
LLM_BASE_URL=https://api.openai.com/v1
2 changes: 1 addition & 1 deletion examples/harnesses/vercel-eve/.gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
node_modules
.env*
!.env.example
.eve
.vercel
.workflow-data
Expand All @@ -12,4 +13,3 @@ dist

# Local-only live integration smoke test (needs a running agent + API key)
scripts/verify-thread-context.mjs

113 changes: 113 additions & 0 deletions examples/harnesses/vercel-eve/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
# OpenUI + Vercel Eve Harness

A generative-UI chat application backed by a [Vercel Eve](https://github.com/vercel/eve)
agent. Eve keeps its native session and resumable-streaming protocol, while a small adapter
translates Eve events into AG-UI events that OpenUI renders as live React components.

## Prerequisites

- Node.js 24
- pnpm 9
- An API key for an OpenAI-compatible model provider

## Run locally

1. Install the monorepo dependencies from the repository root:

```bash
pnpm install
```

2. Enter the example directory:

```bash
cd examples/harnesses/vercel-eve
```

3. Copy the example environment file and add your provider configuration:

```bash
cp .env.example .env
```

Set `LLM_API_KEY` in `.env`. `LLM_MODEL` and `LLM_BASE_URL` select the model and any
OpenAI-compatible endpoint. `OPENAI_API_KEY`, `OPENAI_MODEL`, and `OPENAI_BASE_URL` are
accepted as aliases.

4. Start the Next.js application and embedded Eve development server:

```bash
pnpm dev
```

5. Open [http://localhost:3000](http://localhost:3000) and start a conversation.

## How it works

```text
Browser / OpenUI FullScreen
├─ POST /eve/v1/session or /eve/v1/session/:id
├─ GET /eve/v1/session/:id/stream?startIndex=N
Eve HTTP channel ──► Eve agent ──► model + tools
Eve session events ──► AG-UI adapter ──► OpenUI renderer
```

- `src/app/page.tsx` renders OpenUI's `<FullScreen>` chat with the built-in component library.
- `src/eve-chat.ts` delivers turns through Eve's HTTP session protocol and persists session
cursors per OpenUI thread.
- `src/eve-stream.ts` converts Eve text, tool-call, and failure events into AG-UI events.
- `agent/instructions/openui.ts` injects the generated OpenUI Lang prompt when an Eve session
starts.
- `src/thread-store.ts` stores thread metadata, transcripts, continuation tokens, and stream
positions in browser `localStorage`.

## Configuration

| Environment variable | Default | Purpose |
| -------------------- | ------------------------------------------------ | ---------------------------------------------- |
| `LLM_API_KEY` | `OPENAI_API_KEY` | API key sent to the configured model provider. |
| `LLM_MODEL` | `OPENAI_MODEL` or `gpt-5.5` | Model used by the Eve agent. |
| `LLM_BASE_URL` | `OPENAI_BASE_URL` or `https://api.openai.com/v1` | OpenAI-compatible API endpoint. |

## Eve commands

The normal development command is `pnpm dev`. The package also exposes Eve directly:

```bash
pnpm eve:dev
pnpm eve:build
pnpm eve:start
```

For a production-style Next.js run:

```bash
pnpm build
pnpm start
```

## Project layout

```text
examples/harnesses/vercel-eve/
|- agent/agent.ts # Eve model and build configuration
|- agent/channels/eve.ts # Eve HTTP session channel
|- agent/instructions/openui.ts # Generated OpenUI Lang instructions
|- agent/tools/get_current_time.ts # Example Eve tool
|- src/app/page.tsx # OpenUI FullScreen chat
|- src/eve-chat.ts # Eve session transport and persistence
|- src/eve-stream.ts # Eve-to-AG-UI event mapping
|- src/thread-store.ts # Browser thread and transcript storage
|- next.config.ts # Installs Eve through withEve()
```

## Security

The example uses Eve's `none()` channel authentication for local development. Do not expose it
publicly in that form. Configure an authenticated Eve channel, restrict network access, and apply
the provider and tool permissions appropriate for your deployment.
Loading