context-compiler 0.7.4__tar.gz → 0.7.6__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 (271) hide show
  1. {context_compiler-0.7.4 → context_compiler-0.7.6}/PKG-INFO +17 -14
  2. {context_compiler-0.7.4 → context_compiler-0.7.6}/README.md +16 -13
  3. {context_compiler-0.7.4 → context_compiler-0.7.6}/examples/integrations/README.md +7 -0
  4. {context_compiler-0.7.4 → context_compiler-0.7.6}/examples/integrations/litellm/basic.py +2 -2
  5. {context_compiler-0.7.4 → context_compiler-0.7.6}/examples/integrations/litellm/with_preprocessor.py +2 -2
  6. context_compiler-0.7.6/examples/integrations/ollama_structured_output/README.md +58 -0
  7. context_compiler-0.7.6/examples/integrations/ollama_structured_output/example.py +169 -0
  8. {context_compiler-0.7.4 → context_compiler-0.7.6}/examples/integrations/openwebui/open_webui_pipe.py +2 -2
  9. {context_compiler-0.7.4 → context_compiler-0.7.6}/examples/integrations/openwebui/open_webui_pipe_with_preprocessor.py +2 -2
  10. {context_compiler-0.7.4 → context_compiler-0.7.6}/pyproject.toml +1 -1
  11. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/test_example_integrations_imports.py +5 -0
  12. context_compiler-0.7.6/tests/test_ollama_structured_output_example.py +60 -0
  13. {context_compiler-0.7.4 → context_compiler-0.7.6}/uv.lock +1 -1
  14. {context_compiler-0.7.4 → context_compiler-0.7.6}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  15. {context_compiler-0.7.4 → context_compiler-0.7.6}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  16. {context_compiler-0.7.4 → context_compiler-0.7.6}/.github/pull_request_template.md +0 -0
  17. {context_compiler-0.7.4 → context_compiler-0.7.6}/.github/workflows/ci.yml +0 -0
  18. {context_compiler-0.7.4 → context_compiler-0.7.6}/.github/workflows/publish-pypi.yml +0 -0
  19. {context_compiler-0.7.4 → context_compiler-0.7.6}/.github/workflows/stress-tests.yml +0 -0
  20. {context_compiler-0.7.4 → context_compiler-0.7.6}/.gitignore +0 -0
  21. {context_compiler-0.7.4 → context_compiler-0.7.6}/.pre-commit-config.yaml +0 -0
  22. {context_compiler-0.7.4 → context_compiler-0.7.6}/AGENTS.md +0 -0
  23. {context_compiler-0.7.4 → context_compiler-0.7.6}/CODE_OF_CONDUCT.md +0 -0
  24. {context_compiler-0.7.4 → context_compiler-0.7.6}/CONTRIBUTING.md +0 -0
  25. {context_compiler-0.7.4 → context_compiler-0.7.6}/LICENSE +0 -0
  26. {context_compiler-0.7.4 → context_compiler-0.7.6}/SECURITY.md +0 -0
  27. {context_compiler-0.7.4 → context_compiler-0.7.6}/demos/01_llm_contradiction_clarify.py +0 -0
  28. {context_compiler-0.7.4 → context_compiler-0.7.6}/demos/02_llm_constraint_guardrail.py +0 -0
  29. {context_compiler-0.7.4 → context_compiler-0.7.6}/demos/03_llm_premise_guardrail.py +0 -0
  30. {context_compiler-0.7.4 → context_compiler-0.7.6}/demos/04_llm_tool_denylist_guardrail.py +0 -0
  31. {context_compiler-0.7.4 → context_compiler-0.7.6}/demos/05_llm_prompt_drift_vs_state.py +0 -0
  32. {context_compiler-0.7.4 → context_compiler-0.7.6}/demos/06_llm_context_compaction.py +0 -0
  33. {context_compiler-0.7.4 → context_compiler-0.7.6}/demos/07_llm_prompt_vs_state.py +0 -0
  34. {context_compiler-0.7.4 → context_compiler-0.7.6}/demos/08_llm_replacement_precondition.py +0 -0
  35. {context_compiler-0.7.4 → context_compiler-0.7.6}/demos/09_llm_pending_clarification.py +0 -0
  36. {context_compiler-0.7.4 → context_compiler-0.7.6}/demos/README.md +0 -0
  37. {context_compiler-0.7.4 → context_compiler-0.7.6}/demos/__init__.py +0 -0
  38. {context_compiler-0.7.4 → context_compiler-0.7.6}/demos/common.py +0 -0
  39. {context_compiler-0.7.4 → context_compiler-0.7.6}/demos/llm_client.py +0 -0
  40. {context_compiler-0.7.4 → context_compiler-0.7.6}/demos/run_demo.py +0 -0
  41. {context_compiler-0.7.4 → context_compiler-0.7.6}/docs/DescriptionAndMilestones.md +0 -0
  42. {context_compiler-0.7.4 → context_compiler-0.7.6}/docs/DesignPhilosophy.md +0 -0
  43. {context_compiler-0.7.4 → context_compiler-0.7.6}/docs/DirectiveGrammarSpec.md +0 -0
  44. {context_compiler-0.7.4 → context_compiler-0.7.6}/docs/README.md +0 -0
  45. {context_compiler-0.7.4 → context_compiler-0.7.6}/docs/demos-results.md +0 -0
  46. {context_compiler-0.7.4 → context_compiler-0.7.6}/docs/llm-preprocessor.md +0 -0
  47. {context_compiler-0.7.4 → context_compiler-0.7.6}/docs/multi-engine.md +0 -0
  48. {context_compiler-0.7.4 → context_compiler-0.7.6}/evals/litellm_proxy_additional_findings.md +0 -0
  49. {context_compiler-0.7.4 → context_compiler-0.7.6}/evals/litellm_proxy_behavioral_comparisons.md +0 -0
  50. {context_compiler-0.7.4 → context_compiler-0.7.6}/evals/swe-bench/README.md +0 -0
  51. {context_compiler-0.7.4 → context_compiler-0.7.6}/evals/swe-bench/RUBRIC.md +0 -0
  52. {context_compiler-0.7.4 → context_compiler-0.7.6}/evals/swe-bench/manifest.json +0 -0
  53. {context_compiler-0.7.4 → context_compiler-0.7.6}/evals/swe-bench/swe-bench.py +0 -0
  54. {context_compiler-0.7.4 → context_compiler-0.7.6}/evals/swe-bench/tasks/django__django-12453.json +0 -0
  55. {context_compiler-0.7.4 → context_compiler-0.7.6}/evals/swe-bench/tasks/django__django-13158.json +0 -0
  56. {context_compiler-0.7.4 → context_compiler-0.7.6}/evals/swe-bench/tasks/django__django-13964.json +0 -0
  57. {context_compiler-0.7.4 → context_compiler-0.7.6}/evals/swe-bench/tasks/django__django-15252.json +0 -0
  58. {context_compiler-0.7.4 → context_compiler-0.7.6}/evals/swe-bench/tasks/matplotlib__matplotlib-23299.json +0 -0
  59. {context_compiler-0.7.4 → context_compiler-0.7.6}/evals/swe-bench/tasks/psf__requests-1963.json +0 -0
  60. {context_compiler-0.7.4 → context_compiler-0.7.6}/examples/01_persistent_guardrails.py +0 -0
  61. {context_compiler-0.7.4 → context_compiler-0.7.6}/examples/02_configuration_and_correction.py +0 -0
  62. {context_compiler-0.7.4 → context_compiler-0.7.6}/examples/03_ambiguity_with_clarification.py +0 -0
  63. {context_compiler-0.7.4 → context_compiler-0.7.6}/examples/04_tool_governance_denylist.py +0 -0
  64. {context_compiler-0.7.4 → context_compiler-0.7.6}/examples/05_llm_integration_pattern.py +0 -0
  65. {context_compiler-0.7.4 → context_compiler-0.7.6}/examples/06_transcript_replay.py +0 -0
  66. {context_compiler-0.7.4 → context_compiler-0.7.6}/examples/07_single_policy_correction.py +0 -0
  67. {context_compiler-0.7.4 → context_compiler-0.7.6}/examples/08_controller_preview_diff.py +0 -0
  68. {context_compiler-0.7.4 → context_compiler-0.7.6}/examples/README.md +0 -0
  69. {context_compiler-0.7.4 → context_compiler-0.7.6}/examples/_util.py +0 -0
  70. {context_compiler-0.7.4 → context_compiler-0.7.6}/examples/integrations/litellm/README.md +0 -0
  71. {context_compiler-0.7.4 → context_compiler-0.7.6}/examples/integrations/litellm_proxy/README.md +0 -0
  72. {context_compiler-0.7.4 → context_compiler-0.7.6}/examples/integrations/litellm_proxy/config.example.yaml +0 -0
  73. {context_compiler-0.7.4 → context_compiler-0.7.6}/examples/integrations/litellm_proxy/context_compiler_precall_hook.py +0 -0
  74. {context_compiler-0.7.4 → context_compiler-0.7.6}/examples/integrations/litellm_proxy/context_compiler_precall_hook_with_preprocessor.py +0 -0
  75. {context_compiler-0.7.4 → context_compiler-0.7.6}/examples/integrations/openwebui/README.md +0 -0
  76. {context_compiler-0.7.4 → context_compiler-0.7.6}/experimental/__init__.py +0 -0
  77. {context_compiler-0.7.4 → context_compiler-0.7.6}/experimental/preprocessor/README.md +0 -0
  78. {context_compiler-0.7.4 → context_compiler-0.7.6}/experimental/preprocessor/__init__.py +0 -0
  79. {context_compiler-0.7.4 → context_compiler-0.7.6}/experimental/preprocessor/constants.py +0 -0
  80. {context_compiler-0.7.4 → context_compiler-0.7.6}/experimental/preprocessor/heuristic_preprocessor.py +0 -0
  81. {context_compiler-0.7.4 → context_compiler-0.7.6}/experimental/preprocessor/output_validation.py +0 -0
  82. {context_compiler-0.7.4 → context_compiler-0.7.6}/experimental/preprocessor/prompt_utils.py +0 -0
  83. {context_compiler-0.7.4 → context_compiler-0.7.6}/experimental/preprocessor/prompts/default.txt +0 -0
  84. {context_compiler-0.7.4 → context_compiler-0.7.6}/experimental/preprocessor/prompts/llama.txt +0 -0
  85. {context_compiler-0.7.4 → context_compiler-0.7.6}/host_support/__init__.py +0 -0
  86. {context_compiler-0.7.4 → context_compiler-0.7.6}/host_support/confirmation.py +0 -0
  87. {context_compiler-0.7.4 → context_compiler-0.7.6}/host_support/provider_mode.py +0 -0
  88. {context_compiler-0.7.4 → context_compiler-0.7.6}/src/context_compiler/__init__.py +0 -0
  89. {context_compiler-0.7.4 → context_compiler-0.7.6}/src/context_compiler/const.py +0 -0
  90. {context_compiler-0.7.4 → context_compiler-0.7.6}/src/context_compiler/controller.py +0 -0
  91. {context_compiler-0.7.4 → context_compiler-0.7.6}/src/context_compiler/decision_helpers.py +0 -0
  92. {context_compiler-0.7.4 → context_compiler-0.7.6}/src/context_compiler/engine.py +0 -0
  93. {context_compiler-0.7.4 → context_compiler-0.7.6}/src/context_compiler/observability.py +0 -0
  94. {context_compiler-0.7.4 → context_compiler-0.7.6}/src/context_compiler/repl.py +0 -0
  95. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/README.md +0 -0
  96. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/conformance/api/public-api-v1.json +0 -0
  97. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/conformance/checkpoint/001_import_checkpoint_non_object_rejected.json +0 -0
  98. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/conformance/checkpoint/002_import_checkpoint_unsupported_version_rejected.json +0 -0
  99. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/conformance/checkpoint/003_import_checkpoint_invalid_pending_shape_rejected.json +0 -0
  100. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/conformance/checkpoint/004_import_checkpoint_invalid_replacement_shape_rejected.json +0 -0
  101. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/conformance/checkpoint/005_import_checkpoint_invalid_authoritative_state_rejected_atomically.json +0 -0
  102. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/conformance/checkpoint/006_import_checkpoint_pending_null_clears_existing_pending.json +0 -0
  103. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/conformance/checkpoint/007_import_checkpoint_pending_absent_clears_existing_pending.json +0 -0
  104. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/conformance/checkpoint/008_export_checkpoint_json_wrapper_shape.json +0 -0
  105. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/conformance/checkpoint/009_import_checkpoint_json_restores_authoritative_state_no_pending.json +0 -0
  106. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/conformance/checkpoint/010_checkpoint_json_round_trip_state_and_pending_parity.json +0 -0
  107. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/conformance/checkpoint/011_pending_clarification_through_checkpoint_json_restore_yes_resolution.json +0 -0
  108. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/conformance/checkpoint/012_import_checkpoint_json_malformed_rejected.json +0 -0
  109. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/conformance/checkpoint/013_import_checkpoint_json_invalid_shape_rejected.json +0 -0
  110. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/conformance/checkpoint/014_import_checkpoint_json_invalid_authoritative_state_rejected.json +0 -0
  111. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/conformance/checkpoint/015_import_checkpoint_json_invalid_payload_is_all_or_nothing.json +0 -0
  112. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/conformance/controller/001_step_update_envelope_and_state_snapshot.json +0 -0
  113. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/conformance/controller/002_preview_mutating_update_reports_would_mutate_and_no_live_mutation.json +0 -0
  114. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/conformance/controller/003_preview_idempotent_update_reports_non_mutating.json +0 -0
  115. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/conformance/controller/004_preview_clarify_reports_non_mutating_and_restores_pending.json +0 -0
  116. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/conformance/controller/005_preview_pending_yes_reports_mutation_but_preserves_live_pending.json +0 -0
  117. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/conformance/controller/006_state_diff_structural_changes.json +0 -0
  118. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/conformance/state-json/001_export_json_canonical_sorted_compact.json +0 -0
  119. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/conformance/state-json/002_import_json_invalid_json_rejected.json +0 -0
  120. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/conformance/state-json/003_import_json_non_object_rejected.json +0 -0
  121. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/conformance/state-json/004_import_json_unsupported_version_rejected.json +0 -0
  122. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/conformance/state-json/005_import_json_empty_normalized_policy_key_rejected_atomically.json +0 -0
  123. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/conformance/state-json/006_import_json_valid_normalized_policy_key_accepted.json +0 -0
  124. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/conformance/step/001_set_premise_update.json +0 -0
  125. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/conformance/step/002_use_item_normalization.json +0 -0
  126. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/conformance/step/003_conflict_prohibit_clarify.json +0 -0
  127. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/conformance/step/004_remove_policy_missing_idempotent_update.json +0 -0
  128. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/conformance/step/005_exact_prefix_passthrough_leading_space.json +0 -0
  129. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/conformance/step/006_near_miss_set_premise_to.json +0 -0
  130. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/conformance/step/007_near_miss_change_premise_missing_to.json +0 -0
  131. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/conformance/step/008_replace_missing_source_clarify_prompt.json +0 -0
  132. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/conformance/step/009_pending_affirmative_normalized_token.json +0 -0
  133. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/conformance/step/010_pending_negative_normalized_token.json +0 -0
  134. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/conformance/step/011_pending_unmatched_reuses_prompt.json +0 -0
  135. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/conformance/step/012_clear_premise_populated_update.json +0 -0
  136. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/conformance/step/013_clear_premise_already_null_update.json +0 -0
  137. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/conformance/step/014_reset_policies_populated_update.json +0 -0
  138. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/conformance/step/015_reset_policies_already_empty_update.json +0 -0
  139. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/conformance/step/016_clear_state_populated_update.json +0 -0
  140. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/conformance/step/017_clear_state_already_empty_update.json +0 -0
  141. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/conformance/step/018_pending_affirmative_punctuation_token.json +0 -0
  142. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/conformance/step/019_pending_negative_punctuation_token.json +0 -0
  143. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/conformance/transcript/001_user_only_replay_state.json +0 -0
  144. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/conformance/transcript/002_non_string_user_content_ignored.json +0 -0
  145. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/conformance/transcript/003_stops_at_first_clarify_later_yes.json +0 -0
  146. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/conformance/transcript/004_stops_at_first_clarify_later_no.json +0 -0
  147. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/controller/preview_clarify_no_mutation.json +0 -0
  148. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/controller/preview_idempotent_no_mutation.json +0 -0
  149. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/engine-regression/structured/README.md +0 -0
  150. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/engine-regression/structured/expected/contradiction_clarify.json +0 -0
  151. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/engine-regression/structured/expected/pending_clarify_no.json +0 -0
  152. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/engine-regression/structured/expected/pending_clarify_unmatched.json +0 -0
  153. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/engine-regression/structured/expected/pending_clarify_yes.json +0 -0
  154. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/engine-regression/structured/expected/premise_lifecycle.json +0 -0
  155. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/engine-regression/structured/expected/replacement_clarify.json +0 -0
  156. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/engine-regression/structured/scenarios/contradiction_clarify.json +0 -0
  157. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/engine-regression/structured/scenarios/pending_clarify_no.json +0 -0
  158. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/engine-regression/structured/scenarios/pending_clarify_unmatched.json +0 -0
  159. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/engine-regression/structured/scenarios/pending_clarify_yes.json +0 -0
  160. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/engine-regression/structured/scenarios/premise_lifecycle.json +0 -0
  161. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/engine-regression/structured/scenarios/replacement_clarify.json +0 -0
  162. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/preprocessor/admin-alias-remove-policies-unknown.json +0 -0
  163. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/preprocessor/admin-alias-reset-policy-unknown.json +0 -0
  164. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/preprocessor/ambiguous-directive-adjacent.json +0 -0
  165. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/preprocessor/canonical-directive-bracket-wrapper.json +0 -0
  166. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/preprocessor/canonical-directive-case-normalized-use-docker.json +0 -0
  167. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/preprocessor/canonical-directive-clear-state-period.json +0 -0
  168. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/preprocessor/canonical-directive-clear-state.json +0 -0
  169. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/preprocessor/canonical-directive-paren-wrapper.json +0 -0
  170. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/preprocessor/canonical-directive-prohibit-peanuts.json +0 -0
  171. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/preprocessor/canonical-directive-quoted-payload-use-docker.json +0 -0
  172. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/preprocessor/canonical-directive-reset-policies-bang.json +0 -0
  173. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/preprocessor/canonical-directive-whitespace-collapsed-use-docker.json +0 -0
  174. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/preprocessor/fenced-code-block-directive-unknown.json +0 -0
  175. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/preprocessor/inline-prose-code-directive-unknown.json +0 -0
  176. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/preprocessor/list-prefix-directive-unknown.json +0 -0
  177. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/preprocessor/malformed-replacement-instead-docker-unknown.json +0 -0
  178. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/preprocessor/meta-prefix-directive-unknown.json +0 -0
  179. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/preprocessor/mixed-directive-task-unknown.json +0 -0
  180. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/preprocessor/mixed-intent-unknown.json +0 -0
  181. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/preprocessor/modal-please-clear-state-unknown.json +0 -0
  182. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/preprocessor/multiline-multi-directive-unknown.json +0 -0
  183. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/preprocessor/natural-language-dont-use-unknown.json +0 -0
  184. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/preprocessor/near-miss-change-premise-missing-to-unknown.json +0 -0
  185. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/preprocessor/near-miss-change-premise-to-empty-unknown.json +0 -0
  186. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/preprocessor/near-miss-prohibit-empty-unknown.json +0 -0
  187. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/preprocessor/near-miss-remove-policy-empty-unknown.json +0 -0
  188. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/preprocessor/near-miss-set-premise-empty-unknown.json +0 -0
  189. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/preprocessor/near-miss-set-premise-to-unknown.json +0 -0
  190. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/preprocessor/near-miss-use-empty-unknown.json +0 -0
  191. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/preprocessor/near-miss-use-instead-of-missing-new-item-unknown.json +0 -0
  192. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/preprocessor/near-miss-use-instead-of-missing-old-item-unknown.json +0 -0
  193. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/preprocessor/nested-wrapper-clear-state-unknown.json +0 -0
  194. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/preprocessor/ordinary-non-directive.json +0 -0
  195. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/preprocessor/parse-canonical-directive-prohibit-peanuts.json +0 -0
  196. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/preprocessor/parse-malformed-near-miss-rejected.json +0 -0
  197. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/preprocessor/parse-multiple-directives-rejected.json +0 -0
  198. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/preprocessor/parse-no-directive-sentinel.json +0 -0
  199. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/preprocessor/parse-source-input-fenced-code-rejected.json +0 -0
  200. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/preprocessor/parse-source-input-inline-prose-code-rejected.json +0 -0
  201. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/preprocessor/parse-source-input-mixed-directive-task-rejected.json +0 -0
  202. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/preprocessor/parse-source-input-multiline-rejected.json +0 -0
  203. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/preprocessor/parse-source-input-question-form-rejected.json +0 -0
  204. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/preprocessor/parse-source-input-quoted-payload-locked.json +0 -0
  205. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/preprocessor/parse-source-input-reported-speech-rejected.json +0 -0
  206. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/preprocessor/parse-source-input-safe-canonical-use-docker.json +0 -0
  207. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/preprocessor/parse-source-input-safe-canonicalization-use-docker.json +0 -0
  208. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/preprocessor/parse-source-input-structured-json-directive-self-accepted.json +0 -0
  209. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/preprocessor/parse-unknown-directive-like-rejected.json +0 -0
  210. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/preprocessor/public-api-v1.json +0 -0
  211. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/preprocessor/question-can-you-use-docker-unknown.json +0 -0
  212. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/preprocessor/question-use-docker-unknown.json +0 -0
  213. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/preprocessor/quoted-exact-use-docker-backtick-unknown.json +0 -0
  214. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/preprocessor/quoted-exact-use-docker-single-unknown.json +0 -0
  215. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/preprocessor/quoted-exact-use-docker-unknown.json +0 -0
  216. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/preprocessor/quoted-reported-unknown.json +0 -0
  217. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/preprocessor/reported-speech-docs-say-unknown.json +0 -0
  218. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/preprocessor/sentence-adjacent-directive-unknown.json +0 -0
  219. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/preprocessor/unsupported-alias-unknown.json +0 -0
  220. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/preprocessor/validator-invalid-json-shape-unknown.json +0 -0
  221. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/preprocessor/validator-malformed-json-text-unknown.json +0 -0
  222. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/preprocessor/validator-malformed-sentinel-unknown.json +0 -0
  223. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/preprocessor/validator-malformed-text-unknown.json +0 -0
  224. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/preprocessor/validator-multi-candidate-directive-unknown.json +0 -0
  225. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/preprocessor/validator-sentinel-no-directive.json +0 -0
  226. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/preprocessor/validator-source-input-allow-safe-directive.json +0 -0
  227. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/preprocessor/validator-source-input-block-change-premise-rewrite.json +0 -0
  228. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/preprocessor/validator-source-input-block-set-premise-rewrite.json +0 -0
  229. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/fixtures/preprocessor/validator-structured-json-directive.json +0 -0
  230. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/test_04_grammar_edge_cases.py +0 -0
  231. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/test_04_llm_tool_governance.py +0 -0
  232. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/test_07_llm_prompt_engineering_comparison.py +0 -0
  233. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/test_api_contract_fixture.py +0 -0
  234. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/test_controller.py +0 -0
  235. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/test_decision_constants.py +0 -0
  236. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/test_demo_01_04_behavior.py +0 -0
  237. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/test_demo_05_prompt_contract.py +0 -0
  238. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/test_demo_07_output_clarity.py +0 -0
  239. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/test_demo_08_09_behavior.py +0 -0
  240. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/test_demo_compaction.py +0 -0
  241. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/test_demo_oracle_properties.py +0 -0
  242. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/test_engine.py +0 -0
  243. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/test_examples.py +0 -0
  244. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/test_examples_behavior.py +0 -0
  245. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/test_examples_smoke.py +0 -0
  246. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/test_fixtures.py +0 -0
  247. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/test_host_confirmation.py +0 -0
  248. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/test_host_observability.py +0 -0
  249. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/test_litellm_checkpoint_integration.py +0 -0
  250. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/test_litellm_integration_error_paths.py +0 -0
  251. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/test_litellm_preprocessor_model_config.py +0 -0
  252. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/test_llm_client.py +0 -0
  253. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/test_llm_demos.py +0 -0
  254. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/test_openwebui_pipe.py +0 -0
  255. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/test_openwebui_preprocessor_pipe.py +0 -0
  256. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/test_precompiler_prompt_utils.py +0 -0
  257. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/test_preprocessor_api_contract_fixture.py +0 -0
  258. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/test_preprocessor_conformance.py +0 -0
  259. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/test_preprocessor_heuristic.py +0 -0
  260. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/test_preprocessor_heuristic_properties.py +0 -0
  261. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/test_preprocessor_output_validation.py +0 -0
  262. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/test_preprocessor_validator_properties.py +0 -0
  263. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/test_properties.py +0 -0
  264. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/test_provider_helper.py +0 -0
  265. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/test_repl.py +0 -0
  266. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/test_repl_coverage.py +0 -0
  267. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/test_repl_properties.py +0 -0
  268. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/test_run_demo.py +0 -0
  269. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/test_smoke.py +0 -0
  270. {context_compiler-0.7.4 → context_compiler-0.7.6}/tests/test_structured_regression.py +0 -0
  271. {context_compiler-0.7.4 → context_compiler-0.7.6}/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.4
