Document conversation capture and continuation contracts

This commit is contained in:
2026-11-14 14:26:39 +00:00
parent 5aae5df5fb
commit c23393b2cc
5 changed files with 31 additions and 2 deletions

View File

@@ -697,6 +697,10 @@ its opaque rendered-prompt hash before invoking `RunPrepared`.
### Capture And Continue A Conversation ### Capture And Continue A Conversation
The [request GoDoc](../../types.go), [exchange GoDoc](../../exchange.go), and
[prepared-execution GoDoc](../../prepared_execution.go) own the exact capture,
continuation, inspection, and lifetime contracts.
Capture records the messages actually executed and the final assistant content. Capture records the messages actually executed and the final assistant content.
An exchange is an immutable in-process capability; `Details()` returns detached, An exchange is an immutable in-process capability; `Details()` returns detached,
encodable history that may contain sensitive content. Ordinary result encoding encodable history that may contain sensitive content. Ordinary result encoding

View File

@@ -43,7 +43,11 @@ group members on each incremental update.
## 1. Complete The Public Exchange Capture And Continuation Contract ## 1. Complete The Public Exchange Capture And Continuation Contract
**Priority:** P2. **Status:** Open. **Plan stage:** 13. **Priority:** P2. **Status:** Complete. **Plan stage:** 13.
**Completion:** Expanded the public request, exchange, details, and prepared-handle
GoDoc and linked the consumer walkthrough to those owners. Checked comments
against capture, preparation, and repair behavior; local links and diff verified.
**Locations:** [request fields](../../types.go), **Locations:** [request fields](../../types.go),
[exchange declarations and accessor](../../exchange.go), and [exchange declarations and accessor](../../exchange.go), and

View File

@@ -7,17 +7,28 @@ const exchangeString = "promptkit.Exchange{opaque}"
// Exchange is an immutable, reusable in-process snapshot of a completed // Exchange is an immutable, reusable in-process snapshot of a completed
// conversation. It is not a persistence or restart format. Different engines // conversation. It is not a persistence or restart format. Different engines
// can continue it, and independent branches do not alter one another. // can continue it, and independent branches do not alter one another.
//
// History preserves the effective request's message content, roles, and cache
// metadata, followed by the exact final [RunResult.RawOutput] as an assistant
// message. Intermediate structural-repair candidates and corrective instructions
// are excluded. A continuation extends that logical history according to
// [RunRequest.ContinueFrom], without changing its source exchange.
type Exchange struct{ internal *domain.Exchange } type Exchange struct{ internal *domain.Exchange }
// ExchangeDetails contains a detached copy of an exchange's logical history. // ExchangeDetails contains a detached copy of an exchange's logical history.
type ExchangeDetails struct { type ExchangeDetails struct {
RunID string `json:"run_id"` // RunID identifies the execution that produced this exchange.
RunID string `json:"run_id"`
// ParentRunID identifies the immediate source execution, or is empty.
ParentRunID string `json:"parent_run_id,omitempty"` ParentRunID string `json:"parent_run_id,omitempty"`
Messages []RenderedMessage `json:"messages"` Messages []RenderedMessage `json:"messages"`
} }
// Details returns detached history, or zero details for a nil or empty handle. // Details returns detached history, or zero details for a nil or empty handle.
// Messages include caller and model content and require appropriate handling. // Messages include caller and model content and require appropriate handling.
// Inspection uses only retained state, without rendering, filesystem reads, or
// provider calls. Mutating returned messages or cache metadata cannot affect
// this exchange, another branch, or subsequent Details calls.
func (e *Exchange) Details() ExchangeDetails { func (e *Exchange) Details() ExchangeDetails {
if e == nil || e.internal == nil { if e == nil || e.internal == nil {
return ExchangeDetails{} return ExchangeDetails{}

View File

@@ -15,6 +15,9 @@ const preparedExecutionString = "promptkit.PreparedExecution{opaque}"
// A successful PrepareExecution may retain an Observer function in this // A successful PrepareExecution may retain an Observer function in this
// handle's private payload. The callback and other private execution settings // handle's private payload. The callback and other private execution settings
// are cleared on claim completion or Discard. Details never exposes them. // are cleared on claim completion or Discard. Details never exposes them.
// It also retains RunRequest.CaptureExchange and RunRequest.ContinueFrom for
// execution of the frozen snapshot. Only RunPrepared can produce its completed
// [Exchange]; preparation alone does not.
type PreparedExecution struct { type PreparedExecution struct {
internal *usecase.PreparedExecution internal *usecase.PreparedExecution
} }

View File

@@ -87,10 +87,17 @@ const (
type RunRequest struct { type RunRequest struct {
// CaptureExchange requests an immutable snapshot of a completed run, even // CaptureExchange requests an immutable snapshot of a completed run, even
// when its structural validation fails. Operational errors return no result. // when its structural validation fails. Operational errors return no result.
// The snapshot is returned in RunResult.Exchange; see [Exchange] for its
// logical history contract. Prepare and ValidateRequest create no exchange.
// PrepareExecution retains this choice for its eventual RunPrepared call.
CaptureExchange bool CaptureExchange bool
// ContinueFrom supplies captured history and implies capture of the new run. // ContinueFrom supplies captured history and implies capture of the new run.
// A non-nil zero-value exchange is invalid. Follow-up settings are selected // A non-nil zero-value exchange is invalid. Follow-up settings are selected
// normally and are not inherited from the exchange. // normally and are not inherited from the exchange.
// Messages are assembled as captured history, rendered definition messages,
// then AppendedMessages. Prior templates and inputs are not rendered or read
// again. Continuation adds no history-size limit or truncation; upstream
// rejection follows the ordinary generation-error contract.
ContinueFrom *Exchange `json:"-" yaml:"-"` ContinueFrom *Exchange `json:"-" yaml:"-"`
// PromptID is the required prompt identifier. A namespace-scoped engine view // PromptID is the required prompt identifier. A namespace-scoped engine view
// qualifies a slashless caller value; otherwise it selects the exact // qualifies a slashless caller value; otherwise it selects the exact