context-compiler 0.9.0.dev13__tar.gz → 0.9.0.dev14__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 (37) hide show
  1. {context_compiler-0.9.0.dev13 → context_compiler-0.9.0.dev14}/PKG-INFO +20 -7
  2. {context_compiler-0.9.0.dev13 → context_compiler-0.9.0.dev14}/README.md +19 -6
  3. {context_compiler-0.9.0.dev13 → context_compiler-0.9.0.dev14}/pyproject.toml +1 -1
  4. {context_compiler-0.9.0.dev13 → context_compiler-0.9.0.dev14}/src/context_compiler/grammar.py +31 -3
  5. {context_compiler-0.9.0.dev13 → context_compiler-0.9.0.dev14}/.gitignore +0 -0
  6. {context_compiler-0.9.0.dev13 → context_compiler-0.9.0.dev14}/LICENSE +0 -0
  7. {context_compiler-0.9.0.dev13 → context_compiler-0.9.0.dev14}/demos/01_llm_contradiction_error.py +0 -0
  8. {context_compiler-0.9.0.dev13 → context_compiler-0.9.0.dev14}/demos/02_llm_constraint_guardrail.py +0 -0
  9. {context_compiler-0.9.0.dev13 → context_compiler-0.9.0.dev14}/demos/03_llm_premise_guardrail.py +0 -0
  10. {context_compiler-0.9.0.dev13 → context_compiler-0.9.0.dev14}/demos/04_llm_tool_denylist_guardrail.py +0 -0
  11. {context_compiler-0.9.0.dev13 → context_compiler-0.9.0.dev14}/demos/05_llm_prompt_drift_vs_state.py +0 -0
  12. {context_compiler-0.9.0.dev13 → context_compiler-0.9.0.dev14}/demos/06_llm_context_compaction.py +0 -0
  13. {context_compiler-0.9.0.dev13 → context_compiler-0.9.0.dev14}/demos/07_llm_prompt_vs_state.py +0 -0
  14. {context_compiler-0.9.0.dev13 → context_compiler-0.9.0.dev14}/demos/08_llm_replacement_precondition.py +0 -0
  15. {context_compiler-0.9.0.dev13 → context_compiler-0.9.0.dev14}/demos/README.md +0 -0
  16. {context_compiler-0.9.0.dev13 → context_compiler-0.9.0.dev14}/demos/__init__.py +0 -0
  17. {context_compiler-0.9.0.dev13 → context_compiler-0.9.0.dev14}/demos/common.py +0 -0
  18. {context_compiler-0.9.0.dev13 → context_compiler-0.9.0.dev14}/demos/llm_client.py +0 -0
  19. {context_compiler-0.9.0.dev13 → context_compiler-0.9.0.dev14}/demos/run_demo.py +0 -0
  20. {context_compiler-0.9.0.dev13 → context_compiler-0.9.0.dev14}/examples/01_persistent_guardrails.py +0 -0
  21. {context_compiler-0.9.0.dev13 → context_compiler-0.9.0.dev14}/examples/02_configuration_and_correction.py +0 -0
  22. {context_compiler-0.9.0.dev13 → context_compiler-0.9.0.dev14}/examples/03_ambiguity_with_error.py +0 -0
  23. {context_compiler-0.9.0.dev13 → context_compiler-0.9.0.dev14}/examples/04_tool_governance_denylist.py +0 -0
  24. {context_compiler-0.9.0.dev13 → context_compiler-0.9.0.dev14}/examples/05_llm_integration_pattern.py +0 -0
  25. {context_compiler-0.9.0.dev13 → context_compiler-0.9.0.dev14}/examples/06_step_sequence_and_state_restore.py +0 -0
  26. {context_compiler-0.9.0.dev13 → context_compiler-0.9.0.dev14}/examples/07_single_policy_correction.py +0 -0
  27. {context_compiler-0.9.0.dev13 → context_compiler-0.9.0.dev14}/examples/08_apply_directive_decisions.py +0 -0
  28. {context_compiler-0.9.0.dev13 → context_compiler-0.9.0.dev14}/examples/README.md +0 -0
  29. {context_compiler-0.9.0.dev13 → context_compiler-0.9.0.dev14}/examples/_util.py +0 -0
  30. {context_compiler-0.9.0.dev13 → context_compiler-0.9.0.dev14}/host_support/__init__.py +0 -0
  31. {context_compiler-0.9.0.dev13 → context_compiler-0.9.0.dev14}/host_support/provider_mode.py +0 -0
  32. {context_compiler-0.9.0.dev13 → context_compiler-0.9.0.dev14}/src/context_compiler/__init__.py +0 -0
  33. {context_compiler-0.9.0.dev13 → context_compiler-0.9.0.dev14}/src/context_compiler/const.py +0 -0
  34. {context_compiler-0.9.0.dev13 → context_compiler-0.9.0.dev14}/src/context_compiler/decision.py +0 -0
  35. {context_compiler-0.9.0.dev13 → context_compiler-0.9.0.dev14}/src/context_compiler/engine.py +0 -0
  36. {context_compiler-0.9.0.dev13 → context_compiler-0.9.0.dev14}/src/context_compiler/py.typed +0 -0
  37. {context_compiler-0.9.0.dev13 → context_compiler-0.9.0.dev14}/src/context_compiler/repl.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: context-compiler
