diff --git a/open-sse/config/providers/index.ts b/open-sse/config/providers/index.ts index cc8ec3a703..f3ce825532 100644 --- a/open-sse/config/providers/index.ts +++ b/open-sse/config/providers/index.ts @@ -122,6 +122,7 @@ import { blackbox_webProvider } from "./registry/blackbox/web/index.ts"; import { uncloseaiProvider } from "./registry/uncloseai/index.ts"; import { nscaleProvider } from "./registry/nscale/index.ts"; import { chatgpt_web_codexProvider } from "./registry/chatgpt-web-codex/index.ts"; +import { chatgpt_sessionProvider } from "./registry/chatgpt-session/index.ts"; import { openrouterProvider } from "./registry/openrouter/index.ts"; import { cheaperinferenceProvider } from "./registry/cheaperinference/index.ts"; import { openvectaProvider } from "./registry/openvecta/index.ts"; @@ -388,6 +389,7 @@ export const REGISTRY: Record = { uncloseai: uncloseaiProvider, nscale: nscaleProvider, "chatgpt-web-codex": chatgpt_web_codexProvider, + "chatgpt-session": chatgpt_sessionProvider, openrouter: openrouterProvider, cheaperinference: cheaperinferenceProvider, openvecta: openvectaProvider, diff --git a/open-sse/config/providers/registry/chatgpt-session/index.ts b/open-sse/config/providers/registry/chatgpt-session/index.ts new file mode 100644 index 0000000000..e00b5cc576 --- /dev/null +++ b/open-sse/config/providers/registry/chatgpt-session/index.ts @@ -0,0 +1,27 @@ +import type { RegistryEntry } from "../../shared.ts"; + +const SESSION_CAPABILITIES = { + toolCalling: true, + supportsReasoning: true, + supportsVision: false, +} as const; + +export const chatgpt_sessionProvider: RegistryEntry = { + id: "chatgpt-session", + alias: "cgpt-session", + format: "openai", + executor: "chatgpt-session", + baseUrl: "https://chatgpt.com", + reasoningTransport: "opaque", + authType: "apikey", + authHeader: "cookie", + models: [ + { id: "luna", name: "ChatGPT Session — Luna", ...SESSION_CAPABILITIES }, + { id: "think", name: "ChatGPT Session — Think", ...SESSION_CAPABILITIES }, + { id: "instant", name: "ChatGPT Session — Instant", ...SESSION_CAPABILITIES }, + { id: "medium", name: "ChatGPT Session — Medium", ...SESSION_CAPABILITIES }, + { id: "high", name: "ChatGPT Session — High", ...SESSION_CAPABILITIES }, + { id: "extra-high", name: "ChatGPT Session — Extra High", ...SESSION_CAPABILITIES }, + { id: "pro", name: "ChatGPT Session — Pro", ...SESSION_CAPABILITIES }, + ], +}; diff --git a/open-sse/executors/index.ts b/open-sse/executors/index.ts index fbe9940d80..76c6873ce3 100644 --- a/open-sse/executors/index.ts +++ b/open-sse/executors/index.ts @@ -48,6 +48,10 @@ const lazyExecutors: Record Promise> = { import("./chatgpt-web-codex.ts").then((m) => new m.ChatGptWebCodexExecutor()), "cgpt-codex": () => import("./chatgpt-web-codex.ts").then((m) => new m.ChatGptWebCodexExecutor()), + "chatgpt-session": () => + import("./chatgpt-session.ts").then((m) => new m.ChatGptSessionExecutor()), + "cgpt-session": () => + import("./chatgpt-session.ts").then((m) => new m.ChatGptSessionExecutor()), cursor: () => import("./cursor.ts").then((m) => new m.CursorExecutor()), trae: () => import("./trae.ts").then((m) => new m.TraeExecutor()), glm: () => import("./glm.ts").then((m) => new m.GlmExecutor("glm")), diff --git a/tests/snapshots/executors/executor-map.json b/tests/snapshots/executors/executor-map.json index 3f72a8282b..7bd58b8ae8 100644 --- a/tests/snapshots/executors/executor-map.json +++ b/tests/snapshots/executors/executor-map.json @@ -90,6 +90,16 @@ "configSource": "", "provider": "chatgpt-web-codex" }, + "cgpt-session": { + "className": "ChatGptSessionExecutor", + "configSource": "", + "provider": "chatgpt-session" + }, + "chatgpt-session": { + "className": "ChatGptSessionExecutor", + "configSource": "", + "provider": "chatgpt-session" + }, "chatgpt-web-codex": { "className": "ChatGptWebCodexExecutor", "configSource": "", @@ -666,6 +676,6 @@ "provider": "zai-web" } }, - "keyCount": 133, + "keyCount": 135, "sharedInstances": [] } diff --git a/tests/snapshots/provider/translate-path.json b/tests/snapshots/provider/translate-path.json index d00eb4488a..b1cce4b62c 100644 --- a/tests/snapshots/provider/translate-path.json +++ b/tests/snapshots/provider/translate-path.json @@ -842,6 +842,29 @@ "stream": "https://api.chatanywhere.org/v1/chat/completions" } }, + "chatgpt-session": { + "format": "openai", + "headers": { + "apiKey": { + "Accept": "text/event-stream", + "Authorization": "Bearer ", + "Content-Type": "application/json" + }, + "nonStream": { + "Authorization": "Bearer ", + "Content-Type": "application/json" + }, + "oauth": { + "Accept": "text/event-stream", + "Authorization": "Bearer ", + "Content-Type": "application/json" + } + }, + "url": { + "nonStream": "https://chatgpt.com", + "stream": "https://chatgpt.com" + } + }, "chatgpt-web-codex": { "format": "openai-responses", "headers": { diff --git a/tests/unit/chatgpt-session-registry.test.ts b/tests/unit/chatgpt-session-registry.test.ts new file mode 100644 index 0000000000..d707d70e10 --- /dev/null +++ b/tests/unit/chatgpt-session-registry.test.ts @@ -0,0 +1,35 @@ +import { test } from "node:test"; +import assert from "node:assert/strict"; + +import { REGISTRY } from "../../open-sse/config/providerRegistry.ts"; +import { CHATGPT_SESSION_ROUTE_IDS } from "../../open-sse/executors/chatgpt-session/models.ts"; +import { + RETIRED_COMMON_CHATGPT_WEB_PROVIDER_IDS, + isCommonChatGptWebRetiredProviderId, +} from "../../src/shared/constants/chatgptWebRetirement.ts"; + +test("the registry exposes chatgpt-session with its seven routes", () => { + const entry = REGISTRY["chatgpt-session"]; + assert.ok(entry, "chatgpt-session must be registered"); + assert.equal(entry.alias, "cgpt-session"); + assert.equal(entry.format, "openai"); + assert.equal(entry.executor, "chatgpt-session"); + assert.deepEqual( + entry.models.map((model) => model.id), + [...CHATGPT_SESSION_ROUTE_IDS] + ); +}); + +test("the new ids are not the retired ones", () => { + assert.equal(isCommonChatGptWebRetiredProviderId("chatgpt-session"), false); + assert.equal(isCommonChatGptWebRetiredProviderId("cgpt-session"), false); + assert.deepEqual([...RETIRED_COMMON_CHATGPT_WEB_PROVIDER_IDS], ["chatgpt-web", "cgpt-web"]); +}); + +test("both executor aliases resolve to the session executor", async () => { + const { getExecutor } = await import("../../open-sse/executors/index.ts"); + for (const id of ["chatgpt-session", "cgpt-session"]) { + const executor = await getExecutor(id); + assert.equal(executor.getProvider(), "chatgpt-session"); + } +});