Compare commits

...

2 Commits

4 changed files with 59 additions and 5 deletions
@@ -3,6 +3,7 @@ import { Modal } from '@/components/ui/Modal';
import { Button } from '@/components/ui/Button';
import { LoadingSpinner } from '@/components/ui/LoadingSpinner';
import { Input } from '@/components/ui/Input';
import { ToggleSwitch } from '@/components/ui/ToggleSwitch';
import type {
PrefixProxyEditorField,
PrefixProxyEditorFieldValue,
@@ -141,6 +142,18 @@ export function AuthFilesPrefixProxyEditorModal(props: AuthFilesPrefixProxyEdito
disabled={disableControls || editor.saving || !editor.json}
onChange={(e) => onChange('priority', e.target.value)}
/>
{editor.providerKey === 'codex' && (
<div className="form-group">
<label>{t('ai_providers.codex_websockets_label')}</label>
<ToggleSwitch
checked={editor.websockets}
onChange={(value) => onChange('websockets', value)}
disabled={disableControls || editor.saving || !editor.json}
ariaLabel={t('ai_providers.codex_websockets_label')}
/>
<div className="hint">{t('ai_providers.codex_websockets_hint')}</div>
</div>
)}
<div className="form-group">
<label>{t('auth_files.headers_label')}</label>
<textarea
+1 -1
View File
@@ -222,7 +222,7 @@ export const parseDisableCoolingValue = (value: unknown): boolean | undefined =>
};
export const readCodexAuthFileWebsockets = (value: Record<string, unknown>): boolean =>
parseDisableCoolingValue(value.websockets) ?? false;
parseDisableCoolingValue(value.websockets ?? value.websocket) ?? false;
export const applyCodexAuthFileWebsockets = (
value: Record<string, unknown>,
@@ -3,7 +3,12 @@ import { useTranslation } from 'react-i18next';
import { authFilesApi, type AuthFileFieldsPatch } from '@/services/api';
import type { AuthFileItem } from '@/types';
import { useNotificationStore } from '@/stores';
import { parsePriorityValue } from '@/features/authFiles/constants';
import {
applyCodexAuthFileWebsockets,
normalizeProviderKey,
parsePriorityValue,
readCodexAuthFileWebsockets,
} from '@/features/authFiles/constants';
type AuthFileHeaders = Record<string, string>;
type AuthFileHeadersErrorKey =
@@ -14,9 +19,15 @@ type AuthFileContentErrorKey =
| 'auth_files.prefix_proxy_invalid_json'
| 'auth_files.prefix_proxy_html_challenge';
export type PrefixProxyEditorField = 'prefix' | 'proxyUrl' | 'priority' | 'note' | 'headersText';
export type PrefixProxyEditorField =
| 'prefix'
| 'proxyUrl'
| 'priority'
| 'websockets'
| 'note'
| 'headersText';
export type PrefixProxyEditorFieldValue = string;
export type PrefixProxyEditorFieldValue = string | boolean;
export type PrefixProxyEditorState = {
fileName: string;
@@ -28,9 +39,12 @@ export type PrefixProxyEditorState = {
rawText: string;
invalidContentPreview: string;
json: Record<string, unknown> | null;
providerKey: string;
prefix: string;
proxyUrl: string;
priority: string;
websockets: boolean;
websocketsTouched: boolean;
note: string;
noteTouched: boolean;
headersText: string;
@@ -242,6 +256,14 @@ const buildAuthFileFieldsPatch = (
}
}
if (editor.providerKey === 'codex' && editor.websocketsTouched) {
const originalWebsockets = readCodexAuthFileWebsockets(original);
const nextWebsockets = Boolean(editor.websockets);
if (nextWebsockets !== originalWebsockets) {
patch.websockets = nextWebsockets;
}
}
if (editor.headersTouched) {
const { value: parsedHeaders, errorKey } = parseHeadersText(editor.headersText);
if (errorKey) {
@@ -265,7 +287,7 @@ const buildPrefixProxyUpdatedText = (
): string => {
if (!editor?.json) return editor?.rawText ?? '';
const patch = buildAuthFileFieldsPatch(editor, resolveHeadersError);
const next: Record<string, unknown> = { ...editor.json };
let next: Record<string, unknown> = { ...editor.json };
if (patch.prefix !== undefined) {
if (patch.prefix) {
next.prefix = patch.prefix;
@@ -299,6 +321,10 @@ const buildPrefixProxyUpdatedText = (
applyHeadersPatch(next, patch.headers);
if (patch.websockets !== undefined) {
next = applyCodexAuthFileWebsockets(next, patch.websockets);
}
return JSON.stringify(next);
};
@@ -332,6 +358,7 @@ export function useAuthFilesPrefixProxyEditor(
const openPrefixProxyEditor = async (file: AuthFileItem) => {
const name = file.name;
const fileProviderKey = normalizeProviderKey(String(file.type ?? file.provider ?? ''));
if (disableControls) return;
if (prefixProxyEditor?.fileName === name) {
@@ -349,9 +376,12 @@ export function useAuthFilesPrefixProxyEditor(
rawText: '',
invalidContentPreview: '',
json: null,
providerKey: fileProviderKey,
prefix: '',
proxyUrl: '',
priority: '',
websockets: false,
websocketsTouched: false,
note: '',
noteTouched: false,
headersText: '',
@@ -390,9 +420,13 @@ export function useAuthFilesPrefixProxyEditor(
const json = { ...(parsed as Record<string, unknown>) };
const originalText = JSON.stringify(json);
const providerKey = normalizeProviderKey(
String(json.type ?? json.provider ?? file.type ?? file.provider ?? '')
);
const prefix = typeof json.prefix === 'string' ? json.prefix : '';
const proxyUrl = typeof json.proxy_url === 'string' ? json.proxy_url : '';
const priority = parsePriorityValue(json.priority);
const websockets = providerKey === 'codex' ? readCodexAuthFileWebsockets(json) : false;
const note = typeof json.note === 'string' ? json.note : '';
const headers = json.headers;
let headersText = '';
@@ -412,9 +446,12 @@ export function useAuthFilesPrefixProxyEditor(
rawText: originalText,
invalidContentPreview: '',
json,
providerKey,
prefix,
proxyUrl,
priority: priority !== undefined ? String(priority) : '',
websockets,
websocketsTouched: false,
note,
noteTouched: false,
headersText,
@@ -442,6 +479,9 @@ export function useAuthFilesPrefixProxyEditor(
if (field === 'prefix') return { ...prev, prefix: String(value) };
if (field === 'proxyUrl') return { ...prev, proxyUrl: String(value) };
if (field === 'priority') return { ...prev, priority: String(value) };
if (field === 'websockets') {
return { ...prev, websockets: Boolean(value), websocketsTouched: true };
}
if (field === 'note') return { ...prev, note: String(value), noteTouched: true };
if (field === 'headersText') {
const headersText = String(value);
+1
View File
@@ -15,6 +15,7 @@ export type AuthFileFieldsPatch = {
proxy_url?: string;
headers?: Record<string, string>;
priority?: number;
websockets?: boolean;
note?: string;
};
type AuthFileBatchFailure = { name: string; error: string };