(props.initialInputMethod)
+const isAgentIdentityInput = computed(() => inputMethod.value === 'agent_identity')
const authCodeInput = ref('')
const sessionKeyInput = ref('')
const refreshTokenInput = ref('')
@@ -925,6 +935,7 @@ const methodOptionCount = computed(() => [
props.showSessionTokenOption,
props.showAccessTokenOption,
props.showCodexSessionImportOption,
+ props.showAgentIdentityOption,
props.showCodexPatOption,
props.showSsoOption
].filter(Boolean).length)
diff --git a/frontend/src/components/account/__tests__/CreateAccountModal.spec.ts b/frontend/src/components/account/__tests__/CreateAccountModal.spec.ts
index 7bfd714011..22cee856b4 100644
--- a/frontend/src/components/account/__tests__/CreateAccountModal.spec.ts
+++ b/frontend/src/components/account/__tests__/CreateAccountModal.spec.ts
@@ -67,11 +67,11 @@ const OAuthAuthorizationFlowStub = defineComponent({
props: {
showManualOption: Boolean,
showCodexSessionImportOption: Boolean,
+ showAgentIdentityOption: Boolean,
showCodexPatOption: Boolean,
initialInputMethod: String,
- agentIdentityOnly: Boolean,
- titleOverride: String,
},
+ data: () => ({ inputMethod: 'manual' }),
emits: ['import-codex-session', 'import-codex-pat'],
template: `
@@ -155,54 +155,34 @@ describe('CreateAccountModal OpenAI long-context billing', () => {
expect(createAccountMock.mock.calls[0]?.[0]?.extra?.openai_long_context_billing_enabled).toBe(false)
})
- it('shows Agent Identity as a separate OpenAI account type', async () => {
+ it('exposes Agent Identity in the OpenAI authorization methods', async () => {
const wrapper = mountModal()
await selectButtonByText(wrapper, 'OpenAI')
- await wrapper.get('[data-testid="openai-account-type-agent-identity"]').trigger('click')
- await wrapper.get('form#create-account-form input[type="text"]').setValue('Agent Identity')
+ await wrapper.get('form#create-account-form input[type="text"]').setValue('OpenAI account')
await wrapper.get('form#create-account-form').trigger('submit.prevent')
const flow = wrapper.getComponent(OAuthAuthorizationFlowStub)
- expect(flow.props('showManualOption')).toBe(false)
+ expect(flow.props('showManualOption')).toBe(true)
expect(flow.props('showCodexSessionImportOption')).toBe(true)
- expect(flow.props('showCodexPatOption')).toBe(false)
- expect(flow.props('initialInputMethod')).toBe('codex_session')
- expect(flow.props('agentIdentityOnly')).toBe(true)
- expect(flow.props('titleOverride')).toBe('Agent Identity')
+ expect(flow.props('showAgentIdentityOption')).toBe(true)
+ expect(flow.props('showCodexPatOption')).toBe(true)
+ expect(flow.props('initialInputMethod')).toBe('manual')
})
it.each([
['camelCase', { authMode: 'agentIdentity', agentIdentity: { agentRuntimeId: 'runtime' } }],
['nested identity without auth_mode', { agent_identity: { agent_runtime_id: 'runtime' } }],
])('accepts backend-compatible %s Agent Identity imports', async (_name, content) => {
- const wrapper = mountModal()
- await selectButtonByText(wrapper, 'OpenAI')
- await wrapper.get('[data-testid="openai-account-type-agent-identity"]').trigger('click')
- await wrapper.get('form#create-account-form input[type="text"]').setValue('Agent Identity')
- await wrapper.get('form#create-account-form').trigger('submit.prevent')
+ const wrapper = await openCodexImportStep()
+ const flow = wrapper.getComponent(OAuthAuthorizationFlowStub)
+ flow.vm.inputMethod = 'agent_identity'
- wrapper.getComponent(OAuthAuthorizationFlowStub).vm.$emit('import-codex-session', JSON.stringify(content))
+ flow.vm.$emit('import-codex-session', JSON.stringify(content))
await flushPromises()
expect(importCodexSessionMock).toHaveBeenCalledTimes(1)
})
- it('shows Codex PAT as a separate OpenAI account type', async () => {
- const wrapper = mountModal()
- await selectButtonByText(wrapper, 'OpenAI')
- await wrapper.get('[data-testid="openai-account-type-codex-pat"]').trigger('click')
- await wrapper.get('form#create-account-form input[type="text"]').setValue('Codex PAT')
- await wrapper.get('form#create-account-form').trigger('submit.prevent')
-
- const flow = wrapper.getComponent(OAuthAuthorizationFlowStub)
- expect(flow.props('showManualOption')).toBe(false)
- expect(flow.props('showCodexSessionImportOption')).toBe(false)
- expect(flow.props('showCodexPatOption')).toBe(true)
- expect(flow.props('initialInputMethod')).toBe('codex_pat')
- expect(flow.props('agentIdentityOnly')).toBe(false)
- expect(flow.props('titleOverride')).toBe('Codex PAT')
- })
-
it('sends true explicitly when OpenAI long-context billing is enabled', async () => {
await submitApiKeyAccount('openai', true)
diff --git a/frontend/src/composables/useAccountOAuth.ts b/frontend/src/composables/useAccountOAuth.ts
index a75300c748..e78a19a411 100644
--- a/frontend/src/composables/useAccountOAuth.ts
+++ b/frontend/src/composables/useAccountOAuth.ts
@@ -3,7 +3,7 @@ import { useAppStore } from '@/stores/app'
import { adminAPI } from '@/api/admin'
export type AddMethod = 'oauth' | 'setup-token'
-export type AuthInputMethod = 'manual' | 'cookie' | 'refresh_token' | 'mobile_refresh_token' | 'session_token' | 'access_token' | 'codex_session' | 'codex_pat' | 'sso_cookie'
+export type AuthInputMethod = 'manual' | 'cookie' | 'refresh_token' | 'mobile_refresh_token' | 'session_token' | 'access_token' | 'codex_session' | 'agent_identity' | 'codex_pat' | 'sso_cookie'
export interface OAuthState {
authUrl: string
diff --git a/frontend/src/i18n/locales/en/admin/accounts.ts b/frontend/src/i18n/locales/en/admin/accounts.ts
index 14233f1f6a..f935b09513 100644
--- a/frontend/src/i18n/locales/en/admin/accounts.ts
+++ b/frontend/src/i18n/locales/en/admin/accounts.ts
@@ -108,8 +108,6 @@ export default {
types: {
oauth: 'OAuth',
chatgptOauth: 'ChatGPT OAuth',
- agentIdentity: 'Import Codex auth.json',
- codexPat: 'Personal access token',
responsesApi: 'Responses API',
googleOauth: 'Google OAuth',
codeAssist: 'Code Assist',
@@ -837,6 +835,7 @@ export default {
codexSessionImportFailed: 'Failed to import Codex account',
codexSessionImportSuccess: 'Import completed: created {created}, updated {updated}, skipped {skipped}',
codexSessionImportPartial: 'Partial success: created {created}, updated {updated}, skipped {skipped}, failed {failed}',
+ agentIdentityAuth: 'Agent Identity auth.json',
agentIdentityDesc: 'Import a Codex Agent Identity auth.json. No OAuth access or refresh token is stored.',
agentIdentityInputLabel: 'Agent Identity auth.json',
agentIdentityPlaceholder: 'Paste one Agent Identity auth.json object',
diff --git a/frontend/src/i18n/locales/zh/admin/accounts.ts b/frontend/src/i18n/locales/zh/admin/accounts.ts
index c873edc861..1f5415a3f1 100644
--- a/frontend/src/i18n/locales/zh/admin/accounts.ts
+++ b/frontend/src/i18n/locales/zh/admin/accounts.ts
@@ -227,8 +227,6 @@ export default {
types: {
oauth: 'OAuth',
chatgptOauth: 'ChatGPT OAuth',
- agentIdentity: '导入 Codex auth.json',
- codexPat: '个人访问令牌',
responsesApi: 'Responses API',
googleOauth: 'Google OAuth',
codeAssist: 'Code Assist',
@@ -924,6 +922,7 @@ export default {
codexSessionImportFailed: 'Codex 账号导入失败',
codexSessionImportSuccess: '导入完成:新增 {created},更新 {updated},跳过 {skipped}',
codexSessionImportPartial: '部分成功:新增 {created},更新 {updated},跳过 {skipped},失败 {failed}',
+ agentIdentityAuth: 'Agent Identity auth.json',
agentIdentityDesc: '导入 Codex Agent Identity auth.json,不保存 OAuth access token 或 refresh token。',
agentIdentityInputLabel: 'Agent Identity auth.json',
agentIdentityPlaceholder: '粘贴一个 Agent Identity auth.json 对象',