Skip to content

fix(gateway): translate inbound cache paths to container paths for Docker backend - #19610

Closed
pvdb2178 wants to merge 1 commit into
NousResearch:mainfrom
pvdb2178:fix/inbound-doc-path-translation
Closed

fix(gateway): translate inbound cache paths to container paths for Docker backend#19610
pvdb2178 wants to merge 1 commit into
NousResearch:mainfrom
pvdb2178:fix/inbound-doc-path-translation

Conversation

@pvdb2178

@pvdb2178 pvdb2178 commented May 4, 2026

Copy link
Copy Markdown

What does this PR do?

When terminal.backend: docker, inbound documents (.docx/.pdf/etc.) from messaging platforms are saved at host paths under ~/.hermes/cache/documents/ and _prepare_inbound_message_text injects those raw host paths into the agent's prompt:

[The user sent a document: 'report.docx'. The file is saved at: /home/hermes/.hermes/cache/documents/abc_123_report.docx. ...]

The agent runs inside the Docker container where that host path doesn't exist; the cache directories are bind-mounted at /root/.hermes/cache/documents/ via get_cache_directory_mounts() (added in #4846), but the path translation step was missing — so reads of user-sent docs fail.

This adds to_agent_visible_cache_path() in tools/credential_files.py next to get_cache_directory_mounts, and calls it at the two doc-injection sites in gateway/run.py. Pass-through for non-Docker backends keeps existing behavior unchanged. Mirrors the pattern from #14990 (vision sandbox path resolution).

Out of scope (intentionally, to keep the diff focused):

  • Audio: _enrich_message_with_transcription injects the transcript text, not the file path.
  • Native-vision images: attached as multimodal content blocks, not text-injected paths.
  • Modal / Daytona / Vercel: different mount semantics (per-file upload, etc.). The helper signature accepts a backend arg so they can opt in later if needed.

Related Issue

Fixes #18787

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)

Changes Made

  • tools/credential_files.py: add to_agent_visible_cache_path(host_path, *, backend, container_base='/root/.hermes') that maps host cache paths to their container-side mount points by walking _CACHE_DIRS. Idempotent (already-translated paths pass through). Gated on backend == "docker" (case/space-insensitive).
  • gateway/run.py: call the helper inside the event.message_type == MessageType.DOCUMENT block before injecting the path into both the text-document and binary-document context notes. Backend resolved once via os.getenv("TERMINAL_ENV", "local").
  • tests/tools/test_credential_files.py: add TestToAgentVisibleCachePath (9 tests) — translation for each cache subdir, nested subpaths, non-docker pass-through, paths outside cache, idempotence, case/space-insensitive backend, custom container_base, empty input.
  • website/docs/user-guide/docker.md: brief note in "Skills and credential files" about the cache bind-mount and path rewrite, where the analogous skills/credential-file mount behavior is already documented.

How to Test

Repro (before fix):

  1. Configure terminal.backend: docker and run the gateway.
  2. Send a .docx or .pdf to the bot from Telegram (or any messaging platform with document support).
  3. Ask the agent to read or summarise the file.
  4. The agent calls read_file / terminal cat with the host path it was given (e.g. /home/<user>/.hermes/cache/documents/...) and gets No such file or directory from inside the container.

After fix:

  1. Same flow.
  2. The agent receives the container-visible path (/root/.hermes/cache/documents/...), which is the bind-mount target, and the read succeeds.

Unit-test verification:

pytest tests/tools/test_credential_files.py -v

All 38 tests pass (9 new + 29 existing). Re-ran tests/tools/ and tests/gateway/ for regression — no new failures from this change. There are 14 pre-existing failures in unrelated platform adapters (dingtalk/feishu/teams/whatsapp) that fail on main without this patch as well.

Checklist

