Expose prepared execution handles
This commit is contained in:
86
engine.go
86
engine.go
@@ -63,9 +63,10 @@ var (
|
||||
// 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")
|
||||
// ErrCapacityExceeded identifies a Run rejected because the selected backend
|
||||
// already admitted ConcurrencyLimit + QueueCapacity calls. It is not an
|
||||
// invalid request, an LLM or provider rate-limit response, or ErrLLMGenerate.
|
||||
// ErrCapacityExceeded identifies a Run or RunPrepared rejected because the
|
||||
// selected backend already admitted ConcurrencyLimit + QueueCapacity calls.
|
||||
// It is not an invalid request, an LLM or provider rate-limit response, or
|
||||
// ErrLLMGenerate.
|
||||
ErrCapacityExceeded = errors.New("backend capacity exceeded")
|
||||
// ErrLLMGenerate identifies a model-client failure or a nil successful
|
||||
// response. Errors returned by an injected LLMClient remain available
|
||||
@@ -79,10 +80,12 @@ var (
|
||||
|
||||
// Engine prepares and runs Promptkit prompt requests.
|
||||
//
|
||||
// An Engine is safe for concurrent calls to [Engine.Prepare] and [Engine.Run].
|
||||
// Each Engine owns independent backend-capacity pools that coordinate Run
|
||||
// admission and model generation. Injected collaborators may still be invoked
|
||||
// concurrently across different backend pools or for unlimited backends.
|
||||
// An Engine is safe for concurrent calls to [Engine.Prepare],
|
||||
// [Engine.PrepareExecution], [Engine.Run], and [Engine.RunPrepared]. Each
|
||||
// Engine owns independent backend-capacity pools that coordinate Run and
|
||||
// RunPrepared admission and model generation. Injected collaborators may still
|
||||
// be invoked concurrently across different backend pools or for unlimited
|
||||
// backends.
|
||||
type Engine struct {
|
||||
runner *usecase.Runner
|
||||
}
|
||||
@@ -457,6 +460,38 @@ func (e *Engine) Prepare(ctx context.Context, req RunRequest) (*PreparedRun, err
|
||||
return fromDomainPreparedRun(prepared), nil
|
||||
}
|
||||
|
||||
// PrepareExecution completely prepares a prompt request without calling the
|
||||
// configured LLMClient or reserving backend admission capacity.
|
||||
//
|
||||
// The returned opaque handle is bound to this Engine and permits one
|
||||
// [Engine.RunPrepared] invocation. Preparation freezes the selected sources,
|
||||
// rendered messages, effective settings, inputs, provider structured-output
|
||||
// metadata, and validation resources needed by that invocation. The handle
|
||||
// retains a direct RunRequest.APIKey only in private execution state;
|
||||
// [PreparedExecution.Details] is credential-redacted.
|
||||
//
|
||||
// The context governs preparation only. Cancellation after this method
|
||||
// returns does not invalidate the handle or propagate to RunPrepared.
|
||||
// PrepareExecution returns the same error categories as [Engine.Prepare] and
|
||||
// returns no handle on error. A nil Engine returns an error matching
|
||||
// ErrInvalidConfig.
|
||||
func (e *Engine) PrepareExecution(ctx context.Context, req RunRequest) (*PreparedExecution, error) {
|
||||
if e == nil || e.runner == nil {
|
||||
return nil, fmt.Errorf("%w: engine is nil", ErrInvalidConfig)
|
||||
}
|
||||
|
||||
domainReq, err := toDomainRunRequest(req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%w: %v", ErrInvalidRequest, err)
|
||||
}
|
||||
|
||||
prepared, err := e.runner.PrepareExecution(ctx, domainReq)
|
||||
if err != nil {
|
||||
return nil, mapPublicError(err)
|
||||
}
|
||||
return &PreparedExecution{internal: prepared}, nil
|
||||
}
|
||||
|
||||
// Run prepares a request, invokes the configured LLMClient, and validates the
|
||||
// generated output.
|
||||
//
|
||||
@@ -491,3 +526,40 @@ func (e *Engine) Run(ctx context.Context, req RunRequest) (*RunResult, error) {
|
||||
}
|
||||
return fromDomainRunResult(result), nil
|
||||
}
|
||||
|
||||
// RunPrepared atomically claims and executes a handle created by
|
||||
// [Engine.PrepareExecution].
|
||||
//
|
||||
// A valid owning-Engine invocation consumes the handle's one attempt before
|
||||
// credential revalidation, backend admission, generation, or validation.
|
||||
// Cancellation, capacity rejection, generation failure, operational
|
||||
// validation failure, and success all leave the handle unusable. A nil,
|
||||
// zero-value, foreign-Engine, discarded, claimed, or used handle returns an
|
||||
// error matching ErrInvalidRequest; a nil Engine returns ErrInvalidConfig and
|
||||
// does not claim the handle.
|
||||
//
|
||||
// The supplied context governs this execution attempt independently of the
|
||||
// preparation context. It covers credential revalidation, admission,
|
||||
// generation, validation, and any internal repair. Result timing begins after
|
||||
// the claim and excludes preparation and consumer-held delay.
|
||||
//
|
||||
// RunPrepared can return ErrInvalidRequest, ErrAPIKeyEnvMissing,
|
||||
// ErrCapacityExceeded, ErrLLMGenerate, or ErrValidation as applicable while
|
||||
// preserving documented collaborator and context identities. A completed
|
||||
// content-validation rejection is returned in RunResult, not as an
|
||||
// operational error. An operational error returns no partial RunResult.
|
||||
func (e *Engine) RunPrepared(ctx context.Context, prepared *PreparedExecution) (*RunResult, error) {
|
||||
if e == nil || e.runner == nil {
|
||||
return nil, fmt.Errorf("%w: engine is nil", ErrInvalidConfig)
|
||||
}
|
||||
|
||||
var internal *usecase.PreparedExecution
|
||||
if prepared != nil {
|
||||
internal = prepared.internal
|
||||
}
|
||||
result, err := e.runner.RunPrepared(ctx, internal)
|
||||
if err != nil {
|
||||
return nil, mapPublicError(err)
|
||||
}
|
||||
return fromDomainRunResult(result), nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user