dialectical-framework 1.6.8__tar.gz → 1.7.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/PKG-INFO +1 -1
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/pyproject.toml +1 -1
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/agents/advisor/advisor.py +25 -11
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/agents/advisor/system_prompts.py +192 -23
- dialectical_framework-1.7.1/src/dialectical_framework/agents/advisor/tools/record_decision.py +85 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/agents/advisor/tools/scoped.py +19 -9
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/agents/analyst/analyst.py +3 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/agents/analyst/skills/edit_perspective.py +4 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/agents/analyst/skills/expand_polarities.py +27 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/agents/analyst/skills/introduce_polarity.py +3 -1
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/agents/analyst/system_prompts.py +11 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/agents/app_spec.py +7 -7
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/agents/apps.py +167 -89
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/agents/explorer/explorer.py +3 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/agents/explorer/system_prompts.py +9 -0
- dialectical_framework-1.7.1/src/dialectical_framework/agents/orchestrator/tools/discard.py +23 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/agents/orchestrator/tools/get_schema.py +3 -1
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/agents/orchestrator/tools/inspect_node.py +48 -1
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/concerns/aspect_generation.py +45 -0
- dialectical_framework-1.7.1/src/dialectical_framework/concerns/decision_coherence_check.py +199 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/concerns/dialectical_context.py +88 -10
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/concerns/discard.py +31 -2
- dialectical_framework-1.7.1/src/dialectical_framework/concerns/record_decision.py +257 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/concerns/statement_classification.py +6 -3
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/dialectical_reasoning.py +14 -2
- dialectical_framework-1.7.1/src/dialectical_framework/exceptions/node_errors.py +27 -0
- dialectical_framework-1.7.1/src/dialectical_framework/graph/nodes/decision.py +151 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/graph/relationship_manager.py +7 -0
- dialectical_framework-1.7.1/src/dialectical_framework/graph/relationships/grounded_in_relationship.py +31 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/graph/rendering.py +59 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/graph/repositories/cycle_repository.py +3 -1
- dialectical_framework-1.7.1/src/dialectical_framework/graph/repositories/decision_repository.py +81 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/graph/repositories/nexus_repository.py +1 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/graph/repositories/wheel_repository.py +1 -1
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/graph/scope_context.py +27 -0
- dialectical_framework-1.6.8/src/dialectical_framework/agents/orchestrator/tools/discard.py +0 -23
- dialectical_framework-1.6.8/src/dialectical_framework/exceptions/node_errors.py +0 -10
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/LICENSE +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/PATENTS +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/README.md +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/__init__.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/agents/__init__.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/agents/advisor/__init__.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/agents/advisor/tools/__init__.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/agents/advisor/tools/anchor.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/agents/advisor/tools/deepen.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/agents/advisor/tools/explore.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/agents/advisor/tools/ingest.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/agents/advisor/tools/sync.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/agents/agent_context.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/agents/analyst/__init__.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/agents/analyst/skills/__init__.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/agents/analyst/skills/anchor_theses.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/agents/analyst/skills/find_polarities.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/agents/analyst/skills/surface_theses.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/agents/analyst/tools/__init__.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/agents/analyst/tools/place_statement.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/agents/conversation_facilitator.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/agents/execution_report.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/agents/explorer/__init__.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/agents/explorer/skills/__init__.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/agents/explorer/skills/build_wheels.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/agents/explorer/skills/explore_transformations.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/agents/explorer/skills/generate_synthesis.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/agents/explorer/tools/__init__.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/agents/explorer/tools/create_nexus.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/agents/explorer/tools/expand_nexus.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/agents/explorer/tools/generate_synthesis.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/agents/explorer/tools/present_exploration.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/agents/orchestrator/__init__.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/agents/orchestrator/tools/__init__.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/agents/orchestrator/tools/add_input.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/agents/orchestrator/tools/create_dx_input.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/agents/orchestrator/tools/digest_input.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/agents/orchestrator/tools/present_analysis.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/agents/orchestrator/tools/query_graph.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/agents/orchestrator/tools/read_digest.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/agents/orchestrator/tools/read_input.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/agents/reasonable_concern.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/agents/stream_events.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/agents/toolsets.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/concerns/__init__.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/concerns/ac_re_taxonomy.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/concerns/action_extraction.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/concerns/add_input.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/concerns/ai_dto/__init__.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/concerns/ai_dto/statement_dto.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/concerns/ai_dto/statements_deck_dto.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/concerns/antithesis_classification.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/concerns/antithesis_extraction.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/concerns/antithetical_thesis_detection.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/concerns/aspect_classification.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/concerns/causality/__init__.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/concerns/causality/causality_estimator.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/concerns/causality/causality_estimator_balanced.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/concerns/causality/causality_estimator_criteria.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/concerns/causality/causality_estimator_desirable.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/concerns/causality/causality_estimator_feasible.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/concerns/causality/causality_estimator_realistic.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/concerns/causality/causality_normalizer.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/concerns/causality/estimator_resolver.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/concerns/causality_estimation.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/concerns/control_statements_check.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/concerns/create_dx_input.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/concerns/create_nexus.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/concerns/diagonal_oppositions_check.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/concerns/display_text_edit.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/concerns/expand_nexus.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/concerns/perspective_combination.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/concerns/perspective_validation.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/concerns/positive_ac_re_apex_derivation.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/concerns/scoring_scales.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/concerns/source_digest.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/concerns/statement_deduplication.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/concerns/statement_headline.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/concerns/statement_placement.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/concerns/synthesis_generation.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/concerns/thesis_extraction.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/concerns/transformation_audit.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/concerns/transformation_generation.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/enums/__init__.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/enums/causality_preset.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/enums/di.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/events/__init__.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/events/graph_event.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/events/graph_event_bus.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/exceptions/__init__.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/exceptions/resolver_errors.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/graph/__init__.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/graph/composite_input_resolver.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/graph/dialexity_input_resolver.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/graph/estimation_manager.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/graph/mixins/__init__.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/graph/mixins/incremental_build_mixin.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/graph/mixins/intent_mixin.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/graph/mixins/persistable_mixin.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/graph/nodes/__init__.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/graph/nodes/assessable_entity.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/graph/nodes/base_node.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/graph/nodes/case.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/graph/nodes/cycle.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/graph/nodes/estimation.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/graph/nodes/ideas.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/graph/nodes/input.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/graph/nodes/nexus.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/graph/nodes/perspective.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/graph/nodes/polarity.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/graph/nodes/rationale.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/graph/nodes/statement.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/graph/nodes/synthesis.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/graph/nodes/transformation.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/graph/nodes/transition.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/graph/nodes/wheel.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/graph/relationships/__init__.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/graph/relationships/action_reflection_relationship.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/graph/relationships/belongs_to_cycle_relationship.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/graph/relationships/belongs_to_nexus_relationship.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/graph/relationships/changed_to_relationship.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/graph/relationships/contradiction_of_relationship.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/graph/relationships/critiques_relationship.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/graph/relationships/distilled_to_relationship.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/graph/relationships/estimates_relationship.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/graph/relationships/explains_relationship.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/graph/relationships/has_input_relationship.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/graph/relationships/has_statement_relationship.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/graph/relationships/has_wheel_relationship.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/graph/relationships/immutable_structure.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/graph/relationships/is_source_of_relationship.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/graph/relationships/is_target_of_relationship.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/graph/relationships/negative_side_of_relationship.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/graph/relationships/opposite_direction_relationship.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/graph/relationships/opposite_of_relationship.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/graph/relationships/polarity_relationship.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/graph/relationships/positive_side_of_relationship.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/graph/relationships/provides_relationship.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/graph/relationships/synthesis_of_relationship.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/graph/repositories/__init__.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/graph/repositories/case_repository.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/graph/repositories/input_repository.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/graph/repositories/node_repository.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/graph/repositories/perspective_repository.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/graph/repositories/polarity_repository.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/graph/repositories/schema_repository.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/graph/repositories/statement_repository.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/graph/repositories/transformation_repository.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/graph/verbatim_input_resolver.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/graph/wheel_segment.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/graph/wheel_segment_polar_pair.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/protocols/__init__.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/protocols/has_config.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/protocols/input_resolver.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/settings.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/utils/__init__.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/utils/bedrock_provider.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/utils/concurrency.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/utils/dc_replace.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/utils/decompose_probability_uniformly.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/utils/edge_context.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/utils/effect_logger.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/utils/input_context.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/utils/order_transitions.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/src/dialectical_framework/utils/sequence_generation.py +0 -0
- {dialectical_framework-1.6.8 → dialectical_framework-1.7.1}/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.
|
|
3
|
+
Version: 1.7.1
|
|
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.
|
|
3
|
+
version = "1.7.1"
|
|
4
4
|
description = "A dialectical framework for augmented intelligence. AI reasoning powered with dialectics supports humans in: system optimization (psychology, engineering, business, politics, etc.); dispute resolution (mediation, conflicts, negotiations, etc.); decision-making (dilemmas, challenging situations, win-win, etc.)."
|
|
5
5
|
authors = ["Evaldas Taroza <evaldas@dialexity.com>"]
|
|
6
6
|
readme = "README.md"
|
|
@@ -20,6 +20,7 @@ from pydantic import BaseModel, Field
|
|
|
20
20
|
from dialectical_framework.agents.advisor.system_prompts import \
|
|
21
21
|
system_prompt
|
|
22
22
|
from dialectical_framework.agents.agent_context import agent_scope
|
|
23
|
+
from dialectical_framework.graph.scope_context import require_current_sid
|
|
23
24
|
from dialectical_framework.agents.conversation_facilitator import \
|
|
24
25
|
ConversationFacilitator
|
|
25
26
|
from dialectical_framework.agents.app_spec import AppSpec, resolve_app_layer
|
|
@@ -57,18 +58,18 @@ class Advisor:
|
|
|
57
58
|
|
|
58
59
|
Usage (fresh start):
|
|
59
60
|
with scope(case.sid):
|
|
60
|
-
advisor = Advisor(app_preamble=
|
|
61
|
+
advisor = Advisor(app_preamble=COUNSELOR_PERSONA)
|
|
61
62
|
response = await advisor.chat("My son started smoking...")
|
|
62
63
|
|
|
63
64
|
Usage (post-analysis, rich graph exists):
|
|
64
65
|
with scope(case.sid):
|
|
65
66
|
context = await DialecticalContext().resolve()
|
|
66
|
-
advisor = Advisor(app_preamble=
|
|
67
|
+
advisor = Advisor(app_preamble=COUNSELOR_PERSONA, dialectical_context=context)
|
|
67
68
|
response = await advisor.chat("I want to talk through what we found...")
|
|
68
69
|
|
|
69
70
|
Usage (resuming conversation):
|
|
70
71
|
with scope(case.sid):
|
|
71
|
-
advisor = Advisor(app_preamble=
|
|
72
|
+
advisor = Advisor(app_preamble=COUNSELOR_PERSONA, messages=saved_messages)
|
|
72
73
|
response = await advisor.chat("What about the other angle?")
|
|
73
74
|
|
|
74
75
|
Usage (app-provided domain tools):
|
|
@@ -79,7 +80,7 @@ class Advisor:
|
|
|
79
80
|
# rules in the app preamble, where domain vocabulary lives.
|
|
80
81
|
with scope(case.sid):
|
|
81
82
|
advisor = Advisor(
|
|
82
|
-
app_preamble=
|
|
83
|
+
app_preamble=ASTRO_COUNSELOR_PERSONA, # explains when to consult the chart
|
|
83
84
|
app_tools=[lookup_natal_chart], # @llm.tool from the app
|
|
84
85
|
)
|
|
85
86
|
|
|
@@ -90,7 +91,7 @@ class Advisor:
|
|
|
90
91
|
# exploration:
|
|
91
92
|
with scope(case.sid):
|
|
92
93
|
advisor = Advisor(
|
|
93
|
-
app_preamble=
|
|
94
|
+
app_preamble=NAVIGATOR_APP_EXPLORER_AGENT_COUNSELOR_REGISTER,
|
|
94
95
|
nexus_hash=explorer.nexus_hash,
|
|
95
96
|
messages=explorer.messages,
|
|
96
97
|
)
|
|
@@ -120,11 +121,19 @@ class Advisor:
|
|
|
120
121
|
nexus_hash: Optional[str] = None,
|
|
121
122
|
app_tools: Optional[list] = None,
|
|
122
123
|
app: Optional[AppSpec] = None,
|
|
124
|
+
principal: str = "human",
|
|
123
125
|
) -> None:
|
|
126
|
+
# principal: WHO confirms decisions in this conversation — a host
|
|
127
|
+
# attestation, fixed for the session (the counterpart doesn't change
|
|
128
|
+
# mid-conversation). "human" = an actual person; a delegated driver
|
|
129
|
+
# (agent-to-agent runs) must pass its own identity ("agent:<name>"
|
|
130
|
+
# or <provider>/<model>) so recorded decisions never claim human
|
|
131
|
+
# confirmation they didn't get. Closed over by record_decision —
|
|
132
|
+
# never an LLM-visible parameter.
|
|
124
133
|
self._nexus_hash = nexus_hash
|
|
125
134
|
# app: declarative app definition — composition depends on the mode:
|
|
126
135
|
# counsel toggle (nexus_hash set) keeps the Navigator contract
|
|
127
|
-
# (
|
|
136
|
+
# (NAVIGATOR_APP_EXPLORER_AGENT_COUNSELOR_REGISTER + voicing + tool_guide); standalone uses
|
|
128
137
|
# the spec's advisor_persona (machinery hidden). See AppSpec.
|
|
129
138
|
app_preamble, app_tools = resolve_app_layer(
|
|
130
139
|
app,
|
|
@@ -134,9 +143,9 @@ class Advisor:
|
|
|
134
143
|
)
|
|
135
144
|
if nexus_hash:
|
|
136
145
|
self._validate_nexus(nexus_hash)
|
|
137
|
-
self._tools = _build_scoped_tools(nexus_hash)
|
|
146
|
+
self._tools = _build_scoped_tools(nexus_hash, principal)
|
|
138
147
|
else:
|
|
139
|
-
self._tools = _build_tools()
|
|
148
|
+
self._tools = _build_tools(principal)
|
|
140
149
|
# App-provided @llm.tool functions (domain resources: chart lookups,
|
|
141
150
|
# methodology references, ...) — see toolsets.merge_app_tools.
|
|
142
151
|
self._tools = merge_app_tools(self._tools, app_tools)
|
|
@@ -185,12 +194,14 @@ class Advisor:
|
|
|
185
194
|
return "\n\n".join(parts)
|
|
186
195
|
|
|
187
196
|
async def chat(self, user_message: str) -> str:
|
|
197
|
+
require_current_sid() # unscoped turns silently drop all work
|
|
188
198
|
with agent_scope(self.AGENT_NAME):
|
|
189
199
|
await self._render_pending_context()
|
|
190
200
|
result = await self._conversation.submit(ChatResponse, user_message)
|
|
191
201
|
return result.message
|
|
192
202
|
|
|
193
203
|
async def chat_stream(self, user_message: str) -> AsyncGenerator[StreamEvent, None]:
|
|
204
|
+
require_current_sid() # unscoped turns silently drop all work
|
|
194
205
|
with agent_scope(self.AGENT_NAME):
|
|
195
206
|
await self._render_pending_context()
|
|
196
207
|
async for event in self._conversation.submit_stream(
|
|
@@ -233,11 +244,13 @@ class Advisor:
|
|
|
233
244
|
return self._conversation._messages
|
|
234
245
|
|
|
235
246
|
|
|
236
|
-
def _build_tools() -> list:
|
|
247
|
+
def _build_tools(principal: str = "human") -> list:
|
|
237
248
|
from dialectical_framework.agents.advisor.tools.anchor import anchor
|
|
238
249
|
from dialectical_framework.agents.advisor.tools.deepen import deepen
|
|
239
250
|
from dialectical_framework.agents.advisor.tools.explore import explore
|
|
240
251
|
from dialectical_framework.agents.advisor.tools.ingest import ingest
|
|
252
|
+
from dialectical_framework.agents.advisor.tools.record_decision import \
|
|
253
|
+
build_record_decision
|
|
241
254
|
from dialectical_framework.agents.advisor.tools.sync import sync
|
|
242
255
|
from dialectical_framework.agents.orchestrator.tools.inspect_node import \
|
|
243
256
|
inspect_node
|
|
@@ -251,6 +264,7 @@ def _build_tools() -> list:
|
|
|
251
264
|
anchor,
|
|
252
265
|
explore,
|
|
253
266
|
deepen,
|
|
267
|
+
build_record_decision(principal),
|
|
254
268
|
sync,
|
|
255
269
|
inspect_node,
|
|
256
270
|
read_digest,
|
|
@@ -258,8 +272,8 @@ def _build_tools() -> list:
|
|
|
258
272
|
]
|
|
259
273
|
|
|
260
274
|
|
|
261
|
-
def _build_scoped_tools(nexus_hash: str) -> list:
|
|
275
|
+
def _build_scoped_tools(nexus_hash: str, principal: str = "human") -> list:
|
|
262
276
|
from dialectical_framework.agents.advisor.tools.scoped import \
|
|
263
277
|
build_scoped_tools
|
|
264
278
|
|
|
265
|
-
return build_scoped_tools(nexus_hash)
|
|
279
|
+
return build_scoped_tools(nexus_hash, principal)
|
|
@@ -125,7 +125,7 @@ understanding you've built.
|
|
|
125
125
|
The narrow exceptions where no analysis is called for: greetings and small
|
|
126
126
|
talk, logistics ("can you repeat that?"), pure information requests, and
|
|
127
127
|
moments of grief or crisis where presence matters more than analysis.
|
|
128
|
-
|
|
128
|
+
{decision_filter_note}
|
|
129
129
|
Your response to the person never waits on the machinery — speak from what
|
|
130
130
|
you have. Analysis deepens your next turn; it never delays or deforms this one."""
|
|
131
131
|
|
|
@@ -255,6 +255,101 @@ You now have the integration vision. Use it to:
|
|
|
255
255
|
- Frame synthesis as something they GROW INTO, not something they implement
|
|
256
256
|
in one move. It emerges from sustained Ac+ and Re+ working together."""
|
|
257
257
|
|
|
258
|
+
_DECISION_READINESS = """## Decision Readiness (Convergence)
|
|
259
|
+
|
|
260
|
+
Much of your counsel serves a decision the person must actually make. Mapping
|
|
261
|
+
tensions opens the space; a decision needs the space to CLOSE. These rules
|
|
262
|
+
govern the closing — they apply whenever the conversation is decision-shaped
|
|
263
|
+
(the person is choosing, not just understanding):
|
|
264
|
+
|
|
265
|
+
**The decision bounds the search.** In decision mode, run the search backward
|
|
266
|
+
from the choice: "what would have to be true for this option to be wrong?" —
|
|
267
|
+
not forward from the material. Options are finite; each has a finite set of
|
|
268
|
+
load-bearing assumptions.
|
|
269
|
+
|
|
270
|
+
**Named options (when the choice arrives as "X or Y").** Anchor the pair as
|
|
271
|
+
it comes — the person's own framing is the map they'll recognize. But an
|
|
272
|
+
option-pair is usually a bundle: the options differ along several tensions
|
|
273
|
+
at once, and one tetrad captures one of them. So ask which pull matters most
|
|
274
|
+
before mapping deeper — the person enumerates cheaply what the machinery
|
|
275
|
+
maps expensively — and anchor the same pair again (identical wording) for an
|
|
276
|
+
alternative tetrad only when their reactions show the mapped dimension isn't
|
|
277
|
+
the one the choice turns on. Alternative tetrads are readings of the choice
|
|
278
|
+
itself, not new candidate tensions — the discrimination test below governs
|
|
279
|
+
those. Each perspective names its reading (the dimension its aspects oppose
|
|
280
|
+
along); when a reading strongly resonates — the person keeps returning to
|
|
281
|
+
that dimension — it is itself an anchor candidate: anchor it as its own
|
|
282
|
+
tension (its two poles as thesis and antithesis) to give the root its full
|
|
283
|
+
structure. When weaving, take the reading that resonates plus the tensions
|
|
284
|
+
beyond the fork; sibling readings of one pair only shift the angle. And read
|
|
285
|
+
the anchor result at call time: options that merely differ rather than
|
|
286
|
+
oppose show up as weak opposition (low HS) or a low mode (drifting/absence
|
|
287
|
+
rather than negation) — then the fork is not where the tension is. Keep the
|
|
288
|
+
pair as the person's frame, but also anchor each option alone to discover
|
|
289
|
+
what genuinely opposes it, instead of forcing the menu into a tension it
|
|
290
|
+
doesn't contain.
|
|
291
|
+
|
|
292
|
+
**Discrimination test (when NOT to map).** Before anchoring a new candidate
|
|
293
|
+
tension, ask: if this tension resolved either way, would the person lean
|
|
294
|
+
differently? If not, acknowledge it in conversation but do not map it —
|
|
295
|
+
mapping that cannot change the choice is noise dressed as diligence. But if
|
|
296
|
+
the person wants it mapped anyway, map it: their lived reality outranks the
|
|
297
|
+
test, and what feels load-bearing to them often is.
|
|
298
|
+
|
|
299
|
+
**Saturation.** Surface framings are endless; deep structure is not. When new
|
|
300
|
+
tensions keep landing in already-mapped opposition families (when
|
|
301
|
+
correspondence lines appear in your understanding they are this signal;
|
|
302
|
+
otherwise judge whether the new framing's deep structure matches a mapped
|
|
303
|
+
tension), say so plainly: new framings are collapsing into tensions already
|
|
304
|
+
mapped. Never claim "we found all tensions"; completeness belongs only to
|
|
305
|
+
causal arrangements, which are enumerated systematically for the tensions
|
|
306
|
+
woven in. Tensions saturate; they are never exhausted.
|
|
307
|
+
|
|
308
|
+
**Pre-commit ritual (earned confidence, soft).** Before proposing to record,
|
|
309
|
+
have the choice face its strongest test: name what the unchosen side offers —
|
|
310
|
+
its genuine contribution — and ask whether they can say what choosing costs
|
|
311
|
+
them. Name the trap version of the choice (the resolution that is actually
|
|
312
|
+
one side dominating). A decision that has faced both is earned; record that
|
|
313
|
+
confrontation in the rationale. If the person says "just record it," record
|
|
314
|
+
it — their wish outranks the ritual — and note in the rationale that the cost
|
|
315
|
+
went unconfronted.
|
|
316
|
+
|
|
317
|
+
**Readiness → propose-and-confirm ceremony.** Signals: a leaning is expressed
|
|
318
|
+
and stable, options stopped shifting, recent candidate tensions failed the
|
|
319
|
+
discrimination test. Then — after the ritual above, and only with the
|
|
320
|
+
person's engagement — offer to record the decision. Read the record back in
|
|
321
|
+
their own words: the question, the stance, the why, the accepted cost. Record
|
|
322
|
+
ONLY on their explicit confirmation. A decision is a speech act — it exists
|
|
323
|
+
because they declared it, never because you inferred it. Decisions are NEVER
|
|
324
|
+
recorded silently — whatever else stays behind the scenes, the record is the
|
|
325
|
+
person's artifact, and they must know it exists. Speak of it plainly, in
|
|
326
|
+
their vocabulary — "want me to note this down as your decision, so we can
|
|
327
|
+
hold to it later?" — the record is named in plain words, never as a tool; its
|
|
328
|
+
reference (hash) follows the same disclosure rules as any other node
|
|
329
|
+
reference.
|
|
330
|
+
|
|
331
|
+
**The replacement rule.** Before proposing, check the distilled record
|
|
332
|
+
against the Decisions section of your understanding (and any decisions
|
|
333
|
+
recorded earlier in this conversation): a conflict with a standing decision
|
|
334
|
+
is counsel material, not a silent recording detail — "this would sit against
|
|
335
|
+
what you decided earlier — does it replace that?" If it does, record the new
|
|
336
|
+
decision and, with their consent, retire the old with a reason naming its
|
|
337
|
+
replacement.
|
|
338
|
+
|
|
339
|
+
**After recording — the re-audit.** When a recorded decision exists and a new
|
|
340
|
+
tension or a wobble appears, first ask: does this discriminate against what
|
|
341
|
+
was decided? When it is the already-accepted cost resurfacing, or a framing
|
|
342
|
+
that collapses into what was mapped, reassure FROM the record: they accepted
|
|
343
|
+
this knowingly, here is the recipe they adopted for living with it. That
|
|
344
|
+
reassurance is the record's whole value — but treat the wobble as data
|
|
345
|
+
first, dismissal never: circumstances may genuinely have changed even when
|
|
346
|
+
the wording resembles the accepted cost. If the new tension genuinely
|
|
347
|
+
discriminates — it could change the choice — say so honestly: this reopens
|
|
348
|
+
the decision. Counsel it through, and if a new stance emerges, record it and
|
|
349
|
+
retire the old per the replacement rule above. If a ground of the decision
|
|
350
|
+
has since been discarded, surface that: the record stands, but one of its
|
|
351
|
+
supports moved."""
|
|
352
|
+
|
|
258
353
|
_TOOLS_INTRO = """## Internal Tools
|
|
259
354
|
|
|
260
355
|
Your internal tools — how you think structurally. Use them eagerly and
|
|
@@ -283,8 +378,9 @@ _TOOL_DOCS: dict[str, str] = {
|
|
|
283
378
|
"anchor": """- `anchor` — Plants a specific tension from the conversation. More precise
|
|
284
379
|
than ingest; use when you can see at least the person's position. Two modes:
|
|
285
380
|
- Thesis + antithesis: you know both sides — creates one polarity and one
|
|
286
|
-
perspective (tetrad). Call again with the same T-A
|
|
287
|
-
|
|
381
|
+
perspective (tetrad). Call again with the same T-A (identical wording —
|
|
382
|
+
a rephrase plants a new tension instead) for an alternative tetrad on
|
|
383
|
+
the same opposition.
|
|
288
384
|
- Thesis only: anchors their position and discovers what opposes it — finds
|
|
289
385
|
multiple possible antitheses (each a different polarity), each expanded
|
|
290
386
|
into a perspective. Richer when you want the framework to reveal
|
|
@@ -293,8 +389,9 @@ _TOOL_DOCS: dict[str, str] = {
|
|
|
293
389
|
until woven in with `explore`). Use when you can see at least the person's
|
|
294
390
|
position. Two modes:
|
|
295
391
|
- Thesis + antithesis: you know both sides — creates one polarity and one
|
|
296
|
-
perspective (tetrad). Call again with the same T-A
|
|
297
|
-
|
|
392
|
+
perspective (tetrad). Call again with the same T-A (identical wording —
|
|
393
|
+
a rephrase plants a new tension instead) for an alternative tetrad on
|
|
394
|
+
the same opposition.
|
|
298
395
|
- Thesis only: anchors their position and discovers what opposes it — finds
|
|
299
396
|
multiple possible antitheses (each a different polarity), each expanded
|
|
300
397
|
into a perspective. Richer when you want the framework to reveal
|
|
@@ -352,9 +449,22 @@ _TOOL_DOCS: dict[str, str] = {
|
|
|
352
449
|
them. Deepening only adds analytical depth to existing structure — it
|
|
353
450
|
never changes what the exploration contains, so no consent ceremony is
|
|
354
451
|
needed. Harmless on already-developed wheels.""",
|
|
452
|
+
"record_decision": """- `record_decision` — Records a decision the person has EXPLICITLY
|
|
453
|
+
confirmed, after the propose-and-confirm ceremony (see Decision Readiness).
|
|
454
|
+
Pass the confirmed wording literally: `question` (what was being decided),
|
|
455
|
+
`stance` (the position taken), `rationale` (the distilled why, including
|
|
456
|
+
reasons outside the mapped structure). Pass `grounds` as {hash, role}
|
|
457
|
+
entries: role "accepted_cost" for the unchosen side's contribution they
|
|
458
|
+
confronted, "adopted_pathway" for the pathway adopted as their ongoing
|
|
459
|
+
recipe, no role for plain grounds (tensions weighed, arrangements counseled
|
|
460
|
+
from). The result may carry a coherence verdict — if it flags a
|
|
461
|
+
contradiction, raise it with the person immediately; the record stands
|
|
462
|
+
either way. To replace or retract a recorded decision, use `discard` on it
|
|
463
|
+
(reason naming the newer decision if one replaces it).""",
|
|
355
464
|
"sync": """- `sync` — Re-reads the graph state. Without arguments: the full picture —
|
|
356
465
|
e.g., after multiple ingest/anchor calls, to see all perspectives with
|
|
357
|
-
scores before deciding what to group for
|
|
466
|
+
scores (and any standing decisions) before deciding what to group for
|
|
467
|
+
explore. With a `nexus_hash`:
|
|
358
468
|
zooms into that one exploration in full depth — the overview caps wheels
|
|
359
469
|
per cycle for compactness, the zoom does not. Zoom when counsel settles on
|
|
360
470
|
one exploration and you need arrangements the overview truncated. NOT
|
|
@@ -364,19 +474,24 @@ _TOOL_DOCS: dict[str, str] = {
|
|
|
364
474
|
"sync_scoped": """- `sync` — Re-reads this exploration's state. Use when you need a fresh
|
|
365
475
|
picture after changes. NOT needed at conversation start — the exploration
|
|
366
476
|
is already in your context.""",
|
|
367
|
-
"discard": """- `discard` — Silently retracts something the user rejects. Works on
|
|
368
|
-
perspective (a whole framing — the tension and its aspects)
|
|
369
|
-
(a single claim). Pass the hash from the
|
|
370
|
-
nodes are removed; committed ones are
|
|
371
|
-
reasoning. To drop a tension
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
(cycles/wheels) won't
|
|
477
|
+
"discard": """- `discard` — Silently retracts something the user rejects. Works on a
|
|
478
|
+
perspective (a whole framing — the tension and its aspects), a statement
|
|
479
|
+
(a single claim), or a recorded decision. Pass the hash from the
|
|
480
|
+
anchor/ingest result. Uncommitted nodes are removed; committed ones are
|
|
481
|
+
soft-discarded and filtered from future reasoning. To drop a tension
|
|
482
|
+
entirely, discard the perspective first, then its underlying statement if
|
|
483
|
+
it's no longer wanted (discarding a perspective leaves its shared
|
|
484
|
+
statements intact, and a statement still used by a live perspective won't
|
|
485
|
+
discard). A perspective already woven into pathways (cycles/wheels) won't
|
|
486
|
+
discard — re-anchor the corrected framing instead. Recorded decisions are
|
|
487
|
+
the exception to silence: retire one only after the person explicitly
|
|
488
|
+
confirms, with a reason naming the replacement if one exists.""",
|
|
376
489
|
"discard_scoped": """- `discard` — Retracts something the person no longer stands behind, per the
|
|
377
490
|
consent rules above (confirm for exploration members; a framing you just
|
|
378
|
-
anchored needs no ceremony). Works on
|
|
379
|
-
|
|
491
|
+
anchored needs no ceremony). Works on a perspective (a whole framing), a
|
|
492
|
+
statement (a single claim), or a recorded decision (always confirmed with
|
|
493
|
+
the person first, with a reason naming the replacement if one exists).
|
|
494
|
+
Pass the hash from the anchor result.
|
|
380
495
|
Uncommitted nodes are removed; committed ones are soft-discarded and
|
|
381
496
|
filtered from future reasoning. Members of OTHER explorations refuse.
|
|
382
497
|
A perspective already woven into pathways (cycles/wheels) won't discard —
|
|
@@ -428,7 +543,7 @@ calls for it. It is a compass, not a script:
|
|
|
428
543
|
3. Continue conversation, possibly `anchor` again for new tensions
|
|
429
544
|
4. `explore` → respond with specific paired pathways
|
|
430
545
|
5. Continue with full depth, offer integration vision when they're ready
|
|
431
|
-
|
|
546
|
+
{decision_arc_step}
|
|
432
547
|
Counsel grounded in pathways is stronger than counsel from a single tension;
|
|
433
548
|
counsel from a tension is stronger than counsel from nothing — keep moving the
|
|
434
549
|
understanding deeper as the conversation allows.
|
|
@@ -449,7 +564,7 @@ present findings as structural tables or labeled positions. Do not use
|
|
|
449
564
|
framework terminology (thesis, antithesis, polarity, perspective, nexus,
|
|
450
565
|
wheel, transformation, T+, T-, A+, A-, S+, S-, Ac+, Re+) — unless the app
|
|
451
566
|
preamble above explicitly grants terminology disclosure, in which case the
|
|
452
|
-
preamble's vocabulary rules override this one.
|
|
567
|
+
preamble's vocabulary rules override this one.{decision_speech_note}
|
|
453
568
|
|
|
454
569
|
Speak in the person's own vocabulary about their situation. Statement text
|
|
455
570
|
from the graph is raw material — rephrase it freely into their language;
|
|
@@ -527,6 +642,20 @@ Use `inspect_node` when you want to understand the reasoning behind a score,
|
|
|
527
642
|
explain WHY a specific blindspot exists, or ground a pathway recommendation
|
|
528
643
|
in the actual analytical logic rather than restating the dump.
|
|
529
644
|
|
|
645
|
+
**Decisions:** The dump may contain a Decisions section — the person's
|
|
646
|
+
standing decisions, each recorded with their explicit confirmation: the
|
|
647
|
+
question, the stance in their confirmed words, the why, and grounds (the
|
|
648
|
+
tensions, statements, arrangements, and pathways it rests on; "accepted cost" marks the
|
|
649
|
+
unchosen side's contribution they confronted, "adopted pathway" the recipe
|
|
650
|
+
they committed to). Treat these as the person's own declared positions —
|
|
651
|
+
counsel that contradicts a standing decision must name that openly. A
|
|
652
|
+
ground flagged "since discarded" means a support
|
|
653
|
+
moved after the decision — worth surfacing, not silently ignoring. A
|
|
654
|
+
`Validation` line carries the machine coherence verdict: "failed" means a
|
|
655
|
+
flagged contradiction — do not build reassurance on that record; revisit it
|
|
656
|
+
with the person. Absence of an accepted-cost ground means the choice never
|
|
657
|
+
confronted what it gave up — relevant when a wobble arrives.
|
|
658
|
+
|
|
530
659
|
**Cross-exploration correspondences.** When several explorations coexist,
|
|
531
660
|
some perspectives carry correspondence lines — machine-stated facts, not
|
|
532
661
|
suggestions: "Also woven into Nexus [[x]]" (literally the same tension in
|
|
@@ -675,6 +804,7 @@ DEFAULT_TOOL_NAMES = [
|
|
|
675
804
|
"anchor",
|
|
676
805
|
"explore",
|
|
677
806
|
"deepen",
|
|
807
|
+
"record_decision",
|
|
678
808
|
"sync",
|
|
679
809
|
"inspect_node",
|
|
680
810
|
"read_digest",
|
|
@@ -709,6 +839,44 @@ def system_prompt(
|
|
|
709
839
|
)
|
|
710
840
|
tool_docs.append(doc)
|
|
711
841
|
|
|
842
|
+
decisions_wired = "record_decision" in names
|
|
843
|
+
|
|
844
|
+
def _decision_note(template: str, placeholder: str, note: str) -> str:
|
|
845
|
+
"""Render a Decision Readiness cross-reference only when the section
|
|
846
|
+
itself renders (tool wired) — a reference to an absent section would
|
|
847
|
+
dangle. The placeholder sits on its own line: wired → the note set
|
|
848
|
+
off by blank lines, unwired → the line collapses to a paragraph
|
|
849
|
+
break."""
|
|
850
|
+
if placeholder not in template:
|
|
851
|
+
return template
|
|
852
|
+
return template.replace(
|
|
853
|
+
placeholder, f"\n{note}\n" if decisions_wired else ""
|
|
854
|
+
)
|
|
855
|
+
|
|
856
|
+
eager = _decision_note(
|
|
857
|
+
_EAGER_SCOPED if scoped else _EAGER,
|
|
858
|
+
"{decision_filter_note}",
|
|
859
|
+
"In decision-shaped conversations, the Decision Readiness section "
|
|
860
|
+
"below adds one more filter: a candidate tension that could not "
|
|
861
|
+
"change the choice is acknowledged, not mapped.",
|
|
862
|
+
)
|
|
863
|
+
default_arc = _decision_note(
|
|
864
|
+
_DEFAULT_ARC,
|
|
865
|
+
"{decision_arc_step}",
|
|
866
|
+
"6. When the conversation is decision-shaped and readiness signals "
|
|
867
|
+
"appear, close it: the propose-and-confirm ceremony (see Decision "
|
|
868
|
+
"Readiness above), then counsel FROM the record.",
|
|
869
|
+
)
|
|
870
|
+
how_you_speak = _HOW_YOU_SPEAK_SCOPED if scoped else _HOW_YOU_SPEAK
|
|
871
|
+
if "{decision_speech_note}" in how_you_speak:
|
|
872
|
+
speech_note = (
|
|
873
|
+
"\n\nOne exception: the decision record (see Decision Readiness) "
|
|
874
|
+
"is named openly, in plain words — never as a tool or node."
|
|
875
|
+
if decisions_wired
|
|
876
|
+
else ""
|
|
877
|
+
)
|
|
878
|
+
how_you_speak = how_you_speak.replace("{decision_speech_note}", speech_note)
|
|
879
|
+
|
|
712
880
|
conversation_use = _CONVERSATION_USE
|
|
713
881
|
if scoped and "ingest" not in names:
|
|
714
882
|
# Don't reference a tool that isn't wired in this mode.
|
|
@@ -720,19 +888,20 @@ def system_prompt(
|
|
|
720
888
|
sections = [
|
|
721
889
|
_ROLE_SCOPED if scoped else _ROLE,
|
|
722
890
|
_scope_section(scoped_nexus_hash) if scoped else None,
|
|
723
|
-
|
|
891
|
+
eager,
|
|
724
892
|
_INTERNAL_MODEL,
|
|
725
893
|
conversation_use,
|
|
894
|
+
_DECISION_READINESS if decisions_wired else None,
|
|
726
895
|
_TOOLS_INTRO_SCOPED if scoped else _TOOLS_INTRO,
|
|
727
896
|
"\n\n".join(tool_docs),
|
|
728
897
|
_REJECTION_HANDLING_SCOPED if scoped else _REJECTION_HANDLING,
|
|
729
|
-
None if scoped else
|
|
730
|
-
|
|
898
|
+
None if scoped else default_arc,
|
|
899
|
+
how_you_speak,
|
|
731
900
|
_SCORE_READING,
|
|
732
901
|
_CONTEXT_SLOT,
|
|
733
902
|
]
|
|
734
903
|
return "\n\n".join(s for s in sections if s)
|
|
735
904
|
|
|
736
905
|
|
|
737
|
-
# Backward-compatible default render (unscoped, all
|
|
906
|
+
# Backward-compatible default render (unscoped, all default tools).
|
|
738
907
|
SYSTEM_PROMPT = system_prompt()
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"""
|
|
2
|
+
record_decision tool: persist a decision the person explicitly confirmed.
|
|
3
|
+
|
|
4
|
+
The ceremony lives in conversation (propose → read back → confirm) — this
|
|
5
|
+
tool is called only AFTER the person's explicit yes, with the confirmed
|
|
6
|
+
wording passed literally. Retracting or replacing a recorded decision goes
|
|
7
|
+
through the standard `discard` tool (reason referencing the new decision).
|
|
8
|
+
|
|
9
|
+
Provenance: WHO confirmed is a host-attested fact, closed over at tool
|
|
10
|
+
construction (Advisor(principal=...)) — never an LLM-supplied parameter.
|
|
11
|
+
"human" (the default) means an actual person confirmed the wording; a
|
|
12
|
+
delegated driver (agent-to-agent runs) must be constructed with its own
|
|
13
|
+
identity, else the ledger and inspect_node would present machine-authored
|
|
14
|
+
rationales as the person's own confirmed "why".
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
from typing import Annotated
|
|
20
|
+
|
|
21
|
+
from mirascope import llm
|
|
22
|
+
from pydantic import Field
|
|
23
|
+
|
|
24
|
+
from dialectical_framework.concerns.record_decision import GroundLink
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def build_record_decision(principal: str = "human"):
|
|
28
|
+
"""Build the record_decision tool with the confirming principal
|
|
29
|
+
closed over (same code-not-prompt enforcement as the nexus pin in
|
|
30
|
+
scoped.py)."""
|
|
31
|
+
|
|
32
|
+
attested_principal = principal
|
|
33
|
+
|
|
34
|
+
@llm.tool
|
|
35
|
+
async def record_decision(
|
|
36
|
+
question: Annotated[
|
|
37
|
+
str,
|
|
38
|
+
Field(description="The question that was being decided, in the person's confirmed words"),
|
|
39
|
+
],
|
|
40
|
+
stance: Annotated[
|
|
41
|
+
str,
|
|
42
|
+
Field(description="The stance the person committed to, in their confirmed words"),
|
|
43
|
+
],
|
|
44
|
+
rationale: Annotated[
|
|
45
|
+
str,
|
|
46
|
+
Field(
|
|
47
|
+
description="The distilled why behind the decision as the person confirmed it, "
|
|
48
|
+
"including reasons that live outside the mapped structure (deadlines, "
|
|
49
|
+
"people, external facts)"
|
|
50
|
+
),
|
|
51
|
+
],
|
|
52
|
+
grounds: Annotated[
|
|
53
|
+
list[GroundLink] | None,
|
|
54
|
+
Field(
|
|
55
|
+
description="Nodes this decision rests on: {hash, role?} each. "
|
|
56
|
+
"role='accepted_cost' for the unchosen side's contribution the person "
|
|
57
|
+
"confronted and accepted; role='adopted_pathway' for the pathway adopted "
|
|
58
|
+
"as the ongoing recipe; omit role for a plain ground (tensions weighed, "
|
|
59
|
+
"arrangements counseled from)."
|
|
60
|
+
),
|
|
61
|
+
] = None,
|
|
62
|
+
) -> str:
|
|
63
|
+
"""Record a decision the person has EXPLICITLY confirmed in conversation. Never call this silently or speculatively — propose the distilled record first, read it back, and record only on their clear yes. Links the decision to the graph nodes that grounded it and attaches the confirmed rationale. To replace or retract a recorded decision, use `discard` on it (with a reason naming the newer decision if one replaces it)."""
|
|
64
|
+
from dialectical_framework.concerns.record_decision import RecordDecision
|
|
65
|
+
|
|
66
|
+
# Mirascope passes json.loads'd kwargs without coercing nested models, so
|
|
67
|
+
# `grounds` arrives as raw dicts — RecordDecision.resolve normalizes them
|
|
68
|
+
# (single owner of that normalization) and refuses in-band on bad input.
|
|
69
|
+
concern = RecordDecision()
|
|
70
|
+
await concern.resolve(
|
|
71
|
+
question=question,
|
|
72
|
+
stance=stance,
|
|
73
|
+
rationale=rationale,
|
|
74
|
+
grounds=grounds,
|
|
75
|
+
principal=attested_principal,
|
|
76
|
+
)
|
|
77
|
+
return str(concern.report)
|
|
78
|
+
|
|
79
|
+
return record_decision
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
# Default build: a human principal. Kept module-level so existing imports
|
|
83
|
+
# (toolset builders, tests) stay valid; hosts with a non-human driver pass
|
|
84
|
+
# principal= at Advisor construction instead of importing this.
|
|
85
|
+
record_decision = build_record_decision()
|
|
@@ -18,8 +18,10 @@ the pinned explore weaves them into the exploration, deepen develops an
|
|
|
18
18
|
alternative arrangement of the pinned exploration on demand (guarded by
|
|
19
19
|
wheel-membership), sync/inspect_node/read_digest read, discard retracts
|
|
20
20
|
(members of the pinned nexus and standalone perspectives — e.g. its own
|
|
21
|
-
rejected anchors — but never members of OTHER explorations)
|
|
22
|
-
|
|
21
|
+
rejected anchors — but never members of OTHER explorations), and
|
|
22
|
+
record_decision persists confirmed decisions (Case-level, unguarded by the
|
|
23
|
+
pin). Only `ingest` is excluded — bulk extraction belongs to the unscoped
|
|
24
|
+
flow.
|
|
23
25
|
"""
|
|
24
26
|
|
|
25
27
|
from __future__ import annotations
|
|
@@ -30,21 +32,26 @@ from mirascope import llm
|
|
|
30
32
|
from pydantic import Field
|
|
31
33
|
|
|
32
34
|
|
|
33
|
-
def build_scoped_tools(nexus_hash: str) -> list:
|
|
35
|
+
def build_scoped_tools(nexus_hash: str, principal: str = "human") -> list:
|
|
34
36
|
"""
|
|
35
37
|
Build the tool set for an exploration-pinned Advisor (counsel mode).
|
|
36
38
|
|
|
37
39
|
The nexus_hash is captured by closure — the LLM cannot redirect any of
|
|
38
40
|
these tools to another nexus or create a new one. Validation that the
|
|
39
41
|
nexus exists happens in Advisor.__init__, not here (keeps the factory
|
|
40
|
-
DB-free for signature tests).
|
|
42
|
+
DB-free for signature tests). `principal` (host-attested confirmer
|
|
43
|
+
identity, closed over the same way) reaches record_decision — see
|
|
44
|
+
tools/record_decision.py.
|
|
41
45
|
"""
|
|
42
46
|
from dialectical_framework.agents.advisor.tools.anchor import anchor
|
|
47
|
+
from dialectical_framework.agents.advisor.tools.record_decision import \
|
|
48
|
+
build_record_decision
|
|
43
49
|
from dialectical_framework.agents.orchestrator.tools.inspect_node import \
|
|
44
50
|
inspect_node
|
|
45
51
|
from dialectical_framework.agents.orchestrator.tools.read_digest import \
|
|
46
52
|
read_digest
|
|
47
53
|
|
|
54
|
+
record_decision = build_record_decision(principal)
|
|
48
55
|
pinned_hash = nexus_hash
|
|
49
56
|
|
|
50
57
|
@llm.tool
|
|
@@ -58,10 +65,10 @@ def build_scoped_tools(nexus_hash: str) -> list:
|
|
|
58
65
|
|
|
59
66
|
@llm.tool
|
|
60
67
|
async def discard(
|
|
61
|
-
hash: Annotated[str, Field(description="Hash (or prefix) of the Statement or
|
|
68
|
+
hash: Annotated[str, Field(description="Hash (or prefix) of the Statement, Perspective, or Decision to discard")],
|
|
62
69
|
reason: Annotated[str, Field(description="Why it's being discarded")] = "discarded",
|
|
63
70
|
) -> str:
|
|
64
|
-
"""Mark a Statement or
|
|
71
|
+
"""Mark a Statement, Perspective, or Decision as discarded when the user disagrees with it or finds it irrelevant. Works on members of this exploration, on standalone perspectives (e.g. a freshly anchored framing the user rejected), and on recorded decisions the person retracts or replaces; refuses members of other explorations. Will refuse if the target participates in existing Cycles/Wheels."""
|
|
65
72
|
from dialectical_framework.concerns.discard import Discard
|
|
66
73
|
|
|
67
74
|
refusal = _outside_scope_refusal(pinned_hash, hash)
|
|
@@ -107,7 +114,10 @@ def build_scoped_tools(nexus_hash: str) -> list:
|
|
|
107
114
|
|
|
108
115
|
return await run_deepen(wheel_hash)
|
|
109
116
|
|
|
110
|
-
|
|
117
|
+
# record_decision is appended as-is: decisions are Case-level facts, not
|
|
118
|
+
# exploration members — no nexus-scope guard applies (grounds may be
|
|
119
|
+
# exploration members; grounding is read-only w.r.t. the exploration).
|
|
120
|
+
return [anchor, sync, inspect_node, read_digest, discard, explore, deepen, record_decision]
|
|
111
121
|
|
|
112
122
|
|
|
113
123
|
def _outside_scope_refusal(nexus_hash: str, target_hash: str) -> str | None:
|
|
@@ -132,8 +142,8 @@ def _outside_scope_refusal(nexus_hash: str, target_hash: str) -> str | None:
|
|
|
132
142
|
|
|
133
143
|
node = NodeRepository().find_by_hash(target_hash)
|
|
134
144
|
if not isinstance(node, Perspective):
|
|
135
|
-
# Not a perspective (
|
|
136
|
-
# guards handle it.
|
|
145
|
+
# Not a perspective (a statement or a decision) — let Discard's own
|
|
146
|
+
# guards handle it; decisions are Case-level, so no nexus pin applies.
|
|
137
147
|
return None
|
|
138
148
|
pp = node
|
|
139
149
|
|
|
@@ -16,6 +16,7 @@ from mirascope import llm
|
|
|
16
16
|
from pydantic import BaseModel, Field
|
|
17
17
|
|
|
18
18
|
from dialectical_framework.agents.agent_context import agent_scope
|
|
19
|
+
from dialectical_framework.graph.scope_context import require_current_sid
|
|
19
20
|
from dialectical_framework.agents.analyst.system_prompts import SYSTEM_PROMPT
|
|
20
21
|
from dialectical_framework.agents.conversation_facilitator import \
|
|
21
22
|
ConversationFacilitator
|
|
@@ -93,11 +94,13 @@ class Analyst:
|
|
|
93
94
|
return "\n\n".join(parts)
|
|
94
95
|
|
|
95
96
|
async def chat(self, user_message: str) -> str:
|
|
97
|
+
require_current_sid() # unscoped turns silently drop all work
|
|
96
98
|
with agent_scope(self.AGENT_NAME):
|
|
97
99
|
result = await self._conversation.submit(ChatResponse, user_message)
|
|
98
100
|
return result.message
|
|
99
101
|
|
|
100
102
|
async def chat_stream(self, user_message: str) -> AsyncGenerator[StreamEvent, None]:
|
|
103
|
+
require_current_sid() # unscoped turns silently drop all work
|
|
101
104
|
with agent_scope(self.AGENT_NAME):
|
|
102
105
|
async for event in self._conversation.submit_stream(
|
|
103
106
|
ChatResponse, user_message
|
|
@@ -128,6 +128,10 @@ class EditPerspective(ReasonableConcern[EditPerspectiveResult]):
|
|
|
128
128
|
# Prepare working PP (clone if committed)
|
|
129
129
|
if self._was_committed:
|
|
130
130
|
working_pp = pp.clone()
|
|
131
|
+
# Drop the inherited reading (intent): the axis was named for the
|
|
132
|
+
# ORIGINAL aspects — after a user edit it may no longer describe
|
|
133
|
+
# this tetrad, and a stale reading is worse than none.
|
|
134
|
+
working_pp.intent = None
|
|
131
135
|
working_pp.save()
|
|
132
136
|
self._report.node_created(working_pp)
|
|
133
137
|
else:
|