#!/usr/bin/env python3 """Dump the OpenAPI paths + resolved schemas for the platform domain into tmp/platform-spec/. Usage: python3 tmp/platform_extract.py """ import json, re, sys, yaml from pathlib import Path ROOT = Path(__file__).resolve().parent.parent SPEC = ROOT / "sources/openai/openapi/openapi-master.yaml" OUT = ROOT / "tmp/platform-spec" OUT.mkdir(parents=True, exist_ok=True) spec = yaml.safe_load(SPEC.read_text()) schemas = spec["components"]["schemas"] PREFIXES = ("/files", "/uploads", "/vector_stores", "/batches", "/fine_tuning", "/evals") ops = {} for path, item in spec["paths"].items(): if not path.startswith(PREFIXES): continue for method, op in item.items(): if method not in ("get", "post", "delete", "patch", "put"): continue ops[f"{method.upper()} {path}"] = op def deref(node, depth=0, seen=None): """Resolve $ref recursively, keep names in 'x-ref'.""" seen = seen or set() if isinstance(node, dict): if "$ref" in node: name = node["$ref"].split("/")[-1] if name in seen or depth > 12: return {"x-ref": name} sub = deref(schemas[name], depth + 1, seen | {name}) if isinstance(sub, dict): sub = {"x-ref": name, **sub} return sub return {k: deref(v, depth + 1, seen) for k, v in node.items()} if isinstance(node, list): return [deref(v, depth + 1, seen) for v in node] return node def flatten(schema, prefix="", out=None, required_parent=None, depth=0): """Flatten a resolved schema into dotted parameter rows.""" out = out if out is not None else [] if not isinstance(schema, dict) or depth > 10: return out for comb in ("oneOf", "anyOf", "allOf"): if comb in schema: for alt in schema[comb]: flatten(alt, prefix, out, required_parent, depth + 1) props = schema.get("properties", {}) req = set(schema.get("required", [])) for name, sub in props.items(): p = f"{prefix}{name}" typ = sub.get("type") if not typ and ("oneOf" in sub or "anyOf" in sub): alts = sub.get("oneOf") or sub.get("anyOf") typ = " | ".join(str(a.get("type") or a.get("x-ref") or "object") for a in alts) if typ == "array": it = sub.get("items", {}) typ = f"array<{it.get('type') or it.get('x-ref') or 'object'}>" row = { "parameter": p, "type": typ, "required": name in req, "default": sub.get("default"), "minimum": sub.get("minimum"), "maximum": sub.get("maximum"), "enum": sub.get("enum"), "description": (sub.get("description") or "")[:600], "nullable": sub.get("nullable"), "x-ref": sub.get("x-ref"), } out.append({k: v for k, v in row.items() if v not in (None, False, "") or k in ("parameter", "type", "required")}) # nested if sub.get("type") == "object" or "properties" in sub or "oneOf" in sub or "anyOf" in sub or "allOf" in sub: flatten(sub, p + ".", out, None, depth + 1) if sub.get("type") == "array" and isinstance(sub.get("items"), dict): flatten(sub["items"], p + "[].", out, None, depth + 1) return out summary = {} for key, op in ops.items(): rec = {"operationId": op.get("operationId"), "summary": op.get("summary"), "description": (op.get("description") or "")[:800], "params": [], "body_schema": None, "body_content_type": None, "responses": {}} for prm in op.get("parameters", []): prm = deref(prm) sch = prm.get("schema", {}) rec["params"].append({"name": prm["name"], "in": prm["in"], "required": prm.get("required", False), "type": sch.get("type"), "default": sch.get("default"), "enum": sch.get("enum"), "description": (prm.get("description") or "")[:400]}) rb = op.get("requestBody") if rb: content = rb["content"] ct = list(content.keys())[0] rec["body_content_type"] = ct sch = content[ct]["schema"] rec["body_ref"] = sch.get("$ref", "").split("/")[-1] or None resolved = deref(sch) rec["body_schema"] = resolved rec["body_flat"] = flatten(resolved) for code, resp in op.get("responses", {}).items(): c = resp.get("content", {}) if c: ct = list(c.keys())[0] s = c[ct]["schema"] rec["responses"][code] = {"content_type": ct, "ref": s.get("$ref", "").split("/")[-1] or s.get("type")} summary[key] = rec fn = re.sub(r"[^A-Za-z0-9]+", "_", key).strip("_") (OUT / f"{fn}.json").write_text(json.dumps(rec, indent=1, default=str)) (OUT / "_index.json").write_text(json.dumps( {k: {"operationId": v["operationId"], "summary": v["summary"], "body_ref": v.get("body_ref"), "body_ct": v["body_content_type"], "responses": v["responses"], "params": [p["name"] for p in v["params"]]} for k, v in summary.items()}, indent=1)) # Object schemas of interest OBJ = [s for s in schemas if re.search(r"^(OpenAIFile|Upload|UploadPart|VectorStore|VectorStoreFile|VectorStoreFileBatch|VectorStoreSearchResult|Batch|BatchRequestInput|BatchRequestOutput|FineTuningJob|FineTuningJobEvent|FineTuningJobCheckpoint|FineTuningCheckpointPermission|Grader|Eval|EvalRun|EvalRunOutputItem|FineTuneMethod|FineTuneSupervisedMethod|FineTuneDPOMethod|FineTuneReinforcementMethod|FineTune.*Hyperparameters|StaticChunking|AutoChunking|ChunkingStrategy|ComparisonFilter|CompoundFilter|VectorStoreExpirationAfter|FileExpirationAfter|ListFilesResponse|ListBatchesResponse|CreateEvalRequest|CreateEvalRunRequest|EvalItem|EvalJsonl|EvalStoredCompletions|EvalLogs|EvalCustomDataSourceConfig|EvalResponses|EvalCompletions|FineTuneChatRequestInput|FineTunePreferenceRequestInput|FineTuneReinforcementRequestInput|FineTuneChatCompletionRequestAssistantMessage|RunGrader|ValidateGrader).*", s)] objs = {} for name in OBJ: r = deref(schemas[name]) objs[name] = {"schema": r, "flat": flatten(r)} fn = re.sub(r"[^A-Za-z0-9]+", "_", name) (OUT / f"schema_{fn}.json").write_text(json.dumps(objs[name], indent=1, default=str)) (OUT / "_schemas_index.txt").write_text("\n".join(sorted(OBJ))) print(len(ops), "ops;", len(OBJ), "schemas ->", OUT)