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 CHANGED
@@ -9,4 +9,4 @@ Usage:
9
9
  cog doctor # Check environment setup
10
10
  """
11
11
 
12
- __version__ = "0.5.0"
12
+ __version__ = "0.5.1"
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
- overflow = manifest.get("overflow", {
170
- "enabled": False,
171
- "recoverable": True,
172
- "max_items": 5,
173
- "require_suggested_mapping": True
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
- def aggregate_risk(changes: list[dict]) -> RiskLevel:
85
- """Compute max risk from list of changes."""
86
- if not changes:
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 change in changes:
91
- risk = change.get("risk", "medium")
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
- - Normalize risk enum values
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
- # Aggregate from changes if available
154
- changes = data_payload.get("changes", [])
155
- meta["risk"] = aggregate_risk(changes)
156
-
157
- # Normalize risk value
158
- risk = str(meta.get("risk", "medium")).lower()
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(changes),
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(changes),
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.0
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 cognitive-modules-cli
108
+ npm install -g cogn
109
109
 
110
- # 或 npx 零安装使用
111
- npx cognitive-modules-cli --help
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=pFMrHFn6hsXl4Jd5bosCmWcUnJcwYwPrS7qg1Ogxxhk,401
1
+ cognitive/__init__.py,sha256=FY2NWSVD9Lq_L9DrUPjkacIex_tD2P1xYrC9qawrMYM,401
2
2
  cognitive/cli.py,sha256=tYYWkFJt-eBtWF3GwokuqIZz6vFIP3ZJj7yls1cru6E,26778
3
- cognitive/loader.py,sha256=p3uS5LbAhRxWnRhMsSGzlGqohAxHzVZjPm1WKtoeYes,14537
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=36b9pHa4Jiw01aslK_eFFamqHreLJ-t--nYcukmzuW4,19771
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.0.dist-info/licenses/LICENSE,sha256=NXFYUy2hPJdh3NHRxMChTnMiQD9k8zFxkmR7gWefexc,1064
14
- cognitive_modules-0.5.0.dist-info/METADATA,sha256=nHK8DmSqc1tHhwxpzTKg5AUTl2walIHNBv_LP-ErF3s,12842
15
- cognitive_modules-0.5.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
16
- cognitive_modules-0.5.0.dist-info/entry_points.txt,sha256=1yqKB-MjHrRoe8FcYm-TgZDqGEZxzBPsd0xC4pcfBNU,43
17
- cognitive_modules-0.5.0.dist-info/top_level.txt,sha256=kGIfDucCKylo8cRBtxER_v3DHIea-Sol9x9YSJo1u3Y,10
18
- cognitive_modules-0.5.0.dist-info/RECORD,,
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,,