dialectical-framework 1.6.6__tar.gz → 1.6.8__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 (196) hide show
  1. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/PKG-INFO +1 -1
  2. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/pyproject.toml +1 -1
  3. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/agents/advisor/advisor.py +38 -9
  4. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/agents/advisor/system_prompts.py +91 -19
  5. dialectical_framework-1.6.8/src/dialectical_framework/agents/advisor/tools/sync.py +32 -0
  6. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/agents/analyst/analyst.py +17 -2
  7. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/agents/analyst/system_prompts.py +10 -0
  8. dialectical_framework-1.6.8/src/dialectical_framework/agents/app_spec.py +119 -0
  9. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/agents/apps.py +6 -0
  10. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/agents/explorer/explorer.py +15 -1
  11. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/agents/orchestrator/tools/inspect_node.py +14 -2
  12. dialectical_framework-1.6.8/src/dialectical_framework/agents/toolsets.py +33 -0
  13. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/concerns/action_extraction.py +3 -2
  14. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/concerns/control_statements_check.py +74 -11
  15. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/concerns/dialectical_context.py +167 -15
  16. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/concerns/positive_ac_re_apex_derivation.py +1 -1
  17. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/concerns/scoring_scales.py +10 -5
  18. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/concerns/statement_classification.py +138 -53
  19. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/concerns/synthesis_generation.py +5 -1
  20. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/concerns/transformation_generation.py +4 -0
  21. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/graph/nodes/assessable_entity.py +1 -1
  22. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/graph/nodes/estimation.py +26 -0
  23. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/graph/nodes/perspective.py +11 -0
  24. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/settings.py +10 -2
  25. dialectical_framework-1.6.6/src/dialectical_framework/agents/advisor/tools/sync.py +0 -20
  26. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/LICENSE +0 -0
  27. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/PATENTS +0 -0
  28. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/README.md +0 -0
  29. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/__init__.py +0 -0
  30. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/agents/__init__.py +0 -0
  31. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/agents/advisor/__init__.py +0 -0
  32. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/agents/advisor/tools/__init__.py +0 -0
  33. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/agents/advisor/tools/anchor.py +0 -0
  34. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/agents/advisor/tools/deepen.py +0 -0
  35. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/agents/advisor/tools/explore.py +0 -0
  36. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/agents/advisor/tools/ingest.py +0 -0
  37. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/agents/advisor/tools/scoped.py +0 -0
  38. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/agents/agent_context.py +0 -0
  39. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/agents/analyst/__init__.py +0 -0
  40. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/agents/analyst/skills/__init__.py +0 -0
  41. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/agents/analyst/skills/anchor_theses.py +0 -0
  42. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/agents/analyst/skills/edit_perspective.py +0 -0
  43. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/agents/analyst/skills/expand_polarities.py +0 -0
  44. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/agents/analyst/skills/find_polarities.py +0 -0
  45. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/agents/analyst/skills/introduce_polarity.py +0 -0
  46. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/agents/analyst/skills/surface_theses.py +0 -0
  47. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/agents/analyst/tools/__init__.py +0 -0
  48. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/agents/analyst/tools/place_statement.py +0 -0
  49. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/agents/conversation_facilitator.py +0 -0
  50. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/agents/execution_report.py +0 -0
  51. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/agents/explorer/__init__.py +0 -0
  52. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/agents/explorer/skills/__init__.py +0 -0
  53. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/agents/explorer/skills/build_wheels.py +0 -0
  54. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/agents/explorer/skills/explore_transformations.py +0 -0
  55. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/agents/explorer/skills/generate_synthesis.py +0 -0
  56. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/agents/explorer/system_prompts.py +0 -0
  57. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/agents/explorer/tools/__init__.py +0 -0
  58. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/agents/explorer/tools/create_nexus.py +0 -0
  59. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/agents/explorer/tools/expand_nexus.py +0 -0
  60. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/agents/explorer/tools/generate_synthesis.py +0 -0
  61. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/agents/explorer/tools/present_exploration.py +0 -0
  62. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/agents/orchestrator/__init__.py +0 -0
  63. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/agents/orchestrator/tools/__init__.py +0 -0
  64. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/agents/orchestrator/tools/add_input.py +0 -0
  65. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/agents/orchestrator/tools/create_dx_input.py +0 -0
  66. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/agents/orchestrator/tools/digest_input.py +0 -0
  67. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/agents/orchestrator/tools/discard.py +0 -0
  68. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/agents/orchestrator/tools/get_schema.py +0 -0
  69. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/agents/orchestrator/tools/present_analysis.py +0 -0
  70. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/agents/orchestrator/tools/query_graph.py +0 -0
  71. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/agents/orchestrator/tools/read_digest.py +0 -0
  72. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/agents/orchestrator/tools/read_input.py +0 -0
  73. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/agents/reasonable_concern.py +0 -0
  74. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/agents/stream_events.py +0 -0
  75. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/concerns/__init__.py +0 -0
  76. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/concerns/ac_re_taxonomy.py +0 -0
  77. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/concerns/add_input.py +0 -0
  78. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/concerns/ai_dto/__init__.py +0 -0
  79. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/concerns/ai_dto/statement_dto.py +0 -0
  80. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/concerns/ai_dto/statements_deck_dto.py +0 -0
  81. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/concerns/antithesis_classification.py +0 -0
  82. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/concerns/antithesis_extraction.py +0 -0
  83. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/concerns/antithetical_thesis_detection.py +0 -0
  84. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/concerns/aspect_classification.py +0 -0
  85. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/concerns/aspect_generation.py +0 -0
  86. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/concerns/causality/__init__.py +0 -0
  87. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/concerns/causality/causality_estimator.py +0 -0
  88. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/concerns/causality/causality_estimator_balanced.py +0 -0
  89. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/concerns/causality/causality_estimator_criteria.py +0 -0
  90. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/concerns/causality/causality_estimator_desirable.py +0 -0
  91. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/concerns/causality/causality_estimator_feasible.py +0 -0
  92. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/concerns/causality/causality_estimator_realistic.py +0 -0
  93. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/concerns/causality/causality_normalizer.py +0 -0
  94. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/concerns/causality/estimator_resolver.py +0 -0
  95. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/concerns/causality_estimation.py +0 -0
  96. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/concerns/create_dx_input.py +0 -0
  97. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/concerns/create_nexus.py +0 -0
  98. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/concerns/diagonal_oppositions_check.py +0 -0
  99. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/concerns/discard.py +0 -0
  100. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/concerns/display_text_edit.py +0 -0
  101. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/concerns/expand_nexus.py +0 -0
  102. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/concerns/perspective_combination.py +0 -0
  103. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/concerns/perspective_validation.py +0 -0
  104. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/concerns/source_digest.py +0 -0
  105. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/concerns/statement_deduplication.py +0 -0
  106. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/concerns/statement_headline.py +0 -0
  107. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/concerns/statement_placement.py +0 -0
  108. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/concerns/thesis_extraction.py +0 -0
  109. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/concerns/transformation_audit.py +0 -0
  110. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/dialectical_reasoning.py +0 -0
  111. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/enums/__init__.py +0 -0
  112. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/enums/causality_preset.py +0 -0
  113. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/enums/di.py +0 -0
  114. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/events/__init__.py +0 -0
  115. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/events/graph_event.py +0 -0
  116. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/events/graph_event_bus.py +0 -0
  117. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/exceptions/__init__.py +0 -0
  118. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/exceptions/node_errors.py +0 -0
  119. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/exceptions/resolver_errors.py +0 -0
  120. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/graph/__init__.py +0 -0
  121. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/graph/composite_input_resolver.py +0 -0
  122. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/graph/dialexity_input_resolver.py +0 -0
  123. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/graph/estimation_manager.py +0 -0
  124. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/graph/mixins/__init__.py +0 -0
  125. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/graph/mixins/incremental_build_mixin.py +0 -0
  126. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/graph/mixins/intent_mixin.py +0 -0
  127. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/graph/mixins/persistable_mixin.py +0 -0
  128. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/graph/nodes/__init__.py +0 -0
  129. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/graph/nodes/base_node.py +0 -0
  130. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/graph/nodes/case.py +0 -0
  131. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/graph/nodes/cycle.py +0 -0
  132. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/graph/nodes/ideas.py +0 -0
  133. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/graph/nodes/input.py +0 -0
  134. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/graph/nodes/nexus.py +0 -0
  135. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/graph/nodes/polarity.py +0 -0
  136. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/graph/nodes/rationale.py +0 -0
  137. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/graph/nodes/statement.py +0 -0
  138. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/graph/nodes/synthesis.py +0 -0
  139. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/graph/nodes/transformation.py +0 -0
  140. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/graph/nodes/transition.py +0 -0
  141. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/graph/nodes/wheel.py +0 -0
  142. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/graph/relationship_manager.py +0 -0
  143. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/graph/relationships/__init__.py +0 -0
  144. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/graph/relationships/action_reflection_relationship.py +0 -0
  145. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/graph/relationships/belongs_to_cycle_relationship.py +0 -0
  146. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/graph/relationships/belongs_to_nexus_relationship.py +0 -0
  147. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/graph/relationships/changed_to_relationship.py +0 -0
  148. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/graph/relationships/contradiction_of_relationship.py +0 -0
  149. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/graph/relationships/critiques_relationship.py +0 -0
  150. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/graph/relationships/distilled_to_relationship.py +0 -0
  151. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/graph/relationships/estimates_relationship.py +0 -0
  152. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/graph/relationships/explains_relationship.py +0 -0
  153. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/graph/relationships/has_input_relationship.py +0 -0
  154. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/graph/relationships/has_statement_relationship.py +0 -0
  155. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/graph/relationships/has_wheel_relationship.py +0 -0
  156. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/graph/relationships/immutable_structure.py +0 -0
  157. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/graph/relationships/is_source_of_relationship.py +0 -0
  158. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/graph/relationships/is_target_of_relationship.py +0 -0
  159. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/graph/relationships/negative_side_of_relationship.py +0 -0
  160. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/graph/relationships/opposite_direction_relationship.py +0 -0
  161. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/graph/relationships/opposite_of_relationship.py +0 -0
  162. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/graph/relationships/polarity_relationship.py +0 -0
  163. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/graph/relationships/positive_side_of_relationship.py +0 -0
  164. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/graph/relationships/provides_relationship.py +0 -0
  165. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/graph/relationships/synthesis_of_relationship.py +0 -0
  166. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/graph/rendering.py +0 -0
  167. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/graph/repositories/__init__.py +0 -0
  168. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/graph/repositories/case_repository.py +0 -0
  169. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/graph/repositories/cycle_repository.py +0 -0
  170. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/graph/repositories/input_repository.py +0 -0
  171. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/graph/repositories/nexus_repository.py +0 -0
  172. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/graph/repositories/node_repository.py +0 -0
  173. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/graph/repositories/perspective_repository.py +0 -0
  174. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/graph/repositories/polarity_repository.py +0 -0
  175. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/graph/repositories/schema_repository.py +0 -0
  176. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/graph/repositories/statement_repository.py +0 -0
  177. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/graph/repositories/transformation_repository.py +0 -0
  178. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/graph/repositories/wheel_repository.py +0 -0
  179. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/graph/scope_context.py +0 -0
  180. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/graph/verbatim_input_resolver.py +0 -0
  181. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/graph/wheel_segment.py +0 -0
  182. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/graph/wheel_segment_polar_pair.py +0 -0
  183. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/protocols/__init__.py +0 -0
  184. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/protocols/has_config.py +0 -0
  185. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/protocols/input_resolver.py +0 -0
  186. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/utils/__init__.py +0 -0
  187. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/utils/bedrock_provider.py +0 -0
  188. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/utils/concurrency.py +0 -0
  189. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/utils/dc_replace.py +0 -0
  190. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/utils/decompose_probability_uniformly.py +0 -0
  191. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/utils/edge_context.py +0 -0
  192. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/utils/effect_logger.py +0 -0
  193. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/utils/input_context.py +0 -0
  194. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/utils/order_transitions.py +0 -0
  195. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/utils/sequence_generation.py +0 -0
  196. {dialectical_framework-1.6.6 → dialectical_framework-1.6.8}/src/dialectical_framework/utils/use_brain.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: dialectical-framework
