Commit Graph

361 Commits

Author SHA1 Message Date
cita-777 4b5d045b00 Address high-priority review gaps before merging the dev snapshot
The release branch still had unresolved review comments around payload-rule
atomicity, brand blocking, compact fallback controls, and response
compatibility edge-cases. This patch pulls those behaviors back in line with
the intended contracts and adds focused regression coverage for the fragile
bridges.

Constraint: The fixes must stay narrow to the PR branch so review/merge can continue without reopening the larger dev snapshot conflict set
Rejected: Leave outdated-looking threads unresolved until after merge | reviewers still see concrete unfixed regressions in the current release branch
Rejected: Re-run another broad merge from dev/main | too risky while the PR branch is already green and mergeable
Confidence: medium
Scope-risk: moderate
Directive: If these release-branch fixes need to persist for future release cuts, backport them onto dev instead of re-fighting the same review threads next time
Tested: Focused vitest for settings events, brand matcher, compact responses, codex compatibility, anthropic stream bridge, openai chat response bridge; typecheck; repo drift check; git diff --check
Not-tested: Full npm test; live PR thread resolution state after push
2026-04-18 13:05:52 +08:00
cita-777 4aa888e581 Repair release-branch CI after folding dev onto main
The release branch inherited a few merge-shaped regressions after the
large dev snapshot was layered onto the latest main snapshot. This
commit restores the main-compatible stats and TokenRoutes behavior the
CI suite expects and adds the missing multi-brand helper export so the
release branch reflects a coherent post-merge tree instead of a
partially regressed hybrid.

Constraint: Must keep the release branch mergeable to main while preserving the current publish snapshot shape
Rejected: Re-open the whole release merge and hand-resolve every file again | too broad for targeted CI repair
Confidence: medium
Scope-risk: narrow
Reversibility: clean
Directive: When dev and main have drifted heavily, re-run the main-facing CI tests after any conflict normalization pass
Tested: targeted vitest suite for failing CI jobs plus update-center coverage; typecheck
Not-tested: Full npm test still not representative locally because of unrelated untracked tmp/sub2api suites outside the PR branch content
2026-04-17 23:26:22 +08:00
cita-777 f335a330e3 Prepare the dev snapshot for main review on a clean release branch
This release branch starts from the latest origin/main and folds in the
current origin/dev snapshot so the PR to main can follow the repo's
publish flow without opening directly from dev. Conflict-heavy files
were normalized back to the dev snapshot where necessary so the release
branch reflects the code currently being carried on dev instead of a
line-merged hybrid.

Constraint: Publication flow requires a clean release branch from latest origin/main rather than a PR directly from dev
Constraint: The branch must preserve the current dev snapshot even when main and dev have drifted substantially
Rejected: Open the PR directly from dev | violates the repo publication flow
Rejected: Manually redesign every historic dev/main conflict during release prep | too broad for a publish branch
Confidence: medium
Scope-risk: moderate
Reversibility: clean
Directive: Treat this branch as a publication snapshot of dev-on-top-of-main, not as a general cleanup pass over old divergence
Tested: update-center focused vitest suite on release branch; typecheck; build:web; docs:build; repo:drift-check
Not-tested: Full npm test remains red from inherited tmp/sub2api frontend suites and an existing firstByteTimeout unhandled error
2026-04-17 22:58:06 +08:00
cita-777 f67ade2e59 Keep dev green after moving the active worktree snapshot
The transferred dev snapshot was not publication-ready yet: full tests still
failed because worktree-local docs resolution assumed a repo-root node_modules
tree, some protocol expectations no longer matched the refactored request
bridges, oauth/account-token route tests reused stale modules after resetting
DATA_DIR, and model discovery still fired unawaited default-token writes.

This follow-up makes the moved dev branch self-consistent and green again by
stabilizing module/test isolation, awaiting token mirroring writes, and
aligning narrow tests with the current transformer and request-builder
contracts.

Constraint: The fix set had to stay narrow and unblock the new dev branch without reworking the broader transferred refactor
Rejected: Revert the transferred snapshot | would lose the user's requested dev-branch continuation point
Confidence: medium
Scope-risk: moderate
Reversibility: clean
Directive: If more DATA_DIR-scoped API test files start flaking under shared workers, reset modules before importing singleton db/config modules instead of relying on process env mutation alone
Tested: git diff --check; npm run typecheck; npm run repo:drift-check; npm test
Not-tested: Live OAuth/provider flows outside the mocked test harness
2026-04-17 19:59:14 +08:00
cita-777 88f40e91f7 Preserve the active worktree snapshot on dev for follow-on integration
The root checkout already contained a large in-progress proxy, transformer,
and settings refactor. This commit captures that exact work on a dedicated
local dev branch without disturbing the original dirty worktree, so the
changes can be continued or split from dev instead of living only as
uncommitted state.

