together 1.5.25__tar.gz → 1.5.26__tar.gz

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 (76) hide show
  1. {together-1.5.25 → together-1.5.26}/PKG-INFO +4 -2
  2. {together-1.5.25 → together-1.5.26}/pyproject.toml +1 -1
  3. {together-1.5.25 → together-1.5.26}/src/together/cli/api/evaluation.py +84 -18
  4. {together-1.5.25 → together-1.5.26}/src/together/cli/api/finetune.py +27 -0
  5. together-1.5.26/src/together/cli/api/models.py +133 -0
  6. {together-1.5.25 → together-1.5.26}/src/together/constants.py +14 -2
  7. {together-1.5.25 → together-1.5.26}/src/together/filemanager.py +230 -5
  8. {together-1.5.25 → together-1.5.26}/src/together/resources/evaluation.py +92 -14
  9. {together-1.5.25 → together-1.5.26}/src/together/resources/files.py +12 -3
  10. {together-1.5.25 → together-1.5.26}/src/together/resources/finetune.py +63 -0
  11. together-1.5.26/src/together/resources/models.py +252 -0
  12. {together-1.5.25 → together-1.5.26}/src/together/types/__init__.py +5 -1
  13. {together-1.5.25 → together-1.5.26}/src/together/types/evaluation.py +7 -3
  14. {together-1.5.25 → together-1.5.26}/src/together/types/files.py +1 -1
  15. {together-1.5.25 → together-1.5.26}/src/together/types/finetune.py +5 -0
  16. together-1.5.26/src/together/types/models.py +95 -0
  17. {together-1.5.25 → together-1.5.26}/src/together/utils/files.py +1 -1
  18. together-1.5.25/src/together/cli/api/models.py +0 -55
  19. together-1.5.25/src/together/resources/models.py +0 -134
  20. together-1.5.25/src/together/types/models.py +0 -46
  21. {together-1.5.25 → together-1.5.26}/LICENSE +0 -0
  22. {together-1.5.25 → together-1.5.26}/README.md +0 -0
  23. {together-1.5.25 → together-1.5.26}/src/together/__init__.py +0 -0
  24. {together-1.5.25 → together-1.5.26}/src/together/abstract/__init__.py +0 -0
  25. {together-1.5.25 → together-1.5.26}/src/together/abstract/api_requestor.py +0 -0
  26. {together-1.5.25 → together-1.5.26}/src/together/cli/__init__.py +0 -0
  27. {together-1.5.25 → together-1.5.26}/src/together/cli/api/__init__.py +0 -0
  28. {together-1.5.25 → together-1.5.26}/src/together/cli/api/chat.py +0 -0
  29. {together-1.5.25 → together-1.5.26}/src/together/cli/api/completions.py +0 -0
  30. {together-1.5.25 → together-1.5.26}/src/together/cli/api/endpoints.py +0 -0
  31. {together-1.5.25 → together-1.5.26}/src/together/cli/api/files.py +0 -0
  32. {together-1.5.25 → together-1.5.26}/src/together/cli/api/images.py +0 -0
  33. {together-1.5.25 → together-1.5.26}/src/together/cli/api/utils.py +0 -0
  34. {together-1.5.25 → together-1.5.26}/src/together/cli/cli.py +0 -0
  35. {together-1.5.25 → together-1.5.26}/src/together/client.py +0 -0
  36. {together-1.5.25 → together-1.5.26}/src/together/error.py +0 -0
  37. {together-1.5.25 → together-1.5.26}/src/together/legacy/__init__.py +0 -0
  38. {together-1.5.25 → together-1.5.26}/src/together/legacy/base.py +0 -0
  39. {together-1.5.25 → together-1.5.26}/src/together/legacy/complete.py +0 -0
  40. {together-1.5.25 → together-1.5.26}/src/together/legacy/embeddings.py +0 -0
  41. {together-1.5.25 → together-1.5.26}/src/together/legacy/files.py +0 -0
  42. {together-1.5.25 → together-1.5.26}/src/together/legacy/finetune.py +0 -0
  43. {together-1.5.25 → together-1.5.26}/src/together/legacy/images.py +0 -0
  44. {together-1.5.25 → together-1.5.26}/src/together/legacy/models.py +0 -0
  45. {together-1.5.25 → together-1.5.26}/src/together/resources/__init__.py +0 -0
  46. {together-1.5.25 → together-1.5.26}/src/together/resources/audio/__init__.py +0 -0
  47. {together-1.5.25 → together-1.5.26}/src/together/resources/audio/speech.py +0 -0
  48. {together-1.5.25 → together-1.5.26}/src/together/resources/audio/transcriptions.py +0 -0
  49. {together-1.5.25 → together-1.5.26}/src/together/resources/audio/translations.py +0 -0
  50. {together-1.5.25 → together-1.5.26}/src/together/resources/batch.py +0 -0
  51. {together-1.5.25 → together-1.5.26}/src/together/resources/chat/__init__.py +0 -0
  52. {together-1.5.25 → together-1.5.26}/src/together/resources/chat/completions.py +0 -0
  53. {together-1.5.25 → together-1.5.26}/src/together/resources/code_interpreter.py +0 -0
  54. {together-1.5.25 → together-1.5.26}/src/together/resources/completions.py +0 -0
  55. {together-1.5.25 → together-1.5.26}/src/together/resources/embeddings.py +0 -0
  56. {together-1.5.25 → together-1.5.26}/src/together/resources/endpoints.py +0 -0
  57. {together-1.5.25 → together-1.5.26}/src/together/resources/images.py +0 -0
  58. {together-1.5.25 → together-1.5.26}/src/together/resources/rerank.py +0 -0
  59. {together-1.5.25 → together-1.5.26}/src/together/together_response.py +0 -0
  60. {together-1.5.25 → together-1.5.26}/src/together/types/abstract.py +0 -0
  61. {together-1.5.25 → together-1.5.26}/src/together/types/audio_speech.py +0 -0
  62. {together-1.5.25 → together-1.5.26}/src/together/types/batch.py +0 -0
  63. {together-1.5.25 → together-1.5.26}/src/together/types/chat_completions.py +0 -0
  64. {together-1.5.25 → together-1.5.26}/src/together/types/code_interpreter.py +0 -0
  65. {together-1.5.25 → together-1.5.26}/src/together/types/common.py +0 -0
  66. {together-1.5.25 → together-1.5.26}/src/together/types/completions.py +0 -0
  67. {together-1.5.25 → together-1.5.26}/src/together/types/embeddings.py +0 -0
  68. {together-1.5.25 → together-1.5.26}/src/together/types/endpoints.py +0 -0
  69. {together-1.5.25 → together-1.5.26}/src/together/types/error.py +0 -0
  70. {together-1.5.25 → together-1.5.26}/src/together/types/images.py +0 -0
  71. {together-1.5.25 → together-1.5.26}/src/together/types/rerank.py +0 -0
  72. {together-1.5.25 → together-1.5.26}/src/together/utils/__init__.py +0 -0
  73. {together-1.5.25 → together-1.5.26}/src/together/utils/_log.py +0 -0
  74. {together-1.5.25 → together-1.5.26}/src/together/utils/api_helpers.py +0 -0
  75. {together-1.5.25 → together-1.5.26}/src/together/utils/tools.py +0 -0
  76. {together-1.5.25 → together-1.5.26}/src/together/version.py +0 -0
