context-compiler 0.7.3__tar.gz → 0.7.4__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 (270) hide show
  1. {context_compiler-0.7.3 → context_compiler-0.7.4}/PKG-INFO +58 -5
  2. {context_compiler-0.7.3 → context_compiler-0.7.4}/README.md +57 -4
  3. {context_compiler-0.7.3 → context_compiler-0.7.4}/examples/01_persistent_guardrails.py +2 -2
  4. {context_compiler-0.7.3 → context_compiler-0.7.4}/examples/03_ambiguity_with_clarification.py +3 -3
  5. {context_compiler-0.7.3 → context_compiler-0.7.4}/examples/04_tool_governance_denylist.py +2 -2
  6. {context_compiler-0.7.3 → context_compiler-0.7.4}/examples/05_llm_integration_pattern.py +10 -8
  7. context_compiler-0.7.4/examples/08_controller_preview_diff.py +30 -0
  8. {context_compiler-0.7.3 → context_compiler-0.7.4}/examples/README.md +6 -0
  9. {context_compiler-0.7.3 → context_compiler-0.7.4}/examples/_util.py +12 -9
  10. {context_compiler-0.7.3 → context_compiler-0.7.4}/examples/integrations/README.md +1 -1
  11. {context_compiler-0.7.3 → context_compiler-0.7.4}/examples/integrations/litellm/basic.py +22 -13
  12. {context_compiler-0.7.3 → context_compiler-0.7.4}/examples/integrations/litellm/with_preprocessor.py +22 -13
  13. {context_compiler-0.7.3 → context_compiler-0.7.4}/examples/integrations/litellm_proxy/context_compiler_precall_hook.py +2 -1
  14. {context_compiler-0.7.3 → context_compiler-0.7.4}/examples/integrations/litellm_proxy/context_compiler_precall_hook_with_preprocessor.py +2 -1
  15. {context_compiler-0.7.3 → context_compiler-0.7.4}/examples/integrations/openwebui/README.md +4 -4
  16. {context_compiler-0.7.3 → context_compiler-0.7.4}/examples/integrations/openwebui/open_webui_pipe.py +26 -14
  17. {context_compiler-0.7.3 → context_compiler-0.7.4}/examples/integrations/openwebui/open_webui_pipe_with_preprocessor.py +26 -14
  18. {context_compiler-0.7.3 → context_compiler-0.7.4}/pyproject.toml +1 -1
  19. {context_compiler-0.7.3 → context_compiler-0.7.4}/src/context_compiler/__init__.py +21 -1
  20. {context_compiler-0.7.3 → context_compiler-0.7.4}/src/context_compiler/const.py +5 -0
  21. context_compiler-0.7.4/src/context_compiler/decision_helpers.py +24 -0
  22. {context_compiler-0.7.3 → context_compiler-0.7.4}/src/context_compiler/repl.py +1 -1
  23. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/README.md +1 -1
  24. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/conformance/api/public-api-v1.json +7 -0
  25. context_compiler-0.7.4/tests/test_decision_constants.py +70 -0
  26. {context_compiler-0.7.3 → context_compiler-0.7.4}/uv.lock +1 -1
  27. context_compiler-0.7.3/src/context_compiler/decision_constants.py +0 -5
  28. context_compiler-0.7.3/tests/test_decision_constants.py +0 -7
  29. {context_compiler-0.7.3 → context_compiler-0.7.4}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  30. {context_compiler-0.7.3 → context_compiler-0.7.4}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  31. {context_compiler-0.7.3 → context_compiler-0.7.4}/.github/pull_request_template.md +0 -0
  32. {context_compiler-0.7.3 → context_compiler-0.7.4}/.github/workflows/ci.yml +0 -0
  33. {context_compiler-0.7.3 → context_compiler-0.7.4}/.github/workflows/publish-pypi.yml +0 -0
  34. {context_compiler-0.7.3 → context_compiler-0.7.4}/.github/workflows/stress-tests.yml +0 -0
  35. {context_compiler-0.7.3 → context_compiler-0.7.4}/.gitignore +0 -0
  36. {context_compiler-0.7.3 → context_compiler-0.7.4}/.pre-commit-config.yaml +0 -0
  37. {context_compiler-0.7.3 → context_compiler-0.7.4}/AGENTS.md +0 -0
  38. {context_compiler-0.7.3 → context_compiler-0.7.4}/CODE_OF_CONDUCT.md +0 -0
  39. {context_compiler-0.7.3 → context_compiler-0.7.4}/CONTRIBUTING.md +0 -0
  40. {context_compiler-0.7.3 → context_compiler-0.7.4}/LICENSE +0 -0
  41. {context_compiler-0.7.3 → context_compiler-0.7.4}/SECURITY.md +0 -0
  42. {context_compiler-0.7.3 → context_compiler-0.7.4}/demos/01_llm_contradiction_clarify.py +0 -0
  43. {context_compiler-0.7.3 → context_compiler-0.7.4}/demos/02_llm_constraint_guardrail.py +0 -0
  44. {context_compiler-0.7.3 → context_compiler-0.7.4}/demos/03_llm_premise_guardrail.py +0 -0
  45. {context_compiler-0.7.3 → context_compiler-0.7.4}/demos/04_llm_tool_denylist_guardrail.py +0 -0
  46. {context_compiler-0.7.3 → context_compiler-0.7.4}/demos/05_llm_prompt_drift_vs_state.py +0 -0
  47. {context_compiler-0.7.3 → context_compiler-0.7.4}/demos/06_llm_context_compaction.py +0 -0
  48. {context_compiler-0.7.3 → context_compiler-0.7.4}/demos/07_llm_prompt_vs_state.py +0 -0
  49. {context_compiler-0.7.3 → context_compiler-0.7.4}/demos/08_llm_replacement_precondition.py +0 -0
  50. {context_compiler-0.7.3 → context_compiler-0.7.4}/demos/09_llm_pending_clarification.py +0 -0
  51. {context_compiler-0.7.3 → context_compiler-0.7.4}/demos/README.md +0 -0
  52. {context_compiler-0.7.3 → context_compiler-0.7.4}/demos/__init__.py +0 -0
  53. {context_compiler-0.7.3 → context_compiler-0.7.4}/demos/common.py +0 -0
  54. {context_compiler-0.7.3 → context_compiler-0.7.4}/demos/llm_client.py +0 -0
  55. {context_compiler-0.7.3 → context_compiler-0.7.4}/demos/run_demo.py +0 -0
  56. {context_compiler-0.7.3 → context_compiler-0.7.4}/docs/DescriptionAndMilestones.md +0 -0
  57. {context_compiler-0.7.3 → context_compiler-0.7.4}/docs/DesignPhilosophy.md +0 -0
  58. {context_compiler-0.7.3 → context_compiler-0.7.4}/docs/DirectiveGrammarSpec.md +0 -0
  59. {context_compiler-0.7.3 → context_compiler-0.7.4}/docs/README.md +0 -0
  60. {context_compiler-0.7.3 → context_compiler-0.7.4}/docs/demos-results.md +0 -0
  61. {context_compiler-0.7.3 → context_compiler-0.7.4}/docs/llm-preprocessor.md +0 -0
  62. {context_compiler-0.7.3 → context_compiler-0.7.4}/docs/multi-engine.md +0 -0
  63. {context_compiler-0.7.3 → context_compiler-0.7.4}/evals/litellm_proxy_additional_findings.md +0 -0
  64. {context_compiler-0.7.3 → context_compiler-0.7.4}/evals/litellm_proxy_behavioral_comparisons.md +0 -0
  65. {context_compiler-0.7.3 → context_compiler-0.7.4}/evals/swe-bench/README.md +0 -0
  66. {context_compiler-0.7.3 → context_compiler-0.7.4}/evals/swe-bench/RUBRIC.md +0 -0
  67. {context_compiler-0.7.3 → context_compiler-0.7.4}/evals/swe-bench/manifest.json +0 -0
  68. {context_compiler-0.7.3 → context_compiler-0.7.4}/evals/swe-bench/swe-bench.py +0 -0
  69. {context_compiler-0.7.3 → context_compiler-0.7.4}/evals/swe-bench/tasks/django__django-12453.json +0 -0
  70. {context_compiler-0.7.3 → context_compiler-0.7.4}/evals/swe-bench/tasks/django__django-13158.json +0 -0
  71. {context_compiler-0.7.3 → context_compiler-0.7.4}/evals/swe-bench/tasks/django__django-13964.json +0 -0
  72. {context_compiler-0.7.3 → context_compiler-0.7.4}/evals/swe-bench/tasks/django__django-15252.json +0 -0
  73. {context_compiler-0.7.3 → context_compiler-0.7.4}/evals/swe-bench/tasks/matplotlib__matplotlib-23299.json +0 -0
  74. {context_compiler-0.7.3 → context_compiler-0.7.4}/evals/swe-bench/tasks/psf__requests-1963.json +0 -0
  75. {context_compiler-0.7.3 → context_compiler-0.7.4}/examples/02_configuration_and_correction.py +0 -0
  76. {context_compiler-0.7.3 → context_compiler-0.7.4}/examples/06_transcript_replay.py +0 -0
  77. {context_compiler-0.7.3 → context_compiler-0.7.4}/examples/07_single_policy_correction.py +0 -0
  78. {context_compiler-0.7.3 → context_compiler-0.7.4}/examples/integrations/litellm/README.md +0 -0
  79. {context_compiler-0.7.3 → context_compiler-0.7.4}/examples/integrations/litellm_proxy/README.md +0 -0
  80. {context_compiler-0.7.3 → context_compiler-0.7.4}/examples/integrations/litellm_proxy/config.example.yaml +0 -0
  81. {context_compiler-0.7.3 → context_compiler-0.7.4}/experimental/__init__.py +0 -0
  82. {context_compiler-0.7.3 → context_compiler-0.7.4}/experimental/preprocessor/README.md +0 -0
  83. {context_compiler-0.7.3 → context_compiler-0.7.4}/experimental/preprocessor/__init__.py +0 -0
  84. {context_compiler-0.7.3 → context_compiler-0.7.4}/experimental/preprocessor/constants.py +0 -0
  85. {context_compiler-0.7.3 → context_compiler-0.7.4}/experimental/preprocessor/heuristic_preprocessor.py +0 -0
  86. {context_compiler-0.7.3 → context_compiler-0.7.4}/experimental/preprocessor/output_validation.py +0 -0
  87. {context_compiler-0.7.3 → context_compiler-0.7.4}/experimental/preprocessor/prompt_utils.py +0 -0
  88. {context_compiler-0.7.3 → context_compiler-0.7.4}/experimental/preprocessor/prompts/default.txt +0 -0
  89. {context_compiler-0.7.3 → context_compiler-0.7.4}/experimental/preprocessor/prompts/llama.txt +0 -0
  90. {context_compiler-0.7.3 → context_compiler-0.7.4}/host_support/__init__.py +0 -0
  91. {context_compiler-0.7.3 → context_compiler-0.7.4}/host_support/confirmation.py +0 -0
  92. {context_compiler-0.7.3 → context_compiler-0.7.4}/host_support/provider_mode.py +0 -0
  93. {context_compiler-0.7.3 → context_compiler-0.7.4}/src/context_compiler/controller.py +0 -0
  94. {context_compiler-0.7.3 → context_compiler-0.7.4}/src/context_compiler/engine.py +0 -0
  95. {context_compiler-0.7.3 → context_compiler-0.7.4}/src/context_compiler/observability.py +0 -0
  96. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/conformance/checkpoint/001_import_checkpoint_non_object_rejected.json +0 -0
  97. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/conformance/checkpoint/002_import_checkpoint_unsupported_version_rejected.json +0 -0
  98. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/conformance/checkpoint/003_import_checkpoint_invalid_pending_shape_rejected.json +0 -0
  99. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/conformance/checkpoint/004_import_checkpoint_invalid_replacement_shape_rejected.json +0 -0
  100. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/conformance/checkpoint/005_import_checkpoint_invalid_authoritative_state_rejected_atomically.json +0 -0
  101. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/conformance/checkpoint/006_import_checkpoint_pending_null_clears_existing_pending.json +0 -0
  102. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/conformance/checkpoint/007_import_checkpoint_pending_absent_clears_existing_pending.json +0 -0
  103. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/conformance/checkpoint/008_export_checkpoint_json_wrapper_shape.json +0 -0
  104. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/conformance/checkpoint/009_import_checkpoint_json_restores_authoritative_state_no_pending.json +0 -0
  105. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/conformance/checkpoint/010_checkpoint_json_round_trip_state_and_pending_parity.json +0 -0
  106. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/conformance/checkpoint/011_pending_clarification_through_checkpoint_json_restore_yes_resolution.json +0 -0
  107. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/conformance/checkpoint/012_import_checkpoint_json_malformed_rejected.json +0 -0
  108. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/conformance/checkpoint/013_import_checkpoint_json_invalid_shape_rejected.json +0 -0
  109. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/conformance/checkpoint/014_import_checkpoint_json_invalid_authoritative_state_rejected.json +0 -0
  110. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/conformance/checkpoint/015_import_checkpoint_json_invalid_payload_is_all_or_nothing.json +0 -0
  111. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/conformance/controller/001_step_update_envelope_and_state_snapshot.json +0 -0
  112. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/conformance/controller/002_preview_mutating_update_reports_would_mutate_and_no_live_mutation.json +0 -0
  113. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/conformance/controller/003_preview_idempotent_update_reports_non_mutating.json +0 -0
  114. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/conformance/controller/004_preview_clarify_reports_non_mutating_and_restores_pending.json +0 -0
  115. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/conformance/controller/005_preview_pending_yes_reports_mutation_but_preserves_live_pending.json +0 -0
  116. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/conformance/controller/006_state_diff_structural_changes.json +0 -0
  117. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/conformance/state-json/001_export_json_canonical_sorted_compact.json +0 -0
  118. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/conformance/state-json/002_import_json_invalid_json_rejected.json +0 -0
  119. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/conformance/state-json/003_import_json_non_object_rejected.json +0 -0
  120. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/conformance/state-json/004_import_json_unsupported_version_rejected.json +0 -0
  121. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/conformance/state-json/005_import_json_empty_normalized_policy_key_rejected_atomically.json +0 -0
  122. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/conformance/state-json/006_import_json_valid_normalized_policy_key_accepted.json +0 -0
  123. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/conformance/step/001_set_premise_update.json +0 -0
  124. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/conformance/step/002_use_item_normalization.json +0 -0
  125. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/conformance/step/003_conflict_prohibit_clarify.json +0 -0
  126. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/conformance/step/004_remove_policy_missing_idempotent_update.json +0 -0
  127. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/conformance/step/005_exact_prefix_passthrough_leading_space.json +0 -0
  128. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/conformance/step/006_near_miss_set_premise_to.json +0 -0
  129. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/conformance/step/007_near_miss_change_premise_missing_to.json +0 -0
  130. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/conformance/step/008_replace_missing_source_clarify_prompt.json +0 -0
  131. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/conformance/step/009_pending_affirmative_normalized_token.json +0 -0
  132. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/conformance/step/010_pending_negative_normalized_token.json +0 -0
  133. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/conformance/step/011_pending_unmatched_reuses_prompt.json +0 -0
  134. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/conformance/step/012_clear_premise_populated_update.json +0 -0
  135. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/conformance/step/013_clear_premise_already_null_update.json +0 -0
  136. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/conformance/step/014_reset_policies_populated_update.json +0 -0
  137. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/conformance/step/015_reset_policies_already_empty_update.json +0 -0
  138. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/conformance/step/016_clear_state_populated_update.json +0 -0
  139. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/conformance/step/017_clear_state_already_empty_update.json +0 -0
  140. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/conformance/step/018_pending_affirmative_punctuation_token.json +0 -0
  141. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/conformance/step/019_pending_negative_punctuation_token.json +0 -0
  142. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/conformance/transcript/001_user_only_replay_state.json +0 -0
  143. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/conformance/transcript/002_non_string_user_content_ignored.json +0 -0
  144. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/conformance/transcript/003_stops_at_first_clarify_later_yes.json +0 -0
  145. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/conformance/transcript/004_stops_at_first_clarify_later_no.json +0 -0
  146. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/controller/preview_clarify_no_mutation.json +0 -0
  147. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/controller/preview_idempotent_no_mutation.json +0 -0
  148. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/engine-regression/structured/README.md +0 -0
  149. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/engine-regression/structured/expected/contradiction_clarify.json +0 -0
  150. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/engine-regression/structured/expected/pending_clarify_no.json +0 -0
  151. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/engine-regression/structured/expected/pending_clarify_unmatched.json +0 -0
  152. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/engine-regression/structured/expected/pending_clarify_yes.json +0 -0
  153. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/engine-regression/structured/expected/premise_lifecycle.json +0 -0
  154. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/engine-regression/structured/expected/replacement_clarify.json +0 -0
  155. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/engine-regression/structured/scenarios/contradiction_clarify.json +0 -0
  156. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/engine-regression/structured/scenarios/pending_clarify_no.json +0 -0
  157. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/engine-regression/structured/scenarios/pending_clarify_unmatched.json +0 -0
  158. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/engine-regression/structured/scenarios/pending_clarify_yes.json +0 -0
  159. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/engine-regression/structured/scenarios/premise_lifecycle.json +0 -0
  160. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/engine-regression/structured/scenarios/replacement_clarify.json +0 -0
  161. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/preprocessor/admin-alias-remove-policies-unknown.json +0 -0
  162. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/preprocessor/admin-alias-reset-policy-unknown.json +0 -0
  163. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/preprocessor/ambiguous-directive-adjacent.json +0 -0
  164. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/preprocessor/canonical-directive-bracket-wrapper.json +0 -0
  165. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/preprocessor/canonical-directive-case-normalized-use-docker.json +0 -0
  166. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/preprocessor/canonical-directive-clear-state-period.json +0 -0
  167. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/preprocessor/canonical-directive-clear-state.json +0 -0
  168. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/preprocessor/canonical-directive-paren-wrapper.json +0 -0
  169. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/preprocessor/canonical-directive-prohibit-peanuts.json +0 -0
  170. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/preprocessor/canonical-directive-quoted-payload-use-docker.json +0 -0
  171. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/preprocessor/canonical-directive-reset-policies-bang.json +0 -0
  172. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/preprocessor/canonical-directive-whitespace-collapsed-use-docker.json +0 -0
  173. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/preprocessor/fenced-code-block-directive-unknown.json +0 -0
  174. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/preprocessor/inline-prose-code-directive-unknown.json +0 -0
  175. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/preprocessor/list-prefix-directive-unknown.json +0 -0
  176. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/preprocessor/malformed-replacement-instead-docker-unknown.json +0 -0
  177. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/preprocessor/meta-prefix-directive-unknown.json +0 -0
  178. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/preprocessor/mixed-directive-task-unknown.json +0 -0
  179. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/preprocessor/mixed-intent-unknown.json +0 -0
  180. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/preprocessor/modal-please-clear-state-unknown.json +0 -0
  181. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/preprocessor/multiline-multi-directive-unknown.json +0 -0
  182. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/preprocessor/natural-language-dont-use-unknown.json +0 -0
  183. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/preprocessor/near-miss-change-premise-missing-to-unknown.json +0 -0
  184. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/preprocessor/near-miss-change-premise-to-empty-unknown.json +0 -0
  185. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/preprocessor/near-miss-prohibit-empty-unknown.json +0 -0
  186. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/preprocessor/near-miss-remove-policy-empty-unknown.json +0 -0
  187. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/preprocessor/near-miss-set-premise-empty-unknown.json +0 -0
  188. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/preprocessor/near-miss-set-premise-to-unknown.json +0 -0
  189. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/preprocessor/near-miss-use-empty-unknown.json +0 -0
  190. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/preprocessor/near-miss-use-instead-of-missing-new-item-unknown.json +0 -0
  191. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/preprocessor/near-miss-use-instead-of-missing-old-item-unknown.json +0 -0
  192. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/preprocessor/nested-wrapper-clear-state-unknown.json +0 -0
  193. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/preprocessor/ordinary-non-directive.json +0 -0
  194. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/preprocessor/parse-canonical-directive-prohibit-peanuts.json +0 -0
  195. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/preprocessor/parse-malformed-near-miss-rejected.json +0 -0
  196. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/preprocessor/parse-multiple-directives-rejected.json +0 -0
  197. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/preprocessor/parse-no-directive-sentinel.json +0 -0
  198. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/preprocessor/parse-source-input-fenced-code-rejected.json +0 -0
  199. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/preprocessor/parse-source-input-inline-prose-code-rejected.json +0 -0
  200. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/preprocessor/parse-source-input-mixed-directive-task-rejected.json +0 -0
  201. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/preprocessor/parse-source-input-multiline-rejected.json +0 -0
  202. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/preprocessor/parse-source-input-question-form-rejected.json +0 -0
  203. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/preprocessor/parse-source-input-quoted-payload-locked.json +0 -0
  204. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/preprocessor/parse-source-input-reported-speech-rejected.json +0 -0
  205. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/preprocessor/parse-source-input-safe-canonical-use-docker.json +0 -0
  206. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/preprocessor/parse-source-input-safe-canonicalization-use-docker.json +0 -0
  207. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/preprocessor/parse-source-input-structured-json-directive-self-accepted.json +0 -0
  208. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/preprocessor/parse-unknown-directive-like-rejected.json +0 -0
  209. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/preprocessor/public-api-v1.json +0 -0
  210. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/preprocessor/question-can-you-use-docker-unknown.json +0 -0
  211. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/preprocessor/question-use-docker-unknown.json +0 -0
  212. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/preprocessor/quoted-exact-use-docker-backtick-unknown.json +0 -0
  213. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/preprocessor/quoted-exact-use-docker-single-unknown.json +0 -0
  214. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/preprocessor/quoted-exact-use-docker-unknown.json +0 -0
  215. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/preprocessor/quoted-reported-unknown.json +0 -0
  216. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/preprocessor/reported-speech-docs-say-unknown.json +0 -0
  217. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/preprocessor/sentence-adjacent-directive-unknown.json +0 -0
  218. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/preprocessor/unsupported-alias-unknown.json +0 -0
  219. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/preprocessor/validator-invalid-json-shape-unknown.json +0 -0
  220. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/preprocessor/validator-malformed-json-text-unknown.json +0 -0
  221. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/preprocessor/validator-malformed-sentinel-unknown.json +0 -0
  222. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/preprocessor/validator-malformed-text-unknown.json +0 -0
  223. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/preprocessor/validator-multi-candidate-directive-unknown.json +0 -0
  224. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/preprocessor/validator-sentinel-no-directive.json +0 -0
  225. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/preprocessor/validator-source-input-allow-safe-directive.json +0 -0
  226. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/preprocessor/validator-source-input-block-change-premise-rewrite.json +0 -0
  227. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/preprocessor/validator-source-input-block-set-premise-rewrite.json +0 -0
  228. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/fixtures/preprocessor/validator-structured-json-directive.json +0 -0
  229. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/test_04_grammar_edge_cases.py +0 -0
  230. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/test_04_llm_tool_governance.py +0 -0
  231. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/test_07_llm_prompt_engineering_comparison.py +0 -0
  232. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/test_api_contract_fixture.py +0 -0
  233. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/test_controller.py +0 -0
  234. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/test_demo_01_04_behavior.py +0 -0
  235. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/test_demo_05_prompt_contract.py +0 -0
  236. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/test_demo_07_output_clarity.py +0 -0
  237. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/test_demo_08_09_behavior.py +0 -0
  238. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/test_demo_compaction.py +0 -0
  239. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/test_demo_oracle_properties.py +0 -0
  240. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/test_engine.py +0 -0
  241. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/test_example_integrations_imports.py +0 -0
  242. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/test_examples.py +0 -0
  243. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/test_examples_behavior.py +0 -0
  244. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/test_examples_smoke.py +0 -0
  245. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/test_fixtures.py +0 -0
  246. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/test_host_confirmation.py +0 -0
  247. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/test_host_observability.py +0 -0
  248. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/test_litellm_checkpoint_integration.py +0 -0
  249. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/test_litellm_integration_error_paths.py +0 -0
  250. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/test_litellm_preprocessor_model_config.py +0 -0
  251. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/test_llm_client.py +0 -0
  252. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/test_llm_demos.py +0 -0
  253. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/test_openwebui_pipe.py +0 -0
  254. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/test_openwebui_preprocessor_pipe.py +0 -0
  255. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/test_precompiler_prompt_utils.py +0 -0
  256. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/test_preprocessor_api_contract_fixture.py +0 -0
  257. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/test_preprocessor_conformance.py +0 -0
  258. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/test_preprocessor_heuristic.py +0 -0
  259. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/test_preprocessor_heuristic_properties.py +0 -0
  260. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/test_preprocessor_output_validation.py +0 -0
  261. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/test_preprocessor_validator_properties.py +0 -0
  262. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/test_properties.py +0 -0
  263. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/test_provider_helper.py +0 -0
  264. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/test_repl.py +0 -0
  265. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/test_repl_coverage.py +0 -0
  266. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/test_repl_properties.py +0 -0
  267. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/test_run_demo.py +0 -0
  268. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/test_smoke.py +0 -0
  269. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/test_structured_regression.py +0 -0
  270. {context_compiler-0.7.3 → context_compiler-0.7.4}/tests/test_transcript_replay.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: context-compiler
