Skip to content

feat(clients): add Together AI fine-tuning provider#9987

Open
katherineahn wants to merge 4 commits into
stanfordnlp:mainfrom
katherineahn:feat/togetherai-provider
Open

feat(clients): add Together AI fine-tuning provider#9987
katherineahn wants to merge 4 commits into
stanfordnlp:mainfrom
katherineahn:feat/togetherai-provider

Conversation

@katherineahn

Copy link
Copy Markdown

What

Adds TogetherProvider, a fine-tuning provider for Together AI, mirroring dspy/clients/databricks.py.

Details

finetune() saves training data to JSONL, uploads it, creates a Together fine-tune job, polls until it completes (raises on error/cancelled), and returns the model as together_ai/<name>. together is imported lazily (optional dependency). TrainingJobTogether.status() reports job status, and is_provider_model() recognizes together_ai/ model names.

Tests

tests/clients/test_togetherai.py — a pure-logic test for is_provider_model, plus a mocked test that runs the full finetune() flow against a fake together client (no live API calls; runs in CI).

🤖 Generated with Claude Code

@greptile-apps

greptile-apps Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds Together AI as a fine-tuning provider. The main changes are:

  • New TogetherProvider and TrainingJobTogether classes for Together fine-tuning.
  • JSONL training data upload, job creation, polling, and prefixed model-name return.
  • Tests for provider model detection, pre-start status, and the mocked fine-tuning flow.

Confidence Score: 4/5

Mostly safe to merge after the model-name handling bug is fixed.

The main fine-tuning flow is covered by tests, but prefix removal can submit the wrong base model for names containing together_ai/ after the leading provider prefix.

dspy/clients/togetherai.py

T-Rex T-Rex Logs

What T-Rex did

  • We ran a focused pytest harness against TogetherProvider.finetune with a mocked client and found that the model argument was org/model instead of the expected org/together_ai/model, and the assertion failed.
  • We validated the broader contract and confirmed that the provider tests and lint checks completed successfully with exit code 0.
  • Artifacts documenting the repro harness, verbose test output, and the pytest and lint results were uploaded.

View all artifacts

T-Rex Ran code and verified through T-Rex

Important Files Changed

Filename Overview
dspy/clients/togetherai.py Adds the Together fine-tuning provider flow; prefix stripping still over-applies to internal together_ai/ substrings.
tests/clients/test_togetherai.py Adds mocked coverage for provider model detection, pre-start status, and the successful fine-tuning path.

Reviews (5): Last reviewed commit: "fix(clients): strip together_ai/ prefix ..." | Re-trigger Greptile

Comment thread dspy/clients/togetherai.py
Comment thread dspy/clients/togetherai.py
Comment thread dspy/clients/togetherai.py
Comment thread dspy/clients/togetherai.py Outdated
@katherineahn

Copy link
Copy Markdown
Author

Thanks for the review! Addressed:

  • Training data is now validated against its declared format via validate_data_format.
  • The local JSONL is deleted after upload (try/finally).
  • finetune() raises a clear error if a completed job returns no output model name.

On the fresh Together client per poll tick — left as-is intentionally: it's created once per 60s poll and is cheap (mirrors the Databricks provider), so reusing one would add complexity for negligible benefit.

Comment thread dspy/clients/togetherai.py
Katherine Ahn and others added 3 commits July 19, 2026 22:16
Adds TogetherProvider, a fine-tuning Provider for Together AI (mirrors databricks.py). It saves training data to JSONL, uploads it, creates a fine-tune job, polls until completion, and returns the resulting together_ai/<name> model. Includes mocked unit tests that exercise the full finetune() flow without live API calls.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- validate training data against its declared format via validate_data_format
- delete the local JSONL after upload (try/finally)
- raise a clear error if a completed job returns no output model name

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Return None (matching the databricks provider) instead of calling the Together API with a None job id. Adds a test for the pre-job case.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@katherineahn
katherineahn force-pushed the feat/togetherai-provider branch from 45d1a3a to e52f32a Compare July 20, 2026 05:18
@katherineahn

Copy link
Copy Markdown
Author

Hi @isaacbmiller — thanks for all the review-and-merge work on the repo lately! Checking in on this one when you have a moment.

The Greptile feedback is addressed, and I've just rebased onto the latest main and verified the tests pass locally. The "Lint, Test, and Build" workflow is queued awaiting approval — would you be able to kick it off when you get a chance?

For context: this provider mirrors the existing databricks.py conventions closely, the tests are fully mocked (no live API calls), and I'm happy to maintain it going forward. Happy to make any changes if something's needed — thanks!

Comment thread dspy/clients/togetherai.py
…PI call

Together's fine-tuning API expects the bare model name, but finetune() was
forwarding the full DSPy/LiteLLM-prefixed name (e.g. together_ai/meta-llama/
Llama-3-8b). Add _remove_provider_prefix() (mirrors OpenAIProvider) and strip
the prefix before calling client.fine_tuning.create. Adds a test asserting the
bare model name is passed to the API.
@katherineahn

Copy link
Copy Markdown
Author

Quick update: pushed a fix for the model-prefix issue Greptile flagged. Added a _remove_provider_prefix helper (mirroring OpenAIProvider) so the bare model name is passed to Together's fine-tuning API, plus a test asserting that. All Greptile review threads are resolved now. The Lint/Test/Build workflow is still queued awaiting approval to run whenever a maintainer has a moment. Thanks!

def _remove_provider_prefix(model: str) -> str:
# Together's API wants the bare model name, so strip DSPy's "together_ai/" routing prefix.
provider_prefix = "together_ai/"
return model.replace(provider_prefix, "")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Strip only the prefix
_remove_provider_prefix() removes every together_ai/ segment in the model string, not just the routing prefix. A valid bare Together model path that itself contains this substring, e.g. org/together_ai/model, is rewritten to org/model before fine_tuning.create, so the API receives the wrong base model.

Suggested change
return model.replace(provider_prefix, "")
return model[len(provider_prefix) :] if model.startswith(provider_prefix) else model
Artifacts

Repro: focused pytest harness for TogetherProvider.finetune model argument

  • Evidence file captured while the check ran.

Repro: verbose pytest output showing wrong create model argument and assertion failure

  • The full command output behind this check.

View artifacts

T-Rex Ran code and verified through T-Rex

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant