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.
Files changed (419) hide show
  1. blaxel/__init__.py +6 -3
  2. blaxel/core/__init__.py +44 -0
  3. blaxel/{agents → core/agents}/__init__.py +30 -50
  4. blaxel/{authentication → core/authentication}/apikey.py +1 -0
  5. blaxel/{authentication → core/authentication}/clientcredentials.py +6 -2
  6. blaxel/{client → core/client}/api/agents/create_agent.py +1 -1
  7. blaxel/{client → core/client}/api/agents/update_agent.py +1 -1
  8. blaxel/{client → core/client}/api/compute/create_sandbox.py +1 -1
  9. blaxel/{client → core/client}/api/compute/create_sandbox_preview.py +1 -1
  10. blaxel/{client → core/client}/api/compute/create_sandbox_preview_token.py +1 -1
  11. blaxel/{client → core/client}/api/compute/update_sandbox.py +1 -1
  12. blaxel/{client → core/client}/api/compute/update_sandbox_preview.py +1 -1
  13. blaxel/{client → core/client}/api/functions/create_function.py +1 -1
  14. blaxel/{client → core/client}/api/functions/update_function.py +1 -1
  15. blaxel/{client → core/client}/api/integrations/create_integration_connection.py +1 -1
  16. blaxel/{client → core/client}/api/integrations/update_integration_connection.py +1 -1
  17. blaxel/{client → core/client}/api/jobs/create_job.py +1 -1
  18. blaxel/{client → core/client}/api/jobs/update_job.py +1 -1
  19. blaxel/{client → core/client}/api/knowledgebases/create_knowledgebase.py +1 -1
  20. blaxel/{client → core/client}/api/knowledgebases/update_knowledgebase.py +1 -1
  21. blaxel/{client → core/client}/api/models/create_model.py +1 -1
  22. blaxel/{client → core/client}/api/models/update_model.py +1 -1
  23. blaxel/{client → core/client}/api/policies/create_policy.py +1 -1
  24. blaxel/{client → core/client}/api/policies/update_policy.py +1 -1
  25. blaxel/{client → core/client}/api/service_accounts/create_api_key_for_service_account.py +1 -1
  26. blaxel/{client → core/client}/api/service_accounts/create_workspace_service_account.py +1 -1
  27. blaxel/{client → core/client}/api/service_accounts/update_workspace_service_account.py +1 -1
  28. blaxel/{client → core/client}/api/workspaces/check_workspace_availability.py +1 -1
  29. blaxel/{client → core/client}/api/workspaces/create_worspace.py +1 -1
  30. blaxel/{client → core/client}/api/workspaces/invite_workspace_user.py +1 -1
  31. blaxel/{client → core/client}/api/workspaces/update_workspace.py +1 -1
  32. blaxel/{client → core/client}/api/workspaces/update_workspace_user_role.py +1 -1
  33. blaxel/{client → core/client}/models/agent.py +1 -1
  34. blaxel/{client → core/client}/models/agent_spec.py +2 -2
  35. blaxel/{client → core/client}/models/core_spec.py +1 -1
  36. blaxel/{client → core/client}/models/function.py +1 -1
  37. blaxel/{client → core/client}/models/function_schema_properties.py +1 -1
  38. blaxel/{client → core/client}/models/function_spec.py +2 -2
  39. blaxel/{client → core/client}/models/integration.py +2 -2
  40. blaxel/{client → core/client}/models/integration_endpoints.py +1 -1
  41. blaxel/{client → core/client}/models/job.py +1 -1
  42. blaxel/{client → core/client}/models/job_spec.py +1 -1
  43. blaxel/{client → core/client}/models/knowledgebase.py +1 -1
  44. blaxel/{client → core/client}/models/location_response.py +1 -1
  45. blaxel/{client → core/client}/models/model.py +1 -1
  46. blaxel/{client → core/client}/models/model_spec.py +1 -1
  47. blaxel/{client → core/client}/models/policy_spec.py +2 -2
  48. blaxel/{client → core/client}/models/resource_metrics.py +3 -3
  49. blaxel/{client → core/client}/models/runtime.py +1 -1
  50. blaxel/{client → core/client}/models/sandbox.py +1 -1
  51. blaxel/{client → core/client}/models/sandbox_definition.py +1 -1
  52. blaxel/{client → core/client}/models/sandbox_spec.py +1 -1
  53. blaxel/{client → core/client}/models/store_agent.py +1 -1
  54. blaxel/{client → core/client}/models/store_configuration.py +1 -1
  55. blaxel/{client → core/client}/models/template.py +1 -1
  56. blaxel/core/common/__init__.py +6 -0
  57. blaxel/core/common/autoload.py +21 -0
  58. blaxel/{common → core/common}/internal.py +33 -62
  59. blaxel/core/common/logger.py +131 -0
  60. blaxel/{jobs → core/jobs}/__init__.py +40 -60
  61. blaxel/core/mcp/__init__.py +4 -0
  62. blaxel/{mcp → core/mcp}/client.py +13 -7
  63. blaxel/{mcp → core/mcp}/server.py +4 -30
  64. blaxel/core/models/__init__.py +52 -0
  65. blaxel/core/sandbox/__init__.py +29 -0
  66. blaxel/core/sandbox/action.py +79 -0
  67. blaxel/{sandbox → core/sandbox}/client/api/filesystem/put_filesystem_path.py +1 -1
  68. blaxel/{sandbox → core/sandbox}/client/api/network/post_network_process_pid_monitor.py +1 -1
  69. blaxel/core/sandbox/client/api/process/__init__.py +0 -0
  70. blaxel/{sandbox → core/sandbox}/client/api/process/post_process.py +1 -1
  71. blaxel/{sandbox → core/sandbox}/client/models/directory.py +2 -2
  72. blaxel/core/sandbox/filesystem.py +280 -0
  73. blaxel/core/sandbox/network.py +10 -0
  74. blaxel/{sandbox → core/sandbox}/preview.py +45 -17
  75. blaxel/core/sandbox/process.py +159 -0
  76. blaxel/{sandbox → core/sandbox}/sandbox.py +62 -5
  77. blaxel/core/sandbox/session.py +124 -0
  78. blaxel/core/sandbox/types.py +103 -0
  79. blaxel/{tools → core/tools}/__init__.py +62 -90
  80. blaxel/crewai/__init__.py +4 -0
  81. blaxel/{models/crewai.py → crewai/model.py} +4 -2
  82. blaxel/crewai/py.typed +0 -0
  83. blaxel/crewai/tools.py +26 -0
  84. blaxel/googleadk/__init__.py +4 -0
  85. blaxel/{models/googleadk.py → googleadk/model.py} +8 -2
  86. blaxel/googleadk/py.typed +0 -0
  87. blaxel/googleadk/tools.py +72 -0
  88. blaxel/langgraph/__init__.py +4 -0
  89. blaxel/{models/langchain.py → langgraph/model.py} +8 -4
  90. blaxel/langgraph/py.typed +0 -0
  91. blaxel/{tools/langchain.py → langgraph/tools.py} +7 -3
  92. blaxel/livekit/__init__.py +4 -0
  93. blaxel/{models/livekit.py → livekit/model.py} +7 -1
  94. blaxel/livekit/py.typed +0 -0
  95. blaxel/{tools/livekit.py → livekit/tools.py} +8 -1
  96. blaxel/llamaindex/__init__.py +4 -0
  97. blaxel/{models/llamaindex.py → llamaindex/model.py} +6 -3
  98. blaxel/llamaindex/py.typed +0 -0
  99. blaxel/{tools/llamaindex.py → llamaindex/tools.py} +7 -4
  100. blaxel/openai/__init__.py +4 -0
  101. blaxel/{models/openai.py → openai/model.py} +4 -2
  102. blaxel/openai/py.typed +0 -0
  103. blaxel/{tools/openai.py → openai/tools.py} +7 -3
  104. blaxel/pydantic/__init__.py +4 -0
  105. blaxel/{models/custom/pydantic → pydantic/custom}/gemini.py +0 -1
  106. blaxel/{models/pydantic.py → pydantic/model.py} +6 -4
  107. blaxel/pydantic/py.typed +0 -0
  108. blaxel/{tools/pydantic.py → pydantic/tools.py} +6 -3
  109. blaxel/telemetry/__init__.py +6 -0
  110. blaxel/telemetry/instrumentation/blaxel_core.py +124 -0
  111. blaxel/telemetry/instrumentation/blaxel_langgraph.py +74 -0
  112. blaxel/telemetry/instrumentation/blaxel_langgraph_gemini.py +360 -0
  113. blaxel/telemetry/instrumentation/blaxel_llamaindex.py +89 -0
  114. blaxel/telemetry/instrumentation/map.py +61 -0
  115. blaxel/telemetry/instrumentation/utils.py +74 -0
  116. blaxel/{common → telemetry/log}/logger.py +6 -12
  117. blaxel/{instrumentation → telemetry}/manager.py +20 -12
  118. blaxel/telemetry/py.typed +0 -0
  119. blaxel/{instrumentation → telemetry}/span.py +12 -1
  120. blaxel-0.2.0rc2.dist-info/METADATA +224 -0
  121. blaxel-0.2.0rc2.dist-info/RECORD +408 -0
  122. blaxel/common/autoload.py +0 -9
  123. blaxel/instrumentation/map.py +0 -49
  124. blaxel/mcp/__init__.py +0 -3
  125. blaxel/models/__init__.py +0 -104
  126. blaxel/sandbox/base.py +0 -67
  127. blaxel/sandbox/filesystem.py +0 -104
  128. blaxel/sandbox/process.py +0 -56
  129. blaxel/tools/crewai.py +0 -22
  130. blaxel/tools/googleadk.py +0 -66
  131. blaxel-0.1.22rc70.dist-info/METADATA +0 -169
  132. blaxel-0.1.22rc70.dist-info/RECORD +0 -379
  133. /blaxel/{authentication → core/authentication}/__init__.py +0 -0
  134. /blaxel/{authentication → core/authentication}/devicemode.py +0 -0
  135. /blaxel/{authentication → core/authentication}/oauth.py +0 -0
  136. /blaxel/{authentication → core/authentication}/types.py +0 -0
  137. /blaxel/{cache → core/cache}/__init__.py +0 -0
  138. /blaxel/{cache → core/cache}/cache.py +0 -0
  139. /blaxel/{client → core/client}/__init__.py +0 -0
  140. /blaxel/{client → core/client}/api/__init__.py +0 -0
  141. /blaxel/{client → core/client}/api/agents/__init__.py +0 -0
  142. /blaxel/{client → core/client}/api/agents/delete_agent.py +0 -0
  143. /blaxel/{client → core/client}/api/agents/get_agent.py +0 -0
  144. /blaxel/{client → core/client}/api/agents/list_agent_revisions.py +0 -0
  145. /blaxel/{client → core/client}/api/agents/list_agents.py +0 -0
  146. /blaxel/{client → core/client}/api/compute/__init__.py +0 -0
  147. /blaxel/{client → core/client}/api/compute/delete_sandbox.py +0 -0
  148. /blaxel/{client → core/client}/api/compute/delete_sandbox_preview.py +0 -0
  149. /blaxel/{client → core/client}/api/compute/delete_sandbox_preview_token.py +0 -0
  150. /blaxel/{client → core/client}/api/compute/get_sandbox.py +0 -0
  151. /blaxel/{client → core/client}/api/compute/get_sandbox_preview.py +0 -0
  152. /blaxel/{client → core/client}/api/compute/list_sandbox_preview_tokens.py +0 -0
  153. /blaxel/{client → core/client}/api/compute/list_sandbox_previews.py +0 -0
  154. /blaxel/{client → core/client}/api/compute/list_sandboxes.py +0 -0
  155. /blaxel/{client → core/client}/api/compute/start_sandbox.py +0 -0
  156. /blaxel/{client → core/client}/api/compute/stop_sandbox.py +0 -0
  157. /blaxel/{client → core/client}/api/configurations/__init__.py +0 -0
  158. /blaxel/{client → core/client}/api/configurations/get_configuration.py +0 -0
  159. /blaxel/{client → core/client}/api/default/__init__.py +0 -0
  160. /blaxel/{client → core/client}/api/default/get_template.py +0 -0
  161. /blaxel/{client → core/client}/api/default/list_mcp_hub_definitions.py +0 -0
  162. /blaxel/{client → core/client}/api/default/list_sandbox_hub_definitions.py +0 -0
  163. /blaxel/{client → core/client}/api/functions/__init__.py +0 -0
  164. /blaxel/{client → core/client}/api/functions/delete_function.py +0 -0
  165. /blaxel/{client → core/client}/api/functions/get_function.py +0 -0
  166. /blaxel/{client → core/client}/api/functions/list_function_revisions.py +0 -0
  167. /blaxel/{client → core/client}/api/functions/list_functions.py +0 -0
  168. /blaxel/{client → core/client}/api/integrations/__init__.py +0 -0
  169. /blaxel/{client → core/client}/api/integrations/delete_integration_connection.py +0 -0
  170. /blaxel/{client → core/client}/api/integrations/get_integration.py +0 -0
  171. /blaxel/{client → core/client}/api/integrations/get_integration_connection.py +0 -0
  172. /blaxel/{client → core/client}/api/integrations/get_integration_connection_model.py +0 -0
  173. /blaxel/{client → core/client}/api/integrations/get_integration_connection_model_endpoint_configurations.py +0 -0
  174. /blaxel/{client → core/client}/api/integrations/list_integration_connection_models.py +0 -0
  175. /blaxel/{client → core/client}/api/integrations/list_integration_connections.py +0 -0
  176. /blaxel/{client → core/client}/api/invitations/__init__.py +0 -0
  177. /blaxel/{client → core/client}/api/invitations/list_all_pending_invitations.py +0 -0
  178. /blaxel/{client → core/client}/api/jobs/__init__.py +0 -0
  179. /blaxel/{client → core/client}/api/jobs/delete_job.py +0 -0
  180. /blaxel/{client → core/client}/api/jobs/get_job.py +0 -0
  181. /blaxel/{client → core/client}/api/jobs/list_job_revisions.py +0 -0
  182. /blaxel/{client → core/client}/api/jobs/list_jobs.py +0 -0
  183. /blaxel/{client → core/client}/api/knowledgebases/__init__.py +0 -0
  184. /blaxel/{client → core/client}/api/knowledgebases/delete_knowledgebase.py +0 -0
  185. /blaxel/{client → core/client}/api/knowledgebases/get_knowledgebase.py +0 -0
  186. /blaxel/{client → core/client}/api/knowledgebases/list_knowledgebase_revisions.py +0 -0
  187. /blaxel/{client → core/client}/api/knowledgebases/list_knowledgebases.py +0 -0
  188. /blaxel/{client → core/client}/api/locations/__init__.py +0 -0
  189. /blaxel/{client → core/client}/api/locations/list_locations.py +0 -0
  190. /blaxel/{client → core/client}/api/models/__init__.py +0 -0
  191. /blaxel/{client → core/client}/api/models/delete_model.py +0 -0
  192. /blaxel/{client → core/client}/api/models/get_model.py +0 -0
  193. /blaxel/{client → core/client}/api/models/list_model_revisions.py +0 -0
  194. /blaxel/{client → core/client}/api/models/list_models.py +0 -0
  195. /blaxel/{client → core/client}/api/policies/__init__.py +0 -0
  196. /blaxel/{client → core/client}/api/policies/delete_policy.py +0 -0
  197. /blaxel/{client → core/client}/api/policies/get_policy.py +0 -0
  198. /blaxel/{client → core/client}/api/policies/list_policies.py +0 -0
  199. /blaxel/{client → core/client}/api/privateclusters/__init__.py +0 -0
  200. /blaxel/{client → core/client}/api/privateclusters/create_private_cluster.py +0 -0
  201. /blaxel/{client → core/client}/api/privateclusters/delete_private_cluster.py +0 -0
  202. /blaxel/{client → core/client}/api/privateclusters/get_private_cluster.py +0 -0
  203. /blaxel/{client → core/client}/api/privateclusters/get_private_cluster_health.py +0 -0
  204. /blaxel/{client → core/client}/api/privateclusters/list_private_clusters.py +0 -0
  205. /blaxel/{client → core/client}/api/privateclusters/update_private_cluster.py +0 -0
  206. /blaxel/{client → core/client}/api/privateclusters/update_private_cluster_health.py +0 -0
  207. /blaxel/{client → core/client}/api/service_accounts/__init__.py +0 -0
  208. /blaxel/{client → core/client}/api/service_accounts/delete_api_key_for_service_account.py +0 -0
  209. /blaxel/{client → core/client}/api/service_accounts/delete_workspace_service_account.py +0 -0
  210. /blaxel/{client → core/client}/api/service_accounts/get_workspace_service_accounts.py +0 -0
  211. /blaxel/{client → core/client}/api/service_accounts/list_api_keys_for_service_account.py +0 -0
  212. /blaxel/{client → core/client}/api/templates/__init__.py +0 -0
  213. /blaxel/{client → core/client}/api/templates/list_templates.py +0 -0
  214. /blaxel/{client → core/client}/api/workspaces/__init__.py +0 -0
  215. /blaxel/{client → core/client}/api/workspaces/accept_workspace_invitation.py +0 -0
  216. /blaxel/{client → core/client}/api/workspaces/decline_workspace_invitation.py +0 -0
  217. /blaxel/{client → core/client}/api/workspaces/delete_workspace.py +0 -0
  218. /blaxel/{client → core/client}/api/workspaces/get_workspace.py +0 -0
  219. /blaxel/{client → core/client}/api/workspaces/leave_workspace.py +0 -0
  220. /blaxel/{client → core/client}/api/workspaces/list_workspace_users.py +0 -0
  221. /blaxel/{client → core/client}/api/workspaces/list_workspaces.py +0 -0
  222. /blaxel/{client → core/client}/api/workspaces/remove_workspace_user.py +0 -0
  223. /blaxel/{client → core/client}/client.py +0 -0
  224. /blaxel/{client → core/client}/errors.py +0 -0
  225. /blaxel/{client → core/client}/models/__init__.py +0 -0
  226. /blaxel/{client → core/client}/models/acl.py +0 -0
  227. /blaxel/{client → core/client}/models/api_key.py +0 -0
  228. /blaxel/{client → core/client}/models/billable_time_metric.py +0 -0
  229. /blaxel/{client → core/client}/models/check_workspace_availability_body.py +0 -0
  230. /blaxel/{client → core/client}/models/configuration.py +0 -0
  231. /blaxel/{client → core/client}/models/continent.py +0 -0
  232. /blaxel/{client → core/client}/models/core_event.py +0 -0
  233. /blaxel/{client → core/client}/models/core_spec_configurations.py +0 -0
  234. /blaxel/{client → core/client}/models/country.py +0 -0
  235. /blaxel/{client → core/client}/models/create_api_key_for_service_account_body.py +0 -0
  236. /blaxel/{client → core/client}/models/create_workspace_service_account_body.py +0 -0
  237. /blaxel/{client → core/client}/models/create_workspace_service_account_response_200.py +0 -0
  238. /blaxel/{client → core/client}/models/delete_sandbox_preview_token_response_200.py +0 -0
  239. /blaxel/{client → core/client}/models/delete_workspace_service_account_response_200.py +0 -0
  240. /blaxel/{client → core/client}/models/entrypoint.py +0 -0
  241. /blaxel/{client → core/client}/models/entrypoint_env.py +0 -0
  242. /blaxel/{client → core/client}/models/flavor.py +0 -0
  243. /blaxel/{client → core/client}/models/form.py +0 -0
  244. /blaxel/{client → core/client}/models/form_config.py +0 -0
  245. /blaxel/{client → core/client}/models/form_oauth.py +0 -0
  246. /blaxel/{client → core/client}/models/form_secrets.py +0 -0
  247. /blaxel/{client → core/client}/models/function_kit.py +0 -0
  248. /blaxel/{client → core/client}/models/function_schema.py +0 -0
  249. /blaxel/{client → core/client}/models/function_schema_not.py +0 -0
  250. /blaxel/{client → core/client}/models/function_schema_or_bool.py +0 -0
  251. /blaxel/{client → core/client}/models/get_workspace_service_accounts_response_200_item.py +0 -0
  252. /blaxel/{client → core/client}/models/histogram_bucket.py +0 -0
  253. /blaxel/{client → core/client}/models/histogram_stats.py +0 -0
  254. /blaxel/{client → core/client}/models/integration_additional_infos.py +0 -0
  255. /blaxel/{client → core/client}/models/integration_connection.py +0 -0
  256. /blaxel/{client → core/client}/models/integration_connection_spec.py +0 -0
  257. /blaxel/{client → core/client}/models/integration_connection_spec_config.py +0 -0
  258. /blaxel/{client → core/client}/models/integration_connection_spec_secret.py +0 -0
  259. /blaxel/{client → core/client}/models/integration_endpoint.py +0 -0
  260. /blaxel/{client → core/client}/models/integration_endpoint_token.py +0 -0
  261. /blaxel/{client → core/client}/models/integration_headers.py +0 -0
  262. /blaxel/{client → core/client}/models/integration_model.py +0 -0
  263. /blaxel/{client → core/client}/models/integration_organization.py +0 -0
  264. /blaxel/{client → core/client}/models/integration_query_params.py +0 -0
  265. /blaxel/{client → core/client}/models/integration_repository.py +0 -0
  266. /blaxel/{client → core/client}/models/invite_workspace_user_body.py +0 -0
  267. /blaxel/{client → core/client}/models/job_execution_config.py +0 -0
  268. /blaxel/{client → core/client}/models/job_metrics.py +0 -0
  269. /blaxel/{client → core/client}/models/job_metrics_executions_chart.py +0 -0
  270. /blaxel/{client → core/client}/models/job_metrics_executions_total.py +0 -0
  271. /blaxel/{client → core/client}/models/job_metrics_tasks_chart.py +0 -0
  272. /blaxel/{client → core/client}/models/job_metrics_tasks_total.py +0 -0
  273. /blaxel/{client → core/client}/models/jobs_chart.py +0 -0
  274. /blaxel/{client → core/client}/models/jobs_chart_value.py +0 -0
  275. /blaxel/{client → core/client}/models/jobs_executions.py +0 -0
  276. /blaxel/{client → core/client}/models/jobs_network_chart.py +0 -0
  277. /blaxel/{client → core/client}/models/jobs_success_failed_chart.py +0 -0
  278. /blaxel/{client → core/client}/models/jobs_tasks.py +0 -0
  279. /blaxel/{client → core/client}/models/jobs_total.py +0 -0
  280. /blaxel/{client → core/client}/models/knowledgebase_spec.py +0 -0
  281. /blaxel/{client → core/client}/models/knowledgebase_spec_options.py +0 -0
  282. /blaxel/{client → core/client}/models/last_n_requests_metric.py +0 -0
  283. /blaxel/{client → core/client}/models/latency_metric.py +0 -0
  284. /blaxel/{client → core/client}/models/logs_response.py +0 -0
  285. /blaxel/{client → core/client}/models/logs_response_data.py +0 -0
  286. /blaxel/{client → core/client}/models/mcp_definition.py +0 -0
  287. /blaxel/{client → core/client}/models/mcp_definition_entrypoint.py +0 -0
  288. /blaxel/{client → core/client}/models/mcp_definition_form.py +0 -0
  289. /blaxel/{client → core/client}/models/memory_allocation_by_name.py +0 -0
  290. /blaxel/{client → core/client}/models/memory_allocation_metric.py +0 -0
  291. /blaxel/{client → core/client}/models/metadata.py +0 -0
  292. /blaxel/{client → core/client}/models/metadata_labels.py +0 -0
  293. /blaxel/{client → core/client}/models/metric.py +0 -0
  294. /blaxel/{client → core/client}/models/metrics.py +0 -0
  295. /blaxel/{client → core/client}/models/metrics_models.py +0 -0
  296. /blaxel/{client → core/client}/models/metrics_request_total_per_code.py +0 -0
  297. /blaxel/{client → core/client}/models/metrics_rps_per_code.py +0 -0
  298. /blaxel/{client → core/client}/models/model_private_cluster.py +0 -0
  299. /blaxel/{client → core/client}/models/o_auth.py +0 -0
  300. /blaxel/{client → core/client}/models/owner_fields.py +0 -0
  301. /blaxel/{client → core/client}/models/pending_invitation.py +0 -0
  302. /blaxel/{client → core/client}/models/pending_invitation_accept.py +0 -0
  303. /blaxel/{client → core/client}/models/pending_invitation_render.py +0 -0
  304. /blaxel/{client → core/client}/models/pending_invitation_render_invited_by.py +0 -0
  305. /blaxel/{client → core/client}/models/pending_invitation_render_workspace.py +0 -0
  306. /blaxel/{client → core/client}/models/pending_invitation_workspace_details.py +0 -0
  307. /blaxel/{client → core/client}/models/pod_template_spec.py +0 -0
  308. /blaxel/{client → core/client}/models/policy.py +0 -0
  309. /blaxel/{client → core/client}/models/policy_location.py +0 -0
  310. /blaxel/{client → core/client}/models/policy_max_tokens.py +0 -0
  311. /blaxel/{client → core/client}/models/port.py +0 -0
  312. /blaxel/{client → core/client}/models/preview.py +0 -0
  313. /blaxel/{client → core/client}/models/preview_metadata.py +0 -0
  314. /blaxel/{client → core/client}/models/preview_spec.py +0 -0
  315. /blaxel/{client → core/client}/models/preview_spec_request_headers.py +0 -0
  316. /blaxel/{client → core/client}/models/preview_spec_response_headers.py +0 -0
  317. /blaxel/{client → core/client}/models/preview_token.py +0 -0
  318. /blaxel/{client → core/client}/models/preview_token_metadata.py +0 -0
  319. /blaxel/{client → core/client}/models/preview_token_spec.py +0 -0
  320. /blaxel/{client → core/client}/models/private_cluster.py +0 -0
  321. /blaxel/{client → core/client}/models/private_location.py +0 -0
  322. /blaxel/{client → core/client}/models/repository.py +0 -0
  323. /blaxel/{client → core/client}/models/request_duration_over_time_metric.py +0 -0
  324. /blaxel/{client → core/client}/models/request_duration_over_time_metrics.py +0 -0
  325. /blaxel/{client → core/client}/models/request_total_by_origin_metric.py +0 -0
  326. /blaxel/{client → core/client}/models/request_total_by_origin_metric_request_total_by_origin.py +0 -0
  327. /blaxel/{client → core/client}/models/request_total_by_origin_metric_request_total_by_origin_and_code.py +0 -0
  328. /blaxel/{client → core/client}/models/request_total_metric.py +0 -0
  329. /blaxel/{client → core/client}/models/request_total_metric_request_total_per_code.py +0 -0
  330. /blaxel/{client → core/client}/models/request_total_metric_rps_per_code.py +0 -0
  331. /blaxel/{client → core/client}/models/request_total_response_data.py +0 -0
  332. /blaxel/{client → core/client}/models/resource.py +0 -0
  333. /blaxel/{client → core/client}/models/resource_log.py +0 -0
  334. /blaxel/{client → core/client}/models/resource_log_chart.py +0 -0
  335. /blaxel/{client → core/client}/models/resource_log_response.py +0 -0
  336. /blaxel/{client → core/client}/models/resource_metrics_request_total_per_code.py +0 -0
  337. /blaxel/{client → core/client}/models/resource_metrics_request_total_per_code_previous.py +0 -0
  338. /blaxel/{client → core/client}/models/resource_metrics_rps_per_code.py +0 -0
  339. /blaxel/{client → core/client}/models/resource_metrics_rps_per_code_previous.py +0 -0
  340. /blaxel/{client → core/client}/models/resource_trace.py +0 -0
  341. /blaxel/{client → core/client}/models/revision_configuration.py +0 -0
  342. /blaxel/{client → core/client}/models/revision_metadata.py +0 -0
  343. /blaxel/{client → core/client}/models/runtime_configuration.py +0 -0
  344. /blaxel/{client → core/client}/models/runtime_startup_probe.py +0 -0
  345. /blaxel/{client → core/client}/models/serverless_config.py +0 -0
  346. /blaxel/{client → core/client}/models/serverless_config_configuration.py +0 -0
  347. /blaxel/{client → core/client}/models/spec_configuration.py +0 -0
  348. /blaxel/{client → core/client}/models/start_sandbox.py +0 -0
  349. /blaxel/{client → core/client}/models/stop_sandbox.py +0 -0
  350. /blaxel/{client → core/client}/models/store_agent_labels.py +0 -0
  351. /blaxel/{client → core/client}/models/store_configuration_option.py +0 -0
  352. /blaxel/{client → core/client}/models/template_variable.py +0 -0
  353. /blaxel/{client → core/client}/models/time_fields.py +0 -0
  354. /blaxel/{client → core/client}/models/time_to_first_token_over_time_metrics.py +0 -0
  355. /blaxel/{client → core/client}/models/token_rate_metric.py +0 -0
  356. /blaxel/{client → core/client}/models/token_rate_metrics.py +0 -0
  357. /blaxel/{client → core/client}/models/token_total_metric.py +0 -0
  358. /blaxel/{client → core/client}/models/trace_ids_response.py +0 -0
  359. /blaxel/{client → core/client}/models/trigger.py +0 -0
  360. /blaxel/{client → core/client}/models/trigger_configuration.py +0 -0
  361. /blaxel/{client → core/client}/models/update_workspace_service_account_body.py +0 -0
  362. /blaxel/{client → core/client}/models/update_workspace_service_account_response_200.py +0 -0
  363. /blaxel/{client → core/client}/models/update_workspace_user_role_body.py +0 -0
  364. /blaxel/{client → core/client}/models/websocket_channel.py +0 -0
  365. /blaxel/{client → core/client}/models/websocket_message.py +0 -0
  366. /blaxel/{client → core/client}/models/workspace.py +0 -0
  367. /blaxel/{client → core/client}/models/workspace_labels.py +0 -0
  368. /blaxel/{client → core/client}/models/workspace_runtime.py +0 -0
  369. /blaxel/{client → core/client}/models/workspace_user.py +0 -0
  370. /blaxel/{client → core/client}/py.typed +0 -0
  371. /blaxel/{client → core/client}/types.py +0 -0
  372. /blaxel/{common → core/common}/env.py +0 -0
  373. /blaxel/{common → core/common}/settings.py +0 -0
  374. /blaxel/{sandbox/client/api/filesystem/__init__.py → core/py.typed} +0 -0
  375. /blaxel/{sandbox → core/sandbox}/client/__init__.py +0 -0
  376. /blaxel/{sandbox → core/sandbox}/client/api/__init__.py +0 -0
  377. /blaxel/{sandbox/client/api/network → core/sandbox/client/api/filesystem}/__init__.py +0 -0
  378. /blaxel/{sandbox → core/sandbox}/client/api/filesystem/delete_filesystem_path.py +0 -0
  379. /blaxel/{sandbox → core/sandbox}/client/api/filesystem/get_filesystem_path.py +0 -0
  380. /blaxel/{sandbox → core/sandbox}/client/api/filesystem/get_watch_filesystem_path.py +0 -0
  381. /blaxel/{sandbox → core/sandbox}/client/api/filesystem/get_ws_watch_filesystem_path.py +0 -0
  382. /blaxel/{sandbox/client/api/process → core/sandbox/client/api/network}/__init__.py +0 -0
  383. /blaxel/{sandbox → core/sandbox}/client/api/network/delete_network_process_pid_monitor.py +0 -0
  384. /blaxel/{sandbox → core/sandbox}/client/api/network/get_network_process_pid_ports.py +0 -0
  385. /blaxel/{sandbox → core/sandbox}/client/api/process/delete_process_identifier.py +0 -0
  386. /blaxel/{sandbox → core/sandbox}/client/api/process/delete_process_identifier_kill.py +0 -0
  387. /blaxel/{sandbox → core/sandbox}/client/api/process/get_process.py +0 -0
  388. /blaxel/{sandbox → core/sandbox}/client/api/process/get_process_identifier.py +0 -0
  389. /blaxel/{sandbox → core/sandbox}/client/api/process/get_process_identifier_logs.py +0 -0
  390. /blaxel/{sandbox → core/sandbox}/client/api/process/get_process_identifier_logs_stream.py +0 -0
  391. /blaxel/{sandbox → core/sandbox}/client/api/process/get_ws_process_identifier_logs_stream.py +0 -0
  392. /blaxel/{sandbox → core/sandbox}/client/client.py +0 -0
  393. /blaxel/{sandbox → core/sandbox}/client/errors.py +0 -0
  394. /blaxel/{sandbox → core/sandbox}/client/models/__init__.py +0 -0
  395. /blaxel/{sandbox → core/sandbox}/client/models/delete_network_process_pid_monitor_response_200.py +0 -0
  396. /blaxel/{sandbox → core/sandbox}/client/models/error_response.py +0 -0
  397. /blaxel/{sandbox → core/sandbox}/client/models/file.py +0 -0
  398. /blaxel/{sandbox → core/sandbox}/client/models/file_request.py +0 -0
  399. /blaxel/{sandbox → core/sandbox}/client/models/file_with_content.py +0 -0
  400. /blaxel/{sandbox → core/sandbox}/client/models/get_network_process_pid_ports_response_200.py +0 -0
  401. /blaxel/{sandbox → core/sandbox}/client/models/port_monitor_request.py +0 -0
  402. /blaxel/{sandbox → core/sandbox}/client/models/post_network_process_pid_monitor_response_200.py +0 -0
  403. /blaxel/{sandbox → core/sandbox}/client/models/process_logs.py +0 -0
  404. /blaxel/{sandbox → core/sandbox}/client/models/process_request.py +0 -0
  405. /blaxel/{sandbox → core/sandbox}/client/models/process_request_env.py +0 -0
  406. /blaxel/{sandbox → core/sandbox}/client/models/process_response.py +0 -0
  407. /blaxel/{sandbox → core/sandbox}/client/models/process_response_status.py +0 -0
  408. /blaxel/{sandbox → core/sandbox}/client/models/subdirectory.py +0 -0
  409. /blaxel/{sandbox → core/sandbox}/client/models/success_response.py +0 -0
  410. /blaxel/{sandbox → core/sandbox}/client/py.typed +0 -0
  411. /blaxel/{sandbox → core/sandbox}/client/types.py +0 -0
  412. /blaxel/{tools → core/tools}/common.py +0 -0
  413. /blaxel/{tools → core/tools}/types.py +0 -0
  414. /blaxel/{models/custom/langchain → langgraph/custom}/gemini.py +0 -0
  415. /blaxel/{models/custom/llamaindex → llamaindex/custom}/cohere.py +0 -0
  416. /blaxel/{instrumentation → telemetry}/exporters.py +0 -0
  417. /blaxel/{instrumentation → telemetry/log}/log.py +0 -0
  418. {blaxel-0.1.22rc70.dist-info → blaxel-0.2.0rc2.dist-info}/WHEEL +0 -0
  419. {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 asyncio as create_sandbox_preview
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 asyncio as delete_sandbox_preview
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 asyncio as list_sandbox_preview_tokens
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 Preview, PreviewSpec, PreviewToken, PreviewTokenSpec, Sandbox
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
- def __init__(self, preview: Preview):
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.resource_name,
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.resource_name,
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.resource_name,
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
- def __init__(self, preview: Preview):
94
+
95
+ def __init__(self, preview: Preview, sandbox_name: str = ""):
82
96
  self.preview = preview
83
- self.tokens = SandboxPreviewTokens(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
- return dt.isoformat(timespec="milliseconds").replace("+00:00", "Z")
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.fs = SandboxFileSystem(sandbox)
22
- self.process = SandboxProcess(sandbox)
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