diff --git a/.github/workflows/sync-together-ai-models.yml b/.github/workflows/sync-together-ai-models.yml
new file mode 100644
index 00000000000..f1a8a841d0f
--- /dev/null
+++ b/.github/workflows/sync-together-ai-models.yml
@@ -0,0 +1,68 @@
+name: Sync Together AI model registry
+
+on:
+ schedule:
+ - cron: "30 6 * * *"
+ workflow_dispatch:
+
+permissions:
+ contents: write
+ pull-requests: write
+
+jobs:
+ sync_together_ai_models:
+ if: github.repository == 'BerriAI/litellm'
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
+ with:
+ ref: litellm_internal_staging
+ persist-credentials: false
+ - name: Set up uv
+ uses: ./.github/actions/setup-uv-with-retries
+ with:
+ version: "0.10.9"
+ - name: Look for an already-open sync PR
+ id: existing
+ run: |
+ open_pr="$(gh pr list --repo "$GITHUB_REPOSITORY" --state open --limit 1000 --json headRefName \
+ --jq '[.[].headRefName | select(startswith("litellm_together_registry_sync_"))] | first // empty')"
+ echo "open_pr=$open_pr" >> "$GITHUB_OUTPUT"
+ if [ -n "$open_pr" ]; then
+ echo "An open sync PR already exists on branch $open_pr; skipping this run."
+ fi
+ env:
+ GH_TOKEN: ${{ secrets.GH_TOKEN }}
+ - name: Run the sync
+ if: steps.existing.outputs.open_pr == ''
+ run: |
+ uv run --frozen python scripts/sync_together_ai_models.py --write --pr-body-file "$RUNNER_TEMP/pr_body.md"
+ env:
+ TOGETHER_API_KEY: ${{ secrets.TOGETHER_API_KEY }}
+ - name: Regenerate the JSON schema
+ if: steps.existing.outputs.open_pr == ''
+ run: |
+ uv run --frozen python ci_cd/generate_model_prices_schema.py
+ - name: Create a pull request when the registry changed
+ if: steps.existing.outputs.open_pr == ''
+ run: |
+ if git diff --quiet; then
+ echo "Registry already in sync; no PR needed."
+ exit 0
+ fi
+ branch="litellm_together_registry_sync_$(date +'%Y-%m-%d')"
+ git config user.name "github-actions[bot]"
+ git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
+ git checkout -b "$branch"
+ git add model_prices_and_context_window.json \
+ litellm/model_prices_and_context_window_backup.json \
+ model_prices_and_context_window.schema.json
+ git commit -m "feat(models): sync together_ai model registry $(date +'%Y-%m-%d')"
+ gh auth setup-git
+ git push origin "$branch"
+ gh pr create --title "feat(models): sync together_ai model registry" \
+ --body-file "$RUNNER_TEMP/pr_body.md" \
+ --head "$branch" \
+ --base litellm_internal_staging
+ env:
+ GH_TOKEN: ${{ secrets.GH_TOKEN }}
diff --git a/scripts/sync_together_ai_models.py b/scripts/sync_together_ai_models.py
new file mode 100644
index 00000000000..97b308fb660
--- /dev/null
+++ b/scripts/sync_together_ai_models.py
@@ -0,0 +1,539 @@
+"""Sync the together_ai entries of model_prices_and_context_window.json with Together's live serverless catalog.
+
+Pulls ``GET https://api.together.ai/v1/models?serverless`` plus the deprecations doc, maps API fields onto
+registry fields, merges the reviewed capability rules below for everything the API cannot express, and diffs
+the result against the registry. Dry run (the default) prints the diff summary and the generated PR body;
+``--write`` applies the changes to the root cost map and its ``litellm/`` backup copy.
+
+Policy highlights:
+- Prices arrive per 1M tokens with float artifacts and are normalized to clean per-token values.
+- A registry entry absent from the serverless catalog is marked with ``deprecation_date`` from the docs
+ deprecation table, never deleted; absences with no docs date are surfaced for a human call.
+- Availability comes from the API: a model the docs list as removed but the API still serves stays live,
+ with the conflict surfaced as a warning.
+- Manually curated values the API cannot express (``metadata.successor``, ``max_output_tokens`` on existing
+ entries, capability flags no rule covers) are never overwritten; conflicts are surfaced instead.
+"""
+
+import argparse
+import json
+import os
+import re
+import sys
+from collections.abc import Mapping, Sequence
+from dataclasses import dataclass, field
+from pathlib import Path
+from types import MappingProxyType
+from typing import Final
+
+import httpx
+from pydantic import BaseModel, TypeAdapter, ValidationError
+
+MODELS_URL: Final = "https://api.together.ai/v1/models?serverless"
+DEPRECATIONS_URL: Final = "https://docs.together.ai/docs/deprecations.md"
+PROVIDER: Final = "together_ai"
+PREFIX: Final = "together_ai/"
+SOURCE_URL: Final = "https://docs.together.ai/docs/serverless-models"
+COST_MAP_RELPATHS: Final = (
+ "model_prices_and_context_window.json",
+ "litellm/model_prices_and_context_window_backup.json",
+)
+
+TYPE_TO_MODE: Final = MappingProxyType({"chat": "chat", "embedding": "embedding", "moderation": "chat"})
+
+
+class SyncError(RuntimeError):
+ pass
+
+
+class CatalogPricing(BaseModel):
+ input: float
+ output: float
+ cached_input: float | None = None
+
+
+class CatalogModel(BaseModel):
+ id: str
+ type: str
+ context_length: int | None = None
+ pricing: CatalogPricing
+
+
+CATALOG_ADAPTER: Final = TypeAdapter(list[CatalogModel])
+
+RegistryEntry = dict[str, object]
+CostMap = dict[str, object]
+
+
+@dataclass(frozen=True, slots=True)
+class CapabilityRule:
+ model_id: str
+ fields: Mapping[str, bool | int]
+ provenance: str
+
+
+def _rule(model_id: str, provenance: str, **fields: bool | int) -> CapabilityRule:
+ return CapabilityRule(model_id=model_id, fields=MappingProxyType(dict(fields)), provenance=provenance)
+
+
+_TOOLS: Final = MappingProxyType(
+ {
+ "supports_function_calling": True,
+ "supports_parallel_function_calling": True,
+ "supports_response_schema": True,
+ "supports_tool_choice": True,
+ }
+)
+
+CAPABILITY_RULES: Final = (
+ _rule(
+ "MiniMaxAI/MiniMax-M3",
+ "reviewed for the LIT-5968 backfill against https://www.together.ai/models/minimax-m3",
+ **_TOOLS,
+ supports_reasoning=True,
+ supports_vision=True,
+ ),
+ _rule("Prism-ML/Ternary-Bonsai-27B", "reviewed for the LIT-5968 backfill; no tool or vision support documented"),
+ _rule(
+ "Qwen/Qwen3.5-9B",
+ "reviewed for the LIT-5968 backfill against https://www.together.ai/models/qwen3-5-9b",
+ **_TOOLS,
+ supports_reasoning=True,
+ supports_vision=True,
+ ),
+ _rule(
+ "Qwen/Qwen3.6-Plus",
+ "reviewed for the LIT-5968 backfill; hybrid reasoning model without a documented tools contract",
+ supports_reasoning=True,
+ ),
+ _rule("Qwen/Qwen3.7-Max", "reviewed for the LIT-5968 backfill; no tool or vision support documented"),
+ _rule("Qwen/Qwen3.7-Plus", "reviewed for the LIT-5968 backfill; no tool or vision support documented"),
+ _rule("Qwen/Qwen3.8-2.4T-A95B", "reviewed for the LIT-5968 backfill; no tool or vision support documented"),
+ _rule("arize-ai/qwen-2-1.5b-instruct", "reviewed for the LIT-5968 backfill; no tool or vision support documented"),
+ _rule(
+ "deepseek-ai/DeepSeek-V4-Flash-0731",
+ "reviewed for the LIT-5968 backfill against https://www.together.ai/models/deepseek-v4-flash",
+ **_TOOLS,
+ ),
+ _rule(
+ "deepseek-ai/DeepSeek-V4-Pro",
+ "reviewed for the LIT-5968 backfill against https://www.together.ai/models/deepseek-v4-pro",
+ **_TOOLS,
+ supports_reasoning=True,
+ ),
+ _rule(
+ "deepseek-ai/DeepSeek-V4-Pro-0813",
+ "reviewed for the LIT-5968 backfill against https://www.together.ai/models/deepseek-v4-pro",
+ **_TOOLS,
+ ),
+ _rule("google/gemma-3n-E4B-it", "reviewed for the LIT-5968 backfill; no tool or vision support documented"),
+ _rule(
+ "google/gemma-4-31B-it",
+ "reviewed for the LIT-5968 backfill against https://www.together.ai/models/gemma-4-31b-it",
+ **_TOOLS,
+ supports_vision=True,
+ ),
+ _rule(
+ "intfloat/multilingual-e5-large-instruct",
+ "embedding dims per https://huggingface.co/intfloat/multilingual-e5-large-instruct",
+ output_vector_size=1024,
+ ),
+ _rule(
+ "meta-llama/Llama-3.3-70B-Instruct-Turbo",
+ "reviewed for the LIT-5968 backfill against https://docs.together.ai/docs/function-calling",
+ **_TOOLS,
+ ),
+ _rule(
+ "meta-llama/Llama-Guard-4-12B",
+ "moderation classifier with a chat-shaped API; no tools per the LIT-5968 backfill review",
+ ),
+ _rule("meta-models/Muse-Glimmer-30B", "reviewed for the LIT-5968 backfill; no tool or vision support documented"),
+ _rule(
+ "moonshotai/Kimi-K2.7-Code",
+ "reviewed for the LIT-5968 backfill against https://www.together.ai/models/kimi-k2-7-code",
+ **_TOOLS,
+ supports_vision=True,
+ ),
+ _rule(
+ "moonshotai/Kimi-K3",
+ "reviewed for the LIT-5968 backfill against https://www.together.ai/models/kimi-k3",
+ **_TOOLS,
+ supports_reasoning=True,
+ supports_vision=True,
+ ),
+ _rule(
+ "nvidia/nemotron-3-ultra-550b-a55b",
+ "reviewed for the LIT-5968 backfill against https://www.together.ai/models/nemotron-3-ultra",
+ **_TOOLS,
+ supports_reasoning=True,
+ ),
+ _rule(
+ "openai/gpt-oss-120b",
+ "reviewed for the LIT-5968 backfill against https://www.together.ai/models/gpt-oss-120b",
+ **_TOOLS,
+ supports_reasoning=True,
+ ),
+ _rule(
+ "openai/gpt-oss-20b",
+ "reviewed for the LIT-5968 backfill against https://www.together.ai/models/gpt-oss-20b",
+ **_TOOLS,
+ ),
+ _rule("pearl-ai/gemma-4-31b-it", "reviewed for the LIT-5968 backfill; no tool or vision support documented"),
+ _rule(
+ "thinkingmachines/Inkling",
+ "reviewed for the LIT-5968 backfill against https://www.together.ai/models/inkling",
+ **_TOOLS,
+ ),
+ _rule("thinkingmachines/Inkling-Small", "reviewed for the LIT-5968 backfill; no tool or vision support documented"),
+ _rule(
+ "zai-org/GLM-5.2",
+ "reviewed for the LIT-5968 backfill against https://www.together.ai/models/glm-5-2",
+ **_TOOLS,
+ supports_reasoning=True,
+ ),
+)
+
+RULES_BY_ID: Final = MappingProxyType({rule.model_id: rule for rule in CAPABILITY_RULES})
+
+
+@dataclass(frozen=True, slots=True)
+class DeprecationDoc:
+ removal_dates: Mapping[str, str]
+ redirects: Mapping[str, str]
+
+
+_REDIRECT_ROW: Final = re.compile(r"^\|\s*`([^`]+)`\s*\|\s*`([^`]+)`\s*\|")
+_REMOVAL_ROW: Final = re.compile(r"^\|\s*(\d{4}-\d{2}-\d{2})\s*\|\s*`([^`]+)`\s*\|")
+
+
+def _section(markdown: str, heading: str) -> str:
+ level: Final = heading.split(" ", 1)[0]
+ start: Final = markdown.find(f"\n{heading}\n")
+ if start < 0:
+ return ""
+ body: Final = markdown[start + 1 + len(heading) :]
+ next_heading: Final = re.search(rf"^{re.escape(level)} ", body, flags=re.MULTILINE)
+ return body[: next_heading.start()] if next_heading else body
+
+
+def parse_deprecations(markdown: str) -> DeprecationDoc:
+ redirect_rows: Final = tuple(
+ m.groups()
+ for m in (_REDIRECT_ROW.match(line) for line in _section(markdown, "## Active model redirects").splitlines())
+ if m
+ )
+ inference: Final = _section(_section(markdown, "## Deprecation history"), "### Inference")
+ removal_rows: Final = tuple(m.groups() for m in (_REMOVAL_ROW.match(line) for line in inference.splitlines()) if m)
+ if not redirect_rows or not removal_rows:
+ raise SyncError(
+ "deprecations doc parsed to zero redirect or removal rows; the table format at "
+ f"{DEPRECATIONS_URL} changed and the parser needs updating"
+ )
+ removal_dates: Final = {model: date for date, model in reversed(removal_rows)}
+ return DeprecationDoc(
+ removal_dates=MappingProxyType(dict(reversed(removal_dates.items()))),
+ redirects=MappingProxyType({original: target for original, target in redirect_rows}),
+ )
+
+
+def per_token(price_per_million: float) -> float:
+ return float(f"{price_per_million / 1e6:.6g}")
+
+
+def _resolve_name(name: str, universe: frozenset[str]) -> str | None:
+ if name in universe:
+ return name
+ suffix_matches: Final = tuple(candidate for candidate in universe if candidate.endswith(f"/{name}"))
+ return suffix_matches[0] if len(suffix_matches) == 1 else None
+
+
+def resolve_successor(model_id: str, doc: DeprecationDoc, live_ids: frozenset[str]) -> str | None:
+ canonical: Final = live_ids | frozenset(doc.removal_dates)
+ redirects: Final = {
+ (_resolve_name(raw_source, canonical) or raw_source): (_resolve_name(raw_target, canonical) or raw_target)
+ for raw_source, raw_target in doc.redirects.items()
+ }
+ seen: Final = set()
+ current = model_id # rebind-ok: walks the redirect chain
+ while current in redirects and current not in seen:
+ seen.add(current)
+ current = redirects[current] # rebind-ok: walks the redirect chain
+ return current if current != model_id and current in live_ids else None
+
+
+@dataclass(frozen=True, slots=True)
+class SyncOutcome:
+ cost_map: CostMap
+ added: tuple[str, ...] = ()
+ updated: tuple[str, ...] = ()
+ deprecated: tuple[str, ...] = ()
+ reappeared: tuple[str, ...] = ()
+ warnings: tuple[str, ...] = ()
+ skipped_types: Mapping[str, int] = field(default_factory=dict)
+
+ @property
+ def has_changes(self) -> bool:
+ return bool(self.added or self.updated or self.deprecated or self.reappeared)
+
+
+def _api_fields(model: CatalogModel) -> RegistryEntry:
+ cached: Final = model.pricing.cached_input
+ return {
+ "input_cost_per_token": per_token(model.pricing.input),
+ "output_cost_per_token": per_token(model.pricing.output),
+ **({"cache_read_input_token_cost": per_token(cached), "supports_prompt_caching": True} if cached else {}),
+ **({"max_input_tokens": model.context_length} if model.context_length is not None else {}),
+ }
+
+
+def _new_entry(model: CatalogModel, mode: str) -> RegistryEntry:
+ rule: Final = RULES_BY_ID.get(model.id)
+ length_fields: Final = (
+ {}
+ if model.context_length is None
+ else {"max_input_tokens": model.context_length, "max_tokens": model.context_length}
+ | ({"max_output_tokens": model.context_length} if mode == "chat" else {})
+ )
+ merged: Final = {
+ **_api_fields(model),
+ **length_fields,
+ "litellm_provider": PROVIDER,
+ "mode": mode,
+ "source": SOURCE_URL,
+ **(dict(rule.fields) if rule else {}),
+ }
+ return dict(sorted(merged.items()))
+
+
+def _updated_entry(entry: RegistryEntry, model: CatalogModel) -> tuple[RegistryEntry, tuple[str, ...]]:
+ rule: Final = RULES_BY_ID.get(model.id)
+ desired: Final = {**_api_fields(model), **(dict(rule.fields) if rule else {})}
+ dropped: Final = () if model.pricing.cached_input else ("cache_read_input_token_cost", "supports_prompt_caching")
+ changes: Final = tuple(
+ f"{name}: {entry.get(name)!r} -> {value!r}" for name, value in desired.items() if entry.get(name) != value
+ ) + tuple(
+ f"{name}: {entry[name]!r} removed (no longer in the catalog pricing)" for name in dropped if name in entry
+ )
+ merged: Final = {name: value for name, value in {**entry, **desired}.items() if name not in dropped}
+ return dict(sorted(merged.items())), changes
+
+
+def _with_new_keys_in_block(original: CostMap, result: CostMap, new_keys: Sequence[str]) -> CostMap:
+ provider_keys: Final = tuple(key for key in original if key.startswith(PREFIX))
+ if not new_keys or not provider_keys:
+ return result
+ block_end: Final = provider_keys[-1]
+ return {
+ key: value
+ for existing in original
+ for key, value in (
+ (existing, result[existing]),
+ *((new, result[new]) for new in sorted(new_keys) if existing == block_end),
+ )
+ }
+
+
+def compute_sync(cost_map: CostMap, catalog: Sequence[CatalogModel], doc: DeprecationDoc) -> SyncOutcome:
+ live_ids: Final = frozenset(model.id for model in catalog)
+ token_models: Final = {model.id: model for model in catalog if model.type in TYPE_TO_MODE}
+ skipped: Final = {
+ model.type: sum(1 for m in catalog if m.type == model.type)
+ for model in catalog
+ if model.type not in TYPE_TO_MODE
+ }
+ registry_ids: Final = {key.removeprefix(PREFIX): key for key in cost_map if key.startswith(PREFIX)}
+
+ added: Final[list[str]] = []
+ updated: Final[list[str]] = []
+ deprecated: Final[list[str]] = []
+ reappeared: Final[list[str]] = []
+ warnings: Final[list[str]] = []
+ result: Final[CostMap] = dict(cost_map)
+
+ for model_id, model in sorted(token_models.items()):
+ mode: Final = TYPE_TO_MODE[model.type]
+ key: Final = f"{PREFIX}{model_id}"
+ if model_id in doc.removal_dates:
+ warnings.append(
+ f"`{key}` is listed as removed on {doc.removal_dates[model_id]} in the docs but the serverless "
+ "catalog still serves it; availability kept from the API"
+ )
+ entry = result.get(key)
+ if not isinstance(entry, dict):
+ result[key] = _new_entry(model, mode)
+ added.append(key)
+ if model.type == "chat" and model_id not in RULES_BY_ID:
+ warnings.append(
+ f"`{key}` added without a capability rule; review its tools/vision/reasoning support and add one"
+ )
+ continue
+ if entry.get("mode") != mode:
+ warnings.append(
+ f"`{key}` has curated mode {entry.get('mode')!r} but the catalog maps to {mode!r}; left unchanged"
+ )
+ new_entry, changes = _updated_entry(entry, model)
+ if "deprecation_date" in new_entry:
+ new_entry.pop("deprecation_date")
+ reappeared.append(key)
+ if changes:
+ updated.append(f"{key}: " + "; ".join(changes))
+ if changes or key in reappeared:
+ result[key] = new_entry
+
+ for model_id, key in sorted(registry_ids.items()):
+ if model_id in token_models:
+ continue
+ entry = result.get(key)
+ if not isinstance(entry, dict):
+ continue
+ removal_date: Final = doc.removal_dates.get(model_id)
+ successor: Final = resolve_successor(model_id, doc, live_ids)
+ metadata = entry.get("metadata")
+ curated_successor: Final = metadata.get("successor") if isinstance(metadata, dict) else None
+ new_entry = dict(entry)
+ if removal_date is not None and entry.get("deprecation_date") != removal_date:
+ if "deprecation_date" in entry:
+ warnings.append(
+ f"`{key}` has curated deprecation_date {entry.get('deprecation_date')!r} but the docs list "
+ f"{removal_date!r}; left unchanged"
+ )
+ else:
+ new_entry["deprecation_date"] = removal_date
+ if removal_date is None and "deprecation_date" not in entry:
+ warnings.append(
+ f"`{key}` is absent from the serverless catalog with no removal date in the docs; "
+ "needs a human deprecation call"
+ )
+ if successor is not None:
+ desired_successor: Final = f"{PREFIX}{successor}"
+ if curated_successor is None:
+ new_entry["metadata"] = dict(
+ sorted({**(metadata if isinstance(metadata, dict) else {}), "successor": desired_successor}.items())
+ )
+ elif curated_successor != desired_successor:
+ warnings.append(
+ f"`{key}` has curated successor {curated_successor!r} but the docs redirects resolve to "
+ f"{desired_successor!r}; left unchanged"
+ )
+ if new_entry != entry:
+ result[key] = dict(sorted(new_entry.items()))
+ deprecated.append(f"{key}: " + ", ".join(sorted(set(new_entry) - set(entry)) or ["updated"]))
+
+ return SyncOutcome(
+ cost_map=_with_new_keys_in_block(cost_map, result, tuple(added)),
+ added=tuple(added),
+ updated=tuple(updated),
+ deprecated=tuple(deprecated),
+ reappeared=tuple(reappeared),
+ warnings=tuple(warnings),
+ skipped_types=MappingProxyType(skipped),
+ )
+
+
+def _section_block(title: str, lines: Sequence[str], backtick: bool) -> str:
+ bullets: Final = "\n".join(f"- `{line}`" if backtick else f"- {line}" for line in lines) or "- none"
+ return f"### {title} ({len(lines)})\n{bullets}\n"
+
+
+def render_pr_body(outcome: SyncOutcome) -> str:
+ skipped: Final = ", ".join(f"{kind} ({count})" for kind, count in sorted(outcome.skipped_types.items())) or "none"
+ return (
+ "Automated daily sync of the together_ai entries in model_prices_and_context_window.json against "
+ f"`GET {MODELS_URL}` and {DEPRECATIONS_URL} by scripts/sync_together_ai_models.py.\n"
+ "\n"
+ f"{_section_block('Added', outcome.added, backtick=True)}"
+ "\n"
+ f"{_section_block('Updated', outcome.updated, backtick=True)}"
+ "\n"
+ f"{_section_block('Marked deprecated', outcome.deprecated, backtick=True)}"
+ "\n"
+ f"{_section_block('Returned to the catalog', outcome.reappeared, backtick=True)}"
+ "\n"
+ f"{_section_block('Warnings needing a human call', outcome.warnings, backtick=False)}"
+ "\n"
+ f"Catalog model types outside the sync's token-pricing scope, skipped: {skipped}\n"
+ )
+
+
+def render_summary(outcome: SyncOutcome) -> str:
+ return (
+ f"added={len(outcome.added)} updated={len(outcome.updated)} deprecated={len(outcome.deprecated)} "
+ f"reappeared={len(outcome.reappeared)} warnings={len(outcome.warnings)}"
+ )
+
+
+def load_catalog(raw: bytes) -> list[CatalogModel]:
+ parsed: Final = json.loads(raw)
+ entries: Final = parsed.get("data") if isinstance(parsed, dict) else parsed
+ try:
+ catalog: Final = CATALOG_ADAPTER.validate_python(entries)
+ except ValidationError as error:
+ raise SyncError(f"the catalog response no longer matches the expected shape: {error}") from error
+ if not any(model.type in TYPE_TO_MODE for model in catalog):
+ raise SyncError(
+ "the catalog response contains no token-priced models; refusing to mark the whole registry deprecated"
+ )
+ return catalog
+
+
+def _fetch(url: str, headers: Mapping[str, str]) -> bytes:
+ response: Final = httpx.get(url, headers=dict(headers), timeout=30, follow_redirects=True)
+ if response.status_code != 200:
+ raise SyncError(f"GET {url} returned {response.status_code}")
+ return response.content
+
+
+def _serialize(cost_map: CostMap) -> str:
+ return json.dumps(cost_map, indent=4, ensure_ascii=False) + "\n"
+
+
+def main(argv: Sequence[str]) -> int:
+ parser: Final = argparse.ArgumentParser(description=__doc__)
+ parser.add_argument("--write", action="store_true", help="apply the sync to the cost map files (default: dry run)")
+ parser.add_argument("--models-json", type=Path, help="recorded catalog response to use instead of the live API")
+ parser.add_argument(
+ "--deprecations-md", type=Path, help="recorded deprecations doc to use instead of the live docs"
+ )
+ parser.add_argument("--pr-body-file", type=Path, help="write the generated PR body to this path")
+ parser.add_argument("--repo-root", type=Path, default=Path(__file__).resolve().parent.parent)
+ args: Final = parser.parse_args(argv)
+
+ if args.models_json is not None:
+ catalog_raw: Final = args.models_json.read_bytes()
+ else:
+ api_key: Final = os.environ.get("TOGETHER_API_KEY")
+ if not api_key:
+ raise SyncError("TOGETHER_API_KEY is not set and --models-json was not given")
+ catalog_raw = _fetch(MODELS_URL, {"Authorization": f"Bearer {api_key}"}) # rebind-ok: branch-dependent source
+ catalog: Final = load_catalog(catalog_raw)
+ markdown: Final = (
+ args.deprecations_md.read_text() if args.deprecations_md is not None else _fetch(DEPRECATIONS_URL, {}).decode()
+ )
+ doc: Final = parse_deprecations(markdown)
+
+ cost_map_path: Final = args.repo_root / COST_MAP_RELPATHS[0]
+ cost_map: Final = json.loads(cost_map_path.read_text())
+ outcome: Final = compute_sync(cost_map, catalog, doc)
+ body: Final = render_pr_body(outcome)
+
+ if args.pr_body_file is not None:
+ args.pr_body_file.write_text(body)
+ if args.write and outcome.has_changes:
+ for relpath in COST_MAP_RELPATHS:
+ (args.repo_root / relpath).write_text(_serialize(outcome.cost_map))
+ print(render_summary(outcome))
+ print()
+ print(body)
+ if not args.write:
+ print("dry run: no files were touched")
+ elif not outcome.has_changes:
+ print("registry already in sync: no files were touched")
+ return 0
+
+
+if __name__ == "__main__":
+ try:
+ raise SystemExit(main(sys.argv[1:]))
+ except SyncError as error:
+ print(f"SYNC FAILED: {error}", file=sys.stderr)
+ raise SystemExit(1) from error
diff --git a/tests/test_litellm/fixtures/together_ai_sync/deprecations.md b/tests/test_litellm/fixtures/together_ai_sync/deprecations.md
new file mode 100644
index 00000000000..b75e0825cee
--- /dev/null
+++ b/tests/test_litellm/fixtures/together_ai_sync/deprecations.md
@@ -0,0 +1,442 @@
+> ## Documentation Index
+> Fetch the complete documentation index at: https://docs.together.ai/llms.txt
+> Use this file to discover all available pages before exploring further.
+
+# Deprecations
+
+> Together AI's model lifecycle policy, including upgrades, redirects, and deprecation schedules.
+
+Together AI regularly updates the platform with new open-source models. This page describes the model lifecycle policy and lists active redirects and scheduled deprecations.
+
+## Model lifecycle policy
+
+Together AI follows a structured approach to introducing new models, upgrading existing models, and deprecating older versions, so you can rely on predictable behavior.
+
+### Model upgrades (redirects)
+
+An **upgrade** is a model release that is materially the same model lineage with targeted improvements and no fundamental changes to how developers use or reason about it.
+
+A model qualifies as an upgrade when **one or more** of the following are true (and none of the "new model" criteria apply):
+
+* Same modality and task profile (e.g., instruct → instruct, reasoning → reasoning).
+* Same architecture family (e.g., DeepSeek-V3 → DeepSeek-V3-0324).
+* Post-training or fine-tuning improvements, bug fixes, safety tuning, or small data refresh.
+* Behavior is strongly compatible (prompting patterns and evals are similar).
+* Pricing change is none or small (≤10% increase).
+
+**Outcome:** The current endpoint redirects to the upgraded version after a **3-day notice**. The old version remains available via dedicated endpoints.
+
+### New models (no redirect)
+
+A **new model** is a release with materially different capabilities, costs, or operating characteristics, so a silent redirect would be misleading.
+
+Any of the following triggers classification as a new model:
+
+* Modality shift (e.g., reasoning-only ↔ instruct/hybrid, text → multimodal).
+* Architecture shift (e.g., Qwen3 → Qwen3-Next, Llama 3 → Llama 4).
+* Large behavior shift (prompting patterns, output style, or verbosity materially different).
+* Experimental flag by provider (e.g., DeepSeek-V3-Exp).
+* Large price change (>10% increase or pricing structure change).
+* Benchmark deltas that meaningfully change task positioning.
+* Safety policy or system prompt changes that noticeably affect outputs.
+
+**Outcome:** No automatic redirect. Together AI announces the new model and deprecates the old one on a **2-week timeline** (both are available during this window). You must explicitly switch model IDs.
+
+## Active model redirects
+
+The following models are redirected to newer versions. Requests to the original model ID are automatically routed to the upgraded version:
+
+| Original model | Redirects to | Notes |
+| :----------------------------------- | :---------------------------------------- | :---------------------------------------- |
+| `mistralai/Mistral-7B-Instruct-v0.3` | `mistralai/Ministral-3-14B-Instruct-2512` | Same lineage, upgraded version |
+| `Kimi-K2` | `Kimi-K2-0905` | Same architecture, improved post-training |
+| `DeepSeek-V3` | `DeepSeek-V3.1` | Same architecture, targeted improvements |
+| `DeepSeek-V3-0324` | `DeepSeek-V3.1` | Same architecture, targeted improvements |
+| `DeepSeek-R1` | `DeepSeek-R1-0528` | Same architecture, targeted improvements |
+
+
+ If you need to use the original model version, you can always deploy it as a [dedicated endpoint](/docs/dedicated-endpoints).
+
+
+## Deprecation policy
+
+| Model type | Deprecation notice | Notes |
+| :--------------------------- | :---------------------------------- | :------------------------------------------------------- |
+| Preview model | \<24 hours of notice, after 30 days | Clearly marked in docs and playground with "Preview" tag |
+| Serverless endpoint | 2 or 3 weeks\* | |
+| On-demand dedicated endpoint | 2 or 3 weeks\* | |
+
+\*Depends on usage and whether a newer version of the model is available.
+
+* If you use a model scheduled for deprecation, you receive an email notification.
+* All changes appear on this page.
+* Each deprecated model has a specified removal date.
+* After the removal date, the model is no longer available via its serverless endpoint, but migration options are described below.
+
+## Migration options
+
+When a model is deprecated on the serverless platform, you have three options:
+
+1. **On-demand dedicated endpoint** (if supported):
+ * Reserved solely for you. You choose the underlying hardware.
+ * Charged on a price-per-minute basis.
+ * Endpoints can be dynamically spun up and down.
+2. **Monthly reserved dedicated endpoint:**
+ * Reserved solely for you.
+ * Charged on a month-by-month basis.
+ * Can be requested via this [form](https://together.ai/monthly-reserved).
+3. **Migrate to a newer serverless model:**
+ * Switch to an updated model on the serverless platform.
+
+## Migration steps
+
+1. Review the deprecation table below to find your current model.
+2. Check if on-demand dedicated endpoints are supported for your model.
+3. Decide on your preferred migration option.
+4. If you choose a new serverless model, test your application thoroughly before migrating.
+5. Update your API calls to use the new model or dedicated endpoint.
+
+## Deprecation history
+
+### Inference
+
+The table below lists all models removed from serverless inference, most recent first.
+
+| Removal date | Model | Supported by on-demand dedicated endpoints |
+| :-------------------------- | :-------------------------------------------------- | :----------------------------------------- |
+| 2026-08-21 | `deepcogito/cogito-v2-1-671b` | No |
+| 2026-08-04 | `google/gemma-3n-E4B-it` | No |
+| 2026-07-10 | `Qwen/Qwen3-235B-A22B-Instruct-2507-tput` | Yes |
+| 2026-07-10 | `meta-llama/Meta-Llama-3-8B-Instruct-Lite` | No |
+| 2026-07-10 | `zai-org/GLM-5.1` | Yes |
+| 2026-06-29 | `Qwen/Qwen3.5-397B-A17B` | Yes |
+| 2026-06-22 | `zai-org/GLM-5` | No |
+| 2026-06-11 | `mistralai/Voxtral-Mini-3B-2507` | No |
+| 2026-06-04 | `Qwen/Qwen3-Coder-480B-A35B-Instruct-FP8` | Yes |
+| 2026-05-27 | `black-forest-labs/FLUX.1-krea-dev` | No |
+| 2026-05-21 | `moonshotai/Kimi-K2.5` | No |
+| 2026-05-14 | `deepseek-ai/DeepSeek-R1` | No |
+| 2026-05-14 | `deepseek-ai/DeepSeek-V3.1` | Yes |
+| 2026-05-14 | `Qwen/Qwen3-Coder-Next-FP8` | Yes |
+| 2026-04-16 | `Qwen/Qwen3-VL-8B-Instruct` | Yes |
+| 2026-04-16 | `Qwen/Qwen3-235B-A22B-Thinking-2507` | Yes |
+| 2026-04-16 | `mistralai/Mixtral-8x7B-Instruct-v0.1` | Yes |
+| 2026-04-03 | `ServiceNow-AI/Apriel-1.5-15b-Thinker` | No |
+| 2026-04-03 | `ServiceNow-AI/Apriel-1.6-15b-Thinker` | No |
+| 2026-04-02 | `zai-org/GLM-4.5-Air-FP8` | No |
+| 2026-04-02 | `zai-org/GLM-4.7` | No |
+| 2026-04-02 | `mistralai/Mistral-Small-24B-Instruct-2501` | No |
+| 2026-04-02 | `Qwen/Qwen3-Next-80B-A3B-Instruct` | Yes |
+| 2026-03-31 | `meta-llama/Llama-4-Maverick-17B-128E-Instruct-FP8` | Yes |
+| 2026-03-06 | `mixedbread-ai/Mxbai-Rerank-Large-V2` | No |
+| 2026-03-06 | `meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo` | Yes |
+| 2026-03-06 | `Qwen/Qwen3-235B-A22B-Thinking-2507` | Yes |
+| 2026-03-06 | `moonshotai/Kimi-K2-Thinking` | No |
+| 2026-03-06 | `moonshotai/Kimi-K2-Instruct-0905` | No |
+| 2026-03-06 | `meta-llama/Llama-3.2-3B-Instruct-Turbo` | No |
+| 2026-02-25 | `black-forest-labs/FLUX.1-dev` | No |
+| 2026-02-25 | `black-forest-labs/FLUX.1-dev-lora` | No |
+| 2026-02-25 | `black-forest-labs/FLUX.1-Kontext-dev` | No |
+| 2026-02-25 | `Qwen/Qwen3-VL-32B-Instruct` | No |
+| 2026-02-25 | `meta-llama/Llama-3.2-3B-Instruct-Turbo-Classifier` | No |
+| 2026-02-25 | `mistralai/Ministral-3-14B-Instruct` | No |
+| 2026-02-25 | `Qwen/Qwen3-Next-80B-A3B-Thinking` | No |
+| 2026-02-25 | `Alibaba-NLP/gte-modernbert-base` | No |
+| 2026-02-25 | `BAAI/bge-base-en-v1.5-vllm` | No |
+| 2026-02-25 | `meta-llama/Meta-Llama-3.1-70B-Instruct-Turbo` | No |
+| 2026-02-25 | `meta-llama/Llama-Guard-3-11B-Vision-Turbo` | No |
+| 2026-02-25 | `meta-llama/LlamaGuard-2-8b` | No |
+| 2026-02-25 | `marin-community/Marin-8B-Instruct` | No |
+| 2026-02-25 | `nvidia/Nvidia-Nemotron-Nano-9B-v2` | No |
+| 2026-02-06 | `togethercomputer/m2-bert-80M-32k-retrieval` | No |
+| 2026-02-06 | `Salesforce/Llama-Rank-V1` | No |
+| 2026-02-06 | `togethercomputer/Refuel-Llm-V2` | No |
+| 2026-02-06 | `togethercomputer/Refuel-Llm-V2-Small` | No |
+| 2026-02-06 | `Qwen/Qwen3-235B-A22B-fp8-tput` | No |
+| 2026-02-06 | `qwen-qwen2-5-14b-instruct-lora` | No |
+| 2026-02-06 | `meta-llama/Llama-4-Scout-17B-16E-Instruct` | Yes |
+| 2026-02-06 | `Qwen/Qwen2.5-72B-Instruct-Turbo` | No |
+| 2026-02-06 | `meta-llama/Meta-Llama-3.1-405B-Instruct-Turbo` | No |
+| 2026-02-06 | `BAAI/bge-large-en-v1.5` | No |
+| 2026-02-03 | `deepseek-ai/DeepSeek-R1-0528-tput` | No |
+| 2026-01-05 | `Qwen/Qwen2.5-VL-72B-Instruct` | No |
+| 2025-12-23 | `deepseek-ai/DeepSeek-R1-Distill-Llama-70B` | No |
+| 2025-12-23 | `meta-llama/Meta-Llama-3-70B-Instruct-Turbo` | No |
+| 2025-12-23 | `black-forest-labs/FLUX.1-schnell-free` | No |
+| 2025-12-23 | `meta-llama/Meta-Llama-Guard-3-8B` | No |
+| 2025-11-19 | `deepcogito/cogito-v2-preview-deepseek-671b` | No |
+| 2025-07-25 | `arcee-ai/caller` | No |
+| 2025-07-25 | `arcee-ai/arcee-blitz` | No |
+| 2025-07-25 | `arcee-ai/virtuoso-medium-v2` | No |
+| 2025-11-17 | `arcee-ai/virtuoso-large` | No |
+| 2025-11-17 | `arcee-ai/maestro-reasoning` | No |
+| 2025-11-17 | `arcee_ai/arcee-spotlight` | No |
+| 2025-11-17 | `arcee-ai/coder-large` | No |
+| 2025-11-13 | `deepseek-ai/DeepSeek-R1-Distill-Qwen-14B` | No |
+| 2025-11-13 | `mistralai/Mistral-7B-Instruct-v0.1` | No |
+| 2025-11-13 | `Qwen/Qwen2.5-Coder-32B-Instruct` | No |
+| 2025-11-13 | `Qwen/QwQ-32B` | No |
+| 2025-11-13 | `deepseek-ai/DeepSeek-R1-Distill-Llama-70B-free` | No |
+| 2025-11-13 | `meta-llama/Llama-3.3-70B-Instruct-Turbo-Free` | No |
+| 2025-08-28 | `Qwen/Qwen2-VL-72B-Instruct` | No |
+| 2025-08-28 | `nvidia/Llama-3.1-Nemotron-70B-Instruct-HF` | No |
+| 2025-08-28 | `perplexity-ai/r1-1776` | No |
+| 2025-08-28 | `meta-llama/Meta-Llama-3-8B-Instruct` | No |
+| 2025-08-28 | `google/gemma-2-27b-it` | No |
+| 2025-08-28 | `Qwen/Qwen2-72B-Instruct` | No |
+| 2025-08-28 | `meta-llama/Llama-Vision-Free` | No |
+| 2025-08-28 | `Qwen/Qwen2.5-14B` | No |
+| 2025-08-28 | `meta-llama-llama-3-3-70b-instruct-lora` | No |
+| 2025-08-28 | `meta-llama/Llama-3.2-11B-Vision-Instruct-Turbo` | No |
+| 2025-08-28 | `NousResearch/Nous-Hermes-2-Mixtral-8x7B-DPO` | No |
+| 2025-08-28 | `deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B` | No |
+| 2025-08-28 | `black-forest-labs/FLUX.1-depth` | No |
+| 2025-08-28 | `black-forest-labs/FLUX.1-redux` | No |
+| 2025-08-28 | `meta-llama/Llama-3-8b-chat-hf` | No |
+| 2025-08-28 | `black-forest-labs/FLUX.1-canny` | No |
+| 2025-08-28 | `meta-llama/Llama-3.2-90B-Vision-Instruct-Turbo` | No |
+| 2025-06-13 | `gryphe-mythomax-l2-13b` | No |
+| 2025-06-13 | `mistralai-mixtral-8x22b-instruct-v0-1` | No |
+| 2025-06-13 | `mistralai-mixtral-8x7b-v0-1` | No |
+| 2025-06-13 | `togethercomputer-m2-bert-80m-2k-retrieval` | No |
+| 2025-06-13 | `togethercomputer-m2-bert-80m-8k-retrieval` | No |
+| 2025-06-13 | `whereisai-uae-large-v1` | No |
+| 2025-06-13 | `google-gemma-2-9b-it` | No |
+| 2025-06-13 | `google-gemma-2b-it` | No |
+| 2025-06-13 | `gryphe-mythomax-l2-13b-lite` | No |
+| 2025-05-16 | `meta-llama-llama-3-2-3b-instruct-turbo-lora` | No |
+| 2025-05-16 | `meta-llama-meta-llama-3-8b-instruct-turbo` | No |
+| 2025-04-24 | `meta-llama/Llama-2-13b-chat-hf` | No |
+| 2025-04-24 | `meta-llama-meta-llama-3-70b-instruct-turbo` | No |
+| 2025-04-24 | `meta-llama-meta-llama-3-1-8b-instruct-turbo-lora` | No |
+| 2025-04-24 | `meta-llama-meta-llama-3-1-70b-instruct-turbo-lora` | No |
+| 2025-04-24 | `meta-llama-llama-3-2-1b-instruct-lora` | No |
+| 2025-04-24 | `microsoft-wizardlm-2-8x22b` | No |
+| 2025-04-24 | `upstage-solar-10-7b-instruct-v1` | No |
+| 2025-04-14 | `stabilityai/stable-diffusion-xl-base-1.0` | No |
+| 2025-04-04 | `meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo-lora` | No |
+| 2025-03-27 | `mistralai/Mistral-7B-v0.1` | No |
+| 2025-03-25 | `Qwen/QwQ-32B-Preview` | No |
+| 2025-03-13 | `databricks-dbrx-instruct` | No |
+| 2025-03-11 | `meta-llama/Meta-Llama-3-70B-Instruct-Lite` | No |
+| 2025-03-08 | `Meta-Llama/Llama-Guard-7b` | No |
+| 2025-02-06 | `sentence-transformers/msmarco-bert-base-dot-v5` | No |
+| 2025-02-06 | `bert-base-uncased` | No |
+| 2024-10-29 | `Qwen/Qwen1.5-72B-Chat` | No |
+| 2024-10-29 | `Qwen/Qwen1.5-110B-Chat` | No |
+| 2024-10-07 | `NousResearch/Nous-Hermes-2-Yi-34B` | No |
+| 2024-10-07 | `NousResearch/Hermes-3-Llama-3.1-405B-Turbo` | No |
+| 2024-08-22 | `NousResearch/Nous-Hermes-2-Mistral-7B-DPO` | No |
+| 2024-08-22 | `SG161222/Realistic_Vision_V3.0_VAE` | No |
+| 2024-08-22 | `meta-llama/Llama-2-70b-chat-hf` | No |
+| 2024-08-22 | `mistralai/Mixtral-8x22B` | No |
+| 2024-08-22 | `Phind/Phind-CodeLlama-34B-v2` | No |
+| 2024-08-22 | `meta-llama/Meta-Llama-3-70B` | No |
+| 2024-08-22 | `teknium/OpenHermes-2p5-Mistral-7B` | No |
+| 2024-08-22 | `openchat/openchat-3.5-1210` | No |
+| 2024-08-22 | `WizardLM/WizardCoder-Python-34B-V1.0` | No |
+| 2024-08-22 | `NousResearch/Nous-Hermes-2-Mixtral-8x7B-SFT` | No |
+| 2024-08-22 | `NousResearch/Nous-Hermes-Llama2-13b` | No |
+| 2024-08-22 | `zero-one-ai/Yi-34B-Chat` | No |
+| 2024-08-22 | `codellama/CodeLlama-34b-Instruct-hf` | No |
+| 2024-08-22 | `codellama/CodeLlama-34b-Python-hf` | No |
+| 2024-08-22 | `teknium/OpenHermes-2-Mistral-7B` | No |
+| 2024-08-22 | `Qwen/Qwen1.5-14B-Chat` | No |
+| 2024-08-22 | `stabilityai/stable-diffusion-2-1` | No |
+| 2024-08-22 | `meta-llama/Llama-3-8b-hf` | No |
+| 2024-08-22 | `prompthero/openjourney` | No |
+| 2024-08-22 | `runwayml/stable-diffusion-v1-5` | No |
+| 2024-08-22 | `wavymulder/Analog-Diffusion` | No |
+| 2024-08-22 | `Snowflake/snowflake-arctic-instruct` | No |
+| 2024-08-22 | `deepseek-ai/deepseek-coder-33b-instruct` | No |
+| 2024-08-22 | `Qwen/Qwen1.5-7B-Chat` | No |
+| 2024-08-22 | `Qwen/Qwen1.5-32B-Chat` | No |
+| 2024-08-22 | `cognitivecomputations/dolphin-2.5-mixtral-8x7b` | No |
+| 2024-08-22 | `garage-bAInd/Platypus2-70B-instruct` | No |
+| 2024-08-22 | `google/gemma-7b-it` | No |
+| 2024-08-22 | `meta-llama/Llama-2-7b-chat-hf` | No |
+| 2024-08-22 | `Qwen/Qwen1.5-32B` | No |
+| 2024-08-22 | `Open-Orca/Mistral-7B-OpenOrca` | No |
+| 2024-08-22 | `codellama/CodeLlama-13b-Instruct-hf` | No |
+| 2024-08-22 | `NousResearch/Nous-Capybara-7B-V1p9` | No |
+| 2024-08-22 | `lmsys/vicuna-13b-v1.5` | No |
+| 2024-08-22 | `Undi95/ReMM-SLERP-L2-13B` | No |
+| 2024-08-22 | `Undi95/Toppy-M-7B` | No |
+| 2024-08-22 | `meta-llama/Llama-2-13b-hf` | No |
+| 2024-08-22 | `codellama/CodeLlama-70b-Instruct-hf` | No |
+| 2024-08-22 | `snorkelai/Snorkel-Mistral-PairRM-DPO` | No |
+| 2024-08-22 | `togethercomputer/LLaMA-2-7B-32K-Instruct` | No |
+| 2024-08-22 | `Austism/chronos-hermes-13b` | No |
+| 2024-08-22 | `Qwen/Qwen1.5-72B` | No |
+| 2024-08-22 | `zero-one-ai/Yi-34B` | No |
+| 2024-08-22 | `codellama/CodeLlama-7b-Instruct-hf` | No |
+| 2024-08-22 | `togethercomputer/evo-1-131k-base` | No |
+| 2024-08-22 | `codellama/CodeLlama-70b-hf` | No |
+| 2024-08-22 | `WizardLM/WizardLM-13B-V1.2` | No |
+| 2024-08-22 | `meta-llama/Llama-2-7b-hf` | No |
+| 2024-08-22 | `google/gemma-7b` | No |
+| 2024-08-22 | `Qwen/Qwen1.5-1.8B-Chat` | No |
+| 2024-08-22 | `Qwen/Qwen1.5-4B-Chat` | No |
+| 2024-08-22 | `lmsys/vicuna-7b-v1.5` | No |
+| 2024-08-22 | `zero-one-ai/Yi-6B` | No |
+| 2024-08-22 | `Nexusflow/NexusRaven-V2-13B` | No |
+| 2024-08-22 | `google/gemma-2b` | No |
+| 2024-08-22 | `Qwen/Qwen1.5-7B` | No |
+| 2024-08-22 | `NousResearch/Nous-Hermes-llama-2-7b` | No |
+| 2024-08-22 | `togethercomputer/alpaca-7b` | No |
+| 2024-08-22 | `Qwen/Qwen1.5-14B` | No |
+| 2024-08-22 | `codellama/CodeLlama-70b-Python-hf` | No |
+| 2024-08-22 | `Qwen/Qwen1.5-4B` | No |
+| 2024-08-22 | `togethercomputer/StripedHyena-Hessian-7B` | No |
+| 2024-08-22 | `allenai/OLMo-7B-Instruct` | No |
+| 2024-08-22 | `togethercomputer/RedPajama-INCITE-7B-Instruct` | No |
+| 2024-08-22 | `togethercomputer/LLaMA-2-7B-32K` | No |
+| 2024-08-22 | `togethercomputer/RedPajama-INCITE-7B-Base` | No |
+| 2024-08-22 | `Qwen/Qwen1.5-0.5B-Chat` | No |
+| 2024-08-22 | `microsoft/phi-2` | No |
+| 2024-08-22 | `Qwen/Qwen1.5-0.5B` | No |
+| 2024-08-22 | `togethercomputer/RedPajama-INCITE-7B-Chat` | No |
+| 2024-08-22 | `togethercomputer/RedPajama-INCITE-Chat-3B-v1` | No |
+| 2024-08-22 | `togethercomputer/GPT-JT-Moderation-6B` | No |
+| 2024-08-22 | `Qwen/Qwen1.5-1.8B` | No |
+| 2024-08-22 | `togethercomputer/RedPajama-INCITE-Instruct-3B-v1` | No |
+| 2024-08-22 | `togethercomputer/RedPajama-INCITE-Base-3B-v1` | No |
+| 2024-08-22 | `WhereIsAI/UAE-Large-V1` | No |
+| 2024-08-22 | `allenai/OLMo-7B` | No |
+| 2024-08-22 | `togethercomputer/evo-1-8k-base` | No |
+| 2024-08-22 | `WizardLM/WizardCoder-15B-V1.0` | No |
+| 2024-08-22 | `codellama/CodeLlama-13b-Python-hf` | No |
+| 2024-08-22 | `allenai-olmo-7b-twin-2t` | No |
+| 2024-08-22 | `sentence-transformers/msmarco-bert-base-dot-v5` | No |
+| 2024-08-22 | `codellama/CodeLlama-7b-Python-hf` | No |
+| 2024-08-22 | `hazyresearch/M2-BERT-2k-Retrieval-Encoder-V1` | No |
+| 2024-08-22 | `bert-base-uncased` | No |
+| 2024-08-22 | `mistralai/Mistral-7B-Instruct-v0.1-json` | No |
+| 2024-08-22 | `mistralai/Mistral-7B-Instruct-v0.1-tools` | No |
+| 2024-08-22 | `togethercomputer-codellama-34b-instruct-json` | No |
+| 2024-08-22 | `togethercomputer-codellama-34b-instruct-tools` | No |
+| **Notes on model support:** | | |
+
+* The support column reflects the current [supported models](/docs/dedicated-endpoints/models) catalog for dedicated model inference and is updated automatically as the catalog changes.
+* Models marked "Yes" can be deployed as on-demand dedicated endpoints, either under the listed ID or as the underlying base model of a serving variant (for example, a deprecated `-FP8` or `-Turbo` ID).
+* Models marked "No" are not available as on-demand endpoints and require migration to a different model or a monthly reserved dedicated endpoint.
+
+### Fine-tuning
+
+The table below lists all models removed from the fine-tuning service, most recent first. These models can no longer be used as a base model for a fine-tuning job. Where a close equivalent exists, the suggested replacement is listed. A blank cell means there is no direct equivalent. See [Supported models](/docs/fine-tuning/supported-models) for the full list of models available today.
+
+| Removal date | Model | Suggested replacement |
+| :----------- | :------------------------------------------------------ | :------------------------------------------------ |
+| 2026-07-29 | `nvidia/NVIDIA-Nemotron-Nano-9B-v2` | `Qwen/Qwen3.5-9B` |
+| 2026-07-29 | `Qwen/Qwen3-Next-80B-A3B-Instruct` | `Qwen/Qwen3.5-122B-A10B` |
+| 2026-07-29 | `Qwen/Qwen3-Next-80B-A3B-Thinking` | `Qwen/Qwen3.5-122B-A10B` |
+| 2026-07-29 | `Qwen/Qwen3-0.6B` | `Qwen/Qwen3.5-0.8B` |
+| 2026-07-29 | `Qwen/Qwen3-0.6B-Base` | `Qwen/Qwen3.5-0.8B` |
+| 2026-07-29 | `Qwen/Qwen3-1.7B` | `Qwen/Qwen3.5-2B` |
+| 2026-07-29 | `Qwen/Qwen3-1.7B-Base` | `Qwen/Qwen3.5-2B` |
+| 2026-07-29 | `Qwen/Qwen3-4B` | `Qwen/Qwen3.5-4B` |
+| 2026-07-29 | `Qwen/Qwen3-4B-Base` | `Qwen/Qwen3.5-4B` |
+| 2026-07-29 | `Qwen/Qwen3-8B` | `Qwen/Qwen3.5-9B` |
+| 2026-07-29 | `Qwen/Qwen3-8B-Base` | `Qwen/Qwen3.5-9B` |
+| 2026-07-29 | `Qwen/Qwen3-14B` | `Qwen/Qwen3.5-27B` |
+| 2026-07-29 | `Qwen/Qwen3-14B-Base` | `Qwen/Qwen3.5-27B` |
+| 2026-07-29 | `Qwen/Qwen3-32B` | `Qwen/Qwen3.5-27B` |
+| 2026-07-29 | `Qwen/Qwen3-30B-A3B-Base` | `Qwen/Qwen3.6-35B-A3B` |
+| 2026-07-29 | `Qwen/Qwen3-30B-A3B` | `Qwen/Qwen3.6-35B-A3B` |
+| 2026-07-29 | `Qwen/Qwen3-30B-A3B-Instruct-2507` | `Qwen/Qwen3.6-35B-A3B` |
+| 2026-07-29 | `Qwen/Qwen3-235B-A22B` | `Qwen/Qwen3.5-397B-A17B` |
+| 2026-07-29 | `Qwen/Qwen3-235B-A22B-Instruct-2507` | `Qwen/Qwen3.5-397B-A17B` |
+| 2026-07-29 | `Qwen/Qwen3-Coder-30B-A3B-Instruct` | `Qwen/Qwen3.6-35B-A3B` |
+| 2026-07-29 | `Qwen/Qwen3-Coder-480B-A35B-Instruct` | |
+| 2026-07-29 | `Qwen/Qwen3-VL-8B-Instruct` | `Qwen/Qwen3.5-9B` |
+| 2026-07-29 | `Qwen/Qwen3-VL-32B-Instruct` | |
+| 2026-07-29 | `Qwen/Qwen3-VL-30B-A3B-Instruct` | `Qwen/Qwen3.5-4B` |
+| 2026-07-29 | `Qwen/Qwen3-VL-235B-A22B-Instruct` | |
+| 2026-07-29 | `Qwen/Qwen2.5-72B-Instruct` | `meta-llama/Llama-3.3-70B-Instruct-Reference` |
+| 2026-07-29 | `Qwen/Qwen2.5-72B` | `meta-llama/Llama-3.3-70B-Instruct-Reference` |
+| 2026-07-29 | `Qwen/Qwen2.5-32B-Instruct` | `Qwen/Qwen3.5-27B` |
+| 2026-07-29 | `Qwen/Qwen2.5-32B` | `Qwen/Qwen3.5-27B` |
+| 2026-07-29 | `Qwen/Qwen2.5-14B-Instruct` | `Qwen/Qwen3.5-27B` |
+| 2026-07-29 | `Qwen/Qwen2.5-14B` | `Qwen/Qwen3.5-27B` |
+| 2026-07-29 | `Qwen/Qwen2.5-7B-Instruct` | `Qwen/Qwen3.5-9B` |
+| 2026-07-29 | `Qwen/Qwen2.5-7B` | `Qwen/Qwen3.5-9B` |
+| 2026-07-29 | `Qwen/Qwen2.5-3B-Instruct` | `Qwen/Qwen3.5-4B` |
+| 2026-07-29 | `Qwen/Qwen2.5-3B` | `Qwen/Qwen3.5-4B` |
+| 2026-07-29 | `Qwen/Qwen2.5-1.5B-Instruct` | `Qwen/Qwen3.5-2B` |
+| 2026-07-29 | `Qwen/Qwen2.5-1.5B` | `Qwen/Qwen3.5-2B` |
+| 2026-07-29 | `Qwen/Qwen2-72B-Instruct` | `meta-llama/Llama-3.3-70B-Instruct-Reference` |
+| 2026-07-29 | `Qwen/Qwen2-72B` | `meta-llama/Llama-3.3-70B-Instruct-Reference` |
+| 2026-07-29 | `Qwen/Qwen2-7B-Instruct` | `Qwen/Qwen3.5-9B` |
+| 2026-07-29 | `Qwen/Qwen2-7B` | `Qwen/Qwen3.5-9B` |
+| 2026-07-29 | `Qwen/Qwen2-1.5B-Instruct` | `Qwen/Qwen3.5-2B` |
+| 2026-07-29 | `Qwen/Qwen2-1.5B` | `Qwen/Qwen3.5-2B` |
+| 2026-07-29 | `moonshotai/Kimi-K2.5` | `moonshotai/Kimi-K2.6` |
+| 2026-07-29 | `moonshotai/Kimi-K2-Thinking` | `moonshotai/Kimi-K2.6` |
+| 2026-07-29 | `moonshotai/Kimi-K2-Instruct-0905` | `moonshotai/Kimi-K2.6` |
+| 2026-07-29 | `moonshotai/Kimi-K2-Instruct` | `moonshotai/Kimi-K2.6` |
+| 2026-07-29 | `moonshotai/Kimi-K2-Base` | `moonshotai/Kimi-K2.6` |
+| 2026-07-29 | `zai-org/GLM-5` | `zai-org/GLM-5.1` |
+| 2026-07-29 | `zai-org/GLM-4.7` | `zai-org/GLM-5.1` |
+| 2026-07-29 | `zai-org/GLM-4.6` | `zai-org/GLM-5.1` |
+| 2026-07-29 | `deepseek-ai/DeepSeek-R1-0528` | `deepseek-ai/DeepSeek-V3.1` |
+| 2026-07-29 | `deepseek-ai/DeepSeek-R1` | `deepseek-ai/DeepSeek-V3.1` |
+| 2026-07-29 | `deepseek-ai/DeepSeek-V3-0324` | `deepseek-ai/DeepSeek-V3.1` |
+| 2026-07-29 | `deepseek-ai/DeepSeek-V3` | `deepseek-ai/DeepSeek-V3.1` |
+| 2026-07-29 | `deepseek-ai/DeepSeek-V3.1-Base` | `deepseek-ai/DeepSeek-V3.1` |
+| 2026-07-29 | `deepseek-ai/DeepSeek-V3-Base` | `deepseek-ai/DeepSeek-V3.1` |
+| 2026-07-29 | `deepseek-ai/DeepSeek-R1-Distill-Llama-70B` | `meta-llama/Llama-3.3-70B-Instruct-Reference` |
+| 2026-07-29 | `deepseek-ai/DeepSeek-R1-Distill-Llama-70B-32k` | `meta-llama/Llama-3.3-70B-Instruct-Reference` |
+| 2026-07-29 | `deepseek-ai/DeepSeek-R1-Distill-Llama-70B-131k` | `meta-llama/Llama-3.3-70B-Instruct-Reference` |
+| 2026-07-29 | `deepseek-ai/DeepSeek-R1-Distill-Qwen-14B` | `Qwen/Qwen3.5-27B` |
+| 2026-07-29 | `deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B` | `Qwen/Qwen3.5-2B` |
+| 2026-07-29 | `meta-llama/Llama-4-Scout-17B-16E` | `meta-llama/Llama-4-Scout-17B-16E-Instruct` |
+| 2026-07-29 | `meta-llama/Llama-4-Maverick-17B-128E` | `meta-llama/Llama-4-Maverick-17B-128E-Instruct` |
+| 2026-07-29 | `meta-llama/Llama-3.3-70B-32k-Instruct-Reference` | `meta-llama/Llama-3.3-70B-Instruct-Reference` |
+| 2026-07-29 | `meta-llama/Llama-3.3-70B-131k-Instruct-Reference` | `meta-llama/Llama-3.3-70B-Instruct-Reference` |
+| 2026-07-29 | `meta-llama/Llama-3.2-3B-Instruct` | `meta-llama/Meta-Llama-3.1-8B-Instruct-Reference` |
+| 2026-07-29 | `meta-llama/Llama-3.2-3B` | `meta-llama/Meta-Llama-3.1-8B-Instruct-Reference` |
+| 2026-07-29 | `meta-llama/Llama-3.2-1B-Instruct` | `meta-llama/Meta-Llama-3.1-8B-Instruct-Reference` |
+| 2026-07-29 | `meta-llama/Llama-3.2-1B` | `meta-llama/Meta-Llama-3.1-8B-Instruct-Reference` |
+| 2026-07-29 | `meta-llama/Meta-Llama-3.1-8B-131k-Instruct-Reference` | `meta-llama/Meta-Llama-3.1-8B-Instruct-Reference` |
+| 2026-07-29 | `meta-llama/Meta-Llama-3.1-8B-Reference` | `meta-llama/Meta-Llama-3.1-8B-Instruct-Reference` |
+| 2026-07-29 | `meta-llama/Meta-Llama-3.1-8B-131k-Reference` | `meta-llama/Meta-Llama-3.1-8B-Instruct-Reference` |
+| 2026-07-29 | `meta-llama/Meta-Llama-3.1-70B-Instruct-Reference` | `meta-llama/Llama-3.3-70B-Instruct-Reference` |
+| 2026-07-29 | `meta-llama/Meta-Llama-3.1-70B-32k-Instruct-Reference` | `meta-llama/Llama-3.3-70B-Instruct-Reference` |
+| 2026-07-29 | `meta-llama/Meta-Llama-3.1-70B-131k-Instruct-Reference` | `meta-llama/Llama-3.3-70B-Instruct-Reference` |
+| 2026-07-29 | `meta-llama/Meta-Llama-3.1-70B-Reference` | `meta-llama/Llama-3.3-70B-Instruct-Reference` |
+| 2026-07-29 | `meta-llama/Meta-Llama-3.1-70B-32k-Reference` | `meta-llama/Llama-3.3-70B-Instruct-Reference` |
+| 2026-07-29 | `meta-llama/Meta-Llama-3.1-70B-131k-Reference` | `meta-llama/Llama-3.3-70B-Instruct-Reference` |
+| 2026-07-29 | `meta-llama/Meta-Llama-3.1-405B-Instruct-Reference` | |
+| 2026-07-29 | `meta-llama/Meta-Llama-3.1-405B-Reference` | |
+| 2026-07-29 | `meta-llama/Meta-Llama-3.1-405B-10k-Instruct-Reference` | |
+| 2026-07-29 | `meta-llama/Meta-Llama-3.1-405B-10k-Reference` | |
+| 2026-07-29 | `meta-llama/Meta-Llama-3.1-405B-8k-Instruct-Reference` | |
+| 2026-07-29 | `meta-llama/Meta-Llama-3.1-405B-8k-Reference` | |
+| 2026-07-29 | `meta-llama/Meta-Llama-3-8B-Instruct` | `meta-llama/Meta-Llama-3.1-8B-Instruct-Reference` |
+| 2026-07-29 | `meta-llama/Meta-Llama-3-8B` | `meta-llama/Meta-Llama-3.1-8B-Instruct-Reference` |
+| 2026-07-29 | `meta-llama/Meta-Llama-3-70B-Instruct` | `meta-llama/Llama-3.3-70B-Instruct-Reference` |
+| 2026-07-29 | `google/gemma-3-270m` | `Qwen/Qwen3.5-0.8B` |
+| 2026-07-29 | `google/gemma-3-270m-it` | `Qwen/Qwen3.5-0.8B` |
+| 2026-07-29 | `google/gemma-3-1b-it` | `google/gemma-4-26B-A4B-it` |
+| 2026-07-29 | `google/gemma-3-1b-pt` | `google/gemma-4-26B-A4B-it` |
+| 2026-07-29 | `google/gemma-3-4b-it` | `google/gemma-4-26B-A4B-it` |
+| 2026-07-29 | `google/gemma-3-4b-it-VLM` | `google/gemma-4-26B-A4B-it` |
+| 2026-07-29 | `google/gemma-3-4b-pt` | `google/gemma-4-26B-A4B-it` |
+| 2026-07-29 | `google/gemma-3-12b-it` | `google/gemma-4-26B-A4B-it` |
+| 2026-07-29 | `google/gemma-3-12b-it-VLM` | `google/gemma-4-31B-it-VLM` |
+| 2026-07-29 | `google/gemma-3-12b-pt` | `google/gemma-4-26B-A4B-it` |
+| 2026-07-29 | `google/gemma-3-27b-it` | `google/gemma-4-31B-it` |
+| 2026-07-29 | `google/gemma-3-27b-it-VLM` | `google/gemma-4-31B-it-VLM` |
+| 2026-07-29 | `google/gemma-3-27b-pt` | `google/gemma-4-31B-it` |
+| 2026-07-29 | `mistralai/Mixtral-8x7B-v0.1` | `mistralai/Mixtral-8x7B-Instruct-v0.1` |
+| 2026-07-29 | `mistralai/Mistral-7B-Instruct-v0.2` | `mistralai/Mixtral-8x7B-Instruct-v0.1` |
+| 2026-07-29 | `mistralai/Mistral-7B-v0.1` | `mistralai/Mixtral-8x7B-Instruct-v0.1` |
+| 2026-07-29 | `togethercomputer/llama-2-7b-chat` | `meta-llama/Meta-Llama-3.1-8B-Instruct-Reference` |
+
+## Recommended actions
+
+* Regularly check this page for updates on model deprecations.
+* Plan your migration well in advance of the removal date to ensure a smooth transition.
+* If you have any questions or need assistance with migration, contact the Together AI support team.
+
+For the most up-to-date information on model availability, support, and recommended alternatives, check the API documentation or contact the Together AI support team.
diff --git a/tests/test_litellm/fixtures/together_ai_sync/models_serverless.json b/tests/test_litellm/fixtures/together_ai_sync/models_serverless.json
new file mode 100644
index 00000000000..4988f0820bc
--- /dev/null
+++ b/tests/test_litellm/fixtures/together_ai_sync/models_serverless.json
@@ -0,0 +1 @@
+[{"id":"moonshotai/Kimi-K3","uuid":"endpoint-kk-moonshotai-kimi-k3","object":"model","created":1785049898,"type":"chat","running":false,"display_name":"Kimi K3","organization":"Moonshot AI","link":"https://huggingface.co/moonshotai","license":"other","context_length":1048576,"config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":3,"output":15,"base":0,"finetune":0,"cached_input":0.3,"image_pixel":0,"transcribe":0,"image":0,"video":0}},{"id":"zai-org/GLM-5.2","uuid":"endpoint-83348bee-b0fb-4aad-8ba4-72545469cb9e","object":"model","created":0,"type":"chat","running":false,"display_name":"GLM 5.2","organization":"Zai Org","link":"https://huggingface.co/api/models/nvidia/GLM-5.2-NVFP4","context_length":1048575,"config":{"chat_template":"[gMASK]\n{%- set effective_reasoning_effort = 'high' if reasoning_effort is defined and reasoning_effort == 'high' else 'max' -%}\n{%- if (enable_thinking is not defined or enable_thinking) and effective_reasoning_effort is not none -%}<|system|>Reasoning Effort: {{ effective_reasoning_effort | capitalize }}{%- endif -%}\n{%- if tools -%}\n{%- macro tool_to_json(tool) -%}\n {%- set ns_tool = namespace(first=true) -%}\n {{ '{' -}}\n {%- for k, v in tool.items() -%}\n {%- if k != 'defer_loading' and k != 'strict' -%}\n {%- if not ns_tool.first -%}{{- ', ' -}}{%- endif -%}\n {%- set ns_tool.first = false -%}\n \"{{ k }}\": {{ v | tojson(ensure_ascii=False) }}\n {%- endif -%}\n {%- endfor -%}\n {{- '}' -}}\n{%- endmacro -%}\n<|system|>\n# Tools\n\nYou may call one or more functions to assist with the user query.\n\nYou are provided with function signatures within XML tags:\n\n{% for tool in tools %}\n{%- if 'function' in tool -%}\n {%- set tool = tool['function'] -%}\n{%- endif -%}\n{% if tool.defer_loading is not defined or not tool.defer_loading %}\n{{ tool_to_json(tool) }}\n{% endif %}\n{% endfor %}\n\n\nFor each function call, output the function name and arguments within the following XML format:\n{function-name}{arg-key-1}{arg-value-1}{arg-key-2}{arg-value-2}...{%- endif -%}\n{%- macro visible_text(content) -%}\n {%- if content is string -%}\n {{- content }}\n {%- elif content is iterable and content is not mapping -%}\n {%- for item in content -%}\n {%- if item is mapping and item.type == 'text' -%}\n {{- item.text }}\n {%- elif item is string -%}\n {{- item }}\n {%- elif item is mapping and item.type in ['image', 'image_url', 'video', 'video_url', 'audio', 'audio_url', 'input_audio'] -%}\n {%- set media_type = item.type | replace('_url', '') | replace('input_', '') -%}\n {{- \"You are unable to process this \" ~ media_type ~ \" because you don't have multi-modal input ability. Try different methods.\" }}\n {%- endif -%}\n {%- endfor -%}\n {%- else -%}\n {{- content }}\n {%- endif -%}\n{%- endmacro -%}\n{%- set ns = namespace(last_user_index=-1) -%}\n{%- for m in messages %}\n {%- if m.role == 'user' %}\n {%- set ns.last_user_index = loop.index0 -%}\n {%- endif %}\n{%- endfor %}\n{%- for m in messages -%}\n{%- if m.role == 'user' -%}<|user|>{{ visible_text(m.content) }}\n{%- elif m.role == 'assistant' -%}\n<|assistant|>\n{%- set content = visible_text(m.content) %}\n{%- if m.reasoning_content is string %}\n {%- set reasoning_content = m.reasoning_content %}\n{%- elif '' in content %}\n {%- set reasoning_content = content.split('')[0].split('')[-1] %}\n {%- set content = content.split('')[-1] %}\n{%- endif %}\n{%- if ((clear_thinking is defined and not clear_thinking) or loop.index0 > ns.last_user_index) and reasoning_content is defined -%}\n{{ '' + reasoning_content + ''}}\n{%- else -%}\n{{ '' }}\n{%- endif -%}\n{%- if content.strip() -%}\n{{ content.strip() }}\n{%- endif -%}\n{% if m.tool_calls %}\n{% for tc in m.tool_calls %}\n{%- if tc.function %}\n {%- set tc = tc.function %}\n{%- endif %}\n{{- '' + tc.name -}}\n{% set _args = tc.arguments %}{% for k, v in _args.items() %}{{ k }}{{ v | tojson(ensure_ascii=False) if v is not string else v }}{% endfor %}{% endfor %}\n{% endif %}\n{%- elif m.role == 'tool' -%}\n{%- if loop.first or (messages[loop.index0 - 1].role != \"tool\") %}\n {{- '<|observation|>' -}}\n{%- endif %}\n{%- if m.content is string -%}\n {{- '' + m.content + '' -}}\n{%- elif m.content is iterable and m.content is not mapping and m.content and m.content.0.type == \"tool_reference\" -%}\n {{- '\\n' -}}\n {% for tr in m.content %}\n {%- for tool in tools -%}\n {%- if 'function' in tool -%}\n {%- set tool = tool['function'] -%}\n {%- endif -%}\n {%- if tool.name == tr.name -%}\n {{- tool_to_json(tool) + '\\n' -}}\n {%- endif -%}\n {%- endfor -%}\n {%- endfor -%}\n {{- '' -}}\n{%- elif m.content is iterable and m.content is not mapping and m.content and m.content.0 is mapping and m.content.0.output is defined -%}\n {%- for tr in m.content -%}\n {{- '' + tr.output + '' -}}\n {%- endfor -%}\n{%- else -%}\n {{- '' + visible_text(m.content) + '' -}}\n{% endif -%}\n{%- elif m.role == 'system' -%}\n<|system|>{{ visible_text(m.content) }}\n{%- endif -%}\n{%- endfor -%}\n{%- if add_generation_prompt -%}\n <|assistant|>{{- '' if (enable_thinking is defined and not enable_thinking) else '' -}}\n{%- endif -%}\n","stop":[],"bos_token":null,"eos_token":"<|endoftext|>"},"pricing":{"hourly":0,"input":1.4,"output":4.4,"base":0,"finetune":0,"cached_input":0.25999999999999995,"image_pixel":0,"transcribe":0,"image":0,"video":0}},{"id":"meta-models/Muse-Glimmer-30B","uuid":"endpoint-3da50849-cf6c-4e18-b44a-0dec9a699874","object":"model","created":0,"type":"chat","running":false,"display_name":"Muse Glimmer 30B","organization":"Meta","link":"https://huggingface.co/api/models/togethercomputer/onyx_final_hf-fp8-mlp","context_length":131072,"config":{"chat_template":null,"stop":["<|end_of_text|>"],"bos_token":"<|begin_of_text|>","eos_token":"<|end_of_text|>"},"pricing":{"hourly":0,"input":0.35,"output":1.5,"base":0,"finetune":0,"cached_input":0.04,"image_pixel":0,"transcribe":0,"image":0,"video":0}},{"id":"Qwen/Qwen3.8-2.4T-A95B","uuid":"endpoint-494c76e2-129e-41ee-9ab9-e25c9a3ff08c","object":"model","created":0,"type":"chat","running":false,"display_name":"Qwen3.8-2.4T-A95B","organization":"Qwen","context_length":1010000,"config":{"chat_template":"{%- set image_count = namespace(value=0) %}\n{%- set video_count = namespace(value=0) %}\n{%- macro render_content(content, do_vision_count, is_system_content=false) %}\n {%- if content is string %}\n {{- content }}\n {%- elif content is iterable and content is not mapping %}\n {%- for item in content %}\n {%- if 'image' in item or 'image_url' in item or item.type == 'image' %}\n {%- if is_system_content %}\n {{- raise_exception('System message cannot contain images.') }}\n {%- endif %}\n {%- if do_vision_count %}\n {%- set image_count.value = image_count.value + 1 %}\n {%- endif %}\n {%- if add_vision_id %}\n {{- 'Picture ' ~ image_count.value ~ ': ' }}\n {%- endif %}\n {{- '<|vision_start|><|image_pad|><|vision_end|>' }}\n {%- elif 'video' in item or item.type == 'video' %}\n {%- if is_system_content %}\n {{- raise_exception('System message cannot contain videos.') }}\n {%- endif %}\n {%- if do_vision_count %}\n {%- set video_count.value = video_count.value + 1 %}\n {%- endif %}\n {%- if add_vision_id %}\n {{- 'Video ' ~ video_count.value ~ ': ' }}\n {%- endif %}\n {{- '<|vision_start|><|video_pad|><|vision_end|>' }}\n {%- elif 'text' in item %}\n {{- item.text }}\n {%- else %}\n {{- raise_exception('Unexpected item type in content.') }}\n {%- endif %}\n {%- endfor %}\n {%- elif content is none or content is undefined %}\n {{- '' }}\n {%- else %}\n {{- raise_exception('Unexpected content type.') }}\n {%- endif %}\n{%- endmacro %}\n{%- if not messages %}\n {{- raise_exception('No messages provided.') }}\n{%- endif %}\n{%- set reasoning_instructions = '' %}\n{%- if enable_thinking is undefined or enable_thinking is true %}\n {%- set resolved_reasoning_effort = reasoning_effort|default('xhigh') %}\n {%- if resolved_reasoning_effort not in ('xhigh', 'medium', 'low') %}\n {{- raise_exception('Unexpected reasoning effort ' ~ reasoning_effort ~ '. Supported types are xhigh (default), medium, and low.') }}\n {%- endif %}\n {%- if resolved_reasoning_effort == 'xhigh' %}\n {%- set reasoning_instructions = 'Reasoning effort is set to xhigh. Please think carefully through the task, validate key assumptions, consider plausible alternatives, and prioritize correctness, consistency, and clarity in the final answer.' %}\n {%- elif resolved_reasoning_effort == 'low' %}\n {%- set reasoning_instructions = 'Reasoning effort is set to low. Keep your thinking brief and focused, moving directly to the conclusion without unnecessary elaboration.' %}\n {%- endif %}\n{%- endif %}\n{%- if tools and tools is iterable and tools is not mapping %}\n {{- '<|im_start|>system\\n' }}\n {%- if reasoning_instructions %}\n {{- reasoning_instructions + '\\n\\n' }}\n {%- endif %}\n {{- \"# Tools\\n\\nYou have access to the following functions:\\n\\n\" }}\n {%- for tool in tools %}\n {{- \"\\n\" }}\n {{- tool | tojson }}\n {%- endfor %}\n {{- \"\\n\" }}\n {{- '\\n\\nIf you choose to call a function ONLY reply in the following format with NO suffix:\\n\\n\\n\\n\\nvalue_1\\n\\n\\nThis is the value for the second parameter\\nthat can span\\nmultiple lines\\n\\n\\n\\n\\n\\nReminder:\\n- Function calls MUST follow the specified format: an inner block must be nested within XML tags\\n- Required parameters MUST be specified\\n- You may provide optional reasoning for your function call in natural language BEFORE the function call, but NOT after\\n- If there is no function call available, answer the question like normal with your current knowledge and do not tell the user about function calls\\n' }}\n {%- if messages[0].role == 'system' %}\n {%- set content = render_content(messages[0].content, false, true)|trim %}\n {%- if content %}\n {{- '\\n\\n' + content }}\n {%- endif %}\n {%- endif %}\n {{- '<|im_end|>\\n' }}\n{%- else %}\n {%- if messages[0].role == 'system' %}\n {%- set content = render_content(messages[0].content, false, true)|trim %}\n {%- if content %}\n {{- '<|im_start|>system\\n' + (reasoning_instructions + '\\n\\n' if reasoning_instructions else '') + content + '<|im_end|>\\n' }}\n {%- elif reasoning_instructions %}\n {{- '<|im_start|>system\\n' + reasoning_instructions + '<|im_end|>\\n' }}\n {%- endif %}\n {%- elif reasoning_instructions %}\n {{- '<|im_start|>system\\n' + reasoning_instructions + '<|im_end|>\\n' }}\n {%- endif %}\n{%- endif %}\n{%- set ns = namespace(multi_step_tool=true, last_query_index=messages|length - 1) %}\n{%- for message in messages[::-1] %}\n {%- set index = (messages|length - 1) - loop.index0 %}\n {%- if ns.multi_step_tool and message.role == \"user\" %}\n {%- set content = render_content(message.content, false)|trim %}\n {%- if not(content.startswith('') and content.endswith('')) %}\n {%- set ns.multi_step_tool = false %}\n {%- set ns.last_query_index = index %}\n {%- endif %}\n {%- endif %}\n{%- endfor %}\n{%- if ns.multi_step_tool %}\n {{- raise_exception('No user query found in messages.') }}\n{%- endif %}\n{%- for message in messages %}\n {%- set content = render_content(message.content, true)|trim %}\n {%- if message.role == \"system\" %}\n {%- if not loop.first %}\n {{- raise_exception('System message must be at the beginning.') }}\n {%- endif %}\n {%- elif message.role == \"user\" %}\n {{- '<|im_start|>' + message.role + '\\n' + content + '<|im_end|>' + '\\n' }}\n {%- elif message.role == \"assistant\" %}\n {%- set reasoning_content = '' %}\n {%- if message.reasoning_content is string %}\n {%- set reasoning_content = message.reasoning_content %}\n {%- endif %}\n {%- set reasoning_content = reasoning_content|trim %}\n {%- if preserve_thinking is undefined or preserve_thinking is true or loop.index0 > ns.last_query_index %}\n {{- '<|im_start|>' + message.role + '\\n\\n' + reasoning_content + '\\n\\n\\n' + content }}\n {%- else %}\n {{- '<|im_start|>' + message.role + '\\n' + content }}\n {%- endif %}\n {%- if message.tool_calls and message.tool_calls is iterable and message.tool_calls is not mapping %}\n {%- for tool_call in message.tool_calls %}\n {%- if tool_call.function is defined %}\n {%- set tool_call = tool_call.function %}\n {%- endif %}\n {%- if loop.first %}\n {%- if content|trim %}\n {{- '\\n\\n\\n\\n' }}\n {%- else %}\n {{- '\\n\\n' }}\n {%- endif %}\n {%- else %}\n {{- '\\n\\n\\n' }}\n {%- endif %}\n {%- if tool_call.arguments is defined and tool_call.arguments != '' %}\n {%- for args_name, args_value in tool_call.arguments|items %}\n {{- '\\n' }}\n {%- set args_value = args_value | string if args_value is string else args_value | tojson | safe %}\n {{- args_value }}\n {{- '\\n\\n' }}\n {%- endfor %}\n {%- endif %}\n {{- '\\n' }}\n {%- endfor %}\n {%- endif %}\n {{- '<|im_end|>\\n' }}\n {%- elif message.role == \"tool\" %}\n {%- if loop.previtem and loop.previtem.role != \"tool\" %}\n {{- '<|im_start|>user' }}\n {%- endif %}\n {{- '\\n\\n' }}\n {{- content }}\n {{- '\\n' }}\n {%- if not loop.last and loop.nextitem.role != \"tool\" %}\n {{- '<|im_end|>\\n' }}\n {%- elif loop.last %}\n {{- '<|im_end|>\\n' }}\n {%- endif %}\n {%- else %}\n {{- raise_exception('Unexpected message role.') }}\n {%- endif %}\n{%- endfor %}\n{%- if add_generation_prompt %}\n {{- '<|im_start|>assistant\\n' }}\n {%- if enable_thinking is defined and enable_thinking is false %}\n {{- '\\n\\n\\n\\n' }}\n {%- else %}\n {{- '\\n' }}\n {%- endif %}\n{%- endif %}","stop":["<|im_end|>"],"bos_token":null,"eos_token":"<|im_end|>"},"pricing":{"hourly":0,"input":2.5,"output":6.25,"base":0,"finetune":0,"cached_input":0.5,"image_pixel":0,"transcribe":0,"image":0,"video":0}},{"id":"deepseek-ai/DeepSeek-V4-Pro-0813","object":"model","created":1786804181,"type":"chat","running":false,"display_name":"DeepSeek V4 Pro 0813","organization":"DeepSeek","context_length":1048576,"config":{"chat_template":null,"stop":["<|end▁of▁sentence|>"],"bos_token":"<|begin▁of▁sentence|>","eos_token":"<|end▁of▁sentence|>"},"pricing":{"hourly":0,"input":1.32,"output":3.96,"base":0,"finetune":0,"cached_input":0.12999999999999998,"image_pixel":0,"transcribe":0,"image":0,"video":0}},{"id":"deepseek-ai/DeepSeek-V4-Flash-0731","uuid":"endpoint-59e1bfe8-dcfd-4902-8e59-8e9585cfab4e","object":"model","created":0,"type":"chat","running":false,"display_name":"Deepseek V4 Flash 0731","organization":"Deepseek AI","context_length":1048576,"config":{"chat_template":null,"stop":["<|end▁of▁sentence|>"],"bos_token":"<|begin▁of▁sentence|>","eos_token":"<|end▁of▁sentence|>"},"pricing":{"hourly":0,"input":0.13999999999999999,"output":0.27999999999999997,"base":0,"finetune":0,"cached_input":0.030000000000000002,"image_pixel":0,"transcribe":0,"image":0,"video":0}},{"id":"thinkingmachines/Inkling","uuid":"endpoint-8b0aa8da-8d35-4a01-be0b-eca731d64568","object":"model","created":0,"type":"chat","running":false,"display_name":"Inkling FP4","organization":"Thinking Machines","link":"https://huggingface.co/api/models/thinkingmachines/Inkling-NVFP4","license":"apache-2.0","context_length":524288,"config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":1,"output":4.05,"base":0,"finetune":0,"cached_input":0.17,"image_pixel":0,"transcribe":0,"image":0,"video":0}},{"id":"MiniMaxAI/MiniMax-M3","uuid":"endpoint-5dea048e-3527-4287-8da8-5e61214b9f64","object":"model","created":0,"type":"chat","running":false,"display_name":"MiniMax M3","organization":"MiniMaxAI","context_length":524288,"config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":0.3,"output":1.2,"base":0,"finetune":0,"cached_input":0.060000000000000005,"image_pixel":0,"transcribe":0,"image":0,"video":0}},{"id":"thinkingmachines/Inkling-Small","object":"model","created":1785387855,"type":"chat","running":false,"display_name":"Inkling Small","organization":"Thinking Machines","link":"https://huggingface.co/api/models/thinkingmachines/Inkling-Small","context_length":524288,"config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":0.5,"output":1.2,"base":0,"finetune":0,"cached_input":0.1,"image_pixel":0,"transcribe":0,"image":0,"video":0}},{"id":"moonshotai/Kimi-K2.7-Code","uuid":"endpoint-b8ae5f69-a244-43dd-a6ac-957653518387","object":"model","created":0,"type":"chat","running":false,"display_name":"Kimi K2.7 Code","organization":"Moonshot AI","link":"https://huggingface.co/api/models/togethercomputer/Kimi-K2.7-Code-FP4","context_length":262144,"config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":0.95,"output":4,"base":0,"finetune":0,"cached_input":0.19,"image_pixel":0,"transcribe":0,"image":0,"video":0}},{"id":"deepseek-ai/DeepSeek-V4-Pro","uuid":"endpoint-94151073-7212-43f8-9357-42a6043e1eef","object":"model","created":0,"type":"chat","running":false,"display_name":"Deepseek V4 Pro","organization":"Deepseek","context_length":512000,"config":{"chat_template":null,"stop":["<|end▁of▁sentence|>"],"bos_token":"<|begin▁of▁sentence|>","eos_token":"<|end▁of▁sentence|>"},"pricing":{"hourly":0,"input":1.74,"output":3.48,"base":0,"finetune":0,"cached_input":0.2,"image_pixel":0,"transcribe":0,"image":0,"video":0}},{"id":"nvidia/nemotron-3-ultra-550b-a55b","uuid":"endpoint-0f2ee6f7-0ad9-42e9-89df-cab8904dc46c","object":"model","created":0,"type":"chat","running":false,"display_name":"NVIDIA Nemotron 3 Ultra 550B A55B NVFP4","organization":"NVIDIA","context_length":512288,"config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":0.6,"output":3.6,"base":0,"finetune":0,"cached_input":0.2,"image_pixel":0,"transcribe":0,"image":0,"video":0}},{"id":"Qwen/Qwen3.7-Max","uuid":"endpoint-ba47b6c3-f84c-435c-9d86-d8142b17031b","object":"model","created":1779386434,"type":"chat","running":false,"display_name":"Qwen3.7 Max","organization":"Qwen","context_length":1000000,"config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":1.25,"output":3.75,"base":0,"finetune":0,"cached_input":0.125,"image_pixel":0,"transcribe":0,"image":0,"video":0}},{"id":"google/gemma-4-31B-it","uuid":"endpoint-155df9cc-8c2f-4a04-8840-728681211a34","object":"model","created":0,"type":"chat","running":false,"display_name":"Gemma 4 31B-it FP8","organization":"Google","link":"https://huggingface.co/api/models/google/gemma-4-31B-it","license":"apache-2.0","context_length":262144,"config":{"chat_template":null,"stop":[""],"bos_token":"","eos_token":""},"pricing":{"hourly":0,"input":0.39,"output":0.9700000000000001,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":0,"video":0}},{"id":"pearl-ai/gemma-4-31b-it","object":"model","created":1778777629,"type":"chat","running":false,"display_name":"Pearl-ai Gemma-4-31B-it-pearl","organization":"pearl.ai","link":"https://huggingface.co/pearl-ai/Gemma-4-31B-it-pearl","context_length":262144,"config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":0.27999999999999997,"output":0.86,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":0,"video":0}},{"id":"openai/gpt-oss-120b","uuid":"endpoint-cf361a3e-47d0-4dfc-851a-97098881e6a2","object":"model","created":1754414557,"type":"chat","running":false,"display_name":"OpenAI GPT-OSS 120B","organization":"OpenAI","link":"https://huggingface.co/openai/gpt-oss-120b","license":"other","context_length":131072,"config":{"chat_template":null,"stop":["<|return|>"],"bos_token":"<|startoftext|>","eos_token":"<|return|>"},"pricing":{"hourly":0,"input":0.15,"output":0.6,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":0,"video":0}},{"id":"openai/gpt-oss-20b","uuid":"endpoint-f382c20a-6806-4ac2-abfb-d00d7a0b0c2b","object":"model","created":1774480577,"type":"chat","running":false,"display_name":"OpenAI GPT-OSS 20B","organization":"OpenAI","link":"https://huggingface.co/api/models/openai/gpt-oss-20b","license":"apache-2.0","context_length":131072,"config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":0.05,"output":0.2,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":0,"video":0}},{"id":"Qwen/Qwen3.5-9B","uuid":"endpoint-71bb7894-08d4-4882-bb72-7c257c234513","object":"model","created":0,"type":"chat","running":false,"display_name":"Qwen3.5 9B FP8","organization":"Qwen","link":"https://huggingface.co/api/models/togethercomputer/Qwen3.5-9B-FP8-MLP","context_length":262144,"config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":"<|im_end|>"},"pricing":{"hourly":0,"input":0.17,"output":0.25,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":0,"video":0}},{"id":"meta-llama/Llama-3.3-70B-Instruct-Turbo","object":"model","created":1733466629,"type":"chat","running":false,"display_name":"Meta Llama 3.3 70B Instruct Turbo","organization":"Meta","link":"https://huggingface.co/meta-llama/Llama-3.3-70B-Instruct","license":"Llama-3.3 (Other)","context_length":131072,"config":{"chat_template":"{{- bos_token }}\n{%- if custom_tools is defined %}\n {%- set tools = custom_tools %}\n{%- endif %}\n{%- if not tools_in_user_message is defined %}\n {%- set tools_in_user_message = true %}\n{%- endif %}\n{%- if not date_string is defined %}\n {%- set date_string = \"26 Jul 2024\" %}\n{%- endif %}\n{%- if not tools is defined %}\n {%- set tools = none %}\n{%- endif %}\n\n{#- This block extracts the system message, so we can slot it into the right place. #}\n{%- if messages[0]['role'] == 'system' %}\n {%- set system_message = messages[0]['content']|trim %}\n {%- set messages = messages[1:] %}\n{%- else %}\n {%- set system_message = \"\" %}\n{%- endif %}\n\n{#- System message + builtin tools #}\n{{- \"<|start_header_id|>system<|end_header_id|>\\n\\n\" }}\n{%- if builtin_tools is defined or tools is not none %}\n {{- \"Environment: ipython\\n\" }}\n{%- endif %}\n{%- if builtin_tools is defined %}\n {{- \"Tools: \" + builtin_tools | reject('equalto', 'code_interpreter') | join(\", \") + \"\\n\\n\"}}\n{%- endif %}\n{{- \"Cutting Knowledge Date: December 2023\\n\" }}\n{{- \"Today Date: \" + date_string + \"\\n\\n\" }}\n{%- if tools is not none and not tools_in_user_message %}\n {{- \"You have access to the following functions. To call a function, please respond with JSON for a function call.\" }}\n {{- 'Respond in the format {\"name\": function name, \"parameters\": dictionary of argument name and its value}.' }}\n {{- \"Do not use variables.\\n\\n\" }}\n {%- for t in tools %}\n {{- t | tojson(indent=4) }}\n {{- \"\\n\\n\" }}\n {%- endfor %}\n{%- endif %}\n{{- system_message }}\n{{- \"<|eot_id|>\" }}\n\n{#- Custom tools are passed in a user message with some extra guidance #}\n{%- if tools_in_user_message and not tools is none %}\n {#- Extract the first user message so we can plug it in here #}\n {%- if messages | length != 0 %}\n {%- set first_user_message = messages[0]['content']|trim %}\n {%- set messages = messages[1:] %}\n {%- else %}\n {{- raise_exception(\"Cannot put tools in the first user message when there's no first user message!\") }}\n{%- endif %}\n {{- '<|start_header_id|>user<|end_header_id|>\\n\\n' -}}\n {{- \"Given the following functions, please respond with a JSON for a function call \" }}\n {{- \"with its proper arguments that best answers the given prompt.\\n\\n\" }}\n {{- 'Respond in the format {\"name\": function name, \"parameters\": dictionary of argument name and its value}.' }}\n {{- \"Do not use variables.\\n\\n\" }}\n {%- for t in tools %}\n {{- t | tojson(indent=4) }}\n {{- \"\\n\\n\" }}\n {%- endfor %}\n {{- first_user_message + \"<|eot_id|>\"}}\n{%- endif %}\n\n{%- for message in messages %}\n {%- if not (message.role == 'ipython' or message.role == 'tool' or 'tool_calls' in message) %}\n {{- '<|start_header_id|>' + message['role'] + '<|end_header_id|>\\n\\n'+ message['content'] | trim + '<|eot_id|>' }}\n {%- elif 'tool_calls' in message %}\n {%- if not message.tool_calls|length == 1 %}\n {{- raise_exception(\"This model only supports single tool-calls at once!\") }}\n {%- endif %}\n {%- set tool_call = message.tool_calls[0].function %}\n {%- if builtin_tools is defined and tool_call.name in builtin_tools %}\n {{- '<|start_header_id|>assistant<|end_header_id|>\\n\\n' -}}\n {{- \"<|python_tag|>\" + tool_call.name + \".call(\" }}\n {%- for arg_name, arg_val in tool_call.arguments | items %}\n {{- arg_name + '=\"' + arg_val + '\"' }}\n {%- if not loop.last %}\n {{- \", \" }}\n {%- endif %}\n {%- endfor %}\n {{- \")\" }}\n {%- else %}\n {{- '<|start_header_id|>assistant<|end_header_id|>\\n\\n' -}}\n {{- '{\"name\": \"' + tool_call.name + '\", ' }}\n {{- '\"parameters\": ' }}\n {{- tool_call.arguments | tojson }}\n {{- \"}\" }}\n {%- endif %}\n {%- if builtin_tools is defined %}\n {#- This means we're in ipython mode #}\n {{- \"<|eom_id|>\" }}\n {%- else %}\n {{- \"<|eot_id|>\" }}\n {%- endif %}\n {%- elif message.role == \"tool\" or message.role == \"ipython\" %}\n {{- \"<|start_header_id|>ipython<|end_header_id|>\\n\\n\" }}\n {%- if message.content is mapping or message.content is iterable %}\n {{- message.content | tojson }}\n {%- else %}\n {{- message.content }}\n {%- endif %}\n {{- \"<|eot_id|>\" }}\n {%- endif %}\n{%- endfor %}\n{%- if add_generation_prompt %}\n {{- '<|start_header_id|>assistant<|end_header_id|>\\n\\n' }}\n{%- endif %}\n","stop":["<|eot_id|>","<|eom_id|>"],"bos_token":"<|begin_of_text|>","eos_token":"<|eot_id|>"},"pricing":{"hourly":0,"input":1.0399999999999998,"output":1.0399999999999998,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":0,"video":0}},{"id":"google/gemma-3n-E4B-it","uuid":"endpoint-290b90f1-cdb9-46c1-a919-9a73822375c3","object":"model","created":1750955040,"type":"chat","running":false,"display_name":"Gemma 3N E4B Instruct","organization":"Google","link":"https://huggingface.co/google/gemma-3n-E4B-it","license":"gemma","context_length":32768,"config":{"chat_template":null,"stop":[""],"bos_token":"","eos_token":""},"pricing":{"hourly":0,"input":0.060000000000000005,"output":0.12000000000000001,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":0,"video":0}},{"id":"hexgrad/Kokoro-82M","object":"model","created":1773163054,"type":"audio","running":false,"display_name":"Kokoro 82M","organization":"Hexgrad","link":"https://huggingface.co/hexgrad/Kokoro-82M","license":"apache2","config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":4,"output":0,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":0,"video":0}},{"id":"canopylabs/orpheus-3b-0.1-ft","object":"model","created":1755731205,"type":"audio","running":false,"display_name":"Orpheus 3B 0.1 FT","organization":"Canopy Labs","link":"https://huggingface.co/canopylabs/orpheus-3b-0.1-ft","license":"apache2","config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":15,"output":0,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":0,"video":0}},{"id":"openai/whisper-large-v3","uuid":"endpoint-b0eaec1e-3edb-48c3-85a9-1af9b5ce09fb","object":"model","created":0,"type":"transcribe","running":false,"display_name":"Whisper large-v3","organization":"OpenAI","link":"https://huggingface.co/openai/whisper-large-v3","license":"apache2","context_length":1,"config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":0.27,"output":0.85,"base":0,"finetune":0,"image_pixel":0,"transcribe":{"price_per_minute":0.0015},"image":0,"video":0}},{"id":"black-forest-labs/FLUX.1-kontext-pro","object":"model","created":0,"type":"image","running":false,"display_name":"FLUX.1 Kontext [pro]","organization":"Black Forest Labs","context_length":0,"config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":0,"output":0,"base":0,"finetune":0,"image_pixel":{"price_per_megapixel":0.04,"min_steps":0},"transcribe":0,"image":0,"video":0}},{"id":"black-forest-labs/FLUX.1-kontext-max","object":"model","created":0,"type":"image","running":false,"display_name":"FLUX.1 Kontext [max]","organization":"Black Forest Labs","context_length":0,"config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":0,"output":0,"base":0,"finetune":0,"image_pixel":{"price_per_megapixel":0.08,"min_steps":0},"transcribe":0,"image":0,"video":0}},{"id":"black-forest-labs/FLUX.2-dev","uuid":"endpoint-268047b1-b295-4d9b-bc9f-239d375768ab","object":"model","created":1764086551,"type":"image","running":false,"display_name":"FLUX.2 [dev]","organization":"Black Forest Labs","config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":0,"output":0,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":{"example_price":0.0154,"example_description":"starting price per image"},"video":0}},{"id":"black-forest-labs/FLUX.2-flex","uuid":"endpoint-3d15053d-a558-487c-b0f8-068e9dfd781f","object":"model","created":1764090764,"type":"image","running":false,"display_name":"FLUX.2 [flex]","organization":"Black Forest Labs","config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":0,"output":0,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":{"example_price":0.03,"example_description":"per text-to-image"},"video":0}},{"id":"black-forest-labs/FLUX.2-pro","uuid":"endpoint-f6f3da91-6f41-4b38-b61c-40f60902b714","object":"model","created":1764070232,"type":"image","running":false,"display_name":"FLUX.2 [pro]","organization":"Black Forest Labs","config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":0,"output":0,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":{"example_price":0.03,"example_description":"per text-to-image image"},"video":0}},{"id":"black-forest-labs/FLUX.2-max","object":"model","created":0,"type":"image","running":false,"display_name":"FLUX.2 [max]","organization":"Black Forest Labs","context_length":0,"config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":0,"output":0,"base":0,"finetune":0,"image_pixel":{"price_per_megapixel":0.07,"min_steps":50},"transcribe":0,"image":0,"video":0}},{"id":"black-forest-labs/FLUX.1.1-pro","uuid":"endpoint-071376f6-db8a-44cf-9706-7ba0c9c14833","object":"model","created":0,"type":"image","running":false,"display_name":"FLUX1.1 [pro]","organization":"Black Forest Labs","link":"https://huggingface.co/black-forest-labs/FLUX.1-schnell","config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":0,"output":0,"base":0,"finetune":0,"image_pixel":{"price_per_megapixel":0.04,"min_steps":0},"transcribe":0,"image":0,"video":0}},{"id":"meta-llama/Llama-Guard-4-12B","uuid":"endpoint-2095a2fc-bb95-48df-b94f-f95ccb22fa93","object":"model","created":1746038486,"type":"moderation","running":false,"display_name":"Llama Guard 4 12B","organization":"Meta","link":"https://huggingface.co/meta-llama/Llama-Guard-4-12B","license":"other llama4","context_length":1048576,"config":{"chat_template":"{%- if messages | length % 2 == 0 -%}\n {%- set role = 'Agent' -%}\n{%- else -%}\n {%- set role = 'User' -%}\n{%- endif -%}\n\n{%- if categories is not defined -%}\n {%- set ns = namespace(contains_image=false) -%}\n\n {%- for message in messages -%}\n {%- for content in message['content'] | selectattr('type', 'equalto', 'image') -%}\n {%- set ns.contains_image = true -%}\n {%- endfor -%}\n {%- endfor -%}\n\n {%- if ns.contains_image -%}\n {%- set categories = {\n \"S1\": \"Violent Crimes.\",\n \"S2\": \"Non-Violent Crimes.\",\n \"S3\": \"Sex Crimes.\",\n \"S4\": \"Child Exploitation.\",\n \"S5\": \"Defamation.\",\n \"S6\": \"Specialized Advice.\",\n \"S7\": \"Privacy.\",\n \"S8\": \"Intellectual Property.\",\n \"S9\": \"Indiscriminate Weapons.\",\n \"S10\": \"Hate.\",\n \"S11\": \"Self-Harm.\",\n \"S12\": \"Sexual Content.\",\n \"S13\": \"Elections.\",\n } -%}\n {%- else -%}\n {%- set categories = {\n \"S1\": \"Violent Crimes.\",\n \"S2\": \"Non-Violent Crimes.\",\n \"S3\": \"Sex Crimes.\",\n \"S4\": \"Child Exploitation.\",\n \"S5\": \"Defamation.\",\n \"S6\": \"Specialized Advice.\",\n \"S7\": \"Privacy.\",\n \"S8\": \"Intellectual Property.\",\n \"S9\": \"Indiscriminate Weapons.\",\n \"S10\": \"Hate.\",\n \"S11\": \"Self-Harm.\",\n \"S12\": \"Sexual Content.\",\n \"S13\": \"Elections.\",\n \"S14\": \"Code Interpreter Abuse.\",\n } -%}\n {%- endif -%}\n{%- endif -%}\n\n{{ \"<|begin_of_text|><|header_start|>user<|header_end|>\\n\" }}\n{{ \"Task: Check if there is unsafe content in '\" + role + \"' messages in conversations according to our safety policy with the below categories.\\n\" }}\n{{ \"\\n\" }}\n\n{%- for key in categories -%}\n {%- if key not in excluded_category_keys -%}\n {{ key + \": \" + categories[key] + \"\\n\" }}\n {%- endif -%}\n{%- endfor -%}\n\n{{ \"\\n\" }}\n{{ \"\\n\" }}\n\n{%- for message in messages -%}\n {%- if (message['role'] == 'user') != (loop.index0 % 2 == 0) -%}\n {{ raise_exception('Conversation roles must alternate user/assistant/user/assistant/...') }}\n {%- endif -%}\n\n {%- set content = message['content'] -%}\n\n {%- if message['role'] == 'user' -%}\n {%- set role = 'User' -%}\n {%- elif message['role'] == 'assistant' -%}\n {%- set role = 'Agent' -%}\n {%- endif -%}\n\n {#— #1 Accumulate all images for this message —#}\n {%- set ns = namespace(img_tokens='') -%}\n {%- for img in message.content | selectattr('type', 'equalto', 'image') -%}\n {%- set ns.img_tokens = ns.img_tokens + '<|image|>' -%}\n {%- endfor -%}\n\n {#— #2 Then emit all text —#}\n {%- for txt in message.content | selectattr('type','equalto','text') -%}\n {{ role + ': ' }}{{ ns.img_tokens }}{{ txt.text | trim }}\\n\\n\n\n {#— clear the buffer so only first text prints images —#}\n {%- if loop.first -%}\n {%- set ns.img_tokens = '' -%}\n {%- endif -%}\n {%- endfor -%}\n{%- endfor -%}\n\n{{ \"\\n\" }}\n{{ \"Provide your safety assessment for ONLY THE LAST \" + role + \" message in the above conversation:\" }}\n{{ \" - First line must read 'safe' or 'unsafe'.\" }}\n{{ \" - If unsafe, a second line must include a comma-separated list of violated categories. <|eot|><|header_start|>assistant<|header_end|>\" }}","stop":["<|eot|>"],"bos_token":"<|begin_of_text|>","eos_token":"<|eot|>"},"pricing":{"hourly":0,"input":0.2,"output":0.2,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":0,"video":0}},{"id":"intfloat/multilingual-e5-large-instruct","uuid":"endpoint-b1b563e5-5ec2-4577-9017-16b52ac5c841","object":"model","created":1745513588,"type":"embedding","running":false,"display_name":"Multilingual E5 Large Instruct","organization":"Intfloat","link":"https://huggingface.co/api/models/intfloat/multilingual-e5-large-instruct","license":"mit","context_length":514,"config":{"chat_template":null,"stop":[""],"bos_token":"","eos_token":""},"pricing":{"hourly":0,"input":0.02,"output":0.02,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":0,"video":0}},{"id":"arize-ai/qwen-2-1.5b-instruct","uuid":"endpoint-22ce9f16-299a-47cc-b88f-c59cfb1d235e","object":"model","created":1745522693,"type":"chat","running":false,"display_name":"Arize AI Qwen 2 1.5B Instruct","organization":"Togethercomputer","link":"https://huggingface.co/api/models/togethercomputer/arize-ai-qwen-2-1.5b-instruct","context_length":32768,"config":{"chat_template":"{% for message in messages %}{% if loop.first and messages[0]['role'] != 'system' %}{{ '<|im_start|>system\nYou are a helpful assistant.<|im_end|>\n' }}{% endif %}{{'<|im_start|>' + message['role'] + '\n' + message['content'] + '<|im_end|>' + '\n'}}{% endfor %}{% if add_generation_prompt %}{{ '<|im_start|>assistant\n' }}{% endif %}","stop":["<|im_end|>"],"bos_token":"<|endoftext|>","eos_token":"<|im_end|>"},"pricing":{"hourly":0,"input":0.1,"output":0.1,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":0,"video":0}},{"id":"nvidia/parakeet-tdt-0.6b-v3","uuid":"endpoint-3fbe0c47-5c71-4f52-92fb-abaff932f05f","object":"model","created":0,"type":"transcribe","running":false,"display_name":"Nvidia Parakeet TDT 0.6B V3","organization":"Nvidia","link":"https://huggingface.co/nvidia/parakeet-tdt-0.6b-v3","context_length":448,"config":{"chat_template":null,"stop":["<|endoftext|>"],"bos_token":"<|endoftext|>","eos_token":"<|endoftext|>"},"pricing":{"hourly":0,"input":0,"output":0,"base":0,"finetune":0,"image_pixel":0,"transcribe":{"price_per_minute":0.0015},"image":0,"video":0}},{"id":"openai/gpt-image-1.5","uuid":"endpoint-11f45afc-3f72-41d1-b93e-902e220f4d5a","object":"model","created":1765980893,"type":"image","running":false,"display_name":"GPT Image 1.5","organization":"OpenAI","config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":0,"output":0,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":{"example_price":0.034,"example_description":"/opt/homebrew/bin/zsh.009 - /opt/homebrew/bin/zsh.199 per image based on quality"},"video":0}},{"id":"Wan-AI/Wan2.6-image","uuid":"endpoint-7dc7f98d-c562-4b5a-b710-c24875a6b471","object":"model","created":1769618722,"type":"image","running":false,"display_name":"Wan 2.6 Image","organization":"Wan-AI","config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":0,"output":0,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":{"example_price":0.03,"example_description":"per output image"},"video":0}},{"id":"google/veo-3.0-fast-audio","uuid":"endpoint-8bdb9924-b64e-4f44-ad5f-c979e578e7f4","object":"model","created":1759884907,"type":"video","running":false,"display_name":"Google Veo 3.0 Fast + Audio","organization":"Google","config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":0,"output":0,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":0,"video":{"example_price":1.2,"example_description":"1080p / 8s"}}},{"id":"vidu/vidu-q1","uuid":"endpoint-fea0b805-4d7e-45ec-8b1b-856c932f152c","object":"model","created":1759884996,"type":"video","running":false,"display_name":"Vidu Q1","organization":"Vidu","config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":0,"output":0,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":0,"video":{"example_price":0.22,"example_description":"1080p / 5s"}}},{"id":"cartesia/sonic","object":"model","created":1773696454,"type":"audio","running":false,"display_name":"Cartesia Sonic","organization":"Cartesia","link":"https://www.cartesia.ai","context_length":0,"config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":65,"output":0,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":0,"video":0}},{"id":"ByteDance-Seed/Seedream-3.0","uuid":"endpoint-c2769196-9347-46e4-815a-9c7abf5b8d50","object":"model","created":1759884740,"type":"image","running":false,"display_name":"ByteDance Seedream 3.0","organization":"ByteDance","config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":0,"output":0,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":{"example_price":0.018,"example_description":"720x1280"},"video":0}},{"id":"ByteDance-Seed/Seedream-4.0","uuid":"endpoint-e27a4640-becc-4a5a-92f4-3940b7be23e8","object":"model","created":1759884757,"type":"image","running":false,"display_name":"ByteDance Seedream 4.0","organization":"ByteDance","config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":0,"output":0,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":{"example_price":0.03,"example_description":"720x1280"},"video":0}},{"id":"Rundiffusion/Juggernaut-Lightning-Flux","uuid":"endpoint-63c3e50f-b9eb-41e3-a3ed-7242665874e4","object":"model","created":1759884814,"type":"image","running":false,"display_name":"Juggernaut Lightning Flux by RunDiffusion","organization":"RunDiffusion","config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":0,"output":0,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":{"example_price":0.0017,"example_description":"720x1280"},"video":0}},{"id":"google/veo-3.0-audio","uuid":"endpoint-ced52ba5-3cb0-46a3-aa92-d7a2f59d6bd9","object":"model","created":1759884892,"type":"video","running":false,"display_name":"Google Veo 3.0 + Audio","organization":"Google","config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":0,"output":0,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":0,"video":{"example_price":3.2,"example_description":"720p / 8s"}}},{"id":"kwaivgI/kling-2.1-master","uuid":"endpoint-5e489acf-5401-4843-97b7-8a830648bd3c","object":"model","created":1759884953,"type":"video","running":false,"display_name":"Kling 2.1 Master","organization":"kwaivgI","config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":0,"output":0,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":0,"video":{"example_price":0.924,"example_description":"1080p / 5s"}}},{"id":"ideogram/ideogram-3.0","uuid":"endpoint-3d82f587-56ba-45df-817d-854cd2117f41","object":"model","created":1759884808,"type":"image","running":false,"display_name":"Ideogram 3.0","organization":"ideogram","config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":0,"output":0,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":{"example_price":0.06,"example_description":"720x1280"},"video":0}},{"id":"kwaivgI/kling-2.1-pro","uuid":"endpoint-8fa3e87a-9f35-45fc-8157-8ed046498ba6","object":"model","created":1759884948,"type":"video","running":false,"display_name":"Kling 2.1 Pro","organization":"kwaivgI","config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":0,"output":0,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":0,"video":{"example_price":0.3234,"example_description":"1080p / 5s"}}},{"id":"google/veo-2.0","uuid":"endpoint-ad40ee70-5f82-4283-b2d8-2813a2773022","object":"model","created":1759884886,"type":"video","running":false,"display_name":"Google Veo 2.0","organization":"Google","config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":0,"output":0,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":0,"video":{"example_price":2.5,"example_description":"720p / 5s"}}},{"id":"openai/sora-2","uuid":"endpoint-c4adc1b3-6ac2-491a-b4b0-e0c3b3fea40f","object":"model","created":1760480340,"type":"video","running":false,"display_name":"Sora 2","organization":"OpenAI","config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":0,"output":0,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":0,"video":{"example_price":0.8,"example_description":"720p / 8s"}}},{"id":"kwaivgI/kling-2.1-standard","uuid":"endpoint-09e526e5-8428-4841-8242-c883b8600a8c","object":"model","created":1759884940,"type":"video","running":false,"display_name":"Kling 2.1 Standard","organization":"kwaivgI","config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":0,"output":0,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":0,"video":{"example_price":0.1848,"example_description":"720p / 5s"}}},{"id":"google/veo-3.0-fast","uuid":"endpoint-92bc9b5a-365e-48e2-bc37-e278671310cb","object":"model","created":1759884913,"type":"video","running":false,"display_name":"Google Veo 3.0 Fast","organization":"Google","config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":0,"output":0,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":0,"video":{"example_price":0.8,"example_description":"1080p / 8s"}}},{"id":"google/gemini-3-pro-image","uuid":"endpoint-d2f07d30-6a03-4f98-a52d-cdc5461cf639","object":"model","created":1763662095,"type":"image","running":false,"display_name":"Gemini 3 (Nano Banana Pro)","organization":"Google","config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":0,"output":0,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":{"example_price":0.134,"example_description":"1080p & 2K resolutions costs $0.134/image and 4K resolutions costs $0.24 per image"},"video":0}},{"id":"vidu/vidu-2.0","uuid":"endpoint-31518301-3076-47c8-b42f-542569955820","object":"model","created":1759885002,"type":"video","running":false,"display_name":"Vidu 2.0","organization":"Vidu","config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":0,"output":0,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":0,"video":{"example_price":0.8,"example_description":"720p / 8s"}}},{"id":"openai/sora-2-pro","uuid":"endpoint-03b9298b-8624-4c29-8055-941df060eda4","object":"model","created":1760480692,"type":"video","running":false,"display_name":"Sora 2 Pro","organization":"OpenAI","config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":0,"output":0,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":0,"video":{"example_price":3,"example_description":"1080p / 8s"}}},{"id":"pixverse/pixverse-v5","uuid":"endpoint-1588b5bc-5923-4672-be92-3199a579a18f","object":"model","created":1759884975,"type":"video","running":false,"display_name":"PixVerse v5","organization":"PixVerse","config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":0,"output":0,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":0,"video":{"example_price":0.299,"example_description":"1080p / 5s"}}},{"id":"stabilityai/stable-diffusion-xl-base-1.0","uuid":"endpoint-5bbe64a1-3798-4ad5-bfd5-aee40eca9564","object":"model","created":1759884771,"type":"image","running":false,"display_name":"SD XL","organization":"stabilityai","config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":0,"output":0,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":{"example_price":0.0019,"example_description":"720x1280"},"video":0}},{"id":"ByteDance/Seedance-1.0-lite","uuid":"endpoint-5467de41-51aa-4d08-98b5-8cd34dc19906","object":"model","created":1759884873,"type":"video","running":false,"display_name":"ByteDance Seedance 1.0 Lite","organization":"ByteDance","config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":0,"output":0,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":0,"video":{"example_price":0.143,"example_description":"720p / 5s"}}},{"id":"cartesia/sonic-3","object":"model","created":1774464715,"type":"audio","running":false,"display_name":"Cartesia Sonic 3","organization":"Cartesia","link":"https://www.cartesia.ai","context_length":448,"config":{"chat_template":null,"stop":["<|endoftext|>"],"bos_token":"<|endoftext|>","eos_token":"<|endoftext|>"},"pricing":{"hourly":0,"input":65,"output":0,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":0,"video":0}},{"id":"ByteDance/Seedance-1.0-pro","uuid":"endpoint-9419195a-e048-4865-bf8b-89343a3e9b84","object":"model","created":1759884879,"type":"video","running":false,"display_name":"ByteDance Seedance 1.0 Pro","organization":"ByteDance","config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":0,"output":0,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":0,"video":{"example_price":0.565,"example_description":"720p / 5s"}}},{"id":"google/imagen-4.0-fast","uuid":"endpoint-3ba3bc6f-fe2b-4446-9ec0-71e82ac3348d","object":"model","created":1759884793,"type":"image","running":false,"display_name":"Google Imagen 4.0 Fast","organization":"Google","config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":0,"output":0,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":{"example_price":0.02,"example_description":"720x1280"},"video":0}},{"id":"google/flash-image-2.5","uuid":"endpoint-e9655a27-b014-43b4-bff1-b343a0206e07","object":"model","created":1759884801,"type":"image","running":false,"display_name":"Gemini Flash Image 2.5 (Nano Banana)","organization":"Google","config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":0,"output":0,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":{"example_price":0.039,"example_description":"720x1280"},"video":0}},{"id":"minimax/hailuo-02","uuid":"endpoint-68520084-c967-42b6-bff4-a63b660bd0cf","object":"model","created":1759884967,"type":"video","running":false,"display_name":"MiniMax Hailuo 02","organization":"MiniMaxAI","config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":0,"output":0,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":0,"video":{"example_price":0.56,"example_description":"768p / 10s"}}},{"id":"google/imagen-4.0-ultra","uuid":"endpoint-40d2690e-57a7-4e89-987d-2a3e44c1302d","object":"model","created":1759884786,"type":"image","running":false,"display_name":"Google Imagen 4.0 Ultra","organization":"Google","config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":0,"output":0,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":{"example_price":0.06,"example_description":"720x1280"},"video":0}},{"id":"google/imagen-4.0-preview","uuid":"endpoint-b6561013-bc17-4aa3-9a76-89174973977b","object":"model","created":1759884778,"type":"image","running":false,"display_name":"Google Imagen 4.0 Preview","organization":"Google","config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":0,"output":0,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":{"example_price":0.04,"example_description":"720x1280"},"video":0}},{"id":"RunDiffusion/Juggernaut-pro-flux","uuid":"endpoint-1f51e977-a298-40aa-a0c6-d5865c37bc38","object":"model","created":1759884821,"type":"image","running":false,"display_name":"Juggernaut Pro Flux by RunDiffusion 1.0.0","organization":"RunDiffusion","config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":0,"output":0,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":{"example_price":0.0049,"example_description":"720x1280"},"video":0}},{"id":"Qwen/Qwen-Image","uuid":"endpoint-d4d29f48-ce86-4533-863a-23e9245f6570","object":"model","created":1759884857,"type":"image","running":false,"display_name":"Qwen Image","organization":"Qwen","config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":0,"output":0,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":{"example_price":0.0058,"example_description":"720x1280"},"video":0}},{"id":"google/veo-3.0","uuid":"endpoint-test-duplicate-001","object":"model","created":1778817876,"type":"video","running":false,"display_name":"Duplicate Test","organization":"Google","config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":0,"output":0,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":0,"video":{"example_price":0.08,"example_description":"test"}}},{"id":"kwaivgI/kling-1.6-standard","uuid":"endpoint-9f6794ed-52f7-414f-8974-d3b1ffb8702f","object":"model","created":1759884920,"type":"video","running":false,"display_name":"Kling 1.6 Standard","organization":"kwaivgI","config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":0,"output":0,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":0,"video":{"example_price":0.185,"example_description":"720p / 5s"}}},{"id":"minimax/video-01-director","uuid":"endpoint-d5929bff-e81e-4bab-8b20-17cb99936a68","object":"model","created":1759884960,"type":"video","running":false,"display_name":"MiniMax 01 Director","organization":"MiniMaxAI","config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":0,"output":0,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":0,"video":{}}},{"id":"cartesia/sonic-2","object":"model","created":1774464715,"type":"audio","running":false,"display_name":"Cartesia Sonic 2","organization":"Cartesia","context_length":448,"config":{"chat_template":null,"stop":["<|endoftext|>"],"bos_token":"<|endoftext|>","eos_token":"<|endoftext|>"},"pricing":{"hourly":0,"input":65,"output":0,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":0,"video":0}},{"id":"pixverse/pixverse-v5.6","uuid":"endpoint-5e8550be-7faf-411e-81ee-92773d4a1304","object":"model","created":1769621066,"type":"video","running":false,"display_name":"PixVerse v5.6","organization":"PixVerse","config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":0,"output":0,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":0,"video":{"example_price":0.1326,"example_description":"$0.1031 - $0.221 per 5 sec video without audio. Audio is an additional $0.1326"}}},{"id":"Qwen/Qwen-Image-2.0-Pro","uuid":"endpoint-ea16bed3-cfd1-477b-ad95-1ac0f28bfec2","object":"model","created":1773318281,"type":"image","running":false,"display_name":"Qwen Image 2.0 Pro","organization":"Qwen","config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":0,"output":0,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":{"example_price":0.075,"example_description":"per image"},"video":0}},{"id":"google/flash-image-3.1","uuid":"endpoint-f0e10a8e-9250-4bcc-b1a9-ae34f3ecdaec","object":"model","created":1772535344,"type":"image","running":false,"display_name":"Gemini 3.1 Flash Image (Nano Banana 2)","organization":"Google","config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":0,"output":0,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":{"example_price":0.04657,"example_description":"0.04657 for 512x512. For every input image used, it's an additional $0.00028. When using grounded search, $0.014 will be added on top."},"video":0}},{"id":"Qwen/Qwen-Image-2.0","uuid":"endpoint-9bd5c294-1a2e-4ffb-bf28-482e01eee56f","object":"model","created":1773251084,"type":"image","running":false,"display_name":"Qwen Image 2.0","organization":"Qwen","config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":0,"output":0,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":{"example_price":0.035,"example_description":"per image"},"video":0}},{"id":"Wan-AI/wan2.7-t2v","uuid":"endpoint-4e24da5f-2274-44ad-8bf3-36dc47a8114a","object":"model","created":1775245808,"type":"video","running":false,"display_name":"Wan 2.7 T2V","organization":"Wan-AI","config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":0,"output":0,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":0,"video":{"example_price":0.1,"example_description":"per 5 seconds of video"}}},{"id":"Wan-AI/wan2.7-i2v","uuid":"endpoint-47e29650-3293-4538-bc90-fa3f07b159dc","object":"model","created":1775254675,"type":"video","running":false,"display_name":"Wan 2.7 I2V","organization":"Wan-AI","config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":0,"output":0,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":0,"video":{"example_price":0.1,"example_description":"per 5 seconds of video"}}},{"id":"Wan-AI/wan2.7-r2v","uuid":"endpoint-819be224-66c1-424d-8d79-7d527bcf278c","object":"model","created":1775257231,"type":"video","running":false,"display_name":"Wan 2.7 R2V","organization":"Wan-AI","config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":0,"output":0,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":0,"video":{"example_price":0.1,"example_description":"per 5 seconds of video"}}},{"id":"vidu/vidu-q3","uuid":"endpoint-002dc245-03bd-4e03-bdb0-e3fd55e25aba","object":"model","created":1776175177,"type":"video","running":false,"display_name":"Vidu Q3","organization":"Vidu","config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":0,"output":0,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":0,"video":{"example_price":0.0975,"example_description":"0.0455 - 0.1040 per second depending on resolution"}}},{"id":"vidu/vidu-q3-turbo","uuid":"endpoint-1381491a-63c3-4513-abdc-15005e5e85a3","object":"model","created":1776175206,"type":"video","running":false,"display_name":"Vidu Q3 Turbo","organization":"Vidu","config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":0,"output":0,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":0,"video":{"example_price":0.195,"example_description":"0.13 - 0.26 per second depending on resolution"}}},{"id":"google/veo-3.1-test-debug","uuid":"endpoint-test-debug-001","object":"model","created":0,"type":"video","running":false,"display_name":"Veo 3.1 Debug Test","organization":"Google","config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":0,"output":0,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":0,"video":{"example_price":0.08,"example_description":"test"}}},{"id":"pixverse/pixverse-v6","uuid":"endpoint-9782553a-d1f6-4641-b70f-cf3664e95a8a","object":"model","created":1776953730,"type":"video","running":false,"display_name":"PixVerse v6","organization":"PixVerse","config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":0,"output":0,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":0,"video":{"example_price":0.09,"example_description":"0.090/s at 1080p without audio. 0.115/s with audio"}}},{"id":"ByteDance/Seedance-2.0","uuid":"endpoint-1d17df31-ca97-4848-869e-be0f68b096a7","object":"model","created":1776942761,"type":"video","running":false,"display_name":"ByteDance Seedance 2.0","organization":"ByteDance","config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":0,"output":0,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":0,"video":{"example_price":0.16,"example_description":"Text/Image to Video at 720P: $0.16/sec & Video-to-Video at 720P: from $0.28/sec"}}},{"id":"Qwen/Qwen3.6-Plus","uuid":"endpoint-78f9d01e-0c22-47dc-b2b2-6aa0e2f3570c-v2","object":"model","created":1777340375,"type":"chat","running":false,"display_name":"Qwen3.6 Plus","organization":"Qwen","context_length":1000000,"config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":0.5,"output":3,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":0,"video":0}},{"id":"HappyHorse/HappyHorse-1.0-T2V","object":"model","created":1777283507,"type":"video","running":false,"display_name":"","config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":0,"output":0,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":0,"video":{"example_price":0.1,"example_description":"per 5 seconds of video"}}},{"id":"alibaba/happyhorse-1.0-t2v","uuid":"endpoint-e65e99d1-97f1-443f-94e2-dd139e102897","object":"model","created":1777714549,"type":"video","running":false,"display_name":"HappyHorse 1.0 T2V","organization":"Alibaba","config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":0,"output":0,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":0,"video":{"example_price":0.24,"example_description":"Text to Video at 720P: $0.14/sec and $0.24/sec at 1080p"}}},{"id":"alibaba/happyhorse-1.0-r2v","uuid":"endpoint-320deb45-9a43-46b2-8393-32b466ce9bce","object":"model","created":1777717813,"type":"video","running":false,"display_name":"HappyHorse 1.0 R2V","organization":"Alibaba","config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":0,"output":0,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":0,"video":{"example_price":0.24,"example_description":"Text/Image to Video at 720P: $0.14/sec and $0.24/sec at 1080p"}}},{"id":"alibaba/happyhorse-1.0-i2v","uuid":"endpoint-0fdc51d3-6dd3-4f2c-bce8-418ab47b36ea","object":"model","created":1777717851,"type":"video","running":false,"display_name":"HappyHorse 1.0 I2V","organization":"Alibaba","config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":0,"output":0,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":0,"video":{"example_price":0.24,"example_description":"Text/Image to Video at 720P: $0.14/sec and $0.24/sec at 1080p"}}},{"id":"ByteDance/Seedream-5.0-lite","uuid":"endpoint-90244fc5-096f-4bca-b5f2-79664175e2c4","object":"model","created":1778252567,"type":"image","running":false,"display_name":"ByteDance Seedream 5.0 Lite","organization":"ByteDance","config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":0,"output":0,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":{"example_price":0.035,"example_description":"Pricing is $0.035 for both 2K & 3K outputs"},"video":0}},{"id":"google/veo-3.1","uuid":"endpoint-b0a69f31-f14c-4825-9c01-cf20b5aeece9","object":"model","created":1776790993,"type":"video","running":false,"display_name":"Veo 3.1","organization":"Google","config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":0,"output":0,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":0,"video":{"example_price":0.08,"example_description":"0.08/ per 4s at 720p without audio. .60/s with audio"}}},{"id":"google/veo-3.1-lite","uuid":"endpoint-0a06c93a-68ce-48f6-bfbf-d9a0337a073b","object":"model","created":1778615460,"type":"video","running":false,"display_name":"Veo 3.1 Lite","organization":"Google","config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":0,"output":0,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":0,"video":{"example_price":0.05,"example_description":"0.05/s at 1080p without audio. 0.80/s with audio."}}},{"id":"nvidia/nemotron-3.5-asr-streaming-0.6b","uuid":"endpoint-cd9d043d-92ac-4320-af6a-2638e934861a","object":"model","created":0,"type":"transcribe","running":false,"display_name":"Nvidia Nemotron 3.5 ASR Streaming 0.6B","organization":"Nvidia","link":"https://huggingface.co/nvidia/nemotron-3.5-asr-streaming-0.6b","license":"apache-2.0","context_length":448,"config":{"chat_template":null,"stop":[],"bos_token":"<|endoftext|>","eos_token":"<|endoftext|>"},"pricing":{"hourly":0,"input":0,"output":0,"base":0,"finetune":0,"image_pixel":0,"transcribe":{"price_per_minute":0.0015},"image":0,"video":0}},{"id":"nvidia/nemotron-3-asr-streaming-0.6b","uuid":"endpoint-614e0569-b81e-4234-b08e-976d81913415","object":"model","created":0,"type":"transcribe","running":false,"display_name":"Nvidia Nemotron 3 ASR Streaming 0.6B","organization":"Nvidia","link":"https://huggingface.co/nvidia/nemotron-speech-streaming-en-0.6b","license":"apache-2.0","context_length":448,"config":{"chat_template":null,"stop":[],"bos_token":"<|endoftext|>","eos_token":"<|endoftext|>"},"pricing":{"hourly":0,"input":0.45,"output":0,"base":0,"finetune":0,"image_pixel":0,"transcribe":{"price_per_minute":0.0015},"image":0,"video":0}},{"id":"ideogram/ideogram-4.0","uuid":"endpoint-0304633d-06c9-4d89-a093-eaf52cc62aae","object":"model","created":1780584367,"type":"image","running":false,"display_name":"Ideogram 4.0","organization":"ideogram","config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":0,"output":0,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":{"example_price":0.06,"example_description":"per image price ranging from 0.03 - 0.10 per based on size and quality"},"video":0}},{"id":"openai/gpt-image-2","uuid":"endpoint-3a75d1cd-a76f-4277-b7f6-a6c62d05901b","object":"model","created":1776938977,"type":"image","running":false,"display_name":"GPT Image 2","organization":"OpenAI","config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":0,"output":0,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":{"example_price":0.053,"example_description":"0.006 - 0.165 per image based on size and quality"},"video":0}},{"id":"Qwen/Qwen3.7-Plus","uuid":"endpoint-ddc9fb60-6793-469c-ab42-a6db76013f67","object":"model","created":1781532368,"type":"chat","running":false,"display_name":"Qwen3.7 Plus","organization":"Qwen","context_length":1000000,"config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":0.32,"output":1.28,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":0,"video":0}},{"id":"alibaba/happyhorse-1.1-t2v","uuid":"endpoint-bae418aa-f3a0-42b7-bf16-25639335bee5","object":"model","created":1782485613,"type":"video","running":false,"display_name":"HappyHorse 1.1 T2V","organization":"Alibaba","config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":0,"output":0,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":0,"video":{"example_price":0.14,"example_description":"Text to Video at 720P: $0.14/sec and $0.18/sec at 1080p"}}},{"id":"alibaba/happyhorse-1.1-i2v","uuid":"endpoint-1d482f72-1593-4648-949f-09481c618521","object":"model","created":1782485593,"type":"video","running":false,"display_name":"HappyHorse 1.1 I2V","organization":"Alibaba","config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":0,"output":0,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":0,"video":{"example_price":0.14,"example_description":"Text/Image to Video at 720P: $0.14/sec and $0.18/sec at 1080p"}}},{"id":"alibaba/happyhorse-1.1-r2v","uuid":"endpoint-87cf37d3-6892-40ce-b1ff-56d5aeb80c44","object":"model","created":1782485628,"type":"video","running":false,"display_name":"HappyHorse 1.1 R2V","organization":"Alibaba","config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":0,"output":0,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":0,"video":{"example_price":0.14,"example_description":"Text/Image to Video at 720P: $0.14/sec and $0.18/sec at 1080p"}}},{"id":"google/flash-image-3.1-lite","uuid":"endpoint-acb856f2-4ab1-440e-ba58-2bd6cea1b536","object":"model","created":1782846618,"type":"image","running":false,"display_name":"Gemini 3.1 Flash-Lite Image (Nano Banana 2 Lite)","organization":"Google","config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":0,"output":0,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":{"example_price":0.069,"example_description":"price per image"},"video":0}},{"id":"Prism-ML/Ternary-Bonsai-27B","uuid":"endpoint-6c5092a2-b920-4be3-9e45-1c5cb7eee78f","object":"model","created":0,"type":"chat","running":false,"display_name":"Ternary Bonsai 27B","organization":"Prism Ml","link":"https://huggingface.co/api/models/prism-ml/Ternary-Bonsai-27B-AWQ-4bit","license":"apache-2.0","context_length":262144,"config":{"chat_template":null,"stop":["<|im_end|>"],"bos_token":null,"eos_token":"<|im_end|>"},"pricing":{"hourly":0,"input":0,"output":0,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":0,"video":0}},{"id":"prunaai/p-image-ideogram","uuid":"endpoint-c045bc1c-6174-4d1c-bee0-716fed7e4609","object":"model","created":1785844762,"type":"image","running":false,"display_name":"P-Image-Ideogram","organization":"Pruna AI","config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":0,"output":0,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":{"example_price":0.00225,"example_description":"Pricing starts at $0.00225 per image"},"video":0}},{"id":"black-forest-labs/FLUX-3","uuid":"endpoint-bec520ab-d414-4fad-aad8-d801da1cff65","object":"model","created":1785896986,"type":"video","running":false,"display_name":"FLUX 3","organization":"Black Forest Labs","config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":0,"output":0,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":0,"video":{"example_price":0.17,"example_description":"T2V @ 720p is $0.17/s, T2V @ 1080p is $0.29/s, V2V @720 is $0.43/s, V2V @1080p is $0.54/s"}}},{"id":"ByteDance/Seedance-2.5","uuid":"endpoint-d0ba33d4-1c4e-43db-9f3f-c8a4c2885dad","object":"model","created":1786388202,"type":"video","running":false,"display_name":"ByteDance Seedance 2.5","organization":"ByteDance","config":{"chat_template":null,"stop":[],"bos_token":null,"eos_token":null},"pricing":{"hourly":0,"input":0,"output":0,"base":0,"finetune":0,"image_pixel":0,"transcribe":0,"image":0,"video":{"example_price":0.115,"example_description":"480P: $0.115/sec & 720P: from $0.249/sec"}}}]
\ No newline at end of file
diff --git a/tests/test_litellm/test_sync_together_ai_models.py b/tests/test_litellm/test_sync_together_ai_models.py
new file mode 100644
index 00000000000..7c1287e94b8
--- /dev/null
+++ b/tests/test_litellm/test_sync_together_ai_models.py
@@ -0,0 +1,351 @@
+import importlib.util
+import json
+from pathlib import Path
+from types import MappingProxyType
+
+import pytest
+
+ROOT = Path(__file__).resolve().parents[2]
+SCRIPT = ROOT / "scripts" / "sync_together_ai_models.py"
+FIXTURES = Path(__file__).resolve().parent / "fixtures" / "together_ai_sync"
+
+_spec = importlib.util.spec_from_file_location("sync_together_ai_models", SCRIPT)
+assert _spec is not None and _spec.loader is not None
+sync = importlib.util.module_from_spec(_spec)
+_spec.loader.exec_module(sync)
+
+RECORDED_CATALOG = sync.load_catalog(FIXTURES.joinpath("models_serverless.json").read_bytes())
+RECORDED_DOC = sync.parse_deprecations(FIXTURES.joinpath("deprecations.md").read_text())
+
+
+def _doc(removal_dates: dict[str, str], redirects: dict[str, str] | None = None) -> object:
+ return sync.DeprecationDoc(
+ removal_dates=MappingProxyType(removal_dates),
+ redirects=MappingProxyType(redirects or {}),
+ )
+
+
+def _chat_model(model_id: str, ctx: int = 4096, price: float = 1.0, cached: float | None = None) -> object:
+ return sync.CatalogModel(
+ id=model_id,
+ type="chat",
+ context_length=ctx,
+ pricing=sync.CatalogPricing(input=price, output=price, cached_input=cached),
+ )
+
+
+@pytest.mark.parametrize(
+ ("per_million", "expected"),
+ [
+ (3, 3e-06),
+ (15, 1.5e-05),
+ (1.4, 1.4e-06),
+ (0.25999999999999995, 2.6e-07),
+ (0.060000000000000005, 6e-08),
+ (1.0399999999999998, 1.04e-06),
+ (0, 0.0),
+ ],
+)
+def test_per_token_normalizes_float_artifacts(per_million: float, expected: float) -> None:
+ assert sync.per_token(per_million) == expected
+
+
+def test_parse_deprecations_recorded_fixture() -> None:
+ assert dict(RECORDED_DOC.redirects) == {
+ "mistralai/Mistral-7B-Instruct-v0.3": "mistralai/Ministral-3-14B-Instruct-2512",
+ "Kimi-K2": "Kimi-K2-0905",
+ "DeepSeek-V3": "DeepSeek-V3.1",
+ "DeepSeek-V3-0324": "DeepSeek-V3.1",
+ "DeepSeek-R1": "DeepSeek-R1-0528",
+ }
+ assert len(RECORDED_DOC.removal_dates) == 208
+ assert RECORDED_DOC.removal_dates["google/gemma-3n-E4B-it"] == "2026-08-04"
+
+
+def test_parse_deprecations_duplicate_rows_keep_most_recent_date() -> None:
+ assert RECORDED_DOC.removal_dates["Qwen/Qwen3-235B-A22B-Thinking-2507"] == "2026-04-16"
+
+
+@pytest.mark.parametrize(
+ "markdown",
+ [
+ "# Deprecations\n\nNothing here anymore.\n",
+ "\n## Active model redirects\n\n| A | B |\n| --- | --- |\n| `x` | `y` |\n\n## Something else\n",
+ "\n## Deprecation history\n\n### Inference\n\n| Date | Model | R |\n| --- | --- | --- |\n| 2026-01-01 | `m` | No |\n",
+ ],
+)
+def test_parse_deprecations_raises_when_a_table_parses_empty(markdown: str) -> None:
+ with pytest.raises(sync.SyncError):
+ sync.parse_deprecations(markdown)
+
+
+def test_load_catalog_raises_on_shape_change() -> None:
+ with pytest.raises(sync.SyncError):
+ sync.load_catalog(b'[{"id": "x", "type": "chat"}]')
+
+
+def test_load_catalog_raises_when_no_token_models_remain() -> None:
+ only_video = json.dumps([{"id": "v", "type": "video", "pricing": {"input": 0, "output": 0}}]).encode()
+ with pytest.raises(sync.SyncError):
+ sync.load_catalog(only_video)
+
+
+def test_recorded_catalog_counts() -> None:
+ assert len(RECORDED_CATALOG) == 102
+ assert sum(1 for model in RECORDED_CATALOG if model.type in sync.TYPE_TO_MODE) == 26
+ assert sum(1 for model in RECORDED_CATALOG if model.pricing.cached_input) == 13
+
+
+def test_added_chat_model_matches_reviewed_registry_shape() -> None:
+ outcome = sync.compute_sync({}, RECORDED_CATALOG, RECORDED_DOC)
+ assert len(outcome.added) == 26
+ assert not outcome.deprecated
+ assert outcome.cost_map["together_ai/moonshotai/Kimi-K3"] == {
+ "cache_read_input_token_cost": 3e-07,
+ "input_cost_per_token": 3e-06,
+ "litellm_provider": "together_ai",
+ "max_input_tokens": 1048576,
+ "max_output_tokens": 1048576,
+ "max_tokens": 1048576,
+ "mode": "chat",
+ "output_cost_per_token": 1.5e-05,
+ "source": "https://docs.together.ai/docs/serverless-models",
+ "supports_function_calling": True,
+ "supports_parallel_function_calling": True,
+ "supports_prompt_caching": True,
+ "supports_reasoning": True,
+ "supports_response_schema": True,
+ "supports_tool_choice": True,
+ "supports_vision": True,
+ }
+
+
+def test_added_embedding_model_has_no_output_token_cap() -> None:
+ outcome = sync.compute_sync({}, RECORDED_CATALOG, RECORDED_DOC)
+ assert outcome.cost_map["together_ai/intfloat/multilingual-e5-large-instruct"] == {
+ "input_cost_per_token": 2e-08,
+ "litellm_provider": "together_ai",
+ "max_input_tokens": 514,
+ "max_tokens": 514,
+ "mode": "embedding",
+ "output_cost_per_token": 2e-08,
+ "output_vector_size": 1024,
+ "source": "https://docs.together.ai/docs/serverless-models",
+ }
+
+
+def test_moderation_type_maps_to_chat_mode() -> None:
+ outcome = sync.compute_sync({}, RECORDED_CATALOG, RECORDED_DOC)
+ guard = outcome.cost_map["together_ai/meta-llama/Llama-Guard-4-12B"]
+ assert guard["mode"] == "chat"
+ assert guard["max_output_tokens"] == 1048576
+
+
+def test_docs_removed_but_live_model_stays_live_with_warning() -> None:
+ outcome = sync.compute_sync({}, RECORDED_CATALOG, RECORDED_DOC)
+ gemma = outcome.cost_map["together_ai/google/gemma-3n-E4B-it"]
+ assert "deprecation_date" not in gemma
+ assert any("gemma-3n-E4B-it" in warning and "2026-08-04" in warning for warning in outcome.warnings)
+
+
+def test_price_change_updates_api_fields_and_keeps_curated_ones() -> None:
+ registry = {
+ "together_ai/acme/chat-1": {
+ "input_cost_per_token": 9e-07,
+ "litellm_provider": "together_ai",
+ "max_input_tokens": 4096,
+ "max_output_tokens": 2048,
+ "max_tokens": 2048,
+ "mode": "chat",
+ "output_cost_per_token": 9e-07,
+ "supports_audio_input": True,
+ }
+ }
+ outcome = sync.compute_sync(registry, [_chat_model("acme/chat-1", ctx=8192, price=2.0)], _doc({"x": "2026-01-01"}))
+ entry = outcome.cost_map["together_ai/acme/chat-1"]
+ assert entry["input_cost_per_token"] == 2e-06
+ assert entry["max_input_tokens"] == 8192
+ assert entry["max_output_tokens"] == 2048
+ assert entry["supports_audio_input"] is True
+ assert len(outcome.updated) == 1
+ assert "input_cost_per_token" in outcome.updated[0]
+
+
+def test_cached_input_appearing_and_disappearing() -> None:
+ registry = {
+ "together_ai/acme/chat-1": {
+ "cache_read_input_token_cost": 1e-07,
+ "input_cost_per_token": 1e-06,
+ "litellm_provider": "together_ai",
+ "max_input_tokens": 4096,
+ "mode": "chat",
+ "output_cost_per_token": 1e-06,
+ "supports_prompt_caching": True,
+ },
+ "together_ai/acme/chat-2": {
+ "input_cost_per_token": 1e-06,
+ "litellm_provider": "together_ai",
+ "max_input_tokens": 4096,
+ "mode": "chat",
+ "output_cost_per_token": 1e-06,
+ },
+ }
+ catalog = [_chat_model("acme/chat-1"), _chat_model("acme/chat-2", cached=0.25999999999999995)]
+ outcome = sync.compute_sync(registry, catalog, _doc({"x": "2026-01-01"}))
+ assert "cache_read_input_token_cost" not in outcome.cost_map["together_ai/acme/chat-1"]
+ assert "supports_prompt_caching" not in outcome.cost_map["together_ai/acme/chat-1"]
+ assert outcome.cost_map["together_ai/acme/chat-2"]["cache_read_input_token_cost"] == 2.6e-07
+ assert outcome.cost_map["together_ai/acme/chat-2"]["supports_prompt_caching"] is True
+
+
+def test_capability_rule_backfills_existing_entry() -> None:
+ registry = {
+ "together_ai/moonshotai/Kimi-K3": {
+ "input_cost_per_token": 3e-06,
+ "litellm_provider": "together_ai",
+ "max_input_tokens": 1048576,
+ "mode": "chat",
+ "output_cost_per_token": 1.5e-05,
+ }
+ }
+ kimi = next(model for model in RECORDED_CATALOG if model.id == "moonshotai/Kimi-K3")
+ outcome = sync.compute_sync(registry, [kimi], _doc({"x": "2026-01-01"}))
+ assert outcome.cost_map["together_ai/moonshotai/Kimi-K3"]["supports_reasoning"] is True
+ assert any("supports_reasoning" in line for line in outcome.updated)
+
+
+def test_disappeared_model_gets_docs_date_and_is_never_deleted() -> None:
+ registry = {
+ "together_ai/acme/gone": {
+ "input_cost_per_token": 1e-06,
+ "litellm_provider": "together_ai",
+ "mode": "chat",
+ "output_cost_per_token": 1e-06,
+ }
+ }
+ outcome = sync.compute_sync(registry, [_chat_model("acme/alive")], _doc({"acme/gone": "2026-07-01"}))
+ assert outcome.cost_map["together_ai/acme/gone"]["deprecation_date"] == "2026-07-01"
+ assert outcome.deprecated == ("together_ai/acme/gone: deprecation_date",)
+
+
+def test_disappeared_model_without_docs_date_warns_instead() -> None:
+ registry = {
+ "together_ai/acme/gone": {
+ "input_cost_per_token": 1e-06,
+ "litellm_provider": "together_ai",
+ "mode": "chat",
+ "output_cost_per_token": 1e-06,
+ }
+ }
+ outcome = sync.compute_sync(registry, [_chat_model("acme/alive")], _doc({"other": "2026-07-01"}))
+ assert "deprecation_date" not in outcome.cost_map["together_ai/acme/gone"]
+ assert not outcome.deprecated
+ assert any("acme/gone" in warning and "human" in warning for warning in outcome.warnings)
+
+
+def test_curated_deprecation_date_is_never_overwritten() -> None:
+ registry = {
+ "together_ai/acme/gone": {
+ "deprecation_date": "2026-06-15",
+ "input_cost_per_token": 1e-06,
+ "litellm_provider": "together_ai",
+ "mode": "chat",
+ "output_cost_per_token": 1e-06,
+ }
+ }
+ outcome = sync.compute_sync(registry, [_chat_model("acme/alive")], _doc({"acme/gone": "2026-07-01"}))
+ assert outcome.cost_map["together_ai/acme/gone"]["deprecation_date"] == "2026-06-15"
+ assert any("2026-06-15" in warning and "2026-07-01" in warning for warning in outcome.warnings)
+
+
+def test_redirect_chain_resolves_to_final_live_model() -> None:
+ doc = _doc({"acme/a": "2026-01-01"}, redirects={"acme/a": "acme/b", "acme/b": "acme/c"})
+ live = frozenset({"acme/c"})
+ assert sync.resolve_successor("acme/a", doc, live) == "acme/c"
+
+
+def test_redirect_dead_end_yields_no_successor() -> None:
+ doc = _doc({"acme/a": "2026-01-01"}, redirects={"acme/a": "acme/b"})
+ assert sync.resolve_successor("acme/a", doc, frozenset({"acme/other"})) is None
+
+
+def test_redirect_short_names_resolve_by_unique_suffix() -> None:
+ doc = _doc({"moonshotai/Kimi-K2": "2026-01-01"}, redirects={"Kimi-K2": "Kimi-K2-0905"})
+ live = frozenset({"moonshotai/Kimi-K2-0905"})
+ assert sync.resolve_successor("moonshotai/Kimi-K2", doc, live) == "moonshotai/Kimi-K2-0905"
+
+
+def test_successor_written_only_when_not_curated() -> None:
+ registry = {
+ "together_ai/acme/a": {
+ "input_cost_per_token": 1e-06,
+ "litellm_provider": "together_ai",
+ "mode": "chat",
+ "output_cost_per_token": 1e-06,
+ },
+ "together_ai/acme/b": {
+ "input_cost_per_token": 1e-06,
+ "litellm_provider": "together_ai",
+ "metadata": {"successor": "together_ai/acme/curated"},
+ "mode": "chat",
+ "output_cost_per_token": 1e-06,
+ },
+ }
+ doc = _doc({"acme/a": "2026-01-01", "acme/b": "2026-01-01"}, redirects={"acme/a": "acme/c", "acme/b": "acme/c"})
+ outcome = sync.compute_sync(registry, [_chat_model("acme/c")], doc)
+ assert outcome.cost_map["together_ai/acme/a"]["metadata"] == {"successor": "together_ai/acme/c"}
+ assert outcome.cost_map["together_ai/acme/b"]["metadata"] == {"successor": "together_ai/acme/curated"}
+ assert any("acme/curated" in warning for warning in outcome.warnings)
+
+
+def test_reappearance_clears_deprecation_date() -> None:
+ registry = {
+ "together_ai/acme/back": {
+ "deprecation_date": "2026-05-01",
+ "input_cost_per_token": 1e-06,
+ "litellm_provider": "together_ai",
+ "max_input_tokens": 4096,
+ "mode": "chat",
+ "output_cost_per_token": 1e-06,
+ }
+ }
+ outcome = sync.compute_sync(registry, [_chat_model("acme/back")], _doc({"x": "2026-01-01"}))
+ assert "deprecation_date" not in outcome.cost_map["together_ai/acme/back"]
+ assert outcome.reappeared == ("together_ai/acme/back",)
+
+
+def test_new_chat_model_without_rule_is_flagged() -> None:
+ outcome = sync.compute_sync({}, [_chat_model("acme/unreviewed")], _doc({"x": "2026-01-01"}))
+ assert any("acme/unreviewed" in warning and "capability rule" in warning for warning in outcome.warnings)
+
+
+def test_new_keys_land_at_the_end_of_the_provider_block() -> None:
+ registry = {
+ "aaa": {"mode": "chat"},
+ "together_ai/acme/old": {
+ "input_cost_per_token": 1e-06,
+ "litellm_provider": "together_ai",
+ "mode": "chat",
+ "output_cost_per_token": 1e-06,
+ },
+ "zzz": {"mode": "chat"},
+ }
+ outcome = sync.compute_sync(registry, [_chat_model("acme/old"), _chat_model("acme/new")], _doc({"x": "2026-01-01"}))
+ assert list(outcome.cost_map) == ["aaa", "together_ai/acme/old", "together_ai/acme/new", "zzz"]
+
+
+def test_sync_is_idempotent_over_the_repo_cost_map() -> None:
+ cost_map = json.loads((ROOT / "model_prices_and_context_window.json").read_text())
+ first = sync.compute_sync(cost_map, RECORDED_CATALOG, RECORDED_DOC)
+ second = sync.compute_sync(first.cost_map, RECORDED_CATALOG, RECORDED_DOC)
+ assert not second.has_changes
+ assert second.cost_map == first.cost_map
+
+
+def test_pr_body_lists_every_section_and_the_skipped_types() -> None:
+ outcome = sync.compute_sync({}, RECORDED_CATALOG, RECORDED_DOC)
+ body = sync.render_pr_body(outcome)
+ assert "### Added (26)" in body
+ assert "### Warnings needing a human call" in body
+ assert "image (29)" in body
+ assert "video (38)" in body