3
- Version: 1.6.6
3
+ Version: 1.6.8
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.6.6"
3
+ version = "1.6.8"
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"
@@ -17,12 +17,14 @@ from typing import AsyncGenerator, Optional
17
17
 
18
18
  from pydantic import BaseModel, Field
19
19
 
20
- from dialectical_framework.agents.advisor.system_prompts import (
21
- SYSTEM_PROMPT, system_prompt)
20
+ from dialectical_framework.agents.advisor.system_prompts import \
21
+ system_prompt
22
22
  from dialectical_framework.agents.agent_context import agent_scope
23
23
  from dialectical_framework.agents.conversation_facilitator import \
24
24
  ConversationFacilitator
25
+ from dialectical_framework.agents.app_spec import AppSpec, resolve_app_layer
25
26
  from dialectical_framework.agents.stream_events import StreamEvent
27
+ from dialectical_framework.agents.toolsets import merge_app_tools
26
28
 
27
29
  logger = logging.getLogger(__name__)
28
30
 
@@ -69,6 +71,18 @@ class Advisor:
69
71
  advisor = Advisor(app_preamble=COUNSELOR_APP, messages=saved_messages)
70
72
  response = await advisor.chat("What about the other angle?")
71
73
 
74
+ Usage (app-provided domain tools):
75
+ # The app brings field knowledge two ways: prose in the preamble,
76
+ # and callable resources as app @llm.tool functions. The engine
77
+ # prompt carries no docs for app tools (their tool-schema docstrings
78
+ # travel to the LLM automatically) — introduce them and their usage
79
+ # rules in the app preamble, where domain vocabulary lives.
80
+ with scope(case.sid):
81
+ advisor = Advisor(
82
+ app_preamble=ASTRO_COUNSELOR_APP, # explains when to consult the chart
83
+ app_tools=[lookup_natal_chart], # @llm.tool from the app
84
+ )
85
+
72
86
  Usage (Advisor mode of an exploration session — Explorer handover):
