mirror of
https://github.com/sipeed/picoclaw.git
synced 2026-06-12 18:08:54 +00:00
feat(channels): add MediaSender optional interface for outbound media
Add outbound media sending capability so the agent can publish media attachments (images, files, audio, video) through channels via the bus. - Add MediaPart and OutboundMediaMessage types to bus - Add PublishOutboundMedia/SubscribeOutboundMedia bus methods - Add MediaSender interface discovered via type assertion by Manager - Add media dispatch/worker in Manager with shared retry logic - Extend ToolResult with Media field and MediaResult constructor - Publish outbound media from agent loop on tool results - Implement SendMedia for Telegram, Discord, Slack, LINE, OneBot, WeCom
This commit is contained in:
+34
-7
@@ -10,17 +10,19 @@ import (
|
||||
var ErrBusClosed = errors.New("message bus closed")
|
||||
|
||||
type MessageBus struct {
|
||||
inbound chan InboundMessage
|
||||
outbound chan OutboundMessage
|
||||
done chan struct{}
|
||||
closed atomic.Bool
|
||||
inbound chan InboundMessage
|
||||
outbound chan OutboundMessage
|
||||
outboundMedia chan OutboundMediaMessage
|
||||
done chan struct{}
|
||||
closed atomic.Bool
|
||||
}
|
||||
|
||||
func NewMessageBus() *MessageBus {
|
||||
return &MessageBus{
|
||||
inbound: make(chan InboundMessage, 100),
|
||||
outbound: make(chan OutboundMessage, 100),
|
||||
done: make(chan struct{}),
|
||||
inbound: make(chan InboundMessage, 100),
|
||||
outbound: make(chan OutboundMessage, 100),
|
||||
outboundMedia: make(chan OutboundMediaMessage, 100),
|
||||
done: make(chan struct{}),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,6 +76,31 @@ func (mb *MessageBus) SubscribeOutbound(ctx context.Context) (OutboundMessage, b
|
||||
}
|
||||
}
|
||||
|
||||
func (mb *MessageBus) PublishOutboundMedia(ctx context.Context, msg OutboundMediaMessage) error {
|
||||
if mb.closed.Load() {
|
||||
return ErrBusClosed
|
||||
}
|
||||
select {
|
||||
case mb.outboundMedia <- msg:
|
||||
return nil
|
||||
case <-mb.done:
|
||||
return ErrBusClosed
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
}
|
||||
}
|
||||
|
||||
func (mb *MessageBus) SubscribeOutboundMedia(ctx context.Context) (OutboundMediaMessage, bool) {
|
||||
select {
|
||||
case msg, ok := <-mb.outboundMedia:
|
||||
return msg, ok
|
||||
case <-mb.done:
|
||||
return OutboundMediaMessage{}, false
|
||||
case <-ctx.Done():
|
||||
return OutboundMediaMessage{}, false
|
||||
}
|
||||
}
|
||||
|
||||
func (mb *MessageBus) Close() {
|
||||
if mb.closed.CompareAndSwap(false, true) {
|
||||
close(mb.done)
|
||||
|
||||
@@ -24,3 +24,19 @@ type OutboundMessage struct {
|
||||
ChatID string `json:"chat_id"`
|
||||
Content string `json:"content"`
|
||||
}
|
||||
|
||||
// MediaPart describes a single media attachment to send.
|
||||
type MediaPart struct {
|
||||
Type string `json:"type"` // "image" | "audio" | "video" | "file"
|
||||
Ref string `json:"ref"` // media store ref, e.g. "media://abc123"
|
||||
Caption string `json:"caption,omitempty"` // optional caption text
|
||||
Filename string `json:"filename,omitempty"` // original filename hint
|
||||
ContentType string `json:"content_type,omitempty"` // MIME type hint
|
||||
}
|
||||
|
||||
// OutboundMediaMessage carries media attachments from Agent to channels via the bus.
|
||||
type OutboundMediaMessage struct {
|
||||
Channel string `json:"channel"`
|
||||
ChatID string `json:"chat_id"`
|
||||
Parts []MediaPart `json:"parts"`
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user