# 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