feat(ai-stack-2026): add OpenAPI 3.0.3 schema, Telegram /ai_doctor & /fix integration, AI language selector, and log deduplication
- Agent REST API (agent_api.uc): Added GET /openapi.json returning OpenAPI 3.0.3 spec for ChatGPT Custom GPTs, N8N, Dify, and LLM Agents - AI Doctor (runtime.uc): Added compress_log_snippet() for deduplicating repeated log entries and ai_doctor_lang support (ru/en prompt selection) - Telegram Bot (telegram.uc): Added /ai_doctor and /fix commands with Inline Keyboards for instant quick-fix execution - Settings (renderAdvancedSettings.ts, settings.js): Added AI Doctor Language selector (ru/en) - Documentation: Updated README.md and README.en.md with 2026 AI features
This commit is contained in:
+13
-1
@@ -43,8 +43,20 @@ A feature-rich control center right inside your messenger:
|
|||||||
* **Device Access Control**: View active DHCP clients and block/unblock internet access by MAC address.
|
* **Device Access Control**: View active DHCP clients and block/unblock internet access by MAC address.
|
||||||
* **Network Diagnostics**: Trigger connection tests directly from Telegram.
|
* **Network Diagnostics**: Trigger connection tests directly from Telegram.
|
||||||
|
|
||||||
|
### 🤖 AI Doctor & HTTP REST Agent API (2026 AI Stack)
|
||||||
|
* **Tachyon AI Doctor (v2)**: Advanced AI diagnostic engine supporting modern LLMs (**OpenAI**, **Anthropic Claude**, **DeepSeek**, and custom OpenAI-compatible servers/OpenRouter/Ollama).
|
||||||
|
* **Contextual Intelligence**: Feeds the LLM real-time service status, Watchdog failure history (OOM events, error streaks), and compressed system logs.
|
||||||
|
* **Multi-Fix Execution Chains**: Generates multi-action repair sequences with dedicated UI buttons per fix or a single "Fix All" action.
|
||||||
|
* **13 Built-in Quick Fix Codes**: Automated repairs for sing-box, nftables, dnsmasq, resolv.conf, DNS cache clearing, subscription refreshing, and network restarts.
|
||||||
|
* **Language Modes**: Configurable diagnosis output language (`ru` / `en`).
|
||||||
|
* **🤖 Interactive Telegram Commands (`/ai_doctor` & `/fix`)**:
|
||||||
|
* Trigger AI diagnostics directly from Telegram using `/ai_doctor` with interactive Inline Keyboards for instant quick-fix execution.
|
||||||
|
* **🌐 HTTP REST Agent API & OpenAPI 3.0 (Swagger)**:
|
||||||
|
* Full-featured API at `/cgi-bin/tachyon-agent/` with granular READ/WRITE permission controls secured by a Bearer token (`agent_api_token`).
|
||||||
|
* Native **OpenAPI 3.0.3** spec (`GET /cgi-bin/tachyon-agent/openapi.json`) and OpenAI Function Calling schema (`GET /tools`) for seamless integration with **ChatGPT Custom GPTs**, N8N, Dify, Flowise, and autonomous LLM agents (Cursor, AutoGPT, Claude Code).
|
||||||
|
|
||||||
### 🩺 System Self-Healing — Tachyon Doctor
|
### 🩺 System Self-Healing — Tachyon Doctor
|
||||||
An intelligent diagnostic and repair engine available via CLI (`tachyon doctor`) or WebUI:
|
An intelligent local diagnostic and repair engine available via CLI (`tachyon doctor`) or WebUI:
|
||||||
* Scans all core services (`sing-box`, `zapret`, `zapret2`, `byedpi`, `dnsmasq`, `watchdog`).
|
* Scans all core services (`sing-box`, `zapret`, `zapret2`, `byedpi`, `dnsmasq`, `watchdog`).
|
||||||
* Validates `nftables` chains and local DNS resolution health.
|
* Validates `nftables` chains and local DNS resolution health.
|
||||||
* **Auto-Repair**: Automatically rebuilds broken firewall rules and restarts crashed services without requiring a full router reboot.
|
* **Auto-Repair**: Automatically rebuilds broken firewall rules and restarts crashed services without requiring a full router reboot.
|
||||||
|
|||||||
@@ -43,8 +43,20 @@
|
|||||||
* **Управление устройствами LAN**: Просмотр активных DHCP-клиентов и блокировка/разблокировка доступа в интернет по MAC-адресам.
|
* **Управление устройствами LAN**: Просмотр активных DHCP-клиентов и блокировка/разблокировка доступа в интернет по MAC-адресам.
|
||||||
* **Диагностика сети**: Запуск тестов доступности прямо из чата.
|
* **Диагностика сети**: Запуск тестов доступности прямо из чата.
|
||||||
|
|
||||||
|
### 🤖 ИИ-Доктор и HTTP REST Agent API (2026 AI Stack)
|
||||||
|
* **Tachyon AI Doctor (v2)**: Интеллектуальный диагностический модуль с поддержкой современных LLM (**OpenAI**, **Anthropic Claude**, **DeepSeek** и пользовательских OpenAI-совместимых серверов/OpenRouter/Ollama).
|
||||||
|
* **Контекстный анализ**: Передаёт в модель не только снимки служб, но и события Watchdog (OOM, серии ошибок) и последние сжатые логи роутера.
|
||||||
|
* **Многокомпонентные цепочки фиксов (Multi-Fix)**: Возвращает цепочку автоматических исправлений с возможностью выбора конкретного фикса или одной кнопкой «Исправить всё».
|
||||||
|
* **13 встроенных Quick Fix кодов**: Автоматический ремонт sing-box, nftables, dnsmasq, resolv.conf, очистка кэша DNS, обновление подписок и перезапуск сетевых служб.
|
||||||
|
* **Языковые режимы**: Динамический выбор языка вердикта (`ru` / `en`).
|
||||||
|
* **🤖 Управление через Telegram-бот (`/ai_doctor` & `/fix`)**:
|
||||||
|
* Запуск AI-диагностики прямо из мессенджера одной командой `/ai_doctor` с выведением интерактивных Inline-кнопок для моментального применения авто-исправлений.
|
||||||
|
* **🌐 HTTP REST Agent API & OpenAPI 3.0 (Swagger)**:
|
||||||
|
* Полноценный API по адресу `/cgi-bin/tachyon-agent/` с разделением READ/WRITE эндпоинтов и защиты Bearer-токеном (`agent_api_token`).
|
||||||
|
* Спецификация **OpenAPI 3.0.3** (`GET /cgi-bin/tachyon-agent/openapi.json`) и схема инструментов (`GET /tools`) для подсоединения к **ChatGPT Custom GPTs**, N8N, Dify, Flowise и автономным ИИ-агентам (Cursor, AutoGPT, Claude Code).
|
||||||
|
|
||||||
### 🩺 Системный авторемонт — Tachyon Doctor
|
### 🩺 Системный авторемонт — Tachyon Doctor
|
||||||
Встроенный модуль интеллектуальной диагностики и самовосстановления (`tachyon doctor` или из WebUI):
|
Встроенный модуль локальной диагностики и самовосстановления (`tachyon doctor` или из WebUI):
|
||||||
* Сканирование состояния всех ключевых служб (`sing-box`, `zapret`, `zapret2`, `byedpi`, `dnsmasq`, `watchdog`).
|
* Сканирование состояния всех ключевых служб (`sing-box`, `zapret`, `zapret2`, `byedpi`, `dnsmasq`, `watchdog`).
|
||||||
* Валидация правил файрвола `nftables` и проверка резолвинга DNS через `localhost`.
|
* Валидация правил файрвола `nftables` и проверка резолвинга DNS через `localhost`.
|
||||||
* **Автоматическое исправление**: Самостоятельно устраняет сбои (пересоздает цепочки `nftables`, перезапускает упавшие сервисы) без полной перезагрузки устройства.
|
* **Автоматическое исправление**: Самостоятельно устраняет сбои (пересоздает цепочки `nftables`, перезапускает упавшие сервисы) без полной перезагрузки устройства.
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ interface AdvancedSettingsState {
|
|||||||
enableAiDoctor: boolean;
|
enableAiDoctor: boolean;
|
||||||
aiDoctorProvider: string;
|
aiDoctorProvider: string;
|
||||||
aiDoctorModel: string;
|
aiDoctorModel: string;
|
||||||
|
aiDoctorLang: string;
|
||||||
aiDoctorApiKey: string;
|
aiDoctorApiKey: string;
|
||||||
aiDoctorCustomUrl: string;
|
aiDoctorCustomUrl: string;
|
||||||
aiWatchdog: {
|
aiWatchdog: {
|
||||||
@@ -54,6 +55,7 @@ let _state: AdvancedSettingsState = {
|
|||||||
enableAiDoctor: false,
|
enableAiDoctor: false,
|
||||||
aiDoctorProvider: 'openai',
|
aiDoctorProvider: 'openai',
|
||||||
aiDoctorModel: '',
|
aiDoctorModel: '',
|
||||||
|
aiDoctorLang: 'ru',
|
||||||
aiDoctorApiKey: '',
|
aiDoctorApiKey: '',
|
||||||
aiDoctorCustomUrl: '',
|
aiDoctorCustomUrl: '',
|
||||||
aiWatchdog: {
|
aiWatchdog: {
|
||||||
@@ -153,6 +155,9 @@ export async function loadAdvancedSettingsState() {
|
|||||||
aiDoctorModel:
|
aiDoctorModel:
|
||||||
((settingsSec as unknown as Record<string, unknown>)
|
((settingsSec as unknown as Record<string, unknown>)
|
||||||
?.ai_doctor_model as string) || '',
|
?.ai_doctor_model as string) || '',
|
||||||
|
aiDoctorLang:
|
||||||
|
((settingsSec as unknown as Record<string, unknown>)
|
||||||
|
?.ai_doctor_lang as string) || 'ru',
|
||||||
aiDoctorApiKey:
|
aiDoctorApiKey:
|
||||||
((settingsSec as unknown as Record<string, unknown>)
|
((settingsSec as unknown as Record<string, unknown>)
|
||||||
?.ai_doctor_api_key as string) || '',
|
?.ai_doctor_api_key as string) || '',
|
||||||
@@ -311,6 +316,10 @@ async function saveAiWatchdogSettings() {
|
|||||||
'set',
|
'set',
|
||||||
`${TACHYON_UCI_PACKAGE}.settings.ai_doctor_model=${_state.aiDoctorModel}`,
|
`${TACHYON_UCI_PACKAGE}.settings.ai_doctor_model=${_state.aiDoctorModel}`,
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
'set',
|
||||||
|
`${TACHYON_UCI_PACKAGE}.settings.ai_doctor_lang=${_state.aiDoctorLang}`,
|
||||||
|
],
|
||||||
[
|
[
|
||||||
'set',
|
'set',
|
||||||
`${TACHYON_UCI_PACKAGE}.settings.ai_doctor_api_key=${_state.aiDoctorApiKey}`,
|
`${TACHYON_UCI_PACKAGE}.settings.ai_doctor_api_key=${_state.aiDoctorApiKey}`,
|
||||||
@@ -826,6 +835,42 @@ function renderAiWatchdogSection(state: AdvancedSettingsState) {
|
|||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
]),
|
]),
|
||||||
|
E('div', { class: 'tachyon_adv__row' }, [
|
||||||
|
E(
|
||||||
|
'label',
|
||||||
|
{ class: 'tachyon_adv__label' },
|
||||||
|
_('AI Doctor Language'),
|
||||||
|
),
|
||||||
|
E(
|
||||||
|
'select',
|
||||||
|
{
|
||||||
|
class: 'cbi-input-select',
|
||||||
|
onchange: (e: Event) => {
|
||||||
|
const val = (e.target as HTMLSelectElement).value;
|
||||||
|
_state = { ..._state, aiDoctorLang: val };
|
||||||
|
rerender();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
[
|
||||||
|
E(
|
||||||
|
'option',
|
||||||
|
{
|
||||||
|
value: 'ru',
|
||||||
|
selected: state.aiDoctorLang === 'ru',
|
||||||
|
},
|
||||||
|
'Русский (Russian)',
|
||||||
|
),
|
||||||
|
E(
|
||||||
|
'option',
|
||||||
|
{
|
||||||
|
value: 'en',
|
||||||
|
selected: state.aiDoctorLang === 'en',
|
||||||
|
},
|
||||||
|
'English',
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]),
|
||||||
E('div', { class: 'tachyon_adv__row' }, [
|
E('div', { class: 'tachyon_adv__row' }, [
|
||||||
E('label', { class: 'tachyon_adv__label' }, _('AI API Key')),
|
E('label', { class: 'tachyon_adv__label' }, _('AI API Key')),
|
||||||
E('input', {
|
E('input', {
|
||||||
|
|||||||
@@ -1282,6 +1282,18 @@ function createSettingsContent(section, capabilities) {
|
|||||||
o.rmempty = true;
|
o.rmempty = true;
|
||||||
o.placeholder = _("(provider default)");
|
o.placeholder = _("(provider default)");
|
||||||
|
|
||||||
|
o = section.taboption(
|
||||||
|
"ai",
|
||||||
|
form.ListValue,
|
||||||
|
"ai_doctor_lang",
|
||||||
|
_("AI Doctor Language"),
|
||||||
|
_("Language for AI Doctor diagnosis responses"),
|
||||||
|
);
|
||||||
|
o.depends("enable_ai_doctor", "1");
|
||||||
|
o.value("ru", "Русский (Russian)");
|
||||||
|
o.value("en", "English");
|
||||||
|
o.default = "ru";
|
||||||
|
|
||||||
|
|
||||||
o = section.taboption(
|
o = section.taboption(
|
||||||
"ai",
|
"ai",
|
||||||
|
|||||||
@@ -2941,6 +2941,43 @@ function diagnose_json() {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function compress_log_snippet(raw_snippet) {
|
||||||
|
if (!raw_snippet || raw_snippet == "") return "No recent system errors logged.";
|
||||||
|
let lines = split(raw_snippet, "\n");
|
||||||
|
let compressed = [];
|
||||||
|
let prev_line = "";
|
||||||
|
let repeat_cnt = 1;
|
||||||
|
|
||||||
|
for (let i = 0; i < length(lines); i++) {
|
||||||
|
let line = trim(as_string(lines[i]));
|
||||||
|
if (line == "") continue;
|
||||||
|
let normalized = replace(line, /^[A-Z][a-z]{2}\s+\d+\s+\d+:\d+:\d+\s+[^\s]+\s+/, "");
|
||||||
|
normalized = replace(normalized, /^\d{4}-\d{2}-\d{2}\s+\d+:\d+:\d+\s+/, "");
|
||||||
|
|
||||||
|
if (normalized == prev_line) {
|
||||||
|
repeat_cnt++;
|
||||||
|
} else {
|
||||||
|
if (prev_line != "") {
|
||||||
|
if (repeat_cnt > 1) {
|
||||||
|
push(compressed, sprintf("%s [repeated %dx]", lines[i-1], repeat_cnt));
|
||||||
|
} else {
|
||||||
|
push(compressed, lines[i-1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
prev_line = normalized;
|
||||||
|
repeat_cnt = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (prev_line != "" && length(lines) > 0) {
|
||||||
|
if (repeat_cnt > 1) {
|
||||||
|
push(compressed, sprintf("%s [repeated %dx]", lines[length(lines)-1], repeat_cnt));
|
||||||
|
} else {
|
||||||
|
push(compressed, lines[length(lines)-1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return join("\n", compressed);
|
||||||
|
}
|
||||||
|
|
||||||
function apply_quick_fix(codes_str) {
|
function apply_quick_fix(codes_str) {
|
||||||
if (!codes_str || codes_str == "") {
|
if (!codes_str || codes_str == "") {
|
||||||
print(sprintf("%J\n", { success: false, error: "No fix code provided" }));
|
print(sprintf("%J\n", { success: false, error: "No fix code provided" }));
|
||||||
@@ -3083,7 +3120,8 @@ function ai_doctor() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let log_snippet = trim(command_output("logread | grep -iE 'tachyon|sing-box|dnsmasq|oom|error|fatal' | tail -n 15 2>/dev/null")) || "No recent system errors logged.";
|
let raw_log_snippet = trim(command_output("logread | grep -iE 'tachyon|sing-box|dnsmasq|oom|error|fatal' | tail -n 25 2>/dev/null")) || "No recent system errors logged.";
|
||||||
|
let log_snippet = compress_log_snippet(raw_log_snippet);
|
||||||
|
|
||||||
let sys_context = sprintf(
|
let sys_context = sprintf(
|
||||||
"Tachyon Doctor Report:\n%s\n\n" +
|
"Tachyon Doctor Report:\n%s\n\n" +
|
||||||
@@ -3098,27 +3136,53 @@ function ai_doctor() {
|
|||||||
watchdog_info, log_snippet
|
watchdog_info, log_snippet
|
||||||
);
|
);
|
||||||
|
|
||||||
let prompt = sprintf(
|
let lang = lc(trim(cfg.ai_doctor_lang || "ru"));
|
||||||
"Вы — ИИ-ассистент \"Tachyon AI Doctor\" для сервиса обхода блокировок на OpenWrt.\n" +
|
let prompt = "";
|
||||||
"Проанализируйте диагностический отчет и логи ниже.\n\n%s\n\n" +
|
if (lang == "en") {
|
||||||
"Сформулируйте краткий диагноз (на русском, максимум 3-4 пункта).\n" +
|
prompt = sprintf(
|
||||||
"Если авто-исправление возможно, укажите в самом конце ответа строчку:\n" +
|
"You are \"Tachyon AI Doctor\", an AI assistant for anti-censorship and proxy services on OpenWrt.\n" +
|
||||||
"FIX: код1, код2\n\n" +
|
"Analyze the diagnostic report and system logs below.\n\n%s\n\n" +
|
||||||
"Доступные коды быстрого исправления:\n" +
|
"Formulate a concise diagnosis (in English, max 3-4 bullet points).\n" +
|
||||||
"- start_singbox (sing-box упал или остановлен)\n" +
|
"If automatic quick fix is possible, include at the very end of your response:\n" +
|
||||||
"- rebuild_rules (nftables или ip rule правила нарушены)\n" +
|
"FIX: code1, code2\n\n" +
|
||||||
"- fix_dnsmasq (конфиг или сервис dnsmasq не отвечает)\n" +
|
"Available quick fix codes:\n" +
|
||||||
"- fix_resolv_symlink (resolv.conf повреждён)\n" +
|
"- start_singbox (sing-box process is stopped or missing)\n" +
|
||||||
"- start_watchdog (watchdog остановлен)\n" +
|
"- rebuild_rules (nftables or ip rules damaged)\n" +
|
||||||
"- restart_singbox_dns (sing-box DNS не отвечает)\n" +
|
"- fix_dnsmasq (dnsmasq service not responding)\n" +
|
||||||
"- fix_uci_config (конфиг Tachyon повреждён)\n" +
|
"- fix_resolv_symlink (resolv.conf symlink broken)\n" +
|
||||||
"- fix_wan_interface (WAN интерфейс не работает)\n" +
|
"- start_watchdog (watchdog daemon stopped)\n" +
|
||||||
"- fix_gateway (шлюз отсутствует)\n" +
|
"- restart_singbox_dns (sing-box DNS failed)\n" +
|
||||||
"- clear_dns_cache (очистить кэш DNS и перезапустить dnsmasq)\n" +
|
"- fix_uci_config (Tachyon UCI config corrupted)\n" +
|
||||||
"- update_subscriptions (принудительно обновить прокси подписки)\n" +
|
"- fix_wan_interface (WAN interface down)\n" +
|
||||||
"- reset_firewall (перезапустить файрвол роутера)\n" +
|
"- fix_gateway (default gateway missing)\n" +
|
||||||
"- restart_network (перезапустить сетевой стек)\n\n" +
|
"- clear_dns_cache (clear DNS cache & restart dnsmasq)\n" +
|
||||||
"Если авто-исправление не применимо, не пишите тег FIX.", sys_context);
|
"- update_subscriptions (force update proxy subscriptions)\n" +
|
||||||
|
"- reset_firewall (restart router firewall)\n" +
|
||||||
|
"- restart_network (restart network service)\n\n" +
|
||||||
|
"If no quick fix applies, do NOT output any FIX tag.", sys_context);
|
||||||
|
} else {
|
||||||
|
prompt = sprintf(
|
||||||
|
"Вы — ИИ-ассистент \"Tachyon AI Doctor\" для сервиса обхода блокировок на OpenWrt.\n" +
|
||||||
|
"Проанализируйте диагностический отчет и логи ниже.\n\n%s\n\n" +
|
||||||
|
"Сформулируйте краткий диагноз (на русском, максимум 3-4 пункта).\n" +
|
||||||
|
"Если авто-исправление возможно, укажите в самом конце ответа строчку:\n" +
|
||||||
|
"FIX: код1, код2\n\n" +
|
||||||
|
"Доступные коды быстрого исправления:\n" +
|
||||||
|
"- start_singbox (sing-box упал или остановлен)\n" +
|
||||||
|
"- rebuild_rules (nftables или ip rule правила нарушены)\n" +
|
||||||
|
"- fix_dnsmasq (конфиг или сервис dnsmasq не отвечает)\n" +
|
||||||
|
"- fix_resolv_symlink (resolv.conf повреждён)\n" +
|
||||||
|
"- start_watchdog (watchdog остановлен)\n" +
|
||||||
|
"- restart_singbox_dns (sing-box DNS не отвечает)\n" +
|
||||||
|
"- fix_uci_config (конфиг Tachyon повреждён)\n" +
|
||||||
|
"- fix_wan_interface (WAN интерфейс не работает)\n" +
|
||||||
|
"- fix_gateway (шлюз отсутствует)\n" +
|
||||||
|
"- clear_dns_cache (очистить кэш DNS и перезапустить dnsmasq)\n" +
|
||||||
|
"- update_subscriptions (принудительно обновить прокси подписки)\n" +
|
||||||
|
"- reset_firewall (перезапустить файрвол роутера)\n" +
|
||||||
|
"- restart_network (перезапустить сетевой стек)\n\n" +
|
||||||
|
"Если авто-исправление не применимо, не пишите тег FIX.", sys_context);
|
||||||
|
}
|
||||||
|
|
||||||
let provider = cfg.ai_doctor_provider || "openai";
|
let provider = cfg.ai_doctor_provider || "openai";
|
||||||
let api_key = cfg.ai_doctor_api_key || "";
|
let api_key = cfg.ai_doctor_api_key || "";
|
||||||
|
|||||||
@@ -446,6 +446,165 @@ function handle_domain_add(body) {
|
|||||||
ok({ message: "Domain '" + domain + "' added to section '" + section + "'" });
|
ok({ message: "Domain '" + domain + "' added to section '" + section + "'" });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handle_openapi() {
|
||||||
|
let spec = {
|
||||||
|
openapi: "3.0.3",
|
||||||
|
info: {
|
||||||
|
title: "Tachyon Router AI Agent API",
|
||||||
|
description: "OpenAPI 3.0 REST API for managing Tachyon anti-censorship orchestration & AI Doctor on OpenWrt routers. Supports ChatGPT Custom GPTs, N8N, Dify, and LLM Agents.",
|
||||||
|
version: "1.0.0"
|
||||||
|
},
|
||||||
|
servers: [
|
||||||
|
{
|
||||||
|
url: "/cgi-bin/tachyon-agent",
|
||||||
|
description: "Tachyon Router Agent API Gateway"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
paths: {
|
||||||
|
"/health": {
|
||||||
|
get: {
|
||||||
|
summary: "System health check",
|
||||||
|
operationId: "getHealth",
|
||||||
|
responses: { "200": { description: "Health status" } }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/snapshot": {
|
||||||
|
get: {
|
||||||
|
summary: "Full system state snapshot for LLM context",
|
||||||
|
operationId: "getSnapshot",
|
||||||
|
responses: { "200": { description: "Complete system snapshot" } }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/diagnose": {
|
||||||
|
get: {
|
||||||
|
summary: "Run system diagnostics and auto-repair",
|
||||||
|
operationId: "getDiagnose",
|
||||||
|
responses: { "200": { description: "Diagnostic report" } }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/logs": {
|
||||||
|
get: {
|
||||||
|
summary: "Get recent system log entries",
|
||||||
|
operationId: "getLogs",
|
||||||
|
responses: { "200": { description: "System log lines" } }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/config": {
|
||||||
|
get: {
|
||||||
|
summary: "Get UCI configuration (secrets masked)",
|
||||||
|
operationId: "getConfig",
|
||||||
|
responses: { "200": { description: "UCI settings" } }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/tools": {
|
||||||
|
get: {
|
||||||
|
summary: "Get tool definitions in OpenAI Function Calling format",
|
||||||
|
operationId: "getTools",
|
||||||
|
responses: { "200": { description: "Tool schemas" } }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/ai-doctor/last": {
|
||||||
|
get: {
|
||||||
|
summary: "Get last AI Doctor diagnosis report",
|
||||||
|
operationId: "getAiDoctorLast",
|
||||||
|
responses: { "200": { description: "AI Doctor history report" } }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/heal": {
|
||||||
|
post: {
|
||||||
|
summary: "Trigger autonomous repair cycle",
|
||||||
|
operationId: "postHeal",
|
||||||
|
security: [{ BearerAuth: [] }],
|
||||||
|
responses: { "200": { description: "Repair initiated" } }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/ai-doctor/fix": {
|
||||||
|
post: {
|
||||||
|
summary: "Apply AI Doctor quick fix codes",
|
||||||
|
operationId: "postAiDoctorFix",
|
||||||
|
security: [{ BearerAuth: [] }],
|
||||||
|
requestBody: {
|
||||||
|
required: true,
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
fix: { type: "string", example: "clear_dns_cache,start_singbox" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
responses: { "200": { description: "Quick fix results" } }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/restart": {
|
||||||
|
post: {
|
||||||
|
summary: "Restart system service",
|
||||||
|
operationId: "postRestart",
|
||||||
|
security: [{ BearerAuth: [] }],
|
||||||
|
requestBody: {
|
||||||
|
required: true,
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
service: { type: "string", enum: ["singbox", "tachyon", "dnsmasq", "watchdog"] }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
responses: { "200": { description: "Restart outcome" } }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/reload": {
|
||||||
|
post: {
|
||||||
|
summary: "Reload firewall rules & configs",
|
||||||
|
operationId: "postReload",
|
||||||
|
security: [{ BearerAuth: [] }],
|
||||||
|
responses: { "200": { description: "Reload status" } }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/config/set": {
|
||||||
|
post: {
|
||||||
|
summary: "Set UCI configuration option",
|
||||||
|
operationId: "postConfigSet",
|
||||||
|
security: [{ BearerAuth: [] }],
|
||||||
|
requestBody: {
|
||||||
|
required: true,
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
section: { type: "string" },
|
||||||
|
option: { type: "string" },
|
||||||
|
value: { type: "string" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
responses: { "200": { description: "UCI update result" } }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
securitySchemes: {
|
||||||
|
BearerAuth: {
|
||||||
|
type: "http",
|
||||||
|
scheme: "bearer",
|
||||||
|
bearerFormat: "Secret Token"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
write_json(spec);
|
||||||
|
}
|
||||||
|
|
||||||
function handle_ai_doctor_last() {
|
function handle_ai_doctor_last() {
|
||||||
let raw = fs.readfile("/tmp/ai_doctor_last.json");
|
let raw = fs.readfile("/tmp/ai_doctor_last.json");
|
||||||
if (!raw) {
|
if (!raw) {
|
||||||
@@ -504,6 +663,8 @@ if (method == "GET") {
|
|||||||
handle_tools();
|
handle_tools();
|
||||||
else if (route == "/ai-doctor/last" || route == "/ai-doctor/last/")
|
else if (route == "/ai-doctor/last" || route == "/ai-doctor/last/")
|
||||||
handle_ai_doctor_last();
|
handle_ai_doctor_last();
|
||||||
|
else if (route == "/openapi.json" || route == "/openapi.json/")
|
||||||
|
handle_openapi();
|
||||||
else
|
else
|
||||||
err("Unknown endpoint: GET " + route, 404);
|
err("Unknown endpoint: GET " + route, 404);
|
||||||
} else if (method == "POST") {
|
} else if (method == "POST") {
|
||||||
|
|||||||
Reference in New Issue
Block a user