mirror of
https://github.com/agentscope-ai/ReMe.git
synced 2026-11-10 08:28:22 +00:00
Adds a read-only Environment tab to the ReMe Memory settings card so users can see why the ReMe service is unreachable before touching a terminal: - discover local Python interpreters via the PEP 514 registry, py launcher, PATH and conda (base + named envs), then verify every candidate by actually running it - classify origins (conda base/env, python.org, Microsoft Store, venv, system PATH), drop Store alias stubs, and suggest a preferred interpreter (Python >= 3.11, named conda envs first) - expose detection to the browser through a new remeEnv host gateway (TypertRemoteService) and render it with a connection health check - config gains optional authToken and pythonPath fields with unchanged defaults; existing memory settings keep their behavior Parsing is fixture-tested against real tool output on Windows (GBK codepages, localized reg labels, missing py launcher) and Linux.
146 lines
4.2 KiB
JavaScript
146 lines
4.2 KiB
JavaScript
import assert from "node:assert/strict";
|
|
import { readFile } from "node:fs/promises";
|
|
import { createRequire } from "node:module";
|
|
import test from "node:test";
|
|
import vm from "node:vm";
|
|
import semver from "semver";
|
|
|
|
test("declares one installable DeepSeek Harness plugin", async () => {
|
|
const manifest = JSON.parse(
|
|
await readFile(new URL("../package.json", import.meta.url), "utf8"),
|
|
);
|
|
const patch = await readFile(
|
|
new URL("../cordis.patch.yml", import.meta.url),
|
|
"utf8",
|
|
);
|
|
assert.equal(manifest.name, "@agentscope-ai/reme-dsh-plugin");
|
|
assert.equal(manifest.exports["."].import, "./dist/index.js");
|
|
assert.equal(manifest.exports["./client"].default, "./dist/client.js");
|
|
assert.equal(manifest.dsh.client.platform, "web");
|
|
assert.equal(manifest.dsh.bundle.patch, "./cordis.patch.yml");
|
|
assert.equal(manifest.dependencies, undefined);
|
|
for (const dependency of [
|
|
"@deepseek-ai/dsh-client-ui-primitives",
|
|
"@deepseek-ai/dsh-llm",
|
|
"@deepseek-ai/dsh-tools",
|
|
"@deepseek-ai/dsh-typert-protocol",
|
|
]) {
|
|
for (const version of [
|
|
"0.1.7-rc.2",
|
|
"0.2.0-rc.2",
|
|
"0.2.1-alpha.2",
|
|
"0.2.1-alpha.4",
|
|
"0.2.1-rc.2",
|
|
]) {
|
|
assert.ok(
|
|
semver.satisfies(version, manifest.peerDependencies[dependency]),
|
|
);
|
|
}
|
|
for (const version of [
|
|
"0.1.6",
|
|
"0.2.0-rc.1",
|
|
"0.2.2-alpha.1",
|
|
"0.3.0-alpha.1",
|
|
"0.3.0",
|
|
]) {
|
|
assert.equal(
|
|
semver.satisfies(version, manifest.peerDependencies[dependency]),
|
|
false,
|
|
);
|
|
}
|
|
assert.equal(manifest.peerDependenciesMeta[dependency]?.optional, true);
|
|
}
|
|
assert.equal(manifest.peerDependencies.openclaw, undefined);
|
|
assert.match(patch, /remeMemory: true/);
|
|
assert.match(patch, /id: reme-memory-scope[\s\S]*id: reme-memory\r?\n/);
|
|
assert.doesNotMatch(patch, /id: reme-memory-runtime/);
|
|
assert.doesNotMatch(patch, /@agentscope-ai\/reme\/dsh/);
|
|
assert.equal(patch.match(/@agentscope-ai\/reme-dsh-plugin/g)?.length, 1);
|
|
assert.doesNotMatch(patch, /reme-memory-client/);
|
|
});
|
|
|
|
test("builds a lazy DSH browser module for the ReMe settings card", async () => {
|
|
const bundle = await readFile(
|
|
new URL("../dist/client.js", import.meta.url),
|
|
"utf8",
|
|
);
|
|
const statusPage = await readFile(
|
|
new URL("../src/client/status-page.tsx", import.meta.url),
|
|
"utf8",
|
|
);
|
|
assert.match(bundle, /window\.__ModuleLoader__\.load/);
|
|
assert.match(bundle, /id: "@agentscope-ai\/reme-dsh-plugin"/);
|
|
assert.match(bundle, /plugins\.row\.config/);
|
|
assert.match(bundle, /reme-status/);
|
|
assert.match(bundle, /Personal Knowledge Base/);
|
|
assert.match(statusPage, /个人知识库/);
|
|
assert.match(bundle, /health_check/);
|
|
});
|
|
|
|
test("registers configuration on the ReMe bundle row", async () => {
|
|
const bundle = await readFile(
|
|
new URL("../dist/client.js", import.meta.url),
|
|
"utf8",
|
|
);
|
|
let module;
|
|
const document = {
|
|
head: { appendChild() {} },
|
|
createElement() {
|
|
return { dataset: {}, remove() {} };
|
|
},
|
|
};
|
|
vm.runInNewContext(bundle, {
|
|
document,
|
|
window: {
|
|
__ModuleLoader__: {
|
|
load(value) {
|
|
module = value;
|
|
},
|
|
},
|
|
},
|
|
});
|
|
const nodeRequire = createRequire(import.meta.url);
|
|
const client = module.factory((name) =>
|
|
name === "@deepseek-ai/dsh-client-ui-primitives" ? {} : nodeRequire(name),
|
|
);
|
|
const registrations = [];
|
|
const ctx = {
|
|
locale: {
|
|
bind() {
|
|
return (key) => (key === "title" ? "ReMe Memory" : key);
|
|
},
|
|
register() {
|
|
return () => {};
|
|
},
|
|
},
|
|
configForms: {
|
|
get() {
|
|
return {};
|
|
},
|
|
whileServed(_namespaces, register) {
|
|
return register();
|
|
},
|
|
},
|
|
slots: {
|
|
inject(_name, register) {
|
|
return register();
|
|
},
|
|
register(options) {
|
|
registrations.push(options);
|
|
return () => {};
|
|
},
|
|
},
|
|
get() {
|
|
return { rpc: {} };
|
|
},
|
|
effect(execute) {
|
|
return execute();
|
|
},
|
|
};
|
|
client.apply(ctx);
|
|
const item = registrations.find(
|
|
(options) => options.name === "plugins.row.config",
|
|
);
|
|
assert.equal(item.key, "@agentscope-ai/reme-dsh-plugin#reme-memory");
|
|
assert.equal(item.label(), "ReMe Memory");
|
|
});
|