Add scoped PromptKit flag aliases
This commit is contained in:
13
docs/cli.md
13
docs/cli.md
@@ -574,6 +574,19 @@ controls the engine view and these flags are unavailable.
|
|||||||
Catalog namespace filters remain separate; configuration inspection has no
|
Catalog namespace filters remain separate; configuration inspection has no
|
||||||
resource namespace selectors.
|
resource namespace selectors.
|
||||||
|
|
||||||
|
### PromptKit convenience aliases
|
||||||
|
|
||||||
|
Applications that install `ckprompt.Declarations(suite)` provide scoped
|
||||||
|
convenience spellings for the enabled PromptKit commands. Each applicable
|
||||||
|
`--llm-NAME` flag also accepts `--NAME`; `--llm-input-text` additionally accepts
|
||||||
|
`--llm-input` and `--input` for literal text. Use `--llm-input-file` or
|
||||||
|
`--input-file` for a file reference. Canonical and alias spellings share the
|
||||||
|
same binding, including their occurrence order and explicit-value semantics.
|
||||||
|
|
||||||
|
Applications that install `ckprompt.Command(suite)` receive the canonical
|
||||||
|
spellings only. The aliases do not apply to application-owned commands unless
|
||||||
|
the application installs them separately.
|
||||||
|
|
||||||
## PromptKit prepared-request preview
|
## PromptKit prepared-request preview
|
||||||
|
|
||||||
When `Suite.PrepareRequest` is present, `ckprompt.Command(suite)` installs
|
When `Suite.PrepareRequest` is present, `ckprompt.Command(suite)` installs
|
||||||
|
|||||||
@@ -265,7 +265,9 @@ prepared-request preview, and smoke testing are separate capabilities, added
|
|||||||
with `ckprompt.WithRequestValidation`, `ckprompt.WithRequestPreparation`, and
|
with `ckprompt.WithRequestValidation`, `ckprompt.WithRequestPreparation`, and
|
||||||
`ckprompt.WithSmokeTesting`. The suite has twelve independently optional
|
`ckprompt.WithSmokeTesting`. The suite has twelve independently optional
|
||||||
callbacks in total. `ckprompt.Command(suite)` creates only operations whose
|
callbacks in total. `ckprompt.Command(suite)` creates only operations whose
|
||||||
callbacks are present; these capabilities can be installed independently. A
|
callbacks are present, with canonical flags. `ckprompt.Declarations(suite)`
|
||||||
|
returns the command and its scoped convenience aliases for installation with
|
||||||
|
other declarations. These capabilities can be installed independently. A
|
||||||
composed suite can enable the additional operations:
|
composed suite can enable the additional operations:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Shared reporting and PromptKit v0.20.0 implementation plan
|
# Shared reporting and PromptKit v0.20.0 implementation plan
|
||||||
|
|
||||||
Status: implementation in progress; Stages 1–12 complete.
|
Status: implementation in progress; Stages 1–13 complete.
|
||||||
|
|
||||||
## Scope, authority, and execution
|
## Scope, authority, and execution
|
||||||
|
|
||||||
@@ -466,6 +466,11 @@ namespace membership or requirements-analysis correctness.
|
|||||||
|
|
||||||
## Stage 13: Generated scoped aliases and complete-family installation
|
## Stage 13: Generated scoped aliases and complete-family installation
|
||||||
|
|
||||||
|
**Complete.** `Declarations` generates aliases from each command's selected
|
||||||
|
bindings; `Command` remains canonical-only. The root, ckconfig, and ckprompt
|
||||||
|
workspace suites passed with Go 1.27.0, including alias routing, occurrence
|
||||||
|
order, optional commands, help, completion, and conflict checks.
|
||||||
|
|
||||||
Add `Declarations(suite) []commandkit.Declaration`, assembling the canonical
|
Add `Declarations(suite) []commandkit.Declaration`, assembling the canonical
|
||||||
family and generated exact-command `FlagAliasFor` rules. Retain `Command(suite)`
|
family and generated exact-command `FlagAliasFor` rules. Retain `Command(suite)`
|
||||||
for canonical-only installation. Generate aliases from the selected flags and
|
for canonical-only installation. Generate aliases from the selected flags and
|
||||||
|
|||||||
@@ -63,6 +63,10 @@ type inputAssignment struct {
|
|||||||
// Named resource inspections return native reports through shared formatting.
|
// Named resource inspections return native reports through shared formatting.
|
||||||
// Catalog commands accept config/overlay selection and suite selectors.
|
// Catalog commands accept config/overlay selection and suite selectors.
|
||||||
func Command[I, S any](suite Suite[I, S]) commandkit.Command {
|
func Command[I, S any](suite Suite[I, S]) commandkit.Command {
|
||||||
|
return buildCommand(suite, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildCommand[I, S any](suite Suite[I, S], aliases *[]commandkit.Declaration) commandkit.Command {
|
||||||
if suite.InspectPrompt == nil && suite.InspectProfile == nil && suite.InspectBackend == nil && suite.InspectRequirements == nil && suite.ValidateRequest == nil && suite.PrepareRequest == nil && suite.SmokeTest == nil && suite.ListPrompts == nil && suite.ListProfiles == nil && suite.ListBackends == nil && suite.ListNamespaces == nil && suite.ListCollections == nil {
|
if suite.InspectPrompt == nil && suite.InspectProfile == nil && suite.InspectBackend == nil && suite.InspectRequirements == nil && suite.ValidateRequest == nil && suite.PrepareRequest == nil && suite.SmokeTest == nil && suite.ListPrompts == nil && suite.ListProfiles == nil && suite.ListBackends == nil && suite.ListNamespaces == nil && suite.ListCollections == nil {
|
||||||
command := commandkit.NoCommand()
|
command := commandkit.NoCommand()
|
||||||
for _, issue := range suite.issues {
|
for _, issue := range suite.issues {
|
||||||
@@ -75,16 +79,16 @@ func Command[I, S any](suite Suite[I, S]) commandkit.Command {
|
|||||||
rootCommands := make([]commandkit.Command, 0, 3)
|
rootCommands := make([]commandkit.Command, 0, 3)
|
||||||
showCommands := make([]commandkit.Command, 0, 2)
|
showCommands := make([]commandkit.Command, 0, 2)
|
||||||
if suite.InspectPrompt != nil {
|
if suite.InspectPrompt != nil {
|
||||||
showCommands = append(showCommands, newDefinitionCommand(suite, "prompt"))
|
showCommands = append(showCommands, newDefinitionCommand(suite, "prompt", aliases))
|
||||||
}
|
}
|
||||||
if suite.InspectProfile != nil {
|
if suite.InspectProfile != nil {
|
||||||
showCommands = append(showCommands, newDefinitionCommand(suite, "profile"))
|
showCommands = append(showCommands, newDefinitionCommand(suite, "profile", aliases))
|
||||||
}
|
}
|
||||||
if suite.InspectBackend != nil {
|
if suite.InspectBackend != nil {
|
||||||
showCommands = append(showCommands, newDefinitionCommand(suite, "backend"))
|
showCommands = append(showCommands, newDefinitionCommand(suite, "backend", aliases))
|
||||||
}
|
}
|
||||||
if suite.PrepareRequest != nil {
|
if suite.PrepareRequest != nil {
|
||||||
showCommands = append(showCommands, newPreparationCommand(suite))
|
showCommands = append(showCommands, newPreparationCommand(suite, aliases))
|
||||||
}
|
}
|
||||||
if len(showCommands) != 0 {
|
if len(showCommands) != 0 {
|
||||||
rootCommands = append(rootCommands, commandkit.Group("show", "Show a named PromptKit definition.", showCommands...))
|
rootCommands = append(rootCommands, commandkit.Group("show", "Show a named PromptKit definition.", showCommands...))
|
||||||
@@ -110,16 +114,16 @@ func Command[I, S any](suite Suite[I, S]) commandkit.Command {
|
|||||||
}
|
}
|
||||||
requirementsCommands := make([]commandkit.Command, 0, 2)
|
requirementsCommands := make([]commandkit.Command, 0, 2)
|
||||||
if suite.InspectRequirements != nil {
|
if suite.InspectRequirements != nil {
|
||||||
requirementsCommands = append(requirementsCommands, newRequirementsCommand(suite))
|
requirementsCommands = append(requirementsCommands, newRequirementsCommand(suite, aliases))
|
||||||
}
|
}
|
||||||
if suite.ValidateRequest != nil {
|
if suite.ValidateRequest != nil {
|
||||||
requirementsCommands = append(requirementsCommands, newValidationCommand(suite))
|
requirementsCommands = append(requirementsCommands, newValidationCommand(suite, aliases))
|
||||||
}
|
}
|
||||||
if len(requirementsCommands) != 0 {
|
if len(requirementsCommands) != 0 {
|
||||||
rootCommands = append(rootCommands, commandkit.Group("requirements", "Inspect and validate prompt requirements.", requirementsCommands...))
|
rootCommands = append(rootCommands, commandkit.Group("requirements", "Inspect and validate prompt requirements.", requirementsCommands...))
|
||||||
}
|
}
|
||||||
if suite.SmokeTest != nil {
|
if suite.SmokeTest != nil {
|
||||||
rootCommands = append(rootCommands, newSmokeTestCommand(suite))
|
rootCommands = append(rootCommands, newSmokeTestCommand(suite, aliases))
|
||||||
}
|
}
|
||||||
command := commandkit.RootGroup("promptkit", "Inspect, list, validate requests, and run PromptKit smoke tests.", rootCommands...)
|
command := commandkit.RootGroup("promptkit", "Inspect, list, validate requests, and run PromptKit smoke tests.", rootCommands...)
|
||||||
for _, issue := range suite.issues {
|
for _, issue := range suite.issues {
|
||||||
@@ -231,7 +235,7 @@ func prepareCatalogInput[I, S any](suite Suite[I, S], input *catalogInput[I]) (I
|
|||||||
return prepareSuiteInput(suite, input.selection, input.captured)
|
return prepareSuiteInput(suite, input.selection, input.captured)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newDefinitionCommand[I, S any](suite Suite[I, S], name string) commandkit.Command {
|
func newDefinitionCommand[I, S any](suite Suite[I, S], name string, aliases *[]commandkit.Declaration) commandkit.Command {
|
||||||
flags := commandkit.CaptureFlags(suite.Selectors, func(input **definitionInput[I]) *commandkit.FlagValues[I] {
|
flags := commandkit.CaptureFlags(suite.Selectors, func(input **definitionInput[I]) *commandkit.FlagValues[I] {
|
||||||
if input == nil || *input == nil {
|
if input == nil || *input == nil {
|
||||||
return nil
|
return nil
|
||||||
@@ -247,7 +251,7 @@ func newDefinitionCommand[I, S any](suite Suite[I, S], name string) commandkit.C
|
|||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
if suite.namespaces != nil {
|
if suite.namespaces != nil {
|
||||||
flags = append(flags, namespaceFlags(func(input **definitionInput[I]) *namespaceInput { return &(*input).namespaces }, name)...)
|
flags = appendRequestBindings(flags, "promptkit show "+name, aliases, namespaceFlags(func(input **definitionInput[I]) *namespaceInput { return &(*input).namespaces }, name)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
spec := commandkit.CommandSpec[*definitionInput[I]]{
|
spec := commandkit.CommandSpec[*definitionInput[I]]{
|
||||||
@@ -276,7 +280,7 @@ func newDefinitionCommand[I, S any](suite Suite[I, S], name string) commandkit.C
|
|||||||
return commandkit.NewCommand(spec)
|
return commandkit.NewCommand(spec)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newRequirementsCommand[I, S any](suite Suite[I, S]) commandkit.Command {
|
func newRequirementsCommand[I, S any](suite Suite[I, S], aliases *[]commandkit.Declaration) commandkit.Command {
|
||||||
flags := commandkit.CaptureFlags(suite.Selectors, func(input **requirementsInput[I]) *commandkit.FlagValues[I] {
|
flags := commandkit.CaptureFlags(suite.Selectors, func(input **requirementsInput[I]) *commandkit.FlagValues[I] {
|
||||||
if input == nil || *input == nil {
|
if input == nil || *input == nil {
|
||||||
return nil
|
return nil
|
||||||
@@ -296,10 +300,10 @@ func newRequirementsCommand[I, S any](suite Suite[I, S]) commandkit.Command {
|
|||||||
|
|
||||||
resources := NewResourceFlags(func(input **requirementsInput[I]) *ResourceInput { return &(*input).resources })
|
resources := NewResourceFlags(func(input **requirementsInput[I]) *ResourceInput { return &(*input).resources })
|
||||||
inputs := NewPromptInputFlags(func(input **requirementsInput[I]) *PromptInputs { return &(*input).inputs })
|
inputs := NewPromptInputFlags(func(input **requirementsInput[I]) *PromptInputs { return &(*input).inputs })
|
||||||
flags = append(flags, resources.Profile, resources.SessionID, inputs.Variable)
|
flags = appendRequestBindings(flags, "promptkit requirements show", aliases, requestBinding[*requirementsInput[I]]{resources.Profile, requestFlags.Profile}, requestBinding[*requirementsInput[I]]{resources.SessionID, requestFlags.SessionID}, requestBinding[*requirementsInput[I]]{inputs.Variable, requestFlags.Var})
|
||||||
|
|
||||||
if suite.namespaces != nil {
|
if suite.namespaces != nil {
|
||||||
flags = append(flags, namespaceFlags(func(input **requirementsInput[I]) *namespaceInput { return &(*input).namespaces }, "prompt", "profile")...)
|
flags = appendRequestBindings(flags, "promptkit requirements show", aliases, namespaceFlags(func(input **requirementsInput[I]) *namespaceInput { return &(*input).namespaces }, "prompt", "profile")...)
|
||||||
}
|
}
|
||||||
|
|
||||||
spec := commandkit.CommandSpec[*requirementsInput[I]]{
|
spec := commandkit.CommandSpec[*requirementsInput[I]]{
|
||||||
|
|||||||
31
integrations/ckprompt/declarations.go
Normal file
31
integrations/ckprompt/declarations.go
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
package ckprompt
|
||||||
|
|
||||||
|
import commandkit "go.maximumdirect.net/commandkit"
|
||||||
|
|
||||||
|
type requestBinding[I any] struct {
|
||||||
|
flag commandkit.Flag[I]
|
||||||
|
definition requestFlagDefinition
|
||||||
|
}
|
||||||
|
|
||||||
|
// appendRequestBindings installs the selected handles and, when requested,
|
||||||
|
// records their convenience aliases for the exact owning command.
|
||||||
|
func appendRequestBindings[I any](flags []commandkit.Flag[I], path string, aliases *[]commandkit.Declaration, bindings ...requestBinding[I]) []commandkit.Flag[I] {
|
||||||
|
for _, binding := range bindings {
|
||||||
|
flags = append(flags, binding.flag)
|
||||||
|
if aliases != nil {
|
||||||
|
for _, name := range binding.definition.aliases {
|
||||||
|
*aliases = append(*aliases, commandkit.FlagAliasFor(path, "--"+name, "--"+binding.definition.meta.Name))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return flags
|
||||||
|
}
|
||||||
|
|
||||||
|
// Declarations returns the canonical PromptKit command family and scoped
|
||||||
|
// convenience aliases for the operations and flags enabled by suite. Command
|
||||||
|
// remains available for installations that want only canonical spellings.
|
||||||
|
func Declarations[I, S any](suite Suite[I, S]) []commandkit.Declaration {
|
||||||
|
var aliases []commandkit.Declaration
|
||||||
|
command := buildCommand(suite, &aliases)
|
||||||
|
return append([]commandkit.Declaration{command}, aliases...)
|
||||||
|
}
|
||||||
123
integrations/ckprompt/declarations_test.go
Normal file
123
integrations/ckprompt/declarations_test.go
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
package ckprompt_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"io"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"go.maximumdirect.net/ckprompt"
|
||||||
|
commandkit "go.maximumdirect.net/commandkit"
|
||||||
|
promptkit "go.maximumdirect.net/promptkit"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestDeclarationsInstallOnlySelectedScopedAliases(t *testing.T) {
|
||||||
|
var got ckprompt.PreparationRequest
|
||||||
|
calls := 0
|
||||||
|
suite := ckprompt.WithNamespaces(ckprompt.Suite[struct{}, struct{}]{PrepareRequest: func(_ context.Context, request ckprompt.PreparationRequest, _, _ struct{}) (commandkit.Acquired[*promptkit.PreparedRun], error) {
|
||||||
|
calls++
|
||||||
|
got = request
|
||||||
|
return commandkit.Acquired[*promptkit.PreparedRun]{Value: &promptkit.PreparedRun{}}, nil
|
||||||
|
}}, promptkit.Namespaces{Prompt: "default"})
|
||||||
|
declarations := append(ckprompt.Declarations(suite), commandkit.Alias("preview", "promptkit show prepared"), commandkit.Completion("app"))
|
||||||
|
app, err := commandkit.New(commandkit.Identity{Name: "app"}, declarations...)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
var help bytes.Buffer
|
||||||
|
for _, args := range [][]string{{"promptkit", "show", "prepared", "--help"}, {"__complete", "promptkit", "show", "prepared", ""}} {
|
||||||
|
result := app.Execute(context.Background(), args, commandkit.Streams{Out: &help, Err: io.Discard})
|
||||||
|
if result.Kind != commandkit.OutcomeSuccess || calls != 0 {
|
||||||
|
t.Fatalf("metadata %v = %#v calls=%d", args, result, calls)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !strings.Contains(help.String(), "--llm-input-text") || !strings.Contains(help.String(), "--input") {
|
||||||
|
t.Fatalf("alias help = %q", help.String())
|
||||||
|
}
|
||||||
|
result := app.Execute(context.Background(), []string{"preview", "p", "--profile=", "--prompt-namespace=", "--input-file=x=path", "--llm-input=x=literal", "--input-text=y=first", "--llm-input-file=y=last", "--input=z=", "--model=fixture"}, commandkit.Streams{Out: io.Discard, Err: io.Discard})
|
||||||
|
if result.Kind != commandkit.OutcomeSuccess || calls != 1 || got.Namespaces == nil || got.Namespaces.Prompt != "" || got.Request.Execution == nil || got.Request.Execution.Model != "fixture" || got.Request.Inputs["x"] != promptkit.Inline("literal") || got.Request.Inputs["y"] != promptkit.File("last") || got.Request.Inputs["z"] != promptkit.Inline("") {
|
||||||
|
t.Fatalf("result=%#v request=%#v calls=%d", result, got, calls)
|
||||||
|
}
|
||||||
|
for _, flag := range []string{"--backend=unavailable", "--unknown=value"} {
|
||||||
|
result = app.Execute(context.Background(), []string{"preview", "p", flag}, commandkit.Streams{Out: io.Discard, Err: io.Discard})
|
||||||
|
if result.Kind != commandkit.OutcomeUsage || calls != 1 {
|
||||||
|
t.Fatalf("inapplicable %s = %#v", flag, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
canonical, err := commandkit.New(commandkit.Identity{Name: "app"}, ckprompt.Command(suite))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
help.Reset()
|
||||||
|
result = canonical.Execute(context.Background(), []string{"promptkit", "show", "prepared", "--help"}, commandkit.Streams{Out: &help, Err: io.Discard})
|
||||||
|
if result.Kind != commandkit.OutcomeSuccess || strings.Contains(help.String(), "--input ") {
|
||||||
|
t.Fatalf("canonical help = %q", help.String())
|
||||||
|
}
|
||||||
|
result = canonical.Execute(context.Background(), []string{"promptkit", "show", "prepared", "p", "--input=x=text"}, commandkit.Streams{Out: io.Discard, Err: io.Discard})
|
||||||
|
if result.Kind != commandkit.OutcomeUsage {
|
||||||
|
t.Fatalf("canonical alias accepted: %#v", result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDeclarationsDetectAliasConflicts(t *testing.T) {
|
||||||
|
type input struct{ profile string }
|
||||||
|
selector := commandkit.ValueFlag(commandkit.FlagMeta{Name: "profile"}, (*string)(nil), func(v string) (string, error) { return v, nil }, func(i *input, v commandkit.Supplied[string]) { i.profile = v.Value })
|
||||||
|
suite := ckprompt.Suite[input, struct{}]{Selectors: []commandkit.Flag[input]{selector}, PrepareRequest: func(context.Context, ckprompt.PreparationRequest, input, struct{}) (commandkit.Acquired[*promptkit.PreparedRun], error) {
|
||||||
|
return commandkit.Acquired[*promptkit.PreparedRun]{Value: &promptkit.PreparedRun{}}, nil
|
||||||
|
}}
|
||||||
|
if _, err := commandkit.New(commandkit.Identity{Name: "app"}, ckprompt.Declarations(suite)...); err == nil {
|
||||||
|
t.Fatal("selector conflicting with scoped alias was accepted")
|
||||||
|
}
|
||||||
|
if _, err := commandkit.New(commandkit.Identity{Name: "app"}, ckprompt.Command(suite)); err != nil {
|
||||||
|
t.Fatalf("canonical selector unexpectedly rejected: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDeclarationsCoverEnabledCommandsAndNamespaces(t *testing.T) {
|
||||||
|
var requirements ckprompt.RequirementsRequest
|
||||||
|
var smoke ckprompt.SmokeRequest
|
||||||
|
suite := ckprompt.WithNamespaces(ckprompt.Suite[struct{}, struct{}]{
|
||||||
|
InspectPrompt: func(context.Context, ckprompt.PromptRequest, struct{}, struct{}) (commandkit.Acquired[*promptkit.PromptInspection], error) {
|
||||||
|
return commandkit.Acquired[*promptkit.PromptInspection]{Value: &promptkit.PromptInspection{}}, nil
|
||||||
|
},
|
||||||
|
InspectProfile: func(context.Context, ckprompt.ProfileRequest, struct{}, struct{}) (commandkit.Acquired[*promptkit.ProfileInspection], error) {
|
||||||
|
return commandkit.Acquired[*promptkit.ProfileInspection]{Value: &promptkit.ProfileInspection{}}, nil
|
||||||
|
},
|
||||||
|
InspectBackend: func(context.Context, ckprompt.BackendRequest, struct{}, struct{}) (commandkit.Acquired[*promptkit.BackendInspection], error) {
|
||||||
|
return commandkit.Acquired[*promptkit.BackendInspection]{Value: &promptkit.BackendInspection{}}, nil
|
||||||
|
},
|
||||||
|
InspectRequirements: func(_ context.Context, req ckprompt.RequirementsRequest, _, _ struct{}) (commandkit.Acquired[*promptkit.RequirementInspection], error) {
|
||||||
|
requirements = req
|
||||||
|
return commandkit.Acquired[*promptkit.RequirementInspection]{Value: &promptkit.RequirementInspection{}}, nil
|
||||||
|
},
|
||||||
|
ValidateRequest: func(context.Context, ckprompt.ValidationRequest, struct{}, struct{}) (commandkit.Acquired[struct{}], error) {
|
||||||
|
return commandkit.Acquired[struct{}]{}, nil
|
||||||
|
},
|
||||||
|
PrepareRequest: func(context.Context, ckprompt.PreparationRequest, struct{}, struct{}) (commandkit.Acquired[*promptkit.PreparedRun], error) {
|
||||||
|
return commandkit.Acquired[*promptkit.PreparedRun]{Value: &promptkit.PreparedRun{}}, nil
|
||||||
|
},
|
||||||
|
SmokeTest: func(_ context.Context, req ckprompt.SmokeRequest, _, _ struct{}) (commandkit.Acquired[*promptkit.SmokeTestReport], error) {
|
||||||
|
smoke = req
|
||||||
|
return commandkit.Acquired[*promptkit.SmokeTestReport]{Value: &promptkit.SmokeTestReport{}}, nil
|
||||||
|
},
|
||||||
|
}, promptkit.Namespaces{Prompt: "original", Profile: "profiles", Backend: "backends"})
|
||||||
|
app, err := commandkit.New(commandkit.Identity{Name: "app"}, ckprompt.Declarations(suite)...)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
run := func(args ...string) commandkit.Outcome {
|
||||||
|
return app.Execute(context.Background(), args, commandkit.Streams{Out: io.Discard, Err: io.Discard})
|
||||||
|
}
|
||||||
|
if result := run("promptkit", "requirements", "show", "p", "--profile=first", "--llm-profile=last", "--var=x=y", "--profile-namespace=custom"); result.Kind != commandkit.OutcomeSuccess || requirements.Inspection.ProfileID != "last" || requirements.Inspection.Vars["x"] != "y" || requirements.Namespaces == nil || requirements.Namespaces.Profile != "custom" {
|
||||||
|
t.Fatalf("requirements = %#v %#v", result, requirements)
|
||||||
|
}
|
||||||
|
if result := run("promptkit", "test", "authentication", "--backend=local", "--prompt=p", "--temperature=0", "--extra-params={}", "--backend-namespace="); result.Kind != commandkit.OutcomeSuccess || smoke.Request.BackendID != "local" || smoke.Request.PromptID != "p" || smoke.Request.Execution == nil || smoke.Request.Execution.Temperature == nil || *smoke.Request.Execution.Temperature != 0 || smoke.Request.Execution.ExtraParams == nil || smoke.Namespaces == nil || smoke.Namespaces.Backend != "" {
|
||||||
|
t.Fatalf("smoke = %#v %#v", result, smoke)
|
||||||
|
}
|
||||||
|
for _, args := range [][]string{{"promptkit", "show", "prompt", "p", "--prompt-namespace=x"}, {"promptkit", "show", "profile", "p", "--profile-namespace=x"}, {"promptkit", "show", "backend", "p", "--backend-namespace=x"}, {"promptkit", "requirements", "validate", "p", "--input=x=value"}} {
|
||||||
|
if result := run(args...); result.Kind != commandkit.OutcomeSuccess {
|
||||||
|
t.Fatalf("%v = %#v", args, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -25,11 +25,11 @@ go run . promptkit show prompt briefing --campaign spring --format yaml
|
|||||||
go run . pk show prompt briefing --campaign spring --fmt yaml
|
go run . pk show prompt briefing --campaign spring --fmt yaml
|
||||||
go run . promptkit show profile spring --campaign spring
|
go run . promptkit show profile spring --campaign spring
|
||||||
go run . promptkit requirements show briefing --campaign spring
|
go run . promptkit requirements show briefing --campaign spring
|
||||||
go run . promptkit requirements show briefing --campaign spring --llm-var mode=full --format yaml
|
go run . promptkit requirements show briefing --campaign spring --var mode=full --format yaml
|
||||||
go run . promptkit requirements validate briefing --campaign spring --llm-input-file topic=fixtures/topic.txt
|
go run . promptkit requirements validate briefing --campaign spring --llm-input-file topic=fixtures/topic.txt
|
||||||
go run . promptkit requirements validate briefing --campaign spring --llm-input-file topic=fixtures/topic.txt --llm-var mode=full --llm-input-file notes=fixtures/notes.txt --format yaml
|
go run . promptkit requirements validate briefing --campaign spring --llm-input-file topic=fixtures/topic.txt --llm-var mode=full --llm-input-file notes=fixtures/notes.txt --format yaml
|
||||||
go run . promptkit requirements validate briefing --campaign spring
|
go run . promptkit requirements validate briefing --campaign spring
|
||||||
go run . promptkit test text_inference --campaign spring --llm-prompt briefing --llm-profile spring
|
go run . promptkit test text_inference --campaign spring --prompt briefing --profile spring
|
||||||
go run . smoke text_inference --campaign spring --llm-prompt briefing --llm-profile spring
|
go run . smoke text_inference --campaign spring --llm-prompt briefing --llm-profile spring
|
||||||
go run . promptkit test all --campaign spring --llm-prompt briefing --llm-profile spring
|
go run . promptkit test all --campaign spring --llm-prompt briefing --llm-profile spring
|
||||||
go run . pk --hlep
|
go run . pk --hlep
|
||||||
|
|||||||
@@ -249,7 +249,7 @@ func newAppWithEngineLoader(
|
|||||||
if smokeTest != nil {
|
if smokeTest != nil {
|
||||||
definitions.SmokeTest = smokeTest
|
definitions.SmokeTest = smokeTest
|
||||||
}
|
}
|
||||||
definitionCommand := ckprompt.Command(definitions)
|
definitionDeclarations := ckprompt.Declarations(definitions)
|
||||||
|
|
||||||
store := map[string]session{
|
store := map[string]session{
|
||||||
"session-42": {ID: "session-42", Campaign: "spring", Summary: "A synthetic planning session."},
|
"session-42": {ID: "session-42", Campaign: "spring", Summary: "A synthetic planning session."},
|
||||||
@@ -291,7 +291,6 @@ func newAppWithEngineLoader(
|
|||||||
})
|
})
|
||||||
declarations := []commandkit.Declaration{
|
declarations := []commandkit.Declaration{
|
||||||
configCommand,
|
configCommand,
|
||||||
definitionCommand,
|
|
||||||
commandkit.Completion("composed-example"),
|
commandkit.Completion("composed-example"),
|
||||||
commandkit.Group("session", "Manage saved sessions.", restore),
|
commandkit.Group("session", "Manage saved sessions.", restore),
|
||||||
commandkit.Alias("list collections", "promptkit list collections"),
|
commandkit.Alias("list collections", "promptkit list collections"),
|
||||||
@@ -301,6 +300,7 @@ func newAppWithEngineLoader(
|
|||||||
commandkit.FlagAliasFor("promptkit show prompt", "--fmt", "--format"),
|
commandkit.FlagAliasFor("promptkit show prompt", "--fmt", "--format"),
|
||||||
commandkit.FlagAlias("--hlep", "--help"),
|
commandkit.FlagAlias("--hlep", "--help"),
|
||||||
}
|
}
|
||||||
|
declarations = append(declarations, definitionDeclarations...)
|
||||||
return commandkit.New(commandkit.Identity{Name: "composed-example", Version: "1.0"}, declarations...)
|
return commandkit.New(commandkit.Identity{Name: "composed-example", Version: "1.0"}, declarations...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,23 +17,23 @@ type namespaceInput struct {
|
|||||||
prompt, profile, backend commandkit.Supplied[string]
|
prompt, profile, backend commandkit.Supplied[string]
|
||||||
}
|
}
|
||||||
|
|
||||||
func namespaceFlags[I any](destination func(*I) *namespaceInput, kinds ...string) []commandkit.Flag[I] {
|
func namespaceFlags[I any](destination func(*I) *namespaceInput, kinds ...string) []requestBinding[I] {
|
||||||
flags := make([]commandkit.Flag[I], 0, len(kinds))
|
flags := make([]requestBinding[I], 0, len(kinds))
|
||||||
for _, kind := range kinds {
|
for _, kind := range kinds {
|
||||||
var meta commandkit.FlagMeta
|
var definition requestFlagDefinition
|
||||||
var field func(*namespaceInput) *commandkit.Supplied[string]
|
var field func(*namespaceInput) *commandkit.Supplied[string]
|
||||||
switch kind {
|
switch kind {
|
||||||
case "prompt":
|
case "prompt":
|
||||||
meta = namespaceFlagDefinitions.prompt.meta
|
definition = namespaceFlagDefinitions.prompt
|
||||||
field = func(input *namespaceInput) *commandkit.Supplied[string] { return &input.prompt }
|
field = func(input *namespaceInput) *commandkit.Supplied[string] { return &input.prompt }
|
||||||
case "profile":
|
case "profile":
|
||||||
meta = namespaceFlagDefinitions.profile.meta
|
definition = namespaceFlagDefinitions.profile
|
||||||
field = func(input *namespaceInput) *commandkit.Supplied[string] { return &input.profile }
|
field = func(input *namespaceInput) *commandkit.Supplied[string] { return &input.profile }
|
||||||
case "backend":
|
case "backend":
|
||||||
meta = namespaceFlagDefinitions.backend.meta
|
definition = namespaceFlagDefinitions.backend
|
||||||
field = func(input *namespaceInput) *commandkit.Supplied[string] { return &input.backend }
|
field = func(input *namespaceInput) *commandkit.Supplied[string] { return &input.backend }
|
||||||
}
|
}
|
||||||
flags = append(flags, commandkit.ValueFlag(meta, (*string)(nil), parseDefinitionString, func(input *I, value commandkit.Supplied[string]) { *field(destination(input)) = value }))
|
flags = append(flags, requestBinding[I]{commandkit.ValueFlag(definition.meta, (*string)(nil), parseDefinitionString, func(input *I, value commandkit.Supplied[string]) { *field(destination(input)) = value }), definition})
|
||||||
}
|
}
|
||||||
return flags
|
return flags
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,8 +69,8 @@ func WithRequestPreparation[I, S any](
|
|||||||
return suite
|
return suite
|
||||||
}
|
}
|
||||||
|
|
||||||
func newPreparationCommand[I, S any](suite Suite[I, S]) commandkit.Command {
|
func newPreparationCommand[I, S any](suite Suite[I, S], aliases *[]commandkit.Declaration) commandkit.Command {
|
||||||
spec := newConcreteRequestSpec(suite)
|
spec := newConcreteRequestSpec(suite, "promptkit show prepared", aliases)
|
||||||
spec.Name = "prepared"
|
spec.Name = "prepared"
|
||||||
spec.Summary = "Show a prepared PromptKit request without calling the model."
|
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.Description = "Prepares the request using resource I/O and reports rendered application content without calling the model."
|
||||||
|
|||||||
@@ -70,7 +70,18 @@ type ExecutionFlags[I any] struct {
|
|||||||
|
|
||||||
// All returns all execution controls.
|
// All returns all execution controls.
|
||||||
func (f ExecutionFlags[I]) All() []commandkit.Flag[I] {
|
func (f ExecutionFlags[I]) All() []commandkit.Flag[I] {
|
||||||
return []commandkit.Flag[I]{f.Endpoint, f.Model, f.Temperature, f.MaxTokens, f.TopP, f.TimeoutSeconds, f.ServiceTier, f.ReasoningEffort, f.APIKeyEnv, f.TransientRetries, f.ExtraParams}
|
return appendRequestBindings(nil, "", nil, f.bindings()...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f ExecutionFlags[I]) bindings() []requestBinding[I] {
|
||||||
|
return []requestBinding[I]{
|
||||||
|
{f.Endpoint, requestFlags.Endpoint}, {f.Model, requestFlags.Model},
|
||||||
|
{f.Temperature, requestFlags.Temperature}, {f.MaxTokens, requestFlags.MaxTokens},
|
||||||
|
{f.TopP, requestFlags.TopP}, {f.TimeoutSeconds, requestFlags.TimeoutSeconds},
|
||||||
|
{f.ServiceTier, requestFlags.ServiceTier}, {f.ReasoningEffort, requestFlags.ReasoningEffort},
|
||||||
|
{f.APIKeyEnv, requestFlags.APIKeyEnv}, {f.TransientRetries, requestFlags.TransientRetries},
|
||||||
|
{f.ExtraParams, requestFlags.ExtraParams},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewExecutionFlags binds execution controls to a field of the caller's input.
|
// NewExecutionFlags binds execution controls to a field of the caller's input.
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ type smokeCommandInput[I any] struct {
|
|||||||
selected I
|
selected I
|
||||||
}
|
}
|
||||||
|
|
||||||
func newSmokeTestCommand[I, S any](suite Suite[I, S]) commandkit.Command {
|
func newSmokeTestCommand[I, S any](suite Suite[I, S], aliases *[]commandkit.Declaration) commandkit.Command {
|
||||||
flags := commandkit.CaptureFlags(suite.Selectors, func(input **smokeCommandInput[I]) *commandkit.FlagValues[I] {
|
flags := commandkit.CaptureFlags(suite.Selectors, func(input **smokeCommandInput[I]) *commandkit.FlagValues[I] {
|
||||||
if input == nil || *input == nil {
|
if input == nil || *input == nil {
|
||||||
return nil
|
return nil
|
||||||
@@ -41,11 +41,15 @@ func newSmokeTestCommand[I, S any](suite Suite[I, S]) commandkit.Command {
|
|||||||
|
|
||||||
resources := NewResourceFlags(func(input **smokeCommandInput[I]) *ResourceInput { return &(*input).resources })
|
resources := NewResourceFlags(func(input **smokeCommandInput[I]) *ResourceInput { return &(*input).resources })
|
||||||
execution := NewExecutionFlags(func(input **smokeCommandInput[I]) *ExecutionInput { return &(*input).execution })
|
execution := NewExecutionFlags(func(input **smokeCommandInput[I]) *ExecutionInput { return &(*input).execution })
|
||||||
flags = append(flags, resources.Backend, resources.Prompt, resources.Profile)
|
flags = appendRequestBindings(flags, "promptkit test", aliases,
|
||||||
flags = append(flags, execution.All()...)
|
requestBinding[*smokeCommandInput[I]]{resources.Backend, requestFlags.Backend},
|
||||||
|
requestBinding[*smokeCommandInput[I]]{resources.Prompt, requestFlags.Prompt},
|
||||||
|
requestBinding[*smokeCommandInput[I]]{resources.Profile, requestFlags.Profile},
|
||||||
|
)
|
||||||
|
flags = appendRequestBindings(flags, "promptkit test", aliases, execution.bindings()...)
|
||||||
|
|
||||||
if suite.namespaces != nil {
|
if suite.namespaces != nil {
|
||||||
flags = append(flags, namespaceFlags(func(input **smokeCommandInput[I]) *namespaceInput { return &(*input).namespaces }, "prompt", "profile", "backend")...)
|
flags = appendRequestBindings(flags, "promptkit test", aliases, namespaceFlags(func(input **smokeCommandInput[I]) *namespaceInput { return &(*input).namespaces }, "prompt", "profile", "backend")...)
|
||||||
}
|
}
|
||||||
|
|
||||||
return commandkit.NewCommand(commandkit.CommandSpec[*smokeCommandInput[I]]{
|
return commandkit.NewCommand(commandkit.CommandSpec[*smokeCommandInput[I]]{
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ type requestValidationReport struct {
|
|||||||
Valid bool `json:"valid"`
|
Valid bool `json:"valid"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func newConcreteRequestSpec[I, S any](suite Suite[I, S]) commandkit.CommandSpec[*concreteRequestInput[I]] {
|
func newConcreteRequestSpec[I, S any](suite Suite[I, S], path string, aliases *[]commandkit.Declaration) commandkit.CommandSpec[*concreteRequestInput[I]] {
|
||||||
flags := commandkit.CaptureFlags(suite.Selectors, func(input **concreteRequestInput[I]) *commandkit.FlagValues[I] {
|
flags := commandkit.CaptureFlags(suite.Selectors, func(input **concreteRequestInput[I]) *commandkit.FlagValues[I] {
|
||||||
if input == nil || *input == nil {
|
if input == nil || *input == nil {
|
||||||
return nil
|
return nil
|
||||||
@@ -44,11 +44,17 @@ func newConcreteRequestSpec[I, S any](suite Suite[I, S]) commandkit.CommandSpec[
|
|||||||
resources := NewResourceFlags(func(input **concreteRequestInput[I]) *ResourceInput { return &(*input).resources })
|
resources := NewResourceFlags(func(input **concreteRequestInput[I]) *ResourceInput { return &(*input).resources })
|
||||||
execution := NewExecutionFlags(func(input **concreteRequestInput[I]) *ExecutionInput { return &(*input).execution })
|
execution := NewExecutionFlags(func(input **concreteRequestInput[I]) *ExecutionInput { return &(*input).execution })
|
||||||
inputs := NewPromptInputFlags(func(input **concreteRequestInput[I]) *PromptInputs { return &(*input).inputs })
|
inputs := NewPromptInputFlags(func(input **concreteRequestInput[I]) *PromptInputs { return &(*input).inputs })
|
||||||
flags = append(flags, resources.Profile, resources.SessionID, inputs.Variable, inputs.Text, inputs.File)
|
flags = appendRequestBindings(flags, path, aliases,
|
||||||
flags = append(flags, execution.All()...)
|
requestBinding[*concreteRequestInput[I]]{resources.Profile, requestFlags.Profile},
|
||||||
|
requestBinding[*concreteRequestInput[I]]{resources.SessionID, requestFlags.SessionID},
|
||||||
|
requestBinding[*concreteRequestInput[I]]{inputs.Variable, requestFlags.Var},
|
||||||
|
requestBinding[*concreteRequestInput[I]]{inputs.Text, requestFlags.InputText},
|
||||||
|
requestBinding[*concreteRequestInput[I]]{inputs.File, requestFlags.InputFile},
|
||||||
|
)
|
||||||
|
flags = appendRequestBindings(flags, path, aliases, execution.bindings()...)
|
||||||
|
|
||||||
if suite.namespaces != nil {
|
if suite.namespaces != nil {
|
||||||
flags = append(flags, namespaceFlags(func(input **concreteRequestInput[I]) *namespaceInput { return &(*input).namespaces }, "prompt", "profile", "backend")...)
|
flags = appendRequestBindings(flags, path, aliases, namespaceFlags(func(input **concreteRequestInput[I]) *namespaceInput { return &(*input).namespaces }, "prompt", "profile", "backend")...)
|
||||||
}
|
}
|
||||||
|
|
||||||
return commandkit.CommandSpec[*concreteRequestInput[I]]{
|
return commandkit.CommandSpec[*concreteRequestInput[I]]{
|
||||||
@@ -84,8 +90,8 @@ func newConcreteRequestSpec[I, S any](suite Suite[I, S]) commandkit.CommandSpec[
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func newValidationCommand[I, S any](suite Suite[I, S]) commandkit.Command {
|
func newValidationCommand[I, S any](suite Suite[I, S], aliases *[]commandkit.Declaration) commandkit.Command {
|
||||||
spec := newConcreteRequestSpec(suite)
|
spec := newConcreteRequestSpec(suite, "promptkit requirements validate", aliases)
|
||||||
spec.Name = "validate"
|
spec.Name = "validate"
|
||||||
spec.Summary = "Validate a concrete PromptKit request without executing it."
|
spec.Summary = "Validate a concrete PromptKit request without executing it."
|
||||||
spec.Run = func(invocation commandkit.Invocation, input *concreteRequestInput[I]) commandkit.Outcome {
|
spec.Run = func(invocation commandkit.Invocation, input *concreteRequestInput[I]) commandkit.Outcome {
|
||||||
|
|||||||
Reference in New Issue
Block a user