planar 0.5.0__py3-none-any.whl → 0.8.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 (211) hide show
  1. planar/_version.py +1 -1
  2. planar/ai/agent.py +155 -283
  3. planar/ai/agent_base.py +170 -0
  4. planar/ai/agent_utils.py +7 -0
  5. planar/ai/pydantic_ai.py +638 -0
  6. planar/ai/test_agent_serialization.py +1 -1
  7. planar/app.py +64 -20
  8. planar/cli.py +39 -27
  9. planar/config.py +45 -36
  10. planar/db/db.py +2 -1
  11. planar/files/storage/azure_blob.py +343 -0
  12. planar/files/storage/base.py +7 -0
  13. planar/files/storage/config.py +70 -7
  14. planar/files/storage/s3.py +6 -6
  15. planar/files/storage/test_azure_blob.py +435 -0
  16. planar/logging/formatter.py +17 -4
  17. planar/logging/test_formatter.py +327 -0
  18. planar/registry_items.py +2 -1
  19. planar/routers/agents_router.py +3 -1
  20. planar/routers/files.py +11 -2
  21. planar/routers/models.py +14 -1
  22. planar/routers/test_agents_router.py +1 -1
  23. planar/routers/test_files_router.py +49 -0
  24. planar/routers/test_routes_security.py +5 -7
  25. planar/routers/test_workflow_router.py +270 -3
  26. planar/routers/workflow.py +95 -36
  27. planar/rules/models.py +36 -39
  28. planar/rules/test_data/account_dormancy_management.json +223 -0
  29. planar/rules/test_data/airline_loyalty_points_calculator.json +262 -0
  30. planar/rules/test_data/applicant_risk_assessment.json +435 -0
  31. planar/rules/test_data/booking_fraud_detection.json +407 -0
  32. planar/rules/test_data/cellular_data_rollover_system.json +258 -0
  33. planar/rules/test_data/clinical_trial_eligibility_screener.json +437 -0
  34. planar/rules/test_data/customer_lifetime_value.json +143 -0
  35. planar/rules/test_data/import_duties_calculator.json +289 -0
  36. planar/rules/test_data/insurance_prior_authorization.json +443 -0
  37. planar/rules/test_data/online_check_in_eligibility_system.json +254 -0
  38. planar/rules/test_data/order_consolidation_system.json +375 -0
  39. planar/rules/test_data/portfolio_risk_monitor.json +471 -0
  40. planar/rules/test_data/supply_chain_risk.json +253 -0
  41. planar/rules/test_data/warehouse_cross_docking.json +237 -0
  42. planar/rules/test_rules.py +750 -6
  43. planar/scaffold_templates/planar.dev.yaml.j2 +6 -6
  44. planar/scaffold_templates/planar.prod.yaml.j2 +9 -5
  45. planar/scaffold_templates/pyproject.toml.j2 +1 -1
  46. planar/security/auth_context.py +21 -0
  47. planar/security/{jwt_middleware.py → auth_middleware.py} +70 -17
  48. planar/security/authorization.py +9 -15
  49. planar/security/tests/test_auth_middleware.py +162 -0
  50. planar/sse/proxy.py +4 -9
  51. planar/test_app.py +92 -1
  52. planar/test_cli.py +81 -59
  53. planar/test_config.py +17 -14
  54. planar/testing/fixtures.py +325 -0
  55. planar/testing/planar_test_client.py +5 -2
  56. planar/utils.py +41 -1
  57. planar/workflows/execution.py +1 -1
  58. planar/workflows/orchestrator.py +5 -0
  59. planar/workflows/serialization.py +12 -6
  60. planar/workflows/step_core.py +3 -1
  61. planar/workflows/test_serialization.py +9 -1
  62. {planar-0.5.0.dist-info → planar-0.8.0.dist-info}/METADATA +30 -5
  63. planar-0.8.0.dist-info/RECORD +166 -0
  64. planar/.__init__.py.un~ +0 -0
  65. planar/._version.py.un~ +0 -0
  66. planar/.app.py.un~ +0 -0
  67. planar/.cli.py.un~ +0 -0
  68. planar/.config.py.un~ +0 -0
  69. planar/.context.py.un~ +0 -0
  70. planar/.db.py.un~ +0 -0
  71. planar/.di.py.un~ +0 -0
  72. planar/.engine.py.un~ +0 -0
  73. planar/.files.py.un~ +0 -0
  74. planar/.log_context.py.un~ +0 -0
  75. planar/.log_metadata.py.un~ +0 -0
  76. planar/.logging.py.un~ +0 -0
  77. planar/.object_registry.py.un~ +0 -0
  78. planar/.otel.py.un~ +0 -0
  79. planar/.server.py.un~ +0 -0
  80. planar/.session.py.un~ +0 -0
  81. planar/.sqlalchemy.py.un~ +0 -0
  82. planar/.task_local.py.un~ +0 -0
  83. planar/.test_app.py.un~ +0 -0
  84. planar/.test_config.py.un~ +0 -0
  85. planar/.test_object_config.py.un~ +0 -0
  86. planar/.test_sqlalchemy.py.un~ +0 -0
  87. planar/.test_utils.py.un~ +0 -0
  88. planar/.util.py.un~ +0 -0
  89. planar/.utils.py.un~ +0 -0
  90. planar/ai/.__init__.py.un~ +0 -0
  91. planar/ai/._models.py.un~ +0 -0
  92. planar/ai/.agent.py.un~ +0 -0
  93. planar/ai/.agent_utils.py.un~ +0 -0
  94. planar/ai/.events.py.un~ +0 -0
  95. planar/ai/.files.py.un~ +0 -0
  96. planar/ai/.models.py.un~ +0 -0
  97. planar/ai/.providers.py.un~ +0 -0
  98. planar/ai/.pydantic_ai.py.un~ +0 -0
  99. planar/ai/.pydantic_ai_agent.py.un~ +0 -0
  100. planar/ai/.pydantic_ai_provider.py.un~ +0 -0
  101. planar/ai/.step.py.un~ +0 -0
  102. planar/ai/.test_agent.py.un~ +0 -0
  103. planar/ai/.test_agent_serialization.py.un~ +0 -0
  104. planar/ai/.test_providers.py.un~ +0 -0
  105. planar/ai/.utils.py.un~ +0 -0
  106. planar/ai/providers.py +0 -1088
  107. planar/ai/test_agent.py +0 -1298
  108. planar/ai/test_providers.py +0 -463
  109. planar/db/.db.py.un~ +0 -0
  110. planar/files/.config.py.un~ +0 -0
  111. planar/files/.local.py.un~ +0 -0
  112. planar/files/.local_filesystem.py.un~ +0 -0
  113. planar/files/.model.py.un~ +0 -0
  114. planar/files/.models.py.un~ +0 -0
  115. planar/files/.s3.py.un~ +0 -0
  116. planar/files/.storage.py.un~ +0 -0
  117. planar/files/.test_files.py.un~ +0 -0
  118. planar/files/storage/.__init__.py.un~ +0 -0
  119. planar/files/storage/.base.py.un~ +0 -0
  120. planar/files/storage/.config.py.un~ +0 -0
  121. planar/files/storage/.context.py.un~ +0 -0
  122. planar/files/storage/.local_directory.py.un~ +0 -0
  123. planar/files/storage/.test_local_directory.py.un~ +0 -0
  124. planar/files/storage/.test_s3.py.un~ +0 -0
  125. planar/human/.human.py.un~ +0 -0
  126. planar/human/.test_human.py.un~ +0 -0
  127. planar/logging/.__init__.py.un~ +0 -0
  128. planar/logging/.attributes.py.un~ +0 -0
  129. planar/logging/.formatter.py.un~ +0 -0
  130. planar/logging/.logger.py.un~ +0 -0
  131. planar/logging/.otel.py.un~ +0 -0
  132. planar/logging/.tracer.py.un~ +0 -0
  133. planar/modeling/.mixin.py.un~ +0 -0
  134. planar/modeling/.storage.py.un~ +0 -0
  135. planar/modeling/orm/.planar_base_model.py.un~ +0 -0
  136. planar/object_config/.object_config.py.un~ +0 -0
  137. planar/routers/.__init__.py.un~ +0 -0
  138. planar/routers/.agents_router.py.un~ +0 -0
  139. planar/routers/.crud.py.un~ +0 -0
  140. planar/routers/.decision.py.un~ +0 -0
  141. planar/routers/.event.py.un~ +0 -0
  142. planar/routers/.file_attachment.py.un~ +0 -0
  143. planar/routers/.files.py.un~ +0 -0
  144. planar/routers/.files_router.py.un~ +0 -0
  145. planar/routers/.human.py.un~ +0 -0
  146. planar/routers/.info.py.un~ +0 -0
  147. planar/routers/.models.py.un~ +0 -0
  148. planar/routers/.object_config_router.py.un~ +0 -0
  149. planar/routers/.rule.py.un~ +0 -0
  150. planar/routers/.test_object_config_router.py.un~ +0 -0
  151. planar/routers/.test_workflow_router.py.un~ +0 -0
  152. planar/routers/.workflow.py.un~ +0 -0
  153. planar/rules/.decorator.py.un~ +0 -0
  154. planar/rules/.runner.py.un~ +0 -0
  155. planar/rules/.test_rules.py.un~ +0 -0
  156. planar/security/.jwt_middleware.py.un~ +0 -0
  157. planar/sse/.constants.py.un~ +0 -0
  158. planar/sse/.example.html.un~ +0 -0
  159. planar/sse/.hub.py.un~ +0 -0
  160. planar/sse/.model.py.un~ +0 -0
  161. planar/sse/.proxy.py.un~ +0 -0
  162. planar/testing/.client.py.un~ +0 -0
  163. planar/testing/.memory_storage.py.un~ +0 -0
  164. planar/testing/.planar_test_client.py.un~ +0 -0
  165. planar/testing/.predictable_tracer.py.un~ +0 -0
  166. planar/testing/.synchronizable_tracer.py.un~ +0 -0
  167. planar/testing/.test_memory_storage.py.un~ +0 -0
  168. planar/testing/.workflow_observer.py.un~ +0 -0
  169. planar/workflows/.__init__.py.un~ +0 -0
  170. planar/workflows/.builtin_steps.py.un~ +0 -0
  171. planar/workflows/.concurrency_tracing.py.un~ +0 -0
  172. planar/workflows/.context.py.un~ +0 -0
  173. planar/workflows/.contrib.py.un~ +0 -0
  174. planar/workflows/.decorators.py.un~ +0 -0
  175. planar/workflows/.durable_test.py.un~ +0 -0
  176. planar/workflows/.errors.py.un~ +0 -0
  177. planar/workflows/.events.py.un~ +0 -0
  178. planar/workflows/.exceptions.py.un~ +0 -0
  179. planar/workflows/.execution.py.un~ +0 -0
  180. planar/workflows/.human.py.un~ +0 -0
  181. planar/workflows/.lock.py.un~ +0 -0
  182. planar/workflows/.misc.py.un~ +0 -0
  183. planar/workflows/.model.py.un~ +0 -0
  184. planar/workflows/.models.py.un~ +0 -0
  185. planar/workflows/.notifications.py.un~ +0 -0
  186. planar/workflows/.orchestrator.py.un~ +0 -0
  187. planar/workflows/.runtime.py.un~ +0 -0
  188. planar/workflows/.serialization.py.un~ +0 -0
  189. planar/workflows/.step.py.un~ +0 -0
  190. planar/workflows/.step_core.py.un~ +0 -0
  191. planar/workflows/.sub_workflow_runner.py.un~ +0 -0
  192. planar/workflows/.sub_workflow_scheduler.py.un~ +0 -0
  193. planar/workflows/.test_concurrency.py.un~ +0 -0
  194. planar/workflows/.test_concurrency_detection.py.un~ +0 -0
  195. planar/workflows/.test_human.py.un~ +0 -0
  196. planar/workflows/.test_lock_timeout.py.un~ +0 -0
  197. planar/workflows/.test_orchestrator.py.un~ +0 -0
  198. planar/workflows/.test_race_conditions.py.un~ +0 -0
  199. planar/workflows/.test_serialization.py.un~ +0 -0
  200. planar/workflows/.test_suspend_deserialization.py.un~ +0 -0
  201. planar/workflows/.test_workflow.py.un~ +0 -0
  202. planar/workflows/.tracing.py.un~ +0 -0
  203. planar/workflows/.types.py.un~ +0 -0
  204. planar/workflows/.util.py.un~ +0 -0
  205. planar/workflows/.utils.py.un~ +0 -0
  206. planar/workflows/.workflow.py.un~ +0 -0
  207. planar/workflows/.workflow_wrapper.py.un~ +0 -0
  208. planar/workflows/.wrappers.py.un~ +0 -0
  209. planar-0.5.0.dist-info/RECORD +0 -289
  210. {planar-0.5.0.dist-info → planar-0.8.0.dist-info}/WHEEL +0 -0
  211. {planar-0.5.0.dist-info → planar-0.8.0.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,437 @@
1
+ {
2
+ "nodes": [
3
+ {
4
+ "type": "inputNode",
5
+ "content": {
6
+ "schema": ""
7
+ },
8
+ "id": "inputNode",
9
+ "name": "patient",
10
+ "position": {
11
+ "x": 110,
12
+ "y": 114
13
+ }
14
+ },
15
+ {
16
+ "type": "decisionTableNode",
17
+ "content": {
18
+ "hitPolicy": "first",
19
+ "rules": [
20
+ {
21
+ "_id": "rule1",
22
+ "diagnosis": "'breast_cancer', 'lung_cancer', 'colorectal_cancer'",
23
+ "diagnosisFlag": "true",
24
+ "diagnosisReason": "'Diagnosis matches trial criteria'"
25
+ },
26
+ {
27
+ "_id": "rule2",
28
+ "diagnosis": "",
29
+ "diagnosisFlag": "false",
30
+ "diagnosisReason": "'Diagnosis does not match trial criteria'"
31
+ }
32
+ ],
33
+ "inputs": [
34
+ {
35
+ "id": "diagnosis",
36
+ "name": "Diagnosis",
37
+ "field": "patient.diagnosis"
38
+ }
39
+ ],
40
+ "outputs": [
41
+ {
42
+ "id": "diagnosisFlag",
43
+ "name": "DiagnosisFlag",
44
+ "field": "eligibility.diagnosis.flag"
45
+ },
46
+ {
47
+ "id": "diagnosisReason",
48
+ "name": "DiagnosisReason",
49
+ "field": "eligibility.diagnosis.reason"
50
+ }
51
+ ],
52
+ "passThrough": true,
53
+ "inputField": null,
54
+ "outputPath": null,
55
+ "executionMode": "single"
56
+ },
57
+ "id": "diagnosisEligibility",
58
+ "name": "diagnosisEligibility",
59
+ "position": {
60
+ "x": 430,
61
+ "y": -131
62
+ }
63
+ },
64
+ {
65
+ "type": "decisionTableNode",
66
+ "content": {
67
+ "hitPolicy": "first",
68
+ "rules": [
69
+ {
70
+ "_id": "rule1",
71
+ "stage": "'I', 'II', 'III'",
72
+ "stageFlag": "true",
73
+ "stageReason": "'Disease stage matches trial criteria'"
74
+ },
75
+ {
76
+ "_id": "rule2",
77
+ "stage": "'IV'",
78
+ "stageFlag": "false",
79
+ "stageReason": "'Stage IV patients excluded from trial'"
80
+ },
81
+ {
82
+ "_id": "rule3",
83
+ "stage": "",
84
+ "stageFlag": "false",
85
+ "stageReason": "'Unknown or invalid disease stage'"
86
+ }
87
+ ],
88
+ "inputs": [
89
+ {
90
+ "id": "stage",
91
+ "name": "Stage",
92
+ "field": "patient.diseaseStage"
93
+ }
94
+ ],
95
+ "outputs": [
96
+ {
97
+ "id": "stageFlag",
98
+ "name": "StageFlag",
99
+ "field": "eligibility.stage.flag"
100
+ },
101
+ {
102
+ "id": "stageReason",
103
+ "name": "StageReason",
104
+ "field": "eligibility.stage.reason"
105
+ }
106
+ ],
107
+ "passThrough": true,
108
+ "inputField": null,
109
+ "outputPath": null,
110
+ "executionMode": "single",
111
+ "passThorough": false
112
+ },
113
+ "id": "diseaseStageEligibility",
114
+ "name": "diseaseStageEligibility",
115
+ "position": {
116
+ "x": 430,
117
+ "y": -33
118
+ }
119
+ },
120
+ {
121
+ "type": "decisionTableNode",
122
+ "content": {
123
+ "hitPolicy": "first",
124
+ "rules": [
125
+ {
126
+ "_id": "rule1",
127
+ "medications": "some($, # in ['immunosuppressants', 'anticancer_agents', 'corticosteroids'])",
128
+ "medicationFlag": "false",
129
+ "medicationReason": "'Patient taking excluded medications'"
130
+ },
131
+ {
132
+ "_id": "rule2",
133
+ "medications": "",
134
+ "medicationFlag": "true",
135
+ "medicationReason": "'No conflicting medications'"
136
+ }
137
+ ],
138
+ "inputs": [
139
+ {
140
+ "id": "medications",
141
+ "name": "Medications",
142
+ "field": "patient.currentMedications ?? []"
143
+ }
144
+ ],
145
+ "outputs": [
146
+ {
147
+ "id": "medicationFlag",
148
+ "name": "MedicationFlag",
149
+ "field": "eligibility.medication.flag"
150
+ },
151
+ {
152
+ "id": "medicationReason",
153
+ "name": "MedicationReason",
154
+ "field": "eligibility.medication.reason"
155
+ }
156
+ ],
157
+ "passThrough": true,
158
+ "inputField": null,
159
+ "outputPath": null,
160
+ "executionMode": "single",
161
+ "passThorough": false
162
+ },
163
+ "id": "medicationEligibility",
164
+ "name": "medicationEligibility",
165
+ "position": {
166
+ "x": 430,
167
+ "y": 65
168
+ }
169
+ },
170
+ {
171
+ "type": "decisionTableNode",
172
+ "content": {
173
+ "hitPolicy": "first",
174
+ "rules": [
175
+ {
176
+ "_id": "rule1",
177
+ "age": ")18..75(",
178
+ "ageFlag": "false",
179
+ "ageReason": "'Age outside eligible range (18-75)'"
180
+ },
181
+ {
182
+ "_id": "rule2",
183
+ "age": "",
184
+ "ageFlag": "true",
185
+ "ageReason": "'Age within eligible range'"
186
+ }
187
+ ],
188
+ "inputs": [
189
+ {
190
+ "id": "age",
191
+ "name": "PatientAge",
192
+ "field": "patient.age"
193
+ }
194
+ ],
195
+ "outputs": [
196
+ {
197
+ "id": "ageFlag",
198
+ "name": "AgeFlag",
199
+ "field": "eligibility.age.flag"
200
+ },
201
+ {
202
+ "id": "ageReason",
203
+ "name": "AgeReason",
204
+ "field": "eligibility.age.reason"
205
+ }
206
+ ],
207
+ "passThrough": true,
208
+ "inputField": null,
209
+ "outputPath": null,
210
+ "executionMode": "single",
211
+ "passThorough": false
212
+ },
213
+ "id": "ageEligibility",
214
+ "name": "ageEligibility",
215
+ "position": {
216
+ "x": 430,
217
+ "y": 163
218
+ }
219
+ },
220
+ {
221
+ "type": "decisionTableNode",
222
+ "content": {
223
+ "hitPolicy": "first",
224
+ "rules": [
225
+ {
226
+ "_id": "rule1",
227
+ "priorTreatments": "> 2",
228
+ "treatmentFlag": "false",
229
+ "treatmentReason": "'Too many prior treatments'"
230
+ },
231
+ {
232
+ "_id": "rule2",
233
+ "priorTreatments": "<= 2",
234
+ "treatmentFlag": "true",
235
+ "treatmentReason": "'Acceptable number of prior treatments'"
236
+ },
237
+ {
238
+ "_id": "rule3",
239
+ "priorTreatments": "",
240
+ "treatmentFlag": "true",
241
+ "treatmentReason": "'No prior treatments recorded'"
242
+ }
243
+ ],
244
+ "inputs": [
245
+ {
246
+ "id": "priorTreatments",
247
+ "name": "PriorTreatments",
248
+ "field": "patient.priorTreatments"
249
+ }
250
+ ],
251
+ "outputs": [
252
+ {
253
+ "id": "treatmentFlag",
254
+ "name": "TreatmentFlag",
255
+ "field": "eligibility.priorTreatment.flag"
256
+ },
257
+ {
258
+ "id": "treatmentReason",
259
+ "name": "TreatmentReason",
260
+ "field": "eligibility.priorTreatment.reason"
261
+ }
262
+ ],
263
+ "passThrough": true,
264
+ "inputField": null,
265
+ "outputPath": null,
266
+ "executionMode": "single"
267
+ },
268
+ "id": "priorTreatmentEligibility",
269
+ "name": "priorTreatmentEligibility",
270
+ "position": {
271
+ "x": 430,
272
+ "y": 261
273
+ }
274
+ },
275
+ {
276
+ "type": "decisionTableNode",
277
+ "content": {
278
+ "hitPolicy": "first",
279
+ "rules": [
280
+ {
281
+ "_id": "rule1",
282
+ "comorbidities": "some($, # in ['autoimmune_disease', 'heart_failure', 'uncontrolled_diabetes'])",
283
+ "comorbidityFlag": "false",
284
+ "comorbidityReason": "'Excluded comorbidity present'"
285
+ },
286
+ {
287
+ "_id": "rule2",
288
+ "comorbidities": "",
289
+ "comorbidityFlag": "true",
290
+ "comorbidityReason": "'No exclusionary comorbidities'"
291
+ }
292
+ ],
293
+ "inputs": [
294
+ {
295
+ "id": "comorbidities",
296
+ "name": "Comorbidities",
297
+ "field": "patient.comorbidities ?? []"
298
+ }
299
+ ],
300
+ "outputs": [
301
+ {
302
+ "id": "comorbidityFlag",
303
+ "name": "ComorbidityFlag",
304
+ "field": "eligibility.comorbidity.flag"
305
+ },
306
+ {
307
+ "id": "comorbidityReason",
308
+ "name": "ComorbidityReason",
309
+ "field": "eligibility.comorbidity.reason"
310
+ }
311
+ ],
312
+ "passThrough": true,
313
+ "inputField": null,
314
+ "outputPath": null,
315
+ "executionMode": "single",
316
+ "passThorough": false
317
+ },
318
+ "id": "comorbidityEligibility",
319
+ "name": "comorbidityEligibility",
320
+ "position": {
321
+ "x": 430,
322
+ "y": 359
323
+ }
324
+ },
325
+ {
326
+ "type": "expressionNode",
327
+ "content": {
328
+ "expressions": [
329
+ {
330
+ "id": "expr1",
331
+ "key": "isEligible",
332
+ "value": "all(values(eligibility), #.flag)"
333
+ },
334
+ {
335
+ "id": "expr2",
336
+ "key": "eligibilityReasons",
337
+ "value": "filter(values(eligibility), #.reason != null)"
338
+ },
339
+ {
340
+ "id": "expr3",
341
+ "key": "decisionSummary",
342
+ "value": "$.isEligible ? 'Patient is eligible for clinical trial' : 'Patient is not eligible for clinical trial'"
343
+ },
344
+ {
345
+ "id": "expr4",
346
+ "key": "failedCriteria",
347
+ "value": "filter(keys(eligibility), eligibility[#].flag == false)"
348
+ }
349
+ ],
350
+ "passThrough": false,
351
+ "inputField": null,
352
+ "outputPath": null,
353
+ "executionMode": "single"
354
+ },
355
+ "id": "eligibilitySummary",
356
+ "name": "eligibilitySummary",
357
+ "position": {
358
+ "x": 750,
359
+ "y": 114
360
+ }
361
+ }
362
+ ],
363
+ "edges": [
364
+ {
365
+ "id": "edge1",
366
+ "sourceId": "inputNode",
367
+ "targetId": "diagnosisEligibility",
368
+ "type": "edge"
369
+ },
370
+ {
371
+ "id": "edge2",
372
+ "sourceId": "inputNode",
373
+ "targetId": "diseaseStageEligibility",
374
+ "type": "edge"
375
+ },
376
+ {
377
+ "id": "edge3",
378
+ "sourceId": "inputNode",
379
+ "targetId": "medicationEligibility",
380
+ "type": "edge"
381
+ },
382
+ {
383
+ "id": "edge4",
384
+ "sourceId": "inputNode",
385
+ "targetId": "ageEligibility",
386
+ "type": "edge"
387
+ },
388
+ {
389
+ "id": "edge5",
390
+ "sourceId": "inputNode",
391
+ "targetId": "priorTreatmentEligibility",
392
+ "type": "edge"
393
+ },
394
+ {
395
+ "id": "edge6",
396
+ "sourceId": "inputNode",
397
+ "targetId": "comorbidityEligibility",
398
+ "type": "edge"
399
+ },
400
+ {
401
+ "id": "edge7",
402
+ "sourceId": "diagnosisEligibility",
403
+ "targetId": "eligibilitySummary",
404
+ "type": "edge"
405
+ },
406
+ {
407
+ "id": "edge8",
408
+ "sourceId": "diseaseStageEligibility",
409
+ "targetId": "eligibilitySummary",
410
+ "type": "edge"
411
+ },
412
+ {
413
+ "id": "edge9",
414
+ "sourceId": "medicationEligibility",
415
+ "targetId": "eligibilitySummary",
416
+ "type": "edge"
417
+ },
418
+ {
419
+ "id": "edge10",
420
+ "sourceId": "ageEligibility",
421
+ "targetId": "eligibilitySummary",
422
+ "type": "edge"
423
+ },
424
+ {
425
+ "id": "edge11",
426
+ "sourceId": "priorTreatmentEligibility",
427
+ "targetId": "eligibilitySummary",
428
+ "type": "edge"
429
+ },
430
+ {
431
+ "id": "edge12",
432
+ "sourceId": "comorbidityEligibility",
433
+ "targetId": "eligibilitySummary",
434
+ "type": "edge"
435
+ }
436
+ ]
437
+ }
@@ -0,0 +1,143 @@
1
+ {
2
+ "nodes": [
3
+ {
4
+ "type": "inputNode",
5
+ "content": {
6
+ "schema": ""
7
+ },
8
+ "id": "ip1",
9
+ "name": "request",
10
+ "position": {
11
+ "x": 110,
12
+ "y": 114
13
+ }
14
+ },
15
+ {
16
+ "type": "expressionNode",
17
+ "content": {
18
+ "expressions": [
19
+ {
20
+ "id": "e1-1",
21
+ "key": "averageOrderValue",
22
+ "value": "sum(purchaseHistory.orderValues) / len(purchaseHistory.orderValues)"
23
+ },
24
+ {
25
+ "id": "e1-2",
26
+ "key": "purchaseFrequency",
27
+ "value": "len(purchaseHistory.orderValues) / purchaseHistory.customerDurationMonths * 12"
28
+ },
29
+ {
30
+ "id": "e1-3",
31
+ "key": "grossMargin",
32
+ "value": "purchaseHistory.averageGrossMarginPercent / 100"
33
+ },
34
+ {
35
+ "id": "e1-4",
36
+ "key": "customerLifetimeMonths",
37
+ "value": "1 / (1 - purchaseHistory.retentionRate / 100) * 12"
38
+ },
39
+ {
40
+ "id": "e1-5",
41
+ "key": "basicLTV",
42
+ "value": "$.averageOrderValue * $.purchaseFrequency * $.grossMargin * $.customerLifetimeMonths"
43
+ },
44
+ {
45
+ "id": "e1-6",
46
+ "key": "acquisitionCostRatio",
47
+ "value": "customer.acquisitionCost / $.basicLTV"
48
+ },
49
+ {
50
+ "id": "e1-7",
51
+ "key": "adjustedLTV",
52
+ "value": "$.basicLTV - customer.acquisitionCost"
53
+ }
54
+ ],
55
+ "passThrough": true,
56
+ "inputField": null,
57
+ "outputPath": null,
58
+ "executionMode": "single"
59
+ },
60
+ "id": "ex1",
61
+ "name": "clv_calculation",
62
+ "position": {
63
+ "x": 430,
64
+ "y": 114
65
+ }
66
+ },
67
+ {
68
+ "type": "decisionTableNode",
69
+ "content": {
70
+ "hitPolicy": "first",
71
+ "rules": [
72
+ {
73
+ "_id": "r1-1",
74
+ "i1-1": "> 2000",
75
+ "o1-1": "'platinum'",
76
+ "o1-2": "'High-touch service, premium offers, exclusive events'"
77
+ },
78
+ {
79
+ "_id": "r1-2",
80
+ "i1-1": "> 1000",
81
+ "o1-1": "'gold'",
82
+ "o1-2": "'Priority service, personalized offers, loyalty bonuses'"
83
+ },
84
+ {
85
+ "_id": "r1-3",
86
+ "i1-1": "> 500",
87
+ "o1-1": "'silver'",
88
+ "o1-2": "'Enhanced service, targeted offers, occasional perks'"
89
+ },
90
+ {
91
+ "_id": "r1-4",
92
+ "i1-1": "",
93
+ "o1-1": "'standard'",
94
+ "o1-2": "'Standard service, general promotions'"
95
+ }
96
+ ],
97
+ "inputs": [
98
+ {
99
+ "id": "i1-1",
100
+ "name": "Adjusted LTV",
101
+ "field": "adjustedLTV"
102
+ }
103
+ ],
104
+ "outputs": [
105
+ {
106
+ "id": "o1-1",
107
+ "name": "Customer Tier",
108
+ "field": "customerInsights.tier"
109
+ },
110
+ {
111
+ "id": "o1-2",
112
+ "name": "Recommended Strategy",
113
+ "field": "customerInsights.recommendedStrategy"
114
+ }
115
+ ],
116
+ "passThrough": true,
117
+ "inputField": null,
118
+ "outputPath": null,
119
+ "executionMode": "single"
120
+ },
121
+ "id": "dt1",
122
+ "name": "customer_segmentation",
123
+ "position": {
124
+ "x": 750,
125
+ "y": 114
126
+ }
127
+ }
128
+ ],
129
+ "edges": [
130
+ {
131
+ "id": "ed1",
132
+ "sourceId": "ip1",
133
+ "targetId": "ex1",
134
+ "type": "edge"
135
+ },
136
+ {
137
+ "id": "ed2",
138
+ "sourceId": "ex1",
139
+ "targetId": "dt1",
140
+ "type": "edge"
141
+ }
142
+ ]
143
+ }