Move integration code into optional modules
This commit is contained in:
@@ -1,18 +0,0 @@
|
||||
# Composed consumer
|
||||
|
||||
This example composes application configuration, PromptKit configuration,
|
||||
definition inspection, and one application-owned command:
|
||||
|
||||
```sh
|
||||
go run . config scopes
|
||||
go run . config validate --scope all --campaign spring
|
||||
go run . promptkit show prompt briefing --campaign spring --format yaml
|
||||
go run . promptkit show profile spring --campaign spring
|
||||
go run . session restore session-42 --campaign spring
|
||||
```
|
||||
|
||||
The sources and session store are small in-memory fixtures. `--campaign` is a
|
||||
typed selector shared by the app and PromptKit configuration scopes. Their
|
||||
scope contexts share a per-invocation cache created by `ConfigSuite.NewContext`.
|
||||
Prompt/profile inspection has its own invocation context and composes the same
|
||||
application and engine loader functions.
|
||||
@@ -1,223 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
commandkit "gitea.maximumdirect.net/eric/CommandKit"
|
||||
configkit "gitea.maximumdirect.net/eric/ConfigKit"
|
||||
"gitea.maximumdirect.net/eric/promptkit"
|
||||
)
|
||||
|
||||
type campaign struct {
|
||||
PromptID string `yaml:"prompt_id"`
|
||||
PromptVersion string `yaml:"prompt_version"`
|
||||
ProfileID string `yaml:"profile_id"`
|
||||
Model string `yaml:"model"`
|
||||
}
|
||||
|
||||
type appConfiguration struct {
|
||||
DefaultCampaign string `yaml:"default_campaign"`
|
||||
Campaigns map[string]campaign `yaml:"campaigns"`
|
||||
}
|
||||
|
||||
type invocationCache struct {
|
||||
application *configkit.Result[appConfiguration]
|
||||
}
|
||||
|
||||
type configContext struct {
|
||||
Cache *invocationCache
|
||||
Campaign commandkit.Supplied[string]
|
||||
}
|
||||
|
||||
type definitionContext struct {
|
||||
Cache *invocationCache
|
||||
Campaign commandkit.Supplied[string]
|
||||
}
|
||||
|
||||
type restoreInput struct {
|
||||
Campaign commandkit.Supplied[string]
|
||||
Session string
|
||||
}
|
||||
|
||||
type session struct {
|
||||
ID string
|
||||
Campaign string
|
||||
Summary string
|
||||
}
|
||||
|
||||
type sessionStore struct {
|
||||
active string
|
||||
records map[string]session
|
||||
}
|
||||
|
||||
func loadApplicationConfig(_ context.Context, _ commandkit.Selection, cache *invocationCache) (*configkit.Result[appConfiguration], error) {
|
||||
if cache != nil && cache.application != nil {
|
||||
return cache.application, nil
|
||||
}
|
||||
result, err := configkit.Load[appConfiguration](configkit.Mapping("composed app config", map[string]any{
|
||||
"default_campaign": "spring",
|
||||
"campaigns": map[string]any{
|
||||
"spring": map[string]any{"prompt_id": "briefing", "prompt_version": "1", "profile_id": "spring", "model": "spring-model"},
|
||||
"autumn": map[string]any{"prompt_id": "briefing", "prompt_version": "1", "profile_id": "autumn", "model": "autumn-model"},
|
||||
},
|
||||
}))
|
||||
if err == nil && cache != nil {
|
||||
cache.application = result
|
||||
}
|
||||
return result, err
|
||||
}
|
||||
|
||||
func selectedCampaign(configuration appConfiguration, supplied commandkit.Supplied[string]) (string, campaign, error) {
|
||||
name := configuration.DefaultCampaign
|
||||
if supplied.Set {
|
||||
name = supplied.Value
|
||||
}
|
||||
value, ok := configuration.Campaigns[name]
|
||||
if !ok {
|
||||
return "", campaign{}, fmt.Errorf("unknown campaign %q", name)
|
||||
}
|
||||
return name, value, nil
|
||||
}
|
||||
|
||||
func loadPromptEngine(ctx context.Context, selection commandkit.Selection, cache *invocationCache, selected commandkit.Supplied[string]) (*promptkit.Engine, error) {
|
||||
application, err := loadApplicationConfig(ctx, selection, cache)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
name, chosen, err := selectedCampaign(application.Config, selected)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
engineConfig := configkit.Mapping("campaign "+name, map[string]any{
|
||||
"profiles": map[string]any{chosen.ProfileID: map[string]any{
|
||||
"endpoint": "https://example.invalid/v1",
|
||||
"model": chosen.Model,
|
||||
"extra_params": map[string]any{
|
||||
"campaign": name,
|
||||
},
|
||||
}},
|
||||
"prompts": map[string]any{chosen.PromptID: map[string]any{
|
||||
chosen.PromptVersion: map[string]any{
|
||||
"default_profile": chosen.ProfileID,
|
||||
"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}}."}},
|
||||
"output": map[string]any{"format": "text", "validation_mode": "none"},
|
||||
},
|
||||
}},
|
||||
})
|
||||
return promptkit.NewEngine(promptkit.Config{Sources: promptkit.ConfigurationSources{Main: &configkit.Input{Source: engineConfig}}})
|
||||
}
|
||||
|
||||
func campaignSelector[C any](set func(*C, commandkit.Supplied[string])) commandkit.Selector[C] {
|
||||
return commandkit.Selector[C]{
|
||||
Binding: commandkit.ValueFlag[C](commandkit.FlagMeta{Name: "campaign", Usage: "Select a configured campaign."}, nil, func(value string) (string, error) { return value, nil }, set),
|
||||
Scopes: []string{"app", "promptkit"},
|
||||
}
|
||||
}
|
||||
|
||||
func newApp() (*commandkit.App, error) {
|
||||
app, err := commandkit.New(commandkit.Identity{Name: "composed-example", Version: "1.0"})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
appScope, err := commandkit.NewConfigKitScope[configContext, appConfiguration]("app", "Application campaigns.", func(ctx context.Context, selection commandkit.Selection, input configContext) (*configkit.Result[appConfiguration], error) {
|
||||
return loadApplicationConfig(ctx, selection, input.Cache)
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
promptScope, err := commandkit.NewPromptKitScope(func(ctx context.Context, selection commandkit.Selection, input configContext) (*promptkit.Engine, error) {
|
||||
return loadPromptEngine(ctx, selection, input.Cache, input.Campaign)
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
configSuite := commandkit.ConfigSuite[configContext]{
|
||||
NewContext: func() configContext { return configContext{Cache: &invocationCache{}} },
|
||||
Selectors: []commandkit.Selector[configContext]{campaignSelector(func(input *configContext, value commandkit.Supplied[string]) {
|
||||
input.Campaign = value
|
||||
})},
|
||||
Scopes: []commandkit.ConfigScope[configContext]{appScope, promptScope},
|
||||
}
|
||||
if err := commandkit.RegisterConfig(app, configSuite); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
definitionSuite, err := commandkit.NewPromptKitSuite(func(ctx context.Context, selection commandkit.Selection, input definitionContext) (*promptkit.Engine, error) {
|
||||
return loadPromptEngine(ctx, selection, input.Cache, input.Campaign)
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
definitionSuite.NewContext = func() definitionContext { return definitionContext{Cache: &invocationCache{}} }
|
||||
definitionSuite.Selectors = []commandkit.Selector[definitionContext]{campaignSelector(func(input *definitionContext, value commandkit.Supplied[string]) {
|
||||
input.Campaign = value
|
||||
})}
|
||||
if err := commandkit.RegisterPromptKit(app, definitionSuite); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
store := &sessionStore{records: map[string]session{"session-42": {ID: "session-42", Campaign: "spring", Summary: "A synthetic planning session."}}}
|
||||
restore, err := commandkit.NewCommand(commandkit.CommandSpec[restoreInput]{
|
||||
Name: "restore",
|
||||
Summary: "Restore one saved session.",
|
||||
Flags: []commandkit.Flag[restoreInput]{commandkit.ValueFlag[restoreInput](commandkit.FlagMeta{Name: "campaign", Usage: "Campaign owning the session."}, nil, func(value string) (string, error) { return value, nil }, func(input *restoreInput, value commandkit.Supplied[string]) {
|
||||
input.Campaign = value
|
||||
})},
|
||||
Arguments: []commandkit.Argument[restoreInput]{commandkit.ValueArgument[restoreInput](commandkit.ArgumentMeta{Name: "ID"}, true, func(value string) (string, error) { return value, nil }, func(input *restoreInput, value commandkit.Supplied[string]) {
|
||||
input.Session = value.Value
|
||||
})},
|
||||
Run: func(invocation commandkit.Invocation, input restoreInput) commandkit.Outcome {
|
||||
return restoreSession(invocation, store, input)
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sessionGroup, err := commandkit.Group("session", "Manage saved sessions.", restore)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := app.Register(sessionGroup); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return app, nil
|
||||
}
|
||||
|
||||
func restoreSession(invocation commandkit.Invocation, store *sessionStore, input restoreInput) commandkit.Outcome {
|
||||
application, err := loadApplicationConfig(invocation.Context, commandkit.Selection{}, nil)
|
||||
if err != nil {
|
||||
return commandkit.Failure(err)
|
||||
}
|
||||
name, _, err := selectedCampaign(application.Config, input.Campaign)
|
||||
if err != nil {
|
||||
return commandkit.Failure(err)
|
||||
}
|
||||
record, ok := store.records[input.Session]
|
||||
if !ok {
|
||||
return commandkit.Outcome{Kind: commandkit.OutcomeDomain, Status: 4, Domain: "session_not_found", Cause: errors.New("saved session was not found")}
|
||||
}
|
||||
if record.Campaign != name {
|
||||
return commandkit.Outcome{Kind: commandkit.OutcomeDomain, Status: 3, Domain: "campaign_mismatch", Cause: fmt.Errorf("session belongs to campaign %q", record.Campaign)}
|
||||
}
|
||||
store.active = record.ID
|
||||
if _, err := fmt.Fprintf(invocation.Streams.Out, "restored %s: %s\n", record.ID, record.Summary); err != nil {
|
||||
return commandkit.Failure(err)
|
||||
}
|
||||
return commandkit.Success()
|
||||
}
|
||||
|
||||
func main() {
|
||||
app, err := newApp()
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
outcome := app.Execute(context.Background(), os.Args[1:], commandkit.Streams{Out: os.Stdout, Err: os.Stderr})
|
||||
if outcome.Status != 0 {
|
||||
os.Exit(outcome.Status)
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
# Simple consumer
|
||||
|
||||
Run the maintained example with:
|
||||
|
||||
```sh
|
||||
go run . config show
|
||||
go run . greet
|
||||
go run . greet --count=0 --tag=first --tag second
|
||||
```
|
||||
|
||||
The `config` family comes from one typed ConfigKit scope. The custom `greet`
|
||||
command uses CommandKit's typed bindings and shows the difference between an
|
||||
omitted `--count` and an explicitly supplied zero, plus ordered repeated tags.
|
||||
The configuration is synthetic and stays in memory.
|
||||
@@ -1,90 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
commandkit "gitea.maximumdirect.net/eric/CommandKit"
|
||||
configkit "gitea.maximumdirect.net/eric/ConfigKit"
|
||||
)
|
||||
|
||||
type appConfiguration struct {
|
||||
Greeting string `yaml:"greeting"`
|
||||
}
|
||||
|
||||
type greetInput struct {
|
||||
Count commandkit.Supplied[int]
|
||||
Tags commandkit.Supplied[[]string]
|
||||
}
|
||||
|
||||
func loadAppConfiguration(context.Context, commandkit.Selection, struct{}) (*configkit.Result[appConfiguration], error) {
|
||||
return configkit.Load[appConfiguration](configkit.Bytes("simple example", []byte("greeting: hello\n")))
|
||||
}
|
||||
|
||||
func newApp() (*commandkit.App, error) {
|
||||
app, err := commandkit.New(commandkit.Identity{Name: "simple-example", Version: "1.0"})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
scope, err := commandkit.NewConfigKitScope[struct{}, appConfiguration]("app", "Application settings.", loadAppConfiguration)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := commandkit.RegisterConfig(app, commandkit.ConfigSuite[struct{}]{Scopes: []commandkit.ConfigScope[struct{}]{scope}}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
countDefault := 1
|
||||
tagDefaults := []string{"example"}
|
||||
greet, err := commandkit.NewCommand(commandkit.CommandSpec[greetInput]{
|
||||
Name: "greet",
|
||||
Summary: "Show flag presence and repeated values.",
|
||||
Flags: []commandkit.Flag[greetInput]{
|
||||
commandkit.ValueFlag[greetInput](commandkit.FlagMeta{Name: "count", Usage: "Greeting count."}, &countDefault, strconv.Atoi, func(input *greetInput, value commandkit.Supplied[int]) {
|
||||
input.Count = value
|
||||
}),
|
||||
commandkit.RepeatFlag[greetInput](commandkit.FlagMeta{Name: "tag", Usage: "A repeatable label."}, tagDefaults, func(value string) (string, error) { return value, nil }, func(input *greetInput, value commandkit.Supplied[[]string]) {
|
||||
input.Tags = value
|
||||
}),
|
||||
},
|
||||
Run: func(invocation commandkit.Invocation, input greetInput) commandkit.Outcome {
|
||||
configuration, err := loadAppConfiguration(invocation.Context, commandkit.Selection{}, struct{}{})
|
||||
if err != nil {
|
||||
return commandkit.Failure(err)
|
||||
}
|
||||
count := fmt.Sprintf("default %d (not supplied)", input.Count.Value)
|
||||
if input.Count.Set {
|
||||
count = fmt.Sprintf("explicit %d", input.Count.Value)
|
||||
}
|
||||
tags := fmt.Sprintf("default %v (not supplied)", input.Tags.Value)
|
||||
if input.Tags.Set {
|
||||
tags = fmt.Sprintf("explicit %v", input.Tags.Value)
|
||||
}
|
||||
if _, err := fmt.Fprintf(invocation.Streams.Out, "%s; count=%s; tags=%s\n", configuration.Config.Greeting, count, tags); err != nil {
|
||||
return commandkit.Failure(err)
|
||||
}
|
||||
return commandkit.Success()
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := app.Register(greet); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return app, nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
app, err := newApp()
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
outcome := app.Execute(context.Background(), os.Args[1:], commandkit.Streams{Out: os.Stdout, Err: os.Stderr})
|
||||
if outcome.Status != 0 {
|
||||
os.Exit(outcome.Status)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user