fix(wechat_kf): download attachments to agent_workspace/tmp

So agent tools resolve relative refs like 	mp/xxx.pdf on the first
try, matching weixin's _get_tmp_dir convention.
This commit is contained in:
6vision
2026-05-28 19:40:12 +08:00
parent c605b0b080
commit 99bddb79d6
2 changed files with 19 additions and 5 deletions

View File

@@ -344,6 +344,8 @@ class WechatKfChannel(ChatChannel):
# On a text turn, attach any pending images/files as references # On a text turn, attach any pending images/files as references
# so the downstream agent can pick them up via the text content. # so the downstream agent can pick them up via the text content.
# Paths are already under agent_workspace/tmp (see
# WechatKfMessage._get_tmp_dir), so a relative ref also works.
if kf_msg.ctype == ContextType.TEXT: if kf_msg.ctype == ContextType.TEXT:
cached_files = file_cache.get(session_id) cached_files = file_cache.get(session_id)
if cached_files: if cached_files:

View File

@@ -11,7 +11,19 @@ from wechatpy.enterprise import WeChatClient
from bridge.context import ContextType from bridge.context import ContextType
from channel.chat_message import ChatMessage from channel.chat_message import ChatMessage
from common.log import logger from common.log import logger
from common.tmp_dir import TmpDir from common.utils import expand_path
from config import conf
def _get_tmp_dir() -> str:
"""Save under agent_workspace/tmp/ so agent tools (e.g. `read`) can
resolve a relative path like `tmp/xxx.pdf` against their own
workspace root. Mirrors the convention used by weixin / wecom_bot.
"""
ws_root = expand_path(conf().get("agent_workspace", "~/cow"))
tmp_dir = os.path.join(ws_root, "tmp")
os.makedirs(tmp_dir, exist_ok=True)
return tmp_dir
def _extract_filename(content_disposition: str) -> str: def _extract_filename(content_disposition: str) -> str:
@@ -66,7 +78,7 @@ class WechatKfMessage(ChatMessage):
elif self.msgtype == "image": elif self.msgtype == "image":
self.ctype = ContextType.IMAGE self.ctype = ContextType.IMAGE
media_id = msg.get("image", {}).get("media_id", "") media_id = msg.get("image", {}).get("media_id", "")
self.content = TmpDir().path() + media_id + ".jpg" self.content = os.path.join(_get_tmp_dir(), media_id + ".jpg")
def download_image(): def download_image():
response = client.media.download(media_id) response = client.media.download(media_id)
@@ -81,7 +93,7 @@ class WechatKfMessage(ChatMessage):
self.ctype = ContextType.VOICE self.ctype = ContextType.VOICE
media_id = msg.get("voice", {}).get("media_id", "") media_id = msg.get("voice", {}).get("media_id", "")
# WeCom returns amr by default; downstream voice pipeline will convert. # WeCom returns amr by default; downstream voice pipeline will convert.
self.content = TmpDir().path() + media_id + ".amr" self.content = os.path.join(_get_tmp_dir(), media_id + ".amr")
def download_voice(): def download_voice():
response = client.media.download(media_id) response = client.media.download(media_id)
@@ -97,7 +109,7 @@ class WechatKfMessage(ChatMessage):
media_id = msg.get("file", {}).get("media_id", "") media_id = msg.get("file", {}).get("media_id", "")
# Provisional path; rewritten in download_file() once we have # Provisional path; rewritten in download_file() once we have
# the original filename from Content-Disposition. # the original filename from Content-Disposition.
self.content = TmpDir().path() + media_id self.content = os.path.join(_get_tmp_dir(), media_id)
def download_file(): def download_file():
response = client.media.download(media_id) response = client.media.download(media_id)
@@ -105,7 +117,7 @@ class WechatKfMessage(ChatMessage):
filename = _extract_filename( filename = _extract_filename(
response.headers.get("Content-Disposition", "") response.headers.get("Content-Disposition", "")
) or media_id ) or media_id
self.content = os.path.join(TmpDir().path(), filename) self.content = os.path.join(_get_tmp_dir(), filename)
with open(self.content, "wb") as f: with open(self.content, "wb") as f:
f.write(response.content) f.write(response.content)
else: else: