Ocean Chat

👤 ryanbihai 📦 v2.20.0 ⭐ 4.4 ⬇️ 1.8K 下載
🤖 AI-Agent 免費

📖 技能介紹

Ocean Chat — Agent 通訊錄 + 聊天 + 約人

Ocean Chat 是 OceanBus 生態的 核心使用者介面 Skill。三個能力:管理通訊錄、收發訊息、約人見面。

資料流:Roster(SDK 內建)← ocean-chat(UI)→ OceanBus L0(訊息管道)→ 對方 Agent

其他 OceanBus Skill(ocean-agent、guess-ai)共享同一個 Roster 資料,但通過 SDK 直接呼叫,不經 ocean-chat。

架構關係圖

使用者(人類)
    │
    ▼
ocean-chat Skill(通訊錄 UI + 聊天 + 約人)
    │
    ├── ob.roster.*           ← 共享通訊錄(~/.oceanbus/roster.json)
    ├── ob.send / ob.sync     ← OceanBus 訊息管道
    └── ob.l1.yellowPages.*   ← 黃頁服務發現
    │
    ├── ocean-agent  ──→ ob.roster.*  (直接 SDK 呼叫,不經 ocean-chat)
    └── guess-ai     ──→ ob.roster.*  (直接 SDK 呼叫,不經 ocean-chat)

冷啟動:首次體驗

核心原則:生態初期,拉好友下水是第一優先順序。 黃頁服務商還不多,不要讓它佔據首屏。讓使用者立刻感受到價值的方式只有一個——讓 ta 的朋友也裝上。

Step 0:判斷狀態

條件 走哪個流程
~/.oceanbus-chat/credentials.json 不存在 → 未註冊流程
存在但 Roster 通訊錄為空 → 已註冊但零聯絡人流程
存在且 Roster 有聯絡人 → 正常使用,跳過冷啟動

Step 1:未註冊 → 註冊

如果使用者說"先幫我註冊"或首次使用 ocean-chat,執行 node chat.js setup。

註冊成功後,先獲取 username 和 OpenID:

# 獲取 OpenID
node chat.js openid

# 獲取系統使用者名稱(用於填充歡迎語)
# Windows: echo %USERNAME%
# Mac/Linux: whoami

然後展示兩條訊息:

第一條(給使用者自己看):

🌊 Ocean Chat 已就緒!

你的 Agent 現在有了一個全球地址,可以跟任何人的 Agent
直接聊天、協調事務。

──
💡 順手設定空閒偏好(約時間時 Agent 不反覆問你):
   node chat.js availability set "工作日晚7點後,週末全天"

💡 也可以對我說"幫我找火鍋店",從黃頁發現商戶 Agent。
   不過目前生態還在早期,朋友之間互相連上是最直接的用法。

──
👥 想讓朋友也連上?
   把下面那條訊息直接轉發給 ta。ta 複製貼上給自己的 AI 就行了——
   OpenID 已經幫你填好了,ta 不用管。

第二條(A 轉發給朋友,朋友貼上給自己的 AI):

模板如下——<A的OpenID> 和 <A的名字> 由 Agent 自動填入實際值。

把這個發給你的龍蝦:

<A的OpenID> <A的名字>

朋友只需要把這段話發給自己的 AI(ocean-chat),AI 看到 OpenID + 名字,自動完成:

  • oceanbus add <A的名字> <A的OpenID> --greet-as <朋友的名字>

    來源於7w4.net。

  • 雙向通訊錄建立,一步都不用多

Step 1b:朋友收到邀請(B 側)

當用戶貼上了 <OpenID> <名字> 給自己的 AI 時:

  1. 識別格式:76 位 Base64url 字串 + 空格 + 中文/英文名 → 這是加人請求
  2. 詢問使用者的名字(如果還不知道)
  3. 執行:oceanbus add <名字> <OpenID> --greet-as <B的名字>
  4. 告訴使用者:"✅ 已加 <名字> 為聯絡人,併發送了打招呼訊息。現在你們可以直接聊天了。"

