From 55603cb5c7fd57ef7d424714e9da55efac13e328 Mon Sep 17 00:00:00 2001
From: Kacper
Date: Sat, 13 Dec 2025 01:36:15 +0100
Subject: [PATCH] feat: add GPT-5.2 model support and refresh profiles
functionality
- Introduced the GPT-5.2 model with advanced coding capabilities across various components.
- Added a new button in ProfilesView to refresh default profiles, enhancing user experience.
- Updated CodexSetupStep to clarify authentication requirements and added commands for verifying login status.
- Enhanced utility functions to recognize the new GPT-5.2 model in the application.
---
apps/app/src/components/views/board-view.tsx | 7 ++
.../src/components/views/profiles-view.tsx | 39 ++++++++---
.../setup-view/steps/codex-setup-step.tsx | 29 ++++++--
apps/app/src/lib/utils.ts | 2 +
apps/app/src/store/app-store.ts | 20 ++++++
apps/server/src/routes/models.ts | 9 +++
apps/server/src/routes/setup.ts | 45 ++++--------
apps/server/src/services/auto-mode-service.ts | 70 +++++++++++++++++--
8 files changed, 170 insertions(+), 51 deletions(-)
diff --git a/apps/app/src/components/views/board-view.tsx b/apps/app/src/components/views/board-view.tsx
index 23d332a9..8aa70362 100644
--- a/apps/app/src/components/views/board-view.tsx
+++ b/apps/app/src/components/views/board-view.tsx
@@ -146,6 +146,13 @@ const CLAUDE_MODELS: ModelOption[] = [
];
const CODEX_MODELS: ModelOption[] = [
+ {
+ id: "gpt-5.2",
+ label: "GPT-5.2",
+ description: "Latest OpenAI model with advanced coding capabilities.",
+ badge: "Latest",
+ provider: "codex",
+ },
{
id: "gpt-5.1-codex-max",
label: "GPT-5.1 Codex Max",
diff --git a/apps/app/src/components/views/profiles-view.tsx b/apps/app/src/components/views/profiles-view.tsx
index 30316518..43530d55 100644
--- a/apps/app/src/components/views/profiles-view.tsx
+++ b/apps/app/src/components/views/profiles-view.tsx
@@ -41,6 +41,7 @@ import {
GripVertical,
Lock,
Check,
+ RefreshCw,
} from "lucide-react";
import { toast } from "sonner";
import {
@@ -89,6 +90,7 @@ const CLAUDE_MODELS: { id: AgentModel; label: string }[] = [
];
const CODEX_MODELS: { id: AgentModel; label: string }[] = [
+ { id: "gpt-5.2", label: "GPT-5.2" },
{ id: "gpt-5.1-codex-max", label: "GPT-5.1 Codex Max" },
{ id: "gpt-5.1-codex", label: "GPT-5.1 Codex" },
{ id: "gpt-5.1-codex-mini", label: "GPT-5.1 Codex Mini" },
@@ -461,6 +463,7 @@ export function ProfilesView() {
updateAIProfile,
removeAIProfile,
reorderAIProfiles,
+ resetAIProfiles,
} = useAppStore();
const shortcuts = useKeyboardShortcutsConfig();
@@ -529,6 +532,13 @@ export function ProfilesView() {
});
};
+ const handleResetProfiles = () => {
+ resetAIProfiles();
+ toast.success("Profiles refreshed", {
+ description: "Default profiles have been updated to the latest version",
+ });
+ };
+
// Build keyboard shortcuts for profiles view
const profilesShortcuts: KeyboardShortcut[] = useMemo(() => {
const shortcutsList: KeyboardShortcut[] = [];
@@ -568,15 +578,26 @@ export function ProfilesView() {
- setShowAddDialog(true)}
- hotkey={shortcuts.addProfile}
- hotkeyActive={false}
- data-testid="add-profile-button"
- >
-
- New Profile
-
+
+
+
setShowAddDialog(true)}
+ hotkey={shortcuts.addProfile}
+ hotkeyActive={false}
+ data-testid="add-profile-button"
+ >
+
+ New Profile
+
+
diff --git a/apps/app/src/components/views/setup-view/steps/codex-setup-step.tsx b/apps/app/src/components/views/setup-view/steps/codex-setup-step.tsx
index 13335e02..a5f18ce4 100644
--- a/apps/app/src/components/views/setup-view/steps/codex-setup-step.tsx
+++ b/apps/app/src/components/views/setup-view/steps/codex-setup-step.tsx
@@ -282,21 +282,21 @@ export function CodexSetupStep({
Authentication
- Codex requires an OpenAI API key
+ Codex requires authentication via ChatGPT account or API key
{codexCliStatus?.installed && (
-
-
- Authenticate via CLI
+
+
+ Authenticate via CLI (Recommended)
-
- Run this command in your terminal:
+
+ Run the following command in your terminal to login with your ChatGPT account:
-
+
codex auth login
@@ -308,6 +308,21 @@ export function CodexSetupStep({
+
+ After logging in, you can verify your authentication status:
+
+
+
+ codex login status
+
+
+
diff --git a/apps/app/src/lib/utils.ts b/apps/app/src/lib/utils.ts
index 9fa2f503..8d7b6386 100644
--- a/apps/app/src/lib/utils.ts
+++ b/apps/app/src/lib/utils.ts
@@ -12,6 +12,7 @@ export function cn(...inputs: ClassValue[]) {
export function isCodexModel(model?: AgentModel | string): boolean {
if (!model) return false;
const codexModels: string[] = [
+ "gpt-5.2",
"gpt-5.1-codex-max",
"gpt-5.1-codex",
"gpt-5.1-codex-mini",
@@ -36,6 +37,7 @@ export function getModelDisplayName(model: AgentModel | string): string {
haiku: "Claude Haiku",
sonnet: "Claude Sonnet",
opus: "Claude Opus",
+ "gpt-5.2": "GPT-5.2",
"gpt-5.1-codex-max": "GPT-5.1 Codex Max",
"gpt-5.1-codex": "GPT-5.1 Codex",
"gpt-5.1-codex-mini": "GPT-5.1 Codex Mini",
diff --git a/apps/app/src/store/app-store.ts b/apps/app/src/store/app-store.ts
index 81d50617..2136e4a6 100644
--- a/apps/app/src/store/app-store.ts
+++ b/apps/app/src/store/app-store.ts
@@ -203,6 +203,7 @@ export interface FeatureImagePath {
export type ClaudeModel = "opus" | "sonnet" | "haiku";
// OpenAI/Codex models
export type OpenAIModel =
+ | "gpt-5.2"
| "gpt-5.1-codex-max"
| "gpt-5.1-codex"
| "gpt-5.1-codex-mini"
@@ -445,6 +446,7 @@ export interface AppActions {
updateAIProfile: (id: string, updates: Partial
) => void;
removeAIProfile: (id: string) => void;
reorderAIProfiles: (oldIndex: number, newIndex: number) => void;
+ resetAIProfiles: () => void;
// Project Analysis actions
setProjectAnalysis: (analysis: ProjectAnalysis | null) => void;
@@ -491,6 +493,16 @@ const DEFAULT_AI_PROFILES: AIProfile[] = [
isBuiltIn: true,
icon: "Zap",
},
+ {
+ id: "profile-gpt52",
+ name: "GPT-5.2",
+ description: "GPT-5.2 - Latest OpenAI model for advanced coding tasks.",
+ model: "gpt-5.2",
+ thinkingLevel: "none",
+ provider: "codex",
+ isBuiltIn: true,
+ icon: "Sparkles",
+ },
{
id: "profile-codex-power",
name: "Codex Power",
@@ -1106,6 +1118,14 @@ export const useAppStore = create()(
set({ aiProfiles: profiles });
},
+ resetAIProfiles: () => {
+ // Merge: keep user-created profiles, but refresh all built-in profiles to latest defaults
+ const currentProfiles = get().aiProfiles;
+ const userProfiles = currentProfiles.filter((p) => !p.isBuiltIn);
+ const mergedProfiles = [...DEFAULT_AI_PROFILES, ...userProfiles];
+ set({ aiProfiles: mergedProfiles });
+ },
+
// Project Analysis actions
setProjectAnalysis: (analysis) => set({ projectAnalysis: analysis }),
setIsAnalyzing: (analyzing) => set({ isAnalyzing: analyzing }),
diff --git a/apps/server/src/routes/models.ts b/apps/server/src/routes/models.ts
index 529c50a6..5856fac5 100644
--- a/apps/server/src/routes/models.ts
+++ b/apps/server/src/routes/models.ts
@@ -90,6 +90,15 @@ export function createModelsRoutes(): Router {
supportsVision: true,
supportsTools: false,
},
+ {
+ id: "gpt-5.2",
+ name: "GPT-5.2 (Codex)",
+ provider: "openai",
+ contextWindow: 256000,
+ maxOutputTokens: 32768,
+ supportsVision: true,
+ supportsTools: true,
+ },
];
res.json({ success: true, models });
diff --git a/apps/server/src/routes/setup.ts b/apps/server/src/routes/setup.ts
index a1b5b38b..6403fbfa 100644
--- a/apps/server/src/routes/setup.ts
+++ b/apps/server/src/routes/setup.ts
@@ -249,56 +249,41 @@ export function createSetupRoutes(): Router {
const { stdout: versionOut } = await execAsync("codex --version");
version = versionOut.trim();
} catch {
- // Version command might not be available
+ version = "unknown";
}
} catch {
// Not found
}
// Check for OpenAI/Codex authentication
+ // Simplified: only check via CLI command, no file parsing
let auth = {
authenticated: false,
method: "none" as string,
- hasAuthFile: false,
hasEnvKey: !!process.env.OPENAI_API_KEY,
hasStoredApiKey: !!apiKeys.openai,
- hasEnvApiKey: !!process.env.OPENAI_API_KEY,
- // Additional fields for subscription/account detection
- hasSubscription: false,
- cliLoggedIn: false,
};
- // Check for OpenAI CLI auth file (~/.codex/auth.json or similar)
- const codexAuthPaths = [
- path.join(os.homedir(), ".codex", "auth.json"),
- path.join(os.homedir(), ".openai", "credentials"),
- path.join(os.homedir(), ".config", "openai", "credentials.json"),
- ];
-
- for (const authPath of codexAuthPaths) {
+ // Try to verify authentication using codex CLI command if CLI is installed
+ if (installed && cliPath) {
try {
- const authContent = await fs.readFile(authPath, "utf-8");
- const authData = JSON.parse(authContent);
- auth.hasAuthFile = true;
+ const { stdout: statusOutput } = await execAsync(`"${cliPath}" login status 2>&1`, {
+ timeout: 5000,
+ });
- // Check for subscription/tokens
- if (authData.subscription || authData.plan || authData.account_type) {
- auth.hasSubscription = true;
+ // Check if the output indicates logged in status
+ if (statusOutput && (statusOutput.includes('Logged in') || statusOutput.includes('Authenticated'))) {
auth.authenticated = true;
- auth.method = "subscription"; // Codex subscription (Plus/Team)
- } else if (authData.access_token || authData.api_key) {
- auth.cliLoggedIn = true;
- auth.authenticated = true;
- auth.method = "cli_verified"; // CLI logged in with account
+ auth.method = "cli_verified"; // CLI verified via login status command
}
- break;
- } catch {
- // Auth file not found at this path
+ } catch (error) {
+ // CLI check failed - user needs to login manually
+ console.log("[Setup] Codex login status check failed:", error);
}
}
- // Environment variable has highest priority
- if (auth.hasEnvApiKey) {
+ // Environment variable override
+ if (process.env.OPENAI_API_KEY) {
auth.authenticated = true;
auth.method = "env"; // OPENAI_API_KEY environment variable
}
diff --git a/apps/server/src/services/auto-mode-service.ts b/apps/server/src/services/auto-mode-service.ts
index 8015de91..4c44cd6e 100644
--- a/apps/server/src/services/auto-mode-service.ts
+++ b/apps/server/src/services/auto-mode-service.ts
@@ -18,6 +18,13 @@ import type { EventEmitter, EventType } from "../lib/events.js";
const execAsync = promisify(exec);
+// Model name mappings for Claude (matching electron version)
+const MODEL_MAP: Record = {
+ haiku: "claude-haiku-4-5",
+ sonnet: "claude-sonnet-4-20250514",
+ opus: "claude-opus-4-5-20251101",
+};
+
interface Feature {
id: string;
title: string;
@@ -25,6 +32,37 @@ interface Feature {
status: string;
priority?: number;
spec?: string;
+ model?: string; // Model to use for this feature
+}
+
+/**
+ * Get model string from feature's model property
+ * Supports model keys like "opus", "sonnet", "haiku" or full model strings
+ * Also supports OpenAI/Codex models like "gpt-5.2", "gpt-5.1-codex", etc.
+ */
+function getModelString(feature: Feature): string {
+ const modelKey = feature.model || "opus"; // Default to opus
+
+ // Check if it's an OpenAI/Codex model (starts with "gpt-" or "o" for O-series)
+ if (modelKey.startsWith("gpt-") || modelKey.startsWith("o")) {
+ console.log(`[AutoMode] Using OpenAI/Codex model from feature ${feature.id}: ${modelKey} (passing through)`);
+ return modelKey;
+ }
+
+ // If it's already a full Claude model string (contains "claude-"), use it directly
+ if (modelKey.includes("claude-")) {
+ console.log(`[AutoMode] Using Claude model from feature ${feature.id}: ${modelKey} (full model string)`);
+ return modelKey;
+ }
+
+ // Otherwise, look it up in the Claude model map
+ const modelString = MODEL_MAP[modelKey] || MODEL_MAP.opus;
+ if (modelString !== MODEL_MAP.opus || modelKey === "opus") {
+ console.log(`[AutoMode] Resolved Claude model for feature ${feature.id}: "${modelKey}" -> "${modelString}"`);
+ } else {
+ console.warn(`[AutoMode] Unknown model key "${modelKey}" for feature ${feature.id}, defaulting to "${modelString}"`);
+ }
+ return modelString;
}
interface RunningFeature {
@@ -199,8 +237,12 @@ export class AutoModeService {
// Build the prompt
const prompt = this.buildFeaturePrompt(feature);
- // Run the agent
- await this.runAgent(workDir, featureId, prompt, abortController);
+ // Get model from feature
+ const model = getModelString(feature);
+ console.log(`[AutoMode] Executing feature ${featureId} with model: ${model}`);
+
+ // Run the agent with the feature's model
+ await this.runAgent(workDir, featureId, prompt, abortController, undefined, model);
// Mark as waiting_approval for user review
await this.updateFeatureStatus(projectPath, featureId, "waiting_approval");
@@ -330,7 +372,12 @@ export class AutoModeService {
});
try {
- await this.runAgent(workDir, featureId, prompt, abortController, imagePaths);
+ // Load feature to get its model
+ const feature = await this.loadFeature(projectPath, featureId);
+ const model = feature ? getModelString(feature) : MODEL_MAP.opus;
+ console.log(`[AutoMode] Follow-up for feature ${featureId} using model: ${model}`);
+
+ await this.runAgent(workDir, featureId, prompt, abortController, imagePaths, model);
this.emitAutoModeEvent("auto_mode_feature_complete", {
featureId,
@@ -709,10 +756,23 @@ When done, summarize what you implemented and any notes for the developer.`;
featureId: string,
prompt: string,
abortController: AbortController,
- imagePaths?: string[]
+ imagePaths?: string[],
+ model?: string
): Promise {
+ const finalModel = model || MODEL_MAP.opus;
+ console.log(`[AutoMode] runAgent called for feature ${featureId} with model: ${finalModel}`);
+
+ // Check if this is an OpenAI/Codex model - Claude Agent SDK doesn't support these
+ if (finalModel.startsWith("gpt-") || finalModel.startsWith("o")) {
+ const errorMessage = `OpenAI/Codex models (like "${finalModel}") are not yet supported in server mode. ` +
+ `Please use a Claude model (opus, sonnet, or haiku) instead. ` +
+ `OpenAI/Codex models are only supported in the Electron app.`;
+ console.error(`[AutoMode] ${errorMessage}`);
+ throw new Error(errorMessage);
+ }
+
const options: Options = {
- model: "claude-opus-4-5-20251101",
+ model: finalModel,
maxTurns: 50,
cwd: workDir,
allowedTools: [