From e23e1793f1013c7796f7456ddf9b78e3c0deffb9 Mon Sep 17 00:00:00 2001 From: Huaaudio Date: Sat, 21 Mar 2026 07:21:33 +0100 Subject: [PATCH] remove leave tool due to delay --- pkg/agent/loop.go | 3 -- pkg/bus/types.go | 3 +- pkg/channels/discord/discord.go | 11 +------ pkg/tools/voice_leave.go | 52 --------------------------------- pkg/voice/agent.go | 19 +++++++++++- 5 files changed, 20 insertions(+), 68 deletions(-) delete mode 100644 pkg/tools/voice_leave.go diff --git a/pkg/agent/loop.go b/pkg/agent/loop.go index aa15a23d5..725d42614 100644 --- a/pkg/agent/loop.go +++ b/pkg/agent/loop.go @@ -238,9 +238,6 @@ func registerSharedTools( agent.Tools.Register(messageTool) } - // Always register Voice Leave Tool (it inherently checks if channel == "discord") - agent.Tools.Register(tools.NewVoiceLeaveTool(msgBus)) - // Send file tool (outbound media via MediaStore — store injected later by SetMediaStore) if cfg.Tools.IsToolEnabled("send_file") { sendFileTool := tools.NewSendFileTool( diff --git a/pkg/bus/types.go b/pkg/bus/types.go index b4e99d955..9c637f3e7 100644 --- a/pkg/bus/types.go +++ b/pkg/bus/types.go @@ -68,7 +68,6 @@ type AudioChunk struct { // VoiceControl represents state or commands for voice sessions. type VoiceControl struct { SessionID string `json:"session_id"` - ChatID string `json:"chat_id"` - Type string `json:"type"` // "state", "command" + Type string `json:"type"` // "state", "command" Action string `json:"action"` // "idle", "listening", "start", "stop" } diff --git a/pkg/channels/discord/discord.go b/pkg/channels/discord/discord.go index 6194685e8..26332455a 100644 --- a/pkg/channels/discord/discord.go +++ b/pkg/channels/discord/discord.go @@ -629,17 +629,8 @@ func (c *DiscordChannel) listenVoiceControl(ctx context.Context) { return case ctrl := <-c.bus.VoiceControlsChan(): if ctrl.Type == "command" && ctrl.Action == "leave" { - var guildID string if strings.HasPrefix(ctrl.SessionID, "discord_vc_") { - guildID = strings.TrimPrefix(ctrl.SessionID, "discord_vc_") - } else if ctrl.ChatID != "" { - ch, err := c.session.State.Channel(ctrl.ChatID) - if err == nil { - guildID = ch.GuildID - } - } - - if guildID != "" { + guildID := strings.TrimPrefix(ctrl.SessionID, "discord_vc_") vc, exists := c.session.VoiceConnections[guildID] if exists && vc != nil { vc.Disconnect(ctx) diff --git a/pkg/tools/voice_leave.go b/pkg/tools/voice_leave.go deleted file mode 100644 index 882e7cb9d..000000000 --- a/pkg/tools/voice_leave.go +++ /dev/null @@ -1,52 +0,0 @@ -package tools - -import ( - "context" - - "github.com/sipeed/picoclaw/pkg/bus" - "github.com/sipeed/picoclaw/pkg/logger" -) - -type VoiceLeaveTool struct { - bus *bus.MessageBus -} - -func NewVoiceLeaveTool(mb *bus.MessageBus) *VoiceLeaveTool { - return &VoiceLeaveTool{bus: mb} -} - -func (t *VoiceLeaveTool) Name() string { - return "voice_leave" -} - -func (t *VoiceLeaveTool) Description() string { - return "Disconnects the bot from the current voice channel. Use this tool when the user says goodbye or explicitly asks you to leave the voice chat." -} - -func (t *VoiceLeaveTool) Parameters() map[string]any { - return map[string]any{ - "type": "object", - "properties": map[string]any{}, - } -} - -func (t *VoiceLeaveTool) Execute(ctx context.Context, args map[string]any) *ToolResult { - channel := ToolChannel(ctx) - chatID := ToolChatID(ctx) - - if channel != "discord" { - return &ToolResult{ForLLM: "Can only leave voice channels on Discord", IsError: true} - } - - t.bus.PublishVoiceControl(ctx, bus.VoiceControl{ - ChatID: chatID, - Type: "command", - Action: "leave", - }) - - logger.InfoCF("agent", "Voice command triggered via tool: leave", map[string]any{"chat_id": chatID}) - - return &ToolResult{ - ForLLM: "Successfully sent disconnect command to voice adapter.", - } -} diff --git a/pkg/voice/agent.go b/pkg/voice/agent.go index 233da6019..6a2abd24f 100644 --- a/pkg/voice/agent.go +++ b/pkg/voice/agent.go @@ -5,6 +5,7 @@ import ( "fmt" "os" "path/filepath" + "strings" "sync" "time" @@ -184,7 +185,23 @@ func (a *Agent) processUtterance(ctx context.Context, acc *speechAccumulator) { channelType := "discord" - oralPrompt := "\n\n[SYSTEM]: The user just spoke this to you over voice chat. Please reply in a highly concise, conversational, oral style suitable for text-to-speech. Do not use markdown, emojis, asterisks, or code blocks. Speak naturally. If the user expresses that they want to end the call, say goodbye and use the voice_leave tool." + text := strings.ToLower(strings.TrimSpace(res.Text)) + if strings.Contains(text, "leave the voice channel") || strings.Contains(text, "leave voice") || strings.Contains(text, "disconnect voice") { + logger.InfoCF("voice-agent", "Voice command triggered: leave", nil) + a.bus.PublishVoiceControl(ctx, bus.VoiceControl{ + SessionID: acc.sessionID, + Type: "command", + Action: "leave", + }) + a.bus.PublishOutbound(ctx, bus.OutboundMessage{ + Channel: channelType, + ChatID: acc.chatID, + Content: "Goodbye! Leaving the voice channel.", + }) + return + } + + oralPrompt := "\n\n[SYSTEM]: The user just spoke this to you over voice chat. Please reply in a highly concise, conversational, oral style suitable for text-to-speech. Do not use markdown, emojis, asterisks, or code blocks. Speak naturally." a.bus.PublishInbound(ctx, bus.InboundMessage{ Channel: channelType,