npm package: @gizmo-ai/ag-ui-adapter-plugin
Description: AG-UI protocol adapter plugin for Gizmo runtime
Author: Gizmo Contributors
Latest version: 0.2.1

# @gizmo-ai/ag-ui-adapter-plugin

AG-UI protocol adapter plugin for Gizmo runtime. Provides AG-UI wire protocol compatibility while preserving 100% of Gizmo's observability features.

## Features

- **AG-UI Protocol Compatibility** - Maps Gizmo's 45+ actions to standard AG-UI events (RunStarted, TextMessageContent, ToolCallStart, etc.)
- **RFC 6902 JSON Patch** - Generates STATE_DELTA events with compliant JSON Patch operations for incremental state updates
- **Dual Observability** - Both Gizmo native actions AND AG-UI events visible in Redux DevTools
- **Zero Breaking Changes** - Opt-in plugin that doesn't affect existing Gizmo users
- **SSE Streaming** - Events emitted via EventEmitter for Server-Sent Events integration

## Installation

```bash
bun add @gizmo-ai/ag-ui-adapter-plugin fast-json-patch
```

## Usage

### Basic Setup

```typescript
import { createRuntime } from "@gizmo-ai/runtime";
import { agentPlugin } from "@gizmo-ai/agent-plugin";
import { agUIAdapterPlugin } from "@gizmo-ai/ag-ui-adapter-plugin";
import { createServer, createServerPlugin } from "@gizmo-ai/server";
import { anthropic } from "@gizmo-ai/model-anthropic";

// 1. Create AG-UI adapter plugin
const aguiAdapter = agUIAdapterPlugin({
  trackedSlices: ["agent"], // Which state slices to track for STATE_DELTA
  emitStateDelta: true, // Enable STATE_DELTA events
});

// 2. Create runtime with adapter plugin
const runtime = createRuntime({
  plugins: [
    agentPlugin({ model: anthropic() }),
    aguiAdapter,
    serverPlugin.plugin,
  ] as const,
});

// 3. Create server with AG-UI route
const server = createServer({
  runtime,
  plugin: serverPlugin,
  agUIAdapterBus: aguiAdapter.bus, // Pass adapter bus to enable /events/ag-ui route
});

server.listen(3000);
```

### Consuming AG-UI Events

Connect to the `/events/ag-ui` endpoint to receive AG-UI protocol events:

```typescript
const events = new EventSource("http://localhost:3000/events/ag-ui");

events.addEventListener("RunStarted", (e) => {
  const event = JSON.parse(e.data);
  console.log("Execution started:", event.runId);
});

events.addEventListener("TextMessageContent", (e) => {
  const event = JSON.parse(e.data);
  console.log("Assistant:", event.content);
});

events.addEventListener("ToolCallStart", (e) => {
  const event = JSON.parse(e.data);
  console.log("Tool call:", event.toolName, event.input);
});

events.addEventListener("STATE_DELTA", (e) => {
  const event = JSON.parse(e.data);
  // Apply RFC 6902 JSON Patch operations
  applyPatch(state, event.patches);
});
```

## AG-UI Event Mapping

### Gizmo → AG-UI Event Mapping

| Gizmo Action | AG-UI Event | Notes |
|--------------|-------------|-------|
| `RUNTIME_EXECUTION_STARTED` | `RunStarted` | Direct mapping |
| `RUNTIME_EXECUTION_COMPLETED` | `RunFinished` | status: "completed" |
| `RUNTIME_EXECUTION_FAILED` | `RunFinished` | status: "failed", includes error |
| `RUNTIME_EXECUTION_ABORTED` | `RunFinished` | status: "cancelled" |
| `AGENT_MODEL_RESPONDED` | `TextMessageContent` | Extract text content |
| `AGENT_MODEL_STREAM_CONTENT_DELTA` | `TextMessageContent` | Chunked streaming |
| `AGENT_MODEL_STREAM_REASONING_DELTA` | `ReasoningContent` | Extended thinking |
| `AGENT_MODEL_STREAM_COMPLETED` | `TextMessageContent` | Stream complete marker |
| `AGENT_TOOL_CALL_REQUESTED` | `ToolCallStart` | Direct mapping |
| `AGENT_TOOL_CALL_EXECUTED` | `ToolCallOutput` | Direct mapping |
| `AGENT_TOOL_CALL_FAILED` | `ToolCallError` | Includes error details |
| `AGENT_TOOL_MISSING` | `ToolCallError` | code: "TOOL_NOT_FOUND" |
| State changes | `STATE_DELTA` | RFC 6902 JSON Patch |

### Unmapped Gizmo Actions

The following Gizmo actions are **not** mapped to AG-UI events (preserved in native `/events` endpoint only):

- `RUNTIME_WORK_*` - Internal work tracking
- `AGENT_CONTEXT_PREPARATION_NEEDED` - Internal coordination
- `AGENT_MODEL_REQUESTED` - Only responses matter for AG-UI
- `AGENT_MODEL_STREAM_STARTED` - Covered by first content delta
- `AGENT_LOOP_INCREMENTED` - Internal tracking
- `AGENT_REGISTER_TOOL` - Not in AG-UI spec
- `AGENT_DEREGISTER_TOOL` - Not in AG-UI spec
- `AGENT_SYSTEM_MESSAGE_UPDATED` - Internal state
- `AGENT_CONVERSATION_TRUNCATED` - Internal state

