Cognitive Loops (ReAct/CoT)
Relevant source files
The following files were used as context for generating this wiki page:
The cognitive loop is the "Brain" of a Loom agent, implementing an autonomous perceive-think-act cycle. It transforms a Large Language Model (LLM) from a passive question-answering tool into an active problem-solver that can reason, use tools, and interact with its environment to achieve a goal. This capability is central to Loom's architecture, enabling agents to perform complex, multi-step tasks.
The cognitive module is implemented in Python, aligning with the "Brain/Hand" separation principle. This allows for rapid iteration on reasoning strategies, prompt engineering, and context management, while leveraging the stable, secure Rust core for tool execution.
Sources: loom-py/src/loom/cognitive/README.md, ARCHITECTURE.md, ROADMAP.md
Architecture
The cognitive module is structured to separate concerns between coordination, strategy, and execution. The primary class, CognitiveAgent, orchestrates the process, delegating the thinking process to a StrategyExecutor and tool usage to a ToolExecutor. This design was a refactoring from a single large agent.py file to improve clarity and testability.
Sources: loom-py/src/loom/cognitive/README.md
This diagram shows the high-level architecture of the cognitive module.
Sources: loom-py/src/loom/cognitive/README.md
Key Components
| Component | File | Responsibility |
|---|---|---|
CognitiveAgent | agent.py | The main coordinator. It receives a goal, manages the overall loop, integrates with context engineering, and returns the final result. |
StrategyExecutor | strategies.py | Implements the specific thinking patterns (ReAct, CoT, Single-shot) that the LLM will follow. |
ToolExecutor | executor.py | Handles the secure execution of tools, including human-in-the-loop approval, security validation, and result processing. (Note: executor.py is not in the provided files but is described in loom-py/src/loom/cognitive/README.md). |
LLMProvider | llm.py | Makes direct HTTP calls to the configured LLM API. It is intentionally kept separate from the Rust core. |
Sources: loom-py/src/loom/cognitive/README.md, ARCHITECTURE.md
Thinking Strategies
The StrategyExecutor implements different reasoning patterns. The desired strategy is selected via the thinking_strategy parameter in CognitiveConfig.
Sources: loom-py/src/loom/cognitive/strategies.py, loom-py/src/loom/cognitive/README.md
ReAct (Reason + Act)
The ReAct strategy is an iterative loop of Thought -> Action -> Observation. This is the recommended strategy for complex tasks that require tool use. The agent reasons about what to do next, executes a tool, observes the outcome, and repeats the cycle until it has enough information to provide a final answer.
This flowchart illustrates the iterative ReAct pattern.
Chain of Thought (CoT)
The Chain of Thought strategy involves breaking down a problem into intermediate steps to arrive at a final answer. It is used for complex reasoning that does not require external tools.
Sources: loom-py/src/loom/cognitive/README.md, core/src/cognitive/README.md
Single-shot
This is the simplest strategy, involving a single call to the LLM to get a direct answer. It is suitable for simple questions that do not require iteration or tool use.
Sources: loom-py/src/loom/cognitive/README.md, core/src/cognitive/README.md
Execution Flow
The CognitiveAgent.run() method initiates the cognitive loop. The following sequence diagram illustrates the interactions between components during a ReAct cycle.
Configuration
The behavior of the cognitive loop is controlled by the CognitiveConfig data class.
| Parameter | Type | Default | Description |
|---|---|---|---|
system_prompt | str | None | The system prompt to guide the LLM's behavior. |
max_iterations | int | 10 | The maximum number of Thought -> Action cycles in the ReAct loop. |
thinking_strategy | ThinkingStrategy | REACT | The reasoning strategy to use (REACT, CHAIN_OF_THOUGHT, SINGLE_SHOT). |
require_final_answer | bool | True | If True, the loop must end with a "FINAL ANSWER:" block. |
reflection_enabled | bool | False | Enables a self-reflection step after acting (marked as future work). |
Sources: loom-py/src/loom/cognitive/README.md, core/src/cognitive/config.rs:10-21
Example instantiation:
from loom.cognitive import CognitiveAgent, CognitiveConfig, ThinkingStrategy
from loom.llm import LLMProvider
# Create cognitive agent
cognitive = CognitiveAgent(
ctx=agent.ctx,
llm=LLMProvider.from_name(agent.ctx, "deepseek"),
config=CognitiveConfig(
system_prompt="You are a research assistant...",
max_iterations=10,
thinking_strategy=ThinkingStrategy.REACT,
),
available_tools=["web:search", "fs:write_file"],
workspace_path="/workspace",
)
# Run cognitive loop
result = await cognitive.run("Research AI frameworks")
Sources: loom-py/src/loom/cognitive/README.md:52-70
Context Engineering Integration
The cognitive loop is tightly integrated with Loom's context engineering pipeline to manage token limits and maintain context quality. This happens automatically within the CognitiveAgent.
This diagram shows how context engineering is applied during the cognitive loop.
Usage in Agents
While CognitiveAgent provides a structured implementation, agents can also implement cognitive patterns manually. The deep-research demo agent is an example of this, where the researcher.py agent performs a sequence of searching and summarizing.
The researcher_handler receives a request, calls execute_research, which in turn calls web_search and then analyze_and_summarize. The analyze_and_summarize function constructs a detailed prompt and uses an LLMProvider to generate a structured JSON output, demonstrating a "think" step.
# From apps/deep-research/agents/researcher.py
async def analyze_and_summarize(
ctx,
query: str,
focus_area: str,
search_results: List[SearchResult],
) -> Dict[str, Any]:
# ... build search_context ...
prompt = f"""You are a research analyst..."""
# ...
response = await llm_provider.generate(
prompt=prompt,
system="You are a research analyst. Return only valid JSON.",
# ...
)
# ... parse response ...
return data