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,401 @@
|
|
|
1
|
+
# Copyright © 2025 Constantinos Vidiniotis. All rights reserved.
|
|
2
|
+
# Licensed under Elastic License 2.0 — see LICENSE.md for details.
|
|
3
|
+
"""Meta-learning — ORC, ICML, Reasoning Template Library (§19).
|
|
4
|
+
|
|
5
|
+
Three mechanisms:
|
|
6
|
+
1. Orchestrated Reasoning Chains (ORC): decompose complex reasoning into micro-steps
|
|
7
|
+
2. In-Context Meta-Learning (ICML): reasoning scaffolds + few-shot examples
|
|
8
|
+
3. Reasoning Template Library (RTL): store/retrieve successful reasoning traces
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import time
|
|
14
|
+
import uuid
|
|
15
|
+
from collections.abc import Callable
|
|
16
|
+
from dataclasses import dataclass, field
|
|
17
|
+
from typing import Any
|
|
18
|
+
|
|
19
|
+
# ---------------------------------------------------------------------------
|
|
20
|
+
# Data types
|
|
21
|
+
# ---------------------------------------------------------------------------
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@dataclass
|
|
25
|
+
class ReasoningStep:
|
|
26
|
+
"""Single step in a reasoning chain."""
|
|
27
|
+
|
|
28
|
+
step_description: str = ""
|
|
29
|
+
system_prompt_template: str = ""
|
|
30
|
+
expected_output_format: str = ""
|
|
31
|
+
scaffold_level: int = 0 # 0-3
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@dataclass
|
|
35
|
+
class ReasoningTrace:
|
|
36
|
+
"""Complete reasoning trace for RTL storage."""
|
|
37
|
+
|
|
38
|
+
trace_id: str = field(default_factory=lambda: str(uuid.uuid4()))
|
|
39
|
+
task_type: str = ""
|
|
40
|
+
task_summary: str = ""
|
|
41
|
+
steps: list[ReasoningStep] = field(default_factory=list)
|
|
42
|
+
model_class: str = "" # "0.5B-1B" | "2B-7B" | "7B+"
|
|
43
|
+
quality_score: float = 0.0
|
|
44
|
+
created_at: float = field(default_factory=time.time)
|
|
45
|
+
usage_count: int = 0
|
|
46
|
+
|
|
47
|
+
def to_dict(self) -> dict[str, Any]:
|
|
48
|
+
return {
|
|
49
|
+
"trace_id": self.trace_id,
|
|
50
|
+
"task_type": self.task_type,
|
|
51
|
+
"task_summary": self.task_summary,
|
|
52
|
+
"steps": [
|
|
53
|
+
{
|
|
54
|
+
"step_description": s.step_description,
|
|
55
|
+
"system_prompt_template": s.system_prompt_template,
|
|
56
|
+
"expected_output_format": s.expected_output_format,
|
|
57
|
+
"scaffold_level": s.scaffold_level,
|
|
58
|
+
}
|
|
59
|
+
for s in self.steps
|
|
60
|
+
],
|
|
61
|
+
"model_class": self.model_class,
|
|
62
|
+
"quality_score": self.quality_score,
|
|
63
|
+
"created_at": self.created_at,
|
|
64
|
+
"usage_count": self.usage_count,
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
@classmethod
|
|
68
|
+
def from_dict(cls, data: dict[str, Any]) -> ReasoningTrace:
|
|
69
|
+
steps = [
|
|
70
|
+
ReasoningStep(
|
|
71
|
+
step_description=s.get("step_description", ""),
|
|
72
|
+
system_prompt_template=s.get("system_prompt_template", ""),
|
|
73
|
+
expected_output_format=s.get("expected_output_format", ""),
|
|
74
|
+
scaffold_level=s.get("scaffold_level", 0),
|
|
75
|
+
)
|
|
76
|
+
for s in data.get("steps", [])
|
|
77
|
+
]
|
|
78
|
+
return cls(
|
|
79
|
+
trace_id=data.get("trace_id", str(uuid.uuid4())),
|
|
80
|
+
task_type=data.get("task_type", ""),
|
|
81
|
+
task_summary=data.get("task_summary", ""),
|
|
82
|
+
steps=steps,
|
|
83
|
+
model_class=data.get("model_class", ""),
|
|
84
|
+
quality_score=data.get("quality_score", 0.0),
|
|
85
|
+
created_at=data.get("created_at", 0.0),
|
|
86
|
+
usage_count=data.get("usage_count", 0),
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
@dataclass
|
|
91
|
+
class ORCResult:
|
|
92
|
+
"""Result of orchestrated reasoning chain."""
|
|
93
|
+
|
|
94
|
+
steps_completed: int = 0
|
|
95
|
+
steps_total: int = 0
|
|
96
|
+
final_output: str = ""
|
|
97
|
+
step_outputs: list[str] = field(default_factory=list)
|
|
98
|
+
quality_score: float = 0.0
|
|
99
|
+
trace: ReasoningTrace | None = None
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
@dataclass
|
|
103
|
+
class MetaLearningConfig:
|
|
104
|
+
"""Configuration for meta-learning features."""
|
|
105
|
+
|
|
106
|
+
enabled: bool = True
|
|
107
|
+
orc_enabled: bool = True
|
|
108
|
+
orc_max_steps: int = 10
|
|
109
|
+
orc_min_model_capability: int = 1
|
|
110
|
+
icml_enabled: bool = True
|
|
111
|
+
icml_max_examples: int = 3
|
|
112
|
+
rtl_enabled: bool = True
|
|
113
|
+
rtl_min_quality_for_storage: float = 0.7
|
|
114
|
+
scaffold_level: str = "auto" # "auto" | "none" | "light" | "heavy"
|
|
115
|
+
curation_interval: int = 5
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
# ---------------------------------------------------------------------------
|
|
119
|
+
# MetaLearningEngine
|
|
120
|
+
# ---------------------------------------------------------------------------
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
class MetaLearningEngine:
|
|
124
|
+
"""ORC + ICML + RTL meta-learning capabilities."""
|
|
125
|
+
|
|
126
|
+
def __init__(
|
|
127
|
+
self,
|
|
128
|
+
dispatch_fn: Callable[[str, str], tuple[str, Any]] | None = None,
|
|
129
|
+
model_capability: int = 1,
|
|
130
|
+
config: MetaLearningConfig | None = None,
|
|
131
|
+
) -> None:
|
|
132
|
+
self._dispatch_fn = dispatch_fn
|
|
133
|
+
self._model_capability = model_capability
|
|
134
|
+
self.config = config or MetaLearningConfig()
|
|
135
|
+
self._trace_library: list[ReasoningTrace] = []
|
|
136
|
+
|
|
137
|
+
# ------------------------------------------------------------------
|
|
138
|
+
# Mechanism 1: Orchestrated Reasoning Chains (ORC)
|
|
139
|
+
# ------------------------------------------------------------------
|
|
140
|
+
|
|
141
|
+
def should_use_orc(
|
|
142
|
+
self,
|
|
143
|
+
task_complexity: int = 3,
|
|
144
|
+
resource_pressure: str = "NONE",
|
|
145
|
+
probe_quality: float = 0.0,
|
|
146
|
+
) -> bool:
|
|
147
|
+
"""Gate check for ORC activation.
|
|
148
|
+
|
|
149
|
+
Gate 1: resource_pressure >= HIGH → False
|
|
150
|
+
Gate 2: model_capability >= task_complexity → False
|
|
151
|
+
Gate 3: probe_quality >= 0.7 → False (ORC unnecessary)
|
|
152
|
+
"""
|
|
153
|
+
if not self.config.orc_enabled:
|
|
154
|
+
return False
|
|
155
|
+
if resource_pressure in ("HIGH", "CRITICAL"):
|
|
156
|
+
return False
|
|
157
|
+
if self._model_capability >= task_complexity:
|
|
158
|
+
return False
|
|
159
|
+
return probe_quality < 0.7
|
|
160
|
+
|
|
161
|
+
def orchestrated_reasoning(
|
|
162
|
+
self,
|
|
163
|
+
task_intent: str,
|
|
164
|
+
task_complexity: int = 3,
|
|
165
|
+
resource_pressure: str = "NONE",
|
|
166
|
+
) -> ORCResult:
|
|
167
|
+
"""Decompose and execute orchestrated reasoning chain."""
|
|
168
|
+
# Determine max steps based on resource pressure
|
|
169
|
+
max_steps = self.config.orc_max_steps
|
|
170
|
+
if resource_pressure == "MODERATE":
|
|
171
|
+
max_steps = min(max_steps, 5)
|
|
172
|
+
elif resource_pressure in ("HIGH", "CRITICAL"):
|
|
173
|
+
max_steps = min(max_steps, 3)
|
|
174
|
+
|
|
175
|
+
steps = self._decompose_reasoning(task_intent, max_steps)
|
|
176
|
+
step_outputs: list[str] = []
|
|
177
|
+
|
|
178
|
+
for step in steps:
|
|
179
|
+
if not self._dispatch_fn:
|
|
180
|
+
step_outputs.append(f"[no dispatch] {step.step_description}")
|
|
181
|
+
continue
|
|
182
|
+
|
|
183
|
+
try:
|
|
184
|
+
prompt = step.system_prompt_template or step.step_description
|
|
185
|
+
output, _ = self._dispatch_fn(prompt, "")
|
|
186
|
+
step_outputs.append(output)
|
|
187
|
+
except Exception:
|
|
188
|
+
# Retry with more scaffolding
|
|
189
|
+
scaffolded_prompt = (
|
|
190
|
+
f"Step-by-step, {step.step_description}\n"
|
|
191
|
+
f"Expected format: {step.expected_output_format}"
|
|
192
|
+
)
|
|
193
|
+
try:
|
|
194
|
+
output, _ = self._dispatch_fn(scaffolded_prompt, "")
|
|
195
|
+
step_outputs.append(output)
|
|
196
|
+
except Exception:
|
|
197
|
+
step_outputs.append(f"[failed] {step.step_description}")
|
|
198
|
+
|
|
199
|
+
# Synthesize
|
|
200
|
+
final = self._synthesize_chain(step_outputs, task_intent)
|
|
201
|
+
|
|
202
|
+
trace = ReasoningTrace(
|
|
203
|
+
task_type="orc",
|
|
204
|
+
task_summary=task_intent[:200],
|
|
205
|
+
steps=steps,
|
|
206
|
+
model_class=self._model_class_str(),
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
return ORCResult(
|
|
210
|
+
steps_completed=len(step_outputs),
|
|
211
|
+
steps_total=len(steps),
|
|
212
|
+
final_output=final,
|
|
213
|
+
step_outputs=step_outputs,
|
|
214
|
+
trace=trace,
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
def _decompose_reasoning(
|
|
218
|
+
self, task_intent: str, max_steps: int,
|
|
219
|
+
) -> list[ReasoningStep]:
|
|
220
|
+
"""Decompose task into reasoning steps."""
|
|
221
|
+
if self._dispatch_fn:
|
|
222
|
+
try:
|
|
223
|
+
prompt = (
|
|
224
|
+
f"Decompose this task into {max_steps} or fewer reasoning steps. "
|
|
225
|
+
f"For each step, give a one-line description.\n\n"
|
|
226
|
+
f"Task: {task_intent}"
|
|
227
|
+
)
|
|
228
|
+
output, _ = self._dispatch_fn(prompt, "")
|
|
229
|
+
steps: list[ReasoningStep] = []
|
|
230
|
+
for line in output.split("\n"):
|
|
231
|
+
line = line.strip()
|
|
232
|
+
if line and (line[0].isdigit() or line.startswith("-")):
|
|
233
|
+
desc = line.lstrip("0123456789.-) ").strip()
|
|
234
|
+
if desc:
|
|
235
|
+
steps.append(ReasoningStep(step_description=desc))
|
|
236
|
+
if steps:
|
|
237
|
+
return steps[:max_steps]
|
|
238
|
+
except Exception:
|
|
239
|
+
pass
|
|
240
|
+
|
|
241
|
+
return self._default_decomposition(task_intent, max_steps)
|
|
242
|
+
|
|
243
|
+
def _default_decomposition(
|
|
244
|
+
self, task_intent: str, max_steps: int,
|
|
245
|
+
) -> list[ReasoningStep]:
|
|
246
|
+
"""Default decomposition when LLM unavailable."""
|
|
247
|
+
return [
|
|
248
|
+
ReasoningStep(
|
|
249
|
+
step_description=f"Analyze: {task_intent}",
|
|
250
|
+
expected_output_format="structured analysis",
|
|
251
|
+
scaffold_level=2,
|
|
252
|
+
),
|
|
253
|
+
ReasoningStep(
|
|
254
|
+
step_description="Synthesize findings into coherent response",
|
|
255
|
+
expected_output_format="summary",
|
|
256
|
+
scaffold_level=1,
|
|
257
|
+
),
|
|
258
|
+
][:max_steps]
|
|
259
|
+
|
|
260
|
+
def _synthesize_chain(
|
|
261
|
+
self, step_outputs: list[str], task_intent: str,
|
|
262
|
+
) -> str:
|
|
263
|
+
"""Synthesize step outputs into final response."""
|
|
264
|
+
if self._dispatch_fn and len(step_outputs) > 1:
|
|
265
|
+
joined = "\n\n---\n\n".join(step_outputs)
|
|
266
|
+
try:
|
|
267
|
+
output, _ = self._dispatch_fn(
|
|
268
|
+
f"Synthesize these reasoning steps into a final answer for: {task_intent}",
|
|
269
|
+
joined[:5000],
|
|
270
|
+
)
|
|
271
|
+
return output
|
|
272
|
+
except Exception:
|
|
273
|
+
pass
|
|
274
|
+
return "\n\n".join(step_outputs)
|
|
275
|
+
|
|
276
|
+
# ------------------------------------------------------------------
|
|
277
|
+
# Mechanism 2: In-Context Meta-Learning (ICML)
|
|
278
|
+
# ------------------------------------------------------------------
|
|
279
|
+
|
|
280
|
+
def build_reasoning_scaffold(
|
|
281
|
+
self,
|
|
282
|
+
task_intent: str,
|
|
283
|
+
) -> str:
|
|
284
|
+
"""Build reasoning scaffold adapted to model capability.
|
|
285
|
+
|
|
286
|
+
Capability ≤ 1 (0.5B-1B): Full step-by-step template
|
|
287
|
+
Capability ≤ 2 (2B-7B): Light approach
|
|
288
|
+
Capability > 2: No scaffolding
|
|
289
|
+
"""
|
|
290
|
+
level = self.config.scaffold_level
|
|
291
|
+
if level == "auto":
|
|
292
|
+
if self._model_capability <= 1:
|
|
293
|
+
level = "heavy"
|
|
294
|
+
elif self._model_capability <= 2:
|
|
295
|
+
level = "light"
|
|
296
|
+
else:
|
|
297
|
+
level = "none"
|
|
298
|
+
|
|
299
|
+
if level == "none":
|
|
300
|
+
return ""
|
|
301
|
+
if level == "light":
|
|
302
|
+
return (
|
|
303
|
+
f"[APPROACH]\n"
|
|
304
|
+
f"Consider: key factors, potential issues, evidence available.\n"
|
|
305
|
+
f"Task: {task_intent}\n"
|
|
306
|
+
)
|
|
307
|
+
# Heavy scaffolding
|
|
308
|
+
return (
|
|
309
|
+
f"[REASONING APPROACH]\n"
|
|
310
|
+
f"Step 1: Identify the key elements of: {task_intent}\n"
|
|
311
|
+
f"Step 2: Analyze relationships between elements\n"
|
|
312
|
+
f"Step 3: Consider potential issues or gaps\n"
|
|
313
|
+
f"Step 4: Synthesize findings\n"
|
|
314
|
+
f"Step 5: Verify conclusions against evidence\n"
|
|
315
|
+
)
|
|
316
|
+
|
|
317
|
+
def build_metacognitive_envelope(
|
|
318
|
+
self,
|
|
319
|
+
task_intent: str,
|
|
320
|
+
base_envelope: str = "",
|
|
321
|
+
few_shot_traces: list[ReasoningTrace] | None = None,
|
|
322
|
+
) -> str:
|
|
323
|
+
"""Build envelope with reasoning scaffold + few-shot examples."""
|
|
324
|
+
parts: list[str] = []
|
|
325
|
+
|
|
326
|
+
if base_envelope:
|
|
327
|
+
parts.append(base_envelope)
|
|
328
|
+
|
|
329
|
+
scaffold = self.build_reasoning_scaffold(task_intent)
|
|
330
|
+
if scaffold:
|
|
331
|
+
parts.append(scaffold)
|
|
332
|
+
|
|
333
|
+
# Few-shot examples from trace library
|
|
334
|
+
traces = few_shot_traces or self._retrieve_traces(task_intent)
|
|
335
|
+
if traces and self.config.icml_enabled:
|
|
336
|
+
examples = "\n".join(
|
|
337
|
+
f"Example {i+1}: {t.task_summary[:100]} → {t.steps[0].step_description if t.steps else 'N/A'}"
|
|
338
|
+
for i, t in enumerate(traces[:self.config.icml_max_examples])
|
|
339
|
+
)
|
|
340
|
+
parts.append(f"[EXAMPLES]\n{examples}")
|
|
341
|
+
|
|
342
|
+
return "\n\n".join(parts)
|
|
343
|
+
|
|
344
|
+
# ------------------------------------------------------------------
|
|
345
|
+
# Mechanism 3: Reasoning Template Library (RTL)
|
|
346
|
+
# ------------------------------------------------------------------
|
|
347
|
+
|
|
348
|
+
def store_trace(self, trace: ReasoningTrace) -> bool:
|
|
349
|
+
"""Store a reasoning trace if quality meets threshold."""
|
|
350
|
+
if not self.config.rtl_enabled:
|
|
351
|
+
return False
|
|
352
|
+
if trace.quality_score < self.config.rtl_min_quality_for_storage:
|
|
353
|
+
return False
|
|
354
|
+
self._trace_library.append(trace)
|
|
355
|
+
return True
|
|
356
|
+
|
|
357
|
+
def _retrieve_traces(
|
|
358
|
+
self,
|
|
359
|
+
task_intent: str,
|
|
360
|
+
top_k: int = 3,
|
|
361
|
+
) -> list[ReasoningTrace]:
|
|
362
|
+
"""Retrieve matching traces from library (simplified text match)."""
|
|
363
|
+
if not self._trace_library:
|
|
364
|
+
return []
|
|
365
|
+
task_words = set(task_intent.lower().split())
|
|
366
|
+
scored: list[tuple[float, ReasoningTrace]] = []
|
|
367
|
+
for trace in self._trace_library:
|
|
368
|
+
trace_words = set(trace.task_summary.lower().split())
|
|
369
|
+
if not task_words:
|
|
370
|
+
continue
|
|
371
|
+
overlap = len(task_words & trace_words) / len(task_words)
|
|
372
|
+
scored.append((overlap, trace))
|
|
373
|
+
|
|
374
|
+
scored.sort(key=lambda x: -x[0])
|
|
375
|
+
results = [t for _, t in scored[:top_k] if _ > 0.2]
|
|
376
|
+
for t in results:
|
|
377
|
+
t.usage_count += 1
|
|
378
|
+
return results
|
|
379
|
+
|
|
380
|
+
@property
|
|
381
|
+
def trace_count(self) -> int:
|
|
382
|
+
return len(self._trace_library)
|
|
383
|
+
|
|
384
|
+
def _model_class_str(self) -> str:
|
|
385
|
+
if self._model_capability <= 1:
|
|
386
|
+
return "0.5B-1B"
|
|
387
|
+
if self._model_capability <= 2:
|
|
388
|
+
return "2B-7B"
|
|
389
|
+
return "7B+"
|
|
390
|
+
|
|
391
|
+
def to_dict(self) -> dict[str, Any]:
|
|
392
|
+
return {
|
|
393
|
+
"traces": [t.to_dict() for t in self._trace_library],
|
|
394
|
+
"config": {
|
|
395
|
+
"enabled": self.config.enabled,
|
|
396
|
+
"orc_enabled": self.config.orc_enabled,
|
|
397
|
+
"orc_max_steps": self.config.orc_max_steps,
|
|
398
|
+
"icml_enabled": self.config.icml_enabled,
|
|
399
|
+
"rtl_enabled": self.config.rtl_enabled,
|
|
400
|
+
},
|
|
401
|
+
}
|
crp/advanced/parallel.py
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# Copyright © 2025 Constantinos Vidiniotis. All rights reserved.
|
|
2
|
+
# Licensed under Elastic License 2.0 — see LICENSE.md for details.
|
|
3
|
+
"""Parallel fan-out — N independent windows dispatched concurrently (§4.4)."""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from collections.abc import Callable
|
|
8
|
+
from dataclasses import dataclass, field
|
|
9
|
+
from typing import Any
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@dataclass
|
|
13
|
+
class FanOutTask:
|
|
14
|
+
"""One independent task for parallel dispatch."""
|
|
15
|
+
|
|
16
|
+
task_id: str = ""
|
|
17
|
+
system_prompt: str = ""
|
|
18
|
+
task_input: str = ""
|
|
19
|
+
metadata: dict[str, Any] = field(default_factory=dict)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@dataclass
|
|
23
|
+
class FanOutResult:
|
|
24
|
+
"""Result of one parallel dispatch."""
|
|
25
|
+
|
|
26
|
+
task_id: str = ""
|
|
27
|
+
output: str = ""
|
|
28
|
+
facts_extracted: int = 0
|
|
29
|
+
success: bool = True
|
|
30
|
+
error: str | None = None
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class ParallelFanOut:
|
|
34
|
+
"""Dispatch N independent windows and merge results.
|
|
35
|
+
|
|
36
|
+
Algorithm (§4.4):
|
|
37
|
+
1. Identify N independent tasks
|
|
38
|
+
2. Construct independent envelopes from warm_state
|
|
39
|
+
3. Dispatch all N windows (sequential fallback if no async)
|
|
40
|
+
4. Collect all N outputs
|
|
41
|
+
5. Extract facts from all N outputs
|
|
42
|
+
6. Merge facts into warm_state
|
|
43
|
+
7. Update DAG with fan-out edges
|
|
44
|
+
8. Continue with next dependent task
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
def __init__(
|
|
48
|
+
self,
|
|
49
|
+
dispatch_fn: Callable[[str, str], tuple[str, Any]] | None = None,
|
|
50
|
+
extract_fn: Callable[[str], list[dict[str, Any]]] | None = None,
|
|
51
|
+
max_concurrent: int = 4,
|
|
52
|
+
) -> None:
|
|
53
|
+
self._dispatch_fn = dispatch_fn
|
|
54
|
+
self._extract_fn = extract_fn
|
|
55
|
+
self._max_concurrent = max_concurrent
|
|
56
|
+
|
|
57
|
+
def fan_out(self, tasks: list[FanOutTask]) -> list[FanOutResult]:
|
|
58
|
+
"""Dispatch tasks (sequentially — async version would override).
|
|
59
|
+
|
|
60
|
+
Returns results in same order as tasks.
|
|
61
|
+
"""
|
|
62
|
+
results: list[FanOutResult] = []
|
|
63
|
+
for task in tasks:
|
|
64
|
+
if self._dispatch_fn:
|
|
65
|
+
try:
|
|
66
|
+
output, _ = self._dispatch_fn(task.system_prompt, task.task_input)
|
|
67
|
+
facts_count = 0
|
|
68
|
+
if self._extract_fn:
|
|
69
|
+
facts = self._extract_fn(output)
|
|
70
|
+
facts_count = len(facts)
|
|
71
|
+
results.append(FanOutResult(
|
|
72
|
+
task_id=task.task_id,
|
|
73
|
+
output=output,
|
|
74
|
+
facts_extracted=facts_count,
|
|
75
|
+
success=True,
|
|
76
|
+
))
|
|
77
|
+
except Exception as exc:
|
|
78
|
+
results.append(FanOutResult(
|
|
79
|
+
task_id=task.task_id,
|
|
80
|
+
success=False,
|
|
81
|
+
error=str(exc),
|
|
82
|
+
))
|
|
83
|
+
else:
|
|
84
|
+
results.append(FanOutResult(
|
|
85
|
+
task_id=task.task_id,
|
|
86
|
+
output=f"[no dispatch_fn] task={task.task_id}",
|
|
87
|
+
))
|
|
88
|
+
return results
|
|
89
|
+
|
|
90
|
+
def merge_results(
|
|
91
|
+
self,
|
|
92
|
+
results: list[FanOutResult],
|
|
93
|
+
existing_facts: list[Any] | None = None,
|
|
94
|
+
) -> list[FanOutResult]:
|
|
95
|
+
"""Merge fan-out results. Successful results first, failures last."""
|
|
96
|
+
successes = [r for r in results if r.success]
|
|
97
|
+
failures = [r for r in results if not r.success]
|
|
98
|
+
return successes + failures
|