File size: 4,360 Bytes
9d9a46e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
460aac4
9d9a46e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
#!/usr/bin/env python3
"""Patch hermes-agent gateway to auto-resolve relative media paths.

ROOT CAUSE: When the LLM uses write_file, it often saves files with relative
paths like "广东天气预报.md" or "/tmp/广东天气预报.md", then puts
"MEDIA:广东天气预报.md" in the response.  The gateway's extract_media()
parses this bare filename, but the subsequent send_document() call fails
because the path is relative and os.path.isfile() returns False.

FIX: After extract_media() returns the media_files list, scan each path:
  1. If already absolute and exists → keep as-is
  2. If relative → search well-known directories (/tmp/, /data/hermes/uploads/,
     current working directory, HERMES_HOME) for a file with that name
  3. Replace the path with the resolved absolute path
  4. If still not found → keep the original (will fail with clear error)

This is a surgical patch to the _deliver_response() method in base.py,
inserted right after the "media_files, response = self.extract_media(response)"
line.
"""

import re
import sys
import os
import glob


def patch_file(filepath: str):
    with open(filepath, 'r') as f:
        content = f.read()

    # Find the insertion point: right after extract_media() call
    old = """\
                # Extract MEDIA:<path> tags (from TTS tool) before other processing
                media_files, response = self.extract_media(response)"""

    new = """\
                # Extract MEDIA:<path> tags (from TTS tool) before other processing
                media_files, response = self.extract_media(response)

                # Auto-resolve relative media paths to absolute paths.
                # The LLM often uses bare filenames in MEDIA: tags (e.g. "report.md")
                # which fail because send_document() can't find them.
                _media_search_dirs = ['/tmp', '/data/hermes/uploads', '/data', os.getcwd()]
                _hermes_home = os.path.expanduser('~/.hermes')
                if _hermes_home not in _media_search_dirs:
                    _media_search_dirs.append(_hermes_home)
                _resolved_media = []
                for _mpath, _mvoice in media_files:
                    if os.path.isabs(_mpath) and os.path.isfile(_mpath):
                        _resolved_media.append((_mpath, _mvoice))
                        continue
                    # Try to find the file in well-known directories
                    _basename = os.path.basename(_mpath)
                    _found = None
                    for _search_dir in _media_search_dirs:
                        _candidate = os.path.join(_search_dir, _basename)
                        if os.path.isfile(_candidate):
                            _found = _candidate
                            break
                    if _found:
                        logger.info("[%s] Resolved relative media path '%s' -> '%s'", self.name, _mpath, _found)
                        _resolved_media.append((_found, _mvoice))
                    else:
                        # Keep original — will fail with a clear error message
                        _resolved_media.append((_mpath, _mvoice))
                        logger.warning("[%s] Could not resolve media path '%s' — searched %s", self.name, _mpath, _media_search_dirs)
                media_files = _resolved_media"""

    if old not in content:
        print(f"WARNING: Could not find insertion point in {filepath}", file=sys.stderr)
        print("The upstream code may have changed. Skipping this patch.", file=sys.stderr)
        sys.exit(0)

    content = content.replace(old, new, 1)

    with open(filepath, 'w') as f:
        f.write(content)

    print(f"Patched {filepath}: auto-resolve relative media paths before sending")


if __name__ == "__main__":
    candidates = [
        "/app/hermes-agent/gateway/platforms/base.py",
    ]
    candidates.extend(glob.glob("/app/venv/lib/**/gateway/platforms/base.py", recursive=True))

    filepath = None
    for c in candidates:
        if os.path.isfile(c):
            filepath = c
            break

    if not filepath:
        print("WARNING: base.py not found in any candidate location", file=sys.stderr)
        print(f"Checked: {candidates}", file=sys.stderr)
        print("Skipping patch_resolve_media_paths.", file=sys.stderr)
        sys.exit(0)

    patch_file(filepath)