73
87
  # User was chatting in Explorer (operator mode) and asks "what does
74
88
  # this all mean for me?" — the host toggles to counsel mode by
@@ -104,13 +118,28 @@ class Advisor:
104
118
  dialectical_context: Optional[str] = None,
105
119
  messages: Optional[list] = None,
106
120
  nexus_hash: Optional[str] = None,
121
+ app_tools: Optional[list] = None,
122
+ app: Optional[AppSpec] = None,
107
123
  ) -> None:
108
124
  self._nexus_hash = nexus_hash
125
+ # app: declarative app definition — composition depends on the mode:
126
+ # counsel toggle (nexus_hash set) keeps the Navigator contract
127
+ # (EXPLORATION_ADVISOR_APP + voicing + tool_guide); standalone uses
128
+ # the spec's advisor_persona (machinery hidden). See AppSpec.
129
+ app_preamble, app_tools = resolve_app_layer(
130
+ app,
131
+ app_preamble,
132
+ app_tools,
133
+ preamble_for="advisor_scoped" if nexus_hash else "advisor_unscoped",
134
+ )
109
135
  if nexus_hash:
110
136
  self._validate_nexus(nexus_hash)
111
137
  self._tools = _build_scoped_tools(nexus_hash)
112
138
  else:
113
139
  self._tools = _build_tools()
140
+ # App-provided @llm.tool functions (domain resources: chart lookups,
141
+ # methodology references, ...) — see toolsets.merge_app_tools.
142
+ self._tools = merge_app_tools(self._tools, app_tools)
114
143
  self._conversation = ConversationFacilitator(tools=self._tools)
115
144
  if messages:
116
145
  self._conversation._messages = list(messages)
@@ -144,13 +173,13 @@ class Advisor:
144
173
  dialectical_context
145
174
  or "No prior understanding — this is a fresh conversation."
146
175
  )