3
+ Version: 0.7.6
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
@@ -217,24 +217,27 @@ uv run pytest
217
217
 
218
218
  ## FAQ
219
219
 
220
- **Is this just prompt reinjection?**
221
- Reinjection helps with persistence, and it remains useful. Context Compiler
222
- handles a different problem: rules for when state is allowed to change.
223
-
224
- Examples:
225
- - replacement semantics (`use X instead of Y`) when `Y` may not exist
226
- - contradiction detection before applying a mutation
227
- - lifecycle enforcement (for example, you cannot change an unset premise)
228
- - pending clarification flows that must be resolved before other mutations
229
-
230
- In short: reinjection carries state forward; Context Compiler decides when your
231
- app should change state.
232
-
233
220
  **Isn’t this just prompt engineering?**
234
221
  It complements prompt engineering, but solves a different problem. Prompting
235
222
  shapes model behavior. Context Compiler enforces state rules and updates state
236
223
  only through explicit directives.
237
224
 
225
+ **Why not just use a plain dict?**
226
+ A plain dict is enough to drive prompt construction, schema selection, and
227
+ other host behavior.
228
+
229
+ Context Compiler solves a different problem: who updates that state, under what
230
+ rules, and what happens when instructions conflict.
231
+
232
+ ```text
233
+ User: use python_script
234
+ User: prohibit python_script
235
+ ```
236
+
237
+ With a plain dict, the application must invent conflict-resolution rules.
238
+ Context Compiler applies deterministic state-transition rules and can return
239
+ clarification instead of silently overwriting state.
240
+
238
241
  ---
