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

@@ -123,6 +123,11 @@ Validation: format and run `go test ./examples/go-library/prepare`. Ensure
imports and relative content still resolve from their contributing sources;
do not rewrite configuration fixtures merely to bypass path handling.
Completion: the preparation workflow accepts an explicit context, example
directory, and writer while preserving its inline checks and source contexts.
Its Go test verifies the retained summary, including explicit null collection
metadata, and passed on Go 1.27.0.
## Stage 3: Test The Observation Example And Its Output
Scope: `examples/go-library/observe/main.go` and its new `main_test.go`.

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)
}
}
}