feat: add Gondola channel - #6672
Conversation
Gondola (https://gondola-ai.com) is an OpenAI-compatible marketplace for Venice AI inference. Registers it as channel type 61 following the moonshot / New API precedent. Beyond the usual registration, two entries are functional rather than cosmetic: Gondola honors stream_options include_usage, so the streamSupportedChannels entry keeps streamed requests billing on upstream-reported usage instead of estimates; and Gondola serves a native Anthropic Messages endpoint at /v1/messages, so the adaptor passes Claude-format requests through rather than converting them down to /v1/chat/completions. Rerank, embeddings, audio, Gemini and Responses report unsupported, matching what the upstream actually serves. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (1)
WalkthroughGondola is added as a backend and frontend channel. The change defines channel and API constants, registers relay routing, supports OpenAI and Claude Messages requests, enables streaming, and adds frontend metadata, validation, and icons. ChangesGondola channel integration
Estimated code review effort: 3 (Moderate) | ~20 minutes Sequence Diagram(s)sequenceDiagram
participant Client
participant GetAdaptor
participant GondolaAdaptor
participant GondolaAPI
Client->>GetAdaptor: request with APITypeGondola
GetAdaptor->>GondolaAdaptor: create adaptor
GondolaAdaptor->>GondolaAdaptor: select OpenAI or Claude route
GondolaAdaptor->>GondolaAPI: send authenticated request
GondolaAPI-->>GondolaAdaptor: response
GondolaAdaptor-->>Client: converted response
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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: 2
🧹 Nitpick comments (2)
web/src/features/channels/lib/__tests__/gondola-channel.test.ts (2)
43-69: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueSplit this test into focused behaviors.
This test combines option registration, ordering, model fetching, icon selection, key prompt, and channel configuration. Use one test for each behavior so a failure identifies the broken contract.
As per coding guidelines, “每个用例只保护一个可描述行为”.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@web/src/features/channels/lib/__tests__/gondola-channel.test.ts` around lines 43 - 69, Split the combined test around CHANNEL_TYPE_GONDOLA into focused tests, with separate cases for option registration, ordering, model fetchability, icon selection, key prompt text, and channel configuration/defaultBaseUrl. Keep each assertion group limited to one describable behavior so failures identify the specific broken contract.Source: Coding guidelines
31-40: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueAdd an explicit return type to
gondolaForm.Declare the returned form-value type. This keeps the fixture contract explicit when
CHANNEL_FORM_DEFAULT_VALUESchanges.As per coding guidelines, “参数和返回值应显式标注类型”.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@web/src/features/channels/lib/__tests__/gondola-channel.test.ts` around lines 31 - 40, Update the gondolaForm function to explicitly declare its return type using the existing channel form-value type, while preserving the current fixture fields and values.Source: Coding guidelines
🤖 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 `@web/src/assets/custom/icon-gondola.tsx`:
- Around line 27-35: Update IconGondola’s SVG in the custom icon component to be
accessible and theme-aware: add an explicit aria-hidden="true" for decorative
usage, or provide an accessible name on the IconGondola wrapper/path when it
serves as the only identifier. Replace the hard-coded stroke color in the svg
element with currentColor or a theme CSS variable so styling follows the active
theme, and keep the change localized to the IconGondola component and its svg
props.
In `@web/src/features/channels/constants.ts`:
- Line 86: Replace the Gondola display literal in
web/src/features/channels/constants.ts:86 with a semantic translation key and
resolve it with t() at the UI display boundary; apply the same pattern to the
API-key prompt at web/src/features/channels/constants.ts:409. In
web/src/features/channels/lib/channel-type-config.ts:173-174, store translation
keys for the key and model-hint labels and translate them where rendered. Update
web/src/features/channels/lib/__tests__/gondola-channel.test.ts:48-68 to assert
the translation-key semantics or rendered output under a fixed locale.
---
Nitpick comments:
In `@web/src/features/channels/lib/__tests__/gondola-channel.test.ts`:
- Around line 43-69: Split the combined test around CHANNEL_TYPE_GONDOLA into
focused tests, with separate cases for option registration, ordering, model
fetchability, icon selection, key prompt text, and channel
configuration/defaultBaseUrl. Keep each assertion group limited to one
describable behavior so failures identify the specific broken contract.
- Around line 31-40: Update the gondolaForm function to explicitly declare its
return type using the existing channel form-value type, while preserving the
current fixture fields and values.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: fe80c684-696a-4943-b6f0-e49b805ba9dd
📒 Files selected for processing (14)
common/api_type.gocommon/endpoint_type.goconstant/api_type.goconstant/channel.gorelay/channel/gondola/adaptor.gorelay/channel/gondola/constants.gorelay/common/relay_info.gorelay/relay_adaptor.goweb/src/assets/custom/icon-gondola.tsxweb/src/features/channels/constants.tsweb/src/features/channels/lib/__tests__/gondola-channel.test.tsweb/src/features/channels/lib/channel-type-config.tsweb/src/features/channels/lib/channel-utils.tsweb/src/lib/lobe-icon.tsx
| <svg | ||
| xmlns='http://www.w3.org/2000/svg' | ||
| viewBox='0 0 32 32' | ||
| width={size} | ||
| height={size} | ||
| fill='none' | ||
| stroke='#c9a96a' | ||
| strokeLinecap='round' | ||
| {...props} |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Make the custom SVG accessible and theme-aware.
IconGondola has no accessible name and no aria-hidden attribute. Mark it aria-hidden='true' when it is decorative. If it can be the only channel identifier, provide an accessible name.
stroke='#c9a96a' bypasses the theme system. Use a theme CSS variable or currentColor with theme-controlled styling.
As per coding guidelines, “装饰性图标使用 aria-hidden="true"” and “主题使用 CSS 变量与 dark:”.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@web/src/assets/custom/icon-gondola.tsx` around lines 27 - 35, Update
IconGondola’s SVG in the custom icon component to be accessible and theme-aware:
add an explicit aria-hidden="true" for decorative usage, or provide an
accessible name on the IconGondola wrapper/path when it serves as the only
identifier. Replace the hard-coded stroke color in the svg element with
currentColor or a theme CSS variable so styling follows the active theme, and
keep the change localized to the IconGondola component and its svg props.
Source: Coding guidelines
| 58: 'Advanced Custom', | ||
| 59: 'Sub2API', | ||
| 60: 'New API', | ||
| 61: 'Gondola', |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟠 Major | 🏗️ Heavy lift
Move Gondola display strings to i18n resources.
The new frontend literals bypass i18next. Store semantic translation keys and resolve them with t() where the UI displays them.
web/src/features/channels/constants.ts#L86-L86: replace the Gondola display literal with an i18n-backed label.web/src/features/channels/constants.ts#L409-L409: store a semantic API-key prompt key and translate it at the display boundary.web/src/features/channels/lib/channel-type-config.ts#L173-L174: replace the key and model hint literals with translation keys.web/src/features/channels/lib/__tests__/gondola-channel.test.ts#L48-L68: assert translation-key semantics or output under a fixed test locale.
As per coding guidelines, “面向用户的文案必须使用 i18n” and “常量中的消息和状态 label 应保存翻译键,并在展示时通过 t() 翻译”.
📍 Affects 3 files
web/src/features/channels/constants.ts#L86-L86(this comment)web/src/features/channels/constants.ts#L409-L409web/src/features/channels/lib/channel-type-config.ts#L173-L174web/src/features/channels/lib/__tests__/gondola-channel.test.ts#L48-L68
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@web/src/features/channels/constants.ts` at line 86, Replace the Gondola
display literal in web/src/features/channels/constants.ts:86 with a semantic
translation key and resolve it with t() at the UI display boundary; apply the
same pattern to the API-key prompt at
web/src/features/channels/constants.ts:409. In
web/src/features/channels/lib/channel-type-config.ts:173-174, store translation
keys for the key and model-hint labels and translate them where rendered. Update
web/src/features/channels/lib/__tests__/gondola-channel.test.ts:48-68 to assert
the translation-key semantics or rendered output under a fixed locale.
Source: Coding guidelines
…om a11y tree Addresses CodeRabbit review on QuantumNous#6672: one describable behavior per test case, explicit ChannelFormValues return type on the form fixture, and aria-hidden on the decorative channel icon. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Thanks for the review. Pushed 3186976 for three of the four:
Leaving two as-is, and happy to change either if you disagree: i18n keys for the display strings. The header of
|
Adds Gondola (https://gondola-ai.com) as a first-class channel type (
61).Gondola is an OpenAI-compatible marketplace for Venice AI inference: it routes each request to the cheapest available supplier and exposes one gateway at
https://api.gondola-ai.com. 260+ models (text, image, video), including an uncensored line. Keys look likegnd_....Why a dedicated channel type
Operators can already point a
Customchannel at Gondola, so this is partly convenience (pre-filled base URL, icon, seed model list). But two of the registrations are functional, not cosmetic:streamSupportedChannels— Gondola supportsstream_options: {"include_usage": true}and returns a final usage-only chunk. Without the entry,compatible_handler.gostrips the option and streamed requests fall back to estimated token counts instead of upstream-reported usage. Verified against the live API.EndpointTypeAnthropic— Gondola serves a native Anthropic Messages endpoint at/v1/messages(streaming and non-streaming, with usage). The adaptor passes Claude-format requests straight through rather than converting them down to/v1/chat/completionsthe way a generic OpenAI channel does. Verified against the live API.GET /v1/modelsis public and needs no auth, so the default fetch path already works and the channel is added toMODEL_FETCHABLE_TYPES.Changes
Backend, following the
moonshot/New API(#60) precedent:constant/channel.go—ChannelTypeGondola = 61, base URL, display name.constant/api_type.go—APITypeGondola, inserted beforeAPITypeDummy.common/api_type.go—ChannelType2APITypemapping.common/endpoint_type.go— OpenAI + Anthropic endpoints.relay/common/relay_info.go—streamSupportedChannelsentry.relay/channel/gondola/{adaptor.go,constants.go}— new adaptor. Chat/image delegate toopenai.Adaptor, Claude format toclaude.Adaptor; rerank/embedding/audio/gemini/responses report unsupported (Gondola serves none of them:/v1/completionsand/v1/rerank404,/v1/embeddings501).relay/relay_adaptor.go— switch branch.Frontend:
constants.ts— type label, display order,MODEL_FETCHABLE_TYPES, key-format hint.channel-type-config.ts/channel-utils.ts— config entry + icon mapping.assets/custom/icon-gondola.tsx+lib/lobe-icon.tsx— custom icon (@lobehub/iconshas no Gondola glyph), following theSub2APIpattern.ModelListis a small seed set; the catalog is a live marketplace, so operators are expected to use "Fetch Models". Nomodel_ratio.godefaults, since marketplace prices are dynamic and static entries would be misleading.Verification
Ran the CI gate set locally (
GOWORK=off, with theweb/distplaceholder):go vet ./...andgo build ./...pass for both the root module andrelaykit.make testpasses except for two failures in./service/(TestObserveChannelAffinityUsageCacheByRelayFormat_MixedModeand..._UnsupportedModeKeepsEmpty) that reproduce identically on an unmodifiedmain, so they are unrelated to this change.bun run typecheckpasses.bun testshows the same 12 failures on this branch as on unmodifiedmain(they aredescribe()-inside-test()cases that Bun does not implement on my platform); the 4 channel test files pass, including the 2 new Gondola cases.Placement of
61inCHANNEL_TYPE_DISPLAY_ORDERis next to OpenRouter (same product category); happy to move it if you would rather it sit elsewhere.Summary by CodeRabbit