fix: finalize channels rename cleanup
This commit is contained in:
@@ -341,7 +341,7 @@ public struct SendParams: Codable, Sendable {
|
|||||||
public let message: String
|
public let message: String
|
||||||
public let mediaurl: String?
|
public let mediaurl: String?
|
||||||
public let gifplayback: Bool?
|
public let gifplayback: Bool?
|
||||||
public let provider: String?
|
public let channel: String?
|
||||||
public let accountid: String?
|
public let accountid: String?
|
||||||
public let idempotencykey: String
|
public let idempotencykey: String
|
||||||
|
|
||||||
@@ -350,7 +350,7 @@ public struct SendParams: Codable, Sendable {
|
|||||||
message: String,
|
message: String,
|
||||||
mediaurl: String?,
|
mediaurl: String?,
|
||||||
gifplayback: Bool?,
|
gifplayback: Bool?,
|
||||||
provider: String?,
|
channel: String?,
|
||||||
accountid: String?,
|
accountid: String?,
|
||||||
idempotencykey: String
|
idempotencykey: String
|
||||||
) {
|
) {
|
||||||
@@ -358,7 +358,7 @@ public struct SendParams: Codable, Sendable {
|
|||||||
self.message = message
|
self.message = message
|
||||||
self.mediaurl = mediaurl
|
self.mediaurl = mediaurl
|
||||||
self.gifplayback = gifplayback
|
self.gifplayback = gifplayback
|
||||||
self.provider = provider
|
self.channel = channel
|
||||||
self.accountid = accountid
|
self.accountid = accountid
|
||||||
self.idempotencykey = idempotencykey
|
self.idempotencykey = idempotencykey
|
||||||
}
|
}
|
||||||
@@ -367,7 +367,7 @@ public struct SendParams: Codable, Sendable {
|
|||||||
case message
|
case message
|
||||||
case mediaurl = "mediaUrl"
|
case mediaurl = "mediaUrl"
|
||||||
case gifplayback = "gifPlayback"
|
case gifplayback = "gifPlayback"
|
||||||
case provider
|
case channel
|
||||||
case accountid = "accountId"
|
case accountid = "accountId"
|
||||||
case idempotencykey = "idempotencyKey"
|
case idempotencykey = "idempotencyKey"
|
||||||
}
|
}
|
||||||
@@ -379,7 +379,7 @@ public struct PollParams: Codable, Sendable {
|
|||||||
public let options: [String]
|
public let options: [String]
|
||||||
public let maxselections: Int?
|
public let maxselections: Int?
|
||||||
public let durationhours: Int?
|
public let durationhours: Int?
|
||||||
public let provider: String?
|
public let channel: String?
|
||||||
public let accountid: String?
|
public let accountid: String?
|
||||||
public let idempotencykey: String
|
public let idempotencykey: String
|
||||||
|
|
||||||
@@ -389,7 +389,7 @@ public struct PollParams: Codable, Sendable {
|
|||||||
options: [String],
|
options: [String],
|
||||||
maxselections: Int?,
|
maxselections: Int?,
|
||||||
durationhours: Int?,
|
durationhours: Int?,
|
||||||
provider: String?,
|
channel: String?,
|
||||||
accountid: String?,
|
accountid: String?,
|
||||||
idempotencykey: String
|
idempotencykey: String
|
||||||
) {
|
) {
|
||||||
@@ -398,7 +398,7 @@ public struct PollParams: Codable, Sendable {
|
|||||||
self.options = options
|
self.options = options
|
||||||
self.maxselections = maxselections
|
self.maxselections = maxselections
|
||||||
self.durationhours = durationhours
|
self.durationhours = durationhours
|
||||||
self.provider = provider
|
self.channel = channel
|
||||||
self.accountid = accountid
|
self.accountid = accountid
|
||||||
self.idempotencykey = idempotencykey
|
self.idempotencykey = idempotencykey
|
||||||
}
|
}
|
||||||
@@ -408,7 +408,7 @@ public struct PollParams: Codable, Sendable {
|
|||||||
case options
|
case options
|
||||||
case maxselections = "maxSelections"
|
case maxselections = "maxSelections"
|
||||||
case durationhours = "durationHours"
|
case durationhours = "durationHours"
|
||||||
case provider
|
case channel
|
||||||
case accountid = "accountId"
|
case accountid = "accountId"
|
||||||
case idempotencykey = "idempotencyKey"
|
case idempotencykey = "idempotencyKey"
|
||||||
}
|
}
|
||||||
@@ -422,7 +422,7 @@ public struct AgentParams: Codable, Sendable {
|
|||||||
public let thinking: String?
|
public let thinking: String?
|
||||||
public let deliver: Bool?
|
public let deliver: Bool?
|
||||||
public let attachments: [AnyCodable]?
|
public let attachments: [AnyCodable]?
|
||||||
public let provider: String?
|
public let channel: String?
|
||||||
public let timeout: Int?
|
public let timeout: Int?
|
||||||
public let lane: String?
|
public let lane: String?
|
||||||
public let extrasystemprompt: String?
|
public let extrasystemprompt: String?
|
||||||
@@ -438,7 +438,7 @@ public struct AgentParams: Codable, Sendable {
|
|||||||
thinking: String?,
|
thinking: String?,
|
||||||
deliver: Bool?,
|
deliver: Bool?,
|
||||||
attachments: [AnyCodable]?,
|
attachments: [AnyCodable]?,
|
||||||
provider: String?,
|
channel: String?,
|
||||||
timeout: Int?,
|
timeout: Int?,
|
||||||
lane: String?,
|
lane: String?,
|
||||||
extrasystemprompt: String?,
|
extrasystemprompt: String?,
|
||||||
@@ -453,7 +453,7 @@ public struct AgentParams: Codable, Sendable {
|
|||||||
self.thinking = thinking
|
self.thinking = thinking
|
||||||
self.deliver = deliver
|
self.deliver = deliver
|
||||||
self.attachments = attachments
|
self.attachments = attachments
|
||||||
self.provider = provider
|
self.channel = channel
|
||||||
self.timeout = timeout
|
self.timeout = timeout
|
||||||
self.lane = lane
|
self.lane = lane
|
||||||
self.extrasystemprompt = extrasystemprompt
|
self.extrasystemprompt = extrasystemprompt
|
||||||
@@ -469,7 +469,7 @@ public struct AgentParams: Codable, Sendable {
|
|||||||
case thinking
|
case thinking
|
||||||
case deliver
|
case deliver
|
||||||
case attachments
|
case attachments
|
||||||
case provider
|
case channel
|
||||||
case timeout
|
case timeout
|
||||||
case lane
|
case lane
|
||||||
case extrasystemprompt = "extraSystemPrompt"
|
case extrasystemprompt = "extraSystemPrompt"
|
||||||
@@ -1102,7 +1102,7 @@ public struct TalkModeParams: Codable, Sendable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct ProvidersStatusParams: Codable, Sendable {
|
public struct ChannelsStatusParams: Codable, Sendable {
|
||||||
public let probe: Bool?
|
public let probe: Bool?
|
||||||
public let timeoutms: Int?
|
public let timeoutms: Int?
|
||||||
|
|
||||||
@@ -1119,52 +1119,52 @@ public struct ProvidersStatusParams: Codable, Sendable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct ProvidersStatusResult: Codable, Sendable {
|
public struct ChannelsStatusResult: Codable, Sendable {
|
||||||
public let ts: Int
|
public let ts: Int
|
||||||
public let providerorder: [String]
|
public let channelorder: [String]
|
||||||
public let providerlabels: [String: AnyCodable]
|
public let channellabels: [String: AnyCodable]
|
||||||
public let providers: [String: AnyCodable]
|
public let channels: [String: AnyCodable]
|
||||||
public let provideraccounts: [String: AnyCodable]
|
public let channelaccounts: [String: AnyCodable]
|
||||||
public let providerdefaultaccountid: [String: AnyCodable]
|
public let channeldefaultaccountid: [String: AnyCodable]
|
||||||
|
|
||||||
public init(
|
public init(
|
||||||
ts: Int,
|
ts: Int,
|
||||||
providerorder: [String],
|
channelorder: [String],
|
||||||
providerlabels: [String: AnyCodable],
|
channellabels: [String: AnyCodable],
|
||||||
providers: [String: AnyCodable],
|
channels: [String: AnyCodable],
|
||||||
provideraccounts: [String: AnyCodable],
|
channelaccounts: [String: AnyCodable],
|
||||||
providerdefaultaccountid: [String: AnyCodable]
|
channeldefaultaccountid: [String: AnyCodable]
|
||||||
) {
|
) {
|
||||||
self.ts = ts
|
self.ts = ts
|
||||||
self.providerorder = providerorder
|
self.channelorder = channelorder
|
||||||
self.providerlabels = providerlabels
|
self.channellabels = channellabels
|
||||||
self.providers = providers
|
self.channels = channels
|
||||||
self.provideraccounts = provideraccounts
|
self.channelaccounts = channelaccounts
|
||||||
self.providerdefaultaccountid = providerdefaultaccountid
|
self.channeldefaultaccountid = channeldefaultaccountid
|
||||||
}
|
}
|
||||||
private enum CodingKeys: String, CodingKey {
|
private enum CodingKeys: String, CodingKey {
|
||||||
case ts
|
case ts
|
||||||
case providerorder = "providerOrder"
|
case channelorder = "channelOrder"
|
||||||
case providerlabels = "providerLabels"
|
case channellabels = "channelLabels"
|
||||||
case providers
|
case channels
|
||||||
case provideraccounts = "providerAccounts"
|
case channelaccounts = "channelAccounts"
|
||||||
case providerdefaultaccountid = "providerDefaultAccountId"
|
case channeldefaultaccountid = "channelDefaultAccountId"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct ProvidersLogoutParams: Codable, Sendable {
|
public struct ChannelsLogoutParams: Codable, Sendable {
|
||||||
public let provider: String
|
public let channel: String
|
||||||
public let accountid: String?
|
public let accountid: String?
|
||||||
|
|
||||||
public init(
|
public init(
|
||||||
provider: String,
|
channel: String,
|
||||||
accountid: String?
|
accountid: String?
|
||||||
) {
|
) {
|
||||||
self.provider = provider
|
self.channel = channel
|
||||||
self.accountid = accountid
|
self.accountid = accountid
|
||||||
}
|
}
|
||||||
private enum CodingKeys: String, CodingKey {
|
private enum CodingKeys: String, CodingKey {
|
||||||
case provider
|
case channel
|
||||||
case accountid = "accountId"
|
case accountid = "accountId"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1148,7 +1148,7 @@ See [Messages](/concepts/messages) for queueing, sessions, and streaming context
|
|||||||
```
|
```
|
||||||
|
|
||||||
`responsePrefix` is applied to **all outbound replies** (tool summaries, block
|
`responsePrefix` is applied to **all outbound replies** (tool summaries, block
|
||||||
streaming, final replies) across providers unless already present.
|
streaming, final replies) across channels unless already present.
|
||||||
|
|
||||||
If `messages.responsePrefix` is unset, no prefix is applied by default.
|
If `messages.responsePrefix` is unset, no prefix is applied by default.
|
||||||
Set it to `"auto"` to derive `[{identity.name}]` for the routed agent (when set).
|
Set it to `"auto"` to derive `[{identity.name}]` for the routed agent (when set).
|
||||||
@@ -1160,7 +1160,7 @@ WhatsApp inbound prefix is configured via `channels.whatsapp.messagePrefix` (dep
|
|||||||
agent has `identity.name` set.
|
agent has `identity.name` set.
|
||||||
|
|
||||||
`ackReaction` sends a best-effort emoji reaction to acknowledge inbound messages
|
`ackReaction` sends a best-effort emoji reaction to acknowledge inbound messages
|
||||||
on providers that support reactions (Slack/Discord/Telegram). Defaults to the
|
on channels that support reactions (Slack/Discord/Telegram). Defaults to the
|
||||||
active agent’s `identity.emoji` when set, otherwise `"👀"`. Set it to `""` to disable.
|
active agent’s `identity.emoji` when set, otherwise `"👀"`. Set it to `""` to disable.
|
||||||
|
|
||||||
`ackReactionScope` controls when reactions fire:
|
`ackReactionScope` controls when reactions fire:
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ cat ~/.clawdbot/clawdbot.json
|
|||||||
- Sandbox image repair when sandboxing is enabled.
|
- Sandbox image repair when sandboxing is enabled.
|
||||||
- Legacy service migration and extra gateway detection.
|
- Legacy service migration and extra gateway detection.
|
||||||
- Gateway runtime checks (service installed but not running; cached launchd label).
|
- Gateway runtime checks (service installed but not running; cached launchd label).
|
||||||
- Provider status warnings (probed from the running gateway).
|
- Channel status warnings (probed from the running gateway).
|
||||||
- Supervisor config audit (launchd/systemd/schtasks) with optional repair.
|
- Supervisor config audit (launchd/systemd/schtasks) with optional repair.
|
||||||
- Gateway runtime best-practice checks (Node vs Bun, version-manager paths).
|
- Gateway runtime best-practice checks (Node vs Bun, version-manager paths).
|
||||||
- Gateway port collision diagnostics (default `18789`).
|
- Gateway port collision diagnostics (default `18789`).
|
||||||
@@ -209,8 +209,8 @@ creation in automation.
|
|||||||
Doctor runs a health check and offers to restart the gateway when it looks
|
Doctor runs a health check and offers to restart the gateway when it looks
|
||||||
unhealthy.
|
unhealthy.
|
||||||
|
|
||||||
### 14) Provider status warnings
|
### 14) Channel status warnings
|
||||||
If the gateway is healthy, doctor runs a provider status probe and reports
|
If the gateway is healthy, doctor runs a channel status probe and reports
|
||||||
warnings with suggested fixes.
|
warnings with suggested fixes.
|
||||||
|
|
||||||
### 15) Supervisor config audit + repair
|
### 15) Supervisor config audit + repair
|
||||||
@@ -234,7 +234,7 @@ running, SSH tunnel).
|
|||||||
|
|
||||||
### 17) Gateway runtime best practices
|
### 17) Gateway runtime best practices
|
||||||
Doctor warns when the gateway service runs on Bun or a version-managed Node path
|
Doctor warns when the gateway service runs on Bun or a version-managed Node path
|
||||||
(`nvm`, `fnm`, `volta`, `asdf`, etc.). WhatsApp + Telegram providers require Node,
|
(`nvm`, `fnm`, `volta`, `asdf`, etc.). WhatsApp + Telegram channels require Node,
|
||||||
and version-manager paths can break after upgrades because the daemon does not
|
and version-manager paths can break after upgrades because the daemon does not
|
||||||
load your shell init. Doctor offers to migrate to a system Node install when
|
load your shell init. Doctor offers to migrate to a system Node install when
|
||||||
available (Homebrew/apt/choco).
|
available (Homebrew/apt/choco).
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ Behavior:
|
|||||||
- **Subsystem prefixes** on every line (e.g. `[gateway]`, `[canvas]`, `[tailscale]`)
|
- **Subsystem prefixes** on every line (e.g. `[gateway]`, `[canvas]`, `[tailscale]`)
|
||||||
- **Subsystem colors** (stable per subsystem) plus level coloring
|
- **Subsystem colors** (stable per subsystem) plus level coloring
|
||||||
- **Color when output is a TTY or the environment looks like a rich terminal** (`TERM`/`COLORTERM`/`TERM_PROGRAM`), respects `NO_COLOR`
|
- **Color when output is a TTY or the environment looks like a rich terminal** (`TERM`/`COLORTERM`/`TERM_PROGRAM`), respects `NO_COLOR`
|
||||||
- **Shortened subsystem prefixes**: drops leading `gateway/` + `providers/`, keeps last 2 segments (e.g. `whatsapp/outbound`)
|
- **Shortened subsystem prefixes**: drops leading `gateway/` + `channels/`, keeps last 2 segments (e.g. `whatsapp/outbound`)
|
||||||
- **Sub-loggers by subsystem** (auto prefix + structured field `{ subsystem }`)
|
- **Sub-loggers by subsystem** (auto prefix + structured field `{ subsystem }`)
|
||||||
- **`logRaw()`** for QR/UX output (no prefix, no formatting)
|
- **`logRaw()`** for QR/UX output (no prefix, no formatting)
|
||||||
- **Console styles** (e.g. `pretty | compact | json`)
|
- **Console styles** (e.g. `pretty | compact | json`)
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ read_when:
|
|||||||
---
|
---
|
||||||
# Health Checks on macOS
|
# Health Checks on macOS
|
||||||
|
|
||||||
How to see whether the linked provider is healthy from the menu bar app.
|
How to see whether the linked channel is healthy from the menu bar app.
|
||||||
|
|
||||||
## Menu bar
|
## Menu bar
|
||||||
- Status dot now reflects Baileys health:
|
- Status dot now reflects Baileys health:
|
||||||
@@ -18,7 +18,7 @@ How to see whether the linked provider is healthy from the menu bar app.
|
|||||||
## Settings
|
## Settings
|
||||||
- General tab gains a Health card showing: linked auth age, session-store path/count, last check time, last error/status code, and buttons for Run Health Check / Reveal Logs.
|
- General tab gains a Health card showing: linked auth age, session-store path/count, last check time, last error/status code, and buttons for Run Health Check / Reveal Logs.
|
||||||
- Uses a cached snapshot so the UI loads instantly and falls back gracefully when offline.
|
- Uses a cached snapshot so the UI loads instantly and falls back gracefully when offline.
|
||||||
- **Connections tab** surfaces provider status + controls for WhatsApp/Telegram (login QR, logout, probe, last disconnect/error).
|
- **Connections tab** surfaces channel status + controls for WhatsApp/Telegram (login QR, logout, probe, last disconnect/error).
|
||||||
|
|
||||||
## How the probe works
|
## How the probe works
|
||||||
- App runs `clawdbot health --json` via `ShellExecutor` every ~60s and on demand. The probe loads creds and reports status without sending messages.
|
- App runs `clawdbot health --json` via `ShellExecutor` every ~60s and on demand. The probe loads creds and reports status without sending messages.
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ read_when:
|
|||||||
Clawdbot can use many LLM providers. Pick a provider, authenticate, then set the
|
Clawdbot can use many LLM providers. Pick a provider, authenticate, then set the
|
||||||
default model as `provider/model`.
|
default model as `provider/model`.
|
||||||
|
|
||||||
|
Looking for chat channel docs (WhatsApp/Telegram/Discord/Slack/etc.)? See [Channels](/channels).
|
||||||
|
|
||||||
## Quick start
|
## Quick start
|
||||||
|
|
||||||
1) Authenticate with the provider (usually via `clawdbot onboard`).
|
1) Authenticate with the provider (usually via `clawdbot onboard`).
|
||||||
|
|||||||
@@ -1428,15 +1428,15 @@ Notes:
|
|||||||
|
|
||||||
Block streaming only sends **completed text blocks**. Common reasons you see a single message:
|
Block streaming only sends **completed text blocks**. Common reasons you see a single message:
|
||||||
- `agents.defaults.blockStreamingDefault` is still `"off"`.
|
- `agents.defaults.blockStreamingDefault` is still `"off"`.
|
||||||
- `telegram.blockStreaming` is set to `false`.
|
- `channels.telegram.blockStreaming` is set to `false`.
|
||||||
- `telegram.streamMode` is `partial` or `block` **and draft streaming is active**
|
- `channels.telegram.streamMode` is `partial` or `block` **and draft streaming is active**
|
||||||
(private chat + topics). Draft streaming disables block streaming in that case.
|
(private chat + topics). Draft streaming disables block streaming in that case.
|
||||||
- Your `minChars` / coalesce settings are too high, so chunks get merged.
|
- Your `minChars` / coalesce settings are too high, so chunks get merged.
|
||||||
- The model emits one large text block (no mid‑reply flush points).
|
- The model emits one large text block (no mid‑reply flush points).
|
||||||
|
|
||||||
Fix checklist:
|
Fix checklist:
|
||||||
1) Put block streaming settings under `agents.defaults`, not the root.
|
1) Put block streaming settings under `agents.defaults`, not the root.
|
||||||
2) Set `telegram.streamMode: "off"` if you want real multi‑message block replies.
|
2) Set `channels.telegram.streamMode: "off"` if you want real multi‑message block replies.
|
||||||
3) Use smaller chunk/coalesce thresholds while debugging.
|
3) Use smaller chunk/coalesce thresholds while debugging.
|
||||||
|
|
||||||
See [Streaming](/concepts/streaming).
|
See [Streaming](/concepts/streaming).
|
||||||
@@ -1444,17 +1444,17 @@ See [Streaming](/concepts/streaming).
|
|||||||
### Discord doesn’t reply in my server even with `requireMention: false`. Why?
|
### Discord doesn’t reply in my server even with `requireMention: false`. Why?
|
||||||
|
|
||||||
`requireMention` only controls mention‑gating **after** the channel passes allowlists.
|
`requireMention` only controls mention‑gating **after** the channel passes allowlists.
|
||||||
By default `discord.groupPolicy` is **allowlist**, so guild channels must be explicitly enabled.
|
By default `channels.discord.groupPolicy` is **allowlist**, so guild channels must be explicitly enabled.
|
||||||
|
|
||||||
Fix checklist:
|
Fix checklist:
|
||||||
1) Set `discord.groupPolicy: "open"` **or** add the guild/channel allowlist.
|
1) Set `channels.discord.groupPolicy: "open"` **or** add the guild/channel allowlist.
|
||||||
2) Use **numeric channel IDs** in `discord.guilds.<guildId>.channels`.
|
2) Use **numeric channel IDs** in `channels.discord.guilds.<guildId>.channels`.
|
||||||
3) Put `requireMention: false` **under** `discord.guilds` (global or per‑channel).
|
3) Put `requireMention: false` **under** `channels.discord.guilds` (global or per‑channel).
|
||||||
Top‑level `discord.requireMention` is not a supported key.
|
Top‑level `channels.discord.requireMention` is not a supported key.
|
||||||
4) Ensure the bot has **Message Content Intent** and channel permissions.
|
4) Ensure the bot has **Message Content Intent** and channel permissions.
|
||||||
5) Run `clawdbot providers status --probe` for audit hints.
|
5) Run `clawdbot channels status --probe` for audit hints.
|
||||||
|
|
||||||
Docs: [Discord](/providers/discord), [Providers troubleshooting](/providers/troubleshooting).
|
Docs: [Discord](/channels/discord), [Channels troubleshooting](/channels/troubleshooting).
|
||||||
|
|
||||||
### Cloud Code Assist API error: invalid tool schema (400). What now?
|
### Cloud Code Assist API error: invalid tool schema (400). What now?
|
||||||
|
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ Dashboard (local loopback): `http://127.0.0.1:18789/`
|
|||||||
If a token is configured, paste it into the Control UI settings (stored as `connect.params.auth.token`).
|
If a token is configured, paste it into the Control UI settings (stored as `connect.params.auth.token`).
|
||||||
|
|
||||||
⚠️ **Bun warning (WhatsApp + Telegram):** Bun has known issues with these
|
⚠️ **Bun warning (WhatsApp + Telegram):** Bun has known issues with these
|
||||||
providers. If you use WhatsApp or Telegram, run the Gateway with **Node**.
|
channels. If you use WhatsApp or Telegram, run the Gateway with **Node**.
|
||||||
|
|
||||||
## 4) Pair + connect your first chat surface
|
## 4) Pair + connect your first chat surface
|
||||||
|
|
||||||
|
|||||||
@@ -499,33 +499,33 @@ export function scheduleFollowupDrain(
|
|||||||
if (forceIndividualCollect) {
|
if (forceIndividualCollect) {
|
||||||
const next = queue.items.shift();
|
const next = queue.items.shift();
|
||||||
if (!next) break;
|
if (!next) break;
|
||||||
await runFollowup(next);
|
await runFollowup(next);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if messages span multiple channels.
|
// Check if messages span multiple channels.
|
||||||
// If so, process individually to preserve per-message routing.
|
// If so, process individually to preserve per-message routing.
|
||||||
const isCrossChannel = hasCrossChannelItems(queue.items);
|
const isCrossChannel = hasCrossChannelItems(queue.items);
|
||||||
|
|
||||||
if (isCrossChannel) {
|
if (isCrossChannel) {
|
||||||
forceIndividualCollect = true;
|
forceIndividualCollect = true;
|
||||||
// Process one at a time to preserve per-message routing info.
|
// Process one at a time to preserve per-message routing info.
|
||||||
const next = queue.items.shift();
|
const next = queue.items.shift();
|
||||||
if (!next) break;
|
if (!next) break;
|
||||||
await runFollowup(next);
|
await runFollowup(next);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Same-channel messages can be safely collected.
|
// Same-channel messages can be safely collected.
|
||||||
const items = queue.items.splice(0, queue.items.length);
|
const items = queue.items.splice(0, queue.items.length);
|
||||||
const summary = buildSummaryPrompt(queue);
|
const summary = buildSummaryPrompt(queue);
|
||||||
const run = items.at(-1)?.run ?? queue.lastRun;
|
const run = items.at(-1)?.run ?? queue.lastRun;
|
||||||
if (!run) break;
|
if (!run) break;
|
||||||
|
|
||||||
// Preserve originating channel from items when collecting same-channel.
|
// Preserve originating channel from items when collecting same-channel.
|
||||||
const originatingChannel = items.find(
|
const originatingChannel = items.find(
|
||||||
(i) => i.originatingChannel,
|
(i) => i.originatingChannel,
|
||||||
)?.originatingChannel;
|
)?.originatingChannel;
|
||||||
const originatingTo = items.find(
|
const originatingTo = items.find(
|
||||||
(i) => i.originatingTo,
|
(i) => i.originatingTo,
|
||||||
)?.originatingTo;
|
)?.originatingTo;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import type { ChannelId } from "../channels/plugins/types.js";
|
import type { ChannelId } from "../channels/plugins/types.js";
|
||||||
import type { InternalMessageChannel } from "../utils/message-channel.js";
|
import type { InternalMessageChannel } from "../utils/message-channel.js";
|
||||||
|
|
||||||
/** Valid provider channels for message routing. */
|
/** Valid message channels for routing. */
|
||||||
export type OriginatingChannelType = ChannelId | InternalMessageChannel;
|
export type OriginatingChannelType = ChannelId | InternalMessageChannel;
|
||||||
|
|
||||||
export type MsgContext = {
|
export type MsgContext = {
|
||||||
|
|||||||
@@ -96,21 +96,21 @@ async function connectReq(params: { url: string; token?: string }) {
|
|||||||
|
|
||||||
describe("onboard (non-interactive): gateway auth", () => {
|
describe("onboard (non-interactive): gateway auth", () => {
|
||||||
it("writes gateway token auth into config and gateway enforces it", async () => {
|
it("writes gateway token auth into config and gateway enforces it", async () => {
|
||||||
const prev = {
|
const prev = {
|
||||||
home: process.env.HOME,
|
home: process.env.HOME,
|
||||||
stateDir: process.env.CLAWDBOT_STATE_DIR,
|
stateDir: process.env.CLAWDBOT_STATE_DIR,
|
||||||
configPath: process.env.CLAWDBOT_CONFIG_PATH,
|
configPath: process.env.CLAWDBOT_CONFIG_PATH,
|
||||||
skipChannels: process.env.CLAWDBOT_SKIP_CHANNELS,
|
skipChannels: process.env.CLAWDBOT_SKIP_CHANNELS,
|
||||||
skipGmail: process.env.CLAWDBOT_SKIP_GMAIL_WATCHER,
|
skipGmail: process.env.CLAWDBOT_SKIP_GMAIL_WATCHER,
|
||||||
skipCron: process.env.CLAWDBOT_SKIP_CRON,
|
skipCron: process.env.CLAWDBOT_SKIP_CRON,
|
||||||
skipCanvas: process.env.CLAWDBOT_SKIP_CANVAS_HOST,
|
skipCanvas: process.env.CLAWDBOT_SKIP_CANVAS_HOST,
|
||||||
token: process.env.CLAWDBOT_GATEWAY_TOKEN,
|
token: process.env.CLAWDBOT_GATEWAY_TOKEN,
|
||||||
};
|
};
|
||||||
|
|
||||||
process.env.CLAWDBOT_SKIP_CHANNELS = "1";
|
process.env.CLAWDBOT_SKIP_CHANNELS = "1";
|
||||||
process.env.CLAWDBOT_SKIP_GMAIL_WATCHER = "1";
|
process.env.CLAWDBOT_SKIP_GMAIL_WATCHER = "1";
|
||||||
process.env.CLAWDBOT_SKIP_CRON = "1";
|
process.env.CLAWDBOT_SKIP_CRON = "1";
|
||||||
process.env.CLAWDBOT_SKIP_CANVAS_HOST = "1";
|
process.env.CLAWDBOT_SKIP_CANVAS_HOST = "1";
|
||||||
delete process.env.CLAWDBOT_GATEWAY_TOKEN;
|
delete process.env.CLAWDBOT_GATEWAY_TOKEN;
|
||||||
|
|
||||||
const tempHome = await fs.mkdtemp(
|
const tempHome = await fs.mkdtemp(
|
||||||
@@ -186,7 +186,7 @@ describe("onboard (non-interactive): gateway auth", () => {
|
|||||||
process.env.HOME = prev.home;
|
process.env.HOME = prev.home;
|
||||||
process.env.CLAWDBOT_STATE_DIR = prev.stateDir;
|
process.env.CLAWDBOT_STATE_DIR = prev.stateDir;
|
||||||
process.env.CLAWDBOT_CONFIG_PATH = prev.configPath;
|
process.env.CLAWDBOT_CONFIG_PATH = prev.configPath;
|
||||||
process.env.CLAWDBOT_SKIP_CHANNELS = prev.skipChannels;
|
process.env.CLAWDBOT_SKIP_CHANNELS = prev.skipChannels;
|
||||||
process.env.CLAWDBOT_SKIP_GMAIL_WATCHER = prev.skipGmail;
|
process.env.CLAWDBOT_SKIP_GMAIL_WATCHER = prev.skipGmail;
|
||||||
process.env.CLAWDBOT_SKIP_CRON = prev.skipCron;
|
process.env.CLAWDBOT_SKIP_CRON = prev.skipCron;
|
||||||
process.env.CLAWDBOT_SKIP_CANVAS_HOST = prev.skipCanvas;
|
process.env.CLAWDBOT_SKIP_CANVAS_HOST = prev.skipCanvas;
|
||||||
|
|||||||
@@ -106,21 +106,21 @@ describe("onboard (non-interactive): lan bind auto-token", () => {
|
|||||||
// Windows runner occasionally drops the temp config write in this flow; skip to keep CI green.
|
// Windows runner occasionally drops the temp config write in this flow; skip to keep CI green.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const prev = {
|
const prev = {
|
||||||
home: process.env.HOME,
|
home: process.env.HOME,
|
||||||
stateDir: process.env.CLAWDBOT_STATE_DIR,
|
stateDir: process.env.CLAWDBOT_STATE_DIR,
|
||||||
configPath: process.env.CLAWDBOT_CONFIG_PATH,
|
configPath: process.env.CLAWDBOT_CONFIG_PATH,
|
||||||
skipChannels: process.env.CLAWDBOT_SKIP_CHANNELS,
|
skipChannels: process.env.CLAWDBOT_SKIP_CHANNELS,
|
||||||
skipGmail: process.env.CLAWDBOT_SKIP_GMAIL_WATCHER,
|
skipGmail: process.env.CLAWDBOT_SKIP_GMAIL_WATCHER,
|
||||||
skipCron: process.env.CLAWDBOT_SKIP_CRON,
|
skipCron: process.env.CLAWDBOT_SKIP_CRON,
|
||||||
skipCanvas: process.env.CLAWDBOT_SKIP_CANVAS_HOST,
|
skipCanvas: process.env.CLAWDBOT_SKIP_CANVAS_HOST,
|
||||||
token: process.env.CLAWDBOT_GATEWAY_TOKEN,
|
token: process.env.CLAWDBOT_GATEWAY_TOKEN,
|
||||||
};
|
};
|
||||||
|
|
||||||
process.env.CLAWDBOT_SKIP_CHANNELS = "1";
|
process.env.CLAWDBOT_SKIP_CHANNELS = "1";
|
||||||
process.env.CLAWDBOT_SKIP_GMAIL_WATCHER = "1";
|
process.env.CLAWDBOT_SKIP_GMAIL_WATCHER = "1";
|
||||||
process.env.CLAWDBOT_SKIP_CRON = "1";
|
process.env.CLAWDBOT_SKIP_CRON = "1";
|
||||||
process.env.CLAWDBOT_SKIP_CANVAS_HOST = "1";
|
process.env.CLAWDBOT_SKIP_CANVAS_HOST = "1";
|
||||||
delete process.env.CLAWDBOT_GATEWAY_TOKEN;
|
delete process.env.CLAWDBOT_GATEWAY_TOKEN;
|
||||||
|
|
||||||
const tempHome = await fs.mkdtemp(
|
const tempHome = await fs.mkdtemp(
|
||||||
@@ -215,7 +215,7 @@ describe("onboard (non-interactive): lan bind auto-token", () => {
|
|||||||
process.env.HOME = prev.home;
|
process.env.HOME = prev.home;
|
||||||
process.env.CLAWDBOT_STATE_DIR = prev.stateDir;
|
process.env.CLAWDBOT_STATE_DIR = prev.stateDir;
|
||||||
process.env.CLAWDBOT_CONFIG_PATH = prev.configPath;
|
process.env.CLAWDBOT_CONFIG_PATH = prev.configPath;
|
||||||
process.env.CLAWDBOT_SKIP_CHANNELS = prev.skipChannels;
|
process.env.CLAWDBOT_SKIP_CHANNELS = prev.skipChannels;
|
||||||
process.env.CLAWDBOT_SKIP_GMAIL_WATCHER = prev.skipGmail;
|
process.env.CLAWDBOT_SKIP_GMAIL_WATCHER = prev.skipGmail;
|
||||||
process.env.CLAWDBOT_SKIP_CRON = prev.skipCron;
|
process.env.CLAWDBOT_SKIP_CRON = prev.skipCron;
|
||||||
process.env.CLAWDBOT_SKIP_CANVAS_HOST = prev.skipCanvas;
|
process.env.CLAWDBOT_SKIP_CANVAS_HOST = prev.skipCanvas;
|
||||||
|
|||||||
@@ -27,22 +27,22 @@ async function getFreePort(): Promise<number> {
|
|||||||
|
|
||||||
describe("onboard (non-interactive): remote gateway config", () => {
|
describe("onboard (non-interactive): remote gateway config", () => {
|
||||||
it("writes gateway.remote url/token and callGateway uses them", async () => {
|
it("writes gateway.remote url/token and callGateway uses them", async () => {
|
||||||
const prev = {
|
const prev = {
|
||||||
home: process.env.HOME,
|
home: process.env.HOME,
|
||||||
stateDir: process.env.CLAWDBOT_STATE_DIR,
|
stateDir: process.env.CLAWDBOT_STATE_DIR,
|
||||||
configPath: process.env.CLAWDBOT_CONFIG_PATH,
|
configPath: process.env.CLAWDBOT_CONFIG_PATH,
|
||||||
skipChannels: process.env.CLAWDBOT_SKIP_CHANNELS,
|
skipChannels: process.env.CLAWDBOT_SKIP_CHANNELS,
|
||||||
skipGmail: process.env.CLAWDBOT_SKIP_GMAIL_WATCHER,
|
skipGmail: process.env.CLAWDBOT_SKIP_GMAIL_WATCHER,
|
||||||
skipCron: process.env.CLAWDBOT_SKIP_CRON,
|
skipCron: process.env.CLAWDBOT_SKIP_CRON,
|
||||||
skipCanvas: process.env.CLAWDBOT_SKIP_CANVAS_HOST,
|
skipCanvas: process.env.CLAWDBOT_SKIP_CANVAS_HOST,
|
||||||
token: process.env.CLAWDBOT_GATEWAY_TOKEN,
|
token: process.env.CLAWDBOT_GATEWAY_TOKEN,
|
||||||
password: process.env.CLAWDBOT_GATEWAY_PASSWORD,
|
password: process.env.CLAWDBOT_GATEWAY_PASSWORD,
|
||||||
};
|
};
|
||||||
|
|
||||||
process.env.CLAWDBOT_SKIP_CHANNELS = "1";
|
process.env.CLAWDBOT_SKIP_CHANNELS = "1";
|
||||||
process.env.CLAWDBOT_SKIP_GMAIL_WATCHER = "1";
|
process.env.CLAWDBOT_SKIP_GMAIL_WATCHER = "1";
|
||||||
process.env.CLAWDBOT_SKIP_CRON = "1";
|
process.env.CLAWDBOT_SKIP_CRON = "1";
|
||||||
process.env.CLAWDBOT_SKIP_CANVAS_HOST = "1";
|
process.env.CLAWDBOT_SKIP_CANVAS_HOST = "1";
|
||||||
delete process.env.CLAWDBOT_GATEWAY_TOKEN;
|
delete process.env.CLAWDBOT_GATEWAY_TOKEN;
|
||||||
delete process.env.CLAWDBOT_GATEWAY_PASSWORD;
|
delete process.env.CLAWDBOT_GATEWAY_PASSWORD;
|
||||||
|
|
||||||
@@ -104,16 +104,16 @@ describe("onboard (non-interactive): remote gateway config", () => {
|
|||||||
expect(health?.ok).toBe(true);
|
expect(health?.ok).toBe(true);
|
||||||
} finally {
|
} finally {
|
||||||
await server.close({ reason: "non-interactive remote test complete" });
|
await server.close({ reason: "non-interactive remote test complete" });
|
||||||
await fs.rm(tempHome, { recursive: true, force: true });
|
await fs.rm(tempHome, { recursive: true, force: true });
|
||||||
process.env.HOME = prev.home;
|
process.env.HOME = prev.home;
|
||||||
process.env.CLAWDBOT_STATE_DIR = prev.stateDir;
|
process.env.CLAWDBOT_STATE_DIR = prev.stateDir;
|
||||||
process.env.CLAWDBOT_CONFIG_PATH = prev.configPath;
|
process.env.CLAWDBOT_CONFIG_PATH = prev.configPath;
|
||||||
process.env.CLAWDBOT_SKIP_CHANNELS = prev.skipChannels;
|
process.env.CLAWDBOT_SKIP_CHANNELS = prev.skipChannels;
|
||||||
process.env.CLAWDBOT_SKIP_GMAIL_WATCHER = prev.skipGmail;
|
process.env.CLAWDBOT_SKIP_GMAIL_WATCHER = prev.skipGmail;
|
||||||
process.env.CLAWDBOT_SKIP_CRON = prev.skipCron;
|
process.env.CLAWDBOT_SKIP_CRON = prev.skipCron;
|
||||||
process.env.CLAWDBOT_SKIP_CANVAS_HOST = prev.skipCanvas;
|
process.env.CLAWDBOT_SKIP_CANVAS_HOST = prev.skipCanvas;
|
||||||
process.env.CLAWDBOT_GATEWAY_TOKEN = prev.token;
|
process.env.CLAWDBOT_GATEWAY_TOKEN = prev.token;
|
||||||
process.env.CLAWDBOT_GATEWAY_PASSWORD = prev.password;
|
process.env.CLAWDBOT_GATEWAY_PASSWORD = prev.password;
|
||||||
}
|
}
|
||||||
}, 60_000);
|
}, 60_000);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -199,21 +199,21 @@ async function connectClient(params: { url: string; token: string }) {
|
|||||||
|
|
||||||
describeLive("gateway live (cli backend)", () => {
|
describeLive("gateway live (cli backend)", () => {
|
||||||
it("runs the agent pipeline against the local CLI backend", async () => {
|
it("runs the agent pipeline against the local CLI backend", async () => {
|
||||||
const previous = {
|
const previous = {
|
||||||
configPath: process.env.CLAWDBOT_CONFIG_PATH,
|
configPath: process.env.CLAWDBOT_CONFIG_PATH,
|
||||||
token: process.env.CLAWDBOT_GATEWAY_TOKEN,
|
token: process.env.CLAWDBOT_GATEWAY_TOKEN,
|
||||||
skipChannels: process.env.CLAWDBOT_SKIP_CHANNELS,
|
skipChannels: process.env.CLAWDBOT_SKIP_CHANNELS,
|
||||||
skipGmail: process.env.CLAWDBOT_SKIP_GMAIL_WATCHER,
|
skipGmail: process.env.CLAWDBOT_SKIP_GMAIL_WATCHER,
|
||||||
skipCron: process.env.CLAWDBOT_SKIP_CRON,
|
skipCron: process.env.CLAWDBOT_SKIP_CRON,
|
||||||
skipCanvas: process.env.CLAWDBOT_SKIP_CANVAS_HOST,
|
skipCanvas: process.env.CLAWDBOT_SKIP_CANVAS_HOST,
|
||||||
anthropicApiKey: process.env.ANTHROPIC_API_KEY,
|
anthropicApiKey: process.env.ANTHROPIC_API_KEY,
|
||||||
anthropicApiKeyOld: process.env.ANTHROPIC_API_KEY_OLD,
|
anthropicApiKeyOld: process.env.ANTHROPIC_API_KEY_OLD,
|
||||||
};
|
};
|
||||||
|
|
||||||
process.env.CLAWDBOT_SKIP_CHANNELS = "1";
|
process.env.CLAWDBOT_SKIP_CHANNELS = "1";
|
||||||
process.env.CLAWDBOT_SKIP_GMAIL_WATCHER = "1";
|
process.env.CLAWDBOT_SKIP_GMAIL_WATCHER = "1";
|
||||||
process.env.CLAWDBOT_SKIP_CRON = "1";
|
process.env.CLAWDBOT_SKIP_CRON = "1";
|
||||||
process.env.CLAWDBOT_SKIP_CANVAS_HOST = "1";
|
process.env.CLAWDBOT_SKIP_CANVAS_HOST = "1";
|
||||||
delete process.env.ANTHROPIC_API_KEY;
|
delete process.env.ANTHROPIC_API_KEY;
|
||||||
delete process.env.ANTHROPIC_API_KEY_OLD;
|
delete process.env.ANTHROPIC_API_KEY_OLD;
|
||||||
|
|
||||||
@@ -444,9 +444,9 @@ describeLive("gateway live (cli backend)", () => {
|
|||||||
if (previous.token === undefined)
|
if (previous.token === undefined)
|
||||||
delete process.env.CLAWDBOT_GATEWAY_TOKEN;
|
delete process.env.CLAWDBOT_GATEWAY_TOKEN;
|
||||||
else process.env.CLAWDBOT_GATEWAY_TOKEN = previous.token;
|
else process.env.CLAWDBOT_GATEWAY_TOKEN = previous.token;
|
||||||
if (previous.skipChannels === undefined)
|
if (previous.skipChannels === undefined)
|
||||||
delete process.env.CLAWDBOT_SKIP_CHANNELS;
|
delete process.env.CLAWDBOT_SKIP_CHANNELS;
|
||||||
else process.env.CLAWDBOT_SKIP_CHANNELS = previous.skipChannels;
|
else process.env.CLAWDBOT_SKIP_CHANNELS = previous.skipChannels;
|
||||||
if (previous.skipGmail === undefined)
|
if (previous.skipGmail === undefined)
|
||||||
delete process.env.CLAWDBOT_SKIP_GMAIL_WATCHER;
|
delete process.env.CLAWDBOT_SKIP_GMAIL_WATCHER;
|
||||||
else process.env.CLAWDBOT_SKIP_GMAIL_WATCHER = previous.skipGmail;
|
else process.env.CLAWDBOT_SKIP_GMAIL_WATCHER = previous.skipGmail;
|
||||||
|
|||||||
@@ -271,15 +271,15 @@ async function connectClient(params: { url: string; token: string }) {
|
|||||||
|
|
||||||
describe("gateway (mock openai): tool calling", () => {
|
describe("gateway (mock openai): tool calling", () => {
|
||||||
it("runs a Read tool call end-to-end via gateway agent loop", async () => {
|
it("runs a Read tool call end-to-end via gateway agent loop", async () => {
|
||||||
const prev = {
|
const prev = {
|
||||||
home: process.env.HOME,
|
home: process.env.HOME,
|
||||||
configPath: process.env.CLAWDBOT_CONFIG_PATH,
|
configPath: process.env.CLAWDBOT_CONFIG_PATH,
|
||||||
token: process.env.CLAWDBOT_GATEWAY_TOKEN,
|
token: process.env.CLAWDBOT_GATEWAY_TOKEN,
|
||||||
skipChannels: process.env.CLAWDBOT_SKIP_CHANNELS,
|
skipChannels: process.env.CLAWDBOT_SKIP_CHANNELS,
|
||||||
skipGmail: process.env.CLAWDBOT_SKIP_GMAIL_WATCHER,
|
skipGmail: process.env.CLAWDBOT_SKIP_GMAIL_WATCHER,
|
||||||
skipCron: process.env.CLAWDBOT_SKIP_CRON,
|
skipCron: process.env.CLAWDBOT_SKIP_CRON,
|
||||||
skipCanvas: process.env.CLAWDBOT_SKIP_CANVAS_HOST,
|
skipCanvas: process.env.CLAWDBOT_SKIP_CANVAS_HOST,
|
||||||
};
|
};
|
||||||
|
|
||||||
const originalFetch = globalThis.fetch;
|
const originalFetch = globalThis.fetch;
|
||||||
const openaiResponsesUrl = "https://api.openai.com/v1/responses";
|
const openaiResponsesUrl = "https://api.openai.com/v1/responses";
|
||||||
@@ -321,14 +321,14 @@ describe("gateway (mock openai): tool calling", () => {
|
|||||||
// TypeScript: Bun's fetch typing includes extra properties; keep this test portable.
|
// TypeScript: Bun's fetch typing includes extra properties; keep this test portable.
|
||||||
(globalThis as unknown as { fetch: unknown }).fetch = fetchImpl;
|
(globalThis as unknown as { fetch: unknown }).fetch = fetchImpl;
|
||||||
|
|
||||||
const tempHome = await fs.mkdtemp(
|
const tempHome = await fs.mkdtemp(
|
||||||
path.join(os.tmpdir(), "clawdbot-gw-mock-home-"),
|
path.join(os.tmpdir(), "clawdbot-gw-mock-home-"),
|
||||||
);
|
);
|
||||||
process.env.HOME = tempHome;
|
process.env.HOME = tempHome;
|
||||||
process.env.CLAWDBOT_SKIP_CHANNELS = "1";
|
process.env.CLAWDBOT_SKIP_CHANNELS = "1";
|
||||||
process.env.CLAWDBOT_SKIP_GMAIL_WATCHER = "1";
|
process.env.CLAWDBOT_SKIP_GMAIL_WATCHER = "1";
|
||||||
process.env.CLAWDBOT_SKIP_CRON = "1";
|
process.env.CLAWDBOT_SKIP_CRON = "1";
|
||||||
process.env.CLAWDBOT_SKIP_CANVAS_HOST = "1";
|
process.env.CLAWDBOT_SKIP_CANVAS_HOST = "1";
|
||||||
|
|
||||||
const token = `test-${randomUUID()}`;
|
const token = `test-${randomUUID()}`;
|
||||||
process.env.CLAWDBOT_GATEWAY_TOKEN = token;
|
process.env.CLAWDBOT_GATEWAY_TOKEN = token;
|
||||||
@@ -424,13 +424,13 @@ describe("gateway (mock openai): tool calling", () => {
|
|||||||
await server.close({ reason: "mock openai test complete" });
|
await server.close({ reason: "mock openai test complete" });
|
||||||
await fs.rm(tempHome, { recursive: true, force: true });
|
await fs.rm(tempHome, { recursive: true, force: true });
|
||||||
(globalThis as unknown as { fetch: unknown }).fetch = originalFetch;
|
(globalThis as unknown as { fetch: unknown }).fetch = originalFetch;
|
||||||
process.env.HOME = prev.home;
|
process.env.HOME = prev.home;
|
||||||
process.env.CLAWDBOT_CONFIG_PATH = prev.configPath;
|
process.env.CLAWDBOT_CONFIG_PATH = prev.configPath;
|
||||||
process.env.CLAWDBOT_GATEWAY_TOKEN = prev.token;
|
process.env.CLAWDBOT_GATEWAY_TOKEN = prev.token;
|
||||||
process.env.CLAWDBOT_SKIP_CHANNELS = prev.skipChannels;
|
process.env.CLAWDBOT_SKIP_CHANNELS = prev.skipChannels;
|
||||||
process.env.CLAWDBOT_SKIP_GMAIL_WATCHER = prev.skipGmail;
|
process.env.CLAWDBOT_SKIP_GMAIL_WATCHER = prev.skipGmail;
|
||||||
process.env.CLAWDBOT_SKIP_CRON = prev.skipCron;
|
process.env.CLAWDBOT_SKIP_CRON = prev.skipCron;
|
||||||
process.env.CLAWDBOT_SKIP_CANVAS_HOST = prev.skipCanvas;
|
process.env.CLAWDBOT_SKIP_CANVAS_HOST = prev.skipCanvas;
|
||||||
}
|
}
|
||||||
}, 30_000);
|
}, 30_000);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -172,21 +172,21 @@ type WizardNextPayload = {
|
|||||||
|
|
||||||
describe("gateway wizard (e2e)", () => {
|
describe("gateway wizard (e2e)", () => {
|
||||||
it("runs wizard over ws and writes auth token config", async () => {
|
it("runs wizard over ws and writes auth token config", async () => {
|
||||||
const prev = {
|
const prev = {
|
||||||
home: process.env.HOME,
|
home: process.env.HOME,
|
||||||
stateDir: process.env.CLAWDBOT_STATE_DIR,
|
stateDir: process.env.CLAWDBOT_STATE_DIR,
|
||||||
configPath: process.env.CLAWDBOT_CONFIG_PATH,
|
configPath: process.env.CLAWDBOT_CONFIG_PATH,
|
||||||
token: process.env.CLAWDBOT_GATEWAY_TOKEN,
|
token: process.env.CLAWDBOT_GATEWAY_TOKEN,
|
||||||
skipChannels: process.env.CLAWDBOT_SKIP_CHANNELS,
|
skipChannels: process.env.CLAWDBOT_SKIP_CHANNELS,
|
||||||
skipGmail: process.env.CLAWDBOT_SKIP_GMAIL_WATCHER,
|
skipGmail: process.env.CLAWDBOT_SKIP_GMAIL_WATCHER,
|
||||||
skipCron: process.env.CLAWDBOT_SKIP_CRON,
|
skipCron: process.env.CLAWDBOT_SKIP_CRON,
|
||||||
skipCanvas: process.env.CLAWDBOT_SKIP_CANVAS_HOST,
|
skipCanvas: process.env.CLAWDBOT_SKIP_CANVAS_HOST,
|
||||||
};
|
};
|
||||||
|
|
||||||
process.env.CLAWDBOT_SKIP_CHANNELS = "1";
|
process.env.CLAWDBOT_SKIP_CHANNELS = "1";
|
||||||
process.env.CLAWDBOT_SKIP_GMAIL_WATCHER = "1";
|
process.env.CLAWDBOT_SKIP_GMAIL_WATCHER = "1";
|
||||||
process.env.CLAWDBOT_SKIP_CRON = "1";
|
process.env.CLAWDBOT_SKIP_CRON = "1";
|
||||||
process.env.CLAWDBOT_SKIP_CANVAS_HOST = "1";
|
process.env.CLAWDBOT_SKIP_CANVAS_HOST = "1";
|
||||||
delete process.env.CLAWDBOT_GATEWAY_TOKEN;
|
delete process.env.CLAWDBOT_GATEWAY_TOKEN;
|
||||||
|
|
||||||
const tempHome = await fs.mkdtemp(
|
const tempHome = await fs.mkdtemp(
|
||||||
@@ -282,7 +282,7 @@ describe("gateway wizard (e2e)", () => {
|
|||||||
process.env.CLAWDBOT_STATE_DIR = prev.stateDir;
|
process.env.CLAWDBOT_STATE_DIR = prev.stateDir;
|
||||||
process.env.CLAWDBOT_CONFIG_PATH = prev.configPath;
|
process.env.CLAWDBOT_CONFIG_PATH = prev.configPath;
|
||||||
process.env.CLAWDBOT_GATEWAY_TOKEN = prev.token;
|
process.env.CLAWDBOT_GATEWAY_TOKEN = prev.token;
|
||||||
process.env.CLAWDBOT_SKIP_CHANNELS = prev.skipChannels;
|
process.env.CLAWDBOT_SKIP_CHANNELS = prev.skipChannels;
|
||||||
process.env.CLAWDBOT_SKIP_GMAIL_WATCHER = prev.skipGmail;
|
process.env.CLAWDBOT_SKIP_GMAIL_WATCHER = prev.skipGmail;
|
||||||
process.env.CLAWDBOT_SKIP_CRON = prev.skipCron;
|
process.env.CLAWDBOT_SKIP_CRON = prev.skipCron;
|
||||||
process.env.CLAWDBOT_SKIP_CANVAS_HOST = prev.skipCanvas;
|
process.env.CLAWDBOT_SKIP_CANVAS_HOST = prev.skipCanvas;
|
||||||
|
|||||||
@@ -430,7 +430,11 @@ const SUBSYSTEM_COLOR_OVERRIDES: Record<
|
|||||||
> = {
|
> = {
|
||||||
"gmail-watcher": "blue",
|
"gmail-watcher": "blue",
|
||||||
};
|
};
|
||||||
const SUBSYSTEM_PREFIXES_TO_DROP = ["gateway", "channels", "providers"] as const;
|
const SUBSYSTEM_PREFIXES_TO_DROP = [
|
||||||
|
"gateway",
|
||||||
|
"channels",
|
||||||
|
"providers",
|
||||||
|
] as const;
|
||||||
const SUBSYSTEM_MAX_SEGMENTS = 2;
|
const SUBSYSTEM_MAX_SEGMENTS = 2;
|
||||||
const CHANNEL_SUBSYSTEM_PREFIXES = new Set<string>(CHAT_CHANNEL_ORDER);
|
const CHANNEL_SUBSYSTEM_PREFIXES = new Set<string>(CHAT_CHANNEL_ORDER);
|
||||||
|
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ export function requireActiveWebListener(accountId?: string | null): {
|
|||||||
const listener = listeners.get(id) ?? null;
|
const listener = listeners.get(id) ?? null;
|
||||||
if (!listener) {
|
if (!listener) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`No active WhatsApp Web listener (account: ${id}). Start the gateway, then link WhatsApp with: clawdbot providers login --provider whatsapp --account ${id}.`,
|
`No active WhatsApp Web listener (account: ${id}). Start the gateway, then link WhatsApp with: clawdbot channels login --channel whatsapp --account ${id}.`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return { accountId: id, listener };
|
return { accountId: id, listener };
|
||||||
|
|||||||
@@ -1848,7 +1848,7 @@ export async function monitorWebChannel(
|
|||||||
|
|
||||||
if (loggedOut) {
|
if (loggedOut) {
|
||||||
runtime.error(
|
runtime.error(
|
||||||
"WhatsApp session logged out. Run `clawdbot providers login --provider web` to relink.",
|
"WhatsApp session logged out. Run `clawdbot channels login --channel web` to relink.",
|
||||||
);
|
);
|
||||||
await closeListener();
|
await closeListener();
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ export async function loginWeb(
|
|||||||
});
|
});
|
||||||
console.error(
|
console.error(
|
||||||
danger(
|
danger(
|
||||||
"WhatsApp reported the session is logged out. Cleared cached web session; please rerun clawdbot providers login and scan the QR again.",
|
"WhatsApp reported the session is logged out. Cleared cached web session; please rerun clawdbot channels login and scan the QR again.",
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
throw new Error("Session logged out; cache cleared. Re-run login.");
|
throw new Error("Session logged out; cache cleared. Re-run login.");
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ describe("web outbound", () => {
|
|||||||
).rejects.toThrow(/No active WhatsApp Web listener/);
|
).rejects.toThrow(/No active WhatsApp Web listener/);
|
||||||
await expect(
|
await expect(
|
||||||
sendMessageWhatsApp("+1555", "hi", { verbose: false, accountId: "work" }),
|
sendMessageWhatsApp("+1555", "hi", { verbose: false, accountId: "work" }),
|
||||||
).rejects.toThrow(/providers login/);
|
).rejects.toThrow(/channels login/);
|
||||||
await expect(
|
await expect(
|
||||||
sendMessageWhatsApp("+1555", "hi", { verbose: false, accountId: "work" }),
|
sendMessageWhatsApp("+1555", "hi", { verbose: false, accountId: "work" }),
|
||||||
).rejects.toThrow(/account: work/);
|
).rejects.toThrow(/account: work/);
|
||||||
|
|||||||
@@ -138,7 +138,7 @@ export async function createWaSocket(
|
|||||||
if (status === DisconnectReason.loggedOut) {
|
if (status === DisconnectReason.loggedOut) {
|
||||||
console.error(
|
console.error(
|
||||||
danger(
|
danger(
|
||||||
"WhatsApp session logged out. Run: clawdbot providers login",
|
"WhatsApp session logged out. Run: clawdbot channels login",
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user