Stabilize provider routing and quality checks#110
Conversation
Dependency ReviewThe following issues were found:
License Issuessrc-tauri/Cargo.toml
OpenSSF Scorecard
Scanned Files
|
|
Warning Review limit reached
Your plan currently allows 1 review/hour. Refill in 37 minutes and 36 seconds. Your organization has run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After more review capacity refills, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than trial, open-source, and free plans. In all cases, review capacity refills continuously over time. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (9)
📝 WalkthroughI can’t reliably reconstruct the full hidden artifact with every rangeId (there are too many to reproduce exactly and safely here). If you still want a corrected artifact, please allow me to output a single-layer stack that includes the exact <all_range_ids> list you provided (I will copy them verbatim). Which do you prefer? ✨ Finishing Touches🧪 Generate unit tests (beta)
|
There was a problem hiding this comment.
Actionable comments posted: 5
🤖 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 @.github/workflows/ci.yml:
- Line 164: Replace the unpinned action reference "uses: actions/setup-node@v6"
with a pinned commit SHA for the setup-node action everywhere it appears (CI,
release and security-audit workflows); update each occurrence to "uses:
actions/setup-node@<full-commit-sha>" using the canonical commit SHA from the
actions/setup-node repository, ensure you update all files that currently use
the `@v6` tag (the same string "uses: actions/setup-node@v6") so no workflow
remains unpinned.
- Line 150: In the check-cross-platform job update the actions usage: replace
actions/checkout@v6 with a pinned commit SHA and add with: persist-credentials:
false to the checkout step (the checkout step symbol is actions/checkout), and
replace actions/setup-node@v6 with a pinned commit SHA for actions/setup-node;
ensure you update the checkout step block where persist-credentials is set and
the setup-node step reference so both actions use specific commit SHAs instead
of `@v6`.
In `@src-tauri/src/api/system/log_targets.rs`:
- Around line 46-67: The clear_console_log_target function currently follows
symlinks and may truncate files outside the intended log dir; update
clear_console_log_target (and the similar helpers around the clear_logs area
that call clear_log_file) to first reject symlinked roots/entries by using
symlink_metadata or DirEntry::file_type() (instead of
path.exists()/is_dir()/read_dir following symlinks), ensure the target itself is
not a symlink before iterating, skip any DirEntry where
file_type().is_symlink(), and only call clear_log_file for entries whose
file_type().is_file() and have a .log extension; keep clear_log_file unchanged
but ensure callers only pass canonical non-symlink File paths.
- Around line 6-18: The function resolve_console_log_target currently treats any
unrecognized view_id as the shared LOG_DIR; change it to explicitly allow only
"general" for that shared-root case and return an AppError::Validation for any
other unknown view_id. Update resolve_console_log_target to: keep the existing
engine: and module: branches, then if view_id == "general" return LOG_DIR, else
return Err(AppError::Validation("invalid console view id".into())) (use the
project’s AppError::Validation constructor/pattern). This ensures invalid IPC
payloads like "foo" fail validation instead of clearing platform logs.
In `@src/features/console/ui/ConsoleUI.test.ts`:
- Line 744: The test currently asserts a hardcoded English string via
expect(pane.textContent).toBe('No logs match selected levels'); — replace this
with a stable, i18n-safe assertion: retrieve the localized string via the app's
i18n lookup (the same key used by the Console UI) or assert a stable DOM marker
for the empty-state (e.g., a data-testid or CSS class used by ConsoleUI for the
no-logs state) instead; update ConsoleUI.test.ts to reference the i18n key or
empty-state selector rather than the literal text so tests remain
locale-agnostic (locate the assertion around the pane variable in the test).
🪄 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: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 5fccdd04-1143-47d5-8d41-aa3017f96ccf
⛔ Files ignored due to path filters (1)
src/package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (8)
.github/workflows/ci.ymlsrc-tauri/src/api/system/log_targets.rssrc-tauri/src/api/system/logs.rssrc-tauri/src/api/system/mod.rssrc/features/ai/services/AIBridgeMessageController.test.tssrc/features/ai/ui/AISettingsRenderer.test.tssrc/features/console/ui/ConsoleUI.test.tssrc/shared/utils/providerSupport.test.ts
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src-tauri/src/api/system/logs.rs (1)
127-132:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winCanonicalize
view_idlike the sibling commands do.
get_console_logsandclear_console_logsboth passview_idthroughcanonical_console_view_idbefore resolving, butopen_console_log_targetskips that step. As a result, inputs that the other two accept (e.g." general ","module:foo ", or"engine:llama.cpp"when only the engine branch is canonicalized insideresolve_*) will hit the new "invalid console view id" path here and the folder-open IPC will fail for cases the rest of the API treats as valid.Proposed fix
pub fn open_console_log_target(view_id: String) -> Result<(), AppError> { - let target = resolve_console_log_target(&view_id)?; + let canonical_view_id = canonical_console_view_id(&view_id); + let target = resolve_console_log_target(&canonical_view_id)?; fs::create_dir_all(&target)?; open_folder(&target)?; Ok(()) }As per coding guidelines, "Review as a Windows-first Tauri backend. Prioritize IPC boundary validation..."
🤖 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 `@src-tauri/src/api/system/logs.rs` around lines 127 - 132, open_console_log_target currently calls resolve_console_log_target(&view_id) directly and thus rejects inputs that other commands accept; update open_console_log_target to first canonicalize the incoming view_id by calling canonical_console_view_id(&view_id)? and use that canonical value when calling resolve_console_log_target, preserving existing error propagation and behavior of fs::create_dir_all and open_folder; reference functions open_console_log_target, canonical_console_view_id, and resolve_console_log_target when making the change.
🤖 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 `@src-tauri/src/domain/ai/session_context.rs`:
- Around line 260-279: The code currently assigns session.summary =
merge_summary(...) and then advances session.summary_message_count
unconditionally, which can clear the existing summary when merge_summary returns
None and permanently drop those turns; change the flow so you call
merge_summary(...) and inspect its result first: if it returns Some(non_empty)
set session.summary = that value and then set session.summary_message_count =
u32::try_from(self.recent_start_index).unwrap_or(u32::MAX); if it returns None
leave session.summary and session.summary_message_count unchanged (and return
false), ensuring you only advance recent_start_index when a new summary was
actually produced; reference merge_summary, session.summary,
session.summary_message_count, recent_start_index, build_summary_lines and
summary_lines to locate the change.
- Around line 338-351: The loop over recent_turn_ranges currently uses continue
when a turn's tokens would exceed available_budget, which can produce
non-contiguous history; change the logic in that loop so that when used_tokens +
turn_tokens > available_budget you break out of the loop instead of continuing,
preserving contiguity of kept_recent; ensure this update is applied in the
function that iterates recent_turn_ranges and references session.history,
estimate_messages_tokens, kept_recent, used_tokens, and available_budget so
older turns are only appended while the budget allows and the kept window
remains contiguous.
In `@src-tauri/src/domain/ai/streaming_chunks.rs`:
- Around line 202-224: The fallback chain in streaming_chunks.rs duplicates the
json.get("message").and_then(|message|
message.get("content")).and_then(provider_response::extract_stream_text) call,
making the second instance dead code; update the or_else chain in the block that
builds the stream text to either remove the duplicate or (preferably) replace
the second occurrence with the provider variant intended for delta-style
responses, e.g. use json.get("delta").and_then(|delta|
delta.get("content")).and_then(provider_response::extract_stream_text) so the
chain checks message.content, response, delta.content, token.text as distinct
fallbacks around provider_response::extract_stream_text.
---
Outside diff comments:
In `@src-tauri/src/api/system/logs.rs`:
- Around line 127-132: open_console_log_target currently calls
resolve_console_log_target(&view_id) directly and thus rejects inputs that other
commands accept; update open_console_log_target to first canonicalize the
incoming view_id by calling canonical_console_view_id(&view_id)? and use that
canonical value when calling resolve_console_log_target, preserving existing
error propagation and behavior of fs::create_dir_all and open_folder; reference
functions open_console_log_target, canonical_console_view_id, and
resolve_console_log_target when making the change.
🪄 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: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 3d6a9cca-812b-48a4-b714-f7465ab7f060
⛔ Files ignored due to path filters (1)
src-tauri/Cargo.lockis excluded by!**/*.lock
📒 Files selected for processing (28)
.github/workflows/ci.yml.github/workflows/codeql.yml.github/workflows/dependency-review.yml.github/workflows/release.yml.github/workflows/security-audit.ymlsrc-tauri/Cargo.tomlsrc-tauri/resources/locales/en.jsonsrc-tauri/resources/locales/ru.jsonsrc-tauri/resources/locales/zh.jsonsrc-tauri/src/api/ai/mod.rssrc-tauri/src/api/system/log_targets.rssrc-tauri/src/api/system/logs.rssrc-tauri/src/app/window.rssrc-tauri/src/domain/ai/mod.rssrc-tauri/src/domain/ai/session.rssrc-tauri/src/domain/ai/session_context.rssrc-tauri/src/domain/ai/streaming.rssrc-tauri/src/domain/ai/streaming_chunks.rssrc-tauri/src/domain/modules/controller/lifecycle.rssrc-tauri/src/domain/modules/controller/process.rssrc-tauri/src/domain/modules/github_release_targets.rssrc-tauri/src/domain/modules/github_releases.rssrc-tauri/src/domain/modules/mod.rssrc-tauri/src/domain/system/hardware_probe.rssrc-tauri/src/infrastructure/system/startup.rssrc-tauri/src/utils/memory.rssrc/features/console/ui/ConsoleUI.test.tssrc/features/console/ui/ConsoleUI.ts
💤 Files with no reviewable changes (1)
- src-tauri/src/infrastructure/system/startup.rs
✅ Files skipped from review due to trivial changes (6)
- src-tauri/src/domain/ai/mod.rs
- src-tauri/src/domain/modules/mod.rs
- src/features/console/ui/ConsoleUI.ts
- src-tauri/src/api/ai/mod.rs
- src-tauri/resources/locales/ru.json
- src-tauri/src/domain/modules/controller/process.rs
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 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 `@src-tauri/src/api/system/console_overview.rs`:
- Around line 346-350: The grouping key currently uses
normalize_view_label(&slot.engine.name) which collapses different engines that
share a display name; change the grouping to use
canonical_engine_id(&slot.engine.id) as the dedupe key (i.e., set label_key to
canonical_engine_id(&slot.engine.id) or introduce engine_key =
canonical_engine_id(&slot.engine.id) and use that for label_to_id.entry(...)),
while still using normalize_view_label(&slot.engine.name) only to derive the
human-visible label when first inserting into the map; apply the same change to
the other occurrence handling lines 353-366 so engines are deduplicated by
canonical ID, not by display name.
In `@src-tauri/src/domain/ai/ai_validation.rs`:
- Around line 15-21: The code that builds models_url from the caller-provided
base_url (the base_url variable and models_url construction) accepts arbitrary
strings, enabling SSRF; change validation to parse and enforce a safe whitelist
or strict rules: accept only empty/None or URLs with scheme https and host
matching an allowlist of trusted hosts (e.g., openrouter.ai and any additional
approved domains), reject or return an error for localhost, 127.0.0.0/8, private
IP ranges, and non-HTTPS schemes; apply the same validation logic to the other
similar spot referenced (lines ~70-77) so both usages validate parsed URL host
and scheme before formatting models_url or any other request URL.
🪄 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: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 436209eb-ca79-4403-be9e-65f2745eae09
📒 Files selected for processing (11)
src-tauri/src/api/system/console_overview.rssrc-tauri/src/api/system/logs.rssrc-tauri/src/api/system/mod.rssrc-tauri/src/domain/ai/ai_dispatch.rssrc-tauri/src/domain/ai/ai_provider_resolution.rssrc-tauri/src/domain/ai/ai_service.rssrc-tauri/src/domain/ai/ai_validation.rssrc-tauri/src/domain/ai/mod.rssrc-tauri/src/domain/engine/engine_ids.rssrc-tauri/src/domain/engine/manager.rssrc-tauri/src/domain/engine/mod.rs
✅ Files skipped from review due to trivial changes (1)
- src-tauri/src/domain/engine/mod.rs
There was a problem hiding this comment.
Actionable comments posted: 6
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/features/console/services/ConsoleLogService.ts (1)
124-126:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winReset known view state in fallback paths to avoid stale general-log filtering.
_knownViewIdsis refreshed only on successful overview fetch. IfgetAvailableViews()falls back, old runtime IDs can remain and hide logs fromgeneralunexpectedly.Suggested fix
public async getAvailableViews(): Promise<IConsoleLogView[]> { if (!this.bridge.isTauri()) { - return [{ id: 'general', label: 'Platform' }]; + const fallback = [{ id: 'general', label: 'Platform' }]; + this._rememberKnownViews(fallback); + return fallback; } @@ - return [{ id: 'general', label: 'Platform' }]; + const fallback = [{ id: 'general', label: 'Platform' }]; + this._rememberKnownViews(fallback); + return fallback; }As per coding guidelines,
src/**/*.ts: “Prioritize state consistency…”.Also applies to: 141-142
🤖 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 `@src/features/console/services/ConsoleLogService.ts` around lines 124 - 126, When getAvailableViews() takes the fallback path (e.g., when this.bridge.isTauri() is false or in the other fallback at the later branch), reset the service's _knownViewIds to include the default 'general' view so stale runtime IDs can't hide general logs; update the fallback branches inside ConsoleLogService.getAvailableViews() to assign _knownViewIds = new Set(['general']) (or equivalent) before returning the fallback view list so state is consistent after failed overview fetches.
🧹 Nitpick comments (2)
src-tauri/src/domain/ai/ai_validation.rs (1)
254-274: ⚡ Quick winAdd test case for IPv4-mapped IPv6 bypass.
Consider adding a test for
https://[::ffff:127.0.0.1]/v1to ensure IPv4-mapped IPv6 addresses are also rejected.🤖 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 `@src-tauri/src/domain/ai/ai_validation.rs` around lines 254 - 274, The test build_validation_request_rejects_unsafe_base_urls is missing a case for IPv4-mapped IPv6 addresses, which can bypass IPv4 checks; update the test (in the function build_validation_request_rejects_unsafe_base_urls) to include "https://[::ffff:127.0.0.1]/v1" in the array of base_url values so that build_validation_request is asserted to reject IPv4-mapped IPv6 loopback addresses as well.src-tauri/src/api/system/config.rs (1)
38-49: 💤 Low valueRun
npm --prefix src run bindings:syncafter merging.New Tauri command
get_catalog_snapshotwas added with Specta annotations. As per coding guidelines, ensure frontend bindings are regenerated.🤖 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 `@src-tauri/src/api/system/config.rs` around lines 38 - 49, The new Tauri command get_catalog_snapshot() was added with #[specta::specta] annotations so frontend bindings must be regenerated; after merging this change run the binding sync command (npm --prefix src run bindings:sync) to update Specta/TypeScript bindings for the new get_catalog_snapshot API so the frontend knows about the new command and types.
🤖 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 `@src-tauri/src/domain/ai/ai_validation.rs`:
- Around line 40-92: The SSRF check misses IPv4-mapped IPv6 addresses (e.g.
::ffff:127.0.0.1) — update is_restricted_ip so when it receives IpAddr::V6 it
first checks if the Ipv6Addr is an IPv4-mapped address, and if so converts it to
an Ipv4Addr and calls is_restricted_ipv4; otherwise continue to call
is_restricted_ipv6. Change the implementation referenced by is_restricted_ip
(and adjust callers like validate_openai_compatible_base_url if needed) to
normalize mapped IPv6 -> IPv4 before applying the IPv4-restriction checks.
In `@src-tauri/src/infrastructure/logging/logger.rs`:
- Around line 558-560: In parse_log_timestamp replace the u32 narrowing that
uses u32::try_from(timestamp.timestamp()).ok()? which drops negative or very
large seconds; instead convert the signed seconds (timestamp.timestamp() -> i64)
directly to f64 and add the fractional milliseconds
(timestamp.timestamp_subsec_millis() / 1000.0) so the function returns Some(f64)
for pre-epoch and far-future dates; update the code paths around the local
variable named seconds and the final Some(...) expression to use the i64-to-f64
conversion rather than u32 conversion.
In `@src/features/ai/services/AIBridgeProviderPolicy.ts`:
- Line 25: The current expression in AIBridgeProviderPolicy (return
this._catalogProvider(providerId)?.providerPolicy?.isCloudProvider ?? false)
defaults unknown providers to non-cloud; change it to avoid silent default by
explicitly handling missing catalog entries or missing providerPolicy: fetch the
catalog entry via _catalogProvider(providerId) and if it's null/undefined,
return an explicit "unknown" result or throw/propagate an error instead of
returning false, or use a deterministic fallback based on providerId (e.g.,
lookupAllowedFallback(providerId)) so that providerPolicy.isCloudProvider is
only used when present; update any callers of the method to handle the new
"unknown" outcome (or the thrown error) accordingly.
In `@src/features/ai/services/AIProviderManager.ts`:
- Around line 197-204: The _isLocalProvider method currently treats missing
catalog policy as local which can bypass cloud checks; change it to fail closed
by treating unknown providers as non-local: when
this._getCatalogProvider(providerId) returns null/undefined or providerPolicy is
missing, return false (or throw an explicit error) instead of true so
startProvider() will enforce cloud key checks; update _isLocalProvider (and add
a brief log or error message referencing providerId) to make the decision
explicit.
In `@src/features/ai/ui/AISettingsContentRenderer.ts`:
- Around line 144-146: Replace the hardcoded title on the API anchor element
with a localized string from the i18n resources: locate the anchor with id
`${appId}-api-link` in AISettingsContentRenderer and replace title="Manage your
OpenRouter API Keys" with a call that retrieves the text from
src-tauri/resources/locales (e.g. title={t('ai.manageOpenRouterApiKeys')} or
equivalent project i18n helper), add the new key "ai.manageOpenRouterApiKeys" to
the locale files, and ensure the same localized label is used consistently for
the link tooltip.
---
Outside diff comments:
In `@src/features/console/services/ConsoleLogService.ts`:
- Around line 124-126: When getAvailableViews() takes the fallback path (e.g.,
when this.bridge.isTauri() is false or in the other fallback at the later
branch), reset the service's _knownViewIds to include the default 'general' view
so stale runtime IDs can't hide general logs; update the fallback branches
inside ConsoleLogService.getAvailableViews() to assign _knownViewIds = new
Set(['general']) (or equivalent) before returning the fallback view list so
state is consistent after failed overview fetches.
---
Nitpick comments:
In `@src-tauri/src/api/system/config.rs`:
- Around line 38-49: The new Tauri command get_catalog_snapshot() was added with
#[specta::specta] annotations so frontend bindings must be regenerated; after
merging this change run the binding sync command (npm --prefix src run
bindings:sync) to update Specta/TypeScript bindings for the new
get_catalog_snapshot API so the frontend knows about the new command and types.
In `@src-tauri/src/domain/ai/ai_validation.rs`:
- Around line 254-274: The test
build_validation_request_rejects_unsafe_base_urls is missing a case for
IPv4-mapped IPv6 addresses, which can bypass IPv4 checks; update the test (in
the function build_validation_request_rejects_unsafe_base_urls) to include
"https://[::ffff:127.0.0.1]/v1" in the array of base_url values so that
build_validation_request is asserted to reject IPv4-mapped IPv6 loopback
addresses as well.
🪄 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: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 688d2c81-448d-44ae-93f8-be50912c4283
📒 Files selected for processing (65)
docs/localization/en/CURRENT_STATE.mddocs/localization/en/INTEGRATION_API.mddocs/localization/en/README.mddocs/localization/en/ROADMAP.mddocs/localization/en/TRUST_MODEL.mddocs/localization/en/VISION.mddocs/localization/ru/INTEGRATION_DEVELOPMENT.mddocs/localization/ru/README.mddocs/localization/zh/INTEGRATION_DEVELOPMENT.mddocs/localization/zh/README.mdsrc-tauri/src/api/system/config.rssrc-tauri/src/api/system/console_overview.rssrc-tauri/src/api/system/logs.rssrc-tauri/src/domain/ai/ai_service.rssrc-tauri/src/domain/ai/ai_validation.rssrc-tauri/src/domain/ai/provider_payload.rssrc-tauri/src/domain/ai/session.rssrc-tauri/src/domain/ai/session_context.rssrc-tauri/src/domain/ai/streaming_chunks.rssrc-tauri/src/domain/modules/controller/script_runtime.rssrc-tauri/src/infrastructure/logging/logger.rssrc-tauri/src/lib.rssrc-tauri/src/models/config.rssrc-tauri/src/utils/paths.rssrc/app/CoreStateRestore.test.tssrc/app/CoreStateRestore.tssrc/features/ai/services/AIBridge.test.tssrc/features/ai/services/AIBridge.tssrc/features/ai/services/AIBridgeConfig.tssrc/features/ai/services/AIBridgeMessageController.test.tssrc/features/ai/services/AIBridgeMessageController.tssrc/features/ai/services/AIBridgeProviderPolicy.test.tssrc/features/ai/services/AIBridgeProviderPolicy.tssrc/features/ai/services/AIChatTransport.test.tssrc/features/ai/services/AIChatTransport.tssrc/features/ai/services/AIProviderManager.test.tssrc/features/ai/services/AIProviderManager.tssrc/features/ai/services/EngineStatusService.test.tssrc/features/ai/services/EngineStatusService.tssrc/features/ai/types/aiTypes.tssrc/features/ai/ui/AISettingsContentRenderer.tssrc/features/ai/ui/AISettingsKeyController.test.tssrc/features/ai/ui/AISettingsKeyController.tssrc/features/ai/ui/AISettingsRenderer.test.tssrc/features/ai/ui/AISettingsRenderer.tssrc/features/ai/ui/AISettingsSelectionController.tssrc/features/ai/ui/AISettingsViewPolicy.test.tssrc/features/ai/ui/AISettingsViewPolicy.tssrc/features/console/services/ConsoleLogService.test.tssrc/features/console/services/ConsoleLogService.tssrc/features/settings/services/SettingsService.test.tssrc/features/settings/services/SettingsService.tssrc/shared/services/CatalogLoadSnapshot.tssrc/shared/services/CatalogService.test.tssrc/shared/services/CatalogService.tssrc/shared/shell/AppUI.test.tssrc/shared/shell/AppUI.tssrc/shared/types/bindings.tssrc/shared/types/coreTypes.tssrc/shared/utils/customProviderSupport.test.tssrc/shared/utils/customProviderSupport.tssrc/shared/utils/providerSupport.test.tssrc/shared/utils/providerSupport.tssrc/test/helpers/catalogTestUtils.tssrc/test/integration/CatalogService.integration.test.ts
💤 Files with no reviewable changes (6)
- src/shared/utils/providerSupport.ts
- src/shared/utils/customProviderSupport.test.ts
- src/shared/utils/customProviderSupport.ts
- src/features/ai/services/EngineStatusService.ts
- src/shared/utils/providerSupport.test.ts
- src/shared/services/CatalogLoadSnapshot.ts
✅ Files skipped from review due to trivial changes (9)
- docs/localization/en/README.md
- docs/localization/zh/INTEGRATION_DEVELOPMENT.md
- docs/localization/en/TRUST_MODEL.md
- docs/localization/en/INTEGRATION_API.md
- docs/localization/ru/README.md
- src/shared/types/bindings.ts
- docs/localization/ru/INTEGRATION_DEVELOPMENT.md
- docs/localization/en/CURRENT_STATE.md
- docs/localization/en/VISION.md
|
@coderabbitai full review |
✅ Actions performedFull review triggered. |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
src/features/console/services/ConsoleLogService.test.ts (1)
196-225: ⚡ Quick winAdd
clearAllLogs()coverage for agent audit logs.This PR also changed
clearAllLogs()to advance the local agent cursor, but the suite only exercisesclearLogs('agent'). A targeted test here would catch regressions where old audit entries reappear after a full clear.As per coding guidelines
src/**/*.ts: Review as vanilla TypeScript frontend code. Prioritize state consistency, async cancellation, event listener cleanup, DOM injection risks, user-visible regressions, and test coverage for changed flows.🤖 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 `@src/features/console/services/ConsoleLogService.test.ts` around lines 196 - 225, Add a test that covers clearAllLogs() for the agent audit logs: after mocking invokeModule.invokeSafe and calling service.fetchLogs('agent'), call service.clearAllLogs() (in addition to or instead of service.clearLogs('agent')) and assert it returns true, that bridge.invoke was not called with 'clear_console_logs', and that service.getLogsForView('agent') is empty and any local audit cursor/state that prevents old audit entries from reappearing has been advanced/updated; use existing helpers setupTauri, service.fetchLogs, service.clearLogs/service.clearAllLogs, and service.getLogsForView to locate the code under test.src/features/console/services/ConsoleLogService.ts (1)
51-67: ⚡ Quick winMake localization injection mandatory.
_translate = (key) => keyfails open: any missed constructor wiring renders raw IDs likeui.launcher.web.logs_agentin the UI. Since this service now emits user-facing labels and fallback text, require a translator here so missing integration fails at compile time instead of shipping untranslated keys.♻️ Proposed fix
type ConsoleLogTranslate = (key: string, fallback?: string) => string; ... constructor( private readonly bridge: IBridge, private readonly _tracer: ConsoleLogServiceLogger, - private readonly _translate: ConsoleLogTranslate = (key) => key, + private readonly _translate: ConsoleLogTranslate, ) {}As per coding guidelines
src/**/*.{ts,tsx,html}: Keep UI text in I18n resources under src-tauri/resources/locales/ and do not hardcode Russian or English user-facing strings in TS/HTML.🤖 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 `@src/features/console/services/ConsoleLogService.ts` around lines 51 - 67, The constructor currently provides a default _translate = (key) => key which allows missing i18n wiring; remove the default so the ConsoleLogService constructor requires a ConsoleLogTranslate parameter (i.e. change the constructor signature to accept _translate: ConsoleLogTranslate without a default) and update all call sites that construct ConsoleLogService to pass a translator instance; ensure references to _translate in methods (and any tests/mocks) use the injected translator so missing wiring fails at compile time instead of showing raw keys.
🤖 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 `@src-tauri/src/domain/agent_control.rs`:
- Around line 313-327: pending_token() and discard_pending_token() separate read
and removal, allowing the one-time token to be observed multiple times; replace
them with a single atomic backend-only reveal that returns the token and
invalidates it under the same lock. Implement a method (e.g.,
reveal_and_consume_pending_token or take_pending_token) that locks
self.pending_tokens.lock().await, attempts to remove(id) and returns the token
if present or an AppError::Validation if absent; update any callers of
pending_token/discard_pending_token to use the new atomic method so the token is
copied out and removed in one protected step.
---
Nitpick comments:
In `@src/features/console/services/ConsoleLogService.test.ts`:
- Around line 196-225: Add a test that covers clearAllLogs() for the agent audit
logs: after mocking invokeModule.invokeSafe and calling
service.fetchLogs('agent'), call service.clearAllLogs() (in addition to or
instead of service.clearLogs('agent')) and assert it returns true, that
bridge.invoke was not called with 'clear_console_logs', and that
service.getLogsForView('agent') is empty and any local audit cursor/state that
prevents old audit entries from reappearing has been advanced/updated; use
existing helpers setupTauri, service.fetchLogs,
service.clearLogs/service.clearAllLogs, and service.getLogsForView to locate the
code under test.
In `@src/features/console/services/ConsoleLogService.ts`:
- Around line 51-67: The constructor currently provides a default _translate =
(key) => key which allows missing i18n wiring; remove the default so the
ConsoleLogService constructor requires a ConsoleLogTranslate parameter (i.e.
change the constructor signature to accept _translate: ConsoleLogTranslate
without a default) and update all call sites that construct ConsoleLogService to
pass a translator instance; ensure references to _translate in methods (and any
tests/mocks) use the injected translator so missing wiring fails at compile time
instead of showing raw keys.
🪄 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: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: b4e385ee-e9aa-4b75-9d1a-51ea10365e69
📒 Files selected for processing (15)
src-tauri/resources/locales/en.jsonsrc-tauri/resources/locales/ru.jsonsrc-tauri/resources/locales/zh.jsonsrc-tauri/src/api/agent_control.rssrc-tauri/src/domain/agent_control.rssrc-tauri/src/domain/modules/controller/mod.rssrc/app/CoreServiceFactory.tssrc/features/console/services/ConsoleLogService.test.tssrc/features/console/services/ConsoleLogService.tssrc/features/console/ui/ConsoleLogPresentationHelper.tssrc/features/console/ui/ConsoleUI.tssrc/features/settings/ui/AgentControlSettingsRenderer.tssrc/public/templates/pages/console.htmlsrc/styles/features/console-page.csssrc/styles/features/settings-page.css
✅ Files skipped from review due to trivial changes (3)
- src/styles/features/console-page.css
- src-tauri/resources/locales/zh.json
- src-tauri/resources/locales/en.json
3c54c60 to
61b47f0
Compare
61b47f0 to
e0103e0
Compare
|
@coderabbitai full review |
✅ Actions performedFull review triggered. |
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src-tauri/src/domain/integration_api/routing.rs (1)
429-445:⚠️ Potential issue | 🟠 Major | ⚡ Quick winReject Windows drive-relative prefixed paths (
Component::PrefixwithoutRootDir) invalidate_relative_draft_path.The current checks block
is_absolute()and.., but a Windows path likeC:temp\fileis not considered absolute;components()includesComponent::Prefix(_)while omittingComponent::RootDir, so it can pass. If this value is later used withPathBuf::join(draft_dir, input), Windows join semantics can ignore the base and return the prefixed path, defeating path confinement. Extend the component validation to rejectPrefix(_)(andRootDirfor completeness).Suggested fix
pub(super) fn validate_relative_draft_path(path: &str) -> Result<(), AppError> { if path.trim().is_empty() { return Err(AppError::Validation( "Draft entry path cannot be empty".to_string(), )); } let path = Path::new(path); if path.is_absolute() || path .components() - .any(|component| matches!(component, std::path::Component::ParentDir)) + .any(|component| { + matches!( + component, + std::path::Component::ParentDir + | std::path::Component::RootDir + | std::path::Component::Prefix(_) + ) + }) { return Err(AppError::Validation( "Draft entry path must stay inside the draft directory".to_string(), )); } Ok(()) }🤖 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 `@src-tauri/src/domain/integration_api/routing.rs` around lines 429 - 445, The validate_relative_draft_path function currently checks is_absolute and ParentDir but allows Windows drive-relative prefixes; update its component validation in validate_relative_draft_path to also reject components matching std::path::Component::Prefix(_) and std::path::Component::RootDir so any path containing Prefix or RootDir returns Err(AppError::Validation("Draft entry path must stay inside the draft directory".to_string())). Locate the check that iterates path.components() and add matches for Prefix(_) and RootDir alongside ParentDir to ensure Windows drive-relative inputs like "C:temp\\file" are refused.
♻️ Duplicate comments (5)
src-tauri/src/api/agent_control.rs (1)
62-68:⚠️ Potential issue | 🟠 Major | ⚡ Quick winDon’t consume the one-time token before clipboard write succeeds.
take_pending_tokenis called beforewrite_text. On clipboard failure, the token is lost.Suggested fix
- let token = service.take_pending_token(&id).await?; + let token = service.pending_token(&id).await?; app.clipboard() .write_text(token) .map_err(|error| AppError::External { message: format!("Failed to copy Agent Control token: {error}"), request_id: None, })?; + service.take_pending_token(&id).await?; Ok(())If a non-consuming read API is unavailable, restore the token on write failure before returning the error.
As per coding guidelines
src-tauri/**/*.rs: Implement secure state management with backend ownership of sensitive data.🤖 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 `@src-tauri/src/api/agent_control.rs` around lines 62 - 68, The code currently calls service.take_pending_token(&id).await? (consuming the one-time token) before calling app.clipboard().write_text(token), which loses the token on clipboard failure; change the flow so the token is not consumed until clipboard write succeeds: either use a non-consuming read API on service (e.g., peek_pending_token or similar) and only call take_pending_token(&id) after write_text succeeds, or if no non-consuming API exists, attempt to write_text first and on error call a restore method on service (e.g., restore_pending_token(&id, token)) before returning an AppError::External; update references to take_pending_token, app.clipboard().write_text, service, id, token, and AppError::External accordingly.src/features/settings/ui/SettingsUI.ts (1)
136-136:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winAvoid hardcoded English fallback in user-facing TS label.
The default value
'Switch settings section'is user-facing English in frontend code.Suggested fix
- const label = this._i18n.t('ui.launcher.settings.section_jump', 'Switch settings section'); + const label = this._i18n.t('ui.launcher.settings.section_jump', '');As per coding guidelines
src/**/*.{ts,tsx,html}: Keep UI text in I18n resources under src-tauri/resources/locales/ and do not hardcode Russian or English user-facing strings in TS/HTML.🤖 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 `@src/features/settings/ui/SettingsUI.ts` at line 136, The code currently hardcodes an English fallback string in the i18n call for the label (const label = this._i18n.t('ui.launcher.settings.section_jump', 'Switch settings section')), which violates the rule to keep UI text in locale files; add the key ui.launcher.settings.section_jump to the src-tauri/resources/locales/* locale JSON/YAML files with appropriate translations (including English), then remove the hardcoded fallback from the call and call this._i18n.t('ui.launcher.settings.section_jump') (or ensure the t function uses locale files by default) so the label is sourced from the localization resources instead of inline text.src/public/templates/pages/settings.html (1)
39-40:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winRemove hardcoded English tooltip/label fallback from the HTML button.
titleandaria-labelare hardcoded in English even though this control already uses i18n attributes.Suggested fix
- title="Switch settings section" - aria-label="Switch settings section"As per coding guidelines
src/**/*.{ts,tsx,html}: Keep UI text in I18n resources under src-tauri/resources/locales/ and do not hardcode Russian or English user-facing strings in TS/HTML.🤖 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 `@src/public/templates/pages/settings.html` around lines 39 - 40, Remove the hardcoded English title and aria-label attributes from the button (the element in settings.html that currently has title="Switch settings section" and aria-label="Switch settings section") and replace them with the appropriate i18n attributes/keys so the tooltip/accessible label comes from the locale resources under src-tauri/resources/locales/ (use the same i18n key pattern already used by this control so translations are loaded instead of hardcoding English).src-tauri/src/domain/integration_api/routing.rs (2)
251-258:⚠️ Potential issue | 🟠 Major | ⚡ Quick winKeep successful module control responses independent from UI sync failures.
Line 257 uses
?onsync_launcher_selected_module(...); if sync/save/emit fails, a successful module action is returned as an error.Suggested fix
if response.success && matches!( action, ModuleAction::Start | ModuleAction::Restart | ModuleAction::Repair ) { - sync_launcher_selected_module(&context, client, module_id).await?; + if let Err(error) = sync_launcher_selected_module(&context, client, module_id).await + { + tracing::warn!( + module_id = %module_id, + action = %module_action_name(action), + "Module control succeeded but selected-module sync failed: {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 `@src-tauri/src/domain/integration_api/routing.rs` around lines 251 - 258, The code currently uses `?` on `sync_launcher_selected_module(&context, client, module_id).await` inside the block that handles a successful module control response, which turns any UI sync/save/emit failure into an overall error; instead, call and await `sync_launcher_selected_module` and handle its Result locally (e.g., `if let Err(e) = sync_launcher_selected_module(...).await { ... }`) so the successful response from the module action (ModuleAction::Start | Restart | Repair) is preserved; log or trace the error (using the existing logger/context) and continue without propagating the error to the caller.
114-117:⚠️ Potential issue | 🟠 Major | ⚡ Quick winRestrict approval list visibility to avoid cross-agent data leakage.
Line 115 still allows
AuthorizedClient::Agent(_), and Line 708 returnsstate.approvalsunfiltered. Any observe-scoped agent can read other agents’ pending approval details.As per coding guidelines `src-tauri/src/**/*.rs`: “Prioritize IPC boundary validation … and keep user data scoped to app directories.”Suggested fix
- ("GET", ["v1", "agent", "approvals"]) => { - ensure_launcher_client(client)?; - ensure_agent_scope(client, AgentScope::Observe)?; - handle_agent_approvals_request(&context).await - } + ("GET", ["v1", "agent", "approvals"]) => { + ensure_strict_launcher_client(client)?; + handle_agent_approvals_request(&context).await + }+fn ensure_strict_launcher_client(client: &AuthorizedClient) -> Result<(), AppError> { + match client { + AuthorizedClient::Launcher => Ok(()), + AuthorizedClient::Agent(_) | AuthorizedClient::Module(_) => Err(AppError::PermissionDenied( + "Only launcher tokens can access global approvals".to_string(), + )), + } +}Also applies to: 699-709
🤖 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 `@src-tauri/src/domain/integration_api/routing.rs` around lines 114 - 117, The approvals endpoint currently permits AuthorizedClient::Agent(_) with Observe scope and returns state.approvals unfiltered, allowing cross-agent leakage; update handle_agent_approvals_request to accept the caller's agent identity (or the AuthorizedClient) and filter state.approvals to only include approvals scoped to that agent (e.g., match approval.target_agent_id or approval.agent_id against the caller's agent id) and ensure the routing/authorization (ensure_agent_scope / AuthorizedClient::Agent) passes the caller identity through to the handler so only the caller's approvals are returned.
🤖 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 `@src/styles/features/settings-page.css`:
- Around line 83-87: The CSS uses the keyword "currentColor" in the box-shadow
(the block with offsets "-8px -4px 0 currentColor, 8px -4px 0 currentColor, -4px
0 0 currentColor, 4px 0 0 currentColor, 0 4px 0 currentColor;") which triggers
Stylelint's value-keyword-case rule; update each occurrence of "currentColor" to
the lowercase "currentcolor" so the keyword casing matches the linter
expectation and CI will pass.
---
Outside diff comments:
In `@src-tauri/src/domain/integration_api/routing.rs`:
- Around line 429-445: The validate_relative_draft_path function currently
checks is_absolute and ParentDir but allows Windows drive-relative prefixes;
update its component validation in validate_relative_draft_path to also reject
components matching std::path::Component::Prefix(_) and
std::path::Component::RootDir so any path containing Prefix or RootDir returns
Err(AppError::Validation("Draft entry path must stay inside the draft
directory".to_string())). Locate the check that iterates path.components() and
add matches for Prefix(_) and RootDir alongside ParentDir to ensure Windows
drive-relative inputs like "C:temp\\file" are refused.
---
Duplicate comments:
In `@src-tauri/src/api/agent_control.rs`:
- Around line 62-68: The code currently calls
service.take_pending_token(&id).await? (consuming the one-time token) before
calling app.clipboard().write_text(token), which loses the token on clipboard
failure; change the flow so the token is not consumed until clipboard write
succeeds: either use a non-consuming read API on service (e.g.,
peek_pending_token or similar) and only call take_pending_token(&id) after
write_text succeeds, or if no non-consuming API exists, attempt to write_text
first and on error call a restore method on service (e.g.,
restore_pending_token(&id, token)) before returning an AppError::External;
update references to take_pending_token, app.clipboard().write_text, service,
id, token, and AppError::External accordingly.
In `@src-tauri/src/domain/integration_api/routing.rs`:
- Around line 251-258: The code currently uses `?` on
`sync_launcher_selected_module(&context, client, module_id).await` inside the
block that handles a successful module control response, which turns any UI
sync/save/emit failure into an overall error; instead, call and await
`sync_launcher_selected_module` and handle its Result locally (e.g., `if let
Err(e) = sync_launcher_selected_module(...).await { ... }`) so the successful
response from the module action (ModuleAction::Start | Restart | Repair) is
preserved; log or trace the error (using the existing logger/context) and
continue without propagating the error to the caller.
- Around line 114-117: The approvals endpoint currently permits
AuthorizedClient::Agent(_) with Observe scope and returns state.approvals
unfiltered, allowing cross-agent leakage; update handle_agent_approvals_request
to accept the caller's agent identity (or the AuthorizedClient) and filter
state.approvals to only include approvals scoped to that agent (e.g., match
approval.target_agent_id or approval.agent_id against the caller's agent id) and
ensure the routing/authorization (ensure_agent_scope / AuthorizedClient::Agent)
passes the caller identity through to the handler so only the caller's approvals
are returned.
In `@src/features/settings/ui/SettingsUI.ts`:
- Line 136: The code currently hardcodes an English fallback string in the i18n
call for the label (const label =
this._i18n.t('ui.launcher.settings.section_jump', 'Switch settings section')),
which violates the rule to keep UI text in locale files; add the key
ui.launcher.settings.section_jump to the src-tauri/resources/locales/* locale
JSON/YAML files with appropriate translations (including English), then remove
the hardcoded fallback from the call and call
this._i18n.t('ui.launcher.settings.section_jump') (or ensure the t function uses
locale files by default) so the label is sourced from the localization resources
instead of inline text.
In `@src/public/templates/pages/settings.html`:
- Around line 39-40: Remove the hardcoded English title and aria-label
attributes from the button (the element in settings.html that currently has
title="Switch settings section" and aria-label="Switch settings section") and
replace them with the appropriate i18n attributes/keys so the tooltip/accessible
label comes from the locale resources under src-tauri/resources/locales/ (use
the same i18n key pattern already used by this control so translations are
loaded instead of hardcoding English).
🪄 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: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 01e7f732-9e37-4dec-a432-c0e7fefb51e0
⛔ Files ignored due to path filters (1)
src/assets/fonts/Cubic_11.zh-subset.woff2is excluded by!**/*.woff2
📒 Files selected for processing (25)
SECURITY.mddocs/examples/sdk/javascript/axelate-client.mjsdocs/examples/sdk/python/axelate_sdk.pydocs/localization/en/AGENT_CONTROL.mddocs/localization/en/INTEGRATION_API.mddocs/localization/en/ROADMAP.mddocs/localization/en/TRUST_MODEL.mdsrc-tauri/resources/locales/en.jsonsrc-tauri/resources/locales/ru.jsonsrc-tauri/resources/locales/zh.jsonsrc-tauri/src/api/agent_control.rssrc-tauri/src/domain/agent_control.rssrc-tauri/src/domain/integration_api/routing.rssrc-tauri/src/domain/integration_api/tests.rssrc-tauri/src/lib.rssrc/features/settings/services/SettingsService.test.tssrc/features/settings/services/SettingsService.tssrc/features/settings/ui/AgentControlSettingsRenderer.test.tssrc/features/settings/ui/AgentControlSettingsRenderer.tssrc/features/settings/ui/SettingsPageUI.test.tssrc/features/settings/ui/SettingsUI.tssrc/public/templates/pages/settings.htmlsrc/shared/types/bindings.tssrc/styles/features/console-page.csssrc/styles/features/settings-page.css
💤 Files with no reviewable changes (3)
- src-tauri/src/lib.rs
- src/features/settings/services/SettingsService.ts
- src/shared/types/bindings.ts
✅ Files skipped from review due to trivial changes (3)
- SECURITY.md
- docs/localization/en/AGENT_CONTROL.md
- docs/localization/en/ROADMAP.md
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
Summary
Summary by CodeRabbit
New Features
Localization
Improvements
Tests
Chores