@modelstudio/modelstudio-memory-for-openclaw 1.0.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -57,8 +57,8 @@ openclaw modelstudio-memory stats
57
57
  enabled: true,
58
58
  config: {
59
59
  // 必需配置
60
- "apiKey": "${DASHSCOPE_API_KEY}",
61
- "userId": "user_001",
60
+ "apiKey": "your-dashscope-api-key",
61
+ "userId": "openclaw_memory",
62
62
 
63
63
  // 可选配置(以下为默认值)
64
64
  "baseUrl": "https://dashscope.aliyuncs.com/api/v2/apps/memory",
@@ -80,8 +80,8 @@ openclaw modelstudio-memory stats
80
80
 
81
81
  | 配置项 | 类型 | 必需 | 默认值 | 说明 |
82
82
  |--------|------|------|--------|------|
83
- | `apiKey` | `string` | ✅ | - | DashScope API Key,支持 `${ENV_VAR}` 格式 |
84
- | `userId` | `string` | | - | 用户 ID,用于隔离不同用户的记忆 |
83
+ | `apiKey` | `string` | ✅ | - | DashScope API Key(在 openclaw.json 中配置) |
84
+ | `userId` | `string` | | `openclaw_memory` | 用户 ID,用于隔离不同用户的记忆 |
85
85
  | `baseUrl` | `string` | ❌ | `https://dashscope.aliyuncs.com/api/v2/apps/memory` | API endpoint(私有部署时填写完整 URL) |
86
86
  | `autoCapture` | `boolean` | ❌ | `true` | 是否自动捕获对话 |
87
87
  | `autoRecall` | `boolean` | ❌ | `true` | 是否自动召回记忆 |
@@ -91,17 +91,11 @@ openclaw modelstudio-memory stats
91
91
  | `recallMinPromptLength` | `number` | ❌ | `10` | 触发自动召回的最小 prompt 长度 |
92
92
  | `recallCacheTtlMs` | `number` | ❌ | `300000` | 召回缓存时间(毫秒),0 禁用缓存 |
93
93
 
94
- ## 环境变量
94
+ ## 获取 API Key
95
95
 
96
- ```bash
97
- # 设置 DashScope API Key
98
- export DASHSCOPE_API_KEY="your-api-key"
99
-
100
- # 重启 Gateway
101
- openclaw gateway restart
102
- ```
96
+ 在 [阿里云百炼控制台](https://help.aliyun.com/zh/model-studio/get-api-key) 获取 DashScope API Key,并在 `openclaw.json` 的 `config.apiKey` 中配置。
103
97
 
104
- 获取 API Key:https://help.aliyun.com/zh/model-studio/get-api-key
98
+ **提示**:若安装后未配置 apiKey,插件仍会加载。当用户使用记忆功能(如询问「我之前说过什么」)时,Agent 会提示用户配置 apiKey。
105
99
 
106
100
  ## 使用方法
107
101
 
@@ -230,7 +224,7 @@ tail -f ~/.openclaw/logs/gateway.log | grep modelstudio-memory
230
224
 
231
225
  | 错误 | 原因 | 解决方案 |
232
226
  |------|------|----------|
233
- | `apiKey is required` | 未配置 API Key | 设置 `DASHSCOPE_API_KEY` 环境变量 |
227
+ | `apiKey is required` | 未配置 API Key | openclaw.json config 中配置 apiKey |
234
228
  | `InvalidApiKey` | API Key 无效 | 检查 API Key 是否正确 |
235
229
  | `TooManyRequests` | 请求频率过高 | 降低调用频率 |
236
230
 
package/index.ts CHANGED
@@ -80,14 +80,6 @@ const ALLOWED_KEYS = [
80
80
  "recallCacheTtlMs",
81
81
  ];
82
82
 
83
- function resolveEnvVars(value: string): string {
84
- if (!value) return value;
85
- return value.replace(/\$\{([^}]+)\}/g, (_, key) => {
86
- const envValue = process.env[key];
87
- return envValue || "";
88
- });
89
- }
90
-
91
83
  function assertAllowedKeys(
92
84
  value: Record<string, unknown>,
93
85
  allowed: string[],
@@ -106,17 +98,9 @@ const modelstudioMemoryConfigSchema = {
106
98
  const cfg = value as Record<string, unknown>;
107
99
  assertAllowedKeys(cfg, ALLOWED_KEYS, "modelstudio-memory-for-openclaw config");
108
100
 
109
- // apiKey is required
110
- const apiKey = typeof cfg.apiKey === "string" ? resolveEnvVars(cfg.apiKey) : "";
111
- if (!apiKey) {
112
- throw new Error("apiKey is required for modelstudio-memory-for-openclaw");
113
- }
114
-
115
- // userId is required
116
- const userId = typeof cfg.userId === "string" ? cfg.userId : "";
117
- if (!userId) {
118
- throw new Error("userId is required for modelstudio-memory-for-openclaw");
119
- }
101
+ // apiKey: allow empty at parse time; tools return config prompt when missing
102
+ const apiKey = typeof cfg.apiKey === "string" ? cfg.apiKey : "";
103
+ const userId = typeof cfg.userId === "string" && cfg.userId ? cfg.userId : "openclaw_memory";
120
104
 
121
105
  return {
122
106
  apiKey,
@@ -373,6 +357,9 @@ function stripInjectedContext(text: string): string {
373
357
  return text.replace(/<relevant-memories>[\s\S]*?<\/relevant-memories>\s*/g, "").trim();
374
358
  }
375
359
 
360
+ const CONFIG_REQUIRED_MESSAGE =
361
+ "Memory plugin is not configured. Please add apiKey and userId to ~/.openclaw/openclaw.json under plugins.entries.modelstudio-memory-for-openclaw.config. Get API Key: https://help.aliyun.com/zh/model-studio/get-api-key";
362
+
376
363
  // ============================================================================
377
364
  // Plugin Definition
378
365
  // ============================================================================
@@ -393,6 +380,11 @@ const modelstudioMemoryPlugin = {
393
380
  api.logger
394
381
  );
395
382
 
383
+ if (!cfg.apiKey) {
384
+ api.logger.warn(
385
+ "modelstudio-memory: apiKey not configured. Memory features disabled until config is added to openclaw.json."
386
+ );
387
+ }
396
388
  api.logger.info(
397
389
  `modelstudio-memory: registered (user: ${cfg.userId}, autoCapture: ${cfg.autoCapture}, autoRecall: ${cfg.autoRecall})`
398
390
  );
@@ -413,6 +405,12 @@ const modelstudioMemoryPlugin = {
413
405
  ),
414
406
  }),
415
407
  async execute(_id, params) {
408
+ if (!cfg.apiKey) {
409
+ return {
410
+ content: [{ type: "text", text: CONFIG_REQUIRED_MESSAGE }],
411
+ isError: true,
412
+ };
413
+ }
416
414
  try {
417
415
  const limit = Math.min(
418
416
  Math.max(1, params.limit ?? cfg.topK),
@@ -484,6 +482,12 @@ const modelstudioMemoryPlugin = {
484
482
  content: Type.String({ description: "Content to store" }),
485
483
  }),
486
484
  async execute(_id, params) {
485
+ if (!cfg.apiKey) {
486
+ return {
487
+ content: [{ type: "text", text: CONFIG_REQUIRED_MESSAGE }],
488
+ isError: true,
489
+ };
490
+ }
487
491
  try {
488
492
  const result = await client.addCustomContent(params.content);
489
493
 
@@ -529,6 +533,12 @@ const modelstudioMemoryPlugin = {
529
533
  ),
530
534
  }),
531
535
  async execute(_id, params) {
536
+ if (!cfg.apiKey) {
537
+ return {
538
+ content: [{ type: "text", text: CONFIG_REQUIRED_MESSAGE }],
539
+ isError: true,
540
+ };
541
+ }
532
542
  try {
533
543
  const page = Math.max(1, params.page ?? 1);
534
544
  const pageSize = Math.min(100, Math.max(1, params.pageSize ?? 10));
@@ -589,6 +599,12 @@ const modelstudioMemoryPlugin = {
589
599
  index: Type.Optional(Type.Number({ description: "Delete Nth memory (1-based)" })),
590
600
  }),
591
601
  async execute(_id, params) {
602
+ if (!cfg.apiKey) {
603
+ return {
604
+ content: [{ type: "text", text: CONFIG_REQUIRED_MESSAGE }],
605
+ isError: true,
606
+ };
607
+ }
592
608
  try {
593
609
  let targetId = params.memoryId;
594
610
 
@@ -706,6 +722,7 @@ const modelstudioMemoryPlugin = {
706
722
  // ========== autoRecall ==========
707
723
  if (cfg.autoRecall) {
708
724
  api.on("before_agent_start", async (event) => {
725
+ if (!cfg.apiKey) return;
709
726
  const prompt = extractTextContent(event.prompt);
710
727
  if (!prompt || prompt.length < cfg.recallMinPromptLength) {
711
728
  return;
@@ -739,7 +756,7 @@ const modelstudioMemoryPlugin = {
739
756
  // ========== autoCapture ==========
740
757
  if (cfg.autoCapture) {
741
758
  api.on("agent_end", async (event) => {
742
- if (!event.success || !event.messages) {
759
+ if (!cfg.apiKey || !event.success || !event.messages) {
743
760
  return;
744
761
  }
745
762
 
@@ -814,6 +831,10 @@ const modelstudioMemoryPlugin = {
814
831
  .argument("<query>", "Search query")
815
832
  .option("--limit <n>", "Max results", String(cfg.topK))
816
833
  .action(async (query: string, opts: { limit: string }) => {
834
+ if (!cfg.apiKey) {
835
+ console.error(CONFIG_REQUIRED_MESSAGE);
836
+ return;
837
+ }
817
838
  try {
818
839
  const limit = Math.min(100, Math.max(1, parseInt(opts.limit, 10) || cfg.topK));
819
840
  const cleanQuery = extractTextContent(query) || query.trim();
@@ -848,6 +869,10 @@ const modelstudioMemoryPlugin = {
848
869
  .command("stats")
849
870
  .description("Show memory statistics")
850
871
  .action(async () => {
872
+ if (!cfg.apiKey) {
873
+ console.error(CONFIG_REQUIRED_MESSAGE);
874
+ return;
875
+ }
851
876
  try {
852
877
  const result = await client.listMemory(1, 1);
853
878
  console.log(`User: ${cfg.userId}`);
@@ -867,6 +892,10 @@ const modelstudioMemoryPlugin = {
867
892
  .option("--page <n>", "Page number", "1")
868
893
  .option("--size <n>", "Page size", "10")
869
894
  .action(async (opts: { page: string; size: string }) => {
895
+ if (!cfg.apiKey) {
896
+ console.error(CONFIG_REQUIRED_MESSAGE);
897
+ return;
898
+ }
870
899
  try {
871
900
  const page = Math.max(1, parseInt(opts.page, 10) || 1);
872
901
  const size = Math.min(100, Math.max(1, parseInt(opts.size, 10) || 10));
@@ -3,18 +3,18 @@
3
3
  "name": "modelstudio-memory-for-openclaw",
4
4
  "description": "阿里云百炼长期记忆服务,提供自动记忆捕获和召回能力",
5
5
  "kind": "memory",
6
- "version": "1.0.0",
6
+ "version": "1.0.2",
7
7
  "configSchema": {
8
8
  "type": "object",
9
9
  "additionalProperties": false,
10
10
  "properties": {
11
11
  "apiKey": {
12
12
  "type": "string",
13
- "description": "DashScope API Key(支持环境变量 ${DASHSCOPE_API_KEY})"
13
+ "description": "DashScope API Key"
14
14
  },
15
15
  "userId": {
16
16
  "type": "string",
17
- "description": "用户 ID,用于隔离不同用户的记忆"
17
+ "description": "用户 ID,用于隔离不同用户的记忆(默认 'openclaw_memory')"
18
18
  },
19
19
  "baseUrl": {
20
20
  "type": "string",
@@ -62,11 +62,11 @@
62
62
  "apiKey": {
63
63
  "label": "API Key",
64
64
  "sensitive": true,
65
- "placeholder": "${DASHSCOPE_API_KEY}"
65
+ "placeholder": "sk-..."
66
66
  },
67
67
  "userId": {
68
68
  "label": "用户 ID",
69
- "placeholder": "user_001"
69
+ "placeholder": "openclaw_memory"
70
70
  },
71
71
  "baseUrl": {
72
72
  "label": "API Endpoint",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@modelstudio/modelstudio-memory-for-openclaw",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "type": "module",
5
5
  "description": "阿里云百炼长期记忆服务 OpenClaw 插件",
6
6
  "license": "Apache-2.0",