239
242
 
240
243
  ## 10-Second Example
@@ -181,24 +181,27 @@ uv run pytest
181
181
 
182
182
  ## FAQ
183
183
 
184
- **Is this just prompt reinjection?**
185
- Reinjection helps with persistence, and it remains useful. Context Compiler
186
- handles a different problem: rules for when state is allowed to change.
187
-
188
- Examples:
189
- - replacement semantics (`use X instead of Y`) when `Y` may not exist
190
- - contradiction detection before applying a mutation
191
- - lifecycle enforcement (for example, you cannot change an unset premise)
192
- - pending clarification flows that must be resolved before other mutations
193
-
194
- In short: reinjection carries state forward; Context Compiler decides when your
195
- app should change state.
196
-
197
184
  **Isn’t this just prompt engineering?**
198
185
  It complements prompt engineering, but solves a different problem. Prompting
199
186
  shapes model behavior. Context Compiler enforces state rules and updates state
200
187
  only through explicit directives.
201
188
 
189
+ **Why not just use a plain dict?**
190
+ A plain dict is enough to drive prompt construction, schema selection, and
191
+ other host behavior.
192
+
193
+ Context Compiler solves a different problem: who updates that state, under what
194
+ rules, and what happens when instructions conflict.
195
+
196
+ ```text
197
+ User: use python_script
198
+ User: prohibit python_script
199
+ ```
200
+
201
+ With a plain dict, the application must invent conflict-resolution rules.
202
+ Context Compiler applies deterministic state-transition rules and can return
203
+ clarification instead of silently overwriting state.
204
+
202
205
  ---