3
- Version: 0.7.3
3
+ Version: 0.7.4
4
4
  Summary: Deterministic conversational state engine for LLM applications.
5
5
  Project-URL: Homepage, https://github.com/rlippmann/context-compiler
6
6
  Project-URL: Repository, https://github.com/rlippmann/context-compiler
@@ -139,22 +139,55 @@ Bare REPL input behavior remains unchanged.
139
139
 
140
140
  Or in code:
141
141
  ```python
142
- from context_compiler import DECISION_CLARIFY, DECISION_UPDATE, create_engine
142
+ from context_compiler import (
143
+ create_engine,
144
+ get_clarify_prompt,
145
+ is_clarify,
146
+ is_update,
147
+ )
143
148
 
144
149
  engine = create_engine()
145
150
 
146
151
  user_input = "prohibit peanuts"
147
152
  decision = engine.step(user_input)
148
153
 
149
- if decision["kind"] == DECISION_CLARIFY:
150
- show_to_user(decision["prompt_to_user"])
151
- elif decision["kind"] == DECISION_UPDATE:
154
+ if is_clarify(decision):
155
+ show_to_user(get_clarify_prompt(decision))
156
+ elif is_update(decision):
152
157
  messages = build_messages(engine.state, user_input)
153
158
  render(call_llm(messages))
154
159
  else:
155
160
  render(call_llm(user_input))
156
161
  ```
