dialectical-framework 0.4.4__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 (84) hide show
  1. dialectical_framework/__init__.py +43 -0
  2. dialectical_framework/ai_dto/__init__.py +0 -0
  3. dialectical_framework/ai_dto/causal_cycle_assessment_dto.py +16 -0
  4. dialectical_framework/ai_dto/causal_cycle_dto.py +16 -0
  5. dialectical_framework/ai_dto/causal_cycles_deck_dto.py +11 -0
  6. dialectical_framework/ai_dto/dialectical_component_dto.py +16 -0
  7. dialectical_framework/ai_dto/dialectical_components_deck_dto.py +12 -0
  8. dialectical_framework/ai_dto/dto_mapper.py +103 -0
  9. dialectical_framework/ai_dto/reciprocal_solution_dto.py +24 -0
  10. dialectical_framework/analyst/__init__.py +1 -0
  11. dialectical_framework/analyst/audit/__init__.py +0 -0
  12. dialectical_framework/analyst/consultant.py +30 -0
  13. dialectical_framework/analyst/decorator_action_reflection.py +28 -0
  14. dialectical_framework/analyst/decorator_discrete_spiral.py +30 -0
  15. dialectical_framework/analyst/domain/__init__.py +0 -0
  16. dialectical_framework/analyst/domain/assessable_cycle.py +128 -0
  17. dialectical_framework/analyst/domain/cycle.py +133 -0
  18. dialectical_framework/analyst/domain/interpretation.py +16 -0
  19. dialectical_framework/analyst/domain/rationale.py +116 -0
  20. dialectical_framework/analyst/domain/spiral.py +47 -0
  21. dialectical_framework/analyst/domain/transformation.py +24 -0
  22. dialectical_framework/analyst/domain/transition.py +160 -0
  23. dialectical_framework/analyst/domain/transition_cell_to_cell.py +29 -0
  24. dialectical_framework/analyst/domain/transition_segment_to_segment.py +16 -0
  25. dialectical_framework/analyst/strategic_consultant.py +32 -0
  26. dialectical_framework/analyst/think_action_reflection.py +217 -0
  27. dialectical_framework/analyst/think_constructive_convergence.py +87 -0
  28. dialectical_framework/analyst/wheel_builder_transition_calculator.py +157 -0
  29. dialectical_framework/brain.py +81 -0
  30. dialectical_framework/dialectical_analysis.py +14 -0
  31. dialectical_framework/dialectical_component.py +111 -0
  32. dialectical_framework/dialectical_components_deck.py +48 -0
  33. dialectical_framework/dialectical_reasoning.py +105 -0
  34. dialectical_framework/directed_graph.py +419 -0
  35. dialectical_framework/enums/__init__.py +0 -0
  36. dialectical_framework/enums/causality_type.py +10 -0
  37. dialectical_framework/enums/di.py +11 -0
  38. dialectical_framework/enums/dialectical_reasoning_mode.py +9 -0
  39. dialectical_framework/enums/predicate.py +9 -0
  40. dialectical_framework/protocols/__init__.py +0 -0
  41. dialectical_framework/protocols/assessable.py +141 -0
  42. dialectical_framework/protocols/causality_sequencer.py +111 -0
  43. dialectical_framework/protocols/content_fidelity_evaluator.py +16 -0
  44. dialectical_framework/protocols/has_brain.py +18 -0
  45. dialectical_framework/protocols/has_config.py +18 -0
  46. dialectical_framework/protocols/ratable.py +79 -0
  47. dialectical_framework/protocols/reloadable.py +7 -0
  48. dialectical_framework/protocols/thesis_extractor.py +15 -0
  49. dialectical_framework/settings.py +77 -0
  50. dialectical_framework/synthesis.py +7 -0
  51. dialectical_framework/synthesist/__init__.py +1 -0
  52. dialectical_framework/synthesist/causality/__init__.py +0 -0
  53. dialectical_framework/synthesist/causality/causality_sequencer_balanced.py +398 -0
  54. dialectical_framework/synthesist/causality/causality_sequencer_desirable.py +55 -0
  55. dialectical_framework/synthesist/causality/causality_sequencer_feasible.py +55 -0
  56. dialectical_framework/synthesist/causality/causality_sequencer_realistic.py +56 -0
  57. dialectical_framework/synthesist/concepts/__init__.py +0 -0
  58. dialectical_framework/synthesist/concepts/thesis_extractor_basic.py +135 -0
  59. dialectical_framework/synthesist/polarity/__init__.py +0 -0
  60. dialectical_framework/synthesist/polarity/polarity_reasoner.py +700 -0
  61. dialectical_framework/synthesist/polarity/reason_blind.py +62 -0
  62. dialectical_framework/synthesist/polarity/reason_conversational.py +91 -0
  63. dialectical_framework/synthesist/polarity/reason_fast.py +177 -0
  64. dialectical_framework/synthesist/polarity/reason_fast_and_simple.py +52 -0
  65. dialectical_framework/synthesist/polarity/reason_fast_polarized_conflict.py +55 -0
  66. dialectical_framework/synthesist/reverse_engineer.py +401 -0
  67. dialectical_framework/synthesist/wheel_builder.py +337 -0
  68. dialectical_framework/utils/__init__.py +1 -0
  69. dialectical_framework/utils/dc_replace.py +42 -0
  70. dialectical_framework/utils/decompose_probability_uniformly.py +15 -0
  71. dialectical_framework/utils/extend_tpl.py +12 -0
  72. dialectical_framework/utils/gm.py +12 -0
  73. dialectical_framework/utils/is_async.py +13 -0
  74. dialectical_framework/utils/use_brain.py +80 -0
  75. dialectical_framework/validator/__init__.py +1 -0
  76. dialectical_framework/validator/basic_checks.py +75 -0
  77. dialectical_framework/validator/check.py +12 -0
  78. dialectical_framework/wheel.py +395 -0
  79. dialectical_framework/wheel_segment.py +203 -0
  80. dialectical_framework/wisdom_unit.py +185 -0
  81. dialectical_framework-0.4.4.dist-info/LICENSE +21 -0
  82. dialectical_framework-0.4.4.dist-info/METADATA +123 -0
  83. dialectical_framework-0.4.4.dist-info/RECORD +84 -0
  84. dialectical_framework-0.4.4.dist-info/WHEEL +4 -0
