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 }