157
162
 
163
+ Controller quick example:
164
+
165
+ ```python
166
+ from context_compiler import (
167
+ get_decision_state,
168
+ is_update,
169
+ create_engine,
170
+ preview,
171
+ state_diff,
172
+ step,
173
+ )
174
+
175
+ engine = create_engine()
176
+
177
+ before = engine.state
178
+ dry_run = preview(engine, "prohibit peanuts")
179
+ print(dry_run["would_mutate"]) # True
180
+ planned_change = state_diff(before, dry_run["state_after"])
181
+ print(planned_change["changed"]) # True
182
+
183
+ after_preview = engine.state
184
+ print(state_diff(before, after_preview)["changed"]) # False (preview does not mutate state)
185
+
186
+ applied = step(engine, "prohibit peanuts")
187
+ print(is_update(applied["decision"])) # True
188
+ print(get_decision_state(applied["decision"]) is not None) # True
189
+ ```
190
+
158
191
  ## Installation
159
192
 
160
193
  Requirements:
@@ -297,6 +330,10 @@ Meaning:
297
330
  | update | authoritative state mutated; host may call LLM with updated state |
298
331
  | clarify | show `prompt_to_user` and do not call the LLM |
299
332
 
333
+ For normal app code, prefer exported decision helpers (`is_clarify`,
334
+ `is_update`, `is_passthrough`, `get_clarify_prompt`, `get_decision_state`)
335
+ instead of direct key traversal.
336
+
300
337
  ---
301
338
 
302
339
  ### API Reference
@@ -334,6 +371,17 @@ Decision-kind constants are also exported for host branching readability:
334
371
  - `DECISION_UPDATE`
335
372
  - `DECISION_CLARIFY`
336
373
 
374
+ Decision helpers are also exported for common host-side checks:
375
+ - `is_update(decision)`
376
+ - `is_clarify(decision)`
377
+ - `is_passthrough(decision)`
378
+ - `get_clarify_prompt(decision)`
379
+ - `get_decision_state(decision)`
380
+
381
+ Policy value constants are exported for explicit policy comparisons:
382
+ - `POLICY_USE`
383
+ - `POLICY_PROHIBIT`
384
+
337
385
  ---
338
386
 
339
387
  ## State Model
@@ -348,6 +396,8 @@ The compiler keeps a current state snapshot that your app can trust.
348
396
  Identical input sequences always produce identical state.
349
397
 
350
398
  The internal structure of the state is intentionally opaque to host applications.
399
+ For normal reads, prefer `get_premise_value(state)` and
400
+ `get_policy_items(state, ...)` over direct key traversal.
351
401
 
352
402
  ---
353
403
 
@@ -384,6 +434,9 @@ Checkpoint object shape:
384
434
  }
385
435
  ```
386
436
 
437
+ The checkpoint shape above is an explicit serialization contract. At this
438
+ boundary, direct key access is expected.
439
+
387
440
  Notes:
388
441
 
389
442
  - `pending` is `null` when no continuation is waiting for confirmation.
@@ -103,22 +103,55 @@ Bare REPL input behavior remains unchanged.
103
103
 
104
104
  Or in code:
105
105
  ```python
106
- from context_compiler import DECISION_CLARIFY, DECISION_UPDATE, create_engine
106
+ from context_compiler import (
107
+ create_engine,
108
+ get_clarify_prompt,
109
+ is_clarify,
110
+ is_update,
111
+ )
107
112
 
108
113
  engine = create_engine()
109
114
 
110
115
  user_input = "prohibit peanuts"
111
116
  decision = engine.step(user_input)
112
117
 
113
- if decision["kind"] == DECISION_CLARIFY:
114
- show_to_user(decision["prompt_to_user"])
115
- elif decision["kind"] == DECISION_UPDATE:
118
+ if is_clarify(decision):
119
+ show_to_user(get_clarify_prompt(decision))
120
+ elif is_update(decision):
116
121
  messages = build_messages(engine.state, user_input)
117
122
  render(call_llm(messages))
118
123
  else:
119
124
  render(call_llm(user_input))
120
125
  ```
121
126
 
127
+ Controller quick example:
128
+
129
+ ```python
130
+ from context_compiler import (
131
+ get_decision_state,
132
+ is_update,
133
+ create_engine,
134
+ preview,
135
+ state_diff,
136
+ step,
137
+ )
138
+
139
+ engine = create_engine()
140
+
141
+ before = engine.state
142
+ dry_run = preview(engine, "prohibit peanuts")
143
+ print(dry_run["would_mutate"]) # True
144
+ planned_change = state_diff(before, dry_run["state_after"])
145
+ print(planned_change["changed"]) # True
146
+
147
+ after_preview = engine.state
148
+ print(state_diff(before, after_preview)["changed"]) # False (preview does not mutate state)
149
+
150
+ applied = step(engine, "prohibit peanuts")
151
+ print(is_update(applied["decision"])) # True
152
+ print(get_decision_state(applied["decision"]) is not None) # True
153
+ ```
154
+
122
155
  ## Installation
123
156
 
124
157
  Requirements:
@@ -261,6 +294,10 @@ Meaning:
261
294
  | update | authoritative state mutated; host may call LLM with updated state |
262
295
  | clarify | show `prompt_to_user` and do not call the LLM |
263
296
 
297
+ For normal app code, prefer exported decision helpers (`is_clarify`,
298
+ `is_update`, `is_passthrough`, `get_clarify_prompt`, `get_decision_state`)
299
+ instead of direct key traversal.
300
+
264
301
  ---
265
302
 
266
303
  ### API Reference
@@ -298,6 +335,17 @@ Decision-kind constants are also exported for host branching readability:
298
335
  - `DECISION_UPDATE`
299
336
  - `DECISION_CLARIFY`
300
337
 
338
+ Decision helpers are also exported for common host-side checks:
339
+ - `is_update(decision)`
340
+ - `is_clarify(decision)`
341
+ - `is_passthrough(decision)`
342
+ - `get_clarify_prompt(decision)`
343
+ - `get_decision_state(decision)`
344
+
345
+ Policy value constants are exported for explicit policy comparisons:
346
+ - `POLICY_USE`
347
+ - `POLICY_PROHIBIT`
348
+
301
349
  ---
302
350
 
303
351
  ## State Model
@@ -312,6 +360,8 @@ The compiler keeps a current state snapshot that your app can trust.
312
360
  Identical input sequences always produce identical state.
313
361
 
314
362
  The internal structure of the state is intentionally opaque to host applications.
363
+ For normal reads, prefer `get_premise_value(state)` and
364
+ `get_policy_items(state, ...)` over direct key traversal.
315
365
 
316
366
  ---
317
367
 
@@ -348,6 +398,9 @@ Checkpoint object shape:
348
398
  }
349
399
  ```
350
400
 
401
+ The checkpoint shape above is an explicit serialization contract. At this
402
+ boundary, direct key access is expected.
403
+
351
404
  Notes:
352
405
 
353
406
  - `pending` is `null` when no continuation is waiting for confirmation.
@@ -2,11 +2,11 @@
2
2
 
3
3
  from _util import print_decision_summary, print_state_summary
4
4
 
