147 lines
4.3 KiB
Go
147 lines
4.3 KiB
Go
package llm
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"gitea.maximumdirect.net/eric/promptkit"
|
|
)
|
|
|
|
type PromptKitProfileSourceConfig struct {
|
|
ProfileDir string
|
|
ProfileFile string
|
|
LocalBackend *PromptKitLocalBackendConfig
|
|
}
|
|
|
|
type PromptKitProfileInspectorConfig struct {
|
|
Source PromptKitProfileSourceConfig
|
|
Assets *AssetRegistry
|
|
}
|
|
|
|
func (c PromptKitProfileSourceConfig) localEndpoint() string {
|
|
if c.LocalBackend == nil {
|
|
return ""
|
|
}
|
|
return c.LocalBackend.Endpoint
|
|
}
|
|
|
|
type PromptKitProfileInspector struct {
|
|
engine *promptkit.Engine
|
|
}
|
|
|
|
type PromptKitProfileInspection struct {
|
|
ProfileID string
|
|
BackendID string
|
|
Model string
|
|
CredentialEnvironment string
|
|
CredentialRequired bool
|
|
}
|
|
|
|
type PromptKitProfileInspectionError struct {
|
|
ProfileID string
|
|
err error
|
|
}
|
|
|
|
func (e *PromptKitProfileInspectionError) Error() string {
|
|
switch {
|
|
case errors.Is(e.err, promptkit.ErrProfileNotFound):
|
|
return fmt.Sprintf("PromptKit profile %q is not configured", e.ProfileID)
|
|
case errors.Is(e.err, promptkit.ErrInvalidRequest):
|
|
return fmt.Sprintf("PromptKit profile ID %q is invalid", e.ProfileID)
|
|
case errors.Is(e.err, promptkit.ErrProfileLoad):
|
|
return fmt.Sprintf("PromptKit profile %q is invalid or unreadable", e.ProfileID)
|
|
default:
|
|
return fmt.Sprintf("PromptKit profile %q could not be inspected", e.ProfileID)
|
|
}
|
|
}
|
|
|
|
func (e *PromptKitProfileInspectionError) Unwrap() error {
|
|
return e.err
|
|
}
|
|
|
|
type promptKitProfileConfigurationError struct {
|
|
err error
|
|
}
|
|
|
|
func (e *promptKitProfileConfigurationError) Error() string {
|
|
return "PromptKit profile configuration is invalid or unreadable"
|
|
}
|
|
|
|
func (e *promptKitProfileConfigurationError) Unwrap() error {
|
|
return e.err
|
|
}
|
|
|
|
func NewPromptKitProfileInspector(cfg PromptKitProfileInspectorConfig) (*PromptKitProfileInspector, error) {
|
|
source, options, err := promptKitProfileSourceEngineOptions(cfg.Source)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if cfg.Assets != nil {
|
|
fallbackOption, hasFallback, err := cfg.Assets.promptKitFallbackProfileOption()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if hasFallback {
|
|
options = append(options, fallbackOption)
|
|
}
|
|
}
|
|
engine, err := promptkit.NewEngine(promptkit.Config{
|
|
PromptDir: ".",
|
|
ProfileDir: source.ProfileDir,
|
|
}, options...)
|
|
if err != nil {
|
|
return nil, &promptKitProfileConfigurationError{err: err}
|
|
}
|
|
return &PromptKitProfileInspector{engine: engine}, nil
|
|
}
|
|
|
|
func (i *PromptKitProfileInspector) InspectProfile(ctx context.Context, profileID string) (PromptKitProfileInspection, error) {
|
|
if i == nil || i.engine == nil {
|
|
return PromptKitProfileInspection{}, fmt.Errorf("PromptKit profile inspector must not be nil")
|
|
}
|
|
profileID = strings.TrimSpace(profileID)
|
|
inspection, err := i.engine.InspectProfile(ctx, profileID)
|
|
if err != nil {
|
|
if ctxErr := ctx.Err(); ctxErr != nil {
|
|
return PromptKitProfileInspection{}, ctxErr
|
|
}
|
|
return PromptKitProfileInspection{}, &PromptKitProfileInspectionError{
|
|
ProfileID: profileID,
|
|
err: err,
|
|
}
|
|
}
|
|
return PromptKitProfileInspection{
|
|
ProfileID: inspection.ProfileID,
|
|
BackendID: strings.TrimSpace(inspection.EffectiveModelParams.BackendID),
|
|
Model: strings.TrimSpace(inspection.EffectiveModelParams.Model),
|
|
CredentialEnvironment: strings.TrimSpace(inspection.EffectiveModelParams.APIKeyEnv),
|
|
CredentialRequired: inspection.APIKeyRequired,
|
|
}, nil
|
|
}
|
|
|
|
func promptKitProfileSourceEngineOptions(cfg PromptKitProfileSourceConfig) (PromptKitProfileSourceConfig, []promptkit.Option, error) {
|
|
source := PromptKitProfileSourceConfig{
|
|
ProfileDir: strings.TrimSpace(cfg.ProfileDir),
|
|
ProfileFile: strings.TrimSpace(cfg.ProfileFile),
|
|
}
|
|
if source.ProfileDir != "" && source.ProfileFile != "" {
|
|
return PromptKitProfileSourceConfig{}, nil, fmt.Errorf("PromptKit profile_dir and profile_file are mutually exclusive")
|
|
}
|
|
if cfg.LocalBackend != nil {
|
|
localBackend := *cfg.LocalBackend
|
|
localBackend.Endpoint = strings.TrimSpace(localBackend.Endpoint)
|
|
source.LocalBackend = &localBackend
|
|
}
|
|
|
|
var options []promptkit.Option
|
|
if source.ProfileFile != "" {
|
|
options = append(options, promptkit.WithProfileFile(source.ProfileFile))
|
|
}
|
|
if source.LocalBackend != nil {
|
|
options = append(options, PromptKitLocalBackendOption(*source.LocalBackend))
|
|
}
|
|
return source, options, nil
|
|
}
|