Constraint: The source checkout was already dirty on another branch, so the move had to preserve that worktree while excluding local .idea and .omx residue from the commit
Rejected: Switch the dirty root checkout directly to dev | risked disrupting the original branch and in-progress state
Confidence: medium
Scope-risk: broad
Reversibility: clean
Directive: Treat this as a transfer snapshot; fix the failing oauth/accountTokens/normalized/docs test regressions before merge or publication
Tested: git diff --check; npm run typecheck; npm run repo:drift-check
Not-tested: Clean test pass; npm test currently fails in oauth routes, accountTokens sync, shared normalized helpers, gemini route expectations, architecture-boundaries, and docs vitepress config
2026-04-17 19:41:14 +08:00
Cita 9c766dec1c [codex] add payload rules settings UI (#473)
* Make payload request overrides configurable from Settings

The payload-rules engine already existed in the proxy path, but operators had
no supported runtime UI to manage CPA-style overrides. This wires the setting
through the runtime settings API, adds strict validation, and ships a
low-friction visual editor with an advanced JSON fallback so common cases like
Codex high reasoning can be configured without hand-editing backend state.

Constraint: Must reuse the existing payload-rules execution path and settings table without schema changes
Constraint: Must fit the existing metapi Settings-page patterns rather than introducing a standalone config surface
Rejected: JSON-only editor as the primary UX | too long and too easy to misconfigure for common cases
Rejected: A brand-new backend rule format for the UI | would duplicate the existing payload-rules source of truth
Confidence: high
Scope-risk: moderate
Reversibility: clean
Directive: Keep visual-rule serialization and advanced JSON editing in sync before extending the rule model
Tested: npm run typecheck
Tested: npx vitest run --root . src/server/services/payloadRules.test.ts src/server/routes/api/settings.events.test.ts src/web/pages/settings.payload-rules.test.tsx
Tested: npm run repo:drift-check
Not-tested: Manual browser interaction smoke on the Settings page in this clean PR worktree

* Prevent payload-rules saves from violating review expectations

Code review surfaced two operator-facing edge cases in the first payload-rules
PR: successful rule parsing could still be committed before a later validation
error, and visual edits could silently overwrite unsaved advanced JSON. This
stages payload-rules until the request finishes validating and adds an explicit
confirmation gate before visual actions discard unsynced advanced edits.

Constraint: Keep the fix narrow to the reviewed payload-rules feature without refactoring unrelated runtime-settings atomicity behavior
Rejected: Silently skipping draft resync while keeping visual edits active | would leave save semantics ambiguous when advanced JSON stays dirty
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: If the settings endpoint ever moves toward full request atomicity, re-check this staged payload-rules write path against the broader strategy
Tested: npm run typecheck
Tested: npx vitest run --root . src/server/routes/api/settings.events.test.ts src/web/pages/settings.payload-rules.test.tsx
Tested: npm run repo:drift-check
Not-tested: Manual browser smoke of the confirmation dialog text
2026-04-10 14:27:43 +08:00
Cita 2f774e204c Keep MySQL usage aggregation from crashing startup (#471)
The usage aggregation projector was written with SQLite/Postgres conflict builders, but Render can switch the runtime DB to MySQL from saved settings. That made the startup scheduler throw before the service stayed healthy.

This change branches the projector's checkpoint and aggregate writes to MySQL-safe onDuplicateKeyUpdate calls while preserving the existing SQLite/Postgres onConflict behavior. A mocked MySQL regression test now omits the onConflict builders entirely so future regressions fail fast.

Constraint: Drizzle conflict APIs are dialect-specific and the projector starts during boot

Rejected: Disable the projector on MySQL | would keep admin analytics stale and hide the real incompatibility

Confidence: high

Scope-risk: narrow

Reversibility: clean

Directive: New usage-aggregation writes must branch on runtimeDbDialect before using conflict helpers

Tested: npx vitest run --root . src/server/services/usageAggregationService.test.ts src/server/services/usageAggregationService.mysql.test.ts

Tested: npm run typecheck:server

Tested: npm run repo:drift-check

Tested: npm run build:server

Not-tested: Live MySQL projector pass against a deployed runtime database
2026-04-10 12:41:08 +08:00
Cita c6a28c71c4 [codex] improve LobeHub brand detection coverage (#464)
* Recognize more LobeHub-backed model brands so marketplace filters stop collapsing into other

Metapi was leaving many models under the uncategorized bucket even though the
current LobeHub icon set already contains matching provider or vendor brands.
This change moves brand detection into one shared registry, expands the rules
with the user-reported gaps that have real upstream icon coverage, and makes
server-side brand blocking reuse the same classification result as the web UI.

Constraint: Existing workspace has unrelated in-progress edits, so this commit stages only the brand-classification slice
Constraint: Brand matching must stay consistent between marketplace display and server-side blocked-brand filtering
Rejected: Add more ad hoc rules separately in web and server files | would keep the drift bug alive
Rejected: Blindly import every LobeHub slug as a model brand | would pollute filters with tool and app brands
Confidence: high
Scope-risk: moderate
Reversibility: clean
Directive: Keep new brand additions in src/server/shared/modelBrand.ts and let web/server consume that single source of truth
Tested: npm test -- src/web/components/BrandIcon.test.ts src/server/services/brandMatcher.test.ts src/web/pages/Models.marketplace-text.test.tsx src/web/components/BrandIcon.architecture.test.ts src/web/components/BrandIcon.render.test.tsx
Tested: npm run typecheck
Tested: npm run repo:drift-check
Not-tested: Live browser verification against the user's current marketplace dataset after deployment

* Preserve provider brand blocking without changing display-brand priority

The first pass unified brand detection but server-side blocked-brand checks
started relying on the single display brand. Mixed model paths such as
`deepinfra/meta-llama/...` and `azureai/gpt-4o` still need provider markers to
match global blocked brands even while the UI continues to show the preferred
vendor label.

Constraint: Marketplace display should keep the current preferred vendor-first brand label
Constraint: Server-side blocked-brand matching must still recognize provider and vendor markers on the same model id
Rejected: Reorder display-brand priority to make provider blocks pass | would regress the marketplace labels the PR was improving
Rejected: Reintroduce a separate server-only matcher | would recreate the web/server drift this PR removed
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Use getMatchingBrandNames for blocking-style checks and reserve getBrand for single-label display surfaces
Tested: npm test -- src/server/shared/modelBrand.test.ts src/server/services/brandMatcher.test.ts src/web/components/BrandIcon.test.ts src/web/pages/Models.marketplace-text.test.tsx src/web/components/BrandIcon.architecture.test.ts src/web/components/BrandIcon.render.test.tsx
Tested: npm run typecheck
Tested: npm run repo:drift-check
Not-tested: Live GitHub review-thread auto-resolution behavior after push

* Honor legacy blocked brand casing when canonicalizing global brand filters

The shared brand matcher now supports multi-match provider blocking, but the
blocked-brand rule parser still required exact display-case brand names. That
meant imported or legacy settings like `openai` or `aws bedrock` were silently
ignored even though they should map to known brands.

Constraint: Existing saved settings may contain lower-case or whitespace-variant brand names from imports or older data
Constraint: The server should keep emitting canonical display names after normalizing user-provided blocked brand entries
Rejected: Assume the settings UI always writes canonical brand strings | does not cover imported or hand-edited configuration
Rejected: Normalize only at the settings route | would still leave hydrated legacy config values ineffective in modelService
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Keep blocked-brand parsing tolerant of case and spacing drift, but always return canonical brand names for downstream use
Tested: npm test -- src/server/services/brandMatcher.test.ts src/server/shared/modelBrand.test.ts src/web/components/BrandIcon.test.ts src/web/pages/Models.marketplace-text.test.tsx src/web/components/BrandIcon.architecture.test.ts src/web/components/BrandIcon.render.test.tsx
Tested: npm run typecheck
Tested: npm run repo:drift-check
Not-tested: Manual settings UI round-trip with legacy lowercase globalBlockedBrands payloads
2026-04-09 21:43:43 +08:00
Cita baead855dd Make admin reads snapshot-first for faster ops pages (#457)
* Make admin reads snapshot-first so heavy pages stay responsive

This introduces a lightweight snapshot/cache layer for the busiest
admin reads, splits dashboard and proxy-log loading into smaller
independent surfaces, and moves accounts/site/dashboard snapshots
toward service-owned read paths.

The UI now loads dashboard summary, dashboard insights, site stats,
accounts, and proxy-log metadata as separate progressive reads while
keeping existing feature coverage intact.

Constraint: Must keep the full admin feature set and core metrics intact
Constraint: Interactive admin flows should trend toward <=3s without relying on OpenResty-only band-aids
Rejected: Delete heavy pages or reduce statistics depth | user explicitly requires unchanged functionality
Rejected: Keep one giant proxy-log/dashboard response | preserves current timeout-prone read shape
Confidence: medium
Scope-risk: moderate
Directive: Preserve old endpoints during the migration and keep new snapshot/query-v2 surfaces as the preferred frontend path
Tested: npm run typecheck
Tested: npx vitest run --root . src/server/routes/api/accounts.snapshot-v2.test.ts src/server/routes/api/stats.snapshot-v2.test.ts src/server/routes/api/stats.proxy-logs.test.ts src/server/routes/api/stats.siteStatus.test.ts src/server/routes/api/accounts.todayRewardFallback.test.ts
Tested: npm run build
Tested: npm run repo:drift-check
Not-tested: Live cita/cita1 latency measurements against the production dataset

* Keep snapshot services lean after the admin read-path rollout

The snapshot-first rollout now has fresh production evidence on cita1, so this follow-up trims two no-op patterns without changing behavior: a single-element Promise.all and a catch-then-rethrow refresh chain. Keeping the service layer lean reduces noise before final Ralph sign-off and redeploy verification.

Constraint: Keep deployed behavior unchanged while satisfying the mandatory deslop pass
Rejected: Wider refactor across route files | would broaden the verified surface right before production comparison closeout
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Keep snapshot services focused on cache/read orchestration; avoid reintroducing decorative async wrappers
Tested: npm run typecheck; npm run build; targeted vitest snapshot/proxy-log/account suites; npm run repo:drift-check
Not-tested: Public Cloudflare path, which still appears to hit a different origin than cita1

* Keep admin snapshots warm without introducing Redis

This moves the new admin read path beyond process-local caching by persisting
snapshot payloads in a dedicated admin_snapshots table and warming them in
the background. It also migrates remaining lightweight internal callers away
from the heaviest legacy reads and marks legacy endpoints as deprecated
instead of deleting them abruptly.

Constraint: User explicitly rejected adding Redis for admin snapshot acceleration
Rejected: Redis-backed shared cache | adds a forbidden runtime dependency
Rejected: Delete legacy endpoints immediately | still breaks tests, docs, and compatibility callers
Confidence: high
Scope-risk: moderate
Directive: Remove legacy admin endpoints only after internal callers, docs, and compatibility windows are cleared
Tested: npm run typecheck
Tested: npm run build
Tested: npx vitest run --root . src/server/services/adminSnapshotStore.test.ts src/server/routes/api/accounts.snapshot-v2.test.ts src/server/routes/api/stats.snapshot-v2.test.ts src/server/services/startupInfo.test.ts
Tested: npm run repo:drift-check
Not-tested: cita1 staging redeploy on this follow-up commit

* Collapse admin reads onto the canonical API paths

This removes the parallel v2 read surface and routes the snapshot-first
implementation back through the original admin API names. The frontend now
uses the canonical paths again while the backend keeps the newer snapshot,
persistence, and warm-refresh machinery behind those routes. Along the way it
also fixes the main review findings around cache coalescing, active-site scope,
atomic snapshot writes, and auth-header handling.

Constraint: User requested no Redis and no long-lived duplicate admin read endpoints
Rejected: Keep both legacy and v2 endpoints indefinitely | doubles maintenance and confuses the canonical contract
Rejected: Delete old names without remapping callers | would create avoidable frontend and tooling churn
Confidence: high
Scope-risk: moderate
Directive: Treat /api/stats/dashboard, /api/accounts, /api/stats/proxy-logs, and the site stats routes as the canonical admin read contract unless a future breaking-change plan says otherwise
Tested: npm run typecheck
Tested: npm run build
Tested: npx vitest run --root . src/server/services/adminSnapshotStore.test.ts src/server/routes/api/accounts.snapshot-v2.test.ts src/server/routes/api/stats.snapshot-v2.test.ts src/server/routes/api/stats.proxy-logs.test.ts src/server/services/startupInfo.test.ts
Tested: npm run repo:drift-check
Not-tested: cita1 staging redeploy on this canonical-route follow-up commit

* Keep canonical admin analytics fast without raw log scans

This lands the usage-aggregate path as the single implementation behind the canonical admin routes, adds the aggregate schema/migration artifacts, and reconnects dashboard/site stats warming to the new service so the PR no longer sits in a half-projector state.

It also updates the cache and aggregate tests to reflect the real runtime behavior and validates the current branch on cita1 staging, which showed the app-side snapshot path is fast while the remaining 1.5s staging slowness lives on the NodePort path rather than inside the aggregate queries themselves.

Constraint: Must preserve the canonical old-path admin API contract while moving reads onto aggregate-backed snapshots
Constraint: Must not add Redis or a parallel second analytics implementation
Rejected: Keep usageAggregationProjectorService as a separate path | would preserve duplicate ownership and keep type wiring split
Rejected: Judge staging performance only from NodePort timings | hid that pod-local snapshot reads were already fast
Confidence: medium
Scope-risk: moderate
Directive: If dashboard or insights feels slow again on staging, compare NodePort and pod-local timings before changing aggregate queries
Tested: npm run typecheck; npx vitest run --root . src/server/services/adminSnapshotStore.test.ts src/server/services/usageAggregationService.test.ts src/server/services/snapshotCacheService.test.ts src/server/routes/api/accounts.snapshot-v2.test.ts src/server/routes/api/stats.snapshot-v2.test.ts src/server/routes/api/stats.proxy-logs.test.ts src/server/services/startupInfo.test.ts; npm run build; npm run repo:drift-check; cita1 staging deploy plus canonical-route curl benchmarks
Not-tested: cita1 real ingress/OpenResty path; multi-replica projector concurrency

* Prevent admin aggregate drift under concurrent warmers

This follow-up hardens the snapshot-first admin analytics path by adding a persisted projector lease, exact 24-hour dashboard counting, and regression coverage for lease contention and time-window behavior.

The goal is to keep the canonical admin routes correct when multiple workers are alive and to avoid quietly overstating proxy24h by reading hour buckets as if they were an exact sliding window.

Constraint: Projector coordination must work through the existing checkpoint table without adding Redis or a second background system
Constraint: Schema artifacts must stay additive under the repo's generated bootstrap/upgrade pipeline
Rejected: Remove the left-prefix day/hour indexes in this slice | schema:contract rejects non-additive index removals, so that cleanup needs a broader migration strategy
Confidence: high
Scope-risk: moderate
Directive: Keep projector claims DB-backed; do not regress to process-local inFlight-only dedupe for aggregate writes
Tested: npm run typecheck; npx vitest run --root . src/server/services/usageAggregationService.test.ts src/server/routes/api/stats.snapshot-v2.test.ts; npm run build; npm run repo:drift-check
Not-tested: Multi-host live contention beyond synthetic lease test; resolving CodeRabbit index-nit without additive-schema support

* Keep CI aligned with canonical admin snapshots

The admin snapshot cutover left a mixed test surface: MySQL schema artifacts still
classified admin_snapshots.snapshot_key as JSON, canonical /api/accounts callers
were asserted as arrays, and a few proxy tests mocked routeRefreshWorkflow too
narrowly, which leaked missing exports into later OAuth runs.

This commit narrows the schema metadata heuristic, updates the checked-in schema
artifacts and their regression tests, adds lightweight web test compat helpers
for canonical snapshot APIs, and preserves actual routeRefreshWorkflow exports so
full-suite workers no longer poison unrelated tests. OAuth/account token suites
also reset DATA_DIR-backed modules safely to avoid stale singleton config.

Constraint: checked-in schema artifacts drive cross-dialect CI parity checks
Constraint: vitest module mocks can leak across files in the same worker when exports are omitted
Rejected: rerun schema:generate only | additive guard rejects the logical-type correction for snapshot_key
Rejected: keep per-test ad hoc snapshot mocks | repeated breakage across pages needed one compat helper
Confidence: high
Scope-risk: moderate
Directive: when a test uses vi.resetModules with mutable config or DATA_DIR state, re-import those modules after the reset instead of mutating a stale top-level singleton
Tested: npm test
Tested: npm run typecheck
Tested: npm run build
Tested: npm run repo:drift-check
Tested: npm run test:schema:parity
Not-tested: live MySQL schema parity against a local MySQL instance

* Keep CodeQL from re-flagging already-limited routes

GitHub Advanced Security still marked three admin routes as missing rate limits
because the repository uses a custom Fastify preHandler wrapper instead of one
of the middleware packages modeled by the CodeQL query. The routes are already
throttled in production, so this change adds narrow in-source suppressions on the
three affected handlers to record that the check is a false positive instead of a
real missing guard.

Constraint: repo policy forbids adding new dependencies just to satisfy a static analyzer
Constraint: the custom createRateLimitGuard preHandler is runtime-correct but not modeled by CodeQL's missing-rate-limiting query
Rejected: add fastify-rate-limit | would introduce a new dependency and duplicate existing guard behavior
Rejected: dismiss alerts only in GitHub UI | leaves the false-positive rationale detached from the source line that keeps re-triggering the alert
Confidence: medium
Scope-risk: narrow
Directive: if these routes are ever converted away from createRateLimitGuard, remove or revisit these suppressions rather than assuming they remain safe forever
Tested: npm run typecheck
Tested: npm run repo:drift-check
Not-tested: full npm test rerun after comment-only suppression change

* Use legacy CodeQL suppression syntax for custom rate guards

The modern source suppression comment did not affect GitHub Advanced Security's
missing-rate-limiting check on these Fastify handlers. Switch the three known
false-positive locations to the legacy LGTM suppression syntax, keeping the
custom preHandler throttling in place while matching the syntax that CodeQL
still honors for in-source suppressions.

Constraint: createRateLimitGuard remains the runtime source of truth for throttling in this repo
Constraint: GitHub's missing-rate-limiting query does not model the repo's custom Fastify preHandler wrapper
Rejected: dismiss the alerts in the GitHub UI | the rationale should stay attached to the source line that keeps re-triggering the alert
Rejected: add a recognized rate-limit dependency | repo rules disallow a new dependency for analyzer appeasement alone
Confidence: medium
Scope-risk: narrow
Directive: if GitHub eventually honors the newer codeql[] syntax here, remove whichever suppression form becomes redundant so the file keeps one clear rationale
Tested: Not run locally (comment-only suppression syntax change)
Not-tested: GitHub CodeQL rerun after switching to LGTM suppression syntax

* Keep admin routes clean after CodeQL false-positive triage

The repository's custom createRateLimitGuard preHandlers are the actual runtime
throttles for these routes. Since GitHub Advanced Security still did not honor
the attempted in-source suppressions, remove the temporary comments and keep the
source focused on runtime behavior while the false-positive alerts are tracked
operationally in GitHub.

Constraint: the custom Fastify preHandler remains the only real throttling mechanism in this repo
Rejected: leave non-functional suppression comments in source | they imply enforcement that GitHub did not actually honor
Confidence: high
Scope-risk: narrow
Directive: if CodeQL adds custom Fastify preHandler modeling later, prefer removing any alert dismissals over reintroducing comment noise here
Tested: Not run locally (comment-only cleanup)
Not-tested: GitHub checks after alert dismissal
2026-04-09 21:31:13 +08:00
cita-777 6cca74b039 Recognize more LobeHub-backed model brands so marketplace filters stop collapsing into other
Metapi was leaving many models under the uncategorized bucket even though the
current LobeHub icon set already contains matching provider or vendor brands.
This change moves brand detection into one shared registry, expands the rules
with the user-reported gaps that have real upstream icon coverage, and makes
server-side brand blocking reuse the same classification result as the web UI.

Constraint: Existing workspace has unrelated in-progress edits, so this commit stages only the brand-classification slice
Constraint: Brand matching must stay consistent between marketplace display and server-side blocked-brand filtering
Rejected: Add more ad hoc rules separately in web and server files | would keep the drift bug alive
Rejected: Blindly import every LobeHub slug as a model brand | would pollute filters with tool and app brands
Confidence: high
Scope-risk: moderate
Reversibility: clean
Directive: Keep new brand additions in src/server/shared/modelBrand.ts and let web/server consume that single source of truth
Tested: npm test -- src/web/components/BrandIcon.test.ts src/server/services/brandMatcher.test.ts src/web/pages/Models.marketplace-text.test.tsx src/web/components/BrandIcon.architecture.test.ts src/web/components/BrandIcon.render.test.tsx
Tested: npm run typecheck
Tested: npm run repo:drift-check
Not-tested: Live browser verification against the user's current marketplace dataset after deployment
2026-04-09 19:43:47 +08:00
Cita 03bebae17f fix oauth route unit delete rollback (#450) 2026-04-09 11:15:57 +08:00
puyujian 569a15e14c feat: enhance API key management and fix routing logic
* ```
feat(accounts): 支持批量添加API密钥连接

- 添加accessTokens字段到账户创建载荷模式,允许传递多个API密钥
- 实现批量API密钥解析功能,支持换行符、空格和逗号分隔
- 重构账户创建逻辑以支持单个和批量API密钥处理
- 在前端界面中添加批量API密钥输入检测和处理
- 添加批量创建结果返回和错误处理
- 更新验证流程以支持批量模式下的逐条验证
- 添加详细的批量API密钥测试用例

该更改允许用户一次提交多个API密钥,系统将为每个密钥创建独立的连接并参与负载均衡。
```

* ```
fix(tokenRouter): 调整路由匹配优先级以优先匹配显示名称别名

当精确路由和显式组显示名称冲突时,现在优先选择显式组显示名称
而不是精确路由模式。这修正了路由决策逻辑,使显式组路由能够正
确覆盖精确模型匹配。

相关的测试用例已更新以反映新的匹配行为,确保显式组路由在冲
突情况下获得更高优先级。
```

* ```
fix(accounts): 修复API密钥验证错误消息显示逻辑

当凭证模式不为apikey时显示会话令牌提示信息,否则显示API密钥验证失败信息

feat(accounts): 更新API密钥输入界面提示文本

将批量添加说明从输入框占位符移至独立提示文本,
使界面更清晰易懂
```

* ```
feat(workflow): 在CI/CD工作流中使用动态Docker Hub镜像名称

- 在ci.yml和release.yml工作流中添加DOCKERHUB_IMAGE环境变量
- 将硬编码的Docker Hub用户名替换为从secrets.DOCKERHUB_USERNAME动态获取
- 更新docker.metadata-action配置以使用环境变量中的镜像名称
- 添加测试用例验证Docker Hub镜像名称的正确配置
```

* fix(accounts): 修复批量创建回归并下沉创建流程
2026-04-07 14:28:25 +08:00
cita-777 63c435c901 fix update center release tests for 1.3.0 2026-04-06 15:45:58 +08:00
Cita 42f9049aff [codex] align antigravity special-model non-stream path with CPA (#444)
* align antigravity special-model non-stream path with cpa

* fix antigravity tail aggregation review feedback

* fix antigravity fallback aggregation review feedback
2026-04-06 15:03:55 +08:00
Cita d1b42b2236 fix: support oauth route unit inserts on postgres (#443)
* fix proxy debug undici response header capture

* fix: support oauth route unit inserts on postgres
2026-04-06 13:39:05 +08:00
Cita 2b9200ea7c fix proxy debug undici response header capture (#442) 2026-04-06 13:16:46 +08:00
Cita 2f0e63a1e0 [codex] add oauth route pools and proxy save flow (#440)
* feat: add oauth route pools and proxy save flow

* fix: align oauth route pool schema and rate limits

* fix: harden oauth route pool review fixes

* fix: address oauth ci regressions

* fix: close oauth codeql alerts

* fix: harden oauth route unit recovery

* fix: split oauth route limiters for codeql

* fix: address remaining oauth review comments
2026-04-06 11:55:20 +08:00
Cita a789ddf7f8 [codex] add sub2api managed refresh resilience (#441)
* add sub2api managed refresh resilience

* serialize sub2api managed refresh per account

* bound sub2api refresh scheduler work

* tighten sub2api refresh scheduler rules
2026-04-06 11:43:30 +08:00
Cita 3edeb6e245 feat: refine OAuth proxy controls and quota UI (#433)
* feat: refine oauth management proxy controls

* fix: preserve oauth refresh state and tighten oauth rate limiting

* fix: satisfy codeql oauth rate limiting

* fix: address oauth review comments

* fix: move oauth sensitive limits into prehandlers

* fix: cap oauth quota refresh batch size
2026-04-06 08:50:19 +08:00
Cita 287c5aafd6 fix: localize downstream key trend timestamps (#432)
* fix: localize downstream key trend timestamps

* fix: keep downstream trend metadata on empty responses

* fix: cursor paginate downstream key trend reads

* fix: normalize empty downstream trend timezones

* fix: localize windowed downstream trend buckets
2026-04-06 08:46:40 +08:00
Cita 3e8d69bed6 fix codex compact non-stream accept header (#439) 2026-04-06 08:46:27 +08:00
Cita 38721cb890 [codex] support downstream key site and credential exclusions (#431)
* support downstream key site and credential exclusions

* skip electron binary download in non-desktop ci

* fix migrate partial-journal test for 0020
2026-04-05 23:43:07 +08:00
Cita 492f43c5dc [codex] add oauth pre-refresh resilience (#430)
* oauth pre-refresh resilience

* address oauth refresh review comments
2026-04-05 22:58:50 +08:00
Cita 6feda0e7ba [codex] fix downstream client detection boundaries (#429)
* fix downstream client detection boundaries

* address downstream client detection review comments
2026-04-05 22:38:00 +08:00
Cita 193f3e7181 [codex] fix proxy log usage source metadata (#428)
* fix proxy log usage source metadata

* fix ci follow-up comment regressions
2026-04-05 21:57:08 +08:00
Cita d5560fb036 [codex] normalize primary site URL handling (#424)
* normalize primary site url handling

* fix site create redirect test selector

* fix sub2api gemini model discovery and site detect race

* fix sub2api antigravity fallback and test selectors

* fix site modal wording test

* guard blur detect against manual platform changes
2026-04-05 20:09:34 +08:00
Cita df75a80bf9 Fix responses compact fallback handling (#426)
* fix route drag overlay alignment

* fix(web): address route drag review comments

* fix route card review follow-up

* Fix responses compact fallback handling

* Fix compact endpoint candidate typing

* Tighten compact fallback matcher
2026-04-05 19:41:09 +08:00
Cita ef1962d10b [codex] rename site API request wording (#423)
* rename site api request wording

* replace real site example domains
2026-04-05 19:16:08 +08:00
Cita 5b005d8412 fix: tighten generic upstream passthrough headers (#422)
* fix: tighten generic upstream passthrough headers

* fix: preserve codex passthrough version headers
2026-04-05 18:11:42 +08:00
Cita afbbc4c79a fix failed expired api-key recovery route preservation (#421) 2026-04-05 17:41:35 +08:00
Cita b3e987a2f5 [daily] keep codex continuation current across scope roundtrips (#416) 2026-04-05 17:29:42 +08:00
Cita 63f6b07842 [daily] cap sqlite migration recovery retries (#410)
* [daily] cap sqlite migration recovery retries

* fix typecheck for sqlite retry budget guard
2026-04-03 11:10:55 +08:00
Cita af5b62fd8b [codex] fix codex responses continuation across channel drift (#404)
* fix codex responses continuation across channel drift

* fix: clear codex responses continuation fallback on scoped reset

* fix: harden codex continuation store keying
2026-04-03 11:00:53 +08:00
Cita b9b553d772 [codex] fix sqlite migration journal recovery (#400)
* fix sqlite migration journal recovery

* address sqlite migration review follow-ups
2026-04-02 17:28:45 +08:00
Cita 6ad9ec6911 [codex] strip codex responses max_output_tokens (#399)
* strip codex responses max_output_tokens

* address codex responses review comments
2026-04-02 17:28:38 +08:00
Cita 2be0603e6f [codex] fix expired connection health recovery (#393)
* fix expired connection health recovery

* address review comments and test regressions
2026-04-02 17:27:42 +08:00
Cita 082891a217 [codex] fix runtime settings restart hydration (#392)
* fix runtime settings restart hydration

* fix review followups for settings hydration

* dedupe log cleanup day normalization
2026-04-02 17:27:25 +08:00
Cita 52c6ff5e5c [daily] route codex websocket through site api endpoints (#386)
* fix: route codex websocket through site api endpoints

* fix: preserve websocket endpoint exhaustion errors

* test: align proxy route mocks with first-byte timeout helpers
2026-04-02 11:18:30 +08:00
Cita 180d17adfc feat: add proxy first-byte timeout and log badges (#383)
* add proxy first-byte timeout and log badges

* fix first-byte timeout review feedback
2026-04-02 10:00:11 +08:00
Cita bcd758edac test: harden background task completion waits (#382) 2026-04-02 09:49:50 +08:00
Cita ace5ddd52b fix edit payload clearing boundaries (#381) 2026-04-02 09:49:39 +08:00
Cita 4ca88d0fe5 [codex] fix responses-to-chat tool stream fidelity (#378)
* fix responses chat tool stream fidelity

* fix responses tool call follow-up review comments
2026-04-02 09:49:23 +08:00
Bainily 596d1b93cb feat(server): add proactive channel probes and load-aware stable routing / 服务端新增主动探活与负载感知稳定路由 (#330)
* wip: preserve local changes before upstream merge

* Improve proxy routing stability and add stable-first strategy

* Sync explicit-group routing strategy to eligible source routes

* Fix proxy retry and runtime health review issues

* fix: make proxy channel retry attempts configurable

* fix: harden proxy retry recovery and bookkeeping

* fix: address pr 257 review comments

* feat(proxy): add sticky session channel coordination

* feat(server): add proactive channel probes and load-aware stable routing

* test(server): stabilize session load routing selection assertion

* fix(proxy): harden codex forwarding stability

* fix(router): rotate stable-first channels by healthy order

* fix(server): address probe review feedback

* fix(server): address probe review follow-ups

* fix(ci): address CodeQL and core test failures

* feat(server): refine stable-first routing recovery and observation

* Finish PR 330 settings and review fixes

* Fix chat site endpoint CI mock

* Address latest PR 330 review comments

---------

Co-authored-by: Cita <juricek.chen@gmail.com>
2026-04-02 09:49:04 +08:00
Cita 5fffcb6d66 feat: support CIDR admin allowlists (#377) 2026-04-01 21:06:13 +08:00
Cita 76c85d0a13 [codex] Split site API endpoint pool from panel host (#373)
* feat: add site api endpoint schema scaffolding

* feat: wire site api endpoints into backup migration

* feat: add site api endpoint selection service

* feat: add site api endpoint contracts

* feat: route discovery through site api endpoints

* feat: route proxy traffic through site api endpoints

* feat: add site api endpoint pool editor

* fix: keep proxy video tasks on site endpoint pool

* fix: restore core test compatibility for site endpoint pool

* fix: address endpoint pool review findings
2026-04-01 20:58:37 +08:00
Cita 37a86d1380 [codex] background route decision refresh (#370)
* background route decision refresh

* address route decision refresh review

* fix route decision refresh typing
2026-04-01 18:24:14 +08:00
Cita 21d92e1887 fix: recognize structured oauth accounts in routing (#369)
* fix: recognize structured oauth accounts in routing

* fix: use structured oauth accounts in account list
2026-04-01 17:15:22 +08:00
Cita e2d9481b95 fix anyrouter balance refresh challenge errors (#368) 2026-04-01 16:53:01 +08:00
Cita 532be86e93 [codex] Add route cooldown controls (#365)
* Add route cooldown controls

* Address route cooldown review comments
2026-04-01 16:41:25 +08:00
Cita 1e0dffe543 [codex] Fix mysql insert boundary handling (#364)
* fix mysql insert boundary handling

* fix review comment follow-ups

* fix account insert boundary regressions
2026-04-01 14:33:45 +08:00