ApiLogicServer 12.1.0__py3-none-any.whl → 12.1.26__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 (51) hide show
  1. {ApiLogicServer-12.1.0.dist-info → ApiLogicServer-12.1.26.dist-info}/METADATA +1 -1
  2. {ApiLogicServer-12.1.0.dist-info → ApiLogicServer-12.1.26.dist-info}/RECORD +47 -39
  3. {ApiLogicServer-12.1.0.dist-info → ApiLogicServer-12.1.26.dist-info}/WHEEL +1 -1
  4. api_logic_server_cli/api_logic_server.py +16 -4
  5. api_logic_server_cli/api_logic_server_info.yaml +3 -3
  6. api_logic_server_cli/cli.py +20 -9
  7. api_logic_server_cli/cli_args_base.py +2 -0
  8. api_logic_server_cli/cli_args_project.py +9 -3
  9. api_logic_server_cli/create_from_model/__pycache__/ont_create.cpython-312.pyc +0 -0
  10. api_logic_server_cli/create_from_model/__pycache__/ui_admin_creator.cpython-312.pyc +0 -0
  11. api_logic_server_cli/create_from_model/ont_create.py +3 -1
  12. api_logic_server_cli/create_from_model/ui_admin_creator.py +6 -4
  13. api_logic_server_cli/genai.py +386 -286
  14. api_logic_server_cli/logging.yml +5 -0
  15. api_logic_server_cli/prototypes/.DS_Store +0 -0
  16. api_logic_server_cli/prototypes/base/api_logic_server_run.py +0 -2
  17. api_logic_server_cli/prototypes/base/config/server_setup.py +15 -1
  18. api_logic_server_cli/prototypes/base/integration/kafka/kafka_consumer.py +1 -1
  19. api_logic_server_cli/prototypes/base/integration/kafka/kafka_producer.py +1 -1
  20. api_logic_server_cli/prototypes/base/readme.md +21 -8
  21. api_logic_server_cli/prototypes/manager/.DS_Store +0 -0
  22. api_logic_server_cli/prototypes/manager/.vscode/.DS_Store +0 -0
  23. api_logic_server_cli/prototypes/manager/.vscode/launch.json +20 -0
  24. api_logic_server_cli/prototypes/manager/README.md +25 -1
  25. api_logic_server_cli/prototypes/manager/system/.DS_Store +0 -0
  26. api_logic_server_cli/prototypes/manager/system/genai/.DS_Store +0 -0
  27. api_logic_server_cli/prototypes/manager/system/genai/create_db_models_inserts/create_db_models_create_db.py +1 -0
  28. api_logic_server_cli/prototypes/manager/system/genai/create_db_models_inserts/create_db_models_imports.py +10 -7
  29. api_logic_server_cli/prototypes/manager/system/genai/create_db_models_inserts/create_db_models_test_data.py +1 -1
  30. api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo.response_example +99 -22
  31. api_logic_server_cli/prototypes/manager/system/genai/learning_requests/logic_bank_api.prompt +120 -7
  32. api_logic_server_cli/prototypes/manager/system/genai/prompt_inserts/.DS_Store +0 -0
  33. api_logic_server_cli/prototypes/manager/system/genai/prompt_inserts/response_format.prompt +26 -2
  34. api_logic_server_cli/prototypes/manager/system/genai/prompt_inserts/sqlite_inserts.prompt +10 -4
  35. api_logic_server_cli/prototypes/manager/system/genai/prompt_inserts/{sqlite_inserts_iterations.prompt → zsqlite_inserts_iterations.prompt} +5 -2
  36. api_logic_server_cli/prototypes/manager/system/genai/retry/conv/create_db_models.py +96 -0
  37. api_logic_server_cli/prototypes/manager/system/genai/retry/conv/inf-1_iter_1_1_000.response +1 -0
  38. api_logic_server_cli/prototypes/manager/system/genai/retry/conv/inf-1_iter_1_1_001.prompt +208 -0
  39. api_logic_server_cli/prototypes/manager/system/genai/retry/conv/inf-1_iter_1_1_002.prompt +89 -0
  40. api_logic_server_cli/prototypes/manager/system/genai/retry/conv/inf-1_iter_1_1_003.prompt +40 -0
  41. api_logic_server_cli/prototypes/manager/system/genai/retry/conv/inf-1_iter_1_1_004.response +57 -0
  42. api_logic_server_cli/prototypes/manager/system/genai/retry/conv/inf-1_iter_1_1_005.response +57 -0
  43. api_logic_server_cli/prototypes/manager/system/genai/retry/readme.md +1 -0
  44. api_logic_server_cli/prototypes/manager/system/genai/retry/retry.response +57 -0
  45. api_logic_server_cli/genaiZ.py +0 -752
  46. api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo.response_example_z +0 -130
  47. api_logic_server_cli/prototypes/manager/system/genai/prompt_inserts/web_genai copy.prompt +0 -15
  48. api_logic_server_cli/prototypes/manager/system/secrets.txt +0 -6
  49. {ApiLogicServer-12.1.0.dist-info → ApiLogicServer-12.1.26.dist-info}/LICENSE +0 -0
  50. {ApiLogicServer-12.1.0.dist-info → ApiLogicServer-12.1.26.dist-info}/entry_points.txt +0 -0
  51. {ApiLogicServer-12.1.0.dist-info → ApiLogicServer-12.1.26.dist-info}/top_level.txt +0 -0
