modal 1.6.1.dev1__tar.gz → 1.6.2.dev0__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.2.dev0}/PKG-INFO +3 -3
  2. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_environments.py +2 -1
  3. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_output/status.py +1 -3
  4. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_server.py +34 -9
  5. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_server.pyi +18 -1
  6. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_utils/task_command_router_client.py +29 -8
  7. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cli/function.py +5 -3
  8. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cli/server.py +5 -4
  9. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/client.pyi +2 -2
  10. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/config.py +14 -6
  11. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/functions.pyi +6 -6
  12. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/object.pyi +0 -2
  13. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/sandbox.py +47 -46
  14. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/sandbox.pyi +16 -0
  15. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/skills/modal/SKILL.md +19 -24
  16. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/types.py +4 -0
  17. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/volume.py +4 -0
  18. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/volume.pyi +12 -0
  19. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal.egg-info/PKG-INFO +3 -3
  20. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal.egg-info/requires.txt +2 -2
  21. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal_proto/api_pb2.py +1383 -1373
  22. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal_proto/api_pb2.pyi +64 -8
  23. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal_proto/task_command_router_pb2.py +96 -96
  24. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal_proto/task_command_router_pb2.pyi +12 -2
  25. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal_version/__init__.py +1 -1
  26. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/pyproject.toml +2 -2
  27. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/LICENSE +0 -0
  28. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/README.md +0 -0
  29. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/__init__.py +0 -0
  30. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/__main__.py +0 -0
  31. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_billing.py +0 -0
  32. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_cluster.py +0 -0
  33. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_cluster.pyi +0 -0
  34. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_container_entrypoint.py +0 -0
  35. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_function_variants.py +0 -0
  36. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_functions.py +0 -0
  37. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_grpc_client.py +0 -0
  38. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_image.py +0 -0
  39. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_ipython.py +0 -0
  40. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_load_context.py +0 -0
  41. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_location.py +0 -0
  42. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_logs.py +0 -0
  43. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_logs_manager.py +0 -0
  44. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_logs_manager.pyi +0 -0
  45. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_object.py +0 -0
  46. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_outbound_policy.py +0 -0
  47. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_outbound_policy.pyi +0 -0
  48. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_output/__init__.py +0 -0
  49. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_output/manager.py +0 -0
  50. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_output/pty.py +0 -0
  51. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_output/rich.py +0 -0
  52. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_partial_function.py +0 -0
  53. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_resolver.py +0 -0
  54. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_resources.py +0 -0
  55. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_runtime/__init__.py +0 -0
  56. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_runtime/asgi.py +0 -0
  57. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_runtime/container_io_manager.py +0 -0
  58. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_runtime/container_io_manager.pyi +0 -0
  59. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_runtime/execution_context.py +0 -0
  60. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_runtime/execution_context.pyi +0 -0
  61. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_runtime/gpu_memory_snapshot.py +0 -0
  62. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_runtime/task_lifecycle_manager.py +0 -0
  63. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_runtime/task_lifecycle_manager.pyi +0 -0
  64. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_runtime/telemetry.py +0 -0
  65. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_runtime/user_code_event_loop.py +0 -0
  66. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_runtime/user_code_imports.py +0 -0
  67. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_serialization.py +0 -0
  68. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_supports_logs.py +0 -0
  69. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_traceback.py +0 -0
  70. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_tunnel.py +0 -0
  71. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_tunnel.pyi +0 -0
  72. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_type_manager.py +0 -0
  73. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_utils/__init__.py +0 -0
  74. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_utils/app_utils.py +0 -0
  75. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_utils/async_utils.py +0 -0
  76. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_utils/auth_token_manager.py +0 -0
  77. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_utils/blob_utils.py +0 -0
  78. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_utils/browser_utils.py +0 -0
  79. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_utils/bytes_io_segment_payload.py +0 -0
  80. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_utils/curl_utils.py +0 -0
  81. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_utils/deprecation.py +0 -0
  82. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_utils/display_utils.py +0 -0
  83. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_utils/docker_utils.py +0 -0
  84. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_utils/function_utils.py +0 -0
  85. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_utils/git_utils.py +0 -0
  86. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_utils/grpc_testing.py +0 -0
  87. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_utils/grpc_utils.py +0 -0
  88. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_utils/hash_utils.py +0 -0
  89. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_utils/http_utils.py +0 -0
  90. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_utils/idle_countdown.py +0 -0
  91. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_utils/jwt_utils.py +0 -0
  92. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_utils/logger.py +0 -0
  93. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_utils/mount_utils.py +0 -0
  94. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_utils/name_utils.py +0 -0
  95. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_utils/package_utils.py +0 -0
  96. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_utils/pattern_utils.py +0 -0
  97. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_utils/proxy_support.py +0 -0
  98. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_utils/rand_pb_testing.py +0 -0
  99. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_utils/sandbox_fs_utils.py +0 -0
  100. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_utils/shell_utils.py +0 -0
  101. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_utils/time_utils.py +0 -0
  102. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_vendor/__init__.py +0 -0
  103. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_vendor/a2wsgi_wsgi.py +0 -0
  104. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_vendor/cloudpickle.py +0 -0
  105. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_vendor/tblib.py +0 -0
  106. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_vendor/version.py +0 -0
  107. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_watcher.py +0 -0
  108. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_workspace.py +0 -0
  109. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/app.py +0 -0
  110. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/app.pyi +0 -0
  111. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/billing.py +0 -0
  112. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/billing.pyi +0 -0
  113. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/builder/2023.12.312.txt +0 -0
  114. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/builder/2023.12.txt +0 -0
  115. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/builder/2024.04.txt +0 -0
  116. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/builder/2024.10.txt +0 -0
  117. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/builder/2025.06.txt +0 -0
  118. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/builder/PREVIEW.txt +0 -0
  119. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/builder/README.md +0 -0
  120. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/builder/base-images.json +0 -0
  121. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/call_graph.py +0 -0
  122. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cli/__init__.py +0 -0
  123. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cli/_download.py +0 -0
  124. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cli/_help.py +0 -0
  125. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cli/_logs.py +0 -0
  126. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cli/_stats.py +0 -0
  127. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cli/_traceback.py +0 -0
  128. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cli/app.py +0 -0
  129. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cli/billing.py +0 -0
  130. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cli/changelog.py +0 -0
  131. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cli/config.py +0 -0
  132. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cli/container.py +0 -0
  133. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cli/curl.py +0 -0
  134. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cli/dashboard.py +0 -0
  135. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cli/dict.py +0 -0
  136. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cli/endpoint.py +0 -0
  137. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cli/entry_point.py +0 -0
  138. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cli/environment.py +0 -0
  139. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cli/image.py +0 -0
  140. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cli/import_refs.py +0 -0
  141. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cli/logo.py +0 -0
  142. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cli/network_file_system.py +0 -0
  143. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cli/profile.py +0 -0
  144. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cli/queues.py +0 -0
  145. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cli/run.py +0 -0
  146. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cli/secret.py +0 -0
  147. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cli/selector.py +0 -0
  148. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cli/shell.py +0 -0
  149. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cli/skills.py +0 -0
  150. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cli/token.py +0 -0
  151. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cli/utils.py +0 -0
  152. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cli/volume.py +0 -0
  153. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cli/workspace.py +0 -0
  154. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/client.py +0 -0
  155. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cloud_bucket_mount.py +0 -0
  156. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cloud_bucket_mount.pyi +0 -0
  157. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cls.py +0 -0
  158. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cls.pyi +0 -0
  159. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cluster.py +0 -0
  160. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cluster.pyi +0 -0
  161. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/container_process.py +0 -0
  162. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/container_process.pyi +0 -0
  163. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/dict.py +0 -0
  164. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/dict.pyi +0 -0
  165. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/environments.py +0 -0
  166. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/environments.pyi +0 -0
  167. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/exception.py +0 -0
  168. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/experimental/__init__.py +0 -0
  169. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/experimental/_flash_container_entry.py +0 -0
  170. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/experimental/flash.py +0 -0
  171. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/experimental/flash.pyi +0 -0
  172. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/experimental/flash_server.py +0 -0
  173. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/experimental/flash_server.pyi +0 -0
  174. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/experimental/ipython.py +0 -0
  175. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/file_pattern_matcher.py +0 -0
  176. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/functions.py +0 -0
  177. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/image.py +0 -0
  178. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/image.pyi +0 -0
  179. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/io_streams.py +0 -0
  180. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/io_streams.pyi +0 -0
  181. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/mount.py +0 -0
  182. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/mount.pyi +0 -0
  183. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/network_file_system.py +0 -0
  184. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/network_file_system.pyi +0 -0
  185. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/object.py +0 -0
  186. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/output.py +0 -0
  187. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/parallel_map.py +0 -0
  188. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/parallel_map.pyi +0 -0
  189. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/partial_function.py +0 -0
  190. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/partial_function.pyi +0 -0
  191. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/proxy.py +0 -0
  192. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/proxy.pyi +0 -0
  193. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/py.typed +0 -0
  194. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/queue.py +0 -0
  195. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/queue.pyi +0 -0
  196. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/retries.py +0 -0
  197. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/runner.py +0 -0
  198. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/runner.pyi +0 -0
  199. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/running_app.py +0 -0
  200. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/sandbox_fs.py +0 -0
  201. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/sandbox_fs.pyi +0 -0
  202. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/schedule.py +0 -0
  203. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/scheduler_placement.py +0 -0
  204. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/secret.py +0 -0
  205. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/secret.pyi +0 -0
  206. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/server.py +0 -0
  207. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/server.pyi +0 -0
  208. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/serving.py +0 -0
  209. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/serving.pyi +0 -0
  210. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/snapshot.py +0 -0
  211. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/snapshot.pyi +0 -0
  212. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/stream_type.py +0 -0
  213. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/token_flow.py +0 -0
  214. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/token_flow.pyi +0 -0
  215. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/workspace.py +0 -0
  216. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/workspace.pyi +0 -0
  217. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal.egg-info/SOURCES.txt +0 -0
  218. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal.egg-info/dependency_links.txt +0 -0
  219. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal.egg-info/entry_points.txt +0 -0
  220. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal.egg-info/top_level.txt +0 -0
  221. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal_docs/__init__.py +0 -0
  222. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal_docs/gen_cli_docs.py +0 -0
  223. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal_docs/gen_cli_docs_main.py +0 -0
  224. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal_docs/gen_reference_docs.py +0 -0
  225. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal_docs/gen_reference_docs_main.py +0 -0
  226. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal_docs/mdmd/__init__.py +0 -0
  227. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal_docs/mdmd/mdmd.py +0 -0
  228. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal_docs/mdmd/signatures.py +0 -0
  229. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal_docs/mdmd/types.py +0 -0
  230. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal_docs/reference_intro.md +0 -0
  231. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal_proto/__init__.py +0 -0
  232. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal_proto/api_grpc.py +0 -0
  233. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal_proto/api_pb2_grpc.py +0 -0
  234. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal_proto/api_pb2_grpc.pyi +0 -0
  235. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal_proto/modal_api_grpc.py +0 -0
  236. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal_proto/py.typed +0 -0
  237. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal_proto/task_command_router_grpc.py +0 -0
  238. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal_proto/task_command_router_pb2_grpc.py +0 -0
  239. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal_proto/task_command_router_pb2_grpc.pyi +0 -0
  240. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal_version/__main__.py +0 -0
  241. {modal-1.6.1.dev1 → modal-1.6.2.dev0}/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.2.dev0
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
 
