e93507a09c
Lockfile supply-chain audit / lockfile supply-chain audit (push) Has been cancelled
Windows Studio GGUF CI / GPU prebuilt resolves without Visual Studio (push) Has been cancelled
Windows Studio GGUF CI / setup.ps1 unit tests (VS 2026 / CMake guard) (push) Has been cancelled
Windows Studio GGUF CI / real-VS detection (VS 2022) (push) Has been cancelled
Windows Studio GGUF CI / real-VS detection (VS 2026) (push) Has been cancelled
Windows Studio GGUF CI / VC++ runtime detect + install round-trip (windows-2025-vs2026) (push) Has been cancelled
Windows Studio GGUF CI / VC++ runtime detect + install round-trip (windows-latest) (push) Has been cancelled
Windows Studio Update CI / Studio Updating Tests (push) Has been cancelled
Wheel CI / Wheel build + content sanity + import smoke (push) Has been cancelled
Lint CI / Source lint (Python + shell + YAML + JSON + safety nets) (push) Has been cancelled
MLX CI on Mac M1 / dispatch (push) Has been cancelled
Security audit / advisory audit (pip + npm + cargo) (push) Has been cancelled
Security audit / pip scan-packages :: extras (push) Has been cancelled
Security audit / pip scan-packages :: studio (push) Has been cancelled
Security audit / pip scan-packages :: hf-stack (push) Has been cancelled
Security audit / npm scan-packages (Studio frontend tarballs) (push) Has been cancelled
Security audit / workflow-trigger lint (pull_request_target / cache-poisoning) (push) Has been cancelled
Security audit / pytest tests/security (push) Has been cancelled
Security audit / npm provenance + new install-script diff (push) Has been cancelled
Studio API CI / Studio API & Auth Tests (push) Has been cancelled
Backend CI / (Python 3.10) (push) Has been cancelled
Backend CI / (Python 3.11) (push) Has been cancelled
Backend CI / (Python 3.12) (push) Has been cancelled
Backend CI / (Python 3.13) (push) Has been cancelled
Backend CI / Repo tests (CPU) (push) Has been cancelled
Frontend CI / Frontend build + bundle sanity (push) Has been cancelled
Studio GGUF CI / OpenAI, Anthropic API tests (push) Has been cancelled
Studio GGUF CI / Tool calling Tests (push) Has been cancelled
Studio GGUF CI / JSON, images (push) Has been cancelled
Mac Studio GGUF CI / OpenAI, Anthropic API tests (push) Has been cancelled
Mac Studio GGUF CI / Tool calling Tests (push) Has been cancelled
Mac Studio GGUF CI / JSON, images (push) Has been cancelled
Mac Studio Install Matrix CI / Install + load (macos-14) (push) Has been cancelled
Mac Studio Install Matrix CI / Install + load (macos-15) (push) Has been cancelled
Mac Studio Install Matrix CI / Install + load (macos-26) (push) Has been cancelled
Mac Studio Install Matrix CI / Install + load (macos-15-intel) (push) Has been cancelled
Mac Studio API CI / Studio API & Auth Tests (push) Has been cancelled
Mac Studio Install Matrix CI / Install + load (macos-26-intel) (push) Has been cancelled
Mac Studio UI CI / Chat UI Tests (push) Has been cancelled
Studio Tauri CI / Tauri Linux debug build (no codesign) (push) Has been cancelled
Mac Studio Update CI / Studio Updating Tests (push) Has been cancelled
Studio UI CI / Chat UI Tests (push) Has been cancelled
Windows Studio API CI / Studio API & Auth Tests (push) Has been cancelled
Windows Studio UI CI / Chat UI Tests (push) Has been cancelled
Studio Update CI / Studio Updating Tests (push) Has been cancelled
Core / Core (HF=default + TRL=default) (push) Has been cancelled
Core / Core (HF=4.57.6 + TRL<1) (push) Has been cancelled
Core / Core (HF=latest + TRL=latest) (push) Has been cancelled
Core / llama.cpp build + smoke (push) Has been cancelled
Windows Studio GGUF CI / OpenAI, Anthropic API tests (push) Has been cancelled
Windows Studio GGUF CI / Tool calling Tests (push) Has been cancelled
Windows Studio GGUF CI / JSON, images (push) Has been cancelled
Windows Studio GGUF CI / Studio install + inference without Visual Studio (push) Has been cancelled
Studio export capability / capability (macos-latest) (push) Has been cancelled
Studio export capability / capability (ubuntu-latest) (push) Has been cancelled
Studio export capability / capability (windows-latest) (push) Has been cancelled
Cross-platform parity / parity (macos-latest) (push) Has been cancelled
Cross-platform parity / parity (windows-latest) (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
Studio load-orchestrator CI / test (push) Has been cancelled
222 lines
7.8 KiB
Python
222 lines
7.8 KiB
Python
# SPDX-License-Identifier: AGPL-3.0-only
|
|
# Copyright 2026-present the Unsloth AI Inc. team. All rights reserved. See /studio/LICENSE.AGPL-3.0
|
|
|
|
"""Unit tests for OpenAI Responses API context_management wiring.
|
|
|
|
OpenAI's Responses API supports server-side compaction via
|
|
``context_management: [{type:"compaction", compact_threshold:N}]``. No
|
|
beta header, no dated version pin; the threshold is silently accepted and
|
|
compaction runs when the rendered prompt crosses it.
|
|
|
|
These pin: the body shape when threshold is set on cloud OpenAI, the
|
|
silent no-op on non-cloud base URLs, and the omitted-threshold
|
|
pass-through.
|
|
"""
|
|
|
|
import asyncio
|
|
import json
|
|
|
|
import httpx
|
|
|
|
from core.inference import external_provider as ep_mod
|
|
from core.inference.external_provider import ExternalProviderClient
|
|
|
|
|
|
def _drive(coro):
|
|
return asyncio.new_event_loop().run_until_complete(coro)
|
|
|
|
|
|
def _capture(monkeypatch, *, base_url: str, threshold) -> dict:
|
|
captured: dict = {}
|
|
|
|
def handler(request: httpx.Request) -> httpx.Response:
|
|
captured["body"] = json.loads(request.content.decode("utf-8"))
|
|
# Empty Responses-shaped SSE stream so the helper exits cleanly.
|
|
return httpx.Response(
|
|
200,
|
|
content = (
|
|
b"event: response.completed\n"
|
|
b'data: {"type":"response.completed",'
|
|
b'"response":{"output":[],"usage":{"input_tokens":0,'
|
|
b'"output_tokens":0}}}\n\n'
|
|
),
|
|
headers = {"content-type": "text/event-stream"},
|
|
)
|
|
|
|
monkeypatch.setattr(
|
|
ep_mod,
|
|
"_http_client",
|
|
httpx.AsyncClient(transport = httpx.MockTransport(handler)),
|
|
)
|
|
|
|
async def run():
|
|
client = ExternalProviderClient(
|
|
provider_type = "openai",
|
|
base_url = base_url,
|
|
api_key = "sk-test",
|
|
)
|
|
async for _ in client.stream_chat_completion(
|
|
messages = [{"role": "user", "content": "hi"}],
|
|
model = "gpt-5.5",
|
|
temperature = 0.7,
|
|
top_p = 0.95,
|
|
max_tokens = 32,
|
|
reasoning_effort = "medium",
|
|
compaction_threshold = threshold,
|
|
):
|
|
pass
|
|
await client.close()
|
|
|
|
_drive(run())
|
|
return captured
|
|
|
|
|
|
# ── cloud OpenAI carries the compaction field verbatim ──────────────
|
|
|
|
|
|
def test_cloud_openai_sets_compaction_block(monkeypatch):
|
|
captured = _capture(
|
|
monkeypatch,
|
|
base_url = "https://api.openai.com/v1",
|
|
threshold = 200_000,
|
|
)
|
|
assert captured["body"].get("context_management") == [
|
|
{"type": "compaction", "compact_threshold": 200_000}
|
|
]
|
|
|
|
|
|
def test_cloud_openai_below_default_threshold_passes_through(monkeypatch):
|
|
# Studio doesn't clamp the OpenAI side -- the API accepts whatever the
|
|
# caller sends, so a small probe like 60k still goes through.
|
|
captured = _capture(
|
|
monkeypatch,
|
|
base_url = "https://api.openai.com/v1",
|
|
threshold = 60_000,
|
|
)
|
|
assert captured["body"]["context_management"] == [
|
|
{"type": "compaction", "compact_threshold": 60_000}
|
|
]
|
|
|
|
|
|
# ── non-cloud bases drop the field ──────────────────────────────────
|
|
|
|
|
|
def test_non_cloud_base_silently_drops_compaction(monkeypatch):
|
|
# ollama / llama.cpp / "custom" presets collapse to provider="openai"
|
|
# but lack context_management. Sending the field would 400 them, so it
|
|
# must NOT appear on the wire.
|
|
captured = _capture(
|
|
monkeypatch,
|
|
base_url = "http://127.0.0.1:11434/v1",
|
|
threshold = 200_000,
|
|
)
|
|
assert "context_management" not in captured["body"]
|
|
|
|
|
|
# ── Azure OpenAI Foundry is treated as cloud ────────────────────────
|
|
|
|
|
|
def test_azure_openai_base_url_carries_compaction_block(monkeypatch):
|
|
# Azure OpenAI Foundry exposes the same /v1/responses extensions
|
|
# (context_management, prompt_cache_retention, container shell) under
|
|
# a *.openai.azure.com base URL. Treat it as cloud so the compaction
|
|
# field reaches the API.
|
|
captured = _capture(
|
|
monkeypatch,
|
|
base_url = "https://my-resource.openai.azure.com/openai/v1",
|
|
threshold = 200_000,
|
|
)
|
|
assert captured["body"].get("context_management") == [
|
|
{"type": "compaction", "compact_threshold": 200_000}
|
|
]
|
|
# Sibling Azure-cloud extension: prompt_cache_retention should also
|
|
# be set so caching works the same on Azure deployments.
|
|
assert captured["body"].get("prompt_cache_retention") == "24h"
|
|
|
|
|
|
def test_azure_openai_mixed_case_base_url_matches(monkeypatch):
|
|
# Case-insensitive match so URLs copy-pasted from the Azure portal
|
|
# (which sometimes capitalise the resource name) still get the
|
|
# cloud-only fields.
|
|
captured = _capture(
|
|
monkeypatch,
|
|
base_url = "https://My-Resource.OpenAI.Azure.Com/openai/v1",
|
|
threshold = 50_000,
|
|
)
|
|
assert captured["body"].get("context_management") == [
|
|
{"type": "compaction", "compact_threshold": 50_000}
|
|
]
|
|
|
|
|
|
def test_cloud_gate_uses_hostname_not_substring(monkeypatch):
|
|
# CodeQL py/incomplete-url-substring-sanitization: an attacker
|
|
# controlling base_url could embed `api.openai.com` or
|
|
# `.openai.azure.com` in a path or subdomain on an arbitrary host to
|
|
# slip cloud-only body fields to their own server. The
|
|
# hostname-anchored helper must reject both shapes.
|
|
for evil in [
|
|
"https://evil.com/api.openai.com/v1",
|
|
"https://api.openai.com.attacker.com/v1",
|
|
"https://attacker.com/.openai.azure.com/v1",
|
|
"https://my-resource.openai.azure.com.attacker.com/openai/v1",
|
|
]:
|
|
captured = _capture(
|
|
monkeypatch,
|
|
base_url = evil,
|
|
threshold = 200_000,
|
|
)
|
|
assert "context_management" not in captured["body"], evil
|
|
assert "prompt_cache_retention" not in captured["body"], evil
|
|
|
|
|
|
# ── omitted threshold leaves body untouched ─────────────────────────
|
|
|
|
|
|
def test_omitted_threshold_no_body_field(monkeypatch):
|
|
captured = _capture(
|
|
monkeypatch,
|
|
base_url = "https://api.openai.com/v1",
|
|
threshold = None,
|
|
)
|
|
assert "context_management" not in captured["body"]
|
|
|
|
|
|
# ── schema floor matches what the upstream API actually accepts ────
|
|
|
|
|
|
def test_chat_completion_request_accepts_any_positive_compaction_threshold():
|
|
# Codex follow-up: the field is a no-op for non-cloud OpenAI bases and
|
|
# every non-OpenAI provider, so a cross-provider schema floor would
|
|
# 422 valid Anthropic / ollama / llama.cpp requests carrying it. Keep
|
|
# the schema floor at ge=1 (any positive int) and let per-provider
|
|
# helpers (_stream_openai_responses / _stream_anthropic) enforce or
|
|
# clamp the real floor.
|
|
import pytest as _pytest
|
|
|
|
from models.inference import ChatCompletionRequest
|
|
|
|
# Non-positive values rejected so blank-string posts don't sneak in.
|
|
with _pytest.raises(Exception):
|
|
ChatCompletionRequest.model_validate(
|
|
{
|
|
"model": "default",
|
|
"messages": [{"role": "user", "content": "hi"}],
|
|
"compaction_threshold": 0,
|
|
}
|
|
)
|
|
|
|
# Any positive int passes schema validation, including values that
|
|
# are no-ops on the OpenAI cloud path. Intentional -- the OpenAI
|
|
# helper drops the field on non-cloud bases and forwards as-is on
|
|
# cloud bases; if it's below the model's effective floor, the upstream
|
|
# API surfaces the error.
|
|
for v in (1, 5_000, 9_999, 10_000, 200_000):
|
|
req = ChatCompletionRequest.model_validate(
|
|
{
|
|
"model": "default",
|
|
"messages": [{"role": "user", "content": "hi"}],
|
|
"compaction_threshold": v,
|
|
}
|
|
)
|
|
assert req.compaction_threshold == v
|