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.
- context_compiler_example_integrations/README.md +71 -0
- context_compiler_example_integrations/__init__.py +1 -0
- context_compiler_example_integrations/examples/__init__.py +12 -0
- context_compiler_example_integrations/examples/_shared/__init__.py +1 -0
- context_compiler_example_integrations/examples/_shared/litellm_request.py +61 -0
- context_compiler_example_integrations/examples/_shared/provider_mode.py +91 -0
- context_compiler_example_integrations/examples/checkpoint_continuation/README.md +77 -0
- context_compiler_example_integrations/examples/checkpoint_continuation/example.py +169 -0
- context_compiler_example_integrations/examples/checkpoint_continuation/fastapi/README.md +85 -0
- context_compiler_example_integrations/examples/checkpoint_continuation/fastapi/app.py +205 -0
- context_compiler_example_integrations/examples/execution_authorization/README.md +31 -0
- context_compiler_example_integrations/examples/execution_authorization/expense_approval/README.md +77 -0
- context_compiler_example_integrations/examples/execution_authorization/expense_approval/__init__.py +1 -0
- context_compiler_example_integrations/examples/execution_authorization/expense_approval/example.py +168 -0
- context_compiler_example_integrations/examples/execution_authorization/expense_approval/fastapi/README.md +97 -0
- context_compiler_example_integrations/examples/execution_authorization/expense_approval/fastapi/__init__.py +1 -0
- context_compiler_example_integrations/examples/execution_authorization/expense_approval/fastapi/app.py +312 -0
- context_compiler_example_integrations/examples/execution_authorization/expense_approval/fastapi/model_approval.py +98 -0
- context_compiler_example_integrations/examples/gateway_middleware/README.md +49 -0
- context_compiler_example_integrations/examples/gateway_middleware/customer_support_routing/README.md +40 -0
- context_compiler_example_integrations/examples/gateway_middleware/customer_support_routing/__init__.py +1 -0
- context_compiler_example_integrations/examples/gateway_middleware/customer_support_routing/example.py +220 -0
- context_compiler_example_integrations/examples/prompt_construction/README.md +27 -0
- context_compiler_example_integrations/examples/prompt_construction/litellm/README.md +197 -0
- context_compiler_example_integrations/examples/prompt_construction/litellm/basic.py +392 -0
- context_compiler_example_integrations/examples/prompt_construction/litellm/confirmation_helper.py +91 -0
- context_compiler_example_integrations/examples/prompt_construction/litellm/with_directive_drafter.py +524 -0
- context_compiler_example_integrations/examples/prompt_construction/writing_assistant/README.md +92 -0
- context_compiler_example_integrations/examples/prompt_construction/writing_assistant/__init__.py +1 -0
- context_compiler_example_integrations/examples/prompt_construction/writing_assistant/example.py +205 -0
- context_compiler_example_integrations/examples/retrieval_filtering/README.md +65 -0
- context_compiler_example_integrations/examples/retrieval_filtering/chromadb_hr_policy_lookup/README.md +120 -0
- context_compiler_example_integrations/examples/retrieval_filtering/chromadb_hr_policy_lookup/__init__.py +1 -0
- context_compiler_example_integrations/examples/retrieval_filtering/chromadb_hr_policy_lookup/example.py +320 -0
- context_compiler_example_integrations/examples/retrieval_filtering/hr_policy_lookup/README.md +123 -0
- context_compiler_example_integrations/examples/retrieval_filtering/hr_policy_lookup/__init__.py +1 -0
- context_compiler_example_integrations/examples/retrieval_filtering/hr_policy_lookup/example.py +300 -0
- context_compiler_example_integrations/examples/schema_selection/README.md +41 -0
- context_compiler_example_integrations/examples/schema_selection/litellm_response_format/response_format.py +218 -0
- context_compiler_example_integrations/examples/schema_selection/ollama_structured_output/README.md +60 -0
- context_compiler_example_integrations/examples/schema_selection/ollama_structured_output/example.py +171 -0
- context_compiler_example_integrations/examples/schema_selection/refund_intake/README.md +95 -0
- context_compiler_example_integrations/examples/schema_selection/refund_intake/__init__.py +1 -0
- context_compiler_example_integrations/examples/schema_selection/refund_intake/example.py +180 -0
- context_compiler_example_integrations/examples/tool_gating/README.md +55 -0
- context_compiler_example_integrations/examples/tool_gating/calendar_admin/README.md +34 -0
- context_compiler_example_integrations/examples/tool_gating/calendar_admin/__init__.py +1 -0
- context_compiler_example_integrations/examples/tool_gating/calendar_admin/example.py +195 -0
- context_compiler_example_integrations/examples/tool_gating/mcp_calendar_admin/README.md +93 -0
- context_compiler_example_integrations/examples/tool_gating/mcp_calendar_admin/__init__.py +1 -0
- context_compiler_example_integrations/examples/tool_gating/mcp_calendar_admin/example.py +250 -0
- context_compiler_example_integrations/examples/tool_gating/mcp_calendar_admin/live_model.py +369 -0
- context_compiler_example_integrations/reference_integrations/__init__.py +12 -0
- context_compiler_example_integrations/reference_integrations/litellm_proxy/README.md +251 -0
- context_compiler_example_integrations/reference_integrations/litellm_proxy/_checkpoint_support.py +146 -0
- context_compiler_example_integrations/reference_integrations/litellm_proxy/config.example.yaml +23 -0
- context_compiler_example_integrations/reference_integrations/litellm_proxy/context_compiler_precall_hook.py +163 -0
- context_compiler_example_integrations/reference_integrations/litellm_proxy/context_compiler_precall_hook_with_directive_drafter.py +289 -0
- context_compiler_example_integrations/reference_integrations/openwebui_pipe/README.md +233 -0
- context_compiler_example_integrations/reference_integrations/openwebui_pipe/open_webui_pipe.py +750 -0
- context_compiler_example_integrations/reference_integrations/openwebui_pipe/open_webui_pipe_with_directive_drafter.py +1045 -0
- context_compiler_example_integrations-0.1.0.dist-info/METADATA +110 -0
- context_compiler_example_integrations-0.1.0.dist-info/RECORD +65 -0
- context_compiler_example_integrations-0.1.0.dist-info/WHEEL +4 -0
- 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.
|