# Connector

Connector 在一個外部渠道（聊天平台、直播間）和 Cowork 的 Gateway 之間傳遞訊息。用 `api.registerConnector(definition)` 註冊它。

## ConnectorDefinition

| 欄位 | 類型 | 必填 | 說明 |
|---|---|---|---|
| `id` | `string` | 在 0.1.41 為是；否 <Badge type="warning" text="尚未發布" /> | 小寫字母、數字和連字元。`dozin.connectors` 列出 id 時，必須是其中之一；沒有這個清單時任何有效 id 都可以，最多 16 個 Connector。在 0.1.41 為必填且必須列出。從下一個版本起預設為套件名稱 |
| `systemPrompt` <Badge type="warning" text="尚未發布" /> | `string` | 否 | 這個 Connector 的每個對話都要遵守的規則，最多 4000 個字元；使用者無法編輯 |
| `chat` <Badge type="warning" text="尚未發布" /> | `{ title, roles?, maxLength?, maxPerMinute? }` | 否 | 訊息進入同一個對話，由它用 `gateway_send` 回覆。`title` 1–80 個字元；`roles` 最多 16 項，id 小寫（`host`、`viewer`、`self`）→ 1–24 個字元的標籤；`maxLength` 1–4000（預設 500）；`maxPerMinute` 1–30（預設 6）。無效的 `chat` 會整個被拒絕 |
| `start(ctx)` | function | 是 | 見下文 |
| `stop()` | function | 是 | 見下文 |
| `send(reply)` | function | 是 | 見下文 |

## start(ctx)

Connector 啟動時呼叫。在這裡開啟連線、定時器和頁面監聽。

| 名稱 | 類型 | 說明 |
|---|---|---|
| `ctx` | `ConnectorContext` | `emit`、`log`，有該權限時還有 `browser` |

回傳 `void` 或一個 promise。限時 5 秒。

## stop()

Connector 停止時呼叫。關閉 `start` 開啟的一切。多次呼叫必須安全。限時 5 秒。

## send(reply)

把 Cowork 的一則回覆送到渠道。

| 名稱 | 類型 | 說明 |
|---|---|---|
| `reply.text` | `string` | 回覆內容 |
| `reply.channelKey` | `string` | 送往哪裡，與 `emit` 給出的相同 |
| `reply.idempotencyKey` | `string` | 相同的鍵最多只送出一次 |
| `reply.replyTo` <Badge type="warning" text="尚未發布" /> | `{ id, senderId, senderName, role }` | 有 `chat` 時：這則回覆所回答的訊息 |

回傳 `Promise<{ ok: boolean, error?: string, externalKey?: string, verified?: boolean }>`。`externalKey` 是平台自己為這個對話給的鍵。`verified` <Badge type="warning" text="尚未發布" /> 表示在對方那邊確實看到了這則回覆（預設等於 `ok`）。

| 結果 `error` | 時機 |
|---|---|
| `send_timeout` | `send` 花了超過 30 秒 |
| `unknown_connector` | 沒有註冊這個 id 的 Connector |
| `invalid_reply` | 無法讀取 Cowork 傳入的回覆 |
| `invalid_send_result` | `send` 回傳的內容沒有布林值 `ok` |
| 拋出的錯誤訊息 | `send` 拋出錯誤 |

## ctx.emit(message)

把一則收到的訊息交給 Cowork。

| 欄位 | 類型 | 必填 | 說明 |
|---|---|---|---|
| `text` | `string` | 是 | 對話裡顯示的內容 |
| `channelKey` | `string` | 否 | `<connectorId>/<kind>/<channelId>`；預設 `<connectorId>/group/default` |
| `senderId` | `string` | 否 | 平台給發送者的固定 id |
| `senderName` | `string` | 否 | 顯示名稱 |
| `msgId` | `string` | 否 | 用來去除重複 |
| `at` | `number` | 否 | 平台時間，單位為毫秒 |
| `trigger` | `boolean` | 否 | `false`：只作為上下文，隨下一則會得到回覆的訊息一起送出 |
| `contextText` | `string` | 否 | 模型讀取的內容，取代 `text` |
| `role` <Badge type="warning" text="尚未發布" /> | `string` | 否 | 有 `chat` 時：誰說的（`host`、`viewer`、`self`）；`self` 只作為上下文 |
| `modality` <Badge type="warning" text="尚未發布" /> | `'text' \| 'voice'` | 否 | `voice`：由語音轉寫而來 |

不回傳任何值。

## ctx.log(text)

在 Extension 的日誌寫一行。不回傳任何值。

```js
ctx.log('connected to room 42');
```

## 示例

```js
export function activate(api) {
  let timer;
  api.registerConnector({
    id: 'demo',
    start(ctx) { timer = setInterval(() => ctx.emit({ text: 'ping', senderId: 'bot' }), 60000); },
    stop() { clearInterval(timer); },
    async send(reply) { return { ok: true }; }
  });
}
```

## 相關

- [入口與註冊](https://docs.micromeet.ai/zh-tw/extension-sdk/entry.md): `registerConnector`
- [瀏覽器](https://docs.micromeet.ai/zh-tw/extension-sdk/browser.md): `ctx.browser`，用於讀取網頁的 Connector
- [Gateway 外部渠道訊息](https://docs.micromeet.ai/zh-tw/connections/gateway.md): 訊息去哪
