feat: add user AI spend endpoint (#26978)

## Description

Adds the `GET /api/v2/users/{user}/ai/spend` endpoint returning the
user's current AI spend, effective budget, and period bounds.

## Changes

- Add `userAISpendStatus` handler under the same feature/experiment gate
as `/api/v2/users/{user}/ai/budget`.
- Add `codersdk.UserAIBudgetSummary` (embedded into `UserAISpendStatus`)
and a `UserAISpendStatus` client method.
- Move `LimitSource` from `coderd/aibridge/budget` to `codersdk` so the
type is shared across endpoints.

Closes https://linear.app/codercom/issue/AIGOV-472

> [!NOTE]
> Initially generated by Claude Opus 4.7, modified and reviewed by
@ssncferreira
This commit is contained in:
Susana Ferreira
2026-07-08 12:46:47 +01:00
committed by GitHub
parent 60d0859bde
commit 48f07e6e13
11 changed files with 719 additions and 45 deletions
+85
View File
@@ -9652,6 +9652,40 @@ const docTemplate = `{
]
}
},
"/api/v2/users/{user}/ai/spend": {
"get": {
"produces": [
"application/json"
],
"tags": [
"Enterprise"
],
"summary": "Get user AI spend",
"operationId": "get-user-ai-spend",
"parameters": [
{
"type": "string",
"description": "User ID, username, or me",
"name": "user",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/codersdk.UserAISpendStatus"
}
}
},
"security": [
{
"CoderSessionToken": []
}
]
}
},
"/api/v2/users/{user}/appearance": {
"get": {
"produces": [
@@ -15251,6 +15285,17 @@ const docTemplate = `{
}
}
},
"codersdk.AIBudgetLimitSource": {
"type": "string",
"enum": [
"user_override",
"group"
],
"x-enum-varnames": [
"AIBudgetLimitSourceUserOverride",
"AIBudgetLimitSourceGroup"
]
},
"codersdk.AIConfig": {
"type": "object",
"properties": {
@@ -25657,6 +25702,46 @@ const docTemplate = `{
}
}
},
"codersdk.UserAISpendStatus": {
"type": "object",
"properties": {
"current_spend_micros": {
"description": "CurrentSpendMicros is the user's spend on their effective group over\nthe current budget period.",
"type": "integer"
},
"effective_group_id": {
"description": "EffectiveGroupID is the group the spend is attributed to. Null when\nno budget applies.",
"type": "string",
"format": "uuid"
},
"limit_source": {
"description": "LimitSource identifies which tier produced the limit. Null when no\nbudget applies.",
"allOf": [
{
"$ref": "#/definitions/codersdk.AIBudgetLimitSource"
}
]
},
"period_end": {
"description": "PeriodEnd is the exclusive upper bound of the current budget\nperiod.",
"type": "string",
"format": "date-time"
},
"period_start": {
"description": "PeriodStart is the inclusive lower bound of the current budget\nperiod.",
"type": "string",
"format": "date-time"
},
"spend_limit_micros": {
"description": "SpendLimitMicros is the effective spend limit in micro-units.\nNull when no budget applies to the user (unlimited).",
"type": "integer"
},
"user_id": {
"type": "string",
"format": "uuid"
}
}
},
"codersdk.UserActivity": {
"type": "object",
"properties": {