Skip to content

feat(moonshot): implement provider with model picker, API fetching, streaming, and model metadata#857

Open
grizmin wants to merge 4 commits into
Zoo-Code-Org:mainfrom
grizmin:fix/moonshot-provider-fixes
Open

feat(moonshot): implement provider with model picker, API fetching, streaming, and model metadata#857
grizmin wants to merge 4 commits into
Zoo-Code-Org:mainfrom
grizmin:fix/moonshot-provider-fixes

Conversation

@grizmin

@grizmin grizmin commented Jul 7, 2026

Copy link
Copy Markdown

Summary

Implement the Moonshot provider from scratch, enabling full model selection, API-based model fetching, and working streaming responses.

What was missing

The previous Moonshot implementation was non-functional:

  • No model picker — users could not select which Moonshot model to use
  • No auto-updated model list — models were never fetched from the Moonshot API
  • Custom model ID did not work — entering a custom model ID produced empty streams with no output
  • Wrong handler base classMoonshotHandler extended OpenAICompatibleHandler (Vercel AI SDK) which has compatibility issues with the Moonshot API

Changes

Handler refactor (src/api/providers/moonshot.ts)

  • Switched MoonshotHandler from OpenAICompatibleHandler (Vercel AI SDK) to OpenAiHandler (OpenAI Node SDK)
  • This is the same handler used by the generic "OpenAI Compatible" provider and by DeepSeek/Mimo
  • Moonshot-specific overrides kept: getModel(), processUsageMetrics(), addMaxTokensIfNeeded()

Model fetching (src/api/providers/fetchers/moonshot.ts)

  • New getMoonshotModels() fetcher that calls GET /v1/models
  • Enriches API-returned model IDs with metadata from static model map (pricing, context window, capabilities)
  • Provides fallback defaults for unknown models

Model picker UI (webview-ui/src/components/settings/providers/Moonshot.tsx)

  • New settings component with API key input, base URL selector, and model dropdown
  • "Refresh Models" button to re-fetch the model list from the API
  • Shows only API-fetched models (not merged with static list)

Model metadata (packages/types/src/providers/moonshot.ts)

  • Added kimi-k2.7-code, kimi-k2.7-code-highspeed, kimi-k2.6 with correct pricing from official docs
  • Fixed kimi-k2.5 to correctly mark supportsImages: true

Infrastructure

  • Added moonshot to dynamicProviders list (enables model fetching pipeline)
  • Added Moonshot to model caching (modelCache.ts)
  • Added webview message handler for requestRouterModels

Testing

  • All 6660+ backend tests pass
  • All 1432+ webview-ui tests pass
  • Lint and type-check pass
  • Manually verified with F5 Extension Development Host using kimi-k2.7-code

Summary by CodeRabbit

  • New Features
    • Added Moonshot as a supported dynamic provider, including router model refresh and improved model selection via the router model picker.
    • Updated Moonshot’s catalog with new Kimi K2 variants and adjusted capabilities/descriptions.
  • Bug Fixes
    • Improved Moonshot handling for unknown models to avoid incorrect pricing/token limits.
    • Refined Moonshot streaming, usage reporting, and tool-call event behavior for more accurate updates.
  • Tests
    • Expanded Moonshot coverage for model fetching, caching, router model aggregation, and streaming/tool-call scenarios.

…reaming

- Fix duplicate ModelPicker by adding moonshot to PROVIDERS_WITH_CUSTOM_MODEL_UI
- Fix HTTP 404 on Refresh Models by preserving /v1 in fetcher URL
- Fix empty model list (consequence of 404 fix)
- Fix 'No output generated' error by switching MoonshotHandler from
  OpenAICompatibleHandler (Vercel AI SDK) to OpenAiHandler (OpenAI Node SDK)
  which is what Moonshot's own API docs recommend
- Add dedicated Moonshot fetcher with proper model ID prefixing
- Update tests to match new handler implementation

All 6,660 backend and 1,432 webview-ui tests pass.
@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: c5af3ff1-233b-410c-aace-e389a762ccce

📥 Commits

Reviewing files that changed from the base of the PR and between b54ddbf and 686ae63.

📒 Files selected for processing (2)
  • src/api/providers/fetchers/__tests__/moonshot.spec.ts
  • src/api/providers/fetchers/moonshot.ts
💤 Files with no reviewable changes (1)
  • src/api/providers/fetchers/moonshot.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/api/providers/fetchers/tests/moonshot.spec.ts

📝 Walkthrough

Walkthrough

