Work: พื้นที่ทำงานแบบแยก
Work คือ UI agent เขียนโปรแกรมในตัวของ Libre WebUI แต่ละ task รวม conversation แบบคงอยู่ route ของ provider ที่ชัดเจน และ filesystem /workspace แยก โมเดลดูและแก้ file รัน command ใน Docker container หรือ Kubernetes Pod ของ task และเริ่ม preview ได้
Work ทำงานแบบ native โดยไม่ใช้ Libre Claw หรือ daemon แยก
API ทั้งหมดต้องใช้ account ที่ยืนยันตัวตนและมีสิทธิ์ ค่าเริ่มต้นเฉพาะ administrator แต่เปิดให้ user ที่ active ทั้งหมดได้ Folder ของ host จำกัดเฉพาะ administrator เพราะ mount path ของ server Work ตั้งใจให้รัน shell command ใดก็ได้ใน sandbox Task ใช้ egress เว้นแต่ policy ที่เลือกปิด network ให้ถือ user ทุกคนที่ได้รับอนุญาตเป็น operator runtime ที่เชื่อถือได้ ไม่ใช่เพียง user chat
ความสามารถหลักของรุ่น
- Mode Work และ Chat แยก พร้อม selector ที่มองเห็น
- Task ในรายการข้างหลัก ตำแหน่งคงที่ และลบโดยตรง
- Identity sandbox แยก พร้อม Docker volume แบบคงอยู่หรือ Kubernetes PVC ต่อ task; หยุด/สร้าง environment ใหม่ได้โดยไม่เสีย file
- เก็บ conversation, state ของ run, activity ของ tool, การเลือกโมเดล และ owner ของ task ในฐานข้อมูล Libre WebUI
- Stream ที่ยืนยันตัวตนสำหรับข้อความ assistant, reasoning ที่ provider เปิดเผย, tool call/result, usage, skill และการเปลี่ยน state
- Workflow skill ของ server สอนโมเดลให้ inspect, edit, test และเริ่ม preview โดยไม่สร้าง file ควบคุมใน project
- โมเดล Ollama local ที่มี tool, Ollama Cloud และ plugin provider ที่ตั้งค่าแล้ว
- แบ่ง Conversation/Workspace แบบปรับได้ resize ด้วย mouse/keyboard บน desktop และ switch บนหน้าจอเล็ก
- View Files, Activity, Git, Terminal, Preview, Screen ในตัว; Screen แสดง desktop Work Computer
- Syntax highlighting โหมดสว่าง/มืด formatting ใน browser ตรวจ save conflict และ draft ชั่วคราว
- Data disclosure ต่อ user ที่ปิดได้เมื่อเลือก provider remote
- แปล Work ครบ 25 ภาษา รวม layout RTL ภาษาอาหรับแบบ native โดยรักษา LTR สำหรับ code, path, model ID และ output
หน่วยที่คงอยู่คือ workspace ของ task ไม่ใช่ container ที่รันตลอด Libre เริ่ม หยุด และสร้าง container ใหม่เมื่อจำเป็นโดยเก็บ named volume
สถาปัตยกรรม
Libre WebUI ไม่ใช่โมเดลหรือ browser เป็นผู้เลือกชื่อ sandbox/workspace, image, volume mount, user, ขีดจำกัด, network mode และ preview port โมเดลได้รับเฉพาะ tool ต่อไปนี้:
list_filesread_filewrite_filedelete_filemove_filesearch_filesrun_commandstart_previewstop_preview
delete_file และ move_file ออกจาก workspace ไม่ได้ ไม่ตาม symlink ต้องมี recursive flag ชัดเจนสำหรับ directory และไม่เขียนทับ destination เพราะใช้ file helper tool จึงทำงานใน preview ได้แม้ run_command ถูกบล็อก
Request ของโมเดลทำโดย server ไม่ใช่ container Work จึงไม่ขึ้นกับ network policy ของ container
ข้อกำหนด
- Docker: daemon ติดตั้งและเข้าถึงได้ process ของ server มีสิทธิ์เรียก
dockerหรือ program ในWORK_DOCKER_COMMAND - Kubernetes: API credential Role/RoleBinding จำกัด namespace, namespace sandbox และ NetworkPolicies ที่ Helm สร้างเมื่อ
work.enabled=true
นอกจากนี้:
- โมเดลที่มี tool ผ่าน Ollama/Ollama Cloud ที่พร้อมใช้งาน หรือ plugin completion/chat active พร้อมโมเดลที่ตรงและ credential administrator
- Memory เพียงพอสำหรับ image environment, project และ dependency local
- Account ที่ยืนยันตัวตนและมีสิทธิ์ Work; ค่าเริ่มต้นเฉพาะ administrator แต่เปิดให้ user active ทั้งหมดได้
Libre ตรวจ capability ของ Ollama และปฏิเสธโมเดลที่ไม่มี tools โมเดล plugin ต้องรองรับ protocol tool-calling ของ provider ความล้มเหลวจะจบ run โดยไม่ fallback แบบเงียบ
รันในเครื่อง
วิธีง่ายที่สุดบนเครื่องเดียว:
docker info
npx libre-webui@latest
เปิด http://localhost:8080 login เป็น administrator เลือก Work และโมเดลที่เข้ากัน แล้วอธิบาย task
หากไม่มี Docker หรือเข้าถึงไม่ได้ Work แสดง Runtime unavailable พร้อมเหตุผลและปิดการเริ่ม Command จะไม่รันโดยตรงบน host
ครั้งแรกจะตรวจ image environment และ download อัตโนมัติหากไม่มี จึงอาจใช้เวลานานขึ้น
UI ของ Work
สร้างและเปิดอีกครั้ง
เลือก Work ป้อนคำสั่ง เลือกโมเดล แล้วกด Run message แรกสร้าง task, run แรก, route ของ provider และ workspace คงอยู่
Task อยู่ใน sidebar หลัก เปิดอีกครั้งจะคืน conversation ล่าสุด tab Files, provider/model ปัจจุบัน และ workspace Message เก่า load เป็นหน้า เปลี่ยนชื่อจาก title และลบผ่าน menu/sidebar ได้
มี run active ได้เพียงหนึ่งรายการต่อ task คำสั่งถัดไปใช้ conversation และ filesystem เดิม
Composer รองรับการบอกข้อความ ปุ่ม microphone ใช้ speech API ของ browser หรือโมเดลรู้จำเสียงที่ตั้งค่า และเพิ่ม transcript ลงใน text File ที่สร้าง/ย้ายแสดงเป็น badge ที่คลิกได้ใต้ action ของ tool คลิกเปิด editor และสลับไป workspace บนหน้าจอแคบ มีเพียง tool ที่แก้ไขเท่านั้นสร้าง badge ดังนั้น read 20 ครั้งและ write 1 ครั้งจะแสดง artifact หนึ่งรายการ
จ้างเป็น Agent
หากมี persona คำสั่ง Hire as agent เปลี่ยน task เป็น agent ที่มีชื่อและคงอยู่ Persona อยู่ระหว่าง run ชื่อและ system prompt มาก่อน prompt Work แต่ contract ของ sandbox มีลำดับสูงสุด Sidebar วาง agent ในกลุ่ม Agents เหนือ task ครั้งเดียว พร้อม avatar, activity และ state เมื่อย่อ sidebar จะเหลือเฉพาะ avatar ของ agent ที่ปักหมุดไว้ในแถบ rail ส่วน task Work แบบครั้งเดียวจะกลับมาเมื่อขยาย sidebar อีกครั้ง
บรรทัด state มีสองระดับ หลัง run ของ agent จะมี request โมเดลราคาต่ำแบบไม่มี tool เพื่อขอ status ราว 8 คำ (“กล่องข้อความว่าง มี 2 คำตอบพร้อมแล้ว”) response จำกัดหนึ่งบรรทัด 90 ตัว หาก error/timeout ใช้บรรทัดแรกของคำตอบสุดท้าย Task ครั้งเดียวและ run ที่ล้มเหลวใช้ fallback แบบ deterministic นี้ WORK_STATUS_BLURB_MODEL=0 ปิด request การเปิด task จะเลื่อน marker viewed แบบ monotonic ที่ sync ระหว่างอุปกรณ์ จุดหมายถึง terminal run ที่ใหม่กว่า
Agent รายงานงานผ่าน notification: work-run-finished, work-run-attention, work-takeover Banner ของ Screen เห็นเฉพาะ tab ที่เปิด push notification ไปถึง user ที่อื่น ลิงก์แต่ละรายการไปยัง agent โดยตรง
ใช้ persona ของตนหรือ shared ได้ view แบบ shared ไม่เปิด memory ของ owner หากลบ persona agent จะทำงานต่อโดยไม่มีและบันทึก warning API รับ personaId, isAgent task ที่มี persona จะเป็น agent อัตโนมัติ
Tab Agent
Tab เพิ่มแรกคือ Agent:
- Identity: avatar, ชื่อ, indicator activity และบรรทัด state ล่าสุด
- Screen: หากมี Work Computer จะแสดง thumbnail live แบบ read-only นี่คือ connection เต็มที่นับใน limit คลิกเปิด full screen พร้อม takeover, teaching และ audio
- Routines: automation ที่ผูกกับ task แต่ละ trigger รันใน workspace/conversation เดิมด้วย model/environment ของ agent ไม่ใช่ task ใหม่ จึงสะสม morning report ที่เดียว บรรทัดแสดง schedule และ pause toggle form + Routine ผูกกับ agent แล้ว Trigger ขณะ agent ยุ่งจะจบด้วย
work-task-busyโดยไม่เข้าคิว - Auto Review: สวิตช์ approval ของ agent และ rule Always-allow ที่ agent สะสมไว้ (ลบ rule เพื่อปิดขอบเขตนั้นอีกครั้ง) เมื่อ policy ของ task บังคับให้ review สวิตช์จะถูกล็อกเป็นเปิด
- Taught skills: routine ที่สาธิตแล้วพร้อม enable toggle
เครื่องมือที่เชื่อมต่อ (เซิร์ฟเวอร์ MCP และ OpenAPI)
Agent ของ Work เรียกใช้ เซิร์ฟเวอร์เครื่องมือ ชุดเดียวกับที่ตั้งค่าไว้สำหรับแชตได้ ทั้ง MCP และ OpenAPI ซึ่ง administrator ลงทะเบียนไว้ที่ การตั้งค่า → เครื่องมือ เครื่องมือจะปรากฏต่อ agent ด้วยชื่อที่มี namespace (server__tool) และการเรียกจะรันจาก backend ของ Libre WebUI ผ่าน gateway เครื่องมือที่เสริมความแข็งแรงแล้ว (egress กัน SSRF, credential ต่อ user, จำกัดขนาดและเวลา) ไม่เคยรันจากในกล่อง sandbox
รายการที่เสนอตรงไปตรงมาว่ารันแบบอัตโนมัติใช้อะไรได้จริง:
- Task ที่ออฟไลน์จะไม่ได้เครื่องมือใดเลย: แม้ egress จะออกจาก backend แต่ task ที่ไม่มี network ก็ยังออฟไลน์ ด้วยเหตุผลเดียวกับ
web_search - เซิร์ฟเวอร์ที่ต้องใช้ credential ส่วนตัวซึ่งผู้ใช้ยังไม่ได้บันทึกจะ ถูกกรองออกตั้งแต่ตอนเสนอเครื่องมือ เพราะการรันแบบอัตโนมัติหยุดเพื่อถามไม่ได้ เพิ่ม credential ที่ การตั้งค่า → เครื่องมือ แล้วการรันครั้งถัดไปจะเสนอเซิร์ฟเวอร์นั้น
- โหมดการเข้าถึงเครื่องมือ (เฉพาะ administrator หรือผู้ใช้ทุกคน) และการมองเห็นรายเซิร์ฟเวอร์ใช้เหมือนในแชตทุกประการ และการผูกเซิร์ฟเวอร์เครื่องมือของเพอร์โซนาจะจำกัดว่า agent ที่จ้างจากเพอร์โซนานั้นเห็นเซิร์ฟเวอร์ใดบ้าง
- เมื่อ การอนุมัติ ทำงานอยู่ เครื่องมือที่เชื่อมต่อซึ่งเซิร์ฟเวอร์จัดว่า มีผลข้างเคียง จะหยุดรอการตัดสินใจของคุณเหมือนการกระทำที่ถูกกำกับอื่น ๆ ส่วนเครื่องมือที่อ่านอย่างเดียวจะรันโดยไม่ถาม
การมอบหมายระหว่าง agent (@-mention)
Agent ที่จ้างไว้ส่งงานให้กันได้ พิมพ์ @ ในช่องเขียนของ Work เพื่อกล่าวถึง agent ตัวอื่นของคุณ agent ปัจจุบันจะเห็นรายชื่อเพื่อนร่วมงาน (ชื่อและบรรทัด state) ในคำสั่งของตน แล้วมอบหมายคำขอที่ตรงกันด้วยเครื่องมือ message_agent การมอบหมายคือการประสานงานด้วยข้อความ ไม่ใช่การใช้เครื่องร่วมกันโดยตั้งใจ: agent แต่ละตัวมี workspace และ sandbox ของตัวเอง และปลายทางมองไม่เห็นบทสนทนาที่มอบหมาย คำขอจึงต้องพก context ของตัวเองมาด้วย
การมอบหมายเป็นแบบอะซิงโครนัส เครื่องมือคืนค่าทันที agent ปลายทางรันใน task ของตัวเอง (บทสนทนาของมันแสดงคำขอที่ติดป้าย Delegated by ผู้ส่ง) และเมื่อทำเสร็จ ไม่ว่าจะสำเร็จ ต้องการ input ผิดพลาด หรือถูกยกเลิก คำตอบสุดท้ายจะถูกส่งกลับเข้าบทสนทนาของ agent ผู้มอบหมายเป็นข้อความที่ติดป้าย Report from agent นั้น หากผู้มอบหมายยังรันอยู่ รายงานจะถึงโมเดลใน round ถัดไป หากว่างอยู่ รายงานก็จะรออยู่ในบทสนทนาเฉย ๆ รายงานจะไม่เริ่มรันเองโดยอัตโนมัติ agent สองตัวจึงโยนงานไปมาไม่ได้ รอบที่ถูกมอบหมายจะมอบหมายต่อไม่ได้ ปลายทางที่ยุ่งอยู่จะล้มเหลวอย่างตรงไปตรงมาแทนการเข้าคิว และเมื่อการอนุมัติทำงานอยู่ message_agent จะหยุดรอการตรวจเหมือนการกระทำที่มีผลข้างเคียงอื่น (rule Always-allow ผูกกับ agent ปลายทางตัวนั้นตัวเดียว)
การอนุมัติการกระทำ (Auto Review)
การกระทำที่มีผลข้างเคียงสามารถหยุดรอการตัดสินใจของคุณก่อนรันได้ เมื่อการอนุมัติทำงานอยู่กับ task — policy ของ Work ตั้ง Require approval for side-effecting actions หรือสวิตช์ Auto Review ของ agent เปิดอยู่ — รอบจะหยุดก่อนสั่ง run_command, computer_act, delete_file, move_file หรือ message_agent และแสดงการ์ดตัดสินใจในบทสนทนา: Allow once, Always allow หรือ Deny
- Allow once รันเฉพาะการเรียกครั้งนี้และถามใหม่ในครั้งถัดไป
- Always allow รันการเรียกและบันทึก rule ไว้กับ task: ครอบทั้งเครื่องมือสำหรับการกระทำกับไฟล์และคอมพิวเตอร์ จำกัดเฉพาะโปรแกรมของคำสั่ง (token แรก) สำหรับ
run_command— อนุมัติnpm run buildคืออนุมัติล่วงหน้าให้คำสั่งnpmในอนาคต ไม่ใช่ทั้ง shell — และจำกัดเฉพาะ agent ปลายทางตัวเดียวสำหรับmessage_agentrule จะแสดงในส่วน Auto Review ของแท็บ Agent และลบได้ที่นั่น - Deny ปฏิเสธการเรียก โมเดลจะได้รับแจ้งว่าผู้ใช้ปฏิเสธการกระทำนั้นและต้องไม่ลองใหม่แบบเดิม รอบจะทำงานต่อด้วยคำตอบนั้น
การอนุมัติที่รออยู่จะสร้างการแจ้งเตือนด้วย (ในแอป และ web push เมื่อเปิดใช้) เพราะรอบอาจทำงานโดยไม่มีคนดูมาหลายนาทีแล้วเมื่อไปถึงจุดกำกับ หากไม่มีใครตัดสินใจภายในห้านาที คำขอจะหมดอายุ การกระทำจะไม่ถูกสั่ง และรอบจะจบเป็น ต้องการ input พร้อม handoff ตามปกติแทนการรอจนหมดงบ
การอนุมัติกำกับการกระทำ ไม่ได้กำกับการมองเห็น: write_file และเครื่องมือที่อ่านอย่างเดียวยังไม่ถูกกำกับ และทุกการตัดสินใจจะถูกบันทึกใน log ตรวจสอบความปลอดภัย
State ของ Task
| UI | State ของ Server | สี |
|---|---|---|
| Idle | idle | rgb(255, 255, 255) |
| กำลังประมวลผล | preparing หรือ running | rgb(48, 121, 255) |
| พร้อม | completed | rgb(76, 212, 117) |
| ต้องการ input | needs_input หรือ cancelled | rgb(255, 204, 0) |
| ผิดพลาด | failed | rgb(255, 61, 129) |
หยุด run active จะเปลี่ยนเป็น ต้องการ input และเก็บ file งบ round/tool หมดก็จบแบบเดียวกันหลัง handoff สุดท้ายที่ไม่มี tool งานที่ยังไม่เสร็จจะไม่ถูกทำเครื่องหมาย พร้อม
Run active ไม่บล็อก conversation: message จะรวมทันทีและถึงโมเดลใน round ถัดไป ทำให้ชี้นำ แก้ไข และเพิ่ม context โดยไม่ stop
ปรับขนาด
ที่ความกว้าง desktop xl conversation/workspace แบ่งด้วย divider ที่ลากได้:
- ความกว้าง conversation ค่าเริ่มต้น 45%
- ช่วงแนะนำ 30%–70% โดยคำนึง minimum content width
- Ratio ที่เก็บเป็นของ user ที่ login ใน browser นี้
- ปุ่มลูกศรขยับ 2% และ Shift 10%
- Home/End เลือก minimum/maximum
- Enter หรือ double-click reset split
Control ตามทิศทางการเขียน ภาษาอาหรับ conversation อยู่ขวา workspace อยู่ซ้าย pointer/arrow ตามทิศทาง visual
หน้าจอเล็กใช้ switch ใน header ของ task
Files
Tab Files แสดง /workspace โดยตรง เปิดเฉพาะ file text UTF-8 ที่ถูกต้องและ save การเปลี่ยนแปลงลง volume ของ task ลำดับ byte ที่ไม่ถูกต้องถูกปฏิเสธ ไม่แทนที่จนเสีย data
Editor มี:
- syntax highlighting สว่าง/มืดสำหรับภาษาทั่วไป
- save ด้วย
Cmd/Ctrl+S - format ด้วย
Shift+Alt+F - ตรวจ save conflict แบบ optimistic
- draft ตาม task/path ใน session memory
- warning เมื่อออกพร้อมการเปลี่ยนแปลงที่ยังไม่ save
Live highlighting หยุดเหนือ 8,000 ตัวอักษร/400 บรรทัด Formatting ถึง 100,000 ตัวอักษร/4,000 บรรทัดสำหรับ JavaScript/JSX, TypeScript/TSX, JSON variant, CSS/SCSS/Less, HTML, Markdown/MDX และ YAML
เมื่อโมเดลแก้ file ที่เปิด tab แสดง diff แดง/เขียวตั้งแต่ต้น round และย่อส่วนยาวที่ไม่เปลี่ยน Toggle สลับ diff/editor counter +added −removed สรุป Baseline คือ content ที่ browser เห็นก่อน round file ที่เปิดครั้งแรกภายหลังจะไม่แสดง diff
Draft มีไว้สะดวก ไม่ใช่ backup และล้างหลัง save, delete task หรือจบ session
Activity
Tab แสดง tool call/result, การทำงาน file, command output และ error ขยาย metadata ได้ Output ยังคง LTR ใน UI RTL
Run active เปิด stream SSE ที่ยืนยันตัวตนพร้อม event:
snapshot,run_state;reasoning_deltaหาก provider เปิด reasoningassistant_delta;tool_call,tool_result;usage;skill_loaded; และerror,done.
Reasoning ขึ้นกับ model/provider Libre แสดงเฉพาะ content ที่ API คืนและสร้าง chain-of-thought ที่ซ่อนไม่ได้ บางโมเดลไม่ส่ง Text และ action ของ tool stream แยกได้
Output จำกัดโดยตั้งใจ ผลที่ถูกตัดไม่พิสูจน์ว่าไม่มีต่อ ขอให้โมเดลตรวจผลลัพธ์ที่แคบกว่า
Git
Tab Git ทำงาน local ใน /workspace:
- init repository ด้วย branch
main - แสดง status porcelain, ahead/behind และ commit สูงสุด 20
- แสดง diff จำกัด
- stage path สูงสุด 200
- สร้าง commit ด้วยชื่อ/email administrator หรือ no-reply local
- สร้าง branch หลัง commit แรก
- switch ไป branch ที่มีหาก working tree สะอาด
พื้นผิว local เท่านั้น: ไม่มี clone, fetch, pull, push, จัดการ repository remote, command ใดก็ได้, token, SSH key หรือ pull request ใช้ broker credential ที่เชื่อถือได้แยก โดยควรเป็น GitHub App หรือ installation token ที่จำกัด repository/action เดียว อย่าเก็บ credential อายุยาวใน workspace, environment ของ container หรือ config repository
Git read ใช้ได้เมื่อ task idle/active Write ถูกปฏิเสธเมื่อ run ของโมเดล terminal หรือ preview ครอบครอง container การ switch branch ต้องใช้ tree สะอาด ซึ่งป้องกัน race
Command UI ใช้ array argument คงที่และรันเป็น 1000:1000 input ไม่ถูก shell evaluate Environment ปิด config system/global, prompt, hook, credential helper, signing, submodule, external diff, textconv และ network protocol Repository ถูกปฏิเสธหาก work tree ไม่ใช่ /workspace หรือ Git dir ออกนอก Write ถูกบล็อกหากมี filter clean/smudge/process executable
สิ่งนี้ปกป้อง Git API ของ Libre WebUI Administrator ผ่าน terminal และโมเดลผ่าน run_command ยังรัน Git command ปกติได้ command ใดก็ได้ถูกจำกัดด้วย sandbox และ boundary deployment
Workflow Skill ในตัว
แต่ละ run ได้ reference ของ server เกี่ยวกับ boundary /workspace แบบคงอยู่ root read-only, process ชั่วคราวและ /tmp, network, limit, lifecycle preview Skill กำหนดให้:
- ตรวจ instruction, manifest, lockfile, script และ state repository ก่อน edit
- เก็บงานไม่เกี่ยวข้องและ batch read อิสระ
- ทำ implementation ต่อ ไม่หยุดที่ plan
- ตรวจ targeted ก่อนตรวจวงกว้าง
- diagnosis error ไม่ retry แบบสุ่ม
- verify แอปก่อน start preview เป็น process ยาวสุดท้าย
Reference อยู่เฉพาะใน context โมเดล Libre ไม่สร้าง AGENTS.md, directory skill หรือ file control อื่น Instruction project override security boundary ไม่ได้
Terminal
Shell แบบโต้ตอบเชื่อม sandbox เดียวกัน เพื่อให้ administrator ตรวจ state, build และ debug project
ใช้ policy เดียวกัน: 1000:1000 แบบไม่มี privilege, directory /workspace และ container hardened ที่ไม่มี capability Terminal ไม่ให้ privilege มากกว่า run_command เพียงมี UI สำหรับมนุษย์ไปยัง boundary เดิม
- การยืนยันตัวตน — header Authorization แลกผ่าน HTTP เป็น ticket ใช้ครั้งเดียวอายุสั้นที่ผูกกับ protocol และ task ที่ตรง มีเพียง ticket และ task ID ใน
/ws/work-terminalตรวจ account, access, task และ owner ใหม่ก่อนทุก input การ revoke ปิด session และปล่อย lease - ตรวจ Origin — หากตั้ง
CORS_ORIGINหรือBASE_URLorigin ของ browser ต้องตรง ตั้งอย่างน้อยหนึ่งค่าสำหรับ deployment remote Client Electron/non-browser อาจไม่ส่ง Origin แต่ยังต้องใช้ ticket และ check จัดการด้วย TLS, firewall และ proxy - Admission — terminal ใช้ runtime lease และนับใน
WORK_MAX_ACTIVE_RUNTIMES_* - อายุ Container — terminal ที่เชื่อมจะยึด container ไม่ให้ idle stop
- Concurrency —
WORK_TERMINAL_MAX_SESSIONS_PER_TASKค่าเริ่มต้น 2 - Idle timeout —
WORK_TERMINAL_IDLE_TIMEOUT_MSค่าเริ่มต้น 15 นาที - Run active — terminal รอ model turn จบ
TTY ต้องใช้ stream สองทิศทางที่ capture ดังนั้น terminal เข้าถึง Docker Engine API โดยตรง ลำดับคือ WORK_DOCKER_SOCKET, DOCKER_HOST—socket unix:// หรือ HTTP ธรรมดา tcp:// ผ่าน proxy พร้อม tunnel Connection: Upgrade—แล้ว /var/run/docker.sock ไม่รองรับ ssh:// หรือ tcp:// ที่มี DOCKER_TLS_VERIFY และทำให้ terminal unavailable พร้อมคำอธิบาย โดยไม่กระทบ Work ส่วนอื่น Kubernetes ใช้ TTY WebSocket ของ exec API subresource รวม resize โดยไม่ใช้ Docker
Session แบบโต้ตอบไม่ถูกบันทึก และ command ไม่แสดงใน Activity
Preview
Preview start, stop, embed และเปิดแอป Field command ว่างตรวจพบ:
- script
devใน rootpackage.jsonพร้อม host/port ที่ต้องการ - root
index.htmlที่ static server ในตัวให้บริการ - แอปหนึ่งรายการใน directory nested
ให้ app root มีลำดับก่อน แอป nested หลายรายการที่เท่ากันหรือไม่มี entry point ทำให้เกิด error ชัดเจน ไม่ใช่ npm command แบบสุ่ม สำหรับ project อื่นให้ป้อน command ก่อน Start preview โดยเริ่มที่ /workspace เช่น cd apps/web && npm run dev -- --host 0.0.0.0 --port 4173 Process ต้อง listen บน 0.0.0.0 และ WORK_PREVIEW_PORT และพร้อมภายใน 15 วินาที
โมเดลใช้ start_preview ได้ ซึ่งเป็นวิธีเดียวที่รองรับเพื่อคง process ยาว run_command ล้าง child process background เมื่อเสร็จ
Screen (Work Computer)
Demo เต็ม: run จริงที่ไม่ edit (30x แล้ว real time) ซึ่ง agent browse NASA เลือกรูป build และ test gallery Three.js จากพรอมต์เดียว
Policy Work Computer เพิ่ม tab Screen: หน้าต่าง live ของ desktop เสมือนใน sandbox เดียว พร้อม window manager, panel และ Chromium 1280×800 คุณดู agent, takeover mouse/keyboard, ฟัง audio คอมพิวเตอร์ และสอน action ด้วย demo ได้ การเปิด tab เริ่ม session กราฟิก on-demand (ไม่มีสิ่งใดรันก่อน observer) และเชื่อม view VNC ผ่าน WebSocket
Administrator ใช้ Enable คลิกเดียว Libre สร้าง image กราฟิกในตัวบน Docker daemon ของ deployment (ครั้งแรกหลายนาที) และ policy พร้อมโดยไม่ต้อง docker build ด้วยมือ หลัง proxy กรอง build endpoint ถูกปิดโดยตั้งใจ ให้ pull image ghcr.io/libre-webui/libre-work-computer tag libre-work-computer:latest บน host หรือ build จาก deploy/work-computer/ แล้วปุ่มจะสร้างเฉพาะ policy Task ต้องมี network เพราะ Screen เข้าถึงผ่าน loopback port เช่น preview
VNC server ใน container listen ที่ localhost และใช้ password สองค่าต่อ session: observer ที่อนุญาตได้ password view-only ส่วน control-lease owner เท่านั้นได้ password เต็ม Server ทิ้ง input อื่น WebSocket bridge เป็น surface เดียวที่เข้าถึงได้และ publish เฉพาะ loopback host Observer แต่ละราย authenticate ด้วย ticket session/task ใช้ครั้งเดียวเช่น terminal ตรวจ Work access ทุก connection และ revocation ตัด Screen ทันที สูงสุดสี่ observer และ viewing นับเป็น activity ของ task
Viewing ไม่แข่งกับ execution การเปิดระหว่าง run เชื่อม sandbox เดียว Screen ที่สังเกตไม่ block run ถัดไป และ session อยู่หลัง completion แม้ deployment team มี worker ภายนอก Browser profile เก็บที่ /workspace/.browser-profile ทำให้ login อยู่ข้าม container restart
การควบคุม agent ใช้ tool สองรายการ computer_observe คืน full screenshot, pointer position, active window, current browser URL, focus ของหน้า/UI browser, สรุป element ที่ focused และ hash screenshot สัญญาณ semantic มาจาก DevTools บน loopback container และไม่มีใน image เก่า computer_act รัน batch สูงสุด 24 action—move, click, double/right click, type, key combo, scroll, wait—แล้วคืน screenshot หลังนิ่ง
Guard ทำงานสามจุด: action type/key ประกาศ focus ที่คาดได้และ fail safe หาก field ไม่ focused เพื่อไม่ให้ text เข้า address bar; batch หยุดเมื่อ window, title หรือ focus เปลี่ยนเพราะ coordinate ที่เหลือ stale; batch ประกาศ title, URL หรือ region change ที่คาดได้ และ environment verify ด้วย deadline adaptive—waiting ไม่ใช่ success
หลัง batch จะ poll Screen จนนิ่งแทน delay คงที่ ผลมี evidence: click รายงาน pixel ใกล้เปลี่ยน scroll_until scroll ถึง text/edge และรายงาน visibility แต่ละ observation เทียบก่อนหน้าและบอก no-change ชัด subgoal หนึ่งบรรทัดเก็บเป็น checkpoint และทำซ้ำเมื่อ recovery action เดิมสามครั้งบน Screen ไม่เปลี่ยนทำให้ warning การทำซ้ำหยุด run พร้อมขอ input Wait ที่ไม่ confirm ต่อเนื่องต้อง observation ใหม่ Telemetry round, delay, screenshot, guard และ verdict ถูก log พร้อม tool/outcome
Screenshot ส่งเป็น image จริงทุก route—Ollama, Anthropic, Gemini และ Chat/Responses ที่เข้ากันกับ OpenAI—จึงควรใช้โมเดล vision สำหรับ control หาก provider ปฏิเสธ image run จะไม่ fail: ตัด screenshot ออกจาก run ที่เหลือ โมเดลเปลี่ยนเป็น observation text และ log อธิบาย Verification นี้อ่อนกว่า Context มีเพียง screenshot ล่าสุด log คงอยู่เก็บเฉพาะ text ไม่เก็บ byte image
Content blocking ใน browser มี uBlock Origin Lite สำหรับโฆษณา/tracker (pin version และ verify checksum ตอน build; filter mode จัดการด้วย policy) และปิด cookie-consent banner อัตโนมัติ โฆษณาไม่ใช้ screenshot, token หรือ click Script โฆษณาที่รู้จักถูกแทนด้วย stub local ที่ปลอดภัย Agent ห้ามใส่ credential หรือผ่าน CAPTCHA/2FA และรายงาน blocker สำหรับ task ไม่น่าเชื่อถือให้รวม policy กราฟิกกับ DNS filtering
Audio ค่าเริ่มต้นปิดเพราะ browser ต้อง click ปุ่ม speaker stream audio คอมพิวเตอร์ real time PulseAudio เล่นไป null sink ส่วน monitor ส่ง PCM raw ผ่าน WebSocket ยืนยันตัวตนตัวที่สองบน loopback ด้วย ticket, access recheck และ observer limit เดิม ต้องใช้ image ใหม่จาก deploy/work-computer/
Take over control ให้ mouse/keyboard สำหรับ login, CAPTCHA หรือขั้นตอนมนุษย์ Done คืน Screen Session VNC ใช้ password full/view ที่สร้างและไม่ log password full ให้เฉพาะ lease owner Lease หมดในสองนาที ต่ออายุด้วย UI ที่เปิด และ user อื่นแย่งไม่ได้
Policy Allow screen takeover ห้าม control ทั้งหมดได้: ซ่อนปุ่ม takeover/teaching, endpoint ปฏิเสธ, request_takeover รายงาน unavailable; viewing ยังอยู่ เมื่อมนุษย์ control computer_observe/computer_act ถูก block เพื่อไม่ให้ agent แทรกหรือ capture input request_takeover แสดง banner เหตุผลและรอคืน Credential ไปจาก keyboard ถึงหน้าโดยตรง ไม่ผ่าน model/log Image เก่ารองรับ viewing เท่านั้น
Mode Teach task บันทึก demo: มนุษย์ control Screen พร้อม indicator ที่เห็น และเก็บ action เป็น coordinate แต่ละ click bind กับ tag read-only, ID, label ที่เห็น และ current URL ทำให้ step ตั้งชื่อ target เช่น “Click button#submit (Place order)”; coordinate เป็น hint
Save สร้าง script deterministic ไม่มีโมเดล: รวม keystroke เป็น string แยก click จาก drag ด้วย threshold 8 pixel pause เป็น wait; text ที่ตรง secret lexicon หรือ credential pattern (8+ ตัวจากสาม class) ถูก redact และแทนด้วย request_takeover Routine ภาษาธรรมชาติใช้ target ที่ bind แล้ว coordinate และ reinterpret ผ่าน computer_observe Routine มี condition, input, step, verification, scope ที่อนุญาต จาก host ที่เข้าจริง (ต้อง stop และถามก่อนออก), approval boundary และ stop เมื่อ fail
Script เก็บเป็น skill ปกติ prefix taught- พร้อม versioning, edit, sharing Run Work Computer load/list taught skill active ของ owner; replay เป็น run ปกติด้วย routine ที่ตรง หลัง run badge เพิ่มการประเมิน success/error พร้อมวันที่ใน Track record ด้วย click เดียว (ใหม่สุดด้านบน จำนวน bounded แต่ละ record เป็น version ปกติ) อย่าใส่ password จริงตอนบันทึก ให้ demo flow ถึง login, save แล้วใช้ request_takeover ตอน replay
Provider, Routing และ Data Disclosure
Route ที่รองรับ
| Route | การตรวจและพฤติกรรม |
|---|---|
| Ollama local | Ollama พร้อม โมเดลที่ตรงประกาศ tool support |
| Ollama Cloud | Route ชัดผ่าน Ollama; cloud suffix แสดง disclosure |
| Plugin completion/chat | Active พร้อมโมเดลที่ตรงและ credential administrator ปัจจุบัน |
| Plugin Anthropic | ใช้ adapter message/tool Anthropic สำหรับ Work |
| Plugin Gemini | ใช้ adapter content/function-call Gemini สำหรับ Work |
| อื่นที่เข้ากัน | ใช้รูปแบบ OpenAI สำหรับ message, tool และ tool choice |
เก็บประเภท provider และ plugin ID บน task และทุก run ชื่อโมเดลอย่างเดียวไม่เลือก route plugin ชื่อเดียวกันไม่ยึด task ที่มี
ข้อมูลที่ Provider ได้รับ
- system prompt ของ Work
- workflow skill และ limit environment ปัจจุบัน
- message ล่าสุด 30 รายการของ user/assistant สูงสุด 256 KB
- tool definition
- ประวัติ tool-call
- result รวม list, file content, search, output และ error
Volume ไม่ถูก upload ทั้งหมด แต่ content ที่ tool คืนจะเป็นส่วน conversation และส่ง provider ตรวจ retention, training, pricing และเงื่อนไขก่อนงานละเอียดอ่อน
Credential อยู่ server-side และไม่ mount ใน container Work
แอปเข้ารหัส credential ไม่ได้หมายถึงเข้ารหัส task ทั้งหมด Conversation, result, output และ metadata คือ content ฐานข้อมูลปกติ file คือ file volume/PVC ปกติ ใช้ host control และ disk encryption ตาม threat model
Disclosure ของ Provider Remote
โมเดล plugin และชื่อ Ollama ที่มี :cloud หรือ -cloud ถือเป็น remote เมื่อเลือก notification ที่ปิดได้จะอธิบาย data flow และ paid call หลายครั้ง เก็บ preference ต่อ user
ทุก route ใช้ WORK_MAX_AGENT_ROUNDS ค่าเริ่มต้น 48 round ไม่มี limit 12 เฉพาะ plugin Tool budget คือ max(128, configured rounds × 8) call เมื่อหมด Libre ขอ handoff สุดท้ายที่ไม่มี tool เกี่ยวกับงาน check blocker และส่วนที่เหลือ แล้วเขียน ต้องการ input ไม่ใช่ exception หรือ completion ปลอม การทำต่อใช้ workspace เดิม หนึ่ง run ยังสร้าง request แบบเสียเงินได้หลายครั้ง
Folder ของ Host (ไม่บังคับ)
Docker ปกติใช้ named volume ทำให้โมเดลไม่เห็น file จริง Task bind กับ directory ของ host จริงได้ Kubernetes ปฏิเสธ directory นี้และใช้ PVC
WORK_HOST_WORKSPACES_ENABLED=true
WORK_HOST_WORKSPACE_ROOTS=/Users/you/Projects
WORK_HOST_WORKSPACE_ROOTS คือรายการ root คั่นด้วย : ค่าเริ่มต้นคือ home ของ user server Folder workspace ไม่บังคับ ค่าว่างรักษา isolation
Path ต้องเป็น directory สัมบูรณ์ที่มีและยังอยู่ใน root หลัง resolve symlink .ssh, .gnupg, .aws, .config, .kube, .docker, .claude, .libre-webui และ node_modules ถูกปฏิเสธเสมอ Path ที่อนุญาตถูกเก็บและแสดง
โมเดลอ่านและแก้ file จริง user ที่ไม่มี privilege, capability ที่ drop และ limit ไม่แยกโมเดลจาก directory อีก ปิด feature เว้นแต่จำเป็น ตั้ง root แคบ และเลือก directory ที่มี version control
Persistence และ Lifecycle
| State | การจัดเก็บ | อายุ |
|---|---|---|
| Owner, title, provider, state | ฐานข้อมูล Libre | จนลบ task/user |
| Run, error, message, activity | ฐานข้อมูล Libre | จนลบ task |
| File | Docker volume หรือ K8s PVC | อยู่ข้าม cancel, stop preview, restart |
| ระบบ root และ file ชั่วคราว | Container หรือ Pod | Ephemeral; stop/recreate ได้ |
| Process preview | Sandbox ที่รัน | ชั่วคราว เก็บเมื่อ verify health |
| Draft ยังไม่ save | Session browser | ความสะดวกชั่วคราว |
Server สร้าง task UUID และมีเพียง server กำหนด resource name ตรวจ label management/owner ก่อน reuse/delete และปฏิเสธ resource ของ task อื่น
Sandbox เตรียม on-demand File helper หยุด environment idle, command ปล่อยเมื่อเสร็จ และ preview ที่ verify แล้วอาจยึดไว้ Workspace แบบคงอยู่ mount ใหม่
Administrator กำหนด runtime policy ที่มีชื่อ: image, limit memory/CPU/PID, ขนาด Kubernetes, idle timeout, network และ toggle Work Computer (GUI + browser) กับ Allow screen takeover (กำหนด teaching ด้วย) Task ใช้ policy ที่เลือก field ว่าง inherit ค่า global และการลบ policy คืนค่าใน recreate ถัดไป Policy เปลี่ยนเฉพาะ resource/feature และลดความเข้ม mode ไม่มี privilege, root read-only, capability ที่ drop หรือ network isolation ไม่ได้
WORK_RUNTIME_IDLE_TIMEOUT_MS หยุด sandbox และปล่อย slot หากไม่มี command, terminal หรือ request preview ที่ลงลายเซ็น Workspace ถูกเก็บและ preview start ใหม่ ค่าเริ่มต้น 0 เก็บ environment จน stop ชัด
เมื่อ server startup run active ถูกทำเครื่องหมาย failed และ clear state preview Driver ดึง container/Pod managed ใน query เดียว Environment ของ task ที่รู้จักและกำลังรันถูก stop ที่ stop แล้วไม่เปลี่ยน orphan ถูกลบ Owner กำหนดด้วย label ไม่ใช่ชื่อ มี Libre instance เดียวต่อ namespace/daemon หากพิสูจน์ cleanup ไม่ได้ Work fail closed, retry ทุก 10 วินาที และ block operation mutation
เครือข่าย
หากไม่มี policy มีชื่อ network จะ active Administrator สร้าง policy เครือข่ายที่ปิดเป็นค่าเริ่มต้นและ author เลือกตอนสร้าง task ได้ ไม่มี toggle ต่อ task การเปลี่ยน policy ต้อง recreate environment
Docker เชื่อม task ที่มีเครือข่ายกับ bridge managed (libre-webui-work, WORK_NETWORK_NAME) ด้วย com.docker.network.bridge.enable_icc=false:
- sandbox เชื่อมกันไม่ได้
- ค่าเริ่มต้นเข้าถึง container deployment บน bridge ร่วมไม่ได้ รวมฐานข้อมูลหรือ Ollama ที่ยังไม่ publish
Network ชื่อเดียวกันที่ไม่มี label management ถูกปฏิเสธ
บน Kubernetes Pod ได้ network label Helm สร้าง default-deny, ingress เฉพาะ preview และ internet egress สำหรับ Pod ที่อนุญาต ยกเว้น work.networkPolicy.blockedEgressCidrs มีผลเมื่อ CNI รองรับ ดู Kubernetes
อนุญาต egress สำหรับ package, Git และ API นี่ไม่ใช่ egress firewall Code เข้าถึง:
- service ของ host Docker
- LAN ของ host
- internet
- endpoint metadata infrastructure
เครื่องมือ Policy Egress
WORK_RUNTIME_DNS(Docker) — ที่อยู่ IPv4/IPv6 คั่น comma และบังคับด้วย--dns; resolver filter ให้ list ชื่อ ที่อยู่ invalid ถูกปฏิเสธ/log จึง inject flag ไม่ได้- Firewall host หรือ upstream บน subnet คงที่ของ bridge managed
WORK_NETWORK_NAMEสำหรับ network precreated ที่มี option เอง management label และปิด ICC
DNS ไม่จำกัด IP โดยตรง ต้องใช้ firewall เพื่อรับประกัน
อย่าถือ Work เป็นการป้องกัน exfiltration ให้ access เฉพาะ user ที่เชื่อถือได้ สำหรับ task อัตโนมัติเลือก policy offline มีชื่อ ไม่มีตัวแปร environment global เปลี่ยนค่าเริ่มต้น
Network ไม่เพิ่ม credential: SSH key, cloud credential, browser profile, home ของ host หรือ Docker socket ไม่ mount ใน task Code ยังส่ง secret ที่เขียนใน /workspace ได้
Traffic sandbox แยกจาก request โมเดล Ollama และ plugin ถูกเรียกโดย server ผ่าน route ชัดเสมอ
Boundary ความปลอดภัยของ Sandbox
Docker Container:
- รัน non-root เป็น
1000:1000 - ใช้
/workspaceเป็น working directory - mount เฉพาะ volume ของ task ที่เลือก
- ใช้ root read-only และ
/tmpจำกัด - drop Linux capability ทั้งหมด
no-new-privileges;- ไม่ privileged และใช้ init process
- ใช้ limit CPU, memory, process, เวลา และ output
- ล็อก swap (
--memory-swap=--memory) - เชื่อม network managed ไม่มี ICC หรือไม่มี network
- publish เฉพาะ preview port บน loopback ที่กำหนด
ตรวจ property ทั้งหมดซ้ำด้วย docker inspect และ hash ใน ai.libre-webui.policy Container ที่มี policy เก่าถูกทำลายและ recreate หลัง update
Kubernetes ใช้เทียบเท่า: user ไม่มี privilege, root read-only, seccomp RuntimeDefault, ไม่มี privilege escalation, capability ที่ drop, resource ชั่วคราวจำกัด, ไม่มี ServiceAccount token และ PVC ที่ /workspace ตรวจ label และ fingerprint
Path validation ปฏิเสธ path สัมบูรณ์ traversal, backslash, NUL และความยาวเกิน Helper resolve real path และปฏิเสธ escape ผ่าน symlink Write ใช้ file ชั่วคราวและ atomic rename
มาตรการลด host exposure โดยไม่ตั้งใจ แต่ไม่ทำให้ Work เป็น VM หรือ environment วิเคราะห์ malware ที่ปลอดภัย Container ใช้ kernel host ร่วม vulnerability ของ Docker, Kubernetes, runtime, image, dependency หรือ kernel อาจข้าม boundary
Docker volume ไม่มี quota อิสระ Project อาจใช้ storage หมด ให้ติดตามการเติบโตและใช้ host limit การ enforce ขนาด PVC Kubernetes ขึ้นกับ storage provider
Checklist การ Hardening Docker
บน Kubernetes ตรวจ RBAC namespace, ความปลอดภัย Pod, storage class และ CNI NetworkPolicy enforcement ตาม คู่มือ
แอปตั้ง flag container, validate path และปกป้อง API แต่ให้ host firewall, storage quota หรือระดับ privilege daemon ไม่ได้ เป็นหน้าที่ operator
1. แยกการควบคุม Docker
Container หลักต้อง control daemon; socket คือ credential ของ control plane การ compromise แอปอาจทำให้ host compromise
docker-compose.socket-proxy.yml ไม่ให้ socket กับแอป Proxy ให้เฉพาะ containers, images, volumes, networks, exec และ info; block swarm, secrets, configs, build, commit และ system Libre ใช้ DOCKER_HOST=tcp://docker-socket-proxy:2375 โดยไม่ mount socket/group; CLI, terminal และ diagnostics ตามที่อยู่นี้ API surface เล็กลงแต่ blast radius ยังอยู่ การสร้าง container ทำให้ mount host path ได้
Boundary ที่แข็งแรงกว่าคือ VM แยกที่ไม่มี workload ไม่เกี่ยวข้อง ยิ่งแข็งแรงคือ daemon rootless แยกหรือ runtime host แยก ก่อน rollout ให้ verify file ownership, routing, cleanup และ terminal การ mount socket ปกติแบบ read-only ไม่ทำให้ API read-only
2. บล็อกการควบคุม Host จาก Sandbox
การปิด ICC ไม่ block service ของ host ตรวจ bridge และ subnet จริง:
docker network inspect libre-webui-work \
--format 'id={{.Id}} subnets={{range .IPAM.Config}}{{.Subnet}} {{end}}'
ss -lntup
Firewall คงอยู่ต้องปฏิเสธ traffic bridge ไป SSH, Docker API, ฐานข้อมูล และ admin port ทดสอบ rule ด้วย container ครั้งเดียวและ download ที่อนุญาตแล้ว persist DOCKER-USER control traffic forwarded การ access host อาจต้องใช้ rule INPUT
3. จำกัด Target Egress
Block cloud metadata, infrastructure private และ LAN client หากไม่จำเป็น รวม DNS/firewall IP โดยตรง bypass DNS; HTTP proxy ไม่พอสำหรับ connection โดยตรง ใช้ policy นอก container
สร้าง policy แยกแบบไม่มี network, registry-only และ egress เปิด Policy กำหนด network attachment ส่วน rule ภายนอกกำหนด target ที่อนุญาต
4. Storage Quota จริง
Limit CPU, memory และ PID ไม่จำกัด volume ใช้ XFS project quota, logical volume มี quota หรือ volume/PVC driver ที่ enforce ขนาด Docker local บน ext4 ไม่มี quota ที่น่าเชื่อถือจากขนาดที่ประกาศเท่านั้น
ติดตามทุก volume ai.libre-webui.managed=true และ Docker data root เตือนก่อนเต็มและ test พฤติกรรม failure UI หรือ du แค่ warning ไม่ enforce limit ระหว่าง check
5. ตรวจสอบ Policy
หลังเปลี่ยน สร้าง task ครั้งเดียวและตรวจผ่าน docker inspect: UID, root read-only, capability, no-new-privileges, memory, swap, CPU, PID, volume task เดียว และ network Container หลักควรมีเฉพาะ mount ที่คาด public ingress ต้องผ่าน proxy/tunnel ที่ยืนยันตัวตน ไม่ใช่ port Docker หรือ preview
ความปลอดภัยและการเข้าถึง Preview
Docker publish preview แบบ dynamic บน loopback ของ server; Kubernetes ใช้ IP Pod โมเดล/browser ไม่เลือก origin ใดก็ได้ Libre sign URL สำหรับ task/endpoint ที่ตรง verify process ทุก request และ proxy HTTP/WebSocket ผ่าน /api/work/previews Stop/restart revoke URL
Response ลบ credential Libre และ cookie upstream HTML จำกัดด้วย iframe sandbox/CSP ที่ให้ script, form, modal และ download แบบไม่มี same-origin การป้องกันใช้กับ tab แยกด้วย Generated code ยังไม่น่าเชื่อถือและอาจส่ง data workspace/browser URL คือ secret อายุสั้น
Browser load public origin เดียวกัน ทำให้ HTTPS remote ทำงานโดยไม่เปิด port/IP Pod และไม่ mixed content Reverse proxy ต้องรักษา WebSocket สำหรับ /api/work/previews/; Nginx ในตัวทำ
แอปหลักให้เฉพาะ origin ของตนและ Turnstile ใน frame Preview bypass Helmet policy global เพื่อส่ง body และใช้ sandbox แคบลง ปิด cross-origin embedder policy เพราะ development server แทบไม่มี header ที่ต้องการ
ตาราง Deployment
| Deployment | Run/file | Preview |
|---|---|---|
npx libre-webui local | รองรับเมื่อ Docker ติดตั้ง/เข้าถึงได้ | Proxy ลงลายเซ็นบน origin ของแอป |
| Run จาก source local | ข้อกำหนดเหมือนกัน | Origin API development ที่ port 3001 |
| Electron | มีเงื่อนไข ใช้ backend ภายนอกโดยไม่มี runtime Work แยก | Proxy ลงลายเซ็นของ backend นั้น |
| Bare metal/VM remote | รันเมื่อ host มี Docker | Reverse proxy HTTP/WebSocket |
| Compose มาตรฐาน | รองรับโดยค่าเริ่มต้นบน Docker Desktop: image มี CLI, Compose mount socket และพอร์ต Work วิ่งผ่าน host.docker.internal ส่วน Docker Engine แบบเนทีฟต้องมี WORK_PREVIEW_BIND ที่ไม่เปิดสาธารณะแต่เข้าถึงได้เพิ่มด้วย | public origin เดียวกัน |
| Kubernetes/Helm | --set work.enabled=true: Pod/PVC ผ่าน IP Pod สำหรับ run, file, command, Git, terminal, Screen/audio Work Computer, Role namespace และ default-deny NetworkPolicies; ไม่มี socket ดู Kubernetes | Proxy ใน cluster ไป IP Pod |
Work เมื่อ Libre WebUI อยู่ใน Docker
File Compose ทั้งหมดใน repository รวม Work: image มี CLI และ mount /var/run/docker.sock Docker Desktop ใช้งานได้ด้วยค่าเริ่มต้นของการกำหนดเส้นทางที่มาพร้อมกัน ส่วน Docker Engine แบบเนทีฟต้องตั้ง WORK_PREVIEW_BIND เป็นอินเทอร์เฟซโฮสต์ที่ไม่เปิดสาธารณะแต่คอนเทนเนอร์พี่น้องเข้าถึงได้เพิ่มด้วย ตามที่อธิบายด้านล่าง
Container ของ task เป็น sibling ของ container Libre WebUI มองเห็นใน docker ps และจัดการด้วย lifecycle เดียวกัน
Socket ให้ control host เทียบเท่า root Work ไม่รันหากไม่มี ผลชัดเจน: administrator Libre WebUI ทุกคนเทียบเท่า administrator ของ Docker host ความปลอดภัย network, lifecycle, backup และ access เป็นหน้าที่ operator ลบบรรทัด socket เพื่อปิด Work feature อื่นไม่ขึ้นกับ socket
ทางเลือกคือ docker-compose.socket-proxy.yml ผ่าน DOCKER_HOST ดู การแยก control
ต้องครบสามเงื่อนไข:
- มี Docker CLI Image ทางการมี ส่วน image custom ต้องใช้
docker-cliหรือWORK_DOCKER_COMMANDมิฉะนั้น:The "docker" CLI is not installed… - Mount socket แล้ว มิฉะนั้น:
No Docker daemon is reachable… - User อยู่ group ของ socket Image รันเป็น
nodejsuid 1001; socket มักเป็นของrootหรือdockerจึงใช้ Composegroup_add: ['${DOCKER_GID:-0}']ค่าเริ่มต้นเหมาะกับ Docker Desktop ส่วน Linux ต้องใช้ ID ของตน มิฉะนั้น:The Docker socket is mounted but the Libre WebUI user cannot open it…
# Read the socket's group as seen INSIDE a container. A macOS host reports a
# different value, because Docker Desktop proxies the socket through a VM.
echo "DOCKER_GID=$(docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
alpine stat -c '%g' /var/run/docker.sock)" >> .env
docker compose up -d --force-recreate
Preview port อยู่บน loopback host และเข้าผ่าน proxy ลงลายเซ็น origin เดียวสำหรับ HTTP/WebSocket ทำงานกับ HTTPS/tunnel ใช้ sandbox และ revoke URL เก่า
บน Docker ที่อยู่ publish/connect อาจต่างกัน เก็บ WORK_PREVIEW_BIND=127.0.0.1 และตั้ง WORK_DOCKER_PUBLISHED_HOST เป็นที่อยู่ host ที่เข้าถึงได้ (host.docker.internal บน Docker Desktop) โปรไฟล์ Compose ที่มาพร้อมกันตั้งทั้งสองค่าและแมปชื่อโฮสต์นี้ให้แล้ว การติดตั้งบน Linux แบบเนทีฟต้อง override WORK_PREVIEW_BIND ด้วยเกตเวย์ของ Docker bridge (หรืออินเทอร์เฟซโฮสต์อื่นที่ไม่เปิดสาธารณะแต่เข้าถึงได้ชัดเจน) mapping อย่างเดียวไม่ทำให้ loopback reachable และอย่า bind พอร์ตชั่วคราวดิบเหล่านี้กับ 0.0.0.0 เด็ดขาด
Concurrency จำกัด: WORK_MAX_ACTIVE_RUNTIMES_PER_USER 2 และ WORK_MAX_ACTIVE_RUNTIMES_GLOBAL 3 Response capability บอก busy state เพิ่มเมื่อทรัพยากรพอเท่านั้น
สำหรับ Kubernetes ใช้ work.enabled=true; chart สร้าง RBAC, namespace, policy และ Pod/PVC ตาม คู่มือ
การตั้งค่า Runtime
| ตัวแปร | ค่าเริ่มต้น | วัตถุประสงค์ |
|---|---|---|
WORK_RUNTIME_BACKEND | docker | Backend sandbox: docker หรือ kubernetes |
WORK_RUNTIME_IMAGE | node:22.22-bookworm@sha256:2d178f2785b96dfbf62a416ca2e40f50e30150b4ff3320d706f0d96e90600eb3 | Image sandbox ของ task |
WORK_DOCKER_COMMAND | docker | ไฟล์ executable ของ Docker CLI |
WORK_COMMAND_TIMEOUT_MS | 120000 | Command timeout ค่าเริ่มต้น |
WORK_MAX_OUTPUT_CHARS | 50000 | Output ที่ capture สูงสุด |
WORK_MAX_AGENT_ROUNDS | 48 | Round model/tool ต่อ run |
WORK_MEMORY_LIMIT | 2g | Limit memory ของ container |
WORK_CPU_LIMIT | 2 | Limit CPU ของ container |
WORK_PIDS_LIMIT | 256 | Limit process ของ container |
WORK_PREVIEW_PORT | 4173 | Port แอปใน container |
WORK_PREVIEW_BIND | 127.0.0.1 | Interface publish ของ host |
WORK_DOCKER_PUBLISHED_HOST | เหมือน WORK_PREVIEW_BIND | Host/IP สำหรับ port Work ที่ publish |
WORK_COMPUTER_SCREEN_PORT | 6080 | Port WebSocket bridge ของ Screen |
WORK_COMPUTER_AUDIO_PORT | 6081 | Port WebSocket bridge ของ audio |
WORK_RUN_LEASE_WAIT_MS | 60000 | รอ owner ของ runtime lease ชั่วคราว |
WORK_MAX_ACTIVE_RUNTIMES_GLOBAL | 3 | Task container concurrent ทั้ง instance |
WORK_MAX_ACTIVE_RUNTIMES_PER_USER | 2 | Task concurrent ต่อ administrator |
WORK_MAX_TASKS_GLOBAL | 500 | จำนวน task คงอยู่สูงสุดทั้ง instance |
WORK_MAX_TASKS_PER_USER | 100 | จำนวน task คงอยู่สูงสุดต่อ administrator |
WORK_NETWORK_NAME | libre-webui-work | Bridge managed สำหรับ sandbox มีเครือข่าย |
WORK_RUNTIME_DNS | ไม่ตั้ง | IP resolver คั่น comma |
WORK_DOCKER_SOCKET | DOCKER_HOST หากเป็น unix:///tcp:// มิฉะนั้น /var/run/docker.sock | Docker Engine endpoint สำหรับ terminal/diagnostics |
WORK_TERMINAL_MAX_SESSIONS_PER_TASK | 2 | Terminal browser concurrent ต่อ task |
WORK_TERMINAL_IDLE_TIMEOUT_MS | 900000 | Terminal idle timeout |
WORK_RUNTIME_IDLE_TIMEOUT_MS | 0 (ปิด) | หยุด sandbox idle รวม preview |
WORK_K8S_NAMESPACE | libre-webui-work | Namespace Pod/PVC sandbox Kubernetes |
WORK_K8S_STORAGE_CLASS | ค่าเริ่มต้น cluster | StorageClass สำหรับ workspace PVC |
WORK_K8S_WORKSPACE_SIZE | 5Gi | ขนาด PVC workspace ต่อ task |
WORK_K8S_POD_READY_TIMEOUT_MS | 900000 | รอ Pod sandbox เป็น Running |
WORK_K8S_POD_GONE_TIMEOUT_MS | 60000 | รอ Pod ที่ลบหายไป |
ใน production ใช้ version image หรือ digest คงที่ที่ verify แล้ว Tag mutable อาจเปลี่ยน CLI tool และ security boundary โดย Libre WebUI ไม่เปลี่ยน
Run, preview, file helper, command และ recreate sandbox ใช้ capacity accounting ร่วม Operation nested ของ task ที่นับแล้วไม่ถูกนับซ้ำ เกิน limit คืน HTTP 429
ขีดจำกัด Protocol และ UI คงที่
| รายการ | ขีดจำกัด |
|---|---|
| Message task/run ใหม่ | 65,536 ตัวอักษรและ byte UTF-8 |
| Model ID ตอน create/change | 500 ตัวอักษรและ byte UTF-8 |
| ID provider plugin | 200 ตัวอักษร |
| Run active ต่อ task | 1 |
| Text command | 20,000 ตัวอักษร |
| Timeout command ของ tool | 1–600 วินาที |
| Preview readiness | 15 วินาที |
| Read/write file | 2,000,000 byte text UTF-8 |
| List directory โดยตรง | 1,000 รายการแรก |
| หน้า message | 200 message, 1,000,000 byte |
| Message เดี่ยวที่เก็บ | 100 KB |
| Context conversation ของโมเดล | 30 message ล่าสุด, 256 KB |
| Output tool ที่เก็บ | ราว 20,000 source character และ truncation marker |
| Live editor highlight | 8,000 ตัวอักษร/400 บรรทัด |
| Browser formatting | 100,000 ตัวอักษร/4,000 บรรทัด |
| Output state Git | 2,000,000 ตัวอักษร |
| Output diff Git | 600,000 ตัวอักษร |
| ประวัติ Git | 20 commit local |
| Path ใน request stage หนึ่งครั้ง | 200 |
| Commit message | 4,000 ตัวอักษร |
| Agent loop | 48 round ค่าเริ่มต้นผ่าน WORK_MAX_AGENT_ROUNDS |
| Tool-call budget | max(128, configured rounds × 8) call |
File API ใช้ text UTF-8 Editor ในตัวไม่ edit file binary file ใหญ่กว่า 2 MB เปิดผ่าน Work API ไม่ได้
ภาพรวม API
Endpoint ทั้งหมดอยู่ใต้ /api/work และต้องยืนยันตัวตนพร้อมสิทธิ์ Work ปัจจุบันจากฐานข้อมูล Work ค่าเริ่มต้นเฉพาะ administrator operation ปกติเปิดให้ user active ได้ การเลือก folder host และ admin endpoint สำหรับ policy/access ยังเฉพาะ administrator
| Method | Path | วัตถุประสงค์ |
|---|---|---|
GET | /capabilities | Availability และ limit ของ environment/provider |
GET | /tasks | List task ของ administrator ปัจจุบัน |
POST | /tasks | สร้าง task และ run async แรก |
GET | /tasks/:id | Load state และ message ล่าสุด |
GET | /tasks/:id/messages | Load message เก่า |
PATCH | /tasks/:id | Rename หรือเปลี่ยน route โมเดลที่ตรง |
DELETE | /tasks/:id | ลบ task และ workspace คงอยู่ |
POST | /tasks/:id/runs | Start run ถัดไป |
POST | /tasks/:id/messages | ส่ง message ให้ agent ระหว่าง run |
GET | /tasks/:taskId/runs/:runId/events | Stream event SSE ที่ยืนยันตัวตน |
POST | /tasks/:id/cancel | ยกเลิก run active |
GET | /tasks/:id/approvals | Approval ที่รออยู่และ state Auto Review ของ task |
PUT | /tasks/:id/approvals | เปิด/ปิด approval ต่อ task |
POST | /tasks/:id/approvals/:approvalId | ตัดสิน approval ที่รออยู่ (อนุญาตครั้งเดียว/เสมอ, ปฏิเสธ) |
DELETE | /tasks/:id/approval-rules/:ruleId | ลบ rule Always-allow |
GET | /computer/setup | State setup Work Computer สำหรับ administrator |
POST | /computer/setup | สร้าง image GUI และ policy |
POST | /tasks/:id/computer/start | Start session Work Computer |
GET | /tasks/:id/computer/control | Controller ปัจจุบันและ request takeover |
POST | /tasks/:id/computer/control | Takeover หรือต่ออายุ control |
DELETE | /tasks/:id/computer/control | คืน control ให้ agent |
POST | /tasks/:id/computer/teach | เก็บ demo เป็น skill |
POST | /tasks/:id/computer/anchor | Resolve element ใต้ click |
POST | /computer/skills/:slug/trace | เพิ่ม outcome ให้ skill |
GET | /tasks/:id/files | List directory workspace |
GET | /tasks/:id/file | Read file text |
PUT | /tasks/:id/file | Save file text |
GET | /tasks/:id/git | Read state/history Git hardened |
GET | /tasks/:id/git/diff | Read diff local จำกัด |
POST | /tasks/:id/git/init | Init Git local |
POST | /tasks/:id/git/stage | Stage path ชัด |
POST | /tasks/:id/git/commit | Commit การเปลี่ยนแปลง staged |
POST | /tasks/:id/git/branches | สร้าง branch local |
POST | /tasks/:id/git/switch | Switch ไป branch สะอาด |
POST | /tasks/:id/preview/start | Start preview managed |
POST | /tasks/:id/preview/stop | หยุด preview managed |
ตรวจ Task ID กับ owner ที่ยืนยันตัวตนเสมอ อ่าน state ของ account, role และ access policy จากฐานข้อมูลทุก request ทำให้ revocation ยังใช้แม้ JWT มี role claim เก่า
Schema update ของ task เก็บ field server networkEnabled เพื่อ compatibility ภายใน Field ไม่แสดงเป็น control Work แยก ตอน create เลือก policy มีชื่อพร้อม network state ค่าเริ่มต้นที่ต้องการ อย่าใช้ field ดิบเป็น API config แบบคงอยู่
การลบ การเปลี่ยน Account และ Backup
ลบ Task
การลบเป็น destructive โดยตั้งใจ:
- Server ทำเครื่องหมาย task ว่ากำลัง decommission และ block mutation ใหม่
- ยกเลิก run active และหยุด sandbox
- Libre WebUI verify label ownership ของ resource runtime
- ลบ Container หรือ Pod พร้อม named volume/PVC
- Cascade-delete task จากฐานข้อมูลพร้อม run/message
- Clear draft ใน browser เมื่อสำเร็จ
หาก cleanup runtime ล้มเหลว Libre WebUI เก็บ record และคืน error ให้ operator แก้ Docker/Kubernetes แล้ว retry Metadata ไม่ถูกลบเงียบจนเหลือ resource ที่ไม่ติดตาม
การหยุด run/preview ต่างจาก delete: execution หยุดแต่เก็บ volume และ conversation
ลดสิทธิ์ Administrator และลบ User
เมื่อ downgrade Libre WebUI เก็บ role revocation ก่อน ทุก request ถัดไปตรวจสิทธิ์ปัจจุบัน Server suspend task และลอง stop run/sandbox Cleanup error ไม่คืน access และรายงาน operator ให้ retry
เมื่อลบ user อื่น จะลบ resource managed ก่อน หาก cleanup ล้มเหลวเก็บ record ของ user เพื่อไม่เสีย metadata ownership
Backup Task แบบครบ
Backup Work แบบครบต้องมี:
- ฐานข้อมูล Libre WebUI พร้อม ownership, ชื่อ resource Docker/Kubernetes, routing, run, message และ activity
- Docker volume/Kubernetes PVC ทั้งหมดที่มี label
ai.libre-webui.managed=trueและมี file Work
ไม่ต้อง copy Container ephemeral และ process preview สำหรับ copy ที่สอดคล้องให้หยุด activity Work ใหม่และ server แล้วใช้ procedure snapshot storage
Restore ฐานข้อมูลและ workspace ที่ตรงกันพร้อมกัน สร้าง volume/PVC แต่ละรายการด้วยชื่อที่บันทึกตรง และ restore label ai.libre-webui.task=<task UUID> กับ ai.libre-webui.managed=true มีเพียง file จะขาด label มีเพียงฐานข้อมูลจะขาด file มีเพียง storage จะขาด ownership และชื่อ resource
หาก installation มี credential provider เข้ารหัส ให้ทำตาม procedure backup หลักสำหรับ data directory และ key
Localization และ RTL ภาษาอาหรับ
Work แปลครบ 25 ภาษา: อังกฤษ อาหรับ เบงกาลี เช็ก เดนมาร์ก เยอรมัน สเปน ฝรั่งเศส ฮินดี อินโดนีเซีย ไอซ์แลนด์ อิตาลี ญี่ปุ่น เกาหลี มาเลย์ ดัตช์ โปแลนด์ โปรตุเกส รัสเซีย สวีเดน ไทย ตุรกี ยูเครน เวียดนาม และจีน
ภาษาอาหรับตั้ง lang="ar" และ dir="rtl" ก่อน React render: sidebar/conversation ไปขวา workspace ไปซ้าย icon ทิศทาง mirror และ tab/resize ตาม RTL
Content เทคนิคที่มีผลต่อความถูกต้องยังเป็น LTR:
- code และ highlighting
- filesystem path
- model ID
- command และ log preview
- tool output และ metadata
- content ของ code block
Title ของ task, prompt ภาษาธรรมชาติ, error, filename และ preview command ใช้ทิศทาง text อัตโนมัติ
การแก้ปัญหา
Runtime Unavailable ด้วย npx
npx libre-webui start server บน host แต่ไม่ติดตั้ง Docker รัน docker info ด้วย OS user เดียวกัน ติดตั้ง/start Docker หรือแก้ permission แล้ว reload Work Verify Ollama พร้อมหรือ plugin active พร้อมโมเดลและ credential administrator ปัจจุบัน
Runtime Unavailable ใน Docker หรือ Kubernetes
Compose ใน repository ไม่ควรรายงาน error นี้: image มี CLI และ file mount host socket Panel บอกสาเหตุ—ขาด CLI, socket หรือ group สำหรับ group ให้ตั้ง DOCKER_GID และ recreate container ดู Work ใน Docker
บน Kubernetes ตั้ง --set work.enabled=true Libre รายงาน kubernetes ตรวจ API และ launch Pod พร้อม PVC อย่า mount runtime socket ของ node ดู Kubernetes
ไม่มีโมเดลที่เข้ากันกับ Work
สำหรับ Ollama เลือกโมเดลที่ประกาศ tools สำหรับ plugin ตรวจ:
- ประเภท completion/chat
- activation
- โมเดลที่ตรงใน mapping
- API key ของ administrator ปัจจุบัน
- tool-call support ของโมเดล
Work ไม่ switch ไป provider อื่นเป็น fallback
ติดตั้ง Package ไม่ได้หรือ Git Remote ล้มเหลว
ตรวจว่า policy มีชื่อที่เลือกอนุญาต network ไม่มี toggle ต่อ task จากนั้นตรวจ DNS, proxy, firewall/NetworkPolicy, registry, certificate, runtime, service upstream และ command Tab Git เป็น local เท่านั้น ใช้ terminal/model สำหรับ Git remote เฉพาะ network/credential ที่อนุญาตชัด ห้าม paste token อายุยาว
Run หยุดที่ Limit ของ Agent
Budget round/call อาจหมด Work ขอ handoff สุดท้ายที่ไม่มี tool ให้ review งานและส่วนที่เหลือ ต้องการ input คือ terminal state ของ run ไม่ใช่ claim ว่าเสร็จ Start run ถัดไปหรือเพิ่ม WORK_MAX_AGENT_ROUNDS โดยตั้งใจหาก resource/cost อนุญาต
HTTP 429 ระหว่าง Run
ถึง limit runtime active หรือ task คงอยู่ รอ operation อื่น หยุด preview ที่ไม่ใช้ ลบ task เก่า หรือเพิ่ม WORK_MAX_* ที่เกี่ยวข้องหากทรัพยากรพอ
Preview ไม่พร้อม
Command ต้องรันต่อ bind 0.0.0.0 และ listen WORK_PREVIEW_PORT ภายใน 15 วินาที Field ว่างหา dev ใน package.json, index.html แบบง่าย หรือ app nested หนึ่งรายการ หากหลาย/ไม่มีให้ป้อน command ชัด เริ่มที่ /workspace ใช้ cd <app-directory> && ... สำหรับ app nested
Preview รันบน Server แต่ไม่รันใน Browser Remote
ตรวจ build proxy ลงลายเซ็นและ restart URL เก่า Reverse proxy/tunnel ต้องให้ WebSocket ที่ /api/work/previews/ Docker port ที่ publish ต้องอยู่ loopback และไม่ต้องเปิด firewall
File ยังอยู่แต่ Preview หยุด
นี่เป็น expected หลัง cancel, server restart, stop ชัด หรือ readiness check ล้มเหลว Process ชั่วคราว volume คงอยู่ เปิด task และ start preview ใหม่
File เปิดหรือ Save ไม่ได้
API รับ text UTF-8 ถึง 2 MB หาก file เปลี่ยนหลังเปิด ให้ reload ก่อน save Highlighting เป็น text ปกติเหนือ 8,000 ตัวอักษร/400 บรรทัด formatting limit 100,000 ตัวอักษร/4,000 บรรทัด และเฉพาะ type ที่ documented
Work รายงานการ Recovery Sandbox
เมื่อ startup/shutdown พิสูจน์ไม่ได้ว่า sandbox ที่รู้จัก stop แล้ว Work fail closed และ retry ทุก 10 วินาที แก้ access API Docker/Kubernetes และตรวจ server log อย่าลบแถวฐานข้อมูลจน resource มี label ถูก reconcile
ลบ Task ไม่ได้
ตรวจ runtime ว่า reachable Resource conflict ที่ไม่มี label ai.libre-webui.task ตามคาดถูกปฏิเสธโดยตั้งใจ แก้ conflict อย่างระวังแล้ว retry
สรุปความปลอดภัย
- Work ค่าเริ่มต้นเฉพาะ administrator การเปิดทุกคนทำให้ account active ทุกบัญชีเป็น operator sandbox Folder host เฉพาะ admin
- Server ต้อง control Docker daemon หรือ Kubernetes namespace ที่ตั้งค่า
- Container ลด access filesystem แต่ไม่ใช่ VM
- Task ที่ไม่มี policy offline มี egress การจำกัด target เป็นหน้าที่ operator
- Volume Work ไม่มี disk quota อิสระ
- Git เป็น local เท่านั้น credential remote ไม่ mount หรือรับโดย API
- Firewall, daemon isolation, egress limit และ quota จริงให้โดย operator
- Provider remote รับ result ที่ขอและอาจทำ paid call หลายครั้ง
- Preview port อยู่ loopback และเข้าผ่าน URL ลงลายเซ็นที่ revoke ได้
- Compose มาตรฐานให้ Docker; Kubernetes/Helm ให้ Pod/PVC ด้วย
work.enabled=true - Backup ครบต้องใช้ฐานข้อมูล Libre WebUI และ volume Work