@gizmo-ai/action-tree-plugin
v0.2.1
Published
Action tree plugin for storing and visualizing runtime actions
Readme
@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
bun add @gizmo-ai/action-tree-pluginQuick start
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
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:
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:
actionTreePlugin({
resetOnExecutionStarted: true, // Clear on RUNTIME_EXECUTION_STARTED
});Filtering with tap
Use the tap hook to filter out actions before they're stored:
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:
const state = runtime.getState();
// state.actionTree.actions - Record of all stored actions
// state.actionTree.roots - Array of root action IDsUse selectors to work with the tree:
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:
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 storingmaxActions?: number- Maximum actions to store; oldest pruned when exceededresetOnExecutionStarted?: boolean- Clear tree on new execution (default: false)
Selectors
selectActionTree(state)- Returns tree structure (TreeNode[])selectActionTreeState(state)- Returns raw stateselectActions(state)- Returns actions recordselectRootIds(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 deltaisStreamingAction(action)- Check if action is streaming-relatedisTerminalExecution(action)- Check if action ends executiongetActionId(action)- Extract action ID from metadatagetParentActionId(action)- Extract parent action IDgetExecutionId(action)- Extract execution ID
