137 lines
3.3 KiB
Go
137 lines
3.3 KiB
Go
package tool
|
||
|
||
import (
|
||
"context"
|
||
"fmt"
|
||
"io"
|
||
|
||
"github.com/orca/orca/pkg/bus"
|
||
)
|
||
|
||
type AgentStreamWriter struct {
|
||
agentName string
|
||
eventBus bus.MessageBus
|
||
}
|
||
|
||
func (w *AgentStreamWriter) Write(p []byte) (n int, err error) {
|
||
if w.eventBus != nil {
|
||
w.eventBus.Publish("agent_events", bus.Message{
|
||
Type: bus.MsgTypeLog,
|
||
Content: map[string]interface{}{
|
||
"event": "token",
|
||
"agent": w.agentName,
|
||
"text": string(p),
|
||
},
|
||
})
|
||
}
|
||
return len(p), nil
|
||
}
|
||
|
||
type Agent interface {
|
||
Process(ctx context.Context, msg bus.Message) (bus.Message, error)
|
||
}
|
||
|
||
type agentCallTool struct {
|
||
agentRegistry func(string) (Agent, bool)
|
||
eventBus bus.MessageBus
|
||
}
|
||
|
||
func NewAgentCallTool(registry func(string) (Agent, bool)) Tool {
|
||
return &agentCallTool{agentRegistry: registry}
|
||
}
|
||
|
||
func (t *agentCallTool) SetEventBus(mb bus.MessageBus) {
|
||
t.eventBus = mb
|
||
}
|
||
|
||
func (t *agentCallTool) Name() string { return "agent_call" }
|
||
|
||
func (t *agentCallTool) Description() string {
|
||
return "调用其他专业Agent来协助完成任务。当你需要特定领域的专业知识时,使用此工具委托给专门的Agent处理。"
|
||
}
|
||
|
||
func (t *agentCallTool) Parameters() map[string]ParameterSchema {
|
||
return map[string]ParameterSchema{
|
||
"agent": {
|
||
Type: "string",
|
||
Description: "要调用的Agent名称(如 coder, reviewer, designer)",
|
||
Required: true,
|
||
},
|
||
"task": {
|
||
Type: "string",
|
||
Description: "要委托给该Agent处理的具体任务描述",
|
||
Required: true,
|
||
},
|
||
}
|
||
}
|
||
|
||
func (t *agentCallTool) Execute(ctx context.Context, args map[string]interface{}) (*Result, error) {
|
||
agentName, ok := args["agent"].(string)
|
||
if !ok || agentName == "" {
|
||
return ErrorResult("'agent' argument is required and must be a string"), nil
|
||
}
|
||
|
||
task, ok := args["task"].(string)
|
||
if !ok || task == "" {
|
||
return ErrorResult("'task' argument is required and must be a string"), nil
|
||
}
|
||
|
||
agent, ok := t.agentRegistry(agentName)
|
||
if !ok {
|
||
return ErrorResult(fmt.Sprintf("agent '%s' not found", agentName)), nil
|
||
}
|
||
|
||
msg := bus.Message{
|
||
Type: bus.MsgTypeTaskRequest,
|
||
From: "llm",
|
||
To: agentName,
|
||
Content: task,
|
||
}
|
||
|
||
if t.eventBus != nil {
|
||
t.eventBus.Publish("agent_events", bus.Message{
|
||
Type: bus.MsgTypeToolCall,
|
||
From: "llm",
|
||
To: agentName,
|
||
Content: map[string]interface{}{"event": "start", "agent": agentName, "task": task},
|
||
})
|
||
}
|
||
|
||
if setter, ok := agent.(interface{ SetStreamWriter(io.Writer) }); ok && t.eventBus != nil {
|
||
writer := &AgentStreamWriter{agentName: agentName, eventBus: t.eventBus}
|
||
setter.SetStreamWriter(writer)
|
||
}
|
||
|
||
resp, err := agent.Process(ctx, msg)
|
||
|
||
if t.eventBus != nil {
|
||
status := "completed"
|
||
if err != nil {
|
||
status = "failed"
|
||
}
|
||
resultContent := ""
|
||
if resp.Content != nil {
|
||
resultContent = fmt.Sprintf("%v", resp.Content)
|
||
}
|
||
t.eventBus.Publish("agent_events", bus.Message{
|
||
Type: bus.MsgTypeToolResult,
|
||
From: agentName,
|
||
To: "llm",
|
||
Content: map[string]interface{}{"event": "end", "agent": agentName, "status": status, "result": resultContent},
|
||
})
|
||
}
|
||
|
||
if err != nil {
|
||
return ErrorResult(fmt.Sprintf("agent '%s' execution failed: %v", agentName, err)), nil
|
||
}
|
||
|
||
return &Result{
|
||
Success: true,
|
||
Data: map[string]interface{}{
|
||
"agent": agentName,
|
||
"result": resp.Content,
|
||
"metadata": resp.Metadata,
|
||
},
|
||
}, nil
|
||
}
|