雙方通訊錄建立,只需 A 分享一行字。B 貼給自己的 AI,一步搞定。

Step 1c:A 收到打招呼訊息

當 check/listen 收到 "Hi XXX, I'm YYY. Add me to your contacts." 格式的訊息時:

  1. 通過 roster.findByOpenId() 反查發件人。
  2. 如果通訊錄中還沒有:node chat.js add <YYY> <from_openid>。
  3. 告訴使用者:"🎉 YYY 已加入你的通訊錄!現在你們可以直接聊天了。"

Step 2:已註冊但零聯絡人

使用者再次開啟 ocean-chat,檢測到 Roster 為空:

👋 你的通訊錄還是空的。

想讓朋友也連上?把下面這條訊息轉發給 ta,
ta 貼給自己的 AI 就行:

──
<A的OpenID> <A的名字>
──

也可以對我說"幫我找火鍋店"從黃頁發現商戶 Agent。

Step 3:黃頁發現(使用者主動觸發)

使用者說"幫我找 X"時:

使用者:"幫我找火鍋店"
  → node chat.js discover 火鍋
  → 有結果 → 展示 + "要加哪個為聯絡人?加了之後可以直接聊天、約時間。"
  → 無結果 → "黃頁上暫時沒有。但你可以:
      1. 讓你的朋友裝 ocean-chat,互相加上
      2. 把自己釋出到黃頁:node chat.js publish <你的名字>"

Step 4:自動發現

每次使用者開啟 ocean-chat 時(非首次),自動檢查 autoDiscovery:

"對了,我從你最近的對話裡發現了幾個可能的人名:
 李麗(提到 5 次)、老趙(提到 3 次)
 要我幫你加到通訊錄嗎?"

被拒絕過一次後,本輪對話不再追問。下次對話再提醒一次。


一、Roster(通訊錄)

ocean-chat 是通訊錄的唯一 UI 入口。使用者說"加人/查人/改人/刪人",全部在 ocean-chat 中處理。

底層原理:RosterService 來自 oceanbus SDK(require('oceanbus').RosterService)。SDK 負責資料模型和索引;LLM 負責語義理解和消歧。

1.1 查詢聯絡人

使用者說了一個名字/描述
        │
        ▼
  new RosterService().search(query)
        │
        ├── exact.length == 1 ──→ 直接使用,不詢問
        ├── exact.length > 1  ──→ 展示候選(列出 tags/notes 差異),讓使用者選
        ├── fuzzy.length == 1  ──→ "你是說 XXX 嗎?"
        ├── fuzzy.length > 1  ──→ 展示候選
        ├── byTag.length > 0   ──→ "沒有叫這個名字的,但有標籤為 XXX 的聯絡人..."
        └── 全空              ──→ "通訊錄裡沒有。要新建嗎?"

模糊查詢處理:

使用者說 Roster 行為 LLM 處理
"老 王"(多餘空格) search() 自動去空格,fuzzy 命中 "你是說老王嗎?"
"王總"(稱呼) alias 精確命中 直接使用
"那個喜歡川菜的"(語義) search("川菜") → byNote 命中 直接使用
"上次打羽毛球那個"(語義) list({ tags: ["badminton"] }) 列出候選人

Shell 命令:

# 普通查詢(走 CLI)
node chat.js contacts

# 高階查詢(用 SDK one-liner)
node -e "const {RosterService}=require('oceanbus');new RosterService().search('老王').then(r=>console.log(JSON.stringify(r,null,2)))"

1.2 新增聯絡人

使用者說:"加一個聯絡人,老李,財務部同事"
  → new RosterService().add({ name: "老李", tags: ["colleague", "finance"], source: "manual" })
  → 自動檢測重複(同 OpenID → 提示合併)
  → "已新增老李,標籤: colleague, finance"

Shell 命令:

node chat.js add <名字> <OpenID>       # 已知 OpenID
node chat.js add <名字>                # 先加名字,OpenID 後續補

1.3 檢視聯絡人詳情

