dialectical-framework 1.6.0__tar.gz → 1.6.1__tar.gz

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 (191) hide show
  1. dialectical_framework-1.6.1/PKG-INFO +178 -0
  2. dialectical_framework-1.6.1/README.md +137 -0
  3. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/pyproject.toml +1 -1
  4. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/agents/advisor/system_prompts.py +14 -5
  5. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/agents/analyst/analyst.py +5 -1
  6. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/agents/analyst/skills/anchor_theses.py +20 -5
  7. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/agents/analyst/skills/find_polarities.py +1 -0
  8. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/agents/analyst/skills/introduce_polarity.py +39 -13
  9. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/agents/analyst/skills/surface_theses.py +1 -0
  10. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/agents/analyst/system_prompts.py +8 -0
  11. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/agents/execution_report.py +14 -2
  12. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/agents/explorer/explorer.py +12 -5
  13. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/agents/explorer/system_prompts.py +54 -0
  14. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/agents/orchestrator/tools/get_schema.py +2 -2
  15. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/agents/orchestrator/tools/query_graph.py +4 -4
  16. dialectical_framework-1.6.1/src/dialectical_framework/concerns/statement_headline.py +129 -0
  17. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/concerns/thesis_extraction.py +18 -0
  18. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/events/graph_event.py +1 -1
  19. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/events/graph_event_bus.py +1 -1
  20. dialectical_framework-1.6.0/PKG-INFO +0 -167
  21. dialectical_framework-1.6.0/README.md +0 -126
  22. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/LICENSE +0 -0
  23. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/__init__.py +0 -0
  24. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/agents/__init__.py +0 -0
  25. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/agents/advisor/__init__.py +0 -0
  26. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/agents/advisor/advisor.py +0 -0
  27. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/agents/advisor/tools/__init__.py +0 -0
  28. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/agents/advisor/tools/anchor.py +0 -0
  29. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/agents/advisor/tools/explore.py +0 -0
  30. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/agents/advisor/tools/ingest.py +0 -0
  31. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/agents/advisor/tools/sync.py +0 -0
  32. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/agents/agent_context.py +0 -0
  33. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/agents/analyst/__init__.py +0 -0
  34. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/agents/analyst/skills/__init__.py +0 -0
  35. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/agents/analyst/skills/edit_perspective.py +0 -0
  36. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/agents/analyst/skills/expand_polarities.py +0 -0
  37. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/agents/analyst/tools/__init__.py +0 -0
  38. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/agents/analyst/tools/create_dx_input.py +0 -0
  39. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/agents/analyst/tools/place_statement.py +0 -0
  40. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/agents/apps.py +0 -0
  41. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/agents/conversation_facilitator.py +0 -0
  42. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/agents/explorer/__init__.py +0 -0
  43. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/agents/explorer/skills/__init__.py +0 -0
  44. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/agents/explorer/skills/build_wheels.py +0 -0
  45. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/agents/explorer/skills/explore_transformations.py +0 -0
  46. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/agents/explorer/skills/generate_synthesis.py +0 -0
  47. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/agents/explorer/tools/__init__.py +0 -0
  48. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/agents/explorer/tools/create_nexus.py +0 -0
  49. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/agents/explorer/tools/expand_nexus.py +0 -0
  50. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/agents/explorer/tools/generate_synthesis.py +0 -0
  51. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/agents/explorer/tools/present_exploration.py +0 -0
  52. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/agents/orchestrator/__init__.py +0 -0
  53. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/agents/orchestrator/tools/__init__.py +0 -0
  54. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/agents/orchestrator/tools/add_input.py +0 -0
  55. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/agents/orchestrator/tools/digest_input.py +0 -0
  56. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/agents/orchestrator/tools/discard.py +0 -0
  57. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/agents/orchestrator/tools/inspect_node.py +0 -0
  58. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/agents/orchestrator/tools/present_analysis.py +0 -0
  59. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/agents/orchestrator/tools/read_digest.py +0 -0
  60. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/agents/orchestrator/tools/read_input.py +0 -0
  61. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/agents/reasonable_concern.py +0 -0
  62. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/agents/stream_events.py +0 -0
  63. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/concerns/__init__.py +0 -0
  64. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/concerns/ac_re_taxonomy.py +0 -0
  65. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/concerns/action_extraction.py +0 -0
  66. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/concerns/add_input.py +0 -0
  67. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/concerns/ai_dto/__init__.py +0 -0
  68. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/concerns/ai_dto/statement_dto.py +0 -0
  69. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/concerns/ai_dto/statements_deck_dto.py +0 -0
  70. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/concerns/antithesis_classification.py +0 -0
  71. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/concerns/antithesis_extraction.py +0 -0
  72. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/concerns/aspect_classification.py +0 -0
  73. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/concerns/aspect_generation.py +0 -0
  74. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/concerns/causality/__init__.py +0 -0
  75. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/concerns/causality/causality_estimator.py +0 -0
  76. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/concerns/causality/causality_estimator_balanced.py +0 -0
  77. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/concerns/causality/causality_estimator_criteria.py +0 -0
  78. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/concerns/causality/causality_estimator_desirable.py +0 -0
  79. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/concerns/causality/causality_estimator_feasible.py +0 -0
  80. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/concerns/causality/causality_estimator_realistic.py +0 -0
  81. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/concerns/causality/causality_normalizer.py +0 -0
  82. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/concerns/causality/estimator_resolver.py +0 -0
  83. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/concerns/causality_estimation.py +0 -0
  84. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/concerns/control_statements_check.py +0 -0
  85. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/concerns/create_dx_input.py +0 -0
  86. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/concerns/create_nexus.py +0 -0
  87. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/concerns/diagonal_oppositions_check.py +0 -0
  88. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/concerns/dialectical_context.py +0 -0
  89. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/concerns/discard.py +0 -0
  90. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/concerns/display_text_edit.py +0 -0
  91. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/concerns/expand_nexus.py +0 -0
  92. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/concerns/perspective_combination.py +0 -0
  93. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/concerns/perspective_validation.py +0 -0
  94. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/concerns/positive_ac_re_apex_derivation.py +0 -0
  95. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/concerns/scoring_scales.py +0 -0
  96. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/concerns/source_digest.py +0 -0
  97. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/concerns/statement_classification.py +0 -0
  98. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/concerns/statement_deduplication.py +0 -0
  99. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/concerns/statement_placement.py +0 -0
  100. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/concerns/synthesis_generation.py +0 -0
  101. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/concerns/transformation_audit.py +0 -0
  102. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/concerns/transformation_generation.py +0 -0
  103. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/dialectical_reasoning.py +0 -0
  104. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/enums/__init__.py +0 -0
  105. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/enums/causality_preset.py +0 -0
  106. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/enums/di.py +0 -0
  107. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/events/__init__.py +0 -0
  108. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/exceptions/__init__.py +0 -0
  109. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/exceptions/node_errors.py +0 -0
  110. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/exceptions/resolver_errors.py +0 -0
  111. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/graph/__init__.py +0 -0
  112. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/graph/composite_input_resolver.py +0 -0
  113. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/graph/dialexity_input_resolver.py +0 -0
  114. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/graph/estimation_manager.py +0 -0
  115. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/graph/mixins/__init__.py +0 -0
  116. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/graph/mixins/incremental_build_mixin.py +0 -0
  117. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/graph/mixins/intent_mixin.py +0 -0
  118. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/graph/mixins/persistable_mixin.py +0 -0
  119. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/graph/nodes/__init__.py +0 -0
  120. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/graph/nodes/assessable_entity.py +0 -0
  121. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/graph/nodes/base_node.py +0 -0
  122. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/graph/nodes/case.py +0 -0
  123. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/graph/nodes/cycle.py +0 -0
  124. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/graph/nodes/estimation.py +0 -0
  125. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/graph/nodes/ideas.py +0 -0
  126. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/graph/nodes/input.py +0 -0
  127. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/graph/nodes/nexus.py +0 -0
  128. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/graph/nodes/perspective.py +0 -0
  129. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/graph/nodes/polarity.py +0 -0
  130. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/graph/nodes/rationale.py +0 -0
  131. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/graph/nodes/statement.py +0 -0
  132. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/graph/nodes/synthesis.py +0 -0
  133. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/graph/nodes/transformation.py +0 -0
  134. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/graph/nodes/transition.py +0 -0
  135. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/graph/nodes/wheel.py +0 -0
  136. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/graph/relationship_manager.py +0 -0
  137. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/graph/relationships/__init__.py +0 -0
  138. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/graph/relationships/action_reflection_relationship.py +0 -0
  139. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/graph/relationships/belongs_to_cycle_relationship.py +0 -0
  140. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/graph/relationships/belongs_to_nexus_relationship.py +0 -0
  141. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/graph/relationships/changed_to_relationship.py +0 -0
  142. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/graph/relationships/contradiction_of_relationship.py +0 -0
  143. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/graph/relationships/critiques_relationship.py +0 -0
  144. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/graph/relationships/distilled_to_relationship.py +0 -0
  145. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/graph/relationships/estimates_relationship.py +0 -0
  146. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/graph/relationships/explains_relationship.py +0 -0
  147. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/graph/relationships/has_input_relationship.py +0 -0
  148. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/graph/relationships/has_statement_relationship.py +0 -0
  149. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/graph/relationships/has_wheel_relationship.py +0 -0
  150. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/graph/relationships/immutable_structure.py +0 -0
  151. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/graph/relationships/is_source_of_relationship.py +0 -0
  152. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/graph/relationships/is_target_of_relationship.py +0 -0
  153. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/graph/relationships/negative_side_of_relationship.py +0 -0
  154. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/graph/relationships/opposite_direction_relationship.py +0 -0
  155. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/graph/relationships/opposite_of_relationship.py +0 -0
  156. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/graph/relationships/polarity_relationship.py +0 -0
  157. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/graph/relationships/positive_side_of_relationship.py +0 -0
  158. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/graph/relationships/provides_relationship.py +0 -0
  159. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/graph/relationships/synthesis_of_relationship.py +0 -0
  160. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/graph/rendering.py +0 -0
  161. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/graph/repositories/__init__.py +0 -0
  162. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/graph/repositories/case_repository.py +0 -0
  163. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/graph/repositories/cycle_repository.py +0 -0
  164. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/graph/repositories/input_repository.py +0 -0
  165. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/graph/repositories/nexus_repository.py +0 -0
  166. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/graph/repositories/node_repository.py +0 -0
  167. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/graph/repositories/perspective_repository.py +0 -0
  168. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/graph/repositories/polarity_repository.py +0 -0
  169. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/graph/repositories/schema_repository.py +0 -0
  170. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/graph/repositories/statement_repository.py +0 -0
  171. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/graph/repositories/transformation_repository.py +0 -0
  172. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/graph/repositories/wheel_repository.py +0 -0
  173. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/graph/scope_context.py +0 -0
  174. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/graph/verbatim_input_resolver.py +0 -0
  175. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/graph/wheel_segment.py +0 -0
  176. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/graph/wheel_segment_polar_pair.py +0 -0
  177. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/protocols/__init__.py +0 -0
  178. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/protocols/has_config.py +0 -0
  179. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/protocols/input_resolver.py +0 -0
  180. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/settings.py +0 -0
  181. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/utils/__init__.py +0 -0
  182. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/utils/bedrock_provider.py +0 -0
  183. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/utils/concurrency.py +0 -0
  184. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/utils/dc_replace.py +0 -0
  185. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/utils/decompose_probability_uniformly.py +0 -0
  186. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/utils/edge_context.py +0 -0
  187. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/utils/effect_logger.py +0 -0
  188. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/utils/input_context.py +0 -0
  189. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/utils/order_transitions.py +0 -0
  190. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/utils/sequence_generation.py +0 -0
  191. {dialectical_framework-1.6.0 → dialectical_framework-1.6.1}/src/dialectical_framework/utils/use_brain.py +0 -0
