Stacks & Interactions
The Stack is the heart of Hugin's architecture. Every step an agent takes is an Interaction pushed onto the stack. This immutable history enables powerful features like replay, step-through debugging, and branching.
Interaction Types
| Type | Description |
|---|---|
TaskDefinition |
Initial task prompt that starts the agent |
AskOracle |
Request sent to an LLM |
OracleResponse |
Response from the LLM (text or tool calls) |
ToolCall |
Request to execute a tool |
ToolResult |
Result returned from a tool |
AskHuman |
Request for human input |
HumanResponse |
Response from a human |
TaskResult |
Final result when task completes |
TaskChain |
Transition to a new task |
AgentCall |
Call to another agent |
AgentResult |
Result from another agent |
Stack Visualization
Each interaction is pushed onto the stack in order. The stack provides the context window for LLM calls - when the agent asks the oracle, the full stack is rendered into the prompt.
Branching
Branches allow parallel exploration from any point in the stack:
# Create a branch from current position
branch_id = stack.create_branch("exploration_a")
# Work in the branch
stack.push(interaction, branch_id=branch_id)
# Branch has isolated context but shares parent history
context = stack.get_branch_context(branch_id)
Use Cases for Branching
- Parallel problem solving: Try multiple approaches simultaneously
- Hypothesis testing: Explore different assumptions
- Rollback: Return to a previous state and try again
Context Windows
The stack manages context for LLM calls:
# Get context for main stack
context = stack.get_context()
# Get context for a specific branch
context = stack.get_branch_context(branch_id)
Context includes:
- All interactions from the start to current position
- Branch-specific interactions (if in a branch)
- Rendered templates with current state
Shared State
Stacks can access session-wide shared state via namespaces:
# Get state for a namespace
state = stack.get_shared_state("analytics")
# Modify and save
state["total_processed"] = 100
stack.set_shared_state("analytics", state)
Namespaces enable:
- Producer-consumer patterns: One agent writes, others read
- Coordination: Agents synchronize via shared state
- Access control: Restrict which agents can read/write
Accessing the Stack in Tools
Tools receive the stack as their first parameter:
def my_tool(stack, param1: str) -> str:
# Access agent
agent = stack.agent
# Access environment
env = agent.environment
# Access shared state
state = stack.get_shared_state("my_namespace")
# Access previous interactions
history = stack.get_context()
return "result"
Stack Persistence
Stacks are automatically persisted to storage, enabling:
- Resume from any point: Restart an agent from saved state
- Debugging: Inspect the full history of an agent run
- Auditing: Track every decision an agent made