@@ -26,6 +26,11 @@ root:
26
26
 
27
27
  loggers:
28
28
 
29
+ api_logic_server_cli.api_logic_server:
30
+ # level: DEBUG
31
+ handlers: [console]
32
+ propagate: no
33
+
29
34
  create_from_model.api_logic_server_utils:
30
35
  # level: DEBUG
31
36
  handlers: [console]
Binary file
@@ -68,8 +68,6 @@ import ui.admin.admin_loader as AdminLoader
68
68
  from security.system.authentication import configure_auth
69
69
  import database.multi_db as multi_db
70
70
  import oracledb
71
- import integration.kafka.kafka_producer as kafka_producer
72
- import integration.kafka.kafka_consumer as kafka_consumer
73
71
 
74
72
 
75
73
  app_logger = server_setup.logging_setup()
@@ -317,7 +317,21 @@ def api_logic_server_setup(flask_app: Flask, args: Args):
317
317
  if logic_logger_activate_debug == False:
318
318
  logic_logger.setLevel(logging.INFO)
319
319
  app_logger.info("")
320
- LogicBank.activate(session=session, activator=declare_logic.declare_logic, constraint_event=constraint_handler)
320
+ disable_rules = False
321
+ if os.getenv('APILOGICPROJECT_DISABLE_RULES'):
322
+ disable_rules = os.getenv('APILOGICPROJECT_DISABLE_RULES').startswith("1") or \
323
+ os.getenv('APILOGICPROJECT_DISABLE_RULES').startswith("T") or \
324
+ os.getenv('APILOGICPROJECT_DISABLE_RULES').startswith("t") or \
325
+ os.getenv('APILOGICPROJECT_DISABLE_RULES').startswith("Y") or \
326
+ os.getenv('APILOGICPROJECT_DISABLE_RULES').startswith("y")
327
+ if disable_rules:
328
+ app_logger.info("LogicBank rules disabled") # db opened 1st access
329
+ else: # genai may insert rules with no columns... WebG restarts with rules disabled
330
+ try:
331
+ LogicBank.activate(session=session, activator=declare_logic.declare_logic, constraint_event=constraint_handler)
332
+ except Exception as e:
333
+ app_logger.error("Logic Bank Activation Error: " + str(e))
334
+ app_logger.exception(e)
321
335
  logic_logger.setLevel(logic_logger_level)
322
336
  app_logger.info("Declare Logic complete - logic/declare_logic.py (rules + code)"
323
337
  + f' -- {len(database.models.metadata.tables)} tables loaded\n') # db opened 1st access
