Commit graph

42887 commits

Author SHA1 Message Date
Yassin Kortam
55a80add53 feat(skills): self-service skill submission with admin review
Resolves LIT-5465
2026-08-13 13:55:49 -07:00
yuneng-jiang
160548d40b
Merge pull request #36739 from BerriAI/litellm_/quirky-mcnulty-e432c4
refactor(ui): migrate TruncatedValue and OutputCard to shadcn
2026-08-13 13:31:55 -07:00
Mateo Wang
c1310de342
Merge pull request #36763 from BerriAI/litellm_decrease_anys_fable7
refactor: replace Any with precise types across responses, proxy, and llms modules
2026-08-13 13:24:47 -07:00
Yuneng Jiang
9f947a7406
Merge branch 'litellm_internal_staging' into litellm_/quirky-mcnulty-e432c4 2026-08-13 13:23:51 -07:00
yuneng-jiang
faea98ee7e
Merge pull request #36738 from BerriAI/litellm_/eloquent-wu-3ab1d5
refactor(ui): migrate HistoryTree and CollapsibleMessage to shadcn
2026-08-13 13:23:27 -07:00
Yuneng Jiang
2f7602b028
Merge branch 'litellm_internal_staging' into litellm_/eloquent-wu-3ab1d5 2026-08-13 13:16:48 -07:00
yuneng-jiang
c9b543dbfe
Merge pull request #36737 from BerriAI/litellm_/gifted-colden-355244
refactor(ui): migrate SimpleMessageBlock and SimpleToolCallBlock to shadcn
2026-08-13 13:16:22 -07:00
tin-berri
d8fda675cc
feat: pre-adoption shadow eval for the auto-router (blind pairwise judge, derived state) (#36587) 2026-08-13 13:15:45 -07:00
Yuneng Jiang
b71e7a3213
Merge branch 'litellm_internal_staging' into litellm_/gifted-colden-355244 2026-08-13 13:07:51 -07:00
yuneng-jiang
0f5fa38ef2
Merge pull request #36735 from BerriAI/litellm_/interesting-meitner-e88370
refactor(ui): migrate TokenFlow and JsonViewer to shadcn
2026-08-13 13:04:50 -07:00
yuneng-jiang
b8577516d4
Merge branch 'litellm_internal_staging' into litellm_/quirky-mcnulty-e432c4 2026-08-13 12:51:53 -07:00
yuneng-jiang
21dbd3381e
Merge branch 'litellm_internal_staging' into litellm_/eloquent-wu-3ab1d5 2026-08-13 12:51:51 -07:00
yuneng-jiang
229d258664
Merge branch 'litellm_internal_staging' into litellm_/gifted-colden-355244 2026-08-13 12:51:50 -07:00
yuneng-jiang
6f9ee6e28f
Merge branch 'litellm_internal_staging' into litellm_/interesting-meitner-e88370 2026-08-13 12:51:48 -07:00
Anas Khan
7fcca523aa
fix(proxy/batches): stop forwarding custom_llm_provider twice in list and cancel (#32813)
* fix(proxy/batches): stop forwarding custom_llm_provider twice in list and cancel

The model-routing branches of list_batches and cancel_batch passed
custom_llm_provider as an explicit kwarg while also leaving it inside the dict
they splat, so every such call raised "got multiple values for keyword argument
'custom_llm_provider'" and returned a 500.

list_batches SCENARIO 2 called data.update(credentials) but never removed
custom_llm_provider before litellm.alist_batches(custom_llm_provider=..., **data);
it now uses prepare_data_with_credentials, the same helper the create and
retrieve branches already use, which pops it out.

cancel_batch SCENARIO 3 resolved the provider with
`provider or data.pop("custom_llm_provider", None) or ...`, so when the path
param provider was set the pop short-circuited and a body custom_llm_provider
stayed in data and collided with the explicit kwarg. The body value is now
popped unconditionally before the fallback chain, so the path param wins cleanly
and data no longer carries a duplicate.

Both paths already had strict-xfail regression tests documented "remove when
fixed"; those markers are dropped so the tests now guard the fix.

Signed-off-by: Anas Khan <83116240+anxkhn@users.noreply.github.com>

* fix(proxy/files): avoid duplicate custom_llm_provider in list

Signed-off-by: Anas Khan <83116240+anxkhn@users.noreply.github.com>

---------

Signed-off-by: Anas Khan <83116240+anxkhn@users.noreply.github.com>
2026-08-13 12:50:32 -07:00
Mateo Wang
50ae806784
Merge pull request #36733 from BerriAI/litellm_fix_interactions_responses_bridge
fix(interactions): map step and turn history to Responses API roles and content types
2026-08-13 12:35:21 -07:00
tin-berri
5f2986a1f3
feat(complexity_router): calibrate the classifier rubric with worked examples, selectable per router (#36578)
* feat(complexity_router): calibrate the classifier rubric with worked examples

The built-in rubric stated its tier boundaries as prose alone, and prose
calibrated to consumer chat puts "non-trivial code, multi-step technical work"
at the top of the scale. That is the median request in developer and agent
traffic, so ordinary engineering read as top-tier and the router paid for the
most expensive model on it.

Adds calibration examples to the rubric, selected by a new
classifier_llm_config.rubric preset. The agentic preset (now the default)
anchors routine installs, builds, multi-file edits, and standard debugging at
MEDIUM; the chat preset omits those anchors for deployments serving only
conversational traffic. Both share the same tier criteria, the trust-boundary
paragraph, and the context-window closing line, so this moves where the
boundary sits without changing the taxonomy.

Both presets render byte-identical to the strings a prompt sweep scored, and a
test pins that, so the measured accuracy describes what a router sends.

* feat(ui): pick the classifier rubric preset on an auto-router

Adds a Rubric dropdown to the auto-router's classification panel, so the
agentic and chat presets are selectable rather than config-file only. The
prompt editor prefills from the selected preset, since prefilling agentic text
for a router on chat would show examples its classifier never receives.

The picker is disabled while a custom prompt is set, and the payload builder
drops the preset in that case: a custom prompt is the classifier's whole system
role, so the backend rejects the two together. The builder records the default
preset explicitly, so a later change to which preset is default cannot silently
move an existing router.

* fix(complexity_router): mark an unchosen rubric preset with None, not model_fields_set

The mutual-exclusion check read model_fields_set to tell an explicit preset
from the default. That flag does not survive serialization, and this config is
dumped and handed straight back to ComplexityRouter by /auto_router/test_routing,
where a dump re-states every field. So a custom-prompt classifier saved fine and
then failed validation on preview, rejecting on the second pass what it accepted
on the first.

The preset is now optional, with None meaning the default, matching how None
already means the built-in rubric for system_prompt on the same model. The
default lives in one place, DEFAULT_RUBRIC_PRESET, resolved where the prompt is
assembled. The dashboard stops sending a copy of the default it displays, so a
router nobody configured follows the default rather than pinning today's value,
and UI-built routers behave the same as hand-written config.

Regenerates schema.d.ts, which was left stale by an earlier description edit.

* feat(complexity_router): grandfather existing routers onto the uncalibrated rubric

An unset preset now means LEGACY, the rubric exactly as it shipped before
calibration examples existed, so upgrading cannot move the tier decisions or the
bill of a router that is already running. Config-file routers get this for free
since they name no preset, and a stored config that never had one reads the same
way.

New routers still get the calibrated rubric: switching a classifier to LLM
stamps the agentic preset, because a classifier being configured for the first
time has no prior tier behaviour to preserve. The picker offers legacy so an
existing router's state is representable and opening the form cannot silently
upgrade it.

Each preset is pinned byte-identical to the text the prompt sweep scored,
legacy included, which is what proves an existing router's prompt did not move.

Also collapses the preset data from a NamedTuple with group wrappers and
per-preset frozensets into plain text blocks in a MappingProxyType, matching how
the tier criteria next to it are already stored: 21 lines of prompt text no
longer cost 190 lines of constructors. Tiers are format placeholders so
tier_labels still reach the examples.

* refactor(complexity_router): name the field classification_rubric

`rubric` alone did not say what it selects, and the field sits beside
`system_prompt`, which genuinely is the whole classification prompt. The name
now says which of the two an operator is reaching for: the rubric the built-in
prompt is assembled from, not the prompt itself.

Renames the config field, the query param, the enum, and the dashboard label to
match, and moves the preset text to classification_rubrics.py.

* test(ui): set the preset the mutual-exclusion case is meant to drop

The rename left classification_classification_rubric in the custom-prompt case,
so its input never carried a preset and the assertion held for the wrong reason:
it proved an absent preset stays absent, not that a set one is dropped. A
normalizer that forwards the preset whenever one is set passed with the typo and
fails without it.

tsc reports the typo as TS2353; the earlier sweep grepped for the source file
and not the test, so it went unseen.

* test(ui): scope the role-gate assertions to each page's own endpoint

The memory, workflows, and guardrails-monitor page tests asserted that a denied
role fires no request at all. Their names, and the assertion on the very next
line, say the intent is narrower: the page must not fetch its own data.

Resolving whether a caller is an org admin goes through /organization/list for
every role, since deciding org-admin-for-any-org needs the list, and the route
scopes rows per caller. That legitimate request fails a blanket no-fetch
assertion, so all three files went red on staging for a reason unrelated to
what they test.

Drops the blanket assertion and keeps the scoped one. Bypassing the gate in
memory/page.tsx still fails five tests, so the narrower assertion continues to
catch a genuinely broken gate.

* fix(complexity_router): document that an unset rubric keeps the legacy prompt

The field said 'Leave unset for agentic' while an omitted rubric resolves to
LEGACY, so the OpenAPI schema an operator reads promised calibrated routing
where they got the uncalibrated one.

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 12:22:20 -07:00
tin-berri
add095b494
Fix: ComplexityRouter should not score system prompt text for code/technical complexity (#36721)
System prompts (harnesses, tools, framework boilerplate) are session-wide
constants identical across all requests. Scoring them saturates keyword-match
signals and produces false-positive high-complexity classifications on
trivial utterances like 'hi', routing them to expensive models (sonnet/opus)
instead of tier-1 haiku. A real ~1.6KB CLI-agent harness alone supplied
5 codePresence + 2 technicalTerms matches, overshadowing user signal.

Rescope four scoring dimensions (codePresence, technicalTerms, simpleIndicators,
multiStepPatterns) from full_text (system + user) to user_text (user only).
reasoningMarkers was already scoped this way. This returns 0.63 of the weight
budget to text that actually varies per-request.

Now that every dimension scores user_text only, _score_keyword_match's
disclosable_text param is redundant -- it existed solely to let the signal
name terms matched in the caller's own message while withholding terms
matched only in the (invisible-to-the-caller) system prompt. With no more
system-prompt text in scope, text and disclosable_text were identical at
every call site, so the param is dropped and the function collapses to a
single text argument.

Add mutation-proven regression test: trivial 'hi' message with realistic
Claude Code agent system prompt now routes to haiku tier-1 (not sonnet).

- Unfixed: haiku -> sonnet (bug)
- Fixed: haiku -> haiku (correct)

Invert three pre-existing assertions in TestSignalsNeverQuoteTheSystemPrompt
to capture the corrected behavior: system-prompt-only terms produce no signal.

Co-authored-by: Claude <noreply@anthropic.com>
2026-08-13 11:15:14 -07:00
yuneng-jiang
9f3b1dfec5
Merge pull request #36787 from BerriAI/litellm_osv_nanoid_3_3_18
build(deps): bump nanoid to 3.3.18 to clear osv-scan
2026-08-13 11:09:35 -07:00
Mateo Wang
0a73e0f8d9
Merge pull request #36792 from BerriAI/litellm_gemini_3_7_flash
feat(gemini): day-0 pricing for gemini-3.7-flash
2026-08-13 10:28:16 -07:00
mateo-berri
d9020795dd test: use _local_model_cost_map fixture in gemini 3.7 flash pricing tests 2026-08-13 10:13:40 -07:00
mateo-berri
d3d259b211 feat(gemini): day-0 pricing for gemini-3.7-flash 2026-08-13 09:49:55 -07:00
Devin AI
630a1d0b69 build(deps): bump nanoid to 3.3.18 to clear osv-scan
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-08-13 16:38:24 +00:00
yuneng-jiang
9d069f21dc
refactor(ui): migrate guardrails content tables to shared DataTable (#36708)
* test(ui): characterize guardrails content tables

* refactor(ui): migrate guardrails content tables to shared DataTable

* test(ui): verify shared guardrails table integration
2026-08-13 09:21:00 -07:00
yuneng-jiang
b8241d6664
refactor(ui): migrate guardrails monitor table to shared DataTable (#36709)
* test(ui): characterize guardrails monitor table

* refactor(ui): migrate guardrails monitor table to shared DataTable
2026-08-13 09:20:48 -07:00
yuneng-jiang
bfa34e2b10
refactor(ui): migrate usage tables to shared DataTable (#36707)
* test(ui): decouple usage table test from antd

* refactor(ui): migrate usage tables to shared DataTable

* test(ui): preserve data utility exports in usage tests
2026-08-13 09:20:45 -07:00
mateo-berri
08ae8648e0 fix: restore tolerant auth attribute access in compact summary checks
The summary model access and budget checks read team_id, user_id,
project_id, and end_user_id via getattr with a None default so duck-typed
auth objects without those attributes keep working
2026-08-13 08:24:23 -07:00
mateo-berri
6b5249bcce refactor: replace Any with precise types across responses, proxy, and llms modules
Types 28 files with Protocols, TypedDicts, and Pydantic validation in place
of Any, cutting basedpyright reportAny by 974 and reportExplicitAny by 261
(1411 errors total across 48 rules), and ratchets the basedpyright, ruff
strict, and type discipline budgets down to match
2026-08-13 03:59:26 -07:00
yucheng-berri
09889e1986
fix(langfuse): coerce header-sourced mask and trace-update steering values (#36740)
langfuse_* request headers land in metadata as strings, but the trace path reads
mask_input/mask_output with a bare truthiness check and iterates update_trace_keys
directly. A header saying mask_input: false redacted the payload it was asked to
keep, and update_trace_keys was walked one character at a time so every requested
key silently failed to match
2026-08-13 00:44:26 -07:00
yuneng-jiang
a7397b2459
fix(helm): render nodeSelector on the migrations job (#36747)
The template rendered affinity and tolerations but never nodeSelector, so a
values file that pinned the chart to a node pool got the gateway and every
subchart placed correctly while the migration Job silently fell through to
whatever the cluster's default pool was.

That is worse than an outright failure. On EKS Auto Mode the default pool hands
out 3 GiB nodes and the migration container needs roughly 3.6 GB, so the Job
was OOM-killed on a pool it was never meant to run on, while the values file
that would have placed it on a large enough node looked correct.

The new test fails against the old template with "unknown path
spec.template.spec.nodeSelector".
2026-08-13 00:41:36 -07:00
yucheng-berri
6f84c468d4
fix(guardrails): scan and re-emit raw Anthropic SSE streams in the bedrock post-call hook (#36598)
* fix(guardrails): scan and re-emit raw Anthropic SSE streams in the bedrock post-call hook

* fix(guardrails): keep upstream id and model on a blocked Anthropic stream

* fix(guardrails): deliver a blocked Anthropic stream as an error frame

* fix(guardrails): deliver an unscannable Anthropic stream as an error frame

* fix(guardrails): emit the guardrail block detail as JSON in the stream error frame

* fix(guardrails): deliver an Anthropic block through the shared block-SSE builder

* fix(guardrails): keep the shared SSE assembler behavior-identical for existing callers

* fix(guardrails): keep the stream error message a string and drop an unreachable branch

* chore(guardrails): drop a comment that repeated its own docstring

* fix(guardrails): let bedrock service failures keep their status instead of framing them as blocks

* fix(guardrails): key the streamed block decision on status, not detail shape

InvokeGuardrailChecks details a Mapping on its 500 for an unparseable response,
so a detail-shape test read that outage as a policy block and framed it as a 200
guardrail_error. Both block sites raise 400, so gate on the status too.

* refactor(guardrails): narrow the SSE error-frame helper to the input it actually takes

Both callers pass a string, so the Mapping overload and its json.dumps branch
were unreachable. Folds the block branch's narrative comment into the rebind
suppressions that already carry a reason.
2026-08-13 07:23:49 +00:00
yuneng-jiang
3d76dfc72e
refactor(ui): migrate search and user controls to shadcn (#36694)
* test(ui): characterize shared migration surfaces

* refactor(ui): migrate search and user controls

* fix(ui): restore search tool clear action
2026-08-13 06:43:30 +00:00
yuneng-jiang
fd00b98f64
refactor(ui): migrate guardrails-monitor, projects, logs to shadcn (#34606)
* test(ui): pin behaviour of guardrails-monitor, projects and logs components before migration

Adds role- and text-based characterisation tests for EvaluationSettingsModal,
GuardrailDetail and AuditLogDrawer, which had none, and moves the remaining
antd-specific assertions (.ant-spin, the icon role of an antd Spin indicator)
onto library-neutral ARIA queries. Also covers the enterprise banner on the
deleted keys and deleted teams pages, which no test reached.

All of these pass against the current antd and Tremor components.

* refactor(ui): migrate guardrails-monitor, projects and logs to shadcn

Replaces antd and Tremor with installed shadcn primitives across the files
these three routes exclusively own. Markup only, except where noted below.

Deletes AntDLoadingSpinner, an antd-only primitive living in the shadcn ui/
folder, and moves its single call site onto ui/ui-loading-spinner.

Two behaviour notes. The logs tab handler previously mapped every tab past
the first to "audit logs", so the audit panel kept polling while Deleted
Keys or Deleted Teams was on screen; each tab now reports its own value and
panels stay mounted via keepMounted. The evaluation settings dialog is
bounded to the viewport and scrolls internally, which the antd Modal got
from being top-anchored on a scrolling page.

The tests added in the previous commit pass unedited against these
components.
2026-08-13 06:43:12 +00:00
yuneng-jiang
4df421e058
refactor(ui): migrate guardrail and duration controls to shadcn (#36693)
* test(ui): characterize shared migration surfaces

* refactor(ui): migrate guardrail and duration controls

* fix(ui): preserve duration select callback shape

* fix(ui): narrow duration selection value
2026-08-13 06:42:42 +00:00
yuneng-jiang
e619106306
refactor(ui): migrate team detail controls to shadcn (#36695)
* test(ui): characterize shared migration surfaces

* refactor(ui): migrate team detail controls
2026-08-13 06:41:28 +00:00
Mateo Wang
73e555a3e3
test(interactions): follow Google spec drift replacing Turn with typed steps (#36730)
* test(interactions): follow Google spec drift replacing Turn with typed steps

* test(interactions): send step and content-list input to the live Gemini API
2026-08-12 23:32:57 -07:00
Yuneng Jiang
266a35b88c
test(ui): cover keyboard activation of the log drawer collapse rows
The migration turned each collapse row into a real button, but the existing
tests only click, so a regression in Enter or Space activation would still
pass. Add one test per component that tabs to the row, expands with Enter and
collapses with Space, asserting visibility rather than markup.

Both fail against the antd version and pass against the migrated one.
2026-08-12 22:39:29 -07:00
Yuneng Jiang
f17143086a
refactor(ui): migrate TruncatedValue and OutputCard to shadcn
TruncatedValue swaps antd Tooltip and Typography for the shadcn Tooltip
and the shared CopyButton, so the full value now lives in the page and is
clipped with CSS rather than shortened in the text node.

OutputCard drops antd Typography for token-styled markup and folds its two
duplicated branches into one. Its border and the drawer's mono font stay on
the module's existing constants so the card still matches InputCard, which
is out of scope here.

Both files retire their no-restricted-imports suppression.
2026-08-12 22:29:57 -07:00
Yuneng Jiang
9355953414
refactor(ui): migrate SimpleMessageBlock and SimpleToolCallBlock to shadcn
Replace antd Typography and inline hex styling in the log drawer's message
and tool-call blocks with plain elements and design tokens. Both components'
existing tests pass unedited before and after.

Retires their no-restricted-imports entries from the eslint suppressions
baseline.
2026-08-12 22:27:20 -07:00
Yuneng Jiang
c25f927f03
test(ui): make the TokenFlow grouping assertion locale-independent
The assertion hard-coded en-US separators while toLocaleString follows the
host locale, so it failed under de_DE. Building the expected string the same
way keeps it deterministic everywhere and still catches a dropped
toLocaleString wherever the locale groups at all.
2026-08-12 22:23:06 -07:00
Yuneng Jiang
214a476c3e
refactor(ui): migrate TokenFlow and JsonViewer to shadcn
Drops the antd Typography import from both. TokenFlow renders inside an antd
Descriptions.Item that already sets the colour, font size, line height and
wrapping the Text wrapper restated, so a bare span is pixel-identical there.
JsonViewer's placeholder moves onto the muted-foreground token.

The characterisation tests from the previous commit are unchanged and stay
green, which is what shows the markup swap did not move behaviour.
2026-08-12 22:10:39 -07:00
mateo-berri
2a3b54394f refactor(interactions): drop Any and extra casts from bridge input helpers 2026-08-12 22:03:33 -07:00
Yuneng Jiang
49c697ee89
refactor(ui): migrate HistoryTree and CollapsibleMessage to shadcn
Both log-drawer collapse rows hand-rolled the same pattern: a click
handler on a plain div, hover tracked in React state, and a max-height
tween on an always-mounted panel. Move both onto the ui/collapsible
primitive with lucide chevrons, so the row is a real button that keyboard
users can reach and the open state lives in the primitive.

CollapsibleContent keeps keepMounted, which preserves the existing
contract that panel content stays in the DOM while collapsed.

Neither test file is touched: both were already role and text based, and
they pass unedited against the new markup.
2026-08-12 22:03:20 -07:00
Yuneng Jiang
89d5037780
test(ui): characterize TokenFlow and JsonViewer
Both components are shared by the logs, guardrails-monitor and tool-policies
routes and had no test. These assert on rendered text and roles only, so they
hold against antd Typography and against its replacement.
2026-08-12 21:48:51 -07:00
mateo-berri
432ea8644b test(interactions): send step and content-list input to the live Gemini API 2026-08-12 21:47:33 -07:00
mateo-berri
0aeed16125 test(interactions): follow Google spec drift replacing Turn with typed steps 2026-08-12 21:47:33 -07:00
mateo-berri
3e94f7d71e fix(interactions): map step and turn input to Responses API roles and content types 2026-08-12 21:47:00 -07:00
yucheng-berri
d86336a7c6
fix(langfuse): emit otel trace version and release on the keys langfuse v4 reads (#36702)
* fix(langfuse): emit otel trace version and release on the keys langfuse v4 reads

The langfuse_otel exporter wrote version to langfuse.generation.version and
langfuse.trace.version, and release to langfuse.trace.release. Langfuse v4
recognizes neither, so both landed in the generic span attribute bag and every
trace reported version and release as null. v4 has a single langfuse.version
key, lifted to the trace when it sits on the root span, plus langfuse.release.

Also routes the otel v2 preset's per-request headers through the shared builder
so key-scoped and team-scoped exports carry x-langfuse-ingestion-version like
the other three exporter paths already do.

* fix(langfuse): give trace_version precedence over version on the shared v4 key

Matches the documented contract in docs/observability/langfuse_integration.md
and the legacy langfuse SDK callback, which both treat trace_version as the
authoritative trace version with version as its fallback.
2026-08-12 20:39:58 -07:00
Mateo Wang
c7f5527870
Merge pull request #36726 from BerriAI/litellm_claude_md_remove_at_prefix
docs(claude): drop the @ prefix from the PR template path
2026-08-12 20:31:59 -07:00
mateo
de4765ae88 docs(claude): drop the @ prefix from the PR template path
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-08-13 03:20:15 +00:00