Skip to content

feat: add Vertex AI storage integration - #6779

Open
ywandy wants to merge 2 commits into
QuantumNous:mainfrom
ywandy:codex/vertexai-storage
Open

feat: add Vertex AI storage integration#6779
ywandy wants to merge 2 commits into
QuantumNous:mainfrom
ywandy:codex/vertexai-storage

Conversation

@ywandy

@ywandy ywandy commented Aug 11, 2026

Copy link
Copy Markdown

⚠️ 提交说明 / PR Notice

Important

  • 请提供人工撰写的简洁摘要,避免直接粘贴未经整理的 AI 输出。

📝 变更描述 / Description

为 Vertex AI 渠道增加受控的 Google Cloud Storage 集成,使客户端可以通过 new-api 使用已配置服务账号读写指定 bucket,并可在渠道管理界面直接验证真实的存储权限。

  • 在 Vertex AI 渠道模型配置中使用 storage:gs:<bucket> 精确声明允许访问的 bucket,并提供前端独立配置字段与七语言说明。
  • 新增固定 /vertexai Storage Proxy,共五个方法/路由:可恢复或媒体上传、对象列表、对象下载和对象删除。上游主机固定为 storage.googleapis.com,仅支持服务账号 JSON,不接受 API Key 渠道。
  • 分发层强制选择 Vertex AI 类型渠道并再次校验 bucket 精确授权;客户端 Host、Authorization、Cookie、API Key 与 hop-by-hop headers 不会转发到 GCS。
  • 上传和下载均采用流式传输;禁止自动跟随重定向;GCS resumable Location 会校验主机、bucket 和路径后改写为网关 /vertexai 地址,不泄露 Google session URL。
  • 对象路径拒绝 . / .. 点段,避免上游路径归一化突破对象级 API 边界;响应统一设置 Cache-Control: private, no-store 并移除 Expires / Age,避免共享缓存跨 Token 复用。
  • Vertex Storage 渠道测试会真实执行 upload → get → delete,并在失败路径尽力清理临时对象。该路径在计费与消费日志生成前分流,不扣费,也不生成模型消费日志。
  • 补充公共使用文档、OpenAPI 契约,并在项目原有的路由测试文件中覆盖固定 Storage 路由集合。

本变更由 AI 辅助完成;PR 描述已依据实际代码路径、当前提交文件、验证结果和安全审查结论整理。

🚀 变更类型 / Type of change

  • 🐛 Bug 修复 (Bug fix) - 请关联对应 Issue,避免将设计取舍、理解偏差或预期不一致直接归类为 bug
  • ✨ 新功能 (New feature) - 重大特性建议先通过 Issue 沟通
  • ⚡ 性能优化 / 重构 (Refactor)
  • 📝 文档更新 (Documentation)

🔗 关联任务 / Related Issue

✅ 提交前检查项 / Checklist

  • 人工确认: 我已亲自整理并撰写此描述,没有直接粘贴未经处理的 AI 输出。
  • 非重复提交: 我已搜索现有的 IssuesPRs,确认不是重复提交。
  • Bug fix 说明: 若此 PR 标记为 Bug fix,我已提交或关联对应 Issue,且不会将设计取舍、预期不一致或理解偏差直接归类为 bug。
  • 变更理解: 我已理解这些更改的工作原理及可能影响。
  • 范围聚焦: 本 PR 未包含任何与当前任务无关的代码改动。
  • 本地验证: 已在本地运行并通过测试或手动验证,维护者可以据此复核结果。
  • 安全合规: 代码中无敏感凭据,且符合项目代码规范。

📸 运行证明 / Proof of Work

后端:

  • go test ./...
  • go build ./...

前端:

  • bun run i18n:sync:en、zh、zh-TW、fr、ru、ja、vi 的 missing / extras / untranslated 均为 0。
  • bun run typecheck
  • 本 PR 涉及文件的定向 oxlint。
  • bun run build

安全与差异检查:

  • git diff --check upstream/main...HEAD
  • 已检查对象点段校验、bucket 精确授权、固定 GCS Host、凭据/header 过滤、redirect/Location 校验、响应禁共享缓存、流式传输与非计费分流。
  • 当前提交不包含 docs/superpowers/ 文件,也未新增测试文件。

