Skip to content

Add Submodel channel support#1774

Closed
danding5 wants to merge 0 commit into
QuantumNous:mainfrom
danding5:main
Closed

Add Submodel channel support#1774
danding5 wants to merge 0 commit into
QuantumNous:mainfrom
danding5:main

Conversation

@danding5
Copy link
Copy Markdown
Contributor

@danding5 danding5 commented Sep 10, 2025

Summary by CodeRabbit

  • New Features
    • Added a new “SubModel” channel type with support for 10 popular models (e.g., Hermes-4-405B-FP8, Qwen3-235B, Qwen3-Coder-480B, DeepSeek-R1, DeepSeek-V3).
    • SubModel now appears in channel selection and auto-fills model options in the tag editor.
    • Supports OpenAI-compatible requests and streaming/non‑streaming responses.
    • Added default model ratio entries for SubModel models to improve out‑of‑the‑box weighting.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Sep 10, 2025

Walkthrough

Adds a new “Submodel” channel (type 53) and API type, wires it into adaptor selection, provides a new relay adaptor with basic OpenAI pass-through and request/response handling, defines model list and channel name, updates default model ratios, and exposes the new channel in the web UI with predefined models.

Changes

Cohort / File(s) Summary
API types and wiring
constant/api_type.go, common/api_type.go, relay/relay_adaptor.go
Introduces APITypeSubmodel; maps ChannelTypeSubmodel to it; extends adaptor factory to return submodel.Adaptor{} for the new API type.
Channel constants
constant/channel.go
Adds ChannelTypeSubmodel = 53 and base URL https://llm.submodel.ai at index 53.
Submodel adaptor implementation
relay/channel/submodel/adaptor.go, relay/channel/submodel/constants.go
Adds Adaptor with OpenAI request pass-through, header setup, URL build, request execution, and stream/non-stream response handling; defines ModelList and ChannelName = "submodel". Other Convert* methods stubbed.
Default model ratios
setting/ratio_setting/model_ratio.go
Adds “submodel” block with 10 model ratios.
Web UI: channel exposure
web/src/constants/channel.constants.js, web/src/components/table/channels/modals/EditTagModal.jsx
Adds channel option value 53 “SubModel”; handles type 53 in modal with predefined model list.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant UI as Web UI
  participant Relay as Relay API
  participant Adapt as Submodel Adaptor
  participant Up as Submodel Upstream

  User->>UI: Select channel 53 (SubModel)
  UI->>Relay: OpenAI-style request (stream? flag)
  Relay->>Adapt: GetAdaptor(APITypeSubmodel)
  Note right of Adapt: Build URL, set Authorization header
  Adapt->>Up: POST /v1/... with body
  alt Streaming
    Up-->>Adapt: SSE stream
    Adapt-->>Relay: stream chunks
    Relay-->>UI: stream chunks
  else Non-stream
    Up-->>Adapt: JSON response
    Adapt-->>Relay: JSON response
    Relay-->>UI: JSON response
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • xyfacai

Poem

A hop, a skip, a brand-new trail,
Submodel’s burrow, we unveil.
Models lined like carrots bright,
Streaming whispers through the night.
Ratios set, the routes aligned—
Thump-thump! New paths, neatly defined. 🥕🐇

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.

  • Built-in checks – Quickly apply ready-made checks to enforce title conventions, require pull request descriptions that follow templates, validate linked issues for compliance, and more.
  • Custom agentic checks – Define your own rules using CodeRabbit’s advanced agentic capabilities to enforce organization-specific policies and workflows. For example, you can instruct CodeRabbit’s agent to verify that API documentation is updated whenever API schema files are modified in a PR. Note: Upto 5 custom checks are currently allowed during the preview period. Pricing for this feature will be announced in a few weeks.

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.


📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 78b0f89 and a12ed57.

📒 Files selected for processing (3)
  • relay/channel/submodel/constants.go (1 hunks)
  • setting/ratio_setting/model_ratio.go (1 hunks)
  • web/src/components/table/channels/modals/EditTagModal.jsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • web/src/components/table/channels/modals/EditTagModal.jsx
  • relay/channel/submodel/constants.go
  • setting/ratio_setting/model_ratio.go

Pre-merge checks (3 passed)

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
Title Check ✅ Passed The title “Add Submodel channel support” succinctly and accurately summarizes the pull request’s primary change of integrating a new Submodel channel across core services, constants, adaptors, and UI components without including extraneous details.
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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
Copy Markdown
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: 4

🧹 Nitpick comments (8)
relay/channel/submodel/constants.go (2)

16-16: Use const for ChannelName.

Slightly tighter typing; avoids accidental reassignment.

-var ChannelName = "submodel"
+const ChannelName = "submodel"

3-14: Avoid frontend/backend model list duplication.

These models are hardcoded here and again in the web modal; they’ll drift. Prefer serving this list from the backend (e.g., via GetModelList) and letting the UI consume it.

web/src/constants/channel.constants.js (1)

162-166: Minor label casing consistency.

Most labels are proper-cased words (e.g., “OpenRouter”, “MiniMax”); recommend “Submodel” rather than “SubModel”.

-    label: 'SubModel',
+    label: 'Submodel',
web/src/helpers/render.jsx (1)

345-347: Redundant explicit case.

