@@ -567,6 +567,7 @@ type accountResponse struct {
567567 CreditSkipUsageWindow bool `json:"credit_skip_usage_window"`
568568 SkipWarmTier bool `json:"skip_warm_tier"`
569569 AccountType string `json:"account_type,omitempty"`
570+ AccessTokenType string `json:"access_token_type,omitempty"`
570571 OpenAIResponsesAPI bool `json:"openai_responses_api,omitempty"`
571572 BaseURL string `json:"base_url,omitempty"`
572573 Models []string `json:"models,omitempty"`
@@ -653,6 +654,16 @@ func accountEmailDomain(email string) string {
653654 return domain
654655}
655656
657+ func accountAccessTokenType (row * database.AccountRow ) string {
658+ if row == nil {
659+ return ""
660+ }
661+ if tokenType := strings .TrimSpace (row .GetCredential ("access_token_type" )); tokenType != "" {
662+ return tokenType
663+ }
664+ return accessTokenTypeForToken (row .GetCredential ("access_token" ))
665+ }
666+
656667type schedulerBreakdownResponse struct {
657668 UnauthorizedPenalty float64 `json:"unauthorized_penalty"`
658669 RateLimitPenalty float64 `json:"rate_limit_penalty"`
@@ -719,6 +730,7 @@ func (h *Handler) ListAccounts(c *gin.Context) {
719730 CreditSkipUsageWindow : row .CreditSkipUsageWindow ,
720731 SkipWarmTier : row .SkipWarmTier ,
721732 AccountType : row .Type ,
733+ AccessTokenType : accountAccessTokenType (row ),
722734 OpenAIResponsesAPI : isOpenAIResponsesAccount ,
723735 BaseURL : baseURL ,
724736 Models : row .GetCredentialStringSlice ("models" ),
@@ -1812,40 +1824,13 @@ func (h *Handler) AddATAccount(c *gin.Context) {
18121824 successCount ++
18131825 h .db .InsertAccountEventAsync (id , "added" , "manual_at" )
18141826
1815- // 解析 AT JWT 提取账号信息(email、plan_type、account_id、过期时间)
1816- atInfo := auth .ParseAccessToken (at )
1817-
1818- // 热加载到内存池(AT-only,无 RT)
1819- newAcc := & auth.Account {
1820- DBID : id ,
1821- AccessToken : at ,
1822- ExpiresAt : time .Now ().Add (1 * time .Hour ),
1823- ProxyURL : req .ProxyURL ,
1824- }
1825- if atInfo != nil {
1826- newAcc .Email = atInfo .Email
1827- newAcc .AccountID = atInfo .ChatGPTAccountID
1828- newAcc .PlanType = atInfo .PlanType
1829- if ! atInfo .ExpiresAt .IsZero () {
1830- newAcc .ExpiresAt = atInfo .ExpiresAt
1831- }
1832- if ! atInfo .SubscriptionExpiresAt .IsZero () {
1833- newAcc .SubscriptionExpiresAt = atInfo .SubscriptionExpiresAt
1834- }
1835- }
1827+ // 热加载到内存池(AT-only,无 RT)。codex_at 不走 JWT 解码,
1828+ // 身份信息后续由 wham 用量查询补齐。
1829+ newAcc := accountFromCredentialSeed (id , req .ProxyURL , seed )
18361830 h .store .AddAccount (newAcc )
18371831
1838- // 将解析到的信息持久化到数据库
1839- if atInfo != nil {
1840- creds := map [string ]interface {}{
1841- "email" : atInfo .Email ,
1842- "account_id" : atInfo .ChatGPTAccountID ,
1843- "plan_type" : atInfo .PlanType ,
1844- "expires_at" : newAcc .ExpiresAt .Format (time .RFC3339 ),
1845- }
1846- if ! atInfo .SubscriptionExpiresAt .IsZero () {
1847- creds ["subscription_expires_at" ] = atInfo .SubscriptionExpiresAt .Format (time .RFC3339 )
1848- }
1832+ // 将解析/识别到的信息持久化到数据库。
1833+ if creds := tokenCredentialMap (seed ); len (creds ) > 0 {
18491834 if err := h .db .UpdateCredentials (ctx , id , creds ); err != nil {
18501835 log .Printf ("AT 账号 %d 更新 credentials 失败: %v" , id , err )
18511836 }
@@ -3242,6 +3227,7 @@ type recycleBinAccountResponse struct {
32423227 Email string `json:"email"`
32433228 PlanType string `json:"plan_type"`
32443229 ATOnly bool `json:"at_only"`
3230+ AccessTokenType string `json:"access_token_type,omitempty"`
32453231 OpenAIResponsesAPI bool `json:"openai_responses_api"`
32463232 BaseURL string `json:"base_url,omitempty"`
32473233 Models []string `json:"models,omitempty"`
@@ -3281,6 +3267,7 @@ func (h *Handler) ListRecycleBinAccounts(c *gin.Context) {
32813267 Email : email ,
32823268 PlanType : planType ,
32833269 ATOnly : ! isOpenAIResponsesAccount && row .GetCredential ("refresh_token" ) == "" && row .GetCredential ("access_token" ) != "" ,
3270+ AccessTokenType : accountAccessTokenType (row ),
32843271 OpenAIResponsesAPI : isOpenAIResponsesAccount ,
32853272 BaseURL : baseURL ,
32863273 Models : row .GetCredentialStringSlice ("models" ),
0 commit comments