together 1.5.17__py3-none-any.whl → 2.0.0a8__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 (205) hide show
  1. together/__init__.py +101 -63
  2. together/_base_client.py +1995 -0
  3. together/_client.py +1033 -0
  4. together/_compat.py +219 -0
  5. together/_constants.py +14 -0
  6. together/_exceptions.py +108 -0
  7. together/_files.py +123 -0
  8. together/_models.py +857 -0
  9. together/_qs.py +150 -0
  10. together/_resource.py +43 -0
  11. together/_response.py +830 -0
  12. together/_streaming.py +370 -0
  13. together/_types.py +260 -0
  14. together/_utils/__init__.py +64 -0
  15. together/_utils/_compat.py +45 -0
  16. together/_utils/_datetime_parse.py +136 -0
  17. together/_utils/_logs.py +25 -0
  18. together/_utils/_proxy.py +65 -0
  19. together/_utils/_reflection.py +42 -0
  20. together/_utils/_resources_proxy.py +24 -0
  21. together/_utils/_streams.py +12 -0
  22. together/_utils/_sync.py +58 -0
  23. together/_utils/_transform.py +457 -0
  24. together/_utils/_typing.py +156 -0
  25. together/_utils/_utils.py +421 -0
  26. together/_version.py +4 -0
  27. together/lib/.keep +4 -0
  28. together/lib/__init__.py +23 -0
  29. together/{cli → lib/cli}/api/endpoints.py +108 -75
  30. together/lib/cli/api/evals.py +588 -0
  31. together/{cli → lib/cli}/api/files.py +20 -17
  32. together/{cli/api/finetune.py → lib/cli/api/fine_tuning.py} +161 -120
  33. together/lib/cli/api/models.py +140 -0
  34. together/{cli → lib/cli}/api/utils.py +6 -7
  35. together/{cli → lib/cli}/cli.py +16 -24
  36. together/{constants.py → lib/constants.py} +17 -12
  37. together/lib/resources/__init__.py +11 -0
  38. together/lib/resources/files.py +999 -0
  39. together/lib/resources/fine_tuning.py +280 -0
  40. together/lib/resources/models.py +35 -0
  41. together/lib/types/__init__.py +13 -0
  42. together/lib/types/error.py +9 -0
  43. together/lib/types/fine_tuning.py +455 -0
  44. together/{utils → lib/utils}/__init__.py +6 -14
  45. together/{utils → lib/utils}/_log.py +11 -16
  46. together/lib/utils/files.py +628 -0
  47. together/lib/utils/serializer.py +10 -0
  48. together/{utils → lib/utils}/tools.py +19 -55
  49. together/resources/__init__.py +225 -33
  50. together/resources/audio/__init__.py +72 -21
  51. together/resources/audio/audio.py +198 -0
  52. together/resources/audio/speech.py +574 -122
  53. together/resources/audio/transcriptions.py +282 -0
  54. together/resources/audio/translations.py +256 -0
  55. together/resources/audio/voices.py +135 -0
  56. together/resources/batches.py +417 -0
  57. together/resources/chat/__init__.py +30 -21
  58. together/resources/chat/chat.py +102 -0
  59. together/resources/chat/completions.py +1063 -263
  60. together/resources/code_interpreter/__init__.py +33 -0
  61. together/resources/code_interpreter/code_interpreter.py +258 -0
  62. together/resources/code_interpreter/sessions.py +135 -0
  63. together/resources/completions.py +884 -225
  64. together/resources/embeddings.py +172 -68
  65. together/resources/endpoints.py +598 -395
  66. together/resources/evals.py +452 -0
  67. together/resources/files.py +398 -121
  68. together/resources/fine_tuning.py +1033 -0
  69. together/resources/hardware.py +181 -0
  70. together/resources/images.py +256 -108
  71. together/resources/jobs.py +214 -0
  72. together/resources/models.py +238 -90
  73. together/resources/rerank.py +190 -92
  74. together/resources/videos.py +374 -0
  75. together/types/__init__.py +65 -109
  76. together/types/audio/__init__.py +10 -0
  77. together/types/audio/speech_create_params.py +75 -0
  78. together/types/audio/transcription_create_params.py +54 -0
  79. together/types/audio/transcription_create_response.py +111 -0
  80. together/types/audio/translation_create_params.py +40 -0
  81. together/types/audio/translation_create_response.py +70 -0
  82. together/types/audio/voice_list_response.py +23 -0
  83. together/types/audio_speech_stream_chunk.py +16 -0
  84. together/types/autoscaling.py +13 -0
  85. together/types/autoscaling_param.py +15 -0
  86. together/types/batch_create_params.py +24 -0
  87. together/types/batch_create_response.py +14 -0
  88. together/types/batch_job.py +45 -0
  89. together/types/batch_list_response.py +10 -0
  90. together/types/chat/__init__.py +18 -0
  91. together/types/chat/chat_completion.py +60 -0
  92. together/types/chat/chat_completion_chunk.py +61 -0
  93. together/types/chat/chat_completion_structured_message_image_url_param.py +18 -0
  94. together/types/chat/chat_completion_structured_message_text_param.py +13 -0
  95. together/types/chat/chat_completion_structured_message_video_url_param.py +18 -0
  96. together/types/chat/chat_completion_usage.py +13 -0
  97. together/types/chat/chat_completion_warning.py +9 -0
  98. together/types/chat/completion_create_params.py +329 -0
  99. together/types/code_interpreter/__init__.py +5 -0
  100. together/types/code_interpreter/session_list_response.py +31 -0
  101. together/types/code_interpreter_execute_params.py +45 -0
  102. together/types/completion.py +42 -0
  103. together/types/completion_chunk.py +66 -0
  104. together/types/completion_create_params.py +138 -0
  105. together/types/dedicated_endpoint.py +44 -0
  106. together/types/embedding.py +24 -0
  107. together/types/embedding_create_params.py +31 -0
  108. together/types/endpoint_create_params.py +43 -0
  109. together/types/endpoint_list_avzones_response.py +11 -0
  110. together/types/endpoint_list_params.py +18 -0
  111. together/types/endpoint_list_response.py +41 -0
  112. together/types/endpoint_update_params.py +27 -0
  113. together/types/eval_create_params.py +263 -0
  114. together/types/eval_create_response.py +16 -0
  115. together/types/eval_list_params.py +21 -0
  116. together/types/eval_list_response.py +10 -0
  117. together/types/eval_status_response.py +100 -0
  118. together/types/evaluation_job.py +139 -0
  119. together/types/execute_response.py +108 -0
  120. together/types/file_delete_response.py +13 -0
  121. together/types/file_list.py +12 -0
  122. together/types/file_purpose.py +9 -0
  123. together/types/file_response.py +31 -0
  124. together/types/file_type.py +7 -0
  125. together/types/fine_tuning_cancel_response.py +194 -0
  126. together/types/fine_tuning_content_params.py +24 -0
  127. together/types/fine_tuning_delete_params.py +11 -0
  128. together/types/fine_tuning_delete_response.py +12 -0
  129. together/types/fine_tuning_list_checkpoints_response.py +21 -0
  130. together/types/fine_tuning_list_events_response.py +12 -0
  131. together/types/fine_tuning_list_response.py +199 -0
  132. together/types/finetune_event.py +41 -0
  133. together/types/finetune_event_type.py +33 -0
  134. together/types/finetune_response.py +177 -0
  135. together/types/hardware_list_params.py +16 -0
  136. together/types/hardware_list_response.py +58 -0
  137. together/types/image_data_b64.py +15 -0
  138. together/types/image_data_url.py +15 -0
  139. together/types/image_file.py +23 -0
  140. together/types/image_generate_params.py +85 -0
  141. together/types/job_list_response.py +47 -0
  142. together/types/job_retrieve_response.py +43 -0
  143. together/types/log_probs.py +18 -0
  144. together/types/model_list_response.py +10 -0
  145. together/types/model_object.py +42 -0
  146. together/types/model_upload_params.py +36 -0
  147. together/types/model_upload_response.py +23 -0
  148. together/types/rerank_create_params.py +36 -0
  149. together/types/rerank_create_response.py +36 -0
  150. together/types/tool_choice.py +23 -0
  151. together/types/tool_choice_param.py +23 -0
  152. together/types/tools_param.py +23 -0
  153. together/types/training_method_dpo.py +22 -0
  154. together/types/training_method_sft.py +18 -0
  155. together/types/video_create_params.py +86 -0
  156. together/types/video_job.py +57 -0
  157. together-2.0.0a8.dist-info/METADATA +680 -0
  158. together-2.0.0a8.dist-info/RECORD +164 -0
  159. {together-1.5.17.dist-info → together-2.0.0a8.dist-info}/WHEEL +1 -1
  160. together-2.0.0a8.dist-info/entry_points.txt +2 -0
  161. {together-1.5.17.dist-info → together-2.0.0a8.dist-info/licenses}/LICENSE +1 -1
  162. together/abstract/api_requestor.py +0 -729
  163. together/cli/api/chat.py +0 -276
  164. together/cli/api/completions.py +0 -119
  165. together/cli/api/images.py +0 -93
  166. together/cli/api/models.py +0 -55
  167. together/client.py +0 -176
  168. together/error.py +0 -194
  169. together/filemanager.py +0 -389
  170. together/legacy/__init__.py +0 -0
  171. together/legacy/base.py +0 -27
  172. together/legacy/complete.py +0 -93
  173. together/legacy/embeddings.py +0 -27
  174. together/legacy/files.py +0 -146
  175. together/legacy/finetune.py +0 -177
  176. together/legacy/images.py +0 -27
  177. together/legacy/models.py +0 -44
  178. together/resources/batch.py +0 -136
  179. together/resources/code_interpreter.py +0 -82
  180. together/resources/finetune.py +0 -1064
  181. together/together_response.py +0 -50
  182. together/types/abstract.py +0 -26
  183. together/types/audio_speech.py +0 -110
  184. together/types/batch.py +0 -53
  185. together/types/chat_completions.py +0 -197
  186. together/types/code_interpreter.py +0 -57
  187. together/types/common.py +0 -66
  188. together/types/completions.py +0 -107
  189. together/types/embeddings.py +0 -35
  190. together/types/endpoints.py +0 -123
  191. together/types/error.py +0 -16
  192. together/types/files.py +0 -90
  193. together/types/finetune.py +0 -398
  194. together/types/images.py +0 -44
  195. together/types/models.py +0 -45
  196. together/types/rerank.py +0 -43
  197. together/utils/api_helpers.py +0 -124
  198. together/utils/files.py +0 -425
  199. together/version.py +0 -6
  200. together-1.5.17.dist-info/METADATA +0 -525
  201. together-1.5.17.dist-info/RECORD +0 -69
  202. together-1.5.17.dist-info/entry_points.txt +0 -3
  203. /together/{abstract → lib/cli}/__init__.py +0 -0
  204. /together/{cli → lib/cli/api}/__init__.py +0 -0
  205. /together/{cli/api/__init__.py → py.typed} +0 -0
