mirror of
https://github.com/agentscope-ai/ReMe.git
synced 2026-09-05 08:06:15 +00:00
fix: publish an OpenClaw-specific ClawHub artifact (#513)
* fix: publish an OpenClaw-specific ClawHub artifact * fix: enable ClawHub publication
This commit is contained in:
parent
65cb4ebdd6
commit
f9a45a319a
11 changed files with 310 additions and 14 deletions
26
.github/workflows/release-typescript.yml
vendored
26
.github/workflows/release-typescript.yml
vendored
|
|
@ -2,7 +2,7 @@
|
|||
# 1. Update typescript/package.json and package-lock.json to the release version and merge them.
|
||||
# 2. Configure npm Trusted Publishing for agentscope-ai/ReMe and this workflow file.
|
||||
# 3. Run this workflow manually with the exact package version (an optional v prefix is accepted).
|
||||
# 4. Configure ClawHub Trusted Publishing or CLAWHUB_TOKEN before enabling ClawHub publication.
|
||||
# 4. Configure ClawHub Trusted Publishing for agentscope-ai/ReMe and this workflow file.
|
||||
# 5. Use the `next` tag for prereleases and `latest` only for stable releases.
|
||||
|
||||
name: Release / TypeScript integrations
|
||||
|
|
@ -25,7 +25,7 @@ on:
|
|||
- next
|
||||
- latest
|
||||
publish_clawhub:
|
||||
description: Also publish the verified tarball to ClawHub
|
||||
description: Also publish the OpenClaw-specific ClawPack to ClawHub
|
||||
required: true
|
||||
default: false
|
||||
type: boolean
|
||||
|
|
@ -54,7 +54,7 @@ jobs:
|
|||
- name: Set up Node
|
||||
uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6
|
||||
with:
|
||||
node-version: '22.22.3'
|
||||
node-version: "22.22.3"
|
||||
|
||||
- name: Validate package name and release version
|
||||
id: validate
|
||||
|
|
@ -109,6 +109,19 @@ jobs:
|
|||
path: ${{ runner.temp }}/reme-typescript-package/*.tgz
|
||||
if-no-files-found: error
|
||||
|
||||
- name: Pack ClawHub tarball
|
||||
working-directory: typescript
|
||||
run: |
|
||||
mkdir -p "${RUNNER_TEMP}/reme-clawhub-package"
|
||||
npm run pack:clawhub -- "${RUNNER_TEMP}/reme-clawhub-package"
|
||||
|
||||
- name: Upload ClawHub tarball
|
||||
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
|
||||
with:
|
||||
name: agentscope-ai-reme-clawhub-${{ inputs.version }}
|
||||
path: ${{ runner.temp }}/reme-clawhub-package/*.tgz
|
||||
if-no-files-found: error
|
||||
|
||||
publish:
|
||||
needs: build
|
||||
runs-on: ubuntu-latest
|
||||
|
|
@ -120,7 +133,7 @@ jobs:
|
|||
- name: Set up Node for npm
|
||||
uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6
|
||||
with:
|
||||
node-version: '24'
|
||||
node-version: "24"
|
||||
registry-url: https://registry.npmjs.org
|
||||
|
||||
- name: Download npm tarball
|
||||
|
|
@ -161,7 +174,6 @@ jobs:
|
|||
source_commit: ${{ github.sha }}
|
||||
source_ref: ${{ github.ref }}
|
||||
source_path: typescript
|
||||
package_artifact_name: agentscope-ai-reme-${{ inputs.version }}
|
||||
package_artifact_name: agentscope-ai-reme-clawhub-${{ inputs.version }}
|
||||
dry_run: false
|
||||
wait_for_publication: true
|
||||
secrets:
|
||||
clawhub_token: ${{ secrets.CLAWHUB_TOKEN }}
|
||||
|
|
|
|||
|
|
@ -140,6 +140,7 @@ npm run test:package
|
|||
```
|
||||
|
||||
`npm pack` runs the TypeScript build and includes only `dist`, the DSH patch, the OpenClaw manifest, and the English and
|
||||
Chinese READMEs.
|
||||
Chinese READMEs. `npm run pack:clawhub -- <output-directory>` creates the ClawHub artifact with the same runtime files
|
||||
and the OpenClaw-only `README_OPENCLAW.md` and `README_OPENCLAW_ZH.md` content at the package README paths.
|
||||
|
||||
Stable releases use npm's `latest` distribution tag; prereleases use `next`.
|
||||
|
|
|
|||
72
typescript/README_OPENCLAW.md
Normal file
72
typescript/README_OPENCLAW.md
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
# ReMe memory for OpenClaw
|
||||
|
||||
[中文说明](./README_ZH.md)
|
||||
|
||||
ReMe gives OpenClaw file-native long-term memory while keeping durable memory in a workspace you own. The plugin uses
|
||||
OpenClaw's native lifecycle, hooks, tools, and memory slot.
|
||||
|
||||
## What the plugin does
|
||||
|
||||
- Registers `reme_search` for explicit memory lookup.
|
||||
- Recalls relevant memory before conversational root-agent runs.
|
||||
- Captures completed user/assistant turns in background batches.
|
||||
- Runs optional daily `auto_dream` memory consolidation in the workspace timezone.
|
||||
- Excludes subagent, cron, heartbeat, memory, and overflow runs by default.
|
||||
- Wraps recalled content in `<reme-context>` and marks it as untrusted historical data.
|
||||
|
||||
## Requirements
|
||||
|
||||
- OpenClaw `2026.7.1` or later.
|
||||
- Node.js `22.22.3+`, `24.15.0+`, or `25.9.0+` on the corresponding supported major-version line.
|
||||
- A running ReMe HTTP service with the `search`, `auto_memory`, and `auto_dream` jobs.
|
||||
|
||||
## Start ReMe
|
||||
|
||||
Install ReMe and start its local HTTP service:
|
||||
|
||||
```bash
|
||||
pip install "reme-ai[core]"
|
||||
reme start workspace_dir=/absolute/path/to/workspace
|
||||
```
|
||||
|
||||
The default endpoint is `http://127.0.0.1:2333`. ReMe's HTTP service does not use API-key authentication, so keep it
|
||||
on loopback or another trusted network unless you provide a protected proxy boundary.
|
||||
|
||||
## Install the OpenClaw plugin
|
||||
|
||||
Install explicitly from ClawHub:
|
||||
|
||||
```bash
|
||||
openclaw plugins install clawhub:@agentscope-ai/reme
|
||||
```
|
||||
|
||||
When another memory plugin is enabled, select `reme` for `plugins.slots.memory`. OpenClaw remains authoritative for
|
||||
conversation access and prompt-injection permissions; grant them to ReMe when your policy requires explicit consent.
|
||||
The plugin does not rewrite Gateway configuration.
|
||||
|
||||
## Configuration
|
||||
|
||||
| Option | Default | Meaning |
|
||||
| --------------------- | ----------------------- | --------------------------------------------- |
|
||||
| `endpoint` | `http://127.0.0.1:2333` | ReMe HTTP service URL |
|
||||
| `language` | `en` | Memory guidance language: `en` or `zh` |
|
||||
| `autoRecall` | `true` | Recall before conversational root-agent runs |
|
||||
| `searchLimit` | `5` | Maximum search results |
|
||||
| `recallMinScore` | `0` | Minimum automatic-recall score |
|
||||
| `autoMemoryEnabled` | `true` | Capture completed conversational turns |
|
||||
| `autoMemoryInterval` | `5` | Submit after this many completed turns |
|
||||
| `autoDreamEnabled` | `true` | Enable daily memory consolidation |
|
||||
| `dreamCron` | `0 23 * * *` | Daily schedule in the workspace timezone |
|
||||
| `dreamHint` | empty | Optional guidance sent to `auto_dream` |
|
||||
| `rootAgentsOnly` | `true` | Exclude subagents from guidance and capture |
|
||||
| `timezone` | `Asia/Shanghai` | IANA timezone used for batches and scheduling |
|
||||
| `requestTimeoutMs` | `10000` | Recall and explicit-search timeout |
|
||||
| `backgroundTimeoutMs` | `3600000` | Automatic-memory and dream timeout |
|
||||
| `shutdownTimeoutMs` | `5000` | Best-effort Gateway shutdown drain budget |
|
||||
|
||||
Configuration changes apply to subsequent runs. Failed automatic-memory batches are retained for retry, and the
|
||||
Gateway shutdown hook attempts to flush pending work within `shutdownTimeoutMs`.
|
||||
|
||||
## Source and license
|
||||
|
||||
ReMe is developed at [agentscope-ai/ReMe](https://github.com/agentscope-ai/ReMe) and released under Apache-2.0.
|
||||
71
typescript/README_OPENCLAW_ZH.md
Normal file
71
typescript/README_OPENCLAW_ZH.md
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
# OpenClaw 的 ReMe 长期记忆插件
|
||||
|
||||
[English](./README.md)
|
||||
|
||||
ReMe 为 OpenClaw 提供文件原生的长期记忆,并将持久记忆保存在用户拥有的 workspace 中。插件使用 OpenClaw
|
||||
原生的生命周期、Hook、工具接口和 memory slot。
|
||||
|
||||
## 插件能力
|
||||
|
||||
- 注册 `reme_search`,支持显式检索记忆。
|
||||
- 在根 Agent 的对话运行前自动召回相关记忆。
|
||||
- 在后台分批捕获已完成的用户/助手对话。
|
||||
- 按 workspace 时区运行可选的每日 `auto_dream` 记忆整理。
|
||||
- 默认排除子 Agent、Cron、Heartbeat、Memory 和 Overflow 触发的运行。
|
||||
- 使用 `<reme-context>` 包裹召回内容,并将其标记为不可信历史数据。
|
||||
|
||||
## 环境要求
|
||||
|
||||
- OpenClaw `2026.7.1` 或更高版本。
|
||||
- 对应受支持主版本线上的 Node.js `22.22.3+`、`24.15.0+` 或 `25.9.0+`。
|
||||
- 已启动 ReMe HTTP 服务,并提供 `search`、`auto_memory` 和 `auto_dream` Job。
|
||||
|
||||
## 启动 ReMe
|
||||
|
||||
安装 ReMe 并启动本地 HTTP 服务:
|
||||
|
||||
```bash
|
||||
pip install "reme-ai[core]"
|
||||
reme start workspace_dir=/absolute/path/to/workspace
|
||||
```
|
||||
|
||||
默认地址为 `http://127.0.0.1:2333`。ReMe HTTP 服务不使用 API Key 认证,因此除非前面部署了受保护的代理边界,
|
||||
否则应仅监听 loopback 或其他可信网络。
|
||||
|
||||
## 安装 OpenClaw 插件
|
||||
|
||||
明确指定从 ClawHub 安装:
|
||||
|
||||
```bash
|
||||
openclaw plugins install clawhub:@agentscope-ai/reme
|
||||
```
|
||||
|
||||
如果已经启用了其他记忆插件,请将 `plugins.slots.memory` 设为 `reme`。对话访问和 Prompt 注入权限仍由
|
||||
OpenClaw 管理;策略要求显式授权时,需要为 ReMe 开启相应权限。插件不会修改 Gateway 配置。
|
||||
|
||||
## 配置
|
||||
|
||||
| 配置项 | 默认值 | 作用 |
|
||||
| --------------------- | ----------------------- | ------------------------------------ |
|
||||
| `endpoint` | `http://127.0.0.1:2333` | ReMe HTTP 服务地址 |
|
||||
| `language` | `en` | 记忆指引语言:`en` 或 `zh` |
|
||||
| `autoRecall` | `true` | 在根 Agent 对话运行前自动召回 |
|
||||
| `searchLimit` | `5` | 搜索结果上限 |
|
||||
| `recallMinScore` | `0` | 自动召回的最低搜索分数 |
|
||||
| `autoMemoryEnabled` | `true` | 捕获已完成的对话 |
|
||||
| `autoMemoryInterval` | `5` | 每完成多少轮提交一次 |
|
||||
| `autoDreamEnabled` | `true` | 启用每日记忆整理 |
|
||||
| `dreamCron` | `0 23 * * *` | workspace 时区下的每日计划 |
|
||||
| `dreamHint` | 空字符串 | 传给 `auto_dream` 的可选指引 |
|
||||
| `rootAgentsOnly` | `true` | 不为子 Agent 注入指引或捕获对话 |
|
||||
| `timezone` | `Asia/Shanghai` | 每日批次和计划使用的 IANA 时区 |
|
||||
| `requestTimeoutMs` | `10000` | 自动召回和显式搜索超时 |
|
||||
| `backgroundTimeoutMs` | `3600000` | 自动记忆和 Auto Dream 超时 |
|
||||
| `shutdownTimeoutMs` | `5000` | Gateway 退出时尽力排空任务的时间预算 |
|
||||
|
||||
配置修改会从后续运行开始生效。失败的自动记忆批次会保留等待重试,Gateway 退出时会在 `shutdownTimeoutMs` 范围内
|
||||
尝试刷新未完成任务。
|
||||
|
||||
## 源码与许可证
|
||||
|
||||
ReMe 在 [agentscope-ai/ReMe](https://github.com/agentscope-ai/ReMe) 开发,并使用 Apache-2.0 许可证发布。
|
||||
|
|
@ -130,5 +130,7 @@ npm run test:package
|
|||
```
|
||||
|
||||
`npm pack` 会先构建 TypeScript,并且只打包 `dist`、DSH patch、OpenClaw manifest 和中英文 README。
|
||||
`npm run pack:clawhub -- <输出目录>` 会使用相同的运行时文件生成 ClawHub 产物,并将仅包含 OpenClaw
|
||||
说明的 `README_OPENCLAW.md` 和 `README_OPENCLAW_ZH.md` 放到包内 README 路径。
|
||||
|
||||
稳定版本使用 npm 的 `latest` distribution tag 发布,预发布版本使用 `next`。
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
"contracts": {
|
||||
"tools": ["reme_search"]
|
||||
},
|
||||
"configUiHints": {
|
||||
"uiHints": {
|
||||
"endpoint": {
|
||||
"label": "ReMe endpoint",
|
||||
"placeholder": "http://127.0.0.1:2333"
|
||||
|
|
|
|||
4
typescript/package-lock.json
generated
4
typescript/package-lock.json
generated
|
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"name": "@agentscope-ai/reme",
|
||||
"version": "0.1.1",
|
||||
"version": "0.1.2",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@agentscope-ai/reme",
|
||||
"version": "0.1.1",
|
||||
"version": "0.1.2",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"typebox": "1.3.19"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@agentscope-ai/reme",
|
||||
"version": "0.1.1",
|
||||
"version": "0.1.2",
|
||||
"description": "ReMe client and memory integrations for TypeScript agents",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
|
|
@ -64,6 +64,7 @@
|
|||
"format": "prettier --write .",
|
||||
"format:check": "prettier --check .",
|
||||
"lint": "eslint .",
|
||||
"pack:clawhub": "node scripts/pack-clawhub.mjs",
|
||||
"pretest": "npm run build",
|
||||
"test": "node --test tests/*.test.mjs",
|
||||
"test:package": "node scripts/test-package.mjs",
|
||||
|
|
|
|||
82
typescript/scripts/pack-clawhub.mjs
Normal file
82
typescript/scripts/pack-clawhub.mjs
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
import { execFile } from "node:child_process";
|
||||
import {
|
||||
copyFile,
|
||||
cp,
|
||||
mkdir,
|
||||
mkdtemp,
|
||||
readFile,
|
||||
rm,
|
||||
writeFile,
|
||||
} from "node:fs/promises";
|
||||
import { tmpdir } from "node:os";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { promisify } from "node:util";
|
||||
|
||||
const execFileAsync = promisify(execFile);
|
||||
const packageDirectory = fileURLToPath(new URL("..", import.meta.url));
|
||||
const destinationDirectory = path.resolve(process.argv[2] ?? packageDirectory);
|
||||
const temporaryDirectory = await mkdtemp(
|
||||
path.join(tmpdir(), "reme-clawhub-pack-"),
|
||||
);
|
||||
const stagingDirectory = path.join(temporaryDirectory, "package");
|
||||
|
||||
try {
|
||||
await mkdir(stagingDirectory, { recursive: true });
|
||||
await mkdir(destinationDirectory, { recursive: true });
|
||||
|
||||
const packageManifest = JSON.parse(
|
||||
await readFile(path.join(packageDirectory, "package.json"), "utf8"),
|
||||
);
|
||||
delete packageManifest.scripts?.prepare;
|
||||
|
||||
await Promise.all([
|
||||
cp(
|
||||
path.join(packageDirectory, "dist"),
|
||||
path.join(stagingDirectory, "dist"),
|
||||
{
|
||||
recursive: true,
|
||||
},
|
||||
),
|
||||
cp(path.join(packageDirectory, "dsh"), path.join(stagingDirectory, "dsh"), {
|
||||
recursive: true,
|
||||
}),
|
||||
writeFile(
|
||||
path.join(stagingDirectory, "package.json"),
|
||||
`${JSON.stringify(packageManifest, null, 2)}\n`,
|
||||
),
|
||||
copyFile(
|
||||
path.join(packageDirectory, "openclaw.plugin.json"),
|
||||
path.join(stagingDirectory, "openclaw.plugin.json"),
|
||||
),
|
||||
copyFile(
|
||||
path.join(packageDirectory, "README_OPENCLAW.md"),
|
||||
path.join(stagingDirectory, "README.md"),
|
||||
),
|
||||
copyFile(
|
||||
path.join(packageDirectory, "README_OPENCLAW_ZH.md"),
|
||||
path.join(stagingDirectory, "README_ZH.md"),
|
||||
),
|
||||
]);
|
||||
|
||||
const { stdout } = await execFileAsync(
|
||||
"npm",
|
||||
[
|
||||
"pack",
|
||||
"--json",
|
||||
"--ignore-scripts",
|
||||
"--pack-destination",
|
||||
destinationDirectory,
|
||||
],
|
||||
{ cwd: stagingDirectory },
|
||||
);
|
||||
const [{ filename }] = JSON.parse(stdout);
|
||||
console.log(
|
||||
JSON.stringify({
|
||||
filename,
|
||||
tarball: path.join(destinationDirectory, filename),
|
||||
}),
|
||||
);
|
||||
} finally {
|
||||
await rm(temporaryDirectory, { force: true, recursive: true });
|
||||
}
|
||||
|
|
@ -1,7 +1,9 @@
|
|||
import { execFile } from "node:child_process";
|
||||
import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
|
||||
import assert from "node:assert/strict";
|
||||
import { mkdir, mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
|
||||
import { tmpdir } from "node:os";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { promisify } from "node:util";
|
||||
|
||||
const execFileAsync = promisify(execFile);
|
||||
|
|
@ -57,6 +59,59 @@ try {
|
|||
].join("\n"),
|
||||
);
|
||||
await execFileAsync("node", [consumerEntry], { cwd: temporaryDirectory });
|
||||
|
||||
const clawHubOutputDirectory = path.join(temporaryDirectory, "clawhub-pack");
|
||||
await mkdir(clawHubOutputDirectory, { recursive: true });
|
||||
const packClawHubScript = fileURLToPath(
|
||||
new URL("./pack-clawhub.mjs", import.meta.url),
|
||||
);
|
||||
const clawHubPackResult = await execFileAsync(
|
||||
"node",
|
||||
[packClawHubScript, clawHubOutputDirectory],
|
||||
{ cwd: packageDirectory },
|
||||
);
|
||||
const { tarball: clawHubTarball } = JSON.parse(clawHubPackResult.stdout);
|
||||
const clawHubConsumerDirectory = path.join(
|
||||
temporaryDirectory,
|
||||
"clawhub-consumer",
|
||||
);
|
||||
await mkdir(clawHubConsumerDirectory, { recursive: true });
|
||||
await writeFile(
|
||||
path.join(clawHubConsumerDirectory, "package.json"),
|
||||
JSON.stringify({ private: true, type: "module" }),
|
||||
);
|
||||
await execFileAsync(
|
||||
"npm",
|
||||
["install", "--ignore-scripts", "--no-audit", "--no-fund", clawHubTarball],
|
||||
{ cwd: clawHubConsumerDirectory },
|
||||
);
|
||||
const clawHubPackageDirectory = path.join(
|
||||
clawHubConsumerDirectory,
|
||||
"node_modules",
|
||||
"@agentscope-ai",
|
||||
"reme",
|
||||
);
|
||||
const clawHubReadme = await readFile(
|
||||
path.join(clawHubPackageDirectory, "README.md"),
|
||||
"utf8",
|
||||
);
|
||||
const clawHubReadmeZh = await readFile(
|
||||
path.join(clawHubPackageDirectory, "README_ZH.md"),
|
||||
"utf8",
|
||||
);
|
||||
assert.match(clawHubReadme, /^# ReMe memory for OpenClaw/m);
|
||||
assert.doesNotMatch(clawHubReadme, /DeepSeek Harness/);
|
||||
assert.match(clawHubReadmeZh, /^# OpenClaw 的 ReMe 长期记忆插件/m);
|
||||
assert.doesNotMatch(clawHubReadmeZh, /DeepSeek Harness/);
|
||||
assert.equal(
|
||||
JSON.parse(
|
||||
await readFile(
|
||||
path.join(clawHubPackageDirectory, "package.json"),
|
||||
"utf8",
|
||||
),
|
||||
).version,
|
||||
sourceManifest.version,
|
||||
);
|
||||
} finally {
|
||||
await rm(temporaryDirectory, { force: true, recursive: true });
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ test("keeps the runtime schema aligned with the OpenClaw manifest", async () =>
|
|||
await readFile(new URL("../openclaw.plugin.json", import.meta.url), "utf8"),
|
||||
);
|
||||
assert.deepEqual(manifest.configSchema, OPENCLAW_CONFIG_SCHEMA);
|
||||
assert.deepEqual(manifest.configUiHints, OPENCLAW_CONFIG_UI_HINTS);
|
||||
assert.deepEqual(manifest.uiHints, OPENCLAW_CONFIG_UI_HINTS);
|
||||
assert.deepEqual(manifest.contracts.tools, ["reme_search"]);
|
||||
assert.equal(manifest.activation.onStartup, true);
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue