cannyforge 0.2.0__tar.gz → 0.2.1__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.
Files changed (61) hide show
  1. cannyforge-0.2.1/PKG-INFO +253 -0
  2. cannyforge-0.2.1/README.md +209 -0
  3. {cannyforge-0.2.0 → cannyforge-0.2.1}/cannyforge/__init__.py +8 -1
  4. {cannyforge-0.2.0 → cannyforge-0.2.1}/cannyforge/adapters/__init__.py +1 -0
  5. cannyforge-0.2.1/cannyforge/adapters/langgraph.py +392 -0
  6. cannyforge-0.2.1/cannyforge/bundled_skills/tool-use/SKILL.md +106 -0
  7. cannyforge-0.2.1/cannyforge/bundled_skills/tool-use/assets/templates.yaml +43 -0
  8. {cannyforge-0.2.0 → cannyforge-0.2.1}/cannyforge/core.py +21 -2
  9. cannyforge-0.2.1/cannyforge/corrections.py +238 -0
  10. {cannyforge-0.2.0 → cannyforge-0.2.1}/cannyforge/knowledge.py +241 -0
  11. {cannyforge-0.2.0 → cannyforge-0.2.1}/cannyforge/learning.py +113 -16
  12. {cannyforge-0.2.0 → cannyforge-0.2.1}/cannyforge/llm.py +26 -2
  13. cannyforge-0.2.1/cannyforge.egg-info/PKG-INFO +253 -0
  14. {cannyforge-0.2.0 → cannyforge-0.2.1}/cannyforge.egg-info/SOURCES.txt +7 -0
  15. {cannyforge-0.2.0 → cannyforge-0.2.1}/cannyforge.egg-info/requires.txt +4 -0
  16. {cannyforge-0.2.0 → cannyforge-0.2.1}/pyproject.toml +3 -1
  17. cannyforge-0.2.1/tests/test_corrections.py +94 -0
  18. {cannyforge-0.2.0 → cannyforge-0.2.1}/tests/test_knowledge.py +112 -1
  19. cannyforge-0.2.1/tests/test_langgraph_adapter.py +291 -0
  20. {cannyforge-0.2.0 → cannyforge-0.2.1}/tests/test_learning.py +3 -0
  21. {cannyforge-0.2.0 → cannyforge-0.2.1}/tests/test_llm.py +49 -0
  22. cannyforge-0.2.1/tests/test_tool_use_skill.py +146 -0
  23. cannyforge-0.2.0/PKG-INFO +0 -472
  24. cannyforge-0.2.0/README.md +0 -431
  25. cannyforge-0.2.0/cannyforge.egg-info/PKG-INFO +0 -472
  26. {cannyforge-0.2.0 → cannyforge-0.2.1}/LICENSE +0 -0
  27. {cannyforge-0.2.0 → cannyforge-0.2.1}/cannyforge/adapters/crewai.py +0 -0
  28. {cannyforge-0.2.0 → cannyforge-0.2.1}/cannyforge/adapters/langchain.py +0 -0
  29. {cannyforge-0.2.0 → cannyforge-0.2.1}/cannyforge/bundled_skills/calendar-manager/SKILL.md +0 -0
  30. {cannyforge-0.2.0 → cannyforge-0.2.1}/cannyforge/bundled_skills/calendar-manager/assets/templates.yaml +0 -0
  31. {cannyforge-0.2.0 → cannyforge-0.2.1}/cannyforge/bundled_skills/content-summarizer/SKILL.md +0 -0
  32. {cannyforge-0.2.0 → cannyforge-0.2.1}/cannyforge/bundled_skills/email-writer/SKILL.md +0 -0
  33. {cannyforge-0.2.0 → cannyforge-0.2.1}/cannyforge/bundled_skills/email-writer/assets/templates.yaml +0 -0
  34. {cannyforge-0.2.0 → cannyforge-0.2.1}/cannyforge/bundled_skills/web-searcher/SKILL.md +0 -0
  35. {cannyforge-0.2.0 → cannyforge-0.2.1}/cannyforge/cli.py +0 -0
  36. {cannyforge-0.2.0 → cannyforge-0.2.1}/cannyforge/dashboard.py +0 -0
  37. {cannyforge-0.2.0 → cannyforge-0.2.1}/cannyforge/demo.py +0 -0
  38. {cannyforge-0.2.0 → cannyforge-0.2.1}/cannyforge/export.py +0 -0
  39. {cannyforge-0.2.0 → cannyforge-0.2.1}/cannyforge/mcp_server.py +0 -0
  40. {cannyforge-0.2.0 → cannyforge-0.2.1}/cannyforge/registry.py +0 -0
  41. {cannyforge-0.2.0 → cannyforge-0.2.1}/cannyforge/services/__init__.py +0 -0
  42. {cannyforge-0.2.0 → cannyforge-0.2.1}/cannyforge/services/crm_service.py +0 -0
  43. {cannyforge-0.2.0 → cannyforge-0.2.1}/cannyforge/services/email_service.py +0 -0
  44. {cannyforge-0.2.0 → cannyforge-0.2.1}/cannyforge/services/mock_calendar_mcp.py +0 -0
  45. {cannyforge-0.2.0 → cannyforge-0.2.1}/cannyforge/services/service_base.py +0 -0
  46. {cannyforge-0.2.0 → cannyforge-0.2.1}/cannyforge/services/slack_service.py +0 -0
  47. {cannyforge-0.2.0 → cannyforge-0.2.1}/cannyforge/services/web_search_api.py +0 -0
  48. {cannyforge-0.2.0 → cannyforge-0.2.1}/cannyforge/skills.py +0 -0
  49. {cannyforge-0.2.0 → cannyforge-0.2.1}/cannyforge/storage.py +0 -0
  50. {cannyforge-0.2.0 → cannyforge-0.2.1}/cannyforge/tools.py +0 -0
  51. {cannyforge-0.2.0 → cannyforge-0.2.1}/cannyforge/workers.py +0 -0
  52. {cannyforge-0.2.0 → cannyforge-0.2.1}/cannyforge.egg-info/dependency_links.txt +0 -0
  53. {cannyforge-0.2.0 → cannyforge-0.2.1}/cannyforge.egg-info/entry_points.txt +0 -0
  54. {cannyforge-0.2.0 → cannyforge-0.2.1}/cannyforge.egg-info/top_level.txt +0 -0
  55. {cannyforge-0.2.0 → cannyforge-0.2.1}/setup.cfg +0 -0
  56. {cannyforge-0.2.0 → cannyforge-0.2.1}/tests/test_declarative_skill.py +0 -0
  57. {cannyforge-0.2.0 → cannyforge-0.2.1}/tests/test_integration.py +0 -0
  58. {cannyforge-0.2.0 → cannyforge-0.2.1}/tests/test_production.py +0 -0
  59. {cannyforge-0.2.0 → cannyforge-0.2.1}/tests/test_skill_loader.py +0 -0
  60. {cannyforge-0.2.0 → cannyforge-0.2.1}/tests/test_spec_compliance.py +0 -0
  61. {cannyforge-0.2.0 → cannyforge-0.2.1}/tests/test_tools.py +0 -0
