@@ -349,6 +349,50 @@ negotiate RPC protocol v2 to preserve structured text/image tool results.
349349 enable those receipts without rewriting user settings. Missing or failed
350350 receipts fail startup rather than allowing a model to answer without its
351351 required tools. The enclosing turn timeout still bounds startup.
352+ - ** Per-connection MCP servers.** Pass the constructor callable
353+ ` resolve_mcp_servers ` , an async ` (workspace: str) -> Mapping[str, OmpMcpServer] ` ,
354+ when external servers (or their credentials) can change while the adapter runs.
355+ It is called once for each new room process, with the room's claimed workspace,
356+ before the overlay or process exists; the same result feeds both the overlay and
357+ the startup receipt check. Its result is the room's complete ** external** server
358+ set: it replaces every external entry in ` mcp_servers ` (an empty mapping means
359+ none), and an exception fails that startup with no fallback to them. A ` band `
360+ entry in ` mcp_servers ` is the SDK's own Band endpoint, not an external server: it
361+ is kept beside the resolved set, so Band tools still route through it with
362+ ` inject_band_tools=False ` . The resolver itself may not return ` band ` , because OMP
363+ would mint that server's tools under Band tool names. A reused room process never
364+ calls it again; a retired room (cancellation, failure, or cleanup) resolves afresh
365+ on its next start. The callable is runtime-only and never part of
366+ ` OmpAdapterConfig ` .
367+ - ** Room retirement.** ` on_cleanup ` starts one retirement per room, and overlapping
368+ ` on_cleanup ` and ` cleanup_all ` calls join it. The room's active turn is the
369+ current ` on_message ` call, not the task that made it. A cancellation already
370+ requested when that call starts is delivered at its first step, before anything
371+ is resolved or launched; one its caller had already received and handled does
372+ not stop it. Retirement marks the active turn retired, so nothing it resolves
373+ afterwards can start a process. While the turn is still running, retirement
374+ becomes the cause of its end: it disarms the turn deadline if that has not fired,
375+ so the deadline cannot cancel the turn's settlement again, and cancels the turn
376+ once, or joins a cancellation it is already handling. A turn whose deadline has
377+ fired, or that is already handling its own outcome, keeps its timeout or other
378+ result and its failure report. A fired deadline counts as that cancellation even
379+ if the resolver consumed it with ` uncancel() ` : cleanup joins it rather than
380+ cancelling again, and a server set the resolver returns afterwards is refused, so
381+ the turn ends with ` TimeoutError ` and nothing is launched. A turn that has already
382+ finished is never
383+ cancelled, so its caller's later work is untouched. Retirement then waits for
384+ that call's own finalization (not for the rest of its caller's work), and only
385+ then closes the process and releases the workspace. A turn may request cleanup of
386+ its own room, for example from its resolver: that call returns at once, the turn
387+ is not cancelled again but its unfired deadline is disarmed all the same, it stops
388+ before launching, and teardown follows its settlement. Cancelling a cleanup
389+ call stops only that caller's wait. Until the retirement ends, turns already
390+ waiting for the room and turns that arrive during it are cancelled rather than
391+ starting a new process. A later turn starts normally. A room whose native close
392+ fails keeps its process handle, overlay and exclusive workspace claim until a
393+ later close succeeds: ` on_cleanup ` raises the failure, ` cleanup_all ` and the
394+ room's next turn retry the close first, and the retiring process never receives
395+ new work.
352396- ** Permissions.** ` approval_mode="yolo" ` bypasses native approval checks without
353397 changing Band platform permissions. Otherwise ` resolve_permission ` receives
354398 ` OmpPermissionRequest(room_id, session_id, title, options) ` and returns an
0 commit comments