Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@ instead of direct key traversal.
| `step(user_input)` | Parse one user turn and return a deterministic `Decision`. |
| `compile_transcript(messages: Transcript)` | Replay a transcript from a fresh engine and return either final state or a confirmation prompt. |
| `engine.apply_transcript(messages: Transcript)` | Replay a transcript onto the current engine state and return either final state or a confirmation prompt. |
| `engine.state` | Read current authoritative in-memory state snapshot. |
| `engine.state` | Read the current opaque authoritative in-memory state snapshot; for normal host reads, prefer `get_premise_value(state)` and `get_policy_items(state, ...)`. |
| `engine.has_pending_clarification()` | Return whether a confirmation-required clarification is currently pending. |
| `get_premise_value(state)` | Read the current premise value from a state snapshot. |
| `get_policy_items(state, value=None)` | Read policy items from a state snapshot (all, `use`, or `prohibit`). |
Expand Down Expand Up @@ -535,6 +535,9 @@ It is designed to be conservative and must be used with validation:
- no directive grammar expansion
- raw outputs must not be passed directly to the compiler

If `engine.has_pending_clarification()` is true, bypass preprocessing and pass raw input directly to `engine.step(...)`.
Boundary policy is false-negative-preferred: abstain rather than risk unsafe state mutation.

See [LLM preprocessor](docs/llm-preprocessor.md) and
[`experimental/preprocessor/`](experimental/preprocessor/) for details.

Expand Down
17 changes: 11 additions & 6 deletions demos/09_llm_pending_clarification.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
"""Demo 9: pending clarification requires confirmation-only continuation."""

from context_compiler import DECISION_CLARIFY, DECISION_UPDATE, State, create_engine
from context_compiler import (
DECISION_CLARIFY,
DECISION_UPDATE,
POLICY_USE,
State,
create_engine,
get_policy_items,
)
from demos.common import (
build_baseline_messages,
build_reinjected_messages,
Expand All @@ -19,17 +26,15 @@
TURN_1 = "use podman instead of docker"
TURN_2 = "maybe"
TURN_3 = "yes"
INITIAL_AUTHORITATIVE_STATE = create_engine().state


def _has_podman_use(state: State) -> bool:
policies = state.get("policies")
if not isinstance(policies, dict):
return False
return policies.get("podman") == "use"
return "podman" in get_policy_items(state, POLICY_USE)


def _is_initial_authoritative_state(state: State) -> bool:
return state == {"premise": None, "policies": {}, "version": 2}
return state == INITIAL_AUTHORITATIVE_STATE


def main() -> None:
Expand Down
1 change: 1 addition & 0 deletions examples/integrations/litellm/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ choose different rendering behavior.
- If heuristic returns a directive, that directive is passed to `engine.step(...)`.
- If heuristic does not produce a directive (`no_directive` or `unknown`), LLM fallback prompt conversion runs.
- If fallback yields nothing usable or errors, behavior safely remains equivalent to basic.
- If `engine.has_pending_clarification()` is true, bypass preprocessing and pass raw input directly to `engine.step(...)`.
- Behavior is reject-first and does not broaden the directive grammar.

Decision flow in both examples:
Expand Down
1 change: 1 addition & 0 deletions examples/integrations/litellm_proxy/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ Preprocessor-enabled variant behavior:

- Only the latest user transcript message is preprocessed for compiler replay input.
- Heuristic runs first; if no directive is found, LLM fallback is attempted.
- If `engine.has_pending_clarification()` is true, bypass preprocessing and pass raw input directly to `engine.step(...)`.
- Forwarded upstream request messages are not rewritten (except injected compiler system message).

Optional env vars for preprocessor fallback:
Expand Down
2 changes: 2 additions & 0 deletions examples/integrations/openwebui/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ Decision flow in both pipes:
- `clarify`: show `prompt_to_user`; do not change saved state.
- `update`: state changed; render local acknowledgment for directive-only input, or call downstream model with updated state injected.

For the preprocessor pipe, if `engine.has_pending_clarification()` is true, bypass preprocessing and pass raw input directly to `engine.step(...)`.

## Behavioral comparisons

**Case 1**
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "hatchling.build"

[project]
name = "context-compiler"
version = "0.7.7"
version = "0.7.8"
description = "Deterministic conversational state engine for LLM applications."
readme = "README.md"
requires-python = ">=3.11"
Expand Down
2 changes: 1 addition & 1 deletion uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading