Return generation attempt results as one value
This commit is contained in:
@@ -672,6 +672,11 @@ tests pass on Go 1.27.3; the internal source description is updated.
|
||||
response/error behavior, timing facts and cancellation; no new event or HTTP fact
|
||||
is fabricated for an injected client.
|
||||
|
||||
Completion: built-in attempts return a private result containing outcome,
|
||||
dispatch, capacity, duration, and start-time facts. Generation, use-case, and
|
||||
engine tests pass on Go 1.27.3; permit lifetime and injected dispatch are
|
||||
unchanged.
|
||||
|
||||
## Stage 26: Share Generation Accounting Projections
|
||||
|
||||
**Catalog:** 25, completion. **Files:** generation accounting/evidence/observer tests.
|
||||
|
||||
@@ -126,66 +126,66 @@ func (c *Coordinator) generate(
|
||||
return finish(nil, err)
|
||||
}
|
||||
ordinal := attempts + 1
|
||||
outcome, dispatched, capacityWait, generationDuration, startedAt := c.execute(ctx, req.Target.BackendID, prepared, captureEvidence)
|
||||
if dispatched {
|
||||
result := c.execute(ctx, req.Target.BackendID, prepared, captureEvidence)
|
||||
if result.Dispatched {
|
||||
attempts++
|
||||
}
|
||||
if captureEvidence {
|
||||
attempt := AttemptEvidence{
|
||||
StartedAt: startedAt.UTC(),
|
||||
Dispatched: dispatched,
|
||||
ResponseReceived: outcome.Evidence.ResponseReceived,
|
||||
HTTP: cloneHTTPEvidence(outcome.Evidence),
|
||||
CapacityWait: capacityWait,
|
||||
RequestDuration: generationDuration,
|
||||
Failure: ClassifyFailure(outcome.Err),
|
||||
ResponseDecoded: outcome.ResponseDecoded,
|
||||
GenerationCompleted: outcome.GenerationCompleted,
|
||||
StartedAt: result.StartedAt.UTC(),
|
||||
Dispatched: result.Dispatched,
|
||||
ResponseReceived: result.Outcome.Evidence.ResponseReceived,
|
||||
HTTP: cloneHTTPEvidence(result.Outcome.Evidence),
|
||||
CapacityWait: result.CapacityWait,
|
||||
RequestDuration: result.RequestDuration,
|
||||
Failure: ClassifyFailure(result.Outcome.Err),
|
||||
ResponseDecoded: result.Outcome.ResponseDecoded,
|
||||
GenerationCompleted: result.Outcome.GenerationCompleted,
|
||||
}
|
||||
if outcome.StructuredOutputRequested != nil {
|
||||
requested := *outcome.StructuredOutputRequested
|
||||
if result.Outcome.StructuredOutputRequested != nil {
|
||||
requested := *result.Outcome.StructuredOutputRequested
|
||||
attempt.StructuredOutputRequested = &requested
|
||||
}
|
||||
if dispatched {
|
||||
usage.Add(outcome.Usage, outcome.UsagePresence)
|
||||
if result.Dispatched {
|
||||
usage.Add(result.Outcome.Usage, result.Outcome.UsagePresence)
|
||||
var attemptUsage observation.UsageAccumulator
|
||||
attemptUsage.Add(outcome.Usage, outcome.UsagePresence)
|
||||
attemptUsage.Add(result.Outcome.Usage, result.Outcome.UsagePresence)
|
||||
attempt.Usage = attemptUsage.Observed()
|
||||
}
|
||||
evidence.Attempts = append(evidence.Attempts, attempt)
|
||||
}
|
||||
if recorder != nil {
|
||||
recorder.Attempt(observation.AttemptData{Generation: generation, Attempt: ordinal,
|
||||
Dispatched: dispatched, CapacityWait: capacityWait, GenerationDuration: generationDuration,
|
||||
Outcome: attemptOutcome(outcome.Err), Failure: ClassifyFailure(outcome.Err),
|
||||
StatusCode: outcome.StatusCode, Usage: outcome.Usage, UsagePresence: outcome.UsagePresence})
|
||||
Dispatched: result.Dispatched, CapacityWait: result.CapacityWait, GenerationDuration: result.RequestDuration,
|
||||
Outcome: attemptOutcome(result.Outcome.Err), Failure: ClassifyFailure(result.Outcome.Err),
|
||||
StatusCode: result.Outcome.StatusCode, Usage: result.Outcome.Usage, UsagePresence: result.Outcome.UsagePresence})
|
||||
}
|
||||
if outcome.Err == nil {
|
||||
if result.Outcome.Err == nil {
|
||||
if err := ctx.Err(); err != nil {
|
||||
if captureEvidence {
|
||||
return finish(outcome.Response, err)
|
||||
return finish(result.Outcome.Response, err)
|
||||
}
|
||||
return finish(nil, err)
|
||||
}
|
||||
return finish(outcome.Response, nil)
|
||||
return finish(result.Outcome.Response, nil)
|
||||
}
|
||||
if !dispatched || !eligibleStatus(outcome) {
|
||||
if !result.Dispatched || !eligibleStatus(result.Outcome) {
|
||||
if captureEvidence {
|
||||
return finish(outcome.Response, outcome.Err)
|
||||
return finish(result.Outcome.Response, result.Outcome.Err)
|
||||
}
|
||||
return finish(nil, outcome.Err)
|
||||
return finish(nil, result.Outcome.Err)
|
||||
}
|
||||
if retriesUsed == req.TransientRetries {
|
||||
if retriesUsed == 0 {
|
||||
return finish(nil, outcome.Err)
|
||||
return finish(nil, result.Outcome.Err)
|
||||
}
|
||||
return finish(nil, &ExhaustedError{attempts: attempts, cause: outcome.Err})
|
||||
return finish(nil, &ExhaustedError{attempts: attempts, cause: result.Outcome.Err})
|
||||
}
|
||||
if err := ctx.Err(); err != nil {
|
||||
return finish(nil, err)
|
||||
}
|
||||
retryOrdinal := retriesUsed + 1
|
||||
delay := retryDelay(c.backoff(retryOrdinal), outcome.RetryNotBefore, c.now())
|
||||
delay := retryDelay(c.backoff(retryOrdinal), result.Outcome.RetryNotBefore, c.now())
|
||||
waitStart := c.now()
|
||||
waitErr := c.wait(ctx, delay)
|
||||
waitDuration := elapsed(waitStart, c.now())
|
||||
@@ -306,27 +306,37 @@ func (c *Coordinator) generateInjected(
|
||||
return finish(response, nil)
|
||||
}
|
||||
|
||||
func (c *Coordinator) execute(ctx context.Context, backendID string, prepared *llm.PreparedGeneration, captureEvidence bool) (outcome llm.AttemptOutcome, dispatched bool, capacityWait, generationDuration time.Duration, startedAt time.Time) {
|
||||
start := c.now()
|
||||
startedAt = start
|
||||
type attemptResult struct {
|
||||
Outcome llm.AttemptOutcome
|
||||
Dispatched bool
|
||||
CapacityWait time.Duration
|
||||
RequestDuration time.Duration
|
||||
StartedAt time.Time
|
||||
}
|
||||
|
||||
func (c *Coordinator) execute(ctx context.Context, backendID string, prepared *llm.PreparedGeneration, captureEvidence bool) attemptResult {
|
||||
result := attemptResult{StartedAt: c.now()}
|
||||
release, err := c.manager.Acquire(ctx, backendID)
|
||||
capacityWait = c.capacityWait(backendID, start)
|
||||
result.CapacityWait = c.capacityWait(backendID, result.StartedAt)
|
||||
if err != nil {
|
||||
return llm.AttemptOutcome{Err: err}, false, capacityWait, 0, startedAt
|
||||
result.Outcome.Err = err
|
||||
return result
|
||||
}
|
||||
defer release()
|
||||
if err := ctx.Err(); err != nil {
|
||||
return llm.AttemptOutcome{Err: err}, false, capacityWait, 0, startedAt
|
||||
result.Outcome.Err = err
|
||||
return result
|
||||
}
|
||||
dispatchStart := c.now()
|
||||
if captureEvidence {
|
||||
outcome = prepared.ExecuteWithEvidence(ctx)
|
||||
dispatched = outcome.Evidence.DispatchInvoked
|
||||
result.Outcome = prepared.ExecuteWithEvidence(ctx)
|
||||
result.Dispatched = result.Outcome.Evidence.DispatchInvoked
|
||||
} else {
|
||||
outcome = prepared.Execute(ctx)
|
||||
dispatched = true
|
||||
result.Outcome = prepared.Execute(ctx)
|
||||
result.Dispatched = true
|
||||
}
|
||||
return outcome, dispatched, capacityWait, elapsed(dispatchStart, c.now()), startedAt
|
||||
result.RequestDuration = elapsed(dispatchStart, c.now())
|
||||
return result
|
||||
}
|
||||
|
||||
func (c *Coordinator) capacityWait(backendID string, start time.Time) time.Duration {
|
||||
|
||||
Reference in New Issue
Block a user