Skip to content
Merged
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

### Features

- **GPT-5.6 Codex models** — Added OpenAI's Sol, Terra, and Luna models with API and subscription-backed reasoning effort variants, including the Codex-only `ultra` alias for Sol and Terra.
- **GLM-5.3 model support** — Added the latest Z.AI Coding Plan model with its 1M-token context window and native `low`, `high`, and `max` reasoning efforts.

### Compatibility
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"$schema": "https://json.schemastore.org/package.json",
"version": "0.4.2",
"version": "0.4.3",
"name": "@aictrl/cli",
"description": "Headless execution engine for AI agent skills",
"type": "module",
Expand Down
11 changes: 11 additions & 0 deletions packages/cli/src/plugin/codex.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Installation } from "../installation"
import { Auth, OAUTH_DUMMY_KEY } from "../auth"
import os from "os"
import { ProviderTransform } from "@/provider/transform"
import type { Provider } from "@/provider/provider"

const log = Log.create({ service: "plugin.codex" })

Expand Down Expand Up @@ -357,13 +358,15 @@ export async function CodexAuthPlugin(input: PluginInput): Promise<Hooks> {
if (auth.type !== "oauth") return {}

// Filter models to only allowed Codex models for OAuth
const models = ["gpt-5.6-sol", "gpt-5.6-terra", "gpt-5.6-luna"]
const allowedModels = new Set([
"gpt-5.1-codex-max",
"gpt-5.1-codex-mini",
"gpt-5.2",
"gpt-5.2-codex",
"gpt-5.3-codex",
"gpt-5.1-codex",
...models,
])
for (const modelId of Object.keys(provider.models)) {
if (modelId.includes("codex")) continue
Expand Down Expand Up @@ -403,6 +406,14 @@ export async function CodexAuthPlugin(input: PluginInput): Promise<Hooks> {
provider.models["gpt-5.3-codex"] = model
}

for (const id of models) {
const model = provider.models[id] as Provider.Model | undefined
if (!model) continue
model.family = "gpt-codex"
model.limit = { context: 400_000, input: 272_000, output: 128_000 }
model.variants = ProviderTransform.variants(model)
}

// Zero out costs for Codex (included with ChatGPT subscription)
for (const model of Object.values(provider.models)) {
model.cost = {
Expand Down
35 changes: 25 additions & 10 deletions packages/cli/src/provider/transform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,8 @@ export namespace ProviderTransform {

const WIDELY_SUPPORTED_EFFORTS = ["low", "medium", "high"]
const OPENAI_EFFORTS = ["none", "minimal", ...WIDELY_SUPPORTED_EFFORTS, "xhigh"]
const OPENAI_GPT_5_6_EFFORTS = ["none", ...WIDELY_SUPPORTED_EFFORTS, "xhigh", "max"]
const OPENAI_GPT_5_6_CODEX_EFFORTS = [...WIDELY_SUPPORTED_EFFORTS, "xhigh", "max"]

export function variants(model: Provider.Model): Record<string, Record<string, any>> {
if (!model.capabilities.reasoning) {
Expand Down Expand Up @@ -486,7 +488,7 @@ export namespace ProviderTransform {
case "@ai-sdk/deepinfra":
// https://v5.ai-sdk.dev/providers/ai-sdk-providers/deepinfra
case "venice-ai-sdk-provider":
// https://docs.venice.ai/overview/guides/reasoning-models#reasoning-effort
// https://docs.venice.ai/overview/guides/reasoning-models#reasoning-effort
return Object.fromEntries(WIDELY_SUPPORTED_EFFORTS.map((effort) => [effort, { reasoningEffort: effort }]))

case "@ai-sdk/openai-compatible":
Expand All @@ -513,6 +515,13 @@ export namespace ProviderTransform {
// https://v5.ai-sdk.dev/providers/ai-sdk-providers/openai
if (id === "gpt-5-pro") return {}
const openaiEfforts = iife(() => {
if (["gpt-5.6", "gpt-5.6-sol", "gpt-5.6-terra", "gpt-5.6-luna"].includes(model.api.id)) {
if (model.family === "gpt-codex" && model.api.id !== "gpt-5.6-luna") {
return [...OPENAI_GPT_5_6_CODEX_EFFORTS, "ultra"]
}
if (model.family === "gpt-codex") return OPENAI_GPT_5_6_CODEX_EFFORTS
return OPENAI_GPT_5_6_EFFORTS
}
if (id.includes("codex")) {
if (id.includes("5.2") || id.includes("5.3")) return [...WIDELY_SUPPORTED_EFFORTS, "xhigh"]
return WIDELY_SUPPORTED_EFFORTS
Expand All @@ -530,14 +539,17 @@ export namespace ProviderTransform {
return arr
})
return Object.fromEntries(
openaiEfforts.map((effort) => [
effort,
{
reasoningEffort: effort,
reasoningSummary: "auto",
include: ["reasoning.encrypted_content"],
},
]),
openaiEfforts.map((effort) => {
const value = effort === "ultra" ? "max" : effort
return [
effort,
{
reasoningEffort: value,
reasoningSummary: "auto",
include: ["reasoning.encrypted_content"],
},
]
}),
)

case "@ai-sdk/anthropic":
Expand Down Expand Up @@ -736,7 +748,10 @@ export namespace ProviderTransform {
result["chat_template_args"] = { enable_thinking: true }
}

if (["zai", "zai-coding-plan", "zhipuai"].includes(input.model.providerID) && input.model.api.npm === "@ai-sdk/openai-compatible") {
if (
["zai", "zai-coding-plan", "zhipuai"].includes(input.model.providerID) &&
input.model.api.npm === "@ai-sdk/openai-compatible"
) {
result["thinking"] = {
type: "enabled",
clear_thinking: false,
Expand Down
67 changes: 67 additions & 0 deletions packages/cli/test/plugin/codex.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { describe, expect, test } from "bun:test"
import {
CodexAuthPlugin,
parseJwtClaims,
extractAccountIdFromClaims,
extractAccountId,
Expand Down Expand Up @@ -120,4 +121,70 @@ describe("plugin.codex", () => {
).toBe("acc-123")
})
})

test("exposes GPT-5.6 Codex models with their supported effort levels", async () => {
const hooks = await CodexAuthPlugin({} as never)
if (!hooks.auth?.loader) throw new Error("Codex auth loader is missing")
const provider = {
models: Object.fromEntries(
["gpt-4o", "gpt-5.3-codex", "gpt-5.6-sol", "gpt-5.6-terra", "gpt-5.6-luna"].map((id) => [
id,
{
id,
providerID: "openai",
api: { id, url: "https://api.openai.com", npm: "@ai-sdk/openai" },
name: id,
family: "gpt",
capabilities: {
temperature: false,
reasoning: true,
attachment: true,
toolcall: true,
input: { text: true, audio: false, image: true, video: false, pdf: true },
output: { text: true, audio: false, image: false, video: false, pdf: false },
interleaved: false,
},
cost: { input: 1, output: 1, cache: { read: 1, write: 1 } },
limit: { context: 1_050_000, input: 922_000, output: 128_000 },
status: "active",
options: {},
headers: {},
release_date: "2026-07-09",
variants: {} as Record<string, Record<string, unknown>>,
},
]),
),
}

await hooks.auth.loader(
async () => ({ type: "oauth", refresh: "refresh", access: "access", expires: Date.now() + 60_000 }),
provider as never,
)

expect(provider.models["gpt-4o"]).toBeUndefined()
expect(provider.models["gpt-5.6-sol"].limit).toEqual({ context: 400_000, input: 272_000, output: 128_000 })
expect(Object.keys(provider.models["gpt-5.6-sol"].variants)).toEqual([
"low",
"medium",
"high",
"xhigh",
"max",
"ultra",
])
expect(Object.keys(provider.models["gpt-5.6-terra"].variants)).toEqual([
"low",
"medium",
"high",
"xhigh",
"max",
"ultra",
])
expect(Object.keys(provider.models["gpt-5.6-luna"].variants)).toEqual(["low", "medium", "high", "xhigh", "max"])
expect(provider.models["gpt-5.6-sol"].variants.ultra).toEqual({
reasoningEffort: "max",
reasoningSummary: "auto",
include: ["reasoning.encrypted_content"],
})
expect(provider.models["gpt-5.6-luna"].variants.ultra).toBeUndefined()
})
})
49 changes: 49 additions & 0 deletions packages/cli/test/provider/transform.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2178,6 +2178,55 @@ describe("ProviderTransform.variants", () => {
const result = ProviderTransform.variants(model)
expect(Object.keys(result)).toEqual(["none", "minimal", "low", "medium", "high", "xhigh"])
})

test.each(["gpt-5.6", "gpt-5.6-sol", "gpt-5.6-terra", "gpt-5.6-luna"])(
"%s exposes every supported API reasoning effort",
(id) => {
const model = createMockModel({
id,
providerID: "openai",
api: {
id,
url: "https://api.openai.com",
npm: "@ai-sdk/openai",
},
release_date: "2026-07-09",
})
const result = ProviderTransform.variants(model)
expect(Object.keys(result)).toEqual(["none", "low", "medium", "high", "xhigh", "max"])
expect(result.max).toEqual({
reasoningEffort: "max",
reasoningSummary: "auto",
include: ["reasoning.encrypted_content"],
})
},
)

test.each([
{ id: "gpt-5.6-sol", efforts: ["low", "medium", "high", "xhigh", "max", "ultra"] },
{ id: "gpt-5.6-terra", efforts: ["low", "medium", "high", "xhigh", "max", "ultra"] },
{ id: "gpt-5.6-luna", efforts: ["low", "medium", "high", "xhigh", "max"] },
])("$id exposes its Codex reasoning efforts", ({ id, efforts }) => {
const model = createMockModel({
id,
providerID: "openai",
family: "gpt-codex",
api: {
id,
url: "https://chatgpt.com/backend-api/codex",
npm: "@ai-sdk/openai",
},
release_date: "2026-07-09",
})
const result = ProviderTransform.variants(model)
expect(Object.keys(result)).toEqual([...efforts])
if (id === "gpt-5.6-luna") return
expect(result.ultra).toEqual({
reasoningEffort: "max",
reasoningSummary: "auto",
include: ["reasoning.encrypted_content"],
})
})
})

describe("@ai-sdk/anthropic", () => {
Expand Down
57 changes: 57 additions & 0 deletions packages/cli/test/tool/fixtures/models-api.json
Original file line number Diff line number Diff line change
Expand Up @@ -24977,6 +24977,63 @@
"name": "OpenAI",
"doc": "https://platform.openai.com/docs/models",
"models": {
"gpt-5.6-sol": {
"id": "gpt-5.6-sol",
"name": "GPT-5.6 Sol",
"description": "Frontier GPT-5.6 model for complex professional work, coding, and agentic workflows",
"family": "gpt-sol",
"attachment": true,
"reasoning": true,
"reasoning_options": [{ "type": "effort", "values": ["none", "low", "medium", "high", "xhigh", "max"] }],
"tool_call": true,
"structured_output": true,
"temperature": false,
"knowledge": "2026-02-16",
"release_date": "2026-07-09",
"last_updated": "2026-07-09",
"modalities": { "input": ["text", "image", "pdf"], "output": ["text"] },
"open_weights": false,
"cost": { "input": 5, "output": 30, "cache_read": 0.5, "cache_write": 6.25 },
"limit": { "context": 1050000, "input": 922000, "output": 128000 }
},
"gpt-5.6-terra": {
"id": "gpt-5.6-terra",
"name": "GPT-5.6 Terra",
"description": "Balanced GPT-5.6 model for capable, cost-efficient everyday work",
"family": "gpt-terra",
"attachment": true,
"reasoning": true,
"reasoning_options": [{ "type": "effort", "values": ["none", "low", "medium", "high", "xhigh", "max"] }],
"tool_call": true,
"structured_output": true,
"temperature": false,
"knowledge": "2026-02-16",
"release_date": "2026-07-09",
"last_updated": "2026-07-09",
"modalities": { "input": ["text", "image", "pdf"], "output": ["text"] },
"open_weights": false,
"cost": { "input": 2, "output": 12, "cache_read": 0.2, "cache_write": 2.5 },
"limit": { "context": 1050000, "input": 922000, "output": 128000 }
},
"gpt-5.6-luna": {
"id": "gpt-5.6-luna",
"name": "GPT-5.6 Luna",
"description": "Cost-efficient GPT-5.6 model for fast, high-volume workloads",
"family": "gpt-luna",
"attachment": true,
"reasoning": true,
"reasoning_options": [{ "type": "effort", "values": ["none", "low", "medium", "high", "xhigh", "max"] }],
"tool_call": true,
"structured_output": true,
"temperature": false,
"knowledge": "2026-02-16",
"release_date": "2026-07-09",
"last_updated": "2026-07-09",
"modalities": { "input": ["text", "image", "pdf"], "output": ["text"] },
"open_weights": false,
"cost": { "input": 0.2, "output": 1.2, "cache_read": 0.02, "cache_write": 0.25 },
"limit": { "context": 1050000, "input": 922000, "output": 128000 }
},
"gpt-4.1-nano": {
"id": "gpt-4.1-nano",
"name": "GPT-4.1 nano",
Expand Down