Skip to content

Execution Tree

The Execution Tree tracks all LLM calls, gadget executions, and their hierarchical relationships.

ExecutionTree
├── LLM Call #1 (sonnet, 1,200 tokens, $0.003)
│ ├── Gadget: ReadFile
│ └── Gadget: BrowseWeb (subagent)
│ ├── LLM Call #1 (haiku, 800 tokens)
│ └── LLM Call #2 (haiku, 600 tokens)
└── LLM Call #2 (sonnet, 900 tokens, $0.002)
const result = await LLMist.createAgent()
.withModel('sonnet')
.withGadgets(ReadFile, WriteFile)
.withHooks({
observers: {
onAgentComplete: (ctx) => {
const tree = ctx.tree;
console.log(`Total cost: $${tree.getTotalCost().toFixed(4)}`);
console.log(`Total tokens: ${JSON.stringify(tree.getTotalTokens())}`);
},
},
})
.askAndCollect('Read config.json');
// Total metrics
const totalCost = tree.getTotalCost();
const tokens = tree.getTotalTokens();
// { input: 5000, output: 1200, cached: 800 }
// Subtree metrics (for subagents)
const subtreeCost = tree.getSubtreeCost(gadgetNodeId);
const subtreeTokens = tree.getSubtreeTokens(gadgetNodeId);
const media = tree.getSubtreeMedia(gadgetNodeId);
// Navigation
const node = tree.getNode("llm_1");
const children = tree.getChildren("llm_1");
const ancestors = tree.getAncestors("gadget_xyz");

The ExecutionTree is the single source of truth for all agent events. Both the TUI/CLI and user hook observers receive events from the same source, ensuring consistent behavior.

tree.on("gadget_complete", (event) => {
// Check if this is from a subagent
if (event.depth > 0) {
console.log(`↳ Subagent gadget: ${event.name} (depth ${event.depth})`);
} else {
console.log(`${event.name} completed in ${event.executionTimeMs}ms`);
}
});
// Or iterate with full subagent awareness
for await (const event of tree.events()) {
if (event.type === 'thinking') {
process.stdout.write(` 💭 ${event.content}`);
}
if (event.type === 'llm_call_complete') {
const prefix = event.depth > 0 ? ` ↳ [depth ${event.depth}]` : '';
console.log(`${prefix}LLM #${event.iteration}: ${event.usage?.totalTokens} tokens`);
if (event.thinkingContent) {
console.log(` Thinking: ${event.thinkingContent.length} chars`);
}
}
}
Event TypeDescription
llm_call_startLLM request initiated
llm_call_completeLLM response received with usage stats
gadget_callGadget parsed from stream (before execution)
gadget_startGadget execution started
gadget_completeGadget executed successfully
gadget_errorGadget failed with error
gadget_skippedGadget skipped due to failed dependency
thinkingReasoning model thinking content
textText output from LLM
compactionContext was compacted

When subagents use withParentContext(ctx), they share the parent’s tree:

const agent = new AgentBuilder()
.withParentContext(ctx!) // Shares tree
.withModel('haiku')
.ask(params.task);
// After completion
const subtreeCost = ctx?.tree?.getSubtreeCost(ctx.nodeId!);
  • Subagents - Creating nested agent gadgets
  • Hooks - Lifecycle monitoring