feat(upload): support Excel and Word file attachments — v0.50.61

Squash-merges PR #571 (rebased from contributor PR #566 by @renheqiang). Adds .xls/.xlsx/.doc/.docx to the file picker and MIME map. 1319 tests pass.
This commit is contained in:
nesquena-hermes
2026-04-15 22:43:31 -07:00
committed by GitHub
parent e4fec9e4e0
commit 360379136b
3 changed files with 12 additions and 2 deletions

View File

@@ -1,5 +1,10 @@
# Hermes Web UI -- Changelog # Hermes Web UI -- Changelog
## [v0.50.61] — 2026-04-16
### Added
- **Office file attachments** — `.xls`, `.xlsx`, `.doc`, and `.docx` files can now be selected via the attach button. The file picker's `accept` attribute is extended to include Office MIME types, and the backend MIME map is updated so these files are served with correct content-type headers when accessed through the workspace file browser. Files are saved as binary to the workspace; the AI can reference them by name the same way it does PDFs. (PR #566 by @renheqiang)
## [v0.50.60] — 2026-04-16 ## [v0.50.60] — 2026-04-16
### Changed ### Changed

View File

@@ -342,6 +342,7 @@ MAX_UPLOAD_BYTES = 20 * 1024 * 1024
# ── File type maps ─────────────────────────────────────────────────────────── # ── File type maps ───────────────────────────────────────────────────────────
IMAGE_EXTS = {".png", ".jpg", ".jpeg", ".gif", ".svg", ".webp", ".ico", ".bmp"} IMAGE_EXTS = {".png", ".jpg", ".jpeg", ".gif", ".svg", ".webp", ".ico", ".bmp"}
MD_EXTS = {".md", ".markdown", ".mdown"} MD_EXTS = {".md", ".markdown", ".mdown"}
OFFICE_EXTS = {".xls", ".xlsx", ".doc", ".docx"}
CODE_EXTS = { CODE_EXTS = {
".py", ".py",
".js", ".js",
@@ -380,6 +381,10 @@ MIME_MAP = {
".bmp": "image/bmp", ".bmp": "image/bmp",
".pdf": "application/pdf", ".pdf": "application/pdf",
".json": "application/json", ".json": "application/json",
".xls": "application/vnd.ms-excel",
".xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
".doc": "application/msword",
".docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
} }
# ── Toolsets (from config.yaml or hardcoded default) ───────────────────────── # ── Toolsets (from config.yaml or hardcoded default) ─────────────────────────

View File

@@ -274,7 +274,7 @@
<textarea id="msg" rows="1" placeholder="Message Hermes…"></textarea> <textarea id="msg" rows="1" placeholder="Message Hermes…"></textarea>
<div class="composer-footer"> <div class="composer-footer">
<div class="composer-left"> <div class="composer-left">
<input type="file" id="fileInput" multiple accept="image/*,text/*,application/pdf,application/json,.md,.py,.js,.ts,.yaml,.yml,.toml,.csv,.sh,.txt,.log,.env" style="display:none"> <input type="file" id="fileInput" multiple accept="image/*,text/*,application/pdf,application/json,application/vnd.ms-excel,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document,.md,.py,.js,.ts,.yaml,.yml,.toml,.csv,.sh,.txt,.log,.env,.xls,.xlsx,.doc,.docx" style="display:none">
<button class="icon-btn" id="btnAttach" title="Attach files"> <button class="icon-btn" id="btnAttach" title="Attach files">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21.44 11.05l-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48"/></svg> <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21.44 11.05l-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48"/></svg>
</button> </button>
@@ -553,7 +553,7 @@
<div class="settings-section-title">System</div> <div class="settings-section-title">System</div>
<div class="settings-section-meta">Instance version and access controls.</div> <div class="settings-section-meta">Instance version and access controls.</div>
</div> </div>
<span class="settings-version-badge">v0.50.60</span> <span class="settings-version-badge">v0.50.61</span>
</div> </div>
<div class="settings-field" style="border-top:1px solid var(--border);padding-top:12px;margin-top:8px"> <div class="settings-field" style="border-top:1px solid var(--border);padding-top:12px;margin-top:8px">
<label for="settingsPassword" data-i18n="settings_label_password">Access Password</label> <label for="settingsPassword" data-i18n="settings_label_password">Access Password</label>