Document and demonstrate execution controls

This commit is contained in:
2026-11-14 17:47:55 +00:00
parent 3de3e60c0c
commit 8831ae35f7
11 changed files with 131 additions and 16 deletions

View File

@@ -63,6 +63,9 @@ var (
// ErrOperationTimeout identifies expiration of the timeout selected by
// RunRequest.OperationTimeout. Such errors also match context.DeadlineExceeded
// and retain their underlying operation and collaborator identities.
// Earlier parent cancellation or deadlines and provider-only deadlines do
// not acquire this identity. A completed result remains completed even if
// a terminal observer outlasts the selected budget.
ErrOperationTimeout = errors.New("operation timeout exceeded")
// ErrLLMGenerate identifies a model-client failure or a nil successful
// response. A built-in OpenAI-compatible non-2xx response is available as a
@@ -390,6 +393,7 @@ func (e *Engine) InspectBackend(ctx context.Context, backendID string) (*Backend
// reported in the applicable operation category; no general errors.Is
// relationship to ctx.Err is promised. Prepare returns no partial result on
// error. It validates RunRequest.TransientRetries but makes no model attempts.
// RunRequest.OperationTimeout and RunRequest.OnPrepared have no effect here.
func (e *Engine) Prepare(ctx context.Context, req RunRequest) (*PreparedRun, error) {
prepared, err := e.prepareRequest(ctx, req)
if err != nil {
@@ -411,6 +415,7 @@ func (e *Engine) Prepare(ctx context.Context, req RunRequest) (*PreparedRun, err
// matching ErrInvalidConfig when the Engine is nil. Success does not guarantee
// provider acceptance or later execution success. Use [Engine.PrepareExecution]
// when execution must use the snapshot produced by preparation.
// Execution-only controls do not start a timer or invoke a notification here.
func (e *Engine) ValidateRequest(ctx context.Context, req RunRequest) error {
_, err := e.prepareRequest(ctx, req)
return err
@@ -453,6 +458,8 @@ func (e *Engine) prepareRequest(ctx context.Context, req RunRequest) (*domain.Pr
// ErrInvalidConfig. The effective transient retry budget is frozen privately
// for RunPrepared and is absent from Details. A supplied Observer is retained
// privately for RunPrepared; preparation itself emits no events.
// RunRequest.OperationTimeout and RunRequest.OnPrepared are retained without
// starting a timer or invoking the notification during preparation.
func (e *Engine) PrepareExecution(ctx context.Context, req RunRequest) (*PreparedExecution, error) {
ctx = observation.WithoutExecutionState(ctx)
if e == nil || e.internal == nil {
@@ -483,6 +490,9 @@ func (e *Engine) PrepareExecution(ctx context.Context, req RunRequest) (*Prepare
// returns the final failed validation result with cumulative usage and actual
// repair attempts. An inability to generate or validate returns an error and
// no partial result.
// RunRequest.OperationTimeout selects a cooperative whole-operation deadline;
// RunRequest.OnPrepared selects conditional notification before generation.
// The outcome and timeout attribution are fixed before terminal observation.
//
// The built-in client retries eligible provider statuses using the effective
// Config or request budget. With R additional transient attempts and P repair
@@ -600,6 +610,9 @@ func (e *Engine) run(ctx context.Context, req RunRequest) (*RunResult, error) {
// mapping. Invalid, foreign, discarded, or reused handles emit no events.
// Callbacks run outside the handle and capacity locks; panics propagate and
// do not promise a terminal event.
// The retained RunRequest.OperationTimeout starts after claim; the retained
// RunRequest.OnPrepared is notified only if execution reaches its prepared
// point. Final timeout attribution precedes terminal observation.
func (e *Engine) RunPrepared(ctx context.Context, prepared *PreparedExecution) (*RunResult, error) {
ctx = observation.WithoutExecutionState(ctx)
if e == nil || e.internal == nil {