Skip to content

feat: add log filter autocomplete and tab completion#3419

Open
MisonL wants to merge 9 commits intoQuantumNous:mainfrom
MisonL:feat/log-filter-autocomplete-clean
Open

feat: add log filter autocomplete and tab completion#3419
MisonL wants to merge 9 commits intoQuantumNous:mainfrom
MisonL:feat/log-filter-autocomplete-clean

Conversation

@MisonL
Copy link

@MisonL MisonL commented Mar 24, 2026

📝 变更描述 / Description

  • 为使用日志、任务日志、绘图日志增加筛选联想接口与前端联想输入组件。
  • 联想结果按普通用户 / 管理员视角分别限域,并增加独立的联想请求限流。
  • 增加运行时开关 general_setting.log_filter_autocomplete_enabled,并将开关放到“日志设置”区域。
  • 支持 Tab 键按当前高亮项或首项完成补全。
  • 本次已清理分支历史,当前 PR 仅保留日志筛选自动补全相关改动;responses bootstrap recovery 已独立保留在 Improve responses stream startup recovery during temporary channel outages #3392

🚀 变更类型 / Type of change

  • 🐛 Bug 修复 (Bug fix)
  • ✨ 新功能 (New feature)
  • ⚡ 性能优化 / 重构 (Refactor)
  • 📝 文档更新 (Documentation)

🔗 关联任务 / Related Issue

✅ 提交前检查项 / Checklist

  • 人工确认: 我已亲自撰写此描述,去除了 AI 原始输出的冗余。
  • 深度理解: 我已完全理解这些更改的工作原理及潜在影响。
  • 范围聚焦: 本 PR 未包含任何与当前任务无关的代码改动。
  • 本地验证: 已在本地运行并通过了测试或手动验证。
  • 安全合规: 代码中无敏感凭据,且符合项目代码规范。

📸 运行证明 / Proof of Work

  • go test ./controller ./model ./router ./middleware -count=1
  • PATH=/Volumes/Work/code/new-api/web/node_modules/.bin:$PATH eslint src/components/common/ui/FilterAutoComplete.jsx src/components/table/usage-logs/UsageLogsFilters.jsx src/components/table/task-logs/TaskLogsFilters.jsx src/components/table/mj-logs/MjLogsFilters.jsx src/pages/Setting/Operation/SettingsLog.jsx src/components/settings/OperationSetting.jsx
  • git diff --check
  • docs/reviews/CR-LOG-FILTER-AUTOCOMPLETE-2026-03-24.md

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 24, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds per-user suggestion rate-limit config and middleware; implements autocomplete suggestion endpoints (log/task/midjourney) with model/query helpers and frontend autocomplete component; introduces responses-stream "bootstrap recovery" state, probing, and retry/wait logic across middleware, relay, helper, service, and tests; docs and i18n updates included.

Changes

Cohort / File(s) Summary
Rate limit config & middleware
common/constants.go, common/init.go, middleware/rate-limit.go, middleware/rate_limit_test.go
New suggestion-specific env/config vars and SuggestionRateLimit() middleware; tests verify dedicated suggestion rate-limit behavior.
Context keys
constant/context_key.go
Added ContextKeyResponsesBootstrapRecoveryState constant and minor spacing alignment.
Suggestion controllers & query parsing
controller/log_suggestion.go, controller/task_suggestion.go, controller/midjourney_suggestion.go, controller/suggestion_query.go
New handlers for admin/self suggestion endpoints and parsing helpers (parseSuggestionIntQuery, parseSuggestionInt64Query) that return 400 on parse errors.
Controller tests
controller/log_suggestion_test.go
Integration tests for suggestion endpoints: scoping, ordering, param validation, and admin vs self behavior.
Model suggestion logic
model/suggestion_common.go, model/log_suggestion.go, model/task_suggestion.go, model/midjourney_suggestion.go, model/midjourney.go
New suggestion helpers (limit clamp, LIKE escape, int/string scanners) and model-layer functions for log/task/midjourney suggestions; added gorm:"index" on midjourney.channel_id.
Router
router/api-router.go
Registered new suggestion routes (admin/self variants) and applied SuggestionRateLimit() middleware.
Responses bootstrap recovery — service
service/responses_bootstrap_recovery.go, service/responses_bootstrap_recovery_test.go
New recovery config/state, scheduling and decision helpers (deadline/probe/ping/retryable codes) with comprehensive unit tests.
Distributor & integration tests
middleware/distributor.go, middleware/distributor_bootstrap_integration_test.go
Channel selection gains bootstrap-grace waiting/pinging via getChannelWithBootstrapGrace; integration tests validate recovery/timeouts and SSE ping/error behavior.
Relay changes
controller/relay.go
Refactored retry loop to integrate bootstrap recovery, per-retry pre-consume billing, billing release/probe/wait helpers, and conditional SSE error emission.
Stream helpers & middleware utils
relay/helper/common.go, relay/helper/stream_scanner.go, relay/helper/stream_scanner_test.go, middleware/utils.go, middleware/utils_test.go
Added OpenAIErrorEvent, payload-start marking, default streaming-timeout fallback, conditional SSE error emission, and related tests.
Frontend settings, components & i18n
controller/misc.go, setting/operation_setting/general_setting.go, web/src/pages/.../SettingsGeneral.jsx, web/src/pages/.../SettingsLog.jsx, web/src/components/common/ui/FilterAutoComplete.jsx, web/src/components/table/*Logs/*Filters.jsx, web/src/i18n/locales/*, docs/*
Added log_filter_autocomplete_enabled setting/status, UI toggle and settings for bootstrap recovery, new FilterAutoComplete component integrated into log filters, i18n entries across locales, and documentation for responses-stream bootstrap recovery.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Distributor as Middleware: Distributor
    participant Service as Service: BootstrapRecovery
    participant Relay as Controller: Relay
    participant DB as Database: ChannelStore

    Client->>Distributor: POST /v1/responses (stream=true)
    Distributor->>Service: EnsureResponsesBootstrapRecoveryState(c, isStream)
    Service->>DB: Check for available channel
    alt Channel available
        Distributor->>Relay: Forward request
        Relay->>Client: Stream response payloads
    else No channel available
        loop until deadline or channel found
            Distributor->>Service: NextResponsesBootstrapWait(now)
            Service-->>Distributor: waitDuration, sendPing
            alt sendPing
                Distributor->>Client: SSE ": PING"
            end
            Distributor->>DB: Retry channel query
        end
        alt Channel found
            Distributor->>Relay: Forward request
            Relay->>Client: Stream response payloads
        else Deadline reached
            Distributor->>Client: SSE event: error
        end
    end
    opt Relay encounters pre-payload error
        Relay->>Service: CanContinueResponsesBootstrapRecovery(error)
        alt can continue
            Relay->>Service: NextResponsesBootstrapWait(now)
            Relay->>Relay: Retry attempt(s)
        else cannot continue
            Relay->>Client: SSE event: error
        end
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • Calcium-Ion
  • creamlike1024
  • seefs001

Poem

🐰 I nibble keys and chase a clue,

Suggestions bloom where filters grew,
If channels nap, I'll ping and wait,
Till streams resume and errors abate,
Hooray — autocomplete hops to you!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 5.21% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'feat: add log filter autocomplete and tab completion' is partially related to the changeset. It accurately describes the main feature (log filter autocomplete and tab completion), but omits the significant responses bootstrap recovery feature that comprises a substantial portion of the changes.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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 and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 10

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
middleware/distributor.go (1)

132-145: ⚠️ Potential issue | 🟡 Minor

Stop canceled bootstrap waits instead of converting them into 503/model-not-found errors.

Lines 370-372 can now return context.Canceled / context.DeadlineExceeded, but Lines 132-145 wrap those into the generic “get channel failed” 503 path. On client disconnects or request timeouts, that turns a canceled stream into a misleading channel-selection error.

Suggested fix
 import (
+	"context"
 	"errors"
 	"fmt"
@@
 				if channel == nil {
 					channel, selectGroup, err = getChannelWithBootstrapGrace(c, modelRequest.Model, usingGroup, bootstrapState)
 					if err != nil {
+						if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {
+							return
+						}
 						showGroup := usingGroup
 						if usingGroup == "auto" {

Also applies to: 370-372

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@middleware/distributor.go` around lines 132 - 145, The error handling in the
getChannelWithBootstrapGrace call (used in middleware/distributor.go) treats
context.Canceled and context.DeadlineExceeded the same as other channel lookup
failures and returns a 503/model-not-found via abortWithOpenAiMessage; instead
detect if err == context.Canceled or err == context.DeadlineExceeded (or
errors.Is(err, context.Canceled)/errors.Is(err, context.DeadlineExceeded)) after
getChannelWithBootstrapGrace returns and short-circuit by stopping any bootstrap
waits and returning early (e.g., abort the request without converting to a 503
model-not-found error or propagate the cancellation appropriately), leaving only
genuine channel lookup errors to hit the existing abortWithOpenAiMessage path.
🧹 Nitpick comments (2)
middleware/distributor_bootstrap_integration_test.go (1)

141-175: Consider adding tolerance for timing assertions in CI.

The test asserts elapsed >= 100*time.Millisecond which is reasonable, but timing-based tests can be flaky under CI load. The current approach is acceptable for integration tests, but if flakiness occurs, consider increasing tolerances or using condition-based waits.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@middleware/distributor_bootstrap_integration_test.go` around lines 141 - 175,
The timing assertion in
TestDistributeResponsesBootstrapRecoversBeforeGraceDeadline is brittle; replace
the strict require.GreaterOrEqual(t, elapsed, 100*time.Millisecond) with a
tolerant check or condition-based wait: either lower the required minimum to a
safe-tolerance (e.g., require.GreaterOrEqual(t, elapsed, 80*time.Millisecond))
or remove the elapsed assertion and instead use a condition-based wait (e.g.,
require.Eventually/assert.Eventually) that polls for the expected stream output
in recorder.Body (": PING" / `data: {"status":"ok"}`) within a generous timeout;
update the assertion around elapsed or switch to polling so
TestDistributeResponsesBootstrapRecoversBeforeGraceDeadline and the variables
elapsed, recorder.Body, and handlerCalled are robust under CI load.
web/src/components/common/ui/FilterAutoComplete.jsx (1)

130-150: Document internal Semi UI API dependency for Tab selection.

The code uses component?.state?.focusIndex and component?.foundation?.handleSelect to enable Tab-key selection of the currently focused option. Semi UI's public API (value prop + onChange callback) does not expose this functionality—there is no public method to access which dropdown item is currently focused or to trigger selection programmatically. Add a comment explaining this is a necessary workaround for a Semi UI API limitation to clarify the implementation choice for future maintainers:

// Semi UI AutoComplete does not expose a public API to programmatically select
// the currently focused dropdown item. We use internal APIs (state.focusIndex and
// foundation.handleSelect) as a workaround to support Tab-key selection.
// This may break in future Semi UI versions; consider following up on Semi's public API.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/components/common/ui/FilterAutoComplete.jsx` around lines 130 - 150,
Add an inline comment above the handleTabSelect logic explaining that this code
relies on Semi UI internal APIs because Semi's public AutoComplete API doesn't
expose the focused item or a programmatic select; reference the specific
internals used (autoCompleteRef -> component?.state?.focusIndex and
component?.foundation?.handleSelect) and note this is a workaround that may
break in future Semi UI versions and should be revisited if Semi exposes a
public API (keep comment near handleTabSelect and the options usage).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@relay/helper/common.go`:
- Around line 125-134: In OpenAIErrorEvent,
service.MarkResponsesBootstrapPayloadStarted(c) is called before serializing the
payload so a failed common.Marshal could leave bootstrap marked; move the call
to after jsonData is created successfully (i.e., after the
common.Marshal(payload) returns without error) so
MarkResponsesBootstrapPayloadStarted(c) is invoked only when marshaling succeeds
and the event can actually be emitted; adjust surrounding error handling in
OpenAIErrorEvent accordingly.

In `@web/src/components/common/ui/FilterAutoComplete.jsx`:
- Around line 102-108: The hardcoded Chinese rate-limit message should be
internationalized: import and call useTranslation() inside the
FilterAutoComplete component to get t, then replace the literal string passed to
showError with a t() lookup (e.g. t('errors.rateLimit') or a suitable key like
t('filter.rateLimitNotice')), keeping the existing rate-limit guard that uses
lastRateLimitNoticeAtRef and showError; ensure the translation key is used
consistently where the message appears so all user-facing strings are provided
via t().

In `@web/src/components/table/task-logs/TaskLogsFilters.jsx`:
- Around line 51-56: The autocomplete toggle currently defaults to true before
status loads; change the logic in TaskLogsFilters so autocompleteEnabled reads
the explicit server toggle only when statusState.status exists (e.g., use a
check against statusState?.status and return false otherwise), keeping the
existing suggestionEndpoint/isAdminUser logic intact; update the reference to
statusState and the autocompleteEnabled assignment inside the component to fail
closed until status loads.

In `@web/src/i18n/locales/en.json`:
- Around line 3341-3352: The new English entries were added after the closing of
the "translation" object so the keys (e.g., "启用 Responses 流启动恢复", "仅在
/v1/responses 流式请求首包前生效,用于短时故障恢复。", "启动恢复等待窗口(秒)", etc.) will not be looked up
by t(...) in the default namespace; move all these new key/value pairs into the
existing "translation" object in en.json (i.e., place them before the closing
brace of "translation"), ensure proper commas and JSON validity, and run a quick
i18n lookup or linter to confirm t('启用 Responses 流启动恢复') resolves to the new
English string.

In `@web/src/i18n/locales/fr.json`:
- Around line 3304-3315: The new locale entries (e.g. "启用 Responses 流启动恢复", "仅在
/v1/responses 流式请求首包前生效,用于短时故障恢复。" etc.) were added after the closing of the
"translation" object and thus won't be resolved by t('...'); move these keys
back under the existing "translation" namespace (or reopen/extend the
"translation" object) so they become part of the translation map, ensuring the
JSON braces are balanced and no duplicate keys are introduced; locate the
"translation" object and append these entries inside it (or merge them) and
validate the JSON.

In `@web/src/i18n/locales/ja.json`:
- Around line 3285-3297: The new translation entries (e.g., "启用 Responses
流启动恢复", "仅在 /v1/responses 流式请求首包前生效,用于短时故障恢复。", "启动恢复等待窗口(秒)", etc.) were added
at the JSON root instead of inside the "translation" namespace; move all these
keys and their English values into the existing "translation": { ... } object
(i.e., cut the block starting with "启用 Responses 流启动恢复" through the final
explanatory sentence and paste it before the closing brace of the "translation"
object) so i18next can resolve them and preserve the flat Chinese-key structure
required by the frontend guidelines.

In `@web/src/i18n/locales/ru.json`:
- Around line 3318-3329: The new Russian entries were accidentally placed after
the closing brace of the active "translation" object, so move the keys ("启用
Responses 流启动恢复", "仅在 /v1/responses 流式请求首包前生效,用于短时故障恢复。", "启动恢复等待窗口(秒)",
"在该时间窗口内持续探测可用渠道,超时后返回真实错误。", "渠道探测间隔(毫秒)", "每次重新探测可用渠道之间的等待时间。", "SSE 保活间隔(秒)",
"在等待恢复期间发送 : PING,帮助客户端保持连接。", "可触发启动恢复的状态码", "填写 JSON 数组,例如
[401,403,429,500,502,503,504]。", "Responses 流启动恢复仅作用于 /v1/responses
的流式请求首包前阶段。它会在短时渠道故障时通过 SSE ping 保持连接,并在恢复后继续返回真实内容;首包发出后不会跨渠道续传。") back inside
the existing "translation" object in ru.json, remove the stray closing brace
that separated them, ensure commas and JSON structure remain valid, and run the
JSON linter/type-check to confirm the keys are now resolvable via t('...') in
the default namespace.

In `@web/src/i18n/locales/vi.json`:
- Around line 3855-3866: The new translation keys (e.g., "启用 Responses 流启动恢复",
"仅在 /v1/responses 流式请求首包前生效,用于短时故障恢复。", etc.) were added after the closing of
the existing translation object; move these entries into the existing
"translation" object block (ensure there's a comma after the previous last entry
and remove the extraneous closing brace that currently separates them) so they
reside in the same locale namespace as the rest of the file.

In `@web/src/i18n/locales/zh-CN.json`:
- Around line 2960-2971: The new Chinese translation entries are placed at the
top level instead of under the "translation" namespace; move these keys (e.g.,
"启用 Responses 流启动恢复", "仅在 /v1/responses 流式请求首包前生效,用于短时故障恢复。", "启动恢复等待窗口(秒)",
"在该时间窗口内持续探测可用渠道,超时后返回真实错误。", "渠道探测间隔(毫秒)", "每次重新探测可用渠道之间的等待时间。", "SSE 保活间隔(秒)",
"在等待恢复期间发送 : PING,帮助客户端保持连接。", "可触发启动恢复的状态码", "填写 JSON 数组,例如
[401,403,429,500,502,503,504]。", "Responses 流启动恢复仅作用于 /v1/responses
的流式请求首包前阶段。它会在短时渠道故障时通过 SSE ping 保持连接,并在恢复后继续返回真实内容;首包发出后不会跨渠道续传。") into the
existing "translation" object so they live in the same namespace as other
strings; ensure the file remains a flat JSON object (Chinese source strings as
keys) and remove any duplicated keys at top level after moving.

In `@web/src/i18n/locales/zh-TW.json`:
- Around line 2969-2980: The new i18n entries (e.g. "启用 Responses 流启动恢复", "仅在
/v1/responses 流式请求首包前生效,用于短时故障恢复。", "启动恢复等待窗口(秒)", "在该时间窗口内持续探测可用渠道,超时后返回真实错误。",
"渠道探测间隔(毫秒)", "每次重新探测可用渠道之间的等待时间。", "SSE 保活间隔(秒)", "在等待恢复期间发送 :
PING,帮助客户端保持连接。", "可触发启动恢复的状态码", "填写 JSON 数组,例如 [401,403,429,500,502,503,504]。",
"Responses 流启动恢复仅作用于 /v1/responses 的流式请求首包前阶段。它会在短时渠道故障时通过 SSE ping
保持连接,并在恢复后继续返回真实内容;首包发出后不会跨渠道续传。") were added outside the top-level
"translation" object; move these keys back inside the existing "translation"
object in web/src/i18n/locales/zh-TW.json, preserving the flat JSON format
(Chinese source strings as keys) and existing key/value strings, then validate
the JSON so namespace lookup resolves them normally.

---

Outside diff comments:
In `@middleware/distributor.go`:
- Around line 132-145: The error handling in the getChannelWithBootstrapGrace
call (used in middleware/distributor.go) treats context.Canceled and
context.DeadlineExceeded the same as other channel lookup failures and returns a
503/model-not-found via abortWithOpenAiMessage; instead detect if err ==
context.Canceled or err == context.DeadlineExceeded (or errors.Is(err,
context.Canceled)/errors.Is(err, context.DeadlineExceeded)) after
getChannelWithBootstrapGrace returns and short-circuit by stopping any bootstrap
waits and returning early (e.g., abort the request without converting to a 503
model-not-found error or propagate the cancellation appropriately), leaving only
genuine channel lookup errors to hit the existing abortWithOpenAiMessage path.

---

Nitpick comments:
In `@middleware/distributor_bootstrap_integration_test.go`:
- Around line 141-175: The timing assertion in
TestDistributeResponsesBootstrapRecoversBeforeGraceDeadline is brittle; replace
the strict require.GreaterOrEqual(t, elapsed, 100*time.Millisecond) with a
tolerant check or condition-based wait: either lower the required minimum to a
safe-tolerance (e.g., require.GreaterOrEqual(t, elapsed, 80*time.Millisecond))
or remove the elapsed assertion and instead use a condition-based wait (e.g.,
require.Eventually/assert.Eventually) that polls for the expected stream output
in recorder.Body (": PING" / `data: {"status":"ok"}`) within a generous timeout;
update the assertion around elapsed or switch to polling so
TestDistributeResponsesBootstrapRecoversBeforeGraceDeadline and the variables
elapsed, recorder.Body, and handlerCalled are robust under CI load.

In `@web/src/components/common/ui/FilterAutoComplete.jsx`:
- Around line 130-150: Add an inline comment above the handleTabSelect logic
explaining that this code relies on Semi UI internal APIs because Semi's public
AutoComplete API doesn't expose the focused item or a programmatic select;
reference the specific internals used (autoCompleteRef ->
component?.state?.focusIndex and component?.foundation?.handleSelect) and note
this is a workaround that may break in future Semi UI versions and should be
revisited if Semi exposes a public API (keep comment near handleTabSelect and
the options usage).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 3bfae986-a31a-4b59-b059-8c833c64b857

📥 Commits

Reviewing files that changed from the base of the PR and between 9ae9040 and b9f9157.

📒 Files selected for processing (44)
  • common/constants.go
  • common/init.go
  • constant/context_key.go
  • controller/log_suggestion.go
  • controller/log_suggestion_test.go
  • controller/midjourney_suggestion.go
  • controller/misc.go
  • controller/relay.go
  • controller/suggestion_query.go
  • controller/task_suggestion.go
  • docs/installation/responses-stream-bootstrap-recovery.md
  • docs/reviews/CR-LOG-FILTER-AUTOCOMPLETE-2026-03-24.md
  • middleware/distributor.go
  • middleware/distributor_bootstrap_integration_test.go
  • middleware/rate-limit.go
  • middleware/rate_limit_test.go
  • middleware/utils.go
  • middleware/utils_test.go
  • model/log_suggestion.go
  • model/midjourney.go
  • model/midjourney_suggestion.go
  • model/suggestion_common.go
  • model/task_suggestion.go
  • relay/helper/common.go
  • relay/helper/stream_scanner.go
  • relay/helper/stream_scanner_test.go
  • router/api-router.go
  • service/responses_bootstrap_recovery.go
  • service/responses_bootstrap_recovery_test.go
  • setting/operation_setting/general_setting.go
  • web/src/components/common/ui/FilterAutoComplete.jsx
  • web/src/components/settings/OperationSetting.jsx
  • web/src/components/table/mj-logs/MjLogsFilters.jsx
  • web/src/components/table/task-logs/TaskLogsFilters.jsx
  • web/src/components/table/usage-logs/UsageLogsFilters.jsx
  • 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-CN.json
  • web/src/i18n/locales/zh-TW.json
  • web/src/pages/Setting/Operation/SettingsGeneral.jsx
  • web/src/pages/Setting/Operation/SettingsLog.jsx

@MisonL
Copy link
Author

MisonL commented Mar 24, 2026

CodeRabbit follow-up fixes

补充推送了一组针对最新 CodeRabbit 评论的修复:

  • OpenAIErrorEvent 中的 MarkResponsesBootstrapPayloadStarted 移到 common.Marshal 成功之后,避免 bootstrap 状态提前标记。
  • 将联想请求限流提示改为走 react-i18next,并补齐 7 个 locale。
  • 日志筛选里的联想开关改为在 status 未加载时 fail-closed,避免服务端关闭开关时前端初始化阶段仍短暂请求建议接口。
  • 修正 responses recovery 相关新增文案在多个 locale 文件中被放到 translation 命名空间外的问题。

已验证:

  • go test ./relay/helper
  • bun run build
  • locale JSON 结构与 key 检查

commit: 971efc7d

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
web/src/i18n/locales/ja.json (1)

3285-3296: Localize new ja.json values to Japanese instead of English fallbacks.

Line 3285–3296 adds the correct keys, but their values are English. In Japanese UI this will show mixed-language text (including the autocomplete rate-limit message). Please replace these new values with Japanese translations for consistency.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/i18n/locales/ja.json` around lines 3285 - 3296, The newly added
entries in ja.json currently have English values; replace each English fallback
value with the corresponding Japanese translation for the provided keys (e.g.
"启用 Responses 流启动恢复", "仅在 /v1/responses 流式请求首包前生效,用于短时故障恢复。", "启动恢复等待窗口(秒)",
"在该时间窗口内持续探测可用渠道,超时后返回真实错误。", "渠道探测间隔(毫秒)", "每次重新探测可用渠道之间的等待时间。", "SSE 保活间隔(秒)",
"在等待恢复期间发送 : PING,帮助客户端保持连接。", "可触发启动恢复的状态码", "填写 JSON 数组,例如
[401,403,429,500,502,503,504]。", "Responses 流启动恢复仅作用于 /v1/responses
的流式请求首包前阶段。它会在短时渠道故障时通过 SSE ping 保持连接,并在恢复后继续返回真实内容;首包发出后不会跨渠道续传。",
"联想请求过于频繁,请稍后重试")—translate each English value into natural Japanese and replace
the English strings so ja.json contains Japanese text for those keys.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@web/src/i18n/locales/ja.json`:
- Around line 3285-3296: The newly added entries in ja.json currently have
English values; replace each English fallback value with the corresponding
Japanese translation for the provided keys (e.g. "启用 Responses 流启动恢复", "仅在
/v1/responses 流式请求首包前生效,用于短时故障恢复。", "启动恢复等待窗口(秒)", "在该时间窗口内持续探测可用渠道,超时后返回真实错误。",
"渠道探测间隔(毫秒)", "每次重新探测可用渠道之间的等待时间。", "SSE 保活间隔(秒)", "在等待恢复期间发送 :
PING,帮助客户端保持连接。", "可触发启动恢复的状态码", "填写 JSON 数组,例如 [401,403,429,500,502,503,504]。",
"Responses 流启动恢复仅作用于 /v1/responses 的流式请求首包前阶段。它会在短时渠道故障时通过 SSE ping
保持连接,并在恢复后继续返回真实内容;首包发出后不会跨渠道续传。", "联想请求过于频繁,请稍后重试")—translate each English
value into natural Japanese and replace the English strings so ja.json contains
Japanese text for those keys.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 89da9810-79ef-4e8e-b37e-c0883cccbc65

📥 Commits

Reviewing files that changed from the base of the PR and between b9f9157 and 971efc7.

📒 Files selected for processing (12)
  • relay/helper/common.go
  • web/src/components/common/ui/FilterAutoComplete.jsx
  • web/src/components/table/mj-logs/MjLogsFilters.jsx
  • web/src/components/table/task-logs/TaskLogsFilters.jsx
  • web/src/components/table/usage-logs/UsageLogsFilters.jsx
  • 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-CN.json
  • web/src/i18n/locales/zh-TW.json
✅ Files skipped from review due to trivial changes (3)
  • web/src/i18n/locales/vi.json
  • web/src/i18n/locales/zh-TW.json
  • web/src/i18n/locales/fr.json
🚧 Files skipped from review as they are similar to previous changes (4)
  • relay/helper/common.go
  • web/src/i18n/locales/ru.json
  • web/src/i18n/locales/en.json
  • web/src/components/common/ui/FilterAutoComplete.jsx

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
web/src/i18n/locales/ja.json (1)

3293-3304: Prefer Japanese translations for new ja.json values.

Line 3293–Line 3304 currently use English values, so the Japanese UI will show mixed-language labels/messages in settings and autocomplete errors. Please localize these new values to Japanese for consistency.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/i18n/locales/ja.json` around lines 3293 - 3304, The listed JSON
entries currently have English values; replace the English strings for these
keys with appropriate Japanese translations: "启用 Responses 流启动恢复", "仅在
/v1/responses 流式请求首包前生效,用于短时故障恢复。", "启动恢复等待窗口(秒)", "在该时间窗口内持续探测可用渠道,超时后返回真实错误。",
"渠道探测间隔(毫秒)", "每次重新探测可用渠道之间的等待时间。", "SSE 保活间隔(秒)", "在等待恢复期间发送 :
PING,帮助客户端保持连接。", "可触发启动恢复的状态码", "填写 JSON 数组,例如 [401,403,429,500,502,503,504]。",
"Responses 流启动恢复仅作用于 /v1/responses 的流式请求首包前阶段。它会在短时渠道故障时通过 SSE ping
保持连接,并在恢复后继续返回真实内容;首包发出后不会跨渠道续传。", and "联想请求过于频繁,请稍后重试" — update each value to
natural Japanese so the ja.json locale is fully localized.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@web/src/i18n/locales/ja.json`:
- Around line 3293-3304: The listed JSON entries currently have English values;
replace the English strings for these keys with appropriate Japanese
translations: "启用 Responses 流启动恢复", "仅在 /v1/responses 流式请求首包前生效,用于短时故障恢复。",
"启动恢复等待窗口(秒)", "在该时间窗口内持续探测可用渠道,超时后返回真实错误。", "渠道探测间隔(毫秒)", "每次重新探测可用渠道之间的等待时间。",
"SSE 保活间隔(秒)", "在等待恢复期间发送 : PING,帮助客户端保持连接。", "可触发启动恢复的状态码", "填写 JSON 数组,例如
[401,403,429,500,502,503,504]。", "Responses 流启动恢复仅作用于 /v1/responses
的流式请求首包前阶段。它会在短时渠道故障时通过 SSE ping 保持连接,并在恢复后继续返回真实内容;首包发出后不会跨渠道续传。", and
"联想请求过于频繁,请稍后重试" — update each value to natural Japanese so the ja.json locale
is fully localized.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 11eab327-4655-4394-a647-cd608e5b0824

📥 Commits

Reviewing files that changed from the base of the PR and between 971efc7 and 4fb9028.

📒 Files selected for processing (7)
  • middleware/distributor.go
  • 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
✅ Files skipped from review due to trivial changes (3)
  • web/src/i18n/locales/fr.json
  • web/src/i18n/locales/vi.json
  • web/src/i18n/locales/ru.json
🚧 Files skipped from review as they are similar to previous changes (2)
  • web/src/i18n/locales/zh-TW.json
  • web/src/i18n/locales/en.json

@MisonL MisonL force-pushed the feat/log-filter-autocomplete-clean branch from 4fb9028 to 26781b4 Compare March 26, 2026 08:58
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
web/src/components/common/ui/FilterAutoComplete.jsx (1)

137-151: Avoid coupling Tab completion to Semi UI internals.

Reading component.state.focusIndex and calling component.foundation.handleSelect(...) ties this behavior to private instance internals instead of a stable component contract. That is brittle across Semi UI updates and harder to maintain than owning the highlighted option in this component.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/components/common/ui/FilterAutoComplete.jsx` around lines 137 - 151,
The code currently reads autoCompleteRef.current.state.focusIndex and calls
component.foundation.handleSelect(...), which couples behavior to Semi UI
internals; instead own the highlighted option and invoke the public selection
API/prop. Replace direct access to component.state and
component.foundation.handleSelect by tracking a local highlightedIndex (e.g., in
state) that you update via the AutoComplete's public highlight/hover callbacks
(or onHighlightChange), compute selectedOption from that highlightedIndex, and
call the AutoComplete's public selection handler (prop like onSelect/onChange)
or simulate a user selection via the component's documented public method rather
than calling component.foundation.handleSelect; remove reads of
autoCompleteRef.current.state.focusIndex and calls to
component.foundation.handleSelect and use selectedIndex from your own
highlightedIndex.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@web/src/components/common/ui/FilterAutoComplete.jsx`:
- Around line 72-77: Cached suggestions are applied from
cacheRef.current.get(requestKey) without advancing requestIdRef, so older
in-flight responses can later overwrite the cached options; when serving a cache
hit in the block that sets setOptions(cachedOptions) and setLoading(false), also
advance/increment requestIdRef.current (matching the mechanism used for new
requests) so any pending responses with the previous requestId are
ignored—update the cached-path in FilterAutoComplete.jsx to increment
requestIdRef (or set a new current request id) before returning.

In `@web/src/components/table/usage-logs/UsageLogsFilters.jsx`:
- Around line 137-145: The placeholder prop currently uses t('Request ID') which
violates the project's i18n convention; update the FilterAutoComplete
placeholder to call t with the Chinese source-string key used in the locales
(e.g. replace t('Request ID') with the matching Chinese key such as t('请求 ID')
or the exact Chinese string present in web/src/i18n/locales/*.json), ensuring
FilterAutoComplete, placeholder and useTranslation() usage remain unchanged.

---

Nitpick comments:
In `@web/src/components/common/ui/FilterAutoComplete.jsx`:
- Around line 137-151: The code currently reads
autoCompleteRef.current.state.focusIndex and calls
component.foundation.handleSelect(...), which couples behavior to Semi UI
internals; instead own the highlighted option and invoke the public selection
API/prop. Replace direct access to component.state and
component.foundation.handleSelect by tracking a local highlightedIndex (e.g., in
state) that you update via the AutoComplete's public highlight/hover callbacks
(or onHighlightChange), compute selectedOption from that highlightedIndex, and
call the AutoComplete's public selection handler (prop like onSelect/onChange)
or simulate a user selection via the component's documented public method rather
than calling component.foundation.handleSelect; remove reads of
autoCompleteRef.current.state.focusIndex and calls to
component.foundation.handleSelect and use selectedIndex from your own
highlightedIndex.
🪄 Autofix (Beta)

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

Run ID: 3ff7aac1-27dd-495e-a743-d4d915c9304a

📥 Commits

Reviewing files that changed from the base of the PR and between 4fb9028 and 26781b4.

📒 Files selected for processing (44)
  • common/constants.go
  • common/init.go
  • constant/context_key.go
  • controller/log_suggestion.go
  • controller/log_suggestion_test.go
  • controller/midjourney_suggestion.go
  • controller/misc.go
  • controller/relay.go
  • controller/suggestion_query.go
  • controller/task_suggestion.go
  • docs/installation/responses-stream-bootstrap-recovery.md
  • docs/reviews/CR-LOG-FILTER-AUTOCOMPLETE-2026-03-24.md
  • middleware/distributor.go
  • middleware/distributor_bootstrap_integration_test.go
  • middleware/rate-limit.go
  • middleware/rate_limit_test.go
  • middleware/utils.go
  • middleware/utils_test.go
  • model/log_suggestion.go
  • model/midjourney.go
  • model/midjourney_suggestion.go
  • model/suggestion_common.go
  • model/task_suggestion.go
  • relay/helper/common.go
  • relay/helper/stream_scanner.go
  • relay/helper/stream_scanner_test.go
  • router/api-router.go
  • service/responses_bootstrap_recovery.go
  • service/responses_bootstrap_recovery_test.go
  • setting/operation_setting/general_setting.go
  • web/src/components/common/ui/FilterAutoComplete.jsx
  • web/src/components/settings/OperationSetting.jsx
  • web/src/components/table/mj-logs/MjLogsFilters.jsx
  • web/src/components/table/task-logs/TaskLogsFilters.jsx
  • web/src/components/table/usage-logs/UsageLogsFilters.jsx
  • 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-CN.json
  • web/src/i18n/locales/zh-TW.json
  • web/src/pages/Setting/Operation/SettingsGeneral.jsx
  • web/src/pages/Setting/Operation/SettingsLog.jsx
✅ Files skipped from review due to trivial changes (14)
  • model/midjourney.go
  • relay/helper/stream_scanner_test.go
  • docs/installation/responses-stream-bootstrap-recovery.md
  • web/src/components/settings/OperationSetting.jsx
  • controller/log_suggestion_test.go
  • web/src/i18n/locales/ru.json
  • web/src/i18n/locales/zh-CN.json
  • web/src/i18n/locales/vi.json
  • web/src/i18n/locales/fr.json
  • service/responses_bootstrap_recovery_test.go
  • model/suggestion_common.go
  • web/src/components/table/mj-logs/MjLogsFilters.jsx
  • model/log_suggestion.go
  • web/src/i18n/locales/ja.json
🚧 Files skipped from review as they are similar to previous changes (14)
  • constant/context_key.go
  • web/src/pages/Setting/Operation/SettingsLog.jsx
  • common/init.go
  • controller/misc.go
  • controller/suggestion_query.go
  • middleware/utils_test.go
  • middleware/utils.go
  • common/constants.go
  • setting/operation_setting/general_setting.go
  • controller/task_suggestion.go
  • model/task_suggestion.go
  • model/midjourney_suggestion.go
  • web/src/i18n/locales/zh-TW.json
  • web/src/i18n/locales/en.json

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (2)
web/src/components/common/ui/FilterAutoComplete.jsx (2)

173-175: Cancel queued fetches on clear.

Line 174 invalidates started requests, but a debounced call that has not fired yet is still pending. If Semi's clear interaction does not emit a replacement onChange(''), stale suggestions can repopulate after the field is cleared.

♻️ Proposed fix
       onClear={() => {
+        fetchSuggestions.cancel();
         resetOptions();
       }}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/components/common/ui/FilterAutoComplete.jsx` around lines 173 - 175,
The clear handler currently calls resetOptions() but doesn't cancel a pending
debounced request, so a queued debounced fetch can still fire and repopulate
suggestions; update the onClear handler (the onClear callback that calls
resetOptions()) to also cancel any pending debounced loader (e.g. call
debouncedLoadOptions.cancel() or clearTimeout for the timer used by the
debouncer) and abort any in-flight fetch (e.g. call abortController.abort() used
by loadOptions/fetchSuggestions) to ensure cleared state is not overwritten by
stale results.

138-152: Avoid Semi UI private internals for Tab completion.

Lines 139-152 depend on state.focusIndex and foundation.handleSelect(). If Semi changes either internal, the guard at Line 148 turns Tab completion into a silent no-op. A controlled highlighted-index/value path would be safer here.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/components/common/ui/FilterAutoComplete.jsx` around lines 138 - 152,
The code is reaching into Semi AutoComplete private internals
(autoCompleteRef.current.state.focusIndex and .foundation.handleSelect) which
can break; instead manage a controlled highlighted index/value and use the
component's public callbacks to perform selection. Replace the internals usage
in FilterAutoComplete by keeping a local highlightedIndex state (e.g.
highlightedIndex), wire it to the AutoComplete via its public props (the control
prop for highlighted index or value and the
onHighlight/onFocus/onChange/onSelect callbacks the component exposes), compute
selectedOption from options[highlightedIndex], and invoke the public selection
callback (e.g. the AutoComplete onSelect or onChange prop passed into
FilterAutoComplete) rather than calling foundation.handleSelect; ensure you
initialize highlightedIndex safely and update it from the component's public
highlight/change events so Tab completion never relies on private .state or
.foundation.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@web/src/i18n/locales/zh-CN.json`:
- Around line 2971-2972: The JSON in zh-CN locale has a missing comma after the
"联想请求过于频繁,请稍后重试" entry which causes parse errors; add the trailing comma after
the "联想请求过于频繁,请稍后重试" key/value pair so the subsequent "请求 ID" entry is valid,
then run the i18n CLI checks (bun run i18n:extract, bun run i18n:sync, bun run
i18n:lint) to verify and lint the locale file; specifically update the entries
for "联想请求过于频繁,请稍后重试" and "请求 ID".

In `@web/src/i18n/locales/zh-TW.json`:
- Around line 2988-2989: The JSON in zh-TW locale has a missing comma between
the entries "联想请求过于频繁,请稍后重试" and "请求 ID"; open web/src/i18n/locales/zh-TW.json
and add the missing comma after the value for "联想请求过于频繁,请稍后重试" so the object is
valid JSON, then run the i18n tooling (bun run i18n:lint and bun run i18n:sync /
bun run i18n:extract as needed) to ensure the zh-TW bundle is valid and
synchronized.

---

Nitpick comments:
In `@web/src/components/common/ui/FilterAutoComplete.jsx`:
- Around line 173-175: The clear handler currently calls resetOptions() but
doesn't cancel a pending debounced request, so a queued debounced fetch can
still fire and repopulate suggestions; update the onClear handler (the onClear
callback that calls resetOptions()) to also cancel any pending debounced loader
(e.g. call debouncedLoadOptions.cancel() or clearTimeout for the timer used by
the debouncer) and abort any in-flight fetch (e.g. call abortController.abort()
used by loadOptions/fetchSuggestions) to ensure cleared state is not overwritten
by stale results.
- Around line 138-152: The code is reaching into Semi AutoComplete private
internals (autoCompleteRef.current.state.focusIndex and
.foundation.handleSelect) which can break; instead manage a controlled
highlighted index/value and use the component's public callbacks to perform
selection. Replace the internals usage in FilterAutoComplete by keeping a local
highlightedIndex state (e.g. highlightedIndex), wire it to the AutoComplete via
its public props (the control prop for highlighted index or value and the
onHighlight/onFocus/onChange/onSelect callbacks the component exposes), compute
selectedOption from options[highlightedIndex], and invoke the public selection
callback (e.g. the AutoComplete onSelect or onChange prop passed into
FilterAutoComplete) rather than calling foundation.handleSelect; ensure you
initialize highlightedIndex safely and update it from the component's public
highlight/change events so Tab completion never relies on private .state or
.foundation.
🪄 Autofix (Beta)

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

Run ID: 626209ab-a7ce-4f12-8cbb-fabd240991d4

📥 Commits

Reviewing files that changed from the base of the PR and between 26781b4 and 0e23c9e.

📒 Files selected for processing (8)
  • web/src/components/common/ui/FilterAutoComplete.jsx
  • web/src/components/table/usage-logs/UsageLogsFilters.jsx
  • 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/zh-CN.json
  • web/src/i18n/locales/zh-TW.json
✅ Files skipped from review due to trivial changes (2)
  • web/src/i18n/locales/fr.json
  • web/src/i18n/locales/en.json
🚧 Files skipped from review as they are similar to previous changes (2)
  • web/src/i18n/locales/ja.json
  • web/src/i18n/locales/ru.json

@MisonL MisonL force-pushed the feat/log-filter-autocomplete-clean branch from d7070a6 to 2c74274 Compare March 26, 2026 12:32
@MisonL MisonL changed the title feat: add responses bootstrap recovery and log filter autocomplete feat: add log filter autocomplete and tab completion Mar 26, 2026
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