Commit graph

4874 commits

Author SHA1 Message Date
Yuneng Jiang
3170fff768
refactor(ui): move the settings page and bulk user invite onto shadcn primitives
Rebuilds settings.tsx and bulk_create_users_button.tsx on the in-repo shadcn
layer. The settings callback form moves from antd Form to react-hook-form with
the shared Field primitives, and the CSV drop zone replaces antd Upload with a
native file input plus drag handlers. Both public prop signatures are
unchanged, so no caller moves.
2026-08-14 07:49:33 -07:00
Yuneng Jiang
4544f7dbad
revert(ui): keep the onboarding link modal on antd
The invitation dialog opens over the still-antd Invite User modal. Lifting
only the shadcn dialog content above antd's mask leaves its own backdrop
underneath, so an outside click reaches the wrong modal. Adding a second
backdrop stops that but does not restore dismissal, and the same hazard
already ships in three guardrails modals, so the stacking needs one shared
fix rather than a fourth local workaround.
2026-08-14 07:10:13 -07:00
Yuneng Jiang
15a331f6df
refactor(ui): move the root-level dashboard components onto shadcn primitives
Rebuilds nine components under src/components on the in-repo shadcn layer:
both banners, the navbar chrome, the onboarding link dialog, the model
filters, the model group alias table, the object permissions and logging
settings views, and the user dashboard grid. Every public prop signature is
unchanged, so no caller moves.
2026-08-14 06:52:06 -07:00
Yuneng Jiang
362875a7e6
fix(ui): hold the delete dialog open mid-deletion and keep unmatched select values
DeleteResourceModal let escape, the backdrop and the close button dismiss it
while the delete request was still in flight. SearchSelect blanked its field
whenever the value was missing from options, which happens while they load;
it now falls back to the raw value the way PaginatedSearchSelect already did.
2026-08-14 06:29:49 -07:00
Yuneng Jiang
d7ec4d98b1
test(ui): spread the real lucide-react module in the KeyInfoView mock
The mock returned only CopyIcon and CheckIcon, so any icon a child later
imports resolves to undefined. DeleteResourceModal now renders CircleAlert,
which broke all twelve cases in this file.
2026-08-14 06:22:06 -07:00
Yuneng Jiang
0ee47a0028
test(ui): cover appending a second model in ModelSelect
The rewritten suite only ever picked one ordinary model, so a
regression that replaced the selection instead of appending to it
would have gone unnoticed. The case passes against the antd version
too, so it pins behavior the migration preserves rather than adds.
2026-08-14 06:12:28 -07:00
Yuneng Jiang
afff1b08fa
refactor(ui): move the shared dropdowns and selectors onto shadcn primitives
Rebuilds the thirteen form-free components under common_components on
the in-repo shadcn layer, so they inherit the dashboard's design tokens
instead of styling themselves through Ant Design and Tremor.

SearchSelect and the three dropdowns that wrap it now forward an
optional input id, so an antd Form.Item label still resolves to its
control. The e2e steps that reached into antd's Select and Modal
internals now go through the test id, role and data-slot.
2026-08-14 06:09:10 -07:00
Yuneng Jiang
26e055248b
refactor(ui): give MemberTable its own extra-column type
extraColumns was typed as antd's ColumnsType while the adapter only
honoured string/ReactNode titles, plain-string dataIndex values and
element/string/number render results, so several valid antd column
forms produced blank cells. MemberTableColumn now describes exactly
what the table renders, and a column with a dataIndex but no render
falls back to the member value instead of rendering nothing.
2026-08-14 04:57:13 -07:00
Yuneng Jiang
3a537cce4d
refactor(ui): move the model hub and model select onto shadcn primitives
Rebuilds public_model_hub, MakeSkillPublicForm, ModelSelect and the
guardrail LogViewer on the in-repo shadcn layer, so they inherit the
dashboard's design tokens instead of styling themselves through Ant
Design and Tremor.

