diff --git a/apps/docs/openapi/builder.json b/apps/docs/openapi/builder.json index 19d908244f..3243c12e46 100644 --- a/apps/docs/openapi/builder.json +++ b/apps/docs/openapi/builder.json @@ -18793,7 +18793,8 @@ "dify-ai", "mistral", "elevenlabs", - "together-ai" + "together-ai", + "open-router" ] }, "options": {} diff --git a/apps/docs/openapi/viewer.json b/apps/docs/openapi/viewer.json index 9f9891d074..16f9cff1d3 100644 --- a/apps/docs/openapi/viewer.json +++ b/apps/docs/openapi/viewer.json @@ -9414,7 +9414,8 @@ "dify-ai", "mistral", "elevenlabs", - "together-ai" + "together-ai", + "open-router" ] }, "options": {} diff --git a/packages/forge/blocks/openRouter/actions/createChatCompletion.tsx b/packages/forge/blocks/openRouter/actions/createChatCompletion.tsx new file mode 100644 index 0000000000..f7be41ce27 --- /dev/null +++ b/packages/forge/blocks/openRouter/actions/createChatCompletion.tsx @@ -0,0 +1,50 @@ +import { createAction } from '@typebot.io/forge' +import { auth } from '../auth' +import { parseChatCompletionOptions } from '@typebot.io/openai-block/shared/parseChatCompletionOptions' +import { getChatCompletionSetVarIds } from '@typebot.io/openai-block/shared/getChatCompletionSetVarIds' +import { getChatCompletionStreamVarId } from '@typebot.io/openai-block/shared/getChatCompletionStreamVarId' +import { runChatCompletion } from '@typebot.io/openai-block/shared/runChatCompletion' +import { runChatCompletionStream } from '@typebot.io/openai-block/shared/runChatCompletionStream' +import { defaultOpenRouterOptions } from '../constants' +import { got } from 'got' +import { ModelsResponse } from '../types' + +export const createChatCompletion = createAction({ + name: 'Create chat completion', + auth, + options: parseChatCompletionOptions({ + modelFetchId: 'fetchModels', + }), + getSetVariableIds: getChatCompletionSetVarIds, + fetchers: [ + { + id: 'fetchModels', + dependencies: [], + fetch: async () => { + const response = await got + .get(defaultOpenRouterOptions.baseUrl + '/models') + .json() + + return response.data.map((model) => ({ + value: model.id, + label: model.name, + })) + }, + }, + ], + run: { + server: (params) => + runChatCompletion({ + ...params, + config: { baseUrl: defaultOpenRouterOptions.baseUrl }, + }), + stream: { + getStreamVariableId: getChatCompletionStreamVarId, + run: (params) => + runChatCompletionStream({ + ...params, + config: { baseUrl: defaultOpenRouterOptions.baseUrl }, + }), + }, + }, +}) diff --git a/packages/forge/blocks/openRouter/auth.ts b/packages/forge/blocks/openRouter/auth.ts new file mode 100644 index 0000000000..8e9d128b44 --- /dev/null +++ b/packages/forge/blocks/openRouter/auth.ts @@ -0,0 +1,15 @@ +import { option, AuthDefinition } from '@typebot.io/forge' + +export const auth = { + type: 'encryptedCredentials', + name: 'OpenRouter account', + schema: option.object({ + apiKey: option.string.layout({ + label: 'API key', + isRequired: true, + inputType: 'password', + helperText: + 'You can generate an API key [here](https://openrouter.ai/keys).', + }), + }), +} satisfies AuthDefinition diff --git a/packages/forge/blocks/openRouter/constants.ts b/packages/forge/blocks/openRouter/constants.ts new file mode 100644 index 0000000000..b5f7cebee0 --- /dev/null +++ b/packages/forge/blocks/openRouter/constants.ts @@ -0,0 +1,3 @@ +export const defaultOpenRouterOptions = { + baseUrl: 'https://openrouter.ai/api/v1', +} as const diff --git a/packages/forge/blocks/openRouter/index.ts b/packages/forge/blocks/openRouter/index.ts new file mode 100644 index 0000000000..8d671a9c99 --- /dev/null +++ b/packages/forge/blocks/openRouter/index.ts @@ -0,0 +1,13 @@ +import { createBlock } from '@typebot.io/forge' +import { OpenRouterLogo } from './logo' +import { auth } from './auth' +import { createChatCompletion } from './actions/createChatCompletion' + +export const openRouter = createBlock({ + id: 'open-router', + name: 'OpenRouter', + tags: ['ai', 'openai', 'chat', 'completion'], + LightLogo: OpenRouterLogo, + auth, + actions: [createChatCompletion], +}) diff --git a/packages/forge/blocks/openRouter/logo.tsx b/packages/forge/blocks/openRouter/logo.tsx new file mode 100644 index 0000000000..64044ed2f7 --- /dev/null +++ b/packages/forge/blocks/openRouter/logo.tsx @@ -0,0 +1,23 @@ +import React from 'react' + +export const OpenRouterLogo = (props: React.SVGProps) => ( + + + + + + + + + + + + + +) diff --git a/packages/forge/blocks/openRouter/package.json b/packages/forge/blocks/openRouter/package.json new file mode 100644 index 0000000000..4703d61903 --- /dev/null +++ b/packages/forge/blocks/openRouter/package.json @@ -0,0 +1,17 @@ +{ + "name": "@typebot.io/open-router-block", + "version": "1.0.0", + "description": "", + "main": "index.ts", + "keywords": [], + "license": "ISC", + "devDependencies": { + "@typebot.io/forge": "workspace:*", + "@typebot.io/tsconfig": "workspace:*", + "@types/react": "18.2.15", + "typescript": "5.3.2", + "@typebot.io/lib": "workspace:*", + "@typebot.io/openai-block": "workspace:*", + "got": "12.6.0" + } +} diff --git a/packages/forge/blocks/openRouter/tsconfig.json b/packages/forge/blocks/openRouter/tsconfig.json new file mode 100644 index 0000000000..1eb9c77172 --- /dev/null +++ b/packages/forge/blocks/openRouter/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "@typebot.io/tsconfig/base.json", + "include": ["**/*.ts", "**/*.tsx"], + "exclude": ["node_modules"], + "compilerOptions": { + "lib": ["ESNext", "DOM"], + "noEmit": true, + "jsx": "react" + } +} diff --git a/packages/forge/blocks/openRouter/types.ts b/packages/forge/blocks/openRouter/types.ts new file mode 100644 index 0000000000..1a8aa16946 --- /dev/null +++ b/packages/forge/blocks/openRouter/types.ts @@ -0,0 +1,6 @@ +export type ModelsResponse = { + data: { + id: string + name: string + }[] +} diff --git a/packages/forge/repository/index.ts b/packages/forge/repository/index.ts index 9551f6200a..52b7347d00 100644 --- a/packages/forge/repository/index.ts +++ b/packages/forge/repository/index.ts @@ -9,4 +9,5 @@ export const enabledBlocks = [ 'mistral', 'elevenlabs', 'together-ai', + 'open-router', ] as const diff --git a/packages/forge/schemas/index.ts b/packages/forge/schemas/index.ts index e67a8a2e88..b3d2d2fa7b 100644 --- a/packages/forge/schemas/index.ts +++ b/packages/forge/schemas/index.ts @@ -1,4 +1,5 @@ // Do not edit this file manually +import { openRouter } from '@typebot.io/open-router-block' import { togetherAi } from '@typebot.io/together-ai-block' import { elevenlabs } from '@typebot.io/elevenlabs-block' import { difyAi } from '@typebot.io/dify-ai-block' @@ -26,6 +27,7 @@ export const forgedBlocks = [ mistral, elevenlabs, togetherAi, + openRouter, ] as BlockDefinition<(typeof enabledBlocks)[number], any, any>[] export type ForgedBlockDefinition = (typeof forgedBlocks)[number] diff --git a/packages/forge/schemas/package.json b/packages/forge/schemas/package.json index e5c9d4d368..4e26e54926 100644 --- a/packages/forge/schemas/package.json +++ b/packages/forge/schemas/package.json @@ -17,6 +17,7 @@ "@typebot.io/dify-ai-block": "workspace:*", "@typebot.io/mistral-block": "workspace:*", "@typebot.io/elevenlabs-block": "workspace:*", - "@typebot.io/together-ai-block": "workspace:*" + "@typebot.io/together-ai-block": "workspace:*", + "@typebot.io/open-router-block": "workspace:*" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 21054e11d3..58148f046e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1268,6 +1268,30 @@ importers: specifier: 5.3.2 version: 5.3.2 + packages/forge/blocks/openRouter: + devDependencies: + '@typebot.io/forge': + specifier: workspace:* + version: link:../../core + '@typebot.io/lib': + specifier: workspace:* + version: link:../../../lib + '@typebot.io/openai-block': + specifier: workspace:* + version: link:../openai + '@typebot.io/tsconfig': + specifier: workspace:* + version: link:../../../tsconfig + '@types/react': + specifier: 18.2.15 + version: 18.2.15 + got: + specifier: 12.6.0 + version: 12.6.0 + typescript: + specifier: 5.3.2 + version: 5.3.2 + packages/forge/blocks/openai: dependencies: ai: @@ -1422,6 +1446,9 @@ importers: '@typebot.io/mistral-block': specifier: workspace:* version: link:../blocks/mistral + '@typebot.io/open-router-block': + specifier: workspace:* + version: link:../blocks/openRouter '@typebot.io/openai-block': specifier: workspace:* version: link:../blocks/openai