modal 1.6.1.dev1__tar.gz → 1.6.1.dev3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (241) hide show
  1. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/PKG-INFO +3 -3
  2. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_environments.py +2 -1
  3. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_output/status.py +1 -3
  4. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_server.py +34 -9
  5. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_server.pyi +18 -1
  6. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/cli/function.py +5 -3
  7. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/cli/server.py +5 -4
  8. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/client.pyi +2 -2
  9. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/config.py +14 -6
  10. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/object.pyi +0 -2
  11. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/sandbox.py +23 -6
  12. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/sandbox.pyi +9 -0
  13. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/skills/modal/SKILL.md +19 -24
  14. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/types.py +4 -0
  15. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/volume.py +4 -0
  16. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/volume.pyi +12 -0
  17. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal.egg-info/PKG-INFO +3 -3
  18. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal.egg-info/requires.txt +2 -2
  19. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal_proto/api_pb2.py +1383 -1373
  20. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal_proto/api_pb2.pyi +64 -8
  21. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal_proto/task_command_router_pb2.py +96 -96
  22. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal_proto/task_command_router_pb2.pyi +12 -2
  23. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal_version/__init__.py +1 -1
  24. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/pyproject.toml +2 -2
  25. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/LICENSE +0 -0
  26. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/README.md +0 -0
  27. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/__init__.py +0 -0
  28. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/__main__.py +0 -0
  29. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_billing.py +0 -0
  30. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_cluster.py +0 -0
  31. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_cluster.pyi +0 -0
  32. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_container_entrypoint.py +0 -0
  33. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_function_variants.py +0 -0
  34. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_functions.py +0 -0
  35. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_grpc_client.py +0 -0
  36. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_image.py +0 -0
  37. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_ipython.py +0 -0
  38. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_load_context.py +0 -0
  39. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_location.py +0 -0
  40. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_logs.py +0 -0
  41. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_logs_manager.py +0 -0
  42. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_logs_manager.pyi +0 -0
  43. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_object.py +0 -0
  44. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_outbound_policy.py +0 -0
  45. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_outbound_policy.pyi +0 -0
  46. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_output/__init__.py +0 -0
  47. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_output/manager.py +0 -0
  48. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_output/pty.py +0 -0
  49. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_output/rich.py +0 -0
  50. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_partial_function.py +0 -0
  51. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_resolver.py +0 -0
  52. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_resources.py +0 -0
  53. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_runtime/__init__.py +0 -0
  54. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_runtime/asgi.py +0 -0
  55. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_runtime/container_io_manager.py +0 -0
  56. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_runtime/container_io_manager.pyi +0 -0
  57. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_runtime/execution_context.py +0 -0
  58. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_runtime/execution_context.pyi +0 -0
  59. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_runtime/gpu_memory_snapshot.py +0 -0
  60. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_runtime/task_lifecycle_manager.py +0 -0
  61. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_runtime/task_lifecycle_manager.pyi +0 -0
  62. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_runtime/telemetry.py +0 -0
  63. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_runtime/user_code_event_loop.py +0 -0
  64. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_runtime/user_code_imports.py +0 -0
  65. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_serialization.py +0 -0
  66. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_supports_logs.py +0 -0
  67. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_traceback.py +0 -0
  68. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_tunnel.py +0 -0
  69. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_tunnel.pyi +0 -0
  70. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_type_manager.py +0 -0
  71. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_utils/__init__.py +0 -0
  72. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_utils/app_utils.py +0 -0
  73. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_utils/async_utils.py +0 -0
  74. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_utils/auth_token_manager.py +0 -0
  75. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_utils/blob_utils.py +0 -0
  76. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_utils/browser_utils.py +0 -0
  77. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_utils/bytes_io_segment_payload.py +0 -0
  78. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_utils/curl_utils.py +0 -0
  79. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_utils/deprecation.py +0 -0
  80. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_utils/display_utils.py +0 -0
  81. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_utils/docker_utils.py +0 -0
  82. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_utils/function_utils.py +0 -0
  83. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_utils/git_utils.py +0 -0
  84. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_utils/grpc_testing.py +0 -0
  85. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_utils/grpc_utils.py +0 -0
  86. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_utils/hash_utils.py +0 -0
  87. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_utils/http_utils.py +0 -0
  88. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_utils/idle_countdown.py +0 -0
  89. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_utils/jwt_utils.py +0 -0
  90. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_utils/logger.py +0 -0
  91. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_utils/mount_utils.py +0 -0
  92. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_utils/name_utils.py +0 -0
  93. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_utils/package_utils.py +0 -0
  94. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_utils/pattern_utils.py +0 -0
  95. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_utils/proxy_support.py +0 -0
  96. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_utils/rand_pb_testing.py +0 -0
  97. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_utils/sandbox_fs_utils.py +0 -0
  98. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_utils/shell_utils.py +0 -0
  99. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_utils/task_command_router_client.py +0 -0
  100. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_utils/time_utils.py +0 -0
  101. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_vendor/__init__.py +0 -0
  102. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_vendor/a2wsgi_wsgi.py +0 -0
  103. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_vendor/cloudpickle.py +0 -0
  104. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_vendor/tblib.py +0 -0
  105. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_vendor/version.py +0 -0
  106. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_watcher.py +0 -0
  107. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/_workspace.py +0 -0
  108. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/app.py +0 -0
  109. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/app.pyi +0 -0
  110. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/billing.py +0 -0
  111. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/billing.pyi +0 -0
  112. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/builder/2023.12.312.txt +0 -0
  113. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/builder/2023.12.txt +0 -0
  114. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/builder/2024.04.txt +0 -0
  115. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/builder/2024.10.txt +0 -0
  116. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/builder/2025.06.txt +0 -0
  117. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/builder/PREVIEW.txt +0 -0
  118. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/builder/README.md +0 -0
  119. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/builder/base-images.json +0 -0
  120. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/call_graph.py +0 -0
  121. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/cli/__init__.py +0 -0
  122. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/cli/_download.py +0 -0
  123. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/cli/_help.py +0 -0
  124. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/cli/_logs.py +0 -0
  125. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/cli/_stats.py +0 -0
  126. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/cli/_traceback.py +0 -0
  127. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/cli/app.py +0 -0
  128. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/cli/billing.py +0 -0
  129. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/cli/changelog.py +0 -0
  130. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/cli/config.py +0 -0
  131. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/cli/container.py +0 -0
  132. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/cli/curl.py +0 -0
  133. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/cli/dashboard.py +0 -0
  134. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/cli/dict.py +0 -0
  135. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/cli/endpoint.py +0 -0
  136. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/cli/entry_point.py +0 -0
  137. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/cli/environment.py +0 -0
  138. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/cli/image.py +0 -0
  139. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/cli/import_refs.py +0 -0
  140. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/cli/logo.py +0 -0
  141. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/cli/network_file_system.py +0 -0
  142. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/cli/profile.py +0 -0
  143. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/cli/queues.py +0 -0
  144. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/cli/run.py +0 -0
  145. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/cli/secret.py +0 -0
  146. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/cli/selector.py +0 -0
  147. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/cli/shell.py +0 -0
  148. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/cli/skills.py +0 -0
  149. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/cli/token.py +0 -0
  150. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/cli/utils.py +0 -0
  151. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/cli/volume.py +0 -0
  152. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/cli/workspace.py +0 -0
  153. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/client.py +0 -0
  154. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/cloud_bucket_mount.py +0 -0
  155. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/cloud_bucket_mount.pyi +0 -0
  156. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/cls.py +0 -0
  157. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/cls.pyi +0 -0
  158. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/cluster.py +0 -0
  159. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/cluster.pyi +0 -0
  160. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/container_process.py +0 -0
  161. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/container_process.pyi +0 -0
  162. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/dict.py +0 -0
  163. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/dict.pyi +0 -0
  164. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/environments.py +0 -0
  165. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/environments.pyi +0 -0
  166. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/exception.py +0 -0
  167. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/experimental/__init__.py +0 -0
  168. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/experimental/_flash_container_entry.py +0 -0
  169. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/experimental/flash.py +0 -0
  170. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/experimental/flash.pyi +0 -0
  171. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/experimental/flash_server.py +0 -0
  172. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/experimental/flash_server.pyi +0 -0
  173. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/experimental/ipython.py +0 -0
  174. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/file_pattern_matcher.py +0 -0
  175. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/functions.py +0 -0
  176. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/functions.pyi +0 -0
  177. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/image.py +0 -0
  178. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/image.pyi +0 -0
  179. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/io_streams.py +0 -0
  180. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/io_streams.pyi +0 -0
  181. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/mount.py +0 -0
  182. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/mount.pyi +0 -0
  183. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/network_file_system.py +0 -0
  184. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/network_file_system.pyi +0 -0
  185. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/object.py +0 -0
  186. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/output.py +0 -0
  187. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/parallel_map.py +0 -0
  188. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/parallel_map.pyi +0 -0
  189. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/partial_function.py +0 -0
  190. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/partial_function.pyi +0 -0
  191. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/proxy.py +0 -0
  192. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/proxy.pyi +0 -0
  193. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/py.typed +0 -0
  194. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/queue.py +0 -0
  195. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/queue.pyi +0 -0
  196. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/retries.py +0 -0
  197. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/runner.py +0 -0
  198. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/runner.pyi +0 -0
  199. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/running_app.py +0 -0
  200. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/sandbox_fs.py +0 -0
  201. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/sandbox_fs.pyi +0 -0
  202. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/schedule.py +0 -0
  203. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/scheduler_placement.py +0 -0
  204. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/secret.py +0 -0
  205. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/secret.pyi +0 -0
  206. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/server.py +0 -0
  207. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/server.pyi +0 -0
  208. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/serving.py +0 -0
  209. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/serving.pyi +0 -0
  210. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/snapshot.py +0 -0
  211. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/snapshot.pyi +0 -0
  212. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/stream_type.py +0 -0
  213. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/token_flow.py +0 -0
  214. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/token_flow.pyi +0 -0
  215. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/workspace.py +0 -0
  216. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal/workspace.pyi +0 -0
  217. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal.egg-info/SOURCES.txt +0 -0
  218. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal.egg-info/dependency_links.txt +0 -0
  219. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal.egg-info/entry_points.txt +0 -0
  220. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal.egg-info/top_level.txt +0 -0
  221. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal_docs/__init__.py +0 -0
  222. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal_docs/gen_cli_docs.py +0 -0
  223. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal_docs/gen_cli_docs_main.py +0 -0
  224. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal_docs/gen_reference_docs.py +0 -0
  225. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal_docs/gen_reference_docs_main.py +0 -0
  226. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal_docs/mdmd/__init__.py +0 -0
  227. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal_docs/mdmd/mdmd.py +0 -0
  228. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal_docs/mdmd/signatures.py +0 -0
  229. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal_docs/mdmd/types.py +0 -0
  230. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal_docs/reference_intro.md +0 -0
  231. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal_proto/__init__.py +0 -0
  232. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal_proto/api_grpc.py +0 -0
  233. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal_proto/api_pb2_grpc.py +0 -0
  234. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal_proto/api_pb2_grpc.pyi +0 -0
  235. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal_proto/modal_api_grpc.py +0 -0
  236. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal_proto/py.typed +0 -0
  237. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal_proto/task_command_router_grpc.py +0 -0
  238. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal_proto/task_command_router_pb2_grpc.py +0 -0
  239. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal_proto/task_command_router_pb2_grpc.pyi +0 -0
  240. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/modal_version/__main__.py +0 -0
  241. {modal-1.6.1.dev1 → modal-1.6.1.dev3}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modal
