This documentation-only procedure is for an application owner with a repeated, permitted text task and OpenAI API access. Use real owned prompts and acceptance criteria. BIG CHANGE has not made a model call, observed model quality, measured a bill or found a saving. The code below makes a deterministic application decision from owner-supplied task features; no model learns the route. It names the model on each Agents SDK Agent, uses no tools, explicitly disables SDK trace export, and does not initiate a second run or escalation after an uncertain request. The authorized model API call itself sends the approved prompt externally; verify account data handling before any run.
The reader's output is a private case ledger: chosen tier and model for each call, exact prompt hash, raw answer, reported usage, review decision and any further authorized tier attempt. Keep a fixed baseline route and compare total accepted tasks, latency, billed cost where available, and human review/rework time. A lower token rate alone does not settle the decision.
The big change
- What changed: The application chooses a model for each approved case from three owner-labeled features: complexity, quality sensitivity and measured context size. A frozen rule puts the selected tier's exact model ID on that case's SDK
Agent. - Why it matters: The choice can be checked against a fixed baseline using accepted work and full workflow cost, including failed attempts and review.
- What to watch: This is a proposed reader-run method. Model quality, account charges and any saving remain unmeasured until the owner completes the trial and reconciles billing.
1. Freeze the real workflow and limits
List every step in the existing workflow, including planning, classifier, specialist, tool calls, human review, failed attempts and retries. Choose one repeatable text step whose answer can be checked. Save representative easy, medium, hard, long-context and sensitive cases from your permitted material; reserve a held-out set. For each case, write its correct answer or a reviewer rubric before seeing any candidate output. Assign complexity and quality_sensitivity from 1 to 3, context_tokens from an actual tokenizer or API count, and data_class as approved_api or blocked. Preserve the underlying prompt, revision and source rights. Do not put secrets or customer data in the example files.
Use Python 3.10 or newer in a private project directory. Set up that directory with the commands for your shell. These setup commands do not call a model.
PowerShell on Windows:
python -m venv .venv
.venv\Scripts\Activate.ps1
python -m pip install "openai-agents==0.24.0"
python -m pip show openai-agentsPOSIX shell on macOS or Linux:
python -m venv .venv
source .venv/bin/activate
python -m pip install "openai-agents==0.24.0"
python -m pip show openai-agentsPyPI listed 0.24.0 as the current release on 26 October 2026; pin it in your environment lock and recheck its contract before paid use. Check the Agents SDK model documentation, run API, usage fields, tracing controls, model access, current API rates and data policy for the actual account. Supply OPENAI_API_KEY through your secret manager and confirm that the API project permits every chosen model and approved prompt. This API billing is separate from a ChatGPT/Codex subscription. Before paid trials, have an authorized account owner check the project's spend controls: an alert alone does not stop requests, and even an enforced hard limit can take time to apply and allow a slight overrun. Agree an internal trial spend authorization and review account usage between attempts; neither the configured number nor a single request is a guaranteed charge cap.
Save route-config.json privately, replacing all angle-bracket values with exact currently available model IDs and owner-approved thresholds. Rates are optional; null leaves estimated cost unknown. The three models may be any exact compatible IDs with distinct observed economics; labels do not assert model capability. Set each max_context_tokens below the model's documented limit with room for instructions and output. The numbers below illustrate the schema and are not verified limits for any particular model.
{
"revision": "owner-route-1",
"tiers": [
{"tier": "small", "model": "<approved-small-model-id>", "max_context_tokens": 16000, "input_usd_per_million": null, "output_usd_per_million": null},
{"tier": "middle", "model": "<approved-middle-model-id>", "max_context_tokens": 32000, "input_usd_per_million": null, "output_usd_per_million": null},
{"tier": "high", "model": "<approved-high-model-id>", "max_context_tokens": 64000, "input_usd_per_million": null, "output_usd_per_million": null}
],
"max_output_tokens_reserved": 2048,
"trial": {
"id": "<owner-approved-trial-id>",
"case_ids": ["<stable-real-case-id>"],
"baseline_tier": "middle",
"max_attempts_per_case_arm": 2,
"max_total_attempts": 4,
"authorized_spend_usd": "<owner-approved-API-project-limit>"
}
}For each real case, save a separate JSON file such as cases/case-001.json and keep it out of source control if private. The prompt is a real approved task; the values shown here are field descriptions, not a fictitious test case. Freeze case IDs, baseline/candidate arms, repetitions, escalation ceiling, total attempts and an approved trial-spend amount before any call. max_total_attempts is across both arms. authorized_spend_usd records that approval and is checked for a finite positive value; the script does not calculate spending or enforce a charge limit. Check the available organization/project controls separately, confirm whether a hard limit is enabled, and allow for delayed enforcement or billing. Use one local writer and a private output directory.
Store the approved prompt at the exact prompt_file path and the prewritten pass/fail rubric at rubric_file, both relative to the case JSON's directory. A plan is valid only after these real files and every placeholder have been replaced. Keep case IDs unique within the frozen trial; separate trials need separate output directories because the receipt scan is directory-local. Never run two writers against one trial directory concurrently.
{
"case_id": "<stable-real-case-id>",
"prompt_file": "<relative-path-to-approved-real-prompt.txt>",
"complexity": 1,
"quality_sensitivity": 1,
"context_tokens": 1000,
"data_class": "approved_api",
"rubric_file": "<relative-path-to-owner-frozen-rubric.md>"
}2. Save the complete router
Save as route.py beside the config. Its plan command is local and sends no prompt. Its run command is an optional paid API action for the reader, after they have approved that case and model. It reserves a durable receipt first, then starts one SDK run with one agent turn and a per-attempt timeout, records response and usage, and leaves one-step escalation to a separate explicit call. A further tier requires a newly reviewed config/trial revision. Inspect installed SDK/client transport retries and settled account usage; one local command need not mean one billable network attempt. An uncertain response is unresolved before any repeat. Relative paths below resolve from the case-file directory.
import argparse
import hashlib
import json
import os
import pathlib
import time
import uuid
from datetime import datetime, timezone
from decimal import Decimal, InvalidOperation
ORDER = ("small", "middle", "high")
def load_json(path):
return json.loads(pathlib.Path(path).read_text(encoding="utf-8"))
def text_file(base, relative):
p = (base / relative).resolve()
if not p.is_relative_to(base.resolve()) or not p.is_file():
raise ValueError("Input path must be an existing file under the case directory")
return p.read_text(encoding="utf-8")
def digest(path):
return hashlib.sha256(pathlib.Path(path).read_bytes()).hexdigest()
def reserve(out, plan, trial):
out.parent.mkdir(parents=True, exist_ok=True)
prior = []
for p in out.parent.glob("*.json"):
try:
r = load_json(p)
except (OSError, ValueError):
raise ValueError("Unreadable trial receipt; stop before another call")
if r.get("trial_id") == trial["id"]:
prior.append(r)
if len(prior) >= trial["max_total_attempts"]:
raise ValueError("Trial attempt limit reached")
same = [r for r in prior if r.get("plan", {}).get("case_id") == plan["case_id"]
and r.get("plan", {}).get("arm") == plan["arm"]]
if len(same) >= trial["max_attempts_per_case_arm"]:
raise ValueError("Case/arm attempt limit reached")
intent = {"status": "intent", "trial_id": trial["id"],
"attempt_id": uuid.uuid4().hex, "plan": plan,
"created_at_utc": datetime.now(timezone.utc).isoformat()}
with out.open("x", encoding="utf-8") as f:
json.dump(intent, f, indent=2)
f.write("\n")
f.flush()
os.fsync(f.fileno())
return intent
def replace_receipt(out, record):
temp = out.with_name(out.name + "." + uuid.uuid4().hex + ".new")
with temp.open("x", encoding="utf-8") as f:
json.dump(record, f, indent=2)
f.write("\n")
f.flush()
os.fsync(f.fileno())
os.replace(temp, out)
def detail(value):
return value if value is not None else "unknown"
def route(config, case, escalate=False):
tiers = config["tiers"]
if [t["tier"] for t in tiers] != list(ORDER):
raise ValueError("Expected ordered small, middle, high tiers")
for t in tiers:
if not t["model"] or "<" in t["model"]:
raise ValueError("Replace every model placeholder before planning")
if not isinstance(t["max_context_tokens"], int) or t["max_context_tokens"] <= 0:
raise ValueError("Invalid context limit")
if case["data_class"] != "approved_api":
raise ValueError("Case has no API data permission")
for field in ("complexity", "quality_sensitivity"):
if case[field] not in (1, 2, 3):
raise ValueError("Features must be integers 1, 2 or 3")
if not isinstance(case["context_tokens"], int) or case["context_tokens"] < 1:
raise ValueError("Use an actual positive token count")
needed = max(case["complexity"], case["quality_sensitivity"]) - 1
reserved = config["max_output_tokens_reserved"]
eligible = [i for i in range(needed, 3)
if case["context_tokens"] + reserved <= tiers[i]["max_context_tokens"]]
if not eligible:
raise ValueError("No approved tier fits context and output reserve")
chosen = eligible[0]
if escalate:
later = [i for i in eligible if i > chosen]
if not later:
raise ValueError("No higher fitting tier; return to human review")
chosen = later[0]
return tiers[chosen], needed
def main():
ap = argparse.ArgumentParser()
ap.add_argument("action", choices=("plan", "run"))
ap.add_argument("config")
ap.add_argument("case")
ap.add_argument("--arm", choices=("baseline", "candidate"), default="candidate")
ap.add_argument("--escalate", action="store_true")
ap.add_argument("--out", default="")
args = ap.parse_args()
config = load_json(args.config)
trial = config["trial"]
if not trial.get("id") or "<" in trial["id"]:
raise ValueError("Freeze owner-approved trial ID")
try:
ceiling = Decimal(str(trial["authorized_spend_usd"]))
if not ceiling.is_finite() or ceiling <= 0:
raise ValueError("Positive provider spend ceiling required")
except (InvalidOperation, KeyError):
raise ValueError("Numeric provider spend ceiling required")
if (not isinstance(trial.get("case_ids"), list) or not trial["case_ids"] or
len(set(trial["case_ids"])) != len(trial["case_ids"]) or
trial.get("baseline_tier") not in ORDER):
raise ValueError("Freeze unique case IDs and a valid baseline tier")
for key in ("max_attempts_per_case_arm", "max_total_attempts"):
if type(trial.get(key)) is not int or trial[key] < 1:
raise ValueError("Positive frozen attempt limits required")
case_path = pathlib.Path(args.case).resolve()
case = load_json(case_path)
if case["case_id"] not in trial["case_ids"]:
raise ValueError("Case not in frozen trial")
if args.arm == "baseline" and args.escalate:
raise ValueError("Escalation belongs to candidate arm only")
base = case_path.parent
prompt = text_file(base, case["prompt_file"])
rubric = text_file(base, case["rubric_file"])
if not prompt.strip() or not rubric.strip():
raise ValueError("Real prompt and frozen rubric required")
candidate, minimum = route(config, case, args.escalate)
tier = candidate
if args.arm == "baseline":
tier = next(t for t in config["tiers"] if t["tier"] == trial["baseline_tier"])
if case["context_tokens"] + config["max_output_tokens_reserved"] > tier["max_context_tokens"]:
raise ValueError("Frozen baseline cannot fit this case")
plan = {
"case_id": case["case_id"], "arm": args.arm,
"trial_id": trial["id"], "config_revision": config["revision"],
"config_sha256": digest(args.config), "case_sha256": digest(case_path),
"features": {k: case[k] for k in ("complexity", "quality_sensitivity", "context_tokens", "data_class")},
"minimum_tier_index": minimum, "selected_tier": tier["tier"],
"requested_model": tier["model"],
"prompt_sha256": hashlib.sha256(prompt.encode()).hexdigest(),
"rubric_sha256": hashlib.sha256(rubric.encode()).hexdigest(),
"escalation_requested": args.escalate,
"configured_rates_usd_per_million": {
"input": tier.get("input_usd_per_million"),
"output": tier.get("output_usd_per_million")}
}
if args.action == "plan":
print(json.dumps(plan, indent=2))
return
if not args.out:
raise ValueError("Run requires a new --out receipt path")
out = pathlib.Path(args.out).resolve()
intent = reserve(out, plan, trial)
# Import only after a durable intent exists. The run sends the approved prompt to the model API.
from agents import Agent, ModelSettings, Runner, RunConfig
agent = Agent(name="Reviewed text step", model=tier["model"],
instructions="Answer the supplied authorized task. State uncertainty; do not invent missing evidence.",
model_settings=ModelSettings(timeout=30.0,
max_tokens=config["max_output_tokens_reserved"]))
started = time.monotonic()
try:
result = Runner.run_sync(agent, prompt, max_turns=1,
run_config=RunConfig(tracing_disabled=True))
except Exception as exc:
replace_receipt(out, {**intent, "status": "unknown",
"error_type": type(exc).__name__,
"observed_at_utc": datetime.now(timezone.utc).isoformat()})
raise
try:
usage = result.context_wrapper.usage
entries = []
for e in usage.request_usage_entries:
inp = getattr(e, "input_tokens_details", None)
outp = getattr(e, "output_tokens_details", None)
entries.append({"input_tokens": detail(getattr(e, "input_tokens", None)),
"output_tokens": detail(getattr(e, "output_tokens", None)),
"cached_input_tokens": detail(getattr(inp, "cached_tokens", None)),
"cache_write_tokens": detail(getattr(inp, "cache_write_tokens", None)),
"reasoning_output_tokens": detail(getattr(outp, "reasoning_tokens", None))})
record = {**intent, "status": "response_received",
"observed_at_utc": datetime.now(timezone.utc).isoformat(),
"elapsed_seconds": round(time.monotonic() - started, 3),
"answer": str(result.final_output),
"last_response_id": detail(getattr(result, "last_response_id", None)),
"raw_response_ids": [detail(getattr(r, "response_id", None))
for r in getattr(result, "raw_responses", [])],
"usage": {"requests": usage.requests, "input_tokens": usage.input_tokens,
"output_tokens": usage.output_tokens, "total_tokens": usage.total_tokens,
"per_request": entries},
"settled_billed_usd": "unknown"}
replace_receipt(out, record)
except Exception:
# The original intent remains if serialization or the atomic replace fails.
raise
print(str(out))
if __name__ == "__main__":
main()Plan both arms locally before any API call. Run these from the private project directory in either shell:
python route.py plan route-config.json cases/case-001.json --arm baseline
python route.py plan route-config.json cases/case-001.json --arm candidateCheck selected tier, exact model, hashes, data permission and context fit. These plan commands require no API key. Only after the owner authorizes this exact trial and the account settings are checked, run the baseline once with a new receipt. This command sends the approved prompt to the API and can incur charges.
PowerShell:
python route.py run route-config.json `
cases/case-001.json --arm baseline `
--out private/case-001-baseline-1.jsonPOSIX shell:
python route.py run route-config.json \
cases/case-001.json --arm baseline \
--out private/case-001-baseline-1.jsonReview the baseline answer against the frozen rubric and reconcile its usage and account charge. If the candidate attempt remains authorized, run it separately with a different new receipt. It also sends the prompt to the API and can incur charges.
PowerShell:
python route.py run route-config.json `
cases/case-001.json --arm candidate `
--out private/case-001-candidate-1.jsonPOSIX shell:
python route.py run route-config.json \
cases/case-001.json --arm candidate \
--out private/case-001-candidate-1.jsonReview that answer against the same frozen rubric and original sources. If the candidate fails and a higher tier is justified, record the failure and usage first. Only after separate human approval, run this one-step escalation; it is another paid API call.
PowerShell:
python route.py run route-config.json `
cases/case-001.json --arm candidate --escalate `
--out private/case-001-candidate-escalated-1.jsonPOSIX shell:
python route.py run route-config.json \
cases/case-001.json --arm candidate --escalate \
--out private/case-001-candidate-escalated-1.jsonRepeating --escalate picks the same tier, not a still higher one. The script does not initiate a second run by itself; inspect SDK/client transport retries and account usage. If run errors, an intent or unknown receipt requires provider usage and billing reconciliation before any further call; keep that attempt in trial totals. A response-received receipt still needs reviewer grading and settled billing.
3. Trial, monitor and change the route
Run the same frozen cases under the baseline and candidate arms with the same task instructions and reviewer. Maintain a private review table with case ID, config hash, attempt ID, response IDs if exposed, receipt hash, requested model, effective model if exposed, grade/reason/reviewer, tool charges, retries, elapsed time, input/output/cache/reasoning usage and settled account charge. The SDK's usage totals cover reported model calls, while provider transport retries or unsettled charges may require separate account reconciliation. Preserve unavailable fields as unknown. The rate fields in the config are reference inputs for a later owner calculation, not a bill or automatic estimate. Add outer planner, grader, tool, escalation and human rework costs to the full workflow comparison. Count every attempted and accepted outcome under identical criteria, including failures, refusals and uncertain calls.
Keep or change the deterministic thresholds only after the held-out cases and manual review show that the route meets the quality rule, data permissions, latency and budget. Version the config and rerun the same checks when models, prompts, task mix or prices change. Do not infer a universal saving from one provider's token table. The article's source-derived prose is limited to documentation facts; this route policy and code are an original proposed method, not a vendor-reported result.
This per-case route extends our earlier production model-choice worksheet, seven-role portfolio guide, two-model FAQ trial and fixed-choice routing evaluation. Those guides address related decisions; none supplies a measured outcome for this route.



