fix: improve message handling and bus closure logic for better reliability
This commit is contained in:
parent
41dff3b9b9
commit
334c08a27f
3 changed files with 70 additions and 61 deletions
|
|
@ -251,63 +251,65 @@ func (al *AgentLoop) Run(ctx context.Context) error {
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
return nil
|
return nil
|
||||||
case msg := <-al.bus.InboundChan():
|
case msg, ok := <-al.bus.InboundChan():
|
||||||
|
if !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
// Process message
|
// Process message
|
||||||
func() {
|
// TODO: Re-enable media cleanup after inbound media is properly consumed by the agent.
|
||||||
// TODO: Re-enable media cleanup after inbound media is properly consumed by the agent.
|
// Currently disabled because files are deleted before the LLM can access their content.
|
||||||
// Currently disabled because files are deleted before the LLM can access their content.
|
// defer func() {
|
||||||
// defer func() {
|
// if al.mediaStore != nil && msg.MediaScope != "" {
|
||||||
// if al.mediaStore != nil && msg.MediaScope != "" {
|
// if releaseErr := al.mediaStore.ReleaseAll(msg.MediaScope); releaseErr != nil {
|
||||||
// if releaseErr := al.mediaStore.ReleaseAll(msg.MediaScope); releaseErr != nil {
|
// logger.WarnCF("agent", "Failed to release media", map[string]any{
|
||||||
// logger.WarnCF("agent", "Failed to release media", map[string]any{
|
// "scope": msg.MediaScope,
|
||||||
// "scope": msg.MediaScope,
|
// "error": releaseErr.Error(),
|
||||||
// "error": releaseErr.Error(),
|
// })
|
||||||
// })
|
// }
|
||||||
// }
|
// }
|
||||||
// }
|
// }()
|
||||||
// }()
|
|
||||||
|
|
||||||
response, err := al.processMessage(ctx, msg)
|
response, err := al.processMessage(ctx, msg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
response = fmt.Sprintf("Error processing message: %v", err)
|
response = fmt.Sprintf("Error processing message: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if response != "" {
|
if response != "" {
|
||||||
// Check if the message tool already sent a response during this round.
|
// Check if the message tool already sent a response during this round.
|
||||||
// If so, skip publishing to avoid duplicate messages to the user.
|
// If so, skip publishing to avoid duplicate messages to the user.
|
||||||
// Use default agent's tools to check (message tool is shared).
|
// Use default agent's tools to check (message tool is shared).
|
||||||
alreadySent := false
|
alreadySent := false
|
||||||
defaultAgent := al.GetRegistry().GetDefaultAgent()
|
defaultAgent := al.GetRegistry().GetDefaultAgent()
|
||||||
if defaultAgent != nil {
|
if defaultAgent != nil {
|
||||||
if tool, ok := defaultAgent.Tools.Get("message"); ok {
|
if tool, ok := defaultAgent.Tools.Get("message"); ok {
|
||||||
if mt, ok := tool.(*tools.MessageTool); ok {
|
if mt, ok := tool.(*tools.MessageTool); ok {
|
||||||
alreadySent = mt.HasSentInRound()
|
alreadySent = mt.HasSentInRound()
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !alreadySent {
|
|
||||||
al.bus.PublishOutbound(ctx, bus.OutboundMessage{
|
|
||||||
Channel: msg.Channel,
|
|
||||||
ChatID: msg.ChatID,
|
|
||||||
Content: response,
|
|
||||||
})
|
|
||||||
logger.InfoCF("agent", "Published outbound response",
|
|
||||||
map[string]any{
|
|
||||||
"channel": msg.Channel,
|
|
||||||
"chat_id": msg.ChatID,
|
|
||||||
"content_len": len(response),
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
logger.DebugCF(
|
|
||||||
"agent",
|
|
||||||
"Skipped outbound (message tool already sent)",
|
|
||||||
map[string]any{"channel": msg.Channel},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}()
|
|
||||||
|
if !alreadySent {
|
||||||
|
al.bus.PublishOutbound(ctx, bus.OutboundMessage{
|
||||||
|
Channel: msg.Channel,
|
||||||
|
ChatID: msg.ChatID,
|
||||||
|
Content: response,
|
||||||
|
})
|
||||||
|
logger.InfoCF("agent", "Published outbound response",
|
||||||
|
map[string]any{
|
||||||
|
"channel": msg.Channel,
|
||||||
|
"chat_id": msg.ChatID,
|
||||||
|
"content_len": len(response),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
logger.DebugCF(
|
||||||
|
"agent",
|
||||||
|
"Skipped outbound (message tool already sent)",
|
||||||
|
map[string]any{"channel": msg.Channel},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
|
time.Sleep(time.Second * 5)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -88,11 +88,13 @@ func (mb *MessageBus) OutboundMediaChan() <-chan OutboundMediaMessage {
|
||||||
|
|
||||||
func (mb *MessageBus) Close() {
|
func (mb *MessageBus) Close() {
|
||||||
mb.closeOnce.Do(func() {
|
mb.closeOnce.Do(func() {
|
||||||
mb.closed.Store(true)
|
|
||||||
|
|
||||||
// notify all blocked publishers to exit
|
// notify all blocked publishers to exit
|
||||||
close(mb.done)
|
close(mb.done)
|
||||||
|
|
||||||
|
// because every publisher will check mb.closed before acquiring wg
|
||||||
|
// so we can be sure that new publishers will not be added new messages after this point
|
||||||
|
mb.closed.Store(true)
|
||||||
|
|
||||||
// wait for all ongoing Publish calls to finish, ensuring all messages have been sent to channels or exited
|
// wait for all ongoing Publish calls to finish, ensuring all messages have been sent to channels or exited
|
||||||
mb.wg.Wait()
|
mb.wg.Wait()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -43,14 +43,19 @@ func TestHandleIncoming_DoesNotConsumeGenericCommandsLocally(t *testing.T) {
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
inbound, ok := messageBus.ConsumeInbound(ctx)
|
select {
|
||||||
if !ok {
|
case <-ctx.Done():
|
||||||
t.Fatal("expected inbound message to be forwarded")
|
t.Fatal("timeout waiting for message to be forwarded")
|
||||||
}
|
return
|
||||||
if inbound.Channel != "whatsapp_native" {
|
case inbound, ok := <-messageBus.InboundChan():
|
||||||
t.Fatalf("channel=%q", inbound.Channel)
|
if !ok {
|
||||||
}
|
t.Fatal("expected inbound message to be forwarded")
|
||||||
if inbound.Content != "/new" {
|
}
|
||||||
t.Fatalf("content=%q", inbound.Content)
|
if inbound.Channel != "whatsapp_native" {
|
||||||
|
t.Fatalf("channel=%q", inbound.Channel)
|
||||||
|
}
|
||||||
|
if inbound.Content != "/new" {
|
||||||
|
t.Fatalf("content=%q", inbound.Content)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue