深度解析:多模態幀管線、推按說話語音回路與 LLM 提示面)
Rowboat 視頻通話模式Video Mode / Calls深度解析多模態幀管線、推按說話語音回路與 LLM 提示面【免費下載鏈接】rowboatOpen-source AI coworker, with memory項目地址: https://gitcode.com/GitHub_Trending/rowb/rowboat導讀本文深入剖析 Rowboat開源 AI 協作者具備記憶能力的本地桌面應用中通話Calls / Video Mode功能的完整技術實現用戶在與助手對話時助手可以看見用戶網絡攝像頭與看見用戶的屏幕屏幕共享。全文從產品交互流、幀捕獲管線、消息 Schema 與模型編碼、推按說話Push-to-Talk語音回路、伴隨窗口companion window機制、macOS 權限體系、LLM 提示詞目錄到共享屏幕指向screen-pointer與通話內驅動 App 的底層原理逐一展開并給出精確的源碼指針。讀完本文你將掌握 Rowboat 視頻通話模式單一引擎、四種預設的設計哲學、1fps 幀采樣與容量限制的參數化配置、基于按鍵釋放的零端點化語音回路以及如何通過# Video Mode/# Practice Session提示片段約束多模態模型行為。本文關聯文檔為 apps/x/VIDEO_MODE.md文中所有路徑均以倉庫根目錄為基準。一、產品流一個通話引擎四個預設入口Rowboat 的通話功能遵循ONE call engine單一通話引擎原則只有一套底層通話機制——按住說話Push-to-Talk下稱 PTT語音輸入、強制全文朗讀read-aloud的 TTS 輸出、幀捕獲frame capture——但通過四個只在起始設備上有差異的預設preset向用戶呈現不同的體驗。預設起始設備首次出現的界面voice— 主按鈕點擊、??Space、托盤 Quick Ask、卡片的收納手柄、Home 的 Skipper、發現性 toast攝像頭關、屏幕共享關若用戶選擇過粘性共享則自動重放Skipper 卡片懸停模式share— Share screen共享屏幕屏幕共享開、攝像頭關Skipper 卡片——即同樣的懸停召喚只是從一開始就帶著屏幕共享video— Video call視頻通話攝像頭開浮動小藥丸攝像頭在小藥丸內展開進入全屏practice— Practice session練習會話攝像頭開外加教練coaching人格全屏通話入口控件位于輸入區composer的通話拆分按鈕實現于 chat-input-with-mentions.tsx主點擊即懸停伴生模式voice預設chevron 菜單里才是其余三種偏離項。通話進行中按鈕變為紅色點擊即結束通話。單一懸停流ONE hover flow文檔反復強調ONE hover flow所有懸停入口最終都匯聚到startHoverCall()定義于 App.tsx和弦鍵chord、托盤項、收納手柄、toast 走主進程路徑relaySummon()→quick-ask:tuck→ 應用通話按鈕與 Home 的 Skipper 直接調用startHoverCall()。startHoverCall()會先應答中繼quickAsk:tuckAck啟動voice預設然后才發起粘性的或被share預設強制的屏幕共享——且是 fire-and-forget即發即忘in-flight 守衛in-flight guard在通話引擎落定的那一刻即釋放絕不會在設備獲取期間被長時間占用。一個啟動失敗的會話會回退到文本卡片quickAsk:show因此召喚永遠不會是靜默的空操作若未配置語音則從一開始就以文本卡片作為答案。單一表面規則callSurfaceApp.tsx中的callSurface派生值規定了通話的呈現方式核心鐵律是全屏與屏幕共享互斥——全屏通話覆蓋了整個屏幕此時共享屏幕就等于把通話本身共享出去。具體規則共享中 → 始終浮動彈窗popout小藥丸即工作態未共享 → 全屏除非callMinimized全屏即面對面展開小藥丸會自動停止任何共享最小化全屏通話會自動開啟一個共享藥丸的存在意義就是邊通話邊協作全屏下做演示presenting同樣折疊回藥丸攝像頭開關永不改變表面從藥丸打開攝像頭只是把視頻放進藥丸里展開是另一個顯式動作。屏幕共享的三層同意機制任一共享開始的瞬間彈出 toastYour screen is being shared… [Stop sharing]藥丸上常駐 Sharing screen 徽章macOS 的紫色錄制指示器purple recording indicator。若自動共享失敗未授予屏幕錄制權限通話仍會以純語音通話形式啟動并彈出一個指向系統設置的 toast。練習/教練模式始終是顯式選擇——展開全屏絕不會自動開啟教練。通話內控制與狀態機通話內控制條在兩個表面上完全一致按住說話按鈕按住說 / 點按鎖定免提——與 Right ? 鍵行為完全鏡像、麥克風靜音、攝像頭開關關閉時顯示剪影頭像不捕獲任何攝像頭幀、屏幕共享開關、吉祥物 ? R 字母頭像、結束通話。狀態提示條status chip引導用戶使用 PTT空閑時Hold right ? to talk · tap to go hands-free捕獲中Listening — release to send免提鎖定時Hands-free — tap ? to send。彈窗內嵌的是真實的聊天輸入區ChatInputWithMentions-提及、附件、單輪配置在通話中全部可用消息像普通輸入區消息一樣落入會話幀隨之攜帶。最小化表面上不渲染任何轉寫文本——回復以語音朗讀想看文字就展開。靜音是完整的輸入暫停而不只是靜音麥克風音頻停止到達 DeepgramuseVoiceMode.setPaused與思考/說話自動暫停按 OR 合并攝像頭/屏幕幀捕獲同樣停止useVideoMode.setCapturePaused靜音期間collectFrames()返回空所以靜音期間的打字消息也不攜帶任何幀——用戶可以轉身和房間里的人說話而不被助手偷聽設備保持占用以便即時取消靜音攝像頭指示燈與 macOS 共享指示器保持開啟——藥丸上的共享徽章會切換為 Sharing paused狀態提示條顯示 Muted 而非 Listening助手輸出不受影響進行中的語音繼續播放用 Stop 處理靜音狀態在通話開始/結束時重置為關閉。當助手思考或說話時吉祥物磁貼mascot tile上會出現紅色Stop按鈕立即靜音 TTS、跳過排隊中的語音片段若 run 仍在生成則中止該 run從任何位置停止 run——包括輸入區——也會靜音 TTS。進行中話語的字幕與助手朗讀的句子沿底部滾動。輸入區在通話中仍可打字幀也會隨打字消息一起攜帶。通話之外唯一保留的語音入口通話之外輸入區只保留一個語音控件麥克風按鈕按住說話的聽寫保持不變。語音回復只存在于通話內部強制全文朗讀掛斷即關閉。舊的視頻下拉菜單、talking-head 開關、朗讀耳機開關、摘要/全文 TTS 下拉菜單均已退役——計劃用助手消息上的per-message read aloud動作來替代文本進/語音出。通話按鈕在語音輸入Deepgram與語音輸出TTS均已配置時才可用。call_started攜帶preset事件被 PostHog 采集作為該功能的采納指標。彈窗機制Popout mechanics浮動小藥丸就是伴隨窗口companion window——即 ??Space 召喚的那個始終置頂窗口——的藥丸布局開啟時的攝像頭磁貼 吉祥物磁貼、實時字幕、控制條、輸入區重新定位到右上角。它浮在每個應用之上包括 Rowboat 自己。控制條動作通過video:popoutAction→ 主進程 →video:popout-action→ 應用窗口往返應用窗口擁有麥克風/攝像頭/捕獲expand還會將焦點重新還給應用窗口在 main 中處理。二、幀管線流 → 離屏 video → canvas JPEG → 環形緩沖核心實現在 useVideoMode.ts。useVideoMode為每個數據源各跑一條捕獲管線CapturePipe管道為MediaStream → 離屏 video → canvas JPEG → 環形緩沖。捕獲節奏與幀容量參數useVideoMode.ts頂部常量均可按需調整參數值說明CAPTURE_INTERVAL_MS1000每秒抓一幀足以捕捉表情與姿態變化同時控制請求體積MAX_BUFFERED_FRAMES120環形緩沖上限 ≈ 2 分鐘只覆蓋兩次發送之間的間隙MAX_CAMERA_FRAMES_PER_MESSAGE12每條消息最多攜帶 12 幀攝像頭畫面MAX_SCREEN_FRAMES_PER_MESSAGE4屏幕幀約 4 倍分辨率與 token且最新一幀遠比軌跡重要故上限更小CAMERA_FRAME_WIDTH512攝像頭幀縮到 512px 寬單幀約 20–40KB每條消息內聯十幾幀成本可控SCREEN_FRAME_WIDTH1280屏幕幀保留 1280px保證屏幕上文字對模型可讀CAMERA_JPEG_QUALITY0.65攝像頭幀 JPEG 質量SCREEN_JPEG_QUALITY0.7屏幕幀 JPEG 質量attachPipeSource在數據源首次送達時立即抓取首幀loadeddata事件隨后按setInterval穩定節拍抓取capturePipeFrame對近空 data URL100 字節直接丟棄以跳過源尚未溫熱的空幀。collectFrames()的采樣策略drainPipe排空自上次發送以來緩沖的幀均勻采樣evenly sampled至上限始終保留最新幀并在發送瞬間額外抓取一幀當快速連續發送消息rapid-fire沒有新幀累積時回退到僅最新一幀——保證源預熱后每條消息至少帶一幀。幀按來源標記攝像頭幀在前屏幕幀在后。一個值得注意的細節useVideoMode.ts實現了對 macOS 屏幕錄制權限的經驗性檢測——screenFrameLooksBlank()。因為 macOS 在未授權時仍會讓捕獲成功只是交付全黑幀所以代碼將捕獲到的 160×90 縮略圖做亮度均值與方差分析均值 8 且方差 4 判定為內容被屏蔽真實的桌面——哪怕是深色——也有菜單欄、窗口等結構。該函數先等 700ms 讓捕獲穩定避免把合法的啟動黑幀誤判為權限問題。靜音暫停捕獲setCapturePaused(true)時兩條管道的抓取函數直接 returncollectFrames()也返回空數組連靜音前的緩沖幀都不帶杜絕靜音時段被后來的消息攜帶。在 App.tsx 的handlePromptSubmit中當通話進行時排空的幀會作為UserImagePart附加到外發消息上攝像頭或屏幕任一激活時設置composition.videoMode練習會話期間額外設置composition.coachMode。幀同時也成為isVideoFrame顯示附件轉寫面板里的膠片條——見 chat-message-attachments.tsx歷史會話回填在 lib/run-to-conversation.ts。三、消息 Schema 與模型編碼UserImagePart真正的多模態圖像部分定義于 packages/shared/src/message.tstype: image、data無data:前綴的 base64 字節、mediaType如image/jpegsource: camera | screen可選——標記幀來自攝像頭還是屏幕capturedAt可選 ISO 時間戳。關鍵區別與文件附件不同附件是路徑引用、通過LLMParse工具讀取圖像部分是以真實的多模態圖像部分real multimodal image parts直接發給模型的。convertFromMessages上下文行 分組標簽編碼邏輯位于 packages/core/src/runtime/assembly/message-encoding.ts 的convertFromMessages先發出一個上下文行[Video mode: N live webcam frames … and M frames of the users shared screen …]實測文本為[Video mode: … attached below, each group oldest to newest, recorded while they composed this message.]見該文件 L201攝像頭圖像前加Webcam frames (oldest to newest):文本部分屏幕圖像前加Screen-share frames (oldest to newest):文本部分。這樣模型永遠不會把用戶本人與其屏幕混淆。歷史中的幀刻意保持內聯不裁剪裁剪會每次輪轉都破壞提供方的前綴緩存prefix caching成本反而高于保留。而自動權限分類器auto-permission classifier會把每條消息內容字符串化并截斷到約 3KB因此內聯 base64 不會撐爆其提示詞。四、推按說話Push-to-Talk語音回路Rowboat 語音回路的核心哲學用戶的按鍵手勢就是端點endpoint——沒有靜音檢測silence detection沒有端點化啟發式endpointing heuristics且助手的 TTS永遠不會被轉寫回給自己麥克風門只在用戶刻意說話時打開。手勢語義Right ?或任一表面的屏幕說話按鈕按住≥350ms按住期間麥克風門打開松開即提交話語submit the utterance。快速點按350ms助手正在說話時點按 STOP——完全打斷音頻 排隊回復 生成麥克風保持關閉下一次點按恢復正常行為靜默時點按鎖定免提捕獲hands-free下一次點按提交。免提鎖定期間仍無自動提交——閉合的點按才是端點。和弦Right ? 按住時按其他鍵/點擊此次按壓是鍵盤快捷鍵而非說話手勢——進行中的按住被取消鎖定中的捕獲吞掉對應的松開。Escape 同樣取消。在助手思考/說話時按下靜音其音頻并開始監聽——但 run 與其回復依然存活意外或空按壓永遠不會白費答案未說出的語音段凍結并在松開時恢復。只有真正提交的話語才會中止上一輪并丟棄其未說出的積壓。Stop 按鈕仍是硬中止。邊沿觸發的 PTT 狀態機App.tsx中的handlePttDown/handlePttUp/handlePttChord構成一個邊沿觸發edge-triggered的狀態機聚合兩個輸入源全局按鍵鉤子apps/main/src/ptt.ts基于 uiohook-napi系統級監聽 Right ? 的 down/up/chord通過voice:ptt-key推送給應用窗口。僅當通話或其他消費方激活時運行用voice:setCallActive引用計數。需要 macOS 的輸入監控權限ptt:getStatus中的eventsSeen是活性信號鉤子已運行但事件數為 0 權限未生效——應用會在首次通話約 4 秒后顯示一次性權限對話框。DOM 監聽器應用窗口聚焦時監聽e.code MetaRight的 keydown/keyup——無需輸入監控權限的兜底方案。兩個源在應用聚焦時重疊80ms 內的相同邊沿合并為一次PTT_EDGE_ECHO_MS。useVoiceMode 的會話 API核心實現在 useVoiceMode.tsstartPtt(onUtterance)為整個通話獲取麥克風 Deepgram socket按鍵按下即可瞬時捕獲音頻通過setPaused(true)門控關閉每 5s 一次的 KeepAlive 保持空閑 socket 存活Deepgram 無音頻約 10s 會關閉連接見KEEPALIVE_INTERVAL_MS。pttBegin()清空轉寫緩沖并打開麥克風門。pttEnd()沖刷緩沖音頻發送 DeepgramFinalize讀取最終轉寫 尾部 interim關閉門觸發onUtterance。實現中先flushBufferedAudio()再finalizeDeepgramStream()且先讀轉寫再setPaused(true)setPaused(true)會清空轉寫緩沖注釋明確警告順序問題。pttCancel()關閉門并丟棄已聽到的一切。通話中 socket 掉線 1s 后重連ws.onclose中若pttCbRef.current仍存在則重連離線音頻積壓有上限約 500 塊 × 64ms ≈ 30s。Deepgram 會話參數DEEPGRAM_PARAMSmodelnova-3、encodinglinear16、sample_rate16000、channels1、interim_resultstrue、smart_formattrue、punctuatetrue、languageen、endpointing100、no_delaytrue。波形由 ScriptProcessor 以 1024 采樣幀16kHz 下約 64ms產出約 16 次/秒的振幅更新自動增益基于運行峰值PEAK_DECAY0.97、MIN_PEAK0.02緩沖上限MAX_AUDIO_LEVELS4800。通話生命周期App.tsx的startCall(preset)/endCall()進入通話會保存/強制 TTS 設置、取消任何輸入區聽寫、啟動 PTT 會話結束則恢復一切。通話持有麥克風期間輸入區聽寫被禁用。靜音完全阻斷 PTT靜音時按鍵無操作捕獲中靜音則丟棄已聽內容。五、伴隨窗口懸停表面一個始終置頂的窗口主進程 apps/main/src/quick-ask.ts渲染端 components/quick-ask-bar.tsxhash#quick-ask通過quick-ask:modepinned | hidden推送只有一種可見角色Skipper自包含卡片頂部條logo · 目標 · 窗口操作 · 分享 · 說話/停止 · 小的 ? 關閉下面是真實輸入區藥丸活躍攝像頭需要自視self-view時。吉祥物只存在于攝像頭藥丸中卡片改用信號表達麥克風門打開時輸入區切換為應用的錄制條波形 interim 轉寫接入通話的 PTT 狀態機↑ 發ptt-up? 丟棄發ptt-cancel進行中的輪次顯示為頂部 logo 的輝光 響應面板的 spinner-and-shimmer 活動行輸入區占位符按平臺命名說話鍵hold right ? / right Ctrl to speak平臺感知邏輯在 packages/shared/src/ptt-key.ts。沒有獨立的 popout 窗口也沒有第二個 ask bar 角色。NSPanel 細節窗口是type: panel的 NSPanel關鍵配置setVisibleOnAllWorkspaces(true, { visibleOnFullScreen: true, skipTransformProcessType: true })浮于每個 Space 之上包括其他應用的全屏 SpaceskipTransformProcessType保住 Dock 圖標否則visibleOnFullScreen會在窗口存在期間把應用變成 macOS agent 應用——看起來像 Rowboat 消失了fullscreenable: false否則在激活 Space 為全屏時創建的窗口可能直接以全屏窗口打開藥丸吞掉整個屏幕。釘住pinned當且僅當派生的callSurface popoutApp.tsx 中的 effect。渲染端請求video:setPopout {show}main 重新定位伴隨窗口Skipper 卡片在其錨點角落攝像頭通話用舊的 popout 幾何位置右上角并顯示有待處理的召喚時聚焦否則showInactive()以免搶焦點。Blur 不產生任何行為旁邊工作的伴隨窗口不能因為點擊別處就消失Esc 只是收起文本而非關閉??Space 折疊/展開文本面板。揭示協議Reveal protocol每次quick-ask:mode推送攜帶seq渲染端在提交該呈現兩幀后即已繪制通過quickAsk:modeApplied應答。main 先把窗口以 opacity 0 排序顯示以便渲染端繪制收到 ack 后才置 opacity 1聚焦——絕不讓半成布局上屏。折疊同樣先推送、收到 ack 后縮小窗口開放卡片永遠不會被擠進吉祥物大小的邊界哪怕一幀。超時600ms頁面仍加載時為 6s防止卡死的渲染端阻塞。渲染端在知道自身角色前什么都不繪制hidden 時完全不繪制index.html從第一幀繪制起就給#quick-ask/#screen-pointer透明背景。通話狀態流通過video:popout-state推送通道main 在 quick-ask.ts 緩存最后載荷在窗口加載和每次釘住時重放。渲染端離開 pinned 角色即丟棄其鏡像通話結束時應用推送顯式 idle 狀態緩存跨全屏 ? 彈窗抖動存活所以攝像頭通話回來仍是藥丸而非變形的卡片。無應用窗口用戶關閉了或仍在加載召喚會以隱藏態重建它main.ts中initQuickAsk({ ensureAppWindow })并在應用的quickAsk:appReady握手時重發中繼未應答的中繼由看門狗重發一次有應用窗口時 1.5s啟動期間 8s之后記錄日志絕不用其他表面應答。通話中關閉應用窗口會取消伴隨窗口的釘住onAppWindowClosed。藥丸捕獲自己的攝像頭預覽MediaStream 無法跨窗口并合成吉祥物嘴部幅度該窗口無音頻。而卡片的錄制條波形是真實的應用窗口通過video:popoutLevels→video:popout-levels中繼語音鉤子的逐幀振幅約 16/s批量條隨應用輸入區自己的節拍跟蹤真實語音。Levels 絕不在 main 中緩存——波形只有實時才有意義。磁貼顯示實時像素控件顯示能力。純語音通話攝像頭關、無共享渲染沒有 You 磁貼的藥丸吉祥物 響應 輸入區 控件——展開一個語音通話絕不會被讀成用戶沒開始的視頻通話。切換攝像頭/共享會在原位變換磁貼/徽章。video:popoutAction中繼控制條動作到應用窗口只按真實應用窗口 URL 匹配——getAllWindows()也包含伴隨窗口與隱藏工具窗口PDF 導出這些絕不能顯示或發消息。藥丸聚焦時按 Right ? 同樣作為 ptt-down/ptt-up 動作中繼該場景無需輸入監控權限。收起態迷你通話藥丸voice-to-voice釘住表面可折疊為迷你通話藥丸quickAsk:setPinnedCollapsed呈現狀態隨quick-ask:mode推送logo點擊展開· 狀態通道 · 共享 · 說話/停止 · 結束藥丸主體作為拖拽手柄左側有 ? 展開手柄作為回到文本輸入的可見路徑鏡像卡片的 ? 收納手柄??Space 和 logo 也可。狀態通道在折疊時持續敘述——說話時抖動波形、思考時 spinnershimmer 活動、朗讀回復時連貫滾動說話波、靜止時說話鍵提示Hold right ? / Hold right Ctrl平臺感知——除提示外動態即全部故事藥丸雙向都不顯示轉寫用戶把文本收起來了展開去讀。活躍共享在點亮的共享按鈕上保持同意徽章。卡片的 ? 收納手柄、Esc、點擊卡片旁舞臺均進入此狀態??Space 切換之。收起/展開從不結束會話——只有 End close 才結束。六、權限體系攝像頭voice:ensureCameraAccess在getUserMedia之前解決 macOS TCC 提示與麥克風同一模式——否則首次點擊會在原生提示彈出期間靜默失敗。NSCameraUsageDescription在 forge.config.cjs 的extendInfo中。屏幕getDisplayMedia由 main.ts 的setDisplayMediaRequestHandler以主屏幕自動批準無選擇器meeting:checkScreenPermission在首次使用時把應用注冊進 macOS屏幕錄制設置列表。由于權限被拒或提示未應答時getDisplayMedia可能永遠掛起useVideoMode.startScreenShare將整個獲取過程限時 10sSCREEN_SHARE_START_TIMEOUT_MS并干凈失敗——歷史上一次掛起的共享會把screenState卡在starting直到會話結束見 useVideoMode.ts L321-L384 注釋。輸入監控全局 PTT 鍵鉤子啟動 uiohook 事件 tap 會在首次使用時觸發 macOS 同意提示但缺失授權不會報錯——只是事件永不到達eventsSeen保持 false。授權前創建的 tap 永遠失效ptt:retryHook重新創建它見 ptt.ts 的retryPttHook以及openInputMonitoringSettings直接打開x-apple.systempreferences:...Privacy_ListenEvent面板。拒絕永不沉默components/permission-dialog.tsx 是麥克風/攝像頭/輸入監控失敗背后唯一的對話框——解釋缺失的權限并深鏈到精確的系統設置面板app:openPrivacySettings。屏幕共享失敗保持 toast通話進行中模態框會擋路。七、LLM 提示詞目錄提示位置# Video Mode (Live Camera)系統片段——如何使用攝像頭幀、教練指引、屏幕共享規則把屏幕當作主要主題、最后一幀屏幕幀即當前狀態、禮儀絕不評論外貌packages/core/src/runtime/assembly/capabilities/modes.tsvideo-mode能力的VIDEO_MODE片段由runtime/assembly/compose-instructions.ts組合# Practice Session (Coach Mode)系統片段——教練人格每次 take 后給出具體、可行動的反饋流程中一句句插話收尾時結構化復盤同上modes.tsCOACH_MODE片段緊隨視頻能力之后視頻模式片段中的 Driving the app 段落——通話中優先用應用導航的 read-view/open-item邊說邊展示而非描述或瞇眼看幀同一# Video Mode片段完整動作文檔在app-navigation技能runtime/assembly/skills/app-navigation/skill.ts每消息幀上下文行[Video mode: N live webcam frames … and M frames of the users shared screen …] 分組標簽packages/core/src/runtime/assembly/message-encoding.tsconvertFromMessagesvideoMode/coachMode合成覆蓋會話粘性翻轉會打破前綴緩存packages/core/src/runtime/turns/bridges/real-agent-resolver.tsCompositionOverrides由App.tsx的sendConfig設置語音輸入/輸出提示片段# Voice Input、# Voice Output原樣復用——通話按話語設置voiceInput并強制voiceOutput: full。從modes.ts源碼可提取VIDEO_MODE片段的完整指令語義幀的使用用于視覺感知真正增值之處——表情、肢體語言、姿態、手勢、與鏡頭的眼神接觸、舉到鏡頭前的東西、相關環境跨幀比較以發現消息內的變化對表演性練習pitch、演示、面試、講話給出基于實際所見的具體、可行動反饋最后幾幀你低頭移開了視線而非泛泛建議若用戶向鏡頭展示物體/文檔/白板讀出來并回應。驅動應用優先read-view 讀取數據 屏幕上展示 簡短口述而非瞇眼看屏幕幀——讀視圖數據是精確的。屏幕共享屏幕幀在獨立分組屏幕是主要主題最后一幀最當前幀是降采樣捕獲小字可能難讀需要時明確要求放大錯誤信息而非猜。禮儀不要每輪都敘述所見絕不評論外貌幀是周期性快照而非連續視頻不得斷言看不見的連貫運動。COACH_MODE片段則要求觀察節奏/填充詞/結構/從幀看姿態眼神表情手勢能量每次 take 后給 2-3 條具體觀察并引用事實你說 ask 時低下了頭、開頭的 um so basically 削弱了你的鉤子流程中最多一句插話或保持沉默開局若不明顯就問練習目標投資人 pitch面試會議演講收尾給結構化復盤做得好的、Top 3 改進、一個具體練習/重構建議鼓勵但誠實絕不評論外貌。八、指向共享屏幕Pointing at the shared screen屏幕共享進行中助手可以指向用戶真實顯示器上的位置screen-pointer內建工具由app-navigation技能附加接受分數坐標x/y 取值 0–1從最新屏幕共享幀估算加可選的小標簽main 在那里繪制動畫激光點 ping 環。這個低谷就是周末從此帶著一根手指落在圖表上。工具定義packages/core/src/runtime/tools/domains/screen-pointer.ts——動作pointx、y、label?≤60 字符、durationMs?默認自動隱藏 8s、范圍 1000–30000ms和hide。通過 DI 接縫IScreenPointerService像瀏覽器控制一樣注冊于 main.ts直接在 main 中執行——無渲染端往返——無共享進行時以解釋性錯誤硬失敗No screen share is live — pointing only works while the user shares their screen…。共享門App.tsx 的一個 effect 把video.screenState live通過screenPointer:setShareActive上報共享結束立即拆除指針。覆蓋層apps/main/src/screen-pointer.ts 創建一個透明、點擊穿透setIgnoreMouseEvents、不可聚焦、屏保級別的 NSPanel 覆蓋主顯示器共享始終捕獲主顯示器加載帶#screen-pointer的渲染端 → components/screen-pointer-overlay.tsx。狀態通過screen-pointer:state推送加載時重放nonce在指向同一位置兩次時重啟 ping。窗口只在有點擊目標時存在——隱藏即銷毀。提示面# Video Mode屏幕共享片段中的 You can POINT at their screen 要點modes.tsapp-navigation技能中帶工作示例的 Pointing at the users shared screen 小節。點擊/鍵入曾被探索并移除文檔記錄了一段重要的設計史一個screen-control工具點擊幀坐標 向聚焦字段鍵入曾短暫上線且機制上可用但被移除從 1280px 寬的幀瞄準小目標會落空模型在動作之間是失明的幀只隨用戶消息到達導致它鍵入錯誤的焦點卻報告成功缺失的拼圖是工具結果中的動作后驗證幀post-action verification frame。若重建文檔留下硬性教訓現代 macOS 上 System Events 的click at不點擊也返回成功——應通過osascript -l JavaScript ObjC 橋發送真實 CGEvents無需原生模塊、僅 Accessibility、無需 Automation 同意未受信進程的 CGEventPost 會靜默丟事件所以前置的isTrustedAccessibilityClient自檢是唯一可靠的門TCC 鍵授予的是代碼簽名ad-hoc 構建每次重建都會失去授權Developer ID 簽名可解決。Web 任務從來不需要它——內嵌瀏覽器browser-control以元素級精確操作并逐動作返回頁面狀態。完整實現在分支歷史feat/screen-pointer-controlpre-removal。九、通話中驅動應用Driving the app on a call助手可以通過擴展的app-navigation內建工具app driver驅動 Rowboat UI 本身open-view打開任意主視圖read-view返回該視圖渲染的數據郵件 / 后臺代理 / 會話歷史——渲染端同時導航過去用戶眼睜睜看著它發生open-item深度鏈接打開特定郵件線程、筆記、后臺代理或過往會話。數據來自與 UI 的 IPC 處理器相同的核心函數listImportantThreads/searchThreads、后臺任務的listTasks、sessions 容器——沒有對屏幕幀做 OCR。渲染端通過 App.tsx 的applyAppNavigation應用結果同時從兩條事件路徑取數遺留的runs:eventsref 輪詢以及會話聊天對話上的 watcher輪次運行時不發出遺留 run 事件——漏掉這條導航會在工具報告成功時靜默空轉。會話切換會播種 watcher因此重放歷史從不觸發導航。通話中可見導航還會把全屏通話折疊成藥丸并聚焦應用窗口app:focusMainWindow讓用戶真正看到屏幕變化。卡片標簽在 lib/chat-conversation.ts。通話提示與app-navigation技能共同教授邊說邊展示show-while-telling模式read-view → 口述要點 → 用戶選中后 open-item。十、延遲工程語音到語音的四點優化語音到語音延遲用戶停止說話 → 助手出聲在四個點被工程化call_turn_latencyPostHog 事件度量真實分布utterance → submit → first speak → audio playingPTT 端點useVoiceMode.ts的pttEnd按鍵釋放就是端點——完全沒有靜音檢測。釋放后的提交延遲只剩 DeepgramFinalize往返典型值遠低于舊式 600–1800ms 的端點化等待且誤觸發說到一半被截斷、TTS 混入在結構上不可能。流式 TTSvoice:synthesizeStreamStart→voice:tts-chunk→ useVoiceTTS.ts 中的 MediaSource 播放空閑隊列的首個片段從第一個 MP3 塊就開始播放而非等完整正文ElevenLabs/streamflash 模型。后續片段保持無縫的全正文預取路徑。任何失敗回退到非流式。早句語音turn-view.tsx 的applyOverlay仍在打開的voice塊 ≥60 字符時立即發出其最后一個完整子句——句子其余部分還在生成時語音已經開始。確認提示音lib/call-sounds.ts話語被接受的瞬間播放輕柔 blip——感知延遲與實測延遲同樣重要。十一、在 Skipper 上打字Skipper 卡片承載真實輸入區ChatInputWithMentions知識筆記 -提及、附件、模型/精力選擇器、搜索/代碼/權限開關。提交通過 main 中繼完整載荷quickAsk:submit→quick-ask:submit→handleHoverSubmit進入伴隨窗口自己的會話——絕不是應用窗口的會話——回復通過語音回復的同一調用鏡像返回video:popoutState→video:popout-state因此沒有第二條答案通道。語音跟隨問題的模態打字提問靜默渲染語音提問朗讀出來外加卡片上的顯式揚聲器靜音。輸入區上方的條帶承載目標 chip此會話繼續哪個會話帶最近切換器Command Center 優先、新會話、歷史窺視、揚聲器靜音、Open-in-Rowboat。設備控制麥克風、共享、結束在吉祥物的別針上打開與收起兩種狀態皆有。已退役2026-08summoned角色——一個獨立 Spotlight 式 ask bar帶自己的答案面板quickAsk:state、本地聽寫quick-ask:summoned按住說話、Stop 中繼quickAsk:stop、關閉quickAsk:hide/blur以及 voice-out 無通話共享開關quickAsk:setOptions/quickAsk:optionsState。這些通道及其 App 側管道speakTurnRef、quickAskActiveRef、quickAskOptionsRef已刪除。??Space 現在只有一個結果沒有第二個布局會閃爍、競爭或卡死。無法成為會話的召喚語音未配置或引擎啟動失敗會在應用窗口中解釋——前臺化并帶打開設置的 toast——絕不通過顯示不同的浮動表面。十二、成本說明與已知限制Token 成本基準幀內聯多模態攝像頭幀每幀約 250–350 tokens≤12 幀/消息 ≈ 3–4k屏幕幀每幀約 1.5–2k tokens≤4 幀/消息 ≈ 6–8k。歷史保持幀內聯長會話增長但保持前綴緩存。成本吃緊時的第一根杠桿除非屏幕變化每條消息只發一幀屏幕幀。已知限制以當前倉庫為準無開放式麥克風插話open-mic barge-in——但在助手說話時按 PTT 會靜音它并開始監聽新話語提交后該 run 被中止所以打斷從不依賴 Stop 按鈕。全局 PTT從其他應用按 Right ?需要 macOS 輸入監控權限沒有它 PTT 僅在應用窗口聚焦時可用DOM 兜底。幀采樣而非視頻幀間運動不可見提示明確要求模型不得斷言相反。聲樂交付反饋有限Deepgram 把語音降為文本能量教練依賴視覺線索。屏幕共享始終捕獲主顯示器尚無窗口/顯示器選擇器。全屏通話遮住會話無通話中轉寫抽屜。不發起通話但給打字消息附加攝像頭幀的組合舊 videochat 模式在通話模型簡化中被移除若分析顯示有需求它應以附件 chip 而非模式回歸。結語Rowboat 的視頻通話模式是單一引擎、四種預設設計哲學的完整落地一套 PTT 強制朗讀 TTS 幀捕獲引擎通過起始設備差異呈現 voice / share / video / practice 四種體驗callSurface規則保證全屏與共享互斥collectFrames的均勻采樣與容量上限把多模態請求控制在可預測的 token 預算內convertFromMessages的分組標簽讓模型從不混淆用戶與屏幕PTT 以按鍵釋放為端點消滅了端點化延遲伴隨窗口與揭示協議保證了懸停體驗的即時與穩定。對想要復用或擴展這套能力的人來說VIDEO_MODE.md 與本文給出的源碼指針useVideoMode.ts、useVoiceMode.ts、modes.ts、ptt.ts是繼續深入的最佳起點。【免費下載鏈接】rowboatOpen-source AI coworker, with memory項目地址: https://gitcode.com/GitHub_Trending/rowb/rowboat創作聲明:本文部分內容由AI輔助生成(AIGC),僅供參考