Skip to content

feat: add /clear endpoint for V1 conversations#12786

Merged
hieptl merged 48 commits intoOpenHands:mainfrom
MkDev11:feature/v1-clear-command
Mar 19, 2026
Merged

feat: add /clear endpoint for V1 conversations#12786
hieptl merged 48 commits intoOpenHands:mainfrom
MkDev11:feature/v1-clear-command

Conversation

@MkDev11
Copy link
Copy Markdown
Contributor

@MkDev11 MkDev11 commented Feb 6, 2026

Summary

This PR refactors the /clear command for V1 conversations to use Option 4: New conversation ID, same runtime. Instead of deleting event files (which violated the append-only invariant), /clear now creates a brand new conversation that inherits the parent's sandbox and configuration. The old conversation is preserved and linked via parent_conversation_id.

What changed

Backend (app_conversation_router.py):

  • Rewrote the clear_conversation endpoint to call start_app_conversation with the current conversation as the parent
  • The endpoint fully awaits the new conversation's creation before returning, so the frontend can safely redirect to it
  • Returns the new conversation ID in hex format (no dashes) to match the URL convention used throughout the app

Frontend (chat-interface.tsx, v1-conversation-service.api.ts):

  • Added a clearConversation static method to V1ConversationService
  • When the user types /clear in a V1 conversation, the frontend calls the API, shows a success toast, and navigates to the new conversation using React Router

Infrastructure (deployment-related, not core feature):

  • docker_sandbox_service.py: CORS origins are now passed as indexed environment variables (OH_ALLOW_CORS_ORIGINS_0, _1, etc.) to agent server containers, supporting multiple allowed origins
  • websocket-url.ts: When accessing the frontend from an external IP, WebSocket URLs that point to localhost are rewritten to use the browser's hostname
  • middleware.py: Falls back to allowing all origins when no specific CORS origins are configured

Tests:

  • Updated existing unit tests for the new response format (hex IDs, app_conversation_id)
  • All 11 tests pass

How it works

  1. User types /clear in a V1 conversation
  2. Frontend calls POST /api/v1/app-conversations/{id}/clear
  3. Backend creates a new conversation with parent_conversation_id set to the old one — same sandbox, same agent config, same LLM model
  4. Backend waits for the conversation to be fully saved to the database, then returns the new conversation ID
  5. Frontend navigates to /conversations/{new_id} — fresh chat history, runtime state preserved

Demo Screenshots/Videos

Loom recording showing /clear working end-to-end

Change Type

  • Bug fix
  • New feature
  • Breaking change
  • Refactor
  • Other (dependency update, docs, typo fixes, etc.)

Checklist

  • I have read and reviewed the code and I understand what the code is doing.
  • I have tested the code to the best of my ability and ensured it works as expected.

Fixes

Resolves #12564

Release Notes

  • Include this change in the Release Notes.

Added /clear command for V1 conversations. Typing /clear in the chat creates a new conversation that inherits the current sandbox and configuration, giving you a fresh chat history while keeping your runtime state (files, packages, environment) intact.

@MkDev11
Copy link
Copy Markdown
Contributor Author

MkDev11 commented Feb 6, 2026

@enyst Just opened the PR for v1

Copy link
Copy Markdown
Collaborator

@all-hands-bot all-hands-bot left a comment

Choose a reason for hiding this comment

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

This PR adds a useful clear endpoint, but there are some important security and error handling concerns that should be addressed before merging.

Comment thread openhands/app_server/app_conversation/app_conversation_router.py Outdated
Comment thread openhands/app_server/app_conversation/app_conversation_router.py
Comment thread openhands/app_server/event/event_service_base.py Outdated
Comment thread openhands/app_server/event/event_service_base.py Outdated
@MkDev11
Copy link
Copy Markdown
Contributor Author

MkDev11 commented Feb 6, 2026

This PR adds a useful clear endpoint, but there are some important security and error handling concerns that should be addressed before merging.

Fixed all!

@MkDev11 MkDev11 requested a review from amanape as a code owner February 9, 2026 00:48
@MkDev11 MkDev11 requested a review from all-hands-bot February 9, 2026 05:50
Copy link
Copy Markdown
Collaborator

@all-hands-bot all-hands-bot left a comment

Choose a reason for hiding this comment

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

Overall solid implementation of the /clear command. Found several security and design concerns that should be addressed, particularly around CORS configuration and the contradictory clear_events implementation.