Default already returns null; keeping this case is fine for clarity, but it’s not required.

relay/relay_adaptor.go (1)

3-41: Import grouping/style.

Go tooling will reformat, but keep imports grouped/sorted to avoid lint noise.

web/src/components/table/channels/modals/EditTagModal.jsx (1)

121-123: DRY: avoid duplicating the model list here.

Prefer sourcing from a single place (e.g., backend ModelList via helper or API) to prevent drift from relay/channel/submodel/constants.go.

setting/ratio_setting/model_ratio.go (1)

255-266: Keep model names DRY and in sync with the Submodel model list.

These entries duplicate the list in relay/channel/submodel/constants.go. Consider centralizing the model names (or generating this section) to avoid drift when the upstream list changes.

Would you like a small generator to validate that defaultModelRatio contains all entries from submodel.ModelList and flags extras?

relay/channel/submodel/adaptor.go (1)

31-33: Optional: initialize guarded capabilities.

If this channel intentionally supports only chat/completions, set a capability flag in Init (or channel meta) and short-circuit unsupported relay modes earlier with a consistent error type.

I can add a small capability gate to fail fast with a typed error and unit tests.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 041782c and 78b0f89.

📒 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 (1 hunks)
🧰 Additional context used
🧠 Learnings (3)
📚 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
📚 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
🧬 Code graph analysis (3)
common/api_type.go (2)
constant/channel.go (1)
  • ChannelTypeSubmodel (53-53)
constant/api_type.go (1)
  • APITypeSubmodel (36-36)
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)
relay/channel/submodel/adaptor.go (11)
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 (11-23)
relay/channel/api_request.go (2)
  • SetupApiRequestHeader (25-37)
  • 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)
types/error.go (1)
  • NewAPIError (82-90)
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)
🔇 Additional comments (9)
common/api_type.go (1)

70-72: Mapping looks correct.

ChannelTypeSubmodel → APITypeSubmodel wiring aligns with the new adaptor path.

constant/channel.go (2)

53-57: ChannelType placement is OK relative to Dummy sentinel.

Inserted before ChannelTypeDummy as required by the sentinel comment. Ensure all channel-type–indexed arrays/slices account for the new index.


113-114: Base URL index alignment check.

Index 53 maps to https://llm.submodel.ai; verify no off-by-one in ChannelBaseURLs consumers.

relay/relay_adaptor.go (1)

105-107: Factory wiring LGTM.

New case returns &submodel.Adaptor{} as expected.

relay/channel/submodel/adaptor.go (5)

34-36: URL construction is correct and consistent with existing channels.

Using relaycommon.GetFullRequestURL handles special gateways and keeps routing uniform.


38-42: Header setup looks good for OpenAI-compatible JSON and SSE.

Delegating to channel.SetupApiRequestHeader plus Authorization bearer aligns with other adaptors.

Confirm Submodel requires standard "Authorization: Bearer " (no vendor-specific header). If not, I can patch this method.


44-49: Pass-through ConvertOpenAIRequest is fine for OpenAI-compatible payloads.

Minimal validation is appropriate here.


67-74: Response handling via OpenAI handlers is appropriate.

This assumes Submodel returns OpenAI-compatible shapes for both streaming and non-streaming.

If Submodel’s SSE/event format diverges, we’ll need a custom stream handler; let me know and I can add it.


76-82: Handle SubModel channel in EditTagModal.jsx
EditTagModal.jsx’s localModels switch handles case 52 (Vidu) but never handles case 53 (SubModel, backend’s ChannelTypeSubmodel = 53), so the SubModel list never appears. In the switch around line 120, add a case 53: branch that assigns the adaptor’s GetModelList() to localModels.

⛔ Skipped due to learnings
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.
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.

Comment thread constant/api_type.go
Comment on lines 34 to 36
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
)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

❓ Verification inconclusive

Do not append after sentinels; place Submodel before Moonshot/Dummy to keep iota invariants.

Both APITypeMoonshot and APITypeDummy are marked “do not add any channel after this”. Adding APITypeSubmodel after them violates that contract and risks subtle enum drift elsewhere.

Apply this diff to move Submodel before the sentinels:

-	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
+	APITypeSubmodel
+	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

Also consider freezing enum values (explicit numbers) to prevent future accidental shifts.


Move APITypeSubmodel before the sentinel constants (APITypeMoonshot/APITypeDummy). Placing it after them breaks the intended iota invariant and risks subtle enum drift.

🤖 Prompt for AI Agents
In constant/api_type.go around lines 34 to 37, the enum value APITypeSubmodel is
placed after the sentinel count constants (APITypeMoonshot/APITypeDummy), which
breaks the intended iota ordering and can cause enum drift; fix by moving
APITypeSubmodel so it appears before the sentinel constants, preserving the iota
sequence, and update or keep comments to indicate the sentinel entries are only
for count and must remain last.

Comment thread relay/channel/submodel/adaptor.go Outdated
Comment thread setting/ratio_setting/model_ratio.go Outdated
Comment thread web/src/components/table/channels/modals/EditTagModal.jsx Outdated
@danding5 danding5 changed the title Add channels submodel.ai Add Submodel channel support Sep 10, 2025
@danding5 danding5 closed this Sep 15, 2025
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