cognitive-modules 0.1.1__tar.gz → 0.3.0__tar.gz
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_modules-0.1.1/src/cognitive_modules.egg-info → cognitive_modules-0.3.0}/PKG-INFO +131 -2
- {cognitive_modules-0.1.1 → cognitive_modules-0.3.0}/README.md +130 -1
- {cognitive_modules-0.1.1 → cognitive_modules-0.3.0}/pyproject.toml +1 -1
- cognitive_modules-0.3.0/src/cognitive/loader.py +258 -0
- cognitive_modules-0.3.0/src/cognitive/runner.py +276 -0
- {cognitive_modules-0.1.1 → cognitive_modules-0.3.0}/src/cognitive/templates.py +1 -1
- {cognitive_modules-0.1.1 → cognitive_modules-0.3.0/src/cognitive_modules.egg-info}/PKG-INFO +131 -2
- cognitive_modules-0.1.1/src/cognitive/loader.py +0 -133
- cognitive_modules-0.1.1/src/cognitive/runner.py +0 -140
- {cognitive_modules-0.1.1 → cognitive_modules-0.3.0}/LICENSE +0 -0
- {cognitive_modules-0.1.1 → cognitive_modules-0.3.0}/setup.cfg +0 -0
- {cognitive_modules-0.1.1 → cognitive_modules-0.3.0}/src/cognitive/__init__.py +0 -0
- {cognitive_modules-0.1.1 → cognitive_modules-0.3.0}/src/cognitive/cli.py +0 -0
- {cognitive_modules-0.1.1 → cognitive_modules-0.3.0}/src/cognitive/providers/__init__.py +0 -0
- {cognitive_modules-0.1.1 → cognitive_modules-0.3.0}/src/cognitive/registry.py +0 -0
- {cognitive_modules-0.1.1 → cognitive_modules-0.3.0}/src/cognitive/subagent.py +0 -0
- {cognitive_modules-0.1.1 → cognitive_modules-0.3.0}/src/cognitive/validator.py +0 -0
- {cognitive_modules-0.1.1 → cognitive_modules-0.3.0}/src/cognitive_modules.egg-info/SOURCES.txt +0 -0
- {cognitive_modules-0.1.1 → cognitive_modules-0.3.0}/src/cognitive_modules.egg-info/dependency_links.txt +0 -0
- {cognitive_modules-0.1.1 → cognitive_modules-0.3.0}/src/cognitive_modules.egg-info/entry_points.txt +0 -0
- {cognitive_modules-0.1.1 → cognitive_modules-0.3.0}/src/cognitive_modules.egg-info/requires.txt +0 -0
- {cognitive_modules-0.1.1 → cognitive_modules-0.3.0}/src/cognitive_modules.egg-info/top_level.txt +0 -0
- {cognitive_modules-0.1.1 → cognitive_modules-0.3.0}/tests/test_cli.py +0 -0
- {cognitive_modules-0.1.1 → cognitive_modules-0.3.0}/tests/test_loader.py +0 -0
- {cognitive_modules-0.1.1 → cognitive_modules-0.3.0}/tests/test_registry.py +0 -0
- {cognitive_modules-0.1.1 → cognitive_modules-0.3.0}/tests/test_runner.py +0 -0
- {cognitive_modules-0.1.1 → cognitive_modules-0.3.0}/tests/test_subagent.py +0 -0
- {cognitive_modules-0.1.1 → cognitive_modules-0.3.0}/tests/test_validator.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cognitive-modules
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: Structured LLM task runner with schema validation, confidence scoring, and subagent orchestration
|
|
5
5
|
Author: ziel-io
|
|
6
6
|
License: MIT
|
|
@@ -151,6 +151,7 @@ cog doctor
|
|
|
151
151
|
| 模块 | 功能 | 示例 |
|
|
152
152
|
|------|------|------|
|
|
153
153
|
| `code-reviewer` | 代码审查 | `cog run code-reviewer --args "你的代码"` |
|
|
154
|
+
| `code-simplifier` | 代码简化 | `cog run code-simplifier --args "复杂代码"` |
|
|
154
155
|
| `task-prioritizer` | 任务优先级排序 | `cog run task-prioritizer --args "任务1,任务2"` |
|
|
155
156
|
| `api-designer` | REST API 设计 | `cog run api-designer --args "订单系统"` |
|
|
156
157
|
| `ui-spec-generator` | UI 规范生成 | `cog run ui-spec-generator --args "电商首页"` |
|
|
@@ -241,6 +242,134 @@ export LLM_PROVIDER=ollama
|
|
|
241
242
|
cog doctor
|
|
242
243
|
```
|
|
243
244
|
|
|
245
|
+
## 创建新模块(完整流程)
|
|
246
|
+
|
|
247
|
+
以 `code-simplifier` 为例:
|
|
248
|
+
|
|
249
|
+
### Step 1: 创建目录结构
|
|
250
|
+
|
|
251
|
+
```bash
|
|
252
|
+
mkdir -p cognitive/modules/code-simplifier
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
### Step 2: 编写 MODULE.md
|
|
256
|
+
|
|
257
|
+
```bash
|
|
258
|
+
cat > cognitive/modules/code-simplifier/MODULE.md << 'EOF'
|
|
259
|
+
---
|
|
260
|
+
name: code-simplifier
|
|
261
|
+
version: 1.0.0
|
|
262
|
+
responsibility: Simplify complex code while preserving functionality
|
|
263
|
+
|
|
264
|
+
excludes:
|
|
265
|
+
- Changing the code's behavior
|
|
266
|
+
- Adding new features
|
|
267
|
+
- Removing functionality
|
|
268
|
+
|
|
269
|
+
constraints:
|
|
270
|
+
no_network: true
|
|
271
|
+
no_side_effects: true
|
|
272
|
+
require_confidence: true
|
|
273
|
+
require_rationale: true
|
|
274
|
+
---
|
|
275
|
+
|
|
276
|
+
# Code Simplifier Module
|
|
277
|
+
|
|
278
|
+
You are an expert at refactoring and simplifying code.
|
|
279
|
+
|
|
280
|
+
## Input
|
|
281
|
+
|
|
282
|
+
Code to simplify: $ARGUMENTS
|
|
283
|
+
|
|
284
|
+
## Simplification Strategies
|
|
285
|
+
|
|
286
|
+
1. **Remove redundancy** - Eliminate duplicate code
|
|
287
|
+
2. **Improve naming** - Use clear, descriptive names
|
|
288
|
+
3. **Reduce nesting** - Flatten deep conditionals
|
|
289
|
+
4. **Simplify logic** - Use built-in functions
|
|
290
|
+
|
|
291
|
+
## Output Requirements
|
|
292
|
+
|
|
293
|
+
Return JSON containing:
|
|
294
|
+
- `simplified_code`: The simplified version
|
|
295
|
+
- `changes`: List of changes made
|
|
296
|
+
- `summary`: Brief description
|
|
297
|
+
- `rationale`: Explanation of decisions
|
|
298
|
+
- `confidence`: Confidence score [0-1]
|
|
299
|
+
EOF
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
### Step 3: 编写 schema.json
|
|
303
|
+
|
|
304
|
+
```bash
|
|
305
|
+
cat > cognitive/modules/code-simplifier/schema.json << 'EOF'
|
|
306
|
+
{
|
|
307
|
+
"$schema": "https://ziel-io.github.io/cognitive-modules/schema/v1.json",
|
|
308
|
+
"input": {
|
|
309
|
+
"type": "object",
|
|
310
|
+
"properties": {
|
|
311
|
+
"code": { "type": "string" },
|
|
312
|
+
"language": { "type": "string" },
|
|
313
|
+
"$ARGUMENTS": { "type": "string" }
|
|
314
|
+
}
|
|
315
|
+
},
|
|
316
|
+
"output": {
|
|
317
|
+
"type": "object",
|
|
318
|
+
"required": ["simplified_code", "changes", "summary", "rationale", "confidence"],
|
|
319
|
+
"properties": {
|
|
320
|
+
"simplified_code": { "type": "string" },
|
|
321
|
+
"changes": {
|
|
322
|
+
"type": "array",
|
|
323
|
+
"items": {
|
|
324
|
+
"type": "object",
|
|
325
|
+
"properties": {
|
|
326
|
+
"type": { "type": "string" },
|
|
327
|
+
"description": { "type": "string" }
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
},
|
|
331
|
+
"summary": { "type": "string" },
|
|
332
|
+
"rationale": { "type": "string" },
|
|
333
|
+
"confidence": { "type": "number", "minimum": 0, "maximum": 1 }
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
EOF
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
### Step 4: 验证模块
|
|
341
|
+
|
|
342
|
+
```bash
|
|
343
|
+
cog validate code-simplifier
|
|
344
|
+
cog list # 确认模块出现在列表中
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
### Step 5: 测试运行
|
|
348
|
+
|
|
349
|
+
```bash
|
|
350
|
+
cog run code-simplifier --args "def calc(x): if x > 0: if x < 10: return x * 2 else: return x else: return 0" --pretty
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
### Step 6: 添加示例(可选)
|
|
354
|
+
|
|
355
|
+
```bash
|
|
356
|
+
mkdir -p cognitive/modules/code-simplifier/examples
|
|
357
|
+
# 添加 input.json 和 output.json 作为测试用例
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
### 模块设计要点
|
|
361
|
+
|
|
362
|
+
| 要素 | 必须 | 说明 |
|
|
363
|
+
|------|------|------|
|
|
364
|
+
| `name` | ✅ | 唯一标识符,kebab-case |
|
|
365
|
+
| `version` | ✅ | 语义化版本 |
|
|
366
|
+
| `responsibility` | ✅ | 一句话描述职责 |
|
|
367
|
+
| `excludes` | ✅ | 明确列出不做的事 |
|
|
368
|
+
| `$ARGUMENTS` | ✅ | 支持命令行参数 |
|
|
369
|
+
| `confidence` | ✅ | 输出必须包含 0-1 置信度 |
|
|
370
|
+
| `rationale` | ✅ | 输出必须包含推理过程 |
|
|
371
|
+
| `schema.json` | ✅ | 定义输入输出契约 |
|
|
372
|
+
|
|
244
373
|
## 开发
|
|
245
374
|
|
|
246
375
|
```bash
|
|
@@ -254,7 +383,7 @@ pip install -e ".[dev]"
|
|
|
254
383
|
# 运行测试
|
|
255
384
|
pytest tests/ -v
|
|
256
385
|
|
|
257
|
-
#
|
|
386
|
+
# 创建新模块(使用模板)
|
|
258
387
|
cog init my-module -d "模块描述"
|
|
259
388
|
cog validate my-module
|
|
260
389
|
```
|
|
@@ -99,6 +99,7 @@ cog doctor
|
|
|
99
99
|
| 模块 | 功能 | 示例 |
|
|
100
100
|
|------|------|------|
|
|
101
101
|
| `code-reviewer` | 代码审查 | `cog run code-reviewer --args "你的代码"` |
|
|
102
|
+
| `code-simplifier` | 代码简化 | `cog run code-simplifier --args "复杂代码"` |
|
|
102
103
|
| `task-prioritizer` | 任务优先级排序 | `cog run task-prioritizer --args "任务1,任务2"` |
|
|
103
104
|
| `api-designer` | REST API 设计 | `cog run api-designer --args "订单系统"` |
|
|
104
105
|
| `ui-spec-generator` | UI 规范生成 | `cog run ui-spec-generator --args "电商首页"` |
|
|
@@ -189,6 +190,134 @@ export LLM_PROVIDER=ollama
|
|
|
189
190
|
cog doctor
|
|
190
191
|
```
|
|
191
192
|
|
|
193
|
+
## 创建新模块(完整流程)
|
|
194
|
+
|
|
195
|
+
以 `code-simplifier` 为例:
|
|
196
|
+
|
|
197
|
+
### Step 1: 创建目录结构
|
|
198
|
+
|
|
199
|
+
```bash
|
|
200
|
+
mkdir -p cognitive/modules/code-simplifier
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
### Step 2: 编写 MODULE.md
|
|
204
|
+
|
|
205
|
+
```bash
|
|
206
|
+
cat > cognitive/modules/code-simplifier/MODULE.md << 'EOF'
|
|
207
|
+
---
|
|
208
|
+
name: code-simplifier
|
|
209
|
+
version: 1.0.0
|
|
210
|
+
responsibility: Simplify complex code while preserving functionality
|
|
211
|
+
|
|
212
|
+
excludes:
|
|
213
|
+
- Changing the code's behavior
|
|
214
|
+
- Adding new features
|
|
215
|
+
- Removing functionality
|
|
216
|
+
|
|
217
|
+
constraints:
|
|
218
|
+
no_network: true
|
|
219
|
+
no_side_effects: true
|
|
220
|
+
require_confidence: true
|
|
221
|
+
require_rationale: true
|
|
222
|
+
---
|
|
223
|
+
|
|
224
|
+
# Code Simplifier Module
|
|
225
|
+
|
|
226
|
+
You are an expert at refactoring and simplifying code.
|
|
227
|
+
|
|
228
|
+
## Input
|
|
229
|
+
|
|
230
|
+
Code to simplify: $ARGUMENTS
|
|
231
|
+
|
|
232
|
+
## Simplification Strategies
|
|
233
|
+
|
|
234
|
+
1. **Remove redundancy** - Eliminate duplicate code
|
|
235
|
+
2. **Improve naming** - Use clear, descriptive names
|
|
236
|
+
3. **Reduce nesting** - Flatten deep conditionals
|
|
237
|
+
4. **Simplify logic** - Use built-in functions
|
|
238
|
+
|
|
239
|
+
## Output Requirements
|
|
240
|
+
|
|
241
|
+
Return JSON containing:
|
|
242
|
+
- `simplified_code`: The simplified version
|
|
243
|
+
- `changes`: List of changes made
|
|
244
|
+
- `summary`: Brief description
|
|
245
|
+
- `rationale`: Explanation of decisions
|
|
246
|
+
- `confidence`: Confidence score [0-1]
|
|
247
|
+
EOF
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### Step 3: 编写 schema.json
|
|
251
|
+
|
|
252
|
+
```bash
|
|
253
|
+
cat > cognitive/modules/code-simplifier/schema.json << 'EOF'
|
|
254
|
+
{
|
|
255
|
+
"$schema": "https://ziel-io.github.io/cognitive-modules/schema/v1.json",
|
|
256
|
+
"input": {
|
|
257
|
+
"type": "object",
|
|
258
|
+
"properties": {
|
|
259
|
+
"code": { "type": "string" },
|
|
260
|
+
"language": { "type": "string" },
|
|
261
|
+
"$ARGUMENTS": { "type": "string" }
|
|
262
|
+
}
|
|
263
|
+
},
|
|
264
|
+
"output": {
|
|
265
|
+
"type": "object",
|
|
266
|
+
"required": ["simplified_code", "changes", "summary", "rationale", "confidence"],
|
|
267
|
+
"properties": {
|
|
268
|
+
"simplified_code": { "type": "string" },
|
|
269
|
+
"changes": {
|
|
270
|
+
"type": "array",
|
|
271
|
+
"items": {
|
|
272
|
+
"type": "object",
|
|
273
|
+
"properties": {
|
|
274
|
+
"type": { "type": "string" },
|
|
275
|
+
"description": { "type": "string" }
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
},
|
|
279
|
+
"summary": { "type": "string" },
|
|
280
|
+
"rationale": { "type": "string" },
|
|
281
|
+
"confidence": { "type": "number", "minimum": 0, "maximum": 1 }
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
EOF
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
### Step 4: 验证模块
|
|
289
|
+
|
|
290
|
+
```bash
|
|
291
|
+
cog validate code-simplifier
|
|
292
|
+
cog list # 确认模块出现在列表中
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
### Step 5: 测试运行
|
|
296
|
+
|
|
297
|
+
```bash
|
|
298
|
+
cog run code-simplifier --args "def calc(x): if x > 0: if x < 10: return x * 2 else: return x else: return 0" --pretty
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
### Step 6: 添加示例(可选)
|
|
302
|
+
|
|
303
|
+
```bash
|
|
304
|
+
mkdir -p cognitive/modules/code-simplifier/examples
|
|
305
|
+
# 添加 input.json 和 output.json 作为测试用例
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
### 模块设计要点
|
|
309
|
+
|
|
310
|
+
| 要素 | 必须 | 说明 |
|
|
311
|
+
|------|------|------|
|
|
312
|
+
| `name` | ✅ | 唯一标识符,kebab-case |
|
|
313
|
+
| `version` | ✅ | 语义化版本 |
|
|
314
|
+
| `responsibility` | ✅ | 一句话描述职责 |
|
|
315
|
+
| `excludes` | ✅ | 明确列出不做的事 |
|
|
316
|
+
| `$ARGUMENTS` | ✅ | 支持命令行参数 |
|
|
317
|
+
| `confidence` | ✅ | 输出必须包含 0-1 置信度 |
|
|
318
|
+
| `rationale` | ✅ | 输出必须包含推理过程 |
|
|
319
|
+
| `schema.json` | ✅ | 定义输入输出契约 |
|
|
320
|
+
|
|
192
321
|
## 开发
|
|
193
322
|
|
|
194
323
|
```bash
|
|
@@ -202,7 +331,7 @@ pip install -e ".[dev]"
|
|
|
202
331
|
# 运行测试
|
|
203
332
|
pytest tests/ -v
|
|
204
333
|
|
|
205
|
-
#
|
|
334
|
+
# 创建新模块(使用模板)
|
|
206
335
|
cog init my-module -d "模块描述"
|
|
207
336
|
cog validate my-module
|
|
208
337
|
```
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "cognitive-modules"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.3.0"
|
|
8
8
|
description = "Structured LLM task runner with schema validation, confidence scoring, and subagent orchestration"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = {text = "MIT"}
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Module Loader - Load cognitive modules in all formats.
|
|
3
|
+
|
|
4
|
+
Format v2 (recommended):
|
|
5
|
+
- module.yaml (machine-readable manifest)
|
|
6
|
+
- prompt.md (human-readable prompt)
|
|
7
|
+
- schema.json (input + output + error)
|
|
8
|
+
- tests/ (golden tests)
|
|
9
|
+
|
|
10
|
+
Format v1 (legacy, still supported):
|
|
11
|
+
- MODULE.md (YAML frontmatter + prompt)
|
|
12
|
+
- schema.json (input + output)
|
|
13
|
+
|
|
14
|
+
Format v0 (old, deprecated):
|
|
15
|
+
- module.md (YAML frontmatter)
|
|
16
|
+
- input.schema.json
|
|
17
|
+
- output.schema.json
|
|
18
|
+
- constraints.yaml
|
|
19
|
+
- prompt.txt
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
import json
|
|
23
|
+
from pathlib import Path
|
|
24
|
+
from typing import Optional
|
|
25
|
+
|
|
26
|
+
import yaml
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def detect_format(module_path: Path) -> str:
|
|
30
|
+
"""Detect module format: 'v2', 'v1', or 'v0'."""
|
|
31
|
+
if (module_path / "module.yaml").exists():
|
|
32
|
+
return "v2"
|
|
33
|
+
elif (module_path / "MODULE.md").exists():
|
|
34
|
+
return "v1"
|
|
35
|
+
elif (module_path / "module.md").exists():
|
|
36
|
+
return "v0"
|
|
37
|
+
else:
|
|
38
|
+
raise FileNotFoundError(f"No module.yaml, MODULE.md, or module.md found in {module_path}")
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def parse_frontmatter(content: str) -> tuple[dict, str]:
|
|
42
|
+
"""Parse YAML frontmatter from markdown content."""
|
|
43
|
+
if not content.startswith('---'):
|
|
44
|
+
return {}, content
|
|
45
|
+
|
|
46
|
+
parts = content.split('---', 2)
|
|
47
|
+
if len(parts) < 3:
|
|
48
|
+
return {}, content
|
|
49
|
+
|
|
50
|
+
frontmatter = yaml.safe_load(parts[1]) or {}
|
|
51
|
+
body = parts[2].strip()
|
|
52
|
+
return frontmatter, body
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def load_v2_format(module_path: Path) -> dict:
|
|
56
|
+
"""Load module in v2 format (module.yaml + prompt.md + schema.json)."""
|
|
57
|
+
# Load module.yaml
|
|
58
|
+
with open(module_path / "module.yaml", 'r', encoding='utf-8') as f:
|
|
59
|
+
manifest = yaml.safe_load(f)
|
|
60
|
+
|
|
61
|
+
# Load prompt.md
|
|
62
|
+
prompt_path = module_path / "prompt.md"
|
|
63
|
+
if prompt_path.exists():
|
|
64
|
+
with open(prompt_path, 'r', encoding='utf-8') as f:
|
|
65
|
+
prompt = f.read()
|
|
66
|
+
else:
|
|
67
|
+
prompt = ""
|
|
68
|
+
|
|
69
|
+
# Load schema.json
|
|
70
|
+
schema_path = module_path / "schema.json"
|
|
71
|
+
if schema_path.exists():
|
|
72
|
+
with open(schema_path, 'r', encoding='utf-8') as f:
|
|
73
|
+
schema = json.load(f)
|
|
74
|
+
input_schema = schema.get("input", {})
|
|
75
|
+
output_schema = schema.get("output", {})
|
|
76
|
+
error_schema = schema.get("error", {})
|
|
77
|
+
else:
|
|
78
|
+
input_schema = {}
|
|
79
|
+
output_schema = {}
|
|
80
|
+
error_schema = {}
|
|
81
|
+
|
|
82
|
+
# Extract constraints (supports both old and new format)
|
|
83
|
+
constraints_raw = manifest.get("constraints", {})
|
|
84
|
+
policies_raw = manifest.get("policies", {})
|
|
85
|
+
|
|
86
|
+
constraints = {
|
|
87
|
+
"operational": {
|
|
88
|
+
"no_external_network": constraints_raw.get("no_network", True) or policies_raw.get("network") == "deny",
|
|
89
|
+
"no_side_effects": constraints_raw.get("no_side_effects", True) or policies_raw.get("side_effects") == "deny",
|
|
90
|
+
"no_file_write": constraints_raw.get("no_file_write", True) or policies_raw.get("filesystem_write") == "deny",
|
|
91
|
+
"no_inventing_data": constraints_raw.get("no_inventing_data", True),
|
|
92
|
+
},
|
|
93
|
+
"output_quality": {
|
|
94
|
+
"require_confidence": manifest.get("output", {}).get("require_confidence", True),
|
|
95
|
+
"require_rationale": manifest.get("output", {}).get("require_rationale", True),
|
|
96
|
+
"require_behavior_equivalence": manifest.get("output", {}).get("require_behavior_equivalence", False),
|
|
97
|
+
},
|
|
98
|
+
"behavior_equivalence_false_max_confidence": constraints_raw.get("behavior_equivalence_false_max_confidence", 0.7),
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
# Extract policies (v2.1)
|
|
102
|
+
policies = manifest.get("policies", {})
|
|
103
|
+
|
|
104
|
+
# Extract tools policy
|
|
105
|
+
tools = manifest.get("tools", {})
|
|
106
|
+
|
|
107
|
+
# Extract output contract
|
|
108
|
+
output_contract = manifest.get("output", {})
|
|
109
|
+
|
|
110
|
+
# Extract failure contract
|
|
111
|
+
failure_contract = manifest.get("failure", {})
|
|
112
|
+
|
|
113
|
+
# Extract runtime requirements
|
|
114
|
+
runtime_requirements = manifest.get("runtime_requirements", {})
|
|
115
|
+
|
|
116
|
+
return {
|
|
117
|
+
"name": manifest.get("name", module_path.name),
|
|
118
|
+
"version": manifest.get("version", "1.0.0"),
|
|
119
|
+
"responsibility": manifest.get("responsibility", ""),
|
|
120
|
+
"excludes": manifest.get("excludes", []),
|
|
121
|
+
"path": module_path,
|
|
122
|
+
"format": "v2",
|
|
123
|
+
"metadata": manifest,
|
|
124
|
+
"input_schema": input_schema,
|
|
125
|
+
"output_schema": output_schema,
|
|
126
|
+
"error_schema": error_schema,
|
|
127
|
+
"constraints": constraints,
|
|
128
|
+
"policies": policies,
|
|
129
|
+
"tools": tools,
|
|
130
|
+
"output_contract": output_contract,
|
|
131
|
+
"failure_contract": failure_contract,
|
|
132
|
+
"runtime_requirements": runtime_requirements,
|
|
133
|
+
"prompt": prompt,
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def load_v1_format(module_path: Path) -> dict:
|
|
138
|
+
"""Load module in v1 format (MODULE.md + schema.json)."""
|
|
139
|
+
# Load MODULE.md
|
|
140
|
+
with open(module_path / "MODULE.md", 'r', encoding='utf-8') as f:
|
|
141
|
+
content = f.read()
|
|
142
|
+
|
|
143
|
+
metadata, prompt = parse_frontmatter(content)
|
|
144
|
+
|
|
145
|
+
# Extract constraints from metadata
|
|
146
|
+
constraints = {
|
|
147
|
+
"operational": {
|
|
148
|
+
"no_external_network": metadata.get("constraints", {}).get("no_network", True),
|
|
149
|
+
"no_side_effects": metadata.get("constraints", {}).get("no_side_effects", True),
|
|
150
|
+
"no_inventing_data": metadata.get("constraints", {}).get("no_inventing_data", True),
|
|
151
|
+
},
|
|
152
|
+
"output_quality": {
|
|
153
|
+
"require_confidence": metadata.get("constraints", {}).get("require_confidence", True),
|
|
154
|
+
"require_rationale": metadata.get("constraints", {}).get("require_rationale", True),
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
# Load schema.json
|
|
159
|
+
schema_path = module_path / "schema.json"
|
|
160
|
+
if schema_path.exists():
|
|
161
|
+
with open(schema_path, 'r', encoding='utf-8') as f:
|
|
162
|
+
schema = json.load(f)
|
|
163
|
+
input_schema = schema.get("input", {})
|
|
164
|
+
output_schema = schema.get("output", {})
|
|
165
|
+
else:
|
|
166
|
+
input_schema = {}
|
|
167
|
+
output_schema = {}
|
|
168
|
+
|
|
169
|
+
return {
|
|
170
|
+
"name": metadata.get("name", module_path.name),
|
|
171
|
+
"version": metadata.get("version", "1.0.0"),
|
|
172
|
+
"responsibility": metadata.get("responsibility", ""),
|
|
173
|
+
"excludes": metadata.get("excludes", []),
|
|
174
|
+
"path": module_path,
|
|
175
|
+
"format": "v1",
|
|
176
|
+
"metadata": metadata,
|
|
177
|
+
"input_schema": input_schema,
|
|
178
|
+
"output_schema": output_schema,
|
|
179
|
+
"constraints": constraints,
|
|
180
|
+
"prompt": prompt,
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def load_v0_format(module_path: Path) -> dict:
|
|
185
|
+
"""Load module in v0 format (old 6-file format)."""
|
|
186
|
+
# Load module.md
|
|
187
|
+
with open(module_path / "module.md", 'r', encoding='utf-8') as f:
|
|
188
|
+
content = f.read()
|
|
189
|
+
|
|
190
|
+
metadata, _ = parse_frontmatter(content)
|
|
191
|
+
|
|
192
|
+
# Load schemas
|
|
193
|
+
with open(module_path / "input.schema.json", 'r', encoding='utf-8') as f:
|
|
194
|
+
input_schema = json.load(f)
|
|
195
|
+
|
|
196
|
+
with open(module_path / "output.schema.json", 'r', encoding='utf-8') as f:
|
|
197
|
+
output_schema = json.load(f)
|
|
198
|
+
|
|
199
|
+
# Load constraints
|
|
200
|
+
with open(module_path / "constraints.yaml", 'r', encoding='utf-8') as f:
|
|
201
|
+
constraints = yaml.safe_load(f)
|
|
202
|
+
|
|
203
|
+
# Load prompt
|
|
204
|
+
with open(module_path / "prompt.txt", 'r', encoding='utf-8') as f:
|
|
205
|
+
prompt = f.read()
|
|
206
|
+
|
|
207
|
+
return {
|
|
208
|
+
"name": metadata.get("name", module_path.name),
|
|
209
|
+
"version": metadata.get("version", "1.0.0"),
|
|
210
|
+
"responsibility": metadata.get("responsibility", ""),
|
|
211
|
+
"excludes": [],
|
|
212
|
+
"path": module_path,
|
|
213
|
+
"format": "v0",
|
|
214
|
+
"metadata": metadata,
|
|
215
|
+
"input_schema": input_schema,
|
|
216
|
+
"output_schema": output_schema,
|
|
217
|
+
"constraints": constraints,
|
|
218
|
+
"prompt": prompt,
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
def load_module(module_path: Path) -> dict:
|
|
223
|
+
"""Load a module, auto-detecting format."""
|
|
224
|
+
fmt = detect_format(module_path)
|
|
225
|
+
if fmt == "v2":
|
|
226
|
+
return load_v2_format(module_path)
|
|
227
|
+
elif fmt == "v1":
|
|
228
|
+
return load_v1_format(module_path)
|
|
229
|
+
else:
|
|
230
|
+
return load_v0_format(module_path)
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
def find_module(name: str, search_paths: list[Path]) -> Optional[dict]:
|
|
234
|
+
"""Find and load a module by name from search paths."""
|
|
235
|
+
for base_path in search_paths:
|
|
236
|
+
module_path = base_path / name
|
|
237
|
+
if module_path.exists():
|
|
238
|
+
try:
|
|
239
|
+
return load_module(module_path)
|
|
240
|
+
except FileNotFoundError:
|
|
241
|
+
continue
|
|
242
|
+
return None
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
def list_modules(search_paths: list[Path]) -> list[dict]:
|
|
246
|
+
"""List all modules in search paths."""
|
|
247
|
+
modules = []
|
|
248
|
+
for base_path in search_paths:
|
|
249
|
+
if not base_path.exists():
|
|
250
|
+
continue
|
|
251
|
+
for module_dir in base_path.iterdir():
|
|
252
|
+
if module_dir.is_dir():
|
|
253
|
+
try:
|
|
254
|
+
module = load_module(module_dir)
|
|
255
|
+
modules.append(module)
|
|
256
|
+
except FileNotFoundError:
|
|
257
|
+
continue
|
|
258
|
+
return modules
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Module Runner - Execute cognitive modules with validation.
|
|
3
|
+
Supports v2 envelope format and legacy formats.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import json
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import Optional, TypedDict, Union
|
|
9
|
+
|
|
10
|
+
import jsonschema
|
|
11
|
+
import yaml
|
|
12
|
+
|
|
13
|
+
from .registry import find_module
|
|
14
|
+
from .loader import load_module
|
|
15
|
+
from .providers import call_llm
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class EnvelopeError(TypedDict):
|
|
19
|
+
code: str
|
|
20
|
+
message: str
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class EnvelopeSuccess(TypedDict):
|
|
24
|
+
ok: bool # True
|
|
25
|
+
data: dict
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class EnvelopeFailure(TypedDict):
|
|
29
|
+
ok: bool # False
|
|
30
|
+
error: EnvelopeError
|
|
31
|
+
partial_data: Optional[dict]
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
EnvelopeResponse = Union[EnvelopeSuccess, EnvelopeFailure]
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def validate_data(data: dict, schema: dict, label: str = "Data") -> list[str]:
|
|
38
|
+
"""Validate data against schema. Returns list of errors."""
|
|
39
|
+
errors = []
|
|
40
|
+
if not schema:
|
|
41
|
+
return errors
|
|
42
|
+
try:
|
|
43
|
+
jsonschema.validate(instance=data, schema=schema)
|
|
44
|
+
except jsonschema.ValidationError as e:
|
|
45
|
+
errors.append(f"{label} validation error: {e.message} at {list(e.absolute_path)}")
|
|
46
|
+
except jsonschema.SchemaError as e:
|
|
47
|
+
errors.append(f"Schema error: {e.message}")
|
|
48
|
+
return errors
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def substitute_arguments(text: str, input_data: dict) -> str:
|
|
52
|
+
"""Substitute $ARGUMENTS and $N placeholders in text."""
|
|
53
|
+
# Get arguments
|
|
54
|
+
args_value = input_data.get("$ARGUMENTS", input_data.get("query", input_data.get("code", "")))
|
|
55
|
+
|
|
56
|
+
# Replace $ARGUMENTS
|
|
57
|
+
text = text.replace("$ARGUMENTS", str(args_value))
|
|
58
|
+
|
|
59
|
+
# Replace $ARGUMENTS[N] and $N for indexed access
|
|
60
|
+
if isinstance(args_value, str):
|
|
61
|
+
args_list = args_value.split()
|
|
62
|
+
for i, arg in enumerate(args_list):
|
|
63
|
+
text = text.replace(f"$ARGUMENTS[{i}]", arg)
|
|
64
|
+
text = text.replace(f"${i}", arg)
|
|
65
|
+
|
|
66
|
+
return text
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def build_prompt(module: dict, input_data: dict, use_envelope: bool = False) -> str:
|
|
70
|
+
"""Build the complete prompt for the LLM."""
|
|
71
|
+
# Substitute $ARGUMENTS in prompt
|
|
72
|
+
prompt = substitute_arguments(module["prompt"], input_data)
|
|
73
|
+
|
|
74
|
+
parts = [
|
|
75
|
+
prompt,
|
|
76
|
+
"\n\n## Constraints\n",
|
|
77
|
+
yaml.dump(module["constraints"], default_flow_style=False),
|
|
78
|
+
"\n\n## Input\n",
|
|
79
|
+
"```json\n",
|
|
80
|
+
json.dumps(input_data, indent=2, ensure_ascii=False),
|
|
81
|
+
"\n```\n",
|
|
82
|
+
]
|
|
83
|
+
|
|
84
|
+
if use_envelope:
|
|
85
|
+
parts.extend([
|
|
86
|
+
"\n## Response Format (Envelope)\n",
|
|
87
|
+
"You MUST wrap your response in the envelope format:\n",
|
|
88
|
+
"- Success: { \"ok\": true, \"data\": { ...your output... } }\n",
|
|
89
|
+
"- Error: { \"ok\": false, \"error\": { \"code\": \"ERROR_CODE\", \"message\": \"...\" } }\n",
|
|
90
|
+
"Return ONLY valid JSON.\n",
|
|
91
|
+
])
|
|
92
|
+
else:
|
|
93
|
+
parts.extend([
|
|
94
|
+
"\n## Instructions\n",
|
|
95
|
+
"Analyze the input and generate output matching the required schema.",
|
|
96
|
+
"Return ONLY valid JSON. Do not include any text before or after the JSON.",
|
|
97
|
+
])
|
|
98
|
+
|
|
99
|
+
return "".join(parts)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def parse_llm_response(response: str) -> dict:
|
|
103
|
+
"""Parse LLM response, handling potential markdown code blocks."""
|
|
104
|
+
text = response.strip()
|
|
105
|
+
|
|
106
|
+
# Remove markdown code blocks if present
|
|
107
|
+
if text.startswith("```"):
|
|
108
|
+
lines = text.split("\n")
|
|
109
|
+
start = 1
|
|
110
|
+
end = len(lines) - 1
|
|
111
|
+
for i, line in enumerate(lines[1:], 1):
|
|
112
|
+
if line.strip() == "```":
|
|
113
|
+
end = i
|
|
114
|
+
break
|
|
115
|
+
text = "\n".join(lines[start:end])
|
|
116
|
+
|
|
117
|
+
return json.loads(text)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def is_envelope_response(data: dict) -> bool:
|
|
121
|
+
"""Check if response is in envelope format."""
|
|
122
|
+
return isinstance(data.get("ok"), bool)
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def parse_envelope_response(data: dict) -> EnvelopeResponse:
|
|
126
|
+
"""Parse and normalize envelope response."""
|
|
127
|
+
if data.get("ok") is True:
|
|
128
|
+
return {
|
|
129
|
+
"ok": True,
|
|
130
|
+
"data": data.get("data", {})
|
|
131
|
+
}
|
|
132
|
+
else:
|
|
133
|
+
return {
|
|
134
|
+
"ok": False,
|
|
135
|
+
"error": data.get("error", {"code": "UNKNOWN", "message": "Unknown error"}),
|
|
136
|
+
"partial_data": data.get("partial_data")
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def convert_to_envelope(data: dict, is_error: bool = False) -> EnvelopeResponse:
|
|
141
|
+
"""Convert legacy format to envelope format."""
|
|
142
|
+
if is_error or "error" in data:
|
|
143
|
+
error = data.get("error", {})
|
|
144
|
+
return {
|
|
145
|
+
"ok": False,
|
|
146
|
+
"error": {
|
|
147
|
+
"code": error.get("code", "UNKNOWN"),
|
|
148
|
+
"message": error.get("message", str(error))
|
|
149
|
+
},
|
|
150
|
+
"partial_data": None
|
|
151
|
+
}
|
|
152
|
+
else:
|
|
153
|
+
return {
|
|
154
|
+
"ok": True,
|
|
155
|
+
"data": data
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def run_module(
|
|
160
|
+
name_or_path: str,
|
|
161
|
+
input_data: dict,
|
|
162
|
+
validate_input: bool = True,
|
|
163
|
+
validate_output: bool = True,
|
|
164
|
+
model: Optional[str] = None,
|
|
165
|
+
use_envelope: Optional[bool] = None,
|
|
166
|
+
) -> EnvelopeResponse:
|
|
167
|
+
"""
|
|
168
|
+
Run a cognitive module with the given input.
|
|
169
|
+
Returns envelope format response.
|
|
170
|
+
|
|
171
|
+
Args:
|
|
172
|
+
name_or_path: Module name or path to module directory
|
|
173
|
+
input_data: Input data dictionary
|
|
174
|
+
validate_input: Whether to validate input against schema
|
|
175
|
+
validate_output: Whether to validate output against schema
|
|
176
|
+
model: Optional model override
|
|
177
|
+
use_envelope: Force envelope format (auto-detect if None)
|
|
178
|
+
|
|
179
|
+
Returns:
|
|
180
|
+
EnvelopeResponse with ok=True/False and data/error
|
|
181
|
+
"""
|
|
182
|
+
# Find module path
|
|
183
|
+
path = Path(name_or_path)
|
|
184
|
+
if path.exists() and path.is_dir():
|
|
185
|
+
module_path = path
|
|
186
|
+
else:
|
|
187
|
+
module_path = find_module(name_or_path)
|
|
188
|
+
if not module_path:
|
|
189
|
+
return {
|
|
190
|
+
"ok": False,
|
|
191
|
+
"error": {"code": "MODULE_NOT_FOUND", "message": f"Module not found: {name_or_path}"},
|
|
192
|
+
"partial_data": None
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
# Load module (auto-detects format)
|
|
196
|
+
module = load_module(module_path)
|
|
197
|
+
|
|
198
|
+
# Determine if we should use envelope format
|
|
199
|
+
should_use_envelope = use_envelope
|
|
200
|
+
if should_use_envelope is None:
|
|
201
|
+
# Auto-detect: use envelope for v2 format or if output.envelope is True
|
|
202
|
+
output_contract = module.get("output_contract", {})
|
|
203
|
+
should_use_envelope = (
|
|
204
|
+
module.get("format") == "v2" or
|
|
205
|
+
output_contract.get("envelope", False)
|
|
206
|
+
)
|
|
207
|
+
|
|
208
|
+
# Validate input
|
|
209
|
+
if validate_input and module["input_schema"]:
|
|
210
|
+
errors = validate_data(input_data, module["input_schema"], "Input")
|
|
211
|
+
if errors:
|
|
212
|
+
return {
|
|
213
|
+
"ok": False,
|
|
214
|
+
"error": {"code": "INVALID_INPUT", "message": str(errors)},
|
|
215
|
+
"partial_data": None
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
# Build prompt and call LLM
|
|
219
|
+
full_prompt = build_prompt(module, input_data, use_envelope=should_use_envelope)
|
|
220
|
+
response = call_llm(full_prompt, model=model)
|
|
221
|
+
|
|
222
|
+
# Parse response
|
|
223
|
+
try:
|
|
224
|
+
output_data = parse_llm_response(response)
|
|
225
|
+
except json.JSONDecodeError as e:
|
|
226
|
+
return {
|
|
227
|
+
"ok": False,
|
|
228
|
+
"error": {"code": "PARSE_ERROR", "message": f"Failed to parse JSON: {e}"},
|
|
229
|
+
"partial_data": None
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
# Handle envelope format
|
|
233
|
+
if is_envelope_response(output_data):
|
|
234
|
+
result = parse_envelope_response(output_data)
|
|
235
|
+
else:
|
|
236
|
+
# Convert legacy format to envelope
|
|
237
|
+
result = convert_to_envelope(output_data)
|
|
238
|
+
|
|
239
|
+
# Validate output (only for success responses)
|
|
240
|
+
if result["ok"] and validate_output and module["output_schema"]:
|
|
241
|
+
data_to_validate = result.get("data", {})
|
|
242
|
+
errors = validate_data(data_to_validate, module["output_schema"], "Output")
|
|
243
|
+
if errors:
|
|
244
|
+
return {
|
|
245
|
+
"ok": False,
|
|
246
|
+
"error": {"code": "OUTPUT_VALIDATION_ERROR", "message": str(errors)},
|
|
247
|
+
"partial_data": data_to_validate
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
return result
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
def run_module_legacy(
|
|
254
|
+
name_or_path: str,
|
|
255
|
+
input_data: dict,
|
|
256
|
+
validate_input: bool = True,
|
|
257
|
+
validate_output: bool = True,
|
|
258
|
+
model: Optional[str] = None,
|
|
259
|
+
) -> dict:
|
|
260
|
+
"""
|
|
261
|
+
Run a cognitive module (legacy API, returns raw output).
|
|
262
|
+
For backward compatibility.
|
|
263
|
+
"""
|
|
264
|
+
result = run_module(
|
|
265
|
+
name_or_path,
|
|
266
|
+
input_data,
|
|
267
|
+
validate_input=validate_input,
|
|
268
|
+
validate_output=validate_output,
|
|
269
|
+
model=model,
|
|
270
|
+
use_envelope=False
|
|
271
|
+
)
|
|
272
|
+
|
|
273
|
+
if result["ok"]:
|
|
274
|
+
return result["data"]
|
|
275
|
+
else:
|
|
276
|
+
raise ValueError(f"{result['error']['code']}: {result['error']['message']}")
|
|
@@ -83,7 +83,7 @@ EXAMPLE_OUTPUT = {
|
|
|
83
83
|
def get_schema_template(name: str) -> dict:
|
|
84
84
|
"""Generate schema template as dict."""
|
|
85
85
|
return {
|
|
86
|
-
"$schema": "https://
|
|
86
|
+
"$schema": "https://ziel-io.github.io/cognitive-modules/schema/v1.json",
|
|
87
87
|
"$id": name,
|
|
88
88
|
"title": f"{name.replace('-', ' ').title()} Schema",
|
|
89
89
|
"input": {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cognitive-modules
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: Structured LLM task runner with schema validation, confidence scoring, and subagent orchestration
|
|
5
5
|
Author: ziel-io
|
|
6
6
|
License: MIT
|
|
@@ -151,6 +151,7 @@ cog doctor
|
|
|
151
151
|
| 模块 | 功能 | 示例 |
|
|
152
152
|
|------|------|------|
|
|
153
153
|
| `code-reviewer` | 代码审查 | `cog run code-reviewer --args "你的代码"` |
|
|
154
|
+
| `code-simplifier` | 代码简化 | `cog run code-simplifier --args "复杂代码"` |
|
|
154
155
|
| `task-prioritizer` | 任务优先级排序 | `cog run task-prioritizer --args "任务1,任务2"` |
|
|
155
156
|
| `api-designer` | REST API 设计 | `cog run api-designer --args "订单系统"` |
|
|
156
157
|
| `ui-spec-generator` | UI 规范生成 | `cog run ui-spec-generator --args "电商首页"` |
|
|
@@ -241,6 +242,134 @@ export LLM_PROVIDER=ollama
|
|
|
241
242
|
cog doctor
|
|
242
243
|
```
|
|
243
244
|
|
|
245
|
+
## 创建新模块(完整流程)
|
|
246
|
+
|
|
247
|
+
以 `code-simplifier` 为例:
|
|
248
|
+
|
|
249
|
+
### Step 1: 创建目录结构
|
|
250
|
+
|
|
251
|
+
```bash
|
|
252
|
+
mkdir -p cognitive/modules/code-simplifier
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
### Step 2: 编写 MODULE.md
|
|
256
|
+
|
|
257
|
+
```bash
|
|
258
|
+
cat > cognitive/modules/code-simplifier/MODULE.md << 'EOF'
|
|
259
|
+
---
|
|
260
|
+
name: code-simplifier
|
|
261
|
+
version: 1.0.0
|
|
262
|
+
responsibility: Simplify complex code while preserving functionality
|
|
263
|
+
|
|
264
|
+
excludes:
|
|
265
|
+
- Changing the code's behavior
|
|
266
|
+
- Adding new features
|
|
267
|
+
- Removing functionality
|
|
268
|
+
|
|
269
|
+
constraints:
|
|
270
|
+
no_network: true
|
|
271
|
+
no_side_effects: true
|
|
272
|
+
require_confidence: true
|
|
273
|
+
require_rationale: true
|
|
274
|
+
---
|
|
275
|
+
|
|
276
|
+
# Code Simplifier Module
|
|
277
|
+
|
|
278
|
+
You are an expert at refactoring and simplifying code.
|
|
279
|
+
|
|
280
|
+
## Input
|
|
281
|
+
|
|
282
|
+
Code to simplify: $ARGUMENTS
|
|
283
|
+
|
|
284
|
+
## Simplification Strategies
|
|
285
|
+
|
|
286
|
+
1. **Remove redundancy** - Eliminate duplicate code
|
|
287
|
+
2. **Improve naming** - Use clear, descriptive names
|
|
288
|
+
3. **Reduce nesting** - Flatten deep conditionals
|
|
289
|
+
4. **Simplify logic** - Use built-in functions
|
|
290
|
+
|
|
291
|
+
## Output Requirements
|
|
292
|
+
|
|
293
|
+
Return JSON containing:
|
|
294
|
+
- `simplified_code`: The simplified version
|
|
295
|
+
- `changes`: List of changes made
|
|
296
|
+
- `summary`: Brief description
|
|
297
|
+
- `rationale`: Explanation of decisions
|
|
298
|
+
- `confidence`: Confidence score [0-1]
|
|
299
|
+
EOF
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
### Step 3: 编写 schema.json
|
|
303
|
+
|
|
304
|
+
```bash
|
|
305
|
+
cat > cognitive/modules/code-simplifier/schema.json << 'EOF'
|
|
306
|
+
{
|
|
307
|
+
"$schema": "https://ziel-io.github.io/cognitive-modules/schema/v1.json",
|
|
308
|
+
"input": {
|
|
309
|
+
"type": "object",
|
|
310
|
+
"properties": {
|
|
311
|
+
"code": { "type": "string" },
|
|
312
|
+
"language": { "type": "string" },
|
|
313
|
+
"$ARGUMENTS": { "type": "string" }
|
|
314
|
+
}
|
|
315
|
+
},
|
|
316
|
+
"output": {
|
|
317
|
+
"type": "object",
|
|
318
|
+
"required": ["simplified_code", "changes", "summary", "rationale", "confidence"],
|
|
319
|
+
"properties": {
|
|
320
|
+
"simplified_code": { "type": "string" },
|
|
321
|
+
"changes": {
|
|
322
|
+
"type": "array",
|
|
323
|
+
"items": {
|
|
324
|
+
"type": "object",
|
|
325
|
+
"properties": {
|
|
326
|
+
"type": { "type": "string" },
|
|
327
|
+
"description": { "type": "string" }
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
},
|
|
331
|
+
"summary": { "type": "string" },
|
|
332
|
+
"rationale": { "type": "string" },
|
|
333
|
+
"confidence": { "type": "number", "minimum": 0, "maximum": 1 }
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
EOF
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
### Step 4: 验证模块
|
|
341
|
+
|
|
342
|
+
```bash
|
|
343
|
+
cog validate code-simplifier
|
|
344
|
+
cog list # 确认模块出现在列表中
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
### Step 5: 测试运行
|
|
348
|
+
|
|
349
|
+
```bash
|
|
350
|
+
cog run code-simplifier --args "def calc(x): if x > 0: if x < 10: return x * 2 else: return x else: return 0" --pretty
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
### Step 6: 添加示例(可选)
|
|
354
|
+
|
|
355
|
+
```bash
|
|
356
|
+
mkdir -p cognitive/modules/code-simplifier/examples
|
|
357
|
+
# 添加 input.json 和 output.json 作为测试用例
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
### 模块设计要点
|
|
361
|
+
|
|
362
|
+
| 要素 | 必须 | 说明 |
|
|
363
|
+
|------|------|------|
|
|
364
|
+
| `name` | ✅ | 唯一标识符,kebab-case |
|
|
365
|
+
| `version` | ✅ | 语义化版本 |
|
|
366
|
+
| `responsibility` | ✅ | 一句话描述职责 |
|
|
367
|
+
| `excludes` | ✅ | 明确列出不做的事 |
|
|
368
|
+
| `$ARGUMENTS` | ✅ | 支持命令行参数 |
|
|
369
|
+
| `confidence` | ✅ | 输出必须包含 0-1 置信度 |
|
|
370
|
+
| `rationale` | ✅ | 输出必须包含推理过程 |
|
|
371
|
+
| `schema.json` | ✅ | 定义输入输出契约 |
|
|
372
|
+
|
|
244
373
|
## 开发
|
|
245
374
|
|
|
246
375
|
```bash
|
|
@@ -254,7 +383,7 @@ pip install -e ".[dev]"
|
|
|
254
383
|
# 运行测试
|
|
255
384
|
pytest tests/ -v
|
|
256
385
|
|
|
257
|
-
#
|
|
386
|
+
# 创建新模块(使用模板)
|
|
258
387
|
cog init my-module -d "模块描述"
|
|
259
388
|
cog validate my-module
|
|
260
389
|
```
|
|
@@ -1,133 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Module Loader - Load cognitive modules in both old and new formats.
|
|
3
|
-
|
|
4
|
-
Old format (6 files):
|
|
5
|
-
- module.md (YAML frontmatter)
|
|
6
|
-
- input.schema.json
|
|
7
|
-
- output.schema.json
|
|
8
|
-
- constraints.yaml
|
|
9
|
-
- prompt.txt
|
|
10
|
-
- examples/
|
|
11
|
-
|
|
12
|
-
New format (2 files):
|
|
13
|
-
- MODULE.md (YAML frontmatter + prompt)
|
|
14
|
-
- schema.json (input + output combined)
|
|
15
|
-
"""
|
|
16
|
-
|
|
17
|
-
import json
|
|
18
|
-
from pathlib import Path
|
|
19
|
-
from typing import Optional
|
|
20
|
-
|
|
21
|
-
import yaml
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
def detect_format(module_path: Path) -> str:
|
|
25
|
-
"""Detect module format: 'new' or 'old'."""
|
|
26
|
-
if (module_path / "MODULE.md").exists():
|
|
27
|
-
return "new"
|
|
28
|
-
elif (module_path / "module.md").exists():
|
|
29
|
-
return "old"
|
|
30
|
-
else:
|
|
31
|
-
raise FileNotFoundError(f"No MODULE.md or module.md found in {module_path}")
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
def parse_frontmatter(content: str) -> tuple[dict, str]:
|
|
35
|
-
"""Parse YAML frontmatter from markdown content."""
|
|
36
|
-
if not content.startswith('---'):
|
|
37
|
-
return {}, content
|
|
38
|
-
|
|
39
|
-
parts = content.split('---', 2)
|
|
40
|
-
if len(parts) < 3:
|
|
41
|
-
return {}, content
|
|
42
|
-
|
|
43
|
-
frontmatter = yaml.safe_load(parts[1]) or {}
|
|
44
|
-
body = parts[2].strip()
|
|
45
|
-
return frontmatter, body
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
def load_new_format(module_path: Path) -> dict:
|
|
49
|
-
"""Load module in new format (MODULE.md + schema.json)."""
|
|
50
|
-
# Load MODULE.md
|
|
51
|
-
with open(module_path / "MODULE.md", 'r', encoding='utf-8') as f:
|
|
52
|
-
content = f.read()
|
|
53
|
-
|
|
54
|
-
metadata, prompt = parse_frontmatter(content)
|
|
55
|
-
|
|
56
|
-
# Extract constraints from metadata
|
|
57
|
-
constraints = {
|
|
58
|
-
"operational": {
|
|
59
|
-
"no_external_network": metadata.get("constraints", {}).get("no_network", True),
|
|
60
|
-
"no_side_effects": metadata.get("constraints", {}).get("no_side_effects", True),
|
|
61
|
-
"no_inventing_data": metadata.get("constraints", {}).get("no_inventing_data", True),
|
|
62
|
-
},
|
|
63
|
-
"output_quality": {
|
|
64
|
-
"require_confidence": metadata.get("constraints", {}).get("require_confidence", True),
|
|
65
|
-
"require_rationale": metadata.get("constraints", {}).get("require_rationale", True),
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
# Load schema.json
|
|
70
|
-
schema_path = module_path / "schema.json"
|
|
71
|
-
if schema_path.exists():
|
|
72
|
-
with open(schema_path, 'r', encoding='utf-8') as f:
|
|
73
|
-
schema = json.load(f)
|
|
74
|
-
input_schema = schema.get("input", {})
|
|
75
|
-
output_schema = schema.get("output", {})
|
|
76
|
-
else:
|
|
77
|
-
input_schema = {}
|
|
78
|
-
output_schema = {}
|
|
79
|
-
|
|
80
|
-
return {
|
|
81
|
-
"name": metadata.get("name", module_path.name),
|
|
82
|
-
"path": module_path,
|
|
83
|
-
"format": "new",
|
|
84
|
-
"metadata": metadata,
|
|
85
|
-
"input_schema": input_schema,
|
|
86
|
-
"output_schema": output_schema,
|
|
87
|
-
"constraints": constraints,
|
|
88
|
-
"prompt": prompt,
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
def load_old_format(module_path: Path) -> dict:
|
|
93
|
-
"""Load module in old format (6 files)."""
|
|
94
|
-
# Load module.md
|
|
95
|
-
with open(module_path / "module.md", 'r', encoding='utf-8') as f:
|
|
96
|
-
content = f.read()
|
|
97
|
-
|
|
98
|
-
metadata, _ = parse_frontmatter(content)
|
|
99
|
-
|
|
100
|
-
# Load schemas
|
|
101
|
-
with open(module_path / "input.schema.json", 'r', encoding='utf-8') as f:
|
|
102
|
-
input_schema = json.load(f)
|
|
103
|
-
|
|
104
|
-
with open(module_path / "output.schema.json", 'r', encoding='utf-8') as f:
|
|
105
|
-
output_schema = json.load(f)
|
|
106
|
-
|
|
107
|
-
# Load constraints
|
|
108
|
-
with open(module_path / "constraints.yaml", 'r', encoding='utf-8') as f:
|
|
109
|
-
constraints = yaml.safe_load(f)
|
|
110
|
-
|
|
111
|
-
# Load prompt
|
|
112
|
-
with open(module_path / "prompt.txt", 'r', encoding='utf-8') as f:
|
|
113
|
-
prompt = f.read()
|
|
114
|
-
|
|
115
|
-
return {
|
|
116
|
-
"name": metadata.get("name", module_path.name),
|
|
117
|
-
"path": module_path,
|
|
118
|
-
"format": "old",
|
|
119
|
-
"metadata": metadata,
|
|
120
|
-
"input_schema": input_schema,
|
|
121
|
-
"output_schema": output_schema,
|
|
122
|
-
"constraints": constraints,
|
|
123
|
-
"prompt": prompt,
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
def load_module(module_path: Path) -> dict:
|
|
128
|
-
"""Load a module, auto-detecting format."""
|
|
129
|
-
fmt = detect_format(module_path)
|
|
130
|
-
if fmt == "new":
|
|
131
|
-
return load_new_format(module_path)
|
|
132
|
-
else:
|
|
133
|
-
return load_old_format(module_path)
|
|
@@ -1,140 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Module Runner - Execute cognitive modules with validation.
|
|
3
|
-
Supports both old and new module formats.
|
|
4
|
-
"""
|
|
5
|
-
|
|
6
|
-
import json
|
|
7
|
-
from pathlib import Path
|
|
8
|
-
from typing import Optional
|
|
9
|
-
|
|
10
|
-
import jsonschema
|
|
11
|
-
import yaml
|
|
12
|
-
|
|
13
|
-
from .registry import find_module
|
|
14
|
-
from .loader import load_module
|
|
15
|
-
from .providers import call_llm
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
def validate_data(data: dict, schema: dict, label: str = "Data") -> list[str]:
|
|
19
|
-
"""Validate data against schema. Returns list of errors."""
|
|
20
|
-
errors = []
|
|
21
|
-
if not schema:
|
|
22
|
-
return errors
|
|
23
|
-
try:
|
|
24
|
-
jsonschema.validate(instance=data, schema=schema)
|
|
25
|
-
except jsonschema.ValidationError as e:
|
|
26
|
-
errors.append(f"{label} validation error: {e.message} at {list(e.absolute_path)}")
|
|
27
|
-
except jsonschema.SchemaError as e:
|
|
28
|
-
errors.append(f"Schema error: {e.message}")
|
|
29
|
-
return errors
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
def substitute_arguments(text: str, input_data: dict) -> str:
|
|
33
|
-
"""Substitute $ARGUMENTS and $N placeholders in text."""
|
|
34
|
-
# Get arguments
|
|
35
|
-
args_value = input_data.get("$ARGUMENTS", input_data.get("query", ""))
|
|
36
|
-
|
|
37
|
-
# Replace $ARGUMENTS
|
|
38
|
-
text = text.replace("$ARGUMENTS", str(args_value))
|
|
39
|
-
|
|
40
|
-
# Replace $ARGUMENTS[N] and $N for indexed access
|
|
41
|
-
if isinstance(args_value, str):
|
|
42
|
-
args_list = args_value.split()
|
|
43
|
-
for i, arg in enumerate(args_list):
|
|
44
|
-
text = text.replace(f"$ARGUMENTS[{i}]", arg)
|
|
45
|
-
text = text.replace(f"${i}", arg)
|
|
46
|
-
|
|
47
|
-
return text
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
def build_prompt(module: dict, input_data: dict) -> str:
|
|
51
|
-
"""Build the complete prompt for the LLM."""
|
|
52
|
-
# Substitute $ARGUMENTS in prompt
|
|
53
|
-
prompt = substitute_arguments(module["prompt"], input_data)
|
|
54
|
-
|
|
55
|
-
parts = [
|
|
56
|
-
prompt,
|
|
57
|
-
"\n\n## Constraints\n",
|
|
58
|
-
yaml.dump(module["constraints"], default_flow_style=False),
|
|
59
|
-
"\n\n## Input\n",
|
|
60
|
-
"```json\n",
|
|
61
|
-
json.dumps(input_data, indent=2, ensure_ascii=False),
|
|
62
|
-
"\n```\n",
|
|
63
|
-
"\n## Instructions\n",
|
|
64
|
-
"Analyze the input and generate output matching the required schema.",
|
|
65
|
-
"Return ONLY valid JSON. Do not include any text before or after the JSON.",
|
|
66
|
-
]
|
|
67
|
-
return "".join(parts)
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
def parse_llm_response(response: str) -> dict:
|
|
71
|
-
"""Parse LLM response, handling potential markdown code blocks."""
|
|
72
|
-
text = response.strip()
|
|
73
|
-
|
|
74
|
-
# Remove markdown code blocks if present
|
|
75
|
-
if text.startswith("```"):
|
|
76
|
-
lines = text.split("\n")
|
|
77
|
-
start = 1
|
|
78
|
-
end = len(lines) - 1
|
|
79
|
-
for i, line in enumerate(lines[1:], 1):
|
|
80
|
-
if line.strip() == "```":
|
|
81
|
-
end = i
|
|
82
|
-
break
|
|
83
|
-
text = "\n".join(lines[start:end])
|
|
84
|
-
|
|
85
|
-
return json.loads(text)
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
def run_module(
|
|
89
|
-
name_or_path: str,
|
|
90
|
-
input_data: dict,
|
|
91
|
-
validate_input: bool = True,
|
|
92
|
-
validate_output: bool = True,
|
|
93
|
-
model: Optional[str] = None,
|
|
94
|
-
) -> dict:
|
|
95
|
-
"""
|
|
96
|
-
Run a cognitive module with the given input.
|
|
97
|
-
Supports both old and new module formats.
|
|
98
|
-
|
|
99
|
-
Args:
|
|
100
|
-
name_or_path: Module name or path to module directory
|
|
101
|
-
input_data: Input data dictionary
|
|
102
|
-
validate_input: Whether to validate input against schema
|
|
103
|
-
validate_output: Whether to validate output against schema
|
|
104
|
-
model: Optional model override
|
|
105
|
-
|
|
106
|
-
Returns:
|
|
107
|
-
The module output as a dictionary
|
|
108
|
-
"""
|
|
109
|
-
# Find module path
|
|
110
|
-
path = Path(name_or_path)
|
|
111
|
-
if path.exists() and path.is_dir():
|
|
112
|
-
module_path = path
|
|
113
|
-
else:
|
|
114
|
-
module_path = find_module(name_or_path)
|
|
115
|
-
if not module_path:
|
|
116
|
-
raise FileNotFoundError(f"Module not found: {name_or_path}")
|
|
117
|
-
|
|
118
|
-
# Load module (auto-detects format)
|
|
119
|
-
module = load_module(module_path)
|
|
120
|
-
|
|
121
|
-
# Validate input
|
|
122
|
-
if validate_input and module["input_schema"]:
|
|
123
|
-
errors = validate_data(input_data, module["input_schema"], "Input")
|
|
124
|
-
if errors:
|
|
125
|
-
raise ValueError(f"Input validation failed: {errors}")
|
|
126
|
-
|
|
127
|
-
# Build prompt and call LLM
|
|
128
|
-
full_prompt = build_prompt(module, input_data)
|
|
129
|
-
response = call_llm(full_prompt, model=model)
|
|
130
|
-
|
|
131
|
-
# Parse response
|
|
132
|
-
output_data = parse_llm_response(response)
|
|
133
|
-
|
|
134
|
-
# Validate output
|
|
135
|
-
if validate_output and module["output_schema"]:
|
|
136
|
-
errors = validate_data(output_data, module["output_schema"], "Output")
|
|
137
|
-
if errors:
|
|
138
|
-
raise ValueError(f"Output validation failed: {errors}")
|
|
139
|
-
|
|
140
|
-
return output_data
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{cognitive_modules-0.1.1 → cognitive_modules-0.3.0}/src/cognitive_modules.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
{cognitive_modules-0.1.1 → cognitive_modules-0.3.0}/src/cognitive_modules.egg-info/entry_points.txt
RENAMED
|
File without changes
|
{cognitive_modules-0.1.1 → cognitive_modules-0.3.0}/src/cognitive_modules.egg-info/requires.txt
RENAMED
|
File without changes
|
{cognitive_modules-0.1.1 → cognitive_modules-0.3.0}/src/cognitive_modules.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|