fleet-python 0.2.2__py3-none-any.whl → 0.2.4__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.

Potentially problematic release.


This version of fleet-python might be problematic. Click here for more details.

Files changed (47) hide show
  1. examples/dsl_example.py +108 -92
  2. examples/example.py +2 -2
  3. examples/json_tasks_example.py +82 -0
  4. examples/nova_act_example.py +18 -169
  5. examples/openai_example.py +89 -311
  6. examples/openai_simple_example.py +60 -0
  7. examples/quickstart.py +5 -5
  8. fleet/__init__.py +32 -3
  9. fleet/_async/base.py +51 -0
  10. fleet/_async/client.py +133 -0
  11. fleet/_async/env/__init__.py +0 -0
  12. fleet/_async/env/client.py +15 -0
  13. fleet/_async/exceptions.py +73 -0
  14. fleet/{manager → _async/instance}/__init__.py +4 -2
  15. fleet/{manager → _async/instance}/base.py +1 -24
  16. fleet/{manager → _async/instance}/client.py +44 -24
  17. fleet/{manager → _async/instance}/models.py +13 -0
  18. fleet/_async/models.py +109 -0
  19. fleet/_async/playwright.py +291 -0
  20. fleet/_async/resources/__init__.py +0 -0
  21. fleet/_async/resources/base.py +26 -0
  22. fleet/_async/resources/browser.py +41 -0
  23. fleet/_async/resources/sqlite.py +41 -0
  24. fleet/base.py +1 -24
  25. fleet/client.py +42 -95
  26. fleet/env/__init__.py +13 -1
  27. fleet/env/client.py +7 -7
  28. fleet/instance/__init__.py +26 -0
  29. fleet/instance/base.py +37 -0
  30. fleet/instance/client.py +278 -0
  31. fleet/instance/models.py +141 -0
  32. fleet/playwright.py +289 -0
  33. fleet/resources/__init__.py +0 -0
  34. fleet/resources/base.py +1 -1
  35. fleet/resources/browser.py +20 -23
  36. fleet/resources/sqlite.py +13 -13
  37. fleet/verifiers/__init__.py +10 -3
  38. fleet/verifiers/code.py +1 -0
  39. fleet/verifiers/{database_snapshot.py → db.py} +62 -22
  40. fleet/verifiers/sql_differ.py +1 -1
  41. {fleet_python-0.2.2.dist-info → fleet_python-0.2.4.dist-info}/METADATA +4 -1
  42. fleet_python-0.2.4.dist-info/RECORD +48 -0
  43. {fleet_python-0.2.2.dist-info → fleet_python-0.2.4.dist-info}/top_level.txt +1 -0
  44. scripts/unasync.py +28 -0
  45. fleet_python-0.2.2.dist-info/RECORD +0 -27
  46. {fleet_python-0.2.2.dist-info → fleet_python-0.2.4.dist-info}/WHEEL +0 -0
  47. {fleet_python-0.2.2.dist-info → fleet_python-0.2.4.dist-info}/licenses/LICENSE +0 -0
