fix(agent): use routed agent for model commands, restore Telegram command diff
- Remove modelMu: message processing is serial, no concurrent writes - Pass routed agent to handleCommand/buildCommandsRuntime instead of always using default agent - GetModelInfo/SwitchModel are nil when agent is nil (route failed), handlers reply "unavailable" - Restore GetMyCommands + slices.Equal check before SetMyCommands to avoid unnecessary Telegram API calls on restart Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
c87533eb7a
commit
75f1b58ca0
2 changed files with 31 additions and 27 deletions
|
|
@ -48,7 +48,6 @@ type AgentLoop struct {
|
|||
mediaStore media.MediaStore
|
||||
transcriber voice.Transcriber
|
||||
cmdRegistry *commands.Registry
|
||||
modelMu sync.Mutex // protects AgentInstance.Model writes in SwitchModel
|
||||
}
|
||||
|
||||
// processOptions configures how a message is processed
|
||||
|
|
@ -538,7 +537,7 @@ func (al *AgentLoop) processMessage(ctx context.Context, msg bus.InboundMessage)
|
|||
// Global commands (/help, /show, /switch) work even when routing fails;
|
||||
// context-dependent commands check their own Runtime fields and report
|
||||
// "unavailable" when the required capability is nil.
|
||||
if response, handled := al.handleCommand(ctx, msg); handled {
|
||||
if response, handled := al.handleCommand(ctx, msg, agent); handled {
|
||||
return response, nil
|
||||
}
|
||||
|
||||
|
|
@ -1466,6 +1465,7 @@ func (al *AgentLoop) estimateTokens(messages []providers.Message) int {
|
|||
func (al *AgentLoop) handleCommand(
|
||||
ctx context.Context,
|
||||
msg bus.InboundMessage,
|
||||
agent *AgentInstance,
|
||||
) (string, bool) {
|
||||
if !commands.HasCommandPrefix(msg.Content) {
|
||||
return "", false
|
||||
|
|
@ -1475,7 +1475,7 @@ func (al *AgentLoop) handleCommand(
|
|||
return "", false
|
||||
}
|
||||
|
||||
rt := al.buildCommandsRuntime()
|
||||
rt := al.buildCommandsRuntime(agent)
|
||||
executor := commands.NewExecutor(al.cmdRegistry, rt)
|
||||
|
||||
var commandReply string
|
||||
|
|
@ -1504,16 +1504,9 @@ func (al *AgentLoop) handleCommand(
|
|||
}
|
||||
}
|
||||
|
||||
func (al *AgentLoop) buildCommandsRuntime() *commands.Runtime {
|
||||
return &commands.Runtime{
|
||||
func (al *AgentLoop) buildCommandsRuntime(agent *AgentInstance) *commands.Runtime {
|
||||
rt := &commands.Runtime{
|
||||
Config: al.cfg,
|
||||
GetModelInfo: func() (string, string) {
|
||||
agent := al.registry.GetDefaultAgent()
|
||||
if agent == nil {
|
||||
return al.cfg.Agents.Defaults.GetModelName(), al.cfg.Agents.Defaults.Provider
|
||||
}
|
||||
return agent.Model, al.cfg.Agents.Defaults.Provider
|
||||
},
|
||||
ListAgentIDs: al.registry.ListAgentIDs,
|
||||
ListDefinitions: al.cmdRegistry.Definitions,
|
||||
GetEnabledChannels: func() []string {
|
||||
|
|
@ -1522,20 +1515,6 @@ func (al *AgentLoop) buildCommandsRuntime() *commands.Runtime {
|
|||
}
|
||||
return al.channelManager.GetEnabledChannels()
|
||||
},
|
||||
SwitchModel: func(value string) (string, error) {
|
||||
al.modelMu.Lock()
|
||||
defer al.modelMu.Unlock()
|
||||
defaultAgent := al.registry.GetDefaultAgent()
|
||||
if defaultAgent == nil {
|
||||
return "", fmt.Errorf("no default agent configured")
|
||||
}
|
||||
oldModel := defaultAgent.Model
|
||||
defaultAgent.Model = value
|
||||
if al.cfg != nil {
|
||||
al.cfg.Agents.Defaults.ModelName = value
|
||||
}
|
||||
return oldModel, nil
|
||||
},
|
||||
SwitchChannel: func(value string) error {
|
||||
if al.channelManager == nil {
|
||||
return fmt.Errorf("channel manager not initialized")
|
||||
|
|
@ -1546,6 +1525,20 @@ func (al *AgentLoop) buildCommandsRuntime() *commands.Runtime {
|
|||
return nil
|
||||
},
|
||||
}
|
||||
if agent != nil {
|
||||
rt.GetModelInfo = func() (string, string) {
|
||||
return agent.Model, al.cfg.Agents.Defaults.Provider
|
||||
}
|
||||
rt.SwitchModel = func(value string) (string, error) {
|
||||
oldModel := agent.Model
|
||||
agent.Model = value
|
||||
if al.cfg != nil {
|
||||
al.cfg.Agents.Defaults.ModelName = value
|
||||
}
|
||||
return oldModel, nil
|
||||
}
|
||||
}
|
||||
return rt
|
||||
}
|
||||
|
||||
func mapCommandError(result commands.ExecuteResult) string {
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package telegram
|
|||
import (
|
||||
"context"
|
||||
"math/rand"
|
||||
"slices"
|
||||
"time"
|
||||
|
||||
"github.com/mymmrac/telego"
|
||||
|
|
@ -41,6 +42,16 @@ func (c *TelegramChannel) RegisterCommands(ctx context.Context, defs []commands.
|
|||
})
|
||||
}
|
||||
|
||||
current, err := c.bot.GetMyCommands(ctx, &telego.GetMyCommandsParams{})
|
||||
if err != nil {
|
||||
// If we can't read current commands, fall through to set them.
|
||||
logger.WarnCF("telegram", "Failed to get current commands, will set unconditionally",
|
||||
map[string]any{"error": err.Error()})
|
||||
} else if slices.Equal(current, botCommands) {
|
||||
logger.DebugCF("telegram", "Bot commands are up to date", nil)
|
||||
return nil
|
||||
}
|
||||
|
||||
return c.bot.SetMyCommands(ctx, &telego.SetMyCommandsParams{
|
||||
Commands: botCommands,
|
||||
})
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue