fix(batches): keep deployment credentials out of callback-visible params

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
shivam 2026-09-17 23:31:18 +00:00
parent 890802326a
commit 8aca0c37fd
3 changed files with 8 additions and 3 deletions

View file

@ -856,7 +856,6 @@ class CheckBatchCost:
}
},
**({"api_base": mask_api_base_credentials(deployment_api_base)} if deployment_api_base else {}),
"_litellm_internal_model_credentials": MappingProxyType({**credentials}),
"metadata": {
**(await self._build_creator_attribution_metadata(job, batch_id)),
# spend logs read the deployment identity off these metadata keys, so
@ -868,6 +867,11 @@ class CheckBatchCost:
optional_params={},
custom_llm_provider=str(llm_provider) if llm_provider else None,
)
# deployment credentials stay off litellm_params because every callback sees those; the
# line-item logger reads them back off this private attribute to fetch the batch files
setattr( # noqa: B010 # Logging has no declared attribute for trusted credentials transport
logging_obj, "_litellm_internal_model_credentials", MappingProxyType(dict(credentials))
)
if not await self._claim_job_for_costing(job):
verbose_proxy_logger.info(

View file

@ -299,7 +299,7 @@ async def log_batch_line_items(
is logged and swallowed: aggregate accounting must be unaffected."""
emitted = 0 # rebind-ok: loop accumulator for emitted line count
try:
internal_credentials: Final = (
internal_credentials: Final = getattr(parent, "_litellm_internal_model_credentials", None) or (
litellm_params.get("_litellm_internal_model_credentials") if litellm_params else None
)
internal_mapping: Final = _as_object_mapping(internal_credentials)

View file

@ -414,9 +414,9 @@ async def test_line_items_edge_shapes_and_edge_cases(recorder):
parent: Final = _parent_logging_with_params(
{
"metadata": {"model_info": {"id": "dep-1"}, "model_group": "gpt-4o"},
"_litellm_internal_model_credentials": {"api_key": "sk-line-items-marker"},
}
)
parent._litellm_internal_model_credentials = {"api_key": "sk-line-items-marker"} # test-quality-ok: private transport attribute, same channel the batch cost tracker uses
with (
patch("litellm.files.main.afile_content", file_mock), # test-quality-ok: afile_content is the provider boundary; no injection seam for managed file fetch
patch("litellm.cost_calculator.batch_cost_calculator", return_value=(0.01, 0.02)), # test-quality-ok: the pricing table boundary, same seam existing batch_utils tests patch
@ -446,6 +446,7 @@ async def test_line_items_edge_shapes_and_edge_cases(recorder):
assert "no status here" in _payload(failure)["error_str"]
assert "sk-line-items-marker" in str(file_mock.call_args_list)
assert "sk-line-items-marker" not in str(by_custom_id["e"]["litellm_params"])
file_ids_fetched = [call.kwargs.get("file_id") or call.args[0] for call in file_mock.call_args_list]
assert "input-2" in file_ids_fetched and "output-2" in file_ids_fetched
assert not any(file_id is None for file_id in file_ids_fetched)