Repository navigation
runner: session-scoped upload route with session-end cleanup - #5830
Conversation
|
Just going to leave all feedback here rather than strewn throughout the PR stack, if you don't mind. |
|
On the client: looks like |
|
On the client: is If so:
|
|
Re
|
|
Overall, this looks really neat! I mean "neat" in both senses of the word—cool, and tidy. |
f0f1aa0 to
59e0831
Compare
Codecov Report❌ Patch coverage is
🚀 New features to boost your workflow:
|
This triggered a pretty major update to how files get resolved. See this commit. Caching now lives in the For your first point, resolution and conversion are now fused into a single |
59e0831 to
2f79467
Compare
2f79467 to
5c90031
Compare
This is holdover. I removed the ID option from pipecat but hadn't updated the client yet.
I re-worked the way we set the upload endpoint and really |
5c90031 to
d0a2077
Compare
|
Thanks for the fixes! Will go ahead and approve all individual PRs related to this project. |
| # Where to POST file uploads for this session, when uploads are | ||
| # enabled. A path relative to the /start endpoint's origin (or an | ||
| # absolute URL from backends that know theirs). Omitted when uploads | ||
| # are disabled. | ||
| fileUploadUrl: str |
There was a problem hiding this comment.
Is this something we will need to implement inside PCC as well, or will the client try to fall back to a URL that just works there ? Like this one:
/sessions/{session_id}/files
There was a problem hiding this comment.
it would be something we need to implement in PCC.
| "format": media_type, | ||
| } | ||
|
|
||
| @app.post("/sessions/{session_id}/files") |
There was a problem hiding this comment.
Are we also going to create routes to allow retrieving or deleting a file ? Do we need it ?
There was a problem hiding this comment.
it's not needed for this feature, no.
| raise HTTPException(404, "Invalid or not-yet-ready session_id") | ||
| return await handle_upload(file, session_id) | ||
|
|
||
| @app.post("/files") |
There was a problem hiding this comment.
I might be missing something, but I am not totally sure why we still need this one. What would be a case where we wouldn't have a session ?
There was a problem hiding this comment.
looks like the main reason it's there is for websocket.
Its /start returns a sessionId that's never registered with the runner — the bot mints its own session id when the client connects to /ws-client — so the session-scoped route would reject those clients with a 404. /start only advertises the flat route for that transport; everything else gets /sessions/{id}/files. If we later fix the websocket session-id mismatch (it predates this PR), the flat route can go away.
There was a problem hiding this comment.
Even for the WebSocket, in theory they should have invoked /start first, which would return a session ID. So, if they are using our Web SDK, that should just work.
I think we could accept the limitation that file uploads would not work unless they have created a session first. So they would need to invoke /start in order to be able to upload a file, and we could remove this /files endpoint.
There was a problem hiding this comment.
i'd like to do this as a separate PR. claude is claiming it has to fix pre-existing issues in order to remove /files and not break websocket. I don't fully follow, but I don't want this to hold up merging this feature.
There was a problem hiding this comment.
Yep, let's do that in a different PR. 👍
filipi87
left a comment
There was a problem hiding this comment.
With this approach, it should already be possible to make it work both locally and on Pipecat Cloud. 🙇
Nice feature, @mattieruth. Approved all the PRs. 🚀
cf4c770 to
9744052
Compare
Add POST /sessions/{session_id}/files, mirroring Pipecat Cloud's
session-scoped routes; it validates the session against the active
session store and tracks each upload so the session's files are deleted
when its bot session ends. The flat POST /files remains for transports
whose clients never learn a session id (the websocket flow returns a
sessionId from /start but the bot mints a different one at connect
time); files uploaded there are only removed by the storage backend's
own retention. The uploads routes are registered before the WebRTC
routes so they win over the catch-all /sessions/{session_id}/{path:path}
proxy, which matches later in registration order.
Bot sessions started from the /start flows (daily, livekit, moq) and
from the WebRTC offer now run through _run_bot_session, which on
completion removes the session from the active session store — fixing
entries never being released — and best-effort deletes its uploads.
The daily, livekit, and moq flows now register their sessions in the
store in the first place; previously only webrtc did, so their session
routes always 404ed.
LocalFileStorage.delete ignores an already-missing file: an upload
consumed by delete_after_load is deleted again by session-end cleanup.
…the client to use
Replace set_runner_file_storage()/runner_file_storage() — module globals only the development runner's main() honored — with a host-agnostic convention: the bot module optionally defines create_file_storage() -> FileStorage | None alongside bot(), and whichever host runs the bot discovers it, serves its upload endpoints from the returned backend, and injects it into the bot as runner_args.file_storage. A defined factory wins over -u/--uploads-folder; without one the flag backs uploads with local disk. This keeps bot code identical whether the development runner or a cloud platform's base image hosts it.
9744052 to
491e742
Compare
|
Docs automation failed for this PR — its documentation is missing. The Re-run it once the cause is addressed: If this PR genuinely needs no documentation, remove the |

Part 4 of File Support work
Part 1
Part 2
Part 3
Part 4
Corresponding Client-JS changes
New File Input Example
Add POST /sessions/{session_id}/files, mirroring Pipecat Cloud's session-scoped routes; it validates the session against the active session store and tracks each upload so the session's files are deleted when its bot session ends. The flat POST /files remains for transports whose clients never learn a session id (the websocket flow returns a sessionId from /start but the bot mints a different one at connect time); files uploaded there are only removed by the storage backend's own retention. The uploads routes are registered before the WebRTC routes so they win over the catch-all /sessions/{session_id}/{path:path} proxy, which matches later in registration order.
Bot sessions started from the /start flows (daily, livekit, moq) and from the WebRTC offer now run through _run_bot_session, which on completion removes the session from the active session store — fixing entries never being released — and best-effort deletes its uploads. The daily, livekit, and moq flows now register their sessions in the store in the first place; previously only webrtc did, so their session routes always 404ed.
LocalFileStorage.delete ignores an already-missing file: an upload consumed by delete_after_load is deleted again by session-end cleanup.