Omit unset optional request parameters
This commit is contained in:
@@ -188,25 +188,27 @@ they also cannot collide with the standard fields listed in the
|
||||
|
||||
Execution settings resolve in this order:
|
||||
|
||||
1. framework defaults;
|
||||
1. the framework timeout baseline;
|
||||
2. the selected backend, when the profile names one;
|
||||
3. the selected profile; and
|
||||
4. request `ExecutionTargetOverride` values.
|
||||
|
||||
The framework defaults are:
|
||||
The framework baseline is:
|
||||
|
||||
| Setting | Default |
|
||||
| --- | --- |
|
||||
| `temperature` | `0` |
|
||||
| `max_tokens` | `0` |
|
||||
| `top_p` | `1` |
|
||||
| `temperature` | Unspecified and omitted from compatible provider requests unless a backend, profile, or runtime override selects it. |
|
||||
| `max_tokens` | Unspecified and omitted from compatible provider requests unless a backend, profile, or runtime override selects it. |
|
||||
| `top_p` | Unspecified and omitted from compatible provider requests unless a backend, profile, or runtime override selects it. |
|
||||
| `timeout_seconds` | `600` |
|
||||
|
||||
Numeric zero in a file or in-memory profile means that the profile does not
|
||||
replace the framework default. Numeric request overrides use pointers, so an
|
||||
explicit zero is preserved. In particular, an explicit request
|
||||
`timeout_seconds` of zero disables the per-generation deadline while leaving
|
||||
the caller context and transport timeout intact.
|
||||
replace a lower-precedence value. With no lower value, `temperature`,
|
||||
`max_tokens`, and `top_p` remain unspecified. Numeric request overrides use
|
||||
pointers, so an explicit zero is retained and sent to compatible providers.
|
||||
In particular, an explicit request `timeout_seconds` of zero disables the
|
||||
per-generation deadline while leaving the caller context and transport timeout
|
||||
intact.
|
||||
|
||||
Non-empty profile strings replace backend defaults, and non-empty request
|
||||
strings replace both. Request reasoning is the exception: a nil
|
||||
|
||||
@@ -53,8 +53,9 @@ never also sent as a session header.
|
||||
|
||||
The client conditionally includes:
|
||||
|
||||
- `temperature`, `max_tokens`, and `top_p` when non-zero or explicitly
|
||||
present;
|
||||
- `temperature`, `max_tokens`, and `top_p` only when selected by a backend,
|
||||
profile, or runtime override, including an explicit runtime zero; they are
|
||||
absent when unspecified;
|
||||
- non-empty `service_tier` and effective `reasoning_effort`; an explicitly
|
||||
disabled reasoning setting is empty and therefore omitted; and
|
||||
- `response_format` for JSON Schema structured output, including its name,
|
||||
|
||||
152
docs/roadmap/fallback-profiles.md
Normal file
152
docs/roadmap/fallback-profiles.md
Normal file
@@ -0,0 +1,152 @@
|
||||
# Application Fallback Profiles
|
||||
|
||||
Status: Selected for implementation.
|
||||
|
||||
## Purpose
|
||||
|
||||
Promptkit will allow a consuming application to supply an embedded fallback
|
||||
profile source below operator-configured profiles and above Promptkit's
|
||||
built-in profile catalog.
|
||||
|
||||
This gives consumers stable, application-owned profile IDs with useful
|
||||
packaged defaults while preserving the existing ability for an operator to
|
||||
replace those definitions. Promptkit will own the reusable source layer and
|
||||
lookup semantics without owning downstream profile names, model assignments,
|
||||
or application configuration policy.
|
||||
|
||||
## Consumer Outcome
|
||||
|
||||
A consumer such as Weatherreporter can embed profiles named for application
|
||||
workloads or execution tiers, such as `weather-light`, `weather-balanced`, and
|
||||
`weather-deep`. Prompts can select those logical IDs without coupling the
|
||||
application to a particular provider or model.
|
||||
|
||||
An operator can define the same profile ID in the application's ordinary
|
||||
configured profile source to replace the packaged default. If no operator
|
||||
definition exists, Promptkit resolves the application's embedded definition.
|
||||
If neither source contains the ID, Promptkit retains access to its own built-in
|
||||
profile catalog.
|
||||
|
||||
## Scope
|
||||
|
||||
Promptkit will add one optional `fs.FS`-backed application fallback profile
|
||||
source to engine construction. The intended public surface is:
|
||||
|
||||
```go
|
||||
promptkit.WithFallbackProfileFS(profileFS, ".")
|
||||
```
|
||||
|
||||
The source will use the existing profile YAML format, discovery behavior,
|
||||
strict decoding, validation rules, and credential restrictions. The option
|
||||
will accept a non-nil filesystem and nonblank root. Repeating the option will
|
||||
follow Promptkit's same-category convention: the last valid value replaces the
|
||||
earlier fallback source, while an invalid option still fails construction when
|
||||
it is applied.
|
||||
|
||||
No programmatic fallback-profile option is included. Consumers that need the
|
||||
new precedence relationship can embed YAML assets, while `WithProfiles`
|
||||
continues to serve the distinct highest-precedence in-memory use case.
|
||||
|
||||
## Profile Selection And Source Precedence
|
||||
|
||||
Profile ID selection remains separate from profile definition lookup. An
|
||||
explicit request profile ID continues to take precedence over a prompt's
|
||||
`default_profile`. After an ID has been selected, matching definitions resolve
|
||||
in this order:
|
||||
|
||||
1. in-memory profiles supplied through `WithProfiles`;
|
||||
2. the ordinary configured profile source selected through `WithProfileFile`,
|
||||
`WithProfileFS`, or `Config.ProfileDir`;
|
||||
3. the application fallback profile source; and
|
||||
4. Promptkit's embedded built-in profiles.
|
||||
|
||||
A higher-precedence source falls through only when the requested profile ID is
|
||||
absent. An unreadable, malformed, duplicate, ambiguous, or otherwise invalid
|
||||
matching definition is an error and does not permit lookup in a lower layer.
|
||||
Profiles are selected as complete values; sources do not merge fields or
|
||||
inherit from one another.
|
||||
|
||||
The fallback source remains lazily read and validated when a requested ID
|
||||
reaches that layer. This feature does not introduce engine-wide eager source
|
||||
validation, and an unrelated malformed asset does not acquire stronger
|
||||
validation guarantees than it has in an ordinary profile source.
|
||||
|
||||
## Consistent Engine Behavior
|
||||
|
||||
The engine will assemble one profile repository with the complete precedence
|
||||
chain. Exact profile inspection, ordinary preparation, prepared execution, and
|
||||
ordinary execution will all use that same repository and therefore observe the
|
||||
same definition for a given profile ID.
|
||||
|
||||
Exact profile inspection remains side-effect free and does not contact a model
|
||||
provider. Existing public error identities remain applicable to cancellation,
|
||||
profile-not-found and profile-load failures, invalid fallback definitions,
|
||||
credential resolution, and unknown backends. The feature does not add a new
|
||||
fallback-specific public error category.
|
||||
|
||||
Internally, the root facade will own composition of all profile-source layers.
|
||||
The application fallback is another use of the profile repository's existing
|
||||
error-preserving overlay semantics; it is not a separate profile-loading or
|
||||
validation implementation.
|
||||
|
||||
## Compatibility
|
||||
|
||||
The feature is additive. An engine that does not configure an application
|
||||
fallback source retains its current behavior and profile precedence. Existing
|
||||
uses of `Config.ProfileDir`, `WithProfileFile`, `WithProfileFS`, and
|
||||
`WithProfiles` keep their meanings.
|
||||
|
||||
The application fallback is deliberately below every existing
|
||||
consumer-configured profile source. An ordinary configured profile therefore
|
||||
continues to override any packaged definition with the same ID. A missing or
|
||||
invalid configured source also retains its current behavior; the new layer
|
||||
does not turn configuration failures into silent fallthrough.
|
||||
|
||||
## Ownership Boundaries
|
||||
|
||||
Promptkit owns:
|
||||
|
||||
- the additional source layer and its construction option;
|
||||
- deterministic lookup and fallthrough semantics;
|
||||
- use of the existing profile format, validation, and public error mapping;
|
||||
- consistent repository use across inspection, preparation, and execution;
|
||||
and
|
||||
- canonical public, format, consumer, and contributor documentation for the
|
||||
implemented capability.
|
||||
|
||||
The consuming application owns:
|
||||
|
||||
- whether to supply a fallback source;
|
||||
- application-specific profile IDs and their domain meaning;
|
||||
- embedded profile contents, backend selections, and model choices;
|
||||
- application configuration discovery and operator override policy;
|
||||
- assignment of profiles to reports or other workloads; and
|
||||
- credential policy and operator-facing error presentation beyond Promptkit's
|
||||
public contract.
|
||||
|
||||
## Non-Goals
|
||||
|
||||
This scope does not add:
|
||||
|
||||
- downstream-specific profiles to Promptkit's built-in catalog;
|
||||
- profile inheritance, aliases, or field-level merging;
|
||||
- provider failover after a selected profile or generation attempt fails;
|
||||
- automatic endpoint discovery, probing, benchmarking, or tier selection;
|
||||
- application configuration discovery;
|
||||
- eager validation of every profile in every source;
|
||||
- source-provenance fields in profile inspection or preparation results; or
|
||||
- an in-memory companion to `WithFallbackProfileFS`.
|
||||
|
||||
## Target End State
|
||||
|
||||
The feature is complete when a consumer can embed an application fallback
|
||||
profile source through the root facade and rely on the documented four-layer
|
||||
precedence everywhere profiles are resolved. Operator definitions override
|
||||
application defaults, application defaults override Promptkit built-ins,
|
||||
invalid matching definitions never silently fall through, and engines that do
|
||||
not use the new option remain behaviorally compatible.
|
||||
|
||||
The implemented public option and precedence contract will be owned by GoDoc
|
||||
and the framework format reference. Consumer guidance will show the embedded
|
||||
application-default workflow without making this temporary roadmap a second
|
||||
current-state reference.
|
||||
378
docs/roadmap/implementation.md
Normal file
378
docs/roadmap/implementation.md
Normal file
@@ -0,0 +1,378 @@
|
||||
# Optional Request-Parameter Omission Implementation Plan
|
||||
|
||||
**Status:** Ready for implementation.
|
||||
|
||||
## Purpose
|
||||
|
||||
This document is the decision-complete implementation plan for
|
||||
[omitting unset optional request parameters](optional-request-parameters.md).
|
||||
It is written for a `gpt-5.6-terra` coding agent that will implement each stage
|
||||
in order.
|
||||
|
||||
The feature roadmap owns the motivation, policy choices, compatibility
|
||||
boundary, non-goals, and target end state. This document owns the concrete
|
||||
design, file-level work, test ownership, documentation updates, validation,
|
||||
and completion gates.
|
||||
|
||||
The separate [application fallback profiles](fallback-profiles.md) roadmap is
|
||||
not part of this implementation plan. Preserve it unchanged for its own later
|
||||
planning and implementation cycle.
|
||||
|
||||
## Implementation Rules
|
||||
|
||||
- Complete the stages in order. Stage 1 must leave code, tests, GoDoc, and
|
||||
current-state documentation mutually accurate; Stage 2 performs the final
|
||||
audit and repository-wide acceptance.
|
||||
- Preserve unrelated working-tree changes. In particular, do not edit,
|
||||
implement, retire, or reclassify `fallback-profiles.md`.
|
||||
- Follow every policy under `docs/policy/`, the task-specific reading guide in
|
||||
`docs/development.md`, and the accepted behavior in
|
||||
`optional-request-parameters.md`.
|
||||
- Keep the existing package boundaries. Framework defaults remain in
|
||||
`internal/defaults`, resolution remains in `internal/usecase`, and outbound
|
||||
OpenAI-compatible serialization remains in `internal/llm`.
|
||||
- Do not add an exported type, field, option, method, error, or public package.
|
||||
This feature changes default and wire semantics within existing contracts.
|
||||
- Do not replace numeric profile fields with pointers or add profile presence
|
||||
tracking. File and in-memory profile zero values retain their existing
|
||||
inheritance semantics; runtime pointer overrides remain the only supported
|
||||
way to select an explicit numeric zero.
|
||||
- Preserve required request fields, session IDs, structured output,
|
||||
credentials, extra-parameter validation, reasoning clearing, deadlines,
|
||||
capacity management, and all existing precedence rules.
|
||||
- Do not query a provider for defaults or capabilities and do not add
|
||||
backend- or model-specific serialization branches.
|
||||
- Keep tests lean and behavioral. Use the existing root precedence test to own
|
||||
resolved public/injected-client metadata and the existing model-client tests
|
||||
to own wire inclusion and omission. Do not duplicate those matrices in a
|
||||
new end-to-end fixture.
|
||||
- Update exact exported semantics in GoDoc, profile/default semantics in
|
||||
`docs/formats.md`, and provider request-body semantics in
|
||||
`docs/integrations/openai-compatible-chat.md` in the same stage as the code.
|
||||
- Do not add release notes, change a module version, commit, tag, push, or
|
||||
publish a release as part of this plan.
|
||||
|
||||
## Fixed Design
|
||||
|
||||
### Framework Defaults
|
||||
|
||||
In `internal/defaults/defaults.go`, remove these constants:
|
||||
|
||||
```go
|
||||
ExecutionDefaultTemperature
|
||||
ExecutionDefaultMaxTokens
|
||||
ExecutionDefaultTopP
|
||||
```
|
||||
|
||||
They currently encode zero for `temperature` and `max_tokens` and one for
|
||||
`top_p`. Optional provider controls are no longer framework defaults, so
|
||||
retaining zero-valued constants under default-oriented names would obscure the
|
||||
new contract.
|
||||
|
||||
Keep `ExecutionDefaultTimeoutSeconds` at its current positive value. Timeout is
|
||||
a Promptkit-owned generation deadline and is not an OpenAI-compatible request
|
||||
body field.
|
||||
|
||||
Keep `ExecutionTargetDefault` as the common resolution baseline, but have it
|
||||
initialize only `TimeoutSeconds`. The zero Go values for `Temperature`,
|
||||
`MaxTokens`, and `TopP` then represent unspecified provider controls. Do not
|
||||
rename this internal function or add a second defaults constructor.
|
||||
|
||||
### Resolution And Public Metadata
|
||||
|
||||
Do not change the merge functions or precedence in
|
||||
`internal/usecase/runner.go`:
|
||||
|
||||
1. the baseline target supplies only the Promptkit timeout;
|
||||
2. nonzero profile numeric fields replace the baseline;
|
||||
3. non-nil runtime numeric overrides replace profile values; and
|
||||
4. `ExecutionTargetPresence` records runtime overrides, including explicit
|
||||
zero values.
|
||||
|
||||
Consequently, when a profile omits the optional provider controls, resolved
|
||||
`ExecutionTarget` values contain zero for `Temperature`, `MaxTokens`, and
|
||||
`TopP`. That zero is stable metadata for “unspecified” unless the accompanying
|
||||
`GenerateRequest.TargetPresence` bit reports an explicit runtime zero.
|
||||
|
||||
Do not expose target presence in `PreparedRun`, `RunResult`, or
|
||||
`ProfileInspection`, and do not change their stable JSON shapes. As already
|
||||
true for `max_tokens`, those metadata values report the resolved numeric value
|
||||
rather than provenance. A prepared result containing `top_p: 0` therefore does
|
||||
not distinguish an unspecified value from an explicit runtime zero; injected
|
||||
clients receive the separate presence value when the distinction affects
|
||||
execution.
|
||||
|
||||
Update root GoDoc in `types.go` so it no longer calls an unspecified optional
|
||||
provider control an effective provider value:
|
||||
|
||||
- `ExecutionTarget.Temperature`, `MaxTokens`, and `TopP` must each state that
|
||||
zero leaves the field unspecified to compatible providers unless the
|
||||
corresponding `ExecutionTargetPresence` bit is true;
|
||||
- `ExecutionTarget.TimeoutSeconds` retains its existing deadline semantics;
|
||||
- `Profile` and `ExecutionTargetOverride` documentation must describe zero or
|
||||
nil as inheriting a lower-precedence value and otherwise leaving the provider
|
||||
control unspecified, rather than implying that every field receives a
|
||||
concrete framework value; and
|
||||
- `PreparedRun`, `ProfileInspection`, and other effective-target summaries may
|
||||
continue to describe precedence, but must not imply that Promptkit knows a
|
||||
provider's omitted default.
|
||||
|
||||
Do not change field types, field order, JSON tags, conversion functions, string
|
||||
formatting, or copying behavior.
|
||||
|
||||
### Outbound Request Semantics
|
||||
|
||||
The current built-in client already has the required mechanism:
|
||||
`openAIChatRequestFromGenerateRequest` includes `temperature`, `max_tokens`, or
|
||||
`top_p` when the resolved value is nonzero or the corresponding target-presence
|
||||
bit is true, and `openAIChatRequestPayload` omits nil fields. Preserve that
|
||||
logic.
|
||||
|
||||
No production change should be needed in
|
||||
`internal/llm/openai_compatible_client.go`. Change it only if a focused failing
|
||||
test demonstrates that the existing implementation does not meet this plan;
|
||||
do not special-case `top_p`, inspect profile provenance, or move framework
|
||||
default policy into the transport.
|
||||
|
||||
The resulting behavior is:
|
||||
|
||||
- an omitted profile `top_p` resolves to zero and is absent from the body;
|
||||
- a nonzero profile or runtime `top_p` is included;
|
||||
- an explicit runtime `top_p` of zero is included because presence is true;
|
||||
- the same rules continue to apply to `temperature` and `max_tokens`;
|
||||
- empty `service_tier` and effective `reasoning_effort` remain absent;
|
||||
- configured `extra_params` remain present after validation; and
|
||||
- `model`, `messages`, conditional `session_id`, and conditional
|
||||
`response_format` remain unchanged.
|
||||
|
||||
### Profile Formats And Built-In Profiles
|
||||
|
||||
Do not change YAML or public `Profile` field shapes. Numeric zero in a file or
|
||||
in-memory profile continues to mean “do not replace the lower layer.” With no
|
||||
lower provider value, zero therefore resolves to unspecified. An explicit
|
||||
profile-level numeric zero remains unsupported; consumers use a runtime
|
||||
pointer override when zero itself must be sent.
|
||||
|
||||
Do not edit files under `internal/profile/builtin/assets/`. Values declared in
|
||||
those files are explicit profile policy and remain effective. Existing
|
||||
nonzero-profile tests are sufficient to protect explicit inclusion; do not add
|
||||
one test per built-in asset or parameter.
|
||||
|
||||
### Test Ownership
|
||||
|
||||
Use these existing boundaries:
|
||||
|
||||
- In `engine_test.go`, update the “framework defaults” row of
|
||||
`TestEngineExecutionSettingPrecedence` so the zero-valued profile expects
|
||||
`TopP: 0` while retaining `Temperature: 0`, `MaxTokens: 0`, and the positive
|
||||
timeout. Rename that row to describe unspecified provider controls plus the
|
||||
framework timeout. Keep the rows proving nonzero profile precedence and
|
||||
explicit runtime-zero presence unchanged.
|
||||
- Remove
|
||||
`TestRunnerRunBuiltInDefaultsUsedWhenProfileOmitsOptionalFields` from
|
||||
`internal/usecase/runner_test.go`. Its literal-default assertions duplicate
|
||||
the stronger assembled root precedence test and depend on the internal
|
||||
constants being removed. Do not replace it with another internal
|
||||
default-value test.
|
||||
- Keep
|
||||
`TestOpenAICompatibleClientOmitsImplicitZeroNumericFields` and
|
||||
`TestOpenAICompatibleClientSerializesExplicitZeroNumericOverrides` in
|
||||
`internal/llm/openai_compatible_client_test.go`. Together they own the wire
|
||||
distinction and should pass without weakening their assertions.
|
||||
- Keep the existing nonzero request serialization and profile-precedence tests
|
||||
passing. They prove that explicitly configured values continue to be sent
|
||||
and selected.
|
||||
|
||||
Do not add snapshots, golden files, provider calls, or a broad duplicate
|
||||
integration test. Add a new test only if the implementation exposes a distinct
|
||||
contract risk not covered by the tests above, and record that reason in the
|
||||
test name or nearby test structure rather than in a new planning document.
|
||||
|
||||
### Canonical Documentation
|
||||
|
||||
Update current-state documentation in Stage 1:
|
||||
|
||||
- In `docs/formats.md`, replace the optional provider-control entries in the
|
||||
framework-default table with clear unspecified/omitted semantics, while
|
||||
retaining the positive `timeout_seconds` framework default. Explain that
|
||||
profile numeric zero inherits a lower layer and otherwise remains
|
||||
unspecified; an explicit runtime pointer zero is retained.
|
||||
- In `docs/integrations/openai-compatible-chat.md`, state that
|
||||
`temperature`, `max_tokens`, and `top_p` are included only when selected by a
|
||||
profile or runtime override, including explicit runtime zero, and are absent
|
||||
when unspecified. Keep the existing ownership of required fields,
|
||||
`session_id`, structured output, extra parameters, and timeout behavior.
|
||||
- In `types.go`, apply the GoDoc changes described above; these declarations
|
||||
own the exact public value semantics.
|
||||
|
||||
Do not add a README or release-document note. The consumer guide already
|
||||
routes exact field behavior to GoDoc and profile/default behavior to the format
|
||||
reference, so do not duplicate the new contract there. The internal LLM
|
||||
document describes flow rather than exact field omission and does not require
|
||||
a change unless its current text is found to contradict the implementation.
|
||||
|
||||
## Stage 1: Implement Omission Semantics And Canonical Contracts
|
||||
|
||||
### Objective
|
||||
|
||||
Remove optional provider controls from the framework baseline, preserve
|
||||
explicit profile and runtime values, update the canonical contracts, and prove
|
||||
the behavior at the existing resolution and wire boundaries.
|
||||
|
||||
### Implementation Prompt
|
||||
|
||||
Implement only Stage 1 of `docs/roadmap/implementation.md`. Read the complete
|
||||
feature roadmap, implementation rules, and fixed design above before editing.
|
||||
|
||||
1. In `internal/defaults/defaults.go`, remove the three provider-control
|
||||
constants and make `ExecutionTargetDefault` initialize only
|
||||
`TimeoutSeconds`.
|
||||
2. In `engine_test.go`, update and rename the default-precedence table row
|
||||
exactly as described under Test Ownership.
|
||||
3. Remove the redundant literal-default test from
|
||||
`internal/usecase/runner_test.go`; do not weaken other precedence,
|
||||
profile-value, or runtime-zero tests.
|
||||
4. Update the affected exported GoDoc in `types.go` without changing any
|
||||
declaration, JSON tag, or serialization shape.
|
||||
5. Update `docs/formats.md` and
|
||||
`docs/integrations/openai-compatible-chat.md` according to Canonical
|
||||
Documentation.
|
||||
6. Run the focused validation below. Repair regressions in scope, but do not
|
||||
broaden the feature or change the established serializer merely to make a
|
||||
mistaken expectation pass.
|
||||
|
||||
Do not edit built-in profile assets, fallback-profile work, backend
|
||||
registration, profile parsing, target merge logic, public value shapes,
|
||||
prepared-execution lifecycle, capacity management, or release material.
|
||||
|
||||
### Focused Validation
|
||||
|
||||
Run from the repository root:
|
||||
|
||||
```sh
|
||||
gofmt -w internal/defaults/defaults.go types.go engine_test.go \
|
||||
internal/usecase/runner_test.go
|
||||
go test . -run 'TestEngineExecutionSettingPrecedence'
|
||||
go test ./internal/llm -run \
|
||||
'TestOpenAICompatibleClient(GenerateSuccess|OmitsImplicitZeroNumericFields|SerializesExplicitZeroNumericOverrides)'
|
||||
go test ./internal/usecase -run \
|
||||
'Test(ResolveExecutionTarget|RunnerPrepareRequestNumericOverridePresence|RunnerPrepareSelectedProfileBeatsBuiltInDefault|RunnerRunSelectedProfileBeatsBuiltInDefault)'
|
||||
go test . ./internal/defaults ./internal/usecase ./internal/llm
|
||||
go vet . ./internal/defaults ./internal/usecase ./internal/llm
|
||||
git diff --check
|
||||
```
|
||||
|
||||
If a focused regular expression does not match an existing test name, inspect
|
||||
the current names and run the narrowest equivalent set; do not silently skip
|
||||
the intended resolution, explicit-profile, explicit-zero, and wire-omission
|
||||
coverage.
|
||||
|
||||
### Completion Gate
|
||||
|
||||
Stage 1 is complete only when:
|
||||
|
||||
- the resolution baseline contains no provider tuning value and retains the
|
||||
Promptkit timeout;
|
||||
- an omitted `top_p` resolves to zero and the built-in client omits it;
|
||||
- nonzero profile and runtime values remain effective and serialized;
|
||||
- explicit runtime zero values remain distinguishable and serialized through
|
||||
`ExecutionTargetPresence`;
|
||||
- no public type or stable JSON shape changed;
|
||||
- required fields, structured output, session IDs, extra parameters,
|
||||
reasoning, credentials, and deadlines retain their existing behavior;
|
||||
- GoDoc, format documentation, and the integration contract describe the
|
||||
implemented behavior without conflicting ownership; and
|
||||
- all focused tests, vet, formatting, and whitespace checks pass.
|
||||
|
||||
## Stage 2: Audit Compatibility And Validate The Repository
|
||||
|
||||
### Objective
|
||||
|
||||
Confirm that the narrow semantic change is complete across all public,
|
||||
injected-client, built-in-profile, documentation, and repository surfaces,
|
||||
then mark the temporary planning documents complete.
|
||||
|
||||
### Implementation Prompt
|
||||
|
||||
Implement only Stage 2 of `docs/roadmap/implementation.md` after Stage 1
|
||||
satisfies its completion gate.
|
||||
|
||||
1. Search tracked Go and Markdown files for the removed constant names,
|
||||
framework `top_p` defaults, claims that all effective provider controls have
|
||||
concrete framework values, and request-body inclusion rules. Correct only
|
||||
stale statements or tests owned by this feature.
|
||||
2. Confirm that `internal/profile/builtin/assets/` has no feature-related diff
|
||||
and that its explicit nonzero optional controls still pass ordinary profile
|
||||
validation and resolution tests.
|
||||
3. Confirm that `internal/llm/openai_compatible_client.go` either has no diff or
|
||||
contains only a change required by a focused failing contract test. The
|
||||
default policy must remain outside the transport.
|
||||
4. Follow every changed Markdown link and confirm its target exists. Verify
|
||||
that current-state documents describe implemented behavior and that exact
|
||||
contracts remain with GoDoc, the format reference, and the integration
|
||||
contract.
|
||||
5. Run the complete validation sequence below and repair only in-scope
|
||||
failures.
|
||||
6. After all checks pass, change the status of
|
||||
`optional-request-parameters.md` and this document to `Complete`. Do not
|
||||
change the status or contents of `fallback-profiles.md`.
|
||||
7. Re-run `git diff --check` and inspect the final working tree and diff.
|
||||
|
||||
Do not delete temporary roadmaps in this stage; retirement is a separate
|
||||
maintainer action. Do not add release notes, change versions, or create a
|
||||
commit, tag, push, or release.
|
||||
|
||||
### Full Validation
|
||||
|
||||
Run from the repository root:
|
||||
|
||||
```sh
|
||||
gofmt -w internal/defaults/defaults.go types.go engine_test.go \
|
||||
internal/usecase/runner_test.go
|
||||
gofmt -l $(git ls-files '*.go')
|
||||
go test ./...
|
||||
go test -race ./...
|
||||
go vet ./...
|
||||
go build ./...
|
||||
go run ./examples/go-library/prepare
|
||||
git diff --check
|
||||
git status --short
|
||||
```
|
||||
|
||||
The `gofmt -l` command must print no paths. The maintained example must remain
|
||||
offline and require no real credential or provider.
|
||||
|
||||
Inspect the final diff and confirm:
|
||||
|
||||
- only this feature's files and pre-existing user changes are present;
|
||||
- no built-in profile asset, public declaration shape, stable JSON tag,
|
||||
credential rule, workspace file, local module replacement, generated binary,
|
||||
or unrelated formatting changed;
|
||||
- the removed provider-default constants have no remaining references;
|
||||
- the provider omission policy is implemented by resolution plus the existing
|
||||
generic serializer, not by a `top_p` transport special case;
|
||||
- the optional-parameter roadmap and this plan are complete while the fallback
|
||||
roadmap remains selected; and
|
||||
- no commit, tag, push, or release was created.
|
||||
|
||||
### Completion Gate
|
||||
|
||||
The implementation is complete only when:
|
||||
|
||||
- every Stage 1 gate remains satisfied;
|
||||
- the ordinary and race-enabled suites pass;
|
||||
- vet, build, formatting, the maintained offline example, Markdown links, and
|
||||
whitespace checks pass;
|
||||
- public metadata, injected-client presence, profile inheritance, and outbound
|
||||
omission semantics are mutually consistent;
|
||||
- explicit built-in and consumer profile values retain their behavior;
|
||||
- both feature-specific roadmap statuses are `Complete`;
|
||||
- `fallback-profiles.md` remains unchanged and selected for later work; and
|
||||
- the repository is ready for maintainer review without a commit or release
|
||||
having been created by this plan.
|
||||
|
||||
## Open Questions
|
||||
|
||||
None. The feature roadmap and fixed design above fully specify the behavior,
|
||||
compatibility boundary, implementation, documentation ownership, and test
|
||||
strategy.
|
||||
83
docs/roadmap/optional-request-parameters.md
Normal file
83
docs/roadmap/optional-request-parameters.md
Normal file
@@ -0,0 +1,83 @@
|
||||
# Omit Unset Optional Request Parameters
|
||||
|
||||
Status: Selected for implementation.
|
||||
|
||||
## Purpose
|
||||
|
||||
Promptkit will stop turning an unset optional provider control into an explicit
|
||||
outbound value. Required protocol fields and settings needed to enforce
|
||||
Promptkit's own contracts will retain defined behavior, while provider tuning
|
||||
choices will be sent only when a supported configuration layer selects them.
|
||||
|
||||
This keeps profiles intentional, avoids overriding model- or backend-specific
|
||||
defaults, and improves compatibility across OpenAI-compatible endpoints with
|
||||
different supported parameter sets.
|
||||
|
||||
## Scope
|
||||
|
||||
The framework-level `top_p` default of `1` will become unspecified. When no
|
||||
profile or runtime override supplies `top_p`, the built-in OpenAI-compatible
|
||||
client will omit it from the request body rather than serialize `1`.
|
||||
|
||||
This establishes the general outbound policy for currently supported optional
|
||||
controls:
|
||||
|
||||
- `temperature`, `max_tokens`, and `top_p` are omitted when unspecified and
|
||||
included when selected by a profile or runtime override;
|
||||
- an explicit numeric zero supplied through a runtime override remains present
|
||||
on the wire through the existing numeric-presence contract;
|
||||
- `service_tier` and `reasoning_effort` remain omitted when their resolved
|
||||
values are empty;
|
||||
- backend, profile, or runtime `extra_params` remain explicit configuration and
|
||||
are sent when present; and
|
||||
- `session_id` remains conditional on a supplied nonempty value, while
|
||||
`response_format` remains conditional on the effective output contract.
|
||||
|
||||
The request body will continue to require `model` and `messages`. Endpoint and
|
||||
credential resolution remain transport concerns rather than body defaults.
|
||||
The positive framework `timeout_seconds` default also remains in place because
|
||||
it enforces a Promptkit-owned generation deadline and is not serialized as a
|
||||
provider request field.
|
||||
|
||||
## Effective Settings And Compatibility
|
||||
|
||||
An unspecified numeric provider control continues to use its zero Go value in
|
||||
resolved public metadata. For a `GenerateRequest` delivered to an injected
|
||||
client, the existing `ExecutionTargetPresence` value distinguishes an explicit
|
||||
runtime zero from an inherited unspecified zero. Prepared and inspection
|
||||
metadata will continue to report the resolved numeric value without adding
|
||||
source-provenance fields.
|
||||
|
||||
The behavior change is intentional and belongs in a minor release. Consumers
|
||||
that require stable sampling behavior should declare the desired values in
|
||||
their profiles or runtime overrides instead of relying on Promptkit to repeat a
|
||||
provider's conventional default.
|
||||
|
||||
Built-in profile parameters remain explicit profile policy and will continue
|
||||
to be sent. An explicit built-in setting will not be removed merely because
|
||||
the framework default becomes unspecified.
|
||||
|
||||
## Non-Goals
|
||||
|
||||
This change does not add:
|
||||
|
||||
- pointer-valued numeric fields to file or in-memory profiles;
|
||||
- a general provenance model for effective settings;
|
||||
- automatic discovery of provider defaults or supported parameters;
|
||||
- backend- or model-specific request-shape negotiation;
|
||||
- changes to required request fields, structured-output behavior, credentials,
|
||||
or timeout enforcement; or
|
||||
- removal of deliberately configured settings from consumer or built-in
|
||||
profiles.
|
||||
|
||||
## Target End State
|
||||
|
||||
An otherwise unset optional provider tuning parameter is absent from the
|
||||
OpenAI-compatible request body. Explicit profile values and runtime overrides,
|
||||
including explicit runtime zero values, retain their current precedence and
|
||||
wire effect. Promptkit continues to supply only the required protocol fields
|
||||
and the settings necessary to honor its own execution and output contracts.
|
||||
|
||||
GoDoc, the framework format reference, and the OpenAI-compatible integration
|
||||
contract will own the implemented omission and metadata semantics once the
|
||||
feature lands.
|
||||
Reference in New Issue
Block a user