@@ -1,34 +1,30 @@
1
1
  from __future__ import annotations
2
2
 
3
- import json
4
3
  import sys
4
+ import json
5
+ from typing import Any, Dict, Literal, TypeVar, Callable, cast
5
6
  from functools import wraps
6
- from typing import Any, Callable, Dict, List, Literal, TypeVar, Union
7
7
 
8
8
  import click
9
9
 
10
- from together import Together
11
- from together.error import InvalidRequestError
12
- from together.types import DedicatedEndpoint, ListEndpoint
10
+ from together import Together, omit
11
+ from together.types import DedicatedEndpoint
12
+ from together._exceptions import APIError
13
+ from together.lib.utils.serializer import datetime_serializer
14
+ from together.types.endpoint_list_response import Data as DedicatedEndpointListItem
13
15
 
14
16
 
15
- def print_endpoint(
16
- endpoint: Union[DedicatedEndpoint, ListEndpoint],
17
- ) -> None:
17
+ def print_endpoint(endpoint: DedicatedEndpoint | DedicatedEndpointListItem) -> None:
18
18
  """Print endpoint details in a Docker-like format or JSON."""
19
19
 
20
20
  # Print header info
21
21
  click.echo(f"ID:\t\t{endpoint.id}")
22
22
  click.echo(f"Name:\t\t{endpoint.name}")