@@ -226,6 +226,7 @@ async def fetch_command_router_access_v2(
226
226
  *,
227
227
  sandbox_id: str | None = None,
228
228
  task_id: str | None = None,
229
+ sandbox_token: str | None = None,
229
230
  ) -> api_pb2.SandboxGetCommandRouterAccessResponse:
230
231
  """Fetch direct command router access info from Modal server for a V2 sandbox."""
231
232
  if sandbox_id is not None:
@@ -236,10 +237,10 @@ async def fetch_command_router_access_v2(
236
237
  raise ValueError("Either sandbox_id or task_id must be provided")
237
238
  assert server_client._auth_token_manager
238
239
  auth_token = await server_client._auth_token_manager.get_token()
239
- return await server_client._stub.SandboxGetCommandRouterAccess(
240
- request,
241
- metadata=[("x-modal-auth-token", auth_token)],
242
- )
240
+ metadata = [("x-modal-auth-token", auth_token)]
241
+ if sandbox_token:
242
+ metadata.append(("x-modal-sandbox-token", sandbox_token))
243
+ return await server_client._stub.SandboxGetCommandRouterAccess(request, metadata=metadata)
243
244
 
244
245
 
245
246
  def _finalize_channel(loop, channel):
@@ -267,6 +268,7 @@ class TaskCommandRouterClient:
267
268
  jwt: str,
268
269
  *,
269
270
  sandbox_id: str | None = None,
271
+ sandbox_token: str | None = None,
270
272
  ) -> "TaskCommandRouterClient":
