dialectical-framework 1.2.0__tar.gz → 1.2.2__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 (169) hide show
  1. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/PKG-INFO +1 -1
  2. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/pyproject.toml +1 -1
  3. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/agents/analyst/skills/anchor_theses.py +2 -1
  4. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/agents/analyst/skills/edit_perspective.py +4 -2
  5. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/agents/analyst/skills/expand_polarities.py +1 -1
  6. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/agents/analyst/skills/find_polarities.py +2 -1
  7. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/agents/analyst/skills/surface_theses.py +2 -1
  8. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/agents/execution_report.py +28 -1
  9. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/agents/explorer/explorer.py +15 -8
  10. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/agents/explorer/skills/explore_transformations.py +125 -41
  11. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/agents/explorer/skills/generate_synthesis.py +2 -1
  12. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/agents/explorer/system_prompts.py +29 -17
  13. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/concerns/perspective_combination.py +2 -1
  14. dialectical_framework-1.2.2/src/dialectical_framework/utils/concurrency.py +37 -0
  15. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/utils/use_brain.py +32 -5
  16. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/LICENSE +0 -0
  17. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/README.md +0 -0
  18. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/__init__.py +0 -0
  19. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/agents/__init__.py +0 -0
  20. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/agents/agent_context.py +0 -0
  21. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/agents/analyst/__init__.py +0 -0
  22. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/agents/analyst/analyst.py +0 -0
  23. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/agents/analyst/skills/__init__.py +0 -0
  24. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/agents/analyst/skills/introduce_polarity.py +0 -0
  25. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/agents/analyst/system_prompts.py +0 -0
  26. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/agents/analyst/tools/__init__.py +0 -0
  27. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/agents/analyst/tools/create_dx_input.py +0 -0
  28. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/agents/analyst/tools/place_statement.py +0 -0
  29. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/agents/apps.py +0 -0
  30. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/agents/conversation_facilitator.py +0 -0
  31. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/agents/explorer/__init__.py +0 -0
  32. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/agents/explorer/skills/__init__.py +0 -0
  33. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/agents/explorer/skills/build_wheels.py +0 -0
  34. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/agents/explorer/tools/__init__.py +0 -0
  35. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/agents/explorer/tools/create_nexus.py +0 -0
  36. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/agents/explorer/tools/expand_nexus.py +0 -0
  37. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/agents/explorer/tools/generate_synthesis.py +0 -0
  38. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/agents/explorer/tools/present_exploration.py +0 -0
  39. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/agents/orchestrator/__init__.py +0 -0
  40. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/agents/orchestrator/tools/__init__.py +0 -0
  41. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/agents/orchestrator/tools/add_input.py +0 -0
  42. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/agents/orchestrator/tools/discard.py +0 -0
  43. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/agents/orchestrator/tools/get_schema.py +0 -0
  44. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/agents/orchestrator/tools/inspect_node.py +0 -0
  45. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/agents/orchestrator/tools/present_analysis.py +0 -0
  46. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/agents/orchestrator/tools/query_graph.py +0 -0
  47. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/agents/reasonable_concern.py +0 -0
  48. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/agents/stream_events.py +0 -0
  49. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/concerns/__init__.py +0 -0
  50. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/concerns/ac_re_taxonomy.py +0 -0
  51. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/concerns/action_extraction.py +0 -0
  52. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/concerns/ai_dto/__init__.py +0 -0
  53. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/concerns/ai_dto/statement_dto.py +0 -0
  54. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/concerns/ai_dto/statements_deck_dto.py +0 -0
  55. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/concerns/antithesis_classification.py +0 -0
  56. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/concerns/antithesis_extraction.py +0 -0
  57. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/concerns/aspect_classification.py +0 -0
  58. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/concerns/aspect_generation.py +0 -0
  59. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/concerns/causality/__init__.py +0 -0
  60. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/concerns/causality/causality_estimator.py +0 -0
  61. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/concerns/causality/causality_estimator_balanced.py +0 -0
  62. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/concerns/causality/causality_estimator_criteria.py +0 -0
  63. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/concerns/causality/causality_estimator_desirable.py +0 -0
  64. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/concerns/causality/causality_estimator_feasible.py +0 -0
  65. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/concerns/causality/causality_estimator_realistic.py +0 -0
  66. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/concerns/causality/causality_normalizer.py +0 -0
  67. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/concerns/causality/estimator_resolver.py +0 -0
  68. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/concerns/causality_estimation.py +0 -0
  69. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/concerns/control_statements_check.py +0 -0
  70. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/concerns/create_nexus.py +0 -0
  71. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/concerns/diagonal_oppositions_check.py +0 -0
  72. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/concerns/display_text_edit.py +0 -0
  73. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/concerns/expand_nexus.py +0 -0
  74. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/concerns/perspective_validation.py +0 -0
  75. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/concerns/positive_ac_re_apex_derivation.py +0 -0
  76. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/concerns/statement_classification.py +0 -0
  77. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/concerns/statement_deduplication.py +0 -0
  78. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/concerns/statement_placement.py +0 -0
  79. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/concerns/synthesis_generation.py +0 -0
  80. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/concerns/thesis_extraction.py +0 -0
  81. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/concerns/transformation_audit.py +0 -0
  82. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/concerns/transformation_generation.py +0 -0
  83. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/dialectical_reasoning.py +0 -0
  84. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/enums/__init__.py +0 -0
  85. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/enums/causality_preset.py +0 -0
  86. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/enums/di.py +0 -0
  87. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/events/__init__.py +0 -0
  88. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/events/graph_event.py +0 -0
  89. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/events/graph_event_bus.py +0 -0
  90. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/exceptions/__init__.py +0 -0
  91. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/exceptions/node_errors.py +0 -0
  92. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/exceptions/resolver_errors.py +0 -0
  93. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/graph/__init__.py +0 -0
  94. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/graph/composite_input_resolver.py +0 -0
  95. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/graph/dialexity_input_resolver.py +0 -0
  96. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/graph/estimation_manager.py +0 -0
  97. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/graph/mixins/__init__.py +0 -0
  98. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/graph/mixins/incremental_build_mixin.py +0 -0
  99. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/graph/mixins/intent_mixin.py +0 -0
  100. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/graph/mixins/persistable_mixin.py +0 -0
  101. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/graph/nodes/__init__.py +0 -0
  102. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/graph/nodes/assessable_entity.py +0 -0
  103. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/graph/nodes/base_node.py +0 -0
  104. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/graph/nodes/case.py +0 -0
  105. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/graph/nodes/cycle.py +0 -0
  106. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/graph/nodes/estimation.py +0 -0
  107. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/graph/nodes/ideas.py +0 -0
  108. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/graph/nodes/input.py +0 -0
  109. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/graph/nodes/nexus.py +0 -0
  110. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/graph/nodes/perspective.py +0 -0
  111. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/graph/nodes/polarity.py +0 -0
  112. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/graph/nodes/rationale.py +0 -0
  113. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/graph/nodes/statement.py +0 -0
  114. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/graph/nodes/synthesis.py +0 -0
  115. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/graph/nodes/transformation.py +0 -0
  116. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/graph/nodes/transition.py +0 -0
  117. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/graph/nodes/wheel.py +0 -0
  118. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/graph/relationship_manager.py +0 -0
  119. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/graph/relationships/__init__.py +0 -0
  120. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/graph/relationships/action_reflection_relationship.py +0 -0
  121. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/graph/relationships/belongs_to_cycle_relationship.py +0 -0
  122. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/graph/relationships/belongs_to_nexus_relationship.py +0 -0
  123. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/graph/relationships/changed_to_relationship.py +0 -0
  124. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/graph/relationships/contradiction_of_relationship.py +0 -0
  125. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/graph/relationships/critiques_relationship.py +0 -0
  126. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/graph/relationships/distilled_to_relationship.py +0 -0
  127. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/graph/relationships/estimates_relationship.py +0 -0
  128. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/graph/relationships/explains_relationship.py +0 -0
  129. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/graph/relationships/has_input_relationship.py +0 -0
  130. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/graph/relationships/has_statement_relationship.py +0 -0
  131. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/graph/relationships/has_wheel_relationship.py +0 -0
  132. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/graph/relationships/immutable_structure.py +0 -0
  133. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/graph/relationships/is_source_of_relationship.py +0 -0
  134. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/graph/relationships/is_target_of_relationship.py +0 -0
  135. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/graph/relationships/negative_side_of_relationship.py +0 -0
  136. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/graph/relationships/opposite_direction_relationship.py +0 -0
  137. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/graph/relationships/opposite_of_relationship.py +0 -0
  138. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/graph/relationships/polarity_relationship.py +0 -0
  139. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/graph/relationships/positive_side_of_relationship.py +0 -0
  140. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/graph/relationships/provides_relationship.py +0 -0
  141. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/graph/relationships/synthesis_of_relationship.py +0 -0
  142. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/graph/repositories/__init__.py +0 -0
  143. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/graph/repositories/case_repository.py +0 -0
  144. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/graph/repositories/cycle_repository.py +0 -0
  145. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/graph/repositories/input_repository.py +0 -0
  146. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/graph/repositories/nexus_repository.py +0 -0
  147. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/graph/repositories/node_repository.py +0 -0
  148. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/graph/repositories/perspective_repository.py +0 -0
  149. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/graph/repositories/polarity_repository.py +0 -0
  150. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/graph/repositories/schema_repository.py +0 -0
  151. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/graph/repositories/statement_repository.py +0 -0
  152. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/graph/repositories/transformation_repository.py +0 -0
  153. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/graph/repositories/wheel_repository.py +0 -0
  154. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/graph/scope_context.py +0 -0
  155. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/graph/verbatim_input_resolver.py +0 -0
  156. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/graph/wheel_segment.py +0 -0
  157. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/graph/wheel_segment_polar_pair.py +0 -0
  158. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/protocols/__init__.py +0 -0
  159. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/protocols/has_config.py +0 -0
  160. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/protocols/input_resolver.py +0 -0
  161. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/settings.py +0 -0
  162. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/utils/__init__.py +0 -0
  163. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/utils/bedrock_provider.py +0 -0
  164. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/utils/dc_replace.py +0 -0
  165. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/utils/decompose_probability_uniformly.py +0 -0
  166. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/utils/edge_context.py +0 -0
  167. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/utils/effect_logger.py +0 -0
  168. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/utils/order_transitions.py +0 -0
  169. {dialectical_framework-1.2.0 → dialectical_framework-1.2.2}/src/dialectical_framework/utils/sequence_generation.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: dialectical-framework
