# n8n-nodes-teamorouter Кастомные узлы n8n для шлюза **TeamoRouter** (`https://api.teamorouter.com/v1`) — OpenAI-совместимого роутера к GPT, Claude, Gemini, DeepSeek, GLM, Grok, Kimi и другим моделям. Пакет содержит два узла и один тип учётных данных: | Узел | Тип | Назначение | | --- | --- | --- | | **TeamoRouter Chat Model** (`lmChatTeamRouter`) | sub-node, `ai_languageModel` | Подключается к **AI Agent**, **Basic LLM Chain**, **Question and Answer Chain** и любым другим узлам, которые принимают Language Model | | **TeamoRouter** (`teamorouter`) | обычный узел | Три операции: `Chat → Message a Model`, `Image → Generate an Image`, `Model → List Models` | | **TeamoRouter API** (`teamorouterApi`) | credentials | API-ключ + Base URL | --- ## 1. Установка ### Вариант А. Через интерфейс n8n (рекомендуется) Community nodes в n8n ставятся из npm, поэтому пакет должен быть опубликован: 1. Выгрузите папку в свой git-репозиторий. 2. Опубликуйте в npm: ```bash npm install npm run build npm publish --access public ``` 3. В n8n: **Settings → Community nodes → Install a community node**, введите `n8n-nodes-teamorouter`, подтвердите предупреждение. 4. Перезапускать n8n не нужно — узлы появляются сразу. Нужна роль Owner/Admin и включённые community nodes. Community nodes ставятся на весь инстанс. ### Вариант Б. Копированием папки (если есть доступ к серверу n8n) 1. `npm install && npm run build` — на выходе нужна папка `dist/`. 2. Положите **всю папку пакета** (в ней обязателен `package.json`) в каталог пользовательских расширений, например: * в Docker: `/home/node/.n8n/custom/n8n-nodes-teamorouter/` * через переменную окружения: `N8N_CUSTOM_EXTENSIONS=/path/to/custom-nodes`, а внутри уже папка пакета 3. Внутри папки пакета один раз выполните `npm install --omit=dev`, чтобы `n8n-workflow` (peer-зависимость) был доступен из вашей папки. 4. Перезапустите n8n. ### Вариант В. Локальная разработка ```bash npm install npm run build:watch # tsc в режиме наблюдения export N8N_CUSTOM_EXTENSIONS="$(pwd)" npx n8n start ``` --- ## 2. Учётные данные **Settings → Credentials → New → TeamoRouter API** | Поле | Значение | | --- | --- | | **API Key** | ключ из панели TeamoRouter, начинается с `sk-teamo-` | | **Base URL** | `https://api.teamorouter.com/v1` (по умолчанию; меняйте только для зеркала `.cn` или своего роутера) | Кнопка проверки делает `GET /v1/models` с заголовком `Authorization: Bearer <ключ>`. --- ## 3. TeamoRouter Chat Model (для AI Agent) 1. Добавьте **AI Agent** (или **Basic LLM Chain**). 2. В слот **Chat Model** добавьте **TeamoRouter Chat Model**. 3. Выберите модель из списка — он читается вживую из `GET /v1/models`. В подписи к модели видны провайдер и цена за 1M токенов (если роутер их отдаёт). ### Опции | Опция | Что делает | | --- | --- | | **Sampling Temperature** | случайность ответа, 0…2 | | **Maximum Number of Tokens** | лимит генерации; `-1` = решает модель | | **Top P** | nucleus sampling; меняйте либо temperature, либо topP | | **Force JSON Response** | просит модель отвечать объектом JSON (в промпте должно быть слово JSON) | | **Service Tier → Fast** | режим Fast у TeamoRouter: до 2,5× быстрее, тарифицируется ×2 | | **Extra Body** | произвольные JSON-поля в тело запроса, например `{"top_k": 40}`; перекрывает всё выше | | **Timeout** | по умолчанию 600000 мс (роутер допускает ответы до 600 с) | | **Max Retries** | повторы при ошибке, по умолчанию 2 | ### Модель, которой нет в списке Поле **Model** можно переключить в режим выражения (переключатель `Expression` в правом верхнем углу поля) и вписать ID руками: ``` {{ 'some-new-model-id' }} ``` Это пригодится, если модель появилась у роутера, а список в UI ещё не перечитан. --- ## 4. Узел TeamoRouter (обычные операции) ### Chat → Message a Model Отправляет `POST /v1/chat/completions` и возвращает JSON-ответ как есть. | Поле | Описание | | --- | --- | | **Model** | список читается из `GET /v1/models` (только текстовые модели; картинные скрыты) | | **Prompt** | сообщение пользователя | | **Options → System Prompt** | системная инструкция | | **Options →** остальное | temperature, topP, max tokens, JSON-ответ, Service Tier Fast, Extra Body, Timeout | Текст ответа доступен как `{{ $json.choices[0].message.content }}`, расход токенов — `{{ $json.usage }}`. ### Image → Generate an Image Отправляет `POST /v1/images/generations` и кладёт результат **в бинарное поле** (по умолчанию `data`, PNG). | Поле | Описание | | --- | --- | | **Model** | по умолчанию `gpt-image-2`, список — только картинные модели; можно вписать ID выражением | | **Prompt** | описание картинки | | **Put Output File in Field** | имя бинарного свойства | Дальше файл уходит в **Write Binary File**, в Telegram, в S3 и т. д. Долгие генерации узел ждёт до 5 минут. ### Model → List Models Возвращает модели роутера: по одному элементу на модель (`id`, `object`, `owned_by`, `pricing` и др.). Удобно, чтобы построить собственный справочник или посчитать цены. --- ## 5. Известные особенности и ограничения * **Ответы идут на `/v1/chat/completions`.** Исключение — модель из семейства `gpt-5.6*` и всё, что содержит `codex`: LangChain внутри n8n сам переключает такие ID на `/v1/responses` (это поведение зашито в `@langchain/openai` и не отключается настройками). TeamoRouter поддерживает `/v1/responses`, но **только для GPT-моделей**, поэтому схема рабочая. Для Claude/Gemini запросы идут обычным Chat Completions. * **Claude через OpenAI-формат не отдаёт prompt caching.** Это ограничение формата роутера, а не узла: кэширование промпта доступно только через нативный протокол Anthropic (в README TeamoRouter это указано отдельно). * **`max_tokens`, а не `max_completion_tokens`.** Узел отправляет именно `max_tokens` — как в примере из документации TeamoRouter. Если конкретная модель требует `max_completion_tokens`, добавьте его через **Extra Body**. * **Формат ответа JSON** передаётся через `response_format` — это параметр Chat Completions. Для моделей, которые уходят на `/v1/responses`, он может игнорироваться. * **Список картинных моделей** определяется по имени: `*-image`, `gpt-image*`, `nano-banana*`, `dall-e*`, `imagen*`. Если роутер назовёт модель иначе, она попадёт в список чата (или наоборот); при этом поле всегда можно заполнить вручную выражением. * **Цены в списке моделей** — подсказка. Роутер может отдавать цену за токен или уже за 1M токенов; узел считает значения меньше `0.005` как «за токен». Это только отображение, на запросы не влияет. * У полей **Model** список загружается при открытии, кэша нет: если модель только что появилась, нажмите перезагрузить список или используйте выражение. --- ## 6. Разработка и проверки ```bash npm install npm run build # tsc + копирование иконок в dist/ npm test # проверка структуры пакета + тесты узлов на мок-сервере npm run typecheck npm run mock # мок TeamoRouter на http://127.0.0.1:4123/v1 (ключ test-key) ``` `npm test` запускает два набора: 1. `test/validate-nodes.mjs` — имитирует загрузку пакета n8n: проверяет описание узлов, наличие иконок, реализацию `loadOptionsMethod`, ссылки на credential, тип соединения `ai_languageModel` у саб-узла. 2. `test/run-node-tests.mjs` — поднимает мок роутера (`test/mock-server.mjs`, без зависимостей) и прогоняет скомпилированные узлы с настоящим HTTP и настоящим `@langchain/openai`: список моделей и фильтрация картинных, `supplyData` + реальный вызов модели, проброс опций (`service_tier`, `extra_body`, лимиты), обе операции у обычного узла, генерация изображения в бинарном виде, разбор ошибок 401/402/404, `Continue On Fail` и таймаут. Тесты не требуют ключа TeamoRouter. Модели `fail-401`, `fail-402`, `fail-404`, `fail-500` в моке принудительно отдают ошибку, `slow-model` отвечает через 2,5 с. --- ## 7. Первый запуск и диагностика * Пакет собран и проверен автотестами (см. `npm test`), но **в живом n8n ещё не запускался** — первый запуск делайте на тестовом воркфлоу. * При установке через `Settings → Community nodes` интерфейс может показать предупреждение о сообщественном узле — это нормально. * Если n8n пишет, что узел не загрузился, проверьте `Help → About` (версия n8n) и логи контейнера: чаще всего причина — недоступная peer-зависимость `n8n-workflow` (Вариант Б, шаг 3). ## Лицензия MIT --- --- # English Custom n8n nodes for the **TeamoRouter** gateway (`https://api.teamorouter.com/v1`) — an OpenAI-compatible router in front of GPT, Claude, Gemini, DeepSeek, GLM, Grok, Kimi and other models. The package ships two nodes and one credential type: | Node | Type | Purpose | | --- | --- | --- | | **TeamoRouter Chat Model** (`lmChatTeamRouter`) | sub-node, `ai_languageModel` | Plugs into **AI Agent**, **Basic LLM Chain**, **Question and Answer Chain** and any other node that takes a Language Model | | **TeamoRouter** (`teamorouter`) | regular node | Three operations: `Chat → Message a Model`, `Image → Generate an Image`, `Model → List Models` | | **TeamoRouter API** (`teamorouterApi`) | credentials | API key + Base URL | --- ## 1. Installation ### Option A. Through the n8n UI (recommended) Community nodes in n8n are installed from npm, so the package has to be published: 1. Push this folder to your git repository. 2. Publish to npm: ```bash npm install npm run build npm publish --access public ``` 3. In n8n: **Settings → Community nodes → Install a community node**, enter `n8n-nodes-teamorouter` and confirm the warning. 4. No restart is needed — the nodes appear right away. The Owner/Admin role and enabled community nodes are required. Community nodes are installed instance-wide. ### Option B. Copying the folder (if you have access to the n8n server) 1. Run `npm install && npm run build` — you need the resulting `dist/` folder. 2. Put the **whole package folder** (it must contain `package.json`) into the custom extensions directory, for example: * in Docker: `/home/node/.n8n/custom/n8n-nodes-teamorouter/` * via an environment variable: `N8N_CUSTOM_EXTENSIONS=/path/to/custom-nodes`, with the package folder inside it 3. Inside the package folder run `npm install --omit=dev` once, so that `n8n-workflow` (a peer dependency) is reachable from your folder. 4. Restart n8n. ### Option C. Local development ```bash npm install npm run build:watch # tsc in watch mode export N8N_CUSTOM_EXTENSIONS="$(pwd)" npx n8n start ``` --- ## 2. Credentials **Settings → Credentials → New → TeamoRouter API** | Field | Value | | --- | --- | | **API Key** | the key from the TeamoRouter dashboard, it starts with `sk-teamo-` | | **Base URL** | `https://api.teamorouter.com/v1` (the default; change it only for the `.cn` mirror or your own router) | The test button issues `GET /v1/models` with the `Authorization: Bearer ` header. --- ## 3. TeamoRouter Chat Model (for the AI Agent) 1. Add an **AI Agent** (or a **Basic LLM Chain**). 2. Add **TeamoRouter Chat Model** into the **Chat Model** slot. 3. Pick a model from the list — it is read live from `GET /v1/models`. The label of each model shows the provider and the price per 1M tokens (when the router reports them). ### Options | Option | What it does | | --- | --- | | **Sampling Temperature** | randomness of the answer, 0…2 | | **Maximum Number of Tokens** | generation limit; `-1` = decided by the model | | **Top P** | nucleus sampling; change either temperature or topP, not both | | **Force JSON Response** | asks the model to answer with a JSON object (the prompt must mention JSON) | | **Service Tier → Fast** | TeamoRouter Fast mode: up to 2.5x faster, billed at 2x | | **Extra Body** | arbitrary JSON fields for the request body, e.g. `{"top_k": 40}`; overrides everything above | | **Timeout** | 600000 ms by default (the router allows answers up to 600 s) | | **Max Retries** | retries on failure, 2 by default | ### A model that is missing from the list The **Model** field can be switched to expression mode (the `Expression` toggle in the top right corner of the field) and filled with the ID by hand: ``` {{ 'some-new-model-id' }} ``` Useful when the router already serves a new model but the list in the UI has not been reloaded yet. --- ## 4. The TeamoRouter node (regular operations) ### Chat → Message a Model Sends `POST /v1/chat/completions` and returns the JSON answer as is. | Field | Description | | --- | --- | | **Model** | the list is read from `GET /v1/models` (text models only; image models are hidden) | | **Prompt** | the user message | | **Options → System Prompt** | system instruction | | **Options →** the rest | temperature, topP, max tokens, JSON answer, Service Tier Fast, Extra Body, Timeout | The answer text is available as `{{ $json.choices[0].message.content }}`, the token usage as `{{ $json.usage }}`. ### Image → Generate an Image Sends `POST /v1/images/generations` and puts the result into a **binary field** (`data` by default, PNG). | Field | Description | | --- | --- | | **Model** | `gpt-image-2` by default; the list contains image models only; the ID can be entered as an expression | | **Prompt** | description of the image | | **Put Output File in Field** | name of the binary property | The file can then go to **Write Binary File**, Telegram, S3, and so on. Long generations are awaited for up to 5 minutes. ### Model → List Models Returns the models of the router, one item per model (`id`, `object`, `owned_by`, `pricing` and more). Handy for building your own catalogue or for counting costs. --- ## 5. Known details and limitations * **Requests go to `/v1/chat/completions`.** The exception is the `gpt-5.6*` model family and anything containing `codex`: LangChain inside n8n switches such IDs to `/v1/responses` on its own (this behaviour is hardcoded in `@langchain/openai` and cannot be turned off by settings). TeamoRouter supports `/v1/responses`, but **for GPT models only**, so the scheme works. Claude/Gemini requests use plain Chat Completions. * **Claude through the OpenAI format gives up prompt caching.** That is a limitation of the router's format, not of the node: prompt caching is available only through the native Anthropic protocol (the TeamoRouter README says so explicitly). * **`max_tokens`, not `max_completion_tokens`.** The node sends `max_tokens`, exactly as in the TeamoRouter documentation example. If a particular model requires `max_completion_tokens`, add it through **Extra Body**. * **The JSON response format** is passed as `response_format`, which is a Chat Completions parameter. For models that go to `/v1/responses` it may be ignored. * **The list of image models** is detected by name: `*-image`, `gpt-image*`, `nano-banana*`, `dall-e*`, `imagen*`. If the router names a model differently, it will land in the chat list (or the other way round); the field can always be filled in by hand as an expression. * **Prices in the model list** are a hint. The router may report a price per token or already per 1M tokens; the node treats values below `0.005` as “per token”. This is display only and does not affect requests. * The list of the **Model** fields is loaded when the field is opened and is not cached: if a model has just appeared, reload the list or use an expression. --- ## 6. Development and checks ```bash npm install npm run build # tsc + copying the icons into dist/ npm test # package shape validation + node tests against a mock server npm run typecheck npm run mock # mock TeamoRouter on http://127.0.0.1:4123/v1 (key: test-key) ``` `npm test` runs two suites: 1. `test/validate-nodes.mjs` — imitates n8n loading the package: checks the node descriptions, the presence of the icons, the implementation of every `loadOptionsMethod`, the credential references, and the `ai_languageModel` connection type of the sub-node. 2. `test/run-node-tests.mjs` — starts the mock router (`test/mock-server.mjs`, dependency-free) and drives the compiled nodes with real HTTP and real `@langchain/openai`: the model list and the filtering of image models, `supplyData` plus a real model call, the passing of options (`service_tier`, `extra_body`, limits), both operations of the regular node, image generation into a binary field, the handling of 401/402/404 errors, `Continue On Fail` and the timeout. The tests need no TeamoRouter key. The `fail-401`, `fail-402`, `fail-404` and `fail-500` models in the mock return an error on purpose, and `slow-model` answers after 2.5 s. --- ## 7. First run and troubleshooting * The package is built and covered by the automated tests (see `npm test`), but it **has not been run inside a live n8n yet** — do the first run on a test workflow. * When installing through `Settings → Community nodes`, the UI may show a warning about a community node — that is normal. * If n8n reports that the node failed to load, check `Help → About` (the n8n version) and the container logs: the usual cause is the unreachable `n8n-workflow` peer dependency (Option B, step 3). ## License MIT