feat(tenant): bill AI points by output characters
Previously AI point cost was computed from request (input) characters at reservation time. Switch to reserving a single point up front and settling the final cost from the generated output length on completion. - Reserve 1 point (or FixedPoints) instead of pricing on request chars - On completion, recompute points from output chars vs base chars, update the reservation amounts, and post a ledger delta for the top-up/refund; invalidate the workspace quota summary cache - MarkCompleted now persists final request_chars/base_chars/points - Use ceil division in calculateAIPointCost so an exact base boundary charges one point instead of rolling over - Thread output text through all CompleteAIPoints callers (article selection, KOL assist, question expansion, template assist, compliance judge) and return the settled reservation - Add unit tests plus an integration test gated on TEST_DATABASE_URL - Update the user manual: billing is by output characters Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -317,7 +317,8 @@ func (s *QuestionExpansionService) GenerateByAIDistill(ctx context.Context, bran
|
||||
candidates = append(candidates, buildCandidate(text, QuestionSourceAIDistill, false, existing, brandCtx))
|
||||
}
|
||||
|
||||
if err := CompleteAIPoints(context.Background(), s.pool, actor.TenantID, *reservation, result.Model); err != nil {
|
||||
completed, err := CompleteAIPoints(context.Background(), s.pool, s.cache, actor.TenantID, *reservation, result.Model, result.Content)
|
||||
if err != nil {
|
||||
return nil, response.ErrInternal(50127, "ai_points_commit_failed", "failed to confirm ai points")
|
||||
}
|
||||
|
||||
@@ -329,7 +330,7 @@ func (s *QuestionExpansionService) GenerateByAIDistill(ctx context.Context, bran
|
||||
|
||||
return &QuestionCandidateResult{
|
||||
Candidates: candidates,
|
||||
AIPointsCharged: reservation.Points,
|
||||
AIPointsCharged: completed.Points,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -413,10 +414,11 @@ func (s *QuestionExpansionService) FillQuestionCombination(ctx context.Context,
|
||||
}
|
||||
|
||||
filled := sanitizeQuestionCombinationFillResult(payload, fallback)
|
||||
if err := CompleteAIPoints(context.Background(), s.pool, actor.TenantID, *reservation, result.Model); err != nil {
|
||||
completed, err := CompleteAIPoints(context.Background(), s.pool, s.cache, actor.TenantID, *reservation, result.Model, result.Content)
|
||||
if err != nil {
|
||||
return nil, response.ErrInternal(50127, "ai_points_commit_failed", "failed to confirm ai points")
|
||||
}
|
||||
filled.AIPointsCharged = reservation.Points
|
||||
filled.AIPointsCharged = completed.Points
|
||||
if s.cache != nil {
|
||||
cached := filled
|
||||
cached.AIPointsCharged = 0
|
||||
|
||||
Reference in New Issue
Block a user