Тема
Внешние приложения
Внешние приложения
Внешнее приложение — универсальный способ подключить к workspace собственный код. Life OS не требует указывать, является ли этот код Telegram-ботом, веб-приложением, worker или сервисом клиента.
Текущий встроенный Telegram adapter продолжает работать как раньше. Внешнее приложение нужно, когда интерфейс и его состояние должны полностью жить в вашем коде.
Создать credentials
- Откройте Подключения → Внешнее приложение.
- Нажмите Добавить и задайте название.
- Выберите только необходимые разрешения.
- Скопируйте
client_idиclient_secret.
client_secret показывается один раз. Life OS хранит только его хеш. При потере secret нажмите кнопку ротации: старый secret и все выпущенные по нему access tokens перестанут работать.
Доступные разрешения:
| Scope | Возможность |
|---|---|
events:write | Отправлять provider-neutral события в workflow |
tasks:read | Читать доступные приложению Human Tasks |
tasks:resolve | Отвечать на Human Tasks |
actions:execute | Вызывать заранее созданные opaque action bindings |
Credentials всегда принадлежат одному workspace. Приложение наследует роль создавшего его пользователя; если пользователь потеряет доступ к workspace, приложение также перестанет работать.
Получить access token
Не используйте client_secret как Bearer token. Обменяйте его на короткоживущий access token:
bash
curl -X POST https://mcp.archik.tech/api/external-auth/token \
-H 'Content-Type: application/json' \
-d '{
"grant_type": "client_credentials",
"client_id": "app_...",
"client_secret": "los_..."
}'json
{
"access_token": "lat_...",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "events:write tasks:read"
}Проверить текущую identity можно через GET /api/external/me.
Отправить событие
http
POST /api/external/events
Authorization: Bearer lat_...
Content-Type: application/jsonjson
{
"type": "message.received",
"external_id": "update:12345",
"subject_id": "conversation:42",
"payload": {
"text": "Покажи новые вакансии"
}
}external_id должен быть стабильным и уникальным: повтор события не запустит одну subscription второй раз. subject_id обозначает диалог, пользователя, заказ или другой объект вашего приложения.
В Workflow Builder источник отображается как External applications, а тип подписки — event.received. Исходный бизнес-тип находится в поле type, поэтому один webhook может принимать любые события приложения без изменений ядра Life OS.
Human Tasks
Получить ожидающие решения:
http
GET /api/external/tasks?status=pending&limit=50
Authorization: Bearer lat_...Приложение самостоятельно рендерит document, поля и actions. Ответ:
http
POST /api/external/tasks/int_123/resolve
Authorization: Bearer lat_...
Content-Type: application/jsonjson
{
"expected_version": 1,
"response": {
"action": "approve",
"answers": {}
}
}Life OS валидирует ответ по замороженному response_schema. n8n получает результат и продолжает бизнес-процесс. Детали кнопок, меню и навигации остаются в коде внешнего приложения.
Вызвать action
Приложение не получает ключи CRM, Telegram или других сервисов. Агент или администратор заранее создаёт opaque action binding, после чего приложение вызывает только его:
http
POST /api/external/actions/aab_123
Authorization: Bearer lat_...
Content-Type: application/jsonBody должен соответствовать input_schema binding. Binding из другого workspace вызвать невозможно. Для безопасной проверки передайте заголовок X-LifeOS-Execution-Mode: dry_run.
Минимальный пример на Aiogram
python
import httpx
from aiogram import Bot, Dispatcher
from aiogram.types import Message
LIFEOS = "https://mcp.archik.tech"
async def lifeos_token(client_id: str, client_secret: str) -> str:
async with httpx.AsyncClient() as client:
response = await client.post(
f"{LIFEOS}/api/external-auth/token",
json={
"grant_type": "client_credentials",
"client_id": client_id,
"client_secret": client_secret,
},
)
response.raise_for_status()
return response.json()["access_token"]
async def send_event(token: str, message: Message) -> None:
async with httpx.AsyncClient() as client:
response = await client.post(
f"{LIFEOS}/api/external/events",
headers={"Authorization": f"Bearer {token}"},
json={
"type": "message.received",
"external_id": f"telegram:{message.chat.id}:{message.message_id}",
"subject_id": f"chat:{message.chat.id}",
"payload": {"text": message.text or ""},
},
)
response.raise_for_status()Telegram token, Aiogram handlers, callback data, клавиатуры и UI-state в этой схеме полностью принадлежат приложению. Life OS видит только generic event и service principal.
Безопасность
- храните
client_secretв secret manager или переменной окружения; - не помещайте его в n8n workflow, frontend bundle или Git;
- выдавайте минимальный набор scopes;
- используйте
external_idдля идемпотентности; - ротируйте secret при подозрении на утечку;
- все вызовы записываются в audit log workspace.