File size: 2,402 Bytes
fc93158
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
import type { Api, Model } from "@mariozechner/pi-ai";
import { normalizeModelCompat } from "../model-compat.js";
import { normalizeProviderId } from "../model-selection.js";

const OPENAI_CODEX_BASE_URL = "https://chatgpt.com/backend-api";

function isOpenAIApiBaseUrl(baseUrl?: string): boolean {
  const trimmed = baseUrl?.trim();
  if (!trimmed) {
    return false;
  }
  return /^https?:\/\/api\.openai\.com(?:\/v1)?\/?$/i.test(trimmed);
}

function isOpenAICodexBaseUrl(baseUrl?: string): boolean {
  const trimmed = baseUrl?.trim();
  if (!trimmed) {
    return false;
  }
  return /^https?:\/\/chatgpt\.com\/backend-api\/?$/i.test(trimmed);
}

function normalizeOpenAICodexTransport(params: {
  provider: string;
  model: Model<Api>;
}): Model<Api> {
  if (normalizeProviderId(params.provider) !== "openai-codex") {
    return params.model;
  }

  const useCodexTransport =
    !params.model.baseUrl ||
    isOpenAIApiBaseUrl(params.model.baseUrl) ||
    isOpenAICodexBaseUrl(params.model.baseUrl);

  const nextApi =
    useCodexTransport && params.model.api === "openai-responses"
      ? ("openai-codex-responses" as const)
      : params.model.api;
  const nextBaseUrl =
    nextApi === "openai-codex-responses" &&
    (!params.model.baseUrl || isOpenAIApiBaseUrl(params.model.baseUrl))
      ? OPENAI_CODEX_BASE_URL
      : params.model.baseUrl;

  if (nextApi === params.model.api && nextBaseUrl === params.model.baseUrl) {
    return params.model;
  }

  return {
    ...params.model,
    api: nextApi,
    baseUrl: nextBaseUrl,
  } as Model<Api>;
}

function normalizeOpenAITransport(params: { provider: string; model: Model<Api> }): Model<Api> {
  if (normalizeProviderId(params.provider) !== "openai") {
    return params.model;
  }

  const useResponsesTransport =
    params.model.api === "openai-completions" &&
    (!params.model.baseUrl || isOpenAIApiBaseUrl(params.model.baseUrl));

  if (!useResponsesTransport) {
    return params.model;
  }

  return {
    ...params.model,
    api: "openai-responses",
  } as Model<Api>;
}

export function normalizeResolvedProviderModel(params: {
  provider: string;
  model: Model<Api>;
}): Model<Api> {
  const normalizedOpenAI = normalizeOpenAITransport(params);
  const normalizedCodex = normalizeOpenAICodexTransport({
    provider: params.provider,
    model: normalizedOpenAI,
  });
  return normalizeModelCompat(normalizedCodex);
}