203
206
 
204
207
  ## 10-Second Example
@@ -37,6 +37,13 @@ Gateway-level integration using a LiteLLM pre-call hook.
37
37
 
38
38
  See: [LiteLLM Proxy README](litellm_proxy/README.md)
39
39
 
40
+ ## Ollama structured output (host-side schema selection)
41
+
42
+ Minimal example showing host-side JSON Schema selection for Ollama `format` based on
43
+ Context Compiler policy state.
44
+
45
+ See: [ollama_structured_output/README.md](ollama_structured_output/README.md)
46
+
40
47
  ## Open WebUI Pipe Function
41
48
 
42
49
  Tested target: Open WebUI `v0.8.12`.
@@ -175,7 +175,7 @@ def _persist_session_checkpoint_if_needed(
175
175
  ) -> None:
176
176
  if session_key is None:
177
177
  return
178
- if kind not in {"update", "clarify"}:
178
+ if kind not in {DECISION_UPDATE, DECISION_CLARIFY}:
179
179
  return
180
180
  _CHECKPOINTS_BY_SESSION_KEY[session_key] = engine.export_checkpoint_json()
181
181
 
@@ -305,7 +305,7 @@ def handle_turn(user_input: str, engine: Engine, *, session_key: str | None = No
305
305
  near_miss_prompt,
306
306
  original_input=user_input,
307
307
  compiler_input=user_input,
308
- decision={"kind": "clarify", "prompt_to_user": near_miss_prompt},
308
+ decision={"kind": DECISION_CLARIFY, "prompt_to_user": near_miss_prompt},
309
309
  state_before=state_before,
310
310
  state_after=engine.state,
311
311
  llm_called=False,
@@ -286,7 +286,7 @@ def _persist_session_checkpoint_if_needed(
286
286
  ) -> None:
287
287
  if session_key is None:
288
288
  return
289
- if kind not in {"update", "clarify"}:
289
+ if kind not in {DECISION_UPDATE, DECISION_CLARIFY}:
290
290
  return
291
291
  _CHECKPOINTS_BY_SESSION_KEY[session_key] = engine.export_checkpoint_json()
292
292
 
@@ -430,7 +430,7 @@ def handle_turn(user_input: str, engine: Engine, *, session_key: str | None = No
430
430
  original_input=user_input,
431
431
  compiler_input=compile_input,
432
432
  preprocessor_output=preprocessd,
433
- decision={"kind": "clarify", "prompt_to_user": near_miss_prompt},
433
+ decision={"kind": DECISION_CLARIFY, "prompt_to_user": near_miss_prompt},
434
434
  state_before=state_before,
435
435
  state_after=engine.state,
436
436
  llm_called=False,
@@ -0,0 +1,58 @@
1
+ # Ollama structured output (host-side selection)
2
+
3
+ This example shows a visible host behavior change that is different from prompt reinjection.
4
+
5
+ Flow:
6
+
7
+ `Context Compiler state -> host schema decision -> Ollama format request -> model call`
8
+
9
+ The host reads compiled policy state, picks a JSON Schema (or none), and sends that choice through Ollama's `format` field.
10
+
11
+ ## What this example guarantees
12
+
13
+ - Context Compiler provides deterministic state transitions.
14
+ - The host integration decides whether to request a schema.
15
+ - Ollama structured output is a runtime request made by the host.
16
+ - If policy state is unknown or insufficient, the host requests no schema.
17
+
18
+ ## What `prohibit shell_command` means here
19
+
20
+ - The host will not request the `shell_command` schema.
21
+ - The host may still request a different schema when policy supports it (for example, `python_script`).
22
+ - This does not block normal language discussion about shell commands.
23
+
24
+ ## Observable behavior
25
+
26
+ Given policy state:
27
+
28
+ ```text
29
+ use python_script
30
+ prohibit shell_command
31
+ ```
32
+
33
+ this host selects `python_script` schema and does not request `shell_command` schema.
34
+
35
+ ## Test boundary
36
+
37
+ Tests verify schema selection behavior only:
38
+
39
+ - compiler state -> selected schema (or no schema)
40
+ - contradiction handling stays in compiler `clarify`
41
+
42
+ Tests do not assert exact model wording.
43
+
44
+ ## Run without Ollama
45
+
46
+ ```shell
47
+ uv run python examples/integrations/ollama_structured_output/example.py
48
+ ```
49
+
50
+ ## Optional Ollama smoke run
51
+
52
+ ```shell
53
+ export RUN_OLLAMA_SMOKE=1
54
+ export OLLAMA_MODEL=llama3.1
55
+ uv run python examples/integrations/ollama_structured_output/example.py
56
+ ```
57
+
58
+ When smoke mode is enabled, the host sends the selected JSON Schema through Ollama `format`.
@@ -0,0 +1,169 @@
1
+ """Minimal host-side Ollama structured-output schema selection.
2
+
3
+ Flow:
4
+ Context Compiler state -> host selection logic -> Ollama `format` JSON Schema.
5
+
6
+ This example keeps model execution optional so tests can validate behavior without Ollama.
7
+ """
8
+
9
+ import json
10
+ import os
11
+ import urllib.error
12
+ import urllib.request
13
+ from collections.abc import Mapping
14
+ from typing import Any, TypedDict, cast
15
+
16
+ from context_compiler import (
17
+ POLICY_PROHIBIT,
18
+ POLICY_USE,
19
+ State,
20
+ create_engine,
21
+ get_clarify_prompt,
22
+ get_decision_state,
23
+ get_policy_items,
24
+ is_clarify,
25
+ )
26
+ from context_compiler.engine import Engine
27
+
28
+ PYTHON_SCRIPT_SCHEMA: dict[str, Any] = {
29
+ "type": "object",
30
+ "properties": {
31
+ "python_script": {
32
+ "type": "string",
33
+ "description": "A complete Python script.",
34
+ }
35
+ },
36
+ "required": ["python_script"],
37
+ "additionalProperties": False,
38
+ }
39
+
40
+ SHELL_COMMAND_SCHEMA: dict[str, Any] = {
41
+ "type": "object",
42
+ "properties": {
43
+ "shell_command": {
44
+ "type": "string",
45
+ "description": "A single shell command.",
46
+ }
47
+ },
48
+ "required": ["shell_command"],
49
+ "additionalProperties": False,
50
+ }
51
+
52
+ # Small, explicit mapping from policy item -> Ollama `format` schema.
53
+ _SCHEMA_BY_ITEM: dict[str, dict[str, Any]] = {
54
+ "python_script": PYTHON_SCRIPT_SCHEMA,
55
+ "shell_command": SHELL_COMMAND_SCHEMA,
56
+ }
57
+
58
+
59
+ class TurnPlan(TypedDict):
60
+ decision_kind: str
61
+ clarify_prompt: str | None
62
+ selected_schema_item: str | None
63
+ format_schema: dict[str, Any] | None
64
+
65
+
66
+ def select_ollama_format_schema(state: State) -> tuple[str | None, dict[str, Any] | None]:
67
+ """Return (policy_item, schema) or (None, None) when no safe match exists.
68
+
69
+ Unknown/insufficient policy state intentionally selects no schema.
70
+ """
71
+
72
+ use_items = set(get_policy_items(state, POLICY_USE))
73
+ prohibit_items = set(get_policy_items(state, POLICY_PROHIBIT))
74
+
75
+ for item, schema in _SCHEMA_BY_ITEM.items():
76
+ if item in use_items and item not in prohibit_items:
77
+ return item, schema
78
+
79
+ return None, None
80
+
81
+
82
+ def plan_turn(user_input: str, engine: Engine) -> TurnPlan:
83
+ """Run compiler step and decide whether to request Ollama structured output."""
84
+
85
+ decision = engine.step(user_input)
86
+ if is_clarify(decision):
87
+ return {
88
+ "decision_kind": "clarify",
89
+ "clarify_prompt": get_clarify_prompt(decision),
90
+ "selected_schema_item": None,
91
+ "format_schema": None,
92
+ }
93
+
94
+ decision_state = get_decision_state(decision)
95
+ compiled_state = decision_state if decision_state is not None else engine.state
96
+ selected_item, format_schema = select_ollama_format_schema(compiled_state)
97
+
98
+ return {
99
+ "decision_kind": str(decision["kind"]),
100
+ "clarify_prompt": None,
101
+ "selected_schema_item": selected_item,
102
+ "format_schema": format_schema,
103
+ }
104
+
105
+
106
+ def optional_ollama_call(
107
+ *,
108
+ user_input: str,
109
+ model: str,
110
+ format_schema: Mapping[str, Any] | None,
111
+ host: str | None = None,
112
+ ) -> dict[str, Any]:
113
+ """Optional smoke call to Ollama's /api/chat.
114
+
115
+ If `format_schema` is provided, it is passed through `format` exactly.
116
+ """
117
+
118
+ base_url = host or os.getenv("OLLAMA_BASE_URL") or "http://localhost:11434"
119
+ payload: dict[str, Any] = {
120
+ "model": model,
121
+ "messages": [{"role": "user", "content": user_input}],
122
+ "stream": False,
123
+ }
124
+ if format_schema is not None:
125
+ payload["format"] = dict(format_schema)
126
+
127
+ request = urllib.request.Request(
128
+ url=f"{base_url.rstrip('/')}/api/chat",
129
+ data=json.dumps(payload).encode("utf-8"),
130
+ headers={"Content-Type": "application/json"},
131
+ method="POST",
132
+ )
133
+
134
+ try:
135
+ with urllib.request.urlopen(request, timeout=30) as response:
136
+ raw = response.read().decode("utf-8")
137
+ except urllib.error.URLError as exc:
138
+ raise RuntimeError(f"Ollama call failed: {exc}") from exc
139
+
140
+ decoded = cast(object, json.loads(raw))
141
+ if not isinstance(decoded, dict):
142
+ raise RuntimeError("Ollama response must be a JSON object")
143
+ return cast(dict[str, Any], decoded)
144
+
145
+
146
+ def main() -> None:
147
+ engine = create_engine()
148
+
149
+ # Demonstration setup.
150
+ engine.step("use python_script")
151
+ engine.step("prohibit shell_command")
152
+
153
+ plan = plan_turn("Write a helper script to parse CSV files.", engine)
154
+ print("decision_kind:", plan["decision_kind"])
155
+ print("selected_schema_item:", plan["selected_schema_item"])
156
+ print("format_schema_selected:", plan["format_schema"] is not None)
157
+
158
+ # Optional model execution path; disabled by default.
159
+ if os.getenv("RUN_OLLAMA_SMOKE") == "1":
160
+ response = optional_ollama_call(
161
+ user_input="Write a helper script to parse CSV files.",
162
+ model=os.getenv("OLLAMA_MODEL", "llama3.1"),
163
+ format_schema=plan["format_schema"],
164
+ )
165
+ print("ollama_response_keys:", sorted(response.keys()))
166
+
167
+
168
+ if __name__ == "__main__":
169
+ main()
@@ -3,7 +3,7 @@ title: Context Compiler Pipe
3
3
  author: rlippmann
4
4
  author_url: https://github.com/rlippmann/context-compiler
5
5
  funding_url: https://github.com/rlippmann/context-compiler
6
- version: 0.9.2
6
+ version: 0.9.3
7
7
  requirements: context-compiler>=0.7.4
8
8
 
9
9
  Minimal Open WebUI Pipe integration for Context Compiler.
@@ -643,7 +643,7 @@ class Pipe:
643
643
  near_miss_prompt,
644
644
  original_input=latest_user_text,
645
645
  compiler_input=latest_user_text,
646
- decision={"kind": "clarify", "prompt_to_user": near_miss_prompt},
646
+ decision={"kind": DECISION_CLARIFY, "prompt_to_user": near_miss_prompt},
647
647
  state_before=state_before,
648
648
  state_after=state_after,
649
649
  llm_called=False,
@@ -3,7 +3,7 @@ title: Context Compiler Pipe (Preprocessor)
3
3
  author: rlippmann
4
4
  author_url: https://github.com/rlippmann/context-compiler
5
5
  funding_url: https://github.com/rlippmann/context-compiler
6
- version: 0.9.2
6
+ version: 0.9.3
7
7
  requirements: context-compiler[experimental]>=0.7.4
8
8
 
9
9
  Open WebUI integration with Context Compiler preprocessor.
@@ -922,7 +922,7 @@ class Pipe:
922
922
  near_miss_prompt,
923
923
  original_input=latest_user_text,
924
924
  compiler_input=compile_input,
925
- decision={"kind": "clarify", "prompt_to_user": near_miss_prompt},
925
+ decision={"kind": DECISION_CLARIFY, "prompt_to_user": near_miss_prompt},
926
926
  state_before=state_before,
927
927
  state_after=state_after,
928
928
  preprocessor_output=preprocessd,
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "context-compiler"
7
- version = "0.7.4"
7
+ version = "0.7.6"
8
8
  description = "Deterministic conversational state engine for LLM applications."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -84,6 +84,11 @@ def _block_optional_imports(
84
84
  [
85
85
  (INTEGRATIONS_DIR / "litellm" / "basic.py", ("litellm",), False),
86
86
  (INTEGRATIONS_DIR / "litellm" / "with_preprocessor.py", ("litellm",), False),
87
+ (
88
+ INTEGRATIONS_DIR / "ollama_structured_output" / "example.py",
89
+ (),
90
+ False,
91
+ ),
87
92
  (
88
93
  INTEGRATIONS_DIR / "litellm_proxy" / "context_compiler_precall_hook.py",
89
94
  ("litellm",),
@@ -0,0 +1,60 @@
1
+ import importlib.util
2
+ from pathlib import Path
3
+
4
+ from context_compiler import create_engine
5
+
6
+ REPO_ROOT = Path(__file__).resolve().parents[1]
7
+ EXAMPLE_PATH = REPO_ROOT / "examples" / "integrations" / "ollama_structured_output" / "example.py"
8
+
9
+
10
+ def _load_module():
11
+ spec = importlib.util.spec_from_file_location("ollama_structured_output_example", EXAMPLE_PATH)
12
+ assert spec is not None and spec.loader is not None
13
+ module = importlib.util.module_from_spec(spec)
14
+ spec.loader.exec_module(module)
15
+ return module
16
+
17
+
18
+ def test_use_python_script_selects_python_schema() -> None:
19
+ module = _load_module()
20
+ engine = create_engine()
21
+
22
+ first = engine.step("use python_script")
23
+ assert first["kind"] == "update"
24
+
25
+ plan = module.plan_turn("write script", engine)
26
+ assert plan["selected_schema_item"] == "python_script"
27
+ assert plan["format_schema"] == module.PYTHON_SCRIPT_SCHEMA
28
+
29
+
30
+ def test_prohibit_shell_command_does_not_select_shell_schema() -> None:
31
+ module = _load_module()
32
+ engine = create_engine()
33
+
34
+ assert engine.step("use python_script")["kind"] == "update"
35
+ assert engine.step("prohibit shell_command")["kind"] == "update"
36
+
37
+ plan = module.plan_turn("do task", engine)
38
+ assert plan["selected_schema_item"] == "python_script"
39
+ assert plan["format_schema"] != module.SHELL_COMMAND_SCHEMA
40
+
41
+
42
+ def test_unknown_or_no_matching_state_selects_no_schema() -> None:
43
+ module = _load_module()
44
+ engine = create_engine()
45
+
46
+ plan = module.plan_turn("hello", engine)
47
+ assert plan["decision_kind"] == "passthrough"
48
+ assert plan["selected_schema_item"] is None
49
+ assert plan["format_schema"] is None
50
+
51
+
52
+ def test_contradictory_input_is_compiler_clarify_not_host_resolution() -> None:
53
+ module = _load_module()
54
+ engine = create_engine()
55
+
56
+ assert engine.step("use python_script")["kind"] == "update"
57
+ conflict_plan = module.plan_turn("prohibit python_script", engine)
58
+ assert conflict_plan["decision_kind"] == "clarify"
59
+ assert conflict_plan["selected_schema_item"] is None
60
+ assert conflict_plan["format_schema"] is None
@@ -468,7 +468,7 @@ wheels = [
468
468
 
469
469
  [[package]]
470
470
  name = "context-compiler"
471
- version = "0.7.4"
471
+ version = "0.7.6"
472
472
  source = { editable = "." }
473
473
 
474
474
  [package.optional-dependencies]