together 2.0.0a16__py3-none-any.whl → 2.0.0a18__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.
- together/_base_client.py +5 -2
- together/_client.py +1 -39
- together/_compat.py +3 -3
- together/_utils/_json.py +35 -0
- together/_version.py +1 -1
- together/lib/cli/api/endpoints/create.py +14 -8
- together/lib/cli/api/endpoints/hardware.py +37 -6
- together/lib/cli/api/models/list.py +18 -14
- together/lib/cli/api/models/upload.py +5 -1
- together/resources/__init__.py +0 -14
- together/resources/beta/__init__.py +14 -0
- together/resources/beta/beta.py +32 -0
- together/resources/beta/clusters/clusters.py +12 -12
- together/resources/beta/clusters/storage.py +10 -10
- together/resources/beta/jig/__init__.py +61 -0
- together/resources/beta/jig/jig.py +1024 -0
- together/resources/beta/jig/queue.py +482 -0
- together/resources/beta/jig/secrets.py +548 -0
- together/resources/beta/jig/volumes.py +514 -0
- together/resources/chat/completions.py +10 -0
- together/resources/endpoints.py +2 -2
- together/resources/models/__init__.py +33 -0
- together/resources/{models.py → models/models.py} +41 -9
- together/resources/models/uploads.py +163 -0
- together/types/__init__.py +0 -2
- together/types/beta/__init__.py +6 -0
- together/types/beta/deployment.py +261 -0
- together/types/beta/deployment_logs.py +11 -0
- together/types/beta/jig/__init__.py +20 -0
- together/types/beta/jig/queue_cancel_params.py +13 -0
- together/types/beta/jig/queue_cancel_response.py +11 -0
- together/types/beta/jig/queue_metrics_params.py +12 -0
- together/types/beta/jig/queue_metrics_response.py +8 -0
- together/types/beta/jig/queue_retrieve_params.py +15 -0
- together/types/beta/jig/queue_retrieve_response.py +35 -0
- together/types/beta/jig/queue_submit_params.py +19 -0
- together/types/beta/jig/queue_submit_response.py +25 -0
- together/types/beta/jig/secret.py +33 -0
- together/types/beta/jig/secret_create_params.py +34 -0
- together/types/beta/jig/secret_list_response.py +16 -0
- together/types/beta/jig/secret_update_params.py +34 -0
- together/types/beta/jig/volume.py +47 -0
- together/types/beta/jig/volume_create_params.py +34 -0
- together/types/beta/jig/volume_list_response.py +16 -0
- together/types/beta/jig/volume_update_params.py +34 -0
- together/types/beta/jig_deploy_params.py +150 -0
- together/types/beta/jig_list_response.py +16 -0
- together/types/beta/jig_retrieve_logs_params.py +15 -0
- together/types/beta/jig_update_params.py +141 -0
- together/types/chat/completion_create_params.py +11 -0
- together/types/endpoint_create_params.py +1 -1
- together/types/models/__init__.py +5 -0
- together/types/{job_retrieve_response.py → models/upload_status_response.py} +3 -3
- {together-2.0.0a16.dist-info → together-2.0.0a18.dist-info}/METADATA +11 -14
- {together-2.0.0a16.dist-info → together-2.0.0a18.dist-info}/RECORD +58 -28
- together/resources/jobs.py +0 -214
- together/types/job_list_response.py +0 -47
- {together-2.0.0a16.dist-info → together-2.0.0a18.dist-info}/WHEEL +0 -0
- {together-2.0.0a16.dist-info → together-2.0.0a18.dist-info}/entry_points.txt +0 -0
- {together-2.0.0a16.dist-info → together-2.0.0a18.dist-info}/licenses/LICENSE +0 -0
together/_base_client.py
CHANGED
|
@@ -86,6 +86,7 @@ from ._exceptions import (
|
|
|
86
86
|
APIConnectionError,
|
|
87
87
|
APIResponseValidationError,
|
|
88
88
|
)
|
|
89
|
+
from ._utils._json import openapi_dumps
|
|
89
90
|
|
|
90
91
|
log: logging.Logger = logging.getLogger(__name__)
|
|
91
92
|
|
|
@@ -554,8 +555,10 @@ class BaseClient(Generic[_HttpxClientT, _DefaultStreamT]):
|
|
|
554
555
|
kwargs["content"] = options.content
|
|
555
556
|
elif isinstance(json_data, bytes):
|
|
556
557
|
kwargs["content"] = json_data
|
|
557
|
-
|
|
558
|
-
|
|
558
|
+
elif not files:
|
|
559
|
+
# Don't set content when JSON is sent as multipart/form-data,
|
|
560
|
+
# since httpx's content param overrides other body arguments
|
|
561
|
+
kwargs["content"] = openapi_dumps(json_data) if is_given(json_data) and json_data is not None else None
|
|
559
562
|
kwargs["files"] = files
|
|
560
563
|
else:
|
|
561
564
|
headers.pop("Content-Type", None)
|
together/_client.py
CHANGED
|
@@ -37,7 +37,6 @@ if TYPE_CHECKING:
|
|
|
37
37
|
from .resources import (
|
|
38
38
|
beta,
|
|
39
39
|
chat,
|
|
40
|
-
jobs,
|
|
41
40
|
audio,
|
|
42
41
|
evals,
|
|
43
42
|
files,
|
|
@@ -53,11 +52,9 @@ if TYPE_CHECKING:
|
|
|
53
52
|
fine_tuning,
|
|
54
53
|
code_interpreter,
|
|
55
54
|
)
|
|
56
|
-
from .resources.jobs import JobsResource, AsyncJobsResource
|
|
57
55
|
from .resources.evals import EvalsResource, AsyncEvalsResource
|
|
58
56
|
from .resources.files import FilesResource, AsyncFilesResource
|
|
59
57
|
from .resources.images import ImagesResource, AsyncImagesResource
|
|
60
|
-
from .resources.models import ModelsResource, AsyncModelsResource
|
|
61
58
|
from .resources.rerank import RerankResource, AsyncRerankResource
|
|
62
59
|
from .resources.videos import VideosResource, AsyncVideosResource
|
|
63
60
|
from .resources.batches import BatchesResource, AsyncBatchesResource
|
|
@@ -69,6 +66,7 @@ if TYPE_CHECKING:
|
|
|
69
66
|
from .resources.audio.audio import AudioResource, AsyncAudioResource
|
|
70
67
|
from .resources.completions import CompletionsResource, AsyncCompletionsResource
|
|
71
68
|
from .resources.fine_tuning import FineTuningResource, AsyncFineTuningResource
|
|
69
|
+
from .resources.models.models import ModelsResource, AsyncModelsResource
|
|
72
70
|
from .resources.code_interpreter.code_interpreter import CodeInterpreterResource, AsyncCodeInterpreterResource
|
|
73
71
|
|
|
74
72
|
__all__ = [
|
|
@@ -209,12 +207,6 @@ class Together(SyncAPIClient):
|
|
|
209
207
|
|
|
210
208
|
return ModelsResource(self)
|
|
211
209
|
|
|
212
|
-
@cached_property
|
|
213
|
-
def jobs(self) -> JobsResource:
|
|
214
|
-
from .resources.jobs import JobsResource
|
|
215
|
-
|
|
216
|
-
return JobsResource(self)
|
|
217
|
-
|
|
218
210
|
@cached_property
|
|
219
211
|
def endpoints(self) -> EndpointsResource:
|
|
220
212
|
from .resources.endpoints import EndpointsResource
|
|
@@ -486,12 +478,6 @@ class AsyncTogether(AsyncAPIClient):
|
|
|
486
478
|
|
|
487
479
|
return AsyncModelsResource(self)
|
|
488
480
|
|
|
489
|
-
@cached_property
|
|
490
|
-
def jobs(self) -> AsyncJobsResource:
|
|
491
|
-
from .resources.jobs import AsyncJobsResource
|
|
492
|
-
|
|
493
|
-
return AsyncJobsResource(self)
|
|
494
|
-
|
|
495
481
|
@cached_property
|
|
496
482
|
def endpoints(self) -> AsyncEndpointsResource:
|
|
497
483
|
from .resources.endpoints import AsyncEndpointsResource
|
|
@@ -709,12 +695,6 @@ class TogetherWithRawResponse:
|
|
|
709
695
|
|
|
710
696
|
return ModelsResourceWithRawResponse(self._client.models)
|
|
711
697
|
|
|
712
|
-
@cached_property
|
|
713
|
-
def jobs(self) -> jobs.JobsResourceWithRawResponse:
|
|
714
|
-
from .resources.jobs import JobsResourceWithRawResponse
|
|
715
|
-
|
|
716
|
-
return JobsResourceWithRawResponse(self._client.jobs)
|
|
717
|
-
|
|
718
698
|
@cached_property
|
|
719
699
|
def endpoints(self) -> endpoints.EndpointsResourceWithRawResponse:
|
|
720
700
|
from .resources.endpoints import EndpointsResourceWithRawResponse
|
|
@@ -818,12 +798,6 @@ class AsyncTogetherWithRawResponse:
|
|
|
818
798
|
|
|
819
799
|
return AsyncModelsResourceWithRawResponse(self._client.models)
|
|
820
800
|
|
|
821
|
-
@cached_property
|
|
822
|
-
def jobs(self) -> jobs.AsyncJobsResourceWithRawResponse:
|
|
823
|
-
from .resources.jobs import AsyncJobsResourceWithRawResponse
|
|
824
|
-
|
|
825
|
-
return AsyncJobsResourceWithRawResponse(self._client.jobs)
|
|
826
|
-
|
|
827
801
|
@cached_property
|
|
828
802
|
def endpoints(self) -> endpoints.AsyncEndpointsResourceWithRawResponse:
|
|
829
803
|
from .resources.endpoints import AsyncEndpointsResourceWithRawResponse
|
|
@@ -927,12 +901,6 @@ class TogetherWithStreamedResponse:
|
|
|
927
901
|
|
|
928
902
|
return ModelsResourceWithStreamingResponse(self._client.models)
|
|
929
903
|
|
|
930
|
-
@cached_property
|
|
931
|
-
def jobs(self) -> jobs.JobsResourceWithStreamingResponse:
|
|
932
|
-
from .resources.jobs import JobsResourceWithStreamingResponse
|
|
933
|
-
|
|
934
|
-
return JobsResourceWithStreamingResponse(self._client.jobs)
|
|
935
|
-
|
|
936
904
|
@cached_property
|
|
937
905
|
def endpoints(self) -> endpoints.EndpointsResourceWithStreamingResponse:
|
|
938
906
|
from .resources.endpoints import EndpointsResourceWithStreamingResponse
|
|
@@ -1036,12 +1004,6 @@ class AsyncTogetherWithStreamedResponse:
|
|
|
1036
1004
|
|
|
1037
1005
|
return AsyncModelsResourceWithStreamingResponse(self._client.models)
|
|
1038
1006
|
|
|
1039
|
-
@cached_property
|
|
1040
|
-
def jobs(self) -> jobs.AsyncJobsResourceWithStreamingResponse:
|
|
1041
|
-
from .resources.jobs import AsyncJobsResourceWithStreamingResponse
|
|
1042
|
-
|
|
1043
|
-
return AsyncJobsResourceWithStreamingResponse(self._client.jobs)
|
|
1044
|
-
|
|
1045
1007
|
@cached_property
|
|
1046
1008
|
def endpoints(self) -> endpoints.AsyncEndpointsResourceWithStreamingResponse:
|
|
1047
1009
|
from .resources.endpoints import AsyncEndpointsResourceWithStreamingResponse
|
together/_compat.py
CHANGED
|
@@ -139,6 +139,7 @@ def model_dump(
|
|
|
139
139
|
exclude_defaults: bool = False,
|
|
140
140
|
warnings: bool = True,
|
|
141
141
|
mode: Literal["json", "python"] = "python",
|
|
142
|
+
by_alias: bool | None = None,
|
|
142
143
|
) -> dict[str, Any]:
|
|
143
144
|
if (not PYDANTIC_V1) or hasattr(model, "model_dump"):
|
|
144
145
|
return model.model_dump(
|
|
@@ -148,13 +149,12 @@ def model_dump(
|
|
|
148
149
|
exclude_defaults=exclude_defaults,
|
|
149
150
|
# warnings are not supported in Pydantic v1
|
|
150
151
|
warnings=True if PYDANTIC_V1 else warnings,
|
|
152
|
+
by_alias=by_alias,
|
|
151
153
|
)
|
|
152
154
|
return cast(
|
|
153
155
|
"dict[str, Any]",
|
|
154
156
|
model.dict( # pyright: ignore[reportDeprecated, reportUnnecessaryCast]
|
|
155
|
-
exclude=exclude,
|
|
156
|
-
exclude_unset=exclude_unset,
|
|
157
|
-
exclude_defaults=exclude_defaults,
|
|
157
|
+
exclude=exclude, exclude_unset=exclude_unset, exclude_defaults=exclude_defaults, by_alias=bool(by_alias)
|
|
158
158
|
),
|
|
159
159
|
)
|
|
160
160
|
|
together/_utils/_json.py
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from typing import Any
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
from typing_extensions import override
|
|
5
|
+
|
|
6
|
+
import pydantic
|
|
7
|
+
|
|
8
|
+
from .._compat import model_dump
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def openapi_dumps(obj: Any) -> bytes:
|
|
12
|
+
"""
|
|
13
|
+
Serialize an object to UTF-8 encoded JSON bytes.
|
|
14
|
+
|
|
15
|
+
Extends the standard json.dumps with support for additional types
|
|
16
|
+
commonly used in the SDK, such as `datetime`, `pydantic.BaseModel`, etc.
|
|
17
|
+
"""
|
|
18
|
+
return json.dumps(
|
|
19
|
+
obj,
|
|
20
|
+
cls=_CustomEncoder,
|
|
21
|
+
# Uses the same defaults as httpx's JSON serialization
|
|
22
|
+
ensure_ascii=False,
|
|
23
|
+
separators=(",", ":"),
|
|
24
|
+
allow_nan=False,
|
|
25
|
+
).encode()
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class _CustomEncoder(json.JSONEncoder):
|
|
29
|
+
@override
|
|
30
|
+
def default(self, o: Any) -> Any:
|
|
31
|
+
if isinstance(o, datetime):
|
|
32
|
+
return o.isoformat()
|
|
33
|
+
if isinstance(o, pydantic.BaseModel):
|
|
34
|
+
return model_dump(o, exclude_unset=True, mode="json", by_alias=True)
|
|
35
|
+
return super().default(o)
|
together/_version.py
CHANGED
|
@@ -3,7 +3,6 @@ from __future__ import annotations
|
|
|
3
3
|
import sys
|
|
4
4
|
|
|
5
5
|
import click
|
|
6
|
-
from rich import print
|
|
7
6
|
|
|
8
7
|
from together import APIError, Together, omit
|
|
9
8
|
from together.lib.cli.api._utils import handle_api_errors
|
|
@@ -31,7 +30,7 @@ from .hardware import hardware
|
|
|
31
30
|
)
|
|
32
31
|
@click.option(
|
|
33
32
|
"--gpu",
|
|
34
|
-
type=click.Choice(["h100", "a100", "l40", "l40s", "rtx-6000"]),
|
|
33
|
+
type=click.Choice(["b200", "h200", "h100", "a100", "l40", "l40s", "rtx-6000"]),
|
|
35
34
|
required=True,
|
|
36
35
|
help="GPU type to use for inference",
|
|
37
36
|
)
|
|
@@ -48,7 +47,7 @@ from .hardware import hardware
|
|
|
48
47
|
@click.option(
|
|
49
48
|
"--no-prompt-cache",
|
|
50
49
|
is_flag=True,
|
|
51
|
-
help="
|
|
50
|
+
help="Deprecated and no longer has any effect.",
|
|
52
51
|
)
|
|
53
52
|
@click.option(
|
|
54
53
|
"--no-speculative-decoding",
|
|
@@ -95,6 +94,8 @@ def create(
|
|
|
95
94
|
client: Together = ctx.obj
|
|
96
95
|
# Map GPU types to their full hardware ID names
|
|
97
96
|
gpu_map = {
|
|
97
|
+
"b200": "nvidia_b200_180gb_sxm",
|
|
98
|
+
"h200": "nvidia_h200_140gb_sxm",
|
|
98
99
|
"h100": "nvidia_h100_80gb_sxm",
|
|
99
100
|
"a100": "nvidia_a100_80gb_pcie" if gpu_count == 1 else "nvidia_a100_80gb_sxm",
|
|
100
101
|
"l40": "nvidia_l40",
|
|
@@ -102,6 +103,9 @@ def create(
|
|
|
102
103
|
"rtx-6000": "nvidia_rtx_6000_ada",
|
|
103
104
|
}
|
|
104
105
|
|
|
106
|
+
if no_prompt_cache is not None:
|
|
107
|
+
click.echo("Warning: --no-prompt-cache is deprecated and no longer has any effect.", err=True)
|
|
108
|
+
|
|
105
109
|
hardware_id = f"{gpu_count}x_{gpu_map[gpu]}"
|
|
106
110
|
|
|
107
111
|
try:
|
|
@@ -113,15 +117,19 @@ def create(
|
|
|
113
117
|
"max_replicas": max_replicas,
|
|
114
118
|
},
|
|
115
119
|
display_name=display_name or omit,
|
|
116
|
-
disable_prompt_cache=no_prompt_cache or omit,
|
|
117
120
|
disable_speculative_decoding=no_speculative_decoding or omit,
|
|
118
121
|
state="STOPPED" if no_auto_start else "STARTED",
|
|
119
122
|
inactive_timeout=inactive_timeout,
|
|
120
123
|
extra_query={"availability_zone": availability_zone or omit},
|
|
121
124
|
)
|
|
122
125
|
except APIError as e:
|
|
123
|
-
if
|
|
124
|
-
|
|
126
|
+
if (
|
|
127
|
+
"check the hardware api" in str(e.args[0]).lower()
|
|
128
|
+
or "invalid hardware provided" in str(e.args[0]).lower()
|
|
129
|
+
or "the selected configuration" in str(e.args[0]).lower()
|
|
130
|
+
):
|
|
131
|
+
click.secho("Invalid hardware selected.", fg="red", err=True)
|
|
132
|
+
click.echo("\nAvailable hardware options:")
|
|
125
133
|
ctx.invoke(hardware, available=True, model=model, json=False)
|
|
126
134
|
sys.exit(1)
|
|
127
135
|
raise e
|
|
@@ -134,8 +142,6 @@ def create(
|
|
|
134
142
|
click.echo(f" Hardware: {hardware_id}", err=True)
|
|
135
143
|
if display_name:
|
|
136
144
|
click.echo(f" Display name: {display_name}", err=True)
|
|
137
|
-
if no_prompt_cache:
|
|
138
|
-
click.echo(" Prompt cache: disabled", err=True)
|
|
139
145
|
if no_speculative_decoding:
|
|
140
146
|
click.echo(" Speculative decoding: disabled", err=True)
|
|
141
147
|
if no_auto_start:
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
import re
|
|
3
4
|
import json as json_lib
|
|
5
|
+
from typing import Any, Dict, List
|
|
4
6
|
|
|
5
7
|
import click
|
|
8
|
+
from tabulate import tabulate
|
|
6
9
|
|
|
7
10
|
from together import Together, omit
|
|
11
|
+
from together.types import HardwareListResponse
|
|
8
12
|
from together.lib.cli.api._utils import handle_api_errors
|
|
9
13
|
from together.lib.utils.serializer import datetime_serializer
|
|
10
14
|
|
|
@@ -21,20 +25,47 @@ from together.lib.utils.serializer import datetime_serializer
|
|
|
21
25
|
@handle_api_errors("Endpoints")
|
|
22
26
|
def hardware(client: Together, model: str | None, json: bool, available: bool) -> None:
|
|
23
27
|
"""List all available hardware options, optionally filtered by model."""
|
|
24
|
-
message = "Available hardware options:" if available else "All hardware options:"
|
|
25
|
-
click.echo(message, err=True)
|
|
26
28
|
hardware_options = client.hardware.list(model=model or omit)
|
|
27
|
-
|
|
29
|
+
|
|
28
30
|
if available:
|
|
29
31
|
hardware_options.data = [
|
|
30
32
|
hardware
|
|
31
33
|
for hardware in hardware_options.data
|
|
32
34
|
if hardware.availability is not None and hardware.availability.status == "available"
|
|
33
35
|
]
|
|
34
|
-
|
|
35
36
|
if json:
|
|
36
37
|
json_output = [hardware.model_dump() for hardware in hardware_options.data]
|
|
37
38
|
click.echo(json_lib.dumps(json_output, default=datetime_serializer, indent=2))
|
|
38
39
|
else:
|
|
39
|
-
|
|
40
|
-
|
|
40
|
+
_format_hardware_options(hardware_options, show_availability=model is not None)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def _format_hardware_options(hardware_options: HardwareListResponse, show_availability: bool = True) -> None:
|
|
44
|
+
display_list: List[Dict[str, Any]] = []
|
|
45
|
+
|
|
46
|
+
for hw in hardware_options.data:
|
|
47
|
+
data = {
|
|
48
|
+
"Hardware ID": hw.id,
|
|
49
|
+
"GPU": re.sub(r"\-\d+[a-zA-Z][a-zA-Z]$", "", hw.specs.gpu_type)
|
|
50
|
+
if hw.specs and hw.specs.gpu_type
|
|
51
|
+
else "N/A",
|
|
52
|
+
"Memory": f"{int(hw.specs.gpu_memory)}GB" if hw.specs else "N/A",
|
|
53
|
+
"Count": hw.specs.gpu_count if hw.specs else "N/A",
|
|
54
|
+
"Price (per minute)": (f"${hw.pricing.cents_per_minute / 100:.2f}" if hw.pricing else "N/A"),
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if show_availability:
|
|
58
|
+
status_display = "—"
|
|
59
|
+
if hw.availability:
|
|
60
|
+
status = hw.availability.status
|
|
61
|
+
# Add visual indicators for status
|
|
62
|
+
if status == "available":
|
|
63
|
+
status_display = click.style("✓ available", fg="green")
|
|
64
|
+
elif status == "unavailable":
|
|
65
|
+
status_display = click.style("✗ unavailable", fg="red")
|
|
66
|
+
else: # insufficient
|
|
67
|
+
status_display = click.style("⚠ insufficient", fg="yellow")
|
|
68
|
+
data["availability"] = status_display
|
|
69
|
+
display_list.append(data)
|
|
70
|
+
|
|
71
|
+
click.echo(tabulate(display_list, headers="keys", numalign="left"))
|
|
@@ -5,9 +5,9 @@ import click
|
|
|
5
5
|
from tabulate import tabulate
|
|
6
6
|
|
|
7
7
|
from together import Together, omit
|
|
8
|
-
from together._models import BaseModel
|
|
9
8
|
from together._response import APIResponse as APIResponse
|
|
10
9
|
from together.lib.cli.api._utils import handle_api_errors
|
|
10
|
+
from together.lib.utils.serializer import datetime_serializer
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
@click.command()
|
|
@@ -29,23 +29,27 @@ def list(ctx: click.Context, type: Optional[str], json: bool) -> None:
|
|
|
29
29
|
|
|
30
30
|
models_list = client.models.list(dedicated=type == "dedicated" if type else omit)
|
|
31
31
|
|
|
32
|
+
if json:
|
|
33
|
+
items = [model.model_dump() for model in models_list]
|
|
34
|
+
click.echo(json_lib.dumps(items, indent=2, default=datetime_serializer))
|
|
35
|
+
return
|
|
36
|
+
|
|
32
37
|
display_list: List[Dict[str, Any]] = []
|
|
33
|
-
model:
|
|
34
|
-
|
|
38
|
+
for model in sorted(models_list, key=lambda x: x.type):
|
|
39
|
+
price_parts: List[str] = []
|
|
40
|
+
|
|
41
|
+
# Only show pricing if a value actually exists
|
|
42
|
+
if model.pricing and model.pricing.input > 0 and model.pricing.output > 0:
|
|
43
|
+
price_parts.append(f"${model.pricing.input:.2f}")
|
|
44
|
+
price_parts.append(f"${model.pricing.output:.2f}")
|
|
45
|
+
|
|
35
46
|
display_list.append(
|
|
36
47
|
{
|
|
37
|
-
"
|
|
38
|
-
"Name": model.display_name,
|
|
39
|
-
"Organization": model.organization,
|
|
48
|
+
"Model": model.id,
|
|
40
49
|
"Type": model.type,
|
|
41
|
-
"Context
|
|
42
|
-
"
|
|
43
|
-
"Input per 1M token": model.pricing.input if model.pricing else None,
|
|
44
|
-
"Output per 1M token": model.pricing.output if model.pricing else None,
|
|
50
|
+
"Context length": model.context_length if model.context_length else None,
|
|
51
|
+
"Price per 1M Tokens (input/output)": "/".join(price_parts),
|
|
45
52
|
}
|
|
46
53
|
)
|
|
47
54
|
|
|
48
|
-
|
|
49
|
-
click.echo(json_lib.dumps(display_list, indent=2))
|
|
50
|
-
else:
|
|
51
|
-
click.echo(tabulate(display_list, headers="keys", tablefmt="plain"))
|
|
55
|
+
click.echo(tabulate(display_list, headers="keys"))
|
|
@@ -3,7 +3,7 @@ from typing import Literal, Optional
|
|
|
3
3
|
|
|
4
4
|
import click
|
|
5
5
|
|
|
6
|
-
from together import Together, omit
|
|
6
|
+
from together import Together, TogetherError, omit
|
|
7
7
|
from together._response import APIResponse as APIResponse
|
|
8
8
|
from together.lib.cli.api._utils import handle_api_errors
|
|
9
9
|
from together.types.model_upload_response import ModelUploadResponse
|
|
@@ -76,6 +76,10 @@ def upload(
|
|
|
76
76
|
if json:
|
|
77
77
|
click.echo(json_lib.dumps(response.model_dump(), indent=2))
|
|
78
78
|
else:
|
|
79
|
+
# If the model weights already exist, the api is returning 200 but with no data
|
|
80
|
+
if response.data is None: # type: ignore
|
|
81
|
+
raise TogetherError(response.message)
|
|
82
|
+
|
|
79
83
|
click.echo(f"Model upload job created successfully!")
|
|
80
84
|
if response.data.job_id:
|
|
81
85
|
click.echo(f"Job ID: {response.data.job_id}")
|
together/resources/__init__.py
CHANGED
|
@@ -16,14 +16,6 @@ from .chat import (
|
|
|
16
16
|
ChatResourceWithStreamingResponse,
|
|
17
17
|
AsyncChatResourceWithStreamingResponse,
|
|
18
18
|
)
|
|
19
|
-
from .jobs import (
|
|
20
|
-
JobsResource,
|
|
21
|
-
AsyncJobsResource,
|
|
22
|
-
JobsResourceWithRawResponse,
|
|
23
|
-
AsyncJobsResourceWithRawResponse,
|
|
24
|
-
JobsResourceWithStreamingResponse,
|
|
25
|
-
AsyncJobsResourceWithStreamingResponse,
|
|
26
|
-
)
|
|
27
19
|
from .audio import (
|
|
28
20
|
AudioResource,
|
|
29
21
|
AsyncAudioResource,
|
|
@@ -204,12 +196,6 @@ __all__ = [
|
|
|
204
196
|
"AsyncModelsResourceWithRawResponse",
|
|
205
197
|
"ModelsResourceWithStreamingResponse",
|
|
206
198
|
"AsyncModelsResourceWithStreamingResponse",
|
|
207
|
-
"JobsResource",
|
|
208
|
-
"AsyncJobsResource",
|
|
209
|
-
"JobsResourceWithRawResponse",
|
|
210
|
-
"AsyncJobsResourceWithRawResponse",
|
|
211
|
-
"JobsResourceWithStreamingResponse",
|
|
212
|
-
"AsyncJobsResourceWithStreamingResponse",
|
|
213
199
|
"EndpointsResource",
|
|
214
200
|
"AsyncEndpointsResource",
|
|
215
201
|
"EndpointsResourceWithRawResponse",
|
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
|
|
2
2
|
|
|
3
|
+
from .jig import (
|
|
4
|
+
JigResource,
|
|
5
|
+
AsyncJigResource,
|
|
6
|
+
JigResourceWithRawResponse,
|
|
7
|
+
AsyncJigResourceWithRawResponse,
|
|
8
|
+
JigResourceWithStreamingResponse,
|
|
9
|
+
AsyncJigResourceWithStreamingResponse,
|
|
10
|
+
)
|
|
3
11
|
from .beta import (
|
|
4
12
|
BetaResource,
|
|
5
13
|
AsyncBetaResource,
|
|
@@ -18,6 +26,12 @@ from .clusters import (
|
|
|
18
26
|
)
|
|
19
27
|
|
|
20
28
|
__all__ = [
|
|
29
|
+
"JigResource",
|
|
30
|
+
"AsyncJigResource",
|
|
31
|
+
"JigResourceWithRawResponse",
|
|
32
|
+
"AsyncJigResourceWithRawResponse",
|
|
33
|
+
"JigResourceWithStreamingResponse",
|
|
34
|
+
"AsyncJigResourceWithStreamingResponse",
|
|
21
35
|
"ClustersResource",
|
|
22
36
|
"AsyncClustersResource",
|
|
23
37
|
"ClustersResourceWithRawResponse",
|
together/resources/beta/beta.py
CHANGED
|
@@ -2,6 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
from .jig.jig import (
|
|
6
|
+
JigResource,
|
|
7
|
+
AsyncJigResource,
|
|
8
|
+
JigResourceWithRawResponse,
|
|
9
|
+
AsyncJigResourceWithRawResponse,
|
|
10
|
+
JigResourceWithStreamingResponse,
|
|
11
|
+
AsyncJigResourceWithStreamingResponse,
|
|
12
|
+
)
|
|
5
13
|
from ..._compat import cached_property
|
|
6
14
|
from ..._resource import SyncAPIResource, AsyncAPIResource
|
|
7
15
|
from .clusters.clusters import (
|
|
@@ -17,6 +25,10 @@ __all__ = ["BetaResource", "AsyncBetaResource"]
|
|
|
17
25
|
|
|
18
26
|
|
|
19
27
|
class BetaResource(SyncAPIResource):
|
|
28
|
+
@cached_property
|
|
29
|
+
def jig(self) -> JigResource:
|
|
30
|
+
return JigResource(self._client)
|
|
31
|
+
|
|
20
32
|
@cached_property
|
|
21
33
|
def clusters(self) -> ClustersResource:
|
|
22
34
|
return ClustersResource(self._client)
|
|
@@ -42,6 +54,10 @@ class BetaResource(SyncAPIResource):
|
|
|
42
54
|
|
|
43
55
|
|
|
44
56
|
class AsyncBetaResource(AsyncAPIResource):
|
|
57
|
+
@cached_property
|
|
58
|
+
def jig(self) -> AsyncJigResource:
|
|
59
|
+
return AsyncJigResource(self._client)
|
|
60
|
+
|
|
45
61
|
@cached_property
|
|
46
62
|
def clusters(self) -> AsyncClustersResource:
|
|
47
63
|
return AsyncClustersResource(self._client)
|
|
@@ -70,6 +86,10 @@ class BetaResourceWithRawResponse:
|
|
|
70
86
|
def __init__(self, beta: BetaResource) -> None:
|
|
71
87
|
self._beta = beta
|
|
72
88
|
|
|
89
|
+
@cached_property
|
|
90
|
+
def jig(self) -> JigResourceWithRawResponse:
|
|
91
|
+
return JigResourceWithRawResponse(self._beta.jig)
|
|
92
|
+
|
|
73
93
|
@cached_property
|
|
74
94
|
def clusters(self) -> ClustersResourceWithRawResponse:
|
|
75
95
|
return ClustersResourceWithRawResponse(self._beta.clusters)
|
|
@@ -79,6 +99,10 @@ class AsyncBetaResourceWithRawResponse:
|
|
|
79
99
|
def __init__(self, beta: AsyncBetaResource) -> None:
|
|
80
100
|
self._beta = beta
|
|
81
101
|
|
|
102
|
+
@cached_property
|
|
103
|
+
def jig(self) -> AsyncJigResourceWithRawResponse:
|
|
104
|
+
return AsyncJigResourceWithRawResponse(self._beta.jig)
|
|
105
|
+
|
|
82
106
|
@cached_property
|
|
83
107
|
def clusters(self) -> AsyncClustersResourceWithRawResponse:
|
|
84
108
|
return AsyncClustersResourceWithRawResponse(self._beta.clusters)
|
|
@@ -88,6 +112,10 @@ class BetaResourceWithStreamingResponse:
|
|
|
88
112
|
def __init__(self, beta: BetaResource) -> None:
|
|
89
113
|
self._beta = beta
|
|
90
114
|
|
|
115
|
+
@cached_property
|
|
116
|
+
def jig(self) -> JigResourceWithStreamingResponse:
|
|
117
|
+
return JigResourceWithStreamingResponse(self._beta.jig)
|
|
118
|
+
|
|
91
119
|
@cached_property
|
|
92
120
|
def clusters(self) -> ClustersResourceWithStreamingResponse:
|
|
93
121
|
return ClustersResourceWithStreamingResponse(self._beta.clusters)
|
|
@@ -97,6 +125,10 @@ class AsyncBetaResourceWithStreamingResponse:
|
|
|
97
125
|
def __init__(self, beta: AsyncBetaResource) -> None:
|
|
98
126
|
self._beta = beta
|
|
99
127
|
|
|
128
|
+
@cached_property
|
|
129
|
+
def jig(self) -> AsyncJigResourceWithStreamingResponse:
|
|
130
|
+
return AsyncJigResourceWithStreamingResponse(self._beta.jig)
|
|
131
|
+
|
|
100
132
|
@cached_property
|
|
101
133
|
def clusters(self) -> AsyncClustersResourceWithStreamingResponse:
|
|
102
134
|
return AsyncClustersResourceWithStreamingResponse(self._beta.clusters)
|
|
@@ -110,7 +110,7 @@ class ClustersResource(SyncAPIResource):
|
|
|
110
110
|
timeout: Override the client-level default timeout for this request, in seconds
|
|
111
111
|
"""
|
|
112
112
|
return self._post(
|
|
113
|
-
"/clusters",
|
|
113
|
+
"/compute/clusters",
|
|
114
114
|
body=maybe_transform(
|
|
115
115
|
{
|
|
116
116
|
"billing_type": billing_type,
|
|
@@ -158,7 +158,7 @@ class ClustersResource(SyncAPIResource):
|
|
|
158
158
|
if not cluster_id:
|
|
159
159
|
raise ValueError(f"Expected a non-empty value for `cluster_id` but received {cluster_id!r}")
|
|
160
160
|
return self._get(
|
|
161
|
-
f"/clusters/{cluster_id}",
|
|
161
|
+
f"/compute/clusters/{cluster_id}",
|
|
162
162
|
options=make_request_options(
|
|
163
163
|
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
|
|
164
164
|
),
|
|
@@ -193,7 +193,7 @@ class ClustersResource(SyncAPIResource):
|
|
|
193
193
|
if not cluster_id:
|
|
194
194
|
raise ValueError(f"Expected a non-empty value for `cluster_id` but received {cluster_id!r}")
|
|
195
195
|
return self._put(
|
|
196
|
-
f"/clusters/{cluster_id}",
|
|
196
|
+
f"/compute/clusters/{cluster_id}",
|
|
197
197
|
body=maybe_transform(
|
|
198
198
|
{
|
|
199
199
|
"cluster_type": cluster_type,
|
|
@@ -219,7 +219,7 @@ class ClustersResource(SyncAPIResource):
|
|
|
219
219
|
) -> ClusterListResponse:
|
|
220
220
|
"""List all GPU clusters."""
|
|
221
221
|
return self._get(
|
|
222
|
-
"/clusters",
|
|
222
|
+
"/compute/clusters",
|
|
223
223
|
options=make_request_options(
|
|
224
224
|
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
|
|
225
225
|
),
|
|
@@ -252,7 +252,7 @@ class ClustersResource(SyncAPIResource):
|
|
|
252
252
|
if not cluster_id:
|
|
253
253
|
raise ValueError(f"Expected a non-empty value for `cluster_id` but received {cluster_id!r}")
|
|
254
254
|
return self._delete(
|
|
255
|
-
f"/clusters/{cluster_id}",
|
|
255
|
+
f"/compute/clusters/{cluster_id}",
|
|
256
256
|
options=make_request_options(
|
|
257
257
|
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
|
|
258
258
|
),
|
|
@@ -271,7 +271,7 @@ class ClustersResource(SyncAPIResource):
|
|
|
271
271
|
) -> ClusterListRegionsResponse:
|
|
272
272
|
"""List regions and corresponding supported driver versions"""
|
|
273
273
|
return self._get(
|
|
274
|
-
"/
|
|
274
|
+
"/compute/regions",
|
|
275
275
|
options=make_request_options(
|
|
276
276
|
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
|
|
277
277
|
),
|
|
@@ -355,7 +355,7 @@ class AsyncClustersResource(AsyncAPIResource):
|
|
|
355
355
|
timeout: Override the client-level default timeout for this request, in seconds
|
|
356
356
|
"""
|
|
357
357
|
return await self._post(
|
|
358
|
-
"/clusters",
|
|
358
|
+
"/compute/clusters",
|
|
359
359
|
body=await async_maybe_transform(
|
|
360
360
|
{
|
|
361
361
|
"billing_type": billing_type,
|
|
@@ -403,7 +403,7 @@ class AsyncClustersResource(AsyncAPIResource):
|
|
|
403
403
|
if not cluster_id:
|
|
404
404
|
raise ValueError(f"Expected a non-empty value for `cluster_id` but received {cluster_id!r}")
|
|
405
405
|
return await self._get(
|
|
406
|
-
f"/clusters/{cluster_id}",
|
|
406
|
+
f"/compute/clusters/{cluster_id}",
|
|
407
407
|
options=make_request_options(
|
|
408
408
|
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
|
|
409
409
|
),
|
|
@@ -438,7 +438,7 @@ class AsyncClustersResource(AsyncAPIResource):
|
|
|
438
438
|
if not cluster_id:
|
|
439
439
|
raise ValueError(f"Expected a non-empty value for `cluster_id` but received {cluster_id!r}")
|
|
440
440
|
return await self._put(
|
|
441
|
-
f"/clusters/{cluster_id}",
|
|
441
|
+
f"/compute/clusters/{cluster_id}",
|
|
442
442
|
body=await async_maybe_transform(
|
|
443
443
|
{
|
|
444
444
|
"cluster_type": cluster_type,
|
|
@@ -464,7 +464,7 @@ class AsyncClustersResource(AsyncAPIResource):
|
|
|
464
464
|
) -> ClusterListResponse:
|
|
465
465
|
"""List all GPU clusters."""
|
|
466
466
|
return await self._get(
|
|
467
|
-
"/clusters",
|
|
467
|
+
"/compute/clusters",
|
|
468
468
|
options=make_request_options(
|
|
469
469
|
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
|
|
470
470
|
),
|
|
@@ -497,7 +497,7 @@ class AsyncClustersResource(AsyncAPIResource):
|
|
|
497
497
|
if not cluster_id:
|
|
498
498
|
raise ValueError(f"Expected a non-empty value for `cluster_id` but received {cluster_id!r}")
|
|
499
499
|
return await self._delete(
|
|
500
|
-
f"/clusters/{cluster_id}",
|
|
500
|
+
f"/compute/clusters/{cluster_id}",
|
|
501
501
|
options=make_request_options(
|
|
502
502
|
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
|
|
503
503
|
),
|
|
@@ -516,7 +516,7 @@ class AsyncClustersResource(AsyncAPIResource):
|
|
|
516
516
|
) -> ClusterListRegionsResponse:
|
|
517
517
|
"""List regions and corresponding supported driver versions"""
|
|
518
518
|
return await self._get(
|
|
519
|
-
"/
|
|
519
|
+
"/compute/regions",
|
|
520
520
|
options=make_request_options(
|
|
521
521
|
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
|
|
522
522
|
),
|