23
23
 
24
- # Print type-specific fields
25
24
  if isinstance(endpoint, DedicatedEndpoint):
26
25
  click.echo(f"Display Name:\t{endpoint.display_name}")
27
26
  click.echo(f"Hardware:\t{endpoint.hardware}")
28
- click.echo(
29
- f"Autoscaling:\tMin={endpoint.autoscaling.min_replicas}, "
30
- f"Max={endpoint.autoscaling.max_replicas}"
31
- )
27
+ click.echo(f"Autoscaling:\tMin={endpoint.autoscaling.min_replicas}, Max={endpoint.autoscaling.max_replicas}")
32
28
 
33
29
  click.echo(f"Model:\t\t{endpoint.model}")
34
30
  click.echo(f"Type:\t\t{endpoint.type}")
@@ -40,15 +36,10 @@ def print_endpoint(
40
36
  F = TypeVar("F", bound=Callable[..., Any])
41
37
 
42
38
 
43
- def print_api_error(
44
- e: InvalidRequestError,
45
- ) -> None:
46
- error_details = e.api_response.message
39
+ def print_api_error(e: APIError) -> None:
40
+ error_details = cast(Dict[str, Any], e.body)["error"]["message"]
47
41
 
48
- if error_details and (
49
- "credentials" in error_details.lower()
50
- or "authentication" in error_details.lower()
51
- ):
42
+ if error_details and ("credentials" in error_details.lower() or "authentication" in error_details.lower()):
52
43
  click.echo("Error: Invalid API key or authentication failed", err=True)
53
44
  else:
54
45
  click.echo(f"Error: {error_details}", err=True)
@@ -61,7 +52,7 @@ def handle_api_errors(f: F) -> F:
61
52
  def wrapper(*args: Any, **kwargs: Any) -> Any:
62
53
  try:
63
54
  return f(*args, **kwargs)
64
- except InvalidRequestError as e:
55
+ except APIError as e:
65
56
  print_api_error(e)
66
57
  sys.exit(1)
67
58
  except Exception as e:
@@ -133,8 +124,11 @@ def endpoints(ctx: click.Context) -> None:
133
124
  help="Number of minutes of inactivity after which the endpoint will be automatically stopped. Set to 0 to disable.",
134
125
  )
