An external process owns ComputerSandbox.create() and calls the daemon for each model turn. | An async owner creates the desktop once and sends a versioned ComputerSessionHandle to an application-owned Modal Function. | Move the model trajectory into the Function. Keep provider SDK imports and model calls in application code. |
| Each operation creates or attaches to its own desktop or client context. | The Function enters handle.borrow_async() once for the complete trajectory. | Hoist the borrow outside the model-turn loop. Release it after the trajectory ends. |
| Placement may be absent or broad. | Primary AsyncComputerSandbox.create() requires an explicit Modal environment and a supported narrow or Workspace-granted granular selector. | Declare the same selector for the owner, Function, and borrow_async(). Use create_unplaced() only for an intentional low-level path without handoff. |
Inline screenshots rely on Screenshot.data_base64. | The semantic screenshots.full() method uses binary HTTP internally and returns a byte-backed Screenshot. | Read as_bytes() or call to_base64() at a provider boundary. Do not assume data_base64 is populated. |
A model loop calls actions.run() and then screenshots.full(). | computer.step() sends the ordered action array and returns its immediate post-action frame. | Send one ordered array per step and use ComputerStepResult.screenshot for the next model turn. |
| Cleanup relies only on the outer owner context. | The borrowed client and lease close before the owner terminates the desktop. | Keep the owner alive until the Function reaches a terminal result, including cancellation cleanup. |
| Resource and warm-capacity choices are implicit. | Region, CPU, memory, image, timeouts, retries, scaling limits, and capacity are explicit and inspectable. | Select each cost-bearing value. Keep Function and Sandbox warm capacity at zero unless you intentionally pay for it. |