说明:bun run lint 的全仓扫描仍会被当前 upstream/main 中大量非本 PR 文件的既有 oxlint 错误阻断;上述本 PR 涉及文件的定向 lint 已通过。

Summary by CodeRabbit

  • New Features

    • Added Vertex AI Cloud Storage support for uploading, listing, downloading, and deleting objects.
    • Added resumable upload support and secure request validation.
    • Added channel configuration for Google Cloud Storage buckets.
    • Channel selection now respects the required channel type.
  • User Experience

    • Added bucket configuration fields, GCS labels, and temporary-object connection testing.
    • Updated channel testing to use the test dialog.
    • Restored automatic-group status badges for API key groups.
  • Documentation

    • Added API reference and setup guidance for Vertex AI Cloud Storage.

@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: f4ddb7b9-49ce-4387-8fd3-71910cd10b8d

📥 Commits

Reviewing files that changed from the base of the PR and between 86bccdf and fa0fe3e.

📒 Files selected for processing (1)
  • web/src/features/keys/components/api-key-group-cell.tsx

Walkthrough

Adds Vertex AI Cloud Storage upload, listing, retrieval, resumable upload, and deletion support. The change adds typed channel routing, cached Vertex authentication, storage probing, API documentation, channel configuration UI, and automatic-group badge rendering.

Changes

Vertex AI Cloud Storage relay