Public prop signatures are unchanged, so no caller moves. The two
teams e2e steps that reached into antd's Select internals now drive
the combobox through its test id, role and data-slot instead.
2026-08-14 04:48:49 -07:00
Yuneng Jiang
3465ba4914
refactor(ui): migrate router settings and shared badges off antd and tremor
Replaces Ant Design and Tremor in the fallbacks views, the router general
settings panel, and the two shared banner and badge components.

- Tremor Card, Table and Icon become the ui/card, ui/table and lucide
  equivalents, reproducing Tremor's icon box so click targets keep their size
- antd Alert becomes a composed role="alert" region, since the shadcn CLI's
  alert pulls in class-variance-authority, which this repo does not have
- antd InputNumber becomes a native number input, and Switch onChange becomes
  onCheckedChange
- shadcn TableCell ships whitespace-nowrap where Tremor's did not, so cells
  holding model names and setting descriptions get whitespace-normal back
- adds a DeprecationBanner test covering naming, the link, and dismissal,
  proven against the antd version first and mutation checked
- drops the eslint suppressions these files no longer need
2026-08-14 03:52:41 -07:00
Yuneng Jiang
617ad8194c
refactor(ui): migrate key info and permissions views off antd and tremor
Replaces Ant Design and Tremor in the key info header and detail view, the
agent and vector store permission panels, and the team member permissions
table.

- antd Popover, Dropdown and Modal become HoverCard, DropdownMenu and Dialog,
  and Tremor TabGroup becomes Tabs with keepMounted so panel state survives
  a tab switch the way Tremor's did
- the key id copy control moves to the shared CopyButton, which also fixes an
  icon that rendered at 24px because it inherited the heading font size
- antd Checkbox onChange becomes onCheckedChange
- every public prop signature is unchanged, since these are shared views
- three member permission tests were passing vacuously: they searched for an
  unchecked box by reading .checked, which is undefined on a Base UI checkbox,
  so the assertions sat inside an if that never ran. They now scope the
  checkbox to its own row and assert the toggle, the save and the revert
- drops the eslint suppressions these files no longer need
2026-08-14 03:30:31 -07:00
Yuneng Jiang
fbc56c3b7b
test(ui): assert the publish button is disabled while submitting
The migration closed a double submit hole that antd left open, but the
rewritten tests only proved the flow had not completed, so removing the
guard would not have failed them. Verified by mutation: dropping
disabled={loading} fails exactly this case.
2026-08-14 02:57:55 -07:00
Yuneng Jiang
a98f2380f8
refactor(ui): migrate shared common_components off antd and tremor
Replaces Ant Design and Tremor in the six shared components under
src/components/common_components, which between them are reached by
nine routes.

- antd Table becomes the ui/table primitives, and the Actions column keeps
  antd's fixed: "right" behaviour via a sticky cell
- Tremor Icon, Text and Badge become a plain span, p and StatusBadge
- antd Tooltip and Typography copyable become the shadcn Tooltip and the
  shared CopyButton
- every public prop signature is unchanged, since these are shared components
  and a renamed prop would break callers far from this folder
- two tests dropped assertions on antd internal class names and on DOM
  structure, and gained cases proving a disabled action does not fire onClick

MemberTable keeps a type-only import of antd's ColumnsType because a consumer
annotates its own column array with it. No antd code ships from the file.
2026-08-14 02:55:16 -07:00
Yuneng Jiang
c344b9a052
fix(ui): give the request details drawer an accessible name
Screen readers announced an unnamed dialog. The visible header is a custom
layout, so the title is visually hidden to keep the drawer layout unchanged.
2026-08-14 02:25:18 -07:00
Yuneng Jiang
07492314a8
fix(ui): announce the account popover as a dialog, not a menu
The panel holds switches and ordinary buttons rather than menu items, so
menu semantics promised keyboard behavior it does not provide.
2026-08-14 02:23:24 -07:00
Yuneng Jiang
9b8f9c69ad
refactor(ui): migrate AI Hub off antd and tremor to shadcn
Replaces Ant Design and Tremor across src/components/AIHub, so the model,
agent, MCP and skill hub views compose @/components/ui primitives.

- Modal becomes Dialog, tremor TabGroup becomes Tabs, tremor Card and Table
  become their shadcn counterparts, and Tag and tremor Badge become Badge
