Files
kandev/apps/backend/internal/agent/runtime/lifecycle/utility.go
T
2026-05-16 20:07:57 +01:00

106 lines
3.2 KiB
Go

package lifecycle
import (
"context"
"errors"
"fmt"
"github.com/kandev/kandev/internal/agent/agents"
"github.com/kandev/kandev/internal/agentctl/server/utility"
)
// ErrInferenceAgentIDRequired is returned when ExecuteInferencePrompt is called
// without an agent ID. Callers should treat this as a client validation error
// (HTTP 400) rather than a server-side failure.
var ErrInferenceAgentIDRequired = errors.New("agent_id is required")
// ExecuteInferencePrompt executes an inference prompt via an active session's agentctl.
// It looks up the inference config from the agent registry and passes it to agentctl.
func (m *Manager) ExecuteInferencePrompt(ctx context.Context, sessionID, agentID, model, prompt string) (*utility.PromptResponse, error) {
if sessionID == "" {
return nil, fmt.Errorf("session_id is required")
}
if agentID == "" {
return nil, ErrInferenceAgentIDRequired
}
// Get inference agent from registry
ia, ok := m.registry.GetInferenceAgent(agentID)
if !ok {
return nil, fmt.Errorf("agent %q does not support inference", agentID)
}
cfg := ia.InferenceConfig()
if cfg == nil || !cfg.Supported {
return nil, fmt.Errorf("agent %q inference not supported", agentID)
}
// Get or create execution on-demand (survives backend restart)
execution, err := m.GetOrEnsureExecution(ctx, sessionID)
if err != nil {
return nil, fmt.Errorf("no execution available for session %s: %w", sessionID, err)
}
client := execution.GetAgentCtlClient()
if client == nil {
return nil, fmt.Errorf("agentctl client not available for session %s", sessionID)
}
// Build request with inference config
req := &utility.PromptRequest{
Prompt: prompt,
AgentID: agentID,
Model: model,
InferenceConfig: &utility.InferenceConfigDTO{
Command: cfg.Command.Args(),
ModelFlag: cfg.ModelFlag.Args(),
WorkDir: execution.WorkspacePath,
},
}
return client.InferencePrompt(ctx, req)
}
// ListInferenceAgents returns agents that support inference with their models.
// Only returns agents that are actually installed on the system.
func (m *Manager) ListInferenceAgents() []InferenceAgentInfo {
return m.ListInferenceAgentsWithContext(context.Background())
}
// ListInferenceAgentsWithContext returns installed inference agents using the provided context.
func (m *Manager) ListInferenceAgentsWithContext(ctx context.Context) []InferenceAgentInfo {
inferenceAgents := m.registry.ListInferenceAgents()
result := make([]InferenceAgentInfo, 0, len(inferenceAgents))
for _, ia := range inferenceAgents {
// Get base agent for metadata
ag, ok := ia.(agents.Agent)
if !ok {
continue
}
// Only include agents that are installed
installed, err := ag.IsInstalled(ctx)
if err != nil || installed == nil || !installed.Available {
continue
}
result = append(result, InferenceAgentInfo{
ID: ag.ID(),
Name: ag.Name(),
DisplayName: ag.DisplayName(),
})
}
return result
}
// InferenceAgentInfo contains info about an inference-capable agent.
// Models are no longer listed here — consumers should read them from the
// host utility capability cache directly.
type InferenceAgentInfo struct {
ID string `json:"id"`
Name string `json:"name"`
DisplayName string `json:"display_name"`
}