ApiLogicServer 15.4.3__py3-none-any.whl → 16.0.0__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.
Files changed (26) hide show
  1. api_logic_server_cli/add_cust/add_cust.py +6 -2
  2. api_logic_server_cli/api_logic_server.py +2 -1
  3. api_logic_server_cli/database/basic_demo.sqlite +0 -0
  4. api_logic_server_cli/prototypes/base/.github/.copilot-instructions.md +228 -76
  5. api_logic_server_cli/prototypes/base/docs/training/OVERVIEW.md +64 -0
  6. api_logic_server_cli/prototypes/base/docs/training/README.md +140 -0
  7. api_logic_server_cli/prototypes/base/docs/training/genai_logic_patterns.md +443 -0
  8. api_logic_server_cli/prototypes/base/docs/training/logic_bank_api.prompt +22 -0
  9. api_logic_server_cli/prototypes/base/docs/training/logic_bank_patterns.prompt +445 -0
  10. api_logic_server_cli/prototypes/base/docs/training/probabilistic_logic.prompt +1074 -0
  11. api_logic_server_cli/prototypes/base/docs/training/probabilistic_logic_guide.md +444 -0
  12. api_logic_server_cli/prototypes/base/docs/training/probabilistic_template.py +326 -0
  13. api_logic_server_cli/prototypes/base/logic/logic_discovery/auto_discovery.py +8 -9
  14. api_logic_server_cli/prototypes/basic_demo/.github/.copilot-instructions.md +326 -142
  15. api_logic_server_cli/prototypes/basic_demo/.github/welcome.md +15 -1
  16. api_logic_server_cli/prototypes/basic_demo/customizations/database/db.sqlite +0 -0
  17. api_logic_server_cli/prototypes/basic_demo/iteration/database/db.sqlite +0 -0
  18. api_logic_server_cli/prototypes/manager/.github/.copilot-instructions.md +61 -155
  19. api_logic_server_cli/prototypes/manager/.github/welcome.md +43 -0
  20. api_logic_server_cli/prototypes/manager/samples/basic_demo_sample/.github/.copilot-instructions.md +502 -76
  21. {apilogicserver-15.4.3.dist-info → apilogicserver-16.0.0.dist-info}/METADATA +1 -1
  22. {apilogicserver-15.4.3.dist-info → apilogicserver-16.0.0.dist-info}/RECORD +26 -18
  23. {apilogicserver-15.4.3.dist-info → apilogicserver-16.0.0.dist-info}/WHEEL +0 -0
  24. {apilogicserver-15.4.3.dist-info → apilogicserver-16.0.0.dist-info}/entry_points.txt +0 -0
  25. {apilogicserver-15.4.3.dist-info → apilogicserver-16.0.0.dist-info}/licenses/LICENSE +0 -0
  26. {apilogicserver-15.4.3.dist-info → apilogicserver-16.0.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,140 @@
1
+ # Training Documentation Structure
2
+
3
+ This directory contains training materials for ApiLogicServer with GenAI integration.
4
+
5
+ ## Documentation Organization
6
+
7
+ ### Universal Framework Patterns
8
+ **File:** `genai_logic_patterns.md`
9
+ **Scope:** Framework-level patterns applicable to ANY ApiLogicServer project using AI
10
+ **Topics:**
11
+ - Critical imports (Rule vs RuleBank)
12
+ - LogicBank triggered insert pattern
13
+ - AI value computation architecture
14
+ - Auto-discovery system
15
+ - Formula patterns with AI
16
+ - Event handler patterns
17
+ - Testing patterns
18
+ - Error handling
19
+ - Best practices
20
+
21
+ **Use this when:** You need to understand core GenAI-LogicBank integration patterns regardless of project.
22
+
23
+ ---
24
+
25
+ ### Probabilistic Logic Implementation
26
+ **File:** `probabilistic_logic_guide.md`
27
+ **Scope:** Implementing probabilistic (AI-powered) business rules
28
+ **Topics:**
29
+ - Conditional formulas (deterministic vs AI)
30
+ - Request Pattern for audit trails
31
+ - Integration with deterministic rules
32
+ - Execution flow
33
+ - Testing probabilistic rules
34
+ - Common implementation patterns
35
+ - Troubleshooting AI integration
36
+
37
+ **Use this when:** You're implementing AI-powered rules in your project.
38
+
39
+ ---
40
+
41
+ ### Code Templates
42
+ **File:** `template_probabilistic_rules.py`
43
+ **Scope:** Working code examples for copy/paste
44
+ **Topics:**
45
+ - Complete working implementation
46
+ - Deterministic rules
47
+ - Conditional formula with AI
48
+ - Reusable AI handler pattern
49
+ - Event handler registration
50
+
51
+ **Use this when:** You need code to copy and adapt for your project.
52
+
53
+ ---
54
+
55
+ ## Quick Navigation
56
+
57
+ **I want to...**
58
+
59
+ - **Understand LogicBank + AI patterns** → `genai_logic_patterns.md`
60
+ - **Implement AI rules in my project** → `probabilistic_logic_guide.md`
61
+ - **Copy working code** → `template_probabilistic_rules.py`
62
+ - **Fix import errors** → `genai_logic_patterns.md` (Section 1)
63
+ - **Fix "Session is already flushing"** → `genai_logic_patterns.md` (Section 2)
64
+ - **Add audit trails** → `probabilistic_logic_guide.md` (Section 2)
65
+ - **Test AI rules** → `probabilistic_logic_guide.md` (Section 4)
66
+
67
+ ---
68
+
69
+ ## Other Training Materials
70
+
71
+ This directory also contains:
72
+
73
+ - **API Documentation:**
74
+ - `logic_bank_api.prompt` - LogicBank API reference
75
+ - `logic_bank_api_probabilistic.prompt` - Probabilistic extensions
76
+ - `logic_bank_patterns.prompt` - Pattern library
77
+
78
+ - **Admin App Documentation:**
79
+ - `admin_app_1_context.prompt.md` - Admin app context
80
+ - `admin_app_2_functionality.prompt.md` - Functionality guide
81
+ - `admin_app_3_architecture.prompt.md` - Architecture overview
82
+ - `react_map.prompt.md` - React component mapping
83
+ - `react_tree.prompt.md` - Component tree structure
84
+
85
+ - **Integration Guides:**
86
+ - `MCP_Copilot_Integration.md` - Model Context Protocol integration
87
+ - `testing.md` - Testing strategies
88
+
89
+ - **Refactoring History:**
90
+ - `REFACTORING_SUMMARY.md` - Summary of architecture changes
91
+ - `REFACTORING_v1.5_analysis.md` - v1.5 analysis
92
+ - `UPDATES_v1.4.md` - v1.4 updates
93
+
94
+ - **Examples:**
95
+ - `logic_example.py` - Example logic implementations
96
+
97
+ ---
98
+
99
+ ## Contributing
100
+
101
+ When adding new training materials:
102
+
103
+ 1. **Choose the right file:**
104
+ - Universal patterns → `genai_logic_patterns.md`
105
+ - Implementation patterns → `probabilistic_logic_guide.md`
106
+ - Project-specific → Keep outside `docs/training/` folder
107
+
108
+ 2. **Keep separation clear:**
109
+ - Don't mix framework patterns with project specifics
110
+ - Don't duplicate content across files
111
+ - Use cross-references when needed
112
+
113
+ 3. **Update this README:**
114
+ - Add new files to appropriate section
115
+ - Update quick navigation if needed
116
+
117
+ 4. **Provide examples:**
118
+ - Include code examples
119
+ - Show both correct and incorrect patterns
120
+ - Explain why patterns work
121
+
122
+ ---
123
+
124
+ ## Maintenance
125
+
126
+ **Regular reviews:**
127
+ - Check for outdated information
128
+ - Consolidate duplicate content
129
+ - Update cross-references
130
+ - Add new troubleshooting cases
131
+
132
+ **Version updates:**
133
+ - Update examples when LogicBank API changes
134
+ - Document breaking changes
135
+ - Provide migration guides
136
+
137
+ **Feedback:**
138
+ - Collect common questions
139
+ - Add FAQ sections
140
+ - Improve unclear explanations
@@ -0,0 +1,443 @@
1
+ ---
2
+ version: 1.0
3
+ ---
4
+
5
+ # GenAI Logic Patterns - Universal Guide
6
+
7
+ **Scope:** Framework-level patterns for integrating AI into business logic using LogicBank.
8
+ **Applies to:** Any ApiLogicServer project using AI-powered rules.
9
+
10
+ ---
11
+
12
+ ## 1. Critical Imports - AVOID CIRCULAR IMPORTS
13
+
14
+ ### ⚠️ CRITICAL: Import LogicBank ONLY Inside Functions
15
+
16
+ **Problem:** Importing `LogicRow`, `Rule` at module level causes circular import errors during auto-discovery.
17
+
18
+ ### ❌ WRONG (causes circular import):
19
+ ```python
20
+ # At module level - DO NOT DO THIS
21
+ from logic_bank.exec_row_logic.logic_row import LogicRow
22
+ from logic_bank.logic_bank import Rule
23
+ from database import models
24
+
25
+ def declare_logic():
26
+ Rule.formula(...) # ❌ Circular import error
27
+ ```
28
+
29
+ ### ✅ CORRECT (import inside functions):
30
+ ```python
31
+ # At module level - only non-LogicBank imports
32
+ import database.models as models
33
+
34
+ def declare_logic():
35
+ from logic_bank.logic_bank import Rule # ✅ Import inside function
36
+
37
+ Rule.formula(derive=models.Item.unit_price, calling=my_formula)
38
+
39
+ def my_formula(row, old_row, logic_row): # ✅ No type hints on logic_row
40
+ from logic.ai_requests.handler import get_ai_value # ✅ Import when needed
41
+ return get_ai_value(row, logic_row)
42
+ ```
43
+
44
+ **Why:** LogicBank's auto-discovery imports modules during initialization. Module-level LogicBank imports create circular dependencies that fail with "cannot import name 'LogicRow' from partially initialized module".
45
+
46
+ **Pattern for All Logic Files:**
47
+ 1. ✅ Import `database.models as models` at module level
48
+ 2. ✅ Import `Rule` inside `declare_logic()` function
49
+ 3. ✅ Import other logic modules inside functions where used
50
+ 4. ✅ No type hints on `logic_row` parameters (avoid `LogicRow` import)
51
+ 5. ✅ Import external libraries (OpenAI, yaml, etc.) inside functions that use them
52
+
53
+ ---
54
+
55
+ ## 2. LogicBank Triggered Insert Pattern
56
+
57
+ **Problem:** Cannot use `session.add()` + `session.flush()` inside formulas because formulas execute DURING SQLAlchemy's flush cycle (nested flush not allowed).
58
+
59
+ ### ❌ WRONG (causes "Session is already flushing" error):
60
+ ```python
61
+ def my_formula(row, old_row, logic_row):
62
+ audit_record = models.AuditTable(data=...)
63
+ logic_row.session.add(audit_record)
64
+ logic_row.session.flush() # ❌ ERROR: Session is already flushing
65
+ return audit_record.computed_value
66
+ ```
67
+
68
+ ### ✅ CORRECT (LogicBank triggered insert):
69
+ ```python
70
+ def my_formula(row, old_row, logic_row):
71
+ # Use LogicBank API instead of session
72
+ audit_logic_row = logic_row.new_logic_row(models.AuditTable)
73
+ audit_record = audit_logic_row.row
74
+ audit_logic_row.link(to_parent=logic_row)
75
+ audit_record.data = ...
76
+ audit_logic_row.insert(reason="AI computation")
77
+ return audit_record.computed_value # Populated by event handler
78
+
79
+ def populate_audit_fields(row, old_row, logic_row):
80
+ if logic_row.is_inserted():
81
+ # Event handler fires DURING formula execution
82
+ row.computed_value = ...
83
+ row.audit_details = ...
84
+
85
+ Rule.early_row_event(on_class=models.AuditTable, calling=populate_audit_fields)
86
+ ```
87
+
88
+ **Key Points:**
89
+ - `logic_row.new_logic_row()` creates row without session
90
+ - `logic_row.insert()` uses LogicBank's insert mechanism
91
+ - Event handler fires DURING formula execution
92
+ - Formula returns value populated by event handler
93
+
94
+ **Reference:** https://apilogicserver.github.io/Docs/Logic-Use/#in-logic
95
+
96
+ ---
97
+
98
+ ## 3. AI Value Computation Architecture
99
+
100
+ ### Pattern: Reusable AI Handlers
101
+
102
+ **Structure:**
103
+ ```
104
+ logic/
105
+ logic_discovery/ # Use case logic
106
+ check_credit.py # Business rule that calls AI
107
+ ai_requests/ # Reusable AI handlers
108
+ supplier_selection.py # AI handler module
109
+ system/ # Framework utilities
110
+ ai_value_computation.py # Shared utilities
111
+ ```
112
+
113
+ **Use Case Logic (check_credit.py):**
114
+ ```python
115
+ from logic.logic_discovery.ai_requests.supplier_selection import get_supplier_price_from_ai
116
+
117
+ def ItemUnitPriceFromSupplier(row, old_row, logic_row):
118
+ """Conditional formula - use AI when suppliers exist"""
119
+ if row.product.count_suppliers == 0:
120
+ return row.product.unit_price # Fallback
121
+
122
+ # Call reusable AI handler (encapsulates Request Pattern)
123
+ logic_row.log(f"Item - Product has {row.product.count_suppliers} suppliers, invoking AI")
124
+ return get_supplier_price_from_ai(row=row, logic_row=logic_row)
125
+
126
+ Rule.formula(derive=models.Item.unit_price, calling=ItemUnitPriceFromSupplier)
127
+ ```
128
+
129
+ **AI Handler (ai_requests/supplier_selection.py):**
130
+ ```python
131
+ def get_supplier_price_from_ai(row, logic_row):
132
+ """
133
+ Returns optimal supplier price using AI selection.
134
+ Encapsulates Request Pattern - creates audit record, triggers AI, returns computed value.
135
+ """
136
+ # Create audit record using LogicBank triggered insert (Request Pattern)
137
+ supplier_req_logic_row = logic_row.new_logic_row(models.SysSupplierReq)
138
+ supplier_req = supplier_req_logic_row.row
139
+ supplier_req_logic_row.link(to_parent=logic_row)
140
+ supplier_req.product_id = row.product_id
141
+ supplier_req.item_id = row.id
142
+
143
+ # Insert triggers supplier_id_from_ai event handler which populates chosen_* fields
144
+ supplier_req_logic_row.insert(reason="AI supplier selection request")
145
+
146
+ # Return value populated by event handler
147
+ return supplier_req.chosen_unit_price
148
+
149
+ def supplier_id_from_ai(row, old_row, logic_row):
150
+ """Event handler - fires on SysSupplierReq insert, populates audit fields"""
151
+ if not logic_row.is_inserted():
152
+ return
153
+
154
+ # Get candidates, call AI, populate row fields
155
+ # (Full implementation in actual file)
156
+ row.chosen_supplier_id = ai_result['chosen_supplier_id']
157
+ row.chosen_unit_price = Decimal(str(ai_result['chosen_unit_price']))
158
+ row.reason = ai_result['reason']
159
+
160
+ def declare_logic():
161
+ """Self-register event handler for auto-discovery"""
162
+ from logic_bank.logic_bank import Rule
163
+ Rule.early_row_event(on_class=models.SysSupplierReq, calling=supplier_id_from_ai)
164
+ ```
165
+
166
+ **Benefits:**
167
+ - Separation of concerns (use case vs AI handler vs utilities)
168
+ - Reusability (multiple use cases can call same AI handler)
169
+ - Testability (each layer independently testable)
170
+ - Encapsulation (Request Pattern details hidden from use case)
171
+
172
+ ---
173
+
174
+ ## 4. Auto-Discovery System - RECURSIVE SCANNING REQUIRED
175
+
176
+ ### ⚠️ CRITICAL: Auto-Discovery Must Scan Subdirectories
177
+
178
+ **Problem:** Default auto_discovery.py only scans immediate directory, not subdirectories like `ai_requests/`.
179
+
180
+ ### ❌ WRONG (misses subdirectories):
181
+ ```python
182
+ def discover_logic():
183
+ for root, dirs, files in os.walk(logic_path):
184
+ for file in files:
185
+ spec = importlib.util.spec_from_file_location("module.name", logic_path.joinpath(file))
186
+ # ❌ Uses logic_path instead of actual file location
187
+ ```
188
+
189
+ ### ✅ CORRECT (recursive with proper paths):
190
+ ```python
191
+ def discover_logic():
192
+ """Discover additional logic in this directory and subdirectories"""
193
+ import os
194
+ logic = []
195
+ logic_path = Path(__file__).parent
196
+ for root, dirs, files in os.walk(logic_path):
197
+ root_path = Path(root) # ✅ Use actual subdirectory path
198
+ for file in files:
199
+ if file.endswith(".py") and not file.endswith("auto_discovery.py") and not file.startswith("__"):
200
+ file_path = root_path / file # ✅ Build complete path
201
+ spec = importlib.util.spec_from_file_location("module.name", file_path)
202
+ logic.append(str(file_path))
203
+ try:
204
+ each_logic_file = importlib.util.module_from_spec(spec)
205
+ spec.loader.exec_module(each_logic_file)
206
+ if hasattr(each_logic_file, 'declare_logic'):
207
+ each_logic_file.declare_logic()
208
+ except Exception as e:
209
+ app_logger.error(f"Error loading logic from {file_path}: {e}")
210
+ raise
211
+ ```
212
+
213
+ **Key Fixes:**
214
+ 1. ✅ Use `root_path = Path(root)` to get actual subdirectory path
215
+ 2. ✅ Build complete path: `file_path = root_path / file`
216
+ 3. ✅ Check for `declare_logic` existence with `hasattr()`
217
+ 4. ✅ Skip `__init__.py` and `auto_discovery.py` files
218
+ 5. ✅ Wrap in try/except to catch import errors with context
219
+
220
+ **Requirements:**
221
+ 1. Module must be in `logic/logic_discovery/` or subfolder
222
+ 2. Module must have `declare_logic()` function
223
+ 3. Function registers rules when called
224
+
225
+ **Example Structure:**
226
+ ```
227
+ logic/logic_discovery/
228
+ check_credit.py # ✅ Discovered
229
+ app_integration.py # ✅ Discovered
230
+ ai_requests/ # ✅ Subdirectory scanned
231
+ __init__.py # ✅ Skipped
232
+ supplier_selection.py # ✅ Discovered
233
+ ```
234
+
235
+ ---
236
+
237
+ ## 5. Formula Pattern with AI
238
+
239
+ **Basic Pattern:**
240
+ ```python
241
+ def MyFormula(row, old_row, logic_row):
242
+ """Formula computes value, optionally calling AI"""
243
+ if some_condition:
244
+ return simple_calculation()
245
+ else:
246
+ return ai_computation(...)
247
+
248
+ Rule.formula(derive=models.MyTable.my_field, calling=MyFormula)
249
+ ```
250
+
251
+ **Conditional Pattern:**
252
+ ```python
253
+ def ConditionalFormula(row, old_row, logic_row):
254
+ """Use default value OR call AI based on data availability"""
255
+ if not has_enough_data(row):
256
+ return row.default_value
257
+ return get_ai_value(row, logic_row, ...)
258
+
259
+ Rule.formula(derive=models.MyTable.computed_field, calling=ConditionalFormula)
260
+ ```
261
+
262
+ **Key Points:**
263
+ - Formula function returns computed value
264
+ - Can call reusable AI handlers
265
+ - AI handler encapsulates audit/request pattern
266
+ - Formula remains clean and readable
267
+
268
+ ---
269
+
270
+ ## 6. Event Handler Patterns
271
+
272
+ ### Early Row Event (for audit population):
273
+ ```python
274
+ def populate_audit_fields(row, old_row, logic_row):
275
+ """Fires DURING insert, before other rules"""
276
+ if logic_row.is_inserted():
277
+ row.field1 = compute_value1()
278
+ row.field2 = compute_value2()
279
+ # NO return value needed
280
+
281
+ Rule.early_row_event(on_class=models.AuditTable, calling=populate_audit_fields)
282
+ ```
283
+
284
+ ### Row Event (for side effects):
285
+ ```python
286
+ def notify_on_change(row, old_row, logic_row):
287
+ """Fires after all rules complete"""
288
+ if logic_row.nest_level == 0: # Top-level transaction
289
+ send_notification(row)
290
+ # NO return value
291
+
292
+ Rule.row_event(on_class=models.MyTable, calling=notify_on_change)
293
+ ```
294
+
295
+ **When to use:**
296
+ - **early_row_event:** Populate fields that other rules depend on
297
+ - **row_event:** Side effects after all rules complete
298
+
299
+ ---
300
+
301
+ ## 7. Common Patterns Summary
302
+
303
+ ### Pattern 1: Simple AI Formula
304
+ ```python
305
+ def ai_formula(row, old_row, logic_row):
306
+ return call_ai_service(row.data)
307
+
308
+ Rule.formula(derive=models.MyTable.field, calling=ai_formula)
309
+ ```
310
+
311
+ ### Pattern 2: Conditional AI Formula
312
+ ```python
313
+ def conditional_formula(row, old_row, logic_row):
314
+ if condition:
315
+ return default_value
316
+ return get_ai_value(...)
317
+
318
+ Rule.formula(derive=models.MyTable.field, calling=conditional_formula)
319
+ ```
320
+
321
+ ### Pattern 3: AI with Audit Trail
322
+ ```python
323
+ def formula_with_audit(row, old_row, logic_row):
324
+ audit_logic_row = logic_row.new_logic_row(models.AuditTable)
325
+ audit_logic_row.link(to_parent=logic_row)
326
+ audit_logic_row.insert(reason="AI")
327
+ return audit_logic_row.row.computed_value # From event handler
328
+
329
+ def audit_event(row, old_row, logic_row):
330
+ if logic_row.is_inserted():
331
+ row.computed_value = call_ai_service(...)
332
+ row.details = ...
333
+
334
+ Rule.formula(derive=models.MyTable.field, calling=formula_with_audit)
335
+ Rule.early_row_event(on_class=models.AuditTable, calling=audit_event)
336
+ ```
337
+
338
+ ### Pattern 4: Reusable AI Handler
339
+ ```python
340
+ # ai_requests/my_handler.py
341
+ def get_ai_value(row, logic_row, ...):
342
+ """Reusable across use cases"""
343
+ audit_logic_row = logic_row.new_logic_row(models.Audit)
344
+ audit_logic_row.insert(reason="AI")
345
+ return audit_logic_row.row.value
346
+
347
+ def declare_logic():
348
+ Rule.early_row_event(on_class=models.Audit, calling=populate_audit)
349
+
350
+ # check_credit.py
351
+ from logic.ai_requests.my_handler import get_ai_value
352
+
353
+ def my_formula(row, old_row, logic_row):
354
+ return get_ai_value(row, logic_row, ...)
355
+ ```
356
+
357
+ ---
358
+
359
+ ## 8. Testing Patterns
360
+
361
+ ### Test AI Handler Independently:
362
+ ```python
363
+ def test_ai_handler():
364
+ session = create_test_session()
365
+ row = create_test_item()
366
+ logic_row = LogicRow(row, old_row=None, ins_upd_dlt="ins", nest_level=0, a_session=session, row_sets=None)
367
+
368
+ result = get_ai_value(row, logic_row, ...)
369
+ assert result == expected_value
370
+ ```
371
+
372
+ ### Test with Mock AI:
373
+ ```python
374
+ @patch('logic.ai_requests.handler.call_ai_service')
375
+ def test_formula_with_mock_ai(mock_ai):
376
+ mock_ai.return_value = {"value": 100}
377
+ result = my_formula(row, old_row, logic_row)
378
+ assert result == 100
379
+ ```
380
+
381
+ ---
382
+
383
+ ## 9. Error Handling
384
+
385
+ ### Graceful Fallback:
386
+ ```python
387
+ def safe_ai_formula(row, old_row, logic_row):
388
+ try:
389
+ return get_ai_value(row, logic_row, ...)
390
+ except APIKeyMissing:
391
+ logic_row.log("API key missing, using fallback")
392
+ return row.fallback_value
393
+ except Exception as e:
394
+ logic_row.log(f"AI error: {e}, using fallback")
395
+ return row.fallback_value
396
+ ```
397
+
398
+ ### Audit Error Details:
399
+ ```python
400
+ def ai_event_with_error_handling(row, old_row, logic_row):
401
+ if logic_row.is_inserted():
402
+ try:
403
+ result = call_ai_service(...)
404
+ row.value = result.value
405
+ row.status = "success"
406
+ except Exception as e:
407
+ row.value = fallback_value
408
+ row.status = "error"
409
+ row.error_message = str(e)
410
+ ```
411
+
412
+ ---
413
+
414
+ ## 10. Best Practices
415
+
416
+ 1. **Imports:** Always use `from logic_bank.logic_bank import Rule`
417
+ 2. **Triggered Insert:** Use `logic_row.insert()` not `session.flush()` inside formulas
418
+ 3. **Reusability:** Put AI handlers in `ai_requests/` subfolder
419
+ 4. **Separation:** Use case logic separate from AI handlers separate from utilities
420
+ 5. **Auto-discovery:** Every module with rules needs `declare_logic()`
421
+ 6. **Testing:** Test AI handlers independently with mocks
422
+ 7. **Error Handling:** Always provide fallback values
423
+ 8. **Audit Trail:** Use Request Pattern for observability
424
+ 9. **Documentation:** Document what AI optimizes for
425
+ 10. **Logging:** Use `logic_row.log()` for visibility
426
+
427
+ ---
428
+
429
+ ## Summary
430
+
431
+ **Core Pattern:**
432
+ - Formula calls reusable AI handler
433
+ - AI handler uses triggered insert to create audit record
434
+ - Event handler populates audit fields DURING formula
435
+ - Formula returns value from audit record
436
+ - Everything auto-discovered from `logic/logic_discovery/`
437
+
438
+ **Key Insights:**
439
+ - AI is just value computation with audit trail
440
+ - LogicBank triggered insert avoids nested flush errors
441
+ - Reusable handlers improve maintainability
442
+ - Separation of concerns enables testing
443
+ - Auto-discovery enables modularity
@@ -1,5 +1,15 @@
1
+ ---
2
+ # LogicBank API Reference
3
+ # Version: 1.0.1
4
+ # Last Updated: November 17, 2025
5
+ # Description: The Logic Rosetta Stone: simplified API for creating declarative business logic rules
6
+ ---
7
+
1
8
  Here is the simplified API for LogicBank:
2
9
 
10
+ PREREQUISITE: For general patterns (event handler signatures, logging, request pattern, anti-patterns),
11
+ see docs/training/logic_bank_patterns.prompt
12
+
3
13
  Translate the user prompt into a series of calls to Rule methods, described here.
4
14
 
5
15
  Do not generate import statements.
@@ -10,6 +20,18 @@ Use only the methods provided below.
10
20
 
11
21
  IMPORTANT: Keep it simple! Use the built-in Rule methods with their parameters (like if_condition) rather than creating custom functions. The Rule methods are designed to handle common patterns directly.
12
22
 
23
+ CRITICAL: Follow the FORMATTING GUIDELINE below (lines 23-31) - keep simple rules on single line for scannability.
24
+
25
+ FORMATTING GUIDELINE: Keep rules compact and scannable.
26
+ - Simple rules: Single line preferred, but max about 150.
27
+ - Complex rules: Multi-line is fine, but keep parameters together
28
+ - Goal: Visual scannability - see rule count at a glance
29
+
30
+ Example:
31
+ Rule.sum(derive=Customer.balance, as_sum_of=Order.amount_total, where=lambda row: row.date_shipped is None)
32
+ Rule.constraint(validate=Customer, as_condition=lambda row: row.balance <= row.credit_limit, error_msg="balance exceeds credit")
33
+ Rule.formula(derive=Item.amount, as_expression=lambda row: row.quantity * row.unit_price)
34
+
13
35
 
14
36
  class Rule:
15
37
  """ Invoke these functions to declare rules """