@@ -1,8 +1,9 @@
1
- Metadata-Version: 2.3
1
+ Metadata-Version: 2.4
2
2
  Name: together
3
- Version: 1.5.25
3
+ Version: 1.5.26
4
4
  Summary: Python client for Together's Cloud Platform!
5
5
  License: Apache-2.0
6
+ License-File: LICENSE
6
7
  Author: Together AI
7
8
  Author-email: support@together.ai
8
9
  Requires-Python: >=3.10,<4.0
@@ -13,6 +14,7 @@ Classifier: Programming Language :: Python :: 3.10
13
14
  Classifier: Programming Language :: Python :: 3.11
14
15
  Classifier: Programming Language :: Python :: 3.12
15
16
  Classifier: Programming Language :: Python :: 3.13
17
+ Classifier: Programming Language :: Python :: 3.14
16
18
  Provides-Extra: pyarrow
17
19
  Requires-Dist: aiohttp (>=3.9.3,<4.0.0)
18
20
  Requires-Dist: click (>=8.1.7,<9.0.0)
@@ -12,7 +12,7 @@ build-backend = "poetry.masonry.api"
12
12
 
13
13
  [tool.poetry]
14
14
  name = "together"
15
- version = "1.5.25"
15
+ version = "1.5.26"
16
16
  authors = ["Together AI <support@together.ai>"]
