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:
@@ -52,7 +52,7 @@ type AIPointUsageListParams struct {
|
||||
|
||||
type AIPointUsageRepository interface {
|
||||
Create(ctx context.Context, input CreateAIPointUsageLogInput) (int64, error)
|
||||
MarkCompleted(ctx context.Context, tenantID, id int64, model *string) error
|
||||
MarkCompleted(ctx context.Context, tenantID, id int64, requestChars, baseChars, points int, model *string) error
|
||||
MarkRefunded(ctx context.Context, tenantID, id int64, errorMessage string) error
|
||||
FindPendingByResource(ctx context.Context, tenantID int64, resourceType string, resourceID *int64, resourceUID *string) (*AIPointUsageLog, error)
|
||||
List(ctx context.Context, params AIPointUsageListParams) ([]AIPointUsageLog, error)
|
||||
@@ -97,18 +97,21 @@ RETURNING id
|
||||
return id, err
|
||||
}
|
||||
|
||||
func (r *aiPointUsageRepository) MarkCompleted(ctx context.Context, tenantID, id int64, model *string) error {
|
||||
func (r *aiPointUsageRepository) MarkCompleted(ctx context.Context, tenantID, id int64, requestChars, baseChars, points int, model *string) error {
|
||||
_, err := r.db.Exec(ctx, `
|
||||
UPDATE ai_point_usage_logs
|
||||
SET status = 'completed',
|
||||
model = $1,
|
||||
request_chars = $2,
|
||||
base_chars = $3,
|
||||
points = $4,
|
||||
error_message = NULL,
|
||||
completed_at = COALESCE(completed_at, NOW()),
|
||||
updated_at = NOW()
|
||||
WHERE id = $2
|
||||
AND tenant_id = $3
|
||||
WHERE id = $5
|
||||
AND tenant_id = $6
|
||||
AND status = 'pending'
|
||||
`, model, id, tenantID)
|
||||
`, model, requestChars, baseChars, points, id, tenantID)
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user