-
Notifications
You must be signed in to change notification settings - Fork 5.5k
New components openrouter #16286
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
New components openrouter #16286
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| import openrouter from "../../openrouter.app.mjs"; | ||
|
|
||
| export default { | ||
| key: "openrouter-retrieve-available-models", | ||
| name: "Retrieve Available Models", | ||
| version: "0.0.1", | ||
| description: "Returns a list of models available through the API. [See the documentation](https://openrouter.ai/docs/api-reference/list-available-models)", | ||
| type: "action", | ||
| props: { | ||
| openrouter, | ||
| }, | ||
| async run({ $ }) { | ||
| const response = await this.openrouter.listModels({ | ||
| $, | ||
| }); | ||
|
|
||
| $.export("$summary", `Successfully retrieved ${response.data.length} available model(s)!`); | ||
| return response; | ||
| }, | ||
| }; |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,188 @@ | ||||||
| import { ConfigurationError } from "@pipedream/platform"; | ||||||
| import { parseObject } from "../../common/utils.mjs"; | ||||||
| import openrouter from "../../openrouter.app.mjs"; | ||||||
|
|
||||||
| export default { | ||||||
| key: "openrouter-send-chat-completion-request", | ||||||
| name: "Send Chat Completion Request", | ||||||
| version: "0.0.1", | ||||||
| description: "Send a chat completion request to a selected model. [See the documentation](https://openrouter.ai/docs/api-reference/chat-completion)", | ||||||
| type: "action", | ||||||
| props: { | ||||||
| openrouter, | ||||||
| model: { | ||||||
| propDefinition: [ | ||||||
| openrouter, | ||||||
| "model", | ||||||
| ], | ||||||
| }, | ||||||
| messages: { | ||||||
| type: "string[]", | ||||||
| label: "Messages", | ||||||
| description: "A list of objects containing role and content. E.g. **{\"role\":\"user\", \"content\":\"text\"}**. [See the documentation](https://openrouter.ai/docs/api-reference/chat-completion#request.body.messages) for further details.", | ||||||
| }, | ||||||
| maxTokens: { | ||||||
| propDefinition: [ | ||||||
| openrouter, | ||||||
| "maxTokens", | ||||||
| ], | ||||||
| }, | ||||||
| temperature: { | ||||||
| propDefinition: [ | ||||||
| openrouter, | ||||||
| "temperature", | ||||||
| ], | ||||||
| }, | ||||||
| seed: { | ||||||
| propDefinition: [ | ||||||
| openrouter, | ||||||
| "seed", | ||||||
| ], | ||||||
| }, | ||||||
| topP: { | ||||||
| propDefinition: [ | ||||||
| openrouter, | ||||||
| "topP", | ||||||
| ], | ||||||
| }, | ||||||
| topK: { | ||||||
| propDefinition: [ | ||||||
| openrouter, | ||||||
| "topK", | ||||||
| ], | ||||||
| }, | ||||||
| frequencyPenalty: { | ||||||
| propDefinition: [ | ||||||
| openrouter, | ||||||
| "frequencyPenalty", | ||||||
| ], | ||||||
| }, | ||||||
| presencePenalty: { | ||||||
| propDefinition: [ | ||||||
| openrouter, | ||||||
| "presencePenalty", | ||||||
| ], | ||||||
| }, | ||||||
| repetitionPenalty: { | ||||||
| propDefinition: [ | ||||||
| openrouter, | ||||||
| "repetitionPenalty", | ||||||
| ], | ||||||
| }, | ||||||
| logitBias: { | ||||||
| propDefinition: [ | ||||||
| openrouter, | ||||||
| "logitBias", | ||||||
| ], | ||||||
| }, | ||||||
| togLogprobs: { | ||||||
| propDefinition: [ | ||||||
| openrouter, | ||||||
| "togLogprobs", | ||||||
| ], | ||||||
| }, | ||||||
| minP: { | ||||||
| propDefinition: [ | ||||||
| openrouter, | ||||||
| "minP", | ||||||
| ], | ||||||
| }, | ||||||
| topA: { | ||||||
| propDefinition: [ | ||||||
| openrouter, | ||||||
| "topA", | ||||||
| ], | ||||||
| }, | ||||||
| transforms: { | ||||||
| propDefinition: [ | ||||||
| openrouter, | ||||||
| "transforms", | ||||||
| ], | ||||||
| }, | ||||||
| models: { | ||||||
| propDefinition: [ | ||||||
| openrouter, | ||||||
| "model", | ||||||
| ], | ||||||
| type: "string[]", | ||||||
| label: "Models", | ||||||
| description: "Alternate list of models for routing overrides.", | ||||||
| }, | ||||||
luancazarine marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
| sort: { | ||||||
| propDefinition: [ | ||||||
| openrouter, | ||||||
| "sort", | ||||||
| ], | ||||||
| }, | ||||||
| effort: { | ||||||
| propDefinition: [ | ||||||
| openrouter, | ||||||
| "effort", | ||||||
| ], | ||||||
| }, | ||||||
| reasoningMaxTokens: { | ||||||
| propDefinition: [ | ||||||
| openrouter, | ||||||
| "reasoningMaxTokens", | ||||||
| ], | ||||||
| }, | ||||||
| exclude: { | ||||||
| propDefinition: [ | ||||||
| openrouter, | ||||||
| "exclude", | ||||||
| ], | ||||||
| }, | ||||||
| }, | ||||||
| async run({ $ }) { | ||||||
| if (this.effort && this.reasoningMaxTokens) { | ||||||
| throw new ConfigurationError("**Reasoning Effort** and **Reasoning Max Tokens** cannot be used simultaneously."); | ||||||
| } | ||||||
| const data = { | ||||||
| model: this.model, | ||||||
| messages: parseObject(this.messages), | ||||||
| stream: false, | ||||||
| maxTokens: this.maxTokens, | ||||||
| temperature: this.temperature && parseFloat(this.temperature), | ||||||
| seed: this.seed, | ||||||
| topP: this.topP && parseFloat(this.topP), | ||||||
| topK: this.topK, | ||||||
| frequencyPenalty: this.frequencyPenalty && parseFloat(this.frequencyPenalty), | ||||||
| presencePenalty: this.presencePenalty && parseFloat(this.presencePenalty), | ||||||
| repetitionPenalty: this.repetitionPenalty && parseFloat(this.repetitionPenalty), | ||||||
| logitBias: this.logitBias, | ||||||
| togLogprobs: this.togLogprobs, | ||||||
| minP: this.minP && parseFloat(this.minP), | ||||||
| topA: this.topA && parseFloat(this.topA), | ||||||
| transforms: this.transforms, | ||||||
| models: this.models, | ||||||
| }; | ||||||
| if (this.sort) { | ||||||
| data.provider = { | ||||||
| sort: this.sort, | ||||||
| }; | ||||||
| } | ||||||
| const reasoning = {}; | ||||||
| if (this.effort) { | ||||||
| reasoning.effort = this.effort; | ||||||
| } | ||||||
| if (this.reasoningMaxTokens) { | ||||||
| reasoning.max_tokens = parseFloat(this.reasoningMaxTokens); | ||||||
| } | ||||||
| if (this.exclude) { | ||||||
| reasoning.exclude = this.exclude; | ||||||
| } | ||||||
| if (Object.entries(reasoning).length) { | ||||||
| data.reasoning = reasoning; | ||||||
| } | ||||||
| const response = await this.openrouter.sendChatCompetionRequest({ | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix the typo in method name There appears to be a typo in the method name - const response = await this.openrouter.sendChatCompetionRequest({
+ const response = await this.openrouter.sendChatCompletionRequest({📝 Committable suggestion
Suggested change
|
||||||
| $, | ||||||
| data, | ||||||
| timeout: 1000 * 60 * 5, | ||||||
| }); | ||||||
| if (response.error) { | ||||||
| throw new ConfigurationError(response.error.message); | ||||||
| } | ||||||
| $.export("$summary", `A new chat completion request with Id: ${response.id} was successfully created!`); | ||||||
| return response; | ||||||
| }, | ||||||
| }; | ||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,187 @@ | ||
| import { ConfigurationError } from "@pipedream/platform"; | ||
| import openrouter from "../../openrouter.app.mjs"; | ||
|
|
||
| export default { | ||
| key: "openrouter-send-completion-request", | ||
| name: "Send Completion Request", | ||
| version: "0.0.1", | ||
| description: "Send a completion request to a selected model (text-only format) [See the documentation](https://openrouter.ai/docs/api-reference/completions)", | ||
| type: "action", | ||
| props: { | ||
| openrouter, | ||
| model: { | ||
| propDefinition: [ | ||
| openrouter, | ||
| "model", | ||
| ], | ||
| }, | ||
| prompt: { | ||
| type: "string", | ||
| label: "Prompt", | ||
| description: "The text prompt to complete.", | ||
| }, | ||
| maxTokens: { | ||
| propDefinition: [ | ||
| openrouter, | ||
| "maxTokens", | ||
| ], | ||
| }, | ||
| temperature: { | ||
| propDefinition: [ | ||
| openrouter, | ||
| "temperature", | ||
| ], | ||
| }, | ||
| seed: { | ||
| propDefinition: [ | ||
| openrouter, | ||
| "seed", | ||
| ], | ||
| }, | ||
| topP: { | ||
| propDefinition: [ | ||
| openrouter, | ||
| "topP", | ||
| ], | ||
| }, | ||
| topK: { | ||
| propDefinition: [ | ||
| openrouter, | ||
| "topK", | ||
| ], | ||
| }, | ||
| frequencyPenalty: { | ||
| propDefinition: [ | ||
| openrouter, | ||
| "frequencyPenalty", | ||
| ], | ||
| }, | ||
| presencePenalty: { | ||
| propDefinition: [ | ||
| openrouter, | ||
| "presencePenalty", | ||
| ], | ||
| }, | ||
| repetitionPenalty: { | ||
| propDefinition: [ | ||
| openrouter, | ||
| "repetitionPenalty", | ||
| ], | ||
| }, | ||
| logitBias: { | ||
| propDefinition: [ | ||
| openrouter, | ||
| "logitBias", | ||
| ], | ||
| }, | ||
| togLogprobs: { | ||
| propDefinition: [ | ||
| openrouter, | ||
| "togLogprobs", | ||
| ], | ||
| }, | ||
| minP: { | ||
| propDefinition: [ | ||
| openrouter, | ||
| "minP", | ||
| ], | ||
| }, | ||
| topA: { | ||
| propDefinition: [ | ||
| openrouter, | ||
| "topA", | ||
| ], | ||
| }, | ||
| transforms: { | ||
| propDefinition: [ | ||
| openrouter, | ||
| "transforms", | ||
| ], | ||
| }, | ||
| models: { | ||
| propDefinition: [ | ||
| openrouter, | ||
| "model", | ||
| ], | ||
| type: "string[]", | ||
| label: "Models", | ||
| description: "Alternate list of models for routing overrides.", | ||
| }, | ||
| sort: { | ||
| propDefinition: [ | ||
| openrouter, | ||
| "sort", | ||
| ], | ||
| }, | ||
| effort: { | ||
| propDefinition: [ | ||
| openrouter, | ||
| "effort", | ||
| ], | ||
| }, | ||
| reasoningMaxTokens: { | ||
| propDefinition: [ | ||
| openrouter, | ||
| "reasoningMaxTokens", | ||
| ], | ||
| }, | ||
| exclude: { | ||
| propDefinition: [ | ||
| openrouter, | ||
| "exclude", | ||
| ], | ||
| }, | ||
| }, | ||
| async run({ $ }) { | ||
| if (this.effort && this.reasoningMaxTokens) { | ||
| throw new ConfigurationError("**Reasoning Effort** and **Reasoning Max Tokens** cannot be used simultaneously."); | ||
| } | ||
| const data = { | ||
| model: this.model, | ||
| prompt: this.prompt, | ||
| stream: false, | ||
| maxTokens: this.maxTokens, | ||
| temperature: this.temperature && parseFloat(this.temperature), | ||
| seed: this.seed, | ||
| topP: this.topP && parseFloat(this.topP), | ||
| topK: this.topK, | ||
| frequencyPenalty: this.frequencyPenalty && parseFloat(this.frequencyPenalty), | ||
| presencePenalty: this.presencePenalty && parseFloat(this.presencePenalty), | ||
| repetitionPenalty: this.repetitionPenalty && parseFloat(this.repetitionPenalty), | ||
| logitBias: this.logitBias, | ||
| togLogprobs: this.togLogprobs, | ||
| minP: this.minP && parseFloat(this.minP), | ||
| topA: this.topA && parseFloat(this.topA), | ||
| transforms: this.transforms, | ||
| models: this.models, | ||
| }; | ||
| if (this.sort) { | ||
| data.provider = { | ||
| sort: this.sort, | ||
| }; | ||
| } | ||
| const reasoning = {}; | ||
| if (this.effort) { | ||
| reasoning.effort = this.effort; | ||
| } | ||
| if (this.reasoningMaxTokens) { | ||
| reasoning.max_tokens = parseFloat(this.reasoningMaxTokens); | ||
| } | ||
| if (this.exclude) { | ||
| reasoning.exclude = this.exclude; | ||
| } | ||
| if (Object.entries(reasoning).length) { | ||
| data.reasoning = reasoning; | ||
| } | ||
| const response = await this.openrouter.sendCompetionRequest({ | ||
| $, | ||
| data, | ||
| timeout: 1000 * 60 * 5, | ||
| }); | ||
| if (response.error) { | ||
| throw new ConfigurationError(response.error.message); | ||
| } | ||
| $.export("$summary", `A new completion request with Id: ${response.id} was successfully created!`); | ||
| return response; | ||
| }, | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Add validation for messages format
The
messagesproperty is crucial for chat completion but doesn't have any validation to ensure the correct format.Add validation in the
runmethod to ensure each message has the requiredroleandcontentproperties:async run({ $ }) { + // Validate message format + const messages = parseObject(this.messages); + if (!Array.isArray(messages) || !messages.length) { + throw new ConfigurationError("Messages must be a non-empty array"); + } + + for (const msg of messages) { + if (!msg.role || !msg.content) { + throw new ConfigurationError("Each message must have 'role' and 'content' properties"); + } + + if (!["system", "user", "assistant", "function"].includes(msg.role)) { + throw new ConfigurationError(`Invalid role: ${msg.role}. Valid roles are: system, user, assistant, function`); + } + } // Rest of the run method... const data = { model: this.model, - messages: parseObject(this.messages), + messages, // Other properties... };📝 Committable suggestion