npm package: @gizmo-ai/action-tree-plugin
Description: Action tree plugin for storing and visualizing runtime actions
Latest version: 0.2.1

# @gizmo-ai/action-tree-plugin

Action tree plugin for the Gizmo runtime. Stores all dispatched actions in Redux state as a tree structure, allowing you to query and render them however you want.

## Install

```bash
bun add @gizmo-ai/action-tree-plugin
```

## Quick start

```ts
import { createRuntime } from "@gizmo-ai/runtime";
import { agentPlugin } from "@gizmo-ai/agent-plugin";
import {
  actionTreePlugin,
  selectActionTree,
  renderTree,
} from "@gizmo-ai/action-tree-plugin";

const agent = agentPlugin({ model });
const actionTree = actionTreePlugin();

const runtime = createRuntime({
  plugins: [actionTree, agent],
});

// Subscribe and render when you want
runtime.subscribe(() => {
  const tree = selectActionTree(runtime.getState());
  console.log(renderTree(tree));
});
```

## Configuration

```ts
import { actionTreePlugin, isStreamingDelta } from "@gizmo-ai/action-tree-plugin";

const actionTree = actionTreePlugin({
  // Limit memory usage by pruning oldest actions
  maxActions: 10_000,

  // Clear tree when new execution starts
  resetOnExecutionStarted: true,

  // Filter/transform actions before storing
  tap: (action) => {
    // Skip streaming deltas to reduce noise
    if (isStreamingDelta(action)) return null;
    // Sanitize sensitive data
    return sanitize(action);
  },
});
```

### Memory management

Without limits, the action tree grows indefinitely. In long-running or streaming sessions, this can cause memory issues. Use `maxActions` to cap the tree size:

```ts
actionTreePlugin({
  maxActions: 10_000,  // Prune when exceeded
});
```

When pruning, oldest actions are removed first. Children of removed actions are also removed (orphan cleanup).

### Reset on execution

For agents that run multiple executions, you may want a fresh tree each time:

```ts
actionTreePlugin({
  resetOnExecutionStarted: true,  // Clear on RUNTIME_EXECUTION_STARTED
});
```

### Filtering with tap

Use the `tap` hook to filter out actions before they're stored:

```ts
actionTreePlugin({
  tap: (action) => {
    // Skip streaming deltas
    if (isStreamingDelta(action)) return null;
    return action;
  },
});
```

## Accessing state

The plugin stores actions in state under the `actionTree` key:

```ts
const state = runtime.getState();
// state.actionTree.actions - Record of all stored actions
// state.actionTree.roots - Array of root action IDs
```

Use selectors to work with the tree:

```ts
import {
  selectActionTree,
  selectActions,
  selectRootIds,
} from "@gizmo-ai/action-tree-plugin";

// Get tree structure for rendering
const tree = selectActionTree(state);

// Get raw actions map
const actions = selectActions(state);

// Get root action IDs
const roots = selectRootIds(state);
```

## Custom rendering

The `renderTree` utility produces a formatted string, but you can render however you want:

```ts
import { selectActionTree } from "@gizmo-ai/action-tree-plugin";

const tree = selectActionTree(runtime.getState());

// Custom rendering
function customRender(nodes, depth = 0) {
  for (const node of nodes) {
    console.log("  ".repeat(depth) + node.type);
    customRender(node.children, depth + 1);
  }
}

customRender(tree);
```

## API

### `actionTreePlugin(options?)`

Creates the plugin. Options:

- `tap?: (action) => action | null` - Filter/transform actions before storing
- `maxActions?: number` - Maximum actions to store; oldest pruned when exceeded
- `resetOnExecutionStarted?: boolean` - Clear tree on new execution (default: false)

### Selectors

- `selectActionTree(state)` - Returns tree structure (`TreeNode[]`)
- `selectActionTreeState(state)` - Returns raw state
- `selectActions(state)` - Returns actions record
- `selectRootIds(state)` - Returns root action IDs

### `renderTree(tree, options?)`

Renders tree to string. Options:

- `ignoreActions?: string[]` - Action types to skip in rendering

### Utilities

- `isStreamingDelta(action)` - Check if action is a streaming delta
- `isStreamingAction(action)` - Check if action is streaming-related
- `isTerminalExecution(action)` - Check if action ends execution
- `getActionId(action)` - Extract action ID from metadata
- `getParentActionId(action)` - Extract parent action ID
- `getExecutionId(action)` - Extract execution ID