This PR adds Moonshot as a dynamic provider, including model typing, model fetching and caching, handler behavior updates, router-model aggregation, and settings UI support for refreshing and selecting fetched models.

Changes

Moonshot dynamic provider integration

Layer / File(s) Summary
Provider types and model catalog
packages/types/src/provider-settings.ts, src/shared/api.ts, packages/types/src/providers/moonshot.ts
Adds Moonshot to dynamic provider typing and provider extras, and updates the Moonshot model catalog with new Kimi variants and revised capabilities.
Moonshot model fetcher and cache
src/api/providers/fetchers/moonshot.ts, src/api/providers/fetchers/__tests__/moonshot.spec.ts, src/api/providers/fetchers/modelCache.ts
Adds getMoonshotModels for /v1/models fetching and model normalization, tests the fetcher, and routes Moonshot through model caching and provider dispatch.
MoonshotHandler refactor
src/api/providers/moonshot.ts, src/api/providers/__tests__/moonshot.spec.ts
Switches Moonshot to OpenAiHandler, updates model selection, usage parsing, and max-token behavior, and rewrites the tests around the new client stream/request path.
Router-model aggregation
src/core/webview/webviewMessageHandler.ts, src/core/webview/__tests__/*, webview-ui/src/utils/__tests__/validate.spec.ts
Adds Moonshot to router-model aggregation and related expectations.
Moonshot settings UI
webview-ui/src/components/settings/providers/Moonshot.tsx, webview-ui/src/components/settings/utils/providerModelConfig.ts, webview-ui/src/components/ui/hooks/useSelectedModel.ts
Wires the settings UI to refresh, pick, and render fetched Moonshot models.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related PRs

  • Zoo-Code-Org/Zoo-Code#647: Both changes extend shared provider model fetching and cache-key behavior for URL/key-scoped providers.

Suggested reviewers: taltas, JamesRobert20, navedmerchant, hannesrudolph, edelauna

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main Moonshot provider implementation, including model picker, API fetching, streaming, and metadata support.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@codecov

codecov Bot commented Jul 7, 2026

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 2

🧹 Nitpick comments (2)
webview-ui/src/components/settings/providers/Moonshot.tsx (1)

1-172: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy lift

Missing local Vitest coverage for new stateful component logic.

This component adds a non-trivial state machine (refresh status, message listener, error/success reconciliation, ModelPicker wiring) with no accompanying test file in this PR.

Do you want me to draft a Moonshot.spec.tsx covering the refresh flow, the message-listener success/error paths, and the missing-API-key guard?

As per path instructions, "Prefer local webview-ui tests for React/webview behavior such as component rendering, local state, hooks, form dirty-state, validation, or prop wiring. Add or update Vitest coverage under webview-ui/src/**/__tests__."

🤖 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 `@webview-ui/src/components/settings/providers/Moonshot.tsx` around lines 1 -
172, Add local Vitest coverage for Moonshot’s new stateful behavior by creating
a test near Moonshot that exercises the refresh flow, the window message
listener paths, and the missing API key guard. Cover the `handleRefreshModels`
logic, the `useEffect` message handling for both
`singleRouterModelFetchResponse` error and `routerModels` success
reconciliation, and verify the `ModelPicker`/button wiring in `Moonshot`. Ensure
the tests validate that `refreshStatus`, `refreshError`, and the
disabled/loading states change as expected.

Source: Path instructions

src/core/webview/webviewMessageHandler.ts (1)

1139-1153: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider extracting the repeated credential-resolution/flush/candidate pattern.

This block duplicates the exact same shape used for poe and deepseek just above it (resolve from message.values vs apiConfiguration, conditionally flush on explicit override, push a candidate). A small helper would reduce copy/paste risk as more single-apiKey providers are added.

♻️ Example helper extraction
+function resolveApiKeyGatedCandidate(
+	key: RouterName,
+	apiKeyField: string,
+	baseUrlField: string,
+	message: WebviewMessage,
+	apiConfiguration: ProviderSettings,
+) {
+	const apiKey = (message?.values as any)?.[apiKeyField] ?? (apiConfiguration as any)[apiKeyField]
+	const baseUrl = (message?.values as any)?.[baseUrlField] ?? (apiConfiguration as any)[baseUrlField]
+	return { apiKey, baseUrl, hasExplicitOverride: !!(message?.values as any)?.[apiKeyField] || !!(message?.values as any)?.[baseUrlField] }
+}
🤖 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/core/webview/webviewMessageHandler.ts` around lines 1139 - 1153, The
Moonshot handling in webviewMessageHandler repeats the same credential
resolution, optional flush, and candidate push pattern already used for poe and
deepseek. Extract that shared logic into a small helper so the provider-specific
code only supplies the provider name and credential keys, while the helper
handles resolving from message.values vs apiConfiguration, calling flushModels
on explicit overrides, and adding the candidate. Keep the Moonshot call site
aligned with the existing provider blocks to reduce copy/paste drift as more
single-apiKey providers are added.
🤖 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/api/providers/fetchers/moonshot.ts`:
- Around line 66-87: The fallback in moonshot model fetching is assigning
guessed pricing for unknown IDs, which conflicts with
`MoonshotHandler.resolveModelInfo` treating those same models as unpriced.
Update the unknown-model branch in `src/api/providers/fetchers/moonshot.ts` so
it matches `resolveModelInfo`’s behavior for IDs not in `moonshotModels`,
leaving pricing fields unset/undefined instead of hardcoding values. Keep the
known-model path unchanged and ensure the fallback description still identifies
the model.

