cognitive-modules 0.5.0__py3-none-any.whl → 0.5.1__py3-none-any.whl
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.
- cognitive/__init__.py +1 -1
- cognitive/loader.py +17 -6
- cognitive/runner.py +60 -26
- {cognitive_modules-0.5.0.dist-info → cognitive_modules-0.5.1.dist-info}/METADATA +19 -5
- {cognitive_modules-0.5.0.dist-info → cognitive_modules-0.5.1.dist-info}/RECORD +9 -9
- {cognitive_modules-0.5.0.dist-info → cognitive_modules-0.5.1.dist-info}/WHEEL +0 -0
- {cognitive_modules-0.5.0.dist-info → cognitive_modules-0.5.1.dist-info}/entry_points.txt +0 -0
- {cognitive_modules-0.5.0.dist-info → cognitive_modules-0.5.1.dist-info}/licenses/LICENSE +0 -0
- {cognitive_modules-0.5.0.dist-info → cognitive_modules-0.5.1.dist-info}/top_level.txt +0 -0
cognitive/__init__.py
CHANGED
cognitive/loader.py
CHANGED
|
@@ -166,12 +166,23 @@ def load_v2_format(module_path: Path) -> dict:
|
|
|
166
166
|
tier: Optional[ModuleTier] = manifest.get("tier")
|
|
167
167
|
schema_strictness: SchemaStrictness = manifest.get("schema_strictness", "medium")
|
|
168
168
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
"
|
|
173
|
-
"
|
|
174
|
-
|
|
169
|
+
# Determine default max_items based on strictness (SPEC-v2.2)
|
|
170
|
+
# high=0 (disabled), medium=5, low=20
|
|
171
|
+
strictness_max_items = {
|
|
172
|
+
"high": 0,
|
|
173
|
+
"medium": 5,
|
|
174
|
+
"low": 20
|
|
175
|
+
}
|
|
176
|
+
default_max_items = strictness_max_items.get(schema_strictness, 5)
|
|
177
|
+
default_enabled = schema_strictness != "high"
|
|
178
|
+
|
|
179
|
+
overflow_raw = manifest.get("overflow", {})
|
|
180
|
+
overflow = {
|
|
181
|
+
"enabled": overflow_raw.get("enabled", default_enabled),
|
|
182
|
+
"recoverable": overflow_raw.get("recoverable", True),
|
|
183
|
+
"max_items": overflow_raw.get("max_items", default_max_items),
|
|
184
|
+
"require_suggested_mapping": overflow_raw.get("require_suggested_mapping", True)
|
|
185
|
+
}
|
|
175
186
|
|
|
176
187
|
enums = manifest.get("enums", {
|
|
177
188
|
"strategy": "extensible" if tier in ("decision", "exploration") else "strict",
|
cognitive/runner.py
CHANGED
|
@@ -80,21 +80,49 @@ EnvelopeResponse = Union[EnvelopeResponseV22, EnvelopeSuccessV21, EnvelopeFailur
|
|
|
80
80
|
RISK_LEVELS = {"none": 0, "low": 1, "medium": 2, "high": 3}
|
|
81
81
|
RISK_NAMES = ["none", "low", "medium", "high"]
|
|
82
82
|
|
|
83
|
+
RiskRule = Literal["max_changes_risk", "max_issues_risk", "explicit"]
|
|
83
84
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
85
|
+
|
|
86
|
+
def aggregate_risk_from_list(items: list[dict]) -> RiskLevel:
|
|
87
|
+
"""Compute max risk from list of items with risk field."""
|
|
88
|
+
if not items:
|
|
87
89
|
return "medium" # Default conservative
|
|
88
90
|
|
|
89
91
|
max_level = 0
|
|
90
|
-
for
|
|
91
|
-
risk =
|
|
92
|
+
for item in items:
|
|
93
|
+
risk = item.get("risk", "medium")
|
|
92
94
|
level = RISK_LEVELS.get(risk, 2)
|
|
93
95
|
max_level = max(max_level, level)
|
|
94
96
|
|
|
95
97
|
return RISK_NAMES[max_level]
|
|
96
98
|
|
|
97
99
|
|
|
100
|
+
def aggregate_risk(
|
|
101
|
+
data: dict,
|
|
102
|
+
risk_rule: RiskRule = "max_changes_risk"
|
|
103
|
+
) -> RiskLevel:
|
|
104
|
+
"""
|
|
105
|
+
Compute aggregated risk based on risk_rule.
|
|
106
|
+
|
|
107
|
+
Rules:
|
|
108
|
+
- max_changes_risk: max(data.changes[*].risk) - default
|
|
109
|
+
- max_issues_risk: max(data.issues[*].risk) - for review modules
|
|
110
|
+
- explicit: return "medium", module should set risk explicitly
|
|
111
|
+
"""
|
|
112
|
+
if risk_rule == "max_changes_risk":
|
|
113
|
+
changes = data.get("changes", [])
|
|
114
|
+
return aggregate_risk_from_list(changes)
|
|
115
|
+
elif risk_rule == "max_issues_risk":
|
|
116
|
+
issues = data.get("issues", [])
|
|
117
|
+
return aggregate_risk_from_list(issues)
|
|
118
|
+
elif risk_rule == "explicit":
|
|
119
|
+
return "medium" # Module should override
|
|
120
|
+
else:
|
|
121
|
+
# Fallback to changes
|
|
122
|
+
changes = data.get("changes", [])
|
|
123
|
+
return aggregate_risk_from_list(changes)
|
|
124
|
+
|
|
125
|
+
|
|
98
126
|
# =============================================================================
|
|
99
127
|
# Schema Validation
|
|
100
128
|
# =============================================================================
|
|
@@ -120,15 +148,19 @@ def validate_data(data: dict, schema: dict, label: str = "Data") -> list[str]:
|
|
|
120
148
|
def repair_envelope(
|
|
121
149
|
data: dict,
|
|
122
150
|
meta_schema: Optional[dict] = None,
|
|
123
|
-
max_explain_length: int = 280
|
|
151
|
+
max_explain_length: int = 280,
|
|
152
|
+
risk_rule: RiskRule = "max_changes_risk"
|
|
124
153
|
) -> dict:
|
|
125
154
|
"""
|
|
126
155
|
Attempt to repair envelope format issues without changing semantics.
|
|
127
156
|
|
|
128
|
-
Repairs:
|
|
157
|
+
Repairs (lossless only):
|
|
129
158
|
- Missing meta fields (fill with conservative defaults)
|
|
130
159
|
- Truncate explain if too long
|
|
131
|
-
-
|
|
160
|
+
- Trim whitespace from string fields
|
|
161
|
+
|
|
162
|
+
Does NOT repair:
|
|
163
|
+
- Invalid enum values (treated as validation failure)
|
|
132
164
|
"""
|
|
133
165
|
repaired = dict(data)
|
|
134
166
|
|
|
@@ -148,28 +180,28 @@ def repair_envelope(
|
|
|
148
180
|
if isinstance(meta.get("confidence"), (int, float)):
|
|
149
181
|
meta["confidence"] = max(0.0, min(1.0, float(meta["confidence"])))
|
|
150
182
|
|
|
151
|
-
# Repair risk
|
|
183
|
+
# Repair risk - use configurable aggregation rule
|
|
152
184
|
if "risk" not in meta:
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
if risk not in RISK_LEVELS:
|
|
160
|
-
meta["risk"] = "medium"
|
|
161
|
-
else:
|
|
162
|
-
meta["risk"] = risk
|
|
185
|
+
meta["risk"] = aggregate_risk(data_payload, risk_rule)
|
|
186
|
+
|
|
187
|
+
# Trim whitespace from risk (lossless), but do NOT invent new values
|
|
188
|
+
if isinstance(meta.get("risk"), str):
|
|
189
|
+
meta["risk"] = meta["risk"].strip().lower()
|
|
190
|
+
# If invalid after trim, leave as-is (validation will catch it)
|
|
163
191
|
|
|
164
192
|
# Repair explain
|
|
165
193
|
if "explain" not in meta:
|
|
166
194
|
# Try to extract from rationale
|
|
167
195
|
rationale = data_payload.get("rationale", "")
|
|
168
196
|
if rationale:
|
|
169
|
-
meta["explain"] = rationale[:max_explain_length]
|
|
197
|
+
meta["explain"] = str(rationale)[:max_explain_length]
|
|
170
198
|
else:
|
|
171
199
|
meta["explain"] = "No explanation provided"
|
|
172
200
|
|
|
201
|
+
# Trim whitespace from explain (lossless)
|
|
202
|
+
if isinstance(meta.get("explain"), str):
|
|
203
|
+
meta["explain"] = meta["explain"].strip()
|
|
204
|
+
|
|
173
205
|
# Truncate explain if too long
|
|
174
206
|
if len(meta.get("explain", "")) > max_explain_length:
|
|
175
207
|
meta["explain"] = meta["explain"][:max_explain_length - 3] + "..."
|
|
@@ -230,13 +262,12 @@ def wrap_v21_to_v22(v21_response: dict) -> EnvelopeResponseV22:
|
|
|
230
262
|
# Extract or compute meta fields
|
|
231
263
|
confidence = data.get("confidence", 0.5)
|
|
232
264
|
rationale = data.get("rationale", "")
|
|
233
|
-
changes = data.get("changes", [])
|
|
234
265
|
|
|
235
266
|
return {
|
|
236
267
|
"ok": True,
|
|
237
268
|
"meta": {
|
|
238
269
|
"confidence": confidence,
|
|
239
|
-
"risk": aggregate_risk(
|
|
270
|
+
"risk": aggregate_risk(data), # Uses default max_changes_risk
|
|
240
271
|
"explain": rationale[:280] if rationale else "No explanation provided"
|
|
241
272
|
},
|
|
242
273
|
"data": data
|
|
@@ -279,13 +310,12 @@ def convert_legacy_to_envelope(data: dict, is_error: bool = False) -> EnvelopeRe
|
|
|
279
310
|
# Legacy success response - data is the payload itself
|
|
280
311
|
confidence = data.get("confidence", 0.5)
|
|
281
312
|
rationale = data.get("rationale", "")
|
|
282
|
-
changes = data.get("changes", [])
|
|
283
313
|
|
|
284
314
|
return {
|
|
285
315
|
"ok": True,
|
|
286
316
|
"meta": {
|
|
287
317
|
"confidence": confidence,
|
|
288
|
-
"risk": aggregate_risk(
|
|
318
|
+
"risk": aggregate_risk(data), # Uses default max_changes_risk
|
|
289
319
|
"explain": rationale[:280] if rationale else "No explanation provided"
|
|
290
320
|
},
|
|
291
321
|
"data": data
|
|
@@ -513,13 +543,17 @@ def run_module(
|
|
|
513
543
|
data_schema = module.get("data_schema") or module.get("output_schema")
|
|
514
544
|
meta_schema = module.get("meta_schema")
|
|
515
545
|
|
|
546
|
+
# Get risk_rule from module.yaml meta config
|
|
547
|
+
meta_config = module.get("metadata", {}).get("meta", {})
|
|
548
|
+
risk_rule = meta_config.get("risk_rule", "max_changes_risk")
|
|
549
|
+
|
|
516
550
|
if data_schema:
|
|
517
551
|
data_to_validate = result.get("data", {})
|
|
518
552
|
errors = validate_data(data_to_validate, data_schema, "Data")
|
|
519
553
|
|
|
520
554
|
if errors and enable_repair:
|
|
521
555
|
# Attempt repair pass
|
|
522
|
-
result = repair_envelope(result, meta_schema)
|
|
556
|
+
result = repair_envelope(result, meta_schema, risk_rule=risk_rule)
|
|
523
557
|
|
|
524
558
|
# Re-validate after repair
|
|
525
559
|
errors = validate_data(result.get("data", {}), data_schema, "Data")
|
|
@@ -540,7 +574,7 @@ def run_module(
|
|
|
540
574
|
if meta_schema:
|
|
541
575
|
meta_errors = validate_data(result.get("meta", {}), meta_schema, "Meta")
|
|
542
576
|
if meta_errors and enable_repair:
|
|
543
|
-
result = repair_envelope(result, meta_schema)
|
|
577
|
+
result = repair_envelope(result, meta_schema, risk_rule=risk_rule)
|
|
544
578
|
|
|
545
579
|
return result
|
|
546
580
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cognitive-modules
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.1
|
|
4
4
|
Summary: Structured LLM task runner with schema validation, confidence scoring, and subagent orchestration
|
|
5
5
|
Author: ziel-io
|
|
6
6
|
License: MIT
|
|
@@ -105,10 +105,10 @@ pip install cognitive-modules[all] # 全部
|
|
|
105
105
|
|
|
106
106
|
```bash
|
|
107
107
|
# 全局安装
|
|
108
|
-
npm install -g
|
|
108
|
+
npm install -g cogn
|
|
109
109
|
|
|
110
|
-
# 或 npx
|
|
111
|
-
npx
|
|
110
|
+
# 或 npx 零安装使用(推荐)
|
|
111
|
+
npx cogn --help
|
|
112
112
|
```
|
|
113
113
|
|
|
114
114
|
| 平台 | 包名 | 命令 |
|
|
@@ -402,7 +402,7 @@ cogn validate my-module --v22
|
|
|
402
402
|
|
|
403
403
|
```
|
|
404
404
|
cognitive-modules/
|
|
405
|
-
├── src/cognitive/ # CLI 源码
|
|
405
|
+
├── src/cognitive/ # Python CLI 源码
|
|
406
406
|
│ ├── cli.py # 命令入口
|
|
407
407
|
│ ├── loader.py # 模块加载(支持 v0/v1/v2.2)
|
|
408
408
|
│ ├── runner.py # 模块执行(v2.2 envelope)
|
|
@@ -412,7 +412,12 @@ cognitive-modules/
|
|
|
412
412
|
│ ├── registry.py # 模块安装
|
|
413
413
|
│ ├── templates.py # 模块模板
|
|
414
414
|
│ └── providers/ # LLM 后端
|
|
415
|
+
├── packages/
|
|
416
|
+
│ └── cli-node/ # Node.js CLI (npm: cognitive-modules-cli)
|
|
417
|
+
│ ├── src/ # TypeScript 源码
|
|
418
|
+
│ └── package.json
|
|
415
419
|
├── cognitive/modules/ # 内置模块(全部 v2.2)
|
|
420
|
+
├── coze-plugin/ # Coze 集成插件
|
|
416
421
|
├── tests/ # 单元测试
|
|
417
422
|
├── SPEC.md # v0.1 规范(历史)
|
|
418
423
|
├── SPEC-v2.2.md # v2.2 规范(最新)
|
|
@@ -420,6 +425,15 @@ cognitive-modules/
|
|
|
420
425
|
└── cognitive-registry.json # 公共注册表
|
|
421
426
|
```
|
|
422
427
|
|
|
428
|
+
## 多平台支持
|
|
429
|
+
|
|
430
|
+
| 平台 | 包名 | 命令 | 安装 |
|
|
431
|
+
|------|------|------|------|
|
|
432
|
+
| Python | `cognitive-modules` | `cogn` | `pip install cognitive-modules` |
|
|
433
|
+
| Node.js | `cogn` | `cog` | `npm install -g cogn` 或 `npx cogn` |
|
|
434
|
+
|
|
435
|
+
两个版本共享相同的模块格式和 v2.2 规范。
|
|
436
|
+
|
|
423
437
|
## 文档
|
|
424
438
|
|
|
425
439
|
- [SPEC-v2.2.md](SPEC-v2.2.md) - v2.2 完整规范(Control/Data 分离、Tier、Overflow)
|
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
cognitive/__init__.py,sha256=
|
|
1
|
+
cognitive/__init__.py,sha256=FY2NWSVD9Lq_L9DrUPjkacIex_tD2P1xYrC9qawrMYM,401
|
|
2
2
|
cognitive/cli.py,sha256=tYYWkFJt-eBtWF3GwokuqIZz6vFIP3ZJj7yls1cru6E,26778
|
|
3
|
-
cognitive/loader.py,sha256=
|
|
3
|
+
cognitive/loader.py,sha256=NgFNcGXO56_1T1qxdvwWrpE37NoysTpuKhcQtchnros,15052
|
|
4
4
|
cognitive/mcp_server.py,sha256=NUQT7IqdYB9tQ-1YYfG5MPJuq6A70FXlcV2x3lBnuvM,6852
|
|
5
5
|
cognitive/migrate.py,sha256=15CXw0qWVFbC-kPau1bzPBirs8kg_b_E_1YANlJ34uI,19679
|
|
6
6
|
cognitive/registry.py,sha256=qLGyvUxSDP4frs46UlPa5jCcKubqiikWT3Y9JrBqfFc,18549
|
|
7
|
-
cognitive/runner.py,sha256=
|
|
7
|
+
cognitive/runner.py,sha256=kXfU3A6Per1aZ8wB26XseX48sP51FrydJ47Lgs6PHpY,21240
|
|
8
8
|
cognitive/server.py,sha256=cz8zGqhGrZgFY-HM0RSCjPCpB_Mfg1jsybeoo2ALvAc,9041
|
|
9
9
|
cognitive/subagent.py,sha256=fb7LWwNF6YcJtC_T1dK0EvzqWMBnav-kiCIpvVohEBw,8142
|
|
10
10
|
cognitive/templates.py,sha256=lKC197X9aQIA-npUvVCaplSwvhxjsH_KYVCQtrTZrL4,4712
|
|
11
11
|
cognitive/validator.py,sha256=8B02JQQdNcwvH-mtbyP8bVTRQxUrO9Prt4gU0N53fdg,21843
|
|
12
12
|
cognitive/providers/__init__.py,sha256=hqhVA1IEXpVtyCAteXhO5yD8a8ikQpVIPEKJVHLtRFY,7492
|
|
13
|
-
cognitive_modules-0.5.
|
|
14
|
-
cognitive_modules-0.5.
|
|
15
|
-
cognitive_modules-0.5.
|
|
16
|
-
cognitive_modules-0.5.
|
|
17
|
-
cognitive_modules-0.5.
|
|
18
|
-
cognitive_modules-0.5.
|
|
13
|
+
cognitive_modules-0.5.1.dist-info/licenses/LICENSE,sha256=NXFYUy2hPJdh3NHRxMChTnMiQD9k8zFxkmR7gWefexc,1064
|
|
14
|
+
cognitive_modules-0.5.1.dist-info/METADATA,sha256=m_Yf3eZtNFAVeKWdvtHquUB3BUFDVyqHkqCJo45Ghco,13361
|
|
15
|
+
cognitive_modules-0.5.1.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
16
|
+
cognitive_modules-0.5.1.dist-info/entry_points.txt,sha256=1yqKB-MjHrRoe8FcYm-TgZDqGEZxzBPsd0xC4pcfBNU,43
|
|
17
|
+
cognitive_modules-0.5.1.dist-info/top_level.txt,sha256=kGIfDucCKylo8cRBtxER_v3DHIea-Sol9x9YSJo1u3Y,10
|
|
18
|
+
cognitive_modules-0.5.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|