Page:
Data Flow 02 ReAct Loop
Pages
Architecture Commands and API
Architecture Context System
Architecture Core Engine
Architecture Event Sourcing
Architecture Generative Reflection
Architecture Helpers
Architecture Journal System
Architecture LLM Interaction
Architecture LLM Providers
Architecture Logging
Architecture Memory and Sleep
Architecture Overview
Architecture Persona Protection
Architecture Prompt System
Architecture RAG Implementation
Architecture Resilience System
Architecture Safety System
Architecture Self Management
Architecture Sub Agent Delegation
Architecture Task Assessment
Architecture Token Management
Architecture Tool System
Configuration Reference
Context and Memory Flow Analysis
Data Flow 01 Context Compaction
Data Flow 02 ReAct Loop
Data Flow 03 Memory Consolidation
Data Flow 04 Message Classification
Data Flow 05 Entity Profile System
Data Flow 06 Tool Execution
Data Flow 07 Sleep Mode Transitions
Data Flow 08 LLM Provider Interaction
Data Flow 09 Self Management Operations
Home
LLM Decision Patterns
Research Foundations
User Guide 00 Index
User Guide 01 Getting Started
User Guide 02 Configuration and Customization
User Guide 03 Advanced Capabilities
User Guide 04 Troubleshooting
No results
1
Data Flow 02 ReAct Loop
blightbow edited this page 2025-12-07 00:47:14 +00:00
Data Flow 02: ReAct Loop Execution
Engineering documentation series - Data flows in the AI Assistant system
Overview
The ReAct (Reasoning + Acting) loop is the core execution engine for multi-action AI behavior. Each tick can execute multiple tool calls in sequence until a termination condition is met.
Related Documents
| Document | Description |
|---|---|
| Data-Flow-01-Context-Compaction | Context management |
| Data-Flow-06-Tool-Execution | Individual tool execution |
1. Tick Entry Point
Trigger
TICKER_HANDLER → AssistantScript.at_tick()
└─> Line 710: execute_react_loop() or single action
Pre-Loop Processing
┌─────────────────────────────────────────────────────────────────────────────┐
│ TICK START │
│ assistant_script.py:at_tick() │
└─────────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ EARLY EXITS │
│ ─────────────────────────────────────────────────────────────────────────── │
│ 1. Already ticking (db.is_ticking == True) → return │
│ 2. Not enabled (db.enabled == False) → return │
│ 3. Emergency stopped (db.emergency_stopped == True) → return │
│ 4. No character → return │
└─────────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ EMERGENCY COMPACTION CHECK (lines 646-667) │
│ ─────────────────────────────────────────────────────────────────────────── │
│ If awake mode AND context >= 80%: │
│ yield compact_conversation_history(force=True) │
└─────────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ SLEEP MODE CHECK (lines 669-693) │
│ ─────────────────────────────────────────────────────────────────────────── │
│ If operating_mode == "sleep": │
│ yield _run_sleep_tick() │
│ Check wake conditions │
│ return (skip normal tick) │
└─────────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ REFLECTION CHECK (lines 695-699) │
│ ─────────────────────────────────────────────────────────────────────────── │
│ If ticks_since_reflection >= reflection_interval: │
│ yield _trigger_reflection() │
└─────────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ EXECUTION PATTERN SELECTION (lines 701-708) │
│ ─────────────────────────────────────────────────────────────────────────── │
│ 1. context_type = _determine_context_type() │
│ 2. llm_assessment = yield _assess_task() (Layer 3) │
│ 3. execution_pattern = _get_execution_pattern(context_type, llm_assessment) │
│ │
│ Three-Layer Composition: │
│ Layer 1: Static config (db.execution_config) │
│ Layer 2: Context config (per-context overrides) │
│ Layer 3: LLM assessment (advisory, optional) │
└─────────────────────────────────────────────────────────────────────────────┘
2. ReAct Loop Execution
Decision Point
# Line 713
if should_use_react_loop(execution_pattern):
loop_result = yield execute_react_loop(...)
else:
# Single action mode (legacy)
Loop Flow
┌─────────────────────────────────────────────────────────────────────────────┐
│ REACT LOOP START │
│ tool_execution.py:execute_react_loop() line 381 │
└─────────────────────────────────────────────────────────────────────────────┘
│
┌─────────────────────────┴─────────────────────────┐
│ FOR EACH ITERATION │
│ (up to max_iterations) │
└───────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ STEP 1: PRE-ITERATION CHECK (lines 429-438) │
│ ─────────────────────────────────────────────────────────────────────────── │
│ token_usage = _calculate_token_usage(script) │
│ continuation = check_loop_continuation(token_usage, iteration, max_iter) │
│ │
│ If NOT should_continue: │
│ termination_reason = continuation["reason"] │
│ break │
└─────────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ STEP 2: BUILD LLM MESSAGES (lines 440-447) │
│ ─────────────────────────────────────────────────────────────────────────── │
│ messages = yield build_messages_fn() │
│ │
│ Includes: │
│ - System prompt (persona, tools, context) │
│ - Conversation history │
│ - Previous tool results (if any) │
│ - Token advisory (if approaching limits) │
└─────────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ STEP 3: CALL LLM (lines 449-462) │
│ ─────────────────────────────────────────────────────────────────────────── │
│ response = yield call_llm_fn(messages) │
│ │
│ LLM decides: │
│ - Which tool to call (or noop if done) │
│ - Parameters for the tool │
│ - Reasoning for the decision │
└─────────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ STEP 4: PARSE TOOL CALL (lines 464-481) │
│ ─────────────────────────────────────────────────────────────────────────── │
│ tool_call = parse_tool_call_fn(response) │
│ │
│ If tool_name == "noop": │
│ termination_reason = "noop" │
│ break (LLM explicitly done) │
└─────────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ STEP 5: VALIDATE TOOL (lines 483-509) │
│ ─────────────────────────────────────────────────────────────────────────── │
│ tool = TOOL_REGISTRY.get_tool(tool_name) │
│ │
│ Check: │
│ - Tool exists in registry │
│ - Tool category allowed in current context │
│ │
│ If invalid: log error, continue to next iteration │
└─────────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ STEP 6: EXECUTE TOOL (lines 511-517) │
│ ─────────────────────────────────────────────────────────────────────────── │
│ result = yield execute_tool_call(script, character, tool_call) │
│ │
│ Includes: │
│ - Parameter validation │
│ - Timeout handling │
│ - Retry logic for transient failures │
│ - Result caching (if tool is cacheable) │
└─────────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ STEP 7: INJECT TOKEN ADVISORY (lines 519-522) │
│ ─────────────────────────────────────────────────────────────────────────── │
│ token_usage = _calculate_token_usage(script) │
│ result = inject_token_advisory(result, token_usage) │
│ │
│ Adds advisory to result if approaching limits: │
│ MODERATE (50-70%): "Consider wrapping up" │
│ HIGH (70-80%): "Complete current task soon" │
│ CRITICAL (80%+): "Must conclude immediately" │
└─────────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ STEP 8: CHECK TERMINATION CONDITIONS (lines 524-548) │
│ ─────────────────────────────────────────────────────────────────────────── │
│ │
│ TERMINAL tool (say, page, whisper): │
│ └─> termination_reason = "terminal_tool", break │
│ (Ends loop to await player response) │
│ │
│ DANGEROUS tool (execute_command, set_attribute): │
│ └─> termination_reason = "dangerous_tool", break │
│ (Single execution for safety) │
│ │
│ CRITICAL token usage (80%+): │
│ └─> termination_reason = "critical_tokens", break │
│ │
│ Otherwise: continue to next iteration │
└─────────────────────────────────────────────────────────────────────────────┘
│
▼
[NEXT ITERATION]
3. Termination Conditions
| Condition | Reason Code | Behavior |
|---|---|---|
| TERMINAL tool | terminal_tool |
Loop ends, await player response |
| DANGEROUS tool | dangerous_tool |
Single execution per tick |
| NOOP returned | noop |
LLM explicitly signaled completion |
| Max iterations | max_iterations |
Safety limit reached |
| Critical tokens (80%+) | critical_tokens |
Context limit protection |
| LLM error | llm_error |
Network/API failure |
| Parse error | parse_error |
Invalid LLM response format |
4. Tool Categories
| Category | Loop Behavior | Examples |
|---|---|---|
SAFE_CHAIN |
Continue loop | inspect_location, recall_memories, search_objects |
TERMINAL |
End loop | say, page, whisper, emote |
DANGEROUS |
End loop | execute_command, set_attribute |
ASYNC_REQUIRED |
Continue loop | store_memory, delegate_task |
5. Loop Result Structure
{
"iterations": 3, # Number of iterations executed
"results": [ # Results from each iteration
{"success": True, "tool": "inspect_location", ...},
{"success": True, "tool": "recall_memories", ...},
{"success": True, "tool": "say", ...},
],
"termination_reason": "terminal_tool",
"success": True, # At least one successful execution
"success_count": 3,
"pattern_mode": "react_loop",
"max_allowed_iterations": 10,
}
6. Key Files
| File | Relevant Lines | Purpose |
|---|---|---|
assistant_script.py |
600-812 | at_tick() entry point |
tool_execution.py |
381-573 | execute_react_loop() |
tool_execution.py |
52-277 | execute_tool_call() |
tools/__init__.py |
- | check_loop_continuation(), inject_token_advisory() |
Document created: 2025-12-06