271
273
  """Build a connected client from a jwt and url."""
272
274
  o = urllib.parse.urlparse(url)
@@ -315,7 +317,17 @@ class TaskCommandRouterClient:
315
317
  loop = asyncio.get_running_loop()
316
318
  jwt_refresh_lock = asyncio.Lock()
317
319
 
318
- client = cls(server_client, task_id, url, jwt, channel, loop, jwt_refresh_lock, sandbox_id=sandbox_id)
320
+ client = cls(
321
+ server_client,
322
+ task_id,
323
+ url,
324
+ jwt,
325
+ channel,
326
+ loop,
327
+ jwt_refresh_lock,
328
+ sandbox_id=sandbox_id,
329
+ sandbox_token=sandbox_token,
330
+ )
319
331
  # An unused client releases its connection too.
320
332
  client._arm_idle_release()
321
333
  return client
@@ -337,6 +349,8 @@ class TaskCommandRouterClient:
337
349
  sandbox_id: str,
338
350
  task_id: str,
339
351
  access: api_pb2.CommandRouterAccess | None = None,
352
+ *,
353
+ sandbox_token: str | None = None,
340
354
  ) -> "TaskCommandRouterClient":
341
355
  """Initialize a TaskCommandRouterClient for a V2 sandbox.
342
356
 
@@ -348,10 +362,12 @@ class TaskCommandRouterClient:
348
362
  if access is not None:
349
363
  url, jwt = access.url, access.jwt
350
364
  else:
351
- resp = await fetch_command_router_access_v2(server_client, sandbox_id=sandbox_id)
365
+ resp = await fetch_command_router_access_v2(
366
+ server_client, sandbox_id=sandbox_id, sandbox_token=sandbox_token
367
+ )
352
368
  url, jwt = resp.url, resp.jwt
353
369
  logger.debug(f"Using command router access for sandbox {sandbox_id}")
354
- return await cls._connect(server_client, task_id, url, jwt, sandbox_id=sandbox_id)
370
+ return await cls._connect(server_client, task_id, url, jwt, sandbox_id=sandbox_id, sandbox_token=sandbox_token)
355
371
 
356
372
  @classmethod
357
373
  async def init_v2_by_task_id(
@@ -375,6 +391,7 @@ class TaskCommandRouterClient:
375
391
  jwt_refresh_lock: asyncio.Lock,
376
392
  *,
377
393
  sandbox_id: str | None = None,
394
+ sandbox_token: str | None = None,
378
395
  stream_stdio_retry_delay_secs: float = 0.01,
379
396
  stream_stdio_retry_delay_factor: float = 2,
380
397
  stream_stdio_max_retries: int = 10,
@@ -388,6 +405,7 @@ class TaskCommandRouterClient:
388
405
  self._server_client = server_client
389
406
  self._task_id = task_id
390
407
  self._sandbox_id = sandbox_id
408
+ self._sandbox_token = sandbox_token
391
409
  self._server_url = server_url
392
410
  self._jwt = jwt
393
411
  self._channel = channel
@@ -902,7 +920,10 @@ class TaskCommandRouterClient:
902
920
  if self._is_v2_sandbox:
903
921
  logger.debug(f"Refreshing JWT for V2 exec with task ID {self._task_id}")
904
922
  v2_resp = await fetch_command_router_access_v2(
905
- self._server_client, sandbox_id=self._sandbox_id, task_id=self._task_id
923
+ self._server_client,
924
+ sandbox_id=self._sandbox_id,
925
+ task_id=self._task_id,
926
+ sandbox_token=self._sandbox_token,
906
927
  )
907
928
  logger.debug(f"Finished refreshing JWT for V2 exec with task ID {self._task_id}")
908
929
  jwt, url = v2_resp.jwt, v2_resp.url
@@ -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.2.dev0",
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.2.dev0",
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
 
@@ -613,7 +613,7 @@ class Function(
613
613
 
614
614
  _call_generator: ___call_generator_spec
615
615
 
616
- class __remote_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER]):
616
+ class __remote_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER]):
617
617
  def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> ReturnType_INNER:
618
618
  """Calls the function remotely, executing it with the given arguments and returning the execution's result.