fleet/_async/base.py ADDED
@@ -0,0 +1,51 @@
1
+ import httpx
2
+ from typing import Dict, Any, Optional
3
+
4
+ from .models import InstanceResponse
5
+
6
+
7
+ class EnvironmentBase(InstanceResponse):
8
+ @property
9
+ def manager_url(self) -> str:
10
+ return f"{self.urls.manager.api}"
11
+
12
+
13
+ class BaseWrapper:
14
+ def __init__(self, *, api_key: Optional[str], base_url: Optional[str]):
15
+ if api_key is None:
16
+ raise ValueError("api_key is required")
17
+ self.api_key = api_key
18
+ if base_url is None:
19
+ base_url = "https://fleet.new"
20
+ self.base_url = base_url
21
+
22
+ def get_headers(self) -> Dict[str, str]:
23
+ headers: Dict[str, str] = {
24
+ "X-Fleet-SDK-Language": "Python",
25
+ "X-Fleet-SDK-Version": "1.0.0",
26
+ }
27
+ headers["Authorization"] = f"Bearer {self.api_key}"
28
+ return headers
29
+
30
+
31
+ class AsyncWrapper(BaseWrapper):
32
+ def __init__(self, *, httpx_client: httpx.AsyncClient, **kwargs):
33
+ super().__init__(**kwargs)
34
+ self.httpx_client = httpx_client
35
+
36
+ async def request(
37
+ self,
38
+ method: str,
39
+ url: str,
40
+ params: Optional[Dict[str, Any]] = None,
41
+ json: Optional[Any] = None,
42
+ **kwargs,
43
+ ) -> httpx.Response:
44
+ return await self.httpx_client.request(
45
+ method,
46
+ f"{self.base_url}{url}",
47
+ headers=self.get_headers(),
48
+ params=params,
49
+ json=json,
50
+ **kwargs,
51
+ )
fleet/_async/client.py ADDED
@@ -0,0 +1,133 @@
1
+ # Copyright 2025 Fleet AI
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """Fleet API Client for making HTTP requests to Fleet services."""
16
+
17
+ import os
18
+ import httpx
19
+ import logging
20
+ from typing import Optional, List
21
+
22
+ from .base import EnvironmentBase, AsyncWrapper
23
+ from .models import InstanceRequest, InstanceRecord, Environment as EnvironmentModel
24
+
25
+ from .instance import (
26
+ AsyncInstanceClient,
27
+ ResetRequest,
28
+ ResetResponse,
29
+ ValidatorType,
30
+ ExecuteFunctionResponse,
31
+ )
32
+ from .resources.base import Resource
33
+ from .resources.sqlite import AsyncSQLiteResource
34
+ from .resources.browser import AsyncBrowserResource
35
+
36
+ logger = logging.getLogger(__name__)
37
+
38
+
39
+ class AsyncEnvironment(EnvironmentBase):
40
+ def __init__(self, httpx_client: Optional[httpx.AsyncClient] = None, **kwargs):
41
+ super().__init__(**kwargs)
42
+ self._httpx_client = httpx_client or httpx.AsyncClient(timeout=60.0)
43
+ self._instance: Optional[AsyncInstanceClient] = None
44
+
45
+ @property
46
+ def instance(self) -> AsyncInstanceClient:
47
+ if self._instance is None:
48
+ self._instance = AsyncInstanceClient(self.manager_url, self._httpx_client)
49
+ return self._instance
50
+
51
+ async def reset(
52
+ self, seed: Optional[int] = None, timestamp: Optional[int] = None
53
+ ) -> ResetResponse:
54
+ return await self.instance.reset(ResetRequest(seed=seed, timestamp=timestamp))
55
+
56
+ def db(self, name: str = "current") -> AsyncSQLiteResource:
57
+ return self.instance.db(name)
58
+
59
+ def browser(self, name: str = "cdp") -> AsyncBrowserResource:
60
+ return self.instance.browser(name)
61
+
62
+ def state(self, uri: str) -> Resource:
63
+ return self.instance.state(uri)
64
+
65
+ async def resources(self) -> List[Resource]:
66
+ return await self.instance.resources()
67
+
68
+ async def close(self) -> InstanceRecord:
69
+ return await AsyncFleet().delete(self.instance_id)
70
+
71
+ async def verify(self, validator: ValidatorType) -> ExecuteFunctionResponse:
72
+ return await self.instance.verify(validator)
73
+
74
+ async def verify_raw(
75
+ self, function_code: str, function_name: str
76
+ ) -> ExecuteFunctionResponse:
77
+ return await self.instance.verify_raw(function_code, function_name)
78
+
79
+
80
+ class AsyncFleet:
81
+ def __init__(
82
+ self,
83
+ api_key: Optional[str] = os.getenv("FLEET_API_KEY"),
84
+ base_url: Optional[str] = None,
85
+ httpx_client: Optional[httpx.AsyncClient] = None,
86
+ ):
87
+ self._httpx_client = httpx_client or httpx.AsyncClient(timeout=60.0)
88
+ self.client = AsyncWrapper(
89
+ api_key=api_key,
90
+ base_url=base_url,
91
+ httpx_client=self._httpx_client,
92
+ )
93
+
94
+ async def list_envs(self) -> List[EnvironmentModel]:
95
+ response = await self.client.request("GET", "/v1/env/")
96
+ return [EnvironmentModel(**env_data) for env_data in response.json()]
97
+
98
+ async def environment(self, env_key: str) -> EnvironmentModel:
99
+ response = await self.client.request("GET", f"/v1/env/{env_key}")
100
+ return EnvironmentModel(**response.json())
101
+
102
+ async def make(self, env_key: str) -> AsyncEnvironment:
103
+ if ":" in env_key:
104
+ env_key_part, version = env_key.split(":", 1)
105
+ if not version.startswith("v"):
106
+ version = f"v{version}"
107
+ else:
108
+ env_key_part = env_key
109
+ version = None
110
+
111
+ request = InstanceRequest(env_key=env_key_part, version=version)
112
+ response = await self.client.request(
113
+ "POST", "/v1/env/instances", json=request.model_dump()
114
+ )
115
+ instance = AsyncEnvironment(**response.json())
116
+ await instance.instance.load()
117
+ return instance
118
+
119
+ async def instances(self, status: Optional[str] = None) -> List[AsyncEnvironment]:
120
+ params = {}
121
+ if status:
122
+ params["status"] = status
123
+
124
+ response = await self.client.request("GET", "/v1/env/instances", params=params)
125
+ return [AsyncEnvironment(**instance_data) for instance_data in response.json()]
126
+
127
+ async def instance(self, instance_id: str) -> AsyncEnvironment:
128
+ response = await self.client.request("GET", f"/v1/env/instances/{instance_id}")
129
+ return AsyncEnvironment(**response.json())
130
+
131
+ async def delete(self, instance_id: str) -> InstanceRecord:
132
+ response = await self.client.request("DELETE", f"/v1/env/instances/{instance_id}")
133
+ return InstanceRecord(**response.json())
File without changes
@@ -0,0 +1,15 @@
1
+ from ..client import AsyncFleet, AsyncEnvironment
2
+ from ..models import Environment as EnvironmentModel
3
+ from typing import List
4
+
5
+
6
+ async def make_async(env_key: str) -> AsyncEnvironment:
7
+ return await AsyncFleet().make(env_key)
8
+
9
+
10
+ async def list_envs_async() -> List[EnvironmentModel]:
11
+ return await AsyncFleet().list_envs()
12
+
13
+
14
+ async def get_async(instance_id: str) -> AsyncEnvironment:
15
+ return await AsyncFleet().instance(instance_id)
@@ -0,0 +1,73 @@
1
+ """Fleet SDK Exception Classes."""
2
+
3
+ from typing import Any, Dict, Optional
4
+
5
+
6
+ class FleetError(Exception):
7
+ """Base exception for all Fleet SDK errors."""
8
+
9
+ def __init__(self, message: str, details: Optional[Dict[str, Any]] = None):
10
+ super().__init__(message)
11
+ self.message = message
12
+ self.details = details or {}
13
+
14
+
15
+ class FleetAPIError(FleetError):
16
+ """Exception raised when Fleet API returns an error."""
17
+
18
+ def __init__(
19
+ self,
20
+ message: str,
21
+ status_code: Optional[int] = None,
22
+ response_data: Optional[Dict[str, Any]] = None,
23
+ details: Optional[Dict[str, Any]] = None,
24
+ ):
25
+ super().__init__(message, details)
26
+ self.status_code = status_code
27
+ self.response_data = response_data or {}
28
+
29
+
30
+ class FleetTimeoutError(FleetError):
31
+ """Exception raised when a Fleet operation times out."""
32
+
33
+ def __init__(self, message: str, timeout_duration: Optional[float] = None):
34
+ super().__init__(message)
35
+ self.timeout_duration = timeout_duration
36
+
37
+
38
+ class FleetAuthenticationError(FleetAPIError):
39
+ """Exception raised when authentication fails."""
40
+
41
+ def __init__(self, message: str = "Authentication failed"):
42
+ super().__init__(message, status_code=401)
43
+
44
+
45
+ class FleetRateLimitError(FleetAPIError):
46
+ """Exception raised when rate limit is exceeded."""
47
+
48
+ def __init__(self, message: str = "Rate limit exceeded"):
49
+ super().__init__(message, status_code=429)
50
+
51
+
52
+ class FleetEnvironmentError(FleetError):
53
+ """Exception raised when environment operations fail."""
54
+
55
+ def __init__(self, message: str, environment_id: Optional[str] = None):
56
+ super().__init__(message)
57
+ self.environment_id = environment_id
58
+
59
+
60
+ class FleetFacetError(FleetError):
61
+ """Exception raised when facet operations fail."""
62
+
63
+ def __init__(self, message: str, facet_type: Optional[str] = None):
64
+ super().__init__(message)
65
+ self.facet_type = facet_type
66
+
67
+
68
+ class FleetConfigurationError(FleetError):
69
+ """Exception raised when configuration is invalid."""
70
+
71
+ def __init__(self, message: str, config_key: Optional[str] = None):
72
+ super().__init__(message)
73
+ self.config_key = config_key
@@ -1,6 +1,6 @@
1
1
  """Fleet SDK Environment Module."""