3
- Version: 1.6.1.dev1
3
+ Version: 1.6.1.dev3
4
4
  Summary: Python client library for Modal
5
5
  Author-email: Modal Labs <support@modal.com>
6
6
  License-Expression: Apache-2.0
@@ -21,9 +21,9 @@ Requires-Dist: certifi
21
21
  Requires-Dist: click~=8.1
22
22
  Requires-Dist: grpclib<0.4.10,>=0.4.7; python_version < "3.14"
23
23
  Requires-Dist: grpclib<0.4.10,>=0.4.9; python_version >= "3.14"
24
- Requires-Dist: protobuf!=4.24.0,<7.0,>=3.19
24
+ Requires-Dist: protobuf!=4.24.0,<8.0,>=3.19
25
25
  Requires-Dist: rich>=12.0.0
26
- Requires-Dist: synchronicity~=0.12.5
26
+ Requires-Dist: synchronicity~=0.12.6
27
27
  Requires-Dist: toml
28
28
  Requires-Dist: types-certifi
29
29
  Requires-Dist: types-toml
@@ -22,7 +22,7 @@ from ._utils.time_utils import is_utc_month_aligned, parse_billing_cycle
22
22
  from .client import _Client
23
23
  from .config import config, logger
24
24
  from .exception import InvalidError, WorkspaceManagementError