3
- Version: 1.2.0
3
+ Version: 1.2.2
4
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
5
  License: MIT
6
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
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "dialectical-framework"
3
- version = "1.2.0"
3
+ version = "1.2.2"
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"
@@ -135,6 +135,7 @@ class AnchorTheses(ReasonableConcern[Optional[Ideas]]):
135
135
  intent = ", ".join(self.statements)
136
136
  ideas = Ideas(intent=intent)
137
137
  ideas.save()
138
+ self._report.node_created(ideas)
138
139
 
139
140
  for input_node in self._get_inputs():
140
141
  ideas.inputs.connect(input_node)
@@ -145,7 +146,7 @@ class AnchorTheses(ReasonableConcern[Optional[Ideas]]):
145
146
  self._report.relationship_created(ideas.statements, ideas, comp)
146
147
 
147
148
  ideas.commit()
148
- self._report.node_created(ideas)
149
+ self._report.node_committed(ideas)
149
150
 
150
151
  return ideas
151
152
 
@@ -129,10 +129,12 @@ class EditPerspective(ReasonableConcern[EditPerspectiveResult]):
129
129
  if self._was_committed:
130
130
  working_pp = pp.clone()
131
131
  working_pp.save()
132
+ self._report.node_created(working_pp)
132
133
  else:
