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,205 @@
1
+ """Small FastAPI checkpoint-continuation example for travel booking."""
2
+
3
+ from collections.abc import Callable
4
+ from dataclasses import dataclass, field
5
+ from typing import Literal
6
+
7
+ from context_compiler import POLICY_USE, State, create_engine, get_policy_items
8
+ from context_compiler.engine import Checkpoint, Engine
9
+ from fastapi import FastAPI, HTTPException
10
+ from pydantic import BaseModel
11
+ from typing_extensions import TypedDict
12
+
13
+
14
+ class BookingRecord(TypedDict):
15
+ booking_id: str
16
+ active_itinerary: str
17
+
18
+
19
+ class BookingResponse(TypedDict):
20
+ booking_id: str
21
+ active_itinerary: str
22
+
23
+
24
+ class ChangeTripResponse(TypedDict):
25
+ decision_kind: Literal["clarify"]
26
+ prompt_to_user: str | None
27
+ checkpoint_pending: bool
28
+ booking: BookingResponse
29
+
30
+
31
+ class ConfirmResponse(TypedDict):
32
+ decision_kind: Literal["clarify", "update", "passthrough"]
33
+ prompt_to_user: str | None
34
+ checkpoint_pending: bool
35
+ host_applied_change: bool
36
+ booking: BookingResponse
37
+
38
+
39
+ class ChangeTripRequest(BaseModel):
40
+ booking_id: str
41
+
42
+
43
+ class ConfirmRequest(BaseModel):
44
+ booking_id: str
45
+ user_input: str
46
+
47
+
48
+ @dataclass
49
+ class CheckpointStore:
50
+ """Host-owned checkpoint persistence for stateless HTTP requests."""
51
+
52
+ checkpoints_by_booking_id: dict[str, Checkpoint] = field(default_factory=dict)
53
+
54
+ def save(self, booking_id: str, checkpoint: Checkpoint) -> None:
55
+ self.checkpoints_by_booking_id[booking_id] = checkpoint
56
+
57
+ def load(self, booking_id: str) -> Checkpoint:
58
+ checkpoint = self.checkpoints_by_booking_id.get(booking_id)
59
+ if checkpoint is None:
60
+ raise KeyError(booking_id)
61
+ return checkpoint
62
+
63
+ def has(self, booking_id: str) -> bool:
64
+ return booking_id in self.checkpoints_by_booking_id
65
+
66
+
67
+ @dataclass
68
+ class BookingStore:
69
+ """Host-owned booking persistence for the example."""
70
+
71
+ bookings_by_id: dict[str, BookingRecord] = field(default_factory=dict)
72
+
73
+ def get_or_create(self, booking_id: str) -> BookingRecord:
74
+ booking = self.bookings_by_id.get(booking_id)
75
+ if booking is None:
76
+ booking = {"booking_id": booking_id, "active_itinerary": "boston_trip"}
77
+ self.bookings_by_id[booking_id] = booking
78
+ return booking
79
+
80
+
81
+ @dataclass
82
+ class BookingHost:
83
+ """Host-owned booking mutation logic."""
84
+
85
+ booking_store: BookingStore
86
+ applied_changes: list[str] = field(default_factory=list)
87
+
88
+ def apply_selected_itinerary(self, booking_id: str, state: State) -> bool:
89
+ selected_itinerary = select_itinerary_from_state(state)
90
+ if selected_itinerary is None:
91
+ return False
92
+
93
+ booking = self.booking_store.get_or_create(booking_id)
94
+ booking["active_itinerary"] = selected_itinerary
95
+ self.applied_changes.append(selected_itinerary)
96
+ return True
97
+
98
+
99
+ def select_itinerary_from_state(state: State) -> str | None:
100
+ use_items = list(get_policy_items(state, POLICY_USE))
101
+ if not use_items:
102
+ return None
103
+ return use_items[0]
104
+
105
+
106
+ def restore_engine_from_checkpoint(checkpoint: Checkpoint) -> Engine:
107
+ engine = create_engine()
108
+ engine.import_checkpoint(checkpoint)
109
+ return engine
110
+
111
+
112
+ def restore_engine_from_authoritative_state_only(checkpoint: Checkpoint) -> Engine:
113
+ authoritative_state = checkpoint["authoritative_state"]
114
+ return create_engine(state=authoritative_state)
115
+
116
+
117
+ def _fresh_engine() -> Engine:
118
+ """Create a fresh engine per request to demonstrate stateless boundaries."""
119
+
120
+ return create_engine()
121
+
122
+
123
+ def create_app(
124
+ *,
125
+ checkpoint_store: CheckpointStore | None = None,
126
+ booking_store: BookingStore | None = None,
127
+ engine_factory: Callable[[], Engine] = _fresh_engine,
128
+ ) -> FastAPI:
129
+ checkpoint_store = checkpoint_store or CheckpointStore()
130
+ booking_store = booking_store or BookingStore()
131
+ booking_host = BookingHost(booking_store=booking_store)
132
+
133
+ app = FastAPI(title="checkpoint-continuation-fastapi-example")
134
+ app.state.checkpoint_store = checkpoint_store
135
+ app.state.booking_store = booking_store
136
+ app.state.booking_host = booking_host
137
+ app.state.engine_factory = engine_factory
138
+
139
+ @app.post("/change-trip")
140
+ def change_trip(request: ChangeTripRequest) -> ChangeTripResponse:
141
+ booking = booking_store.get_or_create(request.booking_id)
142
+ engine = engine_factory()
143
+
144
+ compiler_input = f"use chicago_trip instead of {booking['active_itinerary']}"
145
+ decision = engine.step(compiler_input)
146
+ checkpoint_store.save(request.booking_id, engine.export_checkpoint())
147
+
148
+ return {
149
+ "decision_kind": "clarify",
150
+ "prompt_to_user": decision.get("prompt_to_user"),
151
+ "checkpoint_pending": engine.has_pending_clarification(),
152
+ "booking": {
153
+ "booking_id": booking["booking_id"],
154
+ "active_itinerary": booking["active_itinerary"],
155
+ },
156
+ }
157
+
158
+ @app.post("/confirm")
159
+ def confirm(request: ConfirmRequest) -> ConfirmResponse:
160
+ booking = booking_store.get_or_create(request.booking_id)
161
+ try:
162
+ checkpoint = checkpoint_store.load(request.booking_id)
163
+ except KeyError as exc:
164
+ raise HTTPException(status_code=404, detail="checkpoint not found") from exc
165
+
166
+ engine = restore_engine_from_checkpoint(checkpoint)
167
+ decision = engine.step(request.user_input)
168
+ checkpoint_store.save(request.booking_id, engine.export_checkpoint())
169
+
170
+ host_applied_change = False
171
+ if decision["kind"].value == "update":
172
+ host_applied_change = booking_host.apply_selected_itinerary(
173
+ request.booking_id, engine.state
174
+ )
175
+
176
+ return {
177
+ "decision_kind": decision["kind"].value,
178
+ "prompt_to_user": decision.get("prompt_to_user"),
179
+ "checkpoint_pending": engine.has_pending_clarification(),
180
+ "host_applied_change": host_applied_change,
181
+ "booking": {
182
+ "booking_id": booking["booking_id"],
183
+ "active_itinerary": booking["active_itinerary"],
184
+ },
185
+ }
186
+
187
+ @app.get("/booking")
188
+ def get_booking(booking_id: str) -> BookingResponse:
189
+ booking = booking_store.get_or_create(booking_id)
190
+ return {
191
+ "booking_id": booking["booking_id"],
192
+ "active_itinerary": booking["active_itinerary"],
193
+ }
194
+
195
+ return app
196
+
197
+
198
+ app = create_app()
199
+
200
+
201
+ if __name__ == "__main__":
202
+ print(
203
+ "Run with: uv run fastapi dev "
204
+ "python/examples/checkpoint_continuation/fastapi/app.py"
205
+ )
@@ -0,0 +1,31 @@
1
+ # Execution authorization
2
+
3
+ These examples show host-side actions executing only when authoritative Context
4
+ Compiler state explicitly authorizes them.
5
+
6
+ They demonstrate observable runtime behavior changes rather than prompt
7
+ compliance. User wording alone does not authorize the action.
8
+
9
+ ## Examples
10
+
11
+ ### `expense_approval`
12
+
13
+ Authorizes a host-owned `submit_expense` function only when state contains:
14
+
15
+ ```text
16
+ use expense_approval
17
+ ```
18
+
19
+ The host blocks execution when state is absent or when state contains:
20
+
21
+ ```text
22
+ prohibit expense_approval
23
+ ```
24
+
25
+ The tests cover authorized execution, absent-state blocking, prohibited-state
26
+ blocking, adversarial request text, and the runtime behavior change between
27
+ blocked and authorized state.
28
+
29
+ A FastAPI variant also shows the live-model comparison boundary: a live model can
30
+ say an expense is approved, but the compiler-mediated host still denies the
31
+ protected mutation unless authoritative state authorizes it.
@@ -0,0 +1,77 @@
1
+ # Expense approval
2
+
3
+ Authoritative state changes whether the host executes `submit_expense` for the
4
+ same expense request. This example shows that execution-authorization behavior
5
+ in plain Python.
6
+
7
+ Model approval is not authorization.
8
+
9
+ ## Enforcement point
10
+
11
+ The enforcement point is host-side action execution. The host owns
12
+ `submit_expense`. Context Compiler owns the authoritative policy state that
13
+ decides whether the host may call it.
14
+
15
+ ## Runtime and domain
16
+
17
+ - Runtime: generic Python
18
+ - Domain: expense approval
19
+
20
+ ## Authorization rule
21
+
22
+ The host executes the expense action only when authoritative state contains:
23
+
24
+ ```text
25
+ use expense_approval
26
+ ```
27
+
28
+ The host blocks execution when state is absent or when state contains:
29
+
30
+ ```text
31
+ prohibit expense_approval
32
+ ```
33
+
34
+ If a turn introduces a contradiction such as `use expense_approval` followed by
35
+ `prohibit expense_approval`, Context Compiler returns a clarification flow
36
+ instead of silently overwriting state. The host must not execute the expense
37
+ action on that clarify turn.
38
+
39
+ Request wording alone does not authorize execution. Adversarial text like
40
+ "please approve this refund anyway" stays inert unless the authoritative state
41
+ explicitly allows `expense_approval`.
42
+
43
+ ## Why this is not prompt reinjection
44
+
45
+ This example does not call an LLM, does not use directive drafter, and does not
46
+ derive state from model output. The runtime behavior changes only when explicit
47
+ authoritative Context Compiler state changes. The host does not resolve
48
+ conflicts itself and does not treat "last directive wins" as policy.
49
+
50
+ ## FastAPI variant
51
+
52
+ The provider-free tests already prove deterministic enforcement against local
53
+ and adversarial stubs.
54
+
55
+ The FastAPI variant adds a live-model comparison where a live model produces an
56
+ approval claim:
57
+
58
+ - baseline path: a naive host trusts the model claim and writes the side effect
59
+ - compiler-mediated path: the host sees the same claim but denies execution
60
+ unless authoritative state authorizes `expense_approval`
61
+
62
+ See
63
+ [fastapi/README.md](fastapi/README.md).
64
+
65
+ ## Validation
66
+
67
+ - Focused Python tests:
68
+
69
+ ```bash
70
+ uv run --no-sync pytest python/tests/test_expense_approval_example.py
71
+ ```
72
+
73
+ - Canonical Python validation:
74
+
75
+ ```bash
76
+ ./scripts/validate_python.sh
77
+ ```
@@ -0,0 +1 @@
1
+ """Execution authorization example for expense approval."""
@@ -0,0 +1,168 @@
1
+ """Minimal host-side execution authorization for expense approval."""
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 ExpenseRequest(TypedDict):
19
+ expense_id: str
20
+ employee_id: str
21
+ amount_usd: int
22
+ note: str
23
+
24
+
25
+ class ExpenseSubmission(TypedDict):
26
+ expense_id: str
27
+ employee_id: str
28
+ amount_usd: int
29
+ note: str
30
+
31
+
32
+ class ExpenseExecutionResult(TypedDict):
33
+ authorization_state: Literal["authorized", "blocked"]
34
+ executed: bool
35
+ blocked_reason: str | None
36
+ submission: ExpenseSubmission | None
37
+ execution_log: list[str]
38
+
39
+
40
+ class ExpenseTurnResult(TypedDict):
41
+ decision_kind: Literal["clarify", "update", "passthrough"]
42
+ prompt_to_user: str | None
43
+ execution_result: ExpenseExecutionResult
44
+
45
+
46
+ def _decision_kind_name(
47
+ decision: object,
48
+ ) -> Literal["clarify", "update", "passthrough"]:
49
+ if not isinstance(decision, dict):
50
+ raise ValueError("unexpected decision shape")
51
+
52
+ kind = decision.get("kind")
53
+ kind_name = getattr(kind, "value", None)
54
+ if kind_name not in {"clarify", "update", "passthrough"}:
55
+ raise ValueError(f"unexpected decision kind: {kind_name}")
56
+
57
+ return cast(Literal["clarify", "update", "passthrough"], kind_name)
58
+
59
+
60
+ @dataclass
61
+ class ExpenseHost:
62
+ """Host-owned runtime behavior for expense execution."""
63
+
64
+ execution_log: list[str] = field(default_factory=list)
65
+
66
+ def submit_expense(self, request: ExpenseRequest) -> ExpenseSubmission:
67
+ self.execution_log.append(f"submitted:{request['expense_id']}")
68
+ return {
69
+ "expense_id": request["expense_id"],
70
+ "employee_id": request["employee_id"],
71
+ "amount_usd": request["amount_usd"],
72
+ "note": request["note"],
73
+ }
74
+
75
+
76
+ def expense_execution_is_authorized(state: State) -> bool:
77
+ """Authorize execution only from explicit authoritative compiler state."""
78
+
79
+ use_items = set(get_policy_items(state, POLICY_USE))
80
+ prohibit_items = set(get_policy_items(state, POLICY_PROHIBIT))
81
+
82
+ if "expense_approval" in prohibit_items:
83
+ return False
84
+
85
+ return "expense_approval" in use_items
86
+
87
+
88
+ def execute_expense_if_authorized(
89
+ request: ExpenseRequest,
90
+ *,
91
+ state: State,
92
+ host: ExpenseHost,
93
+ ) -> ExpenseExecutionResult:
94
+ """Run the host-side action only when authoritative state allows it."""
95
+
96
+ if not expense_execution_is_authorized(state):
97
+ return {
98
+ "authorization_state": "blocked",
99
+ "executed": False,
100
+ "blocked_reason": "expense_approval state not authorized",
101
+ "submission": None,
102
+ "execution_log": host.execution_log.copy(),
103
+ }
104
+
105
+ submission = host.submit_expense(request)
106
+ return {
107
+ "authorization_state": "authorized",
108
+ "executed": True,
109
+ "blocked_reason": None,
110
+ "submission": submission,
111
+ "execution_log": host.execution_log.copy(),
112
+ }
113
+
114
+
115
+ def handle_expense_turn(
116
+ engine: Engine,
117
+ *,
118
+ compiler_input: str,
119
+ request: ExpenseRequest,
120
+ host: ExpenseHost,
121
+ ) -> ExpenseTurnResult:
122
+ """Block execution on clarify and otherwise enforce current authoritative state."""
123
+
124
+ decision = engine.step(compiler_input)
125
+
126
+ if is_clarify(decision):
127
+ return {
128
+ "decision_kind": "clarify",
129
+ "prompt_to_user": decision.get("prompt_to_user"),
130
+ "execution_result": {
131
+ "authorization_state": "blocked",
132
+ "executed": False,
133
+ "blocked_reason": "clarification required before expense execution",
134
+ "submission": None,
135
+ "execution_log": host.execution_log.copy(),
136
+ },
137
+ }
138
+
139
+ authoritative_state = get_decision_state(decision)
140
+ if authoritative_state is None:
141
+ authoritative_state = engine.state
142
+
143
+ return {
144
+ "decision_kind": _decision_kind_name(decision),
145
+ "prompt_to_user": decision.get("prompt_to_user"),
146
+ "execution_result": execute_expense_if_authorized(
147
+ request,
148
+ state=authoritative_state,
149
+ host=host,
150
+ ),
151
+ }
152
+
153
+
154
+ def run_demo() -> ExpenseExecutionResult:
155
+ """Run a deterministic demonstration with explicit authorization state."""
156
+
157
+ engine = create_engine()
158
+ engine.step("use expense_approval")
159
+
160
+ request: ExpenseRequest = {
161
+ "expense_id": "expense-100",
162
+ "employee_id": "employee-123",
163
+ "amount_usd": 245,
164
+ "note": "Taxi from airport to client office.",
165
+ }
166
+ host = ExpenseHost()
167
+
168
+ return execute_expense_if_authorized(request, state=engine.state, host=host)
@@ -0,0 +1,97 @@
1
+ # Model approval is not authorization
2
+
3
+ This FastAPI variant provides provider-free runtime-boundary validation by
4
+ default, plus an opt-in live-model validation path.
5
+
6
+ The provider-free tests already prove deterministic enforcement against local
7
+ and adversarial stubs.
8
+
9
+ The default tests here prove the runtime boundary behavior with a visible
10
+ approval claim present at the request surface.
11
+
12
+ If you also run the opt-in live-model validation with
13
+ `RUN_EXPENSE_APPROVAL_LIVE_MODEL=1`, this variant demonstrates that the same
14
+ boundary still matters when a real model says the expense is approved.
15
+
16
+ ## What the user sees
17
+
18
+ The app exposes two mutation paths for the same expense request:
19
+
20
+ - baseline path: a naive host trusts the model approval claim and executes the
21
+ protected mutation
22
+ - compiler-mediated path: the host sees the same kind of model approval claim,
23
+ but only executes when authoritative Context Compiler state permits
24
+ `expense_approval`
25
+
26
+ The request also carries a visible `agent_claim` field to represent
27
+ caller-supplied or model-supplied approval text.
28
+
29
+ The observable proof is a host-owned append-only JSONL file:
30
+
31
+ - baseline writes one record when the model returns an approval claim
32
+ - compiler-mediated returns `403` and writes no record when state does not
33
+ authorize execution
34
+ - compiler-mediated writes one record only when authoritative state includes:
35
+
36
+ ```text
37
+ use expense_approval
38
+ ```
39
+
40
+ If a request introduces a contradiction such as `prohibit expense_approval`
41
+ against an already authorized state, Context Compiler returns a clarify flow.
42
+ The host returns a conflict response and writes no record.
43
+
44
+ ## Same request, different state
45
+
46
+ The compiler-mediated proof uses the same endpoint, the same model approval
47
+ claim, and the same expense action. Only authoritative Context Compiler state
48
+ changes.
49
+
50
+ | Endpoint | Model claim | Authoritative state | Compiler input | Outcome |
51
+ | --- | --- | --- | --- | --- |
52
+ | `/compiler/expenses` | approved | absent | none | `403`, no side effect |
53
+ | `/compiler/expenses` | approved | `use expense_approval` | none | `200`, one side effect |
54
+ | `/compiler/expenses` | approved | `use expense_approval` | `prohibit expense_approval` | `409`, clarify, no new side effect |
55
+
56
+ ## Enforcement boundary
57
+
58
+ The model claim is visible in both paths.
59
+
60
+ Caller-supplied approval text is also visible in both paths.
61
+
62
+ The baseline host treats that claim as authority.
63
+
64
+ The compiler-mediated host does not treat the visible approval text as
65
+ authorization.
66
+
67
+ Context Compiler state is the only authorization source for the protected
68
+ mutation after an approval claim is present in the compiler-mediated path.
69
+
70
+ ## Validation
71
+
72
+ Focused provider-free tests:
73
+
74
+ ```bash
75
+ uv run --no-sync pytest python/tests/test_fastapi_expense_approval_example.py
76
+ ```
77
+
78
+ Optional live-model validation:
79
+
80
+ ```bash
81
+ export RUN_EXPENSE_APPROVAL_LIVE_MODEL=1
82
+ export OPENAI_API_KEY=...
83
+ export MODEL=openai/gpt-4o-mini
84
+ uv run --no-sync pytest python/tests/test_fastapi_expense_approval_live_model.py
85
+ ```
86
+
87
+ Unless you run that env-var-gated command, this repo has only validated the
88
+ provider-free runtime-boundary path, not the live-provider path.
89
+
90
+ The live-model path uses the shared provider contract documented in
91
+ [PROVIDER_CONTRACT.md](../../../../../PROVIDER_CONTRACT.md).
92
+
93
+ ## Run locally
94
+
95
+ ```bash
96
+ uv run fastapi dev python/examples/execution_authorization/expense_approval/fastapi/app.py
97
+ ```
@@ -0,0 +1 @@
1
+ """FastAPI execution-authorization comparison for expense approval."""