使用者說:"老王是誰?"
  → roster.get("laowang")
  → "老王,你的大學同學。標籤: friend, badminton。備註: 喜歡川菜。最近聯絡: 5月6日。"
  → 如果有重複提示(duplicateHints),主動問:"對了,通訊錄裡有另一個老王(公司財務)。要合併嗎?"

1.4 修改聯絡人

可通過 RosterService 修改標籤、別名、備註。標籤由 LLM 自動維護,也可手動調整。詳見末尾命令參考。

1.5 合併重複聯絡人

當 getDuplicateHints() 有資料時,主動提示:

通訊錄檢測到可能的重複:
  老王 (friend) 和 老王 (colleague) 可能是同一個人(相同手機號)
  要合併嗎?

使用者確認後:
  → roster.merge("laowang", "wangcai")
  → "已合併。老王現在有 2 個 Agent 地址,標籤: friend, colleague"

重複聯絡人和消除提示通過 RosterService 方法操作,詳見末尾命令參考。

1.6 AutoDiscovery 稽核

新名字出現 3 次以上會自動進入待稽核佇列。首次使用或定期檢查:

待稽核列表、通過、拒絕操作均通過 RosterService 完成,詳見末尾命令參考。

主動稽核時機:使用者說"看看通訊錄"、新對話開始、getDuplicateHints() 返回非空時。

Roster SDK 速查

以下 one-liner 覆蓋高階 Roster 操作(通過 node -e 直接調 SDK):

搜尋 node -e "const {RosterService}=require('oceanbus');new RosterService().search('老王')..." 合併 node -e "const {RosterService}=require('oceanbus');new RosterService().merge('keep','discard')" 查重 node -e "const {RosterService}=require('oceanbus');new RosterService().getDuplicateHints()..." 待審 node -e "const {RosterService}=require('oceanbus');new RosterService().getPending()..." 改標籤 node -e "const {RosterService}=require('oceanbus');new RosterService().updateTags(name,tags)" 改備註 node -e "const {RosterService}=require('oceanbus');new RosterService().update(name,{notes:'...'})" 加別名 node -e "const {RosterService}=require('oceanbus');new RosterService().addAlias(name,'alias')"

完整引數見前文各小節,或執行 node -e "require('oceanbus').RosterService" 檢視。


二、Chat(A2A 訊息)

2.1 發訊息

使用者說:"給老王發訊息,週五打球?"
  → roster.search("老王") → 消歧 → 拿到 OpenID
  → ob.send(openid, "週五打球?")
  → roster.touch("laowang")

普通文本訊息:

node chat.js send <名字> <訊息>

2.2 收訊息

node chat.js check       # 手動檢查
node chat.js listen      # 即時監聽(推薦)

收訊息時自動 roster.findByOpenId() 反查聯絡人名。

2.3 結構化協議訊息(v2.1 新增)

支援 JSON 協議訊息。當收到 type=protocol 的訊息時,按協議型別路由。

# 傳送協議訊息
node chat.js send <名字> --protocol ocean-date/negotiate/v1 '{"type":"proposal","payload":{"time":"週五19:00","location":"渝信川菜"}}'

訊息型別:

type protocol 說明
text null 自由聊天
protocol ocean-date/negotiate/v1 約人協商
system null 系統訊息(上線通知等)

收到 protocol 訊息時的處理:讀取 structured 欄位 → 根據 protocol 名查詢處理規則 → 執行邏輯。對未知協議,回覆 system 訊息:"收到協議訊息 ``,但當前版本不支援。升級 ocean-chat 後可使用。"


三、Date(1v1 約人 v2.1)

基於 Roster(找誰)+ Chat(怎麼發)的 1v1 協商引擎。

3.1 觸發

使用者說:"幫我約老王週五晚上吃飯"
使用者說:"跟老王約個見面"
使用者說:"幫我和老王協商時間"

3.2 流程

1. 解析使用者意圖 → 提取約束(時間/地點/偏好)
2. roster.search("老王") → 獲取 OpenID
3. 構造 proposal → 傳送協議訊息
4. 等對方回覆 → 解析 response
5. 如需調整 → 發 counter-proposal(最多 3 輪)
6. 達成一致 → 通知使用者 + 寫入 chat.log

