preview
agent 可以用 preview 把有網頁介面的東西放到公開連結上,讓你能從手機開啟,或傳給別人:可以是監聽中繼所在機器某個連接埠的 dev server,也可以是一個存放純檔案的資料夾。它也能列出並關閉自己對話中的預覽。
用平常的話提出要求就行:「啟動 dev server,給我一個連結」、「讓我看看建置好的網站」。agent 會被告知:只要你想看、試用或分享網頁介面,就使用這個工具,而且絕不要叫你去開 localhost。
預覽連結是公開的
任何拿到連結的人都不必登入就能開啟這個應用程式。連結中的 token 是唯一的保護。agent 會被告知在給你連結時說明這一點。預覽用完後請把它關閉。
你會看到什麼 #
- 對話的背景任務面板中有這個預覽的卡片,附有 Open(開啟)、Copy link(複製連結)和 Close(關閉)。
- 對話紀錄中,agent 發布預覽的那則回覆上有一張連結卡片。預覽消失後,卡片會顯示
closed徽章。對話的分享檢視只顯示卡片上的名稱,絕不顯示連結。 - 中繼的每個預覽(涵蓋所有對話)都列在 Settings → Previews(設定 → 預覽)下,每個都附有關閉按鈕。
- 連接埠預覽背後的 dev server 停止回應時,卡片上會出現
offline徽章。連結仍保持登記:在同一個連接埠上重新啟動伺服器,同一個連結就又能使用。
不透過 agent,你也可以在輸入區輸入 / 做同樣的事:
/preview 5173 web app publish a port
/preview ./dist built site publish a folder
/preview list list the previews
/preview close close one
設定 #
在中繼的管理者設定好之前,預覽都是關閉的。預覽需要自己的主機名稱,與中繼的主機名稱分開,這樣被預覽的應用程式就永遠無法存取中繼本身。需要三件事:
- 一個你能控制的主機名稱,與中繼的主機名稱不同——必須是名稱不同,不能只是連接埠不同。
- 一個前端 proxy(Caddy、Cloudflare Tunnel……),把這個主機名稱指向預覽連接埠。
- 中繼
config.中的json previews區塊:
{
"publicHostnames": ["relay.example.com"],
"previews": {
"enabled": true,
"port": 3334,
"bindHost": "127.0.0.1",
"publicBaseUrl": "https://preview.example.com",
"allowedTargetHosts": [],
"maxLive": 8
}
}
不論是否完成這些設定,agent 都有這個工具。沒有設定時,create 呼叫會傳回原因,而 agent 會被告知把原因轉告你:這要由管理者來修正。
依供應商 #
| 供應商 | |
|---|---|
| Claude、Claude API 0.9.18 新增、DeepSeek 0.9.17 新增、Cursor | 有 preview 工具 |
| Grok;擴充功能引擎上的 GitHub Copilot 與 OpenAI | 有 preview 工具,透過 OAR 的 MCP 伺服器 0.9.4 新增 |
| SDK 引擎上的 GitHub Copilot 與 OpenAI | 沒有工具。預覽已設定好時,agent 會被告知如何呼叫中繼的預覽 API,規則相同,而且呼叫中已寫入它的對話。你看到的結果一樣。 |
| Claude Cloud | 無:雲端 session 在 Anthropic 的沙箱中執行,你的機器上沒有可發布的連接埠或資料夾 |
動作 #
| 動作 | 作用 | 參數 |
|---|---|---|
create |
發布一個連接埠或資料夾 | port 或 dir,可另加 label |
list |
列出此對話的預覽 | |
close |
關閉此對話的其中一個預覽 | token,對話中恰好只有一個預覽時可省略 |
結果是 JSON,內容為 "ok": true,或 "ok": false 加上一段 error 文字。這個工具不會以其他方式失敗;錯誤的參數會以 agent 讀得懂的 error 傳回。
create #
發布一個連接埠或一個資料夾,一次呼叫中不會兩者都發布。
0.9.11 新增 在同一個對話中再次發布同一個連接埠或資料夾,會傳回已在運作的那個預覽,連結相同,名稱不變;這時結果會寫著 "existing": true。
| 參數 | 類型 | |
|---|---|---|
port |
1024–65535 | dev server 的本機連接埠 |
dir |
路徑 | 要以純檔案提供的資料夾:絕對路徑,或相對於對話工作資料夾的路徑 |
label |
文字,最多 120 個字元 | 預覽卡片上的名稱 |
Dev server(port) #
中繼會把請求轉送給監聽該連接埠的伺服器。它不會啟動、監看或重新啟動那個伺服器;那個伺服器仍是 agent 的一般背景任務,有自己的停止按鈕。
每個預覽都位於預覽主機名稱下自己的路徑。瀏覽器請求的是 /;中繼在轉送請求前會移除這個前綴,並透過 X- 告訴應用程式這個前綴。它不會改寫頁面。所以,只要應用程式送出的連結和資源位址是相對路徑或帶有前綴,同時能處理不帶前綴的請求,它就能正常運作。從主機根目錄請求 / 的應用程式會找不到它。
因此 agent 會被告知要先呼叫 create,從結果中讀取 base,然後才啟動 dev server。
agent 收到的指示不適用於每一種 dev server
工具本身的說明建議在啟動伺服器時設定 base path(Vite --base、Next.js base、Express 的掛載前綴)。但這樣設定後若伺服器預期收到的請求帶有前綴,就與中繼轉送的內容不符:Vite 的 dev server 和掛載在該前綴上的 Express router 都不是這樣運作的。預覽說明了可行的做法。
{ "action": "create", "port": 5173, "label": "web app" }
{
"ok": true,
"existing": false,
"url": "https://preview.example.com/test_0123456789abcdef0123456789abcdef/",
"basePath": "/test_0123456789abcdef0123456789abcdef/",
"token": "0123456789abcdef0123456789abcdef",
"mode": "port",
"hint": "Serve the app under /test_0123456789abcdef0123456789abcdef/ (the proxy strips the prefix and sends X-Forwarded-Prefix). Bind the dev server to 127.0.0.1, not 0.0.0.0: the relay's proxy reaches it there and nothing else should. Tell the user the URL and that the link is public."
}
0.9.17 新增 hint 也會告訴 agent 把 dev server 綁定到 127.,而不是 0.:中繼的 proxy 在那裡連得到它,其他任何東西都不應該連得到。只有具備 preview 工具的 session 會收到這一行(見依供應商)。被教導使用預覽 API 而不是工具的 agent 不會收到:SDK 引擎上的 GitHub Copilot 與 OpenAI,以及中繼以 OAR_ 執行時的 Grok 和 Copilot 擴充功能引擎。
資料夾(dir) #
中繼自己提供資料夾中的檔案。不需要執行任何東西:適合建置輸出、設計稿、單一 HTML 檔案或覆蓋率報告。
- 資料夾必須位於對話的工作資料夾內。每次請求時都會再檢查一次,所以連結之後也無法被導向外部。
- 名稱以點開頭的檔案和資料夾(
.、git .)一律不提供,金鑰檔案(env *.、pem *.、key id_)也一樣。rsa… - 請求資料夾路徑時會提供
index.。html - 相對的資源路徑照常可用。從主機根目錄開始的路徑(
/)則不行。assets/ app. js - 不支援 WebSocket 連線。
{ "action": "create", "dir": "./dist", "label": "built site" }
結果有相同的欄位,並帶有 "mode": "static"。
list #
列出 agent 自己對話中的預覽,包含 token、label、url、target(資料夾,或 localhost:<port>)、online 和所屬對話。0.9.14 新增 0.9.14 之前,這份清單涵蓋中繼的所有預覽;預覽的 token 是它唯一的保護,所以 agent 現在只看得到自己的預覽。整個中繼的清單是給你看的,在 Settings → Previews 中,也可以用 / 查看。中繼重新啟動後無法檢查的預覽會帶有 "unverified": true,在檢查得到回應之前不會提供(見中繼重新啟動後)。
{ "action": "list" }
{
"ok": true,
"enabled": true,
"previews": [
{ "token": "0123456789abcdef0123456789abcdef", "label": "web app", "url": "https://preview.example.com/test_0123456789abcdef0123456789abcdef/", "target": "localhost:5173", "online": true, "conversationId": "3f9c…" }
]
}
close #
關閉連結。連結背後的 dev server 會繼續執行。
| 參數 | 類型 | |
|---|---|---|
token |
32 個十六進位字元 | 來自 create 或 list 的 token。對話中恰好只有一個預覽時可以省略。 |
沒有 token 而對話中有多個預覽時,呼叫會傳回 error 以及可供選擇的清單。
0.9.14 新增 agent 只能關閉自己對話中的預覽。其他對話的預覽 token 會被拒絕:
{ "ok": false, "error": "This preview belongs to another conversation; a conversation can close only its own previews. The owner can close it in Settings → Previews." }
{ "action": "close", "token": "0123456789abcdef0123456789abcdef" }
{ "ok": true, "closed": { "token": "0123456789abcdef0123456789abcdef", "label": "web app" } }
限制 #
| 限制 | 值 |
|---|---|
| 同時存在的預覽數(整個中繼) | 8(previews.) |
| agent 能列出和關閉哪些預覽 | 自己對話中的 0.9.14 新增 |
| 連接埠 | 1024–65535,且絕不能是中繼自己的連接埠 |
| 連接埠預覽可以指向哪裡 | 中繼自己的機器(迴路位址),以及管理者在 previews. 中列出的主機 |
| 資料夾預覽可以指向哪裡 | 對話的工作資料夾內 |
| 存續期間 | 直到被關閉,或所屬對話被刪除。0.9.11 新增 預覽在中繼重新啟動後仍會保留;連接埠預覽在機器重新開機時結束,資料夾預覽則在資料夾不再位於工作資料夾內時結束。預覽不會自行過期。 |
| 名稱 | 120 個字元 |
預覽與中繼彼此隔離:預覽在另一個連接埠、另一個主機名稱下提供,那裡沒有任何中繼自己的頁面或 API。預覽之間共用那個主機名稱,各自位於自己的路徑下。
對話範圍並不是一道牆
中繼會把預覽請求的範圍限定在請求所指名的對話,對話寫在 conversation 查詢參數中,或寫在每個 session worker 和 OAR 的 MCP 伺服器都會傳送的對話標頭中。agent 使用和你相同的中繼 token,所以範圍是由請求自行宣告的,而不是經過證明的:沒有指名對話的請求仍然會拿到所有預覽。這個範圍讓工具和 agent 被教導的呼叫只限於自己的對話;它擋不住讀取中繼 token 並自己動手呼叫 API 的 agent。見 OAR 會暴露什麼。