File size: 6,322 Bytes
8aa2a43
c310c5b
cbfbec3
 
 
 
8aa2a43
c310c5b
ed0e617
e35f3c0
c310c5b
 
 
f0b15e1
 
 
 
c310c5b
f55a35b
c310c5b
f55a35b
c310c5b
4036608
5e3d05b
 
c310c5b
8aa2a43
aa686c9
da7768b
aa686c9
8aa2a43
ca5e3fb
 
 
8aa2a43
52f3483
da7768b
52f3483
8aa2a43
9d9a46e
 
 
2a76983
 
 
 
 
 
f52e0ed
 
 
 
06cb3d4
 
 
 
 
 
4036608
 
 
 
8aa2a43
ed0e617
 
8aa2a43
ed0e617
 
 
 
 
 
8aa2a43
 
 
 
 
 
 
 
9c7e90d
 
 
 
e10e850
 
2eccb58
e10e850
ed0e617
e10e850
da7768b
e10e850
 
ed0e617
 
 
 
 
 
 
 
e10e850
 
ed0e617
f55a35b
c6b874d
c310c5b
272cc2c
c310c5b
 
272cc2c
 
62ec96b
f55a35b
 
c6b874d
020c94b
7b0e47a
c310c5b
 
f55a35b
6ffc130
 
 
c310c5b
 
 
ed0e617
 
c310c5b
6ffc130
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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
FROM python:3.12-slim

# Fix timezone — HF Space defaults to UTC, we need Asia/Shanghai for log timestamps
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone

# System deps (add build tools for node-pty native compilation)
RUN apt-get update && apt-get install -y --no-install-recommends \
    git curl gnupg2 fontconfig make g++ python3 \
    && rm -rf /var/lib/apt/lists/*

WORKDIR /app

# Clone hermes-agent (pinned to v2026.4.30 = v0.12.0)
# Runtime auto-update will pull newer releases transparently
RUN git clone --depth 1 --branch v2026.4.30 https://github.com/NousResearch/hermes-agent.git /app/hermes-agent && \
    echo "v2026.4.30" > /app/hermes-agent.version

# Build venv
RUN python3 -m venv /app/venv
ENV PATH="/app/venv/bin:$PATH"
RUN pip install --quiet --upgrade pip && \
    pip install --quiet psutil networkx duckduckgo-search && \
    pip install --quiet -e "/app/hermes-agent[feishu,mcp,cron,pty]" && \
    pip install --quiet aiohttp cryptography 2>&1 | tail -10

# Patch: add document file extensions to auto-detection for native delivery
COPY scripts/patch_file_delivery.py /tmp/patch_file_delivery.py
RUN python3 /tmp/patch_file_delivery.py; rm -f /tmp/patch_file_delivery.py

# Patch: Feishu media support in send_message_tool + anti-hallucination prompts
COPY patches/hermes-agent/agent/prompt_builder.py /app/hermes-agent/agent/prompt_builder.py
COPY patches/hermes-agent/tools/send_message_tool.py /app/hermes-agent/tools/send_message_tool.py

# Patch: Auto-inject MEDIA: tags from write_file tool calls
COPY scripts/patch_auto_media.py /tmp/patch_auto_media.py
RUN python3 /tmp/patch_auto_media.py; rm -f /tmp/patch_auto_media.py

# Patch: Auto-resolve relative media paths to absolute paths
COPY scripts/patch_resolve_media_paths.py /tmp/patch_resolve_media_paths.py
RUN python3 /tmp/patch_resolve_media_paths.py; rm -f /tmp/patch_resolve_media_paths.py

# Patch: Fix WeixinAdapter cross-event-loop session reuse
# Prevents "Timeout context manager should be used inside a task" when
# send_weixin_direct() reuses the gateway's aiohttp session from _run_async()
COPY scripts/patch_weixin_cross_loop.py /tmp/patch_weixin_cross_loop.py
RUN python3 /tmp/patch_weixin_cross_loop.py; rm -f /tmp/patch_weixin_cross_loop.py

# Patch: Strip <|channel>thinking / <channel|> model tags from user-visible output
COPY scripts/patch_strip_thinking_tags.py /tmp/patch_strip_thinking_tags.py
RUN python3 /tmp/patch_strip_thinking_tags.py; rm -f /tmp/patch_strip_thinking_tags.py

# Patch: Sandbox isolation for dangerous terminal commands (inspired by OpenAI Agents SDK)
# Installs bubblewrap if available, falls back to unshare + resource limits
RUN apt-get update && apt-get install -y --no-install-recommends bubblewrap 2>/dev/null || true; rm -rf /var/lib/apt/lists/*
COPY scripts/patch_sandbox_isolation.py /tmp/patch_sandbox_isolation.py
RUN python3 /tmp/patch_sandbox_isolation.py; rm -f /tmp/patch_sandbox_isolation.py

# Patch: DuckDuckGo free fallback for web_search (no API key needed)
COPY scripts/patch_web_search_fallback.py /tmp/patch_web_search_fallback.py
RUN python3 /tmp/patch_web_search_fallback.py; rm -f /tmp/patch_web_search_fallback.py

# Install Node.js 23
RUN ARCH=$(dpkg --print-architecture) \
    && if [ "$ARCH" = "amd64" ]; then NODE_ARCH="x64"; else NODE_ARCH="$ARCH"; fi \
    && echo "Installing Node.js v23 for ${NODE_ARCH}" \
    && curl -fsSL "https://nodejs.org/dist/v23.11.0/node-v23.11.0-linux-${NODE_ARCH}.tar.gz" \
       -o /tmp/node.tar.gz \
    && tar -xzf /tmp/node.tar.gz -C /usr/local --strip-components=1 \
    && rm -f /tmp/node.tar.gz \
    && node --version && npm --version

# Chinese font (Noto Sans SC Regular + Bold)
RUN mkdir -p /usr/share/fonts/truetype/noto && \
    curl -sL "https://github.com/googlefonts/noto-cjk/raw/main/Sans/SubsetOTF/SC/NotoSansSC-Regular.otf" \
    -o /usr/share/fonts/truetype/noto/NotoSansSC-Regular.otf && \
    curl -sL "https://github.com/googlefonts/noto-cjk/raw/main/Sans/SubsetOTF/SC/NotoSansSC-Bold.otf" \
    -o /usr/share/fonts/truetype/noto/NotoSansSC-Bold.otf && \
    fc-cache -f

# Clone agency-agents-zh (211 expert role prompts for instant role switching)
RUN git clone --depth 1 https://github.com/jnMetaCode/agency-agents-zh.git /app/agency-agents && \
    echo "agency-agents-zh cloned ($(find /app/agency-agents -name '*.md' ! -name 'README*' ! -name 'CATALOG*' ! -name 'AGENT-LIST*' ! -name 'CONTRIBUTING*' ! -name 'LICENSE*' ! -name 'UPSTREAM*' | wc -l) agent files)"

# Build hermes-web-ui v0.5.9
# Aligned with upstream Dockerfile: NODE_OPTIONS + npm rebuild node-pty
RUN rm -rf /tmp/hermes-web-ui && \
    git clone --depth 1 --branch v0.5.9 https://github.com/EKKOLearnAI/hermes-web-ui.git /tmp/hermes-web-ui && \
    cd /tmp/hermes-web-ui && \
    echo "build-v0.5.9-$(date +%Y%m%d)" > .buildstamp && \
    npm install --ignore-scripts 2>&1 | tail -5 && \
    npm rebuild node-pty 2>&1 | tail -5 && \
    NODE_OPTIONS=--max-old-space-size=4096 npm run build 2>&1 | tail -10 && \
    mkdir -p /app/webui-server && \
    cp -r dist/server/* /app/webui-server/ && \
    mkdir -p /app/webui-client && \
    cp -r dist/client/* /app/webui-client/ && \
    cp package.json /app/webui-server/package.json && \
    npm prune --omit=dev --prefix /tmp/hermes-web-ui 2>&1 | tail -3 && \
    cp -r node_modules /app/webui-server/node_modules && \
    rm -rf /tmp/hermes-web-ui && \
    echo "v0.5.9" > /app/webui.version && \
    echo "hermes-web-ui v0.5.9 build done"

# Create hermes home
RUN mkdir -p /root/.hermes/plugins/image_gen/pollinations

# Copy config files (to both hermes home AND /app for persistence fallback)
COPY config.yaml /root/.hermes/config.yaml
COPY SOUL.md /root/.hermes/SOUL.md
# Keep repo copies in /app as fallback sources for persistent storage recovery
COPY config.yaml /app/config.yaml
COPY .env.example /app/.env.example
COPY entry.py /app/entry.py
COPY dashboard.html /app/dashboard.html
COPY plugins/pollinations/ /root/.hermes/plugins/image_gen/pollinations/
COPY scripts/ /app/scripts/
COPY custom-agents/ /app/custom-agents/


# Startup script
COPY start.sh /app/start.sh
RUN chmod +x /app/start.sh

EXPOSE 7860

ENV HERMES_ACCEPT_HOOKS=1
ENV NODE_ENV=production
ENV AUTH_TOKEN=hermes-bot-2026

CMD ["/app/start.sh"]