How FlaskAgent Implements the Delegation Pattern Using the `_parent` Attribute

The FlaskAgent class in the heurist-agent-framework uses a protected _parent attribute combined with custom __getattr__ and __setattr__ methods to delegate all attribute access and mutation to a core agent when running in shared mode, or to itself when operating standalone.

The delegation pattern in the heurist-network/heurist-agent-framework allows the Flask-based API interface to flexibly wrap an existing agent or operate independently. At the heart of this implementation is the _parent attribute within the FlaskAgent class, which determines whether attribute operations are handled locally or forwarded to a core agent.

Initializing the _parent Attribute in interfaces/api.py

The delegation mechanism begins in the FlaskAgent constructor located in interfaces/api.py (lines 28‑39). The initialization logic distinguishes between shared mode (wrapping an existing agent) and standalone mode (self-contained operation).

class FlaskAgent:
    def __init__(self, core_agent=None):
        # …

        if core_agent:
            super().__setattr__("_parent", core_agent)      # ← delegate to provided core

        else:
            # Stand‑alone mode – the agent is its own parent

            super().__setattr__("_parent", self)            # bypass __setattr__

            super().__init__()

When a core agent (an instance of BaseAgent) is supplied, FlaskAgent stores it in _parent. If no core is supplied, the agent sets _parent to itself and then runs the normal BaseAgent constructor. The use of super().__setattr__ avoids invoking the overridden __setattr__ during this bootstrap phase, preventing infinite recursion.

Delegating Attribute Reads via __getattr__

Attribute read delegation is handled by a custom __getattr__ method defined in interfaces/api.py (lines 46‑48). This method is invoked automatically whenever an attribute lookup fails to find the named attribute in the instance dictionary.

def __getattr__(self, name):
    # missing attribute → forward to parent

    return getattr(self._parent, name)

The implementation simply forwards the lookup to whatever object lives in _parent. This gives the FlaskAgent seamless access to the core agent’s methods and properties without explicit proxy methods for every attribute.

Delegating Attribute Writes via __setattr__

Attribute mutation follows a more complex delegation logic in __setattr__ (interfaces/api.py, lines 50‑59). The method must distinguish between initialization-time assignments, local attribute updates, and delegated writes.

def __setattr__(self, name, value):
    if not hasattr(self, "_parent"):
        # still constructing – set locally

        super().__setattr__(name, value)
    elif name == "_parent" or self is self._parent or name in self.__dict__:
        # set on this instance (e.g., _parent itself or already‑existing attrs)

        super().__setattr__(name, value)
    else:
        # forward the assignment to the parent

        setattr(self._parent, name, value)

The logic follows three branches:

  1. Construction phase: If _parent does not yet exist, the assignment is handled locally using super().__setattr__.
  2. Local updates: Assignments to _parent itself, attributes already present in __dict__, or when the agent is its own parent (self is self._parent) are stored on the instance.
  3. Delegation: All other assignments are forwarded to the parent object, ensuring that state changes affect the core agent when running in shared mode.

Detecting Shared vs. Standalone Mode at Runtime

The FlaskAgent uses the _parent reference to determine its operating mode during request handling (interfaces/api.py, lines 95‑99).

if self._parent != self:
    logger.info("Operating in shared mode with core agent")
else:
    logger.info("Operating in standalone mode")

By comparing self._parent to self, the agent can branch logic appropriately, choosing whether to invoke methods on the wrapped core or on its own BaseAgent infrastructure.

Practical Usage Examples

The following patterns demonstrate how to instantiate and use FlaskAgent in both configurations:


# 1️⃣ Stand‑alone usage – no core supplied

flask_agent = FlaskAgent()
assert flask_agent._parent is flask_agent   # self‑parented

# 2️⃣ Shared usage – delegate to an existing core agent

core = BaseAgent()
flask_agent = FlaskAgent(core_agent=core)
assert flask_agent._parent is core          # delegated

# 3️⃣ Attribute delegation

flask_agent.some_core_method()   # __getattr__ forwards call to core

flask_agent.shared_state = 42    # __setattr__ stores on core when not local

Summary

  • _parent serves as the delegation pivot, storing either a supplied core agent or a self-reference.
  • Initialization in interfaces/api.py uses super().__setattr__ to bootstrap the _parent reference without triggering recursion.
  • Read delegation occurs via __getattr__, which forwards missing attribute lookups to _parent.
  • Write delegation in __setattr__ distinguishes between construction, local updates, and forwarded assignments to ensure state consistency.
  • Mode detection compares self._parent to self to determine whether the agent is wrapping a shared core or operating standalone.

Frequently Asked Questions

What is the purpose of the _parent attribute in FlaskAgent?

The _parent attribute stores a reference to the core agent instance when FlaskAgent is initialized with an existing agent, or points to self when operating in standalone mode. This reference enables the delegation mechanism by providing a target for __getattr__ and __setattr__ operations.

How does FlaskAgent handle attribute assignment when running in shared mode?

When running in shared mode, the custom __setattr__ method checks if the attribute already exists locally or if the assignment targets _parent itself. If neither condition is met, the assignment is forwarded via setattr(self._parent, name, value), ensuring that state changes affect the wrapped core agent rather than the Flask wrapper.

Can FlaskAgent operate without a core agent?

Yes. When instantiated without a core_agent argument, FlaskAgent sets _parent to self and invokes super().__init__(), initializing its own BaseAgent infrastructure. This allows the class to function as a self-contained agent while maintaining the same interface used in shared mode.

Where is the delegation logic implemented in the heurist-agent-framework?

The delegation logic is implemented in interfaces/api.py within the FlaskAgent class. The relevant methods—__init__, __getattr__, and __setattr__—appear between lines 28 and 59, while runtime mode detection occurs around lines 95-99. The core agent type, BaseAgent, is defined in agents/base_agent.py.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →