Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
82 commits
Select commit Hold shift + click to select a range
65b1654
Merge pull request #4409 from QuantumNous/nightly
Calcium-Ion Apr 23, 2026
69ba18d
fix(image): only price image model use N ratio
xyfacai Apr 23, 2026
df6d862
fix: correct gpt-5.5 completion ratio
jingx8885 Apr 24, 2026
63ce2db
fix: model pricing use correct display type
feitianbubu Apr 24, 2026
ec8f3dc
Merge pull request #4412 from xyfacai/fix/image-n
Calcium-Ion Apr 24, 2026
05b0041
Merge pull request #4414 from jingx8885/codex/fix-gpt-55-completion-r…
Calcium-Ion Apr 24, 2026
2e610e5
Merge pull request #4426 from feitianbubu/pr/86489c09a85b2b3c6e4c27f3…
Calcium-Ion Apr 24, 2026
e3d64cb
Merge pull request #4431 from yyhhyyyyyy/fix/tiered-billing-model-list
yyhhyyyyyy Apr 24, 2026
3a2138b
refactor: rename and relocate HasModelBillingConfig function for clarity
Calcium-Ion Apr 24, 2026
435d7ae
feat: support DeepSeek V4 reasoning suffix handling
HynoR Apr 24, 2026
8993386
feat: support DeepSeek V4 reasoning suffix handling (#4428)
Calcium-Ion Apr 24, 2026
095e192
fix(channel): load model mapping during upstream model checks
seefs001 Apr 24, 2026
a7c38ec
fix: add PaymentProvider field to prevent cross-gateway callback attacks
Calcium-Ion Apr 24, 2026
02aacb3
feat: add user created_at and last_login_at
feitianbubu Apr 25, 2026
f2f3410
feat: add `len` variable for tier conditions and LLM prompt helper
Calcium-Ion Apr 25, 2026
3553072
fix: clarify affinity disabled channel retry message
seefs001 Apr 25, 2026
62d4b63
feat: configure native messages model matching
seefs001 Apr 26, 2026
db89b57
fix: support raw JSON response tool arguments
seefs001 Apr 26, 2026
4c21c4c
feat: show removed upstream models in fetch models modal
seefs001 Apr 26, 2026
cc4ad6c
Merge pull request #4437 from seefs001/fix/channel-upstream-model-sync
Calcium-Ion Apr 26, 2026
f424f90
feat: sync upstream pricing from pricing endpoint (#4452)
seefs001 Apr 26, 2026
097a50e
fix: clarify affinity disabled channel retry message (#4453)
Calcium-Ion Apr 26, 2026
86cfb39
Merge pull request #4468 from seefs001/feature/ali-anthropic-messsage…
Calcium-Ion Apr 26, 2026
d604f48
Merge pull request #4469 from seefs001/fix/tool-arguments-object
Calcium-Ion Apr 26, 2026
34afe9b
Merge pull request #4470 from seefs001/feature/show-removed-upstream-…
Calcium-Ion Apr 26, 2026
e36d191
Merge pull request #4450 from feitianbubu/pr/7fa4a87ad953642a2f454ad0…
Calcium-Ion Apr 26, 2026
4e93148
fix: ensure proper handling of JSON unmarshalling for maps in config …
Calcium-Ion Apr 27, 2026
bee339d
fix: always serialize ratio/price values for all models to ensure fal…
Calcium-Ion Apr 27, 2026
9f8a4ec
fix: filter pricing variables based on cache token availability in ti…
Calcium-Ion Apr 28, 2026
a42b397
🚀 feat: launch v1.0 — next-generation frontend built from the ground …
t0ng7u Apr 28, 2026
c609cb1
fix: update logo paths in README
Calcium-Ion Apr 28, 2026
df14a0b
CI
Calcium-Ion Apr 28, 2026
fc377da
style: optimize UI
Calcium-Ion Apr 28, 2026
28f7e9e
feat: enhance UI and functionality in various components
Calcium-Ion Apr 28, 2026
22ef5b2
feat(dashboard): update model analytics section and enhance user char…
Calcium-Ion Apr 28, 2026
db48108
feat(logs): enhance usage logs table with log type indicators and imp…
Calcium-Ion Apr 28, 2026
75af3db
feat(logs): add username to TaskLog interface and implement log avata…
Calcium-Ion Apr 29, 2026
4384107
feat(charts): enhance tooltip functionality and improve data sorting …
Calcium-Ion Apr 29, 2026
f982544
feat(ui): refine default frontend layouts
Calcium-Ion Apr 29, 2026
22ae14f
feat(ui): enhance ChannelsTable and CommonLogs components with improv…
Calcium-Ion Apr 29, 2026
8ca1033
fix: Message.ReasoningContent/Reasoning 改为 *string,修复空思考内容在请求转发时被静默丢弃的问题
heimoshuiyu Apr 28, 2026
6f57dcd
Delete dto/message_reasoning_test.go
Calcium-Ion Apr 29, 2026
e0b6eb3
fix: sync theme to runtime when loaded from database (#4518)
Micah-Zheng Apr 29, 2026
3b59289
fix: follow required marker styling convention
yyhhyyyyyy Apr 29, 2026
b44faec
feat(ui): overhaul default channel editor with full param override vi…
Calcium-Ion Apr 29, 2026
b2232f4
feat(ui): add system settings to sidebar and unhide frontend theme sw…
Calcium-Ion Apr 29, 2026
2f86370
fix: 修复默认主题 API 密钥分组行为
Micah-Zheng Apr 29, 2026
9564835
Merge pull request #4548 from Micah-Zheng/fix/default-api-key-group
Calcium-Ion Apr 30, 2026
9b0ec8e
fix: use post for email binding
SHLE1 Apr 30, 2026
22fd174
Merge pull request #4551 from SHLE1/fix/email-bind-post-method
Calcium-Ion Apr 30, 2026
8bff691
feat(ui): add reusable dashboard and log controls
Calcium-Ion Apr 30, 2026
8f3c41a
feat(ui): improve table controls and analytics filters
Calcium-Ion Apr 30, 2026
5f86839
fix: improve tiered pricing number input editing (#4536)
yyhhyyyyyy Apr 30, 2026
987b7ec
fix(vertex): honor custom base_url as gateway prefix
yyhhyyyyyy Apr 30, 2026
d2b30df
feat(ui): redesign model square pricing page
Calcium-Ion Apr 30, 2026
aa73039
fix(ui): polish landing page and navigation
Calcium-Ion Apr 30, 2026
d46df94
feat(ui): improve mobile responsive layouts
Calcium-Ion Apr 30, 2026
5114ad0
Merge pull request #4200 from yyhhyyyyyy/fix/vertex-gateway-base-url
Calcium-Ion Apr 30, 2026
938dc95
fix(web): 修复阶梯计费 Base64 解码失败与标签不匹配导致的显示错误 (#4530)
wans10 Apr 30, 2026
dac55f0
feat(ui): add classic frontend switch
Calcium-Ion Apr 30, 2026
c09408d
style(theme): 调整暗色主题颜色变量以降低亮度
Starry-Sky-World May 1, 2026
581b14d
ci: 添加 GitHub Actions 工作流用于构建和推送 Docker 镜像到 GHCR
Starry-Sky-World May 1, 2026
5e712c6
feat(主题色): 实现自定义主题色功能
Starry-Sky-World May 1, 2026
26a577b
feat(badge): 添加多颜色支持并替换StatusBadge组件
Starry-Sky-World May 1, 2026
5c4c2bb
refactor(ui): 替换 StatusBadge 为通用 Badge 组件
Starry-Sky-World May 2, 2026
dacc488
feat(可用性监控): 添加模型可用性监控面板功能
Starry-Sky-World May 2, 2026
dada555
feat(availability): 优化可用性监控功能并添加多语言支持
Starry-Sky-World May 2, 2026
ee3ecc8
feat(availability): 添加可用性监控按钮并增强数组类型检查
Starry-Sky-World May 2, 2026
44adc11
fix(availability-button): 移除多余的enabled条件检查
Starry-Sky-World May 2, 2026
09c3195
feat(用户设置): 新增注册时自动启用接受未定价模型选项
Starry-Sky-World May 2, 2026
b3064f7
feat: 添加顶部横幅功能,支持多语言和自定义样式
Starry-Sky-World May 2, 2026
70e2562
fix(i18n): 修复多语言文件中未定价模型字符串的引号问题
Starry-Sky-World May 2, 2026
ef5fdc4
feat(横幅): 添加横幅字体颜色配置功能
Starry-Sky-World May 2, 2026
c630437
fix(组件): 修复顶部横幅滚动判断和样式问题
Starry-Sky-World May 2, 2026
139dabc
feat(系统设置): 增强顶部横幅背景样式配置功能
Starry-Sky-World May 2, 2026
e16d98c
fix(ui): 修复响应式布局问题并优化表格显示
Starry-Sky-World May 2, 2026
3f01860
docs: 简化README.md内容并更新为CuzAPI版本
Starry-Sky-World May 3, 2026
83ac068
Update README.md
Starry-Sky-World May 3, 2026
fb6702d
Make banner styling controllable without preset bleed
ukaku689 May 3, 2026
9c5b95a
Merge pull request #1 from Jarvisu88/cuzteam-main-dev
Starry-Sky-World May 3, 2026
706b54d
Add image build and push section to README
Starry-Sky-World May 3, 2026
7901405
feat: Update GitHub Action status image limit
Starry-Sky-World May 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
83 changes: 83 additions & 0 deletions .agents/skills/classic-to-default-sync/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
---
name: classic-to-default-sync
description: Inspect a given commit's web/classic changes and sync all features/fixes to web/default. Use when the user provides a commit ID and wants to audit whether web/default already has the same features as web/classic, port missing features, improve suboptimal implementations, fix bugs, and remove redundant code. Trigger phrases include: "/classic-to-default-sync <hash>", "classic-to-default-sync <hash>", "sync classic to default", "port from classic", "compare classic commit", "classic 和 default 对比", "把这次 classic 的修改同步到 default", "查看这次提交 classic 中的修改并同步", or any request supplying a commit hash together with classic/default comparison intent.
---

# Classic-to-Default Sync

Given a **commit ID**, audit all `web/classic` changes and ensure `web/default` reaches feature parity with the best possible implementation.

## Input

The user must supply a `<commit-id>`.

## Workflow

### Step 1 — Extract classic diff

```bash
git show <commit-id> -- web/classic
```

Read every changed file in `web/classic`. Identify the **logical changes** (new features, UI/UX improvements, bug fixes, config tweaks, removed dead code, etc.) — not just line diffs.

### Step 2 — Map to default counterparts

For each logical change found in Step 1, locate the equivalent file(s) in `web/default/src/`. Use Glob/Grep/SemanticSearch as needed. Consider that:

- `web/classic` uses **React 18 + Vite + Semi Design**
- `web/default` uses **React 19 + Rsbuild + Radix UI + Tailwind CSS**
- Component names, file paths, and API shapes may differ; match by **functionality**, not filename.

### Step 3 — Triage each change

Classify every logical change as one of:

| Status | Meaning |
|--------|---------|
| ✅ Already present & optimal | No action needed |
| ⚠️ Present but suboptimal | Improve: logic, layout, style, or code quality |
| ❌ Missing | Implement from scratch in default's stack |

### Step 4 — Implement

For each **⚠️** or **❌** item:

1. **Read the target file(s) in `web/default`** before editing (required by project conventions).
2. Implement using `web/default` conventions:
- React 19 patterns (hooks, Suspense, etc.)
- Radix UI primitives where applicable
- Tailwind CSS for styling (no inline styles or Semi Design imports)
- `useTranslation()` + `t('English key')` for all user-visible strings
- TypeScript — explicit types, no `any`
- No dead code, no redundant comments
3. Follow **Rule 6** (pointer types for optional relay DTOs) if touching relay-related TS types.
4. After editing, run `ReadLints` on changed files and fix any introduced lint errors.

### Step 5 — i18n

If any new user-visible strings were added, run the i18n sync:

```bash
cd web/default && bun run i18n:sync
```

Then add missing translations for all supported locales (en, zh, fr, ja, ru, vi) following the **i18n-translate** skill.

### Step 6 — Report

Summarise the work in a concise table:

| # | Change (from classic commit) | Status | Action taken |
|---|------------------------------|--------|--------------|
| 1 | … | ✅ / ⚠️ / ❌ | None / Improved / Implemented |

If every item is ✅ with no action needed, simply reply: **"已完成 — web/default 已具备此次提交的所有功能,且实现质量良好,无需修改。"**

## Quality bar

- No unused imports, variables, or components
- No commented-out code left behind
- Consistent naming with surrounding `web/default` code
- All interactive elements accessible (keyboard nav, ARIA labels where Radix doesn't provide them automatically)
- No regressions: existing behaviour in `web/default` must not break
254 changes: 254 additions & 0 deletions .agents/skills/i18n-translate/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,254 @@
---
name: i18n-translate
description: >-
Complete and maintain frontend i18n translations for this project. Covers
finding missing translation keys, detecting untranslated entries, and adding
translations for all supported locales (en, zh, fr, ja, ru, vi). Use when the
user asks to add translations, fix i18n, complete missing translations, or
when new UI text needs to be internationalized.
---

# Frontend i18n Translation Workflow

## Overview

- Locale files: `web/default/src/i18n/locales/{en,zh,fr,ja,ru,vi}.json`
- Format: flat JSON under `"translation"` key, keys are English source strings
- Base locale: `en.json` (most keys), fallback: `zh` (Chinese)
- Sync script: `bun run i18n:sync` (from `web/default/`)
- All `t()` calls must have corresponding keys in every locale file

## Workflow

### Step 1: Run sync and read report

```bash
cd web/default && bun run i18n:sync
```

Read `web/default/src/i18n/locales/_reports/_sync-report.json` to see per-locale status (missingCount, extrasCount, untranslatedCount).

### Step 2: Find missing keys (used in code but not in locale files)

Create and run `web/default/scripts/find-missing-keys.mjs`:

```javascript
import fs from 'node:fs/promises'
import path from 'node:path'

const LOCALES_DIR = path.resolve('src/i18n/locales')
const SRC_DIR = path.resolve('src')

const en = JSON.parse(await fs.readFile(path.join(LOCALES_DIR, 'en.json'), 'utf8'))
const enKeys = new Set(Object.keys(en.translation))

const tCallRegex = /\bt\(\s*['"`]([^'"`\n]+?)['"`]\s*[,)]/g
const tCallMultilineRegex = /\bt\(\s*['"`]([^'"`]+?)['"`]\s*\)/g

async function walkDir(dir) {
const files = []
const entries = await fs.readdir(dir, { withFileTypes: true })
for (const entry of entries) {
const fullPath = path.join(dir, entry.name)
if (entry.isDirectory()) {
if (['node_modules', '.git', 'locales', '_reports', '_extras'].includes(entry.name)) continue
files.push(...(await walkDir(fullPath)))
} else if (/\.(tsx?|jsx?)$/.test(entry.name)) {
files.push(fullPath)
}
}
return files
}

const files = await walkDir(SRC_DIR)
const missingKeys = new Map()

for (const file of files) {
const content = await fs.readFile(file, 'utf8')
const relPath = path.relative(SRC_DIR, file)
for (const regex of [tCallRegex, tCallMultilineRegex]) {
regex.lastIndex = 0
let match
while ((match = regex.exec(content)) !== null) {
const key = match[1]
if (key.startsWith('{{') || key.includes('${')) continue
if (!enKeys.has(key)) {
if (!missingKeys.has(key)) missingKeys.set(key, [])
missingKeys.get(key).push(relPath)
}
}
}
}

if (missingKeys.size === 0) {
console.log('All t() keys found in en.json!')
} else {
console.log(`Found ${missingKeys.size} missing keys:\n`)
for (const [key, files] of [...missingKeys.entries()].sort(([a], [b]) => a.localeCompare(b))) {
console.log(` "${key}"`)
for (const f of [...new Set(files)]) console.log(` -> ${f}`)
}
}
```

### Step 3: Find untranslated entries (value equals English)

Create and run `web/default/scripts/find-untranslated.mjs`:

```javascript
import fs from 'node:fs/promises'
import path from 'node:path'

const LOCALES_DIR = path.resolve('src/i18n/locales')
const en = JSON.parse(await fs.readFile(path.join(LOCALES_DIR, 'en.json'), 'utf8'))
const enTrans = en.translation

// Brand names, URLs, technical terms — skip these
const skipPatterns = [
/^https?:\/\//, /^smtp\./, /^socks5:/, /^name@/, /^noreply@/,
/^org-/, /^price_/, /^whsec_/, /^edit_this$/, /^my-status$/,
/^_copy$/, /^gpt-/, /^checkout\./, /^footer\./, /^\[?\{/,
/^"default/, /^\/status\//, /^\/your\//, /^example\.com/,
/^AZURE_/, /^AccessKey/, /^OAuth/, /^Client /, /^Webhook URL/,
/^API URL$/, /^Well-Known/, /^Worker URL$/, /^Uptime Kuma/,
/^New API/, /^Baidu V2$/, /^Zhipu V4$/, /^Quota:$/,
]

const brandNames = new Set([
'AIGC2D','Anthropic','API2GPT','Claude','Cloudflare','Cohere','DeepSeek',
'Discord','DoubaoVideo','FastGPT','Gemini','GitHub','Jimeng','JustSong',
'LingYiWanWu','LinuxDO','Midjourney','MidjourneyPlus','MiniMax','Mistral',
'MokaAI','Moonshot','NewAPI','OhMyGPT','Ollama','OpenAI','OpenAIMax',
'OpenRouter','Passkey','Perplexity','QuantumNous','Replicate','SiliconFlow',
'Stripe','Submodel','SunoAPI','Telegram','Tencent','Vertex AI','VolcEngine',
'WeChat','Xinference','Xunfei','AI Proxy','One API',
])

const locales = ['fr', 'ja', 'ru', 'zh', 'vi']

for (const locale of locales) {
const locFile = JSON.parse(await fs.readFile(path.join(LOCALES_DIR, `${locale}.json`), 'utf8'))
const locTrans = locFile.translation
const untranslated = {}

for (const [key, enVal] of Object.entries(enTrans)) {
const locVal = locTrans[key]
if (locVal === undefined || locVal !== enVal) continue
if (brandNames.has(key)) continue
if (skipPatterns.some(p => p.test(key))) continue
if (typeof enVal === 'string' && enVal.length < 4) continue
if (/[a-zA-Z]{3,}/.test(String(enVal))) untranslated[key] = enVal
}

const count = Object.keys(untranslated).length
if (count > 0) {
console.log(`\n=== ${locale} (${count} untranslated) ===`)
for (const [k, v] of Object.entries(untranslated))
console.log(` ${JSON.stringify(k)}: ${JSON.stringify(v)}`)
} else {
console.log(`\n=== ${locale}: all translated ===`)
}
}
```

### Step 4: Add translations

Create `web/default/scripts/add-missing-keys.mjs` with this structure:

```javascript
import fs from 'node:fs/promises'
import path from 'node:path'

const LOCALES_DIR = path.resolve('src/i18n/locales')

function stableStringify(obj) {
return JSON.stringify(obj, null, 2) + '\n'
}

const newKeys = {
en: { /* "key": "English value" */ },
zh: { /* "key": "中文翻译" */ },
fr: { /* "key": "Traduction française" */ },
ja: { /* "key": "日本語翻訳" */ },
ru: { /* "key": "Русский перевод" */ },
vi: { /* "key": "Bản dịch tiếng Việt" */ },
}

async function main() {
let totalAdded = 0

for (const [locale, trans] of Object.entries(newKeys)) {
const filePath = path.join(LOCALES_DIR, `${locale}.json`)
const json = JSON.parse(await fs.readFile(filePath, 'utf8'))

let count = 0
for (const [key, value] of Object.entries(trans)) {
if (!Object.prototype.hasOwnProperty.call(json.translation, key)) {
json.translation[key] = value
count++
} else if (json.translation[key] !== value) {
json.translation[key] = value
count++
}
}

if (count > 0) {
json.translation = Object.fromEntries(
Object.entries(json.translation).sort(([a], [b]) => a.localeCompare(b))
)
await fs.writeFile(filePath, stableStringify(json), 'utf8')
}

console.log(`${locale}: ${count} translations applied`)
totalAdded += count
}

console.log(`\nTotal: ${totalAdded} translations applied`)
}

main().catch((err) => { console.error(err); process.exitCode = 1 })
```

Populate the `newKeys` object with actual translations for each locale.

### Step 5: Verify and clean up

```bash
cd web/default
node scripts/add-missing-keys.mjs # apply translations
node scripts/find-missing-keys.mjs # verify: should say "All t() keys found"
bun run i18n:sync # normalize file order
```

Delete temporary scripts after completion.

## Translation Guidelines

| Language | Code | Notes |
|----------|------|-------|
| English | en | Base locale, key = value |
| Chinese | zh | Fallback locale, must be complete |
| French | fr | Many English cognates are valid (e.g., "Configuration") |
| Japanese | ja | Use katakana for technical loanwords |
| Russian | ru | Use formal register |
| Vietnamese | vi | Use standard Vietnamese |

**Keep as English (do not translate):**
- Brand/product names (OpenAI, Claude, Gemini, etc.)
- URLs and email placeholders
- Technical identifiers (JSON keys, API paths, model names)
- Code-like strings (gpt-3.5-turbo, price_xxx, etc.)

**Always translate:**
- UI labels, button text, error messages, descriptions
- Time units (hours, minutes, months, years)
- Action words (Move, Show, Delete, etc.)

## Key Rules

1. All scripts run from `web/default/` directory
2. Use `node scripts/xxx.mjs` (ESM format with top-level await)
3. Sort keys alphabetically when writing locale files
4. Always run `bun run i18n:sync` as the final step
5. Delete temporary scripts after completion
6. The `{{variable}}` placeholders in keys must be preserved in all translations
Loading
Loading