blaxel 0.2.33__py3-none-any.whl → 0.2.35__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 +2 -2
- blaxel/core/__init__.py +2 -1
- blaxel/core/client/api/agents/create_agent.py +64 -19
- blaxel/core/client/api/agents/delete_agent.py +44 -15
- blaxel/core/client/api/agents/get_agent.py +43 -14
- blaxel/core/client/api/agents/list_agents.py +40 -11
- blaxel/core/client/api/agents/update_agent.py +60 -19
- blaxel/core/client/api/compute/create_sandbox.py +60 -23
- blaxel/core/client/api/compute/delete_sandbox.py +40 -19
- blaxel/core/client/api/compute/get_sandbox.py +39 -18
- blaxel/core/client/api/compute/list_sandboxes.py +40 -19
- blaxel/core/client/api/compute/update_sandbox.py +56 -23
- blaxel/core/client/api/configurations/get_configuration.py +16 -4
- blaxel/core/client/api/customdomains/create_custom_domain.py +12 -0
- blaxel/core/client/api/customdomains/list_custom_domains.py +16 -4
- blaxel/core/client/api/default/get_template.py +8 -4
- blaxel/core/client/api/functions/create_function.py +62 -19
- blaxel/core/client/api/functions/delete_function.py +46 -15
- blaxel/core/client/api/functions/get_function.py +45 -14
- blaxel/core/client/api/functions/list_functions.py +44 -15
- blaxel/core/client/api/functions/update_function.py +62 -19
- blaxel/core/client/api/images/cleanup_images.py +12 -12
- blaxel/core/client/api/images/delete_image.py +12 -8
- blaxel/core/client/api/images/delete_image_tag.py +12 -8
- blaxel/core/client/api/images/get_image.py +12 -8
- blaxel/core/client/api/images/list_images.py +12 -8
- blaxel/core/client/api/integrations/create_integration_connection.py +56 -23
- blaxel/core/client/api/integrations/delete_integration_connection.py +48 -19
- blaxel/core/client/api/integrations/get_integration.py +12 -8
- blaxel/core/client/api/integrations/get_integration_connection.py +44 -19
- blaxel/core/client/api/integrations/get_integration_connection_model.py +2 -2
- blaxel/core/client/api/integrations/list_integration_connections.py +36 -19
- blaxel/core/client/api/integrations/update_integration_connection.py +52 -19
- blaxel/core/client/api/jobs/create_job.py +20 -12
- blaxel/core/client/api/jobs/create_job_execution.py +22 -16
- blaxel/core/client/api/jobs/delete_job.py +12 -8
- blaxel/core/client/api/jobs/delete_job_execution.py +12 -8
- blaxel/core/client/api/jobs/get_job.py +24 -20
- blaxel/core/client/api/jobs/get_job_execution.py +8 -4
- blaxel/core/client/api/jobs/list_job_executions.py +8 -4
- blaxel/core/client/api/jobs/list_jobs.py +12 -8
- blaxel/core/client/api/jobs/update_job.py +20 -12
- blaxel/core/client/api/locations/list_locations.py +12 -8
- blaxel/core/client/api/{default → mcphub}/list_mcp_hub_definitions.py +20 -4
- blaxel/core/client/api/models/create_model.py +52 -23
- blaxel/core/client/api/models/delete_model.py +40 -19
- blaxel/core/client/api/models/get_model.py +40 -19
- blaxel/core/client/api/models/list_models.py +40 -19
- blaxel/core/client/api/models/update_model.py +52 -23
- blaxel/core/client/api/policies/create_policy.py +12 -8
- blaxel/core/client/api/policies/delete_policy.py +12 -8
- blaxel/core/client/api/policies/get_policy.py +12 -8
- blaxel/core/client/api/policies/list_policies.py +12 -8
- blaxel/core/client/api/policies/update_policy.py +12 -8
- blaxel/core/client/api/public_ipslist/list_public_ips.py +37 -5
- blaxel/core/client/api/sandboxhub/__init__.py +0 -0
- blaxel/core/client/api/{default → sandboxhub}/list_sandbox_hub_definitions.py +20 -4
- blaxel/core/client/api/service_accounts/create_api_key_for_service_account.py +12 -8
- blaxel/core/client/api/service_accounts/create_workspace_service_account.py +12 -8
- blaxel/core/client/api/service_accounts/delete_api_key_for_service_account.py +6 -4
- blaxel/core/client/api/service_accounts/delete_workspace_service_account.py +12 -8
- blaxel/core/client/api/service_accounts/get_workspace_service_accounts.py +12 -8
- blaxel/core/client/api/service_accounts/list_api_keys_for_service_account.py +12 -8
- blaxel/core/client/api/service_accounts/update_workspace_service_account.py +8 -8
- blaxel/core/client/api/templates/list_templates.py +12 -8
- blaxel/core/client/api/volume_templates/create_volume_template.py +8 -4
- blaxel/core/client/api/volume_templates/list_volume_templates.py +8 -4
- blaxel/core/client/api/volumes/create_volume.py +56 -23
- blaxel/core/client/api/volumes/delete_volume.py +44 -19
- blaxel/core/client/api/volumes/get_volume.py +40 -19
- blaxel/core/client/api/volumes/list_volumes.py +40 -19
- blaxel/core/client/api/workspaces/create_workspace.py +54 -23
- blaxel/core/client/api/workspaces/delete_workspace.py +42 -19
- blaxel/core/client/api/workspaces/get_workspace.py +42 -19
- blaxel/core/client/api/workspaces/invite_workspace_user.py +8 -4
- blaxel/core/client/api/workspaces/list_workspace_users.py +12 -8
- blaxel/core/client/api/workspaces/list_workspaces.py +36 -19
- blaxel/core/client/api/workspaces/update_workspace.py +50 -19
- blaxel/core/client/models/__init__.py +76 -146
- blaxel/core/client/models/agent.py +43 -47
- blaxel/core/client/models/agent_runtime.py +139 -0
- blaxel/core/client/models/agent_runtime_generation.py +18 -0
- blaxel/core/client/models/agent_spec.py +33 -110
- blaxel/core/client/models/api_key.py +5 -4
- blaxel/core/client/models/core_event.py +5 -5
- blaxel/core/client/models/create_api_key_for_service_account_body.py +2 -1
- blaxel/core/client/models/create_job_execution_request.py +1 -1
- blaxel/core/client/models/create_job_execution_response.py +13 -9
- blaxel/core/client/models/custom_domain.py +19 -36
- blaxel/core/client/models/custom_domain_metadata.py +4 -3
- blaxel/core/client/models/custom_domain_spec.py +14 -5
- blaxel/core/client/models/custom_domain_spec_status.py +19 -0
- blaxel/core/client/models/entrypoint.py +39 -13
- blaxel/core/client/models/{workspace_labels.py → entrypoint_args_item.py} +6 -6
- blaxel/core/client/models/entrypoint_env.py +3 -3
- blaxel/core/client/models/{job_metrics_executions_total.py → entrypoint_super_gateway_args_item.py} +6 -6
- blaxel/core/client/models/{spec_configuration.py → env.py} +17 -8
- blaxel/core/{sandbox/client/models/welcome_response.py → client/models/error.py} +26 -23
- blaxel/core/client/models/expiration_policy.py +30 -11
- blaxel/core/client/models/expiration_policy_action.py +17 -0
- blaxel/core/client/models/expiration_policy_type.py +19 -0
- blaxel/core/client/models/flavor.py +13 -5
- blaxel/core/client/models/flavor_type.py +18 -0
- blaxel/core/client/models/form.py +6 -6
- blaxel/core/client/models/function.py +43 -47
- blaxel/core/client/models/function_runtime.py +138 -0
- blaxel/core/client/models/function_runtime_generation.py +18 -0
- blaxel/core/client/models/function_spec.py +27 -73
- blaxel/core/client/models/function_spec_transport.py +18 -0
- blaxel/core/client/models/image.py +19 -36
- blaxel/core/client/models/integration_connection.py +25 -39
- blaxel/core/client/models/integration_connection_spec.py +8 -5
- blaxel/core/client/models/integration_connection_spec_config.py +1 -1
- blaxel/core/client/models/integration_connection_spec_secret.py +1 -1
- blaxel/core/client/models/integration_endpoint.py +41 -11
- blaxel/core/client/models/integration_endpoint_ignore_models_item.py +45 -0
- blaxel/core/client/models/{mcp_definition_entrypoint.py → integration_endpoint_models_item.py} +6 -6
- blaxel/core/client/models/job.py +43 -47
- blaxel/core/client/models/job_execution.py +30 -37
- blaxel/core/client/models/job_execution_metadata.py +3 -3
- blaxel/core/client/models/job_execution_spec.py +2 -2
- blaxel/core/client/models/job_execution_stats.py +5 -5
- blaxel/core/client/models/job_execution_status.py +24 -0
- blaxel/core/client/models/job_execution_task.py +12 -4
- blaxel/core/client/models/job_execution_task_metadata.py +1 -1
- blaxel/core/client/models/job_execution_task_spec.py +2 -2
- blaxel/core/client/models/job_execution_task_status.py +23 -0
- blaxel/core/client/models/job_runtime.py +172 -0
- blaxel/core/client/models/job_runtime_generation.py +18 -0
- blaxel/core/client/models/job_spec.py +20 -88
- blaxel/core/client/models/location_response.py +5 -5
- blaxel/core/client/models/mcp_definition.py +30 -17
- blaxel/core/client/models/{job_metrics_tasks_total.py → mcp_definition_categories_item.py} +6 -6
- blaxel/core/client/models/metadata.py +23 -17
- blaxel/core/client/models/metadata_labels.py +4 -1
- blaxel/core/client/models/model.py +43 -47
- blaxel/core/client/models/model_runtime.py +99 -0
- blaxel/core/client/models/model_runtime_type.py +34 -0
- blaxel/core/client/models/model_spec.py +12 -58
- blaxel/core/client/models/o_auth.py +23 -6
- blaxel/core/client/models/{form_oauth.py → o_auth_scope_item.py} +6 -6
- blaxel/core/client/models/pending_invitation_accept.py +2 -1
- blaxel/core/client/models/pending_invitation_workspace_details.py +27 -6
- blaxel/core/client/models/{metrics_request_total_per_code.py → pending_invitation_workspace_details_emails_item.py} +6 -6
- blaxel/core/client/models/policy.py +20 -36
- blaxel/core/client/models/policy_location.py +13 -5
- blaxel/core/client/models/policy_location_type.py +19 -0
- blaxel/core/client/models/policy_max_tokens.py +6 -6
- blaxel/core/client/models/policy_resource_type.py +20 -0
- blaxel/core/client/models/policy_spec.py +31 -10
- blaxel/core/client/models/policy_spec_type.py +19 -0
- blaxel/core/client/models/port.py +25 -15
- blaxel/core/client/models/port_protocol.py +19 -0
- blaxel/core/client/models/preview.py +19 -36
- blaxel/core/client/models/preview_metadata.py +12 -10
- blaxel/core/client/models/preview_token.py +19 -36
- blaxel/core/client/models/preview_token_metadata.py +8 -6
- blaxel/core/client/models/repository.py +2 -2
- blaxel/core/client/models/revision_configuration.py +3 -3
- blaxel/core/client/models/sandbox.py +45 -58
- blaxel/core/client/models/sandbox_definition.py +37 -22
- blaxel/core/client/models/sandbox_definition_categories_item.py +45 -0
- blaxel/core/client/models/sandbox_error.py +148 -0
- blaxel/core/client/models/sandbox_error_details.py +45 -0
- blaxel/core/client/models/sandbox_lifecycle.py +3 -2
- blaxel/core/client/models/sandbox_runtime.py +145 -0
- blaxel/core/client/models/sandbox_spec.py +33 -134
- blaxel/core/client/models/status.py +25 -0
- blaxel/core/client/models/template.py +8 -7
- blaxel/core/client/models/template_variable.py +5 -5
- blaxel/core/client/models/trigger.py +14 -6
- blaxel/core/client/models/trigger_configuration.py +7 -6
- blaxel/core/client/models/trigger_type.py +19 -0
- blaxel/core/client/models/volume.py +35 -47
- blaxel/core/client/models/volume_attachment.py +6 -4
- blaxel/core/client/models/volume_spec.py +7 -4
- blaxel/core/client/models/volume_state.py +3 -3
- blaxel/core/client/models/volume_template.py +19 -33
- blaxel/core/client/models/volume_template_state.py +12 -4
- blaxel/core/client/models/volume_template_state_status.py +19 -0
- blaxel/core/client/models/volume_template_version.py +12 -4
- blaxel/core/client/models/volume_template_version_status.py +19 -0
- blaxel/core/client/models/workspace.py +35 -25
- blaxel/core/client/models/workspace_runtime.py +3 -2
- blaxel/core/client/models/workspace_status.py +22 -0
- blaxel/core/common/__init__.py +1 -1
- blaxel/core/jobs/__init__.py +0 -1
- blaxel/core/sandbox/__init__.py +2 -0
- blaxel/core/sandbox/client/api/process/post_process.py +8 -4
- blaxel/core/sandbox/client/models/__init__.py +0 -2
- blaxel/core/sandbox/client/models/process_response.py +16 -0
- blaxel/core/sandbox/client/models/process_response_status.py +9 -0
- blaxel/core/sandbox/default/__init__.py +2 -0
- blaxel/core/sandbox/default/interpreter.py +5 -1
- blaxel/core/sandbox/default/preview.py +3 -1
- blaxel/core/sandbox/default/sandbox.py +85 -26
- blaxel/core/sandbox/sync/process.py +2 -1
- blaxel/core/sandbox/sync/sandbox.py +68 -23
- blaxel/core/sandbox/types.py +3 -0
- blaxel/core/tools/common.py +16 -2
- blaxel/core/volume/__init__.py +2 -2
- blaxel/core/volume/volume.py +227 -11
- blaxel/langgraph/tools.py +34 -2
- blaxel/openai/tools.py +33 -1
- {blaxel-0.2.33.dist-info → blaxel-0.2.35.dist-info}/METADATA +3 -3
- {blaxel-0.2.33.dist-info → blaxel-0.2.35.dist-info}/RECORD +209 -248
- blaxel/core/client/models/acl.py +0 -133
- blaxel/core/client/models/billable_time_metric.py +0 -89
- blaxel/core/client/models/core_spec.py +0 -194
- blaxel/core/client/models/core_spec_configurations.py +0 -77
- blaxel/core/client/models/histogram_bucket.py +0 -79
- blaxel/core/client/models/histogram_stats.py +0 -88
- blaxel/core/client/models/integration_model.py +0 -162
- blaxel/core/client/models/job_execution_config.py +0 -79
- blaxel/core/client/models/job_metrics.py +0 -262
- blaxel/core/client/models/jobs_chart_value.py +0 -70
- blaxel/core/client/models/jobs_network_chart.py +0 -102
- blaxel/core/client/models/jobs_success_failed_chart.py +0 -147
- blaxel/core/client/models/jobs_total.py +0 -88
- blaxel/core/client/models/last_n_requests_metric.py +0 -97
- blaxel/core/client/models/latency_metric.py +0 -148
- blaxel/core/client/models/logs_response.py +0 -63
- blaxel/core/client/models/logs_response_data.py +0 -99
- blaxel/core/client/models/mcp_definition_form.py +0 -45
- blaxel/core/client/models/memory_allocation_by_name.py +0 -70
- blaxel/core/client/models/memory_allocation_metric.py +0 -61
- blaxel/core/client/models/metric.py +0 -79
- blaxel/core/client/models/metrics.py +0 -273
- blaxel/core/client/models/metrics_models.py +0 -45
- blaxel/core/client/models/metrics_rps_per_code.py +0 -45
- blaxel/core/client/models/pod_template_spec.py +0 -45
- blaxel/core/client/models/request_duration_over_time_metric.py +0 -97
- blaxel/core/client/models/request_duration_over_time_metrics.py +0 -84
- blaxel/core/client/models/request_total_by_origin_metric.py +0 -129
- blaxel/core/client/models/request_total_by_origin_metric_request_total_by_origin.py +0 -45
- blaxel/core/client/models/request_total_by_origin_metric_request_total_by_origin_and_code.py +0 -45
- blaxel/core/client/models/request_total_metric.py +0 -155
- blaxel/core/client/models/request_total_metric_request_total_per_code.py +0 -45
- blaxel/core/client/models/request_total_metric_rps_per_code.py +0 -45
- blaxel/core/client/models/request_total_response_data.py +0 -97
- blaxel/core/client/models/resource.py +0 -99
- blaxel/core/client/models/resource_log.py +0 -88
- blaxel/core/client/models/resource_log_chart.py +0 -133
- blaxel/core/client/models/resource_log_response.py +0 -83
- blaxel/core/client/models/resource_metrics.py +0 -618
- blaxel/core/client/models/resource_metrics_request_total_per_code.py +0 -45
- blaxel/core/client/models/resource_metrics_request_total_per_code_previous.py +0 -45
- blaxel/core/client/models/resource_metrics_rps_per_code.py +0 -45
- blaxel/core/client/models/resource_metrics_rps_per_code_previous.py +0 -45
- blaxel/core/client/models/resource_trace.py +0 -97
- blaxel/core/client/models/runtime.py +0 -317
- blaxel/core/client/models/runtime_configuration.py +0 -45
- blaxel/core/client/models/runtime_startup_probe.py +0 -45
- blaxel/core/client/models/sandbox_metrics.py +0 -88
- blaxel/core/client/models/serverless_config.py +0 -117
- blaxel/core/client/models/serverless_config_configuration.py +0 -45
- blaxel/core/client/models/start_sandbox.py +0 -98
- blaxel/core/client/models/stop_sandbox.py +0 -98
- blaxel/core/client/models/store_agent.py +0 -181
- blaxel/core/client/models/store_agent_labels.py +0 -45
- blaxel/core/client/models/store_configuration.py +0 -156
- blaxel/core/client/models/store_configuration_option.py +0 -79
- blaxel/core/client/models/time_to_first_token_over_time_metrics.py +0 -87
- blaxel/core/client/models/token_rate_metric.py +0 -106
- blaxel/core/client/models/token_rate_metrics.py +0 -124
- blaxel/core/client/models/token_total_metric.py +0 -112
- blaxel/core/client/models/trace_ids_response.py +0 -45
- blaxel/core/client/models/websocket_channel.py +0 -97
- blaxel/core/client/models/websocket_message.py +0 -106
- blaxel/core/sandbox/client/api/root/delete.py +0 -130
- blaxel/core/sandbox/client/api/root/get.py +0 -130
- blaxel/core/sandbox/client/api/root/options.py +0 -130
- blaxel/core/sandbox/client/api/root/patch.py +0 -130
- blaxel/core/sandbox/client/api/root/post.py +0 -130
- blaxel/core/sandbox/client/api/root/put.py +0 -130
- /blaxel/core/{sandbox/client/api/root → client/api/mcphub}/__init__.py +0 -0
- {blaxel-0.2.33.dist-info → blaxel-0.2.35.dist-info}/WHEEL +0 -0
- {blaxel-0.2.33.dist-info → blaxel-0.2.35.dist-info}/licenses/LICENSE +0 -0
blaxel/core/sandbox/types.py
CHANGED
|
@@ -155,6 +155,7 @@ class SandboxCreateConfiguration:
|
|
|
155
155
|
region: str | None = None,
|
|
156
156
|
lifecycle: Union[SandboxLifecycle, Dict[str, Any]] | None = None,
|
|
157
157
|
snapshot_enabled: bool | None = None,
|
|
158
|
+
labels: Dict[str, str] | None = None,
|
|
158
159
|
):
|
|
159
160
|
self.name = name
|
|
160
161
|
self.image = image
|
|
@@ -167,6 +168,7 @@ class SandboxCreateConfiguration:
|
|
|
167
168
|
self.region = region
|
|
168
169
|
self.lifecycle = lifecycle
|
|
169
170
|
self.snapshot_enabled = snapshot_enabled
|
|
171
|
+
self.labels = labels
|
|
170
172
|
|
|
171
173
|
@classmethod
|
|
172
174
|
def from_dict(cls, data: Dict[str, Any]) -> "SandboxCreateConfiguration":
|
|
@@ -190,6 +192,7 @@ class SandboxCreateConfiguration:
|
|
|
190
192
|
region=data.get("region"),
|
|
191
193
|
lifecycle=lifecycle,
|
|
192
194
|
snapshot_enabled=data.get("snapshot_enabled"),
|
|
195
|
+
labels=data.get("labels"),
|
|
193
196
|
)
|
|
194
197
|
|
|
195
198
|
def _normalize_ports(self) -> List[Port] | None:
|
blaxel/core/tools/common.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from typing import Any, Dict, Type
|
|
1
|
+
from typing import Any, Dict, List, Type, Union
|
|
2
2
|
|
|
3
3
|
from pydantic import BaseModel, Field, create_model
|
|
4
4
|
|
|
@@ -13,6 +13,20 @@ json_type_mapping: Dict[str, Type] = {
|
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
|
|
16
|
+
def _get_python_type_from_json_type(json_type: Union[str, List[str]]) -> Type:
|
|
17
|
+
"""Convert JSON Schema type to Python type.
|
|
18
|
+
|
|
19
|
+
Handles both simple types ("string") and nullable types (["string", "null"]).
|
|
20
|
+
"""
|
|
21
|
+
if isinstance(json_type, list):
|
|
22
|
+
# Filter out "null" and get the primary type
|
|
23
|
+
non_null_types = [t for t in json_type if t != "null"]
|
|
24
|
+
if non_null_types:
|
|
25
|
+
return json_type_mapping.get(non_null_types[0], str)
|
|
26
|
+
return type(None)
|
|
27
|
+
return json_type_mapping.get(json_type, str)
|
|
28
|
+
|
|
29
|
+
|
|
16
30
|
def create_model_from_json_schema(
|
|
17
31
|
schema: Dict[str, Any], model_name: str = "DynamicModel"
|
|
18
32
|
) -> Type[BaseModel]:
|
|
@@ -32,7 +46,7 @@ def create_model_from_json_schema(
|
|
|
32
46
|
|
|
33
47
|
for field_name, field_schema in properties.items():
|
|
34
48
|
json_type = field_schema.get("type", "string")
|
|
35
|
-
field_type =
|
|
49
|
+
field_type = _get_python_type_from_json_type(json_type)
|
|
36
50
|
if field_name in required_fields:
|
|
37
51
|
default_value = ...
|
|
38
52
|
else:
|
blaxel/core/volume/__init__.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"""Volume module for persistent storage management."""
|
|
2
2
|
|
|
3
|
-
from .volume import VolumeCreateConfiguration, VolumeInstance
|
|
3
|
+
from .volume import SyncVolumeInstance, VolumeAPIError, VolumeCreateConfiguration, VolumeInstance
|
|
4
4
|
|
|
5
|
-
__all__ = ["VolumeInstance", "VolumeCreateConfiguration"]
|
|
5
|
+
__all__ = ["VolumeInstance", "SyncVolumeInstance", "VolumeCreateConfiguration", "VolumeAPIError"]
|
blaxel/core/volume/volume.py
CHANGED
|
@@ -1,15 +1,65 @@
|
|
|
1
1
|
import uuid
|
|
2
|
-
from typing import Dict, Union
|
|
2
|
+
from typing import Callable, Dict, List, Union
|
|
3
3
|
|
|
4
4
|
from ..client.api.volumes.create_volume import asyncio as create_volume
|
|
5
|
+
from ..client.api.volumes.create_volume import sync as create_volume_sync
|
|
5
6
|
from ..client.api.volumes.delete_volume import asyncio as delete_volume
|
|
7
|
+
from ..client.api.volumes.delete_volume import sync as delete_volume_sync
|
|
6
8
|
from ..client.api.volumes.get_volume import asyncio as get_volume
|
|
9
|
+
from ..client.api.volumes.get_volume import sync as get_volume_sync
|
|
7
10
|
from ..client.api.volumes.list_volumes import asyncio as list_volumes
|
|
11
|
+
from ..client.api.volumes.list_volumes import sync as list_volumes_sync
|
|
8
12
|
from ..client.client import client
|
|
9
13
|
from ..client.models import Metadata, Volume, VolumeSpec
|
|
14
|
+
from ..client.models.error import Error
|
|
10
15
|
from ..client.types import UNSET
|
|
11
16
|
|
|
12
17
|
|
|
18
|
+
class VolumeAPIError(Exception):
|
|
19
|
+
"""Exception raised when volume API returns an error."""
|
|
20
|
+
|
|
21
|
+
def __init__(self, message: str, status_code: int | None = None, code: str | None = None):
|
|
22
|
+
super().__init__(message)
|
|
23
|
+
self.status_code = status_code
|
|
24
|
+
self.code = code
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class _AsyncDeleteDescriptor:
|
|
28
|
+
"""Descriptor that provides both class-level and instance-level delete functionality."""
|
|
29
|
+
|
|
30
|
+
def __init__(self, delete_func: Callable):
|
|
31
|
+
self._delete_func = delete_func
|
|
32
|
+
|
|
33
|
+
def __get__(self, instance, owner):
|
|
34
|
+
if instance is None:
|
|
35
|
+
# Called on the class: VolumeInstance.delete("name")
|
|
36
|
+
return self._delete_func
|
|
37
|
+
else:
|
|
38
|
+
# Called on an instance: instance.delete()
|
|
39
|
+
async def instance_delete() -> Volume:
|
|
40
|
+
return await self._delete_func(instance.metadata.name or "")
|
|
41
|
+
|
|
42
|
+
return instance_delete
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class _SyncDeleteDescriptor:
|
|
46
|
+
"""Descriptor that provides both class-level and instance-level delete functionality (sync)."""
|
|
47
|
+
|
|
48
|
+
def __init__(self, delete_func: Callable):
|
|
49
|
+
self._delete_func = delete_func
|
|
50
|
+
|
|
51
|
+
def __get__(self, instance, owner):
|
|
52
|
+
if instance is None:
|
|
53
|
+
# Called on the class: SyncVolumeInstance.delete("name")
|
|
54
|
+
return self._delete_func
|
|
55
|
+
else:
|
|
56
|
+
# Called on an instance: instance.delete()
|
|
57
|
+
def instance_delete() -> Volume:
|
|
58
|
+
return self._delete_func(instance.metadata.name or "")
|
|
59
|
+
|
|
60
|
+
return instance_delete
|
|
61
|
+
|
|
62
|
+
|
|
13
63
|
class VolumeCreateConfiguration:
|
|
14
64
|
"""Simplified configuration for creating volumes with default values."""
|
|
15
65
|
|
|
@@ -17,12 +67,14 @@ class VolumeCreateConfiguration:
|
|
|
17
67
|
self,
|
|
18
68
|
name: str | None = None,
|
|
19
69
|
display_name: str | None = None,
|
|
70
|
+
labels: Dict[str, str] | None = None,
|
|
20
71
|
size: int | None = None, # Size in MB
|
|
21
72
|
region: str | None = None, # AWS region
|
|
22
73
|
template: str | None = None, # Template
|
|
23
74
|
):
|
|
24
75
|
self.name = name
|
|
25
76
|
self.display_name = display_name
|
|
77
|
+
self.labels = labels
|
|
26
78
|
self.size = size
|
|
27
79
|
self.region = region
|
|
28
80
|
self.template = template
|
|
@@ -32,6 +84,7 @@ class VolumeCreateConfiguration:
|
|
|
32
84
|
return cls(
|
|
33
85
|
name=data.get("name"),
|
|
34
86
|
display_name=data.get("display_name"),
|
|
87
|
+
labels=data.get("labels"),
|
|
35
88
|
size=data.get("size"),
|
|
36
89
|
region=data.get("region"),
|
|
37
90
|
template=data.get("template"),
|
|
@@ -90,6 +143,7 @@ class VolumeInstance:
|
|
|
90
143
|
metadata=Metadata(
|
|
91
144
|
name=config.name or default_name,
|
|
92
145
|
display_name=config.display_name or config.name or default_name,
|
|
146
|
+
labels=config.labels,
|
|
93
147
|
),
|
|
94
148
|
spec=VolumeSpec(
|
|
95
149
|
size=config.size or default_size,
|
|
@@ -103,6 +157,7 @@ class VolumeInstance:
|
|
|
103
157
|
metadata=Metadata(
|
|
104
158
|
name=volume_config.name or default_name,
|
|
105
159
|
display_name=volume_config.display_name or volume_config.name or default_name,
|
|
160
|
+
labels=volume_config.labels,
|
|
106
161
|
),
|
|
107
162
|
spec=VolumeSpec(
|
|
108
163
|
size=volume_config.size or default_size,
|
|
@@ -126,11 +181,19 @@ class VolumeInstance:
|
|
|
126
181
|
volume.spec.size = default_size
|
|
127
182
|
|
|
128
183
|
response = await create_volume(client=client, body=volume)
|
|
184
|
+
if isinstance(response, Error):
|
|
185
|
+
status_code = int(response.code) if response.code is not UNSET else None
|
|
186
|
+
message = response.message if response.message is not UNSET else response.error
|
|
187
|
+
raise VolumeAPIError(message, status_code=status_code, code=response.error)
|
|
129
188
|
return cls(response)
|
|
130
189
|
|
|
131
190
|
@classmethod
|
|
132
191
|
async def get(cls, volume_name: str) -> "VolumeInstance":
|
|
133
192
|
response = await get_volume(volume_name=volume_name, client=client)
|
|
193
|
+
if isinstance(response, Error):
|
|
194
|
+
status_code = int(response.code) if response.code is not UNSET else None
|
|
195
|
+
message = response.message if response.message is not UNSET else response.error
|
|
196
|
+
raise VolumeAPIError(message, status_code=status_code, code=response.error)
|
|
134
197
|
return cls(response)
|
|
135
198
|
|
|
136
199
|
@classmethod
|
|
@@ -138,11 +201,6 @@ class VolumeInstance:
|
|
|
138
201
|
response = await list_volumes(client=client)
|
|
139
202
|
return [cls(volume) for volume in response or []]
|
|
140
203
|
|
|
141
|
-
@classmethod
|
|
142
|
-
async def delete(cls, volume_name: str) -> Volume:
|
|
143
|
-
response = await delete_volume(volume_name=volume_name, client=client)
|
|
144
|
-
return response
|
|
145
|
-
|
|
146
204
|
@classmethod
|
|
147
205
|
async def create_if_not_exists(
|
|
148
206
|
cls, config: Union[VolumeCreateConfiguration, Volume, Dict[str, any]]
|
|
@@ -150,11 +208,9 @@ class VolumeInstance:
|
|
|
150
208
|
"""Create a volume if it doesn't exist, otherwise return existing."""
|
|
151
209
|
try:
|
|
152
210
|
return await cls.create(config)
|
|
153
|
-
except
|
|
211
|
+
except VolumeAPIError as e:
|
|
154
212
|
# Check if it's a 409 conflict error (volume already exists)
|
|
155
|
-
if
|
|
156
|
-
hasattr(e, "code") and e.code in [409, "VOLUME_ALREADY_EXISTS"]
|
|
157
|
-
):
|
|
213
|
+
if e.status_code == 409 or e.code in ["409", "VOLUME_ALREADY_EXISTS"]:
|
|
158
214
|
# Extract name from different configuration types
|
|
159
215
|
if isinstance(config, VolumeCreateConfiguration):
|
|
160
216
|
name = config.name
|
|
@@ -170,4 +226,164 @@ class VolumeInstance:
|
|
|
170
226
|
|
|
171
227
|
volume_instance = await cls.get(name)
|
|
172
228
|
return volume_instance
|
|
173
|
-
raise
|
|
229
|
+
raise
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
class SyncVolumeInstance:
|
|
233
|
+
"""Synchronous volume instance for managing persistent storage."""
|
|
234
|
+
|
|
235
|
+
def __init__(self, volume: Volume):
|
|
236
|
+
self.volume = volume
|
|
237
|
+
|
|
238
|
+
@property
|
|
239
|
+
def metadata(self):
|
|
240
|
+
return self.volume.metadata
|
|
241
|
+
|
|
242
|
+
@property
|
|
243
|
+
def spec(self):
|
|
244
|
+
return self.volume.spec
|
|
245
|
+
|
|
246
|
+
@property
|
|
247
|
+
def status(self):
|
|
248
|
+
return self.volume.status
|
|
249
|
+
|
|
250
|
+
@property
|
|
251
|
+
def name(self):
|
|
252
|
+
return self.volume.metadata.name if self.volume.metadata else None
|
|
253
|
+
|
|
254
|
+
@property
|
|
255
|
+
def display_name(self):
|
|
256
|
+
return self.volume.metadata.display_name if self.volume.metadata else None
|
|
257
|
+
|
|
258
|
+
@property
|
|
259
|
+
def size(self):
|
|
260
|
+
return self.volume.spec.size if self.volume.spec else None
|
|
261
|
+
|
|
262
|
+
@property
|
|
263
|
+
def region(self):
|
|
264
|
+
return self.volume.spec.region if self.volume.spec else None
|
|
265
|
+
|
|
266
|
+
@property
|
|
267
|
+
def template(self):
|
|
268
|
+
return self.volume.spec.template if self.volume.spec else None
|
|
269
|
+
|
|
270
|
+
@classmethod
|
|
271
|
+
def create(
|
|
272
|
+
cls, config: Union[VolumeCreateConfiguration, Volume, Dict[str, any]]
|
|
273
|
+
) -> "SyncVolumeInstance":
|
|
274
|
+
"""Create a new volume synchronously."""
|
|
275
|
+
# Generate default values
|
|
276
|
+
default_name = f"volume-{uuid.uuid4().hex[:8]}"
|
|
277
|
+
default_size = 1024 # 1GB in MB
|
|
278
|
+
|
|
279
|
+
# Handle different configuration types
|
|
280
|
+
if isinstance(config, Volume):
|
|
281
|
+
volume = config
|
|
282
|
+
elif isinstance(config, VolumeCreateConfiguration):
|
|
283
|
+
volume = Volume(
|
|
284
|
+
metadata=Metadata(
|
|
285
|
+
name=config.name or default_name,
|
|
286
|
+
display_name=config.display_name or config.name or default_name,
|
|
287
|
+
labels=config.labels,
|
|
288
|
+
),
|
|
289
|
+
spec=VolumeSpec(
|
|
290
|
+
size=config.size or default_size,
|
|
291
|
+
region=config.region or UNSET,
|
|
292
|
+
template=config.template or UNSET,
|
|
293
|
+
),
|
|
294
|
+
)
|
|
295
|
+
elif isinstance(config, dict):
|
|
296
|
+
volume_config = VolumeCreateConfiguration.from_dict(config)
|
|
297
|
+
volume = Volume(
|
|
298
|
+
metadata=Metadata(
|
|
299
|
+
name=volume_config.name or default_name,
|
|
300
|
+
display_name=volume_config.display_name or volume_config.name or default_name,
|
|
301
|
+
labels=volume_config.labels,
|
|
302
|
+
),
|
|
303
|
+
spec=VolumeSpec(
|
|
304
|
+
size=volume_config.size or default_size,
|
|
305
|
+
region=volume_config.region or UNSET,
|
|
306
|
+
template=volume_config.template or UNSET,
|
|
307
|
+
),
|
|
308
|
+
)
|
|
309
|
+
else:
|
|
310
|
+
raise ValueError(
|
|
311
|
+
f"Invalid config type: {type(config)}. Expected VolumeCreateConfiguration, Volume, or dict."
|
|
312
|
+
)
|
|
313
|
+
|
|
314
|
+
# Ensure required fields have defaults
|
|
315
|
+
if not volume.metadata:
|
|
316
|
+
volume.metadata = Metadata(name=default_name)
|
|
317
|
+
if not volume.metadata.name:
|
|
318
|
+
volume.metadata.name = default_name
|
|
319
|
+
if not volume.spec:
|
|
320
|
+
volume.spec = VolumeSpec(size=default_size)
|
|
321
|
+
if not volume.spec.size:
|
|
322
|
+
volume.spec.size = default_size
|
|
323
|
+
|
|
324
|
+
response = create_volume_sync(client=client, body=volume)
|
|
325
|
+
if isinstance(response, Error):
|
|
326
|
+
status_code = int(response.code) if response.code is not UNSET else None
|
|
327
|
+
message = response.message if response.message is not UNSET else response.error
|
|
328
|
+
raise VolumeAPIError(message, status_code=status_code, code=response.error)
|
|
329
|
+
return cls(response)
|
|
330
|
+
|
|
331
|
+
@classmethod
|
|
332
|
+
def get(cls, volume_name: str) -> "SyncVolumeInstance":
|
|
333
|
+
"""Get a volume by name synchronously."""
|
|
334
|
+
response = get_volume_sync(volume_name=volume_name, client=client)
|
|
335
|
+
if isinstance(response, Error):
|
|
336
|
+
status_code = int(response.code) if response.code is not UNSET else None
|
|
337
|
+
message = response.message if response.message is not UNSET else response.error
|
|
338
|
+
raise VolumeAPIError(message, status_code=status_code, code=response.error)
|
|
339
|
+
return cls(response)
|
|
340
|
+
|
|
341
|
+
@classmethod
|
|
342
|
+
def list(cls) -> List["SyncVolumeInstance"]:
|
|
343
|
+
"""List all volumes synchronously."""
|
|
344
|
+
response = list_volumes_sync(client=client)
|
|
345
|
+
return [cls(volume) for volume in response or []]
|
|
346
|
+
|
|
347
|
+
@classmethod
|
|
348
|
+
def create_if_not_exists(
|
|
349
|
+
cls, config: Union[VolumeCreateConfiguration, Volume, Dict[str, any]]
|
|
350
|
+
) -> "SyncVolumeInstance":
|
|
351
|
+
"""Create a volume if it doesn't exist, otherwise return existing."""
|
|
352
|
+
try:
|
|
353
|
+
return cls.create(config)
|
|
354
|
+
except VolumeAPIError as e:
|
|
355
|
+
# Check if it's a 409 conflict error (volume already exists)
|
|
356
|
+
if e.status_code == 409 or e.code in ["409", "VOLUME_ALREADY_EXISTS"]:
|
|
357
|
+
# Extract name from different configuration types
|
|
358
|
+
if isinstance(config, VolumeCreateConfiguration):
|
|
359
|
+
name = config.name
|
|
360
|
+
elif isinstance(config, dict):
|
|
361
|
+
name = config.get("name")
|
|
362
|
+
elif isinstance(config, Volume):
|
|
363
|
+
name = config.metadata.name if config.metadata else None
|
|
364
|
+
else:
|
|
365
|
+
name = None
|
|
366
|
+
|
|
367
|
+
if not name:
|
|
368
|
+
raise ValueError("Volume name is required")
|
|
369
|
+
|
|
370
|
+
volume_instance = cls.get(name)
|
|
371
|
+
return volume_instance
|
|
372
|
+
raise
|
|
373
|
+
|
|
374
|
+
|
|
375
|
+
async def _delete_volume_by_name(volume_name: str) -> Volume:
|
|
376
|
+
"""Delete a volume by name (async)."""
|
|
377
|
+
response = await delete_volume(volume_name=volume_name, client=client)
|
|
378
|
+
return response
|
|
379
|
+
|
|
380
|
+
|
|
381
|
+
def _delete_volume_by_name_sync(volume_name: str) -> Volume:
|
|
382
|
+
"""Delete a volume by name (sync)."""
|
|
383
|
+
response = delete_volume_sync(volume_name=volume_name, client=client)
|
|
384
|
+
return response
|
|
385
|
+
|
|
386
|
+
|
|
387
|
+
# Assign the delete descriptors to support both class-level and instance-level calls
|
|
388
|
+
VolumeInstance.delete = _AsyncDeleteDescriptor(_delete_volume_by_name)
|
|
389
|
+
SyncVolumeInstance.delete = _SyncDeleteDescriptor(_delete_volume_by_name_sync)
|
blaxel/langgraph/tools.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from typing import Any
|
|
1
|
+
from typing import Any, Dict
|
|
2
2
|
|
|
3
3
|
from langchain_core.tools import StructuredTool
|
|
4
4
|
from mcp.types import (
|
|
@@ -14,6 +14,35 @@ from blaxel.core.tools.types import Tool, ToolException
|
|
|
14
14
|
NonTextContent = ImageContent | EmbeddedResource
|
|
15
15
|
|
|
16
16
|
|
|
17
|
+
def _clean_schema_for_openai(schema: Dict[str, Any]) -> Dict[str, Any]:
|
|
18
|
+
"""Clean JSON schema to be compatible with OpenAI function calling.
|
|
19
|
+
|
|
20
|
+
OpenAI requires object schemas to have a 'properties' field, even if empty.
|
|
21
|
+
This function ensures the schema is properly formatted.
|
|
22
|
+
"""
|
|
23
|
+
if not isinstance(schema, dict):
|
|
24
|
+
return schema
|
|
25
|
+
|
|
26
|
+
cleaned = schema.copy()
|
|
27
|
+
|
|
28
|
+
# Ensure object type schemas have properties
|
|
29
|
+
if cleaned.get("type") == "object":
|
|
30
|
+
if "properties" not in cleaned:
|
|
31
|
+
cleaned["properties"] = {}
|
|
32
|
+
if "required" not in cleaned:
|
|
33
|
+
cleaned["required"] = []
|
|
34
|
+
|
|
35
|
+
# Recursively clean nested schemas
|
|
36
|
+
if "properties" in cleaned:
|
|
37
|
+
cleaned["properties"] = {
|
|
38
|
+
k: _clean_schema_for_openai(v) for k, v in cleaned["properties"].items()
|
|
39
|
+
}
|
|
40
|
+
if "items" in cleaned and isinstance(cleaned["items"], dict):
|
|
41
|
+
cleaned["items"] = _clean_schema_for_openai(cleaned["items"])
|
|
42
|
+
|
|
43
|
+
return cleaned
|
|
44
|
+
|
|
45
|
+
|
|
17
46
|
def get_langchain_tool(tool: Tool) -> StructuredTool:
|
|
18
47
|
async def langchain_coroutine(
|
|
19
48
|
**arguments: dict[str, Any],
|
|
@@ -36,10 +65,13 @@ def get_langchain_tool(tool: Tool) -> StructuredTool:
|
|
|
36
65
|
|
|
37
66
|
return tool_content, non_text_contents or None
|
|
38
67
|
|
|
68
|
+
# Clean the schema to ensure OpenAI compatibility
|
|
69
|
+
cleaned_schema = _clean_schema_for_openai(tool.input_schema)
|
|
70
|
+
|
|
39
71
|
return StructuredTool(
|
|
40
72
|
name=tool.name,
|
|
41
73
|
description=tool.description,
|
|
42
|
-
args_schema=
|
|
74
|
+
args_schema=cleaned_schema,
|
|
43
75
|
coroutine=langchain_coroutine,
|
|
44
76
|
sync_coroutine=tool.sync_coroutine,
|
|
45
77
|
)
|
blaxel/openai/tools.py
CHANGED
|
@@ -7,6 +7,36 @@ from blaxel.core.tools import bl_tools as bl_tools_core
|
|
|
7
7
|
from blaxel.core.tools.types import Tool
|
|
8
8
|
|
|
9
9
|
|
|
10
|
+
def _clean_schema_for_openai(schema: dict) -> dict:
|
|
11
|
+
"""Clean JSON schema to be compatible with OpenAI agents SDK.
|
|
12
|
+
|
|
13
|
+
OpenAI agents SDK doesn't allow additionalProperties on object types.
|
|
14
|
+
This function recursively removes additionalProperties and $schema fields.
|
|
15
|
+
"""
|
|
16
|
+
if not isinstance(schema, dict):
|
|
17
|
+
return schema
|
|
18
|
+
|
|
19
|
+
cleaned_schema = schema.copy()
|
|
20
|
+
|
|
21
|
+
# Remove $schema and additionalProperties at current level
|
|
22
|
+
if "$schema" in cleaned_schema:
|
|
23
|
+
del cleaned_schema["$schema"]
|
|
24
|
+
if "additionalProperties" in cleaned_schema:
|
|
25
|
+
del cleaned_schema["additionalProperties"]
|
|
26
|
+
|
|
27
|
+
# Recursively clean properties if they exist
|
|
28
|
+
if "properties" in cleaned_schema:
|
|
29
|
+
cleaned_schema["properties"] = {
|
|
30
|
+
k: _clean_schema_for_openai(v) for k, v in cleaned_schema["properties"].items()
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
# Recursively clean items for array types
|
|
34
|
+
if "items" in cleaned_schema:
|
|
35
|
+
cleaned_schema["items"] = _clean_schema_for_openai(cleaned_schema["items"])
|
|
36
|
+
|
|
37
|
+
return cleaned_schema
|
|
38
|
+
|
|
39
|
+
|
|
10
40
|
def get_openai_tool(tool: Tool) -> FunctionTool:
|
|
11
41
|
async def openai_coroutine(
|
|
12
42
|
_: RunContextWrapper,
|
|
@@ -15,10 +45,12 @@ def get_openai_tool(tool: Tool) -> FunctionTool:
|
|
|
15
45
|
result = await tool.coroutine(**json.loads(arguments))
|
|
16
46
|
return result
|
|
17
47
|
|
|
48
|
+
cleaned_schema = _clean_schema_for_openai(tool.input_schema)
|
|
49
|
+
|
|
18
50
|
return FunctionTool(
|
|
19
51
|
name=tool.name,
|
|
20
52
|
description=tool.description,
|
|
21
|
-
params_json_schema=
|
|
53
|
+
params_json_schema=cleaned_schema,
|
|
22
54
|
on_invoke_tool=openai_coroutine,
|
|
23
55
|
)
|
|
24
56
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: blaxel
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.35
|
|
4
4
|
Summary: Blaxel - AI development platform SDK
|
|
5
5
|
Project-URL: Homepage, https://blaxel.ai
|
|
6
6
|
Project-URL: Documentation, https://docs.blaxel.ai
|
|
@@ -23,7 +23,7 @@ Provides-Extra: all
|
|
|
23
23
|
Requires-Dist: crewai==0.159.0; extra == 'all'
|
|
24
24
|
Requires-Dist: google-adk>=1.4.0; extra == 'all'
|
|
25
25
|
Requires-Dist: langchain-anthropic>=0.3.10; extra == 'all'
|
|
26
|
-
Requires-Dist: langchain-cerebras
|
|
26
|
+
Requires-Dist: langchain-cerebras<0.6.0,>=0.5.0; extra == 'all'
|
|
27
27
|
Requires-Dist: langchain-cohere>=0.4.3; extra == 'all'
|
|
28
28
|
Requires-Dist: langchain-community<0.4.0,>=0.3.3; extra == 'all'
|
|
29
29
|
Requires-Dist: langchain-core<0.4.0,>=0.3.13; extra == 'all'
|
|
@@ -74,7 +74,7 @@ Requires-Dist: google-adk>=1.4.0; extra == 'googleadk'
|
|
|
74
74
|
Requires-Dist: litellm>=1.63.11; extra == 'googleadk'
|
|
75
75
|
Provides-Extra: langgraph
|
|
76
76
|
Requires-Dist: langchain-anthropic>=0.3.10; extra == 'langgraph'
|
|
77
|
-
Requires-Dist: langchain-cerebras
|
|
77
|
+
Requires-Dist: langchain-cerebras<0.6.0,>=0.5.0; extra == 'langgraph'
|
|
78
78
|
Requires-Dist: langchain-cohere>=0.4.3; extra == 'langgraph'
|
|
79
79
|
Requires-Dist: langchain-community<0.4.0,>=0.3.3; extra == 'langgraph'
|
|
80
80
|
Requires-Dist: langchain-core<0.4.0,>=0.3.13; extra == 'langgraph'
|