diff --git a/core/control-plane/schema.ts b/core/control-plane/schema.ts index c860d99ee9..02e785b960 100644 --- a/core/control-plane/schema.ts +++ b/core/control-plane/schema.ts @@ -20,7 +20,7 @@ const modelDescriptionSchema = z.object({ "nebius", "siliconflow", "scaleway", - "watsonx" + "watsonx", ]), model: z.string(), apiKey: z.string().optional(), @@ -88,13 +88,14 @@ const embeddingsProviderSchema = z.object({ "ollama", "openai", "cohere", + "morph", "free-trial", "gemini", "ovhcloud", "nebius", "siliconflow", "scaleway", - "watsonx" + "watsonx", ]), apiBase: z.string().optional(), apiKey: z.string().optional(), @@ -116,7 +117,7 @@ const embeddingsProviderSchema = z.object({ }); const rerankerSchema = z.object({ - name: z.enum(["cohere", "voyage", "llm", "watsonx"]), + name: z.enum(["cohere", "morph", "voyage", "llm", "watsonx"]), params: z.record(z.any()).optional(), }); diff --git a/core/llm/llms/Morph.ts b/core/llm/llms/Morph.ts new file mode 100644 index 0000000000..02a7cb70a3 --- /dev/null +++ b/core/llm/llms/Morph.ts @@ -0,0 +1,35 @@ +import { Chunk, LLMOptions } from "../../index.js"; +import OpenAI from "./OpenAI.js"; + +class Morph extends OpenAI { + static providerName = "morph"; + static defaultOptions: Partial = { + apiBase: "https://api.morphllm.com/v1", + maxEmbeddingBatchSize: 96, + }; + static maxStopSequences = 5; + + async rerank(query: string, chunks: Chunk[]): Promise { + const resp = await this.fetch(new URL("rerank", this.apiBase), { + method: "POST", + headers: { + Authorization: `Bearer ${this.apiKey}`, + "Content-Type": "application/json", + }, + body: JSON.stringify({ + model: this.model, + query, + documents: chunks.map((chunk) => chunk.content), + }), + }); + + if (!resp.ok) { + throw new Error(await resp.text()); + } + + const data = (await resp.json()) as any; + const results = data.results.sort((a: any, b: any) => a.index - b.index); + return results.map((result: any) => result.relevance_score); + } +} +export default Morph; diff --git a/core/llm/llms/index.ts b/core/llm/llms/index.ts index 43e70972f5..cc6c3948ba 100644 --- a/core/llm/llms/index.ts +++ b/core/llm/llms/index.ts @@ -18,6 +18,7 @@ import BedrockImport from "./BedrockImport"; import Cerebras from "./Cerebras"; import Cloudflare from "./Cloudflare"; import Cohere from "./Cohere"; +import Morph from "./Morph" import DeepInfra from "./DeepInfra"; import Deepseek from "./Deepseek"; import Docker from "./Docker"; @@ -116,6 +117,7 @@ export const LLMClasses = [ SiliconFlow, Scaleway, Relace, + Morph, Inception, Voyage, ]; diff --git a/docs/docs/customize/model-providers/more/morph.mdx b/docs/docs/customize/model-providers/more/morph.mdx index 710fcccd56..75930debbf 100644 --- a/docs/docs/customize/model-providers/more/morph.mdx +++ b/docs/docs/customize/model-providers/more/morph.mdx @@ -9,7 +9,7 @@ Morph provides a fast apply model that helps you quickly and accurately apply co ```yaml title="config.yaml" models: - - uses: morphllm/morph-v0 + - uses: morphllm/morph-v2 with: MORPH_API_KEY: ${{ secrets.MORPH_API_KEY }} ``` @@ -21,7 +21,7 @@ Morph provides a fast apply model that helps you quickly and accurately apply co { "title": "Morph Fast Apply", "provider": "openai", - "model": "morph-v0", + "model": "morph-v2", "apiKey": "", "apiBase": "https://api.morphllm.com/v1/", "roles": ["apply", "chat"], @@ -34,3 +34,4 @@ Morph provides a fast apply model that helps you quickly and accurately apply co ``` + diff --git a/docs/docs/customize/model-roles/embeddings.mdx b/docs/docs/customize/model-roles/embeddings.mdx index ce5357792b..ba9e3c7d77 100644 --- a/docs/docs/customize/model-roles/embeddings.mdx +++ b/docs/docs/customize/model-roles/embeddings.mdx @@ -152,3 +152,8 @@ See [here](../model-providers/more/watsonx.mdx#embeddings-model) for instruction ### LMStudio See [here](../model-providers/more/lmstudio.mdx#embeddings-model) for instructions on how to use LMStudio for embeddings. + +### Morph + +See [here](../model-providers/more/morph.mdx#embeddings-model) for instructions on how to use Morph for embeddings. + diff --git a/docs/docs/customize/model-roles/reranking.mdx b/docs/docs/customize/model-roles/reranking.mdx index c16dab7a09..760efdff9d 100644 --- a/docs/docs/customize/model-roles/reranking.mdx +++ b/docs/docs/customize/model-roles/reranking.mdx @@ -85,6 +85,8 @@ See Cohere's documentation for rerankers [here](https://docs.cohere.com/docs/rer + + ### LLM If you only have access to a single LLM, then you can use it as a reranker. This is discouraged unless truly necessary, because it will be much more expensive and still less accurate than any of the above models trained specifically for the task. Note that this will not work if you are using a local model, for example with Ollama, because too many parallel requests need to be made. @@ -154,3 +156,7 @@ The `"modelTitle"` field must match one of the models in your "models" array in ``` + +### Morph + +See the [Morph guide](../model-providers/more/morph.mdx) for details on how to use MorphLLM for reranking. \ No newline at end of file diff --git a/extensions/vscode/config_schema.json b/extensions/vscode/config_schema.json index 993198fe0e..b32fce87ef 100644 --- a/extensions/vscode/config_schema.json +++ b/extensions/vscode/config_schema.json @@ -900,6 +900,23 @@ } } }, + { + "if": { + "properties": { + "provider": { + "enum": ["morph"] + } + }, + "required": ["provider"] + }, + "then": { + "properties": { + "model": { + "enum": ["morph-embedding-v2", "morph-rerank-v2", "morph-v2"] + } + } + } + }, { "if": { "properties": { @@ -1515,7 +1532,11 @@ "then": { "properties": { "model": { - "enum": ["llama3.1-8b", "llama3.1-70b", "llama-4-scout-17b-16e-instruct"] + "enum": [ + "llama3.1-8b", + "llama3.1-70b", + "llama-4-scout-17b-16e-instruct" + ] } } } diff --git a/gui/public/logos/morph.png b/gui/public/logos/morph.png new file mode 100644 index 0000000000..8c9af5354d Binary files /dev/null and b/gui/public/logos/morph.png differ diff --git a/gui/src/pages/AddNewModel/configs/providers.ts b/gui/src/pages/AddNewModel/configs/providers.ts index f56a6b2101..a52bdf299c 100644 --- a/gui/src/pages/AddNewModel/configs/providers.ts +++ b/gui/src/pages/AddNewModel/configs/providers.ts @@ -353,6 +353,28 @@ Select the \`GPT-4o\` model below to complete your provider configuration, but n packages: [models.commandR, models.commandRPlus], apiKeyUrl: "https://docs.cohere.com/v2/docs/rate-limits", }, + morph: { + title: "Morph", + provider: "morph", + refPage: "morph", + description: "Fast Apply, Embed, and Rerank models", + icon: "morph.png", + tags: [ModelProviderTags.RequiresApiKey], + longDescription: + "To use Morph, visit the [Morph dashboard](https://morphllm.com/dashboard) to create an API key.", + collectInputFor: [ + { + inputType: "text", + key: "apiKey", + label: "API Key", + placeholder: "Enter your Morph API key", + required: true, + }, + ...completionParamsInputsConfigs, + ], + packages: [models.morphFastApply, models.morphEmbed, models.morphRerank], + apiKeyUrl: "https://morphllm.com/dashboard", + }, groq: { title: "Groq", provider: "groq", @@ -797,7 +819,7 @@ To get started, [register](https://dataplatform.cloud.ibm.com/registration/stepo }, ...completionParamsInputsConfigs, ], - packages:[ + packages: [ models.llama4Scout, models.llama4Maverick, models.llama3370BInstruct, @@ -808,7 +830,7 @@ To get started, [register](https://dataplatform.cloud.ibm.com/registration/stepo models.qwq32B, models.deepseekR1DistillLlama70B, models.deepseekR1, - models.deepseekV3 + models.deepseekV3, ], apiKeyUrl: "https://cloud.sambanova.ai/apis", }, @@ -1011,9 +1033,7 @@ To get started, [register](https://dataplatform.cloud.ibm.com/registration/stepo required: true, }, ], - packages: [ - {...models.AUTODETECT} - ], - apiKeyUrl: "https://venice.ai/chat" - } + packages: [{ ...models.AUTODETECT }], + apiKeyUrl: "https://venice.ai/chat", + }, }; diff --git a/packages/config-types/src/index.ts b/packages/config-types/src/index.ts index dfeb7b0e51..83013f67c6 100644 --- a/packages/config-types/src/index.ts +++ b/packages/config-types/src/index.ts @@ -46,6 +46,7 @@ export const modelDescriptionSchema = z.object({ "openai", "anthropic", "cohere", + "morph", "ollama", "huggingface-tgi", "huggingface-inference-api", @@ -60,7 +61,7 @@ export const modelDescriptionSchema = z.object({ "continue-proxy", "nebius", "scaleway", - "watsonx" + "watsonx", ]), model: z.string(), apiKey: z.string().optional(), @@ -109,13 +110,14 @@ export const embeddingsProviderSchema = z.object({ "ollama", "openai", "cohere", + "morph", "free-trial", "gemini", "ovhcloud", "continue-proxy", "nebius", "scaleway", - "watsonx" + "watsonx", ]), apiBase: z.string().optional(), apiKey: z.string().optional(), @@ -178,7 +180,14 @@ export const contextProviderSchema = z.object({ export type ContextProvider = z.infer; export const rerankerSchema = z.object({ - name: z.enum(["cohere", "voyage", "watsonx", "llm", "continue-proxy"]), + name: z.enum([ + "cohere", + "morph", + "voyage", + "watsonx", + "llm", + "continue-proxy", + ]), params: z.record(z.any()).optional(), }); export type Reranker = z.infer; diff --git a/packages/llm-info/src/index.ts b/packages/llm-info/src/index.ts index fe71f419dd..d7f8c95a8b 100644 --- a/packages/llm-info/src/index.ts +++ b/packages/llm-info/src/index.ts @@ -2,6 +2,7 @@ import { Anthropic } from "./providers/anthropic.js"; import { Azure } from "./providers/azure.js"; import { Bedrock } from "./providers/bedrock.js"; import { Cohere } from "./providers/cohere.js"; +import { Morph } from "./providers/morph.js"; import { Gemini } from "./providers/gemini.js"; import { Mistral } from "./providers/mistral.js"; import { Ollama } from "./providers/ollama.js"; @@ -22,6 +23,7 @@ export const allModelProviders: ModelProvider[] = [ Vllm, Bedrock, Cohere, + Morph, xAI, ]; diff --git a/packages/llm-info/src/providers/morph.ts b/packages/llm-info/src/providers/morph.ts new file mode 100644 index 0000000000..26f28009f4 --- /dev/null +++ b/packages/llm-info/src/providers/morph.ts @@ -0,0 +1,27 @@ +import { ModelProvider } from "../types.js"; + +export const Morph: ModelProvider = { + models: [ + { + model: "morph-rerank-v2", + displayName: "Morph Rerank v2", + // contextLength: 128000, + // maxCompletionTokens: 4000, + // recommendedFor: ["rerank"], + }, + { + model: "morph-v2", + displayName: "Morph Fast Apply v2", + // contextLength: 128000, + // maxCompletionTokens: 4000, + }, + { + model: "morph-embedding-v2", + displayName: "Morph Embedding v2", + // recommendedFor: ["embed"], + // contextLength: 512, + }, + ], + id: "morph", + displayName: "Morph", +}; diff --git a/packages/openai-adapters/README.md b/packages/openai-adapters/README.md index 1f8c849ad1..f873f068f6 100644 --- a/packages/openai-adapters/README.md +++ b/packages/openai-adapters/README.md @@ -21,7 +21,7 @@ They are concerned with: - Cache behavior - max stop words - use legacy completions endpoint? -- anything else that couldn't possibly be guess by the client since it won't know the endpoint behind the proxy +- anything else that couldn't possibly be guess by the client ssince it won't know the endpoint behind the proxy ## Supported APIs @@ -33,6 +33,7 @@ They are concerned with: - [x] Cerebras - [ ] Cloudflare - [x] Cohere +- [x] Morph - [x] DeepInfra - [x] Deepseek - [ ] Flowise diff --git a/packages/openai-adapters/src/test/main.test.ts b/packages/openai-adapters/src/test/main.test.ts index 6d838a48cb..2bbef79afc 100644 --- a/packages/openai-adapters/src/test/main.test.ts +++ b/packages/openai-adapters/src/test/main.test.ts @@ -85,6 +85,12 @@ const TESTS: Omit[] = [ // roles: ["embed"], // }, // { + // provider: "morph", + // model: "morph-embedding-v2", + // apiKey: process.env.MORPH_API_KEY!, + // roles: ["embed"], + // }, + // { // provider: "gemini", // model: "models/text-embedding-004", // apiKey: process.env.GEMINI_API_KEY!, @@ -102,6 +108,12 @@ const TESTS: Omit[] = [ // apiKey: process.env.COHERE_API_KEY!, // roles: ["rerank"], // }, + // { + // provider: "morph", + // model: "morph-rerank-v2", + // apiKey: process.env.MORPH_API_KEY!, + // roles: ["rerank"], + // }, ]; TESTS.forEach((config) => {