146 lines
5.4 KiB
Go
146 lines
5.4 KiB
Go
// Package engine assembles Promptkit's internal execution components.
|
|
package engine
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net/http"
|
|
"strings"
|
|
"time"
|
|
|
|
openrouter "gitea.maximumdirect.net/eric/promptkit-backend-openrouter"
|
|
rakestrawhome "gitea.maximumdirect.net/eric/promptkit-backend-rakestrawhome"
|
|
"gitea.maximumdirect.net/eric/promptkit/internal/artifact"
|
|
"gitea.maximumdirect.net/eric/promptkit/internal/backend"
|
|
"gitea.maximumdirect.net/eric/promptkit/internal/capacity"
|
|
"gitea.maximumdirect.net/eric/promptkit/internal/catalog"
|
|
"gitea.maximumdirect.net/eric/promptkit/internal/defaults"
|
|
"gitea.maximumdirect.net/eric/promptkit/internal/domain"
|
|
"gitea.maximumdirect.net/eric/promptkit/internal/llm"
|
|
"gitea.maximumdirect.net/eric/promptkit/internal/profile"
|
|
"gitea.maximumdirect.net/eric/promptkit/internal/prompt"
|
|
"gitea.maximumdirect.net/eric/promptkit/internal/promptdef"
|
|
"gitea.maximumdirect.net/eric/promptkit/internal/usecase"
|
|
"gitea.maximumdirect.net/eric/promptkit/internal/validate"
|
|
)
|
|
|
|
// Config carries construction settings selected by the public facade.
|
|
type Config struct {
|
|
PromptDir string
|
|
ProfileDir string
|
|
SchemaDir string
|
|
Timeout time.Duration
|
|
HTTPClient *http.Client
|
|
}
|
|
|
|
// Options carries collaborators prepared by the public facade during the
|
|
// transitional composition split.
|
|
type Options struct {
|
|
LLMClient llm.Client
|
|
ArtifactReader artifact.Reader
|
|
PromptDefinitions promptdef.Repository
|
|
Profiles profile.Repository
|
|
FallbackProfiles profile.Repository
|
|
MemoryProfiles profile.Repository
|
|
Backends []domain.Backend
|
|
Validator validate.Validator
|
|
PromptSource bool
|
|
ProfileSource bool
|
|
FallbackProfileSource bool
|
|
MemorySource bool
|
|
ValidatorSource bool
|
|
ArtifactSource bool
|
|
}
|
|
|
|
// Engine forwards domain operations to the single assembled use-case runner.
|
|
type Engine struct {
|
|
runner *usecase.Runner
|
|
}
|
|
|
|
// New assembles an engine from facade-selected configuration and collaborators.
|
|
func New(cfg Config, options Options) (*Engine, error) {
|
|
promptDefinitions := options.PromptDefinitions
|
|
if !options.PromptSource {
|
|
if strings.TrimSpace(cfg.PromptDir) == "" {
|
|
return nil, fmt.Errorf("prompt directory is required")
|
|
}
|
|
promptDefinitions = promptdef.NewFilesystemRepository(cfg.PromptDir)
|
|
}
|
|
|
|
maintained, err := catalog.Load(
|
|
catalog.Source{Name: "OpenRouter", ExpectedBackendID: backend.OpenRouterID, FS: openrouter.FS(), Root: openrouter.Root},
|
|
catalog.Source{Name: "Rakestrawhome", ExpectedBackendID: backend.RakestrawHomeID, FS: rakestrawhome.FS(), Root: rakestrawhome.Root},
|
|
)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to load maintained catalogs: %w", err)
|
|
}
|
|
|
|
profiles := newProfileRepository(cfg.ProfileDir, options, maintained.Profiles)
|
|
registry, err := backend.NewRegistry(maintained.Backends, options.Backends)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to construct backend registry: %w", err)
|
|
}
|
|
manager, err := capacity.NewManager(registry.CapacityPolicies())
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to construct backend capacity manager: %w", err)
|
|
}
|
|
|
|
validator := options.Validator
|
|
if !options.ValidatorSource {
|
|
schemaDir := cfg.SchemaDir
|
|
if strings.TrimSpace(schemaDir) == "" {
|
|
schemaDir = defaults.SchemaDirDefault
|
|
}
|
|
validator = validate.NewStandardValidator(schemaDir)
|
|
}
|
|
client := options.LLMClient
|
|
if client == nil {
|
|
client, err = llm.NewOpenAICompatibleClient(llm.OpenAICompatibleConfig{Timeout: cfg.Timeout, HTTPClient: cfg.HTTPClient})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
client = capacity.NewClient(manager, client)
|
|
reader := options.ArtifactReader
|
|
if !options.ArtifactSource {
|
|
reader = artifact.NewCompositeReader()
|
|
}
|
|
|
|
return &Engine{runner: usecase.NewRunnerWithRepairer(promptDefinitions, profiles, registry, reader, prompt.NewGoRenderer(), client, validator, usecase.NewDefaultOutputRepairer(client), manager)}, nil
|
|
}
|
|
|
|
func newProfileRepository(profileDir string, options Options, maintained profile.Repository) profile.Repository {
|
|
repository := maintained
|
|
if options.FallbackProfileSource {
|
|
repository = profile.NewOverlayRepository(options.FallbackProfiles, repository)
|
|
}
|
|
if options.ProfileSource {
|
|
repository = profile.NewOverlayRepository(options.Profiles, repository)
|
|
} else if strings.TrimSpace(profileDir) != "" {
|
|
repository = profile.NewOverlayRepository(profile.NewFilesystemRepository(profileDir), repository)
|
|
}
|
|
if options.MemorySource {
|
|
repository = profile.NewOverlayRepository(options.MemoryProfiles, repository)
|
|
}
|
|
return profile.NewResolvingRepository(repository)
|
|
}
|
|
|
|
func (e *Engine) InspectPrompt(ctx context.Context, id, version string) (*domain.PromptInspection, error) {
|
|
return e.runner.InspectPrompt(ctx, id, version)
|
|
}
|
|
func (e *Engine) InspectProfile(ctx context.Context, id string) (*domain.ProfileInspection, error) {
|
|
return e.runner.InspectProfile(ctx, id)
|
|
}
|
|
func (e *Engine) Prepare(ctx context.Context, request domain.RunRequest) (*domain.PreparedRun, error) {
|
|
return e.runner.Prepare(ctx, request)
|
|
}
|
|
func (e *Engine) PrepareExecution(ctx context.Context, request domain.RunRequest) (*usecase.PreparedExecution, error) {
|
|
return e.runner.PrepareExecution(ctx, request)
|
|
}
|
|
func (e *Engine) Run(ctx context.Context, request domain.RunRequest) (*domain.RunResult, error) {
|
|
return e.runner.Run(ctx, request)
|
|
}
|
|
func (e *Engine) RunPrepared(ctx context.Context, prepared *usecase.PreparedExecution) (*domain.RunResult, error) {
|
|
return e.runner.RunPrepared(ctx, prepared)
|
|
}
|