# TAgent Core Architecture Documentation

## Technical Overview

TAgent is an autonomous AI agent framework designed for reasoning and execution tasks, inspired by the Redux architecture pattern but simplified for AI scenarios. It manages centralized state updated through actions, enabling proactive decision loops. To maximize compatibility with diverse Large Language Models (LLMs), TAgent avoids dependency on native "function calls," opting instead for **Structured Outputs**.

The framework is ideal for applications like task automation, AI assistants, or autonomous workflows where the agent plans, executes, and evaluates actions until achieving a specified goal.

## Core Architecture Principles

### Redux-Inspired State Management
- **Centralized State**: Single source of truth stored as a dictionary
- **Immutable Updates**: State changes only through dispatched actions
- **Predictable Flow**: Deterministic state transitions
- **Time Travel**: Ability to replay actions for debugging

### Structured Output Integration
- **LLM Compatibility**: Works with any text-generating model
- **No Function Calling**: Avoids model-specific tool calling features
- **JSON Schema**: Enforced output formats for reliability
- **Fallback Mechanisms**: Graceful handling of malformed outputs

### Modular Tool System
- **Dynamic Discovery**: Automatic loading of `tagent.tools.py` files
- **Signature Validation**: Type-safe tool registration
- **State Integration**: Tools receive and update agent state
- **Error Isolation**: Individual tool failures don't crash the system

## Component Architecture

### State Management

```python
class AgentState(BaseModel):
    """Represents agent state as a typed dictionary."""
    data: Dict[str, Any] = {}

class Store:
    """Redux-inspired store managing agent state and tool registry."""
    
    def __init__(self, initial_state: Dict[str, Any]):
        self.state = AgentState(data=initial_state)
        self.tools: Dict[str, Callable] = {}
        self.conversation_history: List[Dict[str, str]] = []
    
    def dispatch(self, action_func: Callable, verbose: bool = False) -> None:
        """Dispatch an action and apply state updates."""
        result = action_func(self.state.data)
        if result:
            self._apply_reducer(result)
```

**State Structure:**
- Dictionary-based for easy serialization and debugging
- Pydantic validation for type safety
- Conversation history tracking for context
- Tool registry for dynamic capability extension

### Action System

Actions are pure functions that receive state and return state updates:

```python
def example_action(state: Dict[str, Any]) -> Optional[Tuple[str, Any]]:
    """
    Example action that processes state and returns updates.
    
    Args:
        state: Current agent state dictionary
        
    Returns:
        Tuple of (key, value) for state update, or None if no update
    """
    # Process current state
    result = process_data(state.get('input_data'))
    
    # Return state update
    return ('processed_result', result)
```

**Action Types:**
- **System Actions**: Core framework actions (plan, execute, evaluate)
- **Tool Actions**: External tools registered dynamically
- **Custom Actions**: Application-specific logic

### Tool Integration

Tools follow a standardized interface:

```python
def my_custom_tool(state: Dict[str, Any], args: Dict[str, Any]) -> Optional[Tuple[str, Any]]:
    """
    Custom tool example with proper signature.
    
    Args:
        state: Current agent state for context
        args: Tool-specific arguments from LLM decision
        
    Returns:
        State update tuple or None
    """
    # Extract parameters
    param1 = args.get('param1')
    param2 = args.get('param2')
    
    # Perform tool logic
    result = external_api_call(param1, param2)
    
    # Return state update
    return ('tool_result', result)
```

**Tool Discovery Process:**
1. Scan specified directories for `tagent.tools.py` files
2. Load modules and extract functions with correct signatures
3. Validate function signatures: `(state, args) -> Optional[Tuple[str, Any]]`
4. Register validated tools in the agent's tool registry
5. Make tools available for LLM selection during execution

### Structured Output System

The framework uses structured outputs to maintain LLM compatibility:

```python
class StructuredResponse(BaseModel):
    """Schema for structured outputs generated by LLMs."""
    action: str  # "plan", "execute", "summarize", "evaluate"
    params: Dict[str, Any] = {}
    reasoning: str = ""

def query_llm(prompt: str, model: str, **kwargs) -> StructuredResponse:
    """
    Query LLM with structured output enforcement.
    
    Args:
        prompt: Input prompt with context and instructions
        model: LLM model identifier
        **kwargs: Additional model parameters
        
    Returns:
        Validated structured response
    """
    # Build messages with system prompt for JSON output
    messages = [
        {"role": "system", "content": "You are an AI assistant that outputs JSON."},
        {"role": "user", "content": f"{prompt}\n\nRespond with valid JSON: {StructuredResponse.model_json_schema()}"}
    ]
    
    # Call LLM and validate response
    response = llm_client.completion(model=model, messages=messages)
    return StructuredResponse.model_validate_json(response.content)
```

**Structured Output Flow:**
1. **Prompt Construction**: Build context-rich prompts with current state
2. **Schema Enforcement**: Include JSON schema in system prompts
3. **LLM Query**: Send to any text-generating model
4. **Response Validation**: Parse and validate JSON against Pydantic schema
5. **Action Dispatch**: Route to appropriate action based on parsed response

## Main Agent Loop

The autonomous decision loop forms the core of agent behavior:

