Skip to content

Conversation

@JackYPCOnline
Copy link
Contributor

@JackYPCOnline JackYPCOnline commented Oct 22, 2025

Description

This is a split from multiagent session persistent part 2.

  • This PR introudce sessionType to session manager.
  • Implement read/write_multiagent_json.
  • Rename deserialize function.
  • Update origin write function to be atomic write.

For more context, see origin: #900

Overview

This PR extends the session management system to support multi-agent workflows alongside existing single-agent functionality.

New APIs Added

SessionType Enum Extension

  • Added SessionType.MULTI_AGENT to distinguish multi-agent sessions from single-agent sessions

SessionRepository Interface

def create_multi_agent(self, session_id: str, multi_agent: MultiAgentBase, **kwargs) -> None
def read_multi_agent(self, session_id: str, multi_agent_id: str, **kwargs) -> Optional[dict[str, Any]]  
def update_multi_agent(self, session_id: str, multi_agent_state: dict[str, Any], **kwargs) -> None

SessionManager Base Class

def sync_multi_agent(self, source: MultiAgentBase, **kwargs) -> None
def initialize_multi_agent(self, source: MultiAgentBase, **kwargs) -> None

Implementation Changes

FileSessionManager

  • Directory Structure: Multi-agent sessions create multi_agents/ instead of agents/ directory
  • Storage Format: Multi-agent state stored as multi_agent_<id>/multi_agent.json
  • File Structure:
    session_<id>/
    ├── session.json
    └── multi_agents/
        └── multi_agent_<multi_agent_id>/
            └── multi_agent.json
    

S3SessionManager

  • S3 Key Structure: Multi-agent state stored under multi_agents/multi_agent_<id>/multi_agent.json
  • Atomic Operations: Uses S3 put_object for state persistence

RepositorySessionManager

  • Hook Integration: Registers multi-agent lifecycle hooks for automatic state persistence
  • State Management: Handles serialization/deserialization of multi-agent state

Backward Compatibility

  • All existing single-agent APIs remain unchanged
  • Default session_type=SessionType.AGENT maintains existing behavior
  • No breaking changes to current session management workflows

Integrate with Graph

Can correctly write to session , fire hooks on initializating, node finished, failed. Restore from saved session, start over if completed.

example state json:

{
  "type": "graph",
  "id": "default",
  "status": "executing",
   "failed_nodes": [],
  "completed_nodes": [
    "research"
  ],
  "node_results": {
    "research": {
      "result": {
        "type": "agent_result",
        "message": {
          "role": "assistant",
          "content": [
            {
              "text": "**The Last Letter**\n\nMaria found the yellowed envelope tucked inside her grandmother's old recipe box. Her name was written in shaky handwriting across the front. Inside, a note dated just weeks before Grandma's passing:\n\n\"My dearest Maria, by now you've discovered my secret ingredient wasn't really cinnamon. It was the love I stirred into every batch of cookies, every Sunday dinner, every moment we shared. The recipes are yours now, but remember—the magic isn't in following directions perfectly. It's in cooking with your heart, just like I taught you. Keep our family's love alive in your kitchen. Forever yours, Grandma.\"\n\nMaria smiled through her tears."
            }
          ]
        },
        "stop_reason": "end_turn"
      },
      "execution_time": 9796,
      "status": "completed",
      "accumulated_usage": {
        "inputTokens": 22,
        "outputTokens": 152,
        "totalTokens": 174
      },
      "accumulated_metrics": {
        "latencyMs": 5769
      },
      "execution_count": 1
    }
  },
  "next_nodes_to_execute": [
    "analysis",
    "fact_check"
  ],
  "current_task": "tell me a simple 100 words story",
  "execution_order": [
    "research"
  ]
}

Related Issues

Documentation PR

Type of Change

Bug fix
New feature
Breaking change
Documentation update
Other (please describe):

Testing

How have you tested the change? Verify that the changes do not break functionality or introduce warnings in consuming repositories: agents-docs, agents-tools, agents-cli

  • [ x] I ran hatch run prepare

