Non-admin keys may only start transcription jobs whose media and transcript output live in the S3 buckets listed in general_settings.transcribe_media_buckets, and may not supply DataAccessRoleArn or JobExecutionSettings. The setting is editable from the Admin UI general settings table (new List editor) and DB values load into the running proxy when config.yaml does not set it
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Restrict signed media fetches to https URLs, treat a job AWS no longer knows as
priceable from the media named in its StartTranscriptionJob response instead of
polling to the eight hour maximum, and read the media length with libsndfile
headers instead of decoding the whole file into memory
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Standard jobs are tagged litellm-owner on StartTranscriptionJob so GetTranscriptionJob
and DeleteTranscriptionJob only work for the owner or a proxy admin, and account-wide
operations need a proxy admin. Media rewritten after job creation is charged the eight
hour maximum, and the success handler takes an injected log dispatch instead of tests
patching its private method
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
The Responses id security hook keeps the id a client addressed under
`_litellm_addressed_response_id` in the request body so internal retries can
re-authorize it. On a model without a native Responses config that body is
bridged into `completion()` kwargs, the key was treated as a provider param,
and providers rejected it, so every follow-up turn carrying
`previous_response_id` returned 400.
Register the key in `all_litellm_params` so it is dropped before any provider
request, and share one constant between the hook and the param list.
Forking a shared budget row rebuilt budget_reset_at from the duration, so editing
an unrelated limit restarted the member's window while their spend carried over:
a tpm bump quietly handed them a fresh period. The fork now inherits the source
row's deadline, and only recomputes when the patch actually sets budget_duration.
The bulk member budget route now writes one audit entry per call, a team-scoped
'updated' row carrying every written member's limits before and after, matching
what /team/member_add already records for membership changes. It honors the
litellm-changed-by header like the other audited team routes.
Virtual-hosted URLs for bucket names containing dots fail TLS verification, so the
media duration fetch failed and completed jobs were charged the eight hour maximum
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Log the underlying ImportError server side and send the client only the installed
version, the supported range and the install hint
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Amazon Transcribe bills every second of the media file, silence included, while the
transcript's last end_time stops at the last word, so pricing from the transcript
undercharged. After a job completes, download Media.MediaFileUri from S3 with the
proxy's credentials and read its length with libsndfile. Formats libsndfile cannot
read (mp4, m4a, webm, amr) and custom language models under LanguageIdSettings are
refused before signing. The S3 signature is only sent to hosts in the AWS partition
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
The roster the authorization check reads came from the routed reader, so a
replica lagging behind a team-admin demotion could still grant that caller
member-budget writes. Pin that read to the writer, as the model reconcile does.
A budget_duration the reset job can never schedule from, a non-positive one
that leaves the row permanently due or an unparseable one that blew up mid
batch as a 500, is now a 422 naming the row it came from, with nothing written.
The check is the same one /team/member_update and /budget/new already run,
lifted out of validate_budget_duration so both surfaces share it.