25
- from .types import BillingReportItem, EnvironmentBillingSummary
25
+ from .types import AppInfo, BillingReportItem, EnvironmentBillingSummary
26
26
 
27
27
  if TYPE_CHECKING:
28
28
  import modal
@@ -346,6 +346,7 @@ class _EnvironmentAppsManager:
346
346
  self._environment.name,
347
347
  self._environment.client,
348
348
  description=item.description or None,
349
+ info=AppInfo._from_proto(item.metadata, item.app_id),
349
350
  )
350
351
  for item in response.apps
351
352
  if item.state not in stopped_app_states
@@ -13,9 +13,7 @@ from .manager import OutputManager
13
13
 
14
14
 
15
15
  def _get_annotation_for_web_url(url_info: api_pb2.WebUrlInfo) -> str:
16
- if url_info.truncated:
17
- suffix = " [grey70](label truncated)[/grey70]"
18
- elif url_info.label_stolen:
16
+ if url_info.label_stolen:
19
17
  suffix = " [grey70](label stolen)[/grey70]"
20
18
  else:
21
19
  suffix = ""
@@ -1,7 +1,10 @@
1
1
  # Copyright Modal Labs 2025
2
+ import asyncio
2
3
  import inspect
3
4
  import json
5
+ import time
4
6
  import typing
7
+ import uuid
5
8
  from datetime import datetime, timedelta, timezone
6
9
 
7
10
  from typing_extensions import Self
@@ -477,9 +480,8 @@ class _Server:
477
480
  return ServerStats._from_proto(stats)
478
481
 
479
482
 
480
- @retry(n_attempts=5, base_delay=0.5, attempt_timeout=65, total_timeout=200)
481
483
  async def _post_session_control(url: str, headers: dict[str, str]) -> tuple[int, str, str]:
482
- """POST to a sticky session control endpoint, retrying connection errors and 5xx. Returns (status, reason, body)."""
484
+ """POST to a sticky session control endpoint, raising on 5xx."""
483
485
  async with ClientSessionRegistry.get_session().post(url, headers=headers) as resp:
484
486
  body = await resp.text()
485
487
  if resp.status >= 400:
@@ -489,6 +491,28 @@ async def _post_session_control(url: str, headers: dict[str, str]) -> tuple[int,
489
491
  return resp.status, resp.reason or "", body
490
492
 
491
493
 
494
+ async def _post_session_start(base_url: str, fn: _Function, idle_timeout: int) -> tuple[int, str, str]:
495
+ idempotency_key = str(uuid.uuid4())
496
+ start_timestamp = str(time.time())
497
+
498
+ @retry(n_attempts=5, base_delay=0.5, attempt_timeout=None, total_timeout=1515)
499
+ async def attempt() -> tuple[int, str, str]:
500
+ headers = {
501
+ "Modal-Authorization": f"Bearer {await fn._get_flash_auth_token()}",
502
+ "x-idempotency-key": idempotency_key,
503
+ "x-modal-timestamp": start_timestamp,
504
+ "x-modal-server-session-idle-timeout": str(idle_timeout),
505
+ }
506
+ return await _post_session_control(f"{base_url}/_modal/sessions/start", headers)
507
+
508
+ return await attempt()
509
+
510
+
511
+ @retry(n_attempts=3, base_delay=0.5, attempt_timeout=None, total_timeout=60)
512
+ async def _post_session_terminate(base_url: str, headers: dict[str, str]) -> tuple[int, str, str]:
513
+ return await _post_session_control(f"{base_url}/_modal/sessions/terminate", headers)
514
+
515
+
492
516
  class _ServerSessionsManager:
493
517
  """mdmd:namespace"""
494
518
 
@@ -507,6 +531,10 @@ class _ServerSessionsManager:
507
531
  session has had no connections for `idle_timeout` seconds or is terminated. A container won't be scaled down
508
532
  for as long as it holds a live session.
509
533
 
534
+ If no container has room for the session, the call waits for additional capacity. It will block for
535
+ up to 25 minutes before giving up. To control the wait per call, use the HTTP API and apply your own retry
536
+ policy.
537
+
510
538
  Args:
511
539
  idle_timeout: Seconds without an in-flight request before the session ends.
512
540
 
@@ -531,13 +559,10 @@ class _ServerSessionsManager:
531
559
  self._validate()
532
560
  assert url is not None, "Server has no URL."
533
561
 
534
- headers = {
535
- "Modal-Authorization": f"Bearer {await fn._get_flash_auth_token()}",
536
- "x-modal-server-session-idle-timeout": str(idle_timeout),
537
- }
538
-
539
562
  try:
540
- status, reason, body = await _post_session_control(f"{url}/_modal/sessions/start", headers)
563
+ status, reason, body = await _post_session_start(url, fn, idle_timeout)
564
+ except asyncio.TimeoutError:
565
+ raise asyncio.TimeoutError("Failed to start session: timed out") from None
541
566
  except ServiceError as exc:
542
567
  raise ExecutionError(f"Failed to start session: {exc}") from None
543
568
  if status >= 400:
@@ -576,7 +601,7 @@ class _ServerSessionsManager:
576
601
  "x-modal-server-session-token": token,
577
602
  }
