111 lines
4.3 KiB
Go
111 lines
4.3 KiB
Go
package cli
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net/http"
|
|
"reflect"
|
|
"strings"
|
|
|
|
"gitea.maximumdirect.net/eric/audita/v3/internal/core/config"
|
|
"gitea.maximumdirect.net/eric/audita/v3/internal/framework/llm"
|
|
"gitea.maximumdirect.net/eric/audita/v3/internal/prompts"
|
|
"go.maximumdirect.net/ckconfig"
|
|
"go.maximumdirect.net/ckprompt"
|
|
commandkit "go.maximumdirect.net/commandkit"
|
|
ck "go.maximumdirect.net/configkit"
|
|
pk "go.maximumdirect.net/promptkit"
|
|
"go.maximumdirect.net/releasekit/buildinfo"
|
|
)
|
|
|
|
type invocationState struct {
|
|
engines []engineEntry
|
|
client *http.Client
|
|
}
|
|
type engineEntry struct {
|
|
selection ckconfig.Selection
|
|
engine *pk.Engine
|
|
}
|
|
|
|
func loadApplication(ctx context.Context, selection ckconfig.Selection, _ struct{}, _ *invocationState) (*ck.Result[config.Config], error) {
|
|
if err := ctx.Err(); err != nil {
|
|
return nil, err
|
|
}
|
|
var source ck.Source
|
|
if selection.Config.Set {
|
|
if strings.TrimSpace(selection.Config.Value) == "" {
|
|
return nil, fmt.Errorf("--config requires a nonempty path")
|
|
}
|
|
source = ck.File(selection.Config.Value)
|
|
} else {
|
|
source = ck.SearchConfig("audita", ck.Searches(ck.WorkingDirectory(), ck.UserConfigDirectory(), ck.UnixSystemDirectories()))
|
|
}
|
|
return config.Load(ck.Input{Source: source}, selection.Overlay.Value, selection.Overrides...)
|
|
}
|
|
|
|
func loadPromptEngine(ctx context.Context, selection ckconfig.Selection, input struct{}, state *invocationState) (*pk.Engine, error) {
|
|
loaded, err := loadApplication(ctx, selection, input, state)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var client *http.Client
|
|
if state != nil {
|
|
client = state.client
|
|
}
|
|
return llm.NewEngine(ctx, loaded, client)
|
|
}
|
|
|
|
func capturePromptEngine(ctx context.Context, selection ckconfig.Selection, input struct{}, state *invocationState) (*pk.Engine, error) {
|
|
if state != nil {
|
|
for _, entry := range state.engines {
|
|
if reflect.DeepEqual(entry.selection, selection) {
|
|
return entry.engine, nil
|
|
}
|
|
}
|
|
}
|
|
engine, err := loadPromptEngine(ctx, selection, input, state)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if state != nil {
|
|
state.engines = append(state.engines, engineEntry{selection: selection, engine: engine})
|
|
}
|
|
return engine, nil
|
|
}
|
|
|
|
func buildApplication(extra ...commandkit.Declaration) (*commandkit.App, error) {
|
|
return buildApplicationWithClient(nil, extra...)
|
|
}
|
|
|
|
func buildApplicationWithClient(client *http.Client, extra ...commandkit.Declaration) (*commandkit.App, error) {
|
|
appScope := ckconfig.FromConfigKit("app", "Audita application settings.", loadApplication)
|
|
appScope.Features.Overrides = true
|
|
promptScope := ckprompt.ConfigScope(loadPromptEngine)
|
|
configCommand := ckconfig.Command(ckconfig.Suite[struct{}, *invocationState]{NewState: func() *invocationState { return &invocationState{client: client} }, Scopes: []ckconfig.Scope[struct{}, *invocationState]{appScope, promptScope}})
|
|
definitions := ckprompt.WithNamespaces(ckprompt.FromEngine(capturePromptEngine), pk.Namespaces{})
|
|
definitions.NewState = func() *invocationState { return &invocationState{client: client} }
|
|
definitions = ckprompt.WithRequestValidation(definitions, capturePromptEngine, func(_ context.Context, seed ckprompt.ValidationRequest, _ struct{}, _ *invocationState) (pk.RunRequest, error) {
|
|
return applicationPromptRequest(seed.Request, seed.Namespaces), nil
|
|
})
|
|
definitions = ckprompt.WithRequestPreparation(definitions, capturePromptEngine, func(_ context.Context, seed ckprompt.PreparationRequest, _ struct{}, _ *invocationState) (pk.RunRequest, error) {
|
|
return applicationPromptRequest(seed.Request, seed.Namespaces), nil
|
|
})
|
|
definitions = ckprompt.WithSmokeTesting(definitions, capturePromptEngine, nil)
|
|
declarations := []commandkit.Declaration{configCommand, commandkit.Completion("audita"), processCommand()}
|
|
declarations = append(declarations, ckprompt.Declarations(definitions)...)
|
|
declarations = append(declarations, extra...)
|
|
return commandkit.New(commandkit.Identity{Name: "audita", Version: buildinfo.Version()}, declarations...)
|
|
}
|
|
|
|
// applicationPromptRequest supplies instructions only for Audita's maintained prompts.
|
|
func applicationPromptRequest(request pk.RunRequest, namespaces *pk.Namespaces) pk.RunRequest {
|
|
id := request.PromptID
|
|
if !strings.Contains(id, "/") && namespaces != nil && namespaces.Prompt != "" {
|
|
id = namespaces.Prompt + "/" + id
|
|
}
|
|
if _, ok := prompts.LookupMetadata(id); ok {
|
|
request.Vars = prompts.WithSharedVariables(request.Vars)
|
|
}
|
|
return request
|
|
}
|