@@ -0,0 +1,253 @@
1
+ Metadata-Version: 2.4
2
+ Name: cannyforge
3
+ Version: 0.2.1
4
+ Summary: Self-improving agents with closed-loop learning — agents that learn to get it right
5
+ License: BSL-1.1
6
+ Project-URL: Homepage, https://github.com/cannyforge/cannyforge
7
+ Project-URL: Documentation, https://github.com/cannyforge/cannyforge#readme
8
+ Classifier: Development Status :: 4 - Beta
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3.10
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Requires-Python: >=3.10
16
+ Description-Content-Type: text/markdown
17
+ License-File: LICENSE
18
+ Requires-Dist: python-dotenv>=1.0.0
19
+ Requires-Dist: requests>=2.31.0
20
+ Requires-Dist: pydantic>=2.5.0
21
+ Requires-Dist: pyyaml>=6.0
22
+ Provides-Extra: dev
23
+ Requires-Dist: pytest>=7.0; extra == "dev"
24
+ Requires-Dist: pytest-cov>=4.0; extra == "dev"
25
+ Provides-Extra: claude
26
+ Requires-Dist: anthropic>=0.39.0; extra == "claude"
27
+ Provides-Extra: openai
28
+ Requires-Dist: openai>=1.0.0; extra == "openai"
29
+ Provides-Extra: deepseek
30
+ Requires-Dist: openai>=1.0.0; extra == "deepseek"
31
+ Provides-Extra: langgraph
32
+ Requires-Dist: langgraph>=0.2.0; extra == "langgraph"
33
+ Provides-Extra: mcp
34
+ Requires-Dist: mcp[cli]>=1.0.0; extra == "mcp"
35
+ Provides-Extra: dashboard
36
+ Requires-Dist: streamlit>=1.30.0; extra == "dashboard"
37
+ Provides-Extra: all
38
+ Requires-Dist: anthropic>=0.39.0; extra == "all"
39
+ Requires-Dist: openai>=1.0.0; extra == "all"
40
+ Requires-Dist: langgraph>=0.2.0; extra == "all"
41
+ Requires-Dist: mcp[cli]>=1.0.0; extra == "all"
42
+ Requires-Dist: streamlit>=1.30.0; extra == "all"
43
+ Dynamic: license-file
44
+
45
+ # CannyForge
46
+
47
+ **Reliability memory for tool-using LLM agents.**
48
+
49
+ CannyForge watches your agent make mistakes, learns corrections, and injects them as SystemMessages before each LLM call. Your agent gets better over time — no retraining required.
50
+
51
+ ```
52
+ Agent makes errors → CannyForge learns corrections → Agent stops repeating them
53
+ ```
54
+
55
+ ## Quick Start (LangGraph)
56
+
57
+ ```python
58
+ from cannyforge import CannyForge
59
+ from cannyforge.adapters.langgraph import CannyForgeMiddleware
60
+ from langgraph.prebuilt import create_react_agent
61
+
62
+ forge = CannyForge()
63
+ middleware = CannyForgeMiddleware(forge)
64
+ agent = create_react_agent(model, tools,
65
+ pre_model_hook=middleware.before_model,
66
+ post_model_hook=middleware.after_model)
67
+
68
+ # Just run tasks. CannyForge records errors via after_model.
69
+ # After learning, before_model injects corrections as SystemMessages.
70
+ ```
71
+
72
+ ## How It Works
73
+
74
+ 1. **Record errors** — `after_model` detects tool failures and records them
75
+ 2. **Learn corrections** — `run_learning_cycle()` clusters errors and generates specific correction text (template or LLM-generated)
76
+ 3. **Inject corrections** — `before_model` prepends a SystemMessage with all active corrections before each LLM call
77
+ 4. **Track effectiveness** — corrections that prevent recurrence are kept; ineffective ones can be regenerated
78
+
79
+ The correction is specific and actionable:
80
+ ```
81
+ [CANNYFORGE] Learned rules for this request:
82
+ - When the task involves report, summary, sales, use `generate_report`, NOT `get_data`.
83
+ Example: "Create a summary of Q4 sales performance"
84
+ ```
85
+
86
+ ## Demo: 60% → 100% on Real LLM
87
+
88
+ ```bash
89
+ pip install langgraph langchain-openai
90
+ # Set LLM_API_KEY in .env
91
+ python scenarios/demo_cannyforge.py
92
+ ```
93
+
94
+ This runs 15 ambiguous tool-selection tasks twice:
95
+ - **Phase 1**: baseline without corrections — records errors
96
+ - **Learning**: generates corrections from observed errors
97
+ - **Phase 2**: same tasks with correction injection — accuracy improves
98
+
99
+ Real output with DeepSeek:
100
+ ```
101
+ Phase 1 accuracy: 9/15 (60%)
102
+ Phase 2 accuracy: 15/15 (100%)
103
+ Tasks fixed:
104
+ - Restart the staging server -> execute_action
105
+ - Send an alert to the on-call team -> execute_action
106
+ - Deploy the latest build to production -> execute_action
107
+ - Create a summary of Q4 sales performance -> generate_report
108
+ - Write up a status report for this sprint -> generate_report
109
+ - Generate a monthly uptime report -> generate_report
110
+ ```
111
+
112
+ No simulated errors. No hand-crafted rules. Real LLM decisions, real corrections from the pipeline.
113
+
114
+ ## Install
115
+
116
+ ```bash
117
+ pip install cannyforge # from PyPI
118
+ ```
119
+
120
+ Or from source:
121
+ ```bash
122
+ git clone https://github.com/cannyforge/cannyforge.git
123
+ cd cannyforge
124
+ pip install -e .
125
+ ```
126
+
127
+ ## Scenarios
128
+
129
+ | Script | Purpose |
130
+ |--------|---------|
131
+ | `scenarios/demo_cannyforge.py` | **Canonical demo** — full pipeline: baseline → learn → improve |
132
+ | `scenarios/demo_langgraph_tool_use.py` | Minimal quickstart — 3-line integration |
133
+ | `scenarios/demo.py` | Animated terminal demo (internal skill system) |
134
+
135
+ Older demo scripts are in `scenarios/archive/` for reference.
136
+
137
+ ## Core Architecture
138
+
139
+ ### Corrections Pipeline (LangGraph integration)
140
+
141
+ ```
142
+ cannyforge/corrections.py — Correction dataclass + CorrectionGenerator
143
+ cannyforge/adapters/langgraph.py — CannyForgeMiddleware (pre/post model hooks)
144
+ cannyforge/knowledge.py — KnowledgeBase stores corrections + rules
145
+ cannyforge/learning.py — PatternDetector + LearningEngine
146
+ cannyforge/core.py — CannyForge orchestrator
147
+ ```
148
+
149
+ **CorrectionGenerator** turns error clusters into actionable text:
150
+ - **Template mode** (no LLM): groups by `(wrong_tool, right_tool)`, extracts keywords, formats guidance
151
+ - **LLM mode**: sends error cluster to LLM asking for a generalized rule covering unseen tasks
152
+
153
+ **CannyForgeMiddleware** hooks into LangGraph's `create_react_agent`:
154
+ - `before_model`: injects always-on corrections + conditional rules as a SystemMessage
155
+ - `after_model`: records tool failures, tracks correction effectiveness
156
+
157
+ ### Internal Skill System
158
+
159
+ CannyForge also includes a declarative skill system for standalone use (without LangGraph):
160
+
161
+ - Skills defined via `SKILL.md` files ([AgentSkills.io](https://agentskills.io/specification) spec)
162
+ - Three-tier execution: custom handler → LLM multi-step → template fallback
163
+ - PATTERN_LIBRARY with condition-based rules for internal context signals
164
+ - Rule lifecycle: ACTIVE → PROBATION → DORMANT → resurrection
165
+
166
+ ```python
167
+ from cannyforge import CannyForge
168
+ forge = CannyForge()
169
+ result = forge.execute("Write an email about the 3 PM meeting")
170
+ ```
171
+
172
+ See `scenarios/demo.py` for the animated terminal demo of this path.
173
+
174
+ ## How Learning Works
175
+
176
+ ### 1. Error Recording
177
+
178
+ ```python
179
+ # Via middleware (automatic):
180
+ agent = create_react_agent(llm, tools, post_model_hook=middleware.after_model)
181
+
182
+ # Or manual:
183
+ forge.learning_engine.record_error(
184
+ skill_name="tool_use",
185
+ task_description="Create a Q4 summary",
186
+ error_type="WrongToolError",
187
+ error_message="Called get_data instead of generate_report",
188
+ context_snapshot={...},
189
+ )
190
+ ```
191
+
192
+ ### 2. Learning Cycle
193
+
194
+ ```python
195
+ metrics = forge.run_learning_cycle(min_frequency=2, min_confidence=0.3)
196
+ # Produces:
197
+ # - Condition-based rules (for internal skill system)
198
+ # - Corrections (for LangGraph injection)
199
+ ```
200
+
201
+ ### 3. Correction Injection
202
+
203
+ ```python
204
+ corrections = forge.knowledge_base.get_corrections("tool_use")
205
+ # [Correction(content="When task involves report, summary... use generate_report, NOT get_data")]
206
+
207
+ # Automatically injected by middleware.before_model() as a SystemMessage
208
+ ```
209
+
210
+ ## Run Tests
211
+
212
+ ```bash
213
+ pytest tests/ -v
214
+ ```
215
+
216
+ ## Project Structure
217
+
218
+ ```
219
+ cannyforge/
220
+ ├── cannyforge/
221
+ │ ├── core.py # CannyForge orchestrator
222
+ │ ├── corrections.py # Correction + CorrectionGenerator
223
+ │ ├── knowledge.py # KnowledgeBase, Rules, Conditions, Actions
224
+ │ ├── learning.py # PatternDetector, LearningEngine
225
+ │ ├── skills.py # Declarative skill system
226
+ │ ├── llm.py # LLM providers (Claude, OpenAI, DeepSeek)
227
+ │ ├── tools.py # Tool definitions and execution
228
+ │ ├── storage.py # Storage backends (JSON, SQLite)
229
+ │ └── adapters/
230
+ │ └── langgraph.py # LangGraph middleware (pre/post model hooks)
231
+
232
+ ├── scenarios/
233
+ │ ├── demo_cannyforge.py # Canonical demo (corrections pipeline)
234
+ │ ├── demo_langgraph_tool_use.py # Minimal quickstart
235
+ │ └── demo.py # Animated demo (internal skill system)
236
+
237
+ ├── tests/ # Test suite
238
+ └── skills/ # Built-in skill definitions (SKILL.md)
239
+ ```
240
+
241
+ ## Further Reading
242
+
243
+ - Blog post: [From Prompt Tweaks to Learning Machines: The Agent Skill Primitive](https://medium.com/@xiweizhou/from-prompt-tweaks-to-learning-machines-the-agent-skill-primitive-93c8fa9dec8c?sk=ac888430da699bce7b635456ae2b1166)
244
+
245
+ ## License
246
+
247
+ Licensed under [BSL 1.1](LICENSE). Free to use in production, but you may not offer CannyForge as a competing hosted service. Converts to Apache 2.0 on 2030-03-01. See LICENSE for full terms.
248
+
249
+ For commercial licensing inquiries: cannyforge@gmail.com
250
+
251
+ ---
252
+
253
+ **CannyForge** — Your agent makes fewer repeated mistakes over time, with measurable evidence.
@@ -0,0 +1,209 @@
1
+ # CannyForge
2
+
3
+ **Reliability memory for tool-using LLM agents.**
4
+
5
+ CannyForge watches your agent make mistakes, learns corrections, and injects them as SystemMessages before each LLM call. Your agent gets better over time — no retraining required.
6
+
7
+ ```
8
+ Agent makes errors → CannyForge learns corrections → Agent stops repeating them
9
+ ```
10
+
11
+ ## Quick Start (LangGraph)
12
+
13
+ ```python
14
+ from cannyforge import CannyForge
15
+ from cannyforge.adapters.langgraph import CannyForgeMiddleware
16
+ from langgraph.prebuilt import create_react_agent
17
+
18
+ forge = CannyForge()
19
+ middleware = CannyForgeMiddleware(forge)
20
+ agent = create_react_agent(model, tools,
21
+ pre_model_hook=middleware.before_model,
22
+ post_model_hook=middleware.after_model)
23
+
24
+ # Just run tasks. CannyForge records errors via after_model.
25
+ # After learning, before_model injects corrections as SystemMessages.
26
+ ```
27
+
28
+ ## How It Works
29
+
30
+ 1. **Record errors** — `after_model` detects tool failures and records them
31
+ 2. **Learn corrections** — `run_learning_cycle()` clusters errors and generates specific correction text (template or LLM-generated)
32
+ 3. **Inject corrections** — `before_model` prepends a SystemMessage with all active corrections before each LLM call
33
+ 4. **Track effectiveness** — corrections that prevent recurrence are kept; ineffective ones can be regenerated
34
+
35
+ The correction is specific and actionable:
36
+ ```
37
+ [CANNYFORGE] Learned rules for this request:
38
+ - When the task involves report, summary, sales, use `generate_report`, NOT `get_data`.
39
+ Example: "Create a summary of Q4 sales performance"
40
+ ```
41
+
42
+ ## Demo: 60% → 100% on Real LLM
43
+
44
+ ```bash
45
+ pip install langgraph langchain-openai
46
+ # Set LLM_API_KEY in .env
47
+ python scenarios/demo_cannyforge.py
48
+ ```
49
+
50
+ This runs 15 ambiguous tool-selection tasks twice:
51
+ - **Phase 1**: baseline without corrections — records errors
52
+ - **Learning**: generates corrections from observed errors
53
+ - **Phase 2**: same tasks with correction injection — accuracy improves
54
+
55
+ Real output with DeepSeek:
56
+ ```
57
+ Phase 1 accuracy: 9/15 (60%)
58
+ Phase 2 accuracy: 15/15 (100%)
59
+ Tasks fixed:
60
+ - Restart the staging server -> execute_action
61
+ - Send an alert to the on-call team -> execute_action
62
+ - Deploy the latest build to production -> execute_action
63
+ - Create a summary of Q4 sales performance -> generate_report
64
+ - Write up a status report for this sprint -> generate_report
65
+ - Generate a monthly uptime report -> generate_report
66
+ ```
67
+
68
+ No simulated errors. No hand-crafted rules. Real LLM decisions, real corrections from the pipeline.
69
+
70
+ ## Install
71
+
72
+ ```bash
73
+ pip install cannyforge # from PyPI
74
+ ```
75
+
76
+ Or from source:
77
+ ```bash
78
+ git clone https://github.com/cannyforge/cannyforge.git
79
+ cd cannyforge
80
+ pip install -e .
81
+ ```
82
+
83
+ ## Scenarios
84
+
85
+ | Script | Purpose |
86
+ |--------|---------|
87
+ | `scenarios/demo_cannyforge.py` | **Canonical demo** — full pipeline: baseline → learn → improve |
88
+ | `scenarios/demo_langgraph_tool_use.py` | Minimal quickstart — 3-line integration |
89
+ | `scenarios/demo.py` | Animated terminal demo (internal skill system) |
90
+
91
+ Older demo scripts are in `scenarios/archive/` for reference.
92
+
93
+ ## Core Architecture
94
+
95
+ ### Corrections Pipeline (LangGraph integration)
96
+
97
+ ```
98
+ cannyforge/corrections.py — Correction dataclass + CorrectionGenerator
99
+ cannyforge/adapters/langgraph.py — CannyForgeMiddleware (pre/post model hooks)
100
+ cannyforge/knowledge.py — KnowledgeBase stores corrections + rules
101
+ cannyforge/learning.py — PatternDetector + LearningEngine
102
+ cannyforge/core.py — CannyForge orchestrator
103
+ ```
104
+
105
+ **CorrectionGenerator** turns error clusters into actionable text:
106
+ - **Template mode** (no LLM): groups by `(wrong_tool, right_tool)`, extracts keywords, formats guidance
107
+ - **LLM mode**: sends error cluster to LLM asking for a generalized rule covering unseen tasks
108
+
109
+ **CannyForgeMiddleware** hooks into LangGraph's `create_react_agent`:
110
+ - `before_model`: injects always-on corrections + conditional rules as a SystemMessage
111
+ - `after_model`: records tool failures, tracks correction effectiveness
112
+
113
+ ### Internal Skill System
114
+
115
+ CannyForge also includes a declarative skill system for standalone use (without LangGraph):
116
+
117
+ - Skills defined via `SKILL.md` files ([AgentSkills.io](https://agentskills.io/specification) spec)
118
+ - Three-tier execution: custom handler → LLM multi-step → template fallback
119
+ - PATTERN_LIBRARY with condition-based rules for internal context signals
120
+ - Rule lifecycle: ACTIVE → PROBATION → DORMANT → resurrection
121
+
122
+ ```python
123
+ from cannyforge import CannyForge
124
+ forge = CannyForge()
125
+ result = forge.execute("Write an email about the 3 PM meeting")
126
+ ```
127
+
128
+ See `scenarios/demo.py` for the animated terminal demo of this path.
129
+
130
+ ## How Learning Works
131
+
132
+ ### 1. Error Recording
133
+
134
+ ```python
135
+ # Via middleware (automatic):
136
+ agent = create_react_agent(llm, tools, post_model_hook=middleware.after_model)
137
+
138
+ # Or manual:
139
+ forge.learning_engine.record_error(
140
+ skill_name="tool_use",
141
+ task_description="Create a Q4 summary",
142
+ error_type="WrongToolError",
143
+ error_message="Called get_data instead of generate_report",
144
+ context_snapshot={...},
145
+ )
146
+ ```
147
+
148
+ ### 2. Learning Cycle
149
+
150
+ ```python
151
+ metrics = forge.run_learning_cycle(min_frequency=2, min_confidence=0.3)
152
+ # Produces:
153
+ # - Condition-based rules (for internal skill system)
154
+ # - Corrections (for LangGraph injection)
155
+ ```
156
+
157
+ ### 3. Correction Injection
158
+
159
+ ```python
160
+ corrections = forge.knowledge_base.get_corrections("tool_use")
161
+ # [Correction(content="When task involves report, summary... use generate_report, NOT get_data")]
162
+
163
+ # Automatically injected by middleware.before_model() as a SystemMessage
164
+ ```
165
+
166
+ ## Run Tests
167
+
168
+ ```bash
169
+ pytest tests/ -v
170
+ ```
171
+
172
+ ## Project Structure
173
+
174
+ ```
175
+ cannyforge/
176
+ ├── cannyforge/
177
+ │ ├── core.py # CannyForge orchestrator
178
+ │ ├── corrections.py # Correction + CorrectionGenerator
179
+ │ ├── knowledge.py # KnowledgeBase, Rules, Conditions, Actions
180
+ │ ├── learning.py # PatternDetector, LearningEngine
181
+ │ ├── skills.py # Declarative skill system
182
+ │ ├── llm.py # LLM providers (Claude, OpenAI, DeepSeek)
183
+ │ ├── tools.py # Tool definitions and execution
184
+ │ ├── storage.py # Storage backends (JSON, SQLite)
185
+ │ └── adapters/
186
+ │ └── langgraph.py # LangGraph middleware (pre/post model hooks)
187
+
188
+ ├── scenarios/
189
+ │ ├── demo_cannyforge.py # Canonical demo (corrections pipeline)
190
+ │ ├── demo_langgraph_tool_use.py # Minimal quickstart
191
+ │ └── demo.py # Animated demo (internal skill system)
192
+
193
+ ├── tests/ # Test suite
194
+ └── skills/ # Built-in skill definitions (SKILL.md)
195
+ ```
196
+
197
+ ## Further Reading
198
+
199
+ - Blog post: [From Prompt Tweaks to Learning Machines: The Agent Skill Primitive](https://medium.com/@xiweizhou/from-prompt-tweaks-to-learning-machines-the-agent-skill-primitive-93c8fa9dec8c?sk=ac888430da699bce7b635456ae2b1166)
200
+
201
+ ## License
202
+
203
+ Licensed under [BSL 1.1](LICENSE). Free to use in production, but you may not offer CannyForge as a competing hosted service. Converts to Apache 2.0 on 2030-03-01. See LICENSE for full terms.
204
+
205
+ For commercial licensing inquiries: cannyforge@gmail.com
206
+
207
+ ---
208
+
209
+ **CannyForge** — Your agent makes fewer repeated mistakes over time, with measurable evidence.
@@ -48,8 +48,10 @@ from cannyforge.learning import (
48
48
  ErrorRepository,
49
49
  )
50
50
  from cannyforge.tools import ToolDefinition, ToolExecutor, ToolRegistry
51
+ from cannyforge.adapters.langgraph import CannyForgeMiddleware
52
+ from cannyforge.corrections import Correction, CorrectionGenerator
51
53
 
52
- __version__ = "0.2.0"
54
+ __version__ = "0.3.0"
53
55
 
54
56
  __all__ = [
55
57
  # Core
@@ -91,4 +93,9 @@ __all__ = [
91
93
  "ToolDefinition",
92
94
  "ToolExecutor",
93
95
  "ToolRegistry",
96
+ # Adapters
97
+ "CannyForgeMiddleware",
98
+ # Corrections
99
+ "Correction",
100
+ "CorrectionGenerator",
94
101
  ]
@@ -6,5 +6,6 @@ AI/agent frameworks. Each adapter is ~50-80 lines.
6
6
 
7
7
  Available adapters:
8
8
  - langchain: CannyForgeTool for LangChain
9
+ - langgraph: CannyForgeMiddleware for LangGraph agents
9
10
  - crewai: CannyForgeCrewTool for CrewAI
10
11
  """