* fix(containers): record ownership for service-account keys + fix Prisma Json field serialization
- Track containers created implicitly via /v1/responses by extracting container IDs
from the response output and calling record_container_owner for each one, so
subsequent file-API calls from the same service account pass ownership checks.
- Fix DataError: Prisma Python requires Json fields to be JSON strings; serialize
file_object with json.dumps() before insert/update in LiteLLM_ManagedObjectTable.
- Add collect_container_ids_from_responses_response utility to responses/utils.py
that walks all output item shapes (code_interpreter_call, message annotations).
- Tests: two new cases covering the responses-tracking path and the end-to-end
record-then-assert flow for service accounts with team scope.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(containers): swallow all exceptions in ownership hook; tighten file_object_json type to str
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(containers): parse file_object JSON string in existing ownership test
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix: container ownership recording bugs
- Remove unreachable _aresponses_websocket from route_type set in
base_process_llm_request; the WebSocket endpoint never flows through
base_process_llm_request, so this branch was dead code that gave a
false impression of coverage.
- Drop the HTTPException re-raise in record_container_owners_from_responses_response
so per-container failures (including HTTP 403/500 from conflicting
ownership rows) no longer abort the batch and skip recording for the
remaining container IDs in the same response.
Co-authored-by: Yassin Kortam <yassin@berri.ai>
* fix(containers): record ownership for streaming /v1/responses too
Streaming /v1/responses returns through the select_data_generator
branch in base_process_llm_request and bypasses the non-streaming
ownership tail, so code-interpreter containers created mid-stream
were never written to LiteLLM_ManagedObjectTable. Follow-up file API
calls would then 403.
Wrap the SSE generator so container ownership is recorded once the
upstream iterator finishes assembling completed_response. Also covers
the background-polling path, which loops body_iterator end-to-end.
Co-authored-by: Yassin Kortam <yassin@berri.ai>
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Yassin Kortam <yassin@berri.ai>