Commit Graph
2191 Commits
Author SHA1 Message Date
erioandClaude Opus 4.6 4aada8a336 fix: resolve golangci-lint errors (gofmt, staticcheck, unused)
- Fix struct field alignment in dto/types.go, settings_view.go,
  sora_generation_service.go for gofmt compliance
- Remove embedded field "Account" from selector in account_handler.go (QF1008)
- Remove unused settingService field from SoraGDriveOAuthService
- Replace deprecated google.CredentialsFromJSON with CredentialsFromJSONWithParams (SA1019)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 05:13:33 +08:00
erioandClaude Opus 4.6 ea5e5dd9c7 feat: display client affinity count badge in account status column
Add colored circle badge showing affinity client count before the account
status indicator. Badge color reflects count severity (gray=0, green=1-5,
yellow=6-15, red=16+). Tooltip shows full client ID list on hover.

Backend: AccountHandler batch queries reverse affinity index via
GetAccountAffinityClientsBatch, returns affinity_client_count and
affinity_clients in DTO. GatewayCache interface extended with the new
batch method backed by a Lua script (get_affinity_clients.lua).

All test mocks synchronized with updated GatewayCache interface.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 04:52:10 +08:00
erioandClaude Opus 4.6 b9dc2e8eb5 refactor: remove dead RemoveClientAffinity code, add affinity scheduling tests
- Remove RemoveClientAffinity from GatewayCache interface, implementation,
  Lua script, and all test mocks (never called in production code)
- Add 26 unit tests for affinity scheduling: filterByMinAffinityCount,
  populateAffinityCounts, Layer 1/2 sort chain integration

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 04:26:08 +08:00
erioandClaude Opus 4.6 d707c1f93f feat: client affinity reverse index and balanced scheduling
- Separate clientAffinityTTL (24h) from stickySessionTTL (1h)
- Atomic Lua dual-write for forward (client→accounts) and reverse
  (account→clients) affinity indexes with lazy expiry cleanup
- Extract Lua scripts to standalone .lua files with //go:embed
- Add filterByMinAffinityCount to Layer 1 & 2 scheduling so new
  clients are routed to accounts with fewest existing affinities
- Skip Redis query when no affinity-enabled accounts exist (zero
  overhead for non-affinity users)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 04:10:54 +08:00
erio fbdba40f59 chore: bump version to 0.1.92.11 2026-03-07 03:16:02 +08:00
erioandClaude Opus 4.6 8d85cb57f1 feat: add client affinity toggle to create account modal
The client affinity setting was only available when editing an account.
Now it's also available during account creation for all Anthropic
platform types (OAuth, Setup Token, API Key).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 03:14:01 +08:00
erio 29d948bbfd Merge branch 'worktree-feature/sora' into release/custom-0.1.92 2026-03-07 00:35:35 +08:00
erioandClaude Opus 4.6 dac451ee0b feat(frontend): move provider selection into drawer and remove quota field
- Move storage provider selection (S3/GDrive) from separate modal into
  the drawer itself, shown as the first step when creating a new profile
- Provider type is locked once selected (read-only badge in header)
- Remove default_storage_quota_gb field from form and table column
- Remove unused formatStorageQuotaGB function and providerSelectOpen ref

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 00:34:11 +08:00
erioandClaude Opus 4.6 8071e9c4d8 fix(frontend): vertically center table row content in storage table
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 00:25:55 +08:00
erioandClaude Opus 4.6 a21f7d650b feat: display daily/weekly/total quota dimensions in account list
- Add quota_daily_limit/used and quota_weekly_limit/used to DTO and
  frontend Account type
- AccountCapacityCell shows D (daily), W (weekly), and $ (total) badges
  with color-coded status (green/yellow/red)
- AccountActionMenu shows reset button when any quota dimension is set
- Extract quotaBadgeClass/quotaBadgeTooltip as shared functions

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 00:18:41 +08:00
erioandClaude Opus 4.6 e6b3808dcd fix(frontend): reduce action column height in storage table
Change flex-wrap gap-2 to items-center gap-1 to keep buttons on one line.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 00:15:06 +08:00
erio 5acf888d06 Merge remote-tracking branch 'origin/release/custom-0.1.92' into worktree-feature/sora 2026-03-06 23:58:40 +08:00
erioandClaude Opus 4.6 9e107fae73 feat(sora): improve storage management page with split columns, test buttons, quota and video stats
- Split compound "Profile" column into separate Profile ID and Name columns
- Replace "Endpoint" column with "Storage Path" showing bucket/prefix or folder info
- Add GDrive quota display (capacity/used) via new backend API endpoint
- Add video count statistics per storage type via new backend API endpoint
- Add inline test button per profile with 15s timeout and per-profile loading state
- Backend: GetQuotaInfo, CountByStorageType, GetGDriveQuota, GetStorageVideoStats

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 23:58:27 +08:00
erioandClaude Opus 4.6 6a7bcabb6f feat(frontend): add GDrive storage test button in profile drawer
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 22:56:23 +08:00
erio 298f5c1baf feat(sora): add GDrive full-cycle test endpoint (upload/download/delete) 2026-03-06 22:33:37 +08:00
erio 3f1ca43514 debug: add OAuth exchange logging 2026-03-06 21:21:29 +08:00
erioandClaude Opus 4.6 33ab8413db feat: support independent daily/weekly/total quota limits for API Key accounts
Replace single-period-selector (三选一) with three independently configurable
quota dimensions (日/周/总) that can all be set simultaneously. Account is
paused when ANY dimension is exceeded. Periodic quotas (daily/weekly) use
lazy reset via atomic SQL — no cron job needed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 21:20:29 +08:00
erioandClaude Opus 4.6 e3f9774eda fix(sora): add GDrive OAuth callback page for postMessage flow
The OAuth flow opens a popup window that redirects to /admin/gdrive-oauth-callback,
but this route and page were missing. Add the callback view that extracts the
authorization code from the URL and sends it back to the opener window via
postMessage, completing the OAuth authorization flow.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 21:10:02 +08:00
erio e0a9c34067 Merge branch 'release/custom-0.1.92' into worktree-feature/sora 2026-03-06 20:47:06 +08:00
erioandClaude Opus 4.6 ad54040c07 feat(sora): add Google Drive storage backend with unified storage abstraction
- Define SoraObjectStorage interface abstracting S3 and GDrive backends
- Implement SoraGDriveStorage with OAuth2 and Service Account auth
- Add SoraStorageRouter to route requests based on active profile provider
- Add GDrive OAuth handler for authorization flow (start + callback)
- Extend profile model with provider, auth_type, and GDrive-specific fields
- Update frontend UI with provider selection, dynamic form fields, and i18n
- Migrate API paths from /sora-s3 to /sora-storage (old paths preserved)
- All existing S3 functionality remains backward compatible

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 20:45:51 +08:00
erioandClaude Opus 4.6 d7a3c7f8a8 chore: bump version to 0.1.92.10
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 20:07:02 +08:00
erioandClaude Opus 4.6 465a58a1c9 fix: replace CTE with inline UPDATE to prevent lost update on period reset
CTE snapshot in READ COMMITTED can cause concurrent requests during
period reset to lose one increment. Inline CASE in single UPDATE
ensures PostgreSQL re-evaluates all expressions with latest row data.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 20:07:02 +08:00
erioandClaude Opus 4.6 9430776393 chore: bump version to 0.1.92.9
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 20:03:29 +08:00
erioandClaude Opus 4.6 c087e94413 fix: use UTC timezone in quota period SQL and reset period_start on quota reset
- Use NOW() AT TIME ZONE 'UTC' to ensure consistent timestamps
  regardless of database timezone setting
- Clear quota_period_start when manually resetting quota so a
  fresh period starts from next usage

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 20:03:16 +08:00
erioandClaude Opus 4.6 a4ee71d796 chore: bump version to 0.1.92.8
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 19:51:52 +08:00
erioandClaude Opus 4.6 e976409ba1 feat: add periodic quota reset for API Key accounts
Support daily/weekly automatic quota reset using a rolling period
anchored to first usage. Implements lazy reset via atomic CTE SQL
in IncrementQuotaUsed - no cron job needed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 19:51:41 +08:00
erioandClaude Opus 4.6 da99de82e9 chore: bump version to 0.1.92.7
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 18:55:38 +08:00
erioandClaude Opus 4.6 e8e5acb9e7 revert: remove client affinity count display infrastructure
Remove frontend badge/tooltip and backend counting/query infrastructure
for client affinity. Core client affinity scheduling logic is preserved.

Removed:
- GatewayCache injection in AccountHandler
- GetAccountAffinityCount/Batch/Clients methods and interface
- AffinityClientInfo struct and ClientAffinityTTL function
- /affinity-clients API endpoint and route
- Reverse index (account_affinity:*) Lua scripts
- Frontend blue badge, tooltip, and lazy-load logic
- affinity_client_count field from types and response

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 18:47:52 +08:00
erioandClaude Opus 4.6 77ae2bcccb fix: exclude Antigravity from OAuth 401 temp-unschedulable and escalation logic
PR #723 changed all OAuth 401 to use SetTempUnschedulable instead of SetError,
and PR #761 added 401 escalation logic in tryTempUnschedulable. Both caused
non-OpenAI accounts to frequently become temporarily unschedulable.

- HandleUpstreamError case 401: limit temp-unschedulable to OpenAI OAuth only,
  other platforms (Anthropic/Gemini/Antigravity) revert to original SetError
- tryTempUnschedulable: skip 401 escalation for Antigravity, let its
  applyErrorPolicy temp_unschedulable_rules handle 401 naturally

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 18:32:57 +08:00
erioandClaude Opus 4.6 6315dea094 fix: prevent reverse affinity index from premature expiration
The reverse index account_affinity:{accountID} was using the same 1h
EXPIRE as the forward index. But the forward key EXPIRE refreshes on
every client request, while the reverse key only refreshes when a
request is routed to that specific account. This caused reverse keys
to expire prematurely.

Fix: set reverse key EXPIRE to 24h as safety net, rely on
ZREMRANGEBYSCORE for member-level expiration. Also clean up empty
keys after member cleanup.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 18:04:52 +08:00
erioandClaude Opus 4.6 c7e88ffcf1 feat: extend client affinity to all Anthropic account types
- Backend: expand IsClientAffinityEnabled() to support all Anthropic
  accounts (OAuth/SetupToken/APIKey), not just OAuth/SetupToken
- Frontend: show client affinity toggle for all Anthropic accounts
- Frontend: fix save logic to properly chain extra field updates
- Antigravity accounts explicitly excluded from client affinity

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 17:46:00 +08:00
erioandClaude Opus 4.6 fb5f471fe1 feat: extend client affinity to all Anthropic account types
- Backend: expand IsClientAffinityEnabled() to support all Anthropic
  accounts (OAuth/SetupToken/APIKey), not just OAuth/SetupToken
- Frontend: show client affinity toggle for all Anthropic accounts
- Frontend: fix save logic to properly chain extra field updates
- Antigravity accounts explicitly excluded from client affinity

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 17:44:27 +08:00
erio 5f4561306f chore: bump version to 0.1.92.5
Made-with: Cursor
2026-03-06 17:31:27 +08:00
erio 6b31b34672 feat: extend client affinity support to Antigravity and Anthropic APIKey accounts
Made-with: Cursor
2026-03-06 17:31:18 +08:00
erioandClaude Opus 4.6 af5d5dbcbc chore: bump version to 0.1.92.4
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 17:01:10 +08:00
erioandClaude Opus 4.6 7fe246b784 fix: show affinity badge for enabled accounts even with 0 clients
- Backend: remove count > 0 filter in GetAccountAffinityCountBatch so
  accounts with 0 bound clients are included in the response
- Frontend: change badge condition from affinityClientCount > 0 to
  account.client_affinity_enabled so the badge always shows for accounts
  with affinity enabled

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 17:00:46 +08:00
erio 064a70db29 fix: update wire_gen.go to pass gatewayCache to NewAccountHandler 2026-03-06 15:55:23 +08:00
erio c616284890 chore: bump version to 0.1.92.3 2026-03-06 15:49:11 +08:00
erio 60f050d184 feat: add account affinity client count indicator
Add reverse Redis index (account_affinity:{accountID}) to track which
clients are bound to each account via affinity scheduling. Display a
blue badge with client count in the admin account list, with a hover
tooltip showing client details (groupID:clientID + TTL).

Backend: reverse index in Lua scripts, batch query methods, new
GET /accounts/:id/affinity-clients endpoint.
Frontend: blue badge + lazy-loaded tooltip in AccountStatusIndicator.
2026-03-06 15:48:58 +08:00
erio 63dff62673 fix: restrict client affinity to Anthropic OAuth/SetupToken accounts only
客户端亲和仅对 Claude Code 账号(Anthropic OAuth/SetupToken)生效,
移除 Antigravity 平台支持。UI toggle 移动到拦截预热请求下方。
2026-03-06 14:46:47 +08:00
erio c1816f39f2 revert: remove passthrough check from isModelSupportedByAccount
该函数不被 OpenAI 调度路径调用,透传短路应只加在
openai_account_scheduler.go 中。
2026-03-06 14:30:44 +08:00
erio 69abdff732 chore: bump version to 0.1.92.2 2026-03-06 14:24:58 +08:00
erio 489a6d4839 fix: OpenAI scheduler also bypass model check for passthrough accounts
之前只在 gateway_service.isModelSupportedByAccount 中添加了透传短路,
但 OpenAI 调度器 (openai_account_scheduler.go) 直接调用
account.IsModelSupported(),未经过该函数,导致 gpt-5.4 仍然 503。
2026-03-06 14:20:08 +08:00
erio 312f2ecb8d fix: OpenAI passthrough accounts bypass model mapping check
透传模式账号仅替换认证,应允许所有模型通过。之前调度阶段的
isModelSupportedByAccount 不感知透传模式,导致 model_mapping
中未配置的新模型(如 gpt-5.4)被拒绝返回 503。
2026-03-06 13:54:25 +08:00
erio 75f1faea14 chore: bump version to 0.1.92.1 2026-03-06 13:08:32 +08:00
erio b4005aa7b2 Merge branch 'release/custom-0.1.91' into release/custom-0.1.92 2026-03-06 13:06:17 +08:00
erio 180c515f9a fix: race condition in TestOpsSystemLogSink_StartStopAndFlushSuccess
done 信号在 BatchInsertSystemLogsFn 内发出,但 writtenCount 在函数返回后
才原子递增,导致测试主 goroutine 收到信号后立即检查 WrittenCount 时可能为 0。
改用短轮询等待 WrittenCount > 0,消除竞态。
2026-03-06 13:02:04 +08:00
erio 896fb2b0b4 feat: add client affinity scheduling for Anthropic/Antigravity accounts
新增客户端亲和调度功能,新会话优先调度到客户端之前使用过的账号,减少账号频繁切换。

- 调度层 Layer 1.6:粘性会话未命中时,从 Redis Sorted Set 按最近使用时间降序
  查找亲和账号,通过全部可调度检查后尝试获取槽位
- 账号级 opt-in:通过 Extra 字段 client_affinity_enabled 控制,未启用的账号
  既不写入亲和关系也不被亲和选中
- Redis 数据结构:ZSET client_affinity:{groupID}:{clientID},Lua 脚本原子清理
  过期成员 + 查询/更新,per-member TTL 通过 score 实现
- 仅 Claude Code/Console 客户端生效(通过 metadata.user_id 格式识别)
- DTO/前端:新增开关 UI,支持 Anthropic OAuth/SetupToken 和 Antigravity 平台
2026-03-06 12:43:22 +08:00
shaw 0cce0a8877 chore: gpt-5.4示例配置修改model_reasoning_effort为xhigh 2026-03-06 11:29:43 +08:00
shaw 225fd035ae chore: 更新codex配置部分支持gpt-5.4的长上下文 2026-03-06 10:55:09 +08:00