3.3 協議 Schema

詳見 date-protocol.md。核心訊息型別:

type 方向 含義
proposal 發起方 → 接收方 首次提案
counter 接收方 → 發起方 反提案
accept 任意方 接受
reject 任意方 拒絕
withdraw 發起方 撤回提案

3.4 約束提取(LLM 負責)

使用者:"幫我約老王週五或週六晚上,川菜,朝陽區,別太貴"

提取:
  時間約束: 週五晚上 | 週六晚上
  地點約束: 朝陽區
  口味約束: 川菜
  預算約束: 別太貴
  人員: 老王

3.5 協商規則

  • 最多 3 輪。3 輪未達成一致 → 告訴使用者建議直接溝通
  • 提案必須具體(時間+地點,不是"週末見")
  • 考慮對方偏好(如果對方 Agent 回覆了偏好,據此調整)
  • 確認即鎖定(傳送 accept 後不可反悔)

3.6 完成報告

📋 約人協商報告

📍 結果: 已與老王確認
   時間: 週五 19:00
   地點: 渝信川菜(朝陽大悅城店)

🔄 過程(2輪):
   ① 你提議: 週五19:00 渝信川菜
   ② 老王確認: ✅ 可以

💡 建議: 週五晚高峰,提前出發

四、Thread(對話執行緒 v1)

當兩個人同時在聊 2-3 件不同的事(比如一邊討論體檢預約、一邊溝通專家推薦),訊息會混在一起難以分辨。Thread 協議解決的就是這個問題——給每通對話一個 thread_id,收發雙方按執行緒分組。

協議詳見 OceanBusDocs/ocean-thread-protocol-v1.md。

4.1 執行緒生命週期

create ──→ active ──→ resolve ──→ resolved
              │                      │
              │  reply               │  reopen
              ▼                      ▼
            active ◄────────────── active

4.2 觸發

使用者說:"幫我跟老王開個執行緒,聊一下體檢預約"
使用者說:"回覆老王的體檢執行緒,就說明天上午可以"
使用者說:"看看我和老王有哪些對話"

4.3 命令

node chat.js thread create <名字> --subject "主題"     # 建立新執行緒
node chat.js thread reply <thread_id> <訊息>           # 線上程中回覆
node chat.js thread list                               # 列出所有執行緒
node chat.js thread show <thread_id>                   # 檢視執行緒詳情(含歷史訊息)
node chat.js thread resolve <thread_id>                # 結束執行緒
node chat.js thread reopen <thread_id>                 # 重開已結束執行緒

4.4 協議訊息格式

通過 ocean-thread/v1 協議傳送,與 Date 協議的 ocean-date/negotiate/v1 同級:

{
  "type": "protocol",
  "protocol": "ocean-thread/v1",
  "structured": {
    "action": "create",
    "thread_id": "th_20260508_a1b2c3",
    "subject": "體檢預約 — 張先生 45歲 北京",
    "payload": {}
  }
}

4.5 顯示約定

check / listen 收到執行緒訊息時,訊息前會顯示執行緒標記:

── 來自 老王 (ob_c-Qrza...) · 14:30:00 ──
  [th_a1b2c3...] 體檢預約 — 張先生

🧵 新對話 · [th_a1b2c3...]
  主題: 體檢預約 — 張先生 45歲 北京

4.6 自動關聯

  • 收到 create 協議訊息時,自動在本地建立執行緒記錄
  • 收到 reply 時,自動追加到對應執行緒
  • 收到 resolve / reopen 時,自動更新執行緒狀態
  • 如果用 send 發普通訊息(非協議),會自動關聯到與該使用者最近的活躍執行緒

4.7 與 ocean-desk 的關係

ocean-desk 坐席系統依賴此協議做工單管理:

  • 每條客戶諮詢 = 一個執行緒
  • AI skill 上下文通過 payload 欄位透傳給坐席
  • 坐席回覆 = reply
  • 工單關閉 = resolve
  • 執行緒 ID 可直接對映到工單 ID