Comment thread openhands/server/middleware.py
Comment thread openhands/app_server/event/event_service_base.py Outdated
Comment thread openhands/app_server/app_conversation/app_conversation_router.py Outdated
Comment thread frontend/src/utils/websocket-url.ts
Comment thread openhands/app_server/sandbox/docker_sandbox_service.py
Comment thread frontend/src/components/features/chat/chat-interface.tsx Outdated
Comment thread openhands/app_server/app_conversation/app_conversation_router.py Outdated
Comment thread frontend/src/api/conversation-service/v1-conversation-service.api.ts Outdated
Comment thread tests/unit/app_server/test_app_conversation_router.py
Comment thread openhands/app_server/app_conversation/app_conversation_service.py Outdated
@MkDev11
Copy link
Copy Markdown
Contributor Author

MkDev11 commented Feb 9, 2026

@enyst hope you had a good weekend! could you please review the changes and let me know your feedback?

Copy link
Copy Markdown
Collaborator

@enyst enyst left a comment

Choose a reason for hiding this comment

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

Thank you for the work on this, @MkDev11 ! I started a discussion on it on slack.

hieptl
hieptl previously requested changes Feb 9, 2026
Copy link
Copy Markdown
Collaborator

@hieptl hieptl left a comment

Choose a reason for hiding this comment

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

Hello @MkDev11,

Thank you for creating this pull request — much appreciated. 🙏

I’ve left a few comments on the PR for your reference. Overall, I believe we should avoid creating a new conversation and instead clear the events of the current conversation.

@tofarr, I would greatly appreciate your feedback and guidance on this approach.

Additionally, could you please add some front-end tests to help cover the changes introduced here?

Thank you very much, and I appreciate your work on this! 🙏

Comment thread frontend/src/components/features/chat/chat-interface.tsx Outdated
Comment thread frontend/src/components/features/chat/chat-interface.tsx Outdated
Comment thread frontend/src/components/features/chat/chat-interface.tsx Outdated
Comment thread frontend/src/components/features/chat/chat-interface.tsx Outdated
Comment thread frontend/src/components/features/chat/chat-interface.tsx Outdated
Comment thread openhands/app_server/event/event_service_base.py Outdated
@MkDev11
Copy link
Copy Markdown
Contributor Author

MkDev11 commented Feb 9, 2026

Hello @MkDev11,

Thank you for creating this pull request — much appreciated. 🙏

I’ve left a few comments on the PR for your reference. Overall, I believe we should avoid creating a new conversation and instead clear the events of the current conversation.

@tofarr, I would greatly appreciate your feedback and guidance on this approach.

Additionally, could you please add some front-end tests to help cover the changes introduced here?

Thank you very much, and I appreciate your work on this! 🙏

The current approach (creating a new conversation with parent_conversation_id) was chosen to preserve the append-only event stream invariant. Deleting events from the agent-server side would break event replay, audit trails, and any downstream consumers that rely on event IDs being immutable. @tofarr — would appreciate your guidance on whether clearing events in-place on the agent-server side is preferred instead.

@MkDev11
Copy link
Copy Markdown
Contributor Author

MkDev11 commented Feb 9, 2026

@hieptl could you please have a look at the changes again?

Comment thread openhands/app_server/sandbox/docker_sandbox_service.py Outdated
@MkDev11
Copy link
Copy Markdown
Contributor Author

MkDev11 commented Feb 18, 2026

@tofarr thanks for your feedback. could you please review again?

Copy link
Copy Markdown
Collaborator

@tofarr tofarr left a comment

Choose a reason for hiding this comment

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

This is some great work - thank you for taking this on. I've left a few comments, and will review again if you have any questions or changes.

Comment thread openhands/app_server/sandbox/docker_sandbox_service.py Outdated
Comment thread openhands/app_server/app_conversation/app_conversation_router.py
Comment thread openhands/app_server/app_conversation/app_conversation_router.py Outdated
@MkDev11 MkDev11 requested a review from tofarr February 18, 2026 10:20
@MkDev11
Copy link
Copy Markdown
Contributor Author

MkDev11 commented Feb 18, 2026

@tofarr fixed all the comments.

Comment thread openhands/app_server/app_conversation/app_conversation_router.py Outdated
Comment thread openhands/app_server/app_conversation/app_conversation_router.py Outdated
@MkDev11 MkDev11 force-pushed the feature/v1-clear-command branch from 094642a to 84f2393 Compare February 19, 2026 14:28
@MkDev11 MkDev11 requested a review from tofarr February 19, 2026 14:44
@hieptl
Copy link
Copy Markdown
Collaborator

hieptl commented Feb 25, 2026

Hello @MkDev11,

