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,111 @@
1
+ from abc import abstractmethod
2
+ from itertools import permutations
3
+ from typing import Union
4
+
5
+ from dialectical_framework.analyst.domain.cycle import Cycle
6
+ from dialectical_framework.dialectical_component import DialecticalComponent
7
+ from dialectical_framework.protocols.reloadable import Reloadable
8
+ from dialectical_framework.wisdom_unit import WisdomUnit
9
+
10
+
11
+ class CausalitySequencer(Reloadable):
12
+ @abstractmethod
13
+ async def arrange(
14
+ self, thoughts: Union[list[str], list[WisdomUnit], list[DialecticalComponent]]
15
+ ) -> list[Cycle]:
16
+ """
17
+ Arranges items in multiple sequences and arranges them as cycles.
18
+ IMPORTANT: we don't do single sequence estimation isolated, because they all depend on each other.
19
+ Isolated estimation would lead to some sort of unnormalized probabilities, which is not good.
20
+ """
21
+ ...
22
+
23
+
24
+ def generate_permutation_sequences(
25
+ dialectical_components: list[DialecticalComponent],
26
+ ) -> list[list[DialecticalComponent]]:
27
+ if len(dialectical_components) < 2:
28
+ return []
29
+
30
+ first, rest = dialectical_components[0], dialectical_components[1:]
31
+ sequences = list([first, *p] for p in permutations(rest))
32
+ return sequences
33
+
34
+
35
+ def generate_compatible_sequences(
36
+ ordered_wisdom_units: list[WisdomUnit],
37
+ ) -> list[list[DialecticalComponent]]:
38
+ """
39
+ Generate all circular, diagonally symmetric arrangements for T/A pairs.
40
+
41
+ Each wisdom unit consists of a thesis (`T`) and its antithesis (`A`). This function arranges them
42
+ around a circle (of length 2n, where n is the number of units) such that:
43
+
44
+ 1. **Circular Symmetry**: For each pair, if `T_i` is at position `p`, then `A_i` is at position `(p + n) % (2n)`.
45
+ 2. **Order Preservation**: The order of all `T`s matches their input order and is strictly increasing
46
+ in placement (i.e., `T1` before `T2`, etc.).
47
+ 3. **Start Condition**: The sequence always starts with the first thesis (`T1`) at position 0.
48
+
49
+ Parameters:
50
+ ordered_wisdom_units (list): List of wisdom units, each having `.t.alias` (thesis) and `.a.alias` (antithesis).
51
+
52
+ Returns:
53
+ list of list: Each inner list is a possible arrangement; positions 0..n-1 represent the 'top row'
54
+ (or first semi-circle), and positions n..2n-1 represent the 'bottom row' (or mirrored second semi-circle),
55
+ such that the diagonal relationship and thesis order constraints are always met.
56
+
57
+ Example:
58
+ For input units T1/A1, T2/A2, T3/A3, T4/A4, a valid output can be:
59
+ [T1, T2, A4, T3, A1, A2, T4, A3]
60
+ Which means:
61
+ Top: T1 -> T2 -> A4 -> T3
62
+ Bottom: A1 -> A2 -> T4 -> A3 (mirrored on the circle)
63
+ """
64
+
65
+ n = len(ordered_wisdom_units)
66
+ ts = [u.t for u in ordered_wisdom_units]
67
+ as_ = [u.a for u in ordered_wisdom_units]
68
+ size = 2 * n
69
+
70
+ results = []
71
+
72
+ # Step 1: set T1 at 0, its diagonal A1 at n
73
+ def backtrack(t_positions, next_t_idx):
74
+ if next_t_idx == n:
75
+ # Fill arrangement based on t_positions
76
+ arrangement = [None] * size
77
+ occupied = set()
78
+ for t_idx, pos in enumerate(t_positions):
79
+ arrangement[pos] = ts[t_idx]
80
+ diag = (pos + n) % size
81
+ arrangement[diag] = as_[t_idx]
82
+ occupied.add(pos)
83
+ occupied.add(diag)
84
+ results.append(arrangement)
85
+ return
86
+
87
+ # Next ti to place: always in order, always > previous ti's position
88
+ # Skip positions already assigned (to ensure symmetry and distinctness)
89
+ prev_pos = t_positions[-1]
90
+ for pos in range(prev_pos + 1, size):
91
+ diag = (pos + n) % size
92
+
93
+ # Check if pos or diag are used by previous Ts/A's
94
+ collision = False
95
+ for prev_t_pos in t_positions:
96
+ if pos == prev_t_pos or diag == prev_t_pos:
97
+ collision = True
98
+ break
99
+ prev_diag = (prev_t_pos + n) % size
100
+ if pos == prev_diag or diag == prev_diag:
101
+ collision = True
102
+ break
103
+ if collision:
104
+ continue
105
+
106
+ # Place next T at pos, corresponding A at diag
107
+ backtrack(t_positions + [pos], next_t_idx + 1)
108
+
109
+ # T1 fixed at position 0
110
+ backtrack([0], 1)
111
+ return results
@@ -0,0 +1,16 @@
1
+ from abc import abstractmethod
2
+ from typing import Union
3
+
4
+
5
+ from dialectical_framework.dialectical_component import DialecticalComponent
6
+ from dialectical_framework.protocols.reloadable import Reloadable
7
+ from dialectical_framework.wheel import Wheel
8
+ from dialectical_framework.wheel_segment import WheelSegment
9
+
10
+
11
+ class ContentFidelityEvaluator(Reloadable):
12
+ @abstractmethod
13
+ async def evaluate(self, *, target: Union[
14
+ list[str | DialecticalComponent | WheelSegment | Wheel],
15
+ str, DialecticalComponent, WheelSegment, Wheel
16
+ ]) -> DialecticalComponent: ...
@@ -0,0 +1,18 @@
1
+ from typing import Protocol, runtime_checkable
2
+
3
+ from dependency_injector.wiring import Provide, inject
4
+
5
+ from dialectical_framework.brain import Brain
6
+ from dialectical_framework.enums.di import DI
7
+
8
+
9
+ @inject
10
+ def di_brain(brain: Brain = Provide[DI.brain]) -> Brain:
11
+ return brain
12
+
13
+
14
+ @runtime_checkable
15
+ class HasBrain(Protocol):
16
+ @property
17
+ def brain(self) -> Brain:
18
+ return di_brain()
@@ -0,0 +1,18 @@
1
+ from typing import Protocol, runtime_checkable
2
+
3
+ from dependency_injector.wiring import Provide, inject
4
+
5
+ from dialectical_framework.enums.di import DI
6
+ from dialectical_framework.settings import Settings
7
+
8
+
9
+ @inject
10
+ def di_settings(settings: Settings = Provide[DI.settings]) -> Settings:
11
+ return settings
12
+
13
+
14
+ @runtime_checkable
15
+ class SettingsAware(Protocol):
16
+ @property
17
+ def settings(self) -> Settings:
18
+ return di_settings()
@@ -0,0 +1,79 @@
1
+ from __future__ import annotations
2
+
3
+ from abc import ABC
4
+ from typing import TYPE_CHECKING, final, List
5
+
6
+ from pydantic import ConfigDict, Field
7
+
8
+ from dialectical_framework.protocols.assessable import Assessable
9
+ from dialectical_framework.utils.gm import gm_with_zeros_and_nones_handled
10
+
11
+ if TYPE_CHECKING: # Conditionally import Rationale for type checking only
12
+ pass
13
+
14
+ class Ratable(Assessable, ABC):
15
+ model_config = ConfigDict(
16
+ arbitrary_types_allowed=True,
17
+ )
18
+
19
+ rating: float | None = Field(
20
+ default=None, ge=0.0, le=1.0,
21
+ description="Importance/quality rating."
22
+ )
23
+
24
+ confidence: float | None = Field(
25
+ default=None, ge=0.0, le=1.0,
26
+ description="Credibility/reputation/confidence of the expert making probability assessments. Used for weighing probabilities (applied during aggregation)")
27
+
28
+ def rating_or_default(self) -> float:
29
+ """
30
+ The default rating is 1.0 when None.
31
+ It's a convenient thing, this way we can estimate higher level CFs and propagate them up and down.
32
+ """
33
+ return self.rating if self.rating is not None else 1.0
34
+
35
+ def confidence_or_default(self) -> float:
36
+ """
37
+ The default confidence is 0.5 when None. This is a rather technical thing, we are never 100% sure, so 0.5 is ok.
38
+ """
39
+ return self.confidence if self.confidence is not None else 0.5
40
+
41
+ def _hard_veto_on_own_zero(self) -> bool:
42
+ return True # default for DC and Transition
43
+
44
+ def calculate_contextual_fidelity(self, *, mutate: bool = True) -> float:
45
+ """
46
+ Leaves combine:
47
+ - own intrinsic CF × own rating (if present; 0 may be a hard veto by policy),
48
+ - rated rationale CFs (weighted in the base helper),
49
+ - any subclass sub-elements (e.g., Rationale's wheels), unrated here.
50
+ Neutral fallback = 1.0. Parent rating never reweights children.
51
+ """
52
+ own_cf = self.contextual_fidelity
53
+ own_rating = self.rating_or_default()
54
+
55
+ # 1) Hard veto on intrinsic CF == 0, independent of rating (policy-controlled)
56
+ if own_cf is not None and own_cf == 0.0 and self._hard_veto_on_own_zero():
57
+ # Do NOT overwrite the manual CF field; return veto as the effective value
58
+ return 0.0
59
+
60
+ # 2) Collect child contributions (already filtered/weighted by helpers)
61
+ parts: List[float] = []
62
+ parts.extend(v for v in (self._calculate_contextual_fidelity_for_rationales(mutate=mutate) or [])
63
+ if v is not None and v > 0.0)
64
+ parts.extend(
65
+ v for v in (self._calculate_contextual_fidelity_for_sub_elements_excl_rationales(mutate=mutate) or [])
66
+ if v is not None and v > 0.0)
67
+
68
+ # 3) Include own positive contribution if present
69
+ if own_cf is not None and own_cf > 0.0 and own_rating > 0.0:
70
+ parts.append(own_cf * own_rating)
71
+
72
+ # 4) Aggregate or neutral fallback
73
+ fidelity = gm_with_zeros_and_nones_handled(parts) if parts else 1.0
74
+
75
+ # 5) Cache only if there was no manual CF provided (don't clobber human input)
76
+ if mutate and own_cf is None:
77
+ self.contextual_fidelity = fidelity
78
+
79
+ return fidelity
@@ -0,0 +1,7 @@
1
+ from abc import ABC, abstractmethod
2
+ from typing import Self
3
+
4
+
5
+ class Reloadable(ABC):
6
+ @abstractmethod
7
+ def reload(self, **kwargs) -> Self: ...
@@ -0,0 +1,15 @@
1
+ from abc import abstractmethod
2
+
3
+
4
+ from dialectical_framework.dialectical_component import DialecticalComponent
5
+ from dialectical_framework.dialectical_components_deck import \
6
+ DialecticalComponentsDeck
7
+ from dialectical_framework.protocols.reloadable import Reloadable
8
+
9
+
10
+ class ThesisExtractor(Reloadable):
11
+ @abstractmethod
12
+ async def extract_multiple_theses( self, *, count: int = 2) -> DialecticalComponentsDeck: ...
13
+
14
+ @abstractmethod
15
+ async def extract_single_thesis(self) -> DialecticalComponent: ...
@@ -0,0 +1,77 @@
1
+ from __future__ import annotations
2
+
3
+ import os
4
+ from typing import Optional, Self
5
+
6
+ from dotenv import load_dotenv
7
+ from pydantic import BaseModel, ConfigDict, Field
8
+
9
+ from dialectical_framework.enums.causality_type import CausalityType
10
+
11
+
12
+ class Settings(BaseModel):
13
+ model_config = ConfigDict(
14
+ arbitrary_types_allowed=True,
15
+ )
16
+
17
+ ai_model: str = Field(..., description="AI model alias/deployment to use.")
18
+ ai_provider: Optional[str] = Field(default=None, description="AI model provider to use.")
19
+ component_length: int = Field(default=7, description="Approximate length in words of the dialectical component.")
20
+ causality_type: CausalityType = Field(default=CausalityType.BALANCED, description="Type of causality in the wheel.")
21
+
22
+ @classmethod
23
+ def from_partial(cls, partial_settings: Optional[Settings] = None) -> Self:
24
+ """
25
+ Create GenerationSettings by merging partial settings with environment defaults.
26
+ Missing fields in partial_settings are filled from Settings.from_env().
27
+ """
28
+ if partial_settings is None:
29
+ return cls.from_env()
30
+
31
+ # Get full defaults from environment
32
+ env_defaults = cls.from_env()
33
+
34
+ # Convert partial_settings to dict, excluding None values
35
+ partial_dict = partial_settings.model_dump(exclude_none=True) if partial_settings else {}
36
+
37
+ # Convert env_defaults to dict
38
+ env_dict = env_defaults.model_dump()
39
+
40
+ # Merge: partial_settings override env_defaults
41
+ merged_dict = {**env_dict, **partial_dict}
42
+
43
+ # Create new instance from merged data
44
+ return cls(**merged_dict)
45
+
46
+ @classmethod
47
+ def from_env(cls) -> Self:
48
+ """
49
+ Static method to set up and return a Config instance.
50
+ It uses environment variables or hardcoded defaults for configuration.
51
+ """
52
+ load_dotenv()
53
+
54
+ model = os.getenv("DIALEXITY_DEFAULT_MODEL", None)
55
+ provider = os.getenv("DIALEXITY_DEFAULT_MODEL_PROVIDER", None)
56
+ missing = []
57
+ if not model:
58
+ missing.append("DIALEXITY_DEFAULT_MODEL")
59
+ if not provider:
60
+ if "/" not in model:
61
+ missing.append("DIALEXITY_DEFAULT_MODEL_PROVIDER")
62
+ else:
63
+ # We will give litellm a chance to derive the provider from the model
64
+ pass
65
+ if missing:
66
+ raise ValueError(
67
+ f"Missing required environment variables: {', '.join(missing)}"
68
+ )
69
+
70
+ return cls(
71
+ ai_model=model,
72
+ ai_provider=provider,
73
+ component_length=int(os.getenv("DIALEXITY_DEFAULT_COMPONENT_LENGTH", 7)),
74
+ causality_type=CausalityType(
75
+ os.getenv("DIALEXITY_DEFAULT_CAUSALITY_TYPE", CausalityType.BALANCED.value)
76
+ ),
77
+ )
@@ -0,0 +1,7 @@
1
+ from dialectical_framework.wheel_segment import WheelSegment
2
+
3
+ ALIAS_S_PLUS = "S+"
4
+ ALIAS_S_MINUS = "S-"
5
+
6
+
7
+ class Synthesis(WheelSegment): ...
File without changes