147
- if self._nexus_hash:
148
- engine = system_prompt(
149
- tool_names=[t.__name__ for t in self._tools],
150
- scoped_nexus_hash=self._nexus_hash,
151
- )
152
- else:
153
- engine = SYSTEM_PROMPT
176
+ # Rendered at construction (not the import-time SYSTEM_PROMPT
177
+ # constant) so settings-derived prompt values (max_wheel_layer)
178
+ # reflect the live DI configuration.
179
+ engine = system_prompt(
180
+ tool_names=[t.__name__ for t in self._tools],
181
+ scoped_nexus_hash=self._nexus_hash,
182
+ )
154
183
  parts.append(engine.replace("{dialectical_context}", context_text))
155
184
 
156
185
  return "\n\n".join(parts)
@@ -34,6 +34,51 @@ def _ladder_lines(scale: dict[str, float], annotations: dict[float, str]) -> str
34
34
  return "\n".join(lines)
35
35
 
36
36
 
37
+ def _resolve_max_wheel_layer() -> int:
38
+ """The live settings.max_wheel_layer, falling back to the Pydantic field
39
+ default when DI isn't wired (e.g. the import-time SYSTEM_PROMPT render).
40
+ """
41
+ from dialectical_framework.settings import Settings
42
+
43
+ try:
44
+ from dialectical_framework.protocols.has_config import SettingsAware
45
+
46
+ value = SettingsAware().settings.max_wheel_layer
47
+ if isinstance(value, int) and value >= 1:
48
+ return value
49
+ except Exception:
50
+ pass
51
+ return Settings.model_fields["max_wheel_layer"].default
52
+
53
+
54
+ def _nexus_evolution(cap: int) -> str:
55
+ """Render the explore doc's 'How a nexus evolves' ladder from the live
56
+ wheel-layer cap (settings.max_wheel_layer), so the prompt's nexus-size
57
+ guidance never drifts from what PerspectiveCombination actually builds.
58
+ """
59
+ lines = [
60
+ " How a nexus evolves:",
61
+ " - 1 perspective: a single self-referential wheel. Already generates",
62
+ " transformations and synthesis — useful even alone.",
63
+ ]
64
+ if cap >= 2:
65
+ lines += [
66
+ " - 2 perspectives: the causal question emerges (which thesis enables which?).",
67
+ " Produces multiple wheels (arrangements), each with its own pathways.",
68
+ ]
69
+ if cap >= 3:
70
+ span = f"3-{cap}" if cap > 3 else "3"
71
+ lines += [
72
+ f" - {span} perspectives: richer causal chains, more transformation variety,",
73
+ " deeper synthesis. The sweet spot for insight.",
74
+ ]
75
+ lines.append(
76
+ f" - >{cap}: combinatorial explosion — arrangements aren't built beyond"
77
+ f" {cap} perspectives; start a new nexus for more tensions."
78
+ )
79
+ return "\n".join(lines)
80
+
81
+
37
82
  _ROLE = """## Role
38
83
 
39
84
  You are in conversation with someone navigating a decision, tension, or
@@ -277,14 +322,7 @@ _TOOL_DOCS: dict[str, str] = {
277
322
  and sibling nexuses on one theme fragment the pathways. Create separate
278
323
  nexuses only for genuinely distinct themes.
279
324
 
280
- How a nexus evolves:
281
- - 1 perspective: a single self-referential wheel. Already generates
282
- transformations and synthesis — useful even alone.
283
- - 2 perspectives: the causal question emerges (which thesis enables which?).
284
- Produces multiple wheels (arrangements), each with its own pathways.
285
- - 3-4 perspectives: richer causal chains, more transformation variety,
286
- deeper synthesis. The sweet spot for insight.
287
- - >4: combinatorial explosion — cap at 4, start a new nexus for more tensions.
325
+ {nexus_evolution}
288
326
 
289
327
  Grouping principle: prefer perspectives from different polarities (different
290
328
  T-A oppositions) — transformations between them represent genuine synthesis
@@ -314,11 +352,15 @@ _TOOL_DOCS: dict[str, str] = {
314
352
  them. Deepening only adds analytical depth to existing structure — it
315
353
  never changes what the exploration contains, so no consent ceremony is
316
354
  needed. Harmless on already-developed wheels.""",
317
- "sync": """- `sync` — Re-reads the full graph state. Use when you need a fresh full
318
- picture — e.g., after multiple ingest/anchor calls, to see all perspectives
319
- with scores before deciding what to group for explore. NOT needed after every
320
- tool call (ingest/anchor/explore return their results directly), and NOT
321
- needed at conversation start — the full state is already in your context.""",
355
+ "sync": """- `sync` — Re-reads the graph state. Without arguments: the full picture —
356
+ e.g., after multiple ingest/anchor calls, to see all perspectives with
357
+ scores before deciding what to group for explore. With a `nexus_hash`:
358
+ zooms into that one exploration in full depth — the overview caps wheels
359
+ per cycle for compactness, the zoom does not. Zoom when counsel settles on
360
+ one exploration and you need arrangements the overview truncated. NOT
361
+ needed after every tool call (ingest/anchor/explore return their results
362
+ directly), and NOT needed at conversation start — the full state is
363
+ already in your context.""",
322
364
  "sync_scoped": """- `sync` — Re-reads this exploration's state. Use when you need a fresh
323
365
  picture after changes. NOT needed at conversation start — the exploration
324
366
  is already in your context.""",
@@ -485,6 +527,22 @@ Use `inspect_node` when you want to understand the reasoning behind a score,
485
527
  explain WHY a specific blindspot exists, or ground a pathway recommendation
486
528
  in the actual analytical logic rather than restating the dump.
487
529
 
