+
{/* Vertical line */}
@@ -475,7 +487,9 @@ const RequestLifecycle = ({ entries }: { entries: GuardrailInformation[] }) => {
{OUTCOME_LABEL[item.outcome]}
)}
- T+{item.offsetMs}ms
+
+ {item.offsetMs === null ? "ā" : `T+${item.offsetMs}ms`}
+
diff --git a/ui/litellm-dashboard/src/lib/http/schema.d.ts b/ui/litellm-dashboard/src/lib/http/schema.d.ts
index 27ffb905237..5138c456ff2 100644
--- a/ui/litellm-dashboard/src/lib/http/schema.d.ts
+++ b/ui/litellm-dashboard/src/lib/http/schema.d.ts
@@ -8544,6 +8544,45 @@ export interface paths {
patch?: never;
trace?: never;
};
+ "/management/v1/teams/{team_id}/members/bulk_update": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ get?: never;
+ put?: never;
+ /**
+ * Bulk Update Team Member Budgets Action
+ * @description Set per-member limits for up to 500 members of one team in one call. Same
+ * authorization and member addressing as `/team/member_update`: proxy admins, the team's
+ * admins, and admins of the team's organization, with each member named by exactly one of
+ * `user_id` or `user_email`. Unknown body fields are a 422 and an unknown team is a 404.
+ *
+ * Each row is a merge patch of that member's limits: a field left out is untouched, a
+ * field sent as null is cleared, and clearing the last limit drops the member back to the
+ * team default. A budget row shared by several memberships, the team default included, is
+ * copied for the member being patched rather than written in place, so one member's new
+ * cap never lands on anybody else.
+ *
+ * `data` holds one result per requested member, in request order, carrying the limits in
+ * force after the write. A row is `success: false` with an `error` when it names nobody on
+ * the team or repeats an earlier row. Roles are not part of this route; `/team/member_update`
+ * still owns them.
+ *
+ * Example curl:
+ * ```
+ * curl --location 'http://0.0.0.0:4000/management/v1/teams/team-1/members/bulk_update' --header 'Authorization: Bearer sk-1234' --header 'Content-Type: application/json' --data '{"members": [{"user_id": "user-1", "max_budget_in_team": 10}, {"user_email": "user-2@example.com", "max_budget_in_team": 10, "budget_duration": "30d"}]}'
+ * ```
+ */
+ post: operations["bulk_update_team_member_budgets_action_management_v1_teams__team_id__members_bulk_update_post"];
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
"/management/v1/users/bulk": {
parameters: {
query?: never;
@@ -24930,6 +24969,22 @@ export interface components {
[key: string]: unknown;
} | null;
};
+ /**
+ * BulkTeamMemberBudgetUpdateRequest
+ * @description Body of `POST /management/v1/teams/{team_id}/members/bulk_update`.
+ */
+ BulkTeamMemberBudgetUpdateRequest: {
+ /** Members */
+ members: components["schemas"]["TeamMemberBudgetPatch"][];
+ };
+ /**
+ * BulkTeamMemberBudgetUpdateResponse
+ * @description `{data: [...]}` with one `TeamMemberBudgetUpdateResult` per requested member, in request order.
+ */
+ BulkTeamMemberBudgetUpdateResponse: {
+ /** Data */
+ data: components["schemas"]["TeamMemberBudgetUpdateResult"][];
+ };
/**
* BulkTeamMemberDeleteRequest
* @description Body of `POST /management/v1/teams/{team_id}/members/bulk_delete`.
@@ -37945,6 +38000,57 @@ export interface components {
/** User Id */
user_id?: string | null;
};
+ /**
+ * TeamMemberBudgetPatch
+ * @description One member's per-member limits, merge-patch style: a field left out of the row is
+ * untouched, a field sent as null is cleared, and clearing the last limit drops the
+ * member back to the team default.
+ */
+ TeamMemberBudgetPatch: {
+ /** Allowed Models */
+ allowed_models?: string[] | null;
+ /** Budget Duration */
+ budget_duration?: string | null;
+ /** Max Budget In Team */
+ max_budget_in_team?: number | null;
+ /** Rpm Limit */
+ rpm_limit?: number | null;
+ /** Tpm Limit */
+ tpm_limit?: number | null;
+ /** User Email */
+ user_email?: string | null;
+ /** User Id */
+ user_id?: string | null;
+ };
+ /**
+ * TeamMemberBudgetUpdateResult
+ * @description Outcome for one requested member, in request order, carrying the limits in force
+ * after the write rather than the ones that were asked for.
+ */
+ TeamMemberBudgetUpdateResult: {
+ /** Allowed Models */
+ allowed_models?: string[] | null;
+ /** Budget Duration */
+ budget_duration?: string | null;
+ /** Budget Id */
+ budget_id?: string | null;
+ /** Error */
+ error?: string | null;
+ /** Max Budget */
+ max_budget?: number | null;
+ /** Max Budget Source */
+ max_budget_source?: ("member" | "team_default") | null;
+ /** Rpm Limit */
+ rpm_limit?: number | null;
+ /** Success */
+ success: boolean;
+ /** Tpm Limit */
+ tpm_limit?: number | null;
+ /** User Email */
+ user_email?: string | null;
+ /** User Id */
+ user_id?: string | null;
+ };
/** TeamMemberDeleteRequest */
TeamMemberDeleteRequest: {
/** Team Id */
@@ -38000,7 +38106,7 @@ export interface components {
};
/**
* TeamMemberRef
- * @description One member to remove, named by exactly one of `user_id` or `user_email`.
+ * @description One member, named by exactly one of `user_id` or `user_email`.
*/
TeamMemberRef: {
/** User Email */
@@ -52113,6 +52219,41 @@ export interface operations {
};
};
};
+ bulk_update_team_member_budgets_action_management_v1_teams__team_id__members_bulk_update_post: {
+ parameters: {
+ query?: never;
+ header?: never;
+ path: {
+ team_id: string;
+ };
+ cookie?: never;
+ };
+ requestBody: {
+ content: {
+ "application/json": components["schemas"]["BulkTeamMemberBudgetUpdateRequest"];
+ };
+ };
+ responses: {
+ /** @description Successful Response */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["BulkTeamMemberBudgetUpdateResponse"];
+ };
+ };
+ /** @description Validation Error */
+ 422: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": components["schemas"]["HTTPValidationError"];
+ };
+ };
+ };
+ };
bulk_create_users_route_management_v1_users_bulk_post: {
parameters: {
query?: never;
diff --git a/uv.lock b/uv.lock
index f8c7a0d7e83..35eaa20c39e 100644
--- a/uv.lock
+++ b/uv.lock
@@ -10,7 +10,7 @@ resolution-markers = [
]
[options]
-exclude-newer = "2026-09-12T22:48:38.53978Z"
+exclude-newer = "2026-09-14T20:32:38.482736111Z"
exclude-newer-span = "P3D"
[manifest]
@@ -535,16 +535,21 @@ wheels = [
[[package]]
name = "aws-sdk-bedrock-runtime"
-version = "0.7.0"
+version = "0.11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "smithy-aws-core", extra = ["eventstream", "json"], marker = "python_full_version >= '3.12'" },
{ name = "smithy-core", marker = "python_full_version >= '3.12'" },
- { name = "smithy-http", extra = ["awscrt"], marker = "python_full_version >= '3.12'" },
+ { name = "smithy-http", extra = ["aiohttp"], marker = "python_full_version >= '3.12'" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/67/8a/ed3fd98775273b0b7f6006b4970aa876d506668b7fe29145f54fcb941c3b/aws_sdk_bedrock_runtime-0.7.0.tar.gz", hash = "sha256:0cb172cbc03ff060e5c1d6f9cfa9a8ac5e71d9e0d58d3117006ebf614cbb4677", size = 170304, upload-time = "2026-06-23T04:04:52.382Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/8e/b3/9c225cbfe9f17ea2e3d75a0fdd0b325ef79839b9c09a376bda63a7bf3bb3/aws_sdk_bedrock_runtime-0.11.0.tar.gz", hash = "sha256:f2c45d34625bf6a7b56375e29a53a16b376880bda771e4bbf7d84491622eb193", size = 173854, upload-time = "2026-08-24T21:17:16.304Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/9e/e1/f86d50f0ad9c8200645f315c524d285e86b30b94bb65118e1108597714e6/aws_sdk_bedrock_runtime-0.7.0-py3-none-any.whl", hash = "sha256:de67ede6f441bbb77ef61c237945d559513843fc827abe1af12535c2519650c5", size = 94948, upload-time = "2026-06-23T04:04:51.281Z" },
+ { url = "https://files.pythonhosted.org/packages/29/0c/9512304ed017ce49992df6661eac2b914550247e13bccb55be6ca594170d/aws_sdk_bedrock_runtime-0.11.0-py3-none-any.whl", hash = "sha256:ef01c26ddfd83a5d3e438ab72ebb3c13b41fc0ef11d81095b22c8016f97e9795", size = 97112, upload-time = "2026-08-24T21:17:17.396Z" },
+]
+
+[package.optional-dependencies]
+awscrt = [
+ { name = "smithy-http", extra = ["awscrt"], marker = "python_full_version >= '3.12'" },
]
[[package]]
@@ -4483,7 +4488,7 @@ dependencies = [
[package.optional-dependencies]
bedrock-realtime = [
- { name = "aws-sdk-bedrock-runtime", marker = "python_full_version >= '3.12'" },
+ { name = "aws-sdk-bedrock-runtime", extra = ["awscrt"], marker = "python_full_version >= '3.12'" },
]
caching = [
{ name = "diskcache" },
@@ -4693,7 +4698,7 @@ requires-dist = [
{ name = "apscheduler", marker = "extra == 'proxy'", specifier = ">=3.11.2,<4.0" },
{ name = "audioread", marker = "extra == 'stt-nvidia-riva'", specifier = ">=3.0.1" },
{ name = "aurelio-sdk", marker = "python_full_version < '3.14' and extra == 'semantic-router'", specifier = ">=0.0.19,<1.0" },
- { name = "aws-sdk-bedrock-runtime", marker = "python_full_version >= '3.12' and extra == 'bedrock-realtime'", specifier = ">=0.7.0,<0.8.0" },
+ { name = "aws-sdk-bedrock-runtime", extras = ["awscrt"], marker = "python_full_version >= '3.12' and extra == 'bedrock-realtime'", specifier = ">=0.10.0,<0.12.0" },
{ name = "azure-ai-contentsafety", marker = "extra == 'proxy-runtime'", specifier = ">=1.0.0,<2.0" },
{ name = "azure-identity", marker = "extra == 'extra-proxy'", specifier = ">=1.25.2,<2.0" },
{ name = "azure-identity", marker = "extra == 'proxy'", specifier = ">=1.25.2,<2.0" },
@@ -4884,7 +4889,7 @@ source = { editable = "enterprise" }
[[package]]
name = "litellm-proxy-extras"
-version = "0.4.98"
+version = "0.4.99"
source = { editable = "litellm-proxy-extras" }
[[package]]
@@ -9126,16 +9131,16 @@ wheels = [
[[package]]
name = "smithy-aws-core"
-version = "0.7.0"
+version = "0.11.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "aws-sdk-signers", marker = "python_full_version >= '3.12'" },
{ name = "smithy-core", marker = "python_full_version >= '3.12'" },
{ name = "smithy-http", marker = "python_full_version >= '3.12'" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/fc/a8/37bfde59519f45d2047d0033b791aca6574d867aaf57bb56a6de42ab5c26/smithy_aws_core-0.7.0.tar.gz", hash = "sha256:34e82d09fc808acd5ffc80f03828d0609c6a211f49f0884dc6ee7ca095a1b6af", size = 15670, upload-time = "2026-06-23T04:04:50.365Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/7d/d3/501c0023548173416109ac42298ca33b708469dc922005770811a597949f/smithy_aws_core-0.11.0.tar.gz", hash = "sha256:29ee89976a520a87e3db557e03e115fdc21a0a60b81161e95174395a1b064da1", size = 38791, upload-time = "2026-08-24T21:16:59.631Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/fd/54/2d06dd9a3972a380d71bb8c3312e317aa8f1ea68dd28cffc06955ccf0220/smithy_aws_core-0.7.0-py3-none-any.whl", hash = "sha256:6c60c8fbb9431c60e80ea7f2d37e7ae48409cc1541f587fe073f202eca067e92", size = 24894, upload-time = "2026-06-23T04:04:49.349Z" },
+ { url = "https://files.pythonhosted.org/packages/e4/f6/fefda9aab809fa1a62bf7073bd6d8ab427bd9989f39b13c0d6e29d4d1045/smithy_aws_core-0.11.0-py3-none-any.whl", hash = "sha256:77cf130c22deac14a8cbeb8ccc4bcfe5a91798f4b38cb53a987080ec58c89f23", size = 58855, upload-time = "2026-08-24T21:16:58.657Z" },
]
[package.optional-dependencies]
@@ -9160,41 +9165,45 @@ wheels = [
[[package]]
name = "smithy-core"
-version = "0.6.0"
+version = "0.8.1"
source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/e9/45/688d52c61cd4d843bb230694259e91d4c7d6954eeecbadf452a168001d45/smithy_core-0.6.0.tar.gz", hash = "sha256:ba2e5d860d716aff75004a23f53e09dfaca3e2b94f8a00c1f76dcb355b769ce0", size = 52095, upload-time = "2026-06-23T04:04:44.687Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/7c/c6/93e9eea3c6163228dfe972c3e989e0553047858805ab7aa4a59f074ba129/smithy_core-0.8.1.tar.gz", hash = "sha256:3d2f8fca5960d74bd7ef380f70901c7bcdebe53f929d2d3d2fa6cb790b3f5214", size = 54259, upload-time = "2026-08-20T17:55:30.354Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/3a/b6/06795faa9844b9667ae492e6293370393e19e7f0c2df8da1b4bf7e5f6ed9/smithy_core-0.6.0-py3-none-any.whl", hash = "sha256:51e347ed309d60ab9d36b783dbf88de614c460d51bec79d39cd403956b00f063", size = 66879, upload-time = "2026-06-23T04:04:43.596Z" },
+ { url = "https://files.pythonhosted.org/packages/0c/23/c6430bbf406477fc7d16254b9908a723b299a4a21a94c99db9d12c84a8bf/smithy_core-0.8.1-py3-none-any.whl", hash = "sha256:44bd9bdf702f76919af58e44a6a1bb3dc136a745b2f955281743022ce767e347", size = 68805, upload-time = "2026-08-20T17:55:29.366Z" },
]
[[package]]
name = "smithy-http"
-version = "0.4.2"
+version = "0.5.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "smithy-core", marker = "python_full_version >= '3.12'" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/66/58/5a772d212e066d6fc1398946c4aae19bcdaa75209879d776f641b6a06b5b/smithy_http-0.4.2.tar.gz", hash = "sha256:50d11b6a55e42448450a01e3d0f605ccee65a72abf52d02eed82862a15be5937", size = 29616, upload-time = "2026-06-23T04:04:45.687Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/98/78/b5f3113d6c8f0bc1f9777a7f5ca84b892d29efac05850e14f7d4f7e645b5/smithy_http-0.5.0.tar.gz", hash = "sha256:bb4a19672f7c7eeb872a308f777eb505281a5bafb1ee3d1ea9c760c06c352510", size = 31122, upload-time = "2026-08-24T21:16:56.488Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/57/3e/7b2464d40893bec0b5d1f479d25116d4aa09f9f66536b4c4b3126202215d/smithy_http-0.4.2-py3-none-any.whl", hash = "sha256:a158f107e9fab925289d20772c2e38b0bba94e55c05d0edc9290310f22a60454", size = 41025, upload-time = "2026-06-23T04:04:46.764Z" },
+ { url = "https://files.pythonhosted.org/packages/27/27/e414082643028846b73afa52a1a8f934548196ee12b187a06803f02a3e66/smithy_http-0.5.0-py3-none-any.whl", hash = "sha256:af273d5f42e7733ce7a6e9bd6fdd6a59ef1b61f6cd1f4a89dd53dfce99da7bef", size = 42198, upload-time = "2026-08-24T21:16:57.52Z" },
]
[package.optional-dependencies]
+aiohttp = [
+ { name = "aiohttp", marker = "python_full_version >= '3.12'" },
+ { name = "yarl", marker = "python_full_version >= '3.12'" },
+]
awscrt = [
{ name = "awscrt", marker = "python_full_version >= '3.12'" },
]
[[package]]
name = "smithy-json"
-version = "0.2.3"
+version = "0.3.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "ijson", marker = "python_full_version >= '3.12'" },
{ name = "smithy-core", marker = "python_full_version >= '3.12'" },
]
-sdist = { url = "https://files.pythonhosted.org/packages/b9/6c/418b5687d8933b7a135d5e1a98c61fe814b98f72517dbae0e666860cb876/smithy_json-0.2.3.tar.gz", hash = "sha256:686e9b55a36dacb08e472732b358573ef78009055e05e9fce2e806d61490b2b3", size = 7805, upload-time = "2026-06-23T04:04:47.71Z" }
+sdist = { url = "https://files.pythonhosted.org/packages/c7/ac/04164eefb3da7479f52f6535b4b39cc8384c292cb2bb74279f2acc4f4b4d/smithy_json-0.3.0.tar.gz", hash = "sha256:c81c7034587e01bc64767cbbecb05a7d65ca9070612fd94e8a03e80540290a22", size = 7956, upload-time = "2026-08-20T17:55:32.177Z" }
wheels = [
- { url = "https://files.pythonhosted.org/packages/3c/14/eabb26b355415bcd9feef27fb5b18f1dad3fabd4208cfcbaf152025fa9ae/smithy_json-0.2.3-py3-none-any.whl", hash = "sha256:594e1bbe3d480963237f8fd0fc648dbd4e988b4503fea90157b5f07706796327", size = 10252, upload-time = "2026-06-23T04:04:48.46Z" },
+ { url = "https://files.pythonhosted.org/packages/9d/cf/0104c40a0e18fa307ea3da4310eba949f474a5bc1df3cc2b5851a72e8486/smithy_json-0.3.0-py3-none-any.whl", hash = "sha256:ffb73d2e60cf5e616e5d0a1019e7b9f518edba076cb423f10981457725dcddc4", size = 10252, upload-time = "2026-08-20T17:55:31.204Z" },
]
[[package]]