619
619
 
@@ -638,7 +638,7 @@ class Function(
638
638
  """
639
639
  ...
640
640
 
641
- remote: __remote_spec[modal._functions.ReturnType, modal._functions.P]
641
+ remote: __remote_spec[modal._functions.P, modal._functions.ReturnType]
642
642
 
643
643
  class __remote_gen_spec(typing_extensions.Protocol):
644
644
  def __call__(self, /, *args, **kwargs) -> typing.Generator[typing.Any, None, None]:
@@ -688,7 +688,7 @@ class Function(
688
688
  """
689
689
  ...
690
690
 
691
- class ___experimental_spawn_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER]):
691
+ class ___experimental_spawn_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER]):
692
692
  def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]:
693
693
  """[Experimental] Calls the function with the given arguments, without waiting for the results.
694
694
 
@@ -721,7 +721,7 @@ class Function(
721
721
  """
722
722
  ...
723
723
 
724
- _experimental_spawn: ___experimental_spawn_spec[modal._functions.ReturnType, modal._functions.P]
724
+ _experimental_spawn: ___experimental_spawn_spec[modal._functions.P, modal._functions.ReturnType]
725
725
 
726
726
  class ___spawn_map_inner_spec(typing_extensions.Protocol[P_INNER]):
727
727
  def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> None: ...
@@ -729,7 +729,7 @@ class Function(
729
729
 
730
730
  _spawn_map_inner: ___spawn_map_inner_spec[modal._functions.P]
731
731
 
732
- class __spawn_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER]):
732
+ class __spawn_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER]):
733
733
  def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]:
734
734
  """Calls the function with the given arguments, without waiting for the results.
735
735
 
@@ -762,7 +762,7 @@ class Function(
762
762
  """
763
763
  ...
764
764
 
765
- spawn: __spawn_spec[modal._functions.ReturnType, modal._functions.P]
765
+ spawn: __spawn_spec[modal._functions.P, modal._functions.ReturnType]
766
766
 
767
767
  @property
768
768
  def _raw_f_(self) -> collections.abc.Callable[..., typing.Any]: ...
@@ -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,