530
+ **Cross-exploration correspondences.** When several explorations coexist,
531
+ some perspectives carry correspondence lines — machine-stated facts, not
532
+ suggestions: "Also woven into Nexus [[x]]" (literally the same tension in
533
+ both explorations) and "Same opposition family (...) as perspective N in
534
+ [[x]]" (both tensions anchored to the same deep-structure category). These
535
+ are your invitation to draw parallels across the person's situations —
536
+ often the most powerful counsel move available: the same structural dynamic
537
+ playing out in two arenas of their life means an insight earned in one
538
+ transfers to the other. But family-level correspondence is coarse (few
539
+ families exist, collisions are common) — before drawing the parallel, check
540
+ it holds in substance: read both tetrads and confirm the dynamics actually
541
+ mirror each other, not just the category. The family name itself (Integrity,
542
+ Fire, ...) is framework vocabulary — the How You Speak rules above govern
543
+ it like any other; by default, name what the two tensions share in the
544
+ person's own terms, not the category label.
545
+
488
546
  **Sequences are circular causality.** Both Cycle and Wheel sequences are
489
547
  closed loops — they start and end with the same element (e.g., "T1 → T2 → T1..."
490
548
  or "T1 → A2 → A1 → T2 → T1..."). The "..." indicates the circle continues.
@@ -520,6 +578,13 @@ Use these scores to prioritize what you draw on:
520
578
  - `rectangularity`: Tetrad balance (lower = better).
521
579
  <0.01 = well-balanced. 0.01–0.09 = mild imbalance, acceptable.
522
580
  >0.09 = one side overdeveloped — note the imbalance.
581
+ - `DV`: Dialectical validity — how NATURAL the tension's dynamics are
582
+ (higher = the poles genuinely complement each other and the pathologies
583
+ arise organically; lower = the framing is forced, one-sided, or held
584
+ together by coercion/ideology rather than natural dynamics). Comparative
585
+ signal, no fixed cutoff: prefer high-DV tensions when choosing what to
586
+ build counsel on, and treat a low-DV tension as a hint the framing itself
587
+ may be distorted — consider re-anchoring rather than polishing aspects.
523
588
  - `Ks` on aspects: Complementarity toward synthesis.
524
589
  T+/A+ should be >0.4 (constructive poles complement the whole).