- the three publish forms wrapped antd Form around zero Form.Item fields, so
  the wrapper became a div and the dead useForm and resetFields calls went
  with it, rather than pulling in react-hook-form for a form with no fields
- antd Steps has no shadcn equivalent, so each form inlines a small ol stepper
- cells holding model names, server ids and URLs gained min-w-0 and break-words
  so a long value cannot bleed into the neighbouring column
- the three form tests dropped assertions invented by their antd mocks in
  favour of roles and rendered text
- drops the eslint suppressions these files no longer need
2026-08-14 02:21:42 -07:00
bhuvan2134686
d499e68e55 Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_scx_ai_provider
# Conflicts:
#	ui/litellm-dashboard/src/components/provider_info_helpers.tsx
2026-08-14 19:15:02 +10:00
Yuneng Jiang
03d2b16bcb
refactor(ui): migrate log details drawer off antd to shadcn
Replaces Ant Design across every source file under src/components/view_logs,
so the request log drawer and its viewers compose @/components/ui primitives.

- Drawer becomes Sheet, Collapse becomes Collapsible, Segmented and Radio.Group
  become Tabs, Tag becomes Badge, Descriptions becomes a local grid helper
- every lucide icon carries an explicit size class, since antd icons render at
  1em while lucide defaults to 24px
- two tests dropped assertions on antd internal class names in favour of
  rendered text and roles, and the Pretty/JSON case now proves the toggle
  actually swaps the body rather than only that both controls render
- drops the eslint suppressions these files no longer need
2026-08-14 01:51:24 -07:00
Yuneng Jiang
0cb48cf23c
refactor(ui): migrate Navbar off antd to shadcn
Replaces Ant Design with the in-repo shadcn layer across every Navbar
component, removing the last antd imports from src/components/Navbar.

- CommunityEngagementButtons, NotificationsBell, ViewSwitcher, BlogDropdown,
  WorkerDropdown and UserDropdown now compose @/components/ui primitives
- antd icons render at 1em while lucide defaults to 24px, so every icon
  carries an explicit size class matching what it replaced
- UserDropdown uses Popover rather than DropdownMenu: its panel holds
  switches and badges, and form controls inside role="menu" are invalid
