@@ -91,12 +91,19 @@ def get_session_mode_state(current_mode: ConfirmationMode) -> SessionModeState:
9191class OpenHandsACPAgent (ACPAgent ):
9292 """OpenHands Agent Client Protocol implementation."""
9393
94- def __init__ (self , conn : Client , initial_confirmation_mode : ConfirmationMode ):
94+ def __init__ (
95+ self ,
96+ conn : Client ,
97+ initial_confirmation_mode : ConfirmationMode ,
98+ resume_conversation_id : str | None = None ,
99+ ):
95100 """Initialize the OpenHands ACP agent.
96101
97102 Args:
98103 conn: ACP connection for sending notifications
99104 initial_confirmation_mode: Default confirmation mode for new sessions
105+ resume_conversation_id: Optional conversation ID to resume when a new
106+ session is created (used with --resume flag)
100107 """
101108 self ._conn = conn
102109 # Cache of active conversations to preserve state (pause, confirmation, etc.)
@@ -106,10 +113,14 @@ def __init__(self, conn: Client, initial_confirmation_mode: ConfirmationMode):
106113 self ._running_tasks : dict [str , asyncio .Task ] = {}
107114 # Default confirmation mode for new sessions
108115 self ._initial_confirmation_mode : ConfirmationMode = initial_confirmation_mode
116+ # Conversation ID to resume (from --resume flag)
117+ self ._resume_conversation_id : str | None = resume_conversation_id
109118 logger .info (
110119 f"OpenHands ACP Agent initialized with "
111120 f"confirmation mode: { initial_confirmation_mode } "
112121 )
122+ if resume_conversation_id :
123+ logger .info (f"Will resume conversation: { resume_conversation_id } " )
113124
114125 async def _cmd_confirm (self , session_id : str , argument : str ) -> str :
115126 """Handle /confirm command.
@@ -362,8 +373,22 @@ async def new_session(
362373 mcp_servers : list [Any ],
363374 ** _kwargs : Any ,
364375 ) -> NewSessionResponse :
365- """Create a new conversation session."""
366- session_id = str (uuid .uuid4 ())
376+ """Create a new conversation session.
377+
378+ If --resume was used when starting the ACP server, the first new_session
379+ call will use the specified conversation ID instead of generating a new one.
380+ When resuming, historic events are replayed to the client.
381+ """
382+ # Use resume_conversation_id if provided (from --resume flag)
383+ # Only use it once, then clear it
384+ is_resuming = False
385+ if self ._resume_conversation_id :
386+ session_id = self ._resume_conversation_id
387+ self ._resume_conversation_id = None
388+ is_resuming = True
389+ logger .info (f"Resuming conversation: { session_id } " )
390+ else :
391+ session_id = str (uuid .uuid4 ())
367392
368393 try :
369394 # Convert ACP MCP servers to Agent format
@@ -377,7 +402,7 @@ async def new_session(
377402
378403 # Create conversation and cache it for future operations
379404 # This reuses the same pattern as openhands --resume
380- _ = self ._get_or_create_conversation (
405+ conversation = self ._get_or_create_conversation (
381406 session_id = session_id ,
382407 working_dir = working_dir ,
383408 mcp_servers = mcp_servers_dict ,
@@ -389,15 +414,27 @@ async def new_session(
389414 await self ._send_available_commands (session_id )
390415
391416 # Get current confirmation mode for this session
392- conversation = self ._active_sessions [session_id ]
393417 current_mode = get_confirmation_mode_from_conversation (conversation )
394418
395- # Return response with modes
396- return NewSessionResponse (
419+ # Build response first (before streaming events)
420+ response = NewSessionResponse (
397421 session_id = session_id ,
398422 modes = get_session_mode_state (current_mode ),
399423 )
400424
425+ # If resuming, replay historic events to the client
426+ # This ensures the ACP client sees the full conversation history
427+ if is_resuming and conversation .state .events :
428+ logger .info (
429+ f"Replaying { len (conversation .state .events )} historic events "
430+ f"for resumed session { session_id } "
431+ )
432+ subscriber = EventSubscriber (session_id , self ._conn )
433+ for event in conversation .state .events :
434+ await subscriber (event )
435+
436+ return response
437+
401438 except MissingAgentSpec as e :
402439 logger .error (f"Agent not configured: { e } " )
403440 raise RequestError .internal_error (
@@ -695,21 +732,28 @@ async def ext_notification(self, method: str, params: dict[str, Any]) -> None:
695732
696733async def run_acp_server (
697734 initial_confirmation_mode : ConfirmationMode = "always-ask" ,
735+ resume_conversation_id : str | None = None ,
698736) -> None :
699737 """Run the OpenHands ACP server.
700738
701739 Args:
702740 initial_confirmation_mode: Default confirmation mode for new sessions
741+ resume_conversation_id: Optional conversation ID to resume when a new
742+ session is created
703743 """
704744 logger .info (
705745 f"Starting OpenHands ACP server with confirmation mode: "
706746 f"{ initial_confirmation_mode } ..."
707747 )
748+ if resume_conversation_id :
749+ logger .info (f"Will resume conversation: { resume_conversation_id } " )
708750
709751 reader , writer = await stdio_streams ()
710752
711753 def create_agent (conn : Client ) -> OpenHandsACPAgent :
712- return OpenHandsACPAgent (conn , initial_confirmation_mode )
754+ return OpenHandsACPAgent (
755+ conn , initial_confirmation_mode , resume_conversation_id
756+ )
713757
714758 AgentSideConnection (create_agent , writer , reader )
715759
0 commit comments