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

@@ -581,6 +581,59 @@ retained callback without invoking it. The function's closure is retained by
identity, so synchronize any shared state it uses. Prepared start events can
include identities already resolved in the frozen snapshot.
## Bound Execution And Retain Prepared Details
Select the optional controls on [RunRequest](../../types.go). The operation
budget is separate from the provider timeout and cancellation is cooperative.
Notification is conditional on reaching the prepared point, synchronous, and
runs while admission is held; its caller-owned details can be retained even if
generation later fails. Do not rely on notification for preparation or admission
failures. The application owns any subsequent diagnostic handling.
```go
var details *promptkit.PreparedRun
result, err := engine.Run(ctx, promptkit.RunRequest{
PromptID: "answer", OperationTimeout: 30 * time.Second,
OnPrepared: func(_ context.Context, prepared promptkit.PreparedRun) { details = &prepared },
})
if errors.Is(err, promptkit.ErrOperationTimeout) && errors.Is(err, context.DeadlineExceeded) {
// details is available only if the notification was reached.
}
```
For coordinated turns, put the controls on each returned request. Assessment
in the next-turn callback runs after the previous admission and child scope
are released, so it can select its own budget:
```go
next := func(ctx context.Context, turn promptkit.ConversationTurn) (*promptkit.RunRequest, error) {
if turn.Result != nil {
_, err := engine.Run(ctx, promptkit.RunRequest{PromptID: "assessment", OperationTimeout: 10 * time.Second})
return nil, err
}
return &promptkit.RunRequest{PromptID: "answer", OperationTimeout: 30 * time.Second,
OnPrepared: func(_ context.Context, prepared promptkit.PreparedRun) { details = &prepared }}, nil
}
```
For split execution, [PrepareExecution](../../engine.go) retains the controls
without starting their timer; idle time does not count. Use the same caller
deadline for both calls if preparation and execution need one shared bound.
```go
handle, err := engine.PrepareExecution(ctx, promptkit.RunRequest{
PromptID: "answer", OperationTimeout: 30 * time.Second,
OnPrepared: func(_ context.Context, prepared promptkit.PreparedRun) { details = &prepared },
})
if err != nil { return err }
defer handle.Discard()
result, err := engine.RunPrepared(ctx, handle)
```
See the [observation example](../../examples/go-library/observe/main.go) for an
offline coordinated workflow and [ErrOperationTimeout](../../engine.go) for
timeout attribution.
## Execute And Validate
[`Engine.Run`](../../engine.go) performs the same preparation, invokes the