135
126
  @click.option(
136
- "--wait",
137
- is_flag=True,
127
+ "--availability-zone",
128
+ help="Start endpoint in specified availability zone (e.g., us-central-4b)",
129
+ )
130
+ @click.option(
131
+ "--wait/--no-wait",
138
132
  default=True,
139
133
  help="Wait for the endpoint to be ready after creation",
140
134
  )
@@ -148,10 +142,11 @@ def create(
148
142
  gpu: str,
149
143
  gpu_count: int,
150
144
  display_name: str | None,
151
- no_prompt_cache: bool,
152
- no_speculative_decoding: bool,
145
+ no_prompt_cache: bool | None,
146
+ no_speculative_decoding: bool | None,
153
147
  no_auto_start: bool,
154
148
  inactive_timeout: int | None,
149
+ availability_zone: str | None,
155
150
  wait: bool,
156
151
  ) -> None:
157
152
  """Create a new dedicated inference endpoint."""
@@ -170,20 +165,21 @@ def create(
170
165
  response = client.endpoints.create(
171
166
  model=model,
172
167
  hardware=hardware_id,
173
- min_replicas=min_replicas,
174
- max_replicas=max_replicas,
175
- display_name=display_name,
176
- disable_prompt_cache=no_prompt_cache,
177
- disable_speculative_decoding=no_speculative_decoding,
168
+ autoscaling={
169
+ "min_replicas": min_replicas,
170
+ "max_replicas": max_replicas,
171
+ },
172
+ display_name=display_name or omit,
173
+ disable_prompt_cache=no_prompt_cache or omit,
174
+ disable_speculative_decoding=no_speculative_decoding or omit,
178
175
  state="STOPPED" if no_auto_start else "STARTED",
179
176
  inactive_timeout=inactive_timeout,
177
+ extra_query={"availability_zone": availability_zone or omit},
180
178
  )
181
- except InvalidRequestError as e:
179
+ except APIError as e:
182
180
  print_api_error(e)
183
- if "check the hardware api" in str(e).lower():
184
- fetch_and_print_hardware_options(
185
- client=client, model=model, print_json=False, available=True
186
- )
181
+ if "check the hardware api" in str(e.args[0]).lower() or "invalid hardware provided" in str(e.args[0]).lower():
182
+ fetch_and_print_hardware_options(client=client, model=model, print_json=False, available=True)
187
183
 
188
184
  sys.exit(1)
189
185
 
@@ -203,6 +199,8 @@ def create(
203
199
  click.echo(" Auto-start: disabled", err=True)
204
200
  if inactive_timeout is not None:
205
201
  click.echo(f" Inactive timeout: {inactive_timeout} minutes", err=True)
202
+ if availability_zone:
203
+ click.echo(f" Availability zone: {availability_zone}", err=True)
206
204
 
207
205
  click.echo(f"Endpoint created successfully, id: {response.id}", err=True)
208
206
 
@@ -210,7 +208,7 @@ def create(
210
208
  import time
211
209
 
212
210
  click.echo("Waiting for endpoint to be ready...", err=True)
213
- while client.endpoints.get(response.id).state != "STARTED":
211
+ while client.endpoints.retrieve(response.id).state != "STARTED":
214
212
  time.sleep(1)
215
213
  click.echo("Endpoint ready", err=True)
216
214
 
@@ -225,11 +223,11 @@ def create(
225
223
  @handle_api_errors
226
224
  def get(client: Together, endpoint_id: str, json: bool) -> None:
227
225
  """Get a dedicated inference endpoint."""
228
- endpoint = client.endpoints.get(endpoint_id)
226
+ endpoint = client.endpoints.retrieve(endpoint_id)
229
227
  if json:
230
228
  import json as json_lib
231
229
 
232
- click.echo(json_lib.dumps(endpoint.model_dump(), indent=2))
230
+ click.echo(json_lib.dumps(endpoint.model_dump(), indent=2, default=datetime_serializer))
233
231
  else:
234
232
  print_endpoint(endpoint)
235
233
 
@@ -249,35 +247,31 @@ def hardware(client: Together, model: str | None, json: bool, available: bool) -
249
247
  fetch_and_print_hardware_options(client, model, json, available)
250
248
 
251
249
 
252
- def fetch_and_print_hardware_options(
253
- client: Together, model: str | None, print_json: bool, available: bool
254
- ) -> None:
250
+ def fetch_and_print_hardware_options(client: Together, model: str | None, print_json: bool, available: bool) -> None:
255
251
  """Print hardware options for a model."""
256
252
 
257
253
  message = "Available hardware options:" if available else "All hardware options:"
258
254
  click.echo(message, err=True)
259
- hardware_options = client.endpoints.list_hardware(model)
255
+ hardware_options = client.hardware.list(model=model or omit)
256
+ # hardware_options = client.endpoints.list_hardware(model)
260
257
  if available:
261
- hardware_options = [
258
+ hardware_options.data = [
262
259
  hardware
263
- for hardware in hardware_options
264
- if hardware.availability is not None
265
- and hardware.availability.status == "available"
260
+ for hardware in hardware_options.data
261
+ if hardware.availability is not None and hardware.availability.status == "available"
266
262
  ]
267
263
 
268
264
  if print_json:
269
- json_output = [hardware.model_dump() for hardware in hardware_options]
270
- click.echo(json.dumps(json_output, indent=2))
265
+ json_output = [hardware.model_dump() for hardware in hardware_options.data]
266
+ click.echo(json.dumps(json_output, default=datetime_serializer, indent=2))
271
267
  else:
272
- for hardware in hardware_options:
268
+ for hardware in hardware_options.data:
273
269
  click.echo(f" {hardware.id}", err=True)
274
270
 
275
271
 
276
272
  @endpoints.command()
277
273
  @click.argument("endpoint-id", required=True)
278
- @click.option(
279
- "--wait", is_flag=True, default=True, help="Wait for the endpoint to stop"
280
- )
274
+ @click.option("--wait/--no-wait", default=True, help="Wait for the endpoint to stop")
281
275
  @click.pass_obj
282
276
  @handle_api_errors
283
277
  def stop(client: Together, endpoint_id: str, wait: bool) -> None:
@@ -289,7 +283,7 @@ def stop(client: Together, endpoint_id: str, wait: bool) -> None:
289
283
  import time
290
284
 
291
285
  click.echo("Waiting for endpoint to stop...", err=True)
292
- while client.endpoints.get(endpoint_id).state != "STOPPED":
286
+ while client.endpoints.retrieve(endpoint_id).state != "STOPPED":
293
287
  time.sleep(1)
294
288
  click.echo("Endpoint stopped", err=True)
295
289
 
@@ -298,9 +292,7 @@ def stop(client: Together, endpoint_id: str, wait: bool) -> None:
298
292
 
299
293
  @endpoints.command()
300
294
  @click.argument("endpoint-id", required=True)
301
- @click.option(
302
- "--wait", is_flag=True, default=True, help="Wait for the endpoint to start"
303
- )
295
+ @click.option("--wait/--no-wait", default=True, help="Wait for the endpoint to start")
304
296
  @click.pass_obj
305
297
  @handle_api_errors
306
298
  def start(client: Together, endpoint_id: str, wait: bool) -> None:
@@ -312,7 +304,7 @@ def start(client: Together, endpoint_id: str, wait: bool) -> None:
312
304
  import time
313
305
 
314
306
  click.echo("Waiting for endpoint to start...", err=True)
315
- while client.endpoints.get(endpoint_id).state != "STARTED":
307
+ while client.endpoints.retrieve(endpoint_id).state != "STARTED":
316
308
  time.sleep(1)
317
309
  click.echo("Endpoint started", err=True)
318
310
 
@@ -337,13 +329,32 @@ def delete(client: Together, endpoint_id: str) -> None:
337
329
  type=click.Choice(["dedicated", "serverless"]),
338
330
  help="Filter by endpoint type",
339
331
  )
332
+ @click.option(
333
+ "--mine",
334
+ type=click.BOOL,
335
+ default=None,
336
+ help="true (only mine), default=all",
337
+ )
338
+ @click.option(
339
+ "--usage-type",
340
+ type=click.Choice(["on-demand", "reserved"]),
341
+ help="Filter by endpoint usage type",
342
+ )
340
343
  @click.pass_obj
341
344
  @handle_api_errors
342
345
  def list(
343
- client: Together, json: bool, type: Literal["dedicated", "serverless"] | None
346
+ client: Together,
347
+ json: bool,
348
+ type: Literal["dedicated", "serverless"] | None,
349
+ usage_type: Literal["on-demand", "reserved"] | None,
350
+ mine: bool | None,
344
351
  ) -> None:
345
352
  """List all inference endpoints (includes both dedicated and serverless endpoints)."""
346
- endpoints: List[ListEndpoint] = client.endpoints.list(type=type)
353
+ endpoints = client.endpoints.list(
354
+ type=type or omit,
355
+ usage_type=usage_type or omit,
356
+ mine=mine if mine is not None else omit,
357
+ )
347
358
 
348
359
  if not endpoints:
349
360
  click.echo("No dedicated endpoints found", err=True)
@@ -354,10 +365,12 @@ def list(
354
365
  import json as json_lib
355
366
 
356
367
  click.echo(
357
- json_lib.dumps([endpoint.model_dump() for endpoint in endpoints], indent=2)
368
+ json_lib.dumps(
369
+ [endpoint.model_dump() for endpoint in endpoints.data], default=datetime_serializer, indent=2
370
+ )
358
371
  )
359
372
  else:
360
- for endpoint in endpoints:
373
+ for endpoint in endpoints.data:
361
374
  print_endpoint(
362
375
  endpoint,
363
376
  )
@@ -400,35 +413,55 @@ def update(
400
413
  click.echo("Error: At least one update option must be specified", err=True)
401
414
  sys.exit(1)
402
415
 
403
- # If only one of min/max replicas is specified, we need both for the update
404
- if (min_replicas is None) != (max_replicas is None):
405
- click.echo(
406
- "Error: Both --min-replicas and --max-replicas must be specified together",
407
- err=True,
408
- )
409
- sys.exit(1)
410
-
411
416
  # Build kwargs for the update
412
417
  kwargs: Dict[str, Any] = {}
413
418
  if display_name is not None:
414
419
  kwargs["display_name"] = display_name
415
- if min_replicas is not None and max_replicas is not None:
416
- kwargs["min_replicas"] = min_replicas
417
- kwargs["max_replicas"] = max_replicas
420
+
421
+ if min_replicas is not None or max_replicas is not None:
422
+ kwargs["autoscaling"] = {}
423
+ if min_replicas is not None:
424
+ kwargs["autoscaling"]["min_replicas"] = min_replicas
425
+ if max_replicas is not None:
426
+ kwargs["autoscaling"]["max_replicas"] = max_replicas
427
+
418
428
  if inactive_timeout is not None:
419
429
  kwargs["inactive_timeout"] = inactive_timeout
420
430
 
421
- _response = client.endpoints.update(endpoint_id, **kwargs)
431
+ client.endpoints.update(endpoint_id, **kwargs)
422
432
 
423
433
  # Print what was updated
424
434
  click.echo("Updated endpoint configuration:", err=True)
425
435
  if display_name:
426
436
  click.echo(f" Display name: {display_name}", err=True)
427
- if min_replicas is not None and max_replicas is not None:
437
+ if min_replicas:
428
438
  click.echo(f" Min replicas: {min_replicas}", err=True)
439
+ if max_replicas:
429
440
  click.echo(f" Max replicas: {max_replicas}", err=True)
430
441
  if inactive_timeout is not None:
431
442
  click.echo(f" Inactive timeout: {inactive_timeout} minutes", err=True)
432
443
 
433
444
  click.echo("Successfully updated endpoint", err=True)
434
445
  click.echo(endpoint_id)
446
+
447
+
448
+ @endpoints.command()
449
+ @click.option("--json", is_flag=True, help="Print output in JSON format")
450
+ @click.pass_obj
451
+ @handle_api_errors
452
+ def availability_zones(client: Together, json: bool) -> None:
453
+ """List all availability zones."""
454
+ avzones = client.endpoints.list_avzones()
455
+
456
+ if not avzones:
457
+ click.echo("No availability zones found", err=True)
458
+ return
459
+
460
+ if json:
461
+ import json as json_lib
462
+
463
+ click.echo(json_lib.dumps(avzones.model_dump(), indent=2))
464
+ else:
465
+ click.echo("Available zones:", err=True)
466
+ for availability_zone in sorted(avzones.avzones):
467
+ click.echo(f" {availability_zone}")