133
134
  working_pp = pp
134
135
  if not working_pp._id:
135
136
  working_pp.save()
137
+ self._report.node_created(working_pp)
136
138
  self._working_pp = working_pp
137
139
 
138
140
  # Route based on what's changing
@@ -401,7 +403,7 @@ class EditPerspective(ReasonableConcern[EditPerspectiveResult]):
401
403
  )
402
404
 
403
405
  pp.commit()
404
- self._report.node_created(pp)
406
+ self._report.node_committed(pp)
405
407
 
406
408
  # ─── Tetrad editing (aspect changes only → validate coherence) ───
407
409
 
@@ -469,7 +471,7 @@ class EditPerspective(ReasonableConcern[EditPerspectiveResult]):
469
471
  )
470
472
 
471
473
  self._working_pp.commit()
472
- self._report.node_created(self._working_pp)
474
+ self._report.node_committed(self._working_pp)
473
475
 
474
476
  return EditPerspectiveResult(
475
477
  perspective=self._working_pp,
@@ -129,7 +129,7 @@ class ExpandPolarity(ReasonableConcern[list[Perspective]]):
129
129
  continue
130
130
 
131
131
  pp.commit()
132
- self._report.node_created(pp)
132
+ self._report.node_committed(pp)
133
133
  completed_pps.append(pp)
134
134
 
135
135
  # Return all PPs: existing complete + newly completed
@@ -503,6 +503,7 @@ class FindPolarities(ReasonableConcern[Optional[Ideas]]):
503
503
 
504
504
  ideas = Ideas(intent=intent)
505
505
  ideas.save()
506
+ self._report.node_created(ideas)
506
507
 
507
508
  # Connect to inputs
508
509
  input_repo = InputRepository()
@@ -531,7 +532,7 @@ class FindPolarities(ReasonableConcern[Optional[Ideas]]):
531
532
  )
532
533
 
533
534
  ideas.commit()
534
- self._report.node_created(ideas)
535
+ self._report.node_committed(ideas)
535
536
 
536
537
  # Add rationale
537
538
  total_theses = len(valid_results)
@@ -387,6 +387,7 @@ Determine:
387
387
 
388
388
  ideas = Ideas(intent=self.intent)
389
389
  ideas.save()
390
+ self._report.node_created(ideas)
390
391
 
391
392
  # Connect to inputs (filtered or all)
392
393
  for input_node in self._get_inputs():
@@ -399,7 +400,7 @@ Determine:
399
400
  self._report.relationship_created(ideas.statements, ideas, comp)
400
401
 
401
402
  ideas.commit()
402
- self._report.node_created(ideas)
403
+ self._report.node_committed(ideas)
403
404
 
