Control UI (เบราว์เซอร์)
Control UI เป็นแอป single-page ขนาดเล็ก Vite + Lit ที่เสิร์ฟโดย Gateway:
- ค่าเริ่มต้น:
http://<host>:18789/ - คำนำหน้าตัวเลือก: ตั้งค่า
gateway.controlUi.basePath(เช่น/mayros)
มันพูดคุย โดยตรงกับ Gateway WebSocket บนพอร์ตเดียวกัน
เปิดอย่างรวดเร็ว (โลคัล)
หาก Gateway ทำงานบนคอมพิวเตอร์เดียวกัน ให้เปิด:
หากหน้าเว็บโหลดไม่ได้ ให้เริ่ม Gateway ก่อน: mayros gateway
การพิสูจน์ตัวตนถูกจัดหาระหว่างการจับมือ WebSocket ผ่าน:
connect.params.auth.tokenconnect.params.auth.passwordแผงการตั้งค่าแดชบอร์ดให้คุณเก็บโทเค็น รหัสผ่านไม่ถูกเก็บถาวร วิซาร์ด onboarding สร้างโทเค็น gateway ตามค่าเริ่มต้น ดังนั้นวางมันที่นี่ในการเชื่อมต่อครั้งแรก
การจับคู่อุปกรณ์ (การเชื่อมต่อครั้งแรก)
เมื่อคุณเชื่อมต่อกับ Control UI จากเบราว์เซอร์หรืออุปกรณ์ใหม่ Gateway
ต้องการ การอนุมัติการจับคู่ครั้งเดียว — แม้ว่าคุณจะอยู่บน Tailnet เดียวกัน
กับ gateway.auth.allowTailscale: true นี่เป็นมาตรการรักษาความปลอดภัยเพื่อป้องกัน
การเข้าถึงที่ไม่ได้รับอนุญาต
สิ่งที่คุณจะเห็น: "disconnected (1008): pairing required"
เพื่ออนุมัติอุปกรณ์:
bash# แสดงคำขอที่รอดำเนินการ mayros devices list # อนุมัติโดย request ID mayros devices approve <requestId>
เมื่ออนุมัติแล้ว อุปกรณ์จะถูกจดจำและจะไม่ต้องการการอนุมัติอีกเว้นแต่
คุณเพิกถอนมันด้วย mayros devices revoke --device <id> --role <role> ดู
Devices CLI สำหรับการหมุนเวียนโทเค็นและการเพิกถอน
หมายเหตุ:
- การเชื่อมต่อโลคัล (
127.0.0.1) ได้รับการอนุมัติอัตโนมัติ - การเชื่อมต่อระยะไกล (LAN, Tailnet, ฯลฯ) ต้องการการอนุมัติที่ชัดเจน
- แต่ละโปรไฟล์เบราว์เซอร์สร้าง device ID ที่ไม่ซ้ำ ดังนั้นการสลับเบราว์เซอร์หรือ ล้างข้อมูลเบราว์เซอร์จะต้องการการจับคู่อีกครั้ง
สิ่งที่มันสามารถทำได้ (วันนี้)
- แชทกับโมเดลผ่าน Gateway WS (
chat.history,chat.send,chat.abort,chat.inject) - สตรีมการเรียกเครื่องมือ + การ์ดเอาต์พุตเครื่องมือสดใน Chat (เหตุการณ์ agent)
- ช่องทาง: WhatsApp/Telegram/Discord/Slack + ช่องทางปลั๊กอิน (Mattermost, ฯลฯ) สถานะ + การล็อกอิน QR + การตั้งค่าต่อช่องทาง (
channels.status,web.login.*,config.patch) - Instances: รายการ presence + รีเฟรช (
system-presence) - เซสชัน: รายการ + การแทนที่ thinking/verbose ต่อเซสชัน (
sessions.list,sessions.patch) - งาน Cron: รายการ/เพิ่ม/รัน/เปิดใช้งาน/ปิดใช้งาน + ประวัติการรัน (
cron.*) - Skills: สถานะ เปิดใช้งาน/ปิดใช้งาน ติดตั้ง การอัปเดต API key (
skills.*) - โหนด: รายการ + capabilities (
node.list) - การอนุมัติ Exec: แก้ไข allowlists ของ gateway หรือโหนด + นโยบายการขอสำหรับ
exec host=gateway/node(exec.approvals.*) - การตั้งค่า: ดู/แก้ไข
~/.mayros/mayros.json(config.get,config.set) - การตั้งค่า: ใช้ + รีสตาร์ทพร้อมการตรวจสอบความถูกต้อง (
config.apply) และปลุกเซสชันที่ active ล่าสุด - การเขียนการตั้งค่ามี base-hash guard เพื่อป้องกันการเขียนทับการแก้ไขที่เกิดขึ้นพร้อมกัน
- สคีมาการตั้งค่า + การเรนเดอร์ฟอร์ม (
config.schemaรวมถึงสคีมาปลั๊กอินและช่องทาง); ตัวแก้ไข Raw JSON ยังคงใช้งานได้ - Debug: สถานะ/สุขภาพ/โมเดล snapshots + บันทึกเหตุการณ์ + การเรียก RPC ด้วยตนเอง (
status,health,models.list) - บันทึก: ติดตามสดของบันทึกไฟล์ gateway พร้อมตัวกรอง/ส่งออก (
logs.tail) - อัปเดต: รันการอัปเดต package/git + รีสตาร์ท (
update.run) พร้อมรายงานการรีสตาร์ท
หมายเหตุแผง Cron jobs:
- สำหรับ isolated jobs delivery จะ default เป็นการประกาศสรุป คุณสามารถเปลี่ยนเป็น none ได้หากต้องการรันภายในเท่านั้น
- ฟิลด์ช่องทาง/เป้าหมายจะปรากฏเมื่อเลือก announce
- โหมด Webhook ใช้
delivery.mode = "webhook"กับdelivery.toที่ตั้งค่าเป็น URL webhook HTTP(S) ที่ถูกต้อง - สำหรับ main-session jobs โหมดการส่ง webhook และ none พร้อมใช้งาน
- ตั้งค่า
cron.webhookTokenเพื่อส่ง bearer token เฉพาะ หากไม่ระบุ webhook จะถูกส่งโดยไม่มี auth header - Deprecated fallback: stored legacy jobs กับ
notify: trueยังคงใช้cron.webhookได้จนกว่าจะย้าย
พฤติกรรมแชท
chat.sendเป็น non-blocking: มันตอบรับทันทีด้วย{ runId, status: "started" }และการตอบกลับสตรีมผ่านเหตุการณ์chat- การส่งซ้ำด้วย
idempotencyKeyเดียวกันส่งคืน{ status: "in_flight" }ในขณะที่รัน และ{ status: "ok" }หลังจากเสร็จสิ้น chat.historyresponses มีขนาดจำกัดเพื่อความปลอดภัยของ UI เมื่อ transcript entries ใหญ่เกินไป Gateway อาจตัดฟิลด์ข้อความยาว ลบบล็อก metadata หนัก และแทนที่ข้อความขนาดใหญ่เกินไปด้วย placeholder ([chat.history omitted: message too large])chat.injectแนบโน้ต assistant ไปยัง transcript เซสชันและออกอากาศเหตุการณ์chatสำหรับการอัปเดต UI เท่านั้น (ไม่มีการรัน agent ไม่มีการส่งช่องทาง)- หยุด:
- คลิก Stop (เรียก
chat.abort) - พิมพ์
/stop(หรือstop|esc|abort|wait|exit|interrupt) เพื่อยกเลิก out-of-band chat.abortรองรับ{ sessionKey }(ไม่มีrunId) เพื่อยกเลิกการรันที่ active ทั้งหมดสำหรับเซสชันนั้น
- คลิก Stop (เรียก
- การเก็บรักษาบางส่วนเมื่อยกเลิก:
- เมื่อการรันถูกยกเลิก ข้อความ assistant บางส่วนยังคงแสดงใน UI ได้
- Gateway เก็บข้อความ assistant บางส่วนที่ถูกยกเลิกลงในประวัติ transcript เมื่อมี buffered output
- รายการที่เก็บรวมเมตาดาต้าการยกเลิกเพื่อให้ผู้บริโภค transcript สามารถแยกแยะ abort partials จากผลลัพธ์การเสร็จสิ้นปกติ
การเข้าถึง Tailnet (แนะนำ)
Integrated Tailscale Serve (ต้องการ)
เก็บ Gateway ไว้ที่ loopback และให้ Tailscale Serve พร็อกซีมันด้วย HTTPS:
bashmayros gateway --tailscale serve
เปิด:
https://<magicdns>/(หรือgateway.controlUi.basePathที่คุณกำหนดค่า)
ตามค่าเริ่มต้น Control UI/WebSocket Serve requests สามารถพิสูจน์ตัวตนผ่าน Tailscale identity headers
(tailscale-user-login) เมื่อ gateway.auth.allowTailscale เป็น true Mayros
ตรวจสอบ identity โดยการ resolve ที่อยู่ x-forwarded-for ด้วย
tailscale whois และจับคู่กับ header และยอมรับเหล่านี้เฉพาะเมื่อ
request มาถึง loopback พร้อมกับ Tailscale x-forwarded-* headers ตั้งค่า
gateway.auth.allowTailscale: false (หรือบังคับ gateway.auth.mode: "password")
หากคุณต้องการให้ต้องมีโทเค็น/รหัสผ่านแม้สำหรับ Serve traffic
Tokenless Serve auth ถือว่า gateway host เชื่อถือได้ หากโค้ดโลคัลที่ไม่เชื่อถือ
อาจรันบนโฮสต์นั้น ให้ต้องการ token/password auth
ผูกกับ tailnet + โทเค็น
bashmayros gateway --bind tailnet --token "$(openssl rand -hex 32)"
จากนั้นเปิด:
http://<tailscale-ip>:18789/(หรือgateway.controlUi.basePathที่คุณกำหนดค่า)
วางโทเค็นลงในการตั้งค่า UI (ส่งเป็น connect.params.auth.token)
HTTP ที่ไม่ปลอดภัย
หากคุณเปิดแดชบอร์ดผ่าน HTTP ธรรมดา (http://<lan-ip> หรือ http://<tailscale-ip>)
เบราว์เซอร์ทำงานใน non-secure context และบล็อก WebCrypto ตามค่าเริ่มต้น
Mayros บล็อก การเชื่อมต่อ Control UI โดยไม่มีอัตลักษณ์อุปกรณ์
แก้ไขที่แนะนำ: ใช้ HTTPS (Tailscale Serve) หรือเปิด UI ในโลคัล:
https://<magicdns>/(Serve)http://127.0.0.1:18789/(บนโฮสต์ gateway)
พฤติกรรม insecure-auth toggle:
json5{ gateway: { controlUi: { allowInsecureAuth: true }, bind: "tailnet", auth: { mode: "token", token: "replace-me" }, }, }
allowInsecureAuth ไม่ bypass Control UI device identity หรือการตรวจสอบการจับคู่
Break-glass เท่านั้น:
json5{ gateway: { controlUi: { dangerouslyDisableDeviceAuth: true }, bind: "tailnet", auth: { mode: "token", token: "replace-me" }, }, }
dangerouslyDisableDeviceAuth ปิดใช้งานการตรวจสอบ device identity ของ Control UI และเป็น
ความปลอดภัยที่ลดระดับลงอย่างรุนแรง คืนค่าอย่างรวดเร็วหลังจากการใช้งานฉุกเฉิน
ดู Tailscale สำหรับคำแนะนำการตั้งค่า HTTPS
การสร้าง UI
Gateway เสิร์ฟไฟล์แบบคงที่จาก dist/control-ui สร้างพวกเขาด้วย:
bashpnpm ui:build # ติดตั้ง UI deps อัตโนมัติในการรันครั้งแรก
Base สัมบูรณ์ตัวเลือก (เมื่อคุณต้องการ URL asset คงที่):
bashMAYROS_CONTROL_UI_BASE_PATH=/mayros/ pnpm ui:build
สำหรับการพัฒนาในโลคัล (เซิร์ฟเวอร์พัฒนาแยก):
bashpnpm ui:dev # ติดตั้ง UI deps อัตโนมัติในการรันครั้งแรก
จากนั้นชี้ UI ไปที่ Gateway WS URL ของคุณ (เช่น ws://127.0.0.1:18789)
การดีบัก/ทดสอบ: dev server + Gateway ระยะไกล
Control UI เป็นไฟล์แบบคงที่; เป้าหมาย WebSocket สามารถกำหนดค่าได้และอาจ แตกต่างจาก HTTP origin นี่สะดวกเมื่อคุณต้องการ Vite dev server ในโลคัลแต่ Gateway ทำงานที่อื่น
- เริ่ม UI dev server:
pnpm ui:dev - เปิด URL เช่น:
texthttp://localhost:5173/?gatewayUrl=ws://<gateway-host>:18789
การพิสูจน์ตัวตนครั้งเดียว (หากจำเป็น):
texthttp://localhost:5173/?gatewayUrl=wss://<gateway-host>:18789&token=<gateway-token>
หมายเหตุ:
gatewayUrlถูกเก็บใน localStorage หลังจากโหลดและถูกลบออกจาก URLtokenถูกเก็บใน localStorage;passwordถูกเก็บในหน่วยความจำเท่านั้น- เมื่อตั้งค่า
gatewayUrlUI จะไม่ fall back ไปที่ config หรือ environment credentials ให้ระบุtoken(หรือpassword) อย่างชัดเจน credentials ที่ขาดหายไปที่ชัดเจนคือ error - ใช้
wss://เมื่อ Gateway อยู่หลัง TLS (Tailscale Serve, HTTPS proxy, ฯลฯ) gatewayUrlยอมรับเฉพาะในหน้าต่างระดับบนสุด (ไม่ฝัง) เพื่อป้องกัน clickjacking- สำหรับ cross-origin dev setups (เช่น
pnpm ui:devไปยัง Gateway ระยะไกล) เพิ่ม UI origin ไปที่gateway.controlUi.allowedOrigins
ตัวอย่าง:
json5{ gateway: { controlUi: { allowedOrigins: ["http://localhost:5173"], }, }, }
รายละเอียดการตั้งค่าการเข้าถึงระยะไกล: การเข้าถึงระยะไกล