{% from "_macros.html" import icon %} {# The composer, used both inside an existing chat and on /chat where no chat row exists yet. The only difference is where it posts. With a chat, the turn is appended to the thread in place; without one, /api/chats/start creates the chat and redirects, and the reply streams on arrival because the page renders the unfinished assistant message with its sse-connect. That is what stops an opened-and-abandoned chat ever being written to the database. The attachment chips live INSIDE this form on purpose. Each carries a hidden file_ids input, and being inside the form is what gets them serialised with the message. Keeping them outside and reaching for hx-include does not work: that attribute only has an effect on the element issuing the request. Layout: chips, then the text, then one toolbar row underneath carrying everything that acts on the message. The kind selector and the connection used to sit in a strip *above* the text, inside the same bordered card, where they read as debris floating in the input rather than as controls. Below the text they are in the same place as attach and send, which is where the hand already is. #}
Enter to send, Shift+Enter for a new line. {% if can.get("files.upload") %} Drag files in, or paste an image. {% if current_model and not current_model.capabilities_json.get("vision") %} {{ current_model.label }} has no vision, so images will not be sent — documents still will. {% endif %} {% endif %}