context-compiler-example-integrations 0.1.0__py3-none-any.whl

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 (65) hide show
  1. context_compiler_example_integrations/README.md +71 -0
  2. context_compiler_example_integrations/__init__.py +1 -0
  3. context_compiler_example_integrations/examples/__init__.py +12 -0
  4. context_compiler_example_integrations/examples/_shared/__init__.py +1 -0
  5. context_compiler_example_integrations/examples/_shared/litellm_request.py +61 -0
  6. context_compiler_example_integrations/examples/_shared/provider_mode.py +91 -0
  7. context_compiler_example_integrations/examples/checkpoint_continuation/README.md +77 -0
  8. context_compiler_example_integrations/examples/checkpoint_continuation/example.py +169 -0
  9. context_compiler_example_integrations/examples/checkpoint_continuation/fastapi/README.md +85 -0
  10. context_compiler_example_integrations/examples/checkpoint_continuation/fastapi/app.py +205 -0
  11. context_compiler_example_integrations/examples/execution_authorization/README.md +31 -0
  12. context_compiler_example_integrations/examples/execution_authorization/expense_approval/README.md +77 -0
  13. context_compiler_example_integrations/examples/execution_authorization/expense_approval/__init__.py +1 -0
  14. context_compiler_example_integrations/examples/execution_authorization/expense_approval/example.py +168 -0
  15. context_compiler_example_integrations/examples/execution_authorization/expense_approval/fastapi/README.md +97 -0
  16. context_compiler_example_integrations/examples/execution_authorization/expense_approval/fastapi/__init__.py +1 -0
  17. context_compiler_example_integrations/examples/execution_authorization/expense_approval/fastapi/app.py +312 -0
  18. context_compiler_example_integrations/examples/execution_authorization/expense_approval/fastapi/model_approval.py +98 -0
  19. context_compiler_example_integrations/examples/gateway_middleware/README.md +49 -0
  20. context_compiler_example_integrations/examples/gateway_middleware/customer_support_routing/README.md +40 -0
  21. context_compiler_example_integrations/examples/gateway_middleware/customer_support_routing/__init__.py +1 -0
  22. context_compiler_example_integrations/examples/gateway_middleware/customer_support_routing/example.py +220 -0
  23. context_compiler_example_integrations/examples/prompt_construction/README.md +27 -0
  24. context_compiler_example_integrations/examples/prompt_construction/litellm/README.md +197 -0
  25. context_compiler_example_integrations/examples/prompt_construction/litellm/basic.py +392 -0
  26. context_compiler_example_integrations/examples/prompt_construction/litellm/confirmation_helper.py +91 -0
  27. context_compiler_example_integrations/examples/prompt_construction/litellm/with_directive_drafter.py +524 -0
  28. context_compiler_example_integrations/examples/prompt_construction/writing_assistant/README.md +92 -0
  29. context_compiler_example_integrations/examples/prompt_construction/writing_assistant/__init__.py +1 -0
  30. context_compiler_example_integrations/examples/prompt_construction/writing_assistant/example.py +205 -0
  31. context_compiler_example_integrations/examples/retrieval_filtering/README.md +65 -0
  32. context_compiler_example_integrations/examples/retrieval_filtering/chromadb_hr_policy_lookup/README.md +120 -0
  33. context_compiler_example_integrations/examples/retrieval_filtering/chromadb_hr_policy_lookup/__init__.py +1 -0
  34. context_compiler_example_integrations/examples/retrieval_filtering/chromadb_hr_policy_lookup/example.py +320 -0
  35. context_compiler_example_integrations/examples/retrieval_filtering/hr_policy_lookup/README.md +123 -0
  36. context_compiler_example_integrations/examples/retrieval_filtering/hr_policy_lookup/__init__.py +1 -0
  37. context_compiler_example_integrations/examples/retrieval_filtering/hr_policy_lookup/example.py +300 -0
  38. context_compiler_example_integrations/examples/schema_selection/README.md +41 -0
  39. context_compiler_example_integrations/examples/schema_selection/litellm_response_format/response_format.py +218 -0
  40. context_compiler_example_integrations/examples/schema_selection/ollama_structured_output/README.md +60 -0
  41. context_compiler_example_integrations/examples/schema_selection/ollama_structured_output/example.py +171 -0
  42. context_compiler_example_integrations/examples/schema_selection/refund_intake/README.md +95 -0
  43. context_compiler_example_integrations/examples/schema_selection/refund_intake/__init__.py +1 -0
  44. context_compiler_example_integrations/examples/schema_selection/refund_intake/example.py +180 -0
  45. context_compiler_example_integrations/examples/tool_gating/README.md +55 -0
  46. context_compiler_example_integrations/examples/tool_gating/calendar_admin/README.md +34 -0
  47. context_compiler_example_integrations/examples/tool_gating/calendar_admin/__init__.py +1 -0
  48. context_compiler_example_integrations/examples/tool_gating/calendar_admin/example.py +195 -0
  49. context_compiler_example_integrations/examples/tool_gating/mcp_calendar_admin/README.md +93 -0
  50. context_compiler_example_integrations/examples/tool_gating/mcp_calendar_admin/__init__.py +1 -0
  51. context_compiler_example_integrations/examples/tool_gating/mcp_calendar_admin/example.py +250 -0
  52. context_compiler_example_integrations/examples/tool_gating/mcp_calendar_admin/live_model.py +369 -0
  53. context_compiler_example_integrations/reference_integrations/__init__.py +12 -0
  54. context_compiler_example_integrations/reference_integrations/litellm_proxy/README.md +251 -0
  55. context_compiler_example_integrations/reference_integrations/litellm_proxy/_checkpoint_support.py +146 -0
  56. context_compiler_example_integrations/reference_integrations/litellm_proxy/config.example.yaml +23 -0
  57. context_compiler_example_integrations/reference_integrations/litellm_proxy/context_compiler_precall_hook.py +163 -0
  58. context_compiler_example_integrations/reference_integrations/litellm_proxy/context_compiler_precall_hook_with_directive_drafter.py +289 -0
  59. context_compiler_example_integrations/reference_integrations/openwebui_pipe/README.md +233 -0
  60. context_compiler_example_integrations/reference_integrations/openwebui_pipe/open_webui_pipe.py +750 -0
  61. context_compiler_example_integrations/reference_integrations/openwebui_pipe/open_webui_pipe_with_directive_drafter.py +1045 -0
  62. context_compiler_example_integrations-0.1.0.dist-info/METADATA +110 -0
  63. context_compiler_example_integrations-0.1.0.dist-info/RECORD +65 -0
  64. context_compiler_example_integrations-0.1.0.dist-info/WHEEL +4 -0
  65. context_compiler_example_integrations-0.1.0.dist-info/licenses/LICENSE +173 -0