## Configuration Options

```typescript
interface AGUIAdapterConfig {
  /**
   * EventEmitter for emitting AG-UI events
   * If not provided, creates a new EventEmitter
   */
  bus?: EventEmitter;

  /**
   * Which state slices to track for STATE_DELTA events
   * Default: ['agent'] (only track agent slice)
   */
  trackedSlices?: string[];

  /**
   * Whether to emit STATE_DELTA events on state changes
   * Default: true
   */
  emitStateDelta?: boolean;

  /**
   * Minimum delay between STATE_DELTA emissions (ms)
   * Used to throttle high-frequency state updates
   * Default: 0 (no throttling)
   */
  stateDeltaThrottleMs?: number;
}
```

## Advanced Usage

### Listening to AG-UI Events in Middleware

```typescript
import { agUIAdapterPlugin } from "@gizmo-ai/ag-ui-adapter-plugin";

const adapter = agUIAdapterPlugin();

// Listen to AG-UI events
adapter.bus.on("ag-ui.event", (event) => {
  if (event.type === "RunStarted") {
    console.log("New execution started:", event.runId);
  }
});
```

### Applying JSON Patch Operations

```typescript
import { applyPatch } from "fast-json-patch";

let state = { agent: { conversation: [], loop: { count: 0 } } };

events.addEventListener("STATE_DELTA", (e) => {
  const event = JSON.parse(e.data);
  const patchResult = applyPatch(state, event.patches, true);
  state = patchResult.newDocument;
});
```

### Redux DevTools Integration

All AG-UI events are dispatched as `AG_UI_EVENT_EMITTED` actions, making them visible in Redux DevTools alongside native Gizmo actions:

```typescript
{
  type: "AG_UI_EVENT_EMITTED",
  payload: {
    event: {
      type: "RunStarted",
      runId: "exec-123",
      input: "Hello",
      timestamp: 1704067200000
    },
    sourceAction: "RUNTIME_EXECUTION_STARTED"
  }
}
```

## Performance Considerations

### State Diff Generation

- **Memory Overhead**: Tracking previous state for JSON Patch adds ~2-5MB overhead
- **Mitigation**: Only track `agent` slice by default (configurable via `trackedSlices`)
- **Performance**: `fast-json-patch` generates diffs at ~1000 ops/sec for 10KB objects

### Throttling STATE_DELTA Events

For high-frequency state updates, use `stateDeltaThrottleMs`:

```typescript
const adapter = agUIAdapterPlugin({
  stateDeltaThrottleMs: 100, // Max 10 STATE_DELTA events per second
});
```

## Architecture

### Plugin Flow

```
┌─────────────────────────────────────┐
│  Gizmo Runtime + Plugins            │
│  ├─ agent-plugin (45+ actions)      │
│  └─ ag-ui-adapter-plugin (NEW)      │
│     • Listens to Gizmo actions      │
│     • Maps to AG-UI events          │
│     • Generates JSON Patch deltas   │
│     • Emits AG_UI_EVENT_EMITTED     │
└──────────────┬──────────────────────┘
               │ Both protocols in Redux DevTools
               ▼
┌─────────────────────────────────────┐
│  Server with Dual Endpoints         │
│  ├─ GET /events (Gizmo native)      │
│  └─ GET /events/ag-ui (AG-UI)       │
└──────────────┬──────────────────────┘
               │
               ├──► Gizmo Client (full observability)
               └──► AG-UI Client (standard protocol)
```

### Key Principles

1. **Zero Breaking Changes** - Existing Gizmo users unaffected
2. **Dual Emission** - Both Gizmo actions AND AG-UI events emitted
3. **100% Observability** - All 45 Gizmo actions preserved in Redux DevTools
4. **Standard Protocol** - AG-UI events follow specification
5. **Clean Layering** - Adapter is pure transformation, no business logic

## Troubleshooting

### No AG-UI events received

Ensure you passed `agUIAdapterBus` to `createServer`:

```typescript
const server = createServer({
  runtime,
  plugin: serverPlugin,
  agUIAdapterBus: aguiAdapter.bus, // Required for /events/ag-ui
});
```

### STATE_DELTA events not emitting

Check that `emitStateDelta` is enabled (default: true):

```typescript
const adapter = agUIAdapterPlugin({
  emitStateDelta: true, // Ensure this is true
});
```

### High memory usage

Reduce tracked state slices:

```typescript
const adapter = agUIAdapterPlugin({
  trackedSlices: ["agent"], // Only track agent slice (default)
});
```

## API Reference

See the [full API documentation](../../docs/ag-ui-compatibility.md) for detailed type definitions and event schemas.

## Related

- [AG-UI Protocol Specification](https://github.com/ag-ui/ag-ui)
- [RFC 6902 JSON Patch](https://datatracker.ietf.org/doc/html/rfc6902)
- [Gizmo Documentation](../../README.md)

## License

MIT