Make GoDoc the public API contract
This commit is contained in:
39
doc.go
39
doc.go
@@ -1,8 +1,39 @@
|
|||||||
// Package promptkit provides an embeddable engine for preparing and executing
|
// Package promptkit provides an embeddable engine for preparing and executing
|
||||||
// prompt-defined LLM workflows.
|
// prompt-defined LLM workflows.
|
||||||
//
|
//
|
||||||
// Applications construct an Engine with NewEngine, select filesystem or
|
// Applications construct an [Engine] with [NewEngine], select filesystem or
|
||||||
// in-memory definition sources with options, and use Prepare or Run to execute
|
// in-memory sources with options, and call [Engine.Prepare] or [Engine.Run].
|
||||||
// requests. Concrete repositories, validators, and outbound clients remain
|
// Concrete repositories, validators, and the built-in OpenAI-compatible client
|
||||||
// internal implementation details.
|
// remain internal implementation details.
|
||||||
|
//
|
||||||
|
// # Concurrency and ownership
|
||||||
|
//
|
||||||
|
// An Engine supports concurrent Prepare and Run calls. An injected [LLMClient]
|
||||||
|
// or [ArtifactReader] can therefore receive concurrent calls and must be safe
|
||||||
|
// for that use.
|
||||||
|
//
|
||||||
|
// NewEngine copies in-memory profiles. Prepare and Run copy request maps,
|
||||||
|
// slices, pointer values, and JSON-compatible extra parameters before using
|
||||||
|
// them. Returned values and values passed to extension interfaces are likewise
|
||||||
|
// isolated from engine state. Callers own those copies and may mutate them
|
||||||
|
// after the call that supplied or returned them.
|
||||||
|
//
|
||||||
|
// # JSON
|
||||||
|
//
|
||||||
|
// Stable JSON representations are provided for [PreparedRun], [RunResult],
|
||||||
|
// [Artifact], [ExecutionTarget], [OutputContract], [ValidationResult],
|
||||||
|
// [TokenUsage], [RenderedPrompt], [RenderedMessage], [CacheControl],
|
||||||
|
// [StructuredOutputSpec], [StructuredOutputJSONSpec], [GenerateRequest],
|
||||||
|
// [GenerateResponse], [ExecutionTargetPresence], and the string value types
|
||||||
|
// used by those values.
|
||||||
|
//
|
||||||
|
// Construction values, including [Config], [RunRequest], [ArtifactRef],
|
||||||
|
// [ExecutionTargetOverride], [Profile], and
|
||||||
|
// [OpenAICompatibleProfileConfig], do not have stable JSON representations.
|
||||||
|
// Direct API keys are nevertheless excluded from JSON for every public value.
|
||||||
|
//
|
||||||
|
// JSON timestamps use time.Time's RFC 3339 encoding and are omitted when zero.
|
||||||
|
// PreparedRun and RunResult durations are encoded as integer milliseconds in
|
||||||
|
// duration_ms and omitted when zero. Run IDs and all exposed hashes are opaque:
|
||||||
|
// their spelling, length, character set, and algorithm are not API contracts.
|
||||||
package promptkit
|
package promptkit
|
||||||
|
|||||||
@@ -1,151 +1,122 @@
|
|||||||
# Package `promptkit`
|
# Package `promptkit`
|
||||||
|
|
||||||
Import path:
|
## Purpose
|
||||||
|
|
||||||
|
This guide helps Go consumers assemble Promptkit and choose the main
|
||||||
|
preparation or execution workflow. The declarations and GoDoc in the
|
||||||
|
[root package](../../doc.go) own exact field, option, serialization,
|
||||||
|
concurrency, ownership, failure, and cancellation semantics. The
|
||||||
|
[framework format reference](../formats.md) owns prompt, profile, and schema
|
||||||
|
file contracts.
|
||||||
|
|
||||||
|
Import the package as:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "gitea.maximumdirect.net/eric/promptkit"
|
import "gitea.maximumdirect.net/eric/promptkit"
|
||||||
```
|
```
|
||||||
|
|
||||||
Package `promptkit` is the supported Go contract for in-process prompt
|
The following Go fragments are illustrative and omit surrounding package,
|
||||||
preparation and execution. The declarations and their GoDoc in the
|
import, and error-handling code. Use the maintained example for a complete
|
||||||
[root package](../../doc.go) own the exact API; this guide explains how the
|
program.
|
||||||
pieces are used together. The [framework format reference](../formats.md) owns
|
|
||||||
prompt, profile, and schema file contracts.
|
|
||||||
|
|
||||||
## Engine Construction And Sources
|
## Construct An Engine
|
||||||
|
|
||||||
Construct an engine with [`NewEngine`, `Config`, and
|
Create an engine with
|
||||||
`Option`](../../engine.go). `PromptDir` is required unless a prompt source
|
[`NewEngine`](../../engine.go). A directory-backed setup supplies a prompt
|
||||||
option is supplied. `ProfileDir` optionally overlays built-in profiles, and an
|
directory and may supply profile and schema directories:
|
||||||
empty `SchemaDir` uses the current directory. `Timeout` is the transport-wide
|
|
||||||
safety cap for the built-in OpenAI-compatible client. An optional `HTTPClient`
|
|
||||||
is cloned; its positive timeout takes precedence.
|
|
||||||
|
|
||||||
Nil options are ignored. Invalid construction, including a nil injected client
|
```go
|
||||||
or artifact reader, returns an error matching `ErrInvalidConfig`.
|
engine, err := promptkit.NewEngine(promptkit.Config{
|
||||||
|
PromptDir: "prompts",
|
||||||
|
ProfileDir: "profiles",
|
||||||
|
SchemaDir: "schemas",
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
The [source options](../../engine.go) replace their matching directory source:
|
Options support single-file or `fs.FS` sources, in-memory profiles, and
|
||||||
|
injected artifact or model clients. Consult the
|
||||||
- `WithPromptFS` and `WithPromptFile` select prompt definitions;
|
[constructor and option GoDoc](../../engine.go) for composition, precedence,
|
||||||
- `WithProfileFS` and `WithProfileFile` overlay built-in profiles;
|
validation, and default transport behavior. Source discovery, format
|
||||||
- `WithProfiles` adds in-memory profiles ahead of file and built-in profiles;
|
validation, and profile precedence are defined by the
|
||||||
- `WithSchemaFS` and `WithSchemaFile` select JSON Schema documents;
|
|
||||||
- `WithLLMClient` replaces the built-in model client; and
|
|
||||||
- `WithArtifactReader` replaces the default reader for every input.
|
|
||||||
|
|
||||||
Source selection, path resolution, strict decoding, profile overlays, and
|
|
||||||
file-to-request precedence are defined in the
|
|
||||||
[framework format reference](../formats.md).
|
[framework format reference](../formats.md).
|
||||||
|
|
||||||
Per-generation timeout values from profiles or requests are independent of
|
## Prepare Without Model Execution
|
||||||
the transport cap and caller context. An explicit request value of zero
|
|
||||||
disables only the per-generation deadline. The
|
|
||||||
[outbound integration contract](../integrations/openai-compatible-chat.md#timeout-and-cancellation)
|
|
||||||
defines the complete timeout layering.
|
|
||||||
|
|
||||||
## Preparation And Execution
|
[`Engine.Prepare`](../../engine.go) resolves the selected prompt and profile,
|
||||||
|
loads inputs and any structured-output schema, and renders messages without
|
||||||
|
calling a model client:
|
||||||
|
|
||||||
[`Engine.Prepare` and `Engine.Run`](../../engine.go) accept the public
|
```go
|
||||||
[`RunRequest`](../../types.go). `Prepare` resolves the prompt, profile, input
|
prepared, err := engine.Prepare(ctx, promptkit.RunRequest{
|
||||||
artifacts, validation contract, and rendered messages without calling an LLM.
|
PromptID: "meeting.summary",
|
||||||
`Run` performs the same preparation, calls the configured client, and validates
|
Inputs: map[string]promptkit.ArtifactRef{
|
||||||
the generated content. The maintained
|
"note": promptkit.Inline("Synthetic meeting notes"),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
The maintained
|
||||||
[offline preparation example](../../examples/go-library/prepare/main.go)
|
[offline preparation example](../../examples/go-library/prepare/main.go)
|
||||||
provides a complete runnable workflow using a prompt file, in-memory profile,
|
shows a complete runnable setup with a prompt file, in-memory profile, and
|
||||||
and inline input.
|
inline input. Exact request requirements and prepared-result fields belong to
|
||||||
|
the [`RunRequest` and `PreparedRun` GoDoc](../../types.go).
|
||||||
|
|
||||||
[`PreparedRun` and `RunResult`](../../types.go) expose copied public values.
|
## Execute And Validate
|
||||||
Preparation returns effective settings, hashes, rendered messages, selected
|
|
||||||
profile, structured-output information, and timing without resolved secrets or
|
|
||||||
model output. Execution adds the generated artifact and raw output, validation
|
|
||||||
state, model metadata, usage, run ID, and duration.
|
|
||||||
|
|
||||||
A generated-content validation failure returns a result with
|
[`Engine.Run`](../../engine.go) performs the same preparation, invokes the
|
||||||
`Validation.Status == ValidationFailed`. An inability to perform validation
|
configured model client, classifies the generated artifact, and validates the
|
||||||
returns an error matching `ErrValidation`.
|
content. A completed content check may return `ValidationFailed` in the result;
|
||||||
|
an operational inability to validate returns an error.
|
||||||
|
|
||||||
## Requests, Inputs, And Overrides
|
Use the [`RunResult` and `ValidationResult` GoDoc](../../types.go) for the
|
||||||
|
returned data and the `Engine.Run` GoDoc for failure and cancellation
|
||||||
|
semantics. The
|
||||||
|
[OpenAI-compatible integration contract](../integrations/openai-compatible-chat.md)
|
||||||
|
owns the built-in client's outbound HTTP behavior.
|
||||||
|
|
||||||
The [request and value declarations](../../types.go) own the available fields,
|
## Inputs, Profiles, And Overrides
|
||||||
serialized constants, and result shapes. Use `File`, `Inline`, or
|
|
||||||
`InlineWithURI` to construct artifact references. The
|
|
||||||
[framework format reference](../formats.md) defines declared inputs, template
|
|
||||||
references, output contracts, and the relationship between file values and
|
|
||||||
request overrides.
|
|
||||||
|
|
||||||
`ExecutionTargetOverride` uses pointers for numeric settings so an explicit
|
Use `File`, `Inline`, or `InlineWithURI` to construct request inputs. A request
|
||||||
zero remains distinct from no override. `ExtraParams` accepts JSON-compatible
|
can select a profile explicitly or use the prompt's default profile, and can
|
||||||
strings, booleans, finite numbers, string-keyed objects, arrays or slices, and
|
replace execution settings or the complete output contract.
|
||||||
nil. Unsupported values, non-string map keys, non-finite numbers, and cycles
|
|
||||||
match `ErrInvalidConfig` in profiles or `ErrInvalidRequest` in request
|
|
||||||
overrides.
|
|
||||||
|
|
||||||
Returned requests, profiles, prepared values, results, artifacts, maps, and
|
The [public value GoDoc](../../types.go) defines nil, empty, zero, replacement,
|
||||||
slices are isolated from internal engine state. Consumers and injected
|
copy, and credential behavior. The
|
||||||
extensions should not retain or mutate values owned by another caller.
|
[framework format reference](../formats.md) defines how those request values
|
||||||
|
interact with prompt definitions, file-backed profiles, built-ins, schemas,
|
||||||
|
and framework defaults.
|
||||||
|
|
||||||
## Profiles And Credentials
|
For programmatic profiles,
|
||||||
|
[`OpenAICompatibleProfile`](../../profiles.go) converts ordinary
|
||||||
|
OpenAI-compatible settings into a value accepted by `WithProfiles`.
|
||||||
|
|
||||||
[`OpenAICompatibleProfile`](../../profiles.go) constructs an ordinary
|
## Credentials
|
||||||
in-memory profile for an OpenAI-compatible chat-completions endpoint.
|
|
||||||
`WithProfiles` rejects duplicate IDs in one call and gives in-memory profiles
|
|
||||||
precedence over explicit file sources and built-ins.
|
|
||||||
|
|
||||||
Raw API keys do not belong in profiles. File-backed profiles may name an
|
File-backed profiles name an environment variable; in-memory profiles can
|
||||||
environment variable, while an in-memory profile can require a request key.
|
require a direct request key. Direct keys are request-scoped and are excluded
|
||||||
A direct `RunRequest.APIKey` is request-scoped and takes precedence over an
|
from supported JSON values and the package's `String` and `GoString`
|
||||||
environment lookup for the built-in client. Profile fields, ranges, built-ins,
|
summaries. The exact precedence and redaction guarantees belong to
|
||||||
precedence, and credential rules are owned by the
|
[`RunRequest`, `GenerateRequest`, and the profile GoDoc](../../types.go).
|
||||||
[framework format reference](../formats.md).
|
|
||||||
|
|
||||||
API keys are excluded from JSON, prepared values, and results. The public
|
|
||||||
`String` and `GoString` methods report only whether a direct key is present.
|
|
||||||
Avoid reflection-based dumps of request structs, which can bypass that
|
|
||||||
redaction.
|
|
||||||
|
|
||||||
## Extension Interfaces
|
## Extension Interfaces
|
||||||
|
|
||||||
The [`LLMClient`, `GenerateRequest`, and
|
Inject an [`LLMClient` or `ArtifactReader`](../../types.go) when the built-in
|
||||||
`GenerateResponse`](../../types.go) boundary lets a consumer replace model
|
behavior does not fit the application. Their GoDoc defines concurrent use,
|
||||||
generation. Injected clients receive copied rendered messages, effective
|
context handling, ownership of copied values, nil responses, and preservation
|
||||||
settings, explicit numeric-setting presence, structured-output constraints,
|
of collaborator errors.
|
||||||
and the request-scoped key. They return generated content and token usage.
|
|
||||||
|
|
||||||
The [`ArtifactReader`](../../types.go) boundary replaces the default inline and
|
## Handle Errors
|
||||||
file reader for every input. Readers provide artifact content and metadata; the
|
|
||||||
engine fills an empty artifact name from the input-map key. A reader error
|
|
||||||
matches `ErrArtifactLoad` while preserving the original identity for
|
|
||||||
`errors.Is`. A nil artifact with a nil error is also an artifact-load failure.
|
|
||||||
|
|
||||||
Extensions should honor context cancellation and avoid logging raw prompts,
|
Use `errors.Is` with the
|
||||||
artifacts, or credentials.
|
[public error sentinels and operation GoDoc](../../engine.go). The declarations
|
||||||
|
distinguish invalid construction, invalid requests, absent sources,
|
||||||
|
source-loading failures, collaborator failures, and operational validation
|
||||||
|
failures. Specific request conditions may also match the broader
|
||||||
|
`ErrInvalidRequest`, and injected collaborator identities are preserved where
|
||||||
|
documented.
|
||||||
|
|
||||||
## Errors
|
## Application Boundary
|
||||||
|
|
||||||
The [public error declarations](../../engine.go) and
|
|
||||||
[mapping](../../errors.go) preserve these sentinel checks through `errors.Is`:
|
|
||||||
|
|
||||||
- `ErrInvalidConfig`
|
|
||||||
- `ErrInvalidRequest`
|
|
||||||
- `ErrPromptNotFound`
|
|
||||||
- `ErrProfileNotFound`
|
|
||||||
- `ErrProfileRequired`
|
|
||||||
- `ErrPromptLoad`
|
|
||||||
- `ErrProfileLoad`
|
|
||||||
- `ErrAPIKeyEnvMissing`
|
|
||||||
- `ErrArtifactLoad`
|
|
||||||
- `ErrPromptRender`
|
|
||||||
- `ErrLLMGenerate`
|
|
||||||
- `ErrValidation`
|
|
||||||
|
|
||||||
`ErrProfileRequired` and `ErrAPIKeyEnvMissing` also match
|
|
||||||
`ErrInvalidRequest`, allowing either broad request handling or a specific
|
|
||||||
condition. Wrapped collaborator errors retain their identity where the public
|
|
||||||
contract promises it.
|
|
||||||
|
|
||||||
## Consumer Boundary
|
|
||||||
|
|
||||||
Promptkit is an importable library. It does not own a command, inbound HTTP
|
Promptkit is an importable library. It does not own a command, inbound HTTP
|
||||||
API, process configuration, or deployment policy. Scriptorium is one
|
API, process configuration, or deployment policy. Applications map the root
|
||||||
downstream application that maps this root package contract into those
|
package's results and errors into those concerns.
|
||||||
application concerns.
|
|
||||||
|
|||||||
@@ -57,47 +57,15 @@ that is currently ambiguous.
|
|||||||
- [x] Confirm the supported JSON Schema dialect and reference boundaries,
|
- [x] Confirm the supported JSON Schema dialect and reference boundaries,
|
||||||
including whether remote references are allowed.
|
including whether remote references are allowed.
|
||||||
|
|
||||||
The resolved contract is:
|
The selected exported API contracts are implemented and tested. Their durable
|
||||||
|
definitions now belong to the root package declarations and GoDoc.
|
||||||
|
|
||||||
- `RunRequest.Metadata` had no observable purpose and has been removed from the
|
One format-level decision remains here until Stage 5 moves it to the framework
|
||||||
public and internal request values.
|
format reference: JSON Schema uses Draft 2020-12, with that dialect selected
|
||||||
- One engine supports overlapping `Prepare` and `Run` calls. Built-in
|
when `$schema` is omitted. Same-document fragments and relative references
|
||||||
collaborators satisfy that contract; injected collaborators may be called
|
contained by a directory or `fs.FS` schema root are supported. A single-file
|
||||||
concurrently and therefore share responsibility for concurrency safety.
|
source supports only references contained in that document. Absolute,
|
||||||
- Options are applied in order. Within each prompt-source, profile-source,
|
escaping, and remote references are rejected.
|
||||||
in-memory-profile, schema-source, model-client, or artifact-reader category,
|
|
||||||
the last non-nil valid option replaces the earlier value for that category.
|
|
||||||
An invalid earlier option still makes construction fail.
|
|
||||||
- The supported JSON values are `PreparedRun`, `RunResult`, `Artifact`,
|
|
||||||
`ExecutionTarget`, `OutputContract`, `ValidationResult`, `TokenUsage`,
|
|
||||||
`RenderedPrompt`, `RenderedMessage`, `CacheControl`,
|
|
||||||
`StructuredOutputSpec`, `StructuredOutputJSONSpec`, `GenerateRequest`,
|
|
||||||
`GenerateResponse`, `ExecutionTargetPresence`, and the public string value
|
|
||||||
types used by them. Construction inputs such as `Config`, `RunRequest`,
|
|
||||||
`ArtifactRef`, `ExecutionTargetOverride`, `Profile`, and
|
|
||||||
`OpenAICompatibleProfileConfig` do not have stable JSON representations.
|
|
||||||
Request-scoped API keys remain excluded from JSON as a security guarantee,
|
|
||||||
including on otherwise unsupported construction values.
|
|
||||||
- JSON timestamps use `time.Time`'s RFC 3339 representation and are omitted
|
|
||||||
when zero. Both prepared and completed run durations use integer
|
|
||||||
milliseconds in `duration_ms` and are omitted when zero. A prepared duration
|
|
||||||
measures preparation only; a run-result duration measures the complete run,
|
|
||||||
including its preparation, generation, and validation.
|
|
||||||
- Run IDs, prompt hashes, rendered-prompt hashes, input hashes, and artifact
|
|
||||||
hashes are non-empty correlation or equality values where produced. Their
|
|
||||||
spelling, length, character set, and algorithm are opaque and not stable
|
|
||||||
formats.
|
|
||||||
- The built-in transport timeout defaults to 10 minutes. A zero or negative
|
|
||||||
`Config.Timeout` selects that default. A supplied HTTP client's positive
|
|
||||||
timeout takes precedence; its zero or negative timeout inherits the positive
|
|
||||||
configured timeout or the default. These transport semantics are independent
|
|
||||||
of caller cancellation and per-generation timeout settings.
|
|
||||||
- JSON Schema uses Draft 2020-12; omission of `$schema` selects that dialect
|
|
||||||
and an explicit different dialect is rejected. Same-document fragment
|
|
||||||
references are supported. Relative references may load other schema
|
|
||||||
documents only within a configured directory or `fs.FS` schema root.
|
|
||||||
A single-file schema source supports only references contained in that
|
|
||||||
document. Absolute, escaping, and remote references are not allowed.
|
|
||||||
|
|
||||||
**Gate:** Each question has an explicit answer backed by existing behavior or
|
**Gate:** Each question has an explicit answer backed by existing behavior or
|
||||||
by an accepted implementation change and proportionate tests. No later stage
|
by an accepted implementation change and proportionate tests. No later stage
|
||||||
@@ -108,21 +76,21 @@ should invent a contract merely to fill a documentation gap.
|
|||||||
Strengthen the root package declarations so `go doc` is sufficient to
|
Strengthen the root package declarations so `go doc` is sufficient to
|
||||||
understand exact public behavior without relying on internal documents.
|
understand exact public behavior without relying on internal documents.
|
||||||
|
|
||||||
- [ ] Add useful field-level GoDoc to configuration, request, profile,
|
- [x] Add useful field-level GoDoc to configuration, request, profile,
|
||||||
execution-target, result, artifact, validation, structured-output, and model
|
execution-target, result, artifact, validation, structured-output, and model
|
||||||
client values.
|
client values.
|
||||||
- [ ] Document required fields and nil, empty, and zero-value semantics.
|
- [x] Document required fields and nil, empty, and zero-value semantics.
|
||||||
- [ ] Document override, replacement, profile-precedence, and copy-ownership
|
- [x] Document override, replacement, profile-precedence, and copy-ownership
|
||||||
behavior where it belongs to the exported API.
|
behavior where it belongs to the exported API.
|
||||||
- [ ] Document credential inputs, redaction, and the values intentionally
|
- [x] Document credential inputs, redaction, and the values intentionally
|
||||||
excluded from serialization.
|
excluded from serialization.
|
||||||
- [ ] Give each public error sentinel an accurate comment and document the
|
- [x] Give each public error sentinel an accurate comment and document the
|
||||||
supported `errors.Is` relationships.
|
supported `errors.Is` relationships.
|
||||||
- [ ] Document engine concurrency and option-composition behavior selected in
|
- [x] Document engine concurrency and option-composition behavior selected in
|
||||||
Stage 1.
|
Stage 1.
|
||||||
- [ ] Document serialization, time, run-ID, and hash semantics selected in
|
- [x] Document serialization, time, run-ID, and hash semantics selected in
|
||||||
Stage 1.
|
Stage 1.
|
||||||
- [ ] Review constructor, option, extension-interface, `Prepare`, and `Run`
|
- [x] Review constructor, option, extension-interface, `Prepare`, and `Run`
|
||||||
GoDoc for complete failure and cancellation expectations.
|
GoDoc for complete failure and cancellation expectations.
|
||||||
|
|
||||||
Update the [consumer guide](../consumers/pkg-promptkit.md) to summarize and link
|
Update the [consumer guide](../consumers/pkg-promptkit.md) to summarize and link
|
||||||
|
|||||||
165
engine.go
165
engine.go
@@ -22,42 +22,93 @@ import (
|
|||||||
"gitea.maximumdirect.net/eric/promptkit/internal/validate"
|
"gitea.maximumdirect.net/eric/promptkit/internal/validate"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ErrInvalidConfig indicates invalid public engine configuration.
|
// ErrInvalidConfig identifies invalid engine construction, including missing
|
||||||
|
// required configuration, invalid options, and a nil Engine receiver.
|
||||||
var ErrInvalidConfig = errors.New("invalid engine configuration")
|
var ErrInvalidConfig = errors.New("invalid engine configuration")
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ErrInvalidRequest = errors.New("invalid run request")
|
// ErrInvalidRequest identifies a request whose required values, overrides,
|
||||||
ErrPromptNotFound = errors.New("prompt not found")
|
// credentials, or effective settings are invalid.
|
||||||
ErrProfileNotFound = errors.New("profile not found")
|
ErrInvalidRequest = errors.New("invalid run request")
|
||||||
ErrProfileRequired = errors.New("profile selection is required")
|
// ErrPromptNotFound identifies a requested prompt ID or version that is not
|
||||||
ErrPromptLoad = errors.New("failed to load prompt definition")
|
// present in the selected prompt source. It does not also match
|
||||||
ErrProfileLoad = errors.New("failed to load execution profile")
|
// ErrPromptLoad.
|
||||||
|
ErrPromptNotFound = errors.New("prompt not found")
|
||||||
|
// ErrProfileNotFound identifies a selected profile ID that is absent from
|
||||||
|
// every configured profile source. It does not also match ErrProfileLoad.
|
||||||
|
ErrProfileNotFound = errors.New("profile not found")
|
||||||
|
// ErrProfileRequired identifies a request for which neither RunRequest.ProfileID
|
||||||
|
// nor the selected prompt's default profile is present. Such an error also
|
||||||
|
// matches ErrInvalidRequest.
|
||||||
|
ErrProfileRequired = errors.New("profile selection is required")
|
||||||
|
// ErrPromptLoad identifies a failure to read, decode, validate, select, or
|
||||||
|
// hash a prompt definition, except for the not-found case represented by
|
||||||
|
// ErrPromptNotFound.
|
||||||
|
ErrPromptLoad = errors.New("failed to load prompt definition")
|
||||||
|
// ErrProfileLoad identifies a failure to read, decode, validate, or select
|
||||||
|
// an execution profile, except for the not-found case represented by
|
||||||
|
// ErrProfileNotFound.
|
||||||
|
ErrProfileLoad = errors.New("failed to load execution profile")
|
||||||
|
// ErrAPIKeyEnvMissing identifies an APIKeyEnv whose environment variable is
|
||||||
|
// unset or empty when no direct RunRequest.APIKey takes precedence. Such an
|
||||||
|
// error also matches ErrInvalidRequest.
|
||||||
ErrAPIKeyEnvMissing = errors.New("api_key_env points to an unset environment variable")
|
ErrAPIKeyEnvMissing = errors.New("api_key_env points to an unset environment variable")
|
||||||
ErrArtifactLoad = errors.New("failed to load artifact")
|
// ErrArtifactLoad identifies a failure to resolve an input artifact. Errors
|
||||||
ErrPromptRender = errors.New("failed to render prompt")
|
// returned by an injected ArtifactReader remain available through errors.Is.
|
||||||
ErrLLMGenerate = errors.New("failed to generate output")
|
ErrArtifactLoad = errors.New("failed to load artifact")
|
||||||
ErrValidation = errors.New("failed to validate output")
|
// ErrPromptRender identifies a failure to render prompt messages or the
|
||||||
|
// session ID from the resolved inputs and variables.
|
||||||
|
ErrPromptRender = errors.New("failed to render prompt")
|
||||||
|
// ErrLLMGenerate identifies a model-client failure or a nil successful
|
||||||
|
// response. Errors returned by an injected LLMClient remain available
|
||||||
|
// through errors.Is.
|
||||||
|
ErrLLMGenerate = errors.New("failed to generate output")
|
||||||
|
// ErrValidation identifies an operational failure to load or compile a
|
||||||
|
// schema or validate output. A completed validation whose Status is
|
||||||
|
// ValidationFailed is returned in RunResult without this error.
|
||||||
|
ErrValidation = errors.New("failed to validate output")
|
||||||
)
|
)
|
||||||
|
|
||||||
// Engine prepares and runs Promptkit prompt requests.
|
// Engine prepares and runs Promptkit prompt requests.
|
||||||
|
//
|
||||||
|
// An Engine is safe for concurrent calls to [Engine.Prepare] and [Engine.Run].
|
||||||
|
// Injected collaborators may consequently be invoked concurrently.
|
||||||
type Engine struct {
|
type Engine struct {
|
||||||
runner *usecase.Runner
|
runner *usecase.Runner
|
||||||
}
|
}
|
||||||
|
|
||||||
// Config configures a public Promptkit engine.
|
// Config selects the directory-backed sources and built-in model-client
|
||||||
|
// transport used by [NewEngine]. Config has no stable JSON representation.
|
||||||
type Config struct {
|
type Config struct {
|
||||||
PromptDir string
|
// PromptDir is the directory searched recursively for prompt definitions.
|
||||||
|
// It is required unless a WithPromptFS or WithPromptFile option supplies the
|
||||||
|
// prompt source.
|
||||||
|
PromptDir string
|
||||||
|
// ProfileDir is an optional directory whose profiles take precedence over
|
||||||
|
// embedded built-in profiles. An empty value selects only built-ins unless
|
||||||
|
// profile options are also supplied.
|
||||||
ProfileDir string
|
ProfileDir string
|
||||||
SchemaDir string
|
// SchemaDir is the root for JSON Schema files. An empty value uses the
|
||||||
|
// current directory. WithSchemaFS or WithSchemaFile replaces this source.
|
||||||
|
SchemaDir string
|
||||||
// Timeout is the transport-wide safety cap for the built-in LLM client
|
// Timeout is the transport-wide safety cap for the built-in LLM client
|
||||||
// when HTTPClient is absent or has a non-positive timeout.
|
// when HTTPClient is absent or has a non-positive timeout. A zero or negative
|
||||||
|
// value selects the 10-minute default.
|
||||||
Timeout time.Duration
|
Timeout time.Duration
|
||||||
// HTTPClient is cloned for the built-in LLM client. Its positive Timeout
|
// HTTPClient is cloned for the built-in LLM client. Its positive Timeout
|
||||||
// takes precedence over Config.Timeout as the transport-wide safety cap.
|
// takes precedence over Timeout. A zero or negative client Timeout inherits
|
||||||
|
// Timeout or the 10-minute default. The supplied client is not mutated. This
|
||||||
|
// field is ignored when WithLLMClient is used.
|
||||||
HTTPClient *http.Client
|
HTTPClient *http.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
// Option customizes engine construction.
|
// Option customizes engine construction.
|
||||||
|
//
|
||||||
|
// NewEngine applies options in argument order and ignores nil options. Within
|
||||||
|
// each prompt-source, profile-source, in-memory-profile, schema-source,
|
||||||
|
// model-client, and artifact-reader category, the last non-nil valid option
|
||||||
|
// replaces earlier options in that category. An invalid option fails
|
||||||
|
// construction even if a later option would replace it.
|
||||||
type Option interface {
|
type Option interface {
|
||||||
apply(*engineOptions) error
|
apply(*engineOptions) error
|
||||||
}
|
}
|
||||||
@@ -82,7 +133,10 @@ type engineOptions struct {
|
|||||||
artifactSource bool
|
artifactSource bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithLLMClient injects a custom LLM client for execution.
|
// WithLLMClient replaces the built-in model client used by [Engine.Run].
|
||||||
|
//
|
||||||
|
// A nil client makes NewEngine fail with ErrInvalidConfig. The client may be
|
||||||
|
// called concurrently and is not used by [Engine.Prepare].
|
||||||
func WithLLMClient(client LLMClient) Option {
|
func WithLLMClient(client LLMClient) Option {
|
||||||
return optionFunc(func(options *engineOptions) error {
|
return optionFunc(func(options *engineOptions) error {
|
||||||
if client == nil {
|
if client == nil {
|
||||||
@@ -93,7 +147,11 @@ func WithLLMClient(client LLMClient) Option {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithArtifactReader injects a reader for every input artifact reference.
|
// WithArtifactReader replaces the default reader for every input artifact
|
||||||
|
// reference, regardless of its ArtifactRef.Type.
|
||||||
|
//
|
||||||
|
// A nil reader makes NewEngine fail with ErrInvalidConfig. The reader may be
|
||||||
|
// called concurrently.
|
||||||
func WithArtifactReader(reader ArtifactReader) Option {
|
func WithArtifactReader(reader ArtifactReader) Option {
|
||||||
return optionFunc(func(options *engineOptions) error {
|
return optionFunc(func(options *engineOptions) error {
|
||||||
if reader == nil {
|
if reader == nil {
|
||||||
@@ -109,6 +167,9 @@ func WithArtifactReader(reader ArtifactReader) Option {
|
|||||||
//
|
//
|
||||||
// The source uses the same strict prompt YAML rules as configured prompt
|
// The source uses the same strict prompt YAML rules as configured prompt
|
||||||
// directories, and prompt content_file paths resolve within this source.
|
// directories, and prompt content_file paths resolve within this source.
|
||||||
|
// fsys must be non-nil and root must be non-empty; otherwise NewEngine fails
|
||||||
|
// with ErrInvalidConfig. This option replaces Config.PromptDir and earlier
|
||||||
|
// prompt-source options.
|
||||||
func WithPromptFS(fsys fs.FS, root string) Option {
|
func WithPromptFS(fsys fs.FS, root string) Option {
|
||||||
return optionFunc(func(options *engineOptions) error {
|
return optionFunc(func(options *engineOptions) error {
|
||||||
if fsys == nil {
|
if fsys == nil {
|
||||||
@@ -125,7 +186,9 @@ func WithPromptFS(fsys fs.FS, root string) Option {
|
|||||||
|
|
||||||
// WithPromptFile loads prompt definitions from the single prompt file at path.
|
// WithPromptFile loads prompt definitions from the single prompt file at path.
|
||||||
//
|
//
|
||||||
// Relative prompt content_file paths resolve from the file's directory.
|
// Relative prompt content_file paths resolve from the file's directory. path
|
||||||
|
// must name an existing non-directory file when NewEngine applies the option.
|
||||||
|
// This option replaces Config.PromptDir and earlier prompt-source options.
|
||||||
func WithPromptFile(path string) Option {
|
func WithPromptFile(path string) Option {
|
||||||
return optionFunc(func(options *engineOptions) error {
|
return optionFunc(func(options *engineOptions) error {
|
||||||
fsys, root, err := fileSource(path)
|
fsys, root, err := fileSource(path)
|
||||||
@@ -142,6 +205,10 @@ func WithPromptFile(path string) Option {
|
|||||||
//
|
//
|
||||||
// Profiles from this source overlay built-in profiles. Profile YAML must use
|
// Profiles from this source overlay built-in profiles. Profile YAML must use
|
||||||
// api_key_env for environment-based credentials; raw API keys are rejected.
|
// api_key_env for environment-based credentials; raw API keys are rejected.
|
||||||
|
// fsys must be non-nil and root must be non-empty; otherwise NewEngine fails
|
||||||
|
// with ErrInvalidConfig. This option replaces Config.ProfileDir and earlier
|
||||||
|
// file or FS profile-source options, but remains below WithProfiles in
|
||||||
|
// precedence.
|
||||||
func WithProfileFS(fsys fs.FS, root string) Option {
|
func WithProfileFS(fsys fs.FS, root string) Option {
|
||||||
return optionFunc(func(options *engineOptions) error {
|
return optionFunc(func(options *engineOptions) error {
|
||||||
if fsys == nil {
|
if fsys == nil {
|
||||||
@@ -159,7 +226,10 @@ func WithProfileFS(fsys fs.FS, root string) Option {
|
|||||||
// WithProfileFile loads execution profiles from the single profile file at path.
|
// WithProfileFile loads execution profiles from the single profile file at path.
|
||||||
//
|
//
|
||||||
// The profile overlays built-in profiles. Profile YAML must use api_key_env for
|
// The profile overlays built-in profiles. Profile YAML must use api_key_env for
|
||||||
// environment-based credentials; raw API keys are rejected.
|
// environment-based credentials; raw API keys are rejected. path must name an
|
||||||
|
// existing non-directory file when NewEngine applies the option. This option
|
||||||
|
// replaces Config.ProfileDir and earlier file or FS profile-source options,
|
||||||
|
// but remains below WithProfiles in precedence.
|
||||||
func WithProfileFile(path string) Option {
|
func WithProfileFile(path string) Option {
|
||||||
return optionFunc(func(options *engineOptions) error {
|
return optionFunc(func(options *engineOptions) error {
|
||||||
fsys, root, err := fileSource(path)
|
fsys, root, err := fileSource(path)
|
||||||
@@ -174,6 +244,11 @@ func WithProfileFile(path string) Option {
|
|||||||
|
|
||||||
// WithProfiles configures in-memory profiles that take precedence over
|
// WithProfiles configures in-memory profiles that take precedence over
|
||||||
// configured profile files and built-in profiles.
|
// configured profile files and built-in profiles.
|
||||||
|
//
|
||||||
|
// NewEngine validates and copies every profile. IDs must be unique within one
|
||||||
|
// call. An invalid profile, duplicate ID, or unsupported ExtraParams value
|
||||||
|
// makes construction fail with ErrInvalidConfig. Repeating WithProfiles
|
||||||
|
// replaces the complete earlier in-memory set rather than merging it.
|
||||||
func WithProfiles(profiles ...Profile) Option {
|
func WithProfiles(profiles ...Profile) Option {
|
||||||
return optionFunc(func(options *engineOptions) error {
|
return optionFunc(func(options *engineOptions) error {
|
||||||
repo, err := newMemoryProfileRepository(profiles)
|
repo, err := newMemoryProfileRepository(profiles)
|
||||||
@@ -189,7 +264,9 @@ func WithProfiles(profiles ...Profile) Option {
|
|||||||
// WithSchemaFS loads JSON Schema documents from fsys under root.
|
// WithSchemaFS loads JSON Schema documents from fsys under root.
|
||||||
//
|
//
|
||||||
// Prompt schema_path values resolve within this source when schema validation
|
// Prompt schema_path values resolve within this source when schema validation
|
||||||
// or structured output is requested.
|
// or structured output is requested. fsys must be non-nil and root must be
|
||||||
|
// non-empty; otherwise NewEngine fails with ErrInvalidConfig. This option
|
||||||
|
// replaces Config.SchemaDir and earlier schema-source options.
|
||||||
func WithSchemaFS(fsys fs.FS, root string) Option {
|
func WithSchemaFS(fsys fs.FS, root string) Option {
|
||||||
return optionFunc(func(options *engineOptions) error {
|
return optionFunc(func(options *engineOptions) error {
|
||||||
if fsys == nil {
|
if fsys == nil {
|
||||||
@@ -206,7 +283,9 @@ func WithSchemaFS(fsys fs.FS, root string) Option {
|
|||||||
|
|
||||||
// WithSchemaFile loads JSON Schema documents from the single schema file at path.
|
// WithSchemaFile loads JSON Schema documents from the single schema file at path.
|
||||||
//
|
//
|
||||||
// Prompt schema_path values refer to the file's base name.
|
// Prompt schema_path values refer to the file's base name. path must name an
|
||||||
|
// existing non-directory file when NewEngine applies the option. This option
|
||||||
|
// replaces Config.SchemaDir and earlier schema-source options.
|
||||||
func WithSchemaFile(path string) Option {
|
func WithSchemaFile(path string) Option {
|
||||||
return optionFunc(func(options *engineOptions) error {
|
return optionFunc(func(options *engineOptions) error {
|
||||||
fsys, root, err := fileSource(path)
|
fsys, root, err := fileSource(path)
|
||||||
@@ -220,6 +299,15 @@ func WithSchemaFile(path string) Option {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewEngine constructs an Engine from configuration and options.
|
// NewEngine constructs an Engine from configuration and options.
|
||||||
|
//
|
||||||
|
// Options are applied in order according to [Option]. PromptDir is required
|
||||||
|
// unless a prompt-source option is present. Construction validates option
|
||||||
|
// arguments and in-memory profiles but defers reading and validating prompt,
|
||||||
|
// file-backed profile, and schema contents until Prepare or Run needs them.
|
||||||
|
//
|
||||||
|
// NewEngine returns an error matching ErrInvalidConfig for invalid
|
||||||
|
// configuration or options. It does not perform model requests or require
|
||||||
|
// credentials.
|
||||||
func NewEngine(cfg Config, opts ...Option) (*Engine, error) {
|
func NewEngine(cfg Config, opts ...Option) (*Engine, error) {
|
||||||
var options engineOptions
|
var options engineOptions
|
||||||
for _, opt := range opts {
|
for _, opt := range opts {
|
||||||
@@ -305,7 +393,22 @@ func fileSource(name string) (fs.FS, string, error) {
|
|||||||
return os.DirFS(dir), filepath.ToSlash(base), nil
|
return os.DirFS(dir), filepath.ToSlash(base), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prepare resolves a prompt request without calling an LLM.
|
// Prepare resolves and renders a prompt request without calling an LLM.
|
||||||
|
//
|
||||||
|
// Prepare selects the prompt and profile, resolves effective execution
|
||||||
|
// settings and the output contract, loads and hashes inputs, loads structured
|
||||||
|
// output schema metadata when required, and renders the session ID and
|
||||||
|
// messages. The returned PreparedRun is owned by the caller and never contains
|
||||||
|
// a resolved API-key value, model output, or validation result.
|
||||||
|
//
|
||||||
|
// A nil Engine returns an error matching ErrInvalidConfig. Request and
|
||||||
|
// preparation failures may match ErrInvalidRequest, ErrPromptNotFound,
|
||||||
|
// ErrPromptLoad, ErrProfileNotFound, ErrProfileLoad, ErrProfileRequired,
|
||||||
|
// ErrAPIKeyEnvMissing, ErrArtifactLoad, ErrPromptRender, or ErrValidation as
|
||||||
|
// applicable. Cancellation is passed to the active collaborator and is
|
||||||
|
// reported in the applicable operation category; no general errors.Is
|
||||||
|
// relationship to ctx.Err is promised. Prepare returns no partial result on
|
||||||
|
// error.
|
||||||
func (e *Engine) Prepare(ctx context.Context, req RunRequest) (*PreparedRun, error) {
|
func (e *Engine) Prepare(ctx context.Context, req RunRequest) (*PreparedRun, error) {
|
||||||
if e == nil || e.runner == nil {
|
if e == nil || e.runner == nil {
|
||||||
return nil, fmt.Errorf("%w: engine is nil", ErrInvalidConfig)
|
return nil, fmt.Errorf("%w: engine is nil", ErrInvalidConfig)
|
||||||
@@ -323,7 +426,21 @@ func (e *Engine) Prepare(ctx context.Context, req RunRequest) (*PreparedRun, err
|
|||||||
return fromDomainPreparedRun(prepared), nil
|
return fromDomainPreparedRun(prepared), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run executes a prompt request and returns the generated artifact and metadata.
|
// Run prepares a request, invokes the configured LLMClient, and validates the
|
||||||
|
// generated output.
|
||||||
|
//
|
||||||
|
// A content-validation failure is a successful run whose
|
||||||
|
// RunResult.Validation has Status ValidationFailed. An inability to perform
|
||||||
|
// validation returns an error matching ErrValidation and no partial result.
|
||||||
|
// The public Engine does not perform output repair, so validation is
|
||||||
|
// single-pass even when OutputContract.RepairAttempts is positive.
|
||||||
|
//
|
||||||
|
// Run can return every error category documented by [Engine.Prepare], plus
|
||||||
|
// ErrLLMGenerate. Errors from injected clients remain available through
|
||||||
|
// errors.Is. Cancellation is passed through the active collaborator and is
|
||||||
|
// reported in the applicable operation category; no general errors.Is
|
||||||
|
// relationship to ctx.Err is promised. A nil Engine returns ErrInvalidConfig.
|
||||||
|
// Run returns no partial result on error.
|
||||||
func (e *Engine) Run(ctx context.Context, req RunRequest) (*RunResult, error) {
|
func (e *Engine) Run(ctx context.Context, req RunRequest) (*RunResult, error) {
|
||||||
if e == nil || e.runner == nil {
|
if e == nil || e.runner == nil {
|
||||||
return nil, fmt.Errorf("%w: engine is nil", ErrInvalidConfig)
|
return nil, fmt.Errorf("%w: engine is nil", ErrInvalidConfig)
|
||||||
|
|||||||
@@ -1020,6 +1020,7 @@ func TestPublicErrorsSupportErrorsIs(t *testing.T) {
|
|||||||
client promptkit.LLMClient
|
client promptkit.LLMClient
|
||||||
schemaDir string
|
schemaDir string
|
||||||
want error
|
want error
|
||||||
|
notWant error
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "invalid request",
|
name: "invalid request",
|
||||||
@@ -1028,10 +1029,11 @@ func TestPublicErrorsSupportErrorsIs(t *testing.T) {
|
|||||||
want: promptkit.ErrInvalidRequest,
|
want: promptkit.ErrInvalidRequest,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "prompt not found",
|
name: "prompt not found",
|
||||||
req: promptkit.RunRequest{PromptID: "missing.prompt"},
|
req: promptkit.RunRequest{PromptID: "missing.prompt"},
|
||||||
client: &fakeLLMClient{response: &promptkit.GenerateResponse{Content: "ok"}},
|
client: &fakeLLMClient{response: &promptkit.GenerateResponse{Content: "ok"}},
|
||||||
want: promptkit.ErrPromptNotFound,
|
want: promptkit.ErrPromptNotFound,
|
||||||
|
notWant: promptkit.ErrPromptLoad,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "profile not found",
|
name: "profile not found",
|
||||||
@@ -1042,8 +1044,9 @@ func TestPublicErrorsSupportErrorsIs(t *testing.T) {
|
|||||||
"transcript": promptkit.Inline("Rin opens the gate."),
|
"transcript": promptkit.Inline("Rin opens the gate."),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
client: &fakeLLMClient{response: &promptkit.GenerateResponse{Content: "ok"}},
|
client: &fakeLLMClient{response: &promptkit.GenerateResponse{Content: "ok"}},
|
||||||
want: promptkit.ErrProfileNotFound,
|
want: promptkit.ErrProfileNotFound,
|
||||||
|
notWant: promptkit.ErrProfileLoad,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "artifact load",
|
name: "artifact load",
|
||||||
@@ -1114,6 +1117,9 @@ func TestPublicErrorsSupportErrorsIs(t *testing.T) {
|
|||||||
if !errors.Is(err, tc.want) {
|
if !errors.Is(err, tc.want) {
|
||||||
t.Fatalf("expected errors.Is(%v), got %v", tc.want, err)
|
t.Fatalf("expected errors.Is(%v), got %v", tc.want, err)
|
||||||
}
|
}
|
||||||
|
if tc.notWant != nil && errors.Is(err, tc.notWant) {
|
||||||
|
t.Fatalf("did not expect errors.Is(%v), got %v", tc.notWant, err)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1699,6 +1705,16 @@ func TestEngineRunLayersTransportAndGenerationTimeouts(t *testing.T) {
|
|||||||
configTimeout: 5 * time.Second,
|
configTimeout: 5 * time.Second,
|
||||||
wantRemainingAtRequest: 5 * time.Second,
|
wantRemainingAtRequest: 5 * time.Second,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "zero configuration uses ten minute transport default",
|
||||||
|
wantRemainingAtRequest: 10 * time.Minute,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "negative configuration uses ten minute transport default",
|
||||||
|
configTimeout: -2 * time.Second,
|
||||||
|
suppliedClientTimeout: -3 * time.Second,
|
||||||
|
wantRemainingAtRequest: 10 * time.Minute,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "profile deadline is shorter than transport cap",
|
name: "profile deadline is shorter than transport cap",
|
||||||
suppliedClientTimeout: 6 * time.Second,
|
suppliedClientTimeout: 6 * time.Second,
|
||||||
|
|||||||
@@ -2,12 +2,16 @@ package promptkit
|
|||||||
|
|
||||||
import "fmt"
|
import "fmt"
|
||||||
|
|
||||||
// String returns a concise request summary without exposing direct API keys.
|
// String returns a concise request summary without exposing the direct API key
|
||||||
|
// or input and variable contents. Reflection-based formatting does not carry
|
||||||
|
// this guarantee.
|
||||||
func (r RunRequest) String() string {
|
func (r RunRequest) String() string {
|
||||||
return r.redactedString()
|
return r.redactedString()
|
||||||
}
|
}
|
||||||
|
|
||||||
// GoString returns a concise request summary without exposing direct API keys.
|
// GoString returns a concise request summary without exposing the direct API
|
||||||
|
// key or input and variable contents. Reflection-based formatting does not
|
||||||
|
// carry this guarantee.
|
||||||
func (r RunRequest) GoString() string {
|
func (r RunRequest) GoString() string {
|
||||||
return r.redactedString()
|
return r.redactedString()
|
||||||
}
|
}
|
||||||
@@ -27,13 +31,15 @@ func (r RunRequest) redactedString() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// String returns a concise request summary without exposing direct API keys or
|
// String returns a concise request summary without exposing direct API keys or
|
||||||
// rendered prompt content.
|
// rendered prompt content. Reflection-based formatting does not carry this
|
||||||
|
// guarantee.
|
||||||
func (r GenerateRequest) String() string {
|
func (r GenerateRequest) String() string {
|
||||||
return r.redactedString()
|
return r.redactedString()
|
||||||
}
|
}
|
||||||
|
|
||||||
// GoString returns a concise request summary without exposing direct API keys or
|
// GoString returns a concise request summary without exposing direct API keys or
|
||||||
// rendered prompt content.
|
// rendered prompt content. Reflection-based formatting does not carry this
|
||||||
|
// guarantee.
|
||||||
func (r GenerateRequest) GoString() string {
|
func (r GenerateRequest) GoString() string {
|
||||||
return r.redactedString()
|
return r.redactedString()
|
||||||
}
|
}
|
||||||
|
|||||||
9
json.go
9
json.go
@@ -5,7 +5,8 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MarshalJSON emits prepared-run timestamps only when they are non-zero.
|
// MarshalJSON implements json.Marshaler for PreparedRun. It uses RFC 3339
|
||||||
|
// timestamps, integer duration_ms, and omits zero timing values.
|
||||||
func (r PreparedRun) MarshalJSON() ([]byte, error) {
|
func (r PreparedRun) MarshalJSON() ([]byte, error) {
|
||||||
var startTime, endTime *time.Time
|
var startTime, endTime *time.Time
|
||||||
if !r.StartTime.IsZero() {
|
if !r.StartTime.IsZero() {
|
||||||
@@ -53,7 +54,8 @@ func (r PreparedRun) MarshalJSON() ([]byte, error) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// MarshalJSON emits run duration in milliseconds and omits zero timing values.
|
// MarshalJSON implements json.Marshaler for RunResult. It encodes Duration as
|
||||||
|
// integer milliseconds in duration_ms and omits zero timing values.
|
||||||
func (r RunResult) MarshalJSON() ([]byte, error) {
|
func (r RunResult) MarshalJSON() ([]byte, error) {
|
||||||
var startTime, endTime *time.Time
|
var startTime, endTime *time.Time
|
||||||
if !r.StartTime.IsZero() {
|
if !r.StartTime.IsZero() {
|
||||||
@@ -90,7 +92,8 @@ func (r RunResult) MarshalJSON() ([]byte, error) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnmarshalJSON decodes the supported run-result representation.
|
// UnmarshalJSON implements json.Unmarshaler for RunResult. It decodes
|
||||||
|
// duration_ms into Duration with millisecond precision.
|
||||||
func (r *RunResult) UnmarshalJSON(data []byte) error {
|
func (r *RunResult) UnmarshalJSON(data []byte) error {
|
||||||
var wire runResultJSON
|
var wire runResultJSON
|
||||||
if err := json.Unmarshal(data, &wire); err != nil {
|
if err := json.Unmarshal(data, &wire); err != nil {
|
||||||
|
|||||||
@@ -16,6 +16,10 @@ import (
|
|||||||
// It does not register global state, maintain a model catalog, or resolve
|
// It does not register global state, maintain a model catalog, or resolve
|
||||||
// credentials. If APIKeyRequired is true, callers satisfy it with
|
// credentials. If APIKeyRequired is true, callers satisfy it with
|
||||||
// RunRequest.APIKey. Raw API keys do not belong in profiles.
|
// RunRequest.APIKey. Raw API keys do not belong in profiles.
|
||||||
|
//
|
||||||
|
// The function copies the ExtraParams map itself but does not recursively copy
|
||||||
|
// nested values. Validation and a deep copy occur when NewEngine applies a
|
||||||
|
// WithProfiles option containing the returned Profile.
|
||||||
func OpenAICompatibleProfile(cfg OpenAICompatibleProfileConfig) Profile {
|
func OpenAICompatibleProfile(cfg OpenAICompatibleProfileConfig) Profile {
|
||||||
return Profile{
|
return Profile{
|
||||||
ID: cfg.ID,
|
ID: cfg.ID,
|
||||||
|
|||||||
@@ -26,6 +26,30 @@ func TestPreparedRunJSONOmitsZeroTimingValues(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPreparedRunJSONTimingRoundTrips(t *testing.T) {
|
||||||
|
start := time.Date(2026, time.July, 29, 12, 0, 0, 0, time.UTC)
|
||||||
|
prepared := promptkit.PreparedRun{
|
||||||
|
PromptID: "prompt",
|
||||||
|
StartTime: start,
|
||||||
|
EndTime: start.Add(1250 * time.Millisecond),
|
||||||
|
DurationMS: 1250,
|
||||||
|
}
|
||||||
|
|
||||||
|
payload, err := json.Marshal(prepared)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("marshal prepared run: %v", err)
|
||||||
|
}
|
||||||
|
var decoded promptkit.PreparedRun
|
||||||
|
if err := json.Unmarshal(payload, &decoded); err != nil {
|
||||||
|
t.Fatalf("unmarshal prepared run: %v", err)
|
||||||
|
}
|
||||||
|
if decoded.DurationMS != prepared.DurationMS ||
|
||||||
|
!decoded.StartTime.Equal(prepared.StartTime) ||
|
||||||
|
!decoded.EndTime.Equal(prepared.EndTime) {
|
||||||
|
t.Fatalf("timing values did not round trip: got %#v, want %#v", decoded, prepared)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestRunResultJSONUsesMillisecondsAndRoundTrips(t *testing.T) {
|
func TestRunResultJSONUsesMillisecondsAndRoundTrips(t *testing.T) {
|
||||||
start := time.Date(2026, time.July, 29, 12, 0, 0, 0, time.UTC)
|
start := time.Date(2026, time.July, 29, 12, 0, 0, 0, time.UTC)
|
||||||
result := promptkit.RunResult{
|
result := promptkit.RunResult{
|
||||||
@@ -74,6 +98,36 @@ func TestRunResultJSONUsesMillisecondsAndRoundTrips(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestEngineValidationIsSinglePass(t *testing.T) {
|
||||||
|
client := &fakeLLMClient{
|
||||||
|
response: &promptkit.GenerateResponse{Content: "not-json"},
|
||||||
|
}
|
||||||
|
engine := newContractEngineWithOptions(t, frameworkSchemaDir, promptkit.WithLLMClient(client))
|
||||||
|
|
||||||
|
result, err := engine.Run(context.Background(), promptkit.RunRequest{
|
||||||
|
PromptID: frameworkMarkdownSummaryPromptID,
|
||||||
|
Inputs: map[string]promptkit.ArtifactRef{
|
||||||
|
"transcript": promptkit.Inline("Rin opens the gate."),
|
||||||
|
"glossary": promptkit.Inline("gate: A guarded passage."),
|
||||||
|
},
|
||||||
|
Validation: &promptkit.OutputContract{
|
||||||
|
Format: promptkit.FormatJSON,
|
||||||
|
ValidationMode: promptkit.ValidationJSON,
|
||||||
|
RepairAttempts: 3,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("run with failed content validation: %v", err)
|
||||||
|
}
|
||||||
|
if result.Validation.Status != promptkit.ValidationFailed ||
|
||||||
|
result.Validation.RepairAttempts != 0 {
|
||||||
|
t.Fatalf("expected failed single-pass validation, got %#v", result.Validation)
|
||||||
|
}
|
||||||
|
if len(client.requests) != 1 {
|
||||||
|
t.Fatalf("expected one model generation, got %d", len(client.requests))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestRepeatedOptionsUseLastValueInEachCategory(t *testing.T) {
|
func TestRepeatedOptionsUseLastValueInEachCategory(t *testing.T) {
|
||||||
profile := promptkit.Profile{ID: "profile", Endpoint: "http://example.test/v1", Model: "model"}
|
profile := promptkit.Profile{ID: "profile", Endpoint: "http://example.test/v1", Model: "model"}
|
||||||
|
|
||||||
|
|||||||
573
types.go
573
types.go
@@ -5,160 +5,314 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ArtifactRefType defines how an artifact is referenced.
|
// ArtifactRefType identifies how an [ArtifactRef] supplies content.
|
||||||
type ArtifactRefType string
|
type ArtifactRefType string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
// ArtifactRefInline selects ArtifactRef.Body as the content.
|
||||||
ArtifactRefInline ArtifactRefType = "inline"
|
ArtifactRefInline ArtifactRefType = "inline"
|
||||||
ArtifactRefFile ArtifactRefType = "file"
|
// ArtifactRefFile selects the filesystem path in ArtifactRef.URI.
|
||||||
|
ArtifactRefFile ArtifactRefType = "file"
|
||||||
)
|
)
|
||||||
|
|
||||||
// OutputFormat defines the desired output format.
|
// OutputFormat identifies the media format of generated output.
|
||||||
|
// OutputFormat has a stable JSON string representation.
|
||||||
type OutputFormat string
|
type OutputFormat string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
FormatText OutputFormat = "text"
|
// FormatText identifies plain-text output.
|
||||||
|
FormatText OutputFormat = "text"
|
||||||
|
// FormatMarkdown identifies Markdown output.
|
||||||
FormatMarkdown OutputFormat = "markdown"
|
FormatMarkdown OutputFormat = "markdown"
|
||||||
FormatJSON OutputFormat = "json"
|
// FormatJSON identifies JSON output.
|
||||||
|
FormatJSON OutputFormat = "json"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ValidationMode defines the output validation strategy.
|
// ValidationMode identifies how generated output is checked.
|
||||||
|
// ValidationMode has a stable JSON string representation.
|
||||||
type ValidationMode string
|
type ValidationMode string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ValidationNone ValidationMode = "none"
|
// ValidationNone skips content validation.
|
||||||
ValidationBasic ValidationMode = "basic"
|
ValidationNone ValidationMode = "none"
|
||||||
ValidationJSON ValidationMode = "json"
|
// ValidationBasic requires non-empty output.
|
||||||
|
ValidationBasic ValidationMode = "basic"
|
||||||
|
// ValidationJSON requires syntactically valid JSON.
|
||||||
|
ValidationJSON ValidationMode = "json"
|
||||||
|
// ValidationJSONSchema requires JSON that satisfies OutputContract.SchemaPath.
|
||||||
ValidationJSONSchema ValidationMode = "json_schema"
|
ValidationJSONSchema ValidationMode = "json_schema"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ValidationStatus defines the result of a validation check.
|
// ValidationStatus identifies the completed state of an output check.
|
||||||
|
// ValidationStatus has a stable JSON string representation.
|
||||||
type ValidationStatus string
|
type ValidationStatus string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ValidationPassed ValidationStatus = "passed"
|
// ValidationPassed means the generated output satisfied its contract.
|
||||||
ValidationFailed ValidationStatus = "failed"
|
ValidationPassed ValidationStatus = "passed"
|
||||||
|
// ValidationFailed means validation completed and rejected the generated
|
||||||
|
// output. Engine.Run returns this status in a result, not as an error.
|
||||||
|
ValidationFailed ValidationStatus = "failed"
|
||||||
|
// ValidationSkipped means ValidationNone selected no content check.
|
||||||
ValidationSkipped ValidationStatus = "skipped"
|
ValidationSkipped ValidationStatus = "skipped"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CacheControlType defines provider cache behavior for prompt content.
|
// CacheControlType identifies provider cache behavior for prompt content.
|
||||||
|
// CacheControlType has a stable JSON string representation.
|
||||||
type CacheControlType string
|
type CacheControlType string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
// CacheControlEphemeral requests provider-defined ephemeral caching.
|
||||||
CacheControlEphemeral CacheControlType = "ephemeral"
|
CacheControlEphemeral CacheControlType = "ephemeral"
|
||||||
)
|
)
|
||||||
|
|
||||||
// StructuredOutputType identifies provider-level structured output modes.
|
// StructuredOutputType identifies provider-level structured output modes.
|
||||||
|
// StructuredOutputType has a stable JSON string representation.
|
||||||
type StructuredOutputType string
|
type StructuredOutputType string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
// StructuredOutputJSONSchema supplies JSON Schema response constraints.
|
||||||
StructuredOutputJSONSchema StructuredOutputType = "json_schema"
|
StructuredOutputJSONSchema StructuredOutputType = "json_schema"
|
||||||
)
|
)
|
||||||
|
|
||||||
// RunRequest represents a request to prepare or run a single prompt.
|
// RunRequest selects one prompt execution. It has no stable JSON
|
||||||
|
// representation.
|
||||||
|
//
|
||||||
|
// Prepare and Run copy the request's maps, pointers, and nested
|
||||||
|
// JSON-compatible values before using them. The caller may mutate the request
|
||||||
|
// after either method returns.
|
||||||
type RunRequest struct {
|
type RunRequest struct {
|
||||||
PromptID string
|
// PromptID is the required non-empty prompt identifier.
|
||||||
|
PromptID string
|
||||||
|
// PromptVersion optionally selects one version of PromptID. When empty, the
|
||||||
|
// prompt source must contain exactly one matching version.
|
||||||
PromptVersion string
|
PromptVersion string
|
||||||
ProfileID string
|
// ProfileID selects an execution profile. When empty, the prompt's default
|
||||||
APIKey string `json:"-"`
|
// profile is used; if both are empty, the error matches ErrProfileRequired
|
||||||
Inputs map[string]ArtifactRef
|
// and ErrInvalidRequest.
|
||||||
Vars map[string]string
|
ProfileID string
|
||||||
Execution *ExecutionTargetOverride
|
// APIKey is a request-scoped direct credential. It takes precedence over
|
||||||
Validation *OutputContract
|
// APIKeyEnv, is passed to the selected LLMClient, and is never included in
|
||||||
|
// prepared values, results, hashes, JSON, String, or GoString output.
|
||||||
|
APIKey string `json:"-"`
|
||||||
|
// Inputs maps prompt input names to references. A nil or empty map is valid
|
||||||
|
// only when the selected prompt and its templates require no inputs.
|
||||||
|
Inputs map[string]ArtifactRef
|
||||||
|
// Vars supplies Go-template data for messages and the session ID. Nil and
|
||||||
|
// empty maps are equivalent.
|
||||||
|
Vars map[string]string
|
||||||
|
// Execution optionally overrides individual profile execution settings.
|
||||||
|
// Nil uses the selected profile over framework defaults.
|
||||||
|
Execution *ExecutionTargetOverride
|
||||||
|
// Validation optionally replaces the prompt's complete output contract. It
|
||||||
|
// does not merge individual fields. Nil uses the prompt contract.
|
||||||
|
Validation *OutputContract
|
||||||
}
|
}
|
||||||
|
|
||||||
// PreparedRun contains prepared prompt execution state. It does not include
|
// PreparedRun contains prepared prompt execution state. It does not include
|
||||||
// resolved API key values, model output, validation results, or internal target
|
// resolved API key values, model output, validation results, or internal target
|
||||||
// presence metadata.
|
// presence metadata. PreparedRun has a stable JSON representation.
|
||||||
|
//
|
||||||
|
// All maps, slices, pointers, and schema values are caller-owned copies. JSON
|
||||||
|
// timestamps use RFC 3339 and zero timing values are omitted. Hash formats are
|
||||||
|
// opaque.
|
||||||
type PreparedRun struct {
|
type PreparedRun struct {
|
||||||
PromptID string `json:"prompt_id"`
|
// PromptID is the selected prompt identifier.
|
||||||
PromptVersion string `json:"prompt_version,omitempty"`
|
PromptID string `json:"prompt_id"`
|
||||||
PromptHash string `json:"prompt_hash,omitempty"`
|
// PromptVersion is the selected prompt version.
|
||||||
SelectedProfileID string `json:"selected_profile_id"`
|
PromptVersion string `json:"prompt_version,omitempty"`
|
||||||
EffectiveModelParams ExecutionTarget `json:"effective_model_params"`
|
// PromptHash is an opaque equality value for the selected definition.
|
||||||
OutputContract OutputContract `json:"output_contract"`
|
PromptHash string `json:"prompt_hash,omitempty"`
|
||||||
StructuredOutput *StructuredOutputSpec `json:"structured_output,omitempty"`
|
// SelectedProfileID is the explicit request profile or prompt default that
|
||||||
InputHashes map[string]string `json:"input_hashes,omitempty"`
|
// supplied execution settings.
|
||||||
SessionID string `json:"session_id,omitempty"`
|
SelectedProfileID string `json:"selected_profile_id"`
|
||||||
RenderedPromptHash string `json:"rendered_prompt_hash"`
|
// EffectiveModelParams contains framework defaults overlaid by the selected
|
||||||
Messages []RenderedMessage `json:"messages"`
|
// profile and then request overrides. It excludes resolved API-key values.
|
||||||
StartTime time.Time `json:"start_time,omitempty"`
|
EffectiveModelParams ExecutionTarget `json:"effective_model_params"`
|
||||||
EndTime time.Time `json:"end_time,omitempty"`
|
// OutputContract is the complete effective output contract.
|
||||||
DurationMS int64 `json:"duration_ms,omitempty"`
|
OutputContract OutputContract `json:"output_contract"`
|
||||||
|
// StructuredOutput is non-nil for JSON Schema validation and contains the
|
||||||
|
// provider-facing response constraint passed to an LLM client.
|
||||||
|
StructuredOutput *StructuredOutputSpec `json:"structured_output,omitempty"`
|
||||||
|
// InputHashes maps every supplied input name to its opaque artifact hash.
|
||||||
|
InputHashes map[string]string `json:"input_hashes,omitempty"`
|
||||||
|
// SessionID is the trimmed rendered session identifier, if any.
|
||||||
|
SessionID string `json:"session_id,omitempty"`
|
||||||
|
// RenderedPromptHash is an opaque equality value for SessionID and Messages.
|
||||||
|
RenderedPromptHash string `json:"rendered_prompt_hash"`
|
||||||
|
// Messages are the rendered messages that Run passes to the LLM client.
|
||||||
|
Messages []RenderedMessage `json:"messages"`
|
||||||
|
// StartTime is the UTC time at which preparation began.
|
||||||
|
StartTime time.Time `json:"start_time,omitempty"`
|
||||||
|
// EndTime is the UTC time at which preparation completed.
|
||||||
|
EndTime time.Time `json:"end_time,omitempty"`
|
||||||
|
// DurationMS is preparation elapsed time in integer milliseconds. JSON uses
|
||||||
|
// duration_ms and omits a zero value.
|
||||||
|
DurationMS int64 `json:"duration_ms,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// RunResult contains generated output, validation state, and run metadata.
|
// RunResult contains generated output, validation state, and run metadata.
|
||||||
|
// RunResult has a stable JSON representation and round-trips its Duration
|
||||||
|
// through the duration_ms JSON field.
|
||||||
|
//
|
||||||
|
// All maps, slices, and nested values are caller-owned copies. JSON timestamps
|
||||||
|
// use RFC 3339 and zero timing values are omitted. Run IDs and hash formats are
|
||||||
|
// opaque.
|
||||||
type RunResult struct {
|
type RunResult struct {
|
||||||
RunID string `json:"run_id"`
|
// RunID is an opaque identifier for this invocation.
|
||||||
Artifact Artifact `json:"artifact"`
|
RunID string `json:"run_id"`
|
||||||
RawOutput string `json:"raw_output"`
|
// Artifact contains the generated output and derived metadata.
|
||||||
Validation ValidationResult `json:"validation"`
|
Artifact Artifact `json:"artifact"`
|
||||||
PromptID string `json:"prompt_id"`
|
// RawOutput is the exact generated content before artifact classification
|
||||||
PromptVersion string `json:"prompt_version,omitempty"`
|
// and validation.
|
||||||
PromptHash string `json:"prompt_hash,omitempty"`
|
RawOutput string `json:"raw_output"`
|
||||||
RenderedPromptHash string `json:"rendered_prompt_hash"`
|
// Validation records the completed content check.
|
||||||
SelectedProfileID string `json:"selected_profile_id"`
|
Validation ValidationResult `json:"validation"`
|
||||||
ModelName string `json:"model_name"`
|
// PromptID is the selected prompt identifier.
|
||||||
Endpoint string `json:"endpoint"`
|
PromptID string `json:"prompt_id"`
|
||||||
EffectiveModelParams ExecutionTarget `json:"effective_model_params"`
|
// PromptVersion is the selected prompt version.
|
||||||
InputHashes map[string]string `json:"input_hashes,omitempty"`
|
PromptVersion string `json:"prompt_version,omitempty"`
|
||||||
Usage TokenUsage `json:"usage"`
|
// PromptHash is the same opaque definition equality value exposed by
|
||||||
StartTime time.Time `json:"start_time,omitempty"`
|
// PreparedRun.
|
||||||
EndTime time.Time `json:"end_time,omitempty"`
|
PromptHash string `json:"prompt_hash,omitempty"`
|
||||||
Duration time.Duration `json:"-"`
|
// RenderedPromptHash is the same opaque rendered-prompt equality value
|
||||||
|
// computed during preparation.
|
||||||
|
RenderedPromptHash string `json:"rendered_prompt_hash"`
|
||||||
|
// SelectedProfileID identifies the profile used for execution.
|
||||||
|
SelectedProfileID string `json:"selected_profile_id"`
|
||||||
|
// ModelName is the effective model name and equals
|
||||||
|
// EffectiveModelParams.Model.
|
||||||
|
ModelName string `json:"model_name"`
|
||||||
|
// Endpoint is the effective base endpoint and equals
|
||||||
|
// EffectiveModelParams.Endpoint.
|
||||||
|
Endpoint string `json:"endpoint"`
|
||||||
|
// EffectiveModelParams contains the settings supplied to the LLM client,
|
||||||
|
// excluding resolved API-key values.
|
||||||
|
EffectiveModelParams ExecutionTarget `json:"effective_model_params"`
|
||||||
|
// InputHashes are the opaque input equality values computed during
|
||||||
|
// preparation.
|
||||||
|
InputHashes map[string]string `json:"input_hashes,omitempty"`
|
||||||
|
// Usage is the token accounting reported by the LLM client.
|
||||||
|
Usage TokenUsage `json:"usage"`
|
||||||
|
// StartTime is the UTC time immediately before preparation begins.
|
||||||
|
StartTime time.Time `json:"start_time,omitempty"`
|
||||||
|
// EndTime is the UTC time after generation and validation complete.
|
||||||
|
EndTime time.Time `json:"end_time,omitempty"`
|
||||||
|
// Duration covers preparation, generation, and validation. JSON represents
|
||||||
|
// it as integer milliseconds in duration_ms and omits a zero value.
|
||||||
|
Duration time.Duration `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ArtifactRef represents a reference to prompt input content.
|
// ArtifactRef identifies prompt input content. It has no stable JSON
|
||||||
|
// representation. Prefer [File], [Inline], or [InlineWithURI] to construct one.
|
||||||
type ArtifactRef struct {
|
type ArtifactRef struct {
|
||||||
|
// Type must be ArtifactRefInline or ArtifactRefFile.
|
||||||
Type ArtifactRefType
|
Type ArtifactRefType
|
||||||
URI string
|
// URI is the file path for ArtifactRefFile and optional provenance metadata
|
||||||
|
// for ArtifactRefInline.
|
||||||
|
URI string
|
||||||
|
// Body is the content for ArtifactRefInline and is ignored for
|
||||||
|
// ArtifactRefFile.
|
||||||
Body string
|
Body string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Artifact represents loaded artifact content.
|
// Artifact represents loaded or generated content and has a stable JSON
|
||||||
|
// representation. Body uses encoding/json's base64 representation for []byte.
|
||||||
type Artifact struct {
|
type Artifact struct {
|
||||||
Name string `json:"name"`
|
// Name is artifact metadata. During input preparation the engine fills an
|
||||||
|
// empty reader-supplied name with the request input-map key.
|
||||||
|
Name string `json:"name"`
|
||||||
|
// ContentType is the media type reported by the reader or derived for
|
||||||
|
// generated output.
|
||||||
ContentType string `json:"content_type"`
|
ContentType string `json:"content_type"`
|
||||||
Body []byte `json:"body"`
|
// Body is the artifact content. Engine boundaries copy this slice.
|
||||||
URI string `json:"uri"`
|
Body []byte `json:"body"`
|
||||||
Size int64 `json:"size"`
|
// URI is optional source or result provenance metadata.
|
||||||
Hash string `json:"hash"`
|
URI string `json:"uri"`
|
||||||
|
// Size is content-size metadata in bytes.
|
||||||
|
Size int64 `json:"size"`
|
||||||
|
// Hash is an opaque content equality value when the producing reader
|
||||||
|
// supplies one. Its format and algorithm are not API contracts.
|
||||||
|
Hash string `json:"hash"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ArtifactReader resolves a prompt input reference into its content.
|
// ArtifactReader resolves a prompt input reference into its content.
|
||||||
//
|
//
|
||||||
// Readers are responsible for supplying artifact metadata. The engine assigns
|
// Read may be called concurrently. It must honor ctx cancellation to make
|
||||||
// an input-map name only when the returned artifact name is empty.
|
// Prepare and Run responsive to cancellation. The engine passes a copied ref
|
||||||
|
// and immediately copies the returned Artifact.Body; it does not retain either
|
||||||
|
// value. Readers supply artifact metadata, and the engine assigns an input-map
|
||||||
|
// name only when the returned artifact name is empty.
|
||||||
|
//
|
||||||
|
// Returning a non-nil error makes the engine return an error matching
|
||||||
|
// ErrArtifactLoad while preserving the reader error through errors.Is.
|
||||||
|
// Returning a nil artifact with a nil error also produces ErrArtifactLoad.
|
||||||
type ArtifactReader interface {
|
type ArtifactReader interface {
|
||||||
Read(context.Context, ArtifactRef) (*Artifact, error)
|
Read(context.Context, ArtifactRef) (*Artifact, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExecutionTarget represents effective model runtime settings.
|
// ExecutionTarget represents effective model runtime settings and has a stable
|
||||||
|
// JSON representation. It never exposes a resolved API-key value.
|
||||||
type ExecutionTarget struct {
|
type ExecutionTarget struct {
|
||||||
Endpoint string `json:"endpoint"`
|
// Endpoint is the model-provider base URL.
|
||||||
Model string `json:"model"`
|
Endpoint string `json:"endpoint"`
|
||||||
Temperature float64 `json:"temperature"`
|
// Model is the provider model identifier.
|
||||||
MaxTokens int `json:"max_tokens"`
|
Model string `json:"model"`
|
||||||
TopP float64 `json:"top_p"`
|
// Temperature is the effective sampling temperature from 0 through 2.
|
||||||
TimeoutSeconds int `json:"timeout_seconds"`
|
Temperature float64 `json:"temperature"`
|
||||||
ServiceTier string `json:"service_tier"`
|
// MaxTokens is the non-negative effective output-token limit. Zero leaves
|
||||||
ReasoningEffort string `json:"reasoning_effort"`
|
// the limit unspecified to compatible providers unless it was an explicit
|
||||||
APIKeyEnv string `json:"api_key_env"`
|
// request override.
|
||||||
ExtraParams map[string]any `json:"extra_params"`
|
MaxTokens int `json:"max_tokens"`
|
||||||
|
// TopP is the effective nucleus-sampling value from 0 through 1.
|
||||||
|
TopP float64 `json:"top_p"`
|
||||||
|
// TimeoutSeconds is the non-negative per-generation deadline. Zero disables
|
||||||
|
// this deadline without disabling caller cancellation or the transport cap.
|
||||||
|
TimeoutSeconds int `json:"timeout_seconds"`
|
||||||
|
// ServiceTier is an optional provider-specific request tier.
|
||||||
|
ServiceTier string `json:"service_tier"`
|
||||||
|
// ReasoningEffort is an optional provider-specific reasoning setting.
|
||||||
|
ReasoningEffort string `json:"reasoning_effort"`
|
||||||
|
// APIKeyEnv is an environment-variable name, not its credential value.
|
||||||
|
APIKeyEnv string `json:"api_key_env"`
|
||||||
|
// ExtraParams contains copied JSON-compatible provider parameters.
|
||||||
|
ExtraParams map[string]any `json:"extra_params"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExecutionTargetOverride represents per-request runtime setting overrides.
|
// ExecutionTargetOverride represents per-request runtime setting overrides and
|
||||||
|
// has no stable JSON representation.
|
||||||
|
//
|
||||||
|
// Non-empty string fields replace profile values. Non-nil numeric pointers
|
||||||
|
// replace profile values and preserve explicit zero. A non-empty ExtraParams
|
||||||
|
// map replaces the complete profile map rather than merging keys. Empty string
|
||||||
|
// fields, nil pointers, and a nil or empty ExtraParams map inherit the selected
|
||||||
|
// profile over framework defaults.
|
||||||
type ExecutionTargetOverride struct {
|
type ExecutionTargetOverride struct {
|
||||||
Endpoint string
|
// Endpoint replaces the profile endpoint when non-empty.
|
||||||
Model string
|
Endpoint string
|
||||||
Temperature *float64
|
// Model replaces the profile model when non-empty.
|
||||||
MaxTokens *int
|
Model string
|
||||||
TopP *float64
|
// Temperature, when non-nil, must point to a value from 0 through 2.
|
||||||
TimeoutSeconds *int
|
Temperature *float64
|
||||||
ServiceTier string
|
// MaxTokens, when non-nil, must point to a non-negative value.
|
||||||
|
MaxTokens *int
|
||||||
|
// TopP, when non-nil, must point to a value from 0 through 1.
|
||||||
|
TopP *float64
|
||||||
|
// TimeoutSeconds, when non-nil, must point to a non-negative value. A
|
||||||
|
// pointed-to zero disables the per-generation deadline.
|
||||||
|
TimeoutSeconds *int
|
||||||
|
// ServiceTier replaces the profile value when non-blank.
|
||||||
|
ServiceTier string
|
||||||
|
// ReasoningEffort replaces the profile value when non-blank. An empty value
|
||||||
|
// cannot clear a profile setting.
|
||||||
ReasoningEffort string
|
ReasoningEffort string
|
||||||
APIKeyEnv string
|
// APIKeyEnv replaces the profile environment-variable name when non-blank.
|
||||||
ExtraParams map[string]any
|
// A direct RunRequest.APIKey still takes precedence over environment lookup.
|
||||||
|
APIKeyEnv string
|
||||||
|
// ExtraParams, when non-empty, replaces the profile map. Values must be
|
||||||
|
// JSON-compatible: nil, booleans, finite numbers, strings, arrays or slices,
|
||||||
|
// and maps with non-empty string keys. Cycles are invalid.
|
||||||
|
ExtraParams map[string]any
|
||||||
}
|
}
|
||||||
|
|
||||||
// Profile is an in-memory execution profile for library consumers.
|
// Profile is an in-memory execution profile for library consumers.
|
||||||
@@ -166,19 +320,39 @@ type ExecutionTargetOverride struct {
|
|||||||
// It is equivalent to a loaded profile file after validation. Raw API keys do
|
// It is equivalent to a loaded profile file after validation. Raw API keys do
|
||||||
// not belong in profiles; use APIKeyRequired to require callers to provide
|
// not belong in profiles; use APIKeyRequired to require callers to provide
|
||||||
// RunRequest.APIKey for each request, or use profile YAML api_key_env with file
|
// RunRequest.APIKey for each request, or use profile YAML api_key_env with file
|
||||||
// and FS profile sources.
|
// and FS profile sources. Profile has no stable JSON representation.
|
||||||
|
//
|
||||||
|
// WithProfiles validates and copies Profile values during NewEngine. Numeric
|
||||||
|
// zero, blank strings, and an empty ExtraParams map inherit framework defaults;
|
||||||
|
// use ExecutionTargetOverride pointer fields to request explicit numeric zero.
|
||||||
type Profile struct {
|
type Profile struct {
|
||||||
ID string
|
// ID is the required non-blank profile identifier. WithProfiles trims it.
|
||||||
Endpoint string
|
ID string
|
||||||
Model string
|
// Endpoint is the required non-blank model-provider base URL.
|
||||||
Temperature float64
|
Endpoint string
|
||||||
MaxTokens int
|
// Model is the required non-blank provider model identifier.
|
||||||
TopP float64
|
Model string
|
||||||
TimeoutSeconds int
|
// Temperature is from 0 through 2. Zero inherits the framework default.
|
||||||
ServiceTier string
|
Temperature float64
|
||||||
|
// MaxTokens is non-negative. Zero inherits the framework default.
|
||||||
|
MaxTokens int
|
||||||
|
// TopP is from 0 through 1. Zero inherits the framework default rather than
|
||||||
|
// selecting an explicit zero.
|
||||||
|
TopP float64
|
||||||
|
// TimeoutSeconds is non-negative. Zero inherits the framework default.
|
||||||
|
TimeoutSeconds int
|
||||||
|
// ServiceTier is optional; a blank value inherits the framework default.
|
||||||
|
ServiceTier string
|
||||||
|
// ReasoningEffort is optional; a blank value inherits the framework
|
||||||
|
// default.
|
||||||
ReasoningEffort string
|
ReasoningEffort string
|
||||||
APIKeyRequired bool
|
// APIKeyRequired requires a non-blank RunRequest.APIKey. It does not store a
|
||||||
ExtraParams map[string]any
|
// credential or enable environment lookup.
|
||||||
|
APIKeyRequired bool
|
||||||
|
// ExtraParams contains provider-specific JSON-compatible values. An empty
|
||||||
|
// map inherits framework defaults. WithProfiles validates and deeply copies
|
||||||
|
// it during NewEngine.
|
||||||
|
ExtraParams map[string]any
|
||||||
}
|
}
|
||||||
|
|
||||||
// OpenAICompatibleProfileConfig configures an OpenAI-compatible in-memory
|
// OpenAICompatibleProfileConfig configures an OpenAI-compatible in-memory
|
||||||
@@ -186,120 +360,215 @@ type Profile struct {
|
|||||||
//
|
//
|
||||||
// It contains ordinary profile fields for OpenAI-compatible chat-completions
|
// It contains ordinary profile fields for OpenAI-compatible chat-completions
|
||||||
// endpoints. APIKeyRequired is satisfied by RunRequest.APIKey. Raw API keys do
|
// endpoints. APIKeyRequired is satisfied by RunRequest.APIKey. Raw API keys do
|
||||||
// not belong in this config.
|
// not belong in this config. OpenAICompatibleProfileConfig has no stable JSON
|
||||||
|
// representation and is not validated until its resulting Profile is supplied
|
||||||
|
// through WithProfiles to NewEngine.
|
||||||
type OpenAICompatibleProfileConfig struct {
|
type OpenAICompatibleProfileConfig struct {
|
||||||
ID string
|
// ID becomes Profile.ID.
|
||||||
Endpoint string
|
ID string
|
||||||
Model string
|
// Endpoint becomes Profile.Endpoint.
|
||||||
APIKeyRequired bool
|
Endpoint string
|
||||||
Temperature float64
|
// Model becomes Profile.Model.
|
||||||
MaxTokens int
|
Model string
|
||||||
TopP float64
|
// APIKeyRequired becomes Profile.APIKeyRequired.
|
||||||
TimeoutSeconds int
|
APIKeyRequired bool
|
||||||
ServiceTier string
|
// Temperature becomes Profile.Temperature.
|
||||||
|
Temperature float64
|
||||||
|
// MaxTokens becomes Profile.MaxTokens.
|
||||||
|
MaxTokens int
|
||||||
|
// TopP becomes Profile.TopP.
|
||||||
|
TopP float64
|
||||||
|
// TimeoutSeconds becomes Profile.TimeoutSeconds.
|
||||||
|
TimeoutSeconds int
|
||||||
|
// ServiceTier becomes Profile.ServiceTier.
|
||||||
|
ServiceTier string
|
||||||
|
// ReasoningEffort becomes Profile.ReasoningEffort.
|
||||||
ReasoningEffort string
|
ReasoningEffort string
|
||||||
ExtraParams map[string]any
|
// ExtraParams becomes a shallow-copied Profile.ExtraParams map. NewEngine
|
||||||
|
// performs validation and a deep copy when WithProfiles applies the result.
|
||||||
|
ExtraParams map[string]any
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExecutionTargetPresence tracks which numeric runtime settings were explicit
|
// ExecutionTargetPresence tracks which numeric runtime settings were explicit
|
||||||
// request overrides.
|
// request overrides, including explicit zero values. It has a stable JSON
|
||||||
|
// representation and is supplied to injected LLM clients so they can preserve
|
||||||
|
// omission semantics.
|
||||||
type ExecutionTargetPresence struct {
|
type ExecutionTargetPresence struct {
|
||||||
Temperature bool `json:"temperature"`
|
// Temperature reports a non-nil ExecutionTargetOverride.Temperature.
|
||||||
MaxTokens bool `json:"max_tokens"`
|
Temperature bool `json:"temperature"`
|
||||||
TopP bool `json:"top_p"`
|
// MaxTokens reports a non-nil ExecutionTargetOverride.MaxTokens.
|
||||||
|
MaxTokens bool `json:"max_tokens"`
|
||||||
|
// TopP reports a non-nil ExecutionTargetOverride.TopP.
|
||||||
|
TopP bool `json:"top_p"`
|
||||||
|
// TimeoutSeconds reports a non-nil ExecutionTargetOverride.TimeoutSeconds.
|
||||||
TimeoutSeconds bool `json:"timeout_seconds"`
|
TimeoutSeconds bool `json:"timeout_seconds"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// OutputContract defines output and validation requirements.
|
// OutputContract defines output and validation requirements and has a stable
|
||||||
|
// JSON representation.
|
||||||
|
//
|
||||||
|
// A non-nil RunRequest.Validation replaces the complete prompt contract. It
|
||||||
|
// does not merge fields. The public Engine validates generated output once and
|
||||||
|
// does not install an output repairer.
|
||||||
type OutputContract struct {
|
type OutputContract struct {
|
||||||
Format OutputFormat `json:"format"`
|
// Format selects generated artifact metadata. An empty effective value
|
||||||
|
// defaults to FormatText.
|
||||||
|
Format OutputFormat `json:"format"`
|
||||||
|
// ValidationMode selects the content check. Use one of the declared
|
||||||
|
// ValidationMode constants.
|
||||||
ValidationMode ValidationMode `json:"validation_mode"`
|
ValidationMode ValidationMode `json:"validation_mode"`
|
||||||
SchemaPath string `json:"schema_path"`
|
// SchemaPath is required when ValidationMode is ValidationJSONSchema and is
|
||||||
RepairAttempts int `json:"repair_attempts"`
|
// ignored by other modes.
|
||||||
|
SchemaPath string `json:"schema_path"`
|
||||||
|
// RepairAttempts is a requested repair limit. A non-positive value requests
|
||||||
|
// no repairs. The public Engine performs no repairs even when this value is
|
||||||
|
// positive, so its runs report zero attempts used.
|
||||||
|
RepairAttempts int `json:"repair_attempts"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ValidationResult represents output validation state.
|
// ValidationResult represents a completed output check and has a stable JSON
|
||||||
|
// representation. An operational inability to perform validation is returned
|
||||||
|
// as ErrValidation instead of a ValidationResult.
|
||||||
type ValidationResult struct {
|
type ValidationResult struct {
|
||||||
Status ValidationStatus `json:"status"`
|
// Status is Passed, Failed, or Skipped.
|
||||||
Mode ValidationMode `json:"mode"`
|
Status ValidationStatus `json:"status"`
|
||||||
Errors []string `json:"errors,omitempty"`
|
// Mode is the effective validation mode.
|
||||||
SchemaPath string `json:"schema_path,omitempty"`
|
Mode ValidationMode `json:"mode"`
|
||||||
RepairAttempts int `json:"repair_attempts"`
|
// Errors contains validation diagnostics when Status is ValidationFailed.
|
||||||
IsValid bool `json:"is_valid"`
|
Errors []string `json:"errors,omitempty"`
|
||||||
|
// SchemaPath is the effective schema path for JSON Schema validation.
|
||||||
|
SchemaPath string `json:"schema_path,omitempty"`
|
||||||
|
// RepairAttempts is the number of repairs actually attempted. It is always
|
||||||
|
// zero for the public Engine.
|
||||||
|
RepairAttempts int `json:"repair_attempts"`
|
||||||
|
// IsValid is true for ValidationPassed and ValidationSkipped and false for
|
||||||
|
// ValidationFailed.
|
||||||
|
IsValid bool `json:"is_valid"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// TokenUsage tracks token consumption.
|
// TokenUsage contains model-client token accounting and has a stable JSON
|
||||||
|
// representation. Promptkit preserves values reported by the client and does
|
||||||
|
// not derive or reconcile them.
|
||||||
type TokenUsage struct {
|
type TokenUsage struct {
|
||||||
PromptTokens int `json:"prompt_tokens"`
|
// PromptTokens is the reported input-token count.
|
||||||
|
PromptTokens int `json:"prompt_tokens"`
|
||||||
|
// CompletionTokens is the reported generated-token count.
|
||||||
CompletionTokens int `json:"completion_tokens"`
|
CompletionTokens int `json:"completion_tokens"`
|
||||||
TotalTokens int `json:"total_tokens"`
|
// TotalTokens is the reported total-token count.
|
||||||
CachedTokens int `json:"cached_tokens"`
|
TotalTokens int `json:"total_tokens"`
|
||||||
|
// CachedTokens is the reported cached-input-token count.
|
||||||
|
CachedTokens int `json:"cached_tokens"`
|
||||||
|
// CacheWriteTokens is the reported cache-write-token count.
|
||||||
CacheWriteTokens int `json:"cache_write_tokens"`
|
CacheWriteTokens int `json:"cache_write_tokens"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// RenderedPrompt is the fully rendered prompt passed to an LLM client.
|
// RenderedPrompt is the fully rendered prompt passed to an LLM client and has
|
||||||
|
// a stable JSON representation.
|
||||||
type RenderedPrompt struct {
|
type RenderedPrompt struct {
|
||||||
SessionID string `json:"session_id,omitempty"`
|
// SessionID is the optional trimmed session identifier rendered from the
|
||||||
Messages []RenderedMessage `json:"messages"`
|
// prompt definition.
|
||||||
|
SessionID string `json:"session_id,omitempty"`
|
||||||
|
// Messages contains rendered messages in definition order.
|
||||||
|
Messages []RenderedMessage `json:"messages"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// RenderedMessage is a rendered chat message.
|
// RenderedMessage is a rendered chat message and has a stable JSON
|
||||||
|
// representation.
|
||||||
type RenderedMessage struct {
|
type RenderedMessage struct {
|
||||||
Role string `json:"role"`
|
// Role is the definition-supplied chat role.
|
||||||
Content string `json:"content"`
|
Role string `json:"role"`
|
||||||
|
// Content is the rendered message text.
|
||||||
|
Content string `json:"content"`
|
||||||
|
// CacheControl is optional provider cache metadata.
|
||||||
CacheControl *CacheControl `json:"cache_control,omitempty"`
|
CacheControl *CacheControl `json:"cache_control,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// CacheControl describes provider cache metadata attached to prompt content.
|
// CacheControl describes provider cache metadata attached to prompt content
|
||||||
|
// and has a stable JSON representation.
|
||||||
type CacheControl struct {
|
type CacheControl struct {
|
||||||
|
// Type identifies the cache behavior.
|
||||||
Type CacheControlType `json:"type"`
|
Type CacheControlType `json:"type"`
|
||||||
TTL string `json:"ttl,omitempty"`
|
// TTL is an optional provider cache lifetime.
|
||||||
|
TTL string `json:"ttl,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// StructuredOutputSpec describes provider-level structured output.
|
// StructuredOutputSpec describes provider-level structured output and has a
|
||||||
|
// stable JSON representation.
|
||||||
type StructuredOutputSpec struct {
|
type StructuredOutputSpec struct {
|
||||||
Type StructuredOutputType `json:"type"`
|
// Type identifies the structured-output mechanism.
|
||||||
|
Type StructuredOutputType `json:"type"`
|
||||||
|
// JSONSchema contains constraints when Type is StructuredOutputJSONSchema.
|
||||||
JSONSchema *StructuredOutputJSONSpec `json:"json_schema,omitempty"`
|
JSONSchema *StructuredOutputJSONSpec `json:"json_schema,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// StructuredOutputJSONSpec contains JSON Schema output constraints.
|
// StructuredOutputJSONSpec contains provider-facing JSON Schema output
|
||||||
|
// constraints and has a stable JSON representation.
|
||||||
type StructuredOutputJSONSpec struct {
|
type StructuredOutputJSONSpec struct {
|
||||||
Name string `json:"name"`
|
// Name is the provider-facing schema name.
|
||||||
Strict bool `json:"strict"`
|
Name string `json:"name"`
|
||||||
Schema any `json:"schema"`
|
// Strict requests strict provider enforcement of Schema.
|
||||||
|
Strict bool `json:"strict"`
|
||||||
|
// Schema is a caller-owned copy of the loaded JSON Schema document.
|
||||||
|
Schema any `json:"schema"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// LLMClient executes rendered prompts for Engine.Run.
|
// LLMClient executes rendered prompts for [Engine.Run].
|
||||||
|
//
|
||||||
|
// Generate may be called concurrently. It must honor context cancellation to
|
||||||
|
// make Run responsive to cancellation. The request and all nested maps,
|
||||||
|
// slices, and pointers are client-owned copies and may be mutated or retained
|
||||||
|
// without affecting engine state.
|
||||||
|
//
|
||||||
|
// A returned error makes Run return ErrLLMGenerate while preserving the client
|
||||||
|
// error through errors.Is. A nil response with a nil error also produces
|
||||||
|
// ErrLLMGenerate. Promptkit copies the non-nil response before returning from
|
||||||
|
// Run.
|
||||||
type LLMClient interface {
|
type LLMClient interface {
|
||||||
Generate(context.Context, GenerateRequest) (*GenerateResponse, error)
|
Generate(context.Context, GenerateRequest) (*GenerateResponse, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GenerateRequest is passed to an injected LLM client.
|
// GenerateRequest is passed to an injected LLM client and has a stable JSON
|
||||||
|
// representation. Its String and GoString methods omit rendered content and
|
||||||
|
// direct credentials.
|
||||||
type GenerateRequest struct {
|
type GenerateRequest struct {
|
||||||
Prompt RenderedPrompt `json:"prompt"`
|
// Prompt contains the rendered session ID and messages.
|
||||||
Target ExecutionTarget `json:"target"`
|
Prompt RenderedPrompt `json:"prompt"`
|
||||||
TargetPresence ExecutionTargetPresence `json:"target_presence"`
|
// Target contains effective model settings without the direct API key.
|
||||||
StructuredOutput *StructuredOutputSpec `json:"structured_output,omitempty"`
|
Target ExecutionTarget `json:"target"`
|
||||||
APIKey string `json:"-"`
|
// TargetPresence distinguishes inherited numeric zeros from explicit
|
||||||
|
// request overrides.
|
||||||
|
TargetPresence ExecutionTargetPresence `json:"target_presence"`
|
||||||
|
// StructuredOutput contains provider response constraints when requested.
|
||||||
|
StructuredOutput *StructuredOutputSpec `json:"structured_output,omitempty"`
|
||||||
|
// APIKey is the direct request-scoped credential, if any. It is excluded
|
||||||
|
// from JSON, String, and GoString output.
|
||||||
|
APIKey string `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// GenerateResponse is returned by an injected LLM client.
|
// GenerateResponse is returned by an injected LLM client and has a stable JSON
|
||||||
|
// representation.
|
||||||
type GenerateResponse struct {
|
type GenerateResponse struct {
|
||||||
Content string `json:"content"`
|
// Content is the generated output. It must be non-empty when using the
|
||||||
Usage TokenUsage `json:"usage"`
|
// built-in client; injected clients may return empty content for Promptkit
|
||||||
|
// validation to classify.
|
||||||
|
Content string `json:"content"`
|
||||||
|
// Usage is the client's token accounting.
|
||||||
|
Usage TokenUsage `json:"usage"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// File returns a file-backed artifact reference.
|
// File returns a file-backed artifact reference whose URI is path.
|
||||||
func File(path string) ArtifactRef {
|
func File(path string) ArtifactRef {
|
||||||
return ArtifactRef{Type: ArtifactRefFile, URI: path}
|
return ArtifactRef{Type: ArtifactRefFile, URI: path}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inline returns an inline artifact reference.
|
// Inline returns an inline artifact reference whose Body is body and whose URI
|
||||||
|
// is empty.
|
||||||
func Inline(body string) ArtifactRef {
|
func Inline(body string) ArtifactRef {
|
||||||
return ArtifactRef{Type: ArtifactRefInline, Body: body}
|
return ArtifactRef{Type: ArtifactRefInline, Body: body}
|
||||||
}
|
}
|
||||||
|
|
||||||
// InlineWithURI returns an inline artifact reference with URI metadata.
|
// InlineWithURI returns an inline artifact reference with body content and uri
|
||||||
|
// provenance metadata.
|
||||||
func InlineWithURI(uri string, body string) ArtifactRef {
|
func InlineWithURI(uri string, body string) ArtifactRef {
|
||||||
return ArtifactRef{Type: ArtifactRefInline, URI: uri, Body: body}
|
return ArtifactRef{Type: ArtifactRefInline, URI: uri, Body: body}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user