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
16 changes: 11 additions & 5 deletions lm15/providers/openai.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ def _attach_unmapped(provider_data: dict[str, Any], unmapped: list[dict[str, str
return out


_GPT_VERSION_RE = re.compile(r"^gpt-(\d+)\.(\d+)")
_GPT_VERSION_RE = re.compile(r"^gpt-(?:(\d+)\.(\d+)|([1-9]))(?:-|$)")


def openai_model_has_cache_options(model: str) -> bool:
Expand All @@ -177,12 +177,18 @@ def openai_model_has_cache_options(model: str) -> bool:
that class accepts it (older models reject it with HTTP 400, and their
writes are free anyway). Deciding client-side needs a model check —
a table that rots. Stated trade-off: a future family whose name does
not match ``gpt-<major>.<minor>`` keeps the provider's implicit writes
on ``mode="off"``; ``extensions={"prompt_cache_options": ...}`` is the
override.
not match ``gpt-<major>`` or ``gpt-<major>.<minor>`` keeps the
provider's implicit writes on ``mode="off"``;
``extensions={"prompt_cache_options": ...}`` is the override.
"""
m = _GPT_VERSION_RE.match(model.lower())
return bool(m) and (int(m.group(1)), int(m.group(2))) >= (5, 6)
if not m:
return False
if m.group(1) is not None:
major, minor = int(m.group(1)), int(m.group(2))
else:
major, minor = int(m.group(3)), 0
return (major, minor) >= (5, 6)


def _cache_breakpoint_index(request: Request, cache_control: str) -> int | None:
Expand Down
7 changes: 7 additions & 0 deletions tests/test_cache_mapping.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,18 @@ def _body(lm, request: Request) -> dict:
# ─── model class table ───────────────────────────────────────────────

def test_openai_model_class_for_cache_options() -> None:
assert openai_model_has_cache_options("gpt-6")
assert openai_model_has_cache_options("gpt-5.6-sol")
assert openai_model_has_cache_options("gpt-6.0")
assert openai_model_has_cache_options("gpt-6-luna")
assert openai_model_has_cache_options("GPT-5.10")
assert not openai_model_has_cache_options("gpt-5")
assert not openai_model_has_cache_options("gpt-5-mini")
assert not openai_model_has_cache_options("gpt-5.5")
assert not openai_model_has_cache_options("gpt-4.1-mini")
assert not openai_model_has_cache_options("gpt-3.5-turbo")
assert not openai_model_has_cache_options("gpt-35-turbo")
assert not openai_model_has_cache_options("gpt-35-turbo-16k")
assert not openai_model_has_cache_options("o3") # unknown pattern -> no switch (stated trade-off)
assert not openai_model_has_cache_options("chat-latest")

Expand Down