🌐 Languages: 🇺🇸 English · 🇪🇹 am · 🇸🇦 ar · 🇦🇿 az · 🇧🇬 bg · 🇧🇩 bn · 🇧🇦 bs · 🇨🇿 cs · 🇩🇰 da · 🇩🇪 de · 🇬🇷 el · 🇪🇸 es · 🇪🇪 et · 🇮🇷 fa · 🇫🇮 fi · 🇫🇷 fr · 🇮🇪 ga · 🇮🇳 gu · 🇳🇬 ha · 🇮🇱 he · 🇮🇳 hi · 🇭🇷 hr · 🇭🇺 hu · 🇦🇲 hy · 🇮🇩 id · 🇳🇬 ig · 🇮🇹 it · 🇯🇵 ja · 🇬🇪 ka · 🇰🇭 km · 🇮🇳 kn · 🇰🇷 ko · 🇱🇹 lt · 🇱🇻 lv · 🇮🇳 ml · 🇮🇳 mr · 🇲🇾 ms · 🇲🇹 mt · 🇲🇲 my · 🇳🇵 ne · 🇳🇱 nl · 🇳🇴 no · 🇮🇳 or · 🇮🇳 pa · 🇵🇭 phi · 🇵🇱 pl · 🇵🇹 pt · 🇧🇷 pt-BR · 🇷🇴 ro · 🇷🇺 ru · 🇱🇰 si · 🇸🇰 sk · 🇸🇮 sl · 🇷🇸 sr · 🇸🇪 sv · 🇮🇳 ta · 🇮🇳 te · 🇹🇭 th · 🇹🇷 tr · 🇺🇦 uk-UA · 🇵🇰 ur · 🇺🇿 uz · 🇻🇳 vi · 🇳🇬 yo · 🇨🇳 zh-CN · 🇹🇼 zh-TW
Toleo: v3.8.44 Ilisasishwa mara ya mwisho: 2026-09-09 Walengwa: Wahandisi wanaoongeza, wanaodumisha, au wanaotatua hitilafu za huduma zilizopachikwa (9Router, CLIProxyAPI, Mux, Bifrost, open-wa).
Huduma zilizopachikwa ni zana saidizi za michakato zilizosakinishwa ndani ya mashine ambazo OmniRoute husakinisha, husimamia, na huziwezesha kama malengo kamili ya uelekezaji. Tofauti na watoa huduma wa nje (ambao hufikiwa kupitia intaneti kwa kutumia funguo za API), huduma zilizopachikwa huendeshwa kwenye mashine ileile kama OmniRoute na huwasiliana kupitia loopback.
- Muhtasari
- Usanifu — tabaka 4
- Mashine ya hali ya mzunguko wa maisha
- Rejeleo la API
- Usalama
- Kuongeza huduma mpya iliyopachikwa
- Utatuzi wa matatizo
- Maswali Yanayoulizwa Mara kwa Mara
Huduma sita zimepachikwa:
| Huduma | Kifurushi cha npm | Porti chaguo-msingi | Kusudi |
|---|---|---|---|
| 9Router | 9router |
20130 | Kipanga njia cha AI ambacho OmniRoute inaweza kutumia kama mtoa huduma mdogo. Modeli zinafichuliwa kama 9router/{sub}/{model} |
| CLIProxyAPI | Faili tekelezi ya toleo la GitHub (cliproxy) |
8317 | Adapta ya proksi ya ndani kwa mitiririko ya uthibitishaji ya Anthropic CLI. Hutoa upangaji mbadala wa njia tokeni za OAuth zinapoisha muda wake |
| Mux | mux (mux server isiyo na kiolesura) |
8322 | Daemon ya ndani ya uratibu wa mawakala (coder/mux). Inadhibitiwa tu katika mzunguko wake wa uhai — si lengo la upangaji wa njia (hakuna uelekezaji wa proksi wa LLM). |
| Bifrost | @maximhq/bifrost |
8080 | Mfumo wa nyuma wa upelekaji wa lango la AI la Go. Unapofanya kazi, huchaguliwa kiotomatiki na njia ya upelekaji (/v1/relay/) |
| Dario | @askalf/dario |
3456 | Proksi ya usajili wa Claude — mbadala/hifadhi ya dharura ya CLIProxyAPI kwa trafiki yenye muundo wa Claude Code; ufunguo unaodungwa huwa DARIO_ADMIN_TOKEN inayodhibiti ufikiaji wa sehemu yake ya udhibiti ya OAuth ya /admin/* |
| open-wa | @open-wa/wa-automate |
8323 | Uendeshaji otomatiki wa WhatsApp Web (Chromium isiyo na kiolesura kupitia Puppeteer). Inadhibitiwa tu katika mzunguko wake wa uhai — si lengo la upangaji wa njia. |
Huduma zote sita hufuata modeli sawa ya usimamizi:
- OmniRoute huzisakinisha chini ya
DATA_DIR/services/{name}/(zikiwa zimetengwa napackage.jsonya OmniRoute) - OmniRoute huzianzisha na kuzifuatilia kama michakato-toto
- OmniRoute hudunga ufunguo wa API wa muda mfupi katika mazingira ya mchakato-toto na kuuzungusha bila muda wa huduma kutopatikana (panapohusika)
- Njia zote za usimamizi (
/api/services/*) ni LOCAL_ONLY — zinaweza kufikiwa tu kutoka loopback (kanuni thabiti #17)
| Uamuzi | Thamani |
|---|---|
| Ufikiaji wa dashibodi kwenye UI asilia ya 9Router | Proksi ya kinyume katika /dashboard/providers/services/9router/embed/* |
| Utaratibu wa usakinishaji | npm install {package} kupitia execFile (hakuna uingizaji wa shell) |
| Hali ya matumizi | Mtoa huduma amesajiliwa kama 9router/{sub}/{model} katika injini ya upangaji wa njia |
| Usimamizi wa ufunguo wa API | OmniRoute huzalisha, husimba kwa njia fiche wakati umehifadhiwa (AES-256-GCM), na hudunga kupitia env |
| Mahali pa dashibodi | /dashboard/providers/services (vichupo vitatu) |
| Uanzishaji otomatiki | Kitufe cha kuwasha/kuzima kwa kila huduma, chaguo-msingi KIMEZIMWA |
┌────────────────────────────────────────────────────────────────────┐
│ Tabaka la 1 — UI │
│ /dashboard/providers/services (vichupo: CLIProxyAPI | 9Router | Mux)│
│ Kumbukumbu mubashara (SSE), Anzisha/Simamisha/Anzisha upya/Sasisha, Mipangilio, Sakinisha│
│ │
│ src/app/(dashboard)/dashboard/providers/services/ │
│ ├── page.tsx Ganda + uelekezaji wa vichupo kwa ?tab=│
│ ├── tabs/ CliproxyServiceTab, NinerouterServiceTab,│
│ │ MuxServiceTab │
│ └── components/ ServiceStatusCard, ServiceLifecycleButtons,│
│ ServiceLogsPanel, ApiKeyCard, ... │
└──────────────────────┬─────────────────────────────────────────────┘
│ HTTP (Next.js fetch)
┌──────────────────────▼─────────────────────────────────────────────┐
│ Tabaka la 2 — API (LOCAL_ONLY — loopback pekee) │
│ │
│ /api/services/9router/{install|start|stop|restart|update| │
│ rotate-key|status|auto-start|logs} │
│ /api/services/cliproxy/{install|start|stop|restart|update| │
│ status|auto-start|logs} │
│ /api/services/mux/{install|start|stop|restart|update| │
│ status|auto-start|logs} │
│ /dashboard/providers/services/9router/embed/[...path] │
│ (proksi ya kinyume ya HTTP + WebSocket → seva chanzo ya 9Router)│
│ │
│ Lango: LOCAL_ONLY_API_PREFIXES inajumuisha "/api/services/" na │
│ "/dashboard/providers/services/*/embed/" │
└──────────────────────┬─────────────────────────────────────────────┘
│ miito ya ndani ya mchakato
┌──────────────────────▼─────────────────────────────────────────────┐
│ Tabaka la 3 — ServiceSupervisor (src/lib/services/) │
│ │
│ ServiceSupervisor.ts Msimamizi wa jumla (child_process.spawn) │
│ ├── install: execFile('npm', ['install', pkg, '--prefix']) │
│ ├── start: spawn(node, [entrypoint], {env, cwd}) │
│ ├── api_key: crypto.randomBytes(32) → env NINEROUTER_API_KEY │
│ ├── port: 20130 kwa 9Router (inaweza kusanidiwa) │
│ ├── logs: bafa ya mzunguko ya stdio ya MB 5 → matukio ya SSE│
│ ├── health: HTTP GET /health kila sekunde 2–5, urejeshaji wa polepole│
│ └── lifecycle: SIGTERM sekunde 15 → SIGKILL │
│ │
│ registry.ts getSupervisor(name) / registerSupervisor() │
│ bootstrap.ts Huanzisha SERVICES[] zote mchakato unapoanza │
│ apiKey.ts getOrCreateApiKey(), generateServiceApiKey() │
│ modelSync.ts GET /v1/models ya mara kwa mara → jedwali la service_models│
│ ringBuffer.ts Bafa ya kumbukumbu ya mzunguko (MB 5 kwa kila huduma)│
│ healthCheck.ts Uchunguzi wa afya wa HTTP kwa upigaji kura │
│ installers/ ninerouter.ts, cliproxy.ts, mux.ts, openwa.ts │
│ (adapta za usakinishaji) │
└──────────────────────┬─────────────────────────────────────────────┘
│ HTTP inayooana na OpenAI (loopback)
┌──────────────────────▼─────────────────────────────────────────────┐
│ Tabaka la 4 — Mtoa huduma / Uelekezaji │
│ │
│ open-sse/executors/ninerouter.ts │
│ Hutafuta upya porti na ufunguo wa API kwa kila ombi (hakuna uhifadhi wa muda).│
│ Huondoa kiambishi awali cha "9router/" kwenye kitambulisho cha modeli kabla ya kupeleka kwa proksi.│
│ Hurejesha 503 service_not_running ikiwa msimamizi hayuko katika hali ya "running".│
│ │
│ src/shared/constants/providers.ts │
│ Ingizo la "9router": isEmbeddedService: true │
│ │
│ open-sse/config/providerRegistry.ts │
│ Modeli huhifadhiwa kama "9router/{sub}/{model}" (zenye kiambishi awali).│
│ Husawazishwa kila dakika 5 na modelSync.ts. │
│ │
│ Mux inadhibitiwa mzunguko wa uhai PEKEE (Tabaka la 1-3) — ni daemoni ya│
│ uratibu wa mawakala, si proksi ya LLM, kwa hivyo haina kitekelezaji/│
│ ingizo la mtoa huduma la Tabaka la 4 na kamwe hailengwi na uelekezaji.│
└────────────────────────────────────────────────────────────────────┘
| Faili | Jukumu |
|---|---|
src/lib/services/ServiceSupervisor.ts |
Darasa kuu: mzunguko wa maisha, kufunga, afya, bafa ya mzunguko |
src/lib/services/bootstrap.ts |
Usajili wa kiwango cha mchakato na uanzishaji wa kiotomatiki |
src/lib/services/registry.ts |
Ramani ya singleton zana → msimamizi |
src/lib/services/apiKey.ts |
Uundaji wa ufunguo, usimbaji fiche wa AES-256-GCM wakati wa kuhifadhi |
src/lib/services/modelSync.ts |
Usawazishaji wa modeli wa mara kwa mara (dakika 5) + unapohitajika |
src/lib/services/ringBuffer.ts |
Bafa ya kumbukumbu ya mzunguko ya MB 5 yenye usajili wa SSE |
src/lib/services/healthCheck.ts |
Uchunguzi wa afya wa HTTP (muda unaweza kusanidiwa) |
src/lib/services/installers/ninerouter.ts |
Usakinishaji/usasishaji/uondoaji wa 9Router kwa npm |
src/lib/services/installers/cliproxy.ts |
Usakinishaji/usasishaji/uondoaji wa CLIProxyAPI kwa npm |
src/lib/services/installers/mux.ts |
Usakinishaji/usasishaji/uondoaji wa Mux kwa npm |
src/lib/services/installers/openwa.ts |
Usakinishaji/usasishaji/uondoaji wa open-wa kwa npm |
src/app/api/services/9router/_lib.ts |
Kitendaji saidizi cha getOrInitSupervisor() |
src/app/api/services/[name]/logs/route.ts |
Endpoint ya pamoja ya kumbukumbu za SSE |
open-sse/executors/ninerouter.ts |
Kitekelezaji cha mtoa huduma (Tabaka la 4) |
install()
┌─────────────┐ ──────────► ┌─────────────┐
│ not_installed│ │ stopped │◄──────────────────┐
└─────────────┘ └──────┬──────┘ │
│ start() │
▼ │ stop()
┌──────────┐ │
│ starting │ │
└────┬─────┘ │
uchunguzi wa afya sawa │ hitilafu / SIGTERM│
┌────▼─────┐ (hutoka ndani ya s 5)│
│ running │─── hitilafu ─────────►┤
└────┬─────┘ ┌─▼────┐
stop() │ │error │
▼ └──────┘
┌──────────┐
│ stopping │
└──────────┘
Hali huhifadhiwa katika jedwali la DB la version_manager (safu ya status) na huakisiwa
katika hali ya ndani ya kumbukumbu ya ServiceSupervisor. Hali ya ndani ya kumbukumbu ndiyo yenye mamlaka kwa
mchakato unaoendelea; hali ya DB ndiyo mbadala endelevu wakati wa kuwasha mfumo.
| Kutoka | Tukio | Kwenda |
|---|---|---|
not_installed |
install() inafanikiwa |
stopped |
stopped |
start() inaitwa |
starting |
starting |
uchunguzi wa afya unarudisha 200 | running |
starting |
mchakato unatoka kabla ya kuwa salama kiafya | error |
running |
stop() inaitwa |
stopping → stopped |
running |
mchakato unatoka bila kutarajiwa (< s 5) | error (hitilafu ya haraka) |
running |
mchakato unatoka bila kutarajiwa (> s 5) | error |
error |
start() inaitwa |
starting |
| yoyote | stop() wakati wa stopping |
hakuna operesheni |
ServiceSupervisor hupanga operesheni za mzunguko wa maisha kwa mfuatano kupitia kufuli ya operesheni isiyosawazishwa
(withLock()). Miito ya wakati mmoja ya start() kwenye msimamizi yuleyule husababisha
uanzishaji wa mchakato mmoja tu; mwitaji wa pili husubiri na kurudisha hali iliyopo. Hii huzuia
hali za mashindano wakati, kwa mfano, uanzishaji otomatiki na kitufe cha UI vinapotumika kwa wakati mmoja.
Njia zote zilizo chini ya /api/services/ ni LOCAL_ONLY (loopback pekee, kanuni thabiti #17).
Maombi yasiyo ya loopback hupokea 403 LOCAL_ONLY bila kujali tokeni ya uthibitishaji.
Sakinisha 9Router kutoka npm. Huunda DATA_DIR/services/9router/ yenye
package.json na node_modules/ zake yenyewe. Haikinzani na vitegemezi vya OmniRoute.
Mwili wa ombi (vyote si lazima):
{ "version": "latest" }| Sehemu | Aina | Chaguo-msingi | Maelezo |
|---|---|---|---|
version |
string |
"latest" |
Lebo ya toleo la npm au semver ya kusakinisha |
Majibu:
| Hali | Maelezo |
|---|---|
200 |
{ ok: true, installedVersion: "x.y.z", path: "..." } |
400 |
Mwili batili wa ombi (uthibitishaji wa Zod umeshindwa) |
409 |
Usakinishaji tayari unaendelea (kufuli limeshikiliwa) |
500 |
Usakinishaji wa npm umeshindwa — tazama message kwa hitilafu inayoeleweka |
Vidokezo: Hutumia execFile('npm', [...]) — hakuna shell, hakuna uchopekaji (kanuni thabiti #13).
Hitilafu za EACCES huwasilishwa kama ujumbe unaoeleweka.
Anzisha 9Router. Husajili msimamizi ikiwa bado hajasajiliwa, kisha huita
supervisor.start(). Ni idempotenti ikiwa tayari inaendelea.
Mwili wa ombi: hakuna
Majibu:
| Hali | Maelezo |
|---|---|
200 |
Kitu cha ServiceStatus (tazama schema hapa chini) |
409 |
9Router haijasakinishwa (status: "not_installed") |
503 |
Uanzishaji umeshindwa (hitilafu ya mchakato — tazama lastError) |
Schema ya ServiceStatus:
{
"tool": "9router",
"state": "running",
"pid": 12345,
"port": 20130,
"health": "healthy",
"startedAt": "2026-05-25T10:00:00.000Z",
"lastError": null
}Simamisha 9Router kwa utaratibu salama. Hutuma SIGTERM, husubiri sekunde 15, kisha SIGKILL ikiwa bado inaendelea. Ni idempotenti ikiwa tayari imesimama.
Mwili wa ombi: hakuna
Majibu:
| Hali | Maelezo |
|---|---|
200 |
ServiceStatus (state: "stopped") |
503 |
Usimamishaji umeshindwa bila kutarajiwa |
Ni sawa na stop() ikifuatwa na start() chini ya kufuli la operesheni.
Mwili wa ombi: hakuna
Majibu: sawa na start (hurejesha ServiceStatus ya mwisho).
Husasisha 9Router hadi toleo jipya zaidi la npm. Ikiwa huduma inaendelea, husimamishwa kwanza, usakinishaji wa npm huendeshwa (ikisakinisha toleo jipya mahali palepale), kisha huduma huanzishwa upya.
Mwili wa ombi (vyote si lazima):
{ "version": "latest" }Majibu:
| Hali | Maelezo |
|---|---|
200 |
{ ok: true, previousVersion: "...", installedVersion: "..." } |
400 |
Mwili batili |
500 |
Usasishaji wa npm umeshindwa |
Hutengeneza ufunguo mpya wa API kwa ajili ya 9Router, huusimba ukiwa umehifadhiwa, na huanzisha upya huduma (ikiwa inaendelea) ili ichukue ufunguo mpya kutoka kwenye mazingira yake. Ufunguo wa zamani hubatilishwa mara moja.
Mwili wa ombi: hakuna
Majibu:
| Hali | Maelezo |
|---|---|
200 |
{ keyRotated: true, restarted: boolean } |
500 |
Ubadilishaji wa ufunguo umeshindwa |
Usalama: Ufunguo mpya haurudishwi kamwe kwenye jibu (hakuna uvujaji wa kitambulisho).
Huhifadhiwa ukiwa umesimbwa (AES-256-GCM) katika jedwali la version_manager.
Hurejesha hali iliyounganishwa ya moja kwa moja + DB, ikijumuisha metadata ya toleo na onyesho la awali la ufunguo wa API.
Majibu:
| Hali | Maelezo |
|---|---|
200 |
Tazama schema hapa chini |
500 |
Usomaji wa hali umeshindwa |
Schema ya jibu:
{
"tool": "9router",
"state": "running",
"pid": 12345,
"port": 20130,
"health": "healthy",
"startedAt": "2026-05-25T10:00:00.000Z",
"lastError": null,
"installedVersion": "1.2.3",
"latestVersion": "1.2.4",
"updateAvailable": true,
"apiKeyMasked": "nr_****abcd",
"autoStart": false,
"providerExpose": false
}Badilisha hali ya alama ya kuanzisha kiotomatiki. Wakati enabled: true, huduma huanza kiotomatiki
OmniRoute itakapowashwa wakati ujao (ikiwa huduma imesakinishwa).
Mwili wa ombi:
{ "enabled": true }Majibu:
| Hali | Maelezo |
|---|---|
200 |
{ autoStart: true } |
400 |
Mwili batili |
Mtiririko wa SSE wa kumbukumbu za moja kwa moja kutoka kwenye bafa ya mzunguko ya stdout/stderr ya 9Router.
Vigezo vya hoja:
| Kigezo | Aina | Chaguo-msingi | Maelezo |
|---|---|---|---|
tail |
integer |
200 | Idadi ya mistari ya kihistoria ya kutuma kwanza (kiwango cha juu 1000) |
filter |
string |
hakuna | Kichujio cha kifungu kidogo kisichojali herufi kubwa au ndogo (hakuna regex — salama dhidi ya ReDoS) |
Matukio ya SSE:
| Tukio | Data | Maelezo |
|---|---|---|
snapshot |
LogLine[] |
Sehemu ya mwisho ya historia ya awali |
log |
LogLine |
Mstari wa kumbukumbu wa moja kwa moja |
heartbeat |
{} |
Kudumisha muunganisho kila sekunde 15 |
Schema ya LogLine:
{
"ts": 1716633600000,
"stream": "stdout",
"line": "[9router] Listening on :20130"
}Majibu:
| Hali | Maelezo |
|---|---|
200 |
text/event-stream |
400 |
Kigezo cha filter ni kirefu mno (> herufi 200) |
404 |
Huduma haijapatikana (msimamizi hajasajiliwa) |
CLIProxyAPI ina muundo sawa wa vituo vya mwisho na 9Router isipokuwa rotate-key, pamoja na
accounts, provider-expose na auto-restart-adopted. Sasa inapokea ufunguo
maalumu wa API wa safu ya data unaowekwa wakati wa kuanzishwa (needsApiKey: true katika
bootstrap.ts, unaotumika kusawazisha modeli); status inajumuisha sehemu chache zaidi.
| Mbinu | Njia | Maelezo |
|---|---|---|
POST |
/api/services/cliproxy/install |
Sakinisha CLIProxyAPI kutoka npm |
POST |
/api/services/cliproxy/start |
Anzisha CLIProxyAPI |
POST |
/api/services/cliproxy/stop |
Simamisha CLIProxyAPI |
POST |
/api/services/cliproxy/restart |
Anzisha upya CLIProxyAPI |
POST |
/api/services/cliproxy/update |
Sasisha hadi toleo jipya zaidi |
GET |
/api/services/cliproxy/status |
Hali ya moja kwa moja + DB (bila apiKeyMasked) |
POST |
/api/services/cliproxy/auto-start |
Washa au zima uanzishaji otomatiki |
Kituo cha mwisho kinachoshirikiwa cha GET /api/services/{name}/logs (tazama §4.1) hufanya kazi kwa
huduma zote nne kwa kutumia sehemu badilifu ya [name].
Mux ina muundo sawa wa vituo vya mwisho na CLIProxyAPI — hakuna njia ya rotate-key katika
kiolesura cha API (tokeni ya bearer huzalishwa kwa njia sawa na ya 9Router kupitia
getOrCreateApiKey("mux") na kuwekwa kupitia kigezo cha mazingira cha MUX_SERVER_AUTH_TOKEN, lakini
bado hakuna kituo maalumu cha mwisho cha kuizungusha). Mux inadhibitiwa tu katika mzunguko wake wa maisha: tofauti na
9Router, haina kitekelezaji cha Safu ya 4 na kamwe haisajiliwi kama mtoa huduma wa uelekezaji.
| Mbinu | Njia | Maelezo |
|---|---|---|
POST |
/api/services/mux/install |
Sakinisha Mux kutoka npm (npm i mux) |
POST |
/api/services/mux/start |
Anzisha Mux (mux server) |
POST |
/api/services/mux/stop |
Simamisha Mux |
POST |
/api/services/mux/restart |
Anzisha upya Mux |
POST |
/api/services/mux/update |
Sasisha hadi toleo jipya zaidi la npm |
GET |
/api/services/mux/status |
Hali ya moja kwa moja + DB |
POST |
/api/services/mux/auto-start |
Washa au zima uanzishaji otomatiki |
Bifrost ni mfumo wa nyuma wa relay wa lango la AI ulioandikwa kwa Go (@maximhq/bifrost). Hutumia
muundo sawa wa vituo vya mwisho na CLIProxyAPI (hakuna rotate-key — Bifrost hudhibiti funguo zake
za watoa huduma katika config.json chini ya -app-dir yake).
| Mbinu | Njia | Maelezo |
|---|---|---|
POST |
/api/services/bifrost/install |
Sakinisha Bifrost kutoka npm (@maximhq/bifrost) |
POST |
/api/services/bifrost/start |
Anzisha Bifrost kwenye porti 8080 (chaguo-msingi) |
POST |
/api/services/bifrost/stop |
Simamisha Bifrost |
POST |
/api/services/bifrost/restart |
Anzisha upya Bifrost |
POST |
/api/services/bifrost/update |
Sasisha hadi toleo jipya zaidi |
GET |
/api/services/bifrost/status |
Hali ya moja kwa moja + DB |
POST |
/api/services/bifrost/auto-start |
Washa au zima uanzishaji otomatiki |
GET |
/api/services/bifrost/logs |
Mwisho wa kumbukumbu wa SSE (kupitia njia badilifu inayoshirikiwa ya [name]/logs) |
Muunganisho wa uelekezaji: Wakati BIFROST_BASE_URL haijawekwa na nakala ya Bifrost
inayosimamiwa inaendeshwa, getBifrostRoutingConfig() (katika routingBackend.ts) hutumia
kiotomatiki http://127.0.0.1:{port} kama URL msingi ya relay. Kigezo cha mazingira cha
BIFROST_BASE_URL kilichowekwa wazi hupewa kipaumbele kila wakati.
Muundo wa mzunguko wa maisha ni sawa na wa huduma nyingine (install, start, stop, restart,
update, status, auto-start, auto-restart-adopted) pamoja na safu ya udhibiti ya OAuth
inayolindwa kwa tokeni chini ya admin/: admin/accounts, admin/import-from-omniroute,
admin/login-start, admin/login-complete (zote zikiwa nyuma ya DARIO_ADMIN_TOKEN).
open-wa (@open-wa/wa-automate) huendesha nakala ya Chromium isiyo na kiolesura cha picha (kupitia
Puppeteer) ili kuendesha WhatsApp Web kiotomatiki. Hutumia muundo sawa wa vituo vya mwisho na Mux (bado hakuna
njia ya rotate-key). Inadhibitiwa tu katika mzunguko wake wa maisha — si lengwa la uelekezaji,
haina ingizo la kitekelezaji/mtoa huduma wa Safu ya 4.
| Mbinu | Njia | Maelezo |
|---|---|---|
POST |
/api/services/openwa/install |
Sakinisha open-wa kutoka npm (@open-wa/wa-automate) |
POST |
/api/services/openwa/start |
Anzisha open-wa kwenye porti 8323 (chaguo-msingi) |
POST |
/api/services/openwa/stop |
Simamisha open-wa |
POST |
/api/services/openwa/restart |
Anzisha upya open-wa |
POST |
/api/services/openwa/update |
Sasisha hadi toleo jipya zaidi |
GET |
/api/services/openwa/status |
Hali ya moja kwa moja + DB |
POST |
/api/services/openwa/auto-start |
Washa au zima uanzishaji wa kiotomatiki |
GET |
/api/services/openwa/logs |
Mwisho wa kumbukumbu wa SSE (kupitia njia badilifu ya pamoja ya [name]/logs) |
Ufunguo wa API: huingizwa kama WA_KEY — ubatilishaji wa jumla wa mazingira wa open-wa wenye kiambishi awali cha WA_*
huuweka kwenye chaguo la CLI la --key/-k
(dist/cli/setup.js::envArgs(), imethibitishwa dhidi ya package iliyosakinishwa ya 4.76.0).
Huongezewa kiambishi awali cha ow_ unapozalishwa na generateServiceApiKey(). open-wa
husoma tena ufunguo kutoka kwenye kichwa cha HTTP cha key/api_key (si Authorization: Bearer); /api-docs* imeondolewa waziwazi kwenye ukaguzi
(setupAuthenticationLayer katika dist/cli/server.js), kwa hivyo uchunguzi wa afya
hauhitaji kichwa cha uthibitishaji.
Uoanishaji: open-wa si rasmi na haina uhusiano na WhatsApp — namba iliyounganishwa ina hatari ya kupigwa marufuku kutokana na utambuzi wa WhatsApp wenyewe wa otomatiki. Inapoanzishwa kwa mara ya kwanza, msimbo wa QR wa uoanishaji huchapishwa kwenye stdout na kuonyeshwa kupitia paneli iliyopo ya Kumbukumbu/mfululizo wa SSE — bado hakuna endpoint maalum ya picha ya QR katika muunganisho huu.
Dashibodi hupachika UI ya wavuti ya 9Router ndani ya iframe kupitia proksi ya ndani ya kinyume kwenye:
GET|POST|... /dashboard/providers/services/9router/embed/[...path]
Proksi hii:
- Husambaza ombi kwenda
http://127.0.0.1:{port}/{path}(loopback pekee) - Huondoa vichwa vinavyoingia vya
cookienaauthorization(hakuna kuvuja kwa kipindi cha OmniRoute) - Huingiza
Authorization: Bearer {apiKey}kwa ajili ya uthibitishaji wa 9Router - Huondoa
set-cookie,content-security-policy,x-frame-options,cross-origin-*kutoka kwenye jibu - Huandika upya majibu ya HTML ili kuingiza
<base href>na kusawazisha njia kamili (/foo→/dashboard/.../embed/foo)
Masasisho ya WebSocket kwa dashibodi iliyopachikwa hushughulikiwa na seva saidizi kwenye
porti maalum (tazama src/lib/services/embedWsProxy.ts).
Usalama: Njia za proksi ya upachikaji zimeainishwa chini ya LOCAL_ONLY_API_PREFIXES
na zinaweza kufikiwa kutoka loopback pekee. Mshambulizi anayepata JWT kupitia
handaki la Cloudflare/Ngrok hawezi kuingia kwenye huduma zilizopachikwa kupitia proksi.
Njia zote zilizo chini ya /api/services/ na /dashboard/providers/services/*/embed/
zinaainishwa kama LOCAL_ONLY katika src/server/authz/routeGuard.ts. Ukaguzi wa loopback
huendeshwa bila masharti kabla ya tawi lolote la uthibitishaji:
ombi linawasili
→ isLocalOnlyPath(path)?
→ si loopback → 403 LOCAL_ONLY (daima, kabla ya ukaguzi wa uthibitishaji)
→ loopback → endelea hadi uthibitishaji wa kawaida
Hii huzuia JWT iliyovuja (kwa mfano, kupitia tunnel) kuanzisha npm install au
kuanzisha michakato. Tazama docs/security/ROUTE_GUARD_TIERS.md kwa matriki kamili
ya viwango.
9Router na Mux zinahitaji ufunguo wa API/tokeni ya bearer kwa endpoint zao za HTTP. OmniRoute:
- Hutengeneza ufunguo kupitia
crypto.randomBytes(32).toString("base64url")wenye kiambishi awali mahususi kwa huduma (nr_kwa 9Router,mx_kwa Mux). - Huusimba kwa njia fiche ukiwa umehifadhiwa kwa kutumia AES-256-GCM (algoriti ileile ya usimbaji inayotumika kwa vitambulisho vya watoa huduma).
- Huusimbua na kuuingiza kama kigezo cha mazingira wakati wa kuanzisha mchakato —
NINEROUTER_API_KEYkwa 9Router,MUX_SERVER_AUTH_TOKENkwa Mux (kamwe si chaguo la CLI, hivyo tokeni haionekani kamwe katikaps/orodha za michakato). - Hairudishi kamwe ufunguo wa maandishi wazi katika jibu lolote la HTTP.
CLIProxyAPI hupokea ufunguo maalumu wa data-plane unaoingizwa wakati wa kuanzisha mchakato
(needsApiKey: true — hutumika kwa ulandanishaji wa modeli dhidi ya adapter).
Proksi ya HTTP ya kinyume (/dashboard/.../embed/[...path]) imewekwa moja kwa moja kuelekeza
tu kwa http://127.0.0.1:{port}. Haifuati kamwe uelekezaji upya kwenda kwenye
maeneo yasiyo ya loopback. Maktaba ya ssrf-req-filter hutumika kukataa URL yoyote ya upstream ambayo
hutatuliwa nje ya masafa ya loopback.
npm install huitwa kupitia execFile('npm', ['install', pkg, '--prefix', dir]) —
hakuna template literals, hakuna shell, wala uingizaji wa njia za nje katika mfuatano wa
amri. Thamani za wakati wa utekelezaji (porti, funguo za API) hupitishwa kupitia kitu cha env cha mchakato mtoto.
Majibu yote ya hitilafu kutoka /api/services/* hupitia buildErrorBody() au
sanitizeErrorMessage(). err.stack na err.message ghafi hazirudishwi kamwe
kama zilivyo kwa mwombaji.
Fuata hatua hizi 8. Soma utekelezaji uliopo katika src/lib/services/installers/
na src/app/api/services/ kama marejeleo rasmi.
Unda src/lib/services/installers/{name}.ts kwa kufuata muundo wa ninerouter.ts:
export const NAME_PACKAGE = "your-npm-package";
export const NAME_DEFAULT_PORT = 20132; // chagua porti iliyo wazi
export async function install(version = "latest"): Promise<InstallResult> { ... }
export async function update(version = "latest"): Promise<InstallResult> { ... }
export async function uninstall(): Promise<void> { ... }
export function resolveSpawnArgs(apiKey: string, port: number): SpawnArgs { ... }
export async function getInstalledVersion(): Promise<string | null> { ... }
export async function getLatestVersion(): Promise<string | null> { ... }Tumia runNpm(['install', NAME_PACKAGE, '--prefix', dir]) kutoka installers/utils.ts
— kamwe usitumie execSync au uingizaji wa thamani kupitia shell.
Ongeza ServiceEntry kwenye safu ya SERVICES katika src/lib/services/bootstrap.ts:
{
tool: "myservice",
port: NAME_DEFAULT_PORT,
healthPath: "/health",
healthIntervalMs: 5_000,
stopTimeoutMs: 15_000,
logsBufferBytes: 5_242_880,
needsApiKey: true, // false ikiwa ufunguo wa API hauhitajiki
}Panua buildSpawnArgsFactory() ili kushughulikia cfg.tool === "myservice".
src/lib/services/providerPlugins/ inaanzisha mkataba wa ServiceProviderPlugin ambao
huunganisha sehemu za ServiceEntry za bootstrap.ts ya backend na sehemu za kiolezo cha manifest za serviceBackends.ts
kuwa kitu kimoja, badala ya muundo wa backend ileile kuwakilishwa
kando katika faili mbili zisizohusiana. Kufikia wakati huu wa uandishi ni 9router pekee
iliyohamishwa — bootstrap.ts huzalisha ingizo lake la SERVICES[] kutoka
getServiceProviderPlugin("9router") (src/lib/services/providerPlugins/registry.ts),
na kutoa hitilafu ya uanzishaji ikiwa plugin hiyo itakosekana. cliproxy, mux, na bifrost
zinasalia bila kubadilishwa kwenye literal za SERVICES[] za ndani zilizokuwepo awali.
open-sse/config/providerPluginManifest.ts pia imepata kitendaji saidizi cha nyongeza cha
createServiceBackendManifestEntry(pluginId, template) ambacho huunda
ProviderPluginManifestEntry yenye muundo sahihi kutoka kwenye ingizo la SERVICE_BACKEND_MANIFEST_TEMPLATE — bado
hakijaunganishwa kwenye njia yoyote hai ya maombi (si generateProviderPluginManifestFromRegistry()
wala /v1/providers/[provider]/models); hilo litasubiri kazi ya ufuatiliaji baada ya mkataba
kuthibitishwa kwa backend ya pili.
Yaliyoahirishwa hadi PR za ufuatiliaji, yanayofuatiliwa chini ya suala #7333: kuhamisha cliproxyapi kupitia
registry ileile, kufanya mux/bifrost kuwa za jumla ndani ya muungano wa ServiceBackendPluginId,
kuunganisha hali maalumu za uelekezaji wa executor (open-sse/executors/index.ts,
open-sse/handlers/chatCore/executorProxy.ts) ndani ya mkataba wa plugin, na kuunganisha
createServiceBackendManifestEntry() kwenye njia hai ya msimbo ya manifest/modeli.
Hakikisha huduma ina safu katika version_manager kupitia uhamishaji katika
src/lib/db/migrations/. Safu hiyo inapaswa kuwa na:
INSERT OR IGNORE INTO version_manager (tool, status, auto_start, provider_expose)
VALUES ('myservice', 'not_installed', 0, 0);Chini ya src/app/api/services/{name}/:
_lib.ts kitendaji saidizi cha getOrInitSupervisor()
install/route.ts POST — huita installer.install()
start/route.ts POST — huita supervisor.start()
stop/route.ts POST — huita supervisor.stop()
restart/route.ts POST — huita supervisor.restart()
update/route.ts POST — huita installer.update()
status/route.ts GET — huunganisha hali ya moja kwa moja + hali ya DB
auto-start/route.ts POST — hubadilisha hali ya alama ya auto_start
Njia ya pamoja ya GET /api/services/[name]/logs tayari imeunganishwa — hakuna mabadiliko
yanayohitajika hapo.
Kabidhi majibu yote ya hitilafu kupitia createErrorResponse() / buildErrorBody().
Katika src/server/authz/routeGuard.ts, hakikisha kwamba /api/services/ tayari imeorodheshwa.
Ukiweka kiambishi awali kipya (kwa mfano, /api/tools/), kiongeze kwenye
LOCAL_ONLY_API_PREFIXES na, ikiwa kinaanzisha michakato, kwenye SPAWN_CAPABLE_PREFIXES.
Ongeza jaribio katika tests/unit/authz/routeGuard.test.ts.
Unda src/app/(dashboard)/dashboard/providers/services/tabs/{Name}ServiceTab.tsx.
Tumia tena vijenzi vya pamoja:
ServiceStatusCard— hali ya moja kwa moja + beji ya afyaServiceLifecycleButtons— Anzisha / Simamisha / Anzisha upya / SasishaServiceLogsPanel— mwendelezo wa kumbukumbu za SSE (huunganisha kwenye/api/services/{name}/logs)ApiKeyCard— onyesha ufunguo + badilisha (ikiwaneedsApiKey: true)
Sajili kichupo katika ServicesPageShell.tsx.
Ikiwa huduma iliyopachikwa inafichua endpoint ya /v1/chat/completions inayooana na OpenAI:
- Ongeza ingizo la mtoa huduma katika
src/shared/constants/providers.tslenyeisEmbeddedService: true. - Unda
open-sse/executors/{name}.tsinayopanuaBaseExecutor. Tafuta upya porti na ufunguo wa API kwa kila ombi (usivihifadhi kamwe kwenye constructor). Rudisha jibu la503 service_not_runningwakati hali ya msimamizi si"running". - Sajili modeli katika
open-sse/config/providerRegistry.tsukitumia kiambishi awali cha huduma (kwa mfano,myservice/sub/model).modelSync.tsitazisasisha.
- Sasisha
docs/frameworks/EMBEDDED-SERVICES.md(faili hii) — ongeza huduma kwenye jedwali katika §1 na endpoint zozote mpya kwenye §4. - Ongeza majaribio ya kitengo katika
tests/unit/services/(mzunguko wa maisha, kisakinishaji, muundo wa API). - Ongeza jaribio la ujumuishaji katika
tests/integration/services/(nyuma yaRUN_SERVICES_INT=1). - Sasisha
docs/openapi.yamlkwa endpoint mpya.
Dalili: Kitufe cha kuanzisha kinarejesha 503, hali inabaki "error" au "starting".
Orodha ya ukaguzi:
- Angalia
GET /api/services/{name}/logs(au paneli ya Kumbukumbu kwenye dashibodi). Tafuta mistari kamaError: ENOENT,address already in use, auCannot find module. - Thibitisha kuwa
npmiko katika PATH: tumiawhich npmkutoka kwenye akaunti ileile ya mtumiaji inayoendesha OmniRoute. - Thibitisha kuwa huduma imesakinishwa: angalia
GET /api/services/{name}/statuskwainstalledVersion. Ikiwa ninull, endesha usakinishaji kwanza. - Angalia kuwa
DATA_DIR/services/{name}/node_modules/ipo na si tupu. - Angalia uga wa
lastErrorkatika jibu la hali ili kuona sababu ya kusitishwa iliyosafishwa.
Dalili: Hali inabaki "starting" kwa muda mrefu kabla ya kubadilika kuwa "running" au "error".
Maelezo: Uanzishaji wa kwanza wa 9Router unajumuisha kuleta miti mikubwa ya vitegemezi (DNS, tunnel, moduli za MITM). Kipindi chaguo-msingi cha ukaguzi wa afya ni sekunde 2, huku majaribio 3 yakifanywa kabla msimamizi hajatangaza kuisha kwa muda (lakini anaendelea kufanya ukaguzi).
Suluhisho: healthIntervalMs na muda wa kuisha wa waitForHealthy
(healthIntervalMs * 3) zinaweza kusanidiwa katika bootstrap.ts. Kwa huduma zenye muda mrefu zaidi
wa kuanza, ongeza healthIntervalMs hadi 5000 na stopTimeoutMs hadi 30 000.
Dalili: Kumbukumbu zinaonyesha address already in use :::20130.
Sababu:
- Mchakato mwingine tayari unatumia mlango 20130.
- Mchakato wa awali wa 9Router haukusimamishwa kikamilifu (PID mfu).
Suluhisho:
- Badilisha mlango chaguo-msingi kupitia kigezo cha mazingira cha
NINEROUTER_PORTkatika.env. - Tafuta na usitishe mchakato unaogongana:
lsof -ti :20130 | xargs kill -9. - Mlango unaweza kusanidiwa kwa kila huduma katika
bootstrap.tskupitia uga waport.
Kumbuka: 9Router hutumia mlango 20130 kwa chaguo-msingi mahsusi ili kuepuka kugongana na mlango chaguo-msingi wa OmniRoute wa 20128.
Dalili: Usakinishaji unarejesha 500, kumbukumbu zinaonyesha EACCES au permission denied.
Sababu:
DATA_DIRau saraka kuu yake haiwezi kuandikwa na mchakato wa OmniRoute.- Inaendeshwa ndani ya Docker rootless bila ruhusa ya kuandika kwenye volume iliyounganishwa.
Suluhisho:
- Angalia
DATA_DIR(chaguo-msingi:~/.omniroute/):ls -la ~/.omniroute/ - Hakikisha mtumiaji wa mchakato wa OmniRoute anamiliki saraka:
chown -R $USER ~/.omniroute/ - Katika Docker, hakikisha volume mount ina ruhusa sahihi kwa mtumiaji wa container.
Dalili: Usasishaji unarejesha 500 ikiwa na InstallError, kumbukumbu zinaonyesha kuisha kwa muda wa mtandao.
Orodha ya ukaguzi:
- Thibitisha kuwa sajili ya npm inaweza kufikiwa:
npm ping. - Angalia kama kuna proksi ya shirika:
npm config get proxy,npm config get https-proxy. - Jaribu usakinishaji mwenyewe:
npm install {package}@latest --prefix ~/.omniroute/services/{name}/. - Ikiwa uko nyuma ya air-gap, pakua tarball mapema na utumie
npm install /path/to/tarball.tgz.
Dalili: Hali inabadilika kutoka "starting" hadi "error" ndani ya chini ya sekunde 5.
lastError inaonyesha "Fast crash (exited with code 1)".
Orodha ya ukaguzi:
- Soma sehemu kamili ya mwisho ya kumbukumbu:
GET /api/services/{name}/logs?tail=500. - Sababu ya kawaida: kukosekana kwa vigezo vya mazingira vinavyotarajiwa na huduma.
- Kwa 9Router: thibitisha kuwa
NINEROUTER_DISABLE_MITM=truenaNINEROUTER_DISABLE_TUNNEL=truezimo katika env inayopitishwa wakati wa spawn (angaliainstallers/ninerouter.tsresolveSpawnArgs).
Swali: Je, ninaweza kufichua endpoint za huduma zilizopachikwa kwa wateja wasio wa loopback?
Hapana. Ngazi ya LOCAL_ONLY imekusudiwa hivyo (sheria ngumu #17). Routes zinazoweza kutekeleza
npm install au kuanzisha michakato ya node lazima zisifikiwe na trafiki isiyo ya loopback,
kwa sababu JWT iliyovuja kupitia tunnel (Cloudflare, Ngrok, Tailscale) ingeweza
kuruhusu kuanzishwa kwa michakato kiholela. Hakuna msamaha wa hiari kwa
/api/services/ — tofauti na /api/mcp/, haijumuishwi kwenye orodha ya kupita
ukaguzi wa manage-scope. Angalia docs/security/ROUTE_GUARD_TIERS.md.
Swali: Je, 9Router na CLIProxyAPI zitapatikana katika upelekaji wa uzalishaji/cloud?
Ndiyo. Huduma zote mbili zinafuata muundo uleule unaotanguliza mazingira ya ndani kama OmniRoute yenyewe. Huendeshwa kwenye mashine hiyo hiyo na kuwasiliana kupitia loopback. "Uzalishaji" hapa unamaanisha VPS au seva ya ndani ambako OmniRoute imepelekwa, si mtoa huduma wa cloud wa mbali.
Swali: Ninawezaje kutatua hitilafu za supervisor?
- Fuatilia mtiririko wa logi wa SSE:
curl -N http://localhost:20128/api/services/9router/logs. - Kagua logi zilizoundwa kwa muundo katika matokeo ya pino ya OmniRoute, yaliyochujwa kwa
namespace ya
service:supervisor. - Kagua safu ya DB:
sqlite3 ~/.omniroute/omniroute.db "SELECT * FROM version_manager WHERE tool='9router'". - Tumia
GET /api/services/9router/statuskuona hali ya sasa ya moja kwa moja, PID, afya, nalastErrorkwa ombi moja.
Swali: Supervisor inaonyesha health: "degraded" au health: "unknown" lakini hali ni "running". Je, hilo ni tatizo?
"degraded" inamaanisha uchunguzi wa afya ulirudisha jibu lisilo la 200. "unknown" inamaanisha hakuna
uchunguzi ambao umekamilika bado (mkanganyiko wa muda na upigaji kura wa kwanza). Hali zote mbili ni za muda wakati wa kuanza.
Ikiwa afya itaendelea kuwa "degraded" kwa zaidi ya ms healthIntervalMs * 3 baada ya
"running", huduma iliyopachikwa inaendeshwa lakini HTTP API yake haijibu. Kagua
ikiwa port ni sahihi katika jibu la hali na ikiwa huduma kwa hakika
inasikiliza kwenye port hiyo.
Swali: Je, ninaweza kubadilisha ufunguo wa API wa 9Router bila kuanzisha upya kikamilifu?
Hapana. Ufunguo wa API hupitishwa kwa 9Router kupitia environment variable wakati wa kuanzisha mchakato.
Environment variables haziwezi kubadilishwa katika mchakato unaoendelea. POST .../rotate-key
husimamisha na kuanzisha upya huduma kiotomatiki ili kutumia ufunguo mpya. Mzunguko wa ufunguo
unaanza kutumika ndani ya stopTimeoutMs ya huduma (chaguo-msingi sekunde 15) pamoja na muda wake
wa kuanza.
Swali: Kikomo cha ring buffer ni kipi na nini hutokea inapojaa?
Kila huduma ina ring buffer yake maalumu ya MB 5. Buffer inapojaa, mistari ya zamani zaidi
ya logi huondolewa ili kutoa nafasi kwa mipya. Tukio la SSE snapshot hurudisha
mistari ya hivi karibuni zaidi ndani ya kikomo cha tail. Logi hazihifadhiwi kwenye diski isipokuwa
logsBufferPath iwe imewekwa katika safu ya DB.
docs/security/ROUTE_GUARD_TIERS.md— maelezo ya ngazi ya LOCAL_ONLYdocs/architecture/CODEBASE_DOCUMENTATION.md— §3.2 ulinganishaji wa moduli ya Huduma Zilizopachikwadocs/architecture/ARCHITECTURE.md— muktadha wa kiwango cha mfumodocs/openapi.yaml— ufafanuzi wa endpoint unaosomeka na mashineCLAUDE.md§"Adding a New Embedded Service" — orodha ya ukaguzi ya marejeleo ya haraka