```python
def run_agent(goal: str, model: str, tools: Dict[str, Callable], **kwargs) -> Any:
    """
    Main agent execution loop.
    
    Args:
        goal: Objective for the agent to achieve
        model: LLM model for decision making
        tools: Dictionary of available tools
        **kwargs: Additional configuration
        
    Returns:
        Final structured output or execution result
    """
    store = Store({'goal': goal, 'results': [], 'used_tools': []})
    
    # Register tools
    for name, tool_func in tools.items():
        store.register_tool(name, tool_func)
    
    iteration = 0
    max_iterations = kwargs.get('max_iterations', 20)
    
    while not store.state.data.get('achieved', False) and iteration < max_iterations:
        iteration += 1
        
        # Build decision prompt
        prompt = build_decision_prompt(store.state.data, tools)
        
        # Get LLM decision
        decision = query_llm(prompt, model)
        
        # Dispatch action based on decision
        if decision.action == "execute" and decision.params.get('tool'):
            tool_name = decision.params['tool']
            tool_args = decision.params.get('args', {})
            
            if tool_name in store.tools:
                result = store.tools[tool_name](store.state.data, tool_args)
                store._apply_reducer(result)
        
        elif decision.action == "evaluate":
            evaluation_result = evaluate_goal_achievement(store.state.data, goal, model)
            store._apply_reducer(('achieved', evaluation_result.get('achieved', False)))
        
        # Additional action handling...
    
    return format_final_output(store.state.data, kwargs.get('output_format'))
```

**Loop Components:**
1. **State Assessment**: Analyze current progress toward goal
2. **Decision Making**: Query LLM for next action with structured output
3. **Action Execution**: Dispatch appropriate action or tool
4. **State Update**: Apply results through reducer pattern
5. **Goal Evaluation**: Assess if objective has been achieved
6. **Iteration Control**: Prevent infinite loops with max iterations

## Advanced Features

### Error Recovery and Loop Detection

```python
def detect_action_loop(recent_actions: List[str], max_recent: int = 3) -> bool:
    """Detect if agent is stuck in repetitive action loops."""
    if len(recent_actions) < 2:
        return False
    
    # Check for immediate repetition
    if recent_actions[-1] == recent_actions[-2]:
        return True
    
    # Check for longer patterns
    if len(recent_actions) >= max_recent:
        last_actions = recent_actions[-max_recent:]
        return len(set(last_actions)) == 1
    
    return False
```

### Conversation History Management

```python
def format_conversation_as_chat(conversation_history: List[Dict[str, str]]) -> str:
    """Format conversation history for context and debugging."""
    chat_lines = ["=== CONVERSATION HISTORY ===\n"]
    
    for i, message in enumerate(conversation_history, 1):
        role = message.get('role', 'unknown')
        content = message.get('content', '')
        
        if role == 'user':
            chat_lines.append(f"👤 USER [{i}]: {content}\n")
        elif role == 'assistant':
            chat_lines.append(f"🤖 ASSISTANT [{i}]: {content}\n")
    
    return "\n".join(chat_lines)
```

### Tool Introspection

```python
def get_tool_documentation(tools: Dict[str, Callable]) -> str:
    """Extract and format tool documentation for LLM prompts."""
    tool_docs = []
    
    for tool_name, tool_func in tools.items():
        sig = inspect.signature(tool_func)
        docstring = inspect.getdoc(tool_func) or "No documentation available"
        
        tool_doc = f"- {tool_name}{sig}: {docstring}"
        tool_docs.append(tool_doc)
    
    return "Available tools:\n" + "\n".join(tool_docs)
```

## Production Considerations

### Performance Optimization
- **LLM Call Minimization**: Cache decisions when possible
- **Parallel Tool Execution**: For independent operations
- **State Serialization**: Efficient storage and retrieval
- **Memory Management**: Clean up large intermediate results

### Error Handling
- **Graceful Degradation**: Continue operation despite individual tool failures
- **Timeout Management**: Prevent infinite loops and long-running operations
- **Validation Layers**: Multiple levels of input/output validation
- **Rollback Mechanisms**: Ability to revert problematic state changes

### Monitoring and Debugging
- **Comprehensive Logging**: All actions, decisions, and state changes
- **Performance Metrics**: Execution time, success rates, resource usage
- **Debug Mode**: Detailed output for development and troubleshooting
- **State Inspection**: Tools for examining agent state at any point

## Extension Points

### Custom Action Types
Extend the framework with new action patterns:

```python
def register_custom_action(action_name: str, action_func: Callable):
    """Register new action type in the agent framework."""
    SYSTEM_ACTIONS[action_name] = action_func
```

### Output Format Handlers
Support new output formats through Pydantic models:

```python
class CustomOutputFormat(BaseModel):
    """Custom output structure for specific use cases."""
    results: List[Dict[str, Any]]
    metadata: Dict[str, str]
    confidence: float

def format_custom_output(state: Dict[str, Any]) -> CustomOutputFormat:
    """Convert agent state to custom output format."""
    return CustomOutputFormat(
        results=state.get('results', []),
        metadata=state.get('metadata', {}),
        confidence=state.get('confidence', 0.0)
    )
```

### Model Integration
Support for new LLM providers:

```python
def integrate_custom_llm(provider_name: str, client_class: Any):
    """Integrate new LLM provider into the framework."""
    LLM_PROVIDERS[provider_name] = client_class
```

This architecture provides a robust, extensible foundation for building autonomous AI agents that can adapt to various tasks while maintaining reliability and performance in production environments.

---

**Version**: 1.0  
**Last Updated**: July 12, 2025  
**Maintainer**: TAgent Development Team