Skip to content

Provides PersistentAgent class for Agent classes with persistent state (#603)#604

Open
kiranandcode wants to merge 12 commits intomasterfrom
kg-persistent-agents
Open

Provides PersistentAgent class for Agent classes with persistent state (#603)#604
kiranandcode wants to merge 12 commits intomasterfrom
kg-persistent-agents

Conversation

@kiranandcode
Copy link
Contributor

This PR provides a subclass to the effectful API which allows users to create PersistentAgents who store their state to file and can be restored and resumed on crash. These agents also compact and restore their context. Closes #603

class ArchitectAgent(PersistentAgent):
    """You are a software architect. Given a project specification, you break
    it into individual module implementation tasks. Each task should specify
    the module filename, its public API, and what tests to write.
    Be concrete and specific — the coder will follow your spec exactly.
    """

    def __init__(self, persist_dir: Path):
        super().__init__(persist_dir=persist_dir, agent_id="architect")
        self._output_dir = OUTPUT_DIR

    @Tool.define
    def read_existing_files(self) -> str:
        """List files already written to the output directory."""
        if not self._output_dir.exists():
            return "No files yet."
        files = sorted(self._output_dir.rglob("*.py"))
        if not files:
            return "No Python files yet."
        return "\n".join(str(f.relative_to(self._output_dir)) for f in files)

    @Template.define
    def plan_modules(self, project_spec: str) -> PlanResult:
        """Given this project specification, output a plan with a "modules" list.
        Each module spec has: module_path, description, public_api, test_path.

        Use `read_existing_files` to check what's already been written
        and skip those.

        Project spec:
        {project_spec}"""
        raise NotHandled

See docs/source/multi_agent_example.py for an example of a non-trivial multi-agent workflow involving three agents doing a larger library task. This code is fairly robust, involves several agents, and can be Ctrl-C'd and restarted on demand.

@eb8680
Copy link
Contributor

eb8680 commented Mar 10, 2026

I don't think Agents should carry implementations of side-effectful behavior like this. Even the blog post you cited in #603 says to manage state separately and globally. Side effect implementations should live in handlers that are separable from one another and from application logic, as with RetryLLMHandler - for example, why should the implementations of compaction and persistence be tightly coupled in this way? Even the append-only message histories currently stored on Agent should probably be replaced with a per-instance identifier and a global message history handler.

@kiranandcode
Copy link
Contributor Author

@eb8680 , Hmm, yeah, that makes sense. I opted for class based state first because that makes tracking histories a little easier as a first pass than using a global handler and then re-associating calls to specific agents, but a global handler might be cleaner.

Will refactor.

kiranandcode and others added 5 commits March 11, 2026 11:35
…d docs

- Changed PersistenceHandler to accept db_path (Path to .db file) instead
  of persist_dir (directory), making the API explicit
- Removed in-memory caching of handoffs and loaded sets; all state is now
  read from/written to SQLite directly (thread-local loaded tracking remains)
- Made ensure_loaded and get_handoff private (_ensure_loaded, _get_handoff)
- Added crash recovery example to docstring
- Updated all tests to use new db_path API and reduced LLM call budgets
  for faster test execution

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

More support for multi-agentic systems in effectful

3 participants