together 2.0.0a15__py3-none-any.whl → 2.0.0a17__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 (83) hide show
  1. together/_base_client.py +134 -11
  2. together/_client.py +7 -0
  3. together/_models.py +16 -1
  4. together/_types.py +9 -0
  5. together/_version.py +1 -1
  6. together/constants.py +1 -1
  7. together/error.py +1 -2
  8. together/lib/_google_colab.py +39 -0
  9. together/lib/cli/__init__.py +73 -0
  10. together/lib/cli/api/beta/clusters/__init__.py +47 -0
  11. together/lib/cli/api/beta/{clusters.py → clusters/create.py} +5 -179
  12. together/lib/cli/api/beta/clusters/delete.py +35 -0
  13. together/lib/cli/api/beta/clusters/get_credentials.py +151 -0
  14. together/lib/cli/api/beta/clusters/list.py +24 -0
  15. together/lib/cli/api/beta/clusters/list_regions.py +37 -0
  16. together/lib/cli/api/beta/clusters/retrieve.py +31 -0
  17. together/lib/cli/api/beta/clusters/storage/__init__.py +19 -0
  18. together/lib/cli/api/beta/clusters/storage/create.py +49 -0
  19. together/lib/cli/api/beta/clusters/storage/delete.py +38 -0
  20. together/lib/cli/api/beta/clusters/storage/list.py +42 -0
  21. together/lib/cli/api/beta/clusters/storage/retrieve.py +34 -0
  22. together/lib/cli/api/beta/clusters/update.py +54 -0
  23. together/lib/cli/api/endpoints/__init__.py +56 -0
  24. together/lib/cli/api/endpoints/availability_zones.py +26 -0
  25. together/lib/cli/api/endpoints/create.py +161 -0
  26. together/lib/cli/api/endpoints/delete.py +15 -0
  27. together/lib/cli/api/endpoints/hardware.py +40 -0
  28. together/lib/cli/api/endpoints/list.py +66 -0
  29. together/lib/cli/api/endpoints/retrieve.py +23 -0
  30. together/lib/cli/api/endpoints/start.py +25 -0
  31. together/lib/cli/api/endpoints/stop.py +25 -0
  32. together/lib/cli/api/endpoints/update.py +77 -0
  33. together/lib/cli/api/evals/__init__.py +19 -0
  34. together/lib/cli/api/{evals.py → evals/create.py} +6 -129
  35. together/lib/cli/api/evals/list.py +58 -0
  36. together/lib/cli/api/evals/retrieve.py +21 -0
  37. together/lib/cli/api/evals/status.py +20 -0
  38. together/lib/cli/api/files/__init__.py +23 -0
  39. together/lib/cli/api/files/check.py +21 -0
  40. together/lib/cli/api/files/delete.py +20 -0
  41. together/lib/cli/api/files/list.py +34 -0
  42. together/lib/cli/api/files/retrieve.py +20 -0
  43. together/lib/cli/api/files/retrieve_content.py +25 -0
  44. together/lib/cli/api/files/upload.py +38 -0
  45. together/lib/cli/api/fine_tuning/__init__.py +27 -0
  46. together/lib/cli/api/fine_tuning/cancel.py +28 -0
  47. together/lib/cli/api/{fine_tuning.py → fine_tuning/create.py} +5 -257
  48. together/lib/cli/api/fine_tuning/delete.py +29 -0
  49. together/lib/cli/api/fine_tuning/download.py +94 -0
  50. together/lib/cli/api/fine_tuning/list.py +44 -0
  51. together/lib/cli/api/fine_tuning/list_checkpoints.py +42 -0
  52. together/lib/cli/api/fine_tuning/list_events.py +35 -0
  53. together/lib/cli/api/fine_tuning/retrieve.py +27 -0
  54. together/lib/cli/api/models/__init__.py +15 -0
  55. together/lib/cli/api/models/list.py +55 -0
  56. together/lib/cli/api/{models.py → models/upload.py} +4 -51
  57. together/resources/beta/clusters/clusters.py +36 -28
  58. together/resources/beta/clusters/storage.py +30 -21
  59. together/resources/endpoints.py +2 -2
  60. together/types/__init__.py +4 -3
  61. together/types/beta/__init__.py +0 -2
  62. together/types/beta/cluster_create_params.py +3 -3
  63. together/types/beta/clusters/__init__.py +0 -1
  64. together/types/beta/clusters/cluster_storage.py +4 -0
  65. together/types/chat_completions.py +1 -1
  66. together/types/endpoint_create_params.py +1 -1
  67. together/types/endpoints.py +1 -1
  68. {together-2.0.0a15.dist-info → together-2.0.0a17.dist-info}/METADATA +4 -2
  69. {together-2.0.0a15.dist-info → together-2.0.0a17.dist-info}/RECORD +74 -38
  70. together-2.0.0a17.dist-info/entry_points.txt +2 -0
  71. together/lib/cli/api/__init__.py +0 -0
  72. together/lib/cli/api/beta/clusters_storage.py +0 -152
  73. together/lib/cli/api/endpoints.py +0 -467
  74. together/lib/cli/api/files.py +0 -133
  75. together/lib/cli/cli.py +0 -73
  76. together/types/beta/cluster_create_response.py +0 -9
  77. together/types/beta/cluster_update_response.py +0 -9
  78. together/types/beta/clusters/storage_create_response.py +0 -9
  79. together-2.0.0a15.dist-info/entry_points.txt +0 -2
  80. /together/lib/cli/api/{utils.py → _utils.py} +0 -0
  81. /together/lib/cli/api/beta/{beta.py → __init__.py} +0 -0
  82. {together-2.0.0a15.dist-info → together-2.0.0a17.dist-info}/WHEEL +0 -0
  83. {together-2.0.0a15.dist-info → together-2.0.0a17.dist-info}/licenses/LICENSE +0 -0
@@ -1,14 +1,10 @@
1
- import sys
2
1
  import json
3
- from typing import Any, Dict, List, Union, Literal, TypeVar, Callable, Optional, cast
4
- from functools import wraps
2
+ from typing import Any, Dict, Union, Literal, Optional, cast
5
3
 
6
4
  import click
7
- from tabulate import tabulate
8
5
 
9
- from together import APIError, Together, TogetherError
10
- from together._types import omit
11
- from together.lib.utils.serializer import datetime_serializer
6
+ from together import Together, TogetherError
7
+ from together.lib.cli.api._utils import handle_api_errors
12
8
  from together.types.eval_create_params import (
13
9
  ParametersEvaluationScoreParameters,
14
10
  ParametersEvaluationCompareParameters,
@@ -23,51 +19,7 @@ from together.types.eval_create_params import (
23
19
  )
24
20
 
25
21
 
26
- def print_api_error(e: Union[APIError, TogetherError]) -> None:
27
- if isinstance(e, APIError):
28
- error_details = cast(Dict[str, Any], e.body)["error"]["message"]
29
-
30
- if error_details and ("credentials" in error_details.lower() or "authentication" in error_details.lower()):
31
- click.echo("Error: Invalid API key or authentication failed", err=True)
32
- else:
33
- click.echo(f"Error: {error_details}", err=True)
34
-
35
- click.echo(f"Error: {e}", err=True)
36
- return
37
-
38
-
39
- F = TypeVar("F", bound=Callable[..., Any])
40
-
41
-
42
- def handle_api_errors(f: F) -> F:
43
- """Decorator to handle common API errors in CLI commands."""
44
-
45
- @wraps(f)
46
- def wrapper(*args: Any, **kwargs: Any) -> Any:
47
- try:
48
- return f(*args, **kwargs)
49
- except APIError as e:
50
- print_api_error(e)
51
- sys.exit(1)
52
- except TogetherError as e:
53
- print_api_error(e)
54
- sys.exit(1)
55
- except Exception as e:
56
- click.echo(f"Error: An unexpected error occurred - {str(e)}", err=True)
57
- sys.exit(1)
58
-
59
- return wrapper # type: ignore
60
-
61
-
62
- @click.group()
63
- @click.pass_context
64
- def evals(ctx: click.Context) -> None:
65
- """Evals API commands"""
66
- pass
67
-
68
-
69
- @evals.command()
70
- @click.pass_context
22
+ @click.command()
71
23
  @click.option(
72
24
  "--type",
73
25
  type=click.Choice(["classify", "score", "compare"]),
@@ -273,7 +225,8 @@ def evals(ctx: click.Context) -> None:
273
225
  type=str,
274
226
  help="Input template for model B.",
275
227
  )
276
- @handle_api_errors
228
+ @click.pass_context
229
+ @handle_api_errors("Evals")
277
230
  def create(
278
231
  ctx: click.Context,
279
232
  type: Literal["classify", "score", "compare"],
@@ -477,82 +430,6 @@ def create(
477
430
  click.echo(json.dumps(response.model_dump(exclude_none=True), indent=4))
478
431
 
479
432
 
480
- @evals.command()
481
- @click.pass_context
482
- @click.option(
483
- "--status",
484
- type=click.Choice(["pending", "queued", "running", "completed", "error", "user_error"]),
485
- help="Filter by job status.",
486
- )
487
- @click.option(
488
- "--limit",
489
- type=int,
490
- help="Limit number of results (max 100).",
491
- )
492
- def list(
493
- ctx: click.Context,
494
- status: Union[Literal["pending", "queued", "running", "completed", "error", "user_error"], None],
495
- limit: Union[int, None],
496
- ) -> None:
497
- """List evals"""
498
-
499
- client: Together = ctx.obj
500
-
501
- response = client.evals.list(status=status or omit, limit=limit or omit)
502
-
503
- display_list: List[Dict[str, Any]] = []
504
- for job in response:
505
- if job.parameters:
506
- model = job.parameters.get("model_to_evaluate", "")
507
- model_a = job.parameters.get("model_a", "")
508
- model_b = job.parameters.get("model_b", "")
509
- else:
510
- model = ""
511
- model_a = ""
512
- model_b = ""
513
-
514
- display_list.append(
515
- {
516
- "Workflow ID": job.workflow_id or "",
517
- "Type": job.type,
518
- "Status": job.status,
519
- "Created At": job.created_at or 0,
520
- "Model": model,
521
- "Model A": model_a,
522
- "Model B": model_b,
523
- }
524
- )
525
-
526
- table = tabulate(display_list, headers="keys", tablefmt="grid", showindex=True)
527
- click.echo(table)
528
-
529
-
530
- @evals.command()
531
- @click.pass_context
532
- @click.argument("evaluation_id", type=str, required=True)
533
- def retrieve(ctx: click.Context, evaluation_id: str) -> None:
534
- """Get details of a specific evaluation job"""
535
-
536
- client: Together = ctx.obj
537
-
538
- response = client.evals.retrieve(evaluation_id)
539
-
540
- click.echo(json.dumps(response.model_dump(exclude_none=True), default=datetime_serializer, indent=4))
541
-
542
-
543
- @evals.command()
544
- @click.pass_context
545
- @click.argument("evaluation_id", type=str, required=True)
546
- def status(ctx: click.Context, evaluation_id: str) -> None:
547
- """Get the status and results of a specific evaluation job"""
548
-
549
- client: Together = ctx.obj
550
-
551
- response = client.evals.status(evaluation_id)
552
-
553
- click.echo(json.dumps(response.model_dump(exclude_none=True), indent=4))
554
-
555
-
556
433
  def _build_judge(
557
434
  type: Literal["classify", "score", "compare"],
558
435
  judge_model: str,
@@ -0,0 +1,58 @@
1
+ from typing import Any, Dict, List, Union, Literal
2
+
3
+ import click
4
+ from tabulate import tabulate
5
+
6
+ from together import Together, omit
7
+ from together.lib.cli.api._utils import handle_api_errors
8
+
9
+
10
+ @click.command()
11
+ @click.option(
12
+ "--status",
13
+ type=click.Choice(["pending", "queued", "running", "completed", "error", "user_error"]),
14
+ help="Filter by job status.",
15
+ )
16
+ @click.option(
17
+ "--limit",
18
+ type=int,
19
+ help="Limit number of results (max 100).",
20
+ )
21
+ @click.pass_context
22
+ @handle_api_errors("Evals")
23
+ def list(
24
+ ctx: click.Context,
25
+ status: Union[Literal["pending", "queued", "running", "completed", "error", "user_error"], None],
26
+ limit: Union[int, None],
27
+ ) -> None:
28
+ """List evals"""
29
+
30
+ client: Together = ctx.obj
31
+
32
+ response = client.evals.list(status=status or omit, limit=limit or omit)
33
+
34
+ display_list: List[Dict[str, Any]] = []
35
+ for job in response:
36
+ if job.parameters:
37
+ model = job.parameters.get("model_to_evaluate", "")
38
+ model_a = job.parameters.get("model_a", "")
39
+ model_b = job.parameters.get("model_b", "")
40
+ else:
41
+ model = ""
42
+ model_a = ""
43
+ model_b = ""
44
+
45
+ display_list.append(
46
+ {
47
+ "Workflow ID": job.workflow_id or "",
48
+ "Type": job.type,
49
+ "Status": job.status,
50
+ "Created At": job.created_at or 0,
51
+ "Model": model,
52
+ "Model A": model_a,
53
+ "Model B": model_b,
54
+ }
55
+ )
56
+
57
+ table = tabulate(display_list, headers="keys", tablefmt="grid", showindex=True)
58
+ click.echo(table)
@@ -0,0 +1,21 @@
1
+ import json
2
+
3
+ import click
4
+
5
+ from together import Together
6
+ from together.lib.cli.api._utils import handle_api_errors
7
+ from together.lib.utils.serializer import datetime_serializer
8
+
9
+
10
+ @click.command()
11
+ @click.pass_context
12
+ @click.argument("evaluation_id", type=str, required=True)
13
+ @handle_api_errors("Evals")
14
+ def retrieve(ctx: click.Context, evaluation_id: str) -> None:
15
+ """Get details of a specific evaluation job"""
16
+
17
+ client: Together = ctx.obj
18
+
19
+ response = client.evals.retrieve(evaluation_id)
20
+
21
+ click.echo(json.dumps(response.model_dump(exclude_none=True), default=datetime_serializer, indent=4))
@@ -0,0 +1,20 @@
1
+ import json
2
+
3
+ import click
4
+
5
+ from together import Together
6
+ from together.lib.cli.api._utils import handle_api_errors
7
+
8
+
9
+ @click.command()
10
+ @click.pass_context
11
+ @click.argument("evaluation_id", type=str, required=True)
12
+ @handle_api_errors("Evals")
13
+ def status(ctx: click.Context, evaluation_id: str) -> None:
14
+ """Get the status and results of a specific evaluation job"""
15
+
16
+ client: Together = ctx.obj
17
+
18
+ response = client.evals.status(evaluation_id)
19
+
20
+ click.echo(json.dumps(response.model_dump(exclude_none=True), indent=4))
@@ -0,0 +1,23 @@
1
+ import click
2
+
3
+ from .list import list
4
+ from .check import check
5
+ from .delete import delete
6
+ from .upload import upload
7
+ from .retrieve import retrieve
8
+ from .retrieve_content import retrieve_content
9
+
10
+
11
+ @click.group()
12
+ @click.pass_context
13
+ def files(ctx: click.Context) -> None:
14
+ """File API commands"""
15
+ pass
16
+
17
+
18
+ files.add_command(upload)
19
+ files.add_command(list)
20
+ files.add_command(retrieve)
21
+ files.add_command(retrieve_content)
22
+ files.add_command(delete)
23
+ files.add_command(check)
@@ -0,0 +1,21 @@
1
+ import json
2
+ import pathlib
3
+
4
+ import click
5
+
6
+ from together.lib.utils import check_file
7
+
8
+
9
+ @click.command()
10
+ @click.pass_context
11
+ @click.argument(
12
+ "file",
13
+ type=click.Path(exists=True, file_okay=True, resolve_path=True, readable=True, dir_okay=False),
14
+ required=True,
15
+ )
16
+ def check(_ctx: click.Context, file: pathlib.Path) -> None:
17
+ """Check file for issues"""
18
+
19
+ report = check_file(file)
20
+
21
+ click.echo(json.dumps(report, indent=4))
@@ -0,0 +1,20 @@
1
+ import json
2
+
3
+ import click
4
+
5
+ from together import Together
6
+ from together.lib.cli.api._utils import handle_api_errors
7
+
8
+
9
+ @click.command()
10
+ @click.pass_context
11
+ @click.argument("id", type=str, required=True)
12
+ @handle_api_errors("Files")
13
+ def delete(ctx: click.Context, id: str) -> None:
14
+ """Delete remote file"""
15
+
16
+ client: Together = ctx.obj
17
+
18
+ response = client.files.delete(id=id)
19
+
20
+ click.echo(json.dumps(response.model_dump(exclude_none=True), indent=4))
@@ -0,0 +1,34 @@
1
+ from typing import Any, Dict, List
2
+ from textwrap import wrap
3
+
4
+ import click
5
+ from tabulate import tabulate
6
+
7
+ from together import Together
8
+ from together.lib.utils import convert_bytes, convert_unix_timestamp
9
+ from together.lib.cli.api._utils import handle_api_errors
10
+
11
+
12
+ @click.command()
13
+ @click.pass_context
14
+ @handle_api_errors("Files")
15
+ def list(ctx: click.Context) -> None:
16
+ """List files"""
17
+ client: Together = ctx.obj
18
+
19
+ response = client.files.list()
20
+
21
+ display_list: List[Dict[str, Any]] = []
22
+ for i in response.data or []:
23
+ display_list.append(
24
+ {
25
+ "File name": "\n".join(wrap(i.filename or "", width=30)),
26
+ "File ID": i.id,
27
+ "Size": convert_bytes(float(str(i.bytes))), # convert to string for mypy typing
28
+ "Created At": convert_unix_timestamp(i.created_at or 0),
29
+ "Line Count": i.line_count,
30
+ }
31
+ )
32
+ table = tabulate(display_list, headers="keys", tablefmt="grid", showindex=True)
33
+
34
+ click.echo(table)
@@ -0,0 +1,20 @@
1
+ import json
2
+
3
+ import click
4
+
5
+ from together import Together
6
+ from together.lib.cli.api._utils import handle_api_errors
7
+
8
+
9
+ @click.command()
10
+ @click.pass_context
11
+ @click.argument("id", type=str, required=True)
12
+ @handle_api_errors("Files")
13
+ def retrieve(ctx: click.Context, id: str) -> None:
14
+ """Upload file"""
15
+
16
+ client: Together = ctx.obj
17
+
18
+ response = client.files.retrieve(id=id)
19
+
20
+ click.echo(json.dumps(response.model_dump(exclude_none=True), indent=4))
@@ -0,0 +1,25 @@
1
+ import click
2
+
3
+ from together import Together
4
+ from together.lib.cli.api._utils import handle_api_errors
5
+
6
+
7
+ @click.command()
8
+ @click.pass_context
9
+ @click.argument("id", type=str, required=True)
10
+ @click.option("--output", type=str, default=None, help="Output filename")
11
+ @handle_api_errors("Files")
12
+ def retrieve_content(ctx: click.Context, id: str, output: str) -> None:
13
+ """Retrieve file content and output to file"""
14
+
15
+ client: Together = ctx.obj
16
+
17
+ response = client.files.content(id=id)
18
+
19
+ if output:
20
+ with open(output, "wb") as f:
21
+ f.write(response.read())
22
+ click.echo(f"File saved to {output}")
23
+
24
+ else:
25
+ click.echo(response.read().decode("utf-8"))
@@ -0,0 +1,38 @@
1
+ import json
2
+ import pathlib
3
+ from typing import get_args
4
+
5
+ import click
6
+
7
+ from together import Together
8
+ from together.types import FilePurpose
9
+ from together.lib.cli.api._utils import handle_api_errors
10
+
11
+
12
+ @click.command()
13
+ @click.pass_context
14
+ @click.argument(
15
+ "file",
16
+ type=click.Path(exists=True, file_okay=True, resolve_path=True, readable=True, dir_okay=False),
17
+ required=True,
18
+ )
19
+ @click.option(
20
+ "--purpose",
21
+ type=click.Choice(get_args(FilePurpose)),
22
+ default="fine-tune",
23
+ help="Purpose of file upload. Acceptable values in enum `together.types.FilePurpose`. Defaults to `fine-tunes`.",
24
+ )
25
+ @click.option(
26
+ "--check/--no-check",
27
+ default=True,
28
+ help="Whether to check the file before uploading.",
29
+ )
30
+ @handle_api_errors("Files")
31
+ def upload(ctx: click.Context, file: pathlib.Path, purpose: FilePurpose, check: bool) -> None:
32
+ """Upload file"""
33
+
34
+ client: Together = ctx.obj
35
+
36
+ response = client.files.upload(file=file, purpose=purpose, check=check)
37
+
38
+ click.echo(json.dumps(response.model_dump(exclude_none=True), indent=4))
@@ -0,0 +1,27 @@
1
+ import click
2
+
3
+ from .list import list
4
+ from .cancel import cancel
5
+ from .create import create
6
+ from .delete import delete
7
+ from .download import download
8
+ from .retrieve import retrieve
9
+ from .list_events import list_events
10
+ from .list_checkpoints import list_checkpoints
11
+
12
+
13
+ @click.group(name="fine-tuning")
14
+ @click.pass_context
15
+ def fine_tuning(ctx: click.Context) -> None:
16
+ """Fine-tunes API commands"""
17
+ pass
18
+
19
+
20
+ fine_tuning.add_command(create)
21
+ fine_tuning.add_command(list)
22
+ fine_tuning.add_command(retrieve)
23
+ fine_tuning.add_command(cancel)
24
+ fine_tuning.add_command(list_events)
25
+ fine_tuning.add_command(list_checkpoints)
26
+ fine_tuning.add_command(download)
27
+ fine_tuning.add_command(delete)
@@ -0,0 +1,28 @@
1
+ import json
2
+
3
+ import click
4
+
5
+ from together import Together
6
+ from together.lib.cli.api._utils import handle_api_errors
7
+ from together.lib.utils.serializer import datetime_serializer
8
+
9
+
10
+ @click.command()
11
+ @click.pass_context
12
+ @click.argument("fine_tune_id", type=str, required=True)
13
+ @click.option("--quiet", is_flag=True, help="Do not prompt for confirmation before cancelling job")
14
+ @handle_api_errors("Fine-tuning")
15
+ def cancel(ctx: click.Context, fine_tune_id: str, quiet: bool = False) -> None:
16
+ """Cancel fine-tuning job"""
17
+ client: Together = ctx.obj
18
+ if not quiet:
19
+ confirm_response = input(
20
+ "You will be billed for any completed training steps upon cancellation. "
21
+ f"Do you want to cancel job {fine_tune_id}? [y/N]"
22
+ )
23
+ if "y" not in confirm_response.lower():
24
+ click.echo({"status": "Cancel not submitted"})
25
+ return
26
+ response = client.fine_tuning.cancel(fine_tune_id)
27
+
28
+ click.echo(json.dumps(response.model_dump(exclude_none=True), indent=4, default=datetime_serializer))