2
2
 
3
- from .client import InstanceClient, AsyncInstanceClient
3
+ from .client import AsyncInstanceClient, ValidatorType
4
4
  from .models import (
5
5
  ResetRequest,
6
6
  ResetResponse,
@@ -8,10 +8,11 @@ from .models import (
8
8
  ChromeStartRequest,
9
9
  ChromeStartResponse,
10
10
  ChromeStatusResponse,
11
+ ExecuteFunctionResponse,
11
12
  )
12
13
 
13
14
  __all__ = [
14
- "InstanceClient",
15
+ "ValidatorType",
15
16
  "AsyncInstanceClient",
16
17
  "ResetRequest",
17
18
  "ResetResponse",
@@ -19,4 +20,5 @@ __all__ = [
19
20
  "ChromeStartRequest",
20
21
  "ChromeStartResponse",
21
22
  "ChromeStatusResponse",
23
+ "ExecuteFunctionResponse"
22
24
  ]
@@ -14,29 +14,6 @@ class BaseWrapper:
14
14
  return headers
15
15
 
16
16
 
17
- class SyncWrapper(BaseWrapper):
18
- def __init__(self, *, httpx_client: httpx.Client, **kwargs):
19
- super().__init__(**kwargs)
20
- self.httpx_client = httpx_client
21
-
22
- def request(
23
- self,
24
- method: str,
25
- path: str,
26
- params: Optional[Dict[str, Any]] = None,
27
- json: Optional[Any] = None,
28
- **kwargs,
29
- ) -> httpx.Response:
30
- return self.httpx_client.request(
31
- method,
32
- f"{self.url}{path}",
33
- headers=self.get_headers(),
34
- params=params,
35
- json=json,
36
- **kwargs,
37
- )
38
-
39
-
40
17
  class AsyncWrapper(BaseWrapper):
41
18
  def __init__(self, *, httpx_client: httpx.AsyncClient, **kwargs):
42
19
  super().__init__(**kwargs)
@@ -57,4 +34,4 @@ class AsyncWrapper(BaseWrapper):
57
34
  params=params,
58
35
  json=json,
59
36
  **kwargs,
60
- )
37
+ )
@@ -1,8 +1,9 @@
1
- """Fleet SDK Base Environment Classes."""
1
+ """Fleet SDK Async Instance Client."""
2
2
 