@@ -1,5 +1,5 @@
1
1
  """
2
- Invoked at server start (api_logic_server_run.py)
2
+ Invoked at server start (api_logic_server_run.py -> config/setup.py)
3
3
 
4
4
  Listen/consume Kafka topis, if KAFKA_CONSUMER specified in Config.py
5
5
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  Version 1.1
4
4
 
5
- Invoked at server start (api_logic_server_run.py)
5
+ Invoked at server start (api_logic_server_run.py -> config/setup.py)
6
6
 
7
7
  Connect to Kafka, if KAFKA_CONNECT specified in Config.py
8
8
 
@@ -98,19 +98,32 @@ As shown above:
98
98
 
99
99
  Your project is ready to run, but it's likely you'll want to customize it - declare logic, new endpoints, etc.
100
100
 
101
- >> Tip: in particular, use the sample app to explore the value of ___declarative logic and security.___ Unique to API Logic Server, this is critical to unlocking the full value of API Logic Server.
102
101
 
103
- The ___Key Customization Files___ listed in the table below are created as stubs, intended for you to add customizations that extend the created API, Logic and Web App.
102
+ <details markdown>
104
103
 
105
- * Since they are separate files, the project can be
106
- [rebuilt](https://apilogicserver.github.io/Docs/Project-Rebuild/) (e.g., synchronized with a revised schema), preserving your customizations.
104
+ <summary>Important: explore customization examples</summary>
105
+ <br>
106
+ In particular, use the sample app to explore the value of declarative logic and security. Unique to API Logic Server, these are critical to unlocking the full value of API Logic Server.
107
107
 
108
- > Tip: create the sample app for customization examples: `ApiLogicServer create --project-name=nw_sample --db_url=nw+`
109
- > <br>Or, open it in GitHub (use Shift + "." to view in project mode) - [click here](https://github.com/ApiLogicServer/demo)
108
+ <br>
109
+
110
+ To create the sample app for customization examples:
111
+
112
+ * `ApiLogicServer create --project-name=nw_sample --db_url=nw+`
113
+ * Or, open it in GitHub (use Shift + "." to view in project mode) - [click here](https://github.com/ApiLogicServer/demo)
110
114
 
111
- To make customizations easy to explore, **search for:**
115
+ To make customizations easy to explore, search for:
112
116
  * `#als` will reveal key customization examples
113
- * `Your Code Goes Here` to find key files to customize, summarized below:
117
+ * `Your Code Goes Here` to find key files to customize, summarized in the table below.
118
+
119
+ </details>
120
+
121
+ &nbsp;
122
+
123
+ The ___Key Customization Files___ listed in the table below are created as stubs, intended for you to add customizations that extend the created API, Logic and Web App.
124
+
125
+ * Since they are separate files, the project can be
126
+ [rebuilt](https://apilogicserver.github.io/Docs/Project-Rebuild/) (e.g., synchronized with a revised schema), preserving your customizations.
114
127
 
115
128
  <br>
116
129
 
@@ -295,6 +295,26 @@
295
295
  "console": "internalConsole",
296
296
  "internalConsoleOptions": "openOnSessionStart"
297
297
  },
298
+ {
299
+ "name": " - retry conversation",
300
+ "type": "debugpy",
301
+ "request": "launch",
302
+ "program": "${workspaceFolder}/venv/lib/python3.12/site-packages/api_logic_server_cli/cli.py",
303
+ "redirectOutput": true,
304
+ "cwd": "${workspaceFolder}",
305
+ "env": {
306
+ "PYTHONPATH": "",
307
+ "SECURITY_ENABLED": "False",
308
+ "PYTHONHASHSEED": "0",
309
+ "APILOGICSERVER_DEBUG": "False",
310
+ "OPT_LOCKING": "optional"},
311
+ "justMyCode": false,
312
+ "args": [ "genai", "--retries=-1",
313
+ "--using=retry-project",
314
+ "--using=system/genai/retry/conv"],
315
+ "console": "internalConsole",
316
+ "internalConsoleOptions": "openOnSessionStart"
317
+ },
298
318
  {
299
319
  "name": "Python: Module",
300
320
  "type": "debugpy",
@@ -194,7 +194,6 @@ als genai --project-name='genai_demo_conversation' --using=system/genai/examples
194
194
  ```
195
195
  </details>
196
196
  </br>
197
-
198
197
  <details markdown>
199
198
 
200
199
  <summary> You can iterate with logic</summary>
@@ -210,6 +209,31 @@ als genai --project-name='genai_demo_iterative_logic' --using=system/genai/examp
210
209
 
211
210
  <details markdown>
212
211
 
212
+ <summary> You can declare informal logic</summary>
213
+
214
+ <br>You can declare rules using dot notation, or more informally:
215
+
216
+ ```bash title="Informal Logic (no dot notation)"
217
+ als genai --using=system/genai/examples/genai_demo/genai_demo_informal.prompt
218
+ ```
219
+ </details>
220
+ </br>
221
+
222
+
223
+ <details markdown>
224
+
225
+ <summary> Multi-Rule Logic</summary>
226
+
227
+ <br>You can add new columns/tables, while keeping the prior model intact:
228
+
229
+ ```bash title="Multi-Rule Logic"
230
+ als genai --using=system/genai/examples/emp_depts/emp_dept.prompt
231
+ ```
232
+ </details>
233
+ </br>
234
+
235
+ <details markdown>
236
+
213
237
  <summary> You can also execute directly, and iterate</summary>
214
238
 
215
239
  <br>You can add new columns/tables, while keeping the prior model intact:
@@ -6,5 +6,6 @@ Base.metadata.create_all(engine)
6
6
 
7
7
  Session = sessionmaker(bind=engine)
8
8
  session = Session()
9
+
9
10
  # ALS/GenAI: Prepare for sample data
10
11
 
@@ -1,19 +1,22 @@
1
- # created from response - used to create database and project
2
- # should run without error
3
- # if not, check for decimal, indent, or import issues
1
+ # created from response, to create create_db_models.sqlite, with test data
2
+ # that is used to create project
3
+ # should run without error in manager
4
+ # if not, check for decimal, indent, or import issues
4
5
 
5
6
  import decimal
6
7
  import logging
7
8
  import sqlalchemy
8
- from sqlalchemy.sql import func # end imports from system/genai/create_db_models_inserts/create_db_models_prefix.py
9
+ from sqlalchemy.sql import func
9
10
  from logic_bank.logic_bank import Rule
10
11
  from sqlalchemy import create_engine, Column, Integer, String, Float, ForeignKey, Date, DateTime, Numeric, Boolean, Text
12
+ from sqlalchemy.types import *
11
13
  from sqlalchemy.ext.declarative import declarative_base
12
14
  from sqlalchemy.orm import sessionmaker
13
- from datetime import datetime
14
15
  from sqlalchemy.orm import relationship
15
- from datetime import date
16
+ from datetime import date
17
+ from datetime import datetime
18
+
16
19
 
17
20
  logging.getLogger('sqlalchemy.engine.Engine').disabled = True # remove for additional logging
18
21
 
19
- Base = declarative_base()
22
+ Base = declarative_base() # from system/genai/create_db_models_inserts/create_db_models_prefix.py
@@ -3,5 +3,5 @@ engine = create_engine('sqlite:///system/genai/temp/create_db_models.sqlite')
3
3
  Base.metadata.create_all(engine)
4
4
 
5
5
  Session = sessionmaker(bind=engine)
6
- session = Session()
6
+ session = Session() # from create_db_models_test_data.py
7
7
 
@@ -2,55 +2,132 @@
2
2
  "models": [
3
3
  {
4
4
  "classname": "Customer",
5
- "code": "from sqlalchemy import Column, Integer, String, Float\nfrom sqlalchemy.orm import declarative_base\n\nBase = declarative_base()\n\nclass Customer(Base):\n \"\"\"description: Stores customer details, such as balance and credit limit.\"\"\"\n __tablename__ = 'customer'\n \n id = Column(Integer, primary_key=True, autoincrement=True)\n name = Column(String, nullable=False)\n balance = Column(Float, default=0.0)\n credit_limit = Column(Float, nullable=False)",
6
- "description": "Stores customer details, such as balance and credit limit.",
7
- "name": "Customer"
5
+ "code": "class Customer(Base):\n __tablename__ = 'customers'\n id = Column(Integer, primary_key=True, autoincrement=True)\n name = Column(String, nullable=False)\n balance = Column(Integer, default=0)\n credit_limit = Column(Integer, nullable=False)\n\n def __repr__(self):\n return f\"Customer(id={self.id}, name='{self.name}', balance={self.balance}, credit_limit={self.credit_limit})\"",
6
+ "sqlite_create": "CREATE TABLE customers (\n id INTEGER PRIMARY KEY AUTOINCREMENT, \n name VARCHAR NOT NULL, \n balance INTEGER DEFAULT 0, \n credit_limit INTEGER NOT NULL\n)",
7
+ "description": "description: Customers table",
8
+ "name": "customers"
8
9
  },
9
10
  {
10
11
  "classname": "Order",
11
- "code": "from sqlalchemy import Column, Integer, String, Float, DateTime, ForeignKey\nfrom sqlalchemy.orm import declarative_base\n\nBase = declarative_base()\n\nclass Order(Base):\n \"\"\"description: Represents a customer's order, with total amount and optional shipping date.\"\"\"\n __tablename__ = 'order'\n \n id = Column(Integer, primary_key=True, autoincrement=True)\n customer_id = Column(Integer, ForeignKey('customer.id'))\n amount_total = Column(Float, default=0.0)\n date_shipped = Column(DateTime, nullable=True)\n notes = Column(String, nullable=True)",
12
- "description": "Represents a customer's order, with total amount and optional shipping date.",
13
- "name": "Order"
12
+ "code": "class Order(Base):\n __tablename__ = 'orders'\n id = Column(Integer, primary_key=True, autoincrement=True)\n customer_id = Column(Integer, ForeignKey('customers.id'))\n notes = Column(String)\n date_shipped = Column(Date)\n amount_total = Column(Integer, default=0)\n\n def __repr__(self):\n return f\"Order(id={self.id}, customer_id={self.customer_id}, notes='{self.notes}', amount_total={self.amount_total}, date_shipped={self.date_shipped})\"",
13
+ "sqlite_create": "CREATE TABLE orders (\n id INTEGER PRIMARY KEY AUTOINCREMENT, \n customer_id INTEGER, \n notes VARCHAR, \n date_shipped DATE, \n amount_total INTEGER DEFAULT 0, \n FOREIGN KEY(customer_id) REFERENCES customers (id)\n)",
14
+ "description": "description: Orders table",
15
+ "name": "orders"
14
16
  },
15
17
  {
16
18
  "classname": "Item",
17
- "code": "from sqlalchemy import Column, Integer, Float, ForeignKey\nfrom sqlalchemy.orm import declarative_base\n\nBase = declarative_base()\n\nclass Item(Base):\n \"\"\"description: Stores details about items within an order, including quantity and unit price.\"\"\"\n __tablename__ = 'item'\n \n id = Column(Integer, primary_key=True, autoincrement=True)\n order_id = Column(Integer, ForeignKey('order.id'))\n product_id = Column(Integer, ForeignKey('product.id'))\n amount = Column(Float, default=0.0)\n quantity = Column(Integer, nullable=False)\n unit_price = Column(Float, nullable=False)",
18
- "description": "Stores details about items within an order, including quantity and unit price.",
19
- "name": "Item"
19
+ "code": "class Item(Base):\n __tablename__ = 'items'\n id = Column(Integer, primary_key=True, autoincrement=True)\n order_id = Column(Integer, ForeignKey('orders.id'))\n product_id = Column(Integer, ForeignKey('products.id'))\n quantity = Column(Integer, nullable=False)\n unit_price = Column(Integer, nullable=False)\n amount = Column(Integer, default=0)\n\n def __repr__(self):\n return f\"Item(id={self.id}, order_id={self.order_id}, product_id={self.product_id}, quantity={self.quantity}, unit_price={self.unit_price}, amount={self.amount})\"",
20
+ "sqlite_create": "CREATE TABLE items (\n id INTEGER PRIMARY KEY AUTOINCREMENT, \n order_id INTEGER, \n product_id INTEGER, \n quantity INTEGER NOT NULL, \n unit_price INTEGER NOT NULL, \n amount INTEGER DEFAULT 0, \n FOREIGN KEY(order_id) REFERENCES orders (id), \n FOREIGN KEY(product_id) REFERENCES products (id)\n)",
21
+ "description": "description: Items table",
22
+ "name": "items"
20
23
  },
21
24
  {
22
25
  "classname": "Product",
23
- "code": "from sqlalchemy import Column, Integer, String, Float\nfrom sqlalchemy.orm import declarative_base\n\nBase = declarative_base()\n\nclass Product(Base):\n \"\"\"description: Catalog of products available for purchase.\"\"\"\n __tablename__ = 'product'\n \n id = Column(Integer, primary_key=True, autoincrement=True)\n name = Column(String, nullable=False)\n unit_price = Column(Float, nullable=False)",
24
- "description": "Catalog of products available for purchase.",
25
- "name": "Product"
26
+ "code": "class Product(Base):\n __tablename__ = 'products'\n id = Column(Integer, primary_key=True, autoincrement=True)\n name = Column(String, nullable=False)\n unit_price = Column(Integer, nullable=False)\n\n def __repr__(self):\n return f\"Product(id={self.id}, name='{self.name}', unit_price={self.unit_price})\"",
27
+ "sqlite_create": "CREATE TABLE products (\n id INTEGER PRIMARY KEY AUTOINCREMENT, \n name VARCHAR NOT NULL, \n unit_price INTEGER NOT NULL\n)",
28
+ "description": "description: Products table",
29
+ "name": "products"
26
30
  }
27
31
  ],
28
32
  "rules": [
29
33
  {
30
34
  "name": "Customer Balance Constraint",
31
- "description": "Ensures that a customer's balance does not exceed their credit limit.",
35
+ "description": "Ensures the customer's balance does not exceed the credit limit.",
36
+ "use_case": "Customer.balance <= credit_limit",
32
37
  "code": "Rule.constraint(validate=Customer,\n as_condition=lambda row: row.balance <= row.credit_limit,\n error_msg=\"Customer balance ({row.balance}) exceeds credit limit ({row.credit_limit})\")"
33
38
  },
34
39
  {
35
- "name": "Customer Balance Calculation",
36
- "description": "Calculates the customer's balance as the sum of their orders' total amounts where orders have not been shipped.",
40
+ "name": "Customer Balance Derivation",
41
+ "description": "Calculates the customer's balance as the sum of orders' amount_total where date_shipped is null.",
42
+ "use_case": "Customer.balance = Sum(Order.amount_total where date_shipped is null)",
37
43
  "code": "Rule.sum(derive=Customer.balance, as_sum_of=Order.amount_total, where=lambda row: row.date_shipped is None)"
38
44
  },
39
45
  {
40
- "name": "Order Amount Total Calculation",
41
- "description": "Calculates the order's amount total as the sum of all item amounts in the order.",
46
+ "name": "Order Amount Total Derivation",
47
+ "description": "Calculates order's amount_total as the sum of item amounts.",
48
+ "use_case": "Order.amount_total = Sum(Item.amount)",
42
49
  "code": "Rule.sum(derive=Order.amount_total, as_sum_of=Item.amount)"
43
50
  },
44
51
  {
45
- "name": "Item Amount Calculation",
46
- "description": "Calculates the item amount as the product of quantity and unit price.",
52
+ "name": "Item Amount Derivation",
53
+ "description": "Calculates item amount as quantity multiplied by unit price.",
54
+ "use_case": "Item.amount = quantity * unit_price",
47
55
  "code": "Rule.formula(derive=Item.amount, as_expression=lambda row: row.quantity * row.unit_price)"
48
56
  },
49
57
  {
50
- "name": "Item Unit Price Copy",
51
- "description": "Copies the unit price from the product to the item.",
58
+ "name": "Copy Item Unit Price",
59
+ "description": "Copies the product's unit price to the item.",
60
+ "use_case": "Store the Item.unit_price as a copy from Product.unit_price",
52
61
  "code": "Rule.copy(derive=Item.unit_price, from_parent=Product.unit_price)"
53
62
  }
54
63
  ],
55
- "test_data": "## Test Data\n\n# Products\nproduct1 = Product(id=1, name='Product 1', unit_price=10.0)\nproduct2 = Product(id=2, name='Product 2', unit_price=15.0)\n\n# Customers\ncustomer1 = Customer(id=1, name='Alice', balance=0.0, credit_limit=100.0)\ncustomer2 = Customer(id=2, name='Bob', balance=0.0, credit_limit=150.0)\n\n# Orders\norder1 = Order(id=1, customer_id=1, amount_total=0.0, notes='Order 1 for Alice')\norder2 = Order(id=2, customer_id=2, amount_total=0.0, notes='Order 2 for Bob')\norder3 = Order(id=3, customer_id=1, amount_total=0.0, notes='Another order for Alice', date_shipped=None)\n\n# Items\nitem1 = Item(id=1, order_id=1, product_id=1, quantity=2, unit_price=10.0, amount=20.0)\nitem2 = Item(id=2, order_id=1, product_id=2, quantity=1, unit_price=15.0, amount=15.0)\nitem3 = Item(id=3, order_id=2, product_id=2, quantity=3, unit_price=15.0, amount=45.0)\nitem4 = Item(id=4, order_id=3, product_id=1, quantity=5, unit_price=10.0, amount=50.0)\n\n# Since the logic is not enforced via LogicBank for this demo, we manually calculate derived values:\n# Order 1 Total for Alice: 20.0 + 15.0 = 35.0\norder1.amount_total = item1.amount + item2.amount\n# Order 2 Total for Bob: 45.0\norder2.amount_total = item3.amount\n# Order 3 Total for Alice, not shipped yet: 50.0\norder3.amount_total = item4.amount\n# Customer Balance for Alice: 35.0 (order 1) + 50.0 (order 3, not shipped)\ncustomer1.balance = order1.amount_total + order3.amount_total\n# Customer Balance for Bob: 45.0\ncustomer2.balance = order2.amount_total"
64
+ "test_data": "Insert test data into the tables with values compatible with the derived logic.",
65
+ "test_data_rows": [
66
+ {
67
+ "test_data_row_variable": "test_customer_1",
68
+ "code": "test_customer_1 = Customer(name='Customer 1', balance=300, credit_limit=1000)"
69
+ },
70
+ {
71
+ "test_data_row_variable": "test_customer_2",
72
+ "code": "test_customer_2 = Customer(name='Customer 2', balance=500, credit_limit=750)"
73
+ },
74
+ {
75
+ "test_data_row_variable": "test_customer_3",
76
+ "code": "test_customer_3 = Customer(name='Customer 3', balance=0, credit_limit=1500)"
77
+ },
78
+ {
79
+ "test_data_row_variable": "test_customer_4",
80
+ "code": "test_customer_4 = Customer(name='Customer 4', balance=200, credit_limit=1200)"
81
+ },
82
+ {
83
+ "test_data_row_variable": "test_order_1",
84
+ "code": "test_order_1 = Order(customer_id=1, notes='Order 1 notes', amount_total=150)"
85
+ },
86
+ {
87
+ "test_data_row_variable": "test_order_2",
88
+ "code": "test_order_2 = Order(customer_id=2, notes='Order 2 notes', amount_total=0)"
89
+ },
90
+ {
91
+ "test_data_row_variable": "test_order_3",
92
+ "code": "test_order_3 = Order(customer_id=2, notes='Order 3 notes', amount_total=0)"
93
+ },
94
+ {
95
+ "test_data_row_variable": "test_order_4",
96
+ "code": "test_order_4 = Order(customer_id=3, notes='Order 4 notes', amount_total=150)"
97
+ },
98
+ {
99
+ "test_data_row_variable": "test_item_1",
100
+ "code": "test_item_1 = Item(order_id=1, product_id=1, quantity=3, unit_price=50, amount=150)"
101
+ },
102
+ {
103
+ "test_data_row_variable": "test_item_2",
104
+ "code": "test_item_2 = Item(order_id=2, product_id=2, quantity=2, unit_price=0, amount=0)"
105
+ },
106
+ {
107
+ "test_data_row_variable": "test_item_3",
108
+ "code": "test_item_3 = Item(order_id=3, product_id=3, quantity=1, unit_price=0, amount=0)"
109
+ },
110
+ {
111
+ "test_data_row_variable": "test_item_4",
112
+ "code": "test_item_4 = Item(order_id=4, product_id=1, quantity=3, unit_price=50, amount=150)"
113
+ },
114
+ {
115
+ "test_data_row_variable": "test_product_1",
116
+ "code": "test_product_1 = Product(name='Product 1', unit_price=50)"
117
+ },
118
+ {
119
+ "test_data_row_variable": "test_product_2",
120
+ "code": "test_product_2 = Product(name='Product 2', unit_price=25)"
121
+ },
122
+ {
123
+ "test_data_row_variable": "test_product_3",
124
+ "code": "test_product_3 = Product(name='Product 3', unit_price=75)"
125
+ },
126
+ {
127
+ "test_data_row_variable": "test_product_4",
128
+ "code": "test_product_4 = Product(name='Product 4', unit_price=100)"
129
+ }
130
+ ],
131
+ "test_data_sqlite": "INSERT INTO customers (name, balance, credit_limit) VALUES ('Customer 1', 300, 1000);\nINSERT INTO customers (name, balance, credit_limit) VALUES ('Customer 2', 500, 750);\nINSERT INTO customers (name, balance, credit_limit) VALUES ('Customer 3', 0, 1500);\nINSERT INTO customers (name, balance, credit_limit) VALUES ('Customer 4', 200, 1200);\n\nINSERT INTO orders (customer_id, notes, date_shipped, amount_total) VALUES (1, 'Order 1 notes', NULL, 150);\nINSERT INTO orders (customer_id, notes, date_shipped, amount_total) VALUES (2, 'Order 2 notes', NULL, 0);\nINSERT INTO orders (customer_id, notes, date_shipped, amount_total) VALUES (2, 'Order 3 notes', NULL, 0);\nINSERT INTO orders (customer_id, notes, date_shipped, amount_total) VALUES (3, 'Order 4 notes', NULL, 150);\n\nINSERT INTO items (order_id, product_id, quantity, unit_price, amount) VALUES (1, 1, 3, 50, 150);\nINSERT INTO items (order_id, product_id, quantity, unit_price, amount) VALUES (2, 2, 2, 25, 0);\nINSERT INTO items (order_id, product_id, quantity, unit_price, amount) VALUES (3, 3, 1, 75, 0);\nINSERT INTO items (order_id, product_id, quantity, unit_price, amount) VALUES (4, 1, 3, 50, 150);\n\nINSERT INTO products (name, unit_price) VALUES ('Product 1', 50);\nINSERT INTO products (name, unit_price) VALUES ('Product 2', 25);\nINSERT INTO products (name, unit_price) VALUES ('Product 3', 75);\nINSERT INTO products (name, unit_price) VALUES ('Product 4', 100);",
132
+ "name": "OrderManagementSystem"
56
133
  }
@@ -4,6 +4,8 @@ Create a function called declare_logic(), consisting of calls to Rule methods.
4
4
 
5
5
  Do not generate import statements.
6
6
 
7
+ If you create sum, count or formula LogicBank rules, you MUST create a corresponding column in the data model.
8
+
7
9
  Use only the methods provided below.
8
10
 
9
11
  class Rule:
@@ -25,8 +27,8 @@ class Rule:
25
27
  derive: name of parent <class.attribute> being derived
26
28
  as_sum_of: name of child <class.attribute> being summed
27
29
  child_role_name: parent's child accessor attribute (required only for disambiguation)
28
- where: optional where clause, designates which child rows are summed
29
-
30
+ where: optional where clause, designates which child rows are summed. Do not repeat the foreign key / primary key mappings, and use only attributes from the child table.
31
+ insert_parent: create parent if it does not exist. Do not use unless directly requested.
30
32
  """