@@ -0,0 +1,401 @@
1
+ from typing import Dict, List
2
+
3
+ from mirascope import BaseMessageParam, Messages, prompt_template
4
+
5
+ from dialectical_framework.analyst.domain.cycle import Cycle
6
+ from dialectical_framework.dialectical_component import DialecticalComponent
7
+ from dialectical_framework.enums.causality_type import CausalityType
8
+ from dialectical_framework.enums.dialectical_reasoning_mode import \
9
+ DialecticalReasoningMode
10
+ from dialectical_framework.utils.extend_tpl import extend_tpl
11
+ from dialectical_framework.wheel import Wheel
12
+ from dialectical_framework.wisdom_unit import WisdomUnit
13
+
14
+
15
+ # TODO: reuse the prompts from the reasoners?
16
+ class ReverseEngineer:
17
+ @prompt_template(
18
+ """
19
+ USER:
20
+ Consider the following text as the initial context for further analysis:
21
+
22
+ <context>{text}</context>
23
+
24
+ ASSISTANT:
25
+ OK, let's start.
26
+ """
27
+ )
28
+ def prompt_input_text(self, *, text: str) -> Messages.Type: ...
29
+
30
+ @prompt_template(
31
+ """
32
+ USER:
33
+ Consider these statements:
34
+
35
+ {dialectical_components:lists}
36
+
37
+ ASSISTANT:
38
+ OK, let's proceed.
39
+ """
40
+ )
41
+ def prompt_input_theses(
42
+ self, *, dialectical_components: list[List:str]
43
+ ) -> Messages.Type: ...
44
+
45
+ @prompt_template(
46
+ """
47
+ USER:
48
+ Extract the central idea or the primary thesis (denote it as {denotation}) of the context with minimal distortion. If already concise (single word/phrase/clear thesis), keep it intact; only condense verbose messages while preserving original meaning.
49
+
50
+ <formatting>
51
+ Output the dialectical component {denotation} and explanation how it was derived in the passive voice.
52
+ </formatting>
53
+
54
+ ASSISTANT:
55
+ ## Dialectical Component:
56
+ Alias = {denotation}
57
+ Statement = {thesis}
58
+ Explanation: {explanation}
59
+ """
60
+ )
61
+ def prompt_dialectical_reasoner_find_thesis(
62
+ self, *, thesis: str, explanation: str, denotation: str = "T"
63
+ ) -> Messages.Type: ...
64
+
65
+ @prompt_template(
66
+ """
67
+ USER:
68
+ Consider these theses:
69
+ {theses:lists}
70
+
71
+ USER:
72
+ ## Dialectical Analysis (Reasoning Mode: {reasoning_mode})
73
+ <instructions>
74
+ For every thesis (T), identify its semantic/functional antithesis (A), such that positive/constructive side of thesis (T+) should oppose/contradict the negative/exaggerated side of antithesis (A-), while negative/exaggerated side of thesis (T-) should oppose/contradict the positive/constructive side of antithesis (A+).
75
+
76
+ For example:
77
+ T = Love
78
+ T+ = Happiness (positive aspect of Love)
79
+ T- = Fixation (negative aspect of Love)
80
+ A = Indifference (antithesis of Love)
81
+ A+ = Objectivity (positive aspect of Indifference, contradicts Fixation)
82
+ A- = Misery (negative aspect of Indifference, contradicts Happiness).
83
+
84
+ Compose the explanations how each dialectical component was derived in the passive voice. Don't mention any special denotations such as "T", "T+", "A-", etc.
85
+ </instructions>
86
+
87
+ ASSISTANT:
88
+ ## Wisdom Units:
89
+ {wisdom_units:lists}
90
+ """
91
+ )
92
+ def prompt_find_wisdom_units__general_concepts(
93
+ self,
94
+ *,
95
+ reasoning_mode: str,
96
+ theses: list[List:str],
97
+ wisdom_units: list[list[str]],
98
+ ) -> Messages.Type: ...
99
+
100
+ @prompt_template(
101
+ """
102
+ USER:
103
+ Consider these theses:
104
+ {theses:lists}
105
+
106
+ USER:
107
+ ## Dialectical Analysis (Reasoning Mode: {reasoning_mode})}
108
+ <instructions>
109
+ For very thesis (T), frame the problem as a tension between two opposing approaches:
110
+ - Thesis (T): The first approach or position
111
+ - Antithesis (A): The contrasting approach or position
112
+
113
+ T and A must be such that positive/constructive side of thesis (T+) should oppose/contradict the negative/exaggerated side of antithesis (A-), while negative/exaggerated side of thesis (T-) should oppose/contradict the positive/constructive side of antithesis (A+).
114
+
115
+ For example:
116
+ In a token vesting dispute, stakeholders disagreed about extending the lock period from January 2025 to January 2026. The original solution was a staged distribution with incentives.
117
+
118
+ T: Vest Now
119
+ T+ = Trust Building
120
+ T- = Loss of Value
121
+ A: Vest Later
122
+ A+ = Value Protection (contradicts T-)
123
+ A- = Trust Erosion (contradicts T+)
124
+ </instructions>
125
+
126
+ ASSISTANT:
127
+ {wisdom_units:lists}
128
+ """
129
+ )
130
+ def prompt_find_wisdom_units__major_tension(
131
+ self,
132
+ *,
133
+ reasoning_mode: str,
134
+ theses: list[list[str]],
135
+ wisdom_units: list[list[str]],
136
+ ) -> Messages.Type: ...
137
+
138
+ @prompt_template(
139
+ """
140
+ USER:
141
+ Consider the following circular causality sequences of dialectical components:
142
+ {sequences:list}
143
+
144
+ <instructions>
145
+ Estimate how realistic is each sequence, i.e. what typically happens in natural systems (given that the final step cycles back to the first step):
146
+ 1) Estimate the numeric probability (0 to 1) regarding its realistic existence in natural/existing systems
147
+ 1) Explain why this sequence might occur in reality
148
+ 3) Describe circumstances or contexts where this sequence would be most applicable or useful
149
+ </instructions>
150
+
151
+ <formatting>
152
+ Probability is a float between 0 and 1.
153
+ In the explanations don't use these technical placeholders.
154
+ </formatting>
155
+
156
+ ASSISTANT:
157
+ {estimations:lists}
158
+ """
159
+ )
160
+ def prompt_cycle__realistic(
161
+ self, sequences: list[str], estimations: list[list[str]]
162
+ ) -> Messages.Type: ...
163
+
164
+ @prompt_template(
165
+ """
166
+ USER:
167
+ Consider the following circular causality sequences of dialectical components:
168
+ {sequences:list}
169
+
170
+ <instructions>
171
+ Estimate how desirable is each sequence, i.e. would produce optimal outcomes and maximum results (given that the final step cycles back to the first step):
172
+ 1) Estimate the numeric probability (0 to 1) regarding how beneficial/optimal this sequence would be if implemented
173
+ 1) Explain why this sequence might occur in reality
174
+ 3) Describe circumstances or contexts where this sequence would be most applicable or useful
175
+ </instructions>
176
+
177
+ <formatting>
178
+ Probability is a float between 0 and 1.
179
+ In the explanations don't use these technical placeholders.
180
+ </formatting>
181
+
182
+ ASSISTANT:
183
+ {estimations:lists}
184
+ """
185
+ )
186
+ def prompt_cycle__desirable(
187
+ self, sequences: list[str], estimations: list[list[str]]
188
+ ) -> Messages.Type: ...
189
+
190
+ @prompt_template(
191
+ """
192
+ USER:
193
+ Consider the following circular causality sequences of dialectical components:
194
+ {sequences:list}
195
+
196
+ <instructions>
197
+ Estimate how feasible is each sequence, i.e. best achievable with minimum resistance (given that the final step cycles back to the first step):
198
+ 1) Estimate the numeric probability (0 to 1) regarding how easily this sequence could be implemented given current constraints
199
+ 1) Explain why this sequence might occur in reality
200
+ 3) Describe circumstances or contexts where this sequence would be most applicable or useful
201
+ </instructions>
202
+
203
+ <formatting>
204
+ Probability is a float between 0 and 1.
205
+ In the explanations don't use these technical placeholders.
206
+ </formatting>
207
+
208
+ ASSISTANT:
209
+ {estimations:lists}
210
+ """
211
+ )
212
+ def prompt_cycle__feasible(
213
+ self, sequences: list[str], estimations: list[list[str]]
214
+ ) -> Messages.Type: ...
215
+
216
+ @prompt_template(
217
+ """
218
+ USER:
219
+ Consider the following circular causality sequences of dialectical components:
220
+ {sequences:list}
221
+
222
+ <instructions>
223
+ Estimate how balanced is each sequence, i.e. provides the best balanced assessment considering realism, desirability, and feasibility (given that the final step cycles back to the first step):
224
+ 1) Estimate the numeric probability (0 to 1) as a balanced assessment considering realistic existence, optimal outcomes, and implementation feasibility
225
+ 1) Explain why this sequence might occur in reality
226
+ 3) Describe circumstances or contexts where this sequence would be most applicable or useful
227
+ </instructions>
228
+
229
+ <formatting>
230
+ Probability is a float between 0 and 1.
231
+ In the explanations don't use these technical placeholders.
232
+ </formatting>
233
+
234
+ ASSISTANT:
235
+ {estimations:lists}
236
+ """
237
+ )
238
+ def prompt_cycle__balanced(
239
+ self, sequences: list[str], estimations: list[list[str]]
240
+ ) -> Messages.Type: ...
241
+
242
+ @staticmethod
243
+ def till_theses(
244
+ theses: list[DialecticalComponent], text: str = None
245
+ ) -> list[BaseMessageParam]:
246
+ reverse_engineer = ReverseEngineer()
247
+ tpl: list[BaseMessageParam] = []
248
+
249
+ if text:
250
+ # Convert Messages.Type to list and extend instead of append
251
+ input_messages = reverse_engineer.prompt_input_text(text=text)
252
+ extend_tpl(tpl, input_messages)
253
+
254
+ theses = [
255
+ [
256
+ f"### Concept/Statement {index + 1} ({dc.alias})",
257
+ f"Alias: {dc.alias}",
258
+ f"Statement: {dc.statement}",
259
+ # Don't render explanations here, as these might be referring to other places in the wisdom unit,
260
+ # which might be confusing or even misleading in further prompt
261
+ ]
262
+ for index, dc in enumerate(theses)
263
+ ]
264
+
265
+ dc_messages = reverse_engineer.prompt_input_theses(
266
+ dialectical_components=theses
267
+ )
268
+ extend_tpl(tpl, dc_messages)
269
+
270
+ return tpl
271
+
272
+ @staticmethod
273
+ def till_wisdom_units(
274
+ wisdom_units: list[WisdomUnit], text: str = None
275
+ ) -> list[BaseMessageParam]:
276
+ reverse_engineer = ReverseEngineer()
277
+ tpl: list[BaseMessageParam] = []
278
+
279
+ if text:
280
+ # Convert Messages.Type to list and extend instead of append
281
+ input_messages = reverse_engineer.prompt_input_text(text=text)
282
+ extend_tpl(tpl, input_messages)
283
+
284
+ wus: Dict[DialecticalReasoningMode, list[WisdomUnit]] = (
285
+ _wisdom_units_grouped_by_reasoning_mode(wisdom_units)
286
+ )
287
+ for mode, wisdom_units in wus.items():
288
+ theses = [
289
+ [
290
+ f"### Thesis {index + 1} ({wu.t.alias})",
291
+ f"Alias: {wu.t.alias}",
292
+ f"Statement: {wu.t.statement}",
293
+ f"Explanation: {wu.t.best_rationale.text if wu.t.best_rationale else 'N/A'}",
294
+ ]
295
+ for index, wu in enumerate(wisdom_units)
296
+ ]
297
+ wu_lists = [
298
+ [
299
+ f"### Wisdom Unit for {wu.t.alias}",
300
+ f"{wu.t.alias} = {wu.t.statement}",
301
+ f"{wu.a.alias} = {wu.a.statement}",
302
+ f"{wu.a.alias} explanation: {wu.a.best_rationale.text if wu.a.best_rationale else 'N/A'}",
303
+ f"{wu.t_minus.alias} = {wu.t_minus.statement}",
304
+ f"{wu.t_minus.alias} explanation: {wu.t_minus.best_rationale.text if wu.t_minus.best_rationale else 'N/A'}",
305
+ f"{wu.t_plus.alias} = {wu.t_plus.statement}",
306
+ f"{wu.t_plus.alias} explanation: {wu.t_plus.best_rationale.text if wu.t_plus.best_rationale else 'N/A'}",
307
+ f"{wu.a_plus.alias} = {wu.a_plus.statement}",
308
+ f"{wu.a_plus.alias} explanation: {wu.a_plus.best_rationale.text if wu.a_plus.best_rationale else 'N/A'}",
309
+ f"{wu.a_minus.alias} = {wu.a_minus.statement}",
310
+ f"{wu.a_minus.alias} explanation: {wu.a_minus.best_rationale.text if wu.a_minus.best_rationale else 'N/A'}",
311
+ ]
312
+ for wu in wisdom_units
313
+ ]
314
+
315
+ if mode == DialecticalReasoningMode.MAJOR_TENSION:
316
+ wu_messages = reverse_engineer.prompt_find_wisdom_units__major_tension(
317
+ reasoning_mode=DialecticalReasoningMode.MAJOR_TENSION.value,
318
+ theses=theses,
319
+ wisdom_units=wu_lists,
320
+ )
321
+ else:
322
+ wu_messages = (
323
+ reverse_engineer.prompt_find_wisdom_units__general_concepts(
324
+ reasoning_mode=DialecticalReasoningMode.GENERAL_CONCEPTS.value,
325
+ theses=theses,
326
+ wisdom_units=wu_lists,
327
+ )
328
+ )
329
+
330
+ extend_tpl(tpl, wu_messages)
331
+
332
+ return tpl
333
+
334
+ @staticmethod
335
+ def till_cycle(
336
+ wisdom_units: list[WisdomUnit],
337
+ t_cycle: Cycle,
338
+ ta_cycle: Cycle = None,
339
+ text: str = None,
340
+ ) -> list[BaseMessageParam]:
341
+ reverse_engineer = ReverseEngineer()
342
+ tpl: list[BaseMessageParam] = ReverseEngineer.till_wisdom_units(
343
+ wisdom_units, text
344
+ )
345
+
346
+ cycles = {
347
+ t_cycle.cycle_str(): [
348
+ f"### {t_cycle.causality_type.value.capitalize()} Causality Estimation for {t_cycle.cycle_str()}",
349
+ f"Probability: {t_cycle.contextual_fidelity}", # Note that it's the initial assessment that we take, not normalized
350
+ f"Rationale: {t_cycle.best_rationale.text if t_cycle.best_rationale and t_cycle.best_rationale.text else 'N/A'}",
351
+ ],
352
+ }
353
+ if ta_cycle:
354
+ cycles[ta_cycle.cycle_str()] = [
355
+ f"### {ta_cycle.causality_type.value.capitalize()} Causality Estimation for {ta_cycle.cycle_str()}",
356
+ f"Probability: {ta_cycle.contextual_fidelity}", # Note that it's the initial assessment that we take, not normalized
357
+ f"Rationale: {ta_cycle.best_rationale.text if ta_cycle.best_rationale and ta_cycle.best_rationale.text else 'N/A'}",
358
+ ]
359
+
360
+ if t_cycle.causality_type == CausalityType.REALISTIC:
361
+ cycle_messages = reverse_engineer.prompt_cycle__realistic(
362
+ sequences=list(cycles.keys()),
363
+ estimations=list(cycles.values()),
364
+ )
365
+ elif t_cycle.causality_type == CausalityType.DESIRABLE:
366
+ cycle_messages = reverse_engineer.prompt_cycle__desirable(
367
+ sequences=list(cycles.keys()),
368
+ estimations=list(cycles.values()),
369
+ )
370
+ elif t_cycle.causality_type == CausalityType.FEASIBLE:
371
+ cycle_messages = reverse_engineer.prompt_cycle__feasible(
372
+ sequences=list(cycles.keys()),
373
+ estimations=list(cycles.values()),
374
+ )
375
+ else:
376
+ cycle_messages = reverse_engineer.prompt_cycle__balanced(
377
+ sequences=list(cycles.keys()),
378
+ estimations=list(cycles.values()),
379
+ )
380
+
381
+ extend_tpl(tpl, cycle_messages)
382
+
383
+ return tpl
384
+
385
+ @staticmethod
386
+ def wheel(wheel: Wheel, text: str = None) -> list[BaseMessageParam]:
387
+ # TODO: transitions/spiral
388
+ return ReverseEngineer.till_cycle(
389
+ wheel.wisdom_units, wheel.t_cycle, wheel.cycle, text
390
+ )
391
+
392
+
393
+ def _wisdom_units_grouped_by_reasoning_mode(
394
+ wisdom_units: list[WisdomUnit],
395
+ ) -> Dict[DialecticalReasoningMode, list[WisdomUnit]]:
396
+ grouped_units = {}
397
+ for wu in wisdom_units:
398
+ if wu.reasoning_mode not in grouped_units:
399
+ grouped_units[wu.reasoning_mode] = []
400
+ grouped_units[wu.reasoning_mode].append(wu)
401
+ return grouped_units