Layer / File(s) Summary
Storage contracts and proxy transport
relay/constant/*, relay/channel/vertex/*
Adds storage routes, bucket and object validation, cached token acquisition, request construction, header sanitization, resumable URL rewriting, and proxied Cloud Storage execution.
Typed channel distribution and retry selection
constant/context_key.go, middleware/distributor.go, model/*, service/channel_select.go, controller/relay.go
Propagates required channel types through distribution, affinity, retries, and channel selection. Vertex storage paths derive the channel model from the bucket.
Storage handlers and channel probes
controller/vertex_storage_proxy.go, controller/vertex_storage_channel_probe.go, controller/channel-test.go
Adds validated handlers and a temporary-object probe that uploads, downloads, verifies, and deletes an object.
Routes and API contract validation
router/relay-router.go, router/relay_router_test.go, docs/openapi/relay.json
Registers the storage routes and validates their methods, parameters, authentication, bodies, and responses.
Channel configuration and test UI
web/src/features/channels/*, web/src/i18n/locales/*
Separates storage buckets from regular models, adds bucket editing for channel type 41, updates channel testing UI, and adds translations.
Storage API documentation
docs/vertex-ai-storage.md
Documents IAM setup, bucket configuration, routes, resumable uploads, object references, validation, errors, and cost behavior.

API key group status badge

Layer / File(s) Summary
Automatic group badge rendering
web/src/features/keys/components/api-key-group-cell.tsx
Restores the automatic-group badge beside the cross-group status badge.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related PRs

Poem

A rabbit checks each bucket’s name,
Then sends each object through the lane.
Tokens wait in cached repose,
Temporary files come and go.
Badges hop back into view—
Storage paths now pass through too.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 2.08% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the pull request's primary change: adding Vertex AI storage integration.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🧹 Nitpick comments (6)
middleware/distributor.go (1)

276-283: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Wrap the bucket parse error with i18n, as the sibling branches do.

The error from relayconstant.VertexStorageModelName reaches the client through abortWithOpenAiMessage at line 48. Every other branch in getModelRequest returns an i18n-translated message. This branch returns a raw English string, so the response text is not localized.

Proposed change
 	if relayconstant.IsVertexStoragePath(c.Request.URL.Path) {
 		modelName, err := relayconstant.VertexStorageModelName(c.Param("bucket"))
 		if err != nil {
-			return nil, false, err
+			return nil, false, errors.New(i18n.T(c, i18n.MsgDistributorInvalidRequest, map[string]any{"Error": err.Error()}))
 		}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@middleware/distributor.go` around lines 276 - 283, Update the Vertex storage
branch in getModelRequest to wrap the error returned by
relayconstant.VertexStorageModelName with the same i18n translation mechanism
used by sibling branches before returning it, while preserving the existing
success behavior and relay mode assignment.
web/src/features/channels/components/drawers/channel-mutate-drawer.tsx (2)

3550-3560: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Align sourceModelOptions with the bucket-filtered options used elsewhere.

sourceModelOptions={currentModelsArray} passes the full model list, including storage:gs: bucket pseudo-model entries, to ModelMappingEditor. Every other guardrail in this file (missingSourceModels at line 1195, exposedTargetModels at line 1207, and targetModelOptions at line 3556) treats storage buckets as non-models by filtering through currentRegularModels/modelOptions.

Use currentRegularModels for sourceModelOptions so storage bucket entries do not appear as selectable "source" models in the model-mapping editor.

♻️ Proposed fix
-                                      sourceModelOptions={currentModelsArray}
+                                      sourceModelOptions={currentRegularModels}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web/src/features/channels/components/drawers/channel-mutate-drawer.tsx`
around lines 3550 - 3560, Update the ModelMappingEditor invocation to pass
currentRegularModels as sourceModelOptions instead of currentModelsArray,
keeping storage bucket pseudo-models excluded from selectable source models.

3435-3447: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Clarify that "Clear All" does not remove configured storage buckets.

handleClearModels calls updateModels([]), which merges the cleared model list with currentStorageBuckets, so Vertex AI storage bucket entries survive this action. The button is labeled "Clear All" and only disables when currentRegularModels.length === 0, so an admin with only storage buckets configured could reasonably expect this action to also affect bucket configuration.

Add a short description, tooltip, or adjust the label so it is clear this action clears regular models only and preserves configured storage buckets.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web/src/features/channels/components/drawers/channel-mutate-drawer.tsx`
around lines 3435 - 3447, Clarify the button action in the JSX using the
existing handleClearModels control: update the “Clear All” label or add a short
description/tooltip stating that it clears regular models only and preserves
configured storage buckets. Keep the current disabled condition and handler
behavior unchanged.
web/src/i18n/locales/zh-TW.json (1)

2097-2097: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use one Traditional Chinese term for "bucket" consistently.

Four of the five new entries translate "bucket" as "儲存值區" (lines 216, 978, 1693, 4341), but line 2097 translates the same English term as "儲存桶". Use the same term for the same concept across all five new strings.

Pick one term (for example "儲存值區", matching the majority of the new entries) and update line 2097 to match.

♻️ Proposed fix
-    "GCS bucket: writes, reads, and deletes a temporary object": "GCS 儲存桶:寫入、讀取並刪除一個暫存物件",
+    "GCS bucket: writes, reads, and deletes a temporary object": "GCS 儲存值區:寫入、讀取並刪除一個暫存物件",

Also applies to: 216-216, 978-978, 1693-1693, 4341-4341

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web/src/i18n/locales/zh-TW.json` at line 2097, Update the Traditional Chinese
translation for “GCS bucket: writes, reads, and deletes a temporary object” to
use the same bucket terminology as the other new entries, preferably “儲存值區”
instead of “儲存桶.”
web/src/features/channels/lib/vertex-storage-models.ts (1)

26-36: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Tighten bucket name validation to match GCS naming rules.

normalizeVertexStorageBucket only rejects \, /, ?, #, ://, ., .., and the model prefix. Google Cloud Storage bucket names must contain only lowercase letters, numbers, dashes, underscores, and dots, must start and end with a letter or number, and must be 3–63 characters long. Uppercase letters, spaces, and other invalid characters currently pass this check and reach the backend, where they will fail against the real GCS API with a less clear error.

Update the validation to enforce the full GCS naming rule set (lowercase-only character class, length bound, start/end character constraint) so invalid names are rejected at the point of entry instead of surfacing later as an upstream failure.

♻️ Proposed tightened validation
-const INVALID_BUCKET_CHARACTERS = /[\\/?#]/
+const VALID_BUCKET_NAME = /^[a-z0-9][a-z0-9._-]{1,61}[a-z0-9]$/

 export function normalizeVertexStorageBucket(value: string): string | null {
   const bucket = value.trim()
   if (!bucket || bucket === '.' || bucket === '..') return null
   if (bucket.startsWith(VERTEX_STORAGE_MODEL_PREFIX)) return null
-  if (bucket.includes('://') || INVALID_BUCKET_CHARACTERS.test(bucket)) {
-    return null
-  }
-  return bucket
+  if (bucket.includes('://') || !VALID_BUCKET_NAME.test(bucket)) {
+    return null
+  }
+  return bucket
 }

Since this relates to Google Cloud Storage's external naming specification, please confirm the exact rule set is still current before adopting this diff verbatim.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web/src/features/channels/lib/vertex-storage-models.ts` around lines 26 - 36,
Update normalizeVertexStorageBucket to enforce the current GCS bucket naming
rules: accept only lowercase letters, digits, dashes, underscores, and dots;
require 3–63 characters; and require the first and last characters to be
alphanumeric. Preserve the existing null returns for empty, dot-only,
model-prefixed, and URL-like values, and verify the validation matches the
current GCS specification.
web/src/features/channels/components/drawers/sections/vertex-storage-buckets-field.tsx (1)

54-54: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Replace the magic number 41 with a named channel-type constant.

Define CHANNEL_TYPE_VERTEX_AI alongside CHANNEL_TYPE_NEW_API and use it for the Vertex AI check. Keep the numeric ID in one central definition.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@web/src/features/channels/components/drawers/sections/vertex-storage-buckets-field.tsx`
at line 54, Define the named CHANNEL_TYPE_VERTEX_AI constant alongside
CHANNEL_TYPE_NEW_API with value 41, then update the channelType check in the
Vertex storage buckets field to use that constant instead of the literal. Keep
the numeric channel ID centralized in the constant definition.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/vertex-ai-storage.md`:
- Line 35: Update every GCS_OBJECT example in the documentation to
percent-encode the complete object name, not only slash characters; ensure
characters such as ?, #, &, %, spaces, and non-ASCII text are encoded
consistently wherever GCS_OBJECT is used as a query value or path segment.
- Line 13: 更新文档中的 GCS IAM 权限说明:为固定的上传、列举、读取和删除流程记录所需的精确自定义角色权限,并将
roles/storage.objectUser 明确标为宽泛的便利回退选项;同时说明只读/列举场景可使用
roles/storage.objectViewer,以及 roles/storage.objectCreator 不能覆盖或删除对象。
- Line 160: Update the Location guidance in the documentation to treat
RESUMABLE_LOCATION as opaque and instruct clients to use the returned Location
unchanged. Remove the requirement that it start with NEW_API_BASE_URL/vertexai/,
while preserving the explanation of gateway validation, rewriting, and
subsequent PUT authorization.

In `@relay/channel/vertex/storage_proxy.go`:
- Around line 188-207: Update DoStorageProxy after copying the HTTP client to
set storageClient.Timeout to zero, preserving request-context cancellation while
preventing the shared RELAY_TIMEOUT from terminating progressing storage
transfers.

In `@web/src/features/channels/components/dialogs/channel-test-dialog.tsx`:
- Around line 889-896: Update the GCS StatusBadge in the channel test dialog to
pass its label through the existing translation function t(), matching the
adjacent Default badge pattern and preserving the current badge behavior.

---

Nitpick comments:
In `@middleware/distributor.go`:
- Around line 276-283: Update the Vertex storage branch in getModelRequest to
wrap the error returned by relayconstant.VertexStorageModelName with the same
i18n translation mechanism used by sibling branches before returning it, while
preserving the existing success behavior and relay mode assignment.

In `@web/src/features/channels/components/drawers/channel-mutate-drawer.tsx`:
- Around line 3550-3560: Update the ModelMappingEditor invocation to pass
currentRegularModels as sourceModelOptions instead of currentModelsArray,
keeping storage bucket pseudo-models excluded from selectable source models.
- Around line 3435-3447: Clarify the button action in the JSX using the existing
handleClearModels control: update the “Clear All” label or add a short
description/tooltip stating that it clears regular models only and preserves
configured storage buckets. Keep the current disabled condition and handler
behavior unchanged.

In
`@web/src/features/channels/components/drawers/sections/vertex-storage-buckets-field.tsx`:
- Line 54: Define the named CHANNEL_TYPE_VERTEX_AI constant alongside
CHANNEL_TYPE_NEW_API with value 41, then update the channelType check in the
Vertex storage buckets field to use that constant instead of the literal. Keep
the numeric channel ID centralized in the constant definition.

In `@web/src/features/channels/lib/vertex-storage-models.ts`:
- Around line 26-36: Update normalizeVertexStorageBucket to enforce the current
GCS bucket naming rules: accept only lowercase letters, digits, dashes,
underscores, and dots; require 3–63 characters; and require the first and last
characters to be alphanumeric. Preserve the existing null returns for empty,
dot-only, model-prefixed, and URL-like values, and verify the validation matches
the current GCS specification.

In `@web/src/i18n/locales/zh-TW.json`:
- Line 2097: Update the Traditional Chinese translation for “GCS bucket: writes,
reads, and deletes a temporary object” to use the same bucket terminology as the
other new entries, preferably “儲存值區” instead of “儲存桶.”
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: a4bacb76-12a5-4369-b5b6-b7ee3033b6b5

📥 Commits

Reviewing files that changed from the base of the PR and between ccd535e and 86bccdf.

📒 Files selected for processing (31)
  • constant/context_key.go
  • controller/channel-test.go
  • controller/relay.go
  • controller/vertex_storage_channel_probe.go
  • controller/vertex_storage_proxy.go
  • docs/openapi/relay.json
  • docs/vertex-ai-storage.md
  • middleware/distributor.go
  • model/ability.go
  • model/channel_cache.go
  • relay/channel/vertex/service_account.go
  • relay/channel/vertex/storage_proxy.go
  • relay/constant/relay_mode.go
  • relay/constant/vertex_storage.go
  • router/relay-router.go
  • router/relay_router_test.go
  • service/channel_select.go
  • web/src/features/channels/components/data-table-row-actions.tsx
  • web/src/features/channels/components/dialogs/channel-test-dialog.tsx
  • web/src/features/channels/components/drawers/channel-mutate-drawer.tsx
  • web/src/features/channels/components/drawers/sections/index.ts
  • web/src/features/channels/components/drawers/sections/vertex-storage-buckets-field.tsx
  • web/src/features/channels/lib/index.ts
  • web/src/features/channels/lib/vertex-storage-models.ts
  • web/src/i18n/locales/en.json
  • web/src/i18n/locales/fr.json
  • web/src/i18n/locales/ja.json
  • web/src/i18n/locales/ru.json
  • web/src/i18n/locales/vi.json
  • web/src/i18n/locales/zh-TW.json
  • web/src/i18n/locales/zh.json

Comment thread docs/vertex-ai-storage.md

1. 在 Google Cloud 项目中创建供 Vertex AI 渠道使用的服务账号。
2. 为服务账号授予调用 Vertex AI 所需的权限,例如 `roles/aiplatform.user`。
3. 在目标 bucket 上授予与实际操作匹配的 GCS 权限。需要完整执行本指南的上传、下载、列举和删除操作时,可授予 `roles/storage.objectUser`;生产环境应按最小权限原则拆分只读或只写权限。

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Use least-privilege IAM guidance.

roles/storage.objectUser grants folder, multipart-upload, object move, restore, and update permissions in addition to the permissions needed by these fixed routes. Document a custom role for the exact upload/list/get/delete flow, or clearly mark roles/storage.objectUser as a broad convenience fallback. Also state that roles/storage.objectViewer is suitable for read/list-only access and roles/storage.objectCreator cannot overwrite or delete objects. (docs.cloud.google.com)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/vertex-ai-storage.md` at line 13, 更新文档中的 GCS IAM
权限说明:为固定的上传、列举、读取和删除流程记录所需的精确自定义角色权限,并将 roles/storage.objectUser
明确标为宽泛的便利回退选项;同时说明只读/列举场景可使用 roles/storage.objectViewer,以及
roles/storage.objectCreator 不能覆盖或删除对象。

Source: MCP tools

Comment thread docs/vertex-ai-storage.md
export NEW_API_BASE_URL="https://api.example.com"
export NEW_API_TOKEN="<your-new-api-token>"
export GCS_BUCKET="example-bucket"
export GCS_OBJECT="docs%2Freport.pdf"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Encode the complete object name.

GCS_OBJECT is used both as the name query value and as a path segment. Encoding only / is insufficient for names containing ?, #, &, %, spaces, or non-ASCII characters. Require percent-encoding of the complete object name and apply the same rule to every example.

Proposed documentation update
- export GCS_OBJECT="docs%2Freport.pdf"
+ # Percent-encode the complete object name as one URL component.
+ export GCS_OBJECT="docs%2Freport.pdf"

- 对象名中的 `/` 应编码为 `%2F`。
+ `GCS_OBJECT` 必须将完整对象名按 URL 组件编码,包括将 `/` 编码为 `%2F`。

Also applies to: 53-53

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/vertex-ai-storage.md` at line 35, Update every GCS_OBJECT example in the
documentation to percent-encode the complete object name, not only slash
characters; ensure characters such as ?, #, &, %, spaces, and non-ASCII text are
encoded consistently wherever GCS_OBJECT is used as a query value or path
segment.

Comment thread docs/vertex-ai-storage.md
} | awk 'tolower($1) == "location:" { sub(/\r$/, "", $2); print $2 }')"
```

返回的 `Location` 必须以 `${NEW_API_BASE_URL}/vertexai/` 开头。网关会校验 Google 返回的 session URL,并使用系统配置的服务地址安全改写;改写失败时返回 `502`,不会把 `storage.googleapis.com` session URL 暴露给客户端。后续每个 `PUT` 都会重新执行 Token 鉴权、限流、渠道分发和 bucket 授权。

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Treat RESUMABLE_LOCATION as opaque.

If the client uses an alias or base URL that differs from system_setting.ServerAddress, the valid rewritten Location will not necessarily start with NEW_API_BASE_URL/vertexai/. The proxy rewrites it from the configured server address in controller/vertex_storage_proxy.go, Lines 48-143. Tell clients to use the returned Location unchanged.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/vertex-ai-storage.md` at line 160, Update the Location guidance in the
documentation to treat RESUMABLE_LOCATION as opaque and instruct clients to use
the returned Location unchanged. Remove the requirement that it start with
NEW_API_BASE_URL/vertexai/, while preserving the explanation of gateway
validation, rewriting, and subsequent PUT authorization.

Comment on lines +188 to +207
func DoStorageProxy(ctx context.Context, input StorageProxyRequest) (*http.Response, error) {
request, err := buildStorageRequest(ctx, input)
if err != nil {
return nil, err
}
client, err := service.GetHttpClientWithProxy(input.Proxy)
if err != nil {
return nil, fmt.Errorf("new proxy http client failed: %w", err)
}
storageClient := *client
storageClient.CheckRedirect = func(_ *http.Request, _ []*http.Request) error {
return http.ErrUseLastResponse
}
response, err := storageClient.Do(request)
if err != nil {
return nil, err
}
response.Header = SanitizeStorageResponseHeader(response.Header)
return response, nil
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Check whether the shared proxy HTTP client sets a global Timeout.
rg -n -C 10 'func GetHttpClientWithProxy\b' service

Repository: QuantumNous/new-api

Length of output: 1789


Clear the shared client timeout for storage transfers.

If RELAY_TIMEOUT is non-zero, DoStorageProxy preserves it on the copied client. The timeout can terminate large uploads or downloads during an otherwise progressing transfer.

Set storageClient.Timeout = 0 and rely on the request context for cancellation.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@relay/channel/vertex/storage_proxy.go` around lines 188 - 207, Update
DoStorageProxy after copying the HTTP client to set storageClient.Timeout to
zero, preserving request-context cancellation while preventing the shared
RELAY_TIMEOUT from terminating progressing storage transfers.

Comment on lines +889 to +896
{isVertexStorage && (
<StatusBadge
label='GCS'
variant='info'
size='sm'
copyable={false}
/>
)}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Wrap the GCS badge label with t().

The GCS badge label is a literal string. The adjacent Default badge at line 883 uses t('Default'). Use the same pattern for consistency and to keep all user-facing text translatable.

🌐 Proposed fix
                 {isVertexStorage && (
                   <StatusBadge
-                    label='GCS'
+                    label={t('GCS')}
                     variant='info'
                     size='sm'
                     copyable={false}
                   />
                 )}

Based on path instructions, "Frontend user-facing text must use i18next/react-i18next: React components should call useTranslation() and t('English key')."

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
{isVertexStorage && (
<StatusBadge
label='GCS'
variant='info'
size='sm'
copyable={false}
/>
)}
{isVertexStorage && (
<StatusBadge
label={t('GCS')}
variant='info'
size='sm'
copyable={false}
/>
)}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web/src/features/channels/components/dialogs/channel-test-dialog.tsx` around
lines 889 - 896, Update the GCS StatusBadge in the channel test dialog to pass
its label through the existing translation function t(), matching the adjacent
Default badge pattern and preserving the current badge behavior.

Source: Path instructions

@ywandy

ywandy commented Aug 13, 2026

Copy link
Copy Markdown
Author

@seefs001 新增vertexai的存储桶逻辑 。 可以合并下

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant