Add opt-in PromptKit namespaces
This commit is contained in:
@@ -19,6 +19,8 @@ type PromptRequest struct {
|
||||
Selection ckconfig.Selection
|
||||
// ID is the selected named prompt.
|
||||
ID string
|
||||
// Namespaces selects the native engine view; nil preserves the loader view.
|
||||
Namespaces *promptkit.Namespaces
|
||||
}
|
||||
|
||||
// ProfileRequest selects one named profile for inspection.
|
||||
@@ -27,6 +29,8 @@ type ProfileRequest struct {
|
||||
Selection ckconfig.Selection
|
||||
// ID is the selected named profile.
|
||||
ID string
|
||||
// Namespaces selects the native engine view; nil preserves the loader view.
|
||||
Namespaces *promptkit.Namespaces
|
||||
}
|
||||
|
||||
// BackendRequest selects one named backend for inspection.
|
||||
@@ -35,6 +39,8 @@ type BackendRequest struct {
|
||||
Selection ckconfig.Selection
|
||||
// ID is the selected named backend.
|
||||
ID string
|
||||
// Namespaces selects the native engine view; nil preserves the loader view.
|
||||
Namespaces *promptkit.Namespaces
|
||||
}
|
||||
|
||||
// CatalogRequest selects the configuration and native namespace filter for a
|
||||
@@ -68,6 +74,8 @@ type RequirementsRequest struct {
|
||||
// discovery context. Profile and session strings retain PromptKit's
|
||||
// empty-value semantics.
|
||||
Inspection promptkit.RequirementInspectionRequest
|
||||
// Namespaces selects the native engine view; nil preserves the loader view.
|
||||
Namespaces *promptkit.Namespaces
|
||||
}
|
||||
|
||||
// Suite describes application-owned input, shared state, and optional catalog,
|
||||
@@ -150,7 +158,8 @@ type Suite[I, S any] struct {
|
||||
// omits only this catalog command.
|
||||
ListCollections func(context.Context, ckconfig.Selection, I, S) (commandkit.Acquired[[]promptkit.CollectionInfo], error)
|
||||
|
||||
issues []error
|
||||
namespaces *promptkit.Namespaces
|
||||
issues []error
|
||||
}
|
||||
|
||||
// WithRequestValidation attaches PromptKit-backed concrete request validation
|
||||
@@ -205,6 +214,12 @@ func WithRequestValidation[I, S any](
|
||||
return commandkit.Acquired[struct{}]{Diagnostics: messages.diagnostics, Explanation: messages.explanation}, fmt.Errorf("PromptKit request validation before native validation: %w", err)
|
||||
}
|
||||
|
||||
engine, err = namespacedEngine(engine, request.Namespaces)
|
||||
if err != nil {
|
||||
messages = messages.withOperationError(err)
|
||||
return commandkit.Acquired[struct{}]{Diagnostics: messages.diagnostics, Explanation: messages.explanation}, err
|
||||
}
|
||||
|
||||
if err := engine.ValidateRequest(ctx, concreteRequest); err != nil {
|
||||
messages = messages.withOperationError(err)
|
||||
return commandkit.Acquired[struct{}]{Diagnostics: messages.diagnostics, Explanation: messages.explanation}, err
|
||||
@@ -384,6 +399,11 @@ func FromEngine[I, S any](load func(context.Context, ckconfig.Selection, I, S) (
|
||||
if err != nil {
|
||||
return commandkit.Acquired[*promptkit.PromptInspection]{Diagnostics: messages.diagnostics, Explanation: messages.explanation}, err
|
||||
}
|
||||
engine, err = namespacedEngine(engine, request.Namespaces)
|
||||
if err != nil {
|
||||
messages = messages.withOperationError(err)
|
||||
return commandkit.Acquired[*promptkit.PromptInspection]{Diagnostics: messages.diagnostics, Explanation: messages.explanation}, err
|
||||
}
|
||||
inspection, err := engine.InspectPrompt(ctx, request.ID)
|
||||
messages = messages.withOperationError(err)
|
||||
return commandkit.Acquired[*promptkit.PromptInspection]{Value: inspection, Diagnostics: messages.diagnostics, Explanation: messages.explanation}, err
|
||||
@@ -393,6 +413,11 @@ func FromEngine[I, S any](load func(context.Context, ckconfig.Selection, I, S) (
|
||||
if err != nil {
|
||||
return commandkit.Acquired[*promptkit.ProfileInspection]{Diagnostics: messages.diagnostics, Explanation: messages.explanation}, err
|
||||
}
|
||||
engine, err = namespacedEngine(engine, request.Namespaces)
|
||||
if err != nil {
|
||||
messages = messages.withOperationError(err)
|
||||
return commandkit.Acquired[*promptkit.ProfileInspection]{Diagnostics: messages.diagnostics, Explanation: messages.explanation}, err
|
||||
}
|
||||
inspection, err := engine.InspectProfile(ctx, request.ID)
|
||||
messages = messages.withOperationError(err)
|
||||
return commandkit.Acquired[*promptkit.ProfileInspection]{Value: inspection, Diagnostics: messages.diagnostics, Explanation: messages.explanation}, err
|
||||
@@ -402,6 +427,11 @@ func FromEngine[I, S any](load func(context.Context, ckconfig.Selection, I, S) (
|
||||
if err != nil {
|
||||
return commandkit.Acquired[*promptkit.BackendInspection]{Diagnostics: messages.diagnostics, Explanation: messages.explanation}, err
|
||||
}
|
||||
engine, err = namespacedEngine(engine, request.Namespaces)
|
||||
if err != nil {
|
||||
messages = messages.withOperationError(err)
|
||||
return commandkit.Acquired[*promptkit.BackendInspection]{Diagnostics: messages.diagnostics, Explanation: messages.explanation}, err
|
||||
}
|
||||
inspection, err := engine.InspectBackend(ctx, request.ID)
|
||||
messages = messages.withOperationError(err)
|
||||
return commandkit.Acquired[*promptkit.BackendInspection]{Value: inspection, Diagnostics: messages.diagnostics, Explanation: messages.explanation}, err
|
||||
@@ -411,6 +441,11 @@ func FromEngine[I, S any](load func(context.Context, ckconfig.Selection, I, S) (
|
||||
if err != nil {
|
||||
return commandkit.Acquired[*promptkit.RequirementInspection]{Diagnostics: messages.diagnostics, Explanation: messages.explanation}, err
|
||||
}
|
||||
engine, err = namespacedEngine(engine, request.Namespaces)
|
||||
if err != nil {
|
||||
messages = messages.withOperationError(err)
|
||||
return commandkit.Acquired[*promptkit.RequirementInspection]{Diagnostics: messages.diagnostics, Explanation: messages.explanation}, err
|
||||
}
|
||||
inspection, err := engine.InspectRequirements(ctx, request.Inspection)
|
||||
messages = messages.withOperationError(err)
|
||||
return commandkit.Acquired[*promptkit.RequirementInspection]{Value: inspection, Diagnostics: messages.diagnostics, Explanation: messages.explanation}, err
|
||||
|
||||
@@ -12,10 +12,11 @@ import (
|
||||
)
|
||||
|
||||
type definitionInput[I any] struct {
|
||||
selection ckconfig.Selection
|
||||
id string
|
||||
captured commandkit.FlagValues[I]
|
||||
selected I
|
||||
namespaces namespaceInput
|
||||
selection ckconfig.Selection
|
||||
id string
|
||||
captured commandkit.FlagValues[I]
|
||||
selected I
|
||||
}
|
||||
|
||||
type catalogInput[I any] struct {
|
||||
@@ -29,6 +30,7 @@ type catalogInput[I any] struct {
|
||||
}
|
||||
|
||||
type requirementsInput[I any] struct {
|
||||
namespaces namespaceInput
|
||||
selection ckconfig.Selection
|
||||
inspection promptkit.RequirementInspectionRequest
|
||||
resources ResourceInput
|
||||
@@ -244,6 +246,10 @@ func newDefinitionCommand[I, S any](suite Suite[I, S], name string) commandkit.C
|
||||
(*input).selection.Overlay = value
|
||||
}),
|
||||
)
|
||||
if suite.namespaces != nil {
|
||||
flags = append(flags, namespaceFlags(func(input **definitionInput[I]) *namespaceInput { return &(*input).namespaces }, name)...)
|
||||
}
|
||||
|
||||
spec := commandkit.CommandSpec[*definitionInput[I]]{
|
||||
Name: name,
|
||||
Summary: "Inspect a named PromptKit " + name + ".",
|
||||
@@ -292,9 +298,14 @@ func newRequirementsCommand[I, S any](suite Suite[I, S]) commandkit.Command {
|
||||
inputs := NewPromptInputFlags(func(input **requirementsInput[I]) *PromptInputs { return &(*input).inputs })
|
||||
flags = append(flags, resources.Profile, resources.SessionID, inputs.Variable)
|
||||
|
||||
if suite.namespaces != nil {
|
||||
flags = append(flags, namespaceFlags(func(input **requirementsInput[I]) *namespaceInput { return &(*input).namespaces }, "prompt", "profile")...)
|
||||
}
|
||||
|
||||
spec := commandkit.CommandSpec[*requirementsInput[I]]{
|
||||
Name: "show",
|
||||
Summary: "Inspect requirements for a named PromptKit prompt.",
|
||||
Name: "show",
|
||||
Summary: "Inspect requirements for a named PromptKit prompt.",
|
||||
Description: "Profile selection establishes the reported profile identity, not a different set of requirements. A profile namespace qualifies an explicitly supplied short profile ID, not the prompt’s stored default reference.",
|
||||
NewInput: func() *requirementsInput[I] {
|
||||
return &requirementsInput[I]{}
|
||||
},
|
||||
@@ -398,21 +409,21 @@ func runDefinitionInspection[I, S any](invocation commandkit.Invocation, suite S
|
||||
switch kind {
|
||||
case "prompt":
|
||||
var result commandkit.Acquired[*promptkit.PromptInspection]
|
||||
result, err = suite.InspectPrompt(invocation.Context, PromptRequest{Selection: input.selection, ID: input.id}, input.selected, state)
|
||||
result, err = suite.InspectPrompt(invocation.Context, PromptRequest{Selection: input.selection, ID: input.id, Namespaces: selectedNamespaces(suite.namespaces, input.namespaces)}, input.selected, state)
|
||||
if result.Value != nil {
|
||||
value = result.Value
|
||||
}
|
||||
diagnostics, explanation = result.Diagnostics, result.Explanation
|
||||
case "profile":
|
||||
var result commandkit.Acquired[*promptkit.ProfileInspection]
|
||||
result, err = suite.InspectProfile(invocation.Context, ProfileRequest{Selection: input.selection, ID: input.id}, input.selected, state)
|
||||
result, err = suite.InspectProfile(invocation.Context, ProfileRequest{Selection: input.selection, ID: input.id, Namespaces: selectedNamespaces(suite.namespaces, input.namespaces)}, input.selected, state)
|
||||
if result.Value != nil {
|
||||
value = result.Value
|
||||
}
|
||||
diagnostics, explanation = result.Diagnostics, result.Explanation
|
||||
case "backend":
|
||||
var result commandkit.Acquired[*promptkit.BackendInspection]
|
||||
result, err = suite.InspectBackend(invocation.Context, BackendRequest{Selection: input.selection, ID: input.id}, input.selected, state)
|
||||
result, err = suite.InspectBackend(invocation.Context, BackendRequest{Selection: input.selection, ID: input.id, Namespaces: selectedNamespaces(suite.namespaces, input.namespaces)}, input.selected, state)
|
||||
if result.Value != nil {
|
||||
value = result.Value
|
||||
}
|
||||
@@ -518,7 +529,7 @@ func runRequirementsInspection[I, S any](invocation commandkit.Invocation, suite
|
||||
}
|
||||
}
|
||||
|
||||
request := RequirementsRequest{Selection: input.selection, Inspection: input.inspection}
|
||||
request := RequirementsRequest{Selection: input.selection, Inspection: input.inspection, Namespaces: selectedNamespaces(suite.namespaces, input.namespaces)}
|
||||
acquired, err := suite.InspectRequirements(invocation.Context, request, input.selected, state)
|
||||
queuePromptDiagnostics(invocation.Reporter(), acquired.Diagnostics)
|
||||
if err != nil {
|
||||
|
||||
69
integrations/ckprompt/namespaces.go
Normal file
69
integrations/ckprompt/namespaces.go
Normal file
@@ -0,0 +1,69 @@
|
||||
package ckprompt
|
||||
|
||||
import (
|
||||
commandkit "go.maximumdirect.net/commandkit"
|
||||
promptkit "go.maximumdirect.net/promptkit"
|
||||
)
|
||||
|
||||
// WithNamespaces enables standard resource namespace selection with explicit
|
||||
// defaults. Supplied CLI namespace flags replace only the corresponding default.
|
||||
// Loaders used with this option should leave namespace selection to the adapter.
|
||||
func WithNamespaces[I, S any](suite Suite[I, S], defaults promptkit.Namespaces) Suite[I, S] {
|
||||
suite.namespaces = &defaults
|
||||
return suite
|
||||
}
|
||||
|
||||
type namespaceInput struct {
|
||||
prompt, profile, backend commandkit.Supplied[string]
|
||||
}
|
||||
|
||||
func namespaceFlags[I any](destination func(*I) *namespaceInput, kinds ...string) []commandkit.Flag[I] {
|
||||
flags := make([]commandkit.Flag[I], 0, len(kinds))
|
||||
for _, kind := range kinds {
|
||||
var meta commandkit.FlagMeta
|
||||
var field func(*namespaceInput) *commandkit.Supplied[string]
|
||||
switch kind {
|
||||
case "prompt":
|
||||
meta = namespaceFlagDefinitions.prompt.meta
|
||||
field = func(input *namespaceInput) *commandkit.Supplied[string] { return &input.prompt }
|
||||
case "profile":
|
||||
meta = namespaceFlagDefinitions.profile.meta
|
||||
field = func(input *namespaceInput) *commandkit.Supplied[string] { return &input.profile }
|
||||
case "backend":
|
||||
meta = namespaceFlagDefinitions.backend.meta
|
||||
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 }))
|
||||
}
|
||||
return flags
|
||||
}
|
||||
|
||||
var namespaceFlagDefinitions = struct{ prompt, profile, backend requestFlagDefinition }{
|
||||
prompt: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-prompt-namespace", Usage: "Prompt resource namespace."}, []string{"prompt-namespace"}},
|
||||
profile: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-profile-namespace", Usage: "Profile resource namespace."}, []string{"profile-namespace"}},
|
||||
backend: requestFlagDefinition{commandkit.FlagMeta{Name: "llm-backend-namespace", Usage: "Backend resource namespace."}, []string{"backend-namespace"}},
|
||||
}
|
||||
|
||||
func selectedNamespaces(defaults *promptkit.Namespaces, selected namespaceInput) *promptkit.Namespaces {
|
||||
if defaults == nil {
|
||||
return nil
|
||||
}
|
||||
value := *defaults
|
||||
if selected.prompt.Set {
|
||||
value.Prompt = selected.prompt.Value
|
||||
}
|
||||
if selected.profile.Set {
|
||||
value.Profile = selected.profile.Value
|
||||
}
|
||||
if selected.backend.Set {
|
||||
value.Backend = selected.backend.Value
|
||||
}
|
||||
return &value
|
||||
}
|
||||
|
||||
func namespacedEngine(engine *promptkit.Engine, namespaces *promptkit.Namespaces) (*promptkit.Engine, error) {
|
||||
if namespaces == nil {
|
||||
return engine, nil
|
||||
}
|
||||
return engine.WithNamespaces(*namespaces)
|
||||
}
|
||||
146
integrations/ckprompt/namespaces_test.go
Normal file
146
integrations/ckprompt/namespaces_test.go
Normal file
@@ -0,0 +1,146 @@
|
||||
package ckprompt
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"io"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"go.maximumdirect.net/ckconfig"
|
||||
commandkit "go.maximumdirect.net/commandkit"
|
||||
promptkit "go.maximumdirect.net/promptkit"
|
||||
)
|
||||
|
||||
func TestNamespaceSelectionAndApplicability(t *testing.T) {
|
||||
var got *promptkit.Namespaces
|
||||
var id string
|
||||
suite := Suite[struct{}, struct{}]{
|
||||
InspectPrompt: func(_ context.Context, req PromptRequest, _, _ struct{}) (commandkit.Acquired[*promptkit.PromptInspection], error) {
|
||||
got, id = req.Namespaces, req.ID
|
||||
return commandkit.Acquired[*promptkit.PromptInspection]{Value: &promptkit.PromptInspection{}}, nil
|
||||
},
|
||||
InspectProfile: func(_ context.Context, req ProfileRequest, _, _ struct{}) (commandkit.Acquired[*promptkit.ProfileInspection], error) {
|
||||
got, id = req.Namespaces, req.ID
|
||||
return commandkit.Acquired[*promptkit.ProfileInspection]{Value: &promptkit.ProfileInspection{}}, nil
|
||||
},
|
||||
InspectBackend: func(_ context.Context, req BackendRequest, _, _ struct{}) (commandkit.Acquired[*promptkit.BackendInspection], error) {
|
||||
got, id = req.Namespaces, req.ID
|
||||
return commandkit.Acquired[*promptkit.BackendInspection]{Value: &promptkit.BackendInspection{}}, nil
|
||||
},
|
||||
InspectRequirements: func(_ context.Context, req RequirementsRequest, _, _ struct{}) (commandkit.Acquired[*promptkit.RequirementInspection], error) {
|
||||
got, id = req.Namespaces, req.Inspection.PromptID
|
||||
return commandkit.Acquired[*promptkit.RequirementInspection]{Value: &promptkit.RequirementInspection{}}, nil
|
||||
},
|
||||
ValidateRequest: func(_ context.Context, req ValidationRequest, _, _ struct{}) (commandkit.Acquired[struct{}], error) {
|
||||
got, id = req.Namespaces, req.Request.PromptID
|
||||
return commandkit.Acquired[struct{}]{}, nil
|
||||
},
|
||||
PrepareRequest: func(_ context.Context, req PreparationRequest, _, _ struct{}) (commandkit.Acquired[*promptkit.PreparedRun], error) {
|
||||
got, id = req.Namespaces, req.Request.PromptID
|
||||
return commandkit.Acquired[*promptkit.PreparedRun]{Value: &promptkit.PreparedRun{}}, nil
|
||||
},
|
||||
SmokeTest: func(_ context.Context, req SmokeRequest, _, _ struct{}) (commandkit.Acquired[*promptkit.SmokeTestReport], error) {
|
||||
got = req.Namespaces
|
||||
return commandkit.Acquired[*promptkit.SmokeTestReport]{Value: &promptkit.SmokeTestReport{}}, nil
|
||||
},
|
||||
ListPrompts: func(context.Context, CatalogRequest, struct{}, struct{}) (commandkit.Acquired[[]promptkit.PromptIdentity], error) {
|
||||
return commandkit.Acquired[[]promptkit.PromptIdentity]{}, nil
|
||||
},
|
||||
}
|
||||
defaults := promptkit.Namespaces{Prompt: "prompt-default", Profile: "profile-default", Backend: "backend-default"}
|
||||
app := newPromptTestApp(t, Command(WithNamespaces(suite, defaults)))
|
||||
tests := []struct {
|
||||
args []string
|
||||
allowed, forbidden string
|
||||
expected promptkit.Namespaces
|
||||
}{
|
||||
{[]string{"show", "prompt", "qualified/name"}, "--llm-prompt-namespace=", "--llm-profile-namespace=x", promptkit.Namespaces{Profile: defaults.Profile, Backend: defaults.Backend}},
|
||||
{[]string{"show", "profile", "qualified/name"}, "--llm-profile-namespace=other", "--llm-prompt-namespace=x", promptkit.Namespaces{Prompt: defaults.Prompt, Profile: "other", Backend: defaults.Backend}},
|
||||
{[]string{"show", "backend", "qualified/name"}, "--llm-backend-namespace=other", "--llm-profile-namespace=x", promptkit.Namespaces{Prompt: defaults.Prompt, Profile: defaults.Profile, Backend: "other"}},
|
||||
{[]string{"requirements", "show", "qualified/name"}, "--llm-profile-namespace=other", "--llm-backend-namespace=x", promptkit.Namespaces{Prompt: defaults.Prompt, Profile: "other", Backend: defaults.Backend}},
|
||||
{[]string{"requirements", "validate", "qualified/name"}, "--llm-backend-namespace=other", "--llm-prompt=invalid", promptkit.Namespaces{Prompt: defaults.Prompt, Profile: defaults.Profile, Backend: "other"}},
|
||||
{[]string{"show", "prepared", "qualified/name"}, "--llm-prompt-namespace=", "--llm-backend=invalid", promptkit.Namespaces{Profile: defaults.Profile, Backend: defaults.Backend}},
|
||||
{[]string{"test", "authentication"}, "--llm-backend-namespace=other", "--llm-session-id=invalid", promptkit.Namespaces{Prompt: defaults.Prompt, Profile: defaults.Profile, Backend: "other"}},
|
||||
}
|
||||
for _, test := range tests {
|
||||
got = nil
|
||||
id = ""
|
||||
args := append(append([]string{"promptkit"}, test.args...), test.allowed)
|
||||
result := app.Execute(context.Background(), args, commandkit.Streams{Out: io.Discard, Err: io.Discard})
|
||||
if result.Kind != commandkit.OutcomeSuccess || got == nil || *got != test.expected || (test.args[0] != "test" && id != "qualified/name") {
|
||||
t.Fatalf("%v: result=%#v got=%#v id=%q", args, result, got, id)
|
||||
}
|
||||
args = append(append([]string{"promptkit"}, test.args...), test.forbidden)
|
||||
if result := app.Execute(context.Background(), args, commandkit.Streams{Out: io.Discard, Err: io.Discard}); result.Kind != commandkit.OutcomeUsage {
|
||||
t.Fatalf("%v: %#v", args, result)
|
||||
}
|
||||
}
|
||||
unscoped := newPromptTestApp(t, Command(suite))
|
||||
result := unscoped.Execute(context.Background(), []string{"promptkit", "show", "prompt", "name"}, commandkit.Streams{Out: io.Discard, Err: io.Discard})
|
||||
if result.Kind != commandkit.OutcomeSuccess || got != nil {
|
||||
t.Fatalf("without option: %#v %#v", result, got)
|
||||
}
|
||||
result = unscoped.Execute(context.Background(), []string{"promptkit", "show", "prompt", "name", "--llm-prompt-namespace=x"}, commandkit.Streams{Out: io.Discard, Err: io.Discard})
|
||||
if result.Kind != commandkit.OutcomeUsage {
|
||||
t.Fatalf("unexpected flag without option: %#v", result)
|
||||
}
|
||||
result = app.Execute(context.Background(), []string{"promptkit", "list", "prompts", "--llm-prompt-namespace=x"}, commandkit.Streams{Out: io.Discard, Err: io.Discard})
|
||||
if result.Kind != commandkit.OutcomeUsage {
|
||||
t.Fatalf("namespace selection on catalog: %#v", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNativeNamespaceViewAndErrorForwarding(t *testing.T) {
|
||||
engine := adapterEngine(t)
|
||||
load := func(context.Context, ckconfig.Selection, struct{}, struct{}) (*promptkit.Engine, error) {
|
||||
return engine, nil
|
||||
}
|
||||
namespaces := promptkit.Namespaces{Prompt: "team"}
|
||||
view, err := engine.WithNamespaces(namespaces)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
want, err := view.InspectProfile(context.Background(), "default")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
suite := FromEngine(load)
|
||||
got, err := suite.InspectProfile(context.Background(), ProfileRequest{ID: "default", Namespaces: &namespaces}, struct{}{}, struct{}{})
|
||||
if err != nil || !reflect.DeepEqual(got.Value, want) {
|
||||
t.Fatalf("native view: %#v %v", got, err)
|
||||
}
|
||||
invalid := promptkit.Namespaces{Prompt: "invalid/name"}
|
||||
_, nativeErr := engine.WithNamespaces(invalid)
|
||||
_, err = suite.InspectProfile(context.Background(), ProfileRequest{ID: "default", Namespaces: &invalid}, struct{}{}, struct{}{})
|
||||
if nativeErr == nil || !errors.Is(err, promptkit.ErrInvalidConfig) {
|
||||
t.Fatalf("namespace error: native=%v forwarded=%v", nativeErr, err)
|
||||
}
|
||||
validation := WithRequestValidation(Suite[struct{}, struct{}]{}, load, nil)
|
||||
_, err = validation.ValidateRequest(context.Background(), ValidationRequest{Namespaces: &invalid}, struct{}{}, struct{}{})
|
||||
if !errors.Is(err, promptkit.ErrInvalidConfig) {
|
||||
t.Fatalf("validation namespace error: %v", err)
|
||||
}
|
||||
preparation := WithRequestPreparation(Suite[struct{}, struct{}]{}, load, nil)
|
||||
_, err = preparation.PrepareRequest(context.Background(), PreparationRequest{Namespaces: &invalid}, struct{}{}, struct{}{})
|
||||
if !errors.Is(err, promptkit.ErrInvalidConfig) {
|
||||
t.Fatalf("preparation namespace error: %v", err)
|
||||
}
|
||||
smoke := WithSmokeTesting(Suite[struct{}, struct{}]{}, load, nil)
|
||||
_, err = smoke.SmokeTest(context.Background(), SmokeRequest{Namespaces: &invalid}, struct{}{}, struct{}{})
|
||||
if !errors.Is(err, promptkit.ErrInvalidConfig) {
|
||||
t.Fatalf("smoke namespace error: %v", err)
|
||||
}
|
||||
preexisting, err := engine.WithNamespaces(promptkit.Namespaces{Profile: "other"})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, nativeErr = preexisting.InspectProfile(context.Background(), "default")
|
||||
custom := FromEngine(func(context.Context, ckconfig.Selection, struct{}, struct{}) (*promptkit.Engine, error) {
|
||||
return preexisting, nil
|
||||
})
|
||||
_, err = custom.InspectProfile(context.Background(), ProfileRequest{ID: "default"}, struct{}{}, struct{}{})
|
||||
if !errors.Is(nativeErr, promptkit.ErrProfileNotFound) || !errors.Is(err, promptkit.ErrProfileNotFound) {
|
||||
t.Fatalf("loader view: native=%v forwarded=%v", nativeErr, err)
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,8 @@ type PreparationRequest struct {
|
||||
Selection ckconfig.Selection
|
||||
// Request contains the native seed request populated by command inputs.
|
||||
Request promptkit.RunRequest
|
||||
// Namespaces selects the native engine view; nil preserves the loader view.
|
||||
Namespaces *promptkit.Namespaces
|
||||
}
|
||||
|
||||
// WithRequestPreparation attaches native prepared-request inspection. The
|
||||
@@ -55,6 +57,11 @@ func WithRequestPreparation[I, S any](
|
||||
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)
|
||||
}
|
||||
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
|
||||
}
|
||||
prepared, err := engine.Prepare(ctx, concrete)
|
||||
messages = messages.withOperationError(err)
|
||||
return commandkit.Acquired[*promptkit.PreparedRun]{Value: prepared, Diagnostics: messages.diagnostics, Explanation: messages.explanation}, err
|
||||
@@ -84,7 +91,7 @@ func runRequestPreparation[I, S any](invocation commandkit.Invocation, suite Sui
|
||||
if err := promptKitContextError(invocation.Context); err != nil {
|
||||
return definitionFailure("PromptKit request preparation was canceled.", commandkit.Explanation{}, err)
|
||||
}
|
||||
request := PreparationRequest{Selection: input.request.Selection, Request: input.request.Request}
|
||||
request := PreparationRequest{Selection: input.request.Selection, Request: input.request.Request, Namespaces: input.request.Namespaces}
|
||||
acquired, err := suite.PrepareRequest(invocation.Context, request, input.selected, state)
|
||||
queuePromptDiagnostics(invocation.Reporter(), acquired.Diagnostics)
|
||||
if err != nil {
|
||||
|
||||
@@ -18,6 +18,8 @@ type SmokeRequest struct {
|
||||
Selection ckconfig.Selection
|
||||
// Request contains the native smoke-test operation and its selected inputs.
|
||||
Request promptkit.SmokeTestRequest
|
||||
// Namespaces selects the native engine view; nil preserves the loader view.
|
||||
Namespaces *promptkit.Namespaces
|
||||
}
|
||||
|
||||
// WithSmokeTesting attaches PromptKit-backed smoke testing to suite while
|
||||
@@ -65,6 +67,11 @@ func WithSmokeTesting[I, S any](
|
||||
return commandkit.Acquired[*promptkit.SmokeTestReport]{Diagnostics: messages.diagnostics, Explanation: messages.explanation}, fmt.Errorf("PromptKit smoke test before native operation: %w", err)
|
||||
}
|
||||
|
||||
engine, err = namespacedEngine(engine, request.Namespaces)
|
||||
if err != nil {
|
||||
messages = messages.withOperationError(err)
|
||||
return commandkit.Acquired[*promptkit.SmokeTestReport]{Diagnostics: messages.diagnostics, Explanation: messages.explanation}, err
|
||||
}
|
||||
report, err := engine.SmokeTest(ctx, concreteRequest)
|
||||
messages = messages.withOperationError(err)
|
||||
return commandkit.Acquired[*promptkit.SmokeTestReport]{Value: report, Diagnostics: messages.diagnostics, Explanation: messages.explanation}, err
|
||||
|
||||
@@ -11,13 +11,14 @@ import (
|
||||
)
|
||||
|
||||
type smokeCommandInput[I any] struct {
|
||||
selection ckconfig.Selection
|
||||
kind string
|
||||
request promptkit.SmokeTestRequest
|
||||
execution ExecutionInput
|
||||
resources ResourceInput
|
||||
captured commandkit.FlagValues[I]
|
||||
selected I
|
||||
namespaces namespaceInput
|
||||
selection ckconfig.Selection
|
||||
kind string
|
||||
request promptkit.SmokeTestRequest
|
||||
execution ExecutionInput
|
||||
resources ResourceInput
|
||||
captured commandkit.FlagValues[I]
|
||||
selected I
|
||||
}
|
||||
|
||||
func newSmokeTestCommand[I, S any](suite Suite[I, S]) commandkit.Command {
|
||||
@@ -43,6 +44,10 @@ func newSmokeTestCommand[I, S any](suite Suite[I, S]) commandkit.Command {
|
||||
flags = append(flags, resources.Backend, resources.Prompt, resources.Profile)
|
||||
flags = append(flags, execution.All()...)
|
||||
|
||||
if suite.namespaces != nil {
|
||||
flags = append(flags, namespaceFlags(func(input **smokeCommandInput[I]) *namespaceInput { return &(*input).namespaces }, "prompt", "profile", "backend")...)
|
||||
}
|
||||
|
||||
return commandkit.NewCommand(commandkit.CommandSpec[*smokeCommandInput[I]]{
|
||||
Name: "test",
|
||||
Summary: "Run one PromptKit smoke test.",
|
||||
@@ -94,7 +99,7 @@ func runSmokeTest[I, S any](invocation commandkit.Invocation, suite Suite[I, S],
|
||||
return runSmokeAggregate(invocation, suite, input, state)
|
||||
}
|
||||
|
||||
request := SmokeRequest{Selection: input.selection, Request: input.request}
|
||||
request := SmokeRequest{Selection: input.selection, Request: input.request, Namespaces: selectedNamespaces(suite.namespaces, input.namespaces)}
|
||||
acquired, operationErr := suite.SmokeTest(invocation.Context, request, input.selected, state)
|
||||
queuePromptDiagnostics(invocation.Reporter(), acquired.Diagnostics)
|
||||
if acquired.Value == nil && operationErr == nil {
|
||||
@@ -143,7 +148,7 @@ func runSmokeAggregate[I, S any](invocation commandkit.Invocation, suite Suite[I
|
||||
}
|
||||
|
||||
seed := smokeRequestForKind(input.request, kind)
|
||||
acquired, operationErr := suite.SmokeTest(invocation.Context, SmokeRequest{Selection: input.selection, Request: seed}, input.selected, state)
|
||||
acquired, operationErr := suite.SmokeTest(invocation.Context, SmokeRequest{Selection: input.selection, Request: seed, Namespaces: selectedNamespaces(suite.namespaces, input.namespaces)}, input.selected, state)
|
||||
if acquired.Value == nil && operationErr == nil {
|
||||
operationErr = errors.New("PromptKit smoke test returned neither a report nor an error")
|
||||
}
|
||||
|
||||
@@ -13,4 +13,6 @@ type ValidationRequest struct {
|
||||
// Request contains the prompt identity, scalar context, variables, and
|
||||
// artifact references supplied to the command.
|
||||
Request promptkit.RunRequest
|
||||
// Namespaces selects the native engine view; nil preserves the loader view.
|
||||
Namespaces *promptkit.Namespaces
|
||||
}
|
||||
|
||||
@@ -8,13 +8,14 @@ import (
|
||||
)
|
||||
|
||||
type concreteRequestInput[I any] struct {
|
||||
promptID string
|
||||
request ValidationRequest
|
||||
execution ExecutionInput
|
||||
resources ResourceInput
|
||||
inputs PromptInputs
|
||||
captured commandkit.FlagValues[I]
|
||||
selected I
|
||||
namespaces namespaceInput
|
||||
promptID string
|
||||
request ValidationRequest
|
||||
execution ExecutionInput
|
||||
resources ResourceInput
|
||||
inputs PromptInputs
|
||||
captured commandkit.FlagValues[I]
|
||||
selected I
|
||||
}
|
||||
|
||||
type requestValidationReport struct {
|
||||
@@ -46,6 +47,10 @@ func newConcreteRequestSpec[I, S any](suite Suite[I, S]) commandkit.CommandSpec[
|
||||
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]{}
|
||||
@@ -62,6 +67,7 @@ func newConcreteRequestSpec[I, S any](suite Suite[I, S]) commandkit.CommandSpec[
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user