Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve agent loop tracking and make concurrent limit configurable #6945

Open
wants to merge 12 commits into
base: main
Choose a base branch
from

Conversation

rbren
Copy link
Collaborator

@rbren rbren commented Feb 25, 2025

This PR improves how we track and manage concurrent agent loops:

  • Add max_concurrent_conversations to AppConfig (default: 3)
  • Add start_time tracking to Session class
  • Make get_running_agent_loops() return sessions in chronological order
  • Simplify oldest session selection by using chronological order

Previously, when the limit of concurrent agent loops was reached, the system would try to guess which was the oldest by reversing the list of session IDs. This was inaccurate. Now we track the actual start time of each session and make get_running_agent_loops() return sessions in chronological order, which makes it trivial to find the oldest session.

The limit of 3 concurrent conversations has also been moved from a hardcoded constant to a configurable value in AppConfig.


To run this PR locally, use the following command:

docker run -it --rm   -p 3000:3000   -v /var/run/docker.sock:/var/run/docker.sock   --add-host host.docker.internal:host-gateway   -e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:94fbecf-nikolaik   --name openhands-app-94fbecf   docker.all-hands.dev/all-hands-ai/openhands:94fbecf

- Add max_concurrent_conversations to AppConfig (default: 3)
- Add start_time tracking to Session class
- Make get_running_agent_loops() return sessions in chronological order
- Simplify oldest session selection by using chronological order
@rbren rbren marked this pull request as ready for review February 25, 2025 19:16
- Add conversation_store to ConversationManager interface
- Pass conversation_store from shared.py to conversation manager
- Use last_updated_at from metadata to determine session age
- Remove Session.start_time field
@rbren
Copy link
Collaborator Author

rbren commented Feb 25, 2025

@OpenHands please fix the lint issues

Copy link

openhands-ai bot commented Feb 25, 2025

I'm working on a fix! @rbren can track my progress at all-hands.dev

@@ -82,6 +82,7 @@ class AppConfig(BaseModel):
daytona_target: str = Field(default='us')
cli_multiline_input: bool = Field(default=False)
conversation_max_age_seconds: int = Field(default=864000) # 10 days in seconds
max_concurrent_conversations: int = Field(default=3) # Maximum number of concurrent agent loops allowed per user
Copy link
Collaborator

Choose a reason for hiding this comment

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

Good call - I could see folks wanting to customize this

sids_with_time = {} # sid -> last_updated_at
for sid, _ in items:
metadata = await self.conversation_store.get_metadata(sid)
if metadata:
Copy link
Contributor

Choose a reason for hiding this comment

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

The thinking here I assume is that metadata would never normally be missing, so we should be returning the same set of results as before.

# Get metadata for each session
sids_with_time = {} # sid -> last_updated_at
for sid, _ in items:
metadata = await self.conversation_store.get_metadata(sid)
Copy link
Contributor

Choose a reason for hiding this comment

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

Fetching from a store n-times instead of once with a list of ids is usually a bad move, but it looks like this is just for the sessions currently running, and that's going to be few, so should be fine,

@tofarr
Copy link
Collaborator

tofarr commented Feb 26, 2025

I strongly suggest we move the sort functionality out of the manager and into the ConversationStore class (adding an optional sort_order variable). In SAAS, this will translate to simple SQL, while in OSS it will function much as it does here.

# Get the conversations sorted (oldest first)
conversation_store = self._get_conversation_store(user_id)
conversations = await conversation_store.get_all_metadata(response_ids)
conversations.sort(key=_last_updated_at_key)
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Should this maybe happen inside the store, so that we can do it in SQL?

Copy link
Collaborator

Choose a reason for hiding this comment

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

The workflow here is thus:

  • We go to the App / Redis Cluster to see what is actually running at the current moment - rather than the data store.
  • This yields a number of ids. Given that we limit this to 3 per user by default, this is likely to be a small number - so I didn't feel the need to paginate this result - we should probably introduce a constraint on the max number of Ids you can pass in. (Like say, 100)
  • Given that we have already grabbed these results by id, there isn't really a reason to sort them in SQL like there would be with the search method - it doesn't yield a performance boost.
  • The SAAS implementation implements get_all_metadata as a single sql query.

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.

5 participants