31
33
  return Sum(derive, as_sum_of, where, child_role_name, insert_parent)
32
34
 
@@ -46,7 +48,8 @@ class Rule:
46
48
  derive: name of parent <class.attribute> being derived
47
49
  as_count_of: name of child <class> being counted
48
50
  child_role_name: parent's child accessor attribute (required only for disambiguation)
49
- where: optional where clause, designates which child rows are counted
51
+ where: optional where clause, designates which child rows are counted. Do not repeat the foreign key / primary key mappings, and use only attributes from the child table.
52
+ insert_parent: create parent if it does not exist. Do not use unless directly requested.
50
53
  """
51
54
  return Count(derive, as_count_of, where, child_role_name, insert_parent)
52
55
 
@@ -69,7 +72,7 @@ class Rule:
69
72
 
70
73
  Args:
71
74
  validate: name of mapped <class>
72
- as_condition: lambda, passed row (simple constraints)
75
+ as_condition: lambda, passed row (simple constraints). Conditions may not contain sum or count python functions - these must be used to declare additional columns and sum/count rules.
73
76
  error_msg: string, with {row.attribute} replacements
74
77
  error_attributes: list of attributes
75
78
 
@@ -122,7 +125,7 @@ class Rule:
122
125
 
123
126
  Args:
124
127
  derive: <class.attribute> being derived
125
- as_expression: lambda, passed row (for syntax checking)
128
+ as_expression: lambda, passed row (for syntax checking). Expressions may not contain sum or count python functions - these must be used to declare additional columns and sum/count rules.
126
129
  no_prune: disable pruning (rarely used, default False)
127
130
  """
