Add PromptKit requirements adapter
This commit is contained in:
@@ -66,6 +66,26 @@ profiles:
|
||||
api_key_required: true
|
||||
`
|
||||
|
||||
const adapterRequirementsPrompt = `prompts:
|
||||
briefing:
|
||||
"1":
|
||||
default_profile: default
|
||||
session_id: '{{input "session-only"}} {{.session_variable}}'
|
||||
messages:
|
||||
- role: user
|
||||
content: '{{if eq .audience "internal"}}{{input "internal-notes"}}{{else}}{{input "public-notes"}}{{end}} {{.audience}}'
|
||||
output:
|
||||
format: text
|
||||
validation_mode: none
|
||||
backends:
|
||||
local:
|
||||
endpoint: "https://example.invalid/v1"
|
||||
profiles:
|
||||
default:
|
||||
backend: local
|
||||
model: example
|
||||
`
|
||||
|
||||
func adapterEngine(t *testing.T) *promptkit.Engine {
|
||||
return adapterEngineFrom(t, "adapter fixture", adapterPrompt)
|
||||
}
|
||||
@@ -321,11 +341,126 @@ func TestFromEnginePassesRequestsAndRetainsNilLoaderIssue(t *testing.T) {
|
||||
empty.ListProfiles = nil
|
||||
empty.InspectPrompt = nil
|
||||
empty.InspectProfile = nil
|
||||
empty.InspectRequirements = nil
|
||||
if len(empty.issues) != 1 || !strings.Contains(empty.issues[0].Error(), "PromptKit engine loader is nil") {
|
||||
t.Fatalf("nil-loader issue was lost when callbacks were cleared: %#v", empty.issues)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFromEngineInspectsRequirementsWithNativeRequest(t *testing.T) {
|
||||
type input struct{ value string }
|
||||
type state struct{ value string }
|
||||
type contextKey struct{}
|
||||
|
||||
engine := adapterEngineFrom(t, "requirements adapter fixture", adapterRequirementsPrompt)
|
||||
wantContext := context.WithValue(context.Background(), contextKey{}, "requirements invocation")
|
||||
wantInput := input{value: "typed input"}
|
||||
wantState := state{value: "shared state"}
|
||||
selection := ckconfig.Selection{
|
||||
Config: commandkit.Supplied[string]{Value: "prompt.yml", Set: true},
|
||||
Overlay: commandkit.Supplied[string]{Value: "overlay.yml", Set: true},
|
||||
}
|
||||
request := RequirementsRequest{
|
||||
Selection: selection,
|
||||
Inspection: promptkit.RequirementInspectionRequest{
|
||||
PromptID: "briefing",
|
||||
PromptVersion: "1",
|
||||
ProfileID: "default",
|
||||
Vars: map[string]string{"audience": "internal"},
|
||||
SessionID: "session-42",
|
||||
},
|
||||
}
|
||||
want, err := engine.InspectRequirements(wantContext, request.Inspection)
|
||||
if err != nil {
|
||||
t.Fatalf("direct native requirements inspection: %v", err)
|
||||
}
|
||||
|
||||
loaderCalls := 0
|
||||
suite := FromEngine(func(ctx context.Context, gotSelection ckconfig.Selection, gotInput input, gotState state) (*promptkit.Engine, error) {
|
||||
loaderCalls++
|
||||
if ctx.Value(contextKey{}) != "requirements invocation" || !reflect.DeepEqual(gotSelection, selection) || gotInput != wantInput || gotState != wantState {
|
||||
t.Errorf("loader args = ctx=%v selection=%#v input=%#v state=%#v", ctx.Value(contextKey{}), gotSelection, gotInput, gotState)
|
||||
}
|
||||
return engine, nil
|
||||
})
|
||||
acquired, err := suite.InspectRequirements(wantContext, request, wantInput, wantState)
|
||||
if err != nil || acquired.Value == nil || !reflect.DeepEqual(acquired.Value, want) || loaderCalls != 1 {
|
||||
t.Fatalf("requirements inspection = (%#v, %v), calls=%d; want native result %#v", acquired, err, loaderCalls, want)
|
||||
}
|
||||
if acquired.Value.PromptID != "briefing" || acquired.Value.PromptVersion != "1" || acquired.Value.ProfileID != "default" {
|
||||
t.Fatalf("requirements selection = %#v", acquired.Value)
|
||||
}
|
||||
inputs := make(map[string]promptkit.InputRequirement, len(acquired.Value.Inputs))
|
||||
for _, input := range acquired.Value.Inputs {
|
||||
inputs[input.Name] = input
|
||||
}
|
||||
if inputs["internal-notes"].Kind != promptkit.RequirementRequired || inputs["public-notes"].Kind != promptkit.RequirementOptional {
|
||||
t.Fatalf("caller variable did not reach native discovery: %#v", acquired.Value.Inputs)
|
||||
}
|
||||
if _, found := inputs["session-only"]; found {
|
||||
t.Fatalf("session template was not bypassed by the supplied session ID: %#v", acquired.Value.Inputs)
|
||||
}
|
||||
variables := make(map[string]promptkit.VariableRequirement, len(acquired.Value.Variables))
|
||||
for _, variable := range acquired.Value.Variables {
|
||||
variables[variable.Name] = variable
|
||||
}
|
||||
if !variables["audience"].Supplied {
|
||||
t.Fatalf("caller variable presence was not forwarded: %#v", acquired.Value.Variables)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFromEngineRequirementsRetainLoadDiagnosticsAndSelectionErrors(t *testing.T) {
|
||||
_, loadErr := configkit.Load[map[string]any](configkit.Bytes("invalid requirements configuration", []byte("broken: [")))
|
||||
if loadErr == nil {
|
||||
t.Fatal("invalid configuration unexpectedly loaded")
|
||||
}
|
||||
loadFailure := FromEngine[int, int](func(context.Context, ckconfig.Selection, int, int) (*promptkit.Engine, error) {
|
||||
return nil, loadErr
|
||||
})
|
||||
acquired, err := loadFailure.InspectRequirements(context.Background(), RequirementsRequest{}, 0, 0)
|
||||
var retained *configkit.LoadError
|
||||
if !errors.As(err, &retained) || retained != loadErr || len(acquired.Diagnostics) == 0 || acquired.Value != nil {
|
||||
t.Fatalf("requirements load failure = (%#v, %v), want original ConfigKit error and diagnostics", acquired, err)
|
||||
}
|
||||
if acquired.Diagnostics[0].Severity != commandkit.SeverityError {
|
||||
t.Fatalf("load diagnostics = %#v, want error severity", acquired.Diagnostics)
|
||||
}
|
||||
|
||||
nilEngine := FromEngine[int, int](func(context.Context, ckconfig.Selection, int, int) (*promptkit.Engine, error) {
|
||||
return nil, nil
|
||||
})
|
||||
acquired, err = nilEngine.InspectRequirements(context.Background(), RequirementsRequest{}, 0, 0)
|
||||
if err == nil || acquired.Value != nil || !strings.Contains(err.Error(), "nil engine") {
|
||||
t.Fatalf("nil engine result = (%#v, %v)", acquired, err)
|
||||
}
|
||||
|
||||
engine := adapterEngine(t)
|
||||
selectionFailure := FromEngine[int, int](func(context.Context, ckconfig.Selection, int, int) (*promptkit.Engine, error) {
|
||||
return engine, nil
|
||||
})
|
||||
acquired, err = selectionFailure.InspectRequirements(context.Background(), RequirementsRequest{
|
||||
Inspection: promptkit.RequirementInspectionRequest{PromptID: "missing", ProfileID: "default"},
|
||||
}, 0, 0)
|
||||
if !errors.Is(err, promptkit.ErrPromptNotFound) || acquired.Value != nil {
|
||||
t.Fatalf("native selection failure = (%#v, %v), want ErrPromptNotFound", acquired, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFromEngineRequirementsHonorCancellationAfterLoad(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
engine := adapterEngine(t)
|
||||
suite := FromEngine[int, int](func(context.Context, ckconfig.Selection, int, int) (*promptkit.Engine, error) {
|
||||
cancel()
|
||||
return engine, nil
|
||||
})
|
||||
acquired, err := suite.InspectRequirements(ctx, RequirementsRequest{
|
||||
Inspection: promptkit.RequirementInspectionRequest{PromptID: "briefing", ProfileID: "default"},
|
||||
}, 0, 0)
|
||||
if !errors.Is(err, context.Canceled) || acquired.Value != nil {
|
||||
t.Fatalf("cancelled requirements inspection = (%#v, %v)", acquired, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFromEngineListsNativeCatalogsWithInvocationValues(t *testing.T) {
|
||||
type input struct{ label string }
|
||||
type state struct{ label string }
|
||||
|
||||
Reference in New Issue
Block a user