blaxel 0.1.22rc70__py3-none-any.whl → 0.2.0rc1__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 +76 -17
- 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.0rc1.dist-info/METADATA +224 -0
- blaxel-0.2.0rc1.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.0rc1.dist-info}/WHEEL +0 -0
- {blaxel-0.1.22rc70.dist-info → blaxel-0.2.0rc1.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,280 @@
|
|
1
|
+
import asyncio
|
2
|
+
import io
|
3
|
+
import json
|
4
|
+
from typing import Any, Callable, Dict, List, Optional, Union
|
5
|
+
|
6
|
+
import httpx
|
7
|
+
|
8
|
+
from ..common.settings import settings
|
9
|
+
from .action import SandboxAction
|
10
|
+
from .client.models import Directory, FileRequest, SuccessResponse
|
11
|
+
from .types import CopyResponse, SandboxConfiguration, SandboxFilesystemFile, WatchEvent
|
12
|
+
|
13
|
+
|
14
|
+
class SandboxFileSystem(SandboxAction):
|
15
|
+
def __init__(self, sandbox_config: SandboxConfiguration):
|
16
|
+
super().__init__(sandbox_config)
|
17
|
+
|
18
|
+
async def mkdir(self, path: str, permissions: str = "0755") -> SuccessResponse:
|
19
|
+
path = self.format_path(path)
|
20
|
+
body = FileRequest(is_directory=True, permissions=permissions)
|
21
|
+
|
22
|
+
async with self.get_client() as client_instance:
|
23
|
+
response = await client_instance.put(f"/filesystem/{path}", json=body.to_dict())
|
24
|
+
self.handle_response_error(
|
25
|
+
response, response.json() if response.content else None, None
|
26
|
+
)
|
27
|
+
return SuccessResponse.from_dict(response.json())
|
28
|
+
|
29
|
+
async def write(self, path: str, content: str) -> SuccessResponse:
|
30
|
+
path = self.format_path(path)
|
31
|
+
body = FileRequest(content=content)
|
32
|
+
|
33
|
+
async with self.get_client() as client_instance:
|
34
|
+
response = await client_instance.put(f"/filesystem/{path}", json=body.to_dict())
|
35
|
+
self.handle_response_error(
|
36
|
+
response, response.json() if response.content else None, None
|
37
|
+
)
|
38
|
+
return SuccessResponse.from_dict(response.json())
|
39
|
+
|
40
|
+
async def write_binary(self, path: str, content: Union[bytes, bytearray]) -> SuccessResponse:
|
41
|
+
"""Write binary content to a file."""
|
42
|
+
path = self.format_path(path)
|
43
|
+
|
44
|
+
# Convert bytearray to bytes if necessary
|
45
|
+
if isinstance(content, bytearray):
|
46
|
+
content = bytes(content)
|
47
|
+
|
48
|
+
# Wrap binary content in BytesIO to provide file-like interface
|
49
|
+
binary_file = io.BytesIO(content)
|
50
|
+
|
51
|
+
# Prepare multipart form data
|
52
|
+
files = {
|
53
|
+
"file": ("binary-file.bin", binary_file, "application/octet-stream"),
|
54
|
+
}
|
55
|
+
data = {"permissions": "0644", "path": path}
|
56
|
+
|
57
|
+
# Use the fixed get_client method
|
58
|
+
url = f"{self.url}/filesystem/{path}"
|
59
|
+
headers = {**settings.headers, **self.sandbox_config.headers}
|
60
|
+
|
61
|
+
async with self.get_client() as client_instance:
|
62
|
+
response = await client_instance.put(url, files=files, data=data, headers=headers)
|
63
|
+
|
64
|
+
if not response.is_success:
|
65
|
+
raise Exception(f"Failed to write binary: {response.status_code} {response.text}")
|
66
|
+
|
67
|
+
return SuccessResponse.from_dict(response.json())
|
68
|
+
|
69
|
+
async def write_tree(
|
70
|
+
self,
|
71
|
+
files: List[Union[SandboxFilesystemFile, Dict[str, Any]]],
|
72
|
+
destination_path: Optional[str] = None,
|
73
|
+
) -> Directory:
|
74
|
+
"""Write multiple files in a tree structure."""
|
75
|
+
files_dict = {}
|
76
|
+
for file in files:
|
77
|
+
if isinstance(file, dict):
|
78
|
+
file = SandboxFilesystemFile.from_dict(file)
|
79
|
+
files_dict[file.path] = file.content
|
80
|
+
|
81
|
+
path = destination_path or ""
|
82
|
+
|
83
|
+
async with self.get_client() as client_instance:
|
84
|
+
response = await client_instance.put(
|
85
|
+
f"/filesystem/tree/{path}",
|
86
|
+
json={"files": files_dict},
|
87
|
+
headers={"Content-Type": "application/json"},
|
88
|
+
)
|
89
|
+
self.handle_response_error(
|
90
|
+
response, response.json() if response.content else None, None
|
91
|
+
)
|
92
|
+
return Directory.from_dict(response.json())
|
93
|
+
|
94
|
+
async def read(self, path: str) -> str:
|
95
|
+
path = self.format_path(path)
|
96
|
+
|
97
|
+
async with self.get_client() as client_instance:
|
98
|
+
response = await client_instance.get(f"/filesystem/{path}")
|
99
|
+
self.handle_response_error(
|
100
|
+
response, response.json() if response.content else None, None
|
101
|
+
)
|
102
|
+
|
103
|
+
data = response.json()
|
104
|
+
if "content" in data:
|
105
|
+
return data["content"]
|
106
|
+
raise Exception("Unsupported file type")
|
107
|
+
|
108
|
+
async def rm(self, path: str, recursive: bool = False) -> SuccessResponse:
|
109
|
+
path = self.format_path(path)
|
110
|
+
|
111
|
+
async with self.get_client() as client_instance:
|
112
|
+
params = {"recursive": "true"} if recursive else {}
|
113
|
+
response = await client_instance.delete(f"/filesystem/{path}", params=params)
|
114
|
+
self.handle_response_error(
|
115
|
+
response, response.json() if response.content else None, None
|
116
|
+
)
|
117
|
+
return SuccessResponse.from_dict(response.json())
|
118
|
+
|
119
|
+
async def ls(self, path: str) -> Directory:
|
120
|
+
path = self.format_path(path)
|
121
|
+
|
122
|
+
async with self.get_client() as client_instance:
|
123
|
+
response = await client_instance.get(f"/filesystem/{path}")
|
124
|
+
self.handle_response_error(
|
125
|
+
response, response.json() if response.content else None, None
|
126
|
+
)
|
127
|
+
|
128
|
+
data = response.json()
|
129
|
+
if not ("files" in data or "subdirectories" in data):
|
130
|
+
raise Exception('{"error": "Directory not found"}')
|
131
|
+
return Directory.from_dict(data)
|
132
|
+
|
133
|
+
async def cp(self, source: str, destination: str) -> CopyResponse:
|
134
|
+
source = self.format_path(source)
|
135
|
+
destination = self.format_path(destination)
|
136
|
+
|
137
|
+
async with self.get_client() as client_instance:
|
138
|
+
response = await client_instance.get(f"/filesystem/{source}")
|
139
|
+
self.handle_response_error(
|
140
|
+
response, response.json() if response.content else None, None
|
141
|
+
)
|
142
|
+
|
143
|
+
data = response.json()
|
144
|
+
if "files" in data or "subdirectories" in data:
|
145
|
+
# Create destination directory
|
146
|
+
await self.mkdir(destination)
|
147
|
+
|
148
|
+
# Process subdirectories in batches of 5
|
149
|
+
subdirectories = data.get("subdirectories", [])
|
150
|
+
for i in range(0, len(subdirectories), 5):
|
151
|
+
batch = subdirectories[i : i + 5]
|
152
|
+
await asyncio.gather(
|
153
|
+
*[
|
154
|
+
self.cp(
|
155
|
+
subdir.get("path", f"{source}/{subdir.get('path', '')}"),
|
156
|
+
f"{destination}/{subdir.get('path', '')}",
|
157
|
+
)
|
158
|
+
for subdir in batch
|
159
|
+
]
|
160
|
+
)
|
161
|
+
|
162
|
+
# Process files in batches of 10
|
163
|
+
files = data.get("files", [])
|
164
|
+
for i in range(0, len(files), 10):
|
165
|
+
batch = files[i : i + 10]
|
166
|
+
tasks = []
|
167
|
+
for file in batch:
|
168
|
+
source_path = file.get("path", f"{source}/{file.get('path', '')}")
|
169
|
+
dest_path = f"{destination}/{file.get('path', '')}"
|
170
|
+
tasks.append(self._copy_file(source_path, dest_path))
|
171
|
+
await asyncio.gather(*tasks)
|
172
|
+
|
173
|
+
return CopyResponse(
|
174
|
+
message="Directory copied successfully", source=source, destination=destination
|
175
|
+
)
|
176
|
+
elif "content" in data:
|
177
|
+
await self.write(destination, data["content"])
|
178
|
+
return CopyResponse(
|
179
|
+
message="File copied successfully", source=source, destination=destination
|
180
|
+
)
|
181
|
+
|
182
|
+
raise Exception("Unsupported file type")
|
183
|
+
|
184
|
+
async def _copy_file(self, source_path: str, dest_path: str):
|
185
|
+
"""Helper method to copy a single file."""
|
186
|
+
content = await self.read(source_path)
|
187
|
+
await self.write(dest_path, content)
|
188
|
+
|
189
|
+
def watch(
|
190
|
+
self,
|
191
|
+
path: str,
|
192
|
+
callback: Callable[[WatchEvent], None],
|
193
|
+
options: Optional[Dict[str, Any]] = None,
|
194
|
+
) -> Dict[str, Callable]:
|
195
|
+
"""Watch for file system changes."""
|
196
|
+
path = self.format_path(path)
|
197
|
+
closed = False
|
198
|
+
|
199
|
+
if options is None:
|
200
|
+
options = {}
|
201
|
+
|
202
|
+
async def start_watching():
|
203
|
+
nonlocal closed
|
204
|
+
|
205
|
+
params = {}
|
206
|
+
if options.get("ignore"):
|
207
|
+
params["ignore"] = ",".join(options["ignore"])
|
208
|
+
|
209
|
+
url = f"{self.url}/filesystem/{path}/watch"
|
210
|
+
headers = {**settings.headers, **self.sandbox_config.headers}
|
211
|
+
|
212
|
+
async with httpx.AsyncClient() as client_instance:
|
213
|
+
async with client_instance.stream(
|
214
|
+
"GET", url, params=params, headers=headers
|
215
|
+
) as response:
|
216
|
+
if not response.is_success:
|
217
|
+
raise Exception(f"Failed to start watching: {response.status_code}")
|
218
|
+
|
219
|
+
buffer = ""
|
220
|
+
async for chunk in response.aiter_text():
|
221
|
+
if closed:
|
222
|
+
break
|
223
|
+
|
224
|
+
buffer += chunk
|
225
|
+
lines = buffer.split("\n")
|
226
|
+
buffer = lines.pop() # Keep incomplete line in buffer
|
227
|
+
|
228
|
+
for line in lines:
|
229
|
+
line = line.strip()
|
230
|
+
if not line:
|
231
|
+
continue
|
232
|
+
|
233
|
+
try:
|
234
|
+
file_event_data = json.loads(line)
|
235
|
+
file_event = WatchEvent(
|
236
|
+
op=file_event_data.get("op", ""),
|
237
|
+
path=file_event_data.get("path", ""),
|
238
|
+
name=file_event_data.get("name", ""),
|
239
|
+
content=file_event_data.get("content"),
|
240
|
+
)
|
241
|
+
|
242
|
+
if options.get("with_content") and file_event.op in [
|
243
|
+
"CREATE",
|
244
|
+
"WRITE",
|
245
|
+
]:
|
246
|
+
try:
|
247
|
+
file_path = file_event.path
|
248
|
+
if file_path.endswith("/"):
|
249
|
+
file_path = file_path + file_event.name
|
250
|
+
else:
|
251
|
+
file_path = file_path + "/" + file_event.name
|
252
|
+
|
253
|
+
content = await self.read(file_path)
|
254
|
+
file_event.content = content
|
255
|
+
except:
|
256
|
+
file_event.content = None
|
257
|
+
|
258
|
+
await asyncio.create_task(asyncio.coroutine(callback)(file_event))
|
259
|
+
except json.JSONDecodeError:
|
260
|
+
continue
|
261
|
+
except Exception as e:
|
262
|
+
if options.get("on_error"):
|
263
|
+
options["on_error"](e)
|
264
|
+
|
265
|
+
# Start watching in the background
|
266
|
+
task = asyncio.create_task(start_watching())
|
267
|
+
|
268
|
+
def close():
|
269
|
+
nonlocal closed
|
270
|
+
closed = True
|
271
|
+
task.cancel()
|
272
|
+
|
273
|
+
return {"close": close}
|
274
|
+
|
275
|
+
def format_path(self, path: str) -> str:
|
276
|
+
if path == "/":
|
277
|
+
return path
|
278
|
+
if path.startswith("/"):
|
279
|
+
path = path[1:]
|
280
|
+
return path
|
@@ -0,0 +1,10 @@
|
|
1
|
+
from .action import SandboxAction
|
2
|
+
from .types import SandboxConfiguration
|
3
|
+
|
4
|
+
|
5
|
+
class SandboxNetwork(SandboxAction):
|
6
|
+
def __init__(self, sandbox_config: SandboxConfiguration):
|
7
|
+
super().__init__(sandbox_config)
|
8
|
+
|
9
|
+
# Network functionality can be expanded here in the future
|
10
|
+
# Currently this is a placeholder matching the TypeScript implementation
|
@@ -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")
|