Add Submodel channel support#1804
Conversation
# Conflicts: # common/api_type.go # constant/api_type.go # constant/channel.go # relay/relay_adaptor.go # web/src/constants/channel.constants.js
# Conflicts: # relay/relay_adaptor.go
WalkthroughAdds a new Submodel channel: constants (channel/API), base URL, adaptor implementation and wiring, model list and ratios, web UI option/icon and modal defaults; includes an unresolved merge conflict in relay adaptor import/merge area. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor Client
participant Relay as Relay (Submodel Adaptor)
participant SubAPI as Submodel API
Client->>Relay: OpenAI-style request (channelType=53)
rect rgba(200,230,255,0.15)
Relay->>Relay: ConvertOpenAIRequest (passthrough check)
Relay->>Relay: GetRequestURL(baseUrl, path, channelType)
Relay->>Relay: SetupRequestHeader (Authorization: Bearer)
end
Relay->>SubAPI: DoRequest (channel.DoApiRequest)
alt Streaming (info.IsStream)
SubAPI-->>Relay: stream chunks
Relay-->>Client: OaiStreamHandler -> stream client
else Non-stream
SubAPI-->>Relay: JSON response
Relay-->>Client: OpenaiHandler -> final response
end
note right of Relay: Unsupported endpoints return "endpoint not supported" errors
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests
Tip 👮 Agentic pre-merge checks are now available in preview!Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.
Please see the documentation for more information. Example: reviews:
pre_merge_checks:
custom_checks:
- name: "Undocumented Breaking Changes"
mode: "warning"
instructions: |
Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).Please share your feedback with us on this Discord post. 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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (11)
web/src/components/table/channels/modals/EditTagModal.jsx (1)
121-123: Dead code path: switch(name==='type') never fires in this modal.This modal doesn’t expose a "type" field, so case 53 won’t execute. Either remove the switch(name==='type') block from this component or source the list via getChannelModels(53) when initializing models for SubModel to avoid duplication.
Apply one of:
- Remove the unused switch block from this component.
- Or, on load for SubModel tags, set models from a single source (helpers/getChannelModels or backend) instead of hardcoding here.
web/src/helpers/render.jsx (2)
346-347: Channel icon mapping added — OK; comment label is misleading.Case 53 is a channel, not “嵌入模型”. Suggest correcting the comment to “SubModel”.
- case 53: // 嵌入模型:SubModel + case 53: // SubModel return <SubModel size={iconSize} />;
1444-1464: Minor: keep i18n messages consistent with existing wording.The updated sentence structure is fine; no functional change. Consider reusing shared fragments to reduce duplication.
setting/ratio_setting/model_ratio.go (1)
253-264: SubModel ratios added — OK; add CompletionRatio entries for namespaced models.
GetCompletionRatio does an exact lookup for names containing '/' and then falls back to hard-coded heuristics (commonly default 1). Add explicit CompletionRatio entries for the new namespaced models in setting/ratio_setting/model_ratio.go (submodel block ~lines 252–264) to avoid unintended defaults; see GetCompletionRatio implementation (~lines 459–476).relay/channel/submodel/constants.go (2)
3-14: Make the model list private and immutable to callers.Exported
ModelListcan be mutated by other packages and viaGetModelList, which returns the backing slice. Make it unexported and return a copy from the adaptor.Apply:
-var ModelList = []string{ +var modelList = []string{ "NousResearch/Hermes-4-405B-FP8", "Qwen/Qwen3-235B-A22B-Thinking-2507", "Qwen/Qwen3-Coder-480B-A35B-Instruct-FP8", "Qwen/Qwen3-235B-A22B-Instruct-2507", "zai-org/GLM-4.5-FP8", "openai/gpt-oss-120b", "deepseek-ai/DeepSeek-R1-0528", "deepseek-ai/DeepSeek-R1", "deepseek-ai/DeepSeek-V3-0324", "deepseek-ai/DeepSeek-V3.1", }
3-14: Model list will drift; consider configuration/override.These identifiers change frequently. Recommend allowing override via DB/admin setting or env (comma‑separated) and documenting defaults here.
relay/channel/submodel/adaptor.go (5)
34-36: Cloudflare Gateway path handling gap.
GetFullRequestURLspecial‑cases OpenAI/Azure when base isgateway.ai.cloudflare.combut not Submodel. If this channel ever uses CF Gateway, requests may be misrouted. Either add a Submodel case inrelay/common/relay_utils.goor ensure Submodel base URLs never use CF Gateway.
38-42: Don’t override Authorization if caller set a custom header.
DoApiRequestappliesHeadersOverridebefore this, but this setter unconditionally clobbers it.Apply:
func (a *Adaptor) SetupRequestHeader(c *gin.Context, req *http.Header, info *relaycommon.RelayInfo) error { channel.SetupApiRequestHeader(info, c, req) - req.Set("Authorization", "Bearer "+info.ApiKey) + if req.Get("Authorization") == "" { + req.Set("Authorization", "Bearer "+info.ApiKey) + } return nil }
44-49: Minor: normalize stream flag (optional).If upstream didn’t set
info.IsStream, consider syncing fromrequest.Streamto avoid mismatches.
19-29: Prefer typed, user‑facing errors.Returning plain
errors.New("endpoint not supported")may map to generic 500s. If available, use a channel‑agnostic error (e.g.,types.NewError(..., ErrorCodeEndpointNotSupported)) for consistent status codes and client messaging.Also applies to: 51-57
76-82: Return a copy of the model list.Prevents external mutation of internal slice.
Apply:
func (a *Adaptor) GetModelList() []string { - return ModelList + return append([]string(nil), modelList...) } func (a *Adaptor) GetChannelName() string { return ChannelName }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (10)
common/api_type.go(1 hunks)constant/api_type.go(1 hunks)constant/channel.go(2 hunks)relay/channel/submodel/adaptor.go(1 hunks)relay/channel/submodel/constants.go(1 hunks)relay/relay_adaptor.go(2 hunks)setting/ratio_setting/model_ratio.go(1 hunks)web/src/components/table/channels/modals/EditTagModal.jsx(1 hunks)web/src/constants/channel.constants.js(1 hunks)web/src/helpers/render.jsx(6 hunks)
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-08-27T02:15:25.448Z
Learnt from: AAEE86
PR: QuantumNous/new-api#1658
File: web/src/components/table/channels/modals/EditChannelModal.jsx:555-569
Timestamp: 2025-08-27T02:15:25.448Z
Learning: In EditChannelModal.jsx, the applyModelMapping function transforms the models list by replacing original model names (mapping values) with display names (mapping keys). The database stores this transformed list containing mapped keys. On channel load, data.models contains these mapped display names, making the initialization filter if (data.models.includes(key)) correct.
Applied to files:
web/src/components/table/channels/modals/EditTagModal.jsx
📚 Learning: 2025-08-27T02:15:25.448Z
Learnt from: AAEE86
PR: QuantumNous/new-api#1658
File: web/src/components/table/channels/modals/EditChannelModal.jsx:555-569
Timestamp: 2025-08-27T02:15:25.448Z
Learning: In EditChannelModal.jsx, the database stores mapped keys (display names) in the models field after applying model mapping transformations. When loading a channel, data.models contains the mapped keys, not the original model names. The filtering logic if (data.models.includes(key)) in the initialization is correct.
Applied to files:
web/src/components/table/channels/modals/EditTagModal.jsx
📚 Learning: 2025-08-05T17:14:17.246Z
Learnt from: neotf
PR: QuantumNous/new-api#1511
File: setting/ratio_setting/model_ratio.go:118-123
Timestamp: 2025-08-05T17:14:17.246Z
Learning: Claude models handle "-thinking" variants differently from Gemini models. For Claude models, only the base model (without "-thinking") gets an entry in defaultModelRatio map. The "-thinking" variants rely on the Claude relay handler stripping the suffix using strings.TrimSuffix(textRequest.Model, "-thinking") before looking up the ratio, so they automatically use the base model's ratio.
Applied to files:
setting/ratio_setting/model_ratio.go
🧬 Code graph analysis (4)
common/api_type.go (2)
constant/channel.go (1)
ChannelTypeSubmodel(53-53)constant/api_type.go (1)
APITypeSubmodel(36-36)
relay/channel/submodel/adaptor.go (10)
relay/common/relay_info.go (1)
RelayInfo(74-120)dto/claude.go (1)
ClaudeRequest(187-203)dto/audio.go (1)
AudioRequest(9-15)relay/common/relay_utils.go (1)
GetFullRequestURL(22-34)relay/channel/api_request.go (3)
SetupApiRequestHeader(25-37)DoRequest(231-233)DoApiRequest(39-72)dto/openai_request.go (2)
GeneralOpenAIRequest(25-78)OpenAIResponsesRequest(768-790)dto/rerank.go (1)
RerankRequest(10-18)dto/embedding.go (1)
EmbeddingRequest(21-32)relay/channel/openai/relay-openai.go (2)
OaiStreamHandler(111-175)OpenaiHandler(177-256)relay/channel/submodel/constants.go (2)
ModelList(3-14)ChannelName(16-16)
relay/relay_adaptor.go (3)
constant/api_type.go (1)
APITypeSubmodel(36-36)relay/channel/submodel/adaptor.go (1)
Adaptor(16-17)relay/channel/adapter.go (1)
Adaptor(13-30)
web/src/helpers/render.jsx (1)
web/src/hooks/model-pricing/useModelPricingData.jsx (1)
groupRatio(50-50)
🔇 Additional comments (9)
constant/channel.go (2)
53-57: New ChannelTypeSubmodel constant — OK.Constant placement is correct (before ChannelTypeDummy). No issues.
113-114: Base URL added — confirm correctness and TLS/cert expectations."https://llm.submodel.ai" looks fine. Ensure adaptor builds paths correctly (e.g., v1 prefix if required) and that self-signed/corporate CAs aren’t needed in production.
web/src/helpers/render.jsx (2)
1604-1632: Claude price log strings — OK.Templates look consistent with renderClaudeModelPrice math.
1197-1215: Translation strings added — verify locale coverageNew Chinese i18n keys introduced in web/src/helpers/render.jsx (lines ~1125, 1132, 1197, 1208). Ensure matching entries exist in your locale files (e.g. web/src/i18n/locales/zh.json and web/src/i18n/locales/en.json) or confirm you intentionally rely on string-as-key fallback.
common/api_type.go (1)
70-72: API mapping for SubModel — OK.ChannelTypeSubmodel → APITypeSubmodel mapping added correctly.
web/src/constants/channel.constants.js (1)
162-166: Add SubModel option — ChannelTypeSubmodel = 53 confirmed in backend; E2E verification required.
constant/channel.go:53 — ChannelTypeSubmodel = 53. Ensure end-to-end consumers (DB, API mappings, clients/tests) recognize the new channel type.relay/channel/submodel/constants.go (1)
16-16: Confirm channel display name casing.Elsewhere UI uses “SubModel”. Verify
"submodel"won’t lead to inconsistent labeling or i18n mismatches.relay/channel/submodel/adaptor.go (2)
59-61: Responses API not supported — verify routing/UI.UI or router may send
/v1/responsesfor some models. If Submodel truly doesn’t support it, ensure it’s hidden/disabled for this channel to prevent 4xx.
67-74: Assumes OpenAI‑compatible responses.
OaiStreamHandler/OpenaiHandlerexpect OpenAI schema and SSE format. Confirm Submodel aligns (event names, deltas, usage fields). Also verify pricing/usage mapping exists for these models to avoid zero/incorrect billing.
| APITypeSubmodel | ||
| ) |
There was a problem hiding this comment.
💡 Verification agent
🧩 Analysis chain
Do not add after APITypeDummy — move APITypeSubmodel before Dummy.
APITypeDummy is a sentinel (“do not add any channel after this”). Adding Submodel after Dummy breaks that contract and may exclude it from counts/loops.
Apply this reordering:
APITypeJimeng
- APITypeMoonshot // this one is only for count, do not add any channel after this
- APITypeDummy // this one is only for count, do not add any channel after this
- APITypeSubmodel
+ APITypeMoonshot
+ APITypeSubmodel
+ APITypeDummy // this one is only for count, do not add any channel after this🏁 Script executed:
#!/bin/bash
# Check for places treating APITypeDummy as an upper bound
rg -nP '(APITypeDummy).*?do not add|for\s*\(.*<\s*constant\.APITypeDummy' -C2Length of output: 317
Move APITypeSubmodel before APITypeDummy (constant/api_type.go:34-36)
APITypeDummy is a sentinel ("do not add any channel after this"); Submodel after it violates that contract and can be excluded from counts/loops.
APITypeJimeng
- APITypeMoonshot // this one is only for count, do not add any channel after this
- APITypeDummy // this one is only for count, do not add any channel after this
- APITypeSubmodel
+ APITypeMoonshot
+ APITypeSubmodel
+ APITypeDummy // this one is only for count, do not add any channel after this📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| APITypeSubmodel | |
| ) | |
| APITypeJimeng | |
| APITypeMoonshot | |
| APITypeSubmodel | |
| APITypeDummy // this one is only for count, do not add any channel after this | |
| ) |
🤖 Prompt for AI Agents
In constant/api_type.go around lines 34 to 37, APITypeSubmodel is declared after
the sentinel APITypeDummy which breaks the sentinel contract; move the
APITypeSubmodel constant declaration so it appears before APITypeDummy (i.e.,
reorder the constants so APITypeDummy remains the final sentinel value), and
ensure any comments/documentation reflect that APITypeDummy is the terminal
sentinel and that Submodel is excluded from sentinel-based counts/loops.
| "one-api/relay/channel/submodel" | ||
| ======= | ||
|
|
||
| "github.com/gin-gonic/gin" | ||
| >>>>>>> 4f760a8d407d321bf7f011331ecffb2744b555fd |
There was a problem hiding this comment.
Unresolved merge conflict and missing imports — blocks build.
Conflict markers present; gin import is dropped; submodel import only on one side. Resolve and include both imports.
Apply this fix:
import (
"one-api/constant"
"one-api/relay/channel"
"one-api/relay/channel/ali"
@@
"one-api/relay/channel/zhipu_4v"
"strconv"
-<<<<<<< HEAD
- "one-api/relay/channel/submodel"
-=======
-
- "github.com/gin-gonic/gin"
->>>>>>> 4f760a8d407d321bf7f011331ecffb2744b555fd
+ "github.com/gin-gonic/gin"
+ "one-api/relay/channel/submodel"
)📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| "one-api/relay/channel/submodel" | |
| ======= | |
| "github.com/gin-gonic/gin" | |
| >>>>>>> 4f760a8d407d321bf7f011331ecffb2744b555fd | |
| "github.com/gin-gonic/gin" | |
| "one-api/relay/channel/submodel" |
🤖 Prompt for AI Agents
In relay/relay_adaptor.go around lines 41 to 45, remove the unresolved git
conflict markers and restore a proper import block that includes both
"one-api/relay/channel/submodel" and "github.com/gin-gonic/gin"; ensure there
are no leftover <<<<<<<, =======, >>>>>>> lines, place both packages as separate
entries in the import section, run gofmt/goimports to fix formatting and then
rebuild to confirm the missing import and conflict errors are resolved.
| case constant.APITypeSubmodel: | ||
| return &submodel.Adaptor{} | ||
| } |
There was a problem hiding this comment.
💡 Verification agent
🧩 Analysis chain
Adaptor wiring for SubModel — OK once imports are fixed.
Case is correct; will work after resolving imports.
🏁 Script executed:
#!/bin/bash
# Ensure no other conflict markers remain
rg -n '^(<{7}|={7}|>{7})' -SLength of output: 147
Resolve git merge conflicts and fix imports in relay/relay_adaptor.go
Submodel adaptor case (lines 110–112) is correct, but relay/relay_adaptor.go contains unresolved git conflict markers at lines 40, 42, 45 — remove the conflict markers and fix imports so the file compiles.
🤖 Prompt for AI Agents
In relay/relay_adaptor.go around lines 40, 42, 45 and 110–112, there are
unresolved git conflict markers that must be removed and the import block fixed
so the file compiles; delete the conflict marker lines (e.g. <<<<<<<, =======,
>>>>>>>) at the referenced lines, ensure the import list includes the submodel
package import path used by the case constant.APITypeSubmodel and any other
packages referenced in the file, remove any duplicate or unused imports, and run
go build or go vet to confirm the file compiles cleanly.
| SubModel, | ||
| } from '@lobehub/icons'; |
There was a problem hiding this comment.
💡 Verification agent
🧩 Analysis chain
Verify SubModel icon export exists in @lobehub/icons.
Import compiles only if SubModel is exported in your installed version.
🌐 Web query:
Does @lobehub/icons export a SubModel icon component? Which package version includes it, and is the component name exactly "SubModel"?
💡 Result:
Short answer: No.
- I couldn't find any exported component named "SubModel" in the @lobehub/icons package or its repository. [1][2].
- The npm package pages and the lobe-icons GitHub repo/releases list show the package and recent versions, but there is no mention or file named SubModel in the source or changelog. [1][3].
If you want, I can search a specific package version tarball or list the package's exported names to double-check—which version should I inspect?
Sources:
- @lobehub/icons (npm) package page. [1]
- lobehub / lobe-icons repository (GitHub). [2]
- lobe-icons releases / changelog (GitHub Releases). [3]
SubModel is not exported by @lobehub/icons — remove or replace import
The @lobehub/icons package does not export a component named "SubModel"; the import in web/src/helpers/render.jsx (lines 57–58) will fail to compile.
- Remove "SubModel" from the import and use an available exported icon or add/point to the package version that provides it.
🤖 Prompt for AI Agents
In web/src/helpers/render.jsx around lines 57-58, the import includes "SubModel"
which is not exported by @lobehub/icons; remove "SubModel" from the import
statement and either replace its usage in this file with an icon that exists in
@lobehub/icons (search current exports and pick a suitable replacement) or
update/package.json to a version of @lobehub/icons that actually exports
SubModel and run npm/yarn install; ensure any JSX references to <SubModel /> are
updated to the chosen replacement component name.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (3)
web/src/helpers/render.jsx (3)
1206-1213: Don’t use literal strings as i18n keys — add stable keys with defaultValuePassing a full sentence (with spaces/Chinese) as the key makes it untranslatable and brittle. Define keys and use defaultValue for fallback text.
Example:
- ? i18next.t( - ' + Web搜索 {{count}}次 / 1K 次 * ${{price}} * {{ratioType}} {{ratio}}', - { count: webSearchCallCount, price: webSearchPrice, ratio: groupRatio, ratioType: ratioLabel } - ) + ? i18next.t('pricing.extra.webSearch', { + defaultValue: ' + Web搜索 {{count}}次 / 1K 次 * ${{price}} * {{ratioType}} {{ratio}}', + count: webSearchCallCount, + price: webSearchPrice, + ratio: groupRatio, + ratioType: ratioLabel, + })And similarly for 文件搜索:
- ? i18next.t( - ' + 文件搜索 {{count}}次 / 1K 次 * ${{price}} * {{ratioType}} {{ratio}}', - { count: fileSearchCallCount, price: fileSearchPrice, ratio: groupRatio, ratioType: ratioLabel } - ) + ? i18next.t('pricing.extra.fileSearch', { + defaultValue: ' + 文件搜索 {{count}}次 / 1K 次 * ${{price}} * {{ratioType}} {{ratio}}', + count: fileSearchCallCount, + price: fileSearchPrice, + ratio: groupRatio, + ratioType: ratioLabel, + })Please also add these keys to your locale files.
Also applies to: 1217-1224
1463-1483: Same i18n issue — replace literal-string keys with proper keys + defaultValueThese sentences should also use stable keys to be translatable and avoid treating the sentence as a lookup key.
Example pattern:
- i18next.t('文字提示 {{nonCacheInput}} tokens / 1M tokens * ${{price}} + ... = ${{total}}', { ... }) + i18next.t('pricing.text.detailWithCache', { + defaultValue: '文字提示 {{nonCacheInput}} tokens / 1M tokens * ${{price}} + 缓存 {{cacheInput}} tokens / 1M tokens * ${{cachePrice}} + 文字补全 {{completion}} tokens / 1M tokens * ${{compPrice}} = ${{total}}', + nonCacheInput, cacheInput, cachePrice, price: inputRatioPrice, completion: completionTokens, compPrice: completionRatioPrice, total: textPrice.toFixed(6), +})
1623-1651: Repeat: convert literal i18n calls to keyed strings with defaultValueEnsure these two branches use translation keys; avoid constructing entire sentences as keys.
Example:
- i18next.t('提示 {{input}} tokens / 1M tokens * ${{price}} + 补全 {{completion}} tokens / 1M tokens * ${{compPrice}} * {{ratioType}} {{ratio}} = ${{total}}', { ... }) + i18next.t('pricing.claude.simple', { + defaultValue: '提示 {{input}} tokens / 1M tokens * ${{price}} + 补全 {{completion}} tokens / 1M tokens * ${{compPrice}} * {{ratioType}} {{ratio}} = ${{total}}', + input: inputTokens, price: inputRatioPrice, completion: completionTokens, compPrice: completionRatioPrice, ratio: groupRatio, ratioType: ratioLabel, total: price.toFixed(6), +})
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
setting/ratio_setting/model_ratio.go(1 hunks)web/src/helpers/render.jsx(6 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- setting/ratio_setting/model_ratio.go
🔇 Additional comments (2)
web/src/helpers/render.jsx (2)
1404-1408: LGTM — formatting onlyLine breaks in the multiplication chain don’t change semantics.
57-58: SubModel icon import will break build — remove named import and guard usageThe @lobehub/icons package doesn’t export SubModel in common versions; this named import will fail at compile time. Prefer feature-detecting via the namespace import you already have and fall back to a generic icon.
Apply:
- Jimeng, - SubModel, + Jimeng, } from '@lobehub/icons';
| case 53: // 嵌入模型:SubModel | ||
| return <SubModel size={iconSize} />; |
There was a problem hiding this comment.
Guard SubModel usage with feature-detect; provide fallback icon
Avoid hard dependency on a possibly-missing icon component. Use LobeIcons.SubModel if present, otherwise a generic Layers icon.
- case 53: // 嵌入模型:SubModel
- return <SubModel size={iconSize} />;
+ case 53: { // 子模型 / SubModel
+ const Icon = LobeIcons.SubModel;
+ return Icon ? <Icon size={iconSize} /> : <Layers size={iconSize} />;
+ }📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| case 53: // 嵌入模型:SubModel | |
| return <SubModel size={iconSize} />; | |
| case 53: { // 子模型 / SubModel | |
| const Icon = LobeIcons.SubModel; | |
| return Icon ? <Icon size={iconSize} /> : <Layers size={iconSize} />; | |
| } |
🤖 Prompt for AI Agents
In web/src/helpers/render.jsx around lines 346-347, the code unconditionally
returns <SubModel /> which can break if that icon component is missing; update
the return to guard feature-detect LobeIcons.SubModel and fall back to a generic
Layers icon: ensure LobeIcons (and the fallback Icons/Layers component) are in
scope, then replace the unconditional return with a conditional usage such as
using a local variable Component = (LobeIcons && LobeIcons.SubModel) ?
LobeIcons.SubModel : Icons.Layers and return <Component size={iconSize} /> so
the code safely uses the SubModel icon when available and a Layers icon
otherwise.
|
编译不过呀 |
Summary by CodeRabbit
New Features
Improvements