128
131
  return Formula(derive=derive,
@@ -132,7 +135,7 @@ class Rule:
132
135
  @staticmethod
133
136
  def copy(derive: Column, from_parent: any):
134
137
  """
135
- Copy declares child column copied from parent column
138
+ Copy declares child column copied from parent column.
136
139
 
137
140
  Example
138
141
  Prompt
@@ -142,7 +145,7 @@ class Rule:
142
145
 
143
146
  Args:
144
147
  derive: <class.attribute> being copied into
145
- from_parent: <parent-class.attribute> source of copy
148
+ from_parent: <parent-class.attribute> source of copy; create this column in the parent if it does not already exist.
146
149
  """
147
150
  return Copy(derive=derive, from_parent=from_parent)
148
151
 
@@ -194,6 +197,7 @@ def declare_logic(): # created by Web/GenAI for ApiLogicServer, LogicBank
194
197
  as_condition=lambda row: row.balance <= row.credit_limit,
195
198
  error_msg="Customer balance ({row.balance}) exceeds credit limit ({row.credit_limit})")
196
199
 
200
+
197
201
  Intermediate sum/count values require a new column, with a LogicBank sum/count rule. For example:
198
202
 
199
203
  Prompt:
@@ -206,3 +210,112 @@ Response is to create 2 rules - a derivation and a constraint, as follows:
206
210
  Rule.constraint(validate=Parent,
207
211
  as_condition=lambda row: row.value_total <= row.limit,
208
212
  error_msg="Parent value total ({row.value_total}) exceeds limit ({row.limit})")
