crprotocol 2.0.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.
- crp/__init__.py +126 -0
- crp/__main__.py +8 -0
- crp/_typing.py +27 -0
- crp/_version.py +5 -0
- crp/adapters.py +31 -0
- crp/advanced/__init__.py +40 -0
- crp/advanced/auto_ingest.py +400 -0
- crp/advanced/cqs.py +235 -0
- crp/advanced/cross_window.py +477 -0
- crp/advanced/curator.py +265 -0
- crp/advanced/feedback.py +146 -0
- crp/advanced/hierarchical.py +211 -0
- crp/advanced/meta_learning.py +401 -0
- crp/advanced/parallel.py +98 -0
- crp/advanced/review_cycle.py +329 -0
- crp/advanced/scale_mode.py +129 -0
- crp/advanced/source_grounding.py +207 -0
- crp/ckf/__init__.py +35 -0
- crp/ckf/community.py +377 -0
- crp/ckf/fabric.py +445 -0
- crp/ckf/gc.py +175 -0
- crp/ckf/graph_walk.py +87 -0
- crp/ckf/merge.py +133 -0
- crp/ckf/pattern_query.py +122 -0
- crp/ckf/pubsub.py +128 -0
- crp/ckf/semantic.py +207 -0
- crp/cli/__init__.py +7 -0
- crp/cli/main.py +329 -0
- crp/cli/sidecar.py +929 -0
- crp/cli/startup.py +272 -0
- crp/continuation/__init__.py +103 -0
- crp/continuation/completion.py +348 -0
- crp/continuation/degradation.py +157 -0
- crp/continuation/document_map.py +160 -0
- crp/continuation/flow.py +109 -0
- crp/continuation/gap.py +419 -0
- crp/continuation/manager.py +484 -0
- crp/continuation/quality_monitor.py +179 -0
- crp/continuation/stitch.py +419 -0
- crp/continuation/trigger.py +142 -0
- crp/continuation/voice.py +157 -0
- crp/core/__init__.py +69 -0
- crp/core/batch.py +77 -0
- crp/core/circuit_breaker.py +116 -0
- crp/core/config.py +377 -0
- crp/core/context_tools.py +540 -0
- crp/core/dispatch_router.py +3977 -0
- crp/core/errors.py +128 -0
- crp/core/extraction_facade.py +384 -0
- crp/core/facilitator.py +713 -0
- crp/core/idempotency.py +215 -0
- crp/core/orchestrator.py +1435 -0
- crp/core/relay_strategies.py +613 -0
- crp/core/security_manager.py +140 -0
- crp/core/session.py +134 -0
- crp/core/task_intent.py +36 -0
- crp/core/window.py +363 -0
- crp/envelope/__init__.py +30 -0
- crp/envelope/builder.py +288 -0
- crp/envelope/decomposer.py +236 -0
- crp/envelope/formatter.py +168 -0
- crp/envelope/packer.py +211 -0
- crp/envelope/reranker.py +209 -0
- crp/envelope/scoring.py +310 -0
- crp/extraction/__init__.py +45 -0
- crp/extraction/complexity.py +96 -0
- crp/extraction/contradiction.py +132 -0
- crp/extraction/pipeline.py +360 -0
- crp/extraction/quality_gate.py +237 -0
- crp/extraction/stage1_regex.py +173 -0
- crp/extraction/stage2_statistical.py +244 -0
- crp/extraction/stage3_gliner.py +210 -0
- crp/extraction/stage4_uie.py +183 -0
- crp/extraction/stage5_discourse.py +175 -0
- crp/extraction/stage6_llm.py +178 -0
- crp/extraction/structured_output.py +219 -0
- crp/extraction/types.py +299 -0
- crp/license_guard.py +722 -0
- crp/observability/__init__.py +30 -0
- crp/observability/audit.py +118 -0
- crp/observability/events.py +233 -0
- crp/observability/metrics.py +264 -0
- crp/observability/quality.py +135 -0
- crp/observability/structured_logging.py +81 -0
- crp/observability/telemetry.py +117 -0
- crp/provenance/__init__.py +314 -0
- crp/provenance/_embeddings.py +97 -0
- crp/provenance/_types.py +378 -0
- crp/provenance/attribution_scorer.py +252 -0
- crp/provenance/claim_detector.py +229 -0
- crp/provenance/contradiction_detector.py +243 -0
- crp/provenance/distortion_detector.py +397 -0
- crp/provenance/entailment_verifier.py +358 -0
- crp/provenance/fabrication_detector.py +203 -0
- crp/provenance/hallucination_scorer.py +320 -0
- crp/provenance/omission_analyzer.py +106 -0
- crp/provenance/provenance_chain.py +205 -0
- crp/provenance/report_generator.py +440 -0
- crp/providers/__init__.py +43 -0
- crp/providers/anthropic.py +270 -0
- crp/providers/base.py +135 -0
- crp/providers/custom.py +63 -0
- crp/providers/diagnostic.py +251 -0
- crp/providers/llamacpp.py +224 -0
- crp/providers/manager.py +139 -0
- crp/providers/ollama.py +243 -0
- crp/providers/openai.py +628 -0
- crp/providers/tokenizers.py +48 -0
- crp/py.typed +0 -0
- crp/resources/__init__.py +53 -0
- crp/resources/adaptive_allocator.py +525 -0
- crp/resources/cost_model.py +388 -0
- crp/resources/overhead_manager.py +217 -0
- crp/resources/resource_manager.py +262 -0
- crp/schemas/__init__.py +20 -0
- crp/schemas/cost-estimate.json +33 -0
- crp/schemas/crp-error.json +43 -0
- crp/schemas/envelope-preview.json +40 -0
- crp/schemas/persisted-state-header.json +27 -0
- crp/schemas/quality-report.json +94 -0
- crp/schemas/session-handle.json +33 -0
- crp/schemas/session-status.json +57 -0
- crp/schemas/stream-event.json +18 -0
- crp/schemas/task-intent.json +42 -0
- crp/security/__init__.py +93 -0
- crp/security/audit_trail.py +392 -0
- crp/security/binding.py +192 -0
- crp/security/compliance.py +813 -0
- crp/security/consent.py +593 -0
- crp/security/embedding_defense.py +161 -0
- crp/security/encryption.py +202 -0
- crp/security/injection.py +335 -0
- crp/security/integrity.py +267 -0
- crp/security/privacy.py +662 -0
- crp/security/quarantine.py +249 -0
- crp/security/rbac.py +221 -0
- crp/security/validation.py +164 -0
- crp/state/__init__.py +31 -0
- crp/state/cold_storage.py +258 -0
- crp/state/compaction.py +263 -0
- crp/state/critical_state.py +104 -0
- crp/state/event_log.py +313 -0
- crp/state/fact.py +189 -0
- crp/state/serialization.py +189 -0
- crp/state/session_cleanup.py +77 -0
- crp/state/snapshot.py +290 -0
- crp/state/warm_store.py +346 -0
- crprotocol-2.0.0.dist-info/METADATA +1295 -0
- crprotocol-2.0.0.dist-info/RECORD +153 -0
- crprotocol-2.0.0.dist-info/WHEEL +4 -0
- crprotocol-2.0.0.dist-info/entry_points.txt +2 -0
- crprotocol-2.0.0.dist-info/licenses/LICENSE.md +170 -0
- crprotocol-2.0.0.dist-info/licenses/NOTICE +18 -0
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
# Copyright © 2025 Constantinos Vidiniotis. All rights reserved.
|
|
2
|
+
# Licensed under Elastic License 2.0 — see LICENSE.md for details.
|
|
3
|
+
"""Centralized resource manager — memory tracking, model registry, pressure (§audit R1).
|
|
4
|
+
|
|
5
|
+
Tracks memory consumption, ML model lifecycle, session budgets,
|
|
6
|
+
and provides pressure signals for adaptive dispatch behavior.
|
|
7
|
+
|
|
8
|
+
Pressure levels:
|
|
9
|
+
"none" : usage < 50% of budget → normal operation
|
|
10
|
+
"low" : 50-70% → compaction eligible
|
|
11
|
+
"medium" : 70-85% → aggressive compaction, idle model unload
|
|
12
|
+
"high" : 85-95% → forced compaction, model unload, GC
|
|
13
|
+
"critical" : >95% → emergency cleanup, session pruning
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
import gc
|
|
19
|
+
import logging
|
|
20
|
+
import os
|
|
21
|
+
import time
|
|
22
|
+
from dataclasses import dataclass, field
|
|
23
|
+
|
|
24
|
+
logger = logging.getLogger(__name__)
|
|
25
|
+
|
|
26
|
+
# ---------------------------------------------------------------------------
|
|
27
|
+
# Budget defaults
|
|
28
|
+
# ---------------------------------------------------------------------------
|
|
29
|
+
|
|
30
|
+
DEFAULT_MEMORY_BUDGET_MB = 512
|
|
31
|
+
PRESSURE_THRESHOLDS: list[tuple[str, float]] = [
|
|
32
|
+
("critical", 0.95),
|
|
33
|
+
("high", 0.85),
|
|
34
|
+
("medium", 0.70),
|
|
35
|
+
("low", 0.50),
|
|
36
|
+
("none", 0.0),
|
|
37
|
+
]
|
|
38
|
+
|
|
39
|
+
# Estimated per-model memory footprint (MB).
|
|
40
|
+
MODEL_ESTIMATES: dict[str, float] = {
|
|
41
|
+
"sentence-transformers": 150.0,
|
|
42
|
+
"cross-encoder": 200.0,
|
|
43
|
+
"gliner": 200.0,
|
|
44
|
+
"uie": 400.0,
|
|
45
|
+
"hnsw-index": 50.0, # varies with fact count
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
# Average bytes per fact in warm store (empirical).
|
|
49
|
+
_BYTES_PER_FACT = 500
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
@dataclass
|
|
53
|
+
class ResourceSnapshot:
|
|
54
|
+
"""Point-in-time resource utilization snapshot."""
|
|
55
|
+
|
|
56
|
+
timestamp: float = 0.0
|
|
57
|
+
process_rss_mb: float = 0.0
|
|
58
|
+
crp_estimated_mb: float = 0.0
|
|
59
|
+
model_memory_mb: float = 0.0
|
|
60
|
+
fact_store_mb: float = 0.0
|
|
61
|
+
budget_mb: float = DEFAULT_MEMORY_BUDGET_MB
|
|
62
|
+
pressure_level: str = "none"
|
|
63
|
+
models_loaded: list[str] = field(default_factory=list)
|
|
64
|
+
fact_count: int = 0
|
|
65
|
+
session_count: int = 0
|
|
66
|
+
|
|
67
|
+
@property
|
|
68
|
+
def utilization_ratio(self) -> float:
|
|
69
|
+
if self.budget_mb <= 0:
|
|
70
|
+
return 0.0
|
|
71
|
+
return self.crp_estimated_mb / self.budget_mb
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
@dataclass
|
|
75
|
+
class ModelEntry:
|
|
76
|
+
"""Registered ML model with lifecycle tracking."""
|
|
77
|
+
|
|
78
|
+
name: str
|
|
79
|
+
estimated_mb: float
|
|
80
|
+
loaded_at: float = 0.0
|
|
81
|
+
last_used_at: float = 0.0
|
|
82
|
+
use_count: int = 0
|
|
83
|
+
is_loaded: bool = False
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
class ResourceManager:
|
|
87
|
+
"""Centralized resource tracking and pressure management.
|
|
88
|
+
|
|
89
|
+
Usage::
|
|
90
|
+
|
|
91
|
+
rm = ResourceManager(budget_mb=512)
|
|
92
|
+
rm.register_model("sentence-transformers", 150)
|
|
93
|
+
rm.mark_model_loaded("sentence-transformers")
|
|
94
|
+
snap = rm.snapshot()
|
|
95
|
+
print(snap.pressure_level)
|
|
96
|
+
"""
|
|
97
|
+
|
|
98
|
+
def __init__(self, budget_mb: float = DEFAULT_MEMORY_BUDGET_MB) -> None:
|
|
99
|
+
self._budget_mb = budget_mb
|
|
100
|
+
self._models: dict[str, ModelEntry] = {}
|
|
101
|
+
self._fact_count = 0
|
|
102
|
+
self._session_count = 0
|
|
103
|
+
self._created_at = time.time()
|
|
104
|
+
self._last_gc = 0.0
|
|
105
|
+
self._cleanup_count = 0
|
|
106
|
+
|
|
107
|
+
# -- Model lifecycle ---------------------------------------------------
|
|
108
|
+
|
|
109
|
+
def register_model(self, name: str, estimated_mb: float) -> None:
|
|
110
|
+
"""Register an ML model (call at init, before loading)."""
|
|
111
|
+
self._models[name] = ModelEntry(name=name, estimated_mb=estimated_mb)
|
|
112
|
+
|
|
113
|
+
def mark_model_loaded(self, name: str) -> None:
|
|
114
|
+
"""Mark a model as loaded into memory."""
|
|
115
|
+
if name in self._models:
|
|
116
|
+
self._models[name].is_loaded = True
|
|
117
|
+
self._models[name].loaded_at = time.time()
|
|
118
|
+
self._models[name].last_used_at = time.time()
|
|
119
|
+
|
|
120
|
+
def mark_model_used(self, name: str) -> None:
|
|
121
|
+
"""Record model usage (resets idle timer)."""
|
|
122
|
+
if name in self._models:
|
|
123
|
+
self._models[name].last_used_at = time.time()
|
|
124
|
+
self._models[name].use_count += 1
|
|
125
|
+
|
|
126
|
+
def mark_model_unloaded(self, name: str) -> None:
|
|
127
|
+
"""Mark a model as unloaded from memory."""
|
|
128
|
+
if name in self._models:
|
|
129
|
+
self._models[name].is_loaded = False
|
|
130
|
+
|
|
131
|
+
# -- Fact store tracking -----------------------------------------------
|
|
132
|
+
|
|
133
|
+
def update_fact_count(self, count: int) -> None:
|
|
134
|
+
self._fact_count = count
|
|
135
|
+
|
|
136
|
+
def update_session_count(self, count: int) -> None:
|
|
137
|
+
self._session_count = count
|
|
138
|
+
|
|
139
|
+
# -- Snapshot & pressure -----------------------------------------------
|
|
140
|
+
|
|
141
|
+
def snapshot(self) -> ResourceSnapshot:
|
|
142
|
+
"""Take a point-in-time resource snapshot."""
|
|
143
|
+
model_mb = sum(m.estimated_mb for m in self._models.values() if m.is_loaded)
|
|
144
|
+
fact_mb = self._fact_count * _BYTES_PER_FACT / (1024 * 1024)
|
|
145
|
+
crp_mb = model_mb + fact_mb
|
|
146
|
+
|
|
147
|
+
rss_mb = _get_process_rss_mb()
|
|
148
|
+
pressure = self._compute_pressure(crp_mb)
|
|
149
|
+
loaded = [m.name for m in self._models.values() if m.is_loaded]
|
|
150
|
+
|
|
151
|
+
return ResourceSnapshot(
|
|
152
|
+
timestamp=time.time(),
|
|
153
|
+
process_rss_mb=round(rss_mb, 1),
|
|
154
|
+
crp_estimated_mb=round(crp_mb, 1),
|
|
155
|
+
model_memory_mb=round(model_mb, 1),
|
|
156
|
+
fact_store_mb=round(fact_mb, 3),
|
|
157
|
+
budget_mb=self._budget_mb,
|
|
158
|
+
pressure_level=pressure,
|
|
159
|
+
models_loaded=loaded,
|
|
160
|
+
fact_count=self._fact_count,
|
|
161
|
+
session_count=self._session_count,
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
def _compute_pressure(self, crp_mb: float) -> str:
|
|
165
|
+
if self._budget_mb <= 0:
|
|
166
|
+
return "none"
|
|
167
|
+
ratio = crp_mb / self._budget_mb
|
|
168
|
+
for name, threshold in PRESSURE_THRESHOLDS:
|
|
169
|
+
if ratio >= threshold:
|
|
170
|
+
return name
|
|
171
|
+
return "none"
|
|
172
|
+
|
|
173
|
+
# -- Cleanup actions ---------------------------------------------------
|
|
174
|
+
|
|
175
|
+
def should_cleanup(self) -> bool:
|
|
176
|
+
snap = self.snapshot()
|
|
177
|
+
return snap.pressure_level in ("medium", "high", "critical")
|
|
178
|
+
|
|
179
|
+
def run_gc(self) -> int:
|
|
180
|
+
collected = gc.collect()
|
|
181
|
+
self._last_gc = time.time()
|
|
182
|
+
self._cleanup_count += 1
|
|
183
|
+
logger.debug("GC collected %d objects (run #%d)", collected, self._cleanup_count)
|
|
184
|
+
return collected
|
|
185
|
+
|
|
186
|
+
def get_idle_models(self, idle_seconds: float = 300.0) -> list[str]:
|
|
187
|
+
now = time.time()
|
|
188
|
+
return [
|
|
189
|
+
m.name for m in self._models.values()
|
|
190
|
+
if m.is_loaded and (now - m.last_used_at) > idle_seconds
|
|
191
|
+
]
|
|
192
|
+
|
|
193
|
+
def mark_unloaded(self, model_name: str) -> None:
|
|
194
|
+
"""Mark a model as unloaded (freed from memory)."""
|
|
195
|
+
if model_name in self._models:
|
|
196
|
+
self._models[model_name].is_loaded = False
|
|
197
|
+
logger.info("Model marked unloaded: %s", model_name)
|
|
198
|
+
|
|
199
|
+
def trigger_gc(self) -> int:
|
|
200
|
+
"""Run GC if pressure warrants it (alias for should_cleanup + run_gc)."""
|
|
201
|
+
if self.should_cleanup():
|
|
202
|
+
return self.run_gc()
|
|
203
|
+
return 0
|
|
204
|
+
|
|
205
|
+
# -- Summary -----------------------------------------------------------
|
|
206
|
+
|
|
207
|
+
def summary(self) -> dict:
|
|
208
|
+
snap = self.snapshot()
|
|
209
|
+
return {
|
|
210
|
+
"budget_mb": self._budget_mb,
|
|
211
|
+
"crp_estimated_mb": snap.crp_estimated_mb,
|
|
212
|
+
"model_memory_mb": snap.model_memory_mb,
|
|
213
|
+
"fact_store_mb": snap.fact_store_mb,
|
|
214
|
+
"process_rss_mb": snap.process_rss_mb,
|
|
215
|
+
"pressure_level": snap.pressure_level,
|
|
216
|
+
"utilization_pct": round(snap.utilization_ratio * 100, 1),
|
|
217
|
+
"models_loaded": snap.models_loaded,
|
|
218
|
+
"fact_count": snap.fact_count,
|
|
219
|
+
"gc_runs": self._cleanup_count,
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
# ---------------------------------------------------------------------------
|
|
224
|
+
# Helpers
|
|
225
|
+
# ---------------------------------------------------------------------------
|
|
226
|
+
|
|
227
|
+
def _get_process_rss_mb() -> float:
|
|
228
|
+
"""Get process RSS in MB (best-effort, returns 0 on failure)."""
|
|
229
|
+
try:
|
|
230
|
+
if os.name == "nt":
|
|
231
|
+
import ctypes
|
|
232
|
+
import ctypes.wintypes
|
|
233
|
+
|
|
234
|
+
class PROCESS_MEMORY_COUNTERS(ctypes.Structure):
|
|
235
|
+
_fields_ = [
|
|
236
|
+
("cb", ctypes.wintypes.DWORD),
|
|
237
|
+
("PageFaultCount", ctypes.wintypes.DWORD),
|
|
238
|
+
("PeakWorkingSetSize", ctypes.c_size_t),
|
|
239
|
+
("WorkingSetSize", ctypes.c_size_t),
|
|
240
|
+
("QuotaPeakPagedPoolUsage", ctypes.c_size_t),
|
|
241
|
+
("QuotaPagedPoolUsage", ctypes.c_size_t),
|
|
242
|
+
("QuotaPeakNonPagedPoolUsage", ctypes.c_size_t),
|
|
243
|
+
("QuotaNonPagedPoolUsage", ctypes.c_size_t),
|
|
244
|
+
("PagefileUsage", ctypes.c_size_t),
|
|
245
|
+
("PeakPagefileUsage", ctypes.c_size_t),
|
|
246
|
+
]
|
|
247
|
+
|
|
248
|
+
pmc = PROCESS_MEMORY_COUNTERS()
|
|
249
|
+
pmc.cb = ctypes.sizeof(pmc)
|
|
250
|
+
kernel32 = ctypes.windll.kernel32 # type: ignore[attr-defined]
|
|
251
|
+
handle = kernel32.GetCurrentProcess()
|
|
252
|
+
psapi = ctypes.windll.psapi # type: ignore[attr-defined]
|
|
253
|
+
if psapi.GetProcessMemoryInfo(handle, ctypes.byref(pmc), pmc.cb):
|
|
254
|
+
return pmc.WorkingSetSize / (1024 * 1024)
|
|
255
|
+
else:
|
|
256
|
+
with open("/proc/self/status") as f:
|
|
257
|
+
for line in f:
|
|
258
|
+
if line.startswith("VmRSS:"):
|
|
259
|
+
return int(line.split()[1]) / 1024
|
|
260
|
+
except Exception:
|
|
261
|
+
pass
|
|
262
|
+
return 0.0
|
crp/schemas/__init__.py
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Copyright © 2025 Constantinos Vidiniotis. All rights reserved.
|
|
2
|
+
# Licensed under Elastic License 2.0 — see LICENSE.md for details.
|
|
3
|
+
"""JSON Schema loader for CRP data contracts."""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
import json
|
|
8
|
+
from importlib import resources
|
|
9
|
+
from typing import Any
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def load_schema(name: str) -> dict[str, Any]:
|
|
13
|
+
"""Load a JSON Schema by name (without .json extension).
|
|
14
|
+
|
|
15
|
+
>>> schema = load_schema("task-intent")
|
|
16
|
+
>>> schema["type"]
|
|
17
|
+
'object'
|
|
18
|
+
"""
|
|
19
|
+
ref = resources.files("crp.schemas").joinpath(f"{name}.json")
|
|
20
|
+
return json.loads(ref.read_text(encoding="utf-8")) # type: ignore[arg-type]
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"title": "CostEstimate",
|
|
4
|
+
"description": "Returned by estimate_session(). Provides pre-flight cost estimation without performing any LLM calls.",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"required": ["estimated_windows", "estimated_input_tokens", "estimated_output_tokens"],
|
|
7
|
+
"properties": {
|
|
8
|
+
"estimated_windows": {
|
|
9
|
+
"type": "integer",
|
|
10
|
+
"minimum": 1,
|
|
11
|
+
"description": "Estimated total windows (dispatches + continuations)."
|
|
12
|
+
},
|
|
13
|
+
"estimated_input_tokens": {
|
|
14
|
+
"type": "integer",
|
|
15
|
+
"minimum": 0,
|
|
16
|
+
"description": "Estimated cumulative input tokens across all windows."
|
|
17
|
+
},
|
|
18
|
+
"estimated_output_tokens": {
|
|
19
|
+
"type": "integer",
|
|
20
|
+
"minimum": 0,
|
|
21
|
+
"description": "Estimated cumulative output tokens across all windows."
|
|
22
|
+
},
|
|
23
|
+
"estimated_cost_usd": {
|
|
24
|
+
"type": ["number", "null"],
|
|
25
|
+
"description": "Estimated cost in USD. NULL if provider pricing not supplied."
|
|
26
|
+
},
|
|
27
|
+
"confidence": {
|
|
28
|
+
"type": "string",
|
|
29
|
+
"enum": ["high", "medium", "low"],
|
|
30
|
+
"description": "Estimation confidence. 'high' = known task pattern, 'low' = novel task."
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"title": "CRPError",
|
|
4
|
+
"description": "Standard error format for all CRP operations. Error codes are inspired by JSON-RPC 2.0 and gRPC status codes.",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"required": ["code", "message", "details"],
|
|
7
|
+
"properties": {
|
|
8
|
+
"code": {
|
|
9
|
+
"type": "integer",
|
|
10
|
+
"minimum": 1001,
|
|
11
|
+
"maximum": 1031,
|
|
12
|
+
"description": "Error code from the CRP error taxonomy (§6.10.4). Range: 1001-1031."
|
|
13
|
+
},
|
|
14
|
+
"message": {
|
|
15
|
+
"type": "string",
|
|
16
|
+
"description": "Human-readable error description."
|
|
17
|
+
},
|
|
18
|
+
"details": {
|
|
19
|
+
"type": "object",
|
|
20
|
+
"description": "Error-specific structured diagnostic data."
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"$defs": {
|
|
24
|
+
"ErrorCodes": {
|
|
25
|
+
"description": "CRP error code reference",
|
|
26
|
+
"enum": [
|
|
27
|
+
{ "const": 1001, "title": "BudgetExhaustedError", "description": "Any cost cap (windows, tokens, rate) exceeded" },
|
|
28
|
+
{ "const": 1002, "title": "RateLimitExceeded", "description": "Per-session rate limit hit" },
|
|
29
|
+
{ "const": 1003, "title": "SessionExpired", "description": "Session timeout reached" },
|
|
30
|
+
{ "const": 1004, "title": "SessionLimitExceeded", "description": "Max concurrent sessions reached" },
|
|
31
|
+
{ "const": 1005, "title": "SessionClosed", "description": "Operation on closed session" },
|
|
32
|
+
{ "const": 1010, "title": "ValidationError", "description": "Structural validation failure (§22.3.1)" },
|
|
33
|
+
{ "const": 1011, "title": "SecurityInvariantError", "description": "Attempted violation of security invariant" },
|
|
34
|
+
{ "const": 1012, "title": "SignatureInvalid", "description": "Request HMAC signature verification failed" },
|
|
35
|
+
{ "const": 1013, "title": "RBACDenied", "description": "Operation not permitted for current role" },
|
|
36
|
+
{ "const": 1020, "title": "ProviderError", "description": "LLM provider returned an error" },
|
|
37
|
+
{ "const": 1021, "title": "ProviderTimeout", "description": "LLM provider did not respond within timeout" },
|
|
38
|
+
{ "const": 1030, "title": "StateCorrupted", "description": "Cold state integrity verification failed" },
|
|
39
|
+
{ "const": 1031, "title": "ChainVerificationFailed", "description": "Fact chain signature verification failed" }
|
|
40
|
+
]
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"title": "EnvelopePreview",
|
|
4
|
+
"description": "Returned by preview_envelope(). Inspect what the envelope would contain without dispatching.",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"required": ["total_tokens", "envelope_tokens", "facts_included", "saturation"],
|
|
7
|
+
"properties": {
|
|
8
|
+
"total_tokens": {
|
|
9
|
+
"type": "integer",
|
|
10
|
+
"minimum": 0,
|
|
11
|
+
"description": "Total tokens (system_prompt + envelope + task_input + generation_reserve)."
|
|
12
|
+
},
|
|
13
|
+
"envelope_tokens": {
|
|
14
|
+
"type": "integer",
|
|
15
|
+
"minimum": 0,
|
|
16
|
+
"description": "Tokens consumed by the envelope content."
|
|
17
|
+
},
|
|
18
|
+
"generation_reserve": {
|
|
19
|
+
"type": "integer",
|
|
20
|
+
"minimum": 0,
|
|
21
|
+
"description": "Tokens reserved for LLM generation output."
|
|
22
|
+
},
|
|
23
|
+
"facts_included": {
|
|
24
|
+
"type": "integer",
|
|
25
|
+
"minimum": 0,
|
|
26
|
+
"description": "Number of facts included in the envelope."
|
|
27
|
+
},
|
|
28
|
+
"facts_available": {
|
|
29
|
+
"type": "integer",
|
|
30
|
+
"minimum": 0,
|
|
31
|
+
"description": "Total facts available in warm + cold state."
|
|
32
|
+
},
|
|
33
|
+
"saturation": {
|
|
34
|
+
"type": "number",
|
|
35
|
+
"minimum": 0.0,
|
|
36
|
+
"maximum": 1.0,
|
|
37
|
+
"description": "Fraction of available envelope space used (0.0–1.0)."
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"title": "PersistedStateHeader",
|
|
4
|
+
"description": "Header for all persisted CRP data structures (cold state, event log, exported state). Enables schema migration across versions.",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"required": ["schema_version", "protocol_version", "created_at", "checksum"],
|
|
7
|
+
"properties": {
|
|
8
|
+
"schema_version": {
|
|
9
|
+
"type": "string",
|
|
10
|
+
"pattern": "^\\d+\\.\\d+\\.\\d+$",
|
|
11
|
+
"description": "SemVer for the persisted format (e.g., '2.0.0'). Implementations MUST read state from the same Major version."
|
|
12
|
+
},
|
|
13
|
+
"protocol_version": {
|
|
14
|
+
"type": "string",
|
|
15
|
+
"pattern": "^\\d+\\.\\d+\\.\\d+$",
|
|
16
|
+
"description": "CRP protocol version that wrote this state."
|
|
17
|
+
},
|
|
18
|
+
"created_at": {
|
|
19
|
+
"type": "number",
|
|
20
|
+
"description": "Timestamp of state creation (seconds since epoch)."
|
|
21
|
+
},
|
|
22
|
+
"checksum": {
|
|
23
|
+
"type": "string",
|
|
24
|
+
"description": "BLAKE3 integrity hash of the payload. If verification fails, implementations MUST raise StateCorrupted (code 1030)."
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"title": "QualityReport",
|
|
4
|
+
"description": "Returned by dispatch() alongside the LLM output. MUST always be provided.",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"required": ["session_id", "window_id", "output", "facts_extracted", "security_flags"],
|
|
7
|
+
"properties": {
|
|
8
|
+
"session_id": {
|
|
9
|
+
"type": "string",
|
|
10
|
+
"format": "uuid",
|
|
11
|
+
"description": "UUID v4 identifying the session. MUST be stable across all windows in a session."
|
|
12
|
+
},
|
|
13
|
+
"window_id": {
|
|
14
|
+
"type": "string",
|
|
15
|
+
"format": "uuid",
|
|
16
|
+
"description": "UUID v4 identifying this specific window invocation."
|
|
17
|
+
},
|
|
18
|
+
"output": {
|
|
19
|
+
"type": "string",
|
|
20
|
+
"description": "The complete, unmodified LLM output (Axiom 9 — Output Integrity). MUST NOT be filtered, summarized, or truncated by CRP."
|
|
21
|
+
},
|
|
22
|
+
"facts_extracted": {
|
|
23
|
+
"type": "integer",
|
|
24
|
+
"minimum": 0,
|
|
25
|
+
"description": "Number of facts extracted from this window's output."
|
|
26
|
+
},
|
|
27
|
+
"continuation_windows": {
|
|
28
|
+
"type": "integer",
|
|
29
|
+
"minimum": 0,
|
|
30
|
+
"description": "Number of continuation windows triggered (0 if output fit in one window)."
|
|
31
|
+
},
|
|
32
|
+
"envelope_saturation": {
|
|
33
|
+
"type": "number",
|
|
34
|
+
"minimum": 0.0,
|
|
35
|
+
"maximum": 1.0,
|
|
36
|
+
"description": "Fraction of available envelope space used (0.0–1.0). SHOULD be > 0.9 for non-trivial tasks."
|
|
37
|
+
},
|
|
38
|
+
"quality_tier": {
|
|
39
|
+
"type": "string",
|
|
40
|
+
"enum": ["S", "A", "B", "C", "D"],
|
|
41
|
+
"description": "CRP quality tier for this task based on window count (§10)."
|
|
42
|
+
},
|
|
43
|
+
"security_flags": {
|
|
44
|
+
"$ref": "#/$defs/SecurityFlags",
|
|
45
|
+
"description": "Security observations for this window. MUST always be present."
|
|
46
|
+
},
|
|
47
|
+
"telemetry": {
|
|
48
|
+
"type": ["object", "null"],
|
|
49
|
+
"description": "Performance telemetry. MAY be omitted if telemetry is disabled."
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
"$defs": {
|
|
53
|
+
"SecurityFlags": {
|
|
54
|
+
"type": "object",
|
|
55
|
+
"properties": {
|
|
56
|
+
"injection_markers_detected": {
|
|
57
|
+
"type": "integer",
|
|
58
|
+
"minimum": 0,
|
|
59
|
+
"description": "Count of injection pattern matches detected in input."
|
|
60
|
+
},
|
|
61
|
+
"injection_marker_details": {
|
|
62
|
+
"type": "array",
|
|
63
|
+
"items": {
|
|
64
|
+
"type": "object",
|
|
65
|
+
"properties": {
|
|
66
|
+
"offset": { "type": "integer", "description": "Character offset of the match." },
|
|
67
|
+
"pattern_name": { "type": "string", "description": "Name of the matched injection pattern." },
|
|
68
|
+
"matched_text": { "type": "string", "description": "The text that matched the pattern." }
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
"description": "Details of each injection pattern match."
|
|
72
|
+
},
|
|
73
|
+
"unicode_normalized": {
|
|
74
|
+
"type": "boolean",
|
|
75
|
+
"description": "Whether Unicode normalization was applied to input."
|
|
76
|
+
},
|
|
77
|
+
"control_chars_stripped": {
|
|
78
|
+
"type": "integer",
|
|
79
|
+
"minimum": 0,
|
|
80
|
+
"description": "Count of control characters removed from input."
|
|
81
|
+
},
|
|
82
|
+
"input_truncated": {
|
|
83
|
+
"type": "boolean",
|
|
84
|
+
"description": "Whether input was truncated to fit max_task_input_bytes."
|
|
85
|
+
},
|
|
86
|
+
"integrity_violations": {
|
|
87
|
+
"type": "integer",
|
|
88
|
+
"minimum": 0,
|
|
89
|
+
"description": "Count of fact integrity chain verification failures."
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"title": "SessionHandle",
|
|
4
|
+
"description": "Returned by init(). Note: session_key is NEVER included in JSON serialization — it exists only in memory.",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"required": ["session_id", "protocol_version", "capabilities", "created_at", "expires_at"],
|
|
7
|
+
"properties": {
|
|
8
|
+
"session_id": {
|
|
9
|
+
"type": "string",
|
|
10
|
+
"format": "uuid",
|
|
11
|
+
"description": "UUID v4 — unique per session."
|
|
12
|
+
},
|
|
13
|
+
"protocol_version": {
|
|
14
|
+
"type": "string",
|
|
15
|
+
"pattern": "^\\d+\\.\\d+\\.\\d+$",
|
|
16
|
+
"description": "SemVer protocol version (e.g., '2.0.0')."
|
|
17
|
+
},
|
|
18
|
+
"capabilities": {
|
|
19
|
+
"type": "array",
|
|
20
|
+
"items": { "type": "string" },
|
|
21
|
+
"uniqueItems": true,
|
|
22
|
+
"description": "Granted RBAC permissions (e.g., 'dispatch', 'configure', 'session_status')."
|
|
23
|
+
},
|
|
24
|
+
"created_at": {
|
|
25
|
+
"type": "number",
|
|
26
|
+
"description": "Monotonic timestamp (seconds since epoch) of session creation."
|
|
27
|
+
},
|
|
28
|
+
"expires_at": {
|
|
29
|
+
"type": "number",
|
|
30
|
+
"description": "Session expiry timestamp (seconds since epoch)."
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"title": "SessionStatus",
|
|
4
|
+
"description": "Returned by session_status(). MUST always be available for OBSERVER role or above.",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"required": ["session_id", "windows_completed", "total_input_tokens", "total_output_tokens", "facts_in_warm_state", "overhead_ratio"],
|
|
7
|
+
"properties": {
|
|
8
|
+
"session_id": {
|
|
9
|
+
"type": "string",
|
|
10
|
+
"format": "uuid",
|
|
11
|
+
"description": "UUID v4 identifying the session."
|
|
12
|
+
},
|
|
13
|
+
"windows_completed": {
|
|
14
|
+
"type": "integer",
|
|
15
|
+
"minimum": 0,
|
|
16
|
+
"description": "Total windows completed in this session (including continuations)."
|
|
17
|
+
},
|
|
18
|
+
"total_input_tokens": {
|
|
19
|
+
"type": "integer",
|
|
20
|
+
"minimum": 0,
|
|
21
|
+
"description": "Cumulative input tokens sent to the LLM across all windows."
|
|
22
|
+
},
|
|
23
|
+
"total_output_tokens": {
|
|
24
|
+
"type": "integer",
|
|
25
|
+
"minimum": 0,
|
|
26
|
+
"description": "Cumulative output tokens received from the LLM across all windows."
|
|
27
|
+
},
|
|
28
|
+
"facts_in_warm_state": {
|
|
29
|
+
"type": "integer",
|
|
30
|
+
"minimum": 0,
|
|
31
|
+
"description": "Current fact count in warm state (Tier 2)."
|
|
32
|
+
},
|
|
33
|
+
"overhead_ratio": {
|
|
34
|
+
"type": "number",
|
|
35
|
+
"minimum": 0.0,
|
|
36
|
+
"description": "Current overhead windows / productive windows ratio."
|
|
37
|
+
},
|
|
38
|
+
"remaining_budget": {
|
|
39
|
+
"type": ["object", "null"],
|
|
40
|
+
"description": "Remaining budget against cost caps. NULL if no caps set.",
|
|
41
|
+
"properties": {
|
|
42
|
+
"windows_remaining": {
|
|
43
|
+
"type": ["integer", "null"],
|
|
44
|
+
"description": "Windows remaining before max_windows_per_session cap."
|
|
45
|
+
},
|
|
46
|
+
"input_tokens_remaining": {
|
|
47
|
+
"type": ["integer", "null"],
|
|
48
|
+
"description": "Input tokens remaining before max_total_input_tokens cap."
|
|
49
|
+
},
|
|
50
|
+
"output_tokens_remaining": {
|
|
51
|
+
"type": ["integer", "null"],
|
|
52
|
+
"description": "Output tokens remaining before max_total_output_tokens cap."
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"title": "StreamEvent",
|
|
4
|
+
"description": "Events emitted by dispatch_stream(). The stream MUST emit exactly one 'done' event as the final event (or one 'error').",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"required": ["event_type", "data"],
|
|
7
|
+
"properties": {
|
|
8
|
+
"event_type": {
|
|
9
|
+
"type": "string",
|
|
10
|
+
"enum": ["token", "extraction", "continuation", "window_complete", "done", "error"],
|
|
11
|
+
"description": "Discriminator for the event type. Concatenating all 'token' data values MUST produce the same string as non-streaming dispatch() output."
|
|
12
|
+
},
|
|
13
|
+
"data": {
|
|
14
|
+
"description": "Event payload. Type depends on event_type: token=string, extraction=ExtractionProgress, continuation=ContinuationInfo, window_complete=WindowSummary, done=QualityReport, error=CRPError."
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"discriminator": { "propertyName": "event_type" }
|
|
18
|
+
}
|