Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions changelog/current.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,6 @@ Record image-affecting changes to `manager/`, `worker/`, `openclaw-base/` here b

---

### Features

- **feat(mem0): add Mem0 long-term memory support for the Manager and OpenClaw Workers** — HiClaw now supports Mem0 in Platform mode, so the Manager and OpenClaw Workers can retain long-term memory across sessions. Each OpenClaw Worker keeps its memory isolated under its own worker identity. CoPaw Workers are not supported yet.
9 changes: 9 additions & 0 deletions install/hiclaw-install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2290,6 +2290,15 @@ HICLAW_DATA_DIR=${HICLAW_DATA_DIR:-hiclaw-data}
HICLAW_WORKSPACE_DIR=${HICLAW_WORKSPACE_DIR:-}
# Host directory sharing
HICLAW_HOST_SHARE_DIR=${HICLAW_HOST_SHARE_DIR:-}

# mem0 Plugin (long-term memory for Manager and OpenClaw Workers)
# Get API key from: https://app.mem0.ai
HICLAW_MEM0_ENABLED=${HICLAW_MEM0_ENABLED:-false}
HICLAW_MEM0_API_KEY=${HICLAW_MEM0_API_KEY:-}
HICLAW_MEM0_USER_ID=${HICLAW_MEM0_USER_ID:-}
HICLAW_MEM0_ORG_ID=${HICLAW_MEM0_ORG_ID:-}
HICLAW_MEM0_PROJECT_ID=${HICLAW_MEM0_PROJECT_ID:-}
HICLAW_MEM0_ENABLE_GRAPH=${HICLAW_MEM0_ENABLE_GRAPH:-false}
EOF

chmod 600 "${ENV_FILE}"
Expand Down
22 changes: 22 additions & 0 deletions manager/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,28 @@ RUN cp /opt/hiclaw/scripts/systemctl-shim.sh /usr/local/bin/systemctl
COPY agent/ /opt/hiclaw/agent/

ARG BUILTIN_VERSION=latest

# ---- Optional: mem0 Plugin (long-term memory for agents) ----
# Set MEM0_PLUGIN_ENABLED=1 at build time to bundle the plugin.
# Runtime configuration is injected via HICLAW_MEM0_* env vars.
ENV OPENCLAW_MEM0_PLUGIN_DIR="/opt/openclaw/extensions/openclaw-mem0"
ARG MEM0_PLUGIN_ENABLED=0
RUN if [ "${MEM0_PLUGIN_ENABLED}" = "1" ]; then \
echo "Installing @mem0/openclaw-mem0 plugin..." && \
tmp_dir="$(mktemp -d)" && \
cd "${tmp_dir}" && \
pack_name="$(npm pack @mem0/openclaw-mem0 --silent)" && \
rm -rf "${OPENCLAW_MEM0_PLUGIN_DIR}" && \
mkdir -p "${OPENCLAW_MEM0_PLUGIN_DIR}" && \
tar -xzf "${pack_name}" -C "${tmp_dir}" && \
cp -rf "${tmp_dir}/package/." "${OPENCLAW_MEM0_PLUGIN_DIR}/" && \
cd "${OPENCLAW_MEM0_PLUGIN_DIR}" && \
npm install --omit=dev --ignore-scripts && \
test -f "${OPENCLAW_MEM0_PLUGIN_DIR}/openclaw.plugin.json" && \
rm -rf "${tmp_dir}" && \
echo "mem0 plugin installed successfully"; \
fi

RUN echo "${BUILTIN_VERSION}" > /opt/hiclaw/agent/.builtin-version \
&& find /opt/hiclaw/agent/skills/*/scripts -name '*.sh' -exec chmod +x {} + 2>/dev/null || true \
&& find /opt/hiclaw/agent/worker-skills/*/scripts -name '*.sh' -exec chmod +x {} + 2>/dev/null || true \
Expand Down
21 changes: 21 additions & 0 deletions manager/Dockerfile.aliyun
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,27 @@ RUN tmp_dir="$(mktemp -d)" && \
npm install --omit=dev --ignore-scripts && \
rm -rf "${tmp_dir}"