17
17
  description = "Python client for Together's Cloud Platform!"
18
18
  readme = "README.md"
@@ -24,10 +24,22 @@ def evaluation(ctx: click.Context) -> None:
24
24
  help="Type of evaluation to create.",
25
25
  )
26
26
  @click.option(
27
- "--judge-model-name",
27
+ "--judge-model",
28
28
  type=str,
29
29
  required=True,
30
- help="Name of the judge model to use for evaluation.",
30
+ help="Name or URL of the judge model to use for evaluation.",
31
+ )
32
+ @click.option(
33
+ "--judge-model-source",
34
+ type=click.Choice(["serverless", "dedicated", "external"]),
35
+ required=True,
36
+ help="Source of the judge model.",
37
+ )
38
+ @click.option(
39
+ "--judge-external-api-token",
40
+ type=str,
41
+ required=False,
42
+ help="Optional external API token for the judge model.",
31
43
  )
32
44
  @click.option(
33
45
  "--judge-system-template",
@@ -48,10 +60,20 @@ def evaluation(ctx: click.Context) -> None:
48
60
  "Can not be used when model-a-name and other model config parameters are specified",
49
61
  )
50
62
  @click.option(
51
- "--model-to-evaluate-name",
63
+ "--model-to-evaluate",
52
64
  type=str,
53
65
  help="Model name when using the detailed config",
54
66
  )
67
+ @click.option(
68
+ "--model-to-evaluate-source",
69
+ type=click.Choice(["serverless", "dedicated", "external"]),
70
+ help="Source of the model to evaluate.",
71
+ )
72
+ @click.option(
73
+ "--model-to-evaluate-external-api-token",
74
+ type=str,
75
+ help="Optional external API token for the model to evaluate.",
76
+ )
55
77
  @click.option(
56
78
  "--model-to-evaluate-max-tokens",
57
79
  type=int,
@@ -104,9 +126,19 @@ def evaluation(ctx: click.Context) -> None:
104
126
  Can not be used when model-a-name and other model config parameters are specified",
105
127
  )
106
128
  @click.option(
107
- "--model-a-name",
129
+ "--model-a",
108
130
  type=str,
109
- help="Model name for model A when using detailed config.",
131
+ help="Model name or URL for model A when using detailed config.",
132
+ )
133
+ @click.option(
134
+ "--model-a-source",
135
+ type=click.Choice(["serverless", "dedicated", "external"]),
136
+ help="Source of model A.",
137
+ )
138
+ @click.option(
139
+ "--model-a-external-api-token",
140
+ type=str,
141
+ help="Optional external API token for model A.",
110
142
  )
111
143
  @click.option(
112
144
  "--model-a-max-tokens",
@@ -135,9 +167,19 @@ def evaluation(ctx: click.Context) -> None:
135
167
  Can not be used when model-b-name and other model config parameters are specified",
136
168
  )
137
169
  @click.option(
138
- "--model-b-name",
170
+ "--model-b",
139
171
  type=str,
140
- help="Model name for model B when using detailed config.",
172
+ help="Model name or URL for model B when using detailed config.",
173
+ )
174
+ @click.option(
175
+ "--model-b-source",
176
+ type=click.Choice(["serverless", "dedicated", "external"]),
177
+ help="Source of model B.",
178
+ )
179
+ @click.option(
180
+ "--model-b-external-api-token",
181
+ type=str,
182
+ help="Optional external API token for model B.",
141
183
  )