3
- Version: 0.9.0.dev13
3
+ Version: 0.9.0.dev14
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
@@ -25,6 +25,7 @@ Description-Content-Type: text/markdown
25
25
  [![PyPI version](https://img.shields.io/pypi/v/context-compiler)](https://pypi.org/project/context-compiler/)
26
26
  [![Python versions](https://img.shields.io/pypi/pyversions/context-compiler)](https://pypi.org/project/context-compiler/)
27
27
  [![License](https://img.shields.io/pypi/l/context-compiler)](https://pypi.org/project/context-compiler/)
28
+ [![codecov](https://codecov.io/gh/rlippmann/context-compiler/branch/main/graph/badge.svg)](https://codecov.io/gh/rlippmann/context-compiler)
28
29
 
29
30
  Context Compiler is a deterministic conversational state authority for LLM applications.
30
31
  It handles canonical directive execution, semantic validation, terminal error
@@ -95,7 +96,7 @@ set premise concise replies
95
96
  - Base model: silently accepts / rewrites
96
97
  - Context Compiler: applies a repeatable state update
97
98
 
98
- ### Single-directive grammar
99
+ ### Compound directive rejection
99
100
 
100
101
  ```text
101
102
  use docker and prohibit peanuts
@@ -113,7 +114,7 @@ use podman instead of docker
113
114
 
114
115
  - Without explicit state transition rules: behavior depends on host/model handling
115
116
  - Context Compiler: applies the deterministic resulting transition when
116
- `docker` is absent and `use podman` is otherwise valid; other semantic
117
+ `docker` is present and `use podman` is otherwise valid; other semantic
117
118
  conflicts may still error
118
119
 
119
120
  ### Lifecycle enforcement
@@ -272,6 +273,10 @@ uv sync --dev
272
273
  uv run pytest
273
274
  ```
274
275
 
276
+ CI enforces 100% coverage for the core `src/context_compiler` package. The
277
+ coverage badge represents that authoritative core-package target, not the
278
+ entire repository.
279
+
275
280
  ## Decision API
276
281
 
277
282
  Each user message produces one immutable `Decision` variant. Use concrete
@@ -480,7 +485,8 @@ User: reset policies
480
485
  User: clear state
481
486
  ```
482
487
 
483
- Grammar invariant: one input may contain at most one canonical directive.
488
+ Grammar invariant: a single input never applies more than one canonical
489
+ directive.
484
490
  Directive-shaped invalid input is outside the canonical language, and
485
491
  `error` is reserved for canonical directives that later fail semantic
486
492
  evaluation against authoritative state.
@@ -504,18 +510,25 @@ clear state
504
510
 
505
511
  Invalid:
506
512
  use docker and prohibit peanuts
507
- set premise vegetarian and use docker
508
513
  clear state then set premise new project
514
+
515
+ Premise payload (opaque):
516
+ set premise vegetarian and use docker
509
517
  ```
510
518
 
519
+ Policy compounds such as `use docker and prohibit peanuts` remain invalid;
520
+ premise `VALUE` is opaque and may contain directive-like words.
521
+
511
522
  Quote behavior follows the current grammar literally:
512
523
 
513
524
  ```text
514
- Passthrough:
525
+ Passthrough (`no_directive`):
515
526
  "use docker and prohibit peanuts"
516
527
 
517
- Invalid:
528
+ Invalid directive:
518
529
  use "docker and prohibit peanuts"
530
+
531
+ Canonical directive (`set premise`):
519
532
  set premise "use docker and prohibit peanuts"
520
533
  ```
521
534
 
@@ -3,6 +3,7 @@
3
3
  [![PyPI version](https://img.shields.io/pypi/v/context-compiler)](https://pypi.org/project/context-compiler/)
4
4
  [![Python versions](https://img.shields.io/pypi/pyversions/context-compiler)](https://pypi.org/project/context-compiler/)
5
5
  [![License](https://img.shields.io/pypi/l/context-compiler)](https://pypi.org/project/context-compiler/)
6
+ [![codecov](https://codecov.io/gh/rlippmann/context-compiler/branch/main/graph/badge.svg)](https://codecov.io/gh/rlippmann/context-compiler)
6
7
 
7
8
  Context Compiler is a deterministic conversational state authority for LLM applications.
8
9
  It handles canonical directive execution, semantic validation, terminal error
@@ -73,7 +74,7 @@ set premise concise replies
73
74
  - Base model: silently accepts / rewrites
74
75
  - Context Compiler: applies a repeatable state update
75
76
 
76
- ### Single-directive grammar
77
+ ### Compound directive rejection
77
78
 
78
79
  ```text
79
80
  use docker and prohibit peanuts
@@ -91,7 +92,7 @@ use podman instead of docker
91
92
 
92
93
  - Without explicit state transition rules: behavior depends on host/model handling
93
94
  - Context Compiler: applies the deterministic resulting transition when
94
- `docker` is absent and `use podman` is otherwise valid; other semantic
95
+ `docker` is present and `use podman` is otherwise valid; other semantic
95
96
  conflicts may still error
96
97
 
97
98
  ### Lifecycle enforcement
@@ -250,6 +251,10 @@ uv sync --dev
250
251
  uv run pytest
251
252
  ```
252
253
 
254
+ CI enforces 100% coverage for the core `src/context_compiler` package. The
255
+ coverage badge represents that authoritative core-package target, not the
256
+ entire repository.
257
+
253
258
  ## Decision API
254
259
 
255
260
  Each user message produces one immutable `Decision` variant. Use concrete
@@ -458,7 +463,8 @@ User: reset policies
458
463
  User: clear state
459
464
  ```
460
465
 
461
- Grammar invariant: one input may contain at most one canonical directive.
466
+ Grammar invariant: a single input never applies more than one canonical
467
+ directive.
462
468
  Directive-shaped invalid input is outside the canonical language, and
463
469
  `error` is reserved for canonical directives that later fail semantic
464
470
  evaluation against authoritative state.
@@ -482,18 +488,25 @@ clear state
482
488
 
483
489
  Invalid:
484
490
  use docker and prohibit peanuts
485
- set premise vegetarian and use docker
486
491
  clear state then set premise new project
492
+
493
+ Premise payload (opaque):
494
+ set premise vegetarian and use docker
487
495
  ```
488
496
 
497
+ Policy compounds such as `use docker and prohibit peanuts` remain invalid;
498
+ premise `VALUE` is opaque and may contain directive-like words.
499
+
489
500
  Quote behavior follows the current grammar literally:
490
501
 
491
502
  ```text
492
- Passthrough:
503
+ Passthrough (`no_directive`):
493
504
  "use docker and prohibit peanuts"
494
505
 
495
- Invalid:
506
+ Invalid directive:
496
507
  use "docker and prohibit peanuts"
508
+
509
+ Canonical directive (`set premise`):
497
510
  set premise "use docker and prohibit peanuts"
498
511
  ```
499
512
 
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "context-compiler"
7
- version = "0.9.0dev13"
7
+ version = "0.9.0dev14"
8
8
  description = "Deterministic conversational state engine for LLM applications."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -316,7 +316,10 @@ def _match_directive_token(
316
316
  token_index += 1
317
317
  continue
318
318
 
319
- if text[index].casefold() != token_char:
319
+ character = text[index]
320
+ if "A" <= character <= "Z":
321
+ character = chr(ord(character) + (ord("a") - ord("A")))
322
+ if character != token_char:
320
323
  return None
321
324
  index += 1
322
325
  token_index += 1
@@ -349,6 +352,18 @@ def _contains_multiple_canonical_directives(text: str) -> bool:
349
352
  return False
350
353
 
351
354
 
355
+ def _contains_multiple_premise_directives(text: str) -> bool:
356
+ """Report premise compounds without inspecting opaque premise payload text."""
357
+ first_start = _match_canonical_directive_start(text, 0)
358
+ if first_start is None:
359
+ return False
360
+
361
+ for index, character in enumerate(text[first_start:], start=first_start):
362
+ if character == "\n" and _match_canonical_directive_start(text, index + 1) is not None:
363
+ return True
364
+ return False
365
+
366
+
352
367
  def _starts_with_directive_family(text: str) -> bool:
353
368
  for token, require_space_or_end in _DIRECTIVE_FAMILY_STARTS:
354
369
  if (
@@ -457,7 +472,12 @@ def _validate_operand_constraints(kind: DirectiveKind, operands: Mapping[str, st
457
472
 
458
473
  def _validate_rendered_canonical_shape(kind: DirectiveKind, operands: Mapping[str, str]) -> None:
459
474
  rendered = _serialize_canonical_directive(kind, MappingProxyType(dict(operands)))
460
- if _contains_multiple_canonical_directives(rendered):
475
+ contains_compound = (
476
+ _contains_multiple_premise_directives(rendered)
477
+ if kind in {DirectiveKind.SET_PREMISE, DirectiveKind.CHANGE_PREMISE}
478
+ else _contains_multiple_canonical_directives(rendered)
479
+ )
480
+ if contains_compound:
461
481
  raise ValueError(f"Operands do not produce a canonical {kind.value} directive.")
462
482
 
463
483
 
@@ -476,7 +496,15 @@ def decompose_directive(text: str) -> CanonicalDirective | InvalidDirectiveSynta
476
496
  return None
477
497
  if not _starts_with_directive_family(trimmed_text):
478
498
  return None
479
- if _contains_multiple_canonical_directives(trimmed_text):
499
+ premise_directive = _match_directive_token(
500
+ trimmed_text, 0, _SET_PREMISE_START, require_space_or_end=True
501
+ ) or _match_directive_token(trimmed_text, 0, _CHANGE_PREMISE_START, require_space_or_end=True)
502
+ contains_compound = (
503
+ _contains_multiple_premise_directives(trimmed_text)
504
+ if premise_directive is not None
505
+ else _contains_multiple_canonical_directives(trimmed_text)
506
+ )
507
+ if contains_compound:
480
508
  return _invalid_directive_syntax(DirectiveSyntaxFailure.COMPOUND_DIRECTIVE)
481
509
 
482
510
  normalized = _normalized_for_matching(trimmed_text)