mirror of
https://github.com/YspCoder/clawgo.git
synced 2026-04-13 14:27:32 +08:00
feat: implement full recursive multi-agent system in ClawGo
This commit is contained in:
@@ -86,7 +86,7 @@ func NewAgentLoop(cfg *config.Config, msgBus *bus.MessageBus, provider providers
|
||||
|
||||
sessionsManager := session.NewSessionManager(filepath.Join(filepath.Dir(cfg.WorkspacePath()), "sessions"))
|
||||
|
||||
return &AgentLoop{
|
||||
loop := &AgentLoop{
|
||||
bus: msgBus,
|
||||
provider: provider,
|
||||
workspace: workspace,
|
||||
@@ -97,6 +97,14 @@ func NewAgentLoop(cfg *config.Config, msgBus *bus.MessageBus, provider providers
|
||||
tools: toolsRegistry,
|
||||
running: false,
|
||||
}
|
||||
|
||||
// 注入递归运行逻辑,使 subagent 具备 full tool-calling 能力
|
||||
subagentManager.SetRunFunc(func(ctx context.Context, task, channel, chatID string) (string, error) {
|
||||
sessionKey := fmt.Sprintf("subagent:%d", time.Now().UnixNano())
|
||||
return loop.ProcessDirect(ctx, task, sessionKey)
|
||||
})
|
||||
|
||||
return loop
|
||||
}
|
||||
|
||||
func (al *AgentLoop) Run(ctx context.Context) error {
|
||||
|
||||
@@ -28,6 +28,7 @@ type SubagentManager struct {
|
||||
bus *bus.MessageBus
|
||||
workspace string
|
||||
nextID int
|
||||
runFunc SubagentRunFunc
|
||||
}
|
||||
|
||||
func NewSubagentManager(provider providers.LLMProvider, workspace string, bus *bus.MessageBus) *SubagentManager {
|
||||
@@ -70,45 +71,74 @@ func (sm *SubagentManager) runTask(ctx context.Context, task *SubagentTask) {
|
||||
task.Status = "running"
|
||||
task.Created = time.Now().UnixMilli()
|
||||
|
||||
messages := []providers.Message{
|
||||
{
|
||||
Role: "system",
|
||||
Content: "You are a subagent. Complete the given task independently and report the result.",
|
||||
},
|
||||
{
|
||||
Role: "user",
|
||||
Content: task.Task,
|
||||
},
|
||||
}
|
||||
|
||||
response, err := sm.provider.Chat(ctx, messages, nil, sm.provider.GetDefaultModel(), map[string]interface{}{
|
||||
"max_tokens": 4096,
|
||||
})
|
||||
|
||||
sm.mu.Lock()
|
||||
defer sm.mu.Unlock()
|
||||
|
||||
if err != nil {
|
||||
task.Status = "failed"
|
||||
task.Result = fmt.Sprintf("Error: %v", err)
|
||||
// 1. 独立 Agent 逻辑:支持递归工具调用
|
||||
// 这里简单实现:通过共享 AgentLoop 的逻辑来实现 full subagent 能力
|
||||
// 但目前 subagent.go 不方便反向依赖 agent 包,我们暂时通过 Inject 方式解决
|
||||
|
||||
// 如果没有注入 RunFunc,则退化为简单的一步 Chat
|
||||
if sm.runFunc != nil {
|
||||
result, err := sm.runFunc(ctx, task.Task, task.OriginChannel, task.OriginChatID)
|
||||
sm.mu.Lock()
|
||||
if err != nil {
|
||||
task.Status = "failed"
|
||||
task.Result = fmt.Sprintf("Error: %v", err)
|
||||
} else {
|
||||
task.Status = "completed"
|
||||
task.Result = result
|
||||
}
|
||||
sm.mu.Unlock()
|
||||
} else {
|
||||
task.Status = "completed"
|
||||
task.Result = response.Content
|
||||
// 原有的 One-shot 逻辑
|
||||
messages := []providers.Message{
|
||||
{
|
||||
Role: "system",
|
||||
Content: "You are a subagent. Complete the given task independently and report the result.",
|
||||
},
|
||||
{
|
||||
Role: "user",
|
||||
Content: task.Task,
|
||||
},
|
||||
}
|
||||
|
||||
response, err := sm.provider.Chat(ctx, messages, nil, sm.provider.GetDefaultModel(), map[string]interface{}{
|
||||
"max_tokens": 4096,
|
||||
})
|
||||
|
||||
sm.mu.Lock()
|
||||
if err != nil {
|
||||
task.Status = "failed"
|
||||
task.Result = fmt.Sprintf("Error: %v", err)
|
||||
} else {
|
||||
task.Status = "completed"
|
||||
task.Result = response.Content
|
||||
}
|
||||
sm.mu.Unlock()
|
||||
}
|
||||
|
||||
// Send announce message back to main agent
|
||||
// 2. 结果广播 (原有逻辑保持)
|
||||
if sm.bus != nil {
|
||||
announceContent := fmt.Sprintf("Task '%s' completed.\n\nResult:\n%s", task.Label, task.Result)
|
||||
prefix := "Task completed"
|
||||
if task.Label != "" {
|
||||
prefix = fmt.Sprintf("Task '%s' completed", task.Label)
|
||||
}
|
||||
announceContent := fmt.Sprintf("%s.\n\nResult:\n%s", prefix, task.Result)
|
||||
sm.bus.PublishInbound(bus.InboundMessage{
|
||||
Channel: "system",
|
||||
SenderID: fmt.Sprintf("subagent:%s", task.ID),
|
||||
// Format: "original_channel:original_chat_id" for routing back
|
||||
ChatID: fmt.Sprintf("%s:%s", task.OriginChannel, task.OriginChatID),
|
||||
Content: announceContent,
|
||||
ChatID: fmt.Sprintf("%s:%s", task.OriginChannel, task.OriginChatID),
|
||||
Content: announceContent,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type SubagentRunFunc func(ctx context.Context, task, channel, chatID string) (string, error)
|
||||
|
||||
func (sm *SubagentManager) SetRunFunc(f SubagentRunFunc) {
|
||||
sm.mu.Lock()
|
||||
defer sm.mu.Unlock()
|
||||
sm.runFunc = f
|
||||
}
|
||||
|
||||
func (sm *SubagentManager) GetTask(taskID string) (*SubagentTask, bool) {
|
||||
sm.mu.RLock()
|
||||
defer sm.mu.RUnlock()
|
||||
|
||||
Reference in New Issue
Block a user