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.
- dialectical_framework/__init__.py +43 -0
- dialectical_framework/ai_dto/__init__.py +0 -0
- dialectical_framework/ai_dto/causal_cycle_assessment_dto.py +16 -0
- dialectical_framework/ai_dto/causal_cycle_dto.py +16 -0
- dialectical_framework/ai_dto/causal_cycles_deck_dto.py +11 -0
- dialectical_framework/ai_dto/dialectical_component_dto.py +16 -0
- dialectical_framework/ai_dto/dialectical_components_deck_dto.py +12 -0
- dialectical_framework/ai_dto/dto_mapper.py +103 -0
- dialectical_framework/ai_dto/reciprocal_solution_dto.py +24 -0
- dialectical_framework/analyst/__init__.py +1 -0
- dialectical_framework/analyst/audit/__init__.py +0 -0
- dialectical_framework/analyst/consultant.py +30 -0
- dialectical_framework/analyst/decorator_action_reflection.py +28 -0
- dialectical_framework/analyst/decorator_discrete_spiral.py +30 -0
- dialectical_framework/analyst/domain/__init__.py +0 -0
- dialectical_framework/analyst/domain/assessable_cycle.py +128 -0
- dialectical_framework/analyst/domain/cycle.py +133 -0
- dialectical_framework/analyst/domain/interpretation.py +16 -0
- dialectical_framework/analyst/domain/rationale.py +116 -0
- dialectical_framework/analyst/domain/spiral.py +47 -0
- dialectical_framework/analyst/domain/transformation.py +24 -0
- dialectical_framework/analyst/domain/transition.py +160 -0
- dialectical_framework/analyst/domain/transition_cell_to_cell.py +29 -0
- dialectical_framework/analyst/domain/transition_segment_to_segment.py +16 -0
- dialectical_framework/analyst/strategic_consultant.py +32 -0
- dialectical_framework/analyst/think_action_reflection.py +217 -0
- dialectical_framework/analyst/think_constructive_convergence.py +87 -0
- dialectical_framework/analyst/wheel_builder_transition_calculator.py +157 -0
- dialectical_framework/brain.py +81 -0
- dialectical_framework/dialectical_analysis.py +14 -0
- dialectical_framework/dialectical_component.py +111 -0
- dialectical_framework/dialectical_components_deck.py +48 -0
- dialectical_framework/dialectical_reasoning.py +105 -0
- dialectical_framework/directed_graph.py +419 -0
- dialectical_framework/enums/__init__.py +0 -0
- dialectical_framework/enums/causality_type.py +10 -0
- dialectical_framework/enums/di.py +11 -0
- dialectical_framework/enums/dialectical_reasoning_mode.py +9 -0
- dialectical_framework/enums/predicate.py +9 -0
- dialectical_framework/protocols/__init__.py +0 -0
- dialectical_framework/protocols/assessable.py +141 -0
- dialectical_framework/protocols/causality_sequencer.py +111 -0
- dialectical_framework/protocols/content_fidelity_evaluator.py +16 -0
- dialectical_framework/protocols/has_brain.py +18 -0
- dialectical_framework/protocols/has_config.py +18 -0
- dialectical_framework/protocols/ratable.py +79 -0
- dialectical_framework/protocols/reloadable.py +7 -0
- dialectical_framework/protocols/thesis_extractor.py +15 -0
- dialectical_framework/settings.py +77 -0
- dialectical_framework/synthesis.py +7 -0
- dialectical_framework/synthesist/__init__.py +1 -0
- dialectical_framework/synthesist/causality/__init__.py +0 -0
- dialectical_framework/synthesist/causality/causality_sequencer_balanced.py +398 -0
- dialectical_framework/synthesist/causality/causality_sequencer_desirable.py +55 -0
- dialectical_framework/synthesist/causality/causality_sequencer_feasible.py +55 -0
- dialectical_framework/synthesist/causality/causality_sequencer_realistic.py +56 -0
- dialectical_framework/synthesist/concepts/__init__.py +0 -0
- dialectical_framework/synthesist/concepts/thesis_extractor_basic.py +135 -0
- dialectical_framework/synthesist/polarity/__init__.py +0 -0
- dialectical_framework/synthesist/polarity/polarity_reasoner.py +700 -0
- dialectical_framework/synthesist/polarity/reason_blind.py +62 -0
- dialectical_framework/synthesist/polarity/reason_conversational.py +91 -0
- dialectical_framework/synthesist/polarity/reason_fast.py +177 -0
- dialectical_framework/synthesist/polarity/reason_fast_and_simple.py +52 -0
- dialectical_framework/synthesist/polarity/reason_fast_polarized_conflict.py +55 -0
- dialectical_framework/synthesist/reverse_engineer.py +401 -0
- dialectical_framework/synthesist/wheel_builder.py +337 -0
- dialectical_framework/utils/__init__.py +1 -0
- dialectical_framework/utils/dc_replace.py +42 -0
- dialectical_framework/utils/decompose_probability_uniformly.py +15 -0
- dialectical_framework/utils/extend_tpl.py +12 -0
- dialectical_framework/utils/gm.py +12 -0
- dialectical_framework/utils/is_async.py +13 -0
- dialectical_framework/utils/use_brain.py +80 -0
- dialectical_framework/validator/__init__.py +1 -0
- dialectical_framework/validator/basic_checks.py +75 -0
- dialectical_framework/validator/check.py +12 -0
- dialectical_framework/wheel.py +395 -0
- dialectical_framework/wheel_segment.py +203 -0
- dialectical_framework/wisdom_unit.py +185 -0
- dialectical_framework-0.4.4.dist-info/LICENSE +21 -0
- dialectical_framework-0.4.4.dist-info/METADATA +123 -0
- dialectical_framework-0.4.4.dist-info/RECORD +84 -0
- dialectical_framework-0.4.4.dist-info/WHEEL +4 -0
@@ -0,0 +1,398 @@
|
|
1
|
+
import asyncio
|
2
|
+
from typing import Self, Union, cast
|
3
|
+
|
4
|
+
from mirascope import Messages, prompt_template
|
5
|
+
from mirascope.integrations.langfuse import with_langfuse
|
6
|
+
|
7
|
+
from dialectical_framework.ai_dto.causal_cycle_assessment_dto import \
|
8
|
+
CausalCycleAssessmentDto
|
9
|
+
from dialectical_framework.ai_dto.causal_cycle_dto import CausalCycleDto
|
10
|
+
from dialectical_framework.ai_dto.causal_cycles_deck_dto import \
|
11
|
+
CausalCyclesDeckDto
|
12
|
+
from dialectical_framework.analyst.domain.assessable_cycle import decompose_probability_into_transitions
|
13
|
+
from dialectical_framework.analyst.domain.cycle import Cycle
|
14
|
+
from dialectical_framework.analyst.domain.rationale import Rationale
|
15
|
+
from dialectical_framework.dialectical_component import DialecticalComponent
|
16
|
+
from dialectical_framework.dialectical_components_deck import \
|
17
|
+
DialecticalComponentsDeck
|
18
|
+
from dialectical_framework.protocols.causality_sequencer import (
|
19
|
+
CausalitySequencer, generate_compatible_sequences,
|
20
|
+
generate_permutation_sequences)
|
21
|
+
from dialectical_framework.protocols.has_brain import HasBrain
|
22
|
+
from dialectical_framework.protocols.has_config import SettingsAware
|
23
|
+
from dialectical_framework.synthesist.reverse_engineer import ReverseEngineer
|
24
|
+
from dialectical_framework.utils.dc_replace import dc_replace
|
25
|
+
from dialectical_framework.utils.extend_tpl import extend_tpl
|
26
|
+
from dialectical_framework.utils.use_brain import use_brain
|
27
|
+
from dialectical_framework.wheel_segment import ALIAS_T
|
28
|
+
from dialectical_framework.wisdom_unit import WisdomUnit
|
29
|
+
|
30
|
+
|
31
|
+
class CausalitySequencerBalanced(CausalitySequencer, HasBrain, SettingsAware):
|
32
|
+
def __init__(self, *, text: str = ""):
|
33
|
+
self.__text = text
|
34
|
+
|
35
|
+
@property
|
36
|
+
def text(self) -> str:
|
37
|
+
return self.__text
|
38
|
+
|
39
|
+
@text.setter
|
40
|
+
def text(self, value: str):
|
41
|
+
self.__text = value
|
42
|
+
|
43
|
+
def reload(self, *, text: str) -> Self:
|
44
|
+
self.text = text
|
45
|
+
return self
|
46
|
+
|
47
|
+
@prompt_template(
|
48
|
+
"""
|
49
|
+
USER:
|
50
|
+
Which of the following circular causality sequences provides the best assessment considering realism, desirability, and feasibility (given that the final step cycles back to the first step):
|
51
|
+
{sequences:list}
|
52
|
+
|
53
|
+
<instructions>
|
54
|
+
For each sequence:
|
55
|
+
1) Estimate the numeric probability (0 to 1) considering realistic existence, optimal outcomes, and (implementation) feasibility
|
56
|
+
2) Explain why this sequence might occur (or already occurs) in reality
|
57
|
+
3) Describe circumstances or contexts where this sequence would be most applicable or useful
|
58
|
+
|
59
|
+
- Only use the sequences **exactly as provided**, do not shorten, skip, collapse, or reorder steps.
|
60
|
+
</instructions>
|
61
|
+
|
62
|
+
<formatting>
|
63
|
+
- Output each circular causality sequence (cycle) as ordered aliases (technical placeholders) of statements as provided e.g. C1, C2, C3, ...
|
64
|
+
- In the explanations, for fluency, use explicit wording instead of aliases.
|
65
|
+
- Probability is a float between 0 and 1.
|
66
|
+
</formatting>
|
67
|
+
"""
|
68
|
+
)
|
69
|
+
def prompt_assess_multiple_sequences(
|
70
|
+
self, *, sequences: list[str]
|
71
|
+
) -> Messages.Type: ...
|
72
|
+
|
73
|
+
@prompt_template(
|
74
|
+
"""
|
75
|
+
USER:
|
76
|
+
Assess the following circular causality sequence considering realism, desirability, and feasibility (given that the final step cycles back to the first step):
|
77
|
+
{sequence}
|
78
|
+
|
79
|
+
<instructions>
|
80
|
+
1) Estimate the numeric probability (0 to 1) considering realistic existence, optimal outcomes, and (implementation) feasibility
|
81
|
+
2) Explain why this sequence might occur (or already occurs) in reality
|
82
|
+
3) Describe circumstances or contexts where this sequence would be most applicable or useful
|
83
|
+
|
84
|
+
- Only use the sequence **exactly as provided**, do not shorten, skip, collapse, or reorder steps.
|
85
|
+
</instructions>
|
86
|
+
|
87
|
+
<formatting>
|
88
|
+
- In the explanations and argumentation, for fluency, try to use explicit wording instead of technical aliases.
|
89
|
+
- Probability is a float between 0 and 1.
|
90
|
+
</formatting>
|
91
|
+
"""
|
92
|
+
)
|
93
|
+
def prompt_assess_single_sequence(self, *, sequence: str) -> Messages.Type: ...
|
94
|
+
|
95
|
+
async def _estimate_cycles(
|
96
|
+
self, *, sequences: list[list[DialecticalComponent]]
|
97
|
+
) -> CausalCyclesDeckDto:
|
98
|
+
sequences_str: dict[str, list[str]] = {}
|
99
|
+
|
100
|
+
# To avoid hallucinations, make all alias uniform so that AI doesn't try to guess where's a thesis or antithesis
|
101
|
+
translated_components: list[DialecticalComponent] = []
|
102
|
+
alias_translations: dict[str, str] = {}
|
103
|
+
for sequence in sequences:
|
104
|
+
for i, dc in enumerate(sequence, 1):
|
105
|
+
if dc in translated_components:
|
106
|
+
continue
|
107
|
+
translated_components.append(dc)
|
108
|
+
alias_translations[f"C{i}"] = dc.alias
|
109
|
+
dc.alias = f"C{i}"
|
110
|
+
# TODO: we should also do dc_replace for statement/rationales texts, and later translate these back (as alias got translated)
|
111
|
+
|
112
|
+
deck = DialecticalComponentsDeck(dialectical_components=sequence)
|
113
|
+
cycle = deck.get_aliases_as_cycle_str()
|
114
|
+
|
115
|
+
# Add statements to sequences, for more clarity
|
116
|
+
as_is_seq = cycle
|
117
|
+
for a in alias_translations:
|
118
|
+
as_is_seq = dc_replace(as_is_seq, a, deck.get_by_alias(a).statement)
|
119
|
+
cycle = f"{cycle} ({as_is_seq})"
|
120
|
+
sequences_str[cycle] = deck.get_aliases()
|
121
|
+
|
122
|
+
dialectical_components = []
|
123
|
+
for dc in translated_components:
|
124
|
+
# Check if this component is already in our deduplicated list
|
125
|
+
if not any(
|
126
|
+
existing_dc.is_same(dc) for existing_dc in dialectical_components
|
127
|
+
):
|
128
|
+
dialectical_components.append(dc)
|
129
|
+
|
130
|
+
@with_langfuse()
|
131
|
+
@use_brain(brain=self.brain, response_model=CausalCyclesDeckDto)
|
132
|
+
async def _estimate_all() -> CausalCyclesDeckDto:
|
133
|
+
prompt = self.prompt_assess_multiple_sequences(
|
134
|
+
sequences=list(sequences_str.keys())
|
135
|
+
)
|
136
|
+
tpl = ReverseEngineer.till_theses(
|
137
|
+
theses=dialectical_components, text=self.text
|
138
|
+
)
|
139
|
+
return extend_tpl(tpl, prompt)
|
140
|
+
|
141
|
+
async def _estimate_single(
|
142
|
+
sequence_str: str, aliases: list[str]
|
143
|
+
) -> CausalCycleDto:
|
144
|
+
@with_langfuse()
|
145
|
+
@use_brain(brain=self.brain, response_model=CausalCycleAssessmentDto)
|
146
|
+
async def _estimate_single_call() -> CausalCycleAssessmentDto:
|
147
|
+
prompt = self.prompt_assess_single_sequence(sequence=sequence_str)
|
148
|
+
tpl = ReverseEngineer.till_theses(
|
149
|
+
theses=dialectical_components, text=self.text
|
150
|
+
)
|
151
|
+
return extend_tpl(tpl, prompt)
|
152
|
+
|
153
|
+
assessment = await _estimate_single_call()
|
154
|
+
return CausalCycleDto(
|
155
|
+
aliases=aliases,
|
156
|
+
probability=assessment.probability,
|
157
|
+
reasoning_explanation=assessment.reasoning_explanation,
|
158
|
+
argumentation=assessment.argumentation,
|
159
|
+
)
|
160
|
+
|
161
|
+
# result = await _estimate_all()
|
162
|
+
async_estimators = []
|
163
|
+
for sequence, aliases in sequences_str.items():
|
164
|
+
async_estimators.append(
|
165
|
+
_estimate_single(sequence_str=sequence, aliases=aliases)
|
166
|
+
)
|
167
|
+
|
168
|
+
# Execute all async estimators concurrently and collect results
|
169
|
+
causal_cycles = await asyncio.gather(*async_estimators)
|
170
|
+
# Create the result deck from collected cycles
|
171
|
+
result = CausalCyclesDeckDto(causal_cycles=causal_cycles)
|
172
|
+
|
173
|
+
# Translate aliases back in the parameter
|
174
|
+
for sequence in sequences:
|
175
|
+
for dc in sequence:
|
176
|
+
if dc.alias in alias_translations:
|
177
|
+
dc.alias = alias_translations[dc.alias]
|
178
|
+
|
179
|
+
# Translate back the aliases in the result
|
180
|
+
for causal_cycle in result.causal_cycles:
|
181
|
+
for a in causal_cycle.aliases:
|
182
|
+
# Normally technical aliases aren't mentioned in the texts, but who knows... let's blindly translate back
|
183
|
+
causal_cycle.reasoning_explanation = dc_replace(
|
184
|
+
causal_cycle.reasoning_explanation, a, alias_translations[a]
|
185
|
+
)
|
186
|
+
causal_cycle.argumentation = dc_replace(
|
187
|
+
causal_cycle.argumentation, a, alias_translations[a]
|
188
|
+
)
|
189
|
+
causal_cycle.aliases = [
|
190
|
+
alias_translations[alias] for alias in causal_cycle.aliases
|
191
|
+
]
|
192
|
+
|
193
|
+
return result
|
194
|
+
|
195
|
+
async def arrange(
|
196
|
+
self, thoughts: Union[list[str], list[WisdomUnit], list[DialecticalComponent]]
|
197
|
+
) -> list[Cycle]:
|
198
|
+
sequences = self._get_sequences(thoughts)
|
199
|
+
|
200
|
+
if thoughts and isinstance(thoughts[0], WisdomUnit):
|
201
|
+
ordered_wisdom_units: list[WisdomUnit] = thoughts
|
202
|
+
if len(thoughts) == 1:
|
203
|
+
return [
|
204
|
+
Cycle(
|
205
|
+
dialectical_components=[
|
206
|
+
ordered_wisdom_units[0].t,
|
207
|
+
ordered_wisdom_units[0].a,
|
208
|
+
],
|
209
|
+
probability=1.0,
|
210
|
+
causality_type=self.settings.causality_type,
|
211
|
+
)
|
212
|
+
]
|
213
|
+
elif len(thoughts) == 2:
|
214
|
+
dialectical_components_deck = DialecticalComponentsDeck(
|
215
|
+
dialectical_components=[
|
216
|
+
ordered_wisdom_units[0].t,
|
217
|
+
ordered_wisdom_units[1].t,
|
218
|
+
ordered_wisdom_units[0].a,
|
219
|
+
ordered_wisdom_units[1].a,
|
220
|
+
]
|
221
|
+
)
|
222
|
+
elif len(thoughts) == 3:
|
223
|
+
dialectical_components_deck = DialecticalComponentsDeck(
|
224
|
+
dialectical_components=[
|
225
|
+
ordered_wisdom_units[0].t,
|
226
|
+
ordered_wisdom_units[1].t,
|
227
|
+
ordered_wisdom_units[2].t,
|
228
|
+
ordered_wisdom_units[0].a,
|
229
|
+
ordered_wisdom_units[1].a,
|
230
|
+
ordered_wisdom_units[2].a,
|
231
|
+
]
|
232
|
+
)
|
233
|
+
elif len(thoughts) == 4:
|
234
|
+
dialectical_components_deck = DialecticalComponentsDeck(
|
235
|
+
dialectical_components=[
|
236
|
+
ordered_wisdom_units[0].t,
|
237
|
+
ordered_wisdom_units[1].t,
|
238
|
+
ordered_wisdom_units[2].t,
|
239
|
+
ordered_wisdom_units[3].t,
|
240
|
+
ordered_wisdom_units[0].a,
|
241
|
+
ordered_wisdom_units[1].a,
|
242
|
+
ordered_wisdom_units[2].a,
|
243
|
+
ordered_wisdom_units[3].a,
|
244
|
+
]
|
245
|
+
)
|
246
|
+
else:
|
247
|
+
raise ValueError(
|
248
|
+
f"{len(ordered_wisdom_units)} thoughts are not supported yet."
|
249
|
+
)
|
250
|
+
causal_cycles_deck = await self._estimate_cycles(sequences=sequences)
|
251
|
+
else:
|
252
|
+
if len(thoughts) == 1:
|
253
|
+
if thoughts and isinstance(thoughts[0], DialecticalComponent):
|
254
|
+
return [
|
255
|
+
Cycle(
|
256
|
+
dialectical_components=thoughts,
|
257
|
+
probability=1.0,
|
258
|
+
causality_type=self.settings.causality_type,
|
259
|
+
)
|
260
|
+
]
|
261
|
+
else:
|
262
|
+
return [
|
263
|
+
Cycle(
|
264
|
+
dialectical_components=[
|
265
|
+
DialecticalComponent(
|
266
|
+
alias="T",
|
267
|
+
statement=thoughts[0],
|
268
|
+
)
|
269
|
+
],
|
270
|
+
probability=1.0,
|
271
|
+
causality_type=self.settings.causality_type,
|
272
|
+
)
|
273
|
+
]
|
274
|
+
elif len(thoughts) <= 4:
|
275
|
+
if thoughts and isinstance(thoughts[0], DialecticalComponent):
|
276
|
+
dialectical_components_deck = DialecticalComponentsDeck(
|
277
|
+
dialectical_components=thoughts
|
278
|
+
)
|
279
|
+
else:
|
280
|
+
# TODO: We need to actualize the thesis using AI, so that we don't need to write 'Provided as string'
|
281
|
+
dialectical_components_deck = DialecticalComponentsDeck(
|
282
|
+
dialectical_components=[
|
283
|
+
DialecticalComponent(
|
284
|
+
alias=f"T{i + 1}",
|
285
|
+
statement=t,
|
286
|
+
# explanation="Provided as string.",
|
287
|
+
)
|
288
|
+
for i, t in enumerate(thoughts)
|
289
|
+
]
|
290
|
+
)
|
291
|
+
else:
|
292
|
+
raise ValueError(f"More than 4 thoughts are not supported yet.")
|
293
|
+
|
294
|
+
causal_cycles_deck = await self._estimate_cycles(sequences=sequences)
|
295
|
+
|
296
|
+
return self._normalize(dialectical_components_deck, causal_cycles_deck)
|
297
|
+
|
298
|
+
def _normalize(
|
299
|
+
self,
|
300
|
+
dialectical_components_deck: DialecticalComponentsDeck,
|
301
|
+
causal_cycles_deck: CausalCyclesDeckDto,
|
302
|
+
) -> list[Cycle]:
|
303
|
+
from decimal import ROUND_HALF_UP, Decimal, getcontext
|
304
|
+
|
305
|
+
cycles: list[Cycle] = []
|
306
|
+
total_score = 0
|
307
|
+
for causal_cycle in causal_cycles_deck.causal_cycles:
|
308
|
+
total_score += causal_cycle.probability
|
309
|
+
|
310
|
+
# Probability was a guesswork, let's make it normalized to have statistical strictness
|
311
|
+
if total_score > 0:
|
312
|
+
getcontext().prec = 16
|
313
|
+
q = Decimal("0.001")
|
314
|
+
|
315
|
+
if causal_cycles_deck.causal_cycles and len(causal_cycles_deck.causal_cycles) > 1:
|
316
|
+
# Normalize and round to 3 decimals using Decimal
|
317
|
+
probs = [
|
318
|
+
Decimal(c.probability) / Decimal(total_score) for c in causal_cycles_deck.causal_cycles
|
319
|
+
]
|
320
|
+
else:
|
321
|
+
# No normalization needed, just round to 3 decimals using Decimal
|
322
|
+
probs = [
|
323
|
+
Decimal(c.probability) for c in causal_cycles_deck.causal_cycles
|
324
|
+
]
|
325
|
+
|
326
|
+
probs = [p.quantize(q, rounding=ROUND_HALF_UP) for p in probs]
|
327
|
+
|
328
|
+
# Sort by rounded probabilities (descending)
|
329
|
+
causal_cycles_deck.causal_cycles.sort(
|
330
|
+
key=lambda c: float(
|
331
|
+
Decimal(c.probability) / Decimal(total_score)
|
332
|
+
),
|
333
|
+
reverse=True,
|
334
|
+
)
|
335
|
+
# Recompute in sorted order
|
336
|
+
probs.sort(reverse=True)
|
337
|
+
|
338
|
+
# Add the exact decimal remainder to the highest-probability cycle
|
339
|
+
total_after = sum(probs)
|
340
|
+
diff = Decimal("1.000") - total_after
|
341
|
+
probs[0] = (probs[0] + diff).quantize(q, rounding=ROUND_HALF_UP)
|
342
|
+
|
343
|
+
for causal_cycle, p in zip(causal_cycles_deck.causal_cycles, probs):
|
344
|
+
# Create rationale from reasoning and argumentation
|
345
|
+
cycle_rationale = Rationale(
|
346
|
+
summary=causal_cycle.reasoning_explanation,
|
347
|
+
text=f"{causal_cycle.reasoning_explanation}\n\n{causal_cycle.argumentation}",
|
348
|
+
# Now here's the trick, the normalized probability is assigned to the cycle
|
349
|
+
# because the initial "probability" is actually "feasibility"
|
350
|
+
contextual_fidelity=causal_cycle.probability,
|
351
|
+
probability=float(p)
|
352
|
+
)
|
353
|
+
|
354
|
+
cycle = Cycle(
|
355
|
+
dialectical_components=dialectical_components_deck.rearrange_by_aliases(causal_cycle.aliases),
|
356
|
+
causality_type=self.settings.causality_type,
|
357
|
+
)
|
358
|
+
|
359
|
+
# Add the rationale to the cycle
|
360
|
+
cycle.rationales.append(cycle_rationale)
|
361
|
+
# Decompose probabilities to transitions (because cycle probability is multiplication of transition probabilities)
|
362
|
+
decompose_probability_into_transitions(
|
363
|
+
probability=cycle_rationale.probability,
|
364
|
+
transitions=cycle.graph.get_all_transitions(),
|
365
|
+
overwrite_existing_transition_probabilities=True)
|
366
|
+
|
367
|
+
for t in cycle.graph.get_all_transitions():
|
368
|
+
# Transfer the fidelity score to the leaves, so that GM of the cycle would end up correct
|
369
|
+
t.contextual_fidelity = cycle_rationale.contextual_fidelity
|
370
|
+
cycles.append(cycle)
|
371
|
+
|
372
|
+
cycles.sort(key=lambda c: cast(Cycle, c).calculate_score(), reverse=True)
|
373
|
+
return cycles
|
374
|
+
|
375
|
+
@staticmethod
|
376
|
+
def _get_sequences(
|
377
|
+
thoughts: Union[list[str], list[WisdomUnit], list[DialecticalComponent]],
|
378
|
+
) -> list[list[DialecticalComponent]]:
|
379
|
+
if len(thoughts) == 0:
|
380
|
+
raise ValueError("No thoughts provided.")
|
381
|
+
|
382
|
+
if thoughts and isinstance(thoughts[0], WisdomUnit):
|
383
|
+
ordered_wisdom_units: list[WisdomUnit] = thoughts
|
384
|
+
return generate_compatible_sequences(ordered_wisdom_units)
|
385
|
+
else:
|
386
|
+
if isinstance(thoughts[0], DialecticalComponent):
|
387
|
+
dialectical_components = thoughts
|
388
|
+
else:
|
389
|
+
# TODO: We need to actualize the thesis using AI, so that we don't need to write 'Provided as string'
|
390
|
+
dialectical_components = [
|
391
|
+
DialecticalComponent(
|
392
|
+
alias=f"{ALIAS_T}{i + 1}",
|
393
|
+
statement=t,
|
394
|
+
# explanation="Provided as string.",
|
395
|
+
)
|
396
|
+
for i, t in enumerate(thoughts)
|
397
|
+
]
|
398
|
+
return generate_permutation_sequences(dialectical_components)
|
@@ -0,0 +1,55 @@
|
|
1
|
+
|
2
|
+
from mirascope import Messages, prompt_template
|
3
|
+
|
4
|
+
from dialectical_framework.synthesist.causality.causality_sequencer_balanced import \
|
5
|
+
CausalitySequencerBalanced
|
6
|
+
|
7
|
+
|
8
|
+
class CausalitySequencerDesirable(CausalitySequencerBalanced):
|
9
|
+
@prompt_template(
|
10
|
+
"""
|
11
|
+
USER:
|
12
|
+
Which of the following circular causality sequences is the most desirable, i.e. would produce optimal outcomes and maximum results (given that the final step cycles back to the first step):
|
13
|
+
{sequences:list}
|
14
|
+
|
15
|
+
<instructions>
|
16
|
+
For each sequence:
|
17
|
+
1) Estimate the numeric probability (0 to 1) regarding how beneficial/optimal this sequence would be if implemented
|
18
|
+
2) Explain why this sequence might occur (or already occurs) in reality
|
19
|
+
3) Describe circumstances or contexts where this sequence would be most applicable or useful
|
20
|
+
|
21
|
+
Only use the sequences **exactly as provided**, do not shorten, skip, collapse, or reorder steps.
|
22
|
+
</instructions>
|
23
|
+
|
24
|
+
<formatting>
|
25
|
+
- Output each circular causality sequence (cycle) as ordered aliases (technical placeholders) of statements as provided e.g. C1, C2, C3, ...
|
26
|
+
- In the explanations, for fluency, use explicit wording instead of aliases.
|
27
|
+
- Probability is a float between 0 and 1.
|
28
|
+
</formatting>
|
29
|
+
"""
|
30
|
+
)
|
31
|
+
def prompt_assess_multiple_sequences(
|
32
|
+
self, *, sequences: list[str]
|
33
|
+
) -> Messages.Type: ...
|
34
|
+
|
35
|
+
@prompt_template(
|
36
|
+
"""
|
37
|
+
USER:
|
38
|
+
Assess the following circular causality sequence considering desirability, i.e. producing optimal outcomes and maximum results (given that the final step cycles back to the first step):
|
39
|
+
{sequence}
|
40
|
+
|
41
|
+
<instructions>
|
42
|
+
1) Estimate the numeric probability (0 to 1) regarding how beneficial/optimal this sequence would be if implemented
|
43
|
+
2) Explain why this sequence might occur (or already occurs) in reality
|
44
|
+
3) Describe circumstances or contexts where this sequence would be most applicable or useful
|
45
|
+
|
46
|
+
- Only use the sequence **exactly as provided**, do not shorten, skip, collapse, or reorder steps.
|
47
|
+
</instructions>
|
48
|
+
|
49
|
+
<formatting>
|
50
|
+
- In the explanations and argumentation, for fluency, try to use explicit wording instead of technical aliases.
|
51
|
+
- Probability is a float between 0 and 1.
|
52
|
+
</formatting>
|
53
|
+
"""
|
54
|
+
)
|
55
|
+
def prompt_assess_single_sequence(self, *, sequence: str) -> Messages.Type: ...
|
@@ -0,0 +1,55 @@
|
|
1
|
+
|
2
|
+
from mirascope import Messages, prompt_template
|
3
|
+
|
4
|
+
from dialectical_framework.synthesist.causality.causality_sequencer_balanced import \
|
5
|
+
CausalitySequencerBalanced
|
6
|
+
|
7
|
+
|
8
|
+
class CausalitySequencerFeasible(CausalitySequencerBalanced):
|
9
|
+
@prompt_template(
|
10
|
+
"""
|
11
|
+
USER:
|
12
|
+
Which of the following circular causality sequences is the most feasible, i.e. best achievable with minimum resistance (given that the final step cycles back to the first step):
|
13
|
+
{sequences:list}
|
14
|
+
|
15
|
+
<instructions>
|
16
|
+
For each sequence:
|
17
|
+
1) Estimate the numeric probability (0 to 1) regarding how easily this sequence could be implemented given current constraints
|
18
|
+
2) Explain why this sequence might occur (or already occurs) in reality
|
19
|
+
3) Describe circumstances or contexts where this sequence would be most applicable or useful
|
20
|
+
|
21
|
+
Only use the sequences **exactly as provided**, do not shorten, skip, collapse, or reorder steps.
|
22
|
+
</instructions>
|
23
|
+
|
24
|
+
<formatting>
|
25
|
+
- Output each circular causality sequence (cycle) as ordered aliases (technical placeholders) of statements as provided e.g. C1, C2, C3, ...
|
26
|
+
- In the explanations, for fluency, use explicit wording instead of aliases.
|
27
|
+
- Probability is a float between 0 and 1.
|
28
|
+
</formatting>
|
29
|
+
"""
|
30
|
+
)
|
31
|
+
def prompt_assess_multiple_sequences(
|
32
|
+
self, *, sequences: list[str]
|
33
|
+
) -> Messages.Type: ...
|
34
|
+
|
35
|
+
@prompt_template(
|
36
|
+
"""
|
37
|
+
USER:
|
38
|
+
Assess the following circular causality sequence considering feasibility, i.e. best achievable with minimum resistance (given that the final step cycles back to the first step):
|
39
|
+
{sequence}
|
40
|
+
|
41
|
+
<instructions>
|
42
|
+
1) Estimate the numeric probability (0 to 1) regarding how easily this sequence could be implemented given current constraints
|
43
|
+
2) Explain why this sequence might occur (or already occurs) in reality
|
44
|
+
3) Describe circumstances or contexts where this sequence would be most applicable or useful
|
45
|
+
|
46
|
+
- Only use the sequence **exactly as provided**, do not shorten, skip, collapse, or reorder steps.
|
47
|
+
</instructions>
|
48
|
+
|
49
|
+
<formatting>
|
50
|
+
- In the explanations and argumentation, for fluency, try to use explicit wording instead of technical aliases.
|
51
|
+
- Probability is a float between 0 and 1.
|
52
|
+
</formatting>
|
53
|
+
"""
|
54
|
+
)
|
55
|
+
def prompt_assess_single_sequence(self, *, sequence: str) -> Messages.Type: ...
|
@@ -0,0 +1,56 @@
|
|
1
|
+
|
2
|
+
from mirascope import Messages, prompt_template
|
3
|
+
|
4
|
+
from dialectical_framework.synthesist.causality.causality_sequencer_balanced import \
|
5
|
+
CausalitySequencerBalanced
|
6
|
+
|
7
|
+
|
8
|
+
class CausalitySequencerRealistic(CausalitySequencerBalanced):
|
9
|
+
@prompt_template(
|
10
|
+
"""
|
11
|
+
USER:
|
12
|
+
Which of the following circular causality sequences is the most realistic, i.e. what typically happens in natural systems (given that the final step cycles back to the first step):
|
13
|
+
{sequences:list}
|
14
|
+
|
15
|
+
<instructions>
|
16
|
+
For each sequence:
|
17
|
+
1) Estimate the numeric probability (0 to 1) regarding its realistic existence in natural/existing systems
|
18
|
+
2) Explain why this sequence might occur (or already occurs) in reality
|
19
|
+
3) Describe circumstances or contexts where this sequence would be most applicable or useful
|
20
|
+
|
21
|
+
Only use the sequences **exactly as provided**, do not shorten, skip, collapse, or reorder steps.
|
22
|
+
</instructions>
|
23
|
+
|
24
|
+
|
25
|
+
<formatting>
|
26
|
+
- Output each circular causality sequence (cycle) as ordered aliases (technical placeholders) of statements as provided e.g. C1, C2, C3, ...
|
27
|
+
- In the explanations, for fluency, use explicit wording instead of aliases.
|
28
|
+
- Probability is a float between 0 and 1.
|
29
|
+
</formatting>
|
30
|
+
"""
|
31
|
+
)
|
32
|
+
def prompt_assess_multiple_sequences(
|
33
|
+
self, *, sequences: list[str]
|
34
|
+
) -> Messages.Type: ...
|
35
|
+
|
36
|
+
@prompt_template(
|
37
|
+
"""
|
38
|
+
USER:
|
39
|
+
Assess the following circular causality sequence for realism, i.e. what typically happens in natural systems (given that the final step cycles back to the first step):
|
40
|
+
{sequence}
|
41
|
+
|
42
|
+
<instructions>
|
43
|
+
1) Estimate the numeric probability (0 to 1) regarding its realistic existence in natural/existing systems
|
44
|
+
2) Explain why this sequence might occur (or already occurs) in reality
|
45
|
+
3) Describe circumstances or contexts where this sequence would be most applicable or useful
|
46
|
+
|
47
|
+
- Only use the sequence **exactly as provided**, do not shorten, skip, collapse, or reorder steps.
|
48
|
+
</instructions>
|
49
|
+
|
50
|
+
<formatting>
|
51
|
+
- In the explanations and argumentation, for fluency, try to use explicit wording instead of technical aliases.
|
52
|
+
- Probability is a float between 0 and 1.
|
53
|
+
</formatting>
|
54
|
+
"""
|
55
|
+
)
|
56
|
+
def prompt_assess_single_sequence(self, *, sequence: str) -> Messages.Type: ...
|
File without changes
|