Code

  • I've read the Contributing Guide
  • My commit messages follow Conventional Commits (fix(scope):, feat(scope):, etc.)
  • I searched for existing PRs to make sure this isn't a duplicate
  • My PR contains only changes related to this fix/feature (no unrelated commits)
  • I've added tests for my changes (required for bug fixes, strongly encouraged for features)
  • I've tested on my platform: macOS 15.4 (Darwin 25.4)
  • I've run pytest tests/ -q and all tests pass — partial: ran tests/tools/ and tests/gateway/ (4322 passed, 14 unrelated pre-existing failures in dingtalk/feishu/teams/whatsapp, confirmed on clean main).

Documentation & Housekeeping

  • I've updated relevant documentation (website/docs/user-guide/docker.md)
  • I've updated cli-config.yaml.example if I added/changed config keys — N/A (no new config)
  • I've updated CONTRIBUTING.md or AGENTS.md if I changed architecture or workflows — N/A
  • I've considered cross-platform impact (Windows, macOS) per the compatibility guide — uses pathlib.Path.relative_to/.resolve() which are cross-platform; container paths are forward-slash POSIX (correct for the Linux container target regardless of host OS).
  • I've updated tool descriptions/schemas if I changed tool behavior — N/A

Open considerations (from #18787 triage questions)

  1. Scope: Docker-only for this PR, matching the backend/docker label. Helper signature takes a backend kwarg so other backends can opt in without breaking callers.
  2. Helper location: placed in tools/credential_files.py next to get_cache_directory_mounts — same _CACHE_DIRS constant, same module that owns the mount mapping. Open to moving it to gateway/platforms/base.py if maintainers prefer the platform layer.
  3. Translation site: single call site in _prepare_inbound_message_text (the only place doc host paths get injected into prompt text). Did not translate _build_media_placeholder (line 646), since queued events re-enter _prepare_inbound_message_text on requeue and get translated there.
  4. Cross-platform: uses Path.resolve() + relative_to, which canonicalise on each platform. Container paths are emitted as forward-slash POSIX strings (as_posix()) since the container target is always Linux.

…cker backend

Inbound documents (.docx/.pdf/etc.) from messaging platforms are saved
to host paths under ~/.hermes/cache/documents/. Under the Docker
terminal backend those directories are bind-mounted at
/root/.hermes/cache/documents/ via get_cache_directory_mounts(), but
the gateway was injecting the raw host path into the agent's prompt
when a doc was received. The agent runs inside the container and
cannot open the host path, so reads of user-sent docs failed silently.

Add to_agent_visible_cache_path() in tools/credential_files.py which
maps host cache paths to their container-side mount points, gated on
backend == "docker". Call it from the doc-injection sites in
_prepare_inbound_message_text. Pass-through for non-docker backends
keeps existing behavior unchanged.

Mirrors the pattern from NousResearch#14990 (vision sandbox path resolution).

Fixes NousResearch#18787
@alt-glitch alt-glitch added type/bug Something isn't working comp/gateway Gateway runner, session dispatch, delivery backend/docker Docker container execution P2 Medium — degraded but workaround exists labels May 4, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

Likely duplicate of #19048 — same fix for #18787 (inbound doc path translation for Docker backend).

@pvdb2178

pvdb2178 commented May 4, 2026

Copy link
Copy Markdown
Author

Closing as duplicate of #19048 — thanks @alt-glitch for the catch. I missed it because I only searched merged PRs, not open ones.

@ambition0802's PR landed ~22h before mine and implements the same fix (same helper name, location, call site, scope). Their backend gate via get_effective_backend() is cleaner than my inline os.getenv("TERMINAL_ENV").

I've offered the unit tests + docs note from this branch to #19048 as a follow-up if @ambition0802 wants them — happy to either push directly (with collaborator access on their fork) or they can cherry-pick from pvdb2178/hermes-agent:fix/inbound-doc-path-translation (commit 6d1b61d).

@pvdb2178

pvdb2178 commented May 4, 2026

Copy link
Copy Markdown
Author

Duplicate of #19048.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backend/docker Docker container execution comp/gateway Gateway runner, session dispatch, delivery P2 Medium — degraded but workaround exists type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Inbound document host paths not translated to container paths under Docker backend

2 participants