Files
agents_and_robots/shell/orchestration/evaluator.go
T
egutierrez 2667af52cc feat: implement multi-bot orchestration system with LLM routing
Implementa el sistema de orquestación para salas Matrix con múltiples bots.
El orquestador es un "special agent" sin identidad Matrix que coordina qué bot
responde y cuándo, usando LLM (Claude) para routing y evaluación de calidad.

Cambios principales:
- pkg/orchestration/task.go: tipos puros (TaskEvent, BotResponse, QualityScore, RoutingDecision)
- shell/orchestration/: runtime del orquestador (orchestrator.go, router.go, evaluator.go)
- agents/specials/orchestrator/: config + prompts (routing, quality, refinement)
- internal/config/: SpecialConfig, OrchestrationCfg, LoadSpecial()
- shell/bus/bus.go: protocolo request-reply (SendAndWait, Reply) para delegación
- shell/matrix/listener.go: InterceptFunc para interceptar eventos en salas orquestadas
- agents/runtime.go: SetBus, listenBus, handleTaskEvent para recibir tareas del orquestador
- cmd/launcher/main.go: creación de bus compartido, arranque del orquestador antes de bots

Incluye deduplicación para evitar que múltiples listeners en la misma sala
disparen el orquestador más de una vez por mensaje.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 09:05:42 +00:00

49 lines
1.5 KiB
Go

package orchestration
import (
"context"
"encoding/json"
"fmt"
"strings"
coretypes "github.com/enmanuel/agents/pkg/llm"
"github.com/enmanuel/agents/pkg/orchestration"
)
// evaluate asks the LLM to score the quality of a bot's response.
func (o *Orchestrator) evaluate(ctx context.Context, question string, response orchestration.BotResponse) orchestration.QualityScore {
userContent := fmt.Sprintf("Question: %s\n\nResponse from %s:\n%s", question, response.BotID, response.Text)
resp, err := o.llm(ctx, coretypes.CompletionRequest{
Model: o.cfg.LLM.Primary.Model,
MaxTokens: o.cfg.LLM.Primary.MaxTokens,
Temperature: o.cfg.LLM.Primary.Temperature,
SystemPrompt: o.qualityPrompt,
Messages: []coretypes.Message{
{Role: coretypes.RoleUser, Content: userContent},
},
})
if err != nil {
o.logger.Error("quality evaluation LLM call failed", "err", err)
// On LLM failure, assume quality is good enough to stop the pipeline
return orchestration.QualityScore{
Score: 1.0,
Continue: false,
Reason: fmt.Sprintf("evaluation failed: %s, assuming good quality", err),
}
}
var qs orchestration.QualityScore
if err := json.Unmarshal([]byte(strings.TrimSpace(resp.Content)), &qs); err != nil {
o.logger.Warn("failed to parse quality score", "content", resp.Content, "err", err)
// On parse failure, assume good quality
return orchestration.QualityScore{
Score: 1.0,
Continue: false,
Reason: fmt.Sprintf("parse failed: %s", err),
}
}
return qs
}