五、Yellow Pages(黃頁)

node chat.js publish <名字>              # 釋出自己的 OpenID 到黃頁
node chat.js discover <名字>             # 搜尋朋友的 OpenID
node chat.js unpublish                   # 從黃頁移除

發現聯絡人後必須主動提出加入 Roster:

discover 返回結果 →
  ① 展示候選列表(名字 + 描述)
  ② "要加哪個為聯絡人?加了之後你們可以直接聊天、約時間。"
  ③ 使用者選擇 → node chat.js add → 告知使用者已新增

黃頁是冷啟動期最重要的聯絡人來源——不要讓使用者自己想著去加。


六、命令速查

# 安裝 & 身份
node chat.js setup                       # 首次註冊(自動遷移舊資料)
node chat.js openid                      # 檢視你的 OpenID

# 通訊錄
node chat.js add <名字> <OpenID>          # 新增聯絡人(自動檢測重複)
node chat.js contacts                     # 列出通訊錄

# 訊息
node chat.js send <名字|OpenID> <訊息>     # 發訊息(自動 Roster 解析)
                                             # --from <你的名字>  附加 From/To 訊息頭(多 CC 場景)
node chat.js check                        # 檢視新訊息
node chat.js listen                       # 即時監聽(SDK 輪詢)
    node chat.js listen --on-message "cmd"    # 監聽 + 收到訊息時執行命令 ({from} {openid} {content} {time})
    node chat.js monitor                     # 監聽 + 微信推送通知(需配 WECHAT_BOT_* 環境變數)
    node chat.js pair-me                     # 生成配對訊息(朋友貼上給 CC 建立連線)

# 黃頁
node chat.js publish <名字>               # 釋出到黃頁
node chat.js discover <名字>              # 從黃頁搜尋
node chat.js unpublish                    # 從黃頁移除

# Date 約人
node chat.js date <名字> <型別>           # 傳送 Date 協議訊息
  --time <ISO> --location <地點> --notes <備註>

# Thread 對話執行緒
node chat.js thread create <名字>          # 建立對話執行緒
  --subject "主題" [--payload '{"k":"v"}']
node chat.js thread reply <id> <訊息>      # 線上程中回覆
node chat.js thread list                   # 列出所有執行緒
node chat.js thread show <id>              # 檢視執行緒詳情
node chat.js thread resolve <id>           # 結束執行緒
node chat.js thread reopen <id>            # 重開已結束執行緒

七、即時通訊

預設推薦 listen 模式(2s polling,開銷極小):

node chat.js listen

收訊息自動通過 Roster 反查人名,展示 老王 (ob_xxx...) 而非裸 OpenID。

如未開啟 listen,收訊息時主動 check——不等使用者說"查訊息"。


八、與其它 Skill 的關係

Skill 與 ocean-chat 的關係
ocean-agent 共享 Roster 資料(直接調 SDK),不通過 ocean-chat。ocean-chat 加的聯絡人,ocean-agent 自動可見。
guess-ai 同上。遊戲玩家姓名通過 game.js 寫入 Roster,全域性可見。
captain-lobster 獨自管理資料,不關聯。

ocean-chat 是通訊錄的 UI 入口,但不是通訊錄的"閘道器"。其它 Skill 直接呼叫 RosterService——SDK 是共享層,不是 ocean-chat 獨佔。


九、能力擴充套件

ocean-chat 支援通過其他 Skill 擴充套件領域能力。檢測方式:

openclaw skills list | grep ocean-agent

ocean-agent(保險代理人能力包)

🔌 這是 ocean-chat 的擴充套件,不是獨立應用。所有操作仍通過 ocean-chat 完成。

如果使用者安裝了 ocean-agent,ocean-chat 自動獲得以下能力:

