工具路由还没实现

This commit is contained in:
2026-06-18 08:14:09 +08:00
parent dfb3fdd3e5
commit 45822fd333
18 changed files with 172 additions and 223 deletions
+19 -8
View File
@@ -7,22 +7,33 @@ import (
// BotServiceAdapter adapts the bot service to the BotSender interface
type BotServiceAdapter struct {
sendTextFn func(ctx context.Context, botID uint64, toNodeNum int64, text string) error
sendDirectTextFn func(ctx context.Context, botID uint64, toNodeNum int64, text string) error
sendChannelTextFn func(ctx context.Context, botID uint64, channelID string, text string) error
}
// NewBotServiceAdapter creates a new bot service adapter
func NewBotServiceAdapter(
sendTextFn func(ctx context.Context, botID uint64, toNodeNum int64, text string) error,
sendDirectTextFn func(ctx context.Context, botID uint64, toNodeNum int64, text string) error,
sendChannelTextFn func(ctx context.Context, botID uint64, channelID string, text string) error,
) *BotServiceAdapter {
return &BotServiceAdapter{
sendTextFn: sendTextFn,
sendDirectTextFn: sendDirectTextFn,
sendChannelTextFn: sendChannelTextFn,
}
}
// SendText sends a text message via the bot service
func (a *BotServiceAdapter) SendText(ctx context.Context, botID uint64, toNodeNum int64, text string) error {
if a.sendTextFn == nil {
return fmt.Errorf("send text function is nil")
// SendDirectText sends a direct/private message to a specific node
func (a *BotServiceAdapter) SendDirectText(ctx context.Context, botID uint64, toNodeNum int64, text string) error {
if a.sendDirectTextFn == nil {
return fmt.Errorf("send direct text function is nil")
}
return a.sendTextFn(ctx, botID, toNodeNum, text)
return a.sendDirectTextFn(ctx, botID, toNodeNum, text)
}
// SendChannelText sends a channel message to a specific channel
func (a *BotServiceAdapter) SendChannelText(ctx context.Context, botID uint64, channelID string, text string) error {
if a.sendChannelTextFn == nil {
return fmt.Errorf("send channel text function is nil")
}
return a.sendChannelTextFn(ctx, botID, channelID, text)
}
+2
View File
@@ -38,6 +38,7 @@ type llmMessageQueueRecord struct {
PacketID int64 `gorm:"column:packet_id;not null"`
ChannelID *string `gorm:"column:channel_id"`
Topic string `gorm:"column:topic;not null"`
MessageType string `gorm:"column:message_type;not null;default:'direct'"` // "channel" 或 "direct"
Status string `gorm:"column:status;not null;index"`
Error string `gorm:"column:error;type:text"`
Reply string `gorm:"column:reply;type:text"`
@@ -79,6 +80,7 @@ func (q *DBMessageQueue) GetPendingMessages(botID uint64, limit int) ([]QueuedMe
PacketID: r.PacketID,
ChannelID: r.ChannelID,
Topic: r.Topic,
MessageType: r.MessageType,
ReceivedAt: r.ReceivedAt,
})
}
+50 -19
View File
@@ -51,22 +51,32 @@ type QueuedMessage struct {
PacketID int64
ChannelID *string
Topic string
MessageType string // "channel" 或 "direct"
ReceivedAt time.Time
}
// BotSender is the interface for sending bot messages
type BotSender interface {
SendText(ctx context.Context, botID uint64, toNodeNum int64, text string) error
// SendDirectText 发送私聊消息给指定节点
SendDirectText(ctx context.Context, botID uint64, toNodeNum int64, text string) error
// SendChannelText 发送频道消息到指定频道
SendChannelText(ctx context.Context, botID uint64, channelID string, text string) error
}
// SystemPromptStore is the interface for getting the system prompt
type SystemPromptStore interface {
GetLLMPrimaryConfigSystemPrompt() (string, error)
}
// Service manages automatic AI replies for bots
type Service struct {
llmState *llm.State
toolRouter *toolrouter.State
toolMgr *toolmanager.Manager
convStore *conversation.Store
msgQueue MessageQueue
botSender BotSender
llmState *llm.State
toolRouter *toolrouter.State
toolMgr *toolmanager.Manager
convStore *conversation.Store
msgQueue MessageQueue
botSender BotSender
systemPromptStore SystemPromptStore
running bool
mu sync.Mutex
@@ -82,14 +92,16 @@ func NewService(
convStore *conversation.Store,
msgQueue MessageQueue,
botSender BotSender,
systemPromptStore SystemPromptStore,
) *Service {
return &Service{
llmState: llmState,
toolRouter: toolRouter,
toolMgr: toolMgr,
convStore: convStore,
msgQueue: msgQueue,
botSender: botSender,
llmState: llmState,
toolRouter: toolRouter,
toolMgr: toolMgr,
convStore: convStore,
msgQueue: msgQueue,
botSender: botSender,
systemPromptStore: systemPromptStore,
}
}
@@ -241,13 +253,22 @@ func (s *Service) processMessage(ctx context.Context, msg QueuedMessage) {
return
}
// Get system prompt from primary config
var systemPrompt string
if s.systemPromptStore != nil {
systemPrompt, err = s.systemPromptStore.GetLLMPrimaryConfigSystemPrompt()
if err != nil {
printJSON(map[string]any{"event": "llm_system_prompt_warning", "msg_id": msg.ID, "error": err.Error()})
}
}
// Run the tool loop to get augmented messages
augmentedMessages, err := toolrouter.RunAgentToolLoop(procCtx, s.toolRouter, profile, conv.Messages, s.toolMgr, nil)
_ = augmentedMessages // We'll use this in the future with proper tool support
// For now, use simple completion since we don't have tools registered yet
printJSON(map[string]any{"event": "llm_process_completion_start", "msg_id": msg.ID})
reply, err := completion.CompleteText(procCtx, profile, conv.Messages, 512)
printJSON(map[string]any{"event": "llm_process_completion_start", "msg_id": msg.ID, "has_system_prompt": systemPrompt != ""})
reply, err := completion.CompleteText(procCtx, profile, systemPrompt, conv.Messages, 512)
if err != nil {
errMsg := fmt.Sprintf("LLM completion failed: %v", err)
printJSON(map[string]any{"event": "llm_process_failed", "msg_id": msg.ID, "step": "llm_completion", "error": errMsg})
@@ -304,10 +325,20 @@ func (s *Service) processMessage(ctx context.Context, msg QueuedMessage) {
// Non-fatal, continue
}
// Send the reply via the bot
printJSON(map[string]any{"event": "llm_process_send_start", "msg_id": msg.ID, "to_node_num": msg.FromNodeNum})
if err := s.botSender.SendText(procCtx, msg.BotID, msg.FromNodeNum, reply); err != nil {
errMsg := fmt.Sprintf("failed to send reply: %v", err)
// Send the reply via the bot - 根据消息类型决定发送方式
// 频道消息:回复到原频道;私聊消息:回复给发送节点
var sendErr error
if msg.MessageType == "channel" && msg.ChannelID != nil && *msg.ChannelID != "" {
// 频道消息 - 回复到原频道
printJSON(map[string]any{"event": "llm_process_send_start", "msg_id": msg.ID, "channel_id": *msg.ChannelID, "message_type": "channel"})
sendErr = s.botSender.SendChannelText(procCtx, msg.BotID, *msg.ChannelID, reply)
} else {
// 私聊消息 - 回复给发送节点
printJSON(map[string]any{"event": "llm_process_send_start", "msg_id": msg.ID, "to_node_num": msg.FromNodeNum, "message_type": "direct"})
sendErr = s.botSender.SendDirectText(procCtx, msg.BotID, msg.FromNodeNum, reply)
}
if sendErr != nil {
errMsg := fmt.Sprintf("failed to send reply: %v", sendErr)
printJSON(map[string]any{"event": "llm_process_failed", "msg_id": msg.ID, "step": "send_reply", "error": errMsg})
_ = s.msgQueue.MarkAsFailed(msg.ID, errMsg)
return