Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 32 additions & 3 deletions apps/server/src/provider/CodexChatGptModels.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,24 @@ it.effect(
models:
request.headers.authorization === "Bearer account-a"
? [
{ slug: "second", display_name: "Second from OpenAI", visibility: "list" },
{
slug: "second",
display_name: "Second from OpenAI",
visibility: "list",
default_reasoning_level: "low",
supported_reasoning_levels: [
{ effort: "low", description: "Fast" },
{ effort: "ultra", description: "Deepest" },
{ effort: "", description: "Malformed" },
],
},
{ slug: "hidden", display_name: "Hidden", visibility: "hidden" },
{ slug: "first", display_name: "First from OpenAI", visibility: "list" },
{
slug: "first",
display_name: "First from OpenAI",
visibility: "list",
supported_reasoning_levels: [{ effort: "low", description: "Fast" }],
},
]
: [{ slug: "account-b-only", display_name: "B", visibility: "list" }],
}),
Expand Down Expand Up @@ -49,14 +64,28 @@ it.effect(
],
);
assert.deepEqual(a[1]!.capabilities, native[0]!.capabilities);
assert.isNull(a[0]!.capabilities);
assert.deepEqual(a[0]!.capabilities, {
optionDescriptors: [
{
id: "reasoningEffort",
label: "Reasoning",
type: "select",
options: [
{ id: "low", label: "Low", isDefault: true },
{ id: "ultra", label: "Ultra" },
],
currentValue: "low",
},
],
});
const b = yield* chatGptModels("account-b", native).pipe(
Effect.provideService(HttpClient.HttpClient, http),
);
assert.deepEqual(
b.map((model) => model.slug),
["account-b-only"],
);
assert.isNull(b[0]!.capabilities);
assert.deepEqual(requests, ["Bearer account-a", "Bearer account-b"]);
}),
);
Expand Down
22 changes: 21 additions & 1 deletion apps/server/src/provider/CodexChatGptModels.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type { ServerProviderModel } from "@t3tools/contracts";
import * as Effect from "effect/Effect";
import * as Schema from "effect/Schema";
import { HttpClient, HttpClientRequest } from "effect/http";
import { mapCodexModelCapabilities } from "./CodexProvider.ts";

export class ChatGptCatalogError extends Schema.TaggedError<ChatGptCatalogError>()(
"ChatGptCatalogError",
Expand All @@ -14,10 +15,28 @@ const Catalog = Schema.Struct({
slug: Schema.NonEmptyString,
display_name: Schema.NonEmptyString,
visibility: Schema.String,
default_reasoning_level: Schema.optionalKey(Schema.String),
supported_reasoning_levels: Schema.optionalKey(
Schema.Array(Schema.Struct({ effort: Schema.String, description: Schema.String })),
),
}),
),
});

// Models newer than the managed Codex CLI are missing from its native catalog,
// so fall back to the reasoning levels OpenAI advertises for them.
function catalogCapabilities(model: (typeof Catalog.Type)["models"][number]) {
const supportedReasoningEfforts = (model.supported_reasoning_levels ?? [])
.filter(({ effort }) => effort.length > 0)
.map(({ effort, description }) => ({ reasoningEffort: effort, description }));
if (supportedReasoningEfforts.length === 0) return null;
return mapCodexModelCapabilities({
model: model.slug,
defaultReasoningEffort: model.default_reasoning_level ?? "",
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved
supportedReasoningEfforts,
});
}

export const chatGptModels = Effect.fn("chatGptModels")(function* (
accessToken: string,
nativeModels: ReadonlyArray<ServerProviderModel>,
Expand All @@ -37,7 +56,8 @@ export const chatGptModels = Effect.fn("chatGptModels")(function* (
({
...nativeModels.find((native) => native.slug === model.slug),
capabilities:
nativeModels.find((native) => native.slug === model.slug)?.capabilities ?? null,
nativeModels.find((native) => native.slug === model.slug)?.capabilities ??
catalogCapabilities(model),
slug: model.slug,
name: model.display_name,
isCustom: false,
Expand Down
6 changes: 5 additions & 1 deletion apps/server/src/provider/CodexProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,11 @@ export function codexDefaultReasoningEffortOverride(model: string): "medium" | u
}

export function mapCodexModelCapabilities(
model: CodexSchema.V2ModelListResponse__Model,
model: Pick<
CodexSchema.V2ModelListResponse__Model,
"model" | "defaultReasoningEffort" | "supportedReasoningEfforts"
> &
Partial<CodexSchema.V2ModelListResponse__Model>,
): ModelCapabilities {
const reasoningOptions = model.supportedReasoningEfforts.map(({ reasoningEffort }) =>
reasoningEffort ===
Expand Down
Loading