525
590
  T-/A- should be <0.6 (destructive poles don't overpower).
@@ -549,12 +614,13 @@ Use these scores to prioritize what you draw on:
549
614
 
550
615
  **Prioritization rules:**
551
616
 
552
- The dump is pre-pruned: tensions below the quality floor (weak opposition,
553
- blurred structure, failed validation) and low-probability wheels are already
554
- suppressed — count lines note what was filtered. Everything you see passed
555
- the floor; you rank within it, you don't re-filter.
617
+ The dump is pre-pruned: tensions below the quality floors (weak opposition,
618
+ blurred structure, unnatural/distorted framing, failed validation) and
619
+ low-probability wheels are already suppressed — count lines note what was
620
+ filtered. Everything you see passed the floors; you rank within them, you
621
+ don't re-filter.
556
622
 
557
- 1. Lead with the strongest tensions (highest HS on A, best area). Softer
623
+ 1. Lead with the strongest tensions (highest HS on A, best area, best DV). Softer
558
624
  ones are still visible by design — usable, and they may resonate with
559
625
  the person's lived experience, but don't build your primary counsel
560
626
  around them.
@@ -635,7 +701,13 @@ def system_prompt(
635
701
  # Scoped variants of sync/explore have their own doc text.
636
702
  key = f"{name}_scoped" if scoped and f"{name}_scoped" in _TOOL_DOCS else name
637
703
  if key in _TOOL_DOCS:
638
- tool_docs.append(_TOOL_DOCS[key])
704
+ doc = _TOOL_DOCS[key]
705
+ if "{nexus_evolution}" in doc:
706
+ doc = doc.replace(
707
+ "{nexus_evolution}",
708
+ _nexus_evolution(_resolve_max_wheel_layer()),
709
+ )
710
+ tool_docs.append(doc)
639
711
 
640
712
  conversation_use = _CONVERSATION_USE
641
713
  if scoped and "ingest" not in names:
@@ -0,0 +1,32 @@
1
+ """
2
+ sync tool: Re-read the dialectical graph state.
3
+
4
+ Returns a structured dump of tensions, pathways, and synthesis for the
5
+ current case scope. With `nexus_hash`, zooms into one exploration and
6
+ renders it in full depth (the unscoped dump caps wheels per cycle for
7
+ compactness; the zoomed render is exempt, same as counsel-mode dumps).
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ from typing import Annotated
13
+
14
+ from mirascope import llm
15
+ from pydantic import Field
16
+
17
+ from dialectical_framework.concerns.dialectical_context import \
18
+ DialecticalContext
19
+
20
+
21
+ @llm.tool
22
+ async def sync(
23
+ nexus_hash: Annotated[
24
+ str | None,
25
+ Field(
26
+ description="Zoom into one exploration: render only this nexus, in full depth (no wheel cap). Omit for the full-case overview."
27
+ ),
28
+ ] = None,
29
+ ) -> str:
30
+ """Re-read the graph state. Without arguments: the full picture across all explorations (compact — wheels capped per cycle). With a nexus_hash: one exploration in full depth. Use the zoom when counsel centers on one exploration and the overview's capped view isn't enough."""
31
+ concern = DialecticalContext(nexus_hash=nexus_hash)
32
+ return await concern.resolve()
@@ -20,7 +20,9 @@ from dialectical_framework.agents.analyst.system_prompts import SYSTEM_PROMPT
20
20
  from dialectical_framework.agents.conversation_facilitator import \
21
21
  ConversationFacilitator
22
22
  from dialectical_framework.agents.reasonable_concern import ReasonableConcern
23
+ from dialectical_framework.agents.app_spec import AppSpec, resolve_app_layer
23
24
  from dialectical_framework.agents.stream_events import StreamEvent
25
+ from dialectical_framework.agents.toolsets import merge_app_tools
24
26
 
25
27
  if TYPE_CHECKING:
26
28
  pass
@@ -48,13 +50,17 @@ class Analyst:
48
50
 
49
51
  Usage:
50
52
  with scope(case.sid):
51
- analyst = Analyst(app_preamble="You are a counselor...")
53
+ analyst = Analyst(app=MY_APP_SPEC) # declarative (see AppSpec)
52
54
  response = await analyst.chat("I'm struggling with work-life balance")
53
55
 
54
56
  # Resuming with history:
55
57
  with scope(case.sid):
56
58
  analyst = Analyst(messages=loaded_messages)
57
59
  response = await analyst.chat("What about the second tension?")
60
+
61
+ # Manual preamble control (app_preamble replaces AppSpec composition):
62
+ with scope(case.sid):
63
+ analyst = Analyst(app_preamble="You are a counselor...")
58
64
  """
59
65
 
60
66
  AGENT_NAME = "analyst"
@@ -63,8 +69,17 @@ class Analyst:
63
69
  self,
64
70
  app_preamble: Optional[str] = None,
65
71
  messages: Optional[list] = None,
72
+ app_tools: Optional[list] = None,
73
+ app: Optional[AppSpec] = None,
66
74
  ) -> None:
67
- self._tools = _build_tools()
75
+ # app: declarative app definition — the framework composes the
76
+ # Navigator preamble (NAVIGATOR_APP + voicing + tool_guide) and tool
77
+ # set from it. app_preamble/app_tools remain for manual control;
78
+ # mixing them with app= raises (see app_spec.resolve_app_layer).
79
+ app_preamble, app_tools = resolve_app_layer(
80
+ app, app_preamble, app_tools, preamble_for="navigator"
81
+ )
82
+ self._tools = merge_app_tools(_build_tools(), app_tools)
68
83
  self._conversation = ConversationFacilitator(tools=self._tools)
69
84
  if messages:
70
85
  self._conversation._messages = list(messages)
@@ -130,6 +130,16 @@ the user wants it fixed; absent = not validated (neutral). Communicate the
130
130
  verdict as meaning ("this one held up under the coherence check"), not as a
131
131
  flag name.
132
132
 
133
+ Validation also scores `DV` (dialectical validity) — how NATURAL the
134
+ tension's dynamics are, separate from coherence: high DV means the poles
135
+ genuinely complement each other and the pathologies arise organically; low
136
+ DV means the framing itself is forced or one-sided even if it reads
137
+ coherently. A low-DV tension is better re-framed (`edit_perspective` or
138
+ discard-and-re-anchor) than polished aspect-by-aspect — the distortion sits
139
+ in the T/A framing, not the aspects. Note: counsel mode prunes very-low-DV
140
+ tensions from its working view, so a framing you keep here may be absent
141
+ there — re-framing it fixes both.
142
+
133
143
  ## Exploration Setup (Nexus)
134
144
 
135
145
  "Nexus" is the internal name for what the user calls an **Exploration** — same
@@ -0,0 +1,119 @@
1
+ """
2
+ AppSpec: declarative app definition — the host describes WHAT its app is,
3
+ each agent head composes the right preamble from it.
4
+
5
+ Without this, an app developer must know framework lore to preamble an app:
6
+ which base constant belongs to which head (NAVIGATOR_APP for Analyst/Explorer,
7
+ EXPLORATION_ADVISOR_APP for the counsel toggle, bare persona for a standalone
8
+ Advisor), that later preamble sections override earlier ones, and that the
9
+ same tool guide must be repeated into every head's preamble. AppSpec owns
10
+ that lore: the app supplies only its custom pieces, the framework supplies
11
+ the generic contract.
12
+
13
+ Usage:
14
+ ASTRO_APP = AppSpec(
15
+ voicing=\"\"\"## Astrological Voicing
16
+ Phrase oppositions in elemental and zodiacal terms where natural...\"\"\",
17
+ advisor_persona=\"\"\"## Persona
18
+ You are a wise astrologer. The person seeks counsel through their chart...\"\"\",
19
+ tool_guide=\"\"\"## Chart Resources
20
+ - lookup_natal_chart(person): fetch a natal chart. Use when...\"\"\",
21
+ tools=[lookup_natal_chart],
22
+ )
23
+
24
+ Analyst(app=ASTRO_APP)
25
+ Explorer(nexus_hash=nx, messages=msgs, app=ASTRO_APP)
26
+ Advisor(nexus_hash=nx, messages=msgs, app=ASTRO_APP) # counsel toggle
27
+ Advisor(app=ASTRO_APP) # standalone advisor
28
+
29
+ Every field is optional — an AppSpec with only `voicing` is a pure
30
+ re-skinning of the Navigator; one with only `tools` + `tool_guide` adds
31
+ domain resources without touching voice. The low-level `app_preamble` /
32
+ `app_tools` constructor params remain for full manual control; passing
33
+ both `app` and either of them raises (ambiguous composition).
34
+ """
35
+
36
+ from __future__ import annotations
37
+
38
+ from dataclasses import dataclass, field
39
+ from typing import Optional
40
+
41
+
42
+ @dataclass(frozen=True)
43
+ class AppSpec:
44
+ """Declarative definition of a host app, composed per agent head.
45
+
46
+ voicing: Domain flavor layered on the Navigator user contract
47
+ (Analyst/Explorer and the counsel toggle). Vocabulary direction,
48
+ framing, domain emphasis — NOT tool docs, NOT persona for the
49
+ standalone Advisor.
50
+ advisor_persona: Persona for the STANDALONE (unscoped) Advisor, where
51
+ the machinery is hidden and the preamble is the entire user-facing
52
+ identity (like COUNSELOR_APP). Ignored in counsel-toggle mode,
53
+ which keeps the Navigator contract.
54
+ tool_guide: Shared documentation for the app's tools — what each does,
55
+ when to reach for it. Included verbatim in EVERY head's preamble
56
+ so the usage rules cannot drift between heads. How tool use
57
+ SURFACES to the user still follows each head's disclosure rules.
58
+ tools: App-provided @llm.tool functions, passed to every head
59
+ (see toolsets.merge_app_tools).
60
+ """
61
+
62
+ voicing: Optional[str] = None
63
+ advisor_persona: Optional[str] = None
64
+ tool_guide: Optional[str] = None
65
+ tools: list = field(default_factory=list)
66
+
67
+ def navigator_preamble(self, advanced: bool = False) -> str:
68
+ """Preamble for Analyst/Explorer heads: Navigator contract + app pieces."""
69
+ from dialectical_framework.agents.apps import (
70
+ NAVIGATOR_ADVANCED_MODE_APP, NAVIGATOR_APP)
71
+
72
+ base = NAVIGATOR_ADVANCED_MODE_APP if advanced else NAVIGATOR_APP
73
+ return _join(base, self.voicing, self.tool_guide)
74
+
75
+ def advisor_preamble(self, scoped: bool) -> str:
76
+ """Preamble for the Advisor head.
77
+
78
+ scoped=True (counsel toggle of a Navigator session): the Navigator
79
+ contract survives the toggle — EXPLORATION_ADVISOR_APP + app pieces.
80
+ scoped=False (standalone Advisor): the persona IS the identity —
81
+ no Navigator base, machinery stays hidden.
82
+ """
83
+ from dialectical_framework.agents.apps import EXPLORATION_ADVISOR_APP
84
+
85
+ if scoped:
86
+ return _join(EXPLORATION_ADVISOR_APP, self.voicing, self.tool_guide)
87
+ return _join(self.advisor_persona, self.tool_guide)
88
+
89
+
90
+ def _join(*parts: Optional[str]) -> str:
91
+ return "\n\n".join(p.strip() for p in parts if p and p.strip())
92
+
93
+
94
+ def resolve_app_layer(
95
+ app: Optional[AppSpec],
96
+ app_preamble: Optional[str],
97
+ app_tools: Optional[list],
98
+ preamble_for: str, # "navigator" | "advisor_scoped" | "advisor_unscoped"
99
+ ) -> tuple[Optional[str], Optional[list]]:
100
+ """Resolve the (preamble, tools) pair from either an AppSpec or the
101
+ low-level params. Mixing both raises — composition would be ambiguous
102
+ (does app_preamble replace the spec's derived preamble or stack on it?).
103
+ """
104
+ if app is None:
105
+ return app_preamble, app_tools
106
+ if app_preamble is not None or app_tools is not None:
107
+ raise ValueError(
108
+ "Pass either app= (declarative) or app_preamble=/app_tools= "
109
+ "(manual), not both."
110
+ )
111
+ if preamble_for == "navigator":
112
+ preamble = app.navigator_preamble()
113
+ elif preamble_for == "advisor_scoped":
114
+ preamble = app.advisor_preamble(scoped=True)
115
+ elif preamble_for == "advisor_unscoped":
116
+ preamble = app.advisor_preamble(scoped=False)
117
+ else:
118
+ raise ValueError(f"Unknown preamble_for: {preamble_for}")
119
+ return preamble or None, app.tools or None
@@ -19,6 +19,12 @@ There are two territories:
19
19
  Apps define HOW the agents communicate — vocabulary, depth, framing, persona.
20
20
  They are injected by the host application at agent construction time.
21
21
 
22
+ The recommended host interface is `AppSpec` (agents/app_spec.py): the app
23
+ declares its custom pieces (voicing, advisor_persona, tool_guide, tools) and
24
+ each agent head composes the right base from THIS module itself — hosts never
25
+ concatenate these constants by hand. Direct `app_preamble=` passing remains
26
+ for full manual control.
27
+
22
28
  Prompt Revision Methodology
23
29
  ===========================
24
30
  When fixing LLM output bugs in these prompts, use /df-review-reasoning-layer for the
@@ -20,7 +20,9 @@ from dialectical_framework.agents.conversation_facilitator import \
20
20
  ConversationFacilitator
21
21
  from dialectical_framework.agents.explorer.system_prompts import system_prompt
22
22
  from dialectical_framework.agents.reasonable_concern import ReasonableConcern
23
+ from dialectical_framework.agents.app_spec import AppSpec, resolve_app_layer
23
24
  from dialectical_framework.agents.stream_events import StreamEvent
25
+ from dialectical_framework.agents.toolsets import merge_app_tools
24
26
  from dialectical_framework.graph.repositories.nexus_repository import \
25
27
  NexusRepository
26
28
 
@@ -66,9 +68,21 @@ class Explorer:
66
68
  nexus_hash: str,
67
69
  app_preamble: Optional[str] = None,
68
70
  messages: Optional[list] = None,
71
+ app_tools: Optional[list] = None,
72
+ app: Optional[AppSpec] = None,
69
73
  ) -> None:
