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.
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/PKG-INFO +3 -3
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_environments.py +2 -1
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_output/status.py +1 -3
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_server.py +34 -9
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_server.pyi +18 -1
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_utils/task_command_router_client.py +29 -8
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cli/function.py +5 -3
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cli/server.py +5 -4
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/client.pyi +2 -2
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/config.py +14 -6
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/functions.pyi +6 -6
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/object.pyi +0 -2
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/sandbox.py +47 -46
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/sandbox.pyi +16 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/skills/modal/SKILL.md +19 -24
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/types.py +4 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/volume.py +4 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/volume.pyi +12 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal.egg-info/PKG-INFO +3 -3
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal.egg-info/requires.txt +2 -2
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal_proto/api_pb2.py +1383 -1373
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal_proto/api_pb2.pyi +64 -8
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal_proto/task_command_router_pb2.py +96 -96
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal_proto/task_command_router_pb2.pyi +12 -2
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal_version/__init__.py +1 -1
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/pyproject.toml +2 -2
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/LICENSE +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/README.md +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/__init__.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/__main__.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_billing.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_cluster.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_cluster.pyi +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_container_entrypoint.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_function_variants.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_functions.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_grpc_client.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_image.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_ipython.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_load_context.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_location.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_logs.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_logs_manager.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_logs_manager.pyi +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_object.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_outbound_policy.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_outbound_policy.pyi +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_output/__init__.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_output/manager.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_output/pty.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_output/rich.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_partial_function.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_resolver.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_resources.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_runtime/__init__.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_runtime/asgi.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_runtime/container_io_manager.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_runtime/container_io_manager.pyi +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_runtime/execution_context.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_runtime/execution_context.pyi +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_runtime/gpu_memory_snapshot.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_runtime/task_lifecycle_manager.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_runtime/task_lifecycle_manager.pyi +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_runtime/telemetry.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_runtime/user_code_event_loop.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_runtime/user_code_imports.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_serialization.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_supports_logs.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_traceback.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_tunnel.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_tunnel.pyi +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_type_manager.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_utils/__init__.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_utils/app_utils.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_utils/async_utils.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_utils/auth_token_manager.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_utils/blob_utils.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_utils/browser_utils.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_utils/bytes_io_segment_payload.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_utils/curl_utils.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_utils/deprecation.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_utils/display_utils.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_utils/docker_utils.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_utils/function_utils.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_utils/git_utils.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_utils/grpc_testing.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_utils/grpc_utils.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_utils/hash_utils.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_utils/http_utils.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_utils/idle_countdown.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_utils/jwt_utils.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_utils/logger.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_utils/mount_utils.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_utils/name_utils.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_utils/package_utils.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_utils/pattern_utils.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_utils/proxy_support.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_utils/rand_pb_testing.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_utils/sandbox_fs_utils.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_utils/shell_utils.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_utils/time_utils.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_vendor/__init__.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_vendor/a2wsgi_wsgi.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_vendor/cloudpickle.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_vendor/tblib.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_vendor/version.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_watcher.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/_workspace.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/app.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/app.pyi +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/billing.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/billing.pyi +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/builder/2023.12.312.txt +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/builder/2023.12.txt +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/builder/2024.04.txt +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/builder/2024.10.txt +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/builder/2025.06.txt +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/builder/PREVIEW.txt +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/builder/README.md +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/builder/base-images.json +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/call_graph.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cli/__init__.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cli/_download.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cli/_help.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cli/_logs.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cli/_stats.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cli/_traceback.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cli/app.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cli/billing.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cli/changelog.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cli/config.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cli/container.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cli/curl.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cli/dashboard.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cli/dict.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cli/endpoint.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cli/entry_point.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cli/environment.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cli/image.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cli/import_refs.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cli/logo.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cli/network_file_system.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cli/profile.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cli/queues.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cli/run.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cli/secret.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cli/selector.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cli/shell.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cli/skills.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cli/token.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cli/utils.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cli/volume.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cli/workspace.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/client.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cloud_bucket_mount.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cloud_bucket_mount.pyi +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cls.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cls.pyi +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cluster.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/cluster.pyi +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/container_process.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/container_process.pyi +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/dict.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/dict.pyi +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/environments.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/environments.pyi +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/exception.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/experimental/__init__.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/experimental/_flash_container_entry.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/experimental/flash.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/experimental/flash.pyi +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/experimental/flash_server.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/experimental/flash_server.pyi +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/experimental/ipython.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/file_pattern_matcher.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/functions.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/image.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/image.pyi +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/io_streams.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/io_streams.pyi +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/mount.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/mount.pyi +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/network_file_system.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/network_file_system.pyi +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/object.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/output.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/parallel_map.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/parallel_map.pyi +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/partial_function.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/partial_function.pyi +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/proxy.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/proxy.pyi +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/py.typed +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/queue.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/queue.pyi +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/retries.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/runner.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/runner.pyi +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/running_app.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/sandbox_fs.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/sandbox_fs.pyi +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/schedule.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/scheduler_placement.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/secret.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/secret.pyi +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/server.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/server.pyi +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/serving.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/serving.pyi +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/snapshot.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/snapshot.pyi +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/stream_type.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/token_flow.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/token_flow.pyi +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/workspace.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal/workspace.pyi +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal.egg-info/SOURCES.txt +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal.egg-info/dependency_links.txt +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal.egg-info/entry_points.txt +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal.egg-info/top_level.txt +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal_docs/__init__.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal_docs/gen_cli_docs.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal_docs/gen_cli_docs_main.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal_docs/gen_reference_docs.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal_docs/gen_reference_docs_main.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal_docs/mdmd/__init__.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal_docs/mdmd/mdmd.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal_docs/mdmd/signatures.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal_docs/mdmd/types.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal_docs/reference_intro.md +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal_proto/__init__.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal_proto/api_grpc.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal_proto/api_pb2_grpc.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal_proto/api_pb2_grpc.pyi +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal_proto/modal_api_grpc.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal_proto/py.typed +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal_proto/task_command_router_grpc.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal_proto/task_command_router_pb2_grpc.py +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal_proto/task_command_router_pb2_grpc.pyi +0 -0
- {modal-1.6.1.dev1 → modal-1.6.2.dev0}/modal_version/__main__.py +0 -0
- {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.
|
|
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,<
|
|
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.
|
|
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.
|
|
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,
|
|
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
|
|
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
|
|
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,
|
|
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
|
-
|
|
240
|
-
|
|
241
|
-
metadata
|
|
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(
|
|
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(
|
|
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,
|
|
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"{
|
|
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
|
-
|
|
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
|
-
|
|
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"{
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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
|
|
138
|
-
|
|
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[
|
|
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.
|
|
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[
|
|
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.
|
|
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[
|
|
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.
|
|
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]: ...
|