3
- from typing import Any, Dict, List, Optional, Tuple
3
+ from typing import Any, Callable, Dict, List, Optional, Tuple
4
4
  import asyncio
5
5
  import httpx
6
+ import inspect
6
7
  import time
7
8
  import logging
8
9
  from urllib.parse import urlparse
@@ -11,15 +12,19 @@ from ..resources.sqlite import AsyncSQLiteResource
11
12
  from ..resources.browser import AsyncBrowserResource
12
13
  from ..resources.base import Resource
13
14
 
15
+ from ...verifiers import DatabaseSnapshot
16
+
14
17
  from ..exceptions import FleetEnvironmentError, FleetAPIError
15
18
 
16
- from .base import SyncWrapper, AsyncWrapper
19
+ from .base import AsyncWrapper
17
20
  from .models import (
18
21
  ResetRequest,
19
22
  ResetResponse,
20
23
  Resource as ResourceModel,
21
24
  ResourceType,
22
25
  HealthResponse,
26
+ ExecuteFunctionRequest,
27
+ ExecuteFunctionResponse,
23
28
  )
24
29
 
25
30
 
@@ -31,22 +36,10 @@ RESOURCE_TYPES = {
31
36
  ResourceType.cdp: AsyncBrowserResource,
32
37
  }
33
38
 