404
405
  # Attach rationale explaining how intent was interpreted
405
406
  if parsed.reasoning:
@@ -73,6 +73,7 @@ def _resolve_rel_type(rel_type: RelType) -> str:
73
73
 
74
74
  EffectType = Literal[
75
75
  "node_created",
76
+ "node_committed",
76
77
  "node_updated",
77
78
  "node_deleted",
78
79
  "relationship_created",
@@ -93,10 +94,15 @@ class NodeRef(BaseModel):
93
94
 
94
95
  label: str # Node class name: "Statement", "Perspective", etc.
95
96
  hash: Optional[str] = None # 7-char short hash (None if uncommitted/draft)
97
+ db_id: Optional[int] = None # DB internal ID (available after save)
96
98
 
97
99
  @classmethod
98
100
  def from_node(cls, node: BaseNode) -> NodeRef:
99
- return cls(label=node.__class__.__name__, hash=node.short_hash)
101
+ return cls(
102
+ label=node.__class__.__name__,
103
+ hash=node.short_hash,
104
+ db_id=node._id,
105
+ )
100
106
 
101
107
 
102
108
  class RelationshipRef(BaseModel):
@@ -269,6 +275,27 @@ class ExecutionReport(BaseModel):
269
275
  self._emit(effect)
270
276
  self._log(effect)
271
277
 
278
+ def node_committed(
279
+ self,
280
+ node: BaseNode,
281
+ patch: Optional[dict[str, Any]] = None,
282
+ meta: Optional[dict[str, Any]] = None,
283
+ ) -> None:
284
+ """Record that a draft node was committed (hash now available)."""
285
+ default_patch = {"text": getattr(node, "text", None)}
286
+ if patch:
287
+ default_patch.update(patch)
288
+ effect = Effect(
289
+ seq=self._next_seq(),
290
+ effect_type="node_committed",
291
+ node=NodeRef.from_node(node),
292
+ patch=default_patch,
293
+ meta=meta or {},
294
+ )
295
+ self.effects.append(effect)
296
+ self._emit(effect)
297
+ self._log(effect)
298
+
272
299
  def node_updated(
273
300
  self,
274
301
  node: BaseNode,
@@ -9,6 +9,7 @@ Also contains ExplorationPipeline — the headless pipeline for programmatic use
9
9
 
10
10
  from __future__ import annotations
11
11
 
12
+ import asyncio
12
13
  from typing import TYPE_CHECKING, Annotated, AsyncGenerator, Optional
13
14
 
14
15
  from mirascope import llm
@@ -230,21 +231,27 @@ class ExplorationPipeline(ReasonableConcern[ExplorationResult]):
230
231
 
231
232
  transformation_count = 0
232
233
 
233
- for wheel_hash in wheel_hashes:
234
+ async def _explore_wheel(wheel_hash: str) -> tuple[int, Optional[StepError]]:
234
235
  try:
235
236
  explore_tr = ExploreTransformations(wheel_hash=wheel_hash)
236
237
  tr_result = await explore_tr.resolve()
237
238
  reports.append(explore_tr.report)
238
- transformation_count += len(tr_result.new)
239
+ return len(tr_result.new), None
239
240
  except Exception as e:
240
- errors.append(
241
- StepError(
242
- step="explore_transformations",
243
- message=str(e),
244
- hash=wheel_hash,
245
- )
241
+ return 0, StepError(
242
+ step="explore_transformations",
243
+ message=str(e),
244
+ hash=wheel_hash,
246
245
  )
247
246
 
247
+ wheel_results = await asyncio.gather(*[
248
+ _explore_wheel(wh) for wh in wheel_hashes
249
+ ])
250
+ for count, error in wheel_results:
251
+ transformation_count += count
252
+ if error:
253
+ errors.append(error)
254
+
248
255
  self._report.ok = True
249
256
  self._report.summary = (
250
257
  f"Exploration complete: {len(cycle_hashes)} cycles, "
@@ -22,8 +22,10 @@ Usage:
22
22
 
23
23
  from __future__ import annotations
24
24
 
25
+ import asyncio
26
+ import logging
25
27
  from dataclasses import dataclass, field
26
- from typing import Annotated, Optional, TYPE_CHECKING
28
+ from typing import Annotated, Any, Optional, TYPE_CHECKING
27
29
 
28
30
  from dependency_injector.wiring import Provide, inject
29
31
  from mirascope import llm
@@ -116,27 +118,47 @@ class ExploreTransformations(ReasonableConcern[ExploreTransformationsResult]):
116
118
  # 3. Get input text from scope
117
119
  input_text = await self._get_input_text()
118
120
 
119
- # 4. Process each edge pair — both edges get Transformations
121
+ # 4. Process edge pairs in parallel — both edges get Transformations
122
+ pair_results = await asyncio.gather(
123
+ *[
124
+ self._process_edge_pair(wheel, nexus, edge_a, edge_b, input_text)
125
+ for edge_a, edge_b in edge_pairs
126
+ ],
127
+ return_exceptions=True,
128
+ )
129
+
120
130
  all_existing: list[Transformation] = []
121
131
  all_new: list[Transformation] = []
122
132
  last_apexes: Optional[ApexDerivationResultDto] = None
123
133
 
124
- for edge_a, edge_b in edge_pairs:
125
- existing, new, apexes = await self._process_edge_pair(
126
- wheel, nexus, edge_a, edge_b, input_text
127
- )
134
+ for result in pair_results:
135
+ if isinstance(result, Exception):
136
+ logging.getLogger(__name__).warning("Edge pair failed: %s", result)
137
+ continue
138
+ existing, new, apexes = result
128
139
  all_existing.extend(existing)
129
140
  all_new.extend(new)
130
141
  if apexes:
131
142
  last_apexes = apexes
132
143
 
133
- # 5. Audit new transformations for feasibility
144
+ # 5. Audit new transformations in parallel
134
145
  if all_new:
135
146
  from dialectical_framework.concerns.transformation_audit import TransformationAudit
136
- for tr in all_new:
147
+
148
+ async def _audit_one(tr: Transformation) -> TransformationAudit:
137
149
  auditor = TransformationAudit()
138
150
  await auditor.resolve(tr, input_text)
139
- self._report = self._report.merge(auditor.report)
151
+ return auditor
152
+
153
+ audit_results = await asyncio.gather(
154
+ *[_audit_one(tr) for tr in all_new],
155
+ return_exceptions=True,
156
+ )
157
+ for result in audit_results:
158
+ if isinstance(result, Exception):
159
+ logging.getLogger(__name__).warning("Audit failed: %s", result)
160
+ continue
161
+ self._report = self._report.merge(result.report)
140
162
 
141
163
  # Summary
142
164
  self._report.artifacts["wheel_hash"] = wheel.short_hash
@@ -166,8 +188,8 @@ class ExploreTransformations(ReasonableConcern[ExploreTransformationsResult]):
166
188
  """
167
189
  Process a diametrically opposite edge pair.
168
190
 
169
- Phase 1: Extract Ac+ candidates for both edges independently.
170
- Phase 2: Generate tetrads for each edge, passing the opposite Ac+ for Re-side.
191
+ Phase 1: Extract Ac+ candidates for both edges in parallel.
192
+ Phase 2: Generate tetrads for all candidates in parallel.
171
193
 
172
194
  Returns:
173
195
  Tuple of (existing, new, apexes)
@@ -176,11 +198,12 @@ class ExploreTransformations(ReasonableConcern[ExploreTransformationsResult]):
176
198
 
177
199
  tr_repo = TransformationRepository()
178
200
  all_existing: list[Transformation] = []
179
- all_new: list[Transformation] = []
180
201
  last_apexes: Optional[ApexDerivationResultDto] = None
181
202
 
182
- # Phase 1: Extract Ac+ for both edges (check existing first)
203
+ # Phase 1: Extract Ac+ for both edges in parallel (check existing first)
204
+ phase1_tasks: list[tuple[Transition, asyncio.Task]] = []
183
205
  edge_data: dict[str, _EdgeProcessingData] = {}
206
+
184
207
  for edge in (edge_a, edge_b):
185
208
  assert edge.hash is not None
186
209
  existing = tr_repo.find_by_edge(edge=edge)
@@ -198,43 +221,50 @@ class ExploreTransformations(ReasonableConcern[ExploreTransformationsResult]):
198
221
  edge_data[edge.hash] = _EdgeProcessingData(skip=True)
199
222
  continue
200
223
 
201
- apex_service = ApexDerivation()
202
- apexes = await apex_service.resolve(edge, input_text)
203
- self._report = self._report.merge(apex_service.report)
204
- last_apexes = apexes
205
-
206
- extractor = ActionExtraction()
207
- ac_candidates = await extractor.resolve(
208
- edge, input_text,
209
- not_like_these=wheel.transformations,
210
- )
211
- self._report = self._report.merge(extractor.report)
212
-
213
224
  edge_data[edge.hash] = _EdgeProcessingData(
214
- ac_candidates=ac_candidates or [],
215
- apexes=apexes,
216
225
  source_segment=source_segment,
217
226
  target_segment=target_segment,
218
227
  )
228
+ phase1_tasks.append((edge, asyncio.ensure_future(
229
+ self._phase1_for_edge(edge, wheel, input_text)
230
+ )))
231
+
232
+ # Await Phase 1 tasks in parallel
233
+ if phase1_tasks:
234
+ results = await asyncio.gather(
235
+ *[t for _, t in phase1_tasks],
236
+ return_exceptions=True,
237
+ )
238
+ for (edge, _), result in zip(phase1_tasks, results):
239
+ assert edge.hash is not None
240
+ if isinstance(result, Exception):
241
+ logging.getLogger(__name__).warning(
242
+ "Phase 1 failed for edge %s: %s", edge.short_hash, result
243
+ )
244
+ edge_data[edge.hash] = _EdgeProcessingData(skip=True)
245
+ continue
246
+ apexes, ac_candidates, report = result
247
+ self._report = self._report.merge(report)
248
+ if apexes:
249
+ last_apexes = apexes
250
+ data = edge_data[edge.hash]
251
+ data.apexes = apexes
252
+ data.ac_candidates = ac_candidates or []
253
+
254
+ # Phase 2: Generate tetrads in parallel
255
+ generation_tasks: list[tuple[Transition, _EdgeProcessingData, ActionCandidateResultDto, asyncio.Task]] = []
219
256
 
220
- # Phase 2: Generate tetrads using opposite Ac+ for Re-side
221
257
  for edge, opposite_edge in [(edge_a, edge_b), (edge_b, edge_a)]:
222
258
  assert edge.hash is not None
223
259
  assert opposite_edge.hash is not None
224
260
  data = edge_data.get(edge.hash)
225
261
  if not data or data.existing or data.skip:
226
262
  continue
227
-
228
263
  if not data.ac_candidates:
229
264
  continue
230
-
231
- source_segment = data.source_segment
232
- target_segment = data.target_segment
233
- apexes = data.apexes
234
- if not source_segment or not target_segment or not apexes:
265
+ if not data.source_segment or not data.target_segment or not data.apexes:
235
266
  continue
236
267
 
237
- # Get opposite edge's Ac+ candidates for Re-side context
238
268
  opp_data = edge_data.get(opposite_edge.hash)
239
269
  opp_ac_candidates = opp_data.ac_candidates if opp_data else []
240
270
 
@@ -245,19 +275,72 @@ class ExploreTransformations(ReasonableConcern[ExploreTransformationsResult]):
245
275
  if not opposite_ac:
246
276
  continue
247
277
 
248
- generator = TransformationGeneration()
249
- tetrad = await generator.resolve(
250
- edge, ac_plus, opposite_ac, apexes, input_text
278
+ task = asyncio.ensure_future(
279
+ self._generate_tetrad(edge, ac_plus, opposite_ac, data.apexes, input_text)
251
280
  )
252
- self._report = self._report.merge(generator.report)
281
+ generation_tasks.append((edge, data, ac_plus, task))
253
282
 
283
+ # Await all generation tasks and create graph nodes sequentially
284
+ all_new: list[Transformation] = []
285
+ if generation_tasks:
286
+ tetrad_results = await asyncio.gather(
287
+ *[t for _, _, _, t in generation_tasks],
288
+ return_exceptions=True,
289
+ )
290
+ for (edge, data, _, _), result in zip(generation_tasks, tetrad_results):
291
+ if isinstance(result, Exception):
292
+ logging.getLogger(__name__).warning(
293
+ "Tetrad generation failed for edge %s: %s", edge.short_hash, result
294
+ )
295
+ continue
296
+ tetrad, report = result
297
+ self._report = self._report.merge(report)
298
+ assert data.source_segment is not None
299
+ assert data.target_segment is not None
254
300
  transformation = self._create_transformation(
255
- nexus, edge, source_segment, target_segment, tetrad,
301
+ nexus, edge, data.source_segment, data.target_segment, tetrad,
256
302
  )
257
303
  all_new.append(transformation)
258
304
 
259
305
  return all_existing, all_new, last_apexes
260
306
 
307
+ async def _phase1_for_edge(
308
+ self,
309
+ edge: Transition,
310
+ wheel: Wheel,
311
+ input_text: str,
312
+ ) -> tuple[Optional[ApexDerivationResultDto], list[ActionCandidateResultDto], Any]:
313
+ """Run ApexDerivation + ActionExtraction for a single edge. Returns (apexes, candidates, merged_report)."""
314
+ from dialectical_framework.agents.execution_report import ExecutionReport
315
+
316
+ merged_report = ExecutionReport(tool=self.__class__.__name__)
317
+
318
+ apex_service = ApexDerivation()
319
+ apexes = await apex_service.resolve(edge, input_text)
320
+ merged_report = merged_report.merge(apex_service.report)
321
+
322
+ extractor = ActionExtraction()
323
+ ac_candidates = await extractor.resolve(
324
+ edge, input_text,
325
+ not_like_these=wheel.transformations,
326
+ )
327
+ merged_report = merged_report.merge(extractor.report)
328
+
329
+ return apexes, ac_candidates or [], merged_report
330
+
331
+ async def _generate_tetrad(
332
+ self,
333
+ edge: Transition,
334
+ ac_plus: ActionCandidateResultDto,
335
+ opposite_ac: ActionCandidateResultDto,
336
+ apexes: ApexDerivationResultDto,
337
+ input_text: str,
338
+ ) -> tuple[TransformationTetradDto, Any]:
339
+ """Run TransformationGeneration for one candidate. Returns (tetrad, report)."""
340
+ generator = TransformationGeneration()
341
+ tetrad = await generator.resolve(edge, ac_plus, opposite_ac, apexes, input_text)
342
+ return tetrad, generator.report
343
+
261
344
  @staticmethod
262
345
  def _find_matching_category(
263
346
  candidates: list[ActionCandidateResultDto],
@@ -451,6 +534,7 @@ class ExploreTransformations(ReasonableConcern[ExploreTransformationsResult]):
451
534
  transformation.set_nexus(nexus)
452
535
  transformation.set_on_edge(ac_edge)
453
536
  transformation.save()
537
+ self._report.node_created(transformation)
454
538
 
455
539
  # === Ac-side (this edge's segments) ===
456
540
 
@@ -611,7 +695,7 @@ class ExploreTransformations(ReasonableConcern[ExploreTransformationsResult]):
611
695
 
612
696
  # Commit transformation
613
697
  transformation.commit()
614
- self._report.node_created(transformation)
698
+ self._report.node_committed(transformation)
615
699
 
616
700
  return transformation
617
701
 
@@ -109,6 +109,7 @@ class GenerateSynthesis(ReasonableConcern[GenerateSynthesisResult]):
109
109
  # Create Synthesis node and wire up
110
110
  synthesis = Synthesis()
111
111
  synthesis.save()
112
+ self._report.node_created(synthesis)
112
113
 
113
114
  synthesis.s_plus.connect(
114
115
  result.s_plus_statement,
@@ -126,7 +127,7 @@ class GenerateSynthesis(ReasonableConcern[GenerateSynthesisResult]):
126
127
  synthesis.commit()
127
128
 
128
129
  # Report
129
- self._report.node_created(synthesis)
130
+ self._report.node_committed(synthesis)
130
131
  self._report.artifacts["wheel"] = wheel.short_hash
131
132
  self._report.artifacts["s_plus"] = result.s_plus_statement.text
132
133
  self._report.artifacts["s_minus"] = result.s_minus_statement.text
@@ -12,11 +12,10 @@ You are working within Nexus [{nexus_hash}]: "{nexus_intent}".
12
12
  ## Context
13
13
 
14
14
  A Nexus groups Perspectives (thesis-antithesis pairs with aspects T+/T-/A+/A-)
15
- for structural combination. Your job is to:
16
- 1. Build the structural combinations (Cycles + Wheels) if not yet done.
17
- 2. Generate Action-Reflection transformations for each Wheel.
18
- 3. Help the user navigate the wisdom: what Ac+ and Re+ mean practically,
19
- how S+ emerges, what pathways are available.
15
+ for structural combination. Your job is to guide the user through three phases:
16
+ 1. **Navigation** — Build and present causal structures (Cycles + Wheels), helping the user understand which causality paths exist and which are most plausible.
17
+ 2. **Insight** — Generate transformations for wheels the user selects, revealing Ac+ and Re+ wisdom.
18
+ 3. **Synthesis** Generate S+/S- for wheels that have transformations.
20
19
 
21
20
  ## How to Work
22
21
 
@@ -24,21 +23,32 @@ On first message (or when resuming):
24
23
  - Call `present_exploration` to see what's been built in this Nexus.
25
24
  - If wheels don't exist yet, call `build_wheels` to create them.
26
25
  - If build_wheels yields no wheels (e.g., only one position), explain that exploration needs at least two positions interacting — suggest the user adds more via the analysis thread.
27
- - If transformations don't exist yet, call `explore_transformations` for each wheel.
28
- - After transformations exist, call `generate_synthesis` to derive S+/S- for each wheel.
26
+
27
+ After wheels exist present the causality landscape:
28
+ - Show which wheels exist and their causality scores (higher = more plausible).
29
+ - Let the user choose which wheel(s) to explore further.
30
+ - Do NOT automatically generate transformations for all wheels.
31
+
32
+ When the user selects a wheel for deeper exploration:
33
+ - Call `explore_transformations` for that specific wheel.
34
+ - Then present the Ac+ and Re+ pathways that emerged.
35
+
36
+ When the user wants synthesis:
37
+ - Call `generate_synthesis` for a wheel that has transformations.
38
+ - Do NOT generate synthesis for all wheels automatically.
29
39
 
30
40
  When presenting transformations:
31
41
  - Focus on the Ac+ (constructive action: T- -> A+) and Re+ (constructive reflection: A- -> T+).
32
- - These are the circular causality paths -- the non-obvious synthetic wisdom.
42
+ - These are the circular causality paths the non-obvious synthetic wisdom.
33
43
  - Explain what they mean practically for the user's situation.
34
44
  - Use the haiku and headline to make it memorable.
35
45
 
36
46
  When the user asks "what should I do?":
37
- - Draw from Ac+ paths -- these are concrete actions.
47
+ - Draw from Ac+ paths these are concrete actions.
38
48
  - Frame them as transitions from an exaggerated position to a constructive opposite.
39
49
 
40
50
  When the user asks "what should I reflect on?":
41
- - Draw from Re+ paths -- these are reflective shifts.
51
+ - Draw from Re+ paths these are reflective shifts.
42
52
  - Frame them as moving from underdevelopment to constructive balance.
43
53
 
44
54
  When the user wants to go deeper on a specific transformation:
@@ -47,13 +57,14 @@ When the user wants to go deeper on a specific transformation:
47
57
 
48
58
  ## Tools
49
59
 
50
- - `build_wheels` -- Generate causal structures (Cycles + Wheels) from this Nexus. Use nexus_hash: "{nexus_hash}".
51
- - `explore_transformations` -- Generate Action-Reflection transformations for a Wheel.
52
- - `generate_synthesis` -- Generate S+/S- synthesis for a Wheel. Requires transformations first.
53
- - `present_exploration` -- Show current state of this Nexus: perspectives, wheels, transformations.
54
- - `inspect_node` -- Deep-dive any node by hash.
55
- - `query_graph` -- Raw Cypher for custom queries. Call `get_schema` first.
56
- - `get_schema` -- Load graph schema on demand.
60
+ - `build_wheels` Generate causal structures (Cycles + Wheels) from this Nexus. Use nexus_hash: "{nexus_hash}".
61
+ - `explore_transformations` Generate Action-Reflection transformations for a specific Wheel the user chose.
62
+ - `generate_synthesis` Generate S+/S- synthesis for a Wheel. Requires transformations first.
63
+ - `expand_nexus` Add more Perspectives to this Nexus.
64
+ - `present_exploration` Show current state of this Nexus: perspectives, wheels, transformations.
65
+ - `inspect_node` Deep-dive any node by hash.
66
+ - `query_graph` Raw Cypher for custom queries. Call `get_schema` first.
67
+ - `get_schema` — Load graph schema on demand.
57
68
 
58
69
  ## Response Style
59
70
 
@@ -66,4 +77,5 @@ Adapt depth and presentation to the persona defined in the app preamble.
66
77
  - When referencing structural nodes (Polarity, Perspective, Nexus, Cycle, Wheel, Transformation, Transition, Synthesis), always include the short hash for disambiguation.
67
78
  - If the user wants to analyze new material, suggest they return to the analysis thread.
68
79
  - Skill reports may contain truncated text previews. When you need to present exact node text to the user, use `inspect_node` or `present_analysis` by hash — never reconstruct or guess full text from truncated previews.
80
+ - Do NOT eagerly explore all wheels or generate all syntheses. Let the user navigate and choose.
69
81
  """
@@ -387,6 +387,7 @@ class PerspectiveCombination(ReasonableConcern[CombinationResult]):
387
387
  # Create new wheel
388
388
  wheel = Wheel(intent=cycle.intent)
389
389
  wheel.save()
390
+ self._report.node_created(wheel)
390
391
 
391
392
  # Create transitions forming the circular causality sequence
392
393
  for i in range(len(components)):
@@ -407,7 +408,7 @@ class PerspectiveCombination(ReasonableConcern[CombinationResult]):
407
408
  cycle.wheels.connect(wheel)
408
409
 
409
410
  wheel.commit()
410
- self._report.node_created(wheel)
411
+ self._report.node_committed(wheel)
411
412
  self._report.relationship_created(cycle.wheels, cycle, wheel)
412
413
 
413
414
  all_wheels.append(wheel)
@@ -0,0 +1,37 @@
1
+ from __future__ import annotations
2
+
3
+ import asyncio
4
+ import os
5
+ from contextlib import asynccontextmanager
6
+ from typing import AsyncIterator
7
+
8
+ _semaphore: asyncio.Semaphore | None = None
9
+ _disabled: bool | None = None
10
+
11
+
12
+ def _init() -> None:
13
+ global _semaphore, _disabled
14
+ if _disabled is not None:
15
+ return
16
+ raw = os.environ.get("DIALEXITY_MAX_CONCURRENT_LLM_CALLS", "0")
17
+ try:
18
+ limit = int(raw)
19
+ except ValueError:
20
+ limit = 0
21
+ if limit > 0:
22
+ _semaphore = asyncio.Semaphore(limit)
23
+ _disabled = False
24
+ else:
25
+ _disabled = True
26
+
27
+
28
+ @asynccontextmanager
29
+ async def llm_concurrency_slot() -> AsyncIterator[None]:
30
+ """Acquire a concurrency slot for an LLM call. Disabled by default (no-op)."""
31
+ _init()
32
+ if _disabled:
33
+ yield
34
+ else:
35
+ assert _semaphore is not None
36
+ async with _semaphore:
37
+ yield