# ---- Optional: mem0 Plugin (long-term memory for agents) ----
# Set MEM0_PLUGIN_ENABLED=1 at build time to bundle the plugin.
# Runtime configuration is injected via HICLAW_MEM0_* env vars.
ENV OPENCLAW_MEM0_PLUGIN_DIR="/opt/openclaw/extensions/openclaw-mem0"
ARG MEM0_PLUGIN_ENABLED=0
RUN if [ "${MEM0_PLUGIN_ENABLED}" = "1" ]; then \
echo "Installing @mem0/openclaw-mem0 plugin..." && \
tmp_dir="$(mktemp -d)" && \
cd "${tmp_dir}" && \
pack_name="$(npm pack @mem0/openclaw-mem0 --silent)" && \
rm -rf "${OPENCLAW_MEM0_PLUGIN_DIR}" && \
mkdir -p "${OPENCLAW_MEM0_PLUGIN_DIR}" && \
tar -xzf "${pack_name}" -C "${tmp_dir}" && \
cp -rf "${tmp_dir}/package/." "${OPENCLAW_MEM0_PLUGIN_DIR}/" && \
cd "${OPENCLAW_MEM0_PLUGIN_DIR}" && \
npm install --omit=dev --ignore-scripts && \
test -f "${OPENCLAW_MEM0_PLUGIN_DIR}/openclaw.plugin.json" && \
rm -rf "${tmp_dir}" && \
echo "mem0 plugin installed successfully"; \
fi

# Ensure openclaw binary is on PATH
ENV PATH="/opt/openclaw/packages/clawdbot/node_modules/.bin:${PATH}"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,54 @@ fi

log "Generated ${OUTPUT_DIR}/openclaw.json (model=${MODEL_NAME}, ctx=${CTX}, max=${MAX})"

# ============================================================
# Optional: inject openclaw-mem0 long-term memory config
#
# Manager runtime config uses HICLAW_MEM0_* env vars; Workers receive a
# per-worker entry in openclaw.json so they do not need mem0 runtime envs.
# ============================================================
_mem0_enabled_lc="$(echo "${HICLAW_MEM0_ENABLED:-false}" | tr '[:upper:]' '[:lower:]')"
if [ "${_mem0_enabled_lc}" = "true" ]; then
_mem0_plugin_name="openclaw-mem0"
_mem0_plugin_dir="${OPENCLAW_MEM0_PLUGIN_DIR:-/opt/openclaw/extensions/${_mem0_plugin_name}}"
_mem0_enable_graph_lc="$(echo "${HICLAW_MEM0_ENABLE_GRAPH:-false}" | tr '[:upper:]' '[:lower:]')"

