Migrate composed PromptKit consumer
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
# PromptKit v0.18.0 implementation plan
|
# PromptKit v0.18.0 implementation plan
|
||||||
|
|
||||||
Status: Stages 1–4 complete; Stages 5–7 remain.
|
Status: Stages 1–5 complete; Stages 6–7 remain.
|
||||||
|
|
||||||
## Authority and execution
|
## Authority and execution
|
||||||
|
|
||||||
@@ -177,6 +177,8 @@ package tests to guide corrections; full final validation is Stage 7.
|
|||||||
|
|
||||||
## Stage 5: Migrate the composed consumer and its tests
|
## Stage 5: Migrate the composed consumer and its tests
|
||||||
|
|
||||||
|
**Complete.** The composed suite passes with identified lists, the native bundle, and explicit local smoke targets; the aggregate report was inspected.
|
||||||
|
|
||||||
1. In `examples/composed/main.go`, convert the root resources and `field-notes`
|
1. In `examples/composed/main.go`, convert the root resources and `field-notes`
|
||||||
collection resources assembled by `loadPromptEngine` to identified lists.
|
collection resources assembled by `loadPromptEngine` to identified lists.
|
||||||
Preserve qualified stored references such as `field-notes/demo` and
|
Preserve qualified stored references such as `field-notes/demo` and
|
||||||
|
|||||||
@@ -2,11 +2,9 @@ default_campaign: autumn
|
|||||||
campaigns:
|
campaigns:
|
||||||
spring:
|
spring:
|
||||||
prompt_id: briefing
|
prompt_id: briefing
|
||||||
prompt_version: "1"
|
|
||||||
profile_id: spring
|
profile_id: spring
|
||||||
model: spring-model-after
|
model: spring-model-after
|
||||||
autumn:
|
autumn:
|
||||||
prompt_id: briefing
|
prompt_id: briefing
|
||||||
prompt_version: "1"
|
|
||||||
profile_id: autumn
|
profile_id: autumn
|
||||||
model: autumn-model
|
model: autumn-model
|
||||||
|
|||||||
@@ -2,11 +2,9 @@ default_campaign: spring
|
|||||||
campaigns:
|
campaigns:
|
||||||
spring:
|
spring:
|
||||||
prompt_id: briefing
|
prompt_id: briefing
|
||||||
prompt_version: "1"
|
|
||||||
profile_id: spring
|
profile_id: spring
|
||||||
model: spring-model
|
model: spring-model
|
||||||
autumn:
|
autumn:
|
||||||
prompt_id: briefing
|
prompt_id: briefing
|
||||||
prompt_version: "1"
|
|
||||||
profile_id: autumn
|
profile_id: autumn
|
||||||
model: autumn-model
|
model: autumn-model
|
||||||
|
|||||||
@@ -8,16 +8,15 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
configkit "go.maximumdirect.net/configkit"
|
|
||||||
promptkit "go.maximumdirect.net/promptkit"
|
|
||||||
"go.maximumdirect.net/ckconfig"
|
"go.maximumdirect.net/ckconfig"
|
||||||
"go.maximumdirect.net/ckprompt"
|
"go.maximumdirect.net/ckprompt"
|
||||||
commandkit "go.maximumdirect.net/commandkit"
|
commandkit "go.maximumdirect.net/commandkit"
|
||||||
|
configkit "go.maximumdirect.net/configkit"
|
||||||
|
promptkit "go.maximumdirect.net/promptkit"
|
||||||
)
|
)
|
||||||
|
|
||||||
type campaign struct {
|
type campaign struct {
|
||||||
PromptID string `yaml:"prompt_id"`
|
PromptID string `yaml:"prompt_id"`
|
||||||
PromptVersion string `yaml:"prompt_version"`
|
|
||||||
ProfileID string `yaml:"profile_id"`
|
ProfileID string `yaml:"profile_id"`
|
||||||
Model string `yaml:"model"`
|
Model string `yaml:"model"`
|
||||||
}
|
}
|
||||||
@@ -90,8 +89,8 @@ func loadApplicationConfig(ctx context.Context, selection ckconfig.Selection, in
|
|||||||
source := configkit.Mapping("composed application settings", map[string]any{
|
source := configkit.Mapping("composed application settings", map[string]any{
|
||||||
"default_campaign": "spring",
|
"default_campaign": "spring",
|
||||||
"campaigns": map[string]any{
|
"campaigns": map[string]any{
|
||||||
"spring": map[string]any{"prompt_id": "briefing", "prompt_version": "1", "profile_id": "spring", "model": "spring-model"},
|
"spring": map[string]any{"prompt_id": "briefing", "profile_id": "spring", "model": "spring-model"},
|
||||||
"autumn": map[string]any{"prompt_id": "briefing", "prompt_version": "1", "profile_id": "autumn", "model": "autumn-model"},
|
"autumn": map[string]any{"prompt_id": "briefing", "profile_id": "autumn", "model": "autumn-model"},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
if selection.Config.Set {
|
if selection.Config.Set {
|
||||||
@@ -128,10 +127,10 @@ func loadPromptEngine(ctx context.Context, selection ckconfig.Selection, input *
|
|||||||
"collections": map[string]any{
|
"collections": map[string]any{
|
||||||
"field-notes": map[string]any{
|
"field-notes": map[string]any{
|
||||||
"release_version": "1",
|
"release_version": "1",
|
||||||
"backends": map[string]any{"demo": map[string]any{"endpoint": "https://example.invalid/v1"}},
|
"backends": []any{map[string]any{"id": "demo", "endpoint": "https://example.invalid/v1"}},
|
||||||
"profiles": map[string]any{"assistant": map[string]any{"backend": "field-notes/demo", "model": "example-model"}},
|
"profiles": []any{map[string]any{"id": "assistant", "backend": "field-notes/demo", "model": "example-model"}},
|
||||||
"prompts": map[string]any{"briefing": map[string]any{
|
"prompts": []any{map[string]any{
|
||||||
"version": "1",
|
"id": "briefing",
|
||||||
"default_profile": "field-notes/assistant",
|
"default_profile": "field-notes/assistant",
|
||||||
"inputs": []any{map[string]any{"name": "topic", "required": true, "content_type": "text/plain", "description": "Topic to brief"}},
|
"inputs": []any{map[string]any{"name": "topic", "required": true, "content_type": "text/plain", "description": "Topic to brief"}},
|
||||||
"messages": []any{map[string]any{"role": "user", "content": "Write a concise briefing about {{.topic}}."}},
|
"messages": []any{map[string]any{"role": "user", "content": "Write a concise briefing about {{.topic}}."}},
|
||||||
@@ -139,15 +138,18 @@ func loadPromptEngine(ctx context.Context, selection ckconfig.Selection, input *
|
|||||||
}},
|
}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"profiles": map[string]any{chosen.ProfileID: map[string]any{
|
"backends": []any{map[string]any{"id": "local", "endpoint": "https://example.invalid/v1"}},
|
||||||
|
"profiles": []any{map[string]any{
|
||||||
|
"id": chosen.ProfileID,
|
||||||
|
"backend": "local",
|
||||||
"endpoint": "https://example.invalid/v1",
|
"endpoint": "https://example.invalid/v1",
|
||||||
"model": chosen.Model,
|
"model": chosen.Model,
|
||||||
"extra_params": map[string]any{
|
"extra_params": map[string]any{
|
||||||
"campaign": name,
|
"campaign": name,
|
||||||
},
|
},
|
||||||
}},
|
}},
|
||||||
"prompts": map[string]any{chosen.PromptID: map[string]any{
|
"prompts": []any{map[string]any{
|
||||||
"version": chosen.PromptVersion,
|
"id": chosen.PromptID,
|
||||||
"default_profile": chosen.ProfileID,
|
"default_profile": chosen.ProfileID,
|
||||||
"inputs": []any{map[string]any{"name": "topic", "required": true, "content_type": "text/plain", "description": "Topic to brief"}},
|
"inputs": []any{map[string]any{"name": "topic", "required": true, "content_type": "text/plain", "description": "Topic to brief"}},
|
||||||
"messages": []any{map[string]any{"role": "user", "content": "Write a concise briefing about {{.topic}}. {{if .mode}}{{input \"notes\"}}{{end}}"}},
|
"messages": []any{map[string]any{"role": "user", "content": "Write a concise briefing about {{.topic}}. {{if .mode}}{{input \"notes\"}}{{end}}"}},
|
||||||
|
|||||||
@@ -4,16 +4,17 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
configkit "go.maximumdirect.net/configkit"
|
|
||||||
promptkit "go.maximumdirect.net/promptkit"
|
|
||||||
"go.maximumdirect.net/ckconfig"
|
"go.maximumdirect.net/ckconfig"
|
||||||
"go.maximumdirect.net/ckprompt"
|
"go.maximumdirect.net/ckprompt"
|
||||||
commandkit "go.maximumdirect.net/commandkit"
|
commandkit "go.maximumdirect.net/commandkit"
|
||||||
|
configkit "go.maximumdirect.net/configkit"
|
||||||
|
promptkit "go.maximumdirect.net/promptkit"
|
||||||
"go.yaml.in/yaml/v4"
|
"go.yaml.in/yaml/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -105,11 +106,41 @@ func TestComposedPromptKitAndDomainCommandsRemainAvailable(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
engine, err := loadPromptEngine(context.Background(), ckconfig.Selection{}, &inspectionInput{Campaign: commandkit.Supplied[string]{Value: "spring", Set: true}}, nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
inspection, err := engine.InspectConfiguration()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
var effective bytes.Buffer
|
||||||
|
if err := inspection.WriteEffective(&effective); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
var config struct {
|
||||||
|
Profiles []struct {
|
||||||
|
ID string `yaml:"id"`
|
||||||
|
} `yaml:"profiles"`
|
||||||
|
}
|
||||||
|
if err := yaml.Unmarshal(effective.Bytes(), &config); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
index := -1
|
||||||
|
for i, profile := range config.Profiles {
|
||||||
|
if profile.ID == "spring" {
|
||||||
|
index = i
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if index < 0 {
|
||||||
|
t.Fatal("selected profile missing from configuration")
|
||||||
|
}
|
||||||
commands := [][]string{
|
commands := [][]string{
|
||||||
{"config", "validate", "--scope", "all", "--campaign", "spring", "--limit=0"},
|
{"config", "validate", "--scope", "all", "--campaign", "spring", "--limit=0"},
|
||||||
{"config", "show", "--scope", "promptkit", "--campaign", "spring"},
|
{"config", "show", "--scope", "promptkit", "--campaign", "spring"},
|
||||||
{"config", "sources", "--scope", "promptkit", "--campaign", "spring"},
|
{"config", "sources", "--scope", "promptkit", "--campaign", "spring"},
|
||||||
{"config", "explain", "--scope", "promptkit", "--path", "/profiles/spring/model", "--campaign", "spring"},
|
{"config", "explain", "--scope", "promptkit", "--path", fmt.Sprintf("/profiles/%d/model", index), "--campaign", "spring"},
|
||||||
{"promptkit", "show", "prompt", "briefing", "--campaign", "spring", "--format", "yaml"},
|
{"promptkit", "show", "prompt", "briefing", "--campaign", "spring", "--format", "yaml"},
|
||||||
{"promptkit", "show", "profile", "spring", "--campaign", "spring"},
|
{"promptkit", "show", "profile", "spring", "--campaign", "spring"},
|
||||||
{"session", "restore", "session-42", "--campaign", "spring"},
|
{"session", "restore", "session-42", "--campaign", "spring"},
|
||||||
@@ -146,12 +177,15 @@ func TestComposedRequirementsDiscoveryUsesSelectedCampaign(t *testing.T) {
|
|||||||
if err := yaml.Unmarshal(output.Bytes(), &report); err != nil {
|
if err := yaml.Unmarshal(output.Bytes(), &report); err != nil {
|
||||||
t.Fatalf("decode requirements report %q: %v", output.String(), err)
|
t.Fatalf("decode requirements report %q: %v", output.String(), err)
|
||||||
}
|
}
|
||||||
for _, key := range []string{"prompt_id", "version", "profile_id", "complete", "inputs", "variables", "issues"} {
|
for _, key := range []string{"prompt_id", "profile_id", "complete", "inputs", "variables", "issues"} {
|
||||||
if _, found := report[key]; !found {
|
if _, found := report[key]; !found {
|
||||||
t.Errorf("requirements report is missing %q: %#v", key, report)
|
t.Errorf("requirements report is missing %q: %#v", key, report)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if report["prompt_id"] != "briefing" || report["version"] != "1" || report["profile_id"] != "spring" {
|
if _, exists := report["version"]; exists {
|
||||||
|
t.Fatalf("unexpected prompt version: %#v", report)
|
||||||
|
}
|
||||||
|
if report["prompt_id"] != "briefing" || report["profile_id"] != "spring" {
|
||||||
t.Fatalf("requirements report metadata = %#v", report)
|
t.Fatalf("requirements report metadata = %#v", report)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -267,9 +301,25 @@ func TestPromptKitScopeDiffAndCatalogsUseSelectedCampaign(t *testing.T) {
|
|||||||
if outcome.Kind != commandkit.OutcomeSuccess {
|
if outcome.Kind != commandkit.OutcomeSuccess {
|
||||||
t.Fatalf("PromptKit diff outcome = %#v", outcome)
|
t.Fatalf("PromptKit diff outcome = %#v", outcome)
|
||||||
}
|
}
|
||||||
value := composedReportValue(t, output.Bytes(), "changes", "profiles", "spring", "model")
|
var diff struct {
|
||||||
if value == nil || value.Value != "spring-model-after" {
|
Changes struct {
|
||||||
t.Fatalf("PromptKit diff spring model = %#v; report %q", value, output.String())
|
Profiles []struct {
|
||||||
|
ID string `yaml:"id"`
|
||||||
|
Model string `yaml:"model"`
|
||||||
|
} `yaml:"profiles"`
|
||||||
|
} `yaml:"changes"`
|
||||||
|
}
|
||||||
|
if err := yaml.Unmarshal(output.Bytes(), &diff); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
foundChange := false
|
||||||
|
for _, profile := range diff.Changes.Profiles {
|
||||||
|
if profile.ID == "spring" && profile.Model == "spring-model-after" {
|
||||||
|
foundChange = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !foundChange {
|
||||||
|
t.Fatalf("PromptKit diff missing spring model: %q", output.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
output.Reset()
|
output.Reset()
|
||||||
@@ -283,7 +333,7 @@ func TestPromptKitScopeDiffAndCatalogsUseSelectedCampaign(t *testing.T) {
|
|||||||
}
|
}
|
||||||
foundPrompt := false
|
foundPrompt := false
|
||||||
for _, prompt := range prompts {
|
for _, prompt := range prompts {
|
||||||
if prompt["id"] == "briefing" && prompt["version"] == "1" {
|
if prompt["id"] == "briefing" && len(prompt) == 1 {
|
||||||
foundPrompt = true
|
foundPrompt = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user