From c533f29e2b94d5d9ca97ed50c181dae0fc2dcd7b Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 19 Nov 2025 19:31:32 +0000 Subject: [PATCH 1/8] chore(api): Remove auto-generated fine_tuning.create method from Python SDK --- .stats.yml | 4 +- api.md | 2 - src/together/resources/fine_tuning.py | 315 +----------------- src/together/types/__init__.py | 9 - .../types/cosine_lr_scheduler_args_param.py | 15 - .../types/fine_tuning_create_params.py | 133 -------- .../types/fine_tuning_create_response.py | 121 ------- .../types/full_training_type_param.py | 11 - .../types/linear_lr_scheduler_args_param.py | 12 - .../types/lo_ra_training_type_param.py | 19 -- src/together/types/lr_scheduler_param.py | 19 -- .../types/training_method_dpo_param.py | 21 -- .../types/training_method_sft_param.py | 18 - tests/api_resources/test_fine_tuning.py | 143 -------- 14 files changed, 3 insertions(+), 839 deletions(-) delete mode 100644 src/together/types/cosine_lr_scheduler_args_param.py delete mode 100644 src/together/types/fine_tuning_create_params.py delete mode 100644 src/together/types/fine_tuning_create_response.py delete mode 100644 src/together/types/full_training_type_param.py delete mode 100644 src/together/types/linear_lr_scheduler_args_param.py delete mode 100644 src/together/types/lo_ra_training_type_param.py delete mode 100644 src/together/types/lr_scheduler_param.py delete mode 100644 src/together/types/training_method_dpo_param.py delete mode 100644 src/together/types/training_method_sft_param.py diff --git a/.stats.yml b/.stats.yml index 4a805cee..ae76cfce 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 45 +configured_endpoints: 44 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/togetherai%2Ftogetherai-57c68db188c5a4e69e16f99e7e4968f08f2dbf64e7e7d8f57f54f84669305189.yml openapi_spec_hash: 4e707463a416fd079a6beeff1d1beecb -config_hash: 566058c6cddd3fb076ade46bc5e78274 +config_hash: ff6223e5c6a73b836f4d70ea6d1f385f diff --git a/api.md b/api.md index 097dbf58..e4fa10a3 100644 --- a/api.md +++ b/api.md @@ -93,7 +93,6 @@ from together.types import ( LrScheduler, TrainingMethodDpo, TrainingMethodSft, - FineTuningCreateResponse, FineTuningListResponse, FineTuningDeleteResponse, FineTuningCancelResponse, @@ -104,7 +103,6 @@ from together.types import ( Methods: -- client.fine_tuning.create(\*\*params) -> FineTuningCreateResponse - client.fine_tuning.retrieve(id) -> FineTune - client.fine_tuning.list() -> FineTuningListResponse - client.fine_tuning.delete(id, \*\*params) -> FineTuningDeleteResponse diff --git a/src/together/resources/fine_tuning.py b/src/together/resources/fine_tuning.py index 19ad2039..49e22f28 100644 --- a/src/together/resources/fine_tuning.py +++ b/src/together/resources/fine_tuning.py @@ -2,12 +2,11 @@ from __future__ import annotations -from typing import Union from typing_extensions import Literal import httpx -from ..types import fine_tuning_create_params, fine_tuning_delete_params, fine_tuning_download_params +from ..types import fine_tuning_delete_params, fine_tuning_download_params from .._types import Body, Omit, Query, Headers, NotGiven, omit, not_given from .._utils import maybe_transform, async_maybe_transform from .._compat import cached_property @@ -28,10 +27,8 @@ ) from .._base_client import make_request_options from ..types.fine_tune import FineTune -from ..types.lr_scheduler_param import LrSchedulerParam from ..types.fine_tuning_list_response import FineTuningListResponse from ..types.fine_tuning_cancel_response import FineTuningCancelResponse -from ..types.fine_tuning_create_response import FineTuningCreateResponse from ..types.fine_tuning_delete_response import FineTuningDeleteResponse from ..types.fine_tuning_list_events_response import FineTuningListEventsResponse from ..types.fine_tuning_list_checkpoints_response import FineTuningListCheckpointsResponse @@ -59,155 +56,6 @@ def with_streaming_response(self) -> FineTuningResourceWithStreamingResponse: """ return FineTuningResourceWithStreamingResponse(self) - def create( - self, - *, - model: str, - training_file: str, - batch_size: Union[int, Literal["max"]] | Omit = omit, - from_checkpoint: str | Omit = omit, - from_hf_model: str | Omit = omit, - hf_api_token: str | Omit = omit, - hf_model_revision: str | Omit = omit, - hf_output_repo_name: str | Omit = omit, - learning_rate: float | Omit = omit, - lr_scheduler: LrSchedulerParam | Omit = omit, - max_grad_norm: float | Omit = omit, - n_checkpoints: int | Omit = omit, - n_epochs: int | Omit = omit, - n_evals: int | Omit = omit, - suffix: str | Omit = omit, - train_on_inputs: Union[bool, Literal["auto"]] | Omit = omit, - training_method: fine_tuning_create_params.TrainingMethod | Omit = omit, - training_type: fine_tuning_create_params.TrainingType | Omit = omit, - validation_file: str | Omit = omit, - wandb_api_key: str | Omit = omit, - wandb_base_url: str | Omit = omit, - wandb_name: str | Omit = omit, - wandb_project_name: str | Omit = omit, - warmup_ratio: float | Omit = omit, - weight_decay: float | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> FineTuningCreateResponse: - """ - Create a fine-tuning job with the provided model and training data. - - Args: - model: Name of the base model to run fine-tune job on - - training_file: File-ID of a training file uploaded to the Together API - - batch_size: Number of training examples processed together (larger batches use more memory - but may train faster). Defaults to "max". We use training optimizations like - packing, so the effective batch size may be different than the value you set. - - from_checkpoint: The checkpoint identifier to continue training from a previous fine-tuning job. - Format is `{$JOB_ID}` or `{$OUTPUT_MODEL_NAME}` or `{$JOB_ID}:{$STEP}` or - `{$OUTPUT_MODEL_NAME}:{$STEP}`. The step value is optional; without it, the - final checkpoint will be used. - - from_hf_model: The Hugging Face Hub repo to start training from. Should be as close as possible - to the base model (specified by the `model` argument) in terms of architecture - and size. - - hf_api_token: The API token for the Hugging Face Hub. - - hf_model_revision: The revision of the Hugging Face Hub model to continue training from. E.g., - hf_model_revision=main (default, used if the argument is not provided) or - hf_model_revision='607a30d783dfa663caf39e06633721c8d4cfcd7e' (specific commit). - - hf_output_repo_name: The name of the Hugging Face repository to upload the fine-tuned model to. - - learning_rate: Controls how quickly the model adapts to new information (too high may cause - instability, too low may slow convergence) - - lr_scheduler: The learning rate scheduler to use. It specifies how the learning rate is - adjusted during training. - - max_grad_norm: Max gradient norm to be used for gradient clipping. Set to 0 to disable. - - n_checkpoints: Number of intermediate model versions saved during training for evaluation - - n_epochs: Number of complete passes through the training dataset (higher values may - improve results but increase cost and risk of overfitting) - - n_evals: Number of evaluations to be run on a given validation set during training - - suffix: Suffix that will be added to your fine-tuned model name - - train_on_inputs: Whether to mask the user messages in conversational data or prompts in - instruction data. - - training_method: The training method to use. 'sft' for Supervised Fine-Tuning or 'dpo' for Direct - Preference Optimization. - - validation_file: File-ID of a validation file uploaded to the Together API - - wandb_api_key: Integration key for tracking experiments and model metrics on W&B platform - - wandb_base_url: The base URL of a dedicated Weights & Biases instance. - - wandb_name: The Weights & Biases name for your run. - - wandb_project_name: The Weights & Biases project for your run. If not specified, will use `together` - as the project name. - - warmup_ratio: The percent of steps at the start of training to linearly increase the learning - rate. - - weight_decay: Weight decay. Regularization parameter for the optimizer. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/fine-tunes", - body=maybe_transform( - { - "model": model, - "training_file": training_file, - "batch_size": batch_size, - "from_checkpoint": from_checkpoint, - "from_hf_model": from_hf_model, - "hf_api_token": hf_api_token, - "hf_model_revision": hf_model_revision, - "hf_output_repo_name": hf_output_repo_name, - "learning_rate": learning_rate, - "lr_scheduler": lr_scheduler, - "max_grad_norm": max_grad_norm, - "n_checkpoints": n_checkpoints, - "n_epochs": n_epochs, - "n_evals": n_evals, - "suffix": suffix, - "train_on_inputs": train_on_inputs, - "training_method": training_method, - "training_type": training_type, - "validation_file": validation_file, - "wandb_api_key": wandb_api_key, - "wandb_base_url": wandb_base_url, - "wandb_name": wandb_name, - "wandb_project_name": wandb_project_name, - "warmup_ratio": warmup_ratio, - "weight_decay": weight_decay, - }, - fine_tuning_create_params.FineTuningCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=FineTuningCreateResponse, - ) - def retrieve( self, id: str, @@ -477,155 +325,6 @@ def with_streaming_response(self) -> AsyncFineTuningResourceWithStreamingRespons """ return AsyncFineTuningResourceWithStreamingResponse(self) - async def create( - self, - *, - model: str, - training_file: str, - batch_size: Union[int, Literal["max"]] | Omit = omit, - from_checkpoint: str | Omit = omit, - from_hf_model: str | Omit = omit, - hf_api_token: str | Omit = omit, - hf_model_revision: str | Omit = omit, - hf_output_repo_name: str | Omit = omit, - learning_rate: float | Omit = omit, - lr_scheduler: LrSchedulerParam | Omit = omit, - max_grad_norm: float | Omit = omit, - n_checkpoints: int | Omit = omit, - n_epochs: int | Omit = omit, - n_evals: int | Omit = omit, - suffix: str | Omit = omit, - train_on_inputs: Union[bool, Literal["auto"]] | Omit = omit, - training_method: fine_tuning_create_params.TrainingMethod | Omit = omit, - training_type: fine_tuning_create_params.TrainingType | Omit = omit, - validation_file: str | Omit = omit, - wandb_api_key: str | Omit = omit, - wandb_base_url: str | Omit = omit, - wandb_name: str | Omit = omit, - wandb_project_name: str | Omit = omit, - warmup_ratio: float | Omit = omit, - weight_decay: float | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> FineTuningCreateResponse: - """ - Create a fine-tuning job with the provided model and training data. - - Args: - model: Name of the base model to run fine-tune job on - - training_file: File-ID of a training file uploaded to the Together API - - batch_size: Number of training examples processed together (larger batches use more memory - but may train faster). Defaults to "max". We use training optimizations like - packing, so the effective batch size may be different than the value you set. - - from_checkpoint: The checkpoint identifier to continue training from a previous fine-tuning job. - Format is `{$JOB_ID}` or `{$OUTPUT_MODEL_NAME}` or `{$JOB_ID}:{$STEP}` or - `{$OUTPUT_MODEL_NAME}:{$STEP}`. The step value is optional; without it, the - final checkpoint will be used. - - from_hf_model: The Hugging Face Hub repo to start training from. Should be as close as possible - to the base model (specified by the `model` argument) in terms of architecture - and size. - - hf_api_token: The API token for the Hugging Face Hub. - - hf_model_revision: The revision of the Hugging Face Hub model to continue training from. E.g., - hf_model_revision=main (default, used if the argument is not provided) or - hf_model_revision='607a30d783dfa663caf39e06633721c8d4cfcd7e' (specific commit). - - hf_output_repo_name: The name of the Hugging Face repository to upload the fine-tuned model to. - - learning_rate: Controls how quickly the model adapts to new information (too high may cause - instability, too low may slow convergence) - - lr_scheduler: The learning rate scheduler to use. It specifies how the learning rate is - adjusted during training. - - max_grad_norm: Max gradient norm to be used for gradient clipping. Set to 0 to disable. - - n_checkpoints: Number of intermediate model versions saved during training for evaluation - - n_epochs: Number of complete passes through the training dataset (higher values may - improve results but increase cost and risk of overfitting) - - n_evals: Number of evaluations to be run on a given validation set during training - - suffix: Suffix that will be added to your fine-tuned model name - - train_on_inputs: Whether to mask the user messages in conversational data or prompts in - instruction data. - - training_method: The training method to use. 'sft' for Supervised Fine-Tuning or 'dpo' for Direct - Preference Optimization. - - validation_file: File-ID of a validation file uploaded to the Together API - - wandb_api_key: Integration key for tracking experiments and model metrics on W&B platform - - wandb_base_url: The base URL of a dedicated Weights & Biases instance. - - wandb_name: The Weights & Biases name for your run. - - wandb_project_name: The Weights & Biases project for your run. If not specified, will use `together` - as the project name. - - warmup_ratio: The percent of steps at the start of training to linearly increase the learning - rate. - - weight_decay: Weight decay. Regularization parameter for the optimizer. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/fine-tunes", - body=await async_maybe_transform( - { - "model": model, - "training_file": training_file, - "batch_size": batch_size, - "from_checkpoint": from_checkpoint, - "from_hf_model": from_hf_model, - "hf_api_token": hf_api_token, - "hf_model_revision": hf_model_revision, - "hf_output_repo_name": hf_output_repo_name, - "learning_rate": learning_rate, - "lr_scheduler": lr_scheduler, - "max_grad_norm": max_grad_norm, - "n_checkpoints": n_checkpoints, - "n_epochs": n_epochs, - "n_evals": n_evals, - "suffix": suffix, - "train_on_inputs": train_on_inputs, - "training_method": training_method, - "training_type": training_type, - "validation_file": validation_file, - "wandb_api_key": wandb_api_key, - "wandb_base_url": wandb_base_url, - "wandb_name": wandb_name, - "wandb_project_name": wandb_project_name, - "warmup_ratio": warmup_ratio, - "weight_decay": weight_decay, - }, - fine_tuning_create_params.FineTuningCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=FineTuningCreateResponse, - ) - async def retrieve( self, id: str, @@ -879,9 +578,6 @@ class FineTuningResourceWithRawResponse: def __init__(self, fine_tuning: FineTuningResource) -> None: self._fine_tuning = fine_tuning - self.create = to_raw_response_wrapper( - fine_tuning.create, - ) self.retrieve = to_raw_response_wrapper( fine_tuning.retrieve, ) @@ -910,9 +606,6 @@ class AsyncFineTuningResourceWithRawResponse: def __init__(self, fine_tuning: AsyncFineTuningResource) -> None: self._fine_tuning = fine_tuning - self.create = async_to_raw_response_wrapper( - fine_tuning.create, - ) self.retrieve = async_to_raw_response_wrapper( fine_tuning.retrieve, ) @@ -941,9 +634,6 @@ class FineTuningResourceWithStreamingResponse: def __init__(self, fine_tuning: FineTuningResource) -> None: self._fine_tuning = fine_tuning - self.create = to_streamed_response_wrapper( - fine_tuning.create, - ) self.retrieve = to_streamed_response_wrapper( fine_tuning.retrieve, ) @@ -972,9 +662,6 @@ class AsyncFineTuningResourceWithStreamingResponse: def __init__(self, fine_tuning: AsyncFineTuningResource) -> None: self._fine_tuning = fine_tuning - self.create = async_to_streamed_response_wrapper( - fine_tuning.create, - ) self.retrieve = async_to_streamed_response_wrapper( fine_tuning.retrieve, ) diff --git a/src/together/types/__init__.py b/src/together/types/__init__.py index 47e5c9c5..2c2c7c39 100644 --- a/src/together/types/__init__.py +++ b/src/together/types/__init__.py @@ -31,7 +31,6 @@ from .eval_update_params import EvalUpdateParams as EvalUpdateParams from .file_list_response import FileListResponse as FileListResponse from .full_training_type import FullTrainingType as FullTrainingType -from .lr_scheduler_param import LrSchedulerParam as LrSchedulerParam from .audio_create_params import AudioCreateParams as AudioCreateParams from .batch_create_params import BatchCreateParams as BatchCreateParams from .batch_list_response import BatchListResponse as BatchListResponse @@ -63,22 +62,14 @@ from .embedding_create_params import EmbeddingCreateParams as EmbeddingCreateParams from .completion_create_params import CompletionCreateParams as CompletionCreateParams from .cosine_lr_scheduler_args import CosineLrSchedulerArgs as CosineLrSchedulerArgs -from .full_training_type_param import FullTrainingTypeParam as FullTrainingTypeParam from .linear_lr_scheduler_args import LinearLrSchedulerArgs as LinearLrSchedulerArgs from .audio_speech_stream_chunk import AudioSpeechStreamChunk as AudioSpeechStreamChunk -from .fine_tuning_create_params import FineTuningCreateParams as FineTuningCreateParams from .fine_tuning_delete_params import FineTuningDeleteParams as FineTuningDeleteParams from .fine_tuning_list_response import FineTuningListResponse as FineTuningListResponse -from .lo_ra_training_type_param import LoRaTrainingTypeParam as LoRaTrainingTypeParam -from .training_method_dpo_param import TrainingMethodDpoParam as TrainingMethodDpoParam -from .training_method_sft_param import TrainingMethodSftParam as TrainingMethodSftParam from .fine_tuning_cancel_response import FineTuningCancelResponse as FineTuningCancelResponse -from .fine_tuning_create_response import FineTuningCreateResponse as FineTuningCreateResponse from .fine_tuning_delete_response import FineTuningDeleteResponse as FineTuningDeleteResponse from .fine_tuning_download_params import FineTuningDownloadParams as FineTuningDownloadParams -from .cosine_lr_scheduler_args_param import CosineLrSchedulerArgsParam as CosineLrSchedulerArgsParam from .endpoint_list_avzones_response import EndpointListAvzonesResponse as EndpointListAvzonesResponse -from .linear_lr_scheduler_args_param import LinearLrSchedulerArgsParam as LinearLrSchedulerArgsParam from .code_interpreter_execute_params import CodeInterpreterExecuteParams as CodeInterpreterExecuteParams from .fine_tuning_list_events_response import FineTuningListEventsResponse as FineTuningListEventsResponse from .fine_tuning_list_checkpoints_response import ( diff --git a/src/together/types/cosine_lr_scheduler_args_param.py b/src/together/types/cosine_lr_scheduler_args_param.py deleted file mode 100644 index 73758e6b..00000000 --- a/src/together/types/cosine_lr_scheduler_args_param.py +++ /dev/null @@ -1,15 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Required, TypedDict - -__all__ = ["CosineLrSchedulerArgsParam"] - - -class CosineLrSchedulerArgsParam(TypedDict, total=False): - min_lr_ratio: Required[float] - """The ratio of the final learning rate to the peak learning rate""" - - num_cycles: Required[float] - """Number or fraction of cycles for the cosine learning rate scheduler""" diff --git a/src/together/types/fine_tuning_create_params.py b/src/together/types/fine_tuning_create_params.py deleted file mode 100644 index 2f34eb24..00000000 --- a/src/together/types/fine_tuning_create_params.py +++ /dev/null @@ -1,133 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from typing_extensions import Literal, Required, TypeAlias, TypedDict - -from .lr_scheduler_param import LrSchedulerParam -from .full_training_type_param import FullTrainingTypeParam -from .lo_ra_training_type_param import LoRaTrainingTypeParam -from .training_method_dpo_param import TrainingMethodDpoParam -from .training_method_sft_param import TrainingMethodSftParam - -__all__ = ["FineTuningCreateParams", "TrainingMethod", "TrainingType"] - - -class FineTuningCreateParams(TypedDict, total=False): - model: Required[str] - """Name of the base model to run fine-tune job on""" - - training_file: Required[str] - """File-ID of a training file uploaded to the Together API""" - - batch_size: Union[int, Literal["max"]] - """ - Number of training examples processed together (larger batches use more memory - but may train faster). Defaults to "max". We use training optimizations like - packing, so the effective batch size may be different than the value you set. - """ - - from_checkpoint: str - """The checkpoint identifier to continue training from a previous fine-tuning job. - - Format is `{$JOB_ID}` or `{$OUTPUT_MODEL_NAME}` or `{$JOB_ID}:{$STEP}` or - `{$OUTPUT_MODEL_NAME}:{$STEP}`. The step value is optional; without it, the - final checkpoint will be used. - """ - - from_hf_model: str - """The Hugging Face Hub repo to start training from. - - Should be as close as possible to the base model (specified by the `model` - argument) in terms of architecture and size. - """ - - hf_api_token: str - """The API token for the Hugging Face Hub.""" - - hf_model_revision: str - """The revision of the Hugging Face Hub model to continue training from. - - E.g., hf_model_revision=main (default, used if the argument is not provided) or - hf_model_revision='607a30d783dfa663caf39e06633721c8d4cfcd7e' (specific commit). - """ - - hf_output_repo_name: str - """The name of the Hugging Face repository to upload the fine-tuned model to.""" - - learning_rate: float - """ - Controls how quickly the model adapts to new information (too high may cause - instability, too low may slow convergence) - """ - - lr_scheduler: LrSchedulerParam - """The learning rate scheduler to use. - - It specifies how the learning rate is adjusted during training. - """ - - max_grad_norm: float - """Max gradient norm to be used for gradient clipping. Set to 0 to disable.""" - - n_checkpoints: int - """Number of intermediate model versions saved during training for evaluation""" - - n_epochs: int - """ - Number of complete passes through the training dataset (higher values may - improve results but increase cost and risk of overfitting) - """ - - n_evals: int - """Number of evaluations to be run on a given validation set during training""" - - suffix: str - """Suffix that will be added to your fine-tuned model name""" - - train_on_inputs: Union[bool, Literal["auto"]] - """ - Whether to mask the user messages in conversational data or prompts in - instruction data. - """ - - training_method: TrainingMethod - """The training method to use. - - 'sft' for Supervised Fine-Tuning or 'dpo' for Direct Preference Optimization. - """ - - training_type: TrainingType - - validation_file: str - """File-ID of a validation file uploaded to the Together API""" - - wandb_api_key: str - """Integration key for tracking experiments and model metrics on W&B platform""" - - wandb_base_url: str - """The base URL of a dedicated Weights & Biases instance.""" - - wandb_name: str - """The Weights & Biases name for your run.""" - - wandb_project_name: str - """The Weights & Biases project for your run. - - If not specified, will use `together` as the project name. - """ - - warmup_ratio: float - """ - The percent of steps at the start of training to linearly increase the learning - rate. - """ - - weight_decay: float - """Weight decay. Regularization parameter for the optimizer.""" - - -TrainingMethod: TypeAlias = Union[TrainingMethodSftParam, TrainingMethodDpoParam] - -TrainingType: TypeAlias = Union[FullTrainingTypeParam, LoRaTrainingTypeParam] diff --git a/src/together/types/fine_tuning_create_response.py b/src/together/types/fine_tuning_create_response.py deleted file mode 100644 index d6e2aca0..00000000 --- a/src/together/types/fine_tuning_create_response.py +++ /dev/null @@ -1,121 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Union, Optional -from datetime import datetime -from typing_extensions import Literal, TypeAlias - -from pydantic import Field as FieldInfo - -from .._models import BaseModel -from .lr_scheduler import LrScheduler -from .fine_tune_event import FineTuneEvent -from .full_training_type import FullTrainingType -from .lo_ra_training_type import LoRaTrainingType -from .training_method_dpo import TrainingMethodDpo -from .training_method_sft import TrainingMethodSft - -__all__ = ["FineTuningCreateResponse", "TrainingMethod", "TrainingType"] - -TrainingMethod: TypeAlias = Union[TrainingMethodSft, TrainingMethodDpo] - -TrainingType: TypeAlias = Union[FullTrainingType, LoRaTrainingType] - - -class FineTuningCreateResponse(BaseModel): - id: str - """Unique identifier for the fine-tune job""" - - created_at: datetime - """Creation timestamp of the fine-tune job""" - - status: Literal[ - "pending", - "queued", - "running", - "compressing", - "uploading", - "cancel_requested", - "cancelled", - "error", - "completed", - ] - - updated_at: datetime - """Last update timestamp of the fine-tune job""" - - batch_size: Optional[int] = None - """Batch size used for training""" - - events: Optional[List[FineTuneEvent]] = None - """Events related to this fine-tune job""" - - from_checkpoint: Optional[str] = None - """Checkpoint used to continue training""" - - from_hf_model: Optional[str] = None - """Hugging Face Hub repo to start training from""" - - hf_model_revision: Optional[str] = None - """The revision of the Hugging Face Hub model to continue training from""" - - learning_rate: Optional[float] = None - """Learning rate used for training""" - - lr_scheduler: Optional[LrScheduler] = None - """Learning rate scheduler configuration""" - - max_grad_norm: Optional[float] = None - """Maximum gradient norm for clipping""" - - model: Optional[str] = None - """Base model used for fine-tuning""" - - x_model_output_name: Optional[str] = FieldInfo(alias="model_output_name", default=None) - - n_checkpoints: Optional[int] = None - """Number of checkpoints saved during training""" - - n_epochs: Optional[int] = None - """Number of training epochs""" - - n_evals: Optional[int] = None - """Number of evaluations during training""" - - owner_address: Optional[str] = None - """Owner address information""" - - suffix: Optional[str] = None - """Suffix added to the fine-tuned model name""" - - token_count: Optional[int] = None - """Count of tokens processed""" - - total_price: Optional[int] = None - """Total price for the fine-tuning job""" - - training_file: Optional[str] = None - """File-ID of the training file""" - - training_method: Optional[TrainingMethod] = None - """Method of training used""" - - training_type: Optional[TrainingType] = None - """Type of training used (full or LoRA)""" - - user_id: Optional[str] = None - """Identifier for the user who created the job""" - - validation_file: Optional[str] = None - """File-ID of the validation file""" - - wandb_name: Optional[str] = None - """Weights & Biases run name""" - - wandb_project_name: Optional[str] = None - """Weights & Biases project name""" - - warmup_ratio: Optional[float] = None - """Ratio of warmup steps""" - - weight_decay: Optional[float] = None - """Weight decay value used""" diff --git a/src/together/types/full_training_type_param.py b/src/together/types/full_training_type_param.py deleted file mode 100644 index 57950250..00000000 --- a/src/together/types/full_training_type_param.py +++ /dev/null @@ -1,11 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["FullTrainingTypeParam"] - - -class FullTrainingTypeParam(TypedDict, total=False): - type: Required[Literal["Full"]] diff --git a/src/together/types/linear_lr_scheduler_args_param.py b/src/together/types/linear_lr_scheduler_args_param.py deleted file mode 100644 index 05931977..00000000 --- a/src/together/types/linear_lr_scheduler_args_param.py +++ /dev/null @@ -1,12 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import TypedDict - -__all__ = ["LinearLrSchedulerArgsParam"] - - -class LinearLrSchedulerArgsParam(TypedDict, total=False): - min_lr_ratio: float - """The ratio of the final learning rate to the peak learning rate""" diff --git a/src/together/types/lo_ra_training_type_param.py b/src/together/types/lo_ra_training_type_param.py deleted file mode 100644 index c554d910..00000000 --- a/src/together/types/lo_ra_training_type_param.py +++ /dev/null @@ -1,19 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["LoRaTrainingTypeParam"] - - -class LoRaTrainingTypeParam(TypedDict, total=False): - lora_alpha: Required[int] - - lora_r: Required[int] - - type: Required[Literal["Lora"]] - - lora_dropout: float - - lora_trainable_modules: str diff --git a/src/together/types/lr_scheduler_param.py b/src/together/types/lr_scheduler_param.py deleted file mode 100644 index 30535c4a..00000000 --- a/src/together/types/lr_scheduler_param.py +++ /dev/null @@ -1,19 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from typing_extensions import Literal, Required, TypeAlias, TypedDict - -from .cosine_lr_scheduler_args_param import CosineLrSchedulerArgsParam -from .linear_lr_scheduler_args_param import LinearLrSchedulerArgsParam - -__all__ = ["LrSchedulerParam", "LrSchedulerArgs"] - -LrSchedulerArgs: TypeAlias = Union[LinearLrSchedulerArgsParam, CosineLrSchedulerArgsParam] - - -class LrSchedulerParam(TypedDict, total=False): - lr_scheduler_type: Required[Literal["linear", "cosine"]] - - lr_scheduler_args: LrSchedulerArgs diff --git a/src/together/types/training_method_dpo_param.py b/src/together/types/training_method_dpo_param.py deleted file mode 100644 index cd776600..00000000 --- a/src/together/types/training_method_dpo_param.py +++ /dev/null @@ -1,21 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["TrainingMethodDpoParam"] - - -class TrainingMethodDpoParam(TypedDict, total=False): - method: Required[Literal["dpo"]] - - dpo_beta: float - - dpo_normalize_logratios_by_length: bool - - dpo_reference_free: bool - - rpo_alpha: float - - simpo_gamma: float diff --git a/src/together/types/training_method_sft_param.py b/src/together/types/training_method_sft_param.py deleted file mode 100644 index 01c3cc15..00000000 --- a/src/together/types/training_method_sft_param.py +++ /dev/null @@ -1,18 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["TrainingMethodSftParam"] - - -class TrainingMethodSftParam(TypedDict, total=False): - method: Required[Literal["sft"]] - - train_on_inputs: Required[Union[bool, Literal["auto"]]] - """ - Whether to mask the user messages in conversational data or prompts in - instruction data. - """ diff --git a/tests/api_resources/test_fine_tuning.py b/tests/api_resources/test_fine_tuning.py index a03b3a72..4a7a3104 100644 --- a/tests/api_resources/test_fine_tuning.py +++ b/tests/api_resources/test_fine_tuning.py @@ -15,7 +15,6 @@ FineTune, FineTuningListResponse, FineTuningCancelResponse, - FineTuningCreateResponse, FineTuningDeleteResponse, FineTuningListEventsResponse, FineTuningListCheckpointsResponse, @@ -33,77 +32,6 @@ class TestFineTuning: parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - @parametrize - def test_method_create(self, client: Together) -> None: - fine_tuning = client.fine_tuning.create( - model="model", - training_file="training_file", - ) - assert_matches_type(FineTuningCreateResponse, fine_tuning, path=["response"]) - - @parametrize - def test_method_create_with_all_params(self, client: Together) -> None: - fine_tuning = client.fine_tuning.create( - model="model", - training_file="training_file", - batch_size=0, - from_checkpoint="from_checkpoint", - from_hf_model="from_hf_model", - hf_api_token="hf_api_token", - hf_model_revision="hf_model_revision", - hf_output_repo_name="hf_output_repo_name", - learning_rate=0, - lr_scheduler={ - "lr_scheduler_type": "linear", - "lr_scheduler_args": {"min_lr_ratio": 0}, - }, - max_grad_norm=0, - n_checkpoints=0, - n_epochs=0, - n_evals=0, - suffix="suffix", - train_on_inputs=True, - training_method={ - "method": "sft", - "train_on_inputs": True, - }, - training_type={"type": "Full"}, - validation_file="validation_file", - wandb_api_key="wandb_api_key", - wandb_base_url="wandb_base_url", - wandb_name="wandb_name", - wandb_project_name="wandb_project_name", - warmup_ratio=0, - weight_decay=0, - ) - assert_matches_type(FineTuningCreateResponse, fine_tuning, path=["response"]) - - @parametrize - def test_raw_response_create(self, client: Together) -> None: - response = client.fine_tuning.with_raw_response.create( - model="model", - training_file="training_file", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - fine_tuning = response.parse() - assert_matches_type(FineTuningCreateResponse, fine_tuning, path=["response"]) - - @parametrize - def test_streaming_response_create(self, client: Together) -> None: - with client.fine_tuning.with_streaming_response.create( - model="model", - training_file="training_file", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - fine_tuning = response.parse() - assert_matches_type(FineTuningCreateResponse, fine_tuning, path=["response"]) - - assert cast(Any, response.is_closed) is True - @parametrize def test_method_retrieve(self, client: Together) -> None: fine_tuning = client.fine_tuning.retrieve( @@ -385,77 +313,6 @@ class TestAsyncFineTuning: "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] ) - @parametrize - async def test_method_create(self, async_client: AsyncTogether) -> None: - fine_tuning = await async_client.fine_tuning.create( - model="model", - training_file="training_file", - ) - assert_matches_type(FineTuningCreateResponse, fine_tuning, path=["response"]) - - @parametrize - async def test_method_create_with_all_params(self, async_client: AsyncTogether) -> None: - fine_tuning = await async_client.fine_tuning.create( - model="model", - training_file="training_file", - batch_size=0, - from_checkpoint="from_checkpoint", - from_hf_model="from_hf_model", - hf_api_token="hf_api_token", - hf_model_revision="hf_model_revision", - hf_output_repo_name="hf_output_repo_name", - learning_rate=0, - lr_scheduler={ - "lr_scheduler_type": "linear", - "lr_scheduler_args": {"min_lr_ratio": 0}, - }, - max_grad_norm=0, - n_checkpoints=0, - n_epochs=0, - n_evals=0, - suffix="suffix", - train_on_inputs=True, - training_method={ - "method": "sft", - "train_on_inputs": True, - }, - training_type={"type": "Full"}, - validation_file="validation_file", - wandb_api_key="wandb_api_key", - wandb_base_url="wandb_base_url", - wandb_name="wandb_name", - wandb_project_name="wandb_project_name", - warmup_ratio=0, - weight_decay=0, - ) - assert_matches_type(FineTuningCreateResponse, fine_tuning, path=["response"]) - - @parametrize - async def test_raw_response_create(self, async_client: AsyncTogether) -> None: - response = await async_client.fine_tuning.with_raw_response.create( - model="model", - training_file="training_file", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - fine_tuning = await response.parse() - assert_matches_type(FineTuningCreateResponse, fine_tuning, path=["response"]) - - @parametrize - async def test_streaming_response_create(self, async_client: AsyncTogether) -> None: - async with async_client.fine_tuning.with_streaming_response.create( - model="model", - training_file="training_file", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - fine_tuning = await response.parse() - assert_matches_type(FineTuningCreateResponse, fine_tuning, path=["response"]) - - assert cast(Any, response.is_closed) is True - @parametrize async def test_method_retrieve(self, async_client: AsyncTogether) -> None: fine_tuning = await async_client.fine_tuning.retrieve( From a6e3ad792393be978b123c87707afe779ef8df34 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 20 Nov 2025 16:14:46 +0000 Subject: [PATCH 2/8] feat(api): Change image creation signature to `images.generate` BREAKING CHANGE: For the TS SDK the `images.create` is now `images.generate` --- .stats.yml | 2 +- api.md | 2 +- src/together/resources/images.py | 30 ++++++++--------- src/together/types/__init__.py | 2 +- ...ate_params.py => image_generate_params.py} | 4 +-- tests/api_resources/test_images.py | 32 +++++++++---------- 6 files changed, 36 insertions(+), 36 deletions(-) rename src/together/types/{image_create_params.py => image_generate_params.py} (96%) diff --git a/.stats.yml b/.stats.yml index ae76cfce..50b97bd9 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 44 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/togetherai%2Ftogetherai-57c68db188c5a4e69e16f99e7e4968f08f2dbf64e7e7d8f57f54f84669305189.yml openapi_spec_hash: 4e707463a416fd079a6beeff1d1beecb -config_hash: ff6223e5c6a73b836f4d70ea6d1f385f +config_hash: 2fabf9b1cee38923853fcfbad54500ca diff --git a/api.md b/api.md index e4fa10a3..b2ad5a50 100644 --- a/api.md +++ b/api.md @@ -145,7 +145,7 @@ from together.types import ImageDataB64, ImageDataURL, ImageFile Methods: -- client.images.create(\*\*params) -> ImageFile +- client.images.generate(\*\*params) -> ImageFile # Videos diff --git a/src/together/resources/images.py b/src/together/resources/images.py index 5ed51c84..bc7cb350 100644 --- a/src/together/resources/images.py +++ b/src/together/resources/images.py @@ -7,7 +7,7 @@ import httpx -from ..types import image_create_params +from ..types import image_generate_params from .._types import Body, Omit, Query, Headers, NotGiven, omit, not_given from .._utils import maybe_transform, async_maybe_transform from .._compat import cached_property @@ -44,7 +44,7 @@ def with_streaming_response(self) -> ImagesResourceWithStreamingResponse: """ return ImagesResourceWithStreamingResponse(self) - def create( + def generate( self, *, model: Union[ @@ -59,7 +59,7 @@ def create( disable_safety_checker: bool | Omit = omit, guidance_scale: float | Omit = omit, height: int | Omit = omit, - image_loras: Iterable[image_create_params.ImageLora] | Omit = omit, + image_loras: Iterable[image_generate_params.ImageLora] | Omit = omit, image_url: str | Omit = omit, n: int | Omit = omit, negative_prompt: str | Omit = omit, @@ -140,7 +140,7 @@ def create( "steps": steps, "width": width, }, - image_create_params.ImageCreateParams, + image_generate_params.ImageGenerateParams, ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout @@ -169,7 +169,7 @@ def with_streaming_response(self) -> AsyncImagesResourceWithStreamingResponse: """ return AsyncImagesResourceWithStreamingResponse(self) - async def create( + async def generate( self, *, model: Union[ @@ -184,7 +184,7 @@ async def create( disable_safety_checker: bool | Omit = omit, guidance_scale: float | Omit = omit, height: int | Omit = omit, - image_loras: Iterable[image_create_params.ImageLora] | Omit = omit, + image_loras: Iterable[image_generate_params.ImageLora] | Omit = omit, image_url: str | Omit = omit, n: int | Omit = omit, negative_prompt: str | Omit = omit, @@ -265,7 +265,7 @@ async def create( "steps": steps, "width": width, }, - image_create_params.ImageCreateParams, + image_generate_params.ImageGenerateParams, ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout @@ -278,8 +278,8 @@ class ImagesResourceWithRawResponse: def __init__(self, images: ImagesResource) -> None: self._images = images - self.create = to_raw_response_wrapper( - images.create, + self.generate = to_raw_response_wrapper( + images.generate, ) @@ -287,8 +287,8 @@ class AsyncImagesResourceWithRawResponse: def __init__(self, images: AsyncImagesResource) -> None: self._images = images - self.create = async_to_raw_response_wrapper( - images.create, + self.generate = async_to_raw_response_wrapper( + images.generate, ) @@ -296,8 +296,8 @@ class ImagesResourceWithStreamingResponse: def __init__(self, images: ImagesResource) -> None: self._images = images - self.create = to_streamed_response_wrapper( - images.create, + self.generate = to_streamed_response_wrapper( + images.generate, ) @@ -305,6 +305,6 @@ class AsyncImagesResourceWithStreamingResponse: def __init__(self, images: AsyncImagesResource) -> None: self._images = images - self.create = async_to_streamed_response_wrapper( - images.create, + self.generate = async_to_streamed_response_wrapper( + images.generate, ) diff --git a/src/together/types/__init__.py b/src/together/types/__init__.py index 2c2c7c39..5170a108 100644 --- a/src/together/types/__init__.py +++ b/src/together/types/__init__.py @@ -34,7 +34,6 @@ from .audio_create_params import AudioCreateParams as AudioCreateParams from .batch_create_params import BatchCreateParams as BatchCreateParams from .batch_list_response import BatchListResponse as BatchListResponse -from .image_create_params import ImageCreateParams as ImageCreateParams from .lo_ra_training_type import LoRaTrainingType as LoRaTrainingType from .model_list_response import ModelListResponse as ModelListResponse from .model_upload_params import ModelUploadParams as ModelUploadParams @@ -50,6 +49,7 @@ from .hardware_list_params import HardwareListParams as HardwareListParams from .batch_cancel_response import BatchCancelResponse as BatchCancelResponse from .batch_create_response import BatchCreateResponse as BatchCreateResponse +from .image_generate_params import ImageGenerateParams as ImageGenerateParams from .job_retrieve_response import JobRetrieveResponse as JobRetrieveResponse from .model_upload_response import ModelUploadResponse as ModelUploadResponse from .video_create_response import VideoCreateResponse as VideoCreateResponse diff --git a/src/together/types/image_create_params.py b/src/together/types/image_generate_params.py similarity index 96% rename from src/together/types/image_create_params.py rename to src/together/types/image_generate_params.py index e32137d0..4d0cd04b 100644 --- a/src/together/types/image_create_params.py +++ b/src/together/types/image_generate_params.py @@ -5,10 +5,10 @@ from typing import Union, Iterable from typing_extensions import Literal, Required, TypedDict -__all__ = ["ImageCreateParams", "ImageLora"] +__all__ = ["ImageGenerateParams", "ImageLora"] -class ImageCreateParams(TypedDict, total=False): +class ImageGenerateParams(TypedDict, total=False): model: Required[ Union[ Literal[ diff --git a/tests/api_resources/test_images.py b/tests/api_resources/test_images.py index b1f2d2e3..a7a2d259 100644 --- a/tests/api_resources/test_images.py +++ b/tests/api_resources/test_images.py @@ -18,16 +18,16 @@ class TestImages: parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) @parametrize - def test_method_create(self, client: Together) -> None: - image = client.images.create( + def test_method_generate(self, client: Together) -> None: + image = client.images.generate( model="black-forest-labs/FLUX.1-schnell", prompt="cat floating in space, cinematic", ) assert_matches_type(ImageFile, image, path=["response"]) @parametrize - def test_method_create_with_all_params(self, client: Together) -> None: - image = client.images.create( + def test_method_generate_with_all_params(self, client: Together) -> None: + image = client.images.generate( model="black-forest-labs/FLUX.1-schnell", prompt="cat floating in space, cinematic", disable_safety_checker=True, @@ -51,8 +51,8 @@ def test_method_create_with_all_params(self, client: Together) -> None: assert_matches_type(ImageFile, image, path=["response"]) @parametrize - def test_raw_response_create(self, client: Together) -> None: - response = client.images.with_raw_response.create( + def test_raw_response_generate(self, client: Together) -> None: + response = client.images.with_raw_response.generate( model="black-forest-labs/FLUX.1-schnell", prompt="cat floating in space, cinematic", ) @@ -63,8 +63,8 @@ def test_raw_response_create(self, client: Together) -> None: assert_matches_type(ImageFile, image, path=["response"]) @parametrize - def test_streaming_response_create(self, client: Together) -> None: - with client.images.with_streaming_response.create( + def test_streaming_response_generate(self, client: Together) -> None: + with client.images.with_streaming_response.generate( model="black-forest-labs/FLUX.1-schnell", prompt="cat floating in space, cinematic", ) as response: @@ -83,16 +83,16 @@ class TestAsyncImages: ) @parametrize - async def test_method_create(self, async_client: AsyncTogether) -> None: - image = await async_client.images.create( + async def test_method_generate(self, async_client: AsyncTogether) -> None: + image = await async_client.images.generate( model="black-forest-labs/FLUX.1-schnell", prompt="cat floating in space, cinematic", ) assert_matches_type(ImageFile, image, path=["response"]) @parametrize - async def test_method_create_with_all_params(self, async_client: AsyncTogether) -> None: - image = await async_client.images.create( + async def test_method_generate_with_all_params(self, async_client: AsyncTogether) -> None: + image = await async_client.images.generate( model="black-forest-labs/FLUX.1-schnell", prompt="cat floating in space, cinematic", disable_safety_checker=True, @@ -116,8 +116,8 @@ async def test_method_create_with_all_params(self, async_client: AsyncTogether) assert_matches_type(ImageFile, image, path=["response"]) @parametrize - async def test_raw_response_create(self, async_client: AsyncTogether) -> None: - response = await async_client.images.with_raw_response.create( + async def test_raw_response_generate(self, async_client: AsyncTogether) -> None: + response = await async_client.images.with_raw_response.generate( model="black-forest-labs/FLUX.1-schnell", prompt="cat floating in space, cinematic", ) @@ -128,8 +128,8 @@ async def test_raw_response_create(self, async_client: AsyncTogether) -> None: assert_matches_type(ImageFile, image, path=["response"]) @parametrize - async def test_streaming_response_create(self, async_client: AsyncTogether) -> None: - async with async_client.images.with_streaming_response.create( + async def test_streaming_response_generate(self, async_client: AsyncTogether) -> None: + async with async_client.images.with_streaming_response.generate( model="black-forest-labs/FLUX.1-schnell", prompt="cat floating in space, cinematic", ) as response: From aa279076c524956e204cb68b7424048a4f93a17d Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 20 Nov 2025 17:43:58 +0000 Subject: [PATCH 3/8] feat(api): Change fine tuning download method to `.create` BREAKING CHANGE: Change Fine Tuning method name from `download()` to `content()` to align with other namespaces --- .stats.yml | 2 +- api.md | 2 +- src/together/resources/fine_tuning.py | 26 +++++++-------- src/together/types/__init__.py | 2 +- ...arams.py => fine_tuning_content_params.py} | 4 +-- tests/api_resources/test_fine_tuning.py | 32 +++++++++---------- 6 files changed, 34 insertions(+), 34 deletions(-) rename src/together/types/{fine_tuning_download_params.py => fine_tuning_content_params.py} (86%) diff --git a/.stats.yml b/.stats.yml index 50b97bd9..508eee3b 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 44 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/togetherai%2Ftogetherai-57c68db188c5a4e69e16f99e7e4968f08f2dbf64e7e7d8f57f54f84669305189.yml openapi_spec_hash: 4e707463a416fd079a6beeff1d1beecb -config_hash: 2fabf9b1cee38923853fcfbad54500ca +config_hash: 13875c495340ee39d9ff60ab63480486 diff --git a/api.md b/api.md index b2ad5a50..cfd70513 100644 --- a/api.md +++ b/api.md @@ -107,7 +107,7 @@ Methods: - client.fine_tuning.list() -> FineTuningListResponse - client.fine_tuning.delete(id, \*\*params) -> FineTuningDeleteResponse - client.fine_tuning.cancel(id) -> FineTuningCancelResponse -- client.fine_tuning.download(\*\*params) -> BinaryAPIResponse +- client.fine_tuning.content(\*\*params) -> BinaryAPIResponse - client.fine_tuning.list_checkpoints(id) -> FineTuningListCheckpointsResponse - client.fine_tuning.list_events(id) -> FineTuningListEventsResponse diff --git a/src/together/resources/fine_tuning.py b/src/together/resources/fine_tuning.py index 49e22f28..024857ba 100644 --- a/src/together/resources/fine_tuning.py +++ b/src/together/resources/fine_tuning.py @@ -6,7 +6,7 @@ import httpx -from ..types import fine_tuning_delete_params, fine_tuning_download_params +from ..types import fine_tuning_delete_params, fine_tuning_content_params from .._types import Body, Omit, Query, Headers, NotGiven, omit, not_given from .._utils import maybe_transform, async_maybe_transform from .._compat import cached_property @@ -185,7 +185,7 @@ def cancel( cast_to=FineTuningCancelResponse, ) - def download( + def content( self, *, ft_id: str, @@ -232,7 +232,7 @@ def download( "checkpoint": checkpoint, "checkpoint_step": checkpoint_step, }, - fine_tuning_download_params.FineTuningDownloadParams, + fine_tuning_content_params.FineTuningContentParams, ), ), cast_to=BinaryAPIResponse, @@ -454,7 +454,7 @@ async def cancel( cast_to=FineTuningCancelResponse, ) - async def download( + async def content( self, *, ft_id: str, @@ -501,7 +501,7 @@ async def download( "checkpoint": checkpoint, "checkpoint_step": checkpoint_step, }, - fine_tuning_download_params.FineTuningDownloadParams, + fine_tuning_content_params.FineTuningContentParams, ), ), cast_to=AsyncBinaryAPIResponse, @@ -590,8 +590,8 @@ def __init__(self, fine_tuning: FineTuningResource) -> None: self.cancel = to_raw_response_wrapper( fine_tuning.cancel, ) - self.download = to_custom_raw_response_wrapper( - fine_tuning.download, + self.content = to_custom_raw_response_wrapper( + fine_tuning.content, BinaryAPIResponse, ) self.list_checkpoints = to_raw_response_wrapper( @@ -618,8 +618,8 @@ def __init__(self, fine_tuning: AsyncFineTuningResource) -> None: self.cancel = async_to_raw_response_wrapper( fine_tuning.cancel, ) - self.download = async_to_custom_raw_response_wrapper( - fine_tuning.download, + self.content = async_to_custom_raw_response_wrapper( + fine_tuning.content, AsyncBinaryAPIResponse, ) self.list_checkpoints = async_to_raw_response_wrapper( @@ -646,8 +646,8 @@ def __init__(self, fine_tuning: FineTuningResource) -> None: self.cancel = to_streamed_response_wrapper( fine_tuning.cancel, ) - self.download = to_custom_streamed_response_wrapper( - fine_tuning.download, + self.content = to_custom_streamed_response_wrapper( + fine_tuning.content, StreamedBinaryAPIResponse, ) self.list_checkpoints = to_streamed_response_wrapper( @@ -674,8 +674,8 @@ def __init__(self, fine_tuning: AsyncFineTuningResource) -> None: self.cancel = async_to_streamed_response_wrapper( fine_tuning.cancel, ) - self.download = async_to_custom_streamed_response_wrapper( - fine_tuning.download, + self.content = async_to_custom_streamed_response_wrapper( + fine_tuning.content, AsyncStreamedBinaryAPIResponse, ) self.list_checkpoints = async_to_streamed_response_wrapper( diff --git a/src/together/types/__init__.py b/src/together/types/__init__.py index 5170a108..bad1d48f 100644 --- a/src/together/types/__init__.py +++ b/src/together/types/__init__.py @@ -66,9 +66,9 @@ from .audio_speech_stream_chunk import AudioSpeechStreamChunk as AudioSpeechStreamChunk from .fine_tuning_delete_params import FineTuningDeleteParams as FineTuningDeleteParams from .fine_tuning_list_response import FineTuningListResponse as FineTuningListResponse +from .fine_tuning_content_params import FineTuningContentParams as FineTuningContentParams from .fine_tuning_cancel_response import FineTuningCancelResponse as FineTuningCancelResponse from .fine_tuning_delete_response import FineTuningDeleteResponse as FineTuningDeleteResponse -from .fine_tuning_download_params import FineTuningDownloadParams as FineTuningDownloadParams from .endpoint_list_avzones_response import EndpointListAvzonesResponse as EndpointListAvzonesResponse from .code_interpreter_execute_params import CodeInterpreterExecuteParams as CodeInterpreterExecuteParams from .fine_tuning_list_events_response import FineTuningListEventsResponse as FineTuningListEventsResponse diff --git a/src/together/types/fine_tuning_download_params.py b/src/together/types/fine_tuning_content_params.py similarity index 86% rename from src/together/types/fine_tuning_download_params.py rename to src/together/types/fine_tuning_content_params.py index 793d3a43..6da6ad00 100644 --- a/src/together/types/fine_tuning_download_params.py +++ b/src/together/types/fine_tuning_content_params.py @@ -4,10 +4,10 @@ from typing_extensions import Literal, Required, TypedDict -__all__ = ["FineTuningDownloadParams"] +__all__ = ["FineTuningContentParams"] -class FineTuningDownloadParams(TypedDict, total=False): +class FineTuningContentParams(TypedDict, total=False): ft_id: Required[str] """Fine-tune ID to download. A string that starts with `ft-`.""" diff --git a/tests/api_resources/test_fine_tuning.py b/tests/api_resources/test_fine_tuning.py index 4a7a3104..ad4f8a6a 100644 --- a/tests/api_resources/test_fine_tuning.py +++ b/tests/api_resources/test_fine_tuning.py @@ -177,9 +177,9 @@ def test_path_params_cancel(self, client: Together) -> None: @parametrize @pytest.mark.respx(base_url=base_url) - def test_method_download(self, client: Together, respx_mock: MockRouter) -> None: + def test_method_content(self, client: Together, respx_mock: MockRouter) -> None: respx_mock.get("/finetune/download").mock(return_value=httpx.Response(200, json={"foo": "bar"})) - fine_tuning = client.fine_tuning.download( + fine_tuning = client.fine_tuning.content( ft_id="ft_id", ) assert fine_tuning.is_closed @@ -189,9 +189,9 @@ def test_method_download(self, client: Together, respx_mock: MockRouter) -> None @parametrize @pytest.mark.respx(base_url=base_url) - def test_method_download_with_all_params(self, client: Together, respx_mock: MockRouter) -> None: + def test_method_content_with_all_params(self, client: Together, respx_mock: MockRouter) -> None: respx_mock.get("/finetune/download").mock(return_value=httpx.Response(200, json={"foo": "bar"})) - fine_tuning = client.fine_tuning.download( + fine_tuning = client.fine_tuning.content( ft_id="ft_id", checkpoint="merged", checkpoint_step=0, @@ -203,10 +203,10 @@ def test_method_download_with_all_params(self, client: Together, respx_mock: Moc @parametrize @pytest.mark.respx(base_url=base_url) - def test_raw_response_download(self, client: Together, respx_mock: MockRouter) -> None: + def test_raw_response_content(self, client: Together, respx_mock: MockRouter) -> None: respx_mock.get("/finetune/download").mock(return_value=httpx.Response(200, json={"foo": "bar"})) - fine_tuning = client.fine_tuning.with_raw_response.download( + fine_tuning = client.fine_tuning.with_raw_response.content( ft_id="ft_id", ) @@ -217,9 +217,9 @@ def test_raw_response_download(self, client: Together, respx_mock: MockRouter) - @parametrize @pytest.mark.respx(base_url=base_url) - def test_streaming_response_download(self, client: Together, respx_mock: MockRouter) -> None: + def test_streaming_response_content(self, client: Together, respx_mock: MockRouter) -> None: respx_mock.get("/finetune/download").mock(return_value=httpx.Response(200, json={"foo": "bar"})) - with client.fine_tuning.with_streaming_response.download( + with client.fine_tuning.with_streaming_response.content( ft_id="ft_id", ) as fine_tuning: assert not fine_tuning.is_closed @@ -458,9 +458,9 @@ async def test_path_params_cancel(self, async_client: AsyncTogether) -> None: @parametrize @pytest.mark.respx(base_url=base_url) - async def test_method_download(self, async_client: AsyncTogether, respx_mock: MockRouter) -> None: + async def test_method_content(self, async_client: AsyncTogether, respx_mock: MockRouter) -> None: respx_mock.get("/finetune/download").mock(return_value=httpx.Response(200, json={"foo": "bar"})) - fine_tuning = await async_client.fine_tuning.download( + fine_tuning = await async_client.fine_tuning.content( ft_id="ft_id", ) assert fine_tuning.is_closed @@ -470,9 +470,9 @@ async def test_method_download(self, async_client: AsyncTogether, respx_mock: Mo @parametrize @pytest.mark.respx(base_url=base_url) - async def test_method_download_with_all_params(self, async_client: AsyncTogether, respx_mock: MockRouter) -> None: + async def test_method_content_with_all_params(self, async_client: AsyncTogether, respx_mock: MockRouter) -> None: respx_mock.get("/finetune/download").mock(return_value=httpx.Response(200, json={"foo": "bar"})) - fine_tuning = await async_client.fine_tuning.download( + fine_tuning = await async_client.fine_tuning.content( ft_id="ft_id", checkpoint="merged", checkpoint_step=0, @@ -484,10 +484,10 @@ async def test_method_download_with_all_params(self, async_client: AsyncTogether @parametrize @pytest.mark.respx(base_url=base_url) - async def test_raw_response_download(self, async_client: AsyncTogether, respx_mock: MockRouter) -> None: + async def test_raw_response_content(self, async_client: AsyncTogether, respx_mock: MockRouter) -> None: respx_mock.get("/finetune/download").mock(return_value=httpx.Response(200, json={"foo": "bar"})) - fine_tuning = await async_client.fine_tuning.with_raw_response.download( + fine_tuning = await async_client.fine_tuning.with_raw_response.content( ft_id="ft_id", ) @@ -498,9 +498,9 @@ async def test_raw_response_download(self, async_client: AsyncTogether, respx_mo @parametrize @pytest.mark.respx(base_url=base_url) - async def test_streaming_response_download(self, async_client: AsyncTogether, respx_mock: MockRouter) -> None: + async def test_streaming_response_content(self, async_client: AsyncTogether, respx_mock: MockRouter) -> None: respx_mock.get("/finetune/download").mock(return_value=httpx.Response(200, json={"foo": "bar"})) - async with async_client.fine_tuning.with_streaming_response.download( + async with async_client.fine_tuning.with_streaming_response.content( ft_id="ft_id", ) as fine_tuning: assert not fine_tuning.is_closed From 921fa591a5a9c70f96d457a7b59749dfdfb6d4d6 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 20 Nov 2025 18:06:22 +0000 Subject: [PATCH 4/8] feat(api): api update --- .stats.yml | 4 ++-- src/together/resources/endpoints.py | 8 ++++++++ src/together/types/endpoint_create_params.py | 3 +++ tests/api_resources/test_endpoints.py | 2 ++ 4 files changed, 15 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 508eee3b..90900b36 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 44 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/togetherai%2Ftogetherai-57c68db188c5a4e69e16f99e7e4968f08f2dbf64e7e7d8f57f54f84669305189.yml -openapi_spec_hash: 4e707463a416fd079a6beeff1d1beecb +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/togetherai%2Ftogetherai-b86f8e6c4674d1a7829ffa8ddff4bc93d21334d231e6a4d0fd734d411c07a4eb.yml +openapi_spec_hash: 8af4975be6ae8f4655fa92fd26af9682 config_hash: 13875c495340ee39d9ff60ab63480486 diff --git a/src/together/resources/endpoints.py b/src/together/resources/endpoints.py index db3b5c82..f591bb83 100644 --- a/src/together/resources/endpoints.py +++ b/src/together/resources/endpoints.py @@ -53,6 +53,7 @@ def create( autoscaling: AutoscalingParam, hardware: str, model: str, + availability_zone: str | Omit = omit, disable_prompt_cache: bool | Omit = omit, disable_speculative_decoding: bool | Omit = omit, display_name: str | Omit = omit, @@ -78,6 +79,8 @@ def create( model: The model to deploy on this endpoint + availability_zone: Create the endpoint in a specified availability zone (e.g., us-central-4b) + disable_prompt_cache: Whether to disable the prompt cache for this endpoint disable_speculative_decoding: Whether to disable speculative decoding for this endpoint @@ -105,6 +108,7 @@ def create( "autoscaling": autoscaling, "hardware": hardware, "model": model, + "availability_zone": availability_zone, "disable_prompt_cache": disable_prompt_cache, "disable_speculative_decoding": disable_speculative_decoding, "display_name": display_name, @@ -343,6 +347,7 @@ async def create( autoscaling: AutoscalingParam, hardware: str, model: str, + availability_zone: str | Omit = omit, disable_prompt_cache: bool | Omit = omit, disable_speculative_decoding: bool | Omit = omit, display_name: str | Omit = omit, @@ -368,6 +373,8 @@ async def create( model: The model to deploy on this endpoint + availability_zone: Create the endpoint in a specified availability zone (e.g., us-central-4b) + disable_prompt_cache: Whether to disable the prompt cache for this endpoint disable_speculative_decoding: Whether to disable speculative decoding for this endpoint @@ -395,6 +402,7 @@ async def create( "autoscaling": autoscaling, "hardware": hardware, "model": model, + "availability_zone": availability_zone, "disable_prompt_cache": disable_prompt_cache, "disable_speculative_decoding": disable_speculative_decoding, "display_name": display_name, diff --git a/src/together/types/endpoint_create_params.py b/src/together/types/endpoint_create_params.py index 70330d81..8fdcbb07 100644 --- a/src/together/types/endpoint_create_params.py +++ b/src/together/types/endpoint_create_params.py @@ -20,6 +20,9 @@ class EndpointCreateParams(TypedDict, total=False): model: Required[str] """The model to deploy on this endpoint""" + availability_zone: str + """Create the endpoint in a specified availability zone (e.g., us-central-4b)""" + disable_prompt_cache: bool """Whether to disable the prompt cache for this endpoint""" diff --git a/tests/api_resources/test_endpoints.py b/tests/api_resources/test_endpoints.py index bc7a6ad2..9a045680 100644 --- a/tests/api_resources/test_endpoints.py +++ b/tests/api_resources/test_endpoints.py @@ -42,6 +42,7 @@ def test_method_create_with_all_params(self, client: Together) -> None: }, hardware="1x_nvidia_a100_80gb_sxm", model="meta-llama/Llama-3-8b-chat-hf", + availability_zone="availability_zone", disable_prompt_cache=True, disable_speculative_decoding=True, display_name="My Llama3 70b endpoint", @@ -298,6 +299,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncTogether) }, hardware="1x_nvidia_a100_80gb_sxm", model="meta-llama/Llama-3-8b-chat-hf", + availability_zone="availability_zone", disable_prompt_cache=True, disable_speculative_decoding=True, display_name="My Llama3 70b endpoint", From 338c415d1cee04520413717ee821f47a64316211 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 20 Nov 2025 18:21:01 +0000 Subject: [PATCH 5/8] feat(api): Change rerank method signature BREAKING CHANGE: Update method signature for reranking to `rerank.create()` --- .stats.yml | 2 +- api.md | 24 +- src/together/_client.py | 174 +------------- src/together/resources/__init__.py | 14 ++ src/together/resources/rerank.py | 226 ++++++++++++++++++ src/together/types/__init__.py | 4 +- ...rank_params.py => rerank_create_params.py} | 4 +- ..._response.py => rerank_create_response.py} | 4 +- .../{test_client.py => test_rerank.py} | 62 ++--- 9 files changed, 302 insertions(+), 212 deletions(-) create mode 100644 src/together/resources/rerank.py rename src/together/types/{client_rerank_params.py => rerank_create_params.py} (92%) rename src/together/types/{rerank_response.py => rerank_create_response.py} (86%) rename tests/api_resources/{test_client.py => test_rerank.py} (77%) diff --git a/.stats.yml b/.stats.yml index 90900b36..1e723030 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 44 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/togetherai%2Ftogetherai-b86f8e6c4674d1a7829ffa8ddff4bc93d21334d231e6a4d0fd734d411c07a4eb.yml openapi_spec_hash: 8af4975be6ae8f4655fa92fd26af9682 -config_hash: 13875c495340ee39d9ff60ab63480486 +config_hash: b337cdd3c62dbd3383529592a029b347 diff --git a/api.md b/api.md index cfd70513..13153257 100644 --- a/api.md +++ b/api.md @@ -1,15 +1,3 @@ -# Together - -Types: - -```python -from together.types import RerankResponse -``` - -Methods: - -- client.rerank(\*\*params) -> RerankResponse - # Chat ## Completions @@ -268,6 +256,18 @@ Methods: - client.hardware.list(\*\*params) -> HardwareListResponse +# Rerank + +Types: + +```python +from together.types import RerankCreateResponse +``` + +Methods: + +- client.rerank.create(\*\*params) -> RerankCreateResponse + # Batches Types: diff --git a/src/together/_client.py b/src/together/_client.py index 3bf16818..c190bba1 100644 --- a/src/together/_client.py +++ b/src/together/_client.py @@ -3,47 +3,31 @@ from __future__ import annotations import os -from typing import Any, Dict, Union, Mapping, Iterable -from typing_extensions import Self, Literal, override +from typing import Any, Mapping +from typing_extensions import Self, override import httpx from . import _exceptions from ._qs import Querystring -from .types import client_rerank_params from ._types import ( - Body, Omit, - Query, - Headers, Timeout, NotGiven, Transport, ProxiesTypes, RequestOptions, - SequenceNotStr, - omit, not_given, ) -from ._utils import ( - is_given, - maybe_transform, - get_async_library, - async_maybe_transform, -) +from ._utils import is_given, get_async_library from ._version import __version__ -from ._response import ( - to_raw_response_wrapper, - to_streamed_response_wrapper, - async_to_raw_response_wrapper, - async_to_streamed_response_wrapper, -) from .resources import ( jobs, evals, files, images, models, + rerank, videos, batches, hardware, @@ -58,11 +42,9 @@ DEFAULT_MAX_RETRIES, SyncAPIClient, AsyncAPIClient, - make_request_options, ) from .resources.chat import chat from .resources.audio import audio -from .types.rerank_response import RerankResponse from .resources.code_interpreter import code_interpreter __all__ = [ @@ -91,6 +73,7 @@ class Together(SyncAPIClient): jobs: jobs.JobsResource endpoints: endpoints.EndpointsResource hardware: hardware.HardwareResource + rerank: rerank.RerankResource batches: batches.BatchesResource evals: evals.EvalsResource with_raw_response: TogetherWithRawResponse @@ -166,6 +149,7 @@ def __init__( self.jobs = jobs.JobsResource(self) self.endpoints = endpoints.EndpointsResource(self) self.hardware = hardware.HardwareResource(self) + self.rerank = rerank.RerankResource(self) self.batches = batches.BatchesResource(self) self.evals = evals.EvalsResource(self) self.with_raw_response = TogetherWithRawResponse(self) @@ -244,68 +228,6 @@ def copy( # client.with_options(timeout=10).foo.create(...) with_options = copy - def rerank( - self, - *, - documents: Union[Iterable[Dict[str, object]], SequenceNotStr[str]], - model: Union[Literal["Salesforce/Llama-Rank-v1"], str], - query: str, - rank_fields: SequenceNotStr[str] | Omit = omit, - return_documents: bool | Omit = omit, - top_n: int | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> RerankResponse: - """ - Query a reranker model - - Args: - documents: List of documents, which can be either strings or objects. - - model: The model to be used for the rerank request. - - [See all of Together AI's rerank models](https://docs.together.ai/docs/serverless-models#rerank-models) - - query: The search query to be used for ranking. - - rank_fields: List of keys in the JSON Object document to rank by. Defaults to use all - supplied keys for ranking. - - return_documents: Whether to return supplied documents with the response. - - top_n: The number of top results to return. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self.post( - "/rerank", - body=maybe_transform( - { - "documents": documents, - "model": model, - "query": query, - "rank_fields": rank_fields, - "return_documents": return_documents, - "top_n": top_n, - }, - client_rerank_params.ClientRerankParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=RerankResponse, - ) - @override def _make_status_error( self, @@ -354,6 +276,7 @@ class AsyncTogether(AsyncAPIClient): jobs: jobs.AsyncJobsResource endpoints: endpoints.AsyncEndpointsResource hardware: hardware.AsyncHardwareResource + rerank: rerank.AsyncRerankResource batches: batches.AsyncBatchesResource evals: evals.AsyncEvalsResource with_raw_response: AsyncTogetherWithRawResponse @@ -429,6 +352,7 @@ def __init__( self.jobs = jobs.AsyncJobsResource(self) self.endpoints = endpoints.AsyncEndpointsResource(self) self.hardware = hardware.AsyncHardwareResource(self) + self.rerank = rerank.AsyncRerankResource(self) self.batches = batches.AsyncBatchesResource(self) self.evals = evals.AsyncEvalsResource(self) self.with_raw_response = AsyncTogetherWithRawResponse(self) @@ -507,68 +431,6 @@ def copy( # client.with_options(timeout=10).foo.create(...) with_options = copy - async def rerank( - self, - *, - documents: Union[Iterable[Dict[str, object]], SequenceNotStr[str]], - model: Union[Literal["Salesforce/Llama-Rank-v1"], str], - query: str, - rank_fields: SequenceNotStr[str] | Omit = omit, - return_documents: bool | Omit = omit, - top_n: int | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> RerankResponse: - """ - Query a reranker model - - Args: - documents: List of documents, which can be either strings or objects. - - model: The model to be used for the rerank request. - - [See all of Together AI's rerank models](https://docs.together.ai/docs/serverless-models#rerank-models) - - query: The search query to be used for ranking. - - rank_fields: List of keys in the JSON Object document to rank by. Defaults to use all - supplied keys for ranking. - - return_documents: Whether to return supplied documents with the response. - - top_n: The number of top results to return. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self.post( - "/rerank", - body=await async_maybe_transform( - { - "documents": documents, - "model": model, - "query": query, - "rank_fields": rank_fields, - "return_documents": return_documents, - "top_n": top_n, - }, - client_rerank_params.ClientRerankParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=RerankResponse, - ) - @override def _make_status_error( self, @@ -618,13 +480,10 @@ def __init__(self, client: Together) -> None: self.jobs = jobs.JobsResourceWithRawResponse(client.jobs) self.endpoints = endpoints.EndpointsResourceWithRawResponse(client.endpoints) self.hardware = hardware.HardwareResourceWithRawResponse(client.hardware) + self.rerank = rerank.RerankResourceWithRawResponse(client.rerank) self.batches = batches.BatchesResourceWithRawResponse(client.batches) self.evals = evals.EvalsResourceWithRawResponse(client.evals) - self.rerank = to_raw_response_wrapper( - client.rerank, - ) - class AsyncTogetherWithRawResponse: def __init__(self, client: AsyncTogether) -> None: @@ -641,13 +500,10 @@ def __init__(self, client: AsyncTogether) -> None: self.jobs = jobs.AsyncJobsResourceWithRawResponse(client.jobs) self.endpoints = endpoints.AsyncEndpointsResourceWithRawResponse(client.endpoints) self.hardware = hardware.AsyncHardwareResourceWithRawResponse(client.hardware) + self.rerank = rerank.AsyncRerankResourceWithRawResponse(client.rerank) self.batches = batches.AsyncBatchesResourceWithRawResponse(client.batches) self.evals = evals.AsyncEvalsResourceWithRawResponse(client.evals) - self.rerank = async_to_raw_response_wrapper( - client.rerank, - ) - class TogetherWithStreamedResponse: def __init__(self, client: Together) -> None: @@ -664,13 +520,10 @@ def __init__(self, client: Together) -> None: self.jobs = jobs.JobsResourceWithStreamingResponse(client.jobs) self.endpoints = endpoints.EndpointsResourceWithStreamingResponse(client.endpoints) self.hardware = hardware.HardwareResourceWithStreamingResponse(client.hardware) + self.rerank = rerank.RerankResourceWithStreamingResponse(client.rerank) self.batches = batches.BatchesResourceWithStreamingResponse(client.batches) self.evals = evals.EvalsResourceWithStreamingResponse(client.evals) - self.rerank = to_streamed_response_wrapper( - client.rerank, - ) - class AsyncTogetherWithStreamedResponse: def __init__(self, client: AsyncTogether) -> None: @@ -689,13 +542,10 @@ def __init__(self, client: AsyncTogether) -> None: self.jobs = jobs.AsyncJobsResourceWithStreamingResponse(client.jobs) self.endpoints = endpoints.AsyncEndpointsResourceWithStreamingResponse(client.endpoints) self.hardware = hardware.AsyncHardwareResourceWithStreamingResponse(client.hardware) + self.rerank = rerank.AsyncRerankResourceWithStreamingResponse(client.rerank) self.batches = batches.AsyncBatchesResourceWithStreamingResponse(client.batches) self.evals = evals.AsyncEvalsResourceWithStreamingResponse(client.evals) - self.rerank = async_to_streamed_response_wrapper( - client.rerank, - ) - Client = Together diff --git a/src/together/resources/__init__.py b/src/together/resources/__init__.py index 0d0a6958..cdcf732b 100644 --- a/src/together/resources/__init__.py +++ b/src/together/resources/__init__.py @@ -56,6 +56,14 @@ ModelsResourceWithStreamingResponse, AsyncModelsResourceWithStreamingResponse, ) +from .rerank import ( + RerankResource, + AsyncRerankResource, + RerankResourceWithRawResponse, + AsyncRerankResourceWithRawResponse, + RerankResourceWithStreamingResponse, + AsyncRerankResourceWithStreamingResponse, +) from .videos import ( VideosResource, AsyncVideosResource, @@ -200,6 +208,12 @@ "AsyncHardwareResourceWithRawResponse", "HardwareResourceWithStreamingResponse", "AsyncHardwareResourceWithStreamingResponse", + "RerankResource", + "AsyncRerankResource", + "RerankResourceWithRawResponse", + "AsyncRerankResourceWithRawResponse", + "RerankResourceWithStreamingResponse", + "AsyncRerankResourceWithStreamingResponse", "BatchesResource", "AsyncBatchesResource", "BatchesResourceWithRawResponse", diff --git a/src/together/resources/rerank.py b/src/together/resources/rerank.py new file mode 100644 index 00000000..b8a62735 --- /dev/null +++ b/src/together/resources/rerank.py @@ -0,0 +1,226 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Iterable +from typing_extensions import Literal + +import httpx + +from ..types import rerank_create_params +from .._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given +from .._utils import maybe_transform, async_maybe_transform +from .._compat import cached_property +from .._resource import SyncAPIResource, AsyncAPIResource +from .._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from .._base_client import make_request_options +from ..types.rerank_create_response import RerankCreateResponse + +__all__ = ["RerankResource", "AsyncRerankResource"] + + +class RerankResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> RerankResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/togethercomputer/together-py#accessing-raw-response-data-eg-headers + """ + return RerankResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> RerankResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/togethercomputer/together-py#with_streaming_response + """ + return RerankResourceWithStreamingResponse(self) + + def create( + self, + *, + documents: Union[Iterable[Dict[str, object]], SequenceNotStr[str]], + model: Union[Literal["Salesforce/Llama-Rank-v1"], str], + query: str, + rank_fields: SequenceNotStr[str] | Omit = omit, + return_documents: bool | Omit = omit, + top_n: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RerankCreateResponse: + """ + Query a reranker model + + Args: + documents: List of documents, which can be either strings or objects. + + model: The model to be used for the rerank request. + + [See all of Together AI's rerank models](https://docs.together.ai/docs/serverless-models#rerank-models) + + query: The search query to be used for ranking. + + rank_fields: List of keys in the JSON Object document to rank by. Defaults to use all + supplied keys for ranking. + + return_documents: Whether to return supplied documents with the response. + + top_n: The number of top results to return. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/rerank", + body=maybe_transform( + { + "documents": documents, + "model": model, + "query": query, + "rank_fields": rank_fields, + "return_documents": return_documents, + "top_n": top_n, + }, + rerank_create_params.RerankCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=RerankCreateResponse, + ) + + +class AsyncRerankResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncRerankResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/togethercomputer/together-py#accessing-raw-response-data-eg-headers + """ + return AsyncRerankResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncRerankResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/togethercomputer/together-py#with_streaming_response + """ + return AsyncRerankResourceWithStreamingResponse(self) + + async def create( + self, + *, + documents: Union[Iterable[Dict[str, object]], SequenceNotStr[str]], + model: Union[Literal["Salesforce/Llama-Rank-v1"], str], + query: str, + rank_fields: SequenceNotStr[str] | Omit = omit, + return_documents: bool | Omit = omit, + top_n: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> RerankCreateResponse: + """ + Query a reranker model + + Args: + documents: List of documents, which can be either strings or objects. + + model: The model to be used for the rerank request. + + [See all of Together AI's rerank models](https://docs.together.ai/docs/serverless-models#rerank-models) + + query: The search query to be used for ranking. + + rank_fields: List of keys in the JSON Object document to rank by. Defaults to use all + supplied keys for ranking. + + return_documents: Whether to return supplied documents with the response. + + top_n: The number of top results to return. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/rerank", + body=await async_maybe_transform( + { + "documents": documents, + "model": model, + "query": query, + "rank_fields": rank_fields, + "return_documents": return_documents, + "top_n": top_n, + }, + rerank_create_params.RerankCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=RerankCreateResponse, + ) + + +class RerankResourceWithRawResponse: + def __init__(self, rerank: RerankResource) -> None: + self._rerank = rerank + + self.create = to_raw_response_wrapper( + rerank.create, + ) + + +class AsyncRerankResourceWithRawResponse: + def __init__(self, rerank: AsyncRerankResource) -> None: + self._rerank = rerank + + self.create = async_to_raw_response_wrapper( + rerank.create, + ) + + +class RerankResourceWithStreamingResponse: + def __init__(self, rerank: RerankResource) -> None: + self._rerank = rerank + + self.create = to_streamed_response_wrapper( + rerank.create, + ) + + +class AsyncRerankResourceWithStreamingResponse: + def __init__(self, rerank: AsyncRerankResource) -> None: + self._rerank = rerank + + self.create = async_to_streamed_response_wrapper( + rerank.create, + ) diff --git a/src/together/types/__init__.py b/src/together/types/__init__.py index bad1d48f..11c20cc9 100644 --- a/src/together/types/__init__.py +++ b/src/together/types/__init__.py @@ -18,7 +18,6 @@ from .image_data_b64 import ImageDataB64 as ImageDataB64 from .image_data_url import ImageDataURL as ImageDataURL from .fine_tune_event import FineTuneEvent as FineTuneEvent -from .rerank_response import RerankResponse as RerankResponse from .completion_chunk import CompletionChunk as CompletionChunk from .eval_list_params import EvalListParams as EvalListParams from .execute_response import ExecuteResponse as ExecuteResponse @@ -40,13 +39,13 @@ from .training_method_dpo import TrainingMethodDpo as TrainingMethodDpo from .training_method_sft import TrainingMethodSft as TrainingMethodSft from .video_create_params import VideoCreateParams as VideoCreateParams -from .client_rerank_params import ClientRerankParams as ClientRerankParams from .endpoint_list_params import EndpointListParams as EndpointListParams from .eval_create_response import EvalCreateResponse as EvalCreateResponse from .eval_status_response import EvalStatusResponse as EvalStatusResponse from .eval_update_response import EvalUpdateResponse as EvalUpdateResponse from .file_delete_response import FileDeleteResponse as FileDeleteResponse from .hardware_list_params import HardwareListParams as HardwareListParams +from .rerank_create_params import RerankCreateParams as RerankCreateParams from .batch_cancel_response import BatchCancelResponse as BatchCancelResponse from .batch_create_response import BatchCreateResponse as BatchCreateResponse from .image_generate_params import ImageGenerateParams as ImageGenerateParams @@ -58,6 +57,7 @@ from .endpoint_update_params import EndpointUpdateParams as EndpointUpdateParams from .file_retrieve_response import FileRetrieveResponse as FileRetrieveResponse from .hardware_list_response import HardwareListResponse as HardwareListResponse +from .rerank_create_response import RerankCreateResponse as RerankCreateResponse from .batch_retrieve_response import BatchRetrieveResponse as BatchRetrieveResponse from .embedding_create_params import EmbeddingCreateParams as EmbeddingCreateParams from .completion_create_params import CompletionCreateParams as CompletionCreateParams diff --git a/src/together/types/client_rerank_params.py b/src/together/types/rerank_create_params.py similarity index 92% rename from src/together/types/client_rerank_params.py rename to src/together/types/rerank_create_params.py index c3334deb..03da2960 100644 --- a/src/together/types/client_rerank_params.py +++ b/src/together/types/rerank_create_params.py @@ -7,10 +7,10 @@ from .._types import SequenceNotStr -__all__ = ["ClientRerankParams"] +__all__ = ["RerankCreateParams"] -class ClientRerankParams(TypedDict, total=False): +class RerankCreateParams(TypedDict, total=False): documents: Required[Union[Iterable[Dict[str, object]], SequenceNotStr[str]]] """List of documents, which can be either strings or objects.""" diff --git a/src/together/types/rerank_response.py b/src/together/types/rerank_create_response.py similarity index 86% rename from src/together/types/rerank_response.py rename to src/together/types/rerank_create_response.py index 73860249..8002027e 100644 --- a/src/together/types/rerank_response.py +++ b/src/together/types/rerank_create_response.py @@ -6,7 +6,7 @@ from .._models import BaseModel from .chat.chat_completion_usage import ChatCompletionUsage -__all__ = ["RerankResponse", "Result", "ResultDocument"] +__all__ = ["RerankCreateResponse", "Result", "ResultDocument"] class ResultDocument(BaseModel): @@ -21,7 +21,7 @@ class Result(BaseModel): relevance_score: float -class RerankResponse(BaseModel): +class RerankCreateResponse(BaseModel): model: str """The model to be used for the rerank request.""" diff --git a/tests/api_resources/test_client.py b/tests/api_resources/test_rerank.py similarity index 77% rename from tests/api_resources/test_client.py rename to tests/api_resources/test_rerank.py index 691c42c4..72c587f4 100644 --- a/tests/api_resources/test_client.py +++ b/tests/api_resources/test_rerank.py @@ -9,17 +9,17 @@ from together import Together, AsyncTogether from tests.utils import assert_matches_type -from together.types import RerankResponse +from together.types import RerankCreateResponse base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") -class TestClient: +class TestRerank: parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) @parametrize - def test_method_rerank(self, client: Together) -> None: - client_ = client.rerank( + def test_method_create(self, client: Together) -> None: + rerank = client.rerank.create( documents=[ { "title": "bar", @@ -41,11 +41,11 @@ def test_method_rerank(self, client: Together) -> None: model="Salesforce/Llama-Rank-V1", query="What animals can I find near Peru?", ) - assert_matches_type(RerankResponse, client_, path=["response"]) + assert_matches_type(RerankCreateResponse, rerank, path=["response"]) @parametrize - def test_method_rerank_with_all_params(self, client: Together) -> None: - client_ = client.rerank( + def test_method_create_with_all_params(self, client: Together) -> None: + rerank = client.rerank.create( documents=[ { "title": "bar", @@ -70,11 +70,11 @@ def test_method_rerank_with_all_params(self, client: Together) -> None: return_documents=True, top_n=2, ) - assert_matches_type(RerankResponse, client_, path=["response"]) + assert_matches_type(RerankCreateResponse, rerank, path=["response"]) @parametrize - def test_raw_response_rerank(self, client: Together) -> None: - response = client.with_raw_response.rerank( + def test_raw_response_create(self, client: Together) -> None: + response = client.rerank.with_raw_response.create( documents=[ { "title": "bar", @@ -99,12 +99,12 @@ def test_raw_response_rerank(self, client: Together) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" - client_ = response.parse() - assert_matches_type(RerankResponse, client_, path=["response"]) + rerank = response.parse() + assert_matches_type(RerankCreateResponse, rerank, path=["response"]) @parametrize - def test_streaming_response_rerank(self, client: Together) -> None: - with client.with_streaming_response.rerank( + def test_streaming_response_create(self, client: Together) -> None: + with client.rerank.with_streaming_response.create( documents=[ { "title": "bar", @@ -129,20 +129,20 @@ def test_streaming_response_rerank(self, client: Together) -> None: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" - client_ = response.parse() - assert_matches_type(RerankResponse, client_, path=["response"]) + rerank = response.parse() + assert_matches_type(RerankCreateResponse, rerank, path=["response"]) assert cast(Any, response.is_closed) is True -class TestAsyncClient: +class TestAsyncRerank: parametrize = pytest.mark.parametrize( "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] ) @parametrize - async def test_method_rerank(self, async_client: AsyncTogether) -> None: - client = await async_client.rerank( + async def test_method_create(self, async_client: AsyncTogether) -> None: + rerank = await async_client.rerank.create( documents=[ { "title": "bar", @@ -164,11 +164,11 @@ async def test_method_rerank(self, async_client: AsyncTogether) -> None: model="Salesforce/Llama-Rank-V1", query="What animals can I find near Peru?", ) - assert_matches_type(RerankResponse, client, path=["response"]) + assert_matches_type(RerankCreateResponse, rerank, path=["response"]) @parametrize - async def test_method_rerank_with_all_params(self, async_client: AsyncTogether) -> None: - client = await async_client.rerank( + async def test_method_create_with_all_params(self, async_client: AsyncTogether) -> None: + rerank = await async_client.rerank.create( documents=[ { "title": "bar", @@ -193,11 +193,11 @@ async def test_method_rerank_with_all_params(self, async_client: AsyncTogether) return_documents=True, top_n=2, ) - assert_matches_type(RerankResponse, client, path=["response"]) + assert_matches_type(RerankCreateResponse, rerank, path=["response"]) @parametrize - async def test_raw_response_rerank(self, async_client: AsyncTogether) -> None: - response = await async_client.with_raw_response.rerank( + async def test_raw_response_create(self, async_client: AsyncTogether) -> None: + response = await async_client.rerank.with_raw_response.create( documents=[ { "title": "bar", @@ -222,12 +222,12 @@ async def test_raw_response_rerank(self, async_client: AsyncTogether) -> None: assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" - client = await response.parse() - assert_matches_type(RerankResponse, client, path=["response"]) + rerank = await response.parse() + assert_matches_type(RerankCreateResponse, rerank, path=["response"]) @parametrize - async def test_streaming_response_rerank(self, async_client: AsyncTogether) -> None: - async with async_client.with_streaming_response.rerank( + async def test_streaming_response_create(self, async_client: AsyncTogether) -> None: + async with async_client.rerank.with_streaming_response.create( documents=[ { "title": "bar", @@ -252,7 +252,7 @@ async def test_streaming_response_rerank(self, async_client: AsyncTogether) -> N assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" - client = await response.parse() - assert_matches_type(RerankResponse, client, path=["response"]) + rerank = await response.parse() + assert_matches_type(RerankCreateResponse, rerank, path=["response"]) assert cast(Any, response.is_closed) is True From ef3bd5245ee254269653ff8e6db1651cfcf89c6d Mon Sep 17 00:00:00 2001 From: Blaine Kasten Date: Fri, 21 Nov 2025 06:55:02 -0600 Subject: [PATCH 6/8] feat(api): Port finetuning create code from together-python (#176) --- src/together/lib/cli/api/fine_tuning.py | 22 +- src/together/lib/resources/fine_tuning.py | 167 +++++----- src/together/lib/types/fine_tuning.py | 370 +++++++++++++++++++++- src/together/resources/fine_tuning.py | 347 ++++++++++++++++++++ tests/unit/test_fine_tuning_resources.py | 168 ++++++---- 5 files changed, 908 insertions(+), 166 deletions(-) diff --git a/src/together/lib/cli/api/fine_tuning.py b/src/together/lib/cli/api/fine_tuning.py index ecf9ecd0..c116d352 100644 --- a/src/together/lib/cli/api/fine_tuning.py +++ b/src/together/lib/cli/api/fine_tuning.py @@ -20,7 +20,7 @@ from together.lib.cli.api.utils import INT_WITH_MAX, BOOL_WITH_AUTO from together.lib.resources.files import DownloadManager from together.lib.utils.serializer import datetime_serializer -from together.lib.resources.fine_tuning import get_model_limits, create_fine_tuning_request +from together.lib.resources.fine_tuning import get_model_limits _CONFIRMATION_MESSAGE = ( "You are about to create a fine-tuning job. " @@ -287,13 +287,7 @@ def create( if from_checkpoint is not None: model_name = from_checkpoint.split(":")[0] - if model_name is None: - raise click.BadParameter("You must specify a model or a checkpoint") - - model_limits = get_model_limits( - client, - model=model_name, - ) + model_limits = get_model_limits(client, str(model_name)) if lora: if model_limits.lora_training is None: @@ -304,9 +298,9 @@ def create( } for arg in default_values: - arg_source = ctx.get_parameter_source("arg") + arg_source = ctx.get_parameter_source("arg") # type: ignore[attr-defined] if arg_source == ParameterSource.DEFAULT: - training_args[str(arg)] = default_values[str(arg_source)] + training_args[arg] = default_values[str(arg_source)] if ctx.get_parameter_source("lora_alpha") == ParameterSource.DEFAULT: # type: ignore[attr-defined] training_args["lora_alpha"] = training_args["lora_r"] * 2 @@ -330,18 +324,16 @@ def create( raise click.BadParameter("You have specified a number of evaluation loops but no validation file.") if confirm or click.confirm(_CONFIRMATION_MESSAGE, default=True, show_default=True): - params = create_fine_tuning_request( - model_limits=model_limits, + response = client.fine_tuning.create( **training_args, + verbose=True, ) - rprint("Submitting a fine-tuning job with the following parameters:", params) - response = client.fine_tuning.create(**params) report_string = f"Successfully submitted a fine-tuning job {response.id}" # created_at reports UTC time, we use .astimezone() to convert to local time formatted_time = response.created_at.astimezone().strftime("%m/%d/%Y, %H:%M:%S") report_string += f" at {formatted_time}" - click.echo(report_string) + rprint(report_string) else: click.echo("No confirmation received, stopping job launch") diff --git a/src/together/lib/resources/fine_tuning.py b/src/together/lib/resources/fine_tuning.py index d88de9dc..f4779191 100644 --- a/src/together/lib/resources/fine_tuning.py +++ b/src/together/lib/resources/fine_tuning.py @@ -1,27 +1,27 @@ from __future__ import annotations -from typing import Any, Dict, Literal -from typing_extensions import Union, TypeAlias +from typing import TYPE_CHECKING, Literal from rich import print as rprint -from together import Together -from together.types import ( - LrSchedulerParam, - FullTrainingTypeParam, - LoRaTrainingTypeParam, - FineTuningCreateParams, - TrainingMethodDpoParam, - TrainingMethodSftParam, - CosineLrSchedulerArgsParam, - LinearLrSchedulerArgsParam, -) from together.lib.utils import log_warn_once -from together.lib.types.fine_tuning import FinetuneTrainingLimits - -TrainingMethod: TypeAlias = Union[TrainingMethodSftParam, TrainingMethodDpoParam] -TrainingType: TypeAlias = Union[FullTrainingTypeParam, LoRaTrainingTypeParam] +if TYPE_CHECKING: + from together import Together, AsyncTogether +from together.lib.types.fine_tuning import ( + TrainingType, + FinetuneRequest, + FullTrainingType, + LoRATrainingType, + CosineLRScheduler, + LinearLRScheduler, + TrainingMethodDPO, + TrainingMethodSFT, + FinetuneLRScheduler, + CosineLRSchedulerArgs, + LinearLRSchedulerArgs, + FinetuneTrainingLimits, +) AVAILABLE_TRAINING_METHODS = { "sft", @@ -29,7 +29,7 @@ } -def create_fine_tuning_request( +def create_finetune_request( model_limits: FinetuneTrainingLimits, training_file: str, model: str | None = None, @@ -40,11 +40,11 @@ def create_fine_tuning_request( batch_size: int | Literal["max"] = "max", learning_rate: float | None = 0.00001, lr_scheduler_type: Literal["linear", "cosine"] = "cosine", - min_lr_ratio: float = 0.0, + min_lr_ratio: float | None = 0.0, scheduler_num_cycles: float = 0.5, warmup_ratio: float | None = None, max_grad_norm: float = 1.0, - weight_decay: float = 0.0, + weight_decay: float | None = 0.0, lora: bool = False, lora_r: int | None = None, lora_dropout: float | None = 0, @@ -66,7 +66,7 @@ def create_fine_tuning_request( hf_model_revision: str | None = None, hf_api_token: str | None = None, hf_output_repo_name: str | None = None, -) -> FineTuningCreateParams: +) -> FinetuneRequest: if model is not None and from_checkpoint is not None: raise ValueError("You must specify either a model or a checkpoint to start a job from, not both") @@ -87,7 +87,7 @@ def create_fine_tuning_request( if warmup_ratio is None: warmup_ratio = 0.0 - training_type: TrainingType = FullTrainingTypeParam(type="Full") + training_type: TrainingType = FullTrainingType() if lora: if model_limits.lora_training is None: raise ValueError(f"LoRA adapters are not supported for the selected model ({model_or_checkpoint}).") @@ -98,15 +98,12 @@ def create_fine_tuning_request( lora_r = lora_r if lora_r is not None else model_limits.lora_training.max_rank lora_alpha = lora_alpha if lora_alpha is not None else lora_r * 2 - training_type = LoRaTrainingTypeParam( - type="Lora", + training_type = LoRATrainingType( lora_r=lora_r, lora_alpha=int(lora_alpha), + lora_dropout=lora_dropout or 0.0, + lora_trainable_modules=lora_trainable_modules or "all-linear", ) - if lora_dropout is not None: - training_type["lora_dropout"] = lora_dropout - if lora_trainable_modules is not None: - training_type["lora_trainable_modules"] = lora_trainable_modules max_batch_size = model_limits.lora_training.max_batch_size min_batch_size = model_limits.lora_training.min_batch_size @@ -139,13 +136,13 @@ def create_fine_tuning_request( if warmup_ratio > 1 or warmup_ratio < 0: raise ValueError(f"Warmup ratio should be between 0 and 1 (got {warmup_ratio})") - if min_lr_ratio > 1 or min_lr_ratio < 0: + if min_lr_ratio is not None and (min_lr_ratio > 1 or min_lr_ratio < 0): raise ValueError(f"Min learning rate ratio should be between 0 and 1 (got {min_lr_ratio})") if max_grad_norm < 0: raise ValueError(f"Max gradient norm should be non-negative (got {max_grad_norm})") - if weight_decay < 0: + if weight_decay is not None and (weight_decay < 0): raise ValueError(f"Weight decay should be non-negative (got {weight_decay})") if training_method not in AVAILABLE_TRAINING_METHODS: @@ -154,10 +151,6 @@ def create_fine_tuning_request( if train_on_inputs is not None and training_method != "sft": raise ValueError("train_on_inputs is only supported for SFT training") - if train_on_inputs is None and training_method == "sft": - log_warn_once("train_on_inputs is not set for SFT training, it will be set to 'auto'") - train_on_inputs = "auto" - if dpo_beta is not None and training_method != "dpo": raise ValueError("dpo_beta is only supported for DPO training") if dpo_normalize_logratios_by_length and training_method != "dpo": @@ -174,24 +167,25 @@ def create_fine_tuning_request( if not simpo_gamma >= 0.0: raise ValueError(f"simpo_gamma should be non-negative (got {simpo_gamma})") - lr_scheduler: LrSchedulerParam + lr_scheduler: FinetuneLRScheduler if lr_scheduler_type == "cosine": if scheduler_num_cycles <= 0.0: raise ValueError(f"Number of cycles should be greater than 0 (got {scheduler_num_cycles})") - lr_scheduler = LrSchedulerParam( - lr_scheduler_type="cosine", - lr_scheduler_args=CosineLrSchedulerArgsParam(min_lr_ratio=min_lr_ratio, num_cycles=scheduler_num_cycles), + lr_scheduler = CosineLRScheduler( + lr_scheduler_args=CosineLRSchedulerArgs(min_lr_ratio=min_lr_ratio, num_cycles=scheduler_num_cycles), ) else: - lr_scheduler = LrSchedulerParam( - lr_scheduler_type="linear", - lr_scheduler_args=LinearLrSchedulerArgsParam(min_lr_ratio=min_lr_ratio), + lr_scheduler = LinearLRScheduler( + lr_scheduler_args=LinearLRSchedulerArgs(min_lr_ratio=min_lr_ratio), ) - training_method_cls: TrainingMethod | None = None + training_method_cls: TrainingMethodSFT | TrainingMethodDPO if training_method == "sft": - training_method_cls = TrainingMethodSftParam(method="sft", train_on_inputs=train_on_inputs or "auto") + if train_on_inputs is None: + log_warn_once("train_on_inputs is not set for SFT training, it will be set to 'auto'") + train_on_inputs = "auto" + training_method_cls = TrainingMethodSFT(train_on_inputs=train_on_inputs) elif training_method == "dpo": if simpo_gamma is not None and simpo_gamma > 0: dpo_reference_free = True @@ -204,59 +198,40 @@ def create_fine_tuning_request( else: dpo_reference_free = False - training_method_cls = TrainingMethodDpoParam( - method="dpo", + training_method_cls = TrainingMethodDPO( + dpo_beta=dpo_beta, dpo_normalize_logratios_by_length=dpo_normalize_logratios_by_length, dpo_reference_free=dpo_reference_free, + rpo_alpha=rpo_alpha, + simpo_gamma=simpo_gamma, ) - if dpo_beta is not None: - training_method_cls["dpo_beta"] = dpo_beta - if rpo_alpha is not None: - training_method_cls["rpo_alpha"] = rpo_alpha - if simpo_gamma is not None: - training_method_cls["simpo_gamma"] = simpo_gamma - - finetune_request = FineTuningCreateParams( - model=model or "", + + finetune_request = FinetuneRequest( + model=model, training_file=training_file, + validation_file=validation_file, n_epochs=n_epochs, + n_evals=n_evals, + n_checkpoints=n_checkpoints, batch_size=batch_size, + learning_rate=learning_rate or 0.00001, lr_scheduler=lr_scheduler, warmup_ratio=warmup_ratio, max_grad_norm=max_grad_norm, - weight_decay=weight_decay, + weight_decay=weight_decay or 0.0, training_type=training_type, + suffix=suffix, + wandb_key=wandb_api_key, + wandb_base_url=wandb_base_url, + wandb_project_name=wandb_project_name, + wandb_name=wandb_name, + training_method=training_method_cls, # pyright: ignore[reportPossiblyUnboundVariable] + from_checkpoint=from_checkpoint, + from_hf_model=from_hf_model, + hf_model_revision=hf_model_revision, + hf_api_token=hf_api_token, + hf_output_repo_name=hf_output_repo_name, ) - if validation_file is not None: - finetune_request["validation_file"] = validation_file - if n_evals is not None: - finetune_request["n_evals"] = n_evals - if n_checkpoints is not None: - finetune_request["n_checkpoints"] = n_checkpoints - if learning_rate is not None: - finetune_request["learning_rate"] = learning_rate - if suffix is not None: - finetune_request["suffix"] = suffix - if wandb_api_key is not None: - finetune_request["wandb_api_key"] = wandb_api_key - if wandb_base_url is not None: - finetune_request["wandb_base_url"] = wandb_base_url - if wandb_project_name is not None: - finetune_request["wandb_project_name"] = wandb_project_name - if wandb_name is not None: - finetune_request["wandb_name"] = wandb_name - if training_method_cls is not None: - finetune_request["training_method"] = training_method_cls - if from_checkpoint is not None: - finetune_request["from_checkpoint"] = from_checkpoint - if from_hf_model is not None: - finetune_request["from_hf_model"] = from_hf_model - if hf_model_revision is not None: - finetune_request["hf_model_revision"] = hf_model_revision - if hf_api_token is not None: - finetune_request["hf_api_token"] = hf_api_token - if hf_output_repo_name is not None: - finetune_request["hf_output_repo_name"] = hf_output_repo_name return finetune_request @@ -283,5 +258,23 @@ def get_model_limits(client: Together, model: str) -> FinetuneTrainingLimits: return response -def not_none_kwargs(**kwargs: Any) -> Dict[str, Any]: - return {k: v for k, v in kwargs.items() if v is not None} +async def async_get_model_limits(client: AsyncTogether, model: str) -> FinetuneTrainingLimits: + """ + Requests training limits for a specific model + + Args: + model_name (str): Name of the model to get limits for + + Returns: + FinetuneTrainingLimits: Object containing training limits for the model + """ + + response = await client.get( + "/fine-tunes/models/limits", + cast_to=FinetuneTrainingLimits, + options={ + "params": {"model_name": model}, + }, + ) + + return response diff --git a/src/together/lib/types/fine_tuning.py b/src/together/lib/types/fine_tuning.py index 7c42d58b..55327e5a 100644 --- a/src/together/lib/types/fine_tuning.py +++ b/src/together/lib/types/fine_tuning.py @@ -1,8 +1,128 @@ -from typing import Any, List, Optional +from enum import Enum +from typing import Any, List, Union, Literal, Optional +from datetime import datetime +from typing_extensions import TypeAlias + +from pydantic import Field, StrictBool from ..._models import BaseModel +class FinetuneJobStatus(str, Enum): + """ + Possible fine-tune job status + """ + + STATUS_PENDING = "pending" + STATUS_QUEUED = "queued" + STATUS_RUNNING = "running" + STATUS_COMPRESSING = "compressing" + STATUS_UPLOADING = "uploading" + STATUS_CANCEL_REQUESTED = "cancel_requested" + STATUS_CANCELLED = "cancelled" + STATUS_ERROR = "error" + STATUS_USER_ERROR = "user_error" + STATUS_COMPLETED = "completed" + + +class FinetuneEventType(str, Enum): + """ + Fine-tune job event types + """ + + JOB_PENDING = "JOB_PENDING" + JOB_START = "JOB_START" + JOB_STOPPED = "JOB_STOPPED" + MODEL_DOWNLOADING = "MODEL_DOWNLOADING" + MODEL_DOWNLOAD_COMPLETE = "MODEL_DOWNLOAD_COMPLETE" + TRAINING_DATA_DOWNLOADING = "TRAINING_DATA_DOWNLOADING" + TRAINING_DATA_DOWNLOAD_COMPLETE = "TRAINING_DATA_DOWNLOAD_COMPLETE" + VALIDATION_DATA_DOWNLOADING = "VALIDATION_DATA_DOWNLOADING" + VALIDATION_DATA_DOWNLOAD_COMPLETE = "VALIDATION_DATA_DOWNLOAD_COMPLETE" + WANDB_INIT = "WANDB_INIT" + TRAINING_START = "TRAINING_START" + CHECKPOINT_SAVE = "CHECKPOINT_SAVE" + BILLING_LIMIT = "BILLING_LIMIT" + EPOCH_COMPLETE = "EPOCH_COMPLETE" + EVAL_COMPLETE = "EVAL_COMPLETE" + TRAINING_COMPLETE = "TRAINING_COMPLETE" + MODEL_COMPRESSING = "COMPRESSING_MODEL" + MODEL_COMPRESSION_COMPLETE = "MODEL_COMPRESSION_COMPLETE" + MODEL_UPLOADING = "MODEL_UPLOADING" + MODEL_UPLOAD_COMPLETE = "MODEL_UPLOAD_COMPLETE" + MODEL_UPLOADING_TO_HF = "MODEL_UPLOADING_TO_HF" + MODEL_UPLOAD_TO_HF_COMPLETE = "MODEL_UPLOAD_TO_HF_COMPLETE" + JOB_COMPLETE = "JOB_COMPLETE" + JOB_ERROR = "JOB_ERROR" + JOB_USER_ERROR = "JOB_USER_ERROR" + CANCEL_REQUESTED = "CANCEL_REQUESTED" + JOB_RESTARTED = "JOB_RESTARTED" + REFUND = "REFUND" + WARNING = "WARNING" + + +class FinetuneEventLevels(str, Enum): + """ + Fine-tune job event status levels + """ + + NULL = "" + INFO = "Info" + WARNING = "Warning" + ERROR = "Error" + LEGACY_INFO = "info" + LEGACY_IWARNING = "warning" + LEGACY_IERROR = "error" + + +class FinetuneEvent(BaseModel): + """ + Fine-tune event type + """ + + # object type + object: Literal["fine-tune-event"] + # created at datetime stamp + created_at: Union[str, None] = None + # event log level + level: Union[FinetuneEventLevels, None] = None + # event message string + message: Union[str, None] = None + # event type + type: Union[FinetuneEventType, None] = None + # optional: model parameter count + param_count: Union[int, None] = None + # optional: dataset token count + token_count: Union[int, None] = None + # optional: weights & biases url + wandb_url: Union[str, None] = None + # event hash + hash: Union[str, None] = None + + +class FullTrainingType(BaseModel): + """ + Training type for full fine-tuning + """ + + type: Union[Literal["Full"], Literal[""]] = "Full" + + +class LoRATrainingType(BaseModel): + """ + Training type for LoRA adapters training + """ + + lora_r: int + lora_alpha: int + lora_dropout: float = 0.0 + lora_trainable_modules: str = "all-linear" + type: Literal["Lora"] = "Lora" + + +TrainingType: TypeAlias = Union[FullTrainingType, LoRATrainingType] + + class FinetuneFullTrainingLimits(BaseModel): max_batch_size: int max_batch_size_dpo: int = -1 @@ -21,9 +141,257 @@ class FinetuneLoraTrainingLimits(FinetuneFullTrainingLimits): target_modules: List[str] +class TrainingMethodSFT(BaseModel): + """ + Training method type for SFT training + """ + + method: Literal["sft"] = "sft" + train_on_inputs: Union[StrictBool, Literal["auto"]] = "auto" + + +class TrainingMethodDPO(BaseModel): + """ + Training method type for DPO training + """ + + method: Literal["dpo"] = "dpo" + dpo_beta: Union[float, None] = None + dpo_normalize_logratios_by_length: bool = False + dpo_reference_free: bool = False + rpo_alpha: Union[float, None] = None + simpo_gamma: Union[float, None] = None + + +TrainingMethod: TypeAlias = Union[TrainingMethodSFT, TrainingMethodDPO] + + class FinetuneTrainingLimits(BaseModel): max_num_epochs: int max_learning_rate: float min_learning_rate: float full_training: Optional[FinetuneFullTrainingLimits] = None lora_training: Optional[FinetuneLoraTrainingLimits] = None + + +class LinearLRSchedulerArgs(BaseModel): + min_lr_ratio: Union[float, None] = 0.0 + + +class CosineLRSchedulerArgs(BaseModel): + min_lr_ratio: Union[float, None] = 0.0 + num_cycles: Union[float, None] = 0.5 + + +class LinearLRScheduler(BaseModel): + lr_scheduler_type: Literal["linear"] = "linear" + lr_scheduler_args: Union[LinearLRSchedulerArgs, None] = None + + +class CosineLRScheduler(BaseModel): + lr_scheduler_type: Literal["cosine"] = "cosine" + lr_scheduler_args: Union[CosineLRSchedulerArgs, None] = None + + +# placeholder for old fine-tuning jobs with no lr_scheduler_type specified +class EmptyLRScheduler(BaseModel): + lr_scheduler_type: Literal[""] + lr_scheduler_args: None = None + + +FinetuneLRScheduler: TypeAlias = Union[LinearLRScheduler, CosineLRScheduler, EmptyLRScheduler] + + +class FinetuneResponse(BaseModel): + """ + Fine-tune API response type + """ + + id: str + """Unique identifier for the fine-tune job""" + + created_at: datetime + """Creation timestamp of the fine-tune job""" + + status: Optional[FinetuneJobStatus] = None + """Status of the fine-tune job""" + + updated_at: datetime + """Last update timestamp of the fine-tune job""" + + batch_size: Optional[int] = None + """Batch size used for training""" + + events: Optional[List[FinetuneEvent]] = None + """Events related to this fine-tune job""" + + from_checkpoint: Optional[str] = None + """Checkpoint used to continue training""" + + from_hf_model: Optional[str] = None + """Hugging Face Hub repo to start training from""" + + hf_model_revision: Optional[str] = None + """The revision of the Hugging Face Hub model to continue training from""" + + learning_rate: Optional[float] = None + """Learning rate used for training""" + + lr_scheduler: Optional[FinetuneLRScheduler] = None + """Learning rate scheduler configuration""" + + max_grad_norm: Optional[float] = None + """Maximum gradient norm for clipping""" + + model: Optional[str] = None + """Base model used for fine-tuning""" + + output_name: Optional[str] = Field(alias="model_output_name") + """Output model name""" + + adapter_output_name: Optional[str] + """Adapter output name""" + + n_checkpoints: Optional[int] = None + """Number of checkpoints saved during training""" + + n_epochs: Optional[int] = None + """Number of training epochs""" + + n_evals: Optional[int] = None + """Number of evaluations during training""" + + owner_address: Optional[str] = None + """Owner address information""" + + suffix: Optional[str] = None + """Suffix added to the fine-tuned model name""" + + token_count: Optional[int] = None + """Count of tokens processed""" + + total_price: Optional[int] = None + """Total price for the fine-tuning job""" + + training_file: Optional[str] = None + """File-ID of the training file""" + + training_method: Optional[TrainingMethod] = None + """Method of training used""" + + training_type: Optional[TrainingType] = None + """Type of training used (full or LoRA)""" + + user_id: Optional[str] = None + """Identifier for the user who created the job""" + + validation_file: Optional[str] = None + """File-ID of the validation file""" + + wandb_name: Optional[str] = None + """Weights & Biases run name""" + + wandb_project_name: Optional[str] = None + """Weights & Biases project name""" + + wandb_base_url: Union[str, None] = None + """Weights & Biases base URL""" + + wandb_url: Union[str, None] = None + """Weights & Biases job URL""" + + warmup_ratio: Optional[float] = None + """Ratio of warmup steps""" + + weight_decay: Optional[float] = None + """Weight decay value used""" + + eval_steps: Union[int, None] = None + """number of steps between evals""" + + job_id: Optional[str] = None + """Job ID""" + + param_count: Optional[int] = None + """Model parameter count""" + + total_steps: Optional[int] = None + """Total number of training steps""" + + steps_completed: Union[int, None] = None + """Number of steps completed (incrementing counter)""" + + epochs_completed: Union[int, None] = None + """Number of epochs completed (incrementing counter)""" + + evals_completed: Union[int, None] = None + """Number of evaluation loops completed (incrementing counter)""" + + queue_depth: Union[int, None] = None + """Place in job queue (decrementing counter)""" + + # # training file metadata + training_file_num_lines: Optional[int] = Field(None, alias="TrainingFileNumLines") + training_file_size: Optional[int] = Field(None, alias="TrainingFileSize") + train_on_inputs: Union[StrictBool, Literal["auto"], None] = "auto" + + @classmethod + def validate_training_type(cls, v: TrainingType) -> TrainingType: + if v.type == "Full" or v.type == "": + return FullTrainingType(**v.model_dump()) + elif v.type == "Lora": + return LoRATrainingType(**v.model_dump()) + else: + raise ValueError("Unknown training type") + + +class FinetuneRequest(BaseModel): + """ + Fine-tune request type + """ + + # training file ID + training_file: str + # validation file id + validation_file: Union[str, None] = None + # base model string + model: Union[str, None] = None + # number of epochs to train for + n_epochs: int + # training learning rate + learning_rate: float + # learning rate scheduler type and args + lr_scheduler: Union[LinearLRScheduler, CosineLRScheduler, None] = None + # learning rate warmup ratio + warmup_ratio: float + # max gradient norm + max_grad_norm: float + # weight decay + weight_decay: float + # number of checkpoints to save + n_checkpoints: Union[int, None] = None + # number of evaluation loops to run + n_evals: Union[int, None] = None + # training batch size + batch_size: Union[int, Literal["max"], None] = None + # up to 40 character suffix for output model name + suffix: Union[str, None] = None + # weights & biases api key + wandb_key: Union[str, None] = None + # weights & biases base url + wandb_base_url: Union[str, None] = None + # wandb project name + wandb_project_name: Union[str, None] = None + # wandb run name + wandb_name: Union[str, None] = None + # training type + training_type: Union[TrainingType, None] = None + # training method + training_method: Union[TrainingMethodSFT, TrainingMethodDPO] = Field(default_factory=TrainingMethodSFT) + # from step + from_checkpoint: Union[str, None] = None + from_hf_model: Union[str, None] = None + hf_model_revision: Union[str, None] = None + # hf related fields + hf_api_token: Union[str, None] = None + hf_output_repo_name: Union[str, None] = None diff --git a/src/together/resources/fine_tuning.py b/src/together/resources/fine_tuning.py index 024857ba..72ce96dc 100644 --- a/src/together/resources/fine_tuning.py +++ b/src/together/resources/fine_tuning.py @@ -5,6 +5,7 @@ from typing_extensions import Literal import httpx +from rich import print as rprint from ..types import fine_tuning_delete_params, fine_tuning_content_params from .._types import Body, Omit, Query, Headers, NotGiven, omit, not_given @@ -27,6 +28,8 @@ ) from .._base_client import make_request_options from ..types.fine_tune import FineTune +from ..lib.types.fine_tuning import FinetuneResponse, FinetuneTrainingLimits +from ..lib.resources.fine_tuning import get_model_limits, async_get_model_limits, create_finetune_request from ..types.fine_tuning_list_response import FineTuningListResponse from ..types.fine_tuning_cancel_response import FineTuningCancelResponse from ..types.fine_tuning_delete_response import FineTuningDeleteResponse @@ -56,6 +59,178 @@ def with_streaming_response(self) -> FineTuningResourceWithStreamingResponse: """ return FineTuningResourceWithStreamingResponse(self) + def create( + self, + *, + training_file: str, + model: str | None = None, + n_epochs: int = 1, + validation_file: str | None = "", + n_evals: int | None = 0, + n_checkpoints: int | None = 1, + batch_size: int | Literal["max"] = "max", + learning_rate: float | None = 0.00001, + lr_scheduler_type: Literal["linear", "cosine"] = "cosine", + min_lr_ratio: float = 0.0, + scheduler_num_cycles: float = 0.5, + warmup_ratio: float = 0.0, + max_grad_norm: float = 1.0, + weight_decay: float = 0.0, + lora: bool = True, + lora_r: int | None = None, + lora_dropout: float | None = 0, + lora_alpha: float | None = None, + lora_trainable_modules: str | None = "all-linear", + suffix: str | None = None, + wandb_api_key: str | None = None, + wandb_base_url: str | None = None, + wandb_project_name: str | None = None, + wandb_name: str | None = None, + verbose: bool = False, + model_limits: FinetuneTrainingLimits | None = None, + train_on_inputs: bool | Literal["auto"] | None = None, + training_method: str = "sft", + dpo_beta: float | None = None, + dpo_normalize_logratios_by_length: bool = False, + rpo_alpha: float | None = None, + simpo_gamma: float | None = None, + from_checkpoint: str | None = None, + from_hf_model: str | None = None, + hf_model_revision: str | None = None, + hf_api_token: str | None = None, + hf_output_repo_name: str | None = None, + ) -> FinetuneResponse: + """ + Method to initiate a fine-tuning job + + Args: + training_file (str): File-ID of a file uploaded to the Together API + model (str, optional): Name of the base model to run fine-tune job on + n_epochs (int, optional): Number of epochs for fine-tuning. Defaults to 1. + validation file (str, optional): File ID of a file uploaded to the Together API for validation. + n_evals (int, optional): Number of evaluation loops to run. Defaults to 0. + n_checkpoints (int, optional): Number of checkpoints to save during fine-tuning. + Defaults to 1. + batch_size (int or "max"): Batch size for fine-tuning. Defaults to max. + learning_rate (float, optional): Learning rate multiplier to use for training + Defaults to 0.00001. + lr_scheduler_type (Literal["linear", "cosine"]): Learning rate scheduler type. Defaults to "cosine". + min_lr_ratio (float, optional): Min learning rate ratio of the initial learning rate for + the learning rate scheduler. Defaults to 0.0. + scheduler_num_cycles (float, optional): Number or fraction of cycles for the cosine learning rate scheduler. Defaults to 0.5. + warmup_ratio (float, optional): Warmup ratio for the learning rate scheduler. + max_grad_norm (float, optional): Max gradient norm. Defaults to 1.0, set to 0 to disable. + weight_decay (float, optional): Weight decay. Defaults to 0.0. + lora (bool, optional): Whether to use LoRA adapters. Defaults to True. + lora_r (int, optional): Rank of LoRA adapters. Defaults to 8. + lora_dropout (float, optional): Dropout rate for LoRA adapters. Defaults to 0. + lora_alpha (float, optional): Alpha for LoRA adapters. Defaults to 8. + lora_trainable_modules (str, optional): Trainable modules for LoRA adapters. Defaults to "all-linear". + suffix (str, optional): Up to 40 character suffix that will be added to your fine-tuned model name. + Defaults to None. + wandb_api_key (str, optional): API key for Weights & Biases integration. + Defaults to None. + wandb_base_url (str, optional): Base URL for Weights & Biases integration. + Defaults to None. + wandb_project_name (str, optional): Project name for Weights & Biases integration. + Defaults to None. + wandb_name (str, optional): Run name for Weights & Biases integration. + Defaults to None. + verbose (bool, optional): whether to print the job parameters before submitting a request. + Defaults to False. + model_limits (FinetuneTrainingLimits, optional): Limits for the hyperparameters the model in Fine-tuning. + Defaults to None. + train_on_inputs (bool or "auto", optional): Whether to mask the user messages in conversational data or prompts in instruction data. + "auto" will automatically determine whether to mask the inputs based on the data format. + For datasets with the "text" field (general format), inputs will not be masked. + For datasets with the "messages" field (conversational format) or "prompt" and "completion" fields + (Instruction format), inputs will be masked. + Defaults to None, or "auto" if training_method is "sft" (set in create_finetune_request). + training_method (str, optional): Training method. Defaults to "sft". + Supported methods: "sft", "dpo". + dpo_beta (float, optional): DPO beta parameter. Defaults to None. + dpo_normalize_logratios_by_length (bool): Whether or not normalize logratios by sample length. Defaults to False, + rpo_alpha (float, optional): RPO alpha parameter of DPO training to include NLL in the loss. Defaults to None. + simpo_gamma: (float, optional): SimPO gamma parameter. Defaults to None. + from_checkpoint (str, optional): The checkpoint identifier to continue training from a previous fine-tuning job. + The format: {$JOB_ID/$OUTPUT_MODEL_NAME}:{$STEP}. + The step value is optional, without it the final checkpoint will be used. + from_hf_model (str, optional): The Hugging Face Hub repo to start training from. + Should be as close as possible to the base model (specified by the `model` argument) in terms of architecture and size. + hf_model_revision (str, optional): The revision of the Hugging Face Hub model to continue training from. Defaults to None. + Example: hf_model_revision=None (defaults to the latest revision in `main`) or + hf_model_revision="607a30d783dfa663caf39e06633721c8d4cfcd7e" (specific commit). + hf_api_token (str, optional): API key for the Hugging Face Hub. Defaults to None. + hf_output_repo_name (str, optional): HF repo to upload the fine-tuned model to. Defaults to None. + + Returns: + FinetuneResponse: Object containing information about fine-tuning job. + """ + + if model_limits is None: + model_name = None + # mypy doesn't understand that model or from_checkpoint is not None + if model is not None: + model_name = model + elif from_checkpoint is not None: + model_name = from_checkpoint.split(":")[0] + else: + # this branch is unreachable, but mypy doesn't know that + pass + model_limits = get_model_limits(self._client, str(model_name)) + + finetune_request = create_finetune_request( + model_limits=model_limits, + training_file=training_file, + model=model, + n_epochs=n_epochs, + validation_file=validation_file, + n_evals=n_evals, + n_checkpoints=n_checkpoints, + batch_size=batch_size, + learning_rate=learning_rate, + lr_scheduler_type=lr_scheduler_type, + min_lr_ratio=min_lr_ratio, + scheduler_num_cycles=scheduler_num_cycles, + warmup_ratio=warmup_ratio, + max_grad_norm=max_grad_norm, + weight_decay=weight_decay, + lora=lora, + lora_r=lora_r, + lora_dropout=lora_dropout, + lora_alpha=lora_alpha, + lora_trainable_modules=lora_trainable_modules, + suffix=suffix, + wandb_api_key=wandb_api_key, + wandb_base_url=wandb_base_url, + wandb_project_name=wandb_project_name, + wandb_name=wandb_name, + train_on_inputs=train_on_inputs, + training_method=training_method, + dpo_beta=dpo_beta, + dpo_normalize_logratios_by_length=dpo_normalize_logratios_by_length, + rpo_alpha=rpo_alpha, + simpo_gamma=simpo_gamma, + from_checkpoint=from_checkpoint, + from_hf_model=from_hf_model, + hf_model_revision=hf_model_revision, + hf_api_token=hf_api_token, + hf_output_repo_name=hf_output_repo_name, + ) + + if verbose: + rprint( + "Submitting a fine-tuning job with the following parameters:", + finetune_request, + ) + parameter_payload = finetune_request.model_dump(exclude_none=True) + + return self._client.post( + "/fine-tunes", + body=parameter_payload, + cast_to=FinetuneResponse, + ) + def retrieve( self, id: str, @@ -325,6 +500,178 @@ def with_streaming_response(self) -> AsyncFineTuningResourceWithStreamingRespons """ return AsyncFineTuningResourceWithStreamingResponse(self) + async def create( + self, + *, + training_file: str, + model: str | None = None, + n_epochs: int = 1, + validation_file: str | None = "", + n_evals: int | None = 0, + n_checkpoints: int | None = 1, + batch_size: int | Literal["max"] = "max", + learning_rate: float | None = 0.00001, + lr_scheduler_type: Literal["linear", "cosine"] = "cosine", + min_lr_ratio: float = 0.0, + scheduler_num_cycles: float = 0.5, + warmup_ratio: float = 0.0, + max_grad_norm: float = 1.0, + weight_decay: float = 0.0, + lora: bool = True, + lora_r: int | None = None, + lora_dropout: float | None = 0, + lora_alpha: float | None = None, + lora_trainable_modules: str | None = "all-linear", + suffix: str | None = None, + wandb_api_key: str | None = None, + wandb_base_url: str | None = None, + wandb_project_name: str | None = None, + wandb_name: str | None = None, + verbose: bool = False, + model_limits: FinetuneTrainingLimits | None = None, + train_on_inputs: bool | Literal["auto"] | None = None, + training_method: str = "sft", + dpo_beta: float | None = None, + dpo_normalize_logratios_by_length: bool = False, + rpo_alpha: float | None = None, + simpo_gamma: float | None = None, + from_checkpoint: str | None = None, + from_hf_model: str | None = None, + hf_model_revision: str | None = None, + hf_api_token: str | None = None, + hf_output_repo_name: str | None = None, + ) -> FinetuneResponse: + """ + Method to initiate a fine-tuning job + + Args: + training_file (str): File-ID of a file uploaded to the Together API + model (str, optional): Name of the base model to run fine-tune job on + n_epochs (int, optional): Number of epochs for fine-tuning. Defaults to 1. + validation file (str, optional): File ID of a file uploaded to the Together API for validation. + n_evals (int, optional): Number of evaluation loops to run. Defaults to 0. + n_checkpoints (int, optional): Number of checkpoints to save during fine-tuning. + Defaults to 1. + batch_size (int or "max"): Batch size for fine-tuning. Defaults to max. + learning_rate (float, optional): Learning rate multiplier to use for training + Defaults to 0.00001. + lr_scheduler_type (Literal["linear", "cosine"]): Learning rate scheduler type. Defaults to "cosine". + min_lr_ratio (float, optional): Min learning rate ratio of the initial learning rate for + the learning rate scheduler. Defaults to 0.0. + scheduler_num_cycles (float, optional): Number or fraction of cycles for the cosine learning rate scheduler. Defaults to 0.5. + warmup_ratio (float, optional): Warmup ratio for the learning rate scheduler. + max_grad_norm (float, optional): Max gradient norm. Defaults to 1.0, set to 0 to disable. + weight_decay (float, optional): Weight decay. Defaults to 0.0. + lora (bool, optional): Whether to use LoRA adapters. Defaults to True. + lora_r (int, optional): Rank of LoRA adapters. Defaults to 8. + lora_dropout (float, optional): Dropout rate for LoRA adapters. Defaults to 0. + lora_alpha (float, optional): Alpha for LoRA adapters. Defaults to 8. + lora_trainable_modules (str, optional): Trainable modules for LoRA adapters. Defaults to "all-linear". + suffix (str, optional): Up to 40 character suffix that will be added to your fine-tuned model name. + Defaults to None. + wandb_api_key (str, optional): API key for Weights & Biases integration. + Defaults to None. + wandb_base_url (str, optional): Base URL for Weights & Biases integration. + Defaults to None. + wandb_project_name (str, optional): Project name for Weights & Biases integration. + Defaults to None. + wandb_name (str, optional): Run name for Weights & Biases integration. + Defaults to None. + verbose (bool, optional): whether to print the job parameters before submitting a request. + Defaults to False. + model_limits (FinetuneTrainingLimits, optional): Limits for the hyperparameters the model in Fine-tuning. + Defaults to None. + train_on_inputs (bool or "auto", optional): Whether to mask the user messages in conversational data or prompts in instruction data. + "auto" will automatically determine whether to mask the inputs based on the data format. + For datasets with the "text" field (general format), inputs will not be masked. + For datasets with the "messages" field (conversational format) or "prompt" and "completion" fields + (Instruction format), inputs will be masked. + Defaults to None, or "auto" if training_method is "sft" (set in create_finetune_request). + training_method (str, optional): Training method. Defaults to "sft". + Supported methods: "sft", "dpo". + dpo_beta (float, optional): DPO beta parameter. Defaults to None. + dpo_normalize_logratios_by_length (bool): Whether or not normalize logratios by sample length. Defaults to False, + rpo_alpha (float, optional): RPO alpha parameter of DPO training to include NLL in the loss. Defaults to None. + simpo_gamma: (float, optional): SimPO gamma parameter. Defaults to None. + from_checkpoint (str, optional): The checkpoint identifier to continue training from a previous fine-tuning job. + The format: {$JOB_ID/$OUTPUT_MODEL_NAME}:{$STEP}. + The step value is optional, without it the final checkpoint will be used. + from_hf_model (str, optional): The Hugging Face Hub repo to start training from. + Should be as close as possible to the base model (specified by the `model` argument) in terms of architecture and size. + hf_model_revision (str, optional): The revision of the Hugging Face Hub model to continue training from. Defaults to None. + Example: hf_model_revision=None (defaults to the latest revision in `main`) or + hf_model_revision="607a30d783dfa663caf39e06633721c8d4cfcd7e" (specific commit). + hf_api_token (str, optional): API key for the Hugging Face Hub. Defaults to None. + hf_output_repo_name (str, optional): HF repo to upload the fine-tuned model to. Defaults to None. + + Returns: + FinetuneResponse: Object containing information about fine-tuning job. + """ + + if model_limits is None: + model_name = None + # mypy doesn't understand that model or from_checkpoint is not None + if model is not None: + model_name = model + elif from_checkpoint is not None: + model_name = from_checkpoint.split(":")[0] + else: + # this branch is unreachable, but mypy doesn't know that + pass + model_limits = await async_get_model_limits(self._client, str(model_name)) + + finetune_request = create_finetune_request( + model_limits=model_limits, + training_file=training_file, + model=model, + n_epochs=n_epochs, + validation_file=validation_file, + n_evals=n_evals, + n_checkpoints=n_checkpoints, + batch_size=batch_size, + learning_rate=learning_rate, + lr_scheduler_type=lr_scheduler_type, + min_lr_ratio=min_lr_ratio, + scheduler_num_cycles=scheduler_num_cycles, + warmup_ratio=warmup_ratio, + max_grad_norm=max_grad_norm, + weight_decay=weight_decay, + lora=lora, + lora_r=lora_r, + lora_dropout=lora_dropout, + lora_alpha=lora_alpha, + lora_trainable_modules=lora_trainable_modules, + suffix=suffix, + wandb_api_key=wandb_api_key, + wandb_base_url=wandb_base_url, + wandb_project_name=wandb_project_name, + wandb_name=wandb_name, + train_on_inputs=train_on_inputs, + training_method=training_method, + dpo_beta=dpo_beta, + dpo_normalize_logratios_by_length=dpo_normalize_logratios_by_length, + rpo_alpha=rpo_alpha, + simpo_gamma=simpo_gamma, + from_checkpoint=from_checkpoint, + from_hf_model=from_hf_model, + hf_model_revision=hf_model_revision, + hf_api_token=hf_api_token, + hf_output_repo_name=hf_output_repo_name, + ) + + if verbose: + rprint( + "Submitting a fine-tuning job with the following parameters:", + finetune_request, + ) + parameter_payload = finetune_request.model_dump(exclude_none=True) + + return await self._client.post( + "/fine-tunes", + body=parameter_payload, + cast_to=FinetuneResponse, + ) + async def retrieve( self, id: str, diff --git a/tests/unit/test_fine_tuning_resources.py b/tests/unit/test_fine_tuning_resources.py index 235f0afa..a8803ae4 100644 --- a/tests/unit/test_fine_tuning_resources.py +++ b/tests/unit/test_fine_tuning_resources.py @@ -1,11 +1,15 @@ +from typing import Union, Literal + import pytest from together.lib.types.fine_tuning import ( + FullTrainingType, + LoRATrainingType, FinetuneTrainingLimits, FinetuneFullTrainingLimits, FinetuneLoraTrainingLimits, ) -from together.lib.resources.fine_tuning import create_fine_tuning_request +from together.lib.resources.fine_tuning import create_finetune_request _MODEL_NAME = "meta-llama/Meta-Llama-3.1-8B-Instruct-Reference" _TRAINING_FILE = "file-7dbce5e9-7993-4520-9f3e-a7ece6c39d84" @@ -31,71 +35,88 @@ def test_simple_request(): - request = create_fine_tuning_request( + request = create_finetune_request( model_limits=_MODEL_LIMITS, model=_MODEL_NAME, training_file=_TRAINING_FILE, ) - assert request["model"] == _MODEL_NAME - assert request["training_file"] == _TRAINING_FILE - assert "learning_rate" in request - assert request["learning_rate"] > 0 - assert "n_epochs" in request - assert request["n_epochs"] > 0 - assert "warmup_ratio" in request - assert request["warmup_ratio"] == 0.0 - assert "training_type" in request - assert request["training_type"]["type"] == "Full" - assert "batch_size" in request - assert _MODEL_LIMITS.full_training is not None - assert request["batch_size"] == "max" + assert request.model == _MODEL_NAME + assert request.training_file == _TRAINING_FILE + assert request.learning_rate > 0 + assert request.n_epochs > 0 + assert request.warmup_ratio == 0.0 + assert request.training_type is not None + assert request.training_type.type == "Full" + assert request.batch_size == "max" def test_validation_file(): - request = create_fine_tuning_request( + request = create_finetune_request( model_limits=_MODEL_LIMITS, model=_MODEL_NAME, training_file=_TRAINING_FILE, validation_file=_VALIDATION_FILE, ) - assert request["training_file"] == _TRAINING_FILE - assert "validation_file" in request - assert request["validation_file"] == _VALIDATION_FILE + assert request.training_file == _TRAINING_FILE + assert request.validation_file == _VALIDATION_FILE def test_no_training_file(): with pytest.raises(TypeError, match="missing 1 required positional argument: 'training_file'"): - _ = create_fine_tuning_request( # type: ignore + _ = create_finetune_request( # type: ignore model_limits=_MODEL_LIMITS, model=_MODEL_NAME, ) def test_lora_request(): - request = create_fine_tuning_request( + request = create_finetune_request( model_limits=_MODEL_LIMITS, model=_MODEL_NAME, training_file=_TRAINING_FILE, lora=True, ) - assert "training_type" in request - assert request["training_type"]["type"] == "Lora" + assert isinstance(request.training_type, LoRATrainingType) + assert request.training_type.type == "Lora" assert _MODEL_LIMITS.lora_training is not None - assert request["training_type"]["lora_r"] == _MODEL_LIMITS.lora_training.max_rank - assert request["training_type"]["lora_alpha"] == _MODEL_LIMITS.lora_training.max_rank * 2 - assert "lora_dropout" in request["training_type"] - assert request["training_type"]["lora_dropout"] == 0.0 - assert "lora_trainable_modules" in request["training_type"] - assert request["training_type"]["lora_trainable_modules"] == "all-linear" - assert "batch_size" in request - assert request["batch_size"] == "max" + assert request.training_type.lora_r == _MODEL_LIMITS.lora_training.max_rank + assert request.training_type.lora_alpha == _MODEL_LIMITS.lora_training.max_rank * 2 + assert request.training_type.lora_dropout == 0.0 + assert request.training_type.lora_trainable_modules == "all-linear" + assert request.batch_size == "max" + + +@pytest.mark.parametrize("lora_dropout", [-1, 0, 0.5, 1.0, 10.0]) +def test_lora_request_with_lora_dropout(lora_dropout: float): + if 0 <= lora_dropout < 1: + request = create_finetune_request( + model_limits=_MODEL_LIMITS, + model=_MODEL_NAME, + training_file=_TRAINING_FILE, + lora=True, + lora_dropout=lora_dropout, + ) + assert isinstance(request.training_type, LoRATrainingType) + assert request.training_type.lora_dropout == lora_dropout + else: + with pytest.raises( + ValueError, + match=r"LoRA dropout must be in \[0, 1\) range.", + ): + create_finetune_request( + model_limits=_MODEL_LIMITS, + model=_MODEL_NAME, + training_file=_TRAINING_FILE, + lora=True, + lora_dropout=lora_dropout, + ) def test_dpo_request_lora(): - request = create_fine_tuning_request( + request = create_finetune_request( model_limits=_MODEL_LIMITS, model=_MODEL_NAME, training_file=_TRAINING_FILE, @@ -103,21 +124,18 @@ def test_dpo_request_lora(): lora=True, ) - assert "training_type" in request - assert request["training_type"]["type"] == "Lora" + assert isinstance(request.training_type, LoRATrainingType) + assert request.training_type.type == "Lora" assert _MODEL_LIMITS.lora_training is not None - assert request["training_type"]["lora_r"] == _MODEL_LIMITS.lora_training.max_rank - assert request["training_type"]["lora_alpha"] == _MODEL_LIMITS.lora_training.max_rank * 2 - assert "lora_dropout" in request["training_type"] - assert request["training_type"]["lora_dropout"] == 0.0 - assert "lora_trainable_modules" in request["training_type"] - assert request["training_type"]["lora_trainable_modules"] == "all-linear" - assert "batch_size" in request - assert request["batch_size"] == "max" + assert request.training_type.lora_r == _MODEL_LIMITS.lora_training.max_rank + assert request.training_type.lora_alpha == _MODEL_LIMITS.lora_training.max_rank * 2 + assert request.training_type.lora_dropout == 0.0 + assert request.training_type.lora_trainable_modules == "all-linear" + assert request.batch_size == "max" def test_dpo_request(): - request = create_fine_tuning_request( + request = create_finetune_request( model_limits=_MODEL_LIMITS, model=_MODEL_NAME, training_file=_TRAINING_FILE, @@ -125,23 +143,20 @@ def test_dpo_request(): lora=False, ) - assert "training_type" in request - assert request["training_type"]["type"] == "Full" - assert "batch_size" in request - assert _MODEL_LIMITS.full_training is not None - assert request["batch_size"] == "max" + assert isinstance(request.training_type, FullTrainingType) + assert request.training_type.type == "Full" + assert request.batch_size == "max" def test_from_checkpoint_request(): - request = create_fine_tuning_request( + request = create_finetune_request( model_limits=_MODEL_LIMITS, training_file=_TRAINING_FILE, from_checkpoint=_FROM_CHECKPOINT, ) - assert request["model"] == "" - assert "from_checkpoint" in request - assert request["from_checkpoint"] == _FROM_CHECKPOINT + assert request.model is None + assert request.from_checkpoint == _FROM_CHECKPOINT def test_both_from_checkpoint_model_name(): @@ -149,7 +164,7 @@ def test_both_from_checkpoint_model_name(): ValueError, match="You must specify either a model or a checkpoint to start a job from, not both", ): - _ = create_fine_tuning_request( + _ = create_finetune_request( model_limits=_MODEL_LIMITS, model=_MODEL_NAME, training_file=_TRAINING_FILE, @@ -159,7 +174,7 @@ def test_both_from_checkpoint_model_name(): def test_no_from_checkpoint_no_model_name(): with pytest.raises(ValueError, match="You must specify either a model or a checkpoint"): - _ = create_fine_tuning_request( + _ = create_finetune_request( model_limits=_MODEL_LIMITS, training_file=_TRAINING_FILE, ) @@ -178,7 +193,7 @@ def test_batch_size_limit(batch_size: int, use_lora: bool): f"Requested batch size of {batch_size} is higher that the maximum allowed value of {max_batch_size}" ) with pytest.raises(ValueError, match=error_message): - _ = create_fine_tuning_request( + _ = create_finetune_request( model_limits=_MODEL_LIMITS, model=_MODEL_NAME, training_file=_TRAINING_FILE, @@ -191,7 +206,7 @@ def test_batch_size_limit(batch_size: int, use_lora: bool): f"Requested batch size of {batch_size} is lower that the minimum allowed value of {min_batch_size}" ) with pytest.raises(ValueError, match=error_message): - _ = create_fine_tuning_request( + _ = create_finetune_request( model_limits=_MODEL_LIMITS, model=_MODEL_NAME, training_file=_TRAINING_FILE, @@ -202,7 +217,7 @@ def test_batch_size_limit(batch_size: int, use_lora: bool): def test_non_lora_model(): with pytest.raises(ValueError, match="LoRA adapters are not supported for the selected model."): - _ = create_fine_tuning_request( + _ = create_finetune_request( model_limits=FinetuneTrainingLimits( max_num_epochs=20, max_learning_rate=1.0, @@ -222,7 +237,7 @@ def test_non_lora_model(): def test_non_full_model(): with pytest.raises(ValueError, match="Full training is not supported for the selected model."): - _ = create_fine_tuning_request( + _ = create_finetune_request( model_limits=FinetuneTrainingLimits( max_num_epochs=20, max_learning_rate=1.0, @@ -245,7 +260,7 @@ def test_non_full_model(): @pytest.mark.parametrize("warmup_ratio", [-1.0, 2.0]) def test_bad_warmup(warmup_ratio: float): with pytest.raises(ValueError, match="Warmup ratio should be between 0 and 1"): - _ = create_fine_tuning_request( + _ = create_finetune_request( model_limits=_MODEL_LIMITS, model=_MODEL_NAME, training_file=_TRAINING_FILE, @@ -256,7 +271,7 @@ def test_bad_warmup(warmup_ratio: float): @pytest.mark.parametrize("min_lr_ratio", [-1.0, 2.0]) def test_bad_min_lr_ratio(min_lr_ratio: float): with pytest.raises(ValueError, match="Min learning rate ratio should be between 0 and 1"): - _ = create_fine_tuning_request( + _ = create_finetune_request( model_limits=_MODEL_LIMITS, model=_MODEL_NAME, training_file=_TRAINING_FILE, @@ -267,7 +282,7 @@ def test_bad_min_lr_ratio(min_lr_ratio: float): @pytest.mark.parametrize("max_grad_norm", [-1.0, -0.01]) def test_bad_max_grad_norm(max_grad_norm: float): with pytest.raises(ValueError, match="Max gradient norm should be non-negative"): - _ = create_fine_tuning_request( + _ = create_finetune_request( model_limits=_MODEL_LIMITS, model=_MODEL_NAME, training_file=_TRAINING_FILE, @@ -278,7 +293,7 @@ def test_bad_max_grad_norm(max_grad_norm: float): @pytest.mark.parametrize("weight_decay", [-1.0, -0.01]) def test_bad_weight_decay(weight_decay: float): with pytest.raises(ValueError, match="Weight decay should be non-negative"): - _ = create_fine_tuning_request( + _ = create_finetune_request( model_limits=_MODEL_LIMITS, model=_MODEL_NAME, training_file=_TRAINING_FILE, @@ -288,9 +303,36 @@ def test_bad_weight_decay(weight_decay: float): def test_bad_training_method(): with pytest.raises(ValueError, match="training_method must be one of .*"): - _ = create_fine_tuning_request( + _ = create_finetune_request( model_limits=_MODEL_LIMITS, model=_MODEL_NAME, training_file=_TRAINING_FILE, training_method="NON_SFT", ) + + +@pytest.mark.parametrize("train_on_inputs", [True, False, "auto", None]) +def test_train_on_inputs_for_sft(train_on_inputs: Union[bool, Literal["auto"], None]): + request = create_finetune_request( + model_limits=_MODEL_LIMITS, + model=_MODEL_NAME, + training_file=_TRAINING_FILE, + training_method="sft", + train_on_inputs=train_on_inputs, + ) + assert request.training_method.method == "sft" + if isinstance(train_on_inputs, bool): + assert request.training_method.train_on_inputs is train_on_inputs + else: + assert request.training_method.train_on_inputs == "auto" + + +def test_train_on_inputs_not_supported_for_dpo(): + with pytest.raises(ValueError, match="train_on_inputs is only supported for SFT training"): + _ = create_finetune_request( + model_limits=_MODEL_LIMITS, + model=_MODEL_NAME, + training_file=_TRAINING_FILE, + training_method="dpo", + train_on_inputs=True, + ) From 35422cb1eef730a04117d83c8df08442461f5ec1 Mon Sep 17 00:00:00 2001 From: Blaine Kasten Date: Fri, 21 Nov 2025 08:58:40 -0600 Subject: [PATCH 7/8] chore: Fix examples --- examples/fine_tuning.py | 2 +- examples/image.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/fine_tuning.py b/examples/fine_tuning.py index 3d731939..d32a4b85 100644 --- a/examples/fine_tuning.py +++ b/examples/fine_tuning.py @@ -26,5 +26,5 @@ print(e) # download the model -downloaded = client.fine_tuning.download(ft_id=fine_tune_id) +downloaded = client.fine_tuning.content(ft_id=fine_tune_id) print(downloaded) diff --git a/examples/image.py b/examples/image.py index 596d92e3..e6f26316 100644 --- a/examples/image.py +++ b/examples/image.py @@ -5,7 +5,7 @@ client = Together(api_key="04cf1e314be9c686cd14b3881f5c4ad76505af4c93a8d3fe6ef62337114d1d51") -image = client.images.create( +image = client.images.generate( model="runwayml/stable-diffusion-v1-5", prompt="space robots", n=1, From 0fe20a89aa7d5d0a061f52d0816b4ce6b32d800c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 21 Nov 2025 14:58:58 +0000 Subject: [PATCH 8/8] release: 2.0.0-alpha.1 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 24 ++++++++++++++++++++++++ pyproject.toml | 2 +- src/together/_version.py | 2 +- 4 files changed, 27 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index f4710698..6e011e8a 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.1.0-alpha.28" + ".": "2.0.0-alpha.1" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 1c6284d2..9478df67 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,29 @@ # Changelog +## 2.0.0-alpha.1 (2025-11-21) + +Full Changelog: [v0.1.0-alpha.28...v2.0.0-alpha.1](https://github.com/togethercomputer/together-py/compare/v0.1.0-alpha.28...v2.0.0-alpha.1) + +### ⚠ BREAKING CHANGES + +* **api:** Update method signature for reranking to `rerank.create()` +* **api:** Change Fine Tuning method name from `download()` to `content()` to align with other namespaces +* **api:** For the TS SDK the `images.create` is now `images.generate` + +### Features + +* **api:** api update ([921fa59](https://github.com/togethercomputer/together-py/commit/921fa591a5a9c70f96d457a7b59749dfdfb6d4d6)) +* **api:** Change fine tuning download method to `.create` ([aa27907](https://github.com/togethercomputer/together-py/commit/aa279076c524956e204cb68b7424048a4f93a17d)) +* **api:** Change image creation signature to `images.generate` ([a6e3ad7](https://github.com/togethercomputer/together-py/commit/a6e3ad792393be978b123c87707afe779ef8df34)) +* **api:** Change rerank method signature ([338c415](https://github.com/togethercomputer/together-py/commit/338c415d1cee04520413717ee821f47a64316211)) +* **api:** Port finetuning create code from together-python ([#176](https://github.com/togethercomputer/together-py/issues/176)) ([ef3bd52](https://github.com/togethercomputer/together-py/commit/ef3bd5245ee254269653ff8e6db1651cfcf89c6d)) + + +### Chores + +* **api:** Remove auto-generated fine_tuning.create method from Python SDK ([c533f29](https://github.com/togethercomputer/together-py/commit/c533f29e2b94d5d9ca97ed50c181dae0fc2dcd7b)) +* Fix examples ([35422cb](https://github.com/togethercomputer/together-py/commit/35422cb1eef730a04117d83c8df08442461f5ec1)) + ## 0.1.0-alpha.28 (2025-11-18) Full Changelog: [v0.1.0-alpha.27...v0.1.0-alpha.28](https://github.com/togethercomputer/together-py/compare/v0.1.0-alpha.27...v0.1.0-alpha.28) diff --git a/pyproject.toml b/pyproject.toml index 856c537e..b39dfdf9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "together" -version = "0.1.0-alpha.28" +version = "2.0.0-alpha.1" description = "The official Python library for the together API" dynamic = ["readme"] license = "Apache-2.0" diff --git a/src/together/_version.py b/src/together/_version.py index 3fc7787f..a5854438 100644 --- a/src/together/_version.py +++ b/src/together/_version.py @@ -1,4 +1,4 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. __title__ = "together" -__version__ = "0.1.0-alpha.28" # x-release-please-version +__version__ = "2.0.0-alpha.1" # x-release-please-version