@@ -0,0 +1,220 @@
1
+ """Minimal host-side gateway middleware for customer support routing."""
2
+
3
+ from dataclasses import dataclass, field
4
+ from typing import Literal, TypedDict, cast
5
+
6
+ from context_compiler import (
7
+ POLICY_PROHIBIT,
8
+ POLICY_USE,
9
+ State,
10
+ create_engine,
11
+ get_decision_state,
12
+ get_policy_items,
13
+ is_clarify,
14
+ )
15
+ from context_compiler.engine import Engine
16
+
17
+
18
+ class SupportRequest(TypedDict):
19
+ request_id: str
20
+ customer_id: str
21
+ queue_hint: str
22
+ message: str
23
+
24
+
25
+ class RoutedRequest(TypedDict):
26
+ request_id: str
27
+ customer_id: str
28
+ queue: Literal["general_support", "billing_support"]
29
+ message: str
30
+
31
+
32
+ class GatewayResult(TypedDict):
33
+ gateway_decision: Literal["forwarded", "blocked", "defaulted"]
34
+ routed_queue: Literal["general_support", "billing_support"] | None
35
+ blocked_reason: str | None
36
+ downstream_called: bool
37
+ downstream_response: str | None
38
+ gateway_log: list[str]
39
+ downstream_log: list[str]
40
+
41
+
42
+ class GatewayTurnResult(TypedDict):
43
+ decision_kind: Literal["clarify", "update", "passthrough"]
44
+ prompt_to_user: str | None
45
+ gateway_result: GatewayResult
46
+
47
+
48
+ def _decision_kind_name(
49
+ decision: object,
50
+ ) -> Literal["clarify", "update", "passthrough"]:
51
+ if not isinstance(decision, dict):
52
+ raise ValueError("unexpected decision shape")
53
+
54
+ kind = decision.get("kind")
55
+ kind_name = getattr(kind, "value", None)
56
+ if kind_name not in {"clarify", "update", "passthrough"}:
57
+ raise ValueError(f"unexpected decision kind: {kind_name}")
58
+
59
+ return cast(Literal["clarify", "update", "passthrough"], kind_name)
60
+
61
+
62
+ @dataclass
63
+ class SupportService:
64
+ """Downstream handler that the gateway may or may not call."""
65
+
66
+ downstream_log: list[str] = field(default_factory=list)
67
+
68
+ def handle(self, request: RoutedRequest) -> str:
69
+ self.downstream_log.append(
70
+ f"handled:{request['queue']}:{request['request_id']}"
71
+ )
72
+ return f"{request['queue']} handled {request['request_id']}"
73
+
74
+
75
+ @dataclass
76
+ class SupportGateway:
77
+ """Host-owned gateway boundary and routing behavior."""
78
+
79
+ gateway_log: list[str] = field(default_factory=list)
80
+
81
+ def forward(
82
+ self,
83
+ request: SupportRequest,
84
+ *,
85
+ queue: Literal["general_support", "billing_support"],
86
+ gateway_decision: Literal["forwarded", "defaulted"] = "forwarded",
87
+ downstream: SupportService,
88
+ ) -> GatewayResult:
89
+ self.gateway_log.append(f"{gateway_decision}:{queue}:{request['request_id']}")
90
+ routed_request: RoutedRequest = {
91
+ "request_id": request["request_id"],
92
+ "customer_id": request["customer_id"],
93
+ "queue": queue,
94
+ "message": request["message"],
95
+ }
96
+ downstream_response = downstream.handle(routed_request)
97
+ return {
98
+ "gateway_decision": gateway_decision,
99
+ "routed_queue": queue,
100
+ "blocked_reason": None,
101
+ "downstream_called": True,
102
+ "downstream_response": downstream_response,
103
+ "gateway_log": self.gateway_log.copy(),
104
+ "downstream_log": downstream.downstream_log.copy(),
105
+ }
106
+
107
+ def block(self, request: SupportRequest, *, reason: str) -> GatewayResult:
108
+ self.gateway_log.append(f"blocked:{request['request_id']}")
109
+ return {
110
+ "gateway_decision": "blocked",
111
+ "routed_queue": None,
112
+ "blocked_reason": reason,
113
+ "downstream_called": False,
114
+ "downstream_response": None,
115
+ "gateway_log": self.gateway_log.copy(),
116
+ "downstream_log": [],
117
+ }
118
+
119
+
120
+ def billing_support_is_allowed(state: State) -> bool:
121
+ """Allow billing support only from explicit authoritative compiler state."""
122
+
123
+ use_items = set(get_policy_items(state, POLICY_USE))
124
+ prohibit_items = set(get_policy_items(state, POLICY_PROHIBIT))
125
+
126
+ if "billing_support" in prohibit_items:
127
+ return False
128
+
129
+ return "billing_support" in use_items
130
+
131
+
132
+ def route_support_request(
133
+ request: SupportRequest,
134
+ *,
135
+ state: State,
136
+ gateway: SupportGateway,
137
+ downstream: SupportService,
138
+ ) -> GatewayResult:
139
+ """Make the gateway decision before any downstream call."""
140
+
141
+ if request["queue_hint"] != "billing_support":
142
+ return gateway.forward(
143
+ request,
144
+ queue="general_support",
145
+ gateway_decision="defaulted",
146
+ downstream=downstream,
147
+ )
148
+
149
+ if not billing_support_is_allowed(state):
150
+ return gateway.block(
151
+ request,
152
+ reason="billing_support state not authorized",
153
+ )
154
+
155
+ return gateway.forward(
156
+ request,
157
+ queue="billing_support",
158
+ downstream=downstream,
159
+ )
160
+
161
+
162
+ def handle_gateway_turn(
163
+ engine: Engine,
164
+ *,
165
+ compiler_input: str,
166
+ request: SupportRequest,
167
+ gateway: SupportGateway,
168
+ downstream: SupportService,
169
+ ) -> GatewayTurnResult:
170
+ """Block routing changes on clarify and otherwise enforce authoritative state."""
171
+
172
+ decision = engine.step(compiler_input)
173
+
174
+ if is_clarify(decision):
175
+ return {
176
+ "decision_kind": "clarify",
177
+ "prompt_to_user": decision.get("prompt_to_user"),
178
+ "gateway_result": gateway.block(
179
+ request,
180
+ reason="clarification required before gateway routing",
181
+ ),
182
+ }
183
+
184
+ authoritative_state = get_decision_state(decision)
185
+ if authoritative_state is None:
186
+ authoritative_state = engine.state
187
+
188
+ return {
189
+ "decision_kind": _decision_kind_name(decision),
190
+ "prompt_to_user": decision.get("prompt_to_user"),
191
+ "gateway_result": route_support_request(
192
+ request,
193
+ state=authoritative_state,
194
+ gateway=gateway,
195
+ downstream=downstream,
196
+ ),
197
+ }
198
+
199
+
200
+ def run_demo() -> GatewayResult:
201
+ """Run a deterministic gateway demonstration with explicit policy state."""
202
+
203
+ engine = create_engine()
204
+ engine.step("use billing_support")
205
+
206
+ request: SupportRequest = {
207
+ "request_id": "support-100",
208
+ "customer_id": "customer-123",
209
+ "queue_hint": "billing_support",
210
+ "message": "Need help correcting an invoice charge.",
211
+ }
212
+ gateway = SupportGateway()
213
+ downstream = SupportService()
214
+
215
+ return route_support_request(
216
+ request,
217
+ state=engine.state,
218
+ gateway=gateway,
219
+ downstream=downstream,
220
+ )
@@ -0,0 +1,27 @@
1
+ # Request construction / context assembly
2
+
3
+ These examples show how a host assembles prompts from explicit authoritative
4
+ Context Compiler state before any model call would occur.
5
+
6
+ ## Current examples
7
+
8
+ - [writing_assistant](./writing_assistant/README.md): generic Python prompt
9
+ construction for a writing assistant with no LLM call, contrasting factual
10
+ document context premise with a small concise-style policy
11
+ - [litellm](./litellm/README.md): LiteLLM-oriented prompt-construction flows,
12
+ including an optional directive-drafter variant
13
+
14
+ ## Related integrations
15
+
16
+ These generic/examples-first docs teach the enforcement point.
17
+
18
+ Related concrete runtime surfaces:
19
+
20
+ - [python/reference_integrations/openwebui_pipe/README.md](../../reference_integrations/openwebui_pipe/README.md): Open WebUI pipe integration
21
+
22
+ ## Example requirements
23
+
24
+ - Host owns prompt assembly.
25
+ - Context Compiler owns authoritative state.
26
+ - Examples must not derive state from model output.
27
+ - Examples must remain meaningful with an adversarial stub or no model call.
@@ -0,0 +1,197 @@
1
+ # LiteLLM examples
2
+
3
+ Saved compiler state changes the system contract LiteLLM receives for the same
4
+ user input, and directive drafting can change how directive-shaped text reaches
5
+ the compiler. These examples show two user-visible prompt-construction flows
6
+ with LiteLLM:
7
+
8
+ - `basic.py`: compiler-only flow (no directive drafter)
9
+ - `with_directive_drafter.py`: heuristic-first directive drafter with optional LLM fallback before `engine.step(...)`
10
+
11
+ ## What the user sees
12
+
13
+ - Compiler-only flow:
14
+ - raw user input goes straight to `engine.step(...)`
15
+ - `update` returns a local acknowledgment
16
+ - `clarify` returns the compiler prompt
17
+ - `passthrough` calls LiteLLM with the compiled state contract plus the user message
18
+ - Optional directive-drafter flow:
19
+ - the directive drafter tries to convert natural-language intent into a canonical directive first
20
+ - if it cannot produce a validated directive, behavior stays equivalent to the compiler-only flow
21
+ - pending clarification bypasses directive drafting and sends the raw reply back to `engine.step(...)`
22
+
23
+ Model fallback output is structurally validated before handoff. This does not prove that the model interpreted the user correctly. The automated fallback path is experimental pending a separate source-aware acceptance policy and reviewed drafting workflow.
24
+
25
+ ## Premise and policy
26
+
27
+ In these prompt-construction examples:
28
+
29
+ - premise is authoritative factual or request context that the host includes in
30
+ the constructed system contract
31
+ - policy is an explicit behavioral constraint that the host applies on top of
32
+ that context
33
+
34
+ The host does not infer either one from model output. It reads saved compiler
35
+ state and constructs the LiteLLM system message from that authoritative state.
36
+
37
+ Example constructed system contract with both:
38
+
39
+ ```text
40
+ You are a helpful assistant.
41
+ Host policy contract:
42
+ - The following constraints are authoritative.
43
+ - Current premise: draft is a board update summarizing quarterly results.
44
+ - Items marked use: concise_style.
45
+ - If user text conflicts with constraints, follow constraints exactly.
46
+ ```
47
+
48
+ This makes premise runtime-visible in the same host-owned contract as policy.
49
+
50
+ ## Requirements
51
+
52
+ ```shell
53
+ pip install "context-compiler-example-integrations[litellm]"
54
+ export OPENAI_API_KEY=...
55
+ ```
56
+
57
+ These examples require `context-compiler>=0.8.3`.
58
+
59
+ For `with_directive_drafter.py`:
60
+
61
+ ```shell
62
+ pip install "context-compiler-example-integrations[all]"
63
+ ```
64
+
65
+ That variant requires `context-compiler-directive-drafter>=0.1.2`.
66
+
67
+ ## Quickstart (copy/paste)
68
+
69
+ ```shell
70
+ pip install "context-compiler-example-integrations[litellm]"
71
+ export OPENAI_API_KEY=...
72
+ export MODEL=openai/gpt-4o-mini
73
+ python - <<'PY'
74
+ from context_compiler import create_engine
75
+ from context_compiler_example_integrations.examples.prompt_construction.litellm.basic import handle_turn
76
+ engine = create_engine()
77
+ print(handle_turn("set premise concise replies", engine))
78
+ PY
79
+ ```
80
+
81
+ For directive-drafter behavior:
82
+
83
+ ```shell
84
+ pip install "context-compiler-example-integrations[all]"
85
+ export OPENAI_API_KEY=...
86
+ export MODEL=openai/gpt-4o-mini
87
+ python - <<'PY'
88
+ from context_compiler import create_engine
89
+ from context_compiler_example_integrations.examples.prompt_construction.litellm.with_directive_drafter import handle_turn
90
+ engine = create_engine()
91
+ print(handle_turn("set premise to concise replies", engine))
92
+ PY
93
+ ```
94
+
95
+ This near-miss input should return `clarify` instead of being rewritten.
96
+
97
+ ## Environment configuration
98
+
99
+ The shared provider contract for live-model examples in this repository is
100
+ documented in
101
+ [PROVIDER_CONTRACT.md](../../../../PROVIDER_CONTRACT.md).
102
+
103
+ ## Usage pattern
104
+
105
+ Use these files as host-side integration references.
106
+
107
+ - Import `handle_turn(...)` from either `basic.py` or `with_directive_drafter.py`.
108
+ - Create and retain an engine instance in host/session state.
109
+ - Pass each user input through `handle_turn(user_input, engine)`.
110
+ - Optional checkpointing: pass `session_key=...`.
111
+ The example restores checkpoint data before the first `engine.step(...)` and
112
+ saves checkpoint data after `update`/`clarify`.
113
+ - In this example, checkpoint/session storage is in-memory only.
114
+ State lasts only for the current process. To survive restarts, store
115
+ checkpoints in external storage (DB/Redis/etc.).
116
+ - Display the returned assistant text.
117
+
118
+ In these LiteLLM examples, `update` is rendered locally and does not call
119
+ the downstream LLM. This makes state changes explicit. Production apps may
120
+ choose different rendering behavior.
121
+
122
+ ## Related schema-selection example
123
+
124
+ If you want the host to choose a LiteLLM `response_format` from saved compiler state
125
+ instead of reinjecting a compiled contract, use
126
+ `python/examples/schema_selection/litellm_response_format/response_format.py`.
127
+
128
+ - Context Compiler owns authoritative state.
129
+ - The host reads saved policy state and selects a LiteLLM `response_format` or omits it.
130
+ - LiteLLM owns model invocation and provider behavior.
131
+ - Context Compiler does not call LiteLLM on its own.
132
+ - Context Compiler does not validate model output.
133
+ - Context Compiler does not generate schemas dynamically.
134
+ - This is application-layer use of authoritative state, not compiler semantics.
135
+
136
+ ## Troubleshooting
137
+
138
+ - `litellm is required`: install `context-compiler` and `litellm` (and `context-compiler-directive-drafter` for directive-drafter flows).
139
+ - `OPENAI_API_KEY is required in openai mode`: export a key or use `ollama` / explicit endpoint override.
140
+ - `Invalid PROVIDER value ...`: set `PROVIDER` to one of `openai`, `ollama`, `openai_compatible`.
141
+ - `OPENAI_BASE_URL is required when PROVIDER=openai_compatible`: set an explicit endpoint URL.
142
+ - model/provider errors (`Model not found`, provider auth errors): confirm `MODEL` uses LiteLLM format and provider credentials are valid.
143
+
144
+ ## Prompt-construction decision flow
145
+
146
+ In both prompt-construction examples in this directory:
147
+
148
+ - `passthrough`: call the model with normal input.
149
+ - `clarify`: show `prompt_to_user`; do not treat state as changed.
150
+ - `update`: state changed; use updated state for the next model call.
151
+
152
+ ## Related schema-selection decision flow
153
+
154
+ In the related schema-selection example:
155
+
156
+ - `passthrough`: let the host decide whether to send `response_format`.
157
+ - `clarify`: show `prompt_to_user`; do not call LiteLLM.
158
+ - `update`: state changed; the next host request may use a different `response_format`.
159
+
160
+ ## Example checks
161
+
162
+ - Premise and policy visibility (`basic.py`):
163
+ - save a premise such as `set premise draft is a board update summarizing quarterly results`
164
+ - save a policy such as `use concise_style`
165
+ - on the next passthrough turn, the LiteLLM system message includes both
166
+ `Current premise: ...` and `Items marked use: concise_style.`
167
+ - Near-miss passthrough (`with_directive_drafter.py`):
168
+ - `set premise to concise replies` is not rewritten by the directive drafter and is passed through unchanged.
169
+ - Engine returns clarify (`Did you mean 'set premise concise replies'?`).
170
+ - Compound directives (`with_directive_drafter.py`):
171
+ - `use docker and prohibit peanuts` returns a local clarify asking for separate directives.
172
+ - No authoritative state is mutated and no downstream model call is made for that turn.
173
+ - Lifecycle enforcement (both):
174
+ - `change premise to formal tone` with no premise -> clarify (`set premise ...` first).
175
+ - Conflict behavior (both):
176
+ - `use docker` then `prohibit docker` -> conflict clarify.
177
+ - Replacement precondition (both):
178
+ - `use podman instead of docker` without prior `use docker` -> replacement clarify.
179
+ - Directive-adjacent abstain (`with_directive_drafter.py`):
180
+ - `change premise concise replies` is classified as `unknown`, not rewritten, and handled by engine clarify.
181
+ - Host-side request shaping (`python/examples/schema_selection/litellm_response_format/response_format.py`):
182
+ - `use compact_summary` -> host selects compact-summary `response_format`.
183
+ - `use action_plan` -> host selects action-plan `response_format`.
184
+ - `prohibit compact_summary` -> host omits that `response_format`.
185
+
186
+ ## Optional smoke run for the schema-selection example
187
+
188
+ ```shell
189
+ export RUN_LITELLM_SMOKE=1
190
+ export PROVIDER=ollama
191
+ export MODEL=ollama/qwen2.5:1.5b-instruct
192
+ uv run python python/examples/schema_selection/litellm_response_format/response_format.py
193
+ ```
194
+
195
+ For local Ollama smoke runs in this repo, `PROVIDER=ollama` is required. A
196
+ `MODEL=ollama/...` value by itself still follows the default OpenAI provider
197
+ path.