context-engineering-core 0.12.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 (84) hide show
  1. context_engine/__init__.py +15 -0
  2. context_engine/__main__.py +3 -0
  3. context_engine/_sqlite.py +19 -0
  4. context_engine/_windows_security.py +125 -0
  5. context_engine/_windows_storage.py +110 -0
  6. context_engine/adapters.py +148 -0
  7. context_engine/answers.py +90 -0
  8. context_engine/budget.py +93 -0
  9. context_engine/cli.py +222 -0
  10. context_engine/config.py +193 -0
  11. context_engine/context.py +116 -0
  12. context_engine/demo.py +98 -0
  13. context_engine/errors.py +91 -0
  14. context_engine/evaluation/__init__.py +1 -0
  15. context_engine/evaluation/commands.py +90 -0
  16. context_engine/evaluation/corpus.py +247 -0
  17. context_engine/evaluation/data/freeze.json +26 -0
  18. context_engine/evaluation/data/ground_truth.json +287 -0
  19. context_engine/evaluation/data/pin_retention.json +8 -0
  20. context_engine/evaluation/data/protocol.json +122 -0
  21. context_engine/evaluation/data/scenario.json +1226 -0
  22. context_engine/evaluation/data/summary_fixture.json +7 -0
  23. context_engine/evaluation/execution.py +538 -0
  24. context_engine/evaluation/fixtures.py +32 -0
  25. context_engine/evaluation/grading.py +62 -0
  26. context_engine/evaluation/harness.py +165 -0
  27. context_engine/evaluation/heldout/__init__.py +260 -0
  28. context_engine/evaluation/heldout/__main__.py +40 -0
  29. context_engine/evaluation/heldout/data/ground_truth.json +18 -0
  30. context_engine/evaluation/heldout/data/manifest.json +9 -0
  31. context_engine/evaluation/heldout/data/protocol.json +14 -0
  32. context_engine/evaluation/heldout/data/scenarios.json +18 -0
  33. context_engine/evaluation/heldout/data/scoring_manifest.json +4 -0
  34. context_engine/evaluation/heldout/data/scoring_protocol.json +12 -0
  35. context_engine/evaluation/heldout/scoring.py +176 -0
  36. context_engine/evaluation/protocol.py +264 -0
  37. context_engine/evaluation/reporting.py +294 -0
  38. context_engine/evaluation/results.py +331 -0
  39. context_engine/evaluation/run_commands.py +146 -0
  40. context_engine/evaluation/strategies.py +261 -0
  41. context_engine/inspection.py +266 -0
  42. context_engine/layers/__init__.py +18 -0
  43. context_engine/layers/cap.py +99 -0
  44. context_engine/layers/common.py +162 -0
  45. context_engine/layers/pin.py +68 -0
  46. context_engine/layers/retrieve.py +233 -0
  47. context_engine/layers/summarize.py +202 -0
  48. context_engine/layers/window.py +29 -0
  49. context_engine/mcp_server.py +267 -0
  50. context_engine/memory/__init__.py +5 -0
  51. context_engine/memory/codec.py +91 -0
  52. context_engine/memory/demo.py +90 -0
  53. context_engine/memory/store.py +770 -0
  54. context_engine/models.py +384 -0
  55. context_engine/pipeline.py +383 -0
  56. context_engine/providers/__init__.py +1 -0
  57. context_engine/providers/client.py +301 -0
  58. context_engine/providers/commands.py +138 -0
  59. context_engine/providers/contracts.py +324 -0
  60. context_engine/providers/credentials.py +66 -0
  61. context_engine/providers/memory.py +112 -0
  62. context_engine/providers/store.py +408 -0
  63. context_engine/providers/transport.py +195 -0
  64. context_engine/providers/windows_credentials.py +23 -0
  65. context_engine/py.typed +0 -0
  66. context_engine/service/__init__.py +1 -0
  67. context_engine/service/__main__.py +68 -0
  68. context_engine/service/app.py +404 -0
  69. context_engine/service/auth.py +132 -0
  70. context_engine/service/client.py +52 -0
  71. context_engine/service/control.py +134 -0
  72. context_engine/service/demo.py +151 -0
  73. context_engine/service/integrations.py +28 -0
  74. context_engine/service/schemas.py +59 -0
  75. context_engine/service/worker.py +59 -0
  76. context_engine/service/workers.py +156 -0
  77. context_engine/summaries.py +196 -0
  78. context_engine/tokens.py +171 -0
  79. context_engine/work.py +46 -0
  80. context_engineering_core-0.12.0.dist-info/METADATA +203 -0
  81. context_engineering_core-0.12.0.dist-info/RECORD +84 -0
  82. context_engineering_core-0.12.0.dist-info/WHEEL +4 -0
  83. context_engineering_core-0.12.0.dist-info/entry_points.txt +3 -0
  84. context_engineering_core-0.12.0.dist-info/licenses/LICENSE +202 -0