578
603
  try:
579
- status, reason, _body = await _post_session_control(f"{url}/_modal/sessions/terminate", headers)
604
+ status, reason, _body = await _post_session_terminate(url, headers)
580
605
  except ServiceError as exc:
581
606
  raise ExecutionError(f"Failed to terminate session: {exc}") from None
582
607
  if status == 404:
@@ -272,9 +272,14 @@ class _Server:
272
272
  ...
273
273
 
274
274
  async def _post_session_control(url: str, headers: dict[str, str]) -> tuple[int, str, str]:
275
- """POST to a sticky session control endpoint, retrying connection errors and 5xx. Returns (status, reason, body)."""
275
+ """POST to a sticky session control endpoint, raising on 5xx."""
276
276
  ...
277
277
 
278
+ async def _post_session_start(
279
+ base_url: str, fn: modal._functions._Function, idle_timeout: int
280
+ ) -> tuple[int, str, str]: ...
281
+ async def _post_session_terminate(base_url: str, headers: dict[str, str]) -> tuple[int, str, str]: ...
282
+
278
283
  class _ServerSessionsManager:
279
284
  """mdmd:namespace"""
280
285
  def __init__(self, server: _Server):
@@ -289,6 +294,10 @@ class _ServerSessionsManager:
289
294
  session has had no connections for `idle_timeout` seconds or is terminated. A container won't be scaled down
290
295
  for as long as it holds a live session.
291
296
 
297
+ If no container has room for the session, the call waits for additional capacity. It will block for
298
+ up to 25 minutes before giving up. To control the wait per call, use the HTTP API and apply your own retry
299
+ policy.
300
+
292
301
  Args:
293
302
  idle_timeout: Seconds without an in-flight request before the session ends.
294
303
 
@@ -342,6 +351,10 @@ class ServerSessionsManager:
342
351
  session has had no connections for `idle_timeout` seconds or is terminated. A container won't be scaled down
343
352
  for as long as it holds a live session.
344
353
 
354
+ If no container has room for the session, the call waits for additional capacity. It will block for
355
+ up to 25 minutes before giving up. To control the wait per call, use the HTTP API and apply your own retry
356
+ policy.
357
+
345
358
  Args:
346
359
  idle_timeout: Seconds without an in-flight request before the session ends.
347
360
 
@@ -367,6 +380,10 @@ class ServerSessionsManager:
367
380
  session has had no connections for `idle_timeout` seconds or is terminated. A container won't be scaled down
368
381
  for as long as it holds a live session.
369
382
 
383
+ If no container has room for the session, the call waits for additional capacity. It will block for
384
+ up to 25 minutes before giving up. To control the wait per call, use the HTTP API and apply your own retry
385
+ policy.
386
+
370
387
  Args:
371
388
  idle_timeout: Seconds without an in-flight request before the session ends.
372
389
 
@@ -112,6 +112,7 @@ def _time_range_stats_json(response: api_pb2.FunctionGetTimeRangeStatsResponse)
112
112
  "input_percentile_stats": _distribution_map_json(
113
113
  cast(dict[str, api_pb2.StatsPercentileDistribution], response.input_percentile_stats)
114
114
  ),
115
+ "container_total_count": response.container_total_count,
115
116
  "container_started_count": response.container_started_count,
116
117
  "container_error_count": response.container_error_count,
117
118
  "container_creating_at_end_count": response.container_creating_at_end_count,
