mirror of
https://github.com/wassname/moral-maps.git
synced 2026-09-21 13:10:52 +08:00
Co-Authored-By: PI[gpt-5.6-terra] <288921227+claudypoo@users.noreply.github.com>
280 lines
14 KiB
Python
280 lines
14 KiB
Python
#!/usr/bin/env python3
|
|
"""Prepare or run one preregistered direct-choice WVS priority panel."""
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import hashlib
|
|
import json
|
|
from datetime import UTC, datetime
|
|
from decimal import Decimal
|
|
from pathlib import Path
|
|
|
|
from moralmaps.read_direct_choice import direct_choice_protocol_identity, read_items_direct_choice
|
|
from wvs_direct_choice_pilot import usage_cost
|
|
from wvs_direct_choice_production_pilot import (
|
|
ANSWER_INSTRUCTION,
|
|
CONCURRENCY,
|
|
MAX_TOKENS,
|
|
PROMPT_INSTRUCTION,
|
|
REQUEST_TIMEOUT,
|
|
RESCUE_INSTRUCTION,
|
|
TEMPERATURE,
|
|
TOTAL_SAMPLES_PER_ITEM,
|
|
items,
|
|
schedule,
|
|
)
|
|
|
|
CATALOG_PATH = Path("slop/research/wvs/20260917_openrouter_models.json")
|
|
MANIFEST_PATH = Path("slop/research/wvs/20260917_direct_choice/priority_direct_choice_manifest.md")
|
|
MANIFEST_JSON_PATH = Path("slop/research/wvs/20260917_direct_choice/priority_direct_choice_manifest.json")
|
|
DIRECT_DIR = Path("slop/research/wvs/20260917_direct_choice/priority")
|
|
RATED_LEDGER = Path("slop/research/wvs/20260916_openrouter/wvs_iw_requests.jsonl")
|
|
PHASE_STOP_USD = Decimal("35")
|
|
GLOBAL_STOP_USD = Decimal("80")
|
|
PROMPT_TOKEN_RESERVE = Decimal("512")
|
|
|
|
GROUPS = {
|
|
"Grok": ("x-ai/grok-4.6", "x-ai/grok-4.5"),
|
|
"OpenAI": (
|
|
"openai/gpt-5.6-luna", "openai/gpt-5.6-terra", "openai/gpt-5.4-nano",
|
|
"openai/gpt-5.4-mini", "openai/gpt-5.2-chat", "openai/gpt-5.2", "openai/gpt-5.1",
|
|
"openai/gpt-5", "openai/gpt-5-mini", "openai/gpt-oss-120b", "openai/gpt-oss-20b",
|
|
"openai/o3", "openai/o4-mini", "openai/gpt-4.1", "openai/gpt-4.1-mini",
|
|
"openai/gpt-4.1-nano", "openai/o3-mini",
|
|
"openai/gpt-4o-2024-11-20", "openai/gpt-4o-2024-08-06", "openai/gpt-4o-mini",
|
|
"openai/gpt-4o", "openai/gpt-3.5-turbo-0613", "openai/gpt-3.5-turbo-instruct",
|
|
"openai/gpt-3.5-turbo-16k", "openai/gpt-3.5-turbo",
|
|
),
|
|
"Google": (
|
|
"google/gemini-3.8-flash", "google/gemini-3.6-flash", "google/gemini-3.5-flash-lite",
|
|
"google/gemini-3.5-flash", "google/gemini-3.1-flash-lite",
|
|
"google/gemini-3.1-flash-lite-preview", "google/gemini-3-flash-preview",
|
|
"google/gemini-2.5-flash-lite", "google/gemini-2.5-flash",
|
|
),
|
|
"Muse": ("meta/muse-spark-1.2", "meta/muse-spark-1.1"),
|
|
}
|
|
|
|
|
|
def utc_date(timestamp: int) -> str:
|
|
return datetime.fromtimestamp(timestamp, UTC).date().isoformat()
|
|
|
|
|
|
def rate_per_million(model: dict, field: str) -> Decimal:
|
|
return Decimal(model["pricing"][field]) * 1_000_000
|
|
|
|
|
|
def reasoning_setting(model: dict) -> tuple[dict | None, str]:
|
|
metadata = model.get("reasoning")
|
|
if metadata is None:
|
|
return None, "not advertised"
|
|
efforts = set(metadata.get("supported_efforts", []))
|
|
optional = not metadata.get("mandatory")
|
|
if optional and "none" in efforts:
|
|
return {"effort": "none"}, "disabled (optional, none advertised)"
|
|
if optional and not efforts and "reasoning" in model["supported_parameters"]:
|
|
return {"enabled": False}, "unverified compatibility probe (optional reasoning parameter; no efforts advertised)"
|
|
if "minimal" in efforts:
|
|
return {"effort": "minimal"}, "minimal"
|
|
if "low" in efforts:
|
|
return {"effort": "low"}, "low"
|
|
if optional and not efforts:
|
|
return None, "not advertised (optional; omitted)"
|
|
raise ValueError(f"no allowed minimal/low reasoning setting for {model['id']}: {metadata}")
|
|
|
|
|
|
def catalog() -> dict[str, dict]:
|
|
return {model["id"]: model for model in json.loads(CATALOG_PATH.read_text())["data"]}
|
|
|
|
|
|
def cache_paths(model_id: str) -> tuple[Path, Path]:
|
|
stem = model_id.replace("/", "__")
|
|
return DIRECT_DIR / f"{stem}_requests.jsonl", DIRECT_DIR / f"{stem}_cache.json"
|
|
|
|
|
|
def observed_cost() -> Decimal:
|
|
paths = [RATED_LEDGER, *Path("slop/research/wvs/20260917_direct_choice").glob("**/*requests.jsonl")]
|
|
return sum((usage_cost(path) for path in paths), Decimal())
|
|
|
|
|
|
def entry(model: dict, pilot_items: list[dict], request_plan: list[dict]) -> dict:
|
|
reasoning, reasoning_label = reasoning_setting(model)
|
|
protocol = direct_choice_protocol_identity(
|
|
model["id"], pilot_items, samples_per_order=10, temperature=TEMPERATURE,
|
|
max_tokens=MAX_TOKENS, concurrency=CONCURRENCY, request_timeout=REQUEST_TIMEOUT,
|
|
reasoning=reasoning, structured_output=True, prompt_instruction=PROMPT_INSTRUCTION,
|
|
answer_instruction=ANSWER_INSTRUCTION, rescue_instruction=RESCUE_INSTRUCTION,
|
|
plan_override=request_plan, fail_fast_first_request=True,
|
|
)
|
|
input_rate = rate_per_million(model, "prompt")
|
|
output_rate = rate_per_million(model, "completion")
|
|
completion_ceiling = output_rate * len(request_plan) * MAX_TOKENS / 1_000_000
|
|
conservative_reserve = (
|
|
len(request_plan)
|
|
* (PROMPT_TOKEN_RESERVE * 2 * input_rate + (MAX_TOKENS + 2048) * output_rate)
|
|
/ 1_000_000
|
|
)
|
|
ledger, cache = cache_paths(model["id"])
|
|
return {
|
|
"id": model["id"], "created_utc": utc_date(model["created"]),
|
|
"input_usd_per_million": str(input_rate), "output_usd_per_million": str(output_rate),
|
|
"reasoning": reasoning, "reasoning_label": reasoning_label,
|
|
"structured_output": "structured_outputs" in model["supported_parameters"],
|
|
"protocol_id": protocol, "initial_calls": len(request_plan),
|
|
"completion_only_ceiling_usd": str(completion_ceiling),
|
|
"conservative_reserve_usd": str(conservative_reserve),
|
|
"records_path": str(ledger), "cache_path": str(cache),
|
|
}
|
|
|
|
|
|
def entries() -> list[dict]:
|
|
models = catalog()
|
|
pilot_items = items()
|
|
request_plan = schedule(pilot_items)
|
|
assert len(request_plan) == 240
|
|
output = []
|
|
for group, ids in GROUPS.items():
|
|
for model_id in ids:
|
|
model = models[model_id]
|
|
assert "structured_outputs" in model["supported_parameters"]
|
|
assert rate_per_million(model, "completion") <= Decimal("15")
|
|
output.append({"group": group, **entry(model, pilot_items, request_plan)})
|
|
assert len({row["id"] for row in output}) == len(output)
|
|
assert len({row["protocol_id"] for row in output}) == len(output)
|
|
return output
|
|
|
|
|
|
def write_manifest(priority: list[dict]) -> None:
|
|
catalog_sha = hashlib.sha256(CATALOG_PATH.read_bytes()).hexdigest()
|
|
current_cost = observed_cost()
|
|
manifest = {
|
|
"schema": 1,
|
|
"catalog_path": str(CATALOG_PATH),
|
|
"catalog_sha256": catalog_sha,
|
|
"design": {
|
|
"construct": "direct_choice", "items": 12, "samples_per_item": TOTAL_SAMPLES_PER_ITEM,
|
|
"initial_calls_per_model": 240, "schedule": "balanced_cyclic_rotations",
|
|
"prompt_instruction": PROMPT_INSTRUCTION, "answer_instruction": ANSWER_INSTRUCTION,
|
|
"rescue_instruction": RESCUE_INSTRUCTION, "strict_structured_output": True,
|
|
"fail_fast_first_request": True,
|
|
},
|
|
"stop_usd": {"priority_phase": str(PHASE_STOP_USD), "global": str(GLOBAL_STOP_USD)},
|
|
"current_observed_cost_usd": str(current_cost),
|
|
"prompt_token_reserve_per_phase": str(PROMPT_TOKEN_RESERVE),
|
|
"models": priority,
|
|
}
|
|
MANIFEST_JSON_PATH.parent.mkdir(parents=True, exist_ok=True)
|
|
MANIFEST_JSON_PATH.write_text(json.dumps(manifest, indent=2, sort_keys=True) + "\n")
|
|
lines = [
|
|
"# Direct-choice priority manifest, prepared but not dispatched",
|
|
"",
|
|
"This manifest prepares the reviewed direct-choice protocol for future panels. It queues and authorizes no API request. Dense-rated panels remain a separate legacy/proxy layer and cannot be mixed with these outputs in coordinates, family summaries, or capability fits.",
|
|
"",
|
|
"## Shared direct-choice identity",
|
|
"",
|
|
f"- saved catalog: `{CATALOG_PATH}`, SHA-256 `{catalog_sha}`",
|
|
"- 12 WVS items x 20 samples/item = 240 initial requests/model",
|
|
"- deterministic balanced cyclic rotations: exact option-position balance for n=2,4,10 and registered nearest 6/7 balance for n=3",
|
|
f"- prompt: `{PROMPT_INSTRUCTION}`",
|
|
f"- final response: `{ANSWER_INSTRUCTION}`",
|
|
f"- rescue response: `{RESCUE_INSTRUCTION}`",
|
|
"- strict structured output; each model has an isolated append-only ledger, cache, and model-specific protocol ID",
|
|
"- compatibility probe: run scheduled sample 0 first; a configuration/request failure or a final parse-invalid response after rescue records a failed run and exits before the other 239 requests",
|
|
"",
|
|
"## Spend checks before any later dispatch",
|
|
"",
|
|
f"- observed provider cost across current rated and direct-choice ledgers: USD {current_cost:.11f}",
|
|
f"- priority phase hard stop: USD {PHASE_STOP_USD}; global hard stop: USD {GLOBAL_STOP_USD}",
|
|
f"- per-model reserve assumes 240 initial 1024-token completions plus 240 possible 2048-token rescues and {PROMPT_TOKEN_RESERVE} prompt tokens per phase; it is a pre-dispatch limit, not an observed cost",
|
|
"- the runner refuses a new model if current observed ledger cost plus its reserve reaches either stop",
|
|
"- no model below is dispatched by this commit",
|
|
"",
|
|
"## Ordered panels",
|
|
"",
|
|
"The order is Grok, OpenAI, Google, then Muse. Optional entries advertising `none` send `reasoning.effort=none`, as documented by OpenRouter. Otherwise `minimal` is used when advertised, then `low`. Optional metadata with no effort list uses an explicitly labelled, unverified `enabled:false` compatibility probe only when the `reasoning` parameter itself is advertised; models with no reasoning metadata omit the field.",
|
|
"- source for `effort=none` and mandatory-model rejection: <https://openrouter.ai/docs/guides/best-practices/reasoning-tokens>, fetched 2026-09-17; the saved catalog's `supported_efforts` remains the exact per-model source.",
|
|
"",
|
|
"| family | exact ID | created UTC | input USD/M | output USD/M | reasoning | structured | protocol ID | calls | completion-only ceiling | conservative reserve | isolated ledger |",
|
|
"|---|---|---:|---:|---:|---|---|---|---:|---:|---:|---|",
|
|
]
|
|
for row in priority:
|
|
lines.append(
|
|
f"| {row['group']} | `{row['id']}` | {row['created_utc']} | {Decimal(row['input_usd_per_million']):g} | "
|
|
f"{Decimal(row['output_usd_per_million']):g} | `{json.dumps(row['reasoning'])}` ({row['reasoning_label']}) | "
|
|
f"{'yes' if row['structured_output'] else 'no'} | `{row['protocol_id']}` | {row['initial_calls']} | "
|
|
f"USD {Decimal(row['completion_only_ceiling_usd']):.4f} | USD {Decimal(row['conservative_reserve_usd']):.4f} | `{row['records_path']}` |"
|
|
)
|
|
lines.extend([
|
|
"",
|
|
"## Exclusions",
|
|
"",
|
|
"- Already plotted dense-rated IDs are not repeated in this prepared direct-choice list, including Grok 4.3/4.20, GPT-6 Astra, GPT-5.6 Sol, GPT-5.5, GPT-5.4, GPT-5.3 Chat, Gemini 3.7 Flash, Gemini 2.5 Pro, and Muse 1.3.",
|
|
"- GPT-5 Nano is retained as a completed dense-rated protocol diagnostic, not silently relabelled as a direct-choice panel.",
|
|
"- Pro/Fast, batch/free aliases, output price above USD 15/M, and code/image/audio/safeguard/multi-agent entries remain excluded. `Flash` is included where it is a general chat model.",
|
|
"- `google/gemma-4-26b-a4b-it` is excluded: it is Gemma, not an identified member of the requested Gemini release series.",
|
|
"- `openai/o4-mini-high` and `openai/o3-mini-high` are excluded because their catalog entries advertise only `high` reasoning, not the registered minimal/low policy.",
|
|
"- The deferred Qwen/GLM/Mistral shortlist remains outside this priority manifest until a direct-choice expansion decision is made.",
|
|
"",
|
|
"## Later execution only after review",
|
|
"",
|
|
"`scripts/wvs_direct_choice_priority.py --model <exact-id> --smoke` validates one saved entry without network requests. The corresponding `--run` is intentionally not invoked or queued here; it requires a reviewed manifest match and the spend checks above.",
|
|
"",
|
|
"-- PI[gpt-5.6-terra]",
|
|
"",
|
|
])
|
|
MANIFEST_PATH.write_text("\n".join(lines))
|
|
|
|
|
|
def preflight(model_id: str) -> dict:
|
|
priority = {row["id"]: row for row in entries()}
|
|
row = priority[model_id]
|
|
saved = json.loads(MANIFEST_JSON_PATH.read_text())
|
|
saved_row = next(entry for entry in saved["models"] if entry["id"] == model_id)
|
|
assert saved_row == row
|
|
assert saved["catalog_sha256"] == hashlib.sha256(CATALOG_PATH.read_bytes()).hexdigest()
|
|
current_cost = observed_cost()
|
|
reserve = Decimal(row["conservative_reserve_usd"])
|
|
assert current_cost + reserve < PHASE_STOP_USD
|
|
assert current_cost + reserve < GLOBAL_STOP_USD
|
|
return row
|
|
|
|
|
|
def main() -> None:
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument("--write-manifest", action="store_true")
|
|
parser.add_argument("--model", choices=[model_id for ids in GROUPS.values() for model_id in ids])
|
|
parser.add_argument("--smoke", action="store_true")
|
|
parser.add_argument("--run", action="store_true", help="make paid calls only after a separate review")
|
|
args = parser.parse_args()
|
|
if args.write_manifest:
|
|
write_manifest(entries())
|
|
print(f"wrote {MANIFEST_PATH} and {MANIFEST_JSON_PATH}")
|
|
if args.model is None:
|
|
assert not args.smoke and not args.run
|
|
return
|
|
row = preflight(args.model)
|
|
if args.smoke:
|
|
print(f"smoke: {row['id']}, 240 direct-choice requests, protocol={row['protocol_id']}")
|
|
print(f"smoke: reasoning={row['reasoning']}, reserve=USD {row['conservative_reserve_usd']}")
|
|
if not args.run:
|
|
return
|
|
request_plan = schedule(items())
|
|
records_path, cache_path = cache_paths(args.model)
|
|
result = read_items_direct_choice(
|
|
args.model, items(), samples_per_order=10, temperature=TEMPERATURE, max_tokens=MAX_TOKENS,
|
|
concurrency=CONCURRENCY, request_timeout=REQUEST_TIMEOUT, reasoning=row["reasoning"],
|
|
structured_output=True, records_path=records_path, cache_path=cache_path,
|
|
prompt_instruction=PROMPT_INSTRUCTION, answer_instruction=ANSWER_INSTRUCTION,
|
|
rescue_instruction=RESCUE_INSTRUCTION, plan_override=request_plan,
|
|
fail_fast_first_request=True,
|
|
)
|
|
if result["cached"]:
|
|
print(f"priority direct-choice cache hit: {args.model}, protocol={result['protocol_id'][:12]}")
|
|
return
|
|
if not result["complete"]:
|
|
raise RuntimeError(f"incomplete priority direct-choice panel: {result['run_id']}; evidence is {records_path}")
|
|
print(f"complete priority direct-choice panel: {args.model}, run={result['run_id']}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|