5
- from context_compiler import State, create_engine, get_policy_items
5
+ from context_compiler import POLICY_PROHIBIT, State, create_engine, get_policy_items
6
6
 
7
7
 
8
8
  def build_prompt(state: State, user_input: str) -> str:
9
- prohibit = get_policy_items(state, "prohibit")
9
+ prohibit = get_policy_items(state, POLICY_PROHIBIT)
10
10
  prohibit_text = ", ".join(prohibit) if prohibit else "(none)"
11
11
  return (
12
12
  "System: Follow authoritative conversation state.\n"
@@ -2,7 +2,7 @@
2
2
 
3
3
  from _util import print_decision_summary, print_state_summary
4
4
 
5
- from context_compiler import create_engine
5
+ from context_compiler import create_engine, get_clarify_prompt, is_clarify
6
6
 
7
7
 
8
8
  def fake_llm(user_input: str) -> str:
@@ -23,9 +23,9 @@ def main() -> None:
23
23
  print_decision_summary(decision2)
24
24
  print()
25
25
 
26
- if decision2["kind"] == "clarify":
26
+ if is_clarify(decision2):
27
27
  print("Host behavior: clarification pending, do NOT call LLM.")
28
- print(f"Clarify prompt: {decision2['prompt_to_user']}")
28
+ print(f"Clarify prompt: {get_clarify_prompt(decision2)}")
29
29
  else:
30
30
  fake_llm("use peanuts")
31
31
  print()
@@ -4,7 +4,7 @@ from dataclasses import dataclass
4
4
 
5
5
  from _util import print_decision_summary, print_state_summary
6
6
 
7
- from context_compiler import create_engine, get_policy_items
7
+ from context_compiler import POLICY_PROHIBIT, create_engine, get_policy_items
8
8
 
9
9
 
10
10
  @dataclass
@@ -32,7 +32,7 @@ def main() -> None:
32
32
  print()
33
33
 
34
34
  print("Host-side tool denylist behavior:")
35
- prohibit = get_policy_items(state, "prohibit")
35
+ prohibit = get_policy_items(state, POLICY_PROHIBIT)
36
36
  tools = [Tool("docker"), Tool("kubectl")]
37
37
  for tool in tools:
38
38
  if tool.name in prohibit:
@@ -3,12 +3,14 @@
3
3
  from _util import print_decision_summary, print_state_summary
4
4
 
5
5
  from context_compiler import (
6
- DECISION_CLARIFY,
7
- DECISION_PASSTHROUGH,
8
- DECISION_UPDATE,
9
6
  Engine,
10
7
  State,
11
8
  create_engine,
9
+ get_clarify_prompt,
10
+ get_decision_state,
11
+ is_clarify,
12
+ is_passthrough,
13
+ is_update,
12
14
  )
13
15
 
14
16
 
@@ -27,15 +29,15 @@ def handle_turn(engine_input: str, engine: Engine) -> None:
27
29
  print(f"User: {engine_input}")
28
30
  print_decision_summary(decision)
29
31
 
30
- if decision["kind"] == DECISION_PASSTHROUGH:
32
+ if is_passthrough(decision):
31
33
  print("Host action: passthrough -> call fake_llm() without state")
32
34
  fake_llm(None, engine_input)
33
- elif decision["kind"] == DECISION_UPDATE:
35
+ elif is_update(decision):
34
36
  print("Host action: update -> call fake_llm() with compiled state")
35
- fake_llm(decision["state"], engine_input)
36
- elif decision["kind"] == DECISION_CLARIFY:
37
+ fake_llm(get_decision_state(decision), engine_input)
38
+ elif is_clarify(decision):
37
39
  print("Host action: clarify -> show prompt, DO NOT call LLM")
38
- print("clarify prompt:", decision["prompt_to_user"])
40
+ print("clarify prompt:", get_clarify_prompt(decision))
39
41
  print()
40
42
 
41
43
 
@@ -0,0 +1,30 @@
1
+ """Example 8: controller preview + state diff + apply flow."""
2
+
3
+ from _util import print_decision_summary, print_state_summary
4
+
5
+ from context_compiler import create_engine, preview, state_diff, step
6
+
7
+
8
+ def main() -> None:
9
+ engine = create_engine()
10
+
11
+ state_before = engine.state
12
+ print_state_summary(state_before, "state before preview")
13
+
14
+ print("\nPreview: prohibit peanuts")
15
+ preview_result = preview(engine, "prohibit peanuts")
16
+ print("would_mutate:", preview_result["would_mutate"])
17
+ print_decision_summary(preview_result["decision"])
18
+
19
+ state_after_preview = engine.state
20
+ diff_after_preview = state_diff(state_before, state_after_preview)
21
+ print("state changed after preview:", diff_after_preview["changed"])
22
+
23
+ print("\nApply: prohibit peanuts")
24
+ step_result = step(engine, "prohibit peanuts")
25
+ print_decision_summary(step_result["decision"])
26
+ print_state_summary(step_result["state"], "state after step")
27
+
28
+
29
+ if __name__ == "__main__":
30
+ main()
@@ -40,3 +40,9 @@ Shows `compile_transcript(messages)` from a fresh engine and `engine.apply_trans
40
40
 
41
41
  Demonstrates explicit single-policy correction without `reset policies`.
42
42
  Shows `prohibit peanuts` -> `remove policy peanuts` -> `use peanuts`.
43
+
44
+ ## 08_controller_preview_diff.py
45
+
46
+ Shows controller-layer dry-run behavior with `preview(engine, user_input)`.
47
+ Shows structural state inspection with `state_diff(state_before, state_after)`.
48
+ Shows `step(engine, user_input)` after preview to apply the same input.
@@ -2,10 +2,14 @@ import json
2
2
  from typing import Any, Literal
3
3
 
4
4
  from context_compiler import (
5
- DECISION_CLARIFY,
6
- DECISION_UPDATE,
5
+ POLICY_PROHIBIT,
6
+ POLICY_USE,
7
+ get_clarify_prompt,
8
+ get_decision_state,
7
9
  get_policy_items,
8
10
  get_premise_value,
11
+ is_clarify,
12
+ is_update,
9
13
  )
10
14
 
11
15
 
@@ -28,22 +32,21 @@ def print_state_summary(state: Any, label: str = "state") -> None:
28
32
 
29
33
  print(f"{label}:")
30
34
  print(f"- premise: {premise_text}")
31
- print(f"- use policies: {_format_policy_values(state, 'use')}")
32
- print(f"- prohibit policies: {_format_policy_values(state, 'prohibit')}")
35
+ print(f"- use policies: {_format_policy_values(state, POLICY_USE)}")
36
+ print(f"- prohibit policies: {_format_policy_values(state, POLICY_PROHIBIT)}")
33
37
 
34
38
 
35
39
  def print_decision_summary(decision: Any) -> None:
36
- kind = decision.get("kind")
37
- if kind == DECISION_UPDATE:
40
+ if is_update(decision):
38
41
  print("result: updated")
39
- state = decision.get("state")
42
+ state = get_decision_state(decision)
40
43
  assert isinstance(state, dict)
41
44
  print_state_summary(state, "compiled state")
42
45
  return
43
46
 
44
- if kind == DECISION_CLARIFY:
47
+ if is_clarify(decision):
45
48
  print("result: clarify")
46
- prompt = decision.get("prompt_to_user")
49
+ prompt = get_clarify_prompt(decision)
47
50
  if isinstance(prompt, str) and prompt:
48
51
  print("clarify prompt:")
49
52
  for line in prompt.splitlines():
@@ -17,7 +17,7 @@ export OPENAI_API_KEY=...
17
17
  export PROVIDER=openai
18
18
  ```
19
19
 
20
- Checkpoint continuation in these integration examples requires `context-compiler>=0.6.14`.
20
+ Checkpoint continuation in these integration examples requires `context-compiler>=0.7.0`.
21
21
 
22
22
  ### Run
23
23
 
@@ -22,9 +22,16 @@ from context_compiler import (
22
22
  DECISION_CLARIFY,
23
23
  DECISION_PASSTHROUGH,
24
24
  DECISION_UPDATE,
25
+ POLICY_PROHIBIT,
26
+ POLICY_USE,
25
27
  State,
28
+ get_clarify_prompt,
29
+ get_decision_state,
26
30
  get_policy_items,
27
31
  get_premise_value,
32
+ is_clarify,
33
+ is_passthrough,
34
+ is_update,
28
35
  )
29
36
  from context_compiler.engine import Engine
30
37
  from context_compiler.observability import build_trace
@@ -98,8 +105,8 @@ def _extract_response_content(response: object) -> str | None:
98
105
 
99
106
  def _render_compiled_state_contract(compiled_state: State) -> str:
100
107
  premise = get_premise_value(compiled_state)
101
- use_items = sorted(get_policy_items(compiled_state, "use"))
102
- prohibit_items = sorted(get_policy_items(compiled_state, "prohibit"))
108
+ use_items = sorted(get_policy_items(compiled_state, POLICY_USE))
109
+ prohibit_items = sorted(get_policy_items(compiled_state, POLICY_PROHIBIT))
103
110
 
104
111
  lines: list[str] = ["The following constraints are authoritative."]
105
112
  if premise:
@@ -272,13 +279,18 @@ def handle_turn(user_input: str, engine: Engine, *, session_key: str | None = No
272
279
  checkpoint_before = engine.export_checkpoint() if has_pending_before else None
273
280
  logger.debug("litellm_basic: engine_input=%s", f"user_input len={len(user_input)}")
274
281
  decision = engine.step(user_input)
275
- kind = cast(str, decision["kind"])
282
+ if is_clarify(decision):
283
+ kind = DECISION_CLARIFY
284
+ elif is_update(decision):
285
+ kind = DECISION_UPDATE
286
+ else:
287
+ kind = DECISION_PASSTHROUGH
276
288
  logger.debug("litellm_basic: decision=%s", kind)
277
289
  near_miss_prompt = _near_miss_directive_clarify(user_input)
278
290
 
279
- if kind == DECISION_CLARIFY:
291
+ if is_clarify(decision):
280
292
  _persist_session_checkpoint_if_needed(engine, kind, session_key)
281
- response_text = near_miss_prompt or decision["prompt_to_user"] or ""
293
+ response_text = near_miss_prompt or get_clarify_prompt(decision) or ""
282
294
  return _append_trace(
283
295
  response_text,
284
296
  original_input=user_input,
@@ -288,7 +300,7 @@ def handle_turn(user_input: str, engine: Engine, *, session_key: str | None = No
288
300
  state_after=engine.state,
289
301
  llm_called=False,
290
302
  )
291
- if near_miss_prompt is not None and kind == DECISION_PASSTHROUGH:
303
+ if near_miss_prompt is not None and is_passthrough(decision):
292
304
  return _append_trace(
293
305
  near_miss_prompt,
294
306
  original_input=user_input,
@@ -299,11 +311,7 @@ def handle_turn(user_input: str, engine: Engine, *, session_key: str | None = No
299
311
  llm_called=False,
300
312
  )
301
313
  _persist_session_checkpoint_if_needed(engine, kind, session_key)
302
- if (
303
- kind == DECISION_UPDATE
304
- and is_confirmation_text(user_input)
305
- and checkpoint_before is not None
306
- ):
314
+ if is_update(decision) and is_confirmation_text(user_input) and checkpoint_before is not None:
307
315
  response_text = _summarize_confirmation_update(user_input, checkpoint_before)
308
316
  return _append_trace(
309
317
  response_text,
@@ -314,7 +322,7 @@ def handle_turn(user_input: str, engine: Engine, *, session_key: str | None = No
314
322
  state_after=engine.state,
315
323
  llm_called=False,
316
324
  )
317
- if kind == DECISION_UPDATE:
325
+ if is_update(decision):
318
326
  response_text = _summarize_update_from_input(user_input)
319
327
  return _append_trace(
320
328
  response_text,
@@ -326,7 +334,8 @@ def handle_turn(user_input: str, engine: Engine, *, session_key: str | None = No
326
334
  llm_called=False,
327
335
  )
328
336
 
329
- compiled_state = decision["state"] if decision["state"] is not None else engine.state
337
+ decision_state = get_decision_state(decision)
338
+ compiled_state = decision_state if decision_state is not None else engine.state
330
339
  messages = _build_messages(user_input, compiled_state)
331
340
  response_text = _call_litellm(messages)
332
341
  return _append_trace(
@@ -28,9 +28,16 @@ from context_compiler import (
28
28
  DECISION_CLARIFY,
29
29
  DECISION_PASSTHROUGH,
30
30
  DECISION_UPDATE,
31
+ POLICY_PROHIBIT,
32
+ POLICY_USE,
31
33
  State,
34
+ get_clarify_prompt,
35
+ get_decision_state,
32
36
  get_policy_items,
33
37
  get_premise_value,
38
+ is_clarify,
39
+ is_passthrough,
40
+ is_update,
34
41
  )
35
42
  from context_compiler.engine import Engine
36
43
  from context_compiler.observability import build_trace
@@ -130,8 +137,8 @@ def _get_litellm_completion() -> Callable[..., object]:
130
137
 
131
138
  def _render_compiled_state_contract(compiled_state: State) -> str:
132
139
  premise = get_premise_value(compiled_state)
133
- use_items = sorted(get_policy_items(compiled_state, "use"))
134
- prohibit_items = sorted(get_policy_items(compiled_state, "prohibit"))
140
+ use_items = sorted(get_policy_items(compiled_state, POLICY_USE))
141
+ prohibit_items = sorted(get_policy_items(compiled_state, POLICY_PROHIBIT))
135
142
 
136
143
  lines: list[str] = ["The following constraints are authoritative."]
137
144
  if premise:
@@ -395,13 +402,18 @@ def handle_turn(user_input: str, engine: Engine, *, session_key: str | None = No
395
402
  )
396
403
 
397
404
  decision = engine.step(compile_input)
398
- kind = cast(str, decision["kind"])
405
+ if is_clarify(decision):
406
+ kind = DECISION_CLARIFY
407
+ elif is_update(decision):
408
+ kind = DECISION_UPDATE
409
+ else:
410
+ kind = DECISION_PASSTHROUGH
399
411
  logger.debug("preprocessor: decision=%s", kind)
400
412
  near_miss_prompt = _near_miss_directive_clarify(user_input)
401
413
 
402
- if kind == DECISION_CLARIFY:
414
+ if is_clarify(decision):
403
415
  _persist_session_checkpoint_if_needed(engine, kind, session_key)
404
- response_text = near_miss_prompt or decision["prompt_to_user"] or ""
416
+ response_text = near_miss_prompt or get_clarify_prompt(decision) or ""
405
417
  return _append_trace(
406
418
  response_text,
407
419
  original_input=user_input,
@@ -412,7 +424,7 @@ def handle_turn(user_input: str, engine: Engine, *, session_key: str | None = No
412
424
  state_after=engine.state,
413
425
  llm_called=False,
414
426
  )
415
- if near_miss_prompt is not None and kind == DECISION_PASSTHROUGH:
427
+ if near_miss_prompt is not None and is_passthrough(decision):
416
428
  return _append_trace(
417
429
  near_miss_prompt,
418
430
  original_input=user_input,
@@ -424,11 +436,7 @@ def handle_turn(user_input: str, engine: Engine, *, session_key: str | None = No
424
436
  llm_called=False,
425
437
  )
426
438
  _persist_session_checkpoint_if_needed(engine, kind, session_key)
427
- if (
428
- kind == DECISION_UPDATE
429
- and is_confirmation_text(user_input)
430
- and checkpoint_before is not None
431
- ):
439
+ if is_update(decision) and is_confirmation_text(user_input) and checkpoint_before is not None:
432
440
  response_text = _summarize_confirmation_update(user_input, checkpoint_before)
433
441
  return _append_trace(
434
442
  response_text,
@@ -440,7 +448,7 @@ def handle_turn(user_input: str, engine: Engine, *, session_key: str | None = No
440
448
  state_after=engine.state,
441
449
  llm_called=False,
442
450
  )
443
- if kind == DECISION_UPDATE:
451
+ if is_update(decision):
444
452
  response_text = _summarize_update_from_input(compile_input)
445
453
  return _append_trace(
446
454
  response_text,
@@ -453,7 +461,8 @@ def handle_turn(user_input: str, engine: Engine, *, session_key: str | None = No
453
461
  llm_called=False,
454
462
  )
455
463
 
456
- compiled_state = decision["state"] if decision["state"] is not None else engine.state
464
+ decision_state = get_decision_state(decision)
465
+ compiled_state = decision_state if decision_state is not None else engine.state
457
466
  messages = _build_messages(user_input, compiled_state)
458
467
  response_text = _call_litellm(messages)
459
468
  return _append_trace(
@@ -20,6 +20,7 @@ except ModuleNotFoundError:
20
20
 
21
21
 
22
22
  from context_compiler import (
23
+ POLICY_PROHIBIT,
23
24
  State,
24
25
  Transcript,
25
26
  compile_transcript,
@@ -38,7 +39,7 @@ _SUPPORTED_CALL_TYPES = {
38
39
 
39
40
 
40
41
  def _render_compiled_state_contract(compiled_state: State) -> str:
41
- prohibited = get_policy_items(compiled_state, "prohibit")
42
+ prohibited = get_policy_items(compiled_state, POLICY_PROHIBIT)
42
43
  premise = get_premise_value(compiled_state)
43
44
 
44
45
  lines: list[str] = ["The following constraints are authoritative."]
@@ -26,6 +26,7 @@ except ModuleNotFoundError:
26
26
 
27
27
 
28
28
  from context_compiler import (
29
+ POLICY_PROHIBIT,
29
30
  State,
30
31
  Transcript,
31
32
  compile_transcript,
@@ -52,7 +53,7 @@ _PROMPTS_DIR = files("experimental.preprocessor").joinpath("prompts")
52
53
 
53
54
 
54
55
  def _render_compiled_state_contract(compiled_state: State) -> str:
55
- prohibited = get_policy_items(compiled_state, "prohibit")
56
+ prohibited = get_policy_items(compiled_state, POLICY_PROHIBIT)
56
57
  premise = get_premise_value(compiled_state)
57
58
 
58
59
  lines: list[str] = ["The following constraints are authoritative."]
@@ -18,7 +18,7 @@ These examples support both sync (`0.8.x`) and async (`0.9.x`) user lookup.
18
18
  The minimal pipe path below is the easiest first-run flow and was runtime-validated in Docker via API flow with a real backend model.
19
19
 
20
20
  1. Import `open_webui_pipe.py` (recommended/default) as a Function by URL.
21
- 2. Open WebUI installs `context-compiler>=0.7.2` from the function frontmatter requirements.
21
+ 2. Open WebUI installs `context-compiler>=0.7.4` from the function frontmatter requirements.
22
22
  3. Enable the function.
23
23
  4. Set `BASE_MODEL_ID` to a valid Open WebUI model id (required).
24
24
  5. Select the pipe model in chat.
@@ -27,7 +27,7 @@ Open WebUI is a separate runtime and must already be installed/configured separa
27
27
  Open WebUI also needs at least one real backend model/provider configured (for example Ollama or OpenAI) so `BASE_MODEL_ID` resolves to an actual model.
28
28
  Note: The `PROVIDER` environment contract used in LiteLLM examples/demos does not apply to OpenWebUI. OpenWebUI manages providers via its own connection settings and model IDs.
29
29
 
30
- Checkpoint continuation in these examples requires `context-compiler>=0.7.2`.
30
+ Checkpoint continuation in these examples requires `context-compiler>=0.7.4`.
31
31
 
32
32
  ### Model configuration
33
33
 
@@ -64,8 +64,8 @@ If frontmatter dependency installs are disabled, offline, or unavailable:
64
64
  1. Open a shell in the Open WebUI container:
65
65
  - `docker exec -it <openwebui-container> sh`
66
66
  2. Install the package manually:
67
- - Minimal pipe: `pip install "context-compiler>=0.7.2"`
68
- - Preprocessor pipe: `pip install "context-compiler[experimental]>=0.7.2"`
67
+ - Minimal pipe: `pip install "context-compiler>=0.7.4"`
68
+ - Preprocessor pipe: `pip install "context-compiler[experimental]>=0.7.4"`
69
69
  3. Import and enable the function in Open WebUI, then configure valves.
70
70
 
71
71
  ### Finding valid model ids