Checklist

  • [ x] I have read the CONTRIBUTING document
  • [ x] I have added any necessary tests that prove my fix is effective or my feature works
  • [ x] I have updated the documentation accordingly
  • [ x] I have added an appropriate example to the documentation to outline the feature, or no new docs are needed
  • [ x] My changes generate no new warnings
  • Any dependent changes have been merged and published

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

@codecov
Copy link

codecov bot commented Oct 22, 2025

self,
session_id: str,
storage_dir: Optional[str] = None,
session_type: SessionType = SessionType.AGENT,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we need to require that this is a named parameter - @dbschmigelski can you confirm - I recall you we discussed a similar situation before? (if so, is there anywhere we can document/write this down)?

Suggested change
session_type: SessionType = SessionType.AGENT,
*,
session_type: SessionType = SessionType.AGENT,

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Out of curiosity, why does this need to be a named parameter?

@JackYPCOnline
Copy link
Contributor Author

JackYPCOnline commented Oct 23, 2025

answer this question: #1071 (comment)

I don't think this is a new issue—it's an aspect we overlooked. Even in the single-agent case, we face this file completeness problem. Talked with Patrick and Dean about this change. We don't perform any validation or defensive checks when reading the session file, ensuring its completeness is crucial.

@JackYPCOnline JackYPCOnline changed the title Split pr p2 feat: add multiagent session/repository management. Oct 26, 2025
@github-actions github-actions bot removed the size/l label Oct 26, 2025
@github-actions github-actions bot added size/l and removed size/l labels Oct 26, 2025
@github-actions github-actions bot removed the size/l label Oct 27, 2025
self,
session_id: str,
storage_dir: Optional[str] = None,
session_type: SessionType = SessionType.AGENT,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Out of curiosity, why does this need to be a named parameter?

self._write_file(multi_agent_file, multi_agent_state)

# Update session.update_at
self.update_session(session_id)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we also need to call self.update_session for update_agent() calls?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see SessionAgent has filed updated_at but yes, even for sinlge agent we should update matadata.

session_data = multi_agent.serialize_state()
self._write_file(multi_agent_file, session_data)

def read_multi_agent(self, session_id: str, multi_agent_id: str, **kwargs: Any) -> Optional[dict[str, Any]]:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For read_agent and update_agent, we pass around a SessionAgent instance. For consistency, do we want to setup a SessionMultiAgent type?

Copy link
Contributor Author

@JackYPCOnline JackYPCOnline Oct 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Initially I introduced a data class MultiagentState then we decided to remove that, so now, I don't think we should do that for update
For read we only have def read_agent(self, session_id: str, agent_id: str, **kwargs: Any) -> Optional[SessionAgent]

boto_session: Optional[boto3.Session] = None,
boto_client_config: Optional[BotocoreConfig] = None,
region_name: Optional[str] = None,
session_type: SessionType = SessionType.AGENT,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we have to make session_type a named parameter on FileSessionManager but not here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah it should, I had a bad rebase

raise SessionException(f"MultiAgent state {multi_agent_id} in session {session_id} does not exist")

multi_agent_key = f"{self._get_multi_agent_path(session_id, multi_agent_id)}multi_agent.json"
self._write_s3_object(multi_agent_key, multi_agent_state)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need an update_session call here also as we did in `FileSessionManager?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function wise no, s3 files has update at in console.
For file itself, yes. I had this conversation with @dbschmigelski in previous large PR. The conclusion is not updating it in S3

Comment on lines 124 to 125
Multi-agent state dictionary or empty dict if not found
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Multi-agent state dictionary or empty dict if not found
Multi-agent state dictionary or empty dict if not found.

) -> list[SessionMessage]:
"""List Messages from an Agent with pagination."""

@abstractmethod
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using @abstractmethod will immediately break anyone who derives a custom SessionRepository even if they don't use multi-agents. We should instead use the NotImplementedError approach.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we want to introduce new interface it has to be non-breaking?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants