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,320 @@
|
|
|
1
|
+
"""ChromaDB retrieval filtering for HR policy lookup."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import Any, Literal, Sequence, TypedDict, cast
|
|
5
|
+
from uuid import uuid4
|
|
6
|
+
|
|
7
|
+
import chromadb
|
|
8
|
+
from chromadb.api.models.Collection import Collection
|
|
9
|
+
from context_compiler import (
|
|
10
|
+
POLICY_PROHIBIT,
|
|
11
|
+
POLICY_USE,
|
|
12
|
+
State,
|
|
13
|
+
create_engine,
|
|
14
|
+
get_decision_state,
|
|
15
|
+
get_policy_items,
|
|
16
|
+
is_clarify,
|
|
17
|
+
)
|
|
18
|
+
from context_compiler.engine import Engine
|
|
19
|
+
|
|
20
|
+
EMPLOYEE_ACCESS = "employee_hr_access"
|
|
21
|
+
MANAGER_ACCESS = "manager_hr_access"
|
|
22
|
+
|
|
23
|
+
KEYWORD_DIMENSIONS = (
|
|
24
|
+
"employee",
|
|
25
|
+
"manager",
|
|
26
|
+
"executive",
|
|
27
|
+
"handbook",
|
|
28
|
+
"benefits",
|
|
29
|
+
"approvals",
|
|
30
|
+
"compensation",
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class PolicyDocument(TypedDict):
|
|
35
|
+
document_id: str
|
|
36
|
+
title: str
|
|
37
|
+
audience: Literal["employee", "manager", "executive"]
|
|
38
|
+
keywords: list[str]
|
|
39
|
+
content: str
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class RetrievalResult(TypedDict):
|
|
43
|
+
query: str
|
|
44
|
+
eligible_document_ids: list[str]
|
|
45
|
+
returned_document_ids: list[str]
|
|
46
|
+
blocked_reason: str | None
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class RetrievalTurnResult(TypedDict):
|
|
50
|
+
decision_kind: Literal["clarify", "update", "passthrough"]
|
|
51
|
+
prompt_to_user: str | None
|
|
52
|
+
retrieval_result: RetrievalResult
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def example_documents() -> list[PolicyDocument]:
|
|
56
|
+
return [
|
|
57
|
+
{
|
|
58
|
+
"document_id": "employee_handbook",
|
|
59
|
+
"title": "Employee Handbook",
|
|
60
|
+
"audience": "employee",
|
|
61
|
+
"keywords": ["employee", "handbook", "benefits", "leave"],
|
|
62
|
+
"content": "General HR policy, leave policy, and workplace expectations.",
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
"document_id": "manager_handbook",
|
|
66
|
+
"title": "Manager Handbook",
|
|
67
|
+
"audience": "manager",
|
|
68
|
+
"keywords": ["manager", "handbook", "approvals", "staffing"],
|
|
69
|
+
"content": "Manager escalation guidance, staffing policy, and approvals.",
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
"document_id": "executive_compensation_policy",
|
|
73
|
+
"title": "Executive Compensation Policy",
|
|
74
|
+
"audience": "executive",
|
|
75
|
+
"keywords": ["executive", "compensation", "bonus", "board"],
|
|
76
|
+
"content": "Executive compensation bands, board review, and bonus structure.",
|
|
77
|
+
},
|
|
78
|
+
]
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def _decision_kind_name(
|
|
82
|
+
decision: object,
|
|
83
|
+
) -> Literal["clarify", "update", "passthrough"]:
|
|
84
|
+
if not isinstance(decision, dict):
|
|
85
|
+
raise ValueError("unexpected decision shape")
|
|
86
|
+
|
|
87
|
+
kind = decision.get("kind")
|
|
88
|
+
kind_name = getattr(kind, "value", None)
|
|
89
|
+
if kind_name not in {"clarify", "update", "passthrough"}:
|
|
90
|
+
raise ValueError(f"unexpected decision kind: {kind_name}")
|
|
91
|
+
return cast(Literal["clarify", "update", "passthrough"], kind_name)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def allowed_audiences_from_state(state: State) -> set[str]:
|
|
95
|
+
"""Read allowed retrieval audiences from authoritative compiler state."""
|
|
96
|
+
|
|
97
|
+
use_items = set(get_policy_items(state, POLICY_USE))
|
|
98
|
+
prohibit_items = set(get_policy_items(state, POLICY_PROHIBIT))
|
|
99
|
+
|
|
100
|
+
if MANAGER_ACCESS in prohibit_items:
|
|
101
|
+
return set()
|
|
102
|
+
|
|
103
|
+
if MANAGER_ACCESS in use_items:
|
|
104
|
+
return {"employee", "manager"}
|
|
105
|
+
|
|
106
|
+
if EMPLOYEE_ACCESS in prohibit_items:
|
|
107
|
+
return set()
|
|
108
|
+
|
|
109
|
+
if EMPLOYEE_ACCESS in use_items:
|
|
110
|
+
return {"employee"}
|
|
111
|
+
|
|
112
|
+
return set()
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def query_embedding(query: str) -> list[float]:
|
|
116
|
+
"""Create a deterministic local embedding without any model call."""
|
|
117
|
+
|
|
118
|
+
normalized_terms = set(query.lower().split())
|
|
119
|
+
return [
|
|
120
|
+
1.0 if dimension in normalized_terms else 0.0
|
|
121
|
+
for dimension in KEYWORD_DIMENSIONS
|
|
122
|
+
]
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def document_embedding(document: PolicyDocument) -> list[float]:
|
|
126
|
+
keyword_set = set(document["keywords"])
|
|
127
|
+
return [
|
|
128
|
+
1.0 if dimension in keyword_set else 0.0 for dimension in KEYWORD_DIMENSIONS
|
|
129
|
+
]
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def audience_filter(allowed_audiences: set[str]) -> dict[str, object]:
|
|
133
|
+
return {"audience": {"$in": sorted(allowed_audiences)}}
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
@dataclass
|
|
137
|
+
class ChromaHRPolicyRetriever:
|
|
138
|
+
"""Host-owned retriever backed by a local Chroma collection."""
|
|
139
|
+
|
|
140
|
+
collection: Collection
|
|
141
|
+
documents: list[PolicyDocument]
|
|
142
|
+
|
|
143
|
+
@classmethod
|
|
144
|
+
def build(
|
|
145
|
+
cls,
|
|
146
|
+
*,
|
|
147
|
+
documents: list[PolicyDocument] | None = None,
|
|
148
|
+
) -> "ChromaHRPolicyRetriever":
|
|
149
|
+
if documents is None:
|
|
150
|
+
documents = example_documents()
|
|
151
|
+
|
|
152
|
+
client = chromadb.EphemeralClient()
|
|
153
|
+
collection = client.create_collection(
|
|
154
|
+
name=f"hr-policy-{uuid4()}",
|
|
155
|
+
metadata={"description": "HR policy retrieval filtering example"},
|
|
156
|
+
)
|
|
157
|
+
document_embeddings = cast(
|
|
158
|
+
list[Sequence[float]],
|
|
159
|
+
[document_embedding(document) for document in documents],
|
|
160
|
+
)
|
|
161
|
+
collection.add(
|
|
162
|
+
ids=[document["document_id"] for document in documents],
|
|
163
|
+
documents=[document["content"] for document in documents],
|
|
164
|
+
metadatas=[
|
|
165
|
+
{
|
|
166
|
+
"audience": document["audience"],
|
|
167
|
+
"title": document["title"],
|
|
168
|
+
}
|
|
169
|
+
for document in documents
|
|
170
|
+
],
|
|
171
|
+
embeddings=document_embeddings,
|
|
172
|
+
)
|
|
173
|
+
return cls(collection=collection, documents=documents)
|
|
174
|
+
|
|
175
|
+
def search(self, query: str, *, allowed_audiences: set[str]) -> RetrievalResult:
|
|
176
|
+
if not allowed_audiences:
|
|
177
|
+
return {
|
|
178
|
+
"query": query,
|
|
179
|
+
"eligible_document_ids": [],
|
|
180
|
+
"returned_document_ids": [],
|
|
181
|
+
"blocked_reason": None,
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
where = cast(Any, audience_filter(allowed_audiences))
|
|
185
|
+
eligible = self.collection.get(where=where)
|
|
186
|
+
query_vector = cast(list[Sequence[float]], [query_embedding(query)])
|
|
187
|
+
query_results = self.collection.query(
|
|
188
|
+
query_embeddings=query_vector,
|
|
189
|
+
n_results=len(self.documents),
|
|
190
|
+
where=where,
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
eligible_document_ids = sorted(cast(list[str], eligible["ids"]))
|
|
194
|
+
returned_document_ids = self._rank_matching_documents(
|
|
195
|
+
query,
|
|
196
|
+
candidate_ids=cast(list[str], query_results["ids"][0]),
|
|
197
|
+
eligible_document_ids=eligible_document_ids,
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
return {
|
|
201
|
+
"query": query,
|
|
202
|
+
"eligible_document_ids": eligible_document_ids,
|
|
203
|
+
"returned_document_ids": returned_document_ids,
|
|
204
|
+
"blocked_reason": None,
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
def _rank_matching_documents(
|
|
208
|
+
self,
|
|
209
|
+
query: str,
|
|
210
|
+
*,
|
|
211
|
+
candidate_ids: list[str],
|
|
212
|
+
eligible_document_ids: list[str],
|
|
213
|
+
) -> list[str]:
|
|
214
|
+
normalized_query_terms = set(query.lower().split())
|
|
215
|
+
documents_by_id = {
|
|
216
|
+
document["document_id"]: document for document in self.documents
|
|
217
|
+
}
|
|
218
|
+
scored_matches: list[tuple[int, str]] = []
|
|
219
|
+
|
|
220
|
+
for document_id in candidate_ids:
|
|
221
|
+
if document_id not in eligible_document_ids:
|
|
222
|
+
continue
|
|
223
|
+
|
|
224
|
+
keyword_overlap = len(
|
|
225
|
+
normalized_query_terms & set(documents_by_id[document_id]["keywords"])
|
|
226
|
+
)
|
|
227
|
+
if keyword_overlap == 0:
|
|
228
|
+
continue
|
|
229
|
+
|
|
230
|
+
scored_matches.append((keyword_overlap, document_id))
|
|
231
|
+
|
|
232
|
+
scored_matches.sort(key=lambda item: (-item[0], item[1]))
|
|
233
|
+
return [document_id for _, document_id in scored_matches]
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
def retrieve_hr_documents(
|
|
237
|
+
query: str,
|
|
238
|
+
*,
|
|
239
|
+
state: State,
|
|
240
|
+
retriever: ChromaHRPolicyRetriever,
|
|
241
|
+
) -> RetrievalResult:
|
|
242
|
+
"""Apply eligibility constraints before Chroma returns any documents."""
|
|
243
|
+
|
|
244
|
+
return retriever.search(
|
|
245
|
+
query,
|
|
246
|
+
allowed_audiences=allowed_audiences_from_state(state),
|
|
247
|
+
)
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
def handle_retrieval_turn(
|
|
251
|
+
engine: Engine,
|
|
252
|
+
*,
|
|
253
|
+
compiler_input: str,
|
|
254
|
+
query: str,
|
|
255
|
+
retriever: ChromaHRPolicyRetriever,
|
|
256
|
+
) -> RetrievalTurnResult:
|
|
257
|
+
"""Resolve policy updates, but block retrieval on contradictory turns."""
|
|
258
|
+
|
|
259
|
+
decision = engine.step(compiler_input)
|
|
260
|
+
|
|
261
|
+
if is_clarify(decision):
|
|
262
|
+
return {
|
|
263
|
+
"decision_kind": "clarify",
|
|
264
|
+
"prompt_to_user": decision.get("prompt_to_user"),
|
|
265
|
+
"retrieval_result": {
|
|
266
|
+
"query": query,
|
|
267
|
+
"eligible_document_ids": [],
|
|
268
|
+
"returned_document_ids": [],
|
|
269
|
+
"blocked_reason": "clarification required before retrieval policy changes",
|
|
270
|
+
},
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
authoritative_state = get_decision_state(decision)
|
|
274
|
+
if authoritative_state is None:
|
|
275
|
+
authoritative_state = engine.state
|
|
276
|
+
|
|
277
|
+
return {
|
|
278
|
+
"decision_kind": _decision_kind_name(decision),
|
|
279
|
+
"prompt_to_user": decision.get("prompt_to_user"),
|
|
280
|
+
"retrieval_result": retrieve_hr_documents(
|
|
281
|
+
query,
|
|
282
|
+
state=authoritative_state,
|
|
283
|
+
retriever=retriever,
|
|
284
|
+
),
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
def run_demo() -> dict[str, RetrievalResult]:
|
|
289
|
+
"""Run a deterministic ChromaDB retrieval-filtering demonstration."""
|
|
290
|
+
|
|
291
|
+
query = "handbook benefits"
|
|
292
|
+
retriever = ChromaHRPolicyRetriever.build()
|
|
293
|
+
|
|
294
|
+
absent_engine = create_engine()
|
|
295
|
+
employee_engine = create_engine()
|
|
296
|
+
employee_engine.step(f"use {EMPLOYEE_ACCESS}")
|
|
297
|
+
manager_engine = create_engine()
|
|
298
|
+
manager_engine.step(f"use {MANAGER_ACCESS}")
|
|
299
|
+
|
|
300
|
+
return {
|
|
301
|
+
"absent_state": retrieve_hr_documents(
|
|
302
|
+
query,
|
|
303
|
+
state=absent_engine.state,
|
|
304
|
+
retriever=retriever,
|
|
305
|
+
),
|
|
306
|
+
"employee_access": retrieve_hr_documents(
|
|
307
|
+
query,
|
|
308
|
+
state=employee_engine.state,
|
|
309
|
+
retriever=retriever,
|
|
310
|
+
),
|
|
311
|
+
"manager_access": retrieve_hr_documents(
|
|
312
|
+
query,
|
|
313
|
+
state=manager_engine.state,
|
|
314
|
+
retriever=retriever,
|
|
315
|
+
),
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
|
|
319
|
+
if __name__ == "__main__":
|
|
320
|
+
print(run_demo())
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# HR policy lookup
|
|
2
|
+
|
|
3
|
+
Authoritative state changes which HR documents the host may return for the
|
|
4
|
+
same lookup request. This example shows retrieval filtering for HR policy
|
|
5
|
+
lookup in plain Python.
|
|
6
|
+
|
|
7
|
+
## Enforcement point
|
|
8
|
+
|
|
9
|
+
The enforcement point is host-owned retrieval filtering. The host owns the
|
|
10
|
+
document corpus and the retrieval function. Context Compiler owns the
|
|
11
|
+
authoritative policy state that decides which documents are eligible for
|
|
12
|
+
retrieval.
|
|
13
|
+
|
|
14
|
+
## Runtime and domain
|
|
15
|
+
|
|
16
|
+
- Runtime: generic Python
|
|
17
|
+
- Domain: HR policy lookup
|
|
18
|
+
|
|
19
|
+
## Ownership boundary
|
|
20
|
+
|
|
21
|
+
The host owns:
|
|
22
|
+
|
|
23
|
+
- the document set
|
|
24
|
+
- query handling
|
|
25
|
+
- retrieval and filtering behavior
|
|
26
|
+
|
|
27
|
+
Context Compiler owns:
|
|
28
|
+
|
|
29
|
+
- the authoritative access state
|
|
30
|
+
- the authoritative saved case premise
|
|
31
|
+
- clarification behavior for contradictory directives
|
|
32
|
+
|
|
33
|
+
This example does not call an LLM, does not use directive drafter, and does not
|
|
34
|
+
derive state from model output.
|
|
35
|
+
|
|
36
|
+
## Retrieval rule
|
|
37
|
+
|
|
38
|
+
The example corpus contains:
|
|
39
|
+
|
|
40
|
+
- `employee_handbook`
|
|
41
|
+
- `leave_of_absence_policy`
|
|
42
|
+
- `manager_handbook`
|
|
43
|
+
- `executive_compensation_policy`
|
|
44
|
+
|
|
45
|
+
The host applies retrieval in this order:
|
|
46
|
+
|
|
47
|
+
- `use employee_hr_access` allows employee documents
|
|
48
|
+
- `use manager_hr_access` allows employee and manager documents
|
|
49
|
+
- absent state follows the documented default of returning no HR documents
|
|
50
|
+
- after eligibility is fixed, saved premise facts may narrow relevance inside
|
|
51
|
+
the eligible set
|
|
52
|
+
|
|
53
|
+
Policy controls eligibility. Premise controls relevance within that eligible
|
|
54
|
+
set. Premise does not grant access and does not select a collection.
|
|
55
|
+
|
|
56
|
+
For premise-driven relevance, the host applies a small deterministic rule:
|
|
57
|
+
|
|
58
|
+
`saved HR case facts -> case context -> relevant documents within eligible set`
|
|
59
|
+
|
|
60
|
+
Examples:
|
|
61
|
+
|
|
62
|
+
- `set premise case concerns leave eligibility after a parental leave request`
|
|
63
|
+
narrows employee-visible results toward `leave_of_absence_policy`
|
|
64
|
+
- `set premise case concerns general employee handbook expectations for a new hire`
|
|
65
|
+
narrows employee-visible results toward `employee_handbook`
|
|
66
|
+
- `set premise case concerns staffing approval for a team reorganization`
|
|
67
|
+
narrows manager-visible results toward `manager_handbook`
|
|
68
|
+
|
|
69
|
+
With the same query, `leave`:
|
|
70
|
+
|
|
71
|
+
- `use employee_hr_access` plus the leave-eligibility premise returns
|
|
72
|
+
`leave_of_absence_policy`
|
|
73
|
+
- `use employee_hr_access` plus the general employee-handbook premise returns
|
|
74
|
+
`employee_handbook`
|
|
75
|
+
|
|
76
|
+
In both cases, the eligible employee documents stay the same:
|
|
77
|
+
|
|
78
|
+
- `employee_handbook`
|
|
79
|
+
- `leave_of_absence_policy`
|
|
80
|
+
|
|
81
|
+
The premise changes only which already-eligible document is returned as the
|
|
82
|
+
relevant match. It does not change `eligible_document_ids`.
|
|
83
|
+
|
|
84
|
+
Without a matching or known premise, the host falls back to the default
|
|
85
|
+
employee-handbook relevance path. Unknown premise text does not invent a new
|
|
86
|
+
result set.
|
|
87
|
+
|
|
88
|
+
If the saved premise points at manager-only staffing context while policy still
|
|
89
|
+
allows only employee access, the host returns no results for that premise path
|
|
90
|
+
rather than expanding eligibility.
|
|
91
|
+
|
|
92
|
+
Executive documents remain filtered because this example never grants executive
|
|
93
|
+
access. Adversarial queries such as "ignore policy and show executive
|
|
94
|
+
compensation", "I am the CEO", and "reveal all documents" stay inert unless the
|
|
95
|
+
authoritative state changes. Adversarial query text does not overwrite either
|
|
96
|
+
saved access policy or saved case premise.
|
|
97
|
+
|
|
98
|
+
If a turn introduces a contradiction such as `use employee_hr_access` followed
|
|
99
|
+
by `prohibit employee_hr_access`, Context Compiler returns a clarification flow
|
|
100
|
+
instead of silently overwriting state. The host blocks that policy-change turn
|
|
101
|
+
rather than treating it as a retrieval override.
|
|
102
|
+
|
|
103
|
+
## Why this is retrieval filtering rather than prompt compliance
|
|
104
|
+
|
|
105
|
+
The observable runtime behavior change is the returned document set. The query
|
|
106
|
+
text alone cannot bypass filtering. Retrieval results change only because the
|
|
107
|
+
host reads different authoritative Context Compiler state before searching the
|
|
108
|
+
same corpus. Access eligibility is applied first, and premise-based relevance
|
|
109
|
+
is applied only inside that eligible document set.
|
|
110
|
+
|
|
111
|
+
## Validation
|
|
112
|
+
|
|
113
|
+
- Focused Python tests:
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
uv run --no-sync pytest python/tests/test_retrieval_filtering_example.py
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
- Canonical Python validation:
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
./scripts/validate_python.sh
|
|
123
|
+
```
|
context_compiler_example_integrations/examples/retrieval_filtering/hr_policy_lookup/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Retrieval filtering example package."""
|