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
@@ -0,0 +1,138 @@
1
+ """Explicit live probe and an entirely synthetic accounting demonstration."""
2
+
3
+ import asyncio
4
+ import os
5
+ from dataclasses import replace
6
+ from pathlib import Path
7
+ from tempfile import TemporaryDirectory
8
+
9
+ from ..config import BudgetConfig, Settings
10
+ from ..errors import ContractError
11
+ from ..inspection import demo_job, load_job
12
+ from ..models import ChatRequest, Message, Role, Scope
13
+ from ..tokens import TiktokenCounter
14
+ from .client import ProviderClient
15
+ from .contracts import Completion, GenerationConfig, PriceCard, QuotaPolicy, ReplayPolicy, Usage
16
+ from .store import RuntimeStore
17
+
18
+
19
+ class SyntheticTransport:
20
+ namespace = "c05-offline-demo-v1"
21
+
22
+ def __init__(self):
23
+ self.calls = 0
24
+
25
+ async def send(self, payload, api_key, timeout):
26
+ self.calls += 1
27
+ return Completion(
28
+ payload["model"],
29
+ f"synthetic-{self.calls}",
30
+ "synthetic-answer",
31
+ "stop",
32
+ Usage(40, 5, cached_input_tokens=4, reasoning_tokens=2),
33
+ )
34
+
35
+
36
+ async def _demo(directory: Path) -> dict:
37
+ store = RuntimeStore(directory / "runtime.sqlite")
38
+ quota = QuotaPolicy("synthetic-demo", 10000, rpd=2)
39
+ transport = SyntheticTransport()
40
+ client = ProviderClient(
41
+ store=store,
42
+ quota=quota,
43
+ prices=PriceCard("synthetic-v1", 1000000, 500000, 2000000),
44
+ transport=transport,
45
+ api_key="synthetic-not-a-credential",
46
+ replay=ReplayPolicy(enabled=True),
47
+ )
48
+ request = ChatRequest((Message("q", Role.USER, "Synthetic question one?"),))
49
+ options = dict(
50
+ scope=Scope("demo", "demo"), security_scope="synthetic-v1", snapshot_revision="synthetic-v1"
51
+ )
52
+ budget = BudgetConfig(input_cap=900)
53
+ first = await client.complete(request, budget, **options)
54
+ replay = await client.complete(request, budget, **options)
55
+ changed = ChatRequest((Message("q", Role.USER, "Synthetic question two?"),))
56
+ miss = await client.complete(changed, budget, **options)
57
+ client.generation = replace(client.generation, temperature=0.5)
58
+ blocked = await client.complete(changed, budget, **options)
59
+ results = dict(
60
+ first=first.to_dict(),
61
+ identical_replay=replay.to_dict(),
62
+ changed_question=miss.to_dict(),
63
+ changed_generation=blocked.to_dict(),
64
+ )
65
+ valid = (
66
+ first.status == miss.status == "success"
67
+ and replay.status == "replay"
68
+ and replay.new_cost_microusd == 0
69
+ and blocked.error_code == "quota_exhausted"
70
+ and blocked.request_key != miss.request_key
71
+ and transport.calls == 2
72
+ )
73
+ return dict(
74
+ mode="offline_provider_demo",
75
+ status="PASS" if valid else "FAIL",
76
+ real_inference_calls=0,
77
+ simulated_transport_calls=transport.calls,
78
+ pricing="synthetic; not provider pricing or billing evidence",
79
+ results=results,
80
+ ledger=store.snapshot(quota),
81
+ )
82
+
83
+
84
+ def provider_demo() -> dict:
85
+ with TemporaryDirectory(prefix="context-provider-demo-") as directory:
86
+ # Let the store create its private directory, not tempfile's Windows ACL.
87
+ return asyncio.run(_demo(Path(directory) / "storage"))
88
+
89
+
90
+ def provider_probe(args) -> dict:
91
+ # All authorization/config checks precede the first file mutation or network operation.
92
+ if not args.allow_live or args.daily_budget_microusd <= 0:
93
+ raise ContractError("Live probe requires --allow-live and a positive explicit spending cap")
94
+ api_key = os.environ.get("GROQ_API_KEY")
95
+ if not api_key or any(ord(c) < 33 or ord(c) > 126 for c in api_key):
96
+ raise ContractError("Live probe requires a valid GROQ_API_KEY environment variable")
97
+ quota = QuotaPolicy(
98
+ args.account_id,
99
+ args.daily_budget_microusd,
100
+ rpm=args.rpm,
101
+ tpm=args.tpm,
102
+ rpd=args.rpd,
103
+ tpd=args.tpd,
104
+ )
105
+ prices = PriceCard(
106
+ args.price_version,
107
+ args.input_rate_microusd,
108
+ args.cached_input_rate_microusd,
109
+ args.output_rate_microusd,
110
+ )
111
+ settings = Settings.from_env()
112
+ job = load_job(args.input, settings) if args.input is not None else demo_job(settings)
113
+ generation = GenerationConfig(
114
+ model=args.model, max_completion_tokens=job.arguments["budget"].completion_reservation
115
+ )
116
+ assembled = job.run()
117
+ client = ProviderClient(
118
+ store=RuntimeStore(args.ledger),
119
+ quota=quota,
120
+ prices=prices,
121
+ api_key=api_key,
122
+ generation=generation,
123
+ counter=TiktokenCounter(job.tokenizer),
124
+ )
125
+ result = asyncio.run(
126
+ client.complete(
127
+ assembled.request,
128
+ job.arguments["budget"],
129
+ scope=job.arguments["pinned_facts"].scope,
130
+ security_scope=args.security_scope,
131
+ snapshot_revision=args.snapshot_revision,
132
+ )
133
+ )
134
+ return dict(
135
+ mode="live_provider_probe",
136
+ synthetic_input=job.synthetic,
137
+ **result.to_dict(include_content=args.show_content),
138
+ )
@@ -0,0 +1,324 @@
1
+ """Provider/accounting contracts; monetary amounts are integer micro-US dollars."""
2
+
3
+ import hashlib
4
+ import math
5
+ import re
6
+ from dataclasses import asdict, dataclass
7
+
8
+ from ..errors import ContractError
9
+ from ..models import ToolCall, canonical_json, freeze_sequence, integer_value, text_value
10
+
11
+ ENDPOINT = "https://api.groq.com/openai/v1/chat/completions"
12
+ ADAPTER_VERSION = "groq-chat-v1"
13
+ MODELS = ("openai/gpt-oss-120b", "openai/gpt-oss-20b")
14
+ # Inception Mercury (OpenAI-compatible); paid per token, no documented free tier.
15
+ INCEPTION_ENDPOINT = "https://api.inceptionlabs.ai/v1/chat/completions"
16
+ INCEPTION_ADAPTER_VERSION = "inception-chat-v1"
17
+ INCEPTION_MODELS = ("mercury-3", "mercury-2.5", "mercury-2")
18
+
19
+
20
+ def fingerprint(value) -> str:
21
+ return hashlib.sha256(canonical_json(value).encode()).hexdigest()
22
+
23
+
24
+ def positive_number(name, value, maximum=300):
25
+ if type(value) not in (int, float) or not math.isfinite(value) or not 0 < value <= maximum:
26
+ raise ContractError("Expected a positive finite bounded duration", field=name)
27
+
28
+
29
+ def identifier(value: str) -> str:
30
+ if not isinstance(value, str) or not re.fullmatch(r"[A-Za-z0-9._:/-]{1,200}", value):
31
+ raise ContractError("Invalid opaque provider identifier")
32
+ return value
33
+
34
+
35
+ @dataclass(frozen=True)
36
+ class GenerationConfig:
37
+ model: str = MODELS[0]
38
+ max_completion_tokens: int = 256
39
+ temperature: float = 0.0
40
+ reasoning_effort: str = "low"
41
+ tool_choice: str = "none"
42
+
43
+ def __post_init__(self):
44
+ if self.model not in MODELS or self.reasoning_effort not in ("low", "medium", "high"):
45
+ raise ContractError("Unsupported C05 model or reasoning setting")
46
+ integer_value("max_completion_tokens", self.max_completion_tokens, minimum=1)
47
+ if self.max_completion_tokens > 65536:
48
+ raise ContractError("Completion request exceeds model profile")
49
+ if (
50
+ type(self.temperature) not in (int, float)
51
+ or not math.isfinite(self.temperature)
52
+ or not 0 <= self.temperature <= 2
53
+ ):
54
+ raise ContractError("Invalid generation temperature")
55
+ if self.tool_choice not in ("none", "auto"):
56
+ raise ContractError("Unsupported tool choice")
57
+
58
+ def to_wire(self, request):
59
+ payload = {
60
+ **request.to_wire(),
61
+ **asdict(self),
62
+ "stream": False,
63
+ "n": 1,
64
+ "include_reasoning": False,
65
+ "service_tier": "on_demand",
66
+ }
67
+ if not request.tools:
68
+ payload.pop("tool_choice")
69
+ return payload
70
+
71
+
72
+ @dataclass(frozen=True)
73
+ class InceptionGenerationConfig:
74
+ """Mercury request settings; the API accepts temperature 0.5-1 only."""
75
+
76
+ model: str = "mercury-3"
77
+ max_completion_tokens: int = 256
78
+ temperature: float = 0.5
79
+ reasoning_effort: str = "low"
80
+ tool_choice: str = "none"
81
+
82
+ def __post_init__(self):
83
+ if self.model not in INCEPTION_MODELS or self.reasoning_effort not in (
84
+ "instant",
85
+ "low",
86
+ "medium",
87
+ "high",
88
+ ):
89
+ raise ContractError("Unsupported Inception model or reasoning setting")
90
+ integer_value("max_completion_tokens", self.max_completion_tokens, minimum=1)
91
+ if self.max_completion_tokens > 50000:
92
+ raise ContractError("Completion request exceeds the smallest Mercury limit")
93
+ if (
94
+ type(self.temperature) not in (int, float)
95
+ or not math.isfinite(self.temperature)
96
+ or not 0.5 <= self.temperature <= 1
97
+ ):
98
+ raise ContractError("Inception temperature must be between 0.5 and 1")
99
+ if self.tool_choice not in ("none", "auto"):
100
+ raise ContractError("Unsupported tool choice")
101
+
102
+ def to_wire(self, request):
103
+ payload = {**request.to_wire(), **asdict(self), "stream": False}
104
+ if not request.tools:
105
+ payload.pop("tool_choice")
106
+ return payload
107
+
108
+
109
+ @dataclass(frozen=True)
110
+ class RetryConfig:
111
+ max_attempts: int = 3
112
+ attempt_timeout: float = 20.0
113
+ total_timeout: float = 45.0
114
+ max_backoff: float = 10.0
115
+
116
+ def __post_init__(self):
117
+ integer_value("max_attempts", self.max_attempts, minimum=1)
118
+ if self.max_attempts > 5:
119
+ raise ContractError("Retry attempt limit is five")
120
+ for name in ("attempt_timeout", "total_timeout", "max_backoff"):
121
+ positive_number(name, getattr(self, name))
122
+
123
+
124
+ @dataclass(frozen=True)
125
+ class QuotaPolicy:
126
+ account_id: str
127
+ daily_budget_microusd: int = 0
128
+ rpm: int = 30
129
+ tpm: int = 8000
130
+ rpd: int = 1000
131
+ tpd: int = 200000
132
+ billing_mode: str = "metered"
133
+
134
+ def __post_init__(self):
135
+ identifier(self.account_id)
136
+ if self.billing_mode not in ("metered", "free_tier"):
137
+ raise ContractError("Billing mode must be metered or explicitly confirmed free_tier")
138
+ if self.billing_mode == "free_tier" and self.daily_budget_microusd != 0:
139
+ raise ContractError("Free-tier mode requires a zero daily paid-spending cap")
140
+ for name in ("daily_budget_microusd", "rpm", "tpm", "rpd", "tpd"):
141
+ integer_value(name, getattr(self, name))
142
+ if getattr(self, name) > 10**12:
143
+ raise ContractError("Quota exceeds local integer accounting range")
144
+
145
+ def validate_prices(self, prices):
146
+ if not isinstance(prices, PriceCard):
147
+ raise ContractError("A validated price card is required")
148
+ if self.billing_mode == "free_tier" and prices.reserve_cost(1_000_000, 1_000_000) != 0:
149
+ raise ContractError("Free-tier mode requires zero configured token prices")
150
+
151
+
152
+ @dataclass(frozen=True)
153
+ class PriceCard:
154
+ version: str
155
+ input_per_million_microusd: int
156
+ cached_input_per_million_microusd: int
157
+ output_per_million_microusd: int
158
+
159
+ def __post_init__(self):
160
+ identifier(self.version)
161
+ for name in (
162
+ "input_per_million_microusd",
163
+ "cached_input_per_million_microusd",
164
+ "output_per_million_microusd",
165
+ ):
166
+ integer_value(name, getattr(self, name))
167
+ if getattr(self, name) > 10**12:
168
+ raise ContractError("Price exceeds local integer accounting range")
169
+
170
+ def cost(self, input_tokens: int, output_tokens: int, cached_tokens: int = 0) -> int:
171
+ for value in (input_tokens, output_tokens, cached_tokens):
172
+ integer_value("tokens", value)
173
+ if cached_tokens > input_tokens:
174
+ raise ContractError("Cached input exceeds total input")
175
+ numerator = (
176
+ (input_tokens - cached_tokens) * self.input_per_million_microusd
177
+ + cached_tokens * self.cached_input_per_million_microusd
178
+ + output_tokens * self.output_per_million_microusd
179
+ )
180
+ return (numerator + 999999) // 1000000
181
+
182
+ def reserve_cost(self, input_tokens: int, output_tokens: int) -> int:
183
+ for value in (input_tokens, output_tokens):
184
+ integer_value("tokens", value)
185
+ # Never assume that caching is discounted in an arbitrary caller-supplied price card.
186
+ numerator = input_tokens * max(
187
+ self.input_per_million_microusd, self.cached_input_per_million_microusd
188
+ )
189
+ return (numerator + output_tokens * self.output_per_million_microusd + 999999) // 1000000
190
+
191
+ def observed_cost(self, usage) -> int:
192
+ if usage.cached_input_tokens is None:
193
+ return self.reserve_cost(usage.input_tokens, usage.output_tokens)
194
+ return self.cost(usage.input_tokens, usage.output_tokens, usage.cached_input_tokens)
195
+
196
+
197
+ @dataclass(frozen=True)
198
+ class ReplayPolicy:
199
+ enabled: bool = False
200
+ ttl_seconds: int = 3600
201
+
202
+ def __post_init__(self):
203
+ if type(self.enabled) is not bool:
204
+ raise ContractError("Replay must be explicitly enabled with a boolean")
205
+ integer_value("ttl_seconds", self.ttl_seconds, minimum=1)
206
+ if self.ttl_seconds > 86400:
207
+ raise ContractError("C05 replay TTL is limited to one day")
208
+
209
+
210
+ @dataclass(frozen=True)
211
+ class Usage:
212
+ input_tokens: int
213
+ output_tokens: int
214
+ cached_input_tokens: int | None = None
215
+ reasoning_tokens: int | None = None
216
+
217
+ def __post_init__(self):
218
+ for name in ("input_tokens", "output_tokens"):
219
+ integer_value(name, getattr(self, name))
220
+ for name, maximum in (
221
+ ("cached_input_tokens", self.input_tokens),
222
+ ("reasoning_tokens", self.output_tokens),
223
+ ):
224
+ value = getattr(self, name)
225
+ if value is not None:
226
+ integer_value(name, value)
227
+ if value > maximum:
228
+ raise ContractError("Usage detail exceeds its containing total")
229
+ if self.input_tokens + self.output_tokens > 10**9:
230
+ raise ContractError("Usage exceeds supported accounting range")
231
+
232
+ @property
233
+ def total_tokens(self):
234
+ return self.input_tokens + self.output_tokens
235
+
236
+ @property
237
+ def visible_output_tokens(self):
238
+ return None if self.reasoning_tokens is None else self.output_tokens - self.reasoning_tokens
239
+
240
+
241
+ @dataclass(frozen=True)
242
+ class Completion:
243
+ model: str
244
+ response_id: str
245
+ content: str
246
+ finish_reason: str
247
+ usage: Usage
248
+ tool_calls: tuple[ToolCall, ...] = ()
249
+ system_fingerprint: str | None = None
250
+
251
+ def __post_init__(self):
252
+ identifier(self.response_id)
253
+ if self.model not in MODELS + INCEPTION_MODELS or self.finish_reason not in (
254
+ "stop",
255
+ "length",
256
+ "tool_calls",
257
+ "content_filter",
258
+ ):
259
+ raise ContractError("Unsupported provider completion")
260
+ text_value("content", self.content, nonempty=False)
261
+ if not isinstance(self.usage, Usage):
262
+ raise ContractError("Completion requires validated usage")
263
+ calls = freeze_sequence(self, "tool_calls", ToolCall)
264
+ if bool(calls) != (self.finish_reason == "tool_calls") or len(
265
+ {c.call_id for c in calls}
266
+ ) != len(calls):
267
+ raise ContractError("Tool-call finish reason disagrees with response")
268
+ if self.system_fingerprint is not None:
269
+ identifier(self.system_fingerprint)
270
+
271
+ def to_dict(self):
272
+ return asdict(self)
273
+
274
+ @classmethod
275
+ def from_dict(cls, value):
276
+ data = dict(value)
277
+ data["usage"] = Usage(**data["usage"])
278
+ data["tool_calls"] = tuple(ToolCall(**c) for c in data["tool_calls"])
279
+ return cls(**data)
280
+
281
+
282
+ class TransportFailure(Exception):
283
+ """Only controlled metadata crosses the network/ledger boundary."""
284
+
285
+ def __init__(
286
+ self, code: str, *, uncertain: bool, retryable=False, retry_after=None, usage=None
287
+ ):
288
+ identifier(code)
289
+ if type(uncertain) is not bool or type(retryable) is not bool:
290
+ raise ContractError("Failure flags must be booleans")
291
+ if retry_after is not None and (
292
+ type(retry_after) not in (int, float)
293
+ or not math.isfinite(retry_after)
294
+ or retry_after < 0
295
+ ):
296
+ raise ContractError("Invalid retry delay")
297
+ if usage is not None and not isinstance(usage, Usage):
298
+ raise ContractError("Failure usage must be validated")
299
+ super().__init__(code)
300
+ self.code, self.uncertain, self.retryable = code, uncertain, retryable
301
+ self.retry_after, self.usage = retry_after, usage
302
+
303
+
304
+ @dataclass(frozen=True)
305
+ class ModelResult:
306
+ status: str
307
+ request_key: str
308
+ attempt_ids: tuple[str, ...] = ()
309
+ completion: Completion | None = None
310
+ error_code: str | None = None
311
+ replay_of: str | None = None
312
+ new_cost_microusd: int | None = 0
313
+ original_cost_microusd: int | None = None
314
+ warning: str | None = None
315
+
316
+ def to_dict(self, *, include_content=False):
317
+ if type(include_content) is not bool:
318
+ raise ContractError("Content export requires an explicit boolean")
319
+ result = asdict(self)
320
+ if self.completion is not None and not include_content:
321
+ result["completion"].pop("content")
322
+ result["completion"].pop("tool_calls")
323
+ result["content_included"] = include_content
324
+ return result
@@ -0,0 +1,66 @@
1
+ """Explicit, bounded credential loading; no shell evaluation or secret-bearing errors."""
2
+
3
+ import os
4
+ import stat
5
+ from pathlib import Path
6
+
7
+ from ..errors import ContractError
8
+
9
+
10
+ def private_bytes(path, maximum):
11
+ if os.name == "nt":
12
+ from .windows_credentials import private_bytes as windows_private_bytes
13
+
14
+ return windows_private_bytes(path, maximum)
15
+ descriptor = None
16
+ try:
17
+ descriptor = os.open(
18
+ Path(path), os.O_RDONLY | getattr(os, "O_NOFOLLOW", 0) | getattr(os, "O_NONBLOCK", 0)
19
+ )
20
+ info = os.fstat(descriptor)
21
+ if not stat.S_ISREG(info.st_mode) or (os.name == "posix" and info.st_mode & 0o077):
22
+ raise ContractError("Configuration must be a private regular file")
23
+ with os.fdopen(descriptor, "rb") as handle:
24
+ descriptor = None
25
+ raw = handle.read(maximum + 1)
26
+ if len(raw) > maximum:
27
+ raise ContractError("Private configuration exceeds its size limit")
28
+ return raw
29
+ except (OSError, TypeError, ValueError):
30
+ raise ContractError("Cannot read private configuration") from None
31
+ finally:
32
+ if descriptor is not None:
33
+ os.close(descriptor)
34
+
35
+
36
+ def load_api_key(env_file=None):
37
+ key = os.environ.get("GROQ_API_KEY")
38
+ if env_file is not None:
39
+ try:
40
+ lines = private_bytes(env_file, 8192).decode("ascii").splitlines()
41
+ except UnicodeError:
42
+ raise ContractError("Credential file must contain a plain ASCII assignment") from None
43
+ values = []
44
+ for line in lines:
45
+ line = line.strip()
46
+ if not line or line.startswith("#"):
47
+ continue
48
+ name, sep, value = line.partition("=")
49
+ if sep != "=" or name.strip() != "GROQ_API_KEY":
50
+ raise ContractError("Credential file permits only GROQ_API_KEY and comments")
51
+ value = value.strip()
52
+ if len(value) >= 2 and value[0] in "\"'" and value[-1] == value[0]:
53
+ value = value[1:-1]
54
+ values.append(value)
55
+ if len(values) != 1:
56
+ raise ContractError("Credential file requires exactly one GROQ_API_KEY assignment")
57
+ if key and key != values[0]:
58
+ raise ContractError("Environment and explicit credential file disagree")
59
+ key = values[0]
60
+ if (
61
+ not key
62
+ or len(key) > 4096
63
+ or any(not (c.isascii() and (c.isalnum() or c in "_-")) for c in key)
64
+ ):
65
+ raise ContractError("Missing or invalid credential; value is never displayed")
66
+ return key
@@ -0,0 +1,112 @@
1
+ """Optional memory-aware inference; memory owns replay lifecycle, not the provider cache."""
2
+
3
+ import uuid
4
+ from dataclasses import asdict
5
+
6
+ from ..errors import ContractError, MemoryConflict, MemoryIntegrityError
7
+ from ..memory import MemoryStore
8
+ from .client import ProviderClient
9
+ from .contracts import Completion, ModelResult, fingerprint
10
+
11
+
12
+ class MemoryProvider:
13
+ def __init__(self, memory: MemoryStore, client: ProviderClient, *, replay=False):
14
+ if not isinstance(memory, MemoryStore) or not isinstance(client, ProviderClient):
15
+ raise ContractError("Memory integration requires validated stores/client")
16
+ if type(replay) is not bool or client.replay.enabled:
17
+ raise ContractError(
18
+ "Use memory-managed replay only; provider body cache must be disabled"
19
+ )
20
+ self.memory, self.client, self.replay = memory, client, replay
21
+
22
+ async def complete(self, scope, question, budget, *, system, security_scope, **assembly):
23
+ if not isinstance(security_scope, str) or not security_scope.strip():
24
+ raise ContractError("An authorized security scope is required")
25
+ snapshot, context = self.memory.assemble(scope, question, budget, system=system, **assembly)
26
+ client = self.client
27
+ key = fingerprint(
28
+ {
29
+ "snapshot": snapshot.snapshot_id,
30
+ "request": context.request.to_wire(),
31
+ "security": security_scope,
32
+ "budget": asdict(budget),
33
+ "generation": asdict(client.generation),
34
+ "prices": asdict(client.prices),
35
+ "account": client.quota.account_id,
36
+ "counting": context.diagnostics.estimate.to_dict(),
37
+ "transport": getattr(
38
+ client.transport, "namespace", type(client.transport).__qualname__
39
+ ),
40
+ "policy": "memory-provider-v1",
41
+ }
42
+ )
43
+ if self.replay and (cached := self.memory.cache_get(snapshot, key)) is not None:
44
+ try:
45
+ completion = Completion.from_dict(cached["completion"])
46
+ with client.store.transaction() as db:
47
+ source = db.execute(
48
+ "SELECT * FROM attempts WHERE id=?", (cached["attempt_id"],)
49
+ ).fetchone()
50
+ if (
51
+ source is None
52
+ or source["account"] != fingerprint(client.quota.account_id)
53
+ or source["state"] != "completed"
54
+ or source["request_key"] != cached["request_key"]
55
+ or source["completion_hash"] != fingerprint(completion.to_dict())
56
+ or source["cost"] != cached["cost"]
57
+ ):
58
+ raise MemoryIntegrityError("Memory replay ancestry is invalid")
59
+ db.execute(
60
+ "INSERT INTO events(id,account,request_key,created,kind,source_attempt,"
61
+ "new_cost) VALUES(?,?,?,?,?,?,0)",
62
+ (
63
+ uuid.uuid4().hex,
64
+ source["account"],
65
+ source["request_key"],
66
+ client.clock(),
67
+ "memory_replay",
68
+ source["id"],
69
+ ),
70
+ )
71
+ self.memory.assert_current(snapshot)
72
+ return ModelResult(
73
+ "replay",
74
+ cached["request_key"],
75
+ completion=completion,
76
+ replay_of=cached["attempt_id"],
77
+ new_cost_microusd=0,
78
+ original_cost_microusd=cached["cost"],
79
+ )
80
+ except (KeyError, TypeError, ValueError):
81
+ raise MemoryIntegrityError("Malformed memory replay") from None
82
+ result = await client.complete(
83
+ context.request,
84
+ budget,
85
+ scope=scope,
86
+ security_scope=security_scope,
87
+ snapshot_revision=snapshot.snapshot_id,
88
+ policy_version="memory-provider-v1",
89
+ )
90
+ try:
91
+ self.memory.assert_current(snapshot)
92
+ if self.replay and result.status == "success":
93
+ self.memory.cache_put(
94
+ snapshot,
95
+ key,
96
+ {
97
+ "completion": result.completion.to_dict(),
98
+ "attempt_id": result.attempt_ids[-1],
99
+ "request_key": result.request_key,
100
+ "cost": result.original_cost_microusd,
101
+ },
102
+ )
103
+ except MemoryConflict:
104
+ return ModelResult(
105
+ "error",
106
+ result.request_key,
107
+ result.attempt_ids,
108
+ error_code="memory_revision_conflict",
109
+ new_cost_microusd=result.new_cost_microusd,
110
+ warning="response_discarded_memory_changed",
111
+ )
112
+ return result