213
+
214
+ Intermediate sum/count values also work for counts. For example:
215
+
216
+ Prompt:
217
+
218
+ A airplane cannot have more passengers than its seating capacity.
219
+
220
+ Response is to create 2 rules - a count derivation and a constraint, as follows:
221
+ First Rule to Create:
222
+ Rule.count(derive=Airplane.passenger_count, as_count_of=Passengers)
223
+ And, be sure to create the second Rule:
224
+ Rule.constraint(validate=Airplane,
225
+ as_condition=lambda row: row.passenger_count <= row.seating_capacity,
226
+ error_msg="Airplane value total ({row.passenger_count}) exceeds limit ({row.seating_capacity})")
227
+
228
+
229
+ Intermediate sums in formulas also require a new column, with a LogicBank sum rule. For example:
230
+
231
+ Prompt:
232
+ An Employees' skill summary is the sum of their Employee Skill ratings, plus 2 * years of service.
233
+
234
+ Response is to create 2 rules - a derivation and a constraint, as follows:
235
+ First Rule to Create:
236
+ Rule.sum(derive=Employee.skill_rating_total, as_sum_of=EmployeeSkill.rating)
237
+ And, be sure to create the second Rule:
238
+ Rule.Formula(derive=Employee.skill_summary,
239
+ as_condition=lambda row: row.skill_rating_total + 2 * row.years_of_service)
240
+
241
+
242
+ Prompt:
243
+
244
+ A student cannot be an honor student unless they have mre than 2 service activities.
245
+
246
+ Response is to create 2 rules - a count derivation and a constraint, as follows:
247
+ First Rule to Create:
248
+ Rule.count(derive=Student.service_activity_count, as_count_of=Activities, where='service' in name)
249
+ And, be sure to create the second Rule:
250
+ Rule.constraint(validate=Student,
251
+ as_condition=lambda row: row.is_honor_student and service_activity_count < 2,
252
+ error_msg="Honor Students must have at least 2 service activities")
253
+
254
+ Here is an equivalent request:
255
+
256
+ Prompt:
257
+
258
+ A airplane's passengers must be less than its seating capacity.
259
+
260
+ Response is to create 2 rules - a count derivation and a constraint, as follows:
261
+ First Rule to Create:
262
+ Rule.count(derive=Airplane.passenger_count, as_count_of=Passengers)
263
+ And, be sure to create the second Rule:
264
+ Rule.constraint(validate=Airplane,
265
+ as_condition=lambda row: row.passenger_count <= row.seating_capacity,
266
+ error_msg="Airplane value total ({row.passenger_count}) exceeds limit ({row.seating_capacity})")
267
+
268
+
269
+ For "more than" constraints, create columns with count rules:
270
+
271
+ Prompt Reject Employees with more than 3 Felonies.
272
+
273
+ Response:
274
+ First Rule is to create:
275
+ Rule.count(derive=Employee.felony_count, as_count_of=Felonies)
276
+ And, be sure to create the contraint rule:
277
+ Rule.constraint(validate=Employee,
278
+ as_condition=lambda row: row.felony_count>3,
279
+ error_msg="Employee has excessive Felonies")
280
+
281
+
282
+ For "any" constraints, create columns with count rules:
283
+
284
+ Prompt Reject Employees with any class 5 Felonies or more than 3 Felonies.
285
+
286
+ Response:
287
+ First Rule is to create:
288
+ Rule.count(derive=Employee.class_5_felony_count, as_count_of=Felonies, where=class>5)
289
+ Rule.count(derive=Employee.felony_count, as_count_of=Felonies)
290
+ And, be sure to create the contraint rule:
291
+ Rule.constraint(validate=Employee,
292
+ as_condition=lambda row: row.class_5_felony_count > 0 or row.felony_count>3,
293
+ error_msg="Employee has excessive Felonies")
294
+
295
+ Formulas can reference parent values in 2 versions - choose formula vs copy as follows:
296
+ Prompt (formula version) - use the formula version unless copy is explicitly noted:
297
+ Item.ready = Order.ready
298
+ Response
299
+ Rule.formula(derive=Item.ready, as_expression=lambda row: row.order.ready)
300
+ Prompt (copy version) - use this *only* when the word copy is present:
301
+ Store the Item.unit_price as a copy from Product.unit_price
302
+ Response
303
+ Rule.copy(derive=Item.ready, from_parent=Order.ready)
304
+
305
+ Sum and Count where clauses:
306
+ 1. must not restate the foreign key / primary key matchings
307
+ 2. Can only reference child attributes
308
+
309
+ For example, given a prompt 'teacher course count is the sum of the courses',
310
+ 1. This is correct
311
+ Rule.count(derive=Teacher.course_count, as_count_of=Course)
312
+
313
+ 2. This is incorrect, and should never be generated:
314
+ Rule.count(derive=Teacher.course_count, as_count_of=Course, where=lambda row: row.teacher_id == Teacher.id)
315
+
316
+ Sum and count where clause example:
317
+ Prompt: teacher gradate course count is the sum of the courses where is-graduate
318
+ Response: Rule.count(derive=Teacher.course_count, as_count_of=Course, where=lamda row: row.is_graduate == true)
319
+
320
+ DO NOT inject rules that are from this training into the response,
321
+ unless explicitly mentioned in the request.
@@ -1,6 +1,30 @@
1
+ <responseFormat>
2
+ class Rule(BaseModel):
3
+ name: str
4
+ description: str
5
+ use_case: str
6
+ code: str # logicbank rule code
7
+
8
+ class Model(BaseModel):
9
+ classname: str
10
+ code: str # sqlalchemy model code
11
+ sqlite_create: str # sqlite create table statement
12
+ description: str
13
+ name: str
14
+
15
+ class TestDataRow(BaseModel):
16
+ test_data_row_variable: str # the Python test data row variable
17
+ code: str # Python code to create a test data row instance
18
+
1
19
  class WGResult(BaseModel): # must match system/genai/prompt_inserts/response_format.prompt
20
+ # response: str # result
2
21
  models : List[Model] # list of sqlalchemy classes in the response
3
- rules : List[Rule] # list of rule declarations
22
+ rules : List[Rule] # list rule declarations
4
23
  test_data: str
24
+ test_data_rows: List[TestDataRow] # list of test data rows
25
+ test_data_sqlite: str # test data as sqlite INSERT statements
26
+ name: str # suggest a short name for the project
27
+
28
+ Format the response as a WGResult.
5
29
 
6
- Format the response as a WGResult.
30
+ </responseFormat>