Could you please add tests to cover your front-end changes when you have a chance?

In addition, I ran the pull request locally and noticed a few issues.

Issue 1:
After using the /clear command, the previous conversations are still displayed in the conversation list. Please refer to the video below for more details.

issue1.mov

Issue 2:
It’s still possible to access the old conversations after using /clear. It appears that these conversations are not deleted and remain accessible. Please see the video below for reference.

issue2.mov

Issue 3:

  • Step 1: Create a new conversation.
  • Step 2: Send a simple message (e.g., “Hello”).
  • Step 3: Use the /clear command.
  • Step 4: Send another message in the new conversation (e.g., “Who are you?”).
  • Step 5: While the new conversation’s title is updated, the title shown in the conversation list is not updated accordingly.

Please refer to the video below for more information.

issue3.mov

Issue 4:
There appears to be a noticeable delay after sending the /clear command. In cases where the WebSocket connection is interrupted or there are network issues, this could lead to a suboptimal user experience. The video below provides additional context.

issue5.mov

Thank you very much! 🙏

@MkDev11
Copy link
Copy Markdown
Contributor Author

MkDev11 commented Feb 26, 2026

@hieptl fixed the issues you mentioned. please review again

@hieptl
Copy link
Copy Markdown
Collaborator

hieptl commented Mar 2, 2026

Hello @MkDev11,

I noticed the issue below while running the code locally. Please feel free to refer to the video below for additional details and context.

issue.mov

Thank you very much! 🙏

@MkDev11 MkDev11 force-pushed the feature/v1-clear-command branch from d0c9c53 to b5f9831 Compare March 2, 2026 13:43
@enyst
Copy link
Copy Markdown
Collaborator

enyst commented Mar 9, 2026

I think maybe it makes a lot of sense, and it would be expected, that the "application control commands" executed on slash /command would be in the menu.

By control commands, I mean those that are not skills. This one is not a skill, it's pure python implementation of a control command. (Of course, we include skills too, those look like slash commands and will be interpreted by the agent as commands for itself; I'm just saying this one is not an agent thing, it's an application thing)

Though I'd add a thought, they make sense to me at the start of the line... like a CLI command.

Could be in a future PR, I suppose? I'm not sure if other control commands are in the slash menu currently.

However, since these conversations share the same runtime, clicking “Close Conversation (Stop Runtime)” will stop the runtime for all of them. I’m not certain whether this behavior is intended.

You're right, that's clearly the case...

We could do as you suggest:

Conversation cleared. Starting a new conversation in the same sandbox. These conversations will share the same runtime.

Would it make sense to rename the command from /clear to /new? This might better reflect the behavior of starting a new conversation.

Yes. I believe we should, it would be inline with what it does, and easier to understand for users coming from other agentic applications.

@MkDev11
Copy link
Copy Markdown
Contributor Author

MkDev11 commented Mar 10, 2026

@tofarr @hieptl do you want me to rename /clear->/new, update toast message, add cursor-not-allowed, add to slash menu?

@hieptl
Copy link
Copy Markdown
Collaborator

hieptl commented Mar 12, 2026

Hello @MkDev11,

As Engel mentioned:

  • Adding this command to the slash command menu can be included in a future pull request.
  • The toast message needs to be updated.
  • The command should be changed from /clear to /new.

Additionally, based on the two issues I noted in my previous comment, both will need to be addressed.

Thank you very much! 🙏

…-allowed, fix cross-conversation change sync

- Rename /clear command to /new in chat-interface.tsx
- Update i18n translations to reflect /new command wording
- Update toast success message to clarify shared runtime
- Add cursor-not-allowed and opacity-50 to disabled chat input
- Add refetchOnMount: 'always' to useUnifiedGetGitChanges so
  navigating between shared-sandbox conversations refetches git changes
@MkDev11
Copy link
Copy Markdown
Contributor Author

MkDev11 commented Mar 13, 2026

@tofarr @hieptl do you want me to rename /clear->/new, update toast message, add cursor-not-allowed, add to slash menu?

I refactored the implementation.

@hieptl
Copy link
Copy Markdown
Collaborator

hieptl commented Mar 13, 2026

Hello @MkDev11,

While testing your code locally, I came across a few issues that might be worth reviewing.

Issue 1:

  • Step 1: Create a new conversation.
  • Step 2: Send a simple message, such as “Hello, World.”
  • Step 3: Send /new to create another conversation.
  • Step 4: In the conversation panel (conversation list), switch to the newly created conversation.
  • Step 5: Send another message, such as “Hi.”
  • Step 6: Send /new again to create a third conversation. At this point, all three conversations share the same sandbox.
  • Step 7: Navigate back to the home page and delete one conversation. The remaining two conversations then appear to be archived.

