package ckprompt import ( "errors" "fmt" commandkit "go.maximumdirect.net/commandkit" ) type concreteRequestInput[I any] struct { namespaces namespaceInput promptID string request ValidationRequest execution ExecutionInput resources ResourceInput inputs PromptInputs captured commandkit.FlagValues[I] selected I } type requestValidationReport struct { PromptID string `json:"prompt_id"` Valid bool `json:"valid"` } func newConcreteRequestSpec[I, S any](suite Suite[I, S]) commandkit.CommandSpec[*concreteRequestInput[I]] { flags := commandkit.CaptureFlags(suite.Selectors, func(input **concreteRequestInput[I]) *commandkit.FlagValues[I] { if input == nil || *input == nil { return nil } return &(*input).captured }) flags = append(flags, commandkit.ValueFlag(commandkit.FlagMeta{Name: "config", Usage: "Configuration input path.", Completion: commandkit.CompleteFiles()}, (*string)(nil), parseDefinitionString, func(input **concreteRequestInput[I], value commandkit.Supplied[string]) { (*input).request.Selection.Config = value }), commandkit.ValueFlag(commandkit.FlagMeta{Name: "overlay", Usage: "Configuration overlay path.", Completion: commandkit.CompleteFiles()}, (*string)(nil), parseDefinitionString, func(input **concreteRequestInput[I], value commandkit.Supplied[string]) { (*input).request.Selection.Overlay = value }), ) resources := NewResourceFlags(func(input **concreteRequestInput[I]) *ResourceInput { return &(*input).resources }) execution := NewExecutionFlags(func(input **concreteRequestInput[I]) *ExecutionInput { return &(*input).execution }) inputs := NewPromptInputFlags(func(input **concreteRequestInput[I]) *PromptInputs { return &(*input).inputs }) flags = append(flags, resources.Profile, resources.SessionID, inputs.Variable, inputs.Text, inputs.File) flags = append(flags, execution.All()...) if suite.namespaces != nil { flags = append(flags, namespaceFlags(func(input **concreteRequestInput[I]) *namespaceInput { return &(*input).namespaces }, "prompt", "profile", "backend")...) } return commandkit.CommandSpec[*concreteRequestInput[I]]{ NewInput: func() *concreteRequestInput[I] { return &concreteRequestInput[I]{} }, Flags: flags, Arguments: []commandkit.Argument[*concreteRequestInput[I]]{ commandkit.ValueArgument(commandkit.ArgumentMeta{Name: "id", Usage: "Prompt ID."}, true, parseDefinitionString, func(input **concreteRequestInput[I], value commandkit.Supplied[string]) { (*input).promptID = value.Value (*input).request.Request.PromptID = value.Value }), }, CheckInput: func(input *concreteRequestInput[I]) error { if input == nil { return errors.New("PromptKit request input must not be nil") } input.request.Namespaces = selectedNamespaces(suite.namespaces, input.namespaces) input.request.Request.ProfileID = input.resources.Profile.Value input.request.Request.SessionID = input.resources.SessionID.Value input.request.Request.Vars = input.inputs.Vars input.request.Request.Inputs = input.inputs.Inputs input.request.Request.Execution = input.execution.Execution input.request.Request.TransientRetries = input.execution.TransientRetries selected, err := prepareSuiteInput(suite, input.request.Selection, input.captured) if err != nil { return err } input.selected = selected return nil }, } } func newValidationCommand[I, S any](suite Suite[I, S]) commandkit.Command { spec := newConcreteRequestSpec(suite) spec.Name = "validate" spec.Summary = "Validate a concrete PromptKit request without executing it." spec.Run = func(invocation commandkit.Invocation, input *concreteRequestInput[I]) commandkit.Outcome { return runRequestValidation(invocation, suite, input) } return commandkit.NewCommand(spec) } func runRequestValidation[I, S any](invocation commandkit.Invocation, suite Suite[I, S], input *concreteRequestInput[I]) commandkit.Outcome { if err := promptKitContextError(invocation.Context); err != nil { return definitionFailure("PromptKit request validation was canceled.", commandkit.Explanation{}, err) } var state S if suite.NewState != nil { state = suite.NewState() } if err := promptKitContextError(invocation.Context); err != nil { return definitionFailure("PromptKit request validation was canceled.", commandkit.Explanation{}, err) } acquired, err := suite.ValidateRequest(invocation.Context, input.request, input.selected, state) queuePromptDiagnostics(invocation.Reporter(), acquired.Diagnostics) if err != nil { return definitionFailure(fmt.Sprintf("Unable to validate the PromptKit request for prompt %q.", input.promptID), acquired.Explanation, err) } if err := promptKitContextError(invocation.Context); err != nil { return definitionFailure(fmt.Sprintf("Validation of the PromptKit request for prompt %q was canceled.", input.promptID), acquired.Explanation, err) } _ = invocation.Reporter().Report(commandkit.Report{Value: requestValidationReport{PromptID: input.promptID, Valid: true}}) return commandkit.Success() }