Skip to content

Bug: createPluginHandler rejects channel plugins missing sendMedia despite type marking it optional #32711

@NOVA-Openclaw

Description

@NOVA-Openclaw

Summary

createPluginHandler() in src/infra/outbound/deliver.ts requires both sendText AND sendMedia at runtime:

if (!outbound?.sendText || !outbound?.sendMedia) {
  return null;
}

But the ChannelOutboundAdapter type in plugin-sdk/channels/plugins/types.adapters.d.ts marks sendMedia as optional:

export type ChannelOutboundAdapter = {
    // ...
    sendText?: (ctx: ChannelOutboundContext) => Promise<OutboundDeliveryResult>;
    sendMedia?: (ctx: ChannelOutboundContext) => Promise<OutboundDeliveryResult>;  // optional
};

The plugin documentation (docs/tools/plugin.md) also shows a minimal channel plugin example with only sendText and no sendMedia.

Impact

Any channel plugin that only implements sendText (text-only channels) is completely broken for outbound. When sendMedia is absent, createPluginHandler() returns null, and the caller throws:

Error: Outbound not configured for channel: <id>

This blocks ALL outbound for that channel — including pure text sends — even though the channel correctly implements sendText.

Use Case

Text-only channels where media doesn't apply:

  • Inter-agent messaging over database tables
  • IRC bridges
  • Webhook-only notification channels
  • Any custom channel where messages are text records, not rich media

Expected Behavior

A channel plugin implementing only sendText should be able to send text messages. When media delivery is attempted on a text-only channel, it should gracefully degrade (e.g., send the caption text, drop the media URL).

Suggested Fix

Only require sendText in the guard. When sendMedia is absent, synthesize a fallback that sends caption text via sendText:

if (!outbound?.sendText) {
  return null;
}

This aligns the runtime behavior with the type definition and the documented minimal channel plugin pattern.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions