From 4f4d6fade56e1e4a7fedee56d47039541824904e Mon Sep 17 00:00:00 2001
From: "A. Ammar Naseer" <ahmedammarnaseer@gmail.com>
Date: Fri, 27 Jun 2025 18:07:38 +0100
Subject: [PATCH 1/3] feat(cli): add support for fine_tuning.jobs (#1224)

---
 src/openai/cli/_api/_main.py                |   3 +-
 src/openai/cli/_api/fine_tuning/__init__.py |  13 ++
 src/openai/cli/_api/fine_tuning/jobs.py     | 169 ++++++++++++++++++++
 3 files changed, 184 insertions(+), 1 deletion(-)
 create mode 100644 src/openai/cli/_api/fine_tuning/__init__.py
 create mode 100644 src/openai/cli/_api/fine_tuning/jobs.py

diff --git a/src/openai/cli/_api/_main.py b/src/openai/cli/_api/_main.py
index fe5a5e6fc0..b04a3e52a4 100644
--- a/src/openai/cli/_api/_main.py
+++ b/src/openai/cli/_api/_main.py
@@ -2,7 +2,7 @@
 
 from argparse import ArgumentParser
 
-from . import chat, audio, files, image, models, completions
+from . import chat, audio, files, image, models, completions, fine_tuning
 
 
 def register_commands(parser: ArgumentParser) -> None:
@@ -14,3 +14,4 @@ def register_commands(parser: ArgumentParser) -> None:
     files.register(subparsers)
     models.register(subparsers)
     completions.register(subparsers)
+    fine_tuning.register(subparsers)
diff --git a/src/openai/cli/_api/fine_tuning/__init__.py b/src/openai/cli/_api/fine_tuning/__init__.py
new file mode 100644
index 0000000000..11a2dfccbd
--- /dev/null
+++ b/src/openai/cli/_api/fine_tuning/__init__.py
@@ -0,0 +1,13 @@
+from __future__ import annotations
+
+from typing import TYPE_CHECKING
+from argparse import ArgumentParser
+
+from . import jobs
+
+if TYPE_CHECKING:
+    from argparse import _SubParsersAction
+
+
+def register(subparser: _SubParsersAction[ArgumentParser]) -> None:
+    jobs.register(subparser)
diff --git a/src/openai/cli/_api/fine_tuning/jobs.py b/src/openai/cli/_api/fine_tuning/jobs.py
new file mode 100644
index 0000000000..806fa0f788
--- /dev/null
+++ b/src/openai/cli/_api/fine_tuning/jobs.py
@@ -0,0 +1,169 @@
+from __future__ import annotations
+
+import json
+from typing import TYPE_CHECKING
+from argparse import ArgumentParser
+
+from ..._utils import get_client, print_model
+from ...._types import NOT_GIVEN, NotGivenOr
+from ..._models import BaseModel
+from ....pagination import SyncCursorPage
+from ....types.fine_tuning import (
+    FineTuningJob,
+    FineTuningJobEvent,
+)
+
+if TYPE_CHECKING:
+    from argparse import _SubParsersAction
+
+
+def register(subparser: _SubParsersAction[ArgumentParser]) -> None:
+    sub = subparser.add_parser("fine_tuning.jobs.create")
+    sub.add_argument(
+        "-m",
+        "--model",
+        help="The model to fine-tune.",
+        required=True,
+    )
+    sub.add_argument(
+        "-F",
+        "--training-file",
+        help="The training file to fine-tune the model on.",
+        required=True,
+    )
+    sub.add_argument(
+        "-H",
+        "--hyperparameters",
+        help="JSON string of hyperparameters to use for fine-tuning.",
+        type=str,
+    )
+    sub.add_argument(
+        "-s",
+        "--suffix",
+        help="A suffix to add to the fine-tuned model name.",
+    )
+    sub.add_argument(
+        "-V",
+        "--validation-file",
+        help="The validation file to use for fine-tuning.",
+    )
+    sub.set_defaults(func=CLIFineTuningJobs.create, args_model=CLIFineTuningJobsCreateArgs)
+
+    sub = subparser.add_parser("fine_tuning.jobs.retrieve")
+    sub.add_argument(
+        "-i",
+        "--id",
+        help="The ID of the fine-tuning job to retrieve.",
+        required=True,
+    )
+    sub.set_defaults(func=CLIFineTuningJobs.retrieve, args_model=CLIFineTuningJobsRetrieveArgs)
+
+    sub = subparser.add_parser("fine_tuning.jobs.list")
+    sub.add_argument(
+        "-a",
+        "--after",
+        help="Identifier for the last job from the previous pagination request. If provided, only jobs created after this job will be returned.",
+    )
+    sub.add_argument(
+        "-l",
+        "--limit",
+        help="Number of fine-tuning jobs to retrieve.",
+        type=int,
+    )
+    sub.set_defaults(func=CLIFineTuningJobs.list, args_model=CLIFineTuningJobsListArgs)
+
+    sub = subparser.add_parser("fine_tuning.jobs.cancel")
+    sub.add_argument(
+        "-i",
+        "--id",
+        help="The ID of the fine-tuning job to cancel.",
+        required=True,
+    )
+    sub.set_defaults(func=CLIFineTuningJobs.cancel, args_model=CLIFineTuningJobsCancelArgs)
+
+    sub = subparser.add_parser("fine_tuning.jobs.list_events")
+    sub.add_argument(
+        "-i",
+        "--id",
+        help="The ID of the fine-tuning job to list events for.",
+        required=True,
+    )
+    sub.add_argument(
+        "-a",
+        "--after",
+        help="Identifier for the last event from the previous pagination request. If provided, only events created after this event will be returned.",
+    )
+    sub.add_argument(
+        "-l",
+        "--limit",
+        help="Number of fine-tuning job events to retrieve.",
+        type=int,
+    )
+    sub.set_defaults(func=CLIFineTuningJobs.list_events, args_model=CLIFineTuningJobsListEventsArgs)
+
+
+class CLIFineTuningJobsCreateArgs(BaseModel):
+    model: str
+    training_file: str
+    hyperparameters: NotGivenOr[str] = NOT_GIVEN
+    suffix: NotGivenOr[str] = NOT_GIVEN
+    validation_file: NotGivenOr[str] = NOT_GIVEN
+
+
+class CLIFineTuningJobsRetrieveArgs(BaseModel):
+    id: str
+
+
+class CLIFineTuningJobsListArgs(BaseModel):
+    after: NotGivenOr[str] = NOT_GIVEN
+    limit: NotGivenOr[int] = NOT_GIVEN
+
+
+class CLIFineTuningJobsCancelArgs(BaseModel):
+    id: str
+
+
+class CLIFineTuningJobsListEventsArgs(BaseModel):
+    id: str
+    after: NotGivenOr[str] = NOT_GIVEN
+    limit: NotGivenOr[int] = NOT_GIVEN
+
+
+class CLIFineTuningJobs:
+    @staticmethod
+    def create(args: CLIFineTuningJobsCreateArgs) -> None:
+        hyperparameters = json.loads(str(args.hyperparameters)) if args.hyperparameters is not NOT_GIVEN else NOT_GIVEN
+        fine_tuning_job: FineTuningJob = get_client().fine_tuning.jobs.create(
+            model=args.model,
+            training_file=args.training_file,
+            hyperparameters=hyperparameters,
+            suffix=args.suffix,
+            validation_file=args.validation_file,
+        )
+        print_model(fine_tuning_job)
+
+    @staticmethod
+    def retrieve(args: CLIFineTuningJobsRetrieveArgs) -> None:
+        fine_tuning_job: FineTuningJob = get_client().fine_tuning.jobs.retrieve(fine_tuning_job_id=args.id)
+        print_model(fine_tuning_job)
+
+    @staticmethod
+    def list(args: CLIFineTuningJobsListArgs) -> None:
+        fine_tuning_jobs: SyncCursorPage[FineTuningJob] = get_client().fine_tuning.jobs.list(
+            after=args.after or NOT_GIVEN, limit=args.limit or NOT_GIVEN
+        )
+        print_model(fine_tuning_jobs)
+
+    @staticmethod
+    def cancel(args: CLIFineTuningJobsCancelArgs) -> None:
+        fine_tuning_job: FineTuningJob = get_client().fine_tuning.jobs.cancel(fine_tuning_job_id=args.id)
+        print_model(fine_tuning_job)
+
+    @staticmethod
+    def list_events(args: CLIFineTuningJobsListEventsArgs) -> None:
+        fine_tuning_job_events: SyncCursorPage[FineTuningJobEvent] = get_client().fine_tuning.jobs.list_events(
+            fine_tuning_job_id=args.id,
+            after=args.after or NOT_GIVEN,
+            limit=args.limit or NOT_GIVEN,
+        )
+        print_model(fine_tuning_job_events)

From 4b4d4864b041d2d93a03f4b36305b4d9c4af5b37 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
 <142633134+stainless-app[bot]@users.noreply.github.com>
Date: Fri, 27 Jun 2025 21:16:22 +0000
Subject: [PATCH 2/3] codegen metadata

---
 .stats.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.stats.yml b/.stats.yml
index cb7aea1814..535155f4ae 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
 configured_endpoints: 111
 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-a473967d1766dc155994d932fbc4a5bcbd1c140a37c20d0a4065e1bf0640536d.yml
 openapi_spec_hash: 67cdc62b0d6c8b1de29b7dc54b265749
-config_hash: 05c7d4a6f4d5983fe9550457114b47dd
+config_hash: 7b53f96f897ca1b3407a5341a6f820db

From 1dbb72b290cb360a9ccbcec17425aaba4ad114b0 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
 <142633134+stainless-app[bot]@users.noreply.github.com>
Date: Fri, 27 Jun 2025 21:16:50 +0000
Subject: [PATCH 3/3] release: 1.93.0

---
 .release-please-manifest.json | 2 +-
 CHANGELOG.md                  | 8 ++++++++
 pyproject.toml                | 2 +-
 src/openai/_version.py        | 2 +-
 4 files changed, 11 insertions(+), 3 deletions(-)

diff --git a/.release-please-manifest.json b/.release-please-manifest.json
index 27bf032fe4..3ceb8e2f5b 100644
--- a/.release-please-manifest.json
+++ b/.release-please-manifest.json
@@ -1,3 +1,3 @@
 {
-  ".": "1.92.3"
+  ".": "1.93.0"
 }
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ac283868ca..3274b67105 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,13 @@
 # Changelog
 
+## 1.93.0 (2025-06-27)
+
+Full Changelog: [v1.92.3...v1.93.0](https://github.com/openai/openai-python/compare/v1.92.3...v1.93.0)
+
+### Features
+
+* **cli:** add support for fine_tuning.jobs ([#1224](https://github.com/openai/openai-python/issues/1224)) ([e362bfd](https://github.com/openai/openai-python/commit/e362bfd10dfd04176560b964470ab0c517c601f3))
+
 ## 1.92.3 (2025-06-27)
 
 Full Changelog: [v1.92.2...v1.92.3](https://github.com/openai/openai-python/compare/v1.92.2...v1.92.3)
diff --git a/pyproject.toml b/pyproject.toml
index 2f44e58aac..0a3e3e1ca8 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
 [project]
 name = "openai"
-version = "1.92.3"
+version = "1.93.0"
 description = "The official Python library for the openai API"
 dynamic = ["readme"]
 license = "Apache-2.0"
diff --git a/src/openai/_version.py b/src/openai/_version.py
index 81494049e6..84c3a45a00 100644
--- a/src/openai/_version.py
+++ b/src/openai/_version.py
@@ -1,4 +1,4 @@
 # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
 
 __title__ = "openai"
-__version__ = "1.92.3"  # x-release-please-version
+__version__ = "1.93.0"  # x-release-please-version