In `@webview-ui/src/components/settings/providers/Moonshot.tsx`:
- Around line 35-59: The Moonshot message handler in useEffect is setting error
state too broadly, which can surface errors from unrelated fetches. Update the
singleRouterModelFetchResponse branch to mirror the routerModels success guard
by only calling setRefreshStatus("error") and setRefreshError when refreshStatus
is "loading" and the message is for the moonshot provider. Keep the existing
moonshot providerName check in handleMessage so only refresh-triggered failures
affect the UI.

---

Nitpick comments:
In `@src/core/webview/webviewMessageHandler.ts`:
- Around line 1139-1153: The Moonshot handling in webviewMessageHandler repeats
the same credential resolution, optional flush, and candidate push pattern
already used for poe and deepseek. Extract that shared logic into a small helper
so the provider-specific code only supplies the provider name and credential
keys, while the helper handles resolving from message.values vs
apiConfiguration, calling flushModels on explicit overrides, and adding the
candidate. Keep the Moonshot call site aligned with the existing provider blocks
to reduce copy/paste drift as more single-apiKey providers are added.

In `@webview-ui/src/components/settings/providers/Moonshot.tsx`:
- Around line 1-172: Add local Vitest coverage for Moonshot’s new stateful
behavior by creating a test near Moonshot that exercises the refresh flow, the
window message listener paths, and the missing API key guard. Cover the
`handleRefreshModels` logic, the `useEffect` message handling for both
`singleRouterModelFetchResponse` error and `routerModels` success
reconciliation, and verify the `ModelPicker`/button wiring in `Moonshot`. Ensure
the tests validate that `refreshStatus`, `refreshError`, and the
disabled/loading states change as expected.
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 040c25c1-8e98-4429-ac98-112116194e26

📥 Commits

Reviewing files that changed from the base of the PR and between e2cdd3c and 204f81f.

📒 Files selected for processing (15)
  • packages/types/src/provider-settings.ts
  • src/api/providers/__tests__/moonshot.spec.ts
  • src/api/providers/fetchers/__tests__/moonshot.spec.ts
  • src/api/providers/fetchers/modelCache.ts
  • src/api/providers/fetchers/moonshot.ts
  • src/api/providers/moonshot.ts
  • src/core/webview/__tests__/ClineProvider.spec.ts
  • src/core/webview/__tests__/webviewMessageHandler.routerModels.spec.ts
  • src/core/webview/__tests__/webviewMessageHandler.spec.ts
  • src/core/webview/webviewMessageHandler.ts
  • src/shared/api.ts
  • webview-ui/src/components/settings/providers/Moonshot.tsx
  • webview-ui/src/components/settings/utils/providerModelConfig.ts
  • webview-ui/src/components/ui/hooks/useSelectedModel.ts
  • webview-ui/src/utils/__tests__/validate.spec.ts

Comment thread src/api/providers/fetchers/moonshot.ts
Comment thread webview-ui/src/components/settings/providers/Moonshot.tsx
… docs

Add kimi-k2.7-code, kimi-k2.7-code-highspeed, and kimi-k2.6 to static
models map with accurate pricing from Moonshot documentation.

Also fix kimi-k2.5 to correctly mark supportsImages: true.
@grizmin grizmin changed the title fix(moonshot): fix provider issues with model picker, refresh, and streaming feat(moonshot): implement provider with model picker, API fetching, streaming, and model metadata Jul 7, 2026
@github-actions github-actions Bot added the awaiting-review PR changes are ready and waiting for maintainer re-review label Jul 7, 2026
grizmin and others added 2 commits July 7, 2026 20:56
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

awaiting-review PR changes are ready and waiting for maintainer re-review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant