Add Morpheus provider with dynamic model discovery#1488
Add Morpheus provider with dynamic model discovery#1488betterbrand wants to merge 5 commits intogenlayerlabs:mainfrom
Conversation
Add Morpheus decentralized AI inference as a provider option. Models are fetched in real time from the Morpheus marketplace API via a schema-driven x-models-url mechanism, with graceful fallback to manual text input if the API is unreachable.
📝 WalkthroughWalkthroughAdded new providers (morpheus, ionet, openrouter) across env, backend and frontend schemas, and updated the provider modal to apply provider-specific defaults and asynchronously fetch/display provider models with loading/error handling. Changes
Sequence DiagramsequenceDiagram
participant User
participant ProviderModal
participant SchemaProcessor
participant MorpheusAPI
participant UIState
User->>ProviderModal: select provider (e.g., "morpheus")
ProviderModal->>SchemaProcessor: evaluate provider schema
SchemaProcessor-->>ProviderModal: return x-models-url & x-plugin-config-defaults
ProviderModal->>UIState: set isLoadingModels = true
ProviderModal->>MorpheusAPI: fetch models from x-models-url
MorpheusAPI-->>ProviderModal: models list / error
ProviderModal->>ProviderModal: filter LLMs, apply plugin_config_defaults
ProviderModal->>UIState: populate modelOptions, set default model, set isLoadingModels = false / set modelFetchError
UIState-->>User: display models or error
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~22 minutes Suggested labels
Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
📝 Coding Plan
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 Tip CodeRabbit can suggest fixes for GitHub Check annotations.Configure the |
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)
backend/node/create_nodes/providers_schema.json (1)
77-83:⚠️ Potential issue | 🟡 MinorDuplicate model entry in google enum.
"gemini-2.5-flash-lite"appears twice in the enum (lines 79 and 82). This won't break functionality but is likely unintended.🔧 Proposed fix
"model": { "enum": [ "gemini-2.0-flash-lite-001", "gemini-2.5-flash-lite", "gemini-2.5-flash", - "gemini-3.0-flash", - "gemini-2.5-flash-lite" + "gemini-3.0-flash" ] }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@backend/node/create_nodes/providers_schema.json` around lines 77 - 83, Remove the duplicate enum entry "gemini-2.5-flash-lite" from the providers_schema.json models enum so each model appears only once; locate the "enum" array that lists model names (contains "gemini-2.0-flash-lite", "gemini-2.5-flash-lite", etc.) and delete the repeated "gemini-2.5-flash-lite" entry to ensure unique values.
🧹 Nitpick comments (1)
frontend/src/components/Simulator/ProviderModal.vue (1)
206-228: Consider adding timeout and request cancellation for reliability.The dynamic model fetch lacks a timeout and cancellation mechanism. If the Morpheus API is slow or unresponsive, the request could hang indefinitely. Additionally, if the user switches providers while a fetch is in progress, stale results could populate the dropdown.
♻️ Suggested improvement with AbortController and timeout
+let modelFetchController: AbortController | null = null; + const fetchDynamicModels = async (modelsUrl: string) => { + // Cancel any in-flight request + if (modelFetchController) { + modelFetchController.abort(); + } + modelFetchController = new AbortController(); + isLoadingModels.value = true; modelFetchError.value = ''; try { - const response = await fetch(modelsUrl); + const timeoutId = setTimeout(() => modelFetchController?.abort(), 10000); + const response = await fetch(modelsUrl, { signal: modelFetchController.signal }); + clearTimeout(timeoutId); if (!response.ok) throw new Error(`HTTP ${response.status}`); const data = await response.json(); // ... rest of the logic } catch (err) { + if ((err as Error).name === 'AbortError') return; console.error('Failed to fetch models:', err); modelFetchError.value = 'Could not fetch available models. You can type a model name manually.'; } finally { isLoadingModels.value = false; + modelFetchController = null; } };🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@frontend/src/components/Simulator/ProviderModal.vue` around lines 206 - 228, The fetchDynamicModels function should be made cancellable and time-limited: create an AbortController for each call (store the controller in a scoped variable so subsequent calls can abort the previous request), pass controller.signal to fetch(modelsUrl), and implement a timeout (e.g., setTimeout that calls controller.abort() after N ms) to ensure the request doesn't hang; handle AbortError in the catch to avoid showing the generic modelFetchError for intentional cancellations, and ensure the timeout is cleared and isLoadingModels.value is reset in the finally block; update references to modelOptions.value, newProviderData.model and modelFetchError.value exactly where fetchDynamicModels sets them so stale responses cannot overwrite UI state after an abort.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@frontend/src/assets/schemas/providers_schema.json`:
- Around line 14-16: The frontend providers schema is missing the "openrouter"
provider present in the backend examples; either add "openrouter" to the
providers list in frontend/src/assets/schemas/providers_schema.json and mirror
the necessary allOf configuration used in the backend (match the backend's
provider example and schema fields for "openrouter"), or add a clear JSON
comment/docstring in that same schema file explaining that "openrouter" is
backend-only and intentionally omitted; locate the providers array near the
entries "google" and "morpheus" and update it accordingly and ensure any
referenced schema definitions used by the backend's "openrouter" example are
also added or referenced.
---
Outside diff comments:
In `@backend/node/create_nodes/providers_schema.json`:
- Around line 77-83: Remove the duplicate enum entry "gemini-2.5-flash-lite"
from the providers_schema.json models enum so each model appears only once;
locate the "enum" array that lists model names (contains
"gemini-2.0-flash-lite", "gemini-2.5-flash-lite", etc.) and delete the repeated
"gemini-2.5-flash-lite" entry to ensure unique values.
---
Nitpick comments:
In `@frontend/src/components/Simulator/ProviderModal.vue`:
- Around line 206-228: The fetchDynamicModels function should be made
cancellable and time-limited: create an AbortController for each call (store the
controller in a scoped variable so subsequent calls can abort the previous
request), pass controller.signal to fetch(modelsUrl), and implement a timeout
(e.g., setTimeout that calls controller.abort() after N ms) to ensure the
request doesn't hang; handle AbortError in the catch to avoid showing the
generic modelFetchError for intentional cancellations, and ensure the timeout is
cleared and isLoadingModels.value is reset in the finally block; update
references to modelOptions.value, newProviderData.model and
modelFetchError.value exactly where fetchDynamicModels sets them so stale
responses cannot overwrite UI state after an abort.
ℹ️ Review info
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
.env.examplebackend/node/create_nodes/providers_schema.jsonfrontend/src/assets/schemas/providers_schema.jsonfrontend/src/components/Simulator/ProviderModal.vue
The backend schema included openrouter and ionet provider blocks (added in genlayerlabs#1427/genlayerlabs#1429) but these were never mirrored to the frontend. Sync the examples array and allOf conditional blocks so both schemas list the same set of providers.
|
Good catch by CodeRabbit on the openrouter/ionet frontend schema drift. T Addressed in 739bf9a where both schemas now list the same 9 providers with matching allOf blocks. Happy to help as always from the Morpheus community |
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
|
@cristiam86 @kstroobants — this is ready for review when you get a chance. Two commits:
|
Match the underscore convention used by newer providers (ANTHROPIC_API_KEY, XAI_API_KEY, GEMINI_API_KEY).
|
Third commit renames the env var from |
|
@cristiam86 @kstroobants — the changes you requested should be reflected. Thanks! |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
backend/node/create_nodes/providers_schema.json (1)
221-239: Add a frontend/backend schema parity check to prevent future drift.This new Morpheus conditional now exists in both schemas; adding a CI guard (snapshot/diff of provider condition blocks) would prevent recurrence of schema drift regressions.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@backend/node/create_nodes/providers_schema.json` around lines 221 - 239, Add a CI parity check that snapshots and diffs provider conditional blocks between the frontend and backend schemas and fails the build on any mismatch; implement the check to locate conditional objects where if.properties.provider.const === "morpheus" (and likewise for other providers), and compare the entire then block (e.g., x-models-url, x-plugin-config-defaults.api_key_env_var, x-plugin-config-defaults.api_url, and properties.plugin.const === "openai-compatible") across repos, emitting a clear diff on failure; wire this into existing CI test runner as a unit/integration test that loads both schema JSONs, extracts provider condition blocks, and asserts deep-equality or updates a committed snapshot.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@backend/node/create_nodes/providers_schema.json`:
- Around line 221-239: Add a CI parity check that snapshots and diffs provider
conditional blocks between the frontend and backend schemas and fails the build
on any mismatch; implement the check to locate conditional objects where
if.properties.provider.const === "morpheus" (and likewise for other providers),
and compare the entire then block (e.g., x-models-url,
x-plugin-config-defaults.api_key_env_var, x-plugin-config-defaults.api_url, and
properties.plugin.const === "openai-compatible") across repos, emitting a clear
diff on failure; wire this into existing CI test runner as a unit/integration
test that loads both schema JSONs, extracts provider condition blocks, and
asserts deep-equality or updates a committed snapshot.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 5b71cff1-91a4-4624-adcb-5609cb6f5dba
📒 Files selected for processing (2)
.env.examplebackend/node/create_nodes/providers_schema.json
With the integration of the Morpheus Marketplace, Intelligent Contracts gain censorship-resistant inference with no single point of failure, and the available model catalog updates automatically as new providers join the marketplace. This PR adds Morpheus as a provider in GenLayer Studio with fully dynamic model discovery. When a user selects Morpheus, Studio fetches the live model catalog from the Morpheus marketplace in real time, so validators always see whatever models are currently available across the decentralized network.
Summary
x-models-urlextension for dynamic model fetchingProviderModal.vueto detectx-models-urland populate the model dropdown from the Morpheus API at runtimeMORPHEUSAPIKEY, API URL) viax-plugin-config-defaultsschema extensionMORPHEUSAPIKEYto.env.exampleHow it works
The integration uses a schema-driven approach: a custom
x-models-urlJSON Schema property tells the frontend where to fetch models dynamically. This is generic — any future provider can opt in by addingx-models-urlto their schema block. If the API is unreachable, the UI gracefully degrades to a free-text input.Files changed
frontend/src/assets/schemas/providers_schema.json— add Morpheus conditional block withx-models-urlbackend/node/create_nodes/providers_schema.json— same schema changes (backend mirror)frontend/src/components/Simulator/ProviderModal.vue— dynamic model fetching, loading states, provider-specific defaults.env.example— addMORPHEUSAPIKEYplaceholderTest plan
cd frontend && npm run test— all 113 unit tests passapi_key_env_varpre-fills asMORPHEUSAPIKEY,api_urlashttps://api.mor.org/api/v1api.mor.orgreturns proper headers for browser requestsSummary by CodeRabbit
New Features
Chores