From 2a06a911bcb3c3c42e178bc36de432f7348e5aca Mon Sep 17 00:00:00 2001 From: Eric Rakestraw Date: Sat, 26 Sep 2026 15:24:55 +0000 Subject: [PATCH] Adopt Promptkit v0.11 and maintained catalog profiles --- README.md | 6 +- docs/api.md | 8 +- docs/cli.md | 6 +- docs/config.md | 22 ++++- docs/consumers/api.md | 4 +- docs/consumers/migrating-to-promptkit.md | 20 ++-- docs/development.md | 8 +- docs/internal/adapters.md | 2 +- docs/internal/overview.md | 2 +- docs/internal/sources.md | 2 +- docs/operations.md | 19 +++- docs/policy/architecture.md | 6 +- docs/roadmap/implementation.md | 6 +- go.mod | 6 +- go.sum | 12 +-- internal/adapter/cli/run_test.go | 113 ++++++++++++++++++++--- 16 files changed, 180 insertions(+), 62 deletions(-) diff --git a/README.md b/README.md index 0652f00..c356c85 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ OpenAI-compatible model endpoints, and returns generated output with validation metadata. The application uses -[Promptkit v0.9.0](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.9.0/) +[Promptkit v0.11.0](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.11.0/) for prompt, profile, schema, preparation, generation, and validation behavior. Scriptorium owns executable configuration, CLI and HTTP mapping, process behavior, output presentation, and HTTP artifact-containment policy. @@ -38,8 +38,8 @@ a model. For complete invocation and output behavior, see the - [Migration from the former Go package](docs/consumers/migrating-to-promptkit.md) - [Subprocess integration](docs/integrations/subprocess.md) - [Architecture policy](docs/policy/architecture.md) -- [Promptkit framework formats](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.9.0/docs/formats.md) -- [Promptkit Go consumer guide](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.9.0/docs/consumers/pkg-promptkit.md) +- [Promptkit framework formats](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.11.0/docs/formats.md) +- [Promptkit Go consumer guide](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.11.0/docs/consumers/pkg-promptkit.md) ## Examples diff --git a/docs/api.md b/docs/api.md index e1f50f3..9d38095 100644 --- a/docs/api.md +++ b/docs/api.md @@ -65,11 +65,13 @@ The optional `model` object accepts `endpoint`, `model`, `temperature`, `max_tokens`, `top_p`, `timeout_seconds`, `service_tier`, `reasoning_effort`, `api_key_env`, and `extra_params`. Numeric ranges and framework credential semantics are defined by the -[Promptkit format reference](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.9.0/docs/formats.md). +[Promptkit format reference](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.11.0/docs/formats.md). Explicit zero values for the numeric fields are overrides; zero -`timeout_seconds` disables the per-generation deadline only, retaining the +`timeout_seconds` disables the per-attempt generation deadline only, retaining the request context and configured transport cap. The timeout layers are defined in -the [Promptkit outbound integration contract](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.9.0/docs/integrations/openai-compatible-chat.md#timeout-and-cancellation). +the [Promptkit outbound integration contract](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.11.0/docs/integrations/openai-compatible-chat.md#timeout-and-cancellation). +Each built-in transient retry gets a fresh generation timeout; the caller's +request context remains the outer cancellation boundary. Raw API-key values are not accepted. `api_key` and any other unknown model field cause `400 invalid_json`. diff --git a/docs/cli.md b/docs/cli.md index cc26772..eeedf7b 100644 --- a/docs/cli.md +++ b/docs/cli.md @@ -69,12 +69,14 @@ Deprecated aliases: `--prompt-id` for `--prompt`, and `--profile-id` for `--profile`. Omitted numeric runtime flags preserve the selected effective value; explicit -zero values override it. `--timeout 0s` disables the per-generation deadline +zero values override it. `--timeout 0s` disables the per-attempt generation deadline only; the caller context and configured transport cap remain active. CLI durations are converted to whole seconds by truncation toward zero, so any duration whose absolute value is below one second becomes an explicit zero-second override. The timeout layers are defined in the -[Promptkit outbound integration contract](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.9.0/docs/integrations/openai-compatible-chat.md#timeout-and-cancellation). +[Promptkit outbound integration contract](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.11.0/docs/integrations/openai-compatible-chat.md#timeout-and-cancellation). +With the built-in client, each transient retry gets a fresh generation timeout; +this flag does not limit the complete run. There is no raw API-key flag. Use `--api-key-env`. diff --git a/docs/config.md b/docs/config.md index c88ff3d..9e25bf9 100644 --- a/docs/config.md +++ b/docs/config.md @@ -3,7 +3,7 @@ This is the canonical reference for Scriptorium application settings. Prompt, profile, schema, execution-setting, built-in profile, and framework credential semantics are defined by the -[Promptkit v0.9.0 format reference](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.9.0/docs/formats.md). +[Promptkit v0.11.0 format reference](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.11.0/docs/formats.md). For command syntax, see the [CLI reference](cli.md); for HTTP request shapes and outcomes, see the [HTTP API reference](api.md). @@ -86,13 +86,20 @@ parse those framework file formats. contracts. See the -[tagged Promptkit format reference](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.9.0/docs/formats.md) +[tagged Promptkit format reference](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.11.0/docs/formats.md) for all of those definitions. The files under [`examples/prompts`](../examples/prompts/), [`examples/profiles`](../examples/profiles/), and [`examples/schemas`](../examples/schemas/) are maintained Scriptorium application inputs using that tagged format. +Promptkit supplies the opt-in profile IDs `promptkit-openrouter-standard` and +`promptkit-openrouter-auto`. They can be selected as a prompt default or request +profile, and custom profile sources retain precedence. Their effective model +settings may change with a catalog upgrade; use a complete application-owned +profile when fixed settings are required. See the tagged format reference for +the maintained-profile contract. + ## Credentials And Outbound Behavior Scriptorium maps `--api-key-env` and HTTP `model.api_key_env` into Promptkit @@ -113,8 +120,15 @@ A positive Promptkit `repair_attempts` budget can add provider calls, latency, token use, and cost; see the tagged format reference for its permitted values and validation-mode requirements. +Promptkit's built-in client now makes up to two additional attempts for eligible +transient HTTP statuses by default. This can increase latency, request count, +and cost. Scriptorium currently uses that upstream default without an +application-level retry setting. Each initial or repair generation has its own +transient budget; an injected client retains its own retry behavior. The tagged +integration contract owns eligibility and timing. + Promptkit's -[OpenAI-compatible integration contract](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.9.0/docs/integrations/openai-compatible-chat.md) +[OpenAI-compatible integration contract](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.11.0/docs/integrations/openai-compatible-chat.md) defines outbound authentication, provider request mapping, transport limits, and timeout layering. @@ -123,4 +137,4 @@ and timeout layering. - [CLI reference](cli.md) - [HTTP API reference](api.md) - [Operations guide](operations.md) -- [Promptkit framework formats](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.9.0/docs/formats.md) +- [Promptkit framework formats](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.11.0/docs/formats.md) diff --git a/docs/consumers/api.md b/docs/consumers/api.md index 47f0a00..4b83b91 100644 --- a/docs/consumers/api.md +++ b/docs/consumers/api.md @@ -14,7 +14,7 @@ and the HTTP service according to the boundary your application needs. Go applications that need an in-process prompt framework should import Promptkit directly. The tagged -[Promptkit Go consumer guide](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.9.0/docs/consumers/pkg-promptkit.md) +[Promptkit Go consumer guide](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.11.0/docs/consumers/pkg-promptkit.md) owns that interface; Scriptorium does not provide a Go library package. Consumers arriving from the former Scriptorium Go API should follow the [migration guide](migrating-to-promptkit.md). @@ -35,4 +35,4 @@ Scriptorium does not persist run state. A retry can produce different output and can incur another provider request. CLI exits belong to the [CLI reference](../cli.md), HTTP status behavior belongs to the [HTTP API reference](../api.md), and framework semantics belong to -[Promptkit v0.9.0](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.9.0/docs/formats.md). +[Promptkit v0.11.0](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.11.0/docs/formats.md). diff --git a/docs/consumers/migrating-to-promptkit.md b/docs/consumers/migrating-to-promptkit.md index 183cf99..b2c2f8b 100644 --- a/docs/consumers/migrating-to-promptkit.md +++ b/docs/consumers/migrating-to-promptkit.md @@ -4,7 +4,7 @@ Scriptorium `v0.11.1` at `gitea.maximumdirect.net/eric/scriptorium` is the final release that provides -the former in-process Go framework. Promptkit `v0.9.0` at +the former in-process Go framework. Promptkit `v0.11.0` at `gitea.maximumdirect.net/eric/promptkit` is the destination for that framework API. Scriptorium `v0.12.0` and later provide the CLI and HTTP application only. @@ -19,7 +19,7 @@ Start from a clean consumer checkout and review the pending diff before committing it. Add the published Promptkit module: ```sh -go get gitea.maximumdirect.net/eric/promptkit@v0.9.0 +go get gitea.maximumdirect.net/eric/promptkit@v0.11.0 ``` For an ordinary consumer that imports the former root package under its @@ -51,14 +51,14 @@ go mod tidy go test ./... ``` -Confirm that `go.mod` selects Promptkit `v0.9.0` and that no Go file imports +Confirm that `go.mod` selects Promptkit `v0.11.0` and that no Go file imports the former Scriptorium package: ```sh test "$( go list -m -f '{{.Path}}@{{.Version}}' \ gitea.maximumdirect.net/eric/promptkit -)" = 'gitea.maximumdirect.net/eric/promptkit@v0.9.0' +)" = 'gitea.maximumdirect.net/eric/promptkit@v0.11.0' if git grep -n \ 'gitea.maximumdirect.net/eric/scriptorium' \ -- '*.go' @@ -73,20 +73,20 @@ fi Promptkit preserves the established engine, request, result, profile, source-option, model-client, artifact, validation-value, and public-error shapes where practical. Exact declarations and current behavior belong to the -tagged [Promptkit consumer guide](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.9.0/docs/consumers/pkg-promptkit.md) +tagged [Promptkit consumer guide](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.11.0/docs/consumers/pkg-promptkit.md) and Go source. Promptkit also includes migration-relevant public contracts that were not in Scriptorium `v0.11.1`: -- [`WithArtifactReader`](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.9.0/engine.go#L182) +- [`WithArtifactReader`](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.11.0/engine.go#L169-L174) and the - [`ArtifactReader` declaration](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.9.0/types.go#L304) + [`ArtifactReader` declaration](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.11.0/types.go#L315) provide the artifact-reading extension described by the tagged - [extension-interface guide](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.9.0/docs/consumers/pkg-promptkit.md#extension-interfaces). -- [`ErrProfileRequired` and `ErrAPIKeyEnvMissing`](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.9.0/engine.go#L46-L61) + [extension-interface guide](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.11.0/docs/consumers/pkg-promptkit.md#extension-interfaces). +- [`ErrProfileRequired` and `ErrAPIKeyEnvMissing`](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.11.0/engine.go#L33-L48) provide the specific identities described by the tagged - [error guide](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.9.0/docs/consumers/pkg-promptkit.md#errors). + [error guide](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.11.0/docs/consumers/pkg-promptkit.md#handle-errors). Use those tagged owners for exact signatures, wrapping guarantees, and extension behavior. diff --git a/docs/development.md b/docs/development.md index 741e355..35aa01c 100644 --- a/docs/development.md +++ b/docs/development.md @@ -2,7 +2,7 @@ This is the contributor entry point for Scriptorium. Scriptorium is an application that consumes the public -[Promptkit v0.9.0 package](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.9.0/docs/consumers/pkg-promptkit.md); +[Promptkit v0.11.0 package](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.11.0/docs/consumers/pkg-promptkit.md); framework implementation work belongs in Promptkit. ## Initial Orientation @@ -28,12 +28,12 @@ tests. | HTTP routes, DTOs, limits, status mapping, or artifact policy | [HTTP API contract](api.md), [adapter internals](internal/adapters.md), and [source internals](internal/sources.md) | | Application configuration or precedence | [Configuration contract](config.md), [adapter internals](internal/adapters.md), and [source internals](internal/sources.md) | | Prepared-run presentation | [CLI contract](cli.md), [adapter internals](internal/adapters.md), and `internal/format` | -| Prompt, profile, schema, generation, or validation semantics | [Promptkit framework formats](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.9.0/docs/formats.md) and the [Promptkit consumer guide](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.9.0/docs/consumers/pkg-promptkit.md) | -| OpenAI-compatible outbound behavior or timeout layering | [Promptkit integration contract](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.9.0/docs/integrations/openai-compatible-chat.md) | +| Prompt, profile, schema, generation, or validation semantics | [Promptkit framework formats](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.11.0/docs/formats.md) and the [Promptkit consumer guide](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.11.0/docs/consumers/pkg-promptkit.md) | +| OpenAI-compatible outbound behavior or timeout layering | [Promptkit integration contract](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.11.0/docs/integrations/openai-compatible-chat.md) | | Subprocess behavior | [Subprocess integration](integrations/subprocess.md) and [CLI contract](cli.md) | | Runtime operation or recovery | [Operations](operations.md) | | Release packaging or publication | The [release policy](policy/release.md), [release procedure](release.md), [hosted release workflow](../.woodpecker/release.yml), and [architecture policy](policy/architecture.md) | -| Examples or copyable assets | The owning Scriptorium contract, the relevant [Promptkit format contract](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.9.0/docs/formats.md), and the related files under `examples/` | +| Examples or copyable assets | The owning Scriptorium contract, the relevant [Promptkit format contract](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.11.0/docs/formats.md), and the related files under `examples/` | | Architecture decisions or future work | The [documentation policy](policy/documentation.md), relevant accepted ADRs, and relevant roadmap documents | Cross-project changes land and release in Promptkit before Scriptorium adopts diff --git a/docs/internal/adapters.md b/docs/internal/adapters.md index dc0f56a..c8a39b9 100644 --- a/docs/internal/adapters.md +++ b/docs/internal/adapters.md @@ -9,7 +9,7 @@ own IO and presentation mechanics, not framework decisions. External contracts are canonical in the [CLI reference](../cli.md) and [HTTP API reference](../api.md). Promptkit's public engine contract is described by its tagged -[Go consumer guide](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.9.0/docs/consumers/pkg-promptkit.md). +[Go consumer guide](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.11.0/docs/consumers/pkg-promptkit.md). ## Components And Collaborators diff --git a/docs/internal/overview.md b/docs/internal/overview.md index a7b3a3d..4248ecd 100644 --- a/docs/internal/overview.md +++ b/docs/internal/overview.md @@ -14,5 +14,5 @@ public behavior belongs in the linked contracts. | `internal/format` | Formats Promptkit prepared-run and prompt/profile inspection values for CLI text or JSON output. | [CLI contract](../cli.md), [adapter internals](adapters.md) | Framework implementation packages are provided by -[Promptkit v0.9.0](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.9.0/docs/consumers/pkg-promptkit.md) +[Promptkit v0.11.0](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.11.0/docs/consumers/pkg-promptkit.md) and are not part of this repository. diff --git a/docs/internal/sources.md b/docs/internal/sources.md index ab572bb..7b3327a 100644 --- a/docs/internal/sources.md +++ b/docs/internal/sources.md @@ -5,7 +5,7 @@ This document covers Scriptorium-owned source locations and the restricted HTTP artifact reader. Prompt, profile, schema, and ordinary artifact semantics are owned by the tagged -[Promptkit format reference](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.9.0/docs/formats.md). +[Promptkit format reference](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.11.0/docs/formats.md). ## Application Source Locations diff --git a/docs/operations.md b/docs/operations.md index a90eea2..8cef358 100644 --- a/docs/operations.md +++ b/docs/operations.md @@ -9,7 +9,7 @@ fields, or HTTP wire behavior. - [CLI reference](cli.md): commands, output destinations, and exit codes. - [Configuration reference](config.md): application settings, source locations, defaults, and credential mapping. -- [Promptkit framework formats](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.9.0/docs/formats.md): +- [Promptkit framework formats](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.11.0/docs/formats.md): prompt, profile, schema, execution-setting, and framework credential contracts. - [HTTP API reference](api.md): route, request/response schema, status codes, @@ -34,6 +34,13 @@ schema sources that follow the tagged framework formats. For an HTTP deployment that accepts file artifacts, use a dedicated, narrow artifact directory rather than a general-purpose or sensitive filesystem tree. +When upgrading existing definitions, review selected profile IDs. +`deepseek-3-2`, `deepseek-4-flash`, and `deepseek-4-pro` were removed from the +selected catalog. Choose an available catalog profile, one of Promptkit's +maintained names, or a complete application-owned profile. New DeepSeek names +are not aliases for the removed ones; see the +[v0.10 migration guide](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.10.0/docs/releases/v0.10.0.md). + Run Scriptorium under an identity that can: - read only the prompt, profile, schema, and allowed input-artifact paths it @@ -102,6 +109,16 @@ runs. When admission is exhausted, HTTP returns `503 capacity_exceeded` without retry timing; callers choose any retry policy that is safe for another model call. +Promptkit's built-in client now allows two additional attempts for eligible +transient provider statuses by default. Account for added calls, latency, and +cost when planning capacity. Each repair generation has its own transient +budget, separate from the structural repair count. The current Scriptorium +interfaces use this upstream retry default. Existing generation timeouts apply +per attempt, while the caller context covers the complete operation. Provider +`Retry-After` timing can exceed Promptkit's ordinary backoff cap; consult the +[outbound integration contract](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.11.0/docs/integrations/openai-compatible-chat.md) +for details. + Before increasing a limit: 1. measure representative input, generated-output, and optional raw-output diff --git a/docs/policy/architecture.md b/docs/policy/architecture.md index 4daf8d5..e45b79c 100644 --- a/docs/policy/architecture.md +++ b/docs/policy/architecture.md @@ -25,7 +25,7 @@ The `inspect` command has prompt and profile modes. Scriptorium does not expose a reusable root Go package. The application consumes -[Promptkit v0.9.0](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.9.0/docs/consumers/pkg-promptkit.md) +[Promptkit v0.11.0](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.11.0/docs/consumers/pkg-promptkit.md) through its supported root package. Promptkit owns prompt execution, preparation, source formats, built-in profiles, model-client behavior, and validation. Scriptorium owns application configuration, executable adapters, @@ -86,9 +86,9 @@ vendored Promptkit implementation, or unpublished dependency assumptions. - `internal/format` owns deterministic prepared-run and definition-inspection text and JSON presentation. - Promptkit owns framework orchestration and contracts. Its - [format reference](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.9.0/docs/formats.md) + [format reference](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.11.0/docs/formats.md) and - [outbound integration contract](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.9.0/docs/integrations/openai-compatible-chat.md) + [outbound integration contract](https://gitea.maximumdirect.net/eric/promptkit/src/tag/v0.11.0/docs/integrations/openai-compatible-chat.md) are canonical. ## HTTP Artifact Security Boundary diff --git a/docs/roadmap/implementation.md b/docs/roadmap/implementation.md index f681e88..e8792f7 100644 --- a/docs/roadmap/implementation.md +++ b/docs/roadmap/implementation.md @@ -2,8 +2,8 @@ ## Status And Authority -Planned on 2026-09-26; no stage in this plan is implemented yet. Execute Stage 1 -through Stage 10 in order. Each stage is intended to fit one focused +Planned on 2026-09-26. Execute Stage 1 through Stage 10 in order; each section +records its own completion status. Each stage is intended to fit one focused gpt-5.6-terra implementation task, including its tests and documentation. The [feature roadmap](upgrade-kit.md) owns desired scope and end state. @@ -70,7 +70,7 @@ No stage authorizes a tag, push, publication, or changes to historical releases. ## Stage 1: Adopt The Released Dependency And Catalog Baseline -**Status: Pending.** +**Status: Complete.** 1. Upgrade `gitea.maximumdirect.net/eric/promptkit` to v0.11.0 and tidy the module graph. Review the resulting go.mod/go.sum changes. Expected indirect diff --git a/go.mod b/go.mod index 0856501..77d2b73 100644 --- a/go.mod +++ b/go.mod @@ -3,13 +3,13 @@ module gitea.maximumdirect.net/eric/scriptorium go 1.25.5 require ( - gitea.maximumdirect.net/eric/promptkit v0.9.0 + gitea.maximumdirect.net/eric/promptkit v0.11.0 gopkg.in/yaml.v3 v3.0.1 ) require ( - gitea.maximumdirect.net/eric/promptkit-backend-openrouter v1.0.0 // indirect - gitea.maximumdirect.net/eric/promptkit-backend-rakestrawhome v1.0.0 // indirect + gitea.maximumdirect.net/eric/promptkit-backend-openrouter/v2 v2.20260922.1 // indirect + gitea.maximumdirect.net/eric/promptkit-backend-rakestrawhome/v2 v2.20260922.0 // indirect github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 // indirect golang.org/x/text v0.14.0 // indirect ) diff --git a/go.sum b/go.sum index c99b921..4b779f8 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,9 @@ -gitea.maximumdirect.net/eric/promptkit v0.9.0 h1:IpvDRC8L6xRxQ9hpuyKOmMc5b6MeLTKYyx+h1YAjy08= -gitea.maximumdirect.net/eric/promptkit v0.9.0/go.mod h1:oMJ/WUJImUtwJ5e+6MAGECPYAErAkOaKel0G+3T/b4E= -gitea.maximumdirect.net/eric/promptkit-backend-openrouter v1.0.0 h1:lc062euk2qseO//D762i3JaFyulDNML3eQQX7DkYTho= -gitea.maximumdirect.net/eric/promptkit-backend-openrouter v1.0.0/go.mod h1:AIa7kAu2mfrRQgcspe4L+DW51WqgnALQT60lqkEywJI= -gitea.maximumdirect.net/eric/promptkit-backend-rakestrawhome v1.0.0 h1:j9YY7wsTVjzke2kHH4YAzpU0oUpM+x+nXwl1IeS+2eg= -gitea.maximumdirect.net/eric/promptkit-backend-rakestrawhome v1.0.0/go.mod h1:4RNS+LILDg4JbS4Ts9Lwy1C92wauXJIbeQaalps4Koo= +gitea.maximumdirect.net/eric/promptkit v0.11.0 h1:x7JguOUiInPVXK0GEitjyoRFqqvcuSTjYUvqJ+whtik= +gitea.maximumdirect.net/eric/promptkit v0.11.0/go.mod h1:0zEBVlJJC+ldDdXazAgybYBXNSe74vwFx5dyOuSos/w= +gitea.maximumdirect.net/eric/promptkit-backend-openrouter/v2 v2.20260922.1 h1:S2/Q/JDE+m8Ca3pDhAjVbfYrdlEhs9blj0STgNopHo0= +gitea.maximumdirect.net/eric/promptkit-backend-openrouter/v2 v2.20260922.1/go.mod h1:a3VBbh9oaGXD6ruxhtwHj+AWW6DY/SSyby1QtMmYSUo= +gitea.maximumdirect.net/eric/promptkit-backend-rakestrawhome/v2 v2.20260922.0 h1:Y0EXc3eh12eKW2NrOviVqdk3oBo6UUjopt1YAa1B3Oc= +gitea.maximumdirect.net/eric/promptkit-backend-rakestrawhome/v2 v2.20260922.0/go.mod h1:mtgD1E0SGm0e/I8Ffhz+AYX7GN7RKUWJXehNFIKHs4Y= github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI= github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 h1:KRzFb2m7YtdldCEkzs6KqmJw4nqEVZGK7IN2kJkjTuQ= diff --git a/internal/adapter/cli/run_test.go b/internal/adapter/cli/run_test.go index 944bc45..7dc5107 100644 --- a/internal/adapter/cli/run_test.go +++ b/internal/adapter/cli/run_test.go @@ -1201,9 +1201,9 @@ func TestInspectionParsersPreserveExplicitEmptyConfigPath(t *testing.T) { } } -func TestPromptkitV09DefinitionsRenderThroughCLI(t *testing.T) { - fixtureRoot := promptkitV09FixtureRoot(t) - configPath := writePromptkitV09Config(t, fixtureRoot, true) +func TestPromptkitDefinitionsRenderThroughCLI(t *testing.T) { + fixtureRoot := definitionFixtureRoot(t) + configPath := writeDefinitionFixtureConfig(t, fixtureRoot, true) inputPath := filepath.Join(fixtureRoot, "inputs", "source.md") code, stdout, stderr := runCLICommand(t, renderCommand, []string{ @@ -1258,9 +1258,9 @@ func TestPromptkitV09DefinitionsRenderThroughCLI(t *testing.T) { } } -func TestPromptkitV09PromptInspectionSelectsVersionsAndContracts(t *testing.T) { - fixtureRoot := promptkitV09FixtureRoot(t) - configPath := writePromptkitV09Config(t, fixtureRoot, true) +func TestPromptkitPromptInspectionSelectsVersionsAndContracts(t *testing.T) { + fixtureRoot := definitionFixtureRoot(t) + configPath := writeDefinitionFixtureConfig(t, fixtureRoot, true) tests := []struct { promptID string version string @@ -1296,12 +1296,12 @@ func TestPromptkitV09PromptInspectionSelectsVersionsAndContracts(t *testing.T) { } } -func TestPromptkitV09ProfileInspectionResolvesSupportedTargets(t *testing.T) { +func TestPromptkitProfileInspectionResolvesSupportedTargets(t *testing.T) { const secret = "sentinel-profile-secret" t.Setenv("FIXTURE_PROFILE_API_KEY", secret) - fixtureRoot := promptkitV09FixtureRoot(t) - configPath := writePromptkitV09Config(t, fixtureRoot, true) + fixtureRoot := definitionFixtureRoot(t) + configPath := writeDefinitionFixtureConfig(t, fixtureRoot, true) tests := []struct { name string profileID string @@ -1311,7 +1311,7 @@ func TestPromptkitV09ProfileInspectionResolvesSupportedTargets(t *testing.T) { }{ {name: "inherited custom backend", profileID: "custom-derived", wantBackend: "fixture-custom", wantModel: "fixture-derived-model", wantAPIKeyEnv: "FIXTURE_PROFILE_API_KEY"}, {name: "endpoint only", profileID: "endpoint-only", wantModel: "fixture-endpoint-model"}, - {name: "built in", profileID: "deepseek-4-flash", wantBackend: "openrouter", wantModel: "deepseek/deepseek-v4-flash", wantAPIKeyEnv: "OPENROUTER_API_KEY"}, + {name: "built in", profileID: "promptkit-openrouter-auto", wantBackend: "openrouter", wantModel: "openrouter/auto", wantAPIKeyEnv: "OPENROUTER_API_KEY"}, } for _, tc := range tests { @@ -1340,7 +1340,7 @@ func TestPromptkitV09ProfileInspectionResolvesSupportedTargets(t *testing.T) { }) } - configWithoutPromptDir := writePromptkitV09Config(t, fixtureRoot, false) + configWithoutPromptDir := writeDefinitionFixtureConfig(t, fixtureRoot, false) code, _, stderr := runCLICommand(t, inspectCommand, []string{ "profile", "--config", configWithoutPromptDir, @@ -1352,9 +1352,92 @@ func TestPromptkitV09ProfileInspectionResolvesSupportedTargets(t *testing.T) { } } +func TestMaintainedProfilesResolveAcrossSelectionAndSourcePrecedence(t *testing.T) { + promptDir := t.TempDir() + profileDir := t.TempDir() + writePromptDefinition(t, promptDir, "maintained.yaml", `id: maintained +version: "1.0.0" +default_profile: promptkit-openrouter-standard +messages: + - role: user + content: Hello +output: + format: text + validation_mode: none +`) + configPath := writeAppConfigFile(t, fmt.Sprintf("prompt_dir: %q\nprofile_dir: %q\n", promptDir, profileDir)) + + for _, profileID := range []string{"promptkit-openrouter-standard", "promptkit-openrouter-auto"} { + t.Run(profileID+" inspection", func(t *testing.T) { + code, stdout, stderr := runCLICommand(t, inspectCommand, []string{"profile", "--config", configPath, "--profile", profileID, "--format", "json"}) + if code != ExitOK { + t.Fatalf("inspect %s: code=%d stderr=%q", profileID, code, stderr) + } + var inspection renderformat.ProfileInspection + if err := json.Unmarshal([]byte(stdout), &inspection); err != nil { + t.Fatal(err) + } + if inspection.ProfileID != profileID || inspection.EffectiveModelParams.BackendID != "openrouter" || inspection.EffectiveModelParams.Model == "" { + t.Fatalf("maintained profile did not resolve: %+v", inspection) + } + if profileID == "promptkit-openrouter-auto" && inspection.EffectiveModelParams.Model != "openrouter/auto" { + t.Fatalf("unexpected auto target: %+v", inspection.EffectiveModelParams) + } + }) + } + + for _, tc := range []struct { + name string + selection []string + wantID string + }{ + {name: "prompt default", wantID: "promptkit-openrouter-standard"}, + {name: "explicit selection", selection: []string{"--profile", "promptkit-openrouter-auto"}, wantID: "promptkit-openrouter-auto"}, + } { + t.Run(tc.name, func(t *testing.T) { + args := append([]string{"--config", configPath, "--prompt", "maintained", "--format", "json"}, tc.selection...) + code, stdout, stderr := runCLICommand(t, renderCommand, args) + if code != ExitOK { + t.Fatalf("render: code=%d stderr=%q", code, stderr) + } + var rendered struct { + SelectedProfileID string `json:"selected_profile_id"` + SelectedBackendID string `json:"selected_backend_id"` + } + if err := json.Unmarshal([]byte(stdout), &rendered); err != nil { + t.Fatal(err) + } + if rendered.SelectedProfileID != tc.wantID || rendered.SelectedBackendID != "openrouter" { + t.Fatalf("unexpected selection: %+v", rendered) + } + }) + } + + writePromptDefinition(t, profileDir, "derived.yaml", "id: derived-maintained\nbase_profile: promptkit-openrouter-standard\nmodel: fixture-inherited-model\n") + writePromptDefinition(t, profileDir, "replacement.yaml", "id: promptkit-openrouter-auto\nbackend: openrouter\nmodel: fixture-override-model\n") + for _, tc := range []struct{ id, model string }{ + {id: "derived-maintained", model: "fixture-inherited-model"}, + {id: "promptkit-openrouter-auto", model: "fixture-override-model"}, + } { + t.Run(tc.id+" source", func(t *testing.T) { + code, stdout, stderr := runCLICommand(t, inspectCommand, []string{"profile", "--config", configPath, "--profile", tc.id, "--format", "json"}) + if code != ExitOK { + t.Fatalf("inspect: code=%d stderr=%q", code, stderr) + } + var inspection renderformat.ProfileInspection + if err := json.Unmarshal([]byte(stdout), &inspection); err != nil { + t.Fatal(err) + } + if inspection.EffectiveModelParams.BackendID != "openrouter" || inspection.EffectiveModelParams.Model != tc.model { + t.Fatalf("unexpected effective target: %+v", inspection) + } + }) + } +} + func TestProfileInspectionHonorsDirectoryPrecedenceOutputAndFailures(t *testing.T) { - fixtureRoot := promptkitV09FixtureRoot(t) - configPath := writePromptkitV09Config(t, fixtureRoot, true) + fixtureRoot := definitionFixtureRoot(t) + configPath := writeDefinitionFixtureConfig(t, fixtureRoot, true) overrideDir := t.TempDir() writeProfileFile(t, overrideDir, "custom-derived", "http://127.0.0.1:9000/v1", "override-model") outPath := filepath.Join(t.TempDir(), "inspection.json") @@ -1971,7 +2054,7 @@ func runCLICommand(t *testing.T, command func([]string, io.Writer, io.Writer) in return code, stdout.String(), stderr.String() } -func promptkitV09FixtureRoot(t *testing.T) string { +func definitionFixtureRoot(t *testing.T) string { t.Helper() root, err := filepath.Abs(filepath.Join("..", "..", "..", "testdata", "promptkit-v0.9")) if err != nil { @@ -1983,7 +2066,7 @@ func promptkitV09FixtureRoot(t *testing.T) string { return root } -func writePromptkitV09Config(t *testing.T, fixtureRoot string, includeSources bool) string { +func writeDefinitionFixtureConfig(t *testing.T, fixtureRoot string, includeSources bool) string { t.Helper() sources := "" if includeSources {