feat(ai,coding-agent): add GPT-6 Sol and Luna support

This commit is contained in:
Armin Ronacher 2026-09-22 20:57:04 +02:00
parent 3a624b82dd
commit db91e03319
7 changed files with 154 additions and 46 deletions

View file

@ -371,6 +371,8 @@ const OPENAI_TOOL_SEARCH_MODEL_IDS = new Set([
"gpt-5.6-terra",
"gpt-5.6-luna",
"gpt-6-astra",
"gpt-6-sol",
"gpt-6-luna",
]);
const OPENAI_ADDITIONAL_TOOLS_MODEL_IDS = OPENAI_TOOL_SEARCH_MODEL_IDS;
const OPENAI_MID_CONVO_SYSTEM_MESSAGE_MODEL_IDS = OPENAI_TOOL_SEARCH_MODEL_IDS;
@ -379,6 +381,8 @@ const OPENAI_CODEX_ADDITIONAL_TOOLS_MODEL_IDS = new Set([
"gpt-5.6-terra",
"gpt-5.6-luna",
"gpt-6-astra",
"gpt-6-sol",
"gpt-6-luna",
]);
const OPENAI_LONG_CONTEXT_INPUT_THRESHOLD = 272000;
const OPENAI_SHORT_CONTEXT_CAPPED_MODEL_IDS = new Set([
@ -388,6 +392,8 @@ const OPENAI_SHORT_CONTEXT_CAPPED_MODEL_IDS = new Set([
"gpt-5.6-terra",
"gpt-5.6-luna",
"gpt-6-astra",
"gpt-6-sol",
"gpt-6-luna",
]);
const OPENAI_LONG_CONTEXT_PRICING_MODEL_IDS = new Set([
"gpt-5.4",
@ -398,6 +404,8 @@ const OPENAI_LONG_CONTEXT_PRICING_MODEL_IDS = new Set([
"gpt-5.6-terra",
"gpt-5.6-luna",
"gpt-6-astra",
"gpt-6-sol",
"gpt-6-luna",
]);
// Keep the generated default no less restrictive than coding-agent's historical
@ -425,12 +433,16 @@ function withOpenAiLongContextPricing(cost: Model<Api>["cost"]): Model<Api>["cos
};
}
// OpenAI reduced GPT-5.6 Terra and Luna prices on 2026-07-30. Keep these
// authoritative values until models.dev and passthrough catalogs catch up.
// Keep current OpenAI prices authoritative until models.dev and passthrough
// catalogs catch up.
// https://developers.openai.com/api/docs/pricing
const OPENAI_GPT_56_STANDARD_COSTS: Record<string, ModelCost> = {
const OPENAI_STANDARD_COSTS: Record<string, ModelCost> = {
"gpt-5.6-luna": { input: 0.2, output: 1.2, cacheRead: 0.02, cacheWrite: 0.25 },
"gpt-5.6-sol": { input: 4, output: 20, cacheRead: 0.4, cacheWrite: 5 },
"gpt-5.6-terra": { input: 2, output: 12, cacheRead: 0.2, cacheWrite: 2.5 },
"gpt-6-astra": { input: 10, output: 50, cacheRead: 1, cacheWrite: 12.5 },
"gpt-6-luna": { input: 0.1, output: 0.5, cacheRead: 0.01, cacheWrite: 0.125 },
"gpt-6-sol": { input: 2, output: 10, cacheRead: 0.2, cacheWrite: 2.5 },
};
const OPENAI_RESPONSES_NONE_REASONING_MODELS = new Set([
@ -444,6 +456,8 @@ const OPENAI_RESPONSES_NONE_REASONING_MODELS = new Set([
"gpt-5.6-sol",
"gpt-5.6-terra",
"gpt-5.6-luna",
"gpt-6-sol",
"gpt-6-luna",
]);
const XAI_BUILTIN_EXCLUDED_MODEL_IDS = new Set([
"grok-3",
@ -557,13 +571,13 @@ function supportsOpenAiXhigh(modelId: string): boolean {
modelId.includes("gpt-5.4") ||
modelId.includes("gpt-5.5") ||
modelId.includes("gpt-5.6") ||
modelId.includes("gpt-6-astra")
modelId.includes("gpt-6")
);
}
function supportsOpenAiMax(model: Model<Api>): boolean {
return (
(model.id.includes("gpt-5.6") || model.id.includes("gpt-6-astra")) &&
(model.id.includes("gpt-5.6") || model.id.includes("gpt-6")) &&
(model.api === "openai-responses" ||
model.api === "azure-openai-responses" ||
model.api === "openai-codex-responses" ||
@ -1010,13 +1024,13 @@ function applyThinkingLevelMetadata(model: Model<any>): void {
mergeThinkingLevelMap(model, { off: null });
}
if (
model.id === "gpt-6-astra" &&
(model.id === "gpt-6-astra" || model.id === "gpt-6-sol" || model.id === "gpt-6-luna") &&
(model.api === "openai-responses" ||
model.api === "azure-openai-responses" ||
model.api === "openai-codex-responses")
) {
mergeThinkingLevelMap(model, {
off: null,
off: model.id === "gpt-6-astra" ? null : "none",
minimal: null,
low: "low",
medium: "medium",
@ -2724,12 +2738,12 @@ async function generateModels() {
candidate.maxTokens = 128000;
}
if (candidate.provider === "openai" && OPENAI_LONG_CONTEXT_PRICING_MODEL_IDS.has(candidate.id)) {
const standardCost = OPENAI_GPT_56_STANDARD_COSTS[candidate.id];
const standardCost = OPENAI_STANDARD_COSTS[candidate.id];
candidate.cost = withOpenAiLongContextPricing(standardCost ?? candidate.cost);
}
// Cloudflare AI Gateway passes OpenAI usage through at OpenAI list prices.
if (candidate.provider === "cloudflare-ai-gateway") {
const standardCost = OPENAI_GPT_56_STANDARD_COSTS[candidate.id];
const standardCost = OPENAI_STANDARD_COSTS[candidate.id];
if (standardCost) candidate.cost = withOpenAiLongContextPricing(standardCost);
}
// models.dev reports gpt-5-pro output as 272000 (a duplicate of the input sub-limit);
@ -2775,7 +2789,31 @@ async function generateModels() {
provider: "openai",
reasoning: true,
input: ["text", "image"],
cost: withOpenAiLongContextPricing({ input: 10, output: 50, cacheRead: 1, cacheWrite: 12.5 }),
cost: withOpenAiLongContextPricing(OPENAI_STANDARD_COSTS["gpt-6-astra"]),
contextWindow: OPENAI_LONG_CONTEXT_INPUT_THRESHOLD,
maxTokens: 128000,
},
{
id: "gpt-6-sol",
name: "GPT-6 Sol",
api: "openai-responses",
baseUrl: "https://api.openai.com/v1",
provider: "openai",
reasoning: true,
input: ["text", "image"],
cost: withOpenAiLongContextPricing(OPENAI_STANDARD_COSTS["gpt-6-sol"]),
contextWindow: OPENAI_LONG_CONTEXT_INPUT_THRESHOLD,
maxTokens: 128000,
},
{
id: "gpt-6-luna",
name: "GPT-6 Luna",
api: "openai-responses",
baseUrl: "https://api.openai.com/v1",
provider: "openai",
reasoning: true,
input: ["text", "image"],
cost: withOpenAiLongContextPricing(OPENAI_STANDARD_COSTS["gpt-6-luna"]),
contextWindow: OPENAI_LONG_CONTEXT_INPUT_THRESHOLD,
maxTokens: 128000,
},
@ -2787,7 +2825,7 @@ async function generateModels() {
provider: "openai",
reasoning: true,
input: ["text", "image"],
cost: withOpenAiLongContextPricing({ input: 5, output: 30, cacheRead: 0.5, cacheWrite: 6.25 }),
cost: withOpenAiLongContextPricing(OPENAI_STANDARD_COSTS["gpt-5.6-sol"]),
contextWindow: OPENAI_LONG_CONTEXT_INPUT_THRESHOLD,
maxTokens: 128000,
},
@ -2799,7 +2837,7 @@ async function generateModels() {
provider: "openai",
reasoning: true,
input: ["text", "image"],
cost: withOpenAiLongContextPricing(OPENAI_GPT_56_STANDARD_COSTS["gpt-5.6-terra"]),
cost: withOpenAiLongContextPricing(OPENAI_STANDARD_COSTS["gpt-5.6-terra"]),
contextWindow: OPENAI_LONG_CONTEXT_INPUT_THRESHOLD,
maxTokens: 128000,
},
@ -2811,7 +2849,7 @@ async function generateModels() {
provider: "openai",
reasoning: true,
input: ["text", "image"],
cost: withOpenAiLongContextPricing(OPENAI_GPT_56_STANDARD_COSTS["gpt-5.6-luna"]),
cost: withOpenAiLongContextPricing(OPENAI_STANDARD_COSTS["gpt-5.6-luna"]),
contextWindow: OPENAI_LONG_CONTEXT_INPUT_THRESHOLD,
maxTokens: 128000,
},
@ -2969,7 +3007,7 @@ async function generateModels() {
// OpenAI Codex (ChatGPT OAuth) models
// NOTE: These are not fetched from models.dev; we keep a small, explicit list to avoid aliases.
// Older model limits are based on observed server behavior; GPT-5.6 and GPT-6 Astra use Codex's 272k default catalog limit.
// Older model limits are based on observed server behavior; GPT-5.6 and GPT-6 use Codex's 272k default catalog limit.
const CODEX_BASE_URL = "https://chatgpt.com/backend-api";
const CODEX_CONTEXT = 272000;
const CODEX_GPT_56_CONTEXT = 272000;
@ -2984,7 +3022,31 @@ async function generateModels() {
baseUrl: CODEX_BASE_URL,
reasoning: true,
input: ["text", "image"],
cost: withOpenAiLongContextPricing({ input: 10, output: 50, cacheRead: 1, cacheWrite: 12.5 }),
cost: withOpenAiLongContextPricing(OPENAI_STANDARD_COSTS["gpt-6-astra"]),
contextWindow: CODEX_CONTEXT,
maxTokens: CODEX_MAX_TOKENS,
},
{
id: "gpt-6-sol",
name: "GPT-6 Sol",
api: "openai-codex-responses",
provider: "openai-codex",
baseUrl: CODEX_BASE_URL,
reasoning: true,
input: ["text", "image"],
cost: withOpenAiLongContextPricing(OPENAI_STANDARD_COSTS["gpt-6-sol"]),
contextWindow: CODEX_CONTEXT,
maxTokens: CODEX_MAX_TOKENS,
},
{
id: "gpt-6-luna",
name: "GPT-6 Luna",
api: "openai-codex-responses",
provider: "openai-codex",
baseUrl: CODEX_BASE_URL,
reasoning: true,
input: ["text", "image"],
cost: withOpenAiLongContextPricing(OPENAI_STANDARD_COSTS["gpt-6-luna"]),
contextWindow: CODEX_CONTEXT,
maxTokens: CODEX_MAX_TOKENS,
},
@ -3020,7 +3082,7 @@ async function generateModels() {
baseUrl: CODEX_BASE_URL,
reasoning: true,
input: ["text", "image"],
cost: withOpenAiLongContextPricing(OPENAI_GPT_56_STANDARD_COSTS["gpt-5.6-luna"]),
cost: withOpenAiLongContextPricing(OPENAI_STANDARD_COSTS["gpt-5.6-luna"]),
contextWindow: CODEX_GPT_56_CONTEXT,
maxTokens: CODEX_MAX_TOKENS,
},
@ -3032,7 +3094,7 @@ async function generateModels() {
baseUrl: CODEX_BASE_URL,
reasoning: true,
input: ["text", "image"],
cost: withOpenAiLongContextPricing({ input: 5, output: 30, cacheRead: 0.5, cacheWrite: 6.25 }),
cost: withOpenAiLongContextPricing(OPENAI_STANDARD_COSTS["gpt-5.6-sol"]),
contextWindow: CODEX_GPT_56_CONTEXT,
maxTokens: CODEX_MAX_TOKENS,
},
@ -3044,7 +3106,7 @@ async function generateModels() {
baseUrl: CODEX_BASE_URL,
reasoning: true,
input: ["text", "image"],
cost: withOpenAiLongContextPricing(OPENAI_GPT_56_STANDARD_COSTS["gpt-5.6-terra"]),
cost: withOpenAiLongContextPricing(OPENAI_STANDARD_COSTS["gpt-5.6-terra"]),
contextWindow: CODEX_GPT_56_CONTEXT,
maxTokens: CODEX_MAX_TOKENS,
},