For additional context, please refer to the video below.

issue1.mov

Issue 2:
When a new conversation is created and begins to start up, the chat input becomes disabled. This appears to be a regression. Ideally, the chat input should remain enabled so that users can type their messages while the conversation is initializing.

In one of my earlier comments, I suggested disabling the chat input only during the brief moment when a new conversation is being created after the user enters /new. However, it seems that the current implementation disables the chat input more broadly than intended.

For additional context, please refer to the video below.

issue2.mov

Thank you very much! 🙏

MkDev11 added 3 commits March 18, 2026 12:29
…rsations

When deleting a conversation that shares a sandbox with other conversations
(created via /new), skip the DELETE /api/conversations call to the agent
server. This prevents destabilizing the shared runtime, which would cause
remaining conversations to appear as ARCHIVED.

- Add skip_agent_server_delete param to delete_app_conversation
- Check count_conversations_by_sandbox_id before deletion
- Pass skip flag when sandbox is shared (count > 1)
- Re-check remaining count after deletion before sandbox cleanup
Thread a separate inputLocked prop through the component chain so that
ChatInputField is only locked (contentEditable=false, cursor-not-allowed)
during /new command processing, not during AgentState.LOADING.

- Add inputLocked prop to CustomChatInput, ChatInputContainer, ChatInputRow
- ChatInputRow passes inputLocked (not disabled) to ChatInputField
- disabled still controls send button, file button, and Enter submission
- ChatInputField only gets disabled=true during /new (isClearingConversation)

This fixes the regression where typing was blocked during conversation
startup, while preserving cursor-not-allowed feedback during /new.
…mmand

# Conflicts:
#	frontend/src/components/features/chat/interactive-chat-box.tsx
#	frontend/src/i18n/declaration.ts
#	frontend/src/i18n/translation.json
#	openhands/server/routes/manage_conversations.py
@MkDev11
Copy link
Copy Markdown
Contributor Author

MkDev11 commented Mar 18, 2026

@hieptl I fixed the issues you mentioend. can you review the change?

@MkDev11
Copy link
Copy Markdown
Contributor Author

MkDev11 commented Mar 19, 2026

@hieptl do you have any feedbacK?

@MkDev11
Copy link
Copy Markdown
Contributor Author

MkDev11 commented Mar 19, 2026

@hieptl just fixed the lint error

Copy link
Copy Markdown
Collaborator

@hieptl hieptl left a comment

Choose a reason for hiding this comment

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

Hello @MkDev11,

For the front-end changes, it looks like the current updates focus on adding tests for use-clear-conversation. It would be helpful to also include tests that cover the changes made in the component files. There’s no need to add tests specifically for styling.

Thank you! 🙏

Comment thread frontend/__tests__/hooks/use-websocket.test.ts Outdated
Comment thread frontend/src/components/features/chat/components/chat-input-row.tsx Outdated
Comment thread frontend/src/components/features/chat/components/chat-input-field.tsx Outdated
Comment thread frontend/src/hooks/mutation/use-new-conversation-command.ts
Comment thread openhands/server/middleware.py Outdated
MkDev11 added 2 commits March 19, 2026 14:34
- Fix flaky WebSocket onClose test (reset spy after connection instead of skipping)
- Rename inputLocked → isNewConversationPending for clarity
- Use cn() instead of template string in chat-input-field.tsx
- Rename use-clear-conversation → use-new-conversation-command (file, hook, tests)
- Move get_global_config import to top of middleware.py
- Add component tests for disabled input field behavior
@MkDev11 MkDev11 requested a review from hieptl March 19, 2026 13:59
@MkDev11
Copy link
Copy Markdown
Contributor Author

MkDev11 commented Mar 19, 2026

all of your comments are addressed, could you please review again?

@hieptl hieptl dismissed their stale review March 19, 2026 14:13

The changes look good to me. Thank you very much!

Copy link
Copy Markdown
Collaborator

@hieptl hieptl left a comment

Choose a reason for hiding this comment

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

Thank you! 🙏

@hieptl hieptl merged commit 0ec962e into OpenHands:main Mar 19, 2026
43 checks passed
@MkDev11
Copy link
Copy Markdown
Contributor Author

MkDev11 commented Mar 19, 2026

thanks for your help!

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

Labels

release:cloud-1.18.0 Released in Cloud 1.18.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature: /new command to reset conversation history while keeping runtime alive

7 participants