70
74
  self._nexus_hash = nexus_hash
71
- self._tools = _build_tools()
75
+ # app: declarative app definition (Navigator base + voicing +
76
+ # tool_guide + tools) — see AppSpec. Pass the SAME AppSpec to every
77
+ # head (Analyst, Explorer, Advisor): the Explorer<->Advisor toggle
78
+ # shares literal history (a missing tool breaks capability
79
+ # mid-conversation), and the Analyst thread owes the user the same
80
+ # domain resources by parity. For advanced-mode preambles compose
81
+ # manually: app_preamble=my_app.navigator_preamble(advanced=True).
82
+ app_preamble, app_tools = resolve_app_layer(
83
+ app, app_preamble, app_tools, preamble_for="navigator"
84
+ )
85
+ self._tools = merge_app_tools(_build_tools(), app_tools)
72
86
  self._conversation = ConversationFacilitator(tools=self._tools)
73
87
 
74
88
  if messages:
@@ -149,6 +149,8 @@ from pydantic import Field
149
149
 
150
150
  from dialectical_framework.agents.reasonable_concern import ReasonableConcern
151
151
  from dialectical_framework.enums.di import DI
152
+ from dialectical_framework.graph.nodes.estimation import \
153
+ DialecticalValidityEstimation
152
154
  from dialectical_framework.graph.rendering import (
153
155
  build_pp_index,
154
156
  component_alias,
@@ -215,7 +217,11 @@ def _inspect_perspective(pp: Perspective) -> str:
215
217
  # Tetrad quality metrics
216
218
  diff_t = pp.diff_t
217
219
  diff_a = pp.diff_a
218
- area = pp.area_normalized
220
+ # Raw area (= theory's SP, -2..2) — the scale every band/gate/prompt in the
221
+ # system speaks (settings min_sp, advisor bands, dialectical_context).
222
+ # area_normalized (area/2) is a UI-only hint; showing it here under a
223
+ # different scale than the Advisor's dump confused cross-surface reads.
224
+ area = pp.area
219
225
  rect = pp.rectangularity
220
226
  metrics: list[str] = []
221
227
  if diff_t is not None:
@@ -223,9 +229,15 @@ def _inspect_perspective(pp: Perspective) -> str:
223
229
  if diff_a is not None:
224
230
  metrics.append(f"diff_a={diff_a:.3f}")
225
231
  if area is not None:
226
- metrics.append(f"area_normalized={area:.3f}")
232
+ metrics.append(f"area={area:.3f}")
227
233
  if rect is not None:
228
234
  metrics.append(f"rect={rect:.4f}")
235
+ # DV (Dialectical Validity, paper's naturalness companion to SP) — read
236
+ # from the persisted estimation, annotation only.
237
+ for est, _ in pp.estimations.all():
238
+ if isinstance(est, DialecticalValidityEstimation):
239
+ metrics.append(f"DV={est.value:.3f}")
240
+ break
229
241
  if metrics:
230
242
  lines.append(f"Quality: {', '.join(metrics)}")
231
243
 
@@ -0,0 +1,33 @@
1
+ """
2
+ Shared helper for merging app-provided tools into an agent's built-in set.
3
+
4
+ All three conversational agents (Analyst, Explorer, Advisor) expose an
5
+ `app_tools` constructor parameter — the app-side seam for domain
6
+ resources (chart lookups, methodology references, knowledge-base fetches).
7
+ The merge rules are identical across agents, so they live here.
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ from typing import Optional
13
+
14
+
15
+ def merge_app_tools(builtin: list, app_tools: Optional[list]) -> list:
16
+ """Append app-provided @llm.tool functions to an agent's built-in set.
17
+
18
+ The agent's system prompt has no docs for app tools and skips unknown
19
+ names — apps describe them in the app preamble, where domain vocabulary
20
+ lives; the tool schemas (name, params, docstring) reach the LLM through
21
+ the tool protocol itself.
22
+
23
+ Raises:
24
+ ValueError: If an app tool shadows a built-in tool name — the app
25
+ tool would silently hijack framework machinery.
26
+ """
27
+ if not app_tools:
28
+ return builtin
29
+ builtin_names = {t.__name__ for t in builtin}
30
+ collisions = [t.__name__ for t in app_tools if t.__name__ in builtin_names]
31
+ if collisions:
32
+ raise ValueError(f"app_tools shadow built-in tools: {collisions}")
33
+ return builtin + list(app_tools)
@@ -111,8 +111,9 @@ APEX
111
111
  2. Must help transition FROM T- (problem) TOWARD A+ (benefit)
112
112
  3. Must NOT simply restate A+ - it's the PATH, not the destination
113
113
  4. Should be generative: enable discovery rather than prescribe specific outcomes
114
- 5. Length: a fuller actionable form, longer than the headline
115
- 6. Choose the insight level that best matches the nature of the action
114
+ 5. Must stay subtle, not forceful: an action that imposes, coerces, or overpowers reverses its polarity from Ac+ to Ac-. Prefer enabling over forcing
115
+ 6. Length: a fuller actionable form, longer than the headline
116
+ 7. Choose the insight level that best matches the nature of the action
116
117
  """
117
118
 
118
119