Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion common/config_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -462,7 +462,9 @@ class SamplingConfig(BaseConfigModel):
None,
description=(
"Select a sampler override preset (default: None).\n"
"Find this in the sampler-overrides folder.\n"
"This is a preset name, not a path: TabbyAPI reads "
"sampler_overrides/<name>.yml relative to the directory it is "
"launched from.\n"
"This overrides default fallbacks for sampler values "
"that are passed to the API.\n"
"NOTE: safe_defaults preset provides a fallback for frontends "
Expand Down
33 changes: 26 additions & 7 deletions common/sampling.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@
from common.utils import filter_none_values, unwrap


# Directory that sampler override presets are looked up in. This is a relative
# path, so it resolves against the current working directory (where TabbyAPI
# was launched from) rather than the directory TabbyAPI is installed in.
SAMPLER_OVERRIDES_DIR = pathlib.Path("sampler_overrides")

# Params that are accepted for API compatibility but not implemented by the
# exllamav3 backend, mapped to the neutral value that leaves them inactive.
# Requests that activate any of these get a warning and the param is ignored.
Expand Down Expand Up @@ -408,9 +413,16 @@ def overrides_from_dict(new_overrides: dict):


async def overrides_from_file(preset_name: str):
"""Fetches an override preset from a file"""
"""
Fetches an override preset from a file.

The preset name is not a path: it is looked up as
`sampler_overrides/<preset_name>.yml` relative to the current working
directory, so TabbyAPI has to be launched from the directory that holds
the `sampler_overrides` folder.
"""

preset_path = pathlib.Path(f"sampler_overrides/{preset_name}.yml")
preset_path = SAMPLER_OVERRIDES_DIR / f"{preset_name}.yml"
if preset_path.exists():
overrides_container.selected_preset = preset_path.stem
async with aiofiles.open(preset_path, "r", encoding="utf8") as raw_preset:
Expand All @@ -424,18 +436,25 @@ async def overrides_from_file(preset_name: str):
xlogger.info("Applied sampler overrides from file.", {"preset": preset})
else:
error_message = (
f'Sampler override file named "{preset_name}" was not found. '
+ "Make sure it's located in the sampler_overrides folder."
f'Sampler override file named "{preset_name}" was not found at '
f"{preset_path.resolve()}. Presets are read from the "
f'"{SAMPLER_OVERRIDES_DIR}" folder relative to the current working '
f"directory ({pathlib.Path.cwd()}), so make sure the file is there "
"and that TabbyAPI is launched from that directory."
)

raise FileNotFoundError(error_message)


def get_all_presets():
"""Fetches all sampler override presets from the overrides directory"""
"""
Fetches all sampler override presets from the overrides directory.

Uses the same lookup as `overrides_from_file`: the `sampler_overrides`
folder relative to the current working directory.
"""

override_directory = pathlib.Path("sampler_overrides")
preset_files = [file.stem for file in override_directory.glob("*.yml")]
preset_files = [file.stem for file in SAMPLER_OVERRIDES_DIR.glob("*.yml")]

return preset_files

Expand Down
2 changes: 1 addition & 1 deletion config_sample.yml
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ draft_model:
# Options for Sampling
sampling:
# Select a sampler override preset (default: None).
# Find this in the sampler-overrides folder.
# This is a preset name, not a path: TabbyAPI reads sampler_overrides/<name>.yml relative to the directory it is launched from.
# This overrides default fallbacks for sampler values that are passed to the API.
# NOTE: safe_defaults is noob friendly and provides fallbacks for frontends that don't send sampling parameters.
# Remove this for any advanced usage.
Expand Down
2 changes: 1 addition & 1 deletion docs/02.-Server-options.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ Note: This block is for sampling overrides, not samplers themselves.

| Config Option | Type (Default) | Description |
| --------------- | -------------- | ------------------------------------------------------------------------- |
| override_preset | String (None) | Startup the given sampler override preset in the sampler_overrides folder |
| override_preset | String (None) | Startup the given sampler override preset. This is a preset name, not a path: it is read from `sampler_overrides/<name>.yml` relative to the directory TabbyAPI is launched from |

### Developer Options

Expand Down
5 changes: 5 additions & 0 deletions docs/08.-Sampler-Overrides.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ Sampler overrides is tabbyAPI's flexible proxy for adding or forcing sampler val

All supported samplers are located in `sampler_overrides/sample_preset.yml`.

> [!IMPORTANT]
> `sampler_overrides` is a **relative** path. TabbyAPI resolves it against the current working directory — the directory you launch TabbyAPI from — not against the directory TabbyAPI is installed in. If you start TabbyAPI from somewhere else, it will look for `sampler_overrides` there and report that the preset was not found.
>
> The value you configure is a preset *name*, not a file path: a preset named `my_preset` is read from `sampler_overrides/my_preset.yml`.

> [!NOTE]
> Sampler overrides can also be switched at runtime via the `/v1/sampling/override` endpoint set. Please read the [API docs](https://theroyallab.github.io/tabbyAPI/#operation/list_sampler_overrides_v1_sampling_override_list_get) for more information.

Expand Down