- WorkerDropdown moves to Combobox since shadcn Select has no search
- drops the nine no-restricted-imports suppressions these files no longer need
2026-08-14 01:20:57 -07:00
Yuneng Jiang
28c1e43196
feat(ui): standardize the Teams page header 2026-08-14 00:01:16 -07:00
Mateo Wang
784259bbd9
Merge pull request #36769 from BerriAI/litellm_nvidia_riva_ui_provider
fix(ui): add nvidia riva to the model provider list
2026-08-13 20:39:24 -07:00
yucheng-berri
0a25756e78
fix(ptu): stop per-token billing on a PTU-configured deployment (#36829)
A deployment with PTU flat-cost attribution also billed every request per
token, so a team paid for reserved capacity and again for the traffic that
capacity serves. Nothing set the per-token price and an unset price falls
back to the public cost map, which made the double charge the default.

/model/new and /model/{id}/update now store zero for every pricing field the
cost map could otherwise fill, refuse a price the caller supplies alongside
PTU config with a 400 naming the field, zero a price already on the row
rather than rejecting later edits of unrelated fields, and drop the zeros
again when the PTU config goes.

A PTU deployment is no longer read as a free model by the budget checks,
which would have waived every budget for it.
2026-08-13 20:16:12 -07:00
mateo-berri
ea4316b245 fix(ui): resolve provider dropdown enum keys in getPlaceholder 2026-08-13 19:58:06 -07:00
mateo-berri
60c6c2c703 test: drop redundant explanatory comments from riva provider tests 2026-08-13 19:24:45 -07:00
mateo
a0a536216f Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_model-deprecation-alerts-55bc
Some checks failed
Terraform Modules / fmt, validate, test (aws) (push) Has been cancelled
Terraform Provider / gofmt, vet, build, test (push) Has been cancelled
Terraform Provider / Provider endpoints vs proxy OpenAPI schema (push) Has been cancelled
2026-08-14 02:19:03 +00:00
Yassin Kortam
909a2e6232
perf(spend-logs): bound retention cleanup so one run cannot saturate the database (#36594) 2026-08-13 18:56:37 -07:00
yuneng-jiang
89f81919cc
Merge pull request #36832 from BerriAI/litellm_/quizzical-jennings-5df447
refactor(ui): migrate guardrails to shadcn
2026-08-13 18:30:56 -07:00
yuneng-jiang
2913ee811c
Merge pull request #36847 from BerriAI/litellm_/awesome-shirley-6a1a86
refactor(ui): migrate playground to shadcn
2026-08-13 18:30:48 -07:00
yuneng-jiang
6797327dc8
Merge pull request #36838 from BerriAI/litellm_/brave-hermann-3d77ac
refactor(ui): migrate guardrails-monitor to shadcn
2026-08-13 18:30:40 -07:00
yuneng-jiang
ce3a56dce6
Merge pull request #36834 from BerriAI/litellm_/compassionate-jones-9c0d5c
refactor(ui): migrate usage to shadcn
2026-08-13 18:30:30 -07:00
Yassin Kortam
b344043eaf
fix(ui): stop a deselected MCP server keeping its grant on a virtual key (#36840)
* fix(ui): stop a deselected MCP server keeping its grant on a virtual key

The key editor sent `mcp_tool_permissions` unfiltered, and the MCP resolver
counts a server named only under `mcp_tool_permissions` as entitled, unioning
`tool_perm_servers` into `all_servers` at four sites in
`user_api_key_auth_mcp.py`. Deselecting a server, or removing the access group
that supplied it, therefore left a stale entry that kept the key reaching that
server with its old tool allowlist attached.

Reuse `extractMcpEntitlement`, which already landed for the internal-user
surface, so the key surface drops an entry only once the server is known and no
longer granted, and keeps it whenever a retained access group or toolset could
still supply it. The helper moves to a shared module so the key template does
not import a users page component.

Setting the map unconditionally is part of the same fix: the old
`Object.keys(...).length > 0` guard let the previous map ride through the
`object_permission` spread, which filtering to an empty map would otherwise hit
in exactly the case the fix is for.

* fix(ui): resolve retained MCP groups and toolsets per server when pruning tool permissions

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* test(ui): mock the MCP toolsets hook in the key update suite

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-08-13 18:00:42 -07:00
Yassin Kortam
e0f388cb5c
feat(ui): render request metrics on the /ui/chat surface (#36845)
/ui/chat never rendered a metrics bar. The Responses helper already parses
usage off the response.completed event, but the chat page passed positional
undefined where onTimingData, onUsageData and onTotalLatency sit, ChatMessage
had nowhere to hold them, and ChatMessages never rendered ResponseMetrics.

Thread the three callbacks through, persist the values on the assistant
message, and reuse the playground's ResponseMetrics to show latency, TTFT,
input/output/total tokens and cost. Also map the cost the proxy reports on the
streamed usage object, which only the chat-completions helper did before.
2026-08-13 17:31:13 -07:00
Yuneng Jiang
62523c1734
fix(ui): restore pattern search and popup layering in the guardrail wizard
Two behaviour differences the port introduced, both found in browser QA

The antd Select matched a prebuilt pattern on its display_name and its
internal name; a Base UI Combobox only searches itemToStringLabel, so
queries like "amex" and "sg" stopped matching. Restore the second field
with a filter predicate on the Root, covered by a regression test that
searches on a token the visible label does not contain

Base UI portals a popup into a positioner whose "isolate z-50" is fixed
in the primitive, so inside an antd Modal at z-index 1000 the options
were visible but not clickable. antd hid this because its own dropdowns
and tooltips already sat above its Modal. The positioner is not reachable
from the call site, so this needs one app-wide rule keyed on an antd
modal being present, and it becomes deletable when the last one goes
2026-08-13 17:27:26 -07:00
tin-berri
83e890bdde
feat(ui): shadow evals tab beside auto-router usage (#36588) 2026-08-13 17:19:45 -07:00
Yassin Kortam
b72dab8049
feat(ui): show provider prompt cache tokens in chat response metrics (#36827)
The chat metrics bar reported In/Out/Reasoning/Total/cost only, so a
playground user had no signal that provider prompt caching worked. The
cached-token counts were already visible in the Logs drawer, which meant
the answer to "does caching work here" lived on a different page.

Adds cacheReadTokens and cacheCreationTokens to TokenUsage and renders
them as two chips, reusing the prompt-cache tooltip wording already
introduced for the Logs drawer so both surfaces say the same thing.

A single helper, extractPromptCacheTokens, normalizes the three usage
shapes the playground consumes: Anthropic Messages
(cache_read_input_tokens / cache_creation_input_tokens), chat
completions (prompt_tokens_details) and the Responses API
(input_tokens_details). All three producers call it instead of parsing
per surface. Counts that are absent, zero or non-finite are dropped, so
providers without prompt caching render exactly what they render today.
2026-08-13 16:58:14 -07:00
Yuneng Jiang
0ebbda92d7
style(ui): drop the playground migration's explanatory comments
The repository's comment policy keeps reasoning out of the source, so the
notes on the delete dialog, the tooltip wrapper, and the test query choices
move to the pull request instead.
2026-08-13 16:51:22 -07:00
Yuneng Jiang
615de5d922
Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_/awesome-shirley-6a1a86 2026-08-13 16:32:16 -07:00
Yuneng Jiang
30b933dd5e
test(ui): drop the metric grid class assertion
The assertion pinned the Tailwind track string, which jsdom can never
evaluate: it does no layout, so the test could not fail for the reason
that matters, and its pattern accepted any minmax minimum, staying green
if that minimum changed enough to break the layout outright.

Only a viewport-resize browser test can observe this, which belongs in
tests/e2e/ui rather than a route's unit tests. The responsive behaviour
itself is unchanged; the widths it reproduces are recorded in b341a22339
2026-08-13 16:21:01 -07:00
Yuneng Jiang
9a26da90a4
refactor(ui): migrate playground to shadcn
Replaces antd and Tremor with shadcn primitives across the six route-owned,
form-free playground components: the compare view and its panel, message input
and unified selector, plus the realtime playground and the agent builder.

Markup only, no behaviour change. The characterisation tests added in the
previous commit are untouched here and stay green through the swap.

Adds ui/slider.tsx via the shadcn CLI and retires the six antd
no-restricted-imports suppressions the migration made obsolete.
2026-08-13 15:59:53 -07:00
Yuneng Jiang
b341a22339
fix(ui): keep the guardrails metric cards wrapping at narrow widths
The antd Row and Col the migration replaced never squeezed the summary
cards below their content width; they wrapped onto a second line instead.
Measured on a live dashboard, antd laid out five per row at 1280 and 1024,
then four plus one at 900 and three plus two at 820, never narrower than
about 126px. A fixed grid-cols-5 kept all five on one line and compressed
them to 86px at 820, so the metric values overflowed their cards.

An auto-fit track with a 7rem minimum reproduces antd's wrap points and
card widths exactly at all four measured viewports, and is identical at
1280, so the route's visual baseline is unchanged.

The added test fails against grid-cols-5 and passes against the track
2026-08-13 15:57:03 -07:00
Yuneng Jiang
923a49a6f8
test(ui): pin playground behaviour with library-agnostic queries
Rewrite the playground tests that reached for antd class names so they
locate controls by role, text, placeholder or lucide icon instead. Add
characterisation suites for AgentBuilderView and RealtimePlayground,
which had none, including tab state that must survive a round trip
through another tab.

Every assertion here passes against the current antd components.
2026-08-13 15:56:45 -07:00
Yuneng Jiang
5af59f3d53
Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_/brave-hermann-3d77ac 2026-08-13 15:30:24 -07:00
ryan-crabbe-berri
262ed530f8
fix(proxy): honor explicit null budget_duration on team and key create + clearable UI dropdowns (#36699)
* fix(proxy): honor explicit null budget_duration over default_team_params on /team/new

* fix(ui): clearable team budget reset with explicit Never resets option

* docs(proxy): align default_team_params docstrings with actual all-teams scope

* fix(proxy): honor explicit null budget_duration on /key/generate over configured defaults

* fix(proxy): keep upperbound_key_generate_params filling explicitly-null key params

* fix(proxy): restrict explicit-null default opt-out to budget_duration
2026-08-13 15:22:11 -07:00
Yuneng Jiang
355ef22257
refactor(ui): drop narration comments from the migrated usage components 2026-08-13 15:22:03 -07:00
Yuneng Jiang
7c9cd2b3df
refactor(ui): migrate guardrails-monitor to shadcn
Replaces the antd Button, Row, Col, Spin and Typography usage in
GuardrailsOverview with the shadcn button, a CSS grid and the house
loading wrapper, and swaps the ant-design icons for lucide equivalents
that the already-migrated GuardrailDetail sibling uses. The busy state
keeps the aria-busy attribute the antd Spin exposed, so the loading
contract is unchanged for assistive tech.

The route's other analyzer-listed file, GuardrailsMonitorView, keeps its
DateRangePickerValue type import because the shared AdvancedDatePicker
prop contract requires it, so there is nothing to migrate there.

Retires the file's now unused no-restricted-imports suppression
2026-08-13 15:21:54 -07:00
Yuneng Jiang
4beac28ab5
Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_/quizzical-jennings-5df447
# Conflicts:
#	ui/litellm-dashboard/eslint-suppressions.json
2026-08-13 15:06:03 -07:00
Yuneng Jiang
771c36c1ee
refactor(ui): migrate guardrails route to shadcn
Ports the 21 route-owned guardrails components off antd and Tremor onto the
installed shadcn base-vega primitives. Forms, tables and shared components stay
where they are: the route analyzer buckets add_guardrail_form, guardrail_info
and six others as DEFERRED, and eleven components under src/components as
SHARED, so none of them are touched here.

Three behaviours needed explicit handling because Base UI does not match antd by
default. Base UI Tabs mounts only the active panel, so the playground draft and
every panel's local state would reset on a tab switch; TabsContent now carries
keepMounted. ComboboxList takes a function child to render the filtered items,
and mapping over the array instead renders everything and silently disables the
type to filter behaviour antd gave for free. SelectContent gets
alignItemWithTrigger={false} so popups anchor below the trigger the way antd's
did, which also removes a focus race that made the template picker
intermittently unclickable.

The three dialogs reached from inside the still-antd wizard need a layer above
its z-index of 1000 to be visible at all.

Adds three tests rather than editing the characterisation tests from the
previous commit: a guard that every tab panel stays mounted, and one filtering
regression each for the pattern and mode dropdowns.

Prunes the guardrails entries from eslint-suppressions.json.
2026-08-13 15:05:09 -07:00
Yuneng Jiang
2d7581e32e
Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_/compassionate-jones-9c0d5c 2026-08-13 15:02:48 -07:00
Yuneng Jiang
b69177712e
refactor(ui): migrate usage to shadcn
Replaces antd and Tremor markup on the usage route with the installed shadcn
base-vega primitives. Behaviour is unchanged: the route's characterisation
tests were rewritten to role and text queries in the previous commit, proven
green against the antd components, and pass through this commit unedited.

Tremor tab panels stayed mounted once rendered, so every migrated TabsContent
and the collapsible model sections in activity_metrics carry keepMounted to
keep view-mode and expansion state alive across tab switches.
2026-08-13 15:02:40 -07:00
devin-ai-integration[bot]
87736a767c
feat(ui): highlight Auto Router in the navbar announcement (#36315)
* chore(ui): remove Agent Platform announcement bell from navbar

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* feat(ui): highlight Auto Router in the navbar announcement

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix(ui): open Auto Router docs link in a new tab

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* Revert "fix(ui): open Auto Router docs link in a new tab"

This reverts commit 3be861bafe.

* chore(ui): title the navbar announcement LiteLLM Auto Router

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

---------

Co-authored-by: Mubashir Osmani <mubashir@berri.ai>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-08-13 21:57:14 +00:00