fix(channel): add describeAccount so health-monitor sees real configured
openclaw's `channelManager.getRuntimeSnapshot()` — called every minute
by the channel-health-monitor — runs accounts through
`applyDescribedAccountFields(next, plugin.config.describeAccount?.(...))`.
When the callback is missing it defaults `configured: true`. Fabric
never defined it, so every health-monitor cycle:
snapshot = { enabled: true, configured: true, running: false }
For fabric's synthetic 'default' account (returned by
`listFabricAccountIds` when `channels.fabric.accounts` is empty —
the prod shape, where per-agent api-keys live in
`~/.openclaw/fabric-identity.json` and the channel framework never
runs `startAccount` so `running` stays false):
isManagedAccount({enabled:true, configured:true}) === true
-> not-running -> 'stopped' -> restart every ~10 min, logging
'[fabric:default] health-monitor: restarting (reason: stopped)'
The restart is a no-op (fabric's `gateway.startAccount` is absent so
`startChannelInternal` returns early), but the log is loud and
operators chasing real outages keep wasting time on it.
Mirror `isConfigured` from describeAccount so the snapshot
truthfully reports configured:false for any account without a
fabricApiKey. The fabric plugin still self-manages real agents via
`gateway_start` -> `FabricInbound.start()`; the framework just no
longer thinks 'default' is something it should restart.
Verified in sim (this patch alone, no debug instrumentation):
- gateway up 8+ minutes, 0 restart events
- pre-patch sim with same config restarted at 5min mark
- evaluateChannelHealth snapshot for both 'default' and 'recruiter'
accountId reads configured:false (instrumented with temporary
console.log in channel-health-policy, since reverted)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -153,6 +153,19 @@ export const fabricChannelPlugin = createChatChannelPlugin<ResolvedFabricAccount
|
||||
resolveAccount: (cfg, accountId) => resolveFabricAccount(cfg as never, accountId),
|
||||
defaultAccountId: (cfg) => resolveDefaultFabricAccountId(cfg as never),
|
||||
isConfigured: (account: ResolvedFabricAccount) => Boolean(account.fabricApiKey),
|
||||
// openclaw's channelManager.getRuntimeSnapshot() — called every minute
|
||||
// by the channel-health-monitor — defaults `configured: true` when the
|
||||
// plugin doesn't expose describeAccount (see applyDescribedAccountFields
|
||||
// in server-channels). Without this, fabric's synthetic 'default'
|
||||
// account (returned by listFabricAccountIds when channels.fabric.accounts
|
||||
// is empty — the prod shape) gets snapshot {enabled:true, configured:true,
|
||||
// running:false} → isManagedAccount=true → not-running → restart loop
|
||||
// every ~10 min, logging `[fabric:default] health-monitor: restarting`.
|
||||
// Mirror isConfigured here so the snapshot truthfully reports false for
|
||||
// any account without a fabricApiKey.
|
||||
describeAccount: (account: ResolvedFabricAccount) => ({
|
||||
configured: Boolean(account.fabricApiKey),
|
||||
}),
|
||||
},
|
||||
// Minimal setup adapter: Fabric is configured directly under
|
||||
// channels.fabric.* (no interactive wizard). applyAccountConfig is the
|
||||
|
||||
Reference in New Issue
Block a user