refactor: rename teacher/student to optimizer/target, remove best skills, fix slow update

- Rename teacher -> optimizer, student -> target across all code, configs, docs, prompts
- CLI: --teacher_model -> --optimizer_model, --student_model -> --target_model
- Remove best_skill files, keep only initial skills
- Fix slow update gate (force write into skill)
- Fix SLOW_UPDATE marker stripping
- Remove deep_reflect and meta_reflect mechanisms
- Update .env.example with export prefix and azure_cli docs
- Add endpoint empty validation in azure_openai.py

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
Cuzyoung
2026-05-24 19:15:03 +00:00
parent 6e165d5347
commit 4a1b984d87
70 changed files with 1083 additions and 2068 deletions
+87 -87
View File
@@ -1,4 +1,4 @@
"""ReflACT model API with runtime backend selection for the student path."""
"""ReflACT model API with runtime backend selection for the target path."""
from __future__ import annotations
@@ -12,73 +12,73 @@ from skillopt.model.backend_config import ( # noqa: F401
configure_codex_exec,
get_claude_code_exec_config,
get_codex_exec_config,
get_student_backend,
get_teacher_backend,
is_student_chat_backend,
is_student_exec_backend,
is_teacher_chat_backend,
set_student_backend,
set_teacher_backend,
get_target_backend,
get_optimizer_backend,
is_target_chat_backend,
is_target_exec_backend,
is_optimizer_chat_backend,
set_target_backend,
set_optimizer_backend,
)
def set_backend(name: str | None) -> str:
"""Backward-compatible global backend setter.
Historically the codebase used one shared backend for both teacher and
student. Keep that entry point so older scripts continue to work, while
mapping it onto the split teacher/student backend model.
Historically the codebase used one shared backend for both optimizer and
target. Keep that entry point so older scripts continue to work, while
mapping it onto the split optimizer/target backend model.
"""
normalized = str(name or "azure_openai").strip().lower()
if normalized in {"azure_openai", "openai_chat", "azure", "azure-openai"}:
set_teacher_backend("openai_chat")
set_student_backend("openai_chat")
set_optimizer_backend("openai_chat")
set_target_backend("openai_chat")
return "azure_openai"
if normalized in {"claude", "claude_chat", "anthropic"}:
set_teacher_backend("claude_chat")
set_student_backend("claude_chat")
set_optimizer_backend("claude_chat")
set_target_backend("claude_chat")
return "claude_chat"
if normalized == "codex":
set_teacher_backend("openai_chat")
set_student_backend("codex_exec")
set_optimizer_backend("openai_chat")
set_target_backend("codex_exec")
return "codex"
if normalized in {"codex_exec", "claude_code_exec"}:
set_teacher_backend("openai_chat")
set_student_backend(normalized)
set_optimizer_backend("openai_chat")
set_target_backend(normalized)
return normalized
if normalized in {"qwen", "qwen_chat"}:
set_teacher_backend("openai_chat")
set_student_backend("qwen_chat")
set_optimizer_backend("openai_chat")
set_target_backend("qwen_chat")
return "qwen_chat"
raise ValueError(f"Unsupported legacy backend: {name!r}")
def get_backend_name() -> str:
"""Best-effort backward-compatible backend summary."""
teacher = get_teacher_backend()
student = get_student_backend()
if teacher == "claude_chat" and student == "claude_chat":
optimizer = get_optimizer_backend()
target = get_target_backend()
if optimizer == "claude_chat" and target == "claude_chat":
return "claude_chat"
if teacher == "openai_chat" and student == "openai_chat":
if optimizer == "openai_chat" and target == "openai_chat":
return "azure_openai"
if teacher == "openai_chat" and student == "codex_exec":
if optimizer == "openai_chat" and target == "codex_exec":
return "codex"
if teacher == "openai_chat" and student == "qwen_chat":
if optimizer == "openai_chat" and target == "qwen_chat":
return "qwen_chat"
return f"{teacher}+{student}"
return f"{optimizer}+{target}"
def chat_teacher(
def chat_optimizer(
system: str,
user: str,
max_completion_tokens: int = 16384,
retries: int = 5,
stage: str = "teacher",
stage: str = "optimizer",
reasoning_effort: str | None = None,
timeout: int | None = None,
) -> tuple[str, dict]:
if get_teacher_backend() == "claude_chat":
return _claude.chat_teacher(
if get_optimizer_backend() == "claude_chat":
return _claude.chat_optimizer(
system=system,
user=user,
max_completion_tokens=max_completion_tokens,
@@ -86,7 +86,7 @@ def chat_teacher(
stage=stage,
timeout=timeout,
)
return _openai.chat_teacher(
return _openai.chat_optimizer(
system=system,
user=user,
max_completion_tokens=max_completion_tokens,
@@ -97,17 +97,17 @@ def chat_teacher(
)
def chat_student(
def chat_target(
system: str,
user: str,
max_completion_tokens: int = 16384,
retries: int = 5,
stage: str = "student",
stage: str = "target",
reasoning_effort: str | None = None,
timeout: int | None = None,
) -> tuple[str, dict]:
if get_student_backend() == "claude_chat":
return _claude.chat_student(
if get_target_backend() == "claude_chat":
return _claude.chat_target(
system=system,
user=user,
max_completion_tokens=max_completion_tokens,
@@ -115,8 +115,8 @@ def chat_student(
stage=stage,
timeout=timeout,
)
if get_student_backend() == "qwen_chat":
return _qwen.chat_student(
if get_target_backend() == "qwen_chat":
return _qwen.chat_target(
system=system,
user=user,
max_completion_tokens=max_completion_tokens,
@@ -124,12 +124,12 @@ def chat_student(
stage=stage,
reasoning_effort=reasoning_effort,
)
if not is_student_chat_backend():
if not is_target_chat_backend():
raise NotImplementedError(
"chat_student is only supported with student_backend=openai_chat, claude_chat, or qwen_chat. "
"chat_target is only supported with target_backend=openai_chat, claude_chat, or qwen_chat. "
"Exec backends are handled in environment-specific rollout code."
)
return _openai.chat_student(
return _openai.chat_target(
system=system,
user=user,
max_completion_tokens=max_completion_tokens,
@@ -140,11 +140,11 @@ def chat_student(
)
def chat_teacher_messages(
def chat_optimizer_messages(
messages: list[dict[str, Any]],
max_completion_tokens: int = 16384,
retries: int = 5,
stage: str = "teacher",
stage: str = "optimizer",
reasoning_effort: str | None = None,
*,
tools: list[dict[str, Any]] | None = None,
@@ -152,8 +152,8 @@ def chat_teacher_messages(
return_message: bool = False,
timeout: int | None = None,
) -> tuple[Any, dict]:
if get_teacher_backend() == "claude_chat":
return _claude.chat_teacher_messages(
if get_optimizer_backend() == "claude_chat":
return _claude.chat_optimizer_messages(
messages=messages,
max_completion_tokens=max_completion_tokens,
retries=retries,
@@ -163,7 +163,7 @@ def chat_teacher_messages(
return_message=return_message,
timeout=timeout,
)
return _openai.chat_teacher_messages(
return _openai.chat_optimizer_messages(
messages=messages,
max_completion_tokens=max_completion_tokens,
retries=retries,
@@ -176,11 +176,11 @@ def chat_teacher_messages(
)
def chat_student_messages(
def chat_target_messages(
messages: list[dict[str, Any]],
max_completion_tokens: int = 16384,
retries: int = 5,
stage: str = "student",
stage: str = "target",
reasoning_effort: str | None = None,
*,
tools: list[dict[str, Any]] | None = None,
@@ -188,8 +188,8 @@ def chat_student_messages(
return_message: bool = False,
timeout: int | None = None,
) -> tuple[Any, dict]:
if get_student_backend() == "claude_chat":
return _claude.chat_student_messages(
if get_target_backend() == "claude_chat":
return _claude.chat_target_messages(
messages=messages,
max_completion_tokens=max_completion_tokens,
retries=retries,
@@ -199,8 +199,8 @@ def chat_student_messages(
return_message=return_message,
timeout=timeout,
)
if get_student_backend() == "qwen_chat":
return _qwen.chat_student_messages(
if get_target_backend() == "qwen_chat":
return _qwen.chat_target_messages(
messages=messages,
max_completion_tokens=max_completion_tokens,
retries=retries,
@@ -210,12 +210,12 @@ def chat_student_messages(
tool_choice=tool_choice,
return_message=return_message,
)
if not is_student_chat_backend():
if not is_target_chat_backend():
raise NotImplementedError(
"chat_student_messages is only supported with student_backend=openai_chat, claude_chat, or qwen_chat. "
"chat_target_messages is only supported with target_backend=openai_chat, claude_chat, or qwen_chat. "
"Exec backends are handled in environment-specific rollout code."
)
return _openai.chat_student_messages(
return _openai.chat_target_messages(
messages=messages,
max_completion_tokens=max_completion_tokens,
retries=retries,
@@ -332,18 +332,18 @@ def configure_azure_openai(
auth_mode: str | None = None,
ad_scope: str | None = None,
managed_identity_client_id: str | None = None,
teacher_endpoint: str | None = None,
teacher_api_version: str | None = None,
teacher_api_key: str | None = None,
teacher_auth_mode: str | None = None,
teacher_ad_scope: str | None = None,
teacher_managed_identity_client_id: str | None = None,
student_endpoint: str | None = None,
student_api_version: str | None = None,
student_api_key: str | None = None,
student_auth_mode: str | None = None,
student_ad_scope: str | None = None,
student_managed_identity_client_id: str | None = None,
optimizer_endpoint: str | None = None,
optimizer_api_version: str | None = None,
optimizer_api_key: str | None = None,
optimizer_auth_mode: str | None = None,
optimizer_ad_scope: str | None = None,
optimizer_managed_identity_client_id: str | None = None,
target_endpoint: str | None = None,
target_api_version: str | None = None,
target_api_key: str | None = None,
target_auth_mode: str | None = None,
target_ad_scope: str | None = None,
target_managed_identity_client_id: str | None = None,
) -> None:
_openai.configure_azure_openai(
endpoint=endpoint,
@@ -352,18 +352,18 @@ def configure_azure_openai(
auth_mode=auth_mode,
ad_scope=ad_scope,
managed_identity_client_id=managed_identity_client_id,
teacher_endpoint=teacher_endpoint,
teacher_api_version=teacher_api_version,
teacher_api_key=teacher_api_key,
teacher_auth_mode=teacher_auth_mode,
teacher_ad_scope=teacher_ad_scope,
teacher_managed_identity_client_id=teacher_managed_identity_client_id,
student_endpoint=student_endpoint,
student_api_version=student_api_version,
student_api_key=student_api_key,
student_auth_mode=student_auth_mode,
student_ad_scope=student_ad_scope,
student_managed_identity_client_id=student_managed_identity_client_id,
optimizer_endpoint=optimizer_endpoint,
optimizer_api_version=optimizer_api_version,
optimizer_api_key=optimizer_api_key,
optimizer_auth_mode=optimizer_auth_mode,
optimizer_ad_scope=optimizer_ad_scope,
optimizer_managed_identity_client_id=optimizer_managed_identity_client_id,
target_endpoint=target_endpoint,
target_api_version=target_api_version,
target_api_key=target_api_key,
target_auth_mode=target_auth_mode,
target_ad_scope=target_ad_scope,
target_managed_identity_client_id=target_managed_identity_client_id,
)
@@ -392,12 +392,12 @@ def set_reasoning_effort(effort: str | None) -> None:
_qwen.set_reasoning_effort(effort)
def set_student_deployment(deployment: str) -> None:
_openai.set_student_deployment(deployment)
_claude.set_student_deployment(deployment)
_qwen.set_student_deployment(deployment)
def set_target_deployment(deployment: str) -> None:
_openai.set_target_deployment(deployment)
_claude.set_target_deployment(deployment)
_qwen.set_target_deployment(deployment)
def set_teacher_deployment(deployment: str) -> None:
_openai.set_teacher_deployment(deployment)
_claude.set_teacher_deployment(deployment)
def set_optimizer_deployment(deployment: str) -> None:
_openai.set_optimizer_deployment(deployment)
_claude.set_optimizer_deployment(deployment)
+167 -161
View File
@@ -1,6 +1,6 @@
"""ReflACT Model backend — Azure OpenAI wrapper with token tracking.
Provides teacher/student dual-deployment chat functions and a global
Provides optimizer/target dual-deployment chat functions and a global
TokenTracker for per-stage cost accounting. Previously llm/azure_openai.py.
"""
from __future__ import annotations
@@ -35,69 +35,69 @@ MANAGED_IDENTITY_CLIENT_ID = os.environ.get(
"",
).strip()
TEACHER_ENDPOINT = (
os.environ.get("TEACHER_AZURE_OPENAI_ENDPOINT")
or os.environ.get("AZURE_OPENAI_TEACHER_ENDPOINT")
OPTIMIZER_ENDPOINT = (
os.environ.get("OPTIMIZER_AZURE_OPENAI_ENDPOINT")
or os.environ.get("AZURE_OPENAI_OPTIMIZER_ENDPOINT")
or ENDPOINT
)
STUDENT_ENDPOINT = (
os.environ.get("STUDENT_AZURE_OPENAI_ENDPOINT")
or os.environ.get("AZURE_OPENAI_STUDENT_ENDPOINT")
TARGET_ENDPOINT = (
os.environ.get("TARGET_AZURE_OPENAI_ENDPOINT")
or os.environ.get("AZURE_OPENAI_TARGET_ENDPOINT")
or ENDPOINT
)
TEACHER_API_VERSION = (
os.environ.get("TEACHER_AZURE_OPENAI_API_VERSION")
or os.environ.get("AZURE_OPENAI_TEACHER_API_VERSION")
OPTIMIZER_API_VERSION = (
os.environ.get("OPTIMIZER_AZURE_OPENAI_API_VERSION")
or os.environ.get("AZURE_OPENAI_OPTIMIZER_API_VERSION")
or API_VERSION
)
STUDENT_API_VERSION = (
os.environ.get("STUDENT_AZURE_OPENAI_API_VERSION")
or os.environ.get("AZURE_OPENAI_STUDENT_API_VERSION")
TARGET_API_VERSION = (
os.environ.get("TARGET_AZURE_OPENAI_API_VERSION")
or os.environ.get("AZURE_OPENAI_TARGET_API_VERSION")
or API_VERSION
)
TEACHER_API_KEY = (
os.environ.get("TEACHER_AZURE_OPENAI_API_KEY")
or os.environ.get("AZURE_OPENAI_TEACHER_API_KEY")
OPTIMIZER_API_KEY = (
os.environ.get("OPTIMIZER_AZURE_OPENAI_API_KEY")
or os.environ.get("AZURE_OPENAI_OPTIMIZER_API_KEY")
or API_KEY
)
STUDENT_API_KEY = (
os.environ.get("STUDENT_AZURE_OPENAI_API_KEY")
or os.environ.get("AZURE_OPENAI_STUDENT_API_KEY")
TARGET_API_KEY = (
os.environ.get("TARGET_AZURE_OPENAI_API_KEY")
or os.environ.get("AZURE_OPENAI_TARGET_API_KEY")
or API_KEY
)
TEACHER_AUTH_MODE = (
os.environ.get("TEACHER_AZURE_OPENAI_AUTH_MODE")
or os.environ.get("AZURE_OPENAI_TEACHER_AUTH_MODE")
OPTIMIZER_AUTH_MODE = (
os.environ.get("OPTIMIZER_AZURE_OPENAI_AUTH_MODE")
or os.environ.get("AZURE_OPENAI_OPTIMIZER_AUTH_MODE")
or AUTH_MODE
).strip().lower()
STUDENT_AUTH_MODE = (
os.environ.get("STUDENT_AZURE_OPENAI_AUTH_MODE")
or os.environ.get("AZURE_OPENAI_STUDENT_AUTH_MODE")
TARGET_AUTH_MODE = (
os.environ.get("TARGET_AZURE_OPENAI_AUTH_MODE")
or os.environ.get("AZURE_OPENAI_TARGET_AUTH_MODE")
or AUTH_MODE
).strip().lower()
TEACHER_AD_SCOPE = (
os.environ.get("TEACHER_AZURE_OPENAI_AD_SCOPE")
or os.environ.get("AZURE_OPENAI_TEACHER_AD_SCOPE")
OPTIMIZER_AD_SCOPE = (
os.environ.get("OPTIMIZER_AZURE_OPENAI_AD_SCOPE")
or os.environ.get("AZURE_OPENAI_OPTIMIZER_AD_SCOPE")
or AD_SCOPE
)
STUDENT_AD_SCOPE = (
os.environ.get("STUDENT_AZURE_OPENAI_AD_SCOPE")
or os.environ.get("AZURE_OPENAI_STUDENT_AD_SCOPE")
TARGET_AD_SCOPE = (
os.environ.get("TARGET_AZURE_OPENAI_AD_SCOPE")
or os.environ.get("AZURE_OPENAI_TARGET_AD_SCOPE")
or AD_SCOPE
)
TEACHER_MANAGED_IDENTITY_CLIENT_ID = (
os.environ.get("TEACHER_AZURE_OPENAI_MANAGED_IDENTITY_CLIENT_ID")
or os.environ.get("AZURE_OPENAI_TEACHER_MANAGED_IDENTITY_CLIENT_ID")
OPTIMIZER_MANAGED_IDENTITY_CLIENT_ID = (
os.environ.get("OPTIMIZER_AZURE_OPENAI_MANAGED_IDENTITY_CLIENT_ID")
or os.environ.get("AZURE_OPENAI_OPTIMIZER_MANAGED_IDENTITY_CLIENT_ID")
or MANAGED_IDENTITY_CLIENT_ID
).strip()
STUDENT_MANAGED_IDENTITY_CLIENT_ID = (
os.environ.get("STUDENT_AZURE_OPENAI_MANAGED_IDENTITY_CLIENT_ID")
or os.environ.get("AZURE_OPENAI_STUDENT_MANAGED_IDENTITY_CLIENT_ID")
TARGET_MANAGED_IDENTITY_CLIENT_ID = (
os.environ.get("TARGET_AZURE_OPENAI_MANAGED_IDENTITY_CLIENT_ID")
or os.environ.get("AZURE_OPENAI_TARGET_MANAGED_IDENTITY_CLIENT_ID")
or MANAGED_IDENTITY_CLIENT_ID
).strip()
TEACHER_DEPLOYMENT = os.environ.get("TEACHER_DEPLOYMENT", "gpt-5.5")
STUDENT_DEPLOYMENT = os.environ.get("STUDENT_DEPLOYMENT", "gpt-5.5")
OPTIMIZER_DEPLOYMENT = os.environ.get("OPTIMIZER_DEPLOYMENT", "gpt-4o")
TARGET_DEPLOYMENT = os.environ.get("TARGET_DEPLOYMENT", "gpt-4o")
REASONING_EFFORT: str | None = None
@@ -177,30 +177,30 @@ tracker = TokenTracker()
# ── Client management ─────────────────────────────────────────────────────────
_teacher_client: AzureOpenAI | None = None
_student_client: AzureOpenAI | None = None
_teacher_lock = threading.Lock()
_student_lock = threading.Lock()
_optimizer_client: AzureOpenAI | None = None
_target_client: AzureOpenAI | None = None
_optimizer_lock = threading.Lock()
_target_lock = threading.Lock()
def _role_config(role: str) -> dict[str, str]:
if role == "teacher":
if role == "optimizer":
return {
"endpoint": TEACHER_ENDPOINT,
"api_version": TEACHER_API_VERSION,
"api_key": TEACHER_API_KEY,
"auth_mode": TEACHER_AUTH_MODE,
"ad_scope": TEACHER_AD_SCOPE,
"managed_identity_client_id": TEACHER_MANAGED_IDENTITY_CLIENT_ID,
"endpoint": OPTIMIZER_ENDPOINT,
"api_version": OPTIMIZER_API_VERSION,
"api_key": OPTIMIZER_API_KEY,
"auth_mode": OPTIMIZER_AUTH_MODE,
"ad_scope": OPTIMIZER_AD_SCOPE,
"managed_identity_client_id": OPTIMIZER_MANAGED_IDENTITY_CLIENT_ID,
}
if role == "student":
if role == "target":
return {
"endpoint": STUDENT_ENDPOINT,
"api_version": STUDENT_API_VERSION,
"api_key": STUDENT_API_KEY,
"auth_mode": STUDENT_AUTH_MODE,
"ad_scope": STUDENT_AD_SCOPE,
"managed_identity_client_id": STUDENT_MANAGED_IDENTITY_CLIENT_ID,
"endpoint": TARGET_ENDPOINT,
"api_version": TARGET_API_VERSION,
"api_key": TARGET_API_KEY,
"auth_mode": TARGET_AUTH_MODE,
"ad_scope": TARGET_AD_SCOPE,
"managed_identity_client_id": TARGET_MANAGED_IDENTITY_CLIENT_ID,
}
raise ValueError(f"Unknown Azure OpenAI client role: {role!r}")
@@ -280,6 +280,12 @@ def _make_azure_cli_token_provider(ad_scope: str):
def _make_client(role: str) -> AzureOpenAI:
cfg = _role_config(role)
if not cfg["endpoint"]:
raise ValueError(
f"Azure OpenAI endpoint is not configured for {role}. "
"Pass --azure_openai_endpoint https://your-resource.openai.azure.com/ "
"or set AZURE_OPENAI_ENDPOINT in your environment."
)
auth_mode = cfg["auth_mode"]
if auth_mode in {"api_key", "key"}:
if not cfg["api_key"]:
@@ -303,29 +309,29 @@ def _make_client(role: str) -> AzureOpenAI:
)
def get_teacher_client() -> AzureOpenAI:
global _teacher_client
with _teacher_lock:
if _teacher_client is None:
_teacher_client = _make_client("teacher")
return _teacher_client
def get_optimizer_client() -> AzureOpenAI:
global _optimizer_client
with _optimizer_lock:
if _optimizer_client is None:
_optimizer_client = _make_client("optimizer")
return _optimizer_client
def get_student_client() -> AzureOpenAI | OpenAI:
global _student_client
with _student_lock:
if _student_client is None:
def get_target_client() -> AzureOpenAI | OpenAI:
global _target_client
with _target_lock:
if _target_client is None:
# When using qwen_chat backend, return an OpenAI client pointing to vLLM
from skillopt.model.backend_config import get_student_backend
if get_student_backend() == "qwen_chat":
from skillopt.model.backend_config import get_target_backend
if get_target_backend() == "qwen_chat":
from skillopt.model import qwen_backend as _qwen
_student_client = OpenAI(
_target_client = OpenAI(
base_url=_qwen.BASE_URL,
api_key=_qwen.API_KEY or "dummy",
)
else:
_student_client = _make_client("student")
return _student_client
_target_client = _make_client("target")
return _target_client
def _needs_responses_api(deployment: str) -> bool:
@@ -587,25 +593,25 @@ def configure_azure_openai(
auth_mode: str | None = None,
ad_scope: str | None = None,
managed_identity_client_id: str | None = None,
teacher_endpoint: str | None = None,
teacher_api_version: str | None = None,
teacher_api_key: str | None = None,
teacher_auth_mode: str | None = None,
teacher_ad_scope: str | None = None,
teacher_managed_identity_client_id: str | None = None,
student_endpoint: str | None = None,
student_api_version: str | None = None,
student_api_key: str | None = None,
student_auth_mode: str | None = None,
student_ad_scope: str | None = None,
student_managed_identity_client_id: str | None = None,
optimizer_endpoint: str | None = None,
optimizer_api_version: str | None = None,
optimizer_api_key: str | None = None,
optimizer_auth_mode: str | None = None,
optimizer_ad_scope: str | None = None,
optimizer_managed_identity_client_id: str | None = None,
target_endpoint: str | None = None,
target_api_version: str | None = None,
target_api_key: str | None = None,
target_auth_mode: str | None = None,
target_ad_scope: str | None = None,
target_managed_identity_client_id: str | None = None,
) -> None:
global ENDPOINT, API_VERSION, API_KEY, AUTH_MODE, AD_SCOPE, MANAGED_IDENTITY_CLIENT_ID
global TEACHER_ENDPOINT, TEACHER_API_VERSION, TEACHER_API_KEY, TEACHER_AUTH_MODE
global TEACHER_AD_SCOPE, TEACHER_MANAGED_IDENTITY_CLIENT_ID
global STUDENT_ENDPOINT, STUDENT_API_VERSION, STUDENT_API_KEY, STUDENT_AUTH_MODE
global STUDENT_AD_SCOPE, STUDENT_MANAGED_IDENTITY_CLIENT_ID
global _teacher_client, _student_client
global OPTIMIZER_ENDPOINT, OPTIMIZER_API_VERSION, OPTIMIZER_API_KEY, OPTIMIZER_AUTH_MODE
global OPTIMIZER_AD_SCOPE, OPTIMIZER_MANAGED_IDENTITY_CLIENT_ID
global TARGET_ENDPOINT, TARGET_API_VERSION, TARGET_API_KEY, TARGET_AUTH_MODE
global TARGET_AD_SCOPE, TARGET_MANAGED_IDENTITY_CLIENT_ID
global _optimizer_client, _target_client
def _clean(value: str | None, *, lower: bool = False) -> str | None:
if value is None:
@@ -641,72 +647,72 @@ def configure_azure_openai(
"AZURE_OPENAI_MANAGED_IDENTITY_CLIENT_ID",
)
resolved_teacher_endpoint = _clean(teacher_endpoint) or shared_endpoint
resolved_teacher_api_version = _clean(teacher_api_version) or shared_api_version
resolved_teacher_api_key = _clean(teacher_api_key) or shared_api_key
resolved_teacher_auth_mode = _clean(teacher_auth_mode, lower=True) or shared_auth_mode
resolved_teacher_ad_scope = _clean(teacher_ad_scope) or shared_ad_scope
resolved_teacher_mi = (
_clean(teacher_managed_identity_client_id)
resolved_optimizer_endpoint = _clean(optimizer_endpoint) or shared_endpoint
resolved_optimizer_api_version = _clean(optimizer_api_version) or shared_api_version
resolved_optimizer_api_key = _clean(optimizer_api_key) or shared_api_key
resolved_optimizer_auth_mode = _clean(optimizer_auth_mode, lower=True) or shared_auth_mode
resolved_optimizer_ad_scope = _clean(optimizer_ad_scope) or shared_ad_scope
resolved_optimizer_mi = (
_clean(optimizer_managed_identity_client_id)
or shared_managed_identity_client_id
)
resolved_student_endpoint = _clean(student_endpoint) or shared_endpoint
resolved_student_api_version = _clean(student_api_version) or shared_api_version
resolved_student_api_key = _clean(student_api_key) or shared_api_key
resolved_student_auth_mode = _clean(student_auth_mode, lower=True) or shared_auth_mode
resolved_student_ad_scope = _clean(student_ad_scope) or shared_ad_scope
resolved_student_mi = (
_clean(student_managed_identity_client_id)
resolved_target_endpoint = _clean(target_endpoint) or shared_endpoint
resolved_target_api_version = _clean(target_api_version) or shared_api_version
resolved_target_api_key = _clean(target_api_key) or shared_api_key
resolved_target_auth_mode = _clean(target_auth_mode, lower=True) or shared_auth_mode
resolved_target_ad_scope = _clean(target_ad_scope) or shared_ad_scope
resolved_target_mi = (
_clean(target_managed_identity_client_id)
or shared_managed_identity_client_id
)
_set("TEACHER_ENDPOINT", resolved_teacher_endpoint, "TEACHER_AZURE_OPENAI_ENDPOINT")
_set("OPTIMIZER_ENDPOINT", resolved_optimizer_endpoint, "OPTIMIZER_AZURE_OPENAI_ENDPOINT")
_set(
"TEACHER_API_VERSION",
resolved_teacher_api_version,
"TEACHER_AZURE_OPENAI_API_VERSION",
"OPTIMIZER_API_VERSION",
resolved_optimizer_api_version,
"OPTIMIZER_AZURE_OPENAI_API_VERSION",
)
_set("TEACHER_API_KEY", resolved_teacher_api_key, "TEACHER_AZURE_OPENAI_API_KEY")
_set("TEACHER_AUTH_MODE", resolved_teacher_auth_mode, "TEACHER_AZURE_OPENAI_AUTH_MODE")
_set("TEACHER_AD_SCOPE", resolved_teacher_ad_scope, "TEACHER_AZURE_OPENAI_AD_SCOPE")
_set("OPTIMIZER_API_KEY", resolved_optimizer_api_key, "OPTIMIZER_AZURE_OPENAI_API_KEY")
_set("OPTIMIZER_AUTH_MODE", resolved_optimizer_auth_mode, "OPTIMIZER_AZURE_OPENAI_AUTH_MODE")
_set("OPTIMIZER_AD_SCOPE", resolved_optimizer_ad_scope, "OPTIMIZER_AZURE_OPENAI_AD_SCOPE")
_set(
"TEACHER_MANAGED_IDENTITY_CLIENT_ID",
resolved_teacher_mi,
"TEACHER_AZURE_OPENAI_MANAGED_IDENTITY_CLIENT_ID",
"OPTIMIZER_MANAGED_IDENTITY_CLIENT_ID",
resolved_optimizer_mi,
"OPTIMIZER_AZURE_OPENAI_MANAGED_IDENTITY_CLIENT_ID",
)
_set("STUDENT_ENDPOINT", resolved_student_endpoint, "STUDENT_AZURE_OPENAI_ENDPOINT")
_set("TARGET_ENDPOINT", resolved_target_endpoint, "TARGET_AZURE_OPENAI_ENDPOINT")
_set(
"STUDENT_API_VERSION",
resolved_student_api_version,
"STUDENT_AZURE_OPENAI_API_VERSION",
"TARGET_API_VERSION",
resolved_target_api_version,
"TARGET_AZURE_OPENAI_API_VERSION",
)
_set("STUDENT_API_KEY", resolved_student_api_key, "STUDENT_AZURE_OPENAI_API_KEY")
_set("STUDENT_AUTH_MODE", resolved_student_auth_mode, "STUDENT_AZURE_OPENAI_AUTH_MODE")
_set("STUDENT_AD_SCOPE", resolved_student_ad_scope, "STUDENT_AZURE_OPENAI_AD_SCOPE")
_set("TARGET_API_KEY", resolved_target_api_key, "TARGET_AZURE_OPENAI_API_KEY")
_set("TARGET_AUTH_MODE", resolved_target_auth_mode, "TARGET_AZURE_OPENAI_AUTH_MODE")
_set("TARGET_AD_SCOPE", resolved_target_ad_scope, "TARGET_AZURE_OPENAI_AD_SCOPE")
_set(
"STUDENT_MANAGED_IDENTITY_CLIENT_ID",
resolved_student_mi,
"STUDENT_AZURE_OPENAI_MANAGED_IDENTITY_CLIENT_ID",
"TARGET_MANAGED_IDENTITY_CLIENT_ID",
resolved_target_mi,
"TARGET_AZURE_OPENAI_MANAGED_IDENTITY_CLIENT_ID",
)
with _teacher_lock:
_teacher_client = None
with _student_lock:
_student_client = None
with _optimizer_lock:
_optimizer_client = None
with _target_lock:
_target_client = None
def chat_teacher(
def chat_optimizer(
system: str,
user: str,
max_completion_tokens: int = 16384,
retries: int = 5,
stage: str = "teacher",
stage: str = "optimizer",
reasoning_effort: str | None = None,
timeout: int | None = None,
) -> tuple[str, dict]:
"""Call the teacher model. Returns (response_text, usage_dict)."""
"""Call the optimizer model. Returns (response_text, usage_dict)."""
return _chat_impl(
get_teacher_client(), TEACHER_DEPLOYMENT,
get_optimizer_client(), OPTIMIZER_DEPLOYMENT,
system, user, max_completion_tokens, retries, stage, reasoning_effort, timeout,
)
@@ -723,7 +729,7 @@ def chat_with_deployment(
) -> tuple[str, dict]:
"""Call an arbitrary deployment using the shared Azure client."""
return _chat_impl(
get_teacher_client(),
get_optimizer_client(),
deployment,
system,
user,
@@ -735,27 +741,27 @@ def chat_with_deployment(
)
def chat_student(
def chat_target(
system: str,
user: str,
max_completion_tokens: int = 16384,
retries: int = 5,
stage: str = "student",
stage: str = "target",
reasoning_effort: str | None = None,
timeout: int | None = None,
) -> tuple[str, dict]:
"""Call the student model. Returns (response_text, usage_dict)."""
"""Call the target model. Returns (response_text, usage_dict)."""
return _chat_impl(
get_student_client(), STUDENT_DEPLOYMENT,
get_target_client(), TARGET_DEPLOYMENT,
system, user, max_completion_tokens, retries, stage, reasoning_effort, timeout,
)
def chat_teacher_messages(
def chat_optimizer_messages(
messages: list[dict[str, Any]],
max_completion_tokens: int = 16384,
retries: int = 5,
stage: str = "teacher",
stage: str = "optimizer",
reasoning_effort: str | None = None,
*,
tools: list[dict[str, Any]] | None = None,
@@ -763,10 +769,10 @@ def chat_teacher_messages(
return_message: bool = False,
timeout: int | None = None,
) -> tuple[Any, dict]:
"""Call the teacher model with a pre-built chat message list."""
"""Call the optimizer model with a pre-built chat message list."""
return _chat_messages_impl(
get_teacher_client(),
TEACHER_DEPLOYMENT,
get_optimizer_client(),
OPTIMIZER_DEPLOYMENT,
messages,
max_completion_tokens,
retries,
@@ -794,7 +800,7 @@ def chat_messages_with_deployment(
) -> tuple[Any, dict]:
"""Call an arbitrary deployment with a pre-built chat message list."""
return _chat_messages_impl(
get_teacher_client(),
get_optimizer_client(),
deployment,
messages,
max_completion_tokens,
@@ -808,11 +814,11 @@ def chat_messages_with_deployment(
)
def chat_student_messages(
def chat_target_messages(
messages: list[dict[str, Any]],
max_completion_tokens: int = 16384,
retries: int = 5,
stage: str = "student",
stage: str = "target",
reasoning_effort: str | None = None,
*,
tools: list[dict[str, Any]] | None = None,
@@ -820,10 +826,10 @@ def chat_student_messages(
return_message: bool = False,
timeout: int | None = None,
) -> tuple[Any, dict]:
"""Call the student model with a pre-built chat message list."""
"""Call the target model with a pre-built chat message list."""
return _chat_messages_impl(
get_student_client(),
STUDENT_DEPLOYMENT,
get_target_client(),
TARGET_DEPLOYMENT,
messages,
max_completion_tokens,
retries,
@@ -845,14 +851,14 @@ def reset_token_tracker() -> None:
tracker.reset()
def set_student_deployment(deployment: str) -> None:
"""Change student deployment at runtime."""
global _student_client, STUDENT_DEPLOYMENT
STUDENT_DEPLOYMENT = deployment
os.environ["STUDENT_DEPLOYMENT"] = deployment
def set_target_deployment(deployment: str) -> None:
"""Change target deployment at runtime."""
global _target_client, TARGET_DEPLOYMENT
TARGET_DEPLOYMENT = deployment
os.environ["TARGET_DEPLOYMENT"] = deployment
os.environ["AZURE_OPENAI_DEPLOYMENT"] = deployment
with _student_lock:
_student_client = None
with _target_lock:
_target_client = None
try:
import llm_client as _legacy
_legacy.DEPLOYMENT = deployment
@@ -872,10 +878,10 @@ def get_reasoning_effort() -> str | None:
return REASONING_EFFORT
def set_teacher_deployment(deployment: str) -> None:
"""Change teacher deployment at runtime."""
global _teacher_client, TEACHER_DEPLOYMENT
TEACHER_DEPLOYMENT = deployment
os.environ["TEACHER_DEPLOYMENT"] = deployment
with _teacher_lock:
_teacher_client = None
def set_optimizer_deployment(deployment: str) -> None:
"""Change optimizer deployment at runtime."""
global _optimizer_client, OPTIMIZER_DEPLOYMENT
OPTIMIZER_DEPLOYMENT = deployment
os.environ["OPTIMIZER_DEPLOYMENT"] = deployment
with _optimizer_lock:
_optimizer_client = None
+25 -25
View File
@@ -1,4 +1,4 @@
"""Runtime backend configuration for teacher/student model calls."""
"""Runtime backend configuration for optimizer/target model calls."""
from __future__ import annotations
import os
@@ -12,8 +12,8 @@ def _parse_bool(value: str | None, default: bool) -> bool:
return str(value).strip().lower() in {"1", "true", "yes", "on"}
TEACHER_BACKEND = normalize_backend_name(os.environ.get("TEACHER_BACKEND", "openai_chat"))
STUDENT_BACKEND = normalize_backend_name(os.environ.get("STUDENT_BACKEND", "openai_chat"))
OPTIMIZER_BACKEND = normalize_backend_name(os.environ.get("OPTIMIZER_BACKEND", "openai_chat"))
TARGET_BACKEND = normalize_backend_name(os.environ.get("TARGET_BACKEND", "openai_chat"))
CODEX_EXEC_PATH = os.environ.get("CODEX_EXEC_PATH", "codex")
CODEX_EXEC_SANDBOX = os.environ.get("CODEX_EXEC_SANDBOX", "workspace-write")
@@ -46,46 +46,46 @@ CLAUDE_CODE_EXEC_MAX_THINKING_TOKENS = max(
)
def set_teacher_backend(backend: str) -> None:
global TEACHER_BACKEND
TEACHER_BACKEND = normalize_backend_name(backend or "openai_chat")
if TEACHER_BACKEND not in {"openai_chat", "claude_chat"}:
def set_optimizer_backend(backend: str) -> None:
global OPTIMIZER_BACKEND
OPTIMIZER_BACKEND = normalize_backend_name(backend or "openai_chat")
if OPTIMIZER_BACKEND not in {"openai_chat", "claude_chat"}:
raise ValueError(
f"Unsupported teacher backend: {TEACHER_BACKEND!r}. "
f"Unsupported optimizer backend: {OPTIMIZER_BACKEND!r}. "
"Supported values are 'openai_chat' and 'claude_chat'."
)
os.environ["TEACHER_BACKEND"] = TEACHER_BACKEND
os.environ["OPTIMIZER_BACKEND"] = OPTIMIZER_BACKEND
def get_teacher_backend() -> str:
return TEACHER_BACKEND
def get_optimizer_backend() -> str:
return OPTIMIZER_BACKEND
def set_student_backend(backend: str) -> None:
global STUDENT_BACKEND
STUDENT_BACKEND = normalize_backend_name(backend or "openai_chat")
if STUDENT_BACKEND not in {"openai_chat", "claude_chat", "qwen_chat", "codex_exec", "claude_code_exec"}:
def set_target_backend(backend: str) -> None:
global TARGET_BACKEND
TARGET_BACKEND = normalize_backend_name(backend or "openai_chat")
if TARGET_BACKEND not in {"openai_chat", "claude_chat", "qwen_chat", "codex_exec", "claude_code_exec"}:
raise ValueError(
f"Unsupported student backend: {STUDENT_BACKEND!r}. "
f"Unsupported target backend: {TARGET_BACKEND!r}. "
"Supported values are 'openai_chat', 'claude_chat', 'qwen_chat', 'codex_exec', and 'claude_code_exec'."
)
os.environ["STUDENT_BACKEND"] = STUDENT_BACKEND
os.environ["TARGET_BACKEND"] = TARGET_BACKEND
def get_student_backend() -> str:
return STUDENT_BACKEND
def get_target_backend() -> str:
return TARGET_BACKEND
def is_student_exec_backend() -> bool:
return STUDENT_BACKEND in {"codex_exec", "claude_code_exec"}
def is_target_exec_backend() -> bool:
return TARGET_BACKEND in {"codex_exec", "claude_code_exec"}
def is_teacher_chat_backend() -> bool:
return TEACHER_BACKEND in {"openai_chat", "claude_chat"}
def is_optimizer_chat_backend() -> bool:
return OPTIMIZER_BACKEND in {"openai_chat", "claude_chat"}
def is_student_chat_backend() -> bool:
return STUDENT_BACKEND in {"openai_chat", "claude_chat", "qwen_chat"}
def is_target_chat_backend() -> bool:
return TARGET_BACKEND in {"openai_chat", "claude_chat", "qwen_chat"}
def configure_codex_exec(
+19 -19
View File
@@ -19,8 +19,8 @@ CLAUDE_PERMISSION_MODE = os.environ.get("CLAUDE_PERMISSION_MODE", "dontAsk")
CLAUDE_SETTING_SOURCES = os.environ.get("CLAUDE_SETTING_SOURCES", "user,project")
CLAUDE_ALLOW_ATTACHMENT_READ = os.environ.get("CLAUDE_ALLOW_ATTACHMENT_READ", "1").strip().lower() not in {"0", "false", "no"}
TEACHER_DEPLOYMENT = os.environ.get("TEACHER_DEPLOYMENT", "claude-sonnet-4-6")
STUDENT_DEPLOYMENT = os.environ.get("STUDENT_DEPLOYMENT", "claude-sonnet-4-6")
OPTIMIZER_DEPLOYMENT = os.environ.get("OPTIMIZER_DEPLOYMENT", "claude-sonnet-4-6")
TARGET_DEPLOYMENT = os.environ.get("TARGET_DEPLOYMENT", "claude-sonnet-4-6")
REASONING_EFFORT: str | None = None
_VALID_EFFORTS = {"low", "medium", "high", "xhigh", "max"}
@@ -292,7 +292,7 @@ def _compat_message_from_payload(payload: Any) -> CompatAssistantMessage:
def _call_messages(messages: list[dict[str, Any]], max_completion_tokens: int, retries: int, stage: str, *, tools: list[dict[str, Any]] | None = None, tool_choice: str | dict[str, Any] | None = None, return_message: bool = False, deployment: str | None = None, timeout: int | None = None) -> tuple[Any, dict[str, int]]:
del max_completion_tokens
system, prompt, attachments = _build_prompt_from_messages(messages, tools=tools, tool_choice=tool_choice, structured_output=return_message)
model = deployment or STUDENT_DEPLOYMENT
model = deployment or TARGET_DEPLOYMENT
last_err = None
for attempt in range(retries):
try:
@@ -307,14 +307,14 @@ def _call_messages(messages: list[dict[str, Any]], max_completion_tokens: int, r
raise RuntimeError(f"Claude backend failed after {retries} retries: {last_err}")
def chat_teacher(system: str, user: str, max_completion_tokens: int = 16384, retries: int = 5, stage: str = "teacher", timeout: int | None = None) -> tuple[str, dict[str, int]]:
def chat_optimizer(system: str, user: str, max_completion_tokens: int = 16384, retries: int = 5, stage: str = "optimizer", timeout: int | None = None) -> tuple[str, dict[str, int]]:
messages = [{"role": "system", "content": system}, {"role": "user", "content": user}]
return _call_messages(messages, max_completion_tokens, retries, stage, deployment=TEACHER_DEPLOYMENT, timeout=timeout)
return _call_messages(messages, max_completion_tokens, retries, stage, deployment=OPTIMIZER_DEPLOYMENT, timeout=timeout)
def chat_student(system: str, user: str, max_completion_tokens: int = 16384, retries: int = 5, stage: str = "student", timeout: int | None = None) -> tuple[str, dict[str, int]]:
def chat_target(system: str, user: str, max_completion_tokens: int = 16384, retries: int = 5, stage: str = "target", timeout: int | None = None) -> tuple[str, dict[str, int]]:
messages = [{"role": "system", "content": system}, {"role": "user", "content": user}]
return _call_messages(messages, max_completion_tokens, retries, stage, deployment=STUDENT_DEPLOYMENT, timeout=timeout)
return _call_messages(messages, max_completion_tokens, retries, stage, deployment=TARGET_DEPLOYMENT, timeout=timeout)
def chat_with_deployment(deployment: str, system: str, user: str, max_completion_tokens: int = 16384, retries: int = 5, stage: str = "custom", timeout: int | None = None) -> tuple[str, dict[str, int]]:
@@ -322,12 +322,12 @@ def chat_with_deployment(deployment: str, system: str, user: str, max_completion
return _call_messages(messages, max_completion_tokens, retries, stage, deployment=deployment, timeout=timeout)
def chat_teacher_messages(messages: list[dict[str, Any]], max_completion_tokens: int = 16384, retries: int = 5, stage: str = "teacher", *, tools: list[dict[str, Any]] | None = None, tool_choice: str | dict[str, Any] | None = None, return_message: bool = False, timeout: int | None = None) -> tuple[Any, dict[str, int]]:
return _call_messages(messages, max_completion_tokens, retries, stage, tools=tools, tool_choice=tool_choice, return_message=return_message, deployment=TEACHER_DEPLOYMENT, timeout=timeout)
def chat_optimizer_messages(messages: list[dict[str, Any]], max_completion_tokens: int = 16384, retries: int = 5, stage: str = "optimizer", *, tools: list[dict[str, Any]] | None = None, tool_choice: str | dict[str, Any] | None = None, return_message: bool = False, timeout: int | None = None) -> tuple[Any, dict[str, int]]:
return _call_messages(messages, max_completion_tokens, retries, stage, tools=tools, tool_choice=tool_choice, return_message=return_message, deployment=OPTIMIZER_DEPLOYMENT, timeout=timeout)
def chat_student_messages(messages: list[dict[str, Any]], max_completion_tokens: int = 16384, retries: int = 5, stage: str = "student", *, tools: list[dict[str, Any]] | None = None, tool_choice: str | dict[str, Any] | None = None, return_message: bool = False, timeout: int | None = None) -> tuple[Any, dict[str, int]]:
return _call_messages(messages, max_completion_tokens, retries, stage, tools=tools, tool_choice=tool_choice, return_message=return_message, deployment=STUDENT_DEPLOYMENT, timeout=timeout)
def chat_target_messages(messages: list[dict[str, Any]], max_completion_tokens: int = 16384, retries: int = 5, stage: str = "target", *, tools: list[dict[str, Any]] | None = None, tool_choice: str | dict[str, Any] | None = None, return_message: bool = False, timeout: int | None = None) -> tuple[Any, dict[str, int]]:
return _call_messages(messages, max_completion_tokens, retries, stage, tools=tools, tool_choice=tool_choice, return_message=return_message, deployment=TARGET_DEPLOYMENT, timeout=timeout)
def chat_messages_with_deployment(deployment: str, messages: list[dict[str, Any]], max_completion_tokens: int = 16384, retries: int = 5, stage: str = "custom", *, tools: list[dict[str, Any]] | None = None, tool_choice: str | dict[str, Any] | None = None, return_message: bool = False, timeout: int | None = None) -> tuple[Any, dict[str, int]]:
@@ -347,13 +347,13 @@ def set_reasoning_effort(effort: str | None) -> None:
REASONING_EFFORT = effort if effort else None
def set_student_deployment(deployment: str) -> None:
global STUDENT_DEPLOYMENT
STUDENT_DEPLOYMENT = deployment or default_model_for_backend("claude")
os.environ["STUDENT_DEPLOYMENT"] = STUDENT_DEPLOYMENT
def set_target_deployment(deployment: str) -> None:
global TARGET_DEPLOYMENT
TARGET_DEPLOYMENT = deployment or default_model_for_backend("claude")
os.environ["TARGET_DEPLOYMENT"] = TARGET_DEPLOYMENT
def set_teacher_deployment(deployment: str) -> None:
global TEACHER_DEPLOYMENT
TEACHER_DEPLOYMENT = deployment or default_model_for_backend("claude")
os.environ["TEACHER_DEPLOYMENT"] = TEACHER_DEPLOYMENT
def set_optimizer_deployment(deployment: str) -> None:
global OPTIMIZER_DEPLOYMENT
OPTIMIZER_DEPLOYMENT = deployment or default_model_for_backend("claude")
os.environ["OPTIMIZER_DEPLOYMENT"] = OPTIMIZER_DEPLOYMENT
+22 -22
View File
@@ -24,8 +24,8 @@ CODEX_BIN = os.environ.get("CODEX_CLI_BIN", "codex")
CODEX_PROFILE = os.environ.get("CODEX_PROFILE", "review")
CODEX_SANDBOX_MODE = os.environ.get("CODEX_SANDBOX_MODE", "read-only")
TEACHER_DEPLOYMENT = os.environ.get("TEACHER_DEPLOYMENT", "gpt-5.5")
STUDENT_DEPLOYMENT = os.environ.get("STUDENT_DEPLOYMENT", "gpt-5.5")
OPTIMIZER_DEPLOYMENT = os.environ.get("OPTIMIZER_DEPLOYMENT", "gpt-4o")
TARGET_DEPLOYMENT = os.environ.get("TARGET_DEPLOYMENT", "gpt-4o")
REASONING_EFFORT: str | None = None
@@ -508,16 +508,16 @@ def chat_messages_with_model(
)
def chat_teacher(
def chat_optimizer(
system: str,
user: str,
max_completion_tokens: int = 16384,
retries: int = 5,
stage: str = "teacher",
stage: str = "optimizer",
timeout: int | None = None,
) -> tuple[str, dict[str, int]]:
return chat_with_model(
model=TEACHER_DEPLOYMENT,
model=OPTIMIZER_DEPLOYMENT,
system=system,
user=user,
max_completion_tokens=max_completion_tokens,
@@ -547,16 +547,16 @@ def chat_with_deployment(
)
def chat_student(
def chat_target(
system: str,
user: str,
max_completion_tokens: int = 16384,
retries: int = 5,
stage: str = "student",
stage: str = "target",
timeout: int | None = None,
) -> tuple[str, dict[str, int]]:
return chat_with_model(
model=STUDENT_DEPLOYMENT,
model=TARGET_DEPLOYMENT,
system=system,
user=user,
max_completion_tokens=max_completion_tokens,
@@ -566,11 +566,11 @@ def chat_student(
)
def chat_teacher_messages(
def chat_optimizer_messages(
messages: list[dict[str, Any]],
max_completion_tokens: int = 16384,
retries: int = 5,
stage: str = "teacher",
stage: str = "optimizer",
*,
tools: list[dict[str, Any]] | None = None,
tool_choice: str | dict[str, Any] | None = None,
@@ -578,7 +578,7 @@ def chat_teacher_messages(
timeout: int | None = None,
) -> tuple[Any, dict[str, int]]:
return _chat_messages_impl(
TEACHER_DEPLOYMENT,
OPTIMIZER_DEPLOYMENT,
messages,
max_completion_tokens,
retries,
@@ -615,11 +615,11 @@ def chat_messages_with_deployment(
)
def chat_student_messages(
def chat_target_messages(
messages: list[dict[str, Any]],
max_completion_tokens: int = 16384,
retries: int = 5,
stage: str = "student",
stage: str = "target",
*,
tools: list[dict[str, Any]] | None = None,
tool_choice: str | dict[str, Any] | None = None,
@@ -627,7 +627,7 @@ def chat_student_messages(
timeout: int | None = None,
) -> tuple[Any, dict[str, int]]:
return _chat_messages_impl(
STUDENT_DEPLOYMENT,
TARGET_DEPLOYMENT,
messages,
max_completion_tokens,
retries,
@@ -647,10 +647,10 @@ def reset_token_tracker() -> None:
tracker.reset()
def set_student_deployment(deployment: str) -> None:
global STUDENT_DEPLOYMENT
STUDENT_DEPLOYMENT = deployment
os.environ["STUDENT_DEPLOYMENT"] = deployment
def set_target_deployment(deployment: str) -> None:
global TARGET_DEPLOYMENT
TARGET_DEPLOYMENT = deployment
os.environ["TARGET_DEPLOYMENT"] = deployment
def set_reasoning_effort(effort: str | None) -> None:
@@ -658,7 +658,7 @@ def set_reasoning_effort(effort: str | None) -> None:
REASONING_EFFORT = effort if effort else None
def set_teacher_deployment(deployment: str) -> None:
global TEACHER_DEPLOYMENT
TEACHER_DEPLOYMENT = deployment
os.environ["TEACHER_DEPLOYMENT"] = deployment
def set_optimizer_deployment(deployment: str) -> None:
global OPTIMIZER_DEPLOYMENT
OPTIMIZER_DEPLOYMENT = deployment
os.environ["OPTIMIZER_DEPLOYMENT"] = deployment
+19 -19
View File
@@ -1,4 +1,4 @@
"""Helpers for running exec backends as the student harness."""
"""Helpers for running exec backends as the target harness."""
from __future__ import annotations
import asyncio
@@ -14,7 +14,7 @@ from typing import Any
from skillopt.model.backend_config import (
get_claude_code_exec_config,
get_codex_exec_config,
get_student_backend,
get_target_backend,
)
@@ -38,7 +38,7 @@ ANSWER_SCHEMA: dict[str, Any] = {
def render_skill_md(
skill_content: str,
*,
name: str = "skillopt-student",
name: str = "skillopt-target",
description: str = "Dynamic ReflACT skill for the current benchmark task.",
preamble: str = "",
) -> str:
@@ -49,7 +49,7 @@ def render_skill_md(
f'description: "{description}"',
"---",
"",
"# ReflACT Student Skill",
"# ReflACT Target Skill",
"",
]
if preamble.strip():
@@ -77,9 +77,9 @@ def prepare_workspace(
) -> tuple[str, str]:
if os.path.exists(work_dir):
shutil.rmtree(work_dir)
os.makedirs(os.path.join(work_dir, ".agents", "skills", "skillopt-student"), exist_ok=True)
os.makedirs(os.path.join(work_dir, ".agents", "skills", "skillopt-target"), exist_ok=True)
skill_path = os.path.join(work_dir, ".agents", "skills", "skillopt-student", "SKILL.md")
skill_path = os.path.join(work_dir, ".agents", "skills", "skillopt-target", "SKILL.md")
with open(skill_path, "w", encoding="utf-8") as f:
f.write(skill_md)
@@ -318,7 +318,7 @@ def parse_codex_raw(raw: str) -> dict:
def format_codex_trace_steps(raw: str, *, max_chars: int = 4000) -> str:
"""Render parsed Codex trace into numbered compact steps for teacher prompts."""
"""Render parsed Codex trace into numbered compact steps for optimizer prompts."""
parsed = parse_codex_raw(raw)
steps = parsed["steps"]
if not steps:
@@ -474,12 +474,12 @@ def _exec_prompt(prompt: str, *, allow_file_edits: bool = False) -> str:
)
return (
"Use the workspace files to solve the task. Read task.md and the skill at "
".agents/skills/skillopt-student/SKILL.md before answering. "
".agents/skills/skillopt-target/SKILL.md before answering. "
"If ATTACHMENTS.md exists, read it and inspect the listed local files. "
"Do not call a Skill tool; the ReflACT guidance is a local markdown file. "
f"Do not ask for permission. {edit_instruction}"
"Return only the final answer text, keeping any required <answer>...</answer> tags exactly.\n\n"
f"{_normalize_student_exec_prompt(prompt)}"
f"{_normalize_target_exec_prompt(prompt)}"
)
@@ -489,20 +489,20 @@ def _retry_prompt(prompt: str, attempt: int) -> str:
return (
f"{prompt}\n\n"
"Previous execution returned an empty final response. Re-read task.md and "
".agents/skills/skillopt-student/SKILL.md. If ATTACHMENTS.md exists, use the listed files. "
".agents/skills/skillopt-target/SKILL.md. If ATTACHMENTS.md exists, use the listed files. "
"Then produce the final answer inside <answer>...</answer>."
)
def _normalize_student_exec_prompt(prompt: str) -> str:
def _normalize_target_exec_prompt(prompt: str) -> str:
"""Avoid wording that makes Claude Code call an unregistered Skill tool."""
text = prompt or ""
replacements = {
"Use the `skillopt-student` skill available in this workspace.": (
"Read `.agents/skills/skillopt-student/SKILL.md` directly; do not call a Skill tool."
"Use the `skillopt-target` skill available in this workspace.": (
"Read `.agents/skills/skillopt-target/SKILL.md` directly; do not call a Skill tool."
),
"- Use the local `skillopt-student` skill before writing code.": (
"- Read `.agents/skills/skillopt-student/SKILL.md` before writing code; do not call a Skill tool."
"- Use the local `skillopt-target` skill before writing code.": (
"- Read `.agents/skills/skillopt-target/SKILL.md` before writing code; do not call a Skill tool."
),
}
for old, new in replacements.items():
@@ -586,7 +586,7 @@ def _run_claude_code_sdk_exec(
"preset": "claude_code",
"append": (
"Use the workspace files to solve the task. Read task.md and the skill at "
".agents/skills/skillopt-student/SKILL.md before answering. "
".agents/skills/skillopt-target/SKILL.md before answering. "
"If ATTACHMENTS.md exists, read it and inspect the listed local files. "
"Do not call a Skill tool; the ReflACT guidance is a local markdown file. "
+ (
@@ -619,7 +619,7 @@ def _run_claude_code_sdk_exec(
messages = []
async with ClaudeSDKClient(options) as client:
await client.query(_normalize_student_exec_prompt(prompt))
await client.query(_normalize_target_exec_prompt(prompt))
messages = [msg async for msg in client.receive_response()]
last = messages[-1] if messages else None
raw_structured_output = _extract_claude_structured_output(messages)
@@ -1016,7 +1016,7 @@ def run_codex_exec(
return last_response, combined
def run_student_exec(
def run_target_exec(
*,
work_dir: str,
prompt: str,
@@ -1030,7 +1030,7 @@ def run_student_exec(
full_auto: bool | None = None,
allow_file_edits: bool = False,
) -> tuple[str, str]:
backend = get_student_backend()
backend = get_target_backend()
if backend == "codex_exec":
return run_codex_exec(
work_dir=work_dir,
+4 -4
View File
@@ -17,10 +17,10 @@ _RESPONSES_API_MODELS = {
}
_BACKEND_DEFAULT_MODELS = {
"azure_openai": "gpt-5.5",
"openai_chat": "gpt-5.5",
"codex": "gpt-5.5",
"codex_exec": "gpt-5.5",
"azure_openai": "gpt-4o",
"openai_chat": "gpt-4o",
"codex": "gpt-4o",
"codex_exec": "gpt-4o",
"claude": "claude-sonnet-4-6",
"claude_chat": "claude-sonnet-4-6",
"claude_code_exec": "claude-sonnet-4-6",
+12 -12
View File
@@ -1,4 +1,4 @@
"""OpenAI-compatible Qwen chat backend for the student path."""
"""OpenAI-compatible Qwen chat backend for the target path."""
from __future__ import annotations
import json
@@ -32,8 +32,8 @@ ENABLE_THINKING = os.environ.get("QWEN_CHAT_ENABLE_THINKING", "false").strip().l
"on",
}
STUDENT_DEPLOYMENT = os.environ.get(
"STUDENT_DEPLOYMENT",
TARGET_DEPLOYMENT = os.environ.get(
"TARGET_DEPLOYMENT",
default_model_for_backend("qwen_chat"),
)
@@ -140,7 +140,7 @@ def _chat_messages_impl(
timeout: float | None = None,
) -> tuple[Any, dict[str, int]]:
payload: dict[str, Any] = {
"model": deployment or STUDENT_DEPLOYMENT,
"model": deployment or TARGET_DEPLOYMENT,
"messages": _json_safe(messages),
"max_tokens": min(max_completion_tokens, MAX_TOKENS),
}
@@ -214,12 +214,12 @@ def get_max_tokens() -> int:
return MAX_TOKENS
def chat_student(
def chat_target(
system: str,
user: str,
max_completion_tokens: int = 16384,
retries: int = 5,
stage: str = "student",
stage: str = "target",
reasoning_effort: str | None = None,
timeout: float | None = None,
) -> tuple[str, dict[str, int]]:
@@ -234,11 +234,11 @@ def chat_student(
)
def chat_student_messages(
def chat_target_messages(
messages: list[dict[str, Any]],
max_completion_tokens: int = 16384,
retries: int = 5,
stage: str = "student",
stage: str = "target",
reasoning_effort: str | None = None,
*,
tools: list[dict[str, Any]] | None = None,
@@ -271,7 +271,7 @@ def set_reasoning_effort(effort: str | None) -> None:
del effort
def set_student_deployment(deployment: str) -> None:
global STUDENT_DEPLOYMENT
STUDENT_DEPLOYMENT = deployment or default_model_for_backend("qwen_chat")
os.environ["STUDENT_DEPLOYMENT"] = STUDENT_DEPLOYMENT
def set_target_deployment(deployment: str) -> None:
global TARGET_DEPLOYMENT
TARGET_DEPLOYMENT = deployment or default_model_for_backend("qwen_chat")
os.environ["TARGET_DEPLOYMENT"] = TARGET_DEPLOYMENT
+40 -40
View File
@@ -43,15 +43,15 @@ def get_backend_name() -> str:
return _ACTIVE_BACKEND
def chat_teacher(
def chat_optimizer(
system: str,
user: str,
max_completion_tokens: int = 16384,
retries: int = 5,
stage: str = "teacher",
stage: str = "optimizer",
timeout: int | None = None,
) -> tuple[str, dict[str, int]]:
return _backend_module(_ACTIVE_BACKEND).chat_teacher(
return _backend_module(_ACTIVE_BACKEND).chat_optimizer(
system=system,
user=user,
max_completion_tokens=max_completion_tokens,
@@ -61,15 +61,15 @@ def chat_teacher(
)
def chat_student(
def chat_target(
system: str,
user: str,
max_completion_tokens: int = 16384,
retries: int = 5,
stage: str = "student",
stage: str = "target",
timeout: int | None = None,
) -> tuple[str, dict[str, int]]:
return _backend_module(_ACTIVE_BACKEND).chat_student(
return _backend_module(_ACTIVE_BACKEND).chat_target(
system=system,
user=user,
max_completion_tokens=max_completion_tokens,
@@ -99,18 +99,18 @@ def chat_with_deployment(
)
def chat_teacher_messages(
def chat_optimizer_messages(
messages: list[dict[str, Any]],
max_completion_tokens: int = 16384,
retries: int = 5,
stage: str = "teacher",
stage: str = "optimizer",
*,
tools: list[dict[str, Any]] | None = None,
tool_choice: str | dict[str, Any] | None = None,
return_message: bool = False,
timeout: int | None = None,
) -> tuple[Any, dict[str, int]]:
return _backend_module(_ACTIVE_BACKEND).chat_teacher_messages(
return _backend_module(_ACTIVE_BACKEND).chat_optimizer_messages(
messages=messages,
max_completion_tokens=max_completion_tokens,
retries=retries,
@@ -122,18 +122,18 @@ def chat_teacher_messages(
)
def chat_student_messages(
def chat_target_messages(
messages: list[dict[str, Any]],
max_completion_tokens: int = 16384,
retries: int = 5,
stage: str = "student",
stage: str = "target",
*,
tools: list[dict[str, Any]] | None = None,
tool_choice: str | dict[str, Any] | None = None,
return_message: bool = False,
timeout: int | None = None,
) -> tuple[Any, dict[str, int]]:
return _backend_module(_ACTIVE_BACKEND).chat_student_messages(
return _backend_module(_ACTIVE_BACKEND).chat_target_messages(
messages=messages,
max_completion_tokens=max_completion_tokens,
retries=retries,
@@ -183,14 +183,14 @@ def set_reasoning_effort(effort: str | None) -> None:
module.set_reasoning_effort(effort)
def set_student_deployment(deployment: str) -> None:
def set_target_deployment(deployment: str) -> None:
for module in _all_backend_modules():
module.set_student_deployment(deployment)
module.set_target_deployment(deployment)
def set_teacher_deployment(deployment: str) -> None:
def set_optimizer_deployment(deployment: str) -> None:
for module in _all_backend_modules():
module.set_teacher_deployment(deployment)
module.set_optimizer_deployment(deployment)
def configure_azure_openai(
@@ -201,18 +201,18 @@ def configure_azure_openai(
auth_mode: str | None = None,
ad_scope: str | None = None,
managed_identity_client_id: str | None = None,
teacher_endpoint: str | None = None,
teacher_api_version: str | None = None,
teacher_api_key: str | None = None,
teacher_auth_mode: str | None = None,
teacher_ad_scope: str | None = None,
teacher_managed_identity_client_id: str | None = None,
student_endpoint: str | None = None,
student_api_version: str | None = None,
student_api_key: str | None = None,
student_auth_mode: str | None = None,
student_ad_scope: str | None = None,
student_managed_identity_client_id: str | None = None,
optimizer_endpoint: str | None = None,
optimizer_api_version: str | None = None,
optimizer_api_key: str | None = None,
optimizer_auth_mode: str | None = None,
optimizer_ad_scope: str | None = None,
optimizer_managed_identity_client_id: str | None = None,
target_endpoint: str | None = None,
target_api_version: str | None = None,
target_api_key: str | None = None,
target_auth_mode: str | None = None,
target_ad_scope: str | None = None,
target_managed_identity_client_id: str | None = None,
) -> None:
azure_openai.configure_azure_openai(
endpoint=endpoint,
@@ -221,16 +221,16 @@ def configure_azure_openai(
auth_mode=auth_mode,
ad_scope=ad_scope,
managed_identity_client_id=managed_identity_client_id,
teacher_endpoint=teacher_endpoint,
teacher_api_version=teacher_api_version,
teacher_api_key=teacher_api_key,
teacher_auth_mode=teacher_auth_mode,
teacher_ad_scope=teacher_ad_scope,
teacher_managed_identity_client_id=teacher_managed_identity_client_id,
student_endpoint=student_endpoint,
student_api_version=student_api_version,
student_api_key=student_api_key,
student_auth_mode=student_auth_mode,
student_ad_scope=student_ad_scope,
student_managed_identity_client_id=student_managed_identity_client_id,
optimizer_endpoint=optimizer_endpoint,
optimizer_api_version=optimizer_api_version,
optimizer_api_key=optimizer_api_key,
optimizer_auth_mode=optimizer_auth_mode,
optimizer_ad_scope=optimizer_ad_scope,
optimizer_managed_identity_client_id=optimizer_managed_identity_client_id,
target_endpoint=target_endpoint,
target_api_version=target_api_version,
target_api_key=target_api_key,
target_auth_mode=target_auth_mode,
target_ad_scope=target_ad_scope,
target_managed_identity_client_id=target_managed_identity_client_id,
)