Python 88.3%
TypeScript 7.6%
Shell 4.1%
1#!/usr/bin/env python32"""Generate parameter + object fragments for the platform domain from the OpenAPI spec (+ curated overrides).3Writes generated/fragments/parameters/openai-{files,uploads,vector-stores,batch,fine-tuning,graders,evals}.json4and generated/fragments/objects/openai-platform-objects.json5"""6from __future__ import annotations7import json, sys8from pathlib import Path9ROOT = Path(__file__).resolve().parent.parent10sys.path.insert(0, str(ROOT / "tmp"))11import platform_extract as X # noqa: E402 (re-runs extraction, cheap)1213RETRIEVED = "2026-09-18"14REF = "https://developers.openai.com/api/reference/resources/"15SRC = {16 "files": REF + "files", "uploads": REF + "uploads", "vector_stores": REF + "vector_stores",17 "batches": REF + "batches", "fine_tuning": REF + "fine_tuning", "graders": REF + "graders", "evals": REF + "evals",18}19DEPRECATION = {20 "fine_tuning": ["DEPRECATED"], # self-serve fine-tuning winds down (Jan 6 2027 job creation cutoff)21 "graders": ["DEPRECATED"], # graders deprecated with evals + fine-tuning (Nov 30 2026 / Jan 6 2027)22 "evals": ["DEPRECATED"], # Evals API shuts down Nov 30 2026 (read-only Oct 31 2026)23}24FAMILY = { # api_family per path prefix25 "/files": "files", "/uploads": "uploads", "/vector_stores": "vector_stores", "/batches": "batches",26 "/fine_tuning/alpha/graders": "graders", "/fine_tuning": "fine_tuning", "/evals": "evals",27}28OUTNAME = {"files": "openai-files", "uploads": "openai-uploads", "vector_stores": "openai-vector-stores",29 "batches": "openai-batch", "fine_tuning": "openai-fine-tuning", "graders": "openai-graders", "evals": "openai-evals"}303132def family(path: str) -> str:33 for p, f in FAMILY.items():34 if path.startswith(p):35 return f36 raise KeyError(path)373839def norm_type(t):40 if t is None:41 return "object"42 return t434445rows_by_family: dict[str, list[dict]] = {k: [] for k in OUTNAME}46seen = set()47for key, op in X.summary.items():48 method, path = key.split(" ", 1)49 fam = family(path)50 ep = f"{method} /v1{path}"51 status = ["DOCUMENTED"] + DEPRECATION.get(fam, [])52 for p in op["params"]:53 rid = (ep, p["name"], p["in"])54 if rid in seen:55 continue56 seen.add(rid)57 rows_by_family[fam].append({58 "provider": "openai", "endpoint": ep, "parameter": p["name"], "location": p["in"],59 "type": norm_type(p["type"]), "required": bool(p["required"]), "default": p["default"],60 "minimum": None, "maximum": None, "enum": p["enum"], "description": p["description"].strip(),61 "compatible_models": [], "beta_header": None, "status": status, "source": SRC[fam],62 })63 for r in op.get("body_flat", []):64 rid = (ep, r["parameter"], "body", json.dumps(r.get("enum")), r.get("type"))65 if rid in seen:66 continue67 seen.add(rid)68 desc = r.get("description", "").strip()69 if r.get("x-ref"):70 desc = (desc + f" [schema: {r['x-ref']}]").strip()71 rows_by_family[fam].append({72 "provider": "openai", "endpoint": ep, "parameter": r["parameter"],73 "location": "body" if op["body_content_type"] != "multipart/form-data" else "body(multipart)",74 "type": norm_type(r.get("type")), "required": bool(r["required"]), "default": r.get("default"),75 "minimum": r.get("minimum"), "maximum": r.get("maximum"), "enum": r.get("enum"), "description": desc,76 "compatible_models": [], "beta_header": None, "status": status, "source": SRC[fam],77 })7879# ---- curated additions / corrections (facts from guides, not in the spec)80def add(fam, ep, param, loc, typ, req, desc, **kw):81 row = {"provider": "openai", "endpoint": ep, "parameter": param, "location": loc, "type": typ, "required": req,82 "default": kw.get("default"), "minimum": kw.get("minimum"), "maximum": kw.get("maximum"), "enum": kw.get("enum"),83 "description": desc, "compatible_models": kw.get("models", []), "beta_header": None,84 "status": kw.get("status", ["DOCUMENTED"] + DEPRECATION.get(fam, [])), "source": kw.get("source", SRC[fam])}85 rows_by_family[fam].append(row)8687add("files", "POST /v1/files", "file", "body(multipart)", "binary", True,88 "File bytes (multipart field). Max 512 MB per file; project storage cap 2.5 TB; upload endpoint rate limit 1,000 req/min per user. "89 "Batch inputs must be .jsonl <= 200 MB; fine-tune inputs must be .jsonl; vector-store ingestion needs a supported MIME type and <= 5M tokens/file.",90 source=REF + "files/methods/create", status=["DOCUMENTED", "LIVE_VERIFIED"])91add("files", "POST /v1/files", "purpose", "body(multipart)", "string", True,92 "Intended purpose. `evals` is accepted by the API (used by the Evals guide) although the OpenAPI enum only lists assistants|batch|fine-tune|vision|user_data|evals; "93 "response-side purposes also include assistants_output, batch_output, fine-tune-results. Files with purpose=batch expire after 30 days by default.",94 enum=["assistants", "batch", "fine-tune", "vision", "user_data", "evals"], source=REF + "files/methods/create", status=["DOCUMENTED", "LIVE_VERIFIED"])95add("vector_stores", "POST /v1/vector_stores/{vector_store_id}/files", "attributes.<key>", "body", "string | number | boolean", False,96 "Attribute map used by search filters: at most 16 keys, each key and string value <= 256 characters (Retrieval guide).",97 maximum=16, source="https://developers.openai.com/api/docs/guides/retrieval#attributes")98add("vector_stores", "POST /v1/vector_stores/{vector_store_id}/search", "ranking_options.hybrid_search.embedding_weight", "body", "number", False,99 "Reciprocal-rank-fusion weight for semantic (embedding) matches (alias rrf_embedding_weight). At least one of the two weights must be > 0. Documented in the Retrieval guide only (not in the OpenAPI spec).",100 source="https://developers.openai.com/api/docs/guides/retrieval#ranking", status=["DOCUMENTED", "UNVERIFIED"])101add("vector_stores", "POST /v1/vector_stores/{vector_store_id}/search", "ranking_options.hybrid_search.text_weight", "body", "number", False,102 "Reciprocal-rank-fusion weight for sparse keyword matches (alias rrf_text_weight). Documented in the Retrieval guide only.",103 source="https://developers.openai.com/api/docs/guides/retrieval#ranking", status=["DOCUMENTED", "UNVERIFIED"])104add("fine_tuning", "POST /v1/fine_tuning/jobs", "method.reinforcement.response_format", "body", "object", False,105 "Structured-output format applied to samples during RFT training ({type: json_schema, json_schema: {name, strict, schema}}); used by the RFT guide, "106 "populates sample.output_json for graders. Present in guide/reference examples; not in the FineTuneReinforcementMethod spec properties.",107 source="https://developers.openai.com/api/docs/guides/reinforcement-fine-tuning", status=["DOCUMENTED", "UNVERIFIED", "DEPRECATED"])108add("fine_tuning", "POST /v1/fine_tuning/jobs", "method.dpo.hyperparameters.beta", "body", "number | 'auto'", False,109 "DPO only. Float in [0, 2]: higher = more conservative (stick to reference behaviour), lower = follow the preferences more aggressively. Default auto.",110 default="auto", minimum=0, maximum=2, source="https://developers.openai.com/api/docs/guides/direct-preference-optimization")111add("fine_tuning", "POST /v1/fine_tuning/jobs", "model", "body", "string", True,112 "Base model or previously fine-tuned model id. Per model pages (2026-09-18) fine-tuning is 'Supported' for: gpt-4.1, gpt-4.1-mini, gpt-4.1-nano, gpt-4o, gpt-4o-mini, o4-mini (RFT), gpt-4, gpt-3.5-turbo (legacy). "113 "Guides pin snapshots: SFT/DPO -> gpt-4.1-2025-04-14 / -mini / -nano; vision SFT -> gpt-4o-2024-08-06; RFT -> o4-mini-2025-04-16. No gpt-5.x model supports fine-tuning.",114 models=["gpt-4.1-2025-04-14", "gpt-4.1-mini-2025-04-14", "gpt-4.1-nano-2025-04-14", "gpt-4o-2024-08-06", "gpt-4o-mini-2024-07-18", "o4-mini-2025-04-16", "gpt-4", "gpt-3.5-turbo"],115 source="https://developers.openai.com/api/docs/guides/model-optimization#fine-tuning-methods")116# training-file line formats (documented as pseudo-parameters of the training file)117add("fine_tuning", "training_file (JSONL line, method=supervised)", "messages[]", "file", "array<message>", True,118 "Chat-format example: system/developer, user, assistant, tool messages; assistant messages may carry tool_calls and `weight` (0|1) to exclude a turn from the loss. Optional top-level `tools[]`, `parallel_tool_calls`, `functions[]`(legacy). Min 10 lines.",119 source="https://developers.openai.com/api/docs/guides/supervised-fine-tuning#formatting-your-data")120add("fine_tuning", "training_file (JSONL line, method=supervised)", "messages[].weight", "file", "integer", False,121 "Assistant messages only. 0 = do not train on this message, 1 = train (default).", enum=[0, 1], source=REF + "fine_tuning")122add("fine_tuning", "training_file (JSONL line, method=dpo)", "input.messages[]", "file", "array<message>", True,123 "Prompt messages (one-turn conversations only). Optional input.tools[], input.parallel_tool_calls.",124 source="https://developers.openai.com/api/docs/guides/direct-preference-optimization#data-format")125add("fine_tuning", "training_file (JSONL line, method=dpo)", "preferred_output[]", "file", "array<assistant message>", True,126 "Ideal assistant response (must be the last assistant message).", source="https://developers.openai.com/api/docs/guides/direct-preference-optimization#data-format")127add("fine_tuning", "training_file (JSONL line, method=dpo)", "non_preferred_output[]", "file", "array<assistant message>", True,128 "Suboptimal assistant response.", source="https://developers.openai.com/api/docs/guides/direct-preference-optimization#data-format")129add("fine_tuning", "training_file (JSONL line, method=reinforcement)", "messages[]", "file", "array<message>", True,130 "Prompt messages; every other top-level key of the line is exposed to the grader as `item.<key>` (e.g. reference_answer). No assistant answer is required.",131 source="https://developers.openai.com/api/docs/guides/reinforcement-fine-tuning#prepare-your-dataset")132add("fine_tuning", "training_file (JSONL line, vision SFT)", "messages[].content[].image_url", "file", "object", False,133 "Image inputs as HTTP URL or data URL; JPEG/PNG/WEBP, RGB/RGBA, <= 10 MB each, <= 10 images per example, <= 50,000 image examples per file; `detail: low` -> 85 tokens/image. No images in assistant messages.",134 source="https://developers.openai.com/api/docs/guides/vision-fine-tuning#image-data-requirements")135add("batches", "input_file (JSONL line)", "custom_id", "file", "string", True, "Unique per line; echoed in the output/error lines (output order is not guaranteed).",136 source="https://developers.openai.com/api/docs/guides/batch#1-prepare-your-batch-file", status=["DOCUMENTED", "LIVE_VERIFIED"])137add("batches", "input_file (JSONL line)", "method", "file", "string", True, "Always POST.", enum=["POST"],138 source="https://developers.openai.com/api/docs/guides/batch#1-prepare-your-batch-file", status=["DOCUMENTED", "LIVE_VERIFIED"])139add("batches", "input_file (JSONL line)", "url", "file", "string", True, "Must equal the batch `endpoint`; all lines target one endpoint and one model.",140 enum=["/v1/responses", "/v1/chat/completions", "/v1/embeddings", "/v1/completions", "/v1/moderations", "/v1/images/generations", "/v1/images/edits", "/v1/videos"],141 source="https://developers.openai.com/api/docs/guides/batch#1-prepare-your-batch-file", status=["DOCUMENTED", "LIVE_VERIFIED"])142add("batches", "input_file (JSONL line)", "body", "file", "object", True, "Same JSON body as the synchronous endpoint (stream must be false/absent; videos/images must be JSON not multipart, assets referenced by file_id/image_url).",143 source="https://developers.openai.com/api/docs/guides/batch#1-prepare-your-batch-file", status=["DOCUMENTED", "LIVE_VERIFIED"])144145for fam, rows in rows_by_family.items():146 out = ROOT / "generated/fragments/parameters" / f"{OUTNAME[fam]}.json"147 out.parent.mkdir(parents=True, exist_ok=True)148 out.write_text(json.dumps(rows, indent=1, ensure_ascii=False) + "\n")149 print(out.name, len(rows))150151# ---------------------------------------------------------------- objects152OBJECTS = [153 ("File", "OpenAIFile", "files", "file"), ("Upload", "Upload", "uploads", "upload"), ("UploadPart", "UploadPart", "uploads", "upload.part"),154 ("VectorStore", "VectorStoreObject", "vector_stores", "vector_store"), ("VectorStoreFile", "VectorStoreFileObject", "vector_stores", "vector_store.file"),155 ("VectorStoreFileBatch", "VectorStoreFileBatchObject", "vector_stores", "vector_store.files_batch"),156 ("VectorStoreSearchResultsPage", "VectorStoreSearchResultsPage", "vector_stores", "vector_store.search_results.page"),157 ("VectorStoreFileContentPage", "VectorStoreFileContentResponse", "vector_stores", "vector_store.file_content.page"),158 ("Batch", "Batch", "batches", "batch"), ("BatchRequestCounts", "BatchRequestCounts", "batches", None), ("BatchError", "BatchError", "batches", None),159 ("FineTuningJob", "FineTuningJob", "fine_tuning", "fine_tuning.job"), ("FineTuningJobEvent", "FineTuningJobEvent", "fine_tuning", "fine_tuning.job.event"),160 ("FineTuningJobCheckpoint", "FineTuningJobCheckpoint", "fine_tuning", "fine_tuning.job.checkpoint"),161 ("CheckpointPermission", "FineTuningCheckpointPermission", "fine_tuning", "checkpoint.permission"),162 ("GraderStringCheck", "GraderStringCheck", "graders", None), ("GraderTextSimilarity", "GraderTextSimilarity", "graders", None),163 ("GraderScoreModel", "GraderScoreModel", "graders", None), ("GraderLabelModel", "GraderLabelModel", "graders", None),164 ("GraderPython", "GraderPython", "graders", None), ("GraderMulti", "GraderMulti", "graders", None),165 ("RunGraderResponse", "RunGraderResponse", "graders", None), ("ValidateGraderResponse", "ValidateGraderResponse", "graders", None),166 ("Eval", "Eval", "evals", "eval"), ("EvalRun", "EvalRun", "evals", "eval.run"), ("EvalRunOutputItem", "EvalRunOutputItem", "evals", "eval.run.output_item"),167 ("EvalRunOutputItemResult", "EvalRunOutputItemResult", "evals", None), ("EvalApiError", "EvalApiError", "evals", None),168 ("ListFilesResponse", "ListFilesResponse", "files", "list"), ("ListBatchesResponse", "ListBatchesResponse", "batches", "list"),169 ("EvalList", "EvalList", "evals", "list"), ("EvalRunList", "EvalRunList", "evals", "list"), ("EvalRunOutputItemList", "EvalRunOutputItemList", "evals", "list"),170 ("ComparisonFilter", "ComparisonFilter", "vector_stores", None), ("CompoundFilter", "CompoundFilter", "vector_stores", None),171 ("StaticChunkingStrategy", "StaticChunkingStrategy", "vector_stores", None), ("VectorStoreExpirationAfter", "VectorStoreExpirationAfter", "vector_stores", None),172 ("FileExpirationAfter", "FileExpirationAfter", "files", None), ("BatchFileExpirationAfter", "BatchFileExpirationAfter", "batches", None),173 ("FineTuneMethod", "FineTuneMethod", "fine_tuning", None), ("FineTuneSupervisedHyperparameters", "FineTuneSupervisedHyperparameters", "fine_tuning", None),174 ("FineTuneDPOHyperparameters", "FineTuneDPOHyperparameters", "fine_tuning", None), ("FineTuneReinforcementHyperparameters", "FineTuneReinforcementHyperparameters", "fine_tuning", None),175 ("FineTuneChatCompletionRequestAssistantMessage", "FineTuneChatCompletionRequestAssistantMessage", "fine_tuning", None),176 ("EvalCustomDataSourceConfig", "EvalCustomDataSourceConfig", "evals", None), ("EvalLogsDataSourceConfig", "EvalLogsDataSourceConfig", "evals", None),177 ("EvalStoredCompletionsDataSourceConfig", "EvalStoredCompletionsDataSourceConfig", "evals", None),178 ("EvalJsonlFileContentSource", "EvalJsonlFileContentSource", "evals", None), ("EvalJsonlFileIdSource", "EvalJsonlFileIdSource", "evals", None),179 ("EvalStoredCompletionsSource", "EvalStoredCompletionsSource", "evals", None), ("EvalResponsesSource", "EvalResponsesSource", "evals", None),180]181objs = []182for name, schema_name, fam, obj_type in OBJECTS:183 sch = X.schemas.get(schema_name)184 if sch is None:185 print("missing schema", schema_name); continue186 resolved = X.deref(sch)187 flat = X.flatten(resolved)188 fields = []189 for r in flat:190 if r["parameter"].count(".") > 3:191 continue192 fields.append({k: r.get(k) for k in ("parameter", "type", "required", "enum", "default", "minimum", "maximum", "nullable") if r.get(k) not in (None, False, "")} |193 {"parameter": r["parameter"], "type": r.get("type") or "object", "description": (r.get("description") or "")[:300].strip()})194 objs.append({195 "provider": "openai", "api_family": fam, "name": name, "spec_schema": schema_name, "object_type": obj_type,196 "description": (resolved.get("description") or "").strip()[:500], "required": resolved.get("required") or [],197 "fields": fields, "status": ["DOCUMENTED"] + DEPRECATION.get(fam, []), "verification": {"method": "docs_only"},198 "sources": [{"url": SRC[fam], "retrieved_at": RETRIEVED}, {"url": "https://developers.openai.com/api/openapi (openapi-master.yaml)", "retrieved_at": RETRIEVED}],199 })200# pseudo-objects for JSONL lines (not named in the spec)201objs.append({202 "provider": "openai", "api_family": "batches", "name": "BatchRequestInputLine", "spec_schema": None, "object_type": None,203 "description": "One line of the batch input JSONL file.", "required": ["custom_id", "method", "url", "body"],204 "fields": [{"parameter": "custom_id", "type": "string", "required": True, "description": "Unique id per line, echoed in output."},205 {"parameter": "method", "type": "string", "required": True, "enum": ["POST"], "description": "HTTP method."},206 {"parameter": "url", "type": "string", "required": True, "description": "Target endpoint path; must match batch.endpoint."},207 {"parameter": "body", "type": "object", "required": True, "description": "Request body of the target endpoint."}],208 "status": ["DOCUMENTED"], "verification": {"method": "docs_only"},209 "sources": [{"url": "https://developers.openai.com/api/docs/guides/batch#1-prepare-your-batch-file", "retrieved_at": RETRIEVED}],210})211objs.append({212 "provider": "openai", "api_family": "batches", "name": "BatchRequestOutputLine", "spec_schema": None, "object_type": None,213 "description": "One line of the batch output (output_file_id) or error (error_file_id) JSONL file. Exactly one of response/error is non-null.",214 "required": ["id", "custom_id", "response", "error"],215 "fields": [{"parameter": "id", "type": "string", "required": True, "description": "batch_req_… id."},216 {"parameter": "custom_id", "type": "string", "required": True, "description": "Echo of the input custom_id."},217 {"parameter": "response", "type": "object | null", "required": True, "description": "{status_code, request_id, body} — body is the normal endpoint response."},218 {"parameter": "response.status_code", "type": "integer", "required": True, "description": "HTTP status of the individual request."},219 {"parameter": "response.request_id", "type": "string", "required": True, "description": "req_… id usable with support."},220 {"parameter": "response.body", "type": "object", "required": True, "description": "Endpoint response object (e.g. Response, ChatCompletion, embeddings list)."},221 {"parameter": "error", "type": "object | null", "required": True, "description": "{code, message}; e.g. code=batch_expired for requests cancelled at the 24h window."}],222 "status": ["DOCUMENTED"], "verification": {"method": "docs_only"},223 "sources": [{"url": "https://developers.openai.com/api/docs/guides/batch#5-retrieve-the-results", "retrieved_at": RETRIEVED}],224})225out = ROOT / "generated/fragments/objects/openai-platform-objects.json"226out.parent.mkdir(parents=True, exist_ok=True)227out.write_text(json.dumps(objs, indent=1, ensure_ascii=False) + "\n")228print(out.name, len(objs))229