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
6 changes: 3 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,12 @@ Issues = "https://github.com/rlippmann/context-compiler-example-integrations/iss
[project.optional-dependencies]
all = [
"chromadb",
"context-compiler-directive-drafter==0.2.0dev2",
"context-compiler-directive-drafter==0.2.0dev4",
"fastapi",
"litellm",
]
drafter = [
"context-compiler-directive-drafter==0.2.0dev2",
"context-compiler-directive-drafter==0.2.0dev4",
]
fastapi = [
"fastapi",
Expand All @@ -67,7 +67,7 @@ retrieval = [
[dependency-groups]
dev = [
"chromadb",
"context-compiler-directive-drafter==0.2.0dev2",
"context-compiler-directive-drafter==0.2.0dev4",
"fastapi",
"httpx2>=2.5.0",
"httpx>=0.28.1",
Expand Down
2 changes: 1 addition & 1 deletion python/examples/prompt_construction/litellm/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ For `with_directive_drafter.py`:
pip install "context-compiler-example-integrations[all]"
```

That variant requires `context-compiler-directive-drafter>=0.2.0dev2`.
That variant requires `context-compiler-directive-drafter>=0.2.0dev4`.

## Quickstart (copy/paste)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,10 @@
from context_compiler_directive_drafter import (
DraftResult,
DirectiveDrafter,
NoDirective,
RejectedDirective,
UnknownDirective,
get_converter_prompt,
)
from context_compiler_directive_drafter.fallbacks import get_converter_prompt

from context_compiler_example_integrations.examples._shared.provider_mode import (
print_startup_config,
Expand Down Expand Up @@ -262,7 +262,7 @@ def _extract_drafted_text(drafted_result: DraftResult) -> str | None:
result = drafted_result.result
if isinstance(result, CanonicalDirective):
return result.text
if isinstance(result, NoDirective):
if isinstance(result, RejectedDirective):
return None
if isinstance(result, UnknownDirective):
return None
Expand Down
2 changes: 1 addition & 1 deletion python/reference_integrations/litellm_proxy/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ For `context_compiler_precall_hook_with_directive_drafter.py`:
pip install "context-compiler-example-integrations[all]"
```

That variant requires `context-compiler-directive-drafter>=0.2.0dev2`.
That variant requires `context-compiler-directive-drafter>=0.2.0dev4`.

For the opt-in runtime smoke test, install the proxy runtime extras:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ class CustomLogger: # type: ignore[no-redef]
from context_compiler_directive_drafter import (
DirectiveDrafter,
DraftResult,
get_converter_prompt,
)
from context_compiler_directive_drafter.fallbacks import get_converter_prompt
from context_compiler_example_integrations.reference_integrations.litellm_proxy._checkpoint_support import (
MODE_PERSISTENT,
CheckpointStore,
Expand Down
6 changes: 3 additions & 3 deletions python/reference_integrations/openwebui_pipe/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ These examples require `context-compiler>=0.9.0dev13`.
If using `open_webui_pipe_with_directive_drafter.py`:

- Install directive-drafter support if needed:
`pip install "context-compiler>=0.9.0dev13" "context-compiler-directive-drafter>=0.2.0dev2"`
`pip install "context-compiler>=0.9.0dev13" "context-compiler-directive-drafter>=0.2.0dev4"`
- Set `PREPROCESSOR_PROMPT_PROFILE=default` for heuristic-first behavior
- Optionally set `PREPROCESSOR_MODEL_ID` to use a separate fallback drafting model
- If `PREPROCESSOR_MODEL_ID` is unset, fallback uses `BASE_MODEL_ID`
Expand All @@ -86,7 +86,7 @@ If frontmatter dependency installs are disabled, offline, or unavailable:
1. Install the package manually:

- Minimal pipe: `pip install "context-compiler>=0.9.0dev13"`
- Directive Drafter pipe: `pip install "context-compiler>=0.9.0dev13" "context-compiler-directive-drafter>=0.2.0dev2"`
- Directive Drafter pipe: `pip install "context-compiler>=0.9.0dev13" "context-compiler-directive-drafter>=0.2.0dev4"`

1. Import and enable the function in Open WebUI, then configure valves.

Expand Down Expand Up @@ -246,7 +246,7 @@ rejection flows.
- `PREPROCESSOR_MODEL_ID must not match the selected pipe model id`: choose a real backend model id, not the pipe model id itself.
- `PREPROCESSOR_MODEL_ID is invalid or not configured in Open WebUI`: the fallback route hit a missing model; fix the configured fallback model or unset it to reuse `BASE_MODEL_ID`.
- `ALLOW_MISSING_BASE_MODEL_FOR_DEBUG=true`: directive-only updates still run locally, but passthrough returns a deterministic debug message instead of calling a downstream model.
- imports fail after function upload: install `context-compiler>=0.9.0dev13` in the Open WebUI runtime, and add `context-compiler-directive-drafter>=0.2.0dev2` only for the Directive Drafter pipe, because the copied function runs from a temp/cached location.
- imports fail after function upload: install `context-compiler>=0.9.0dev13` in the Open WebUI runtime, and add `context-compiler-directive-drafter>=0.2.0dev4` only for the Directive Drafter pipe, because the copied function runs from a temp/cached location.

## Fallback notes

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
title: Context Compiler Open WebUI Pipe (Directive Drafter)
author: rlippmann
author_url: https://github.com/rlippmann/context-compiler-example-integrations
version: 0.10.0
requirements: context-compiler>=0.9.0dev13, context-compiler-directive-drafter>=0.2.0dev2
version: 0.10.1
requirements: context-compiler>=0.9.0dev13, context-compiler-directive-drafter>=0.2.0dev4

Open WebUI integration with Context Compiler directive drafter.

Expand Down Expand Up @@ -59,10 +59,10 @@ def Field(*, default: Any, description: str = "") -> Any: # type: ignore[no-red
from context_compiler_directive_drafter import (
DirectiveDrafter,
DraftResult,
NoDirective,
RejectedDirective,
UnknownDirective,
get_converter_prompt,
)
from context_compiler_directive_drafter.fallbacks import get_converter_prompt

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -683,7 +683,7 @@ async def fallback(candidate_message: str) -> str | None:
def _extract_drafted_text(self, drafted_result: DraftResult) -> str | None:
if isinstance(drafted_result.result, CanonicalDirective):
return drafted_result.result.text
if isinstance(drafted_result.result, NoDirective):
if isinstance(drafted_result.result, RejectedDirective):
return None
if isinstance(drafted_result.result, UnknownDirective):
return None
Expand Down
16 changes: 10 additions & 6 deletions python/tests/test_litellm_proxy_with_directive_drafter.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@

import pytest
from context_compiler.grammar import decompose_directive
from context_compiler_directive_drafter import NoDirective, UnknownDirective
from context_compiler_directive_drafter import (
REASON_MULTIPLE_DIRECTIVES,
REASON_NON_DIRECTIVE,
RejectedDirective,
)

REPO_ROOT = Path(__file__).resolve().parents[2]
MODULE_PATH = (
Expand Down Expand Up @@ -51,7 +55,7 @@ def fake_draft(message: str) -> object:
drafted_calls.append((message, {}))
return module.DraftResult(
source="test",
result=NoDirective(reason="reject.confident_non_directive"),
result=RejectedDirective(reason=REASON_NON_DIRECTIVE),
)

monkeypatch.setattr(module, "_draft_last_user_message", fake_draft)
Expand Down Expand Up @@ -156,7 +160,7 @@ def test_default_mode_is_stateless_and_requires_no_session_key(monkeypatch) -> N
"_draft_last_user_message",
lambda message: module.DraftResult(
source="test",
result=NoDirective(reason="reject.confident_non_directive"),
result=RejectedDirective(reason=REASON_NON_DIRECTIVE),
),
)
data = {
Expand All @@ -177,7 +181,7 @@ def test_stateless_mode_has_no_cross_call_continuity(monkeypatch) -> None:
"_draft_last_user_message",
lambda message: module.DraftResult(
source="test",
result=NoDirective(reason="reject.confident_non_directive"),
result=RejectedDirective(reason=REASON_NON_DIRECTIVE),
),
)
first = {
Expand Down Expand Up @@ -307,7 +311,7 @@ def fake_draft(message: str) -> object:
seen_messages.append(message)
return module.DraftResult(
source="test",
result=NoDirective(reason="reject.confident_non_directive"),
result=RejectedDirective(reason=REASON_NON_DIRECTIVE),
)

monkeypatch.setattr(module, "_draft_last_user_message", fake_draft)
Expand Down Expand Up @@ -381,7 +385,7 @@ def test_compound_directives_fall_through_to_normal_forwarding_when_not_applied(
"_draft_last_user_message",
lambda _message: module.DraftResult(
source="test",
result=UnknownDirective(reason="reject.multi_candidate_directive"),
result=RejectedDirective(reason=REASON_MULTIPLE_DIRECTIVES),
),
)
data = {
Expand Down
15 changes: 10 additions & 5 deletions python/tests/test_litellm_with_directive_drafter.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
from context_compiler_directive_drafter import (
DirectiveDrafter,
DraftResult,
NoDirective,
REASON_INCOMPLETE,
REASON_NON_DIRECTIVE,
RejectedDirective,
UnknownDirective,
)

Expand Down Expand Up @@ -136,7 +138,7 @@ def downstream(messages: list[dict[str, str]]) -> str:

monkeypatch.setattr(module, "_call_litellm", downstream)

result = module.handle_turn("please use docker", engine)
result = module.handle_turn("maybe use docker", engine)

assert compile_inputs == []
assert result == "stubbed reply"
Expand All @@ -150,7 +152,7 @@ def test_extract_drafted_text_observes_draft_result_behavior() -> None:
assert module._extract_drafted_text(drafted_result) == "use docker"

no_directive_result = DraftResult(
source="test", result=NoDirective("not a directive")
source="test", result=RejectedDirective(reason=REASON_NON_DIRECTIVE)
)

assert module._extract_drafted_text(no_directive_result) is None
Expand Down Expand Up @@ -222,7 +224,7 @@ def downstream(messages: list[dict[str, str]]) -> str:
)

clarify_engine = Engine()
clarify = module.handle_turn("set premise to concise replies", clarify_engine)
clarify = module.handle_turn("set premise to", clarify_engine)

assert clarify == "downstream reply"
assert llm_calls
Expand Down Expand Up @@ -393,7 +395,10 @@ def fallback(_message: str) -> str | None:
monkeypatch.setattr(module, "_call_litellm", lambda _messages: "downstream reply")

assert module.handle_turn("use docker instead of", Engine()) == "downstream reply"
assert fallback_calls == 1
drafted_result = module._DIRECTIVE_DRAFTER.draft_directive("use docker instead of")
assert isinstance(drafted_result.result, RejectedDirective)
assert drafted_result.result.reason == REASON_INCOMPLETE
assert fallback_calls == 0


def test_compound_directives_fall_through_when_not_applied(monkeypatch) -> None:
Expand Down
Loading
Loading