34
-
35
- class InstanceClient:
36
- def __init__(
37
- self,
38
- url: str,
39
- httpx_client: Optional[httpx.Client] = None,
40
- ):
41
- self.base_url = url
42
- self.client = SyncWrapper(
43
- url=self.base_url, httpx_client=httpx_client or httpx.Client()
44
- )
45
- raise NotImplementedError("SyncManager is not implemented")
46
-
47
- def reset(self) -> ResetResponse:
48
- response = self.client.request("POST", "/reset")
49
- return ResetResponse(**response.json())
39
+ ValidatorType = Callable[
40
+ [DatabaseSnapshot, DatabaseSnapshot, Optional[str]],
41
+ int,
42
+ ]
50
43
 
51
44
 
52
45
  class AsyncInstanceClient:
@@ -57,7 +50,8 @@ class AsyncInstanceClient:
57
50
  ):
58
51
  self.base_url = url
59
52
  self.client = AsyncWrapper(
60
- url=self.base_url, httpx_client=httpx_client or httpx.AsyncClient()
53
+ url=self.base_url,
54
+ httpx_client=httpx_client or httpx.AsyncClient(timeout=60.0),
61
55
  )
62
56
  self._resources: Optional[List[ResourceModel]] = None
63
57
  self._resources_state: Dict[str, Dict[str, Resource]] = {
@@ -106,15 +100,41 @@ class AsyncInstanceClient:
106
100
  for resource in resources_by_name.values()
107
101
  ]
108
102
 
103
+ async def verify(self, validator: ValidatorType) -> ExecuteFunctionResponse:
104
+ function_code = inspect.getsource(validator)
105
+ function_name = validator.__name__
106
+ return await self.verify_raw(function_code, function_name)
107
+
108
+ async def verify_raw(
109
+ self, function_code: str, function_name: str
110
+ ) -> ExecuteFunctionResponse:
111
+ response = await self.client.request(
112
+ "POST",
113
+ "/execute_verifier_function",
114
+ json=ExecuteFunctionRequest(
115
+ function_code=function_code,
116
+ function_name=function_name,
117
+ ).model_dump(),
118
+ )
119
+ return ExecuteFunctionResponse(**response.json())
120
+
109
121
  async def _load_resources(self) -> None:
110
122
  if self._resources is None:
111
123
  response = await self.client.request("GET", "/resources")
112
124
  if response.status_code != 200:
113
125
  self._resources = []
114
126
  return
115
- self._resources = [
116
- ResourceModel(**resource) for resource in response.json()
117
- ]
127
+
128
+ # Handle both old and new response formats
129
+ response_data = response.json()
130
+ if isinstance(response_data, dict) and "resources" in response_data:
131
+ # Old format: {"resources": [...]}
132
+ resources_list = response_data["resources"]
133
+ else:
134
+ # New format: [...]
135
+ resources_list = response_data
136
+
137
+ self._resources = [ResourceModel(**resource) for resource in resources_list]
118
138
  for resource in self._resources:
119
139
  if resource.type not in self._resources_state:
120
140
  self._resources_state[resource.type.value] = {}
@@ -255,4 +275,4 @@ class AsyncInstanceClient:
255
275
 
256
276
  async def __aexit__(self, exc_type, exc_val, exc_tb):
257
277
  """Async context manager exit."""
258
- await self.close()
278
+ await self.close()
@@ -126,3 +126,16 @@ class Resource(BaseModel):
126
126
  type: ResourceType
127
127
  mode: ResourceMode
128
128
  label: Optional[str] = Field(None, title="Label")
129
+
130
+
131
+ class ExecuteFunctionRequest(BaseModel):
132
+ function_code: str
133
+ function_name: str
134
+ text_solution: Optional[str] = None
135
+
136
+
137
+ class ExecuteFunctionResponse(BaseModel):
138
+ success: bool
139
+ result: Optional[Any] = None
140
+ error: Optional[str] = None
141
+ message: str
fleet/_async/models.py ADDED
@@ -0,0 +1,109 @@
1
+ # generated by datamodel-codegen:
2
+ # filename: openapi.json
3
+ # timestamp: 2025-07-08T18:21:47+00:00
4
+
5
+ from __future__ import annotations
6
+
7
+ from enum import Enum
8
+ from typing import Dict, List, Optional, Union
9
+
10
+ from pydantic import BaseModel, Field
11
+
12
+
13
+ class Environment(BaseModel):
14
+ env_key: str = Field(..., title="Env Key")
15
+ name: str = Field(..., title="Name")
16
+ description: Optional[str] = Field(..., title="Description")
17
+ default_version: Optional[str] = Field(..., title="Default Version")
18
+ versions: Dict[str, str] = Field(..., title="Versions")
19
+
20
+
21
+ class Instance(BaseModel):
22
+ instance_id: str = Field(..., title="Instance Id")
23
+ env_key: str = Field(..., title="Env Key")
24
+ version: str = Field(..., title="Version")
25
+ status: str = Field(..., title="Status")
26
+ subdomain: str = Field(..., title="Subdomain")
27
+ created_at: str = Field(..., title="Created At")
28
+ updated_at: str = Field(..., title="Updated At")
29
+ terminated_at: Optional[str] = Field(None, title="Terminated At")
30
+ team_id: str = Field(..., title="Team Id")
31
+ region: str = Field(..., title="Region")
32
+
33
+
34
+ class InstanceRequest(BaseModel):
35
+ env_key: str = Field(..., title="Env Key")
36
+ version: Optional[str] = Field(None, title="Version")
37
+ region: Optional[str] = Field("us-east-2", title="Region")
38
+ seed: Optional[int] = Field(None, title="Seed")
39
+ timestamp: Optional[int] = Field(None, title="Timestamp")
40
+ p_error: Optional[float] = Field(None, title="P Error")
41
+ avg_latency: Optional[float] = Field(None, title="Avg Latency")
42
+ run_id: Optional[str] = Field(None, title="Run Id")
43
+ task_id: Optional[str] = Field(None, title="Task Id")
44
+
45
+
46
+ class InstanceStatus(Enum):
47
+ pending = "pending"
48
+ running = "running"
49
+ stopped = "stopped"
50
+ error = "error"
51
+
52
+
53
+ class ManagerURLs(BaseModel):
54
+ api: str = Field(..., title="Api")
55
+ docs: str = Field(..., title="Docs")
56
+ reset: str = Field(..., title="Reset")
57
+ diff: str = Field(..., title="Diff")
58
+ snapshot: str = Field(..., title="Snapshot")
59
+ execute_verifier_function: str = Field(..., title="Execute Verifier Function")
60
+ execute_verifier_function_with_upload: str = Field(
61
+ ..., title="Execute Verifier Function With Upload"
62
+ )
63
+
64
+
65
+ class ValidationError(BaseModel):
66
+ loc: List[Union[str, int]] = Field(..., title="Location")
67
+ msg: str = Field(..., title="Message")
68
+ type: str = Field(..., title="Error Type")
69
+
70
+
71
+ class HTTPValidationError(BaseModel):
72
+ detail: Optional[List[ValidationError]] = Field(None, title="Detail")
73
+
74
+
75
+ class InstanceURLs(BaseModel):
76
+ root: str = Field(..., title="Root")
77
+ app: str = Field(..., title="App")
78
+ api: Optional[str] = Field(None, title="Api")
79
+ health: Optional[str] = Field(None, title="Health")
80
+ api_docs: Optional[str] = Field(None, title="Api Docs")
81
+ manager: ManagerURLs
82
+
83
+
84
+ class InstanceResponse(BaseModel):
85
+ instance_id: str = Field(..., title="Instance Id")
86
+ env_key: str = Field(..., title="Env Key")
87
+ version: str = Field(..., title="Version")
88
+ status: str = Field(..., title="Status")
89
+ subdomain: str = Field(..., title="Subdomain")
90
+ created_at: str = Field(..., title="Created At")
91
+ updated_at: str = Field(..., title="Updated At")
92
+ terminated_at: Optional[str] = Field(None, title="Terminated At")
93
+ team_id: str = Field(..., title="Team Id")
94
+ region: str = Field(..., title="Region")
95
+ urls: InstanceURLs
96
+ health: Optional[bool] = Field(None, title="Health")
97
+
98
+
99
+ class InstanceRecord(BaseModel):
100
+ instance_id: str
101
+ env_key: str
102
+ version: str
103
+ status: str
104
+ subdomain: str
105
+ created_at: str
106
+ updated_at: str
107
+ terminated_at: Optional[str] = None
108
+ team_id: str
109
+ region: str