blaxel 0.1.22rc70__py3-none-any.whl → 0.2.0rc2__py3-none-any.whl
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.
- blaxel/__init__.py +6 -3
- blaxel/core/__init__.py +44 -0
- blaxel/{agents → core/agents}/__init__.py +30 -50
- blaxel/{authentication → core/authentication}/apikey.py +1 -0
- blaxel/{authentication → core/authentication}/clientcredentials.py +6 -2
- blaxel/{client → core/client}/api/agents/create_agent.py +1 -1
- blaxel/{client → core/client}/api/agents/update_agent.py +1 -1
- blaxel/{client → core/client}/api/compute/create_sandbox.py +1 -1
- blaxel/{client → core/client}/api/compute/create_sandbox_preview.py +1 -1
- blaxel/{client → core/client}/api/compute/create_sandbox_preview_token.py +1 -1
- blaxel/{client → core/client}/api/compute/update_sandbox.py +1 -1
- blaxel/{client → core/client}/api/compute/update_sandbox_preview.py +1 -1
- blaxel/{client → core/client}/api/functions/create_function.py +1 -1
- blaxel/{client → core/client}/api/functions/update_function.py +1 -1
- blaxel/{client → core/client}/api/integrations/create_integration_connection.py +1 -1
- blaxel/{client → core/client}/api/integrations/update_integration_connection.py +1 -1
- blaxel/{client → core/client}/api/jobs/create_job.py +1 -1
- blaxel/{client → core/client}/api/jobs/update_job.py +1 -1
- blaxel/{client → core/client}/api/knowledgebases/create_knowledgebase.py +1 -1
- blaxel/{client → core/client}/api/knowledgebases/update_knowledgebase.py +1 -1
- blaxel/{client → core/client}/api/models/create_model.py +1 -1
- blaxel/{client → core/client}/api/models/update_model.py +1 -1
- blaxel/{client → core/client}/api/policies/create_policy.py +1 -1
- blaxel/{client → core/client}/api/policies/update_policy.py +1 -1
- blaxel/{client → core/client}/api/service_accounts/create_api_key_for_service_account.py +1 -1
- blaxel/{client → core/client}/api/service_accounts/create_workspace_service_account.py +1 -1
- blaxel/{client → core/client}/api/service_accounts/update_workspace_service_account.py +1 -1
- blaxel/{client → core/client}/api/workspaces/check_workspace_availability.py +1 -1
- blaxel/{client → core/client}/api/workspaces/create_worspace.py +1 -1
- blaxel/{client → core/client}/api/workspaces/invite_workspace_user.py +1 -1
- blaxel/{client → core/client}/api/workspaces/update_workspace.py +1 -1
- blaxel/{client → core/client}/api/workspaces/update_workspace_user_role.py +1 -1
- blaxel/{client → core/client}/models/agent.py +1 -1
- blaxel/{client → core/client}/models/agent_spec.py +2 -2
- blaxel/{client → core/client}/models/core_spec.py +1 -1
- blaxel/{client → core/client}/models/function.py +1 -1
- blaxel/{client → core/client}/models/function_schema_properties.py +1 -1
- blaxel/{client → core/client}/models/function_spec.py +2 -2
- blaxel/{client → core/client}/models/integration.py +2 -2
- blaxel/{client → core/client}/models/integration_endpoints.py +1 -1
- blaxel/{client → core/client}/models/job.py +1 -1
- blaxel/{client → core/client}/models/job_spec.py +1 -1
- blaxel/{client → core/client}/models/knowledgebase.py +1 -1
- blaxel/{client → core/client}/models/location_response.py +1 -1
- blaxel/{client → core/client}/models/model.py +1 -1
- blaxel/{client → core/client}/models/model_spec.py +1 -1
- blaxel/{client → core/client}/models/policy_spec.py +2 -2
- blaxel/{client → core/client}/models/resource_metrics.py +3 -3
- blaxel/{client → core/client}/models/runtime.py +1 -1
- blaxel/{client → core/client}/models/sandbox.py +1 -1
- blaxel/{client → core/client}/models/sandbox_definition.py +1 -1
- blaxel/{client → core/client}/models/sandbox_spec.py +1 -1
- blaxel/{client → core/client}/models/store_agent.py +1 -1
- blaxel/{client → core/client}/models/store_configuration.py +1 -1
- blaxel/{client → core/client}/models/template.py +1 -1
- blaxel/core/common/__init__.py +6 -0
- blaxel/core/common/autoload.py +21 -0
- blaxel/{common → core/common}/internal.py +33 -62
- blaxel/core/common/logger.py +131 -0
- blaxel/{jobs → core/jobs}/__init__.py +40 -60
- blaxel/core/mcp/__init__.py +4 -0
- blaxel/{mcp → core/mcp}/client.py +13 -7
- blaxel/{mcp → core/mcp}/server.py +4 -30
- blaxel/core/models/__init__.py +52 -0
- blaxel/core/sandbox/__init__.py +29 -0
- blaxel/core/sandbox/action.py +79 -0
- blaxel/{sandbox → core/sandbox}/client/api/filesystem/put_filesystem_path.py +1 -1
- blaxel/{sandbox → core/sandbox}/client/api/network/post_network_process_pid_monitor.py +1 -1
- blaxel/core/sandbox/client/api/process/__init__.py +0 -0
- blaxel/{sandbox → core/sandbox}/client/api/process/post_process.py +1 -1
- blaxel/{sandbox → core/sandbox}/client/models/directory.py +2 -2
- blaxel/core/sandbox/filesystem.py +280 -0
- blaxel/core/sandbox/network.py +10 -0
- blaxel/{sandbox → core/sandbox}/preview.py +45 -17
- blaxel/core/sandbox/process.py +159 -0
- blaxel/{sandbox → core/sandbox}/sandbox.py +62 -5
- blaxel/core/sandbox/session.py +124 -0
- blaxel/core/sandbox/types.py +103 -0
- blaxel/{tools → core/tools}/__init__.py +62 -90
- blaxel/crewai/__init__.py +4 -0
- blaxel/{models/crewai.py → crewai/model.py} +4 -2
- blaxel/crewai/py.typed +0 -0
- blaxel/crewai/tools.py +26 -0
- blaxel/googleadk/__init__.py +4 -0
- blaxel/{models/googleadk.py → googleadk/model.py} +8 -2
- blaxel/googleadk/py.typed +0 -0
- blaxel/googleadk/tools.py +72 -0
- blaxel/langgraph/__init__.py +4 -0
- blaxel/{models/langchain.py → langgraph/model.py} +8 -4
- blaxel/langgraph/py.typed +0 -0
- blaxel/{tools/langchain.py → langgraph/tools.py} +7 -3
- blaxel/livekit/__init__.py +4 -0
- blaxel/{models/livekit.py → livekit/model.py} +7 -1
- blaxel/livekit/py.typed +0 -0
- blaxel/{tools/livekit.py → livekit/tools.py} +8 -1
- blaxel/llamaindex/__init__.py +4 -0
- blaxel/{models/llamaindex.py → llamaindex/model.py} +6 -3
- blaxel/llamaindex/py.typed +0 -0
- blaxel/{tools/llamaindex.py → llamaindex/tools.py} +7 -4
- blaxel/openai/__init__.py +4 -0
- blaxel/{models/openai.py → openai/model.py} +4 -2
- blaxel/openai/py.typed +0 -0
- blaxel/{tools/openai.py → openai/tools.py} +7 -3
- blaxel/pydantic/__init__.py +4 -0
- blaxel/{models/custom/pydantic → pydantic/custom}/gemini.py +0 -1
- blaxel/{models/pydantic.py → pydantic/model.py} +6 -4
- blaxel/pydantic/py.typed +0 -0
- blaxel/{tools/pydantic.py → pydantic/tools.py} +6 -3
- blaxel/telemetry/__init__.py +6 -0
- blaxel/telemetry/instrumentation/blaxel_core.py +124 -0
- blaxel/telemetry/instrumentation/blaxel_langgraph.py +74 -0
- blaxel/telemetry/instrumentation/blaxel_langgraph_gemini.py +360 -0
- blaxel/telemetry/instrumentation/blaxel_llamaindex.py +89 -0
- blaxel/telemetry/instrumentation/map.py +61 -0
- blaxel/telemetry/instrumentation/utils.py +74 -0
- blaxel/{common → telemetry/log}/logger.py +6 -12
- blaxel/{instrumentation → telemetry}/manager.py +20 -12
- blaxel/telemetry/py.typed +0 -0
- blaxel/{instrumentation → telemetry}/span.py +12 -1
- blaxel-0.2.0rc2.dist-info/METADATA +224 -0
- blaxel-0.2.0rc2.dist-info/RECORD +408 -0
- blaxel/common/autoload.py +0 -9
- blaxel/instrumentation/map.py +0 -49
- blaxel/mcp/__init__.py +0 -3
- blaxel/models/__init__.py +0 -104
- blaxel/sandbox/base.py +0 -67
- blaxel/sandbox/filesystem.py +0 -104
- blaxel/sandbox/process.py +0 -56
- blaxel/tools/crewai.py +0 -22
- blaxel/tools/googleadk.py +0 -66
- blaxel-0.1.22rc70.dist-info/METADATA +0 -169
- blaxel-0.1.22rc70.dist-info/RECORD +0 -379
- /blaxel/{authentication → core/authentication}/__init__.py +0 -0
- /blaxel/{authentication → core/authentication}/devicemode.py +0 -0
- /blaxel/{authentication → core/authentication}/oauth.py +0 -0
- /blaxel/{authentication → core/authentication}/types.py +0 -0
- /blaxel/{cache → core/cache}/__init__.py +0 -0
- /blaxel/{cache → core/cache}/cache.py +0 -0
- /blaxel/{client → core/client}/__init__.py +0 -0
- /blaxel/{client → core/client}/api/__init__.py +0 -0
- /blaxel/{client → core/client}/api/agents/__init__.py +0 -0
- /blaxel/{client → core/client}/api/agents/delete_agent.py +0 -0
- /blaxel/{client → core/client}/api/agents/get_agent.py +0 -0
- /blaxel/{client → core/client}/api/agents/list_agent_revisions.py +0 -0
- /blaxel/{client → core/client}/api/agents/list_agents.py +0 -0
- /blaxel/{client → core/client}/api/compute/__init__.py +0 -0
- /blaxel/{client → core/client}/api/compute/delete_sandbox.py +0 -0
- /blaxel/{client → core/client}/api/compute/delete_sandbox_preview.py +0 -0
- /blaxel/{client → core/client}/api/compute/delete_sandbox_preview_token.py +0 -0
- /blaxel/{client → core/client}/api/compute/get_sandbox.py +0 -0
- /blaxel/{client → core/client}/api/compute/get_sandbox_preview.py +0 -0
- /blaxel/{client → core/client}/api/compute/list_sandbox_preview_tokens.py +0 -0
- /blaxel/{client → core/client}/api/compute/list_sandbox_previews.py +0 -0
- /blaxel/{client → core/client}/api/compute/list_sandboxes.py +0 -0
- /blaxel/{client → core/client}/api/compute/start_sandbox.py +0 -0
- /blaxel/{client → core/client}/api/compute/stop_sandbox.py +0 -0
- /blaxel/{client → core/client}/api/configurations/__init__.py +0 -0
- /blaxel/{client → core/client}/api/configurations/get_configuration.py +0 -0
- /blaxel/{client → core/client}/api/default/__init__.py +0 -0
- /blaxel/{client → core/client}/api/default/get_template.py +0 -0
- /blaxel/{client → core/client}/api/default/list_mcp_hub_definitions.py +0 -0
- /blaxel/{client → core/client}/api/default/list_sandbox_hub_definitions.py +0 -0
- /blaxel/{client → core/client}/api/functions/__init__.py +0 -0
- /blaxel/{client → core/client}/api/functions/delete_function.py +0 -0
- /blaxel/{client → core/client}/api/functions/get_function.py +0 -0
- /blaxel/{client → core/client}/api/functions/list_function_revisions.py +0 -0
- /blaxel/{client → core/client}/api/functions/list_functions.py +0 -0
- /blaxel/{client → core/client}/api/integrations/__init__.py +0 -0
- /blaxel/{client → core/client}/api/integrations/delete_integration_connection.py +0 -0
- /blaxel/{client → core/client}/api/integrations/get_integration.py +0 -0
- /blaxel/{client → core/client}/api/integrations/get_integration_connection.py +0 -0
- /blaxel/{client → core/client}/api/integrations/get_integration_connection_model.py +0 -0
- /blaxel/{client → core/client}/api/integrations/get_integration_connection_model_endpoint_configurations.py +0 -0
- /blaxel/{client → core/client}/api/integrations/list_integration_connection_models.py +0 -0
- /blaxel/{client → core/client}/api/integrations/list_integration_connections.py +0 -0
- /blaxel/{client → core/client}/api/invitations/__init__.py +0 -0
- /blaxel/{client → core/client}/api/invitations/list_all_pending_invitations.py +0 -0
- /blaxel/{client → core/client}/api/jobs/__init__.py +0 -0
- /blaxel/{client → core/client}/api/jobs/delete_job.py +0 -0
- /blaxel/{client → core/client}/api/jobs/get_job.py +0 -0
- /blaxel/{client → core/client}/api/jobs/list_job_revisions.py +0 -0
- /blaxel/{client → core/client}/api/jobs/list_jobs.py +0 -0
- /blaxel/{client → core/client}/api/knowledgebases/__init__.py +0 -0
- /blaxel/{client → core/client}/api/knowledgebases/delete_knowledgebase.py +0 -0
- /blaxel/{client → core/client}/api/knowledgebases/get_knowledgebase.py +0 -0
- /blaxel/{client → core/client}/api/knowledgebases/list_knowledgebase_revisions.py +0 -0
- /blaxel/{client → core/client}/api/knowledgebases/list_knowledgebases.py +0 -0
- /blaxel/{client → core/client}/api/locations/__init__.py +0 -0
- /blaxel/{client → core/client}/api/locations/list_locations.py +0 -0
- /blaxel/{client → core/client}/api/models/__init__.py +0 -0
- /blaxel/{client → core/client}/api/models/delete_model.py +0 -0
- /blaxel/{client → core/client}/api/models/get_model.py +0 -0
- /blaxel/{client → core/client}/api/models/list_model_revisions.py +0 -0
- /blaxel/{client → core/client}/api/models/list_models.py +0 -0
- /blaxel/{client → core/client}/api/policies/__init__.py +0 -0
- /blaxel/{client → core/client}/api/policies/delete_policy.py +0 -0
- /blaxel/{client → core/client}/api/policies/get_policy.py +0 -0
- /blaxel/{client → core/client}/api/policies/list_policies.py +0 -0
- /blaxel/{client → core/client}/api/privateclusters/__init__.py +0 -0
- /blaxel/{client → core/client}/api/privateclusters/create_private_cluster.py +0 -0
- /blaxel/{client → core/client}/api/privateclusters/delete_private_cluster.py +0 -0
- /blaxel/{client → core/client}/api/privateclusters/get_private_cluster.py +0 -0
- /blaxel/{client → core/client}/api/privateclusters/get_private_cluster_health.py +0 -0
- /blaxel/{client → core/client}/api/privateclusters/list_private_clusters.py +0 -0
- /blaxel/{client → core/client}/api/privateclusters/update_private_cluster.py +0 -0
- /blaxel/{client → core/client}/api/privateclusters/update_private_cluster_health.py +0 -0
- /blaxel/{client → core/client}/api/service_accounts/__init__.py +0 -0
- /blaxel/{client → core/client}/api/service_accounts/delete_api_key_for_service_account.py +0 -0
- /blaxel/{client → core/client}/api/service_accounts/delete_workspace_service_account.py +0 -0
- /blaxel/{client → core/client}/api/service_accounts/get_workspace_service_accounts.py +0 -0
- /blaxel/{client → core/client}/api/service_accounts/list_api_keys_for_service_account.py +0 -0
- /blaxel/{client → core/client}/api/templates/__init__.py +0 -0
- /blaxel/{client → core/client}/api/templates/list_templates.py +0 -0
- /blaxel/{client → core/client}/api/workspaces/__init__.py +0 -0
- /blaxel/{client → core/client}/api/workspaces/accept_workspace_invitation.py +0 -0
- /blaxel/{client → core/client}/api/workspaces/decline_workspace_invitation.py +0 -0
- /blaxel/{client → core/client}/api/workspaces/delete_workspace.py +0 -0
- /blaxel/{client → core/client}/api/workspaces/get_workspace.py +0 -0
- /blaxel/{client → core/client}/api/workspaces/leave_workspace.py +0 -0
- /blaxel/{client → core/client}/api/workspaces/list_workspace_users.py +0 -0
- /blaxel/{client → core/client}/api/workspaces/list_workspaces.py +0 -0
- /blaxel/{client → core/client}/api/workspaces/remove_workspace_user.py +0 -0
- /blaxel/{client → core/client}/client.py +0 -0
- /blaxel/{client → core/client}/errors.py +0 -0
- /blaxel/{client → core/client}/models/__init__.py +0 -0
- /blaxel/{client → core/client}/models/acl.py +0 -0
- /blaxel/{client → core/client}/models/api_key.py +0 -0
- /blaxel/{client → core/client}/models/billable_time_metric.py +0 -0
- /blaxel/{client → core/client}/models/check_workspace_availability_body.py +0 -0
- /blaxel/{client → core/client}/models/configuration.py +0 -0
- /blaxel/{client → core/client}/models/continent.py +0 -0
- /blaxel/{client → core/client}/models/core_event.py +0 -0
- /blaxel/{client → core/client}/models/core_spec_configurations.py +0 -0
- /blaxel/{client → core/client}/models/country.py +0 -0
- /blaxel/{client → core/client}/models/create_api_key_for_service_account_body.py +0 -0
- /blaxel/{client → core/client}/models/create_workspace_service_account_body.py +0 -0
- /blaxel/{client → core/client}/models/create_workspace_service_account_response_200.py +0 -0
- /blaxel/{client → core/client}/models/delete_sandbox_preview_token_response_200.py +0 -0
- /blaxel/{client → core/client}/models/delete_workspace_service_account_response_200.py +0 -0
- /blaxel/{client → core/client}/models/entrypoint.py +0 -0
- /blaxel/{client → core/client}/models/entrypoint_env.py +0 -0
- /blaxel/{client → core/client}/models/flavor.py +0 -0
- /blaxel/{client → core/client}/models/form.py +0 -0
- /blaxel/{client → core/client}/models/form_config.py +0 -0
- /blaxel/{client → core/client}/models/form_oauth.py +0 -0
- /blaxel/{client → core/client}/models/form_secrets.py +0 -0
- /blaxel/{client → core/client}/models/function_kit.py +0 -0
- /blaxel/{client → core/client}/models/function_schema.py +0 -0
- /blaxel/{client → core/client}/models/function_schema_not.py +0 -0
- /blaxel/{client → core/client}/models/function_schema_or_bool.py +0 -0
- /blaxel/{client → core/client}/models/get_workspace_service_accounts_response_200_item.py +0 -0
- /blaxel/{client → core/client}/models/histogram_bucket.py +0 -0
- /blaxel/{client → core/client}/models/histogram_stats.py +0 -0
- /blaxel/{client → core/client}/models/integration_additional_infos.py +0 -0
- /blaxel/{client → core/client}/models/integration_connection.py +0 -0
- /blaxel/{client → core/client}/models/integration_connection_spec.py +0 -0
- /blaxel/{client → core/client}/models/integration_connection_spec_config.py +0 -0
- /blaxel/{client → core/client}/models/integration_connection_spec_secret.py +0 -0
- /blaxel/{client → core/client}/models/integration_endpoint.py +0 -0
- /blaxel/{client → core/client}/models/integration_endpoint_token.py +0 -0
- /blaxel/{client → core/client}/models/integration_headers.py +0 -0
- /blaxel/{client → core/client}/models/integration_model.py +0 -0
- /blaxel/{client → core/client}/models/integration_organization.py +0 -0
- /blaxel/{client → core/client}/models/integration_query_params.py +0 -0
- /blaxel/{client → core/client}/models/integration_repository.py +0 -0
- /blaxel/{client → core/client}/models/invite_workspace_user_body.py +0 -0
- /blaxel/{client → core/client}/models/job_execution_config.py +0 -0
- /blaxel/{client → core/client}/models/job_metrics.py +0 -0
- /blaxel/{client → core/client}/models/job_metrics_executions_chart.py +0 -0
- /blaxel/{client → core/client}/models/job_metrics_executions_total.py +0 -0
- /blaxel/{client → core/client}/models/job_metrics_tasks_chart.py +0 -0
- /blaxel/{client → core/client}/models/job_metrics_tasks_total.py +0 -0
- /blaxel/{client → core/client}/models/jobs_chart.py +0 -0
- /blaxel/{client → core/client}/models/jobs_chart_value.py +0 -0
- /blaxel/{client → core/client}/models/jobs_executions.py +0 -0
- /blaxel/{client → core/client}/models/jobs_network_chart.py +0 -0
- /blaxel/{client → core/client}/models/jobs_success_failed_chart.py +0 -0
- /blaxel/{client → core/client}/models/jobs_tasks.py +0 -0
- /blaxel/{client → core/client}/models/jobs_total.py +0 -0
- /blaxel/{client → core/client}/models/knowledgebase_spec.py +0 -0
- /blaxel/{client → core/client}/models/knowledgebase_spec_options.py +0 -0
- /blaxel/{client → core/client}/models/last_n_requests_metric.py +0 -0
- /blaxel/{client → core/client}/models/latency_metric.py +0 -0
- /blaxel/{client → core/client}/models/logs_response.py +0 -0
- /blaxel/{client → core/client}/models/logs_response_data.py +0 -0
- /blaxel/{client → core/client}/models/mcp_definition.py +0 -0
- /blaxel/{client → core/client}/models/mcp_definition_entrypoint.py +0 -0
- /blaxel/{client → core/client}/models/mcp_definition_form.py +0 -0
- /blaxel/{client → core/client}/models/memory_allocation_by_name.py +0 -0
- /blaxel/{client → core/client}/models/memory_allocation_metric.py +0 -0
- /blaxel/{client → core/client}/models/metadata.py +0 -0
- /blaxel/{client → core/client}/models/metadata_labels.py +0 -0
- /blaxel/{client → core/client}/models/metric.py +0 -0
- /blaxel/{client → core/client}/models/metrics.py +0 -0
- /blaxel/{client → core/client}/models/metrics_models.py +0 -0
- /blaxel/{client → core/client}/models/metrics_request_total_per_code.py +0 -0
- /blaxel/{client → core/client}/models/metrics_rps_per_code.py +0 -0
- /blaxel/{client → core/client}/models/model_private_cluster.py +0 -0
- /blaxel/{client → core/client}/models/o_auth.py +0 -0
- /blaxel/{client → core/client}/models/owner_fields.py +0 -0
- /blaxel/{client → core/client}/models/pending_invitation.py +0 -0
- /blaxel/{client → core/client}/models/pending_invitation_accept.py +0 -0
- /blaxel/{client → core/client}/models/pending_invitation_render.py +0 -0
- /blaxel/{client → core/client}/models/pending_invitation_render_invited_by.py +0 -0
- /blaxel/{client → core/client}/models/pending_invitation_render_workspace.py +0 -0
- /blaxel/{client → core/client}/models/pending_invitation_workspace_details.py +0 -0
- /blaxel/{client → core/client}/models/pod_template_spec.py +0 -0
- /blaxel/{client → core/client}/models/policy.py +0 -0
- /blaxel/{client → core/client}/models/policy_location.py +0 -0
- /blaxel/{client → core/client}/models/policy_max_tokens.py +0 -0
- /blaxel/{client → core/client}/models/port.py +0 -0
- /blaxel/{client → core/client}/models/preview.py +0 -0
- /blaxel/{client → core/client}/models/preview_metadata.py +0 -0
- /blaxel/{client → core/client}/models/preview_spec.py +0 -0
- /blaxel/{client → core/client}/models/preview_spec_request_headers.py +0 -0
- /blaxel/{client → core/client}/models/preview_spec_response_headers.py +0 -0
- /blaxel/{client → core/client}/models/preview_token.py +0 -0
- /blaxel/{client → core/client}/models/preview_token_metadata.py +0 -0
- /blaxel/{client → core/client}/models/preview_token_spec.py +0 -0
- /blaxel/{client → core/client}/models/private_cluster.py +0 -0
- /blaxel/{client → core/client}/models/private_location.py +0 -0
- /blaxel/{client → core/client}/models/repository.py +0 -0
- /blaxel/{client → core/client}/models/request_duration_over_time_metric.py +0 -0
- /blaxel/{client → core/client}/models/request_duration_over_time_metrics.py +0 -0
- /blaxel/{client → core/client}/models/request_total_by_origin_metric.py +0 -0
- /blaxel/{client → core/client}/models/request_total_by_origin_metric_request_total_by_origin.py +0 -0
- /blaxel/{client → core/client}/models/request_total_by_origin_metric_request_total_by_origin_and_code.py +0 -0
- /blaxel/{client → core/client}/models/request_total_metric.py +0 -0
- /blaxel/{client → core/client}/models/request_total_metric_request_total_per_code.py +0 -0
- /blaxel/{client → core/client}/models/request_total_metric_rps_per_code.py +0 -0
- /blaxel/{client → core/client}/models/request_total_response_data.py +0 -0
- /blaxel/{client → core/client}/models/resource.py +0 -0
- /blaxel/{client → core/client}/models/resource_log.py +0 -0
- /blaxel/{client → core/client}/models/resource_log_chart.py +0 -0
- /blaxel/{client → core/client}/models/resource_log_response.py +0 -0
- /blaxel/{client → core/client}/models/resource_metrics_request_total_per_code.py +0 -0
- /blaxel/{client → core/client}/models/resource_metrics_request_total_per_code_previous.py +0 -0
- /blaxel/{client → core/client}/models/resource_metrics_rps_per_code.py +0 -0
- /blaxel/{client → core/client}/models/resource_metrics_rps_per_code_previous.py +0 -0
- /blaxel/{client → core/client}/models/resource_trace.py +0 -0
- /blaxel/{client → core/client}/models/revision_configuration.py +0 -0
- /blaxel/{client → core/client}/models/revision_metadata.py +0 -0
- /blaxel/{client → core/client}/models/runtime_configuration.py +0 -0
- /blaxel/{client → core/client}/models/runtime_startup_probe.py +0 -0
- /blaxel/{client → core/client}/models/serverless_config.py +0 -0
- /blaxel/{client → core/client}/models/serverless_config_configuration.py +0 -0
- /blaxel/{client → core/client}/models/spec_configuration.py +0 -0
- /blaxel/{client → core/client}/models/start_sandbox.py +0 -0
- /blaxel/{client → core/client}/models/stop_sandbox.py +0 -0
- /blaxel/{client → core/client}/models/store_agent_labels.py +0 -0
- /blaxel/{client → core/client}/models/store_configuration_option.py +0 -0
- /blaxel/{client → core/client}/models/template_variable.py +0 -0
- /blaxel/{client → core/client}/models/time_fields.py +0 -0
- /blaxel/{client → core/client}/models/time_to_first_token_over_time_metrics.py +0 -0
- /blaxel/{client → core/client}/models/token_rate_metric.py +0 -0
- /blaxel/{client → core/client}/models/token_rate_metrics.py +0 -0
- /blaxel/{client → core/client}/models/token_total_metric.py +0 -0
- /blaxel/{client → core/client}/models/trace_ids_response.py +0 -0
- /blaxel/{client → core/client}/models/trigger.py +0 -0
- /blaxel/{client → core/client}/models/trigger_configuration.py +0 -0
- /blaxel/{client → core/client}/models/update_workspace_service_account_body.py +0 -0
- /blaxel/{client → core/client}/models/update_workspace_service_account_response_200.py +0 -0
- /blaxel/{client → core/client}/models/update_workspace_user_role_body.py +0 -0
- /blaxel/{client → core/client}/models/websocket_channel.py +0 -0
- /blaxel/{client → core/client}/models/websocket_message.py +0 -0
- /blaxel/{client → core/client}/models/workspace.py +0 -0
- /blaxel/{client → core/client}/models/workspace_labels.py +0 -0
- /blaxel/{client → core/client}/models/workspace_runtime.py +0 -0
- /blaxel/{client → core/client}/models/workspace_user.py +0 -0
- /blaxel/{client → core/client}/py.typed +0 -0
- /blaxel/{client → core/client}/types.py +0 -0
- /blaxel/{common → core/common}/env.py +0 -0
- /blaxel/{common → core/common}/settings.py +0 -0
- /blaxel/{sandbox/client/api/filesystem/__init__.py → core/py.typed} +0 -0
- /blaxel/{sandbox → core/sandbox}/client/__init__.py +0 -0
- /blaxel/{sandbox → core/sandbox}/client/api/__init__.py +0 -0
- /blaxel/{sandbox/client/api/network → core/sandbox/client/api/filesystem}/__init__.py +0 -0
- /blaxel/{sandbox → core/sandbox}/client/api/filesystem/delete_filesystem_path.py +0 -0
- /blaxel/{sandbox → core/sandbox}/client/api/filesystem/get_filesystem_path.py +0 -0
- /blaxel/{sandbox → core/sandbox}/client/api/filesystem/get_watch_filesystem_path.py +0 -0
- /blaxel/{sandbox → core/sandbox}/client/api/filesystem/get_ws_watch_filesystem_path.py +0 -0
- /blaxel/{sandbox/client/api/process → core/sandbox/client/api/network}/__init__.py +0 -0
- /blaxel/{sandbox → core/sandbox}/client/api/network/delete_network_process_pid_monitor.py +0 -0
- /blaxel/{sandbox → core/sandbox}/client/api/network/get_network_process_pid_ports.py +0 -0
- /blaxel/{sandbox → core/sandbox}/client/api/process/delete_process_identifier.py +0 -0
- /blaxel/{sandbox → core/sandbox}/client/api/process/delete_process_identifier_kill.py +0 -0
- /blaxel/{sandbox → core/sandbox}/client/api/process/get_process.py +0 -0
- /blaxel/{sandbox → core/sandbox}/client/api/process/get_process_identifier.py +0 -0
- /blaxel/{sandbox → core/sandbox}/client/api/process/get_process_identifier_logs.py +0 -0
- /blaxel/{sandbox → core/sandbox}/client/api/process/get_process_identifier_logs_stream.py +0 -0
- /blaxel/{sandbox → core/sandbox}/client/api/process/get_ws_process_identifier_logs_stream.py +0 -0
- /blaxel/{sandbox → core/sandbox}/client/client.py +0 -0
- /blaxel/{sandbox → core/sandbox}/client/errors.py +0 -0
- /blaxel/{sandbox → core/sandbox}/client/models/__init__.py +0 -0
- /blaxel/{sandbox → core/sandbox}/client/models/delete_network_process_pid_monitor_response_200.py +0 -0
- /blaxel/{sandbox → core/sandbox}/client/models/error_response.py +0 -0
- /blaxel/{sandbox → core/sandbox}/client/models/file.py +0 -0
- /blaxel/{sandbox → core/sandbox}/client/models/file_request.py +0 -0
- /blaxel/{sandbox → core/sandbox}/client/models/file_with_content.py +0 -0
- /blaxel/{sandbox → core/sandbox}/client/models/get_network_process_pid_ports_response_200.py +0 -0
- /blaxel/{sandbox → core/sandbox}/client/models/port_monitor_request.py +0 -0
- /blaxel/{sandbox → core/sandbox}/client/models/post_network_process_pid_monitor_response_200.py +0 -0
- /blaxel/{sandbox → core/sandbox}/client/models/process_logs.py +0 -0
- /blaxel/{sandbox → core/sandbox}/client/models/process_request.py +0 -0
- /blaxel/{sandbox → core/sandbox}/client/models/process_request_env.py +0 -0
- /blaxel/{sandbox → core/sandbox}/client/models/process_response.py +0 -0
- /blaxel/{sandbox → core/sandbox}/client/models/process_response_status.py +0 -0
- /blaxel/{sandbox → core/sandbox}/client/models/subdirectory.py +0 -0
- /blaxel/{sandbox → core/sandbox}/client/models/success_response.py +0 -0
- /blaxel/{sandbox → core/sandbox}/client/py.typed +0 -0
- /blaxel/{sandbox → core/sandbox}/client/types.py +0 -0
- /blaxel/{tools → core/tools}/common.py +0 -0
- /blaxel/{tools → core/tools}/types.py +0 -0
- /blaxel/{models/custom/langchain → langgraph/custom}/gemini.py +0 -0
- /blaxel/{models/custom/llamaindex → llamaindex/custom}/cohere.py +0 -0
- /blaxel/{instrumentation → telemetry}/exporters.py +0 -0
- /blaxel/{instrumentation → telemetry/log}/log.py +0 -0
- {blaxel-0.1.22rc70.dist-info → blaxel-0.2.0rc2.dist-info}/WHEEL +0 -0
- {blaxel-0.1.22rc70.dist-info → blaxel-0.2.0rc2.dist-info}/licenses/LICENSE +0 -0
@@ -1,25 +1,38 @@
|
|
1
1
|
from dataclasses import dataclass
|
2
2
|
from datetime import datetime
|
3
|
-
from typing import List, Optional
|
3
|
+
from typing import Any, Dict, List, Optional, Union
|
4
4
|
|
5
|
-
from ..client.api.compute.create_sandbox_preview import
|
5
|
+
from ..client.api.compute.create_sandbox_preview import (
|
6
|
+
asyncio as create_sandbox_preview,
|
7
|
+
)
|
6
8
|
from ..client.api.compute.create_sandbox_preview_token import (
|
7
9
|
asyncio as create_sandbox_preview_token,
|
8
10
|
)
|
9
|
-
from ..client.api.compute.delete_sandbox_preview import
|
11
|
+
from ..client.api.compute.delete_sandbox_preview import (
|
12
|
+
asyncio as delete_sandbox_preview,
|
13
|
+
)
|
10
14
|
from ..client.api.compute.delete_sandbox_preview_token import (
|
11
15
|
asyncio as delete_sandbox_preview_token,
|
12
16
|
)
|
13
17
|
from ..client.api.compute.get_sandbox_preview import asyncio as get_sandbox_preview
|
14
|
-
from ..client.api.compute.list_sandbox_preview_tokens import
|
18
|
+
from ..client.api.compute.list_sandbox_preview_tokens import (
|
19
|
+
asyncio as list_sandbox_preview_tokens,
|
20
|
+
)
|
15
21
|
from ..client.api.compute.list_sandbox_previews import asyncio as list_sandbox_previews
|
16
22
|
from ..client.client import client
|
17
|
-
from ..client.models import
|
23
|
+
from ..client.models import (
|
24
|
+
Preview,
|
25
|
+
PreviewSpec,
|
26
|
+
PreviewToken,
|
27
|
+
PreviewTokenSpec,
|
28
|
+
Sandbox,
|
29
|
+
)
|
18
30
|
|
19
31
|
|
20
32
|
@dataclass
|
21
33
|
class SandboxPreviewToken:
|
22
34
|
"""Represents a preview token with its value and expiration."""
|
35
|
+
|
23
36
|
preview_token: PreviewToken
|
24
37
|
|
25
38
|
@property
|
@@ -30,23 +43,22 @@ class SandboxPreviewToken:
|
|
30
43
|
def expires_at(self) -> datetime:
|
31
44
|
return self.preview_token.spec.expires_at if self.preview_token.spec else datetime.now()
|
32
45
|
|
46
|
+
|
33
47
|
class SandboxPreviewTokens:
|
34
48
|
"""Manages preview tokens for a sandbox preview."""
|
35
|
-
|
49
|
+
|
50
|
+
def __init__(self, preview: Preview, sandbox_name: str):
|
36
51
|
self.preview = preview
|
52
|
+
self.sandbox_name = sandbox_name
|
37
53
|
|
38
54
|
@property
|
39
55
|
def preview_name(self) -> str:
|
40
56
|
return self.preview.metadata.name if self.preview.metadata else ""
|
41
57
|
|
42
|
-
@property
|
43
|
-
def resource_name(self) -> str:
|
44
|
-
return self.preview.metadata.resource_name if self.preview.metadata else ""
|
45
|
-
|
46
58
|
async def create(self, expires_at: datetime) -> SandboxPreviewToken:
|
47
59
|
"""Create a new preview token."""
|
48
60
|
response: PreviewToken = await create_sandbox_preview_token(
|
49
|
-
self.
|
61
|
+
self.sandbox_name,
|
50
62
|
self.preview_name,
|
51
63
|
body=PreviewToken(
|
52
64
|
spec=PreviewTokenSpec(
|
@@ -60,7 +72,7 @@ class SandboxPreviewTokens:
|
|
60
72
|
async def list(self) -> List[SandboxPreviewToken]:
|
61
73
|
"""List all preview tokens."""
|
62
74
|
response: List[PreviewToken] = await list_sandbox_preview_tokens(
|
63
|
-
self.
|
75
|
+
self.sandbox_name,
|
64
76
|
self.preview_name,
|
65
77
|
client=client,
|
66
78
|
)
|
@@ -69,18 +81,21 @@ class SandboxPreviewTokens:
|
|
69
81
|
async def delete(self, token_name: str) -> dict:
|
70
82
|
"""Delete a preview token."""
|
71
83
|
response: PreviewToken = await delete_sandbox_preview_token(
|
72
|
-
self.
|
84
|
+
self.sandbox_name,
|
73
85
|
self.preview_name,
|
74
86
|
token_name,
|
75
87
|
client=client,
|
76
88
|
)
|
77
89
|
return response
|
78
90
|
|
91
|
+
|
79
92
|
class SandboxPreview:
|
80
93
|
"""Represents a sandbox preview with its metadata and tokens."""
|
81
|
-
|
94
|
+
|
95
|
+
def __init__(self, preview: Preview, sandbox_name: str = ""):
|
82
96
|
self.preview = preview
|
83
|
-
self.
|
97
|
+
self.sandbox_name = sandbox_name
|
98
|
+
self.tokens = SandboxPreviewTokens(preview, sandbox_name)
|
84
99
|
|
85
100
|
@property
|
86
101
|
def name(self) -> str:
|
@@ -94,8 +109,10 @@ class SandboxPreview:
|
|
94
109
|
def spec(self) -> Optional[PreviewSpec]:
|
95
110
|
return self.preview.spec
|
96
111
|
|
112
|
+
|
97
113
|
class SandboxPreviews:
|
98
114
|
"""Manages sandbox previews."""
|
115
|
+
|
99
116
|
def __init__(self, sandbox: Sandbox):
|
100
117
|
self.sandbox = sandbox
|
101
118
|
|
@@ -111,8 +128,11 @@ class SandboxPreviews:
|
|
111
128
|
)
|
112
129
|
return [SandboxPreview(preview) for preview in response]
|
113
130
|
|
114
|
-
async def create(self, preview: Preview) -> SandboxPreview:
|
131
|
+
async def create(self, preview: Union[Preview, Dict[str, Any]]) -> SandboxPreview:
|
115
132
|
"""Create a new preview."""
|
133
|
+
if isinstance(preview, dict):
|
134
|
+
preview = Preview.from_dict(preview)
|
135
|
+
|
116
136
|
response: Preview = await create_sandbox_preview(
|
117
137
|
self.sandbox_name,
|
118
138
|
body=preview,
|
@@ -138,5 +158,13 @@ class SandboxPreviews:
|
|
138
158
|
)
|
139
159
|
return response
|
140
160
|
|
161
|
+
|
141
162
|
def to_utc_z(dt: datetime) -> str:
|
142
|
-
|
163
|
+
"""Convert datetime to UTC Z format string."""
|
164
|
+
# Simple approach: format as ISO string and add Z
|
165
|
+
iso_string = dt.isoformat()
|
166
|
+
if iso_string.endswith("+00:00"):
|
167
|
+
return iso_string.replace("+00:00", "Z")
|
168
|
+
elif "T" in iso_string and not iso_string.endswith("Z"):
|
169
|
+
return iso_string + "Z"
|
170
|
+
return iso_string
|
@@ -0,0 +1,159 @@
|
|
1
|
+
import asyncio
|
2
|
+
from typing import Any, Callable, Dict, Literal, Optional, Union
|
3
|
+
|
4
|
+
import httpx
|
5
|
+
|
6
|
+
from ..common.settings import settings
|
7
|
+
from .action import SandboxAction
|
8
|
+
from .client.models import ProcessResponse, SuccessResponse
|
9
|
+
from .client.models.process_request import ProcessRequest
|
10
|
+
from .types import SandboxConfiguration
|
11
|
+
|
12
|
+
|
13
|
+
class SandboxProcess(SandboxAction):
|
14
|
+
def __init__(self, sandbox_config: SandboxConfiguration):
|
15
|
+
super().__init__(sandbox_config)
|
16
|
+
|
17
|
+
def stream_logs(
|
18
|
+
self, identifier: str, options: Optional[Dict[str, Callable[[str], None]]] = None
|
19
|
+
) -> Dict[str, Callable[[], None]]:
|
20
|
+
"""Stream logs from a process with callbacks for different output types."""
|
21
|
+
if options is None:
|
22
|
+
options = {}
|
23
|
+
|
24
|
+
closed = False
|
25
|
+
|
26
|
+
async def start_streaming():
|
27
|
+
nonlocal closed
|
28
|
+
|
29
|
+
url = f"{self.url}/process/{identifier}/logs/stream"
|
30
|
+
headers = {**settings.headers, **self.sandbox_config.headers}
|
31
|
+
|
32
|
+
try:
|
33
|
+
async with httpx.AsyncClient() as client_instance:
|
34
|
+
async with client_instance.stream("GET", url, headers=headers) as response:
|
35
|
+
if response.status_code != 200:
|
36
|
+
raise Exception(f"Failed to stream logs: {await response.aread()}")
|
37
|
+
|
38
|
+
buffer = ""
|
39
|
+
async for chunk in response.aiter_text():
|
40
|
+
if closed:
|
41
|
+
break
|
42
|
+
|
43
|
+
buffer += chunk
|
44
|
+
lines = buffer.split("\n")
|
45
|
+
buffer = lines.pop() # Keep incomplete line in buffer
|
46
|
+
|
47
|
+
for line in lines:
|
48
|
+
if line.startswith("stdout:"):
|
49
|
+
content = line[7:] # Remove 'stdout:' prefix
|
50
|
+
if options.get("on_stdout"):
|
51
|
+
options["on_stdout"](content)
|
52
|
+
if options.get("on_log"):
|
53
|
+
options["on_log"](content)
|
54
|
+
elif line.startswith("stderr:"):
|
55
|
+
content = line[7:] # Remove 'stderr:' prefix
|
56
|
+
if options.get("on_stderr"):
|
57
|
+
options["on_stderr"](content)
|
58
|
+
if options.get("on_log"):
|
59
|
+
options["on_log"](content)
|
60
|
+
else:
|
61
|
+
if options.get("on_log"):
|
62
|
+
options["on_log"](line)
|
63
|
+
except Exception as e:
|
64
|
+
# Suppress AbortError when closing
|
65
|
+
if not (hasattr(e, "name") and e.name == "AbortError"):
|
66
|
+
raise e
|
67
|
+
|
68
|
+
# Start streaming in the background
|
69
|
+
task = asyncio.create_task(start_streaming())
|
70
|
+
|
71
|
+
def close():
|
72
|
+
nonlocal closed
|
73
|
+
closed = True
|
74
|
+
task.cancel()
|
75
|
+
|
76
|
+
return {"close": close}
|
77
|
+
|
78
|
+
async def exec(self, process: Union[ProcessRequest, Dict[str, Any]]) -> ProcessResponse:
|
79
|
+
if isinstance(process, dict):
|
80
|
+
process = ProcessRequest.from_dict(process)
|
81
|
+
|
82
|
+
async with self.get_client() as client_instance:
|
83
|
+
response = await client_instance.post("/process", json=process.to_dict())
|
84
|
+
self.handle_response_error(
|
85
|
+
response, response.json() if response.content else None, None
|
86
|
+
)
|
87
|
+
return ProcessResponse.from_dict(response.json())
|
88
|
+
|
89
|
+
async def wait(
|
90
|
+
self, identifier: str, max_wait: int = 60000, interval: int = 1000
|
91
|
+
) -> ProcessResponse:
|
92
|
+
"""Wait for a process to complete."""
|
93
|
+
start_time = asyncio.get_event_loop().time() * 1000 # Convert to milliseconds
|
94
|
+
status = "running"
|
95
|
+
data = await self.get(identifier)
|
96
|
+
|
97
|
+
while status == "running":
|
98
|
+
await asyncio.sleep(interval / 1000) # Convert to seconds
|
99
|
+
try:
|
100
|
+
data = await self.get(identifier)
|
101
|
+
status = data.status or "running"
|
102
|
+
except:
|
103
|
+
break
|
104
|
+
|
105
|
+
if (asyncio.get_event_loop().time() * 1000) - start_time > max_wait:
|
106
|
+
raise Exception("Process did not finish in time")
|
107
|
+
|
108
|
+
return data
|
109
|
+
|
110
|
+
async def get(self, identifier: str) -> ProcessResponse:
|
111
|
+
async with self.get_client() as client_instance:
|
112
|
+
response = await client_instance.get(f"/process/{identifier}")
|
113
|
+
self.handle_response_error(
|
114
|
+
response, response.json() if response.content else None, None
|
115
|
+
)
|
116
|
+
return ProcessResponse.from_dict(response.json())
|
117
|
+
|
118
|
+
async def list(self) -> list[ProcessResponse]:
|
119
|
+
async with self.get_client() as client_instance:
|
120
|
+
response = await client_instance.get("/process")
|
121
|
+
self.handle_response_error(
|
122
|
+
response, response.json() if response.content else None, None
|
123
|
+
)
|
124
|
+
return [ProcessResponse.from_dict(item) for item in response.json()]
|
125
|
+
|
126
|
+
async def stop(self, identifier: str) -> SuccessResponse:
|
127
|
+
async with self.get_client() as client_instance:
|
128
|
+
response = await client_instance.delete(f"/process/{identifier}")
|
129
|
+
self.handle_response_error(
|
130
|
+
response, response.json() if response.content else None, None
|
131
|
+
)
|
132
|
+
return SuccessResponse.from_dict(response.json())
|
133
|
+
|
134
|
+
async def kill(self, identifier: str) -> SuccessResponse:
|
135
|
+
async with self.get_client() as client_instance:
|
136
|
+
response = await client_instance.delete(f"/process/{identifier}/kill")
|
137
|
+
self.handle_response_error(
|
138
|
+
response, response.json() if response.content else None, None
|
139
|
+
)
|
140
|
+
return SuccessResponse.from_dict(response.json())
|
141
|
+
|
142
|
+
async def logs(
|
143
|
+
self, identifier: str, log_type: Literal["stdout", "stderr", "all"] = "all"
|
144
|
+
) -> str:
|
145
|
+
async with self.get_client() as client_instance:
|
146
|
+
response = await client_instance.get(f"/process/{identifier}/logs")
|
147
|
+
self.handle_response_error(
|
148
|
+
response, response.json() if response.content else None, None
|
149
|
+
)
|
150
|
+
|
151
|
+
data = response.json()
|
152
|
+
if log_type == "all":
|
153
|
+
return data.get("logs", "")
|
154
|
+
elif log_type == "stdout":
|
155
|
+
return data.get("stdout", "")
|
156
|
+
elif log_type == "stderr":
|
157
|
+
return data.get("stderr", "")
|
158
|
+
|
159
|
+
raise Exception("Unsupported log type")
|
@@ -1,26 +1,33 @@
|
|
1
1
|
import asyncio
|
2
2
|
import logging
|
3
3
|
import time
|
4
|
-
from typing import List
|
4
|
+
from typing import Any, Dict, List, Union
|
5
5
|
|
6
6
|
from ..client.api.compute.create_sandbox import asyncio as create_sandbox
|
7
7
|
from ..client.api.compute.delete_sandbox import asyncio as delete_sandbox
|
8
8
|
from ..client.api.compute.get_sandbox import asyncio as get_sandbox
|
9
9
|
from ..client.api.compute.list_sandboxes import asyncio as list_sandboxes
|
10
10
|
from ..client.client import client
|
11
|
-
from ..client.models import Sandbox
|
11
|
+
from ..client.models import Metadata, Sandbox
|
12
12
|
from .filesystem import SandboxFileSystem
|
13
|
+
from .network import SandboxNetwork
|
13
14
|
from .preview import SandboxPreviews
|
14
15
|
from .process import SandboxProcess
|
16
|
+
from .session import SandboxSessions
|
17
|
+
from .types import SandboxConfiguration, SessionWithToken
|
15
18
|
|
16
19
|
logger = logging.getLogger(__name__)
|
17
20
|
|
21
|
+
|
18
22
|
class SandboxInstance:
|
19
23
|
def __init__(self, sandbox: Sandbox):
|
20
24
|
self.sandbox = sandbox
|
21
|
-
self.
|
22
|
-
self.
|
25
|
+
self.config = SandboxConfiguration(sandbox)
|
26
|
+
self.fs = SandboxFileSystem(self.config)
|
27
|
+
self.process = SandboxProcess(self.config)
|
23
28
|
self.previews = SandboxPreviews(sandbox)
|
29
|
+
self.sessions = SandboxSessions(self.config)
|
30
|
+
self.network = SandboxNetwork(self.config)
|
24
31
|
|
25
32
|
@property
|
26
33
|
def metadata(self):
|
@@ -49,6 +56,7 @@ class SandboxInstance:
|
|
49
56
|
)
|
50
57
|
logger.info(f"Waiting for sandbox to be deployed, status: {response.status}")
|
51
58
|
self.sandbox = response
|
59
|
+
self.config = SandboxConfiguration(self.sandbox)
|
52
60
|
except Exception as e:
|
53
61
|
logger.error("Could not retrieve sandbox", exc_info=e)
|
54
62
|
|
@@ -59,7 +67,10 @@ class SandboxInstance:
|
|
59
67
|
raise Exception("Sandbox did not deploy in time")
|
60
68
|
|
61
69
|
@classmethod
|
62
|
-
async def create(cls, sandbox: Sandbox) -> "SandboxInstance":
|
70
|
+
async def create(cls, sandbox: Union[Sandbox, Dict[str, Any]]) -> "SandboxInstance":
|
71
|
+
if isinstance(sandbox, dict):
|
72
|
+
sandbox = Sandbox.from_dict(sandbox)
|
73
|
+
|
63
74
|
if not sandbox.spec:
|
64
75
|
raise Exception("Sandbox spec is required")
|
65
76
|
if not sandbox.spec.runtime:
|
@@ -92,3 +103,49 @@ class SandboxInstance:
|
|
92
103
|
client=client,
|
93
104
|
)
|
94
105
|
return response
|
106
|
+
|
107
|
+
@classmethod
|
108
|
+
async def create_if_not_exists(
|
109
|
+
cls, sandbox: Union[Sandbox, Dict[str, Any]]
|
110
|
+
) -> "SandboxInstance":
|
111
|
+
"""Create a sandbox if it doesn't exist, otherwise return existing."""
|
112
|
+
if isinstance(sandbox, dict):
|
113
|
+
sandbox = Sandbox.from_dict(sandbox)
|
114
|
+
|
115
|
+
try:
|
116
|
+
sandbox_instance = await cls.get(sandbox.metadata.name)
|
117
|
+
return sandbox_instance
|
118
|
+
except Exception as e:
|
119
|
+
# Check if it's a 404 error (sandbox not found)
|
120
|
+
if hasattr(e, "status_code") and e.status_code == 404:
|
121
|
+
return await cls.create(sandbox)
|
122
|
+
raise e
|
123
|
+
|
124
|
+
@classmethod
|
125
|
+
async def from_session(
|
126
|
+
cls, session: Union[SessionWithToken, Dict[str, Any]]
|
127
|
+
) -> "SandboxInstance":
|
128
|
+
"""Create a sandbox instance from a session with token."""
|
129
|
+
if isinstance(session, dict):
|
130
|
+
session = SessionWithToken.from_dict(session)
|
131
|
+
|
132
|
+
# Create a minimal sandbox configuration for session-based access
|
133
|
+
sandbox_name = session.name.split("-")[0] if "-" in session.name else session.name
|
134
|
+
sandbox = Sandbox(metadata=Metadata(name=sandbox_name))
|
135
|
+
config = SandboxConfiguration(
|
136
|
+
sandbox=sandbox,
|
137
|
+
force_url=session.url,
|
138
|
+
headers={"X-Blaxel-Preview-Token": session.token},
|
139
|
+
params={"bl_preview_token": session.token},
|
140
|
+
)
|
141
|
+
|
142
|
+
instance = cls.__new__(cls)
|
143
|
+
instance.sandbox = sandbox
|
144
|
+
instance.config = config
|
145
|
+
instance.fs = SandboxFileSystem(config)
|
146
|
+
instance.process = SandboxProcess(config)
|
147
|
+
instance.previews = SandboxPreviews(sandbox)
|
148
|
+
instance.sessions = SandboxSessions(config)
|
149
|
+
instance.network = SandboxNetwork(config)
|
150
|
+
|
151
|
+
return instance
|
@@ -0,0 +1,124 @@
|
|
1
|
+
from datetime import datetime, timedelta
|
2
|
+
from typing import Any, Dict, List, Optional, Union
|
3
|
+
|
4
|
+
from ..client.api.compute import (
|
5
|
+
create_sandbox_preview,
|
6
|
+
delete_sandbox_preview,
|
7
|
+
get_sandbox_preview,
|
8
|
+
list_sandbox_preview_tokens,
|
9
|
+
list_sandbox_previews,
|
10
|
+
)
|
11
|
+
from ..client.client import client
|
12
|
+
from ..client.models import Metadata, Preview, PreviewSpec
|
13
|
+
from .preview import SandboxPreview
|
14
|
+
from .types import SandboxConfiguration, SessionCreateOptions, SessionWithToken
|
15
|
+
|
16
|
+
|
17
|
+
class SandboxSessions:
|
18
|
+
def __init__(self, sandbox_config: SandboxConfiguration):
|
19
|
+
self.sandbox_config = sandbox_config
|
20
|
+
|
21
|
+
@property
|
22
|
+
def sandbox_name(self) -> str:
|
23
|
+
return self.sandbox_config.metadata.name if self.sandbox_config.metadata else ""
|
24
|
+
|
25
|
+
async def create(
|
26
|
+
self, options: Optional[Union[SessionCreateOptions, Dict[str, Any]]] = None
|
27
|
+
) -> SessionWithToken:
|
28
|
+
if options is None:
|
29
|
+
options = SessionCreateOptions()
|
30
|
+
elif isinstance(options, dict):
|
31
|
+
options = SessionCreateOptions.from_dict(options)
|
32
|
+
|
33
|
+
expires_at = options.expires_at or datetime.now() + timedelta(days=1)
|
34
|
+
|
35
|
+
preview_body = Preview(
|
36
|
+
metadata=Metadata(name=f"session-{int(datetime.now().timestamp() * 1000)}"),
|
37
|
+
spec=PreviewSpec(
|
38
|
+
port=443,
|
39
|
+
public=False,
|
40
|
+
request_headers=options.request_headers,
|
41
|
+
response_headers=options.response_headers,
|
42
|
+
),
|
43
|
+
)
|
44
|
+
|
45
|
+
preview_response = await create_sandbox_preview.asyncio(
|
46
|
+
self.sandbox_name, client=client, body=preview_body
|
47
|
+
)
|
48
|
+
|
49
|
+
preview = SandboxPreview(preview_response, self.sandbox_name)
|
50
|
+
token_obj = await preview.tokens.create(expires_at)
|
51
|
+
|
52
|
+
return SessionWithToken(
|
53
|
+
name=preview_body.metadata.name,
|
54
|
+
url=preview.spec.url or "",
|
55
|
+
token=token_obj.value,
|
56
|
+
expires_at=token_obj.expires_at,
|
57
|
+
)
|
58
|
+
|
59
|
+
async def create_if_expired(
|
60
|
+
self,
|
61
|
+
options: Optional[Union[SessionCreateOptions, Dict[str, Any]]] = None,
|
62
|
+
delta_seconds: int = 3600, # 1 hour
|
63
|
+
) -> SessionWithToken:
|
64
|
+
if options is None:
|
65
|
+
options = SessionCreateOptions()
|
66
|
+
elif isinstance(options, dict):
|
67
|
+
options = SessionCreateOptions.from_dict(options)
|
68
|
+
|
69
|
+
all_sessions = await self.list()
|
70
|
+
now = datetime.now()
|
71
|
+
threshold = now + timedelta(seconds=delta_seconds)
|
72
|
+
|
73
|
+
if all_sessions:
|
74
|
+
session_data = all_sessions[0]
|
75
|
+
if session_data.expires_at < threshold:
|
76
|
+
await self.delete(session_data.name)
|
77
|
+
session_data = await self.create(options)
|
78
|
+
else:
|
79
|
+
session_data = await self.create(options)
|
80
|
+
|
81
|
+
return session_data
|
82
|
+
|
83
|
+
async def list(self) -> List[SessionWithToken]:
|
84
|
+
previews_response = await list_sandbox_previews.asyncio(self.sandbox_name, client=client)
|
85
|
+
|
86
|
+
sessions = []
|
87
|
+
for preview in previews_response:
|
88
|
+
if preview.metadata and preview.metadata.name and "session-" in preview.metadata.name:
|
89
|
+
token = await self.get_token(preview.metadata.name)
|
90
|
+
if token:
|
91
|
+
sessions.append(
|
92
|
+
SessionWithToken(
|
93
|
+
name=preview.metadata.name,
|
94
|
+
url=preview.spec.url or "",
|
95
|
+
token=token.spec.token or "",
|
96
|
+
expires_at=token.spec.expires_at or datetime.now(),
|
97
|
+
)
|
98
|
+
)
|
99
|
+
|
100
|
+
return sessions
|
101
|
+
|
102
|
+
async def get(self, name: str) -> SessionWithToken:
|
103
|
+
preview_response = await get_sandbox_preview.asyncio(self.sandbox_name, name, client=client)
|
104
|
+
|
105
|
+
token = await self.get_token(name)
|
106
|
+
|
107
|
+
return SessionWithToken(
|
108
|
+
name=name,
|
109
|
+
url=preview_response.spec.url or "",
|
110
|
+
token=token.spec.token or "" if token else "",
|
111
|
+
expires_at=token.spec.expires_at or datetime.now() if token else datetime.now(),
|
112
|
+
)
|
113
|
+
|
114
|
+
async def delete(self, name: str):
|
115
|
+
return await delete_sandbox_preview.asyncio(self.sandbox_name, name, client=client)
|
116
|
+
|
117
|
+
async def get_token(self, preview_name: str):
|
118
|
+
tokens_response = await list_sandbox_preview_tokens.asyncio(
|
119
|
+
self.sandbox_name, preview_name, client=client
|
120
|
+
)
|
121
|
+
|
122
|
+
if not tokens_response:
|
123
|
+
return None
|
124
|
+
return tokens_response[0]
|
@@ -0,0 +1,103 @@
|
|
1
|
+
from datetime import datetime
|
2
|
+
from typing import Any, Dict, Optional
|
3
|
+
|
4
|
+
from ..client.models import Sandbox
|
5
|
+
|
6
|
+
|
7
|
+
class SessionCreateOptions:
|
8
|
+
def __init__(
|
9
|
+
self,
|
10
|
+
expires_at: Optional[datetime] = None,
|
11
|
+
response_headers: Optional[Dict[str, str]] = None,
|
12
|
+
request_headers: Optional[Dict[str, str]] = None,
|
13
|
+
):
|
14
|
+
self.expires_at = expires_at
|
15
|
+
self.response_headers = response_headers or {}
|
16
|
+
self.request_headers = request_headers or {}
|
17
|
+
|
18
|
+
@classmethod
|
19
|
+
def from_dict(cls, data: Dict[str, Any]) -> "SessionCreateOptions":
|
20
|
+
expires_at = None
|
21
|
+
if "expires_at" in data and data["expires_at"]:
|
22
|
+
if isinstance(data["expires_at"], str):
|
23
|
+
expires_at = datetime.fromisoformat(data["expires_at"].replace("Z", "+00:00"))
|
24
|
+
elif isinstance(data["expires_at"], datetime):
|
25
|
+
expires_at = data["expires_at"]
|
26
|
+
|
27
|
+
return cls(
|
28
|
+
expires_at=expires_at,
|
29
|
+
response_headers=data.get("response_headers"),
|
30
|
+
request_headers=data.get("request_headers"),
|
31
|
+
)
|
32
|
+
|
33
|
+
|
34
|
+
class SessionWithToken:
|
35
|
+
def __init__(self, name: str, url: str, token: str, expires_at: datetime):
|
36
|
+
self.name = name
|
37
|
+
self.url = url
|
38
|
+
self.token = token
|
39
|
+
self.expires_at = expires_at
|
40
|
+
|
41
|
+
@classmethod
|
42
|
+
def from_dict(cls, data: Dict[str, Any]) -> "SessionWithToken":
|
43
|
+
expires_at = data["expires_at"]
|
44
|
+
if isinstance(expires_at, str):
|
45
|
+
expires_at = datetime.fromisoformat(expires_at.replace("Z", "+00:00"))
|
46
|
+
|
47
|
+
return cls(
|
48
|
+
name=data["name"],
|
49
|
+
url=data["url"],
|
50
|
+
token=data["token"],
|
51
|
+
expires_at=expires_at,
|
52
|
+
)
|
53
|
+
|
54
|
+
|
55
|
+
class SandboxConfiguration:
|
56
|
+
def __init__(
|
57
|
+
self,
|
58
|
+
sandbox: Sandbox,
|
59
|
+
force_url: Optional[str] = None,
|
60
|
+
headers: Optional[Dict[str, str]] = None,
|
61
|
+
params: Optional[Dict[str, str]] = None,
|
62
|
+
):
|
63
|
+
self.sandbox = sandbox
|
64
|
+
self.force_url = force_url
|
65
|
+
self.headers = headers or {}
|
66
|
+
self.params = params or {}
|
67
|
+
|
68
|
+
@property
|
69
|
+
def metadata(self):
|
70
|
+
return self.sandbox.metadata
|
71
|
+
|
72
|
+
@property
|
73
|
+
def status(self):
|
74
|
+
return self.sandbox.status
|
75
|
+
|
76
|
+
@property
|
77
|
+
def spec(self):
|
78
|
+
return self.sandbox.spec
|
79
|
+
|
80
|
+
|
81
|
+
class WatchEvent:
|
82
|
+
def __init__(self, op: str, path: str, name: str, content: Optional[str] = None):
|
83
|
+
self.op = op
|
84
|
+
self.path = path
|
85
|
+
self.name = name
|
86
|
+
self.content = content
|
87
|
+
|
88
|
+
|
89
|
+
class SandboxFilesystemFile:
|
90
|
+
def __init__(self, path: str, content: str):
|
91
|
+
self.path = path
|
92
|
+
self.content = content
|
93
|
+
|
94
|
+
@classmethod
|
95
|
+
def from_dict(cls, data: Dict[str, Any]) -> "SandboxFilesystemFile":
|
96
|
+
return cls(data["path"], data["content"])
|
97
|
+
|
98
|
+
|
99
|
+
class CopyResponse:
|
100
|
+
def __init__(self, message: str, source: str, destination: str):
|
101
|
+
self.message = message
|
102
|
+
self.source = source
|
103
|
+
self.destination = destination
|