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
|
response/error behavior, timing facts and cancellation; no new event or HTTP fact
|
||||||
is fabricated for an injected client.
|
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
|
## Stage 26: Share Generation Accounting Projections
|
||||||
|
|
||||||
**Catalog:** 25, completion. **Files:** generation accounting/evidence/observer tests.
|
**Catalog:** 25, completion. **Files:** generation accounting/evidence/observer tests.
|
||||||
|
|||||||
@@ -126,66 +126,66 @@ func (c *Coordinator) generate(
|
|||||||
return finish(nil, err)
|
return finish(nil, err)
|
||||||
}
|
}
|
||||||
ordinal := attempts + 1
|
ordinal := attempts + 1
|
||||||
outcome, dispatched, capacityWait, generationDuration, startedAt := c.execute(ctx, req.Target.BackendID, prepared, captureEvidence)
|
result := c.execute(ctx, req.Target.BackendID, prepared, captureEvidence)
|
||||||
if dispatched {
|
if result.Dispatched {
|
||||||
attempts++
|
attempts++
|
||||||
}
|
}
|
||||||
if captureEvidence {
|
if captureEvidence {
|
||||||
attempt := AttemptEvidence{
|
attempt := AttemptEvidence{
|
||||||
StartedAt: startedAt.UTC(),
|
StartedAt: result.StartedAt.UTC(),
|
||||||
Dispatched: dispatched,
|
Dispatched: result.Dispatched,
|
||||||
ResponseReceived: outcome.Evidence.ResponseReceived,
|
ResponseReceived: result.Outcome.Evidence.ResponseReceived,
|
||||||
HTTP: cloneHTTPEvidence(outcome.Evidence),
|
HTTP: cloneHTTPEvidence(result.Outcome.Evidence),
|
||||||
CapacityWait: capacityWait,
|
CapacityWait: result.CapacityWait,
|
||||||
RequestDuration: generationDuration,
|
RequestDuration: result.RequestDuration,
|
||||||
Failure: ClassifyFailure(outcome.Err),
|
Failure: ClassifyFailure(result.Outcome.Err),
|
||||||
ResponseDecoded: outcome.ResponseDecoded,
|
ResponseDecoded: result.Outcome.ResponseDecoded,
|
||||||
GenerationCompleted: outcome.GenerationCompleted,
|
GenerationCompleted: result.Outcome.GenerationCompleted,
|
||||||
}
|
}
|
||||||
if outcome.StructuredOutputRequested != nil {
|
if result.Outcome.StructuredOutputRequested != nil {
|
||||||
requested := *outcome.StructuredOutputRequested
|
requested := *result.Outcome.StructuredOutputRequested
|
||||||
attempt.StructuredOutputRequested = &requested
|
attempt.StructuredOutputRequested = &requested
|
||||||
}
|
}
|
||||||
if dispatched {
|
if result.Dispatched {
|
||||||
usage.Add(outcome.Usage, outcome.UsagePresence)
|
usage.Add(result.Outcome.Usage, result.Outcome.UsagePresence)
|
||||||
var attemptUsage observation.UsageAccumulator
|
var attemptUsage observation.UsageAccumulator
|
||||||
attemptUsage.Add(outcome.Usage, outcome.UsagePresence)
|
attemptUsage.Add(result.Outcome.Usage, result.Outcome.UsagePresence)
|
||||||
attempt.Usage = attemptUsage.Observed()
|
attempt.Usage = attemptUsage.Observed()
|
||||||
}
|
}
|
||||||
evidence.Attempts = append(evidence.Attempts, attempt)
|
evidence.Attempts = append(evidence.Attempts, attempt)
|
||||||
}
|
}
|
||||||
if recorder != nil {
|
if recorder != nil {
|
||||||
recorder.Attempt(observation.AttemptData{Generation: generation, Attempt: ordinal,
|
recorder.Attempt(observation.AttemptData{Generation: generation, Attempt: ordinal,
|
||||||
Dispatched: dispatched, CapacityWait: capacityWait, GenerationDuration: generationDuration,
|
Dispatched: result.Dispatched, CapacityWait: result.CapacityWait, GenerationDuration: result.RequestDuration,
|
||||||
Outcome: attemptOutcome(outcome.Err), Failure: ClassifyFailure(outcome.Err),
|
Outcome: attemptOutcome(result.Outcome.Err), Failure: ClassifyFailure(result.Outcome.Err),
|
||||||
StatusCode: outcome.StatusCode, Usage: outcome.Usage, UsagePresence: outcome.UsagePresence})
|
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 err := ctx.Err(); err != nil {
|
||||||
if captureEvidence {
|
if captureEvidence {
|
||||||
return finish(outcome.Response, err)
|
return finish(result.Outcome.Response, err)
|
||||||
}
|
}
|
||||||
return finish(nil, 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 {
|
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 == req.TransientRetries {
|
||||||
if retriesUsed == 0 {
|
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 {
|
if err := ctx.Err(); err != nil {
|
||||||
return finish(nil, err)
|
return finish(nil, err)
|
||||||
}
|
}
|
||||||
retryOrdinal := retriesUsed + 1
|
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()
|
waitStart := c.now()
|
||||||
waitErr := c.wait(ctx, delay)
|
waitErr := c.wait(ctx, delay)
|
||||||
waitDuration := elapsed(waitStart, c.now())
|
waitDuration := elapsed(waitStart, c.now())
|
||||||
@@ -306,27 +306,37 @@ func (c *Coordinator) generateInjected(
|
|||||||
return finish(response, nil)
|
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) {
|
type attemptResult struct {
|
||||||
start := c.now()
|
Outcome llm.AttemptOutcome
|
||||||
startedAt = start
|
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)
|
release, err := c.manager.Acquire(ctx, backendID)
|
||||||
capacityWait = c.capacityWait(backendID, start)
|
result.CapacityWait = c.capacityWait(backendID, result.StartedAt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return llm.AttemptOutcome{Err: err}, false, capacityWait, 0, startedAt
|
result.Outcome.Err = err
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
defer release()
|
defer release()
|
||||||
if err := ctx.Err(); err != nil {
|
if err := ctx.Err(); err != nil {
|
||||||
return llm.AttemptOutcome{Err: err}, false, capacityWait, 0, startedAt
|
result.Outcome.Err = err
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
dispatchStart := c.now()
|
dispatchStart := c.now()
|
||||||
if captureEvidence {
|
if captureEvidence {
|
||||||
outcome = prepared.ExecuteWithEvidence(ctx)
|
result.Outcome = prepared.ExecuteWithEvidence(ctx)
|
||||||
dispatched = outcome.Evidence.DispatchInvoked
|
result.Dispatched = result.Outcome.Evidence.DispatchInvoked
|
||||||
} else {
|
} else {
|
||||||
outcome = prepared.Execute(ctx)
|
result.Outcome = prepared.Execute(ctx)
|
||||||
dispatched = true
|
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 {
|
func (c *Coordinator) capacityWait(backendID string, start time.Time) time.Duration {
|
||||||
|
|||||||
Reference in New Issue
Block a user