2026-11-07 04:19:58 +00:00
|
|
|
package ckprompt
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"context"
|
|
|
|
|
"errors"
|
|
|
|
|
"fmt"
|
|
|
|
|
|
|
|
|
|
"go.maximumdirect.net/ckconfig"
|
|
|
|
|
commandkit "go.maximumdirect.net/commandkit"
|
|
|
|
|
promptkit "go.maximumdirect.net/promptkit"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// PreparationRequest carries the configuration selection and seed native request
|
|
|
|
|
// supplied to preparation callbacks and builders.
|
|
|
|
|
type PreparationRequest struct {
|
|
|
|
|
// Selection identifies the configuration sources used to load the engine.
|
|
|
|
|
Selection ckconfig.Selection
|
|
|
|
|
// Request contains the native seed request populated by command inputs.
|
|
|
|
|
Request promptkit.RunRequest
|
2026-11-07 04:23:39 +00:00
|
|
|
// Namespaces selects the native engine view; nil preserves the loader view.
|
|
|
|
|
Namespaces *promptkit.Namespaces
|
2026-11-07 04:19:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// WithRequestPreparation attaches native prepared-request inspection. The
|
|
|
|
|
// optional builder may replace the complete seed request before engine loading.
|
|
|
|
|
// Preparation may read resources and returns rendered application content; it
|
|
|
|
|
// does not call the model or retain an execution handle.
|
|
|
|
|
func WithRequestPreparation[I, S any](
|
|
|
|
|
suite Suite[I, S],
|
|
|
|
|
load func(context.Context, ckconfig.Selection, I, S) (*promptkit.Engine, error),
|
|
|
|
|
build func(context.Context, PreparationRequest, I, S) (promptkit.RunRequest, error),
|
|
|
|
|
) Suite[I, S] {
|
|
|
|
|
if load == nil {
|
|
|
|
|
issues := append([]error(nil), suite.issues...)
|
|
|
|
|
suite.issues = append(issues, errors.New("PromptKit engine loader is nil"))
|
|
|
|
|
return suite
|
|
|
|
|
}
|
|
|
|
|
suite.PrepareRequest = func(ctx context.Context, request PreparationRequest, input I, state S) (commandkit.Acquired[*promptkit.PreparedRun], error) {
|
|
|
|
|
if err := promptKitContextError(ctx); err != nil {
|
|
|
|
|
return commandkit.Acquired[*promptkit.PreparedRun]{}, fmt.Errorf("PromptKit request preparation before building: %w", err)
|
|
|
|
|
}
|
|
|
|
|
concrete := request.Request
|
|
|
|
|
if build != nil {
|
|
|
|
|
built, err := build(ctx, request, input, state)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return commandkit.Acquired[*promptkit.PreparedRun]{}, err
|
|
|
|
|
}
|
|
|
|
|
concrete = built
|
|
|
|
|
}
|
|
|
|
|
if err := promptKitContextError(ctx); err != nil {
|
|
|
|
|
return commandkit.Acquired[*promptkit.PreparedRun]{}, fmt.Errorf("PromptKit request preparation after building: %w", err)
|
|
|
|
|
}
|
|
|
|
|
engine, _, messages, err := loadPromptKitEngine(ctx, request.Selection, input, state, "", load)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return commandkit.Acquired[*promptkit.PreparedRun]{Diagnostics: messages.diagnostics, Explanation: messages.explanation}, err
|
|
|
|
|
}
|
|
|
|
|
if err := promptKitContextError(ctx); err != nil {
|
|
|
|
|
return commandkit.Acquired[*promptkit.PreparedRun]{Diagnostics: messages.diagnostics, Explanation: messages.explanation}, fmt.Errorf("PromptKit request preparation before native preparation: %w", err)
|
|
|
|
|
}
|
2026-11-07 04:23:39 +00:00
|
|
|
engine, err = namespacedEngine(engine, request.Namespaces)
|
|
|
|
|
if err != nil {
|
|
|
|
|
messages = messages.withOperationError(err)
|
|
|
|
|
return commandkit.Acquired[*promptkit.PreparedRun]{Diagnostics: messages.diagnostics, Explanation: messages.explanation}, err
|
|
|
|
|
}
|
2026-11-07 04:19:58 +00:00
|
|
|
prepared, err := engine.Prepare(ctx, concrete)
|
|
|
|
|
messages = messages.withOperationError(err)
|
|
|
|
|
return commandkit.Acquired[*promptkit.PreparedRun]{Value: prepared, Diagnostics: messages.diagnostics, Explanation: messages.explanation}, err
|
|
|
|
|
}
|
|
|
|
|
return suite
|
|
|
|
|
}
|
|
|
|
|
|
2026-11-07 04:27:28 +00:00
|
|
|
func newPreparationCommand[I, S any](suite Suite[I, S], aliases *[]commandkit.Declaration) commandkit.Command {
|
|
|
|
|
spec := newConcreteRequestSpec(suite, "promptkit show prepared", aliases)
|
2026-11-07 04:19:58 +00:00
|
|
|
spec.Name = "prepared"
|
|
|
|
|
spec.Summary = "Show a prepared PromptKit request without calling the model."
|
|
|
|
|
spec.Description = "Prepares the request using resource I/O and reports rendered application content without calling the model."
|
|
|
|
|
spec.Run = func(invocation commandkit.Invocation, input *concreteRequestInput[I]) commandkit.Outcome {
|
|
|
|
|
return runRequestPreparation(invocation, suite, input)
|
|
|
|
|
}
|
|
|
|
|
return commandkit.NewCommand(spec)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func runRequestPreparation[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 preparation 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 preparation was canceled.", commandkit.Explanation{}, err)
|
|
|
|
|
}
|
2026-11-07 04:23:39 +00:00
|
|
|
request := PreparationRequest{Selection: input.request.Selection, Request: input.request.Request, Namespaces: input.request.Namespaces}
|
2026-11-07 04:19:58 +00:00
|
|
|
acquired, err := suite.PrepareRequest(invocation.Context, request, input.selected, state)
|
|
|
|
|
queuePromptDiagnostics(invocation.Reporter(), acquired.Diagnostics)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return definitionFailure(fmt.Sprintf("Unable to prepare the PromptKit request for prompt %q.", input.promptID), acquired.Explanation, err)
|
|
|
|
|
}
|
|
|
|
|
if err := promptKitContextError(invocation.Context); err != nil {
|
|
|
|
|
return definitionFailure(fmt.Sprintf("Preparation of the PromptKit request for prompt %q was canceled.", input.promptID), acquired.Explanation, err)
|
|
|
|
|
}
|
|
|
|
|
_ = invocation.Reporter().Report(commandkit.Report{Value: acquired.Value})
|
|
|
|
|
return commandkit.Success()
|
|
|
|
|
}
|