133 lines
3.7 KiB
Go
133 lines
3.7 KiB
Go
package usecase
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"gitea.maximumdirect.net/eric/promptkit/internal/domain"
|
|
"gitea.maximumdirect.net/eric/promptkit/internal/jsonvalue"
|
|
)
|
|
|
|
type resolvedProfileSelection struct {
|
|
id string
|
|
profile *domain.ExecutionProfile
|
|
}
|
|
|
|
type profileIdentityRepository interface {
|
|
GetProfileIdentity(context.Context, string) (string, error)
|
|
}
|
|
|
|
func (r *Runner) profileLookupID(profileID string) (string, error) {
|
|
if strings.TrimSpace(profileID) == "" {
|
|
return "", fmt.Errorf("%w: profile id is required", ErrInvalidRequest)
|
|
}
|
|
if r == nil || r.profiles == nil {
|
|
return "", fmt.Errorf("%w: profile repository is not configured", ErrProfileLoad)
|
|
}
|
|
return profileID, nil
|
|
}
|
|
|
|
func (r *Runner) resolveProfileSelection(
|
|
ctx context.Context,
|
|
profileID string,
|
|
) (*resolvedProfileSelection, error) {
|
|
lookupID, err := r.profileLookupID(profileID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
selectedProfile, err := r.profiles.GetProfile(ctx, lookupID)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("%w: %w", ErrProfileLoad, err)
|
|
}
|
|
if selectedProfile == nil {
|
|
return nil, fmt.Errorf("%w: profile repository returned nil profile", ErrProfileLoad)
|
|
}
|
|
|
|
profileValue := *selectedProfile
|
|
if profileValue.ResolvedTarget == nil {
|
|
return nil, fmt.Errorf("%w: profile %q has no resolved target", ErrProfileLoad, lookupID)
|
|
}
|
|
|
|
return &resolvedProfileSelection{
|
|
id: lookupID,
|
|
profile: &profileValue,
|
|
}, nil
|
|
}
|
|
|
|
func (r *Runner) resolveProfileIdentity(ctx context.Context, profileID string) (string, error) {
|
|
lookupID, err := r.profileLookupID(profileID)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
if indexed, ok := r.profiles.(profileIdentityRepository); ok {
|
|
identity, err := indexed.GetProfileIdentity(ctx, lookupID)
|
|
if err != nil {
|
|
return "", fmt.Errorf("%w: %w", ErrProfileLoad, err)
|
|
}
|
|
return identity, nil
|
|
}
|
|
selection, err := r.resolveProfileSelection(ctx, lookupID)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return selection.id, nil
|
|
}
|
|
|
|
func normalizeResolvedExecutionTarget(target domain.ExecutionTarget) (domain.ExecutionTarget, error) {
|
|
target, err := normalizeResolvedExecutionSettings(target)
|
|
if err != nil {
|
|
return domain.ExecutionTarget{}, err
|
|
}
|
|
if strings.TrimSpace(target.Model) == "" {
|
|
return domain.ExecutionTarget{}, errors.New("execution model is required")
|
|
}
|
|
return target, nil
|
|
}
|
|
|
|
func normalizeResolvedExecutionSettings(target domain.ExecutionTarget) (domain.ExecutionTarget, error) {
|
|
endpoint, err := domain.NormalizeOpenAICompatibleBaseEndpoint(target.Endpoint)
|
|
if err != nil {
|
|
return domain.ExecutionTarget{}, fmt.Errorf("execution endpoint: %w", err)
|
|
}
|
|
target.Endpoint = endpoint
|
|
if err := domain.ValidateExecutionTargetSettings(target); err != nil {
|
|
return domain.ExecutionTarget{}, err
|
|
}
|
|
return target, nil
|
|
}
|
|
|
|
// InspectProfile resolves one explicit profile without prompt or execution work.
|
|
func (r *Runner) InspectProfile(
|
|
ctx context.Context,
|
|
profileID string,
|
|
) (*domain.ProfileInspection, error) {
|
|
if strings.TrimSpace(profileID) == "" {
|
|
return nil, fmt.Errorf("%w: profile id is required", ErrInvalidRequest)
|
|
}
|
|
select {
|
|
case <-ctx.Done():
|
|
return nil, fmt.Errorf("%w: %w", ErrProfileLoad, ctx.Err())
|
|
default:
|
|
}
|
|
|
|
selection, err := r.resolveProfileSelection(ctx, profileID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
target, _ := resolveExecutionTarget(selection.profile, nil)
|
|
target.APIKey = ""
|
|
params, err := jsonvalue.CopyMap(target.ExtraParams)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("%w: profile extra parameters: %w", ErrProfileLoad, err)
|
|
}
|
|
target.ExtraParams = params
|
|
|
|
return &domain.ProfileInspection{
|
|
ProfileID: selection.id,
|
|
EffectiveModelParams: target,
|
|
APIKeyRequired: target.APIKeyRequired,
|
|
}, nil
|
|
}
|