Test the preparation example in Go
This commit is contained in:
@@ -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;
|
imports and relative content still resolve from their contributing sources;
|
||||||
do not rewrite configuration fixtures merely to bypass path handling.
|
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
|
## Stage 3: Test The Observation Example And Its Output
|
||||||
|
|
||||||
Scope: `examples/go-library/observe/main.go` and its new `main_test.go`.
|
Scope: `examples/go-library/observe/main.go` and its new `main_test.go`.
|
||||||
|
|||||||
@@ -4,7 +4,9 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
"go.maximumdirect.net/configkit"
|
"go.maximumdirect.net/configkit"
|
||||||
"go.maximumdirect.net/promptkit"
|
"go.maximumdirect.net/promptkit"
|
||||||
@@ -28,26 +30,33 @@ type collectionSummary struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
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, err := promptkit.CollectionInput(
|
||||||
"support",
|
"support",
|
||||||
configkit.File("examples/go-library/prepare/collections/support/collection.yaml"),
|
configkit.File(filepath.Join(exampleDir, "collections", "support", "collection.yaml")),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
exit(err)
|
return err
|
||||||
}
|
}
|
||||||
review, err := promptkit.CollectionInput(
|
review, err := promptkit.CollectionInput(
|
||||||
"review",
|
"review",
|
||||||
configkit.File("examples/go-library/prepare/collections/review/collection.yaml"),
|
configkit.File(filepath.Join(exampleDir, "collections", "review", "collection.yaml")),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
exit(err)
|
return err
|
||||||
}
|
}
|
||||||
override, err := promptkit.CollectionInput(
|
override, err := promptkit.CollectionInput(
|
||||||
"support",
|
"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 {
|
if err != nil {
|
||||||
exit(err)
|
return err
|
||||||
}
|
}
|
||||||
engine, err := promptkit.NewEngine(promptkit.Config{Sources: promptkit.ConfigurationSources{
|
engine, err := promptkit.NewEngine(promptkit.Config{Sources: promptkit.ConfigurationSources{
|
||||||
Underlays: []configkit.Underlay{
|
Underlays: []configkit.Underlay{
|
||||||
@@ -56,32 +65,31 @@ func main() {
|
|||||||
},
|
},
|
||||||
}})
|
}})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
exit(err)
|
return err
|
||||||
}
|
}
|
||||||
ctx := context.Background()
|
|
||||||
scoped, err := engine.WithNamespaces(promptkit.Namespaces{
|
scoped, err := engine.WithNamespaces(promptkit.Namespaces{
|
||||||
Prompt: "support", Profile: "support", Backend: "support",
|
Prompt: "support", Profile: "support", Backend: "support",
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
exit(err)
|
return err
|
||||||
}
|
}
|
||||||
view, err := engine.InspectConfiguration()
|
view, err := engine.InspectConfiguration()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
exit(err)
|
return err
|
||||||
}
|
}
|
||||||
if _, found := view.Explain(configkit.Keys("collections", "support", "profiles").Index(1).Key("timeout_seconds")); !found {
|
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{
|
requirements, err := scoped.InspectRequirements(ctx, promptkit.RequirementInspectionRequest{
|
||||||
PromptID: "prepare",
|
PromptID: "prepare",
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
exit(err)
|
return err
|
||||||
}
|
}
|
||||||
if !requirements.Complete || len(requirements.Inputs) != 1 ||
|
if !requirements.Complete || len(requirements.Inputs) != 1 ||
|
||||||
requirements.Inputs[0].Name != "note" ||
|
requirements.Inputs[0].Name != "note" ||
|
||||||
requirements.Inputs[0].Kind != promptkit.RequirementRequired {
|
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{
|
request := promptkit.RunRequest{
|
||||||
@@ -92,39 +100,39 @@ func main() {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
if err := scoped.ValidateRequest(ctx, request); err != nil {
|
if err := scoped.ValidateRequest(ctx, request); err != nil {
|
||||||
exit(err)
|
return err
|
||||||
}
|
}
|
||||||
prepared, err := scoped.Prepare(ctx, request)
|
prepared, err := scoped.Prepare(ctx, request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
exit(err)
|
return err
|
||||||
}
|
}
|
||||||
profile, err := scoped.InspectProfile(ctx, "fast")
|
profile, err := scoped.InspectProfile(ctx, "fast")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
exit(err)
|
return err
|
||||||
}
|
}
|
||||||
if profile.EffectiveModelParams.TimeoutSeconds != 30 {
|
if profile.EffectiveModelParams.TimeoutSeconds != 30 {
|
||||||
exit(fmt.Errorf(
|
return fmt.Errorf(
|
||||||
"later profile override was not applied: timeout is %d seconds",
|
"later profile override was not applied: timeout is %d seconds",
|
||||||
profile.EffectiveModelParams.TimeoutSeconds,
|
profile.EffectiveModelParams.TimeoutSeconds,
|
||||||
))
|
)
|
||||||
}
|
}
|
||||||
namespaces, err := scoped.ListNamespaces(ctx)
|
namespaces, err := scoped.ListNamespaces(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
exit(err)
|
return err
|
||||||
}
|
}
|
||||||
collections, err := scoped.ListCollections(ctx)
|
collections, err := scoped.ListCollections(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
exit(err)
|
return err
|
||||||
}
|
}
|
||||||
scopedPrompts, err := scoped.ListPrompts(ctx)
|
scopedPrompts, err := scoped.ListPrompts(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
exit(err)
|
return err
|
||||||
}
|
}
|
||||||
reviewPrompts, err := scoped.ListPrompts(ctx, promptkit.NamespaceFilter{
|
reviewPrompts, err := scoped.ListPrompts(ctx, promptkit.NamespaceFilter{
|
||||||
Mode: promptkit.NamespaceNamed, Name: "review",
|
Mode: promptkit.NamespaceNamed, Name: "review",
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
exit(err)
|
return err
|
||||||
}
|
}
|
||||||
scopedPromptIDs := make([]string, len(scopedPrompts))
|
scopedPromptIDs := make([]string, len(scopedPrompts))
|
||||||
for index := range scopedPrompts {
|
for index := range scopedPrompts {
|
||||||
@@ -141,9 +149,9 @@ func main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
encoder := json.NewEncoder(os.Stdout)
|
encoder := json.NewEncoder(out)
|
||||||
encoder.SetIndent("", " ")
|
encoder.SetIndent("", " ")
|
||||||
if err := encoder.Encode(summary{
|
return encoder.Encode(summary{
|
||||||
PromptID: prepared.PromptID,
|
PromptID: prepared.PromptID,
|
||||||
SelectedProfile: prepared.SelectedProfileID,
|
SelectedProfile: prepared.SelectedProfileID,
|
||||||
Model: prepared.EffectiveModelParams.Model,
|
Model: prepared.EffectiveModelParams.Model,
|
||||||
@@ -153,12 +161,5 @@ func main() {
|
|||||||
Collections: collectionSummaries,
|
Collections: collectionSummaries,
|
||||||
ScopedPrompts: scopedPromptIDs,
|
ScopedPrompts: scopedPromptIDs,
|
||||||
ReviewPrompts: reviewPromptIDs,
|
ReviewPrompts: reviewPromptIDs,
|
||||||
}); err != nil {
|
})
|
||||||
exit(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func exit(err error) {
|
|
||||||
fmt.Fprintln(os.Stderr, err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
|
|||||||
45
examples/go-library/prepare/main_test.go
Normal file
45
examples/go-library/prepare/main_test.go
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user