sophhub 0.4.18 → 0.4.19

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.
@@ -1,7 +1,8 @@
1
1
  {
2
- "version": "1.1.0",
2
+ "version": "1.2.0",
3
3
  "agent_id": "intern-admin",
4
4
  "description": "实习事务管理员:维护实习相关 knowledge/、workspace-intern-qa/records/(日报按日、请假 leave.md),并配合配对实习生答疑实例",
5
+ "auto_generate_image_description": false,
5
6
  "bot_api_enabled": false,
6
7
  "workspace": "/home/node/.openclaw/workspace-intern",
7
8
  "agent_dependencies": [],
@@ -1,7 +1,8 @@
1
1
  {
2
- "version": "1.1.0",
2
+ "version": "1.2.0",
3
3
  "agent_id": "intern-qa",
4
4
  "description": "实习生助手 bot:只读 knowledge/ 答疑;日报按日追加 records/,请假单独 records/leave.md(解析公历日期);归档查询;memory/ 备忘;预装 image-description",
5
+ "auto_generate_image_description": false,
5
6
  "bot_api_enabled": true,
6
7
  "workspace": "/home/node/.openclaw/workspace-intern/workspace-intern-qa",
7
8
  "agent_dependencies": ["intern-admin"],
@@ -1,7 +1,9 @@
1
1
  {
2
- "version": "1.0.0",
2
+ "version": "1.1.0",
3
3
  "agent_id": "parent-toddler",
4
+ "agent_label": "幼儿家长助手",
4
5
  "description": "面向幼儿家长的成长陪伴助手:亲子互动、图片与多媒体创作、日常记录与轻量咨询",
6
+ "auto_generate_image_description": false,
5
7
  "bot_api_enabled": false,
6
8
  "workspace": "/home/node/.openclaw/workspace-parent-toddler",
7
9
  "agent_dependencies": [],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sophhub",
3
- "version": "0.4.18",
3
+ "version": "0.4.19",
4
4
  "description": "SophHub CLI - Manage and download AI Agent skills",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,12 +1,19 @@
1
1
  {
2
2
  "name": "agent-install",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "types": [
5
5
  "store"
6
6
  ],
7
7
  "displayName": "Agent安装",
8
8
  "description": "通用 Agent 安装与升级。",
9
9
  "changelog": [
10
+ {
11
+ "changes": [
12
+ "update_openclaw 根据 .config.json 的 auto_generate_image_description 同步自动生成图片描述开关(默认开启)"
13
+ ],
14
+ "date": "2026-05-15",
15
+ "version": "0.1.5"
16
+ },
10
17
  {
11
18
  "changes": [
12
19
  "修复依赖 Agent 使用自定义 openclaw_id 时的安装检测逻辑"
@@ -23,5 +30,5 @@
23
30
  }
24
31
  ],
25
32
  "createdAt": "2026-04-21",
26
- "updatedAt": "2026-04-21"
33
+ "updatedAt": "2026-05-15"
27
34
  }
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: agent-install
3
3
  description: 安装或升级通用 OpenClaw Agent(含按 .config.json 自动下载 skill)。Use when the user asks to install an agent, upgrade an agent, download agent config, back up an existing agent, update openclaw.json, or install skills listed with auto_install.
4
- version: 0.1.0
4
+ version: 0.1.5
5
5
  ---
6
6
 
7
7
  # Agent Install
@@ -165,6 +165,8 @@ uv run {baseDir}/scripts/update_openclaw.py \
165
165
  --name "{agent_name}"
166
166
  ```
167
167
 
168
+ **自动生成图片描述**:Agent 包 `.config.json` 顶层可选 **`auto_generate_image_description`**(布尔);不写或与 `true` 为开启,`false` 为关闭。与 **`update_openclaw.py`** 一并生效;具体写入 **`openclaw.json`** 的规则以实现为准,脚本标准输出中含 **`auto_generate_image_description`** 字段便于核对。
169
+
168
170
  `NOT_INSTALLED` 无备份,直接 2)。`UPDATABLE` / `SAME_VERSION_REINSTALL` 须已完成 1)。
169
171
 
170
172
  **输入模版(仅要备份时)**
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "agent-install"
3
- version = "0.1.4"
3
+ version = "0.1.5"
4
4
  description = "通用 Agent 安装与升级"
5
5
  requires-python = ">=3.10"
6
6
  dependencies = []
@@ -231,16 +231,25 @@ def build_agent_entry(
231
231
  ) -> dict[str, Any]:
232
232
  source_agent_id = agent_def["agent_id"]
233
233
  agent_id = target_id_override.strip() if isinstance(target_id_override, str) and target_id_override.strip() else source_agent_id
234
- install = agent_def.get("install", {})
235
- identity = install.get("identity", {})
234
+ install = agent_def.get("install", {}) if isinstance(agent_def.get("install"), dict) else {}
235
+ identity = install.get("identity", {}) if isinstance(install.get("identity"), dict) else {}
236
236
  resolved_name = name_override.strip() if isinstance(name_override, str) and name_override.strip() else None
237
237
 
238
- display_name = resolved_name or install.get("name") or identity.get("name") or source_agent_id
238
+ install_name_raw = install.get("name")
239
+ install_name_str = install_name_raw.strip() if isinstance(install_name_raw, str) and install_name_raw.strip() else None
240
+
241
+ identity_name_raw = identity.get("name")
242
+ identity_name_str = identity_name_raw.strip() if isinstance(identity_name_raw, str) and identity_name_raw.strip() else None
243
+
244
+ agent_label_raw = agent_def.get("agent_label")
245
+ agent_label_str = agent_label_raw.strip() if isinstance(agent_label_raw, str) and agent_label_raw.strip() else None
246
+
247
+ display_name = resolved_name or install_name_str or identity_name_str or agent_label_str or source_agent_id
239
248
  entry: dict[str, Any] = {
240
249
  "id": agent_id,
241
250
  "workspace": desired_workspace(agent_def, workspace_override),
242
251
  "identity": {
243
- "name": resolved_name or identity.get("name", display_name),
252
+ "name": resolved_name or identity_name_str or agent_label_str or display_name,
244
253
  "theme": identity.get("theme", display_name),
245
254
  "emoji": identity.get("emoji", "🤖"),
246
255
  },
@@ -248,8 +257,8 @@ def build_agent_entry(
248
257
 
249
258
  if resolved_name:
250
259
  entry["name"] = resolved_name
251
- elif install.get("name"):
252
- entry["name"] = install["name"]
260
+ elif install_name_str:
261
+ entry["name"] = install_name_str
253
262
 
254
263
  if install.get("agent_dir"):
255
264
  entry["agentDir"] = install["agent_dir"]
@@ -285,15 +294,20 @@ def build_bot_api_account(
285
294
  if not agent_def.get("bot_api_enabled"):
286
295
  return None
287
296
 
288
- install = agent_def.get("install", {})
289
- identity = install.get("identity", {})
290
- bot_api = install.get("bot_api", {})
297
+ install = agent_def.get("install", {}) if isinstance(agent_def.get("install"), dict) else {}
298
+ identity = install.get("identity", {}) if isinstance(install.get("identity"), dict) else {}
299
+ bot_api = install.get("bot_api", {}) if isinstance(install.get("bot_api"), dict) else {}
291
300
  resolved_name = name_override.strip() if isinstance(name_override, str) and name_override.strip() else None
292
301
 
302
+ identity_name_raw = identity.get("name")
303
+ identity_name_str = identity_name_raw.strip() if isinstance(identity_name_raw, str) and identity_name_raw.strip() else None
304
+ agent_label_raw = agent_def.get("agent_label")
305
+ agent_label_str = agent_label_raw.strip() if isinstance(agent_label_raw, str) and agent_label_raw.strip() else None
306
+
293
307
  source_agent_id = agent_def["agent_id"]
294
308
  agent_id = agent_id_override.strip() if isinstance(agent_id_override, str) and agent_id_override.strip() else source_agent_id
295
309
  account_id = bot_api.get("account_id", agent_id)
296
- account_name = bot_api.get("account_name") or resolved_name or identity.get("name", source_agent_id)
310
+ account_name = bot_api.get("account_name") or resolved_name or identity_name_str or agent_label_str or source_agent_id
297
311
  enabled = bot_api.get("enabled", True)
298
312
 
299
313
  return account_id, {
@@ -485,3 +499,70 @@ def deep_merge_dict(base: dict[str, Any], override: dict[str, Any]) -> dict[str,
485
499
  else:
486
500
  result[key] = deepcopy(value)
487
501
  return result
502
+
503
+
504
+ def auto_generate_image_description_prefix(openclaw_agent_id: str) -> str:
505
+ """与 openclaw.json 中 tools.media.image.scope.rules.match.keyPrefix 对齐。"""
506
+ aid = openclaw_agent_id.strip() if isinstance(openclaw_agent_id, str) else ""
507
+ return f"agent:{aid}:" if aid else ""
508
+
509
+
510
+ def is_auto_generate_image_description_enabled(agent_def: dict[str, Any]) -> bool:
511
+ """未设置或为真时启用自动生成图片描述;仅当显式为 false 时关闭。"""
512
+ raw = agent_def.get("auto_generate_image_description")
513
+ if raw is None:
514
+ return True
515
+ if isinstance(raw, bool):
516
+ return raw
517
+ return bool(raw)
518
+
519
+
520
+ def _rule_is_auto_image_description_deny(rule: Any, key_prefix: str) -> bool:
521
+ if not isinstance(rule, dict):
522
+ return False
523
+ if rule.get("action") != "deny":
524
+ return False
525
+ match = rule.get("match")
526
+ if not isinstance(match, dict):
527
+ return False
528
+ return match.get("keyPrefix") == key_prefix
529
+
530
+
531
+ def sync_openclaw_auto_image_description_rules(
532
+ config: dict[str, Any],
533
+ openclaw_agent_id: str,
534
+ *,
535
+ enabled: bool,
536
+ ) -> None:
537
+ """
538
+ 同步根级 tools.media.image.scope.rules:
539
+ - enabled=True:移除本安装流程写入的 deny(keyPrefix agent:<id>:)
540
+ - enabled=False:确保存在对应 deny 规则(与产品侧「关闭自动生成图片描述」一致)
541
+ """
542
+ key_prefix = auto_generate_image_description_prefix(openclaw_agent_id)
543
+ if not key_prefix:
544
+ return
545
+
546
+ tools = config.setdefault("tools", {})
547
+ media = tools.setdefault("media", {})
548
+ image = media.setdefault("image", {})
549
+ scope = image.setdefault("scope", {})
550
+ scope.setdefault("default", "allow")
551
+ rules_any = scope.setdefault("rules", [])
552
+ if not isinstance(rules_any, list):
553
+ scope["rules"] = []
554
+ rules_any = scope["rules"]
555
+
556
+ if enabled:
557
+ scope["rules"] = [r for r in rules_any if not _rule_is_auto_image_description_deny(r, key_prefix)]
558
+ return
559
+
560
+ if any(_rule_is_auto_image_description_deny(r, key_prefix) for r in rules_any):
561
+ return
562
+
563
+ rules_any.append(
564
+ {
565
+ "action": "deny",
566
+ "match": {"keyPrefix": key_prefix},
567
+ }
568
+ )
@@ -15,9 +15,11 @@ from common import (
15
15
  find_agent_entry,
16
16
  find_bot_api_accounts_by_agent_id,
17
17
  find_agent_by_workspace,
18
+ is_auto_generate_image_description_enabled,
18
19
  load_agent_definition,
19
20
  load_openclaw_config,
20
21
  resolve_existing_agent_entry,
22
+ sync_openclaw_auto_image_description_rules,
21
23
  write_install_state,
22
24
  )
23
25
 
@@ -125,6 +127,13 @@ def update_openclaw(
125
127
  name_override=resolved_name,
126
128
  )
127
129
 
130
+ auto_img_desc = is_auto_generate_image_description_enabled(agent_def)
131
+ sync_openclaw_auto_image_description_rules(
132
+ config,
133
+ target_agent_id,
134
+ enabled=auto_img_desc,
135
+ )
136
+
128
137
  dump_json(config_path, config)
129
138
  state_path = write_install_state(
130
139
  config_path,
@@ -149,6 +158,7 @@ def update_openclaw(
149
158
  "previous_workspace": previous.get("workspace") if previous else None,
150
159
  "version": agent_def["version"],
151
160
  "install_state": str(state_path),
161
+ "auto_generate_image_description": auto_img_desc,
152
162
  }
153
163
 
154
164