Skip to content

Comments

release#199

Merged
ding113 merged 76 commits intomainfrom
dev
Nov 25, 2025
Merged

release#199
ding113 merged 76 commits intomainfrom
dev

Conversation

@ding113
Copy link
Owner

@ding113 ding113 commented Nov 25, 2025

摘要

发布 PR,将 dev 分支累积的功能、改进和错误修复合并到 main 分支。

主要功能

MCP(模型上下文协议)直通 (#193)

  • 添加 MCP 直通功能,将工具调用转发给第三方 AI 服务

  • 支持 GLM MCP 直通并提供多语言配置

  • 提升 MCP 处理的安全性和稳定性

提供商 API 测试改进

  • 支持流式响应检测与处理

  • 增强错误解析逻辑,提供更好的诊断信息

  • 为 API 测试功能添加免责声明翻译

  • 修复 Codex 提供商 API 测试失败的问题

  • 通过 API_TEST_TIMEOUT_MS 环境变量可配置 API 测试超时时间

改进

  • 提供商超时:将默认超时更新为无限制,以提高兼容性

  • 静默期:将流式静默期超时从 10 秒调整为 300 秒

  • 使用记录:优化状态码颜色显示以提高可见性

  • 响应模型标签:明确提供商响应模型的标注

错误修复

  • 修复 Gemini 模型重定向无法正常工作的错误

  • 修复模型重定向信息未保存到数据库的问题

  • 修复提供商多标签匹配问题

  • 修复模型重定向日志记录问题

  • 修复错误规则的正则匹配及缓存刷新问题

  • 修复 i18n API 测试免责声明翻译键路径问题

  • 修复代理回退时出现“Body has already been read”错误

  • 修复 errorRules.cacheStats i18n 参数不匹配问题

  • 修复错误规则版本同步问题

  • 修复 Anthropic API 测试同时发送两个认证头的问题

  • 修复 Codex API 测试请求体格式问题

  • 修复 Pino 日志时间戳配置位置错误

  • 恢复意外删除的 i18n 字段(descriptionFull/Warning)

  • 修复数据导入跨版本兼容性和错误提示问题

文档

  • 简化 CLAUDE.md,使 AI 代理指南更加简洁

  • 更新 AGENTS.md,提供更清晰的项目结构和命令说明

测试

  • 已进行手动测试

  • 对现有 API 无重大破坏性更改

相关 PR


🤖 由 Claude Code 生成

flintttan and others added 30 commits November 21, 2025 17:59
完整实现 MCP (Model Context Protocol) 透传功能,支持 minimax 图片识别和联网搜索

功能特性:
- 支持 4 种透传类型: none, minimax, glm (预留), custom (预留)
- 实现 MinimaxMcpClient: webSearch() 和 understandImage() 方法
- 完整的 UI 配置表单和国际化支持 (中英文)
- 数据库迁移文件和数据访问层集成
- MCP 透传处理器实现

技术实现:
- 数据模型: McpPassthroughType 类型定义
- 数据库: providers 表新增 mcp_passthrough_type 字段
- Repository: 6 处字段映射添加
- Actions: addProvider/editProvider 支持 MCP 配置
- UI: Collapsible 配置区域,支持类型选择
- MCP Client: 类型安全的 API 调用封装
- Handler: 工具调用检测和透传处理

Author: flintttan <flintttan@gmail.com>
Related: WFS-mcp-passthrough-feature (IMPL-001 ~ IMPL-008)
完整实现 GLM MCP 透传功能,支持图片分析和视频分析,并补充完整的多语言 i18n 配置

## 主要功能
- 新增 GLM MCP 客户端:支持 analyze_image、analyze_video 工具
- 更新 MCP 透传处理器:集成 GLM 工具调用处理
- 扩展类型定义:添加 GLM 相关的请求/响应类型
- 完善 i18n 配置:5 种语言(EN、ZH-CN、ZH-TW、JA、RU)共 100 个翻译条目

## 技术实现
- 架构:统一端点设计(/api/chat/completions)
- 客户端:GlmMcpClient 类,完整错误处理和日志
- 处理器:handleGlmToolCall() 方法,参数验证
- 类型安全:TypeScript 严格类型检查

## 支持的工具
MiniMax (2个):
  • web_search - 联网搜索
  • understand_image - 图片理解

GLM (2个):
  • analyze_image - 图片分析 ⭐ 新增
  • analyze_video - 视频分析 ⭐ 新增

## 文件变更
新增文件:
  • src/lib/mcp/glm-client.ts (169 行)
  • src/lib/mcp/types.ts (扩展 +30 行)
  • src/lib/mcp/minimax-client.ts (从 commit 37d8665 恢复)
  • src/app/v1/_lib/proxy/mcp-passthrough-handler.ts (扩展 +70 行)

修改文件:
  • messages/*/settings.json (5 个语言文件,各 20 个 MCP 配置项)

## 验证结果
  ✓ TypeScript 语法检查通过
  ✓ JSON 格式验证通过
  ✓ i18n 配置验证通过(5 种语言)
  ✓ GLM 描述已从 "reserved" 更新为实际功能

Related: WFS-mcp-passthrough-feature (IMPL-001 ~ IMPL-009)
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Resolve merge conflicts and integrate GLM MCP functionality
- Maintain MiniMax MCP support (web_search, understand_image)
- Add GLM MCP support (analyze_image, analyze_video)
- Update i18n configurations for 5 languages

Files updated:
  • src/lib/mcp/types.ts - Added GLM type definitions
  • src/app/v1/_lib/proxy/mcp-passthrough-handler.ts - Added GLM handler
  • messages/*/settings.json - Updated i18n for GLM support

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
…-code-hub into feature/mcp-passthrough

# Please enter a commit message to explain why this merge is necessary,
# especially if it merges an updated upstream into a topic branch.
#
# Lines starting with '#' will be ignored, and an empty message aborts
# the commit.
新增对流式响应(如 SSE 和 NDJSON)的识别逻辑,在检测到流式响应时返回明确提示信息。
同时优化 JSON 响应解析流程,增加对非法 JSON 格式的捕获与日志记录。
此外,调整 OpenAI Responses API 测试输入格式,确保符合其接口规范。
某些中转服务不支持 max_output_tokens 参数,导致测试失败。根据注释说明,
该参数在当前上下文中并非必需,因此将其移除以确保与所有服务兼容。
新增对 SSE 和 NDJSON 格式流式响应的解析能力,包括:
- 添加 `streamInfo` 字段以记录接收到的数据块数量及格式
- 实现 `parseSSEText` 和 `parseStreamResponse` 函数用于解析流式数据
- 引入 `mergeStreamChunks` 方法将多个响应块合并为完整响应
- 更新 API 测试逻辑以正确处理并展示流式响应结果
- 增强错误处理机制以应对流式响应解析失败的情况
- 调整 API 测试配置中响应内容预览最大长度从 100 到 500 字符
- 在测试结果中新增 streamInfo 字段用于记录流式响应数据
- UI 上增加流式响应信息的展示区域,包括接收到的数据块数量和流格式
- 支持在结果详情和错误信息区域显示流式响应相关统计
应用 Prettier 格式化规则到 providers.ts,修复 Code Quality Check 失败问题。

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
根据 PR #185 的代码审查建议,修复以下问题:

**Critical 修复**:
- 🔴 修复 Stream reader 资源泄漏
  - 在错误路径中添加 `await reader.cancel()` 防止内存泄漏
  - 确保在异常情况下正确释放资源

**High 修复**:
- 🟠 添加日志记录
  - 为 chunk 解析失败添加 warn 级别日志
  - 记录跳过的 chunk 数量和错误详情
  - 添加流式响应解析完成的 info 日志

- 🟠 改进 SSE 检测逻辑
  - 使用正则表达式替代字符串匹配
  - 提高检测的健壮性,避免误判

- 🟠 增强类型安全
  - 在类型转换前添加运行时类型守卫
  - 为空数组情况添加默认值处理
  - 确保不会创建无效的响应对象

**改进点**:
- 统一错误处理模式
- 提高代码可维护性
- 增强调试能力

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
fix:修复 Codex API 测试参数兼容性问题与增加支持流式测试
## 主要改进

### 1. 供应商模型测试优化
- **显示详细错误信息**: 将后端日志中的 errorDetail 字段返回给前端,用户无需查看容器日志
- **改进测试结果弹窗**: 在"复制结果"按钮右侧添加"关闭"按钮,提升用户体验
- **完善错误处理**: 优化 API 测试失败时的错误信息展示

### 2. 日志时间格式化
- **新增工具函数**: 创建 log-time-formatter.ts,支持将 Unix 时间戳转换为本地时间
- **格式化输出**: 统一日志时间格式为 YYYY/MM/DD HH:mm
- **时区支持**: 支持环境变量 TZ 和浏览器自动检测时区

### 3. ErrorRuleDetector 初始化优化
- **延迟加载**: 移除构造函数中的自动加载,避免数据库未准备好时重复加载
- **显式初始化**: 在 instrumentation.ts 中,数据库连接成功后显式调用 reload()
- **减少启动日志**: 避免在数据库准备前输出重复的加载日志

## 技术细节

### 修改文件
- src/actions/providers.ts: 返回详细错误信息
- src/app/[locale]/settings/providers/_components/forms/api-test-button.tsx: 添加关闭按钮
- messages/*/settings.json: 添加"关闭"翻译
- src/lib/utils/log-time-formatter.ts: 新增日志时间格式化工具
- src/lib/error-rule-detector.ts: 移除构造函数中的自动加载
- src/instrumentation.ts: 在数据库准备好后显式初始化 ErrorRuleDetector

### 测试
- ✅ TypeScript 类型检查通过
- ✅ 所有修改符合 SOLID、KISS、DRY、YAGNI 原则

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
合并供应商测试和日志系统优化

主要改进:
- 供应商模型测试显示详细错误信息
- 测试结果弹窗添加关闭按钮
- 新增日志时间格式化工具
- 优化 ErrorRuleDetector 初始化时机

详见 commit 07267a5
## 修改内容

### 1. 重构 instrumentation.ts 中的重复代码
- **提取公共函数**: 将 ErrorRuleDetector 初始化逻辑提取为独立的 `initializeErrorRuleDetector()` 函数
- **消除重复**: 生产环境和开发环境共用同一个初始化函数
- **提高可维护性**: 遵循 DRY 原则,未来修改只需更新一处

### 2. 优化 log-time-formatter.ts
- **移除硬编码区域设置**: 将 `zh-CN` 改为 `undefined`,使用运行时默认区域设置,提高通用性
- **统一日志记录**: 使用 `logger.error` 替代 `console.error`,保持日志记录一致性
- **改进错误回退**: 使用 `toISOString()` 替代 `toLocaleString()`,提供明确的 ISO 8601 格式

## 技术改进

- ✅ 遵循 DRY (Don't Repeat Yourself) 原则
- ✅ 提高代码可维护性和健壮性
- ✅ 增强国际化支持
- ✅ 统一错误处理策略
- ✅ TypeScript 类型检查通过

## 相关 PR

- 响应 PR #186 的代码审查建议
- 感谢 @gemini-code-assist 的详细审查

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Add postgres and drizzle-orm to serverExternalPackages to prevent bundling Node.js-only modules (net, tls, crypto, stream, perf_hooks)
- Set CI=true in Dockerfile to skip instrumentation database connections during build
- Fixes Module not found errors for Node.js built-in modules during Next.js build
## 修改内容

### 1. 修复 providers.ts 中的 null 检查 (Medium Priority) ✅
**问题**: 缺少对 errorText 的 null/undefined 检查,可能产生误导性错误消息

**解决方案**:
- 添加防御性检查: `errorText ? clipText(errorText, 200) : "No error details available"`
- 移除冗余的 `|| "API 请求失败"` 回退,直接使用 finalErrorDetail

**效果**: 避免空字符串产生误导性错误消息,提供更清晰的错误反馈

### 2. 修复 ErrorRuleDetector 竞态条件 (High Priority) ✅
**问题**: 移除构造函数自动加载后,在启动阶段调用 detect() 会返回 false negatives

**解决方案**:
- 添加 `isInitialized` 状态跟踪
- 实现 `ensureInitialized()` 懒加载保护
- 新增 `detectAsync()` 方法,确保规则已加载
- 同步 `detect()` 方法添加未初始化警告

**效果**:
- 避免启动阶段的竞态条件
- 保持向后兼容性(同步 detect 方法)
- 推荐使用 detectAsync 以确保规则已加载

### 3. 确认 instrumentation.ts 重构 ✅
**状态**: 已在上一次提交中完成,符合审查要求
- 提取了 `initializeErrorRuleDetector()` 公共函数
- 消除了生产和开发环境的代码重复
- 遵循 DRY 原则

### 4. 添加 JSDoc 示例 (Low Priority) ✅
**改进**: 为 log-time-formatter.ts 添加使用示例

**新增内容**:
- `formatLogTime()` 添加系统时区和指定时区的示例
- `formatLogTimes()` 添加批量格式化的示例

**效果**: 提升开发者体验,特别是 timezone 参数的使用

## 技术验证
- ✅ TypeScript 类型检查通过
- ✅ 所有修改符合项目编码规范
- ✅ 解决了所有 High 和 Medium 优先级问题
- ✅ 完成了 Low 优先级改进建议

## 相关 PR
- 响应 PR #186 的 ding113 审查意见
- 感谢 @ding113 的详细审查和建议

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
The Docker build was failing because Next.js webpack was trying to bundle
Node.js built-in modules (net, tls, crypto, stream, perf_hooks) imported
by the postgres package through instrumentation.ts.

While serverExternalPackages was configured, it wasn't sufficient for the
build phase. This fix adds explicit webpack externals configuration to
properly exclude Node.js built-in modules from the server bundle.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
## 修改内容

### 1. 修复 null 安全问题 (🟠 High Priority) ✅
**问题**: Map.get() 返回 `string | undefined`,直接插值可能产生 "undefined" 字符串

**解决方案**:
- 添加验证检查,确保所有必需的时间部分都已成功获取
- 如果任一部分缺失,记录警告并回退到 ISO 8601 格式
- 提供详细的日志信息(timestamp, timezone)便于调试

**代码**:
```typescript
if (!year || !month || !day || !hour || !minute) {
  logger.warn(
    "[log-time-formatter] Failed to get all date parts, falling back to ISO string",
    { timestamp, timezone }
  );
  return new Date(timestamp).toISOString();
}
```

**效果**: 防止输出 "undefined/undefined/undefined undefined:undefined" 的无效日期字符串

### 2. 添加文件级文档说明 (🟡 Medium Priority) ✅
**问题**: 文件未被使用,违反 YAGNI 原则

**解决方案**:
- 添加详细的模块文档,说明计划用途
- 列出具体的集成场景:
  1. Dashboard 日志显示组件
  2. 实时监控页面
  3. 日志导出功能
- 添加集成计划清单
- 预留 issue 链接位置

**效果**:
- 明确工具函数的设计意图和使用场景
- 为后续集成提供清晰的路线图
- 符合代码文档最佳实践

## 技术验证
- ✅ TypeScript 类型检查通过
- ✅ 增强了代码健壮性
- ✅ 提供了清晰的文档和集成计划

## 相关 PR
- 响应 PR #186 的最新审查意见
- 感谢 @ding113@gemini-code-assist 的详细审查

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
## 修改内容

### 1. 删除未使用的 log-time-formatter.ts (🟢 Low) ✅
**问题**: 整个文件未被使用,违反 YAGNI 原则

**解决方案**: 删除文件,遵循 "You Aren't Gonna Need It" 原则

**理由**:
- 文件中包含 TODO 清单,但没有实际集成
- 没有任何导入或使用此文件的代码
- 根据 CLAUDE.md: "不要为假设的未来需求设计"
- 当实际需要时可以在未来 PR 中重新添加

**效果**: 减少技术债务和维护负担

### 2. 优化错误处理避免代码重复 (🟡 Medium) ✅
**问题**: `initializeErrorRuleDetector()` 函数内部捕获错误但不传播,可能掩盖严重问题

**解决方案**:
- 移除函数内部的 try-catch,让关键错误传播
- 在调用处添加 try-catch,实现优雅降级
- 添加清晰的注释说明错误处理策略

**代码**:
```typescript
// 函数内部 - 让关键错误传播
async function initializeErrorRuleDetector(): Promise<void> {
  await initializeDefaultErrorRules();
  logger.info("Default error rules initialized successfully");

  await errorRuleDetector.reload();
  logger.info("Error rule detector cache loaded successfully");
}

// 调用处 - 优雅降级
try {
  await initializeErrorRuleDetector();
} catch (error) {
  logger.error("[Instrumentation] Non-critical: Error rule detector initialization failed", error);
  // 继续启动 - 错误检测不是核心功能的关键依赖
}
```

**效果**:
- ✅ 关键错误可以被正确传播和处理
- ✅ 调用者可以决定是否需要优雅降级
- ✅ 避免掩盖严重的数据库连接问题
- ✅ 保持应用启动的灵活性

## 技术验证
- ✅ TypeScript 类型检查通过
- ✅ 遵循 YAGNI 原则
- ✅ 改进错误处理策略
- ✅ 减少代码重复

## 相关 PR
- 响应 PR #186 的最新审查意见
- 感谢 @ding113 的详细审查和建议

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
fix: 优化供应商测试和日志系统
- 移除 session.requestUrl 的 readonly 属性
- 在 ModelRedirector.apply() 中添加 Gemini URL 路径重写逻辑
- Gemini API 模型名称通过 URL 路径传递,需要修改 pathname 而非 body
@ding113
Copy link
Owner Author

ding113 commented Nov 25, 2025

📊 PR Size Analysis

This PR is XL (Extra Large) with 7,692 lines changed across 59 files.

Large PRs are harder to review and more likely to introduce bugs. Consider splitting this release PR into smaller, focused PRs.

🔀 Suggested Split:

Based on the changes, this PR could be split into 6 separate PRs:

1. MCP Passthrough Feature (~5 files)

New MCP (Model Context Protocol) passthrough functionality:

  • src/lib/mcp/glm-client.ts
  • src/lib/mcp/minimax-client.ts
  • src/lib/mcp/types.ts
  • src/app/v1/_lib/proxy/mcp-passthrough-handler.ts
  • src/app/v1beta/[...route]/route.ts

2. Error Rules Feature (~4 files)

Error classification and rules system:

  • scripts/init-error-rules.ts
  • src/actions/error-rules.ts
  • src/lib/error-rule-detector.ts
  • src/repository/error-rules.ts

3. Proxy Core Improvements (~10 files)

Core proxy handling changes:

  • src/app/v1/_lib/codex/chat-completions-handler.ts
  • src/app/v1/_lib/proxy/error-handler.ts
  • src/app/v1/_lib/proxy/errors.ts
  • src/app/v1/_lib/proxy/forwarder.ts
  • src/app/v1/_lib/proxy/message-service.ts
  • src/app/v1/_lib/proxy/model-redirector.ts
  • src/app/v1/_lib/proxy/provider-selector.ts
  • src/app/v1/_lib/proxy/response-handler.ts
  • src/app/v1/_lib/proxy/session.ts
  • src/lib/rate-limit/service.ts

4. Provider Management Updates (~5 files + i18n)

Provider form and API test improvements:

  • src/actions/providers.ts
  • src/repository/provider.ts
  • src/app/[locale]/settings/providers/_components/forms/api-test-button.tsx
  • src/app/[locale]/settings/providers/_components/forms/provider-form.tsx
  • messages/*/settings.json (5 translation files)

5. Database Schema & Migrations (~11 files)

Schema changes and migrations:

  • src/drizzle/schema.ts
  • src/types/provider.ts
  • src/lib/constants/provider.constants.ts
  • drizzle/0022_simple_stardust.sql
  • drizzle/0023_*.sql
  • drizzle/0024_*.sql
  • drizzle/meta/*.json

6. Documentation & Cleanup (~10 files)

Documentation updates and utilities:

  • AGENTS.md, CLAUDE.md, README.md, README.en.md, CHANGELOG.md
  • .env.example, next.config.ts
  • UI component updates
  • Utility/validation improvements

Why Split?

  • Easier to review - Reviewers can focus on one concern at a time
  • Faster CI feedback - Smaller PRs complete CI faster
  • Easier to revert - If a feature causes issues, revert just that PR
  • Better git history - Clear separation of features and fixes
  • Reduced merge conflicts - Smaller PRs are less likely to conflict

Alternative: Merge as Release PR

If this is an intentional release/merge PR combining multiple feature branches, consider:

  • Adding a detailed PR description listing all included features
  • Using squash merge to keep history clean
  • Ensuring all included changes have been individually reviewed

🤖 Automated analysis by Claude AI

This comment was marked as off-topic.

This comment was marked as off-topic.

@ding113
Copy link
Owner Author

ding113 commented Nov 25, 2025

🔒 Security Scan Results

🚨 Vulnerabilities Found

  • Critical (🔴): 0 vulnerabilities
  • High (🟠): 2 vulnerabilities
  • Medium (🟡): 0 weaknesses
  • Low (🟢): 0 informational findings

⚡ Actions Recommended

  1. Enhance SSRF Protection in Zod Schema (src/lib/validation/schemas.ts)

    • Add IPv6 localhost/private address blocking (::1, fe80::, fd00::)
    • Block 0.0.0.0 wildcard address
    • Explicitly block cloud metadata endpoints (169.254.169.254)
    • Consider DNS resolution check at runtime
  2. MCP Tool Input Validation (src/lib/mcp/minimax-client.ts, src/lib/mcp/glm-client.ts)

    • Validate image_url, image_source, video_source parameters for SSRF
    • These parameters come from AI model tool calls and could be manipulated

📋 OWASP Top 10 Coverage

  • A01: Injection - ✅ ReDoS protection present via safe-regex
  • A02: Broken Authentication - ✅ Session validation present
  • A03: Sensitive Data Exposure - ✅ API keys properly sanitized in logs
  • A04: XML External Entities - N/A (no XML parsing)
  • A05: Broken Access Control - ✅ Admin-only actions properly gated
  • A06: Security Misconfiguration - ✅ Good defaults, DoS limits for streams
  • A07: XSS - N/A (server-side changes)
  • A08: Insecure Deserialization - ✅ JSON.parse with proper error handling
  • A09: Known Vulnerabilities - Not analyzed (dependency check out of scope)
  • A10: Logging & Monitoring - ✅ Comprehensive logging present

✅ Security Positives Noted

  1. DoS Protection: Stream parsing includes limits (MAX_STREAM_CHUNKS, MAX_STREAM_BUFFER_SIZE, MAX_STREAM_ITERATIONS)
  2. Credential Sanitization: sanitizeErrorTextForLogging() properly redacts API keys, Bearer tokens, and sensitive paths
  3. ReDoS Protection: Error rules validation uses safe-regex to prevent catastrophic backtracking
  4. SSRF Foundation: Initial SSRF protection in place (blocks common private IPs), needs enhancement
  5. Timeout Protection: MCP clients have 30s timeout to prevent hanging connections

🛡️ Security Posture

Needs Improvement - The PR implements good security foundations (DoS limits, credential sanitization, ReDoS protection), but the SSRF protection has gaps that should be addressed before production deployment, especially if the system will be exposed to untrusted users.


🤖 Automated security scan by Claude AI - OWASP Top 10 & CWE coverage

Copy link
Owner Author

@ding113 ding113 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Documentation Review

📊 Issues Summary

  • Critical (🔴): 0 - No blocking issues
  • High (🟠): 2 - Should fix before merge
  • Medium (🟡): 1 - Consider addressing
  • Low (🟢): 0 - No minor issues

⚡ Priority Fixes

  1. 🟠 Missing Provider Type in AGENTS.md: Documentation omits gemini provider type (distinct from gemini-cli) that exists in schema. See src/drizzle/schema.ts:105.

  2. 🟠 CHANGELOG.md removes existing entries: The PR removes several documented changelog entries (real-time monitoring #184, dark mode provider quota #170, i18n improvements #182, database migration fix #181, error handling fix #179) that appear to be legitimate historical changes.

  3. 🟡 AGENTS.md title mismatch: File is renamed with title "# CLAUDE.md" but filename remains AGENTS.md. This creates confusion about the file's purpose. Either:

    • Rename file to CLAUDE.md if intended as duplicate/replacement
    • Keep unique title like "# Repository Guidelines" or "# AGENTS.md"

📋 Review Coverage

  • Technical accuracy - 1 issue (missing provider type)
  • Completeness - 1 issue (changelog entries removed)
  • Code examples - 0 issues (all commands verified correct)
  • Links and references - 0 issues (paths verified)
  • Clarity and organization - 1 issue (title mismatch)

💡 Detailed Issues


Issue 1: Missing Provider Type (AGENTS.md)

🟠 HIGH

Problem: The Provider Types section lists 5 provider types but omits the gemini type.

Current (Incomplete):

- `claude` - Anthropic API (standard)
- `claude-auth` - Claude relay services (Bearer auth only)
- `codex` - Codex CLI (Response API)
- `gemini-cli` - Gemini CLI
- `openai-compatible` - OpenAI Compatible APIs

Suggested Fix:

- `claude` - Anthropic API (standard)
- `claude-auth` - Claude relay services (Bearer auth only)
- `codex` - Codex CLI (Response API)
- `gemini` - Gemini API
- `gemini-cli` - Gemini CLI
- `openai-compatible` - OpenAI Compatible APIs

Reference: src/drizzle/schema.ts:105 shows all 6 types:

.$type<'claude' | 'claude-auth' | 'codex' | 'gemini-cli' | 'gemini' | 'openai-compatible'>()

Issue 2: CHANGELOG.md Removes Existing Entries

🟠 HIGH

Problem: The PR removes the following documented changes from CHANGELOG.md that appear to be legitimate historical entries:

Removed entries:

  • Add real-time monitoring big screen dashboard with live metrics, 24h trends, provider slots status, and activity stream (#184) @ding113
  • Add dark mode support to provider quota management page (#170) @ding113
  • Merge dev to main with internationalization improvements (Japanese, Russian, Traditional Chinese) and UI enhancements for daily limit dialogs (#182) @ding113
  • Refactor provider quota management page from card layout to compact list layout with circular progress indicators, search, and sorting capabilities (#170) @ding113
  • Fix database migration duplicate enum type creation error (#181) @ding113
  • Fix error handling and status codes in response handler, improve user management page UX (#179) @ding113

Impact: Loss of project history and traceability.

Suggested Fix: Preserve existing changelog entries and only add the new MCP passthrough entry (#193).


Issue 3: AGENTS.md Title Mismatch

🟡 MEDIUM

Problem: The file AGENTS.md now starts with # CLAUDE.md as its title, which is confusing.

Impact: Developers may be confused about whether this is AGENTS.md or CLAUDE.md.

Suggested Fix: Either:

  1. Use a unique title: # AGENTS.md or # Claude Code Hub Guidelines
  2. Or if this file is meant to replace/duplicate CLAUDE.md, rename the file accordingly

✅ Verified Correct Items

The following documentation elements were verified as accurate:

  1. Development Commands: All bun run commands verified in package.json
  2. Directory Structure: All paths (src/app/v1/_lib/, src/actions/, etc.) exist
  3. Guard Pipeline: GuardPipelineBuilder verified in src/app/v1/_lib/proxy/guard-pipeline.ts
  4. Database Schema Tables: All 7 tables verified in src/drizzle/schema.ts
  5. OpenAPI Documentation URLs: Paths verified correct
  6. i18n Messages Path: /messages/{locale}/ directory structure verified
  7. Format Converters Location: src/app/v1/_lib/converters/ contains all mentioned converters
  8. README Changes: API_TEST_TIMEOUT_MS addition is correct and matches .env.example

🤖 Automated docs review by Claude AI

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This is a substantial pull request that introduces the MCP passthrough feature, significantly enhances the provider API testing capabilities, and includes numerous improvements to robustness, logging, and configuration. The code quality is high, with good attention to detail, security (SSRF protection), and user experience (improved i18n strings, better error feedback). The database migrations and schema changes are well-aligned with the new features. The refactoring of error detection and application initialization logic improves maintainability and resilience. I found one minor issue in the provider update logic. Overall, this is an excellent set of changes.

Copy link
Owner Author

@ding113 ding113 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📋 Code Review Summary

This PR introduces MCP (Model Context Protocol) passthrough functionality and makes several improvements including lazy initialization for ErrorRuleDetector, schema changes for timeout defaults, and database backup migration integration. Overall, the changes are well-structured, but I've identified a few issues that should be addressed.

🔍 Issues Found

  • Critical (🔴): 0 issues
  • High (🟠): 2 issues
  • Medium (🟡): 1 issue
  • Low (🟢): 0 issues

🎯 Priority Actions

  1. Race condition in lazy initialization (src/lib/error-rule-detector.ts): The ensureInitialized() method returns early when isLoading is true, but doesn't wait for the ongoing load to complete. Concurrent calls during initialization will proceed with potentially empty rules.

  2. Unused variable in IP validation (src/actions/notifications.ts): The variable c from IPv4 regex match is removed but the array destructuring pattern [, a, b] doesn't match the original comment about checking octet c for the 172.16-31.x.x range.

  3. Missing MCP passthrough URL validation in UpdateProviderSchema (src/lib/validation/schemas.ts): While CreateProviderSchema has URL validation with SSRF protection for mcp_passthrough_url, UpdateProviderSchema appears to be missing this validation (based on the pattern of other fields).

💡 Detailed Issues

🟠 High: Race Condition in Lazy Initialization

File: src/lib/error-rule-detector.ts:72-83

The ensureInitialized() method has a race condition:

private async ensureInitialized(): Promise<void> {
  if (this.isInitialized || this.isLoading) {
    return; // ❌ Returns immediately without waiting
  }
  await this.reload();
}

When multiple concurrent requests call detectAsync() while the first initialization is in progress, all subsequent calls will skip reload() entirely and proceed to detect() with potentially empty rules.

Suggested fix:

private initializationPromise: Promise<void> | null = null;

private async ensureInitialized(): Promise<void> {
  if (this.isInitialized) {
    return;
  }
  
  if (\!this.initializationPromise) {
    this.initializationPromise = this.reload().finally(() => {
      this.initializationPromise = null;
    });
  }
  
  await this.initializationPromise;
}

🟠 High: Timeout Default Changes May Break Existing Deployments

File: src/drizzle/schema.ts:169-172

The default timeout values are changed from non-zero values to 0 (disabled):

  • firstByteTimeoutStreamingMs: 30000 → 0
  • streamingIdleTimeoutMs: 10000 → 0
  • requestTimeoutNonStreamingMs: 600000 → 0

This is a behavioral change that could cause issues for existing deployments that rely on the default timeouts. With 0 meaning "no timeout", requests could hang indefinitely if the provider becomes unresponsive.

Recommendation: Consider adding a database migration that explicitly sets the old default values for existing providers, or document this breaking change clearly in the changelog.

🟡 Medium: SSRF Validation Missing in UpdateProviderSchema

File: src/lib/validation/schemas.ts

The CreateProviderSchema has comprehensive SSRF protection for mcp_passthrough_url:

mcp_passthrough_url: z
  .string()
  .max(512)
  .url()
  .refine((url) => {
    // Block localhost, private IPs, etc.
  })

However, the UpdateProviderSchema should also include this validation to prevent SSRF when updating an existing provider.

Suggested fix: Add the same SSRF validation refine to the UpdateProviderSchema's mcp_passthrough_url field.


🤖 Automated review by Claude AI - focused on identifying issues for improvement

ding113

This comment was marked as off-topic.

ding113 and others added 3 commits November 26, 2025 01:08
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
使用 Promise 合并模式确保并发请求都等待同一个初始化 Promise,
防止冷启动时后续请求在规则加载完成前就执行检测。

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@ding113 ding113 merged commit 159b0a5 into main Nov 25, 2025
8 checks passed
@ding113 ding113 added the bug Something isn't working label Nov 25, 2025
ding113 pushed a commit that referenced this pull request Nov 25, 2025
@ding113
Copy link
Owner Author

ding113 commented Nov 25, 2025

📊 PR Size Analysis

This PR is XL (Extra Large) with 7,708 lines changed across 59 files.

Large PRs are harder to review and more likely to introduce bugs.


ℹ️ Context

This appears to be a release PR merging accumulated changes from dev to main, consolidating work from PRs #157, #185, #186, #188, #189, #190, #193, #194, #197.

🔀 Suggested Split (for future releases):

Based on the changes, future releases could be split into smaller, focused PRs:

  1. MCP Passthrough Feature (~15 files)

    • src/app/v1beta/[...route]/route.ts
    • src/app/v1/_lib/proxy/mcp-passthrough-handler.ts
    • src/lib/mcp/glm-client.ts
    • src/lib/mcp/minimax-client.ts
    • src/lib/mcp/types.ts
    • Related i18n files
  2. Provider API Test Improvements (~10 files)

    • src/app/[locale]/settings/providers/_components/forms/api-test-button.ts
    • src/app/[locale]/settings/providers/_components/forms/provider-form.tsx
    • src/lib/constants/provider.constants.ts
    • Related configuration files
  3. Error Rules System (~5 files)

    • src/actions/error-rules.ts
    • src/lib/error-rule-detector.ts
    • src/repository/error-rules.ts
    • scripts/init-error-rules.ts
  4. Model Redirector Fixes (~5 files)

    • src/app/v1/_lib/proxy/model-redirector.ts
    • src/app/v1/_lib/proxy/provider-selector.ts
    • src/repository/message.ts
  5. Documentation & Config Updates (~10 files)

    • CLAUDE.md, AGENTS.md, README.md, README.en.md
    • CHANGELOG.md
    • .env.example
    • next.config.ts
  6. Bug Fixes & Minor Improvements (~15 files)

    • Proxy forwarder fixes
    • Response handler improvements
    • Database migration files
    • i18n translations

💡 Recommendations

For a release PR like this, the size is understandable since it consolidates multiple features. However, consider:

  • More frequent releases: Merge to main more often with smaller batches
  • Feature flags: Deploy features incrementally
  • Separate documentation PRs: Keep docs/config changes separate

Why Split?

  • Easier to review (reviewers can focus on one concern at a time)
  • Faster CI feedback
  • Easier to revert if needed
  • Better git history and bisect capability

🤖 Automated analysis by Claude AI

Copy link
Owner Author

@ding113 ding113 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📋 Code Review Summary

This PR introduces significant changes including error rule detection improvements with lazy initialization, MCP passthrough configuration, provider timeout defaults changing to 0 (unlimited), and model recording fixes. The changes are generally well-structured, but there are some issues that should be addressed before merging.

🔍 Issues Found

  • Critical (🔴): 0 issues
  • High (🟠): 2 issues
  • Medium (🟡): 2 issues
  • Low (🟢): 1 issue

🎯 Priority Actions

  1. 🟠 High - Race condition in ErrorRuleDetector: The isInitialized flag is set inside reload() at line 186 of error-rule-detector.ts, but the ensureInitialized() method checks isInitialized before awaiting the promise. If two async operations call detectAsync() simultaneously when not initialized, both might enter ensureInitialized(), and after the first completes and sets isInitialized = true, the second awaits a null promise (since it was set to null in finally). Consider setting isInitialized = true inside the .then() callback of the initialization promise for better atomicity.

  2. 🟠 High - Timeout defaults changed to 0 (unlimited): The schema in src/drizzle/schema.ts changes all timeout defaults to 0 (unlimited):

    • firstByteTimeoutStreamingMs: 30000 → 0
    • streamingIdleTimeoutMs: 10000 → 0
    • requestTimeoutNonStreamingMs: 600000 → 0

    This is a significant behavior change that could cause hanging requests in production if providers don't respond. Existing deployments that relied on default timeouts will now have unlimited timeouts. Consider keeping safe defaults or documenting this breaking change prominently.

  3. 🟡 Medium - SSRF validation mismatch: The SSRF validation in mcp_passthrough_url (lines 205-229 in schemas.ts) validates internal IPs but the validation in validateProviderUrlForConnectivity() in providers.ts has a slightly different pattern set (includes ::1, fe80:, fc00:, fd00: IPv6). These should be consolidated into a shared utility to ensure consistent SSRF protection.

  4. 🟡 Medium - Unused constants: PROXY_RETRY_STATUS_CODES and CLOUDFLARE_ERROR_STATUS_CODES are defined in providers.ts but don't appear to be used anywhere in the visible diff. Verify if they're used or remove them.

  5. 🟢 Low - Documentation inconsistency: The initializeDefaultErrorRules() function is marked as @deprecated in the repository file with a comment suggesting to use syncDefaultErrorRules() instead, but instrumentation.ts still calls initializeDefaultErrorRules() at lines 42 and 78.

💡 General Observations

  • The error rule detector's lazy initialization pattern is a good improvement for startup reliability, but the state management between isLoading, isInitialized, and initializationPromise could be simplified.
  • The change to unlimited timeouts (0) by default is a breaking behavioral change that deserves prominent documentation in CHANGELOG.
  • Good SSRF protection added for MCP passthrough URLs, but consolidate validation logic to avoid drift.

🤖 Automated review by Claude AI - focused on identifying issues for improvement

@@ -0,0 +1,319 @@
/**
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 SSRF (Server-Side Request Forgery): Missing URL validation for user-controlled MCP tool inputs

Security Impact: Attacker can potentially use the MCP passthrough feature to make the server send HTTP requests to internal network resources (localhost, 192.168.x.x, 10.x.x.x, etc.) by supplying malicious image_url, image_source, or video_source values in tool call inputs.

Attack Scenario:

  1. Attacker sends a request with understand_image tool containing image_url: "http://127.0.0.1:5432" or image_url: "http://169.254.169.254/latest/meta-data/" (AWS metadata endpoint)
  2. The MCP client (MinimaxMcpClient/GlmMcpClient) forwards this URL directly to the upstream provider without validation
  3. Even though the upstream provider's URL has SSRF protection (in schema validation), the image_url, image_source, and video_source parameters from tool calls are not validated
  4. This could allow scanning of internal networks or accessing cloud metadata services

Remediation: Add SSRF validation to the MCP passthrough handler before passing user-controlled URLs to MCP clients.

References:

@ding113
Copy link
Owner Author

ding113 commented Nov 25, 2025

🔒 Security Scan Results

🚨 Vulnerabilities Found

  • Critical (🔴): 0 vulnerabilities
  • High (🟠): 1 vulnerability
  • Medium (🟡): 0 weaknesses
  • Low (🟢): 0 informational findings

⚡ Immediate Actions Required

  1. 🟠 SSRF in MCP Tool Inputs (see comment): The image_url, image_source, and video_source parameters in MCP tool calls (understand_image, analyze_image, analyze_video) are validated for type but not for SSRF attacks. While the mcp_passthrough_url configuration field has proper SSRF protection (blocking localhost, private IPs like 10.x.x.x, 192.168.x.x, 172.16-31.x.x), the runtime user inputs bypass this validation.

    Recommended Fix: Reuse the existing SSRF validation logic from CreateProviderSchema/UpdateProviderSchema to validate URLs at runtime before passing them to MCP clients.

✅ Security Strengths Observed

  • SSRF Protection on Config: The mcp_passthrough_url field has comprehensive SSRF protection blocking localhost, 127.0.0.1, ::1, and private IP ranges
  • Type Validation: Tool inputs are validated for proper types (non-empty strings) - this was improved in commit 229f447
  • Timeout Protection: 30-second timeouts implemented for MCP clients to prevent resource exhaustion
  • Sensitive Data Sanitization: The sanitizeErrorTextForLogging() function properly redacts API keys, Bearer tokens, emails, and passwords from error logs
  • Schema Validation: Zod schemas provide input validation for provider configuration

📋 OWASP Top 10 Coverage

  • A01: Injection - ✅ Clean (using Drizzle ORM with parameterized queries)
  • A02: Broken Authentication - ✅ Clean (API keys properly handled)
  • A03: Sensitive Data Exposure - ✅ Clean (proper sanitization in logs)
  • A04: XML External Entities - N/A (no XML processing)
  • A05: Broken Access Control - ✅ Clean
  • A06: Security Misconfiguration - ✅ Clean
  • A07: XSS - N/A (API-focused changes)
  • A08: Insecure Deserialization - ✅ Clean
  • A09: Known Vulnerabilities - N/A (no dependency changes)
  • A10: Logging & Monitoring - ✅ Good (structured logging with Pino)

Additional Checks

  • SSRF - ⚠️ Partial protection (config-level only, runtime inputs unvalidated)
  • Path Traversal - ✅ Clean (no file path operations from user input)
  • Command Injection - ✅ Clean (no shell commands with user input)
  • Cryptographic Issues - ✅ Clean

🛡️ Security Posture

Needs Improvement - The PR has good security practices overall with proper SSRF protection on configuration and log sanitization, but the runtime SSRF gap in MCP tool inputs should be addressed before merge.


🤖 Automated security scan by Claude AI - OWASP Top 10 & CWE coverage

Copy link
Owner Author

@ding113 ding113 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Additional Inline Analysis

Issue 1: Race condition in ErrorRuleDetector (src/lib/error-rule-detector.ts)

Location: Lines 78-92 (ensureInitialized) and line 186 (this.isInitialized = true)

The isInitialized flag is set inside reload() at line 186, but ensureInitialized() checks isInitialized at line 79 before awaiting the promise. Concurrent calls could result in:

  1. Thread A enters ensureInitialized(), isInitialized = false
  2. Thread A creates initializationPromise and starts awaiting
  3. Thread B enters ensureInitialized(), isInitialized = false (reload still in progress)
  4. Thread B sees initializationPromise exists and awaits it
  5. Thread A's reload completes, sets isInitialized = true at line 186, sets initializationPromise = null in finally
  6. Thread B's await completes (was waiting on the promise that just resolved)

This works correctly. However, if reload() is called directly (not through ensureInitialized()), for example from the event listener at line 72, it doesn't use the promise merging pattern and could cause race conditions.

Suggested fix: Make reload() also use the promise merging pattern, or mark it as private and only expose ensureInitialized().


Issue 2: Timeout defaults changed to 0 (src/drizzle/schema.ts)

Location: Lines 169-173 (schema defaults)

-  firstByteTimeoutStreamingMs: integer('first_byte_timeout_streaming_ms').notNull().default(30000),
-  streamingIdleTimeoutMs: integer('streaming_idle_timeout_ms').notNull().default(10000),
-  requestTimeoutNonStreamingMs: integer('request_timeout_non_streaming_ms').notNull().default(600000),
+  firstByteTimeoutStreamingMs: integer('first_byte_timeout_streaming_ms').notNull().default(0),
+  streamingIdleTimeoutMs: integer('streaming_idle_timeout_ms').notNull().default(0),
+  requestTimeoutNonStreamingMs: integer('request_timeout_non_streaming_ms').notNull().default(0),

This changes default behavior from "fail fast with reasonable timeouts" to "wait indefinitely". While the migration script (drizzle/0024_update_provider_timeout_defaults.sql) updates existing providers, new providers will have unlimited timeouts by default. This could lead to resource exhaustion.


Issue 3: SSRF validation inconsistency (src/lib/validation/schemas.ts vs src/actions/providers.ts)

Location: Lines 205-229 in schemas.ts, lines 1012-1023 in providers.ts

The SSRF blocklist in mcp_passthrough_url validation (schemas.ts) misses IPv6 patterns that are present in validateProviderUrlForConnectivity() (providers.ts):

  • ::1 (IPv6 localhost)
  • fe80: (link-local IPv6)
  • fc00:, fd00: (unique local IPv6)

Issue 4: Unused constants (src/actions/providers.ts)

Location: Lines 72-73

const PROXY_RETRY_STATUS_CODES = new Set([502, 504, 520, 521, 522, 523, 524, 525, 526, 527, 530]);
const CLOUDFLARE_ERROR_STATUS_CODES = new Set([520, 521, 522, 523, 524, 525, 526, 527, 530]);

These are defined but not used in the diff. If they're planned for future use, add a TODO comment. If not, remove them.


Issue 5: Deprecated function usage (src/instrumentation.ts)

Location: Lines 42-46 and 76-82

The code calls initializeDefaultErrorRules() which is marked @deprecated in the repository file. The deprecation notice suggests using syncDefaultErrorRules() instead.

- `claude` - Anthropic API (standard)
- `claude-auth` - Claude relay services (Bearer auth only)
- `codex` - Codex CLI (Response API)
- `gemini-cli` - Gemini CLI
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 Missing Provider Type: gemini not listed in Provider Types section

Problem: The Provider Types section lists 5 provider types but omits gemini. According to the database schema in src/drizzle/schema.ts:105, the providerType field supports 6 types including gemini:

.$type<'claude' | 'claude-auth' | 'codex' | 'gemini-cli' | 'gemini' | 'openai-compatible'>()

Impact: Developers may not know that gemini (distinct from gemini-cli) is a valid provider type, leading to confusion when configuring providers.

Suggested Fix:

### Provider Types

The system supports multiple provider types via `providerType` field:

- `claude` - Anthropic API (standard)
- `claude-auth` - Claude relay services (Bearer auth only)
- `codex` - Codex CLI (Response API)
- `gemini` - Gemini API
- `gemini-cli` - Gemini CLI
- `openai-compatible` - OpenAI Compatible APIs

Note: The same issue exists in CLAUDE.md (which correctly includes gemini in the PR version), but this file (AGENTS.md) is missing it.

Copy link
Owner Author

@ding113 ding113 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Documentation Review

📊 Issues Summary

  • Critical (🔴): 0 - Must fix before merge
  • High (🟠): 1 - Should fix before merge
  • Medium (🟡): 0 - Consider addressing
  • Low (🟢): 0 - Optional improvements

⚡ Priority Fix

AGENTS.md - Missing gemini Provider Type: The Provider Types section is missing the gemini provider type. The database schema (src/drizzle/schema.ts:105) defines 6 provider types, but only 5 are documented. This inconsistency between AGENTS.md and CLAUDE.md should be resolved.

📋 Review Coverage

  • Technical accuracy - 1 issue (missing provider type)
  • Completeness - No issues
  • Code examples - No issues
  • Links and references - No issues
  • Clarity and organization - No issues

💡 General Observations

Overall Quality: The documentation changes are well-structured and provide a significant simplification of the project documentation. The changes successfully:

  1. Simplified CLAUDE.md: Reduced from ~900 lines to ~150 lines while preserving essential information
  2. Updated AGENTS.md: Transformed from a coding guidelines file to a proper project overview document
  3. Added API_TEST_TIMEOUT_MS: Both README.md and README.en.md correctly document the new environment variable with appropriate range limits

Recommendation: Fix the missing gemini provider type in AGENTS.md and this PR is ready to merge from a documentation perspective.


🤖 Automated docs review by Claude AI

@ding113 ding113 mentioned this pull request Nov 26, 2025
4 tasks
sususu98 pushed a commit to sususu98/claude-code-hub that referenced this pull request Nov 28, 2025
ding113 pushed a commit that referenced this pull request Nov 28, 2025
ding113 pushed a commit that referenced this pull request Nov 28, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working documentation Improvements or additions to documentation enhancement New feature or request size/XL Extra Large PR (> 1000 lines)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

codex会出现多个超时,但是没有熔断 使用记录中出现多次的Error: Streaming idle timeout

3 participants