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
74 changes: 73 additions & 1 deletion src/ucode/agents/pi.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,78 @@ def _resolve_model_selector(
return model


def _pi_openai_model_entry(model_id: str) -> dict:
"""Build a Pi Responses entry with model-specific reasoning controls.

Pi's generic custom-model defaults include levels that are not valid for
every OpenAI Responses model. Explicit null mappings hide those choices,
while string mappings translate Pi's ``off`` choice to the API's ``none``
value where the model supports it.
"""
entry: dict = {"id": model_id}
normalized_id = model_id.rsplit("/", 1)[-1].lower()
for prefix in ("system.ai.", "databricks-"):
if normalized_id.startswith(prefix):
normalized_id = normalized_id[len(prefix) :]
break
normalized_id = normalized_id.replace(".", "-")

if normalized_id == "gpt-6-astra":
# Astra is reasoning-only and does not support `none`. Declare its
# actual limits because Pi otherwise applies a conservative custom
# model default of 128k context / 4k output.
entry.update(
{
"reasoning": True,
"input": ["text", "image"],
"contextWindow": 1_050_000,
"maxTokens": 128_000,
}
)
entry["thinkingLevelMap"] = {
"off": None,
"minimal": None,
"xhigh": "xhigh",
"max": "max",
}
elif normalized_id.startswith("gpt-5-6-") or (
normalized_id.startswith("gpt-5-5") and not normalized_id.startswith("gpt-5-5-pro")
):
# GPT-5.5 supports none/low/medium/high/xhigh; GPT-5.6 also supports
# max. Neither family supports Pi's generic minimal level.
entry["reasoning"] = True
entry["thinkingLevelMap"] = {
"off": "none",
"minimal": None,
"xhigh": "xhigh",
}
if normalized_id.startswith("gpt-5-6-"):
entry["thinkingLevelMap"]["max"] = "max"
elif normalized_id.startswith(("gpt-5-4-pro", "gpt-5-5-pro")):
# Pro variants support medium/high/xhigh only.
entry["reasoning"] = True
entry["thinkingLevelMap"] = {
"off": None,
"minimal": None,
"low": None,
"xhigh": "xhigh",
}
elif normalized_id.startswith("gpt-5-4"):
# GPT-5.4 standard/mini/nano support none/low/medium/high/xhigh.
entry["reasoning"] = True
entry["thinkingLevelMap"] = {
"off": "none",
"minimal": None,
"xhigh": "xhigh",
}
elif "gpt-5" in normalized_id:
# Older GPT-5 variants reject `none`; retain their established
# minimal/low/medium/high choices.
entry["reasoning"] = True
entry["thinkingLevelMap"] = {"off": None}
return entry


def render_overlay(
model: str,
token: str,
Expand Down Expand Up @@ -134,7 +206,7 @@ def render_overlay(
"apiKey": token,
"authHeader": True,
"headers": ua_headers,
"models": [{"id": m} for m in codex_models],
"models": [_pi_openai_model_entry(m) for m in codex_models],
}
keys.append(["providers", "databricks-openai"])
if gemini_models:
Expand Down
59 changes: 59 additions & 0 deletions tests/test_agent_pi.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,65 @@ def test_openai_provider_uses_openai_responses(self):
assert provider["api"] == "openai-responses"
assert provider["baseUrl"] == f"{WS}/ai-gateway/codex/v1"

def test_gpt6_astra_exposes_supported_thinking_levels(self):
overlay, _ = _overlay("system.ai.gpt-6-astra", codex_models=["system.ai.gpt-6-astra"])
entry = overlay["providers"]["databricks-openai"]["models"][0]

assert entry["reasoning"] is True
assert entry["input"] == ["text", "image"]
assert entry["contextWindow"] == 1_050_000
assert entry["maxTokens"] == 128_000
assert entry["thinkingLevelMap"] == {
"off": None,
"minimal": None,
"xhigh": "xhigh",
"max": "max",
}

def test_newer_gpt_models_use_their_responses_effort_values(self):
overlay, _ = _overlay(
"system.ai.gpt-5-6-luna",
codex_models=[
"system.ai.gpt-5-4",
"system.ai.gpt-5-5",
"system.ai.gpt-5-6-luna",
"system.ai.gpt-5-5-pro",
],
)
entries = {
entry["id"]: entry for entry in overlay["providers"]["databricks-openai"]["models"]
}

assert entries["system.ai.gpt-5-4"]["thinkingLevelMap"] == {
"off": "none",
"minimal": None,
"xhigh": "xhigh",
}
assert entries["system.ai.gpt-5-5"]["thinkingLevelMap"] == {
"off": "none",
"minimal": None,
"xhigh": "xhigh",
}
assert entries["system.ai.gpt-5-6-luna"]["thinkingLevelMap"] == {
"off": "none",
"minimal": None,
"xhigh": "xhigh",
"max": "max",
}
assert entries["system.ai.gpt-5-5-pro"]["thinkingLevelMap"] == {
"off": None,
"minimal": None,
"low": None,
"xhigh": "xhigh",
}

def test_legacy_gpt5_keeps_its_compatible_levels(self):
overlay, _ = _overlay("gpt-5", codex_models=["gpt-5"])
entry = overlay["providers"]["databricks-openai"]["models"][0]

assert entry["reasoning"] is True
assert entry["thinkingLevelMap"] == {"off": None}

def test_gemini_provider_uses_google_generative_ai(self):
overlay, _ = _overlay("gemini-2", gemini_models=["gemini-2"])
provider = overlay["providers"]["databricks-gemini"]
Expand Down
Loading