Found while writing the developer docs for #111.
What happens. Every YAML- or admin-defined Word and email template tool calls the synchronous upload_file() inside its offloaded body (docx_tools/dynamic_docx_tools.py, email_tools/dynamic_email_tools.py). upload_file() refuses the LibreChat strategy:
if UPLOAD_STRATEGY == StorageStrategy.LIBRECHAT:
raise RuntimeError("LIBRECHAT strategy requires async upload. Use upload_file_async() instead.")
So on a LibreChat deployment the six built-in tools work and every dynamic template tool fails with ToolError("Error generating document from template <name>: LIBRECHAT strategy requires async upload…").
Why the static tools work. Their handlers in main.py read the user context on the event loop with extract_user_context_from_request() and upload through librechat_integration.upload_and_format_response(), which branches to upload_file_async() for LibreChat.
Fix. In each _register_single_*_template():
- Make the handler read
extract_user_context_from_request() on the event loop before dispatching.
- Split
_sync_impl so it returns the BytesIO and filename instead of uploading.
- Have the async handler call
upload_and_format_response(buffer, ext, filename, user_context, message, add_unique_prefix=payload.get("add_unique_prefix")), which already offloads the sync upload for the other strategies and returns the artifact dict for LibreChat.
- Keep
metrics.record_call/record_error around the whole thing.
The return annotation of the tool changes from str to Union[str, dict], matching the static tools. Add a test in tests/test_librechat_integration.py that registers a template against a fresh FastMCP() with the strategy patched to LibreChat.
Documented as a known limitation in docs/development/dynamic-templates.md and docs/development/architecture.md until fixed.
Found while writing the developer docs for #111.
What happens. Every YAML- or admin-defined Word and email template tool calls the synchronous
upload_file()inside its offloaded body (docx_tools/dynamic_docx_tools.py,email_tools/dynamic_email_tools.py).upload_file()refuses the LibreChat strategy:So on a LibreChat deployment the six built-in tools work and every dynamic template tool fails with
ToolError("Error generating document from template <name>: LIBRECHAT strategy requires async upload…").Why the static tools work. Their handlers in
main.pyread the user context on the event loop withextract_user_context_from_request()and upload throughlibrechat_integration.upload_and_format_response(), which branches toupload_file_async()for LibreChat.Fix. In each
_register_single_*_template():extract_user_context_from_request()on the event loop before dispatching._sync_implso it returns theBytesIOand filename instead of uploading.upload_and_format_response(buffer, ext, filename, user_context, message, add_unique_prefix=payload.get("add_unique_prefix")), which already offloads the sync upload for the other strategies and returns the artifact dict for LibreChat.metrics.record_call/record_erroraround the whole thing.The return annotation of the tool changes from
strtoUnion[str, dict], matching the static tools. Add a test intests/test_librechat_integration.pythat registers a template against a freshFastMCP()with the strategy patched to LibreChat.Documented as a known limitation in
docs/development/dynamic-templates.mdanddocs/development/architecture.mduntil fixed.