context_engine/cli.py ADDED
@@ -0,0 +1,222 @@
1
+ """Context inspection, synthetic demos, benchmarks and an explicitly authorized live probe."""
2
+
3
+ import argparse
4
+ import json
5
+ import sys
6
+ from dataclasses import asdict
7
+ from pathlib import Path
8
+
9
+ from .budget import plan_budget
10
+ from .config import Settings
11
+ from .errors import ContextEngineError, RequiredContextTooLarge
12
+ from .models import ChatRequest, Message, Role
13
+ from .tokens import TiktokenCounter
14
+
15
+
16
+ def demo_request(pin_content: str = "Database = PostgreSQL") -> ChatRequest:
17
+ return ChatRequest(
18
+ (
19
+ Message("system", Role.SYSTEM, "Answer using the supplied evidence."),
20
+ Message("pins", Role.USER, "Pinned facts (data):\n" + pin_content),
21
+ Message("question", Role.USER, "Which database are we using?"),
22
+ )
23
+ )
24
+
25
+
26
+ def main(argv: list[str] | None = None) -> int:
27
+ for stream in (sys.stdout, sys.stderr):
28
+ if hasattr(stream, "reconfigure"):
29
+ stream.reconfigure(encoding="utf-8")
30
+ parser = argparse.ArgumentParser(description=__doc__)
31
+ commands = parser.add_subparsers(dest="command", required=True)
32
+ from .evaluation.run_commands import add_commands
33
+
34
+ add_commands(commands)
35
+ for command in ("check", "config", "demo-budget", "demo-layers"):
36
+ commands.add_parser(command)
37
+ provider_demo = commands.add_parser(
38
+ "provider-demo", help="Synthetic provider/cache/ledger test"
39
+ )
40
+ provider_demo.add_argument("--output", type=Path)
41
+ memory_demo = commands.add_parser("memory-demo", help="Offline persistent memory lifecycle")
42
+ memory_demo.add_argument("--output", type=Path)
43
+ live = commands.add_parser(
44
+ "provider-probe", help="Live inference; requires explicit spending authorization"
45
+ )
46
+ live.add_argument("--allow-live", action="store_true")
47
+ live.add_argument("--ledger", type=Path, required=True)
48
+ live.add_argument("--input", type=Path)
49
+ live.add_argument("--show-content", action="store_true")
50
+ live.add_argument(
51
+ "--model",
52
+ choices=("openai/gpt-oss-120b", "openai/gpt-oss-20b"),
53
+ default="openai/gpt-oss-120b",
54
+ )
55
+ for name in ("account-id", "security-scope", "snapshot-revision", "price-version"):
56
+ live.add_argument("--" + name, required=True)
57
+ for name in (
58
+ "daily-budget-microusd",
59
+ "input-rate-microusd",
60
+ "cached-input-rate-microusd",
61
+ "output-rate-microusd",
62
+ "rpm",
63
+ "tpm",
64
+ "rpd",
65
+ "tpd",
66
+ ):
67
+ live.add_argument("--" + name, type=int, required=True)
68
+ benchmark = commands.add_parser(
69
+ "benchmark-check", help="Validate the frozen synthetic benchmark offline"
70
+ )
71
+ benchmark.add_argument("--fact", default="shard")
72
+ benchmark.add_argument("--budget", type=int, default=900)
73
+ benchmark.add_argument("--model")
74
+ benchmark.add_argument("--show-content", action="store_true")
75
+ benchmark.add_argument("--data-dir", type=Path)
76
+ benchmark.add_argument("--output", type=Path)
77
+ strategies = commands.add_parser(
78
+ "strategy-eval", help="Compare context strategies on the frozen corpus; no inference"
79
+ )
80
+ strategies.add_argument(
81
+ "--budget", type=int, action="append", help="Input allowance; repeatable"
82
+ )
83
+ strategies.add_argument("--probes", action="store_true", help="Include per-fact results")
84
+ strategies.add_argument("--data-dir", type=Path)
85
+ strategies.add_argument("--output", type=Path, help="Save JSON to a new file; never overwrite")
86
+ planned = commands.add_parser(
87
+ "benchmark-plan", help="List frozen probe slots without inference"
88
+ )
89
+ planned.add_argument("--data-dir", type=Path)
90
+ planned.add_argument("--output", type=Path)
91
+ for command in ("inspect", "probe"):
92
+ command_parser = commands.add_parser(command, help="Inspect context locally; no inference")
93
+ command_parser.add_argument(
94
+ "--input", type=Path, help="Version-1 JSON input; omit for synthetic demo"
95
+ )
96
+ command_parser.add_argument("--budget", type=int, help="Override the input token allowance")
97
+ command_parser.add_argument(
98
+ "--show-content", action="store_true", help="Include assembled prompt bodies"
99
+ )
100
+ command_parser.add_argument(
101
+ "--output", type=Path, help="Save JSON to a new file; never overwrite"
102
+ )
103
+ args = parser.parse_args(argv)
104
+ try:
105
+ if args.command == "memory-demo":
106
+ from .inspection import save_inspection
107
+ from .memory.demo import memory_demo
108
+
109
+ result = memory_demo()
110
+ if args.output is not None:
111
+ save_inspection(args.output, result)
112
+ print(json.dumps(result, indent=2, ensure_ascii=False))
113
+ return 0
114
+ if args.command in ("benchmark-run", "model-swap", "benchmark-report"):
115
+ from .evaluation.run_commands import run_command
116
+
117
+ result = run_command(args)
118
+ print(json.dumps(result, indent=2, ensure_ascii=False))
119
+ return 1 if result["status"] == "INVALID" else 0
120
+ if args.command in ("provider-demo", "provider-probe"):
121
+ from .inspection import save_inspection
122
+ from .providers.commands import provider_demo, provider_probe
123
+
124
+ result = provider_demo() if args.command == "provider-demo" else provider_probe(args)
125
+ if args.command == "provider-demo" and args.output is not None:
126
+ save_inspection(args.output, result)
127
+ print(json.dumps(result, indent=2, ensure_ascii=False))
128
+ return 0 if result["status"] in ("PASS", "success", "replay") else 1
129
+ if args.command == "strategy-eval":
130
+ from .evaluation.corpus import check_fixture, load_bundle
131
+ from .evaluation.strategies import compare_strategies
132
+ from .inspection import save_inspection
133
+
134
+ bundle = load_bundle(args.data_dir)
135
+ check_fixture(bundle)
136
+ budgets = None if args.budget is None else tuple(args.budget)
137
+ if budgets is not None and any(b <= 0 for b in budgets):
138
+ raise ContextEngineError("Budgets must be positive integers")
139
+ result = compare_strategies(bundle, budgets, include_probes=args.probes)
140
+ if args.output is not None:
141
+ save_inspection(args.output, result)
142
+ print(json.dumps(result, indent=2, ensure_ascii=False))
143
+ return 0
144
+ if args.command in ("benchmark-check", "benchmark-plan"):
145
+ from .evaluation.commands import benchmark_check, benchmark_plan
146
+ from .inspection import save_inspection
147
+
148
+ if args.command == "benchmark-check":
149
+ result = benchmark_check(
150
+ fact=args.fact,
151
+ budget=args.budget,
152
+ model=args.model,
153
+ show_content=args.show_content,
154
+ data_dir=args.data_dir,
155
+ )
156
+ else:
157
+ result = benchmark_plan(data_dir=args.data_dir)
158
+ if args.output is not None:
159
+ save_inspection(args.output, result)
160
+ print(json.dumps(result, indent=2, ensure_ascii=False))
161
+ return 1 if result["status"] == "INVALID" else 0
162
+ settings = Settings.from_env()
163
+ if args.command == "config":
164
+ print(
165
+ json.dumps(
166
+ {
167
+ key: asdict(getattr(settings, key))
168
+ for key in ("budget", "tokenizer", "cap", "retrieval")
169
+ },
170
+ indent=2,
171
+ )
172
+ )
173
+ return 0
174
+ if args.command in ("inspect", "probe"):
175
+ from .inspection import demo_job, load_job, save_inspection
176
+
177
+ job = load_job(args.input, settings) if args.input is not None else demo_job(settings)
178
+ result = job.run(input_cap=args.budget).to_dict(include_content=args.show_content)
179
+ result.update(
180
+ mode="offline_probe" if args.command == "probe" else "offline_inspection",
181
+ synthetic_input=job.synthetic,
182
+ inference_calls=0,
183
+ )
184
+ if args.output is not None:
185
+ save_inspection(args.output, result)
186
+ print(json.dumps(result, indent=2, ensure_ascii=False))
187
+ return 0
188
+ counter = TiktokenCounter(settings.tokenizer)
189
+ if args.command == "check":
190
+ from rank_bm25 import BM25Plus
191
+
192
+ BM25Plus([["setup"]]).get_scores(["setup"])
193
+ counter.count_request(demo_request())
194
+ print("deps ok")
195
+ return 0
196
+ if args.command == "demo-layers":
197
+ from .demo import layer_demo
198
+
199
+ print(json.dumps(layer_demo(counter), indent=2, ensure_ascii=False))
200
+ return 0
201
+ plan = plan_budget(required_request=demo_request(), config=settings.budget, counter=counter)
202
+ print(json.dumps({"valid_request": plan.to_dict()}, indent=2))
203
+ # Synthetic, bounded fixture: enough tokens to exceed the allowance.
204
+ if settings.budget.input_allowance > 10000:
205
+ raise ContextEngineError("Demo accepts input allowances up to 10,000 tokens")
206
+ try:
207
+ plan_budget(
208
+ required_request=demo_request("oversized pin " * settings.budget.input_allowance),
209
+ config=settings.budget,
210
+ counter=counter,
211
+ )
212
+ except RequiredContextTooLarge as error:
213
+ print(json.dumps({"expected_failure": error.to_dict()}, indent=2))
214
+ return 0
215
+ raise ContextEngineError("Oversized demo fixture unexpectedly fit")
216
+ except ContextEngineError as error:
217
+ print(json.dumps(error.to_dict()), file=sys.stderr)
218
+ return 1
219
+
220
+
221
+ if __name__ == "__main__":
222
+ raise SystemExit(main())
@@ -0,0 +1,193 @@
1
+ """Validated scalar configuration; no models, tokenizer, provider or benchmark imports."""
2
+
3
+ import math
4
+ import os
5
+ from collections.abc import Mapping
6
+ from dataclasses import dataclass, field
7
+ from pathlib import Path
8
+
9
+ from .errors import ConfigurationError
10
+
11
+ CONFIG_DIRECTORY = Path(__file__).resolve().parent
12
+ MAX_INSPECTION_BYTES = 2_000_000
13
+ MAX_INSPECTION_TURNS = 10_000
14
+
15
+
16
+ def nonnegative_integer(name: str, value: int, *, minimum: int = 0) -> None:
17
+ if type(value) is not int or value < minimum:
18
+ raise ConfigurationError("Expected an integer within range", field=name, minimum=minimum)
19
+
20
+
21
+ @dataclass(frozen=True, slots=True)
22
+ class BudgetConfig:
23
+ input_cap: int = 3000
24
+ model_capacity: int = 131072
25
+ completion_reservation: int = 256
26
+ retrieval_reserve: int = 280
27
+ summary_reserve: int = 80
28
+ provider_input_cap: int | None = None
29
+
30
+ def __post_init__(self) -> None:
31
+ for name in ("input_cap", "model_capacity", "completion_reservation"):
32
+ nonnegative_integer(name, getattr(self, name), minimum=1)
33
+ for name in ("retrieval_reserve", "summary_reserve"):
34
+ nonnegative_integer(name, getattr(self, name))
35
+ if self.provider_input_cap is not None:
36
+ nonnegative_integer("provider_input_cap", self.provider_input_cap, minimum=1)
37
+ if self.completion_reservation >= self.model_capacity:
38
+ raise ConfigurationError("Completion reservation leaves no input capacity")
39
+ if self.retrieval_reserve + self.summary_reserve > self.input_allowance:
40
+ raise ConfigurationError("Layer reserves exceed the input allowance")
41
+
42
+ @property
43
+ def input_allowance(self) -> int:
44
+ ceilings = [self.input_cap, self.model_capacity - self.completion_reservation]
45
+ if self.provider_input_cap is not None:
46
+ ceilings.append(self.provider_input_cap)
47
+ return min(ceilings)
48
+
49
+
50
+ @dataclass(frozen=True, slots=True)
51
+ class TokenizerConfig:
52
+ encoding_name: str = "o200k_harmony"
53
+ calibration_factor: float = 1.07
54
+ adapter_overhead_tokens: int = 0
55
+
56
+ def __post_init__(self) -> None:
57
+ if not isinstance(self.encoding_name, str) or not self.encoding_name.strip():
58
+ raise ConfigurationError("Tokenizer name must be non-empty", field="encoding_name")
59
+ factor = self.calibration_factor
60
+ if (
61
+ type(factor) not in (int, float)
62
+ or factor < 1
63
+ or (isinstance(factor, float) and not math.isfinite(factor))
64
+ ):
65
+ raise ConfigurationError("Calibration factor must be finite and at least one")
66
+ nonnegative_integer("adapter_overhead_tokens", self.adapter_overhead_tokens)
67
+
68
+
69
+ @dataclass(frozen=True, slots=True)
70
+ class CapConfig:
71
+ max_tokens: int = 35
72
+ head_tokens: int = 22
73
+ tail_tokens: int = 8
74
+
75
+ def __post_init__(self) -> None:
76
+ for name in ("max_tokens", "head_tokens", "tail_tokens"):
77
+ nonnegative_integer(name, getattr(self, name), minimum=1)
78
+ if max(self.head_tokens, self.tail_tokens) > self.max_tokens:
79
+ raise ConfigurationError("CAP head/tail limits exceed the message cap")
80
+
81
+
82
+ @dataclass(frozen=True, slots=True)
83
+ class RetrievalConfig:
84
+ chunk_characters: int = 360
85
+ overlap_characters: int = 80
86
+ top_k: int = 4
87
+ minimum_score: float = 0.0
88
+ k1: float = 1.5
89
+ b: float = 0.75
90
+ recover_capped_window: bool = True
91
+
92
+ def __post_init__(self) -> None:
93
+ if type(self.recover_capped_window) is not bool:
94
+ raise ConfigurationError("WINDOW recovery must be an explicit boolean")
95
+ nonnegative_integer("chunk_characters", self.chunk_characters, minimum=1)
96
+ nonnegative_integer("overlap_characters", self.overlap_characters)
97
+ nonnegative_integer("top_k", self.top_k, minimum=1)
98
+ if self.overlap_characters >= self.chunk_characters:
99
+ raise ConfigurationError("Chunk overlap must be smaller than chunk size")
100
+ for name in ("minimum_score", "k1", "b"):
101
+ value = getattr(self, name)
102
+ try:
103
+ valid = type(value) in (int, float) and math.isfinite(value) and value >= 0
104
+ except OverflowError:
105
+ valid = False
106
+ if not valid:
107
+ raise ConfigurationError("Invalid retrieval parameter", field=name)
108
+ if self.k1 <= 0 or self.b > 1:
109
+ raise ConfigurationError("BM25 requires positive k1 and b between zero and one")
110
+
111
+
112
+ @dataclass(frozen=True, slots=True)
113
+ class Settings:
114
+ budget: BudgetConfig = field(default_factory=BudgetConfig)
115
+ tokenizer: TokenizerConfig = field(default_factory=TokenizerConfig)
116
+ output_dir: Path = CONFIG_DIRECTORY / "output"
117
+ cap: CapConfig = field(default_factory=CapConfig)
118
+ retrieval: RetrievalConfig = field(default_factory=RetrievalConfig)
119
+
120
+ def __post_init__(self) -> None:
121
+ if not isinstance(self.budget, BudgetConfig) or not isinstance(
122
+ self.tokenizer, TokenizerConfig
123
+ ):
124
+ raise ConfigurationError(
125
+ "Settings require validated budget and tokenizer configuration"
126
+ )
127
+ if not isinstance(self.cap, CapConfig) or not isinstance(self.retrieval, RetrievalConfig):
128
+ raise ConfigurationError("Settings require validated layer configuration")
129
+ try:
130
+ path = Path(self.output_dir).expanduser()
131
+ if not path.is_absolute():
132
+ path = CONFIG_DIRECTORY / path
133
+ object.__setattr__(self, "output_dir", path.resolve())
134
+ except (TypeError, ValueError, OSError, RuntimeError):
135
+ raise ConfigurationError("Invalid output directory", field="output_dir") from None
136
+
137
+ @classmethod
138
+ def from_env(cls, environ: Mapping[str, str] | None = None) -> "Settings":
139
+ env = os.environ if environ is None else environ
140
+
141
+ def integer(key: str, default: int) -> int:
142
+ try:
143
+ return int(env[key]) if key in env else default
144
+ except (ValueError, TypeError):
145
+ raise ConfigurationError(
146
+ "Environment setting must be an integer", field=key
147
+ ) from None
148
+
149
+ def number(key: str, default: float) -> float:
150
+ try:
151
+ return float(env[key]) if key in env else default
152
+ except (TypeError, ValueError, OverflowError):
153
+ raise ConfigurationError("Environment setting must be numeric", field=key) from None
154
+
155
+ try:
156
+ factor = float(env.get("TOKENIZER_FUDGE", "1.07"))
157
+ except (ValueError, TypeError):
158
+ raise ConfigurationError(
159
+ "Environment setting must be numeric", field="TOKENIZER_FUDGE"
160
+ ) from None
161
+ return cls(
162
+ budget=BudgetConfig(
163
+ input_cap=integer("CONTEXT_BUDGET_TOKENS", 3000),
164
+ model_capacity=integer("MODEL_CONTEXT_TOKENS", 131072),
165
+ completion_reservation=integer("MAX_COMPLETION_TOKENS", 256),
166
+ retrieval_reserve=integer("RETRIEVAL_RESERVE_TOKENS", 280),
167
+ summary_reserve=integer("SUMMARY_RESERVE_TOKENS", 80),
168
+ provider_input_cap=(
169
+ integer("PROVIDER_INPUT_CAP_TOKENS", 0)
170
+ if "PROVIDER_INPUT_CAP_TOKENS" in env
171
+ else None
172
+ ),
173
+ ),
174
+ tokenizer=TokenizerConfig(
175
+ encoding_name=env.get("TOKENIZER_NAME", "o200k_harmony"),
176
+ calibration_factor=factor,
177
+ adapter_overhead_tokens=integer("ADAPTER_OVERHEAD_TOKENS", 0),
178
+ ),
179
+ output_dir=Path(env.get("CONTEXT_OUTPUT_DIR", str(CONFIG_DIRECTORY / "output"))),
180
+ cap=CapConfig(
181
+ max_tokens=integer("CAP_MAX_TOKENS", 35),
182
+ head_tokens=integer("CAP_HEAD_TOKENS", 22),
183
+ tail_tokens=integer("CAP_TAIL_TOKENS", 8),
184
+ ),
185
+ retrieval=RetrievalConfig(
186
+ chunk_characters=integer("RETRIEVAL_CHUNK_CHARACTERS", 360),
187
+ overlap_characters=integer("RETRIEVAL_OVERLAP_CHARACTERS", 80),
188
+ top_k=integer("RETRIEVAL_TOP_K", 4),
189
+ minimum_score=number("RETRIEVAL_MINIMUM_SCORE", 0.0),
190
+ k1=number("BM25_K1", 1.5),
191
+ b=number("BM25_B", 0.75),
192
+ ),
193
+ )
@@ -0,0 +1,116 @@
1
+ """Typed, immutable carrier snapshots and composable layer contract."""
2
+
3
+ from dataclasses import dataclass
4
+ from typing import Protocol
5
+
6
+ from .budget import BudgetPlan
7
+ from .errors import ContractError
8
+ from .models import (
9
+ ChatRequest,
10
+ Chunk,
11
+ ContextBlock,
12
+ KeyedPins,
13
+ Message,
14
+ Role,
15
+ Scope,
16
+ Turn,
17
+ freeze_sequence,
18
+ integer_value,
19
+ text_value,
20
+ )
21
+ from .work import Cancellation, validate_cancellation
22
+
23
+
24
+ @dataclass(frozen=True, slots=True)
25
+ class LayerDiagnostic:
26
+ layer: str
27
+ reason_code: str
28
+ changed_turn_ids: tuple[str, ...] = ()
29
+ input_text_tokens: int = 0
30
+ output_text_tokens: int = 0
31
+
32
+ def __post_init__(self) -> None:
33
+ text_value("layer", self.layer)
34
+ text_value("reason_code", self.reason_code)
35
+ ids = freeze_sequence(self, "changed_turn_ids", str)
36
+ if len(set(ids)) != len(ids) or any(not value.strip() for value in ids):
37
+ raise ContractError("Diagnostic turn IDs must be unique and nonempty")
38
+ integer_value("input_text_tokens", self.input_text_tokens)
39
+ integer_value("output_text_tokens", self.output_text_tokens)
40
+
41
+
42
+ @dataclass(frozen=True, slots=True)
43
+ class ContextCarrier:
44
+ scope: Scope
45
+ original_turns: tuple[Turn, ...]
46
+ working_turns: tuple[Turn, ...]
47
+ pins: KeyedPins
48
+ question: Message
49
+ plan: BudgetPlan | None = None
50
+ blocks: tuple[ContextBlock, ...] = ()
51
+ diagnostics: tuple[LayerDiagnostic, ...] = ()
52
+ required_request: ChatRequest | None = None
53
+ prepared_fingerprint: str | None = None
54
+ window_planned: bool = False
55
+ retrieved_chunks: tuple[Chunk, ...] = ()
56
+ cancellation: Cancellation | None = None
57
+
58
+ def __post_init__(self) -> None:
59
+ if not isinstance(self.scope, Scope):
60
+ raise ContractError("Carrier requires a scope")
61
+ originals = freeze_sequence(self, "original_turns", Turn)
62
+ working = freeze_sequence(self, "working_turns", Turn)
63
+ blocks = freeze_sequence(self, "blocks", ContextBlock)
64
+ diagnostics = freeze_sequence(self, "diagnostics", LayerDiagnostic)
65
+ chunks = freeze_sequence(self, "retrieved_chunks", Chunk)
66
+ if any(chunk.source.scope != self.scope for chunk in chunks):
67
+ raise ContractError("Retrieved chunk scope mismatch")
68
+ if self.required_request is not None and not isinstance(self.required_request, ChatRequest):
69
+ raise ContractError("Carrier requires a validated mandatory request")
70
+ if self.prepared_fingerprint is not None:
71
+ text_value("prepared_fingerprint", self.prepared_fingerprint)
72
+ if type(self.window_planned) is not bool:
73
+ raise ContractError("window_planned must be boolean")
74
+ if any(turn.scope != self.scope for turn in (*originals, *working)):
75
+ raise ContractError("Carrier history scope mismatch")
76
+ if not isinstance(self.pins, KeyedPins) or self.pins.scope != self.scope:
77
+ raise ContractError("Carrier pin scope mismatch")
78
+ if not isinstance(self.question, Message) or self.question.role != Role.USER:
79
+ raise ContractError("Current question must be a user message")
80
+ if self.plan is not None and not isinstance(self.plan, BudgetPlan):
81
+ raise ContractError("Carrier requires a validated budget plan")
82
+ if len({block.kind for block in blocks}) != len(blocks):
83
+ raise ContractError("Carrier block kinds must be unique")
84
+ if any(source.scope != self.scope for block in blocks for source in block.sources):
85
+ raise ContractError("Carrier block source scope mismatch")
86
+ original_ids = [turn.turn_id for turn in originals]
87
+ working_ids = [turn.turn_id for turn in working]
88
+ if len(set(original_ids)) != len(original_ids):
89
+ raise ContractError("Original turn IDs must be unique")
90
+ if working_ids != original_ids:
91
+ raise ContractError("Working copies must preserve original turn order and IDs")
92
+ original_messages = [m.message_id for turn in originals for m in turn.messages]
93
+ if len(set(original_messages)) != len(original_messages):
94
+ raise ContractError("History message IDs must be unique")
95
+ if self.question.message_id in original_messages:
96
+ raise ContractError("Current question must not already occur in history")
97
+ for original, copy in zip(originals, working, strict=True):
98
+ if original.revision != copy.revision or original.timestamp != copy.timestamp:
99
+ raise ContractError("Working copies must preserve source revision and timestamp")
100
+ if [
101
+ (m.message_id, m.role, m.tool_call_id, m.tool_calls) for m in original.messages
102
+ ] != [(m.message_id, m.role, m.tool_call_id, m.tool_calls) for m in copy.messages]:
103
+ raise ContractError(
104
+ "Working copies must preserve message identity and tool metadata"
105
+ )
106
+ if self.plan is not None and not set(self.plan.window_turn_ids).issubset(original_ids):
107
+ raise ContractError("Planned window contains unknown turns")
108
+ if any(not set(item.changed_turn_ids).issubset(original_ids) for item in diagnostics):
109
+ raise ContractError("Layer diagnostic references unknown turns")
110
+ validate_cancellation(self.cancellation)
111
+
112
+
113
+ class Layer(Protocol):
114
+ """Implementations return a new snapshot and never mutate source history."""
115
+
116
+ def apply(self, context: ContextCarrier) -> ContextCarrier: ...
context_engine/demo.py ADDED
@@ -0,0 +1,98 @@
1
+ """Synthetic C02 layer walkthrough. No provider or answer generation."""
2
+
3
+ from datetime import UTC, datetime
4
+
5
+ from .budget import validate_request
6
+ from .config import BudgetConfig, CapConfig, RetrievalConfig
7
+ from .context import ContextCarrier
8
+ from .layers import CapLayer, PinLayer, RetrieveLayer, SummaryLayer, SummarySnapshot, WindowLayer
9
+ from .layers.common import render_request
10
+ from .layers.summarize import FrozenSummaryPolicy
11
+ from .models import BlockKind, KeyedPins, Message, Pin, Role, Scope, Turn
12
+ from .tokens import TokenCounter
13
+
14
+
15
+ def demo_context():
16
+ at = datetime(2026, 9, 7, tzinfo=UTC)
17
+ scope = Scope("demo", "incident")
18
+ old = Turn(
19
+ "t1",
20
+ scope,
21
+ (
22
+ Message(
23
+ "m1",
24
+ Role.TOOL,
25
+ "BEGIN "
26
+ + "routine telemetry. " * 60
27
+ + "The partition carrying the blame was shard-19. "
28
+ + "routine telemetry. " * 60
29
+ + " END",
30
+ tool_call_id="historical-call",
31
+ ),
32
+ ),
33
+ timestamp=at,
34
+ )
35
+ recent = tuple(
36
+ Turn(
37
+ f"t{i}",
38
+ scope,
39
+ (
40
+ Message(
41
+ f"m{i}", Role.USER, f"Recent update {i}: " + "routine checks continue. " * 40
42
+ ),
43
+ ),
44
+ timestamp=at,
45
+ )
46
+ for i in range(2, 13)
47
+ )
48
+ turns = (old,) + recent
49
+ pins = KeyedPins(
50
+ scope, (Pin(scope, "environment", "production", "application", effective_at=at),)
51
+ )
52
+ context = ContextCarrier(
53
+ scope,
54
+ turns,
55
+ turns,
56
+ pins,
57
+ Message("question", Role.USER, "Which partition carried the blame?"),
58
+ )
59
+ budget = BudgetConfig(input_cap=900, retrieval_reserve=280, summary_reserve=80)
60
+ return context, budget, at
61
+
62
+
63
+ def layer_demo(counter: TokenCounter) -> dict:
64
+ context, budget, at = demo_context()
65
+ turns = context.original_turns
66
+ old = turns[0]
67
+ scope = context.scope
68
+ capped = CapLayer(counter, CapConfig()).apply(context)
69
+ prepared = PinLayer(counter, budget, "Use the supplied evidence to answer.", at).apply(capped)
70
+ retrieved = RetrieveLayer(counter, RetrievalConfig()).apply(prepared)
71
+ windowed = WindowLayer(counter).apply(retrieved)
72
+ omitted = tuple(t for t in turns if t.turn_id not in windowed.plan.window_turn_ids)
73
+ snapshot = SummarySnapshot.from_history(
74
+ scope=scope,
75
+ content="Earlier discussion concerned an incident and routine telemetry.",
76
+ history=omitted,
77
+ policy_version="demo-v1",
78
+ created_at=at,
79
+ )
80
+ completed = SummaryLayer(counter, FrozenSummaryPolicy(snapshot), at).apply(windowed)
81
+ request = render_request(completed.blocks, completed.question, completed.required_request.tools)
82
+ estimate = validate_request(request=request, config=budget, counter=counter)
83
+ evidence = next(b for b in completed.blocks if b.kind == BlockKind.RETRIEVED)
84
+ return {
85
+ "inference_calls": 0,
86
+ "input_allowance": budget.input_allowance,
87
+ "original_message_tokens": counter.count_text(old.messages[0].content),
88
+ "capped_message_tokens": counter.count_text(capped.working_turns[0].messages[0].content),
89
+ "original_preserved": completed.original_turns == context.original_turns,
90
+ "capped_middle_fact_present": "shard-19" in capped.working_turns[0].messages[0].content,
91
+ "retrieved_middle_fact_present": "shard-19" in evidence.content,
92
+ "retrieved_turn_ids": sorted({c.source.turn_id for c in completed.retrieved_chunks}),
93
+ "window_turn_ids": list(completed.plan.window_turn_ids),
94
+ "summary_used": any(b.kind == BlockKind.SUMMARY and b.content for b in completed.blocks),
95
+ "estimated_request_tokens": estimate.estimated_tokens,
96
+ "layer_order": [d.layer for d in completed.diagnostics],
97
+ "retrieved_evidence": evidence.content,
98
+ }