@kenhkl/agent-moss 0.15.4 → 0.15.7

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,148 +0,0 @@
1
- """场景定制化规则注册中心(客户沙箱场景级规则)
2
-
3
- 按 `scenario_id` 加载该场景的专属规则集(JSON 单一事实源)。
4
- 规则文件位置:`agent_moss/scenarios/<scenario_id>/rules.json`
5
-
6
- 与 agent 定制规则(agent_moss/agents/<id>/rules.json)**同构**——场景规则也是
7
- `AgentExtensions` 结构(extra_command_patterns / extra_injection_keywords /
8
- extra_sensitive_paths / builtin_safe_skills / builtin_safe_action_types),
9
- 唯一区别是顶层 id 字段叫 `scenario_id` 而非 `agent_id`,由
10
- `AgentExtensions.from_json(..., id_key="scenario_id")` 解析。
11
-
12
- 设计动机:agent 规则靠调用方传 `agent_id`(真实 agent instance 身份)启用;
13
- 场景规则是**部署级**约束(客户沙箱的目录访问边界、禁 ssh 等),没有天然调用方
14
- 身份,启用判定为:
15
- 1. 调用方显式传 `scenario_id`(请求级,与 agent_id 并列)
16
- 2. 兜底环境变量 `AGENT_MOSS_SCENARIO`(部署级,客户沙箱设一次,所有请求生效)
17
- 3. 两者都空 → 通用模式(不加载场景规则)
18
-
19
- 使用:
20
- from agent_moss.scenarios import get_scenario_extensions
21
- ext = get_scenario_extensions("bank")
22
- if ext:
23
- # 把 ext.extra_command_patterns 追加到 agent_ext/通用规则之后
24
- ...
25
-
26
- Python 与 TypeScript 两端共享同一份 rules.json:
27
- - py: agent_moss/scenarios/__init__.py:get_scenario_extensions
28
- - ts: ts/src/scenarios/index.ts:getScenarioExtensions
29
-
30
- 无 scenario_id 或 rules.json 不存在时返回 None(通用模式)。
31
- """
32
-
33
- from pathlib import Path
34
- import threading
35
- import logging
36
-
37
- # 场景规则与 agent 规则同构:复用 AgentExtensions 数据载体(agents/base.py)
38
- from ..agents.base import AgentExtensions, InjectionKeyword, CommandPattern, SensitivePath # noqa: F401
39
-
40
- logger = logging.getLogger(__name__)
41
-
42
- _SCENARIOS_DIR = Path(__file__).parent
43
- _cache: dict[str, AgentExtensions | None] = {}
44
- _lock = threading.Lock()
45
-
46
-
47
- def get_scenario_extensions(scenario_id: str) -> AgentExtensions | None:
48
- """按 scenario_id 加载该场景的专属规则集。
49
-
50
- Args:
51
- scenario_id: 场景标识,如 "bank"。空字符串返回 None(通用模式)。
52
-
53
- Returns:
54
- AgentExtensions 实例,或 None(无场景专属规则 / rules.json 不存在)。
55
- """
56
- if not scenario_id:
57
- return None
58
-
59
- # 双重检查锁定,避免并发重复 IO
60
- if scenario_id in _cache:
61
- return _cache[scenario_id]
62
-
63
- with _lock:
64
- if scenario_id in _cache:
65
- return _cache[scenario_id]
66
-
67
- # 统一存储:优先读 runtime_config 的 scenario_rules 分区(用户可在 console
68
- # 查看/编辑/禁用/新增,与 agent_rules 同构,享受一致的合并升级)。回退
69
- # rules.json(无 runtime_config 时,如直接起服务未 seed、或旧部署)。
70
- ext = None
71
- try:
72
- from ..infra.runtime_config import (has_runtime_config, load_runtime_config,
73
- get_enabled_scenario_extensions)
74
- if has_runtime_config():
75
- ext = get_enabled_scenario_extensions(load_runtime_config(), scenario_id)
76
- except Exception:
77
- pass # runtime_config 不可用时回退 rules.json
78
-
79
- if ext is None:
80
- rules_file = _SCENARIOS_DIR / scenario_id / "rules.json"
81
- if not rules_file.exists():
82
- logger.debug("场景 %s 无 rules.json,走通用模式", scenario_id)
83
- _cache[scenario_id] = None
84
- return None
85
- try:
86
- ext = AgentExtensions.from_json(rules_file, id_key="scenario_id")
87
- except Exception as e:
88
- logger.error("加载场景 %s rules.json 失败: %s", scenario_id, e)
89
- _cache[scenario_id] = None
90
- return None
91
-
92
- _cache[scenario_id] = ext
93
- logger.info(
94
- "加载场景 %s 定制规则: %d cmd patterns, %d injection keywords, "
95
- "%d sensitive paths, %d builtin safe skills, %d builtin safe action types",
96
- scenario_id,
97
- len(ext.extra_command_patterns),
98
- len(ext.extra_injection_keywords),
99
- len(ext.extra_sensitive_paths),
100
- len(ext.builtin_safe_skills),
101
- len(ext.builtin_safe_action_types),
102
- )
103
- return ext
104
-
105
-
106
- def clear_scenario_extensions_cache() -> None:
107
- """清空场景扩展缓存(用于测试或 rules.json 热加载)"""
108
- with _lock:
109
- _cache.clear()
110
-
111
-
112
- def get_scenario_extensions_multi(scenario_spec: str | None) -> AgentExtensions | None:
113
- """按逗号分隔的场景列表加载并合并扩展(AGENT_MOSS_SCENARIO 支持多场景)。
114
-
115
- 引擎层兜底 env 时使用:`AGENT_MOSS_SCENARIO=bank,meow` 会被拆成多个场景 id,
116
- 逐个加载后合并成一个 AgentExtensions(append 语义,与 console 的
117
- _enabled_scenario_ids 逗号分隔口径一致)。
118
-
119
- Args:
120
- scenario_spec: 逗号分隔的场景 id 字符串(可为空)。
121
-
122
- Returns:
123
- 合并后的 AgentExtensions,或 None(无任何场景可加载)。
124
- """
125
- if not scenario_spec:
126
- return None
127
- ids = [s.strip() for s in scenario_spec.split(",") if s.strip()]
128
- if not ids:
129
- return None
130
- exts = [get_scenario_extensions(sid) for sid in ids]
131
- non_null = [e for e in exts if e is not None]
132
- if not non_null:
133
- return None
134
- merged: AgentExtensions | None = non_null[0]
135
- for e in non_null[1:]:
136
- merged = AgentExtensions.merge(merged, e)
137
- return merged
138
-
139
-
140
- __all__ = [
141
- "AgentExtensions",
142
- "InjectionKeyword",
143
- "CommandPattern",
144
- "SensitivePath",
145
- "get_scenario_extensions",
146
- "get_scenario_extensions_multi",
147
- "clear_scenario_extensions_cache",
148
- ]