142
184
  @click.option(
143
185
  "--model-b-max-tokens",
@@ -162,11 +204,15 @@ def evaluation(ctx: click.Context) -> None:
162
204
  def create(
163
205
  ctx: click.Context,
164
206
  type: str,
165
- judge_model_name: str,
207
+ judge_model: str,
208
+ judge_model_source: str,
166
209
  judge_system_template: str,
210
+ judge_external_api_token: Optional[str],
167
211
  input_data_file_path: str,
168
212
  model_field: Optional[str],
169
- model_to_evaluate_name: Optional[str],
213
+ model_to_evaluate: Optional[str],
214
+ model_to_evaluate_source: Optional[str],
215
+ model_to_evaluate_external_api_token: Optional[str],
170
216
  model_to_evaluate_max_tokens: Optional[int],
171
217
  model_to_evaluate_temperature: Optional[float],
172
218
  model_to_evaluate_system_template: Optional[str],
@@ -177,13 +223,17 @@ def create(
177
223
  max_score: Optional[float],
178
224
  pass_threshold: Optional[float],
179
225
  model_a_field: Optional[str],
180
- model_a_name: Optional[str],
226
+ model_a: Optional[str],
227
+ model_a_source: Optional[str],
228
+ model_a_external_api_token: Optional[str],
181
229
  model_a_max_tokens: Optional[int],
182
230
  model_a_temperature: Optional[float],
183
231
  model_a_system_template: Optional[str],
184
232
  model_a_input_template: Optional[str],
185
233
  model_b_field: Optional[str],
186
- model_b_name: Optional[str],
234
+ model_b: Optional[str],
235
+ model_b_source: Optional[str],
236
+ model_b_external_api_token: Optional[str],
187
237
  model_b_max_tokens: Optional[int],
188
238
  model_b_temperature: Optional[float],
189
239
  model_b_system_template: Optional[str],
@@ -203,7 +253,8 @@ def create(
203
253
  # Check if any config parameters are provided
204
254
  config_params_provided = any(
205
255
  [
206
- model_to_evaluate_name,
256
+ model_to_evaluate,
257
+ model_to_evaluate_source,
207
258
  model_to_evaluate_max_tokens,
208
259
  model_to_evaluate_temperature,
209
260
  model_to_evaluate_system_template,
@@ -223,17 +274,23 @@ def create(
223
274
  elif config_params_provided:
224
275
  # Config mode: config parameters are provided
225
276
  model_to_evaluate_final = {
226
- "model_name": model_to_evaluate_name,
277
+ "model": model_to_evaluate,
278
+ "model_source": model_to_evaluate_source,
227
279
  "max_tokens": model_to_evaluate_max_tokens,
228
280
  "temperature": model_to_evaluate_temperature,
229
281
  "system_template": model_to_evaluate_system_template,
230
282
  "input_template": model_to_evaluate_input_template,
231
283
  }
284
+ if model_to_evaluate_external_api_token:
285
+ model_to_evaluate_final["external_api_token"] = (
286
+ model_to_evaluate_external_api_token
287
+ )
232
288
 
233
289
  # Build model-a configuration
234
290
  model_a_final: Union[Dict[str, Any], None, str] = None
235
291
  model_a_config_params = [
236
- model_a_name,
292
+ model_a,
293
+ model_a_source,
237
294
  model_a_max_tokens,
238
295
  model_a_temperature,
239
296
  model_a_system_template,
@@ -252,17 +309,21 @@ def create(
252
309
  elif any(model_a_config_params):
253
310
  # Config mode: config parameters are provided
254
311
  model_a_final = {
255
- "model_name": model_a_name,
312
+ "model": model_a,
313
+ "model_source": model_a_source,
256
314
  "max_tokens": model_a_max_tokens,
257
315
  "temperature": model_a_temperature,
258
316
  "system_template": model_a_system_template,
259
317
  "input_template": model_a_input_template,
260
318
  }
319
+ if model_a_external_api_token:
320
+ model_a_final["external_api_token"] = model_a_external_api_token
261
321
 
262
322
  # Build model-b configuration
263
323
  model_b_final: Union[Dict[str, Any], None, str] = None
264
324
  model_b_config_params = [
265
- model_b_name,
325
+ model_b,
326
+ model_b_source,
266
327
  model_b_max_tokens,
267
328
  model_b_temperature,
268
329
  model_b_system_template,
@@ -281,18 +342,23 @@ def create(
281
342
  elif any(model_b_config_params):
282
343
  # Config mode: config parameters are provided
283
344
  model_b_final = {
284
- "model_name": model_b_name,
345
+ "model": model_b,
346
+ "model_source": model_b_source,
285
347
  "max_tokens": model_b_max_tokens,
286
348
  "temperature": model_b_temperature,
287
349
  "system_template": model_b_system_template,
288
350
  "input_template": model_b_input_template,
289
351
  }
352
+ if model_b_external_api_token:
353
+ model_b_final["external_api_token"] = model_b_external_api_token
290
354
 
291
355
  try:
292
356
  response = client.evaluation.create(
293
357
  type=type,
294
- judge_model_name=judge_model_name,
358
+ judge_model=judge_model,
359
+ judge_model_source=judge_model_source,
295
360
  judge_system_template=judge_system_template,
361
+ judge_external_api_token=judge_external_api_token,
296
362
  input_data_file_path=input_data_file_path,
297
363
  model_to_evaluate=model_to_evaluate_final,
298
364
  labels=labels_list,
@@ -543,3 +543,30 @@ def download(
543
543
  )
544
544
 
545
545
  click.echo(json.dumps(response.model_dump(exclude_none=True), indent=4))
546
+
547
+
548
+ @fine_tuning.command()
549
+ @click.pass_context
550
+ @click.argument("fine_tune_id", type=str, required=True)
551
+ @click.option("--force", is_flag=True, help="Force deletion without confirmation")
552
+ @click.option(
553
+ "--quiet", is_flag=True, help="Do not prompt for confirmation before deleting job"
554
+ )
555
+ def delete(
556
+ ctx: click.Context, fine_tune_id: str, force: bool = False, quiet: bool = False
557
+ ) -> None:
558
+ """Delete fine-tuning job"""
559
+ client: Together = ctx.obj
560
+
561
+ if not quiet:
562
+ confirm_response = input(
563
+ f"Are you sure you want to delete fine-tuning job {fine_tune_id}? "
564
+ "This action cannot be undone. [y/N] "
565
+ )
566
+ if confirm_response.lower() != "y":
567
+ click.echo("Deletion cancelled")
568
+ return
569
+
570
+ response = client.fine_tuning.delete(fine_tune_id, force=force)
571
+
572
+ click.echo(json.dumps(response.model_dump(exclude_none=True), indent=4))
@@ -0,0 +1,133 @@
1
+ import json as json_lib
2
+
3
+ import click
4
+ from tabulate import tabulate
5
+
6
+ from together import Together
7
+ from together.types.models import ModelObject, ModelUploadResponse
8
+
9
+
10
+ @click.group()
11
+ @click.pass_context
12
+ def models(ctx: click.Context) -> None:
13
+ """Models API commands"""
14
+ pass
15
+
16
+
17
+ @models.command()
18
+ @click.option(
19
+ "--type",
20
+ type=click.Choice(["dedicated"]),
21
+ help="Filter models by type (dedicated: models that can be deployed as dedicated endpoints)",
22
+ )
23
+ @click.option(
24
+ "--json",
25
+ is_flag=True,
26
+ help="Output in JSON format",
27
+ )
28
+ @click.pass_context
29
+ def list(ctx: click.Context, type: str | None, json: bool) -> None:
30
+ """List models"""
31
+ client: Together = ctx.obj
32
+
33
+ response = client.models.list(dedicated=(type == "dedicated"))
34
+
35
+ display_list = []
36
+
37
+ model: ModelObject
38
+ for model in response:
39
+ display_list.append(
40
+ {
41
+ "ID": model.id,
42
+ "Name": model.display_name,
43
+ "Organization": model.organization,
44
+ "Type": model.type,
45
+ "Context Length": model.context_length,
46
+ "License": model.license,
47
+ "Input per 1M token": model.pricing.input,
48
+ "Output per 1M token": model.pricing.output,
49
+ }
50
+ )
51
+
52
+ if json:
53
+ click.echo(json_lib.dumps(display_list, indent=2))
54
+ else:
55
+ click.echo(tabulate(display_list, headers="keys", tablefmt="plain"))
56
+
57
+
58
+ @models.command()
59
+ @click.option(
60
+ "--model-name",
61
+ required=True,
62
+ help="The name to give to your uploaded model",
63
+ )
64
+ @click.option(
65
+ "--model-source",
66
+ required=True,
67
+ help="The source location of the model (Hugging Face repo or S3 path)",
68
+ )
69
+ @click.option(
70
+ "--model-type",
71
+ type=click.Choice(["model", "adapter"]),
72
+ default="model",
73
+ help="Whether the model is a full model or an adapter",
74
+ )
75
+ @click.option(
76
+ "--hf-token",
77
+ help="Hugging Face token (if uploading from Hugging Face)",
78
+ )
79
+ @click.option(
80
+ "--description",
81
+ help="A description of your model",
82
+ )
83
+ @click.option(
84
+ "--base-model",
85
+ help="The base model to use for an adapter if setting it to run against a serverless pool. Only used for model_type 'adapter'.",
86
+ )
87
+ @click.option(
88
+ "--lora-model",
89
+ help="The lora pool to use for an adapter if setting it to run against, say, a dedicated pool. Only used for model_type 'adapter'.",
90
+ )
91
+ @click.option(
92
+ "--json",
93
+ is_flag=True,
94
+ help="Output in JSON format",
95
+ )
96
+ @click.pass_context
97
+ def upload(
98
+ ctx: click.Context,
99
+ model_name: str,
100
+ model_source: str,
101
+ model_type: str,
102
+ hf_token: str | None,
103
+ description: str | None,
104
+ base_model: str | None,
105
+ lora_model: str | None,
106
+ json: bool,
107
+ ) -> None:
108
+ """Upload a custom model or adapter from Hugging Face or S3"""
109
+ client: Together = ctx.obj
110
+
111
+ response: ModelUploadResponse = client.models.upload(
112
+ model_name=model_name,
113
+ model_source=model_source,
114
+ model_type=model_type,
115
+ hf_token=hf_token,
116
+ description=description,
117
+ base_model=base_model,
118
+ lora_model=lora_model,
119
+ )
120
+
121
+ if json:
122
+ click.echo(json_lib.dumps(response.model_dump(), indent=2))
123
+ else:
124
+ click.echo(f"Model upload job created successfully!")
125
+ if response.job_id:
126
+ click.echo(f"Job ID: {response.job_id}")
127
+ if response.model_name:
128
+ click.echo(f"Model Name: {response.model_name}")
129
+ if response.model_id:
130
+ click.echo(f"Model ID: {response.model_id}")
131
+ if response.model_source:
132
+ click.echo(f"Model Source: {response.model_source}")
133
+ click.echo(f"Message: {response.message}")
@@ -15,6 +15,20 @@ BASE_URL = "https://api.together.xyz/v1"
15
15
  DOWNLOAD_BLOCK_SIZE = 10 * 1024 * 1024 # 10 MB
16
16
  DISABLE_TQDM = False
17
17
 
18
+ # Upload defaults
19
+ MAX_CONCURRENT_PARTS = 4 # Maximum concurrent parts for multipart upload
20
+
21
+ # Multipart upload constants
22
+ MIN_PART_SIZE_MB = 5 # Minimum part size (S3 requirement)
23
+ TARGET_PART_SIZE_MB = 100 # Target part size for optimal performance
24
+ MAX_MULTIPART_PARTS = 250 # Maximum parts per upload (S3 limit)
25
+ MULTIPART_UPLOAD_TIMEOUT = 300 # Timeout in seconds for uploading each part
26
+ MULTIPART_THRESHOLD_GB = 5.0 # threshold for switching to multipart upload
27
+
28
+ # maximum number of GB sized files we support finetuning for
29
+ MAX_FILE_SIZE_GB = 25.0
30
+
31
+
18
32
  # Messages
19
33
  MISSING_API_KEY_MESSAGE = """TOGETHER_API_KEY not found.
20
34
  Please set it as an environment variable or set it as together.api_key
@@ -26,8 +40,6 @@ MIN_SAMPLES = 1
26
40
  # the number of bytes in a gigabyte, used to convert bytes to GB for readable comparison
27
41
  NUM_BYTES_IN_GB = 2**30
28
42
 
29
- # maximum number of GB sized files we support finetuning for
30
- MAX_FILE_SIZE_GB = 4.9
31
43
 
32
44
  # expected columns for Parquet files
33
45
  PARQUET_EXPECTED_COLUMNS = ["input_ids", "attention_mask", "labels"]