Jump to content

Connect Leeroopedia MCP: Equip your AI agents to search best practices, build plans, verify code, diagnose failures, and look up hyperparameter defaults.

Implementation:Spcl Graph of thoughts Selector Operation

From Leeroopedia
Knowledge Sources
Domains Graph_Reasoning, Thought_Operations
Last Updated 2026-02-14
Implements Principle:Spcl_Graph_of_thoughts_Thought_Selection

Overview

Implementation of the thought selection pattern that partitions thoughts from predecessors using a custom selection function, enabling different subsequent operations on different thought subsets.

Description

The Selector class is a concrete operation in the Graph of Thoughts framework that applies a user-defined selection function to choose a subset of thoughts from predecessors. It is implemented as a subclass of Operation with operation type OperationType.selector.

The execution flow is:

  1. Retrieve all predecessor thoughts via get_previous_thoughts()
  2. If there are no predecessor thoughts (including when there are no predecessors), create a single thought from the operation's kwargs (passed from the Controller) as a fallback
  3. Apply the selector function to the list of thoughts
  4. Clone each selected thought via Thought.from_thought()
  5. Store the selected thoughts and log the count

This operation does not interact with the language model, Prompter, or Parser. Unlike most other operations, the Selector does not assert that it has predecessors -- it can operate as an entry point by using kwargs to create an initial thought.

Usage

from graph_of_thoughts.operations import Selector

# Select a specific sublist by index
sel_first = Selector(selector=lambda thoughts: [thoughts[0]])
sel_second = Selector(selector=lambda thoughts: [thoughts[1]])

# Select thoughts matching a condition
sel_large = Selector(
    selector=lambda thoughts: [t for t in thoughts if len(t.state.get("list", [])) > 10]
)

# Wire into graph after a Generate that produces sub-problems
sel_first.add_predecessor(generate_split_op)
sel_second.add_predecessor(generate_split_op)

Code Reference

Source Location

  • File: graph_of_thoughts/operations/operations.py, Lines 840-900
  • Import: from graph_of_thoughts.operations import Selector

Class Signature

class Selector(Operation):
    operation_type: OperationType = OperationType.selector

    def __init__(self, selector: Callable[[List[Thought]], List[Thought]]) -> None:
        """
        Initializes a new Selector operation.

        :param selector: A function to select thoughts from the predecessors' thoughts.
        :type selector: A function that takes a list of thoughts and returns a list of thoughts.
        """

Key Methods

  • __init__(self, selector: Callable[[List[Thought]], List[Thought]]) -> None -- Initializes the operation with the selector function and an empty thoughts list.
  • get_thoughts(self) -> List[Thought] -- Returns the list of selected thoughts after execution.
  • _execute(self, lm, prompter, parser, **kwargs) -> None -- Core execution logic: retrieves predecessors (or creates from kwargs), applies selector, clones results.

Internal State

  • self.selector: Callable[[List[Thought]], List[Thought]] -- The user-defined selection function.
  • self.thoughts: List[Thought] -- Stores the selected thoughts after execution.

I/O Contract

Input Output Side Effects
Predecessor thoughts (or kwargs as Thought if no predecessors). When predecessors exist, all their thoughts are collected. When no predecessor thoughts are available, a single Thought(kwargs) is created from the Controller's keyword arguments. Selected subset of thoughts (cloned) -- new Thought objects for each thought returned by the selector function. The number and identity of output thoughts depends entirely on the selector function's logic. No language model interaction. Logs selected thoughts at DEBUG level and count at INFO level.

Selection logic:

previous_thoughts = self.get_previous_thoughts()

if len(previous_thoughts) == 0:
    previous_thoughts = [Thought(kwargs)]

self.thoughts = [
    Thought.from_thought(thought)
    for thought in self.selector(previous_thoughts)
]

No assertions on predecessors: Unlike most operations, Selector does not require predecessors. It gracefully handles the no-predecessor case by creating a thought from kwargs.

Usage Examples

Sorting: Route Sublists to Separate Branches

from graph_of_thoughts.operations import Generate, Selector, Score, KeepBestN

# Generate splits the input list into sublists
gen_split = Generate(num_branches_prompt=1, num_branches_response=1)

# Each Selector routes one sublist to its own processing branch
sel_0 = Selector(selector=lambda thoughts, i=0: [thoughts[i]])
sel_1 = Selector(selector=lambda thoughts, i=1: [thoughts[i]])

sel_0.add_predecessor(gen_split)
sel_1.add_predecessor(gen_split)

# Each branch independently sorts its sublist
gen_sort_0 = Generate(num_branches_prompt=5, num_branches_response=1)
gen_sort_0.add_predecessor(sel_0)

gen_sort_1 = Generate(num_branches_prompt=5, num_branches_response=1)
gen_sort_1.add_predecessor(sel_1)

Conditional Branching

from graph_of_thoughts.operations import Selector

# Route thoughts to different branches based on state content
sel_easy = Selector(
    selector=lambda thoughts: [t for t in thoughts if t.state.get("difficulty") == "easy"]
)
sel_hard = Selector(
    selector=lambda thoughts: [t for t in thoughts if t.state.get("difficulty") == "hard"]
)

sel_easy.add_predecessor(classification_op)
sel_hard.add_predecessor(classification_op)

Entry Point Without Predecessors

from graph_of_thoughts.operations import Selector

# Use Selector as an entry point to partition initial state
sel = Selector(selector=lambda thoughts: thoughts)

# When executed with kwargs (e.g., via Controller), the kwargs
# are wrapped in a Thought and passed to the selector function.
# Controller.run(initial_state={"input": "some data"})

Related Pages

Page Connections

Double-click a node to navigate. Hold to expand connections.
Principle
Implementation
Heuristic
Environment