Test the preparation example in Go

This commit is contained in:
2026-11-03 01:37:44 +00:00
parent 8896d8733b
commit 3e3cc677fb
3 changed files with 83 additions and 32 deletions

View File

@@ -4,7 +4,9 @@ import (
"context"
"encoding/json"
"fmt"
"io"
"os"
"path/filepath"
"go.maximumdirect.net/configkit"
"go.maximumdirect.net/promptkit"
@@ -28,26 +30,33 @@ type collectionSummary struct {
}
func main() {
if err := run(context.Background(), "examples/go-library/prepare", os.Stdout); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}
func run(ctx context.Context, exampleDir string, out io.Writer) error {
support, err := promptkit.CollectionInput(
"support",
configkit.File("examples/go-library/prepare/collections/support/collection.yaml"),
configkit.File(filepath.Join(exampleDir, "collections", "support", "collection.yaml")),
)
if err != nil {
exit(err)
return err
}
review, err := promptkit.CollectionInput(
"review",
configkit.File("examples/go-library/prepare/collections/review/collection.yaml"),
configkit.File(filepath.Join(exampleDir, "collections", "review", "collection.yaml")),
)
if err != nil {
exit(err)
return err
}
override, err := promptkit.CollectionInput(
"support",
configkit.File("examples/go-library/prepare/collections/support/operator-overrides.yaml"),
configkit.File(filepath.Join(exampleDir, "collections", "support", "operator-overrides.yaml")),
)
if err != nil {
exit(err)
return err
}
engine, err := promptkit.NewEngine(promptkit.Config{Sources: promptkit.ConfigurationSources{
Underlays: []configkit.Underlay{
@@ -56,32 +65,31 @@ func main() {
},
}})
if err != nil {
exit(err)
return err
}
ctx := context.Background()
scoped, err := engine.WithNamespaces(promptkit.Namespaces{
Prompt: "support", Profile: "support", Backend: "support",
})
if err != nil {
exit(err)
return err
}
view, err := engine.InspectConfiguration()
if err != nil {
exit(err)
return err
}
if _, found := view.Explain(configkit.Keys("collections", "support", "profiles").Index(1).Key("timeout_seconds")); !found {
exit(fmt.Errorf("collection profile override was not found"))
return fmt.Errorf("collection profile override was not found")
}
requirements, err := scoped.InspectRequirements(ctx, promptkit.RequirementInspectionRequest{
PromptID: "prepare",
})
if err != nil {
exit(err)
return err
}
if !requirements.Complete || len(requirements.Inputs) != 1 ||
requirements.Inputs[0].Name != "note" ||
requirements.Inputs[0].Kind != promptkit.RequirementRequired {
exit(fmt.Errorf("required note input was not discovered before preparation"))
return fmt.Errorf("required note input was not discovered before preparation")
}
request := promptkit.RunRequest{
@@ -92,39 +100,39 @@ func main() {
},
}
if err := scoped.ValidateRequest(ctx, request); err != nil {
exit(err)
return err
}
prepared, err := scoped.Prepare(ctx, request)
if err != nil {
exit(err)
return err
}
profile, err := scoped.InspectProfile(ctx, "fast")
if err != nil {
exit(err)
return err
}
if profile.EffectiveModelParams.TimeoutSeconds != 30 {
exit(fmt.Errorf(
return fmt.Errorf(
"later profile override was not applied: timeout is %d seconds",
profile.EffectiveModelParams.TimeoutSeconds,
))
)
}
namespaces, err := scoped.ListNamespaces(ctx)
if err != nil {
exit(err)
return err
}
collections, err := scoped.ListCollections(ctx)
if err != nil {
exit(err)
return err
}
scopedPrompts, err := scoped.ListPrompts(ctx)
if err != nil {
exit(err)
return err
}
reviewPrompts, err := scoped.ListPrompts(ctx, promptkit.NamespaceFilter{
Mode: promptkit.NamespaceNamed, Name: "review",
})
if err != nil {
exit(err)
return err
}
scopedPromptIDs := make([]string, len(scopedPrompts))
for index := range scopedPrompts {
@@ -141,9 +149,9 @@ func main() {
}
}
encoder := json.NewEncoder(os.Stdout)
encoder := json.NewEncoder(out)
encoder.SetIndent("", " ")
if err := encoder.Encode(summary{
return encoder.Encode(summary{
PromptID: prepared.PromptID,
SelectedProfile: prepared.SelectedProfileID,
Model: prepared.EffectiveModelParams.Model,
@@ -153,12 +161,5 @@ func main() {
Collections: collectionSummaries,
ScopedPrompts: scopedPromptIDs,
ReviewPrompts: reviewPromptIDs,
}); err != nil {
exit(err)
}
}
func exit(err error) {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
})
}

View File

@@ -0,0 +1,45 @@
package main
import (
"bytes"
"encoding/json"
"reflect"
"testing"
)
func TestPrepareExample(t *testing.T) {
var output bytes.Buffer
if err := run(t.Context(), ".", &output); err != nil {
t.Fatal(err)
}
var got struct {
PromptID string `json:"prompt_id"`
Profile string `json:"selected_profile"`
Model string `json:"model"`
MessageCount int `json:"message_count"`
Timeout int `json:"profile_timeout_seconds"`
Namespaces []string `json:"namespaces"`
Collections []map[string]json.RawMessage `json:"collections"`
ScopedPrompts []string `json:"scoped_prompts"`
ReviewPrompts []string `json:"review_prompts"`
}
if err := json.Unmarshal(output.Bytes(), &got); err != nil {
t.Fatal(err)
}
if got.PromptID != "support/prepare" || got.Profile != "support/fast" || got.Model != "offline-model" ||
got.MessageCount <= 0 || got.Timeout != 30 || !reflect.DeepEqual(got.Namespaces, []string{"review", "support"}) ||
!reflect.DeepEqual(got.ScopedPrompts, []string{"support/prepare"}) || !reflect.DeepEqual(got.ReviewPrompts, []string{"review/check"}) || len(got.Collections) != 2 {
t.Fatalf("unexpected preparation summary: %+v", got)
}
for index, want := range []struct{ namespace, release string }{{"review", ""}, {"support", "1.4.0"}} {
var namespace string
if err := json.Unmarshal(got.Collections[index]["namespace"], &namespace); err != nil || namespace != want.namespace {
t.Fatalf("collection namespace = %q, %v", namespace, err)
}
value, present := got.Collections[index]["release_version"]
var release *string
if !present || json.Unmarshal(value, &release) != nil || (index == 0 && release != nil) || (index == 1 && (release == nil || *release != want.release)) {
t.Fatalf("collection release = %s, present %t; want %q", value, present, want.release)
}
}
}