openclaw/extensions/discord/index.ts
Johnathon Selstad c624ff3098 feat(discord): Add bot presence/status updates with token usage tracking
Integrates presence updates directly into the Discord channel integration:

- Added presence config schema (channels.discord.presence):
  - enabled: Toggle presence updates
  - showTokenUsage: Show cumulative token count
  - format: Custom format string with placeholders ({tokens}, {model}, etc.)
  - activityType: Playing, Watching, Listening, Competing (NOT Custom - bots can't use it)
  - status: online, idle, dnd, invisible

- Created PresenceManager in src/discord/monitor/presence-manager.ts:
  - Tracks cumulative token usage per session
  - Formats status text with configurable placeholders
  - Interfaces with Carbon GatewayPlugin.updatePresence()

- Created presence registry (src/discord/presence-registry.ts):
  - Shared registry for presence managers across accounts
  - Exported via plugin-sdk for extension access

- Wired up message_sent hook in Discord extension:
  - Hook triggers after each reply is delivered
  - Updates bot presence with session token counts

Config example:
```json5
channels: {
  discord: {
    presence: {
      enabled: true,
      showTokenUsage: true,
      format: "📊 {tokens} tokens",
      activityType: "Watching",  // Shows: "Watching 📊 1,234 tokens"
      status: "online"
    }
  }
}
```

Note: Discord API limitation - bots cannot use Custom activity type (type 4).
Available types: Playing, Watching, Listening, Competing.
2026-01-26 14:31:47 -08:00

48 lines
1.4 KiB
TypeScript

import type { ClawdbotPluginApi } from "clawdbot/plugin-sdk";
import { emptyPluginConfigSchema, getPresenceManager } from "clawdbot/plugin-sdk";
import { discordPlugin } from "./src/channel.js";
import { setDiscordRuntime } from "./src/runtime.js";
const plugin = {
id: "discord",
name: "Discord",
description: "Discord channel plugin",
configSchema: emptyPluginConfigSchema(),
register(api: ClawdbotPluginApi) {
setDiscordRuntime(api.runtime);
api.registerChannel({ plugin: discordPlugin });
// Register message_sent hook for presence updates
api.registerHook({
hookName: "message_sent",
priority: 5,
handler: async (event, ctx) => {
// Only handle Discord channel
if (ctx.channelId !== "discord") {
return;
}
// Find the presence manager for this account
const accountId = ctx.accountId ?? "default";
const manager = getPresenceManager(accountId);
if (!manager) {
return;
}
// Update presence with usage info
manager.updatePresence({
sessionKey: ctx.sessionKey,
tokens: event.usage?.totalTokens,
inputTokens: event.usage?.inputTokens,
outputTokens: event.usage?.outputTokens,
model: event.usage?.model,
provider: event.usage?.provider,
});
},
});
},
};
export default plugin;