Load prompt configuration comparison sides independently
This commit is contained in:
@@ -190,6 +190,8 @@ the actionable configuration problem through the same path.
|
||||
|
||||
## R5 — P3: Keep PromptKit Configuration Comparison Sides Independent
|
||||
|
||||
**Status:** Completed. The native configuration scope acquires each comparison side independently. A comparison with equal selections detects a resource edit between loads. Request commands retain invocation-local capture.
|
||||
|
||||
**Category**
|
||||
|
||||
Native behavior overridden in Stage 5.
|
||||
|
||||
@@ -44,13 +44,6 @@ func loadApplication(ctx context.Context, selection ckconfig.Selection, _ struct
|
||||
}
|
||||
|
||||
func loadPromptEngine(ctx context.Context, selection ckconfig.Selection, input struct{}, state *invocationState) (*pk.Engine, error) {
|
||||
if state != nil {
|
||||
for _, entry := range state.engines {
|
||||
if reflect.DeepEqual(entry.selection, selection) {
|
||||
return entry.engine, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
loaded, err := loadApplication(ctx, selection, input, state)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -63,12 +56,27 @@ func loadPromptEngine(ctx context.Context, selection ckconfig.Selection, input s
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if state != nil {
|
||||
state.engines = append(state.engines, engineEntry{selection: selection, engine: runtime.Engine})
|
||||
}
|
||||
return runtime.Engine, nil
|
||||
}
|
||||
|
||||
func capturePromptEngine(ctx context.Context, selection ckconfig.Selection, input struct{}, state *invocationState) (*pk.Engine, error) {
|
||||
if state != nil {
|
||||
for _, entry := range state.engines {
|
||||
if reflect.DeepEqual(entry.selection, selection) {
|
||||
return entry.engine, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
engine, err := loadPromptEngine(ctx, selection, input, state)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if state != nil {
|
||||
state.engines = append(state.engines, engineEntry{selection: selection, engine: engine})
|
||||
}
|
||||
return engine, nil
|
||||
}
|
||||
|
||||
func buildApplication(extra ...commandkit.Declaration) (*commandkit.App, error) {
|
||||
return buildApplicationWithClient(nil, extra...)
|
||||
}
|
||||
@@ -78,15 +86,15 @@ func buildApplicationWithClient(client *http.Client, extra ...commandkit.Declara
|
||||
appScope.Features.Overrides = true
|
||||
promptScope := ckprompt.ConfigScope(loadPromptEngine)
|
||||
configCommand := ckconfig.Command(ckconfig.Suite[struct{}, *invocationState]{NewState: func() *invocationState { return &invocationState{client: client} }, Scopes: []ckconfig.Scope[struct{}, *invocationState]{appScope, promptScope}})
|
||||
definitions := ckprompt.WithNamespaces(ckprompt.FromEngine(loadPromptEngine), pk.Namespaces{})
|
||||
definitions := ckprompt.WithNamespaces(ckprompt.FromEngine(capturePromptEngine), pk.Namespaces{})
|
||||
definitions.NewState = func() *invocationState { return &invocationState{client: client} }
|
||||
definitions = ckprompt.WithRequestValidation(definitions, loadPromptEngine, func(_ context.Context, seed ckprompt.ValidationRequest, _ struct{}, _ *invocationState) (pk.RunRequest, error) {
|
||||
definitions = ckprompt.WithRequestValidation(definitions, capturePromptEngine, func(_ context.Context, seed ckprompt.ValidationRequest, _ struct{}, _ *invocationState) (pk.RunRequest, error) {
|
||||
return applicationPromptRequest(seed.Request, seed.Namespaces), nil
|
||||
})
|
||||
definitions = ckprompt.WithRequestPreparation(definitions, loadPromptEngine, func(_ context.Context, seed ckprompt.PreparationRequest, _ struct{}, _ *invocationState) (pk.RunRequest, error) {
|
||||
definitions = ckprompt.WithRequestPreparation(definitions, capturePromptEngine, func(_ context.Context, seed ckprompt.PreparationRequest, _ struct{}, _ *invocationState) (pk.RunRequest, error) {
|
||||
return applicationPromptRequest(seed.Request, seed.Namespaces), nil
|
||||
})
|
||||
definitions = ckprompt.WithSmokeTesting(definitions, loadPromptEngine, nil)
|
||||
definitions = ckprompt.WithSmokeTesting(definitions, capturePromptEngine, nil)
|
||||
declarations := []commandkit.Declaration{configCommand, commandkit.Completion("audita"), processCommand()}
|
||||
declarations = append(declarations, ckprompt.Declarations(definitions)...)
|
||||
declarations = append(declarations, extra...)
|
||||
|
||||
@@ -11,6 +11,8 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"go.maximumdirect.net/ckconfig"
|
||||
"go.maximumdirect.net/ckprompt"
|
||||
commandkit "go.maximumdirect.net/commandkit"
|
||||
pk "go.maximumdirect.net/promptkit"
|
||||
)
|
||||
@@ -80,6 +82,40 @@ func TestExplicitEmptyConfigurationPathFails(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestPromptConfigurationComparisonAcquiresEqualSelectionsIndependently(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
main := filepath.Join(dir, "config.yml")
|
||||
if err := os.WriteFile(main, []byte("version: 3\n"), 0600); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
resource := filepath.Join(dir, "prompts.yml")
|
||||
writeProfile := func(model string) {
|
||||
t.Helper()
|
||||
if err := os.WriteFile(resource, []byte("profiles: [{id: local, model: "+model+"}]\n"), 0600); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
writeProfile("before")
|
||||
scope := ckprompt.ConfigScope(func(ctx context.Context, selection ckconfig.Selection, input struct{}, state *invocationState) (*pk.Engine, error) {
|
||||
engine, err := loadPromptEngine(ctx, selection, input, state)
|
||||
writeProfile("after")
|
||||
return engine, err
|
||||
})
|
||||
side := ckconfig.ComparisonSide[struct{}]{Selection: ckconfig.Selection{
|
||||
Config: commandkit.Supplied[string]{Value: main, Set: true},
|
||||
}}
|
||||
result, err := scope.Compare(context.Background(), ckconfig.ComparisonRequest[struct{}]{Left: side, Right: side}, &invocationState{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, difference := range result.Value {
|
||||
if strings.Contains(difference.Left.YAML, "before") && strings.Contains(difference.Right.YAML, "after") {
|
||||
return
|
||||
}
|
||||
}
|
||||
t.Fatal("comparison did not capture the model before and after the resource changed")
|
||||
}
|
||||
|
||||
func TestRequestInspectionAndExplicitSmokeUseSameSources(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
file := filepath.Join(dir, "config.yml")
|
||||
|
||||
Reference in New Issue
Block a user