Commit Graph
5241 Commits
Author SHA1 Message Date
superman2003 4a97491be6 fix(grok): let manual connection tests bypass the scheduling gate
Grok OAuth 'test connection' reused the production GrokTokenProvider
request path, whose eligibility gate rejects any account that is not
currently schedulable (manual switch off, rate limited, overloaded,
temporarily cooled down). Every such test failed before reaching xAI
with the generic 'oauth refresh account state changed', while
Codex/OpenAI account tests read credentials regardless of scheduling
state (#4598).

Add GetAccessTokenForManualTest and use it from the account test
service:

- skips the request-path scheduling eligibility gate so admins can
  probe excluded accounts; credential integrity checks (configured
  proxy present, refresh token present) still apply
- refreshes expired tokens through the shared OAuthRefreshAPI without
  the request-path marker, so the lock protocol and DB re-read keep
  working while scheduling state no longer blocks the refresh;
  credential rotation for non-active accounts stays blocked inside
  RefreshIfNeeded
- falls back to the still-valid current token when a refresh attempt
  fails or another worker holds the refresh lock, and otherwise
  surfaces the concrete refresh error instead of the generic message

Fixes #4598
2026-07-19 22:40:58 +08:00
superman2003 35b5edb24c fix(update): detach in-place update from the HTTP request lifetime
The in-place update ran entirely inside c.Request.Context(). Browsers and
reverse proxies commonly abort long-idle requests (axios global timeout
30s, nginx proxy_read_timeout 60s by default), which canceled the request
context mid-download and killed every slow update with
'download failed: context canceled' while the version stayed unchanged.
Users behind slow GitHub links saw the update button fail at a wall-clock
ceiling (~60s) on every attempt (#4504).

- Run PerformUpdate and RollbackToVersion on a context detached from the
  request (context.WithoutCancel) and bounded by a 15-minute deadline so
  the 10-minute GitHub download client owns its own timeout. A client
  disconnect no longer aborts the binary swap; retries then hit the
  system operation lock or report 'Already up to date'.
- Raise the frontend timeout for the update/rollback calls from the
  global 30s axios default to 15 minutes so the browser can actually
  wait for the result.

Fixes #4504
2026-07-19 22:40:44 +08:00
wucm667 01062c3244 fix(openai): correct buffered messages content type 2026-07-19 22:28:49 +08:00
zhangxaochen 604b764cf5 fix(openai): return standard insufficient quota errors 2026-07-19 21:59:45 +08:00
JlypxandSisyphus f69042ca6e docs: 更新客户端 IP 配置索引
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-07-19 21:42:54 +08:00
JlypxandSisyphus 41b58b640a docs: 更新可信代理部署说明
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-07-19 21:42:33 +08:00
JlypxandSisyphus 5da3325a30 feat: 在安全设置中配置客户端 IP 模式
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-07-19 21:42:12 +08:00
JlypxandSisyphus 93717394b2 fix: 迁移客户端 IP 兼容开关
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-07-19 21:41:45 +08:00
JlypxandSisyphus 6aa6b3a968 fix: 将客户端 IP 模式注入请求上下文
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-07-19 21:41:12 +08:00
JlypxandSisyphus 39107ca457 fix: 安全初始化 Gin 可信代理
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-07-19 21:40:32 +08:00
JlypxandSisyphus 6e2ba0e4cd fix: 统一请求级客户端 IP 模式
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-07-19 21:39:49 +08:00
JlypxandSisyphus 8a147fcc51 fix: 解析显式可信代理配置
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-07-19 21:39:24 +08:00
cugxuan d0fa8c63f1 fix(subscription): round remaining days up 2026-07-19 21:37:26 +08:00
cat 3a4966f786 fix(openai): 限制 Codex call_id 归一化长度 2026-07-19 21:28:47 +08:00
superman2003andCursor 3ed2873f14 fix(openai): mark OAuth accounts unschedulable on Codex models manifest 401
The Codex models manifest path returned upstream 401s straight to the
client without feeding them into the account state machinery. A revoked
or invalidated OAuth account therefore stayed active and schedulable,
kept being selected for subsequent /models requests, and produced
repeated 502s until an admin ran a manual connection test (#4544).

- Route ChatGPT-backend manifest 401s through the shared upstream-error
  handling: token cache invalidation, temp-unschedulable cooldown for
  refreshable OAuth accounts, permanent disable for
  token_revoked/token_invalidated, plus the runtime scheduling block.
- Treat ChatGPT-backend manifest 401s as failover-eligible so the
  current /models request can switch to a healthy account instead of
  returning 502. Custom API key upstream 401s keep the existing
  no-failover, no-disable behavior since their /models auth is not
  authoritative for the account.
- Skip Agent Identity accounts: their 401s can be task-scoped and have
  a dedicated recovery flow.
- Attach the selected account to the ops error-log context so /models
  failures record the account_id.

Fixes #4544

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-19 21:13:27 +08:00
orchief c044d5c1f1 fix(openai): avoid duplicate OAuth system prompts
Root cause: Chat bridge system messages were mirrored to instructions while remaining in input as developer messages.

Fix: omit only losslessly promoted system messages for non-JSON-object OAuth Chat requests while preserving compatibility paths.

Closes #4603
2026-07-19 19:48:25 +08:00
Jlypx 732aeef880 fix: 兼容反代和 Docker 客户端 IP 解析 2026-07-19 19:41:01 +08:00
superman2003 3dcf412b65 fix(grok): preserve Trae cache routing across turns 2026-07-19 19:00:08 +08:00
superman2003 c8ff478876 fix(grok): default client tool caching on for Free accounts 2026-07-19 18:59:50 +08:00
jjaw f7979ae8ff 优化 Responses SSE 事件类型解析 2026-07-19 18:50:33 +08:00
jjaw 8fd6f91b7e 优化 Responses 生图意图复用 2026-07-19 18:49:08 +08:00
Kinso 7840eb1c49 [verified] fix(openai): make HTTP bridge failover safe
Route first-turn pre-response transport, HTTP, and SSE failures through the existing account failover path without replaying later turns. Require a real Responses terminal event and preserve platform-specific OpenAI/Grok error side effects.
2026-07-19 17:13:27 +08:00
harukaandClaude Opus 4.8 6102d64274 fix(wire): 补上 PromptAdminService 的绑定,恢复 wire 代码生成
ProviderSet 提供了 NewPromptAdminHandler,也绑定了 PromptEngine,却没有为
PromptAdminService 绑定实现,导致 go generate ./cmd/server 直接失败:

  no provider found for securityaudit.PromptAdminService
  needed by *securityaudit.PromptAdminHandler

*PromptService 本就实现了该接口的全部方法,wire_gen.go 也一直是手工维护到位的
(补上绑定后重新生成的结果与现有文件逐字节一致),只是生成这条路被堵死了,
后续任何依赖改动都无法再靠 go generate 同步。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VHreE5pzCkSYz7J45fmd2Y
2026-07-19 01:03:41 -07:00
superman2003 eea02c38fc fix(grok): cache Claude Desktop client tools 2026-07-19 16:03:18 +08:00
harukaandClaude Opus 4.8 0343dba916 feat(admin): 备份页新增异步生图对象存储配置卡片
对应后端 /admin/backups/image-storage。放在备份页而非系统设置页,是因为它与
数据库备份共用同一套 S3 客户端与凭证——用户的心智就是"在备份的 S3 上加个开关"。

- 默认勾选"复用备份 S3",此时隐藏端点/密钥字段,只留 bucket 与 prefix,
  bucket 留空则沿用备份桶。
- 保存走 useStepUp,与备份 S3 配置的保存路径一致。
- 补中英文案。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VHreE5pzCkSYz7J45fmd2Y
2026-07-19 00:56:33 -07:00
harukaandClaude Opus 4.8 b08cab91a9 feat(image-storage): 异步生图对象存储改为后台配置,保存即生效
此前开启异步生图必须改服务器上的 config.yaml 并重启容器(#4542),且若想
复用已配置的备份 S3,还得把同一套凭证再填一遍(#4458)。

- 新增 ImageStorageSettingService:配置存 settings 表,SecretAccessKey 经
  SecretEncryptor 加密落库、读回脱敏、留空表示沿用旧值,与备份 S3 配置同一套做法。
- reuse_backup_s3(默认开)直接借用 backup_s3_config 的端点与密钥,只用自己的
  bucket/prefix 区分对象,因此备份走 backups/、图片走 images/,且密钥不会在库里存两份。
- ImageTaskService 的启用状态改由 ImageStorageResolver 在运行时解析并缓存,
  保存设置后 Invalidate 使下次请求重建客户端——不再需要重启。
- repository 侧由提供实例改为提供工厂,客户端才可能在运行期重建。
- 轮询接口的门控从 enabled() 放宽为 Pollable():关掉开关只拒绝新提交,
  已受理的任务仍可取回结果,不再被中途吞掉。
- config.yaml 的 image_storage 保留为回落,后台从未保存过时沿用,
  升级前已用配置文件开启的部署不受影响。
- 管理端 GET/PUT/POST /admin/backups/image-storage,PUT 与备份 S3 配置一样要求
  step-up 2FA:改写存储目标同样能把生成内容导向外部账号。

注:go generate ./cmd/server 在当前 upstream 基线上即失败(securityaudit.
PromptAdminService 缺 provider),故 wire_gen.go 为手工同步。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VHreE5pzCkSYz7J45fmd2Y
2026-07-19 00:56:21 -07:00
huangjunsen ef88cf3f89 fix(grok): improve Claude Messages prompt-cache round-trip
Round-trip Grok encrypted reasoning via Anthropic thinking.signature and
seed cache identity from Claude Code session IDs, so multi-turn /v1/messages
traffic can hit xAI prompt cache more like CLIProxyAPI. Also strip invalid
encrypted_content and retry on the Messages path when decrypt fails after
account switches.
2026-07-19 15:00:09 +08:00
superman2003 9d79b42729 feat(admin): expose Grok client tool cache opt-in 2026-07-19 14:42:06 +08:00
cat 7a05a7cdcc test(openai): 检查 Agent Identity 测试类型断言 2026-07-19 14:42:01 +08:00
superman2003 752b2eaa9b fix(grok): bridge Trae tool requests through responses 2026-07-19 14:41:55 +08:00
superman2003 026d2a8083 fix(grok): promote Codex Lite tools for caching 2026-07-19 14:41:47 +08:00
superman2003 5af38ccf41 fix(grok): add guarded client tool cache routing 2026-07-19 14:41:38 +08:00
NickandClaude Fable 5 340dc99e02 fix(deploy): pass the documented postgres tuning values to postgres
deploy/.env.example documents POSTGRES_MAX_CONNECTIONS,
POSTGRES_SHARED_BUFFERS, POSTGRES_EFFECTIVE_CACHE_SIZE and
POSTGRES_MAINTENANCE_WORK_MEM, with notes on how to size them — but no
compose file ever passes them to the postgres container. A user who sets
them in .env gets nothing, silently.

Wire them into the postgres command in deploy/docker-compose.yml. The
fallbacks are the postgres:18 stock defaults (100 / 128MB / 4GB / 64MB),
so a deploy that does not set the variables behaves exactly as before.

Checked with postgres:18-alpine: with the variables unset, SHOW gives
the stock values; with them set (1024 / 1GB / 6GB / 128MB), SHOW gives
the set values.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 12:17:31 +07:00
NickandClaude Fable 5 8a2d7c5bd3 fix(deploy): make the redis command flags take effect in dev and local compose
PR #4506 fixed this in deploy/docker-compose.yml, but the same broken
form is still in docker-compose.dev.yml and docker-compose.local.yml.
The redis command is one quoted script given to the inner sh -c, and
compose keeps the newlines inside the quoted string, so redis-server on
the first line runs as a complete command with no flags at all. The
--save / --appendonly / --appendfsync lines are silently never applied,
and ${REDIS_PASSWORD:+--requirepass ...} is dead too — redis takes no
password even when REDIS_PASSWORD is set.

The fix is the same trailing `\` line continuations as #4506, with the
same comment, so the three compose files read the same way.

Checked with both files on redis:8-alpine, REDIS_PASSWORD set. Before:
PING with no auth said PONG, appendonly was "no", save was the stock
"3600 1 300 100 60 10000". After: no-auth PING gets NOAUTH, appendonly
is "yes", save is "60 1". With REDIS_PASSWORD unset the server still
starts open, as before.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 12:16:27 +07:00
huangjunsen ba2b0044e3 fix(apicompat): emit null stop_reason on Anthropic message_start
Use *string for AnthropicResponse.StopReason so streaming message_start
serializes as JSON null instead of "", matching official Anthropic wire
format and avoiding strict client turn-finalization failures.
2026-07-19 13:05:24 +08:00
superman2003 d2753dc2e2 fix(grok): serve current free quota policy 2026-07-19 12:17:52 +08:00
superman2003 c99e479bcc fix(grok): retry transient billing probes 2026-07-19 12:17:42 +08:00
superman2003 b8c640d218 fix(proxy): include Grok in quality checks 2026-07-19 12:17:31 +08:00
superman2003 1433fbc44d fix(grok): estimate messages count tokens locally 2026-07-19 12:17:23 +08:00
Jlypx 2cff4bf169 fix: 修复 golangci-lint 检查错误 2026-07-19 11:39:20 +08:00
Jlypx 361983cf4d feat: 优化运维定时报表邮件模板 2026-07-19 11:23:26 +08:00
wucm667 510ee451bd feat: support GitHub token for update checks 2026-07-19 11:02:56 +08:00
AstrenixandClaude Fable 5 7bbe170405 feat(frontend): migrate batch image page to vue-i18n
BatchImageGuideView carried ~140 user-visible strings outside vue-i18n:
hardcoded Chinese template strings (buttons, placeholders, tooltips,
table headers, dialog titles, empty states) plus an inline bilingual
batchImageText dictionary switched by isZhLocale() in script.

Move all of it into a new batchImage locale namespace (180 leaf keys
per language, zh/en verified key-aligned) registered in both locale
indexes, reusing 15 existing common.*/pagination.* keys. Column and
filter-option definitions become computed so language switches take
effect immediately; countable strings use vue-i18n plurals and the
three rich-text counters keep their inner bold spans via <i18n-t>
slots.

The Codex agent-instruction prompt template intentionally stays as a
plain string: it is an AI-facing prompt document containing literal
JSON braces that conflict with vue-i18n message syntax.

Verified: eslint, vue-tsc --noEmit, vite build, and the full vitest
suite (175 files / 1219 tests) all pass.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 03:12:39 +08:00
AstrenixandClaude Fable 5 3401a971a8 fix(frontend): localize stray hardcoded UI strings
Move the last few user-visible hardcoded strings into vue-i18n:

- AppHeader: "Toggle Menu" / "User Menu" aria-labels (screen readers
  read these in English regardless of locale)
- CustomPageView: "Page not found" error body
- PaymentProviderDialog: display-name example placeholder hardcoded in
  Chinese for all locales

Adds common.toggleMenu / common.userMenu / common.pageNotFound and
admin.settings.payment.customMethodDisplayNamePlaceholder to both zh
and en locales, and registers the new placeholder key in the
PaymentProviderDialog spec's i18n mock.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 02:55:50 +08:00
AstrenixandClaude Fable 5 ed280b81fc style(frontend): align dark-mode surfaces with the slate dark palette
The project's dark theme uses the custom slate-based dark-* palette
(928 dark:bg-dark-* / 787 dark:border-dark-* occurrences), but a
minority of surfaces still used Tailwind's neutral gray-* scale, which
has a visibly cooler hue next to slate cards — most noticeably the
filter dropdown panels on the usage, accounts and subscriptions pages.

Migrate the remaining dark:bg-gray-* / dark:border-gray-* (and their
hover: variants) to the dark-* palette across 12 components: filter
dropdowns, chart card borders, menu separators, and small badges.
49 class-string substitutions, no structural or logic changes;
dark:text-gray-* is untouched since gray text on dark surfaces is the
established project-wide convention.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 02:45:41 +08:00
AstrenixandClaude Fable 5 841544345f fix(frontend): make user email readable in balance modal dark mode
The user info banner in UserBalanceModal renders on a dark:bg-dark-700
container, but the email line kept text-gray-900 and the balance line
text-gray-500 with no dark variants, leaving near-black text on a dark
background. Align both with the pattern already used elsewhere in the
same dialog (text-gray-900 dark:text-gray-100 / text-gray-500
dark:text-gray-400).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 02:41:32 +08:00
AstrenixandClaude Fable 5 4c73149af8 fix(frontend): restore scrolling on the available channels page
The available channels table rendered inside its own
"card overflow-hidden" wrapper instead of the ".table-wrapper" element
that TablePageLayout's scroll chain expects. The outer
.table-scroll-container is overflow-hidden, so when the channel list
grew taller than the viewport the content was simply clipped with no
scrollbar. The extra card wrapper also drew a double border inside the
layout's own card chrome.

Mount the table on .table-wrapper like every other table page so it
receives overflow-y-auto from the layout, and add a source-convention
regression test in the style of TablePageLayout.spec.ts.

Fixes #4555

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 02:18:41 +08:00
AstrenixandClaude Fable 5 a1e1997632 fix(openai): accept standard OpenAI model list for Codex model discovery
Custom API key upstreams that only implement the standard OpenAI
GET /v1/models endpoint return {"object":"list","data":[{"id":...}]},
which the Codex models manifest validation rejected with
"missing top-level models array", surfacing HTTP 502 to Codex clients.

Convert the standard list envelope into the Codex manifest shape
({"models":[{"slug":...}]}) for API key upstreams before validation.
Bodies that already carry a top-level models field, are not the
standard list shape, or yield no usable model IDs are left unchanged
so existing validation and account failover behavior is preserved.

Fixes #4490

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 02:09:57 +08:00
cat a67351caec fix(openai): 按 Team 隔离 Agent Identity 导入 2026-07-19 01:40:49 +08:00
abbzbb 62846bb074 fix(security-audit): 仅在 blocking 意图下 fail-closed,修复无法关闭审计
configUntrusted 不再单独强制 ModeBlocking,避免默认关闭部署在配置
加载失败时对全部请求返回 prompt_guard_unavailable;成功保存配置后
清除 untrusted,确保管理员关闭提示词审计能立即生效。

Fixes #4560
2026-07-18 23:57:45 +08:00