@@ -794,9 +795,10 @@ async def stats(
794
795
 
795
796
  output.print("")
796
797
  container_count = resp.container_started_count + resp.container_error_count
798
+ total_containers = resp.container_total_count
797
799
  container_heading = Text("Containers", style=stats_style(STATS_SECTION_STYLE, use_color))
798
800
  container_heading.append(" " * (46 - len("Containers")))
799
- container_heading.append(f"{container_count:,} total (")
801
+ container_heading.append(f"{total_containers:,} Total (")
800
802
  container_heading.append(
801
803
  f"{resp.container_creating_at_end_count:,} creating",
802
804
  style=progress_style(resp.container_creating_at_end_count, use_color),
@@ -806,12 +808,12 @@ async def stats(
806
808
 
807
809
  container_counts = Text(" ")
808
810
  container_counts.append(
809
- _count_with_percentage(resp.container_started_count, container_count, "started"),
811
+ f"{resp.container_started_count:,} started",
810
812
  style=success_style(resp.container_started_count, container_count, use_color),
811
813
  )
812
814
  container_counts.append(" · ")
813
815
  container_counts.append(
814
- _count_with_percentage(resp.container_error_count, container_count, "errored"),
816
+ f"{resp.container_error_count:,} errored",
815
817
  style=problem_style(resp.container_error_count, container_count, use_color),
816
818
  )
817
819
  output.print(container_counts)
@@ -33,7 +33,6 @@ from ._stats import (
33
33
  STATS_METADATA_STYLE,
34
34
  STATS_PROBLEM_STYLE,
35
35
  STATS_SECTION_STYLE,
36
- _count_with_percentage,
37
36
  _distribution_map_json,
38
37
  _metric_rows,
39
38
  _percentile_table,
@@ -560,6 +559,7 @@ def _stats_json(
560
559
  "request_rate_per_second": history.request_rate_per_second,
561
560
  "container_started_count": history.container_started_count,
562
561
  "container_error_count": history.container_error_count,
562
+ "container_total_count": history.container_total_count,
563
563
  "container_creating_at_end_count": history.container_creating_at_end_count,
564
564
  "request_percentile_stats": _distribution_map_json(
565
565
  cast(dict[str, api_pb2.StatsPercentileDistribution], history.request_percentile_stats)
@@ -754,9 +754,10 @@ async def _run_server_stats(
754
754
 
755
755
  output.print("")
756
756
  container_count = history.container_started_count + history.container_error_count
757
+ container_total_count = history.container_total_count
757
758
  container_heading = Text("Containers", style=stats_style(STATS_SECTION_STYLE, use_color))
758
759
  container_heading.append(" " * (46 - len("Containers")))
759
- container_heading.append(f"{container_count:,} total (")
760
+ container_heading.append(f"{container_total_count:,} Total (")
760
761
  container_heading.append(
761
762
  f"{history.container_creating_at_end_count:,} creating",
762
763
  style=progress_style(history.container_creating_at_end_count, use_color),
@@ -766,12 +767,12 @@ async def _run_server_stats(
766
767
 
767
768
  container_counts = Text(" ")
768
769
  container_counts.append(
769
- _count_with_percentage(history.container_started_count, container_count, "started"),
770
+ f"{history.container_started_count:,} started",
770
771
  style=success_style(history.container_started_count, container_count, use_color),
771
772
  )
772
773
  container_counts.append(" · ")
773
774
  container_counts.append(
774
- _count_with_percentage(history.container_error_count, container_count, "errored"),
775
+ f"{history.container_error_count:,} errored",
775
776
  style=problem_style(history.container_error_count, container_count, use_color),
776
777
  )
777
778
  output.print(container_counts)
@@ -80,7 +80,7 @@ class _Client:
80
80
  server_url: str,
81
81
  client_type: int,
82
82
  credentials: typing.Optional[tuple[str, str]],
83
- version: str = "1.6.1.dev1",
83
+ version: str = "1.6.1.dev3",
84
84
  *,
85
85
  oauth_credentials: typing.Optional[_OAuthCredentials] = None,
86
86
  ):
@@ -290,7 +290,7 @@ class Client:
290
290
  server_url: str,
291
291
  client_type: int,
292
292
  credentials: typing.Optional[tuple[str, str]],
293
- version: str = "1.6.1.dev1",
293
+ version: str = "1.6.1.dev3",
294
294
  *,
295
295
  oauth_credentials: typing.Optional[_OAuthCredentials] = None,
296
296
  ):
@@ -134,13 +134,9 @@ def _agent_environment() -> str | None:
134
134
 
135
135
  Returns the agent name if detected, or None otherwise.
136
136
 
137
- Checks the emerging `AGENT` standard variable first, then falls back to
138
- tool-specific environment variables used by known agent harnesses.
137
+ Checks tool-specific environment variables used by known agent harnesses
138
+ first, then falls back to the emerging `AGENT` and `AI_AGENT` standards.
139
139
  """
140
- # Emerging standard: AGENT=<name>
141
- if agent := os.environ.get("AGENT"):
142
- return agent
143
-
144
140
  # Tool-specific environment variables
145
141
  _TOOL_SPECIFIC_ENV_VARS: list[tuple[str, str]] = [
146
142
  ("CLAUDECODE", "claude-code"),
@@ -152,11 +148,23 @@ def _agent_environment() -> str | None:
152
148
  ("OPENCODE_CLIENT", "opencode"),
153
149
  ("GOOSE_TERMINAL", "goose"), # honk
154
150
  ("TRAE_AI_SHELL_ID", "trae"),
151
+ ("PI_CODING_AGENT", "pi"),
152
+ ("COPILOT_AGENT_SESSION_ID", "copilot"),
153
+ ("ANTIGRAVITY_AGENT", "antigravity"),
154
+ ("JUNIE_SHIM_PATH", "junie"),
155
155
  ]
156
156
  for env_var, agent_name in _TOOL_SPECIFIC_ENV_VARS:
157
157
  if os.environ.get(env_var):
158
158
  return agent_name
159
159
 
160
+ # Emerging standards, checked last because neither value is normalized.
161
+ # `AGENT` may be a bare `1` rather than a name (opencode), and `AI_AGENT`
162
+ # may embed a version or suffix (e.g. `claude-code_2-1-268_agent`).
163
+ if agent := os.environ.get("AGENT"):
164
+ return agent
165
+ if agent := os.environ.get("AI_AGENT"):
166
+ return agent
167
+
160
168
  return None
161
169
 
162
170
 
@@ -45,8 +45,6 @@ class Object:
45
45
  def _is_hydrated(self) -> bool: ...
46
46
  @_is_hydrated.setter
47
47
  def _is_hydrated(self, value: bool): ...
48
- @classmethod
49
- def __init_subclass__(cls, type_prefix: typing.Optional[str] = None): ...
50
48
  def _init(
51
49
  self,
52
50
  rep: str,
@@ -3121,6 +3121,7 @@ class _SidecarManager:
3121
3121
  outbound_cidr_allowlist: Sequence[str] | None = None,
3122
3122
  outbound_domain_allowlist: Sequence[str] | None = None,
3123
3123
  include_oidc_identity_token: bool = False,
3124
+ proxy: _Proxy | None = None,
3124
3125
  pty: bool = False,
3125
3126
  experimental_memory_reserve_consume_mib: int | None = None,
3126
3127
  ) -> _SidecarContainer:
@@ -3153,6 +3154,8 @@ class _SidecarManager:
3153
3154
  include_oidc_identity_token: If True, the sidecar receives a MODAL_IDENTITY_TOKEN env var for
3154
3155
  OIDC-based auth (e.g. to AWS, GCP). The token identifies the sidecar container itself,
3155
3156
  not the main container. Not supported for GPU Sandboxes.
3157
+ proxy: Reference to a Modal Proxy to use in front of this sidecar. Not supported for GPU
3158
+ Sandboxes.
3156
3159
  pty: Whether to enable PTY for the sidecar container.
3157
3160
  experimental_memory_reserve_consume_mib: Memory, in MiB, this sidecar consumes from the Sandbox's
3158
3161
  sidecar memory reserve (the experimental `vm_sidecar_memory_reserve_mib` option).
@@ -3188,6 +3191,13 @@ class _SidecarManager:
3188
3191
  "CloudBucketMount is not supported in sidecars when MODAL_USE_CONTROL_PLANE_SIDECAR_CREATE=0 is set; "
3189
3192
  "unset it to use cloud bucket mounts."
3190
3193
  )
3194
+ if proxy is not None and not self._sandbox._is_v2:
3195
+ raise InvalidError("Sandbox._experimental_sidecars.create(proxy=...) is not supported for GPU Sandboxes.")
3196
+ if proxy is not None and not via_control_plane:
3197
+ raise InvalidError(
3198
+ "Sandbox._experimental_sidecars.create(proxy=...) is not supported when "
3199
+ f"{_CONTROL_PLANE_SIDECAR_CREATE_ENV_VAR}=0 is set; unset it to use a proxy."
3200
+ )
3191
3201
 
3192
3202
  if include_oidc_identity_token and not self._sandbox._is_v2:
3193
3203
  raise InvalidError("include_oidc_identity_token is not supported for GPU Sandboxes.")
@@ -3224,12 +3234,18 @@ class _SidecarManager:
3224
3234
  for _, mount in cloud_bucket_mounts
3225
3235
  if mount.secret is not None and not mount.secret._is_ephemeral
3226
3236
  ]
3227
- hydrate_coros = (
3228
- [secret.hydrate(client=self._sandbox._client) for secret in resolvable_secrets]
3229
- + [volume.hydrate(client=self._sandbox._client) for _, volume in validated_volumes]
3230
- + [secret.hydrate(client=self._sandbox._client) for secret in bucket_credential_secrets]
3231
- )
3232
- await TaskContext.gather(*hydrate_coros)
3237
+ resolver = Resolver()
3238
+ async with TaskContext() as tc:
3239
+ load_context = LoadContext(client=self._sandbox._client, task_context=tc)
3240
+ dependencies = [
3241
+ *resolvable_secrets,
3242
+ *(volume for _, volume in validated_volumes),
3243
+ *bucket_credential_secrets,
3244
+ *([proxy] if proxy is not None else []),
3245
+ ]
3246
+ await asyncio.gather(
3247
+ *(resolver.load(dependency, load_context) for dependency in dependencies if not dependency._is_hydrated)
3248
+ )
3233
3249
 
3234
3250
  # `env` takes precedence over environment variables from secrets
3235
3251
  env_dict = _local_secret_env(secrets) | (env or {})
@@ -3257,6 +3273,7 @@ class _SidecarManager:
3257
3273
  cloud_bucket_mounts=cloud_bucket_mount_protos,
3258
3274
  network_access=network_access,
3259
3275
  include_oidc_identity_token=include_oidc_identity_token,
3276
+ proxy_id=(proxy.object_id if proxy else None),
3260
3277
  pty_info=pty_info,
3261
3278
  resources=(
3262
3279
  api_pb2.Resources(memory_mb=experimental_memory_reserve_consume_mib)
@@ -1298,6 +1298,7 @@ class _SidecarManager:
1298
1298
  outbound_cidr_allowlist: typing.Optional[collections.abc.Sequence[str]] = None,
1299
1299
  outbound_domain_allowlist: typing.Optional[collections.abc.Sequence[str]] = None,
1300
1300
  include_oidc_identity_token: bool = False,
1301
+ proxy: typing.Optional[modal.proxy._Proxy] = None,
1301
1302
  pty: bool = False,
1302
1303
  experimental_memory_reserve_consume_mib: typing.Optional[int] = None,
1303
1304
  ) -> _SidecarContainer:
@@ -1330,6 +1331,8 @@ class _SidecarManager:
1330
1331
  include_oidc_identity_token: If True, the sidecar receives a MODAL_IDENTITY_TOKEN env var for
1331
1332
  OIDC-based auth (e.g. to AWS, GCP). The token identifies the sidecar container itself,
1332
1333
  not the main container. Not supported for GPU Sandboxes.
1334
+ proxy: Reference to a Modal Proxy to use in front of this sidecar. Not supported for GPU
1335
+ Sandboxes.
1333
1336
  pty: Whether to enable PTY for the sidecar container.
1334
1337
  experimental_memory_reserve_consume_mib: Memory, in MiB, this sidecar consumes from the Sandbox's
1335
1338
  sidecar memory reserve (the experimental `vm_sidecar_memory_reserve_mib` option).
@@ -1782,6 +1785,7 @@ class SidecarManager:
1782
1785
  outbound_cidr_allowlist: typing.Optional[collections.abc.Sequence[str]] = None,
1783
1786
  outbound_domain_allowlist: typing.Optional[collections.abc.Sequence[str]] = None,
1784
1787
  include_oidc_identity_token: bool = False,
1788
+ proxy: typing.Optional[modal.proxy.Proxy] = None,
1785
1789
  pty: bool = False,
1786
1790
  experimental_memory_reserve_consume_mib: typing.Optional[int] = None,
1787
1791
  ) -> SidecarContainer:
@@ -1814,6 +1818,8 @@ class SidecarManager:
1814
1818
  include_oidc_identity_token: If True, the sidecar receives a MODAL_IDENTITY_TOKEN env var for
1815
1819
  OIDC-based auth (e.g. to AWS, GCP). The token identifies the sidecar container itself,
1816
1820
  not the main container. Not supported for GPU Sandboxes.
1821
+ proxy: Reference to a Modal Proxy to use in front of this sidecar. Not supported for GPU
1822
+ Sandboxes.
1817
1823
  pty: Whether to enable PTY for the sidecar container.
1818
1824
  experimental_memory_reserve_consume_mib: Memory, in MiB, this sidecar consumes from the Sandbox's
1819
1825
  sidecar memory reserve (the experimental `vm_sidecar_memory_reserve_mib` option).
@@ -1843,6 +1849,7 @@ class SidecarManager:
1843
1849
  outbound_cidr_allowlist: typing.Optional[collections.abc.Sequence[str]] = None,
1844
1850
  outbound_domain_allowlist: typing.Optional[collections.abc.Sequence[str]] = None,
1845
1851
  include_oidc_identity_token: bool = False,
1852
+ proxy: typing.Optional[modal.proxy.Proxy] = None,
1846
1853
  pty: bool = False,
1847
1854
  experimental_memory_reserve_consume_mib: typing.Optional[int] = None,
1848
1855
  ) -> SidecarContainer:
@@ -1875,6 +1882,8 @@ class SidecarManager:
1875
1882
  include_oidc_identity_token: If True, the sidecar receives a MODAL_IDENTITY_TOKEN env var for
1876
1883
  OIDC-based auth (e.g. to AWS, GCP). The token identifies the sidecar container itself,
1877
1884
  not the main container. Not supported for GPU Sandboxes.
1885
+ proxy: Reference to a Modal Proxy to use in front of this sidecar. Not supported for GPU
1886
+ Sandboxes.
1878
1887
  pty: Whether to enable PTY for the sidecar container.
1879
1888
  experimental_memory_reserve_consume_mib: Memory, in MiB, this sidecar consumes from the Sandbox's
1880
1889
  sidecar memory reserve (the experimental `vm_sidecar_memory_reserve_mib` option).
@@ -1,13 +1,15 @@
1
1
  ---
2
2
  name: modal
3
3
  description: >
4
- This skill provides guidance for working with the Modal cloud platform. Use
5
- this skill whenever the user mentions Modal or has code that imports the
6
- `modal` SDK in Python, Go, or JavaScript. This skill should also trigger when
7
- the user needs to run Python code with vertical or horizontal scalability
8
- (e.g. batch jobs), needs access to GPUs (e.g. AI workloads including training
9
- and inference) or needs to run untrusted processes in a sandbox, since Modal
10
- serves these use cases well.
4
+ This skill provides guidance for working with the Modal cloud platform. Read
5
+ this skill before answering any questions about Modal, reading any Modal docs,
6
+ inspecting the `modal` SDK, or interacting with any code that imports the
7
+ `modal` SDK in Python, Go, or JavaScript, even for simple tasks you already
8
+ know how to do. This skill should also trigger when the user needs to run
9
+ Python code with vertical or horizontal scalability (e.g. batch jobs), needs
10
+ access to GPUs (e.g. AI workloads including training and inference) or needs
11
+ to run untrusted processes in a sandbox, since Modal serves these use cases
12
+ well.
11
13
  ---
12
14
 
13
15
  # Overview
@@ -16,21 +18,18 @@ This is a foundational skill for working with the Modal cloud platform.
16
18
 
17
19
  Modal is a platform for AI workloads. It offers highly scalable serverless compute (including GPUs) with minimal configuration.
18
20
 
21
+ Using the CLI or running code that depends on the `modal` library requires internet access and an authorization token. There is no "local development mode" with Modal.
22
+
19
23
  # Documentation
20
24
 
21
25
  The official docs are the best source for up-to-date information on the platform. Make use of them when planning, debugging, or answering questions!
22
26
 
23
- Modal's documentation is outlined at https://modal.com/llms.txt. This file contains titles and URLs for all public docs; reading it directly will guide you to specific content.
24
-
25
- The docs are divided into three sections:
27
+ Modal's latest documentation, which may cover features introduced in newer SDK versions, is outlined at https://modal.com/llms.txt. This file contains titles and URLs for all public docs; reading it directly will guide you to specific content. Fetch the docs using a `.md` extension to get plain text.
26
28
 
27
- - _Guide_ pages have explanations of Modal features, primitives, and workflows
28
- - _API Reference_ pages have detailed information about each component of the SDK
29
- - _Examples_ pages contain didactic examples of various AI applications on Modal
29
+ When installed via the Modal CLI, this skill installs local documentation in `references/` unless `--no-docs` is passed:
30
30
 
31
- Fetch the docs using a `.md` extension to get plain text.
32
-
33
- If this skill has been installed via the `modal` CLI, the docs are also bundled locally under `references/`.
31
+ - `api/`: An API reference generated locally from the signatures and docstrings of the SDK used to install or update the skill.
32
+ - `guide/` and `examples/`: Guides and examples downloaded from the online docs. These reflect the website at download time and may cover features unavailable in that SDK version.
34
33
 
35
34
  You can also refer to https://modal.com/llms-full.txt, which aggregates all docs in a single very large file. Do *not* read this into your main context, but it may be useful for searching.
36
35
 
@@ -46,6 +45,8 @@ Tip: many CLI commands accept a `--json` flag to make their output more easily p
46
45
 
47
46
  The `modal` CLI is part of the Python SDK and executes in a Python runtime. Depending on the user's preferred Python development workflow, you may need to prefix `modal` CLI invocations with, e.g., `uv run` to ensure a consistent Python environment. The CLI can also be used via `uvx` as a standalone tool, but only do this when working outside of a Python project.
48
47
 
48
+ Do not run Modal CLI commands with an attached terminal (TTY/PTY), so logs appear as plain text rather than spinner redraws.
49
+
49
50
  # Getting up to date
50
51
 
51
52
  You have significant knowledge about Modal from your training data but may not be aware of new features or recent changes to the API. Modal is continuously adding new features. Reading relevant docs while planning or debugging can help you discover the most up-to-date way to accomplish a task on Modal.
@@ -56,19 +57,13 @@ The Modal CLI provides a `modal changelog` command for learning about recent cha
56
57
  - `modal changelog --since [VERSION]` when migrating a codebase to a newer version
57
58
  - `modal changelog --newer` to discover features that would be available on update
58
59
 
59
- Note: `modal changelog` requires network access.
60
+ Note: the output of `modal changelog` may be long. Do not load it fully into your context.
60
61
 
61
62
  Run `modal --version` to see the SDK version that is in use.
62
63
 
63
64
  If your code exercises deprecated APIs, Modal will issue warnings. Use the warning message and related documentation to migrate your code to stable API.
64
65
 
65
- This skill will also be improved over time. Its version should correspond to the version of the Modal SDK that you are using. If the skill is out of date, it can be updated by running `modal skills update`.
66
-
67
- # Auth
68
-
69
- Modal is a cloud platform. Using the CLI or running code that depends on the `modal` library requires internet access and an authorization token. There is no "local development mode" with Modal.
70
-
71
- You can use the `modal token` CLI to create a new token (note: this workflow requires human user involvement) or to debug authorization issues. Token setup only needs to happen once, so assume it is configured unless you encounter issues.
66
+ Before using this skill, check that its version in the metadata is identical to `modal --version`. If not, run `modal skills update` to update it, passing `--claude` if this skill lives under a `.claude/` directory and `--global` if it lives under the home directory rather than the project.
72
67
 
73
68
  # Async Python
74
69
 
@@ -181,6 +181,7 @@ class FunctionStats:
181
181
  container_error_count: int
182
182
  container_creating_at_end_count: int
183
183
  container_percentile_stats: dict[str, StatsPercentileDistribution]
184
+ container_total_count: int
184
185
  variant_count: int
185
186
  all_variants: bool
186
187
 
@@ -198,6 +199,7 @@ class FunctionStats:
198
199
  },
199
200
  container_started_count=proto.container_started_count,
200
201
  container_error_count=proto.container_error_count,
202
+ container_total_count=proto.container_total_count,
201
203
  container_creating_at_end_count=proto.container_creating_at_end_count,
202
204
  container_percentile_stats={
203
205
  k: StatsPercentileDistribution._from_proto(v) for k, v in proto.container_percentile_stats.items()
@@ -256,6 +258,7 @@ class ServerStats:
256
258
  container_started_count: int
257
259
  container_error_count: int
258
260
  container_creating_at_end_count: int
261
+ container_total_count: int
259
262
  container_percentile_stats: dict[str, StatsPercentileDistribution]
260
263
  inference: InferenceStats | None
261
264
 
@@ -274,6 +277,7 @@ class ServerStats:
274
277
  container_started_count=proto.container_started_count,
275
278
  container_error_count=proto.container_error_count,
276
279
  container_creating_at_end_count=proto.container_creating_at_end_count,
280
+ container_total_count=proto.container_total_count,
277
281
  container_percentile_stats={
278
282
  name: StatsPercentileDistribution._from_proto(distribution)
279
283
  for name, distribution in proto.container_percentile_stats.items()
@@ -888,6 +888,8 @@ class _Volume(_Object, type_prefix="vo"):
888
888
  async def commit(self):
889
889
  """Commit changes to a mounted volume.
890
890
 
891
+ Must be called inside a container that mounts the Volume.
892
+
891
893
  If successful, the changes made are now persisted in durable storage and available to other containers accessing
892
894
  the volume.
893
895
  """
@@ -906,6 +908,8 @@ class _Volume(_Object, type_prefix="vo"):
906
908
  async def reload(self):
907
909
  """Make latest committed state of volume available in the running container.
908
910
 
911
+ Must be called inside a container that mounts the Volume.
912
+
909
913
  Any uncommitted changes to the volume, such as new or modified files, may implicitly be committed when
910
914
  reloading.
911
915
 
@@ -726,6 +726,8 @@ class _Volume(modal._object._Object):
726
726
  async def commit(self):
727
727
  """Commit changes to a mounted volume.
728
728
 
729
+ Must be called inside a container that mounts the Volume.
730
+
729
731
  If successful, the changes made are now persisted in durable storage and available to other containers accessing
730
732
  the volume.
731
733
  """
@@ -734,6 +736,8 @@ class _Volume(modal._object._Object):
734
736
  async def reload(self):
735
737
  """Make latest committed state of volume available in the running container.
736
738
 
739
+ Must be called inside a container that mounts the Volume.
740
+
737
741
  Any uncommitted changes to the volume, such as new or modified files, may implicitly be committed when
738
742
  reloading.
739
743
 
@@ -1146,6 +1150,8 @@ class Volume(modal.object.Object):
1146
1150
  def __call__(self, /):
1147
1151
  """Commit changes to a mounted volume.
1148
1152
 
1153
+ Must be called inside a container that mounts the Volume.
1154
+
1149
1155
  If successful, the changes made are now persisted in durable storage and available to other containers accessing
1150
1156
  the volume.
1151
1157
  """
@@ -1154,6 +1160,8 @@ class Volume(modal.object.Object):
1154
1160
  async def aio(self, /):
1155
1161
  """Commit changes to a mounted volume.
1156
1162
 
1163
+ Must be called inside a container that mounts the Volume.
1164
+
1157
1165
  If successful, the changes made are now persisted in durable storage and available to other containers accessing
1158
1166
  the volume.
1159
1167
  """
@@ -1165,6 +1173,8 @@ class Volume(modal.object.Object):
1165
1173
  def __call__(self, /):
1166
1174
  """Make latest committed state of volume available in the running container.
1167
1175
 
1176
+ Must be called inside a container that mounts the Volume.
1177
+
1168
1178
  Any uncommitted changes to the volume, such as new or modified files, may implicitly be committed when
1169
1179
  reloading.
1170
1180
 
@@ -1175,6 +1185,8 @@ class Volume(modal.object.Object):
1175
1185
  async def aio(self, /):
1176
1186
  """Make latest committed state of volume available in the running container.
1177
1187
 
1188
+ Must be called inside a container that mounts the Volume.
1189
+
1178
1190
  Any uncommitted changes to the volume, such as new or modified files, may implicitly be committed when
1179
1191
  reloading.
1180
1192