if [ -z "${HICLAW_MEM0_API_KEY:-}" ]; then
log "WARNING: HICLAW_MEM0_ENABLED=true but HICLAW_MEM0_API_KEY is not set; skipping mem0 config for worker ${WORKER_NAME}"
else
jq --arg pluginName "${_mem0_plugin_name}" \
--arg pluginDir "${_mem0_plugin_dir}" \
--arg apiKey "${HICLAW_MEM0_API_KEY}" \
--arg userId "${WORKER_NAME}" \
--arg orgId "${HICLAW_MEM0_ORG_ID:-}" \
--arg projectId "${HICLAW_MEM0_PROJECT_ID:-}" \
--arg enableGraphRaw "${_mem0_enable_graph_lc}" \
'
.plugins = (.plugins // {})
| .plugins.load = (.plugins.load // {})
| .plugins.entries = (.plugins.entries // {})
| if (.plugins.allow | type) != "array" then .plugins.allow = [] else . end
| if (.plugins.allow | index($pluginName)) == null then .plugins.allow += [$pluginName] else . end
| if (.plugins.load.paths | type) != "array" then .plugins.load.paths = [] else . end
| if (.plugins.load.paths | index($pluginDir)) == null then .plugins.load.paths += [$pluginDir] else . end
| .plugins.entries[$pluginName] = {
"enabled": true,
"config": (
{
"apiKey": $apiKey,
"userId": $userId
}
+ (if $orgId != "" then {"orgId": $orgId} else {} end)
+ (if $projectId != "" then {"projectId": $projectId} else {} end)
+ (if $enableGraphRaw == "true" then {"enableGraph": true} else {} end)
)
}
' "${OUTPUT_DIR}/openclaw.json" > "${OUTPUT_DIR}/openclaw.json.mem0-tmp" && \
mv "${OUTPUT_DIR}/openclaw.json.mem0-tmp" "${OUTPUT_DIR}/openclaw.json"
log "mem0 config injected into Worker ${WORKER_NAME} openclaw.json (userId=${WORKER_NAME}, enableGraph=${_mem0_enable_graph_lc})"
fi
fi

# ============================================================
# Optional: inject openclaw-cms-plugin observability config
#
Expand Down
57 changes: 57 additions & 0 deletions manager/scripts/init/start-manager-agent.sh
Original file line number Diff line number Diff line change
Expand Up @@ -600,6 +600,63 @@ if [ "${HICLAW_RUNTIME}" = "aliyun" ]; then
log "Cloud overlay applied"
fi

# mem0 Plugin Configuration (Platform mode only)
# Injects openclaw-mem0 plugin config into openclaw.json when enabled.
# Requires: HICLAW_MEM0_ENABLED=true, HICLAW_MEM0_API_KEY
# Optional: HICLAW_MEM0_USER_ID, HICLAW_MEM0_ORG_ID, HICLAW_MEM0_PROJECT_ID, HICLAW_MEM0_ENABLE_GRAPH
# ============================================================
if [ "${HICLAW_MEM0_ENABLED:-false}" = "true" ]; then
MEM0_PLUGIN_NAME="openclaw-mem0"
MEM0_PLUGIN_DIR="${OPENCLAW_MEM0_PLUGIN_DIR:-/opt/openclaw/extensions/${MEM0_PLUGIN_NAME}}"
MEM0_PLUGIN_MANIFEST="${MEM0_PLUGIN_DIR}/openclaw.plugin.json"
if [ -z "${HICLAW_MEM0_API_KEY:-}" ]; then
log "WARNING: HICLAW_MEM0_ENABLED=true but HICLAW_MEM0_API_KEY is not set, skipping mem0 plugin"
elif [ ! -f "${MEM0_PLUGIN_MANIFEST}" ]; then
log "WARNING: mem0 plugin manifest not found at ${MEM0_PLUGIN_MANIFEST}, skipping mem0 config. Verify the image was built with MEM0_PLUGIN_ENABLED=1."
else
log "Configuring mem0 plugin (Platform mode)..."
_mem0_user_id="${HICLAW_MEM0_USER_ID:-${HICLAW_ADMIN_USER:-admin}}"
_mem0_org_id="${HICLAW_MEM0_ORG_ID:-}"
_mem0_project_id="${HICLAW_MEM0_PROJECT_ID:-}"
_mem0_enable_graph="$(echo "${HICLAW_MEM0_ENABLE_GRAPH:-false}" | tr '[:upper:]' '[:lower:]')"

# Build mem0 plugin config JSON
_mem0_config=$(jq -n \
--arg apiKey "${HICLAW_MEM0_API_KEY}" \
--arg userId "${_mem0_user_id}" \
--arg orgId "${_mem0_org_id}" \
--arg projectId "${_mem0_project_id}" \
--arg enableGraphRaw "${_mem0_enable_graph}" \
'{
"enabled": true,
"config": {
"apiKey": $apiKey,
"userId": $userId
} + (if $orgId != "" then {"orgId": $orgId} else {} end)
+ (if $projectId != "" then {"projectId": $projectId} else {} end)
+ (if $enableGraphRaw == "true" then {"enableGraph": true} else {} end)
}')

# Inject into openclaw.json (idempotent merge)
jq --arg pluginName "${MEM0_PLUGIN_NAME}" \
--arg pluginDir "${MEM0_PLUGIN_DIR}" \
--argjson mem0 "${_mem0_config}" '
.plugins = (.plugins // {})
| .plugins.load = (.plugins.load // {})
| .plugins.entries = (.plugins.entries // {})
| if (.plugins.allow | type) != "array" then .plugins.allow = [] else . end
| if (.plugins.allow | index($pluginName)) == null then .plugins.allow += [$pluginName] else . end
| if (.plugins.load.paths | type) != "array" then .plugins.load.paths = [] else . end
| if (.plugins.load.paths | index($pluginDir)) == null then .plugins.load.paths += [$pluginDir] else . end
| .plugins.entries[$pluginName] = $mem0
' /root/manager-workspace/openclaw.json > /tmp/openclaw-mem0.json && \
mv /tmp/openclaw-mem0.json /root/manager-workspace/openclaw.json

log "mem0 plugin configured (userId: ${_mem0_user_id})"
fi
fi
unset MEM0_PLUGIN_NAME MEM0_PLUGIN_DIR MEM0_PLUGIN_MANIFEST

# ============================================================
# Optional: enable openclaw-cms-plugin observability
# Config is applied at runtime so secrets stay out of image layers.
Expand Down
22 changes: 22 additions & 0 deletions worker/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
# HIGRESS_REGISTRY - base image registry (default: cn-hangzhou)
# OPENCLAW_BASE_IMAGE - openclaw-base image (default: hiclaw/openclaw-base:latest)
# OPENCLAW_CMS_PLUGIN_URL - observability plugin tarball URL (bundled unconditionally)
# MEM0_PLUGIN_ENABLED - set to 1 to bundle @mem0/openclaw-mem0 at build time
# ============================================================

ARG HIGRESS_REGISTRY=higress-registry.cn-hangzhou.cr.aliyuncs.com
Expand Down Expand Up @@ -48,6 +49,27 @@ RUN tmp_dir="$(mktemp -d)" && \
# which correctly resolves to <workspace>/.openclaw/openclaw.json
ENV PATH="/opt/openclaw/packages/clawdbot/node_modules/.bin:${PATH}"

# ---- Optional: mem0 Plugin (long-term memory for agents) ----
# Set MEM0_PLUGIN_ENABLED=1 at build time to bundle the plugin.
# Runtime configuration is injected via HICLAW_MEM0_* env vars.
ENV OPENCLAW_MEM0_PLUGIN_DIR="/opt/openclaw/extensions/openclaw-mem0"
ARG MEM0_PLUGIN_ENABLED=0
RUN if [ "${MEM0_PLUGIN_ENABLED}" = "1" ]; then \
echo "Installing @mem0/openclaw-mem0 plugin..." && \
tmp_dir="$(mktemp -d)" && \
cd "${tmp_dir}" && \
pack_name="$(npm pack @mem0/openclaw-mem0 --silent)" && \
rm -rf "${OPENCLAW_MEM0_PLUGIN_DIR}" && \
mkdir -p "${OPENCLAW_MEM0_PLUGIN_DIR}" && \
tar -xzf "${pack_name}" -C "${tmp_dir}" && \
cp -rf "${tmp_dir}/package/." "${OPENCLAW_MEM0_PLUGIN_DIR}/" && \
cd "${OPENCLAW_MEM0_PLUGIN_DIR}" && \
npm install --omit=dev --ignore-scripts && \
test -f "${OPENCLAW_MEM0_PLUGIN_DIR}/openclaw.plugin.json" && \
rm -rf "${tmp_dir}" && \
echo "mem0 plugin installed successfully"; \
fi

# Shared environment bootstrap and credential management
COPY --from=shared . /opt/hiclaw/scripts/lib/

Expand Down
Loading