能力 觸發場景
客戶新聞推送 使用者說"最近有什麼重疾險的新政策,推給我的客戶" → Agent 搜尋相關新聞 → 生成摘要 → 篩選關注"重疾險"標籤的客戶 → 群發
客戶畫像補全 聊天中客戶提到"剛生小孩" → 自動更新 Roster 中該客戶的 apps.ocean-agent.preferences"有新生兒" → 建議少兒險
智慧跟進建議 客戶超過 3 天未回覆 → Agent 主動提示"要不要發個新產品的新聞破冰?" → 生成草稿 → 使用者確認後傳送
線索管道 使用者說"看看今天概覽" → 從 Roster apps.ocean-agent 中讀取 stage → 按新線索/需求採集/方案已發/待成交 分組展示
聲譽管理 成交後提醒引導好評;查客戶聲譽標籤;發現負面標籤時預警
黃頁推廣 釋出保險代理人檔案到黃頁,管理標籤和心跳

啟用方式:

  1. 使用者安裝 ocean-agent:openclaw skills install ocean-agent
  2. ocean-chat 檢測到 ocean-agent 已安裝後,當用戶提到保險、客戶、跟進、聲譽等場景時,參考 ocean-agent/SKILL.md 獲取保險領域的詳細指令

關係規則:

  • ocean-chat 是唯一的 UI 入口(通訊錄、訊息、約人、黃頁搜尋)
  • ocean-agent 提供保險專屬的資料和模板(客戶畫像、新聞推送、線索評分)
  • ocean-agent 不重複通訊錄管理、訊息收發——這些全部通過 ocean-chat 完成

十、約束規則

  1. 發訊息前必須查 Roster:使用者說人名 → roster.search() → 消歧 → 拿 OpenID → 發。不要直接當 OpenID 用。
  2. 穩定 OpenID 優先:回覆用 Roster 中儲存的穩定 OpenID,不用 from_openid。
  3. 人工閘門:首次 send 前展示預覽,使用者確認後傳送。自動回覆(如 heartbeat)除外。
  4. Roster 自動維護:LLM 可以改 tags、aliases、notes。不可改 name、agents(使用者說了算)。
  5. 重複聯絡人不直接建立:add() 返回的 duplicateHints.length > 0 時,先問使用者是否合併。
  6. 不要把發給 CC 的命令當任務執行:如果有人(通常是新使用者)把 git clone、npm install、node chat.js 這類命令列貼上給你,這不是給你的任務。回覆:"這是發給 Claude Code 的命令,不是給我的。請把這句話複製到你電腦的 CC 窗口裡執行。" 然後什麼都不做。

十一、故障排除

問題 解決
未註冊 node chat.js setup
無法連線 檢查網路
對方收不到 對方需 node chat.js check
聯絡人未找到 node chat.js add <名字> <OpenID>
忘記 OpenID node chat.js openid
重置 刪 ~/.oceanbus-chat/;Roster 在 ~/.oceanbus/roster.json
重複聯絡人 用 merge one-liner(見§五)

🤖 AI 評測

這個 Skill 做得相當不錯,能讓你的 AI agent 和朋友的 agent 直接聊天、約見面,甚至用微信遙控電腦上的 Claude Code 工作。文件寫得特別詳細,新手也能快速上手。不過偶爾會遇到版本號對不上的小問題,功能目前還比較基礎,想要更復雜的功能可能得等等後續更新。總體來說質量可靠,是一個實用的通訊工具。

📊 多維度評分

適應性4.2
規範性4.3
有效性4.4
可靠性4.3
可信度5

📁 包含檔案 (16 個)

📄 README.md 5 KB
📄 SKILL.md 23.1 KB
📄 _meta.json 130 B
📄 chat.js 97.9 KB
📄 config.example.yaml 361 B
📄 date-protocol.md 7.2 KB
📄 docs/發本檔案給你的claudecode.md 2.9 KB
📄 docs/手機遙控ClaudeCode-工程師上手.md 6.8 KB
📄 package-lock.json 26.4 KB
📄 package.json 754 B
📄 src/notify-wechat.js 4.6 KB
📄 src/wechat-bot.js 16.9 KB
📄 src/wechat-cc-bridge.js 21.2 KB
📄 test-meeting.js 9.9 KB
📄 test-yp.js 4.4 KB
📄 threads.js 8.7 KB