Jackken commited on
Commit
496d1d3
·
1 Parent(s): be539ea

fix: scripts/patch_auto_media.py

Browse files
Files changed (1) hide show
  1. scripts/patch_auto_media.py +128 -0
scripts/patch_auto_media.py ADDED
@@ -0,0 +1,128 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """Patch hermes-agent gateway to auto-inject MEDIA: tags from write_file tool calls.
3
+
4
+ Problem: When the LLM creates files via write_file but doesn't include MEDIA: tags
5
+ in its final response, the gateway has no way to detect and deliver those files as
6
+ native attachments. The LLM may say "I've sent the file" when it actually only saved
7
+ it locally.
8
+
9
+ Solution: After the existing TTS MEDIA: propagation block in _run_agent(), scan the
10
+ assistant messages for write_file tool calls. Extract file paths from the tool call
11
+ arguments and append MEDIA: tags for files that:
12
+ 1. Actually exist on disk
13
+ 2. Have a document/media extension
14
+ 3. Are not already referenced in the final_response
15
+
16
+ This mirrors the existing TTS propagation pattern (gateway/run.py ~line 10968).
17
+ """
18
+
19
+ import re
20
+ import sys
21
+ import os
22
+ import glob
23
+ import json
24
+
25
+
26
+ def patch_gateway(filepath: str):
27
+ with open(filepath, 'r') as f:
28
+ content = f.read()
29
+
30
+ # The patch insertion point: right after the TTS MEDIA: propagation block
31
+ # ends with "final_response = final_response + ..."
32
+ old = ''' final_response = final_response + "\n" + "\n".join(unique_tags)
33
+
34
+ # Sync session_id: the agent may have created a new session during'''
35
+
36
+ new = ''' final_response = final_response + "\n" + "\n".join(unique_tags)
37
+
38
+ # Auto-inject MEDIA: tags for write_file tool results.
39
+ # When the LLM creates files via write_file but forgets to include
40
+ # MEDIA: tags in its response, this ensures the files are still
41
+ # delivered as native attachments on Feishu/WeChat/etc.
42
+ _doc_exts = {
43
+ '.md', '.txt', '.csv', '.json', '.xml', '.yaml', '.yml', '.toml', '.log',
44
+ '.pdf', '.doc', '.docx', '.xls', '.xlsx', '.ppt', '.pptx',
45
+ '.html', '.htm', '.zip', '.tar', '.gz', '.7z', '.rar',
46
+ '.png', '.jpg', '.jpeg', '.gif', '.webp', '.bmp', '.svg',
47
+ '.mp4', '.mov', '.avi', '.mkv', '.webm',
48
+ '.ogg', '.opus', '.mp3', '.wav', '.m4a',
49
+ }
50
+ _auto_media_paths = []
51
+ for _msg in result.get("messages", []):
52
+ if _msg.get("role") != "assistant":
53
+ continue
54
+ _tool_calls = _msg.get("tool_calls") or []
55
+ for _tc in _tool_calls:
56
+ _fn = (_tc.get("function") or {})
57
+ if not isinstance(_fn, dict):
58
+ continue
59
+ _fn_name = _fn.get("name", "")
60
+ if _fn_name not in ("write_file",):
61
+ continue
62
+ try:
63
+ _args = json.loads(_fn.get("arguments", "{}"))
64
+ except (json.JSONDecodeError, TypeError):
65
+ continue
66
+ _fpath = _args.get("path", "")
67
+ if not _fpath:
68
+ continue
69
+ _fpath = os.path.expanduser(_fpath)
70
+ # Only inject for files with document/media extensions
71
+ _ext = os.path.splitext(_fpath)[1].lower()
72
+ if _ext not in _doc_exts:
73
+ continue
74
+ # File must actually exist
75
+ if not os.path.isfile(_fpath):
76
+ continue
77
+ # Avoid duplicates and paths already in response
78
+ _media_tag = f"MEDIA:{_fpath}"
79
+ if _media_tag in final_response:
80
+ continue
81
+ if _fpath in final_response:
82
+ continue
83
+ _auto_media_paths.append(_media_tag)
84
+
85
+ if _auto_media_paths:
86
+ logger.info(
87
+ "Auto-injecting %d MEDIA: tag(s) from write_file tool calls: %s",
88
+ len(_auto_media_paths),
89
+ ", ".join(os.path.basename(p.split(":")[1]) for p in _auto_media_paths),
90
+ )
91
+ final_response = final_response + "\n" + "\n".join(_auto_media_paths)
92
+
93
+ # Sync session_id: the agent may have created a new session during'''
94
+
95
+ if old not in content:
96
+ print(f"ERROR: Could not find insertion point in {filepath}", file=sys.stderr)
97
+ print("The TTS MEDIA: propagation block may have changed.", file=sys.stderr)
98
+ sys.exit(1)
99
+
100
+ content = content.replace(old, new, 1)
101
+
102
+ with open(filepath, 'w') as f:
103
+ f.write(content)
104
+
105
+ print(f"Patched {filepath}: auto-inject MEDIA: tags from write_file tool calls")
106
+
107
+
108
+ if __name__ == "__main__":
109
+ # hermes-agent is installed in editable mode (-e), so source is in /app/hermes-agent/
110
+ candidates = [
111
+ "/app/hermes-agent/gateway/run.py",
112
+ ]
113
+
114
+ # Also search venv site-packages as fallback
115
+ candidates.extend(glob.glob("/app/venv/lib/**/gateway/run.py", recursive=True))
116
+
117
+ filepath = None
118
+ for c in candidates:
119
+ if os.path.isfile(c):
120
+ filepath = c
121
+ break
122
+
123
+ if not filepath:
124
+ print("ERROR: run.py not found in any candidate location", file=sys.stderr)
125
+ print(f"Checked: {candidates}", file=sys.stderr)
126
+ sys.exit(1)
127
+
128
+ patch_gateway(filepath)