fix(hub,web): query Codex models via machine RPC instead of session cwd (#1186)

SessionChat fetched Codex models through the session-scoped endpoint,
so the CLI listed models in the session process cwd, where a missing
directory or project-level Codex config could skew or break the result.
Use the machine-scoped endpoint (already used by NewSession) and drop
the now-unused session route and RPC plumbing.

Fixes #1072
This commit is contained in:
weishu
2026-07-27 12:58:22 +08:00
committed by GitHub
parent da6f4cc5b0
commit 54bddd9db1
8 changed files with 4 additions and 76 deletions
-4
View File
@@ -294,10 +294,6 @@ export class RpcGateway {
}
}
async listCodexModelsForSession(sessionId: string): Promise<RpcListCodexModelsResponse> {
return await this.sessionRpc(sessionId, RPC_METHODS.ListCodexModels, {}, MODEL_LIST_RPC_TIMEOUT_MS) as RpcListCodexModelsResponse
}
async listCodexModelsForMachine(machineId: string): Promise<RpcListCodexModelsResponse> {
return await this.machineRpc(machineId, RPC_METHODS.ListCodexModels, {}, MODEL_LIST_RPC_TIMEOUT_MS) as RpcListCodexModelsResponse
}
-4
View File
@@ -1696,10 +1696,6 @@ export class SyncEngine {
return await this.rpcGateway.listSkills(sessionId, flavor)
}
async listCodexModelsForSession(sessionId: string): Promise<RpcListCodexModelsResponse> {
return await this.rpcGateway.listCodexModelsForSession(sessionId)
}
async listCodexModelsForMachine(machineId: string): Promise<RpcListCodexModelsResponse> {
return await this.rpcGateway.listCodexModelsForMachine(machineId)
}
-21
View File
@@ -69,12 +69,6 @@ function createApp(session: Session, opts?: {
const applySessionConfig = async (sessionId: string, config: Record<string, unknown>) => {
applySessionConfigCalls.push([sessionId, config])
}
const listCodexModelsForSession = async () => ({
success: true,
models: [
{ id: 'gpt-5.5', displayName: 'GPT-5.5', isDefault: true }
]
})
const listOpencodeModelsForSession = async () => ({
success: true,
availableModels: [
@@ -128,7 +122,6 @@ function createApp(session: Session, opts?: {
? { ok: true, sessionId: session.id, session }
: { ok: false, reason: 'not-found' },
applySessionConfig,
listCodexModelsForSession,
listCursorModelsForSession,
listOpencodeModelsForSession,
listOpencodeReasoningEffortOptionsForSession,
@@ -717,20 +710,6 @@ describe('sessions routes', () => {
expect(localApp.applySessionConfigCalls).toEqual([])
})
it('returns Codex models for active Codex sessions', async () => {
const { app } = createApp(createSession())
const response = await app.request('/api/sessions/session-1/codex-models')
expect(response.status).toBe(200)
expect(await response.json()).toEqual({
success: true,
models: [
{ id: 'gpt-5.5', displayName: 'GPT-5.5', isDefault: true }
]
})
})
it('returns OpenCode reasoning effort options for active OpenCode sessions', async () => {
const session = createSession({
metadata: { path: '/tmp/project', host: 'localhost', flavor: 'opencode' }
-30
View File
@@ -766,36 +766,6 @@ export function createSessionsRoutes(getSyncEngine: () => SyncEngine | null): Ho
}
})
app.get('/sessions/:id/codex-models', async (c) => {
const engine = requireSyncEngine(c, getSyncEngine)
if (engine instanceof Response) {
return engine
}
const sessionResult = requireSessionFromParam(c, engine, { requireActive: true })
if (sessionResult instanceof Response) {
return sessionResult
}
const flavor = sessionResult.session.metadata?.flavor ?? 'claude'
if (flavor !== 'codex') {
return c.json({
success: false,
error: 'Codex models are only available for Codex sessions'
}, 400)
}
try {
const result = await engine.listCodexModelsForSession(sessionResult.sessionId)
return c.json(result)
} catch (error) {
return c.json({
success: false,
error: error instanceof Error ? error.message : 'Failed to list Codex models'
}, 500)
}
})
app.get('/sessions/:id/opencode-models', async (c) => {
const engine = requireSyncEngine(c, getSyncEngine)
if (engine instanceof Response) {
-6
View File
@@ -653,12 +653,6 @@ export class ApiClient {
)
}
async getSessionCodexModels(sessionId: string): Promise<CodexModelsResponse> {
return await this.request<CodexModelsResponse>(
`/api/sessions/${encodeURIComponent(sessionId)}/codex-models`
)
}
async getSessionOpencodeModels(sessionId: string): Promise<OpencodeModelsResponse> {
return await this.request<OpencodeModelsResponse>(
`/api/sessions/${encodeURIComponent(sessionId)}/opencode-models`
+1 -1
View File
@@ -544,7 +544,7 @@ function SessionChatInner(props: SessionChatProps) {
const codexCollaborationModeSupported = agentFlavor === 'codex' && !controlledByUser
const codexModelsState = useCodexModels({
api: props.api,
sessionId: props.session.id,
machineId: props.session.metadata?.machineId ?? null,
enabled: agentFlavor === 'codex' && props.session.active && !controlledByUser
})
const effectiveCodexServiceTier = agentFlavor === 'codex'
+3 -9
View File
@@ -5,7 +5,6 @@ import { queryKeys } from '@/lib/query-keys'
export function useCodexModels(args: {
api: ApiClient | null
sessionId?: string | null
machineId?: string | null
enabled?: boolean
}): {
@@ -13,11 +12,9 @@ export function useCodexModels(args: {
isLoading: boolean
error: string | null
} {
const { api, sessionId, machineId } = args
const enabled = Boolean(args.enabled && api && (sessionId || machineId))
const queryKey = sessionId
? queryKeys.sessionCodexModels(sessionId)
: queryKeys.machineCodexModels(machineId ?? 'unknown')
const { api, machineId } = args
const enabled = Boolean(args.enabled && api && machineId)
const queryKey = queryKeys.machineCodexModels(machineId ?? 'unknown')
const query = useQuery({
queryKey,
@@ -25,9 +22,6 @@ export function useCodexModels(args: {
if (!api) {
throw new Error('API unavailable')
}
if (sessionId) {
return await api.getSessionCodexModels(sessionId)
}
if (machineId) {
return await api.getMachineCodexModels(machineId)
}
-1
View File
@@ -15,7 +15,6 @@ export const queryKeys = {
staged ? 'staged' : 'unstaged'
] as const,
slashCommands: (sessionId: string) => ['slash-commands', sessionId] as const,
sessionCodexModels: (sessionId: string) => ['session-codex-models', sessionId] as const,
sessionCursorModels: (sessionId: string) => ['session-cursor-models', sessionId] as const,
sessionCursorChatStore: (sessionId: string) => ['session-cursor-chat-store', sessionId] as const,
sessionPiModels: (sessionId: string) => ['session-pi-models', sessionId] as const,