@@ -0,0 +1,178 @@
1
+ Metadata-Version: 2.3
2
+ Name: dialectical-framework
3
+ Version: 1.6.1
4
+ Summary: A dialectical framework for augmented intelligence. AI reasoning powered with dialectics supports humans in: system optimization (psychology, engineering, business, politics, etc.); dispute resolution (mediation, conflicts, negotiations, etc.); decision-making (dilemmas, challenging situations, win-win, etc.).
5
+ License: MIT
6
+ Keywords: dialectics,dialectical-reasoning,synthesis,thesis-antithesis,ai,artificial-intelligence,llm,reasoning-framework,philosophy,logic,argumentation,conflict-resolution,decision-making,critical-thinking,semantic-graph,mirascope,pydantic,perspectives,polarity-reasoning
7
+ Author: Evaldas Taroza
8
+ Author-email: evaldas@dialexity.com
9
+ Requires-Python: >=3.11,<4.0
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Environment :: Console
12
+ Classifier: Framework :: Pydantic
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Intended Audience :: Education
15
+ Classifier: Intended Audience :: Science/Research
16
+ Classifier: License :: OSI Approved :: MIT License
17
+ Classifier: Natural Language :: English
18
+ Classifier: Operating System :: OS Independent
19
+ Classifier: Programming Language :: Python :: 3
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Programming Language :: Python :: 3.13
23
+ Classifier: Topic :: Education
24
+ Classifier: Topic :: Office/Business :: Financial :: Investment
25
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
26
+ Classifier: Topic :: Scientific/Engineering :: Human Machine Interfaces
27
+ Classifier: Topic :: Sociology
28
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
29
+ Classifier: Topic :: Text Processing :: Linguistic
30
+ Requires-Dist: boto3 (>=1.43.4,<2.0.0)
31
+ Requires-Dist: broadcaster (>=0.3.1,<0.4.0)
32
+ Requires-Dist: dependency-injector (>=4.48.2,<5.0.0)
33
+ Requires-Dist: gqlalchemy (>=1.8.0,<2.0.0)
34
+ Requires-Dist: langfuse (>=4.5.1,<5.0.0)
35
+ Requires-Dist: mirascope[anthropic,openai,ops] (>=2.5.0,<3.0.0)
36
+ Requires-Dist: python-dotenv (>=1.2.1,<2.0.0)
37
+ Requires-Dist: tabulate (>=0.9.0,<0.10.0)
38
+ Project-URL: Homepage, https://github.com/dialexity/dialectical-framework
39
+ Project-URL: Repository, https://github.com/dialexity/dialectical-framework
40
+ Description-Content-Type: text/markdown
41
+
42
+ # Dialectical Framework
43
+
44
+ **Make an LLM reason in oppositions, not averages.**
45
+
46
+ Ask a model a hard question and it tends to collapse the tension into one confident answer — or hedge with a bland "on one hand… on the other." This framework does neither. For every thesis it generates a genuine antithesis, maps precisely where each side overreaches (T-, A-) and where it constructively balances the other (T+, A+), and drives the pair toward a **synthesis** — not a compromise, but a new quality that emerges from their circular causality and that neither pole held alone.
47
+
48
+ The reasoning lives in a graph. Every move — surfacing a thesis, finding its opposition, developing its four aspects, arranging them into a **Wheel** — writes semantic, rule-validated nodes and edges into a graph database. The graph **is** the state: a persistent, compounding map of how a domain's tensions resolve, that any application can query, visualize, or build on.
49
+
50
+ And the synthesis is *earned*, not asserted. Where "think step by step" leaves rigor to chance, formal generative rules define what counts as valid: exactly one antithesis per thesis, modality kept in balance, and positive synthesis (S+) only when T-'s excess transforms into A+ and A-'s into T+. The structure enforces a discipline the prompt alone can't.
51
+
52
+ ## Learn More
53
+ - [Structured Dialectics](https://dialexity.com/blog/structured-dialectics-consolidated-manuscript/) - the theory
54
+ - [Dialectical Wheels for Systems Optimization](https://dialexity.com/blog/dialectical-wheels-for-systems-optimization/)
55
+ - [Dialectical Ethics](https://dialexity.com/blog/dialectical-ethics/)
56
+
57
+
58
+ ## How It Works
59
+
60
+ 1. **Input** — text, URLs, or raw ideas from any domain
61
+ 2. **Analysis** — extract the theses, find each one's true antithesis, develop the four aspects (T+, T-, A+, A-) that say where each side helps and where it overreaches
62
+ 3. **Graph curation** — commit every insight as content-addressed, rule-validated nodes and edges — nothing is stored until it holds up
63
+ 4. **Exploration** — combine perspectives into Cycles, arrange them into Wheels, and trace the Transformations whose circular causality yields synthesis
64
+
65
+ Each pass leaves the graph richer than it found it: new tensions enter an existing web of validated reasoning, so understanding compounds instead of resetting every prompt.
66
+
67
+ ## Architecture
68
+
69
+ ```
70
+ Host Application (Chainlit, API, CLI)
71
+
72
+
73
+ Agent: Analyst · Explorer · Advisor (LLM + tools)
74
+
75
+
76
+ Graph Database (Memgraph / Neo4j)
77
+ ```
78
+
79
+ An **agent** is the entry point — a thin LLM orchestrator that manages a conversation with tools that read and write the graph. There are three (Analyst, Explorer, Advisor); each owns a tool set and a domain-neutral reasoning prompt. The host app controls persona (via the app preamble) and scope identity (`sid`); the framework handles reasoning and graph curation. See [docs/agents.md](docs/agents.md).
80
+
81
+ ### Docs
82
+ - [Agents: Analyst, Explorer, Advisor](docs/agents.md) — the building blocks, their tools, and the UX to build around them
83
+ - [Graph Data Model](docs/graph.md)
84
+ - [Scoring & Metrics](docs/scoring.md)
85
+
86
+ ## Why a Reasoning Graph
87
+
88
+ Most AI systems treat knowledge as flat context — dump text into the prompt and hope the LLM figures out the structure. The dialectical framework builds a **persistent reasoning graph** where the structure itself encodes how to think about a domain:
89
+
90
+ - **Oppositions are explicit.** The LLM doesn't rediscover the tensions on every call — they persist as typed T/A pairs, so reasoning starts from a mapped conflict instead of a blank page.
91
+ - **Transformations encode causality.** Edges don't just connect — they show how one position's failure becomes another's strength. This is the circular causality that drives synthesis.
92
+ - **Quality is measurable.** Complementarity, modality balance, area metrics tell the LLM which reasoning paths are well-developed and which are thin — no guessing about confidence.
93
+ - **Knowledge compounds.** Each new perspective enters an existing graph of validated reasoning. The LLM builds on prior synthesis rather than re-deriving from scratch.
94
+
95
+ The result: an LLM with this graph in context doesn't just have facts about a topic — it has the intellectual terrain mapped. What opposes what, where balance was achieved, what assumptions remain untested, and where synthesis is possible.
96
+
97
+ This is the [LLM Wiki](https://gist.github.com/karpathy/442a6bf555914893e9891c11519de94f) pattern realized as a semantic graph rather than a pile of markdown files — knowledge that is structured, rule-validated, and queryable by reasoning topology.
98
+
99
+ | Simple | Detailed |
100
+ |--------|----------|
101
+ | ![Wheel](https://raw.githubusercontent.com/dialexity/dialectical-framework/main/docs/wheel-scheme.png) | ![Wheel](https://raw.githubusercontent.com/dialexity/dialectical-framework/main/docs/wheel-scheme2.png) |
102
+
103
+ ## Core Graph Structure
104
+
105
+ It's all one graph. **Statements** are the atoms; typed edges carry the dialectical relationships — opposition, complementarity, transformation — and each structure below composes the ones above it into progressively richer reasoning, culminating in the **Dialectical Wheel**.
106
+
107
+ | Structure | Role |
108
+ |-----------|------|
109
+ | **Statement** | Atomic unit of meaning — a thesis, position, or claim |
110
+ | **Polarity** | A single T↔A tension (thesis vs. antithesis); reusable across perspectives |
111
+ | **Perspective** | A full tetrad — a Polarity developed with its four aspects (T+, T-, A+, A-) |
112
+ | **Nexus** | A working set of Perspectives grouped for exploration |
113
+ | **Cycle** | An ordered sequence of Perspectives — which tension drives which |
114
+ | **Wheel** | A concrete circular arrangement of a Cycle, with the edges between components |
115
+ | **Transition** | A directed edge between two components — one step around the Wheel |
116
+ | **Transformation** | The Action-Reflection paths on an edge that turn one pole's excess into the other's strength |
117
+ | **Synthesis** | The emergent S+/S- arising from the whole Wheel's circular causality |
118
+
119
+ Picture the Wheel as a pizza sliced into segments: each **segment** bundles a component with its plus and minus (e.g. T, T+, T-), a **Perspective** joins a thesis segment with the antithesis segment directly across from it, and **Transitions** are the arrows running segment to segment around the rim.
120
+
121
+ ## Integration
122
+
123
+ Wherever the answer is a tension rather than a fact, this drops in as the reasoning engine: decision support that weighs both sides, systems thinking, mediation between opposed positions, ethical modeling. You wire it into your app through three conversational agents — the main building blocks:
124
+
125
+ - **Analyst** — turns raw material into structured tensions, up to grouping them into a Nexus (Case-scoped).
126
+ - **Explorer** — takes one Nexus and works out its causal pathways and synthesis (Nexus-scoped).
127
+ - **Advisor** — runs the whole machine silently and returns pure counsel, with no framework vocabulary exposed (Case-scoped).
128
+
129
+ Analyst + Explorer are the structure-forward "graph navigator" experience; the Advisor is a chat-only product over the same graph. See [docs/agents.md](docs/agents.md) for full specs, tool lists, and the UX to build around each.
130
+
131
+ ```python
132
+ from dialectical_framework.dialectical_reasoning import DialecticalReasoning
133
+ from dialectical_framework.settings import Settings
134
+ from dialectical_framework.graph.nodes.case import Case
135
+ from dialectical_framework.graph.scope_context import scope
136
+ from dialectical_framework.agents.advisor.advisor import Advisor
137
+
138
+ # Initialize once
139
+ DialecticalReasoning.setup(Settings.from_env())
140
+
141
+ # A Case owns the scope id (sid); all graph writes are sid-scoped.
142
+ case = Case(); case.commit()
143
+
144
+ with scope(case.sid):
145
+ advisor = Advisor(app_preamble="You are a systems thinking coach...")
146
+ async for event in advisor.chat_stream("Analyze the tension between growth and sustainability"):
147
+ # ThinkingDelta, TextDelta, ToolStart, ToolResult, ResponseComplete
148
+ handle(event)
149
+ ```
150
+
151
+ ## Setup
152
+
153
+ ### Requirements
154
+
155
+ - Python 3.11+
156
+ - Memgraph or Neo4j
157
+ - An LLM provider (OpenAI, Anthropic, or Bedrock via a custom Mirascope provider)
158
+
159
+ ### Install
160
+
161
+ ```bash
162
+ poetry install
163
+ cp .env.example .env # then fill in the values (see .env.example for details)
164
+ ```
165
+
166
+ ### Run Tests
167
+
168
+ ```bash
169
+ poetry run pytest # All tests (LLM mocked)
170
+ poetry run pytest -m llm # Only LLM-path tests (mocked)
171
+ poetry run pytest --real-llm # Hit real LLM provider
172
+ ```
173
+
174
+ ## Built With
175
+
176
+ - [Mirascope](https://mirascope.com/) — LLM abstraction
177
+ - [GQLAlchemy](https://memgraph.com/docs/gqlalchemy) — Graph ORM
178
+ - [dependency-injector](https://python-dependency-injector.ets-labs.org/) — DI container
@@ -0,0 +1,137 @@
1
+ # Dialectical Framework
2
+
3
+ **Make an LLM reason in oppositions, not averages.**
4
+
5
+ Ask a model a hard question and it tends to collapse the tension into one confident answer — or hedge with a bland "on one hand… on the other." This framework does neither. For every thesis it generates a genuine antithesis, maps precisely where each side overreaches (T-, A-) and where it constructively balances the other (T+, A+), and drives the pair toward a **synthesis** — not a compromise, but a new quality that emerges from their circular causality and that neither pole held alone.
6
+
7
+ The reasoning lives in a graph. Every move — surfacing a thesis, finding its opposition, developing its four aspects, arranging them into a **Wheel** — writes semantic, rule-validated nodes and edges into a graph database. The graph **is** the state: a persistent, compounding map of how a domain's tensions resolve, that any application can query, visualize, or build on.
8
+
9
+ And the synthesis is *earned*, not asserted. Where "think step by step" leaves rigor to chance, formal generative rules define what counts as valid: exactly one antithesis per thesis, modality kept in balance, and positive synthesis (S+) only when T-'s excess transforms into A+ and A-'s into T+. The structure enforces a discipline the prompt alone can't.
10
+
11
+ ## Learn More
12
+ - [Structured Dialectics](https://dialexity.com/blog/structured-dialectics-consolidated-manuscript/) - the theory
13
+ - [Dialectical Wheels for Systems Optimization](https://dialexity.com/blog/dialectical-wheels-for-systems-optimization/)
14
+ - [Dialectical Ethics](https://dialexity.com/blog/dialectical-ethics/)
15
+
16
+
17
+ ## How It Works
18
+
19
+ 1. **Input** — text, URLs, or raw ideas from any domain
20
+ 2. **Analysis** — extract the theses, find each one's true antithesis, develop the four aspects (T+, T-, A+, A-) that say where each side helps and where it overreaches
21
+ 3. **Graph curation** — commit every insight as content-addressed, rule-validated nodes and edges — nothing is stored until it holds up
22
+ 4. **Exploration** — combine perspectives into Cycles, arrange them into Wheels, and trace the Transformations whose circular causality yields synthesis
23
+
24
+ Each pass leaves the graph richer than it found it: new tensions enter an existing web of validated reasoning, so understanding compounds instead of resetting every prompt.
25
+
26
+ ## Architecture
27
+
28
+ ```
29
+ Host Application (Chainlit, API, CLI)
30
+
31
+
32
+ Agent: Analyst · Explorer · Advisor (LLM + tools)
33
+
34
+
35
+ Graph Database (Memgraph / Neo4j)
36
+ ```
37
+
38
+ An **agent** is the entry point — a thin LLM orchestrator that manages a conversation with tools that read and write the graph. There are three (Analyst, Explorer, Advisor); each owns a tool set and a domain-neutral reasoning prompt. The host app controls persona (via the app preamble) and scope identity (`sid`); the framework handles reasoning and graph curation. See [docs/agents.md](docs/agents.md).
39
+
40
+ ### Docs
41
+ - [Agents: Analyst, Explorer, Advisor](docs/agents.md) — the building blocks, their tools, and the UX to build around them
42
+ - [Graph Data Model](docs/graph.md)
43
+ - [Scoring & Metrics](docs/scoring.md)
44
+
45
+ ## Why a Reasoning Graph
46
+
47
+ Most AI systems treat knowledge as flat context — dump text into the prompt and hope the LLM figures out the structure. The dialectical framework builds a **persistent reasoning graph** where the structure itself encodes how to think about a domain:
48
+
49
+ - **Oppositions are explicit.** The LLM doesn't rediscover the tensions on every call — they persist as typed T/A pairs, so reasoning starts from a mapped conflict instead of a blank page.
50
+ - **Transformations encode causality.** Edges don't just connect — they show how one position's failure becomes another's strength. This is the circular causality that drives synthesis.
51
+ - **Quality is measurable.** Complementarity, modality balance, area metrics tell the LLM which reasoning paths are well-developed and which are thin — no guessing about confidence.
52
+ - **Knowledge compounds.** Each new perspective enters an existing graph of validated reasoning. The LLM builds on prior synthesis rather than re-deriving from scratch.
53
+
54
+ The result: an LLM with this graph in context doesn't just have facts about a topic — it has the intellectual terrain mapped. What opposes what, where balance was achieved, what assumptions remain untested, and where synthesis is possible.
55
+
56
+ This is the [LLM Wiki](https://gist.github.com/karpathy/442a6bf555914893e9891c11519de94f) pattern realized as a semantic graph rather than a pile of markdown files — knowledge that is structured, rule-validated, and queryable by reasoning topology.
57
+
58
+ | Simple | Detailed |
59
+ |--------|----------|
60
+ | ![Wheel](https://raw.githubusercontent.com/dialexity/dialectical-framework/main/docs/wheel-scheme.png) | ![Wheel](https://raw.githubusercontent.com/dialexity/dialectical-framework/main/docs/wheel-scheme2.png) |
61
+
62
+ ## Core Graph Structure
63
+
64
+ It's all one graph. **Statements** are the atoms; typed edges carry the dialectical relationships — opposition, complementarity, transformation — and each structure below composes the ones above it into progressively richer reasoning, culminating in the **Dialectical Wheel**.
65
+
66
+ | Structure | Role |
67
+ |-----------|------|
68
+ | **Statement** | Atomic unit of meaning — a thesis, position, or claim |
69
+ | **Polarity** | A single T↔A tension (thesis vs. antithesis); reusable across perspectives |
70
+ | **Perspective** | A full tetrad — a Polarity developed with its four aspects (T+, T-, A+, A-) |
71
+ | **Nexus** | A working set of Perspectives grouped for exploration |
72
+ | **Cycle** | An ordered sequence of Perspectives — which tension drives which |
73
+ | **Wheel** | A concrete circular arrangement of a Cycle, with the edges between components |
74
+ | **Transition** | A directed edge between two components — one step around the Wheel |
75
+ | **Transformation** | The Action-Reflection paths on an edge that turn one pole's excess into the other's strength |
76
+ | **Synthesis** | The emergent S+/S- arising from the whole Wheel's circular causality |
77
+
78
+ Picture the Wheel as a pizza sliced into segments: each **segment** bundles a component with its plus and minus (e.g. T, T+, T-), a **Perspective** joins a thesis segment with the antithesis segment directly across from it, and **Transitions** are the arrows running segment to segment around the rim.
79
+
80
+ ## Integration
81
+
82
+ Wherever the answer is a tension rather than a fact, this drops in as the reasoning engine: decision support that weighs both sides, systems thinking, mediation between opposed positions, ethical modeling. You wire it into your app through three conversational agents — the main building blocks:
83
+
84
+ - **Analyst** — turns raw material into structured tensions, up to grouping them into a Nexus (Case-scoped).
85
+ - **Explorer** — takes one Nexus and works out its causal pathways and synthesis (Nexus-scoped).
86
+ - **Advisor** — runs the whole machine silently and returns pure counsel, with no framework vocabulary exposed (Case-scoped).
87
+
88
+ Analyst + Explorer are the structure-forward "graph navigator" experience; the Advisor is a chat-only product over the same graph. See [docs/agents.md](docs/agents.md) for full specs, tool lists, and the UX to build around each.
89
+
90
+ ```python
91
+ from dialectical_framework.dialectical_reasoning import DialecticalReasoning
92
+ from dialectical_framework.settings import Settings
93
+ from dialectical_framework.graph.nodes.case import Case
94
+ from dialectical_framework.graph.scope_context import scope
95
+ from dialectical_framework.agents.advisor.advisor import Advisor
96
+
97
+ # Initialize once
98
+ DialecticalReasoning.setup(Settings.from_env())
99
+
100
+ # A Case owns the scope id (sid); all graph writes are sid-scoped.
101
+ case = Case(); case.commit()
102
+
103
+ with scope(case.sid):
104
+ advisor = Advisor(app_preamble="You are a systems thinking coach...")
105
+ async for event in advisor.chat_stream("Analyze the tension between growth and sustainability"):
106
+ # ThinkingDelta, TextDelta, ToolStart, ToolResult, ResponseComplete
107
+ handle(event)
108
+ ```
109
+
110
+ ## Setup
111
+
112
+ ### Requirements
113
+
114
+ - Python 3.11+
115
+ - Memgraph or Neo4j
116
+ - An LLM provider (OpenAI, Anthropic, or Bedrock via a custom Mirascope provider)
117
+
118
+ ### Install
119
+
120
+ ```bash
121
+ poetry install
122
+ cp .env.example .env # then fill in the values (see .env.example for details)
123
+ ```
124
+
125
+ ### Run Tests
126
+
127
+ ```bash
128
+ poetry run pytest # All tests (LLM mocked)
129
+ poetry run pytest -m llm # Only LLM-path tests (mocked)
130
+ poetry run pytest --real-llm # Hit real LLM provider
131
+ ```
132
+
133
+ ## Built With
134
+
135
+ - [Mirascope](https://mirascope.com/) — LLM abstraction
136
+ - [GQLAlchemy](https://memgraph.com/docs/gqlalchemy) — Graph ORM
137
+ - [dependency-injector](https://python-dependency-injector.ets-labs.org/) — DI container
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "dialectical-framework"
3
- version = "1.6.0"
3
+ version = "1.6.1"
4
4
  description = "A dialectical framework for augmented intelligence. AI reasoning powered with dialectics supports humans in: system optimization (psychology, engineering, business, politics, etc.); dispute resolution (mediation, conflicts, negotiations, etc.); decision-making (dilemmas, challenging situations, win-win, etc.)."
5
5
  authors = ["Evaldas Taroza <evaldas@dialexity.com>"]
6
6
  readme = "README.md"
@@ -136,11 +136,13 @@ Seven tools. Use silently — never mention them.
136
136
 
137
137
  - `ingest` — Processes raw material (text, files, transcripts) through
138
138
  dialectical analysis: extracts theses, finds oppositions, builds full
139
- perspectives with aspects. Use when raw material needs analysis and you
140
- don't yet see the tensions compose the `text` parameter from what they've
141
- shared. Do NOT ingest greetings or small talk. When pre-loaded sources exist
142
- (shown in the dump under Sources), call ingest with just an `intent` to
143
- extract tensions from them without new text.
139
+ perspectives with aspects. Use for open-ended material where no single
140
+ position is yet articulated and the tensions must be discovered compose
141
+ the `text` parameter from what they've shared. When the person has already
142
+ named a clear position (or an explicit either/or), prefer `anchor` it is
143
+ more reliable than extraction. Do NOT ingest greetings or small talk. When
144
+ pre-loaded sources exist (shown in the dump under Sources), call ingest with
145
+ just an `intent` to extract tensions from them without new text.
144
146
 
145
147
  - `anchor` — Plants a specific tension from the conversation. More precise
146
148
  than ingest; use when you can see at least the person's position. Two modes:
@@ -215,6 +217,13 @@ should reflect what resonates — retract what doesn't.
215
217
  4. `explore` → respond with specific paired pathways
216
218
  5. Continue with full depth, offer integration vision when they're ready
217
219
 
220
+ **When a tool surfaces no tensions:** If `ingest` returns nothing (no
221
+ perspectives in its result), the material resisted automatic extraction — this
222
+ is a signal to `anchor` directly, not to fall back to unstructured discussion.
223
+ Name the position you heard and the force that opposes it, and `anchor` that
224
+ tension before responding. Only proceed on your own judgement if you genuinely
225
+ cannot identify any opposition in what they've shared.
226
+
218
227
  ## What You Must Never Do
219
228
 
220
229
  - Reveal tools or internal processes
@@ -261,7 +261,11 @@ class AnalysisPipeline(ReasonableConcern[AnalysisResult]):
261
261
 
262
262
  if not thesis_hashes:
263
263
  self._report.ok = True
264
- self._report.summary = "No theses found"
264
+ self._report.summary = (
265
+ "No tensions extracted from this material. Anchor an "
266
+ "explicit position (and its opposition, if visible) "
267
+ "instead of ingesting."
268
+ )
265
269
  return AnalysisResult(
266
270
  ideas_hash=ideas_hash, errors=errors, reports=reports
267
271
  )
@@ -21,6 +21,7 @@ from pydantic import Field
21
21
  from dialectical_framework.agents.reasonable_concern import ReasonableConcern
22
22
  from dialectical_framework.concerns.statement_classification import (
23
23
  ClassificationResult, StatementClassification)
24
+ from dialectical_framework.concerns.statement_headline import StatementHeadline
24
25
  from dialectical_framework.enums.di import DI
25
26
  from dialectical_framework.graph.nodes.ideas import Ideas
26
27
  from dialectical_framework.graph.nodes.rationale import Rationale
@@ -83,7 +84,11 @@ class AnchorTheses(ReasonableConcern[Optional[Ideas]]):
83
84
  statements: list[str],
84
85
  text: str = "",
85
86
  ) -> list[Statement]:
87
+ # Condense in parallel with classification. The agent may hand this skill
88
+ # verbose prose (there is no extraction step to clamp length), so the
89
+ # stored text becomes a headline while classification reads the full text.
86
90
  classifiers = [StatementClassification() for _ in statements]
91
+ headliners = [StatementHeadline() for _ in statements]
87
92
  tasks = [
88
93
  classifier.resolve(
89
94
  statement=stmt,
@@ -92,25 +97,35 @@ class AnchorTheses(ReasonableConcern[Optional[Ideas]]):
92
97
  )
93
98
  for classifier, stmt in zip(classifiers, statements)
94
99
  ]
100
+ headline_tasks = [
101
+ headliner.resolve(statement=stmt, text=text)
102
+ for headliner, stmt in zip(headliners, statements)
103
+ ]
95
104
 
96
105
  results: list[ClassificationResult] = await asyncio.gather(*tasks)
106
+ headlines: list[str] = await asyncio.gather(*headline_tasks)
97
107
 
98
108
  components: list[Statement] = []
99
- for classifier, result in zip(classifiers, results):
100
- component = self._create_component(result)
109
+ for classifier, headliner, result, headline in zip(
110
+ classifiers, headliners, results, headlines
111
+ ):
112
+ component = self._create_component(result, headline)
101
113
  components.append(component)
102
114
  self._report = self._report.merge(classifier.report)
115
+ self._report = self._report.merge(headliner.report)
103
116
 
104
117
  return components
105
118
 
106
- def _create_component(self, result: ClassificationResult) -> Statement:
107
- component = Statement(text=result.statement, meaning=result.meaning)
119
+ def _create_component(
120
+ self, result: ClassificationResult, headline: str
121
+ ) -> Statement:
122
+ component = Statement(text=headline, meaning=result.meaning)
108
123
  component.commit()
109
124
 
110
125
  classification_label = "SIMPLE" if result.is_simple else "COMPLEX"
111
126
  self._report.node_created(
112
127
  component,
113
- patch={"meaning": result.meaning, "text": result.statement},
128
+ patch={"meaning": result.meaning, "text": headline},
114
129
  meta={"classification": classification_label},
115
130
  )
116
131
 
@@ -178,6 +178,7 @@ class FindPolarities(ReasonableConcern[Optional[Ideas]]):
178
178
  vocabulary=dedup_vocab,
179
179
  text=input_text,
180
180
  )
181
+ self._report = self._report.merge(deduplicator.report)
181
182
 
182
183
  # Reconnect OPPOSITE_OF: thesis -> DB version for replacements
183
184
  self._reconnect_oppositions(results, dedup_result)
@@ -18,6 +18,7 @@ Usage:
18
18
 
19
19
  from __future__ import annotations
20
20
 
21
+ import asyncio
21
22
  from dataclasses import dataclass
22
23
  from typing import TYPE_CHECKING, Annotated, Optional
23
24
 
@@ -26,17 +27,18 @@ from mirascope import llm
26
27
  from pydantic import Field
27
28
 
28
29
  from dialectical_framework.agents.reasonable_concern import ReasonableConcern
29
- from dialectical_framework.enums.di import DI
30
30
  from dialectical_framework.concerns.antithesis_classification import \
31
31
  AntithesisClassification
32
32
  from dialectical_framework.concerns.statement_classification import \
33
33
  StatementClassification
34
+ from dialectical_framework.concerns.statement_headline import StatementHeadline
35
+ from dialectical_framework.enums.di import DI
34
36
  from dialectical_framework.graph.estimation_manager import EstimationManager
35
- from dialectical_framework.graph.nodes.estimation import (
36
- ArousalEstimation, ModeEstimation)
37
- from dialectical_framework.graph.nodes.statement import Statement
37
+ from dialectical_framework.graph.nodes.estimation import (ArousalEstimation,
38
+ ModeEstimation)
38
39
  from dialectical_framework.graph.nodes.polarity import Polarity
39
40
  from dialectical_framework.graph.nodes.rationale import Rationale
41
+ from dialectical_framework.graph.nodes.statement import Statement
40
42
  from dialectical_framework.graph.repositories.input_repository import \
41
43
  InputRepository
42
44
  from dialectical_framework.graph.repositories.polarity_repository import \
@@ -117,12 +119,19 @@ class IntroducePolarity(ReasonableConcern[IntroducePolarityResult]):
117
119
  primary_polarity.commit()
118
120
  self._report.node_created(primary_polarity)
119
121
  self._report.relationship_created(
120
- primary_polarity.t, thesis_stmt, primary_polarity,
122
+ primary_polarity.t,
123
+ thesis_stmt,
124
+ primary_polarity,
121
125
  patch={"heuristic_similarity": 1.0, "alias": "T"},
122
126
  )
123
127
  self._report.relationship_created(
124
- primary_polarity.a, antithesis_stmt, primary_polarity,
125
- patch={"heuristic_similarity": classification.heuristic_similarity, "alias": "A"},
128
+ primary_polarity.a,
129
+ antithesis_stmt,
130
+ primary_polarity,
131
+ patch={
132
+ "heuristic_similarity": classification.heuristic_similarity,
133
+ "alias": "A",
134
+ },
126
135
  )
127
136
  self._report.artifacts["primary_polarity_source"] = "created"
128
137
 
@@ -135,9 +144,13 @@ class IntroducePolarity(ReasonableConcern[IntroducePolarityResult]):
135
144
  antithesis_stmt, ArousalEstimation, classification.arousal_value
136
145
  )
137
146
  if mode_est:
138
- self._report.node_updated(mode_est, patch={"value": classification.mode_value})
147
+ self._report.node_updated(
148
+ mode_est, patch={"value": classification.mode_value}
149
+ )
139
150
  if arousal_est:
140
- self._report.node_updated(arousal_est, patch={"value": classification.arousal_value})
151
+ self._report.node_updated(
152
+ arousal_est, patch={"value": classification.arousal_value}
153
+ )
141
154
 
142
155
  # Build result
143
156
  result = IntroducePolarityResult(
@@ -166,12 +179,23 @@ class IntroducePolarity(ReasonableConcern[IntroducePolarityResult]):
166
179
  return result
167
180
 
168
181
  async def _resolve_statement(self, text: str, context: str) -> Statement:
169
- """Classify and commit a Statement. Commit is an upsert — same text reuses existing node."""
182
+ """Classify and commit a Statement. Commit is an upsert — same text reuses existing node.
183
+
184
+ The agent may pass verbose prose (the anchor path has no extraction step
185
+ to clamp length), so condense to a headline in parallel with
186
+ classification. Classification reads the full text for richer taxonomy
187
+ anchoring; only the stored ``text`` becomes the headline.
188
+ """
170
189
  classifier = StatementClassification()
171
- result = await classifier.resolve(statement=text, text=context)
190
+ headliner = StatementHeadline()
191
+ result, headline = await asyncio.gather(
192
+ classifier.resolve(statement=text, text=context),
193
+ headliner.resolve(statement=text, text=context),
194
+ )
172
195
  self._report = self._report.merge(classifier.report)
196
+ self._report = self._report.merge(headliner.report)
173
197
 
174
- stmt = Statement(text=result.statement, meaning=result.meaning)
198
+ stmt = Statement(text=headline, meaning=result.meaning)
175
199
  stmt.commit()
176
200
  self._report.node_created(stmt)
177
201
 
@@ -207,7 +231,9 @@ class IntroducePolarity(ReasonableConcern[IntroducePolarityResult]):
207
231
  async def introduce_polarity(
208
232
  thesis: Annotated[str, Field(description="The thesis statement text")],
209
233
  antithesis: Annotated[str, Field(description="The antithesis statement text")],
210
- text: Annotated[str, Field(description="Additional context for classification")] = "",
234
+ text: Annotated[
235
+ str, Field(description="Additional context for classification")
236
+ ] = "",
211
237
  ) -> str:
212
238
  """Introduce a known thesis-antithesis tension directly as a Polarity. Classifies both statements, creates the Polarity node (T-A pair) with HS score. Use when the tension is already clear from conversation rather than needing extraction from source material."""
213
239
  concern = IntroducePolarity(thesis=thesis, antithesis=antithesis, text=text)
@@ -157,6 +157,7 @@ class SurfaceTheses(ReasonableConcern[Optional[Ideas]]):
157
157
  vocabulary=vocab,
158
158
  text=input_text,
159
159
  )
160
+ self._report = self._report.merge(deduplicator.report)
160
161
  deleted_count = dedup_result.deleted_count
161
162
  deduped = dedup_result.components
162
163
  else:
@@ -77,6 +77,14 @@ When the user wants to explore interactions between perspectives:
77
77
  Only create separate if user deliberately wants a different scope.
78
78
  3. Confirm the exploration direction with the user before creating.
79
79
 
80
+ **Grouping (which perspectives to combine):**
81
+ - Prefer perspectives from different polarities (different T-A oppositions). Transformations
82
+ between different oppositions are genuine synthesis with opponents — the richest exploration.
83
+ - Same-polarity grouping is still valid when it fits the intent or the user asks for it.
84
+ It produces "angle shifts" (reframing within one opposition) rather than cross-opposition
85
+ synthesis — note that tradeoff so the user knows what they'll get. Never refuse or override
86
+ an explicit same-polarity request.
87
+
80
88
  **Intent (internal quality gate — do not surface to user):**
81
89
  - Must be specific: what the user wants to understand or navigate.
82
90
  - Refine vague requests ("explore this") into purposeful intents internally.
@@ -37,7 +37,9 @@ if TYPE_CHECKING:
37
37
  from dialectical_framework.events.graph_event_bus import GraphEventBus
38
38
  from dialectical_framework.graph.nodes.base_node import BaseNode
39
39
  from dialectical_framework.graph.relationship_manager import (
40
- BoundRelationshipManager, RelationshipManager)
40
+ BoundRelationshipManager,
41
+ RelationshipManager,
42
+ )
41
43
  from dialectical_framework.utils.effect_logger import EffectLogger
42
44
 
43
45
  # Type alias for relationship type parameter
@@ -209,11 +211,13 @@ class ExecutionReport(BaseModel):
209
211
  if self._event_bus is None:
210
212
  return
211
213
  import asyncio
214
+
212
215
  try:
213
216
  loop = asyncio.get_running_loop()
214
217
  except RuntimeError:
215
218
  return
216
219
  from dialectical_framework.graph.scope_context import get_current_sid
220
+
217
221
  sid = get_current_sid()
218
222
  if sid:
219
223
  loop.create_task(self._event_bus.publish(sid, effect))
@@ -224,6 +228,7 @@ class ExecutionReport(BaseModel):
224
228
  return
225
229
  from dialectical_framework.agents.agent_context import get_current_agent
226
230
  from dialectical_framework.graph.scope_context import get_current_sid
231
+
227
232
  sid = get_current_sid()
228
233
  if not sid:
229
234
  return
@@ -239,6 +244,7 @@ class ExecutionReport(BaseModel):
239
244
  return
240
245
  from dialectical_framework.agents.agent_context import get_current_agent
241
246
  from dialectical_framework.graph.scope_context import get_current_sid
247
+
242
248
  sid = get_current_sid()
243
249
  if not sid:
244
250
  return
@@ -431,10 +437,16 @@ class ExecutionReport(BaseModel):
431
437
 
432
438
  merged_artifacts = {**self.artifacts, **other.artifacts}
433
439
 
434
- return ExecutionReport(
440
+ merged = ExecutionReport(
435
441
  tool=self.tool,
436
442
  ok=self.ok and other.ok,
437
443
  summary=f"{self.summary}\n{other.summary}".strip(),
438
444
  effects=self.effects,
439
445
  artifacts=merged_artifacts,
440
446
  )
447
+ # Carry the sequence counter forward so subsequent _next_seq()/merge()
448
+ # calls continue the timeline. Without this the fresh report resets to
449
+ # 0, and chained merges (self._report = self._report.merge(...)) emit
450
+ # duplicate seq values.
451
+ merged._seq_counter = self._seq_counter
452
+ return merged