mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
refactor: make user AI budget and spend endpoints consistent (#27611)
## Description
Makes the user AI cost control endpoints consistent.
## Changes
- Replaces the flat `spend_limit_micros` and `limit_source` fields on
`GET /users/{user}/ai/spend` with a nested `effective_budget`, reusing
the type behind `group_budget`. The flat pair made it possible to encode
a limit without a source.
- Renames `AIGroupBudget` to `AIBudgetLimit`, since it also carries
`user_override` limits and is no longer group-specific. The type name is
not part of the wire format.
- Moves `/users/{user}/ai/budget` to `/users/{user}/ai/budget/override`.
The endpoint only ever managed the per-user override, which the type,
the handlers, and the operation IDs all already said; the path was the
only place that didn't.
> [!NOTE]
> Initially generated by Claude Opus 4.7, modified and reviewed by
@ssncferreira
This commit is contained in:
Generated
+21
-25
@@ -9950,7 +9950,7 @@ const docTemplate = `{
|
||||
]
|
||||
}
|
||||
},
|
||||
"/api/v2/users/{user}/ai/budget": {
|
||||
"/api/v2/users/{user}/ai/budget/override": {
|
||||
"get": {
|
||||
"produces": [
|
||||
"application/json"
|
||||
@@ -15784,6 +15784,17 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"codersdk.AIBudgetLimit": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"limit_source": {
|
||||
"$ref": "#/definitions/codersdk.AIBudgetLimitSource"
|
||||
},
|
||||
"spend_limit_micros": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"codersdk.AIBudgetLimitSource": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
@@ -15832,17 +15843,6 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"codersdk.AIGroupBudget": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"limit_source": {
|
||||
"$ref": "#/definitions/codersdk.AIBudgetLimitSource"
|
||||
},
|
||||
"spend_limit_micros": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"codersdk.AIProvider": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -20838,7 +20838,7 @@ const docTemplate = `{
|
||||
"description": "GroupBudget is the budget when the queried group is this user's\neffective budget source. Null when the user's budget resolves to another\ngroup or no budget applies to the user.",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/codersdk.AIGroupBudget"
|
||||
"$ref": "#/definitions/codersdk.AIBudgetLimit"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -26529,19 +26529,19 @@ const docTemplate = `{
|
||||
"description": "CurrentSpendMicros is the user's spend on their effective group over\nthe current budget period.",
|
||||
"type": "integer"
|
||||
},
|
||||
"effective_budget": {
|
||||
"description": "EffectiveBudget is the spend limit that applies to the user, whether it\ncame from a group budget or a user override. Null when no budget\napplies, leaving the user's spend unlimited.",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/codersdk.AIBudgetLimit"
|
||||
}
|
||||
]
|
||||
},
|
||||
"effective_group_id": {
|
||||
"description": "EffectiveGroupID is the group the spend is attributed to, falling back to\nthe Everyone group when no budget applies. Null only when the user has no\norganization membership.",
|
||||
"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",
|
||||
@@ -26552,10 +26552,6 @@ const docTemplate = `{
|
||||
"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"
|
||||
|
||||
Generated
+21
-25
@@ -8823,7 +8823,7 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
"/api/v2/users/{user}/ai/budget": {
|
||||
"/api/v2/users/{user}/ai/budget/override": {
|
||||
"get": {
|
||||
"produces": ["application/json"],
|
||||
"tags": ["Enterprise"],
|
||||
@@ -14078,6 +14078,17 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"codersdk.AIBudgetLimit": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"limit_source": {
|
||||
"$ref": "#/definitions/codersdk.AIBudgetLimitSource"
|
||||
},
|
||||
"spend_limit_micros": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"codersdk.AIBudgetLimitSource": {
|
||||
"type": "string",
|
||||
"enum": ["user_override", "group"],
|
||||
@@ -14123,17 +14134,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"codersdk.AIGroupBudget": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"limit_source": {
|
||||
"$ref": "#/definitions/codersdk.AIBudgetLimitSource"
|
||||
},
|
||||
"spend_limit_micros": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"codersdk.AIProvider": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -18972,7 +18972,7 @@
|
||||
"description": "GroupBudget is the budget when the queried group is this user's\neffective budget source. Null when the user's budget resolves to another\ngroup or no budget applies to the user.",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/codersdk.AIGroupBudget"
|
||||
"$ref": "#/definitions/codersdk.AIBudgetLimit"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -24386,19 +24386,19 @@
|
||||
"description": "CurrentSpendMicros is the user's spend on their effective group over\nthe current budget period.",
|
||||
"type": "integer"
|
||||
},
|
||||
"effective_budget": {
|
||||
"description": "EffectiveBudget is the spend limit that applies to the user, whether it\ncame from a group budget or a user override. Null when no budget\napplies, leaving the user's spend unlimited.",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/codersdk.AIBudgetLimit"
|
||||
}
|
||||
]
|
||||
},
|
||||
"effective_group_id": {
|
||||
"description": "EffectiveGroupID is the group the spend is attributed to, falling back to\nthe Everyone group when no budget applies. Null only when the user has no\norganization membership.",
|
||||
"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",
|
||||
@@ -24409,10 +24409,6 @@
|
||||
"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"
|
||||
|
||||
@@ -1490,7 +1490,7 @@ func GroupMemberAISpend(row database.GetGroupMembersAISpendRow) codersdk.GroupMe
|
||||
member.EffectiveGroupID = &row.EffectiveGroupID.UUID
|
||||
}
|
||||
if row.SpendLimitMicros.Valid {
|
||||
member.GroupBudget = &codersdk.AIGroupBudget{
|
||||
member.GroupBudget = &codersdk.AIBudgetLimit{
|
||||
SpendLimitMicros: row.SpendLimitMicros.Int64,
|
||||
LimitSource: codersdk.AIBudgetLimitSource(row.LimitSource.String),
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user